Guides03/10
For engineers
OpenDesigner turns design decisions into files you import: DTCG 2025.10 tokens, CSS variables, a Tailwind v4 theme, Swift and Jetpack Compose files, and a DTCG resolver. engine.py review finds values typed straight into your code that skip the tokens. DESIGN.md and a short note in AGENTS.md tell coding agents to use the tokens too.
What you get
All paths are inside opendesigner/ in your project.
tokens/: the source of truth, in DTCG 2025.10 format. Light and dark, three densities and reduced motion are modes, tied together byopendesigner..resolver.json build/: CSS custom properties, namedcss/ tokens.css --ds-....build/: a Tailwind CSS v4 theme.tailwind/ theme.css build/: SwiftUI values underswift/ DesignTokens. swift DS.build/: Jetpack Compose values.compose/ DesignTokens.kt build/: one resolver file for tools that take a single entry point.dtcg/
Never edit an export by hand. Change the decision and rebuild, and every export updates together.
Wire it in
Plain CSS
Import the file once at the root of your app, then use the variables:
@import "../opendesigner/build/css/tokens.css";
.card {
background: var(--ds-color-surface-raised);
color: var(--ds-color-text-primary);
}Dark mode follows prefers-color-scheme. Set data-theme="light" or data-theme="dark" to override it. Density switches with data-density (spacious, comfortable or compact). Reduced motion follows prefers-reduced-motion, with a data-motion override. Font sizes are in rem, so browser text zoom works.
A value typed in by hand
It looks right today. It skips dark mode, density and the next rebuild, and engine.py review flags all three.
.card {
background: #f3f4f6;
border-radius: 7px;
padding: 13px;
}
The token for the role
The value follows the decision. Change the decision and rebuild, and this card changes with every other one.
.card {
background: var(--ds-color-surface-sunken);
border-radius: var(--ds-radius-container);
padding: var(--ds-space-12);
}
Tailwind v4
Add two lines to your main CSS file, for example src/. Adjust the path to where that file sits:
@import "tailwindcss";
@import "../opendesigner/build/tailwind/theme.css"; theme.css imports tokens.css itself, so modes keep working. Classes follow the token roles, such as bg-action-primary, text-fg-primary, rounded-control and h-control-md. DESIGN.md lists the class for each role.
By default, the export switches off Tailwind's own colors, text sizes, radii and shadows. That way a stray bg-blue-600 or rounded-lg doesn't compile. To keep them, run engine.py set exports.tailwindReset false, then engine.py build.
iOS
Add DesignTokens.swift to your iOS target. Colors switch with the system appearance, for example DS.Colors.textPrimary. Text uses Dynamic Type text styles, so it follows the person's text size setting.
Android
Add DesignTokens.kt to your Android UI module. It holds light and dark color sets plus spacing, type and motion values.
If the brand font's licence doesn't cover apps, the Swift and Compose files use the system font instead, and say so.
Token tools
Point your token tool at tokens/, or at the single file in build/. The export skill names Style Dictionary, Terrazzo, Tokens Studio and Penpot as tools that read this format. We have not tested any of them yet.
Add a value the system lacks
First check that no existing token fits. If none does, add one through the engine with a reason:
engine.py set size.row.md 36 --why "table rows in the jobs list"
engine.py set color.bg.highlight '"#fff4c2"' --why "highlighted search matches"
engine.py set dark:color.bg.highlight '"#3a3000"' --why "the same highlight in dark mode"
engine.py buildA new color still has to pass the contrast check. build reports it if it doesn't.
Find hard-coded values
Run this at the end of any piece of work:
engine.py review --project srcIt reads style sheets, JavaScript and TypeScript, Vue, Svelte, HTML, Swift and Kotlin files. It finds colors, sizes, radii, shadows and durations typed in by hand and names the token to use instead. Here is part of the output from a test run:
card.css:1 #f3f4f6 -> use var(--ds-color-surface-sunken)
card.css:1 border-radius: 7px -> use var(--ds-radius-container) (12px, the container radius)
card.css:1 padding: 13px -> use var(--ds-space-12) (13 is off the 4px ladder)It also lists code that breaks a standard, and DESIGN.md sections that are out of date. Add the comment od-ignore to a line to keep a raw value on purpose. --strict makes the command fail when it finds anything, and --json prints machine-readable output.
DESIGN.md and AGENTS.md for coding agents
DESIGN.md has a section for AI agents. It tells them to read the file and the tokens before changing any screen, to use tokens instead of raw values, and to leave locked decisions alone.
At the end of a session, OpenDesigner asks whether to add a short note to your AGENTS.md. It adds it only after you say yes. The note tells later agents to:
- read
DESIGN.mdandPRODUCT.mdbefore any visual work; - use the tokens or their exports, and never hard-code colors, sizes, spacing, radii, shadows or durations;
- check
opendesigner/for why a value is what it is;decisions.md - run
engine.py reviewat the end of every implementation and fix what it finds.
About the engine
The engine is one Python file that needs Python 3.10 or newer. It uses only the standard library and makes no network calls. The same state.json gives the same tokens. It has 157 tests, which pass on the maintainer's computer. No CI runs are recorded yet.
Not yet
- No direct React Native or Flutter export.
- Only buttons, a text field and a card are previewed as components.
See Engine commands and Export for more.