Scholar HeistScholar Heist
← All skills
Productionv1.0.0 · 2026-08-07

Design System Spec

A brand has colours and a logo. A design system tells you what size the body text is, which colour pairs are legal to put together, and how far apart two things sit. Without it, every page is decided from scratch and no two look related.

Download skill

What it does

  • Set the type scale
  • Check the palette before committing to it
  • Set the spacing scale
  • Set the breakpoints
  • Specify the components
  • Write it down
SKILL.md
---
name: design-system-spec
description: Turn a brand into a usable website design system — type scale, colour palette with checked contrast, spacing scale, breakpoints and component specs. Use when asked to design a website, create a design system or style guide, pick fonts and colours for a site, check colour contrast or accessibility of a palette, set typography or spacing standards, set up brand guidelines for web, hand a developer a visual spec, or someone says 'every page we make looks different'. For the copy that fills the system, see landing-page-copy. For auditing a built page against it, see design-review.
metadata:
  version: 1.0.0
---

# Design system spec

A brand has colours and a logo. A **design system** tells you what size the body text
is, which colour pairs are legal to put together, and how far apart two things sit.
Without it, every page is decided from scratch and no two look related.

This produces a written spec a developer or designer builds from. It does not produce
a website.

The whole job in one line: **decide once, apply everywhere.**

## Before you start

| Input | Why |
| --- | --- |
| Brand colours as hex codes | Step 2 checks which pairs are legible. Names like "our blue" cannot be checked |
| Brand fonts, or a decision to pick some | Step 1 needs a body font before it can set a scale |
| The logo file and where it sits | Header spec |
| What the site is for — content-heavy, marketing, dashboard | Drives the type ratio in step 1 |

If you have brand colours but not as hex, get the hex first. Everything in step 2 is
arithmetic on those values.

## Step 1 — Set the type scale

```bash
python3 scripts/type_scale.py --base 16 --ratio major-third
python3 scripts/type_scale.py --ratio 1.333 --css     # emit CSS variables
```

A modular scale multiplies each step by a fixed ratio, so sizes relate to one another
instead of being picked one at a time. That relationship is most of what makes a page
look designed.

| Site type | Ratio | Why |
| --- | --- | --- |
| Dashboard, dense UI | 1.125–1.2 | Many levels, little room |
| Content-heavy, blog | 1.2–1.25 | Comfortable hierarchy that survives long pages |
| Marketing, landing pages | 1.333–1.5 | Fewer levels, bigger statements |

**Body copy is 16px minimum.** Below that, iOS Safari zooms the page when someone
focuses an input, and long-form reading gets tiring. The script warns you.

Line length matters as much as size: **45–75 characters** per line, around 66 ideal.
Set a `max-width` on text containers, not just a font size.

## Step 2 — Check the palette before committing to it

```bash
python3 scripts/contrast.py "#E1306C" "#ffffff"
python3 scripts/contrast.py --palette brand.txt --min 4.5
```

Do not eyeball this. Contrast is a defined ratio and the script computes exactly what
an auditor's tool will report.

| Requirement | Ratio | WCAG |
| --- | --- | --- |
| Body text | **4.5:1** | SC 1.4.3, Level AA |
| Large text — 24px+, or 18.5px+ bold | **3:1** | SC 1.4.3, Level AA |
| Icons, borders, form outlines, focus rings | **3:1** | SC 1.4.11, Level AA |
| Body text, enhanced | 7:1 | SC 1.4.6, Level AAA |

Expect some brand colours to fail. That is normal and it is not a reason to ignore
the number — it is a reason to define a **text-safe variant**. A worked example using
a real brand palette is in
[references/palette-worked-example.md](references/palette-worked-example.md).

Record for every colour: its hex, what it may be used for, and its checked ratio
against your background.

## Step 3 — Set the spacing scale

An **8px base grid**: 8, 16, 24, 32, 40, 48, 56, 64. Use 4px only for fine
adjustments inside components.

Every margin and padding in the spec comes from this list. "Whatever looks right"
is what produces pages where nothing lines up.

## Step 4 — Set the breakpoints

Three is usually enough:

