Palette enforcement
{
"styles": {
"gb": {
"generator": "map",
"outDir": "art/gb",
"palette": ["#0f380f", "#306230", "#8bac0f", "#9bbc0f"],
"enforcePalette": true
}
}
}
With enforcePalette, fetch maps every visible pixel of a downloaded PNG
to the nearest palette colour (redmean distance, no dithering) before the
file is written, and records what it did on the lock entry:
"postprocess": { "palette": { "colors": ["#0f380f", "..."], "dither": "none", "distance": "redmean" } },
"outputs": [{ "path": "art/gb/anvil.png", "sha256": "<snapped>", "raw": "<provider bytes>" }]
sha256 is the file on disk. raw is the provider's bytes before snapping,
present only when snapping changed something; a provider that honoured the
palette leaves the file, and the record, exactly as it came. Both live in
the content cache, so the step can be undone or redone without a download.
The flag is not part of the spec hash. Turning it on for a style with
generated art makes plan report each entry as recoverable, and the next
fetch (or gen, or restore) re-applies the rule to the files already on
disk, spending nothing. Turning it off puts the provider's bytes back the
same way. Changing the colours themselves is a different matter: palette
is sent to providers, so it is in the spec hash and a change is stale.
A file you changed by hand is never re-snapped; it shows as orphaned and
waits for --force or pixelkiln edit. GIF output passes through untouched.
Transparent pixels keep their alpha and get zeroed colour so the same
picture always has the same bytes.
enforcePalette and a quality profile are different tools. Enforcement
is one deterministic step on the provider's bytes with no external
dependency and no review gate. A quality profile recovers the native pixel
grid with Pixel Art Fixer first, then applies its own closed palette, and
holds packaging until a person approves the result.