Design systems

Three token tiers, the semantic contract every pack satisfies, the thirteen packs and twelve original templates, and how to build your own.

A UI document never contains a colour, a font size or a radius. Every visual value comes from a design-system pack: a set of design tokens in the W3C DTCG 2025.10 format. Swap the pack and the same document renders in a different design system, with no change to the JSON.

Three token tiers#

Tier What it holds Example
Primitive (reference) Raw palettes, type families, spacing steps md.ref.palette.primary.40, carbon.color.blue.60
System The design system's own named roles, often per mode md.sys.color.on-surface, carbon.theme.text-primary, antd.token.colorText
Semantic The Polyxd contract: the only tier renderers and documents see color.text.default, type.body.default, size.target.min

Each pack keeps its design system's own names in the primitive and system tiers, so every semantic token can be traced back to its source. Semantic tokens are {alias} references to system tokens wherever an equivalent exists.

The semantic contract#

packages/spec/tokens/semantic-contract.json (contract version 0.1.0) lists what every pack must provide, in every mode it declares:

Token Constraint Why
type.body.default font size at least 16px Readable body text
size.target.min at least 24px WCAG 2.2 2.5.8 target size (minimum)
measure.max 45–75 Comfortable line length
opacity.state.disabled 0.3–0.6 Disabled content stays perceivable but clearly inactive

The contract checker resolves aliases, checks each token's type, measures every contrast pair (compositing translucent colours before measuring), and checks the constraints.

The packs#

