pencil-skill
npx skills add https://github.com/de-novo/pencil-skill --skill pencil-skill
Agent 安装分布
Skill 文档
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": []
}
versionandchildrenare requiredthemesandvariablesare optional, but practically essential for a design system
3) List of Object Types
rectangle: basic rectangleellipse: circle/arcline: linepolygon: polygonpath: path geometrytext: textframe: layout container + can declare slotsgroup: group containernote: annotationprompt: prompt memocontext: context memoicon_font: icon-font-based vector iconref: reusable component instance
4) Layout (Summary)
Remember only the core properties:
layout:none | vertical | horizontalgap,paddingjustifyContent:start | center | end | space_between | space_aroundalignItems:start | center | end
Gotcha:
- Child
x,yvalues 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_contentfill_containerfit_content(${number})
width and height can use numbers, variables, or the SizingBehavior values above.
6) Graphics Essentials
fill: color / gradient / image / mesh_gradientstroke:align,thickness,join,cap,dashPattern,filleffect:blur,background_blur,shadow
Color values are recommended in hex format (#RGB, #RRGGBB, #RRGGBBAA).
7) Text Rules (Important)
- Set
textGrowthfirst fortext textGrowth:auto | fixed-width | fixed-width-height- If you set
width/heightwithouttextGrowth, behavior may be ignored or inconsistent
8) Components (reusable + ref + descendants + slot)
Defining a component
- Add
reusable: trueto aframe(or another entity) - Its
idacts as the component key
Creating an instance
type: "ref"ref: "<reusable id>"
descendants override
- Keys are child
idvalues - 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 invariables - When using theme-based variable values, they must match
themesaxis/value
10) IconFont
Supported families:
lucidefeatherMaterial Symbols OutlinedMaterial Symbols RoundedMaterial Symbols Sharpphosphor
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.
- Check available components with
search-nodes.mjs --reusable - If a matching component exists, insert it as a
refinstance - Customize with
descendants - Create a new one only when no match exists
Rule 2: Variables are mandatory
No hardcoding. Colors, spacing, and typography must use variables.
- Check existing variables with
get-variables.mjs - Reference values in
"$variable.name"format - If a new variable is needed, register it first with
set-variables.mjs
Rule 3: Prevent text overflow
For every text node:
- Set
textGrowthfirst (autoorfixed-width) - If the parent frame has layout, use
fill_containerfor width - Validate with
validate-pen.mjsafter editing
Rule 4: Always validate after changes
After each modification:
- Validate structural/lint with
validate-pen.mjs - Verify structure with
read-tree.mjs --depth 2
Rule 5: Reuse assets
For logos, images, and icons:
- Search existing assets with
search-nodes.mjs --name "logo|brand|icon" - If found, duplicate using
batch-design.mjscopyop - Create new assets only when none exist
12) Required Checklist for Creation
- Root
versionandchildrenexist -
idis unique and does not use slashes - Target reusable component for each
refexists -
variablesreferences match real keys ($...) -
textGrowthis set before usingwidth/heighton text - When using slot, confirm
slotdeclaration,nameframe, andref.childreninjection 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:
toParentIdis optional. If omitted, the copied node is inserted at the root level.- During copy, all internal child ids must remain unique â using a
newIdprefix 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 containerslayout-sizingâ width/height rules by scenariolayout-overflowâ overflow prevention checklistlayout-responsiveâ responsive simulation (separate frame)layout-spacing-consistencyâ gap/padding consistencylayout-z-orderâ Z-order and overlay placementlayout-no-overlapâ prevent element overlaplayout-canvas-placementâ Top-level canvas placement, no layer overlap
2. Design Tokens (CRITICAL)
token-namingâ naming format: $category.purpose.varianttoken-semantic-colorsâ required semantic color systemtoken-theme-requiredâ light/dark themes requiredtoken-no-hardcodeâ no hardcodingtoken-workflowâ token setup workflow
3. Anti-AI Aesthetic (HIGH)
aesthetic-layoutâ avoid AI-looking layoutsaesthetic-typographyâ avoid AI-looking type choicesaesthetic-colorâ avoid AI-looking colorsaesthetic-decorationâ avoid AI-looking decorationaesthetic-contentâ avoid AI-looking contentaesthetic-checklistâ self-check checklist
4. Component System (HIGH)
component-atomicâ apply Atomic Designcomponent-namingâ Figma-standard namingcomponent-variantâ variant patternscomponent-slotâ slot patternscomponent-reuse-firstâ component reuse first
5. Typography (MEDIUM)
typo-scaleâ define type scaletypo-weightâ font-weight usage rulestypo-pairingâ type pairing guidetypo-line-heightâ line-height rulestypo-text-rulesâ text layout rules
6. Color System (MEDIUM)
color-semanticâ semantic color systemcolor-accessibilityâ WCAG 2.1 AA accessibilitycolor-ratioâ 60-30-10 color ratiocolor-dark-modeâ dark mode rules
7. Spacing System (MEDIUM)
spacing-8pt-gridâ 8pt grid systemspacing-proximityâ proximity principlespacing-paddingâ padding systemspacing-forbiddenâ forbidden patterns
8. Showcase & Style Guide (MEDIUM)
showcase-pre-designâ required pre-design processshowcase-design-systemâ design-system-first principleshowcase-frameâ showcase frame patternshowcase-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
- pen-schema.json: Official JSON Schema (v2.8)
- pen-types.ts: TypeScript type definitions
Conversion Guide
- pen-to-tailwind.md: .pen â Tailwind CSS conversion table
- component-patterns.md: UI component patterns
Examples
- example-card.pen: Complete .pen file example
- reddit-ui.pen: Reddit-style 3-column UI layout with reusable components