The broken palette swapping of "It's The Leash I Could Do"

While working on our game (https://ldjam.com/events/ludum-dare/47/its-the-leash-i-could-do) one of the features we really wanted to make sure to include was some character diversity. Since our game is about helping people find relationships (however abstractly), we had two core concepts we wanted to make sure we included in the game: 1) Same-gender pairings 2) Multiple represented ethnicities
The first was really easy. Our artist (Andrew) made a sprite for both a female and male-appearing character and we simply spawned & matched the characters at complete random.
The second was more involved - it'd involve either a lot of sprite tinting and copying, or some clever palette swapping tech.
As an engineer/programmer (and someone who works on mobile titles for a day job), the answer was obvious here: Have the artist make one sprite, and palette swap it.
If you're unfamiliar with the term, palette swapping is conceptually relatively simple: every pixel of a certain color in the source art becomes replaced with a different color based on the new palette.
There's a couple different ways you can perform this swapping, but for various reasons, I decided to try to accomplish it in a shader. I settled on a paradigm: Since every pixel in an RGBA32 texture is 4 bytes, each color channel is represented as a value from [0-255]. I'd take the value of one of these color channels (specifically the 'red' channel), and index into a long thin texture 256 pixels wide. Whatever color I found at the index would be the replacement.
And it worked great - here's an early test case of me swapping two of the greens of our tree sprite (one of the first that was ready) with some yellow and red (forgive my color choices, I am not an artist):

I went ahead and attached this to our npcs, and set up a whole bunch of code to dynamically mix different color 'sets' (for example: a clothing set, a skin tone set, and a hair color set) to generate a combined palette texture programatically. Here's an example of our interface for swapping these:

And it worked (but, sadly, I have no screenshots of this brief golden era). And then I implemented our NPCs animations - really, just a simple sprite swap every .1 seconds. And then I went to bed.
And I woke up the next day to reports that the palette swapping was... sorta broken.
Animation was causing artifacting, and certain colors were just never swapping. The problematic colors included skin tone... which was most of the point of the feature.
Zooming in also showed color bleeding, which totally shouldn't happen with point filtered textures - left is the swapped character, right is the unswapped character. Notice the strange 'outlines' on some of the pixels.
Here's a shot from when I briefly had the skin tone swaps fixed again, showing the color bleeding issue - note both characters are using my palette swapped shader, but the right one has a 'blank' palette swap applied (i.e, it just renders the original image):

So I spent a few hours debugging this, and couldn't actually isolate the issue. Instead, the longer I debugged it, the less reasoanble the issue seemed to be - pieces of the problem seemed to start and stop occuring with no rhyme or reason. I knew it was tied to the larger texture sheets we were using, and I suspect interpolation is problematic somehow, but nothing I tried seemed to fix it. Normally I'd give myself a day or two to 'reset' on a problem like this and come at it from a fresh angle, but... no time to do that in a jam.
So our team talked about what to do, and decided to just live with the current state of the art when we went live. So that's the story of how palette swapping totally doesn't work in our game, despite me wasting ~8 hours on it.
The cheerful upside is that in the week since, I rewrote how I handled all of it. I built a few components that generate a mesh from an input sprite, and assign it vertex colors - these are working great, and I look forward to using that approach next time.
