Alpha — breaking changes ship without a deprecation cycle. What is built vs. planned
Status & roadmap
Transtyle’s design phase produced a complete blueprint before any code; the walking skeleton implements the core slice end-to-end. This page is the ledger of which is which.
Implemented today (v0.1 walking skeleton)#
| Area | Status |
|---|---|
| Compiler pipeline (load → normalize → derive → resolve → emit → report) | ✅ end-to-end, byte-deterministic |
| DTCG-superset token loading, aliases, cycle detection, tiers | ✅ |
Modes: any number of independent dimensions (for example color-scheme + density), inline $extensions and mode-scoped layer files |
✅ equivalent by construction; single-dimension configs unaffected |
| Derivation: standard@1, the role grid (prominence × state per color role), the elevation ladder, content hierarchy, and full foundations scales (space/size/border-width/breakpoint/z/type/motion) + radius family aliases; a default page and body text, and the light page/text pair swapped into dark mode when only the text is authored | ✅ with provenance |
| OKLCH color engine, WCAG 2.1 contrast checks (AA/AAA) on surface text and every on-color; APCA as a selectable standard, for checks and on-color picks | ✅ color engine zero-dep, in-house; APCA through the optional apca-w3 peer package |
| shadcn/ui exporter, tailwind-v4 + tailwind-v3 era profiles | ✅ |
| Apache ECharts exporter: per-mode theme JSON + self-registering scripts, 8-color derived palette | ✅ |
| daisyUI exporter (v5 era): light+dark theme blocks, brand-direct role mapping | ✅ |
Bootstrap exporter (≥5.3): Sass path (_variables + _maps) and CSS-variable path |
✅ engine-exact vs the Phase 0 fixtures |
| Storybook exporter (SB 8–9): chrome ThemeVars + sibling preview composition | ✅ |
css-variables exporter: the plugin-API reference implementation, full catalog as --custom-properties |
✅ 467 declarations (305 distinct) on Acme, 100% native |
| Radix Colors/Themes exporter: 12-step scales + alpha + contrast per role, the role grid’s own acceptance test | ✅ only 2 of 12 steps needed a fresh mix; surfaced (and fixed) a gamut-clamp gap in text-strong |
PrimeNG exporter: definePreset(Aura, overrides), the first target with its own three-tier component-token system. One generic severity-grid mapper + exporter-private archetype helpers, proven on Button/Tag/Badge/Message/InlineMessage/Listbox/Menu/Popover/Dialog |
✅ first Angular demo in the repo; every preset type-checked against PrimeNG’s own DesignTokens types |
Mantine exporter (Mantine 9): a createTheme object with one virtualColor per role + a cssVariablesResolver carrying the per-scheme variant colours, with no override stylesheet because Mantine writes its variables at runtime |
✅ every theme type-checked against Mantine’s own types in the demo build; every entry of its surface inventory accounted for by check:coverage-bar |
Chakra UI exporter (Chakra v3): a createSystem config whose semantic tokens give every role Chakra’s eight palette keys (solid, contrast, fg, subtle, muted, emphasized, border, focusRing) per scheme; Chakra’s default palette and Alert statuses routed to roles |
✅ every config type-checked against Chakra’s own types in the demo build; every entry of its surface inventory accounted for by check:coverage-bar |
Material UI exporter (MUI 9): a createTheme in CSS-variables mode, every role a palette key per scheme (danger → error, extra keys declared for TypeScript); Button variants read the grid’s text and outline cells, Paper overlays carry the elevation surfaces, the ring turns on MUI’s focusVisible |
✅ every theme type-checked against MUI’s own ThemeOptions in the demo build; every surface-inventory entry accounted for by check:coverage-bar |
Role archetypes: custom semantic.color.<name> roles declaring $extensions.transtyle.role derive the full grid like a built-in and export to open-role targets (daisyUI, css-variables) |
✅ Cathode’s crt-amber as the example |
Custom vocabulary: every custom semantic.* token is written, reached through a binding, or reported dropped on every target, counted in report.json and the build summary; open-vocabulary targets (css-variables, daisyUI) write them, with a customTokens: "omit" opt-out |
✅ GOV.UK’s 14 tokens accounted for on all 11 targets; held by check:plugins and check:catalog-signals |
Multi-dimension modes: a second independent mode dimension (for example density) alongside color-scheme; css-variables emits a [data-<dim>="<value>"] block per non-default value; targets that don’t express it report dropped(mode:<dim>) |
✅ Acme’s density: comfortable|compact (space.* × 0.875) as the worked example |
Reserved contrast, motion and brand dimensions: combo layers for one combination’s values (TST1125 when one is missing); contrast-more (7:1) and motion-reduced (0ms) derivation; check on every combination; CSS targets add attribute blocks, prefers-contrast / prefers-reduced-motion media blocks and compound blocks for combinations, file targets emit one file set per brand, daisyUI one theme per combination, Storybook a toolbar per dimension |
✅ a four-dimension test fixture, every CSS combination verified through a cascade |
Per-example demo projects (examples/*/demo/*): the same fake app per target, npm-run-dev-able |
✅ consume dist/ only |
| Target instances (one exporter, many configs) | ✅ |
Config inheritance: extends a base config and --config <file> on every command, for several products or design systems in one repository; merge rules for every key, token paths follow their file, outputs follow the product |
✅ ADR-0016, golden-tested (check:cli) |
Coverage report (report.json, with the slots each target read) + diagnostics with stable codes |
✅ |
Report viewer: a report.json read as a page, from a file, a paste, a sample of every example × target, or a ?src= link; validated against the published schema, nothing uploaded |
✅ |
Emitted-file manifest (transtyle-manifest.json per target, written in the same atomic swap as the files) and drift detection: build and check warn TST1312 when a generated file was changed or removed by hand |
✅ |
CLI: build, check, explain (with --target and the reverse --variable lookup), init (questions in a terminal, a flag for each, recommended/minimal presets, single/layered layouts), add, diff, catalog, bind --suggest (binding proposals from your own names and colors), migrate --from style-dictionary (Style Dictionary v3 → DTCG codemod, dry run unless --write), --cwd, --config, --json, check --matrix (which targets read each slot, also as the generated slot matrix page) |
✅ golden-tested (check:cli) |
Completeness levels: check --completeness, an authored n/m line on every build, require: ["completeness:<level>"] |
✅ golden-tested (check:cli) |
Adoption report: check counts the project’s own semantic tokens, lists the ones no catalog slot reads with hints (same value, or a shadowed slot name), and notes false-friend bindings (TST1124); check --json carries it as adoption |
✅ golden-tested on GOV.UK (govuk.focus-text), Cathode (all bound) and two fixtures (check:cli) |
DTCG structural validation: unrecognized $type, missing $value, tier violations, foreign $extensions namespaces |
✅ new stable codes (docs/specs/validation-and-coverage.md), fixture-tested |
DTCG structured values: dimension/duration objects ({ "value": 16, "unit": "px" }), cubicBezier arrays, fontWeight keywords, also as composite members; fontFamily as one CSS list string |
✅ canonicalized to the CSS string, byte-identical to it on every target; malformed → TST1106 |
Tokens Studio exports as input ({ "tokensStudio": … }): folder or single file, theme groups as mode dimensions, tier per set, the Tokens Studio dialect and math evaluated per mode, explain naming the set file (ADR-0014); color modifiers refused (TST1007) |
✅ |
DTCG token metadata: $description and $deprecated (group inheritance, false opt-out) carried to report.json, explain, every usage.md and the comments of the CSS and Sass targets; a slot reaching a deprecated token warns TST1122 |
✅ GOV.UK’s and Carbon’s binding descriptions ship in their CSS-variables, shadcn, daisyUI and Bootstrap output |
Component tier (component.control.*, component.button.*, component.tooltip.max-width, semantic.opacity.disabled), layered over the semantic tier |
✅ driving Bootstrap’s and PrimeNG’s component surfaces; every inventoried slot accounted for by check:coverage-bar |
Plugin conformance kit (@transtyle/plugin-kit): shape, determinism, IR immutability, coverage honesty, no leaked values, mode dimensions accounted, diagnostics shape, schema validity, open vocabulary, over ten fixture design systems |
✅ gates all 11 official exporters + an inline third-party plugin in CI (check:plugins) |
Exporter compatibility: each exporter’s irSpec and pluginApi checked against core at load time, a mismatch refused with TST1309 |
✅ every official exporter declares matching values (check:plugins); a mismatch is tested end to end in check:cli |
Version profiles: targets.<t>.version selects the exporter manifest range covering it (ctx.targetProfile, recorded in report.json); shadcn picks its era from the Tailwind version; an uncovered version is refused with TST1313 |
✅ every official exporter declares matching values (check:plugins); a mismatch is tested end to end in check:cli |
Declarative exporters: a JSON mapping table (CSS custom properties, Sass, Less or JSON rows of variable → slot) is an exporter without code, from a file next to the config or a package that is never imported; validated with TST1014/TST1015, published schema |
✅ every official exporter declares matching values (check:plugins); a mismatch is tested end to end in check:cli |
Community exporters from npm: transtyle add <package> prints the manifest before installing, says when no code will run (declarative), asks before installing code, installs with scripts off and registers the target |
✅ installed from packed tarballs, built, and every refusal tested end to end (check:cli) |
Published JSON schemas for transtyle.config.json, report.json and transtyle-manifest.json, validated at load time |
✅ one source of truth, regenerated by gen:schemas, enforced by check:schemas |
Programmatic API without a filesystem: compileProject({ config, files, exporters }) from @transtyle/core/browser (no Node built-in on its path, nor in any official exporter); compile({ cwd }) is it plus reading the project (its extends chain included) and writing it (with its emitted-file manifest) |
✅ every example compiled in a Node-free sandbox, byte-identical to build (check:browser) |
| Examples: Acme (minimal), Cathode (hostile), GOV.UK and Carbon (real, independently-designed) | ✅ |
Ground-truth checks: catalog completeness + frozen fixture values (check:grid), Phase 0 fixture diffing (check:fixtures), byte-for-byte determinism (check:determinism), chained as check:all |
✅ |
| CI (GitHub Actions): every check above + site build + a matrix build of all 44 demo projects, on every push/PR | ✅ |
DTCG color objects (colorSpace/components/alpha/hex) in all fourteen DTCG color spaces, and the hwb()/lab()/lch()/oklab()/color() CSS syntaxes on the same converter |
✅ to OKLCH, an srgb object bit-identical to its hex; malformed → TST1106, a disagreeing hex → TST1123 |
2026-07-20, the catalog revision: the semantic catalog was rebuilt around the role grid. A 14-ecosystem comparative study (docs/proposals/0001-universal-token-ir.md) found that every mature design system samples the same prominence × state grid per color role. It landed as a pre-release breaking revision. Transtyle is unreleased, so old slot names were removed outright rather than aliased, and no version number moved (still IR spec v0; see docs/adr/0010-pre-release-breaking-changes.md). The same change migrated all five shipped exporters, both examples, and their fixtures (css-variables, added after, was built fresh against the new catalog). Color values are unchanged except one documented, intentional refinement (overlay/popover is now a deeper elevation level, not an alias of the raised-card level). Sequenced in docs/plan/catalog-revision.md.
Specced, not yet implemented#
Design-complete in the repo’s docs/ (architecture specs + ADRs), waiting their turn:
| Feature | Where the design lives |
|---|---|
CLI: import, preview, migrate without --from (IR-spec upgrades) |
docs/specs/cli.md |
Derivation overrides, user rule expressions, autoDark color synthesis (darkBrandAdjust, an open research question, docs/exercises/phase0-shadcn.md F7) |
docs/architecture/derivation.md |
| Importers (Figma variables, Tailwind config, Bootstrap Sass) | ADR-0008 |
--force-profile and a third-party exporter pilot (the conformance kit, version profiles, declarative exporters and transtyle add <npm package> shipped, see above) |
docs/architecture/plugins.md |
Lockfile (transtyle.lock), --frozen CI mode |
docs/architecture/versioning.md |
The rest of the component theming layer (v2); the shared component.* tier itself shipped, on Bootstrap and PrimeNG |
docs/specs/component-layer.md, ADR-0003 |
Sequencing (from the project ROADMAP)#
- Phase 0: validate the IR (in progress): the shadcn round is done on paper (three IR amendments accepted). The ECharts round was validated directly in code, and the exporter shipped without requiring IR changes. The Bootstrap round (the hardest constraint set) found zero IR-catalog changes, one rule-pack amendment (radius-scale derivation), and confirmed round 1’s key amendment as general. The Storybook round (meta-target) found zero amendments on the first clean attempt. The shadcn re-run then found a subtle-foreground rule ambiguity precisely because it diffed the paper expectation against real compiler output. The rule is now ratified in spec and code together, the clean-attempt counter was reset, and the exercise protocol now requires the output diff. Under the ratified rules, the next shadcn attempt came back clean on both probes. The Bootstrap re-run then diffed its hand maps against the derivation engine directly and found two more: a catalog slot that was guaranteed but underivable (
<role>.contrast), and unpinnedmixsemantics hiding a polar-vs-cartesian hue bug in border tints. Both were ratified in spec and code, shipped outputs are unchanged, and the counter was reset. Two machine-vs-hand diffs in a row caught what spec re-reading could not. The Bootstrap and shadcn re-runs under the ratified rules then both came back clean, with the verification mechanized: fixture values exact-matched against fresh engine runs. The Phase 0 exercise exit criterion is met (21 findings over 8 rounds; the ones that mattered most were only findable by diffing hand expectations against the machine). Remaining in Phase 0: the formal freeze declaration of IR spec v0 and plugin API v0, plus the naming tail. - Phase 1: foundations compiler + four reference exporters, npm publication,
init. Eight exporters shipped rather than four; npm publication was deliberately parked until the first alpha, and that alpha is now being released (experimental, under thealphadist-tag). - Phase 2: trust & workflow: preview site and importers beyond DTCG.
explain,diffand the plugin conformance kit landed early, in Phase 1. Exit criterion for v1.0: a third party ships a working exporter using only public docs. - Phase 3: ecosystem translation: importers from Bootstrap/MUI/shadcn; round-trip fidelity reporting.
- Phase 4: component theming layer (v2), partially pulled forward by the first-alpha definition (2026-07-23). The shared
component.*catalog, generalized from two real component-heavy implementations (PrimeNG shipped; Bootstrap is the alpha’s second prototype), is now part of the first-alpha bar. The remainder of the layer stays Phase 4.
The first alpha, the first published, publicly deployed release, is defined in the project ROADMAP (2026-07-23). A large DTCG-speaking design system exports to rich component libraries (Bootstrap, PrimeNG) with all three tiers mapped (raw/option, semantic, and component tokens), proven on the Carbon and GOV.UK examples, plus a reference-docs rewrite and a diagnostics polish pass. Non-DTCG importers (Tailwind, Figma, CSS custom properties) are explicitly post-alpha.
What is deliberately never coming#
No runtime shipped to your app. No component implementation generation. No visual editor. No AI inside the compiler (deterministic rules only; AI belongs outside, writing config; see AI agents). No pixel-perfect-equivalence claims. The coverage report exists precisely because translation is lossy.