Skip to main content
PerfectPalette
PerfectPalette HelpColor Tools
Back to app

Color Tools

The Tools page provides standalone utilities for common color tasks. They all live under /tools, reachable from Tools in the main navigation. The footer links the most-used ones directly, plus All tools for the full list. Each tool works independently — you don't need a palette open to use them, and you don't need an account.

Tools that produce colors have an action that carries their output into the editor. What it's called depends on where you are: inside the workspace it names what will happen to the palette you already have open — Send to palette, Merge into palette, Add scale to palette — because the tools differ in whether they append, replace, merge, or regenerate. On a public tool page there's no palette open yet, so the button reads Open in Perfect Palette and takes you to the editor with your colors applied. Your work carries over even if you weren't signed in when you started.

Each tool page also ends with a short summary of what the full editor does beyond that tool, and a link into it.

What happens on arrival depends on whether you already have a palette in progress:

  • Starting fresh — the colors you sent become the palette. They're locked so nothing overwrites them, the first becomes your hero color, and Perfect Palette builds the rest around them: supporting accents plus light and dark neutrals. You land on the Colors step with a complete palette rather than being asked what you'd like to do. Because generation is based on the colors themselves, sending the same color always gives you the same starting palette.
  • Already working on something — your palette is restored first and the tool's action applies to it, replacing, merging, or adding depending on the tool. Nothing you had is lost.

Sent colors stay locked either way, so you can change the harmony mode and regenerate freely — your colors keep their exact values while everything around them changes.


Accessible Palette Generator

Generate a palette and check it against WCAG contrast requirements.

How it works: pick a base color; it's locked in as your hero and the rest of the palette is built around it — supporting accents plus light and dark neutrals. Every chromatic color is then scored against both neutral backgrounds.

Reading the results: a color counts as readable if it clears AA (4.5:1 for 16px body text) on at least one of your two neutrals. This is not a lenient reading of the standard — no single color can clear AA against both a near-white and a near-black background, because the lightness range where it passes on white barely overlaps the range where it passes on black. What matters is that a color works on the background you actually pair it with, so both ratios are shown and the stronger one is listed first.

A color that fails on every background genuinely can't carry body text. Those get a Fix button, which searches for the nearest lightness that clears 4.5:1 on whichever neutral it's already closest to, keeping the hue and saturation so the color stays recognisably yours. A fix is only applied if it actually increases the number of readable colors. Fix all repeats this until nothing is left to improve.

Color vision simulation: switch between normal vision, protanopia, deuteranopia, tritanopia, and achromatopsia. This does two things — it recolors the swatches to preview the palette, and it flags any two colors that become hard to tell apart. That second part is a different question from contrast: color vision deficiency barely changes lightness, so a pair can have perfectly good contrast and still be indistinguishable. Contrast ratios are always measured on your real colors, never the simulated ones.

Every combination: the grid shows every color against every other color, if you want to read the full matrix rather than just the text/background pairs.

Exports: CSS variables, Tailwind v4 @theme, JSON tokens, and Figma tokens — copy straight out of the page, no account needed. The full export set lives in the workspace.


Color Converter

Convert a color between formats instantly.

Supported formats:

  • Hex
  • RGB
  • HSL
  • HSV
  • CMYK
  • CIELAB
  • LCH
  • CSS lab()
  • CSS lch()
  • OKLCH
  • Pantone (nearest match)

Enter a value in any format and see the equivalent in all other formats.

Which rows are CSS: RGB, HSL, OKLCH, and the two rows labelled CSS lab() and CSS lch() are valid CSS you can paste straight into a stylesheet. The rest — HSV, CMYK, CIELAB, LCH, and Pantone — are notation for reading and comparing values, not for stylesheets.

Three details worth knowing:

  • OKLCH is space-separated (oklch(0.480 0.120 160.5)). Unlike rgb() and hsl(), which kept their commas for backwards compatibility, oklch() has no comma form and a comma there is a parse error.
  • CIELAB appears twice, and the two rows disagree on purpose. CSS lab() and lch() are defined against the D50 white point, while CIELAB is conventionally reported against D65 — which is the correct illuminant for sRGB and what other online converters show you. The same three numbers therefore name two different colors: sRGB blue is lab(32.3, 79.2, -107.9) at D65 and lab(29.6 68.3 -112) in CSS. So the CIELAB and LCH rows give you the conventional D65 answer in a comma form a browser rejects outright, and the CSS lab() and CSS lch() rows give you the D50 values that are correct in a stylesheet. Copy from whichever row matches your question; pasting a D65 value into CSS produces a noticeably different color rather than an error.
  • Percentages mean different things in different formats. oklch(52.1% 0.107 164.6) and lab(52.1% -37 11) do not scale the same way — CSS defines 100% as 1.0 for OKLCH lightness but 100 for CIELAB lightness. The converter follows the spec per component, so both the percentage and plain-number forms of a value give you the same color.

