Skip to content
Resources

Concept

What color debt is

Design systems accumulate near-identical colors nobody can tell apart. Here is how that happens, what it costs, and how to measure it before it becomes unfixable.

7 min read

Nobody decides to have forty-three colors. It happens one reasonable decision at a time: a card needs a slightly softer border, a marketing page ships with its own blue, a component library arrives with its own greys, someone matches a colour by eye from a screenshot. Every one of those was the right call in the moment. The sum of them is color debt — colours in a system that carry no meaning the system did not already have.

The two kinds

Debt shows up in a shape worth naming, because the fix differs:

  • Duplicates. Two values nobody can distinguish. Below a CIEDE2000 distance of 2.3 — the just-noticeable difference — the colours are the same colour to a human eye, and keeping both means maintaining two values forever to express one idea.
  • Near-misses. Between 2.3 and 5, the difference is technically visible but not reliably so — not across displays, not in sunlight, not side by side on different screens. These are the dangerous ones. They are different enough to survive review and too close to communicate anything.

The second category is where the cost hides. A duplicate is embarrassing and harmless. A near-miss is a colour that looks like it means something — so someone will eventually build a rule on top of it, and now the difference between #2563EB and #2A66EC carries semantics that no display will reliably render.

What it actually costs

Not aesthetics. The costs are operational, and they compound:

  • Every colour is a value to keep in sync. A brand refresh has to find all forty-three, and the near-misses are the ones that get missed — leaving a page that is subtly, unfixably last-season.
  • Review stops working. Once a palette is large enough that nobody holds it in their head, “is this an existing colour?” becomes unanswerable in a pull request, so the answer defaults to yes and the palette grows again.
  • Accessibility work multiplies. Each colour is a set of pairings to check. Duplicates add the entire checking burden while adding no expressive range whatsoever.
  • It is the one kind of debt that gets harder, never easier. Deleting a colour means touching every call site, and the number of call sites only goes up. The cheapest moment to merge two colours is always now.

Measuring it

The reason to have a threshold at all is that “these look the same to me” is not an argument that survives a design review, and ΔE < 2.3 is. Perceptual distance gives the conversation a number that neither party owns.

Two measurements are worth taking on any system: how many colours could be removed without anyone noticing, and how few colours the system could be expressed in. The first is duplicate detection. The second is compression — and the answer is usually far lower than the palette’s current size, which is the number that tends to change people’s minds.

One rule when you merge

Survivors must be colours that already exist in the system, never averages. Replacing a cluster with its mathematical centroid produces a palette containing none of the values currently in the codebase — so every single call site changes, the diff is unreviewable, and a merge that was supposed to reduce risk has touched everything.

Keeping one original member instead means the diff only shows the colours that genuinely moved. That is the difference between a merge that ships and one that sits in review until it goes stale.

Where this is heading

The Palette Doctor measures debt for a palette you paste in. The colour debt linter does the same thing for a whole codebase — paste or upload real stylesheets and get the duplicates, the near-misses and a debt ratio for the project, not just the five swatches in front of you. Next is the same engine in CI, on every pull request — the point being to catch the forty-fourth colour at the moment someone adds it, which is the only moment removing it is free.

Scan a codebase for colour debt →