NOTES · ENGINEERING · 2026-04-22 · 1 MIN
Tokens as contract
There are no hex codes in components. There are no transition: 200ms strings, no border-radius: 8px inline. Every value has a name, every name lives in @joao/tokens, and a Biome rule blocks the rest at PR-time.
This sounds like overhead. It is the opposite. Every change to the brand happens in one file. The seven motion durations — instant / quick / base / lucid / slow / cinematic / epic — are the only durations the site can express. The five easings — signal / velvet / line / tuna / cast — are the only easings. The ten ink shades, four bones, four bronzes, four golds, four embers, four signals are the only colours.
You don't pick. You compose.
And when the brand needs to shift — say, the ember opacity wants to be 30% warmer for the Tuna corner — you change one token, and the whole site moves with it. Not "the whole codebase rebuilds"; the whole site moves. The atelier itself is a token consumer; so is the static poster, so is the cursor, so is the preloader.
The contract has three deliveries:
- A CSS file (
@joao/tokens/css) of:root { --gold-500: #c89b4f; --dur-base: 280ms; ... }— for any component that wants to consume viavar(--…). - A typed TS barrel (
@joao/tokens) —import { color, duration, ease } from '@joao/tokens'— for components that need values at runtime (R3F, OG cards, audio envelopes). - A Tailwind preset (
@joao/tokens/tailwind-preset) — so utilities liketext-gold-400 duration-base ease-signalwork everywhere withouttheme.extendboilerplate per app.
All three are derived from the same tokens.ts. If you only edit one, CI fails the others. The system doesn't trust me.
The deeper invariant is: tokens are the medium, not the style. Style is what you do with a medium. Token-discipline gets that right by removing the pretence that the medium is being made decision-by-decision in each file. It is decided once, in the open, with a name. Then everyone composes.