186 lines
8.2 KiB
Markdown
186 lines
8.2 KiB
Markdown
---
|
|
id: AGD-0005
|
|
ticket: variable-tile-bank-palette-serialization
|
|
title: Variable Glyph Bank Palette Serialization
|
|
status: accepted
|
|
created: 2026-03-26
|
|
resolved: 2026-07-14
|
|
decision: DEC-0038
|
|
tags:
|
|
- packer
|
|
- legacy-import
|
|
- glyph-bank
|
|
- palette-serialization
|
|
- rgba8888
|
|
- runtime-alignment
|
|
---
|
|
|
|
## Pain
|
|
|
|
Domain owner: `packer`, with runtime-facing impact through `assets.pa`.
|
|
|
|
The current `GLYPH/indexed_v1` glyph-bank contract serializes a fixed block of
|
|
`64` palettes even when an asset authors far fewer palettes.
|
|
|
|
After `DSC-0038`, each palette entry is RGBA8888, so the fixed palette block is
|
|
now `64 * 16 * 4 = 4096` bytes. That keeps decoding simple, but it wastes
|
|
cartridge space and leaves a deliberate mismatch between authored palette count
|
|
and serialized palette count.
|
|
|
|
## Context
|
|
|
|
Legacy source: `docs/packer/agendas/Variable Tile Bank Palette Serialization Agenda.md`
|
|
|
|
Cross-domain dependency:
|
|
|
|
- runtime
|
|
|
|
Runtime follow-up:
|
|
|
|
- `../runtime/discussion/workflow/decisions/DEC-0041-variable-glyph-bank-palette-protocol.md`
|
|
is accepted and normative for the runtime side.
|
|
- Runtime `DSC-0046` keeps `GLYPH/indexed_v1`, adopts variable glyph-bank
|
|
palette serialization, and treats this as an incompatible v1 correction.
|
|
- Runtime plans `PLN-0167` through `PLN-0172` are done and publish the
|
|
downstream handoff.
|
|
|
|
Current runtime-owned `GLYPH/indexed_v1` contract:
|
|
|
|
- pixels are serialized as packed `u4`;
|
|
- palettes are serialized as RGBA8888 values in runtime `R`, `G`, `B`, `A`
|
|
byte order;
|
|
- `palette_count` is the number of serialized and resident palettes;
|
|
- `palette_count` must be in `1..=64`;
|
|
- payload size includes exactly `palette_count * 16 * 4` palette bytes;
|
|
- palette index `0` is ordinary;
|
|
- each palette has 16 usable colors;
|
|
- transparency is represented by alpha, not by a reserved index or magenta
|
|
color-key;
|
|
- resident runtime memory materializes exactly `palette_count` palettes;
|
|
- `palette_id` is a direct palette identity inside the loaded glyph bank and is
|
|
valid only when `palette_id < palette_count`;
|
|
- sparse-to-dense palette remapping is not part of v1;
|
|
- missing palettes must fail explicitly in scene/sprite/composer use, not
|
|
silently resolve to a default color.
|
|
|
|
Downstream producers must emit:
|
|
|
|
- root effective metadata fields `tile_size`, `width`, `height`, and
|
|
`palette_count`;
|
|
- `size = ceil(width * height / 2) + palette_count * 16 * 4`;
|
|
- `decoded_size = width * height + palette_count * 16 * 4`;
|
|
- exactly `palette_count * 16 * 4` RGBA8888 palette bytes;
|
|
- no `GLYPH/indexed_v2` payload for this change;
|
|
- no fixed 64-palette padding unless `palette_count = 64` and the payload
|
|
directly satisfies the runtime v1 contract;
|
|
- no effective runtime behavior based on `palette_authored`.
|
|
|
|
`DSC-0038` intentionally did not solve variable palette-count serialization.
|
|
It changed the color encoding from RGB565-era semantics to RGBA8888 and kept
|
|
the fixed 64-palette model stable for that wave.
|
|
|
|
Runtime `DEC-0041` now closes the cross-domain protocol questions that this
|
|
agenda previously carried as open. The remaining Studio/packer work is
|
|
downstream alignment with the runtime-owned contract.
|
|
|
|
## Open Questions
|
|
|
|
- [x] Should variable palette serialization arrive as a new payload version or
|
|
as an incompatible change to the current one?
|
|
- Runtime `DEC-0041` resolves this as an incompatible correction to
|
|
`GLYPH/indexed_v1`, with no v2 format.
|
|
- [x] If `palette_count` becomes variable, should runtime still materialize a
|
|
64-slot resident bank, or truly shrink in-memory representation too?
|
|
- Runtime `DEC-0041` resolves this: resident runtime memory materializes
|
|
exactly `palette_count` palettes.
|
|
- [x] Should sparse authored palette indices remain sparse in serialization, or
|
|
be canonicalized into a dense runtime block?
|
|
- Runtime `DEC-0041` rejects sparse-to-dense remapping. `palette_id` remains
|
|
direct identity inside the loaded glyph bank.
|
|
- [x] Should this repository create the owner agenda/decision for the runtime
|
|
side, or should a matching runtime `discussion/` artifact be opened before
|
|
implementation planning?
|
|
- Runtime `DSC-0046` now owns the protocol through accepted `DEC-0041`.
|
|
Studio/packer must follow that handoff.
|
|
- [x] Which domain owns compatibility for existing cartridges: `packer`,
|
|
`runtime`, or `shipper`?
|
|
- Runtime `DEC-0041` introduces no compatibility mode. Old payloads with
|
|
`palette_count = 64` remain valid only when they satisfy the new contract
|
|
directly.
|
|
|
|
## Options
|
|
|
|
### Option A - Keep fixed 64-palette serialization in v1
|
|
- **Approach:** Preserve the current fixed v1 payload with zero-filled unused palette slots.
|
|
- **Pro:** No runtime change and current specs/tests remain stable.
|
|
- **Con:** Every glyph bank keeps paying the full 4096-byte palette cost.
|
|
- **Maintainability:** Medium.
|
|
|
|
### Option B - Align packer output with runtime variable palette serialization
|
|
- **Approach:** Keep the `GLYPH/indexed_v1` format name, serialize only
|
|
`palette_count` palettes, and make packer metadata, payload sizes, fixtures,
|
|
and Studio projections follow runtime `DEC-0041`.
|
|
- **Pro:** Removes fixed padding while the project is still in v1, keeps the
|
|
public format vocabulary stable, and makes runtime metadata match the payload.
|
|
- **Con:** Requires coordinated packer/spec/test changes and fixture
|
|
regeneration because the current producer still emits the old fixed-padding
|
|
shape.
|
|
- **Maintainability:** Strong if implemented as an explicit contract update,
|
|
weak if done as an incidental size tweak. Runtime has already closed the
|
|
protocol questions.
|
|
|
|
### Option C - Keep fixed external metadata but trim trailing palettes
|
|
- **Approach:** Keep some 64-slot assumptions in metadata or runtime memory, but
|
|
serialize only a shortened trailing subset of palettes in the payload.
|
|
- **Pro:** Can reduce cartridge size while limiting some runtime changes.
|
|
- **Con:** Creates a split-brain contract where serialized count, logical count,
|
|
and resident count can disagree.
|
|
- **Maintainability:** Weak. It preserves the ambiguity this agenda is trying
|
|
to remove.
|
|
|
|
## Discussion
|
|
|
|
The retained concern is still valid after `DSC-0038`, but runtime `DEC-0041`
|
|
has now closed the protocol. The problem is no longer an open cross-domain
|
|
design question; it is a downstream producer-alignment task for Studio/packer.
|
|
|
|
The old recommendation favored a versioned follow-up because compatibility and
|
|
runtime stability were treated as constraints. Runtime `DEC-0041` removes that
|
|
constraint: the project is still in v1, keeps `GLYPH/indexed_v1`, and does not
|
|
need compatibility for the old fixed 64-palette payload.
|
|
|
|
That makes Option B the required direction for this repository. Runtime already
|
|
changed the contract directly; Studio/packer must now emit the runtime-owned
|
|
shape and stop treating `palette_authored` or the old 64-padding model as
|
|
effective runtime behavior.
|
|
|
|
Option C should be avoided because it preserves multiple meanings for palette
|
|
count. If the payload becomes variable, `palette_count` should mean the number
|
|
of serialized palettes, not an unrelated fixed resident capacity.
|
|
|
|
## Resolution
|
|
|
|
Recommended direction: adopt **Option B**.
|
|
|
|
Updated recommendation:
|
|
|
|
1. keep the format name `GLYPH/indexed_v1`;
|
|
2. follow runtime `DEC-0041` as the protocol authority;
|
|
3. remove the fixed 64-palette payload block from packer output;
|
|
4. make packer `palette_count` describe the serialized and resident RGBA8888
|
|
palette count;
|
|
5. emit exactly `palette_count * 16 * 4` palette bytes;
|
|
6. update `size` and `decoded_size` formulas to use variable `palette_count`;
|
|
7. do not create a v2 format solely for this change;
|
|
8. do not preserve compatibility with the old fixed-padding payload;
|
|
9. do not introduce sparse-to-dense palette remapping metadata;
|
|
10. treat `palette_authored` as informative only unless a later runtime
|
|
decision promotes it to effective metadata;
|
|
11. add downstream fixture coverage for `palette_count = 1`, an intermediate
|
|
count, and `palette_count = 64`;
|
|
12. add a negative producer validation case for metadata/payload mismatch.
|
|
|
|
Next step suggestion: convert this agenda into a Studio/packer decision that
|
|
references runtime `DEC-0041` and scopes implementation to specs, packer
|
|
payload emission, Studio projections if needed, tests, and fixtures.
|