undefined

If you ever tried to mix colours in your code, and you are used to work with RGB hex, you might think that what you learned as a kid applies to mixing colours digitally as well.

At least I did.

I thought that mixing RGB blue (#0000ff) and yellow (#ffff00) would give me green (#00ff00), which is totally wrong. I learned pretty quickly that my digital world used additive colouring, which is quite different from what we are used to in our real life (subtractive colouring, more here).

Simply put, it has to do how the light reflect on a surface, in contrast to how light is emitted from a device.

People expect the intuitive

So why bother? Well, if you tell someone that you can mix colours on your webpage, they will expect blue and yellow to mix into green. Telling them that blue and yellow becomes #808080 (greyish, which is what you will get if you mix it with the RGB model) will just get you frustrated users.

In order to give them what they expect, you need to use another color model, and in the case of real world subtractive colouring, the model is called RYB (red, yellow, blue, i.e. the base colours, read more on wikipedia).

To make sure that your results are as expected, the best way to mix colours is to start with RYB and mix as RYB, and then convert your colours to RGB when you need to use them on your screen. You can convert RGB to RYB, mix and then convert them back, but since each conversion is an approximation, you won't get the perfect results that you would expect.

Mixing

Lets begin with mixing yellow and blue to get green.

First we have yellow, which in RYB is 0, 255, 0. Since we all are used to use hex, we can represent it as

#00ff00

Then we have blue, which is 0, 0, 255. And in hex:

#0000ff

The hex representation of green is quite simple:

#00ffff

Its simply full yellow and full blue together. In the same fashion, you can represent orange by full red and full yellow:

#ff0000 + #00ff00 = #ffff00
red       yellow    orange

So how do we mix them together? We just add each color part to the other, but remember what the max of each sum is and use it to calculate how much each addition is a percentage of the total.

In our blue + yellow case its something like this:

var yellow = [0, 255, 0];
var blue = [0, 0, 255];

var rSum = yellow[0] + blue[0]; // 0
var ySum = yellow[1] + blue[1]; // 255
var bSum = yellow[2] + blue[2]; // 255

var max = Math.max(rSum, ySum, bSum); // 255

// our new color
var green = [
    Math.floor(rSum / max) * 255, // 0 / 255 * 255 = 0 
    Math.floor(ySum / max) * 255, // 255 / 255 * 255 = 255 
    Math.floor(bSum / max) * 255  // 255 / 255 * 255 = 255 
];

console.log(green); // [0, 255, 255]

It might seem more complicated that it is, but whats more interesting is that you can use this method to mix more colours than just two.

The tricky part is to convert your RYB color to RGB, which is much more difficult. Luckily, some smart people created a formula and then others took it to javascript, which means we can use it pretty easily. You can see the code here: https://github.com/bahamas10/node-ryb2rgb. All the code above, including the conversion part is part of a small module I've created. Just read on.

All together

If you just want to mix, I've put together a small library that takes a two colours or more and mixes them for your. The result is returned as either RYB or RGB.

You basically use it like this (the default return is RYB hex):

var green = rybColorMixer.mix("#00ff00", "#0000ff");

or

var green = rybColorMixer.mix(["#00ff00", "#0000ff"]);

or

var green = rybColorMixer.mix([0, 255, 0], [0, 0, 255]);

or in RGB

var green = rybColorMixer.mix("#00ff00", "#0000ff", { result: "rgb" } );

or in RGB array

var green = rybColorMixer.mix("#00ff00", "#0000ff", { result: "rgb", hex: false } );

Examples

Here is a complete palette rendered from just the base colours red, yellow and blue:

More about ryb-color-mixer

If you want to know what more you can do with the mixer, just head over to github.