# App Metadata — The Expandable Seam for App Info

ChainRender apps carry descriptive metadata (title, author, description, kind, tags, …) in a single,
versioned, open-ended container stored on-chain. This page documents the seam so that adding a new
piece of app info in the future is a one-line change, never an archaeology expedition.

## Why this exists

The scene registry stores an app's floor and binding, but originally had nowhere to put a human title —
which is why the Apps page once showed generic id-names like "3D Scene a1b2c3". Rather than bolt on a
single `title` field, ChainRender defines an **open metadata container**: title is simply its first
resident. The whole class of "an app needs to carry more descriptive info" (author, description,
category, license, thumbnail pointer, a "verified" flag, …) becomes a trivial addition to one module.

## Where it lives

- **On-chain:** a compact, versioned JSON string carried in the scene binding's trailing `meta` field.
  The binding is `abi.encode(bytes32 libHash, bytes32 seed, string entry, string meta)`. Older apps have
  a 3-field binding with no `meta`; readers fall back gracefully, so nothing breaks.
- **In code:** [`chainc/appmeta.ts`](../reference/sdk-client.md) is the single source of truth —
  `encodeAppMeta`, `decodeAppMeta`, and accessors (`getTitle`, `getAuthor`, …). Every surface (Apps page,
  viewer, builder) reads metadata through this module, so there is no second copy to drift out of sync.

### Fields in v1

, , , ,  (Lucide name for the app's card),  (grouping
in the collection, e.g. DeFi/Art/Games/Tools), , . The Apps page reads , ,
, and  to render a categorized, filterable collection; the builder writes them at
deploy from the project name + the App-collection-info UI.

## The container's guarantees

- **Versioned.** Each record stamps a schema version. A reader that only understands v1 can still read a
  v3 app's title — it reads the keys it knows and ignores the rest. Old readers never choke on new data;
  new readers gracefully handle old or missing data.
- **Open.** Metadata is a key→value map, not a fixed struct. Adding a field needs no schema migration —
  you add the key. Unknown keys are preserved verbatim on decode (forward-compatibility).
- **Fail-safe.** `decodeAppMeta` never throws: malformed, empty, or missing input returns an empty record,
  so a missing title simply falls back to an id-derived name. Nothing ever blanks or errors.
- **Bounded.** Serialized metadata is size-capped, keeping deploy cost predictable. Large or binary data
  (e.g. a thumbnail image) is never inlined — only a hash pointer to it.

## How to add a new field (the repeatable move)

1. Add the key to the `AppMeta` interface and `KNOWN_KEYS` in `chainc/appmeta.ts` (documentation).
2. If it deserves a fallback, add an accessor like `getTitle` (e.g. `getLicense(meta, fallback)`).
3. Write it at deploy time (the builder passes it into `encodeAppMeta({...})`).
4. Read it wherever needed via the accessor.
5. If the record *shape* changed meaningfully, bump `APP_META_VERSION`. Adding an optional key does not
   require a bump — readers ignore unknown keys.

That's the whole change, in one module. Every surface picks it up because they all read through the same
accessors.

## Honest limits

- **Descriptive, not functional.** This carries info an app *has* (title, author, tags). Functional gaps
  (e.g. live-data bridges) use their own seams; app-metadata is deliberately scoped to self-description.
- **Only new deploys.** On-chain bindings are immutable, so a new field only appears on apps deployed
  after it's added. Existing apps keep whatever metadata they were deployed with (often none → fallback).
- **References, not payloads.** Big things live behind a hash pointer in the metadata, not inline.

## Related
- **[Building Correctly](./building-correctly.md)** — the on-chain paradigm apps are built on.
- **[The Apps Directory](./apps-directory.md)** — where app titles are displayed, read from this metadata.
- **[Content Addressing](./content-addressing.md)** — the hash identity the metadata sits alongside.
