Layering Sprite Data
If you’re familiar with my posts then you’ve probably picked up that I enjoy getting the most out of PICO-8 and something that’s hindered my development in the past was sprite space. Today I’ll beat that issue into submission.
I’ve decided I wanted to design a custom font setup for a project I plan on working on (more on that later), but this takes up quite a bit of sprite space. 44 in total. Since PICO-8 only gives you 256 sprites, this is quite a hefty chunk. Even after doing my best to rearrange the sprites, removing transparent chunks and pairing sprites with those that can share a border, it still takes up 37 sprites.
Okay, well the good news is, I’ve got more tricks up my sleeve. As you can see these sprites use 4 colors. Trasnparency, border, shadow, and main. PICO-8 supports 16 colors. Let’s do some binary wizardry.
Each pixel in the spritesheet can represent 4 bits, but for our usage, the only data that’s really needed is 2 bits (since we’re using 4 colors, 00,01,10,11). This means we can layer these sprites on top of each other.
00 = transparent
01 = outline
10 = shadow
11 = main
So let’s say our first pixel on layer 1 will be an outline pixel, and the second layer would be transparent. This means we’d use the color 0100, which is 4 (brown). If that doesn’t work, check out this grid.
tran outl shad main
tran 0000 0001 0010 0011
outl 0100 0101 0110 0111
shad 1000 1001 1010 1011
main 1100 1101 1101 1111Alright cool. So let’s apply that to these sprites. First, let’s make the sprites actually match the right bits, so we’re gonna set the transparency color to 0, outline to 1, shadow to 2, and main to 3.

Awesome. Now let’s try layering those two top rows.
-- clear the screen, so nothing previously ran screws this up
cls()
for x = 0, 127 do
for y = 8, 15 do
-- get the pixels at the bottom layer (0-15)
bottom_color = sget(x,y-8)
-- get the pixels at the top layer (16,31)
top_color = sget(x,y)
-- add them together, shifting the bottom layer two bits over
total_color = top_color + shl(bottom_color,2)
-- set the pixel on the screen to display it.
pset(x,y-8,total_color)
-- set the sprite pixel on the next page the combined layer.
sset(x,y+24,total_color)
end
end
-- save the new spritesheet to rom.
cstore(0,0,0x2000)
-- pause the program until exit.
function _update() endHere’s some simple code, that accesses the sprite data using PICO-8′S sget and sset functions, cstore then saves it to the actual cart. Here’s what that looks like on the spritesheet now!
At first glance this looks like jumbled insanity. On closer inspection however… no yeah that’s basically what it is. Data’s not always pretty folks. I’ve still got to do the same thing for the third smaller row, so I did the same code, but adjusted the values so to not overwrite the first couple of rows.

Alright. compressed this text into using only 18 sprites! Remember that we started with 44! So, how do we render this out?
function set_layer(top, colors)
pal()
for i=0, 15 do
local id = (top and i % 4 or flr(i / 4))
if id == 0 then
palt(i,true)
else
pal(i, colors[id])
end
end
end
local layer = false
function _update()
-- toggle layer on button press
if btnp(4) then
layer = not layer
end
end
function _draw()
cls()
pal()
print('layer: '..(layer and 2 or 1),0,24)
-- set_layer takes a boolean as which layer to set
-- and a table for outline, shadow, and main
set_layer(layer,{0,13,6})
-- draw the whole chunk of layered sprites
sspr(0,32,128,16,0,0)
endSo, our next issue is rendering individual characters. But I’ll leave that for a different post as this has gone on long enough! I hope you enjoyed this little endeavor.

