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. 01Pencilノード構造の確認
  2. 02コンポーネントインスタンスと変数の解決
  3. 03デザイントークンのTailwindへの対応付け
  4. 04Reactコンポーネントの生成
  5. 05スクリーンショット比較による検証

活用シーン

  1. 01PencilレイアウトからReactページを作成
  2. 02デザイン変数をTailwind設定に変換
  3. 03再利用可能なUIコンポーネントの構築
  4. 04生成コードをデザインと照合

MCP 対応

Pencilファイルの確認とデザイン変数の取得に、`mcp__pencil__batch_get` と `mcp__pencil__get_variables` を使う方法を示します。

インストール

コマンドをコピーしてターミナルで実行します。

$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の使用
  • ユーティリティクラスを優先します
  • 繰り返し使うパターンはコンポーネントとして抽出します
  • 複雑な値には任意の値を使用します(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 - 一般的なコンポーネントのテンプレート

コメント