🎨 Color Palette Generator

Pull a palette from a photo or build one from a color. Every swatch carries its WCAG contrast ratio, and the image is read in your browser, never uploaded.

✓ Free✓ No Signup Required✓ Browser-Based

Opposite sides of the wheel. Maximum contrast — strong for a call to action against a dominant color, tiring if used in equal amounts.

White text

5.2:1 with white text — passes for body text

Black text

8.5:1 with black text — passes for body text

Black text

10.5:1 with black text — passes for body text

Black text

13.0:1 with black text — passes for body text

White text

10.6:1 with white text — passes for body text

Take it with you

Hex list
#2563eb, #86a4e6, #ebad25, #e6c886, #0d3792
CSS custom properties
:root {
  --color-1: #2563eb;
  --color-2: #86a4e6;
  --color-3: #ebad25;
  --color-4: #e6c886;
  --color-5: #0d3792;
}
Tailwind config
// tailwind.config.js
theme: {
  extend: {
    colors: {
      'color-1': '#2563eb',
      'color-2': '#86a4e6',
      'color-3': '#ebad25',
      'color-4': '#e6c886',
      'color-5': '#0d3792',
    },
  },
}
JSON
[
  {
    "name": "color-1",
    "hex": "#2563eb",
    "rgb": "rgb(37, 99, 235)",
    "hsl": "hsl(221, 83%, 53%)",
    "contrastWithWhite": 5.17,
    "contrastWithBlack": 4.06
  },
  {
    "name": "color-2",
    "hex": "#86a4e6",
    "rgb": "rgb(134, 164, 230)",
    "hsl": "hsl(221, 66%, 71%)",
    "contrastWithWhite": 2.48,
    "contrastWithBlack": 8.47
  },
  {
    "name": "color-3",
    "hex": "#ebad25",
    "rgb": "rgb(235, 173, 37)",
    "hsl": "hsl(41, 83%, 53%)",
    "contrastWithWhite": 1.99,
    "contrastWithBlack": 10.54
  },
  {
    "name": "color-4",
    "hex": "#e6c886",
    "rgb": "rgb(230, 200, 134)",
    "hsl": "hsl(41, 66%, 71%)",
    "contrastWithWhite": 1.62,
    "contrastWithBlack": 12.97
  },
  {
    "name": "color-5",
    "hex": "#0d3792",
    "rgb": "rgb(13, 55, 146)",
    "hsl": "hsl(221, 84%, 31%)",
    "contrastWithWhite": 10.61,
    "contrastWithBlack": 1.98
  }
]

Contrast is measured against black and white only. Text in one of your own palette colors on another needs checking as a pair — and a color that fails here will fail everywhere it carries text, which is much cheaper to discover now than during an accessibility audit.

What Color Palette Generator Does

Color harmony is geometry on a wheel. Complementary colors sit opposite each other, triadic ones at the corners of an equilateral triangle, analogous ones side by side — the schemes are rotations of hue, which is why this generator works in HSL: it is the space where those relationships are actually defined. Convert to any other space and the classical relationships stop being simple rotations.

The schemes are a starting point rather than an answer. A complementary pair used in equal amounts is exhausting to look at; the same pair with one color dominant and the other reserved for a call to action is the most reliable interface palette there is. That is a proportion decision, and no generator makes it for you.

What this adds, and what the popular palette tools leave out, is the number that decides whether a palette survives contact with real content: contrast. Every swatch carries its ratio against black and white and says which to use on it. A palette that looks beautiful and fails WCAG is one you will discover has to be rebuilt, usually late, usually after it is already in production.

Contrast is computed the way the guideline defines it — relative luminance in linear light, not a simple brightness average — so the figures match what an accessibility checker will tell you rather than approximating it.

It will also pull a palette out of an image, which is the thing most people actually want from a palette tool and the part where implementations quietly differ. The clustering runs in linear light rather than on the stored bytes, because the byte 128 is not half the light of 255, it is 21.6% of it. Average the bytes across a black-and-white boundary and you get 128; average the light and you get 188. Gamma-space extraction pulls every color it finds toward the dark end, and on a photo with hard edges you can see it.

