There are two ways to give an AI coding agent design context. The first is a screenshot. The second is structured text. If you've tried both, you already know which one produces better output. This post explains the DESIGN.md format — what it is, how each section is structured, and why the token notation makes agents more accurate than screenshots ever can.
What is DESIGN.md?
DESIGN.md is a structured markdown file that describes a website's visual design system in terms an AI coding agent can use directly. It's not a style guide written for human designers. It's not an export of a Figma file. It's a machine-readable spec that contains the exact information a code-generating agent needs to produce on-spec UI: token names and values, typographic scale, layout rules, component behaviors, and explicit constraints on what not to do.
The format was influenced by Impeccable, a tool that pioneered the idea of distilling a design system into a portable, agent-readable document. Design Catcher automates this process — instead of writing DESIGN.md by hand, you capture it from any live website in one click.
Section by section
Overview
The first section is a short prose description of the design aesthetic. It sets the tone that governs all the detailed rules that follow. A typical overview for a productivity tool might read:
Dense, functional aesthetic with deliberate use of whitespace. High information density on dashboard views. Neutral grays dominate the palette; accent color is reserved for primary actions and active states only. Typography is tight and technical — no decorative elements.
This matters because agents use it as a prior when making decisions the rest of the file doesn't explicitly cover. If the agent needs to choose between two typographic treatments and one "feels decorative," the Overview tells it to pick the non-decorative one.
Colors
The color section defines every meaningful color in the system using a dot-notation token structure:
## Colors
### Background
- colors.bg.primary: #0F0F10
- colors.bg.surface: #1A1A1D
- colors.bg.elevated: #222226
- colors.bg.overlay: rgba(0, 0, 0, 0.6)
### Text
- colors.text.primary: #E8E8E8
- colors.text.secondary: #8C8C8C
- colors.text.disabled: #444447
### Accent
- colors.accent.default: #5E6AD2
- colors.accent.hover: #6B76E5
- colors.accent.subtle: rgba(94, 106, 210, 0.15)
### Border
- colors.border.default: rgba(255, 255, 255, 0.08)
- colors.border.strong: rgba(255, 255, 255, 0.16)
Notice that these aren't just color values — they're semantic names. colors.bg.elevated is not just
#222226. It's the surface that appears on top of colors.bg.surface. The agent understands
the elevation relationship.
Typography
Typography defines the font families, weights, and a named typographic scale:
## Typography
### Font Families
- fonts.sans: "Inter", -apple-system, BlinkMacSystemFont, sans-serif
- fonts.mono: "JetBrains Mono", "Fira Code", monospace
### Scale
- text.xs: 11px / 1.4 / weight 400
- text.sm: 12px / 1.5 / weight 400
- text.base: 13px / 1.6 / weight 400
- text.md: 14px / 1.6 / weight 400
- text.lg: 16px / 1.5 / weight 500
- text.xl: 20px / 1.3 / weight 600
- text.display: 28px / 1.2 / weight 700
### Weights
- weight.regular: 400
- weight.medium: 500
- weight.semibold: 600
- weight.bold: 700
The scale notation — size / line-height / weight — gives the agent three values in a single line.
It can generate a CSS class from this directly without interpreting prose.
Layout & Spacing
This section defines the spacing system, grid, and structural constants:
## Layout
### Spacing
- space-1: 4px
- space-2: 8px
- space-3: 12px
- space-4: 16px
- space-6: 24px
- space-8: 32px
- space-12: 48px
- space-16: 64px
### Grid
- layout.maxWidth: 1280px
- layout.gutter: space-6
- layout.columns: 12
- layout.sidebarWidth: 240px
- layout.contentMaxWidth: 720px
### Border Radius
- radius.sm: 4px
- radius.md: 6px
- radius.lg: 10px
- radius.pill: 9999px Components
The components section describes recurrent UI patterns using token references rather than raw values:
## Components
### Button (Primary)
- background: {colors.accent.default}
- background-hover: {colors.accent.hover}
- color: {colors.text.primary}
- padding: {space-2} {space-4}
- border-radius: {radius.md}
- font: {text.sm} / {weight.medium}
- border: none
### Button (Ghost)
- background: transparent
- background-hover: {colors.bg.elevated}
- color: {colors.text.secondary}
- border: 1px solid {colors.border.default}
- padding: {space-2} {space-4}
- border-radius: {radius.md}
This is where the curly-brace token notation — {colors.accent.default} — becomes load-bearing.
The component spec doesn't contain a single hardcoded hex value. It's built entirely from the tokens defined
in the Colors and Layout sections. This means if you tell an agent to "implement the primary button," it
resolves the token chain automatically.
Do's and Don'ts
One of the most practically useful sections. This explicitly encodes the constraints that are invisible in screenshots:
## Do's and Don'ts
### Do
- Use {colors.accent.default} only for primary interactive elements
- Maintain a minimum touch target of 32px × 32px for interactive elements
- Use {colors.bg.elevated} for dropdowns and popovers, never {colors.bg.primary}
- Use {text.sm} as the default body size in dense UI contexts
- Apply {radius.md} to all card and panel surfaces
### Don't
- Don't use color for decorative purposes — use it to signal state
- Don't mix {fonts.sans} and {fonts.mono} in the same UI element
- Don't add drop shadows — use background elevation instead
- Don't use font weights above {weight.semibold} in body text
- Don't add horizontal rules between list items These constraints are what prevent the agent from making technically correct but aesthetically wrong decisions. "Use background elevation instead of drop shadows" is the kind of rule that distinguishes a system like Linear's from an output that merely approximates it.
Responsive Behavior
The final section describes breakpoints and what changes at each:
## Responsive Behavior
### Breakpoints
- bp.sm: 640px
- bp.md: 768px
- bp.lg: 1024px
- bp.xl: 1280px
### Mobile Adaptations (below bp.md)
- Sidebar collapses to bottom navigation
- {layout.gutter} reduces to {space-4}
- {text.display} scales to {text.xl}
- Card grids stack to single column
- Primary navigation becomes a hamburger menu Why curly-brace tokens work better than hex values
The difference between #5E6AD2 and {colors.accent.default} isn't cosmetic. Here's
a concrete before/after example.
Before: hardcoded colors in agent prompt
"The primary button background is #5E6AD2, hover state is #6B76E5.
The ghost button border is rgba(255,255,255,0.08), hover background
is #222226."
The agent generates buttons that use these values correctly. But when it generates a card component five prompts
later, it invents #222222 for the card background — a value that's close to #222226
but not the same. It has no way to know that #222226 is the canonical elevated surface. The
relationship was never stated.
After: token references
"The primary button background is {colors.accent.default}. The ghost
button border is {colors.border.default}, hover background is
{colors.bg.elevated}."
Now the agent knows that colors.bg.elevated is a system token. When it generates the card component,
it uses colors.bg.elevated because it remembers the token — not because it remembers the hex value.
The card background is #222226 by resolution, not by guess. Consistency compounds across every
component the agent generates.
This is the fundamental advantage of DESIGN.md over screenshots. A screenshot of a button tells the agent what a button looks like. DESIGN.md tells the agent the rules that generate every button, card, dropdown, and modal — all derived from the same token set.
How agents use DESIGN.md differently from screenshots
When you give an agent a screenshot, it has to perform visual inference. It estimates that a color is "dark gray, probably around #333." It guesses that spacing is "about 16px." These are approximations compounded through every component it generates.
When you give an agent DESIGN.md, it performs token resolution. It knows colors.text.secondary is
exactly #8C8C8C. It knows a card uses colors.bg.surface as background and
colors.border.default as border. The output is deterministic in a way that visual inference
fundamentally cannot be.
Screenshots have a different failure mode too: they don't capture hover states, focus rings, disabled states, or dark mode. DESIGN.md captures all of these because it reads computed CSS — including the full cascade of pseudo-class rules.
The other difference is composability. DESIGN.md is a text file. You can concatenate multiple captures, diff them, store them in git, and reference them in your project's AI instructions. A screenshot is a static artifact. DESIGN.md is living project context.
Generating DESIGN.md automatically
Writing DESIGN.md by hand for a complex site takes 2–4 hours and requires careful audit of computed styles in DevTools. Design Catcher generates it in under 30 seconds by:
- Extracting all computed CSS properties from every visible element
- Extracting all CSS custom properties (
--var-name) from the stylesheet cascade - Sampling the DOM structure to understand section hierarchy
- Running the extracted data through Gemini 2.5 Flash with a synthesis prompt that produces the DESIGN.md format
The output is not always perfect. Heavily JavaScript-rendered apps can have gaps if critical styles are applied after the extension's capture window. In practice, captures of well-built sites are reliable enough to use directly. For internal tools, BYOK mode lets you run synthesis with your own Gemini key and review the output before committing it to your project.
The three-file bundle — DESIGN.md for tokens and rules, STRUCTURE.md for layout architecture, UI-KIT.md for component recipes — covers the full spectrum of information a coding agent needs to produce matching UI. None of the files require a Figma subscription, a design team handoff, or an API key to generate.