overhaul: assets & performance (media pipeline, Lighthouse CI budgets) - #25
Open
CS-5 wants to merge 3 commits into
Open
overhaul: assets & performance (media pipeline, Lighthouse CI budgets)#25CS-5 wants to merge 3 commits into
CS-5 wants to merge 3 commits into
Conversation
Deletes public/image entirely (33 files, 5.4 MB — nothing in src/ or the build referenced any of them), re-encodes the hero video from 36.9 MB across two formats to 1.7 MB, and makes Lighthouse CI a blocking PR check. Images: HeroImage.astro replaces six identical attributes at eleven hero call sites, every photographic <Image> carries PHOTO_QUALITY, and every responsive one carries an explicit width so Astro stops emitting a full-resolution fallback nobody displays. Largest emitted variant 436 KB -> 199 KB. Hero video: 720p H.264 + VP9 of a 10.5 s cut, behind HeroVideo.astro, which arms an IntersectionObserver only after load and only when the visitor has neither asked for reduced motion nor turned on Save-Data. Three ADRs record where the measurements contradicted plan/09: WebP-only variants (0005), the video encode (0006), the Lighthouse gate's shape (0007), and the font preloads that were costing ~660 ms of LCP (0008). Medians of three runs: Perf 99-100, A11y 100, SEO 100, BP 96-100, CLS 0.000, TBT 0, LCP 1210-1958 ms across the six budgeted URLs. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CxssDiw8XBERsuHMQZTtCr
Three runs per URL produce a bimodal LCP under Lantern — either ~1.2 s or ~2.0 s, nothing between, tracking a ~750 ms step in simulated FCP that appears run to run on an idle machine. Five runs of /programs/frc/robots/: 1212, 1218, 2039, 2109, 2110 ms. lighthouserc.json now sets aggregationMethod: "optimistic" rather than inheriting it as a default, so the gate's meaning is stated: best of three has to clear 2000 ms. Two of the six budgeted pages have runs above it, which the phase's As-built table now reports as run triples instead of a median that would read as a contradiction of a green gate. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CxssDiw8XBERsuHMQZTtCr
@fontsource-variable/inter ships wght 100 900. DESIGN.md §3 sanctions 400/500/600 for Inter and nothing in the tree exceeds it — the two font-bold call sites are Orbitron — so more than half the axis was delta data for weights that never render. Instancing to 400 700 takes the face on the critical path from 47.1 KB to 35.2 KB, and the latin-ext face it sits beside from 83.1 KB to 57.9 KB. That 12 KB is what collapsed the bimodal LCP. Before: clusters around 1.2 s and 2.1 s with nothing between, and two of the six budgeted URLs had runs above the 2000 ms budget. After: every run on every URL is under it, worst 1953 ms. So lighthouserc.json asserts on the median of three runs rather than the best, which is what the budget was always supposed to mean. Orbitron and Source Code Pro were measured and left alone: 0.7 KB and 3.2 KB, not worth narrowing what the design may reach for. DESIGN.md §3 gains a note that Inter can no longer render above 700, since that is where someone would look before reaching for a heavier weight. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01CxssDiw8XBERsuHMQZTtCr
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Phase 09 of the stacked overhaul (
plan/09-assets-performance.md), stacked on #24 per D23.What this does
public/+src/assets/: 72 MB → 11 MB.public/image/is deleted in full — 33 files, 5.4 MB. Nothing insrc/,functions/,tools/, or the built output referenced any of them: the unDraw set retired with DESIGN.md §7, the pattern SVGs with the engineering grid (§2.3),meta.pngwithpublic/og/default.png, and the rest are Docusaurus-era leftovers. Everything a page renders had already moved tosrc/assets/in Phase 04.+faststart. Encode parameters and reasoning in ADR 0006; largest remaining image source is 470 KB.Images.
HeroImage.astro. Eleven heroes were repeating the same six<Image>attributes; they now render one component.class="h-full w-full object-cover"went with them —Hero's own style already sizes whatever lands in itsmediaslot.PHOTO_QUALITY, and every responsive one carries an explicitwidthequal to its widestwidthsentry. Without it Astro fills thesrcfallback from the source's intrinsic size, which was emitting a 436 KB variant no page displays. Largest emitted image is now 199 KB.Fonts. Two changes, and they are what actually met the LCP budget:
<link rel="preload">font tags are gone (ADR 0008). 61 KB of High-priority font was queued from<head>ahead of the render-blocking stylesheet and well ahead of the hero<img>, on pages whose LCP element is always a photograph. Removing them: FCP 1054 → 766 ms, LCP 2028 → 1366 ms on/programs/frc/robots/, CLS 0.000 either way.@fontsource-variable/intershipswght 100 900; DESIGN.md §3 sanctions 400/500/600 and nothing in the tree exceeds it — the twofont-boldcall sites are Orbitron. 47.1 KB → 35.2 KB on the critical path, 83.1 KB → 57.9 KB for the latin-ext face beside it.pnpm assets:fonts, output committed, and DESIGN.md §3 now notes that Inter cannot render heavier.Hero video behaviour (D20).
HeroVideo.astrorenders the poster as a real<Image>— so it gets a responsive ladder, whichposter=cannot — with the video over it atpreload="none". Playback arms only afterload, and only when the visitor has neither asked for reduced motion nor turned on Save-Data.Lighthouse CI is a blocking check.
.github/workflows/lighthouse.yml+lighthouserc.json, six URLs, three runs each.Measured
Every assertion passes, on the median of three runs:
//programs/frc//programs/frc/robots//sponsors//openhouse//contact//contact/'s Best Practices is 96 because of the Turnstile widget's third-party script; the threshold is 0.95 and the widget is the form's spam defence.How the LCP budget was met, and why the aggregation says
median. Before trimming Inter, LCP was bimodal — clusters around 1.2 s and 2.1 s with nothing between — and/programs/frc/robots/and/sponsors/each had runs above the 2000 ms budget (1355 / 2108 / 2110 and 1210 / 2032 / 2036). Chasing it structurally got nowhere: an LCP-image<link rel="preload">moved the median by 2 ms. Taking 12 KB off the critical path is what collapsed it. Every run on every budgeted URL is now under 2000 ms, worst 1953 ms, so the gate asserts on the median rather than the best run — which is what the budget was always supposed to mean.Deviations from the brief, each with an ADR
<Picture>exposes no per-format effort knob. Full measurement table in the ADR.@lhci/cliruns throughpnpm dlxat a pinned version, not as a devDependency — ADR 0007. It brings Lighthouse and Puppeteer, for a tool nobody runs while writing a page.Notes for the reviewer
tools/assets/optimize-sources.mjsis at its fixpoint — a dry run reports zero changes across the relocated inventory. That is the "refuses changes with no meaningful gain" floor working as designed; the re-encode §2 asks for happened in Phase 04.loading={index === 0 ? "eager" : "lazy"}was left alone. It reads like a below-the-fold eager fetch, but index 0 is a season with no photo yet, so the eager branch never renders — confirmed against the built HTML, where every robot image is lazy.pnpm build: the video encode (ffmpeg, ADR 0006) and the font instancing (pnpm assets:fonts, needs Python withfonttoolsandbrotli, ADR 0011). Both change when the source material or DESIGN.md §3 changes, which is not per-build. Masters live in git history.docs/tooling.md;pnpm check && pnpm buildgreen.Verification
Lighthouse driven against the production preview (
astro preview, which gzips — verified, so the measurement is comparable to what Cloudflare serves) in the pre-installed Chromium. The trimmed Inter was checked in a browser to confirm all four weights interpolate rather than synthesize (measured glyph-run widths at 400/500/600/700: 521 / 531 / 538 / 542 px).