Installation

Download and extract to your repository:

.github/skills/penpot-uiux-design/

Extract the ZIP to .github/skills/ in your repo. The folder name must match penpot-uiux-design for Copilot to auto-discover it.

Skill Files (5)

SKILL.md 11.8 KB
---
name: penpot-uiux-design
description: 'Comprehensive guide for creating professional UI/UX designs in Penpot using MCP tools. Use this skill when: (1) Creating new UI/UX designs for web, mobile, or desktop applications, (2) Building design systems with components and tokens, (3) Designing dashboards, forms, navigation, or landing pages, (4) Applying accessibility standards and best practices, (5) Following platform guidelines (iOS, Android, Material Design), (6) Reviewing or improving existing Penpot designs for usability. Triggers: "design a UI", "create interface", "build layout", "design dashboard", "create form", "design landing page", "make it accessible", "design system", "component library".'
---

# Penpot UI/UX Design Guide

Create professional, user-centered designs in Penpot using the `penpot/penpot-mcp` MCP server and proven UI/UX principles.

## Available MCP Tools

| Tool | Purpose |
| ---- | ------- |
| `mcp__penpot__execute_code` | Run JavaScript in Penpot plugin context to create/modify designs |
| `mcp__penpot__export_shape` | Export shapes as PNG/SVG for visual inspection |
| `mcp__penpot__import_image` | Import images (icons, photos, logos) into designs |
| `mcp__penpot__penpot_api_info` | Retrieve Penpot API documentation |

## MCP Server Setup

The Penpot MCP tools require the `penpot/penpot-mcp` server running locally. For detailed installation and troubleshooting, see [setup-troubleshooting.md](references/setup-troubleshooting.md).

### Before Setup: Check If Already Running

**Always check if the MCP server is already available before attempting setup:**

1. **Try calling a tool first**: Attempt `mcp__penpot__penpot_api_info` - if it succeeds, the server is running and connected. No setup needed.

2. **If the tool fails**, ask the user:
   > "The Penpot MCP server doesn't appear to be connected. Is the server already installed and running? If so, I can help troubleshoot. If not, I can guide you through the setup."

3. **Only proceed with setup instructions if the user confirms the server is not installed.**

### Quick Start (Only If Not Installed)

```bash
# Clone and install
git clone https://github.com/penpot/penpot-mcp.git
cd penpot-mcp
npm install

# Build and start servers
npm run bootstrap
```

Then in Penpot:
1. Open a design file
2. Go to **Plugins** → **Load plugin from URL**
3. Enter: `http://localhost:4400/manifest.json`
4. Click **"Connect to MCP server"** in the plugin UI

### VS Code Configuration

Add to `settings.json`:
```json
{
  "mcp": {
    "servers": {
      "penpot": {
        "url": "http://localhost:4401/sse"
      }
    }
  }
}
```

### Troubleshooting (If Server Is Installed But Not Working)

| Issue | Solution |
| ----- | -------- |
| Plugin won't connect | Check servers are running (`npm run start:all` in penpot-mcp dir) |
| Browser blocks localhost | Allow local network access prompt, or disable Brave Shield, or try Firefox |
| Tools not appearing in client | Restart VS Code/Claude completely after config changes |
| Tool execution fails/times out | Ensure Penpot plugin UI is open and shows "Connected" |
| "WebSocket connection failed" | Check firewall allows ports 4400, 4401, 4402 |

## Quick Reference

| Task | Reference File |
| ---- | -------------- |
| MCP server installation & troubleshooting | [setup-troubleshooting.md](references/setup-troubleshooting.md) |
| Component specs (buttons, forms, nav) | [component-patterns.md](references/component-patterns.md) |
| Accessibility (contrast, touch targets) | [accessibility.md](references/accessibility.md) |
| Screen sizes & platform specs | [platform-guidelines.md](references/platform-guidelines.md) |

## Core Design Principles

### The Golden Rules

1. **Clarity over cleverness**: Every element must have a purpose
2. **Consistency builds trust**: Reuse patterns, colors, and components
3. **User goals first**: Design for tasks, not features
4. **Accessibility is not optional**: Design for everyone
5. **Test with real users**: Validate assumptions early

### Visual Hierarchy (Priority Order)

1. **Size**: Larger = more important
2. **Color/Contrast**: High contrast draws attention
3. **Position**: Top-left (LTR) gets seen first
4. **Whitespace**: Isolation emphasizes importance
5. **Typography weight**: Bold stands out

## Design Workflow

1. **Check for design system first**: Ask user if they have existing tokens/specs, or discover from current Penpot file
2. **Understand the page**: Call `mcp__penpot__execute_code` with `penpotUtils.shapeStructure()` to see hierarchy
3. **Find elements**: Use `penpotUtils.findShapes()` to locate elements by type or name
4. **Create/modify**: Use `penpot.createBoard()`, `penpot.createRectangle()`, `penpot.createText()` etc.
5. **Apply layout**: Use `addFlexLayout()` for responsive containers
6. **Validate**: Call `mcp__penpot__export_shape` to visually check your work

## Design System Handling

**Before creating designs, determine if the user has an existing design system:**

1. **Ask the user**: "Do you have a design system or brand guidelines to follow?"
2. **Discover from Penpot**: Check for existing components, colors, and patterns

```javascript
// Discover existing design patterns in current file
const allShapes = penpotUtils.findShapes(() => true, penpot.root);

// Find existing colors in use
const colors = new Set();
allShapes.forEach(s => {
  if (s.fills) s.fills.forEach(f => colors.add(f.fillColor));
});

// Find existing text styles (font sizes, weights)
const textStyles = allShapes
  .filter(s => s.type === 'text')
  .map(s => ({ fontSize: s.fontSize, fontWeight: s.fontWeight }));

// Find existing components
const components = penpot.library.local.components;

return { colors: [...colors], textStyles, componentCount: components.length };
```

**If user HAS a design system:**

- Use their specified colors, spacing, typography
- Match their existing component patterns
- Follow their naming conventions

