Loading...
Loading...
AI-native open-source Figma alternative with CLI, MCP server, and Vue SDK for reading/writing .fig files programmatically.
npx skill4agent add aradotso/trending-skills open-pencil-design-editorSkill by ara.so — Daily 2026 Skills collection.
.figbrew install open-pencil/tap/open-pencilbun add -g @open-pencil/clibun add -g @open-pencil/mcpgit 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)open-pencil.fig# 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# 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"# 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<div className="flex flex-col gap-4 p-6 bg-white rounded-xl">
<p className="text-2xl font-bold text-[#1D1B20]">Card Title</p>
<p className="text-sm text-[#49454F]">Description text</p>
</div>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 candidateseval# 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--jsonopen-pencil find design.fig --type TEXT --json
open-pencil analyze colors design.fig --json.figbun add -g @open-pencil/mcp~/.claude/mcp.json{
"mcpServers": {
"open-pencil": {
"command": "openpencil-mcp"
}
}
}openpencil-mcp-http
# Listens at http://localhost:3100/mcpnpm i -g @zed-industries/claude-agent-acp~/.claude/settings.json{
"permissions": {
"allow": ["mcp__open-pencil"]
}
}Ctrl+Jnpx skills add open-pencil/skills@open-pencil⌘JCtrl+J| Provider | Env var |
|---|---|
| Anthropic | |
| OpenAI | |
| Google AI | |
| OpenRouter | |
| Any compatible endpoint | Custom base URL |
app.openpencil.dev/share/<room-id>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)| 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 |
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 buildopen-pencil eval design.fig \
-c "figma.currentPage.findAll(n => n.type === 'TEXT').forEach((t, i) => t.name = 'Text_' + i)" \
-wopen-pencil analyze colors design.fig --json > colors.jsonfor 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# Find all nodes named with a "btn-" prefix
open-pencil query design.fig "//*[starts-with(@name, 'btn-')]"{
"mcpServers": {
"open-pencil": {
"command": "openpencil-mcp"
}
}
}open-pencil export design.fig --id 1:23 -f jsx --style tailwindopenpencil-mcpbunPATHexport PATH="$HOME/.bun/bin:$PATH"npx openpencil-mcprustup update.fig.figopen-pencil info design.fig