Visual Verification
ptb verify catches visual drift between your code and the Figma design by comparing a screenshot of your running component against the thumbnail captured during ptb scan. No live Figma connection required at verify time.
How it Works
- Scan captures references.
ptb scansaves a grid thumbnail for each component to.ptb/thumbnails/<slug>.png. For components with variants, it also exports a per-variant PNG for every variant state — the ground truth for each. - Verify screenshots your implementation. With Storybook running locally,
ptb verifyuses Playwright to capture the component at its default variant and at each additional variant (by passing?args=overrides to the Storybook URL). - Multi-signal verdict. Three scores are computed and combined in priority order:
- Token score (primary): fraction of Figma design text tokens found in the rendered DOM — catches wrong content, placeholder text, missing labels.
- Structure score: fraction of expected text and image slots present in the DOM — catches missing sections without caring about exact pixel alignment.
- Pixel score: full-frame pixel diff similarity — the final visual check.
- Per-variant pixel diff. Each variant state gets its own diff against its single-variant Figma reference.
pixelMatchin the report is set to the worst variant — a single failing variant cannot hide behind a passing default.
CLI Usage
ptb verify component Button # verify a single component (all variants)
ptb verify component . # verify all implemented components
ptb verify component Button --story Primary # target a specific Storybook story
ptb verify component Button --fresh-figma # re-fetch reference live from Figma API
Storybook must be running on
localhost:6006— the port PTB's generated stories and verify pipeline assume for the CLI verify to work.
MCP Usage
From your AI IDE chat:
run_verify({ name: "Button" })
run_verify({ name: "Button", story: "Primary" })
The AI can read the diff image and adjust styles to fix failing areas without you describing what's wrong.
Interpreting Results
The verdict is driven by whichever score is available, in priority order: token → structure → pixel.
| Score | Status | Typical cause |
|---|---|---|
| ≥ 0.90 | Pass | Implementation matches design |
| 0.70–0.89 | Warning | Minor spacing, color, or content deviation |
| < 0.70 | Fail | Significant structural difference |
ptb status shows the Visual column only after at least one ptb verify run. The column reflects the worst score across all variants.
Output files
All output is written to .ptb/verify/<slug>/:
| File | Contents |
|---|---|
figma.png | Figma reference (cached thumbnail or live export) |
impl.png | Playwright screenshot of the default story |
diff.png | Annotated pixel diff (red = mismatch regions) |
report.json | Full report: pixelMatch, tokenScore, structureScore, variantResults[], variantMeanScore |
report.json includes per-variant results when the component has multiple variants:
{
"pixelMatch": { "score": 0.87 },
"tokenScore": 0.92,
"structureScore": 1.0,
"variantMeanScore": 0.91,
"variantResults": [
{ "selection": { "Size": "sm", "State": "Default" }, "pixelMatch": { "score": 0.93 } },
{ "selection": { "Size": "lg", "State": "Hover" }, "pixelMatch": { "score": 0.87 } }
]
}
pixelMatch.score is always the worst variant score — it is what ptb status --fail-on-stale checks.
Tips
- Run
ptb scanagain if the Figma design has changed since you last scanned — thumbnails need to be fresh. - Storybook stories generated by
ptb generate-componentsare pre-wired to match the Figma default variant, making verification accurate out of the box. Variant args mapping is driven by the component'svariantAxes. - Use
ptb verify component .after bulk implementing all components to catch regressions before stamping. - If a variant's Storybook
?args=override doesn't bind correctly, check that the generated story prop name matches the Figma variant axis name (converted to camelCase).
Next Steps
Once implementation passes verification, stamp it with State & Freshness Commands.