Skip to content
Shapemetry

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 / textures are functions: .parent cut, entered only through placement args.
  • sheets runs its ad hoc operations through evaluateFlatOperations, which shares the same isolated-scope builder and (since 2026-07-26) is handed the sheet's own parameters — 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"
Last updated: 📖 3 min readEdit on GitHub