**If user has NO design system:**

- Use the default tokens below as a starting point
- Offer to help establish consistent patterns
- Reference specs in [component-patterns.md](references/component-patterns.md)

## Key Penpot API Gotchas

- `width`/`height` are READ-ONLY → use `shape.resize(w, h)`
- `parentX`/`parentY` are READ-ONLY → use `penpotUtils.setParentXY(shape, x, y)`
- Use `insertChild(index, shape)` for z-ordering (not `appendChild`)
- Flex children array order is REVERSED for `dir="column"` or `dir="row"`
- After `text.resize()`, reset `growType` to `"auto-width"` or `"auto-height"`

## Positioning New Boards

**Always check existing boards before creating new ones** to avoid overlap:

```javascript
// Find all existing boards and calculate next position
const boards = penpotUtils.findShapes(s => s.type === 'board', penpot.root);
let nextX = 0;
const gap = 100; // Space between boards

if (boards.length > 0) {
  // Find rightmost board edge
  boards.forEach(b => {
    const rightEdge = b.x + b.width;
    if (rightEdge + gap > nextX) {
      nextX = rightEdge + gap;
    }
  });
}

// Create new board at calculated position
const newBoard = penpot.createBoard();
newBoard.x = nextX;
newBoard.y = 0;
newBoard.resize(375, 812);
```

**Board spacing guidelines:**

- Use 100px gap between related screens (same flow)
- Use 200px+ gap between different sections/flows
- Align boards vertically (same y) for visual organization
- Group related screens horizontally in user flow order

## Default Design Tokens

**Use these defaults only when user has no design system. Always prefer user's tokens if available.**

### Spacing Scale (8px base)

| Token | Value | Usage |
| ----- | ----- | ----- |
| `spacing-xs` | 4px | Tight inline elements |
| `spacing-sm` | 8px | Related elements |
| `spacing-md` | 16px | Default padding |
| `spacing-lg` | 24px | Section spacing |
| `spacing-xl` | 32px | Major sections |
| `spacing-2xl` | 48px | Page-level spacing |

### Typography Scale

| Level | Size | Weight | Usage |
| ----- | ---- | ------ | ----- |
| Display | 48-64px | Bold | Hero headlines |
| H1 | 32-40px | Bold | Page titles |
| H2 | 24-28px | Semibold | Section headers |
| H3 | 20-22px | Semibold | Subsections |
| Body | 16px | Regular | Main content |
| Small | 14px | Regular | Secondary text |
| Caption | 12px | Regular | Labels, hints |

### Color Usage

| Purpose | Recommendation |
| ------- | -------------- |
| Primary | Main brand color, CTAs |
| Secondary | Supporting actions |
| Success | #22C55E range (confirmations) |
| Warning | #F59E0B range (caution) |
| Error | #EF4444 range (errors) |
| Neutral | Gray scale for text/borders |

## Common Layouts

### Mobile Screen (375×812)

```text
┌─────────────────────────────┐
│ Status Bar (44px)           │
├─────────────────────────────┤
│ Header/Nav (56px)           │
├─────────────────────────────┤
│                             │
│ Content Area                │
│ (Scrollable)                │
│ Padding: 16px horizontal    │
│                             │
├─────────────────────────────┤
│ Bottom Nav/CTA (84px)       │
└─────────────────────────────┘

```

### Desktop Dashboard (1440×900)

```text
┌──────┬──────────────────────────────────┐
│      │ Header (64px)                    │
│ Side │──────────────────────────────────│
│ bar  │ Page Title + Actions             │
│      │──────────────────────────────────│
│ 240  │ Content Grid                     │
│ px   │ ┌─────┐ ┌─────┐ ┌─────┐ ┌─────┐ │
│      │ │Card │ │Card │ │Card │ │Card │ │
│      │ └─────┘ └─────┘ └─────┘ └─────┘ │
│      │                                  │
└──────┴──────────────────────────────────┘

```

## Component Checklist

### Buttons

- [ ] Clear, action-oriented label (2-3 words)
- [ ] Minimum touch target: 44×44px
- [ ] Visual states: default, hover, active, disabled, loading
- [ ] Sufficient contrast (3:1 against background)
- [ ] Consistent border radius across app

### Forms

- [ ] Labels above inputs (not just placeholders)
- [ ] Required field indicators
- [ ] Error messages adjacent to fields
- [ ] Logical tab order
- [ ] Input types match content (email, tel, etc.)

### Navigation

- [ ] Current location clearly indicated
- [ ] Consistent position across screens
- [ ] Maximum 7±2 top-level items
- [ ] Touch-friendly on mobile (48px targets)

## Accessibility Quick Checks

1. **Color contrast**: Text 4.5:1, Large text 3:1
2. **Touch targets**: Minimum 44×44px
3. **Focus states**: Visible keyboard focus indicators
4. **Alt text**: Meaningful descriptions for images
5. **Hierarchy**: Proper heading levels (H1→H2→H3)
6. **Color independence**: Never rely solely on color

## Design Review Checklist

Before finalizing any design:

- [ ] Visual hierarchy is clear
- [ ] Consistent spacing and alignment
- [ ] Typography is readable (16px+ body text)
- [ ] Color contrast meets WCAG AA
- [ ] Interactive elements are obvious
- [ ] Mobile-friendly touch targets
- [ ] Loading/empty/error states considered
- [ ] Consistent with design system

## Validating Designs

Use these validation approaches with `mcp__penpot__execute_code`:

| Check | Method |
| ----- | ------ |
| Elements outside bounds | `penpotUtils.analyzeDescendants()` with `isContainedIn()` |
| Text too small (<12px) | `penpotUtils.findShapes()` filtering by `fontSize` |
| Missing contrast | Call `mcp__penpot__export_shape` and visually inspect |
| Hierarchy structure | `penpotUtils.shapeStructure()` to review nesting |

### Export CSS

Use `penpot.generateStyle(selection, { type: 'css', includeChildren: true })` via `mcp__penpot__execute_code` to extract CSS from designs.

