| name | designtools-tokens |
| description | Generate a complete colour token system from a brand colour and write it into a scaffolded project. Drives the @designtools/tokens generator; CSS custom properties are the lead output, with Tailwind v3/v4, DTCG, and Lovable exports available. Use at scaffold time (designtools-start) or whenever a project's palette needs regenerating from a brand colour. |
Design tokens
The design-system step of the designtools suite. Given a brand colour, @designtools/tokens generates twelve-step primitive scales, semantic intents with contrast-checked foregrounds, surface and utility tokens, in light and dark, and serialises them for a scaffolded project. Pure computation — no browser, DOM, or React.
It is a package the agent runs, not code the suite carries: the canonical source lives at packages/tokens in the designtools repo and ships as the published @designtools/tokens, exactly like @designtools/surface.
Usage
Run the published CLI with npx (no install; skill sandboxes run plain Node, and the published package is compiled):
npx @designtools/tokens --primary "#4e9caf" # CSS custom properties to stdout
npx @designtools/tokens --primary "#4e9caf" --vanilla --out src/styles/tokens.css
npx @designtools/tokens --primary "#4e9caf" --format all --out ./tokens
For the vanilla-CSS suite, the default --format css is the one to use: write it to the project's stylesheet directory and reference the variables directly (var(--primary), var(--canvas), var(--border)). Pass --vanilla to omit the shadcn/ui aliases — right for Base UI / vanilla-CSS stacks. The Tailwind exports are secondary, only needed when a scaffold uses Tailwind.
Working inside the designtools monorepo itself, run it from source instead:
npx tsx packages/tokens/src/cli.ts --primary "#4e9caf" --vanilla --out src/styles/tokens.css
Programmatic use:
import { generateTokens, exportTokens } from "@designtools/tokens";
const tokens = generateTokens({ primary: "#4e9caf", neutral: "#9aa1af" });
const css = exportTokens(tokens, "css", { colorFormat: "oklch" });
Input contract
Seeds:
| Input | CLI flag | Default |
|---|
| Primary brand colour | --primary (required) | — |
| Neutral seed | --neutral | #747474 |
| Additional colours | --color name=value (repeatable) | none |
Any culori-parseable colour string is accepted: hex, rgb(), hsl(), oklch(), named colours.
Options:
| Option | CLI flag | Values | Default |
|---|
| Contrast algorithm | --contrast | wcag, apca | wcag |
| Contrast target | --target | aa-large, aa, aaa | aa |
| Lightness strategy | --lightness | fixed, perceptual | fixed |
| Shade overrides | --overrides file.json | see the package's types.ts | none |
| Colour value format | --color-format | oklch, hex, rgb, hsl | oklch |
The library defaults are wcag/aa/fixed. The original web tool's UI defaults differ in one place: it starts on apca. Pass --contrast apca to match the tool's out-of-the-box behaviour.
Success, destructive, and warning colours are not inputs: they are derived from the primary (fixed hues 145°, 25°, 75°; lightness and chroma scale with the primary's chroma, clamped so they always read as green/red/amber).
Output contract
Four token tiers:
- Primitives —
black, white, and a twelve-step scale per colour: 25, 50, 100, 200, 300, 400, 500, 600, 700, 800, 900, 950. Shade 500 is exactly the seed colour. Scales exist for primary, neutral, success/green, destructive/red, warning/yellow (aliases share one scale), plus any additional colours.
- Semantic intents (per mode, light and dark) —
primary, neutral, success, destructive, warning, each with six slots: DEFAULT, foreground, subdued, subdued-foreground, highlight, highlight-foreground; plus a two-slot muted pair. Light mode maps DEFAULT/subdued/highlight to shades 500/50/700; dark mode to 600/200/400. Foregrounds are chosen by contrast search, not fixed mapping.
- Surfaces (per mode) —
canvas, surface, overlay with paired foregrounds, drawn from the neutral scale and white/black. Light: canvas neutral-25 on white surfaces; dark: canvas neutral-950 on black surfaces.
- Utility (per mode) —
border, input (neutral 200/800), ring (primary 400/700), shadow (neutral 950).
Dark mode is not a transformation of light mode: both are derived independently from the same primitive scales using different shade mappings, and foreground selection reruns per mode.
The TokenSystem object also carries static non-colour defaults (typography, radii, box shadows) from the web tool, visible in the json format. They are not in the CSS output the suite uses: --vanilla --format css is colour-only by design, because base.css (designtools-frontend) owns the scale. So there is no collision between the two — tokens.css is colour, base.css is the scale.
Export formats
| Format | File | Notes |
|---|
css | tokens.css | Lead format. Primitives on :root, light mode on :root, [data-theme="light"], dark on [data-theme="dark"] plus a prefers-color-scheme fallback. Semantic tokens reference primitives via var(). Includes shadcn/ui-compatible aliases unless --vanilla. |
tailwind-v4 | tailwind.css | @theme block mapping Tailwind colour names onto the same variables. Honours --vanilla. |
tailwind-v3 | tailwind.config.js | theme.extend.colors config. |
dtcg | tokens.dtcg.json | W3C Design Token Community Group JSON (hex values). |
lovable | lovable.css | shadcn/ui globals.css for Lovable-style scaffolds. |
json | tokens.json | The raw TokenSystem object, for downstream steps that want structured data. |
Guarantees
- Deterministic: same seeds and options always produce byte-identical output. No randomness, no clocks, no environment reads. (One portability caveat: the hue of a fully-desaturated colour in the
hsl colour-format is meaningless and not stable across engines; every other value is exact.)
- Parity-tested:
packages/tokens/test/ asserts the generator reproduces golden fixtures generated from the original web-tool source, run in the repo's vitest suite. Regenerate them only when a behaviour change is intended.
- Dependencies:
culori (colour maths) and apca-w3 (APCA contrast) only.