- Shipped
- August 19, 2026 at 7:17 PM UTC
- Author
- Kamo
- Commit
- 2d7c0c0
The last two rounds took the score from 87 to 67. Total Blocking Time went from 80 ms to 460 ms and LCP from 3.9 s to 4.4 s. Two of my own changes did that, and both were made for the same bad reason. The reason is worth stating first, because it is the actual lesson: the items under "Insights" in that report are marked **Unscored**. They do not feed the performance score. FCP, LCP, TBT, CLS and Speed Index do. I spent two rounds optimising unscored insights and paid for them in the scored metrics. `experimental.inlineCss` — reverted. It does what it promises: the stylesheet stops being a render-blocking request. But 93 KB of CSS then has to arrive and be parsed *inside* the document parse rather than in parallel beside it, and the document went from 36 KB gzip to 74.7 KB. Lighthouse measured the document alone at 750 ms of CPU, and Style & Layout rose from 573 ms to 826 ms. One immutable, cacheable, parallel request is better than that, and "render-blocking requests" was never scored. The headline's compositable sweep — reverted. This one is more embarrassing, because it failed on its own terms: the non-composited element count went UP, from 34 to 41. Two text-clipped masked layers cannot be composited either, so the replacement was two paint-animated elements where there had been one, plus a permanently running double raster of the h1. The original single-element version is back. What replaces both is the change that should have been made first. Twenty-five rules on this page declare an infinite animation — hexagon fields drifting, meshes pulsing, gradients sliding, particles floating, banner shimmer. On a desktop nobody notices. On the low-power phone a run emulates, they are a permanent tax: most of Style & Layout, most of Rendering, and every one of them counted under the non-composited animation audit. None of it is content; the page reads identically with all of it still. They now stop below 768 px — the same breakpoint Hero already uses to decide `desktopMotion`, so the particle field, the background rotation and this switch together rather than at three different widths — and under `prefers-reduced-motion`. All 25 are covered. Each is pinned to the value its keyframe rests at rather than only being switched off: an element whose 0%/100% frame sets `opacity: 0.05` has no opacity of its own to fall back to, and stopping it unpinned would either black out a texture or leave a full-opacity overlay across the content under it. The themed section backdrops now request half-viewport widths on phones. At quality 60 they halve in size, but 4.08% of their pixels shift perceptibly once composited, and banding across a smooth sky is what a full-bleed backdrop shows worst — the same objection that rejected quality 50 at 6.60%. Dropping the requested width instead takes one from 193 KB to 77 KB with no compression artifacts at all, on a picture already darkened to 60% under a radial black overlay, behind opaque content. Quality stays at 75. Also fixed, and separately from this commit: the HLS playlists were still answering `max-age=300` because the encode job only rewrites them on a re-encode. Their metadata is set directly now, so the 1 KiB cache-lifetime item is closed without waiting for one. One real bug caught on the way: the CSS surgery above left a stray closing brace at line 1480. Turbopack had been serving cached CSS, so three builds passed before a clean one failed on it. It would have failed CI.