Cytopia
0.3
A city building simulation game

A magic pixel is a pixel which has the same RED and BLUE values. This includes black, white, grays, purples, and greens. From this criteria, there are \(255 \times 255 \times 255 = 16581375\) possible magic pixels that you can use (Pick a green, pick an alpha, and pick a redblue). Magic pixels are less than 0.4% of all the possible pixel colors you can use.
When a sprite has magic pixels and is being tagged as recolorable, Cytopia will be allowed to recolor those pixels at runtime. This can be done randomly, or specifically depending on for what your asset is being used. Randomly refers to picking a random color and recoloring all magic pixels with it, while specifically refers to using a specific color.
Recoloring is done in the following manner: Given a sprite of RGBA pixels, and a target RGBA color, we find all pixels that are "magic" according to the Magic Pixel Criteria. For each of these magic pixels, we apply the following filter
\begin{align*} H_o &= H_t\\ S_o &= \mathrm{overlay}(S_i, S_t)\\ L_o &= \mathrm{overlay}(L_i, L_t)\\ \end{align*}
Where \(H_o, S_o, L_o\) are the resulting hue, saturation, and lightness, \(H_i, S_i, L_i\) are the magic pixel's hue, saturation, and lightness, \(H_t, S_t, L_t\) are the target's hue, saturation, and lightness, and we define
\begin{align*} \mathrm{overlay}(X, Y) &= \begin{cases} \frac{2}{100}XY & \mathrm{if } X < 50\\ 100  \frac{2}{100}(100X)(100Y) & \mathrm{otherwise} \end{cases} \end{align*}
With RGB, we derive the following. Given \(X_{min}=\min\{R_o,G_o,B_o\}\) and \(X_{max}=\max\{R_o,G_o,B_o\}\), we have that
\begin{align*} L_o &= \mathrm{mid}\{R_o,G_o,B_o\} = \mathrm{overlay}\left(\mathrm{mid}\{R_i, G_i, B_i\}, \mathrm{mid}\{R_t,G_t,B_t\}\right)\\ X_{max} + X_{min} &= 2L_o & (1)\\ S_o &= \frac{X_{max}X_{min}}{\min\{L_o, 1L_o\}} = \mathrm{overlay}\left( \frac{\max\{R_i,G_i,B_i\}  \min\{R_i,G_i,B_i\}}{\min\{\mathrm{mid}\{R_i,G_i,B_i\}, 1\mathrm{mid}\{R_i,G_i,B_i\}\}}, \frac{\max\{R_t,G_t,B_t\}  \min\{R_t,G_t,B_t\}}{\min\{\mathrm{mid}\{R_t,G_t,B_t\}, 1\mathrm{mid}\{R_t,G_t,B_t\}\}}, \right)\\ X_{max}X_{min} &=S_o\min\{L_o, 1L_o\} & (2)\\ \end{align*}
From Eqn (1), you can see that \(L_o=0\implies X_{max}=X_{min}=0\), hence if there is no lightness, we always return black. From Eqn (2), you can see that \(S_o=0\implies X_{max}=X_{min}=L_o\), hence if there is no saturation, we always return a grayscale color. Note that if any denominator in the \(S_o\) equation is 0, then \(S_o=0\) to prevent dividing by 0. Finally for hue, there are many ways to convert it back to RGB.