Colors and the palette
BLIT386 is "palette-first". Instead of drawing with a color directly, you fill a small set of numbered slots with colors once, then draw using the slot...
Written for blit386 1.8.0. The rest of blit386.dev documents the newest engine, so an API you find there may be missing from a game pinned to 1.8.0.
BLIT386 is "palette-first". Instead of drawing with a color directly, you fill a small set of numbered slots with colors once, then draw using the slot numbers. This is how old game consoles worked, and it unlocks tricks like recoloring the whole screen by changing one slot.
Make a palette in init()
async init() {
// A palette with room for 16 colors. Slot 0 is always transparent, so use 1 and up.
this.palette = BT.paletteCreate(16);
// Put colors in slots. Color32(red, green, blue) with each value from 0 to 255.
this.palette.set(1, new Color32(230, 80, 60)); // a warm red
this.palette.set(2, new Color32(20, 24, 40)); // a dark blue background
this.palette.set(3, new Color32(120, 200, 120)); // a soft green
this.palette.set(4, new Color32(240, 240, 255)); // near-white for text
// Hand the palette to the engine. From now on, drawing uses slot numbers.
BT.paletteSet(this.palette);
return true;
}Draw with slot numbers
render() {
BT.clear(2); // slot 2 = background
BT.drawRectFill(new Rect2i(10, 10, 32, 32), 1); // slot 1 = red
BT.systemPrint(new Vector2i(8, 8), 4, 'Hi'); // slot 4 = near-white
}Color32 quick reference
new Color32(r, g, b)- red, green, blue, each 0 to 255.new Color32(r, g, b, a)- add alpha (0 transparent, 255 solid).- Handy presets are properties, not calls:
Color32.white,Color32.black,Color32.red,Color32.green,Color32.blue(no parentheses). color.luminance- how bright a color looks, 0 to 255. Use it instead of writing the brightness formula yourself.color.toLinear()/color.toSrgb()- switch between the numbers a color is stored as and actual light (blit386 1.5.0+). Only needed if you are doing your own brightness math; the palette effects already do this for you.
Filling a block of slots at once (blit386 1.7.0+)
When you want a run of slots built from one list of colors - a darker copy of your sprite colors for a shadow, a tinted
copy for a night theme - fillBlock does the whole run in one call instead of a hand-written loop:
async init() {
// Room for the colors above plus a darker copy of them.
this.palette = BT.paletteCreate(16);
this.baseColors = [new Color32(230, 80, 60), new Color32(120, 200, 120), new Color32(240, 240, 255)];
// palette.fillBlock(start, source, transform)
// Writes transform(source[i], i) into slot start + i, and returns the next free slot.
const nextFree = this.palette.fillBlock(
5, // first slot to write, so this fills 5, 6, and 7
this.baseColors, // an array of Color32 to read from
(color) => new Color32(color.r >> 1, color.g >> 1, color.b >> 1), // half brightness
);
BT.paletteSet(this.palette);
return true;
}The return value is start + source.length - the first slot the block did not use, 8 here - so you can chain a
second block straight after it without counting by hand.
The whole block has to fit: start + source.length must not run past the size you gave paletteCreate. Three colors
starting at slot 5 need a palette of at least 8 slots.
transform also receives the index ((color, i) => ...) if you want the change to vary across the run. Each write goes
through palette.set(), so the same rules apply: the block must fit inside the palette, and it must not try to make
slot 0 solid.
The transparent slot
Slot 0 is always see-through. Drawing with slot 0 draws nothing, which is occasionally useful, but for visible colors start at slot 1.
Changing a color later
The palette is live. Change a slot during the game and everything drawn with that slot changes on the next frame:
update() {
if (this.hurt) {
this.palette.set(1, new Color32(255, 255, 255)); // flash the player white
}
}Fading the whole screen
Two fades, same start and end, different middle:
// A crossfade: every slot dims by the same share at the same time.
BT.paletteFade(this.nightPalette, 2000, 'ease-in-out');
// A camera fade: bright slots come up first and hold on longest, dark slots
// arrive late and crush early (blit386 1.5.0+).
BT.paletteFadeExposure(this.gamePalette, 2000);Use the first for a cross-dissolve between themes, the second for a title card or a fade up into the game. The
animate-the-palette skill covers cycling, flashing, and swapping too.
Start a fade (or any palette effect) from init() or update(), not render(). Effects move once per update() step,
right after yours runs (blit386 1.8.0+), so they keep the same pace on every display and BT.renderAt can replay them
for a screenshot. A palette write made in render() lands after that step's effects instead of before them.
Next: docs/drawing.md for the full list of things you can draw.
Input
Read input inside `update()` - button presses, key presses, and typed text are one-frame events that already reset by the time `render()` runs, so checking...
Random numbers and world generation
Games need surprise: which enemy appears, where the coin lands, how the ground is shaped. BLIT386 gives you two tools for that, and picking the right one...