Help your AI make better designs for you

What is a DESIGN.md?

It is a design system written for the thing that now builds most first drafts of your UI: a coding agent. Ask one for a settings page with no guidance and it falls back on the average of everything it has ever read — an invented palette, four corner radii, a second font nobody asked for, and contrast nobody checked.

A DESIGN.md replaces that guess with your tokens, contrast ratios we measured rather than claimed, and rules the agent can be held to. One file, committed at your repo root, applied every session.

The specification

Eight fields. Six are required, because an agent that is missing any of them will invent the difference. Every DESIGN.md we publish carries all eight, generated from the palette rather than written by hand.

FieldWhat it holdsWhy it earns its place
Semantic color roles Required Six roles: bg, surface, primary, accent, text, muted. Hex and OKLCH. Roles survive a rebrand; raw hex values do not. An agent told to use var(--primary) writes swappable code.
Full token set Required Every shadcn/ui token, in light and dark, derived from the six roles. Agents generate components, and components reference tokens like card, border and ring that the six roles do not name directly.
Typography Required Heading family and body family. Two, not three. A third family is the most common thing an agent adds unprompted.
Shape and rhythm Required One radius token and an explicit spacing scale. Mixed radii and arbitrary pixel values are the clearest visual tell of generated UI.
Measured contrast Required Real WCAG ratios for the pairs the agent will actually produce, with a pass or fail verdict. A number an agent can check beats an adjective it has to interpret. If a pair fails AA, the file must say so.
Rules Required Numbered constraints, each checkable against the tables above it. This is the half that makes it a contract instead of a description. Use only these tokens is verifiable; keep it clean is not.
CSS variables Recommended A paste-ready :root and .dark block, plus the Tailwind v4 theme mapping. Closes the loop: the agent writes the components, this writes the tokens.
Source link Recommended Where the system came from, and how to install it for real. Provenance. A design system with no traceable source is a guess with good formatting.

A worked example

Raw file →

This is Deep Ocean, generated at build time. Not an illustration of the format: the actual file an agent fetches.

# DESIGN.md — Deep Ocean

> Design context for AI coding agents. Paste this file into Cursor, Claude Code, Codex, v0 or Lovable
> before asking for UI, or commit it at your repo root as `DESIGN.md`.

