when-am-i / files / scripts / generate-screenshots.mts
generate-screenshots.mts
| 1 | // Generate documentation screenshots of key app states. |
| 2 | // |
| 3 | // Forces deterministic state via URL params (the same hook the app reads), so |
| 4 | // shots are reproducible. Output: screenshots/app/. Run from the repo root: |
| 5 | // npm run screenshot |
| 6 | |
| 7 | import { chromium } from 'playwright'; |
| 8 | import { mkdir, rm } from 'node:fs/promises'; |
| 9 | import path from 'node:path'; |
| 10 | import { startDevServer, BASE_URL, REPO_ROOT } from './lib/server.mts'; |
| 11 | |
| 12 | const OUT_DIR = path.join(REPO_ROOT, 'screenshots', 'app'); |
| 13 | |
| 14 | const STATES = [ |
| 15 | { name: '01-landing', query: '', desc: "Landing (today's date, no pin)" }, |
| 16 | { |
| 17 | name: '02-boston-1650', |
| 18 | query: '?lat=42.32&lng=-71.06&zoom=10&year=1650&month=6&day=15', |
| 19 | desc: 'Boston, 1650 — coexistence (Massachusett + colonial Julian)', |
| 20 | }, |
| 21 | { |
| 22 | name: '03-boston-1752', |
| 23 | query: '?lat=42.32&lng=-71.06&zoom=10&year=1752&month=9&day=20', |
| 24 | desc: 'Boston, 1752 — the British Julian→Gregorian switch mid-September (day-of-year track splits)', |
| 25 | }, |
| 26 | { |
| 27 | name: '04-boston-1800', |
| 28 | query: '?lat=42.32&lng=-71.06&zoom=10&year=1800&month=6&day=15', |
| 29 | desc: 'Boston, 1800 — Gregorian', |
| 30 | }, |
| 31 | ]; |
| 32 | |
| 33 | async function run() { |
| 34 | console.log('\n📸 Generating app screenshots…\n'); |
| 35 | const server = await startDevServer(); |
| 36 | try { |
| 37 | await rm(OUT_DIR, { recursive: true, force: true }); |
| 38 | await mkdir(OUT_DIR, { recursive: true }); |
| 39 | |
| 40 | const browser = await chromium.launch(); |
| 41 | const page = await browser.newPage({ viewport: { width: 1100, height: 920 }, deviceScaleFactor: 2 }); |
| 42 | |
| 43 | for (const state of STATES) { |
| 44 | await page.goto(`${BASE_URL}${state.query}`, { waitUntil: 'networkidle' }); |
| 45 | await page.waitForTimeout(800); // let map tiles settle |
| 46 | const file = path.join(OUT_DIR, `${state.name}.png`); |
| 47 | await page.screenshot({ path: file, fullPage: true }); |
| 48 | console.log(` ✅ ${state.name} — ${state.desc}`); |
| 49 | } |
| 50 | |
| 51 | await browser.close(); |
| 52 | console.log('\n✨ Done — screenshots/app/\n'); |
| 53 | } finally { |
| 54 | server.stop(); |
| 55 | } |
| 56 | } |
| 57 | |
| 58 | run().catch((err) => { |
| 59 | console.error(err); |
| 60 | process.exit(1); |
| 61 | }); |