create-brand-os-app
Version:
Create a Brand-OS powered Next.js app in seconds
598 lines (513 loc) ⢠16.8 kB
JavaScript
#!/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!
`);