design-parity

August 28, 2026 · View on GitHub

A tool-neutral bot that proves a UI pull request is at parity with its intended design. On a UI PR it (1) resolves which design reference matches the changed component, (2) renders the new code (the candidate), (3) diffs candidate vs reference (visual + semantic + token), and (4) posts a verdict in the PR — e.g. "implements Figma Button/Primary; padding 12dp vs spec 16dp; dark-theme contrast fails AA."

The candidate side is owned by the upstream compose-preview renderer. The value here is the reference side (Figma / Google Stitch / Claude Design) and the correspondence layer that decides which design maps to which code component.

Architecture

One ReferenceAdapter interface, four drivers, a source-agnostic diff engine:

reference source ─┐
 figma (REST +    │   ┌──────────────┐      ┌───────────┐     ┌─────────┐
  Code Connect)   │   │ DesignReference│ ──▶ │ diff engine│ ──▶ │ Verdict │
 stitch (SDK)     ├─▶ └──────────────┘      └───────────┘     └─────────┘
 claude-design    │           ▲                   ▲
  (HTML export)   │           │                   │
 bundle (PNGs +  ─┘    correspondence        CandidateRender
  manifest)             resolver              (compose-preview)

Correspondence is resolved by Code Connect where available (Figma), else by an in-repo design-map.json, else by name convention with a low-confidence flag.

Six principles shape the design — generate committed scripts over runtime AI; lead with a11y + i18n; bootstrap a baseline for projects with no design system; interactive for setup, unattended in steady state; parity has a committed direction; and promote (never require) Compose Multiplatform for cheaper rendering. See docs/PRINCIPLES.md.

Packages

PackageStatusWhat it owns
@design-parity/core✅ this PRShared contracts (DesignReference, CandidateRender, DesignTokens, SemanticTree, ReferenceAdapter, Verdict) + the design-map.json schema, loader, and validator CLI.
@design-parity/adapter-figma✅ #2Figma REST + Code Connect driver.
@design-parity/adapter-stitch✅ #3Google Stitch SDK + manifest driver.
@design-parity/adapter-claude-design✅ #4Claude Design committed-HTML-export driver (no read API; rasterized headlessly, linked via design-map.json).
@design-parity/adapter-bundle✅ #32Image-bundle driver: a committed directory or .zip of reference PNGs + a manifest.json (no design-tool API, no HTML export), linked via design-map.json.
@design-parity/candidatecompose-preview CLI wrapper → CandidateRender.
@design-parity/diff✅ #6Visual + semantic + token diff → Verdict (a11y + i18n first, then tokens, then pixels).
@design-parity/resolverCorrespondence (code ↔ design): Code Connect → design-map.json → name convention.
@design-parity/checks✅ #25a11y + i18n spec checks (the high-value findings) + the committed design-parity.checks.json (schema, loader, validator CLI) so bootstrap's tuned thresholds reach the engine at run time.
@design-parity/baselineDetect maturity (3 rungs); materialize a concrete parity direction; bootstrap an opinionated committed baseline (tokens, starter design-map.json, check config) when there's no design system; propose a design reference per component by ranking a design file's components against it. Interactive CLIs; never on the Action path.
@design-parity/policy✅ issue #12Committed .design-parity.json (schema, loader, validator CLI) + the deterministic autodesign-led/code-led direction resolver. Also carries the tokens comparison policy — missingNumerics (what a numeric the candidate cannot report is worth) and textDerivedInsets (whether an inset measured off a glyph counts as padding); see token matching §4.3.
@design-parity/action🚧 #8 · #9Orchestrator + CLI landed (registry → resolve → diff → policy → report); GitHub Action surface next. Includes optional Code-to-Canvas push-back (#9): gated on an opt-in flag + code-led + a figma source, writing the candidate render back via an injectable CanvasWriter (@design-parity/adapter-figma's FigmaCanvasWriter).
@design-parity/report-html✅ #31Per-run self-contained HTML comparison page: reference | candidate | diff side by side with the verdict findings, inlined to one offline .html (data-URI PNGs + inline CSS/JS, no external assets). Deterministic; leaf consumer.
design-parity✅ #61Top-level CLI package (unscoped) — owns the design-parity bin so npx design-parity run … works with no checkout. A thin launcher over @design-parity/action that also re-exports its programmatic API.
@design-parity/catalog-exportCode → design-artifact direction: render a whole component system and export it as an importable sticker-sheet catalog — per-component ideal+layout variants, a DTCG token set + Figma variable projection, and an accessibility greenline layer. Also projects a run's verdicts into parity/findings.json (compose-preview-parity-findings/v1), so a preview server can show the a11y / i18n / token / layout findings under its own comparison panels with each one anchored to the region it is about. Code-led; published kits are seed only (see docs/design-artifacts/REFERENCE_KITS.md).
@design-parity/page-backdropOpt-in, off by default. Whole-screen direction: import key Figma pages as backdrops, place every component instance on them, link each back to its code component (Code Connect → design-map.json → name → unlinked), and view the page with the code renders optionally laid on top. Not referenced by @design-parity/action; driven only by the design-parity-pages CLI. See docs/page-backdrops.md.
@design-parity/kit-indexThe design kit's own variant vocabulary, committed: walk the kit's pages, project what design-map.json references into a small figma-kit-index.json, and resolve a catalog knob (size=l) to the exact kit node that depicts it — a variant axis, or a configured instance when the variation is a component property no definition can express. Resolution reads only the committed index, so a parity run needs no design-tool credentials. Driven by the design-parity-kit-index CLI.

fixtures/ holds one golden reference per source plus a candidate render, so every package can be built and tested against stubs with no live source or renderer. See fixtures/README.md.

Guides

The pick of the doc tree is below; docs/README.md indexes all of it, including the contracts, the code→design catalog docs, and the written-up research verdicts.

Use

Run a parity check with no checkout — the design-parity CLI installs straight from npm, pairing with the already-published compose-preview CLI and Gradle plugin:

npx design-parity run \
  --components "ui/Home.kt#HomeScreen" \
  --candidate-bundles build/compose-previews/ \
  --out .design-parity/out

You get the markdown verdict on stdout plus a self-contained report.html per component under --out. See the CMP adoption guide for the full pipeline, and packages/cli for the package. For CI, consume the GitHub Action (@design-parity/action), or — for a catalog large enough that one job can't check it all inside a timeout — call the reusable workflow, which runs the same check split across N parallel jobs:

jobs:
  parity:
    uses: yschimke/design-parity/.github/workflows/design-parity-reusable.yml@main
    permissions:
      contents: write
    with:
      module: ':catalog'
      shards: 6
    secrets:
      figma-token: ${{ secrets.FIGMA_TOKEN }}

See docs/PARALLEL_PARITY.md.

Develop

npm install
npm run build      # tsc --build across the workspace
npm test           # vitest
npm run validate   # validate design-map.json against the schema

Requires Node ≥ 22.

Contributing

See AGENTS.md. In short: conventional commits, one issue per branch + PR, human-only git authorship, and agent/... branch names.