Detail 13 · Performance
Fast, light and accessible
Keeping all this motion smooth and usable: cheap animations, a calm version of each motion, and the numbers. 7 minutes, 2 demos.
- The intro’s signatureWritten stroke by stroke, over 3.2 s
- Page changesThe page sinks, is sketched, then builds in
- ParallaxEach layer at its own speed
- Smooth scrollingEased by Lenis
- The stringsRing with the music
- The grainJumps ten times a second
- Music notesSlip out of the island on each note
- RevealsBlur in, zooming from 125%
- IslandsSpring open through a blur
01 · The idea
Motion shouldn't be the price of entry
Everything on this site moves: pages sink and get sketched, letters swell, strings ring, grain jumps. None of it is worth anything if the page stutters, takes long to arrive, or can’t be used by someone who can’t use a mouse or gets dizzy from motion. So three rules sat under all of it: smooth on an ordinary laptop, light on a phone, and usable by anyone.
This detail is the plain side of the site: the habits that keep it fast, the switch that calms it down, and the numbers, including the ones that still need work.
02 · Smooth
Only the cheap things move
A browser can move, scale and fade something almost for free, on the graphics card, without laying the page out again. Almost every animation here sticks to those: transforms and opacity. Anything that follows the pointer or the scroll runs on motion values, which change the style directly instead of re-rendering React, as the proximity detail showed.
Blur is the exception, because it’s expensive while it’s on. The reveals blur things in, so once a block is sharp the filter is taken off altogether, not left at zero. Left on, every scroll would keep redrawing it.
animate={
ready
? {
opacity: 1,
filter: "blur(0px)",
scale: 1,
// Drop the filter once sharp so scrolling doesn't keep re-rendering it
transitionEnd: { filter: "none" },
}
: undefined
}And things that are idle should cost nothing. The strings aren’t redrawn while they’re still, the grain is drawn once and only moved, and the newer demos here pause their loops when they scroll out of view. Not everything does yet: the music island’s wave keeps running while you’re scrolled away from it.
03 · Reduced motion
One switch, every motion
Some people get dizzy or sick from movement on screen, and set their device to reduce motion. The site listens for that setting, and most of its motion has a calmer version. Switch it on below to see each one change, and the two that don’t yet.
- The intro’s signatureWritten stroke by stroke, over 3.2 s
- Page changesThe page sinks, is sketched, then builds in
- ParallaxEach layer at its own speed
- Smooth scrollingEased by Lenis
- The stringsRing with the music
- The grainJumps ten times a second
- Music notesSlip out of the island on each note
- RevealsBlur in, zooming from 125%
- IslandsSpring open through a blur
Most of it is one condition where the motion starts. The parallax hook, for example, simply returns nothing, and the layers move with the page:
export function useParallax(speed) {
const reduceMotion = useReducedMotion();
const { scrollY } = useScroll();
const y = useTransform(scrollY, (scroll) => scroll * speed);
return speed && !reduceMotion ? y : undefined;
}Two aren’t done yet. The reveals should only fade with reduced motion, but they still zoom in from 125%, and zooming is exactly the kind of motion the setting is there to stop. And the islands still spring open through a blur, where a quick fade would do. Both are at the top of the list.
04 · Accessible
Anything you can hover, you can reach
A site this visual is easy to make for a mouse only. The rule here is that anything that reacts to hovering can also be reached from the keyboard and by touch. The scroll ruler’s index has a hidden “Jump to a section” stop for the keyboard and opens with a tap on a touchscreen. Demos that react to a cursor have a play button that runs one across them, for anyone without one.
Custom controls are real controls underneath. The pencil sliders are drawn over real range inputs, so arrow keys, screen readers and touch all work; the switches are buttons with the switch role. And the purely decorative layers, the grain, the strings and the sketches, are hidden from screen readers, so they don’t read out as noise.
05 · The numbers
Where the bytes go
Here’s what a first visit to the home page downloads, from a production build. Two of the fixes are already in: the grain went from a 3.1 MB image to 600 bytes, and the portrait is sized and converted by Next’s image component instead of sent as a 572 KB PNG. Switch “Before the fixes” on to see what they saved.
- The glow behind the heroa 1 MB PNG, sent as WebP352 KB
- JavaScript12 files281 KB
- Fonts5 WOFF2 + the signature’s TTF268 KB
- HTML185 KB before gzip22 KB
- CSS2 files19 KB
- The portraitWebP, sized by next/image10 KB
- The grainan SVG inside the CSS0.6 KB
First visit, before the music953 KB
The biggest thing on the page is a blur. The soft orange glow behind the hero is a 1 MB PNG, and even converted to WebP it’s 352 KB: more than all the JavaScript. A glow that soft could be a CSS gradient, which weighs nothing. That’s the next fix.
The fonts held a surprise too. The site asks for six weights of Roboto, which looks wasteful, but Roboto is a variable font: all six come from one file per style, so trimming them would save nothing. What’s worth checking instead is whether the italic Roboto, preloaded on every page, is used at all.
The music isn’t in the total. Each track is 3 to 8 MB, but it’s streamed after the page has loaded, and it never holds anything up.
06 · Decisions
Why it’s built this way
Transforms and opacity
The two things a browser moves for free. Everything else that animates has to earn it.
A calm version of everything
Reduced motion isn’t “no motion”: the site still works and still looks like itself, it just stops moving you around.
Hover is a bonus
Nothing important lives only behind a hover. The keyboard and a tap reach it too.
Measure, then fix
The obvious suspect, six weights of one font, cost nothing. The real weight was a blur nobody would guess.
07 · Takeaways
What to keep
- Animate transforms and opacity; take filters off once they’ve done their job, and let idle things cost nothing.
- Give every motion a calm version for reduced motion, and check none is missed.
- Measure a production build before optimising: the heaviest thing on the page is rarely the one you’d guess.
Turn on reduced motion in your system settings, then open the home page and change pages.