superdesign-claude
Version:
SuperDesign Claude v2.2 - AI-Powered Design Pattern Recognition Engine with Code Generation - PHASE 1 + CODE GEN
947 lines (827 loc) • 26.3 kB
JavaScript
/**
* SuperDesign Code Generation Engine
* Transforms wireframes and patterns into production-ready HTML/CSS/JS code
*/
const fs = require('fs-extra');
const path = require('path');
class CodeGenerationEngine {
constructor(logger, errorHandler) {
this.logger = logger;
this.errorHandler = errorHandler;
this.designSystem = this.loadDesignSystem();
this.componentTemplates = this.loadComponentTemplates();
this.layoutEngines = this.loadLayoutEngines();
}
/**
* Generate complete codebase from SuperDesign result
*/
async generateCode(designResult, outputOptions = {}) {
try {
const startTime = performance.now();
const codeGeneration = {
html: await this.generateHTML(designResult),
css: await this.generateCSS(designResult),
javascript: await this.generateJavaScript(designResult),
components: await this.generateComponents(designResult),
assets: await this.generateAssets(designResult),
metadata: {
designSystem: 'SuperDesign v2.0',
framework: outputOptions.framework || 'vanilla',
responsive: true,
accessibility: 'WCAG 2.1 AA',
performance: 'optimized'
}
};
// Write files if output directory specified
if (outputOptions.outputDir) {
await this.writeCodeFiles(codeGeneration, outputOptions.outputDir);
}
const generationTime = performance.now() - startTime;
this.logger.info('Code generation completed', {
generationTime: Math.round(generationTime),
filesGenerated: Object.keys(codeGeneration).length,
framework: outputOptions.framework
});
return codeGeneration;
} catch (error) {
this.logger.error('Code generation failed', error);
throw error;
}
}
/**
* Generate HTML structure from wireframe and components
*/
async generateHTML(designResult) {
const { pattern, components, layout, intent } = designResult;
const htmlStructure = {
doctype: '<!DOCTYPE html>',
html: {
attributes: { lang: 'en', class: `superdesign-${intent.intent.type}` },
head: this.generateHTMLHead(designResult),
body: this.generateHTMLBody(designResult)
}
};
return this.renderHTML(htmlStructure);
}
/**
* Generate HTML head section
*/
generateHTMLHead(designResult) {
const { intent, pattern } = designResult;
return `
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="description" content="${intent.intent.type} built with SuperDesign">
<meta name="generator" content="SuperDesign Claude v2.2">
<title>${this.generatePageTitle(intent, pattern)}</title>
<link rel="stylesheet" href="styles/main.css">
<link rel="stylesheet" href="styles/components.css">
<link rel="stylesheet" href="styles/responsive.css">`;
}
/**
* Generate HTML body structure
*/
generateHTMLBody(designResult) {
const { pattern, components, layout } = designResult;
return `
<body class="layout-${layout.type.replace('css-', '')}">
${this.buildLayoutStructure(pattern, components, layout)}
<script src="scripts/main.js"></script>
</body>`;
}
/**
* Build layout structure from pattern and components
*/
buildLayoutStructure(pattern, components, layout) {
let structure = '';
// Header section
if (components.required.includes('navigation')) {
structure += `
<header class="site-header">
<nav class="navigation">
<a href="#" class="nav-logo">${pattern.selectedPattern.name}</a>
<ul class="nav-menu">
<li><a href="#" class="nav-link">Home</a></li>
<li><a href="#" class="nav-link">Products</a></li>
<li><a href="#" class="nav-link">About</a></li>
<li><a href="#" class="nav-link">Contact</a></li>
</ul>
</nav>
</header>`;
}
// Main content
structure += `
<main class="main-content ${layout.type}">
${this.generateMainContent(pattern, components, layout)}
</main>`;
// Footer section
if (components.required.includes('footer') || components.recommended.includes('footer')) {
structure += `
<footer class="site-footer">
<p>© 2025 ${pattern.selectedPattern.name}. Built with SuperDesign.</p>
</footer>`;
}
return structure;
}
/**
* Generate main content based on pattern and components
*/
generateMainContent(pattern, components, layout) {
const { selectedPattern } = pattern;
let content = '';
if (selectedPattern.type === 'ecommerce') {
content = this.generateEcommerceContent(components);
} else if (selectedPattern.type === 'dashboard') {
content = this.generateDashboardContent(components);
} else if (selectedPattern.type === 'landing') {
content = this.generateLandingContent(components);
} else if (selectedPattern.type === 'auth') {
content = this.generateAuthContent(components);
} else {
content = this.generateGenericContent(components);
}
return content;
}
/**
* Generate ecommerce-specific content
*/
generateEcommerceContent(components) {
return `
<div class="hero-section">
<h1>Welcome to Our Store</h1>
<p>Discover amazing products at great prices</p>
${components.required.includes('search') ? `
<div class="search-bar">
<input type="text" placeholder="Search products..." class="form-input">
<button class="button button-primary">Search</button>
</div>` : ''}
</div>
<section class="products-section">
<div class="products-grid">
${this.generateProductCards()}
</div>
</section>`;
}
/**
* Generate product cards for ecommerce
*/
generateProductCards() {
let cards = '';
for (let i = 1; i <= 6; i++) {
cards += `
<div class="card product-card">
<div class="card-image">
<img src="https://via.placeholder.com/300x200" alt="Product ${i}">
</div>
<div class="card-content">
<h3 class="card-title">Product ${i}</h3>
<p class="product-price">$${(Math.random() * 100 + 20).toFixed(2)}</p>
<button class="button button-primary">Add to Cart</button>
</div>
</div>`;
}
return cards;
}
/**
* Generate dashboard content
*/
generateDashboardContent(components) {
return `
<div class="dashboard-grid">
<aside class="dashboard-sidebar">
<nav class="sidebar-nav">
<a href="#" class="sidebar-link active">Dashboard</a>
<a href="#" class="sidebar-link">Analytics</a>
<a href="#" class="sidebar-link">Reports</a>
<a href="#" class="sidebar-link">Settings</a>
</nav>
</aside>
<div class="dashboard-main">
<h1>Dashboard</h1>
<div class="stats-grid">
${this.generateStatCards()}
</div>
${components.required.includes('chart') ? `
<div class="chart-section">
<div class="card">
<div class="card-header">
<h2 class="card-title">Analytics Overview</h2>
</div>
<div class="card-content">
<div class="chart-placeholder">
📊 Chart would be rendered here
</div>
</div>
</div>
</div>` : ''}
</div>
</div>`;
}
/**
* Generate stat cards for dashboard
*/
generateStatCards() {
const stats = [
{ title: 'Total Users', value: '12,345', change: '+12%' },
{ title: 'Revenue', value: '$45,678', change: '+8%' },
{ title: 'Orders', value: '1,234', change: '+15%' },
{ title: 'Conversion', value: '3.45%', change: '+2%' }
];
return stats.map(stat => `
<div class="card stat-card">
<div class="card-content">
<h3 class="stat-title">${stat.title}</h3>
<div class="stat-value">${stat.value}</div>
<div class="stat-change positive">${stat.change}</div>
</div>
</div>`).join('');
}
/**
* Generate landing page content
*/
generateLandingContent(components) {
return `
<div class="hero-section">
<div class="hero-content">
<h1 class="hero-title">Welcome to the Future</h1>
<p class="hero-subtitle">Transform your workflow with our innovative platform</p>
<div class="hero-actions">
<button class="button button-primary">Get Started</button>
<button class="button button-secondary">Learn More</button>
</div>
</div>
</div>
<section class="features-section">
<h2>Why Choose Us</h2>
<div class="features-grid">
${this.generateFeatureCards()}
</div>
</section>`;
}
/**
* Generate feature cards for landing page
*/
generateFeatureCards() {
const features = [
{ title: 'Fast & Reliable', description: 'Lightning fast performance you can count on' },
{ title: 'Secure', description: 'Enterprise-grade security for your data' },
{ title: 'Scalable', description: 'Grows with your business needs' }
];
return features.map(feature => `
<div class="card feature-card">
<div class="card-content">
<h3 class="card-title">${feature.title}</h3>
<p>${feature.description}</p>
</div>
</div>`).join('');
}
/**
* Generate auth content
*/
generateAuthContent(components) {
return `
<div class="auth-container">
<div class="auth-card card">
<div class="card-header">
<h1 class="card-title">Sign In</h1>
<p>Welcome back! Please sign in to your account.</p>
</div>
<form class="auth-form">
<div class="form-group">
<label class="form-label">Email</label>
<input type="email" class="form-input" placeholder="Enter your email">
</div>
<div class="form-group">
<label class="form-label">Password</label>
<input type="password" class="form-input" placeholder="Enter your password">
</div>
<button type="submit" class="button button-primary auth-submit">Sign In</button>
</form>
</div>
</div>`;
}
/**
* Generate generic content
*/
generateGenericContent(components) {
return `
<div class="content-section">
<h1>Welcome</h1>
<p>This is a generic layout generated by SuperDesign.</p>
<div class="cards-grid">
<div class="card">
<div class="card-header">
<h2 class="card-title">Card Title</h2>
</div>
<div class="card-content">
<p>Card content goes here.</p>
<button class="button button-primary">Action</button>
</div>
</div>
</div>
</div>`;
}
/**
* Generate CSS styles with design system
*/
async generateCSS(designResult) {
const { layout, components, intent, pattern } = designResult;
const cssFiles = {
'main.css': this.generateMainCSS(designResult),
'components.css': this.generateComponentsCSS(components),
'responsive.css': this.generateResponsiveCSS(layout),
'design-system.css': this.generateDesignSystemCSS()
};
return cssFiles;
}
/**
* Generate main CSS file
*/
generateMainCSS(designResult) {
const { layout, intent, pattern } = designResult;
return `/* SuperDesign Generated CSS - ${intent.intent.type} */
/* Design System: SuperDesign v2.1 */
:root {
/* Design System Variables */
--primary-color: #2563eb;
--secondary-color: #64748b;
--accent-color: #0ea5e9;
--background-color: #ffffff;
--surface-color: #f8fafc;
--text-primary: #0f172a;
--text-secondary: #475569;
--border-color: #e2e8f0;
--shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.05);
--shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.1);
--shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.1);
--radius-sm: 0.375rem;
--radius-md: 0.5rem;
--radius-lg: 0.75rem;
--spacing-xs: 0.5rem;
--spacing-sm: 0.75rem;
--spacing-md: 1rem;
--spacing-lg: 1.5rem;
--spacing-xl: 2rem;
--font-sans: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
--font-mono: 'SF Mono', Monaco, 'Cascadia Code', monospace;
}
/* Global Styles */
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family: var(--font-sans);
line-height: 1.6;
color: var(--text-primary);
background-color: var(--background-color);
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
/* Layout System */
${this.generateLayoutCSS(layout)}
/* Accessibility */
(prefers-reduced-motion: reduce) {
* {
animation-duration: 0.01ms !important;
animation-iteration-count: 1 !important;
transition-duration: 0.01ms !important;
}
}
/* Focus Styles */
:focus-visible {
outline: 2px solid var(--primary-color);
outline-offset: 2px;
}
`;
}
/**
* Generate layout-specific CSS
*/
generateLayoutCSS(layout) {
if (layout.type === 'css-grid') {
return `
/* CSS Grid Layout */
.layout-grid {
display: grid;
grid-template-columns: repeat(${layout.grid.columns}, 1fr);
gap: ${layout.grid.gutters}px;
max-width: 1200px;
margin: 0 auto;
padding: var(--spacing-md);
}
.site-header {
grid-column: 1 / -1;
}
.main-content {
grid-column: 1 / -1;
display: grid;
grid-template-columns: repeat(${layout.grid.columns}, 1fr);
gap: ${layout.grid.gutters}px;
}
.site-footer {
grid-column: 1 / -1;
}`;
}
return `
/* Flexbox Layout */
.layout-flex {
display: flex;
flex-direction: column;
min-height: 100vh;
}
.main-content {
flex: 1;
max-width: 1200px;
margin: 0 auto;
padding: var(--spacing-md);
}`;
}
/**
* Generate components CSS
*/
generateComponentsCSS(components) {
let css = '/* SuperDesign Components */\n\n';
const allComponents = [...components.required, ...components.recommended];
for (const component of allComponents) {
css += this.getComponentCSS(component);
}
return css;
}
/**
* Get CSS for specific component
*/
getComponentCSS(componentName) {
const componentStyles = {
navigation: `
/* Navigation Component */
.navigation {
display: flex;
align-items: center;
justify-content: space-between;
padding: var(--spacing-md) 0;
border-bottom: 1px solid var(--border-color);
}
.nav-logo {
font-size: 1.5rem;
font-weight: 700;
color: var(--primary-color);
text-decoration: none;
}
.nav-menu {
display: flex;
list-style: none;
gap: var(--spacing-lg);
}
.nav-link {
color: var(--text-secondary);
text-decoration: none;
font-weight: 500;
transition: color 0.2s ease;
}
.nav-link:hover,
.nav-link:focus {
color: var(--primary-color);
}
`,
card: `
/* Card Component */
.card {
background: var(--surface-color);
border: 1px solid var(--border-color);
border-radius: var(--radius-md);
padding: var(--spacing-lg);
box-shadow: var(--shadow-sm);
transition: all 0.2s ease;
}
.card:hover {
box-shadow: var(--shadow-md);
transform: translateY(-1px);
}
.card-header {
margin-bottom: var(--spacing-md);
}
.card-title {
font-size: 1.25rem;
font-weight: 600;
margin-bottom: var(--spacing-xs);
}
.card-content {
color: var(--text-secondary);
}
`,
button: `
/* Button Component */
.button {
display: inline-flex;
align-items: center;
justify-content: center;
padding: var(--spacing-sm) var(--spacing-lg);
border: none;
border-radius: var(--radius-md);
font-weight: 500;
text-decoration: none;
cursor: pointer;
transition: all 0.2s ease;
font-family: inherit;
}
.button-primary {
background: var(--primary-color);
color: white;
}
.button-primary:hover {
background: color-mix(in srgb, var(--primary-color) 85%, black);
}
.button-secondary {
background: var(--surface-color);
color: var(--text-primary);
border: 1px solid var(--border-color);
}
.button-secondary:hover {
background: color-mix(in srgb, var(--surface-color) 85%, black);
}
`,
form: `
/* Form Components */
.form {
max-width: 400px;
margin: 0 auto;
}
.form-group {
margin-bottom: var(--spacing-lg);
}
.form-label {
display: block;
margin-bottom: var(--spacing-xs);
font-weight: 500;
color: var(--text-primary);
}
.form-input {
width: 100%;
padding: var(--spacing-sm) var(--spacing-md);
border: 1px solid var(--border-color);
border-radius: var(--radius-md);
font-family: inherit;
transition: border-color 0.2s ease;
}
.form-input:focus {
outline: none;
border-color: var(--primary-color);
box-shadow: 0 0 0 3px color-mix(in srgb, var(--primary-color) 10%, transparent);
}
`
};
return componentStyles[componentName] || `/* ${componentName} component styles */\n`;
}
/**
* Generate responsive CSS
*/
generateResponsiveCSS(layout) {
return `/* Responsive Design */
/* Mobile First Approach */
(max-width: ${layout.breakpoints.tablet - 1}px) {
.layout-grid {
grid-template-columns: 1fr;
padding: var(--spacing-sm);
}
.navigation {
flex-direction: column;
gap: var(--spacing-md);
}
.nav-menu {
flex-direction: column;
gap: var(--spacing-sm);
}
}
/* Tablet */
(min-width: ${layout.breakpoints.tablet}px) and (max-width: ${layout.breakpoints.desktop - 1}px) {
.layout-grid {
grid-template-columns: repeat(${Math.ceil(layout.grid.columns / 2)}, 1fr);
}
}
/* Desktop */
(min-width: ${layout.breakpoints.desktop}px) {
.layout-grid {
grid-template-columns: repeat(${layout.grid.columns}, 1fr);
}
}
/* Large Desktop */
(min-width: 1440px) {
.layout-grid {
max-width: 1400px;
}
}`;
}
/**
* Generate JavaScript functionality
*/
async generateJavaScript(designResult) {
const { components, intent } = designResult;
return `// SuperDesign Generated JavaScript
// Design System: SuperDesign v2.1
class SuperDesignApp {
constructor() {
this.init();
}
init() {
this.setupEventListeners();
this.initializeComponents();
this.setupAccessibility();
}
setupEventListeners() {
document.addEventListener('DOMContentLoaded', () => {
console.log('SuperDesign app initialized');
});
}
initializeComponents() {
${this.generateComponentInitialization(components)}
}
setupAccessibility() {
// Keyboard navigation
document.addEventListener('keydown', (e) => {
if (e.key === 'Tab') {
document.body.classList.add('keyboard-navigation');
}
});
// Mouse navigation
document.addEventListener('mousedown', () => {
document.body.classList.remove('keyboard-navigation');
});
}
}
// Initialize app
new SuperDesignApp();`;
}
/**
* Generate component initialization code
*/
generateComponentInitialization(components) {
const allComponents = [...components.required, ...components.recommended];
let initCode = '';
if (allComponents.includes('navigation')) {
initCode += `
// Navigation component
this.initNavigation();`;
}
if (allComponents.includes('form')) {
initCode += `
// Form validation
this.initFormValidation();`;
}
if (allComponents.includes('modal')) {
initCode += `
// Modal functionality
this.initModals();`;
}
return initCode;
}
/**
* Write generated code to files
*/
async writeCodeFiles(codeGeneration, outputDir) {
try {
// Ensure output directory exists
await fs.ensureDir(outputDir);
// Create directory structure
await fs.ensureDir(path.join(outputDir, 'styles'));
await fs.ensureDir(path.join(outputDir, 'scripts'));
await fs.ensureDir(path.join(outputDir, 'components'));
// Write HTML file
await fs.writeFile(
path.join(outputDir, 'index.html'),
codeGeneration.html
);
// Write CSS files
for (const [filename, content] of Object.entries(codeGeneration.css)) {
await fs.writeFile(
path.join(outputDir, 'styles', filename),
content
);
}
// Write JavaScript file
await fs.writeFile(
path.join(outputDir, 'scripts', 'main.js'),
codeGeneration.javascript
);
// Write component files if any
if (codeGeneration.components) {
for (const [componentName, componentCode] of Object.entries(codeGeneration.components)) {
await fs.writeFile(
path.join(outputDir, 'components', `${componentName}.html`),
componentCode
);
}
}
this.logger.info('Code files written successfully', {
outputDir,
filesWritten: Object.keys(codeGeneration).length
});
} catch (error) {
this.logger.error('Failed to write code files', error);
throw error;
}
}
/**
* Load design system configuration
*/
loadDesignSystem() {
return {
colors: {
primary: '#2563eb',
secondary: '#64748b',
accent: '#0ea5e9',
background: '#ffffff',
surface: '#f8fafc',
text: {
primary: '#0f172a',
secondary: '#475569'
},
border: '#e2e8f0'
},
typography: {
fontFamily: {
sans: '-apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif',
mono: '"SF Mono", Monaco, "Cascadia Code", monospace'
},
fontSize: {
xs: '0.75rem',
sm: '0.875rem',
base: '1rem',
lg: '1.125rem',
xl: '1.25rem',
'2xl': '1.5rem',
'3xl': '1.875rem'
}
},
spacing: {
xs: '0.5rem',
sm: '0.75rem',
md: '1rem',
lg: '1.5rem',
xl: '2rem',
'2xl': '3rem'
},
borderRadius: {
sm: '0.375rem',
md: '0.5rem',
lg: '0.75rem',
xl: '1rem'
}
};
}
/**
* Load component templates
*/
loadComponentTemplates() {
return {
navigation: this.getNavigationTemplate(),
card: this.getCardTemplate(),
button: this.getButtonTemplate(),
form: this.getFormTemplate()
};
}
/**
* Render HTML from structure object
*/
renderHTML(structure) {
return `${structure.doctype}
<html${this.renderAttributes(structure.html.attributes)}>
<head>${structure.html.head}
</head>
${structure.html.body}
</html>`;
}
/**
* Render HTML attributes
*/
renderAttributes(attributes) {
if (!attributes) return '';
return Object.entries(attributes)
.map(([key, value]) => ` ${key}="${value}"`)
.join('');
}
// Component template methods would go here...
getNavigationTemplate() { return '<nav class="navigation"><!-- Navigation --></nav>'; }
getCardTemplate() { return '<div class="card"><!-- Card content --></div>'; }
getButtonTemplate() { return '<button class="button button-primary">Button</button>'; }
getFormTemplate() { return '<form class="form"><!-- Form fields --></form>'; }
loadLayoutEngines() { return {}; }
generateDesignSystemCSS() { return '/* Design system styles */'; }
generateComponents() { return {}; }
generateAssets() { return {}; }
generatePageTitle(intent, pattern) {
return `${pattern.selectedPattern.name} - ${intent.intent.type.charAt(0).toUpperCase() + intent.intent.type.slice(1)}`;
}
// Component template methods
getNavigationTemplate() { return '<nav class="navigation"><!-- Navigation --></nav>'; }
getCardTemplate() { return '<div class="card"><!-- Card content --></div>'; }
getButtonTemplate() { return '<button class="button button-primary">Button</button>'; }
getFormTemplate() { return '<form class="form"><!-- Form fields --></form>'; }
// Helper methods
loadLayoutEngines() { return {}; }
generateDesignSystemCSS() { return '/* Design system styles */'; }
generateComponents() { return {}; }
generateAssets() { return {}; }
}
module.exports = { CodeGenerationEngine };