## Tips for Great Designs

1. **Start with content**: Real content reveals layout needs
2. **Design mobile-first**: Constraints breed creativity
3. **Use a grid**: 8px base grid keeps things aligned
4. **Limit colors**: 1 primary + 1 secondary + neutrals
5. **Limit fonts**: 1-2 typefaces maximum
6. **Embrace whitespace**: Breathing room improves comprehension
7. **Be consistent**: Same action = same appearance everywhere
8. **Provide feedback**: Every action needs a response
references/
accessibility.md 7.2 KB
# Accessibility Guidelines Reference (WCAG)

## Quick Compliance Checklist

### Level AA Requirements (Minimum Standard)

- [ ] Color contrast 4.5:1 for normal text
- [ ] Color contrast 3:1 for large text (18px+ or 14px bold)
- [ ] Touch targets minimum 44×44px
- [ ] All functionality available via keyboard
- [ ] Visible focus indicators
- [ ] No content flashes more than 3 times/second
- [ ] Page has descriptive title
- [ ] Link purpose clear from text
- [ ] Form inputs have labels
- [ ] Error messages are descriptive

---

## Color and Contrast

### Contrast Ratios

| Element | Minimum Ratio | Enhanced (AAA) |
| ------- | ------------- | -------------- |
| Body text | 4.5:1 | 7:1 |
| Large text (18px+) | 3:1 | 4.5:1 |
| UI components | 3:1 | - |
| Graphical objects | 3:1 | - |

### Color Independence

Never use color as the only means of conveying information:

```text
✗ Error fields shown only in red
✓ Error fields with red border + error icon + text message

✗ Required fields marked only with red asterisk
✓ Required fields labeled "(required)" or with icon + tooltip

✗ Status shown only by color dots
✓ Status with color + icon + label text

```

### Accessible Color Combinations

**Safe text colors on backgrounds:**

