Design System Contracts

Spec reference

Shape parts

Parametric vector decor — triangles, ellipses, rotated rects — carried as geometry, projected as clip-paths in code and real vector nodes on the canvas.

Shape partsGeneratedCurated#

A leaf decor part that is a parametric vector, not a box — the projection of capture-geometry into the contract (field case: a tooltip’s pointer triangle). Bounded by construction: exactly three kinds — polygon by side count, ellipse, rect — an explicit intrinsic size, and a CSS-clockwise rotation. Everything else about a shape rides existing channels: fill via tokens.background-color, per-variant placement via stylesWhen, visibility via visibleWhen.

kindrequired"polygon" | "ellipse" | "rect"

polygon | ellipse | rect.

sidesnumber

Polygon point count, ≥ 3. A polygon with no captured side count renders the canvas default (3) — and the proposer names that assumption in its notes.

widthrequirednumber

Intrinsic (pre-rotation) width, px.

heightrequirednumber

Intrinsic (pre-rotation) height, px.

rotationnumber

CSS-clockwise degrees. Omit for 0.

arc{ start: number; end: number; innerRadius: number }

Ellipse-only partial sweep — see ellipse arcs.

Projections: code surfaces render width/height + clip-path: polygon(…) (or border-radius: 50%) + transform: rotate(…) — one shared implementation (shapeCssDecls in the schema module) so the projection cannot fork across emitters; the canvas generator constructs a real RegularPolygon/Ellipse/Rectangle node with native rotation.

Refusals: Each of these fails the build by name — the generator refuses, it never papers over (source: core/emit-react.ts validateContract, exercised by the C2 eval family).

  • a shape part must be a leaf — no parts, slot, component, content, text, icon, or meter alongside it
  • sides only on polygons — side count is polygon vocabulary
proposed at build time by the import engine from the committed live capture extract/figma/fixtures/cbds-tooltip.rest-dump.json — the CBDS Tooltip pointer: a real triangle with per-placement stylesWhen insets and rotation
{
  "Pointer": {
    "shape": {
      "kind": "polygon",
      "sides": 3,
      "width": 12,
      "height": 12
    },
    "tokens": {
      "background-color": "{imported.tooltip.pointer.background-color}"
    },
    "visibleWhen": {
      "prop": "pointer"
    },
    "stylesWhen": [
      {
        "prop": "pointerPosition",
        "equals": "topRight",
        "styles": {
          "position": "absolute",
          "right": "12px",
          "top": "-8px"
        }
      },
      {
        "prop": "pointerPosition",
        "equals": "none",
        "styles": {
          "display": "none"
        }
      },
      {
        "prop": "pointerPosition",
        "equals": "bottomRight",
        "styles": {
          "position": "absolute",
          "right": "12px",
          "bottom": "-8px",
          "transform": "rotate(180deg)"
        }
      }
    ]
  }
}

Every value above — the 12×12 intrinsic size, each inset, each rotation — comes from the captured file, not from this page. The standing receipt for this field case is npm run extract:figma:tooltip:check.

Ellipse arcsGeneratedCurated#

shape.arc — partial-sweep geometry for an ellipse shape (a spinner’s three-quarter ring, a donut gauge), carried as Figma Plugin-API ArcData radians, verbatim: 0 at 3 o’clock, increasing clockwise on screen. Ellipse-only vocabulary, and carried only when the sweep is partial (< 2π) and constant across variants — a full sweep is the plain ellipse, and an axis-varying sweep rides per-value stylesWhen mask rules instead (the rotation discipline).

startrequirednumber

Sweep start, radians — 0 at 3 o’clock, increasing clockwise on screen.

endrequirednumber

Sweep end, same convention.

innerRadiusrequirednumber

Figma’s donut-hole fraction, 0–1 — recorded for round-trip fidelity, see below.

Projections: code surfaces render the sweep as a conic-gradient mask over the part’s border-drawn ring — one spelling, arcMaskCss in the schema module, shared by every emitter so the projection cannot fork; the canvas generator sets native arcData (core/emit-figma-script.ts).

Refusals: Each of these fails the build by name — the generator refuses, it never papers over (source: core/emit-react.ts validateContract, exercised by the C2 eval family).

  • arc on a non-ellipse shape — sweep is ellipse vocabulary

Honest carriage: the mask’s hard color stops render butt caps — Figma’s stroke-cap style is not on the dump surface, a named residue. innerRadius at 1 (the observed class — a pure stroked ring) costs nothing: the border-drawn ring already leaves the hole. The proposer names innerRadius < 1 (a filled donut) instead of carrying it.

a three-quarter stroked ring — the sweep in ArcData radians — illustrative, schema-validated at build time
{
  "shape": {
    "kind": "ellipse",
    "width": 16,
    "height": 16,
    "arc": {
      "start": -1.5708,
      "end": 3.1416,
      "innerRadius": 1
    }
  },
  "tokens": {
    "border-color": "{color.icon.brand}"
  }
}