Behind the Star Cursor

How the Star Cursor draws its comet tail and sparkle dust, and why it quietly steps aside on touch screens and for anyone who prefers reduced motion.

The Star Cursor from the Night Sky UI Kit, a white star with a glowing trail on a dark background

A custom cursor is a strange thing to ship. It replaces the one part of the screen people rely on to know where they are, so it had better earn its place. The Star Cursor tries to earn it by being polite first and sparkly second. Before it draws a single pixel, it asks the browser three questions. Can this device hover? Is the pointer fine, like a mouse or a trackpad? And has the visitor said nothing about wanting less motion? Only when all three answers are yes does the star appear and the normal arrow hide. If any answer is no, the component does nothing at all, and your page looks exactly as it did before.

Here is that check, straight from the component. A phone fails the hover test, so it keeps its ordinary taps. Someone who has turned on reduced motion in their system settings fails the last test, so they keep the plain cursor too. The check also keeps listening. If a visitor switches reduced motion on while the page is open, the component stops, puts the regular cursor back and clears its canvas. Even when the query passes, every pointer move is checked for its type, and anything that isn't a mouse gets ignored. That matters on laptops with touch screens, where a finger and a trackpad share the same machine.

TSX
const media = window.matchMedia(
  touch ? '(prefers-reduced-motion: no-preference)' : '(hover: hover) and (pointer: fine) and (prefers-reduced-motion: no-preference)',
)

The star itself is a small SVG, 25 pixels by default, with a very dark navy outline. The chunky bottom right edge comes from stacking copies of the star shape, each nudged a little further down and to the right, which reads like a soft offset shadow. The tail lives on a canvas underneath. Every frame, the pointer position goes to the front of a list that keeps the last 30 points by default, and the component draws a line through them that gets thinner and fainter toward the end, with a glow that fades as well. Sparkle dust only shows up when you move quickly. Faster moves shed more specks, and each one drifts gently downward and fades out after about 40 frames.

The rest of its manners are quieter. The star and its canvas are both aria-hidden, so screen readers skip them, and both use pointer-events: none, so every click lands on whatever sits underneath. The star also hides when the window loses focus or the pointer leaves the window. If you do want it on phones, set touch to true and it follows a finger, then hides when the finger lifts. You can try all of this on the Star Cursor page, which has a live preview and a Customize panel for size, outline, offset, colors, tail length, tail width and dust. It costs $9 on its own, or comes with the other two effects in the $19 Night Sky UI Kit.

Night Sky UI Kit

Every effect in this post, ready to drop into a React app.

Explore the Night Sky UI Kit →