Skip to main content
Substrate is a generative design-token engine that replaces static token libraries with mathematical intent — explicitly not a component library. Instead of hand-authoring color ramps and parallel mode palettes, you declare what your brand means — a hue and chroma per intent, a spatial unit, a type ratio — and Substrate’s runtime kernel solves every color’s lightness with APCA against the actual surface it sits on, driven by a continuous preference vector (scheme, contrast, density, type scale, motion, warmth, color vision). The result is an always-accessible, continuously adaptive system delivered for Web (CSS + a small JS runtime), iOS (Swift), Android (Kotlin/Compose), and design tooling (DTCG).

The Problem With Static Tokens

Static design tokens store a value. color-primary-500: #1A7F5A. That value was probably chosen to look good in light mode, on a calibrated display, by someone with standard color vision. It may pass a WCAG 2.x contrast check against a white background. But it says nothing about:
  • Dark surfaces — the same hue at the same lightness often fails contrast on dark backgrounds, where APCA polarity flips.
  • In-between states — real preferences aren’t binary. A comfortable low-light reading position sits between light and dark; a static ramp has no value there.
  • High-contrast needs — users with low vision need foregrounds solved to genuinely higher contrast targets, not a slightly bolder version of the same token.
  • Color vision deficiency (CVD) — a palette designed around green and red as signal colors fails a large portion of users without a CVD-aware remap.
  • Density, type scale, and motion sensitivity — spacing, sizing, and animation are preferences too, and ladders of fixed steps can’t follow them continuously.
Teams that care about these users end up maintaining parallel token sets — a light ramp, a dark ramp, a high-contrast ramp — all authored by hand, all drifting apart the moment the primary color changes.

How Substrate Works

1

Declare your brand intent

Author a YAML brand config: an open map of intents, each just a hue and chroma — lightness is never authored. Add your spatial unit, type ratio, motion, elevation, and the flexibility bounds users may adjust within.
2

Generate solver inputs and artifacts

The pipeline compiles the CSS cascade, component style descriptors, and per-mode baked artifacts for every brand — plus Swift, Kotlin, DTCG, and React Native outputs.
3

Solve at runtime

A small kernel (JS on the web; Swift and Kotlin ports on mobile) solves APCA contrast per surface under the user’s preference vector and writes the results as --ucs-* variables. Change a preference and the whole interface re-solves — no rebuild.
Foreground colors are never hand-picked: the APCA (Accessible Perceptual Contrast Algorithm) solver finds the exact lightness that achieves the contrast target against the actual surface, for the user’s exact position on the preference continuum. Named modes are just presets on that continuum. See Core Concepts for the full model. APCA attribution and use restrictions: see About APCA.

Key Benefits

Every foreground in every context meets its APCA target by construction — foreground Lc 75, borders Lc 50, focus rings Lc 60, scaled by the user’s contrast preference. Shortfalls are reported explicitly, and a build-failing accessibility gate keeps every brand in the build honest.
One brand config serves the whole preference continuum. Named presets — light, dark, dimmed, highContrast, darkHighContrast — are convenience points, and users can sit anywhere between them. You don’t maintain parallel files.
CVD support is a runtime preference (protan, deutan, tritan, achromat, with continuous severity): intent hues are redistributed onto a CVD-safe arc before contrast solving, and achromat mode adds pattern overlays so meaning never rides on color alone.
Brand families share a base config; sub-brands author only deltas and inherit everything else through a deep-merge cascade. All accessibility behavior comes with the model.
Every target — Web (CSS + JS runtime), iOS (Swift, Display P3), Android (Kotlin/Compose), React Native, DTCG JSON for design tools, xcassets — derives from the same brand data.

Where to Go Next

Quickstart

Vendor the engine, run substrate init, and initialize the runtime solver.

Core Concepts

Dive deeper into color intent, runtime APCA solving, and cascading inheritance.

Runtime & Imports

The required app wiring: the import contract and the three-call runtime sequence.

Surface Component

The one shipped component — required wherever surfaces nest inside surfaces.