# UI Canvas

> Before writing any system-UI code, hand the user a draggable wireframe canvas so screens, layout, and content become a contract you both signed off on — then write the code. Use it whenever the user wants to build, rebuild, or imitate an interface: admin panels, consoles, dashboards, internal tools, multi-screen apps, role/permission systems, form flows, list-detail pages, mobile screens — or says "build me a system", "set up the frontend", "just make it look however", "show me what it'll look like first". 后台管理系统、控制台、数据看板、多屏应用、权限系统、表单流程、"帮我做个系统"、"先把前端搭起来"、"界面你看着办"、"先给我看看长什么样". Fire even if the user never says "wireframe" or "prototype". Skip for: styling tweaks to one component, visual polish on an existing page, backend-only or non-UI work, or a layout the user already spelled out block by block.

- Skill: `mrkery-dotcom/ui-canvas` (Agent Skill, multi-file: 7 files)
- Install (CLI): `npx skillmds@latest add mrkery-dotcom/ui-canvas`
- Raw SKILL.md: https://api.skillmd.com/api/skills/mrkery-dotcom/ui-canvas/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Web & Frontend
- Author: mrkery-dotcom (https://skillmd.com/u/mrkery-dotcom)
- Updated: 2026-09-22
- Page: https://skillmd.com/skills/mrkery-dotcom/ui-canvas

---


# UI Canvas

The biggest waste in building an interface is not slow code generation — it is **guessing wrong**. Guess the direction wrong once, and the cost of redoing a version far exceeds the cost of generating one.

This skill's approach: first pin down the layout, the screen breakdown, and the amount of content as a contract using a wireframe the user has **dragged with their own hands**, and only then write code. It is much faster for a user to change a diagram than to describe a requirement, and once the AI has explicit coordinates it basically will not guess wrong.

## When it is worth it, and when it is not

The canvas costs the user 5–15 minutes of attention. Use it only when the cost of "guessing wrong once" clearly exceeds that.

| Situation | What to do |
|---|---|
| A single component, a styling tweak, pure logic | No canvas, just do it |
| A single screen, a small page whose structure is obvious | No canvas. Ship a runnable first version — it is faster to let the user point at it and ask for changes |
| Multi-screen systems, admin backends, consoles, dashboards | **Use the canvas.** This is its home turf |
| Multiple roles / permission differences / complex states | **Use the canvas.** States and role differences are exactly the part that is hardest to explain in prose and easiest for an AI to guess wrong |
| The user cannot say what they want, or says "do whatever you think" | **Use the canvas.** Handing them a written proposal here is the same as making them read an essay |
| The user has already described the layout block by block | No canvas, just do it |

In one sentence: **the more screens there are and the less clearly the user can articulate them, the more it is worth it.**

## Step 1: Turn the requirement into a seed

**Do not hand the user a blank canvas.** A blank canvas is a procrastination machine — most people cannot draw a good layout, and they will stare at an empty box for ten minutes and then give up. Your job is to draw a first draft that they **can edit**.

- Read `references/schema.md` first; that is where the block type catalog and the coordinate reading strategies live.
- Extract the screen list from what the user said, 4–9 blocks per screen. Fewer than 3 blocks means you were lazy; more than 12 means you are making decisions on the user's behalf.
- **Pick the right device for each screen** (`screens[].device`). Device is per-screen: roles that are out in the field — inspectors, couriers, sales — get phone screens; roles that manage, configure, and watch dashboards get desktop. Mixing within one system is the norm, so do not set every screen to `desktop`.
- Give each block the area its real content volume deserves. A page that needs a table gets a table 8 rows tall, not 3 — density is part of the design, and half the value of the canvas is right here.
- **`note` holds declarative assumptions, not questions.** "Defaults to order time descending, amount right-aligned" is something the user can change into what they want at a glance; "How would you like it sorted?" turns `note` into a to-do list and forces the user to answer you item by item. You are here to put their thinking down on paper, not to send them a questionnaire.
- If you are not even sure which screens there are, **ask 2–3 questions before drawing**: who uses it, when do they open this page, and what is the one thing that matters most. A wireframe forced out of insufficient information is fiction; the user will tear it up and start over, which is worse than not drawing at all.
- For the feel of it, look at `examples/seed-shop-admin.json`.

Write the seed out as a JSON file (for example `.ui-canvas/seed.json`). Do not try to edit `assets/canvas.html` — it is 45KB, and reading it into context and rewriting it is both expensive and error-prone.

## Step 2: Generate and open the canvas

```bash
node <skill-dir>/scripts/make-canvas.mjs <seed.json> <project-dir> --open
```

The script injects the seed into the template, assigns a standalone canvas ID, writes `ui-canvas.html`, and — with `--open` — launches it in the default browser. Drop `--open` if you would rather hand the user a path. If there is no Node, see the fallback at the end of SKILL.md.

**Set the canvas language to match the conversation.** The canvas UI ships in English and Chinese, resolved in this order: `?lang=` query parameter → `meta.lang` in the seed → browser language → English. If you are talking to the user in Chinese, put `"lang": "zh"` in the seed's `meta` so the tool matches the language they are already using. This only affects the canvas chrome; block labels and notes are the user's data and are never translated.

Then tell the user only three things. Do not write an operating manual:

> Click on the left or drag onto the canvas to add a block; once it is selected, drag a corner to resize it; in the note field on the right, write clearly what actually goes in that block (especially "I haven't decided this part yet"). When you are done, click "Export JSON" in the top right, select all, copy it, and paste it back to me.

## Step 3: Read the JSON back and produce the contract

After the user pastes the JSON back, **do not immediately start writing code**. First produce this contract and let them glance over it:

```markdown
## Screen map
| Screen | Who comes here, and when | What they need to accomplish |

## Layout contract
### <screen name>
| Block | Type | x/y/w/h | What content goes in it | Hard constraints from the user's note |

## Component inventory (deduplicated across screens)
Do not let the same thing be implemented three times across three pages. This step
specifically hunts for the repeats, the kind where
"the order list and the order detail each have their own status tag".

## State matrix
For **every** interactive block, write out what each of loading / empty / error /
no-permission / over-limit looks like. Per block, not once for the whole system.

Do it this way because of which states get forgotten. The dramatic failures tend to
get covered — someone always writes down what happens when a tablet loses wifi
mid-entry. The quiet ones get skipped: what the screen shows when the queue is empty,
what a user without permission sees instead of a blank 403, what happens at row
10,001. Those are the states that decide whether the thing feels finished, and they
are the ones a reader can point at and reject.

## Defaults I will adopt (you can veto these)
## Questions I need you to confirm (at most 3, ordered by impact)
```

**"Defaults I will adopt" is the single most important mechanism in this whole flow.** The canvas cannot express color, type, motion, microcopy, or states — but you also cannot go ask about each one, because that turns one canvas round trip into twenty rounds of Q&A. The right move is: pick the defaults using your professional judgment, **write them down**, and let the user scan them and veto whatever is wrong.

The difference between writing them down and assuming them silently is everything: in the first case the user spends 10 seconds vetoing one item; in the second, the user discovers it is wrong after you have written 2000 lines of code.

## What the canvas cannot express

These **may not be decided silently**; they must appear in the contract's "defaults" or "to confirm" section:

- Color, theme, dark mode, brand tone
- Typography and the font-size scale
- Motion and transitions
- Microcopy (does the button say "Save" or "Submit changes")
- What loading / empty / error / no-permission / over-limit actually look like
- Responsive breakpoint behavior (the canvas only has the three approximations desktop/tablet/mobile)
- Tech stack, component library, whether an existing design system is in place
- Accessibility requirements, internationalization, time zone and currency formats
- Pagination, virtual scrolling, data volume ceilings

## Step 4: Write the code according to the contract

- **One block = one component.** The coordinates are layout intent; the `note` is a hard constraint.
- Map the layout onto a 12-column grid. `references/schema.md` has three legal reading strategies; pick the one that matches your tech stack.
- Implement the deduplicated component inventory first, then assemble the pages.
- **Finally, go through the notes block by block**: every constraint the user wrote has to be traceable to a landing spot in the code. This is an acceptance checklist handed to you for free — do not waste it.

## When the user wants a second round of changes

The canvas in the user's hands auto-saves a draft, so **have them edit the original canvas directly** and then export again. Do not re-run the script — that generates a new canvas ID and wipes out their changes. Only regenerate the seed when the user explicitly says "scrap it and start over".

## Delivery quality floor

You may be working standalone, with no other design skill to catch you. Hold these lines while writing code, or you will produce the classic AI template face:

- **Use real content volume, not Lorem ipsum.** An empty-shell interface hides layout problems.
- **One accent color.** Not three. A neutral scale plus one brand color covers 95% of system UI.
- **A 4–6 step font-size scale, spacing in multiples of 4/8.** Off-the-cuff 13px/17px makes an interface look dirty.
- **Every clickable element needs hover, focus, and disabled.** The focus state is the floor for keyboard usability.
- **Empty, loading, and error states are mandatory.** Implementing only the "has data" case is the most common half-finished job.
- **Table numbers right-aligned, with tabular figures** (`font-variant-numeric: tabular-nums`).
- **Body text contrast ≥ 4.5:1**; do not write in light gray.
- **Do not** do a centered big headline + three cards + a purple gradient. System UI does not need that.
- **Mark your own inventions as deletable.** Anything you added that the user never asked for is a proposal, not a requirement. Say so where you added it ("deletable if the clinic takes no walk-ins"), and keep one explicit list of what you deliberately did *not* build. The failure mode is escalating your own guess into an acceptance criterion, at which point the user has to argue you out of it — and they will not, because it looks like it was decided on purpose.
- If a design system already exists (Ant Design, shadcn, Carbon, Material), use it — do not hand-roll colors and corner radii.

## Files

- `assets/canvas.html` — the canvas itself. Single file, zero dependencies, openable offline, and the user's data is stored locally in the browser.
- `scripts/make-canvas.mjs` — injects the seed into the template and generates an openable `ui-canvas.html`.
- `references/schema.md` — the JSON contract structure, the coordinate reading strategies, and the block type catalog. **Read it before every use.**
- `examples/seed-shop-admin.json` — what a decent seed looks like.

**Fallback when there is no Node** (PowerShell):

```powershell
$t = Get-Content "<skill-dir>\assets\canvas.html" -Raw -Encoding UTF8
$s = Get-Content seed.json -Raw -Encoding UTF8
$t.Replace('window.__UI_CANVAS_SEED__ = null;', "window.__UI_CANVAS_SEED__ = $s") |
  Set-Content ui-canvas.html -Encoding UTF8
```

The seed must be a single valid JSON object; injected this way it becomes a valid JS object literal.

