---
name: design-tokens-dtcg-format
source: https://app.decimal.ai/s/design-tokens-dtcg-format@1/SKILL.md
source_sha256: c47011aaf01a
---

# Design tokens — DTCG format

## Contract

When you output a design-tokens file (a `tokens.json` / design-system token set for a
Figma-to-code or Style-Dictionary pipeline), emit the **W3C Design Tokens Community Group
(DTCG) Format Module** exactly. This means `$`-prefixed reserved properties, the fixed
`$type` vocabulary, per-type value **objects** (not CSS strings), and curly-brace `{alias}`
references. Apply whenever the requested artifact is a machine-readable token file.

## Rules

1. **A token is a JSON object; `$value` is the only required property.** Optional reserved
   properties: `$type`, `$description`, `$extensions`, `$deprecated`. **Every reserved
   property begins with `$`.** A *group* is a plain object whose non-`$` keys are nested
   tokens or groups.
2. **Never use the bare keys `value`, `type`, `description`, `extensions`, `deprecated`.**
   Always the `$`-prefixed form (`$value`, `$type`, …). This is the single most common miss.
3. **`$type` comes from a closed vocabulary.** Atomic: `color` `dimension` `fontFamily`
   `fontWeight` `duration` `cubicBezier` `number`. Composite: `strokeStyle` `border`
   `transition` `shadow` `gradient` `typography`. Use these exact tokens — never `size`,
   `spacing`, `space`, `px`, `font`, `text`, `string`, or `boolean`.
4. **Set `$type` once on a group; children omit it.** A token with no `$type` inherits the
   `$type` of its nearest ancestor group; if its value is an alias, the type resolves from
   the referenced token. Do not repeat `$type` on every leaf when a group covers them.
5. **Reference another token with a curly-brace dot path:** `"$value": "{group.subgroup.token}"`.
   Never put a `$ref`, a `var(--x)`, an `@token`, or a copied hex literal in a `$value` to
   mean "same as". (A property-level `$ref` JSON Pointer exists for document access, but the
   *token-value* alias is the curly form.)
6. **Naming:** a token or group name **MUST NOT begin with `$`** and **MUST NOT contain
   `.`, `{`, or `}`** — those are reserved for the alias path syntax. Use nesting or hyphens
   instead of dots (`color.brand.primary` → nested `color` → `brand` → `primary`).
7. **Per-type `$value` shapes:**
   - **color** → object `{ "colorSpace": "srgb", "components": [r, g, b] }` with 0–1 channel
     numbers; optional `"alpha"` (0–1) and optional `"hex"` fallback. Not a bare `"#2563eb"` string.
   - **dimension** → object `{ "value": <number>, "unit": "px" | "rem" }`. Not `"16px"`.
   - **duration** → object `{ "value": <number>, "unit": "ms" | "s" }`. Not `"200ms"`.
   - **number** → a plain JSON number (opacity, z-index, unitless line-height, multipliers).
   - **fontFamily** → a single string, or an array of strings for a fallback stack.
   - **fontWeight** → an integer `1`–`1000`, or a lowercase hyphenated keyword alias:
     `thin` `hairline` `extra-light` `ultra-light` `light` `normal` `regular` `book`
     `medium` `semi-bold` `demi-bold` `bold` `extra-bold` `ultra-bold` `black` `heavy`
     `extra-black` `ultra-black`. Not `"Bold"`, not CSS `"bolder"`/`"lighter"`.
   - **cubicBezier** → an array of **exactly four numbers** `[x1, y1, x2, y2]` (x in `[0,1]`).
     Not `"ease-in-out"`, not `"cubic-bezier(0.4,0,0.2,1)"`.
   - **strokeStyle** → a keyword string from `{ solid dashed dotted double groove ridge
     outset inset }`, or an object `{ "dashArray": [<dimension>…], "lineCap": "round"|"butt"|"square" }`.
   - **border** → object `{ "color", "width", "style" }` (each a value or `{alias}`).
   - **transition** → object `{ "duration", "delay", "timingFunction" }`.
   - **shadow** → object `{ "color", "offsetX", "offsetY", "blur", "spread" }` (or an array
     of these for layered shadows). Not a `"0 1px 2px rgba(...)"` string.
   - **gradient** → an array of stops, each `{ "color", "position" }` with `position` in `[0,1]`.
   - **typography** → object `{ "fontFamily", "fontSize", "fontWeight", "lineHeight" }`.
8. **Tool/vendor data lives under `$extensions`** keyed by reverse-domain names
   (`"com.figma.tokens": {…}`), never as extra top-level keys on the token.
