Merge pull request 'dev/variable-tile-bank-palette-serialization' (#12) from dev/variable-tile-bank-palette-serialization into master
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

Reviewed-on: #12
This commit is contained in:
bquarkz 2026-07-14 15:47:50 +00:00
commit fa089c5cd0
25 changed files with 1428 additions and 1507 deletions

View File

@ -1,5 +1,5 @@
{"type":"meta","next_id":{"DSC":39,"AGD":42,"DEC":38,"PLN":87,"LSN":53,"CLSN":1}}
{"type":"discussion","id":"DSC-0038","status":"open","ticket":"studio-packer-rgba8888-asset-pipeline","title":"Studio and Packer RGBA8888 Asset Pipeline Alignment","created_at":"2026-05-23","updated_at":"2026-05-23","tags":["studio","packer","assets","glyph-bank","palette","rgba8888","runtime-alignment"],"agendas":[{"id":"AGD-0041","file":"AGD-0041-studio-packer-rgba8888-asset-pipeline.md","status":"accepted","created_at":"2026-05-23","updated_at":"2026-05-23"}],"decisions":[{"id":"DEC-0037","file":"DEC-0037-studio-packer-rgba8888-asset-pipeline.md","status":"accepted","created_at":"2026-05-23","updated_at":"2026-05-23","ref_agenda":"AGD-0041"}],"plans":[{"id":"PLN-0081","file":"PLN-0081-rgba8888-packer-and-studio-spec-propagation.md","status":"done","created_at":"2026-05-23","updated_at":"2026-05-23","ref_decisions":["DEC-0037"]},{"id":"PLN-0082","file":"PLN-0082-rgba8888-palette-model-and-argb-conversion.md","status":"done","created_at":"2026-05-23","updated_at":"2026-05-23","ref_decisions":["DEC-0037"]},{"id":"PLN-0083","file":"PLN-0083-rgba8888-glyph-payload-emission-and-sizes.md","status":"done","created_at":"2026-05-23","updated_at":"2026-05-23","ref_decisions":["DEC-0037"]},{"id":"PLN-0084","file":"PLN-0084-rgba8888-packer-projections-and-workspace-apis.md","status":"done","created_at":"2026-05-23","updated_at":"2026-05-23","ref_decisions":["DEC-0037"]},{"id":"PLN-0085","file":"PLN-0085-rgba8888-tests-fixtures-and-conformance.md","status":"done","created_at":"2026-05-23","updated_at":"2026-05-23","ref_decisions":["DEC-0037"]},{"id":"PLN-0086","file":"PLN-0086-rgba8888-final-integration-and-residue-removal.md","status":"done","created_at":"2026-05-23","updated_at":"2026-05-23","ref_decisions":["DEC-0037"]}],"lessons":[]}
{"type":"meta","next_id":{"DSC":39,"AGD":42,"DEC":39,"PLN":92,"LSN":54,"CLSN":1}}
{"type":"discussion","id":"DSC-0038","status":"done","ticket":"studio-packer-rgba8888-asset-pipeline","title":"Studio and Packer RGBA8888 Asset Pipeline Alignment","created_at":"2026-05-23","updated_at":"2026-07-14","tags":["studio","packer","assets","glyph-bank","palette","rgba8888","runtime-alignment"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0053","file":"discussion/lessons/DSC-0038-studio-packer-rgba8888-asset-pipeline/LSN-0053-rgba8888-is-the-canonical-studio-packer-palette-contract.md","status":"done","created_at":"2026-07-14","updated_at":"2026-07-14"}]}
{"type":"discussion","id":"DSC-0037","status":"done","ticket":"pbs-autocomplete-parameter-names","title":"PBS autocomplete parameter names for stdlib and method calls","created_at":"2026-05-08","updated_at":"2026-05-14","tags":["compiler-pbs","studio","lsp","autocomplete","signature-help","stdlib"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0052","file":"discussion/lessons/DSC-0037-pbs-autocomplete-parameter-names/LSN-0052-canonical-callable-parameter-names-through-pbs-editor-assistance.md","status":"done","created_at":"2026-05-14","updated_at":"2026-05-14"}]}
{"type":"discussion","id":"DSC-0036","status":"open","ticket":"pbs-symbol-documentation-and-hover-markdown","title":"Modelo de documentacao de simbolos em PBS e consumo markdown no hover","created_at":"2026-05-08","updated_at":"2026-05-08","tags":["compiler","compiler-pbs","studio","lsp","vscode","editor","hover","documentation","markdown"],"agendas":[{"id":"AGD-0039","file":"AGD-0039-pbs-symbol-documentation-and-hover-markdown.md","status":"open","created_at":"2026-05-08","updated_at":"2026-05-08"}],"decisions":[],"plans":[],"lessons":[]}
{"type":"discussion","id":"DSC-0035","status":"done","ticket":"pbs-lsp-editor-assistance-wave-1","title":"Wave 1 de assistencia editorial via LSP para PBS no VS Code","created_at":"2026-05-08","updated_at":"2026-05-08","tags":["studio","lsp","vscode","compiler","compiler-pbs","editor","completion","hover","signature-help"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0051","file":"discussion/lessons/DSC-0035-pbs-lsp-editor-assistance-wave-1/LSN-0051-compiler-backed-editor-assistance-for-pbs.md","status":"done","created_at":"2026-05-08","updated_at":"2026-05-08"}]}
@ -18,7 +18,7 @@
{"type":"discussion","id":"DSC-0002","status":"done","ticket":"palette-management-in-studio","title":"Palette Management in Studio","created_at":"2026-03-26","updated_at":"2026-04-23","tags":["studio","legacy-import","palette-management","tile-bank","packer-boundary"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0042","file":"discussion/lessons/DSC-0002-palette-management-in-studio/LSN-0042-schema-driven-palette-authoring-and-local-metadata-events.md","status":"done","created_at":"2026-04-23","updated_at":"2026-04-23"}]}
{"type":"discussion","id":"DSC-0003","status":"done","ticket":"packer-docs-import","title":"Import docs/packer into discussion-framework artifacts","created_at":"2026-03-26","updated_at":"2026-03-26","tags":["packer","migration","discussion-framework","docs-import"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0009","file":"discussion/lessons/DSC-0003-packer-docs-import/LSN-0009-mental-model-packer-legacy.md","status":"done","created_at":"2026-03-26","updated_at":"2026-03-26"},{"id":"LSN-0010","file":"discussion/lessons/DSC-0003-packer-docs-import/LSN-0010-asset-identity-and-runtime-contract-legacy.md","status":"done","created_at":"2026-03-26","updated_at":"2026-03-26"},{"id":"LSN-0011","file":"discussion/lessons/DSC-0003-packer-docs-import/LSN-0011-foundations-workspace-runtime-and-build-legacy.md","status":"done","created_at":"2026-03-26","updated_at":"2026-03-26"},{"id":"LSN-0012","file":"discussion/lessons/DSC-0003-packer-docs-import/LSN-0012-runtime-ownership-and-studio-boundary-legacy.md","status":"done","created_at":"2026-03-26","updated_at":"2026-03-26"},{"id":"LSN-0013","file":"discussion/lessons/DSC-0003-packer-docs-import/LSN-0013-metadata-convergence-and-runtime-sink-legacy.md","status":"done","created_at":"2026-03-26","updated_at":"2026-03-26"},{"id":"LSN-0014","file":"discussion/lessons/DSC-0003-packer-docs-import/LSN-0014-pack-wizard-summary-validation-and-pack-execution-legacy.md","status":"done","created_at":"2026-03-26","updated_at":"2026-03-26"},{"id":"LSN-0015","file":"discussion/lessons/DSC-0003-packer-docs-import/LSN-0015-tile-bank-packing-contract-legacy.md","status":"done","created_at":"2026-03-26","updated_at":"2026-03-26"},{"id":"LSN-0017","file":"discussion/lessons/DSC-0003-packer-docs-import/LSN-0017-packer-docs-import-pattern.md","status":"done","created_at":"2026-03-26","updated_at":"2026-03-26"}]}
{"type":"discussion","id":"DSC-0004","status":"abandoned","ticket":"tilemap-and-metatile-runtime-binary-layout","title":"Tilemap and Metatile Runtime Binary Layout","created_at":"2026-03-26","updated_at":"2026-04-24","tags":["packer","legacy-import","tilemap","metatile","runtime-layout"],"agendas":[{"id":"AGD-0004","file":"AGD-0004-tilemap-and-metatile-runtime-binary-layout.md","status":"abandoned","created_at":"2026-03-26","updated_at":"2026-04-24","_override_reason":"Explicit user request on 2026-04-24 to abandon AGD-0004 because the agenda is no longer valid."}],"decisions":[],"plans":[],"lessons":[]}
{"type":"discussion","id":"DSC-0005","status":"open","ticket":"variable-tile-bank-palette-serialization","title":"Variable Tile Bank Palette Serialization","created_at":"2026-03-26","updated_at":"2026-03-26","tags":["packer","legacy-import","tile-bank","palette-serialization","versioning"],"agendas":[{"id":"AGD-0005","file":"AGD-0005-variable-tile-bank-palette-serialization.md","status":"open","created_at":"2026-03-26","updated_at":"2026-03-26"}],"decisions":[],"plans":[],"lessons":[]}
{"type":"discussion","id":"DSC-0005","status":"open","ticket":"variable-tile-bank-palette-serialization","title":"Variable Glyph Bank Palette Serialization","created_at":"2026-03-26","updated_at":"2026-07-14","tags":["packer","legacy-import","glyph-bank","palette-serialization","rgba8888","runtime-alignment"],"agendas":[{"id":"AGD-0005","file":"AGD-0005-variable-tile-bank-palette-serialization.md","status":"accepted","created_at":"2026-03-26","updated_at":"2026-07-14"}],"decisions":[{"id":"DEC-0038","file":"DEC-0038-variable-glyph-bank-palette-serialization.md","status":"accepted","created_at":"2026-07-14","updated_at":"2026-07-14","ref_agenda":"AGD-0005"}],"plans":[{"id":"PLN-0087","file":"PLN-0087-variable-glyph-palette-spec-propagation.md","status":"done","created_at":"2026-07-14","updated_at":"2026-07-14","ref_decisions":["DEC-0038"]},{"id":"PLN-0088","file":"PLN-0088-variable-glyph-palette-metadata-and-count-model.md","status":"done","created_at":"2026-07-14","updated_at":"2026-07-14","ref_decisions":["DEC-0038"]},{"id":"PLN-0089","file":"PLN-0089-variable-glyph-palette-payload-emission-and-size-accounting.md","status":"done","created_at":"2026-07-14","updated_at":"2026-07-14","ref_decisions":["DEC-0038"]},{"id":"PLN-0090","file":"PLN-0090-studio-and-packer-projections-for-variable-glyph-palettes.md","status":"done","created_at":"2026-07-14","updated_at":"2026-07-14","ref_decisions":["DEC-0038"]},{"id":"PLN-0091","file":"PLN-0091-variable-glyph-palette-tests-fixtures-and-final-validation.md","status":"done","created_at":"2026-07-14","updated_at":"2026-07-14","ref_decisions":["DEC-0038"]}],"lessons":[]}
{"type":"discussion","id":"DSC-0006","status":"done","ticket":"pbs-game-facing-asset-refs-and-call-result-discard","title":"PBS Game-Facing Asset References and Ignored Call Result Lowering","created_at":"2026-03-27","updated_at":"2026-03-30","tags":["compiler","pbs","ergonomics","lowering","runtime","asset-identity","expression-statements"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0024","file":"discussion/lessons/DSC-0006-pbs-game-facing-asset-refs-and-call-result-discard/LSN-0024-addressable-surface-host-metadata-and-ignored-value-discipline.md","status":"done","created_at":"2026-03-30","updated_at":"2026-03-30"}]}
{"type":"discussion","id":"DSC-0007","status":"done","ticket":"pbs-learn-to-discussion-lessons-migration","title":"Migrate PBS Learn Documents into Discussion Lessons","created_at":"2026-03-27","updated_at":"2026-03-27","tags":["compiler","pbs","migration","discussion-framework","lessons","learn-prune"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0018","file":"discussion/lessons/DSC-0007-pbs-learn-to-discussion-lessons-migration/LSN-0018-pbs-ast-and-parser-contract-legacy.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27"},{"id":"LSN-0019","file":"discussion/lessons/DSC-0007-pbs-learn-to-discussion-lessons-migration/LSN-0019-pbs-name-resolution-and-linking-legacy.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27"},{"id":"LSN-0020","file":"discussion/lessons/DSC-0007-pbs-learn-to-discussion-lessons-migration/LSN-0020-pbs-runtime-values-identity-memory-boundaries-legacy.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27"},{"id":"LSN-0021","file":"discussion/lessons/DSC-0007-pbs-learn-to-discussion-lessons-migration/LSN-0021-pbs-diagnostics-and-conformance-governance-legacy.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27"},{"id":"LSN-0022","file":"discussion/lessons/DSC-0007-pbs-learn-to-discussion-lessons-migration/LSN-0022-pbs-globals-lifecycle-and-published-entrypoint-legacy.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27"}]}
{"type":"discussion","id":"DSC-0008","status":"done","ticket":"pbs-low-level-asset-manager-surface","title":"PBS Low-Level Asset Manager Surface for Runtime AssetManager","created_at":"2026-03-27","updated_at":"2026-03-27","tags":["compiler","pbs","runtime","asset-manager","host-abi","stdlib","asset"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0023","file":"discussion/lessons/DSC-0008-pbs-low-level-asset-manager-surface/LSN-0023-lowassets-runtime-aligned-sdk-surface.md","status":"done","created_at":"2026-03-27","updated_at":"2026-03-27"}]}

View File

@ -0,0 +1,108 @@
---
id: LSN-0053
ticket: studio-packer-rgba8888-asset-pipeline
title: RGBA8888 Is the Canonical Studio and Packer Palette Contract
created: 2026-07-14
tags:
- studio
- packer
- assets
- glyph-bank
- palette
- rgba8888
- runtime-alignment
---
# RGBA8888 Is the Canonical Studio and Packer Palette Contract
### Original Problem
The runtime moved to RGBA8888 as the canonical logical color and framebuffer
format, but Studio and packer still treated glyph-bank palettes as RGB565-era
data. The old pipeline exposed `convertedRgb565`, preserved ARGB as normal
projected metadata, reserved palette index `0` for transparency, flattened or
discarded alpha semantics, and carried magenta color-key behavior as a hidden
transparency shortcut.
That made the asset pipeline ambiguous. A glyph-bank asset could look valid to
Studio while still carrying palette data that no longer matched the runtime
contract.
### Consolidated Decision
`GLYPH/indexed_v1` remains the runtime-facing format name and keeps its
indexed/paletized glyph-bank identity. The incompatible change is inside the
palette contract:
1. `rgba8888` is the canonical authored, projected, and emitted palette field.
2. RGBA8888 values are interpreted as `0xRRGGBBAA` in runtime channel order.
3. Java `BufferedImage` ARGB values are input-only host API details and must be
converted deliberately at the packer boundary.
4. Palette index `0` is ordinary. Glyph palettes have 16 usable entries.
5. Transparency, including partial transparency, is represented only by alpha.
6. Magenta color-key behavior is not a normal Studio or packer feature.
7. RGB565 is not a compatibility path for runtime-facing glyph-bank palettes.
### Implementation Result
The packer specs now define glyph-bank palette metadata with `rgba8888`, and
the binary `GLYPH/indexed_v1` payload uses a `64 * 16 * 4 = 4096` byte palette
block instead of the old `64 * 16 * 2 = 2048` byte RGB565 block.
The packer palette model now carries canonical RGBA8888 values. Image import
converts Java ARGB pixels into runtime RGBA values before palette extraction,
and palette identity includes alpha. This allows transparent and partially
transparent colors to be distinct palette entries.
Packer read, detail, write, and cache paths now use `rgba8888` as the normal
metadata contract. Emission writes palette bytes in `R`, `G`, `B`, `A` order
and no longer emits a synthetic magenta entry for index `0`.
Tests and fixtures were updated to prove the new contract: RGBA channel order,
alpha preservation, 16 usable colors, index `0` as ordinary data, magenta as
ordinary color data, and 4096-byte palette blocks. Final validation confirmed
that remaining stale-looking references are either normative "not supported"
statements, historical discussion context, or explicitly out-of-scope generated
project cache data.
### Practical Pattern
When a host API exposes color in a different layout than the runtime contract,
name the boundary explicitly and keep the canonical field runtime-oriented.
For this pipeline:
- accept host ARGB only at import/read time;
- convert to RGBA8888 before storing palette metadata;
- project `rgba8888` to Studio and packer clients;
- emit RGBA bytes directly into `assets.pa`;
- convert back to UI-friendly ARGB only inside presentation code.
This keeps tooling convenient without letting host representation leak into the
runtime asset contract.
### Common Pitfalls and Anti-patterns
- Do not treat `originalArgb8888` as canonical pipeline data. ARGB can be a UI
or image-input representation, but `rgba8888` owns the contract.
- Do not reintroduce `convertedRgb565` as a normal projected field or emitted
payload. RGB565 compatibility was deliberately rejected for this path.
- Do not reserve palette index `0` for transparency. Alpha owns transparency.
- Do not use magenta as a hidden color key. A magenta RGBA value is just color
data unless an explicit future import tool defines a separate conversion.
- Do not change scene `palette_id` semantics as part of color-format work.
Scene records still reference glyph-bank palette indices.
- Do not fold `DSC-0005` variable palette-count work into RGBA8888 cleanup.
Palette encoding changed here; palette-count optimization remains separate.
### References
- `DEC-0037`: Studio and Packer RGBA8888 Asset Pipeline Contract.
- `PLN-0081`: Packer and Studio spec propagation.
- `PLN-0082`: Palette model and ARGB conversion boundary.
- `PLN-0083`: Glyph payload emission and size accounting.
- `PLN-0084`: Packer projections and workspace APIs.
- `PLN-0085`: Tests, fixtures, and conformance updates.
- `PLN-0086`: Final integration and residue removal.
- `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`.

View File

@ -1,87 +1,185 @@
---
id: AGD-0005
ticket: variable-tile-bank-palette-serialization
title: Variable Tile Bank Palette Serialization
status: open
title: Variable Glyph Bank Palette Serialization
status: accepted
created: 2026-03-26
resolved:
decision:
resolved: 2026-07-14
decision: DEC-0038
tags:
- packer
- legacy-import
- tile-bank
- glyph-bank
- palette-serialization
- versioning
- rgba8888
- runtime-alignment
---
## Pain
The current tile-bank contract serializes a fixed block of `64` palettes in v1 even when an asset authors far fewer palettes.
Domain owner: `packer`, with runtime-facing impact through `assets.pa`.
That keeps decoding simple, but it wastes cartridge space and leaves the system with a deliberate mismatch between authored and serialized palette counts.
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`
Domain owner: `docs/packer`
Cross-domain dependency:
- runtime
Current aligned v1 contract:
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 `RGB565 u16`;
- `palette_count = 64`;
- payload size includes a fixed `64 * 16 * 2` palette block.
- 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.
The packer now exposes:
Downstream producers must emit:
- `metadata.palette_count = 64`
- `metadata.palette_authored = <actual authored count>`
- 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
- [ ] Should variable palette serialization arrive as a new payload version or as an incompatible change to the current one?
- [ ] If `palette_count` becomes variable, should runtime still materialize a 64-slot resident bank, or truly shrink in-memory representation too?
- [ ] Should sparse authored palette indices remain sparse in serialization, or be canonicalized into a dense runtime block?
- [ ] Which domain owns compatibility for existing cartridges: `packer`, `runtime`, or `shipper`?
- [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
### 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 palette cost.
- **Con:** Every glyph bank keeps paying the full 4096-byte palette cost.
- **Maintainability:** Medium.
### Option B - Move to variable palette serialization now
- **Approach:** Serialize only authored palettes and shrink payload size immediately.
- **Pro:** Better cartridge efficiency and tighter semantics for `palette_count`.
- **Con:** Reopens a just-stabilized cross-domain runtime contract and forces compatibility decisions now.
- **Maintainability:** Medium if done carefully, risky if done incidentally.
### 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 v1 fixed and design variable serialization for v2
- **Approach:** Preserve v1 stability now and open a later versioned follow-up for variable palette serialization.
- **Pro:** Keeps current work stable while preserving a clean path for future optimization.
- **Con:** Known waste remains in v1.
- **Maintainability:** Strong.
### 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 agenda recommendation is already clear: the waste is real, but it is not a correctness bug, and reopening the runtime-facing contract immediately would mix optimization work into a freshly stabilized path.
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.
That makes versioned follow-up a cleaner vehicle than incidental mutation of the current contract.
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 C**.
Recommended direction: adopt **Option B**.
Imported retained recommendation:
Updated recommendation:
1. keep the current fixed 64-palette contract for v1;
2. if variable serialization is desired, design it explicitly as a versioned follow-up;
3. treat compatibility, runtime representation, and sparse-vs-dense palette identity as explicit next-wave questions rather than silent payload tweaks.
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: if the team wants to remove the fixed padding, open the corresponding runtime-side discussion and close the versioning/compatibility story before planning implementation.
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.

View File

@ -1,273 +0,0 @@
---
id: AGD-0041
ticket: studio-packer-rgba8888-asset-pipeline
title: Agenda - Studio and Packer RGBA8888 Asset Pipeline Alignment
status: accepted
created: 2026-05-23
resolved: 2026-05-23
decision: DEC-0037
tags:
- studio
- packer
- assets
- glyph-bank
- palette
- rgba8888
- runtime-alignment
---
## Pain
Domain owner: `studio`, with direct subdomain ownership in `packer` and
cross-domain dependency on `runtime`.
The runtime RGBA8888 migration changes the color contract underneath the Studio
asset pipeline. Runtime `DEC-0029` says RGBA8888 is the single canonical logical
color and physical framebuffer format, and that asset packages must encode
palettes as RGBA8888 without preserving RGB565 compatibility.
Studio still carries RGB565 in the packer-facing asset pipeline:
- `docs/specs/packer/4. Build Artifacts and Deterministic Packing Specification.md`
defines `GLYPH/indexed_v1` palette payloads as `64 * 16 * 2` bytes of
little-endian `RGB565` values.
- `PackerPaletteV1` stores both `originalArgb8888` and `convertedRgb565`.
- `PackerGlyphBankWalker` drops partial alpha, treats alpha 0 and magenta as
transparent index `0`, stores only RGB identity for palette lookup, and
converts palette colors to RGB565.
- `PackerAssetDetailsService`, `PackerReadMessageMapper`, test fixtures, and
project `asset.json` files expose `convertedRgb565` as normal pipeline data.
The problem is not only changing one serializer. The Studio/packer side must
decide how authoring metadata, palette UI/data, emitted `assets.pa`, tests, and
existing project fixtures align with runtime RGBA channel order and meaningful
alpha.
## Context
Runtime discussion context:
- `../runtime/discussion/workflow/agendas/AGD-0037-rgba8888-framebuffer-and-pixel-format-direction.md`
was consulted as the originating discussion.
- `../runtime/discussion/workflow/decisions/DEC-0029-rgba8888-runtime-pixel-format-contract.md`
is accepted and normative for runtime.
- Runtime plans already split execution across specs, HAL/ABI, renderer,
asset palettes/tooling, host presentation, and validation.
Relevant runtime invariants for this Studio discussion:
- raw color values use RGBA channel order;
- asset package palettes must be RGBA8888;
- old RGB565 palette assets are not compatible runtime input;
- indexed tile/sprite payloads may remain indexed/paletized;
- transparency is represented by alpha in the resolved palette entry, not by
reserving palette index `0` as a special transparent index;
- RGB565 helpers may exist only as temporary migration utilities, not the
normal runtime path.
Relevant Studio/packer state:
- `assets.pa` is the authoritative runtime-facing artifact owned by the packer.
- `output.pipeline` is tooling-only by default, but current glyph palette data
lives there and is used by packer details/read flows.
- `GLYPH/indexed_v1` currently emits a fixed 256x256 packed `u4` pixel plane
plus a fixed 64-palette RGB565 block.
- `DSC-0005` is still open around variable tile-bank palette serialization.
That discussion optimizes fixed-vs-variable palette count. RGBA8888 changes
the color encoding and transparency semantics first, so it should supersede
or reframe any RGB565 assumptions before variable palette work continues.
- Studio scene publication currently carries `palette_id` in scene pack
requests. Scene payload shape is mostly unaffected by color format, but scene
previews, palette defaults, validation, and any editor-visible palette data
must remain consistent with the glyph-bank contract.
## Open Questions
- [x] Should Studio keep the runtime-facing format name `GLYPH/indexed_v1` and
make it an incompatible v1 contract update, or should packer emit a new
explicit format/version such as `GLYPH/indexed_rgba8888_v1`?
- Keep `GLYPH/indexed_v1`. The structural change is in palette encoding; the
remaining glyph payload model stays stable.
- [x] What is the canonical authoring-side palette field name: keep
`originalArgb8888`, rename to `rgba8888`, or store structured channel data?
- Use `rgba8888` unless the decision stage finds a concrete tooling reason to
choose a more explicit variant.
- [x] How should Java `BufferedImage` ARGB input be converted to runtime RGBA
raw values without confusing storage order, JSON numeric representation, or
signed `int` display in tooling?
- Convert ARGB input to RGBA output directly at the packer boundary.
- [x] Does palette index `0` remain an ordinary palette slot immediately, as
runtime `DEC-0029` requires, or does Studio need a temporary migration step to
rewrite existing transparent-index assets into alpha-bearing palette entries?
- Palette index `0` becomes an ordinary palette slot. Glyph palettes therefore
have 16 usable colors, not 15 plus a reserved transparent index.
- [x] Should magenta color-key support disappear from Studio authoring now, or
survive only as an explicit import/conversion helper outside the normal pack
path?
- Magenta color-key support should disappear completely.
- [x] Should partial alpha in PNG tiles become first-class palette data, or
should the packer still reject/diagnose partial alpha until renderer behavior
is fully proven?
- Partial alpha becomes valid palette data now. Existing validations and
warnings that flatten or reject partial alpha should be removed.
- [x] Which existing fixtures and sample projects should be regenerated versus
deleted because they encode RGB565-specific expectations?
- `main` and `fragments` will be regenerated manually later; they should not
block the Studio/packer decision.
- [x] How should this agenda relate to `DSC-0005`: close it as superseded,
revise it after RGBA8888, or keep it open as a later palette-count
optimization?
- `DSC-0005` remains a later step. RGBA8888 should not absorb variable
palette-count serialization.
## Options
### Option A - Minimal serializer swap inside current names
- **Approach:** Keep current public names and `GLYPH/indexed_v1`, replace the
palette block with fixed `64 * 16 * 4` RGBA8888 entries, remove
`convertedRgb565`, and update tests/specs in place.
- **Pro:** Smallest naming churn and likely the fastest path to unblock runtime
asset decode.
- **Con:** The `v1` label would silently change binary meaning, which is risky
for fixtures, docs, and any stale build output.
- **Maintainability:** Medium. Fast, but it relies on the repository accepting a
coordinated breaking change with no compatibility ambiguity.
### Option B - Explicit RGBA8888 glyph payload format
- **Approach:** Add an explicit runtime-facing glyph format/version for the
RGBA8888 palette payload, retire RGB565 output from the normal pack path, and
update asset declarations, specs, materialization, tests, fixtures, and sample
projects to the new format.
- **Pro:** Makes the breaking contract visible in file format names, tests, and
diagnostics while still obeying the runtime decision not to support RGB565 as
compatible input.
- **Con:** More code and fixture churn; requires clear migration handling for
stale project declarations and generated build artifacts.
- **Maintainability:** Strong. The format boundary becomes explicit and easier
to audit.
### Option C - Broaden the wave into full palette model redesign
- **Approach:** Use the RGBA8888 migration to redesign palette count, sparse vs
dense indices, material palettes, import/export, alpha authoring UI, and scene
palette defaults in one decision.
- **Pro:** Could produce a cleaner long-term asset model and resolve `DSC-0005`
at the same time.
- **Con:** Mixes a mandatory runtime alignment with optional model improvements,
increasing risk and delaying the renderer/asset migration.
- **Maintainability:** Weak for this wave. Better reserved for follow-up after
the RGBA8888 contract is stable.
## Discussion
The discussion converged toward an in-place `GLYPH/indexed_v1` structural
update rather than a new format name. This keeps the glyph-bank identity stable:
indexed pixels, fixed emitted sheet shape, scene `palette_id` references, and
the broad runtime glyph-bank model remain the same. The incompatible change is
the palette block and palette metadata moving from RGB565-derived values to raw
RGBA8888.
The authoring/read projection should expose `rgba8888` as the canonical palette
field. Java image inputs may still arrive as ARGB through `BufferedImage`, but
that is an input representation only. The packer boundary converts ARGB to
runtime RGBA and the rest of the pipeline should speak RGBA8888.
Palette index `0` is no longer special. It becomes a normal usable palette
entry, which gives glyph palettes 16 usable colors. Transparency comes from the
alpha byte in the RGBA8888 palette value. As a consequence, the old magenta
color-key behavior should be removed completely, not retained as a normal
authoring shortcut or hidden compatibility rule.
Partial alpha is valid data in this model. The packer should preserve it in the
palette instead of warning, flattening, or rejecting it. Existing validations
around partial alpha and the 15-color limit are therefore stale and should be
rewritten around the new 16-entry RGBA palette contract.
Existing sample projects and fixtures that still carry RGB565 assumptions are
not part of the discussion blocker. `main` and `fragments` will be regenerated
later. `DSC-0005` remains a separate future discussion for palette-count
serialization and should not be folded into this RGBA8888 wave.
## Tradeoffs
### Compatibility vs explicit break
Runtime `DEC-0029` already rejects RGB565 compatibility for this migration.
Studio therefore should not preserve RGB565 input as a normal path. The open
tradeoff is whether the packer should make the break visible through a new
format/version or simply mutate the existing v1 meaning.
### Authoring convenience vs runtime truth
Java image tooling naturally reads pixels as ARGB ints. Runtime wants raw RGBA
channel order. Studio can keep ARGB only as an import-side implementation detail,
but packer output, public metadata, and tests need one unambiguous RGBA8888
representation.
### Indexed art identity vs alpha semantics
The indexed/palette model can remain. What changes is that every palette entry,
including index `0`, should be a real RGBA color. Transparent pixels should be
encoded by alpha, not by a hardwired index rule or magenta color key.
### Scope control vs complete cleanup
It is tempting to combine RGBA8888 with variable palette serialization from
`DSC-0005`. That should be resisted unless the decision explicitly expands
scope. RGBA8888 changes bytes per palette entry and transparency semantics;
palette count optimization is a separate axis.
## Recommendation
Adopt a refined Option A.
The Studio/packer decision should keep `GLYPH/indexed_v1` as the runtime-facing
format name, but redefine its palette block and palette metadata around
RGBA8888. This is an intentional structural break in the palette contract, not
a new glyph-bank format.
The recommended shape for the decision is:
1. emit palette entries as raw RGBA8888 values in runtime RGBA channel order;
2. replace `convertedRgb565` with canonical `rgba8888` data in authoring and
read/detail projections;
3. treat Java/PNG ARGB as an input decoding detail and convert deliberately at
the packer boundary;
4. make palette index `0` ordinary, yielding 16 usable palette entries;
5. represent transparency and partial transparency only through RGBA alpha;
6. remove magenta color-key behavior completely;
7. remove partial-alpha flattening/rejection and preserve partial alpha as
valid palette data;
8. preserve fixed 64-palette serialization for this wave unless a decision
explicitly revises `DSC-0005`;
9. regenerate or rewrite RGB565 fixtures instead of supporting stale RGB565
assets at runtime.
## Next Step
The agenda is ready to move to decision if the refined recommendation is
accepted.
The next artifact should be a Studio/packer decision that references runtime
`DEC-0029`, leaves `DSC-0005` for a later palette-count step, and defines
propagation targets for:
- `docs/specs/packer`;
- `docs/specs/studio`;
- `prometeu-packer` models, walkers, serializers, services, fixtures, and
tests;
- sample project assets;
- any Studio asset workspace UI/read projections that expose palette data.
## Resolution
Accepted on 2026-05-23.
The discussion is closed in favor of decision `DEC-0037`. The accepted
direction keeps `GLYPH/indexed_v1`, moves its palette contract to RGBA8888,
uses `rgba8888` as the canonical palette field, makes palette index `0`
ordinary, removes magenta color-key behavior completely, accepts partial alpha
as valid palette data, and leaves `DSC-0005` for a later palette-count
serialization step.

View File

@ -1,228 +0,0 @@
---
id: DEC-0037
ticket: studio-packer-rgba8888-asset-pipeline
title: Studio and Packer RGBA8888 Asset Pipeline Contract
status: accepted
created: 2026-05-23
accepted: 2026-05-23
ref_agenda: AGD-0041
plans:
- PLN-0081
- PLN-0082
- PLN-0083
- PLN-0084
- PLN-0085
- PLN-0086
tags:
- studio
- packer
- assets
- glyph-bank
- palette
- rgba8888
- runtime-alignment
---
## Status
Accepted. Drafted from accepted agenda `AGD-0041` and accepted on
2026-05-23.
## Context
Runtime `DEC-0029` makes RGBA8888 the canonical logical color representation
and physical framebuffer format for Prometeu. It also requires asset package
palettes to use RGBA8888, rejects RGB565 compatibility as normal runtime input,
and defines transparency through alpha rather than a reserved palette index.
Studio embeds the packer and owns the asset authoring and publication pipeline
that emits `assets.pa`. Before this decision, the Studio/packer glyph-bank path
still carried RGB565 assumptions:
- `GLYPH/indexed_v1` palette payloads were specified as fixed
`64 * 16 * 2` RGB565 `u16` values.
- `PackerPaletteV1` exposed `originalArgb8888` and `convertedRgb565`.
- `PackerGlyphBankWalker` flattened partial alpha, treated alpha zero and
magenta as transparent index `0`, limited authored colors to 15 usable
entries, and converted colors to RGB565.
- Studio/packer read projections, details APIs, fixtures, and sample assets
exposed `convertedRgb565` as ordinary pipeline data.
The runtime decision is already normative for the color contract. This decision
locks how Studio and packer align their glyph-bank asset pipeline with it.
## Decision
Studio and packer SHALL keep the runtime-facing glyph payload format name
`GLYPH/indexed_v1`.
The `GLYPH/indexed_v1` glyph-bank model SHALL remain indexed/paletized. Indexed
pixel payloads, fixed emitted sheet shape, scene `palette_id` references, and
the broad glyph-bank identity remain stable.
The structural change is the palette contract. `GLYPH/indexed_v1` palette data
MUST move from RGB565-derived values to RGBA8888 values in runtime RGBA channel
order.
Packer output, packer metadata, Studio read/detail projections, tests, and
fixtures MUST stop treating RGB565 as the normal palette representation.
`convertedRgb565` MUST be removed from the normal authored and projected
palette contract.
The canonical authored/projected palette field for this wave SHALL be
`rgba8888`.
Java `BufferedImage` and PNG inputs MAY be read as ARGB by host APIs, but ARGB
is only an input representation. The packer boundary MUST convert ARGB input to
runtime RGBA8888 output deliberately before emitting or projecting canonical
palette data.
Palette index `0` MUST be an ordinary palette index. Glyph palettes SHALL have
16 usable entries, not 15 usable entries plus a reserved transparent index.
Transparency and partial transparency MUST be represented only by the alpha
channel in the RGBA8888 palette value.
Magenta color-key behavior MUST be removed completely from the normal Studio
and packer asset pipeline. Magenta MUST NOT remain a hidden compatibility rule,
normal authoring shortcut, or runtime-facing transparency encoding.
Partial alpha in PNG/glyph inputs SHALL be valid palette data. Packer behavior
that warns about, flattens, rejects, or otherwise strips partial alpha MUST be
removed or rewritten around the RGBA8888 palette contract.
The fixed 64-palette serialization model remains in scope for this wave unless
another accepted decision explicitly revises it. `DSC-0005` remains a later
palette-count serialization discussion and MUST NOT be folded into this
RGBA8888 migration by implication.
Existing `main` and `fragments` sample project assets may be regenerated
manually later. Their regeneration is not a blocker for this decision and MUST
NOT justify preserving RGB565 compatibility in the packer.
## Rationale
Keeping `GLYPH/indexed_v1` avoids renaming a format whose core identity remains
the same: indexed glyph pixels resolved through palettes. The incompatible part
is specifically the palette encoding and transparency semantics.
Making RGBA8888 the normal packer-side representation aligns Studio with
runtime `DEC-0029` without introducing a parallel RGB565 compatibility path.
This keeps the asset pipeline direct: authoring input is normalized once at the
packer boundary, and emitted runtime artifacts carry the runtime color contract.
Treating index `0` as ordinary is required because transparency now belongs to
the alpha channel. This also gives each glyph palette the full 16 authored
entries available from the indexed payload.
Removing magenta color-key behavior avoids a second transparency mechanism that
would conflict with meaningful alpha. Allowing partial alpha preserves source
image information and supports the broader RGBA8888 renderer direction.
Keeping fixed 64-palette serialization separates mandatory color-format
migration from later payload-size optimization. Palette count and sparse/dense
serialization remain independent questions.
## Technical Specification
### Runtime-Facing Glyph Payload
- The format name remains `GLYPH/indexed_v1`.
- The indexed pixel plane remains packed `u4`.
- The emitted glyph-bank sheet shape remains unchanged for this wave.
- The palette block changes from 2-byte RGB565 entries to 4-byte RGBA8888
entries.
- The fixed palette block remains `64 * 16` entries for this wave.
- The byte-size formula for the palette block MUST be updated from
`64 * 16 * 2` to `64 * 16 * 4`.
- Size and decoded-size formulas for glyph-bank payloads MUST be updated
accordingly.
- Palette bytes MUST be interpreted as runtime RGBA channel order.
### Authored and Projected Palette Data
- Canonical palette data exposed by Studio/packer SHALL use `rgba8888`.
- `convertedRgb565` SHALL be removed from normal authored pipeline metadata,
details projections, read projections, fixtures, and tests.
- `originalArgb8888` SHALL NOT be the canonical field for runtime-facing or
packer-projected palette data in this wave.
- ARGB values read from Java image APIs MUST be converted to RGBA8888 before
entering canonical packer metadata or emitted payloads.
### Transparency and Alpha
- Palette index `0` is ordinary.
- A glyph palette has 16 usable entries.
- Alpha `0`, alpha between `1` and `254`, and alpha `255` are all valid
palette-entry states.
- Partial alpha MUST be preserved as data.
- Packer warnings or validations that describe partial alpha as flattened,
ignored, or unsupported MUST be removed.
- Color limit validation MUST be rewritten for 16 usable palette entries.
### Removed Behaviors
- RGB565 palette emission is not a normal packer output.
- RGB565 palette projection is not a normal Studio/packer read or details
contract.
- Magenta color-key transparency is not supported in the normal path.
- Palette index `0` is not reserved for transparency.
- Runtime asset compatibility with stale RGB565 palette payloads is not a
Studio/packer requirement for this wave.
## 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 read/projection behavior is documented there.
### Code
- `prometeu-packer` palette model types.
- `PackerGlyphBankWalker`.
- `PackerAssetWalker` glyph-bank size and metadata calculations.
- `PackerAssetDetailsService`.
- `PackerReadMessageMapper`.
- Any packer serializer/materializer that emits `assets.pa` glyph payloads.
- Studio asset workspace read/detail surfaces that display or depend on
palette metadata.
### Tests and Fixtures
- Packer glyph-bank walker tests.
- Asset declaration parser tests that mention `convertedRgb565`.
- Runtime asset materializer tests.
- File-system workspace service tests.
- Fixture `asset.json` files that still declare RGB565-derived palette data.
- Test expectations for alpha, 16 usable colors, and removed magenta color-key
behavior.
`main` and `fragments` project assets are expected to be regenerated manually
later and are not blockers for this decision.
## Constraints
- This decision MUST NOT introduce an RGB565 compatibility mode.
- This decision MUST NOT rename the runtime-facing format away from
`GLYPH/indexed_v1`.
- This decision MUST NOT change scene `palette_id` semantics except as needed
to ensure referenced glyph palettes now resolve RGBA8888 entries.
- This decision MUST NOT decide variable palette-count serialization.
- This decision MUST NOT close or revise `DSC-0005`; that discussion remains a
later palette-count optimization track.
- Any implementation plan derived from this decision MUST preserve all
normative requirements above unless the user explicitly requests a decision
revision.
## References
- Agenda: `AGD-0041`
- Runtime decision: `../runtime/discussion/workflow/decisions/DEC-0029-rgba8888-runtime-pixel-format-contract.md`
- Related future discussion: `DSC-0005`
## Revision Log
- 2026-05-23: Initial accepted decision from `AGD-0041`.

View File

@ -0,0 +1,208 @@
---
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`.

View File

@ -1,136 +0,0 @@
---
id: PLN-0081
ticket: studio-packer-rgba8888-asset-pipeline
title: RGBA8888 Packer and Studio Spec Propagation
status: done
created: 2026-05-23
completed: 2026-05-23
ref_decisions:
- DEC-0037
tags:
- specs
- packer
- studio
- rgba8888
---
## Objective
Propagate `DEC-0037` into the normative Studio and packer specifications before
code implementation starts.
## Background
`DEC-0037` keeps `GLYPH/indexed_v1` but changes its palette contract from
RGB565 to RGBA8888. Specs currently still describe RGB565 palette bytes,
`convertedRgb565`, and a 2048-byte palette block.
## Scope
### Included
- Update packer specs for `asset.json` palette metadata and `assets.pa`
glyph-bank payload layout.
- Update Studio asset workspace specs if they expose palette metadata or
details/read projection behavior.
- Preserve the fixed 64-palette model and explicitly leave `DSC-0005` for a
later palette-count optimization.
### Excluded
- Code changes.
- Test changes.
- Variable palette-count serialization.
- Runtime spec changes, except references to runtime `DEC-0029`.
## Execution Steps
### Step 1 - Update asset declaration palette fields
**What:** Replace `originalArgb8888`/`convertedRgb565` examples and rules with
canonical `rgba8888`.
**How:** Edit the palette portions of the asset declaration spec so
`output.pipeline.palettes[*].palette.rgba8888` is the canonical field. State
that ARGB may be an input API detail but is not canonical authored/projected
palette data.
**File(s):**
- `docs/specs/packer/3. Asset Declaration and Virtual Asset Contract Specification.md`
### Step 2 - Update glyph-bank payload layout
**What:** Change `GLYPH/indexed_v1` palette layout from RGB565 to RGBA8888.
**How:** Keep the format name. Change the palette block from
`64 * 16 * 2 = 2048` bytes to `64 * 16 * 4 = 4096` bytes. Update size and
decoded-size formulas. State that palette entries use runtime RGBA channel
order.
**File(s):**
- `docs/specs/packer/4. Build Artifacts and Deterministic Packing Specification.md`
### Step 3 - Document alpha and index semantics
**What:** Document that palette index `0` is ordinary and all 16 palette entries
are usable.
**How:** Add normative rules that transparency and partial transparency are
encoded only by RGBA alpha, magenta color-key is removed, and partial alpha is
valid palette data.
**File(s):**
- `docs/specs/packer/3. Asset Declaration and Virtual Asset Contract Specification.md`
- `docs/specs/packer/4. Build Artifacts and Deterministic Packing Specification.md`
### Step 4 - Update Studio-facing projection rules
**What:** Ensure Studio-facing docs use `rgba8888` where palette metadata is
visible.
**How:** Update asset workspace language only where it describes palette read,
details, scene preview, or palette default behavior. Keep scene `palette_id`
semantics unchanged.
**File(s):**
- `docs/specs/studio/4. Assets Workspace Specification.md`
## Test Requirements
### Unit Tests
- Not applicable for this spec-only plan.
### Integration Tests
- Not applicable for this spec-only plan.
### Manual Verification
- Search specs for stale `RGB565`, `convertedRgb565`, 2048-byte palette block,
reserved index `0`, and magenta color-key language.
## Acceptance Criteria
- [x] Packer specs define `rgba8888` as the canonical palette field.
- [x] `GLYPH/indexed_v1` remains named exactly that.
- [x] Palette block formulas use `64 * 16 * 4 = 4096`.
- [x] Specs state palette index `0` is ordinary and all 16 entries are usable.
- [x] Specs state partial alpha is valid and magenta color-key is removed.
- [x] Specs leave `DSC-0005` variable palette-count work out of scope.
## Dependencies
- Depends on accepted `DEC-0037`.
- Should complete before code plans are implemented.
## Risks
- Leaving stale RGB565 examples in specs will make implementation review
ambiguous.
- Over-editing scene specs could accidentally imply a scene payload change that
`DEC-0037` does not authorize.

View File

@ -1,144 +0,0 @@
---
id: PLN-0082
ticket: studio-packer-rgba8888-asset-pipeline
title: RGBA8888 Palette Model and ARGB Conversion
status: done
created: 2026-05-23
completed: 2026-05-23
ref_decisions:
- DEC-0037
tags:
- packer
- palette
- rgba8888
- conversion
---
## Objective
Replace the packer palette model with canonical RGBA8888 data and introduce a
single deliberate ARGB-to-RGBA conversion boundary for image inputs.
## Background
`PackerPaletteV1` currently stores `originalArgb8888` and `convertedRgb565`.
`PackerGlyphBankWalker` reads Java ARGB pixels, drops alpha semantics, reserves
index `0`, applies magenta color-key, and converts colors to RGB565.
## Scope
### Included
- Replace `PackerPaletteV1` fields with canonical `rgba8888`.
- Add or localize ARGB-to-RGBA conversion helpers.
- Preserve partial alpha.
- Remove RGB565 conversion from the normal palette model.
- Expand glyph palette extraction from 15 to 16 usable colors.
### Excluded
- Binary `assets.pa` emission changes.
- Read/detail API projection changes outside direct model compile fixes.
- Spec edits.
- Fixture regeneration for `main` and `fragments`.
## Execution Steps
### Step 1 - Replace the palette record
**What:** Change the packer palette model to carry canonical RGBA8888 values.
**How:** Replace `int[] originalArgb8888, short[] convertedRgb565` with
`int[] rgba8888`. Keep the record name only if it remains semantically useful;
otherwise rename only if all callers are updated in the same change.
**File(s):**
- `prometeu-packer/prometeu-packer-v1/src/main/java/p/packer/models/PackerPaletteV1.java`
### Step 2 - Convert ARGB image pixels to RGBA
**What:** Introduce one conversion path from Java `BufferedImage` ARGB to raw
runtime RGBA.
**How:** Convert `0xAARRGGBB` to `0xRRGGBBAA` when building palette entries.
Do not store ARGB in canonical packer metadata.
**File(s):**
- `prometeu-packer/prometeu-packer-v1/src/main/java/p/packer/repositories/PackerGlyphBankWalker.java`
### Step 3 - Remove magenta color-key and reserved index behavior
**What:** Stop treating alpha zero or magenta as special palette-index behavior.
**How:** Remove `COLOR_KEY_RGB`. Build palette identity from full RGBA8888
values, including alpha. Assign indices from `0` through `15`.
**File(s):**
- `prometeu-packer/prometeu-packer-v1/src/main/java/p/packer/repositories/PackerGlyphBankWalker.java`
### Step 4 - Preserve partial alpha
**What:** Remove partial-alpha warnings and flattening.
**How:** Delete the `partialAlphaFound` warning path. Ensure pixels with alpha
from `0` through `255` participate in palette extraction by full RGBA value.
**File(s):**
- `prometeu-packer/prometeu-packer-v1/src/main/java/p/packer/repositories/PackerGlyphBankWalker.java`
### Step 5 - Update color-limit validation
**What:** Change validation from 15 usable colors to 16 usable colors.
**How:** Replace `MAX_COLORS_PER_PALETTE = 15` with a 16-entry limit and update
diagnostic wording to remove `indices 1..15`.
**File(s):**
- `prometeu-packer/prometeu-packer-v1/src/main/java/p/packer/repositories/PackerGlyphBankWalker.java`
## Test Requirements
### Unit Tests
- Update `PackerGlyphBankWalkerTest` to assert:
- 16 unique RGBA colors are valid.
- a 17th unique RGBA color is blocking.
- alpha `0`, partial alpha, and alpha `255` are preserved.
- magenta is treated as an ordinary color.
- palette index `0` can hold an ordinary color.
### Integration Tests
- None for this plan; binary emission is covered by a later plan.
### Manual Verification
- Search packer model and glyph walker sources for `convertedRgb565`,
`originalArgb8888`, `COLOR_KEY_RGB`, `convertToRgb565`, and partial-alpha
warning text.
## Acceptance Criteria
- [x] `PackerPaletteV1` exposes `rgba8888` and no RGB565 field.
- [x] `PackerGlyphBankWalker` stores canonical RGBA values.
- [x] Magenta is not special.
- [x] Alpha zero and partial alpha are valid palette data.
- [x] All 16 palette indices are usable.
- [x] Unit tests cover conversion and palette indexing semantics.
## Dependencies
- Depends on `PLN-0081` for spec wording.
- Must complete before payload emission and projection plans.
## Risks
- Confusing Java ARGB input with runtime RGBA output will create hard-to-debug
byte-order failures.
- Cache reuse may keep stale palette metadata if reusable metadata checks are
not updated with the model change.

View File

@ -1,145 +0,0 @@
---
id: PLN-0083
ticket: studio-packer-rgba8888-asset-pipeline
title: RGBA8888 Glyph Payload Emission and Size Accounting
status: done
created: 2026-05-23
completed: 2026-05-23
ref_decisions:
- DEC-0037
tags:
- packer
- assets-pa
- glyph-bank
- rgba8888
---
## Objective
Change packer glyph-bank runtime payload emission from RGB565 palette bytes to
RGBA8888 palette bytes while keeping `GLYPH/indexed_v1` and the fixed
64-palette model.
## Background
`DEC-0037` requires `GLYPH/indexed_v1` to retain its format name and indexed
model but emit RGBA8888 palette entries. Current payload emission in
`FileSystemPackerWorkspaceService` writes RGB565 bytes, reserves index `0`, and
uses color-key bytes.
## Scope
### Included
- Update glyph-bank payload palette byte emission.
- Update measured payload size and decoded-size accounting.
- Remove RGB565 palette constants and palette color-key bytes from emission.
- Keep scene `palette_id` payload semantics unchanged.
### Excluded
- Palette model extraction changes covered by `PLN-0082`.
- Read/detail projection changes covered by `PLN-0084`.
- Variable palette count.
## Execution Steps
### Step 1 - Update glyph payload constants and formulas
**What:** Change palette entry width from 2 bytes to 4 bytes.
**How:** Introduce clear constants for palette count, colors per palette, and
RGBA bytes per color. Use `64 * 16 * 4` for palette block size.
**File(s):**
- `prometeu-packer/prometeu-packer-v1/src/main/java/p/packer/services/FileSystemPackerWorkspaceService.java`
- `prometeu-packer/prometeu-packer-v1/src/main/java/p/packer/repositories/PackerAssetWalker.java`
- `prometeu-packer/prometeu-packer-v1/src/main/java/p/packer/repositories/PackerRuntimeAssetMaterializer.java`
### Step 2 - Emit RGBA8888 palette bytes
**What:** Write each palette color as runtime RGBA channel bytes.
**How:** Replace RGB565 little-endian writes with four byte writes in `R`, `G`,
`B`, `A` order derived from the canonical `rgba8888` integer value.
**File(s):**
- `prometeu-packer/prometeu-packer-v1/src/main/java/p/packer/services/FileSystemPackerWorkspaceService.java`
### Step 3 - Remove reserved color-key emission
**What:** Stop writing a synthetic color-key value at palette index `0`.
**How:** Remove `GLYPH_BANK_COLOR_KEY_RGB565` and any emission path that fills
index `0` with magenta. Emit declared RGBA values for index `0` like every
other index.
**File(s):**
- `prometeu-packer/prometeu-packer-v1/src/main/java/p/packer/services/FileSystemPackerWorkspaceService.java`
### Step 4 - Update declared palette lookup
**What:** Read `rgba8888` from declared pipeline metadata.
**How:** Replace `originalArgb8888`/`convertedRgb565` lookup paths with
`rgba8888`. Ensure empty or malformed `rgba8888` is structural failure where
emission requires a palette.
**File(s):**
- `prometeu-packer/prometeu-packer-v1/src/main/java/p/packer/services/FileSystemPackerWorkspaceService.java`
- `prometeu-packer/prometeu-packer-v1/src/main/java/p/packer/repositories/PackerAssetWalker.java`
### Step 5 - Keep scene payload stable
**What:** Preserve scene `palette_id` layout.
**How:** Do not change `writeSceneBankPayload` except compile fixes caused by
shared helper changes. Scene tile records continue carrying `palette_id` as an
index into the referenced glyph palette.
**File(s):**
- `prometeu-packer/prometeu-packer-v1/src/main/java/p/packer/services/FileSystemPackerWorkspaceService.java`
## Test Requirements
### Unit Tests
- Add or update tests asserting glyph payload size includes a 4096-byte palette
block.
- Assert emitted palette bytes for a known RGBA value, including alpha.
- Assert index `0` emits declared RGBA data, not magenta.
### Integration Tests
- Update workspace build tests that read `build/assets.pa` and assert glyph-bank
offsets/sizes.
### Manual Verification
- Search production packer code for `GLYPH_BANK_COLOR_KEY_RGB565`,
`convertedRgb565`, RGB565 palette byte writes, and hard-coded `2048`.
## Acceptance Criteria
- [x] Glyph payloads keep `GLYPH/indexed_v1`.
- [x] Glyph palette blocks are 4096 bytes.
- [x] Palette entries are emitted as RGBA bytes in runtime channel order.
- [x] No synthetic magenta/color-key value is emitted.
- [x] Size and decoded-size metadata match the new payload length.
- [x] Scene `palette_id` payload shape is unchanged.
## Dependencies
- Depends on `PLN-0082`.
- Should run before tests/fixture conformance in `PLN-0085`.
## Risks
- Updating size formulas without updating emitted bytes, or vice versa, will
corrupt payload slicing in `assets.pa`.
- Accidental scene payload edits could widen the change beyond `DEC-0037`.

View File

@ -1,141 +0,0 @@
---
id: PLN-0084
ticket: studio-packer-rgba8888-asset-pipeline
title: RGBA8888 Packer Projections and Workspace APIs
status: done
created: 2026-05-23
completed: 2026-05-23
ref_decisions:
- DEC-0037
tags:
- packer
- studio
- api
- rgba8888
---
## Objective
Update packer and Studio-facing read/detail/write projections so palette data
is exposed and accepted as `rgba8888`, with no normal `convertedRgb565` or
canonical `originalArgb8888` surface.
## Background
`DEC-0037` requires packer metadata, Studio read/detail projections, tests, and
fixtures to stop treating RGB565 as normal palette data. Several services still
parse or project `originalArgb8888` and `convertedRgb565`.
## Scope
### Included
- Update parser and declaration normalization for palette metadata.
- Update read/detail mappers.
- Update palette-overhauling and bank-composition support to emit `rgba8888`.
- Preserve existing DTO shapes except for palette payload field names.
### Excluded
- Binary payload byte emission.
- Renderer/runtime changes.
- Manual regeneration of `main` and `fragments`.
## Execution Steps
### Step 1 - Update asset declaration parsing
**What:** Parse canonical `rgba8888` arrays from `asset.json`.
**How:** Replace palette validation that requires `originalArgb8888` and
`convertedRgb565` with validation for `rgba8888`. Keep numeric validation.
Reject malformed or missing `rgba8888` where a palette payload is required.
**File(s):**
- `prometeu-packer/prometeu-packer-v1/src/main/java/p/packer/services/PackerAssetDeclarationParser.java`
### Step 2 - Update details projection
**What:** Return `rgba8888` from asset details.
**How:** Change `palettePayloadFromNode` to project `{ index, rgba8888 }`.
Remove `convertedRgb565` and canonical `originalArgb8888` from details output.
**File(s):**
- `prometeu-packer/prometeu-packer-v1/src/main/java/p/packer/services/PackerAssetDetailsService.java`
### Step 3 - Update read message mapping
**What:** Map `PackerPaletteV1` and cached palette metadata to `rgba8888`.
**How:** Replace `originalArgb8888` and `convertedRgb565` mapping with a single
`rgba8888` array.
**File(s):**
- `prometeu-packer/prometeu-packer-v1/src/main/java/p/packer/services/PackerReadMessageMapper.java`
### Step 4 - Update workspace write operations
**What:** Ensure packer write APIs that apply palette changes persist `rgba8888`.
**How:** Replace palette-overhauling and related write-lane logic that requires
both `originalArgb8888` and `convertedRgb565` with a `rgba8888` contract.
**File(s):**
- `prometeu-packer/prometeu-packer-v1/src/main/java/p/packer/services/FileSystemPackerWorkspaceService.java`
### Step 5 - Update cache reuse and walk projection checks
**What:** Make cache reuse validate new palette metadata.
**How:** Replace reusable metadata checks for `originalArgb8888` with
`rgba8888`. Stale cached RGB565-derived metadata must not be considered
reusable.
**File(s):**
- `prometeu-packer/prometeu-packer-v1/src/main/java/p/packer/repositories/PackerGlyphBankWalker.java`
- `prometeu-packer/prometeu-packer-v1/src/main/java/p/packer/repositories/PackerAssetWalker.java`
## Test Requirements
### Unit Tests
- Update parser tests to accept `rgba8888` and reject missing/malformed
`rgba8888`.
- Update details service tests to assert `rgba8888`.
- Update read mapper coverage for `PackerPaletteV1`.
- Update write operation tests for palette overhauling.
### Integration Tests
- Exercise a workspace read/build flow from `asset.json` using `rgba8888`.
### Manual Verification
- Search `prometeu-packer` for `originalArgb8888` and `convertedRgb565` after
this plan. Remaining matches must be migration-only or removed in later
fixture plan.
## Acceptance Criteria
- [x] `asset.json` palette metadata uses `rgba8888`.
- [x] Details/read projections expose `rgba8888`.
- [x] Workspace write operations persist `rgba8888`.
- [x] Stale RGB565-derived cache metadata is not reused as canonical.
- [x] No normal API requires `convertedRgb565`.
## Dependencies
- Depends on `PLN-0082`.
- Can run partly in parallel with `PLN-0083` after the palette model is stable.
## Risks
- DTO consumers may assume old map keys. Tests must cover the Studio-facing
projection boundary.
- Cache reuse can hide stale behavior if not invalidated by metadata shape.

View File

@ -1,141 +0,0 @@
---
id: PLN-0085
ticket: studio-packer-rgba8888-asset-pipeline
title: RGBA8888 Tests, Fixtures, and Conformance Updates
status: done
created: 2026-05-23
completed: 2026-05-23
ref_decisions:
- DEC-0037
tags:
- tests
- fixtures
- conformance
- rgba8888
---
## Objective
Update packer tests and fixtures so RGBA8888 is the asserted source of truth and
RGB565-specific expectations are removed.
## Background
`DEC-0037` requires tests and fixtures to stop proving RGB565 behavior. The code
base has parser, walker, details, materializer, and workspace service tests that
mention `convertedRgb565`, `originalArgb8888`, 15-color limits, magenta
color-key behavior, and RGB565 payload sizes.
## Scope
### Included
- Update packer unit tests and integration-style workspace tests.
- Update fixture `asset.json` files under packer test resources.
- Add conformance-oriented assertions for RGBA channel order, alpha, index `0`,
16 usable colors, and removed color-key behavior.
### Excluded
- Manual regeneration of `test-projects/main` and `fragments`.
- Production code changes except minor compile-fix test helpers.
- Runtime repository tests.
## Execution Steps
### Step 1 - Update parser and details tests
**What:** Replace palette payload fixtures with `rgba8888`.
**How:** Rewrite test JSON snippets and assertions that mention
`originalArgb8888` or `convertedRgb565`.
**File(s):**
- `prometeu-packer/prometeu-packer-v1/src/test/java/p/packer/services/PackerAssetDeclarationParserTest.java`
- `prometeu-packer/prometeu-packer-v1/src/test/java/p/packer/services/PackerAssetDetailsServiceTest.java`
### Step 2 - Update glyph walker tests
**What:** Assert new palette extraction semantics.
**How:** Add image fixtures in tests that cover:
16 colors, 17-color failure, alpha 0, partial alpha, magenta as ordinary color,
and index `0` as ordinary.
**File(s):**
- `prometeu-packer/prometeu-packer-v1/src/test/java/p/packer/repositories/PackerGlyphBankWalkerTest.java`
### Step 3 - Update materializer and workspace service tests
**What:** Assert RGBA8888 runtime payload and metadata behavior.
**How:** Update tests that read `assets.pa`, measured bank size, payload offsets,
and palette byte expectations. Replace RGB565 byte checks with RGBA byte checks.
**File(s):**
- `prometeu-packer/prometeu-packer-v1/src/test/java/p/packer/repositories/PackerRuntimeAssetMaterializerTest.java`
- `prometeu-packer/prometeu-packer-v1/src/test/java/p/packer/services/FileSystemPackerWorkspaceServiceTest.java`
- `prometeu-packer/prometeu-packer-v1/src/test/java/p/packer/services/PackerRuntimePatchServiceTest.java`
- `prometeu-packer/prometeu-packer-v1/src/test/java/p/packer/services/PackerRuntimeRegistryTest.java`
### Step 4 - Update packer fixture assets
**What:** Replace fixture `asset.json` palette fields with `rgba8888`.
**How:** Edit packer test fixtures under `src/test/resources/fixtures` so
canonical palette declarations do not contain `convertedRgb565`.
**File(s):**
- `prometeu-packer/prometeu-packer-v1/src/test/resources/fixtures/**/asset.json`
### Step 5 - Add stale-contract guards
**What:** Add tests or quality checks that catch old RGB565 palette contract
residue.
**How:** Add assertions in existing tests or a focused repository quality test
that normal packer specs/tests/fixtures do not contain `convertedRgb565` or
RGB565 glyph palette payload expectations.
**File(s):**
- Existing packer test suites under `prometeu-packer/prometeu-packer-v1/src/test/java`
## Test Requirements
### Unit Tests
- Parser, details, mapper, glyph walker, and workspace service unit tests must
all pass.
### Integration Tests
- Run the relevant Gradle test task for `prometeu-packer-v1`.
### Manual Verification
- Search for `convertedRgb565`, `originalArgb8888`, `RGB565`, `rgb565`, `2048`,
and magenta color-key references in packer tests and fixtures.
## Acceptance Criteria
- [x] Tests use `rgba8888` as canonical palette data.
- [x] Tests assert RGBA channel order and alpha preservation.
- [x] Tests assert 16 usable palette entries.
- [x] Tests assert magenta is ordinary or no longer special.
- [x] Tests assert 4096-byte palette blocks where payload size is checked.
- [x] Packer test fixtures no longer rely on `convertedRgb565`.
## Dependencies
- Depends on `PLN-0082`, `PLN-0083`, and `PLN-0084`.
## Risks
- Some stale generated fixture data may be easier to regenerate than hand-edit.
- Overbroad residue checks could flag historical discussion artifacts; scope
checks to normal specs, code, tests, and fixtures.

View File

@ -1,159 +0,0 @@
---
id: PLN-0086
ticket: studio-packer-rgba8888-asset-pipeline
title: RGBA8888 Final Integration and Residue Removal
status: done
created: 2026-05-23
completed: 2026-05-23
ref_decisions:
- DEC-0037
tags:
- integration
- validation
- residue-removal
- rgba8888
---
## Objective
Run final integration checks and remove normal-path RGB565 residue after the
spec, model, emission, projection, and test plans are implemented.
## Background
`DEC-0037` prohibits RGB565 compatibility mode, normal `convertedRgb565`
projection, magenta color-key behavior, reserved palette index `0`, and partial
alpha flattening. Final validation must prove that the repository implements
those constraints coherently.
## Scope
### Included
- Repository-wide residue audit.
- Full relevant Gradle test execution.
- Discussion workflow validation.
- Final implementation notes for follow-up plan or lesson creation.
### Excluded
- New feature design.
- Runtime repository changes.
- Variable palette-count work in `DSC-0005`.
- Manual regeneration of `main` and `fragments`.
## Execution Steps
### Step 1 - Run focused residue searches
**What:** Find stale RGB565 palette-contract residue.
**How:** Search production specs/code/tests/fixtures for:
`convertedRgb565`, `originalArgb8888`, `RGB565`, `rgb565`, `COLOR_KEY`,
`magenta`, `2048`, `indices 1..15`, and partial-alpha flattening text.
Classify each match as removed, historical discussion-only, or out-of-scope.
**File(s):**
- `docs/specs/packer/**`
- `docs/specs/studio/**`
- `prometeu-packer/**`
### Step 2 - Run packer tests
**What:** Execute the packer test suite.
**How:** Run the Gradle test task that covers `prometeu-packer-v1` and related
API modules.
**File(s):**
- Gradle modules under `prometeu-packer`
### Step 3 - Run broader build validation
**What:** Verify Studio build integration still compiles.
**How:** Run the repository's standard build or the narrowest existing Gradle
task that compiles Studio plus packer consumers.
**File(s):**
- Root Gradle project
- `prometeu-app`
- `prometeu-packer`
### Step 4 - Validate discussion workflow
**What:** Ensure discussion artifacts remain consistent.
**How:** Run `discussion validate` after implementation and before any
housekeeping.
**File(s):**
- `discussion/index.ndjson`
- `discussion/workflow/**`
### Step 5 - Record remaining intentional residue
**What:** Document any allowed remaining RGB565 references.
**How:** If matches remain only in historical discussions, runtime references,
or explicit future migration notes, list them in the implementation summary so
housekeeping and lesson work can distinguish intentional context from missed
normal-path behavior.
**File(s):**
- Implementation summary or future lesson, after code work is complete.
## Test Requirements
### Unit Tests
- Packer unit tests must pass.
### Integration Tests
- Packer workspace build/materialization tests must pass.
- Studio compile/build validation must pass.
### Manual Verification
- Residue search results must contain no normal-path `convertedRgb565`,
RGB565 glyph palette payload, magenta color-key, reserved index `0`, or
partial-alpha flattening behavior.
## Acceptance Criteria
- [x] `discussion validate` passes.
- [x] Packer tests pass.
- [x] Studio/packer build validation passes.
- [x] Normal specs/code/tests/fixtures contain no stale RGB565 glyph-palette
contract residue.
- [x] Remaining stale-looking matches, if any, are documented as historical or
explicitly out of scope.
- [x] `DSC-0005` remains untouched except by explicit future work.
## Execution Notes
- `discussion validate` passed.
- `./gradlew build` passed.
- Residue search found only:
- normative spec statements explicitly saying `convertedRgb565` and magenta
color-key behavior are not normal contract;
- `test-projects/main` asset manifests, which are intentionally out of scope
for this implementation because they will be regenerated manually later.
- `DSC-0005` was not modified.
## Dependencies
- Depends on `PLN-0081` through `PLN-0085`.
## Risks
- A broad residue search may include historical discussions and cause false
positives.
- Generated project cache files may change during tests; those changes must be
reviewed separately from source edits.

View File

@ -0,0 +1,132 @@
---
id: PLN-0087
ticket: variable-tile-bank-palette-serialization
title: Variable Glyph Palette Spec Propagation
status: done
created: 2026-07-14
completed: 2026-07-14
ref_decisions:
- DEC-0038
tags:
- specs
- packer
- studio
- glyph-bank
- palette-serialization
---
## Objective
Propagate `DEC-0038` into the canonical Studio and packer specifications before
code changes start.
## Background
Runtime `DEC-0041` makes `palette_count` the serialized and resident palette
count for `GLYPH/indexed_v1`. Studio/packer `DEC-0038` adopts that runtime
contract downstream. Current packer specs still describe a fixed
`64 * 16 * 4 = 4096` palette block and `palette_count = 64`.
## Scope
### Included
- Update packer specs for glyph-bank metadata, payload layout, and size formulas.
- Update Studio specs only where Studio-facing palette count projection or asset
details are documented.
- Preserve RGBA8888 channel order, packed `u4` pixels, and `GLYPH/indexed_v1`.
### Excluded
- Code changes.
- Fixture regeneration.
- Runtime spec changes.
- Any `GLYPH/indexed_v2` design.
## Execution Steps
### Step 1 - Update asset declaration metadata rules
**What:** Define `palette_count` as the effective runtime metadata field.
**How:** Update glyph-bank declaration language so `palette_count` means the
number of serialized and resident RGBA8888 palettes, constrained to `1..=64`.
State that `palette_authored`, if present, is informative and not runtime
effective.
**File(s):**
- `docs/specs/packer/3. Asset Declaration and Virtual Asset Contract Specification.md`
### Step 2 - Update glyph payload layout
**What:** Replace fixed 4096-byte palette block text.
**How:** Change the layout to `palette_count * 16 * 4` palette bytes and update
formulas to:
```text
size = ceil(width * height / 2) + palette_count * 16 * 4
decoded_size = width * height + palette_count * 16 * 4
```
**File(s):**
- `docs/specs/packer/4. Build Artifacts and Deterministic Packing Specification.md`
### Step 3 - Preserve v1 boundaries
**What:** Explicitly prohibit v2, compatibility padding, and remapping.
**How:** Add rules that this remains `GLYPH/indexed_v1`, old fixed-padding is
not a compatibility mode, and v1 has no sparse-to-dense palette remapping.
**File(s):**
- `docs/specs/packer/4. Build Artifacts and Deterministic Packing Specification.md`
### Step 4 - Update Studio-facing spec text
**What:** Align Studio projections if they mention palette count or fixed bank
shape.
**How:** Search the Studio asset workspace spec for palette projection, details,
or pack wizard language and update only stale fixed-count wording.
**File(s):**
- `docs/specs/studio/4. Assets Workspace Specification.md`
## Test Requirements
### Unit Tests
- Not applicable for this spec-only plan.
### Integration Tests
- Not applicable for this spec-only plan.
### Manual Verification
- Search specs for stale normal-path `palette_count = 64`, `4096`, fixed
64-palette block, `GLYPH/indexed_v2`, and remapping language.
## Acceptance Criteria
- [x] Packer specs define `palette_count` as runtime-effective `1..=64`.
- [x] Packer specs use variable palette byte and size formulas.
- [x] Specs keep `GLYPH/indexed_v1` and reject v2 for this change.
- [x] Specs reject fixed-padding compatibility and sparse-to-dense remapping.
- [x] Studio specs contain no stale fixed 64-palette projection wording.
## Dependencies
- Depends on accepted `DEC-0038`.
- Should complete before code plans.
## Risks
- Leaving stale fixed 4096-byte examples will make implementation review
ambiguous.
- Over-editing Studio specs could imply UI behavior not required by `DEC-0038`.

View File

@ -0,0 +1,140 @@
---
id: PLN-0088
ticket: variable-tile-bank-palette-serialization
title: Variable Glyph Palette Metadata and Count Model
status: done
created: 2026-07-14
completed: 2026-07-14
ref_decisions:
- DEC-0038
tags:
- packer
- metadata
- glyph-bank
- palette-count
---
## Objective
Make packer metadata compute and expose runtime-effective glyph-bank
`palette_count` from declared palette data instead of hard-coding `64`.
## Background
`DEC-0038` requires `palette_count` to describe the number of serialized and
resident palettes expected by runtime. Current packer code emits
`palette_count = 64` and uses `palette_authored` for the actual authored count.
That makes the informative count and effective runtime count diverge.
## Scope
### Included
- Compute effective glyph palette count from declared `output.pipeline.palettes`.
- Validate `palette_count` in `1..=64`.
- Keep palette identity direct; do not remap sparse authored indices.
- Stop using `palette_authored` as a runtime-effective field.
### Excluded
- Binary payload byte emission.
- Size formula changes.
- Studio UI changes except compile-safe DTO/projection adjustments.
## Execution Steps
### Step 1 - Add a runtime-effective palette count helper
**What:** Centralize effective glyph palette count calculation.
**How:** Add or update helper logic so packer derives `palette_count` from
declared palette indices. Because v1 has no remapping, the effective count must
cover the highest direct palette id: `max(index) + 1`. Reject no palettes,
negative indices, duplicate indices, and any effective count above `64`.
**File(s):**
- `prometeu-packer/prometeu-packer-v1/src/main/java/p/packer/services/FileSystemPackerWorkspaceService.java`
- `prometeu-packer/prometeu-packer-v1/src/main/java/p/packer/repositories/PackerAssetWalker.java`
- `prometeu-packer/prometeu-packer-v1/src/main/java/p/packer/services/PackerAssetDeclarationParser.java`
### Step 2 - Replace fixed runtime metadata
**What:** Stop writing `palette_count = 64` unconditionally.
**How:** Replace runtime metadata emission so glyph-bank entries publish the
computed runtime-effective `palette_count`. Keep `palette_authored` only if it
is useful as pipeline/tooling information and never as runtime-effective root
metadata.
**File(s):**
- `prometeu-packer/prometeu-packer-v1/src/main/java/p/packer/services/FileSystemPackerWorkspaceService.java`
- `prometeu-packer/prometeu-packer-v1/src/main/java/p/packer/repositories/PackerRuntimeAssetMaterializer.java`
### Step 3 - Validate direct palette identity
**What:** Preserve runtime direct `palette_id` semantics.
**How:** Ensure packer does not compact or renumber palette indices. If palette
indices are sparse, emitted palette slots up to `palette_count - 1` must keep
their direct identity, with missing slots represented by deterministic default
RGBA8888 palette data only when required to preserve direct ids.
**File(s):**
- `prometeu-packer/prometeu-packer-v1/src/main/java/p/packer/services/FileSystemPackerWorkspaceService.java`
- `prometeu-packer/prometeu-packer-v1/src/main/java/p/packer/repositories/PackerGlyphBankWalker.java`
### Step 4 - Update projections that expose metadata
**What:** Align details/read projections with the effective count.
**How:** Ensure packer read/details APIs expose `palette_count` consistently
where runtime metadata is projected, and do not present `palette_authored` as
the field that runtime consumes.
**File(s):**
- `prometeu-packer/prometeu-packer-v1/src/main/java/p/packer/services/PackerAssetDetailsService.java`
- `prometeu-packer/prometeu-packer-v1/src/main/java/p/packer/services/PackerReadMessageMapper.java`
## Test Requirements
### Unit Tests
- Parser/metadata tests for `palette_count = 1`, intermediate count, and `64`.
- Rejection tests for zero effective palettes, duplicate indices, negative
indices, and count above `64`.
- Sparse direct identity tests where palette index `3` implies
`palette_count = 4`, without remapping palette `3` to `0`.
### Integration Tests
- Workspace read/build test proving asset table metadata reports variable
`palette_count`.
### Manual Verification
- Search packer code for `palette_count = 64` and `GLYPH_BANK_PALETTE_COUNT`
assumptions after the change.
## Acceptance Criteria
- [x] Packer computes runtime-effective `palette_count` from declared palettes.
- [x] `palette_count` is validated as `1..=64`.
- [x] Sparse palette ids are not remapped.
- [x] `palette_authored` is not treated as runtime-effective metadata.
- [x] Read/details projections do not expose stale fixed-count assumptions.
## Dependencies
- Depends on `PLN-0087`.
- Must complete before payload emission changes in `PLN-0089`.
## Risks
- Sparse palette handling can accidentally become remapping if implemented by
sorting and compacting declarations.
- Keeping `palette_authored` in tooling may confuse readers unless tests prove
runtime-effective metadata uses `palette_count`.

View File

@ -0,0 +1,140 @@
---
id: PLN-0089
ticket: variable-tile-bank-palette-serialization
title: Variable Glyph Palette Payload Emission and Size Accounting
status: done
created: 2026-07-14
completed: 2026-07-14
ref_decisions:
- DEC-0038
tags:
- packer
- assets-pa
- glyph-bank
- payload
---
## Objective
Change packer `GLYPH/indexed_v1` payload emission from a fixed 64-palette block
to exactly `palette_count * 16 * 4` RGBA8888 bytes, with matching size and
decoded-size accounting.
## Background
`FileSystemPackerWorkspaceService` currently defines fixed palette constants
and emits a fixed `GLYPH_BANK_PALETTE_BYTES` block. `DEC-0038` requires packer
to emit only the runtime-effective palette count and compute asset table sizes
from that count.
## Scope
### Included
- Replace fixed palette byte constants with count-dependent formulas.
- Emit exactly `palette_count` palettes in RGBA byte order.
- Update asset table `size` and `decoded_size`.
- Reject metadata/payload mismatches.
### Excluded
- Palette model extraction changes covered by `PLN-0088`.
- Studio UI changes.
- Runtime code changes.
## Execution Steps
### Step 1 - Replace fixed palette byte constants
**What:** Remove normal-path fixed `64 * 16 * 4` size assumptions.
**How:** Keep maximum constants such as `MAX_PALETTE_COUNT = 64`, but compute
payload palette bytes as `palette_count * 16 * 4` at each glyph-bank packing
boundary.
**File(s):**
- `prometeu-packer/prometeu-packer-v1/src/main/java/p/packer/services/FileSystemPackerWorkspaceService.java`
- `prometeu-packer/prometeu-packer-v1/src/main/java/p/packer/repositories/PackerAssetWalker.java`
- `prometeu-packer/prometeu-packer-v1/src/main/java/p/packer/repositories/PackerRuntimeAssetMaterializer.java`
### Step 2 - Emit variable palette bytes
**What:** Write only runtime-effective palettes.
**How:** Update palette byte generation to allocate
`palette_count * 16 * 4` bytes and fill direct palette ids from `0` through
`palette_count - 1`. Each color remains RGBA8888 in `R`, `G`, `B`, `A` order.
**File(s):**
- `prometeu-packer/prometeu-packer-v1/src/main/java/p/packer/services/FileSystemPackerWorkspaceService.java`
### Step 3 - Update size and decoded-size formulas
**What:** Align asset table sizes with runtime `DEC-0041`.
**How:** Compute:
```text
size = ceil(width * height / 2) + palette_count * 16 * 4
decoded_size = width * height + palette_count * 16 * 4
```
Use these formulas for asset table entries, materializer expectations, and
workspace build outputs.
**File(s):**
- `prometeu-packer/prometeu-packer-v1/src/main/java/p/packer/services/FileSystemPackerWorkspaceService.java`
- `prometeu-packer/prometeu-packer-v1/src/main/java/p/packer/repositories/PackerRuntimeAssetMaterializer.java`
### Step 4 - Reject metadata/payload mismatches
**What:** Prevent stale fixed-padding artifacts.
**How:** Add validation that emitted palette byte length, root metadata
`palette_count`, `size`, and `decoded_size` agree. Do not allow a fixed
64-palette block when `palette_count < 64`.
**File(s):**
- `prometeu-packer/prometeu-packer-v1/src/main/java/p/packer/services/FileSystemPackerWorkspaceService.java`
- `prometeu-packer/prometeu-packer-v1/src/main/java/p/packer/repositories/PackerRuntimeAssetMaterializer.java`
## Test Requirements
### Unit Tests
- Assert emitted palette bytes for `palette_count = 1`, an intermediate count,
and `64`.
- Assert `size` and `decoded_size` formulas for variable counts.
- Assert RGBA byte order is unchanged.
### Integration Tests
- Build a workspace and inspect `assets.pa` asset table and payload length for
variable palette counts.
### Manual Verification
- Search for fixed normal-path `4096`, `64 * 16 * 4`, and
`GLYPH_BANK_PALETTE_BYTES` residue.
## Acceptance Criteria
- [x] Glyph payloads emit exactly `palette_count * 16 * 4` palette bytes.
- [x] Asset table `size` and `decoded_size` use variable formulas.
- [x] RGBA byte order is unchanged.
- [x] Fixed 64-palette padding is emitted only when `palette_count = 64`.
- [x] Metadata/payload mismatch is rejected or impossible by construction.
## Dependencies
- Depends on `PLN-0088`.
## Risks
- Updating metadata without payload length will corrupt runtime slicing.
- Updating payload length without decoded-size metadata will fail runtime asset
validation.

View File

@ -0,0 +1,147 @@
---
id: PLN-0090
ticket: variable-tile-bank-palette-serialization
title: Studio and Packer Projections for Variable Glyph Palettes
status: done
created: 2026-07-14
completed: 2026-07-14
ref_decisions:
- DEC-0038
tags:
- studio
- packer
- api
- projections
- glyph-bank
---
## Objective
Align Studio-facing and packer-facing projections so variable glyph
`palette_count` is visible and not confused with `palette_authored`.
## Background
`DEC-0038` says 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.
## Scope
### Included
- Update packer read/detail DTO projections where runtime metadata is surfaced.
- Update Studio asset details, palette overhauling, schema, or pack wizard code
if it reads fixed counts or authored counts as runtime-effective.
- Keep `rgba8888` color projection unchanged.
### Excluded
- Binary payload emission.
- General palette UI redesign.
- `originalArgb8888` UI fallback cleanup unrelated to variable `palette_count`.
## Execution Steps
### Step 1 - Audit projection boundaries
**What:** Find all Studio/packer paths that expose glyph palette metadata.
**How:** Search for `palette_count`, `palette_authored`,
`GLYPH_BANK_PALETTE_COUNT`, fixed `64`, and related asset details projections.
Classify each match as runtime-effective metadata, tooling-only metadata, UI
fallback, or unrelated.
**File(s):**
- `prometeu-packer/prometeu-packer-v1/src/main/java/p/packer/services/PackerAssetDetailsService.java`
- `prometeu-packer/prometeu-packer-v1/src/main/java/p/packer/services/PackerReadMessageMapper.java`
- `prometeu-studio/src/main/java/p/studio/workspaces/assets/**`
### Step 2 - Update packer details/read surfaces
**What:** Expose runtime-effective `palette_count`.
**How:** Ensure details/read projections show the `palette_count` that will be
written to the runtime asset table. Preserve `palette_authored` only as
explicitly tooling-only information if it remains useful.
**File(s):**
- `prometeu-packer/prometeu-packer-v1/src/main/java/p/packer/services/PackerAssetDetailsService.java`
- `prometeu-packer/prometeu-packer-v1/src/main/java/p/packer/services/PackerReadMessageMapper.java`
### Step 3 - Update Studio consumers
**What:** Prevent Studio from using authored count as runtime count.
**How:** Adjust Studio asset details and pack wizard code so any displayed or
validated runtime count comes from effective `palette_count`. Keep palette
color rendering based on `rgba8888`.
**File(s):**
- `prometeu-studio/src/main/java/p/studio/workspaces/assets/details/**`
- `prometeu-studio/src/test/java/p/studio/workspaces/assets/details/**`
### Step 4 - Preserve scene palette id shape
**What:** Avoid accidental scene payload changes.
**How:** Confirm scene projections still carry `palette_id` unchanged and only
runtime/packer validation changes count semantics.
**File(s):**
- `prometeu-studio/src/main/java/p/studio/workspaces/assets/**`
- `prometeu-packer/prometeu-packer-v1/src/main/java/p/packer/services/FileSystemPackerWorkspaceService.java`
## Test Requirements
### Unit Tests
- Packer details/read tests for variable `palette_count`.
- Studio asset details tests proving runtime count and authored/tooling count
are not conflated.
### Integration Tests
- Workspace read/build flow where a glyph bank with an intermediate
`palette_count` is projected through packer/Studio surfaces.
### Manual Verification
- Search Studio and packer projection code for stale assumptions that
`palette_authored` is runtime-effective.
## Acceptance Criteria
- [x] Packer read/details projections expose effective `palette_count`.
- [x] Studio consumers do not use `palette_authored` as runtime-effective count.
- [x] `rgba8888` color projection remains unchanged.
- [x] Scene `palette_id` payload shape is unchanged.
- [x] Tests cover variable count projection.
## Execution Notes
- Packer runtime output projection is the `assets.pa` asset table generated by
`FileSystemPackerWorkspaceService`; `PLN-0088` and `PLN-0089` now project the
runtime-effective `palette_count` there.
- `PackerAssetDetailsService` and `PackerReadMessageMapper` project palette
color data through `pipelinePalettes` and do not expose
`palette_authored` as runtime-effective metadata.
- Studio asset details mapping forwards packer details without deriving a
runtime count from `palette_authored`.
- No DTO field was added because doing so would create a new Studio/packer API
surface not required by `DEC-0038`.
## Dependencies
- Depends on `PLN-0088`.
- Can run in parallel with `PLN-0089` after metadata semantics are stable.
## Risks
- UI code may still need ARGB helper fields for presentation. This plan must not
turn that into a runtime metadata decision.
- Overbroad projection edits could accidentally change scene contracts.

View File

@ -0,0 +1,167 @@
---
id: PLN-0091
ticket: variable-tile-bank-palette-serialization
title: Variable Glyph Palette Tests, Fixtures, and Final Validation
status: done
created: 2026-07-14
completed: 2026-07-14
ref_decisions:
- DEC-0038
tags:
- tests
- fixtures
- validation
- glyph-bank
- palette-serialization
---
## Objective
Update tests and fixtures to prove Studio/packer emit runtime-conforming
variable glyph palette payloads and contain no stale fixed-padding assumptions.
## Background
`DEC-0038` requires downstream fixture coverage for `palette_count = 1`, an
intermediate count, and `palette_count = 64`, plus producer validation for
metadata/payload mismatch. Earlier tests still assert `palette_count = 64`,
4096-byte palette blocks, and fixed glyph payload sizes.
## Scope
### Included
- Update packer unit tests and integration-style workspace tests.
- Update packer fixture `asset.json` files and expected runtime payload checks.
- Update Studio tests only where Studio projections or UI logic expose
effective palette count.
- Run focused and broad validation.
### Excluded
- Runtime repository tests.
- New feature design.
- Palette remapping behavior.
## Execution Steps
### Step 1 - Update packer parser and metadata tests
**What:** Prove effective `palette_count` validation.
**How:** Add tests for `palette_count = 1`, intermediate counts, `64`,
duplicate/sparse direct identity behavior, and rejection above `64`.
**File(s):**
- `prometeu-packer/prometeu-packer-v1/src/test/java/p/packer/services/PackerAssetDeclarationParserTest.java`
- `prometeu-packer/prometeu-packer-v1/src/test/java/p/packer/repositories/PackerGlyphBankWalkerTest.java`
### Step 2 - Update payload and asset table tests
**What:** Prove variable payload lengths and size formulas.
**How:** Replace fixed 4096-byte expectations with
`palette_count * 16 * 4`. Assert `size`, `decoded_size`, payload offsets, and
RGBA bytes for several counts.
**File(s):**
- `prometeu-packer/prometeu-packer-v1/src/test/java/p/packer/services/FileSystemPackerWorkspaceServiceTest.java`
- `prometeu-packer/prometeu-packer-v1/src/test/java/p/packer/repositories/PackerRuntimeAssetMaterializerTest.java`
- `prometeu-packer/prometeu-packer-v1/src/test/java/p/packer/services/PackerRuntimePatchServiceTest.java`
- `prometeu-packer/prometeu-packer-v1/src/test/java/p/packer/services/PackerRuntimeRegistryTest.java`
### Step 3 - Update fixtures
**What:** Replace stale fixed-padding fixtures.
**How:** Regenerate or edit packer test fixtures so at least one glyph bank uses
`palette_count = 1`, one uses an intermediate count, and one uses `64`.
Fixtures with fixed 64 padding are valid only when metadata says
`palette_count = 64`.
**File(s):**
- `prometeu-packer/prometeu-packer-v1/src/test/resources/fixtures/**/asset.json`
- Related binary or generated expected payload fixtures under packer test
resources.
### Step 4 - Update Studio tests
**What:** Cover Studio-facing projection changes.
**How:** Adjust tests only where Studio surfaces effective palette counts or
metadata. Keep color rendering assertions focused on `rgba8888`.
**File(s):**
- `prometeu-studio/src/test/java/p/studio/workspaces/assets/details/**`
### Step 5 - Run validation and residue scans
**What:** Prove no normal-path fixed-padding residue remains.
**How:** Run relevant Gradle tests and search normal specs/code/tests/fixtures
for stale `palette_count = 64`, `4096`, fixed `64 * 16 * 4`, `GLYPH/indexed_v2`,
and sparse remapping language. Classify any remaining match as historical,
max-bound, or a bug.
**File(s):**
- `docs/specs/packer/**`
- `docs/specs/studio/**`
- `prometeu-packer/**`
- `prometeu-studio/**`
## Test Requirements
### Unit Tests
- Packer parser, walker, materializer, details/read, and workspace service tests
pass.
- Studio asset details tests pass where touched.
### Integration Tests
- Packer workspace build/materialization tests pass.
- Repository build or narrow Studio/packer build validation passes.
### Manual Verification
- Residue scan finds no normal-path fixed-padding contract text or code.
- `discussion validate` passes.
## Acceptance Criteria
- [x] Tests cover `palette_count = 1`, an intermediate count, and `64`.
- [x] Tests cover variable `size` and `decoded_size`.
- [x] Tests cover emitted palette byte length and RGBA order.
- [x] Tests cover metadata/payload mismatch rejection or producer validation.
- [x] Fixtures no longer rely on fixed 64-palette padding unless count is `64`.
- [x] Validation commands pass.
- [x] Residue scan results are clean or explicitly classified.
## Execution Notes
- Added packer workspace coverage for `palette_count = 1` and intermediate
`palette_count = 7`.
- Existing fixture and build paths continue to cover `palette_count = 64` where
a max-count payload is intended.
- Added parser coverage rejecting palette declaration index `64`, preserving
the v1 maximum effective count of `64` through direct ids `0..63`.
- `:prometeu-packer:prometeu-packer-v1:test` passed.
- `./gradlew build` passed.
- Residue scan found only intentional normative statements rejecting
`convertedRgb565`, `GLYPH/indexed_v2`, fixed-padding compatibility, and
sparse-to-dense remapping.
## Dependencies
- Depends on `PLN-0087`, `PLN-0088`, `PLN-0089`, and `PLN-0090`.
## Risks
- Generated project fixtures may require regeneration rather than manual edits.
- Broad residue scans may include historical discussions; scope final checks to
active specs, code, tests, and fixtures.

View File

@ -121,6 +121,11 @@ Rules:
- glyph-bank palette payloads must expose canonical `rgba8888` color values in runtime RGBA channel order;
- ARGB values produced by host image APIs are import-side implementation details, not canonical declaration or projection fields;
- `convertedRgb565` is not part of the normal palette contract;
- glyph-bank `palette_count` is an effective runtime metadata field and means
the number of serialized and resident RGBA8888 palettes for the bank;
- glyph-bank `palette_count` must be in the inclusive range `1..=64`;
- `palette_authored`, when present, is informative tooling metadata only and
must not be treated as runtime-effective metadata;
- the packer must sort such entries by numeric `index`, not by physical array position;
- duplicate or malformed indices are structural errors;
- missing or malformed `palette` payloads are structural errors;

View File

@ -147,7 +147,8 @@ Offset ambiguity guardrail:
## Format-Specific Baseline: `GLYPH/indexed_v1`
The first-wave producer contract for `GLYPH/indexed_v1` is fixed and runtime-aligned.
The producer contract for `GLYPH/indexed_v1` is runtime-aligned and uses a
variable RGBA8888 palette block.
### Tile Selection and Identity
@ -178,7 +179,7 @@ Rules:
- the serialized payload for `GLYPH/indexed_v1` is:
1. one packed `u4` pixel plane for the full emitted sheet;
2. one palette block of `64 * 16 * 4 = 4096` bytes;
2. one palette block of `palette_count * 16 * 4` bytes;
- packed pixel bytes must be emitted by the packer, not inferred later by the runtime;
- the palette block is serialized as RGBA8888 values in runtime RGBA channel order;
- each palette entry is emitted as four bytes in `R`, `G`, `B`, `A` order;
@ -196,10 +197,15 @@ Rules:
- `width`
- `height`
- `palette_count`
- tile-bank v1 requires `palette_count = 64`;
- tile-bank v1 requires `palette_count` in the inclusive range `1..=64`;
- `palette_count` is the number of serialized palettes and resident runtime
palettes for the bank;
- tile-bank v1 size formulas are:
- `size = ceil(width * height / 2) + 4096`
- `decoded_size = (width * height) + 4096`
- `size = ceil(width * height / 2) + palette_count * 16 * 4`
- `decoded_size = (width * height) + palette_count * 16 * 4`
- fixed 64-palette padding is not a compatibility mode unless
`palette_count = 64` and the payload directly satisfies the v1 contract;
- `GLYPH/indexed_v2` must not be introduced for this palette-count correction.
### Palette Contract
@ -209,7 +215,8 @@ Rules:
- each palette declaration uses the shape `{ "index": <int>, "palette": { ... } }`;
- each palette payload uses canonical `rgba8888` entries interpreted as `0xRRGGBBAA`;
- palette ordering is ascending numeric `index`, never raw array position;
- palette ids in the emitted glyph bank are the normalized declared palette indices;
- palette ids in the emitted glyph bank are direct declared palette indices;
- v1 has no sparse-to-dense palette remapping metadata;
- palette index `0` is ordinary and may carry any RGBA8888 value;
- glyph palettes have 16 usable entries;
- transparency and partial transparency are encoded only by RGBA alpha;

View File

@ -226,6 +226,11 @@ Rules:
- `preload`
- Glyph-bank palette projections must use canonical `rgba8888` values when
palette data is shown.
- Glyph-bank runtime output projections must present `palette_count`, when
shown, as the runtime-effective serialized and resident palette count in
`1..=64`.
- Studio-facing glyph palette views must not present `palette_authored` as the
runtime-effective count.
- Studio-facing glyph palette views must not expose `convertedRgb565` as normal
runtime or tooling truth.
- Runtime-facing output information must not require raw JSON inspection.

View File

@ -38,11 +38,9 @@ import java.util.*;
import java.util.stream.Stream;
public final class FileSystemPackerWorkspaceService implements PackerWorkspaceService {
private static final int GLYPH_BANK_PALETTE_COUNT = 64;
private static final int GLYPH_BANK_MAX_PALETTE_COUNT = 64;
private static final int GLYPH_BANK_COLORS_PER_PALETTE = 16;
private static final int GLYPH_BANK_RGBA8888_BYTES_PER_COLOR = 4;
private static final int GLYPH_BANK_PALETTE_BYTES =
GLYPH_BANK_PALETTE_COUNT * GLYPH_BANK_COLORS_PER_PALETTE * GLYPH_BANK_RGBA8888_BYTES_PER_COLOR;
private static final String SCENE_BANK_SUPPORT_FILE = "scene-bank.studio.json";
private static final String SCENE_PACK_REQUEST_FILE = "scene-bank.pack-request.json";
@ -1125,7 +1123,8 @@ public final class FileSystemPackerWorkspaceService implements PackerWorkspaceSe
});
final byte[] packedPixels = packNibbles(sheetPixels);
final byte[] paletteBytes = emitGlyphBankPalettes(declaration);
final int paletteCount = runtimeGlyphPaletteCount(declaration);
final byte[] paletteBytes = emitGlyphBankPalettes(declaration, paletteCount);
final byte[] payload = new byte[packedPixels.length + paletteBytes.length];
System.arraycopy(packedPixels, 0, payload, 0, packedPixels.length);
System.arraycopy(paletteBytes, 0, payload, packedPixels.length, paletteBytes.length);
@ -1134,7 +1133,7 @@ public final class FileSystemPackerWorkspaceService implements PackerWorkspaceSe
runtimeMetadata.put("tile_size", tileSize);
runtimeMetadata.put("width", width);
runtimeMetadata.put("height", height);
runtimeMetadata.put("palette_count", GLYPH_BANK_PALETTE_COUNT);
runtimeMetadata.put("palette_count", paletteCount);
runtimeMetadata.put("palette_authored", countAuthoredGlyphBankPalettes(declaration));
runtimeMetadata.put("codec", Map.of());
declaration.outputMetadata().forEach((key, value) -> {
@ -1154,7 +1153,7 @@ public final class FileSystemPackerWorkspaceService implements PackerWorkspaceSe
"GLYPH",
"NONE",
payload,
width * height + GLYPH_BANK_PALETTE_BYTES,
width * height + paletteBytes.length,
runtimeMetadata,
toolingMetadata,
declaration.preloadEnabled());
@ -1275,8 +1274,8 @@ public final class FileSystemPackerWorkspaceService implements PackerWorkspaceSe
return packed;
}
private byte[] emitGlyphBankPalettes(PackerAssetDeclaration declaration) {
final byte[] bytes = new byte[GLYPH_BANK_PALETTE_BYTES];
private byte[] emitGlyphBankPalettes(PackerAssetDeclaration declaration, int paletteCount) {
final byte[] bytes = new byte[glyphBankPaletteBytes(paletteCount)];
final JsonNode palettesNode = declaration.outputPipelineMetadata().get("palettes");
if (!(palettesNode instanceof com.fasterxml.jackson.databind.node.ArrayNode palettesArray)) {
return bytes;
@ -1288,7 +1287,7 @@ public final class FileSystemPackerWorkspaceService implements PackerWorkspaceSe
continue;
}
final int paletteIndex = indexNode.intValue();
if (paletteIndex < 0 || paletteIndex >= GLYPH_BANK_PALETTE_COUNT) {
if (paletteIndex < 0 || paletteIndex >= paletteCount) {
continue;
}
final JsonNode rgbaNode = paletteNode.path("rgba8888");
@ -1308,11 +1307,53 @@ public final class FileSystemPackerWorkspaceService implements PackerWorkspaceSe
return bytes;
}
private int glyphBankPaletteBytes(int paletteCount) {
if (paletteCount < 1 || paletteCount > GLYPH_BANK_MAX_PALETTE_COUNT) {
throw new IllegalStateException("Glyph packing requires palette_count in 1..="
+ GLYPH_BANK_MAX_PALETTE_COUNT + ".");
}
return paletteCount * GLYPH_BANK_COLORS_PER_PALETTE * GLYPH_BANK_RGBA8888_BYTES_PER_COLOR;
}
private int countAuthoredGlyphBankPalettes(PackerAssetDeclaration declaration) {
final JsonNode palettesNode = declaration.outputPipelineMetadata().get("palettes");
return palettesNode instanceof ArrayNode palettesArray ? palettesArray.size() : 0;
}
private int runtimeGlyphPaletteCount(PackerAssetDeclaration declaration) {
final JsonNode palettesNode = declaration.outputPipelineMetadata().get("palettes");
if (!(palettesNode instanceof ArrayNode palettesArray) || palettesArray.isEmpty()) {
throw new IllegalStateException("Glyph packing requires at least one declared pipeline palette.");
}
int maxPaletteIndex = -1;
final Set<Integer> seen = new HashSet<>();
for (JsonNode declarationNode : palettesArray) {
final JsonNode indexNode = declarationNode.path("index");
final JsonNode paletteNode = declarationNode.path("palette");
if (!indexNode.isInt() || indexNode.intValue() < 0) {
throw new IllegalStateException("Glyph packing requires non-negative integer palette indices.");
}
final int paletteIndex = indexNode.intValue();
if (!seen.add(paletteIndex)) {
throw new IllegalStateException("Glyph packing requires unique palette indices.");
}
if (paletteIndex >= GLYPH_BANK_MAX_PALETTE_COUNT) {
throw new IllegalStateException("Glyph packing supports palette indices in 0.."
+ (GLYPH_BANK_MAX_PALETTE_COUNT - 1) + ".");
}
if (!paletteNode.path("rgba8888").isArray()) {
throw new IllegalStateException("Glyph packing requires rgba8888 entries in each declared palette.");
}
maxPaletteIndex = Math.max(maxPaletteIndex, paletteIndex);
}
final int paletteCount = maxPaletteIndex + 1;
if (paletteCount < 1 || paletteCount > GLYPH_BANK_MAX_PALETTE_COUNT) {
throw new IllegalStateException("Glyph packing requires palette_count in 1..="
+ GLYPH_BANK_MAX_PALETTE_COUNT + ".");
}
return paletteCount;
}
private byte[] encodeScenePackRequest(ScenePackRequest request) {
final ByteArrayOutputStream output = new ByteArrayOutputStream();
writeBytes(output, new byte[]{'S', 'C', 'N', 'E'});

View File

@ -324,6 +324,14 @@ public final class PackerAssetDeclarationParser {
"Field 'output.pipeline.palettes' contains duplicate palette index " + indexNode.intValue() + ".",
manifestPath,
true));
} else if (indexNode.intValue() >= MAX_PIPELINE_PALETTES) {
diagnostics.add(new PackerDiagnostic(
PackerDiagnosticSeverity.ERROR,
PackerDiagnosticCategory.STRUCTURAL,
"Field 'output.pipeline.palettes' cannot declare palette index " + indexNode.intValue()
+ "; maximum supported index is " + (MAX_PIPELINE_PALETTES - 1) + ".",
manifestPath,
true));
}
if (!paletteNode.isObject()) {

View File

@ -338,8 +338,10 @@ final class FileSystemPackerWorkspaceServiceTest {
assertEquals(16, assetTable.get(0).path("metadata").path("tile_size").asInt());
assertEquals(256, assetTable.get(0).path("metadata").path("width").asInt());
assertEquals(256, assetTable.get(0).path("metadata").path("height").asInt());
assertEquals(64, assetTable.get(0).path("metadata").path("palette_count").asInt());
assertEquals(1, assetTable.get(0).path("metadata").path("palette_count").asInt());
assertEquals(1, assetTable.get(0).path("metadata").path("palette_authored").asInt());
assertEquals(32768 + 64, assetTable.get(0).path("size").asInt());
assertEquals(65536 + 64, assetTable.get(0).path("decoded_size").asInt());
assertTrue(assetTable.get(0).path("metadata").path("pipeline").isMissingNode());
final var preload = MAPPER.readTree(projectRoot.resolve("build/preload.json").toFile());
@ -354,6 +356,53 @@ final class FileSystemPackerWorkspaceServiceTest {
assertEquals(0, assetTableMetadata.get(0).path("metadata").path("pipeline").path("palettes").get(0).path("index").asInt());
}
@Test
void packWorkspaceEmitsIntermediateGlyphPaletteCountWithoutRemappingPaletteIdentity() throws Exception {
final Path projectRoot = copyFixture("workspaces/managed-basic", tempDir.resolve("pack-workspace-palette-count-7"));
final Path assetRoot = projectRoot.resolve("assets/ui/atlas");
final Path manifestPath = assetRoot.resolve("asset.json");
writeTilePng(assetRoot.resolve("confirm.png"), 16);
final ObjectNode manifest = (ObjectNode) MAPPER.readTree(manifestPath.toFile());
final ObjectNode output = (ObjectNode) manifest.path("output");
output.putObject("metadata").put("tile_size", "16x16");
final ObjectNode pipeline = output.putObject("pipeline");
final var palettes = pipeline.putArray("palettes");
final ObjectNode palette = palettes.addObject();
palette.put("index", 6);
palette.putObject("palette")
.putArray("rgba8888").add(0xFF0000FF);
final var artifacts = manifest.putArray("artifacts");
artifacts.addObject().put("file", "confirm.png").put("index", 0);
MAPPER.writerWithDefaultPrettyPrinter().writeValue(manifestPath.toFile(), manifest);
final FileSystemPackerWorkspaceService service = service();
final var result = service.packWorkspace(new PackWorkspaceRequest(project(projectRoot)));
assertEquals(PackerOperationStatus.SUCCESS, result.status());
final byte[] assetsPa = Files.readAllBytes(projectRoot.resolve("build/assets.pa"));
final var assetTable = MAPPER.readTree(projectRoot.resolve("build/asset_table.json").toFile());
assertEquals(7, assetTable.get(0).path("metadata").path("palette_count").asInt());
assertEquals(1, assetTable.get(0).path("metadata").path("palette_authored").asInt());
assertEquals(32768 + (7 * 16 * 4), assetTable.get(0).path("size").asInt());
assertEquals(65536 + (7 * 16 * 4), assetTable.get(0).path("decoded_size").asInt());
final int payloadOffset = (int) readLeLong(assetsPa, 12);
final int assetOffset = assetTable.get(0).path("offset").asInt();
final int packedPixelBytes = (assetTable.get(0).path("metadata").path("width").asInt()
* assetTable.get(0).path("metadata").path("height").asInt()) / 2;
final int paletteStart = payloadOffset + assetOffset + packedPixelBytes;
final int paletteSixStart = paletteStart + (6 * 16 * 4);
assertEquals(0x00, assetsPa[paletteStart] & 0xFF);
assertEquals(0x00, assetsPa[paletteStart + 1] & 0xFF);
assertEquals(0x00, assetsPa[paletteStart + 2] & 0xFF);
assertEquals(0x00, assetsPa[paletteStart + 3] & 0xFF);
assertEquals(0xFF, assetsPa[paletteSixStart] & 0xFF);
assertEquals(0x00, assetsPa[paletteSixStart + 1] & 0xFF);
assertEquals(0x00, assetsPa[paletteSixStart + 2] & 0xFF);
assertEquals(0xFF, assetsPa[paletteSixStart + 3] & 0xFF);
}
@Test
void packWorkspaceRemapsGlyphTileIndicesUsingGlyphMaterialSchema() throws Exception {
final Path projectRoot = copyFixture("workspaces/managed-basic", tempDir.resolve("pack-workspace-remap-material"));

View File

@ -215,6 +215,39 @@ final class PackerAssetDeclarationParserTest {
assertTrue(result.diagnostics().stream().anyMatch(diagnostic -> diagnostic.message().contains("duplicate palette index 0")));
}
@Test
void rejectsPaletteDeclarationIndexAboveV1Maximum() throws Exception {
final Path manifest = tempDir.resolve("asset.json");
Files.writeString(manifest, """
{
"schema_version": 1,
"asset_uuid": "uuid-palette-too-high",
"name": "palette_asset",
"type": "glyph_bank",
"output": {
"format": "GLYPH/indexed_v1",
"codec": "NONE",
"pipeline": {
"palettes": [
{
"index": 64,
"palette": {
"rgba8888": [-16776961]
}
}
]
}
},
"preload": { "enabled": true }
}
""");
final var result = parser.parse(manifest);
assertFalse(result.valid());
assertTrue(result.diagnostics().stream().anyMatch(diagnostic -> diagnostic.message().contains("maximum supported index is 63")));
}
@Test
void rejectsMalformedJsonWithStructuralDiagnostic() {
final var result = parser.parse(PackerFixtureLocator.fixtureRoot("workspaces/invalid-malformed/assets/bad/asset.json"));

View File

@ -14,13 +14,13 @@
"last_modified" : 1779659315450,
"fingerprint" : "ac565160c0dceb321b8f6c9094f2b5e6ae398396fe32c8ead706f5cc36f465cf",
"metadata" : {
"palette" : {
"rgba8888" : [ 0, 673720574, -523190018, -117903106, 945858814, -1600620290, 1484833022 ]
},
"tile" : {
"width" : 32,
"height" : 32,
"paletteIndices" : "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAgICAgICAQAAAAAAAAAAAAABAQEAAAAAAAAAAAAAAAEDBAQEBAQCAQAAAAAAAQEBAQICAgEAAAAAAAAAAAAAAQMEAgUFBQQCAQEBAQECAgICBAQEAgEAAAAAAAAAAAABAwQCBQUFBQQDAwMDAgQEBAQFAgIEAwEBAAAAAAAAAAEDBAIFBQUFAgQEBgYEBQUFBQICAgIEAwMBAQAAAAAAAQMEAgUFBQICAgMDAwIFBQUFBQICAgIGBgMCAQAAAAABAwQCBQUFAgICAgMDAgUFBQUFAgICAwMDBAQCAQEAAAEDBAIFBQUCAgICAwMCBQUFBQUCAgICAwMCAgQFAQAAAQMEAgUFBQICAgIDAwIFBQUFBAQEBAQDAwQEBQEAAAABAwQCBQUFAgICAgMDAgUFBAQFAgICAgYGAgUBAAAAAAEDBAIEBAQEBAICAwMCBQQFBQEBAQEBAwMBAQAAAAAAAQMEBAUFBQUCBAIDAwIEBQEBAAAAAAABAQAAAAAAAAABAwICBQEBAQECBAYGBAUBAAAAAAAAAAAAAAAAAAAAAQECAgIBAAAAAAEDAwICAQAAAAAAAAAAAAAAAAAAAAEBAQEBAQAAAAAAAAEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=="
},
"palette" : {
"rgba8888" : [ 0, 673720574, -523190018, -117903106, 945858814, -1600620290, 1484833022 ]
}
},
"diagnostics" : [ ]
@ -59,13 +59,13 @@
"last_modified" : 1779659315452,
"fingerprint" : "6dd024eb2259efaa03908ff0c3b75eb67f9da56d365e4a35d8e619b71c7507db",
"metadata" : {
"palette" : {
"rgba8888" : [ 0, 255, -540033025, -134746113, -101191169, 945858815, 1501544959, -1617463297, -1583777281, -1583908353, -1617462785, 929015807, 962701823, 690432511 ]
},
"tile" : {
"width" : 32,
"height" : 32,
"paletteIndices" : "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAgMDBAEBAQEBAAAAAAAAAAAAAAABAQAAAAAAAAAAAAECBQYGBAIHBwgBAAAAAAAAAAEBAQICAQEAAAAAAAAAAQIFAwMGBQUFBQIBAAAAAAEBCQIHBQUDBAEBAAAAAAABAgUDAwIICAoIBQIBAQEBBwcLCwwIAgYGAwMBAAAAAAECBQMDAgoKCgoKBQMDAwIFBQgCCgIKAgIGAwEAAAAAAQIFAwMCCAgICAgCBQYGBQoKCgoCCgICAwMGAwEAAAABAgUDAggICAgICAICAwMCCAgIAggFBQUGBgYDDQAAAAECBgMCCAgICAgIAgIDAggICAgFBQoCAwMDAwQEAQAAAQIGAwIICAgICAgCAgMCCAgIBQgKAQEBAQEBAQQBAAABAgYDAggICAgIAgICAwIKCAUIAQEAAAAAAAAAAQEAAAECBgMCCAgICAUFAgIDAggFCgEAAAAAAAAAAAAAAAAAAQIGAwIICAUFCAIFBQYLBQgBAAAAAAAAAAAAAAAAAAABAgYFBQUFCAoBAQIDBAIJAQAAAAAAAAAAAAAAAAAAAQECAwIICAgBAQAAAQEBAQEAAAAAAAAAAAAAAAAAAAEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=="
},
"palette" : {
"rgba8888" : [ 0, 255, -540033025, -134746113, -101191169, 945858815, 1501544959, -1617463297, -1583777281, -1583908353, -1617462785, 929015807, 962701823, 690432511 ]
}
},
"diagnostics" : [ ]
@ -76,13 +76,13 @@
"last_modified" : 1779659315453,
"fingerprint" : "c8e30f40473deedb265be26967f6bf5f2ba35a2bd5d0a049dcb8843fa60d5600",
"metadata" : {
"palette" : {
"rgba8888" : [ 0, 538976511, 1368527103, 1907499263, -205315841, -1014890241, -1302257409, -202116097, -207461889, -476950017, 1631658239, -1300082177 ]
},
"tile" : {
"width" : 32,
"height" : 32,
"paletteIndices" : "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQICAwMBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBAQBAgIDAwMCAQAAAAAAAAAAAAAAAAAAAAAAAAAAAQUFBAQBAgIDAgICAQAAAAAAAAAAAAAAAAAAAAAAAAABBQEFBAUBAgICAgMBAAAAAAAAAAAAAAAAAAAAAAAAAAABBgEFBQUBAgECAgMBAAAAAAAAAAAAAAAAAAAAAAAAAAEGBwEFBAEBCAECAwEAAAAAAAAAAAAAAAAAAAAAAAAAAQgBBwEEAQgJAQICAQAAAAAAAAAAAAAAAAAAAAAAAAEICAEHAQQBCQYBAgIBAAAAAAAAAAAAAAAAAAAAAAAAAAEGCQkBBQEGAQUBAgEAAAAAAAAAAAAAAAAAAAAAAAAAAAEBBgYBBgEBAQABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQcBAQEBAgIBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAECAwECAwIBAgEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQECAQcHBwECAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBAEBAQEBAQECAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAgEJCgoBAgEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEJCQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQEKAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQELCwoKAQEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=="
},
"palette" : {
"rgba8888" : [ 0, 538976511, 1368527103, 1907499263, -205315841, -1014890241, -1302257409, -202116097, -207461889, -476950017, 1631658239, -1300082177 ]
}
},
"diagnostics" : [ ]
@ -93,13 +93,13 @@
"last_modified" : 1779659315454,
"fingerprint" : "58a6a9bc02d9174fdc6bcd6f71f5fb86c47d506812e83cae5b0e23a1f951dbbf",
"metadata" : {
"palette" : {
"rgba8888" : [ 0, 538976511, 1368527103, 1907499263, -205315841, -1014890241, -1302257409, -202116097, -207461889, -476950017, 1631658239, -1300082177 ]
},
"tile" : {
"width" : 32,
"height" : 32,
"paletteIndices" : "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQECAgMDAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQQEAQICAwMDAgEAAAAAAAAAAAAAAAAAAAAAAAAAAAEFBQQEAQICAwICAgEAAAAAAAAAAAAAAAAAAAAAAAAAAQUBBQQFAQICAgIDAQAAAAAAAAAAAAAAAAAAAAAAAAAAAQYBBQUFAQIBAgIDAQAAAAAAAAAAAAAAAAAAAAAAAAABBgcBBQQBAQgBAgMBAAAAAAAAAAAAAAAAAAAAAAAAAAEIAQcBBAEICQECAgEAAAAAAAAAAAAAAAAAAAAAAAABCAgBBwEEAQkGAQICAQAAAAAAAAAAAAAAAAAAAAAAAAABBgkJAQUBBgEFAQIBAAAAAAAAAAAAAAAAAAAAAAAAAAABAQYGAQYBAQEAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAEHAQEBAQECAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAgEBBwMBAwMBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBCQoBBwEDAgEBAAAAAAAAAAAAAAAAAAAAAAAAAAABAgEJCQoBAgIBAQIBAAAAAAAAAAAAAAAAAAAAAAAAAAECAgEBAQICAQECAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAgECAQECAgEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQICAgEBAQoKAQAAAAAAAAAAAAAAAAAAAAAAAAEBAQEBAQEBAQELCwoBAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQsLAQEAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=="
},
"palette" : {
"rgba8888" : [ 0, 538976511, 1368527103, 1907499263, -205315841, -1014890241, -1302257409, -202116097, -207461889, -476950017, 1631658239, -1300082177 ]
}
},
"diagnostics" : [ ]
@ -110,13 +110,13 @@
"last_modified" : 1779659315454,
"fingerprint" : "110c4f835a40bb370c7bb7761afcd69de0d38e75798d20d50f4c203aa56f213a",
"metadata" : {
"palette" : {
"rgba8888" : [ 0, 538976511, 1368527103, 1907499263, -205315841, -1014890241, -1302257409, -202116097, -207461889, -476950017, 1631658239, -1300082177 ]
},
"tile" : {
"width" : 32,
"height" : 32,
"paletteIndices" : "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQECAgMDAQEAAAEBAAAAAAAAAAAAAAAAAAAAAAABBAQEAQICAwMDAgEBAwEAAAAAAAAAAAAAAAAAAAAAAAEFBQQEAQICAwICAQIDAQAAAAAAAAAAAAAAAAAAAAAAAAEBBQQFAQICAgICAwEBAAAAAAAAAAAAAAAAAAAAAAAAAQYBBQUFAQIBAgICAQAAAAAAAAAAAAAAAAAAAAAAAAABBgcBBQQFAQgBAQEBAAAAAAAAAAAAAAAAAAAAAAAAAAEIAQcBBAUBCQEBBQUBAAAAAAAAAAAAAAAAAAAAAAABCAgBBwgBBAUBAQUBAAAAAAAAAAAAAAAAAAAAAAAAAAABBgkJBgYBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQYGBgYBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAQEBAQMBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEJCgEHAwECAwEBAQAAAAAAAAAAAAAAAAAAAAAAAAABAQkKAQcCAQIDAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAEKAQEBAQECAgEBAgELAQAAAAAAAAAAAAAAAAAAAAAAAQEKAQICAQEBAgIBAQoLAQAAAAAAAAAAAAAAAAAAAAAAAQEBAQECAgICAQEAAQEAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=="
},
"palette" : {
"rgba8888" : [ 0, 538976511, 1368527103, 1907499263, -205315841, -1014890241, -1302257409, -202116097, -207461889, -476950017, 1631658239, -1300082177 ]
}
},
"diagnostics" : [ ]
@ -127,13 +127,13 @@
"last_modified" : 1779659315455,
"fingerprint" : "2e6fb2cfbf77f4b3c0d116b9b77a3ae228cdc5671bd18320285824faef9674d3",
"metadata" : {
"palette" : {
"rgba8888" : [ 0, 538976511, 1368527103, 1907499263, -205315841, -1014890241, -1302257409, -202116097, -207461889, -476950017, 1631658239, -1300082177 ]
},
"tile" : {
"width" : 32,
"height" : 32,
"paletteIndices" : "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAAAAAAEBAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQICAwMBAQEBAwEAAAAAAAAAAAAAAAAAAAAAAAABBAQBAgIDAwMCAQMDAQAAAAAAAAAAAAAAAAAAAAAAAQUFBAQBAgIDAgICAwIBAAAAAAAAAAAAAAAAAAAAAAABBQEFBAUBAgICAgMCAQAAAAAAAAAAAAAAAAAAAAAAAAABBgEFBQUBAgECAgIBAAAAAAAAAAAAAAAAAAAAAAAAAAEGBwEFBAUBCAEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAQgBBwEEBQEJAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAEICAEHCQEEBQEFAQAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBCQkGBgEBAQUBAAAAAAAAAAAAAAAAAAAAAAAAAAABCQoBAQEGBgEBAQUBAAAAAAAAAAAAAAAAAAAAAAAAAAEKCgEHAgEBAQMBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBBwICAQIDAwEBAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAQECAgMBAQIBAAAAAAAAAAAAAAAAAAAAAAAAAQoBAQIBAgICAgECAQEAAAAAAAAAAAAAAAAAAAAAAAABCgoBAgIBAQEBAgELAQAAAAAAAAAAAAAAAAAAAAAAAAEBAQEBAQICAgIBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=="
},
"palette" : {
"rgba8888" : [ 0, 538976511, 1368527103, 1907499263, -205315841, -1014890241, -1302257409, -202116097, -207461889, -476950017, 1631658239, -1300082177 ]
}
},
"diagnostics" : [ ]
@ -144,13 +144,13 @@
"last_modified" : 1779659315455,
"fingerprint" : "c8e30f40473deedb265be26967f6bf5f2ba35a2bd5d0a049dcb8843fa60d5600",
"metadata" : {
"palette" : {
"rgba8888" : [ 0, 538976511, 1368527103, 1907499263, -205315841, -1014890241, -1302257409, -202116097, -207461889, -476950017, 1631658239, -1300082177 ]
},
"tile" : {
"width" : 32,
"height" : 32,
"paletteIndices" : "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQICAwMBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBAQBAgIDAwMCAQAAAAAAAAAAAAAAAAAAAAAAAAAAAQUFBAQBAgIDAgICAQAAAAAAAAAAAAAAAAAAAAAAAAABBQEFBAUBAgICAgMBAAAAAAAAAAAAAAAAAAAAAAAAAAABBgEFBQUBAgECAgMBAAAAAAAAAAAAAAAAAAAAAAAAAAEGBwEFBAEBCAECAwEAAAAAAAAAAAAAAAAAAAAAAAAAAQgBBwEEAQgJAQICAQAAAAAAAAAAAAAAAAAAAAAAAAEICAEHAQQBCQYBAgIBAAAAAAAAAAAAAAAAAAAAAAAAAAEGCQkBBQEGAQUBAgEAAAAAAAAAAAAAAAAAAAAAAAAAAAEBBgYBBgEBAQABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQcBAQEBAgIBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAECAwECAwIBAgEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQECAQcHBwECAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBAEBAQEBAQECAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAgEJCgoBAgEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEJCQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQEKAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQELCwoKAQEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=="
},
"palette" : {
"rgba8888" : [ 0, 538976511, 1368527103, 1907499263, -205315841, -1014890241, -1302257409, -202116097, -207461889, -476950017, 1631658239, -1300082177 ]
}
},
"diagnostics" : [ ]
@ -161,13 +161,13 @@
"last_modified" : 1779659315456,
"fingerprint" : "94ac699b5e913925cf881e76ff951875147b598b1ee9870187111e7ca0b40d1d",
"metadata" : {
"palette" : {
"rgba8888" : [ 0, 538976511, 1368527103, 1907499263, -205315841, -1014890241, -1302257409, -202116097, -207461889, -476950017, 1631658239 ]
},
"tile" : {
"width" : 32,
"height" : 32,
"paletteIndices" : "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQICAwMBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBAQBAgIDAwMCAQAAAAAAAAAAAAAAAAAAAAAAAAAAAQUFBAQBAgIDAgICAQAAAAAAAAAAAAAAAAAAAAAAAAABBQEFBAUBAgICAgMBAAAAAAAAAAAAAAAAAAAAAAAAAAABBgEFBQUBAgECAgMBAAAAAAAAAAAAAAAAAAAAAAAAAAEGBwEFBAEBCAECAwEAAAAAAAAAAAAAAAAAAAAAAAAAAQgBBwEEAQgJAQICAQAAAAAAAAAAAAAAAAAAAAAAAAEICAEHAQQBCQYBAgIBAAAAAAAAAAAAAAAAAAAAAAAAAAEGCQkBBQEGAQUBAgEAAAAAAAAAAAAAAAAAAAAAAAAAAAEBBgYBAQEBAQABAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQcBAQEDAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAwMBAgcHAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQMDAwIBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAABBAIDAgEKCgECAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAECAQEBAQkJAQIBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQECAgICAQECAQoBAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAQICAgEKCgEAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBCgoKAQAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAQEBAQEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAQEBAQEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=="
},
"palette" : {
"rgba8888" : [ 0, 538976511, 1368527103, 1907499263, -205315841, -1014890241, -1302257409, -202116097, -207461889, -476950017, 1631658239 ]
}
},
"diagnostics" : [ ]
@ -178,13 +178,13 @@
"last_modified" : 1779659315457,
"fingerprint" : "fc0a623650619ca39c1ce2f9f9e1b0f6951abd194e18ea60c682fae6a769df97",
"metadata" : {
"palette" : {
"rgba8888" : [ 0, 538976511, 1368527103, 1907499263, -205315841, -1014890241, -1302257409, -202116097, -207461889, -476950017, 1631658239, -1300082177 ]
},
"tile" : {
"width" : 32,
"height" : 32,
"paletteIndices" : "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQICAwMBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAEEBAQBAgIDAwMCAQABAQAAAAAAAAAAAAAAAAAAAAAAAQUFBAQBAgIDAgIBAQMBAAAAAAAAAAAAAAAAAAAAAAAAAQEFBAUBAgICAgIDAwEAAAAAAAAAAAAAAAAAAAAAAAABBgEFBQUBAgECAgIBAAAAAAAAAAAAAAAAAAAAAAAAAAEGBwEFBAUBCAEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAQgBBwEEBQEJAQEFBQEAAAAAAAAAAAAAAAAAAAAAAAEICAEHCAEEBQEBBQEBAAAAAAAAAAAAAAAAAAAAAAAAAAEGCQkGBgEBAQEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBBgYGAQIDAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAABCQEBAQEBAQEHAQAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBBwcDAgEKCgEBAAAAAAAAAAAAAAAAAAAAAAAAAAABAgIBAwMCAQkJAQEAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQIBAgMCAQEBCgEAAAAAAAAAAAAAAAAAAAAAAAABCwsKAQIBAQECAgEKAQAAAAAAAAAAAAAAAAAAAAAAAAABCwsKAQICAgIBCgoBAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAQEBAQEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAQEBAQEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=="
},
"palette" : {
"rgba8888" : [ 0, 538976511, 1368527103, 1907499263, -205315841, -1014890241, -1302257409, -202116097, -207461889, -476950017, 1631658239, -1300082177 ]
}
},
"diagnostics" : [ ]
@ -195,13 +195,13 @@
"last_modified" : 1779659315457,
"fingerprint" : "7ada8efefcd6d069b10846fefb9bd9cff1a1fa4c1565bbebfd68fc83645f0732",
"metadata" : {
"palette" : {
"rgba8888" : [ 0, 538976511, 1368527103, 1907499263, -205315841, -1014890241, -1302257409, -202116097, -207461889, -476950017, 1631658239, -1300082177 ]
},
"tile" : {
"width" : 32,
"height" : 32,
"paletteIndices" : "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBAAAAAAEBAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQICAwMBAQEBAwEAAAAAAAAAAAAAAAAAAAAAAAABBAQBAgIDAwMCAQMDAQAAAAAAAAAAAAAAAAAAAAAAAQUFBAQBAgIDAgICAwIBAAAAAAAAAAAAAAAAAAAAAAABBQEFBAUBAgICAgMCAQAAAAAAAAAAAAAAAAAAAAAAAAABBgEFBQUBAgECAgIBAAAAAAAAAAAAAAAAAAAAAAAAAAEGBwEFBAUBCAEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAQgBBwEEBQEJAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAEICAEHCQEEBQEFAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAEGCQkGBgEBAQEBAAAAAAAAAAAAAAAAAAAAAAAAAAABAQEBBgYGAQIDAgEBAAAAAAAAAAAAAAAAAAAAAAAAAAEJAQEBAQEBAgIBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBBwcDAgIBAQoKAQAAAAAAAAAAAAAAAAAAAAAAAAAAAQQBAwMDAgIBCQkBAAAAAAAAAAAAAAAAAAAAAAAAAAEBAgECAwMCAQEBAQEAAAAAAAAAAAAAAAAAAAAAAAABCwYBAgEBAQECAgEKAQAAAAAAAAAAAAAAAAAAAAAAAAELCgYBAgICAgEBAQEAAAAAAAAAAAAAAAAAAAAAAAAAAAEKCgoBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQEBAAAAAAAAAAAAAAAAAAAAAAAAAAAAAQEBAQEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQEBAQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=="
},
"palette" : {
"rgba8888" : [ 0, 538976511, 1368527103, 1907499263, -205315841, -1014890241, -1302257409, -202116097, -207461889, -476950017, 1631658239, -1300082177 ]
}
},
"diagnostics" : [ ]
@ -250,13 +250,13 @@
"last_modified" : 1776965154257,
"fingerprint" : "8771c3e294d0edbc8dd3aaa6995a6db32166ae6bfb3e063170cc79b298d17e71",
"metadata" : {
"palette" : {
"rgba8888" : [ 1217939711 ]
},
"tile" : {
"width" : 8,
"height" : 8,
"paletteIndices" : "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=="
},
"palette" : {
"rgba8888" : [ 1217939711 ]
}
},
"diagnostics" : [ ]
@ -267,13 +267,13 @@
"last_modified" : 1776965154257,
"fingerprint" : "5d81eef8be13043330b42b546e10beed8ba00dfaa42df67477a8778c2b9484d7",
"metadata" : {
"palette" : {
"rgba8888" : [ 1217939711, 1081622783, 677921023, 676868351, 673720575, -2005909249, -1466932993, 1615868159 ]
},
"tile" : {
"width" : 8,
"height" : 8,
"paletteIndices" : "AAAAAAAAAAAAAAAAAAEBAQABAQEBAQEBAQIDBAQEBAMCAwQFBQUFBAIDBAUFBgYHAgMEBwUFBwcAAgQEBwcHBg=="
},
"palette" : {
"rgba8888" : [ 1217939711, 1081622783, 677921023, 676868351, 673720575, -2005909249, -1466932993, 1615868159 ]
}
},
"diagnostics" : [ ]
@ -284,13 +284,13 @@
"last_modified" : 1776965154258,
"fingerprint" : "3250840c4fe08c134ea966ce7c8fcaccae2c2a45660d7173c5e262a2e5076548",
"metadata" : {
"palette" : {
"rgba8888" : [ 1081622783, 676868351, 673720575, 1615868159, -1466932993, -2005909249 ]
},
"tile" : {
"width" : 8,
"height" : 8,
"paletteIndices" : "AAAAAAABAgIAAAAAAQIDBAAAAAECAwQEAAECAgMDAwMCAgUEBAQEBAMFBAQFBQUFBAQEBQUEBAQEBQUFBAQFBQ=="
},
"palette" : {
"rgba8888" : [ 1081622783, 676868351, 673720575, 1615868159, -1466932993, -2005909249 ]
}
},
"diagnostics" : [ ]
@ -301,13 +301,13 @@
"last_modified" : 1776965154258,
"fingerprint" : "fe3ab2b7eb3b10a042de14484d53e718e6b505edb1ad19053668565bfe3a8f25",
"metadata" : {
"palette" : {
"rgba8888" : [ 673720575, 676868351, 1081622783, -1466932993, 1615868159, -2005909249 ]
},
"tile" : {
"width" : 8,
"height" : 8,
"paletteIndices" : "AAABAgICAgIDBAABAgICAgMDBAABAgICBAQEBAAAAQIDAwMDAwUAAAUFBQUDAwUEAwMDBQUDAwMFBQMDBQUFAw=="
},
"palette" : {
"rgba8888" : [ 673720575, 676868351, 1081622783, -1466932993, 1615868159, -2005909249 ]
}
},
"diagnostics" : [ ]
@ -318,13 +318,13 @@
"last_modified" : 1776965154259,
"fingerprint" : "7fcbf90e1e9a69d6ce3be80ea1901d66c9992f68dc72e4c636dcd2ad52fa2898",
"metadata" : {
"palette" : {
"rgba8888" : [ 1217939711, 1081622783, 676868351, 673720575, 677921023, -2005909249, 1615868159, -1466932993 ]
},
"tile" : {
"width" : 8,
"height" : 8,
"paletteIndices" : "AAAAAAAAAAABAQEAAAAAAAEBAQEBAQEAAgMDAwMCBAEDBQUFBQMCBAYHBwUFAwIEBgYFBQYDAgQHBgYGAwMEAA=="
},
"palette" : {
"rgba8888" : [ 1217939711, 1081622783, 676868351, 673720575, 677921023, -2005909249, 1615868159, -1466932993 ]
}
},
"diagnostics" : [ ]
@ -335,13 +335,13 @@
"last_modified" : 1776965154259,
"fingerprint" : "451fc8d646049944d5aa7c7dc254636eec0151aaff6e2051059304b9d6ebc31e",
"metadata" : {
"palette" : {
"rgba8888" : [ 1217939711, 677921023, 676868351, 673720575, 1615868159, -1466932993, -2005909249 ]
},
"tile" : {
"width" : 8,
"height" : 8,
"paletteIndices" : "AAECAwMEBQUAAAECAwUFBgAAAAIDBQYGAAAAAwMFBgYAAAMEAwUGBgADBgQDBQYGAwYFBAMFBgYDBgUEAwUGBg=="
},
"palette" : {
"rgba8888" : [ 1217939711, 677921023, 676868351, 673720575, 1615868159, -1466932993, -2005909249 ]
}
},
"diagnostics" : [ ]
@ -352,13 +352,13 @@
"last_modified" : 1776965154260,
"fingerprint" : "aa757df4600823ec6655235a1081061777124ccee74b31481bbe402e53635f53",
"metadata" : {
"palette" : {
"rgba8888" : [ -2005909249, -1466932993, 1615868159, 673720575 ]
},
"tile" : {
"width" : 8,
"height" : 8,
"paletteIndices" : "AAABAgIAAAAAAQEAAgIAAQEBAAAAAgIBAQEAAAECAwIBAQAAAQIDAwEBAAABAgMDAQEAAAECAwIBAQEAAgMCAQ=="
},
"palette" : {
"rgba8888" : [ -2005909249, -1466932993, 1615868159, 673720575 ]
}
},
"diagnostics" : [ ]
@ -369,13 +369,13 @@
"last_modified" : 1776965154260,
"fingerprint" : "38162157f5685cce25b835d3a2caee3465fd2ec3ee5db2a5089d7d5ae5ea3bb7",
"metadata" : {
"palette" : {
"rgba8888" : [ -2005909249, 1615868159, -1466932993, 673720575 ]
},
"tile" : {
"width" : 8,
"height" : 8,
"paletteIndices" : "AAAAAQECAAACAAEBAAICAAIBAQAAAAICAQMBAgAAAgIDAwECAAACAgMDAQIAAAICAQMBAgAAAgICAQMBAAICAg=="
},
"palette" : {
"rgba8888" : [ -2005909249, 1615868159, -1466932993, 673720575 ]
}
},
"diagnostics" : [ ]
@ -386,13 +386,13 @@
"last_modified" : 1776965154260,
"fingerprint" : "8cab5b3d553af9ed371bd19fc624763accc90e5d926d300ba31dd8d9d6bab803",
"metadata" : {
"palette" : {
"rgba8888" : [ -1466932993, 1615868159, 673720575, 676868351, 677921023, 1217939711, -2005909249 ]
},
"tile" : {
"width" : 8,
"height" : 8,
"paletteIndices" : "AAABAgIDBAUGAAACAwQFBQYGAAIDBQUFBgYAAgIFBQUGBgACAQIFBQYGAAIBBgIFBgYAAgEABgIGBgACAQAGAg=="
},
"palette" : {
"rgba8888" : [ -1466932993, 1615868159, 673720575, 676868351, 677921023, 1217939711, -2005909249 ]
}
},
"diagnostics" : [ ]
@ -403,13 +403,13 @@
"last_modified" : 1776965154261,
"fingerprint" : "d9ff5a6df0f65f5fcfb8f22376beeb266d429e2c6e9c82f51c12bc6ee4c3fcdc",
"metadata" : {
"palette" : {
"rgba8888" : [ 673720575, 1615868159, -2005909249, -1466932993, 676868351, 677921023, 1217939711 ]
},
"tile" : {
"width" : 8,
"height" : 8,
"paletteIndices" : "AAECAQEAAwIEAAABAQADAwQFBAABAQADBgUEBAABAAAGBgUFBAAAAQYGBgUEAAICBgYGBgAAAgIGBgYEAAEBAg=="
},
"palette" : {
"rgba8888" : [ 673720575, 1615868159, -2005909249, -1466932993, 676868351, 677921023, 1217939711 ]
}
},
"diagnostics" : [ ]
@ -420,13 +420,13 @@
"last_modified" : 1776965154261,
"fingerprint" : "b9ff45c77f7779a6acebcc537c2ddac0e27e91162b656a04dc4772ec5f24fc26",
"metadata" : {
"palette" : {
"rgba8888" : [ -2005909249, -1466932993, 1615868159, 673720575 ]
},
"tile" : {
"width" : 8,
"height" : 8,
"paletteIndices" : "AAEBAgIAAAEAAAICAQEAAAEAAAAAAQEAAQEBAQAAAQEDAgIBAQAAAAIDAgIBAQAAAAIDAgICAQEAAgIDAgICAg=="
},
"palette" : {
"rgba8888" : [ -2005909249, -1466932993, 1615868159, 673720575 ]
}
},
"diagnostics" : [ ]
@ -437,13 +437,13 @@
"last_modified" : 1776965154261,
"fingerprint" : "43f370324fedccda888d49409e2a64f182f08b4143b4bdd5bafaf498feebd21a",
"metadata" : {
"palette" : {
"rgba8888" : [ -1466932993, -2005909249, 1615868159, 673720575 ]
},
"tile" : {
"width" : 8,
"height" : 8,
"paletteIndices" : "AAEBAgIAAAEBAQAAAgIBAQEAAAEBAQEAAAABAQAAAAABAQEAAAICAwEBAAACAgMCAAACAgIDAgECAgICAwICAQ=="
},
"palette" : {
"rgba8888" : [ -1466932993, -2005909249, 1615868159, 673720575 ]
}
},
"diagnostics" : [ ]
@ -454,13 +454,13 @@
"last_modified" : 1776965154262,
"fingerprint" : "cb047e655f4e196f22ca0048149df5dcb959f895faeaeb94920182d4a2d16b38",
"metadata" : {
"palette" : {
"rgba8888" : [ -2005909249, -1466932993, 673720575, 1615868159, 676868351, 677921023, 1217939711 ]
},
"tile" : {
"width" : 8,
"height" : 8,
"paletteIndices" : "AAECAwMAAwIBAQIDAwICBAECAwMCBAUEAgIDAgQEBQYDAgIEBQUGBgAAAgQFBgYGAAACAgYGBgYAAwMCBAYGBg=="
},
"palette" : {
"rgba8888" : [ -2005909249, -1466932993, 673720575, 1615868159, 676868351, 677921023, 1217939711 ]
}
},
"diagnostics" : [ ]
@ -471,13 +471,13 @@
"last_modified" : 1776965154262,
"fingerprint" : "25eba17b67dd5159f5fb9d3edd531d54a44d1c76f997385840dac53517b98886",
"metadata" : {
"palette" : {
"rgba8888" : [ 1217939711, 673720575, -2005909249, 1615868159, 676868351, 677921023 ]
},
"tile" : {
"width" : 8,
"height" : 8,
"paletteIndices" : "AAAAAQICAwMAAAECAgICAwAAAQICAgIDAAABAgIDAQMAAAEDAQQEAQAABAQFBAUEAAAAAAAFAAUAAAAAAAAAAA=="
},
"palette" : {
"rgba8888" : [ 1217939711, 673720575, -2005909249, 1615868159, 676868351, 677921023 ]
}
},
"diagnostics" : [ ]
@ -488,13 +488,13 @@
"last_modified" : 1776965154262,
"fingerprint" : "32ca96c14290de8009fd2db623f55514bed2345b7d5881a80dd3fe6235012854",
"metadata" : {
"palette" : {
"rgba8888" : [ 1615868159, 673720575, 676868351, -2005909249, 677921023, 1217939711 ]
},
"tile" : {
"width" : 8,
"height" : 8,
"paletteIndices" : "AAAAAQAAAQEBAAEBAAEAAAEBAgEBAAADAQICAgEAAAMCAgQCAgEAAAQEBQQEAQADBQUFBQUCAQAFBQUFBQUCAQ=="
},
"palette" : {
"rgba8888" : [ 1615868159, 673720575, 676868351, -2005909249, 677921023, 1217939711 ]
}
},
"diagnostics" : [ ]
@ -505,13 +505,13 @@
"last_modified" : 1776965154263,
"fingerprint" : "7a093fe00c805bcf38d4facff14a6d4c2b8baeaa2d553fa8d3db9f2d76b32f3b",
"metadata" : {
"palette" : {
"rgba8888" : [ 673720575, 1615868159, -2005909249, 676868351, 677921023, 1217939711 ]
},
"tile" : {
"width" : 8,
"height" : 8,
"paletteIndices" : "AAABAQABAQEBAQABAAABAAIBAQAAAwAAAgEBAAMDAwABAQADAwQDAwIBAAQEBQQEAQADBQUFBQUAAwUFBQUFBQ=="
},
"palette" : {
"rgba8888" : [ 673720575, 1615868159, -2005909249, 676868351, 677921023, 1217939711 ]
}
},
"diagnostics" : [ ]
@ -522,13 +522,13 @@
"last_modified" : 1776965154263,
"fingerprint" : "77c5277220421226d16f58b1bcfb4eaf157fa4f6c740c5aaebefaf88fb91c22e",
"metadata" : {
"palette" : {
"rgba8888" : [ 1615868159, -2005909249, 673720575, 1217939711, 676868351, 677921023 ]
},
"tile" : {
"width" : 8,
"height" : 8,
"paletteIndices" : "AAABAQIDAwMAAQEBAQIDAwABAQEBAgMDAAIAAQECAwMCBAQCAAIDAwQFBAUEBAMDBQMFAwMDAwMDAwMDAwMDAw=="
},
"palette" : {
"rgba8888" : [ 1615868159, -2005909249, 673720575, 1217939711, 676868351, 677921023 ]
}
},
"diagnostics" : [ ]