Prompt
Build a custom cursor: a rounded Figma-style arrow plus a ring of rotating text that follows with a lag.
Stack: Next.js (App Router), React, TypeScript and Tailwind CSS v4. Use gsap.
SETUP
- A client component mounted once in the root layout. Only run when matchMedia("(pointer: fine)") matches.
- Global CSS:
- Inside @media (pointer: fine), set cursor: none !important on *, *::before and *::after.
- Inside @media (pointer: coarse), hide the component.
- Wrapper: aria-hidden, pointer-events none, position fixed, inset 0, z-index 9999, mix-blend-mode: difference. Everything inside is pure white (#fff), so it inverts whatever is underneath.
- IMPORTANT: give <html> its own background color (the same as body). Otherwise the body background moves to the canvas, the difference blend has nothing to blend with, and the cursor shows plain white.
ARROW
- A 28×28 SVG with path "M6 5v17.5l5.2-5.2h7.8Z", drawn twice for rounded corners:
- First with a 4px stroke, round line joins and paint-order stroke.
- Then with a 1.2px stroke and round joins.
- Translate it by (-6px, -5px) so the tip sits exactly on the pointer.
- Follows the pointer with gsap.quickTo on x/y, duration 0.05.
RING
- A 124×124 SVG with a thin circle (r 38, 0.75px stroke).
- Text on a circular path of r 48: "WELCOME • SCROLL DOWN •".
- 8.5px, uppercase, letter-spacing 0.5.
- Use textLength 301 (≈ 2π×48) with lengthAdjust="spacing" so the text fills the circle evenly.
- Spins with a CSS keyframe rotate(360deg), 10s linear infinite.
- Centered with xPercent/yPercent -50. Follows with gsap.quickTo, duration 0.45, ease "power3.out", offset (+4px, +8px) so it centers on the arrow's body.
BEHAVIOR
- On the first pointermove, fade both to opacity 1 (0.2s). On pointerleave of the document, fade both out.
- When the pointer is over any a or button (check with closest), shrink the ring's inner wrapper to scale 0.5 and opacity 0 (0.25s, power2.out).
- When it leaves, bring the ring back after a 0.5s delay. Use overwrite: true so hovering another link cancels a pending reveal.More in Animations
GSAP split-text hover: each letter rolls up and is replaced by its twin, letter by letter, and always finishes.
Letter Roll Hover Text
A glowing yellow band of light that sweeps left to right through the letters — not a static glow.
Shine Sweep Text
A rounded, inset section that grows to the screen edges (and upward) as you scroll, then eases back partway as it leaves.
Scroll-Grow Section
An endless, seamless row of tech pills that fades out at both edges — pure CSS, no JavaScript.
Tech Stack Marquee
A heart that pops, rings and bursts into tiny lime and purple dots and hearts when you favorite something.