Back to skills
extension
Category: OtherNo API key required

Pencil Skill

Create and edit Pencil (.pen) design files programmatically. Generate UI designs as JSON-based .pen files with themes, variables, components, and layouts. In...

personAuthor: de-novohubclawhub

pencil-skill

1) Overview

Pencil is a design tool that uses the JSON-based .pen format. Because .pen is Git-friendly, it is ideal for agents to create and modify directly. The key is not generic JSON syntax, but Pencil-specific rules (ref, slot, textGrowth, variable binding).

2) Core Document Structure

{
  "version": "2.8",
  "themes": {
    "mode": [
      "light",
      "dark"
    ]
  },
  "variables": {
    "color.surface": {
      "type": "color",
      "value": [
        {
          "theme": {
            "mode": "light"
          },
          "value": "#FFFFFF"
        },
        {
          "theme": {
            "mode": "dark"
          },
          "value": "#111827"
        }
      ]
    }
  },
  "children": []
}
  • version and children are required
  • themes and variables are optional, but practically essential for a design system

3) List of Object Types

  • rectangle: basic rectangle
  • ellipse: circle/arc
  • line: line
  • polygon: polygon
  • path: path geometry
  • text: text
  • frame: layout container + can declare slots
  • group: group container
  • note: annotation
  • prompt: prompt memo
  • context: context memo
  • icon_font: icon-font-based vector icon
  • ref: reusable component instance

4) Layout (Summary)

Remember only the core properties:

  • layout: none | vertical | horizontal
  • gap, padding
  • justifyContent: start | center | end | space_between | space_around
  • alignItems: start | center | end

Gotcha:

  • Child x, y values are effectively ignored inside flex (vertical/horizontal) containers

Practical frame properties

| Property | Type | Description | |------|------|------| | clip | boolean | Clips content outside the frame bounds when true. Default is false |

General entity properties (all node types)

| Property | Type | Description | |------|------|------| | enabled | boolean | Hides the node when false (applies to all entities, not frame-specific) |

[
  {
    "type": "frame",
    "id": "modal-overlay",
    "clip": true,
    "layout": "vertical"
  },
  {
    "type": "frame",
    "id": "hidden-panel",
    "enabled": false,
    "layout": "vertical"
  }
]

5) SizingBehavior

  • fit_content
  • fill_container
  • fit_content(${number})

width and height can use numbers, variables, or the SizingBehavior values above.

6) Graphics Essentials

  • fill: color / gradient / image / mesh_gradient
  • stroke: align, thickness, join, cap, dashPattern, fill
  • effect: blur, background_blur, shadow

Color values are recommended in hex format (#RGB, #RRGGBB, #RRGGBBAA).

7) Text Rules (Important)

  • Set textGrowth first for text
  • textGrowth: auto | fixed-width | fixed-width-height
  • If you set width/height without textGrowth, behavior may be ignored or inconsistent

8) Components (reusable + ref + descendants + slot)

Defining a component

  • Add reusable: true to a frame (or another entity)
  • Its id acts as the component key

Creating an instance

  • type: "ref"
  • ref: "<reusable id>"

descendants override

  • Keys are child id values
  • Access deep children with slash paths: "container/button/label"

slot pattern

  • Declare slot: ["body"] in the component
  • Create an internal frame with name: "body"
  • Inject content through ref.children

9) Variables

Binding format:

  • "$variable.name"

Example:

{
  "fill": "$color.surface",
  "padding": "$space.card.padding"
}

Validation points:

  • The key after $ must exist in variables
  • When using theme-based variable values, they must match themes axis/value

10) IconFont

Supported families:

  • lucide
  • feather
  • Material Symbols Outlined
  • Material Symbols Rounded
  • Material Symbols Sharp
  • phosphor

11) Forbidden Patterns

| Pattern | Result | |---|---| | / in id (e.g., "a/b") | ❌ invalid | | Duplicate id values in the same file | ❌ invalid | | ref points to a non-existent reusable id | ❌ invalid | | width/height on text without textGrowth | ⚠️ warning (may be ignored) | | "$unknown.var" reference | ⚠️ warning (unresolved variable) |

Critical Rules

These rules prevent the most common mistakes agents make.

Rule 1: Component reuse is mandatory

