mcpField
D
Design to Code

Design to Code

github.com/gyejoon设计与 UI241 次安装39 周前更新
代码仓库

关于 Design to Code

Design to Code 是一项指导将 Pencil .pen 设计转换为 React 和 Tailwind CSS 代码的技能,涵盖设计检查、设计令牌映射、组件生成和截图视觉比对。

主要功能

  1. 01检查 Pencil 节点结构
  2. 02解析组件实例与变量
  3. 03将设计令牌映射到 Tailwind
  4. 04生成 React 组件
  5. 05通过截图比对验证

适用场景

  1. 01将 Pencil 布局转为 React 页面
  2. 02把设计变量转换为 Tailwind 配置
  3. 03构建可复用 UI 组件
  4. 04对照设计检查生成代码

MCP 相关

该技能展示使用 `mcp__pencil__batch_get` 和 `mcp__pencil__get_variables` 检查 Pencil 文件并获取设计变量。

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/gyejoon/pencil-plugin --skill design-to-code

安装后在 Claude Code 中输入/design-to-code确认已加载。

附带文件references/tailwind-mapping.mdreferences/component-templates.md

详细介绍

设计转代码

提供将 Pencil .pen 文件中的设计转换为 React + Tailwind CSS 代码的指南。

转换工作流

1. 分析设计

了解目标节点的结构:

mcp__pencil__batch_get(
  filePath: "design.pen",
  nodeIds: ["targetNodeId"],
  readDepth: 5,
  resolveInstances: true,
  resolveVariables: true
)

使用 resolveInstances: true 展开组件实例进行检查,并使用 resolveVariables: true 将变量值解析为实际值。

2. 提取变量

将设计令牌转换为 Tailwind 配置:

mcp__pencil__get_variables(filePath: "design.pen")
3. 生成代码

根据节点类型将其转换为合适的 React 组件。

4. 对比截图

通过视觉方式验证生成的代码。

节点到组件的映射

Pencil 节点React/HTMLTailwind 类
frame(layout: vertical)<div>flex flex-col
frame(layout: horizontal)<div>flex flex-row
frame(layout: grid)<div>grid grid-cols-N
text<p>、<span>、<h1-6>text-*、font-*
rectangle<div>rounded-*、bg-*
ref(Button)<button> 或 <Button>按组件而定

属性到 Tailwind 的映射

布局
Pencil 属性Tailwind
layout: "horizontal"flex flex-row
layout: "vertical"flex flex-col
layout: "grid"grid
gap: 16gap-4
padding: 16p-4
padding: [16, 24, 16, 24]py-4 px-6
alignItems: "center"items-center
justifyContent: "center"justify-center
justifyContent: "space-between"justify-between
尺寸
Pencil 属性Tailwind
width: "fill_container"w-full
height: "fill_container"h-full
width: "hug_contents"w-fit
width: 320w-80 或 w-[320px]
排版
Pencil 属性Tailwind
fontSize: 16text-base
fontSize: 24text-2xl
fontWeight: "bold"font-bold
fontWeight: "semibold"font-semibold
textAlign: "center"text-center
textColor: "#3B82F6"text-blue-500
颜色
Pencil 颜色Tailwind
#3B82F6blue-500
#EF4444red-500
#22C55Egreen-500
#F8FAFCslate-50
#0F172Aslate-900
边框圆角
Pencil 属性Tailwind
cornerRadius: 4rounded-sm
cornerRadius: 8rounded-lg
cornerRadius: 12rounded-xl
cornerRadius: 9999rounded-full
效果
Pencil 属性Tailwind
opacity: 0.5opacity-50
overflow: "hidden"overflow-hidden
阴影(小)shadow-sm
阴影(中)shadow-md

代码生成模式

基础组件

Pencil 节点:

