Manifest reference

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.