← back to Professional Directory
scripts/snapshot-mockups.js
51 lines
#!/usr/bin/env node
/**
* Snapshot every generated mockup to a 1200×750 PNG (so the pitch modal
* can show real thumbnails instead of slow live iframes).
*
* Reads: data/mockups/<id>.html
* Writes: data/mockups/<id>.png
*
* Usage:
* node scripts/snapshot-mockups.js # snapshots all mockups missing PNG
* FORCE=1 node scripts/snapshot-mockups.js # re-snapshots even if PNG exists
*/
const fs = require('fs');
const path = require('path');
const { chromium } = require('playwright');
const DIR = path.resolve(__dirname, '../data/mockups');
const FORCE = process.env.FORCE === '1';
const VIEWPORT = { width: 1200, height: 750 };
(async () => {
const files = fs.readdirSync(DIR).filter(f => f.endsWith('.html'));
console.log(`[snap] ${files.length} mockups in ${DIR}`);
const browser = await chromium.launch({ headless: true });
const context = await browser.newContext({ viewport: VIEWPORT, deviceScaleFactor: 1 });
let ok = 0, skip = 0, fail = 0;
for (const f of files) {
const id = f.replace(/\.html$/, '');
const png = path.join(DIR, `${id}.png`);
if (fs.existsSync(png) && !FORCE) { skip++; continue; }
const url = 'file://' + path.join(DIR, f);
const page = await context.newPage();
try {
await page.goto(url, { waitUntil: 'networkidle', timeout: 20_000 });
// Hide our injected chat widget so it doesn't dominate the thumbnail.
await page.addStyleTag({ content: '#vw-chat-fab, #vw-chat-panel { display: none !important; }' });
await page.waitForTimeout(400); // let any animations settle
await page.screenshot({ path: png, fullPage: false, type: 'png' });
console.log(`[snap] ${id}.png ✓`);
ok++;
} catch (e) {
console.log(`[snap] ${id} FAIL ${e.message}`);
fail++;
}
await page.close();
}
await browser.close();
console.log(`[snap] done. ok=${ok} skip=${skip} fail=${fail}`);
})();