DESIGN.md

A format specification for describing a visual identity to coding agents. It gives AI agents a persistent, structured understanding of a design system so stylistic choices stay consistent across design sessions and between different agents/tools. It’s a human-readable, open-format living source of truth that both humans and AI can refine.

Made by Google Labs (used in Stitch). Currently at version alpha — expect the format to change.


The Core Idea

A DESIGN.md file combines two layers:

  1. YAML front matter — machine-readable design tokens (colors, typography, spacing…). These are the normative values.
  2. Markdown body — human-readable design rationale/prose organized into ## sections. This tells the agent why the values exist and how to apply them.

Tokens give agents exact values. Prose tells them why those values exist and how to apply them. The tokens are context/reference — not rendering instructions.

An agent reading the file will produce a UI matching both the exact token values and the described intent.

Minimal example

---
name: Heritage
colors:
  primary: "#1A1C1E"
  secondary: "#6C7278"
  tertiary: "#B8422E"
  neutral: "#F7F5F2"
typography:
  h1: { fontFamily: Public Sans, fontSize: 3rem }
  body-md: { fontFamily: Public Sans, fontSize: 1rem }
rounded: { sm: 4px, md: 8px }
spacing: { sm: 8px, md: 16px }
---
 
## Overview
Architectural Minimalism meets Journalistic Gravitas. The UI evokes a
premium matte finish — a high-end broadsheet or contemporary gallery.
 
