- Shipped
- August 19, 2026 at 5:50 PM UTC
- Author
- Kamo
- Commit
- 849051c
ThemedBackground was the most expensive thing left on the homepage, and none of it looked like a bug. It rendered a raw <img> straight at the theme bucket, so the browser received the untouched source file — 606, 646 and 585 KB, WebP, at full resolution, on a phone. Nothing resized them and nothing served AVIF, because the request never went near the image optimizer. Nothing lazy-loaded them either, and all three instances (Features, Pricing, SignupSection) mount on hydration, so roughly 1.8 MB began downloading at the moment the page was trying to become interactive, for three sections nobody had scrolled to. And each frame was fetched twice: an availability probe built a `new Image()`, waited for it to load in full, and only then set the state that rendered the real element. `onError` is the right tool for that and costs nothing. Through `next/image` each is a lazily-fetched, correctly-sized AVIF on an immutable URL, and the settle is a CSS transition rather than a Framer Motion `animate` on the <img>. `images.qualities` is configured, which is a prerequisite rather than a tuning knob: Next 16 answers 400 for any quality not in that list, and the list defaults to [75] alone — so `quality={50}` was not being ignored, it would have cost the image outright. Quality is now set from how each surface is actually composited, measured rather than guessed. Decoding both encodings and comparing them *after* the page's own filters: hero background brightness(.21) 41.1 dB PSNR 0.57% of pixels differ by >8/255 → quality 50 themed background brightness(.6), grayscale 20%, radial black overlay 36.9 dB PSNR 6.60% of pixels differ by >8/255 → left at 75 The hero is the LCP element and is composited at a fifth of its luminance, so half the bits buy detail that nothing can resolve through that much black: 77.7 KB at the default, 22.0 KB at 50, for a difference 0.57% of pixels can express. The themed frames sit under a much lighter overlay, where the same step reaches 6.6% — enough to band a smooth area of sky across a full-bleed surface. Their saving was never the quality setting anyway; it was the resize and the laziness. The poster frame is measured rather than assumed. A fixed w=828 was three times the pixels the aperture shows on a phone, where it is around 370 CSS px; it is now derived from the element's width and the device pixel ratio, against the configured deviceSizes. 26.5 KB → 7.6 KB on a phone. The two preconnects are dns-prefetch now. A preconnect opens a socket immediately and holds it, which it earns only for an origin needed during the first paint. With the themed photography going through this origin's optimizer, the browser's own first request to theme.kamocrm.com is the chat widget or the hero reel, both deliberately after the load event, and the analytics origin is the same story since the tracker moved to lazyOnload. Lighthouse reported the theme preconnect as unused and it was: a socket opened during the critical path, competing with it, idle until long after it closed. Two things measured and deliberately NOT changed, so they are not re-litigated: · A browserslist targeting modern browsers does not remove the 13.5 KB of polyfills Lighthouse flags **************** Object.fromEntries/hasOwn, **************** They are Next's own `polyfill-module`, included unconditionally; with browserslist set, the containing chunk built byte-identical, same hash. Adding config that demonstrably does nothing is what `optimizeCss` was. · Deleting the 90 of 149 components that are referenced nowhere moves the render-blocking stylesheet by 678 bytes gzip (17,398 → 16,720). Tailwind scanning dead files is not what makes that file 17 KB, so a 90-file deletion cannot be justified as a performance fix. Still open, and not fixable from this repository: kamo-chat.js is served from the theme bucket with no Cache-Control header at all, 143 KB. The HLS playlists' 300s TTL is deliberate — hero-hls-encode-job.yaml rewrites them on re-encode — and is worth 1 KiB, so it stays.