SceneModel ​Contract 2.0.0 · package sha256
a857eca95b35921109faf997094bb4192f12527d9d0fcd4be7e97f06425bad6e· generated fromconfigurator-runtime.d.tsbyservices/onsite-scripter/scripts/build-contract-docs.mjs; edit the source, not this file.
Interface · import type { SceneModel } from '@holostep-configurators/runtime-client/contract'; · stable · since 2.0.0 · section 21. Stored data (vendored; replaces @holo/interfaces)
What the runtime renders: the IConfigurator fields it reads. IConfigurator stays assignable to
it. The runtime's copy (getSceneModel()) carries no key material: never save it as is.
The package has no tree helpers: the runtime never prices, and in an app with its own store the
store owns the model (one scene-model writer). The example's helpers are the app-side ones a
page writes once; run withNode on the store's document, then sync.
| Member | Kind | Summary |
|---|---|---|
root |
property | The node tree. |
defaultNodeId? |
property | As IConfigurator.defaultNodeId. |
connections? |
property | Input only: getSceneModel(), state().model and the events never carry it (read assembly.connections()). |
connectionsBasis? |
property | Input only, as connections. |
defaultView? |
property | Stored data the app converts with cameraViewFromStored, then passes to camera.set; a scene write never moves the camera (IDefaultView). |
presets? |
property | |
attributes? |
property | |
parameters? |
property | |
toneMapping? |
property | Carried for a spread IConfigurator; never read (IConfigurator.toneMapping). |
backgroundColor? |
property | As IConfigurator.backgroundColor: a non-null value is the scene model's background layer (BackgroundValue). |
hdrUrl? |
property | Carried for a spread IConfigurator; never read (IConfigurator.hdrUrl). |
name? |
property | |
_id? |
property |
export interface SceneModel {
root: ConfiguratorNode[];
defaultNodeId?: string;
connections?: Connection[];
connectionsBasis?: string;
defaultView?: IDefaultView;
presets?: IPreset[];
attributes?: Record<string, unknown>;
parameters?: Record<string, unknown>;
toneMapping?: string;
backgroundColor?: BackgroundValue;
hdrUrl?: string;
name?: string;
_id?: string;
}
Imports: values (has, validate, the Holo*Error classes, the pure helpers) from @holostep-configurators/runtime-client, types from @holostep-configurators/runtime-client/contract, /math and /testing names from those entries; boot from the runtime module the root's loadRuntimeAtFloor resolves to. A type your page defines is your app's: declare it there, never import it from the package.
Compiled under the contract's strict settings (examples/declaration/21-SceneModel.ts):
import type { ConfiguratorNode, DeepReadonly, SceneModel, Session } from '@holostep-configurators/runtime-client/contract';
declare const session: Session;
declare const signal: AbortSignal;
// A node anywhere in the tree, by nodeId.
export function findNode(
nodes: readonly DeepReadonly<ConfiguratorNode>[],
nodeId: string,
): DeepReadonly<ConfiguratorNode> | null {
for (const node of nodes) {
if (node.nodeId === nodeId) return node;
const found = findNode(node.children ?? [], nodeId);
if (found) return found;
}
return null;
}
// A copy with `node` added under `parentId` (at the root without one), the rest untouched.
export function withNode(
model: DeepReadonly<SceneModel>,
node: ConfiguratorNode,
parentId?: string,
): SceneModel {
const copy = structuredClone(model) as SceneModel;
const addUnder = (nodes: ConfiguratorNode[]): boolean =>
nodes.some((n) => {
if (n.nodeId !== parentId) return addUnder(n.children ?? []);
n.children = [...(n.children ?? []), node];
return true;
});
if (parentId === undefined) copy.root.push(node);
else if (!addUnder(copy.root)) throw new Error(`no node ${parentId}`);
return copy;
}
// A global-material group's selected material: `select(group, material)` records it as the
// group's `defaultNodeId`. Prices are your app's: read them from your catalogue by this id.
export function selectedMaterial(model: DeepReadonly<SceneModel>, group: string): string | null {
const node = findNode(model.root, group);
return node?.type === 'GroupNode' ? (node.defaultNodeId ?? null) : null;
}
| Rule | Result |
|---|---|
| 1. Neutral name | pass: SceneModel names no product |
| 2. A precedent | not recorded: no ledger row (coverage.json) names this member or its owner |
| 3. Two apps, or labs | pass: 20 apps (fleet cross-check: app-04c2774145, app-0c773a4ee3, app-37356bf09f, app-4762caacdc, app-4fd23bc869, app-822bb9d6aa, app-8675b3225c, app-b362a81c85 and 12 more) |
| 4. The cheaper fix first | not recorded per member (Appendix B decides it per need) |