A custom cursor that's allowed to exist
How we lazy-load a custom cursor with dynamic import and SSR false so it adds polish without blocking content or hurting Core Web Vitals.
The Blog
How we use Motion's scroll hooks for hero and media depth effects, transforms only, springs for smoothing, and a static fallback for reduced motion.
The approach
Parallax is a scroll-linked effect where elements move at different speeds relative to the viewport. Done well, it creates depth. Done poorly, it causes jank, dropped frames, layout thrash, and a scroll experience that feels like wading through mud.
The key is keeping animation on the GPU. We use Motion's useScroll to track scroll progress, useTransform to map that progress to CSS transforms, and useSpring to smooth the values. The browser composites the transform on the GPU without triggering layout recalculations.
Our parallax component applies this to hero images, page head media, and multi-column sliders. Each maps scroll progress to a vertical or scale transform. The spring smoothing prevents jerky movement when the user scrolls quickly.
Reduced motion
When prefers-reduced-motion is enabled, our parallax components render statically. The useReducedMotion hook from Motion returns true, and the component skips the scroll-linked transforms entirely. Same content, same layout, no spatial movement.
This connects to our broader reduced-motion approach. Every animation effect in the system has a calmer fallback. Parallax goes static. Magnetic buttons become standard buttons. Text reveals become simple fades.