--- name: visual-regression description: Prove a refactor did not change how the site looks. Use before and after any page migration, token consolidation, or breakpoint change on ai-for-dummies. --- # Visual regression "Maintain the same styles" is a testable claim. Test it. ## Capture The repo already has a Playwright pattern (`scripts/inspect.py`). Extend it rather than inventing one. ```python from playwright.sync_api import sync_playwright ROUTES = ['/', '/full-guide/', '/summary/', '/models/', '/agents/', '/skills/', '/rules/', '/skills-review/', '/hands-on/starter/', '/hands-on/rules/'] WIDTHS = [560, 800, 1100, 1600] with sync_playwright() as p: browser = p.chromium.launch(headless=True) for route in ROUTES: for w in WIDTHS: page = browser.new_page(viewport={'width': w, 'height': 900}) page.goto(f'{BASE}{route}', wait_until='networkidle') page.screenshot(path=f'{OUT}/{route.strip("/").replace("/","_") or "index"}-{w}.png', full_page=True) page.close() browser.close() ``` Run once against `pnpm run preview`. To compare against the vanilla site, serve a pre-cutover worktree on :4173 first — those files are no longer on `main`. Keep both sets. ## Compare ```bash for f in before/*.png; do compare -metric AE "$f" "after/$(basename $f)" null: 2>&1 # ImageMagick echo " <- $(basename $f)" done ``` Pixel-exact is not the bar — antialiasing differs. Judge by eye where the metric is non-trivial, and attach the pair to the task report. ## The three widths that catch the most - **560px** — where the 16 ad-hoc breakpoints collapse to `--bp-sm`. Highest risk in the whole migration. - **800px** — the most common existing breakpoint; layout flips here. - **1600px** — `min-width` rules that only fire on large screens are the ones nobody notices are broken. Also screenshot at the **old** breakpoint values you removed (520, 530, 600, 620, 720, 850, 880, 900), not just the new ones. Regressions hide exactly there. ## What a real difference looks like Expect and accept: sub-pixel text shifts, antialiasing. Investigate: anything that moves by more than ~2px, any colour change (that is a token bug), any element that appears or disappears (that is content loss — stop and check the snapshot diff). ## Reduced motion Capture one pass with `prefers_reduced_motion='reduce'`. Animations must land in their correct end state, not vanish.