58 lines
2.5 KiB
JavaScript
58 lines
2.5 KiB
JavaScript
// Renders the opening's global frames to PNG, manifest and preview.
|
|
import { spawnSync } from "node:child_process";
|
|
import { mkdirSync, rmSync, writeFileSync } from "node:fs";
|
|
import { dirname, join, resolve } from "node:path";
|
|
import { fileURLToPath } from "node:url";
|
|
import { chromium } from "../scenes/node_modules/playwright/index.mjs";
|
|
import { createServer } from "vite";
|
|
|
|
const here = dirname(fileURLToPath(import.meta.url));
|
|
const site = resolve(here, "../..");
|
|
const extra = resolve(here, "../out/extra");
|
|
const dir = join(extra, "opening");
|
|
const PAGES = 6;
|
|
|
|
const server = await createServer({ root: site, configFile: false, logLevel: "error", server: { port: 0 } });
|
|
await server.listen();
|
|
const url = `${server.resolvedUrls.local[0]}video/opening/index.html`;
|
|
const browser = await chromium.launch();
|
|
|
|
/** A film-sized page; any page error stops the run. */
|
|
async function open() {
|
|
const page = await browser.newPage({ viewport: { width: 1920, height: 1080 }, deviceScaleFactor: 1 });
|
|
page.on("pageerror", (e) => {
|
|
throw e;
|
|
});
|
|
await page.goto(url, { waitUntil: "networkidle" });
|
|
return page;
|
|
}
|
|
|
|
const pages = await Promise.all(Array.from({ length: PAGES }, open));
|
|
const { first, end } = await pages[0].evaluate(() => ({ first: window.opening.first, end: window.opening.end }));
|
|
const only = process.argv.slice(2).map(Number);
|
|
const frames = only.length ? only : Array.from({ length: end - first }, (_, i) => first + i);
|
|
if (!only.length) rmSync(dir, { recursive: true, force: true });
|
|
mkdirSync(dir, { recursive: true });
|
|
|
|
const queue = [...frames];
|
|
await Promise.all(
|
|
pages.map(async (page) => {
|
|
for (let f = queue.shift(); f !== undefined; f = queue.shift()) {
|
|
await page.evaluate((f) => window.opening.render(f), f);
|
|
await page.screenshot({ path: join(dir, `${String(f).padStart(5, "0")}.png`) });
|
|
}
|
|
}),
|
|
);
|
|
await browser.close();
|
|
await server.close();
|
|
|
|
if (!only.length) {
|
|
const manifest = { name: "opening", first, count: end - first, fps: 30, kind: "base" };
|
|
writeFileSync(join(dir, "manifest.json"), JSON.stringify(manifest, null, 1));
|
|
const args = ["-y", "-v", "error", "-framerate", "30", "-start_number", String(first), "-i", join(dir, "%05d.png")];
|
|
args.push("-c:v", "libx264", "-preset", "slow", "-crf", "16", "-pix_fmt", "yuv420p", "-movflags", "+faststart");
|
|
const run = spawnSync("ffmpeg", [...args, join(extra, "opening.mp4")], { stdio: "inherit" });
|
|
if (run.status !== 0) throw new Error("ffmpeg failed");
|
|
console.log(`opening: frames ${first}..${end - 1} (${end - first})`);
|
|
}
|