---
name: open-pencil-design-editor
description: AI-native open-source Figma alternative with CLI, MCP server, and Vue SDK for reading/writing .fig files programmatically.
triggers:
- open pencil design editor
- figma alternative open source
- open fig files programmatically
- design editor cli typescript
- mcp server for figma files
- ai design editor self-hosted
- open pencil cli commands
- figma file scripting automation
---
# OpenPencil Design Editor
> Skill by [ara.so](https://ara.so) — Daily 2026 Skills collection.
OpenPencil is an open-source, AI-native design editor that reads and writes native Figma (`.fig`) files, provides a headless CLI, an MCP server for AI agents, and a Vue SDK for building custom editors. It is MIT-licensed and runs in the browser, as a desktop app (Tauri/macOS/Windows/Linux), or fully headlessly.
---
## Installation
### Web app (no install)
Visit [app.openpencil.dev/demo](https://app.openpencil.dev/demo).
### Desktop (macOS)
```sh
brew install open-pencil/tap/open-pencil
```
Or download from [releases](https://github.com/open-pencil/open-pencil/releases/latest).
### CLI
```sh
bun add -g @open-pencil/cli
```
### MCP server
```sh
bun add -g @open-pencil/mcp
```
### Local development
```sh
git clone https://github.com/open-pencil/open-pencil
cd open-pencil
bun install
bun run dev # Web app at localhost:1420
bun run tauri dev # Desktop (requires Rust)
```
---
## CLI Reference
The `open-pencil` CLI operates on `.fig` files headlessly. When the desktop app is running, omit the file argument to connect to the live canvas via RPC.
### Inspect file structure
```sh
# Print the full node tree
open-pencil tree design.fig
# Find nodes by type
open-pencil find design.fig --type TEXT
open-pencil find design.fig --type FRAME
# Get a specific node by ID
open-pencil node design.fig --id 1:23
# File metadata
open-pencil info design.fig
```
### XPath queries
```sh
# All frames
open-pencil query design.fig "//FRAME"
# Frames narrower than 300px
open-pencil query design.fig "//FRAME[@width < 300]"
# Text nodes whose name contains "Button"
open-pencil query design.fig "//TEXT[contains(@name, 'Button')]"
# Nodes with rounded corners
open-pencil query design.fig "//*[@cornerRadius > 0]"
# Text inside sections
open-pencil query design.fig "//SECTION//TEXT"
```
### Export
```sh
# PNG (default)
open-pencil export design.fig
# JPG at 2x scale, quality 90
open-pencil export design.fig -f jpg -s 2 -q 90
# SVG
open-pencil export design.fig -f svg
# WEBP
open-pencil export design.fig -f webp
# JSX with Tailwind v4 utility classes
open-pencil export design.fig -f jsx --style tailwind
```
Example Tailwind output:
```html
Card Title
Description text
```
### Design token analysis
```sh
open-pencil analyze colors design.fig
open-pencil analyze typography design.fig
open-pencil analyze spacing design.fig
open-pencil analyze clusters design.fig # Repeated structures / component candidates
```
### Scripting with Figma Plugin API (`eval`)
```sh
# Read: count children on the current page
open-pencil eval design.fig -c "figma.currentPage.children.length"
# Read: get all text node contents
open-pencil eval design.fig -c "figma.currentPage.findAll(n => n.type === 'TEXT').map(n => n.characters)"
# Write: set opacity of all selected nodes (-w writes back to file)
open-pencil eval design.fig -c "figma.currentPage.selection.forEach(n => n.opacity = 0.5)" -w
# Write: rename all frames on the page
open-pencil eval design.fig -c "figma.currentPage.findAll(n => n.type === 'FRAME').forEach((f, i) => f.name = 'Frame ' + i)" -w
# Connect to the live running desktop app (no file arg)
open-pencil eval -c "figma.currentPage.name"
open-pencil tree
open-pencil export -f png
```
All commands support `--json` for machine-readable output:
```sh
open-pencil find design.fig --type TEXT --json
open-pencil analyze colors design.fig --json
```
---
## MCP Server
The MCP server exposes 90 tools (87 core + 3 file management) for AI agents to read and write `.fig` files.
### Stdio (Claude Code, Cursor, Windsurf)
```sh
bun add -g @open-pencil/mcp
```
Add to your MCP client config (e.g. `~/.claude/mcp.json` or Cursor settings):
```json
{
"mcpServers": {
"open-pencil": {
"command": "openpencil-mcp"
}
}
}
```
### HTTP server (scripts, CI)
```sh
openpencil-mcp-http
# Listens at http://localhost:3100/mcp
```
### Claude Code desktop integration
1. Install the ACP adapter:
```sh
npm i -g @zed-industries/claude-agent-acp
```
2. Add MCP permission to `~/.claude/settings.json`:
```json
{
"permissions": {
"allow": ["mcp__open-pencil"]
}
}
```
3. Open the desktop app → `Ctrl+J` → select **Claude Code** from the provider dropdown.
### Agent skill (quick setup)
```sh
npx skills add open-pencil/skills@open-pencil
```
---
## AI Chat (Built-in)
- Open with `⌘J` (macOS) or `Ctrl+J` (desktop/web).
- 87 tools: create shapes, set fills/strokes, manage auto-layout, work with components and variables, boolean operations, token analysis, asset export.
- Bring your own API key — no backend or account required.
### Supported providers
Configure via the provider dropdown in the chat panel:
| Provider | Env var |
|---|---|
| Anthropic | `ANTHROPIC_API_KEY` |
| OpenAI | `OPENAI_API_KEY` |
| Google AI | `GOOGLE_AI_API_KEY` |
| OpenRouter | `OPENROUTER_API_KEY` |
| Any compatible endpoint | Custom base URL |
---
## Real-time Collaboration
No server, no account. Peer-to-peer via WebRTC.
1. Click the **Share** button (top-right).
2. Share the generated URL: `app.openpencil.dev/share/`.
3. Peers see live cursors, selections, and edits.
4. Click a peer's avatar to follow their viewport.
---
## Project Structure
```
packages/
core/ @open-pencil/core — engine: scene graph, renderer, layout, codec
cli/ @open-pencil/cli — headless CLI
mcp/ @open-pencil/mcp — MCP server (stdio + HTTP)
docs/ Documentation site
src/ Vue 3 app — components, composables, stores
desktop/ Tauri v2 (Rust + config)
tests/ E2E (188 tests) + unit (764 tests)
```
### Tech stack
| Layer | Technology |
|---|---|
| Rendering | Skia (CanvasKit WASM) |
| Layout | Yoga WASM (flex + CSS Grid) |
| UI | Vue 3, Reka UI, Tailwind CSS 4 |
| File format | Kiwi binary + Zstd + ZIP |
| Collaboration | Trystero (WebRTC P2P) + Yjs (CRDT) |
| Desktop | Tauri v2 |
| AI/MCP | Anthropic, OpenAI, Google AI, OpenRouter; MCP SDK; Hono |
---
## Development Commands
```sh
bun run dev # Start web dev server (localhost:1420)
bun run tauri dev # Start desktop app (requires Rust)
bun run check # Lint + typecheck
bun run test # E2E visual regression tests
bun run test:unit # Unit tests
bun run format # Code formatting
bun run tauri build # Production desktop build
```
Desktop prerequisites: [Rust](https://rustup.rs/) + [Tauri v2 platform deps](https://v2.tauri.app/start/prerequisites/).
---
## Common Patterns
### Batch-rename all text nodes in a .fig file
```sh
open-pencil eval design.fig \
-c "figma.currentPage.findAll(n => n.type === 'TEXT').forEach((t, i) => t.name = 'Text_' + i)" \
-w
```
### Extract all colors as JSON
```sh
open-pencil analyze colors design.fig --json > colors.json
```
### Export every frame as PNG in CI
```sh
for id in $(open-pencil find design.fig --type FRAME --json | jq -r '.[].id'); do
open-pencil export design.fig --id "$id" -f png -o "frames/$id.png"
done
```
### Query nodes matching a naming convention
```sh
# Find all nodes named with a "btn-" prefix
open-pencil query design.fig "//*[starts-with(@name, 'btn-')]"
```
### Connect an MCP client to a running desktop app
When the desktop app is open, the MCP stdio server can connect to the live canvas. No file path needed — all reads and writes go to the open document.
```json
{
"mcpServers": {
"open-pencil": {
"command": "openpencil-mcp"
}
}
}
```
### Export a selection as Tailwind JSX programmatically
```sh
open-pencil export design.fig --id 1:23 -f jsx --style tailwind
```
---
## Troubleshooting
**`openpencil-mcp` not found after install**
- Ensure `bun`'s global bin dir is on your `PATH`: `export PATH="$HOME/.bun/bin:$PATH"`
- Or use `npx openpencil-mcp` as the MCP command value.
**Desktop app CLI connection fails**
- The desktop app must be running before issuing commands without a file argument.
- Check that no firewall rule blocks the local RPC socket.
**Tauri dev build errors**
- Install platform prerequisites: [v2.tauri.app/start/prerequisites](https://v2.tauri.app/start/prerequisites/)
- Ensure Rust is up to date: `rustup update`
**`.fig` file won't open**
- Confirm the file was exported from Figma (not a `.fig` backup or plugin artifact).
- Run `open-pencil info design.fig` to check if the codec can parse the header.
**AI chat returns no response**
- Verify your API key is set correctly in the provider settings panel.
- For OpenRouter, ensure your key has credits and the selected model is available.
**Collaboration peers not connecting**
- Both peers must use the exact same share URL (room ID is case-sensitive).
- WebRTC requires both peers to allow the browser/app through any firewall.
---
## Links
- Web app: [app.openpencil.dev/demo](https://app.openpencil.dev/demo)
- Documentation: [openpencil.dev](https://openpencil.dev)
- MCP tools reference: [openpencil.dev/reference/mcp-tools](https://openpencil.dev/reference/mcp-tools)
- Releases: [github.com/open-pencil/open-pencil/releases](https://github.com/open-pencil/open-pencil/releases/latest)
- License: MIT