---
title: Draw me like one of your JSON files
date: 2026-07-02T11:48:26Z
modified: 2026-07-02T12:02:44Z
permalink: "https://dgw.ltd/2026/07/02/draw-me-like-one-of-your-json-files/"
type: post
status: publish
excerpt: ""
wpid: 1161
categories:
  - AI
  - Code
  - Design
featured_image: "https://dgw.ltd/wp-content/uploads/2026/07/draw-me-like-one-of-your-json-files-og.png"
featured_image_alt: /design-sync assumes React React (strikethrough) theme.json
---

In [Pixel Pushing, Redux](/2026/04/24/pixel-pushing-redux/) I rebuilt this site with Claude Design over a weekend and £23.84, then handed off to Claude Code for the WordPress build. One thing intrigued me when setting up the design, Claude Design’s first pass was to set up a design system, you can import assets and it will set up a system before it ‘designs’ anything. Good. But the design system I’d set up now lives _inside_ Claude Design – the swatches, the type scale, the little reference cards the design agent builds with – was a (AI?) generated version of my `theme.json`. Every time I nudged a token in the theme, the Claude version drifts. Plus ça change. This is not new. The moment we handover from one translation layer to another things change.

## The copy had drifted

But this week `/design-sync` shipped and I was curious, could I now sync back up the design system and the code I had continue to evolve? Before we get onto the more salient point I want to make, an example of drift probably all too familiar to people that manage design systems:



| Token | Claude Design | theme.json |  |
| --- | --- | --- | --- |
| accent-peach | `#FFC3B9` | `#f8d2cd` | changed |
| container width | `70rem` | `72.5rem` | changed |
| `--fs-sm` | `1rem` | `1.0625rem` | wrong |
| muted, four tints | — | present | missing |
| `2xs`, `4xl` sizes | — | present | missing |

None of that is catastrophic. A slightly-off peach won’t end me. Missing a couple of bigger font sizes, meh.

Fine, but what does `/design-sync` actually **do**. Officially it’s to allow Claude Design to sync in **both directions** (interesting), sounds ideal for keeping the code and design in sync.

So I run it on my code base and get this handy message:


```
/design-sync converts a JS/React design system — one whose dist/ compiles to a standalone browser bundle exposing components at window.<globalName>.* — so the claude.ai/design agent can render them live and emit React code your engineers ship.
```

