Visual Verification for Design Review
Why this exists: SquadScope's 6-phase editorial redesign (issues #170–#177) has shipped; the original proposal is archived at
docs/processed/redesign-proposal-2026-05.md. Ongoing look-and-feel work continues under the design epic #357 and its children. Layout, token, and typography changes still need regression evidence. This doc explains how Calculon (Designer) catches regressions before they ship.
Why We Do This
The redesign proposal defines explicit acceptance criteria per phase — heading scale, palette tokens, contrast ratios, layout breakpoints. Without screenshots, design review is reading diffs and hoping. Playwright lets us:
- See the page as a reader would at 4 viewport widths
- Verify light and dark mode in the same pass
- Catch regressions automatically once a baseline exists
- Attach evidence screenshots to PR comments
Related: docs/processed/redesign-proposal-2026-05.md
Prerequisites
- Hugo installed —
hugo versionshould return ≥ v0.100 - Node.js ≥ 18 —
node --version - Playwright Chromium — install once:
npx playwright install chromium --with-deps
That's it. No npm install needed — run everything via npx.
How to Run Locally
Quick screenshot pass (standalone script)
# 1. Start Hugo with drafts
hugo server -D --bind 0.0.0.0
# 2. In a second terminal, run the capture script
node scripts/design/verify-visual.mjs
# Screenshots land in:
# screenshots/design-verification/2026-05-25/
Each filename follows the pattern: {page}-{viewport}-{theme}.png
Example: home-desktop-dark.png, weekly-w22-mobile-light.png
A manifest.json is written to the same folder with pass/fail status.
Playwright snapshot regression test
# 1. Start Hugo
hugo server -D --bind 0.0.0.0
# 2. Generate baselines (run ONCE on the main branch):
npx playwright test --config tests/visual/playwright.config.mjs --update-snapshots
# 3. On PR branch — compare against baselines:
npx playwright test --config tests/visual/playwright.config.mjs
Test results appear at playwright-report/index.html (open in browser).
Snapshot baselines are saved to tests/visual/snapshots/.
Matrix Covered
Viewports
| Name | Width | Height |
|---|---|---|
| mobile | 375 | 667 |
| tablet | 768 | 1024 |
| desktop | 1280 | 800 |
| wide | 1920 | 1080 |
Themes
| Mode | Playwright setting |
|---|---|
| light | colorScheme: 'light' |
| dark | colorScheme: 'dark' |
Pages
| Key | URL path |
|---|---|
| home | / |
| latest-weekly | /weekly/2026/w22/ |
| monthly-rollup | /monthly/2026/05/ |
| yearly-rollup | /yearly/2026/ |
Total: 4 pages × 4 viewports × 2 themes = 32 screenshots per pass
How Calculon Uses This in PR Review
- Checkout the PR branch, start Hugo.
- Run
node scripts/design/verify-visual.mjs. - Open the screenshots. Compare to the acceptance criteria table for the relevant redesign phase in
docs/processed/redesign-proposal-2026-05.md. - Run
npx playwright test --config tests/visual/playwright.config.mjsto get a diff count vs. baseline. - Post a PR comment (template in
.squad/skills/design-visual-verification/SKILL.md) with:- The summary table (✅ / ⚠️ per cell)
- Any mismatches against spec with screenshot attachments
- Approve or request changes
Updating Baselines
Baselines should be updated when a design change is intentional — i.e., a redesign phase has been approved and merged to main.
# After phase N merges to main:
git checkout main && git pull
hugo server -D --bind 0.0.0.0 &
npx playwright test --config tests/visual/playwright.config.mjs --update-snapshots
kill %1 # stop Hugo
git add tests/visual/snapshots/
git commit -m "chore: update visual baselines after phase N merge [skip ci]"
git push
Never update baselines on a PR branch — that defeats the purpose of regression testing.
Known Limitations
| Issue | Impact | Workaround |
|---|---|---|
| Cost dashboard run date | Changes every crawl — always fails snapshot diff | Suppressed via visibility: hidden in NOISE_SUPPRESSION_CSS (in both the script and spec) |
| Dynamic repo counters | Same — live data | Same suppression |
| Web font rendering | Sub-pixel differences between OS/CI | maxDiffPixels: 150 threshold in Playwright config |
| Hugo draft pages | Pages with draft: true won't appear |
Run Hugo with -D flag |
| Dynamic shortcodes | Any shortcode pulling live data will vary | Identify per-shortcode and add CSS suppression selectors |
| OS rendering differences | macOS vs Linux produce different font metrics | Always run baseline and comparison on the same OS |
Files Reference
| File | Purpose |
|---|---|
scripts/design/verify-visual.mjs |
Standalone capture script — now includes the added 320/360/390/414 mobile widths |
scripts/design/lighthouse-gates.mjs |
Lighthouse accessibility / best-practices / CLS gate runner |
tests/visual/playwright.config.mjs |
Playwright config for snapshot regression tests |
tests/visual/visual.spec.mjs |
Snapshot specs for each page |
tests/visual/a11y-perf.spec.mjs |
Playwright viewport gate checks for overflow, tap targets, and pre-content height |
tests/visual/snapshots/ |
Committed baseline screenshots |
screenshots/design-verification/ |
Ad-hoc capture output (gitignored) |
.squad/skills/design-visual-verification/SKILL.md |
Full skill pattern for the team |
Accessibility & Performance Gates
The design review flow now includes a lightweight gate pass focused on mobile resilience and Lighthouse regressions.
Gate viewport matrix
320×568360×640390×844414×896768×1024
Checks performed
- No horizontal overflow (
document.documentElement.scrollWidth <= document.documentElement.clientWidth) - Tap targets for all visible
<a>and<button>elements are at least44×44pxunless explicitly marked withdata-small-ok - Home-page pre-content height guard: the main content container (
.main,main, or#main-content) must begin within600pxof the top edge at320–414px - Lighthouse mobile gates on
/,/weekly/2026/w22/,/monthly/2026/05/, and/yearly/2026/
Thresholds
- Accessibility score ≥
95 - Best Practices score ≥
95 - CLS ≤
0.1 - Tap targets ≥
44×44 - No horizontal scrolling
- Pre-content start ≤
600pxon home at mobile widths
How to run
npx playwright test --config tests/visual/playwright.config.mjs tests/visual/a11y-perf.spec.mjs
node scripts/design/lighthouse-gates.mjs
PR review summary (Fry)
Fry should summarize the gate pass as a page-by-page matrix, call out any tap-target or pre-content exceptions that need data-small-ok, and include the Lighthouse score table with any threshold failures highlighted for reviewers.
Established: 2026-05-25 — Calculon (Designer)