# Reference: The Vocabulary

The vocabulary is the closed set of everything a ChainRender app can express. It's machine-readable via
`vocabulary()`, and it's *closed* by design — that closure is what makes apps analyzable and safe. Every list in it is
derived from the real constants (the on-chain format dictionaries, the capability bits, the resolver-kind mirrors), so
tooling never hardcodes them.

```ts
import { vocabulary } from "@chainrender/client";
const v = vocabulary();
// v.nodeTypes      the 9 node types and their own fields
// v.a11y           accessibility fields (every node type except image and ref)
// v.behavior       cond / step / anim / live (every node type except ref)
// v.enums          allowed values: role, ariaState, variant, direction, inputType, provenance, anim, animRepeat
// v.capabilities   the capability bits
// v.kinds          IR sub-vocabularies: chart, control, layout
// v.resolverKinds  every first-party resolver kind, with its args (most of the payload)
// v.limits         maxNodes, maxDepth
```

## Node types

The compiler reads exactly nine node types: `text`, `box`, `button`, `input`, `icon`, `link`, `slot`, `image` and
`ref`. Everything else you build is made of these:

- **Headings, notes, captions** are `text` with a `role` (`compose.heading(...)` is a `text` with `role: "heading"`).
- **Charts, tables, controls (toggle, select, slider, search), layouts (stack/grid/flow) and multi-view apps** are
  structured renderers with their own sub-vocabularies in `vocabulary().kinds`, built with the format builders
  (`buildTabs`, `buildWizard`, …) and rendered by their own on-chain views.
- **Live data** is a `slot` (text) or an `image` (media) bound to a resolver kind.

Every field of every node type — which ones are required, the allowed enum values, which a11y and behaviour fields
apply — is listed on **[Node Fields](./node-fields.md)**, generated from the same table the compiler is tested
against.

## Checking a tree before you compile it

`compile()` is lenient: it silently drops anything it doesn't read. A misspelled enum value (`direction:
"vertical"`), a role that isn't in the dictionary (`role: "note"`), an unknown field, a11y fields on an image, or
`args` on a batch member all compile without an error — and ship without what you wrote. Check first:

```ts
import { checkNode, nodeJsonSchema } from "@chainrender/client";   // 0.10.0+

const r = checkNode(tree);              // { ok, issues: [{ path, code, message }], nodeCount, depth }
if (!r.ok) console.table(r.issues);     // e.g. /children/2/role  enum  role must be one of button, textbox, …

const schema = nodeJsonSchema();        // the same rules as a strict JSON Schema (draft 2020-12) for an AI tool
```

`checkNode` also enforces what JSON Schema can't express: at most 1024 nodes, depth at most 64, 255 children or
attributes per node, and 65,535 bytes per literal. A tree made in the visual builder carries builder-only fields —
`argValues` on slots and images (encoded into `arg` at export), `image.scene`, a root `pinnedDep`, and `_`-prefixed
design-time keys such as `_multiview`; check it with `checkNode(tree, { authoring: true })` (SDK 0.10.1+).

## Capabilities
`READ_CHAIN` (read state), `WRITE_CHAIN` (send a tx), `VALUE` (move ETH), `SIGN_MESSAGE` (typed signing),
`BATCH_EXECUTE` (atomic multi-action), `CLIENT_FETCH` (off-chain fetch — drops the grade), `GPU_EXECUTE`
(client GPU enhancement, fails closed to a poster). An app declares its envelope; the enforcer verifies it.

## Resolver kinds
Each resolver declares which kinds it serves. `vocabulary().resolverKinds` lists every first-party kind with its
args, data edge and capability — never hardcode a kind string or guess an arg shape; read it from here. The full list
is on **[All Resolver Kinds](./resolver-kinds.md)**. Encode a slot's `arg` exactly as the kind says: `abi.encode` of
its args unless the kind is marked `argsEncoding: "packed"` (raw bytes, e.g. `ensName` takes the 20 address bytes).

The kind list is most of the vocabulary's size, so an AI building one component rarely needs all of it. Through the
MCP server, request the vocabulary without `resolverKinds` and look kinds up with `chainrender_search_kinds` /
`chainrender_describe_kind` — see **[MCP Server & AI Skill](./mcp-and-skill.md)**.