On input, pick the matching source format — CIELAB and CSS lab() are listed separately because the numbers look identical and mean different colors. The field accepts either separator.


Color Wheel

An interactive color wheel for exploring harmony relationships.

  • Click or drag on the wheel to select a color.
  • Choose a harmony mode (Complementary, Analogous, Triadic, etc.) to see related colors.
  • Use this to quickly find harmonious combinations before committing to a full palette.

Image Extract

Upload an image to extract its dominant colors.

  • Drag and drop or click to upload an image.
  • PerfectPalette analyzes the image using k-means clustering to find the most prominent colors.
  • Near-white and near-black colors are excluded by default to focus on meaningful hues.
  • Use the extracted colors as a starting point for a new palette.

Website Extract

Pull the color palette from any live website.

  • Enter a website URL.
  • PerfectPalette scans the site and extracts the colors used in its CSS and design.
  • Review the extracted colors and import any you'd like to use.

Scale Generator

Generate a monochromatic or multi-hue color scale.

  • Pick a base color.
  • Generate a stepped scale (lightest to darkest) using perceptually uniform color space.
  • Useful for creating consistent shade ramps for buttons, backgrounds, and borders.
  • A dot on a step means it was gamut-corrected: the scale asked for a color more vivid than sRGB can display, so its saturation was reduced to the most vivid version that fits. Lightness and hue are kept exactly, so the step still sits correctly in the ramp. This is most common in the lightest and darkest steps of a strongly saturated color — there is simply less room for saturation near white and near black.

OKLCH Palette Generator

Build a scale by setting OKLCH lightness, chroma, and hue directly.

  • How it differs from the Scale Generator: the Scale Generator gives you full control over the shape of the curve — lightness range, chroma peak, hue drift. This one gives you direct control over the anchor color's three OKLCH values and shows you what sRGB can do with them. Use this when you are working in OKLCH and want to understand the gamut; use the Scale Generator when you want to tune the ramp itself.
  • The chroma slider shows the gamut. The shaded region past the end of the colored track is chroma sRGB cannot display at your current lightness and hue. It moves as you drag the other two sliders — there is very little chroma available near white or black, and a lot in the mid-tones. How much also depends strongly on hue: yellow stays vivid at high lightness, blue does not.
  • If a color is outside sRGB, the readout tells you the ceiling and the swatch shows the closest displayable color. Chroma is reduced while lightness and hue are held exactly, so the color stays the hue you picked rather than drifting the way clamping RGB channels would.
  • Steps marked with a dot sit at the sRGB boundary. That is not an error — they are the most vivid colors that hue can reach at those lightnesses. On a strongly saturated anchor, most of the light and dark steps will be marked.
  • Copy CSS variables gives you a :root block of oklch() values keyed 50 to 900, ready for a Tailwind v4 @theme block or any design-token pipeline. The syntax is space-separated per CSS Color 4 — oklch(55% 0.17 264), never commas.

Tailwind Palette Generator

Turn a single brand color into a complete Tailwind color scale.

  • Pick one color, get eleven shades. Tailwind's built-in palettes run 50, 100 through 900, and 950. That set is what the whole ecosystem is written against, so a custom color only drops in cleanly if it has the same stops — a button styled bg-brand-600 hover:bg-brand-700 needs both of those to exist.
  • Your color is pinned to step 500 and is not adjusted. The other ten shades are built around it.
  • Choose your Tailwind version. v4 gives you an @theme block of CSS custom properties — paste it into your stylesheet and the utilities exist, with no config file involved, because declaring --color-brand-500 is itself what creates bg-brand-500. v3 gives you a nested object for theme.extend.colors in tailwind.config.js.
  • Use extend, not theme.colors. The generated v3 snippet goes under theme.extend.colors. Putting colors in theme.colors instead replaces Tailwind's default palette outright, and every gray-* and red-* class in your project stops resolving.
  • Name your color to change the class prefix. The name is sanitized into a valid key — "My Brand" becomes my-brand, giving you bg-my-brand-500 — and the key actually in use is shown beneath the field.
  • Shades are generated in OKLCH with hue held fixed, so light steps don't drift toward a neighbouring color the way RGB lightening does. See the Scale Generator notes above for what gamut correction means.

Color Contrast Checker