{
  "type": "frame",
  "layout": "vertical",
  "padding": 24,
  "gap": 16,
  "fill": "#FFFFFF",
  "cornerRadius": 12,
  "children": [
    { "type": "text", "content": "Title", "fontSize": 24, "fontWeight": "bold" },
    { "type": "text", "content": "Description", "textColor": "#64748B" }
  ]
}

React + Tailwind:

function Card() {
  return (
    <div className="flex flex-col p-6 gap-4 bg-white rounded-xl">
      <h2 className="text-2xl font-bold">Title</h2>
      <p className="text-slate-500">Description</p>
    </div>
  )
}
交互组件

按钮组件:

interface ButtonProps {
  children: React.ReactNode
  variant?: 'primary' | 'secondary'
  onClick?: () => void
}

function Button({ children, variant = 'primary', onClick }: ButtonProps) {
  const baseClasses = "flex items-center justify-center px-6 py-3 gap-2 rounded-lg font-medium transition-colors"
  const variantClasses = {
    primary: "bg-blue-500 text-white hover:bg-blue-600",
    secondary: "bg-transparent border border-blue-500 text-blue-500 hover:bg-blue-50"
  }

  return (
    <button
      className={`${baseClasses} ${variantClasses[variant]}`}
      onClick={onClick}
    >
      {children}
    </button>
  )
}
布局组件

页面布局:

function PageLayout({ children }: { children: React.ReactNode }) {
  return (
    <div className="flex min-h-screen">
      {/* Sidebar */}
      <aside className="flex flex-col w-64 p-6 gap-4 bg-slate-50 border-r border-slate-200">
        <h1 className="text-xl font-bold">Logo</h1>
        <nav className="flex flex-col gap-2">
          <a href="#" className="px-4 py-2 rounded-lg hover:bg-slate-100">Dashboard</a>
          <a href="#" className="px-4 py-2 rounded-lg hover:bg-slate-100">Settings</a>
        </nav>
      </aside>

      {/* Main Content */}
      <main className="flex-1 p-8">
        {children}
      </main>
    </div>
  )
}

将变量转换为 Tailwind 配置

将 Pencil 变量转换为 tailwind.config.js:

输入(Pencil 变量)
{
  "colors": {
    "primary": { "500": "#3B82F6", "600": "#2563EB" },
    "neutral": { "50": "#F8FAFC", "900": "#0F172A" }
  },
  "spacing": { "4": 16, "6": 24, "8": 32 },
  "radii": { "md": 8, "lg": 12 }
}
输出(Tailwind 配置)
// tailwind.config.js
module.exports = {
  theme: {
    extend: {
      colors: {
        primary: {
          500: '#3B82F6',
          600: '#2563EB',
        },
        neutral: {
          50: '#F8FAFC',
          900: '#0F172A',
        },
      },
      spacing: {
        4: '16px',
        6: '24px',
        8: '32px',
      },
      borderRadius: {
        md: '8px',
        lg: '12px',
      },
    },
  },
}

最佳实践

组件命名
  • 使用有意义的名称(Card、Button、Header)
  • 使用 PascalCase
  • 文件名与组件名保持一致
Props 设计
  • 区分必需 props 和可选 props
  • 提供合理的默认值
  • 定义 TypeScript 接口
Tailwind 用法
  • 优先使用工具类
  • 将重复模式提取为组件
  • 复杂值使用 arbitrary values w-[320px]
  • 尽量少用 @apply
无障碍访问
  • 使用语义化 HTML 元素
  • 适当添加 ARIA 属性
  • 支持键盘导航
  • 检查颜色对比度

输出格式

单个 TSX 文件格式:

// ComponentName.tsx
import { useState } from 'react'

interface ComponentNameProps {
  // props 정의
}

export function ComponentName({ ...props }: ComponentNameProps) {
  // 상태 및 로직

  return (
    // JSX
  )
}

其他资源

参考文件
  • references/tailwind-mapping.md - 完整的 Pencil-Tailwind 映射表
  • references/component-templates.md - 常用组件模板

评论

支持 Markdown