Field Notes
The Token Chain

Primitives

Layer 1 — raw values that are theme-aware but never used directly in components.

Definition

Primitives are raw values. They are theme-aware (light/dark mode) but should never be used directly in components.

Naming Pattern

--{category}-{name}

Common categories include:

CategoryExample
colors--colors-neutral-500
size--size-16
radii--radii-08
font-family--font-family-primary
font-weight--font-weight-500
font-size--font-size-14
leading--leading-20

Names typically use pixel-equivalent values (e.g. --font-size-14 = 0.875rem) for easy mental mapping.

Rules

  • Never use primitives directly in component styles
  • Primitives are only referenced when defining semantic tokens via var()
  • Import primitives before semantics in CSS (semantics depend on primitive declarations)
  • Never edit auto-generated files — use extension files for manual tokens

Color Space: OKLCH

Color primitives are defined in the OKLCH color space (oklch(L C H)).

ChannelMeaningRange
L (Lightness)Perceptual brightness0 (black) – 1 (white)
C (Chroma)Color intensity0 (grey) – ~0.37 (most vivid)
H (Hue)Hue angle360°

Why OKLCH over HSL or raw sRGB hex:

  • Perceptual uniformity — equal numeric steps produce equal visual steps. Two colors at the same L value look equally bright, which makes contrast ratios predictable across an entire ramp.
  • Wide gamut — OKLCH can represent Display P3 and Rec 2020 colors. Gamut mapping to sRGB is applied at build time so tokens degrade gracefully.
  • Theme symmetry — inverting lightness for dark mode produces natural-looking results because L is perceptually linear.

Anchor Model

Each palette starts from one or more anchor colors — designer-chosen hue and chroma values pinned to specific steps in the ramp. The generator holds these anchors fixed and fills the remaining steps algorithmically.

An anchor defines:

  • Hue (H) — the base hue angle for the palette
  • Chroma (C) — peak color intensity at the anchor step
  • Step — which ramp position (e.g. 500) the anchor occupies

Multiple anchors per palette are supported. When present, hue is interpolated between them using shortest-arc (circular) interpolation to prevent unexpected hue shifts.

Lightness Ramps

Each scheme (light, dark) has a fixed set of lightness targets — the L value assigned to each step. The two schemes are approximate mirrors of each other.

Light scheme (LIGHTNESS_TARGETS_LIGHT)

StepL
500.98
1000.95
2000.92
3000.88
4000.82
5000.75
6000.65
7000.52
8000.45
9000.35
9500.25
10000.15

Dark scheme (LIGHTNESS_TARGETS_DARK)

StepL
500.12
1000.16
2000.22
3000.28
4000.34
5000.42
6000.52
7000.65
8000.75
9000.85
9500.92
10000.98

These values are defined in generate-ramps.ts and may evolve — treat the generator as the source of truth.

Generation Pipeline

generate-ramps.ts converts anchor definitions into primitive tokens through these steps:

  1. Parse anchors — load anchor hex values and their designated steps
  2. Convert to OKLCH — parse each anchor hex into the OKLCH color space
  3. Set lightness — assign L from the appropriate lightness-targets array (light or dark scheme)
  4. Interpolate hue — for steps between anchors, interpolate H via shortest-arc to avoid crossing through unrelated hues
  5. Distribute chroma — apply a bell-curve distribution (σ = 0.28) centred on the peak-chroma anchor, with a floor at 8% of peak chroma to prevent fully desaturated mid-ramp steps
  6. Gamut-map — clamp chroma via clampChroma() so every output color falls within sRGB
  7. Emit tokens — output as CSS custom properties, JSON, and Figma variable schemas

On this page