The palette tool of the opensnes-* family (The opensnes-* tools: conventions). Two jobs a game has around colour, before and after the picture tools: planning how every .pal of the project fits the SNES's 8 background and 8 sprite palettes of 16 colours (CGRAM 0..127 and 128..255), and quantizing the RGB art an artist draws into the indexed PNG that opensnes-sprite — sheets, metasprites and Aseprite clips and opensnes-tileset — pictures to tilesets and tilemaps eat. The planner is palplan's (palplan — project shared-palette planner) and the quantizer img2snes's (img2snes — RGB artwork to indexed palettes), linked as libraries: same slots, same bytes.
A plan is a composed asset: res/palettes.toml lists the project's .pal files (as opensnes-sprite and opensnes-tileset write them beside each picture), in slot order, relative to the file:
Identical palettes share a slot; every palette gets its CGRAM index and its slot number; a ninth distinct palette in a region is refused (exit 1), with the near-duplicates named so you know which two to merge. The plan prints as a table, and --hints N sets how close two palettes must be to be named (2 differing colours by default; 0 never).
Out, beside the file or in --out:
| File | What it is |
|---|---|
| palettes.inc | PAL_<NAME>_CGRAM (the startColor of dmaCopyCGram), PAL_<NAME>_SLOT (the OAM palette number, or the palette bank of a tilemap entry) and PAL_<NAME>_COLORS for each palette, <NAME> the file's stem in capitals |
| palettes.pal, palettes_data.as | with cgram = true: the whole plan as one 512-byte CGRAM image, palettes_cgram in the .inc, for a single dmaCopyCGram(palettes_cgram, 0, 512) |
The build runs a plan after the pictures' conversions, so the .pal files it reads are fresh (make/common.mk). examples/games/rpg plans its sprite palettes this way.
In: an RGB or RGBA PNG. Out: <stem>_indexed.png, an indexed PNG of --colors colours (16 for 4 bpp, 4 for 2 bpp, 256 for 8 bpp) chosen by median cut, or mapped onto the colours of --palette (a .pal, or a PNG's palette) when several pictures must share a slot. Transparent pixels (alpha below 128) become index 0, the colour the SNES does not draw. --round snaps the palette to the 15-bit colour of the hardware, so the picture shows what the console will; --scale PERCENT resizes first (nearest neighbour) and --align N pads the size to a multiple of N.
This is the one step of the pipeline meant to be looked at: run it on new art, open the result, commit it, and let the picture tools work from the indexed file. Pixel-art tools that export indexed PNGs skip it.
-v prints the colours in hex; --json for a script.
| earlier tools | opensnes-palette |
|---|---|
| palplan -o plan.h -b plan.pal project.txt (a three-column manifest) | plan palettes.toml with bg = [...], sprite = [...], cgram = true |
| name type file lines | the file's stem is the name; two lists are the types |
| -t N | --hints N |
| img2snes -i art.png -c 16 --round-snes | quantize art.png --colors 16 --round |
| -p ref.png | --palette ref.pal or --palette ref.png |
| -s 2.0, -t 8 | --scale 200, --align 8 |
The same CGRAM image and the same PAL_ macros as palplan, the same indexed PNGs as img2snes (both golden suites are the family's). One change under both tools: the quantizer's sort now breaks ties by index, so a picture quantizes to the same bytes on every OS (it depended on the C library's qsort before).