Open Design 深度拆解:当 AI 代理遇上设计系统——从 12 种编程 CLI 到 72 套设计语言的全链路技术实战
14.8K Stars,5 天破万,这个开源项目凭什么成为 Claude Design 的最强挑战者?
前言:设计工具的「代理化」时刻
2026 年 4 月 17 日,Anthropic 发布了 Claude Design——一个让 LLM 从「写文字」变成「产出设计物」的工具。它在社交媒体上疯传,因为这是第一次,AI 不再只是给你设计建议,而是直接输出可用的设计稿、PPT、原型页面。
但 Claude Design 有三个致命问题:闭源、付费、只支持 Anthropic 的模型。
五天后,一个名为 Open Design 的开源项目横空出世。它用一套完全不同的架构,实现了几乎相同的能力,还额外支持 12 种编程代理 CLI、72 套品牌设计系统、31 种组合式技能,以及完整的 BYOK(Bring Your Own Key)能力。
本文将从程序员视角,深入拆解 Open Design 的技术架构、设计哲学和实现细节。
一、项目概览:为什么它能在 5 天内引爆社区
1.1 核心定位
Open Design 的定位非常清晰:
Claude Design 的开源替代品,本地优先,BYOK,支持 12 种编程代理 CLI 自动检测。
它的核心洞察是:最强的编程代理已经装在你的笔记本上了——Claude Code、Codex、Cursor、Gemini CLI……为什么不直接复用它们,而不是重新造一个代理?
1.2 技术栈一览
├── TypeScript (主语言)
├── Next.js (Web 层)
├── SQLite (持久化)
├── React 18 + Babel (沙箱渲染)
├── Tailwind CSS (样式系统)
├── Node.js Daemon (本地守护进程)
└── 多种 AI CLI 适配器
1.3 核心数据
| 指标 | 数值 |
|---|---|
| Stars | 14,812 |
| Forks | 1,673 |
| Skills | 31 |
| Design Systems | 72 |
| 支持的 CLI 代理 | 12 |
| 媒体生成模板 | 93 |
二、架构设计:四层分离的代理驱动模型
Open Design 的架构可以用一张图概括:
┌─────────────────────────────────────────────────────────────┐
│ Web UI (Next.js) │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────┐ │
│ │ Skill Picker │ │ Direction │ │ Live Preview │ │
│ │ (31 Skills) │ │ Picker (5) │ │ (Sandboxed Iframe) │ │
│ └─────────────┘ └─────────────┘ └─────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ API Layer (Next.js API) │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────┐ │
│ │ Agent Router │ │ Proxy API │ │ Import Handler │ │
│ │ (12 CLIs) │ │ (BYOK) │ │ (Claude Design) │ │
│ └─────────────┘ └─────────────┘ └─────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ Local Daemon (Node.js Process) │
│ ┌───────────────────────────────────────────────────────┐ │
│ │ - PATH 扫描,检测已安装的 CLI │ │
│ │ - 在项目文件夹中 spawn 子进程 │ │
│ │ - 提供真实的 Read/Write/Bash/WebFetch 能力 │ │
│ │ - 阻止 SSRF / Internal-IP 访问 │ │
│ └───────────────────────────────────────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ Project Workspace (文件系统) │
│ ┌─────────────────┐ ┌─────────────┐ ┌────────────────┐ │
│ │ Seed Templates │ │ Layout Lib │ │ Self-check │ │
│ │ (按 Skill 初始化)│ │ (设计系统) │ │ Checklist │ │
│ └─────────────────┘ └─────────────┘ └────────────────┘ │
└─────────────────────────────────────────────────────────────┘
2.1 第一层:Web UI
Open Design 的前端是一个标准的 Next.js 应用,但有几个关键设计:
Skill Picker(技能选择器)
31 种技能被分为 9 个场景:
// apps/web/src/prompts/skills.ts
export const SKILL_GROUPS = {
design: ['web-prototype', 'saas-landing', 'dashboard', 'mobile-app', 'gamified-app', 'social-carousel', 'magazine-poster', 'dating-web', 'sprite-animation', 'motion-frames'],
marketing: ['pitch-deck', 'product-launch', 'case-study'],
operation: ['weekly-update', 'team-okrs', 'kanban-board'],
engineering: ['wireframe-sketch', 'pm-spec', 'eng-runbook', 'api-doc'],
product: ['user-journey', 'feature-spec', 'roadmap'],
finance: ['finance-report', 'invoice', 'budget-plan'],
hr: ['onboarding-guide', 'job-description', 'performance-review'],
sale: ['proposal', 'contract', 'pricing-page'],
personal: ['resume', 'portfolio', 'blog-theme']
};
Direction Picker(视觉方向选择器)
五种设计风格,每种都有确定的配色和字体:
// apps/web/src/prompts/directions.ts
export const VISUAL_DIRECTIONS = {
editorial_monocle: {
name: 'Editorial Monocle',
palette: [
'#1a1a2e', '#16213e', '#0f3460', '#e94560', '#ffffff'
],
fonts: {
heading: 'Playfair Display',
body: 'Source Serif Pro'
}
},
modern_minimal: {
name: 'Modern Minimal',
palette: [
'#ffffff', '#f8f9fa', '#e9ecef', '#212529', '#0d6efd'
],
fonts: {
heading: 'Inter',
body: 'Inter'
}
},
warm_soft: {
name: 'Warm Soft',
palette: [
'#fefae0', '#faedcd', '#e9edc9', '#ccd5ae', '#d4a373'
],
fonts: {
heading: 'Nunito',
body: 'Nunito'
}
},
tech_utility: {
name: 'Tech Utility',
palette: [
'#0d1117', '#161b22', '#21262d', '#30363d', '#c9d1d9'
],
fonts: {
heading: 'JetBrains Mono',
body: 'Space Grotesk'
}
},
brutalist_experimental: {
name: 'Brutalist Experimental',
palette: [
'#ff0000', '#000000', '#ffffff', '#ffff00', '#00ff00'
],
fonts: {
heading: 'Space Mono',
body: 'Courier New'
}
}
};
Live Preview(实时预览)
这是一个沙箱化的 iframe,使用 React 18 + Babel 在浏览器端实时编译 JSX:
// apps/web/src/components/preview/SandboxedPreview.tsx
export function SandboxedPreview({ artifact }: { artifact: string }) {
const iframeRef = useRef<HTMLIFrameElement>(null);
useEffect(() => {
const iframe = iframeRef.current;
if (!iframe) return;
// 注入 React 18 + Babel 运行时
const html = `
<!DOCTYPE html>
<html>
<head>
<script src="https://unpkg.com/react@18/umd/react.production.min.js"></script>
<script src="https://unpkg.com/react-dom@18/umd/react-dom.production.min.js"></script>
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
<script src="https://cdn.tailwindcss.com"></script>
</head>
<body>
<div id="root"></div>
<script type="text/babel">
${artifact}
</script>
</body>
</html>
`;
iframe.srcdoc = html;
}, [artifact]);
return (
<iframe
ref={iframeRef}
sandbox="allow-scripts allow-same-origin"
className="w-full h-full border-0"
/>
);
}
2.2 第二层:API Layer
这一层负责路由请求到不同的代理后端。
Agent Router(代理路由器)
// apps/web/src/lib/agent-router.ts
import { spawn } from 'child_process';
import which from 'which';
const AGENT_CLIS = [
{ name: 'claude', command: 'claude', protocol: 'claude-code' },
{ name: 'codex', command: 'codex', protocol: 'codex' },
{ name: 'devin', command: 'devin', protocol: 'devin-terminal' },
{ name: 'cursor', command: 'cursor-agent', protocol: 'cursor' },
{ name: 'gemini', command: 'gemini', protocol: 'gemini-cli' },
{ name: 'opencode', command: 'openode', protocol: 'openode' },
{ name: 'qwen', command: 'qwen-code', protocol: 'qwen' },
{ name: 'copilot', command: 'gh', args: ['copilot', 'chat'], protocol: 'copilot' },
{ name: 'hermes', command: 'hermes', protocol: 'acp' },
{ name: 'kimi', command: 'kimi', protocol: 'acp' },
{ name: 'pi', command: 'pi', protocol: 'rpc' },
{ name: 'kiro', command: 'kiro', protocol: 'acp' }
];
export async function detectAgents(): Promise<AgentInfo[]> {
const detected: AgentInfo[] = [];
for (const agent of AGENT_CLIS) {
try {
const path = await which(agent.command);
detected.push({ ...agent, path });
} catch {
// CLI 未安装
}
}
return detected;
}
BYOK Proxy
如果没有安装任何 CLI,用户可以直接提供 OpenAI 兼容的 API:
// apps/web/pages/api/proxy/stream.ts
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
const { baseUrl, apiKey, model, messages } = req.body;
// SSRF 防护:阻止内网 IP
const url = new URL(baseUrl);
if (isInternalIP(url.hostname)) {
return res.status(400).json({ error: 'Internal IP blocked' });
}
// 转发请求到用户指定的端点
const response = await fetch(`${baseUrl}/chat/completions`, {
method: 'POST',
headers: {
'Authorization': `Bearer ${apiKey}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({ model, messages, stream: true })
});
// 流式响应
res.setHeader('Content-Type', 'text/event-stream');
for await (const chunk of response.body) {
res.write(chunk);
}
res.end();
}
2.3 第三层:Local Daemon
这是整个系统最关键的部分——一个本地守护进程,负责:
- 扫描 PATH,检测已安装的 CLI
- 在项目文件夹中 spawn 子进程
- 提供真实的文件系统访问能力
- 执行安全策略(阻止 SSRF)
// daemon/src/index.ts
import { spawn, ChildProcess } from 'child_process';
import { Server } from 'socket.io';
import fs from 'fs/promises';
import path from 'path';
interface AgentSession {
process: ChildProcess;
projectDir: string;
agent: string;
}
const sessions = new Map<string, AgentSession>();
const io = new Server(3001, { cors: { origin: '*' } });
io.on('connection', (socket) => {
socket.on('start-agent', async ({ agent, projectDir, taskId }) => {
// 创建项目目录
await fs.mkdir(projectDir, { recursive: true });
// 初始化种子模板
await initializeSeedTemplate(projectDir, taskId);
// Spawn 代理进程
const proc = spawn(agent, [], {
cwd: projectDir,
stdio: ['pipe', 'pipe', 'pipe'],
env: { ...process.env, AGENT_MODE: 'design' }
});
sessions.set(socket.id, { process: proc, projectDir, agent });
proc.stdout.on('data', (data) => {
socket.emit('agent-stdout', data.toString());
});
proc.stderr.on('data', (data) => {
socket.emit('agent-stderr', data.toString());
});
proc.on('close', (code) => {
socket.emit('agent-close', { code });
sessions.delete(socket.id);
});
});
socket.on('send-input', ({ input }) => {
const session = sessions.get(socket.id);
if (session) {
session.process.stdin.write(input + '\n');
}
});
socket.on('disconnect', () => {
const session = sessions.get(socket.id);
if (session) {
session.process.kill();
sessions.delete(socket.id);
}
});
});
2.4 第四层:Project Workspace
每个设计任务都会创建一个独立的项目文件夹,包含:
project-workspace/
├── .od/
│ ├── app.sqlite # SQLite 数据库
│ └── config.json # 项目配置
├── seed/
│ ├── template.tsx # 种子模板
│ ├── layout-lib.ts # 布局库
│ └── checklist.md # 自检清单
├── design-systems/
│ └── linear/ # 选用的设计系统
├── assets/
│ ├── frames/ # 设备框架
│ └── images/ # 生成的图片
└── output/
├── index.html # 最终输出
├── deck.pdf # PPT 导出
└── preview.mp4 # 视频导出
三、Skill 系统:31 种组合式设计技能
Open Design 的 Skill 系统是其核心创新之一。每个 Skill 都是一个独立的「设计任务模板」,包含:
- 前置问卷:收集用户需求的表单
- 种子模板:初始化项目结构的代码
- 自检清单:AI 必须遵守的质量标准
- 输出格式:最终产物的结构定义
3.1 Skill 定义示例
以 saas-landing(SaaS 落地页)为例:
// skills/saas-landing/index.ts
export const skill: Skill = {
id: 'saas-landing',
name: 'SaaS Landing Page',
category: 'design',
description: 'Generate a conversion-optimized landing page for SaaS products',
// 前置问卷
questions: [
{ id: 'product_name', label: 'Product Name', type: 'text', required: true },
{ id: 'tagline', label: 'Tagline', type: 'text', required: true },
{ id: 'target_audience', label: 'Target Audience', type: 'textarea', required: true },
{ id: 'key_features', label: 'Key Features (comma-separated)', type: 'text', required: true },
{ id: 'pricing_tiers', label: 'Pricing Tiers (e.g., Free/Pro/Enterprise)', type: 'text', required: true },
{ id: 'cta_text', label: 'Primary CTA Text', type: 'text', default: 'Get Started Free' }
],
// 种子模板
seedTemplate: async (answers) => {
return `
import React from 'react';
import { Hero } from './components/Hero';
import { Features } from './components/Features';
import { Pricing } from './components/Pricing';
import { CTA } from './components/CTA';
export default function LandingPage() {
return (
<main className="min-h-screen bg-background">
<Hero
productName="${answers.product_name}"
tagline="${answers.tagline}"
ctaText="${answers.cta_text}"
/>
<Features features={${JSON.stringify(answers.key_features.split(','))}} />
<Pricing tiers={${JSON.stringify(answers.pricing_tiers.split('/'))}} />
<CTA ctaText="${answers.cta_text}" />
</main>
);
}
`;
},
// 自检清单
checklist: [
'✓ Hero section has clear value proposition',
'✓ Features section is visually balanced',
'✓ Pricing cards have consistent heights',
'✓ CTA buttons are prominent and accessible',
'✓ Mobile responsive layout'
],
// 输出格式
outputFormat: {
type: 'react-component',
entryFile: 'LandingPage.tsx',
exportFormats: ['html', 'pdf', 'zip']
}
};
3.2 五维自评系统
每个 Skill 都会触发一个「五维自评」流程,让 AI 对自己的输出进行质量检查:
// apps/web/src/prompts/critique.ts
export const CRITIQUE_DIMENSIONS = [
{
id: 'visual_hierarchy',
name: 'Visual Hierarchy',
description: 'Is the information architecture clear? Does the eye flow naturally?',
weight: 0.25
},
{
id: 'brand_consistency',
name: 'Brand Consistency',
description: 'Does it follow the selected design system? Colors, fonts, spacing?',
weight: 0.20
},
{
id: 'accessibility',
name: 'Accessibility',
description: 'WCAG 2.1 AA compliant? Color contrast, focus states, semantic HTML?',
weight: 0.20
},
{
id: 'responsiveness',
name: 'Responsiveness',
description: 'Does it work across 375px to 1440px? Mobile-first approach?',
weight: 0.20
},
{
id: 'conversion_optimization',
name: 'Conversion Optimization',
description: 'Clear CTAs? Trust signals? Social proof elements?',
weight: 0.15
}
];
export function generateCritiquePrompt(artifact: string): string {
return `
You are a senior design reviewer. Evaluate the following artifact against these 5 dimensions:
${CRITIQUE_DIMENSIONS.map(d => `- ${d.name}: ${d.description}`).join('\n')}
For each dimension, give:
1. A score from 1-10
2. A brief justification
3. Specific improvement suggestions
Artifact:
\`\`\`tsx
${artifact}
\`\`\`
Output JSON format:
{
"dimensions": [
{ "id": "visual_hierarchy", "score": 8, "justification": "...", "suggestions": ["...", "..."] },
...
],
"overall_score": 7.5,
"summary": "..."
}
`;
}
四、设计系统:72 套品牌级视觉语言
Open Design 内置了 72 套设计系统,来源包括:
- 手写入门模板:2 套基础模板
- 产品级设计系统:70 套(Linear、Stripe、Vercel、Airbnb 等)
- 设计技能包:57 套来自
awesome-design-skills
4.1 设计系统结构
每个设计系统包含以下元素:
// design-systems/linear/index.ts
export const linearDesignSystem: DesignSystem = {
name: 'Linear',
source: 'https://linear.app',
colors: {
// 语义化颜色
background: '#0a0a0b',
foreground: '#f5f5f5',
primary: '#5e6ad2',
secondary: '#2c2d30',
muted: '#8b8b8b',
accent: '#5e6ad2',
destructive: '#f44d4d',
border: '#212121',
card: '#141415',
// 扩展色板
palette: {
gray: ['#fafafa', '#f5f5f5', '#e5e5e5', '#d4d4d4', '#a3a3a3', '#737373', '#525252', '#404040', '#262626', '#171717'],
blue: ['#eff6ff', '#dbeafe', '#bfdbfe', '#93c5fd', '#60a5fa', '#3b82f6', '#2563eb', '#1d4ed8', '#1e40af', '#1e3a8a'],
purple: ['#faf5ff', '#f3e8ff', '#e9d5ff', '#d8b4fe', '#c084fc', '#a855f7', '#9333ea', '#7e22ce', '#6b21a8', '#581c87']
}
},
typography: {
fontFamily: {
sans: ['Inter', 'system-ui', 'sans-serif'],
mono: ['JetBrains Mono', 'Consolas', 'monospace']
},
fontSize: {
xs: '0.75rem',
sm: '0.875rem',
base: '1rem',
lg: '1.125rem',
xl: '1.25rem',
'2xl': '1.5rem',
'3xl': '1.875rem',
'4xl': '2.25rem',
'5xl': '3rem'
},
fontWeight: {
normal: '400',
medium: '500',
semibold: '600',
bold: '700'
},
lineHeight: {
tight: '1.25',
normal: '1.5',
relaxed: '1.75'
}
},
spacing: {
0: '0',
1: '0.25rem',
2: '0.5rem',
3: '0.75rem',
4: '1rem',
5: '1.25rem',
6: '1.5rem',
8: '2rem',
10: '2.5rem',
12: '3rem',
16: '4rem',
20: '5rem',
24: '6rem'
},
borderRadius: {
none: '0',
sm: '0.125rem',
DEFAULT: '0.25rem',
md: '0.375rem',
lg: '0.5rem',
xl: '0.75rem',
'2xl': '1rem',
full: '9999px'
},
shadows: {
sm: '0 1px 2px 0 rgb(0 0 0 / 0.05)',
DEFAULT: '0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1)',
md: '0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1)',
lg: '0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1)',
xl: '0 20px 25px -5px rgb(0 0 0 / 0.1), 0 8px 10px -6px rgb(0 0 0 / 0.1)'
},
animations: {
fadeIn: 'fadeIn 0.2s ease-out',
slideUp: 'slideUp 0.3s ease-out',
scaleIn: 'scaleIn 0.2s ease-out'
},
// 组件样式
components: {
button: {
base: 'inline-flex items-center justify-center rounded-md font-medium transition-colors',
variants: {
primary: 'bg-primary text-white hover:bg-primary/90',
secondary: 'bg-secondary text-foreground hover:bg-secondary/80',
outline: 'border border-border bg-transparent hover:bg-secondary'
},
sizes: {
sm: 'h-8 px-3 text-sm',
md: 'h-10 px-4 text-base',
lg: 'h-12 px-6 text-lg'
}
},
card: {
base: 'rounded-lg border border-border bg-card p-4',
variants: {
elevated: 'shadow-lg',
interactive: 'hover:border-primary/50 cursor-pointer'
}
}
}
};
4.2 设计系统集成方式
设计系统通过 Tailwind CSS 配置注入:
// tailwind.config.js
const designSystem = require('./design-systems/linear');
module.exports = {
content: ['./src/**/*.{ts,tsx}'],
theme: {
extend: {
colors: designSystem.colors,
fontFamily: designSystem.typography.fontFamily,
fontSize: designSystem.typography.fontSize,
spacing: designSystem.spacing,
borderRadius: designSystem.borderRadius,
boxShadow: designSystem.shadows,
animation: designSystem.animations
}
},
plugins: []
};
五、多代理适配器:12 种 CLI 的统一接口
Open Design 支持的代理列表:
| 代理 | CLI 命令 | 协议 | 特点 |
|---|---|---|---|
| Claude Code | claude | claude-code | Anthropic 官方 |
| Codex | codex | codex | OpenAI 官方 |
| Devin Terminal | devin | devin-terminal | Cognition AI |
| Cursor Agent | cursor-agent | cursor | IDE 内嵌 |
| Gemini CLI | gemini | gemini-cli | Google 官方 |
| OpenCode | openode | openode | 开源替代 |
| Qwen Code | qwen-code | qwen | 阿里云 |
| GitHub Copilot CLI | gh copilot chat | copilot | GitHub |
| Hermes | hermes | acp | ACP 协议 |
| Kimi CLI | kimi | acp | 月之暗面 |
| Pi | pi | rpc | RPC 协议 |
| Kiro CLI | kiro | acp | AWS |
5.1 适配器抽象
// daemon/src/adapters/base.ts
export interface AgentAdapter {
name: string;
command: string;
protocol: 'claude-code' | 'codex' | 'acp' | 'rpc';
// 启动代理
start(projectDir: string, task: string): Promise<ChildProcess>;
// 发送消息
sendMessage(process: ChildProcess, message: string): Promise<void>;
// 解析输出
parseOutput(data: string): AgentMessage[];
// 获取 artifact
extractArtifact(output: string): string | null;
}
export interface AgentMessage {
type: 'text' | 'tool_use' | 'artifact' | 'error';
content: string;
metadata?: Record<string, any>;
}
5.2 Claude Code 适配器示例
// daemon/src/adapters/claude-code.ts
import { spawn, ChildProcess } from 'child_process';
import { AgentAdapter, AgentMessage } from './base';
export class ClaudeCodeAdapter implements AgentAdapter {
name = 'Claude Code';
command = 'claude';
protocol = 'claude-code' as const;
async start(projectDir: string, task: string): Promise<ChildProcess> {
const proc = spawn(this.command, [
'--print',
'--permission-mode', 'bypassPermissions',
'--max-tokens', '8000',
task
], {
cwd: projectDir,
stdio: ['pipe', 'pipe', 'pipe'],
env: { ...process.env, CLAUDE_CODE_MODE: 'design' }
});
return proc;
}
async sendMessage(proc: ChildProcess, message: string): Promise<void> {
proc.stdin?.write(message + '\n');
}
parseOutput(data: string): AgentMessage[] {
const messages: AgentMessage[] = [];
const lines = data.split('\n');
for (const line of lines) {
if (line.startsWith('[TOOL]')) {
messages.push({
type: 'tool_use',
content: line.replace('[TOOL] ', '')
});
} else if (line.includes('<artifact')) {
messages.push({
type: 'artifact',
content: this.extractArtifact(data) || ''
});
} else if (line.trim()) {
messages.push({
type: 'text',
content: line
});
}
}
return messages;
}
extractArtifact(output: string): string | null {
const match = output.match(/<artifact[^>]*>([\s\S]*?)<\/artifact>/);
return match ? match[1].trim() : null;
}
}
5.3 ACP 协议适配器
ACP (Agent Communication Protocol) 是一种标准化的代理通信协议:
// daemon/src/adapters/acp.ts
import { spawn, ChildProcess } from 'child_process';
import { AgentAdapter, AgentMessage } from './base';
export class ACPAdapter implements AgentAdapter {
name: string;
command: string;
protocol = 'acp' as const;
constructor(name: string, command: string) {
this.name = name;
this.command = command;
}
async start(projectDir: string, task: string): Promise<ChildProcess> {
// ACP 协议通过 stdin/stdout 传递 JSON-RPC 消息
const proc = spawn(this.command, ['--mode', 'acp'], {
cwd: projectDir,
stdio: ['pipe', 'pipe', 'pipe']
});
// 发送初始化请求
const initRequest = {
jsonrpc: '2.0',
method: 'initialize',
params: {
capabilities: { artifacts: true, tools: true }
},
id: 1
};
proc.stdin?.write(JSON.stringify(initRequest) + '\n');
// 发送任务
const taskRequest = {
jsonrpc: '2.0',
method: 'task',
params: { prompt: task },
id: 2
};
proc.stdin?.write(JSON.stringify(taskRequest) + '\n');
return proc;
}
parseOutput(data: string): AgentMessage[] {
try {
const response = JSON.parse(data);
if (response.method === 'artifact') {
return [{
type: 'artifact',
content: response.params.content
}];
}
if (response.method === 'tool_use') {
return [{
type: 'tool_use',
content: response.params
}];
}
return [{
type: 'text',
content: response.result?.content || ''
}];
} catch {
return [];
}
}
}
六、媒体生成:从图片到视频的完整能力链
Open Design 集成了三种媒体生成能力:
6.1 GPT-Image-2(图片生成)
用于海报、头像、信息图、地图插图:
// apps/web/src/lib/media/gpt-image.ts
import OpenAI from 'openai';
export async function generateImage(prompt: string, options?: ImageOptions) {
const openai = new OpenAI({
apiKey: process.env.OPENAI_API_KEY,
baseURL: process.env.OPENAI_BASE_URL // 支持 Azure
});
const response = await openai.images.generate({
model: 'gpt-image-2',
prompt: `
${prompt}
Style: Professional, clean, brand-appropriate
Aspect ratio: ${options?.aspectRatio || '16:9'}
Output format: PNG with transparency
`,
size: options?.size || '1920x1080',
quality: 'hd',
n: 1
});
return response.data[0].url;
}
// 使用示例
const heroImage = await generateImage(
'A sleek SaaS dashboard showing real-time analytics with purple accents on dark background',
{ aspectRatio: '16:9' }
);
6.2 Seedance 2.0(视频生成)
用于 15 秒文本转视频、图转视频:
// apps/web/src/lib/media/seedance.ts
import { ByteDanceSeedance } from '@bytedance/seedance-sdk';
export async function generateVideo(prompt: string, image?: string) {
const client = new ByteDanceSeedance({
apiKey: process.env.BYTEDANCE_API_KEY
});
const params: VideoParams = {
model: 'seedance-2.0',
prompt,
duration: 15, // 秒
fps: 24,
resolution: '1080p'
};
if (image) {
params.image = image; // 图生视频
params.mode = 'image-to-video';
} else {
params.mode = 'text-to-video';
}
const job = await client.createJob(params);
// 轮询等待完成
while (job.status !== 'completed' && job.status !== 'failed') {
await new Promise(r => setTimeout(r, 5000));
job = await client.getJob(job.id);
}
return job.outputUrl;
}
6.3 HyperFrames(HTML 转 MP4)
用于产品展示、动态排版、数据图表:
// apps/web/src/lib/media/hyperframes.ts
export async function htmlToVideo(html: string, options: VideoOptions) {
const response = await fetch('https://api.hyperframes.dev/v1/render', {
method: 'POST',
headers: {
'Authorization': `Bearer ${process.env.HYPERFRAMES_API_KEY}`,
'Content-Type': 'application/json'
},
body: JSON.stringify({
html,
duration: options.duration || 10,
fps: options.fps || 30,
width: options.width || 1920,
height: options.height || 1080,
animations: options.animations || []
})
});
const { jobId } = await response.json();
// 等待渲染完成
while (true) {
const status = await fetch(`https://api.hyperframes.dev/v1/jobs/${jobId}`);
const { state, outputUrl } = await status.json();
if (state === 'completed') return outputUrl;
if (state === 'failed') throw new Error('Render failed');
await new Promise(r => setTimeout(r, 2000));
}
}
// 使用示例:产品展示动画
await htmlToVideo(`
<div class="product-reveal">
<div class="logo animate-fade-in">Product Name</div>
<div class="screenshot animate-slide-up">
<img src="dashboard.png" />
</div>
<div class="cta animate-pulse">
Start Free Trial
</div>
</div>
`, {
duration: 10,
animations: [
{ target: '.logo', animation: 'fadeIn', start: 0, duration: 2 },
{ target: '.screenshot', animation: 'slideUp', start: 2, duration: 3 },
{ target: '.cta', animation: 'pulse', start: 6, duration: 4 }
]
});
七、安全设计:SSRF 防护与沙箱隔离
7.1 SSRF 防护
在 BYOK Proxy 中,Open Design 实现了严格的 SSRF 防护:
// apps/web/src/lib/security/ssrf.ts
import { isPrivate, isLocalhost } from 'ip-utils';
const BLOCKED_HOSTS = [
'localhost',
'127.0.0.1',
'0.0.0.0',
'169.254.169.254', // AWS 元数据
'metadata.google.internal', // GCP 元数据
'10.0.0.0/8',
'172.16.0.0/12',
'192.168.0.0/16'
];
export function isInternalIP(hostname: string): boolean {
// 检查是否是内网 IP
if (isPrivate(hostname)) return true;
// 检查是否是 localhost
if (isLocalhost(hostname)) return true;
// 检查是否在黑名单中
for (const blocked of BLOCKED_HOSTS) {
if (blocked.includes('/')) {
if (isIPInCIDR(hostname, blocked)) return true;
} else if (hostname === blocked) {
return true;
}
}
return false;
}
export async function safeFetch(url: string): Promise<Response> {
const parsed = new URL(url);
// DNS 重绑定攻击防护
const dns = await resolveDNS(parsed.hostname);
for (const ip of dns) {
if (isInternalIP(ip)) {
throw new Error('SSRF attempt blocked: internal IP resolved');
}
}
return fetch(url);
}
7.2 沙箱隔离
预览 iframe 使用严格的沙箱策略:
<iframe
sandbox="allow-scripts allow-same-origin"
// 注意:没有 allow-forms, allow-popups, allow-top-navigation
// 防止表单提交、弹窗、跳转
/>
八、导入能力:从 Claude Design 无缝迁移
Open Design 支持直接导入 Claude Design 的导出文件:
// apps/web/pages/api/import/claude-design.ts
import { NextApiRequest, NextApiResponse } from 'next';
import { parse as parseZip } from 'jszip';
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
const file = req.body; // ZIP 文件的 Buffer
const zip = await parseZip(file);
// Claude Design 导出结构
// - project.json (项目元数据)
// - messages.json (对话历史)
// - artifacts/ (所有 artifact 文件)
const projectMeta = JSON.parse(await zip.file('project.json')?.async('text') || '{}');
const messages = JSON.parse(await zip.file('messages.json')?.async('text') || '[]');
// 转换为 Open Design 的项目结构
const odProject = {
id: generateId(),
name: projectMeta.name,
createdAt: new Date().toISOString(),
designSystem: projectMeta.design_system || 'linear',
messages: messages.map(convertMessage),
artifacts: []
};
// 提取 artifacts
const artifactsFolder = zip.folder('artifacts');
if (artifactsFolder) {
for (const [path, file] of Object.entries(artifactsFolder.files)) {
if (!file.dir) {
const content = await file.async('text');
odProject.artifacts.push({
id: path.replace('.tsx', ''),
content,
createdAt: new Date().toISOString()
});
}
}
}
// 保存到数据库
await saveProject(odProject);
res.json({ success: true, projectId: odProject.id });
}
function convertMessage(msg: any): Message {
// Claude Design 的消息格式转换为 Open Design 格式
return {
role: msg.role,
content: msg.content,
timestamp: msg.timestamp,
artifactId: msg.artifact_id
};
}
九、性能优化:流式渲染与增量更新
9.1 流式 Artifact 渲染
Open Design 支持流式渲染 artifact,用户可以实时看到 AI 正在编写的内容:
// apps/web/src/components/preview/StreamingPreview.tsx
import { useEffect, useState, useRef } from 'react';
export function StreamingPreview({ stream }: { stream: ReadableStream<string> }) {
const [code, setCode] = useState('');
const [artifact, setArtifact] = useState<string | null>(null);
const readerRef = useRef<ReadableStreamDefaultReader<string>>();
useEffect(() => {
const reader = stream.getReader();
readerRef.current = reader;
const process = async () => {
while (true) {
const { done, value } = await reader.read();
if (done) break;
setCode(prev => prev + value);
// 尝试解析 artifact
const parsed = tryParseArtifact(code);
if (parsed) {
setArtifact(parsed);
}
}
};
process();
return () => {
reader.cancel();
};
}, [stream]);
return (
<div className="grid grid-cols-2 h-full">
<div className="border-r overflow-auto p-4">
<pre className="text-sm">{code}</pre>
</div>
<div className="overflow-hidden">
{artifact ? (
<SandboxedPreview artifact={artifact} />
) : (
<div className="flex items-center justify-center h-full text-muted">
Waiting for artifact...
</div>
)}
</div>
</div>
);
}
function tryParseArtifact(code: string): string | null {
// 宽松的 artifact 提取
const startMatch = code.match(/<artifact[^>]*>/);
if (!startMatch) return null;
const startIdx = startMatch.index! + startMatch[0].length;
const endMatch = code.slice(startIdx).match(/<\/artifact>/);
if (!endMatch) return null;
return code.slice(startIdx, startIdx + endMatch.index!);
}
9.2 增量更新
对于大型 artifact,Open Design 只更新变化的部分:
// apps/web/src/lib/diff/patch.ts
import * as diff from 'diff';
export function patchArtifact(oldCode: string, newCode: string): string {
const patches = diff.diffLines(oldCode, newCode);
// 只返回有变化的部分
return patches
.filter(p => p.added)
.map(p => p.value)
.join('');
}
export function applyPatch(baseCode: string, patch: string): string {
// 应用增量补丁
const lines = baseCode.split('\n');
const patchLines = patch.split('\n');
// 找到插入位置(简化版)
// 实际实现需要更复杂的定位逻辑
return baseCode + '\n' + patch;
}
十、实战案例:从零构建一个 SaaS 落地页
让我们用 Open Design 实战演练一次。
10.1 启动项目
# 克隆仓库
git clone https://github.com/nexu-io/open-design.git
cd open-design
# 安装依赖
pnpm install
# 启动开发服务器
pnpm tools-dev
10.2 选择 Skill
在 Web UI 中选择 saas-landing Skill。
10.3 填写问卷
Product Name: DataPulse
Tagline: Real-time Analytics for Modern Teams
Target Audience: Product teams at B2B SaaS companies, 10-500 employees
Key Features: Real-time dashboards, Custom events, Team collaboration, API access
Pricing Tiers: Free/Pro/Enterprise
CTA Text: Start Free Trial
10.4 选择设计系统
选择 linear 设计系统(暗色科技风)。
10.5 AI 输出
代理会自动生成完整的 React 组件:
// 生成的内容示例
import React from 'react';
import { LineChart, BarChart, PieChart } from 'lucide-react';
export default function DataPulseLanding() {
return (
<main className="min-h-screen bg-[#0a0a0b] text-[#f5f5f5]">
{/* Hero Section */}
<section className="relative px-6 py-24 lg:px-8">
<div className="mx-auto max-w-4xl text-center">
<div className="inline-flex items-center gap-2 rounded-full bg-[#212121] px-4 py-2 text-sm text-[#8b8b8b]">
<span className="h-2 w-2 rounded-full bg-[#5e6ad2]" />
Now with AI-powered insights
</div>
<h1 className="mt-6 text-5xl font-bold tracking-tight lg:text-7xl">
Real-time Analytics<br />
<span className="text-[#5e6ad2]">for Modern Teams</span>
</h1>
<p className="mt-6 text-lg text-[#8b8b8b] lg:text-xl">
Ship faster with instant visibility into user behavior.
No more waiting for batch processing.
</p>
<div className="mt-10 flex items-center justify-center gap-4">
<button className="rounded-lg bg-[#5e6ad2] px-6 py-3 font-medium hover:bg-[#5e6ad2]/90">
Start Free Trial
</button>
<button className="rounded-lg border border-[#212121] px-6 py-3 font-medium hover:bg-[#141415]">
Watch Demo
</button>
</div>
</div>
{/* Dashboard Preview */}
<div className="mt-16 overflow-hidden rounded-xl border border-[#212121] bg-[#141415] p-4">
<div className="aspect-[16/9] w-full overflow-hidden rounded-lg bg-[#0a0a0b]">
<img
src="/dashboard-preview.png"
alt="DataPulse Dashboard"
className="h-full w-full object-cover"
/>
</div>
</div>
</section>
{/* Features Section */}
<section className="px-6 py-24 lg:px-8">
<div className="mx-auto max-w-6xl">
<h2 className="text-center text-3xl font-bold">
Everything you need to understand your users
</h2>
<div className="mt-16 grid gap-8 lg:grid-cols-3">
{/* Feature cards */}
</div>
</div>
</section>
{/* Pricing Section */}
<section className="px-6 py-24 lg:px-8">
<div className="mx-auto max-w-5xl">
<div className="grid gap-8 lg:grid-cols-3">
{/* Pricing cards */}
</div>
</div>
</section>
{/* CTA Section */}
<section className="px-6 py-24 lg:px-8">
<div className="mx-auto max-w-4xl rounded-2xl bg-gradient-to-r from-[#5e6ad2]/20 to-[#5e6ad2]/5 p-12 text-center">
<h2 className="text-3xl font-bold">Ready to get started?</h2>
<p className="mt-4 text-[#8b8b8b]">
Join 1,000+ teams already using DataPulse
</p>
<button className="mt-8 rounded-lg bg-[#5e6ad2] px-8 py-4 font-medium">
Start Free Trial
</button>
</div>
</section>
</main>
);
}
10.6 五维自评
{
"dimensions": [
{
"id": "visual_hierarchy",
"score": 9,
"justification": "Clear hero → features → pricing → CTA flow. Good use of section breaks.",
"suggestions": ["Consider adding a navigation bar for longer pages"]
},
{
"id": "brand_consistency",
"score": 10,
"justification": "Perfectly follows Linear design system. Colors, fonts, spacing all match.",
"suggestions": []
},
{
"id": "accessibility",
"score": 8,
"justification": "Good contrast ratios, semantic HTML. Missing some ARIA labels.",
"suggestions": ["Add aria-label to buttons", "Ensure focus states are visible"]
},
{
"id": "responsiveness",
"score": 9,
"justification": "Mobile-first responsive classes. Good breakpoint usage.",
"suggestions": ["Test on 375px viewport for hero text sizing"]
},
{
"id": "conversion_optimization",
"score": 9,
"justification": "Strong CTAs, social proof, clear value proposition.",
"suggestions": ["Add trust badges or testimonials"]
}
],
"overall_score": 9.0,
"summary": "Production-ready landing page with excellent brand alignment and clear conversion path."
}
十一、总结与展望
11.1 Open Design 的核心价值
Open Design 解决了三个关键问题:
- 闭源垄断:Claude Design 闭源,Open Design 开源
- 模型锁定:Claude Design 只支持 Anthropic 模型,Open Design 支持任何 OpenAI 兼容 API
- 代理重复建设:最强的编程代理已经在你的笔记本上,直接复用
11.2 技术亮点
| 特性 | 实现方式 |
|---|---|
| 多代理支持 | PATH 扫描 + 协议适配器 |
| 设计系统 | Tailwind 配置 + 组件样式库 |
| 实时预览 | React 18 + Babel 沙箱 |
| 安全隔离 | SSRF 防护 + iframe sandbox |
| 持久化 | SQLite + 文件系统 |
| 媒体生成 | GPT-Image-2 + Seedance + HyperFrames |
11.3 未来展望
Open Design 仍有几个方向值得期待:
- 更多 Skill:目前 31 个,社区正在贡献更多
- 协作功能:多人实时编辑同一设计
- 版本控制:集成 Git,追踪设计变更
- AI 评估:自动 A/B 测试生成的变体
结语
Open Design 证明了:开源不等于低质量。它的 14.8K Stars、31 种 Skill、72 套设计系统,以及完整的多代理适配架构,使其成为目前最强的 Claude Design 开源替代品。
如果你是一名开发者,这个项目值得你 clone 下来跑一遍——不是为了「尝鲜」,而是为了理解「AI 时代的软件应该怎么设计」。
项目地址:https://github.com/nexu-io/open-design
文档:README.md
协议:Apache 2.0