| Name | Width | Represents |
| --- | --- | --- |
| Mobile | base, no media query | Design here first |
| Tablet | 768px | Two columns become possible |
| Desktop | 1024px | Full layout |
| Wide (optional) | 1280px | Cap the content width, do not keep stretching |

**Design mobile first.** It is far easier to add space than to remove it, and most
traffic to a marketing site is mobile.

Breakpoints should follow your content, not device names. If your layout breaks at
900px, put a breakpoint at 900px.

## Step 5 — Specify the components

For each one, state the resting look, the states, and the size. Minimum set: button
(primary, secondary), link, form input, card, header, footer.

**Every interactive element needs four states**: rest, hover, focus, disabled. The
one people skip is **focus** — that is how keyboard users see where they are, and its
outline needs 3:1 contrast against the background.

**Touch targets: 24×24 CSS px minimum** (WCAG 2.2 SC 2.5.8, Level AA). Aim for
**44×44** on anything important (SC 2.5.5, Level AAA) — it is the difference between
a button people hit and one they miss.

## Step 6 — Write it down

Produce the spec as a single document. A design system that lives in someone's head
is not a design system.

## Output

```
# Design system: <brand>

## Type
Font:        <body font> / <heading font>
Base:        16px    Ratio: 1.25 (major third)
| Step | px | rem | line-height | Use for |
Max line length: <n>ch

## Colour
| Name | Hex | Ratio on <bg> | Usable for |
Text-safe variants: <where a brand colour failed and what replaces it>

## Spacing
8px grid: 8 / 16 / 24 / 32 / 40 / 48 / 56 / 64

## Breakpoints
mobile (base) / tablet 768px / desktop 1024px

## Components
### Button (primary)
Rest / Hover / Focus / Disabled — with hex, size, radius, padding
Min target: 44x44

## Known limits
<Any brand colour that cannot be used for text, and what to use instead.>
```

## When it breaks

| What you see | What it means | The fix |
| --- | --- | --- |
| A brand colour fails 4.5:1 | The brand was designed for print or logos, not body text | Define a darker text-safe variant. Keep the original for large text and graphics |
| Every pair in the palette fails | The palette is all mid-tones with no light/dark anchors | Add a near-black and a near-white. Most palettes need both |
| Body text set below 16px | Density was chosen over readability | Raise to 16px. iOS zooms on input focus below it |
| Headings look almost the same size | The ratio is too small for the number of levels | Raise the ratio, or cut a heading level |
| Top heading is enormous next to body | Ratio too large across too many steps | Lower the ratio, or drop the top step |
| Layout looks cramped or arbitrary | Spacing picked per element instead of from the scale | Every value comes from the 8px grid |
| Keyboard users get lost | Focus states were never specified | Add a visible focus ring at 3:1 contrast to every interactive element |
| Buttons hard to tap on mobile | Targets under 24×24 CSS px | 24×24 is the AA floor; use 44×44 for anything important |
| Developer keeps asking "what about…" | The spec covers only the happy path | Specify all four states for every component |

If brand colours are not available as hex, stop and get them. Guessing a hex from a
screenshot produces a spec that does not match the brand.

## Rules

- **Check contrast, never estimate it.** It is a computed ratio; a guess that looks
  fine to you can fail for someone with low vision.
- **A failing brand colour gets a text-safe variant, not an exception.** "It's our
  brand colour" does not make 3:1 text readable.
- **16px body minimum.** No exceptions for "design reasons".
- **Every interactive element specifies all four states.** Skipping focus locks out
  keyboard users entirely.
- **Design mobile first.** Adding space is easy; removing it is a rebuild.
- **Every spacing value comes from the scale.** One arbitrary value invites fifty.
- This skill produces a **written spec**, not a built site. It does not cover
  animation, illustration style, or print. Its standards are external — see
  `SOURCES.md`.

## Related skills

- **design-review** — audits built pages against this spec's standards.
- **landing-page-copy** — the words this system sets; copy and system ship together.
- **static-ad-builder** — ad-format assembly under the same brand-lock idea.
- **ai-image-generation-rules** — generated imagery obeys this system's lock too.

Reviews

Sign in to leave a review.