Nothing about any of this is a model, which matters if you have been burned by a generator that returns something different every time you ask. The harmonies are rotations of hue and the image colors are k-means over pixels — arithmetic with a defined answer, so the same input gives you the same palette today and next year. Your image is read in the browser and never uploaded.

How to Use Color Palette Generator

  1. Start from a color, or switch to "From an image" and choose a photo
  2. Pick a harmony, or set how many colors to pull out of the picture
  3. Check the contrast ratio printed on each swatch before committing to it
  4. Copy a single value, or export the palette as CSS variables, Tailwind config or JSON

Formula Used by Color Palette Generator

Contrast ratio

(L₁ + 0.05) ÷ (L₂ + 0.05), L = 0.2126·R + 0.7152·G + 0.0722·B in linear light

L₁, L₂
the relative luminance of the lighter and darker color
linear light
sRGB values are gamma-encoded and must be linearized first, or the answer is wrong
the weights
green dominates perceived brightness, which is why green text on white is harder to read than it looks

Worked example

#2563eb, a common interface blue, with white text on it.

  1. Linearize each channel, then L = 0.2126·R + 0.7152·G + 0.0722·B
  2. L for #2563eb ≈ 0.1387, L for white = 1.0
  3. (1.0 + 0.05) ÷ (0.1387 + 0.05)

Result: 5.17:1 — clears 4.5:1, so white body text on that blue passes.

The harmonies, and what they are for

SchemeHue relationshipCharacter
ComplementaryOpposite, 180° apartMaximum contrast. Strong for one accent against a dominant color; tiring in equal amounts
AnalogousNeighbors, ±30–60°Calm and cohesive. Needs an accent from elsewhere or it reads flat
TriadicThree points 120° apartVivid and balanced; best with one lead and two accents
Split complementaryThe complement, split ±30°Most of the tension of complementary with much less clash
TetradicTwo complementary pairsRichest and hardest to balance — mute all but one
MonochromaticOne hue, varying lightnessAlways harmonious; hierarchy comes from contrast, not hue

WCAG contrast thresholds

What the ratio on each swatch has to clear.

ContentMinimum (AA)Enhanced (AAA)
Body text4.5:17:1
Large text (18pt, or 14pt bold)3:14.5:1
Interface components and graphics3:1—

Source: WCAG 2.2 — Contrast (Minimum)

Why the stored number is not the brightness

The sRGB transfer curve, which is the reason both the contrast figures and the image extraction work in linear light. A gray written as 128 — exactly halfway through the byte range — emits barely a fifth of the light of white. Anything that averages the stored bytes is averaging a number that is not proportional to what you see.

sRGB valueShare of white's light
00.0%
321.4%
645.1%
12821.6%
16035.2%
18850.3%
22474.5%
255100.0%

Source: WCAG — relative luminance

How to Read Your Result

Pick a dominant color, not five equal ones

The reason generated palettes often look worse in use than on the swatch grid is proportion. A common working rule is roughly 60% of a surface in a dominant neutral or light color, 30% in a secondary, and 10% in the accent. Five colors at equal weight reads as noise whatever the harmony.

A mid-tone that fails both is the trap

Colors around the middle of the lightness range frequently fail against black and white alike — the swatch shows a ratio near 3:1 either way. Those are fine as large blocks or borders and unusable behind body text. Finding that out here is cheaper than finding it out in an audit.

Contrast against black and white is the start, not the end

If you intend to put one palette color on another — a colored button on a colored section — that pair needs checking on its own. The ratios here tell you about text on each color, which covers most uses and not all of them.

Why a palette pulled from a photo comes out dark elsewhere

sRGB stores color with a transfer curve, so the numbers in the file are not proportional to light. Byte 128 emits 21.6% of the light of byte 255, not 50%. A palette extractor that averages those bytes — which is the obvious implementation, and a common one — is averaging the wrong quantity, and the error runs one way: toward the dark end. Over a boundary between black and white the byte average is 128 while the color with the true mean light output is 188, a gap of 60 levels out of 255. This one converts every pixel to linear light, clusters there, and converts the cluster centers back at the end. Verified on synthetic images whose answer is known by construction: three flat colors in 60/30/10 proportion come back as exactly those three colors with exactly those shares.

Where the colors come from, and what the percentage means

