/** * Record demo.html as video using Puppeteer + FFmpeg * Usage: node record-demo.mjs */ import puppeteer from 'puppeteer'; import { spawn } from 'child_process'; import fs from 'fs'; import path from 'path'; const WIDTH = 1280; const HEIGHT = 800; const FPS = 30; const OUTPUT = 'docs/demo.mp4'; async function recordDemo() { console.log('[Record] Starting demo video recording...'); const browser = await puppeteer.launch({ headless: true, args: ['--no-sandbox', '--disable-setuid-sandbox'], }); const page = await browser.newPage(); await page.setViewport({ width: WIDTH, height: HEIGHT }); console.log('[Record] Loading demo.html...'); await page.goto(`file://${path.resolve('docs/demo.html')}`, { waitUntil: 'networkidle2', }); // Set up FFmpeg for video recording const ffmpeg = spawn('ffmpeg', [ '-y', '-f', 'gdigrab', '-framerate', String(FPS), '-i', 'desktop', '-c:v', 'libx264', '-preset', 'medium', '-crf', '23', '-pix_fmt', 'yuv420p', OUTPUT, ]); ffmpeg.stderr.on('data', (data) => { console.log(`[FFmpeg] ${data}`); }); // Wait for FFmpeg to start await new Promise(resolve => setTimeout(resolve, 1000)); console.log('[Record] Running demo sequence...'); // Click "Run Full Demo" await page.click('button[onclick="runDemo()"]'); // Wait for demo to complete (~15 seconds) await page.waitForTimeout(18000); console.log('[Record] Stopping recording...'); ffmpeg.stdin.write('q'); await new Promise(resolve => { ffmpeg.on('close', resolve); }); await browser.close(); console.log(`[Record] ✓ Video saved: ${OUTPUT}`); console.log(`[Record] Size: ${fs.statSync(OUTPUT).size / 1024 / 1024}MB`); } recordDemo().catch(console.error);