--- id: DEC-0038 ticket: variable-tile-bank-palette-serialization title: Variable Glyph Bank Palette Serialization for Studio and Packer status: accepted created: 2026-07-14 accepted: 2026-07-14 ref_agenda: AGD-0005 plans: - PLN-0087 - PLN-0088 - PLN-0089 - PLN-0090 - PLN-0091 tags: - packer - studio - glyph-bank - palette-serialization - rgba8888 - runtime-alignment --- ## Status Accepted. Drafted from accepted agenda `AGD-0005` and accepted on 2026-07-14. ## Context This decision belongs to the `packer` domain, with Studio-facing projection and fixture impact. Runtime protocol ownership remains in `../runtime`. Studio/packer already aligned glyph-bank colors with RGBA8888 through `DSC-0038`. That work kept the `GLYPH/indexed_v1` format name and changed the palette color encoding from RGB565-era data to RGBA8888 in runtime channel order. It deliberately preserved the fixed 64-palette payload model for that wave. Runtime `DEC-0041` now changes the authoritative `GLYPH/indexed_v1` contract: - `palette_count` is the number of serialized and resident palettes; - `palette_count` MUST be in `1..=64`; - payloads contain exactly `palette_count * 16 * 4` RGBA8888 palette bytes; - `size = ceil(width * height / 2) + palette_count * 16 * 4`; - `decoded_size = width * height + palette_count * 16 * 4`; - resident runtime memory materializes exactly `palette_count` palettes; - `palette_id` is direct identity within the loaded glyph bank and is valid only when `palette_id < palette_count`; - v1 has no sparse-to-dense palette remapping metadata; - this remains `GLYPH/indexed_v1`, not a new v2 payload. Studio/packer must now follow that runtime-owned contract as downstream producers of runtime-conforming `assets.pa` payloads. ## Decision Studio and packer SHALL adopt variable glyph-bank palette serialization for `GLYPH/indexed_v1`, following runtime `DEC-0041` as the protocol authority. Packer MUST stop emitting a fixed 64-palette block for glyph banks unless the effective `palette_count` is actually `64`. Packer MUST emit exactly `palette_count * 16 * 4` palette bytes for each `GLYPH/indexed_v1` glyph-bank payload. Packer MUST compute glyph-bank `size` as: ```text size = ceil(width * height / 2) + palette_count * 16 * 4 ``` Packer MUST compute glyph-bank `decoded_size` as: ```text decoded_size = width * height + palette_count * 16 * 4 ``` Packer MUST publish root effective metadata fields required by runtime: - `tile_size` - `width` - `height` - `palette_count` For `GLYPH/indexed_v1`, `palette_count` MUST describe the number of serialized RGBA8888 palettes and the number of resident palettes expected by runtime. `palette_count` MUST be in the inclusive range `1..=64`. Packer and Studio MUST NOT introduce `GLYPH/indexed_v2` for this change. Packer and Studio MUST NOT preserve compatibility with the old fixed-padding payload shape as a special mode. Packer and Studio MUST NOT introduce sparse-to-dense palette remapping metadata for v1. `palette_authored`, when present in tooling or pipeline metadata, is informative only. It MUST NOT be treated as effective runtime metadata unless a later runtime decision promotes it. Palette bytes SHALL remain RGBA8888 in runtime `R`, `G`, `B`, `A` byte order. Palette index `0` and color index `0` remain ordinary indices. Transparency remains represented by the alpha channel of the resolved RGBA8888 color. ## Rationale Runtime owns the `GLYPH/indexed_v1` wire contract. Once runtime `DEC-0041` accepted variable palette serialization, keeping packer output fixed at 64 palettes would make Studio/packer produce stale runtime payloads. Making `palette_count` the effective serialized and resident count removes the old mismatch between authored palette count and payload shape. The packer no longer needs to pad every glyph bank to 4096 palette bytes unless the bank really uses all 64 palettes. Keeping the existing format name is correct because the project is still in v1 and runtime explicitly accepted this as an incompatible v1 correction. A v2 name would add migration surface without protecting any required compatibility contract. Rejecting sparse-to-dense remapping keeps `palette_id` direct. Scene, sprite, packer output, and runtime lookup all refer to the same palette identity inside the loaded glyph bank. ## Implications ### Specs Packer specs MUST be updated so `GLYPH/indexed_v1` no longer describes a fixed `64 * 16 * 4 = 4096` palette block as the normal payload shape. Packer specs MUST define `palette_count` as the effective serialized palette count for glyph banks, constrained to `1..=64`. Studio specs MUST be updated only where Studio-facing projections, asset details, pack wizard behavior, or fixtures expose the old fixed-padding model. ### Code Packer payload emission MUST write only `palette_count` palettes. Packer payload validation/materialization helpers MUST compute size and decoded size from variable `palette_count`. Packer metadata projection and Studio-facing read/detail APIs MUST expose the runtime-effective `palette_count` correctly. Studio code MUST NOT treat `palette_authored` as the runtime-effective count. ### Tests and Fixtures Tests MUST cover: - `palette_count = 1`; - an intermediate `palette_count`; - `palette_count = 64`; - size and decoded-size formulas for variable counts; - emitted RGBA8888 palette byte count; - metadata/payload mismatch rejection or producer validation. Fixtures that encode the old fixed-padding assumption MUST be regenerated or updated unless they intentionally use `palette_count = 64` and satisfy the new runtime contract directly. ### Non-goals This decision does not change RGBA8888 channel order. This decision does not change the packed `u4` indexed pixel plane. This decision does not change scene `palette_id` payload shape. This decision does not introduce v2, compatibility branches, or palette identity remapping. ## Propagation Targets - Specs: - `docs/specs/packer/3. Asset Declaration and Virtual Asset Contract Specification.md` - `docs/specs/packer/4. Build Artifacts and Deterministic Packing Specification.md` - `docs/specs/studio/4. Assets Workspace Specification.md`, if Studio-facing palette count projection is documented there. - Code: - packer glyph-bank payload emission; - packer asset walking/materialization; - packer read/detail projections; - Studio asset details or pack wizard surfaces if they expose palette counts. - Tests: - packer parser, walker, materializer, workspace service, and fixture tests; - Studio tests if Studio projections or UI logic expose palette counts. - Docs: - downstream implementation plans derived from this decision. ## References - Agenda: `AGD-0005` - Runtime decision: `../runtime/discussion/workflow/decisions/DEC-0041-variable-glyph-bank-palette-protocol.md` - Runtime handoff: `../runtime/discussion/workflow/plans/PLN-0172-runtime-spec-handoff-to-packer-and-studio.md` - Prior Studio/packer RGBA8888 lesson: `discussion/lessons/DSC-0038-studio-packer-rgba8888-asset-pipeline/LSN-0053-rgba8888-is-the-canonical-studio-packer-palette-contract.md` ## Revision Log - 2026-07-14: Initial accepted decision from `AGD-0005`, aligned with runtime `DEC-0041`.