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:
Technical Requirements — Check for frontend technologies:
- React, Next.js, Vue, Angular, Svelte, Remix, Astro
- Any
frontendoruisection in the tech stack
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
- Tasks creating/modifying
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:
- Identify distinct pages/screens from routes mentioned in tasks
- For each page, identify components (forms, tables, navigation, etc.)
- For each component, document states and interactions
- Map user flows between pages
- Write
ux/wireframe-spec.yaml
See 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 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)
- Single File — All components and page wireframes in one
ux/wireframes.penfile (no cross-file refs) - No Hardcoded Colors — All fills/strokes/text use
$wf-*variables - No Raw Shapes for Known Components — Use component instances (
type: "ref") referencing in-file components - Use Component Structure — Compose pages using
wf-page-shelland populate its child slots - Consistent Dimensions — Use literal
1440for page width and900for page height (Pencil silently drops$wf-*variable references on width/height properties) - Label Everything — Override all descendant labels with actual content names
- State Annotations — Add
wf-state-badgewhere 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 --strict
Phase 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 Review