#!/usr/bin/env node /** * Screenshot Generator for Infinite Agents Dashboard * * Automatically captures screenshots of all demos for preview thumbnails. * Uses Playwright to render each demo and save a screenshot. * * Installation: * npm install -D playwright * npx playwright install chromium * * Usage: * node generate_screenshots.js * node generate_screenshots.js --category threejs * node generate_screenshots.js --single threejs_viz/threejs_viz_1.html */ const { chromium } = require('playwright'); const fs = require('fs'); const path = require('path'); // Demo categories and their file patterns const DEMO_CATEGORIES = { threejs: { pattern: 'threejs_viz/threejs_viz_*.html', delay: 3000, // Extra time for WebGL to render }, sdg: { pattern: 'sdg_viz/sdg_viz_*.html', delay: 2000, }, d3: { pattern: 'd3_test/d3_viz_*.html', delay: 1500, }, mapbox: { pattern: 'mapbox_test/mapbox_globe_*/index.html', delay: 3000, // Mapbox needs time to load tiles }, claudeDevTools: { pattern: 'claude_code_devtools/claude_devtool_*.html', delay: 1000, }, uiSingle: { pattern: 'src/ui_hybrid_*.html', delay: 800, }, uiInfinite: { pattern: 'src_infinite/ui_hybrid_*.html', delay: 800, }, uiModular: { pattern: 'src_group/ui_hybrid_*/index.html', delay: 800, }, infiniteVariants: { pattern: 'infinite_variants/infinite_variant_*/test_output/*.html', delay: 1500, // Mixed content, some may have animations }, }; // Parse command line arguments const args = process.argv.slice(2); const categoryFilter = args.find(arg => arg.startsWith('--category='))?.split('=')[1]; const singleFile = args.find(arg => arg.startsWith('--single='))?.split('=')[1]; const PORT = args.find(arg => arg.startsWith('--port='))?.split('=')[1] || 8889; // Create screenshots directory const SCREENSHOTS_DIR = path.join(__dirname, 'screenshots'); if (!fs.existsSync(SCREENSHOTS_DIR)) { fs.mkdirSync(SCREENSHOTS_DIR, { recursive: true }); console.log(`āœ… Created screenshots directory: ${SCREENSHOTS_DIR}`); } // Scan directory for demo files function scanDirectory(pattern) { const glob = require('glob'); return glob.sync(pattern); } // Get all demo files function getAllDemos() { const demos = []; for (const [category, config] of Object.entries(DEMO_CATEGORIES)) { if (categoryFilter && category !== categoryFilter) continue; const files = scanDirectory(config.pattern); files.forEach(file => { demos.push({ path: file, category, delay: config.delay, }); }); } return demos; } // Capture screenshot for a single demo async function captureScreenshot(browser, demo, index, total) { const page = await browser.newPage(); try { // Set viewport size (desktop resolution) await page.setViewportSize({ width: 1920, height: 1080 }); const url = `http://localhost:${PORT}/${demo.path}`; console.log(`\nšŸ“ø [${index + 1}/${total}] ${demo.path}`); // Navigate to demo await page.goto(url, { waitUntil: 'networkidle', timeout: 30000, }); // Wait for demo to render await page.waitForTimeout(demo.delay); // Generate screenshot filename const screenshotFilename = demo.path.replace(/\//g, '_').replace('.html', '.png'); const screenshotPath = path.join(SCREENSHOTS_DIR, screenshotFilename); // Capture screenshot await page.screenshot({ path: screenshotPath, fullPage: false, // Just viewport, not entire scrollable page }); console.log(` āœ… Saved: ${screenshotFilename}`); } catch (error) { console.error(` āŒ Failed: ${error.message}`); } finally { await page.close(); } } // Main execution async function main() { console.log('šŸš€ Infinite Agents Screenshot Generator\n'); // Get demo files let demos; if (singleFile) { demos = [{ path: singleFile, category: 'custom', delay: 2000, }]; } else { demos = getAllDemos(); } if (demos.length === 0) { console.error('āŒ No demo files found!'); console.log('\nMake sure:'); console.log(' 1. You are in the project root directory'); console.log(' 2. Demo files exist in their respective directories'); console.log(' 3. Category filter is correct (if using --category)'); process.exit(1); } console.log(`šŸ“Š Found ${demos.length} demos to screenshot\n`); // Check if server is running console.log(`šŸ” Checking if server is running on http://localhost:${PORT}...`); try { const http = require('http'); await new Promise((resolve, reject) => { const req = http.get(`http://localhost:${PORT}`, (res) => { resolve(); }); req.on('error', reject); req.setTimeout(3000, () => reject(new Error('Timeout'))); }); console.log(' āœ… Server is running\n'); } catch (error) { console.error(' āŒ Server is not running!'); console.log(`\nšŸ”§ Start the server first:`); console.log(` python3 -m http.server ${PORT}\n`); process.exit(1); } // Launch browser console.log('🌐 Launching browser...'); const browser = await chromium.launch({ headless: true, }); console.log(' āœ… Browser ready\n'); // Capture screenshots console.log('šŸ“ø Capturing screenshots...'); console.log('━'.repeat(50)); for (let i = 0; i < demos.length; i++) { await captureScreenshot(browser, demos[i], i, demos.length); } // Cleanup await browser.close(); console.log('\n' + '━'.repeat(50)); console.log(`\n✨ Done! Captured ${demos.length} screenshots`); console.log(`šŸ“ Screenshots saved to: ${SCREENSHOTS_DIR}\n`); } // Run main().catch(error => { console.error('\nāŒ Fatal error:', error); process.exit(1); });