#!/usr/bin/env node
/**
* MCP Animation Frame Generator
* Usage: node generate.js configs/your-config.json
*/
import fs from 'fs';
import path from 'path';
const configPath = process.argv[2];
if (!configPath) {
console.error('Usage: node generate.js configs/your-config.json');
process.exit(1);
}
const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
const outputDir = path.join('output', config.name);
fs.mkdirSync(outputDir, { recursive: true });
// Generate panel HTML based on type
function generatePanel(panel, index) {
const gridSpan = panel.gridSpan === 2 ? 'grid-row: span 2;' : '';
let content = '';
switch (panel.type) {
case 'list':
content = generateListPanel(panel);
break;
case 'stats':
content = generateStatsPanel(panel);
break;
case 'chart':
content = generateChartPanel(panel);
break;
case 'chat':
content = generateChatPanel(panel);
break;
default:
content = '
Unknown panel type
';
}
return `
`;
}
function generateListPanel(panel) {
const items = panel.items.map(item => `
${item.avatar}
${item.name}
${item.status}
${item.meta}
`).join('');
return `${items}
`;
}
function generateStatsPanel(panel) {
const stats = panel.stats.map(stat => `
${stat.label}
${stat.value}
${stat.change ? `${stat.change}` : ''}
`).join('');
const highlight = panel.highlight ? `
${panel.highlight.label}
${panel.highlight.value}
` : '';
return `${stats}
${highlight}`;
}
function generateChartPanel(panel) {
return `
${panel.bottomValue}
${panel.bottomLabel}
`;
}
function generateChatPanel(panel) {
const messages = panel.messages.map(msg => `
${msg.text}
`).join('');
return `${messages}
`;
}
// Base HTML template
function generateHTML(config, frameType) {
const showUserMessage = ['first-exchange', 'typing-second', 'loading', 'final'].includes(frameType);
const showAiResponse = ['first-exchange', 'typing-second', 'loading', 'final'].includes(frameType);
const showPanels = ['loading', 'final'].includes(frameType);
const showLoading = frameType === 'loading';
const showTyping = frameType === 'typing' || frameType === 'typing-second';
const panels = showPanels ? config.panels.map((p, i) => generatePanel(p, i)).join('') : '';
return `
${config.title}
${showUserMessage ? `
` : ''}
${showTyping && !showAiResponse ? `
` : ''}
${showAiResponse ? `
${config.aiResponse}
${showPanels ? `
${panels}
` : ''}
` : ''}
`;
}
// Generate all frames
const frames = [
{ name: 'frame-01-empty', type: 'empty' },
{ name: 'frame-02-typing', type: 'typing' },
{ name: 'frame-03-first-exchange', type: 'first-exchange' },
{ name: 'frame-04-typing-second', type: 'typing-second' },
{ name: 'frame-05-loading', type: 'loading' },
{ name: 'frame-06-final', type: 'final' }
];
frames.forEach(frame => {
const html = generateHTML(config, frame.type);
const filePath = path.join(outputDir, `${frame.name}.html`);
fs.writeFileSync(filePath, html);
console.log(`Generated: ${filePath}`);
});
console.log(`\n✓ Generated ${frames.length} frames in ${outputDir}/`);
console.log(`\nTo preview: open ${outputDir}/frame-06-final.html`);
console.log(`To export: use browser screenshot or puppeteer`);