Documentation Index
Fetch the complete documentation index at: https://mintlify.com/open-pencil/open-pencil/llms.txt
Use this file to discover all available pages before exploring further.
Getting Started
OpenPencil is open source and welcomes contributions. This guide will help you set up your development environment and understand the contribution workflow.Setup
Prerequisites
- Bun — JavaScript runtime and package manager
- Git — Version control
- Rust — Only needed for desktop app development
Clone and Install
Development Workflow
Running the App
Web version (recommended for quick iteration):http://localhost:1420 with hot reload.
Desktop app:
Before Submitting a PR
Run all quality checks to ensure your code meets project standards:Project Structure
OpenPencil uses a monorepo structure with Bun workspaces:Packages
-
packages/core—@open-pencil/core- Scene graph, renderer, layout, codec
- Zero DOM dependencies, runs headless in Bun
- Core functionality used by all other packages
-
packages/cli—@open-pencil/cli- Headless CLI for
.figinspection and export - Uses
cittyfor CLI framework andagentfmtfor output formatting
- Headless CLI for
-
packages/mcp—@open-pencil/mcp- MCP server for AI coding tools
- Supports both stdio and HTTP transports
- Reuses tools from core package
Application Code
-
src/— Main Tauri/Vite desktop editorsrc/ai/— AI tool wiringsrc/components/— Vue componentssrc/composables/— Vue composables for canvas, keyboard, collaborationsrc/stores/— Editor state managementsrc/engine/— Re-export shims from@open-pencil/core
-
desktop/— Tauri v2 configuration and Rust code -
tests/tests/e2e/— Playwright visual regression teststests/engine/— Unit teststests/fixtures/— Test.figfiles (Git LFS)
Code Conventions
General Rules
- Bun runtime — Use Bun, not Node.js
- TypeScript — All code is TypeScript
- No
any— Use proper types, generics, or unknowns - No
!assertions — Use guards, optional chaining (?.), or nullish coalescing (??) - No
Math.random()— Usecrypto.getRandomValues()for all randomness
Imports
@/alias — Use for app-level cross-directory imports (e.g.,@/stores/editor)- Relative imports — Use within
packages/core(e.g.,../../types)
Styling
- Tailwind 4 — All styling via Tailwind classes
- No inline CSS — Avoid
styleattributes - No
<style>blocks — Don’t use component-scoped styles
Icons
- unplugin-icons — Use with Iconify/Lucide collections
- Component syntax —
<icon-lucide-menu />(not raw SVG or Unicode)
Vue
- Vue 3 Composition API — Use
<script setup> - VueUse — Use
@vueuse/corehooks (e.g.,useEventListener) - Reka UI — Use for UI components (Splitter, ContextMenu, etc.)
Constants
src/constants.ts— Define constants here, not inline magic numbers
Browser API Guards
Code inpackages/core must guard browser APIs since it runs headless in Bun:
Test Fixtures
Test.fig files in tests/fixtures/ use Git LFS:
- Regular push —
git push(slow, uploads LFS files) - Skip LFS —
git push --no-verify(fast, skips LFS pre-push hook)
git push when you’ve changed .fig fixtures.
Documentation
Update relevant docs when making changes:CHANGELOG.md— Add user-facing changes under “Unreleased”README.md— Update if feature descriptions changeAGENTS.md— Update if architecture or conventions changepackages/docs/— Update VitePress docs for major features
Commit Messages
Follow the existing style ingit log:
- Keep messages concise
- Use imperative mood (“Add feature” not “Added feature”)
- Reference issues when applicable
CLI Development
Output Formatting
- Always use
agentfmt— All CLI output must use formatters fromagentfmt - Available formatters —
fmtList,fmtHistogram,fmtSummary,fmtTree,kv,entity,bold,dim - Don’t hand-roll formatting — Use helpers from
packages/cli/src/format.ts - JSON flag — Every command supports
--jsonfor machine-readable output
Commands
Tool Development
Tools (AI / MCP / CLI operations) are defined once inpackages/core/src/tools/schema.ts:
- Add a
defineTool()inschema.ts - Add to
ALL_TOOLSarray - Tool is instantly available in:
- AI chat (via Vercel AI adapter)
- MCP server (stdio + HTTP)
- CLI
evalcommand
Tool Structure
Rendering
- Canvas — CanvasKit (Skia WASM) on WebGL, not DOM
- Versioning —
sceneVersionfor scene mutations,renderVersionfor repaints - Render requests —
requestRender()bumps both,requestRepaint()only bumps render - Culling — Off-screen nodes are skipped, but unclipped parents aren’t
Collaboration
- P2P — Trystero (WebRTC), no server
- CRDT — Yjs for document state
- Persistence — y-indexeddb for local storage
- Composable —
src/composables/use-collab.ts
File Format
.figfiles — Kiwi binary codec, same as Figma- Schema —
packages/core/src/kiwi/codec.ts - Vector data — Reverse-engineered
vectorNetworkBlobformat - Testing — Round-trip by exporting and reimporting in Figma
Desktop App
- Tauri v2 — Rust backend, web frontend
- Plugins — dialog, fs, opener
- Permissions — Configure in
desktop/tauri.conf.json
Platform Prerequisites
macOS:- Install Rust
- Install Visual Studio Build Tools
Release Process
Releases are handled by maintainers:- Update versions in
package.json,packages/*/package.json,desktop/tauri.conf.json - Update
CHANGELOG.md - Commit:
Release v0.x.y - Tag:
git tag v0.x.y && git push --tags - CI builds binaries and publishes to npm
CI Workflows
| Workflow | Trigger | Action |
|---|---|---|
build.yml | v* tag | Build desktop apps, publish to npm |
app.yml | Push to master | Deploy web app to Cloudflare Pages |
docs.yml | packages/docs/** | Deploy docs to Cloudflare Pages |
Getting Help
- Issues — GitHub Issues
- Discussions — GitHub Discussions
- Documentation — openpencil.dev
Code of Conduct
Be respectful and constructive. We’re building this tool together.Reference
For implementation details, see:- AGENTS.md — Architecture and conventions
- README.md — User-facing features
- figma-use — Reference toolkit