Easel
Git-backed workflow for design files: a Snapshot menu commits only the design folder, and layout, notes and comments are stored in small one-entry-per-line JSON files so that concurrent branches editing different boards merge without conflicts. The HTML screens and JSON metadata live in the repository and merge like any other code.
Easel
An infinite canvas for HTML screens. Your AI agent writes the designs; you see and tweak them live.
A real Claude Code run on the bundled demo (the agent's thinking time is sped up 4×).
Easel turns a folder of plain HTML files into a design canvas. Claude Code or Codex writes a screen, and it shows up on the canvas a moment later. Drag, resize, retype or restyle anything on the canvas, and only that part of the source file changes. There is no export step and no proprietary file format: your designs stay in your repo as HTML and merge with git like any other code.
Try it in 30 seconds
npx easel-canvas --demoThat copies the "Tidy" habit tracker demo to ./easel-demo and opens it at http://localhost:4317. Open the AI tab (⌘J) and ask Claude Code or Codex for a change, or double-click a screen and start editing.
Already have HTML screens? Run it in your project:
npx easel-canvas # opens ./docs/design (or the current folder if it has screens/)
npx easel-canvas --init # starts a new ./docs/design with one screen
npx easel-canvas --dir ./designs # any folder of screens/*.htmlRelated MCP server: pulp
Why Easel
HTML is the source of truth. Each
screens/*.htmlfile is one board. What you see is exactly what ships to the browser, and there's nothing to export or keep in sync.Built for AI agents. An MCP server with 20 tools lets agents see the boards, read what you selected, leave comments, check tokens and arrange the canvas. An in-app chat runs
claude -porcodex execwith your selection as context.Surgical edits. Changes are patched into the exact source range (parse5 locations), so formatting, comments and the rest of the file stay untouched. If an agent edits the same element first, your edit is rejected instead of overwriting it.
Git-friendly by design. Layout, notes and comments live in small JSON files written one entry per line, so two branches moving different boards merge without conflicts.
Local-first. It runs on
127.0.0.1and works directly on the files in your repo. No account, no cloud, no lock-in.
Features
Connect your AI agent
Keep the canvas running (npx easel-canvas). Agents write HTML files directly; the MCP server lets them see (list_boards, read_board, screenshot, list_errors), know what you mean (get_selection with the selected element, visible boards and the current page), talk (comments and replies) and arrange (place_board, create_board, notes, pages, check_tokens, save_snapshot).
Claude Code: add .mcp.json to your project root:
{ "mcpServers": { "easel": { "type": "stdio", "command": "npx", "args": ["-y", "-p", "easel-canvas", "easel-mcp", "--port", "4317"] } } }Codex: add to ~/.codex/config.toml:
[mcp_servers.easel]
command = "npx"
args = ["-y", "-p", "easel-canvas", "easel-mcp", "--port", "4317"]
default_tools_approval_mode = "approve" # the tools only view, comment and arrangeUsing Easel as a submodule (below)? Point args at tools/easel/bin/mcp.mjs with "command": "node" instead.
Then try:
"Fix what I selected on the canvas: make the button text shorter." "Make three variants of the Stats screen." "Create an onboarding screen at 390×844 and put it next to Today."
New files with <meta name="board-size" content="390x844"> are placed on the canvas automatically at that size.
Pin it in your project
npx easel-canvas is all most projects need. To pin an exact version for your team, add it as a dev dependency (npm i -D easel-canvas, then "design": "easel-canvas" in your scripts) or as a git submodule. With your designs in <project>/docs/design/screens/:
git submodule add https://github.com/nemodleo/easel.git tools/easel{
"scripts": {
"design:install": "git submodule update --init tools/easel && npm --prefix tools/easel install",
"design": "npm --prefix tools/easel start"
}
}npm run design:install # once: fetch the submodule and install
npm run design # http://localhost:4317The default design folder is
../../docs/designrelative to the tool, sotools/easelopens yourdocs/designwith no flags. Anywhere else:npm --prefix tools/easel start -- --dir <design folder> --port <port>.It installs separately from your app, so it never touches your app's dependencies, build or deploy, and CI that skips submodules (the
actions/checkoutdefault) is unaffected.To update: push to this repo, then run
git submodule update --remote tools/easelin your project and commit the new pointer. Teammates runnpm run design:installaftergit pull.
To do this | How |
Pan and zoom | Drag empty space, Space, or Hand (H); trackpad scroll; ⌘+wheel or pinch (4–400%). ⇧1 Fit all, ⇧2 selection, ⌘0 Zoom to 100%, Minimap (M) |
Find | Left "Boards" tab: ⌘K search and list; pages (drag to reorder; right-click to rename, delete, or set the launch page) |
Boards | Draw with the board tool (B), use a "New board" template (Blank · Mobile screen · Desktop screen · Document), or drop an HTML file on the canvas. Duplicate ⌘D, rename F2 (renaming the file offers to update references), Delete (confirm, trash, undo), Bring to front / Send to back ⌘] ⌘[ |
Multiple items | Drag on empty space to marquee-select or use Shift; move together (snap guides, Alt to disable); arrow keys 1, Shift 10, Option 100 |
Board options | Right "Properties": position, size, Radius, No frame, Interactive (Play), Stretch to window, Open as launch screen, Layout guides (Columns · Rows · Grid, up to 6, ⌃G), Adjustable values |
View | Focus view (F, ←→), Play in place (P or ▶, Esc), Play full screen (right-click) |
Notes and shapes | Title (T), sticky note (N, 8 colors, size, bold, italic), Rectangle (R), Oval (O), Line (L), Arrow (A), Pen (P when no board is selected), image (Assets or paste) |
Edit mode | Double-click or E. Click or Shift, Esc for parent, Enter for child, ↑↓ for siblings, Option+↑↓ to reorder, ⌘A for all siblings, ⌘G Wrap in flex |
Direct editing | Move with handles (Alt drops inside a box) and resize, 6 align options, double-click text (Shift+Enter for a line break), Properties panel (token chips, ⚠, contrast ratio), Replace image, ⌘C/⌘V to paste into another board |
Undo | ⌘Z / ⌘⇧Z. Canvas actions, HTML edits and board create/delete share one history (100 entries) |
Design system | Register tokens ( |
Collaboration | Comments (Reply, Resolve, author), Snapshot menu (git-commits only the design folder) |
AI | Right "AI" tab (⌘J): Claude Code or Codex; selection, boards, visible boards, comments and references go along as context; N variants; Ask AI for a review |
Screen | F6 to move between regions, Tab to move between boards, ⌘\ to hide panels, Appearance (System · Light · Dark) |
How it works
your-project/docs/design/
├── screens/*.html ← one board per file; agents and you both edit these
├── board.json ← positions, titles, pages, notes, shapes (one line per entry)
├── comments.json ← comment threads pinned to elements
└── tokens.json ← optional design tokens and themesA small Node server watches the folder (chokidar) and tells the browser which board changed, so only that board reloads, keeping scroll and selection.
Element paths and hashes are computed from the source with parse5. Every edit is a minimal string patch into that range, written atomically.
The canvas is a Vite + React app. Each board is an iframe of the real HTML, so scripts, links and CSS behave exactly as in a browser.
Development
npm test # unit tests (source patching, board format, chat parsing, tokens…)
npm run test:e2e # Playwright end-to-end tests against test/fixtures/design
npm run typecheck
npm run demo # run the repo's demo from sourcetest/fixtures/design/intentionally keeps Korean screen content and board titles: it mimics real user content and is needed to test Korean text input (IME) and rendering. SetDESIGN_CANVAS_E2E_DIR=<folder>to run the e2e tests against another design folder.examples/demo/is the "Tidy" demo used for the screenshots above.
Folder | Contents |
|
|
| API and routes, board.json, file watching, element paths and hashes, source patching, history, chat runner, tokens |
| Canvas UI (Vite + React + TypeScript); all UI text lives in |
|
|
Background reading: the original plan is in PLAN.md, a feature-by-feature comparison with Claude Design is in PARITY.md, and the work log is in tasks.md.
Contributions are welcome: open an issue or a pull request.
License
MIT © Hyun Park
This server cannot be deployed
Maintenance
Related MCP Connectors
Your AI agent designs editable, clickable UI prototypes on a live canvas.
1Real-time collaborative whiteboard — AI agents and humans edit the same board live over MCP.
Agent-Native design tool - create and edit visual designs with agent assistance
Intelligent product canvas: iterate on your product's design with your coding agent, synced to code.
Related MCP Servers
- AlicenseNot gradedqualityCmaintenanceMCP server that enables AI coding agents to read and write to a local-first HTML/CSS design canvas, bridging visual design and code generation.1MIT
- AlicenseNot gradedqualityDmaintenanceEnables AI agents to collaboratively design and edit web pages on an infinite canvas using real HTML/CSS, with tools for reading, mutating, and exporting documents.372 npm1LGPL 3.0
- AlicenseNot gradedqualityAmaintenanceOpen-source multiplayer design canvas (alternative to Paper.design) with a built-in MCP server. Agents create and stream HTML artboards live next to human collaborators, review them via screenshots, comment on elements, search icons/images/logos and follow shared design guidelines.2 npm875AGPL 3.0
- AlicenseNot gradedqualityCmaintenanceEnables AI agents to build and edit real HTML/CSS designs on a live canvas through 35 MCP tools, letting them inspect screenshots, computed styles and layout, then export production-ready React or Tailwind code. Humans can refine the same layers visually in a macOS editor.6,734 npmMIT