9. **Deprecate with `"$deprecated": true`** (or a string reason) — never a bare `deprecated`
   key and never a `// comment`.

## Worked examples

**Color — before (bare keys + hex string) → after:**
```json
// before
{ "color": { "primary": { "value": "#2563eb", "type": "color" } } }
// after
{ "color": { "$type": "color",
  "primary": { "$value": { "colorSpace": "srgb", "components": [0.145, 0.388, 0.922] } } } }
```

**Dimension — before → after:**
```json
// before  { "spacing": { "md": { "value": "16px", "type": "size" } } }
// after   { "spacing": { "$type": "dimension",
//            "md": { "$value": { "value": 16, "unit": "px" } } } }
```

**Alias — before (copy / $ref / var) → after (curly path):**
```json
// before  { "button": { "bg": { "$value": "#2563eb" } } }        // copied literal
// before  { "button": { "bg": { "$ref": "#/color/primary" } } }  // wrong: $ref in value
// after   { "button": { "bg": { "$value": "{color.primary}" } } }
```

**Typography composite — before (flat CSS-ish) → after:**
```json
// before  { "heading": { "value": "700 24px/1.2 Inter", "type": "font" } }
// after
{ "heading": { "$type": "typography", "$value": {
    "fontFamily": "Inter", "fontSize": { "value": 24, "unit": "px" },
    "fontWeight": "bold", "lineHeight": 1.2 } } }
```

**Shadow — before (CSS string) → after (object):**
```json
// before  { "elevation": { "1": { "$value": "0 1px 2px rgba(0,0,0,0.1)" } } }
// after
{ "elevation": { "1": { "$type": "shadow", "$value": {
    "color": { "colorSpace": "srgb", "components": [0,0,0], "alpha": 0.1 },
    "offsetX": { "value": 0, "unit": "px" }, "offsetY": { "value": 1, "unit": "px" },
    "blur": { "value": 2, "unit": "px" }, "spread": { "value": 0, "unit": "px" } } } } }
```

## Edge cases & exceptions

- **Aliased token has no `$type`** → its type resolves from the token it points at; do not
  invent one. `{ "$value": "{color.primary}" }` is a color because `color.primary` is.
- **A `hex` may accompany a color** as an optional convenience property inside the color
  object, but `colorSpace` + `components` remain the authoritative value.
- **Layered shadows** use an *array* of shadow objects; a single shadow is one object.
- **Property-level `$ref`** (JSON Pointer, `"#/…"`) is allowed for cross-document reuse of a
  *property*, but the ordinary "same value as another token" case uses the `{curly}` alias.
- **Unitless numbers** (opacity `0.5`, line-height multiplier `1.5`, z-index `10`) are
  `$type: "number"`, a plain JSON number — not a `dimension`, not a string.

## Do / Don't

- **Do** prefix every reserved property with `$`. **Don't** write `value`/`type`.
- **Do** make color/dimension/duration values **objects**. **Don't** use `"#hex"`, `"16px"`, `"200ms"`.
- **Do** reference with `"{group.token}"`. **Don't** use `$ref`, `var(--x)`, `@`, or a copied literal in `$value`.
- **Do** hoist `$type` to the group. **Don't** contradict it on children.
- **Do** keep names free of `.`/`{`/`}`/leading `$`. **Don't** name a token `"brand.primary"`.
- **Do** put tool data in `$extensions` (reverse-domain key). **Don't** add ad-hoc top-level keys.

## Common mistakes

- `"value"` / `"type"` without the `$` — the #1 non-conformance.
- `$type: "size"` or `"spacing"` instead of `"dimension"`; `"font"`/`"text"` instead of `"typography"`.
- Color as `"#2563eb"`, dimension as `"16px"`, duration as `"200ms"` (CSS strings, not objects).
- `cubicBezier` as `"ease-in-out"` instead of `[0.4, 0, 0.2, 1]`.
- Repeating `$type` on every leaf instead of once on the group.
- Using `$ref`/`var()` inside `$value` for a simple alias.

## Quick checklist

- [ ] Every reserved property is `$`-prefixed (`$value` required).
- [ ] `$type` drawn from the closed atomic/composite vocabulary; hoisted to groups.
- [ ] color/dimension/duration are objects; number is a plain number; cubicBezier is `[4 numbers]`.
- [ ] Aliases use `"{group.token}"`, never `$ref`/`var()`/copied literals.
- [ ] Names contain no `.`/`{`/`}` and never start with `$`.
- [ ] Composite `$value`s carry their exact sub-keys; tool data under `$extensions`.
