#!/usr/bin/env node import puppeteer from 'puppeteer'; import { execSync } from 'child_process'; import path from 'path'; import { fileURLToPath } from 'url'; import fs from 'fs'; import { mcpConfigs } from './mcp-configs.js'; const __dirname = path.dirname(fileURLToPath(import.meta.url)); // Only render these 3 MCPs const targetIds = ['lightspeed', 'bigcommerce', 'toast']; const configs = mcpConfigs.filter(c => targetIds.includes(c.id)); function generateHTML(config) { const { name, color, question, statLabel, statValue, statLabel2, statValue2, rows, insight } = config; return ` ${name} MCP Demo
AI Assistant ยท ${name} Connected
${question}
Here's what I found:
${name}
${statValue}
${statLabel}
${statValue2}
${statLabel2}
${rows[0].label} ${rows[0].value}
${rows[1].label} ${rows[1].value}
${rows[2].label} ${rows[2].value}
๐Ÿ’ก Recommendation
${insight}
Ask anything...
`; } async function renderVideo(config, browser) { const htmlPath = path.join(__dirname, 'output', `${config.id}.html`); const framesDir = path.join(__dirname, 'output', `${config.id}-frames`); const mp4Path = path.join(__dirname, 'output', `${config.id}.mp4`); // Generate HTML fs.writeFileSync(htmlPath, generateHTML(config)); // Create frames directory fs.rmSync(framesDir, { recursive: true, force: true }); fs.mkdirSync(framesDir, { recursive: true }); // Capture frames const page = await browser.newPage(); await page.setViewport({ width: 1920, height: 1080 }); await page.goto(`file://${htmlPath}`, { waitUntil: 'networkidle0' }); await new Promise(r => setTimeout(r, 300)); const fps = 30; const totalFrames = 300; // 10 seconds for (let i = 0; i < totalFrames; i++) { const scroll = i / (totalFrames - 1); await page.evaluate(s => window.updateScene(s), scroll); await new Promise(r => setTimeout(r, 15)); await page.screenshot({ path: path.join(framesDir, `frame-${String(i+1).padStart(4,'0')}.png`), type: 'png' }); } await page.close(); // Encode video execSync(`ffmpeg -y -framerate ${fps} -i "${framesDir}/frame-%04d.png" -c:v libx264 -pix_fmt yuv420p -crf 20 "${mp4Path}"`, { stdio: 'pipe' }); // Cleanup frames fs.rmSync(framesDir, { recursive: true, force: true }); return mp4Path; } async function main() { console.log(`\n๐ŸŽฌ Generating ${configs.length} MCP videos...\n`); const browser = await puppeteer.launch({ headless: true, executablePath: '/Applications/Google Chrome.app/Contents/MacOS/Google Chrome', args: ['--no-sandbox'] }); const results = []; for (let i = 0; i < configs.length; i++) { const config = configs[i]; const start = Date.now(); process.stdout.write(`[${i+1}/${configs.length}] ${config.name}... `); try { await renderVideo(config, browser); console.log(`โœ“ (${Math.round((Date.now() - start) / 1000)}s)`); results.push({ name: config.name, id: config.id, success: true }); } catch (err) { console.log(`โœ— ${err.message}`); results.push({ name: config.name, id: config.id, success: false, error: err.message }); } } await browser.close(); console.log(`\nโœ“ Done! Videos saved to output/\n`); return results; } main().catch(console.error);