Turn one brand colour into a complete token scale — eleven steps from 50 to 950 — built in OKLCH so the steps are perceptually even rather than mathematically even. Chroma and hue can be shaped across the ramp, and the output is CSS custom properties you can paste straight into a stylesheet.
Steps, 50 to 950
11
Space the ramp is built in
OKLCH
Anchor colour needed
1
Requests made
0
Step by step
How to use it
01Set the anchor
One colour, in any CSS notation. It sets the hue and chroma the whole scale inherits, and it is the step the rest of the ramp is built around.
02Shape the ramp
Chroma scale controls how saturated the middle of the scale stays, hue shift bends the hue gradually across it, and range decides how far the ends travel toward white and black.
03Check the ends against real use
50 to 100 is a canvas tint, 200 to 300 are borders, 500 to 700 are primary actions, and the dark end is text. Read each step against the surface it will actually sit on.
04Copy the variables
Output is CSS custom properties in OKLCH or hex, named from your token name — ready to paste into a stylesheet or a theme file without renaming anything.
Worked example
Why the scale is built in OKLCH
The same eleven steps, generated two ways. This is the difference between a scale that looks even and one that only measures even.
Given
Anchor
#7C3AED
Steps
50 … 950
Question
even by what measure?
Equal steps in HSL against equal steps in OKLCH
HSL lightness, evenly spaced
the yellows and cyans wash out early
the blues stay dark far too long
step 400 and 500 look almost identical
OKLCH lightness, evenly spaced
every step differs from its neighbour
by the same perceived amount
and the same recipe works on any hue
Steps generated
11
Even in
perception
Hue drift
yours to set
A token scale is a promise that 500 means the same thing for every colour in the system — same weight, same emphasis, same contrast behaviour. That only holds if the steps are even to the eye, which is what OKLCH gives you and HSL does not. It is also why a palette generated this way needs so little hand-correction afterwards.
Before you adopt the scale
What to know about token scales
The numbers are a contract, not decoration
500 should mean the same emphasis whether the hue is your brand purple or a warning red, so a component using primary-600 for a hover state works when the theme changes. That only holds if every scale is built the same way — which is the argument for generating them rather than picking them.
Chroma cannot stay constant across lightness
There is far more room for saturated colour in the middle of the lightness range than at either end, so a scale that holds chroma flat clips at the extremes and comes back grey or shifted. Tapering it toward the ends is why the light and dark steps look like the same colour rather than a different one.
A little hue shift makes a ramp feel natural
Shadows tend cooler and highlights warmer in the physical world, and scales that mimic that read as more considered. Keep it small — a few degrees across the whole ramp. A large shift stops being a scale of one colour and becomes two.
Check contrast at the pairs you will actually use
The useful question is not whether step 600 passes in the abstract but whether 600 on 50 passes, and whether 100 on 900 does. Those pairs are what components are built from — verify them once, and the whole system inherits the answer.
Generate, then hand-correct sparingly
A generated ramp gets you most of the way and will occasionally produce a step that is wrong for a specific use — a brand colour that must be exact, or a mid-step that clashes with an existing asset. Fix those individually, and leave the rest of the ramp generated so it stays regenerable.
Everything runs in your browser
The ramp, the contrast readouts, and the CSS output are all computed locally, and the share link carries the anchor and the shaping controls — enough for a colleague to reproduce the identical scale.
The judgement call
Which step for which job?
A scale is only useful if the team agrees what each end is for.
Page and card backgrounds
50–100
Barely tinted. Enough to separate surfaces without becoming a colour in its own right.
Borders, dividers, disabled fills
200–300
Visible against the canvas but never competing with content for attention.
Buttons, links, primary actions
500–700
The saturated middle, where there is enough contrast for white text and enough colour to read as the brand.
Body text on a light canvas
800–950
Dark enough to clear 4.5:1 comfortably while staying tinted rather than flat black.
A dark theme
Invert the roles
Do not invert the values — reassign which steps are surface and which are text, and re-check every pair.
One colour that must match a brand exactly
Pin it
Set it by hand and generate the rest around it. Do not bend the whole ramp to make the generator produce it.
Reference
How the scale is built
Steps
50 · 100 · 200 … 900 · 950Eleven stops, matching the convention most design systems and utility frameworks already use.
Space
OKLCHLightness is stepped perceptually, so neighbouring steps differ by the same visible amount at every hue.
Chroma scale
Multiplies the anchor's chromaLets the ramp stay saturated through the middle and taper toward the ends, where the gamut narrows.
Hue shift
Degrees across the rampA small drift — cooler in the shadows, warmer in the lights — reads as natural. Large shifts read as two colours.
Range
How far the ends travelControls whether 50 and 950 approach white and black or stop short of them.
Output
CSS custom propertiesOKLCH or hex, named from your token name, ready to paste into a stylesheet.
FAQ
Questions, answered plainly
How do I generate a colour palette from one colour?
Paste your brand colour as the anchor. Eleven steps from 50 to 950 are generated around it in OKLCH, inheriting its hue and chroma, and the output is CSS custom properties you can paste straight into a stylesheet.
Why 50 to 950 rather than 1 to 10?
The 50 to 950 scale is the convention most design systems and utility CSS frameworks already use, which means your tokens line up with what other tools and other engineers expect. The gaps also leave room to insert a step later without renumbering everything.
Why build the scale in OKLCH instead of HSL?
Because equal steps in HSL are not equal to the eye — yellows wash out early and blues stay dark far too long, so a scale looks uneven even though the numbers are regular. OKLCH lightness tracks perception, so one recipe produces an even ramp at any hue.
How do I know the palette is accessible?
Check the pairs you actually use rather than the steps in isolation: text steps against surface steps, typically 800 or above on 50 to 100. Once those pairs pass, every component built from the tokens inherits the result — which is the main practical benefit of having a scale at all.
Can I use this for a dark theme?
Yes, but reassign the roles rather than inverting the values. In dark mode the light steps become text and the dark steps become surfaces, and the contrast pairs need re-checking because the relationships are not symmetric.
Is anything sent to a server?
No. The ramp, the contrast readouts, and the CSS output are all computed in your browser, and the share link carries only the anchor colour and the shaping controls.
The ramp, contrast readouts, and CSS output are all computed in your browser. Share links carry only the anchor and the shaping controls.