--- name: shadcn-theme description: "Create or update a defuss-shadcn theme from instructions - text, colours, a brand or design guide, screenshots or photos when the harness reads images: every theme token in light and dark, checked by a bundled checker for unknown tokens, missing colours, radius and WCAG contrast. Use when asked for a theme, a palette, a brand look or a dark mode for defuss-shadcn." --- # defuss-shadcn / shadcn-theme Scope: one theme file for defuss-shadcn 0.9.8 - the agentic twin of the docs' Theme Designer, which imports the same file. Components never change for a theme: a theme is a value for each token, nothing else. ## Where things are Paths are relative to this file. - `references/tokens.md` - every token a theme sets, its role, its defaults, and the contrast pairs the checker measures. - `scripts/theme-check.mjs` - the checker (Node 18 or later, or Bun; no dependencies). - `assets/theme-preview.html` - a page of components in light and dark that loads `./theme.css`. ## Workflow 1. **Read the inputs** the harness gives you: - **text** - mood words set the hue family, the chroma (muted or vivid), the contrast, the shape (`--radius`), the elevation (shadows) and the type (font families); - **colours** - take them literally and convert them to `oklch()`; - **images** (only if the harness can read them) - sample the main surface, the text colour, the brand colour and one or two secondary hues; note the corner roundness and the shadow depth. If the harness cannot read the image, ask for the colours instead of guessing them; - **a design guide** - map its named roles onto the token roles in `references/tokens.md`; - **an existing theme** (update) - read the file and change only what the request names; leave every other declaration as it is. 2. **Map to roles.** Background and foreground first; card and popover usually sit next to the background; primary is the brand; secondary, muted and accent are quiet fills; destructive stays in the red family unless the brand forbids it; border, input and ring; `chart-1` to `chart-5` are five hues a reader tells apart, the primary among them; the sidebar set is a sibling palette. Dark mode is the same identity: the same hues at inverted lightness, not another brand. 3. **Write `.css`** with colours as `oklch(L C H)`, in this order and nothing else: - font `@import`s (Google Fonts) for any family the stacks name; - `:root { ... }` - every token in `references/tokens.md` (light); - `.dark { ... }` - every colour token (dark) and the same `--radius`. Font values are stacks with a generic fallback (`"Inter", ui-sans-serif, system-ui, sans-serif`). Never set `--radius-sm`, `--radius-md`, `--radius-lg` or `--radius-xl`: they are derived from `--radius`. 4. **Check.** Run `node /scripts/theme-check.mjs .css`. Fix every error. Fix every warning unless the request asks for exactly that look, and then report it. Each contrast finding comes with a fix line - the nearest lightness that passes, chroma and hue kept. Repeat until the last line reads `VERIFIED[theme-check]=true`. 5. **Look**, when the harness can render or take screenshots: copy `assets/theme-preview.html` next to the theme as `index.html`, rename the theme to `theme.css` (or edit the link), serve the folder over HTTP (`npx serve .`) and view it in light and dark (the button in its header). Compare it with the input, adjust, check again. Otherwise report `UNKNOWN[theme.visual]`. 6. **Apply.** Load the file after `core.css` (CDN or npm) and put `class="dark"` on `` for dark mode. To fine-tune by eye, import the file in the Theme Designer (docs: Guides, Theming, Theme Designer, Import). In the defuss-shadcn repository itself a preset is an entry in `src/documentation/runtime/themes.ts` with both modes and the same radius; `bun run build` writes `dist/theme/.css`, and verify checks radius and sidebar contrast. ## Output contract ```text THEME: (from: ) PALETTE: --background / --foreground ; --primary ; ... (one line per role group that changed) VERIFIED[theme-check]=true BC errors=0 warnings= (each warning kept, and why) VERIFIED|UNKNOWN[theme.visual] BC ```