Zum Inhalt

scripts/crash-preview.mjs

// Phase-1 visual check: trigger the CRT crash sequence directly (via the
// DEV-only window.__kuro hook) and capture it, so we can review the loop seam
// without waiting for a full ~8-min narrative shift.
//
// Needs the dev server running (npm run dev).
// Outputs render-out/crash.webm + timed screenshots crash-NN.png.

import { chromium } from 'playwright';
import { mkdirSync } from 'node:fs';

const URL = 'http://localhost:5173/screensaver.html?scene=city&preset=phosphor';
const OUT = 'render-out';
mkdirSync(OUT, { recursive: true });

const browser = await chromium.launch({
  headless: false,
  args: ['--use-gl=angle', '--use-angle=metal', '--ignore-gpu-blocklist'],
});
const context = await browser.newContext({
  viewport: { width: 1280, height: 720 },
  deviceScaleFactor: 1,
  recordVideo: { dir: OUT, size: { width: 1280, height: 720 } },
});
const page = await context.newPage();
await page.goto(URL, { waitUntil: 'load' });

// Let the engine + narrative spin up.
await page.waitForTimeout(3500);

console.log('triggering playCrash()');
// Fire the crash but don't await it inside evaluate — we want to screenshot
// the sequence as it runs.
await page.evaluate(() => {
  const c = window.__kuro;
  c?.crt?.playCrash(() => {
    // blackout callback — clear marker so we can confirm timing if needed
    document.title = 'BLACKOUT';
  });
});

// Sample the ~2s sequence at fixed offsets.
const shots = [200, 500, 850, 1100, 1400, 1700, 2100, 2600];
let prev = 0;
for (let n = 0; n < shots.length; n++) {
  await page.waitForTimeout(shots[n] - prev);
  prev = shots[n];
  await page.screenshot({ path: `${OUT}/crash-${String(n).padStart(2, '0')}-${shots[n]}ms.png` });
}
console.log('screenshots written');

await page.waitForTimeout(800);
await context.close();
await browser.close();
console.log(`done — ${OUT}/crash.webm + crash-*.png`);