Check one foreground/background pair against every WCAG contrast requirement.

  • Three thresholds, not one. Normal text needs 4.5:1 for AA and 7:1 for AAA. Large text — 24px and up, or 18.7px and up when bold — needs 3:1 and 4.5:1. Icons, borders, and focus rings need 3:1 under WCAG 1.4.11. All three are evaluated at once from the same ratio.
  • No AAA badge appears for UI contrast. WCAG defines no AAA level for non-text content, so there is nothing there to pass or fail. An absent badge is not a failing one.
  • The ratio is symmetric. Swapping foreground and background changes the preview but never the verdict — WCAG divides the lighter luminance by the darker one, so order cannot matter.
  • Fix searches for the nearest lightness that clears 4.5:1, holding hue and chroma so the color stays recognisably yours, and adjusts whichever side needs the smaller change. The button only appears when a fix is both needed and reachable.
  • Shareable links. The address bar tracks your pair as ?fg=&bg=, and Copy link gives you that URL. Opening one restores both colors. Either side can be omitted — a link with only ?fg= keeps the default background — and the leading # is dropped because in a URL it would truncate everything after it.
  • Contrast is necessary but not sufficient: two colors can have excellent contrast and still be indistinguishable to someone with a color vision deficiency, since CVD barely changes lightness. Use the Accessible Palette Generator above to check hue separation as well.

Gradient Generator

Create and preview smooth gradients.

  • Set start and end colors.
  • Adjust the gradient type (linear, radial) and direction.
  • Preview the result and copy the CSS.

Brand Alignment

Compare a palette against brand guidelines.

  • Enter your brand's target colors.
  • Upload or input the palette you want to evaluate.
  • See how closely each color matches the brand targets, with distance scores.
  • Useful for verifying that a design implementation stays faithful to brand specs.

Design Token Import

Import an existing design system into Perfect Palette from standard token files.

  • Upload a design token JSON file, a Figma Variables export, a Tailwind v3 config (.js/.cjs/.mjs), or a CSS custom properties file.
  • Both design token JSON shapes are read: W3C DTCG ($value / $type) and Tokens Studio's default export (value / type).
  • Figma Variables exports are read — the meta.variables payload from GET /v1/files/:key/variables/local. Colors are decoded from Figma's RGBA floats and variables that point at other variables are followed to the value they end on. Figma states only a storage type for its numbers and text, never what they are for, so those are reported rather than sorted into scales: a FLOAT named Radius/4 and one named Breakpoint/Width look identical to us.
  • Coming from Figma? Figma has no built-in token export, so the file comes out of a Community exporter plugin — Variable Export, Design Token Exporter and Styles & Variables Exporter among them. Which plugin you used matters less than what it writes: W3C DTCG and Tokens Studio JSON are both read, as is Figma's own Variables payload. Drop the file in and the result names the format it recognised, rather than reporting an unfamiliar file as empty.
  • Zip archives containing multiple files are supported.
  • From a design token JSON file, the whole design system is read — not just the palette. Alongside colors, the importer captures font families, type sizes, line-heights, font weights, letter spacing, named typography roles, corner radii, elevations (box shadows) and the spacing scale, each of which has a section in an exported design.md. Values written the way the DESIGN.md format itself writes them — colors as { colorSpace, components } objects and measurements as { value, unit } objects — are read as well as the plain strings Tokens Studio emits. Tailwind configs and CSS variable files still contribute colors, font families and spacing only.
  • Aliases in token JSON are resolved. A token defined as {Color.Primitive.Blue.500} is followed to its value, including references written the way Tokens Studio namespaces them to a token set. Where a semantic name and a primitive name describe the same color, the semantic one is kept and the primitive is recorded alongside it.
  • Anything read but not imported is reported rather than dropped — most often colors carrying transparency, which a palette color cannot represent.
  • A file with modes has one of them read, and the page says which. Figma collections carry modes, and they are not reliably a light/dark pair — real files use them for brand and for breakpoint too, and a color mode may be named something else entirely. A design system holds one value per token, so one mode is read from each collection (the one Figma marks as that collection's default) and the page names the collection, how many modes it found, and which it took. The rest stay in your Figma file. Values are only ever taken from the mode that was named: a variable defining nothing in that mode is reported as such rather than quietly read from another one, so the mode the page names is true of every color it imported.
  • If a file cannot be read, the page says so and names the format where it can, rather than reporting the file as empty.
  • Extraction is free and needs no account. Files are read in your browser and nothing is uploaded — the colors appear immediately, and Open in Perfect Palette takes them into the editor as a palette.
  • Before you save, the page says what will be read and what will be guessed. A file that names no typography roles has its six assigned from the size scale, and the preview says so rather than letting them arrive looking like a reading of the file.
  • Scale keys are kept as you named them. A spacing step called gutter stays gutter rather than being renamed to its position in the scale, and a corner radius called full stays full. A step named unit or base is taken as the system's base unit.
  • Typography levels beyond the six Perfect Palette names are kept too. The six — display, heading, subheading, body, caption, label — are matched to the levels your file states; anything left over is stored under its own name and printed in the exported design.md alongside them. A file that states no roles at all has them inferred from its size scale instead.
  • Create a design spec saves the result as a full design spec and takes you to it. Typography, spacing and surface systems are created from what the file described, so the spec arrives with those sections filled in rather than empty. A section the file said nothing about is left unset rather than filled from a preset — an empty typography section means your file described no typography, which is recoverable; one filled from defaults would claim it named fonts it never named. This step uploads the files and is available on Pro plans.