Why Gradie's colour switcher does two things at once (and why that's not a bug)

Hey. I’m Emmanuel. I built a little app. Nothing super complex. It does one thing and it does it well (if I do say so myself). It’s called Gradie. Upload an image, and Gradie will get the five most prominent colours from that image and use them to create a bunch of custom gradients. Sounds great, yeah?

This is me doing promo, I guess? Before this, I posted three demo videos on Twitter, BlueSky, and, of course, LinkedIn. Well, I don’t have any videos today, so here’s an article instead. My first in years!

So let’s talk about one very specific design decision I made while building Gradie. And why, even though it might seem a little off at first glance, I’m sticking by it.

Before I started building Gradie, here’s the only type of gradient I knew about:

.gradie-theme {
    background: linear-gradient(180deg, #eeedea, #ee6495);
}

I knew nothing about conic, radial, the repeating-* variants, colour interpolation, etc.

So yeah, I was wearing a big cap with “Noob” on it in block letters. But why am I talking about all this so much?

When I had the idea for Gradie, it was meant to be very simple:

  1. Upload image

  2. Grab colours

  3. Generate gradient

  4. Export

  5. ???

  6. Profit.

There wasn’t meant to be any fancy colour switcher or customisation options.

So what changed? I read an article from the folks over at Evil Martians explaining why OKLCH was the best thing since sliced bread.

After having my eyes opened, I just had to have my gradient tool use OKLCH. I originally planned for Gradie’s gradients to be OKLCH-only, but I hated that idea. I’m a fan of customisation, as someone who uses software and someone who makes it.

Back when I was working on AspectMatic v3, I was so annoyed by how the plugin worked that I planned on rewriting the entire thing. You know that feeling when you look at old code (your old code!) and go “ewww, who wrote this?” Then you check git blame and realise it was you. Yeah.

Before v3, it only returned aspect ratios as decimals, so 4:3 became 1.3333... But it had users anyway, so why remove something people use just because I didn't like it?

If you haven’t heard of AspectMatic, it’s a Figma plugin (later ported to Penpot) for calculating aspect ratios, made by yours truly.

I knew I’d need a colour switcher, meaning I’d have to use a colour library to handle colour conversion, because I was not going to manually write the code for that. Not out of laziness, but because this was a feature I didn’t plan for, and I was already dealing with a lot of new stuff.

Choosing a colour library was way more stressful than it should have been, but after many (so many) refactors, I finally settled on colorjs.io. It was the easiest to set up and supported all the major web colour formats.

Of course, the only reward for hard work is more hard work. After I added the colour switcher, I found out about interpolation colour spaces — basically, the method the browser uses to blend colours in a gradient.

Here's what I mean. The same two colours can look completely different depending on how they're blended:

/* Interpolating in sRGB (default) */
.gradient-srgb {
    background: linear-gradient(90deg, #44b, #dcdc3a);
}

/* Interpolating in OKLCH */
.gradient-oklch {
    background: linear-gradient(90deg in oklch, #44b, #dcdc3a)
}

Interpolating in sRGB

gradient-srgb

Interpolating in OKLCH

gradient-oklch

Completely different gradients from the exact same input colours.

And like that, a new question pops up: “From the user’s perspective, what does the colour switcher control? When they switch from RGB to OKLCH, what are they switching?”

The colour format?

The interpolation method?

Well, it’s both.

When you pick a colour format in Gradie, you're picking both how the colours are written and what interpolation space is used to blend them. I could have made separate controls, but this wasn’t a feature I planned for, and I was trying to avoid (even more) feature creep.

Thankfully, except for RGB and HEX (which are usually both represented by sRGB), the formats I chose in Gradie matched up cleanly with an available interpolation space, like OKLCH or LAB.

So when you select a format, let’s say OKLCH, Gradie sets both the colour format (how it’s written) and the interpolation space (how it blends) to OKLCH.

Technically, the CSS spec lets you mix and match. You can write a gradient in HEX and still interpolate it in LCH. But I don’t support that in Gradie. And honestly? I’m glad. If I did, I’d probably still be refactoring.

Sometimes you stumble into decent design decisions while just trying not to break everything.

One control to rule them all. This is the way.

Thank you for coming to my TED Talk.

Fin.

PS: I’d love corrections, whether grammatical or technical.

Fun fact: I had to rewrite parts of this multiple times because I kept on confusing colour spaces with colour interpolation method spaces.

0
Subscribe to my newsletter

Read articles from Emmanuel C. Jemeni directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Emmanuel C. Jemeni
Emmanuel C. Jemeni

Front-end Web Developer • A parselmouth in my spare time • Always coding in Py & Js • Currently learning NextJS