UI changes ship a human-reviewable screenshot index
State: open/proposed
Summary
Section titled “Summary”- A UI change ships screenshots of every surface it touches, organized for a human first: grouped by surface or category, captioned, with before and after where a surface changed.
- One static page indexes the set with a table of contents.
- The same organization serves agents reviewing the change.
A PR that changes a UI surface ships all of the following:
- (a) Captured screenshots. Taken by a repeatable driver — a gated Playwright spec or a Storybook capture — light and dark where the surface supports both, at a stated viewport.
- (b) Committed images. Beside the surface’s own docs, at
docs/screenshots/<set>/, named by surface and variant. - (c) A static index. An
index.htmlbeside the images with a left table of contents, one section per category, a caption per image, and before/after pairs where a surface changed. - (d) A PR body that embeds the evidence. The key screenshots, each with a caption and the decision the reviewer should react to, plus a link to the index.
- (e) A current set. A stale committed screenshot is a defect. Regenerate the set for every surface the change touched.
A human reviews by looking. A PR of Vue or component diffs is not reviewable by a product owner, a designer, or anyone who does not read the framework’s markup for a living. Agents reviewing the same change need the same organized evidence, not a second format. Screenshots are the contract for whether a change matches the design; without them, “does it look right” has no answer until someone runs the app. See P-0016-understandable-by-humans.
How to apply
Section titled “How to apply”- Write the capture driver as a gated Playwright spec
(
CAPTURE_SHOTS=1 bunx playwright test ...) or a Storybook capture, following an existing driver’s conventions in the same product: the shell’s own theme toggle rather than color-scheme emulation, a settle pause before the shutter, a fixed viewport such as 1440x900 at 2x. - Commit the PNGs at
docs/screenshots/<set>/, named by surface and variant — a<surface>-{light,dark}.pngpair, or<surface>--<variant>.pngfor a captioned state. - Build
index.htmlbeside the screenshots: a left-hand table of contents grouped by category, one caption per image, before/after pairs shown together where a surface changed. No build step; it opens as a plain file. - In the PR body, embed the screenshots that matter most, each with a caption and the specific decision the reviewer should react to, and link the index page for the full set.
- When a change touches a UI surface, regenerate every screenshot for that surface in the same PR — never update some and leave others stale.
- Reviewers: a UI PR with no screenshot index, or with a screenshot older than the diff it documents, is incomplete. Ask for the set before approving.
Anti-examples
Section titled “Anti-examples”- A PR that changes a Vue component’s markup with no screenshots attached — the diff alone does not show what changed on screen.
- A screenshot set where only some of the surfaces a shared-component change touched were recaptured.
- Screenshots pasted into a PR body with no committed index — a later reviewer or an agent has no way to browse the full set.
- A change with no visual effect — a refactor that renders identically — may cite the existing, unchanged screenshots instead of recapturing them.
- A hotfix may ship before the index is regenerated, if the PR names the follow-up that will update it.
- S-0010-design-language-consumption is the sibling standard for how a surface looks once it ships.