@huukhanhnguyen/model / core/rootFold
core/rootFold
materialsResolverOf
constmaterialsResolverOf:WeakMap<NodeCollection<any>, () =>MaterialData[]>
sceneNodeOf
constsceneNodeOf:WeakMap<NodeCollection<any>,SceneNode<ScenePull>>
collectFonts()
collectFonts(
nodes):AssetFile[]
Parameters
nodes
NodeCollection<any>
Returns
collectGeometryFromSlices()
collectGeometryFromSlices(
nodes,slices,diagnostics?):GeometryNode[]
Parameters
nodes
NodeCollection<any>
slices
Map<string, ObjectData[]> | null
diagnostics?
Returns
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
collectParams()
collectParams(
nodes):ParamInfo[]
Parameters
nodes
NodeCollection<any>
Returns
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
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
frameLeaves()
frameLeaves(
frame):ObjectData[]
Every leaf a whole frame carries, in world space — sliceLeaves over each slice, in declaration order.
Parameters
frame
Returns
modelCombinationFromSlices()
modelCombinationFromSlices(
nodes,slices,patterns?):ObjectData[]
Parameters
nodes
NodeCollection<any>
slices
Map<string, ObjectData[]> | null
patterns?
Pattern[]
Returns
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
dataOverride?
diagnostics?
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.