Skip to content

Palette Generator

Builds a harmonious palette from a base colour using complementary, triadic and analogous rules.

Takes one colour and rotates its hue by a harmony rule, holding the OKLCH lightness and chroma so a triad does not come back with one member visibly darker than the others. The same rule is drawn in HSL underneath, which is the fastest way to see why that matters. Before you export, it checks whether any two swatches collapse into each other under a colour vision deficiency and whether each one can carry text.

🔒 Runs entirely in your browserpalettecolorharmonygenerator

Base colour

Any CSS notation. The harmony holds this colour's OKLCH lightness and chroma and rotates the hue.

Harmony

Rule

Neighbours, 30° either side. Reads as one colour family; needs a contrast difference to carry hierarchy because the hues will not.

OKLCH

#0094c3

L 62.3 C 0.188 H 230

#3b82f6

L 62.3 C 0.188 H 260

#886cee

L 62.3 C 0.188 H 290

The same rule in HSL, for comparison

#3be0f6

L 83.3 C 0.132 H 209

#3b82f6

L 62.3 C 0.188 H 260

#523bf6

L 51.4 C 0.260 H 278

Both strips rotate the hue by the same angles. The OKLCH row holds perceived lightness constant — its spread is 0.0000 — while the HSL row's spread is 0.3191, because HSL's “lightness” is not perceptual: pure yellow and pure blue both claim 50% and differ by more than 65 points of L*. That difference is not a rendering artefact; it is a lightness ramp nobody asked for, baked into every HSL harmony.

Lightness spread

0.0000

Outside sRGB

1 of 3

1 swatch could not keep the base chroma inside sRGB and gave up 0.064 of it. The hex values are the mapped versions; the oklch() values in the export are what a wide-gamut display will actually show.

Will it hold up?

Closest pair under each simulated vision type, in ΔE OKLab

  • Protanopia0.026— these two collapse
  • Deuteranopia0.021— these two collapse
  • Tritanopia0.012— these two collapse
  • Achromatopsia0.013— these two collapse

WCAG contrast against paper

  • on white 3.49·on black 6.02text-safe on one of them
  • on white 3.68·on black 5.71text-safe on one of them
  • on white 3.87·on black 5.43text-safe on one of them

A pair that collapses under a simulation is a pair that must not be the only difference between two things — add a shape, a label or a lightness step. The contrast checker has the full APCA verdict for a specific pair.

Export

Format

The CSS and Tailwind forms emit oklch() with the hex as a comment — throwing the precision away at the export would undo the reason for computing in OKLCH at all, and a browser given oklch() renders the wide-gamut colour where it can.

Want a full 50–950 ramp from one of these instead of a set of hues? The tint and shade generator builds one, anchored to a measured lightness curve.

How to use it

  1. Put in the colour you already have

    Usually the brand colour, in any CSS notation. Everything else is derived from its hue, lightness and chroma, so this is the one decision that shapes the whole set.

  2. Choose the rule, then adjust its spread

    Complementary is one opposite hue; analogous is neighbours; triadic is three at 120°; split complementary softens a complementary pair. The spread slider scales those offsets — 1 is the textbook spacing, and below it the set reads as one family. Monochromatic and shades ask for a step count instead, because they vary lightness rather than hue.

  3. Compare the two strips

    The lightness spread under the OKLCH row is near zero by construction. The HSL row rotates by the same angles and its spread is not, because HSL lightness is not perceptual — pure yellow and pure blue both claim 50%. If the two strips look the same to you for this particular base colour, they are, and either one is fine.

  4. Read the "will it hold up" panel before exporting

    It reports the closest pair under each simulated vision type in ΔE OKLab, and the WCAG contrast of every swatch against white and black. A pair marked as collapsing must not be the only thing distinguishing two states — add a shape, a label, or a lightness step.

  5. Export with the prefix your code uses

    CSS variables, a Tailwind `@theme` block, SCSS, JSON tokens or an SVG swatch sheet. The CSS forms emit `oklch()` with the hex beside it as a comment.

Common questions

The hex and the oklch() in the export are different colours. Which is right?

Both, for different displays. When holding the base chroma would put a swatch outside sRGB, the hex is the gamut-mapped version — chroma given up to fit — and the `oklch()` value is the colour that was actually computed, which a wide-gamut screen will show. The panel says how much chroma each clipped swatch lost.

Does a harmony rule mean the palette will look good?

No. These are angles on a hue wheel, and geometry is not taste. What a rule gives you is a defensible starting set with a reason behind each hue, which is worth more than three colours picked one at a time. Judgement about proportion — which one is the large area and which one is the 5% accent — is not in here at all.

Can I paste in a palette I already have and check it?

Not here — this page starts from one colour and derives the rest. For a specific pair, the contrast checker takes both colours and gives the full verdict. For a ramp from one of these swatches, the tint and shade scale builds it.

What counts as "these two collapse"?

A ΔE OKLab below 0.06 after simulation, which is roughly where two fills stop being separable at a glance. The simulation itself is the Brettel-style matrix approach: a model of the common deficiencies, not a measurement of any particular person, and it says nothing about the rarer types or about acquired vision loss.

Feed it from

Next

These accept what this tool produces, so the result can go straight in.