- **Source:** [Deep Ocean on CSS Crème](https://csscreme.com/themes/deep-ocean)
- **Default mode:** dark
- **Tags:** dark, blue, calm
- **Install as a real shadcn/ui theme:** `npx shadcn@latest add https://csscreme.com/r/deep-ocean.json`

A restrained, professional blue palette — trustworthy without the corporate stiffness.

---

## Semantic color roles

Six roles carry the identity. Everything else in this file is derived from them.

| Role | Hex | OKLCH | Use it for |
| --- | --- | --- | --- |
| `bg` | `#071A2B` | `oklch(21.2% 0.042 247.8)` | page background |
| `surface` | `#0F2A40` | `oklch(27.6% 0.052 245.9)` | cards, panels, popovers |
| `primary` | `#36B7C2` | `oklch(71.6% 0.109 203.5)` | brand actions: primary buttons, links, focus rings |
| `accent` | `#5BA7F7` | `oklch(71.4% 0.140 251.4)` | secondary emphasis only, never a second primary |
| `text` | `#E4F1F6` | `oklch(95.0% 0.015 222.7)` | body and heading text |
| `muted` | `#7E9AAC` | `oklch(67.1% 0.041 236.4)` | secondary text, borders, disabled states |

## Full token set (shadcn/ui, both modes)

Colors are OKLCH (Tailwind v4 / shadcn native). Brand colors are identical in both modes by design:
only the neutrals move, and they keep their hue, so light and dark read as the same design system.

| Token | Light | Dark |
| --- | --- | --- |
| `--background` | `oklch(98.8% 0.002 247.8)` | `oklch(21.2% 0.042 247.8)` |
| `--foreground` | `oklch(26.9% 0.014 220.1)` | `oklch(95.0% 0.015 222.7)` |
| `--card` | `oklch(97.2% 0.003 247.9)` | `oklch(27.6% 0.052 245.9)` |
| `--card-foreground` | `oklch(26.9% 0.014 220.1)` | `oklch(95.0% 0.015 222.7)` |
| `--popover` | `oklch(97.2% 0.003 247.9)` | `oklch(27.6% 0.052 245.9)` |
| `--popover-foreground` | `oklch(26.9% 0.014 220.1)` | `oklch(95.0% 0.015 222.7)` |
| `--primary` | `oklch(71.6% 0.109 203.5)` | `oklch(71.6% 0.109 203.5)` |
| `--primary-foreground` | `oklch(15.2% 0.009 285.3)` | `oklch(15.2% 0.009 285.3)` |
| `--secondary` | `oklch(97.8% 0.003 228.8)` | `oklch(25.3% 0.050 247.7)` |
| `--secondary-foreground` | `oklch(26.9% 0.014 220.1)` | `oklch(95.0% 0.015 222.7)` |
| `--muted` | `oklch(97.8% 0.003 228.8)` | `oklch(25.3% 0.050 247.7)` |
| `--muted-foreground` | `oklch(54.0% 0.014 240.1)` | `oklch(67.1% 0.041 236.4)` |
| `--accent` | `oklch(71.4% 0.140 251.4)` | `oklch(71.4% 0.140 251.4)` |
| `--accent-foreground` | `oklch(15.2% 0.009 285.3)` | `oklch(15.2% 0.009 285.3)` |
| `--destructive` | `oklch(62.6% 0.193 23.0)` | `oklch(62.6% 0.193 23.0)` |
| `--destructive-foreground` | `oklch(15.2% 0.009 285.3)` | `oklch(15.2% 0.009 285.3)` |
| `--border` | `oklch(83.8% 0.005 247.9)` | `oklch(35.3% 0.041 242.5)` |
| `--input` | `oklch(83.8% 0.005 247.9)` | `oklch(35.3% 0.041 242.5)` |
| `--ring` | `oklch(71.6% 0.109 203.5)` | `oklch(71.6% 0.109 203.5)` |

## Typography

- **Headings:** Sora
- **Body:** Inter

## Shape and rhythm

- **Radius:** `10px` (the `--radius` token; derive smaller/larger from it, do not invent new values)
- **Spacing scale:** 4px base · 4 / 8 / 12 / 16 / 24 / 32

## Contrast, measured

Computed from the tokens above in dark mode, not asserted. Ratios are WCAG 2.1 relative luminance.

| Pair | Foreground | Background | Ratio | Verdict |
| --- | --- | --- | --- | --- |
| Body text on page background | `#E4F1F6` | `#071A2B` | 15.28:1 | AAA |
| Body text on card | `#E4F1F6` | `#0F2A40` | 12.78:1 | AAA |
| Muted text on page background | `#7E9AAC` | `#071A2B` | 5.96:1 | AA |
| Button label on primary | `#0b0b0f` | `#36B7C2` | 8.15:1 | AAA |
| Button label on accent | `#0b0b0f` | `#5BA7F7` | 7.78:1 | AAA |

## Rules for the agent

These are constraints, not suggestions. Each one is checkable against the tables above.

1. **Use only the tokens listed here.** Do not introduce a hex value that is not in the token table. If
   you need an in-between shade, mix two existing tokens rather than inventing a new hue.
2. **`#36B7C2` (primary) is the only call-to-action color.** One primary action per view. `accent`
   is for secondary emphasis and must never be styled as a second primary button.
3. **Never restyle brand colors between light and dark.** Only neutrals change mode. A theme whose
   primary shifts between modes is a different theme.
4. **Respect the radius token.** Every corner derives from `10px`. Mixed radii across a view is
   the most common tell of generated UI.
5. **Stay on the spacing scale.** 4px base · 4 / 8 / 12 / 16 / 24 / 32. No arbitrary pixel values.
6. **Do not drop below the contrast ratios above.** If a combination you need is not in the contrast
   table, compute it before shipping it. Text under 4.5:1 fails AA.
7. **Headings in Sora, body in Inter.** Do not add a third family.
8. **Use the semantic role, not the raw color.** Write `var(--primary)`, never `#36B7C2`, so the
   theme stays swappable.

## CSS variables

Paste into `globals.css`:

```css
:root {
  --background: oklch(98.8% 0.002 247.8);
  --foreground: oklch(26.9% 0.014 220.1);
  --card: oklch(97.2% 0.003 247.9);
  --card-foreground: oklch(26.9% 0.014 220.1);
  --popover: oklch(97.2% 0.003 247.9);
  --popover-foreground: oklch(26.9% 0.014 220.1);
  --primary: oklch(71.6% 0.109 203.5);
  --primary-foreground: oklch(15.2% 0.009 285.3);
  --secondary: oklch(97.8% 0.003 228.8);
  --secondary-foreground: oklch(26.9% 0.014 220.1);
  --muted: oklch(97.8% 0.003 228.8);
  --muted-foreground: oklch(54.0% 0.014 240.1);
  --accent: oklch(71.4% 0.140 251.4);
  --accent-foreground: oklch(15.2% 0.009 285.3);
  --destructive: oklch(62.6% 0.193 23.0);
  --destructive-foreground: oklch(15.2% 0.009 285.3);
  --border: oklch(83.8% 0.005 247.9);
  --input: oklch(83.8% 0.005 247.9);
  --ring: oklch(71.6% 0.109 203.5);
  --radius: 10px;
}

.dark {
  --background: oklch(21.2% 0.042 247.8);
  --foreground: oklch(95.0% 0.015 222.7);
  --card: oklch(27.6% 0.052 245.9);
  --card-foreground: oklch(95.0% 0.015 222.7);
  --popover: oklch(27.6% 0.052 245.9);
  --popover-foreground: oklch(95.0% 0.015 222.7);
  --primary: oklch(71.6% 0.109 203.5);
  --primary-foreground: oklch(15.2% 0.009 285.3);
  --secondary: oklch(25.3% 0.050 247.7);
  --secondary-foreground: oklch(95.0% 0.015 222.7);
  --muted: oklch(25.3% 0.050 247.7);
  --muted-foreground: oklch(67.1% 0.041 236.4);
  --accent: oklch(71.4% 0.140 251.4);
  --accent-foreground: oklch(15.2% 0.009 285.3);
  --destructive: oklch(62.6% 0.193 23.0);
  --destructive-foreground: oklch(15.2% 0.009 285.3);
  --border: oklch(35.3% 0.041 242.5);
  --input: oklch(35.3% 0.041 242.5);
  --ring: oklch(71.6% 0.109 203.5);
}
```

Tailwind v4 maps them into utilities:

```css
@theme inline {
  --color-background: var(--background);
  --color-foreground: var(--foreground);
  --color-card: var(--card);
  --color-card-foreground: var(--card-foreground);
  --color-popover: var(--popover);
  --color-popover-foreground: var(--popover-foreground);
  --color-primary: var(--primary);
  --color-primary-foreground: var(--primary-foreground);
  --color-secondary: var(--secondary);
  --color-secondary-foreground: var(--secondary-foreground);
  --color-muted: var(--muted);
  --color-muted-foreground: var(--muted-foreground);
  --color-accent: var(--accent);
  --color-accent-foreground: var(--accent-foreground);
  --color-destructive: var(--destructive);
  --color-destructive-foreground: var(--destructive-foreground);
  --color-border: var(--border);
  --color-input: var(--input);
  --color-ring: var(--ring);
  --radius: var(--radius);
}
```

---

Generated by [CSS Crème](https://csscreme.com) — curated web design, decoded so you can build it.
Every value above is computed from the palette, not written by hand.

Getting one

Use a curated theme

52 of them, each with a matching DESIGN.md at /d/<slug>.md. Browse the themes, pick one, copy the file.

Extract from a real site

Point the extractor at any URL or drop a screenshot. It samples the pixels, maps them to semantic roles, checks contrast, and hands back a DESIGN.md for that site.

Build your own

Open the workbench, set your six roles, radius and font, then switch the export tab to DESIGN.md. The contrast table recomputes as you edit.

Wiring it into your tool

Each page states where that tool expects the file and how it picks it up, because the convention differs: a root file, a rules directory, or pasted context.

Or skip the copy-paste: the MCP server

Connect your agent straight to the catalogue. It can search the design systems, pull a DESIGN.md and fetch the tokens without you fetching anything by hand. Free, no account, no API key — the competing server requires a paid plan.

claude mcp add --transport http csscreme https://csscreme.com/mcp

Works with any client that speaks remote MCP: Claude Code, Cursor, Windsurf, Codex and others. Five tools: search_themes, list_themes, get_design_md, get_theme_tokens, how_to_use.

What this format does not do

It does not make an agent a designer. It removes one specific failure: the agent inventing a visual system because nobody gave it one. Layout, hierarchy and whether the screen is any good remain yours.

It also is not a standard. Nobody owns this file name, us included. If a better spec appears, the useful part of ours is the generator, not the noun. That is why every field above says what it is for, so the format can be argued with rather than adopted on faith.