# Token Pipeline

Overview of how raw JSON tokens are transformed into CSS custom properties.

## Pipeline stages

```
Figma → Supernova → tokens/brands/{brand}/*.json
       → Style Dictionary
           ├── color: base + theme layers
           └── space, border-radius, blur, shadow, dimension, size, gradient
       → append shadcn theme → CSS
```

Font/typography tokens (`font-family`, `font-size`, `font-weight`, `line-height`, `letter-spacing`, `paragraph-spacing`) live in the source JSON but are **not** emitted as CSS — typography is owned by the Tailwind plugin in `src/tailwind/`.

### 1. Source: Figma + Supernova

Designers maintain color tokens in Figma. Supernova.io syncs these into JSON files and pushes them via the `supernovaio[bot]` GitHub App as PRs to the repository.

Token files land in `packages/css/tokens/brands/{brand}/color.json`.

### 2. Transform: Style Dictionary

The generate script (`scripts/generate.ts`) uses Style Dictionary with custom configuration defined in `src/style-dictionary/`.

#### Transforms

Defined in `src/style-dictionary/transforms.ts`:

**`color/rgbaOrHex`** (value transform)

Converts raw hex values to the appropriate CSS format:

- Fully opaque colors become `#hex` (e.g., `#329dff`)
- Translucent colors become `rgba()` (e.g., `rgba(0, 0, 0, 0.12)`)

Uses the `tinycolor2` library to detect alpha and convert.

**`name/color/kebab`** (name transform)

Flattens the nested JSON path into a flat kebab-case variable name. The logic handles two different path structures:

| Brand | JSON path | Output name |
| --- | --- | --- |
| Mindvalley | `colors.blue.50.base` | `blue-50` |
| B2B | `color.primary.blue.50.base` | `blue-50` |

Rules:

- Strips the theme suffix (`base`, `dark`, `desktop`, `tablet`, `mobile`) from the end
- Strips the category prefix (`color` for B2B, first segment for Mindvalley)
- Cleans alpha notation: `0-a` becomes `0a`, `12-a` becomes `12a`
- Special case: `grey.black` outputs `black`, `grey.white` outputs `white` (no `grey-` prefix)

**`name/token/kebab`** (name transform)

Used for every non-color, non-font token type (border-radius, blur, shadow, dimension, size, gradient). Strips the type prefix (`path[0]`) and the variant suffix (last segment), then joins the remaining segments with `-`.

| Source path | Output name |
| --- | --- |
| `border-radius.rounded.lg.base` | `rounded-lg` |
| `blur.blur.background.intense-3.base` | `blur-background-intense-3` |
| `dimension.spacing.400.base` | `spacing-400` |
| `gradient.gradients.pastel.bubblegum.base` | `gradients-pastel-bubblegum` |

**`value/gradient/rgbaResolve`** (transitive value transform)

Defensive cleanup for gradient values: if a resolved value still contains `rgba(#hex, alpha)` (i.e. a hex color wrapped in `rgba(...)` after Style Dictionary resolves a `{color.*}` reference), it is rewritten to `rgba(r, g, b, alpha)` for valid CSS. In practice Style Dictionary already strips most of these wrappers itself, but the transform keeps the output safe.

#### Transform groups

| Group | Used for | Transforms |
| --- | --- | --- |
| `css-colors` | Color tokens | `attribute/cti → color/rgbaOrHex → name/color/kebab` |
| `css-tokens` | All non-color, non-gradient types | `attribute/cti → name/token/kebab` |
| `css-gradient` | Gradient tokens (refs need resolution) | `attribute/cti → value/gradient/rgbaResolve → name/token/kebab` |

`attribute/cti` is a built-in Style Dictionary transform that sets `category`, `type`, `item` attributes from the token path.

#### Gradient handling

Gradient source values reference color tokens via `{color.*}` syntax (e.g. `rgba({color.gradient-base.black.0}, 1)`). To resolve these, the gradient build includes the brand's `color.json` in its source list, then filters output to gradient tokens only.

Some Supernova-generated gradients reference object paths (e.g. `{color.gradient-base.primary.medium}`) where the path resolves to a parent of variants rather than a leaf token. Style Dictionary cannot resolve these, and the format silently drops any token whose value still contains an unresolved `{...}` reference. This is a source-data limitation; affected gradients should be fixed in Supernova/Figma.

### 3. Filter

Brand-specific color filters (defined in `src/style-dictionary/filters.ts`) determine which color tokens are included. Each brand includes `base` and `dark` theme variants. See [Brand Filtering](brand-filtering.md) for details.

For non-color types, a `createSingleVariantFilter(name, type)` factory in `filters.ts` produces one filter per token type. Each filter keeps only tokens whose `type` matches and whose final path segment is `base`, dropping the duplicate `desktop`/`tablet`/`mobile`/`light` variants.

`dimensionFilter` additionally strips tokens whose path begins with `dimension.typography.*` (e.g. `--typography-list-spacing-*`) so no font-related variables leak into the dimension block.

### 4. Format: CSS custom properties

Defined in `src/style-dictionary/formats.ts`.

Before grouping, the format drops any token whose value still contains an unresolved `{...}` reference, so broken refs in source data never leak into the output CSS.

For non-color token types the build produces a single `:root` block per type, appended to the brand's main CSS file by `scripts/generate.ts`. Color tokens use the original two-layer format:

**Base layer** — Raw color scale variables with direct values. Rendered inside `:root` and `.dark` selectors. Tokens are grouped by subcategory with CSS comment headers (e.g., `/* Accent */`, `/* Colors */`).

**Theme layer** — Semantic tokens that reference base-layer variables via `var()`. Controlled by the `themeSubcategories` file option, which specifies which subcategories belong to the theme layer. Theme tokens are also rendered inside `:root` and `.dark` with subcategory headers (e.g., `/* Backgrounds */`, `/* Content */`, `/* Stroke */`).

The format builds a value → CSS variable name lookup from base-layer tokens so that theme-layer tokens are resolved to `var(--base-token)` references instead of raw hex values.

### 5. Append: non-color token types

After the color layer is written, the generate script iterates a fixed `TOKEN_TYPES` list and, for each type whose source JSON exists, runs Style Dictionary with the appropriate transform group + filter. The resulting CSS is appended to the brand's main file (without the auto-generated header).

### 6. Append: shadcn theme

Finally, the generate script appends the static shadcn theme CSS from `src/themes/{brand}-shadcn.css`. This adds shadcn/ui-compatible variable mappings. See [shadcn Mapping](shadcn-mapping.md).
