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

  1. Scan captures references. ptb scan saves 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.
  2. Verify screenshots your implementation. With Storybook running locally, ptb verify uses Playwright to capture the component at its default variant and at each additional variant (by passing ?args= overrides to the Storybook URL).
  3. 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.
  4. Per-variant pixel diff. Each variant state gets its own diff against its single-variant Figma reference. pixelMatch in 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.

ScoreStatusTypical cause
≥ 0.90PassImplementation matches design
0.70–0.89WarningMinor spacing, color, or content deviation
< 0.70FailSignificant 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>/:

FileContents
figma.pngFigma reference (cached thumbnail or live export)
impl.pngPlaywright screenshot of the default story
diff.pngAnnotated pixel diff (red = mismatch regions)
report.jsonFull 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 scan again if the Figma design has changed since you last scanned — thumbnails need to be fresh.
  • Storybook stories generated by ptb generate-components are pre-wired to match the Figma default variant, making verification accurate out of the box. Variant args mapping is driven by the component's variantAxes.
  • 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.