Design tokens

Variables for a canvas — colours, spacing, radii and type that every frame and agent shares.

A design token is a named value a canvas owns: color-primary, radius-card, font-heading. Frames use it as an ordinary CSS variable, var(--color-primary), so changing the token once restyles every frame that names it — the person who edits in the Design panel and the agent that writes HTML over MCP are reading the same list. Tokens carry a value per theme, so one frame can switch to dark, compact or a brand variant without a second copy of the design. If you have used variables in Figma or tokens in Paper, this is the same idea.

What a token is

Every token has a type, a name, a value and an optional note on when to reach for it. There are eleven types, in three groups:

Names are typed without the leading dashes (color-primary) and used in CSS with them (var(--color-primary)). Letters, digits, hyphens and underscores are allowed; spaces become hyphens. A name is unique on its canvas, and a canvas holds up to 500 tokens.

A value is one CSS value — #0177d3, 12px, 'Inter', sans-serif, 1.4. It can also be var(--other-token), which aliases another token on the same canvas: color-button pointing at color-primary, say. Aliases must resolve, and a token another token aliases cannot be deleted until the alias is repointed.

Create and edit tokens

Open the Layers panel and switch to its Tokens tab (the braces icon; the collapsed rail has the same button). The tab lists the canvas's tokens folded by type, like frames in the layer tree. Press + beside the Tokens heading, pick a type, and the new token opens with a suggested name (color-2, radius-1) and a default value for its type. Each type gets a fitting control: a swatch and hex field for colours, font and weight lists for type, a number with its unit for everything else — drag the glyph at the left of a number to scrub it, as in the Design panel. Enter saves.

Click a token to edit it, rename it, add a note, or delete it. A rename rewrites every var(--old-name) in every frame and in any token that aliased it, so nothing breaks. A delete leaves frames naming the token; they fall back to whatever default they wrote until a token of that name exists again.

Bind a field in the Design panel

You rarely need the Tokens tab to use a token. Select an element and the Design panel's fill, stroke and text colour, corner radius, font size, font family and font weight fields each carry a braces button — it appears over the field's unit on hover, or beside the font selects. Click it to pick from the canvas's tokens of that kind; the field now writes var(--name) and shows the token as a chip with its resolved swatch. The broken-chain button beside the chip detaches it back to the literal value.

The same menu has a +: it takes the field's current value, asks for a name, and creates the token and binds the field in one step — Figma's "create variable from this fill", for any of the seven fields.

Themes

Every canvas has a default theme, the value you set first. Up to eight more — dark, compact, brand-b, any lowercase slug — give a token a second value where it should differ. In the token editor a segmented switch flips between default and each theme; a dot marks a theme that overrides, and the reset beside the field puts it back to following the default. A theme is declared the first time a token names it, or from the Themes heading's + in the Tokens tab. Right-click a theme row to rename it (its values follow) or delete it (its values go with it).

A frame picks its theme with one attribute on its root: <html data-doop-theme="dark">. Put the same attribute on a subtree to theme only part of a frame. On the canvas, selecting a theme row in the Tokens tab switches the selected frames to it — or every frame on the page when nothing is selected — one undo step per frame.

How frames carry tokens

A frame is always a self-contained HTML document, so Doop writes the values of the tokens a frame names into a managed <style data-doop-tokens> block at the top of its <head>: a :root { … } rule with the defaults, then one rule per theme with its overrides. Screenshots, exports and anything else that reads the frame's HTML get the right values with no extra lookup.

When a token changes, Doop rewrites that block in every frame on the canvas that names it. This is a restyle, not a redesign: a frame marked ready for dev keeps its sign-off, no version is filed, and the activity feed gets one line naming the token and how many frames followed. Leave the block alone — it is regenerated on every save.

Tokens for agents

An agent connected over MCP sees the canvas's tokens and themes in get_canvas, with a brief telling it to use var(--name) rather than literal values, and has four tools of its own. The Doop Agent has the same four.

A brief that leans on tokens tends to produce consistent work across many frames and agents:

Set up tokens for this canvas from the imported homepage — a colour scale, a 4px
spacing scale, two radii and the type ramp — with a dark theme. Then rebuild the
pricing page using only tokens, no literal colours or sizes.

Export tokens to code

Tokens are meant to leave the canvas. Three formats are available from the REST API and from get_tokens:

# JSON by default; ?format=css | tailwind | md
$ curl https://doop.design/api/canvases/<canvas-id>/tokens?format=tailwind
# tokens as tables + the :root CSS, followed by every style guide on the canvas
$ curl https://doop.design/api/canvases/<canvas-id>/styleguide.md

styleguide.md is the one file a coding agent needs: the tokens as tables, the CSS block, then every style guide written on the canvas. Drop it into a repo as its DESIGN.md and the implementation starts from the same values the design used.

Tips