No big story here - I'm a big fan of the bot rain.gif and wanted to make something in PICO-8 that would produce similar images. Is configured to loop seamlessly for 8-second gifs (PICO-8's default), but the parameter should be obvious and easy to change. No sound.
Currently has 16 palettes, all chosen to have reasonably good contrast ratio - should be clear how to edit those as well.
I spent a while being very, very confused about screen palettes and draw palettes, but I've started to feel like I've got a hang of it? And I decided to make a visual expression of how these work as a PICO-8 cart.
In the default state, the screen palette contains the sixteen colors of the default palette - 0-15 - and the draw palette links the sixteen draw colors 0-15 directly to these default colors.
When the draw palette changes, different colors from the screen palette are loaded into the draw color slots. The sprite still refers to the same draw colors - in this case, 0-3 across the top, 4-7 in the second row, 8-11 in the second-to-bottom row, and 12-15 in the bottom row - but these draw colors have been redefined in terms of the screen palette.
...and the screen palette in turn can be redefined by changing the colors in its 16 slots.
I think how this is intended to be understood is:
- 4 components: video output hardware (5-bit input, RGB output), screen palette RAM (4-bit address, 8-bit output), screen data RAM (14-bit address, 4-bit output), draw palette lookup table RAM (4-bit address, 4-bit output)
- Every sixtieth of a second, one frame of graphics is sent to the monitor. As the hardware scans through the 128x128 pixels of the screen data, the 4-bit screen data output addresses the screen palette RAM, and the high-order bit plus lower 4 bits of the screen palette output goes to the video output hardware. (I can attest from having bugs in my screen palette code for a while that the other bits in the screen palette are ignored.)
- When commands are run to draw graphics on the screen, the 4-bit addresses to be drawn go through the draw palette lookup table to set the 4 bits actually stored in the corresponding addresses of the screen data RAM.
Or, in less technical terms: the data stored for the sprite (or whatever) chooses a row in the draw palette (center) which chooses a row in the screen palette (left) which chooses a color on the screen. Changing the draw palette doesn't change what the screen shows until PICO-8 draws something new to the screen data; changing the screen palette does.
What honestly made it click for me, though, was thinking in practical terms.
The draw palette, for example, is a tool for recoloring images as I draw them. For example, if I have this little gray box stored as a sprite in my sprite sheet:
then I can use the draw palette to declare that I'm drawing it as an orange sprite instead:
The screen palette, on the other hand, I think of as 16 meanings. Rather than thinking of the, say, 11th color in the screen palette as a color, when I am using the screen palette to change the colors of images, I think of it by its purpose: in this case, the color of the character's shirt.
Then, changing that color represents a change corresponding to that meaning: to put the value 136 in screen palette slot 11, then, is to say that the color of the character's shirt is not green, it is red.
These ideas can obviously be combined - perhaps screen palette 1 is the color of player 1's vehicle and screen palette 2 is the color of player 2's vehicle, and which color is drawn when a vehicle sprite is drawn is selected using the draw palette. Thus, both players can select the colors of their vehicles and both vehicles can be drawn using the same sprites.
This is very long and probably well-known in the community, but I figured I'd make the tutorial anyway because I'm proud of figuring this out.
One of the things that's been very much on my mind as I've been learning PICO-8 and making my first full game project in it has been how to use the console's limited palette, and particularly how to ensure that everything I put on screen is clear and straightforward to read. It is very easy when designing user interfaces to make something that looks fine in a screenshot viewed in a well-lit room on a bright monitor by someone who knows where and what everything is, but obscure or confusing in actual play under the varied conditions which your audience plays in.
Nothing substitutes for testing, but the number one idea that I've used to try to make sure I start with something easily-read or close to it is contrast ratios - essentially, how much difference in brightness there is between two colors.
The hex codes and names for colors 0-15 I copied from the wiki page on Graphics - the names being from Roman Zolotarev's PICO-8 palette reference. The hex codes for colors 128-143 (the extended palette - see the draw state section of the wiki page on Memory) I measured myself with paint.net from screenshots, and I picked names for them using https://klaash.github.io/xkcdcolorpicker/ as guide/inspiration.
The brightness numbers and the guidelines for difference of brightness need a little bit of explaining.
WCAG2 and contrast ratios
The Web Contrast Accessibility Guidelines (WCAG) 2.0 have a section on the visual presentation of text and images of text. There are no guidelines as far as I am aware for purely graphical elements - how could there be? - but I use the three thresholds that WCAG2 describes as the basis for how I do this.
- For large-scale text, WCAG2 minimum contrast requires a contrast ratio of at least 3:1.
- For ordinary text, WCAG2 minimum contrast requires a contrast ratio of at least 4.5:1.
- For large-scale text, WCAG2 enhanced contrast requires a contrast ratio of at least 4.5:1.
- For ordinary text, WCAG2 enhanced contrast requires a contrast ratio of at least 7:1.
So: what is a contrast ratio? Click the link on the page, and it gives a formula in terms of relative luminance:
contrast ratio = (L1 + 0.05) / (L2 + 0.05)
What is relative luminance? Click the link on the page, and it gives ... a collection of equations that are more complex than I want to get into, but trace all the way back to the 8-bit R, G, and B values used in sRGB color spaces, which I'm pretty sure is what most everything uses, including PICO-8. I plugged the formulae into a spreadsheet and managed to get out the contrast ratio data I wanted, which I then compared to these three thresholds from WCAG2 and used conditional formatting to display them all nicely.
...then I spent a long time thinking about how to make this easier to use as a general reference, because the difficulty of accessing information is probably what makes these things less commonly thought about.
What I've got right now probably isn't perfect. But I remembered a bit of math that might make things more straightforward: logarithms.
ln contrast ratio = ln (L1 + 0.05) - ln (L2 + 0.05)
By recording brightness as a logarithm of the relative luminance term in the equation (kind of like how magnitudes of stars in the sky are recorded), I turn a ratio into a simple subtraction. For a pair of colors to have sufficient contrast, these log-L brightnesses merely need to differ by enough to meet the necessary contrast ratio:
- ln 3 = 1.10
- ln 4.5 = 1.50
- ln 7 = 1.95
...and thus I have a possible workflow: find your color in the list sorted by index, read out its brightness, add and/or subtract to calculate what brightnesses contrast at the level you need them to (a judgment call, but practice should help), and look at the list sorted by luminance to see what groups of colors at the ends of the lists hit that contrast level.
I hope this is useful to people, or at least a fun toy to explore the full list of PICO-8 colors with.
Edit: For convenience, I've also uploaded a text file with substantially the same information - probably more convenient to work with for many purposes, even if it's less colorful.