<!-- GENERATED by scripts/gen-reference-docs.ts (scripts/sdk-api-doc.ts) from the @chainrender/client entry points — do not edit by hand; edit the source and rerun. -->

# Reference: SDK API (every export)

> Generated for **`@chainrender/client` 0.21.0** — these are its exports, exactly. Using another version? Check yours with `npm ls @chainrender/client`.

Every export of `@chainrender/client`, generated from the SDK source: the signature as written and the doc comment next to it. If a name is not on this page, the package does not export it — do not import it. Import paths are exact: an export listed under `@chainrender/client` is not available from `@chainrender/client/runtime`, and a name listed inside a namespace (for example `events.eventTopic0`) is reached through that namespace (`import { events } from "@chainrender/client/runtime"`).

For what each part is for and how to combine them, start with **[@chainrender/client](./sdk-client.md)**, **[Runtime API](./runtime.md)** and **[React API](./react.md)**. `viem` is a required peer dependency.

Coverage: 180 value exports across 4 entry points; 171 carry a doc comment in the source. Without one (signature only): `compile`, `decompile`, `DecompileError`, `HINTS`, `HINTS_REGISTRY_VERSION`, `hintSpec`, `hintRegistry`, `presentationFindings`, `isCrArg`.

## `@chainrender/client`

Authoring core: compile, check, grade, describe, validate, the vocabulary, manifests, themes, naming.

```ts
import { compileComponent } from "@chainrender/client";
```

### Compile

#### `compileComponent`

```ts
function compileComponent(root: Node, opts: CompileOptions = {}): Compiled
```

Compiles a JSON AST component and returns its bytes, hex, content hash, and size.

Source: `chainc/index.ts`

#### `compileJsx`

```ts
function compileJsx(src: string): Compiled
```

Compiles a JSX-like string via the thin front-end, then the shared JSON-AST core.

Source: `chainc/index.ts`

#### `compile`

```ts
function compile(root: Node, opts: CompileOptions = {}): Uint8Array
```

_No doc comment in the source._

Source: `chainc/compile.ts`

#### `parseJsx`

```ts
function parseJsx(src: string): Node
```

Parses a JSX-like string into the chainc JSON AST.

Source: `chainc/jsx.ts`

#### `toHex`

```ts
function toHex(bytes: Uint8Array): `0x${string}`
```

Hex-encodes CRO2 bytes as an 0x-prefixed string (for passing to viem/ethers).

Source: `chainc/compile.ts`

### Decompile (0.21.0): CRO2 bytes back to the tree, exact or it throws — the builder's Fork (doc 119 §3.6)

#### `decompile`

```ts
function decompile(input: Uint8Array | string): Decompiled
```

_No doc comment in the source._

Source: `chainc/decompile.ts`

#### `DecompileError`

```ts
class DecompileError extends Error
```

_No doc comment in the source._

Source: `chainc/decompile.ts`

### Vocabulary constants + IR builders (the closed vocabularies)

#### `format` (namespace)

chainc — CRO2 format constants.

Source: `chainc/format.ts`

| Member | Signature | Summary |
|---|---|---|
| `format.VERSION_1` | `const VERSION_1 = 0x01` |  |
| `format.VERSION_2` | `const VERSION_2 = 0x02` |  |
| `format.VERSION_3` | `const VERSION_3 = 0x03` |  |
| `format.VERSION_4` | `const VERSION_4 = 0x04` |  |
| `format.VERSION_5` | `const VERSION_5 = 0x05` | docs/202: V4 + style tokens, hints, lang/dir, aria-level and the full WAI-ARIA 1.2 role table (opt-in; strict superset of V4). |
| `format.HEADER_LEN` | `const HEADER_LEN = 4` |  |
| `format.ROOT_FLAGS_RESERVED` | `const ROOT_FLAGS_RESERVED = 0x00` |  |
| `format.TAG` | `const TAG = { … } as const` |  |
| `format.TAG_MAX_KNOWN` | `const TAG_MAX_KNOWN = 0x07` |  |
| `format.ATTR` | `const ATTR = { … } as const` |  |
| `format.ATTR_KEY_MASK` | `const ATTR_KEY_MASK = 0x7f` |  |
| `format.ATTR_DICT_FLAG` | `const ATTR_DICT_FLAG = 0x80` |  |
| `format.ROLE` | `const ROLE = { … } as const` |  |
| `format.ROLE_V5_FROM` | `const ROLE_V5_FROM = 0x17` | The first role index that needs VERSION_5. |
| `format.ARIA_STATE` | `const ARIA_STATE = { … } as const` | ARIA state indices (order matches OpcodeFormat.sol ARIA_* + chainc/a11y.ts A11Y_STATES; drift-guarded). |
| `format.VARIANT` | `const VARIANT = { … } as const` |  |
| `format.DIRECTION` | `const DIRECTION = { … } as const` |  |
| `format.DIR` | `const DIR = { … } as const` | VERSION_5 (docs/202): text direction, emitted as dir="…". |
| `format.LANG_RE` | `const LANG_RE = /^[A-Za-z]{2,3}(-[A-Za-z0-9]{1,8}){0,3}$/` | VERSION_5 (docs/202 §4.1): the shape of a BCP-47 language tag the interpreter accepts for lang="…". |
| `format.ARIA_LEVELS` | `const ARIA_LEVELS = [ … ] as const` | VERSION_5 (docs/202): heading levels, emitted as aria-level (dict index = level). |
| `format.INPUTTYPE` | `const INPUTTYPE = { … } as const` |  |
| `format.PROVENANCE` | `const PROVENANCE = { … } as const` | Media provenance — how "on-chain" a media node is. |
| `format.ANIM` | `const ANIM = { … } as const` | Bounded declarative animation kinds. |
| `format.ANIM_REPEAT` | `const ANIM_REPEAT = { … } as const` |  |
| `format.MAX_NODES` | `const MAX_NODES = 1024` |  |
| `format.MAX_DEPTH` | `const MAX_DEPTH = 64` |  |

#### `compose` (namespace)

@chainrender/client — compose.*: ergonomic, typed AST builders (doc 73 §4). Thin constructors over the Node union plus re-exported IR builder modules, so a builder / AI / MCP constructs valid trees without hand-writing object literals. Everything here returns plain `Node`s in the closed vocabulary — nothing here can express outside it (constrained by construction).

Source: `client/compose.ts`

