prometeu-studio/discussion/lessons/DSC-0005-variable-glyph-bank-palette-serialization/LSN-0054-runtime-owned-variable-glyph-palette-counts.md
bQUARKz ad2ae00f39
All checks were successful
JaCoCo Coverage #### Project Overview No changes detected, that affect the code coverage. * Line Coverage: 61.08% (17147/28073) * Branch Coverage: 51.93% (6599/12707) * Lines of Code: 28073 * Cyclomatic Complexity: 11234 #### Quality Gates Summary Output truncated.
Test / Build skipped: 15, passed: 583
Intrepid/Prometeu/Studio/pipeline/head This commit looks good
Variable Glyph Bank Palette Serialization
2026-07-14 16:53:20 +01:00

127 lines
5.3 KiB
Markdown

---
id: LSN-0054
ticket: variable-tile-bank-palette-serialization
title: Runtime-Owned Variable Glyph Palette Counts
created: 2026-07-14
tags:
- packer
- studio
- glyph-bank
- palette-serialization
- rgba8888
- runtime-alignment
---
# Runtime-Owned Variable Glyph Palette Counts
### Original Problem
The first RGBA8888 alignment wave made Studio and packer emit palette colors in
the runtime channel order, but it deliberately kept the old fixed glyph-bank
palette payload shape. Every `GLYPH/indexed_v1` payload still reserved room for
64 palettes, so the emitted palette block was always `64 * 16 * 4 = 4096`
bytes even when the bank used one or a few palettes.
That fixed shape left two problems:
- packer output was larger than the runtime needed;
- `palette_count` could not be trusted as the effective runtime resident count,
because the payload still looked like a 64-palette bank.
Runtime later accepted the variable-palette protocol for
`GLYPH/indexed_v1`. Studio and packer had to follow that runtime-owned wire
contract instead of keeping a stale producer-side convention.
### Consolidated Decision
Runtime owns the `GLYPH/indexed_v1` protocol. Studio and packer are downstream
producers of runtime-conforming `assets.pa` payloads.
The accepted rule is:
1. `palette_count` is the effective serialized and resident palette count.
2. `palette_count` must be in the inclusive range `1..=64`.
3. Palette bytes are exactly `palette_count * 16 * 4`.
4. `size = ceil(width * height / 2) + palette_count * 16 * 4`.
5. `decoded_size = width * height + palette_count * 16 * 4`.
6. Palette bytes remain RGBA8888 in `R`, `G`, `B`, `A` order.
7. `GLYPH/indexed_v1` remains the format name. This change does not introduce
`GLYPH/indexed_v2`.
8. There is no compatibility mode for the old fixed 64-palette padding.
9. Palette IDs remain direct. There is no sparse-to-dense remapping metadata in
v1.
10. `palette_authored`, when present, is informative tooling metadata only.
### Implementation Result
The packer specs now define `palette_count` as runtime-effective metadata for
glyph banks and describe the variable palette payload in the build-artifact
contract. Studio-facing asset workspace docs now keep `palette_count` distinct
from any authored or tooling-only palette count.
The packer metadata model derives and validates effective palette count instead
of hard-coding `64`. Sparse direct palette IDs are preserved by materializing
intermediate palette slots up to the highest referenced ID; those slots are not
a remapping table.
Payload emission now writes exactly the effective number of palette slots. Size
and decoded-size accounting use the same formula as the runtime contract, so
metadata, asset-table entries, and payload lengths agree.
Tests and fixtures cover `palette_count = 1`, intermediate counts, `64`, sparse
direct identity, invalid counts above `64`, RGBA8888 byte order, and payload
size accounting. Final validation passed with:
- `discussion validate`;
- `./gradlew :prometeu-packer:prometeu-packer-v1:test`;
- `./gradlew build`.
### Practical Examples
A 256 by 256 glyph bank with one palette has:
```text
pixel bytes = ceil(256 * 256 / 2) = 32768
palette bytes = 1 * 16 * 4 = 64
size = 32768 + 64 = 32832
decoded_size = 256 * 256 + 64 = 65600
```
A bank that references palette ID `6` has an effective `palette_count` of at
least `7`. Palette slots `0` through `6` exist in the serialized palette block.
If some lower slots were not authored directly, they are deterministic
placeholders; palette `6` is not remapped to palette `0`.
### Common Pitfalls and Anti-patterns
- Do not infer runtime payload length from the maximum allowed palette count.
`64` is the upper bound, not the default emitted count.
- Do not use `palette_authored` as a runtime-effective field. It may describe a
tool view, but runtime loads `palette_count`.
- Do not preserve fixed 4096-byte palette padding for banks with fewer than 64
effective palettes.
- Do not create `GLYPH/indexed_v2` to carry this change. The accepted runtime
protocol keeps the v1 format name.
- Do not introduce sparse-to-dense palette remapping metadata. Existing scene,
sprite, packer, and runtime references use direct palette identity.
- Do not combine RGBA8888 channel-order work with palette-count semantics.
RGBA8888 defines each color value; `palette_count` defines how many palettes
are serialized and resident.
### References
- Runtime decision:
`../runtime/discussion/workflow/decisions/DEC-0041-variable-glyph-bank-palette-protocol.md`.
- Studio/packer decision:
`discussion/workflow/decisions/DEC-0038-variable-glyph-bank-palette-serialization.md`.
- `PLN-0087`: Variable glyph palette spec propagation.
- `PLN-0088`: Variable glyph palette metadata and count model.
- `PLN-0089`: Variable glyph palette payload emission and size accounting.
- `PLN-0090`: Studio and packer projections for variable glyph palettes.
- `PLN-0091`: Variable glyph palette tests, fixtures, and final validation.
- Prior lesson:
`discussion/lessons/DSC-0038-studio-packer-rgba8888-asset-pipeline/LSN-0053-rgba8888-is-the-canonical-studio-packer-palette-contract.md`.
- `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`.