# Asset Declaration and Virtual Asset Contract Specification Status: Draft Scope: Common `asset.json` contract Purpose: Define the shared declaration model for raw and virtual assets. ## Authority and Precedence This specification consolidates the initial packer agenda and decision wave into normative form. ## Core Rules The common `asset.json` contract requires these top-level fields: - `schema_version` - `asset_uuid` - `name` - `type` - `inputs` - `output` - `preload` The common contract may also include: - `build` ## Meaning of `asset_uuid` `asset_uuid` is the stable asset-local identity anchor. Rules: - it is required; - it must be stable across relocate and rename flows; - it is not the project-local runtime artifact identity; - it is not a substitute for registry-owned `asset_id`; - it exists so the asset root can preserve identity even when path-based assumptions drift; - it must remain compatible with packer reconcile behavior and migration flows. ## Meaning of `name` `name` is the logical asset reference label. Rules: - it is required; - it is not the stable artifact identity; - it may still be used by runtime-facing APIs and source-level workflows. ## Meaning of `type` `type` identifies the authoring-side asset family. Rules: - it is not the runtime bank identity; - the runtime-facing technical target belongs in `output.format`. Examples: - `glyph_bank` - `sound_bank` ## Inputs `inputs` is a structured object keyed by semantic role. Rules: - each key names an input role such as `sprites`, `palettes`, or `sources`; - each value is a list of paths; - paths are relative to the asset root; - even a single input is represented as a list. This model supports grouped virtual assets such as atlases and bank-style assets. ## Output `output` is the runtime-relevant output declaration. Required baseline fields: - `output.format` - `output.codec` Optional baseline field: - `output.metadata` - `output.pipeline` Rules: - `output.format` defines the semantic/runtime format contract; - `output.codec` defines storage/extraction behavior; - `output.codec` serialized values must use `SCREAMING_SNAKE_CASE`; - `output.metadata` carries runtime-relevant format-specific detail; - `output.pipeline` carries tooling/build metadata kept separate at authoring time; - codec must remain explicit and must not be hidden inside format naming. ### Explicit Index Collections When `output.pipeline` carries ordered collections whose members need stable semantic identity, that identity must not depend on raw list position alone. Rules: - collections such as `output.pipeline.palettes` may remain JSON arrays for authoring ergonomics; - when a collection member has runtime- or packing-relevant identity, each entry must carry an explicit `index`; - `output.pipeline.palettes` entries must use the shape `{ "index": , "palette": { ... } }`; - the packer must sort such entries by numeric `index`, not by physical array position; - duplicate or malformed indices are structural errors; - missing or malformed `palette` payloads are structural errors; - editorial reordering of the JSON array alone must not change semantic meaning. Example: ```json { "output": { "pipeline": { "palettes": [ { "index": 0, "palette": { "originalArgb8888": [4294901760, 4278255360], "convertedRgb565": [63488, 2016] } } ] } } } ``` ## Metadata Source Segmentation and Runtime Sink `asset.json` may keep metadata segmented by concern during authoring. Rules: - declaration-time metadata may come from multiple sources under the asset contract (for example, format metadata, codec-related metadata, and build/pipeline-derived declarations); - `output.pipeline` may carry nested pipeline-derived metadata objects; - this segmentation exists for authoring clarity and does not define multiple runtime sinks; - `output.pipeline` is tooling-only and must not become part of the runtime-facing asset header by default; - pipeline-derived values required at runtime must be promoted explicitly into normative runtime-owned metadata fields; - runtime consumers must read effective metadata from the runtime asset entry metadata sink (`AssetEntry.metadata`); - convergence/normalization behavior is normative in the build artifact specification. ## Build `build` is optional and process-oriented. Rules: - it may describe how authoring inputs are transformed or organized; - if a parameter affects the runtime-facing output contract, it belongs in `output.metadata`; - `build` must not hide runtime-relevant semantics. ## Operational State Exclusion `asset.json` is a declaration artifact, not a catalog cache. Rules: - transient UI state must not be stored in `asset.json`; - registry-managed fields such as `asset_id` and `included_in_build` must not be duplicated into `asset.json`; - packer cache or snapshot bookkeeping must not be materialized into `asset.json` as normal operational state; - `asset.json` should remain focused on identity anchoring plus declared authoring/packing behavior. ## Preload Each registered asset must declare preload intent explicitly. Baseline shape: ```json { "preload": { "enabled": true } } ``` Rules: - `preload.enabled` is required and boolean; - preload participation is declared, not inferred; - richer preload policy fields are deferred. ## Defaults and Materialization Defaults that affect runtime-visible behavior must not remain hidden. Rules: - runtime-relevant defaults should be materialized in `asset.json` whenever practical; - if materialized later, the resulting artifact must expose effective values explicitly. ## Versioning The `asset.json` schema is versioned independently from: - registry schema - runtime-facing artifact schema - format contract versions Format-specific contracts evolve through values such as `GLYPH/indexed_v1`. ## Non-Goals - field-level format schemas for every output family - rich preload policies - source-language lowering behavior for asset references ## Exit Criteria This specification is complete enough when: - the common `asset.json` shape is stable; - raw and virtual assets share a coherent baseline contract; - format-specific specs can build on it cleanly.