|
| 1 | +# Generate TypeScript tokens by combining the Tokens Studio DTCG and CSS exports |
| 2 | + |
| 3 | +- **Status:** Accepted |
| 4 | +- **Date:** 2026-07-13 |
| 5 | +- **Decision makers:** Frida Erdal, EDS Core Team |
| 6 | + |
| 7 | +## Context |
| 8 | + |
| 9 | +The new Tokens Studio pipeline replaces the legacy Figma-REST + Style Dictionary token build. The platform exports CSS, SCSS, DTCG, Figma, Swift, Android, and Compose — but **no TypeScript format**. `equinor/design-system-mobile` (React Native) consumes TypeScript token modules (semantic colours per colour scheme, typography, spacing per density), so the pipeline must produce a TS surface. |
| 10 | + |
| 11 | +Two platform behaviours constrain the solution: |
| 12 | + |
| 13 | +- The **DTCG export preserves `{alias}` references and unevaluated colour formulas** (`set_chroma(set_lightness(...))`). It is a structural interchange format, not resolved values. |
| 14 | +- The **CSS export is the only format that runs the platform's formula engine**, producing concrete `oklch()` values, joined across files by plain `var(--eds-*)` chains. |
| 15 | + |
| 16 | +## Decision Drivers |
| 17 | + |
| 18 | +- No Style Dictionary — the legacy build is being retired |
| 19 | +- React Native-compatible values: hex colours (no `oklch()`), unitless numbers |
| 20 | +- Must not reimplement the platform's colour formula engine |
| 21 | +- Runs unattended in CI (release-triggered, no CI on the resulting PR) — failures must be loud, never silently wrong output |
| 22 | +- TS values must be identical to what CSS consumers get |
| 23 | + |
| 24 | +## Options Considered |
| 25 | + |
| 26 | +### Option 1: Style Dictionary on the pulled raw token sets |
| 27 | + |
| 28 | +Keep the legacy tooling, pointed at the Studio-pulled JSON. |
| 29 | + |
| 30 | +**Pros:** |
| 31 | + |
| 32 | +- Familiar tooling, existing formats |
| 33 | + |
| 34 | +**Cons:** |
| 35 | + |
| 36 | +- The raw token sets contain unevaluated colour formulas Style Dictionary cannot compute |
| 37 | +- Keeps alive the dependency the new pipeline exists to remove |
| 38 | + |
| 39 | +### Option 2: Resolve the DTCG export in our own codegen |
| 40 | + |
| 41 | +Dereference `{alias}` chains and evaluate formulas locally. |
| 42 | + |
| 43 | +**Pros:** |
| 44 | + |
| 45 | +- Single input, pure DTCG |
| 46 | + |
| 47 | +**Cons:** |
| 48 | + |
| 49 | +- Requires reimplementing Tokens Studio's colour engine (`set_chroma`, `set_lightness`, gaussian scales) — a moving target we would have to keep bug-compatible |
| 50 | + |
| 51 | +### Option 3: Parse the CSS export alone |
| 52 | + |
| 53 | +The CSS output has evaluated values; derive the TS structure from the custom property names. |
| 54 | + |
| 55 | +**Pros:** |
| 56 | + |
| 57 | +- Single input, values already evaluated |
| 58 | + |
| 59 | +**Cons:** |
| 60 | + |
| 61 | +- Flattened kebab-case names make tree reconstruction ambiguous (`corner-radius-rounded-outer` → `cornerRadius.roundedOuter` or `cornerRadius.rounded.outer`?) |
| 62 | +- No `$type` metadata to drive value conversion |
| 63 | + |
| 64 | +### Option 4: The platform's resolved-tokens REST API |
| 65 | + |
| 66 | +`GET /api/v1/projects/:id/resolved_tokens` returns computed values. |
| 67 | + |
| 68 | +**Pros:** |
| 69 | + |
| 70 | +- Purpose-built for CI consumption |
| 71 | + |
| 72 | +**Cons:** |
| 73 | + |
| 74 | +- Not exposed through the `studio` CLI — would need separate HTTP client and auth plumbing alongside the existing OIDC CLI flow |
| 75 | + |
| 76 | +## Decision |
| 77 | + |
| 78 | +**Combine both exports** (`scripts/generate-ts-tokens.mjs` in `packages/eds-tokens`, zero dependencies): the DTCG export supplies the token tree and `$type` metadata; for every leaf the script derives the CSS custom property name, dereferences the `var()` chain in the right dimension context (colour scheme × density), and converts values — `oklch()` to hex via CSS Color 4 §13.2 gamut mapping (chroma bisection, verified identical to lightningcss for every colour in the export), `px` to unitless numbers. Modules whose resolved values differ per colour scheme are split into per-scheme files automatically. Unknown `$type`s, broken `var()` chains, and unsupported value syntax fail the build. |
| 79 | + |
| 80 | +This satisfies the drivers: no Style Dictionary, no reimplemented formula engine (the platform evaluates; we only convert), RN-ready values guaranteed identical to the CSS output, and loud failures for the unattended run. |
| 81 | + |
| 82 | +### Consequences |
| 83 | + |
| 84 | +- Good, because token values cannot drift between the CSS and TS outputs — they share one evaluation |
| 85 | +- Good, because the script has no dependencies and no coupling to retired tooling |
| 86 | +- Good, because per-scheme splitting is data-driven — new divergent dimensions surface automatically |
| 87 | +- Bad, because the codegen is pinned to the saved export configurations' shape (file layout, `eds` prefix, kebab casing) — changing those in Studio requires a matching script change |
| 88 | +- Bad, because the value parser accepts only today's CSS syntax; new value forms from the platform fail the release run until the converter learns them (intentionally loud, but requires a fix before tokens flow again) |
| 89 | +- Bad, because the gamut-mapping code must track the CSS Color 4 algorithm to stay bit-identical with browsers |
| 90 | + |
| 91 | +### Confirmation |
| 92 | + |
| 93 | +The release workflow (`tokens_studio_release.yaml`) runs the script on every Tokens Studio release; any deviation fails the run and alerts via the Slack step. Generated modules were verified with `tsc --noEmit --strict`, Prettier, and a lightningcss cross-check of all colour conversions. |
| 94 | + |
| 95 | +## Related |
| 96 | + |
| 97 | +- [`documentation/agent-instructions/TOKENS_STUDIO.md`](../agent-instructions/TOKENS_STUDIO.md) — pipeline documentation |
| 98 | +- [`documentation/how-to/TOKEN_SYSTEM_GUIDE.md`](../how-to/TOKEN_SYSTEM_GUIDE.md) — the legacy Figma-REST + Style Dictionary pipeline this replaces |
| 99 | +- [ADR-0007](./0007-token-variable-architecture-spacing-typography.md) — token variable architecture (Figma structure) |
| 100 | +- Issues [#5164](https://github.com/equinor/design-system/issues/5164), [#5108](https://github.com/equinor/design-system/issues/5108); PR [#5166](https://github.com/equinor/design-system/pull/5166) |
0 commit comments