The image is scaled down so its longest edge is 160 pixels — the dominant colors of a thumbnail are the dominant colors of the original, and putting twelve million pixels through k-means buys nothing — then clustered into as many groups as you asked for. The percentage on each swatch is the share of opaque pixels that fell into that cluster, which is why the order is by prevalence rather than by prettiness. Fully transparent pixels are skipped rather than counted as black, which matters for logos on a transparent background: count them and every palette comes back with a black that is not in the picture.

Limitations & Accuracy Notes

  • Contrast is reported against pure black and pure white only. Pairs of your own colors need checking individually.
  • No Pantone, RAL, Sherwin-Williams or other proprietary color system. Those catalogs are licensed, and their values are not public data to map to — a tool claiming to give you "the Pantone" for a hex code is giving you a guess with a trademark attached. Take a physical swatch to the supplier instead.
  • A palette extracted from an image describes that image. It is not a brand palette, and the dominant color of a photograph is frequently a background you do not want. Treat the result as a starting set to edit down.
  • The extraction is deterministic, which means it has no taste. It returns the colors that cover the most pixels, so a picture that is 70% sky returns a lot of sky.
  • The harmonies are geometric constructions in HSL. They are a reliable starting point, not a design; proportion, context and content do most of the work.
  • HSL lightness is not perceptual — two colors at the same L can look very different in brightness, which is exactly why the contrast figure is shown rather than inferred from the lightness value.
  • No color-blindness simulation. Palettes that distinguish states by hue alone can be unusable for some viewers regardless of contrast.
  • Output is sRGB. Wide-gamut colors in Display P3 or oklch are not generated.

Frequently Asked Questions

What are color harmonies?
Color harmonies are combinations of colors that are visually pleasing. Common types include complementary (opposite on color wheel), analogous (adjacent), triadic (three equally spaced), and split-complementary.
Can I get a palette from a photo?
Yes — switch to "From an image" and pick a file. It clusters the picture into as many colors as you ask for and reports what share of the image each one covers, so the order is by prevalence. The file is read in your browser and never uploaded.
Why do palettes extracted from photos often look too dark?
Because most extractors average the stored sRGB bytes, and those are not proportional to light. The byte 128 emits 21.6% of the light of white, not 50%. Averaged across a black-and-white boundary the bytes give 128 where the true mean light is 188 — a 60-level error, always toward the dark end. This tool clusters in linear light and converts back at the end.
What color formats can I copy?
HEX, RGB and HSL per swatch, plus the whole palette as a hex list, CSS custom properties, a Tailwind config block, or JSON that includes each color's contrast ratios and its share of the image.
Can it give me Pantone or Sherwin-Williams codes?
No, and be wary of tools that claim to. Those catalogs are licensed and their values are not public data to map a hex code onto, so any conversion is a guess wearing a trademark. For paint or print, match against a physical swatch from the supplier.
Does this use AI?
No. The harmonies are rotations of hue on the color wheel and the image colors are k-means clustering over pixels. Both are arithmetic with a defined answer, so the same input always produces the same palette.
What do the harmony types mean?
They are relationships on the color wheel. Complementary takes opposites for maximum contrast, analogous takes neighbors for a calm scheme, triadic takes three evenly spaced hues for vibrancy with balance, and monochromatic varies only lightness and saturation of one hue.
How many colors should a palette have?
Fewer than people expect. A dominant color, a secondary and one accent covers most interfaces, plus neutrals for text and backgrounds. The common failure is too many competing colors rather than too few.
Does a generated palette meet accessibility requirements?
Not automatically. Harmony is about aesthetics, not contrast, and two colors can be pleasing together and unreadable as text on background. Check any text pairing with a contrast checker before committing to it.
Why do my colors look different on another screen?
Displays vary in calibration, color gamut and default profile, and phones apply their own adjustments. A color picked on a wide-gamut monitor can look noticeably duller elsewhere, which is why brand colors are specified in values rather than by eye.
Should I work in HSL rather than hex?
For building a palette, yes. HSL separates hue from saturation and lightness, so generating a lighter or muted variant is one number change rather than recalculating three. Hex is for delivering the result.
Is anything sent to a server?
No. Palettes are generated in your browser.

References & Further Reading

By OnlineToolHubs Team • Updated September 2026