Writing

Shaving 400ms off first paint

The hero on this site used to cost 400ms it didn't need to. Lab LCP sat around 2.4s on a throttled mid-tier phone; the Phase 1 budget is under 2.0s. This is how I closed the gap without removing the part that makes the page feel alive.

Where the time actually went

The first version animated the gradient mesh on a <canvas> driven by requestAnimationFrame. It looked great on my laptop and terrible everywhere else: the canvas blocked the main thread during hydration, pushing the largest text block's paint behind a layout it was waiting on. The trace was blunt — a long task at 1.6s that had no business existing.

The fix was to stop running code for something that was, fundamentally, a picture. The whole mesh is now three radial gradients composited by the GPU:

.hero {
  background: var(--mesh-hero);
}

That token (--mesh-hero) is layered radial gradients in OKLCH, defined once in tokens.css. No canvas, no rAF loop, no main-thread work. The hero paints with the rest of the document.

Motion without the cost

I didn't want a static page. The trick is that motion shouldn't be on the critical path. The subtle drift on the mesh is a CSS animation gated behind prefers-reduced-motion and started only after the LCP element has painted, via a one-line IntersectionObserver that adds a class. If the animation never starts, the page is still complete. It's decoration, and it's treated like decoration.

The other 150ms

Two smaller wins finished the job:

  • Font display. The display face was blocking text. Switching to font-display: swap on the variable display font and preloading only the Latin subset removed the invisible-text stall.
  • Prerender, don't fetch. The content routes read Markdown at build time and ship as static HTML. There's no API round-trip on the critical path, so the hero text is in the initial response, not a second waterfall.

Result

Lab LCP landed at 1.98s; field data is still coming in but trending the same way. The lesson I keep relearning: before optimizing the JavaScript, ask whether the JavaScript should run at all. A picture is cheaper than a program.