If a matching reusable component exists, you must reuse it with ref.

  1. Check available components with search-nodes.mjs --reusable
  2. If a matching component exists, insert it as a ref instance
  3. Customize with descendants
  4. Create a new one only when no match exists

Rule 2: Variables are mandatory

No hardcoding. Colors, spacing, and typography must use variables.

  1. Check existing variables with get-variables.mjs
  2. Reference values in "$variable.name" format
  3. If a new variable is needed, register it first with set-variables.mjs

Rule 3: Prevent text overflow

For every text node:

  1. Set textGrowth first (auto or fixed-width)
  2. If the parent frame has layout, use fill_container for width
  3. Validate with validate-pen.mjs after editing

Rule 4: Always validate after changes

After each modification:

  1. Validate structural/lint with validate-pen.mjs
  2. Verify structure with read-tree.mjs --depth 2

Rule 5: Reuse assets

For logos, images, and icons:

  1. Search existing assets with search-nodes.mjs --name "logo|brand|icon"
  2. If found, duplicate using batch-design.mjs copy op
  3. Create new assets only when none exist

12) Required Checklist for Creation

  • [ ] Root version and children exist
  • [ ] id is unique and does not use slashes
  • [ ] Target reusable component for each ref exists
  • [ ] variables references match real keys ($...)
  • [ ] textGrowth is set before using width/height on text
  • [ ] When using slot, confirm slot declaration, name frame, and ref.children injection relationship
  • [ ] Check theme axis/value consistency when needed

Property Aliases

The schema defines both singular and plural forms in $defs. On node properties, the canonical key is singular:

  • fill (value can be single fill or array)
  • stroke (value can be single stroke or array)
  • effect (value can be single effect or array)

Scripts accept plural forms (fills, strokes, effects) and normalize them to singular keys on write.

AGENTS.md (Agent Guide)

