Experiment · Mar 2026 · 4 min read

A cursor that thinks

Building a magnetic, mix‑blend cursor that reacts to everything it touches — in about 60 lines.

LAB‑01

Let me say it first: most custom cursors are bad. Laggy little circles chasing your mouse around like they're being paid by the hour. I almost didn't ship mine. But here's the thing — the cursor touches every single element on your site, which makes it the cheapest personality-per-line-of-code deal you'll ever get. So I gave it a brain. Sixty-ish lines.

01 The lag is the whole trick

Two elements, that's it. A tiny dot glued to the pointer 1:1, and a bigger ring that's always catching up — every frame it covers a fixed slice of the remaining distance. That little delay? That's the magic. Instant feels robotic. Slightly late feels alive. (Very late feels broken — don't overdo it.)

The ring lives in one requestAnimationFrame loop; the dot is a raw transform inside the mousemove handler. Splitting them matters: the dot gives you precision, the ring gives you character, and neither one waits for the other.

02 It reads the room

I didn't want to wire hover states one by one — that way lies madness. So the cursor reads data attributes instead. data-hover="link" makes the ring shrink and glow. data-hover="view" morphs it into a little pill that says 'Read' or 'Open' or whatever the element wants it to say. New components get cursor behaviour for free, just by asking. The cursor file hasn't grown in months.

And the finishing move: mix-blend-mode: difference. The cursor inverts whatever's underneath — dark hero, light card, red headline, doesn't matter. Zero conditionals. The browser does the theming and I take the credit.

Next upDesigning motion as a language
Thinking out loudBuilding in the openMore soonThinking out loudBuilding in the openMore soon