| name | penpot-design |
| description | Design and manipulate Penpot projects using the Penpot MCP Plugin. Use when working with Penpot designs including creating shapes, boards, layouts, styling, components, generating CSS/HTML from designs, or any design task when Penpot MCP is connected. Triggers on mentions of "Penpot", design manipulation requests with connected MCP, or design-to-code workflows. |
| license | MIT |
| metadata | {"author":"iperez","version":"1.0.0"} |
Penpot Design Skill
Create, edit, and manipulate designs in Penpot using the connected MCP plugin.
Prerequisites
User must have Penpot MCP Plugin connected to their Penpot project.
Available Tools
| Tool | Purpose |
|---|
execute_code | Run JavaScript in Penpot plugin context |
penpot_api_info | Get API docs for types/members |
export_shape | Export shapes as PNG/SVG for inspection |
Core Objects
penpot
penpotUtils
storage
Critical Rules
1. Child Ordering is REVERSED in Flex Layout
For dir="column" or dir="row", the children array order is reversed relative to visual order. First in array = visually last.
2. Use insertChild, NOT appendChild
parent.insertChild(parent.children.length, shape);
parent.appendChild(shape);
Exception: For flex layout boards, use board.appendChild(shape) which inserts at the visual end.
3. Position Properties
shape.x = 100;
shape.y = 200;
shape.parentX;
shape.parentY;
penpotUtils.setParentXY(shape, relativeX, relativeY);
4. Resize and Dimensions
shape.width;
shape.height;
shape.resize(200, 100);
5. Text Sizing
text.fontSize = '24';
text.resize(200, 100);
text.growType = 'auto-width';
6. Store Selection Immediately
storage.selection = [...penpot.selection];
Workflow
1. Explore Design Structure
return penpotUtils.shapeStructure(penpot.root, 3);
storage.selection = [...penpot.selection];
return storage.selection.map(s => ({ id: s.id, name: s.name, type: s.type }));
2. Find Elements
const shape = penpotUtils.findShape(s => s.name === 'Button');
const texts = penpotUtils.findShapes(s => s.type === 'text', penpot.root);
const images = penpotUtils.findShapes(
s => s.type === 'image' || s.fills?.some(f => f.fillImage),
penpot.root
);
const boards = penpotUtils.findShapes(s => s.type === 'board', penpot.root);
3. Create Shapes
const rect = penpot.createRectangle();
rect.name = 'Card Background';
rect.x = 100; rect.y = 100;
rect.resize(300, 200);
rect.fills = [{ fillColor: '#FFFFFF' }];
rect.borderRadius = 12;
const text = penpot.createText('Hello World');
text.x = 120; text.y = 120;
text.fontSize = '24';
text.fontFamily = 'Inter';
text.growType = 'auto-width';
const board = penpot.createBoard();
board.name = 'Card';
board.x = 0; board.y = 0;
board.resize(400, 300);
board.fills = [{ fillColor: '#FFFFFF' }];
const ellipse = penpot.createEllipse();
ellipse.resize(100, 100);
const path = penpot.createPath();
4. Build Hierarchy
CRITICAL: Add background shapes FIRST, then foreground shapes. Z-order = array order.
const card = penpot.createBoard();
card.resize(300, 200);
const bg = penpot.createRectangle();
bg.resize(300, 200);
bg.fills = [{ fillColor: '#F5F5F5' }];
card.insertChild(card.children.length, bg);
const title = penpot.createText('Title');
title.fontSize = '20';
card.insertChild(card.children.length, title);
penpotUtils.setParentXY(bg, 0, 0);
penpotUtils.setParentXY(title, 20, 20);
5. Flex Layout
const container = penpot.createBoard();
container.resize(400, 0);
const flex = penpotUtils.addFlexLayout(container, 'column');
flex.rowGap = 16;
flex.columnGap = 16;
flex.topPadding = 24;
flex.rightPadding = 24;
flex.bottomPadding = 24;
flex.leftPadding = 24;
flex.alignItems = 'stretch';
flex.justifyContent = 'start';
container.appendChild(item1);
container.appendChild(item2);
item1.layoutChild.horizontalSizing = 'fill';
item1.layoutChild.verticalSizing = 'auto';
Flex Layout Properties:
dir: 'row' | 'column' | 'row-reverse' | 'column-reverse'
alignItems: 'start' | 'center' | 'end' | 'stretch'
justifyContent: 'start' | 'center' | 'end' | 'stretch' | 'space-between' | 'space-around' | 'space-evenly'
rowGap, columnGap: number
topPadding, rightPadding, bottomPadding, leftPadding: number
6. Styling
Fills:
shape.fills = [{ fillColor: '#3B82F6', fillOpacity: 1 }];
shape.fills = [{
fillColorGradient: {
type: 'linear',
startX: 0, startY: 0,
endX: 1, endY: 1,
width: 1,
stops: [
{ color: '#3B82F6', offset: 0 },
{ color: '#8B5CF6', offset: 1 }
]
}
}];
Strokes:
shape.strokes = [{
strokeColor: '#E5E7EB',
strokeWidth: 1,
strokeAlignment: 'center',
strokeStyle: 'solid'
}];
Shadows:
shape.shadows = [{
style: 'drop-shadow',
color: { color: '#000000', opacity: 0.1 },
offsetX: 0,
offsetY: 4,
blur: 12,
spread: 0
}];
Border Radius:
shape.borderRadius = 8;
shape.borderRadiusTopLeft = 8;
shape.borderRadiusTopRight = 8;
shape.borderRadiusBottomRight = 0;
shape.borderRadiusBottomLeft = 0;
Opacity & Blend:
shape.opacity = 0.8;
shape.blendMode = 'multiply';
7. Text Styling
const text = penpot.createText('Hello');
text.fontSize = '16';
text.fontFamily = 'Inter';
text.fontWeight = '600';
text.fontStyle = 'normal';
text.lineHeight = '1.5';
text.letterSpacing = '0';
text.align = 'center';
text.verticalAlign = 'center';
text.textTransform = 'uppercase';
text.textDecoration = 'underline';
text.direction = 'ltr';
text.growType = 'auto-width';
text.fills = [{ fillColor: '#1F2937' }];
8. Z-Order Methods
shape.bringToFront();
shape.sendToBack();
shape.bringForward();
shape.sendBackward();
shape.setParentIndex(0);
Design-to-Code
Generate CSS
return penpot.generateStyle(penpot.selection, {
type: 'css',
withPrelude: true,
includeChildren: true
});
Generate HTML/SVG
return penpot.generateMarkup(penpot.selection, { type: 'html' });
return penpot.generateMarkup(penpot.selection, { type: 'svg' });
Design-to-Code Workflow
- Select target element(s) in Penpot
- Use
export_shape to visually verify
- Generate CSS with
generateStyle
- Generate markup with
generateMarkup
- Combine into working code
CRITICAL: Never assume values. Strictly adhere to the design. Use black/white defaults only when information is genuinely missing.
Components & Libraries
const local = penpot.library.local;
const connected = penpot.library.connected;
const btn = local.components.find(c => c.name.includes('Button'));
const instance = btn.instance();
instance.x = 100;
instance.y = 100;
const primary = local.colors.find(c => c.name === 'Primary');
const heading = local.typographies.find(t => t.name === 'Heading');
const newColor = local.createColor();
newColor.name = 'Brand Blue';
newColor.color = '#3B82F6';
const newTypo = local.createTypography();
newTypo.name = 'Body';
newTypo.fontSize = '16';
newTypo.fontFamily = 'Inter';
Visual Inspection
Always verify designs visually:
Common Patterns
See references/patterns.md for:
- Card components
- Button variants
- Navigation bars
- Form fields
- Grid layouts
- Modal dialogs
API Quick Reference
See references/api-quick-ref.md for:
- All shape types and properties
- Layout system details
- Complete styling reference
- Library management
Shape Types
| Type | Description |
|---|
Board | Container/frame, supports layouts |
Rectangle | Basic rectangle shape |
Ellipse | Circle/ellipse shape |
Text | Text element |
Path | Vector path |
Group | Non-layout container |
Boolean | Boolean operations result |
Image | Image element (legacy) |
SvgRaw | Raw SVG content |