Canvas sync
Local-first, open-source alternative to Anthropic's Claude Design. MIT-licensed, BYO agent CLI — Claude Code, Kimi, Codex, or any SDK-compatible model. Composable skills · three edit paths · designs as plain HTML/JSX/CSS folders · run locally, no cloud round-trip. Generate banners, thumbnails, websites, animations, design systems.
npx -y skills add aiatelie/ai-atelie --skill canvas-syncAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 7 stars7 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Keep the canvas surface coherent across its three places — the canonical starter at `mcp/starters/DesignCanvas.jsx`, the byte-identical demo copy at `web/projects/demo/design-canvas.jsx`, and the host-side wiring in `web/src/lib/tweakBridge.ts` plus `mcp/CANVAS_PROTOCOL.md`. Use whenever the diff touches any of those files, or when the user says "fix the canvas", "update DesignCanvas", "tweak the design canvas", "the canvas isn't working in new projects", or anything similar. Without this rule, fixes land in one place and silently miss the other — the demo project tests stale code, or new projects get content that doesn't match what's been verified.
SKILL.md
9.9 KB, as published. Nobody here has run it
canvas-sync
A contributor workflow for AI Atelie. The DesignCanvas surface (the pannable, zoomable workspace that wraps every project's content) lives in three places at once, and a change to one without the others is almost always a bug.
This skill is dev-time only. It does not load into adapter sessions spawned by the editor.
The three places, and what each one is for
| Location | Role | Loaded when |
|---|---|---|
mcp/starters/DesignCanvas.jsx | Canonical source of truth. The starter the agent copies via mcp__starters__copy_starter and the route POST /api/projects/create reads to seed every new project. | An agent calls copy_starter in an existing project · A user creates a new project. |
web/projects/demo/design-canvas.jsx | Demo project's copy. The "AI Atelie demo" project that ships in the repo and renders on first run. | A user opens the demo from /projects (e.g. via home-shows-demo journey, or anyone testing locally). |
web/src/lib/tweakBridge.ts + mcp/CANVAS_PROTOCOL.md | Host-side wiring. The parent's listener for __page_is_canvas, the __dc_set_theme broadcast, and the documented protocol contract. | The editor mounts an iframe that announces __page_is_canvas. |
The parity rule
The two .jsx files MUST be byte-identical at every commit. They are not "two copies that drift" — they are two materializations of one source. Verify with:
md5 mcp/starters/DesignCanvas.jsx web/projects/demo/design-canvas.jsx
# (Linux: md5sum)
The two hashes must match. If they don't, stop and reconcile before committing.
The flow direction
Always edit the canonical first, then mirror — never the other way around. The canonical is the file every NEW project copies; the demo is just a testbed.
# 1. Edit the canonical
$EDITOR mcp/starters/DesignCanvas.jsx
# 2. Mirror to the demo
cp mcp/starters/DesignCanvas.jsx web/projects/demo/design-canvas.jsx
# 3. Verify they match
md5 mcp/starters/DesignCanvas.jsx web/projects/demo/design-canvas.jsx
# 4. Both files go in the same commit
git add mcp/starters/DesignCanvas.jsx web/projects/demo/design-canvas.jsx
Why both, and what breaks if you skip one
- Canonical only, no demo mirror — your changes ship to brand-new projects (via
POST /api/projects/createreading the canonical), but the demo project that everyone uses to test still runs the old code. You think you've verified the change; you haven't. The journey suite (which exercises the demo viahome-shows-demo) exercises stale behavior. - Demo only, no canonical mirror — your changes are visible in the demo but every new project the user creates gets the OLD canvas. First-run users see the wrong thing; the demo lies.
- Both
.jsxfiles but no host-side update — the iframe protocol expects something the host doesn't send (or vice versa). Silent misbehavior — the canvas mounts but the theme isn't pushed, or the viewport doesn't react to the toolbar zoom. - Host-side update without protocol doc — the next contributor adds a third type with no idea the second exists. Documentation drift compounds.
When the host wiring needs to change too
If your edit adds or changes a postMessage type — anything starting with __dc_* or __page_is_canvas — you also need to:
- Update
web/src/lib/tweakBridge.tswith the new send or receive logic. The bridge owns the host side of every iframe-↔-host message pair; new types live there. - Update
mcp/CANVAS_PROTOCOL.mdwith the new type, payload schema, direction, and side-effects. The protocol doc is the canonical contract — third-party starters read it; future contributors read it; it must not lie. - Update both
.jsxfiles as above so the iframe side speaks the new type too.
A diff that touches the iframe's postMessage handlers but leaves tweakBridge.ts untouched is suspect. A diff that adds a __dc_* type but leaves CANVAS_PROTOCOL.md untouched is suspect.
Hard rules — and what to do INSTEAD
- Don't edit only one of the two
.jsxfiles. INSTEAD: edit the canonical, mirror withcp, verify withmd5, commit both together. The demo copy is not a "live" file — it's a snapshot. - Don't edit
web/projects/demo/design-canvas.jsxfirst andcpback. INSTEAD: canonical first, every time. The demo is downstream. Editing it directly inverts the flow and creates merge confusion when the canonical is later updated by someone else. - Don't add a postMessage type without updating
mcp/CANVAS_PROTOCOL.md. INSTEAD: same commit adds the new type to the protocol doc with a payload schema, a direction, and one sentence on what receipt is supposed to do. - Don't assume the agent's
copy_starteris the only consumer ofmcp/starters/. INSTEAD: remember thatPOST /api/projects/create(inapi/src/routes/projects.ts) also readsmcp/starters/DesignCanvas.jsxat create time. Two distinct consumers; the canonical must satisfy both. - Don't update existing user projects'
design-canvas.jsx. INSTEAD: only the demo (which ships as part of the repo) is in version control. User projects underweb/projects/p_*/are user data — gitignored. They keep whatever copy was current at the time they were created. If the user wants the latest canvas in an existing project, the agent re-runscopy_starterfor them.
When to invoke
- The diff touches
mcp/starters/DesignCanvas.jsx,web/projects/demo/design-canvas.jsx,web/src/lib/tweakBridge.ts, ormcp/CANVAS_PROTOCOL.md. - The diff adds, removes, or renames any postMessage type whose name starts with
__dc_or__page_is_canvas. - The user says "fix the canvas", "the canvas isn't working in new projects", "update DesignCanvas", "tweak the design canvas", "add a feature to the canvas", or "why does the demo behave differently from new projects".
Skip when:
- The diff is in
mcp/starters/but for a non-canvas starter (e.g.Stage16x9.jsx,Stage9x16.jsx,LowerThird.jsx) AND those starters have no demo copy. Sister starters can graduate to the same parity rule — see "Future starters" below. - The diff is in
web/projects/demo/but in a file that isn'tdesign-canvas.jsx(e.g.Banner.jsx, the demo'sindex.htmlcontent). Those are demo-specific content, not a canonical starter mirror.
Workflow (paste this into your reply and tick as you go)
- Read both files. Open
mcp/starters/DesignCanvas.jsxand confirmmd5 mcp/starters/DesignCanvas.jsx web/projects/demo/design-canvas.jsxalready match (sanity baseline). - Edit the canonical only. All edits land in
mcp/starters/DesignCanvas.jsx. - Mirror.
cp mcp/starters/DesignCanvas.jsx web/projects/demo/design-canvas.jsx - Verify parity.
md5 mcp/starters/DesignCanvas.jsx web/projects/demo/design-canvas.jsx— both hashes match. - If postMessage protocol changed — update
web/src/lib/tweakBridge.ts(host side) ANDmcp/CANVAS_PROTOCOL.md(contract). - Stage everything together.
git add mcp/starters/DesignCanvas.jsx web/projects/demo/design-canvas.jsx(and the host-side files if they changed). - Commit via
.claude/skills/semantic-commit/SKILL.mdwithscope=mcpfor canvas-only changes, orscope=repoif the diff spans starters + host side. - If the change is user-visible — add a
--taskspec or useverify-with-playwrightso the journey evidence on the PR shows the new behavior in the canvas, not just in the chrome.
Future starters
The parity rule generalizes. Today only DesignCanvas.jsx has a demo mirror — but as soon as another starter (Stage9x16.jsx, Stage16x9.jsx, LowerThird.jsx, future animations.jsx) gets used inside the demo project, the same byte-identical rule kicks in for that file.
Forward-compatible workflow when adopting:
- Decide whether the demo wants to USE the starter (i.e. the demo's
index.htmlreferences it). - If yes, copy
mcp/starters/<Name>.jsx→web/projects/demo/<name>.jsx(note the case difference is the existing convention — kebab-case in the demo, PascalCase inmcp/starters/). - From that point on, every edit to the canonical mirrors to the demo copy.
When this happens, update the table at the top of this skill and the parity rule below it.
See also
mcp/CANVAS_PROTOCOL.md— the postMessage contract between host and canvas iframes.mcp/starters/DesignCanvas.jsx— canonical canvas source.web/projects/demo/design-canvas.jsx— demo project's mirror.web/src/lib/tweakBridge.ts— host bridge owning__page_is_canvasreceive +__dc_set_themesend.api/src/routes/projects.ts—POST /api/projects/createreadsmcp/starters/DesignCanvas.jsxat create time and writes it into the new project..claude/skills/frontend-design/SKILL.md— the chrome-aesthetic skill that fires forweb/src/changes, including anytweakBridge.tsedit that's user-visible..claude/skills/verify-with-playwright/SKILL.md— capture canvas evidence after a change.