Published Build3 min read
A JSON schema is a better model-to-Figma interface than a plugin API
Compact Design puts schema validation, semantic checks and advisory lint between a language model and the canvas, and keeps its core package free of any Figma dependency.
Written for builders.See today for builders

What happened
- Compact Design is described by Elliot Silver on dev.to as a small JSON language that a language model can write, a schema can reject, and Figma can turn into native, editable frames; the package @compact-design/core validates, normalizes, lints and patches it.
- The Figma plugin is the first adapter for Compact Design, and core never depends on Figma; another tool can implement the same language.
- Core is ordinary TypeScript with no figma.* calls and no plugin typings, exposing validate, normalize, lint and applyPatch.
- The engine pipeline is: Compact Design JSON, then @compact-design/core (schema, normalize, semantic checks, lint/patch), then an adapter, then Figma.
- Schema and semantic errors block import; lint does not block and is advisory.
Compiled by The EngineerSomething wrong?How this is made
Why it matters
Elliot Silver has published Compact Design, a small JSON language that a language model can write and a Figma plugin can import as native frames, with validation, normalization, lint and patch handled by a core package called @compact-design/core [1]. The Figma plugin is only the first adapter, and the core carries no Figma dependency at all: ordinary TypeScript, no figma.* calls, no plugin typings [2][3].
The ordering is the point. Input goes schema, then normalize, then semantic checks, then lint or patch, and only then to an adapter [4]. Schema and semantic errors block import; lint does not [5]. So there are two gates that stop bad output before it reaches the canvas and one that merely complains afterwards [20].
The surface a model has to hit is small. A node requires w and h, type defaults to FRAME, and IDs are generated when you omit them, though anything you intend to update later needs an explicit one [8]. Within that, the language still covers hex fills, HUG/FILL/FIXED sizing, angle gradients, elevation presets, variables, styles, components, prototypes and images, against a single current schema rather than a set of versions [9].
What makes this usable in a generation loop is the shape of the failure. Issues come back structured with severity, code, a JSON path, a message and a suggestion; the documented example points at nodes[0].children[2].layout.direction and states that the value must be HORIZONTAL, VERTICAL or GRID [6]. That is not a pass/fail signal, it is a repair instruction with coordinates. Silver's framing is that you should not ask a model to speak Figma's plugin API, and should not ask it for CSS and then treat a screenshot as a design [17].
The advisory tier is honest about its own limits. Lint flags contrast, 44px touch targets, 4px spacing, missing Auto Layout, hard-coded colours and broken prototype destinations [7], which means a schema-valid but badly built screen still lands. There is also no browser thumbnail; Silver argues a thumbnail would lie about fonts, Auto Layout, masks and effects, so the plugin returns counts, matches and repair JSON instead [10].
Round-tripping is where most model-to-canvas tooling falls apart, and this one at least has a mechanism. Every imported canvas and layer stores its JSON id as plugin data [11]. Create new refuses a canvas ID already on the page, Update matching IDs replaces canvases in place, Replace matching canvases rebuilds them, and Export selection writes Compact Design JSON back out [12]. Full-document update is canvas-granular while a patch is node-granular, and failures roll back because the previous design is cloned first [13]. Patch operations are set, remove and append, with set touching only the fields you list [14].
Caveats are the author's own. The package is not on npm yet, so you clone the repo, npm install, npm run build, then import plugins/figma/manifest.json through Figma desktop's development menu [15][16]. Silver's closing claim, that this is the format he would trust for model-generated UI, is his alone [18].
Watch for a second adapter, which is the only real test of whether the language is tool-neutral or quietly Figma-shaped [2]. Watch whether any lint rules get promoted to blocking [5][7], and whether "one current schema" [9] survives the first breaking change once other people depend on it.
Claim ledger
Ranked by verification strength, evidence, and original report placement.
- [1]
Compact Design is described by Elliot Silver on dev.to as a small JSON language that a language model can write, a schema can reject, and Figma can turn into native, editable frames; the package @compact-design/core validates, normalizes, lints and patches it.
- [2]
The Figma plugin is the first adapter for Compact Design, and core never depends on Figma; another tool can implement the same language.
- [3]
Core is ordinary TypeScript with no figma.* calls and no plugin typings, exposing validate, normalize, lint and applyPatch.
- [4]
The engine pipeline is: Compact Design JSON, then @compact-design/core (schema, normalize, semantic checks, lint/patch), then an adapter, then Figma.
- [5]
Schema and semantic errors block import; lint does not block and is advisory.
- [6]
Validation issues are returned as structured objects with severity, code, path, message and suggestion; the documented example reports severity ERROR, code SCHEMA_VALIDATION, path nodes[0].children[2].layout.direction, and the message that the value must be HORIZONTAL, VERTICAL, or GRID.
Sources & coverage · 1 publisher
The reporting this story was synthesized from, earliest first. Every link goes to the original.
- dev.toElliot SilverAug 14Compact Design: a JSON language models can write and Figma can import
Cited in this coverage: Elliot Silver, dev.to

