Eyedropper isn't enough
Most designers have done this: open a reference image in some app, eyedropper a handful of colors, paste them into a palette doc, call it a day. It works the way ordering takeout works — fast, expedient, you'll remember to do it better next time.
The problem isn't the eyedropper. It's that an image's identity isn't five hand-picked pixels. It's a distribution: a dominant tone, the seconds and thirds that show up in quieter quantities, the high-chroma accent that takes a sliver of the canvas but does most of the work. Hand-picking gets the obvious ones — the dominant, the accent — and misses everything between. The result reads like a poster of the image; it doesn't read like the image.
A clustering algorithm doesn't have your bias toward the obvious. It looks at every pixel and asks the same question for each: which group does this belong to? The answer is a palette that captures the image's actual color identity, not just the eye-grabbing parts. The trade is intentional: you give up the artistic control of curating five colors and get back something more honest about what's actually in the image.
Workbench then adds the part most extractors skip: role suggestions.
What clustering does
Think of every pixel as a point in color space. A photo has nearly a million of those points. Some areas of the space are dense (a dominant background tone has a million near-duplicates); some are sparse (a single brass detail might be 200 pixels in a corner of the distribution). The cloud has shape.
k-means clustering summarizes that shape with a smaller set of representative points called centroids. Each centroid stands for a coherent group of nearby pixels.
That makes palette extraction useful in two ways. First, the centroids land at the densest regions of the cloud — they represent the colors the image actually uses, not the colors that show up in a single corner. Second, the choice of color space controls what "nearby" means. For color work, that second part matters.
Why OKLCH, not RGB
The default clustering spaces are RGB or HSL. Both are wrong for palette extraction, but in different ways.
RGB clusters by raw byte distance. The space treats a 30-unit shift in green the same as a 30-unit shift in blue, but human vision doesn't. We're vastly more sensitive to mid-tone greens than to dark blues. Cluster a sunset photo in RGB and you'll get a palette weighted toward dark navies and underweighted on warm mid-tones. The algorithm is doing what you asked; you just asked for the wrong thing.
HSL is closer but distorts in its own direction. Its lightness channel isn't perceptual.
Pure yellow at hsl(60, 100%, 50%) and pure blue at
hsl(240, 100%, 50%) have the same numeric lightness and very different perceived
brightness. Cluster on HSL and the algorithm treats them as equally bright. They aren't, and
the resulting palette inherits the mistake.
OKLCH is the perceptually uniform alternative. Equal numeric distance roughly corresponds to equal perceived distance. Cluster a photo in OKLCH and the centroids land where your eye would land, not where the byte arithmetic does.
Implementation note: OKLCH and OKLab are the same color space in different coordinate systems. OKLCH is cylindrical (lightness, chroma, hue), which is how humans intuit color. OKLab is rectangular (lightness plus two opposing axes), which is how Euclidean distance naturally works. Clustering runs in OKLab to avoid the cyclic-hue boundary problem; centroids convert back to OKLCH for display and editing.
Roles, not just colors
Most extractors stop at the colors. Here's the strip; here's the hex codes; good luck.
But a palette isn't a collection of equal-weight colors. A palette has structure: a background, a body-text color, a maybe-surface for cards or panels, an accent that carries small high-chroma moments, and the muted in-betweens. Without that structure, eight hex codes is exactly as much work as five hex codes you eyedroppered manually.
Workbench tags each extracted color with a suggested role:
- Background — the lightest color in the palette.
- Surface — the second lightest, but only if it is still light enough to function as a surface and distinct enough from the background.
- Text — the darkest color, but only if it is actually dark enough to read on the background.
- Accent — the highest-chroma color in the mid-lightness range, but only if it has enough chroma to read as colorful.
- Muted — everything that doesn't fit another role.
The "but only if" guards matter. A medium gray shouldn't be labeled text just because it's the darkest available color. A near-black shouldn't become the accent just because it technically has the highest chroma. When the heuristic isn't confident, the tool leaves the color muted so you can decide.
Color clustering is solved. Role assignment is the part most extractors skip.
When to re-extract
k-means with k-means++ seeding produces stable but not deterministic results. Same image with a fresh seed can produce a slightly different palette.
Re-extract when:
- A color you'd swear is in the image isn't represented.
- The accent lands on a transition pixel (between an accent and its shadow) instead of the accent itself.
- The result feels too neutral.
One or two re-extracts is normal. If you're hitting it five times looking for a specific palette, the image probably doesn't have that palette to give.
How it composes
Save a palette to the bench and the other workbench tools see it immediately. Send the colors into the gradient tool as a 2-stop OKLCH gradient. Send the text and background into the contrast tool to check WCAG and APCA in one click.
Cross-tool URLs carry palette state too. A palette URL with
#palette={id} opens directly into /gradient or
/contrast with the right colors applied. Share it with a colleague; their browser
does the rest.
Workbench tools share a bench. Save once, reuse where the next design decision needs it.
What this tool isn't
A few honest scope limits.
It is not a brand color generator. A brand palette needs strategy, audience, accessibility, and repetition. This tool only knows the image you gave it.
It is not a color-theory tutor. The role assignment is heuristic, not theoretical. The tool tags the lightest color "background"; it doesn't argue that the lightest color makes a good background. Those are different decisions you make.
There is no AI-anything. No "let the model suggest a name," no semantic tagging, no trend feed. k-means dates to the 1950s; OKLCH is from 2020; the combination is what does the work. Both are deterministic given the same inputs and seed; both are explainable in a paragraph. That is a feature.
It is not Adobe Color. Adobe Color is a deeper toolkit aimed at a different workflow — color-rule transforms, harmony-mode pickers, named-color libraries. Workbench's palette extractor is intentionally narrower. Image in, useful palette out, save it, use it.
Related tools
- Gradient — turn saved palette colors into editable OKLCH gradients.
- Contrast — check whether suggested text and background roles are readable.
- Type Scale — test palette decisions against real type sizes.
- Shadow — preview shadows against palette-driven card surfaces.