Problem
docs/hero.png (the README hero) is a raster screenshot of the Dashboard pattern from docs/patterns.html. Because it's a baked PNG, any design change that affects that pattern — logo swap, token change, component restyle — silently leaves the hero stale until someone notices and re-captures it by hand. This has already bitten us twice during the logo swap (the old key glyph lingered in the hero after the live pattern was updated).
It's annoying to remember and do manually. We want it cued automatically.
Trigger surface
The hero should be considered stale whenever any of these change:
docs/patterns.html — the #dashboard .pattern-frame block (currently lines ~74–244)
docs/docs.css — .pattern-frame, .sidebar, and related chrome
lib/globals.css, lib/components.css — tokens + components the pattern consumes
- the logo mark (
logo.svg / the inline mark in the pattern)
Proposed approach
A small script + CI step (or a pre-push/make hero target) that:
- Builds an isolated capture page from the real source slices (no manual transcription), then
- Renders it headless and writes
docs/hero.png, failing CI if the committed PNG differs from the freshly rendered one (so a stale hero blocks merge).
Known-good recipe (used to regenerate the hero on 2026-06-15)
Assemble docs/capture.html from live slices:
- shared
<head> CSS links (fonts + ../lib/globals.css + ../lib/components.css + docs.css)
- the page's inline
<style> block (patterns.html lines 15–59)
- a capture wrapper:
.capture-wrap { width: 952px; box-sizing: border-box; padding: 16px; } on background: var(--surface-page)
- the dashboard
.pattern-frame markup (patterns.html lines 74–244)
Render at 2x to match the original 1904×1286:
CHROME="/Applications/Google Chrome.app/Contents/MacOS/Google Chrome"
"$CHROME" --headless=new --disable-gpu --hide-scrollbars \
--force-device-scale-factor=2 --window-size=952,643 \
--virtual-time-budget=6000 \
--screenshot="$PWD/docs/hero.png" "file://$PWD/docs/capture.html"
rm -f docs/capture.html
Line numbers above will drift — the script should anchor on markers (e.g. id="dashboard" … next <h2) rather than hardcoded ranges, or the dashboard frame should be extracted into its own includable partial.
Notes
Problem
docs/hero.png(the README hero) is a raster screenshot of the Dashboard pattern fromdocs/patterns.html. Because it's a baked PNG, any design change that affects that pattern — logo swap, token change, component restyle — silently leaves the hero stale until someone notices and re-captures it by hand. This has already bitten us twice during the logo swap (the old key glyph lingered in the hero after the live pattern was updated).It's annoying to remember and do manually. We want it cued automatically.
Trigger surface
The hero should be considered stale whenever any of these change:
docs/patterns.html— the#dashboard.pattern-frameblock (currently lines ~74–244)docs/docs.css—.pattern-frame,.sidebar, and related chromelib/globals.css,lib/components.css— tokens + components the pattern consumeslogo.svg/ the inline mark in the pattern)Proposed approach
A small script + CI step (or a pre-push/
make herotarget) that:docs/hero.png, failing CI if the committed PNG differs from the freshly rendered one (so a stale hero blocks merge).Known-good recipe (used to regenerate the hero on 2026-06-15)
Assemble
docs/capture.htmlfrom live slices:<head>CSS links (fonts +../lib/globals.css+../lib/components.css+docs.css)<style>block (patterns.htmllines 15–59).capture-wrap { width: 952px; box-sizing: border-box; padding: 16px; }onbackground: var(--surface-page).pattern-framemarkup (patterns.htmllines 74–244)Render at 2x to match the original 1904×1286:
Line numbers above will drift — the script should anchor on markers (e.g.
id="dashboard"… next<h2) rather than hardcoded ranges, or the dashboard frame should be extracted into its own includable partial.Notes