# Creating a Theme [English](creating-a-theme.md) | [简体中文](creating-a-theme.zh.md) A theme is one frozen `ThemeDefinition` file plus a catalog entry. Follow these steps and the test suite enforces the contract. ## 1. Read the spec [`docs/theme-spec.md`](theme-spec.md) defines the token contract. Every theme must cover the full `REQUIRED_TOKENS` and `RECOMMENDED_TOKENS` sets; `pnpm test` enforces both. ## 2. Add the theme file Create `packages/core/src/themes/.ts` (kebab-case id): ```ts import type { ThemeDefinition } from '../types.ts' /** One-line description: palette family and mood. */ export const : ThemeDefinition = Object.freeze({ id: '', colorScheme: 'dark', // or 'light' — the host base palette tokens: Object.freeze({ '--dsw-alias-bg-base': '#101418', // ... the full REQUIRED_TOKENS and RECOMMENDED_TOKENS sets }), }) ``` Rules: - The id is unique and never `light`, `dark`, or `system`. - `colorScheme` names the host base palette the theme builds on; dark themes pick `'dark'` so their tokens are the dark values. - Token values are CSS color expressions only (hex, `rgb()`/`rgba()`, `hsl()`/`hsla()`, `var()`). - Freeze both the definition and the token dictionary. ## 3. Register the theme Add it to `packages/core/src/themes/index.ts` (named export plus the catalog array). Catalog order is the registration order. ## 4. Add picker copy Add the theme name to both dictionaries in `packages/ui/src/locales.ts` under `theme.` (and the `PickerKey` union). ## 5. Verify ```sh pnpm test # id uniqueness, token coverage, color validity, freeze, contrast bars pnpm typecheck pnpm test:coverage # per-file 100% gate ``` Contrast failures name the token, the surface, and the ratio reached. Prefer a lighter entry from the palette you are reproducing over inventing one; if the palette has none, say so in the theme file's JSDoc. The bars are in [theme-spec.md](theme-spec.md#contrast). ## 6. Preview Generate the theme's preview and commit it with the theme: ```sh pnpm previews ``` The generator paints `previews/.svg` from the token dictionary you just wrote, and `pnpm test` fails while a committed preview is missing or stale. Capture the mounted theme from the live pair below into `screenshots/.png`. Add the row to the theme tables in both READMEs and a section to [docs/previews.md](previews.md) and its Chinese twin — the section carries the projection, the capture, and the theme's two identity colours (`--dsw-alias-bg-base`, `--dsw-alias-brand-primary`); `pnpm test` fails while any of the three is missing. For a live check, run the harness web development pair with the plugin installed (see [docs/installation.md](installation.md)).