UNPKG

create-brand-os-app

Version:

Create a Brand-OS powered Next.js app in seconds

598 lines (513 loc) • 16.8 kB
#!/usr/bin/env node /** * create-brand-os-app v2 * Enhanced starter that ensures AI tools generate perfect Brand-OS code */ const { execSync } = require('child_process'); const fs = require('fs'); const path = require('path'); const appName = process.argv[2] || 'my-brand-app'; console.log(`\nšŸš€ Creating Brand-OS app: ${appName}\n`); // Create Next.js app (force no src directory for simplicity) console.log('šŸ“¦ Creating Next.js app...'); execSync(`npx create-next-app@latest ${appName} --typescript --tailwind --app --no-git --no-src`, { stdio: 'inherit' }); // Navigate to app directory const appPath = path.join(process.cwd(), appName); process.chdir(appPath); // Install Brand-OS console.log('\nšŸ“¦ Installing Brand-OS...'); execSync('npm install brand-os-core@latest --legacy-peer-deps', { stdio: 'inherit' }); // Create COMPLETE layout.tsx with all tokens const layoutContent = `import type { Metadata } from "next"; import { BrandOSProvider } from 'brand-os-core'; import "./globals.css"; export const metadata: Metadata = { title: "Brand-OS App", description: "AI-enforced design system", }; // COMPLETE token set - DO NOT REMOVE ANY const brandTokens = { // Glass morphism (ESSENTIAL) '--glass-bg': 'rgba(255, 255, 255, 0.6)', '--glass-border': 'rgba(255, 255, 255, 0.2)', '--glass-blur': '40px', '--shadow-xl': '0 20px 25px -5px rgba(0, 0, 0, 0.1)', '--shadow-lg': '0 10px 15px -3px rgba(0, 0, 0, 0.1)', '--shadow-md': '0 4px 6px -1px rgba(0, 0, 0, 0.1)', '--shadow-sm': '0 1px 2px 0 rgba(0, 0, 0, 0.05)', // Brand colors '--brand-primary': '#3B82F6', '--brand-secondary': '#8B5CF6', '--brand-accent': '#10B981', '--brand-success': '#10B981', '--brand-warning': '#F59E0B', '--brand-danger': '#EF4444', '--brand-info': '#3B82F6', // Text colors '--text-primary': '#111827', '--text-secondary': '#6B7280', '--text-tertiary': '#9CA3AF', '--text-inverse': '#FFFFFF', // Backgrounds '--bg-primary': '#FFFFFF', '--bg-secondary': '#F9FAFB', '--bg-tertiary': '#F3F4F6', '--bg-inverse': '#111827', // Borders '--border-primary': '#E5E7EB', '--border-secondary': '#D1D5DB', '--border-tertiary': '#9CA3AF', // Spacing '--spacing-1': '0.25rem', '--spacing-2': '0.5rem', '--spacing-3': '0.75rem', '--spacing-4': '1rem', '--spacing-5': '1.25rem', '--spacing-6': '1.5rem', '--spacing-8': '2rem', '--spacing-10': '2.5rem', '--spacing-12': '3rem', '--spacing-16': '4rem', // Radius '--radius-sm': '0.125rem', '--radius-md': '0.375rem', '--radius-lg': '0.5rem', '--radius-xl': '0.75rem', '--radius-2xl': '1rem', '--radius-full': '9999px', // Typography '--font-sans': 'system-ui, -apple-system, sans-serif', '--font-mono': 'Consolas, Monaco, monospace', '--text-xs': '0.75rem', '--text-sm': '0.875rem', '--text-base': '1rem', '--text-lg': '1.125rem', '--text-xl': '1.25rem', '--text-2xl': '1.5rem', '--text-3xl': '1.875rem', '--text-4xl': '2.25rem', '--font-light': '300', '--font-normal': '400', '--font-medium': '500', '--font-semibold': '600', '--font-bold': '700', }; export default function RootLayout({ children, }: { children: React.ReactNode; }) { return ( <html lang="en"> <body style={{ margin: 0, padding: 0 }}> <BrandOSProvider config={{ nano: brandTokens }}> {children} </BrandOSProvider> </body> </html> ); }`; fs.writeFileSync('app/layout.tsx', layoutContent); // Create PERFECT example page const pageContent = `'use client'; import { PageShell } from 'brand-os-core'; import { CardShell, MetricItem, Stack, Grid, Badge, TargetBand, Panel } from 'brand-os-core/primitives'; export default function Dashboard() { // Sample data const metrics = [ { label: "Revenue", value: "125,000", change: "+12.5%", trend: "up" as const }, { label: "Users", value: "8,421", change: "+8.2%", trend: "up" as const }, { label: "Sessions", value: "3,291", change: "+5.7%", trend: "up" as const }, { label: "Error Rate", value: "0.42%", change: "-15.3%", trend: "down" as const }, ]; const features = [ { name: "Analytics", value: 85, target: 100 }, { name: "Reporting", value: 72, target: 100 }, { name: "Automation", value: 93, target: 100 }, { name: "Integration", value: 65, target: 100 }, ]; const activities = [ { user: "Alex Chen", action: "Generated report", time: "2 mins ago", status: "success" }, { user: "Sarah Miller", action: "Updated dashboard", time: "5 mins ago", status: "info" }, { user: "John Davis", action: "API integration", time: "8 mins ago", status: "warning" }, ]; return ( <PageShell layout="dashboard" pattern="gradient"> {/* Header Section */} <PageShell.Header> <h1 style={{ fontSize: 'var(--text-3xl)', fontWeight: 'var(--font-bold)', color: 'var(--text-primary)', margin: 0, }}> Welcome to Brand-OS </h1> <p style={{ color: 'var(--text-secondary)', marginTop: 'var(--spacing-2)', }}> Your AI now generates perfect UI automatically </p> </PageShell.Header> {/* Metrics Row */} <PageShell.Metrics cols={4}> {metrics.map((metric, i) => ( <CardShell key={i} hover> <MetricItem {...metric} /> </CardShell> ))} </PageShell.Metrics> {/* Main Content */} <PageShell.Main> <Grid cols={2} gap="large"> {/* Feature Usage */} <CardShell padding="large"> <Stack gap="normal"> <h3 style={{ fontSize: 'var(--text-lg)', fontWeight: 'var(--font-semibold)', color: 'var(--text-primary)', }}> Feature Usage </h3> {features.map(feature => ( <div key={feature.name}> <TargetBand value={feature.value} target={feature.target} label={\`\${feature.name} (\${feature.value}%)\`} /> </div> ))} </Stack> </CardShell> {/* Live Activity */} <Panel variant="elevated"> <div style={{ padding: 'var(--spacing-4)' }}> <h3 style={{ fontSize: 'var(--text-lg)', fontWeight: 'var(--font-semibold)', color: 'var(--text-primary)', marginBottom: 'var(--spacing-4)', }}> Live Activity </h3> <Stack gap="small"> {activities.map((activity, i) => ( <div key={i} style={{ display: 'flex', alignItems: 'center', gap: 'var(--spacing-3)', padding: 'var(--spacing-2)', borderRadius: 'var(--radius-md)', background: 'var(--bg-tertiary)', }}> <Badge variant={activity.status as any}> {activity.status} </Badge> <span style={{ flex: 1, color: 'var(--text-primary)', fontSize: 'var(--text-sm)', }}> <strong>{activity.user}</strong> {activity.action} </span> <span style={{ color: 'var(--text-secondary)', fontSize: 'var(--text-xs)', }}> {activity.time} </span> </div> ))} </Stack> </div> </Panel> </Grid> {/* Instructions Card */} <div style={{ marginTop: 'var(--spacing-6)' }}> <CardShell padding="large"> <Stack gap="normal"> <h3 style={{ fontSize: 'var(--text-xl)', fontWeight: 'var(--font-semibold)', color: 'var(--text-primary)', }}> šŸŽÆ Quick Start Guide </h3> <div style={{ color: 'var(--text-secondary)' }}> <p>1. This page shows the correct Brand-OS structure</p> <p>2. Every page must use PageShell as the wrapper</p> <p>3. Import primitives from 'brand-os-core/primitives'</p> <p>4. Never use className or Tailwind - only CSS variables</p> <p>5. Check CLAUDE.md for AI-specific rules</p> </div> </Stack> </CardShell> </div> </PageShell.Main> </PageShell> ); }`; fs.writeFileSync('app/page.tsx', pageContent); // Create STRICT CLAUDE.md with examples const claudeRules = `# 🚨 MANDATORY BRAND-OS RULES FOR CLAUDE CODE ## CRITICAL: You MUST use Brand-OS components for EVERYTHING ### āŒ NEVER WRITE THIS (Instant failure): \`\`\`jsx // āŒ WRONG - Never use vanilla HTML/CSS <div className="grid grid-cols-4 gap-6"> <div className="bg-white rounded-lg shadow p-6"> <h3 className="text-gray-800">Revenue</h3> <p className="text-3xl">$125,000</p> </div> </div> \`\`\` ### āœ… ALWAYS WRITE THIS: \`\`\`jsx // āœ… CORRECT - Always use Brand-OS import { PageShell } from 'brand-os-core'; import { CardShell, MetricItem } from 'brand-os-core/primitives'; <PageShell layout="dashboard" pattern="gradient"> <PageShell.Metrics cols={4}> <CardShell hover> <MetricItem value="125,000" label="Revenue" trend="up" /> </CardShell> </PageShell.Metrics> </PageShell> \`\`\` ## IMPORT RULES (Follow exactly): \`\`\`jsx // Core imports import { PageShell, Resolved, useBrandOS } from 'brand-os-core'; // Primitive imports (ALWAYS from /primitives) import { CardShell, Panel, Stack, Grid, MetricItem, Badge, TargetBand, Sparkline } from 'brand-os-core/primitives'; \`\`\` ## MANDATORY PAGE STRUCTURE: Every page.tsx MUST follow this pattern: \`\`\`jsx 'use client'; // Required for interactivity export default function PageName() { return ( <PageShell layout="dashboard" pattern="gradient"> <PageShell.Header> {/* Header content */} </PageShell.Header> <PageShell.Metrics cols={4}> {/* Metric cards */} </PageShell.Metrics> <PageShell.Main> {/* Main content */} </PageShell.Main> </PageShell> ); } \`\`\` ## COMPONENT REFERENCE: ### PageShell (Required wrapper) - Props: layout="dashboard|analytics|settings|landing" - Props: pattern="gradient|dots|grid|aurora|none" - Sections: Header, Metrics, Main, Sidebar, Footer ### CardShell (Glass morphism cards) - Props: hover={true}, padding="small|normal|large" - Use for: Any card-like content ### MetricItem (Metrics display) - Props: value, label, change, trend="up|down|neutral" - Use for: KPIs, statistics ### TargetBand (Progress bars) - Props: value={number}, target={number}, label="text" - Use for: Progress, quotas, goals ### Badge (Status indicators) - Props: variant="success|warning|danger|info|default" - Use for: Status, tags, labels ### Stack (Vertical layout) - Props: gap="small|normal|large" - Use for: Vertical spacing ### Grid (Grid layout) - Props: cols={2|3|4}, gap="small|normal|large" - Use for: Multi-column layouts ### Panel (Simple container) - Props: variant="default|bordered|elevated" - Use for: Sections, groups ## STYLING RULES: 1. āŒ NEVER use className 2. āŒ NEVER use Tailwind classes 3. āŒ NEVER write custom CSS 4. āœ… ONLY use inline styles with CSS variables 5. āœ… ALWAYS use var(--spacing-*) for spacing 6. āœ… ALWAYS use var(--text-*) for colors 7. āœ… ALWAYS use var(--radius-*) for border radius ## CSS VARIABLES YOU CAN USE: - Spacing: --spacing-1 through --spacing-16 - Text: --text-primary, --text-secondary, --text-tertiary - Colors: --brand-primary, --brand-success, --brand-warning - Shadows: --shadow-sm, --shadow-md, --shadow-lg, --shadow-xl - Radius: --radius-sm, --radius-md, --radius-lg, --radius-xl - Typography: --text-xs through --text-4xl - Font weights: --font-light through --font-bold ## EXAMPLES TO COPY: ### Metric Card: \`\`\`jsx <CardShell hover> <MetricItem value="125,000" label="Revenue" change="+12%" trend="up" /> </CardShell> \`\`\` ### Feature List: \`\`\`jsx <CardShell padding="large"> <Stack gap="normal"> <h3>Features</h3> <TargetBand value={85} target={100} label="Analytics" /> <TargetBand value={72} target={100} label="Reports" /> </Stack> </CardShell> \`\`\` ### Activity Feed: \`\`\`jsx <Panel variant="elevated"> <Stack gap="small"> <h3>Activity</h3> <div style={{ display: 'flex', gap: 'var(--spacing-2)' }}> <Badge variant="success">Active</Badge> <span>User action here</span> </div> </Stack> </Panel> \`\`\` ## IF YOU WRITE ANY OF THESE, YOU FAILED: - <div className="..."> - bg-white, text-gray-800, shadow-lg - display: flex without CSS variables - Regular HTML elements for layout - import from 'react' for UI components ## REMEMBER: - app/page.tsx has a complete working example - Copy its structure for ALL new pages - When in doubt, use Brand-OS primitives - Glass morphism is automatic with CardShell `; fs.writeFileSync('CLAUDE.md', claudeRules); // Create .cursorrules for Cursor IDE const cursorRules = `# Brand-OS Rules for Cursor When generating code for this project: 1. ALWAYS import from 'brand-os-core' and 'brand-os-core/primitives' 2. ALWAYS wrap pages in PageShell component 3. NEVER use className or Tailwind classes 4. NEVER use div for layout - use Stack, Grid, CardShell, Panel 5. ALWAYS use CSS variables for styling (var(--spacing-4), etc.) Example structure for EVERY page: \`\`\`jsx import { PageShell } from 'brand-os-core'; import { CardShell, MetricItem } from 'brand-os-core/primitives'; export default function Page() { return ( <PageShell layout="dashboard" pattern="gradient"> <PageShell.Header> <PageShell.Metrics> <PageShell.Main> </PageShell> ); } \`\`\` Refer to app/page.tsx for the correct implementation pattern. `; fs.writeFileSync('.cursorrules', cursorRules); // Create MCP config for Cursor fs.mkdirSync('.cursor', { recursive: true }); const cursorMCP = { mcpServers: { "brand-os": { command: "npx", args: ["-y", "brand-os-mcp-server"] } } }; fs.writeFileSync('.cursor/mcp.json', JSON.stringify(cursorMCP, null, 2)); // Create MCP config for VS Code fs.mkdirSync('.vscode', { recursive: true }); const vscodeMCP = { mcpServers: { "brand-os": { command: "npx", args: ["-y", "brand-os-mcp-server"] } } }; fs.writeFileSync('.vscode/mcp.json', JSON.stringify(vscodeMCP, null, 2)); // Create examples directory with more examples fs.mkdirSync('app/examples', { recursive: true }); // Create a simple example const simpleExample = `'use client'; import { PageShell } from 'brand-os-core'; import { CardShell, Badge, Stack } from 'brand-os-core/primitives'; export default function SimpleExample() { return ( <PageShell layout="dashboard" pattern="gradient"> <PageShell.Header> <h1>Simple Example</h1> </PageShell.Header> <PageShell.Main> <CardShell> <Stack gap="normal"> <h2>This is the correct structure</h2> <p>Every component uses Brand-OS primitives</p> <Badge variant="success">Working</Badge> </Stack> </CardShell> </PageShell.Main> </PageShell> ); }`; fs.writeFileSync('app/examples/simple.tsx', simpleExample); console.log(` āœ… Brand-OS app created with AI optimization! Next steps: 1. cd ${appName} 2. npm run dev 3. Open http://localhost:3000 ✨ What's included: - Complete token system for glass morphism - Working dashboard example - CLAUDE.md with strict rules - .cursorrules for Cursor IDE - Example components to copy šŸ¤– AI IDE Support Configured: šŸ“± Cursor IDE: āœ… Ready MCP configured in .cursor/mcp.json Just restart Cursor to activate šŸ’» VS Code: āœ… Ready MCP configured in .vscode/mcp.json Just restart VS Code to activate šŸ–„ļø Claude Code: Setup Required Add to ~/Library/Application Support/Claude/claude_desktop_config.json: { "mcpServers": { "brand-os": { "command": "npx", "args": ["-y", "brand-os-mcp-server"] } } } šŸ“ Important: - NEVER use className or Tailwind - ALWAYS use PageShell wrapper - ALWAYS import from brand-os-core/primitives Your AI will now generate perfect Brand-OS code! `);