Building a demo site with a teal brand, I set the primary colour token and the hero button stayed black. The tokens shipped in v0.2.0, the editor preview and the public page both read them, and the two loudest elements in the block library had the colour hardcoded the whole time.
Design tokens went into Atelier eight releases ago. Colour, font, spacing and width, emitted as CSS custom properties into the public page and the editor preview from the same layout, so the two cannot drift. A site overrides one key in config and does not restate the rest.
Building a demo site for v0.5.0 was the first time I actually used them for a brand.
'tokens' => [
'color' => [
'primary' => '#0d9488',
'on-primary' => '#ffffff',
'tint' => '#f0fdfa',
],
],
Reload. Section backgrounds turned teal, because the shared background control resolves a token reference. The hero button stayed black. The call to action panel stayed black.
What was actually in the views
<a href="..." class="rounded-md px-5 py-3 bg-neutral-900 text-white hover:bg-neutral-700">
Nine block views, and the only thing reading --atelier-color-primary was the shared control that lets a client pick a section background. The primary colour token existed, was documented, was emitted into the page, and coloured nothing anybody looks at.
That is a specific kind of bug. Nothing is broken, no test fails, the feature works exactly as built. It is only wrong against its own purpose, which you can only see by trying to use it for the thing it was built for.
The fix, and why it is inline
<a href="..."
class="rounded-lg px-5 py-3 text-sm font-semibold transition hover:opacity-90"
style="background:var(--atelier-color-primary);color:var(--atelier-color-on-primary)">
Inline style, not a class. There is a rule in this project about that, written when the shared controls were built: a class written in PHP is a class Tailwind never scans. The package's block views are scanned by the consuming app, so classes in a view are fine, but a colour composed at runtime cannot become a class name that exists. Custom properties have no such problem, which is most of the reason the tokens exist.
The image variant of the hero keeps its white button. A brand colour on top of an arbitrary photograph is a coin toss, and white on a dark overlay is not.
The part that makes it a breaking change
Every site that already sets color.primary now has a different hero button and a different call to action panel. Under 1.0.0 a minor bump may carry that, and the changelog says so, but it still needs the sentence that tells someone how to get the old look back:
If you were relying on the black panel, set
color.primaryto#171717and nothing moves.
That is the whole revert: the previous hardcoded value, as a token. Which is a decent sign the change is the right way round.
Why the demo found it and eight releases did not
The example app existed before this. It had pages, blocks, both languages, structured data and a passing test suite. What it did not have was a brand. Everything in it was neutral grey on white, which is exactly the palette the hardcoded values happened to be.
A demo built to prove a feature works will use the defaults. A demo built to look like a real client site sets a colour, and finds out which parts of the system were only pretending to be configurable.
Where it stands
Shipped in v0.5.0. The hero button and the call to action panel read color.primary and color.on-primary, in the editor preview as well as on the public page, because both get the same custom properties from the same layout.
Eight releases between shipping a token and having one block honour it. The tokens were not wrong. Nothing had asked them a question yet.