Turn the .design/ directory (produced by /figma2design) into working pages and components in your project. Adapts to the project's existing tech stack, directory structure, and coding conventions.
Usage
/design2code # generate all pages from .design/
/design2code home # generate only the "home" page
/design2code home,skills # generate specific pages
/design2code --components-only # generate only shared components, no pages
/design2code --tokens-only # generate only design tokens (colors, fonts, etc.)
/design2code --dry-run # show what would be generated, write nothing
/design2code --target web # target a specific app in a monorepo
What This Skill Does
.design/ → your project
├── DESIGN.md src/styles/tokens.css (or tailwind.config)
├── CODE_PATTERNS.md src/components/Sidebar.tsx
├── COMPONENTS.md src/components/InputArea.tsx
├── PAGES.md src/pages/Home.tsx
├── ICONS.md src/pages/Skills.tsx
└── screenshots/ src/lib/icons.ts
+ route wiring
It does NOT:
- Overwrite existing files without asking
- Create a new project from scratch (use
create-react-app/vitefirst) - Install dependencies without confirmation
- Generate backend/API code
Prerequisites
- A
.design/directory in the project root (produced by/figma2design) - An existing frontend project (React/Vue/Svelte + a CSS framework)
- If
.design/is missing, prompt: ".design/ directory not found. Please run/figma2design <figma-url>"
What You Must Do When Invoked
Follow these steps in order. Do not skip steps.
Step 1 — Read all design specs
Read every file in .design/ to build a complete mental model:
# Read in this order (each builds on the previous)
cat .design/DESIGN.md # tokens: colors, typography, spacing, shapes
cat .design/CODE_PATTERNS.md # tech stack, naming conventions, layout patterns
cat .design/COMPONENTS.md # component props, states, interactions
cat .design/PAGES.md # page layout, data flow, states
cat .design/ICONS.md # icon names, sources, sizes
From these files, extract and internalize:
- Token map: all color hex → semantic name mappings
- Component inventory: every component with its props interface
- Page inventory: every page with its layout diagram and state table
- Code style: naming conventions, file structure, import patterns
Step 2 — Detect project tech stack
Scan the project to understand what already exists:
# Check for framework indicators
cat package.json # React/Vue/Svelte/Next.js/Nuxt
cat tsconfig.json 2>/dev/null # TypeScript config
cat tailwind.config.* 2>/dev/null # Tailwind CSS
cat vite.config.* 2>/dev/null # Vite
cat next.config.* 2>/dev/null # Next.js
ls src/ 2>/dev/null # Source structure
ls src/components/ 2>/dev/null # Existing components
ls src/pages/ 2>/dev/null # Existing pages
ls src/styles/ 2>/dev/null # Existing styles
Build a profile:
Project profile:
Framework: React 18 / Next.js 14 / Vue 3 / SvelteKit
Language: TypeScript / JavaScript
Styling: Tailwind CSS / CSS Modules / Styled Components / Emotion
State: Zustand / Redux / Pinia / Context
Router: React Router / Next.js App Router / Vue Router
Icons: Lucide / Heroicons / Custom SVG
Directory: src/components/ + src/pages/ / src/app/ / src/views/
Naming: PascalCase components / kebab-case files / camelCase hooks
If the project has no frontend:
⚠️ 未检测到前端项目。建议:
1. npm create vite@latest frontend -- --template react-ts
2. cd frontend && npm install tailwindcss @tailwindcss/vite lucide-react
3. 再次运行 /design2code
Step 3 — Resolve conflicts and plan generation
Compare what .design/ specifies vs what the project already has:
Already exists → skip or update:
- If a component already exists with the same name, show the user both versions and ask
- If the styling approach differs (e.g., project uses CSS Modules but DESIGN.md says Tailwind), adapt to the project's existing approach
Missing → generate:
- New components that don't exist yet
- New pages that don't exist yet
- Design tokens that aren't configured yet
Present the plan to the user:
📋 生成计划:
新建:
src/components/Sidebar.tsx
src/components/InputArea.tsx
src/components/SkillCard.tsx
src/components/ToggleSwitch.tsx
src/pages/Home.tsx
src/pages/Skills.tsx
更新:
tailwind.config.ts (添加自定义颜色)
跳过 (已存在):
src/components/Button.tsx
目标: web/src/ (monorepo app)
继续生成? [Y/n]
If --dry-run, stop here.
Step 4 — Generate design tokens
Map DESIGN.md tokens to the project's styling system.
Tailwind CSS (inline arbitrary values)
If the project uses Tailwind, no config changes needed — use inline values:
// Colors from DESIGN.md used directly
<div className="bg-[#FAFAFA] text-[#181818]" />
CSS Custom Properties
If the project uses CSS variables, generate a tokens file:
/* src/styles/tokens.css — generated from .design/DESIGN.md */
:root {
/* Backgrounds */
--color-bg-page: #FAFAFA;
--color-bg-sidebar: #F2F2F2;
--color-bg-main: #FCFCFC;
/* Text */
--color-text-primary: #181818;
--color-text-secondary: #797979;
--color-text-tertiary: #808080;
--color-text-muted: #4A5970;
/* Borders */
--color-border: #E6E6E6;
--color-border-input: #F1F1F1;
/* Semantic */
--color-brand: #0A6CFF;
--color-success: #04C29A;
--color-error: #DB3543;
--color-info: #1792EA;
/* Typography */
--font-sans: 'PingFang SC', -apple-system, BlinkMacSystemFont, sans-serif;
--font-brand: 'Montserrat', sans-serif;
/* Radius */
--radius-xs: 3px;
--radius-sm: 6px;
--radius-md: 8px;
--radius-lg: 16px;
--radius-pill: 91px;
/* Shadows */
--shadow-card: 0px 2px 8.1px rgba(0, 0, 0, 0.03);
--shadow-panel: -3px 0px 10.7px rgba(39, 70, 141, 0.03);
}
Tailwind Config Extension (optional)
If the user prefers semantic token names in Tailwind:
// tailwind.config.ts
export default {
theme: {
extend: {
colors: {
'bg-page': '#FAFAFA',
'bg-sidebar': '#F2F2F2',
'text-primary': '#181818',
'text-secondary': '#797979',
'brand': '#0A6CFF',
'success': '#04C29A',
'error': '#DB3543',
},
fontFamily: {
sans: ['PingFang SC', '-apple-system', 'BlinkMacSystemFont', 'sans-serif'],
brand: ['Montserrat', 'sans-serif'],
},
borderRadius: {
'xs': '3px',
'sm': '6px',
'md': '8px',
'lg': '16px',
},
boxShadow: {
'card': '0px 2px 8.1px rgba(0, 0, 0, 0.03)',
'panel': '-3px 0px 10.7px rgba(39, 70, 141, 0.03)',
},
},
},
}
Default: use inline Tailwind values (simpler, no config needed). Only extend config if the user asks or the project already uses semantic tokens.
Step 5 — Generate base components
Generate components from COMPONENTS.md, one file per component.
For each component:
- Read its spec from COMPONENTS.md (props, states, interactions, dimensions)
- Look up design tokens from DESIGN.md (colors, spacing, radius, shadows)
- Look up icons from ICONS.md (which Lucide icon, what size)
- Follow CODE_PATTERNS.md conventions (naming, file structure, import style)
Component template:
// src/components/<ComponentName>.tsx
// Generated from .design/COMPONENTS.md — <ComponentName>
import { useState } from 'react'
// import icons from ICONS.md
import { Sparkles, ChevronDown } from 'lucide-react'
interface <ComponentName>Props {
// from COMPONENTS.md Props section
}
/**
* <one-line description from COMPONENTS.md>
*
* States:
* - default: <description>
* - active: <description>
* - disabled: <description>
*/
export function <ComponentName>({ ...props }: <ComponentName>Props) {
// state from COMPONENTS.md States table
// handlers from COMPONENTS.md Interactions table
return (
// JSX from DESIGN.md visual spec + CODE_PATTERNS.md layout patterns
// Use exact hex values: bg-[#FAFAFA], text-[#181818]
// Use exact dimensions: w-[273px] h-[114px]
// Use exact spacing: p-[14px] gap-[6px]
)
}
Generation order (dependencies first):
- Atomic:
ToggleSwitch,FileBadge,SegmentedControl - Simple composite:
SkillCard,SidebarItem,TabBar,TaskStepRow - Complex composite:
InputArea,ProjectBar,Sidebar,DeliverablesPanel
After each component, verify:
- All hex colors match DESIGN.md tokens
- All dimensions match DESIGN.md key dimensions table
- All interactions from COMPONENTS.md are implemented
- TypeScript types are correct
- No hardcoded strings (use props)
Step 6 — Generate pages
Generate pages from PAGES.md, using the components from Step 5.
For each page:
- Read its spec from PAGES.md (layout diagram, component list, data, interactions, states)
- Import the components generated in Step 5
- Wire up state management per CODE_PATTERNS.md
- Implement all interactions from PAGES.md
Page template:
// src/pages/<PageName>.tsx
// Generated from .design/PAGES.md — Page: <pageName>
import { useState } from 'react'
import { Sidebar } from '../components/Sidebar'
import { InputArea } from '../components/InputArea'
// ... other components from PAGES.md component list
/**
* <Function description from PAGES.md>
*
* Layout:
* <ASCII diagram from PAGES.md>
*
* States: <state list from PAGES.md>
*/
export default function <PageName>() {
// State from PAGES.md Data section
const [inputText, setInputText] = useState('')
// ...
// Handlers from PAGES.md Interactions table
const handleSubmit = () => {
// POST /api/tasks → navigate to /task/:id
}
return (
// Layout from PAGES.md Layout section
// Use CODE_PATTERNS.md layout patterns (app shell, centered, three-panel)
<div className="flex h-screen bg-[#FAFAFA]">
<Sidebar currentRoute="/<route>" />
<main className="flex-1 flex flex-col items-center justify-center gap-6">
{/* Components from PAGES.md component list */}
</main>
</div>
)
}
Generation order:
- Pages with fewest dependencies first (Home, Skills)
- Complex pages last (TaskExecution)
Step 7 — Wire routing
Add routes for all generated pages. Adapt to the project's router:
React Router
// Update src/App.tsx or src/router.tsx
import Home from './pages/Home'
import Skills from './pages/Skills'
import Automation from './pages/Automation'
import TaskExecution from './pages/TaskExecution'
// Add to existing route config
const routes = [
{ path: '/', element: <Home /> },
{ path: '/skills', element: <Skills /> },
{ path: '/automation', element: <Automation /> },
{ path: '/task/:id', element: <TaskExecution /> },
]
Next.js App Router
src/app/page.tsx → Home
src/app/skills/page.tsx → Skills
src/app/automation/page.tsx → Automation
src/app/task/[id]/page.tsx → TaskExecution
Vue Router
const routes = [
{ path: '/', component: () => import('./pages/Home.vue') },
{ path: '/skills', component: () => import('./pages/Skills.vue') },
// ...
]
If a router file already exists, add routes to it — do NOT overwrite.
Step 8 — Verify and fix
Run the project's existing checks:
# TypeScript check
npx tsc --noEmit 2>&1 | head -30
# Lint
npx eslint src/pages/ src/components/ --max-warnings 0 2>&1 | head -20
# Dev server (if available)
npm run dev &
# Check the URL printed by the dev server
If errors found:
- Read each error message
- Fix the specific issue in the specific file
- Re-run the check
- Repeat until clean
Visual verification (if dev server is running):
- Compare each generated page against its screenshot in
.design/screenshots/ - Note any visual discrepancies and fix:
- Wrong colors → check hex values against DESIGN.md
- Wrong spacing → check gap/padding against DESIGN.md key dimensions
- Wrong layout → check PAGES.md ASCII diagram
- Missing icons → check ICONS.md
Step 9 — Report results
✅ 生成完成!
新建文件 (N):
src/components/Sidebar.tsx
src/components/InputArea.tsx
src/components/SkillCard.tsx
src/components/ToggleSwitch.tsx
src/components/FileBadge.tsx
src/components/TabBar.tsx
src/pages/Home.tsx
src/pages/Skills.tsx
src/pages/Automation.tsx
src/pages/TaskExecution.tsx
更新文件 (N):
src/App.tsx (added routes)
设计 token:
15 colors, 10 typography styles, 5 radius, 8 spacing
→ inline Tailwind values (no config change)
Dev server: http://localhost:5173
/ → Home
/skills → Skills
/automation → Automation
/task/:id → TaskExecution
⚠️ 待完善:
- API 调用需要连接后端 (当前用 mock data)
- 拖拽文件交互需要 react-dropzone
- 动画 transition 需要微调
Handling Edge Cases
No .design/ directory
未找到 .design/ 目录。请先运行:
/figma2design <figma-url>
.design/ is incomplete (e.g., only DESIGN.md, no PAGES.md)
Generate what you can from available files. Note what's missing:
⚠️ .design/ 缺少 PAGES.md, 将基于 DESIGN.md 和截图推断页面结构。
建议补充: /figma2design <url> --update
Target app in a monorepo
If the project has multiple frontend apps (apps/web, apps/desktop, etc.):
- List all detected frontend apps
- Ask the user which one to target (or use
--target <name>) - Generate into that app's
src/directory
Existing components conflict
If a generated component name matches an existing file:
⚠️ src/components/Button.tsx 已存在。
[s] 跳过 — 保留现有文件
[o] 覆盖 — 用设计系统版本替换
[m] 合并 — 将设计系统 props 添加到现有组件
[r] 重命名 — 生成为 Button.design.tsx
Non-React project (Vue, Svelte, etc.)
Adapt the output:
- Vue:
.vuefiles with<script setup lang="ts">,<template>,<style scoped> - Svelte:
.sveltefiles with<script lang="ts">, markup,<style> - Same design tokens, same layout logic, different syntax
Project uses a component library (Ant Design, MUI, etc.)
Prefer the library's components where possible:
- Map
button-primary→<Button variant="contained" /> - Map
tab-bar→<Tabs>from the library - Only generate custom components for things the library doesn't cover
- Override library theme with DESIGN.md tokens
Key Principles
-
Match the project, not the spec — if the project uses 4-space indent, use 4-space. If it uses barrel exports, use barrel exports. The design spec defines WHAT to build; the project defines HOW to build it.
-
Exact values from DESIGN.md — never approximate colors, spacing, or dimensions.
#FAFAFAis not#F5F5F5.w-[273px]is notw-[272px]. Every pixel matters. -
ASCII layout diagrams are gospel — the PAGES.md layout diagram is the single best guide for page structure. Follow it exactly.
-
Components before pages — always generate leaf components first, then compose them into pages. This ensures every page only uses components that already exist.
-
Screenshots are the final judge — after generating, compare against
.design/screenshots/. If it doesn't look right, fix it. The spec might be ambiguous; the screenshot never is. -
Don't generate mock data as real data — use proper TypeScript interfaces and leave clear
// TODO: connect APIcomments where data should come from a backend. -
One component per file — never put multiple components in one file, even if they're small. The project's future self will thank you.