#!/usr/bin/env node // Keep vanilla screenshots before a page changes; compare them against the // migrated preview when a visual diff needs investigation. import { mkdirSync } from 'node:fs'; const routes = [ '/', '/full-guide/', '/summary/', '/models/', '/agents/', '/skills/', '/rules/', '/skills-review/', '/hands-on/starter/', '/hands-on/rules/', ]; const widths = [560, 800, 1100, 1600]; const hasReducedMotion = process.argv.includes('--reduced-motion'); const base = process.env.VISUAL_BASE_URL ?? 'http://localhost:4173'; const output = process.env.VISUAL_OUTPUT_DIR ?? `.agents/snapshots/${hasReducedMotion ? 'before-reduced-motion' : 'before'}`; mkdirSync(output, { recursive: true }); let chromium; try { ({ chromium } = await import('playwright')); } catch { throw new Error( 'visual regression requires Playwright; install its project dependency and run pnpm exec playwright install chromium', ); } const browser = await chromium.launch({ headless: true, ...(process.env.VISUAL_BROWSER_PATH ? { executablePath: process.env.VISUAL_BROWSER_PATH } : {}), }); try { for (const route of routes) { for (const width of widths) { const page = await browser.newPage({ viewport: { width, height: 900 } }); if (hasReducedMotion) await page.emulateMedia({ reducedMotion: 'reduce' }); // The legacy site intentionally calls optional services that may be down; // visual capture is about the rendered page, not their network lifetime. await page.goto(new URL(route, base).toString(), { waitUntil: 'domcontentloaded' }); const name = route.replace(/^\/+|\/+$/g, '').replaceAll('/', '_') || 'index'; await page.screenshot({ path: `${output}/${name}-${width}.png`, fullPage: true }); await page.close(); } } } finally { await browser.close(); } console.log(`captured ${routes.length * widths.length} screenshots in ${output}`);