| Background | Text Color | Contrast |
| ---------- | ---------- | -------- |
| White (#FFFFFF) | Dark gray (#1F2937) | 15.5:1 ✓ |
| Light gray (#F3F4F6) | Dark gray (#374151) | 10.9:1 ✓ |
| Primary blue (#2563EB) | White (#FFFFFF) | 4.6:1 ✓ |
| Dark (#111827) | White (#FFFFFF) | 18.1:1 ✓ |

**Colors to avoid for text:**

- Yellow on white (insufficient contrast)
- Light gray on white
- Orange on white (marginal at best)

---

## Keyboard Navigation

### Requirements

1. **All interactive elements** must be reachable via Tab key
2. **Logical tab order** following visual layout
3. **No keyboard traps** (user can always Tab away)
4. **Focus visible** at all times during keyboard navigation
5. **Skip links** to bypass repetitive navigation

### Focus Indicators

```css
/* Example focus styles */
:focus {
  outline: 2px solid #2563EB;
  outline-offset: 2px;
}

:focus:not(:focus-visible) {
  outline: none; /* Hide for mouse users */
}

:focus-visible {
  outline: 2px solid #2563EB;
  outline-offset: 2px;
}

```

### Keyboard Shortcuts

| Key | Expected Behavior |
| --- | ----------------- |
| Tab | Move to next interactive element |
| Shift+Tab | Move to previous element |
| Enter | Activate button/link |
| Space | Activate button, toggle checkbox |
| Escape | Close modal/dropdown |
| Arrow keys | Navigate within components |

---

## Screen Reader Support

### Semantic HTML Elements

Use appropriate elements for their purpose:

| Purpose | Element | Not This |
| ------- | ------- | -------- |
| Navigation | `<nav>` | `<div class="nav">` |
| Main content | `<main>` | `<div id="main">` |
| Header | `<header>` | `<div class="header">` |
| Footer | `<footer>` | `<div class="footer">` |
| Button | `<button>` | `<div onclick>` |
| Link | `<a href>` | `<span onclick>` |

### Heading Hierarchy

```text
h1 - Page Title (one per page)
  h2 - Major Section
    h3 - Subsection
      h4 - Sub-subsection
    h3 - Another Subsection
  h2 - Another Major Section

```

**Never skip levels** (h1 → h3 without h2)

### Image Alt Text

```text
Decorative: alt="" (empty, not omitted)
Informative: alt="Description of what image shows"
Functional: alt="Action the image performs"
Complex: alt="Brief description" + detailed description nearby

```

**Alt text examples:**

```text
✓ alt="Bar chart showing sales growth from $10M to $15M in Q4"
✓ alt="Company logo"
✓ alt="" (for decorative background pattern)

✗ alt="image" or alt="photo"
✗ alt="img_12345.jpg"
✗ Missing alt attribute entirely

```

---

## Touch and Pointer

### Touch Target Sizes

| Platform | Minimum | Recommended |
| -------- | ------- | ----------- |
| WCAG 2.1 | 44×44px | 48×48px |
| iOS (Apple) | 44×44pt | - |
| Android | 48×48dp | - |

### Touch Target Spacing

- Minimum 8px between adjacent targets
- Prefer 16px+ for comfort
- Larger targets for primary actions

### Pointer Gestures

- Complex gestures must have single-pointer alternatives
- Drag operations need equivalent click actions
- Avoid hover-only functionality on touch devices

---

## Forms Accessibility

### Labels

Every input must have an associated label:

```text
<label for="email">Email Address</label>
<input type="email" id="email" name="email">

```

### Required Fields

```text
<!-- Announce to screen readers -->
<label for="name">
  Name <span aria-label="required">*</span>
</label>
<input type="text" id="name" required aria-required="true">

```

### Error Handling

```text
<label for="email">Email</label>
<input type="email" id="email" aria-invalid="true" aria-describedby="email-error">
<span id="email-error" role="alert">
  Please enter a valid email address
</span>

```

### Form Instructions

- Provide format hints before input
- Show password requirements before errors
- Group related fields with fieldset/legend

---

## Dynamic Content

### Live Regions

For content that updates dynamically:

```text
aria-live="polite" - Announce when convenient
aria-live="assertive" - Announce immediately (interrupts)
role="alert" - Urgent messages (like assertive)
role="status" - Status updates (like polite)

```

### Loading States

```text
<button aria-busy="true" aria-live="polite">
  <span class="spinner"></span>
  Loading...
</button>

```

### Modal Dialogs

- Focus moves into modal when opened
- Focus trapped within modal
- Escape key closes modal
- Focus returns to trigger element when closed

---

## Testing Accessibility

### Manual Testing Checklist

1. **Keyboard only:** Navigate entire page with Tab/Enter
2. **Screen reader:** Test with VoiceOver (Mac) or NVDA (Windows)
3. **Zoom 200%:** Content remains readable and usable
4. **High contrast:** Test with system high contrast mode
5. **No mouse:** Complete all tasks without pointing device

### Automated Tools

- axe DevTools (browser extension)
- WAVE (WebAIM browser extension)
- Lighthouse (Chrome DevTools)
- Color contrast checkers (WebAIM, Contrast Ratio)

### Common Issues to Check

- [ ] Missing or empty alt text
- [ ] Empty links or buttons
- [ ] Missing form labels
- [ ] Insufficient color contrast
- [ ] Missing language attribute
- [ ] Incorrect heading structure
- [ ] Missing skip navigation link
- [ ] Inaccessible custom widgets

---

## ARIA Quick Reference

### Roles

| Role | Purpose |
| ---- | ------- |
| `button` | Clickable button |
| `link` | Navigation link |
| `dialog` | Modal dialog |
| `alert` | Important message |
| `navigation` | Navigation region |
| `main` | Main content |
| `search` | Search functionality |
| `tab/tablist/tabpanel` | Tab interface |

### Properties

| Property | Purpose |
| -------- | ------- |
| `aria-label` | Accessible name |
| `aria-labelledby` | Reference to labeling element |
| `aria-describedby` | Reference to description |
| `aria-hidden` | Hide from assistive tech |
| `aria-expanded` | Expandable state |
| `aria-selected` | Selection state |
| `aria-disabled` | Disabled state |
| `aria-required` | Required field |
| `aria-invalid` | Invalid input |

### Golden Rule

**First rule of ARIA:** Don't use ARIA if native HTML works.

```text
✗ <div role="button" tabindex="0">Click</div>
✓ <button>Click</button>

```
component-patterns.md 8.9 KB
# UI Component Patterns Reference

## Buttons

### Button Types

| Type | Purpose | Visual Treatment |
| ---- | ------- | ---------------- |
| Primary | Main action on page | Solid fill, brand color |
| Secondary | Supporting actions | Outline or muted fill |
| Tertiary | Low-emphasis actions | Text-only, underline optional |
| Destructive | Delete/remove actions | Red color, confirmation required |
| Ghost | Minimal UI, icon buttons | Transparent, subtle hover |

### Button States

```text
Default    → Resting state, clearly interactive
Hover      → Cursor over (desktop): darken 10%, subtle shadow
Active     → Being pressed: darken 20%, slight scale down
Focus      → Keyboard selected: visible outline ring
Disabled   → Not available: 50% opacity, cursor: not-allowed
Loading    → Processing: spinner replaces or accompanies label

```

### Button Specifications

- **Minimum size:** 44×44px (touch target)
- **Padding:** 12-16px horizontal, 8-12px vertical
- **Border radius:** 4-8px (consistent across app)
- **Font weight:** Medium or Semibold (600-700)
- **Text:** Sentence case, 2-4 words max

### Button Label Patterns

```text
✓ Save Changes        ✗ Submit
✓ Add to Cart         ✗ Click Here
✓ Create Account      ✗ OK
✓ Download PDF        ✗ Go
✓ Start Free Trial    ✗ Continue

```

---

## Forms

### Form Layout Guidelines

- **Single column preferred:** Reduces cognitive load
- **Top-aligned labels:** Fastest completion times
- **Logical grouping:** Related fields together
- **Smart defaults:** Pre-fill when possible

### Input Field Anatomy

```text
┌─ Label (required) ─────────────────────────┐
│                                            │
│  ┌────────────────────────────────────┐   │
│  │ Placeholder text...                 │   │
│  └────────────────────────────────────┘   │
│  Helper text or error message              │
└────────────────────────────────────────────┘

```

### Input States

| State | Border | Background | Additional |
| ----- | ------ | ---------- | ---------- |
| Default | Gray (#D1D5DB) | White | - |
| Focus | Primary color | White | Shadow/glow |
| Filled | Gray | White | Checkmark optional |
| Error | Red (#EF4444) | Light red tint | Error icon + message |
| Disabled | Light gray | Gray (#F3F4F6) | 50% opacity text |

### Validation Timing

- **On blur:** Validate when user leaves field
- **On change (after error):** Clear error as user types correct input
- **On submit:** Final validation before processing
- **Never on focus:** Don't show errors before user types

### Error Message Guidelines

```text
✓ "Email address is required"
✓ "Password must be at least 8 characters"
✓ "Please enter a valid phone number (e.g., 555-123-4567)"

✗ "Invalid input"
✗ "Error"
✗ "This field is required" (generic)

```

### Form Best Practices

- Mark optional fields, not required (fewer asterisks)
- Show password requirements before errors occur
- Use input masks for formatted data (phone, date)
- Preserve data on errors (don't clear the form)
- Provide clear success confirmation

---

## Navigation

### Navigation Patterns

#### Top Navigation Bar

```text
┌─────────────────────────────────────────────────────┐
│ Logo    Nav Item  Nav Item  Nav Item    [Search] [User] │
└─────────────────────────────────────────────────────┘

```

- **Best for:** Marketing sites, simple apps
- **Max items:** 5-7 top-level links
- **Mobile:** Collapse to hamburger menu

#### Sidebar Navigation

```text
┌────────┬────────────────────────────────┐
│ Logo   │ Content Area                   │
├────────┤                                │
│ Nav 1  │                                │
│ Nav 2  │                                │
│ Nav 3  │                                │
│        │                                │
│ ────── │                                │
│ Nav 4  │                                │
│ Nav 5  │                                │
└────────┴────────────────────────────────┘

```

- **Best for:** Dashboards, complex apps
- **Width:** 200-280px expanded, 64px collapsed
- **Mobile:** Overlay drawer

#### Bottom Navigation (Mobile)

```text
┌─────────────────────────────────────┐
│           Content Area              │
│                                     │
├─────────────────────────────────────┤
│  🏠    🔍    ➕    💬    👤        │
│ Home  Search Add  Chat  Profile     │
└─────────────────────────────────────┘

```

- **Max items:** 3-5 destinations
- **Best for:** Primary app sections
- **Always visible:** Persistent navigation

#### Breadcrumbs

```text
Home > Products > Electronics > Headphones

```

- **Use for:** Deep hierarchies (3+ levels)
- **Current page:** Not clickable, different style
- **Separator:** > or / or chevron icon

### Tab Navigation

```text
┌─────────┬─────────┬─────────┬─────────┐
│ Tab 1   │ Tab 2   │ Tab 3   │ Tab 4   │
└─────────┴─────────┴─────────┴─────────┘
│                                       │
│        Tab Content Area               │
│                                       │
└───────────────────────────────────────┘

```

- **Max tabs:** 3-5 for clarity
- **Active indicator:** Underline or background
- **Use for:** Related content within same page

---

## Cards

### Card Anatomy

```text
┌─────────────────────────────────┐
│ ░░░░░░░ Image/Media ░░░░░░░░░░ │
├─────────────────────────────────┤
│ Category Label                  │
│ Card Title                      │
│ Description text that may       │
│ span multiple lines...          │
│                                 │
│ [Action Button]  [Secondary]    │
└─────────────────────────────────┘

```

### Card Guidelines

- **Consistent sizing:** Use grid, equal heights
- **Content hierarchy:** Image → Title → Description → Actions
- **Padding:** 16-24px internal spacing
- **Border radius:** 8-12px (matching buttons)
- **Shadow:** Subtle elevation (0 2px 4px rgba(0,0,0,0.1))

---

## Modals and Dialogs

### Modal Structure

```text
┌─────────────────────────────────────┐
│ Modal Title                    [×]  │
├─────────────────────────────────────┤
│                                     │
│ Modal content goes here.            │
│ Keep it focused on one task.        │
│                                     │
├─────────────────────────────────────┤
│           [Cancel]  [Confirm]       │
└─────────────────────────────────────┘

```

### Modal Guidelines

- **Size:** 400-600px width (desktop), full-width minus margins (mobile)
- **Overlay:** Semi-transparent dark background (rgba(0,0,0,0.5))
- **Close options:** X button, overlay click, Escape key
- **Focus trap:** Keep keyboard focus within modal
- **Primary action:** Right-aligned, visually prominent

---

## Dashboards

### Dashboard Layout Principles

1. **Most important metrics at top:** KPIs, summary cards
2. **Progressive detail:** Overview → Drill-down capability
3. **Consistent card sizes:** Use grid system
4. **Minimal chartjunk:** Only data-serving visuals
5. **Actionable insights:** Highlight anomalies

### Data Visualization Selection

| Data Type | Chart Type |
| --------- | ---------- |
| Comparison across categories | Bar chart |
| Trend over time | Line chart |
| Part of whole | Pie (≤5 slices) or Donut |
| Distribution | Histogram |
| Correlation | Scatter plot |
| Geographic | Map |
| Single metric | Big number + sparkline |

### Dashboard Best Practices

- **Limit to 5-9 widgets** per view
- **Align to grid:** Consistent gutters and sizing
- **Filter controls:** Top or sidebar, always visible
- **Date range selector:** Common need, make prominent
- **Export options:** PDF, CSV for data tables
- **Responsive:** Stack cards on smaller screens

---

## Empty States

### Empty State Components

```text
┌─────────────────────────────────────┐
│                                     │
│         [Illustration/Icon]         │
│                                     │
│      No projects yet                │
│                                     │
│   Create your first project to      │
│   start organizing your work.       │
│                                     │
│       [Create Project]              │
│                                     │
└─────────────────────────────────────┘

```

### Empty State Guidelines

- **Friendly illustration:** Not just "No data"
- **Explain value:** Why create something?
- **Clear CTA:** Primary action to fix empty state
- **Keep it brief:** 1-2 sentences max

---

## Loading States

### Loading Patterns

| Duration | Pattern |
| -------- | ------- |
| <1 second | No indicator (feels instant) |
| 1-3 seconds | Spinner or progress indicator |
| 3-10 seconds | Skeleton screens + progress |
| >10 seconds | Progress bar + explanation |

### Skeleton Screen

```text
┌─────────────────────────────────────┐
│ ░░░░░░░░░░░░ ░░░░░░░░░░           │
├─────────────────────────────────────┤
│ ░░░░░░░░░░░░░░░░░░░░░░░░░         │
│ ░░░░░░░░░░░░░░░░░░░               │
│ ░░░░░░░░░░░░░░░░░░░░░░░           │
└─────────────────────────────────────┘

```

- Match layout of loaded content
- Use subtle animation (shimmer/pulse)
- Show actual content structure
platform-guidelines.md 8.6 KB
# Platform Design Guidelines Reference

## Mobile Design Fundamentals

### Screen Sizes

| Device | Size | Design At |
| ------ | ---- | --------- |
| iPhone SE | 375×667 | Small mobile |
| iPhone 14/15 | 390×844 | Standard mobile |
| iPhone 14 Pro Max | 430×932 | Large mobile |
| Android small | 360×640 | Minimum target |
| Android large | 412×915 | Large Android |

### Safe Areas

```text
┌─────────────────────────────────┐
│ ▓▓▓▓▓▓▓ Status Bar ▓▓▓▓▓▓▓▓▓▓ │ 44-47px
├─────────────────────────────────┤
│                                 │
│      Safe Content Area          │
│                                 │
│                                 │
├─────────────────────────────────┤
│ ▓▓▓▓▓▓ Home Indicator ▓▓▓▓▓▓▓ │ 34px
└─────────────────────────────────┘

```

### Touch Targets

- **Minimum:** 44×44pt (iOS) / 48×48dp (Android)
- **Recommended:** 48×48px for all platforms
- **Spacing:** Minimum 8px between targets

---

## iOS Human Interface Guidelines (HIG)

### Design Philosophy

- **Clarity:** Text is legible, icons precise, adornments subtle
- **Deference:** UI helps people understand content, never competes
- **Depth:** Distinct visual layers convey hierarchy

### Navigation Patterns

| Pattern | When to Use |
| ------- | ----------- |
| Tab Bar | 3-5 top-level destinations |
| Navigation Bar | Hierarchical content |
| Sidebar | iPad, rich content apps |
| Search | Content discovery |

### Tab Bar Specifications

```text
┌─────────────────────────────────┐
│  🏠    🔍    ➕    💬    👤    │
│ Home  Search Add  Chat  Profile │ 49pt height
└─────────────────────────────────┘

```

- Max 5 tabs
- Icons 25×25pt with 10pt labels
- Active tab uses fill/tint color
- Inactive tabs use gray

### Navigation Bar

```text
┌─────────────────────────────────┐
│ ‹ Back    Page Title    Action │ 44pt minimum
└─────────────────────────────────┘

```

- Left: Back button or cancel
- Center: Title
- Right: Primary action (text or icon)

### Typography (SF Pro)

| Style | Size | Weight |
| ----- | ---- | ------ |
| Large Title | 34pt | Bold |
| Title 1 | 28pt | Bold |
| Title 2 | 22pt | Bold |
| Title 3 | 20pt | Semibold |
| Headline | 17pt | Semibold |
| Body | 17pt | Regular |
| Callout | 16pt | Regular |
| Subhead | 15pt | Regular |
| Footnote | 13pt | Regular |
| Caption | 12pt | Regular |

### iOS Colors (System)

| Color | Light | Dark |
| ----- | ----- | ---- |
| Label | #000000 | #FFFFFF |
| Secondary Label | #3C3C43 @ 60% | #EBEBF5 @ 60% |
| Tertiary Label | #3C3C43 @ 30% | #EBEBF5 @ 30% |
| System Blue | #007AFF | #0A84FF |
| System Green | #34C759 | #30D158 |
| System Red | #FF3B30 | #FF453A |
| System Orange | #FF9500 | #FF9F0A |

### iOS-Specific Patterns

- **Swipe gestures:** Delete, archive, actions
- **Pull to refresh:** Standard list refresh
- **Long press:** Context menus
- **Haptic feedback:** Confirm actions
- **Edge swipe:** Back navigation

---

## Android Material Design

### Android Design Philosophy

- **Material as metaphor:** Physical properties, elevation
- **Bold, graphic, intentional:** Deliberate color, typography, space
- **Motion provides meaning:** Feedback and continuity

### Android Navigation Patterns

| Pattern | When to Use |
| ------- | ----------- |
| Bottom Navigation | 3-5 top destinations |
| Navigation Drawer | 5+ destinations, less frequent |
| Navigation Rail | Tablet landscape |
| Tabs | Related content groups |

### Bottom Navigation

```text
┌─────────────────────────────────┐
│  🏠    🔍    📷    💬    👤    │
│ Home  Search Camera Chat Account│ 80dp height
└─────────────────────────────────┘

```

- 3-5 destinations
- Icons 24dp with 12sp labels
- Active: filled icon + primary color
- Inactive: outlined icon + on-surface

### App Bar

```text
┌─────────────────────────────────┐
│ ≡  App Title                🔍 │ 64dp height
└─────────────────────────────────┘

```

- Left: Navigation icon (menu or back)
- Center: Title (can be left-aligned)
- Right: Action icons (max 3)

### Floating Action Button (FAB)

- **Size:** 56dp standard, 40dp mini
- **Position:** Bottom right, 16dp from edges
- **Purpose:** Primary action only
- **Behavior:** Can hide on scroll

### Typography (Roboto)

| Style | Size | Weight | Tracking |
| ----- | ---- | ------ | -------- |
| Display Large | 57sp | Regular | -0.25 |
| Display Medium | 45sp | Regular | 0 |
| Display Small | 36sp | Regular | 0 |
| Headline Large | 32sp | Regular | 0 |
| Headline Medium | 28sp | Regular | 0 |
| Headline Small | 24sp | Regular | 0 |
| Title Large | 22sp | Regular | 0 |
| Title Medium | 16sp | Medium | 0.15 |
| Title Small | 14sp | Medium | 0.1 |
| Body Large | 16sp | Regular | 0.5 |
| Body Medium | 14sp | Regular | 0.25 |
| Body Small | 12sp | Regular | 0.4 |
| Label Large | 14sp | Medium | 0.1 |
| Label Medium | 12sp | Medium | 0.5 |
| Label Small | 11sp | Medium | 0.5 |

### Material Colors

| Role | Purpose |
| ---- | ------- |
| Primary | Main brand color |
| On Primary | Text/icons on primary |
| Primary Container | Filled buttons, active states |
| Secondary | Less prominent components |
| Tertiary | Contrast, balance |
| Error | Error states |
| Surface | Card backgrounds |
| On Surface | Text on surfaces |
| Outline | Borders, dividers |

### Elevation (Shadows)

| Level | Elevation | Use Case |
| ----- | --------- | -------- |
| 0 | 0dp | Flat surfaces |
| 1 | 1dp | Cards, raised buttons |
| 2 | 3dp | Elevated cards |
| 3 | 6dp | FAB resting |
| 4 | 8dp | Dialogs, pickers |
| 5 | 12dp | FAB pressed |

### Android-Specific Patterns

- **Snackbar:** Brief feedback at bottom
- **Bottom sheet:** Additional content/actions
- **Chips:** Filter, input, choice, action
- **Speed dial FAB:** Multiple related actions

---

## Responsive Web Design

### Breakpoints

| Name | Width | Typical Device |
| ---- | ----- | -------------- |
| xs | <576px | Mobile portrait |
| sm | 576-767px | Mobile landscape |
| md | 768-991px | Tablet |
| lg | 992-1199px | Small desktop |
| xl | 1200-1399px | Desktop |
| xxl | ≥1400px | Large desktop |

### Grid System

- **Columns:** 12-column grid standard
- **Gutters:** 16-24px between columns
- **Margins:** 16px (mobile) to 64px (desktop)
- **Max content width:** 1200-1440px

### Responsive Typography

```text
Mobile (base):
  Body: 16px
  H1: 28-32px
  H2: 22-24px
  
Tablet:
  Body: 16px
  H1: 32-40px
  H2: 24-28px
  
Desktop:
  Body: 16-18px
  H1: 40-56px
  H2: 28-36px

```

### Mobile-First Approach

1. Design for smallest screen first
2. Add complexity for larger screens
3. Content priority: What's essential?
4. Performance: Minimize for mobile
5. Touch-first interactions

### Responsive Patterns

| Pattern | Description |
| ------- | ----------- |
| Stack | Columns become rows on mobile |
| Reflow | Content reorders based on priority |
| Reveal | More content shown at larger sizes |
| Off-canvas | Navigation slides in on mobile |
| Scale | Elements scale proportionally |

---

## Desktop Applications

### Window Chrome

```text
┌─────────────────────────────────────────┐
│ ● ● ●   App Title              ─ □ ×  │ Title bar
├────────┬────────────────────────────────┤
│ Sidebar│ Content Area                   │
│        │                                │
│        │                                │
│        │                                │
│        ├────────────────────────────────┤
│        │ Status Bar                     │
└────────┴────────────────────────────────┘

```

### Keyboard-First Design

- All actions accessible via keyboard
- Visible keyboard shortcuts
- Focus management for tab order
- Search/command palette (Cmd/Ctrl+K)

### Hover States

Desktop has hover (mobile doesn't):

- Show additional info on hover
- Preview actions before click
- Tooltips for icon-only buttons
- Dropdown menus on hover

### Dense Information

Desktop allows for:

- Smaller touch targets (32px min)
- More visible information
- Complex tables and data grids
- Multi-column layouts
- Side-by-side comparisons

---

## Cross-Platform Considerations

### Shared Principles

- Consistent brand identity
- Same core user flows
- Synchronized data/state
- Familiar information architecture

### Platform-Specific Adaptations

| Aspect | iOS | Android | Web |
| ------ | --- | ------- | --- |
| Back | Left nav | Left or gesture | Browser back |
| Primary action | Right nav | FAB | Top right button |
| Lists | Swipe actions | Long press | Hover actions |
| Menus | Action sheets | Bottom sheet | Dropdown/context |
| Alerts | Centered modal | Centered modal | Various positions |

### Design Tokens Across Platforms

Create platform-agnostic tokens:

```text
// Spacing
spacing-sm: 8
spacing-md: 16
spacing-lg: 24

// These map to platform units
iOS: points (pt)
Android: density-independent pixels (dp)
Web: pixels (px) or rem

```
setup-troubleshooting.md 7.9 KB
# Penpot MCP Server Setup & Troubleshooting

Complete guide for installing, configuring, and troubleshooting the Penpot MCP Server.

## Architecture Overview

The Penpot MCP integration requires **three components** working together:

```
┌─────────────────┐     ┌─────────────────┐     ┌─────────────────┐
│   MCP Client    │────▶│   MCP Server    │◀───▶│  Penpot Plugin  │
│ (VS Code/Claude)│     │  (port 4401)    │     │ (in browser)    │
└─────────────────┘     └────────┬────────┘     └────────┬────────┘
                                 │                       │
                                 │    WebSocket          │
                                 │    (port 4402)        │
                                 └───────────────────────┘
```

1. **MCP Server** - Exposes tools to your AI client (HTTP on port 4401)
2. **Plugin Server** - Serves the Penpot plugin files (HTTP on port 4400)
3. **Penpot MCP Plugin** - Runs inside Penpot browser, executes design commands

## Prerequisites

- **Node.js v22+** - [Download](https://nodejs.org/)
- **Git** - For cloning the repository
- **Modern browser** - Chrome, Firefox, or Chromium-based browser

Verify Node.js installation:
```bash
node --version  # Should be v22.x or higher
npm --version
npx --version
```

## Installation

### Step 1: Clone and Install

```bash
# Clone the repository
git clone https://github.com/penpot/penpot-mcp.git
cd penpot-mcp

# Install dependencies
npm install
```

### Step 2: Build and Start Servers

```bash
# Build all components and start servers
npm run bootstrap
```

This command:

- Installs dependencies for all components
- Builds the MCP server and plugin
- Starts both servers (MCP on 4401, Plugin on 4400)

**Expected output:**

```txt
MCP Server listening on http://localhost:4401
Plugin server listening on http://localhost:4400
WebSocket server listening on port 4402
```

### Step 3: Load Plugin in Penpot

1. Open [Penpot](https://design.penpot.app/) in your browser
2. Open or create a design file
3. Go to **Plugins** menu (or press the plugins icon)
4. Click **Load plugin from URL**
5. Enter: `http://localhost:4400/manifest.json`
6. The plugin UI will appear - click **"Connect to MCP server"**
7. Status should change to **"Connected to MCP server"**

> **Important**: Keep the plugin UI open while using MCP tools. Closing it disconnects the server.

### Step 4: Configure Your MCP Client

#### VS Code with GitHub Copilot

Add to your VS Code `settings.json`:

```json
{
  "mcp": {
    "servers": {
      "penpot": {
        "url": "http://localhost:4401/sse"
      }
    }
  }
}
```

Or use the HTTP endpoint:

```json
{
  "mcp": {
    "servers": {
      "penpot": {
        "url": "http://localhost:4401/mcp"
      }
    }
  }
}
```

#### Claude Desktop

Claude Desktop requires the `mcp-remote` proxy (stdio-only transport):

1. Install the proxy:

   ```bash
   npm install -g mcp-remote
   ```

2. Edit Claude Desktop config:
   - **macOS**: `~/Library/Application Support/Claude/claude_desktop_config.json`
   - **Windows**: `%APPDATA%/Claude/claude_desktop_config.json`
   - **Linux**: `~/.config/Claude/claude_desktop_config.json`

3. Add the Penpot server:

   ```json
   {
     "mcpServers": {
       "penpot": {
         "command": "npx",
         "args": ["-y", "mcp-remote", "http://localhost:4401/sse", "--allow-http"]
       }
     }
   }
   ```

4. **Fully quit** Claude Desktop (File → Quit, not just close window) and restart

#### Claude Code (CLI)

```bash
claude mcp add penpot -t http http://localhost:4401/mcp
```

## Troubleshooting

### Connection Issues

#### "Plugin cannot connect to MCP server"

**Symptoms**: Plugin shows "Not connected" even after clicking Connect

**Solutions**:

1. Verify servers are running:
   ```bash
   # Check if ports are in use
   lsof -i :4401  # MCP server
   lsof -i :4402  # WebSocket
   lsof -i :4400  # Plugin server
   ```

2. Restart the servers:

   ```bash
   # In the penpot-mcp directory
   npm run start:all
   ```

3. Check browser console (F12) for WebSocket errors

#### Browser Blocks Local Connection

**Symptoms**: Browser refuses to connect to localhost from Penpot

**Cause**: Chromium 142+ enforces Private Network Access (PNA) restrictions

**Solutions**:

1. **Chrome/Chromium**: When prompted, allow access to local network
2. **Brave**: Disable Shield for the Penpot website:
   - Click the Brave Shield icon in address bar
   - Toggle Shield off for this site
3. **Try Firefox**: Firefox doesn't enforce these restrictions as strictly

#### "WebSocket connection failed"

**Solutions**:

1. Check firewall settings - allow ports 4400, 4401, 4402
2. Disable VPN if active
3. Check for conflicting applications using the same ports

### MCP Client Issues

#### Tools Not Appearing in VS Code/Claude

1. **Verify endpoint**:

   ```bash
   # Test the SSE endpoint
   curl http://localhost:4401/sse
   
   # Test the MCP endpoint
   curl http://localhost:4401/mcp
   ```

2. **Check configuration syntax** - JSON must be valid
3. **Restart the MCP client** completely
4. **Check MCP server logs**:

   ```bash
   # Logs are in mcp-server/logs/
   tail -f mcp-server/logs/mcp-server.log
   ```

#### "Tool execution timed out"

**Cause**: Plugin disconnected or operation took too long

**Solutions**:

1. Ensure plugin UI is still open in Penpot
2. Verify plugin shows "Connected" status
3. Try reconnecting: click Disconnect then Connect in plugin

### Plugin Issues

#### "Plugin failed to load"

1. Verify plugin server is running on port 4400
2. Try accessing `http://localhost:4400/manifest.json` directly in browser
3. Clear browser cache and reload Penpot
4. Remove and re-add the plugin

#### "Cannot find penpot object"

**Cause**: Plugin not properly initialized or design file not open

**Solutions**:

1. Make sure you have a design file open (not just the dashboard)
2. Wait a few seconds after opening file before connecting
3. Refresh Penpot and reload the plugin

### Server Issues

#### Port Already in Use

```bash
# Find process using the port
lsof -i :4401

# Kill the process if needed
kill -9 <PID>
```

Or configure different ports via environment variables:
```bash
PENPOT_MCP_SERVER_PORT=4501 npm run start:all
```

#### Server Crashes on Startup

1. Check Node.js version (must be v22+)
2. Delete `node_modules` and reinstall:

   ```bash
   rm -rf node_modules
   npm install
   npm run bootstrap
   ```

## Configuration Reference

### Environment Variables

| Variable | Default | Description |
|----------|---------|-------------|
| `PENPOT_MCP_SERVER_PORT` | 4401 | HTTP/SSE server port |
| `PENPOT_MCP_WEBSOCKET_PORT` | 4402 | WebSocket server port |
| `PENPOT_MCP_SERVER_LISTEN_ADDRESS` | localhost | Server bind address |
| `PENPOT_MCP_LOG_LEVEL` | info | Log level (trace/debug/info/warn/error) |
| `PENPOT_MCP_LOG_DIR` | logs | Log file directory |
| `PENPOT_MCP_REMOTE_MODE` | false | Enable remote mode (disables file system access) |

### Example: Custom Configuration

```bash
# Run on different ports with debug logging
PENPOT_MCP_SERVER_PORT=5000 \
PENPOT_MCP_WEBSOCKET_PORT=5001 \
PENPOT_MCP_LOG_LEVEL=debug \
npm run start:all
```

## Verifying the Setup

Run this checklist to confirm everything works:

1. **Servers Running**:
   ```bash
   curl -s http://localhost:4401/sse | head -1
   # Should return SSE stream headers
   ```

2. **Plugin Connected**: Plugin UI shows "Connected to MCP server"

3. **Tools Available**: In your MCP client, verify these tools appear:
   - `mcp__penpot__execute_code`
   - `mcp__penpot__export_shape`
   - `mcp__penpot__import_image`
   - `mcp__penpot__penpot_api_info`

4. **Test Execution**: Ask your AI assistant to run a simple command:
   > "Use Penpot to get the current page name"

## Getting Help

- **GitHub Issues**: [penpot/penpot-mcp/issues](https://github.com/penpot/penpot-mcp/issues)
- **GitHub Discussions**: [penpot/penpot-mcp/discussions](https://github.com/penpot/penpot-mcp/discussions)
- **Penpot Community**: [community.penpot.app](https://community.penpot.app/)

License (MIT)

View full license text
MIT License

Copyright GitHub, Inc.

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.