main
md 211 lines 7.08 KB
Rendered Raw
1 ---
2 name: "design-visual-verification"
3 description: "Visually verify that what Amy ships matches what Calculon specified screenshot diffs at viewport × theme × page matrix using Playwright."
4 domain: "design, frontend, testing"
5 confidence: "low"
6 source: "manual"
7 tools: []
8 ---
9
10 ## Context
11
12 Before approving any frontend PR that changes layouts, typography, components, or theme tokens, Calculon runs a Playwright screenshot pass against the live Hugo preview of the PR branch. Screenshots are diffed against a baseline saved on `main`. Mismatches are compared against the acceptance criteria in `docs/processed/redesign-proposal-2026-05.md`.
13
14 This skill was established 2026-05-25. Bump confidence to **medium** after it has been used successfully on 2+ PRs.
15
16 ---
17
18 ## When to Use
19
20 - Any frontend PR touching: CSS/design tokens, Hugo templates, layout, typography, spacing, color, dark-mode overrides, or the cost-dashboard shortcode.
21 - After each redesign phase (#170–#175) lands — update baseline immediately so the next phase starts clean.
22 - **Do not skip** even for "small" changes — a one-line token change can affect every heading on every page.
23
24 ---
25
26 ## Workflow
27
28 ### 1. Checkout the PR branch and start Hugo
29
30 ```bash
31 git checkout <pr-branch>
32 hugo server -D --bind 0.0.0.0
33 # Hugo serves at http://localhost:1313/SquadScope/ by default
34 ```
35
36 Wait for Hugo to print `Web Server is available at …` before running the script.
37
38 ### 2. Run the verification script
39
40 ```bash
41 # Run with default base URL (http://localhost:1313/SquadScope/)
42 node scripts/design/verify-visual.mjs
43
44 # Or specify a different base URL
45 node scripts/design/verify-visual.mjs --base http://localhost:1313/SquadScope/
46 ```
47
48 Screenshots land in `screenshots/design-verification/YYYY-MM-DD/`.
49
50 ### 3. Diff against main baseline
51
52 ```bash
53 # Checkout main baseline first time (or use git stash approach)
54 git stash
55 hugo server -D --bind 0.0.0.0 &
56 node scripts/design/verify-visual.mjs --out screenshots/baseline/
57 git stash pop
58 ```
59
60 Compare the two `screenshots/` folders visually (Preview / Finder diff, or use `pixelmatch` CLI).
61
62 For structured regression, run via Playwright snapshot mode:
63
64 ```bash
65 # Generate/update baseline on main
66 npx playwright test tests/visual/ --update-snapshots
67
68 # On PR branch — test against baseline
69 npx playwright test tests/visual/
70 ```
71
72 ### 4. Compare against acceptance criteria
73
74 Open `docs/processed/redesign-proposal-2026-05.md`. Each phase has an **Acceptance Criteria** section. For each viewport × theme screenshot, check:
75
76 - Heading typescale matches spec (`--heading-xl`, `--heading-lg`, etc.)
77 - Accent color, bg, and text color match palette tokens
78 - No unexpected overflow or scroll bars at mobile (375px)
79 - Dark mode: no near-black-on-black contrast failures
80 - Cost dashboard date element is hidden in screenshots (see Pitfalls)
81
82 ### 5. Comment on the PR
83
84 Post a PR comment containing:
85
86 ```markdown
87 ## 🎨 Visual Verification — Calculon Review
88
89 | Page | Viewport | Light | Dark | Notes |
90 |------|----------|-------|------|-------|
91 | `/` | 375 | ✅ / ⚠️ | ✅ / ⚠️ | … |
92 | `/` | 768 | | | |
93 | `/` | 1280 | | | |
94 | `/` | 1920 | | | |
95 | `/weekly/2026/w22/` | … | | | |
96 | `/monthly/2026/05/` | … | | | |
97 | `/yearly/2026/` | … | | | |
98
99 ### Mismatches against spec
100 - [ ] List any deviations from `docs/processed/redesign-proposal-2026-05.md` acceptance criteria
101
102 **Decision:** ✅ Approved / 🔄 Changes requested
103 ```
104
105 ---
106
107 ## Viewport Matrix
108
109 | Name | Width | Height |
110 |------|-------|--------|
111 | mobile | 375 | 667 |
112 | tablet | 768 | 1024 |
113 | desktop | 1280 | 800 |
114 | wide | 1920 | 1080 |
115
116 ---
117
118 ## Theme Matrix
119
120 | Theme | Playwright setting |
121 |-------|--------------------|
122 | light | `page.emulateMedia({ colorScheme: 'light' })` |
123 | dark | `page.emulateMedia({ colorScheme: 'dark' })` |
124
125 ---
126
127 ## Pages Matrix
128
129 | Key | Path |
130 |-----|------|
131 | home | `/` |
132 | latest-weekly | `/weekly/2026/w22/` |
133 | monthly-rollup | `/monthly/2026/05/` |
134 | yearly-rollup | `/yearly/2026/` |
135
136 ---
137
138 ## Patterns
139
140 ### Navigate, emulate, screenshot
141
142 ```js
143 import { chromium } from 'playwright';
144
145 const browser = await chromium.launch();
146 const context = await browser.newContext({
147 viewport: { width: 1280, height: 800 },
148 colorScheme: 'dark', // or 'light'
149 });
150 const page = await context.newPage();
151
152 // Wait for fonts to load before screenshotting
153 await page.goto('http://localhost:1313/SquadScope/');
154 await page.waitForLoadState('networkidle');
155
156 // Hide dynamic elements that create screenshot noise
157 await page.addStyleTag({ content: '.cost-dashboard__date { visibility: hidden !important; }' });
158
159 await page.screenshot({ path: 'home-1280-dark.png', fullPage: true });
160 await browser.close();
161 ```
162
163 ### Playwright Test snapshot assertion
164
165 ```ts
166 // tests/visual/home.spec.ts
167 import { test, expect } from '@playwright/test';
168
169 test('home — desktop — dark', async ({ page }) => {
170 await page.emulateMedia({ colorScheme: 'dark' });
171 await page.goto('/');
172 await page.waitForLoadState('networkidle');
173 await page.addStyleTag({ content: '.cost-dashboard__date { visibility: hidden !important; }' });
174 await expect(page).toHaveScreenshot('home-desktop-dark.png', { maxDiffPixels: 150 });
175 });
176 ```
177
178 ### Update snapshots after intentional design change
179
180 ```bash
181 npx playwright test tests/visual/ --update-snapshots
182 git add tests/visual/*.spec.ts-snapshots/
183 git commit -m "chore: update visual baselines for phase N"
184 ```
185
186 ---
187
188 ## Anti-Patterns
189
190 - **Don't screenshot before `networkidle`** — fonts and theme CSS may not have applied yet, producing false diffs.
191 - **Don't leave the cost-dashboard date visible** — it changes every run and will always fail snapshot comparison. Hide it with `page.addStyleTag`.
192 - **Don't set `maxDiffPixels: 0`** — sub-pixel anti-aliasing differences on text will produce constant noise. Start at 150 and tighten per page.
193 - **Don't compare across OS/CI and local** — browser rendering differs. Always run baseline and comparison in the same environment.
194 - **Don't approve a PR without running dark mode** — dark-mode bugs are invisible in light screenshots.
195
196 ---
197
198 ## Pitfalls
199
200 1. **Font rendering noise** — Use `page.waitForLoadState('networkidle')` and consider adding a small `page.waitForTimeout(500)` after load to ensure web fonts have rendered before capturing.
201 2. **Dynamic date in cost dashboard** — The `{{< cost-dashboard >}}` shortcode displays a run date. Hide or mock this element via `page.addStyleTag` before screenshotting.
202 3. **Run counters / live data** — Any element showing "last crawl N repos" is dynamic. Add `.dynamic-counter { visibility: hidden !important; }` to the style injection.
203 4. **Hugo draft pages** — Run `hugo server -D` (the `-D` flag) to include draft content matching the pages matrix.
204 5. **Pixel diff thresholds** — Set `maxDiffPixels: 150` as default; tighten to 50 once stable; loosen temporarily for pages with many text nodes if needed.
205
206 ---
207
208 ## Confidence Bump Criteria
209
210 - **low → medium:** Used successfully on 2+ merged frontend PRs. At least one mismatch caught and fixed by the process.
211 - **medium → high:** Baseline management is automated in CI (not just local); thresholds are stable; no false positives in 5+ consecutive PRs.