AGENTS.md is a concise guide with rule summaries and references to individual rules/*.md files for full details. To regenerate after editing rules: node scripts/compile-agents.mjs

CLI Tools

These scripts manipulate .pen files directly. They work without MCP.

Read Tools

| Script | Purpose | Usage | |--------|------|--------| | read-tree.mjs | Print node tree structure | node scripts/read-tree.mjs file.pen [--depth 2] [--id nodeId] | | search-nodes.mjs | Search nodes | node scripts/search-nodes.mjs file.pen --type frame [--reusable] [--name regex] | | get-variables.mjs | View variables/themes | node scripts/get-variables.mjs file.pen [--format json] | | find-space.mjs | Find empty-space coordinates | node scripts/find-space.mjs file.pen --width 300 --height 200 |

Write Tools

| Script | Purpose | Usage | |--------|------|--------| | batch-design.mjs | Insert/update/delete/move/copy nodes | node scripts/batch-design.mjs file.pen --ops '[{"op":"update","id":"node1","props":{"name":"Header"}}]' | | replace-props.mjs | Bulk property replacement | node scripts/replace-props.mjs file.pen --match '{"fill":"#FF0000"}' --replace '{"fill":"$color.primary"}' | | set-variables.mjs | Add/update variables | node scripts/set-variables.mjs file.pen --var 'name=type:value' |

set-variables.mjs theme syntax (@theme):

# Single value
node scripts/set-variables.mjs file.pen --var 'color.primary=color:#0D9488'

# Per-theme variable setting — @theme syntax
node scripts/set-variables.mjs file.pen --var 'color.bg=color:#FFFFFF@light,#0F172A@dark'
node scripts/set-variables.mjs file.pen --var 'space.md=number:12'

Validation Tool

| Script | Purpose | Usage | |--------|------|--------| | validate-pen.mjs | Structural validation + value-type checks + lint | node scripts/validate-pen.mjs file.pen |

batch-design Operations

batch-design.mjs accepts operations as a JSON array:

insert — Insert a new node

{
  "op": "insert",
  "parentId": "frame-1",
  "node": {
    "type": "text",
    "id": "title",
    "content": "Hello",
    "textGrowth": "auto"
  }
}

update — Update properties (deep merge)

{
  "op": "update",
  "id": "title",
  "props": {
    "content": "Updated",
    "fill": "$color.primary"
  }
}

delete — Delete a node

{
  "op": "delete",
  "id": "title"
}

move — Move to another parent

{
  "op": "move",
  "id": "title",
  "toParentId": "frame-2",
  "index": 0
}

copy — Duplicate a node

{
  "op": "copy",
  "id": "card-1",
  "newId": "card-2",
  "toParentId": "grid"
}

Notes:

  • toParentId is optional. If omitted, the copied node is inserted at the root level.
  • During copy, all internal child ids must remain unique → using a newId prefix is recommended
  • Do not send too many ops at once (25 or fewer recommended)
  • Backup is automatically created (.pen.bak)

Standard Workflow

1. read-tree.mjs          → Inspect current structure
2. search-nodes.mjs       → Search reusable components
3. get-variables.mjs      → Check variables/themes
4. find-space.mjs         → Calculate frame placement coordinates
5. batch-design.mjs       → Create/modify nodes
6. validate-pen.mjs       → Validate results

Design Rules

Required rules for production-grade design. 41 rules, 8 categories.

Rule Categories by Priority

| Priority | Category | Impact | Prefix | Rules | |----------|----------|--------|--------|-------| | 1 | Layout & Overflow | CRITICAL | layout- | 8 | | 2 | Design Tokens | CRITICAL | token- | 5 | | 3 | Anti-AI Aesthetic | HIGH | aesthetic- | 6 | | 4 | Component System | HIGH | component- | 5 | | 5 | Typography | MEDIUM | typo- | 5 | | 6 | Color System | MEDIUM | color- | 4 | | 7 | Spacing System | MEDIUM | spacing- | 4 | | 8 | Showcase & Style Guide | MEDIUM | showcase- | 4 |

Quick Reference

1. Layout & Overflow (CRITICAL)

  • layout-auto-layout — Auto Layout is required for all containers
  • layout-sizing — width/height rules by scenario
  • layout-overflow — overflow prevention checklist
  • layout-responsive — responsive simulation (separate frame)
  • layout-spacing-consistency — gap/padding consistency
  • layout-z-order — Z-order and overlay placement
  • layout-no-overlap — prevent element overlap
  • layout-canvas-placement — Top-level canvas placement, no layer overlap

2. Design Tokens (CRITICAL)

  • token-naming — naming format: $category.purpose.variant
  • token-semantic-colors — required semantic color system
  • token-theme-required — light/dark themes required
  • token-no-hardcode — no hardcoding
  • token-workflow — token setup workflow

3. Anti-AI Aesthetic (HIGH)

  • aesthetic-layout — avoid AI-looking layouts
  • aesthetic-typography — avoid AI-looking type choices
  • aesthetic-color — avoid AI-looking colors
  • aesthetic-decoration — avoid AI-looking decoration
  • aesthetic-content — avoid AI-looking content
  • aesthetic-checklist — self-check checklist

4. Component System (HIGH)

  • component-atomic — apply Atomic Design
  • component-naming — Figma-standard naming
  • component-variant — variant patterns
  • component-slot — slot patterns
  • component-reuse-first — component reuse first

5. Typography (MEDIUM)

  • typo-scale — define type scale
  • typo-weight — font-weight usage rules
  • typo-pairing — type pairing guide
  • typo-line-height — line-height rules
  • typo-text-rules — text layout rules

6. Color System (MEDIUM)

  • color-semantic — semantic color system
  • color-accessibility — WCAG 2.1 AA accessibility
  • color-ratio — 60-30-10 color ratio
  • color-dark-mode — dark mode rules

7. Spacing System (MEDIUM)

  • spacing-8pt-grid — 8pt grid system
  • spacing-proximity — proximity principle
  • spacing-padding — padding system
  • spacing-forbidden — forbidden patterns

8. Showcase & Style Guide (MEDIUM)

  • showcase-pre-design — required pre-design process
  • showcase-design-system — design-system-first principle
  • showcase-frame — showcase frame pattern
  • showcase-final-checklist — final QA checklist

How to Use

Check each individual rule file for detailed explanations and code examples:

rules/layout-auto-layout.md
rules/token-naming.md
rules/aesthetic-layout.md

Agent guide with rule summaries: AGENTS.md — full rules in rules/*.md

References

Schema & Types

Conversion Guide

Examples