Files
open-design/docs/design-systems.md
lefarcenandGitHub 16fad1c4d8 revert(design-systems): remove structured runtime workflow (#7110)
* revert: remove structured design system runtime

* fix: preserve authority boundaries during revert
2026-08-19 05:37:48 +00:00

252 lines
10 KiB
Markdown

# Design system authoring guide
**Parent:** [`spec.md`](spec.md) · **Siblings:** [`architecture.md`](architecture.md) · [`skills-protocol.md`](skills-protocol.md) · [`agent-adapters.md`](agent-adapters.md)
This guide describes the current design-system package consumed by the daemon,
picker, prompt composer, importers, and repository guards. Read it together with
[`design-systems/README.md`](../design-systems/README.md) and the contract notes
in [`design-systems/_schema/AGENTS.md`](../design-systems/_schema/AGENTS.md).
## 1. Package contract
A new design system is a package, not a standalone Markdown file. Its minimum
machine-readable shape is:
```text
design-systems/<slug>/
├── manifest.json ← discovery metadata and declared package files
├── DESIGN.md ← canonical design prose for agents
└── tokens.css ← canonical compiled CSS custom properties
```
All three files are present in the bundled catalog. The daemon retains a
`DESIGN.md`-only discovery path for legacy or user-installed folders, but that is
a compatibility fallback, not the authoring target for new repository content.
The v1 manifest uses fixed canonical file names:
```json
{
"schemaVersion": "od-design-system-project/v1",
"id": "acme",
"name": "Acme",
"category": "Productivity & SaaS",
"description": "A concise English catalog summary.",
"source": {
"type": "bundled",
"origin": "OpenDesign curated bundled fixture"
},
"files": {
"design": "DESIGN.md",
"tokens": "tokens.css"
}
}
```
- The folder and `manifest.id` must use the same normalized ASCII slug.
- `files.design` is `DESIGN.md`; `files.tokens` is `tokens.css`.
- `name`, `category`, and `description` are the primary catalog copy for a
packaged system.
- `source` records whether the package is bundled, local, GitHub, or shadcn and
carries the source-specific provenance fields.
- Every declared path must be safe, relative, and present. The schema in
[`manifest.schema.ts`](../design-systems/_schema/manifest.schema.ts) is the
source of truth for allowed keys and values.
### Rich package files
The migrated package profile can also declare:
```text
USAGE.md agent-facing read-order and usage guide
components.html standalone component fixture
components.manifest.json derived component/token index
design-tokens.json derived Design Tokens JSON
tailwind-v4.css derived Tailwind v4 mapping
assets/ optional static assets
fonts/ optional webfonts
preview/ indexed preview pages
source/ importer evidence and token reports
```
Declare these through the corresponding manifest fields (`usage`,
`files.components`, `componentsManifest`, `files.designTokens`,
`files.tailwind`, `assetsDir`, `fonts`, `preview`, and `sourceFiles`). Do not add
undeclared alternate canonical files.
Once a package opts into the rich profile, the package-quality guard expects a
complete profile: `USAGE.md`; `components.html` plus its derived manifest; and
at least three preview pages covering colors, typography, and spacing. Imported
`hybrid` and `verbatim` packages also have source-evidence requirements enforced
by the manifest guard.
Derived files are caches, not competing sources of truth:
- `components.manifest.json` is regenerated from `components.html` and
`tokens.css`.
- `design-tokens.json` is regenerated from the token-contract report and must
agree with `tokens.css`.
- `tailwind-v4.css` is regenerated from `tokens.css`.
## 2. Catalog metadata precedence
Packaged systems should put stable display metadata in `manifest.json`. The
daemon resolves catalog fields in this order:
| Field | Precedence |
| --- | --- |
| Title | user `metadata.json` override → `manifest.name` → Markdown H1 → frontmatter `name` → folder id |
| Category | user `metadata.json` override → `manifest.category` → Markdown `> Category:` → frontmatter `category` → `Uncategorized` |
| Summary | non-empty `manifest.description` → first Markdown summary paragraph → frontmatter `description` |
| Surface | user `metadata.json` override → Markdown surface metadata → frontmatter `surface` → `web` |
The H1 and `> Category:` convention therefore remains useful for readable prose
and legacy fallback, but it does not override manifest metadata in a packaged
system. Complete frontmatter color metadata wins over Markdown-derived swatches;
otherwise the daemon uses Markdown swatches and finally any partial frontmatter
row.
## 3. Writing `DESIGN.md`
`DESIGN.md` explains intent, decisions, and usage to an agent. It is not a
fixed nine-section numbered schema. For a migrated package, the quality guard
requires at least seven H2 headings (`## ...`); it does not require
specific numbers, titles, or ordering.
A useful document normally covers at least:
- visual theme and atmosphere;
- color roles and contrast intent;
- typography families, scale, leading, and tracking;
- spacing, layout, and composition;
- components and interaction states;
- motion behavior and reduced-motion handling;
- accessibility expectations;
- concrete anti-patterns.
Use headings that describe the actual system. A source-derived brand may add
sections for provenance, imagery, data visualization, editorial voice, or
platform-specific behavior. Avoid empty headings added only to meet the count.
Keep prose and compiled values synchronized. If `DESIGN.md` names an accent,
type scale, spacing rhythm, or motion duration, the corresponding binding in
`tokens.css` must express the same decision.
## 4. Authoring `tokens.css`
`tokens.css` is the canonical compiled token stylesheet that agents can consume
without translating prose into ad hoc values. Put shared declarations in a
`:root { ... }` block:
```css
:root {
--bg: #ffffff;
--fg: #18181b;
--accent: #625df5;
--font-display: "Inter", system-ui, sans-serif;
--font-body: "Inter", system-ui, sans-serif;
}
```
The current token contract lives in
[`packages/contracts/src/design-systems/token-schema.ts`](../packages/contracts/src/design-systems/token-schema.ts)
and is re-exported through `design-systems/_schema/`. The repository guard
checks required A1, A2, and B-slot tokens, default parity, fixture synchronization,
and unknown-token allowlists. A final `tokens.css` must contain every required
shared slot; brand-specific extensions must use the documented extension
allowlist rather than silently inventing cross-brand tokens.
Use semantic variables in component CSS instead of repeating raw colors:
```css
.button-primary {
background: var(--accent);
color: var(--accent-on);
}
```
When the system supports a dark variant, override semantic tokens under a
theme selector rather than copying unrelated component rules:
```css
[data-theme="dark"] {
--bg: #111113;
--fg: #fafafa;
}
```
## 5. Component fixtures and usage guides
For a rich package, `components.html` is the executable proof that the tokens
compose into real controls and layouts. It should cover at least four component
groups and use declared tokens. The quality guard currently requires at least
10 fixture selectors and 8 referenced tokens. The derived component manifest
must not contain undeclared token references.
`USAGE.md` is the agent-facing router. It must contain the H2 sections `Read
Order`, `Design Highlights`, `Do`, and `Avoid`. Keep it concise: direct the agent
to the relevant package files and call out decisions that would otherwise be
easy to miss.
## 6. Accessibility
- Verify normal text at 4.5:1 contrast and large text at 3:1 against the actual
paired background.
- Give every interactive control a visible `:focus-visible` treatment.
- Preserve native semantics and keyboard behavior in component fixtures.
- Do not claim conformance without checking every foreground/background pair
used by the fixture.
- Scope reduced-motion overrides to the elements and properties that animate.
## 7. Motion and interaction
The repository UI motion convention is a strong ease-out:
```css
:root {
--ease-standard: cubic-bezier(0.23, 1, 0.32, 1);
--motion-enter: 200ms;
--motion-exit: 140ms;
}
```
Use about 200ms for entry and 140ms for exit. Do not use `ease-in` for UI
elements, and do not animate from `scale(0)`; start at `scale(0.9)` or higher
with opacity when scale is appropriate. Continuous data or progress motion may
remain linear. A brand may bind different token values when motion is genuinely
part of its identity, but the behavior must still be accessible and documented.
## 8. Localized catalog copy
English fallback metadata comes from the package. Built-in localized catalog
copy is keyed by design-system id in `apps/web/src/i18n/content.ts` and its
language modules.
There are currently 17 direct non-English content bundles:
`de`, `fr`, `ru`, `zh-CN`, `ja`, `id`, `es-ES`, `pt-BR`, `ar`, `fa`, `ko`,
`pl`, `hu`, `uk`, `tr`, `th`, and `it`.
`zh-TW` intentionally reuses the `zh-CN` built-in-content bundle when a
dedicated entry is unavailable. When adding or renaming bundled catalog copy,
update the same id in all 17 direct `*_DESIGN_SYSTEM_SUMMARIES` maps and keep
category mappings aligned. The runtime still falls back to the package summary
or category, but that fallback is not a substitute for the repository's full
localized-content coverage.
## 9. Review checklist
- [ ] Folder slug and `manifest.id` match and are normalized.
- [ ] `manifest.json`, `DESIGN.md`, and `tokens.css` are present and consistent.
- [ ] Every declared manifest path exists; source and license provenance are clear.
- [ ] `DESIGN.md` has at least seven substantive H2 sections without relying on a fixed numbered template.
- [ ] `tokens.css` satisfies the shared token schema and agrees with the prose.
- [ ] Rich-package usage, component, preview, and source-evidence files are complete.
- [ ] Derived component, Design Tokens, and Tailwind outputs are regenerated rather than hand-edited.
- [ ] Component fixtures use declared semantic tokens and include keyboard, focus, contrast, and reduced-motion behavior.
- [ ] All 17 direct non-English catalog maps are updated for bundled copy changes.
- [ ] `pnpm guard` and `pnpm typecheck` pass.
The executable guard inventory is owned by [`scripts/guard.ts`](../scripts/guard.ts).
Read it and the scripts it invokes instead of relying on a copied list of checks.