Centinadocs

Spacing tokens — use-case guide

Every canvas carries a named spacing scale — seeded xs 4 · sm 8 · md 16 · lg 24 · xl 32 · 2xl 48 · 3xl 64, fully editable — and any spacing field (flex gap, grid row/column gap, padding, margin) can bind to a token instead of holding a loose number. Bound fields follow the token: change md once and every bound node across every page re-spaces, in one undo step. Bindings live beside the px values, so exports and code generation are untouched — the CSS is always real. Margin binds on ANY node type — text in a flex row is the classic case — where gap/padding are box-only.

Try it: draw a box (B), drop two boxes inside, select the parent, switch Display to Flex, and click the diamond at the end of the Gap field.

Reading the chrome

  • Hollow diamond at a field's end — unbound; click to open the picker.
  • Filled accent diamond + accent chip (md) beside the value — bound.
  • Half-lit diamond, no chip — the selection (or a linked pair like padding X) disagrees; picking a token re-unifies.
  • On canvas, bound padding/margin/gap bands tint accent and show the token name at full guide intensity. Unbound margin bands wear margin orange (the same ink as the Compass extension's box-model view), padding green, gap purple hatch.

Use cases

Bind a field to a token

  1. Click the diamond at the right end of any spacing input.
  2. The picker opens: rows in value order, xs · 4 through 3xl · 64.
  3. Hover (or arrow) down the rows — the canvas previews each token live.
  4. Click a row or press Enter.

The field shows the accent chip + the token's px. Binding + px land as one undo step. Multi-select fans the binding out to every selected box.

Preview without committing

Open the picker, hover to compare spacings, then press Escape or click outside. The canvas reverts exactly — previews never touch history.

Walk a bound field through the scale

  • Scrub the field's label: the value steps token-to-token (16 → 24 → 32), chip following, never landing between tokens and never detaching. The whole scrub is one undo step.
  • ↑/↓ in the field: one token per press. The ends of the scale hold — arrows never detach.

Detach

By declared intent, three ways:

  • Type a number — explicit raw intent: detaches and takes the exact px.
  • Alt-scrub — detaches and scrubs raw px (Alt trades away fine-scrub on bound fields only; spacing is integer px).
  • Picker → Detach — keeps the current px, drops the link. Disabled (not hidden) when the field isn't bound.

Change a token's value everywhere

  1. Any picker → Manage tokens….
  2. Scrub or type the token's value.
  3. Every bound box on every page re-spaces live; release seals one undo step covering the table and all boxes. Escape mid-scrub rolls back.

Rename, add, delete tokens

In the manage view:

  • Rename — click the name, type, Enter. Bindings survive renames — every chip re-labels and nothing orphans. Empty/duplicate names are rejected inline.
  • Add+ Add token appears with the next free t-shirt name; the picker keeps rows value-sorted.
  • Delete — bound fields keep their current px and detach. One entry: undo restores the token and its bindings.

Drag spacing on the canvas

With a single node selected, grip pills appear for both of its roles (per the CSS box model — no display or flow gates): any box gets pills on every nonzero padding band, a flex box adds gap-band pills (grid gaps keep the grid editor's own pills, same math), and any node gets pills on every nonzero margin band, outside the box. A flex box inside a flex parent shows both sets — padding pills inside, margin pills outside.

  • Drag — a live badge follows: md · 16 when magnetically snapped on-token (8 screen px radius), plain px between tokens. The growth mnemonic is one rule: dragging away from the box edge grows the spacing — inward for padding, outward for margin.
  • ⌥-drag (padding/margin pills) — symmetric: the opposite side follows, both sides becoming identical. Landing on a token rebinds BOTH sides; a raw frame writes both raw, detaching whichever was bound. Releasing ⌥ mid-drag restores the opposite side's starting px and binding exactly.
  • ⌘-drag — raw px, no magnet; detaches if bound.
  • Escape mid-drag — cancels and restores the exact starting values, opposite side included.
  • Bound fields step the scale as you drag and stay bound; unbound fields snap to token values only — snap ≠ bind. Landing on 16 writes 16px; binding is always an explicit picker act, so casual drags can't quietly couple boxes to the scale.

Spacing of zero shows no pill — creation-from-zero stays in the inspector (no invisible hover zones).

Resize to the scale

Dragging a resize handle magnets the box's width/height onto token values — same 8-screen-px radius as the pills, per axis independently. The cursor badge speaks the pill vocabulary: md · 16 on a hit; a corner drag landing both axes on different tokens reads xl × lg (W × H order), a square landing on one token collapses back to md · 16. ⌘ resizes raw (no token or guide snap), a canvas-guide edge snap wins its axis, and shift (aspect/scale) never token-snaps. Snap ≠ bind holds here too — width/height are not bindable; a hit writes plain px.

Linked padding & margin

The Padding X field writes left+right, Y writes top+bottom; binding one binds both sides in one entry. Sides bound to different tokens read as diverged (half-lit diamond) — pick to re-unify or edit per-side. Both live in the "Padding & Margin" section, which renders for any selection per the CSS box model: padding on any box whatever its Display (greyed "Boxes only" for non-box selections), margin on any node — out of flow it composes with x/y (left/top position the margin edge). Margin clamps ≥ 0 like padding, with raw CSS in Other styles as the negative-margin escape hatch.

Co-editing

When several people share a canvas, token scrubs stream to same-page guests live; guests on other pages see the change land once, at release. Concurrent edits to the same token resolve last-writer-wins. View-only guests get an inert inspector.

Agents (MCP)

get_canvas_info returns spacingTokens; get_node_info includes any node's spacing bindings (margin binds on non-boxes too). An update_styles patch that writes raw px over a bound field clears the binding in the same batch — a binding never lies about its value; layout.margin per-side writes reject negatives (rawCss is the escape hatch). Token create/rename/delete and binding via MCP is deliberately not offered yet.

Interaction semantics

SurfaceActEffectUndo / cancel
Field diamondclickOpens picker (toggle)
Picker rowhover / arrowsLive preview on canvasEscape/outside reverts exactly
Picker rowclick / EnterBinds token: binding + pxOne step
Picker DetachclickClears binding, keeps pxOne step
Bound field labelscrubSteps the scale, stays boundOne step per scrub; Escape N/A (label scrub has no cancel, undo instead)
Bound field↑ / ↓One token per press; ends holdOne step per press
Bound fieldtype pxDetaches + writes px togetherOne step
Bound field labelAlt-scrubDetaches + raw scrubOne step
Manage valuescrub / typeTable write + fan-out to all bound boxesOne step; Escape rolls back a live scrub
Manage nametype + EnterRenames; bindings surviveOne step; Escape cancels the edit
Manage deleteclickRemoves token, detaches bound fields, px keptOne step restores both
Canvas pad/margin/gap pilldragSnaps to token values (badge md · 16); bound fields re-bind per stepOne step; Escape restores exactly
Canvas pad/margin pill⌥-dragOpposite side follows (identical value + binding)One step covers both sides; Escape restores both; releasing ⌥ restores the opposite side
Canvas pill⌘-dragRaw px; detaches if boundOne step; Escape restores
Resize handledragW/H magnet to token values (badge md · 16; corners per-axis, xl × lg when both land) — snap ≠ bind, plain px; guide snap wins its axisOne step; Escape restores exactly
Resize handle⌘-dragRaw px — no token or guide snapOne step

Known limits (by design)

  • Raw CSS in Other styles can visually contradict a binding — the same escape-hatch opacity as everywhere else.
  • A remote guest on another page sees a token scrub land once at release, not per-frame.
  • Concurrent edits to the same token: last write wins.