Creating a systematic color palette
From random hex choices to systematic colors in product design

Recently, I was tasked with creating a cohesive color system for the product design team as part of the broader Design System. This was done to reduce redundancy in production variables and to enhance consistency across modules spreading across multiple business units and product lines.
What type of redundancy, you might ask?
- Identical hex codes assigned to different variable names, e.g., blue100 and bluee100 both referred to the same hex code.
- Visually similar colors having different hex codes. For instance, #000000 and #010101, while visually similar and nearly indistinguishable, were both present in the production codebase for same dark shade.
Here’s the approach I took to create a scalable color system.
Understanding what’s going on
First, design.
The existing color system was constrained and lacked flexibility, having no clear guidelines. This allowed designers to opt for any color they deemed visually appealing for the UI they were addressing. The same values were then translated to UI dev team, increasing the redundancy at its peak.

Second, production codebase
After several requests and emails, I finally secured access to the codebase. (I don’t understand why some teams maintain such barriers with cross-functional teams).
What I discovered was quite unsettling. The front-end development team was using two variable files in different languages (clearly a migration attempt that fell short), teeming with redundant values. Additionally, there were pages with colors hardcoded right into them.
My initial step was to gather all the colors, their key names, key values (be it hex code or rgba), and their paths. I then transformed their names and values into a JSON format, readying them for import into Figma.

I discovered a total of 339 colors in the production code. While some were redundant, as previously mentioned, others seemed out of place, being used in production without any logical reason or any design decision. On the design side, 22 colors were defined as styles. However, designers were also incorporating colors outside this system in individual files. Conversations with both the design and development teams revealed that the limited palette was not catering to all the designs, indicating a need for a thorough and logical revamp.
Finding ways 🛣️
Option 1: We thought about creating a new color system. We’d link these primitive colors to variables/tokens, define usage guidelines, and then have the developers implement it.
However, given the scale we were aiming for, this would likely require more than a quarter’s worth of dedicated resources for design, development and testing — a luxury we didn’t have. We planned to take this route later, but first, we needed to tidy up our color palette and align it with a singular brand-focused color scheme.
Option 2: Given our existing use of variables, our immediate goal was to establish a foundational layer in middle of the system to minimize color dependencies. We aimed to trim down more than 250 colors we had. One limitation of this method was the garbage work of creating and implementing a map of existing variables to this foundation layer (Color Primitives).
Despite its constraints, Option 2 emerged as the most viable immediate solution. It allowed us to globally streamline our color usage while maintaining the flexibility to adjust colors during component implementation. After all, as we updated each component, their respective tokens would naturally be revised.
Crafting palette for design team
Defining the core brand colors
Working closely with the creative design team, we settled on using 6 core colors for our system:
- Brand Primary
- Secondary
- 3 Accents (Traffic light colors) and
- Neutral
Using these 6 core colors and considering our product’s usage patterns, I crafted a detailed palette and used Figma’s variables to create a primitive library (only to be edited by the design systems team). This palette, comprised of shades and tints, and was designed to cater to a wide range of use cases.
I also added variables for Transparent neutrals (with spatial scale of 8 ➝ 96 for alpha value), with a scope of adding alpha values to other colors with the similar pattern.
Once we integrated the Primitive layer into our system, we established a request and approval workflow for adding new colors. This ensured that any new colors would only be introduced into the system after passing through this defined process.

But wth is Primitive here?
In our context, a “Primitive” referred to design decisions with a direct, unaltered value, whether that was in decimal or hex format. If it was a raw numerical value, it was labeled as a primitive. Conversely, if something pointed to another variable, we categorized it as a token.
For instance, colors with hex codes possess raw hexadecimal values. Aspects like type scale, spatial scale, and micro-interaction transitions have clear decimal values. Conversely, properties like border-radius might reference a value from the spatial scale, without any specific hardcoded value.
Defining tokens
While our initial focus wasn’t set on integrating tokens directly into the product, they played a pivotal role in getting the team on board with the color system. They were a bridge to help understand that in design layouts, we wouldn’t apply primitives outright but would instead utilize these tokens for specific purposes.
To illustrate, both a brand-primary-dark color and a text-default might share the same value as, let’s say, gray.900.
This method provided a controlled environment, preventing designers from straying from the established palette. Leveraging Figma’s then-newly introduced color scoping further simplified the process for designers, minimizing exposure to redundant color tokens.

Solution for the existing variables and random hex codes 🛠️
As said earlier, I had to do the garbage work of creating a map of these primitives to be used as values for the current variable till we would have implemented the tokenized format for each component for a quick fix.
Manually squinting at the screen to map out the primitives for all 339+ colors was no easy feat. While some colors were straightforward, others required careful attention, especially those that were not part of the older design color system but had found their way into various production pages.
What did I do next?
I scoured the internet and consulted several design systems experts but couldn’t find a satisfactory answer. However, I did stumble upon a library by Markus Ekholm and Daniel Tao on GitHub. It featured a color difference algorithm, which I leveraged to create a basic local HTML and CSS version of “Nearest Color Finder.”
Using this tool, I could match any random hex code with our predefined primitive colors. I faced few problems in start with the color not matching as I wanted, though updating few lines of code helped me to achieve the optimal result.

This tool was a game-changer for me; it expedited the mapping process and effortlessly answered the question: “Which color from my color system does this match closely?”
And that’s when it struck me — why should I be the only one benefiting from this incredible tool? I decided to develop a Figma plugin that would enable any designer or design team worldwide to effortlessly access automatic color matching without the time-consuming manual effort.
Nearest Color Finder Figma Plugin was born

Nearest Color Finder lets you pick any color — be it from an image, a screenshot, or just a random hex a designer or developer might have used. It then scans through your styles and variables to match with the nearest matching token.
How to use? I’ve a written a dedicated guide for it ➝ Read here.
All this is good, but how does it help?

With the help of using primitives alone, we reduced the number of differentiated redundant colors to 64 from 339, which helped us to increase consistency across the product modules, increasing efficiency in design language and translation between cross functional teams, and reducing errors in front-end cycle and visual QA for consistency check, which ultimately reduced the cost.
Was it enough? No, not at all. Tokens are great and has to be implemented, but this was a foundational step towards reducing the chaotic clutter we had with colors further giving us scope to improve components and pages.
Implementation on development
To reduce the debt and clutter on production, we decided to inject one more file in the codebase for primitives and convert the existing variable files as tokenized files for modular scalability. The plan was to first map the existing variables with primitives, and later updating the variables with new tokens as specified by design system team while improving each component.
And that’s it, read my other articles on designing data visualization cards, web and mobile artboard guide, breakpoints, and CSS units designers should know at appy013.medium.com / Arpit Gupta
If you liked my article, connect with me on LinkedIn and say “Hi 👋”.
Subscribe to my Medium reads and support my content by pressing 👏.

You can write to me directly at hi@appy013.design or find me on 𝕏 (Twitter)→ x.com/appy_013 or Google me @appy013