## Colors
The palette is rooted in high-contrast neutrals and a single accent color.
- **Primary (#1A1C1E):** Deep ink for headlines and core text.
- **Tertiary (#B8422E):** "Boston Clay" — the sole driver for interaction.

Philosophy — Prose is the Point

The most important idea in DESIGN.md: the quality of a generated design is determined less by the precision of its values than by how clearly the intent is described. The prose is where the design actually lives; everything else supports it.

Key principles:

  • A specific reference beats a list of adjectives. “A 1970s graduate lecture handout in the tradition of an old, established university” evokes a complete world (one ink color, generous margins, serif at reading size, no decoration). “Modern, clean, trustworthy, premium” evokes nothing specific — the model lands in generic center-mass. Adjectives describe a region; a specific reference describes a point.

  • Negative constraints arrive for free. Naming a concrete reference automatically carries its restrictions — a model knows a lecture handout doesn’t glow or use gradients, the same way “dog” tells it dogs don’t meow. A short intentional Do’s/Don’ts list is the sweet spot; a long rambling one is usually a sign the reference was too vague.

  • Tokens are context, not requirements. DESIGN.md generally does not recommend token requirements in the spec. Tokens serve as reference points named in the prose — this avoids reinventing decades of work by existing design languages and tools.

  • The format grows through its users, not its spec. The spec standardizes only the universal minimum (name + colors, typography, spacing, rounded, components). Everything else — motion, iconography, elevation, text casing, paragraph measure — is yours to define. It accepts any key, any section, any structure. The linter accepts custom values and agents just read the prose; no spec change needed because tokens are context, not instruction.


Specification

File structure

  • Front matter block must start and end with a line containing exactly ---.
  • Body uses ## (<h2>) headings for sections. An optional # (<h1>) title is allowed but not parsed as a section.
  • Tokens are inspired by the W3C Design Token Format — convertible to/from tokens.json, Figma variables, Tailwind theme configs.

Token schema

version: <string>          # optional, current: "alpha"
name: <string>
description: <string>      # optional
colors:
  <token-name>: <Color>
typography:
  <token-name>: <Typography>
rounded:
  <scale-level>: <Dimension>
spacing:
  <scale-level>: <Dimension | number>
components:
  <component-name>:
    <token-name>: <string | token reference>

<scale-level> = a named level like xs, sm, md, lg, xl, full (any descriptive string is valid).

Token types

TypeFormatExample
ColorAny valid CSS color: hex (#RGB/#RGBA/#RRGGBB/#RRGGBBAA), named, rgb()/rgba()/hsl()/hwb(), wide-gamut oklch()/oklab()/lch()/lab(), color-mix()"#1A1C1E", "oklch(62% 0.18 250)"
Dimensionnumber + unit (px, em, rem)48px, -0.02em
Token Reference{path.to.token} — must point to a primitive (except in components, where composite refs like {typography.label-md} are allowed){colors.primary}
Typographyobject: fontFamily, fontSize, fontWeight, lineHeight, letterSpacing, fontFeature, fontVariationsee below
  • Colors are internally converted to sRGB for WCAG contrast checks; original format preserved for display/export. Hex is the recommended default.
  • lineHeight accepts a Dimension or a unitless multiplier number (e.g. 1.6) — unitless is recommended CSS practice.
  • fontWeight may be a bare number or quoted string (equivalent).

Section order

Sections can be omitted, but those present must appear in this order:

#SectionAliases
1OverviewBrand & Style
2Colors
3Typography
4LayoutLayout & Spacing
5Elevation & DepthElevation
6Shapes
7Components
8Do’s and Don’ts

What each section is for:

  • Overview — holistic look & feel: brand personality, target audience, emotional response (playful/professional, dense/spacious). High-level fallback context.
  • Colors — at least primary must be defined. Common role order: primary, secondary, tertiary, neutral.
  • Typography — usually 9–15 levels; semantic categories (headline, display, body, label, caption) × sizes (sm/md/lg).
  • Layout — grid/spacing strategy (fluid grid, fixed-max-width, margins/safe areas).
  • Elevation & Depth — how hierarchy is conveyed (shadows vs. tonal layers vs. borders for flat designs).
  • Shapes — corner radius language via rounded tokens.
  • Components — style guidance for atoms (buttons, chips, inputs, tooltips, etc.).
  • Do’s and Don’ts — guardrails and common pitfalls.

Components

Map a component name to sub-token properties. Values may be literals or references.

components:
  button-primary:
    backgroundColor: "{colors.tertiary}"
    textColor: "{colors.on-tertiary}"
    rounded: "{rounded.sm}"
    padding: 12px
  button-primary-hover:
    backgroundColor: "{colors.tertiary-container}"
  • Valid properties: backgroundColor, textColor, typography, rounded, padding, size, height, width.
  • Variants (hover, active, pressed) = separate entries with related key names (button-primary, button-primary-hover, button-primary-active). The agent considers all variants together.
  • The components spec is intentionally flexible and actively evolving.
  • Colors: primary, secondary, tertiary, neutral, surface, on-surface, error
  • Typography: headline-display, headline-lg/md, body-lg/md/sm, label-lg/md/sm
  • Rounded: none, sm, md, lg, xl, full

Consumer behavior for unknown content

ScenarioBehavior
Unknown section heading (## Iconography)Preserve; don’t error
Unknown color token nameAccept if value valid
Unknown typography token nameAccept as valid typography
Unknown spacing valueAccept; store as string if not a valid dimension
Unknown component property (borderColor)Accept with warning
Duplicate section heading (two ## Colors)Error; reject the file

Extending the format (custom sections)

Because tokens are context (not instruction), you can add whole domains the spec doesn’t standardize — the linter accepts them and agents read the prose. E.g. Motion:

## Motion
 
```yaml
motion:
  feedback: 120ms
  content: 250ms
  easing: 'cubic-bezier(0.2, 0, 0, 1)'
```
 
Transitions are quick and mechanical. Nothing bounces or lingers.
- Interactive feedback (hover, press): {motion.feedback}, always {motion.easing}.
- Nothing animates longer than 300ms. Respect `prefers-reduced-motion`.

CLI — @google/design.md

npm install @google/design.md
# or run directly:
npx @google/design.md lint DESIGN.md

All commands accept a file path or - for stdin. Output defaults to JSON.

Windows/PowerShell gotcha: the .md in the bin name collides with the Markdown file association. Use the dot-free alias: npx -p @google/design.md designmd lint DESIGN.md. In package.json scripts also use the designmd alias. ENOVERSIONS usually means npm isn’t hitting the public registry (npm config get registry should be https://registry.npmjs.org/).

lint — validate structure

npx @google/design.md lint DESIGN.md
cat DESIGN.md | npx @google/design.md lint -

Exit code 1 if errors found, else 0. Returns findings + summary as JSON:

{ "findings": [ { "severity": "warning", "path": "components.button-primary",
  "message": "textColor (#ffffff) on backgroundColor (#1A1C1E) has contrast ratio 15.42:1 — passes WCAG AA." } ],
  "summary": { "errors": 0, "warnings": 1, "info": 1 } }

diff — compare two versions

npx @google/design.md diff DESIGN.md DESIGN-v2.md

Reports token-level added/removed/modified + a regression boolean. Exit 1 if regressions detected (more errors/warnings in the “after” file).

export — convert tokens to other formats

npx @google/design.md export --format json-tailwind DESIGN.md > tailwind.theme.json
npx @google/design.md export --format css-tailwind  DESIGN.md > theme.css
npx @google/design.md export --format dtcg          DESIGN.md > tokens.json
FormatOutputDescription
json-tailwind (alias tailwind)JSONTailwind v3 theme.extend config
css-tailwindCSSTailwind v4 @theme { … } block with CSS custom props (--color-*, --font-*, --radius-*, --spacing-*…)
dtcgJSONW3C Design Tokens Format Module

Exit 0 on successful export (regardless of lint findings — run lint to gate), 1 on invalid format/emitter error, 2 if input unreadable.

spec — output the spec (for injecting into agent prompts)

npx @google/design.md spec                       # full spec markdown
npx @google/design.md spec --rules               # + linting rules table
npx @google/design.md spec --rules-only --format json

This is the “get instructions” use case: pipe the spec into an agent’s context so it knows the format before generating/editing a DESIGN.md.

Programmatic API

import { lint } from '@google/design.md/linter';
const report = lint(markdownString);
report.findings;      // Finding[]
report.summary;       // { errors, warnings, info }
report.designSystem;  // parsed DesignSystemState

Linting Rules

The linter runs nine rules against a parsed DESIGN.md, each at a fixed severity:

RuleSeverityChecks
broken-referrorToken refs ({colors.primary}) that don’t resolve to a defined token
missing-primarywarningColors defined but no primary — agents will auto-generate one
contrast-ratiowarningComponent backgroundColor/textColor pairs below WCAG AA (4.5:1)
orphaned-tokenswarningColor tokens defined but never referenced by any component
missing-typographywarningColors defined but no typography — agents fall back to default fonts
section-orderwarningSections out of canonical order
unknown-keywarningTop-level YAML key that looks like a typo of a schema key (colours:colors:); genuine custom extension keys stay silent
token-summaryinfoCount of tokens defined per section
missing-sectionsinfoOptional sections (spacing, rounded) absent when other tokens exist

Interoperability

Tokens are inspired by the W3C Design Token Format and export to: