Core concepts
Five ideas explain everything Transtyle does. Master these and the rest of the docs is reference material.
1. The compiler pipeline
Every build runs the same six stages:
| Stage | What happens |
|---|---|
| LOAD | Read transtyle.config.json and the token layers it lists |
| NORMALIZE | Merge layers, resolve aliases (with cycle detection), expand modes, parse colors to OKLCH |
| DERIVE | Fill every unauthored semantic slot using deterministic rules |
| RESOLVE | Map the completed token graph onto each target’s native theming surface |
| EMIT | Write native artifacts (only this stage touches your disk; check skips it) |
| REPORT | Coverage classification + diagnostics, human and JSON |
Identical inputs produce byte-identical outputs — no timestamps, no randomness, no network.
2. The three-tier token model
Tiers are structural — the top-level group name (option, semantic, component) declares the tier. Exporters only ever bind to the semantic tier: you can rename your entire option palette tomorrow and no target output changes, as long as the semantic aliases still point somewhere sensible.
3. The semantic catalog
The catalog is the fixed set of semantic slots that exporters can rely on existing after derivation — the “instruction set” of the compiler. Every color role is a grid: prominence (solid fill, tint wash, outline, text) × interaction state (rest, -hover, -active, -selected), plus the paired foregrounds (on-solid, on-tint) — see the language reference for the full shape and why a grid instead of a flat list.
- Color roles —
primary,secondary,accent,success,warning,danger,info,neutral. Each carries the full grid:<role>.solid,<role>.solid-hover,<role>.tint,<role>.outline,<role>.on-solid,<role>.text,<role>.text-strong, and so on. - Elevation —
elevation.0.surfacethroughelevation.5.surface(the page, cards, raised panels, popovers…), each with a pairedelevation.N.shadowfor levels 1–4;scrimis the separate dimming veil behind modals. - Content —
text.{strong, base, muted, subtle, disabled, inverse},link.{base, hover, visited};border,ringas single-value slots. - Also —
radius.*(+control/field/containerfamily aliases),font.*, and defaulted scales forspace.*,size.control.*,border-width.*,breakpoint.*,z.*,type.*(primitives and compositetype.role.*),duration.*,easing.*.
You may add custom semantic tokens beyond the catalog — they’re carried with full provenance and can be aliased by catalog slots. That’s how a design system keeps its own vocabulary: see the Cathode walkthrough.
4. Modes
A mode dimension is a declared axis of variation — the skeleton supports one, color-scheme, with values like light/dark. Every token resolves per mode; unspecified mode values fall back to the default-mode value.
Two equivalent authoring forms exist (inline $extensions, or separate mode-scoped files — see Authoring tokens), and one important rule: default declares your design system’s native mode; exporters bind mode names. A dark-native design system still compiles correctly to shadcn’s light-first :root/.dark structure.
5. Provenance and coverage
Every resolved value carries its origin:
| Provenance | Meaning |
|---|---|
authored |
You wrote this value |
aliased |
You pointed at another token |
derived |
A named rule computed it from your tokens |
defaulted |
A catalog constant, no user input involved |
And every emitted variable is classified in report.json:
| Coverage class | Meaning |
|---|---|
native |
The target has a first-class slot; lossless mapping |
derived |
Synthesized by derivation, then mapped natively |
approximated |
Mapped, but meaning changed (unit conversion, gamut clamp, concept mismatch) |
dropped |
Your system expresses it; this target can’t; omitted with a reason |
unsupported |
The target has a themable slot Transtyle doesn’t cover yet |
A build isn’t “done” at 100% native — that’s impossible across real ecosystems. It’s done when the report matches your intent: your decisions authored, coherent derivation for the rest, every approximation known and accepted.
For the same reason, don’t compare one target’s coverage against another’s. Each percentage measures a different surface with a different ceiling, set by how that framework is themable rather than by how much of it we’ve mapped. A framework that resolves token references at runtime spreads one binding across many slots; one that needs each variable bound individually can’t. Two targets at very different percentages can both be as complete as their architecture allows. Compare a target against its own previous build — which is exactly what transtyle diff does.
This is the trust mechanism: Transtyle never pretends translation is lossless — it measures the loss and shows you.