SuperAPI AI Directory

design system patterns

Design & creation

View repository

Updated 10-15 22:11

About this skill

Design System Patterns

Provides patterns and best practices for building and managing a design system in Pencil.

Core Concepts

Design Tokens

Design tokens are the basic units of a design system, defined as variables to maintain consistency.

Token Type Example Purpose
Colors primary, secondary, neutral Brand colors, UI colors
Typography heading, body, caption Font size, weight, line height
Spacing xs, sm, md, lg, xl Padding, spacing
Radii sm, md, lg, full Corner radius
Shadows sm, md, lg Shadow effects

Component Hierarchy

Primitives (기본 요소)
  └── Atoms (원자: Button, Input, Badge)
       └── Molecules (분자: SearchBar, Card, MenuItem)
            └── Organisms (유기체: Header, Sidebar, Form)
                 └── Templates (템플릿: PageLayout, DashboardLayout)

Variables Management

Query with get_variables

mcp__pencil__get_variables(filePath: string)

Returns all currently defined variables and themes.

Set with set_variables

mcp__pencil__set_variables(
  filePath: string,
  variables: object,
  replace?: boolean
)

Variable Structure Example

{
  "colors": {
    "primary": {
      "50": "#EFF6FF",
      "100": "#DBEAFE",
      "500": "#3B82F6",
      "600": "#2563EB",
      "700": "#1D4ED8"
    },
    "neutral": {
      "50": "#F8FAFC",
      "100": "#F1F5F9",
      "500": "#64748B",
      "900": "#0F172A"
    }
  },
  "typography": {
    "fontFamily": "Inter, sans-serif",
    "fontSize": {
      "xs": 12,
      "sm": 14,
      "base": 16,
      "lg": 18,
      "xl": 20,
      "2xl": 24,
      "3xl": 30
    },
    "fontWeight": {
      "normal": 400,
      "medium": 500,
      "semibold": 600,
      "bold": 700
    }
  },
  "spacing": {
    "0": 0,
    "1": 4,
    "2": 8,
    "3": 12,
    "4": 16,
    "5": 20,
    "6": 24,
    "8": 32,
    "10": 40,
    "12": 48
  },
  "radii": {
    "none": 0,
    "sm": 4,
    "md": 8,
    "lg": 12,
    "xl": 16,
    "full": 9999
  }
}

Variable Reference

Variable reference in node properties:

button=I("parentId", {
  type: "frame",
  fill: "var(colors/primary/500)",
  padding: "var(spacing/4)",
  cornerRadius: "var(radii/md)"
})
label=I(button, {
  type: "text",
  content: "Button",
  fontSize: "var(typography/fontSize/base)",
  fontWeight: "var(typography/fontWeight/medium)",
  textColor: "#FFFFFF"
})

Creating Reusable Components

Component Definition

reusable: true Register a component with the property:

// Button 컴포넌트 정의
buttonComp=I(document, {
  type: "frame",
  name: "Button",
  reusable: true,
  layout: "horizontal",
  padding: [12, 24, 12, 24],
  alignItems: "center",
  justifyContent: "center",
  gap: 8,
  fill: "var(colors/primary/500)",
  cornerRadius: "var(radii/md)"
})
btnLabel=I(buttonComp, {
  type: "text",
  name: "label",
  content: "Button",
  textColor: "#FFFFFF",
  fontWeight: "var(typography/fontWeight/medium)"
})

Using Component Instances

// 컴포넌트 인스턴스 생성
btn1=I("formId", { type: "ref", ref: "buttonCompId" })

// 인스턴스 내부 수정
U(btn1+"/label", { content: "Submit" })

Component Variants

Define state-specific variations as separate components:

// Primary Button
primaryBtn=I(document, {
  type: "frame",
  name: "Button/Primary",
  reusable: true,
  fill: "var(colors/primary/500)"
  // ... rest
})

// Secondary Button
secondaryBtn=I(document, {
  type: "frame",
  name: "Button/Secondary",
  reusable: true,
  fill: "transparent",
  stroke: "var(colors/primary/500)",
  strokeWidth: 1
  // ... rest
})

// Ghost Button
ghostBtn=I(document, {
  type: "frame",
  name: "Button/Ghost",
  reusable: true,
  fill: "transparent"
  // ... rest
})

Common Component Patterns

Button

