Custom cursor
The emmetts.dev spring cursor, with shared motion and customizable colors.
The cursor from emmetts.dev is an optional, dependency-free CDN component. Its 16 px circle follows with a responsive spring and eases to 40 px over links, buttons, and marked interactive targets. It is 90% opaque, including during hover. Color changes preserve the shape, motion, and interaction timing.
This is the only CDN documentation page that enables it. All other pages use their normal cursor.
Move anywhere on this page. Hover to expand. Move away to settle.
16 px circle · 40 px on hover · 90% opacity. Touch uses the native pointer. Reduced motion removes spring travel and easing. White is easiest to see on the dark surface; black on the light surface.
Install
Place the element in the page body and load the script after it:
<shaughv-cursor color="orange"></shaughv-cursor>
<script src="https://cdn.shaughv.com/js/shaughv-cursor.js"></script>
Use one instance per page. Loading the script alone does not change the cursor. Removing the element restores the normal cursor. No React, Tailwind, or Framer Motion is required.
Colors
| Preset | Value |
|---|---|
orange (default) |
#FF5E1A |
sage (vintage sage) |
#5B8A5B |
black |
#000000 |
white |
#FFFFFF |
Use any valid CSS color, including a custom property available on the document body. These presets match the CDN’s orange motion example and vintage sage identity; they are available as ShaughvCursor.colors and in the cursor metadata.
<shaughv-cursor color="#8359c7"></shaughv-cursor>
<!-- Or color="var(--site-accent)" -->
Solid color is the default so the selected color remains predictable. For the original site’s background-reactive appearance, add blend="difference". Difference blending changes the visible color against the surface; black has little visible effect in that mode. Use solid black on a light background and white on a dark one. Colors with their own alpha multiply the 90% element opacity.
<shaughv-cursor color="orange" blend="difference"></shaughv-cursor>
Frameworks and cleanup
After loading the script, mount once in a client lifecycle and call destroy() on unmount or route change. The target defaults to the full page; pass an element to limit it to a region. A new mount replaces the previous instance.
const cursor = window.ShaughvCursor.mount({ color: "sage", blend: "normal" });
cursor.setColor("#8359c7");
cursor.setBlend("difference");
// On unmount:
cursor.destroy();
// Load the CDN script before mounting this client component.
useEffect(() => {
const cursor = window.ShaughvCursor.mount({ color: "sage" });
return () => cursor.destroy();
}, []);
Interaction contract
The shared spring retains mass 0.4, damping 28, and stiffness 900 from the original site. Hover expansion and contraction use 200 ms ease-in-out. The first position appears at the pointer, and the animation stops when it settles. Mouse clicks still reach the underlying element; the decorative cursor never intercepts input.
Only one cursor should be visible: the native pointer stays hidden throughout custom-cursor tracking. Entering a native control hides the custom circle before restoring the system pointer. The component inspects site-defined cursor styles when entering each target, without toggling native-pointer visibility on every movement.
Links, buttons, summaries, button/link roles, and [data-magnetic] targets expand the circle. The marker also works on descendants. It does not move the target itself: the original site’s magnetic button movement belongs to a separate component.
<span data-magnetic>Custom interactive target</span>
<div data-cursor="native">Keep the site's native cursor in this region</div>
Text fields, editable content, selects, disabled controls, and resize/grab/wait/precision cursor styles keep their native cursor. The decoration hides on window exit, blur, scrolling, and keyboard navigation, then returns on mouse movement. Touch and coarse pointers retain native behavior. With reduced motion, it tracks directly and switches hover size without easing.
Agents may choose presets or custom colors to fit each website. Keep the shared view, spring, hover sizes, easing, and opacity; do not reimplement a different animation for every site. Discover this guide via usage.documentation.cursor in the catalog.