// A stretch of Starlock's real cutscene (public/ideas/starlock/.tests/cutscene-demo.html), filmed frame by frame
// by headless Chromium on a phone-sized page (390 x 844) at a pixel ratio of 2, or as given: each frame drawn at its own moment and saved as
// a lossless PNG, so nothing is lost before the footage is cut. Run it from a checkout's root to film that
// checkout's cutscene (the before and after footage are two checkouts: before the glow change and after it).
//
//   node --input-type=module - <out-dir> [from-ms to-ms fps dpr] < research/2026-10-22-starlock-glow/code/film.mjs.txt
//
// (named .txt because the site serves code/ as text; see README.md). The software GPU is slow, so the page
// isn't timed: each frame is drawn at t = from + i * 1000 / fps, whatever the wall clock says.
import { spawn } from 'node:child_process';
import { createRequire } from 'node:module';
import fs from 'node:fs';
import net from 'node:net';
import path from 'node:path';

const require = createRequire(path.join(process.cwd(), 'x.js'));
const { chromium } = (() => {
  for (const id of [process.env.PLAYWRIGHT, 'playwright', '/opt/node-tools/node_modules/playwright'].filter(Boolean)) {
    try { return require(id); } catch {}
  }
  throw new Error('Playwright not found: set PLAYWRIGHT to its path.');
})();
const [out, from = '7600', to = '10800', fps = '30', dpr = '2'] = process.argv.slice(2);
fs.mkdirSync(out, { recursive: true });
const port = await new Promise((r) => { const s = net.createServer().listen(0, () => { const { port } = s.address(); s.close(() => r(port)); }); });
const srv = spawn(process.execPath, [path.join(process.cwd(), 'public/ideas/starlock/.tests/serve.mjs'), String(port)], { stdio: 'ignore' });
const url = `http://127.0.0.1:${port}/ideas/starlock/.tests/cutscene-demo.html`;
for (let i = 0; i < 100 && !(await fetch(url).then((r) => r.ok, () => false)); i++) await new Promise((r) => setTimeout(r, 50));
const browser = await chromium.launch({ args: ['--use-gl=angle', '--use-angle=swiftshader', '--enable-unsafe-swiftshader'] });
try {
  const page = await browser.newPage({ viewport: { width: 390, height: 844 }, deviceScaleFactor: +dpr });
  await page.goto(`${url}?render=3d&n=4&t=${from}&paint=full`);
  await page.waitForFunction(() => document.body.dataset.ready === '1', null, { timeout: 120000 });
  const n = Math.round(((+to - +from) * +fps) / 1000);
  for (let i = 0; i <= n; i++) {
    await page.evaluate((t) => window.__frame(t), +from + (i * 1000) / +fps);
    await page.screenshot({ path: path.join(out, `f${String(i).padStart(4, '0')}.png`), timeout: 180000 });
  }
} finally { await browser.close(); srv.kill(); }
