Figure contract
Screenshots are the part of a manual that rots fastest. This contract exists so a stale figure is a build failure rather than something a reader discovers.
One id, one master
A figure's id is its filename stem, kebab-case and unique across the whole site:
static/img/figures/<module>/<area>/<nn>-<what-it-shows>.png
→ id: intelie-konnect/import-create/02-list-empty
Masters are 2880×1800 PNG — a 1440×900 viewport at 2× — committed to this repo and never served to a browser. Because they are byte-stable, a diff on a master means the product really changed.
The id is identical whether the shot came from the capture harness or from someone's keyboard, so a page cannot tell the difference.
Using one
<Figure
id="intelie-konnect/import-create/02-list-empty"
alt="The Import Connectors list with no connectors, showing the message No Connectors found."
caption="An empty list — the starting point."
priority
/>
alt is required and non-empty; the build throws otherwise. Write what a sighted reader
would see, in a sentence. caption says why the figure is there. Add priority to the
first figure on a page only — it is usually the largest thing the reader waits for.
Numbered callouts are rendered from percentage coordinates, never baked into pixels, so they stay readable to a screen reader and survive a recapture.
What happens to it at build time
npm run images turns each master into AVIF and WebP at four widths, plus a wider variant
for click-to-zoom and a tiny blurred placeholder so nothing pops in white. The largest
variant a browser can use is 1600px, because the text column is 800px — serving the master
would waste most of its bytes.
Derivatives are generated, hashed and gitignored. The repo holds masters only.
Missing figures are visible, then fatal
A figure with no master renders a dashed Screenshot pending capture box carrying its id,
so gaps are obvious in review instead of silent. STRICT_FIGURES=1 promotes that to a build
failure, which is how release builds are gated.
Prefer omitting a figure to referencing one you have not captured — an unwritten page with no figures is honest; a page full of pending boxes is not.
The release gate
Two things are fine while drafting and unacceptable in public: an uncaptured figure, and a
page still marked draft_stub: true. Both warn on an ordinary build and both fail under
npm run verify:release
which is npm run verify with STRICT_FIGURES=1 and STRICT_STUBS=1 set. Use it before
publishing; use plain verify while writing, so a half-finished section never blocks the
build you are iterating on.
Keeping them honest
| Command | What it does |
|---|---|
npm run figures:list | Scans the MDX for every referenced figure and writes the capture work list. |
npm run figures:check | Reports missing masters, orphaned files, dangling references and duplicate images. Always fatal. |
make figures m=<module> | Re-captures a module against the running local stack. |
make figures-bootstrap | Creates the dedicated capture workspace the harness signs in as. |
The duplicate check matters more than it sounds: two figures with identical bytes almost always means a capture step silently did nothing.
Capture rules
Captures use a fixed viewport, the light theme, UK English, UTC, reduced motion and a frozen clock, and they mask generated ids and timestamps. Re-running a capture twice must produce no file changes — if it does, something non-deterministic is leaking into the image, and that is a harness bug rather than something to commit.
A handful of figures cannot be automated: third-party sign-in screens and file pickers belong to other companies. Those are captured by hand into the same path and the same contract.
Next
- House style — voice, length and structure.
- Page template — where figures sit on a page.