| 1 | # Visual Verification for Design Review |
| 2 | |
| 3 | > **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. |
| 4 | |
| 5 | --- |
| 6 | |
| 7 | ## Why We Do This |
| 8 | |
| 9 | 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: |
| 10 | |
| 11 | - See the page as a reader would at 4 viewport widths |
| 12 | - Verify light *and* dark mode in the same pass |
| 13 | - Catch regressions automatically once a baseline exists |
| 14 | - Attach evidence screenshots to PR comments |
| 15 | |
| 16 | Related: [`docs/processed/redesign-proposal-2026-05.md`](../processed/redesign-proposal-2026-05.md) |
| 17 | |
| 18 | --- |
| 19 | |
| 20 | ## Prerequisites |
| 21 | |
| 22 | 1. **Hugo installed** — `hugo version` should return ≥ v0.100 |
| 23 | 2. **Node.js ≥ 18** — `node --version` |
| 24 | 3. **Playwright Chromium** — install once: |
| 25 | |
| 26 | ```bash |
| 27 | npx playwright install chromium --with-deps |
| 28 | ``` |
| 29 | |
| 30 | That's it. No `npm install` needed — run everything via `npx`. |
| 31 | |
| 32 | --- |
| 33 | |
| 34 | ## How to Run Locally |
| 35 | |
| 36 | ### Quick screenshot pass (standalone script) |
| 37 | |
| 38 | ```bash |
| 39 | # 1. Start Hugo with drafts |
| 40 | hugo server -D --bind 0.0.0.0 |
| 41 | |
| 42 | # 2. In a second terminal, run the capture script |
| 43 | node scripts/design/verify-visual.mjs |
| 44 | |
| 45 | # Screenshots land in: |
| 46 | # screenshots/design-verification/2026-05-25/ |
| 47 | ``` |
| 48 | |
| 49 | Each filename follows the pattern: `{page}-{viewport}-{theme}.png` |
| 50 | Example: `home-desktop-dark.png`, `weekly-w22-mobile-light.png` |
| 51 | |
| 52 | A `manifest.json` is written to the same folder with pass/fail status. |
| 53 | |
| 54 | ### Playwright snapshot regression test |
| 55 | |
| 56 | ```bash |
| 57 | # 1. Start Hugo |
| 58 | hugo server -D --bind 0.0.0.0 |
| 59 | |
| 60 | # 2. Generate baselines (run ONCE on the main branch): |
| 61 | npx playwright test --config tests/visual/playwright.config.mjs --update-snapshots |
| 62 | |
| 63 | # 3. On PR branch — compare against baselines: |
| 64 | npx playwright test --config tests/visual/playwright.config.mjs |
| 65 | ``` |
| 66 | |
| 67 | Test results appear at `playwright-report/index.html` (open in browser). |
| 68 | Snapshot baselines are saved to `tests/visual/snapshots/`. |
| 69 | |
| 70 | --- |
| 71 | |
| 72 | ## Matrix Covered |
| 73 | |
| 74 | ### Viewports |
| 75 | |
| 76 | | Name | Width | Height | |
| 77 | |------|-------|--------| |
| 78 | | mobile | 375 | 667 | |
| 79 | | tablet | 768 | 1024 | |
| 80 | | desktop | 1280 | 800 | |
| 81 | | wide | 1920 | 1080 | |
| 82 | |
| 83 | ### Themes |
| 84 | |
| 85 | | Mode | Playwright setting | |
| 86 | |------|--------------------| |
| 87 | | light | `colorScheme: 'light'` | |
| 88 | | dark | `colorScheme: 'dark'` | |
| 89 | |
| 90 | ### Pages |
| 91 | |
| 92 | | Key | URL path | |
| 93 | |-----|----------| |
| 94 | | home | `/` | |
| 95 | | latest-weekly | `/weekly/2026/w22/` | |
| 96 | | monthly-rollup | `/monthly/2026/05/` | |
| 97 | | yearly-rollup | `/yearly/2026/` | |
| 98 | |
| 99 | **Total:** 4 pages × 4 viewports × 2 themes = **32 screenshots per pass** |
| 100 | |
| 101 | --- |
| 102 | |
| 103 | ## How Calculon Uses This in PR Review |
| 104 | |
| 105 | 1. **Checkout the PR branch**, start Hugo. |
| 106 | 2. Run `node scripts/design/verify-visual.mjs`. |
| 107 | 3. Open the screenshots. Compare to the acceptance criteria table for the relevant redesign phase in `docs/processed/redesign-proposal-2026-05.md`. |
| 108 | 4. Run `npx playwright test --config tests/visual/playwright.config.mjs` to get a diff count vs. baseline. |
| 109 | 5. Post a PR comment (template in `.squad/skills/design-visual-verification/SKILL.md`) with: |
| 110 | - The summary table (✅ / ⚠️ per cell) |
| 111 | - Any mismatches against spec with screenshot attachments |
| 112 | - Approve or request changes |
| 113 | |
| 114 | --- |
| 115 | |
| 116 | ## Updating Baselines |
| 117 | |
| 118 | Baselines should be updated when a design change is **intentional** — i.e., a redesign phase has been approved and merged to `main`. |
| 119 | |
| 120 | ```bash |
| 121 | # After phase N merges to main: |
| 122 | git checkout main && git pull |
| 123 | hugo server -D --bind 0.0.0.0 & |
| 124 | npx playwright test --config tests/visual/playwright.config.mjs --update-snapshots |
| 125 | kill %1 # stop Hugo |
| 126 | git add tests/visual/snapshots/ |
| 127 | git commit -m "chore: update visual baselines after phase N merge [skip ci]" |
| 128 | git push |
| 129 | ``` |
| 130 | |
| 131 | **Never update baselines on a PR branch** — that defeats the purpose of regression testing. |
| 132 | |
| 133 | --- |
| 134 | |
| 135 | ## Known Limitations |
| 136 | |
| 137 | | Issue | Impact | Workaround | |
| 138 | |-------|--------|------------| |
| 139 | | 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) | |
| 140 | | Dynamic repo counters | Same — live data | Same suppression | |
| 141 | | Web font rendering | Sub-pixel differences between OS/CI | `maxDiffPixels: 150` threshold in Playwright config | |
| 142 | | Hugo draft pages | Pages with `draft: true` won't appear | Run Hugo with `-D` flag | |
| 143 | | Dynamic shortcodes | Any shortcode pulling live data will vary | Identify per-shortcode and add CSS suppression selectors | |
| 144 | | OS rendering differences | macOS vs Linux produce different font metrics | Always run baseline and comparison on the same OS | |
| 145 | |
| 146 | --- |
| 147 | |
| 148 | ## Files Reference |
| 149 | |
| 150 | | File | Purpose | |
| 151 | |------|---------| |
| 152 | | `scripts/design/verify-visual.mjs` | Standalone capture script — now includes the added 320/360/390/414 mobile widths | |
| 153 | | `scripts/design/lighthouse-gates.mjs` | Lighthouse accessibility / best-practices / CLS gate runner | |
| 154 | | `tests/visual/playwright.config.mjs` | Playwright config for snapshot regression tests | |
| 155 | | `tests/visual/visual.spec.mjs` | Snapshot specs for each page | |
| 156 | | `tests/visual/a11y-perf.spec.mjs` | Playwright viewport gate checks for overflow, tap targets, and pre-content height | |
| 157 | | `tests/visual/snapshots/` | Committed baseline screenshots | |
| 158 | | `screenshots/design-verification/` | Ad-hoc capture output (gitignored) | |
| 159 | | `.squad/skills/design-visual-verification/SKILL.md` | Full skill pattern for the team | |
| 160 | |
| 161 | --- |
| 162 | |
| 163 | |
| 164 | ## Accessibility & Performance Gates |
| 165 | |
| 166 | The design review flow now includes a lightweight gate pass focused on mobile resilience and Lighthouse regressions. |
| 167 | |
| 168 | ### Gate viewport matrix |
| 169 | |
| 170 | - `320×568` |
| 171 | - `360×640` |
| 172 | - `390×844` |
| 173 | - `414×896` |
| 174 | - `768×1024` |
| 175 | |
| 176 | ### Checks performed |
| 177 | |
| 178 | - No horizontal overflow (`document.documentElement.scrollWidth <= document.documentElement.clientWidth`) |
| 179 | - Tap targets for all visible `<a>` and `<button>` elements are at least `44×44px` unless explicitly marked with `data-small-ok` |
| 180 | - Home-page pre-content height guard: the main content container (`.main`, `main`, or `#main-content`) must begin within `600px` of the top edge at `320–414px` |
| 181 | - Lighthouse mobile gates on `/`, `/weekly/2026/w22/`, `/monthly/2026/05/`, and `/yearly/2026/` |
| 182 | |
| 183 | ### Thresholds |
| 184 | |
| 185 | - Accessibility score ≥ `95` |
| 186 | - Best Practices score ≥ `95` |
| 187 | - CLS ≤ `0.1` |
| 188 | - Tap targets ≥ `44×44` |
| 189 | - No horizontal scrolling |
| 190 | - Pre-content start ≤ `600px` on home at mobile widths |
| 191 | |
| 192 | ### How to run |
| 193 | |
| 194 | ```bash |
| 195 | npx playwright test --config tests/visual/playwright.config.mjs tests/visual/a11y-perf.spec.mjs |
| 196 | node scripts/design/lighthouse-gates.mjs |
| 197 | ``` |
| 198 | |
| 199 | ### PR review summary (Fry) |
| 200 | |
| 201 | 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. |
| 202 | |
| 203 | --- |
| 204 | |
| 205 | *Established: 2026-05-25 — Calculon (Designer)* |