# 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.

### Scene Bank Contract Boundary

For `Scene Bank` assets, `output.format = SCENE/tilemap_v1` identifies the runtime-facing scene contract.

Rules:

- `SCENE/tilemap_v1` is a runtime/publication format, not an editor-file format;
- `TMX`, `TSX`, and other editor-specific files may exist as tooling/editorial surfaces, but they are not the canonical publication contract;
- the canonical packer input for `Scene Bank` publication is the editor-agnostic Scene Bank request emitted by Studio from canonical scene state;
- packer must not reinterpret the presence of editorial files as authorization to bypass the request boundary;
- packer must not assume any external scene file is canonical persistence, even when Studio supports that file as import/export compatibility.

### 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": <int>, "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.
