@design-parity/adapter-claude-design
v0.1.38
Published
Claude Design reference adapter: resolves a committed HTML export via design-map.json, rasterizes it headlessly, and normalizes to a DesignReference. Claude Design has no read API and no Figma export.
Downloads
2,561
Readme
@design-parity/adapter-claude-design
The Claude Design ReferenceAdapter for
design-parity. Depends only on @design-parity/core.
There is no Claude Design read API
Claude Design (beta since 2026-06) exposes no read API and no Figma export,
so — unlike the Figma adapter (REST + Code Connect) or even Stitch (SDK) — there
is nothing to fetch at run time. The reference is consumed as a committed HTML
export checked into the consumer repo. Because there is no machine link to
call, the correspondence is always a design-map.json entry and the resulting
DesignReference always has linkMethod: "manifest".
/design-sync(2026-06): Claude Code's/design-syncnow syncs a design system between the canvas and the repo — including pushing built UI back into Claude Design (the reverse direction thecompose-preview-design-boardskill used to own) and emitting committed, machine-readable tokens/components. This is a governed read → plan → write skill, not a read API the adapter can call, so the committed-export shape below is unchanged. But it does make the input machine-generated-and-committed rather than hand-authored, and opens a richer reference (synced tokens, see below) and aref → codereverse index (already shipped:buildReverseIndexin@design-parity/resolver). See docs/claude-design-sync-impact.md.
Push-back is /design-sync, not a CanvasWriter
design-parity ships no claude-design CanvasWriter and runs no
Code-to-Canvas push-back for this source. There is no Claude Design write API,
and /design-sync's canvas push-back is an interactive, human-run terminal
skill — it has no place on design-parity's unattended GitHub Action path
(PRINCIPLES.md 1 "no AI in the CI loop", 4 "unattended in steady state", 5).
So the reverse direction — getting what you built into Claude Design — is
/design-sync itself, run by a person, and supersedes the older
compose-preview-design-board skill that
hand-built HTML to import. The Action's read-only job stays the same: resolve a
committed reference and diff it. (Contrast Figma, where FigmaCanvasWriter +
the opt-in code-led push-back exist precisely because that bridge is a
non-interactive REST/plugin write.)
design-map.json ──▶ design/reference/*.html ──▶ rasterize ─┐
(manifest) (committed export) (headless) ├─▶ DesignReference
└─ handoff manifest ──▶ tokens ───┘ (manifest)The HTML export
A committed export is an ordinary HTML document carrying one embedded handoff manifest:
<script type="application/design-parity+json">
{
"componentId": "ui/Card.kt#OfferCard",
"tokens": { "spacing": { "padding": 16 }, "radius": { "corner": 12 } },
"images": [
{ "state": "default", "theme": "light", "size": "medium",
"src": "./offer-card.light.png" }
]
}
</script>images[].src— a pre-rendered PNG, resolved relative to the HTML file. Itswidth/heightare read from the PNG itself, so reference dimensions can never drift from the committed bytes. A variant with nosrc(or an export with noimagesat all) is rasterized headlessly from the document.tokens— inlineDesignTokens, or a string path to a handoff token file (relative to the HTML) for token-compliance checks.componentId— optional; when present it must match the component the resolver asked for, elseresolvethrows.
The synced token artifact (.json ref)
When a design-map.json ref ends in .json, the adapter treats it as a
synced design-system token artifact — a committed W3C DTCG
document, typically emitted by Claude Code's /design-sync — instead of an HTML
export. It is loaded through @design-parity/core's loadDtcgTokens into a
token-only DesignReference:
referenceImagesis[]and nothing rasterizes (no HTML, no layout capture) — the reference feeds the token-compliance diff only.linkMethodis still"manifest"(there is no read API; this is a committed file).resolvethrows aclaude-design-prefixed error if the file is missing, isn't JSON, or fails DTCG schema validation.
// design-map.json — point the ref at the synced DTCG document
{ "code": "ui/Card.kt#OfferCard", "source": "claude-design",
"ref": "design/design-system.tokens.json" }This is the richer of the two shapes: the token table comes straight from the synced design system rather than an export's embedded handoff block. See docs/claude-design-sync-impact.md.
Live-render a prototype (live: ref, #85)
A committed export is a single flattened frame. When a design-map.json ref is
prefixed live:, the adapter instead drives the actual clickable
prototype in a browser and captures it at each configured viewport — a
truer reference that also picks up whatever the static export flattened, and one
that pairs per-cell against the candidate's device × breakpoint render matrix.
// design-map.json — opt one component into live-render
{ "code": "ui/Card.kt#OfferCard", "source": "claude-design",
"ref": "live:design/prototypes/offer-card.html" }- Opt-in. Only a
live:-prefixed ref takes this path; every unprefixed ref stays on the lighter static-export path, unchanged. Mirrors thefigma:/stitch:ref schemes. - Multi-viewport. Each configured
LiveViewportbecomes oneImagekeyed by itssizeslot (compact/medium/expanded). The default is a single compact frame; passliveViewportsfor a wider matrix. - Same contract. The result is a normal
DesignReferencewithlinkMethod: "manifest"— the diff engine can't tell it from a static export. - Injectable renderer. The default
browserLiveRendererdrives headless Chrome/Chromium onPATH(setCHROME_BIN), identical in spirit to the rasterizer — no browser-automation dependency is bundled. A caller already running Playwright (or a hosted renderer) injects its ownliveRenderer:
new ClaudeDesignAdapter({
liveRenderer: myPlaywrightRenderer,
liveViewports: [
{ size: "compact", width: 412 },
{ size: "expanded", width: 1280 },
],
});resolve throws a prefixed error when the live: ref names no path, the
prototype is unreadable, or a configured viewport fails to render.
Usage
import { ClaudeDesignAdapter } from "@design-parity/adapter-claude-design";
const adapter = new ClaudeDesignAdapter();
const ref = await adapter.resolve(
"ui/Card.kt#OfferCard", // resolver-supplied code handle
"design/reference/offer-card.html", // the design-map ref (repo-relative)
{ repoRoot: process.cwd(), env: process.env },
);Rasterization
Rasterizing raw HTML variants defaults to browserRasterizer, which drives a
headless Chrome/Chromium already on PATH (set CHROME_BIN to point at a
specific binary) — no browser-automation dependency is bundled, keeping the
package's only runtime dependency @design-parity/core. Inject your own to
render inside an existing harness:
new ClaudeDesignAdapter({ rasterizer: myRasterizer });Exports that ship pre-rendered src images never invoke a rasterizer.
Errors
resolve throws a clear, prefixed error when the export is missing, its handoff
block is malformed, a referenced token file or image is missing, or the export's
componentId contradicts the resolver.
