Skip to content
Conduit

mcp server

easel

Easel — an HTML design canvas for AI agents. Claude Code / Codex write screens, you see and edit them live (MCP)

nemodleo/easelcommunitylistedunreviewed

Set up

Runs on your computer. Pick your agent and operating system.

Before you start

  • Node.js 20 or newer
~/Library/Application Support/Claude/claude_desktop_config.json
{
  "mcpServers": {
    "nemodleo-easel": {
      "command": "npx",
      "args": [
        "-y",
        "easel-canvas"
      ]
    }
  }
}

same format Cursor, GitHub Copilot CLI, Junie, JetBrains AI Assistant, Augment (Auggie CLI), Factory Droid, Kiro, Devin CLI +12

Values in angle brackets are placeholders. Restart Claude Desktop after editing its config.Claude Desktop docs

README

synced Oct 26, 2026

Easel

An infinite canvas for HTML screens. Your AI agent writes the designs; you see and tweak them live.

npm License: MIT Node MCP Works with

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 --demo

That 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/*.html

Why Easel

  • HTML is the source of truth. Each screens/*.html file 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 -p or codex exec with 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.1 and 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 arrange

Using 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:4317
  • The default design folder is ../../docs/design relative to the tool, so tools/easel opens your docs/design with 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/checkout default) is unaffected.
  • To update: push to this repo, then run git submodule update --remote tools/easel in your project and commit the new pointer. Teammates run npm run design:install after git pull.
To do thisHow
Pan and zoomDrag empty space, Space, or Hand (H); trackpad scroll; ⌘+wheel or pinch (4–400%). ⇧1 Fit all, ⇧2 selection, ⌘0 Zoom to 100%, Minimap (M)
FindLeft "Boards" tab: ⌘K search and list; pages (drag to reorder; right-click to rename, delete, or set the launch page)
BoardsDraw 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 itemsDrag on empty space to marquee-select or use Shift; move together (snap guides, Alt to disable); arrow keys 1, Shift 10, Option 100
Board optionsRight "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
ViewFocus view (F, ←→), Play in place (P or ▶, Esc), Play full screen (right-click)
Notes and shapesTitle (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 modeDouble-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 editingMove 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 systemRegister tokens (tokens.json) and themes in the left "Tokens" tab, Theme menu in the toolbar, Token check and Accessibility lists on the right
CollaborationComments (Reply, Resolve, author), Snapshot menu (git-commits only the design folder)
AIRight "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
ScreenF6 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 themes
  • A 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 source
  • test/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. Set DESIGN_CANVAS_E2E_DIR=<folder> to run the e2e tests against another design folder.
  • examples/demo/ is the "Tidy" demo used for the screenshots above.
FolderContents
bin/server.mjs (app server), mcp.mjs (MCP stdio server)
server/API and routes, board.json, file watching, element paths and hashes, source patching, history, chat runner, tokens
app/Canvas UI (Vite + React + TypeScript); all UI text lives in app/src/strings.ts
test/node --test unit tests and Playwright e2e tests

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

↑↓ navigate openesc close