Log In  

The first paragraphs are just some opening thoughts to contextualize where I'm coming from with this idea. If you are not interested in that, skip to [Suggestion].


When the 2nd palette was first discovered, increasing the total number of colors on the screen has been suggested a number of times. That in itself is a pretty weak idea: bumping up pico-8's limitations is against its whole purpose of self-imposed limitations. If you want more colors, just use any other platform. End of story.

But recently, with the 0.2.0x versions, a lot of new features have been added that expand what pico-8 is capable of: better code compression, tline, the upcoming oval(), new chars (kana, puny). Tline in particular changes the whole feel of the carts that use it, with the possibility of mode7, rotation, map lighting, etc. While those effects were previously possible, the games that had them would pay a high cost in CPU and tokens.

Ever since the 2nd palette came, I had some ideas of how the color limit could be increased without going against pico-8's design principles. From these ideas, I selected my favorite and arguably the one that fits pico-8 the best. With pico-8 going beta and possibly its core being set, this might be my last opportunity of sharing it, so here it is:


  • Change the [p] parameter in pal(tbl,[p]) to a integer value between 0 and 128. The [p] value is the first scanline that uses the new palette;

  • This would effectively increase the possible uses of the function from 2 (draw palette and screen palette) to 3 (draw palette, screen palette, and mid-screen palette);

  • If [p] is 0, you change the draw palette as usual. Likewise if [p] is 1, the first line is changed to the new palette, all the way to the last line. No changes here. If [p] is above 1 it means the first scanline of this palette is not at the top of the screen, so it will change the screen palette from that line onwards;

  • Using [p>1] more than once per flip will replace the last mid-screen palette. In the code below, only the [64] value would take effect:
function _draw()
 pal({129,130,131},32) --changes the mid-screen palette for y>=32

 pal({132,2,0},64) --overwrites the pal() above so only this one takes effect when the screen is drawn


In alignment with pico-8's philosophy, this would allow new things to be done, but also create new challenges to overcome and breed creativity through its limitations. Here are some examples:

Water palette

Pal-swap the lower half for some water effects, like in some 16-bit games. It could also be used for water reflection.


In a game with split-screen, changing the screen palette would affect the other player's half-screen. This new feature would prevent that.

Fighting game character select/VS screen

Poke(0x5f2c,0x85) rotates the screen, so instead of top/down palettes, it's left/right. With that, you can have nice 15-color palettes for each character in a VS screen, with the black background hiding the transition between palettes. More juice could be added to each side with their respective palettes (character's names, country flags or whatever else).


Kind of a crude example, since this game was not intended for that, but you could have some different colors for UI if it has a more clear separation from the game area, like it's common in RTSs and some point-and-click games (the red arrow indicates the transition line).

Custom Tools

In my custom tool, Painto-8, the entire screen changes when you open the palette selection. This feature could help to circumvent that, making it less jarring.

Mode 7

In games that use mode7-like effects, you can have 1 palette above the horizon (for the sky and UI) and another below (ground, characters and objects).

Anyways, you get the idea. It really creates a new layer of cool things to explore while mostly keeping the same restrictions. I think it fits pico-8 well... Who knows :)

P#78471 2020-06-24 23:45

Great suggested implementation! When I first found out about the alternate palette, Sonic underwater palettes were the first thing that my mind went to, so it was a huge disappointment to see it only being available on a frame-by-frame basis.

It should be noted that hardware-wise, there is no difference between enabling a new palette before the first scanline of a new frame (during v-blank time) and enabling it before a later scanline (during h-blank time). Once a scanline has been drawn to the CRT, it's history and forgotten about: the hardware is still only drawing at most 16 colours per scanline from its set palette, and that is all that matters to it. The palette simply changes while drawing, but the hardware couldn't care less (it wouldn't even notice) and just keeps colouring each pixel by its denoted palette index, disregarding what that index really refers to; it's just a number after all.

P#78490 2020-06-25 10:49

The idea is sound but the proposed is a bit awkward.
Maybe a vblank callback could be more interesting?
Say a _vblank(i) function called for each line (with a cost) that would allow changing of draw state?

P#78492 2020-06-25 11:30 ( Edited 2020-06-25 11:31)

@freds72 You must mean _hblank(i), as vblank is before/after each frame, and hblank is before/after each scanline. (The _update()/_update60() callback essentially already works as _vblank().)

Other than palette modifications, what would be another compelling use for an hblank callback? I personally have a hard time thinking of any, so I feel a modification of the pal() function would be more elegant, especially since all existing functionality of the second parameter would stay unmodified from how it is currently and intuitively fits into the proposed additional functionality.

P#78493 2020-06-25 11:46 ( Edited 2020-06-25 11:48)

camera state could be changed as well (as a post draw offset)
but yeah, interest is a bit shaky
but allowing 32 colors on screen at once is a massive design switch!

P#78496 2020-06-25 12:15

@BoneVolt This is a beautiful post. I hope this will suffice 8)

for i=0,15 do
P#78509 2020-06-25 18:34

Zep, that sneaky boi keeps hiding things right under our noses!

P#78513 2020-06-25 19:42

So you suggested some kind of mid-frame palette swap thing to be added, yet Zep came in and posted a snippet that follows exactly what you wanted! What a coincidence!

P#78527 2020-06-26 02:21

Wait, does this mean we have copperlists now?

P#78570 2020-06-27 11:05

somehow yes (and it shows your age ;)

P#78571 2020-06-27 11:49

I see now how it works. Not quite copperlists, but a tolerable compromise.

This would be quite nice for the raycasters, lets the floor and ceiling share palette slots.

Nice. :) Now that we know about your little gift, would it be reasonable to request that pal(a,b,2) write to the memory range as pal(a,b,1) does for the default screen palette's range? Also pal(tbl,2) for that matter. Just for convenience. Or you could let this remain something for only the l33t h@xx0r people who are down for some poking. ;)

P#78573 2020-06-27 14:10 ( Edited 2020-06-27 14:12)

I personally feel that since the equivalent feature on real consoles was somewhat of a hack, it would only be appropriate for this to remain hidden behind pokes, to keep that same, hacky feeling.

P#78574 2020-06-27 14:30

I think that the fact that those features are only accessible through code makes them hidden enough. Just look at the new cartridges page. From the thumbnails, it looks like only 1 out of 30 games use the hidden palette, almost a year after being discovered. Standard palette is OP, plz nerf ;P

P#78584 2020-06-27 18:12

These numbers might be slightly inaccurate, because the hidden palette wasn't properly handled in cart labels until 0.2.0g.

P#78587 2020-06-27 20:19

You're right, I went and played all 30, and 4 of them have at least one color from the alternate palette (played the first few screens). I think it's a decent number, considering you have to dig a bit to be able to use it.

P#78589 2020-06-27 20:57

[Please log in to post a comment]