Model - References
API reference for src/schema/references 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.
COLLECTION_LANES
const
Lanes that have a CollectionNode — i.e. lanes whose MEMBERSHIP (which entries exist, in what order) can be pulled as a real dependency, separate from any entry's body.
Only the KEYED record lanes qualify: an entry needs a key to be addressable, and materials/layers/styles carry theirs in an expression name arg, so they have no key until something evaluates them.
tables is DELIBERATELY absent even though it is keyed. A table chain already references tables in the other direction (a table chain reading itself), so serving a collection of them would make the lane relation two-way — exactly the shape this file exists to surface rather than create. None has a consumer either. animations, skeletons and components were cut too (2026-07-26): each already sits on a declared relation (faceSkeleton.skeleton, placeComponent, and — since 2026-08-14's consumer-holds-the-reference redesign — joint.*Track / Operation.animation reaching INTO animations), and serving its membership added edges no consumer justifies — a collection is wired when a reader exists, not ahead of one.
SSOT for both Model._laneEntries (what it will serve) and the Graph page (what it draws feeding the collection). A lane in one and not the other is the kind of silent divergence this file exists to stop.
const COLLECTION_LANES: ("sheets" | "skeletons" | "animations" | "materials" | "layers" | "styles" | "textStyles" | "annotationStyles" | "cameras" | "views" | "components" | "textures" | "tables")[]LANE_REFERENCES
const
const LANE_REFERENCES: LaneReference[]LANE_SCOPE
const
Lane → how deep a name resolves inside its body. DERIVED from LANES plus the two PSEUDO-lanes the edge table below has to name (parameters and scene are the root header and body, not arrays of entries).
Notes on the non-obvious classifications, which live here because this is the file that explains the mechanism:
components/texturesare functions:.parentcut, entered only through placement args.sheetsruns its ad hoc operations through evaluateFlatOperations, which shares the same isolated-scope builder and (since 2026-07-26) is handed the sheet's ownparameters— a function with a real signature rather than an isolated scope with nothing in it.
The title of a sheet is deliberately NOT covered by any of this: a title is lane HEADER data (what a drawing index reads through CollectionNode), so Model._evaluateLaneExpression evaluates it against the model's parameters WITH the lane's own layered on top.
const LANE_SCOPE: Record<string, LaneScope>LaneReference
type
One declared cross-lane edge.
type LaneReference
// = {
/**
* Lane that holds the reader (`"scene"` = the root operations fold), or
* `lane.branch` when the lane is a CHAIN whose parts reach different
* places. A component is a mini-model — `parameters` plus `operations` —
* and every reference it makes is written in the BODY: the definition
* itself is a function of its own signature and reaches nothing. Saying
* `components` reads tables attributes the body's edge to the definition,
* which is the difference between "a definition depends on host state"
* (false, and the thing isolation exists to prevent) and "code inside it
* does" (true).
*/
from: string;
/** Lane the reader reaches, same `lane.branch` form when it matters. */
to: string;
/** `method.arg` when carrier is "arg" (checked against the registry and
* the lane method tables); the hook's `Type.field` when "hook" (checked
* to exist in the engine source); a short phrase when "expression". */
via: string;
carrier: ReferenceCarrier;
mechanism: "reference" | "key" | "name" | "scene";
/** What to call this edge on the Graph page. Needed for `hook` edges,
* whose `via` is an INTERNAL wire name (`ResolveTextureOptions
* .resolveTable`) that an author never writes and cannot look up —
* drawn raw it reads as a mystery. Say the author-facing thing instead
* ("Table.get"). Arg edges name a real method.arg, so they need none. */
label?: string;
note: string;
}ReferenceCarrier
type
WHERE an edge physically lives. Three answers, and forcing all three into method.arg is how this table first got written — which produced entries like "views→materials via viewSection.depth", an arg that has nothing to do with materials, picked only because the guard demanded a method and an arg.
arg— an author writes the target's key/name in that arg.hook— nobody writes it: the resolver is HANDED the lane the document, real in the dependency graph.expression— any expression in the reading lane may reach it (a parameter key, Table.get, Material.get).
type ReferenceCarrier
// = "arg" | "hook" | "expression"