dev/glyph-bank-alignment #3

Merged
bquarkz merged 4 commits from dev/glyph-bank-alignment into master 2026-04-10 06:14:08 +00:00
46 changed files with 467 additions and 185 deletions
Showing only changes of commit 99e9102004 - Show all commits

View File

@ -1,4 +1,5 @@
{"type":"meta","next_id":{"DSC":25,"AGD":28,"DEC":25,"PLN":48,"LSN":40,"CLSN":1}} {"type":"meta","next_id":{"DSC":27,"AGD":29,"DEC":26,"PLN":49,"LSN":40,"CLSN":1}}
{"type":"discussion","id":"DSC-0026","status":"open","ticket":"glyph-bank-naming-alignment-with-runtime","title":"Glyph Bank Naming Alignment with Runtime DEC-0006","created_at":"2026-04-10","updated_at":"2026-04-10","tags":["packer","studio","naming","asset-contract","runtime-alignment","glyph-bank"],"agendas":[{"id":"AGD-0028","file":"AGD-0028-glyph-bank-naming-alignment-with-runtime.md","status":"accepted","created_at":"2026-04-10","updated_at":"2026-04-10"}],"decisions":[{"id":"DEC-0025","file":"DEC-0025-glyph-bank-local-alignment-with-runtime.md","status":"in_progress","created_at":"2026-04-10","updated_at":"2026-04-10","ref_agenda":"AGD-0028"}],"plans":[{"id":"PLN-0048","file":"PLN-0048-implement-glyph-bank-local-alignment.md","status":"done","created_at":"2026-04-10","updated_at":"2026-04-10","ref_decisions":["DEC-0025"]}],"lessons":[]}
{"type":"discussion","id":"DSC-0025","status":"done","ticket":"packer-pipeline-metadata-ownership","title":"Pipeline Metadata Ownership and Runtime Contract","created_at":"2026-04-09","updated_at":"2026-04-10","tags":["packer","metadata","runtime-contract","tooling","studio"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0039","file":"discussion/lessons/DSC-0025-packer-pipeline-metadata-ownership/LSN-0039-runtime-header-boundary-and-tooling-owned-pipeline-metadata.md","status":"done","created_at":"2026-04-10","updated_at":"2026-04-10"}]} {"type":"discussion","id":"DSC-0025","status":"done","ticket":"packer-pipeline-metadata-ownership","title":"Pipeline Metadata Ownership and Runtime Contract","created_at":"2026-04-09","updated_at":"2026-04-10","tags":["packer","metadata","runtime-contract","tooling","studio"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0039","file":"discussion/lessons/DSC-0025-packer-pipeline-metadata-ownership/LSN-0039-runtime-header-boundary-and-tooling-owned-pipeline-metadata.md","status":"done","created_at":"2026-04-10","updated_at":"2026-04-10"}]}
{"type":"discussion","id":"DSC-0024","status":"done","ticket":"jacoco-reports-consolidation","title":"JaCoCo Reports Consolidation in Gradle","created_at":"2026-04-07","updated_at":"2026-04-07","tags":["infra","gradle","jacoco","coverage","jenkins"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0038","file":"discussion/lessons/DSC-0024-jacoco-reports-consolidation/LSN-0038-jacoco-reports-consolidation.md","status":"done","created_at":"2026-04-07","updated_at":"2026-04-07"}]} {"type":"discussion","id":"DSC-0024","status":"done","ticket":"jacoco-reports-consolidation","title":"JaCoCo Reports Consolidation in Gradle","created_at":"2026-04-07","updated_at":"2026-04-07","tags":["infra","gradle","jacoco","coverage","jenkins"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0038","file":"discussion/lessons/DSC-0024-jacoco-reports-consolidation/LSN-0038-jacoco-reports-consolidation.md","status":"done","created_at":"2026-04-07","updated_at":"2026-04-07"}]}
{"type":"discussion","id":"DSC-0001","status":"done","ticket":"studio-docs-import","title":"Import docs/studio into discussion-framework artifacts","created_at":"2026-03-26","updated_at":"2026-03-26","tags":["studio","migration","discussion-framework","docs-import"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0001","file":"discussion/lessons/DSC-0001-studio-docs-import/LSN-0001-assets-workspace-execution-wave-legacy.md","status":"done","created_at":"2026-03-26","updated_at":"2026-03-26"},{"id":"LSN-0002","file":"discussion/lessons/DSC-0001-studio-docs-import/LSN-0002-bank-composition-editor-legacy.md","status":"done","created_at":"2026-03-26","updated_at":"2026-03-26"},{"id":"LSN-0003","file":"discussion/lessons/DSC-0001-studio-docs-import/LSN-0003-mental-model-asset-mutations-legacy.md","status":"done","created_at":"2026-03-26","updated_at":"2026-03-26"},{"id":"LSN-0004","file":"discussion/lessons/DSC-0001-studio-docs-import/LSN-0004-mental-model-assets-workspace-legacy.md","status":"done","created_at":"2026-03-26","updated_at":"2026-03-26"},{"id":"LSN-0005","file":"discussion/lessons/DSC-0001-studio-docs-import/LSN-0005-mental-model-studio-events-and-components-legacy.md","status":"done","created_at":"2026-03-26","updated_at":"2026-03-26"},{"id":"LSN-0006","file":"discussion/lessons/DSC-0001-studio-docs-import/LSN-0006-mental-model-studio-shell-legacy.md","status":"done","created_at":"2026-03-26","updated_at":"2026-03-26"},{"id":"LSN-0007","file":"discussion/lessons/DSC-0001-studio-docs-import/LSN-0007-pack-wizard-shell-legacy.md","status":"done","created_at":"2026-03-26","updated_at":"2026-03-26"},{"id":"LSN-0008","file":"discussion/lessons/DSC-0001-studio-docs-import/LSN-0008-project-scoped-state-and-activity-legacy.md","status":"done","created_at":"2026-03-26","updated_at":"2026-03-26"},{"id":"LSN-0016","file":"discussion/lessons/DSC-0001-studio-docs-import/LSN-0016-studio-docs-import-pattern.md","status":"done","created_at":"2026-03-26","updated_at":"2026-03-26"}]} {"type":"discussion","id":"DSC-0001","status":"done","ticket":"studio-docs-import","title":"Import docs/studio into discussion-framework artifacts","created_at":"2026-03-26","updated_at":"2026-03-26","tags":["studio","migration","discussion-framework","docs-import"],"agendas":[],"decisions":[],"plans":[],"lessons":[{"id":"LSN-0001","file":"discussion/lessons/DSC-0001-studio-docs-import/LSN-0001-assets-workspace-execution-wave-legacy.md","status":"done","created_at":"2026-03-26","updated_at":"2026-03-26"},{"id":"LSN-0002","file":"discussion/lessons/DSC-0001-studio-docs-import/LSN-0002-bank-composition-editor-legacy.md","status":"done","created_at":"2026-03-26","updated_at":"2026-03-26"},{"id":"LSN-0003","file":"discussion/lessons/DSC-0001-studio-docs-import/LSN-0003-mental-model-asset-mutations-legacy.md","status":"done","created_at":"2026-03-26","updated_at":"2026-03-26"},{"id":"LSN-0004","file":"discussion/lessons/DSC-0001-studio-docs-import/LSN-0004-mental-model-assets-workspace-legacy.md","status":"done","created_at":"2026-03-26","updated_at":"2026-03-26"},{"id":"LSN-0005","file":"discussion/lessons/DSC-0001-studio-docs-import/LSN-0005-mental-model-studio-events-and-components-legacy.md","status":"done","created_at":"2026-03-26","updated_at":"2026-03-26"},{"id":"LSN-0006","file":"discussion/lessons/DSC-0001-studio-docs-import/LSN-0006-mental-model-studio-shell-legacy.md","status":"done","created_at":"2026-03-26","updated_at":"2026-03-26"},{"id":"LSN-0007","file":"discussion/lessons/DSC-0001-studio-docs-import/LSN-0007-pack-wizard-shell-legacy.md","status":"done","created_at":"2026-03-26","updated_at":"2026-03-26"},{"id":"LSN-0008","file":"discussion/lessons/DSC-0001-studio-docs-import/LSN-0008-project-scoped-state-and-activity-legacy.md","status":"done","created_at":"2026-03-26","updated_at":"2026-03-26"},{"id":"LSN-0016","file":"discussion/lessons/DSC-0001-studio-docs-import/LSN-0016-studio-docs-import-pattern.md","status":"done","created_at":"2026-03-26","updated_at":"2026-03-26"}]}

View File

@ -20,8 +20,8 @@ This lesson preserves the first-wave producer contract for tile-bank assets.
### Tile bank packing emits one canonical payload per asset with explicit normalization and early structural validation ### Tile bank packing emits one canonical payload per asset with explicit normalization and early structural validation
**What:** The first-wave contract emits one canonical `TILES/indexed_v1` payload per asset, normalizes artifacts by explicit `artifacts[*].index`, packs one fixed `256 x 256` row-major sheet with packed `u4` pixels and `RGB565` palette blocks, treats palette identity as semantic rather than positional, and surfaces structural blockers early in walker/materialization. **What:** The first-wave contract emits one canonical `GLYPH/indexed_v1` payload per asset, normalizes artifacts by explicit `artifacts[*].index`, packs one fixed `256 x 256` row-major sheet with packed `u4` pixels and `RGB565` palette blocks, treats palette identity as semantic rather than positional, and surfaces structural blockers early in walker/materialization.
**Why:** The repository needed one explicit producer contract for tile banks rather than a mix of implicit artifact ordering, late byte-emission surprises, and unstable palette identity. **Why:** The repository needed one explicit producer contract for glyph banks rather than a mix of implicit artifact ordering, late byte-emission surprises, and unstable palette identity.
**Trade-offs:** This contract is more explicit and restrictive than ad hoc per-artifact packing, but it yields stable reviewability, predictable runtime metadata, and earlier validation. **Trade-offs:** This contract is more explicit and restrictive than ad hoc per-artifact packing, but it yields stable reviewability, predictable runtime metadata, and earlier validation.
## Patterns and Algorithms ## Patterns and Algorithms

View File

@ -16,7 +16,7 @@ tags:
## Pain ## Pain
Studio already has a retained agenda for palette management in the `tile bank` form session, but that agenda exists only under `docs/studio/agendas/` and therefore sits outside the discussion-framework lifecycle. Studio already has a retained agenda for palette management in the `glyph bank` form session, but that agenda exists only under `docs/studio/agendas/` and therefore sits outside the discussion-framework lifecycle.
Without importing it into `discussion/`, the canonical discussion surface would lose the still-open Studio question about: Without importing it into `discussion/`, the canonical discussion surface would lose the still-open Studio question about:
@ -32,11 +32,11 @@ Legacy source: `docs/studio/agendas/Palette Management in Studio Agenda.md`
Domain owner: `docs/studio` Domain owner: `docs/studio`
Cross-domain impact: `docs/packer` Cross-domain impact: `docs/packer`
The retained agenda is intentionally scoped to `tile bank`. The retained agenda is intentionally scoped to `glyph bank`.
The imported context keeps the same baseline: The imported context keeps the same baseline:
- every `*.png` input of a tile bank is one tile; - every `*.png` input of a glyph bank is one tile;
- each tile yields one extracted palette during cache construction; - each tile yields one extracted palette during cache construction;
- developers may also work with favorite palettes and asset palettes; - developers may also work with favorite palettes and asset palettes;
- each bank may integrate at most `64` palettes; - each bank may integrate at most `64` palettes;
@ -57,8 +57,8 @@ The current UI shape already converged on:
- [ ] Should extracted tile palettes always enter the candidate set automatically, or can the developer suppress some of them before curation? - [ ] Should extracted tile palettes always enter the candidate set automatically, or can the developer suppress some of them before curation?
- [ ] Should clicking a palette on the `selected` side be the only interaction needed to change the previewed palette in the first wave? - [ ] Should clicking a palette on the `selected` side be the only interaction needed to change the previewed palette in the first wave?
- [ ] Which palette operations are read-only in the first wave, and which require staged preview/apply treatment? - [ ] Which palette operations are read-only in the first wave, and which require staged preview/apply treatment?
- [ ] Which parts of this interaction model should remain explicitly `tile bank`-specific, and which parts are reusable Studio form-session primitives? - [ ] Which parts of this interaction model should remain explicitly `glyph bank`-specific, and which parts are reusable Studio form-session primitives?
- [ ] Does the first release need only an asset-scoped `tile bank` section, or also a project-level palette browser for discovery and favorites management? - [ ] Does the first release need only an asset-scoped `glyph bank` section, or also a project-level palette browser for discovery and favorites management?
## Options ## Options
@ -70,7 +70,7 @@ The current UI shape already converged on:
### Option B - Asset-Scoped Curated Selection ### Option B - Asset-Scoped Curated Selection
- **Approach:** Treat bank palettes as an asset-scoped curated selection built from tile-derived palettes, favorites, and asset palettes, with Studio owning the curation UX and packer owning persistence. - **Approach:** Treat bank palettes as an asset-scoped curated selection built from tile-derived palettes, favorites, and asset palettes, with Studio owning the curation UX and packer owning persistence.
- **Pro:** Matches the concrete `tile bank` workflow and keeps authority boundaries clear. - **Pro:** Matches the concrete `glyph bank` workflow and keeps authority boundaries clear.
- **Con:** Requires explicit UX for capacity, identity, deduplication, and preview semantics. - **Con:** Requires explicit UX for capacity, identity, deduplication, and preview semantics.
- **Maintainability:** Strong. It makes responsibilities explicit and keeps family-specific rules close to the workflow that needs them. - **Maintainability:** Strong. It makes responsibilities explicit and keeps family-specific rules close to the workflow that needs them.
@ -82,7 +82,7 @@ The current UI shape already converged on:
## Discussion ## Discussion
The imported agenda keeps the original recommendation intact: palette management should be first-class for `tile bank`, but Studio must not become the persistence authority. The imported agenda keeps the original recommendation intact: palette management should be first-class for `glyph bank`, but Studio must not become the persistence authority.
That means the key open problem is not whether palettes exist. It is how Studio explains and curates them safely: That means the key open problem is not whether palettes exist. It is how Studio explains and curates them safely:
@ -90,7 +90,7 @@ That means the key open problem is not whether palettes exist. It is how Studio
- clear source and identity display; - clear source and identity display;
- explicit `1..64` capacity feedback; - explicit `1..64` capacity feedback;
- a preview model that stays tied to the selected bank palettes; - a preview model that stays tied to the selected bank palettes;
- a boundary between `tile bank`-specific UX and reusable Studio primitives. - a boundary between `glyph bank`-specific UX and reusable Studio primitives.
The retained source already converged on a pragmatic first wave: The retained source already converged on a pragmatic first wave:
@ -106,7 +106,7 @@ Recommended direction: adopt **Option B**.
The imported agenda preserves the retained Studio direction: The imported agenda preserves the retained Studio direction:
1. palette management belongs to the `tile bank` asset workflow; 1. palette management belongs to the `glyph bank` asset workflow;
2. Studio aggregates candidate palettes from tile-derived extraction, favorites, and asset palettes; 2. Studio aggregates candidate palettes from tile-derived extraction, favorites, and asset palettes;
3. the first wave uses a custom-rendered transfer list with an explicit `1..64` selected range; 3. the first wave uses a custom-rendered transfer list with an explicit `1..64` selected range;
4. the right-side preview panel stays tied to the current selected palette set; 4. the right-side preview panel stays tied to the current selected palette set;

View File

@ -53,7 +53,7 @@ The packer now exposes:
### Option A - Keep fixed 64-palette serialization ### Option A - Keep fixed 64-palette serialization
- **Approach:** Preserve the current fixed v1 payload with zero-filled unused palette slots. - **Approach:** Preserve the current fixed v1 payload with zero-filled unused palette slots.
- **Pro:** No runtime change and current specs/tests remain stable. - **Pro:** No runtime change and current specs/tests remain stable.
- **Con:** Every tile bank keeps paying the full palette cost. - **Con:** Every glyph bank keeps paying the full palette cost.
- **Maintainability:** Medium. - **Maintainability:** Medium.
### Option B - Move to variable palette serialization now ### Option B - Move to variable palette serialization now

View File

@ -0,0 +1,89 @@
---
id: AGD-0028
ticket: glyph-bank-naming-alignment-with-runtime
title: Glyph Bank Naming Alignment with Runtime DEC-0006
status: accepted
created: 2026-04-10
resolved: 2026-04-10
decision: DEC-0025
tags: [packer, studio, naming, asset-contract, runtime-alignment, glyph-bank]
---
## Pain
O runtime já aceitou a `DEC-0006` em `../runtime`, travando que o artefato gráfico concreto hoje chamado `GlyphBank` passa a ser canonicamente `GlyphBank`, com `BankType::GLYPH`, sem renomear `TileMap`, `TileLayer` ou `TileSize`.
Este repositório ainda usa vocabulário centrado em `glyph bank` no contrato de asset, nas specs do packer, em partes do Studio e nos fixtures. Se esse repositório não alinhar a nomenclatura, o ecossistema passa a operar com contrato misto entre `runtime` e `studio/packer`, exatamente o estado que a decisão upstream proibiu para superfícies ativas.
## Context
1. A decisão externa de referência é `../runtime/discussion/workflow/decisions/DEC-0006-glyph-bank-domain-naming-contract.md`.
2. Ela define que a mudança é **rename-only**: sem alterar formato, layout, payload, codec, metadata ou semântica de renderização.
3. Ela também fixa o boundary editorial:
- o artefato gráfico concreto migra para `GlyphBank` / `Glyph*`;
- conceitos geométricos e de mapa/camada continuam `tile`.
4. Neste repositório, os impactos visíveis hoje incluem:
- `AssetFamilyCatalog.TILE_BANK`;
- `OutputFormatCatalog.TILES_INDEXED_V1`;
- specs que falam em `tile_bank`, `TILES/indexed_v1` e `bank_type = TILES`;
- classes e testes do Studio/Packer nomeados como `TileBank`;
- fixtures e `asset.json` de teste usando `type = tile_bank` e `format = TILES/indexed_v1`.
5. O owner primário aqui parece ser `packer`, com impacto explícito também em `studio`.
## Open Questions
- [x] O alinhamento local deve migrar o contrato serializado imediatamente para `glyph_bank` / `GLYPH/indexed_v1` / `bank_type = GLYPH`, ou precisamos de uma fase explícita de compatibilidade de leitura para manifests e fixtures legados?
Resposta: migrar imediatamente o contrato serializado. Não haverá fase de compatibilidade.
- [x] O `AssetFamilyCatalog.TILE_BANK` deve ser renomeado no código local junto com o contrato serializado, ou o código pode adotar uma estratégia temporária de alias interno sem expor vocabulário misto nas superfícies mantidas?
Resposta: renomear junto com o contrato serializado. Não haverá alias nem camada de compatibilidade.
- [x] Quais superfícies do Studio ainda são realmente específicas do artefato concreto e devem virar `Glyph*`, e quais continuam corretamente no domínio geométrico `tile`?
Resposta: o Studio deve seguir a nomenclatura 1:1 do artefato concreto. Superfícies do artefato concreto migram para `Glyph*`; conceitos geométricos continuam `tile`.
- [x] O rename local deve ser tratado como uma única wave transversal `packer + studio + specs + fixtures`, ou precisamos fatiar entre contrato serializado e nomenclatura interna?
Resposta: uma única wave transversal. Trata-se de rename-only, sem mudança funcional.
## Options
### Option A - Full Local Alignment with Runtime Naming
- **Approach:** Migrar as superfícies mantidas deste repositório para `GlyphBank`/`glyph_bank`/`GLYPH` de forma consistente, preservando `tile` apenas onde o significado é geométrico ou de mapa/camada.
- **Pro:** Alinha totalmente com a `DEC-0006` upstream e elimina vocabulário misto entre repositórios ativos.
- **Con:** Toca contrato serializado, fixtures, specs e nomes internos ao mesmo tempo.
- **Maintainability:** Alta, porque reduz ambiguidade estrutural entre artifact bank e tile-domain concepts.
### Option B - Compatibility Alias Around a Deferred Rename
- **Approach:** Aceitar a direção do runtime, mas manter `tile_bank` / `TILES/indexed_v1` como contrato serializado temporário neste repositório, renomeando só docs e algumas APIs internas por enquanto.
- **Pro:** Reduz churn imediato no packer e nos fixtures.
- **Con:** Mantém exatamente o vocabulário misto que a decisão upstream quer evitar nas superfícies ativas.
- **Maintainability:** Baixa, porque exige conviver com dois nomes para o mesmo artefato concreto.
### Option C - Editorial Alignment Only
- **Approach:** Atualizar apenas specs/lessons/discussion docs para refletir `GlyphBank`, mantendo código e contrato serializado locais como estão até uma wave futura.
- **Pro:** Menor custo inicial.
- **Con:** Cria desalinhamento entre documentação e implementação local, além de não resolver o contrato ativo.
- **Maintainability:** Baixa, porque transforma o problema em dívida operacional documentada em vez de resolvê-lo.
## Discussion
A `DEC-0006` do runtime já fechou o ponto conceitual mais importante: `tile` ficou reservado para mapa/camada/geometria, enquanto o banco gráfico concreto passa a ser `glyph`.
O que continua aberto neste repositório não é a direção conceitual, mas a estratégia local de propagação:
- se o packer deve mudar o contrato serializado já nesta wave;
- se precisamos de leitura compatível para assets/fixtures legados;
- como separar corretamente as classes/strings do Studio entre domínio concreto de banco e domínio geométrico.
O risco dominante é fazer rename mecânico. Aqui, assim como no runtime, há superfícies onde `tile` ainda é o nome certo.
## Resolution
Recomendação consolidada: seguir integralmente a direção da `DEC-0006` do runtime e emitir uma decisão local owner `packer`, com impacto explícito em `studio`, para alinhar este repositório ao novo nome canônico do artefato concreto.
A resolução desta agenda fica:
1. o contrato serializado local migra imediatamente para `glyph_bank`, `GLYPH/indexed_v1` e `bank_type = GLYPH`;
2. não haverá camada de compatibilidade, alias interno, nem fase de leitura legada para o vocabulário antigo;
3. o Studio deve seguir a nomenclatura do artefato concreto em modo 1:1;
4. `tile` permanece apenas onde o significado for geométrico, de layer ou de map;
5. a propagação local será uma única wave transversal em `packer + studio + specs + fixtures`;
6. a mudança é estritamente rename-only, sem alteração de formato, layout, payload, metadata, codec ou comportamento.
Próximo passo sugerido: converter esta agenda em decisão local e travar os propagation targets para `packer`, `studio`, specs e fixtures.

View File

@ -0,0 +1,76 @@
---
id: DEC-0025
ticket: glyph-bank-naming-alignment-with-runtime
title: Glyph Bank Local Alignment with Runtime
status: in_progress
created: 2026-04-10
accepted: 2026-04-10
agenda: AGD-0028
plans: [PLN-0048]
tags: [packer, studio, naming, asset-contract, runtime-alignment, glyph-bank]
---
## Decision
This repository MUST align its active `packer` and `studio` surfaces with the runtime naming contract accepted in `../runtime` `DEC-0006`.
The concrete graphical bank artifact currently referred to locally through `tile bank`, `TileBank`, `tile_bank`, `TILES/indexed_v1`, and `bank_type = TILES` MUST migrate to `GlyphBank`, `glyph_bank`, `GLYPH/indexed_v1`, and `bank_type = GLYPH`, according to the surface involved.
This migration MUST be treated as rename-only. It MUST NOT change payload layout, metadata semantics, codec behavior, packing behavior, runtime contract meaning, Studio behavior, or any other functional behavior.
The migration MUST happen as one single transversal wave across `packer`, `studio`, specs, fixtures, tests, and maintained discussion/lesson surfaces in this repository.
There MUST NOT be a compatibility layer, alias, fallback parser, or dual-vocabulary phase for the previous `tile bank` naming on active maintained surfaces.
`tile` MUST remain in place wherever the correct meaning is geometric, map-related, layer-related, or otherwise outside the concrete graphical bank artifact boundary.
Studio MUST follow the concrete artifact naming 1:1 for the renamed artifact surfaces. It MUST NOT keep local alternative terminology for the same artifact.
## Rationale
The upstream runtime decision already closed the conceptual split between the concrete graphical bank artifact and the broader tile-domain vocabulary.
If this repository keeps the old local naming while the runtime adopts `GlyphBank`, the project enters a mixed-contract state where active repositories describe the same concrete artifact through incompatible names. That directly undermines the purpose of the upstream decision.
A no-compatibility, single-wave rename is the only option that preserves one active canonical vocabulary instead of institutionalizing drift between specs, fixtures, code, and UI.
Keeping `tile` only where the meaning is geometric or map/layer-oriented preserves the domain distinction that motivated the runtime decision in the first place.
## Technical Specification
1. The canonical local asset-family name for the concrete graphical bank artifact MUST migrate from `tile_bank` to `glyph_bank`.
2. The canonical local output format name for the concrete graphical bank artifact MUST migrate from `TILES/indexed_v1` to `GLYPH/indexed_v1`.
3. The canonical runtime-facing `bank_type` value emitted by the packer for the concrete graphical bank artifact MUST migrate from `TILES` to `GLYPH`.
4. Code symbols, class names, helpers, tests, and maintained strings that refer to the concrete graphical bank artifact MUST migrate from `Tile*`/`tile bank` naming to `Glyph*`/`glyph bank` naming as appropriate to the local language surface.
5. Specs and maintained lessons/docs in this repository MUST describe the concrete graphical bank artifact using `Glyph*` naming after the migration.
6. `tile` naming MUST remain unchanged in surfaces that describe geometric tile size, tile layers, tile maps, grid semantics, or other non-artifact tile-domain concepts.
7. Implementations MUST NOT preserve active dual support for both `tile bank` and `glyph bank` terminology in the serialized contract.
8. Fixtures and test assets maintained by this repository MUST migrate to the new serialized contract names in the same wave as the implementation.
9. This decision does not authorize any behavior change beyond naming propagation.
## Constraints
- No compatibility parser or alias layer for the old serialized names.
- No staged split between `packer` and `studio`; the rename is one coordinated wave.
- No rename of geometric or map/layer `tile` concepts.
- No change to payload bytes, metadata structure, codec semantics, or packing algorithms as part of this decision.
## Propagation Targets
- Specs:
- Update packer specs that currently define `tile_bank`, `TILES/indexed_v1`, or `bank_type = TILES`.
- Update Studio-facing maintained discussion/spec text where the concrete artifact is still described as `tile bank`.
- Code:
- Rename local packer asset-family, output-format, and emitted bank-type surfaces to the new canonical glyph naming.
- Rename Studio artifact-specific composition/support/coordinator surfaces that refer to the concrete graphical bank artifact.
- Preserve `tile` naming in geometric and map/layer surfaces.
- Tests and Fixtures:
- Update fixtures and test manifests that still serialize the old `tile_bank` and `TILES/indexed_v1` contract.
- Update tests and helper names to remove mixed vocabulary for the concrete artifact.
- Docs and Lessons:
- Rewrite maintained lessons and active workflow artifacts by meaning, not mechanical token replacement.
## Revision Log
- 2026-04-10: Accepted and linked to PLN-0048 for implementation planning.
- 2026-04-10: Initial draft from AGD-0028.

View File

@ -0,0 +1,119 @@
---
id: PLN-0048
ticket: glyph-bank-naming-alignment-with-runtime
title: Implement Glyph Bank Local Alignment
status: done
created: 2026-04-10
completed: 2026-04-10
tags: [packer, studio, naming, asset-contract, runtime-alignment, glyph-bank]
---
## Objective
Implement DEC-0025 by renaming the concrete graphical bank artifact from `tile bank` to `glyph bank` across active `packer` and `studio` code, serialized contract surfaces, specs, fixtures, tests, and maintained repository documentation, with no compatibility layer and no functional behavior change.
## Background
The runtime repository already accepted `DEC-0006`, which reserves `tile` for geometric, map, and layer concepts while moving the concrete graphical bank artifact to `GlyphBank` and `GLYPH`. This repository still exposes the old naming through local asset-family values, output formats, emitted bank types, Studio asset-family handling, specs, and fixtures. The accepted local decision locks a one-wave rename with no fallback parsing, no aliasing, and no staged split between `packer` and `studio`.
## Scope
### Included
- Rename the serialized asset-family contract from `tile_bank` to `glyph_bank`.
- Rename the serialized output-format contract from `TILES/indexed_v1` to `GLYPH/indexed_v1`.
- Rename emitted runtime-facing `bank_type` values from `TILES` to `GLYPH`.
- Rename packer and Studio artifact-specific code surfaces that still describe the concrete graphical bank as `Tile*` or `glyph bank`.
- Update fixtures, tests, specs, and maintained lessons/discussion artifacts that refer to the concrete graphical bank artifact.
- Preserve `tile` terminology where the meaning remains geometric, map-related, layer-related, or otherwise outside the artifact boundary.
### Excluded
- Any payload, layout, metadata, codec, or packing behavior change.
- Any compatibility parser, alias layer, or dual support for the previous serialized names.
- Renaming geometric tile-size concepts or map/layer terminology that is still semantically correct.
- Any broader runtime-side rename work already owned by `../runtime`.
## Execution Steps
### Step 1 - Rename the packer serialized contract surface
**What:** Migrate the local packer contract enums and parser-facing surfaces from `tile_bank` / `TILES/indexed_v1` / `TILES` to `glyph_bank` / `GLYPH/indexed_v1` / `GLYPH`.
**How:** Rename `AssetFamilyCatalog.TILE_BANK`, `OutputFormatCatalog.TILES_INDEXED_V1`, parser validation strings, materialized `bank_type` values, and any packer-owned contract constants or messages tied to the concrete artifact. Keep semantics unchanged and do not introduce compatibility parsing for the old names.
**File(s):** `prometeu-packer/prometeu-packer-api/src/main/java/p/packer/messages/assets/AssetFamilyCatalog.java`; `prometeu-packer/prometeu-packer-api/src/main/java/p/packer/messages/assets/OutputFormatCatalog.java`; `prometeu-packer/prometeu-packer-v1/src/main/java/p/packer/services/PackerAssetDeclarationParser.java`; `prometeu-packer/prometeu-packer-v1/src/main/java/p/packer/services/PackerOutputContractCatalog.java`; `prometeu-packer/prometeu-packer-v1/src/main/java/p/packer/services/FileSystemPackerWorkspaceService.java`
**Dependencies:** None.
### Step 2 - Rename packer artifact-specific implementation surfaces
**What:** Rename packer implementation types, walkers, requirements, helper methods, and diagnostics that describe the concrete graphical bank artifact.
**How:** Rename artifact-specific `TileBank` classes, helpers, and strings to `Glyph*` equivalents while preserving `tile` in geometric concepts such as `tileSize`. Adjust callsites consistently so active code no longer uses mixed vocabulary for the concrete artifact.
**File(s):** `prometeu-packer/prometeu-packer-v1/src/main/java/p/packer/models/PackerGlyphBankRequirements.java`; `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`; `prometeu-packer/prometeu-packer-v1/src/main/java/p/packer/services/FileSystemPackerWorkspaceService.java`
**Dependencies:** Step 1.
### Step 3 - Rename Studio artifact-specific surfaces 1:1
**What:** Align Studio asset-family handling, bank composition support, palette overhauling gating, list/details presentation, and artifact labels with the new glyph naming.
**How:** Rename Studio classes, switches, and i18n keys/labels that refer to the concrete graphical bank artifact, keeping the rename artifact-specific and preserving any remaining geometric `tile` semantics outside that boundary. Studio must use the same canonical artifact vocabulary as the packer contract.
**File(s):** `prometeu-studio/src/main/java/p/studio/workspaces/assets/details/bank/AssetDetailsGlyphBankCompositionFamilySupport.java`; `prometeu-studio/src/main/java/p/studio/workspaces/assets/details/bank/AssetBankCapacityService.java`; `prometeu-studio/src/main/java/p/studio/workspaces/assets/details/bank/AssetDetailsBankCompositionCoordinator.java`; `prometeu-studio/src/main/java/p/studio/workspaces/assets/details/palette/AssetDetailsPaletteOverhaulingCoordinator.java`; `prometeu-studio/src/main/java/p/studio/workspaces/assets/details/AssetDetailsUiSupport.java`; `prometeu-studio/src/main/java/p/studio/workspaces/assets/list/AssetListItemControl.java`; `prometeu-studio/src/main/java/p/studio/utilities/i18n/I18n.java`
**Dependencies:** Steps 1 and 2.
### Step 4 - Update specs, lessons, and maintained discussion text by meaning
**What:** Rewrite maintained documentation so the concrete graphical bank artifact uses glyph naming, while tile-domain concepts remain tile-domain concepts.
**How:** Update packer specs and maintained lessons/discussions manually by artifact meaning. Replace artifact-specific `tile bank` references with `glyph bank`, `glyph_bank`, `GLYPH/indexed_v1`, or `GLYPH` as appropriate, but preserve `tile` where it refers to tile geometry, tilemaps, layers, or palette-per-tile semantics.
**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`; `discussion/lessons/DSC-0003-packer-docs-import/LSN-0015-tile-bank-packing-contract-legacy.md`; `discussion/workflow/agendas/AGD-0002-palette-management-in-studio.md`; `discussion/workflow/agendas/AGD-0005-variable-tile-bank-palette-serialization.md`
**Dependencies:** Step 1.
### Step 5 - Migrate fixtures and tests in the same wave
**What:** Rename manifests, fixture content, test expectations, and helper names to the new serialized contract and artifact vocabulary.
**How:** Update test assets and fixtures that still use `type = tile_bank` and `format = TILES/indexed_v1`, then update unit and integration tests in `prometeu-packer` and `prometeu-studio` so expectations point to `glyph_bank`, `GLYPH/indexed_v1`, and `GLYPH`. Keep assertion coverage focused on proving no behavior change beyond naming.
**File(s):** `test-projects/main/assets/**/asset.json`; `prometeu-packer/prometeu-packer-v1/src/test/resources/fixtures/workspaces/**/asset.json`; `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`; `prometeu-packer/prometeu-packer-v1/src/test/java/p/packer/services/FileSystemPackerWorkspaceServiceTest.java`; `prometeu-packer/prometeu-packer-v1/src/test/java/p/packer/repositories/PackerGlyphBankWalkerTest.java`; `prometeu-packer/prometeu-packer-v1/src/test/java/p/packer/repositories/PackerRuntimeAssetMaterializerTest.java`; `prometeu-studio/src/test/java/p/studio/workspaces/assets/details/bank/AssetDetailsBankCompositionCoordinatorTest.java`; `prometeu-studio/src/test/java/p/studio/workspaces/assets/details/palette/AssetDetailsPaletteOverhaulingCoordinatorTest.java`
**Dependencies:** Steps 1 through 4.
### Step 6 - Validate the one-wave rename
**What:** Run focused verification across packer and Studio to prove the new vocabulary is canonical and behavior is unchanged.
**How:** Execute the relevant test suites, review representative specs/fixtures, and search for residual concrete-artifact `tile bank` references. Classify any remaining `tile` occurrence as either correct geometric/domain meaning or a rename miss to be fixed before completion.
**File(s):** all files touched by Steps 1 through 5
**Dependencies:** Steps 1 through 5.
## Test Requirements
### Unit Tests
- Update packer parser, walker, materializer, and workspace-service tests to use `glyph_bank`, `GLYPH/indexed_v1`, and `GLYPH`.
- Update Studio asset-details and palette/bank tests to use the renamed artifact-family symbols and labels.
### Integration Tests
- Run packer tests that exercise manifest parsing, fixture loading, pack execution, and emitted `bank_type` values.
- Run Studio tests that exercise asset-family-specific bank composition and palette overhauling paths.
### Manual Verification
- Inspect updated packer specs to confirm artifact-specific references use glyph naming while geometric tile concepts remain unchanged.
- Search the repository for residual `tile bank` / `TileBank` / `tile_bank` / `TILES/indexed_v1` references and classify each remaining hit.
- Inspect representative fixture manifests and packed output expectations to confirm the rename is contract-wide and behavior-preserving.
## Acceptance Criteria
- [ ] Active local serialized contract surfaces use `glyph_bank`, `GLYPH/indexed_v1`, and `GLYPH` for the concrete graphical bank artifact.
- [ ] No compatibility layer or alias remains for the old serialized names on active maintained surfaces.
- [ ] Packer artifact-specific code no longer uses mixed `Tile*`/`Glyph*` vocabulary for the same concrete artifact.
- [ ] Studio artifact-specific code follows the renamed glyph vocabulary 1:1.
- [ ] Maintained specs and lessons describe the concrete graphical bank artifact with glyph naming while preserving geometric/map/layer tile terminology where appropriate.
- [ ] Fixtures and tests are migrated in the same wave as the implementation.
- [ ] Relevant packer and Studio tests pass after the rename.
- [ ] No functional behavior change is introduced beyond naming propagation.
## Dependencies
- Accepted decision `DEC-0025`.
- Upstream runtime naming contract in `../runtime` `DEC-0006`.
- Coordinated updates across `prometeu-packer`, `prometeu-studio`, maintained docs, and fixture manifests.
## Risks
- Blind mechanical renaming can incorrectly touch geometric tile semantics that are explicitly out of scope.
- Removing old serialized names without compatibility means any missed fixture or parser path will fail fast and block the wave.
- Studio and packer may drift if one side is renamed more aggressively than the other during implementation.
- Historical or maintained discussion artifacts can keep mixed terminology if they are not reviewed semantically.

View File

@ -58,7 +58,7 @@ Rules:
Examples: Examples:
- `tile_bank` - `glyph_bank`
- `sound_bank` - `sound_bank`
## Inputs ## Inputs
@ -203,7 +203,7 @@ The `asset.json` schema is versioned independently from:
- runtime-facing artifact schema - runtime-facing artifact schema
- format contract versions - format contract versions
Format-specific contracts evolve through values such as `TILES/indexed_v1`. Format-specific contracts evolve through values such as `GLYPH/indexed_v1`.
## Non-Goals ## Non-Goals

View File

@ -145,15 +145,15 @@ Offset ambiguity guardrail:
- internal pipeline indexing data (for example per-sample ranges for audio banks) must live under `asset_table[].metadata`; - internal pipeline indexing data (for example per-sample ranges for audio banks) must live under `asset_table[].metadata`;
- internal indexing fields must not be interpreted as payload slicing fields. - internal indexing fields must not be interpreted as payload slicing fields.
## Format-Specific Baseline: `TILES/indexed_v1` ## Format-Specific Baseline: `GLYPH/indexed_v1`
The first-wave producer contract for `TILES/indexed_v1` is fixed and runtime-aligned. The first-wave producer contract for `GLYPH/indexed_v1` is fixed and runtime-aligned.
### Tile Selection and Identity ### Tile Selection and Identity
Rules: Rules:
- only selected artifacts participate in the emitted tile bank; - only selected artifacts participate in the emitted glyph bank;
- `1 artifact = 1 tile` in v1; - `1 artifact = 1 tile` in v1;
- artifacts are normalized by ascending `artifacts[*].index`; - artifacts are normalized by ascending `artifacts[*].index`;
- emitted `tile_id` equals the normalized artifact index; - emitted `tile_id` equals the normalized artifact index;
@ -176,7 +176,7 @@ Rules:
Rules: Rules:
- the serialized payload for `TILES/indexed_v1` is: - the serialized payload for `GLYPH/indexed_v1` is:
1. one packed `u4` pixel plane for the full emitted sheet; 1. one packed `u4` pixel plane for the full emitted sheet;
2. one palette block of `64 * 16 * 2 = 2048` bytes; 2. one palette block of `64 * 16 * 2 = 2048` bytes;
- packed pixel bytes must be emitted by the packer, not inferred later by the runtime; - packed pixel bytes must be emitted by the packer, not inferred later by the runtime;
@ -189,7 +189,7 @@ Rules:
Rules: Rules:
- emitted tile-bank entries use: - emitted tile-bank entries use:
- `bank_type = TILES` - `bank_type = GLYPH`
- `codec = NONE` - `codec = NONE`
- tile-bank v1 metadata must expose at least: - tile-bank v1 metadata must expose at least:
- `tile_size` - `tile_size`
@ -208,7 +208,7 @@ Rules:
- bank palettes are declared under `output.pipeline.palettes`; - bank palettes are declared under `output.pipeline.palettes`;
- each palette declaration uses the shape `{ "index": <int>, "palette": { ... } }`; - each palette declaration uses the shape `{ "index": <int>, "palette": { ... } }`;
- palette ordering is ascending numeric `index`, never raw array position; - palette ordering is ascending numeric `index`, never raw array position;
- palette ids in the emitted tile bank are the normalized declared palette indices; - palette ids in the emitted glyph bank are the normalized declared palette indices;
- any tile in the bank may be rendered with any palette in the bank at runtime; - any tile in the bank may be rendered with any palette in the bank at runtime;
- palette selection is a runtime draw concern, not a tile-payload embedding concern. - palette selection is a runtime draw concern, not a tile-payload embedding concern.

View File

@ -3,7 +3,7 @@ package p.packer.messages.assets;
import java.util.Locale; import java.util.Locale;
public enum AssetFamilyCatalog { public enum AssetFamilyCatalog {
TILE_BANK("tile_bank"), GLYPH_BANK("glyph_bank"),
SOUND_BANK("sound_bank"), SOUND_BANK("sound_bank"),
UNKNOWN("unknown"); UNKNOWN("unknown");

View File

@ -4,7 +4,7 @@ import java.util.List;
import java.util.Locale; import java.util.Locale;
public enum OutputFormatCatalog { public enum OutputFormatCatalog {
TILES_INDEXED_V1(AssetFamilyCatalog.TILE_BANK, "TILES/indexed_v1", "TILES/indexed_v1"), GLYPH_INDEXED_V1(AssetFamilyCatalog.GLYPH_BANK, "GLYPH/indexed_v1", "GLYPH/indexed_v1"),
SOUND_V1(AssetFamilyCatalog.SOUND_BANK, "SOUND/v1", "SOUND/v1"), SOUND_V1(AssetFamilyCatalog.SOUND_BANK, "SOUND/v1", "SOUND/v1"),
UNKNOWN(AssetFamilyCatalog.UNKNOWN, "unknown", "Unknown"); UNKNOWN(AssetFamilyCatalog.UNKNOWN, "unknown", "Unknown");

View File

@ -0,0 +1,4 @@
package p.packer.models;
public record PackerGlyphBankRequirements(int tileSize) {
}

View File

@ -1,4 +0,0 @@
package p.packer.models;
public record PackerTileBankRequirements(int tileSize) {
}

View File

@ -17,21 +17,21 @@ import java.util.Optional;
import java.util.Set; import java.util.Set;
public class PackerAssetWalker { public class PackerAssetWalker {
private static final int TILE_BANK_EMITTED_SHEET_SIZE = 256; private static final int GLYPH_BANK_EMITTED_SHEET_SIZE = 256;
private static final int TILE_BANK_MAX_PALETTES = 64; private static final int GLYPH_BANK_MAX_PALETTES = 64;
private static final Set<OutputFormatCatalog> TILE_BANK_SUPPORTED_FORMATS = Set.of( private static final Set<OutputFormatCatalog> GLYPH_BANK_SUPPORTED_FORMATS = Set.of(
OutputFormatCatalog.TILES_INDEXED_V1 OutputFormatCatalog.GLYPH_INDEXED_V1
); );
private static final Set<OutputFormatCatalog> SOUND_BANK_SUPPORTED_FORMATS = Set.of( private static final Set<OutputFormatCatalog> SOUND_BANK_SUPPORTED_FORMATS = Set.of(
OutputFormatCatalog.SOUND_V1 OutputFormatCatalog.SOUND_V1
); );
private final PackerTileBankWalker tileBankWalker; private final PackerGlyphBankWalker glyphBankWalker;
private final PackerSoundBankWalker soundBankWalker; private final PackerSoundBankWalker soundBankWalker;
public PackerAssetWalker(final ObjectMapper mapper) { public PackerAssetWalker(final ObjectMapper mapper) {
this.tileBankWalker = new PackerTileBankWalker(mapper); this.glyphBankWalker = new PackerGlyphBankWalker(mapper);
this.soundBankWalker = new PackerSoundBankWalker(mapper); this.soundBankWalker = new PackerSoundBankWalker(mapper);
} }
@ -47,18 +47,18 @@ public class PackerAssetWalker {
final Optional<PackerAssetCacheEntry> priorAssetCache) { final Optional<PackerAssetCacheEntry> priorAssetCache) {
final List<PackerDiagnostic> diagnostics = new ArrayList<>(); final List<PackerDiagnostic> diagnostics = new ArrayList<>();
switch (declaration.assetFamily()) { switch (declaration.assetFamily()) {
case TILE_BANK -> { case GLYPH_BANK -> {
var metadata = declaration.outputMetadata(); var metadata = declaration.outputMetadata();
if (MapUtils.isEmpty(metadata)) { if (MapUtils.isEmpty(metadata)) {
diagnostics.add(new PackerDiagnostic( diagnostics.add(new PackerDiagnostic(
PackerDiagnosticSeverity.WARNING, PackerDiagnosticSeverity.WARNING,
PackerDiagnosticCategory.HYGIENE, PackerDiagnosticCategory.HYGIENE,
"Output metadata for tile bank cannot be empty, using default values", "Output metadata for glyph bank cannot be empty, using default values",
assetRoot, assetRoot,
false)); false));
metadata = Map.of("tile_size", "16x16"); metadata = Map.of("tile_size", "16x16");
} }
final var requirementBuildResult = buildTileBankRequirements(declaration, metadata); final var requirementBuildResult = buildGlyphBankRequirements(declaration, metadata);
if (requirementBuildResult.hasError()) { if (requirementBuildResult.hasError()) {
diagnostics.add(new PackerDiagnostic( diagnostics.add(new PackerDiagnostic(
PackerDiagnosticSeverity.ERROR, PackerDiagnosticSeverity.ERROR,
@ -68,11 +68,11 @@ public class PackerAssetWalker {
true)); true));
return new PackerWalkResult(List.of(), diagnostics); return new PackerWalkResult(List.of(), diagnostics);
} }
diagnostics.addAll(tileBankDeclarationDiagnostics(assetRoot, declaration, requirementBuildResult.requirements)); diagnostics.addAll(glyphBankDeclarationDiagnostics(assetRoot, declaration, requirementBuildResult.requirements));
final var walkResult = tileBankWalker.walk(assetRoot, requirementBuildResult.requirements, priorAssetCache); final var walkResult = glyphBankWalker.walk(assetRoot, requirementBuildResult.requirements, priorAssetCache);
diagnostics.addAll(walkResult.diagnostics()); diagnostics.addAll(walkResult.diagnostics());
diagnostics.addAll(tileBankSelectedArtifactDiagnostics(assetRoot, declaration, walkResult)); diagnostics.addAll(glyphBankSelectedArtifactDiagnostics(assetRoot, declaration, walkResult));
diagnostics.addAll(tileBankFragileIndexDiagnostics(declaration, walkResult)); diagnostics.addAll(glyphBankFragileIndexDiagnostics(declaration, walkResult));
return new PackerWalkResult(walkResult.probeResults(), diagnostics); return new PackerWalkResult(walkResult.probeResults(), diagnostics);
} }
case SOUND_BANK -> { case SOUND_BANK -> {
@ -81,7 +81,7 @@ public class PackerAssetWalker {
diagnostics.add(new PackerDiagnostic( diagnostics.add(new PackerDiagnostic(
PackerDiagnosticSeverity.WARNING, PackerDiagnosticSeverity.WARNING,
PackerDiagnosticCategory.HYGIENE, PackerDiagnosticCategory.HYGIENE,
"Output metadata for tile bank cannot be empty, using default values", "Output metadata for sound bank cannot be empty, using default values",
assetRoot, assetRoot,
false)); false));
metadata = Map.of("sample_rate", "44100", "channels", "1"); metadata = Map.of("sample_rate", "44100", "channels", "1");
@ -113,15 +113,15 @@ public class PackerAssetWalker {
return PackerWalkResult.EMPTY; return PackerWalkResult.EMPTY;
} }
private RequirementBuildResult<PackerTileBankRequirements> buildTileBankRequirements( private RequirementBuildResult<PackerGlyphBankRequirements> buildGlyphBankRequirements(
final PackerAssetDeclaration declaration, final PackerAssetDeclaration declaration,
final Map<String, String> metadata) { final Map<String, String> metadata) {
if (!TILE_BANK_SUPPORTED_FORMATS.contains(declaration.outputFormat())) { if (!GLYPH_BANK_SUPPORTED_FORMATS.contains(declaration.outputFormat())) {
return RequirementBuildResult.fail("Unsupported output format for tile bank: " + declaration.outputFormat()); return RequirementBuildResult.fail("Unsupported output format for glyph bank: " + declaration.outputFormat());
} }
final var tileSizeStr = metadata.get("tile_size"); final var tileSizeStr = metadata.get("tile_size");
if (StringUtils.isBlank(tileSizeStr)) { if (StringUtils.isBlank(tileSizeStr)) {
return RequirementBuildResult.fail("Tile size metadata for tile bank cannot be empty"); return RequirementBuildResult.fail("Tile size metadata for glyph bank cannot be empty");
} }
final int tileSize; final int tileSize;
switch (tileSizeStr) { switch (tileSizeStr) {
@ -135,16 +135,16 @@ public class PackerAssetWalker {
tileSize = 32; tileSize = 32;
} break; } break;
default: { default: {
return RequirementBuildResult.fail("Unsupported tile size for tile bank: " + tileSizeStr); return RequirementBuildResult.fail("Unsupported tile size for glyph bank: " + tileSizeStr);
} }
} }
return RequirementBuildResult.success(new PackerTileBankRequirements(tileSize)); return RequirementBuildResult.success(new PackerGlyphBankRequirements(tileSize));
} }
private List<PackerDiagnostic> tileBankDeclarationDiagnostics( private List<PackerDiagnostic> glyphBankDeclarationDiagnostics(
final Path assetRoot, final Path assetRoot,
final PackerAssetDeclaration declaration, final PackerAssetDeclaration declaration,
final PackerTileBankRequirements requirements) { final PackerGlyphBankRequirements requirements) {
final List<PackerDiagnostic> diagnostics = new ArrayList<>(); final List<PackerDiagnostic> diagnostics = new ArrayList<>();
final List<PackerAssetArtifactSelection> artifacts = declaration.artifacts(); final List<PackerAssetArtifactSelection> artifacts = declaration.artifacts();
final Set<Integer> seenIndices = new java.util.HashSet<>(); final Set<Integer> seenIndices = new java.util.HashSet<>();
@ -169,8 +169,8 @@ public class PackerAssetWalker {
} }
} }
final int tileCapacity = (TILE_BANK_EMITTED_SHEET_SIZE / requirements.tileSize()) final int tileCapacity = (GLYPH_BANK_EMITTED_SHEET_SIZE / requirements.tileSize())
* (TILE_BANK_EMITTED_SHEET_SIZE / requirements.tileSize()); * (GLYPH_BANK_EMITTED_SHEET_SIZE / requirements.tileSize());
if (artifacts.size() > tileCapacity) { if (artifacts.size() > tileCapacity) {
diagnostics.add(new PackerDiagnostic( diagnostics.add(new PackerDiagnostic(
PackerDiagnosticSeverity.ERROR, PackerDiagnosticSeverity.ERROR,
@ -191,18 +191,18 @@ public class PackerAssetWalker {
assetRoot, assetRoot,
true)); true));
} }
if (declaredPalettes.size() > TILE_BANK_MAX_PALETTES) { if (declaredPalettes.size() > GLYPH_BANK_MAX_PALETTES) {
diagnostics.add(new PackerDiagnostic( diagnostics.add(new PackerDiagnostic(
PackerDiagnosticSeverity.ERROR, PackerDiagnosticSeverity.ERROR,
PackerDiagnosticCategory.STRUCTURAL, PackerDiagnosticCategory.STRUCTURAL,
"Tile bank cannot declare more than " + TILE_BANK_MAX_PALETTES + " palettes.", "Glyph bank cannot declare more than " + GLYPH_BANK_MAX_PALETTES + " palettes.",
assetRoot, assetRoot,
true)); true));
} }
return diagnostics; return diagnostics;
} }
private List<PackerDiagnostic> tileBankSelectedArtifactDiagnostics( private List<PackerDiagnostic> glyphBankSelectedArtifactDiagnostics(
final Path assetRoot, final Path assetRoot,
final PackerAssetDeclaration declaration, final PackerAssetDeclaration declaration,
final PackerWalkResult walkResult) { final PackerWalkResult walkResult) {
@ -225,7 +225,7 @@ public class PackerAssetWalker {
return diagnostics; return diagnostics;
} }
private List<PackerDiagnostic> tileBankFragileIndexDiagnostics( private List<PackerDiagnostic> glyphBankFragileIndexDiagnostics(
final PackerAssetDeclaration declaration, final PackerAssetDeclaration declaration,
final PackerWalkResult walkResult) { final PackerWalkResult walkResult) {
final List<DeclaredPalette> declaredPalettes = declaredPalettes(declaration); final List<DeclaredPalette> declaredPalettes = declaredPalettes(declaration);

View File

@ -7,19 +7,17 @@ import p.packer.models.*;
import javax.imageio.ImageIO; import javax.imageio.ImageIO;
import java.io.ByteArrayInputStream; import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path; import java.nio.file.Path;
import java.util.*; import java.util.*;
public class PackerTileBankWalker extends PackerAbstractBankWalker<PackerTileBankRequirements> { public class PackerGlyphBankWalker extends PackerAbstractBankWalker<PackerGlyphBankRequirements> {
private static final int MAX_COLORS_PER_PALETTE = 15; private static final int MAX_COLORS_PER_PALETTE = 15;
private static final int COLOR_KEY_RGB = 0x00FF00FF; private static final int COLOR_KEY_RGB = 0x00FF00FF;
private static final Set<String> SUPPORTED_MIME_TYPES = Set.of( private static final Set<String> SUPPORTED_MIME_TYPES = Set.of(
"image/png" "image/png"
); );
public PackerTileBankWalker(ObjectMapper mapper) { public PackerGlyphBankWalker(ObjectMapper mapper) {
super(mapper); super(mapper);
} }
@ -42,7 +40,7 @@ public class PackerTileBankWalker extends PackerAbstractBankWalker<PackerTileBan
protected PackerProbeResult processFileProbe( protected PackerProbeResult processFileProbe(
final PackerFileProbe fileProbe, final PackerFileProbe fileProbe,
final Path assetRoot, final Path assetRoot,
final PackerTileBankRequirements requirements) { final PackerGlyphBankRequirements requirements) {
final List<PackerDiagnostic> diagnostics = new ArrayList<>(); final List<PackerDiagnostic> diagnostics = new ArrayList<>();
final var image = readImage(fileProbe, diagnostics); final var image = readImage(fileProbe, diagnostics);
@ -63,7 +61,7 @@ public class PackerTileBankWalker extends PackerAbstractBankWalker<PackerTileBan
diagnostics.add(new PackerDiagnostic( diagnostics.add(new PackerDiagnostic(
PackerDiagnosticSeverity.ERROR, PackerDiagnosticSeverity.ERROR,
PackerDiagnosticCategory.STRUCTURAL, PackerDiagnosticCategory.STRUCTURAL,
"Invalid tile dimensions for " + fileProbe.path().getFileName() "Invalid glyph dimensions for " + fileProbe.path().getFileName()
+ ": expected " + requirements.tileSize() + "x" + requirements.tileSize() + ": expected " + requirements.tileSize() + "x" + requirements.tileSize()
+ " but got " + width + "x" + height, + " but got " + width + "x" + height,
fileProbe.path(), fileProbe.path(),
@ -140,7 +138,6 @@ public class PackerTileBankWalker extends PackerAbstractBankWalker<PackerTileBan
return new PackerProbeResult(fileProbe, Map.of("tile", tile, "palette", palette), diagnostics); return new PackerProbeResult(fileProbe, Map.of("tile", tile, "palette", palette), diagnostics);
} }
@SuppressWarnings("unchecked")
private boolean hasReusableTileMetadata(final Map<String, Object> metadata) { private boolean hasReusableTileMetadata(final Map<String, Object> metadata) {
final Object tileValue = metadata.get("tile"); final Object tileValue = metadata.get("tile");
if (!(tileValue instanceof Map<?, ?> tile)) { if (!(tileValue instanceof Map<?, ?> tile)) {

View File

@ -37,7 +37,7 @@ import java.util.*;
import java.util.stream.Stream; import java.util.stream.Stream;
public final class FileSystemPackerWorkspaceService implements PackerWorkspaceService { public final class FileSystemPackerWorkspaceService implements PackerWorkspaceService {
private static final int TILE_BANK_COLOR_KEY_RGB565 = 0xF81F; private static final int GLYPH_BANK_COLOR_KEY_RGB565 = 0xF81F;
private final ObjectMapper mapper; private final ObjectMapper mapper;
private final PackerWorkspaceFoundation workspaceFoundation; private final PackerWorkspaceFoundation workspaceFoundation;
@ -816,7 +816,7 @@ public final class FileSystemPackerWorkspaceService implements PackerWorkspaceSe
if (declaration == null) { if (declaration == null) {
return List.of(); return List.of();
} }
if (declaration.assetFamily() == AssetFamilyCatalog.TILE_BANK) { if (declaration.assetFamily() == AssetFamilyCatalog.GLYPH_BANK) {
return List.of(); return List.of();
} }
return List.of(new PackerDiagnostic( return List.of(new PackerDiagnostic(
@ -909,10 +909,10 @@ public final class FileSystemPackerWorkspaceService implements PackerWorkspaceSe
private PackedAsset packRuntimeAsset(PackerRuntimeAsset runtimeAsset) { private PackedAsset packRuntimeAsset(PackerRuntimeAsset runtimeAsset) {
final PackerAssetDeclaration declaration = runtimeAsset.parsedDeclaration().declaration(); final PackerAssetDeclaration declaration = runtimeAsset.parsedDeclaration().declaration();
if (declaration == null || declaration.assetFamily() != AssetFamilyCatalog.TILE_BANK) { if (declaration == null || declaration.assetFamily() != AssetFamilyCatalog.GLYPH_BANK) {
throw new IllegalStateException("Unsupported pack output family for current implementation."); throw new IllegalStateException("Unsupported pack output family for current implementation.");
} }
return packTileBank(runtimeAsset, declaration); return packGlyphBank(runtimeAsset, declaration);
} }
private boolean isEffectivelyIncludedInPackSet(PackerRuntimeAsset runtimeAsset) { private boolean isEffectivelyIncludedInPackSet(PackerRuntimeAsset runtimeAsset) {
@ -923,7 +923,7 @@ public final class FileSystemPackerWorkspaceService implements PackerWorkspaceSe
return declaration == null || !declaration.artifacts().isEmpty(); return declaration == null || !declaration.artifacts().isEmpty();
} }
private PackedAsset packTileBank(PackerRuntimeAsset runtimeAsset, PackerAssetDeclaration declaration) { private PackedAsset packGlyphBank(PackerRuntimeAsset runtimeAsset, PackerAssetDeclaration declaration) {
final int tileSize = parseTileSize(declaration.outputMetadata().get("tile_size")); final int tileSize = parseTileSize(declaration.outputMetadata().get("tile_size"));
final int width = 256; final int width = 256;
final int height = 256; final int height = 256;
@ -955,7 +955,7 @@ public final class FileSystemPackerWorkspaceService implements PackerWorkspaceSe
}); });
final byte[] packedPixels = packNibbles(sheetPixels); final byte[] packedPixels = packNibbles(sheetPixels);
final byte[] paletteBytes = emitTileBankPalettes(declaration); final byte[] paletteBytes = emitGlyphBankPalettes(declaration);
final byte[] payload = new byte[packedPixels.length + paletteBytes.length]; final byte[] payload = new byte[packedPixels.length + paletteBytes.length];
System.arraycopy(packedPixels, 0, payload, 0, packedPixels.length); System.arraycopy(packedPixels, 0, payload, 0, packedPixels.length);
System.arraycopy(paletteBytes, 0, payload, packedPixels.length, paletteBytes.length); System.arraycopy(paletteBytes, 0, payload, packedPixels.length, paletteBytes.length);
@ -965,7 +965,7 @@ public final class FileSystemPackerWorkspaceService implements PackerWorkspaceSe
runtimeMetadata.put("width", width); runtimeMetadata.put("width", width);
runtimeMetadata.put("height", height); runtimeMetadata.put("height", height);
runtimeMetadata.put("palette_count", 64); runtimeMetadata.put("palette_count", 64);
runtimeMetadata.put("palette_authored", countAuthoredTileBankPalettes(declaration)); runtimeMetadata.put("palette_authored", countAuthoredGlyphBankPalettes(declaration));
runtimeMetadata.put("codec", Map.of()); runtimeMetadata.put("codec", Map.of());
declaration.outputMetadata().forEach((key, value) -> { declaration.outputMetadata().forEach((key, value) -> {
if (!"tile_size".equals(key)) { if (!"tile_size".equals(key)) {
@ -981,7 +981,7 @@ public final class FileSystemPackerWorkspaceService implements PackerWorkspaceSe
return new PackedAsset( return new PackedAsset(
registryEntry.assetId(), registryEntry.assetId(),
declaration.name(), declaration.name(),
"TILES", "GLYPH",
"NONE", "NONE",
payload, payload,
width * height + 2048, width * height + 2048,
@ -1009,7 +1009,7 @@ public final class FileSystemPackerWorkspaceService implements PackerWorkspaceSe
return packed; return packed;
} }
private byte[] emitTileBankPalettes(PackerAssetDeclaration declaration) { private byte[] emitGlyphBankPalettes(PackerAssetDeclaration declaration) {
final byte[] bytes = new byte[64 * 16 * 2]; final byte[] bytes = new byte[64 * 16 * 2];
final JsonNode palettesNode = declaration.outputPipelineMetadata().get("palettes"); final JsonNode palettesNode = declaration.outputPipelineMetadata().get("palettes");
if (!(palettesNode instanceof com.fasterxml.jackson.databind.node.ArrayNode palettesArray)) { if (!(palettesNode instanceof com.fasterxml.jackson.databind.node.ArrayNode palettesArray)) {
@ -1026,8 +1026,8 @@ public final class FileSystemPackerWorkspaceService implements PackerWorkspaceSe
continue; continue;
} }
final int paletteBaseOffset = (paletteIndex * 16) * 2; final int paletteBaseOffset = (paletteIndex * 16) * 2;
bytes[paletteBaseOffset] = (byte) (TILE_BANK_COLOR_KEY_RGB565 & 0xFF); bytes[paletteBaseOffset] = (byte) (GLYPH_BANK_COLOR_KEY_RGB565 & 0xFF);
bytes[paletteBaseOffset + 1] = (byte) ((TILE_BANK_COLOR_KEY_RGB565 >>> 8) & 0xFF); bytes[paletteBaseOffset + 1] = (byte) ((GLYPH_BANK_COLOR_KEY_RGB565 >>> 8) & 0xFF);
final JsonNode convertedNode = paletteNode.path("convertedRgb565"); final JsonNode convertedNode = paletteNode.path("convertedRgb565");
if (!convertedNode.isArray()) { if (!convertedNode.isArray()) {
continue; continue;
@ -1042,7 +1042,7 @@ public final class FileSystemPackerWorkspaceService implements PackerWorkspaceSe
return bytes; return bytes;
} }
private int countAuthoredTileBankPalettes(PackerAssetDeclaration declaration) { private int countAuthoredGlyphBankPalettes(PackerAssetDeclaration declaration) {
final JsonNode palettesNode = declaration.outputPipelineMetadata().get("palettes"); final JsonNode palettesNode = declaration.outputPipelineMetadata().get("palettes");
return palettesNode instanceof ArrayNode palettesArray ? palettesArray.size() : 0; return palettesNode instanceof ArrayNode palettesArray ? palettesArray.size() : 0;
} }

View File

@ -121,7 +121,7 @@ public final class PackerAssetDeclarationParser {
diagnostics.add(new PackerDiagnostic( diagnostics.add(new PackerDiagnostic(
PackerDiagnosticSeverity.ERROR, PackerDiagnosticSeverity.ERROR,
PackerDiagnosticCategory.STRUCTURAL, PackerDiagnosticCategory.STRUCTURAL,
"Field 'type' must be one of: tile_bank, palette_bank, sound_bank.", "Field 'type' must be one of: glyph_bank, palette_bank, sound_bank.",
manifestPath, manifestPath,
true)); true));
return null; return null;

View File

@ -29,7 +29,7 @@ final class PackerOutputContractCatalog {
codecs.addAll(outputFormat.availableCodecs()); codecs.addAll(outputFormat.availableCodecs());
} else { } else {
final String normalizedFormat = outputFormat.manifestValue().trim().toUpperCase(Locale.ROOT); final String normalizedFormat = outputFormat.manifestValue().trim().toUpperCase(Locale.ROOT);
if (normalizedFormat.startsWith("TILES/") if (normalizedFormat.startsWith("GLYPH/")
|| normalizedFormat.startsWith("PALETTE/") || normalizedFormat.startsWith("PALETTE/")
|| normalizedFormat.startsWith("SOUND/") || normalizedFormat.startsWith("SOUND/")
|| normalizedFormat.startsWith("AUDIO/")) { || normalizedFormat.startsWith("AUDIO/")) {
@ -54,7 +54,7 @@ final class PackerOutputContractCatalog {
private static List<PackerCodecConfigurationField> metadataFieldsFor(OutputFormatCatalog outputFormat) { private static List<PackerCodecConfigurationField> metadataFieldsFor(OutputFormatCatalog outputFormat) {
return switch (outputFormat) { return switch (outputFormat) {
case TILES_INDEXED_V1 -> List.of(new PackerCodecConfigurationField( case GLYPH_INDEXED_V1 -> List.of(new PackerCodecConfigurationField(
"tile_size", "tile_size",
"TileSize", "TileSize",
PackerCodecConfigurationFieldType.ENUM, PackerCodecConfigurationFieldType.ENUM,

View File

@ -6,7 +6,7 @@ import org.junit.jupiter.api.io.TempDir;
import p.packer.models.PackerAssetCacheEntry; import p.packer.models.PackerAssetCacheEntry;
import p.packer.models.PackerFileCacheEntry; import p.packer.models.PackerFileCacheEntry;
import p.packer.models.PackerTileIndexedV1; import p.packer.models.PackerTileIndexedV1;
import p.packer.models.PackerTileBankRequirements; import p.packer.models.PackerGlyphBankRequirements;
import javax.imageio.ImageIO; import javax.imageio.ImageIO;
import java.awt.image.BufferedImage; import java.awt.image.BufferedImage;
@ -18,7 +18,7 @@ import java.util.Optional;
import static org.junit.jupiter.api.Assertions.*; import static org.junit.jupiter.api.Assertions.*;
final class PackerTileBankWalkerTest { final class PackerGlyphBankWalkerTest {
private static final ObjectMapper MAPPER = new ObjectMapper(); private static final ObjectMapper MAPPER = new ObjectMapper();
@TempDir @TempDir
@ -30,7 +30,7 @@ final class PackerTileBankWalkerTest {
final Path filePath = assetRoot.resolve("tile.png"); final Path filePath = assetRoot.resolve("tile.png");
writeTile(filePath); writeTile(filePath);
final PackerTileBankWalker walker = new PackerTileBankWalker(MAPPER); final PackerGlyphBankWalker walker = new PackerGlyphBankWalker(MAPPER);
final PackerAssetCacheEntry priorCache = new PackerAssetCacheEntry( final PackerAssetCacheEntry priorCache = new PackerAssetCacheEntry(
1, 1,
"contract", "contract",
@ -45,7 +45,7 @@ final class PackerTileBankWalkerTest {
"palette", Map.of("originalArgb8888", List.of(0xFFFFFFFF))), "palette", Map.of("originalArgb8888", List.of(0xFFFFFFFF))),
List.of()))); List.of())));
final var result = walker.walk(assetRoot, new PackerTileBankRequirements(16), Optional.of(priorCache)); final var result = walker.walk(assetRoot, new PackerGlyphBankRequirements(16), Optional.of(priorCache));
final PackerTileIndexedV1 tile = (PackerTileIndexedV1) result.probeResults().getFirst().metadata().get("tile"); final PackerTileIndexedV1 tile = (PackerTileIndexedV1) result.probeResults().getFirst().metadata().get("tile");
assertNotNull(tile); assertNotNull(tile);

View File

@ -135,9 +135,9 @@ final class PackerRuntimeAssetMaterializerTest {
1, 1,
"uuid", "uuid",
"asset", "asset",
AssetFamilyCatalog.TILE_BANK, AssetFamilyCatalog.GLYPH_BANK,
artifacts, artifacts,
OutputFormatCatalog.TILES_INDEXED_V1, OutputFormatCatalog.GLYPH_INDEXED_V1,
OutputCodecCatalog.NONE, OutputCodecCatalog.NONE,
metadata, metadata,
pipelineMetadata, pipelineMetadata,

View File

@ -141,7 +141,7 @@ final class FileSystemPackerWorkspaceServiceTest {
assertEquals(PackerOperationStatus.SUCCESS, result.status()); assertEquals(PackerOperationStatus.SUCCESS, result.status());
assertEquals(1, result.packSummary().assets().size()); assertEquals(1, result.packSummary().assets().size());
assertEquals(1, result.packSummary().assets().getFirst().artifactCount()); assertEquals(1, result.packSummary().assets().getFirst().artifactCount());
assertEquals(OutputFormatCatalog.TILES_INDEXED_V1, result.packSummary().assets().getFirst().outputFormat()); assertEquals(OutputFormatCatalog.GLYPH_INDEXED_V1, result.packSummary().assets().getFirst().outputFormat());
assertEquals("16x16", result.packSummary().assets().getFirst().outputMetadata().get("tile_size")); assertEquals("16x16", result.packSummary().assets().getFirst().outputMetadata().get("tile_size"));
assertEquals(64L, ((Map<?, ?>) ((Map<?, ?>) result.packSummary().assets().getFirst().outputPipeline().get("samples")).get("1")).get("length")); assertEquals(64L, ((Map<?, ?>) ((Map<?, ?>) result.packSummary().assets().getFirst().outputPipeline().get("samples")).get("1")).get("length"));
assertEquals(0L, result.packSummary().assets().getFirst().lastModified()); assertEquals(0L, result.packSummary().assets().getFirst().lastModified());
@ -232,14 +232,14 @@ final class FileSystemPackerWorkspaceServiceTest {
} }
@Test @Test
void packValidationBlocksTileBanksWithoutDeclaredPalettes() throws Exception { void packValidationBlocksGlyphBanksWithoutDeclaredPalettes() throws Exception {
final Path projectRoot = copyFixture("workspaces/managed-basic", tempDir.resolve("pack-validation-no-palettes")); final Path projectRoot = copyFixture("workspaces/managed-basic", tempDir.resolve("pack-validation-no-palettes"));
final Path assetRoot = projectRoot.resolve("assets/ui/atlas"); final Path assetRoot = projectRoot.resolve("assets/ui/atlas");
final Path manifestPath = assetRoot.resolve("asset.json"); final Path manifestPath = assetRoot.resolve("asset.json");
writeTilePng(assetRoot.resolve("confirm.png"), 16); writeTilePng(assetRoot.resolve("confirm.png"), 16);
final ObjectNode manifest = (ObjectNode) MAPPER.readTree(manifestPath.toFile()); final ObjectNode manifest = (ObjectNode) MAPPER.readTree(manifestPath.toFile());
manifest.putObject("output").put("format", "TILES/indexed_v1").put("codec", "NONE"); manifest.putObject("output").put("format", "GLYPH/indexed_v1").put("codec", "NONE");
final var artifacts = manifest.putArray("artifacts"); final var artifacts = manifest.putArray("artifacts");
artifacts.addObject().put("file", "confirm.png").put("index", 0); artifacts.addObject().put("file", "confirm.png").put("index", 0);
MAPPER.writerWithDefaultPrettyPrinter().writeValue(manifestPath.toFile(), manifest); MAPPER.writerWithDefaultPrettyPrinter().writeValue(manifestPath.toFile(), manifest);
@ -278,7 +278,7 @@ final class FileSystemPackerWorkspaceServiceTest {
} }
@Test @Test
void packWorkspaceEmitsTileBankArtifactsFromFrozenSnapshot() throws Exception { void packWorkspaceEmitsGlyphBankArtifactsFromFrozenSnapshot() throws Exception {
final Path projectRoot = copyFixture("workspaces/managed-basic", tempDir.resolve("pack-workspace-success")); final Path projectRoot = copyFixture("workspaces/managed-basic", tempDir.resolve("pack-workspace-success"));
final Path assetRoot = projectRoot.resolve("assets/ui/atlas"); final Path assetRoot = projectRoot.resolve("assets/ui/atlas");
final Path manifestPath = assetRoot.resolve("asset.json"); final Path manifestPath = assetRoot.resolve("asset.json");
@ -330,7 +330,7 @@ final class FileSystemPackerWorkspaceServiceTest {
assertEquals(0xF81F, readLeUnsignedShort(assetsPa, paletteStart)); assertEquals(0xF81F, readLeUnsignedShort(assetsPa, paletteStart));
assertEquals(0xF800, readLeUnsignedShort(assetsPa, paletteStart + 2)); assertEquals(0xF800, readLeUnsignedShort(assetsPa, paletteStart + 2));
assertEquals(1, assetTable.get(0).path("asset_id").asInt()); assertEquals(1, assetTable.get(0).path("asset_id").asInt());
assertEquals("TILES", assetTable.get(0).path("bank_type").asText()); assertEquals("GLYPH", assetTable.get(0).path("bank_type").asText());
assertEquals("NONE", assetTable.get(0).path("codec").asText()); assertEquals("NONE", assetTable.get(0).path("codec").asText());
assertEquals(16, assetTable.get(0).path("metadata").path("tile_size").asInt()); 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("width").asInt());
@ -491,8 +491,8 @@ final class FileSystemPackerWorkspaceServiceTest {
project(projectRoot), project(projectRoot),
"ui/new-atlas", "ui/new-atlas",
"new_atlas", "new_atlas",
AssetFamilyCatalog.TILE_BANK, AssetFamilyCatalog.GLYPH_BANK,
OutputFormatCatalog.TILES_INDEXED_V1, OutputFormatCatalog.GLYPH_INDEXED_V1,
OutputCodecCatalog.NONE, OutputCodecCatalog.NONE,
true)); true));
@ -521,8 +521,8 @@ final class FileSystemPackerWorkspaceServiceTest {
project(projectRoot), project(projectRoot),
"ui/new-atlas", "ui/new-atlas",
"new_atlas", "new_atlas",
AssetFamilyCatalog.TILE_BANK, AssetFamilyCatalog.GLYPH_BANK,
OutputFormatCatalog.TILES_INDEXED_V1, OutputFormatCatalog.GLYPH_INDEXED_V1,
OutputCodecCatalog.NONE, OutputCodecCatalog.NONE,
true)); true));
@ -539,7 +539,7 @@ final class FileSystemPackerWorkspaceServiceTest {
assertEquals("new_atlas", detailsResult.details().summary().identity().assetName()); assertEquals("new_atlas", detailsResult.details().summary().identity().assetName());
assertNotNull(detailsResult.details().summary().identity().assetUuid()); assertNotNull(detailsResult.details().summary().identity().assetUuid());
assertTrue(detailsResult.diagnostics().stream().noneMatch(diagnostic -> diagnostic.blocking())); assertTrue(detailsResult.diagnostics().stream().noneMatch(diagnostic -> diagnostic.blocking()));
assertTrue(detailsResult.diagnostics().stream().anyMatch(diagnostic -> diagnostic.message().contains("Output metadata for tile bank cannot be empty"))); assertTrue(detailsResult.diagnostics().stream().anyMatch(diagnostic -> diagnostic.message().contains("Output metadata for glyph bank cannot be empty")));
} }
@Test @Test
@ -555,8 +555,8 @@ final class FileSystemPackerWorkspaceServiceTest {
project(projectRoot), project(projectRoot),
"ui/new-atlas", "ui/new-atlas",
"new_atlas", "new_atlas",
AssetFamilyCatalog.TILE_BANK, AssetFamilyCatalog.GLYPH_BANK,
OutputFormatCatalog.TILES_INDEXED_V1, OutputFormatCatalog.GLYPH_INDEXED_V1,
OutputCodecCatalog.NONE, OutputCodecCatalog.NONE,
true)); true));
@ -987,7 +987,7 @@ final class FileSystemPackerWorkspaceServiceTest {
"name": "ui_atlas", "name": "ui_atlas",
"type": "IMAGE/bank", "type": "IMAGE/bank",
"output": { "output": {
"format": "TILES/indexed_v1", "format": "GLYPH/indexed_v1",
"codec": "none" "codec": "none"
}, },
"preload": { "preload": {
@ -1002,7 +1002,7 @@ final class FileSystemPackerWorkspaceServiceTest {
"name": "ui_clone", "name": "ui_clone",
"type": "IMAGE/bank", "type": "IMAGE/bank",
"output": { "output": {
"format": "TILES/indexed_v1", "format": "GLYPH/indexed_v1",
"codec": "none" "codec": "none"
}, },
"preload": { "preload": {
@ -1053,8 +1053,8 @@ final class FileSystemPackerWorkspaceServiceTest {
project(projectRoot), project(projectRoot),
"ui/delete-me", "ui/delete-me",
"delete_me", "delete_me",
AssetFamilyCatalog.TILE_BANK, AssetFamilyCatalog.GLYPH_BANK,
OutputFormatCatalog.TILES_INDEXED_V1, OutputFormatCatalog.GLYPH_INDEXED_V1,
OutputCodecCatalog.NONE, OutputCodecCatalog.NONE,
false)); false));
final Path assetRoot = projectRoot.resolve("assets/ui/delete-me"); final Path assetRoot = projectRoot.resolve("assets/ui/delete-me");
@ -1081,8 +1081,8 @@ final class FileSystemPackerWorkspaceServiceTest {
project(projectRoot), project(projectRoot),
"ui/source-atlas", "ui/source-atlas",
"source_atlas", "source_atlas",
AssetFamilyCatalog.TILE_BANK, AssetFamilyCatalog.GLYPH_BANK,
OutputFormatCatalog.TILES_INDEXED_V1, OutputFormatCatalog.GLYPH_INDEXED_V1,
OutputCodecCatalog.NONE, OutputCodecCatalog.NONE,
true)); true));
Files.writeString(projectRoot.resolve("assets/ui/source-atlas/atlas.png"), "fixture"); Files.writeString(projectRoot.resolve("assets/ui/source-atlas/atlas.png"), "fixture");
@ -1148,16 +1148,16 @@ final class FileSystemPackerWorkspaceServiceTest {
project(projectRoot), project(projectRoot),
"ui/source", "ui/source",
"source", "source",
AssetFamilyCatalog.TILE_BANK, AssetFamilyCatalog.GLYPH_BANK,
OutputFormatCatalog.TILES_INDEXED_V1, OutputFormatCatalog.GLYPH_INDEXED_V1,
OutputCodecCatalog.NONE, OutputCodecCatalog.NONE,
false)); false));
final CreateAssetResult target = service.createAsset(new CreateAssetRequest( final CreateAssetResult target = service.createAsset(new CreateAssetRequest(
project(projectRoot), project(projectRoot),
"ui/target", "ui/target",
"target", "target",
AssetFamilyCatalog.TILE_BANK, AssetFamilyCatalog.GLYPH_BANK,
OutputFormatCatalog.TILES_INDEXED_V1, OutputFormatCatalog.GLYPH_INDEXED_V1,
OutputCodecCatalog.NONE, OutputCodecCatalog.NONE,
false)); false));
@ -1223,7 +1223,7 @@ final class FileSystemPackerWorkspaceServiceTest {
project(projectRoot), project(projectRoot),
"audio/bad", "audio/bad",
"bad_asset", "bad_asset",
AssetFamilyCatalog.TILE_BANK, AssetFamilyCatalog.GLYPH_BANK,
OutputFormatCatalog.SOUND_V1, OutputFormatCatalog.SOUND_V1,
OutputCodecCatalog.NONE, OutputCodecCatalog.NONE,
false)); false));
@ -1243,16 +1243,16 @@ final class FileSystemPackerWorkspaceServiceTest {
project(projectRoot), project(projectRoot),
"ui/atlas-a", "ui/atlas-a",
"atlas_a", "atlas_a",
AssetFamilyCatalog.TILE_BANK, AssetFamilyCatalog.GLYPH_BANK,
OutputFormatCatalog.TILES_INDEXED_V1, OutputFormatCatalog.GLYPH_INDEXED_V1,
OutputCodecCatalog.NONE, OutputCodecCatalog.NONE,
true))); true)));
final Future<CreateAssetResult> second = executor.submit(() -> service.createAsset(new CreateAssetRequest( final Future<CreateAssetResult> second = executor.submit(() -> service.createAsset(new CreateAssetRequest(
project(projectRoot), project(projectRoot),
"ui/atlas-b", "ui/atlas-b",
"atlas_b", "atlas_b",
AssetFamilyCatalog.TILE_BANK, AssetFamilyCatalog.GLYPH_BANK,
OutputFormatCatalog.TILES_INDEXED_V1, OutputFormatCatalog.GLYPH_INDEXED_V1,
OutputCodecCatalog.NONE, OutputCodecCatalog.NONE,
false))); false)));

View File

@ -29,8 +29,8 @@ final class PackerAssetDeclarationParserTest {
assertEquals(1, result.declaration().schemaVersion()); assertEquals(1, result.declaration().schemaVersion());
assertEquals("fixture-uuid-1", result.declaration().assetUuid()); assertEquals("fixture-uuid-1", result.declaration().assetUuid());
assertEquals("ui_atlas", result.declaration().name()); assertEquals("ui_atlas", result.declaration().name());
assertEquals(AssetFamilyCatalog.TILE_BANK, result.declaration().assetFamily()); assertEquals(AssetFamilyCatalog.GLYPH_BANK, result.declaration().assetFamily());
assertEquals("TILES/indexed_v1", result.declaration().outputFormat().displayName()); assertEquals("GLYPH/indexed_v1", result.declaration().outputFormat().displayName());
assertEquals(OutputCodecCatalog.NONE, result.declaration().outputCodec()); assertEquals(OutputCodecCatalog.NONE, result.declaration().outputCodec());
assertEquals(Map.of(), result.declaration().outputPipelineMetadata()); assertEquals(Map.of(), result.declaration().outputPipelineMetadata());
assertTrue(result.declaration().preloadEnabled()); assertTrue(result.declaration().preloadEnabled());
@ -75,9 +75,9 @@ final class PackerAssetDeclarationParserTest {
"schema_version": 1, "schema_version": 1,
"asset_uuid": "uuid-pipeline", "asset_uuid": "uuid-pipeline",
"name": "pipeline_asset", "name": "pipeline_asset",
"type": "tile_bank", "type": "glyph_bank",
"output": { "output": {
"format": "TILES/indexed_v1", "format": "GLYPH/indexed_v1",
"codec": "NONE", "codec": "NONE",
"pipeline": [] "pipeline": []
}, },
@ -99,9 +99,9 @@ final class PackerAssetDeclarationParserTest {
"schema_version": 1, "schema_version": 1,
"asset_uuid": "uuid-palette-contract", "asset_uuid": "uuid-palette-contract",
"name": "palette_asset", "name": "palette_asset",
"type": "tile_bank", "type": "glyph_bank",
"output": { "output": {
"format": "TILES/indexed_v1", "format": "GLYPH/indexed_v1",
"codec": "NONE", "codec": "NONE",
"pipeline": { "pipeline": {
"palettes": [ "palettes": [
@ -135,9 +135,9 @@ final class PackerAssetDeclarationParserTest {
"schema_version": 1, "schema_version": 1,
"asset_uuid": "uuid-palette-duplicate", "asset_uuid": "uuid-palette-duplicate",
"name": "palette_asset", "name": "palette_asset",
"type": "tile_bank", "type": "glyph_bank",
"output": { "output": {
"format": "TILES/indexed_v1", "format": "GLYPH/indexed_v1",
"codec": "NONE", "codec": "NONE",
"pipeline": { "pipeline": {
"palettes": [ "palettes": [
@ -203,9 +203,9 @@ final class PackerAssetDeclarationParserTest {
"schema_version": 1, "schema_version": 1,
"asset_uuid": "uuid-outside", "asset_uuid": "uuid-outside",
"name": "bad_asset", "name": "bad_asset",
"type": "tile_bank", "type": "glyph_bank",
"inputs": { "sprites": ["../outside.png"] }, "inputs": { "sprites": ["../outside.png"] },
"output": { "format": "TILES/indexed_v1", "codec": "NONE" }, "output": { "format": "GLYPH/indexed_v1", "codec": "NONE" },
"preload": { "enabled": true } "preload": { "enabled": true }
} }
"""); """);
@ -225,7 +225,7 @@ final class PackerAssetDeclarationParserTest {
"asset_uuid": "uuid-video", "asset_uuid": "uuid-video",
"name": "bad_asset", "name": "bad_asset",
"type": "video_bank", "type": "video_bank",
"output": { "format": "TILES/indexed_v1", "codec": "NONE" }, "output": { "format": "GLYPH/indexed_v1", "codec": "NONE" },
"preload": { "enabled": true } "preload": { "enabled": true }
} }
"""); """);

View File

@ -44,14 +44,14 @@ final class PackerAssetDetailsServiceTest {
assertEquals(PackerBuildParticipation.INCLUDED, result.details().summary().buildParticipation()); assertEquals(PackerBuildParticipation.INCLUDED, result.details().summary().buildParticipation());
assertEquals("fixture-uuid-1", result.details().summary().identity().assetUuid()); assertEquals("fixture-uuid-1", result.details().summary().identity().assetUuid());
assertEquals("ui_atlas", result.details().summary().identity().assetName()); assertEquals("ui_atlas", result.details().summary().identity().assetName());
assertEquals("TILES/indexed_v1", result.details().outputFormat().displayName()); assertEquals("GLYPH/indexed_v1", result.details().outputFormat().displayName());
assertEquals(List.of(OutputCodecCatalog.NONE), result.details().availableOutputCodecs()); assertEquals(List.of(OutputCodecCatalog.NONE), result.details().availableOutputCodecs());
assertEquals(List.of(), result.details().codecConfigurationFieldsByCodec().get(OutputCodecCatalog.NONE)); assertEquals(List.of(), result.details().codecConfigurationFieldsByCodec().get(OutputCodecCatalog.NONE));
assertNotNull(result.details().bankComposition()); assertNotNull(result.details().bankComposition());
assertTrue(result.details().bankComposition().selectedFiles().isEmpty()); assertTrue(result.details().bankComposition().selectedFiles().isEmpty());
assertTrue(result.details().pipelinePalettes().isEmpty()); assertTrue(result.details().pipelinePalettes().isEmpty());
assertTrue(result.diagnostics().stream().noneMatch(diagnostic -> diagnostic.blocking())); assertTrue(result.diagnostics().stream().noneMatch(diagnostic -> diagnostic.blocking()));
assertTrue(result.diagnostics().stream().anyMatch(diagnostic -> diagnostic.message().contains("Output metadata for tile bank cannot be empty"))); assertTrue(result.diagnostics().stream().anyMatch(diagnostic -> diagnostic.message().contains("Output metadata for glyph bank cannot be empty")));
} }
@Test @Test

View File

@ -1,6 +1,6 @@
{ {
"schema_version": 1, "schema_version": 1,
"type": "tile_bank", "type": "glyph_bank",
"inputs": "wrong", "inputs": "wrong",
"output": { "output": {
"codec": "" "codec": ""

View File

@ -2,9 +2,9 @@
"schema_version": 9, "schema_version": 9,
"asset_uuid": "future-uuid-1", "asset_uuid": "future-uuid-1",
"name": "future_asset", "name": "future_asset",
"type": "tile_bank", "type": "glyph_bank",
"output": { "output": {
"format": "TILES/indexed_v1", "format": "GLYPH/indexed_v1",
"codec": "NONE" "codec": "NONE"
}, },
"preload": { "preload": {

View File

@ -2,9 +2,9 @@
"schema_version": 1, "schema_version": 1,
"asset_uuid": "fixture-uuid-1", "asset_uuid": "fixture-uuid-1",
"name": "ui_atlas", "name": "ui_atlas",
"type": "tile_bank", "type": "glyph_bank",
"output": { "output": {
"format": "TILES/indexed_v1", "format": "GLYPH/indexed_v1",
"codec": "NONE" "codec": "NONE"
}, },
"preload": { "preload": {

View File

@ -1,6 +1,6 @@
{ {
"schema_version": 1, "schema_version": 1,
"type": "tile_bank", "type": "glyph_bank",
"inputs": "wrong", "inputs": "wrong",
"output": { "output": {
"codec": "" "codec": ""

View File

@ -2,9 +2,9 @@
"schema_version": 1, "schema_version": 1,
"asset_uuid": "uuid-1", "asset_uuid": "uuid-1",
"name": "ui_atlas", "name": "ui_atlas",
"type": "tile_bank", "type": "glyph_bank",
"output": { "output": {
"format": "TILES/indexed_v1", "format": "GLYPH/indexed_v1",
"codec": "NONE" "codec": "NONE"
}, },
"preload": { "preload": {

View File

@ -190,7 +190,7 @@ public enum I18n {
ASSETS_LABEL_BUILD_PARTICIPATION("assets.label.buildParticipation"), ASSETS_LABEL_BUILD_PARTICIPATION("assets.label.buildParticipation"),
ASSETS_LABEL_ASSET_ID("assets.label.assetId"), ASSETS_LABEL_ASSET_ID("assets.label.assetId"),
ASSETS_LABEL_TYPE("assets.label.type"), ASSETS_LABEL_TYPE("assets.label.type"),
ASSETS_TYPE_TILE_BANK("assets.type.tileBank"), ASSETS_TYPE_GLYPH_BANK("assets.type.glyphBank"),
ASSETS_TYPE_PALETTE_BANK("assets.type.paletteBank"), ASSETS_TYPE_PALETTE_BANK("assets.type.paletteBank"),
ASSETS_TYPE_SOUND_BANK("assets.type.soundBank"), ASSETS_TYPE_SOUND_BANK("assets.type.soundBank"),
ASSETS_TYPE_UNKNOWN("assets.type.unknown"), ASSETS_TYPE_UNKNOWN("assets.type.unknown"),

View File

@ -113,7 +113,7 @@ public final class AssetDetailsUiSupport {
public static String typeLabel(AssetFamilyCatalog assetFamily) { public static String typeLabel(AssetFamilyCatalog assetFamily) {
return switch (assetFamily) { return switch (assetFamily) {
case TILE_BANK -> Container.i18n().text(I18n.ASSETS_TYPE_TILE_BANK); case GLYPH_BANK -> Container.i18n().text(I18n.ASSETS_TYPE_GLYPH_BANK);
case SOUND_BANK -> Container.i18n().text(I18n.ASSETS_TYPE_SOUND_BANK); case SOUND_BANK -> Container.i18n().text(I18n.ASSETS_TYPE_SOUND_BANK);
case UNKNOWN -> Container.i18n().text(I18n.ASSETS_TYPE_UNKNOWN); case UNKNOWN -> Container.i18n().text(I18n.ASSETS_TYPE_UNKNOWN);
}; };
@ -121,7 +121,7 @@ public final class AssetDetailsUiSupport {
public static String typeChipTone(AssetFamilyCatalog assetFamily) { public static String typeChipTone(AssetFamilyCatalog assetFamily) {
return switch (assetFamily) { return switch (assetFamily) {
case TILE_BANK -> "assets-details-chip-image"; case GLYPH_BANK -> "assets-details-chip-image";
case SOUND_BANK -> "assets-details-chip-audio"; case SOUND_BANK -> "assets-details-chip-audio";
case UNKNOWN -> "assets-details-chip-generic"; case UNKNOWN -> "assets-details-chip-generic";
}; };

View File

@ -20,7 +20,7 @@ public final class AssetBankCapacityService {
final Map<String, String> safeMetadata = Map.copyOf(Objects.requireNonNull(outputMetadata, "outputMetadata")); final Map<String, String> safeMetadata = Map.copyOf(Objects.requireNonNull(outputMetadata, "outputMetadata"));
final Map<String, Object> safePipeline = Map.copyOf(Objects.requireNonNull(outputPipeline, "outputPipeline")); final Map<String, Object> safePipeline = Map.copyOf(Objects.requireNonNull(outputPipeline, "outputPipeline"));
return switch (safeFamily) { return switch (safeFamily) {
case TILE_BANK -> evaluateTileBank(artifactCount, safeMetadata); case GLYPH_BANK -> evaluateGlyphBank(artifactCount, safeMetadata);
case SOUND_BANK -> evaluateSoundBank(resolveSoundBankUsedBytes(safePipeline, usedBytes)); case SOUND_BANK -> evaluateSoundBank(resolveSoundBankUsedBytes(safePipeline, usedBytes));
case UNKNOWN -> new AssetDetailsBankCompositionCapacityState( case UNKNOWN -> new AssetDetailsBankCompositionCapacityState(
0.0d, 0.0d,
@ -31,7 +31,7 @@ public final class AssetBankCapacityService {
}; };
} }
public int maxArtifactsForTileBank(Map<String, String> outputMetadata) { public int maxArtifactsForGlyphBank(Map<String, String> outputMetadata) {
final String tileSizeValue = Objects.requireNonNull(outputMetadata, "outputMetadata") final String tileSizeValue = Objects.requireNonNull(outputMetadata, "outputMetadata")
.getOrDefault("tile_size", "16x16"); .getOrDefault("tile_size", "16x16");
return switch (tileSizeValue) { return switch (tileSizeValue) {
@ -41,10 +41,10 @@ public final class AssetBankCapacityService {
}; };
} }
private AssetDetailsBankCompositionCapacityState evaluateTileBank( private AssetDetailsBankCompositionCapacityState evaluateGlyphBank(
int artifactCount, int artifactCount,
Map<String, String> outputMetadata) { Map<String, String> outputMetadata) {
final int maxSlots = maxArtifactsForTileBank(outputMetadata); final int maxSlots = maxArtifactsForGlyphBank(outputMetadata);
final int safeArtifactCount = Math.max(0, artifactCount); final int safeArtifactCount = Math.max(0, artifactCount);
final double progress = maxSlots <= 0 ? 0.0d : (double) safeArtifactCount / (double) maxSlots; final double progress = maxSlots <= 0 ? 0.0d : (double) safeArtifactCount / (double) maxSlots;
final boolean blocked = safeArtifactCount >= maxSlots; final boolean blocked = safeArtifactCount >= maxSlots;
@ -53,7 +53,7 @@ public final class AssetBankCapacityService {
severityFor(progress), severityFor(progress),
blocked, blocked,
safeArtifactCount + " / " + maxSlots, safeArtifactCount + " / " + maxSlots,
blocked ? "Tile bank slot capacity reached." : ""); blocked ? "Glyph bank slot capacity reached." : "");
} }
private AssetDetailsBankCompositionCapacityState evaluateSoundBank(long usedBytes) { private AssetDetailsBankCompositionCapacityState evaluateSoundBank(long usedBytes) {

View File

@ -10,7 +10,7 @@ import java.util.Objects;
public final class AssetDetailsBankCompositionCoordinator { public final class AssetDetailsBankCompositionCoordinator {
private final List<AssetDetailsBankCompositionFamilySupport> familySupports = List.of( private final List<AssetDetailsBankCompositionFamilySupport> familySupports = List.of(
new AssetDetailsTileBankCompositionFamilySupport(), new AssetDetailsGlyphBankCompositionFamilySupport(),
new AssetDetailsSoundBankCompositionFamilySupport(), new AssetDetailsSoundBankCompositionFamilySupport(),
new AssetDetailsFallbackBankCompositionFamilySupport()); new AssetDetailsFallbackBankCompositionFamilySupport());

View File

@ -7,21 +7,21 @@ import p.studio.workspaces.assets.messages.AssetWorkspaceBankCompositionFile;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
final class AssetDetailsTileBankCompositionFamilySupport extends AssetDetailsAbstractBankCompositionFamilySupport { final class AssetDetailsGlyphBankCompositionFamilySupport extends AssetDetailsAbstractBankCompositionFamilySupport {
private final AssetBankCapacityService capacityService = new AssetBankCapacityService(); private final AssetBankCapacityService capacityService = new AssetBankCapacityService();
private int maxSlots = capacityService.maxArtifactsForTileBank(Map.of()); private int maxSlots = capacityService.maxArtifactsForGlyphBank(Map.of());
private Map<String, String> outputMetadata = Map.of(); private Map<String, String> outputMetadata = Map.of();
@Override @Override
public boolean supports(AssetFamilyCatalog assetFamily) { public boolean supports(AssetFamilyCatalog assetFamily) {
return assetFamily == AssetFamilyCatalog.TILE_BANK; return assetFamily == AssetFamilyCatalog.GLYPH_BANK;
} }
@Override @Override
public AssetDetailsBankCompositionDraft createDraft(AssetWorkspaceAssetDetails details) { public AssetDetailsBankCompositionDraft createDraft(AssetWorkspaceAssetDetails details) {
outputMetadata = metadataMap(details); outputMetadata = metadataMap(details);
maxSlots = capacityService.maxArtifactsForTileBank(outputMetadata); maxSlots = capacityService.maxArtifactsForGlyphBank(outputMetadata);
return super.createDraft(details); return super.createDraft(details);
} }
@ -36,7 +36,7 @@ final class AssetDetailsTileBankCompositionFamilySupport extends AssetDetailsAbs
@Override @Override
public AssetDetailsBankCompositionCapacityState evaluate(AssetDetailsBankCompositionDraft draft) { public AssetDetailsBankCompositionCapacityState evaluate(AssetDetailsBankCompositionDraft draft) {
return capacityService.evaluate( return capacityService.evaluate(
AssetFamilyCatalog.TILE_BANK, AssetFamilyCatalog.GLYPH_BANK,
draft.selectedFiles().size(), draft.selectedFiles().size(),
outputMetadata, outputMetadata,
Map.of(), Map.of(),

View File

@ -18,7 +18,7 @@ public final class AssetDetailsPaletteOverhaulingCoordinator {
private StudioFormSession<AssetDetailsPaletteOverhaulingDraft> formSession; private StudioFormSession<AssetDetailsPaletteOverhaulingDraft> formSession;
public void replaceDetails(AssetWorkspaceAssetDetails details) { public void replaceDetails(AssetWorkspaceAssetDetails details) {
if (details == null || details.summary().assetFamily() != AssetFamilyCatalog.TILE_BANK) { if (details == null || details.summary().assetFamily() != AssetFamilyCatalog.GLYPH_BANK) {
formSession = null; formSession = null;
return; return;
} }

View File

@ -112,7 +112,7 @@ public final class AssetListItemControl extends VBox {
private String assetRowToneClass(AssetFamilyCatalog assetFamily) { private String assetRowToneClass(AssetFamilyCatalog assetFamily) {
return switch (assetFamily) { return switch (assetFamily) {
case TILE_BANK -> "assets-workspace-asset-row-tone-image"; case GLYPH_BANK -> "assets-workspace-asset-row-tone-image";
case SOUND_BANK -> "assets-workspace-asset-row-tone-audio"; case SOUND_BANK -> "assets-workspace-asset-row-tone-audio";
default -> "assets-workspace-asset-row-tone-generic"; default -> "assets-workspace-asset-row-tone-generic";
}; };
@ -120,7 +120,7 @@ public final class AssetListItemControl extends VBox {
private String assetNameToneClass(AssetFamilyCatalog assetFamily) { private String assetNameToneClass(AssetFamilyCatalog assetFamily) {
return switch (assetFamily) { return switch (assetFamily) {
case TILE_BANK -> "assets-workspace-asset-name-tone-image"; case GLYPH_BANK -> "assets-workspace-asset-name-tone-image";
case SOUND_BANK -> "assets-workspace-asset-name-tone-audio"; case SOUND_BANK -> "assets-workspace-asset-name-tone-audio";
default -> "assets-workspace-asset-name-tone-generic"; default -> "assets-workspace-asset-name-tone-generic";
}; };

View File

@ -181,7 +181,7 @@ assets.label.registration=Registration
assets.label.buildParticipation=Build Participation assets.label.buildParticipation=Build Participation
assets.label.assetId=Asset ID assets.label.assetId=Asset ID
assets.label.type=Type assets.label.type=Type
assets.type.tileBank=Tile Bank assets.type.glyphBank=Glyph Bank
assets.type.paletteBank=Palette Bank assets.type.paletteBank=Palette Bank
assets.type.soundBank=Sound Bank assets.type.soundBank=Sound Bank
assets.type.unknown=Unknown assets.type.unknown=Unknown

View File

@ -101,9 +101,9 @@ final class AssetDetailsBankCompositionCoordinatorTest {
private AssetWorkspaceAssetDetails tileDetails(String tileSize, int fileCount) { private AssetWorkspaceAssetDetails tileDetails(String tileSize, int fileCount) {
return new AssetWorkspaceAssetDetails( return new AssetWorkspaceAssetDetails(
summary(AssetFamilyCatalog.TILE_BANK), summary(AssetFamilyCatalog.GLYPH_BANK),
List.of(), List.of(),
OutputFormatCatalog.TILES_INDEXED_V1, OutputFormatCatalog.GLYPH_INDEXED_V1,
OutputCodecCatalog.NONE, OutputCodecCatalog.NONE,
List.of(OutputCodecCatalog.NONE), List.of(OutputCodecCatalog.NONE),
Map.of(OutputCodecCatalog.NONE, List.of()), Map.of(OutputCodecCatalog.NONE, List.of()),

View File

@ -80,12 +80,12 @@ final class AssetDetailsPaletteOverhaulingCoordinatorTest {
AssetWorkspaceAssetState.REGISTERED, AssetWorkspaceAssetState.REGISTERED,
AssetWorkspaceBuildParticipation.INCLUDED, AssetWorkspaceBuildParticipation.INCLUDED,
1, 1,
AssetFamilyCatalog.TILE_BANK, AssetFamilyCatalog.GLYPH_BANK,
Path.of("/tmp/bank"), Path.of("/tmp/bank"),
false, false,
false), false),
List.of(), List.of(),
OutputFormatCatalog.TILES_INDEXED_V1, OutputFormatCatalog.GLYPH_INDEXED_V1,
OutputCodecCatalog.NONE, OutputCodecCatalog.NONE,
List.of(OutputCodecCatalog.NONE), List.of(OutputCodecCatalog.NONE),
Map.of(OutputCodecCatalog.NONE, List.of()), Map.of(OutputCodecCatalog.NONE, List.of()),

View File

@ -7,7 +7,7 @@
"relative_path" : "confirm.png", "relative_path" : "confirm.png",
"mime_type" : "image/png", "mime_type" : "image/png",
"size" : 137, "size" : 137,
"last_modified" : 1774359768919, "last_modified" : 1775797786944,
"fingerprint" : "aa7d241deabcebe29a6096e14eaf16fdc06cf06380c11a507620b00fc7bff094", "fingerprint" : "aa7d241deabcebe29a6096e14eaf16fdc06cf06380c11a507620b00fc7bff094",
"metadata" : { }, "metadata" : { },
"diagnostics" : [ { "diagnostics" : [ {
@ -1263,7 +1263,7 @@
"relative_path" : "right-palette.png", "relative_path" : "right-palette.png",
"mime_type" : "image/png", "mime_type" : "image/png",
"size" : 327, "size" : 327,
"last_modified" : 1774359773932, "last_modified" : 1775797786950,
"fingerprint" : "0526996900bdeef23c72fe987fb45800f11895946dcd5f0f7f8390c879069a37", "fingerprint" : "0526996900bdeef23c72fe987fb45800f11895946dcd5f0f7f8390c879069a37",
"metadata" : { "metadata" : {
"palette" : { "palette" : {
@ -1281,7 +1281,7 @@
"relative_path" : "wrong-palette.png", "relative_path" : "wrong-palette.png",
"mime_type" : "image/png", "mime_type" : "image/png",
"size" : 248, "size" : 248,
"last_modified" : 1774359771814, "last_modified" : 1775797786946,
"fingerprint" : "15850f68547775866b01a0fe0b0012bb0243dec303ce1f9c3e02220e05b593e6", "fingerprint" : "15850f68547775866b01a0fe0b0012bb0243dec303ce1f9c3e02220e05b593e6",
"metadata" : { }, "metadata" : { },
"diagnostics" : [ { "diagnostics" : [ {
@ -1311,7 +1311,7 @@
"relative_path" : "confirm.png", "relative_path" : "confirm.png",
"mime_type" : "image/png", "mime_type" : "image/png",
"size" : 137, "size" : 137,
"last_modified" : 1774359768918, "last_modified" : 1775797786770,
"fingerprint" : "aa7d241deabcebe29a6096e14eaf16fdc06cf06380c11a507620b00fc7bff094", "fingerprint" : "aa7d241deabcebe29a6096e14eaf16fdc06cf06380c11a507620b00fc7bff094",
"metadata" : { "metadata" : {
"palette" : { "palette" : {
@ -1341,7 +1341,7 @@
"relative_path" : "flag00.png", "relative_path" : "flag00.png",
"mime_type" : "image/png", "mime_type" : "image/png",
"size" : 507, "size" : 507,
"last_modified" : 1774359777378, "last_modified" : 1775797786709,
"fingerprint" : "6ca635a7906067b6a2a8460a8562718c445783e6df18b9f2c80c83c5ac569db6", "fingerprint" : "6ca635a7906067b6a2a8460a8562718c445783e6df18b9f2c80c83c5ac569db6",
"metadata" : { "metadata" : {
"palette" : { "palette" : {
@ -1365,7 +1365,7 @@
"relative_path" : "flag01.png", "relative_path" : "flag01.png",
"mime_type" : "image/png", "mime_type" : "image/png",
"size" : 766, "size" : 766,
"last_modified" : 1774359777379, "last_modified" : 1775797786708,
"fingerprint" : "79257d8437747a68e9e8eb8f43fced7aa55940dc8eca98f95767994abbacdd81", "fingerprint" : "79257d8437747a68e9e8eb8f43fced7aa55940dc8eca98f95767994abbacdd81",
"metadata" : { }, "metadata" : { },
"diagnostics" : [ { "diagnostics" : [ {
@ -1379,7 +1379,7 @@
"relative_path" : "flag02.png", "relative_path" : "flag02.png",
"mime_type" : "image/png", "mime_type" : "image/png",
"size" : 684, "size" : 684,
"last_modified" : 1774359777379, "last_modified" : 1775797786703,
"fingerprint" : "5fd43c447cf6dd9b164458860239427d2f4544ff6e007814731b50c17ffe75bf", "fingerprint" : "5fd43c447cf6dd9b164458860239427d2f4544ff6e007814731b50c17ffe75bf",
"metadata" : { }, "metadata" : { },
"diagnostics" : [ { "diagnostics" : [ {
@ -1393,7 +1393,7 @@
"relative_path" : "flag03.png", "relative_path" : "flag03.png",
"mime_type" : "image/png", "mime_type" : "image/png",
"size" : 669, "size" : 669,
"last_modified" : 1774359777380, "last_modified" : 1775797786706,
"fingerprint" : "7feab8c868bb446afd3dd7250e70504fb0ca228f463650d2dd7c525144e0b321", "fingerprint" : "7feab8c868bb446afd3dd7250e70504fb0ca228f463650d2dd7c525144e0b321",
"metadata" : { "metadata" : {
"palette" : { "palette" : {
@ -1411,7 +1411,7 @@
"relative_path" : "link00.png", "relative_path" : "link00.png",
"mime_type" : "image/png", "mime_type" : "image/png",
"size" : 497, "size" : 497,
"last_modified" : 1774359777381, "last_modified" : 1775797786710,
"fingerprint" : "c363f3ef7f32d9b249c7dc8babdb3eb5aae68c524099e5e97290202b054dda71", "fingerprint" : "c363f3ef7f32d9b249c7dc8babdb3eb5aae68c524099e5e97290202b054dda71",
"metadata" : { "metadata" : {
"palette" : { "palette" : {
@ -1429,7 +1429,7 @@
"relative_path" : "link01.png", "relative_path" : "link01.png",
"mime_type" : "image/png", "mime_type" : "image/png",
"size" : 500, "size" : 500,
"last_modified" : 1774359777382, "last_modified" : 1775797786711,
"fingerprint" : "e2130efbb9643b41a4fb62619f2713402f9622c7db040fe18d929609ef70b89a", "fingerprint" : "e2130efbb9643b41a4fb62619f2713402f9622c7db040fe18d929609ef70b89a",
"metadata" : { "metadata" : {
"palette" : { "palette" : {
@ -1447,7 +1447,7 @@
"relative_path" : "link02.png", "relative_path" : "link02.png",
"mime_type" : "image/png", "mime_type" : "image/png",
"size" : 517, "size" : 517,
"last_modified" : 1774359777383, "last_modified" : 1775797786713,
"fingerprint" : "9216dfc6a6226fac398e9f781550d23fbfaa65bd377cdda69187149beca114ec", "fingerprint" : "9216dfc6a6226fac398e9f781550d23fbfaa65bd377cdda69187149beca114ec",
"metadata" : { "metadata" : {
"palette" : { "palette" : {
@ -1465,7 +1465,7 @@
"relative_path" : "link03.png", "relative_path" : "link03.png",
"mime_type" : "image/png", "mime_type" : "image/png",
"size" : 507, "size" : 507,
"last_modified" : 1774359777383, "last_modified" : 1775797786712,
"fingerprint" : "ebc4b7ca7bb1455288681c5d71424f60f658a44cb343d0c3934329cec676c867", "fingerprint" : "ebc4b7ca7bb1455288681c5d71424f60f658a44cb343d0c3934329cec676c867",
"metadata" : { "metadata" : {
"palette" : { "palette" : {
@ -1483,7 +1483,7 @@
"relative_path" : "link04.png", "relative_path" : "link04.png",
"mime_type" : "image/png", "mime_type" : "image/png",
"size" : 497, "size" : 497,
"last_modified" : 1774359777384, "last_modified" : 1775797786718,
"fingerprint" : "c363f3ef7f32d9b249c7dc8babdb3eb5aae68c524099e5e97290202b054dda71", "fingerprint" : "c363f3ef7f32d9b249c7dc8babdb3eb5aae68c524099e5e97290202b054dda71",
"metadata" : { "metadata" : {
"palette" : { "palette" : {
@ -1501,7 +1501,7 @@
"relative_path" : "link05.png", "relative_path" : "link05.png",
"mime_type" : "image/png", "mime_type" : "image/png",
"size" : 495, "size" : 495,
"last_modified" : 1774359777384, "last_modified" : 1775797786717,
"fingerprint" : "1ba8ce75c445396334737143e0cfa56c87a1fb64cca8ad0962192594849249eb", "fingerprint" : "1ba8ce75c445396334737143e0cfa56c87a1fb64cca8ad0962192594849249eb",
"metadata" : { "metadata" : {
"palette" : { "palette" : {
@ -1519,7 +1519,7 @@
"relative_path" : "link06.png", "relative_path" : "link06.png",
"mime_type" : "image/png", "mime_type" : "image/png",
"size" : 518, "size" : 518,
"last_modified" : 1774359777385, "last_modified" : 1775797786714,
"fingerprint" : "5e0954447699c6d5eac7550f1a10cf520efcddad0b9fbd9a716434da9d9550d4", "fingerprint" : "5e0954447699c6d5eac7550f1a10cf520efcddad0b9fbd9a716434da9d9550d4",
"metadata" : { "metadata" : {
"palette" : { "palette" : {
@ -1537,7 +1537,7 @@
"relative_path" : "link07.png", "relative_path" : "link07.png",
"mime_type" : "image/png", "mime_type" : "image/png",
"size" : 517, "size" : 517,
"last_modified" : 1774359777385, "last_modified" : 1775797786716,
"fingerprint" : "6104ba7f216a937994d478ed07766ec28f48ad72fdd6620508535a1f877b8ddb", "fingerprint" : "6104ba7f216a937994d478ed07766ec28f48ad72fdd6620508535a1f877b8ddb",
"metadata" : { "metadata" : {
"palette" : { "palette" : {
@ -1555,7 +1555,7 @@
"relative_path" : "t1381s1.png", "relative_path" : "t1381s1.png",
"mime_type" : "image/png", "mime_type" : "image/png",
"size" : 4970, "size" : 4970,
"last_modified" : 1774359777386, "last_modified" : 1775797786715,
"fingerprint" : "c8b667527b32436ab97fd57b3215917f7065d6d1b7f6d71be1827351bdc61fa6", "fingerprint" : "c8b667527b32436ab97fd57b3215917f7065d6d1b7f6d71be1827351bdc61fa6",
"metadata" : { }, "metadata" : { },
"diagnostics" : [ { "diagnostics" : [ {
@ -1569,7 +1569,7 @@
"relative_path" : "t1489s1.png", "relative_path" : "t1489s1.png",
"mime_type" : "image/png", "mime_type" : "image/png",
"size" : 6489, "size" : 6489,
"last_modified" : 1774359777387, "last_modified" : 1775797786719,
"fingerprint" : "678c6f48c6d1fcd1209c9d0ab1c46f20eea4871946135263b7363488cceb74f0", "fingerprint" : "678c6f48c6d1fcd1209c9d0ab1c46f20eea4871946135263b7363488cceb74f0",
"metadata" : { }, "metadata" : { },
"diagnostics" : [ { "diagnostics" : [ {

View File

@ -2,7 +2,7 @@
"schema_version" : 1, "schema_version" : 1,
"asset_uuid" : "87396aab-337e-479e-b1f4-ec296678389e", "asset_uuid" : "87396aab-337e-479e-b1f4-ec296678389e",
"name" : "Zelda", "name" : "Zelda",
"type" : "tile_bank", "type" : "glyph_bank",
"output" : { "output" : {
"codec" : "NONE", "codec" : "NONE",
"pipeline" : { "pipeline" : {
@ -14,7 +14,7 @@
} }
} ] } ]
}, },
"format" : "TILES/indexed_v1", "format" : "GLYPH/indexed_v1",
"codec_configuration" : { }, "codec_configuration" : { },
"metadata" : { "metadata" : {
"tile_size" : "32x32" "tile_size" : "32x32"

View File

@ -2,9 +2,9 @@
"schema_version" : 1, "schema_version" : 1,
"asset_uuid" : "64147d33-e8bf-4272-bb5c-b4c07c0276b3", "asset_uuid" : "64147d33-e8bf-4272-bb5c-b4c07c0276b3",
"name" : "Bigode", "name" : "Bigode",
"type" : "tile_bank", "type" : "glyph_bank",
"output" : { "output" : {
"format" : "TILES/indexed_v1", "format" : "GLYPH/indexed_v1",
"codec" : "NONE", "codec" : "NONE",
"codec_configuration" : { }, "codec_configuration" : { },
"metadata" : { "metadata" : {

View File

@ -2,9 +2,9 @@
"schema_version" : 1, "schema_version" : 1,
"asset_uuid" : "b15b319f-5cab-4254-93ea-d83f4742d204", "asset_uuid" : "b15b319f-5cab-4254-93ea-d83f4742d204",
"name" : "ui_atlas", "name" : "ui_atlas",
"type" : "tile_bank", "type" : "glyph_bank",
"output" : { "output" : {
"format" : "TILES/indexed_v1", "format" : "GLYPH/indexed_v1",
"codec" : "NONE", "codec" : "NONE",
"codec_configuration" : { }, "codec_configuration" : { },
"metadata" : { "metadata" : {

View File

@ -2,10 +2,10 @@
"schema_version" : 1, "schema_version" : 1,
"asset_uuid" : "f64d3bfe-443d-4703-b62a-face19a32cac", "asset_uuid" : "f64d3bfe-443d-4703-b62a-face19a32cac",
"name" : "bbb2", "name" : "bbb2",
"type" : "tile_bank", "type" : "glyph_bank",
"output" : { "output" : {
"codec" : "NONE", "codec" : "NONE",
"format" : "TILES/indexed_v1" "format" : "GLYPH/indexed_v1"
}, },
"preload" : { "preload" : {
"enabled" : false "enabled" : false

View File

@ -2,9 +2,9 @@
"schema_version" : 1, "schema_version" : 1,
"asset_uuid" : "4d9847b0-5a23-421f-8b78-bf3909ca2281", "asset_uuid" : "4d9847b0-5a23-421f-8b78-bf3909ca2281",
"name" : "one-more-atlas", "name" : "one-more-atlas",
"type" : "tile_bank", "type" : "glyph_bank",
"output" : { "output" : {
"format" : "TILES/indexed_v1", "format" : "GLYPH/indexed_v1",
"codec" : "NONE" "codec" : "NONE"
}, },
"preload" : { "preload" : {

View File

@ -2,9 +2,9 @@
"schema_version" : 1, "schema_version" : 1,
"asset_uuid" : "21953cb8-4101-4790-9e5e-d95f5fbc9b5a", "asset_uuid" : "21953cb8-4101-4790-9e5e-d95f5fbc9b5a",
"name" : "ui_atlas", "name" : "ui_atlas",
"type" : "tile_bank", "type" : "glyph_bank",
"output" : { "output" : {
"format" : "TILES/indexed_v1", "format" : "GLYPH/indexed_v1",
"codec" : "NONE", "codec" : "NONE",
"codec_configuration" : { }, "codec_configuration" : { },
"metadata" : { "metadata" : {

View File

@ -2,9 +2,9 @@
"schema_version" : 1, "schema_version" : 1,
"asset_uuid" : "62a81570-8f47-4612-9288-6060e6c9a2e2", "asset_uuid" : "62a81570-8f47-4612-9288-6060e6c9a2e2",
"name" : "one-more-atlas", "name" : "one-more-atlas",
"type" : "tile_bank", "type" : "glyph_bank",
"output" : { "output" : {
"format" : "TILES/indexed_v1", "format" : "GLYPH/indexed_v1",
"codec" : "NONE" "codec" : "NONE"
}, },
"preload" : { "preload" : {