Effects
Scramble text, spotlight cards, marquee, grain, magnetic hover and count-up — built without driving per-frame work through React state.
Six effects that show up on nearly every developer-tool landing page. The interesting part is not what they do, it is what they avoid.
Live at /lab/effects.
Installation
npx shadcn@latest add https://ui.whoisroktim.lol/r/effects.jsonThe rule they all follow
Nothing pointer-driven goes through React state. A spotlight card built with
onMouseMove={e => setPos(...)} re-renders on every pointer event to move a
gradient — sixty renders a second, per card, to change one background position.
These write to CSS custom properties on the node instead, so the browser does
the compositing and React never hears about it.
el.style.setProperty("--mx", `${e.clientX - r.left}px`);Working before the script does
ScrambleText and CountUp both render their real content in the markup and
only animate once an IntersectionObserver fires.
<ScrambleText text="Landing page furniture" />
<CountUp to={32} />That ordering matters more than it looks. Build the scramble from an empty span
that script fills in, and the text is missing for anyone whose script fails,
whose observer never fires because they never scrolled, or who is reading the
page through a search index. Same for a counter that starts at 0 — the number
on the page should be the true one, with the animation as decoration on top.
Both are asserted in tests/dom/effects.test.tsx.
Details worth keeping
The marquee renders its children twice and translates exactly -50%. That is
what makes the wrap seamless; animating a single copy from 100% to -100%
leaves a visible gap every cycle, which is the tell on most implementations. The
duplicate is aria-hidden — a screen reader announcing every logo twice is a
real cost for no gain — and both edges are masked so the loop point never shows.
The spotlight has an edge. Two layers: a soft fill inside the card, and a
brighter ring masked to the border with mask-composite. A glow without that
ring reads as a smudge rather than as light catching a surface.
Grain is inline SVG turbulence, not a PNG. A few hundred bytes, no network
request, and it never blurs at high DPR. It animates by stepping
background-position between whole-pixel offsets, so the tile moves without any
of it being resampled.
Magnetic pull eases to zero at the edge of its field. A linear pull with a hard cutoff snaps when the pointer crosses the boundary, which is what makes most magnetic buttons feel jumpy.
Reduced motion
Every one of these has a defined answer, and for most of them it is show the end state: the text is already decoded, the number is already correct, the magnet does not move. The marquee stops. Nothing here hides content when motion is turned down.