Oh. React says no. My [design system](https://developer.wordpress.org/themes/global-settings-and-styles/) is one JSON file and PHP that reads it – no `dist/`, no browser bundle, no `window.DgLtd`. But it turned “try the new command” into a more interesting question than the one I started with: not “will Claude Design sync my tokens for me” – it won’t. Well unless you use React. I don’t, I’ve never really taken to it to be honest. It has its place, but that appears to be increasingly a lot of places + 100kb of Javascript before a page renders.

## The tool tells you what it thinks a design system is

Read that error message again slowly and it’s not describing a limitation, it’s proposing a definition. A “design system”, to this tool, _is_ a compiled React bundle that mounts in a browser and answers to `window.<globalName>`. Everything else – a `theme.json`, a set of Sass tokens, a Rails design system expressed as ERB partials and a stylesheet – isn’t a design system in the sense the tool means. It’s a thing you’d need to translate into one first.

React becomes the default medium for “design system” the way it became the default for a lot of things over the last decade: not because it’s the only correct way to express reusable, styled, documented components, but because it’s the format the tooling ecosystem converged on, there are [myriad reasons for this](https://infrequently.org/series/reckoning/). A design system is genuinely just tokens, rules, and components, with one place those are defined and everything else reading from it. That definition doesn’t care what language does the reading. The moment a tool narrows “design system” down to “compiled JS bundle exposing `window.*`“, it’s not offering interoperability with design systems in general – it’s offering interoperability with itself.

None of this is unique to Claude Design’s sync command – it’s how the wider industry has decreed design becomes code. Figma sells itself as the best way to design an interface, and a whole ecosystem of “tape” exists purely to carry that output into React so it can ship: dev-mode inspectors, code-gen plugins, Storybook, handoff tools that turn a frame into a component. The tape mostly works, in the sense that code comes out the other end. But look at what’s upstream of what in that pipeline: the source of truth is a picture, and the tape’s entire job is reverse-engineering intent out of pixels after the fact. A frame in Figma isn’t a fact about the product the way a token is a fact – it’s an artist’s impression of one, redrawn every time someone opens the file.

I’m not the first to notice. There’s a whole tooling category – Tokens Studio, Style Dictionary, the W3C Design Tokens spec – that exists purely to get tokens out of design files without hand-copying, which only makes sense if the industry already agrees this is a real, common failure and not something I ran into because I happened to be using Claude Design. And a frame can’t carry the parts of a product that were never visual in the first place: a11y, tab order, ARIA semantics, focus behaviour, the states nobody drew, the pages nobody thought about. Tape can approximate a colour. It can’t reverse-engineer accessibility out of a rectangle that never had any.

This takes real collaboration between teams, no amount of tooling can get around those issues. This plumbing has been built up so we don’t have to speak to each other.

To be fair to Figma, modern auto-layout isn’t purely a picture any more – padding, gap, and resize behaviour are real rules that map fairly closely to flexbox, so some of this gap has already narrowed. But it’s not zero. And the design is not the whole system. It never can be. No amount of tooling will change that, this is not an engineering problem.

## The sync process, end to end

Back to the /design-sync command, I wasn’t going to reshape a WordPress theme into a React bundle to satisfy an import format, and I don’t think the fix is better tape either. WordPress is the thing I use; the drawing in Claude Design is a picture of it, same as a Figma frame is a picture of it – neither gets to outrank the thing it’s a picture of. So, as an experiment, I built the smaller thing instead: a process that keeps `theme.json` as the only place a value is ever written, and treats Claude Design as just another reader of it. If Claude Design wants to sync to React, could I sync back up by pretending I am something I am not?

What I ended up with, tl;dr:

- **Generate** – a Eleventy template reads the same `theme.json` the theme itself builds from, and writes the tokens and reference-card data Claude Design expects.
- **Validate** – a small linter checks every card against the real palette before I trust a push.
- **Publish** – manual step. Nothing here talks to anything automatically.
- **Verify** – a hash check compares built files against a stamped manifest and tells me if I forgot to push.

I could basically sync back up to main, but it’s flaky and honestly not worth it.

## Is this AI tools talking to each other?

I set out partly to see if it could be – two AI-adjacent tools, sharing a live source, no human doing the copying. Having built it, the honest answer is no, and I think that’s the actually useful finding here, more than the token pipeline itself.

At no point does Claude Design read from my repo, and at no point does anything in my repo talk to Claude Design’s API. What exists is: a script that reads `theme.json` and writes files in two dialects, a linter that checks one of those dialects against the source before I trust it, a human (me) who clicks a button in a browser, and a second script that nags me if I didn’t. That’s not agent-to-agent sync. That’s a human with a coding assistant built a translator, then built a second, smaller assistant whose whole job is catching the human when they forget the manual step. The intelligence involved was almost entirely mine and Claude Code’s, applied to a very old problem – keep one source of truth, make everything else read from it – dressed up in a new tool’s vocabulary.

If that sounds like a smaller result than “AI tools syncing,” it is, and I think that’s worth saying plainly rather than overselling the four scripts as more than they are. What actually blocked true interoperability wasn’t a capability gap – Claude Design clearly _can_ render from data, that’s what the cards are. It was a format gap: the sync command has one accepted input shape, my source wasn’t in it, and nothing on either end negotiates that. That’s the same failure mode as any two systems that were each built assuming they’d be the centre of the workflow – it just happens to be dressed in AI branding on both sides this time.

There is a separate point that this is a **two** way sync, pull down and push up and that is pretty cool. It’s not a 1 directional flow from design > dev but both ways, which is pretty interesting in and of itself and different to how things were done traditionally. But only if you use React.

## The default nobody chose

But the more I sit with it, the token pipeline itself isn’t really the point either. Traditionally designers manage design systems. They drift, naturally, the moment a developer starts translating one into code – and a system can’t cover everything a real product throws at it; there will always be a residue that needs a person’s judgement, on both sides of that translation.

To do so, developers and designers need to be part of the end-to-end process.

- Teams make good software _not_ JSON
- People talking around a problem delivers better outcomes for users, _not_ `npm run design:status`
- Tokens are _not_ user experience

Further, this is a new design tool that’s prescribing a singular framework choice, React – why? I believe this is partly due to the training data. Many projects instinctively reached for React over the last decade (sometimes referred to as [front-end’s lost decade](https://www.youtube.com/watch?v=7ge8iwaNNAw)) not because it was the best tool for the job – in many cases it really was not. It’s bloated, complex and can be less performant (especially on lower powered mobile devices), but teams and engineers preferred it due to its developer experience (DX), app like experiences, as well as teams doing it because it’s what others were reaching for. So millions of projects were built on React, millions of repos, millions of data points for training data in AI. React sits at 83.6% of front-end framework usage ([State of JS 2025](https://www.infoq.com/news/2026/03/state-of-js-survey-2025/)) and 44.7% among all developers ([Stack Overflow 2025](https://survey.stackoverflow.co/2025/technology)) – and among React’s own users, ‘design systems’ is the second most common thing they build with it, after web apps ([State of React 2025](https://2025.stateofreact.com/en-US/usage/)). No wonder it’s the preferred outcome for AI agents, why wouldn’t it be?

![Person pouring large olive oil bottle over a salad with the words Developers (person), Javascript (bottle) and Website (salad)](https://dgw.ltd/wp-content/uploads/2026/07/javascript-273x300.png)

So what started as an “oh, I wonder if I can sync my design system” ended up as a “huh, we are heading towards a singular tooling landscape just because” – not the best fit for the project, not the best experience for the user, but a de facto default system.

So yes, you can have synchronicity in your code and design, but only if you use this specific tooling. We run the risk of extending front-ends lost decade even further.