A checkout card for a boat slip with its fee labels selected, next to the Swatchbook panel suggesting ink/700 because the nearest token, ink/500, fails contrast on the gray price box.

Case study 07 / 08
Design tool plugin

Swatchbook

An open-source design tool plugin that finds near-miss colors in a file and swaps each one for the nearest token that still passes contrast.

Client
Open source, sponsored by Halyard
Year
2024
Role
Designer and maintainer
Team
  • Ines Okafor, plugin engineering
  • Ravi Menon, color science (contributor)
  • Joon Park, accessibility testing (contributor)

The problem

Design files drift. When Halyard audited the booking file of a client, a slip-rental company called Moorage, it found 212 unique hex values against a library of 38 tokens. Most of the extras were near misses nobody could see, like #6E7A87 standing in for #66727F, but 41 text layers failed contrast, and cleaning the file up by hand took a designer three days.

Decisions

  1. 01

    Audit by distance, not exact match

    An exact-match search calls #18242F and #14202B different colors, which is true and useless. Swatchbook converts every fill and stroke to CIELAB, measures ΔE2000 to each token, and groups strays into clusters around the nearest one, so 174 strays read as 31 decisions.

  2. 02

    Suggest the nearest token that passes where the layer sits

    Gray fee labels were closest to ink/500, which passes on white but reaches only 4.36:1 on the gray price box. Swatchbook measures contrast against the fill actually beneath each layer and steps along the same ramp until it passes. My first version searched every token and offered a blue for gray text, so staying in the ramp became the rule.

  3. 03

    One click to replace, one row to undo

    Replacing is a single button, so every swap is written to a Changelog page in the file: layer, before and after, ΔE, contrast, and who ran it. Anyone can revert a row weeks later, which is what made design leads comfortable running it on shared files.

Outcome

Swatchbook has 11,400 installs. An average audit replaces 86% of strays automatically, and Moorage’s booking file went from 212 colors to 41 in an afternoon: 38 tokens plus three illustration colors kept on purpose.

The brief

Halyard, a design-systems consultancy, kept running the same cleanup for clients: export every color in a file, sort the hexes in a spreadsheet, then fix them layer by layer. They sponsored me to turn that routine into a free, open-source plugin that teams could run on their own files.

The constraint was trust. A plugin that quietly rewrites colors across a shared file gets uninstalled after one bad afternoon. So the design had three jobs: show how far each color has drifted, pick a replacement a designer would agree with, and make every change easy to see and undo.

A vector editor with two Moorage frames on the canvas and the Swatchbook audit panel open: 212 colors in use, 38 matching a token, 174 strays, mostly under ΔE 2.
Most strays sit under ΔE 2, which is why nobody had noticed them. The 41 contrast failures are the ones that matter.
The Clusters tab: strays grouped under ink/500, kelp/600, and coral/600, each with a count of layers, a ΔE range, and how many fail AA.The Fix tab with the cancellation note selected: its stray green fails at 3.93:1, and kelp/600 is suggested at 4.56:1.
Clusters turn 174 strays into 31 decisions. The fix panel always shows the nearest token, even when it fails, so a suggestion is never a mystery.

Live demo

Fix the strays on a checkout card

Pick a stray, check the suggested token and its contrast, then Replace. Undo puts the old color back.

Contrast is measured against the fill under each layer: the same gray that passes on the white card fails on the price box.

Why the nearest color was wrong

Fixing every stray to its nearest token would have repaired only half of the 41 failing text layers, because the nearest token often failed too. Designers had eyeballed a lighter gray on a gray background, and the token they were reaching for was built for white.

The ramp rule accepts a bigger visual jump, ΔE 18.4 for the fee labels, to get text people can read. The panel lists the nearest token anyway, marked Fail, so the jump is a visible decision rather than a surprise.

The same card after cleanup: nine colors, all tokens, every text layer passing AA.
The checkout card before cleanup, with six numbered strays: 13 colors on the frame, two of them failing contrast.
Before: 13 colorsAfter: 9 tokens
Drag to compare. Most swaps are invisible; the fee labels get darker on purpose.

We had been calling it the gray problem for a year. Swatchbook showed us it was nineteen grays, six of them failing on our own price boxes, and we cleaned up the whole booking file before dinner.”

Dana Whitlock — Design lead, Moorage
The Swatchbook changelog page inside the file: a table of replacements with layer, before and after colors, ΔE, contrast before and after, and one reverted row.
The Changelog page lives in the file, so the history travels with it, even to people who never install the plugin.
Settings: tokens come from the Moorage Core and Extended libraries, matching uses ΔE2000 up to 10, contrast target AA, and illustration layers are skipped.The audit report: 212 colors down to 41, with 150 replaced automatically, 21 by hand, 3 kept as exceptions, and no text failing AA.
Token source is set per file. Exceptions are kept deliberately and listed in the report, not hidden.

Results

Installs
11,400
free and open source
Strays replaced
86%
in an average audit, automatically
Colors in Moorage’s file
212 → 41
in one afternoon

What I would do next

Swatchbook only trusts solid fills. Gradients and text over photos are flagged for a person, which is honest but slow: in Moorage’s file they were 9 of the 24 decisions left after the automatic pass. The next version samples the pixels under text on images and suggests a scrim token when no text color can pass.