Skip to content
Transtyle v0.1.0-alpha.5
ok: build 10:17 UTC31 pages main · 7ed21c5

Alpha — breaking changes ship without a deprecation cycle. What is built vs. planned

Core concepts

Five ideas explain everything Transtyle does. Learn 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. Nothing depends on timestamps, randomness or the network.

2. The three-tier token model#

option color.blue.600 · font.mono raw values, your private vocabulary, any names you like
semantic primary.solid · text.base · elevation.0.surface meaning, the stable public surface exporters bind to
component component.control.*, component.button.* optional per-component refinement, layered, defaults from semantic

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.surface through elevation.5.surface (the page, cards, raised panels, popovers…), each with a paired elevation.N.shadow for levels 1–4. scrim is the separate dimming veil behind modals.
  • Content: text.{strong, base, muted, subtle, disabled, inverse}, link.{base, hover, visited}; the border ladder border.{subtle, base, strong, field}; the inverse pair inverse.{surface, text}; ring as a single-value slot.
  • Also: radius.* (+ control/field/container family aliases), font.*, the focus ring’s geometry ring.{width, offset}, and defaulted scales for space.*, size.control.*, border-width.*, breakpoint.*, z.*, type.* (primitives and composite type.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. Every target accounts for each one. It’s written under its own name where the target takes any variable (css-variables, daisyUI), reached through a catalog slot bound to it, or reported dropped in coverage, with a custom vocabulary line in the build summary. 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, which is 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.