Skip to main content
Glama

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

Related MCP server: pulp

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 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 (tokens.json) and themes in the left "Tokens" tab, Theme menu in the toolbar, Token check and Accessibility lists on the right

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

Folder

Contents

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

Related MCP Connectors

Related MCP Servers

  • A
    license
    Not graded
    quality
    C
    maintenance
    MCP server that enables AI coding agents to read and write to a local-first HTML/CSS design canvas, bridging visual design and code generation.
    1
    MIT
  • A
    license
    Not graded
    quality
    D
    maintenance
    Enables 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 npm
    1
    LGPL 3.0
  • A
    license
    Not graded
    quality
    A
    maintenance
    Open-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 npm
    875
    AGPL 3.0
  • A
    license
    Not graded
    quality
    C
    maintenance
    Enables 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 npm
    MIT