It began with the dream of a dynamic theme. Given a base color, I could construct glorious palettes of varying types and for different purposes.
I shared the initial results in a blog post from 2023, Automatic Color Theming. By modifying HSL values, I could programmatically generate palettes. So, I can find the complement to red hsl(0 100 50)
by adding 180 to the hue, that is, moving halfway around the color wheel to cyan hsl(180 100 50)
.
But I was immediately dissatisfied with the result.
The palettes were often gross, with luminosity all over the place, clashing colors, and garish combinations. Worst of all, they didn't apply that well to UIs, which was what I really wanted with dynamic theming.
That set off a deep dive into color theory, reading various articles and books like Josef Albers' Interaction of Color (1963), understanding color space better, all of which coincided with an explosion of new color methods and technical support on the web.

These frustrations and browser improvements culminated in a realization and an app.
The realization? Programmatic color palettes (dynamic theming) are nearly impossible, both in generation and in application. Nothing beats the practice of a good eye and keen sensibility.
Some systems are better than others
Nevertheless, I wanted to see how far I could get, so (like so many others) I created ColorPalette Pro. They generated palettes aren't all bangers, but it does generate pretty good palettes, while solving some of my major frustrations with existing tools with a synthesizer-like interface.
Here are my gripes with other palette generators:
- Shitty palettes
- Can't (or tedious) to provide a base color
- Limited export options
- Difficult to use with too many options
- Not applicable to UIs
- Not synthesizer shaped
But enough with the carping. Let's see how the ColorPalette Pro works, and you can judge for yourself.
Let's Create a Palette
To start: Give me a color, any color.
How about ◉ Thuja Green ? (Click on the link to open the color in the synth!)
We plug this into the ColorPalette Pro and—voila—color info and programmatic palettes.
The synthesizer generates 6 programmatic palettes comprising the base color and 5-11 others.
Analogous (ANA) ◉◉◉◉◉◉
Colors adjacent on the color wheel. Importantly, palette types are abbreviated with 3 letters, not 4.
Complementary (COM) ◉◉◉◉◉◉
Colors opposed on the color wheel.
Split Complementary (SPL) ◉◉◉◉◉◉
Colors opposed then bifurcated on the color wheel.
Triadic (TRI) ◉◉◉◉◉◉
Colors arranged on the color wheel in a triangle.
Tetradic (TET) ◉◉◉◉◉◉
Colors arranged on the color wheel in a square.
Tints & Shades (TAS) ◉◉◉◉◉◉◉◉◉◉◉◉
The base color, mixed with white and black, to create 12 swatches of increasing lightness.
Variations
For each palette, I also include 4 variations that algorithmically modulate the colors. These modulations include changes to lightness, chroma, and hue—and can be somewhat generalized as follows:
- Square: Raw mathematical relationships with few perceptual adjustments
- Triangle: Compensates for how your eye perceives color changes (e.g., Bezold-Brücke effect).
- Circle: Creates smooth color progressions by blending toward white/black
- Diamond: Creates tonal variations by blending toward neutral gray
🎛️ Use the knobs to manipulate the palettes more.
Inputs
I count 6 ways to get a color into the synthesizer.
Text Input
You can enter a color in nearly any format (OKLCH, hex, RGB, name) into the text field and click "Play" to parse the color and generate palettes. If the color can't be parsed, you'll see an error message in the bottom-right info display.
Hint: If a color isn't parsing, look how other colors are formatted and enter it like that. You can enter any format in any space. If OKLCH is active, for example, you can still paste in a hex code and have it parse correctly.
Sliders
You can manipulate a color using the sliders (or input values directly or click them up/down). What's cool here is that the sliders change depending on your color space: lightness, chroma, and hue for LCH, but lightness, A (green/red), and B (blue/yellow) for LAB.
Eyedropper
Use the eyedropper to pick any color on your display. It'll be captured as a hex value. Note that if you don't see the eyedropper, then your particular browser doesn't support it. (It's not supported in Firefox or mobile browsers ☹️)
History
Click the rewind button to show all your previous colors (up to 240). Click any of them to return to that color.
Tip: Right-click a color to delete it from your history.
Random
Click the twisted, intersected arrows (🔀) to pick a random, curated color. (So, you don't even really need a color to get started.)
URL
Every color change (along with most other options) is preserved in the URL. You can click the link button to copy the URL to share your selected color and fave palette with anyone (or save it yourself for later).
Output
Aside from the URL, there are 3 other ways to get palettes out of the synth. Two are simple to explain: copy the CSS palette values or download a CSS file. The CSS file uses variables (custom property) names and includes the contrast color (white/black).
The last export option is pretty neat. Generate an image of your palette, making it easy to use in design tools or to save for later. Here's our beloved Thuja Green in the split complementary palette called Darkness Purple:

Other Cool Shit
The info button reveals palette color values and names. You can click on every color value, and it'll be copied to you clipboard. This holds generally, across the app.
The app window button enables UI mode, which generates a color palette suitable for UIs that incorporates your base color and palette type. What's really cool is that when dark mode's enabled, this creates a dark mode palette and vice versa.
The palette syntax follows familiar patterns , where surface colors are meant for backgrounds and containers and "on-surface" colors are meant for elements that—yep—go on surfaces (like text or icons).


Once you generate a palette image, you can drag it into Figma and use the eyedropper there to add colors to your design.
Thuja Green by Any Other Name Wouldn’t Look as Good
Each color and palette gets a name. This is done by a call to an API I wrote in Go, which is a fork of this amazing Color Name API. They did the hard work of compiling the names. The API receives a hex version of the colors and finds the nearest match. Color names are combined to make the palette name.
What's Next?
Again, the best palettes will always be those created by someone with a good eye. ColorPalette Pro is like a good recipe: It gives you a great place starting point but doesn't guarantee perfect results. You might need to adjust the seasoning to taste
I'd be remiss, too, if I didn't mention the library that makes all the color science possible. Color.js is a fantastic TS library built by Lea Verou and Chris Lilley, who are co-editors of the CSS color spec; i.e., they know their shit.
I'm calling this version of the ColorPalette Pro done. While I could finesse the algorithms, fix broken layouts, and fiddle, I'm excited to get on to my next project.
That also means I have no plans to monetize via ads or subscriptions or other annoying shit. It's just something weird I made that's out there.
What's next, then, is for you to try it out. Share your palette in the comments, let me know if it's fantastic, shit, or fantastically shit.