SuperAPI AI Directory

Design to Code

Design & creation

View repository

Updated 10-15 22:11

About this skill

Design to Code

Provides guidelines for converting designs from Pencil .pen files into React + Tailwind CSS code.

Conversion Workflow

1. Design Analysis

Identify the structure of the target node:

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

resolveInstances: trueto expand and inspect component instances, and resolveVariables: trueto check variable values as actual values.

2. Variable Extraction

Convert design tokens into Tailwind configuration:

mcp__pencil__get_variables(filePath: "design.pen")

3. Code Generation

Convert to appropriate React components according to node type.

4. Screenshot Comparison

Visually verify the generated code.

Node to Component Mapping

Pencil Node React/HTML Tailwind Classes
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> or <Button> Per component

Property to Tailwind Mapping

Layout

Pencil Property Tailwind
layout: "horizontal" flex flex-row
layout: "vertical" flex flex-col
layout: "grid" grid
gap: 16 gap-4
padding: 16 p-4
padding: [16, 24, 16, 24] py-4 px-6
alignItems: "center" items-center
justifyContent: "center" justify-center
justifyContent: "space-between" justify-between

Sizing

Pencil Property Tailwind
width: "fill_container" w-full
height: "fill_container" h-full
width: "hug_contents" w-fit
width: 320 w-80 or w-[320px]

Typography

Pencil Property Tailwind
fontSize: 16 text-base
fontSize: 24 text-2xl
fontWeight: "bold" font-bold
fontWeight: "semibold" font-semibold
textAlign: "center" text-center
textColor: "#3B82F6" text-blue-500

Colors

Pencil Color Tailwind
#3B82F6 blue-500
#EF4444 red-500
#22C55E green-500
#F8FAFC slate-50
#0F172A slate-900

Border Radius

Pencil Property Tailwind
cornerRadius: 4 rounded-sm
cornerRadius: 8 rounded-lg
cornerRadius: 12 rounded-xl
cornerRadius: 9999 rounded-full

Effects

Pencil Property Tailwind
opacity: 0.5 opacity-50
overflow: "hidden" overflow-hidden
Shadow (small) shadow-sm
Shadow (medium) shadow-md

Code Generation Patterns

Basic Component

Pencil node:

{
  "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>
  )
}

Interactive Component

Button component:

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>
  )
}

Layout Component

Page layout:

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>
  )
}

Variable to Tailwind Config

Convert Pencil variables to tailwind.config.js:

Input (Pencil Variables)

{
  "colors": {
    "primary": { "500": "#3B82F6", "600": "#2563EB" },
    "neutral": { "50": "#F8FAFC", "900": "#0F172A" }
  },
  "spacing": { "4": 16, "6": 24, "8": 32 },
  "radii": { "md": 8, "lg": 12 }
}

Output (Tailwind Config)

// 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',
      },
    },
  },
}

Best Practices

Component Naming

  • Use meaningful names (Card, Button, Header)
  • Use PascalCase
  • File names match component names

Props Design

  • Distinguish required props from optional props
  • Provide reasonable default values
  • Define TypeScript interfaces

Tailwind Usage

  • Prefer utility classes
  • Extract repeated patterns into components
  • Use arbitrary values for complex values w-[320px]
  • @applyminimize

Accessibility

  • Use semantic HTML elements
  • Add ARIA attributes appropriately
  • Support keyboard navigation
  • Check color contrast

Output Format

Single TSX file format:

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

interface ComponentNameProps {
  // props 정의
}

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

  return (
    // JSX
  )
}

Additional Resources

Reference Files

  • references/tailwind-mapping.md - Full Pencil-Tailwind mapping table
  • references/component-templates.md - Common component templates