// check-poster-raster — a poster with NO pre-rendered image must still download. // // ★ THE POINT: 378 posters ship as .webp — 41 MB in every clone, delivered to every // reader whether or not they open one, and a publish was ALREADY rejected once at a // 74 MB asset tree. Not shipping ~80 MB of images in a public folder, and letting // the website generate the posters, is a big win. // // The fallback rasterises posters/.html in the browser. This gate proves the // generated image is REAL, because the failure mode here is silent and total: // // ⚠ AN SVG LOADED THROUGH IS AN ISOLATED DOCUMENT. It cannot see the host // page's CSS, so every var() falls back to its initial value — and `fill`'s initial // value is BLACK. A poster that lost its stylesheet downloads as a black rectangle // with no error, no exception and a perfectly normal file size. So this gate // MEASURES PIXELS: mean luminance and colour variety, not "did it produce bytes". // // Usage: node internal/check-poster-raster.mjs [zoneId] // PACKET_ORIGIN (default http://127.0.0.1:4898) import { chromium } from './lib/playwright-guarded.mjs' import { requireThisTree } from './_serves-this-tree.mjs' import { resolve as _resolvePath, dirname as _dirnamePath } from 'node:path' import { fileURLToPath as _fileURLToPath } from 'node:url' const ORIGIN = process.env.PACKET_ORIGIN || 'http://127.0.0.1:4898' const ROOT = _resolvePath(_dirnamePath(_fileURLToPath(import.meta.url)), '..') // ★ MEASURE THIS BUILD, OR MEASURE NOTHING. Several worktrees run on one machine and a default port // belongs to whichever server started first — measured 2026-09-24 on :4173, where browser gates // reported confidently about a build nobody here had touched. 75 (EX_TEMPFAIL), not 1: the wrong // tree is a precondition, not a product defect, and the wave runner reports 75 as ⊘ rather than ✗. // A file:// target passes straight through — there is no server there to be wrong about. await requireThisTree(ORIGIN, ROOT, 'POSTER-RASTER') const ZONE = process.argv[2] || 'laos' const HTML = `${ORIGIN}/library/scripts/posters/out/posters/${ZONE}.html` const b = await chromium.launch() const pg = await b.newPage({ viewport: { width: 1200, height: 900 } }) const errs = []; pg.on('pageerror', e => errs.push(String(e).slice(0, 140))) await pg.goto(ORIGIN + '/') const r = await pg.evaluate(async ({ ORIGIN, HTML }) => { const { rasterPoster, looksRendered, inlineSvg } = await import(`${ORIGIN}/library/packet/poster-raster.js`) const res = await fetch(HTML) if (!res.ok) return { error: `poster HTML ${res.status}` } const html = await res.text() // The stylesheet must actually travel with the svg. const svg = inlineSvg(html) const carriesCss = /