Brand Kit Generator
Ten steps built so the gaps look even to a human eye, each one telling you whether black or white text passes on it. Plus a type scale from a single base size. Copy the CSS and go.
A hex code. Everything below is built from this one value.
Ten steps built by walking perceptual lightness, so the gaps look even rather than measuring even. Each row says which text colour is legible on it — measured, not guessed.
50#ddffea
Black 19.57 · White 1.07
black text passes AA here
100#bbfdd7
Black 18.14 · White 1.16
black text passes AA here
200#a7e9c4
Black 15.10 · White 1.39
black text passes AA here
300#8ecfaa
Black 11.66 · White 1.80
black text passes AA here
400#72b28f
Black 8.48 · White 2.48
black text passes AA here
500#569674
Black 6.01 · White 3.49
black text passes AA here
600#3e7e5d
Black 4.35 · White 4.83
white text passes AA here
700#226344
Black 2.94 · White 7.15
white text passes AA here
800#004a2d
Black 2.02 · White 10.41
white text passes AA here
900#002c19
Black 1.37 · White 15.28
white text passes AA here
Ratios are WCAG 2.1 contrast, computed on the hex above. AA wants 4.5 for body text and 3 for large text — 24px and up, or 19px and up if it's bold. A step with neither black nor white passing is a background for shapes, not for words.
Greys carrying a trace of your hue. Pure greys next to a saturated brand colour read as dirty — a shared hue is what makes a palette look like one family rather than two projects.
The question a palette never answers: put THIS text on THAT background — does it pass? Every cell is measured. AA needs 4.5 for body text.
| Text on → | 50 | 100 | Brand 50 | Brand 500 | Brand 900 | 900 |
|---|---|---|---|---|---|---|
| Neutral 900 | Aa14.26pass | Aa13.05pass | Aa14.40pass | Aa4.42fail | Aa1.01fail | Aa1.00fail |
| Neutral 600 | Aa4.64pass | Aa4.24fail | Aa4.68pass | Aa1.44fail | Aa3.04fail | Aa3.08fail |
| Brand 700 | Aa6.60pass | Aa6.04pass | Aa6.66pass | Aa2.05fail | Aa2.14fail | Aa2.16fail |
| Neutral 50 | Aa1.00fail | Aa1.09fail | Aa1.01fail | Aa3.22fail | Aa14.10pass | Aa14.26pass |
Paste this straight into your stylesheet. Nothing here needs a build step or a library.
CSS custom properties
:root {
--brand-50: #ddffea;
--brand-100: #bbfdd7;
--brand-200: #a7e9c4;
--brand-300: #8ecfaa;
--brand-400: #72b28f;
--brand-500: #569674;
--brand-600: #3e7e5d;
--brand-700: #226344;
--brand-800: #004a2d;
--brand-900: #002c19;
--neutral-50: #eff8f2;
--neutral-100: #e5eee8;
--neutral-200: #d1dad5;
--neutral-300: #b8c0bb;
--neutral-400: #9ca49f;
--neutral-500: #808883;
--neutral-600: #69716c;
--neutral-700: #505753;
--neutral-800: #383f3b;
--neutral-900: #1f2622;
--text-small-print: 0.875rem;
--leading-small-print: 1.5;
--text-body: 1.125rem;
--leading-body: 1.6;
--text-lead-paragraph: 1.438rem;
--leading-lead-paragraph: 1.5;
--text-heading-3: 1.75rem;
--leading-heading-3: 1.35;
--text-heading-2: 2.188rem;
--leading-heading-2: 1.25;
--text-heading-1: 2.75rem;
--leading-heading-1: 1.15;
--text-display: 3.438rem;
--leading-display: 1.05;
}Tailwind v4 theme
@theme {
--color-brand-50: #ddffea;
--color-brand-100: #bbfdd7;
--color-brand-200: #a7e9c4;
--color-brand-300: #8ecfaa;
--color-brand-400: #72b28f;
--color-brand-500: #569674;
--color-brand-600: #3e7e5d;
--color-brand-700: #226344;
--color-brand-800: #004a2d;
--color-brand-900: #002c19;
--color-neutral-50: #eff8f2;
--color-neutral-100: #e5eee8;
--color-neutral-200: #d1dad5;
--color-neutral-300: #b8c0bb;
--color-neutral-400: #9ca49f;
--color-neutral-500: #808883;
--color-neutral-600: #69716c;
--color-neutral-700: #505753;
--color-neutral-800: #383f3b;
--color-neutral-900: #1f2622;
}JSON (design tokens)
{
"color": {
"brand": {
"50": {
"value": "#ddffea",
"onWhite": 1.07,
"onBlack": 19.57
},
"100": {
"value": "#bbfdd7",
"onWhite": 1.16,
"onBlack": 18.14
},
"200": {
"value": "#a7e9c4",
"onWhite": 1.39,
"onBlack": 15.1
},
"300": {
"value": "#8ecfaa",
"onWhite": 1.8,
"onBlack": 11.66
},
"400": {
"value": "#72b28f",
"onWhite": 2.48,
"onBlack": 8.48
},
"500": {
"value": "#569674",
"onWhite": 3.49,
"onBlack": 6.01
},
"600": {
"value": "#3e7e5d",
"onWhite": 4.83,
"onBlack": 4.35
},
"700": {
"value": "#226344",
"onWhite": 7.15,
"onBlack": 2.94
},
"800": {
"value": "#004a2d",
"onWhite": 10.41,
"onBlack": 2.02
},
"900": {
"value": "#002c19",
"onWhite": 15.28,
"onBlack": 1.37
}
},
"neutral": {
"50": {
"value": "#eff8f2"
},
"100": {
"value": "#e5eee8"
},
"200": {
"value": "#d1dad5"
},
"300": {
"value": "#b8c0bb"
},
"400": {
"value": "#9ca49f"
},
"500": {
"value": "#808883"
},
"600": {
"value": "#69716c"
},
"700": {
"value": "#505753"
},
"800": {
"value": "#383f3b"
},
"900": {
"value": "#1f2622"
}
}
},
"type": {
"small-print": {
"size": "0.875rem",
"lineHeight": 1.5
},
"body": {
"size": "1.125rem",
"lineHeight": 1.6
},
"lead-paragraph": {
"size": "1.438rem",
"lineHeight": 1.5
},
"heading-3": {
"size": "1.75rem",
"lineHeight": 1.35
},
"heading-2": {
"size": "2.188rem",
"lineHeight": 1.25
},
"heading-1": {
"size": "2.75rem",
"lineHeight": 1.15
},
"display": {
"size": "3.438rem",
"lineHeight": 1.05
}
}
}Why the steps look right
The usual way to build a ramp is to hold the hue and walk lightness in HSL. It's also why so many generated palettes have muddy middles: HSL's lightness isn't perceptual. Pure yellow and pure blue both sit at 50%, and one of them is blinding.
This builds the ramp in OKLCh instead, a space designed so equal steps in lightness look like equal steps. When a step would be too saturated for a screen to show, the saturation comes down rather than the channels being clipped — clipping is what shifts the hue and gives you a ramp that drifts from orange to brown.
The contrast figures are measured, not estimated. The lightness targets and the line-height suggestions are opinions, and the tool says which is which rather than presenting all of it as fact.
If you need the whole system — logo, type, the rules for using them — that's brand & design systems work, and it starts with a conversation rather than a hex code.
Common questions
Two things. The ramp is built in a perceptual colour space, so the steps look evenly spaced instead of merely being evenly spaced in numbers — the usual approach produces muddy middles and ends that bunch up. And every step tells you whether black or white text actually passes contrast on it, which is the question you'll hit the moment you try to use the colour.
They're the WCAG 2.1 formula computed on the exact hex shown, so yes. Worth being precise about what they cover: contrast between a text colour and a solid background. They say nothing about text over a photo, over a gradient, or at a weight so light it's hard to read at any ratio.
No. It's a starting palette and a type scale — the mechanical part. A brand is what you sound like and what you're for, and no tool derives that from a hex code. This gets you a coherent set of colours to build with instead of picking shades one at a time until they clash.
Because it's a mid-tone. Colours in the middle of the lightness range are too dark for black text and too light for white, and no amount of wanting changes that. Use it for a shape, a border, or a chart fill, and put words on the steps that pass.
Beyond the palette
The hard half is a set of rules everyone actually follows, so the site, the invoice and the van all look like the same company.
Fixed price agreed before work starts. No hourly billing, no surprises.