Pack Modes Built from
@polyxd/ds-material3 light, dark @material/material-color-utilities 0.4.0 (seed #6750A4, tonal spot) and material-web v0_192 token sources
@polyxd/ds-carbon light (Carbon White), dark (Carbon Gray 100) @carbon/colors, themes, layout, type, motion and charts, at pinned versions
@polyxd/ds-antd light (defaultAlgorithm), dark (darkAlgorithm) antd 6.6.4 and @ant-design/colors 8.0.1
@polyxd/ds-fluent light (webLightTheme), dark (webDarkTheme) @fluentui/tokens 1.0.0-alpha.24
@polyxd/ds-shadcn light, dark shadcn/ui's default theme variables and Tailwind CSS 4.3.3's scales
@polyxd/ds-bootstrap light, dark ([data-bs-theme]) bootstrap 5.3.8's CSS custom properties
@polyxd/ds-mantine light, dark ([data-mantine-color-scheme]) @mantine/core 8.4.2's stylesheet
@polyxd/ds-radix light, dark @radix-ui/themes 3.3.0 at its defaults: indigo accent, medium radius, 100% scaling
@polyxd/ds-polaris light, dark (.p-theme-dark) @shopify/polaris-tokens 9.4.2's stylesheet
@polyxd/ds-primer light, dark @primer/primitives 11.10.0's base scales, functional scales and theme files
@polyxd/ds-spectrum light, dark @adobe/spectrum-tokens 15.4.1's variables.json, desktop scale
@polyxd/ds-govuk light (GOV.UK has one theme) govuk-frontend 6.5.1's Sass settings
@polyxd/ds-chakra light, dark @chakra-ui/react 3.37.0, via its own getTokenCss() emitter

Each pack is generated by a script from vendored, version-pinned sources, gives the same output on every run, and records provenance in its manifest. None of the values are scraped from design-system websites.

A pack's manifest also records its logo, and the pack ships it: "logo": { "file": "logo.svg", "source": "<the owner's URL>", "guidelines": "<their brand rules>" }. It is the system's official file, unaltered, from the owner's own site or repository, and Polyxd shows it only beside the system's name, on a white tile, to say which system a pack is modelled on. Where the owner doesn't allow that, the manifest has words instead of a file ("text", with a note saying why) and the pack is named without a logo: GOV.UK, whose crown and logotype are protected, and Material 3, Carbon, Polaris, Fluent 2, Spectrum 2 and Primer, whose owners allow their logos only with permission. Six packs have their logo today: shadcn/ui, Ant Design, Bootstrap, Chakra UI, Mantine and Radix.

Templates#

Alongside the 13 design systems there are twelve original templates: packs that reproduce nobody's brand, each with one clear character, each passing the same contract check in light and dark. They exist to be copied and changed. A team without a design system starts from the nearest one; a team with one uses them to see what a role is for before mapping its own tokens. Their manifests carry "template": true and provenance that says so. Each has a small mark, logo.svg, that Polyxd draws from the template's own tokens (its ground, border, radius, text, primary and accent) with node packages/ds-kit/scripts/pack-logos.ts; a test fails if one no longer matches its tokens.

Template Character Type
@polyxd/ds-sketch Hand-drawn: paper and ink, pencil-grey borders, no shadows, uneven corners, wavy underlines, cards that lean a third of a degree Caveat, Patrick Hand, Nunito
@polyxd/ds-wireframe The second sketch look, low-fidelity: greyscale, dashed borders, placeholder blue for anything you can act on, hatched media, mono labels System sans, JetBrains Mono
@polyxd/ds-editorial Serif display, warm paper, hairline rules, a 72-character measure, oxblood accent; magazines and long reads Fraunces
@polyxd/ds-brutalist Two-pixel black borders, flat yellow and black, hard 4px shadows, no radius anywhere, mono labels Space Grotesk, Arial, JetBrains Mono
@polyxd/ds-glass Translucent surfaces over a cool ground, an edge highlight, wide soft shadows, 20px corners System sans
@polyxd/ds-terminal Dark by default, monospace in every role, phosphor green and amber, 2px radii, dense JetBrains Mono
@polyxd/ds-pastel Mint, lavender and peach, pill buttons, 16px cards, a friendly rounded sans; consumer apps Nunito
@polyxd/ds-civic Plain and high-contrast: 18px body, one blue, 48px targets, a thick focus ring; public services System sans
@polyxd/ds-finance Navy and gold, serif titles, tabular figures, 4px radii, dense tables; banking and trading Georgia, system sans
@polyxd/ds-health Calm teal on cream, extra spacing, 48px targets, warm feedback colours; care and wellbeing System sans
@polyxd/ds-neon Dark by default, magenta primary, cyan links, shadows that glow; entertainment and gaming Space Grotesk
@polyxd/ds-mono One hue in every role, written as oklch(L C 275): change the hue once and the whole system follows System sans

The Google Fonts they name are OFL and are not shipped; each falls back to a stated system stack and still passes every check without them.

The two sketch looks need one thing tokens can't say. A wobbly corner, a wavy underline or a dashed border isn't a value, so a manifest may name an extras stylesheet ("extras": "tokens/extras.css") that the theme compiler appends verbatim to the pack's theme CSS. It is held to two rules, checked at build: every selector is scoped by [data-pxd-theme="<name>"], and it names no colour of its own — only var(--pxd-…) tokens — so recolouring the tokens recolours the extras. Sketch and wireframe are the only packs that use it, and a test keeps it that way.

Each template's README says what it is for and how to make it yours: edit its palette (every role points at a named colour), or run npx polyxd pack on your own tokens and keep the template beside you as a reference.

Layout a token can't express#

One thing kept not fitting: a dialog's footer. Carbon's runs the full width of the dialog in equal halves; Material's, Ant's and everyone else's sits inline at the trailing edge. That is a layout decision, not a value, and copying Carbon's into the renderer as a special case would have put a design system's name in the renderer.

So a manifest may set layout, a small set of variables the renderer defines and documents — currently action-gap, action-item and action-bleed. The renderer's stylesheet reads them with its own defaults, so a pack that says nothing keeps the inline footer, and a pack may set these variables but may never add a rule. Carbon is the only pack that sets any today:

"layout": {
  "action-gap": "1px",
  "action-item": "1 1 0",
  "action-bleed": "var(--pxd-space-stack-default) calc(-1 * var(--pxd-space-inset-comfortable)) calc(-1 * var(--pxd-space-inset-comfortable))"
}

What building the packs found#

Mapping thirteen real design systems onto one contract surfaced real accessibility gaps. The packs fix them by moving to the nearest passing value from the same design system, and leave the original tokens in place.

Each pack's README lists every mapping and adjustment with before and after ratios.

Theme CSS#

@polyxd/react compiles each pack into one CSS file, themes/<pack>.css. Only semantic contract tokens are emitted; renderers never see primitives.

[data-pxd-theme="material3"]:not([data-pxd-mode]),
[data-pxd-theme="material3"][data-pxd-mode="light"] {
  --pxd-color-surface-default: #fdf7ff;
  --pxd-color-text-default: #1d1b20;
  --pxd-color-action-primary-background: #65558f;
  /* … every contract token … */

  /* shadcn/ui variable names, so shadcn components follow this pack too */
  --background: var(--pxd-color-surface-default);
  --primary: var(--pxd-color-action-primary-background);
  --radius: var(--pxd-radius-default);
  color-scheme: light;
}

Token names become variables by replacing dots with dashes and adding --pxd-: color.text.default is --pxd-color-text-default. Typography tokens expand into -family, -size, -weight, -line-height and -letter-spacing.

Each theme also sets shadcn/ui's variable names (--background, --foreground, --card, --popover, --primary, --secondary, --muted, --accent, --destructive, --border, --input, --ring, --radius, --chart-1 to --chart-5), so an existing shadcn app picks up the same pack.

The PolyxdSurface theme and mode props set data-pxd-theme and data-pxd-mode on the surface element.

Make your own pack#

A pack is a manifest plus DTCG token files.

1. Write the manifest (manifest.json, validated by schema/design-system.schema.json). Files listed for a mode are merged in order, later files overriding earlier ones.

{
  "$schema": "../spec/schema/design-system.schema.json",
  "name": "acme",
  "displayName": "Acme",
  "version": "0.1.0",
  "contractVersion": "0.1.0",
  "license": "Apache-2.0",
  "modes": {
    "light": ["tokens/primitive.json", "tokens/system.json", "tokens/system.light.json", "tokens/semantic.json"],
    "dark": ["tokens/primitive.json", "tokens/system.json", "tokens/system.dark.json", "tokens/semantic.json"]
  },
  "defaultMode": "light",
  "provenance": [{ "source": "Acme brand tokens", "version": "2026.1" }]
}

2. Write DTCG token files. Keep your own names in the primitive and system tiers, and alias them from a semantic file that defines all 86 contract tokens. A $type on a group is inherited by its tokens.

{
  "color": {
    "$type": "color",
    "text": {
      "default": { "$value": "{acme.color.ink}" },
      "muted": { "$value": "{acme.color.ink-soft}" }
    }
  }
}

3. Check it against the contract.

npm run check-ds -w @polyxd/spec -- ../ds-acme/manifest.json
[light] color.text.muted: contrast 3.92:1 against color.surface.default is below 4.5:1 (WCAG 2.2 1.4.3)

1 issue(s)

It exits with 0 and prints "Design system satisfies the semantic token contract." when every mode passes. From code, use checkDesignSystem(manifestPath) from @polyxd/spec.

4. Compile it to CSS. Put the pack in packages/ds-<name>/ and run npm run build:themes -w @polyxd/react, or pass manifest paths to scripts/build-themes.ts directly.

Studio imports a design system as it is: an npm package, a .tgz, a Tokens Studio file, a W3C DTCG file or CSS custom properties. An importer for Figma variables is planned.

Polyxd is an early preview. Found something unclear? It will get better with your feedback.