Installs the per-project half of the visual-verify skill. The skill itself is portable; what varies
per project is how to render a UI state. This setup detects that, pins it in writing, and
ships the screenshot script.
1. Detect the render surface
Look before asking — recommend, don't present a blank menu:
.storybook/present → Storybook (best: stories enumerate states).- A design-handoff studies dir → studies (screenshot the HTML directly).
- A
dev/startscript serving UI → dev server. - Several present → Storybook for components, studies for unbuilt designs; say so.
Confirm the choice with the user, along with anything non-obvious you found (custom ports, auth walls, build steps).
2. Install the screenshot script
Copy templates/screenshot-states.mjs to scripts/screenshot-states.mjs in the project.
It needs Playwright: use the project's existing playwright devDependency if there is one;
otherwise note that the visual-verify skill will run it via npx playwright and skip adding a
dependency.
3. Declare the method in AGENTS.md
Append a section so any agent — including one that never runs this wizard — knows how to render states. Template, adapted to what was detected:
## Visual verification
UI diffs are visually verified before a PR opens (see the `visual-verify` skill). To render
states in this project: <the detected method — e.g. "`bun run build-storybook`, serve
`storybook-static/` on a free port, states are story URLs via
`iframe.html?id=<story-id>&viewMode=story`">. Screenshot with
`node scripts/screenshot-states.mjs <states.json> <out-dir>`. UI tickets end with
the `visual-verify` skill; screenshots are published to a throwaway `refs/pr-screenshots/<branch-slug>`
ref (never committed to the branch) and embedded in the PR body via raw URLs.
4. Optional — pixel-diff regression tests
Distinct layer, separate opt-in: committed screenshot baselines over the project's stories
(vitest browser mode toMatchScreenshot, or Playwright toHaveScreenshot against the static
Storybook build) with a CI gate, so blessed UI can't drift silently. Offer it only when the
project has Storybook + CI; if accepted, wire it with baselines generated in one
environment only (CI or a container — cross-OS font rendering false-positives otherwise),
animations disabled, dynamic regions masked.