button=I(document, {
  type: "frame",
  name: "Button",
  reusable: true,
  layout: "horizontal",
  padding: [12, 24, 12, 24],
  alignItems: "center",
  justifyContent: "center",
  gap: 8,
  fill: "var(colors/primary/500)",
  cornerRadius: "var(radii/md)"
})
icon=I(button, {
  type: "frame",
  name: "iconSlot",
  width: 20,
  height: 20,
  placeholder: true
})
label=I(button, {
  type: "text",
  name: "label",
  content: "Button",
  fontSize: "var(typography/fontSize/base)",
  fontWeight: "var(typography/fontWeight/medium)",
  textColor: "#FFFFFF"
})

Input Field

inputField=I(document, {
  type: "frame",
  name: "InputField",
  reusable: true,
  layout: "vertical",
  gap: 8,
  width: "fill_container"
})
label=I(inputField, {
  type: "text",
  name: "label",
  content: "Label",
  fontSize: "var(typography/fontSize/sm)",
  fontWeight: "var(typography/fontWeight/medium)"
})
input=I(inputField, {
  type: "frame",
  name: "input",
  layout: "horizontal",
  width: "fill_container",
  height: 44,
  padding: [0, 16, 0, 16],
  alignItems: "center",
  fill: "#FFFFFF",
  stroke: "var(colors/neutral/200)",
  strokeWidth: 1,
  cornerRadius: "var(radii/md)"
})
placeholder=I(input, {
  type: "text",
  name: "placeholder",
  content: "Enter value...",
  textColor: "var(colors/neutral/400)"
})
helper=I(inputField, {
  type: "text",
  name: "helperText",
  content: "",
  fontSize: "var(typography/fontSize/xs)",
  textColor: "var(colors/neutral/500)"
})

Card

card=I(document, {
  type: "frame",
  name: "Card",
  reusable: true,
  layout: "vertical",
  width: 320,
  fill: "#FFFFFF",
  cornerRadius: "var(radii/lg)",
  clipContent: true
})
media=I(card, {
  type: "frame",
  name: "mediaSlot",
  width: "fill_container",
  height: 180,
  placeholder: true
})
content=I(card, {
  type: "frame",
  name: "content",
  layout: "vertical",
  padding: 24,
  gap: 12
})
title=I(content, {
  type: "text",
  name: "title",
  content: "Card Title",
  fontSize: "var(typography/fontSize/lg)",
  fontWeight: "var(typography/fontWeight/semibold)"
})
description=I(content, {
  type: "text",
  name: "description",
  content: "Card description...",
  textColor: "var(colors/neutral/600)"
})
actions=I(card, {
  type: "frame",
  name: "actionsSlot",
  layout: "horizontal",
  padding: [0, 24, 24, 24],
  gap: 12,
  placeholder: true
})

Theming

Defining Theme Axes

Light/dark mode support:

{
  "themeAxes": {
    "mode": ["light", "dark"]
  },
  "colors": {
    "background": {
      "mode:light": "#FFFFFF",
      "mode:dark": "#0F172A"
    },
    "text": {
      "primary": {
        "mode:light": "#0F172A",
        "mode:dark": "#F8FAFC"
      },
      "secondary": {
        "mode:light": "#64748B",
        "mode:dark": "#94A3B8"
      }
    }
  }
}

Applying Themes

// 변수 참조 시 현재 테마 값 자동 적용
container=I("parentId", {
  type: "frame",
  fill: "var(colors/background)"
})
title=I(container, {
  type: "text",
  content: "Title",
  textColor: "var(colors/text/primary)"
})

Best Practices

Naming Conventions

  • Components: PascalCase (Button, InputField, Card)
  • Variants: Slash-separated (Button/Primary, Button/Secondary)
  • Internal nodes: camelCase (label, iconSlot, contentArea)
  • Variables: lowercase/slash (colors/primary/500, spacing/4)

Component Organization

  1. Primitives first: Define from basic elements
  2. Compose up: Compose large components from small components
  3. Single responsibility: Handle only one role
  4. Prop slots: Provide customization points with placeholders

Variable Usage

  1. Consistent tokens: Reference variables instead of hardcoding
  2. Semantic names: Purpose-based names (primary, danger, not blue, red)
  3. Scale systems: Consistent scale (4px unit spacing)

Additional Resources

Reference Files

  • references/token-scales.md - Define standard token scale
  • references/component-catalog.md - Common component catalog