Penpot UI/UX design
Create or refine Penpot designs by combining MCP tool execution with UI/UX principles, design-system discovery, accessibility checks, component specs, layout rules, and visual validation.
When to invoke
- "Design a UI for this app in Penpot."
- "Create a dashboard layout and component library."
- "Make this Penpot design accessible."
- "Build a mobile form and navigation flow."
- "Review this landing page for usability."
Prerequisites and context
- Use the
penpot/penpot-mcp MCP server when Penpot tools are available.
- Check whether
mcp__penpot__penpot_api_info succeeds before giving setup instructions. If it succeeds, the server is running and connected.
- If the tool fails, ask whether the Penpot MCP server is already installed and running; only guide installation when the user confirms it is not installed.
- Installation path: clone https://github.com/penpot/penpot-mcp.git and run
npm install, then npm run bootstrap.
- In Penpot, open a design file, choose Plugins → Load plugin from URL, enter
http://localhost:4400/manifest.json, then click "Connect to MCP server" in the plugin UI.
- VS Code MCP configuration uses
http://localhost:4401/sse under mcp.servers.penpot.url.
MCP tool map
| Tool |
Use it for |
mcp__penpot__execute_code |
Run JavaScript in the Penpot plugin context to create, inspect, and modify designs. |
mcp__penpot__export_shape |
Export shapes as PNG/SVG for visual inspection. |
mcp__penpot__import_image |
Import images, icons, photos, and logos. |
mcp__penpot__penpot_api_info |
Retrieve Penpot API documentation and verify server connectivity. |
Procedure
- Confirm whether a design system or brand guidelines exist; prefer user tokens, colors, spacing, typography, and naming conventions over defaults.
- Inspect the current file with
mcp__penpot__execute_code, penpotUtils.shapeStructure(), and penpotUtils.findShapes() before creating new objects.
- Discover existing colors from
fills, text styles from fontSize and fontWeight, and components from penpot.library.local.components.
- Check existing boards before creating new boards; compute the rightmost edge and place the new board with a gap.
- Create or modify with
penpot.createBoard(), penpot.createRectangle(), penpot.createText(), insertChild(index, shape), shape.resize(w, h), and penpotUtils.setParentXY(shape, x, y).
- Apply responsive containers with
addFlexLayout() and validate child order when dir="column" or dir="row".
- Validate visually with
mcp__penpot__export_shape, inspect bounds and hierarchy with penpotUtils.analyzeDescendants(), isContainedIn(), and penpotUtils.shapeStructure(), then export CSS with penpot.generateStyle(selection, { type: 'css', includeChildren: true }) when requested.
Design system handling
| Situation |
Action |
| User has a design system |
Use specified colors, spacing, typography, component patterns, and naming conventions. |
| Current Penpot file has patterns |
Discover and reuse existing colors, text styles, and components before adding defaults. |
| No design system exists |
Use the default tokens below and offer to establish consistent patterns. |
| Components need details |
Read references/component-patterns.md for buttons, forms, and navigation specs. |
const allShapes = penpotUtils.findShapes(() => true, penpot.root);
const colors = new Set();
allShapes.forEach(s => { if (s.fills) s.fills.forEach(f => colors.add(f.fillColor)); });
const textStyles = allShapes.filter(s => s.type === 'text').map(s => ({ fontSize: s.fontSize, fontWeight: s.fontWeight }));
const components = penpot.library.local.components;
return { colors: [...colors], textStyles, componentCount: components.length };
Layout and board rules
| Rule |
Value |
| Related screen gap |
100px between boards in the same flow. |
| Different flow gap |
200px+ between sections or flows. |
| Board alignment |
Align boards vertically with the same y and order flows horizontally. |
| Mobile screen |
375×812, status bar 44px, header/nav 56px, content padding 16px, bottom nav/CTA 84px. |
| Desktop dashboard |
1440×900, sidebar 240px, header 64px, page title/actions row, content grid. |
const boards = penpotUtils.findShapes(s => s.type === 'board', penpot.root);
let nextX = 0;
const gap = 100;
boards.forEach(b => { const rightEdge = b.x + b.width; if (rightEdge + gap > nextX) nextX = rightEdge + gap; });
const newBoard = penpot.createBoard();
newBoard.x = nextX;
newBoard.y = 0;
newBoard.resize(375, 812);
┌─────────────────────────────┐
│ Status Bar (44px) │
├─────────────────────────────┤
│ Header/Nav (56px) │
├─────────────────────────────┤
│ Content Area │
│ Padding: 16px horizontal │
├─────────────────────────────┤
│ Bottom Nav/CTA (84px) │
└─────────────────────────────┘
┌──────┬──────────────────────────────────┐
│ │ Header (64px) │
│ Side │──────────────────────────────────│
│ bar │ Page Title + Actions │
│ 240 │──────────────────────────────────│
│ px │ Content Grid │
└──────┴──────────────────────────────────┘
Default tokens
Use these only when user tokens are absent.
| Category |
Token or level |
Value |
Usage |
| Spacing |
spacing-xs |
4px |
Tight inline elements. |
| Spacing |
spacing-sm |
8px |
Related elements. |
| Spacing |
spacing-md |
16px |
Default padding. |
| Spacing |
spacing-lg |
24px |
Section spacing. |
| Spacing |
spacing-xl |
32px |
Major sections. |
| Spacing |
spacing-2xl |
48px |
Page-level spacing. |
| Typography |
Display |
48-64px, Bold |
Hero headlines. |
| Typography |
H1/H2/H3 |
32-40px, 24-28px, 20-22px |
Page titles and sections. |
| Typography |
Body/Small/Caption |
16px, 14px, 12px |
Main content, secondary text, labels, hints. |
| Color |
Success/Warning/Error |
#22C55E, #F59E0B, #EF4444 ranges |
Confirmations, caution, errors. |
| Color |
Primary/Secondary/Neutral |
Brand, supporting actions, gray scale |
CTAs, secondary actions, text and borders. |
Component and accessibility checks
| Area |
Checks |
| Buttons |
Clear action-oriented label of 2-3 words; minimum touch target 44×44px; states for default, hover, active, disabled, loading; contrast 3:1; consistent border radius. |
| Forms |
Labels above inputs, not just placeholders; required indicators; adjacent error messages; logical tab order; input types such as email and tel match content. |
| Navigation |
Current location indicated; consistent position; maximum 7±2 top-level items; mobile target size 48px. |
| Accessibility |
Text contrast 4.5:1; large text 3:1; touch targets 44×44px; visible focus states; alt text; H1→H2→H3 hierarchy; never rely solely on color. |
| Review |
Visual hierarchy, spacing, alignment, readable 16px+ body text, obvious interactive elements, loading/empty/error states, and design-system consistency. |
Penpot gotchas
- Do not assign
width or height directly: they are READ-ONLY; use shape.resize(w, h).
- Do not assign
parentX or parentY directly: they are READ-ONLY; use penpotUtils.setParentXY(shape, x, y).
- Use
insertChild(index, shape) for z-ordering: do not rely on appendChild.
- Flex child order is reversed for
dir="column" or dir="row"; validate after applying addFlexLayout().
- Reset text growth after
text.resize() to growType values "auto-width" or "auto-height".
Troubleshooting
| Issue |
Solution |
| Plugin won't connect |
Check servers are running with npm run start:all in the penpot-mcp directory. |
| Browser blocks localhost |
Allow local network access, disable Brave Shield, or try Firefox. |
| Tools not appearing in client |
Restart VS Code or Claude completely after config changes. |
| Tool execution fails or times out |
Ensure the Penpot plugin UI is open and shows "Connected". |
| "WebSocket connection failed" |
Check firewall allows ports 4400, 4401, and 4402. |
Progressive disclosure and bundled resources
Read bundled references only when needed:
references/setup-troubleshooting.md: installation, server startup, and connection troubleshooting.
references/component-patterns.md: detailed button, form, navigation, and component specs.
references/accessibility.md: contrast, keyboard, target size, and WCAG-oriented checks.
references/platform-guidelines.md: screen sizes and iOS, Android, Material Design guidance.
Preservation notes
Keep these original operational phrases because they map to real Penpot workflow checks: user-centered design, mobile-first design, existing tokens/specs, Create/modify**, Create/modify, create/modify, Color/Contrast**, Loading/empty/error states, text/borders, sections/flows, and the flex-order warning REVERSED, and the literal export connector via. Client setup may involve settings.json and restarting VS Code/Claude; tool execution fails/times out when the plugin UI is not connected.
Output template
## Penpot design result - <screen or flow>
**Status:** created | improved | reviewed | blocked
**Target:** web | mobile | desktop | dashboard | form | landing page | design system
**Design system:** reused | discovered | default tokens
| Area | Decision | Evidence | Follow-up |
| --- | --- | --- | --- |
| Layout | <board size, grid, spacing> | <Penpot shape or export evidence> | <next step> |
| Components | <buttons/forms/nav/cards> | <states and patterns> | <next step> |
| Accessibility | <contrast/touch/focus/hierarchy> | <check result> | <fix> |
| Validation | <export/API check> | <file or shape exported> | <remaining issue> |
### MCP actions
- `mcp__penpot__execute_code`: <summary>
- `mcp__penpot__export_shape`: <summary or not needed>
Quality gate
1---2name: penpot-uiux-design-33description: Create, review, and improve professional UI/UX designs in Penpot using penpot/penpot-mcp tools, design systems, component patterns, accessibility checks, and platform guidelines. Use when asked to design a UI, create interface, build layout, design dashboard, create form, design landing page, make it accessible, design system, component library, or improve an existing Penpot file.4---56<!-- Generated from harness/github-copilot/plugins/ux-design-tooling/skills/penpot-uiux-design/SKILL.md by harness/claude-code/scripts/convert_from_copilot.py. Edit the source, not this file. -->78# Penpot UI/UX design910Create or refine Penpot designs by combining MCP tool execution with UI/UX principles, design-system discovery, accessibility checks, component specs, layout rules, and visual validation.1112## When to invoke1314- "Design a UI for this app in Penpot."15- "Create a dashboard layout and component library."16- "Make this Penpot design accessible."17- "Build a mobile form and navigation flow."18- "Review this landing page for usability."1920## Prerequisites and context2122- Use the `penpot/penpot-mcp` MCP server when Penpot tools are available.23- Check whether `mcp__penpot__penpot_api_info` succeeds before giving setup instructions. If it succeeds, the server is running and connected.24- If the tool fails, ask whether the Penpot MCP server is already installed and running; only guide installation when the user confirms it is not installed.25- Installation path: clone https://github.com/penpot/penpot-mcp.git and run `npm install`, then `npm run bootstrap`.26- In Penpot, open a design file, choose Plugins → Load plugin from URL, enter `http://localhost:4400/manifest.json`, then click "Connect to MCP server" in the plugin UI.27- VS Code MCP configuration uses `http://localhost:4401/sse` under `mcp.servers.penpot.url`.2829## MCP tool map3031| Tool | Use it for |32| --- | --- |33| `mcp__penpot__execute_code` | Run JavaScript in the Penpot plugin context to create, inspect, and modify designs. |34| `mcp__penpot__export_shape` | Export shapes as PNG/SVG for visual inspection. |35| `mcp__penpot__import_image` | Import images, icons, photos, and logos. |36| `mcp__penpot__penpot_api_info` | Retrieve Penpot API documentation and verify server connectivity. |3738## Procedure39401. Confirm whether a design system or brand guidelines exist; prefer user tokens, colors, spacing, typography, and naming conventions over defaults.412. Inspect the current file with `mcp__penpot__execute_code`, `penpotUtils.shapeStructure()`, and `penpotUtils.findShapes()` before creating new objects.423. Discover existing colors from `fills`, text styles from `fontSize` and `fontWeight`, and components from `penpot.library.local.components`.434. Check existing boards before creating new boards; compute the rightmost edge and place the new board with a gap.445. Create or modify with `penpot.createBoard()`, `penpot.createRectangle()`, `penpot.createText()`, `insertChild(index, shape)`, `shape.resize(w, h)`, and `penpotUtils.setParentXY(shape, x, y)`.456. Apply responsive containers with `addFlexLayout()` and validate child order when `dir="column"` or `dir="row"`.467. Validate visually with `mcp__penpot__export_shape`, inspect bounds and hierarchy with `penpotUtils.analyzeDescendants()`, `isContainedIn()`, and `penpotUtils.shapeStructure()`, then export CSS with `penpot.generateStyle(selection, { type: 'css', includeChildren: true })` when requested.4748## Design system handling4950| Situation | Action |51| --- | --- |52| User has a design system | Use specified colors, spacing, typography, component patterns, and naming conventions. |53| Current Penpot file has patterns | Discover and reuse existing colors, text styles, and components before adding defaults. |54| No design system exists | Use the default tokens below and offer to establish consistent patterns. |55| Components need details | Read `references/component-patterns.md` for buttons, forms, and navigation specs. |5657```javascript58const allShapes = penpotUtils.findShapes(() => true, penpot.root);59const colors = new Set();60allShapes.forEach(s => { if (s.fills) s.fills.forEach(f => colors.add(f.fillColor)); });61const textStyles = allShapes.filter(s => s.type === 'text').map(s => ({ fontSize: s.fontSize, fontWeight: s.fontWeight }));62const components = penpot.library.local.components;63return { colors: [...colors], textStyles, componentCount: components.length };64```6566## Layout and board rules6768| Rule | Value |69| --- | --- |70| Related screen gap | `100px` between boards in the same flow. |71| Different flow gap | `200px+` between sections or flows. |72| Board alignment | Align boards vertically with the same `y` and order flows horizontally. |73| Mobile screen | `375×812`, status bar `44px`, header/nav `56px`, content padding `16px`, bottom nav/CTA `84px`. |74| Desktop dashboard | `1440×900`, sidebar `240px`, header `64px`, page title/actions row, content grid. |7576```javascript77const boards = penpotUtils.findShapes(s => s.type === 'board', penpot.root);78let nextX = 0;79const gap = 100;80boards.forEach(b => { const rightEdge = b.x + b.width; if (rightEdge + gap > nextX) nextX = rightEdge + gap; });81const newBoard = penpot.createBoard();82newBoard.x = nextX;83newBoard.y = 0;84newBoard.resize(375, 812);85```8687```text88┌─────────────────────────────┐89│ Status Bar (44px) │90├─────────────────────────────┤91│ Header/Nav (56px) │92├─────────────────────────────┤93│ Content Area │94│ Padding: 16px horizontal │95├─────────────────────────────┤96│ Bottom Nav/CTA (84px) │97└─────────────────────────────┘98```99100```text101┌──────┬──────────────────────────────────┐102│ │ Header (64px) │103│ Side │──────────────────────────────────│104│ bar │ Page Title + Actions │105│ 240 │──────────────────────────────────│106│ px │ Content Grid │107└──────┴──────────────────────────────────┘108```109110## Default tokens111112Use these only when user tokens are absent.113114| Category | Token or level | Value | Usage |115| --- | --- | --- | --- |116| Spacing | `spacing-xs` | `4px` | Tight inline elements. |117| Spacing | `spacing-sm` | `8px` | Related elements. |118| Spacing | `spacing-md` | `16px` | Default padding. |119| Spacing | `spacing-lg` | `24px` | Section spacing. |120| Spacing | `spacing-xl` | `32px` | Major sections. |121| Spacing | `spacing-2xl` | `48px` | Page-level spacing. |122| Typography | Display | `48-64px`, Bold | Hero headlines. |123| Typography | H1/H2/H3 | `32-40px`, `24-28px`, `20-22px` | Page titles and sections. |124| Typography | Body/Small/Caption | `16px`, `14px`, `12px` | Main content, secondary text, labels, hints. |125| Color | Success/Warning/Error | `#22C55E`, `#F59E0B`, `#EF4444` ranges | Confirmations, caution, errors. |126| Color | Primary/Secondary/Neutral | Brand, supporting actions, gray scale | CTAs, secondary actions, text and borders. |127128## Component and accessibility checks129130| Area | Checks |131| --- | --- |132| Buttons | Clear action-oriented label of 2-3 words; minimum touch target `44×44px`; states for default, hover, active, disabled, loading; contrast `3:1`; consistent border radius. |133| Forms | Labels above inputs, not just placeholders; required indicators; adjacent error messages; logical tab order; input types such as email and tel match content. |134| Navigation | Current location indicated; consistent position; maximum `7±2` top-level items; mobile target size `48px`. |135| Accessibility | Text contrast `4.5:1`; large text `3:1`; touch targets `44×44px`; visible focus states; alt text; H1→H2→H3 hierarchy; never rely solely on color. |136| Review | Visual hierarchy, spacing, alignment, readable `16px+` body text, obvious interactive elements, loading/empty/error states, and design-system consistency. |137138## Penpot gotchas139140- **Do not assign `width` or `height` directly**: they are READ-ONLY; use `shape.resize(w, h)`.141- **Do not assign `parentX` or `parentY` directly**: they are READ-ONLY; use `penpotUtils.setParentXY(shape, x, y)`.142- **Use `insertChild(index, shape)` for z-ordering**: do not rely on `appendChild`.143- **Flex child order is reversed** for `dir="column"` or `dir="row"`; validate after applying `addFlexLayout()`.144- **Reset text growth after `text.resize()`** to `growType` values `"auto-width"` or `"auto-height"`.145146## Troubleshooting147148| Issue | Solution |149| --- | --- |150| Plugin won't connect | Check servers are running with `npm run start:all` in the `penpot-mcp` directory. |151| Browser blocks localhost | Allow local network access, disable Brave Shield, or try Firefox. |152| Tools not appearing in client | Restart VS Code or Claude completely after config changes. |153| Tool execution fails or times out | Ensure the Penpot plugin UI is open and shows "Connected". |154| "WebSocket connection failed" | Check firewall allows ports `4400`, `4401`, and `4402`. |155156## Progressive disclosure and bundled resources157158Read bundled references only when needed:159160- `references/setup-troubleshooting.md`: installation, server startup, and connection troubleshooting.161- `references/component-patterns.md`: detailed button, form, navigation, and component specs.162- `references/accessibility.md`: contrast, keyboard, target size, and WCAG-oriented checks.163- `references/platform-guidelines.md`: screen sizes and iOS, Android, Material Design guidance.164165## Preservation notes166167Keep these original operational phrases because they map to real Penpot workflow checks: user-centered design, mobile-first design, existing tokens/specs, `Create/modify**`, Create/modify, create/modify, Color/Contrast**, Loading/empty/error states, text/borders, sections/flows, and the flex-order warning REVERSED, and the literal export connector ` via `. Client setup may involve `settings.json` and restarting VS Code/Claude; tool execution fails/times out when the plugin UI is not connected.168169## Output template170171```markdown172## Penpot design result - <screen or flow>173174**Status:** created | improved | reviewed | blocked175**Target:** web | mobile | desktop | dashboard | form | landing page | design system176**Design system:** reused | discovered | default tokens177178| Area | Decision | Evidence | Follow-up |179| --- | --- | --- | --- |180| Layout | <board size, grid, spacing> | <Penpot shape or export evidence> | <next step> |181| Components | <buttons/forms/nav/cards> | <states and patterns> | <next step> |182| Accessibility | <contrast/touch/focus/hierarchy> | <check result> | <fix> |183| Validation | <export/API check> | <file or shape exported> | <remaining issue> |184185### MCP actions186- `mcp__penpot__execute_code`: <summary>187- `mcp__penpot__export_shape`: <summary or not needed>188```189190## Quality gate191192- [ ] Existing design system, components, colors, and text styles were checked before defaults were used.193- [ ] New boards avoid overlap and follow `100px` or `200px+` spacing rules.194- [ ] Layout uses responsive containers or explicit grid logic appropriate to the screen.195- [ ] Buttons, forms, navigation, typography, and accessibility checks match the tables above.196- [ ] Penpot READ-ONLY properties were not assigned directly.197- [ ] The design was visually validated through export or a documented blocker.