← back to Quadrille Showroom
Add 30s captioned how-to-use demo recorder
80afbd8e4457761c0b01ef510176d4b840cb0304 · 2026-06-27 00:45:04 -0700 · Steve
Files touched
Diff
commit 80afbd8e4457761c0b01ef510176d4b840cb0304
Author: Steve <steve@designerwallcoverings.com>
Date: Sat Jun 27 00:45:04 2026 -0700
Add 30s captioned how-to-use demo recorder
---
scripts/demo-record.js | 65 ++++++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 65 insertions(+)
diff --git a/scripts/demo-record.js b/scripts/demo-record.js
new file mode 100644
index 0000000..32991c0
--- /dev/null
+++ b/scripts/demo-record.js
@@ -0,0 +1,65 @@
+#!/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); });
← 15f8c33 Clean+clear pass: bright even gallery lighting, true-colour
·
back to Quadrille Showroom
·
Usable view: 6ft back + dead-centre + 65° open + ISOLATE (hi 6e2efdd →