
Ux Wireframe Planning
- 9 installs
- 1 repo stars
- Updated June 17, 2026
- validkeys/sherpy
Helps with productivity & planning tasks.
About
ux-wireframe-planning is a Claude Code skill for productivity & planning. It helps solo builders move faster with AI-assisted development.
- ux-wireframe-planning
- Productivity & Planning
- AI-coding skill
Ux Wireframe Planning by the numbers
- 9 all-time installs (skills.sh)
- +1 installs in the week ending Jul 27, 2026 (Skillselion tracking)
- Ranked #2,221 of 3,282 Productivity & Planning skills by installs in the Skillselion catalog
- Data as of Jul 27, 2026 (Skillselion catalog sync)
npx skills add https://github.com/validkeys/sherpy --skill ux-wireframe-planningAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 9 |
|---|---|
| repo stars | ★ 1 |
| Last updated | June 17, 2026 |
| Repository | validkeys/sherpy ↗ |
What it does
Helps with productivity & planning tasks.
Files
UX/Wireframe Planning
Detects whether a project involves UI/webapp work and, when it does, generates a wireframe specification plus visual wireframes. For projects with no frontend changes, the step auto-skips after generating a minimal spec with has_ui_changes: false.
Prerequisites
implementation/milestones.yamlandimplementation/tasks/milestone-m*.tasks.yamlrequirements/technical-requirements.yamlrequirements/business-requirements.yaml(for requirement references)
Usage
/ux-wireframe-planning [base-directory]If no base directory is provided, auto-detect by looking for implementation/milestones.yaml.
Process
Phase 1: Detection
Read the following documents and scan for UI-related work:
1. Technical Requirements — Check for frontend technologies:
- React, Next.js, Vue, Angular, Svelte, Remix, Astro
- Any
frontendoruisection in the tech stack
2. Implementation Plan Tasks — Scan all task files for:
- Tasks creating/modifying
.tsx,.jsx,.vue,.sveltefiles - Tasks mentioning: component, page, route, layout, navigation, modal, form, table
- Tasks with
ui_component: truetag
3. Business Requirements — Check for:
- Use cases involving user interaction
- Personas that are end-users
Phase 2: Decision
If NO UI changes detected across all signals:
- Generate
ux/wireframe-spec.yamlwithhas_ui_changes: false - Output detection summary
- Step is complete — auto-skip wireframe generation
If UI changes ARE detected:
- Proceed to Phase 3
Phase 3: Wireframe Spec Generation
Extract pages and components from the detected UI tasks and requirements:
1. Identify distinct pages/screens from routes mentioned in tasks 2. For each page, identify components (forms, tables, navigation, etc.) 3. For each component, document states and interactions 4. Map user flows between pages 5. Write ux/wireframe-spec.yaml
See [references/example.yaml](references/example.yaml) for the output format.
Phase 4: Wireframe File Creation (Components + Pages)
All wireframe content — variables, reusable components, and page frames — lives in a single self-contained `.pen` file: ux/wireframes.pen.
Important: Pencil does NOT support cross-file component references. Every.penfile must contain its own component definitions inline. Attempting toimportsa library file and reference its components viarefwill producebroken_refnodes. Therefore, all components and pages go in one file.
The wireframe file contains three sections:
- Variables (design tokens): Colors, spacing, typography, sizing — all prefixed
wf- - Reusable components: Wireframe primitives (page-shell, header, sidebar, card, form-field, button, table, etc.) as top-level children with
reusable: true - Page wireframes: Top-level
refnodes that instance the in-file components
See [references/pencil-wireframe-kit.md](references/pencil-wireframe-kit.md) for the complete variable catalog, component definitions, and slot map.
Creating the File via MCP Tools
// 1. Set all design tokens as variables
pencil_set_variables({
filePath: "ux/wireframes.pen",
variables: {
"wf-page-bg": {"type": "color", "value": "#F0F0F0"},
"wf-surface": {"type": "color", "value": "#FFFFFF"},
"wf-border": {"type": "color", "value": "#CCCCCC"},
"wf-text-primary": {"type": "color", "value": "#333333"},
"wf-text-secondary": {"type": "color", "value": "#888888"},
"wf-accent": {"type": "color", "value": "#4A90D9"},
// ... see references for full list
}
})
// 2. Create reusable components as top-level children
pencil_batch_design({
filePath: "ux/wireframes.pen",
input: `
pageShell = I(document, {
type: "frame", name: "Page Shell", reusable: true,
width: 1440, height: 900,
layout: "vertical", fill: "$wf-page-bg"
})
headerSlot = I(pageShell, {
type: "frame", name: "Header Slot",
width: "fill_container", height: "fit_content",
layout: "horizontal", fill: "$wf-surface",
padding: ["$wf-space-md", "$wf-space-lg"]
})
bodySlot = I(pageShell, {
type: "frame", name: "Body Slot",
width: "fill_container", height: "fill_container", layout: "horizontal"
})
footerSlot = I(pageShell, {
type: "frame", name: "Footer Slot",
width: "fill_container", height: "fit_content", fill: "$wf-surface"
})
// ... create all remaining components as top-level children
// header, sidebar, content-area, card, form-field, button, etc.
`
})Phase 5: Per-Page Wireframe Generation
For each page in the wireframe spec, add a page frame to the same .pen file:
Consistency Rules (MANDATORY)
1. Single File — All components and page wireframes in one ux/wireframes.pen file (no cross-file refs) 2. No Hardcoded Colors — All fills/strokes/text use $wf-* variables 3. No Raw Shapes for Known Components — Use component instances (type: "ref") referencing in-file components 4. Use Component Structure — Compose pages using wf-page-shell and populate its child slots 5. Consistent Dimensions — Use literal 1440 for page width and 900 for page height (Pencil silently drops $wf-* variable references on width/height properties) 6. Label Everything — Override all descendant labels with actual content names 7. State Annotations — Add wf-state-badge where component states are defined
Generation Pattern
// Add page wireframe to the SAME file using in-file component refs
pencil_batch_design({
filePath: "ux/wireframes.pen",
input: `
page = I(document, {
type: "ref", ref: "wf-page-shell",
x: 0, y: 1100,
descendants: {
"header-slot": { children: [
{type: "ref", ref: "wf-header", descendants: {
"header-nav": { children: [
{type: "ref", ref: "wf-nav-item", descendants: {
"nav-label": {content: "Dashboard"}
}},
{type: "ref", ref: "wf-nav-item", descendants: {
"nav-label": {content: "Settings"}
}}
]}
}}
]},
"body-slot": { children: [
{type: "ref", ref: "wf-sidebar"},
{type: "ref", ref: "wf-content-area", descendants: {
"content-title": {content: "User Profile"},
"content-slot": { children: [
{type: "ref", ref: "wf-card", descendants: {
"card-title": {content: "Profile"},
"card-body": { children: [
{type: "ref", ref: "wf-form-field", descendants: {
"field-label": {content: "Name"}
}},
{type: "ref", ref: "wf-button", descendants: {
"button-label": {content: "Save"}
}}
]}
}}
]}
}}
]},
"footer-slot": { children: [
{type: "ref", ref: "wf-footer", descendants: {
"footer-text": {content: "Wireframe Preview"}
}}
]}
}
})
`
})
// Export PNG preview for this page
pencil_export_nodes({
filePath: "ux/wireframes.pen",
nodeIds: [pageNodeId],
outputDir: "ux/",
format: "png"
})Phase 6: Update Wireframe Spec
After generating all wireframes, update ux/wireframe-spec.yaml with:
pen_file: "ux/wireframes.pen"for each wireframe entry (same file for all pages)preview_pngpaths for each exported PNGstatus: generated
Phase 7: Validate
sherpy validate -t wireframe-spec -f ux/wireframe-spec.yaml --strictPhase 8: Consistency Checklist
Before completing, verify:
- [ ]
ux/wireframes.pencontains all defined variables - [ ] All components from the catalog exist as top-level reusable nodes
- [ ] All page wireframes reference in-file components (no cross-file refs)
- [ ] No hardcoded color values (all use
$wf-*variables) - [ ] Every page uses
wf-page-shellas root component - [ ] Every component instance has overridden labels
- [ ] State badges present where spec defines states
- [ ] PNG previews exported for all wireframes
Output Files
ux/
├── wireframe-spec.yaml # Structured spec
├── wireframes.pen # All components + page wireframes (self-contained)
├── PAGE-001.png # Exported preview
├── PAGE-002.png # Exported preview
└── ...Self-Review
## Wireframe Planning Summary
**UI Changes Detected:** [yes/no]
**Detection Summary:** [how determined]
**Pages:** [n]
**Components:** [n]
**Wireframes Generated:** [n]
By Page:
PAGE-001 [name]: [n] components, wireframe ✓/pending
PAGE-002 [name]: [n] components, wireframe ✓/pending
...
Next step → Continue to Implementation Plan Reviewmetadata:
project_name: "TaskFlow"
generated_date: "2025-06-12"
source_documents:
- "requirements/business-requirements.yaml"
- "requirements/technical-requirements.yaml"
- "implementation/milestones.yaml"
has_ui_changes: true
detection_summary: >-
Tech stack includes React 18 + Next.js 14. Implementation tasks reference
.tsx files for dashboard, settings, and auth pages. Business requirements
define 3 end-user personas with interactive use cases.
pages:
- id: PAGE-001
name: "Dashboard"
route: "/dashboard"
description: "Main task overview showing assigned tasks, progress charts, and recent activity"
source_requirement: "FR-001"
components:
- id: COMP-001
name: "Task List"
type: list
description: "Sortable list of assigned tasks with priority badges"
states: [empty, loading, error]
interactions:
- trigger: "click task row"
action: "Navigate to task detail"
destination: "PAGE-003"
- trigger: "click sort header"
action: "Toggle sort direction"
- id: COMP-002
name: "Progress Chart"
type: chart
description: "Bar chart showing weekly task completion"
states: [empty, loading]
- id: COMP-003
name: "Quick Actions"
type: navigation
description: "Buttons for create task, filter, and export"
interactions:
- trigger: "click create task"
action: "Open create task modal"
destination: "PAGE-002"
user_flows:
- name: "View and open task"
steps:
- from: "Dashboard"
to: "Task List"
action: "Page loads, tasks displayed"
- from: "Task List"
to: "Task Detail"
action: "User clicks a task row"
- id: PAGE-002
name: "Create Task Modal"
route: "/dashboard#create"
description: "Modal dialog for creating a new task"
source_requirement: "FR-003"
components:
- id: COMP-001
name: "Task Form"
type: form
description: "Form with title, description, assignee, priority, and due date fields"
states: [empty, error, success]
interactions:
- trigger: "submit"
action: "Create task and close modal"
destination: "PAGE-001"
- trigger: "cancel"
action: "Close modal without saving"
- id: PAGE-003
name: "Task Detail"
route: "/tasks/:id"
description: "Detailed view of a single task with comments and activity log"
source_requirement: "FR-002"
components:
- id: COMP-001
name: "Task Header"
type: detail
description: "Title, status badge, assignee avatar, due date"
- id: COMP-002
name: "Description"
type: detail
description: "Rich text description of the task"
- id: COMP-003
name: "Comments"
type: list
description: "Threaded comments with author and timestamp"
states: [empty, loading]
interactions:
- trigger: "submit comment"
action: "Add comment to thread"
- id: COMP-004
name: "Activity Log"
type: table
description: "Chronological log of status changes and updates"
states: [empty]
wireframes:
- page_id: PAGE-001
pen_file: "ux/wireframes.pen"
preview_png: "ux/PAGE-001.png"
status: generated
notes: "Desktop layout with sidebar navigation"
- page_id: PAGE-002
pen_file: "ux/wireframes.pen"
preview_png: "ux/PAGE-002.png"
status: generated
notes: "Modal overlay on dashboard"
- page_id: PAGE-003
pen_file: "ux/wireframes.pen"
preview_png: "ux/PAGE-003.png"
status: generated
Pencil Wireframe Kit — Consistency Strategy
Overview
Wireframes generated by Sherpy's UX/Wireframe Planning step (Step 6) must look consistent across pages, projects, and sessions. This is enforced via three mechanisms within a single self-contained `.pen` file:
1. Variables — Design tokens (colors, spacing, fonts) defined once, referenced everywhere 2. Reusable Components — Wireframe primitives built once as top-level nodes, instanced via ref throughout the file 3. Slots — Typed content areas in components that guide what goes where
The strategy: create a single `ux/wireframes.pen` file containing all design tokens, reusable components, and page wireframe frames. All page wireframes reference the in-file component definitions via ref.
Critical: Pencil does NOT support cross-file component references. Theimportsmechanism in.penfiles does not make components referenceable viareffrom other files. Attempting to reference components across files producesbroken_refnodes. All components and pages MUST be in the same.penfile.
Location
{base_directory}/
└── ux/
├── wireframe-spec.yaml # structured spec
├── wireframes.pen # all components + page wireframes (self-contained)
├── PAGE-001.png # exported preview
├── PAGE-002.png # exported preview
└── ...---
2. Variables (Design Tokens)
All visual properties are defined as variables. Wireframes reference these using the $ prefix (e.g., fill: "$wf-surface"). No hardcoded hex values anywhere in wireframe files.
Color Variables
| Variable | Value | Purpose |
|---|---|---|
wf-page-bg | #F0F0F0 | Page background (light gray) |
wf-surface | #FFFFFF | Component/card surfaces (white) |
wf-surface-alt | #E8E8E8 | Alternate surface (slightly darker gray) |
wf-border | #CCCCCC | Borders and dividers |
wf-border-strong | #999999 | Emphasized borders |
wf-text-primary | #333333 | Primary text/labels |
wf-text-secondary | #888888 | Secondary text/annotations |
wf-text-placeholder | #AAAAAA | Placeholder text |
wf-accent | #4A90D9 | Accent/highlight (links, active nav) |
wf-state-empty | #E8E8E8 | Empty state indicator |
wf-state-loading | #D0D0D0 | Loading state indicator |
wf-state-error | #D9534F | Error state indicator |
wf-state-success | #5CB85C | Success state indicator |
Spacing & Sizing Variables
| Variable | Value | Purpose |
|---|---|---|
wf-space-xs | 4 | Extra small spacing |
wf-space-sm | 8 | Small spacing (default gap) |
wf-space-md | 16 | Medium spacing (padding) |
wf-space-lg | 24 | Large spacing (section gaps) |
wf-space-xl | 32 | Extra large spacing |
wf-radius | 4 | Standard corner radius |
wf-radius-lg | 8 | Large corner radius (cards) |
Typography Variables
| Variable | Value | Purpose |
|---|---|---|
wf-font-family | Inter | Font family for all wireframe text |
wf-text-xs | 10 | Annotation/badge text size |
wf-text-sm | 12 | Label text size |
wf-text-base | 14 | Body text size |
wf-text-lg | 18 | Section heading size |
wf-text-xl | 24 | Page title size |
wf-text-2xl | 32 | Large page title size |
Sizing — Literal Values (NOT Variables)
Pencil's layout engine silently drops $wf-* variable references on width/height properties. Use literal values instead:
| Dimension | Value | Purpose |
|---|---|---|
| Page width | 1440 | Standard desktop page width |
| Page height | 900 | Standard desktop page height |
| Sidebar width | 240 | Standard sidebar width |
| Header height | fit_content | Header slot (content-driven) |
| Footer height | fit_content | Footer slot (content-driven) |
Variable Definition (for pencil_set_variables)
{
"wf-page-bg": {"type": "color", "value": "#F0F0F0"},
"wf-surface": {"type": "color", "value": "#FFFFFF"},
"wf-surface-alt": {"type": "color", "value": "#E8E8E8"},
"wf-border": {"type": "color", "value": "#CCCCCC"},
"wf-border-strong": {"type": "color", "value": "#999999"},
"wf-text-primary": {"type": "color", "value": "#333333"},
"wf-text-secondary": {"type": "color", "value": "#888888"},
"wf-text-placeholder": {"type": "color", "value": "#AAAAAA"},
"wf-accent": {"type": "color", "value": "#4A90D9"},
"wf-state-empty": {"type": "color", "value": "#E8E8E8"},
"wf-state-loading": {"type": "color", "value": "#D0D0D0"},
"wf-state-error": {"type": "color", "value": "#D9534F"},
"wf-state-success": {"type": "color", "value": "#5CB85C"},
"wf-space-xs": {"type": "number", "value": 4},
"wf-space-sm": {"type": "number", "value": 8},
"wf-space-md": {"type": "number", "value": 16},
"wf-space-lg": {"type": "number", "value": 24},
"wf-space-xl": {"type": "number", "value": 32},
"wf-radius": {"type": "number", "value": 4},
"wf-radius-lg": {"type": "number", "value": 8},
"wf-font-family": {"type": "string", "value": "Inter"},
"wf-text-xs": {"type": "number", "value": 10},
"wf-text-sm": {"type": "number", "value": 12},
"wf-text-base": {"type": "number", "value": 14},
"wf-text-lg": {"type": "number", "value": 18},
"wf-text-xl": {"type": "number", "value": 24},
"wf-text-2xl": {"type": "number", "value": 32}
}Do NOT define `wf-page-width`, `wf-page-height`, `wf-sidebar-width`, `wf-header-height`, or `wf-footer-height` as variables. Pencil silently drops$wf-*references onwidth/height. Use literal values (1440,900,240) orfit_content/fill_container(N)instead.
---
3. Reusable Components
Wireframe primitives defined as Pencil reusable components (reusable: true). Each generated wireframe creates instances (type: "ref") of these components — never raw shapes.
Component Catalog
Layout Components
| Component ID | Description | Slots |
|---|---|---|
wf-page-shell | Full page container (1440x900). Vertical layout. Has header slot, body slot, footer slot. | header, body, footer |
wf-header | Top navigation bar (full width, 64px tall). Horizontal layout. Has logo slot, nav slot, actions slot. | logo, nav, actions |
wf-sidebar | Left sidebar (240px wide). Vertical layout. Has nav-items slot. | nav-items |
wf-content-area | Main content region. Vertical layout with padding. Has content slot. | content |
wf-footer | Bottom bar (full width, 48px tall). Horizontal layout. | — |
Content Components
| Component ID | Description | Slots |
|---|---|---|
wf-card | Rounded rectangle container with surface fill, border, padding. Has title slot, body slot. | title, body |
wf-section | Labeled content section. Has label text + content slot. | content |
wf-placeholder-box | Generic gray placeholder rectangle with centered label text. Configurable via label override. | — |
wf-divider | Horizontal line divider using border color. | — |
Form Components
| Component ID | Description | Slots |
|---|---|---|
wf-form | Vertical container for form fields. Has fields slot. | fields |
wf-form-field | Label + input placeholder. Two children: label text and input rectangle. Configurable via label override. | — |
wf-button | Pill-shaped button placeholder. Has label slot. Configurable via label/style override. | — |
wf-checkbox | Square box + label text. Configurable via label override. | — |
wf-radio | Circle + label text. Configurable via label override. | — |
wf-dropdown | Input rectangle with chevron indicator. Configurable via label override. | — |
wf-textarea | Tall input rectangle with label. Configurable via label override. | — |
Data Components
| Component ID | Description | Slots |
|---|---|---|
wf-table | Table structure: header row + body. Has rows slot. | rows |
wf-table-row | Horizontal row of cell placeholders. | — |
wf-list-item | Horizontal list row with icon placeholder + text. Configurable via label override. | — |
wf-chart | Chart placeholder (bar chart silhouette). Configurable via title override. | — |
Navigation Components
| Component ID | Description | Slots |
|---|---|---|
wf-nav-item | Navigation item with icon placeholder + label. Configurable via label override. | — |
wf-breadcrumb | Horizontal breadcrumb trail. Has items slot. | items |
wf-tab | Tab label with optional active indicator. Configurable via label/active override. | — |
Annotation Components
| Component ID | Description | Purpose |
|---|---|---|
wf-label | Small annotation text (secondary color). Used to label wireframe areas. | |
wf-state-badge | Small colored badge indicating component state. Configurable via state override (empty/loading/error/success). | |
wf-note | Italic annotation with arrow connector. Used for interaction notes. |
Component Example (JSON structure)
Here is how wf-page-shell is defined in the library:
{
"id": "wf-page-shell",
"type": "frame",
"name": "Page Shell",
"reusable": true,
"width": 1440,
"height": 900,
"layout": "vertical",
"fill": "$wf-page-bg",
"children": [
{
"id": "header",
"type": "frame",
"name": "Header Slot",
"width": "fill_container",
"height": "fit_content",
"layout": "horizontal",
"fill": "$wf-surface",
"slot": ["wf-header"],
"padding": ["$wf-space-md", "$wf-space-lg"]
},
{
"id": "body",
"type": "frame",
"name": "Body Slot",
"width": "fill_container",
"height": "fill_container",
"layout": "horizontal",
"slot": ["wf-sidebar", "wf-content-area"]
},
{
"id": "footer",
"type": "frame",
"name": "Footer Slot",
"width": "fill_container",
"height": "fit_content",
"layout": "horizontal",
"fill": "$wf-surface",
"slot": ["wf-footer"]
}
]
}And wf-form-field:
{
"id": "wf-form-field",
"type": "frame",
"name": "Form Field",
"reusable": true,
"width": "fill_container",
"height": "fit_content",
"layout": "vertical",
"gap": "$wf-space-xs",
"children": [
{
"id": "field-label",
"type": "text",
"content": "Label",
"fontFamily": "$wf-font-family",
"fontSize": "$wf-text-sm",
"fill": "$wf-text-primary"
},
{
"id": "field-input",
"type": "rectangle",
"width": "fill_container",
"height": 36,
"fill": "$wf-surface",
"stroke": "$wf-border",
"strokeWidth": 1,
"cornerRadius": "$wf-radius"
}
]
}---
4. Slots — Typed Content Areas
Slots tell the AI (and human designers) what kind of content belongs in each area. From the Pencil docs:
Slots are designated areas within a component where elements can be dropped in. They let you define flexible, customizable regions in your components.
A slot's slot property lists the IDs of components that are suggested for that area:
{
"id": "body",
"type": "frame",
"slot": ["wf-sidebar", "wf-content-area"]
}This means when generating a wireframe, the AI knows the body area should contain a wf-sidebar instance and a wf-content-area instance — not random shapes.
Slot Map
| Component | Slot | Suggested Components |
|---|---|---|
wf-page-shell | header | wf-header |
wf-page-shell | body | wf-sidebar, wf-content-area |
wf-page-shell | footer | wf-footer |
wf-header | logo | wf-placeholder-box |
wf-header | nav | wf-nav-item |
wf-header | actions | wf-button |
wf-sidebar | nav-items | wf-nav-item |
wf-content-area | content | wf-card, wf-section, wf-table, wf-form, wf-chart |
wf-card | title | text nodes |
wf-card | body | wf-form-field, wf-table, wf-list-item, wf-placeholder-box, wf-button |
wf-section | content | wf-card, wf-table, wf-form, wf-chart, wf-placeholder-box |
wf-form | fields | wf-form-field, wf-checkbox, wf-radio, wf-dropdown, wf-textarea |
wf-table | rows | wf-table-row |
---
5. Skill Rules for Wireframe Generation
The UX/Wireframe Planning skill MUST enforce these rules in its instructions:
Rule 1: Single File — No Cross-File Refs
All components and page wireframes must be in the same ux/wireframes.pen file. Do NOT use imports or cross-file ref references — Pencil does not support them and will produce broken_ref nodes.
// CORRECT — in-file ref (component defined as top-level child in same file)
{"type": "ref", "ref": "wf-page-shell"}
// WRONG — cross-file ref (produces broken_ref even with imports)
{"imports": {"kit": "../wireframe-kit.lib.pen"}}
{"type": "ref", "ref": "kit/wf-page-shell"}Rule 2: No Hardcoded Colors
All fills, strokes, and text colors must reference variables:
// CORRECT
{"fill": "$wf-surface"}
// WRONG
{"fill": "#FFFFFF"}Rule 3: No Raw Shapes for Known Components
Use component instances (type: "ref") from the file's own component definitions. Only use raw rectangle/frame/text when no library component matches.
// CORRECT — use form field component instance (in-file ref)
{
"type": "ref",
"ref": "wf-form-field",
"descendants": {
"field-label": {"content": "Email Address"}
}
}
// WRONG — raw rectangle for a form field
{
"type": "rectangle",
"width": 300,
"height": 36,
"fill": "#FFFFFF"
}Rule 4: Use Component Structure for Pages
When composing a page, use the wf-page-shell component and populate its child slots. Don't build layout from scratch.
// CORRECT — page shell with slot content (all in-file refs)
{
"type": "ref",
"ref": "wf-page-shell",
"descendants": {
"header-slot": {
"children": [
{"type": "ref", "ref": "wf-header", "descendants": {
"header-nav": {"children": [
{"type": "ref", "ref": "wf-nav-item", "descendants": {
"nav-label": {"content": "Dashboard"}
}},
{"type": "ref", "ref": "wf-nav-item", "descendants": {
"nav-label": {"content": "Settings"}
}}
]}
}}
]
},
"body-slot": {
"children": [
{"type": "ref", "ref": "wf-sidebar"},
{"type": "ref", "ref": "wf-content-area", "descendants": {
"content-title": {"content": "User Profile"},
"content-slot": {"children": [
{"type": "ref", "ref": "wf-card", "descendants": {
"card-title": {"content": "Profile"},
"card-body": {"children": [
{"type": "ref", "ref": "wf-form-field", "descendants": {
"field-label": {"content": "Name"}
}},
{"type": "ref", "ref": "wf-form-field", "descendants": {
"field-label": {"content": "Email"}
}},
{"type": "ref", "ref": "wf-button", "descendants": {
"button-label": {"content": "Save"}
}}
]}
}}
]}
}}
]
}
}
}Rule 5: Consistent Dimensions
Always use literal 1440 for page width and 900 for page height. Pencil silently drops $wf-* variable references on width/height properties — use literal numbers (1440, 900, 240), fit_content, or fill_container(N) instead. Mobile wireframes (if added later) would use different literal dimensions.
Rule 6: Label Everything
Every component instance must have its label/descendant properties overridden with the actual content name. Generic labels like "Label" or "Button" are only in the library definition — instances must specify what they represent.
Rule 7: State Annotations
When the wireframe spec defines component states (empty, loading, error, success), add wf-state-badge instances near the component to annotate which states apply.
---
6. File Creation Flow
When the UX/Wireframe Planning skill runs (Step 6), it creates a single self-contained file:
1. Create ux/wireframes.pen
a. Call pencil_set_variables with all design tokens
b. Call pencil_batch_design to create all reusable components as top-level children
c. For each page in the spec:
- Call pencil_batch_design to add a page frame (type: "ref", ref: "wf-page-shell")
- Override descendants with page-specific content
d. Export PNG previews for each page frame
e. Save as ux/wireframes.penWhy Not Multiple Files?
Pencil's imports mechanism does NOT enable cross-file ref references. From the Pencil documentation: "You cannot reference components across files. If you want to use a component from a different file you must copy it over." Therefore:
- All reusable components must be top-level children in the same
.penfile as the page wireframes - Component
refvalues use bare IDs (e.g.,"wf-page-shell") not prefixed paths (e.g.,"kit/wf-page-shell") - A single file simplifies sharing, version control, and consistency management
---
7. Theming (Future)
The variable system supports theming via theme axes. A future enhancement could define:
"themes": {
"mode": ["wireframe", "hifi"]
}With variable values:
{
"wf-surface": {
"type": "color",
"value": [
{"value": "#FFFFFF", "theme": {"mode": "wireframe"}},
{"value": "#F8F9FA", "theme": {"mode": "hifi"}}
]
}
}This would let the same wireframe file switch between low-fidelity wireframe and higher-fidelity mockup modes. Not needed for the initial implementation.
---
8. MCP Tool Usage Pattern
The skill uses these Pencil MCP tools in this order, all targeting the same file:
Phase 1: Create File + Components (once per project)
// 1. Set variables
pencil_set_variables({
filePath: "ux/wireframes.pen",
variables: { /* all wf-* tokens from section 2 */ }
})
// 2. Create components via batch_design (all as top-level children)
pencil_batch_design({
filePath: "ux/wireframes.pen",
input: `
// Layout components — all reusable, all top-level
pageShell = I(document, {type:"frame", name:"Page Shell", reusable:true, ...})
header = I(document, {type:"frame", name:"Header", reusable:true, ...})
sidebar = I(document, {type:"frame", name:"Sidebar", reusable:true, ...})
contentArea = I(document, {type:"frame", name:"Content Area", reusable:true, ...})
// Content components
card = I(document, {type:"frame", name:"Card", reusable:true, ...})
placeholderBox = I(document, {type:"frame", name:"Placeholder Box", reusable:true, ...})
// Form components
formField = I(document, {type:"frame", name:"Form Field", reusable:true, ...})
button = I(document, {type:"frame", name:"Button", reusable:true, ...})
// Data components
table = I(document, {type:"frame", name:"Table", reusable:true, ...})
tableRow = I(document, {type:"frame", name:"Table Row", reusable:true, ...})
// Navigation
navItem = I(document, {type:"frame", name:"Nav Item", reusable:true, ...})
// Annotations
stateBadge = I(document, {type:"frame", name:"State Badge", reusable:true, ...})
`
})Phase 2: Add Page Wireframes (per page, same file)
// Add each page as a top-level ref node
pencil_batch_design({
filePath: "ux/wireframes.pen",
input: `
// Page wireframe using in-file component refs
page = I(document, {
type: "ref",
ref: "wf-page-shell",
x: 0, y: 1100,
descendants: {
"header-slot": { /* populate with wf-header instance */ },
"body-slot": { /* populate with wf-sidebar + wf-content-area */ },
"footer-slot": { /* populate with wf-footer */ }
}
})
`
})
// Export PNG preview for this page
pencil_export_nodes({
filePath: "ux/wireframes.pen",
nodeIds: [pageId],
outputDir: "ux/",
format: "png"
})---
9. Consistency Checklist
Before completing Step 6, the skill verifies:
- [ ]
ux/wireframes.penexists with all defined variables - [ ] All components from the catalog exist as top-level reusable nodes in the file
- [ ] All page wireframes reference in-file components (no cross-file refs)
- [ ] No hardcoded color values in any wireframe (all use
$wf-*variables) - [ ] Every page uses
wf-page-shellas its root component - [ ] Every component instance has overridden labels (no default "Label" text)
- [ ] State badges present where the spec defines component states
- [ ] PNG previews exported for all wireframes