Skip to content
Shapemetry

Model - Registry

API reference for src/schema/registry, src/conventions/registry, src/registry/Registry, src/validate/registry on @huukhanhnguyen/model, reachable from ..

See the Guide for the ModelJSON / evaluate pipeline.

API reference

Signatures are generated from the live package .d.ts - not hand-written.

ArgDef

type

The RUNTIME arg definition — the registry contract for OperationDefinition.args. The AUTHORED/catalog arg shape (typed label/tooltip/options/description fields) is NodeArgEntry (schema/nodesRegistry.ts); nodesRegistry/wiring.ts's toArgDef packs those into the opaque attributes bag below, so the two layers never drift.

type ArgDef
// = {
    key: string;
    type: string;
    default?: string;
    min?: string;
    max?: string;
    step?: string;
    attributes?: Record<string, unknown>;
}

ChainState

type

type ChainState
// = Entity[]

ComputeArgs

type

Evaluated + coerced arg values, keyed by ArgDef.key.

type ComputeArgs
// = Record<string, unknown>

ComputeContext

type

  • store — session asset registry (fonts/materials/images/models), immutable during eval.
  • definitions — model definition registry (id → shared geometry) for resolving nested blocks.
type ComputeContext
// = {
    store?: StoreHost;
    definitions?: DefinitionMap;
    /** True when the calling node evaluates in a 2D context: the node itself
     *  (or an ancestor container) is declared `flat: true`, or it sits in a
     *  "flat" lane (a sheet's ad hoc operations / flat component content —
     *  see schema/model.ts's FLAT_LANE_METHODS). Enforcement (flat
     *  vocabulary gate, point-arg z=0, per-step force-flatten) is
     *  engine-owned in EntitiesNode; methods may read this to keep their
     *  own output planar. Always false for value nodes. */
    flat: boolean;
    /** The model's materials[] lane. */
    materials?: Material[];
    /** The model's textStyles[] / annotationStyles[] lanes, RESOLVED. A
     *  drafting mark builds its drawn form at evaluate time, which is when the
     *  style has to be known — see nodesRegistry/wiring.ts's
     *  STYLE_AWARE_METHODS. A name matching neither a record here nor the
     *  builtin "standard" throws rather than drawing something arbitrary. */
    textStyles?: TextStyle[];
    annotationStyles?: AnnotationStyle[];
    /** Resolve a textures-lane chain to its evaluated ImageBuffer (displace). */
    sampleTexture?: (key: string) => unknown;
    /** Resolve a url-method parameter KEY to its literal url (falls back to
     *  the ref itself when no parameter matches, so a direct https:/data: URI
     *  passes through unchanged) — imageEntity's `name` arg. */
    imageUrlOf?: (name: string) => string;
}

ConventionRegistry

class

class ConventionRegistry

Members: all, get, register

createRegistry

function

Merge the engine's own builtins + the given RegistryInput into a validated Registry. registry.nodes (OperationDefinition[]) is itself the serializable view docs/UI menus render from — nothing to strip, create/compute are just unused function properties for a consumer that only reads attributes/args.

createRegistry(input?: RegistryInput): Registry

EntityDefinition

type

type EntityDefinition
// = OperationDefinitionBase & { foldRole: "producer" | "transform"; /** PRODUCER form — the engine concats [...input, ...create(args, context)]. */ create?: (args: ComputeArgs, context: ComputeContext) => ChainState | Promise<ChainState>

FoldRole

type

How a method participates in evaluation — orthogonal to the value type: a binding returns "length", a producer returns "entity[]", a material step returns "material"; the fold role is what the engine dispatches on.

type FoldRole
// = "binding" | "producer" | "transform" | "step"

FunctionNamespaces

type

type FunctionNamespaces
// = Record<string, Record<string, (...args: unknown[]) => unknown>>

mergeConventions

function

Build a registry from a base set plus any pack sets, later wins per lane — the same last-writer merge createRegistry uses for nodes.

mergeConventions(...sets: Convention[][]): ConventionRegistry

OperationDefinition

type

type OperationDefinition
// = ValueDefinition | EntityDefinition | StepDefinition

Registry

class

Registry — the merged, validated view over the engine's own builtins plus one flat RegistryInput. Built ONCE per composition via createRegistry(input) and passed to Model.fromJSON(json, { registry }); there is no module-global mutable registry. Two registries can coexist in one process.

v21 — ONE table of OperationDefinitions, keyed by globally-unique method. The container form has no method and never appears here.

class Registry

Members: argDefs, argKeys, argTypes, defaultKeyOf, entity, has, isReservedKey, methods, operation, typeOf, value

registryErrors

function

registryErrors(model: ModelJSON, registry: Registry): RegistryError[]

RegistryInput

type

The flat input createRegistry(input) merges onto the engine's own builtins. List order = display/catalog order (there is deliberately no order metadata).

  • namespaces — PascalCase expression namespaces (Point., Vector., …). Names become reserved (node keys cannot shadow them).
  • types — extra value types. These are INERT: display + coerce hook only — they never join the core dimension lattice (unit inference).
  • builtinParameters — reserved parameter keys auto-seeded per model (e.g. lengthX/lengthY/lengthZ).
  • builtinParameterMethods — for each builtinParameters/catalogParameters key, the value method required to legitimately claim it (e.g. { lengthX: "length", lengthY: "length" }). A builtin key absent here is reserved outright: no node may ever take it.
  • catalogParameters — reserved app-layer identity parameter keys (host-injected; core ships the mechanism empty — no domain vocabulary) (manufacturer/sku/price/currency/productUrl). Reserved exactly like builtinParameters (a key is claimable only by a value node whose method matches builtinParameterMethods) but deliberately NOT part of that set: builtinParameters doubles as the auto-seed list AND the host-facing filter (the viewer element, the /embed postMessage SDK and the ConfiguratorPanel all hide builtinParameters from their parameter lists), and catalog params must STAY VISIBLE — a shop needs price/currency in parashape:ready/parashape:change and in the evaluate API output. Never auto-seeded: a model without catalog metadata simply omits them.
  • builtinMaterials — named material records a node set's own generators stamp by name (e.g. the tree node's bark/leaf textures) but that don't live in any document's materials[] lane. Merged UNDER the doc lane by the engine's material collector (Model.ts's collectMaterials) — a doc record with the same name always overrides a builtin one.
type RegistryInput
// = {
    nodes?: OperationDefinition[];
    namespaces?: FunctionNamespaces;
    types?: TypeDef[];
    builtinParameters?: string[];
    builtinParameterMethods?: Record<string, string>;
    catalogParameters?: string[];
    builtinMaterials?: Material[];
}

StepDefinition

type

Linear-lane step (docs/views/materials/layers/styles/helpers/lights/cameras). No entity-fold create/compute — the lane's own evaluator is the sole consumer.

type StepDefinition
// = OperationDefinitionBase & { foldRole: "step"; }

TypeName

type

A TYPE_REGISTRY name, optionally with a list suffix (entity[], length[]). INPUT arg types and OUTPUT returns share this vocabulary.

type TypeName
// = string

ValueDefinition

type

type ValueDefinition
// = OperationDefinitionBase & { foldRole: "binding"; /** Optional value-build hook for a registry-declared resource lookup; * scalar parameters omit it — their value is the evaluated primary arg. */ compute?: (args: ComputeArgs, context: ComputeContext) => unknown | Promise<unknown>
Last updated: 📖 3 min readEdit on GitHub