spike(Design Tokens) - #3406
Draft
dreamwasp wants to merge 2 commits into
Draft
Conversation
Go/no-go criterion #3 from the reboot recommendation §5, and the only one of the four that had never been spiked. It matters because §3 recommends tokens move to an engine-neutral pipeline while every other spike has Panda generating tokens directly — the opposite of the stated goal. It works. From the real Core theme, exported to DTCG and built with Style Dictionary: palette colours 68 byte-identical to what Gamut emits today semantic aliases 32 per mode x 2 modes, as var() references token names 137 match keyof theme[scale] exactly engine-neutrality 139 tokens identical across CSS / TS / Panda preset The Panda preset is generated FROM the tokens rather than being where they live, so swapping the styling engine no longer touches the token pipeline. Aliases emit var(--color-x) rather than inlined hex, so colour mode still works by variable reassignment and stays a x1 multiplier. Findings, all in the README: - DTCG has no concept of modes. Each mode is a separate token file merged at build time, so the mode dimension lives in build config rather than in the tokens — fine while Gamut owns the build, not fine if tokens are handed to a third party expecting modes to travel with them. - spacing[0] can't round-trip: DTCG dimensions require a unit, so bare 0 returns as "0px". keyof is unaffected, so type safety holds; only the value type shifts. Recorded as an explicit accepted deviation so new ones fail. - Style Dictionary's TS formats can't express Gamut's token names (navy-800, 0, 400 aren't valid JS identifiers). name/camel would rename them, which parity forbids, so a custom format emits a quoted-key as-const object. - borders isn't expressible: a CSS shorthand embedding a var() ref to a mode-dependent semantic colour. Decomposing it is the real fix. style-dictionary pinned to 5.5.0 rather than ^5.5.1 to respect the repo's npmMinimalAgeGate of 7d. Adds spikes/* to root workspaces, which main lacks. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
.unexpressible.json was written without a trailing newline, so every run left the working tree dirty against the lint-formatted committed copy. Also ignore the drafted PR body. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
|
View your CI Pipeline Execution ↗ for commit 94feea3 ☁️ Nx Cloud last updated this comment at |
|
Contributor
|
🚀 Styleguide deploy preview ready! Preview URL: https://6a7b29955cefeb3c49ca395d--gamut-preview.netlify.app |
Collaborator
|
📬 Published Alpha Packages:
|
This was referenced Aug 11, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Overview
Spike, not for merge. Closes go/no-go criterion #3 for the 1.0 reboot: stand up
a DTCG → Style Dictionary pipeline emitting CSS variables + TS types, and verify
parity with today's typed tokens.
Passed. Full writeup in
spikes/dtcg-tokens-poc/README.md.Why it matters more than "tokens in a new format"
The reboot recommendation proposes tokens move to an engine-neutral source so they
survive an engine change. But every earlier spike had Panda generating the tokens,
which coupled tokens to Panda — the opposite of the stated goal. The only DTCG reference
anywhere was a comment saying "real Gamut would source these from the same DTCG /…",
explicitly deferred.
This closes that gap. From the real Core theme:
var()referenceskeyof theme[scale]exactlyThat last one is the point: Panda becomes a consumer of the tokens rather than where
they live, so "engine-neutral" is now demonstrated rather than aspirational.
The constraint worth knowing about
DTCG has no concept of modes. The 2025.10 spec gives a token exactly one
$value;Gamut has 5 themes × 2 modes. So each mode is a separate token file merged at build
time — correct output, but the mode dimension lives in build configuration rather than
in the tokens. A consumer handed the JSON alone cannot discover that modes exist.
Fine while Gamut owns the build. Not fine if tokens are handed to Figma or a partner
expecting modes to travel with them. That is now a deliberate decision rather than an
unknown.
Two values aren't expressible at all —
borders.1/borders.2, CSS shorthandsembedding a
var()reference to a mode-dependent semantic colour. Recorded explicitlyin
tokens/.unexpressible.jsonrather than quietly dropped, andbordersstayshand-maintained outside DTCG (2 tokens; composite + modes not worth it).
The verification is designed to fail loudly
verify.mjsuses anEXPECTED_DEVIATIONSallowlist, so a new deviation still failsthe run while known ones stay documented. Of the reboot's spikes this is the assertion
design most worth copying — most of the others report numbers without failing.
94feea34dmakes the export idempotent, so re-running produces no diff.PR Checklist
verify.mjsis the assertion; itexits non-zero on any unexpected deviation
Codecademy repositories — no; nothing consumes these tokens yet
Testing Instructions
yarn workspace dtcg-tokens-poc all # export → build → verifyExpect: 68 colours byte-identical, 137 names matching
keyof theme[scale], 139 tokensagreeing across all three consumers, and a non-zero exit if any unlisted deviation
appears. Re-run it twice — the export is idempotent, so the second run should produce no
diff.
Note this adds
spikes/*to the rootworkspaces.Known follow-ups
is not a superset, so this is not a trivial repeat.
emotion-to-gamut-poc'spanda.config.ts— doing so would close the loop and prove the whole split end to end.PR Links and Envs
Related reboot spikes: #3402 (styling proof of concept) · #3405 (Panda under the hood) ·
#3407 (tsdown build).