| Member | Signature | Summary |
|---|---|---|
| `compose.text` | `const text = (content: string, extra: Partial<Node> = {}): Node => …` |  |
| `compose.box` | `const box = (children: Kids, extra: Partial<Node> = {}): Node => …` |  |
| `compose.heading` | `const heading = (content: string): Node => …` |  |
| `compose.button` | `const button = (content: string, opts: { variant?: string; action?: { to?: string; sig: string; value?: string; args?: string } } = {},): Node => …` |  |
| `compose.input` | `const input = (opts: { inputType?: string; placeholder?: string; name?: string } = {}): Node => …` |  |
| `compose.link` | `const link = (href: string, content: string): Node => …` |  |
| `compose.icon` | `const icon = (name: string): Node => …` |  |
| `compose.slot` | `const slot = (bind: string, opts: { arg?: string; resolver?: string; content?: string } = {}): Node => …` |  |
| `compose.image` | `const image = (opts: { alt?: string; bind?: string; arg?: string; resolver?: string; provenance?: string } = {}): Node => …` |  |
| `compose.ref` | `const ref = (hash: string): Node => …` |  |
| `compose.composition` | namespace | The higher IR vocabularies (composition / layout / multi-view / data-binding / controls / table / chart), re-exported so `compose.layout.*`, `compose.chart.*`, etc. |
| `compose.composition.ANCHOR` | `const ANCHOR = { … } as const` | Closed placement vocabulary: a 2D anchor over the scene canvas. |
| `compose.composition.ANCHOR_NAME` | `const ANCHOR_NAME: Record<number, string> = { … }` |  |
| `compose.composition.PLACE_MODE` | `const PLACE_MODE = { … } as const` | Placement mode — composition-v2 adds SPATIAL_3D alongside the original 2D overlay. |
| `compose.composition.PLACE_MODE_NAME` | `const PLACE_MODE_NAME: Record<number, string> = { … }` |  |
| `compose.composition.SCENE_KIND` | `const SCENE_KIND = { … } as const` | The scene the components are composed over. |
| `compose.composition.aggregateCapabilities` | `function aggregateCapabilities(scene: SceneRef, components: PlacedComponentInput[]): number` | The honest aggregate: READ_CHAIN baseline + the union of every placed component's capabilities + the scene's GPU capability if it renders on the GPU. |
| `compose.composition.buildComposition` | `function buildComposition(input: CompositionInput): BuiltComposition` | Build the canonical composition bytes + hash. |
| `compose.layout` | namespace |  |
| `compose.layout.LAYOUT_KIND` | `const LAYOUT_KIND = { … } as const` | Composition-level responsive layout — mirror of contracts/scene/LayoutFormat.sol. |
| `compose.layout.LAYOUT_DIR` | `const LAYOUT_DIR = { … } as const` |  |
| `compose.layout.LAYOUT_ALIGN` | `const LAYOUT_ALIGN = { … } as const` |  |
| `compose.layout.LAYOUT_JUSTIFY` | `const LAYOUT_JUSTIFY = { … } as const` |  |
| `compose.layout.toLayoutTuple` | `function toLayoutTuple(L: LayoutInput)` |  |
| `compose.layout.LAYOUT_ABI` | `const LAYOUT_ABI = { … } as const` |  |
| `compose.layout.encodeLayout` | `function encodeLayout(L: LayoutInput): '0x${string}'` | Canonical encoded bytes for a layout (for content-addressed storage / an app manifest). |
| `compose.multiview` | namespace |  |
| `compose.multiview.TGT_VIEW` | `const TGT_VIEW = 0x40` | In-app routing/navigation vocabulary — mirror of contracts/scene/MultiViewFormat.sol. |
| `compose.multiview.NAV` | `const NAV = { … } as const` |  |
| `compose.multiview.VIEW_FLAG` | `const VIEW_FLAG = { … } as const` |  |
| `compose.multiview.FROM_ANY` | `const FROM_ANY = 0xff` |  |
| `compose.multiview.SEL_MODE` | `const SEL_MODE = { … } as const` |  |
| `compose.multiview.buildMultiView` | `function buildMultiView(input: MultiViewInput): BuiltMultiView` | Build the canonical multi-view bytes + hash (content-addressed, ownerless). |
| `compose.multiview.reachable` | `function reachable(input: MultiViewInput): boolean` | Client-side mirror of MultiViewFormat._reachable — the reachability invariant (no stranding). |
| `compose.multiview.buildTabs` | `function buildTabs(views: '0x${string}'[], opts: { shell?: '0x${string}'; defaultView?: number; name?: string; version?: string } = {}): TemplateResult` | TABS — peer views, a persistent shell tab bar reaches every view from every view. |
| `compose.multiview.buildWizard` | `function buildWizard(steps: '0x${string}'[], opts: { shell?: '0x${string}'; name?: string; version?: string } = {}): TemplateResult` | WIZARD — ordered steps with Next (i→i+1) and Back (i→i-1). |
| `compose.multiview.buildMasterDetail` | `function buildMasterDetail(listView: '0x${string}', detailViews: '0x${string}'[], opts: { shell?: '0x${string}'; name?: string; version?: string } = {}): TemplateResult` | MASTER-DETAIL — a list (default) plus detail view(s). |
| `compose.multiview.buildModal` | `function buildModal(baseView: '0x${string}', modalViews: '0x${string}'[], opts: { shell?: '0x${string}'; name?: string; version?: string } = {}): TemplateResult` | MODAL — a base view (default) plus overlay view(s) rendered on top under a scrim. |
| `compose.databind` | namespace |  |
| `compose.databind.BIND_ANCHOR` | `const BIND_ANCHOR = { … } as const` | App-level data-binding — mirror of contracts/DataBinder.sol. |
| `compose.databind.bindKind` | `function bindKind(kind: string): '0x${string}'` | A binding kind ("balance", "ensName", …) right-padded into bytes32, matching the resolver-hook ABI. |
| `compose.databind.toBindingTuples` | `function toBindingTuples(bindings: DataBindingInput[])` | The tuple array form for a direct `renderBindings` / `resolveValue` / `capabilities` call. |
| `compose.databind.encodeDataBindings` | `function encodeDataBindings(bindings: DataBindingInput[]): '0x${string}'` | Canonical encoded bytes for a data-binding set (for content-addressed storage / an app manifest). |
| `compose.controls` | namespace | Parameter-interaction vocabulary — mirror of contracts/scene/ControlFormat.sol. |
| `compose.controls.CONTROL_KIND` | `const CONTROL_KIND = { … } as const` | Parameter-interaction vocabulary — mirror of contracts/scene/ControlFormat.sol. |
| `compose.controls.toControlTuple` | `function toControlTuple(c: ControlInput)` | Tuple form for a direct renderControl / renderControls call. |
| `compose.controls.toControlTuples` | `function toControlTuples(cs: ControlInput[])` |  |
| `compose.table` | namespace |  |
| `compose.table.COL_ALIGN` | `const COL_ALIGN = { … } as const` | Table presentation vocabulary — mirror of contracts/TableRenderer.sol. |
| `compose.table.toColumnTuples` | `function toColumnTuples(cols: ColumnInput[])` |  |
| `compose.table.tableKind` | `function tableKind(kind: string): '0x${string}'` | A table-source kind ("ledger", …) right-padded into bytes32, matching the source ABI. |
| `compose.chart` | namespace | Chart vocabulary — mirror of contracts/scene/ChartFormat.sol. |
| `compose.chart.CHART_KIND` | `const CHART_KIND = { … } as const` |  |
| `compose.chart.toChartTuple` | `function toChartTuple(c: ChartInput)` |  |
| `compose.chart.niceStep` | `function niceStep(range: bigint, target: bigint): bigint` | JS mirror of ChartFormat._niceStep — the fixed-point port of D3's nice-tick step (power of ten × {1,2,5}, geometric-nearest via integer squares). |
| `compose.chart.CHART_ABI` | `const CHART_ABI = { … } as const` | The ChartSlotAdapter arg ABI (mirror of ChartSlotAdapter.resolve decode + seed-explorer's CHART_ABI): abi.encode(ChartFormat.Chart config, address source, bytes32 dataKind, bytes fetchArgs). |
| `compose.chart.PALETTE_ABI` | `const PALETTE_ABI = { … } as const` | ThemeTokens.Palette ABI tuple — field order MUST match contracts/ThemeTokens.sol Palette exactly. |
| `compose.chart.DEFAULT_CHART_PALETTE` | `const DEFAULT_CHART_PALETTE = { … } as const` | The default palette (mirror of ThemeTokens.defaults() -> paletteOf). |
| `compose.chart.chartKindOf` | `function chartKindOf(name: string \| number \| undefined): number` | A chart type by name: line, area, bar, scatter, pie, donut. |
| `compose.chart.encodeChartSlotArgs` | `function encodeChartSlotArgs(i: ChartSlotInput): Hex` | The `arg` of an image bound to ChartSlotAdapter: abi.encode(Chart, source, dataKind, fetchArgs, Palette). |
| `compose.chart.chainlinkHistoryChartArgs` | `function chainlinkHistoryChartArgs(i: ChainlinkHistoryChartInput): Hex` | The `arg` for a live price-history chart of a Chainlink-shaped feed: ChainlinkChartSource reads the last N rounds on every render (fails closed to an axes-only frame when the feed is unreadable). |
| `compose.chart.CHART_AUTHORING` | `const CHART_AUTHORING = { … } as const` | The builder's authoring descriptor for `bind: "chart"` (an image bound to ChartSlotAdapter). |

### Introspect

#### `requiredCapabilities`

```ts
function requiredCapabilities(node: Node): number
```

Derive the capability bits the behaviour REQUIRES from what the AST actually contains. This is the honest capability set: declaring more is over-claiming, declaring less is under-declaring.

Source: `chainc/describe.ts`

#### `describeBehavior`

```ts
function describeBehavior(node: Node, declaredCaps: number): BehaviorDescriptor
```

What a component can do, in plain language, derived from its AST without running it: the capabilities it requires vs the ones declared (and whether that declaration is honest), its actions, batches, signature requests, chain reads, media, GPU use and off-chain fetches, plus a human-readable summary. Pass requiredCapabilities(node) as declaredCaps to describe the honest set.

Source: `chainc/describe.ts`

#### `describeComposition`

```ts
function describeComposition(manifest: { scene: { kind: number; gpu?: boolean }; components: { hash: string; anchor: number; capabilities: number }[]; aggregated?: number; capabilities?: number; }, componentFloors: Map<string, BehaviorDescriptor>, anchorName: (a: number) => string,): CompositionFloor
```

The composed floor of a mini-app: the scene, every placed component with what each can do, and the aggregated capability set with whether it is escalation-free (the aggregate equals the union of the components' caps).

Source: `chainc/describe.ts`

### Validate

#### `collectBehavior`

```ts
function collectBehavior(node: Node): Collected
```

One walk of the AST collecting everything with consequences: actions, resolvers, refs, media, batches and signature requests. The same walk validateApp() and describeBehavior() use, so the description and the checks cannot disagree.

Source: `chainc/validate.ts`

#### `validateApp`

```ts
function validateApp(manifest: AppManifestInput, rootAst: Node, knownComponents: Set<string>, knownApps?: Set<string>,): ValidationReport
```

Validates an assembled app.

Source: `chainc/validate.ts`

#### `validateComposition`

```ts
function validateComposition(manifest: { scene: { kind: number; ref: string; gpu?: boolean }; components: { hash: string; anchor: number; capabilities: number }[]; capabilities?: number; aggregated?: number; parent?: string; }, knownComponentCaps: Map<string, number>, knownCompositions?: Set<string>,): ValidationReport
```

Validate a composition (mini-app): a scene + placed components + aggregated capabilities. The heart is capability aggregation with NO privilege escalation — the mini-app's capability set must be EXACTLY the union of its components' own declared capabilities (plus the scene's GPU), and no placed component may claim a capability it doesn't actually have. Placement aggregates and surfaces power; it never grants it.

Source: `chainc/validate.ts`

### Enforce (the drift-guarded mirrors of the on-chain enforcer)

#### `analyze`

```ts
function analyze(parts: Part[]): Analysis
```

The grade computation without the refusal rails: the capability envelope (union of every part's caps), the worst-link grade across the presentation, data and dependency axes, and one deviation per axis below A. Mirrors contracts/enforcer/TrustGrade.sol; most callers want check() or grade().

Source: `chainc/trustgrade.ts`

#### `check`

```ts
function check(parts: Part[], declaredEnvelope?: number): Result
```

The enforcer gate: rails first (R1 escape-hatch, I5 malformed, R2 capability-dishonesty), then grade.

Source: `chainc/trustgrade.ts`

#### `gateAction`

```ts
function gateAction(a: Action, envelope: number, allowed: Target[]): number
```

The action gate (doc 67 §4b): permit an action only if it fits the effective envelope + declared call set.

Source: `chainc/trustgrade.ts`

#### `gateBinding`

```ts
function gateBinding(bindCap: number, envelope: number): number
```

Rule R6: a data binding may not need a capability outside the envelope. Returns GATE.OK or GATE.OFF_ENVELOPE_BIND.

Source: `chainc/trustgrade.ts`

#### `firstBlocked`

```ts
function firstBlocked(actions: Action[], envelope: number, allowed: Target[]):
```

Runs gateAction() over a list and returns the first action it refuses (index and GATE reason), or blocked: false.

Source: `chainc/trustgrade.ts`

#### `gradeLetter`

```ts
function gradeLetter(g: number): string
```

presentation-layer helpers (the label)

Source: `chainc/trustgrade.ts`

#### `gradeWord`

```ts
function gradeWord(g: number): string
```

The word for a grade number: A "Trustless", B "Pinned", C "Live", X "Refused".

Source: `chainc/trustgrade.ts`

#### `gradeLocks`

```ts
function gradeLocks(g: number): string
```

The padlock meter for a grade number: A 🔒🔒🔒, B 🔒🔒◻, C 🔒◻◻, X ⛔.

Source: `chainc/trustgrade.ts`

#### `CAP`

```ts
const CAP = { … } as const
```

capability bits — MUST match chainc/manifest.ts CAP and TrustGrade.sol

Source: `chainc/trustgrade.ts`

#### `GRADE`

```ts
const GRADE = { … } as const
```

Grade numbers: A = 3 (Trustless), B = 2 (Pinned), C = 1 (Live), X = 0 (Refused). Higher is more trustless.

Source: `chainc/trustgrade.ts`

#### `GATE`

```ts
const GATE = { … } as const
```

Action-gate results: OK, or why an action is refused — a capability outside the envelope (R3), value without TRANSFER_VALUE (R4), a target not in the declared call set (R5), a binding outside the envelope (R6).

Source: `chainc/trustgrade.ts`

#### `PRES`

```ts
const PRES = { … } as const
```

Presentation axis: COMPUTED (rendered from on-chain interpreter output) grades A, PINNED B, LIVE C.

Source: `chainc/trustgrade.ts`

#### `DEP`

```ts
const DEP = { … } as const
```

Dependency axis: NONE / IMMUTABLE grade A, ATTESTED (content-addressed, pinned on-chain) B, UNPROVEN / MUTABLE C.

Source: `chainc/trustgrade.ts`

#### `construct`

```ts
function construct(a: WriteAction, userArgs: string[], envelope: number, allowed: Target[]): Constructed
```

Gate-check then construct the tx for signing. Returns ok=false + reason if the gate blocks it (no tx).

Source: `chainc/actionvocab.ts`

#### `word`

```ts
function word(n: bigint): string
```

Encode a bigint as a left-padded 32-byte word (for uint256 / bool user args).

Source: `chainc/actionvocab.ts`

#### `addrWord`

```ts
function addrWord(addr: string): string
```

Encode an address as a left-padded 32-byte word.

Source: `chainc/actionvocab.ts`

#### `userArgCount`

```ts
function userArgCount(a: WriteAction): number
```

How many of an action's argument slots the user fills in (source ARG.USER), as opposed to fixed by the component.

Source: `chainc/actionvocab.ts`

#### `ARG`

```ts
const ARG = { … } as const
```

Where an action argument comes from: FIXED in the component, or USER-supplied at the wallet.

Source: `chainc/actionvocab.ts`

#### `ATYPE`

```ts
const ATYPE = { … } as const
```

The argument types the closed action vocabulary can encode.

Source: `chainc/actionvocab.ts`

### Manifest / addressing

#### `buildManifest`

```ts
function buildManifest(input: AppManifestInput): BuiltManifest
```

Builds the canonical manifest bytes and app hash.

Source: `chainc/manifest.ts`

#### `capabilityNames`

```ts
function capabilityNames(bitmap: number): string[]
```

Human-readable capability names for a declared envelope, for consent/display surfaces.

Source: `chainc/manifest.ts`

### NET-NEW core primitives (doc 73 §8)

#### `grade`

```ts
function grade(node: Node, opts: GradeOptions = {}): GradeResult
```

Live, no-deploy trust grade of a component AST. Derives caps via `requiredCapabilities`, then grades as the chain does. Grade (presentation/data/dependency) and envelope (what it can touch) are orthogonal — both are returned; a WRITE component is still Grade A if it renders from computed, immutable, on-chain material.

Source: `client/grade.ts`

#### `gradeCaps`

```ts
function gradeCaps(caps: number, opts: GradeOptions = {}): GradeResult
```

Grade a capability set directly — the single source of truth `grade()` and `gradeComposition()` both call. Mirrors the seed's per-item derivation exactly, so it is drift-locked to the on-chain enforcer.

Source: `client/grade.ts`

#### `gradeComposition`

```ts
function gradeComposition(aggregatedCaps: number, opts: GradeOptions = {}): GradeResult
```

Grade a composition / app from its aggregated capability union (the honest aggregate the validator enforces — pass the composition's aggregated caps here).

Source: `client/grade.ts`

#### `aboveFloorText`

```ts
function aboveFloorText(kinds: readonly string[]): string
```

What runs above the floor, in words: "a client-side p5 sketch", "client-side reads of the viewer's own wallet and a client-side transfer history read from logs" (docs/201). The review and the builder say it the same way.

Source: `client/grade.ts`

#### `isVerifiablePinnedDep`

```ts
function isVerifiablePinnedDep(pd?: PinnedDep | null): boolean
```

Pinned-IPFS dependency → Grade B (Pinned): the drift-guarded predicate + type an app/builder/AI uses to declare an honest off-chain-but-content-addressed dependency (docs/B-GRADE-pinned-ipfs-dependency.md).

Source: `chainc/pinneddep.ts`

#### `pinnedDependencyLevel`

```ts
function pinnedDependencyLevel(pd?: PinnedDep | null): number | null
```

The dependency level a pinned dep contributes: DEP.ATTESTED (→ B) when honest, else null (leave the caller's default, i.e. IMMUTABLE → A). Fail-closed: an invalid CID never yields a silent B.

Source: `chainc/pinneddep.ts`

#### `pinnedCid`

```ts
function pinnedCid(pd?: PinnedDep | null): string
```

Pinned-IPFS dependency → Grade B (Pinned): the drift-guarded predicate + type an app/builder/AI uses to declare an honest off-chain-but-content-addressed dependency (docs/B-GRADE-pinned-ipfs-dependency.md).

Source: `chainc/pinneddep.ts`

#### `RAW_CIDV1`

```ts
const RAW_CIDV1 = /^bafkrei[a-z2-7]{52}$/
```

The ONLY re-verifiable shape: a raw CIDv1 (bafkrei…). dag-pb (Qm… / bafybe…) can't be verified in-browser.

Source: `chainc/pinneddep.ts`

#### `vocabulary`

```ts
function vocabulary(opts: { mode?: VocabMode } = {}): VocabularySchema
```

The machine-readable vocabulary. Constrains AI generation to valid IR and generates MCP tool surfaces. `{ mode: "enhanced" }` (docs/202 §16.4) adds the VERSION_5 presentation fields; the default "classic" is exactly the pre-V5 vocabulary, so an AI or tool in classic mode can never emit a tree a chain without V5 refuses.

Source: `client/vocabulary.ts`

### v0.10.0: the strict schema of compile()'s input (chainc/node-schema.ts)

#### `checkNode`

```ts
function checkNode(root: unknown, opts: { authoring?: boolean; mode?: "classic" | "enhanced" } = {}): NodeCheck
```

Check a tree against the strict schema plus the limits compile() / the interpreter enforce. Never throws. `{ authoring: true }` accepts the builder-only AUTHORING_FIELDS (slot/image argValues, image.scene, a root pinnedDep, and `_`-prefixed design-time keys) without an issue.

Source: `chainc/node-schema.ts`

#### `nodeJsonSchema`

```ts
function nodeJsonSchema(opts: { authoring?: boolean } = {}): JsonSchema
```

The strict JSON Schema (draft 2020-12) of the tree compile() consumes. The `node` def is recursive. Limits that JSON Schema cannot express (total nodes, depth, encoded byte lengths, pinnedDep only at the root) are enforced by checkNode(). `{ authoring: true }` also admits the builder-only AUTHORING_FIELDS.

Source: `chainc/node-schema.ts`

#### `fieldsOf`

```ts
function fieldsOf(type: NodeType): FieldSpec[]
```

Every field compile() reads for a node type, in emit order (type fields, then a11y, then behaviour, then the VERSION_5 presentation fields).

Source: `chainc/node-schema.ts`

#### `NODE_TYPES`

```ts
const NODE_TYPES = [ … ] as const
```

Element types (everything but `ref`).

Source: `chainc/node-schema.ts`

#### `NODE_ENUMS`

```ts
const NODE_ENUMS = { … } as const
```

compile() silently drops what it does not read (unknown fields, bad enum values, a11y on images, batch `args`); checkNode() reports each with its path, and nodeJsonSchema() is the same rules as a JSON Schema an AI tool or MCP server hands to a model. Drift-locked to compile() by tsc (`_coverage`) and by test/node-schema.ts.

Source: `chainc/node-schema.ts`

#### `TYPE_FIELDS`

```ts
const TYPE_FIELDS: Record<NodeType, FieldSpec[]> = { … }
```

Type-specific fields, in compile()'s emit order.

Source: `chainc/node-schema.ts`

#### `A11Y_FIELDS`

```ts
const A11Y_FIELDS: FieldSpec[] = [ … ]
```

Accessibility fields: every element type except `image` (which uses `alt`) and `ref`.

Source: `chainc/node-schema.ts`

#### `BEHAVIOR_FIELDS`

```ts
const BEHAVIOR_FIELDS: FieldSpec[] = [ … ]
```

Behaviour fields: every element type except `ref` (images included).

Source: `chainc/node-schema.ts`

#### `AUTHORING_FIELDS`

```ts
const AUTHORING_FIELDS = { … } as const
```

Authoring fields: read by the visual builder / grade(), never by compile(). A builder tree may carry them; a tree handed to compile() should not (the builder's encodeBindings() turns them into compiled fields or drops them). checkNode reports them as `authoring-field` unless called with `{ authoring: true }`; with it, `image.scene` is checked against SCENE_FIELDS and SCENE_BINDS (0.11.0), while argValues / pinnedDep contents stay the builder's to validate. Grounded in builder/index-next.html: - slot/image argValues the human-typed resolver args, keyed by arg name; encodeBindings() encodes them into `arg` per the kind's descriptor (abi.encode, or packed when argsEncoding says so) - image.scene the client-side sketch that runs ABOVE the on-chain floor (builder "Scene" panel) - root pinnedDep the pinned-dependency declaration grade() reads (`grade(tree, { pinnedDep: tree.pinnedDep })`) - any `_`-prefixed key design-time metadata (`_multiview`, `_view`, `_mvId` for multi-view tabs) 0.10.0 listed only image.scene and root pinnedDep, so a builder tree with argValues was wrongly flagged.

Source: `chainc/node-schema.ts`

#### `AUTHORING_PREFIX`

```ts
const AUTHORING_PREFIX = "_"
```

Keys starting with this prefix are builder design-time metadata on any element (see AUTHORING_FIELDS).

Source: `chainc/node-schema.ts`

#### `SCENE_FIELDS`

```ts
const SCENE_FIELDS: FieldSpec[] = [ … ]
```

The fields of `image.scene`, exactly as the builder's Scene panel and rich-media deploy read them (builder/index-next.html). An empty string means "not set" for seed / libHash / entry, as in the builder's inputs. At deploy the builder stores `source` in SourceStore (chunked if large) and registers the scene in SceneComponentRegistry with the binding (libHash, seed, SourceStore id[, app metadata]) — see chainc/depscene.ts.

Source: `chainc/node-schema.ts`

#### `SCENE_BINDS`

```ts
const SCENE_BINDS = [ … ] as const
```

The `bind` values that make an image's `scene` a rich-media sketch. The builder only treats `image.scene` as a sketch when the image's `bind` is one of these (builder/index-next.html: findScene / runAboveFloorPreview / the rich-media deploy all test `bind === "p5" || bind === "three"`).

Source: `chainc/node-schema.ts`

#### `IGNORED_BY_COMPILE`

```ts
const IGNORED_BY_COMPILE: Partial<Record<NodeType, string[]>> = { … }
```

Fields the TypeScript `Node` type allows but compile() never encodes. The checker reports them; the runtime drift test proves compile() really ignores them (setting one leaves the bytes unchanged).

Source: `chainc/node-schema.ts`

#### `IGNORED_NESTED`

```ts
const IGNORED_NESTED: Record<string, string[]> = { … }
```

Nested fields the type allows but compile() drops: a batch member's `args` is not part of the encoded `to|sig|value|label` member, so it never reaches the wallet.

Source: `chainc/node-schema.ts`

#### `NODE_LIMITS`

```ts
const LIMITS = { … } as const  (exported as NODE_LIMITS)
```

compile() silently drops what it does not read (unknown fields, bad enum values, a11y on images, batch `args`); checkNode() reports each with its path, and nodeJsonSchema() is the same rules as a JSON Schema an AI tool or MCP server hands to a model. Drift-locked to compile() by tsc (`_coverage`) and by test/node-schema.ts.

Source: `chainc/node-schema.ts`

### v0.16.0: one review for every surface (client/review.ts, docs/190)

#### `reviewTree`

```ts
function reviewTree(tree: unknown, opts: ReviewOptions = {}): Review
```

Review a tree: check + grade + compile + honesty, and the pass/fail verdict every surface reports.

Source: `client/review.ts`

#### `reviewText`

```ts
function reviewText(r: Review, title = "ChainRender review"): string
```

The review as plain text — what the builder's "Copy for AI" button and the command line print. An AI that cannot run the review itself is given this text, and fixes what it lists.

Source: `client/review.ts`

### v0.14.0: honesty and privacy findings (chainc/honesty.ts, docs/188)

#### `honestyFindings`

```ts
function honestyFindings(root: unknown, opts: HonestyOptions = {}): HonestyFinding[]
```

Honesty and privacy findings for a Node tree. Empty array = nothing to fix.

Source: `chainc/honesty.ts`

#### `publicInputNames`

```ts
function publicInputNames(args: string | readonly string[] | undefined | null): string[]
```

The `$name` placeholders in an action's args — a comma-separated template ("$amount,0xabc…") or a list.

Source: `chainc/honesty.ts`

#### `publicInputNotice`

```ts
function publicInputNotice(names: readonly string[]): string
```

The sign-panel line for an action whose args take these input names; "" when it takes none.

Source: `chainc/honesty.ts`

#### `PUBLIC_INPUT_NOTICE`

```ts
const PUBLIC_INPUT_NOTICE = "Values you enter here become public on-chain, permanently: anyone can read them."
```

The line every surface that signs an action with typed-in values shows (viewer sign panel, apps, AI-built UIs).

Source: `chainc/honesty.ts`

#### `ONCHAIN_P5_VERSION`

```ts
const ONCHAIN_P5_VERSION = "2.3.2"
```

The p5 every ChainRender chain registers in its DependencyRegistry (deployment/genesis-libraries*.json: p5@2.3.2 is the only p5 on Sepolia, Robinhood and Arc).

Source: `chainc/honesty.ts`

#### `p5V1ApiUses`

```ts
function p5V1ApiUses(source: string):
```

Where a p5 sketch uses the p5 1.x API the on-chain p5 2.3.2 does not have. Each item: what, the line (1-based, in the sketch source) of its first use, how many uses, and the 2.x replacement. Empty = none found.

Source: `chainc/honesty.ts`

#### `signMessageProblems`

```ts
function signMessageProblems(sign: AnyNode): string[]
```

What is wrong with an EIP-712 `sign` object's message: a `$name` (never substituted), or a value that does not fit its declared type (address, bool, uintN/intN, bytesN, string; nested struct types are followed). Empty = fine.

Source: `chainc/honesty.ts`

### v0.20.0: VERSION_5 presentation — style tokens, hints, lang/dir, heading levels, WAI-ARIA roles (docs/202)

#### `STYLE_FAMILIES`

```ts
const STYLE_FAMILIES: readonly StyleFamily[] = [ … ] as const
```

Enhanced mode only: compile(tree, { mode: "enhanced" }) / compileComponent(tree, { mode: "enhanced" }) / checkNode(tree, { mode: "enhanced" }) / reviewTree(tree, { mode: "enhanced" }) / vocabulary({ mode: "enhanced" }). The default (classic) is exactly the pre-V5 behaviour. VERSION_5 renders only where the chain's RenderRouter.interpreterFor(5) is the V5 HTML interpreter (doc 202 phase 2).

Source: `chainc/style-tokens.ts`

#### `STYLE_TOKENS`

```ts
const STYLE_TOKENS: ReadonlyMap<string, StyleFamily> = new Map(STYLE_FAMILIES.flatMap((f) => f.values.map((v) => [f.token(v), f] as const)))
```

Every registered token, by token string -> its family.

Source: `chainc/style-tokens.ts`

#### `STYLE_TOKEN_RE`

```ts
const STYLE_TOKEN_RE = /^[a-z][a-z0-9]{0,15}(-[a-z0-9]{1,15}){0,3}$/
```

One wire token: a lowercase word, then up to three -segments. docs/202 §4.1 (the V5 interpreter enforces the same).

Source: `chainc/style-tokens.ts`

#### `STYLE_REGISTRY_VERSION`

```ts
const STYLE_REGISTRY_VERSION = 1
```

Enhanced mode only: compile(tree, { mode: "enhanced" }) / compileComponent(tree, { mode: "enhanced" }) / checkNode(tree, { mode: "enhanced" }) / reviewTree(tree, { mode: "enhanced" }) / vocabulary({ mode: "enhanced" }). The default (classic) is exactly the pre-V5 behaviour. VERSION_5 renders only where the chain's RenderRouter.interpreterFor(5) is the V5 HTML interpreter (doc 202 phase 2).

Source: `chainc/style-tokens.ts`

#### `styleFamily`

```ts
const styleFamily = (name: string): StyleFamily | undefined => …
```

Enhanced mode only: compile(tree, { mode: "enhanced" }) / compileComponent(tree, { mode: "enhanced" }) / checkNode(tree, { mode: "enhanced" }) / reviewTree(tree, { mode: "enhanced" }) / vocabulary({ mode: "enhanced" }). The default (classic) is exactly the pre-V5 behaviour. VERSION_5 renders only where the chain's RenderRouter.interpreterFor(5) is the V5 HTML interpreter (doc 202 phase 2).

Source: `chainc/style-tokens.ts`

#### `styleFamiliesFor`

```ts
const styleFamiliesFor = (type: NodeType): StyleFamily[] => …
```

Enhanced mode only: compile(tree, { mode: "enhanced" }) / compileComponent(tree, { mode: "enhanced" }) / checkNode(tree, { mode: "enhanced" }) / reviewTree(tree, { mode: "enhanced" }) / vocabulary({ mode: "enhanced" }). The default (classic) is exactly the pre-V5 behaviour. VERSION_5 renders only where the chain's RenderRouter.interpreterFor(5) is the V5 HTML interpreter (doc 202 phase 2).

Source: `chainc/style-tokens.ts`

#### `styleStringOf`

```ts
function styleStringOf(node: { type: string } & Record<string, unknown>): string | undefined
```

The ATTR.STYLE string for a node: its family fields in registry order, then raw `style` tokens (sorted, de-duplicated, grammar-valid only). Deterministic, so the same tree always gives the same hash. Families not allowed on the node's type and values not in the family are left out (checkNode reports them). Returns undefined when there are none.

Source: `chainc/style-tokens.ts`

#### `isValidStyleList`

```ts
function isValidStyleList(s: string): boolean
```

Whether a wire style list passes the V5 grammar (what the interpreter checks; anything else is dropped whole).

Source: `chainc/style-tokens.ts`

#### `structureCss`

```ts
function structureCss(opts: { scope?: string } = {}): string
```

The structure CSS: one rule per token, the heading levels, the app container. Only elements carrying `cr-t` or `aria-level` (VERSION_5 output) match, so it has no effect on V2–V4 apps. `scope` is the app root's selector.

Source: `chainc/style-tokens.ts`

#### `structureCssProblems`

```ts
function structureCssProblems(css: string): string[]
```

What the honesty rules (docs/202 §11) forbid in the structure CSS. Empty = fine. Exceptions are by name: overflow only in the scroll family, content only as "" (marker shapes), a literal colour only as a var() fallback, font sizes only as max(12px, calc(var(--cr-…) * k)) with k >= FONT_FLOOR.

Source: `chainc/style-tokens.ts`

#### `STRUCTURE_SCOPE`

```ts
const STRUCTURE_SCOPE = ".cr-root"
```

The default app root the structure CSS is scoped to (the SDK themes and the builder preview use `.cr-root`).

Source: `chainc/style-tokens.ts`

#### `styleRegistry`

```ts
function styleRegistry()
```

For vocabulary({ mode: "enhanced" }) and the docs.

Source: `chainc/style-tokens.ts`

#### `HINTS`

```ts
const HINTS: readonly HintSpec[] = [ … ]
```

_No doc comment in the source._

Source: `chainc/hints.ts`

#### `HINTS_REGISTRY_VERSION`

```ts
const HINTS_REGISTRY_VERSION = 1
```

_No doc comment in the source._

Source: `chainc/hints.ts`

#### `hintSpec`

```ts
const hintSpec = (key: string): HintSpec | undefined => …
```

_No doc comment in the source._

Source: `chainc/hints.ts`

#### `hintStringOf`

```ts
function hintStringOf(hints: unknown): string | undefined
```

The ATTR.HINTS string for a node's `hints` object: known keys in registry order, then other grammar-valid keys sorted. Pairs whose key or value break the grammar are left out (checkNode reports them). Undefined when there are none.

Source: `chainc/hints.ts`

#### `hintProblems`

```ts
function hintProblems(type: NodeType, hints: unknown): string[]
```

Problems with a node's hints (empty = fine): grammar, unknown keys, wrong node type, values that do not fit.

Source: `chainc/hints.ts`

#### `hintRegistry`

```ts
function hintRegistry()
```

_No doc comment in the source._

Source: `chainc/hints.ts`

#### `presentationFieldsOf`

```ts
function presentationFieldsOf(type: NodeType): FieldSpec[]
```

VERSION_5 presentation fields for a node type (docs/202), in compile()'s emit order: the style families its type allows (chainc/style-tokens.ts), raw `style`, `hints`, `lang`, `dir`, and `level` (not on images). Each opts the component into VERSION_5.

Source: `chainc/node-schema.ts`

#### `PRESENTATION_KEYS`

```ts
const PRESENTATION_KEYS = [ … ] as const
```

Runtime half (test/style-tokens.ts): equals the registry's families + style/hints/lang/dir/level.

Source: `chainc/node-schema.ts`

#### `presentationFindings`

```ts
function presentationFindings(tree: unknown, opts: PresentationReviewOptions = {}): PresentationFinding[]
```

_No doc comment in the source._

Source: `client/presentation-review.ts`

#### `PRESENTATION_RULES`

```ts
const PRESENTATION_RULES: readonly { rule: PresentationRule; severity: "warn" | "error"; when: string }[] = [ … ]
```

For the docs and the builder: the rules and what each checks.

Source: `client/presentation-review.ts`

#### `THEME_LABEL_HOOKS`

```ts
const THEME_LABEL_HOOKS: readonly string[] = [ … ]
```

The aria-label values the default theme styles by (a frozen list for existing hashes, docs/202 §1.2, §12) that read as machine names: lowercase ("dash-row", "alert-*", "tooltip"). The capitalised ones the theme also matches ("Addresses", "Ownership", "Records") are real names a person would give the element, so they are not flagged.

Source: `client/presentation-review.ts`

### v0.19.0: the viewer's own wallet data and transfer histories (chainc/viewer-context.ts, docs/201)

#### `VIEWER_PLACEHOLDER`

```ts
const VIEWER_PLACEHOLDER = "$viewer"
```

The placeholder an author writes for the viewer's own address.

Source: `chainc/viewer-context.ts`

#### `VIEWER_KINDS`

```ts
const VIEWER_KINDS: readonly ViewerKind[] = [ … ]
```

A viewer read is a client slot whose account arg is "$viewer"; a transfer history is a client slot bound to "transfers". The on-chain render shows their fallback text to everyone; a ChainRender viewer fills them only after the person chooses to show their own data, with this chain's published resolvers (⚙ above the floor).

Source: `chainc/viewer-context.ts`

#### `VIEWER_READS`

```ts
const VIEWER_READS = { … } as const
```

For vocabulary(): what an author (or an AI) needs to write one.

Source: `chainc/viewer-context.ts`

#### `VIEWER_FALLBACK`

```ts
const VIEWER_FALLBACK = "Connect your wallet to see this"
```

What a viewer slot shows until the person chooses to show their data (the builder uses it when content is empty).

Source: `chainc/viewer-context.ts`

#### `HISTORY_BIND`

```ts
const HISTORY_BIND = "transfers"
```

The bind of a transfer-history slot.

Source: `chainc/viewer-context.ts`

#### `HISTORY_KINDS`

```ts
const HISTORY_KINDS = [ … ] as const
```

ChainRenderFeed kinds a history may read (no raw `logs`, and no chain-wide `transfers` mix).

Source: `chainc/viewer-context.ts`

#### `HISTORY_LIMITS`

```ts
const HISTORY_LIMITS = { … } as const
```

A viewer read is a client slot whose account arg is "$viewer"; a transfer history is a client slot bound to "transfers". The on-chain render shows their fallback text to everyone; a ChainRender viewer fills them only after the person chooses to show their own data, with this chain's published resolvers (⚙ above the floor).

Source: `chainc/viewer-context.ts`

#### `HISTORY_FALLBACK`

```ts
const HISTORY_FALLBACK = "Recent transfers load in a ChainRender viewer"
```

A viewer read is a client slot whose account arg is "$viewer"; a transfer history is a client slot bound to "transfers". The on-chain render shows their fallback text to everyone; a ChainRender viewer fills them only after the person chooses to show their own data, with this chain's published resolvers (⚙ above the floor).

Source: `chainc/viewer-context.ts`

#### `VIEWER_HISTORY_FALLBACK`

```ts
const VIEWER_HISTORY_FALLBACK = "Connect your wallet to see your recent transfers"
```

A viewer read is a client slot whose account arg is "$viewer"; a transfer history is a client slot bound to "transfers". The on-chain render shows their fallback text to everyone; a ChainRender viewer fills them only after the person chooses to show their own data, with this chain's published resolvers (⚙ above the floor).

Source: `chainc/viewer-context.ts`

#### `SAMPLE_ACCOUNT`

```ts
const SAMPLE_ACCOUNT = "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045"
```

The address the builder previews viewer slots with when no wallet is connected — labelled a sample everywhere.

Source: `chainc/viewer-context.ts`

#### `viewerFallback`

```ts
function viewerFallback(node: unknown): string | null
```

The fallback text (the floor) a viewer slot shows to everyone until the viewer fills it.

Source: `chainc/viewer-context.ts`

#### `viewerKind`

```ts
const viewerKind = (kind: unknown): ViewerKind | undefined => …
```

A viewer read is a client slot whose account arg is "$viewer"; a transfer history is a client slot bound to "transfers". The on-chain render shows their fallback text to everyone; a ChainRender viewer fills them only after the person chooses to show their own data, with this chain's published resolvers (⚙ above the floor).

Source: `chainc/viewer-context.ts`

#### `viewerReadArg`

```ts
function viewerReadArg(kind: string, values: Record<string, unknown>): string
```

The client-slot arg for a viewer read: `cr:viewer;token=0x…;account=$viewer`. Throws on anything the viewer would refuse.

Source: `chainc/viewer-context.ts`

#### `historyArg`

```ts
function historyArg(values: Record<string, unknown>): string
```

The client-slot arg for a transfer history: `cr:history;kind=token-transfers;account=$viewer;token=0x…;blocks=5000;limit=20`.

Source: `chainc/viewer-context.ts`

#### `parseCrArg`

```ts
function parseCrArg(text: unknown): CrArg
```

Parses a `cr:` arg. Strict: one mode, known keys, no repeats, bounded. Does not check the fields against a kind.

Source: `chainc/viewer-context.ts`

#### `viewerReadProblems`

```ts
function viewerReadProblems(kind: unknown, fields: Record<string, unknown>): string[]
```

Problems with a viewer read for `kind` given its fields (empty = fine).

Source: `chainc/viewer-context.ts`

#### `historyProblems`

```ts
function historyProblems(fields: Record<string, unknown>): string[]
```

Problems with a transfer history's fields (empty = fine).

Source: `chainc/viewer-context.ts`

#### `viewerNodeMode`

```ts
function viewerNodeMode(node: unknown): "viewer" | "history" | null
```

Whether argValues (or an already-encoded arg) make this node a viewer read or a transfer history.

Source: `chainc/viewer-context.ts`

### v0.11.0: presentation context (render-time theme / palette / size, doc 106)

#### `presentationContext`

```ts
function presentationContext(o: { themeId?: `0x${string}`; palette?: ContextPalette; // chart/image palette override tokens?: ThemeTokens; // OR derive the palette from a full token set chartW?: number; chartH?: number; overrideTokens?: ThemeTokens; // doc 109: full token override (regenerates component CSS at render time) ext?: `0x${string}`; }): PresentationContext
```

Build a present context from optional overrides — the viewer's ergonomic entry (theme/palette/dims).

Source: `chainc/presentation-context.ts`

#### `emptyContext`

```ts
function emptyContext(): PresentationContext
```

The empty context — everything falls back to the component's baked defaults (== renderHash behavior).

Source: `chainc/presentation-context.ts`

#### `PRESENTATION_CONTEXT_ABI`

```ts
const PRESENTATION_CONTEXT_ABI = { … } as const
```

The ABI tuple for PresentationContextLib.Context — field order MUST match the Solidity struct exactly.

Source: `chainc/presentation-context.ts`

#### `PRESENTATION_CONTEXT_VERSION`

```ts
const PRESENTATION_CONTEXT_VERSION = 1
```

Build the context renderComponentWithContext() (@chainrender/client/runtime) passes to RenderRouter.renderHashWithContext. Skin only: never identity, behaviour or grade.

Source: `chainc/presentation-context.ts`

### v0.11.0: rich-media scene binding (chainc/depscene.ts)

#### `encodeSceneBinding`

```ts
function encodeSceneBinding(b: SceneBinding): `0x${string}`
```

abi-encode a binding: 3 fields, or 4 when `meta` is a non-empty string (the builder's rich-media deploy form).

Source: `chainc/depscene.ts`

#### `decodeSceneBinding`

```ts
function decodeSceneBinding(kind: SceneKind, value: `0x${string}`): SceneBinding
```

Decode either form; `meta` is present only for a 4-field binding.

Source: `chainc/depscene.ts`

#### `sceneIdOf`

```ts
function sceneIdOf(floorContract: `0x${string}`, floorSelector: `0x${string}`, seed: `0x${string}`, binding: `0x${string}`): `0x${string}`
```

SceneComponentRegistry.idOf: keccak256(abi.encode(floorContract, floorSelector, seed, binding)).

Source: `chainc/depscene.ts`

#### `sceneNamespaceId`

```ts
const namespaceId = (kind: SceneKind): `0x${string}` => …  (exported as sceneNamespaceId)
```

namespace id the ComponentAnnotationRegistry keys on (keccak of the namespace string)

Source: `chainc/depscene.ts`

#### `SCENE_NS`

```ts
const SCENE_NS = { … } as const
```

The binding a p5/three app carries: the on-chain library by DependencyRegistry hash, the seed, and the sketch (a SourceStore id once deployed), optionally with app metadata — exactly what the builder's rich-media deploy registers in SceneComponentRegistry. Previously documented but not exported.

Source: `chainc/depscene.ts`

#### `SCENE_FLOOR_SELECTORS`

```ts
const SCENE_FLOOR_SELECTORS = { … } as const
```

The on-chain floors SceneFloor ships (contracts/SceneFloor.sol), by name → 4-byte selector. A registered scene's floor is `floorContract.<selector>(seed)`; the builder's rich-media deploy uses `sigil`.

Source: `chainc/depscene.ts`

### First-party on-chain resolver kinds (oracle feeds, selective-disclosure credentials)

#### `kinds` (namespace)

Not part of the closed tag vocabulary — the resolver mechanism is extensible — but the kinds ChainRender ships as first-party, surfaced with their KIND constants + arg encoders (re-exported from the drift-locked mirrors) so an app, a builder, an MCP server, or an AI can discover and encode them. Also in vocabulary().resolverKinds.

Source: `chainc/resolverkinds.ts`

| Member | Signature | Summary |
|---|---|---|
| `kinds.oracle` | namespace | chainc mirror for OracleFeedResolver — the binding kind + argument encoding, drift-locked against the on-chain resolver (see test/oracle.ts). |
| `kinds.oracle.KIND_FEED` | `const KIND_FEED = stringToHex("oracle-feed", { size: 32 })` | Binding kind, right-padded into bytes32 — mirrors OracleFeedResolver.KIND_FEED. |
| `kinds.oracle.encodeFeedArgs` | `function encodeFeedArgs(a: FeedArgs): '0x${string}'` | abi.encode(address feed, uint8 fracDigits, uint256 maxStaleSeconds) — the resolver's args layout. |
| `kinds.credential` | namespace | chainc mirror for CredentialResolver — the binding kind, the MVP statement id, and the argument encoding, drift-locked against the on-chain resolver (see test/credential.ts). |
| `kinds.credential.KIND_CREDENTIAL` | `const KIND_CREDENTIAL = stringToHex("credential", { size: 32 })` | Binding kind, right-padded into bytes32 — mirrors CredentialResolver.KIND_CREDENTIAL. |
| `kinds.credential.STMT_MEMBER_OF_SET` | `const STMT_MEMBER_OF_SET = stringToHex("member-of-set", { size: 32 })` | MVP statement id — "the prover is a member of the set with this public root", revealing nothing about which member. |
| `kinds.credential.encodeCredentialArgs` | `function encodeCredentialArgs(x: CredentialArgs): '0x${string}'` | abi.encode(bytes32 statementId, uint256[2] a, uint256[2][2] b, uint256[2] c, uint256[] pub) — the resolver's args layout. |
| `kinds.credentialBound` | namespace | chainc mirror for BoundCredentialResolver + NullifierRegistry — the binding kind, the statement id, and the argument encoding, drift-locked against the on-chain contracts (see test/credential-bound.ts). |
| `kinds.credentialBound.KIND_CREDENTIAL_BOUND` | `const KIND_CREDENTIAL_BOUND = stringToHex("credential-bound", { size: 32 })` | Binding kind, right-padded into bytes32 — mirrors BoundCredentialResolver.KIND_CREDENTIAL_BOUND. |
| `kinds.credentialBound.STMT_MEMBER_BOUND` | `const STMT_MEMBER_BOUND = stringToHex("member-bound", { size: 32 })` | Statement id for the bound, single-use member-of-set credential. |
| `kinds.credentialBound.BOUND_PUBLIC_ORDER` | `const BOUND_PUBLIC_ORDER = [ … ] as const` | Public-signal layout of the bound statement (nPublic === 4), in snarkjs order. |
| `kinds.credentialBound.encodeBoundCredentialArgs` | `function encodeBoundCredentialArgs(x: BoundCredentialArgs): '0x${string}'` | abi.encode(bytes32 statementId, uint256[2] a, uint256[2][2] b, uint256[2] c, uint256[4] pub) — mirrors BoundCredentialResolver._verify's abi.decode. |
| `kinds.ens` | namespace | chainc/ens.ts — first-party ENS resolver kinds, mirrored + drift-locked to EnsRecordResolver.sol and EnsV2Resolver.sol. |
| `kinds.ens.KIND_ADDR` | `const KIND_ADDR = stringToHex("ensAddr", { size: 32 })` | bytes32 KIND constants — mirror the on-chain resolvers. |
| `kinds.ens.KIND_TEXT` | `const KIND_TEXT = stringToHex("ensText", { size: 32 })` |  |
| `kinds.ens.KIND_NAME` | `const KIND_NAME = stringToHex("ensName", { size: 32 })` |  |
| `kinds.ens.KIND_ENS_V2` | `const KIND_ENS_V2 = stringToHex("ensV2", { size: 32 })` |  |
| `kinds.ens.encodeAddrArgs` | `function encodeAddrArgs(node: '0x${string}'): '0x${string}'` | node is the ENS namehash (bytes32). |
| `kinds.ens.encodeTextArgs` | `function encodeTextArgs(node: '0x${string}', key: string): '0x${string}'` |  |
| `kinds.ens.encodeNameArgs` | `function encodeNameArgs(who: '0x${string}'): '0x${string}'` | ensName takes the ACCOUNT ADDRESS as exactly 20 raw bytes — not a namehash and not a 32-byte abi.encode. |
| `kinds.ens.SEL_ADDR` | `const SEL_ADDR = "0x3b3b57de" as const` | addr(bytes32) selector — the `inner` call for an address record. |
| `kinds.ens.SEL_TEXT` | `const SEL_TEXT = "0x59d1d43c" as const` | text(bytes32,string) selector — the `inner` call for a text record. |
| `kinds.ens.v2AddrCall` | `function v2AddrCall(node: '0x${string}'): '0x${string}'` | The `inner` record call for ensV2: addr(node). |
| `kinds.ens.v2TextCall` | `function v2TextCall(node: '0x${string}', key: string): '0x${string}'` | The `inner` record call for ensV2: text(node, key). |
| `kinds.ens.encodeV2Args` | `function encodeV2Args(resolver: '0x${string}', inner: '0x${string}', isText: boolean): '0x${string}'` | ensV2 args: abi.encode(address resolver, bytes inner, bool isText). |
| `kinds.attestation` | namespace | chainc/attestation.ts — first-party identity/attestation resolver kinds, mirrored + drift-locked to IdentityResolver.sol. |
| `kinds.attestation.KIND_VERIFIED` | `const KIND_VERIFIED = stringToHex("identityVerified", { size: 32 })` |  |
| `kinds.attestation.KIND_CLAIM` | `const KIND_CLAIM = stringToHex("identityClaim", { size: 32 })` |  |
| `kinds.attestation.encodeVerifiedArgs` | `function encodeVerifiedArgs(subject: '0x${string}', schema: '0x${string}', uid: '0x${string}'): '0x${string}'` |  |
| `kinds.attestation.encodeClaimArgs` | `function encodeClaimArgs(uid: '0x${string}', schema: '0x${string}', subject: '0x${string}'): '0x${string}'` |  |
| `kinds.por` | namespace | chainc mirror for ProofOfReserveResolver — binding kinds + argument encoding, drift-locked against the on-chain resolver (contracts/examples/ProofOfReserveResolver.sol, docs/131). |
| `kinds.por.KIND_RESERVES` | `const KIND_RESERVES = stringToHex("por-reserves", { size: 32 })` | Binding kinds, right-padded into bytes32 — mirror ProofOfReserveResolver.KIND_*. |
| `kinds.por.KIND_SUPPLY` | `const KIND_SUPPLY = stringToHex("por-supply", { size: 32 })` |  |
| `kinds.por.KIND_COVERAGE` | `const KIND_COVERAGE = stringToHex("por-coverage", { size: 32 })` |  |
| `kinds.por.encodePorArgs` | `function encodePorArgs(a: PorArgs): '0x${string}'` | abi.encode(address reserveFeed, address token, uint8 fracDigits, uint256 maxStaleSeconds) — all three kinds. |
| `kinds.erc3643` | namespace | chainc mirror for Erc3643PermissionAdapter — binding kinds + argument encoding, drift-locked against the on-chain adapter (contracts/examples/Erc3643PermissionAdapter.sol, docs/133). |
| `kinds.erc3643.KIND_VERIFIED` | `const KIND_VERIFIED = stringToHex("erc3643-verified", { size: 32 })` | Binding kinds, right-padded into bytes32 — mirror Erc3643PermissionAdapter.KIND_*. |
| `kinds.erc3643.KIND_FROZEN` | `const KIND_FROZEN = stringToHex("erc3643-frozen", { size: 32 })` |  |
| `kinds.erc3643.KIND_STATUS` | `const KIND_STATUS = stringToHex("erc3643-status", { size: 32 })` |  |
| `kinds.erc3643.KIND_CANTX` | `const KIND_CANTX = stringToHex("erc3643-can-transfer", { size: 32 })` |  |
| `kinds.erc3643.encodeHolderArgs` | `function encodeHolderArgs(a: HolderArgs): '0x${string}'` | abi.encode(address token, address holder) — for erc3643-verified / -frozen / -status. |
| `kinds.erc3643.encodeCanTransferArgs` | `function encodeCanTransferArgs(a: CanTransferArgs): '0x${string}'` | abi.encode(address token, address from, address to, uint256 amount) — for erc3643-can-transfer. |
| `kinds.credlife` | namespace | chainc mirror for CredentialLifecycleResolver — binding kinds + argument encoding, drift-locked against the on-chain resolver (contracts/examples/CredentialLifecycleResolver.sol, docs/134). |
| `kinds.credlife.KIND_STATUS` | `const KIND_STATUS = stringToHex("cred-status", { size: 32 })` | Binding kinds, right-padded into bytes32 — mirror CredentialLifecycleResolver.KIND_*. |
| `kinds.credlife.KIND_VALID` | `const KIND_VALID = stringToHex("cred-valid", { size: 32 })` |  |
| `kinds.credlife.encodeCredLifecycleArgs` | `function encodeCredLifecycleArgs(a: CredLifecycleArgs): '0x${string}'` | abi.encode(address registry, bytes32 credentialId, address expectedIssuer) — both kinds. |
| `kinds.efp` | namespace | chainc mirror for EfpResolver — binding kinds + argument encoding, drift-locked against the on-chain resolver (contracts/examples/EfpResolver.sol, docs/149). |
| `kinds.efp.KIND_FOLLOWS` | `const KIND_FOLLOWS = stringToHex("efp-follows", { size: 32 })` | Binding kinds, right-padded into bytes32 — mirror EfpResolver.KIND_*. |
| `kinds.efp.KIND_TAG` | `const KIND_TAG = stringToHex("efp-tag", { size: 32 })` |  |
| `kinds.efp.KIND_STATE` | `const KIND_STATE = stringToHex("efp-state", { size: 32 })` |  |
| `kinds.efp.KIND_LIST_SIZE` | `const KIND_LIST_SIZE = stringToHex("efp-list-size", { size: 32 })` |  |
| `kinds.efp.encodeForwardArgs` | `function encodeForwardArgs(a: ForwardArgs): '0x${string}'` | abi.encode(address listRecords, uint256 slot, address target) — for efp-follows / efp-state. |
| `kinds.efp.encodeTagArgs` | `function encodeTagArgs(a: TagArgs): '0x${string}'` | abi.encode(address listRecords, uint256 slot, address target, string tag) — for efp-tag. |
| `kinds.efp.encodeListSizeArgs` | `function encodeListSizeArgs(a: ListSizeArgs): '0x${string}'` | abi.encode(address listRecords, uint256 slot) — for efp-list-size (raw op count; NOT a follower count). |
| `kinds.addressrep` | namespace | chainc mirror for AddressReputationResolver — binding kinds + argument encoding, drift-locked against the on-chain resolver (contracts/examples/AddressReputationResolver.sol) and its registry (AddressAttestationRegistry.sol, docs/149). |
| `kinds.addressrep.KIND_VOUCH` | `const KIND_VOUCH = stringToHex("rep-vouch", { size: 32 })` | Binding kinds, right-padded into bytes32 — mirror AddressReputationResolver.KIND_*. |
| `kinds.addressrep.KIND_TALLY` | `const KIND_TALLY = stringToHex("rep-tally", { size: 32 })` |  |
| `kinds.addressrep.topic` | `function topic(label: string): '0x${string}'` | Encode a caller-chosen topic label as bytes32 (e.g. |
| `kinds.addressrep.encodeVouchArgs` | `function encodeVouchArgs(a: VouchArgs): '0x${string}'` | abi.encode(address registry, address attester, address subject, bytes32 topic) — for rep-vouch. |
| `kinds.addressrep.encodeTallyArgs` | `function encodeTallyArgs(a: TallyArgs): '0x${string}'` | abi.encode(address registry, address[] attesters, address subject, bytes32 topic) — for rep-tally. |
| `kinds.repagg` | namespace | chainc mirror for ReputationAggregateResolver — binding kind + argument encoding, drift-locked against the on-chain resolver (contracts/examples/ReputationAggregateResolver.sol, docs/149). |
| `kinds.repagg.KIND_AGGREGATE` | `const KIND_AGGREGATE = stringToHex("rep-aggregate", { size: 32 })` | Binding kind, right-padded into bytes32 — mirror ReputationAggregateResolver.KIND_AGGREGATE. |
| `kinds.repagg.encodeAggregateArgs` | `function encodeAggregateArgs(a: AggregateArgs): '0x${string}'` | abi.encode(address subject, address[] sources, bytes[] ctxs) — for rep-aggregate. |
| `kinds.repagg.encodeEfpSourceCtx` | `function encodeEfpSourceCtx(a: { listRecords: '0x${string}'; slot: bigint; requiredTag?: string; // "" (default) => follow alone is the signal excludeBlockedMuted?: boolean; // default false }): '0x${string}'` | ctx for an EfpReputationSource: abi.encode(address listRecords, uint256 slot, string requiredTag, bool excludeBlockedMuted). |
| `kinds.repagg.encodeVouchSourceCtx` | `function encodeVouchSourceCtx(a: { registry: '0x${string}'; attester: '0x${string}'; topic: '0x${string}'; // bytes32 (use addressreputation.topic() to build from a string) }): '0x${string}'` | ctx for a VouchReputationSource: abi.encode(address registry, address attester, bytes32 topic). |
| `kinds.ccip` | namespace | chainc mirror for CcipResolver — binding kinds + argument encoding, drift-locked against the on-chain resolver (contracts/examples/CcipResolver.sol, docs/154/155). |
| `kinds.ccip.KIND_SUPPORTED` | `const KIND_SUPPORTED = stringToHex("ccip-supported", { size: 32 })` | Binding kinds, right-padded into bytes32 — mirror CcipResolver.KIND_*. |
| `kinds.ccip.KIND_FEE` | `const KIND_FEE = stringToHex("ccip-fee", { size: 32 })` |  |
| `kinds.ccip.encodeSupportedArgs` | `function encodeSupportedArgs(a: SupportedArgs): '0x${string}'` | abi.encode(address router, uint64 destSelector) — for ccip-supported. |
| `kinds.ccip.encodeFeeArgs` | `function encodeFeeArgs(a: FeeArgs): '0x${string}'` | abi.encode(address router, uint64 destSelector, address feeToken, address receiver, uint256 gasLimit, uint8 feeDecimals, uint8 fracDigits) — for ccip-fee. |
| `kinds.messaging` | namespace | chainc/messaging.ts — first-party MESSAGING + note-privacy resolver kinds and client-side decoders, mirrored + drift-locked to the on-chain resolvers (contracts/examples/Sig1271Resolver.sol, StealthMetaResolver.sol, ShieldedPoolViewResolver.sol) and grounded in the authoritative specs (ERC-1271, ERC-6538/5564, ERC-3722, EIP-712; see docs/157). |
| `kinds.messaging.KIND_SIG_1271` | `const KIND_SIG_1271 = stringToHex("sig-1271", { size: 32 })` | ───────────────────────────────────────────────────────────────────────────────────────────────────────────── Binding kinds, right-padded into bytes32 — mirror the on-chain KIND_* constants (≤ 32 ASCII chars each). |
| `kinds.messaging.KIND_STEALTH_META` | `const KIND_STEALTH_META = stringToHex("stealth-meta", { size: 32 })` |  |
| `kinds.messaging.KIND_SHIELDED_ROOT` | `const KIND_SHIELDED_ROOT = stringToHex("shielded-root", { size: 32 })` |  |
| `kinds.messaging.KIND_SHIELDED_SET` | `const KIND_SHIELDED_SET = stringToHex("shielded-set", { size: 32 })` |  |
| `kinds.messaging.KIND_SHIELDED_NULLIFIER` | `const KIND_SHIELDED_NULLIFIER = stringToHex("shielded-nullifier", { size: 32 })` |  |
| `kinds.messaging.KIND_MSG_712` | `const KIND_MSG_712 = stringToHex("msg-712", { size: 32 })` | client-side / off-chain kinds (≤ C by construction — see the render/adapter helpers below) |
| `kinds.messaging.KIND_POSTER_FEED` | `const KIND_POSTER_FEED = stringToHex("poster-feed", { size: 32 })` |  |
| `kinds.messaging.KIND_STEALTH_SCAN` | `const KIND_STEALTH_SCAN = stringToHex("stealth-scan", { size: 32 })` |  |
| `kinds.messaging.encodeSig1271Args` | `function encodeSig1271Args(account: '0x${string}', hash: '0x${string}', signature: '0x${string}'): '0x${string}'` | abi.encode(address account, bytes32 hash, bytes signature) — for sig-1271. |
| `kinds.messaging.encodeStealthMetaArgs` | `function encodeStealthMetaArgs(registry: '0x${string}', registrant: '0x${string}', schemeId: bigint = 1n,): '0x${string}'` | abi.encode(address registry, address registrant, uint256 schemeId) — for stealth-meta. |
| `kinds.messaging.encodeShieldedArgs` | `function encodeShieldedArgs(pool: '0x${string}', callData: '0x${string}'): '0x${string}'` | abi.encode(address pool, bytes callData) — shared by shielded-root / shielded-set / shielded-nullifier. |
| `kinds.messaging.renderTyped712` | `function renderTyped712(t: Typed712): RenderedMessage` | Render an EIP-712 typed message honestly. |
| `kinds.messaging.decodePrivacyLeaks` | `function decodePrivacyLeaks(action: ShieldedAction):` |  |
| `kinds.messaging.POSTER_NEWPOST_TOPIC0` | `const POSTER_NEWPOST_TOPIC0 = keccak256(toBytes("NewPost(address,string,string)"))` | keccak topic0 for NewPost(address,string,string) — DERIVED from the signature (no hardcoded constant). |
| `kinds.messaging.posterFeedFilter` | `function posterFeedFilter(poster: '0x${string}', tagTopic?: '0x${string}'): PosterLogFilter` | Build an eth_getLogs filter for a Poster contract, optionally filtered by an indexed tag (keccak of the tag). |
| `kinds.skeletal` | namespace | chainc/skeletalanim.ts — DECLARATIVE SKELETAL ANIMATION as on-chain DATA (doc 158/159). |
| `kinds.skeletal.POS_SCALE` | `const POS_SCALE = 16` | ── fixed-point scales (deterministic, lossless within quantization) ── |
| `kinds.skeletal.ANG_SCALE` | `const ANG_SCALE = 32768` |  |
| `kinds.skeletal.MAGIC` | `const MAGIC = 0x4352434c` |  |
| `kinds.skeletal.PACK_VERSION` | `const PACK_VERSION = 1` |  |
| `kinds.skeletal.KIND_CLIP_COUNT` | `const KIND_CLIP_COUNT = k32("clip-count")` |  |
| `kinds.skeletal.KIND_CLIP_SLICE` | `const KIND_CLIP_SLICE = k32("clip-slice")` |  |
| `kinds.skeletal.encodePack` | `function encodePack(lib: ClipLibrary, ceilingHint = 0): Uint8Array` | Encode a library to its canonical bytes. |
| `kinds.skeletal.decodePack` | `function decodePack(bytes: Uint8Array): ClipLibrary` | Decode canonical bytes back to a library. |
| `kinds.skeletal.evalPose` | `function evalPose(lib: ClipLibrary, clipIndex: number, frame: number): Pt[]` | Evaluate world joint positions for a clip on its rig at a given frame. |
| `kinds.skeletal.renderPuppetSVG` | `function renderPuppetSVG(lib: ClipLibrary, clipIndex: number, frame: number, o: PuppetOpts = {}): string` | Render a pose as an SVG "vector puppet" — bones as round-capped lines, head as a circle. |
| `kinds.skeletal.packReport` | `function packReport(lib: ClipLibrary, ceiling: number): PackReport` |  |
| `kinds.skeletal.HUMANOID` | `const HUMANOID: Rig = { … }` | A 15-joint humanoid (hip root → spine → head; two arms hanging from shoulders; two full legs). |
| `kinds.skeletal.QUADRUPED` | `const QUADRUPED: Rig = { … }` | A 13-joint side-view QUADRUPED (dog/horse-like), facing +x. |
| `kinds.skeletal.AVIAN` | `const AVIAN: Rig = { … }` | A 13-joint side-view AVIAN (bird), facing +x: body → chest → neck → head → beak; one wing (shoulder/mid/tip); one leg (hip/knee/foot); tail. |
| `kinds.skeletal.INSECTOID` | `const INSECTOID: Rig = { … }` | A 13-joint side-view INSECTOID (ant/beetle), facing +x: thorax root, head + antenna forward, abdomen rear, and THREE legs (front/mid/rear) each hip→knee→foot. |
| `kinds.skeletal.MARINE` | `const MARINE: Rig = { … }` | A 9-joint side-view MARINE (fish), facing +x: an undulating spine (tail-base root → mid1 → mid2 → head), a caudal fin (top/bottom), a dorsal fin, and a pectoral fin. |
| `kinds.skeletal.buildReferenceLibrary` | `function buildReferenceLibrary(): ClipLibrary` | Build a varied reference library. |
| `kinds.settlement` | namespace | chainc mirror for SettlementCardResolver — binding kinds + argument encoding, drift-locked against the on-chain resolver (contracts/examples/SettlementCardResolver.sol, docs/172 §8/§9). |
| `kinds.settlement.KIND_STATUS` | `const KIND_STATUS = stringToHex("settle-status", { size: 32 })` | Binding kinds, right-padded into bytes32 — mirror SettlementCardResolver.KIND_*. |
| `kinds.settlement.KIND_REPAID` | `const KIND_REPAID = stringToHex("settle-repaid", { size: 32 })` |  |
| `kinds.settlement.KIND_PRINCIPAL` | `const KIND_PRINCIPAL = stringToHex("settle-principal", { size: 32 })` |  |
| `kinds.settlement.SETTLEMENT_STATUS` | `const SETTLEMENT_STATUS = { … } as const` | The agreement `status` enum, mirroring AttestedLoanChannel/LoanChannel `Status` (docs/172 §9). |
| `kinds.settlement.SETTLEMENT_GRADE` | `const SETTLEMENT_GRADE = { … } as const` | The honest grade boundary the settlement framework renders (docs/172 §5). |
| `kinds.settlement.encodeSettlementArgs` | `function encodeSettlementArgs(a: SettlementArgs): '0x${string}'` | abi.encode(address agreement, uint8 assetDecimals, uint8 fracDigits) — shared by all three kinds. |
| `kinds.trustFacets` | namespace | chainc mirror for TrustDisclosureResolver + the shared TrustFacets library (docs/174) — the declarative trust-disclosure vocabulary every ChainRender card composes instead of hand-writing honesty prose. |
| `kinds.trustFacets.KIND_FACETS` | `const KIND_FACETS = stringToHex("trust-facets", { size: 32 })` | Binding kind, right-padded bytes32 — mirror TrustDisclosureResolver.KIND_FACETS. |
| `kinds.trustFacets.CUSTODY` | `const CUSTODY = { … } as const` | enum ordinals — mirror TrustFacets.{Custody,Exit,RelayerBinding,Artifact} |
| `kinds.trustFacets.EXIT` | `const EXIT = { … } as const` |  |
| `kinds.trustFacets.RELAYER_BINDING` | `const RELAYER_BINDING = { … } as const` |  |
| `kinds.trustFacets.ARTIFACT` | `const ARTIFACT = { … } as const` |  |
| `kinds.trustFacets.relayerIsBound` | `function relayerIsBound(b: number): boolean` | True iff a relayer/submitter CANNOT rewrite the bound payload — mirror TrustFacets.relayerIsBound. |
| `kinds.trustFacets.custodyWord` | `const custodyWord = (c: number) => …` |  |
| `kinds.trustFacets.exitWord` | `const exitWord = (e: number) => …` |  |
| `kinds.trustFacets.relayerWord` | `const relayerWord = (b: number) => …` |  |
| `kinds.trustFacets.artifactWord` | `const artifactWord = (a: number) => …` |  |
| `kinds.trustFacets.renderTrustFacetsLine` | `function renderTrustFacetsLine(f: TrustFacets): string` | The compact one-line honest summary — mirror TrustFacets.line (joined by " · "). |
| `kinds.trustFacets.encodeTrustArgs` | `function encodeTrustArgs(subject: '0x${string}'): '0x${string}'` | abi.encode(address subject) — the resolver's args for KIND_FACETS. |
| `kinds.trustFacets.trustFacetsVocabulary` | `function trustFacetsVocabulary()` | Machine-readable vocabulary for the SDK/MCP/AI: the facet dimensions and their allowed values. |
| `kinds.door` | namespace | chainc mirror for the "door" capability (docs/174) — the zipcoin Doorstep learning, ChainRender-native and split honestly across the two grade axes: • door-knocks — ON-CHAIN aggregate (total burned, knock count, loudest knock) read from a DoorRegistry via a view → Grade A. |
| `kinds.door.KIND_DOOR_KNOCKS` | `const KIND_DOOR_KNOCKS = stringToHex("door-knocks", { size: 32 })` | Binding kinds, right-padded bytes32 — door-knocks mirrors DoorResolver.KIND_DOOR_KNOCKS. |
| `kinds.door.KIND_DOOR_FEED` | `const KIND_DOOR_FEED = stringToHex("door-feed", { size: 32 })` |  |
| `kinds.door.doorTargetFromAddress` | `function doorTargetFromAddress(addr: '0x${string}'): '0x${string}'` | A door key: an address left-padded to 32 bytes. |
| `kinds.door.encodeDoorArgs` | `function encodeDoorArgs(registry: '0x${string}', target: '0x${string}', assetDecimals: number, fracDigits: number,): '0x${string}'` | abi.encode(address registry, bytes32 target, uint8 assetDecimals, uint8 fracDigits) — for door-knocks (Grade A). |
| `kinds.door.KNOCK_TOPIC0` | `const KNOCK_TOPIC0 = keccak256(toBytes("Knock(bytes32,address,uint256,string)"))` | topic0 for Knock(...) — DERIVED from the signature (no hardcoded constant), mirroring DoorRegistry's event. |
| `kinds.door.doorFeedFilter` | `function doorFeedFilter(registry: '0x${string}', target?: '0x${string}'): DoorLogFilter` | Build an eth_getLogs filter for a DoorRegistry, optionally scoped to one `target` (the first indexed topic). |
| `kinds.door.rankKnocks` | `function rankKnocks(knocks: Knock[]): Knock[]` | Rank decoded knocks loudest-first (the weight-sorted message list). |
| `kinds.proofBadge` | namespace | chainc mirror for the artifact-pinning badge (docs/174, zipcoin learning #3) — honestly split: • proof-setup — ON-CHAIN: a digest is pinned in a SetupPinRegistry (content-addressed). |
| `kinds.proofBadge.KIND_PROOF_SETUP` | `const KIND_PROOF_SETUP = stringToHex("proof-setup", { size: 32 })` | Binding kinds — proof-setup mirrors ProofBadgeResolver.KIND_PROOF_SETUP. |
| `kinds.proofBadge.KIND_ARTIFACT_VERIFY` | `const KIND_ARTIFACT_VERIFY = stringToHex("artifact-verify", { size: 32 })` |  |
| `kinds.proofBadge.pinId` | `function pinId(sha256Digest: '0x${string}', uri: string): '0x${string}'` | Content-addressed pin id — mirror SetupPinRegistry.idOf: keccak256(abi.encode(bytes32 sha256, string uri)). |
| `kinds.proofBadge.encodeProofSetupArgs` | `function encodeProofSetupArgs(registry: '0x${string}', id: '0x${string}'): '0x${string}'` | abi.encode(address registry, bytes32 id) — for proof-setup (Grade A). |
| `kinds.proofBadge.verifyArtifact` | `function verifyArtifact(bytes: Uint8Array, expectedSha256: '0x${string}'): ArtifactVerdict` | ≤ C client check: SHA-256 the FETCHED artifact bytes and compare to the on-chain-pinned digest. |
| `kinds.proofBadge.renderArtifactBadge` | `function renderArtifactBadge(v: ArtifactVerdict): string` | A short honest badge string for the ≤ C verdict. |
| `kinds.computeCredit` | namespace | chainc mirror for the play-key metered-compute adapter (docs/174 §6 #4) — drift-locked to contracts/examples/ComputeCreditVault.sol + ComputeCreditResolver.sol. |
| `kinds.computeCredit.KIND_COMPUTE_CREDIT` | `const KIND_COMPUTE_CREDIT = stringToHex("compute-credit", { size: 32 })` | Binding kind — mirror ComputeCreditResolver.KIND_COMPUTE_CREDIT. |
| `kinds.computeCredit.encodeComputeCreditArgs` | `function encodeComputeCreditArgs(vault: '0x${string}', playKey: '0x${string}', assetDecimals: number, fracDigits: number,): '0x${string}'` | abi.encode(address vault, address playKey, uint8 assetDecimals, uint8 fracDigits) — for compute-credit (A). |
| `kinds.computeCredit.usageReceiptTypedData` | `function usageReceiptTypedData(params: { vault: '0x${string}'; chainId: number; playKey: '0x${string}'; provider: '0x${string}'; cumulativeSpent: bigint; })` | The EIP-712 typed data a PLAY-KEY signs to authorize the provider to draw down to `cumulativeSpent`. |
| `kinds.computeCredit.splitSig` | `function splitSig(sig: '0x${string}'):` | Split a 65-byte signature into the (v, r, s) the vault's claim() takes. |
| `kinds.xchain` | namespace | chainc mirror for the doc 175 / docs/176 Milestone 1 cross-chain balance stack — drift-locked to contracts/xchain/{CanonicalTokenLayout,CanonicalTokenFactory,XchainBalanceCache,XchainBalanceResolver}.sol. |
| `kinds.xchain.KIND_XCHAIN_BALANCE` | `const KIND_XCHAIN_BALANCE = stringToHex("xchain-balance", { size: 32 })` | Binding kind, right-padded bytes32 — mirror XchainBalanceResolver.KIND_XCHAIN_BALANCE. |
| `kinds.xchain.CANONICAL_TOKEN_NAMESPACE` | `const CANONICAL_TOKEN_NAMESPACE = "chainrender.xchain.CanonicalToken.v1"` | Approved storage namespace (2026-10-06) — mirror CanonicalTokenLayout.CANONICAL_TOKEN_NAMESPACE. |
| `kinds.xchain.erc7201Base` | `function erc7201Base(id: string): Hex` | ERC-7201: keccak256(abi.encode(uint256(keccak256(id)) - 1)) & ~0xff. |
| `kinds.xchain.CANONICAL_TOKEN_BASE` | `const CANONICAL_TOKEN_BASE = erc7201Base(CANONICAL_TOKEN_NAMESPACE)` | Mirror CanonicalTokenLayout.CANONICAL_TOKEN_BASE (recomputed, never typed in). |
| `kinds.xchain.balanceSlot` | `function balanceSlot(holder: Hex, base: Hex = CANONICAL_TOKEN_BASE): Hex` | Slot of balances[holder] in a CanonicalToken — mirror ICanonicalState.balanceSlot. |
| `kinds.xchain.recordSlot` | `function recordSlot(token: Hex): Hex` | Slot of the factory's recordOf[token] (slot 0 mapping) — mirror CanonicalTokenFactory.recordSlot. |
| `kinds.xchain.definitionId` | `function definitionId(p: { name: string; symbol: string; decimals: number; homeChainId: bigint; layoutHash: Hex; issueHash: Hex; }): Hex` | Mirror CanonicalTokenFactory.definitionIdOf / XchainBalanceCache._definitionId. |
| `kinds.xchain.layoutHash` | `function layoutHash(tokenCreationCodeHash: Hex, base: Hex = CANONICAL_TOKEN_BASE): Hex` | layoutHash = keccak256(abi.encode(tokenCreationCodeHash, anchorMode=0, adapter="erc20", privacyMode=0, base)). |
| `kinds.xchain.issueHash` | `function issueHash(creator: Hex, supply: bigint, recipient: Hex): Hex` | issueHash = keccak256(abi.encode(creator, supply, recipient)). |
| `kinds.xchain.encodeXchainBalanceArgs` | `function encodeXchainBalanceArgs(token: Hex, holder: Hex, maxAgeSeconds: bigint, fracDigits: number): Hex` | abi.encode(address token, address holder, uint64 maxAgeSeconds, uint8 fracDigits) — the resolver's args. |
| `kinds.xchain.MAX_SYMBOL_LENGTH` | `const MAX_SYMBOL_LENGTH = 11` | Mirror XchainBalanceCache.MAX_SYMBOL_LENGTH / MAX_DECIMALS (also enforced by the factory and the resolver). |
| `kinds.xchain.MAX_DECIMALS` | `const MAX_DECIMALS = 77` |  |
| `kinds.xchain.isValidSymbol` | `function isValidSymbol(s: string): boolean` | Mirror XchainBalanceCache.isValidSymbol: [A-Za-z0-9]{1,11}. |
| `kinds.xchain.MAX_HOST_LABEL_LENGTH` | `const MAX_HOST_LABEL_LENGTH = 32` | Mirror XchainBalanceResolver.MAX_HOST_LABEL_LENGTH / isValidHostLabel: [A-Za-z0-9 .-]{1,32}, no edge spaces. |
| `kinds.xchain.isValidHostLabel` | `function isValidHostLabel(s: string): boolean` |  |
| `kinds.xchain.MAX_HOST_FACET_LENGTH` | `const MAX_HOST_FACET_LENGTH = 48` | Mirror XchainBalanceResolverV2.MAX_HOST_FACET_LENGTH / isValidHostFacet: [A-Za-z0-9 .,:-]{1,48}, no edge spaces. |
| `kinds.xchain.isValidHostFacet` | `function isValidHostFacet(s: string): boolean` |  |
| `kinds.xchain.formatFixed` | `function formatFixed(value: bigint, decimals: number, fracDigits: number): string` | Mirror DecimalStrings.formatFixed (truncating; scales up when decimals < fracDigits). |
| `kinds.xchain.gradeWord` | `function gradeWord(g: number): string` |  |
| `kinds.xchain.pickEntry` | `function pickEntry(v: XchainBalanceView, maxAgeSeconds: bigint):` | Mirror XchainBalanceResolver._pick: fresh beats stale; then highest grade; then newest. |
| `kinds.xchain.renderXchainBalance` | `function renderXchainBalance(v: XchainBalanceView, maxAgeSeconds: bigint, fracDigits: number): string` | Mirror XchainBalanceResolver.render — the exact string the on-chain resolver produces. |
| `kinds.xchain.readXchainView` | `async function readXchainView(cache: any, token: Hex, holder: Hex, now: bigint, host: string, facet = ""): Promise<XchainBalanceView>` | Read everything renderXchainBalance needs from a deployed cache (for off-chain previews and drift tests). |
| `kinds.xchain.encodeHeader` | `function encodeHeader(raw: Record<string, string>): Hex` | RLP-encode a block header from the raw `eth_getBlockByNumber` JSON. |
| `kinds.xchain.waitUntilProvable` | `async function waitUntilProvable(client: Requester, number: bigint, opts: { pollMs?: number; timeoutMs?: number; mine?: () => Promise<unknown> } = {}): Promise<bigint>` | A SAME-CHAIN root for block `number` exists only once block `number + 1` exists: BLOCKHASH(n) is zero while n is the current block, and SameChainRootSource reverts RootUnavailable(n) for n >= block.number. |
| `kinds.xchain.headerFor` | `async function headerFor(client: Requester, number: bigint): Promise<{ rlpHeader: Hex; hash: Hex }>` | Fetch + encode block `number`'s header, verifying it hashes to the block hash (fail closed). |
| `kinds.xchain.buildBalanceProof` | `async function buildBalanceProof(client: Requester, token: Hex, holder: Hex, number: bigint, base: Hex = CANONICAL_TOKEN_BASE)` | Proof bundle for XchainBalanceCache.refresh. |
| `kinds.xchain.buildRecordProof` | `async function buildRecordProof(client: Requester, factory: Hex, token: Hex, number: bigint)` | Proof bundle for XchainBalanceCache.registerToken. |
| `kinds.xchain.ARB_ALIAS_OFFSET` | `const ARB_ALIAS_OFFSET = 0x1111000000000000000000000000000000001111n` | Arbitrum L1→L2 alias offset (protocol constant of the Arbitrum stack; Arbitrum docs) — mirror ArbParentRootSource. |
| `kinds.xchain.l1ToL2Alias` | `function l1ToL2Alias(address: Hex): Hex` | The address a parent-chain CONTRACT appears as on the child chain: address + offset, mod 2^160. |
| `kinds.xchain.ARB_PRECOMPILES` | `const ARB_PRECOMPILES = { … }` | Arbitrum precompile addresses (Arbitrum docs) — config, overridable per chain. |
| `kinds.xchain.retryableParams` | `async function retryableParams(opts: { parent: any; child: any; inbox: Hex; sender: Hex; receiver: Hex; data: Hex; refund: Hex; margin?: bigint; nodeInterface?: Hex; }): Promise<RetryableParams>` | Fees for one ArbRootSender.deliver. |
| `kinds.xchain.waitForRoot` | `async function waitForRoot(receiver: any, n: bigint, opts: { pollMs?: number; timeoutMs?: number } = {}): Promise<Hex>` | Poll the child-chain ArbParentRootSource until block `n`'s root has arrived. |
| `kinds.xchain.assertResolverForHost` | `function assertResolverForHost(resolver: "XchainBalanceResolver" \| "XchainBalanceResolverV2", homeChainId: bigint, hostChainId: bigint, facet = ""): void` | docs/177 L-3 — which resolver may render a cache on a given host. |
| `kinds.scopeDisclosure` | namespace | chainc mirror for ScopeDisclosureResolver + IScopeDisclosure (doc 175 X7, docs/176 §3.8 / §4.2): what a subject's trust grade does NOT establish. |
| `kinds.scopeDisclosure.KIND_SCOPE_DISCLOSURE` | `const KIND_SCOPE_DISCLOSURE = stringToHex("scope-disclosure", { size: 32 })` | Binding kind, right-padded bytes32 — mirror ScopeDisclosureResolver.KIND_SCOPE_DISCLOSURE. |
| `kinds.scopeDisclosure.SCOPE_DISCLOSURE_INTERFACE_ID` | `const SCOPE_DISCLOSURE_INTERFACE_ID: Hex = toFunctionSelector("doesNotEstablish()")` | ERC-165 id of IScopeDisclosure (single function). |
| `kinds.scopeDisclosure.NOT_DISCLOSED` | `const NOT_DISCLOSED = "scope not disclosed"` |  |
| `kinds.scopeDisclosure.MAX_ITEMS` | `const MAX_ITEMS = 16` | Mirror ScopeDisclosureResolver bounds: a longer list, or a longer item, renders NOT_DISCLOSED. |
| `kinds.scopeDisclosure.MAX_ITEM_BYTES` | `const MAX_ITEM_BYTES = 160` |  |
| `kinds.scopeDisclosure.encodeScopeArgs` | `function encodeScopeArgs(subject: Hex): Hex` | abi.encode(address subject) — the resolver's args. |
| `kinds.scopeDisclosure.renderScopeDisclosure` | `function renderScopeDisclosure(list: string[] \| null): string` | Mirror ScopeDisclosureResolver.render for a subject that returned `list` (null = not implemented / failed). |
| `kinds.scopeDisclosure.scopeDisclosureVocabulary` | `function scopeDisclosureVocabulary()` | Machine-readable note for the SDK/MCP/AI. |
| `kinds.xsnap` | namespace | chainc mirror for docs/178 Mode A (snapshot balances) — drift-locked to contracts/xchain/{BalanceSnapshotter, SnapshotBalanceCache,SnapshotBalanceResolver}.sol. |
| `kinds.xsnap.KIND_XCHAIN_SNAPSHOT_BALANCE` | `const KIND_XCHAIN_SNAPSHOT_BALANCE = stringToHex("xchain-snapshot-balance", { size: 32 })` | Binding kind, right-padded bytes32 — mirror SnapshotBalanceResolver.KIND_XCHAIN_SNAPSHOT_BALANCE. |
| `kinds.xsnap.encodeSnapshotBalanceArgs` | `function encodeSnapshotBalanceArgs(token: Hex, holder: Hex, maxAgeSeconds: bigint, fracDigits: number): Hex` |  |
| `kinds.xsnap.snapshotCommitment` | `function snapshotCommitment(value: bigint, decimals: number, codeHash: Hex, snapBlock: bigint, snapTime: bigint): Hex` |  |
| `kinds.xsnap.metadataCommitment` | `function metadataCommitment(name: string, symbol: string, codeHash: Hex, metaBlock: bigint): Hex` |  |
| `kinds.xsnap.metaSlot` | `function metaSlot(token: Hex): Hex` | metaOf[token] — slot 0. |
| `kinds.xsnap.snapSlot` | `function snapSlot(token: Hex, holder: Hex): Hex` | snapOf[token][holder] — slot 1. |
| `kinds.xsnap.isValidName` | `function isValidName(s: string): boolean` | Mirror BalanceSnapshotter/SnapshotBalanceCache.isValidName: printable ASCII, 1..64 bytes. |
| `kinds.xsnap.buildSnapshotProof` | `async function buildSnapshotProof(client: Requester & LogReader, snapshotter: Hex, token: Hex, holder: Hex, n: bigint, opts: { fromBlock?: bigint } = {})` | Arguments for SnapshotBalanceCache.refresh: the latest snapshot of (token, holder) as of home block n, its preimage read from the snapshotter's Snapshot events (relies on the RPC serving those logs — docs/178 §3.3) and checked against the slot at n before anything is returned (fail closed). |
| `kinds.xsnap.buildMetadataProof` | `async function buildMetadataProof(client: Requester & LogReader, snapshotter: Hex, token: Hex, n: bigint, opts: { fromBlock?: bigint } = {})` | Arguments for SnapshotBalanceCache.registerToken (latest metadata as of block n), checked against the slot. |
| `kinds.xsnap.renderSnapshotBalance` | `function renderSnapshotBalance(v: SnapshotView, maxAgeSeconds: bigint, fracDigits: number): string` | Mirror SnapshotBalanceResolver.render. |
| `kinds.xsnap.readSnapshotView` | `async function readSnapshotView(cache: any, token: Hex, holder: Hex, now: bigint, host: string, facet = ""): Promise<SnapshotView>` | Read everything renderSnapshotBalance needs from a deployed SnapshotBalanceCache + resolver host settings. |
| `kinds.xadopt` | namespace | chainc mirror for docs/178 Mode B (storage-layout adoption of existing tokens) — drift-locked to contracts/xchain/{TokenAdoptionRegistry,AdoptedBalanceCache,AdoptedBalanceResolver}.sol and the adapters in contracts/xchain/adapters/. |
| `kinds.xadopt.KIND_XCHAIN_ADOPTED_BALANCE` | `const KIND_XCHAIN_ADOPTED_BALANCE = stringToHex("xchain-adopted-balance", { size: 32 })` | Binding kind, right-padded bytes32 — mirror AdoptedBalanceResolver.KIND_XCHAIN_ADOPTED_BALANCE. |
| `kinds.xadopt.ADOPTED_GRADE_CEILING` | `const ADOPTED_GRADE_CEILING = 1` |  |
| `kinds.xadopt.ADOPTED` | `const ADOPTED = 1` |  |
| `kinds.xadopt.CONFIRMED` | `const CONFIRMED = 2` |  |
| `kinds.xadopt.encodeAdoptedBalanceArgs` | `function encodeAdoptedBalanceArgs(claimId: Hex, holder: Hex, maxAgeSeconds: bigint, fracDigits: number): Hex` |  |
| `kinds.xadopt.ADOPTION_RECORD_ABI` | `const ADOPTION_RECORD_ABI = { … } as const` |  |
| `kinds.xadopt.adoptionClaimId` | `function adoptionClaimId(r: AdoptionRecord): Hex` | claimId = keccak256(abi.encode(record)) — mirror TokenAdoptionRegistry.claimIdOf. |
| `kinds.xadopt.registryStateSlot` | `function registryStateSlot(claimId: Hex): Hex` | stateOf[claimId] — slot 0 of the registry. |
| `kinds.xadopt.shortClaimId` | `function shortClaimId(claimId: Hex): string` | 0x + first 8 hex + "…" + last 8 hex — mirror AdoptedBalanceResolver._shortId. |
| `kinds.xadopt.plainPinningParams` | `const plainPinningParams = (): Hex => …` |  |
| `kinds.xadopt.slotProxyPinningParams` | `function slotProxyPinningParams(implSlot: Hex, implementation: Hex, implCodeHash: Hex): Hex` |  |
| `kinds.xadopt.mappingWordLayoutParams` | `function mappingWordLayoutParams(keyOrder: 0 \| 1, baseSlot: bigint \| Hex, valueBits: number): Hex` | keyOrder 0 = Solidity keccak256(abi.encode(holder, baseSlot)); 1 = keccak256(abi.encode(baseSlot, holder)). |
| `kinds.xadopt.mappingWordLayout` | `const mappingWordLayout = { … } as const` |  |
| `kinds.xadopt.DELEGATING` | `const DELEGATING = new Set([0xf2, 0xf4])` |  |
| `kinds.xadopt.PURE_ALLOWED` | `const PURE_ALLOWED: Set<number> = (() => …` |  |
| `kinds.xadopt.firstReachable` | `function firstReachable(code: Hex, refused: (op: number) => boolean):` | First reachable opcode for which `refused(op)` is true — mirror CodeScan.firstReachable. |
| `kinds.xadopt.hasPush` | `function hasPush(code: Hex, width: number, immediate: Hex): boolean` | Mirror CodeScan.hasPush (immediate as a 0x hex string of exactly `width` bytes). |
| `kinds.xadopt.isPureAdapterCode` | `const isPureAdapterCode = (code: Hex) => …` |  |
| `kinds.xadopt.planFor` | `async function planFor(client: Reader, c: Claim, holder: Hex, n: bigint): Promise<Plan>` | What the on-chain core will prove for `holder` (AdoptedStateLib.plan), asked of the claim's adapters at block n. |
| `kinds.xadopt.buildAdoptedStateProof` | `async function buildAdoptedStateProof(client: Reader, c: Claim, holder: Hex, n: bigint): Promise<{ proof: StateProof; value: bigint; plan: Plan }>` | A StateProof for `holder` under claim `c` at home block n (for confirmWitness at the adoption block, or refresh at any block the root source vouches for): one eth_getProof per account with that account's slots. |
| `kinds.xadopt.buildRegistryProof` | `async function buildRegistryProof(client: Requester, registry: Hex, claimId: Hex, n: bigint)` | A RegistryProof (AdoptedBalanceCache.register): the registry account and stateOf[claimId] at block n. |
| `kinds.xadopt.ADOPTED_EVENT` | `const ADOPTED_EVENT = parseAbiItem("event Adopted(bytes32 indexed claimId, address indexed token, address indexed by, ((address token, bytes32 codeHash, (address adapter, bytes32 codeHash, bytes para…` |  |
| `kinds.xadopt.recordOf` | `async function recordOf(client: Reader, registry: Hex, claimId: Hex, opts: { fromBlock?: bigint; toBlock?: bigint } = {}): Promise<AdoptionRecord>` | The AdoptionRecord of `claimId` from the registry's Adopted event; checked against the id (fail closed). |
| `kinds.xadopt.renderAdoptedBalance` | `function renderAdoptedBalance(v: AdoptedView, maxAgeSeconds: bigint, fracDigits: number): string` | Mirror AdoptedBalanceResolver.render. |
| `kinds.xadopt.readAdoptedView` | `async function readAdoptedView(cache: any, claimId: Hex, holder: Hex, now: bigint, host: string, facet = ""): Promise<AdoptedView>` | Read everything renderAdoptedBalance needs from a deployed AdoptedBalanceCache + the resolver's host settings. |
| `kinds.xswap` | namespace | chainc mirror for docs/179 Milestone 4 — the bridge-free cross-chain swap (`timelock-swap`, doc 175 §5.5): HashTimelockSwap (same code on every chain), SwapLockProofCache (proves a home lock on another chain and guards the second lock) and SwapLockResolver ("swap-lock"). |
| `kinds.xswap.KIND_SWAP_LOCK` | `const KIND_SWAP_LOCK = stringToHex("swap-lock", { size: 32 })` | Binding kind, right-padded bytes32 — mirror SwapLockResolver.KIND_SWAP_LOCK. |
| `kinds.xswap.SWAP_OPEN` | `const SWAP_OPEN = 1` |  |
| `kinds.xswap.SWAP_CLAIMED` | `const SWAP_CLAIMED = 2` |  |
| `kinds.xswap.SWAP_REFUNDED` | `const SWAP_REFUNDED = 3` |  |
| `kinds.xswap.SWAP_TERMS_ABI` | `const SWAP_TERMS_ABI = { … } as const` |  |
| `kinds.xswap.swapId` | `function swapId(chainId: bigint, swap: Hex, t: SwapTerms): Hex` | Mirror HashTimelockSwap.idOf / SwapLockProofCache.homeIdOf: keccak256(abi.encode(chainId, swap, terms)). |
| `kinds.xswap.hashlockOf` | `function hashlockOf(secret: Hex): Hex` | Mirror HashTimelockSwap.hashOf: sha256 of the 32-byte secret. |
| `kinds.xswap.swapStateSlot` | `function swapStateSlot(id: Hex): Hex` | Mirror HashTimelockSwap.stateSlot: keccak256(abi.encode(id, uint256(0))). |
| `kinds.xswap.encodeSwapLockArgs` | `function encodeSwapLockArgs(id: Hex, maxAgeSeconds: bigint, fracDigits: number): Hex` | abi.encode(bytes32 id, uint64 maxAgeSeconds, uint8 fracDigits) — the resolver's args. |
| `kinds.xswap.guardVerdict` | `function guardVerdict(counterpart: { state: number; terms: SwapTerms; tokenRegistered: boolean } \| null, mine: SwapTerms, guard: Hex, nowTs: bigint, minGap: bigint, minWindow: bigint): string \| null` | The guard rule SwapLockProofCache.checkLock enforces, for clients that want to explain a refusal before sending. |
| `kinds.xswap.shortAddress` | `function shortAddress(a: Hex): string` | Mirror SwapLockResolver._short: "0x" + first 4 bytes + "…" + last 4 bytes, lowercase. |
| `kinds.xswap.renderSwapLock` | `function renderSwapLock(v: SwapLockView, maxAgeSeconds: bigint, fracDigits: number): string` | Mirror SwapLockResolver.render — the exact string the on-chain resolver produces. |
| `kinds.xswap.readSwapLockView` | `async function readSwapLockView(locks: any, balances: any \| null, id: Hex, now: bigint, homeLabel: string, host: string, facet = ""): Promise<SwapLockView>` | Read everything renderSwapLock needs from deployed contracts (previews and drift tests). |
| `kinds.xswap.buildLockProof` | `async function buildLockProof(client: Requester, swap: Hex, id: Hex, number: bigint)` | Proof bundle for SwapLockProofCache.proveLock: home header + home swap account proof + stateOf[id] proof. |
| `kinds.xswap.tokenCreationCodeHashFromFactory` | `function tokenCreationCodeHashFromFactory(factoryRuntime: Hex, artifactCreation: Hex): Hex` | keccak256 of the CanonicalToken creation code AS EMBEDDED IN A DEPLOYED FACTORY — the input of the factory's layoutHash. |
| `kinds.xswap.confirmCreationCodeHash` | `function confirmCreationCodeHash(creationCodeHash: Hex, t: { name: string; symbol: string; decimals: number; homeChainId: bigint; creator: Hex; supply: bigint; recipient: Hex; definitionId: Hex }): boolean` | True when `creationCodeHash` reproduces a real token's definition id (factory.definitionIdOf, chainc mirror). |
| `kinds.RESOLVER_KINDS` | `const RESOLVER_KINDS: ResolverKindDescriptor[] = [ … ]` | The first-party on-chain resolver kinds ChainRender ships, drift-locked to their mirrors. |
| `kinds.assertEdgeHonesty` | `function assertEdgeHonesty(kinds: ResolverKindDescriptor[] = RESOLVER_KINDS): void` | Invariant R2 (edge honesty by construction). |
| `kinds.edgeCeiling` | `function edgeCeiling(k: ResolverKindDescriptor): "A" \| "C"` | The honest grade CEILING a kind's data edge implies: off-chain → "C" (Live), on-chain → "A" (Trustless). |
| `kinds.HOST_CHAIN_ENTRY` | `const HOST_CHAIN_ENTRY = "anything beyond the host chain's own consensus (host-chain grade)"` | Doc 175 host-chain facet every X7 list must carry. |
| `kinds.assertCrosschainHonesty` | `function assertCrosschainHonesty(kinds: ResolverKindDescriptor[] = RESOLVER_KINDS): void` | Doc 175 X1 + X7 (cross-chain honesty by construction). |
| `kinds.xchainCeiling` | `function xchainCeiling(k: ResolverKindDescriptor, source: string): "A" \| "C"` | The grade ceiling of an xchain kind fed by `source`: min(edge ceiling, that source's ceiling). |

#### `reads` (namespace)

v0.11.0: generic on-chain reads — arg encoders for the `staticread` (CallResolver: any view function on any co-located contract, STATICCALL-only) and `multiread` (MultiCallResolver) slots; the most common way an app shows its own contract's state. reads.staticReadSlot(resolver, { target, callData: reads.callData("totalSupply()") }).

Source: `chainc/callresolver.ts`

| Member | Signature | Summary |
|---|---|---|
| `reads.STATICREAD_KIND` | `const STATICREAD_KIND = "staticread"` |  |
| `reads.STATICREAD_KIND_HEX` | `const STATICREAD_KIND_HEX = stringToHex("staticread", { size: 32 })` |  |
| `reads.RET` | `const RET = { … } as const` | How CallResolver decodes the target's return bytes. |
| `reads.FMT` | `const FMT = { … } as const` | How CallResolver formats the decoded value. |
| `reads.callData` | `function callData(signature: string, args: readonly unknown[] = []): '0x${string}'` | Build the STATICCALL calldata from a human signature + args. |
| `reads.staticReadArg` | `function staticReadArg(spec: StaticReadSpec): '0x${string}'` | Encode the CallResolver `arg` bytes for a slot. |
| `reads.staticReadSlot` | `function staticReadSlot(resolver: '0x${string}', spec: StaticReadSpec, fallback = "\u2014")` | Build a ready-to-drop slot node that reads `spec` via the deployed CallResolver at `resolver`. |
| `reads.STATICREAD_DESCRIPTOR` | `const STATICREAD_DESCRIPTOR = { … } as const` | Machine-readable descriptor for SDK / builder / assistant discovery (generic, extensible kind). |
| `reads.MULTIREAD_KIND` | `const MULTIREAD_KIND = "multiread"` | ── multi-read (contracts/MultiCallResolver.sol) ── |
| `reads.COMBINE` | `const COMBINE = { … } as const` | Combine modes. |
| `reads.multiReadArg` | `function multiReadArg(reads: ReadItem[], mode: number, opts: MultiReadOpts = {}): '0x${string}'` | Encode the MultiCallResolver `arg` bytes: N reads + a combine mode + separator/format. |
| `reads.multiReadSlot` | `function multiReadSlot(resolver: '0x${string}', reads: ReadItem[], mode: number, opts: MultiReadOpts = {})` | Build a slot that reads several co-located view fns via the deployed MultiCallResolver and combines them. |
| `reads.COMPUTE_KIND` | `const COMPUTE_KIND = "compute"` | ── compute / expression (contracts/ComputeResolver.sol) ── |
| `reads.OP` | `const OP = { … } as const` | Opcodes for the bounded RPN stack machine. |
| `reads.encodeProgram` | `function encodeProgram(steps: Step[]): '0x${string}'` | Encode an RPN program to bytes. |
| `reads.computeArg` | `function computeArg(reads: ComputeRead[], steps: Step[], opts: ComputeOpts = {}): '0x${string}'` | Encode the ComputeResolver `arg` bytes: the input reads + the RPN program + output format. |
| `reads.computeSlot` | `function computeSlot(resolver: '0x${string}', reads: ComputeRead[], steps: Step[], opts: ComputeOpts = {})` | Build a slot that computes a derived value from co-located reads via the deployed ComputeResolver. |

#### `appmeta` (namespace)

App metadata: the single source of truth for on-chain app titles/authors/etc. (see chainc/appmeta.ts).

Source: `chainc/appmeta.ts`

| Member | Signature | Summary |
|---|---|---|
| `appmeta.APP_META_VERSION` | `const APP_META_VERSION = 1 as const` | Bump when the metadata SHAPE changes in a way readers should be aware of. |
| `appmeta.KNOWN_KEYS` | `const KNOWN_KEYS = [ … ] as const` | Documentation of the keys this version knows about. |
| `appmeta.MAX_META_BYTES` | `const MAX_META_BYTES = 4096` | Hard cap on the serialized metadata size (bytes). |
| `appmeta.encodeAppMeta` | `function encodeAppMeta(meta: Partial<AppMeta> \| null \| undefined): string` | Serialize an app-metadata object to the compact string that goes on-chain. |
| `appmeta.decodeAppMeta` | `function decodeAppMeta(raw: string \| null \| undefined): AppMeta` | Parse an on-chain metadata string into an AppMeta object. |
| `appmeta.getTitle` | `function getTitle(meta: AppMeta \| null \| undefined, fallback = ""): string` | The display title, or the provided fallback (e.g. |
| `appmeta.getAuthor` | `function getAuthor(meta: AppMeta \| null \| undefined): string` | The author, or "" if none. |
| `appmeta.getDescription` | `function getDescription(meta: AppMeta \| null \| undefined): string` | The description, or "" if none. |
| `appmeta.getKind` | `function getKind(meta: AppMeta \| null \| undefined, fallback = ""): string` | The app kind, or the provided fallback. |
| `appmeta.getIcon` | `function getIcon(meta: AppMeta \| null \| undefined, fallback = ""): string` | The card icon name, or the provided fallback (e.g. |
| `appmeta.getCategory` | `function getCategory(meta: AppMeta \| null \| undefined, fallback = ""): string` | The category for grouping, or the provided fallback (e.g. |
| `appmeta.getGrade` | `function getGrade(meta: AppMeta \| null \| undefined, fallback = ""): string` | The trust grade letter ("A"\|"B"\|"C"\|"gear"), or the provided fallback. |
| `appmeta.getGradeWord` | `function getGradeWord(meta: AppMeta \| null \| undefined): string` | The grade word ("Trustless"\|"Pinned"\|"Live"\|"Above-floor"), or "". |
| `appmeta.gradeLocks` | `function gradeLocks(gradeLetter: string): string` | Render a lock string for a grade letter: A=3 locks, B=2, C=1, gear=the gear glyph. |
| `appmeta.getTags` | `function getTags(meta: AppMeta \| null \| undefined): string[]` | The tag list, or [] if none/malformed. |
| `appmeta.hasMeta` | `function hasMeta(meta: AppMeta \| null \| undefined): boolean` | True if the metadata carries any meaningful field beyond the version stamp. |

#### `RESOLVER_KINDS`

```ts
const RESOLVER_KINDS: ResolverKindDescriptor[] = [ … ]
```

The first-party on-chain resolver kinds ChainRender ships, drift-locked to their mirrors.

Source: `chainc/resolverkinds.ts`

### v0.4.0: Naming / submission helpers (docs 72/86)

#### `labelHashOf`

```ts
function labelHashOf(label: string): `0x${string}`
```

labelHash = keccak256(utf8 bytes of the subname label) — mirrors SubnameStakeRegistrar.labelHashOf.

Source: `chainc/submission.ts`

#### `SPAM_TOPIC`

```ts
const SPAM_TOPIC = stringToHex("spam", { size: 32 })
```

The topic an attester publishes to flag spam (right-padded into bytes32) — mirrors SPAM_TOPIC.

Source: `chainc/submission.ts`

#### `SubmissionStatus`

```ts
enum SubmissionStatus
```

Submission status — mirrors SubnameStakeRegistrar.Status. Enum order is load-bearing (matched on-chain).

Source: `chainc/submission.ts`

#### `isLive`

```ts
function isLive(status: SubmissionStatus): boolean
```

A submission is live (resolves to its component) only when Active or Refunded — mirrors `resolves()`.

Source: `chainc/submission.ts`

### v0.4.0: Theming (design tokens + CSS generation)

#### `defaultTokens`

```ts
function defaultTokens(): ThemeTokens
```

── DEFAULT tokens — grounded in the LIVE seeded theme (not invented), extended to the full surface with sane fail-closed defaults for the axes the CSS didn't previously tokenize. This is `_defaultTokens()`'s mirror. ──

Source: `chainc/theme-tokens.ts`

#### `darkDefaults`

```ts
function darkDefaults(): ThemeTokens
```

A standard DARK preset (doc 102) — EXACT mirror of ThemeTokens.darkDefaults(). Drift-locked.

Source: `chainc/theme-tokens.ts`

#### `highContrastDefaults`

```ts
function highContrastDefaults(): ThemeTokens
```

doc 107 gap #1 — high-contrast preset (WCAG AAA). Maximum legibility: near-pure black text on pure white, saturated accents chosen for >=7:1, thicker borders/focus for the non-text indicator floor (1.4.11). A THIRD preset alongside light/dark — the standard accessibility trio. Drift-locked + contrast-invariant-checked.

Source: `chainc/theme-tokens.ts`

#### `toCss`

```ts
function toCss(t: ThemeTokens): string
```

Generate the .cr-root CSS from tokens — the SAME values the palette inlines, so components + image renderers can't disagree. (On-chain, ThemeCssView produces this exact string; this is the mirror for the drift-lock.)

Source: `chainc/theme-tokens.ts`

#### `toPalette`

```ts
function toPalette(t: ThemeTokens)
```

The inlined palette image renderers use — literal values (never var()). Colors + the font scale + fonts.

Source: `chainc/theme-tokens.ts`

#### `THEME_TOKENS_VERSION`

```ts
const THEME_TOKENS_VERSION = 1
```

chainc/theme-tokens.ts — the SINGLE SOURCE OF TRUTH for ChainRender's design-token system (doc 98). From this one token set derive BOTH outputs, so components (CSS) and image renderers (inlined palette) can never diverge: • toCss(tokens) → the .cr-root CSS string (what components consume via the shadow root / ThemeCssView) • toPalette(tokens) → literal color/font values image renderers INLINE into SVG (never var(), which is inert inside an <img> — the bug doc 98 fixes) Complete to the W3C Design Tokens taxonomy (color/dimension/fontFamily/fontWeight/number/duration/cubicBezier + composite typography/border/shadow/transition/gradient/strokeStyle) plus layering + breakpoints. Closed core + additive extension + version byte (fail-closed on unknown) — expandable, robust, upgradable, fully on-chain.

Source: `chainc/theme-tokens.ts`

#### `LEGIBILITY_FLOOR`

```ts
const LEGIBILITY_FLOOR = 12
```

The token model + the on-chain-identical CSS generators, so an SDK consumer (or a visual builder) can theme an app: pick a preset, edit tokens, and produce the exact .cr-root CSS the on-chain ThemeCssView produces.

Source: `chainc/theme-tokens.ts`

#### `fullThemeCss`

```ts
function fullThemeCss(tokens: ThemeTokens): string
```

The complete .cr-root CSS for a token set: the token variables (as ThemeCssView produces on-chain) plus the shared component rules.

Source: `client/runtime/default-theme.ts`

#### `lightThemeCss`

```ts
function lightThemeCss(): string
```

fullThemeCss() of the default light tokens.

Source: `client/runtime/default-theme.ts`

#### `darkThemeCss`

```ts
function darkThemeCss(): string
```

fullThemeCss() of the default dark tokens.

Source: `client/runtime/default-theme.ts`

### v0.4.0: Verified-subname preflight (SubnameStakeRegistrarV2, docs 72/86 §5)

#### `expectedEnsNode`

```ts
function expectedEnsNode(label: string): `0x${string}`
```

/ The ENS node a VERIFIED claim of `label` must prove ownership of: namehash(`<label>.eth`) = / keccak256(namehash("eth"), keccak256(label)). Equals SubnameStakeRegistrarV2.expectedEnsNode(label) and / viem's namehash(label + ".eth"). Use it to build the registerVerified call and preflight the binding.

Source: `chainc/submission-v2.ts`

#### `isValidLabel`

```ts
function isValidLabel(label: string): boolean
```

/ True iff `label` passes the on-chain charset/normalization gate: non-empty, <= MAX_LABEL_LEN, lowercase ASCII / [a-z0-9-], no leading/trailing hyphen, no consecutive hyphens. Mirrors SubnameStakeRegistrarV2.isValidLabel — / categorically excludes homoglyph/confusable/whitespace/mixed-case spoofs. Preflight before register().

Source: `chainc/submission-v2.ts`

#### `ETH_NODE`

```ts
const ETH_NODE = "0x93cdeb708b7545dc668eb9280176169d1c33cfd8ed6f04690a0bcc88a93fc4ae" as const
```

/ namehash("eth") — the parent under which a verified label's name must exist (mirrors ETH_NODE in the contract).

Source: `chainc/submission-v2.ts`

#### `MAX_LABEL_LEN`

```ts
const MAX_LABEL_LEN = 63
```

/ The maximum label length the registrar accepts (mirrors MAX_LABEL_LEN).

Source: `chainc/submission-v2.ts`

### Types

TypeScript types exported here (type-only: `import type { … }`):

| Type | Definition | Source |
|---|---|---|
| `Compiled` | `interface Compiled { bytes: Uint8Array; hex: '0x${string}'; hash: '0x${string}'; byteSize: number; }` | `chainc/index.ts` |
| `Node` | `type Node = \| ({ type: "text"; content?: string; children?: Node[] } & A11y & Presentation) \| ({ type: "box"; direction?: DirectionName; children?: Node[] } & A11y & Presentation) \| ({ type: "button"; content?: string; variant?: VariantName; children?: Node[]; /** A declarative submit action: the t…` | `chainc/compile.ts` |
| `Decompiled` | `interface Decompiled { tree: Node; version: number; mode: "classic" \| "enhanced"; nodeCount: number; }` | `chainc/decompile.ts` |
| `BehaviorDescriptor` | `interface BehaviorDescriptor { requiredCapabilities: string[]; declaredCapabilities: string[]; capabilitiesHonest: boolean; actions: BehaviorAction[]; batchedActionGroups: number; signatureRequests: number; chainReads: number; media: { provenance: string; onChain: boolean }[]; gpu: boolean; offChainFetch: boolean; summary: string[]; }` | `chainc/describe.ts` |
| `CompositionFloor` | `interface CompositionFloor { sceneSummary: string; placedComponents: { hash: string; anchor: string; summary: string[] }[]; aggregatedCapabilities: string[]; escalationFree: boolean; summary: string[]; }` | `chainc/describe.ts` |
| `ValidationReport` | `interface ValidationReport { ok: boolean; checks: ValidationCheck[]; }` | `chainc/validate.ts` |
| `ValidationCheck` | `interface ValidationCheck { name: string; ok: boolean; detail?: string; }` | `chainc/validate.ts` |
| `Collected` | `interface Collected { actions: CollectedAction[]; resolvers: Set<string>; refs: Set<string>; media: CollectedMedia[]; batches: CollectedAction[][]; signs: Record<string, unknown>[]; }` | `chainc/validate.ts` |
| `Part` | `interface Part { caps: number; presentation: number; dependency: number; escapeHatch?: boolean; fetchIsEnhancement?: boolean; }` | `chainc/trustgrade.ts` |
| `Analysis` | `interface Analysis { envelope: number; grade: number; deviations: Deviation[]; }` | `chainc/trustgrade.ts` |
| `Result` | `interface Result { refused: boolean; reason: number; envelope: number; grade: number; deviations: Deviation[]; }` | `chainc/trustgrade.ts` |
| `Action` | `interface Action { cap: number; carriesValue: boolean; to: string; selector: string; }` | `chainc/trustgrade.ts` |
| `Target` | `interface Target { to: string; selector: string; }` | `chainc/trustgrade.ts` |
| `Deviation` | `interface Deviation { part: number; axis: number; reason: number; grade: number; }` | `chainc/trustgrade.ts` |
| `WriteAction` | `interface WriteAction { cap: number; to: string; selector: string; value: bigint; args: ArgSlot[]; }` | `chainc/actionvocab.ts` |
| `ArgSlot` | `interface ArgSlot { source: number; argType: number; value: string; }` | `chainc/actionvocab.ts` |
| `Constructed` | `interface Constructed { ok: boolean; reason: number; to: string; value: bigint; data: string; }` | `chainc/actionvocab.ts` |
| `BuiltManifest` | `interface BuiltManifest { encoded: '0x${string}'; appHash: '0x${string}'; manifest: Required<AppManifestInput>; }` | `chainc/manifest.ts` |
| `AppManifestInput` | `interface AppManifestInput { root: '0x${string}'; components: '0x${string}'[]; contracts?: ContractBinding[]; resolvers?: '0x${string}'[]; capabilities?: number; name: string; version: string; attestationSchema?: '0x${string}'; parent?: '0x${string}'; }` | `chainc/manifest.ts` |
| `ContractBinding` | `interface ContractBinding { target: '0x${string}'; chainId: bigint \| number; methods: string[]; }` | `chainc/manifest.ts` |
| `GradeResult` | `interface GradeResult { grade: number; letter: string; word: string; locks: string; envelope: number; refused: boolean; reason: number; deviations: Deviation[]; aboveFloor?: { kinds: string[]; word: "Above-floor"; locks: "\u2699" }; }` | `client/grade.ts` |
| `GradeOptions` | `interface GradeOptions { fetchIsEnhancement?: boolean; presentation?: number; dependency?: number; pinnedDep?: PinnedDep \| null; }` | `client/grade.ts` |
| `PinnedDep` | `interface PinnedDep { protocol: "ipfs"; cid: string; ens?: string; codec?: string; hash?: string; verify?: string; }` | `chainc/pinneddep.ts` |
| `VocabularySchema` | `interface VocabularySchema { version: string; nodeTypes: VocabNode[]; a11y: VocabField[]; behavior: VocabField[]; scene: { binds: string[]; fields: VocabField[]; note: string }; enums: Record<string, string[]>; capabilities: Record<string, number>; kinds: Record<string, Record<string, number>>; resolverKinds: ResolverKindDescriptor[]; authoringBinds: Record<string, typeof CHART_AUTHORING>; viewerReads: typeof VIEWER_READS; mode: VocabMode; presentation?: { requires: string; fieldsByType: Record<string, VocabField[]>; style: ReturnType<typeof styleRegistry>; hints: ReturnType<typeof hintRegist…` | `client/vocabulary.ts` |
| `VocabNode` | `interface VocabNode { type: string; summary: string; fields: VocabField[]; }` | `client/vocabulary.ts` |
| `VocabField` | `interface VocabField { name: string; kind: string; required?: boolean; enum?: string; of?: string; values?: string[]; note?: string; }` | `client/vocabulary.ts` |
| `NodeCheck` | `interface NodeCheck { ok: boolean; issues: NodeIssue[]; nodeCount: number; depth: number; }` | `chainc/node-schema.ts` |
| `NodeIssue` | `interface NodeIssue { path: string; code: "unknown-field" \| "ignored-field" \| "authoring-field" \| "required" \| "type" \| "enum" \| "format" \| "limit" \| "mode"; message: string; }` | `chainc/node-schema.ts` |
| `FieldSpec` | `interface FieldSpec { name: string; kind: FieldKind; required?: boolean; enum?: NodeEnumName; fields?: FieldSpec[]; values?: "typedFields" \| "scalar"; family?: string; since?: number; note?: string; }` | `chainc/node-schema.ts` |
| `FieldKind` | `type FieldKind = \| "string" \| "bool" \| "integer" // whole number >= 1 \| "number\|string" // a positive number, or the same as a decimal string \| "address" // 0x + 20 bytes \| "bytes32" // 0x + 32 bytes \| "hex" // 0x + whole bytes \| "arg" // slot/image arg: hex bytes when a 'resolver' is set, otherwis…` | `chainc/node-schema.ts` |
| `NodeType` | `type NodeType = (typeof NODE_TYPES)[number]` | `chainc/node-schema.ts` |
| `NodeEnumName` | `type NodeEnumName = keyof typeof NODE_ENUMS` | `chainc/node-schema.ts` |
| `Review` | `interface Review { pass: boolean; verdict: string; check: ReturnType<typeof checkNode>; grade: { letter: string; word: string; deviations: unknown; aboveFloor?: unknown; error?: string }; compiled: { hash?: string; size?: number; error?: string }; honesty: (HonestyFinding \| PresentationFinding)[]; counts: { checkIssues: number; errors: number; warnings: number }; }` | `client/review.ts` |
| `ReviewOptions` | `interface ReviewOptions { authoring?: boolean; pinnedDep?: unknown; knownAddresses?: Iterable<string>; codeSizes?: Record<string, number> \| Map<string, number>; chainLabel?: string; mode?: "classic" \| "enhanced"; v5Available?: boolean; langRequired?: boolean; }` | `client/review.ts` |
| `HonestyFinding` | `interface HonestyFinding { rule: HonestyRule; severity: "error" \| "warn"; path: string; message: string; fix: string; address?: string; }` | `chainc/honesty.ts` |
| `HonestyRule` | `type HonestyRule = "public-input" \| "public-secret" \| "live-claim" \| "unknown-address" \| "unbacked-claim" \| "stage-touch" \| "stage-pinch" \| "stage-own-toggle" \| "stage-safe-area" \| "p5-v1-api" \| "sign-message" \| "viewer-read" \| "transfer-history"` | `chainc/honesty.ts` |
| `HonestyOptions` | `interface HonestyOptions { knownAddresses?: Iterable<string>; codeSizes?: Record<string, number> \| Map<string, number>; chainLabel?: string; }` | `chainc/honesty.ts` |
| `StyleFamily` | `interface StyleFamily { family: string; nodes: readonly NodeType[]; values: readonly string[]; token: (v: string) => string; css: (v: string) => string; extra?: (v: string, sel: string) => string; summary: string; since: number; }` | `chainc/style-tokens.ts` |
| `HintSpec` | `interface HintSpec { key: string; nodes: readonly NodeType[]; value: RegExp; summary: string; viewer: string; since: number; }` | `chainc/hints.ts` |
| `PresentationFinding` | `type PresentationFinding = Omit<HonestyFinding, "rule"> & { rule: PresentationRule }` | `client/presentation-review.ts` |
| `PresentationRule` | `type PresentationRule = "style-token" \| "label-as-style" \| "heading-order" \| "scroll-region" \| "lang-missing" \| "v5-unavailable"` | `client/presentation-review.ts` |
| `PresentationReviewOptions` | `interface PresentationReviewOptions { v5Available?: boolean; langRequired?: boolean; chainLabel?: string; }` | `client/presentation-review.ts` |
| `ViewerKind` | `interface ViewerKind { kind: string; kindHex: '0x${string}'; contract: string; args: ResolverKindArg[]; accountArg: string; encoding: "abi" \| "packed"; image: boolean; canonicalEns: boolean; }` | `chainc/viewer-context.ts` |
| `CrArg` | `type CrArg = \| { ok: true; mode: "viewer" \| "history"; fields: Record<string, string> } \| { ok: false; error: string }` | `chainc/viewer-context.ts` |
| `PresentationContext` | `interface PresentationContext { version: number; present: boolean; themeId: '0x${string}'; overridePalette: boolean; palette: ContextPalette; overrideDims: boolean; chartW: number; chartH: number; overrideTokens: boolean; tokens: ReturnType<typeof tokensToOnchain>; ext: '0x${string}'; }` | `chainc/presentation-context.ts` |
| `ContextPalette` | `interface ContextPalette { bg: string; surface: string; fg: string; mutedFg: string; border: string; primary: string; primaryFg: string; danger: string; fontFamily: string; monoFamily: string; scale: { title: number; heading: number; body: number; label: number; legend: number }; weightBold: number; strokeStyle: string; radius: string; borderWidth: string; series: [string, string, string, string, string, string]; }` | `chainc/presentation-context.ts` |
| `SceneBinding` | `interface SceneBinding { kind: SceneKind; libHash: '0x${string}'; seed: '0x${string}'; entry: string; meta?: string; }` | `chainc/depscene.ts` |
| `SceneKind` | `type SceneKind = keyof typeof SCENE_NS` | `chainc/depscene.ts` |
| `ResolverKindDescriptor` | `interface ResolverKindDescriptor { kind: string; kindHex: '0x${string}'; summary: string; capability: number; consumeCapability?: number; dataEdge: "on-chain" \| "off-chain"; args: ResolverKindArg[]; argsEncoding?: "abi" \| "packed"; statements?: string[]; firstParty: true; extensible: true; note?: string; xchain?: { rootSources: string[]; ceilingBySource: Record<string, "A" \| "C">; hostFacetRequired?: boolean; instantUpgrades?: Record<string, boolean>; createsHomeClaim?: boolean; hostFacetResolver?: string; adopted?: boolean; }; contracts?: string[]; doesNotEstablish?: string[]; }` | `chainc/resolverkinds.ts` |
| `ResolverKindArg` | `interface ResolverKindArg { name: string; type: string; note?: string; }` | `chainc/resolverkinds.ts` |
| `ThemeTokens` | `interface ThemeTokens { version: number; color: { bg: string; surface: string; fg: string; mutedFg: string; muted: string; border: string; primary: string; primaryFg: string; accent: string; accentFg: string; success: string; successFg: string; warning: string; warningFg: string; danger: string; dangerFg: string; info: string; infoFg: string; hover: string; active: string; focus: string; disabled: string; selected: string; series1: string; series2: string; series3: string; series4: string; series5: string; series6: string; gradient?: Gradient; }; type: { fontFamily: string; monoFamily: string…` | `chainc/theme-tokens.ts` |
| `FontScale` | `interface FontScale { title: number; heading: number; body: number; label: number; legend: number; }` | `chainc/theme-tokens.ts` |
| `Gradient` | `interface Gradient { kind: "linear" \| "radial" \| "conic"; angle: number; stops: GradientStop[]; }` | `chainc/theme-tokens.ts` |
| `GradientStop` | `interface GradientStop { color: string; pos: number; }` | `chainc/theme-tokens.ts` |

## `@chainrender/client/runtime`

Off-chain runtime: render a deployed component with a free eth_call, fill its slots, turn declared actions into wallet requests, events, themes, local state.

```ts
import { renderComponent } from "@chainrender/client/runtime";
```

### Exports

#### `renderComponent`

```ts
async function renderComponent(dep: Deployment, hash: string): Promise<string>
```

Renders a stored component by its content hash through the RenderRouter (free `eth_call`). Returns the on-chain interpreter's HTML string — already escaped and safe to insert into an isolated container (a shadow root or sandboxed iframe under a strict CSP).

Source: `client/runtime/core.ts`

#### `enumerate`

```ts
async function enumerate(dep: Deployment): Promise<ComponentMeta[]>
```

Enumerates the registry (proof-of-concept on-chain list; a production app would use an event indexer — see the Explorer README). Returns each component's hash + basic metadata.

Source: `client/runtime/core.ts`

#### `decodeAbiString`

```ts
function decodeAbiString(hex: string): string
```

Decodes an ABI-encoded dynamic string return value (offset, length, data).

Source: `client/runtime/core.ts`

#### `splitArgs`

```ts
function splitArgs(raw: string): string[]
```

Splits an args template on top-level commas only, so bracketed/parenthesised groups (arrays, tuples) stay intact: "0xabc,[1,2,3],(x,y)" -> ["0xabc","[1,2,3]","(x,y)"].

Source: `client/runtime/core.ts`

#### `SELECTORS`

```ts
const SELECTORS = { … } as const
```

Function selectors for the RenderRouter / ComponentRegistry view functions used here. Precomputed (keccak of the signature, first 4 bytes) so the client needs no crypto lib.

Source: `client/runtime/core.ts`

#### `bindSlots`

```ts
async function bindSlots(root: ParentNode, resolvers: SlotResolvers): Promise<void>
```

Fills every `[data-cr-bind]` slot under `root` using the matching resolver, except `cr:` slots (see isCrArg). `root` can be a shadow root, an element, or a document fragment. For `<img>` slots the resolved value is a validated image src set on the element; for all other slots it is inserted as `textContent` (never parsed as HTML). Filled slots get the `cr-filled` class; slots with no matching resolver keep their on-chain fallback.

Source: `client/runtime/bind.ts`

#### `readAction`

```ts
function readAction(el: Element): ActionDeclaration | null
```

Reads a declarative submit action off a rendered button (its data-cr-* attributes), or null if the element carries no action.

Source: `client/runtime/bind.ts`

#### `readActions`

```ts
function readActions(root: ParentNode): ActionDeclaration[]
```

Collects every declared submit action under `root`.

Source: `client/runtime/bind.ts`

#### `isValidImageSrc`

```ts
function isValidImageSrc(src: string): boolean
```

Validates an image src the same way the on-chain interpreter does: only base64 data URIs for svg/png/jpeg, whose body is pure base64. Refuses javascript:, data:text/html, external URLs, and any body containing quotes/brackets — defense in depth on the client side.

Source: `client/runtime/bind.ts`

#### `isCrArg`

```ts
const isCrArg = (arg: string | null | undefined): boolean => …
```

_No doc comment in the source._

Source: `client/runtime/bind.ts`

#### `renderComponentWithContext`

```ts
async function renderComponentWithContext(dep: Deployment, hash: `0x${string}`, ctx: PresentationContext): Promise<string>
```

Render a stored component through the RenderRouter with a presentation context (free eth_call). Returns the on-chain interpreter's HTML — escaped and safe to insert into an isolated container, as with renderComponent().

Source: `client/runtime/context.ts`

#### `renderWithContextCalldata`

```ts
function renderWithContextCalldata(hash: `0x${string}`, ctx: PresentationContext): `0x${string}`
```

The eth_call data for renderHashWithContext(hash, ctx).

Source: `client/runtime/context.ts`

#### `RENDER_WITH_CONTEXT_ABI`

```ts
const RENDER_WITH_CONTEXT_ABI = [ … ] as const
```

The RenderRouter function this calls (contracts/RenderRouter.sol).

Source: `client/runtime/context.ts`

#### `staticResolvers`

```ts
const staticResolvers: SlotResolvers = { … }
```

Resolvers that need no chain access — safe defaults that work offline.

Source: `client/runtime/resolvers.ts`

#### `makeProviderResolvers`

```ts
function makeProviderResolvers(provider: EnsBalanceProvider): SlotResolvers
```

Builds resolvers backed by a provider (e.g. a viem PublicClient), for the bindings that need live data. Merge over `staticResolvers` for full coverage:

Source: `client/runtime/resolvers.ts`

#### `resolveArgs`

```ts
function resolveArgs(action: ActionDeclaration, inputs: Record<string, string> = {}): string[]
```

Resolves `$name` argument references against form inputs; literals pass through unchanged.

Source: `client/runtime/submit.ts`

#### `buildActionRequest`

```ts
function buildActionRequest(action: ActionDeclaration, inputs: Record<string, string> = {}): TxRequest
```

Builds the calldata + tx request for a declared action, filling `$input` refs from `inputs`.

Source: `client/runtime/submit.ts`

#### `describeAction`

```ts
function describeAction(action: ActionDeclaration, inputs: Record<string, string> = {}): string
```

A plain-language description of what a declared action would do, for user review before signing. Always show this — never trust the button's own label.

Source: `client/runtime/submit.ts`

#### `events` (namespace)

EventSource deferred-lock-in family + readEvents — doc 94. Namespaced to avoid the `custom` collision with the ThemeSource family (both families ship a `custom` escape hatch).

Source: `client/runtime/events.ts`

| Member | Signature | Summary |
|---|---|---|
| `events.eventTopic0` | `function eventTopic0(eventSig: string): '0x${string}'` | topic0 = the event selector (keccak of the canonical signature). |
| `events.eventTopics` | `function eventTopics(eventSig: string, indexedArgs?: Record<string, unknown>): ('0x${string}' \| null)[]` | The eth_getLogs topics: [topic0, …indexed-arg matches]. |
| `events.getLogs` | `function getLogs(rpc: string): EventSource` | on-chain via eth_getLogs (grade A). |
| `events.indexer` | `function indexer(query: (spec: EventSpec, opts?: { limit?: number }) => Promise<LogRecord[]>): EventSource` | off-chain (grade C). |
| `events.custom` | `function custom(read: EventSource["read"]): EventSource` | the always-available escape hatch — any log source. |
| `events.readEvents` | `async function readEvents(spec: EventSpec, opts: { rpc: string; source?: EventSource; limit?: number },): Promise<LogRecord[]>` | Convenience: read an EventSpec's feed. |

#### `MULTICALL3`

```ts
const MULTICALL3 = "0xcA11bde05977b3631167028862bE2a173976CA11" as const
```

Canonical deterministic Multicall3 (mds1/multicall3) — same address on every chain that has it deployed.

Source: `client/runtime/batch.ts`

#### `batchRead`

```ts
async function batchRead(specs: readonly CallSpec[], opts: { rpc: string; multicall?: `0x${string}` },): Promise<BatchResult[]>
```

Execute specs via Multicall3.aggregate3 in one eth_call. Order-preserving; each call fails closed independently.

Source: `client/runtime/batch.ts`

#### `themes` (namespace)

The on-chain theme render path — ThemeSource family (sourceStore/bundled/custom) + applyTheme + renderToShadow (doc 90, Phase 3). Namespaced as a sibling of `events`.

Source: `client/runtime/theme.ts`

| Member | Signature | Summary |
|---|---|---|
| `themes.sourceStore` | `function sourceStore(cssHash: '0x${string}', opts: { rpc: string; sourceStore: '0x${string}' }): ThemeSource` | On-chain: read CSS from `SourceStore.read(cssHash)` — content-addressed, immutable. |
| `themes.bundled` | `function bundled(css: string): ThemeSource` | On-chain-equivalent: a baked, inert CSS string (the doc-90 baked model). |
| `themes.custom` | `function custom(load: () => Promise<string>, opts?: { dataEdge?: "on-chain" \| "off-chain" }): ThemeSource` | Escape hatch: a developer-supplied loader (may reach a CDN/server). |
| `themes.applyTheme` | `async function applyTheme(root: ShadowRoot \| HTMLElement, source: ThemeSource): Promise<AppliedTheme>` | Inject a ThemeSource's CSS into a shadow root (or element) as a single scoped `<style data-cr-theme>`. |
| `themes.renderToShadow` | `async function renderToShadow(host: HTMLElement, html: string, source?: ThemeSource): Promise<ShadowRender>` | The full on-chain theme render path (doc 90): the component's on-chain HTML → a shadow root wrapped in a single `.cr-root`, with theme CSS applied. |

#### `DEFAULT_THEME_CSS`

```ts
const DEFAULT_THEME_CSS = ".cr-root{display:block;box-sizing:border-box;padding:var(--cr-space-md,12px);line-height:1.5;text-align:left;letter-spacing:normal;\n font-family:var(--cr-font, system-ui, …
```

client/runtime/default-theme.ts — the COMPLETE bundled default theme (Phase 3, theme-finish). BASE component theme (.wrap block: buttons/inputs/slots/headings/images/alerts/timeline/steps) + a11y INTERACTION states, --cr-*-tokenized, scoped under `.cr-root`. Explicit inherited-property resets (line-height/text-align/letter-spacing) for shadow isolation WITHOUT `all:initial` (which was found to interfere with the --cr-* token override / theming). Highlighted states filled + contrast-robust. 13 vars.

Source: `client/runtime/default-theme.ts`

#### `local` (namespace)

LocalStore family (memory/localStorage/indexedDB/custom) + settle — optimistic-local-state + on-chain settlement (doc 94, Phase 3 sub-step 4). Namespaced (custom collides with events/themes families).

Source: `client/runtime/local.ts`

| Member | Signature | Summary |
|---|---|---|
| `local.memory` | `function memory(): LocalStore` | In-memory (Map). |
| `local.localStorage` | `function localStorage(namespace = "cr"): LocalStore` | `localStorage`, namespaced + JSON-serialized. |
| `local.indexedDB` | `function indexedDB(dbName = "chainrender", storeName = "cr"): LocalStore` | IndexedDB — the persistent async store for larger/structured local state (game move logs, drafts). |
| `local.custom` | `function custom(impl: LocalStore): LocalStore` | The escape hatch — any developer-supplied store (a library, a server-backed store, whatever). |
| `local.settle` | `function settle(action: ActionDeclaration, selectiveData: Record<string, string> = {}): SettleResult` | Settle selected local results on-chain via the existing buildActionRequest. |

### Types

TypeScript types exported here (type-only: `import type { … }`):

| Type | Definition | Source |
|---|---|---|
| `Deployment` | `interface Deployment { rpc: string; router?: string; registry?: string; }` | `client/runtime/core.ts` |
| `ComponentMeta` | `interface ComponentMeta { hash: string; chunkCount: number; attestationSchema: string; }` | `client/runtime/core.ts` |
| `SlotResolver` | `type SlotResolver = (arg: string \| null, kind: string) => string \| Promise<string>` | `client/runtime/core.ts` |
| `SlotResolvers` | `type SlotResolvers = Record<string, SlotResolver>` | `client/runtime/core.ts` |
| `ActionDeclaration` | `interface ActionDeclaration { to: string \| null; sig: string; value: bigint; args: string[]; }` | `client/runtime/core.ts` |
| `EnsBalanceProvider` | `interface EnsBalanceProvider { getEnsName(args: { address: '0x${string}' }): Promise<string \| null>; getEnsAvatar(args: { name: string }): Promise<string \| null>; getBalance(args: { address: '0x${string}' }): Promise<bigint>; getChainId?(): Promise<number>; }` | `client/runtime/resolvers.ts` |
| `BatchResult` | `interface BatchResult { success: boolean; returnData: '0x${string}'; }` | `client/runtime/batch.ts` |

## `@chainrender/client/react`

React adapter over the runtime (react is a peer dependency).

```ts
import { useChainRenderComponent } from "@chainrender/client/react";
```

### Exports

#### `useChainRenderComponent`

```ts
function useChainRenderComponent(deployment: Deployment, hash: string): UseComponentResult
```

Fetches a component's on-chain-rendered HTML by hash. Re-fetches when hash/deployment change or when `refetch()` is called.

Source: `client/react/react.ts`

#### `ChainRenderView`

```ts
function ChainRenderView(props: ChainRenderViewProps)
```

Renders a ChainRender component into a style-isolated shadow root and fills its slots. The interpreter's HTML is already escaped; rendering into a shadow root keeps the host page's styles out and the component's markup contained.

Source: `client/react/react.ts`

### Types

TypeScript types exported here (type-only: `import type { … }`):

| Type | Definition | Source |
|---|---|---|
| `UseComponentResult` | `interface UseComponentResult { html: string \| null; loading: boolean; error: Error \| null; refetch: () => void; }` | `client/react/react.ts` |
| `ChainRenderViewProps` | `interface ChainRenderViewProps { deployment: Deployment; hash: string; resolvers?: SlotResolvers; styleSheet?: string; className?: string; }` | `client/react/react.ts` |

## `@chainrender/client/miniapp`

Farcaster Mini App distribution: manifest, embed tags, identity, wallet, notifications — all fail-closed outside a Farcaster host.

```ts
import { capabilitiesForEnvelope } from "@chainrender/client/miniapp";
```

### Exports

#### `capabilitiesForEnvelope`

```ts
function capabilitiesForEnvelope(envelope: number): string[]
```

Map a ChainRender capability envelope (the honesty bits) to the Mini App SDK capabilities the host must support. This carries ChainRender's capability honesty through to the Mini App layer: if the app declares on-chain writes/value/signing, it declares it needs a wallet provider here too.

Source: `client/miniapp/manifest.ts`

#### `buildManifest`

```ts
function buildManifest(cfg: MiniAppConfig, accountAssociation?: AccountAssociation): Record<string, unknown>
```

Build the `/.well-known/farcaster.json` manifest. Serve it at that path on `homeUrl`'s domain. Without an accountAssociation the app still runs as a standard web app / unverified Mini App; with it, the domain is provably owned by your FID and the app is discoverable + can notify.

Source: `client/miniapp/manifest.ts`

#### `buildEmbed`

```ts
function buildEmbed(embed: EmbedConfig): Record<string, unknown>
```

Build the embed object placed in the `fc:miniapp` meta tag on any page that shares the app.

Source: `client/miniapp/manifest.ts`

#### `buildEmbedMetaTags`

```ts
function buildEmbedMetaTags(embed: EmbedConfig): string
```

Render the embed as HTML meta tags — emits `fc:miniapp` plus the legacy `fc:frame` alias for hosts still on the older tag. Inject the result into the page `<head>`.

Source: `client/miniapp/manifest.ts`

#### `inMiniAppHost`

```ts
async function inMiniAppHost(): Promise<boolean>
```

Whether we're running inside a Mini App host (a Farcaster client webview). False for a plain page.

Source: `client/miniapp/runtime.ts`

#### `signalReady`

```ts
async function signalReady(opts?: { disableNativeGestures?: boolean }): Promise<void>
```

Signal to the host that the app has finished loading and can be shown. MUST be called once the ChainRender render is on screen, or the host shows an infinite splash. No-op outside a host.

Source: `client/miniapp/runtime.ts`

#### `mountChainRenderApp`

```ts
async function mountChainRenderApp(render: () => void | Promise<void>): Promise<void>
```

Render the ChainRender floor first, then signal ready. `render` is your own mount (e.g. inject the HTML from an eth_call into the DOM). The floor is visible even if the host/SDK never resolves.

Source: `client/miniapp/runtime.ts`

#### `currentUser`

```ts
async function currentUser(): Promise<FarcasterUser | null>
```

The current Farcaster user from host context (no signature), or null outside a host. Use this for a lightweight FID read; use signInWithFarcaster to get a verifiable SIWF credential.

Source: `client/miniapp/runtime.ts`

#### `signInWithFarcaster`

```ts
async function signInWithFarcaster(nonce: string): Promise<FarcasterUser | null>
```

Sign In With Farcaster: returns the FID + a SIWF message/signature to verify on your server, or null outside a host. `nonce` should come from your server to bind the session. Fails closed.

Source: `client/miniapp/runtime.ts`

#### `enableNotifications`

```ts
async function enableNotifications(): Promise<boolean>
```

Prompt the user to add the app, which enables notifications (the host then delivers a notification token to your manifest webhookUrl — send with sendMiniAppNotification server-side). Returns whether the prompt was shown; false outside a host.

Source: `client/miniapp/runtime.ts`

#### `miniAppWalletProvider`

```ts
async function miniAppWalletProvider(): Promise<unknown | null>
```

The host's embedded EIP-1193 wallet provider — the final gate for a ChainRender WRITE_CHAIN action when embedded — or null outside a host (fall back to the user's own injected wallet).

Source: `client/miniapp/runtime.ts`

#### `sendMiniAppNotification`

```ts
async function sendMiniAppNotification(n: NotificationSend): Promise<Response>
```

POST a Mini App notification to the host. Returns the raw Response; inspect it for the per-token result (delivered / rate-limited / invalid) per the Mini App spec. Server-side only.

Source: `client/miniapp/notify.ts`

### Types

TypeScript types exported here (type-only: `import type { … }`):

| Type | Definition | Source |
|---|---|---|
| `AccountAssociation` | `interface AccountAssociation { header: string; payload: string; signature: string; }` | `client/miniapp/manifest.ts` |
| `MiniAppConfig` | `interface MiniAppConfig { name: string; homeUrl: string; iconUrl: string; splashImageUrl?: string; splashBackgroundColor?: string; webhookUrl?: string; subtitle?: string; description?: string; primaryCategory?: string; tags?: string[]; requiredChains?: string[]; requiredCapabilities?: string[]; }` | `client/miniapp/manifest.ts` |
| `EmbedConfig` | `interface EmbedConfig { imageUrl: string; buttonTitle: string; appUrl: string; appName?: string; splashImageUrl?: string; splashBackgroundColor?: string; }` | `client/miniapp/manifest.ts` |
| `FarcasterUser` | `interface FarcasterUser { fid: number; username?: string; displayName?: string; pfpUrl?: string; siwf?: { message: string; signature: string }; }` | `client/miniapp/runtime.ts` |
| `NotificationSend` | `interface NotificationSend { url: string; tokens: string[]; notificationId: string; title: string; body: string; targetUrl: string; }` | `client/miniapp/notify.ts` |
