Jan 2020: Palette Swaps, Modernized

This post builds on the ideas from our October 2019 article on linear algebra and sprite coloring. If you haven’t read it yet, I’d recommend reading up until the “recipe book” section of that article.

Late in the development process — around the seventh inning, so to speak — Susan and I made the decision to revise the game’s sprites. All of them, nearly. Hundreds of sprites, altogether. It’s not a decision we could have made had we not had a few tricks up our sleeve, and today I’m going to talk about one of those tricks.

The Challenge at Hand

There were two main issues we were trying to address by switching up the art style. First, we had decided to switch out our lineless vector style for something inspired by comic book inking techniques — but this decision is part of a separate story I’ll save for another day.

The second bundle of issues, the one we’re talking about today, had to do with our color palettes. Each of our twenty-odd enemy ship designs had between one and five different color variants for each of four different planets, and they weren’t perfect:

  • Over years of development, some color palettes had drifted and were not very consistent between different ships using the same scheme; some older experimental palettes lingered in later builds, and it was the kind of thing we were going to need to sort out at some point

  • Some other color schemes were not terribly high-contrast, particularly for users with color vision deficiencies, and the only way to tweak those schemes was to change colors in a couple dozen individual illustrator files. We were in need of a way to make high-level adjustments across an entire planet’s enemy sprites.

Turning to History

My first though was about how much easier these color issues would be, were we living in the era of 8-bit paletted sprites.

For those of you whippersnappers encroaching upon my lawn who don’t remember these early days, back when we had eight bits or less to store each pixel’s data, it was customary to give each pixel a number, and send along with that image a palette — a decoder key telling which numbers meant which colors. And the really slick thing? You could easily get dozens of different variations of your original sprite just by pairing it with different palettes, no need to re-create the image with a new color scheme. It’s a bit like typing “The quick brown fox jumps over the lazy dog” once and being able to see it in a hundred different fonts without re-typing it. It’s a technique many of you might know from pixel JRPGs, where you knew things had gotten serious because the enemies in the area had suddenly turned from green to red to blue, and in early versus fighting games, where a palette swap was applied to one player’s fighter when both players chose the same character.

 
 

But perhaps the best illustration, for our purposes, goes all the way back to 1985’s Super Mario Bros. Go from an above-ground to underground level? The ground changes color; the bricks and goombas follow suit. This is exactly the sort of thing we want to emulate… but how can we reconstruct this using modern 24-bit artwork, without doing it all by hand?

Finding a modern equivalent

The answer we settled on? Creating artwork in a neutral color space, and then using linear algebra to apply our color schemes.

Even though convention might say the three channels are green, red, and blue, we’re reinterpreting those channels to mean base color, first accent color, and second accent color, essentially stretching and squashing the color cube to suit our own purposes with a matrix multiplication.

For the first step, Susan prepares some artwork using neutral grays as the base color, reds as the first accent color, and blues as the second accent color.
(We use grays instead of greens at this step since that’s a more visually neutral color, and it’s just a simple channel mix to swap the grays out for greens during pre-processing)

Meanwhile, Cathy is sampling some reference artwork, dropping numbers into spreadsheets, and calculating what matrices we’ll need for

For our simpler sprites, a single 4x4 matrix transformation will take care of everything we need to generate a whole bunch of variants…

For those more complicated sprites that have richer shading in the accent colors, we keep the artwork split into layers and apply a different matrix to each layer before flattening into the final sprite.

(NB: While this added layer of complexity essentially precludes the ability to change palettes in realtime with a shader, it does still allow us to automate the art creation process.)


Catherine Kimport