Model
A compiled parametric model: value nodes (the parameters header) plus one flat body fold (the operations list) that evaluates to a scene tree.
Root = container
The root IS a container: its top-level body nodes fold exactly like any nested operations list (producers/containers concat into the root stream, root-level transforms process it, in listed order — rootFoldSlices). It is a DEFINITION — it has no instances lane, because a model carries no transform of its own. Placement is the consumer's job: placeModel/clone supply the instances when this definition is placed inside another model.
Materials and layers
Declared as value nodes in parameters with method:"createMaterial" or method:"createLayer". They register named resources in the Store before evaluation; resolved values are returned in evaluate().materials / evaluate().layers. The toScene() packet references them by name only (bodies resolved from the Store at render time).
{ "method": "createMaterial", "key": "material",
"args": [{ "key": "name", "input": "'oak'" }, { "key": "baseColor", "input": "'#c8a96e'" }] }Source: packages/parametric/src/nodes/Model.ts
Properties
| Name | Type | Description |
|---|---|---|
id | string | Unique model ID (empty string for unsaved models). |
name | string | Display name of the model. |
nodes | NodeCollection<ChildNode> | Flat ordered collection of every node in the model (header value nodes first, then the body fold list — see modelSections). |
unit | UnitConfig | Measurement unit config (default: { length: "mm" }). |
scope | ModelScope | Expression evaluation scope shared across all nodes in this model. |
Methods
| Signature | Description |
|---|---|
convertUnit(unitType: string, newUnit: string): void | Convert all unit-carrying literals in the model from Applies to:
Uses dimensional inference to only convert literals that carry physical units (not dimensionless counts or ratios). Cross-param references resolve their own inputs independently, so expressions like |
toJSON(): ModelJSON | Serialize the model back to a ModelJSON document (v21: the flat runtime collection partitions back into parameters[] / operations[] by lane — value nodes and header containers are parameters, the rest is the body). |
evaluate(params: Record<string, unknown>): EvaluateResult | Evaluate the model with optional parameter overrides; returns the full render result. Every asset (fonts/images/sub-models) is pre-loaded in the Store, so the graph itself never does async I/O — this call always returns synchronously. A node's OWN registry-supplied compute() may still be maybe-async (see registry/contract.ts): ParaShape's bundled node registry stays 100% synchronous by policy, so this stays true in practice, but the return value can reflect a still-pending node if some OTHER registry's compute hasn't settled yet (it settles later via that node's own notify cascade). |
bakeValue(value: unknown[] | undefined): EntityJSON[] | Bake a node's value (an EntityJSON[] that may mix leaf entities with nested groupEntity placements) into flat leaf entities, resolving this model's group definitions. A host or test that reads node.value directly uses this to get concrete geometry. Delegates to the scope so a node-tree consumer reaching the same scope via its own .model getter (e.g. a hover preview) shares the identical bake logic. |
toScene(params: Record<string, unknown>): SceneJSON | Produce a JSON-safe SceneJSON packet for a host renderer (Three.js / SketchUp). Runs the full evaluation first (evaluate() — one shared compute path), then formats the already-computed node values into the pure-geometry SceneJSON tree (materials / layers / fonts referenced by name, bodies resolved from the Store). |