Skip to content
Shapemetry

@huukhanhnguyen/model / core/rootFold

core/rootFold

materialsResolverOf

const materialsResolverOf: WeakMap<NodeCollection<any>, () => MaterialData[]>


sceneNodeOf

const sceneNodeOf: WeakMap<NodeCollection<any>, SceneNode<ScenePull>>


collectFonts()

collectFonts(nodes): AssetFile[]

Parameters

nodes

NodeCollection<any>

Returns

AssetFile[]


collectGeometryFromSlices()

collectGeometryFromSlices(nodes, slices, diagnostics?): GeometryNode[]

Parameters

nodes

NodeCollection<any>

slices

Map<string, ObjectData[]> | null

diagnostics?

EvaluateDiagnostic[]

Returns

GeometryNode[]


collectMaterials()

collectMaterials(nodes): MaterialData[]

Exported for render hosts: the resolved material records reaching this collection (materials[] nodes evaluated + texture-attached, via the owning Model's SnapshotLaneNode pull — see materialsResolverOf) — a host syncs these into its material table on every render pass so node edits show up live. A registry may supply its own builtinMaterials (e.g. the tree node's bark/leaf textures, stamped by name with no doc-lane record) — merged UNDER the doc lane here so a doc record with the same name always wins.

Parameters

nodes

NodeCollection<any>

Returns

MaterialData[]


collectParams()

collectParams(nodes): ParamInfo[]

Parameters

nodes

NodeCollection<any>

Returns

ParamInfo[]


collectRenderFrame()

collectRenderFrame(nodes): RenderFrameSlice[]

One SNAPSHOT of everything renderable. When nodes is a Model-owned collection, pulls the SceneNode cache (single fold with tessellate/sceneFrame). Bare collections (tests without a Model) fold directly.

Parameters

nodes

NodeCollection<any>

Returns

RenderFrameSlice[]


frameFromSlices()

frameFromSlices(nodes, slices): RenderFrameSlice[]

Build a render frame from fold slices (or Group values when no fold). Pure over already-collected slices — does NOT re-run the root fold.

Parameters

nodes

NodeCollection<any>

slices

Map<string, ObjectData[]> | null

Returns

RenderFrameSlice[]


frameLeaves()

frameLeaves(frame): ObjectData[]

Every leaf a whole frame carries, in world space — sliceLeaves over each slice, in declaration order.

Parameters

frame

RenderFrameSlice[]

Returns

ObjectData[]


modelCombinationFromSlices()

modelCombinationFromSlices(nodes, slices, patterns?): ObjectData[]

Parameters

nodes

NodeCollection<any>

slices

Map<string, ObjectData[]> | null

patterns?

Pattern[]

Returns

ObjectData[]


nodeGeometry()

nodeGeometry(node, dataOverride?, diagnostics?): { instances?: GeometryPlacement[]; items: GeometryItem[]; material?: string; packs?: { instances: GeometryPlacement[]; items: GeometryItem[]; }[]; } | null

Render a single generator node's value into its GeometryNode content: { items, instances?, material? } (or null if it renders nothing). The definition of the split — instanced vs baked — lives HERE so both the engine's collectGeometry and the host's incremental re-render use the same rule.

Instanced path: value = blockData wrappers only → geometry once per shared children array + placements. Single nest → items+instances. Several nests (multi-member array) → packs[] (each nest once). Baked path (mixed / explode / raw): flatten to concrete leaf geometry.

Parameters

node

DataNode | ContainerNode

dataOverride?

ObjectData[]

diagnostics?

EvaluateDiagnostic[]

Returns

{ instances?: GeometryPlacement[]; items: GeometryItem[]; material?: string; packs?: { instances: GeometryPlacement[]; items: GeometryItem[]; }[]; } | null


rootBodyNodes()

rootBodyNodes(nodes): (DataNode | ContainerNode)[]

Top-level body nodes (the root fold list), in declaration order.

Parameters

nodes

NodeCollection<any>

Returns

(DataNode | ContainerNode)[]


rootFoldSlices()

rootFoldSlices(nodes): Map<string, ObjectData[]> | null

Run the root fold and slice the result per source node key. Returns null when the model has no root-level scene steps (Group values render directly — no fold pass needed). Throws a named "Circular dependency" error when a self-referential whole-scene embed (cycleGate) re-enters.

Parameters

nodes

NodeCollection<any>

Returns

Map<string, ObjectData[]> | null


sliceLeaves()

sliceLeaves(slice): ObjectData[]

Every leaf ONE slice carries, in WORLD space.

The frame keeps the two channels APART on purpose — blocks exists so a renderer can place one shared tessellation N times instead of N copies of the geometry. A reader that only wants the geometry (a table scan, an expression, a writer with no instancing slot) wants them composed instead, and composing them means baking each placement's matrix into its content. Every such reader calls THIS, so "did you remember the blocks channel?" is asked once here rather than at each of them — a reader that forgets it silently publishes a scene missing every placed assembly.

Parameters

slice

RenderFrameSlice

Returns

ObjectData[]

Last updated: 📖 4 min readEdit on GitHub