← back to Quadrille Showroom
scripts/demo-record.js
66 lines
#!/usr/bin/env node
/**
* demo-record.js — a ~30s "how to use it" guided demo of the showroom with
* elegant on-screen captions. Drives a real Chromium and records WebM; convert
* to MP4 afterward. Local 127.0.0.1 is auth-exempt.
*
* Run: NODE_PATH=$HOME/.npm-global/lib/node_modules node scripts/demo-record.js
*/
const path = require('path');
const fs = require('fs');
const { chromium } = require('playwright');
const URL = process.env.SHOWROOM_URL || 'http://127.0.0.1:7690/';
const OUT = path.join(__dirname, '..', 'recordings');
fs.mkdirSync(OUT, { recursive: true });
const sleep = (ms) => new Promise(r => setTimeout(r, ms));
async function caption(page, text) {
await page.evaluate((t) => {
let el = document.getElementById('__demo_cap');
if (!el) {
el = document.createElement('div');
el.id = '__demo_cap';
el.style.cssText = [
'position:fixed','left:50%','bottom:8%','transform:translateX(-50%)','z-index:99999',
'padding:14px 30px','background:rgba(14,12,9,0.82)','backdrop-filter:blur(8px)',
'border:1px solid rgba(185,147,63,0.45)','border-radius:40px',
'font-family:Georgia,serif','font-size:24px','letter-spacing:0.5px','color:#e9dcc0',
'box-shadow:0 10px 40px rgba(0,0,0,0.5)','transition:opacity .4s','max-width:80vw','text-align:center'
].join(';');
document.body.appendChild(el);
}
el.style.opacity = '0';
setTimeout(() => { el.textContent = t; el.style.opacity = '1'; }, 180);
}, text);
}
async function holdKey(page, key, ms) { await page.keyboard.down(key); await sleep(ms); await page.keyboard.up(key); }
(async () => {
const browser = await chromium.launch({ args: ['--use-gl=angle', '--enable-webgl', '--ignore-gpu-blocklist'] });
const ctx = await browser.newContext({ viewport: { width: 1600, height: 900 }, recordVideo: { dir: OUT, size: { width: 1600, height: 900 } } });
const page = await ctx.newPage();
await page.goto(URL, { waitUntil: 'domcontentloaded', timeout: 30000 });
await page.waitForFunction(() => window._wingBoards && window._wingBoards.length > 0, { timeout: 25000 }).catch(() => {});
await sleep(2500);
// ~30s captioned sequence
await caption(page, 'The Quadrille House · China Seas Showroom'); await sleep(3000);
await caption(page, 'Walk through with W · A · S · D'); await holdKey(page, 'KeyW', 1500); await sleep(1500);
await caption(page, 'Step up to a board — it opens to present the design'); await holdKey(page, 'KeyW', 600); await sleep(2600);
await caption(page, 'Click a board to inspect it'); await page.mouse.click(800, 430); await sleep(2200);
await caption(page, 'Full spec sheet — 27″ × 27″ · straight match'); await sleep(3200);
await caption(page, 'Fan the panels open to browse the design'); await page.click('#btn-fan-right').catch(()=>{}); await sleep(2800);
await page.keyboard.press('Escape'); await sleep(600);
await caption(page, 'Press P to Peruse — an auto-tour of the collection');await page.keyboard.press('KeyP'); await sleep(7000);
await caption(page, 'Pause anytime with Space for more info'); await sleep(3000);
await page.keyboard.press('Escape'); await sleep(500);
await caption(page, 'The Quadrille House'); await sleep(2600);
await page.close();
const vid = await page.video().path().catch(() => null);
await ctx.close(); await browser.close();
if (vid && fs.existsSync(vid)) { const f = path.join(OUT, 'demo.webm'); fs.renameSync(vid, f); console.log('✓ demo webm:', f); }
})().catch(e => { console.error('DEMO FAILED:', e.message); process.exit(1); });