@vizij/render 0.1.1 → 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -2,49 +2,11 @@ import * as react_jsx_runtime from 'react/jsx-runtime';
2
2
  import * as react from 'react';
3
3
  import { CSSProperties, ComponentProps, ReactNode, RefObject, MouseEvent } from 'react';
4
4
  import { Canvas, ThreeEvent } from '@react-three/fiber';
5
- import * as zustand from 'zustand';
6
5
  import * as THREE from 'three';
7
- import { Mesh, Group as Group$1, BufferGeometry, ShapeGeometry, AnimationClip, Object3D } from 'three';
6
+ import { BufferGeometry, ShapeGeometry, ToneMapping, Group as Group$1, Mesh, AnimationClip, Object3D } from 'three';
7
+ import * as zustand from 'zustand';
8
8
  import { RawValue, AnimatableValue, RawVector2 } from '@vizij/utils';
9
9
 
10
- interface VizijProps {
11
- style?: CSSProperties;
12
- className?: string;
13
- rootId: string;
14
- namespace?: string;
15
- showSafeArea?: boolean;
16
- showSelectionGlow?: boolean;
17
- onPointerMissed?: ComponentProps<typeof Canvas>["onPointerMissed"];
18
- }
19
- /**
20
- * Renders the Vizij component.
21
- *
22
- * @param style - The style object for the Vizij component.
23
- *
24
- * @param className - The CSS class name for the Vizij component
25
- *
26
- * @param rootId - The root identifier for the Vizij component.
27
- *
28
- * @param namespace - The namespace for the Vizij component
29
- *
30
- * @param showSafeArea - Whether to show the safe area.
31
- *
32
- * @returns The rendered ReactNode.
33
- */
34
- declare function Vizij({ style, className, rootId, namespace, showSafeArea, showSelectionGlow, onPointerMissed, }: VizijProps): ReactNode;
35
- interface InnerVizijProps {
36
- rootId: string;
37
- namespace: string;
38
- container?: {
39
- width: number;
40
- height: number;
41
- resolution: number;
42
- };
43
- showSafeArea?: boolean;
44
- showSelectionGlow?: boolean;
45
- }
46
- declare function InnerVizij({ rootId, namespace, container, showSafeArea, showSelectionGlow, }: InnerVizijProps): react_jsx_runtime.JSX.Element;
47
-
48
10
  /**
49
11
  * A wrapping type to reference an attribute that is animatable.
50
12
  *
@@ -92,7 +54,6 @@ interface RenderableBase {
92
54
  name: string;
93
55
  tags: string[];
94
56
  type: string;
95
- refs: Record<string, RefObject<any>>;
96
57
  features: Record<string, Feature>;
97
58
  }
98
59
 
@@ -109,19 +70,17 @@ interface Stored<T extends Omit<RenderableBase, "refs">> {
109
70
  type StoredRenderable = Stored<RenderableBase>;
110
71
 
111
72
  /**
112
- * An object for creating hierarchies/bodies
73
+ * An object for creating rectangles
113
74
  *
114
- * @param id - The id of the ellipse
115
- * @param name - The name of the ellipse
116
- * @param tags - The tags of the ellipse
75
+ * @param id - The id of the rectangle
76
+ * @param name - The name of the rectangle
77
+ * @param tags - The tags of the rectangle
117
78
  * @param type - Type flag
118
- * @param refs - The reference to the group[s] in the scene, for each namespace
119
- * @param features - The features of the ellipse (translation, rotation, and scale)
120
- * @param children - The children of the ellipse (list of ids for other bodies or shapes)
79
+ * @param features - The features of the rectangle (translation, rotation, and scale)
80
+ * @param children - The children of the rectangle (list of ids for other bodies or shapes)
121
81
  */
122
- interface Ellipse extends RenderableBase {
123
- type: "ellipse";
124
- refs: Record<string, RefObject<Mesh>>;
82
+ interface Rectangle extends RenderableBase {
83
+ type: "rectangle";
125
84
  features: {
126
85
  height: Feature;
127
86
  width: Feature;
@@ -130,28 +89,27 @@ interface Ellipse extends RenderableBase {
130
89
  fillColor?: Feature;
131
90
  strokeColor?: Feature;
132
91
  strokeWidth?: Feature;
92
+ strokeRadius?: Feature;
133
93
  strokeOffset?: Feature;
134
94
  translation: Feature;
135
95
  rotation: Feature;
136
96
  };
137
97
  }
138
- type EllipseFeature = keyof Ellipse["features"];
139
- type StoredEllipse = Stored<Ellipse>;
98
+ type RectangleFeature = keyof Rectangle["features"];
99
+ type StoredRectangle = Stored<Rectangle>;
140
100
 
141
101
  /**
142
- * An object for creating rectangles
102
+ * An object for creating hierarchies/bodies
143
103
  *
144
- * @param id - The id of the rectangle
145
- * @param name - The name of the rectangle
146
- * @param tags - The tags of the rectangle
104
+ * @param id - The id of the ellipse
105
+ * @param name - The name of the ellipse
106
+ * @param tags - The tags of the ellipse
147
107
  * @param type - Type flag
148
- * @param refs - The reference to the group[s] in the scene, for each namespace
149
- * @param features - The features of the rectangle (translation, rotation, and scale)
150
- * @param children - The children of the rectangle (list of ids for other bodies or shapes)
108
+ * @param features - The features of the ellipse (translation, rotation, and scale)
109
+ * @param children - The children of the ellipse (list of ids for other bodies or shapes)
151
110
  */
152
- interface Rectangle extends RenderableBase {
153
- type: "rectangle";
154
- refs: Record<string, RefObject<Mesh>>;
111
+ interface Ellipse extends RenderableBase {
112
+ type: "ellipse";
155
113
  features: {
156
114
  height: Feature;
157
115
  width: Feature;
@@ -160,14 +118,13 @@ interface Rectangle extends RenderableBase {
160
118
  fillColor?: Feature;
161
119
  strokeColor?: Feature;
162
120
  strokeWidth?: Feature;
163
- strokeRadius?: Feature;
164
121
  strokeOffset?: Feature;
165
122
  translation: Feature;
166
123
  rotation: Feature;
167
124
  };
168
125
  }
169
- type RectangleFeature = keyof Rectangle["features"];
170
- type StoredRectangle = Stored<Rectangle>;
126
+ type EllipseFeature = keyof Ellipse["features"];
127
+ type StoredEllipse = Stored<Ellipse>;
171
128
 
172
129
  /**
173
130
  * An object for creating hierarchies/groups
@@ -176,14 +133,12 @@ type StoredRectangle = Stored<Rectangle>;
176
133
  * @param name - The name of the group
177
134
  * @param tags - The tags of the group
178
135
  * @param type - Type flag
179
- * @param refs - The reference to the group[s] in the vizij, for each namespace
180
136
  * @param features - The features of the group (translation, rotation, and scale)
181
137
  * @param root - Whether the group is a root node
182
138
  * @param children - The children of the group (list of ids for other groups or shapes)
183
139
  */
184
140
  interface Group extends RenderableBase {
185
141
  type: "group";
186
- refs: Record<string, RefObject<Group$1>>;
187
142
  root: boolean;
188
143
  features: {
189
144
  translation: Feature;
@@ -209,7 +164,6 @@ type StoredGroup = Stored<Group>;
209
164
  * @property name - Human-readable name for the shape
210
165
  * @property tags - List of tags for categorizing and filtering
211
166
  * @property type - Always "shape"
212
- * @property refs - Map of React refs to Three.js Mesh objects
213
167
  * @property features - Visual and transformation properties that can be animated
214
168
  * @property material - The type of Three.js material to use for rendering
215
169
  * @property geometry - The Three.js geometry defining the shape's structure
@@ -220,13 +174,15 @@ type StoredGroup = Stored<Group>;
220
174
  */
221
175
  interface Shape extends RenderableBase {
222
176
  type: "shape";
223
- refs: Record<string, RefObject<Mesh>>;
224
177
  features: {
225
178
  shininess?: Feature;
226
179
  opacity?: Feature;
227
180
  roughness?: Feature;
228
181
  metalness?: Feature;
229
182
  color?: Feature;
183
+ emissive?: Feature;
184
+ emissiveIntensity?: Feature;
185
+ specular?: Feature;
230
186
  translation: Feature;
231
187
  rotation: Feature;
232
188
  scale?: Feature;
@@ -252,8 +208,6 @@ declare enum ShapeMaterial {
252
208
  type ShapeFeature = keyof Shape["features"];
253
209
  type StoredShape = Stored<Omit<Shape, "geometry">>;
254
210
 
255
- type World = Record<string, Group | Ellipse | Rectangle | Shape>;
256
-
257
211
  type RenderableFeature = GroupFeature | EllipseFeature;
258
212
 
259
213
  /**
@@ -276,6 +230,57 @@ interface Selection {
276
230
  };
277
231
  }
278
232
 
233
+ type World = Record<string, Group | Ellipse | Rectangle | Shape>;
234
+
235
+ /**
236
+ * Vizij-level tone-mapping selection.
237
+ *
238
+ * This is a stable, serializable string enum rather than a raw three.js
239
+ * constant so it can be persisted in the `VIZIJ_bundle` extension and round-trip
240
+ * through import/export without leaking three's numeric enum values into stored
241
+ * data.
242
+ *
243
+ * - `"none"` — no tone mapping. Values are written to the framebuffer as-is and
244
+ * clip at 1.0. This matches plain web/canvas rendering and is the historical
245
+ * vizij default (chosen so studio colors match the canvas).
246
+ * - `"agx"` — AgX, Blender 4.x's default view transform. Compresses
247
+ * over-1.0 emissive into soft, slightly-desaturated color; matches faces
248
+ * authored/exported from Blender.
249
+ * - `"aces"` — ACES Filmic, a punchier cinematic curve.
250
+ * - `"neutral"` — Khronos PBR Neutral, a mild curve that preserves hue/saturation
251
+ * while taming highlights.
252
+ */
253
+ type ToneMappingMode = "none" | "agx" | "aces" | "neutral";
254
+ /**
255
+ * The set of supported tone-mapping modes, in display order. Useful for
256
+ * building selection UIs.
257
+ */
258
+ declare const TONE_MAPPING_MODES: ToneMappingMode[];
259
+ /**
260
+ * Human-readable labels for each tone-mapping mode.
261
+ */
262
+ declare const TONE_MAPPING_LABELS: Record<ToneMappingMode, string>;
263
+ /**
264
+ * The default tone-mapping mode used when a face/scene has not specified one.
265
+ * `"none"` preserves the historical web-matching behavior.
266
+ */
267
+ declare const DEFAULT_TONE_MAPPING_MODE: ToneMappingMode;
268
+ /**
269
+ * Type guard: is `value` a valid {@link ToneMappingMode}?
270
+ */
271
+ declare function isToneMappingMode(value: unknown): value is ToneMappingMode;
272
+ /**
273
+ * Resolve a {@link ToneMappingMode} (or an unknown/undefined stored value) to
274
+ * the corresponding three.js tone-mapping constant. Falls back to
275
+ * {@link DEFAULT_TONE_MAPPING_MODE} for missing/invalid input.
276
+ */
277
+ declare function resolveToneMapping(mode: unknown): ToneMapping;
278
+ /**
279
+ * Normalize an unknown/stored value into a valid {@link ToneMappingMode},
280
+ * falling back to {@link DEFAULT_TONE_MAPPING_MODE}.
281
+ */
282
+ declare function normalizeToneMappingMode(value: unknown): ToneMappingMode;
283
+
279
284
  type VizijBundleVersion = 1;
280
285
  type VizijBundleGraphKind = "rig" | "pose" | "pose-driver" | "animation-bridge" | "low-level" | string;
281
286
  type VizijPoseId = string;
@@ -288,6 +293,40 @@ interface VizijBundleGraphMetadata {
288
293
  exportedAt?: string;
289
294
  [key: string]: unknown;
290
295
  }
296
+ /**
297
+ * One path in a profile, with its type and constraints — arora's `KeyInfo`
298
+ * shape, so a profile round-trips through the descriptor the runtime already
299
+ * speaks.
300
+ */
301
+ interface VizijProfileKey {
302
+ path: string;
303
+ kind?: string;
304
+ value_type?: string;
305
+ min?: number;
306
+ max?: number;
307
+ default_value?: unknown;
308
+ /** Standard metadata: the FACS action unit, ARKit blendshape, and tier. */
309
+ meta?: {
310
+ au?: number;
311
+ arkit?: string;
312
+ tier?: string;
313
+ };
314
+ }
315
+ /**
316
+ * A profile the face declares it speaks: a set of paths and their types — the
317
+ * vocabulary its graphs are authored against.
318
+ *
319
+ * A profile is names and types, not a graph, so it sits beside `graphs` rather
320
+ * than inside it. Declaring it on the asset is what lets a reader know which
321
+ * vocabulary to hold the face to.
322
+ */
323
+ interface VizijBundleProfile {
324
+ id: string;
325
+ version: string;
326
+ title?: string;
327
+ description?: string;
328
+ keys: VizijProfileKey[];
329
+ }
291
330
  interface VizijBundleGraphEntry {
292
331
  id: VizijGraphId;
293
332
  kind: VizijBundleGraphKind;
@@ -357,6 +396,19 @@ interface VizijBundleAnimationEntry {
357
396
  [key: string]: unknown;
358
397
  };
359
398
  }
399
+ type VizijStarredKind = "driver" | "pose";
400
+ /**
401
+ * A starred reference collected into the "Starred" control surface. Points at a
402
+ * real driver (standard-input id) or pose (pose id) by stable id so both the
403
+ * source panel and the Starred panel render the same underlying object.
404
+ */
405
+ interface VizijStarredItem {
406
+ kind: VizijStarredKind;
407
+ id: string;
408
+ }
409
+ interface VizijBundleStarredSection {
410
+ items: VizijStarredItem[];
411
+ }
360
412
  interface VizijSpeechConfig {
361
413
  /** TTS voice name (e.g., "Ruth") */
362
414
  voice?: string;
@@ -385,8 +437,22 @@ interface VizijBundleExtension {
385
437
  version: VizijBundleVersion;
386
438
  exportedAt?: string;
387
439
  graphs?: VizijBundleGraphEntry[];
440
+ /** The profiles this face declares it speaks (see {@link VizijBundleProfile}). */
441
+ profiles?: VizijBundleProfile[];
388
442
  poses?: VizijBundlePoseSection | null;
389
443
  animations?: VizijBundleAnimationEntry[];
444
+ /**
445
+ * Scene-level view transform this face should be rendered with. Travels with
446
+ * the asset so a face authored in Blender (which typically wants `"agx"`)
447
+ * renders consistently wherever it is loaded. Omitted/unknown falls back to
448
+ * the renderer default (`"none"` — web match).
449
+ */
450
+ toneMapping?: ToneMappingMode;
451
+ /**
452
+ * Designer-curated set of starred drivers/poses (the "Starred" control
453
+ * surface). References real functionality by stable id.
454
+ */
455
+ starred?: VizijBundleStarredSection | null;
390
456
  /**
391
457
  * Bundle-level metadata. May include `speechConfig: VizijSpeechConfig`
392
458
  * for configuring the STT/LLM/TTS speech pipeline.
@@ -437,8 +503,59 @@ interface VizijAnimationClipData {
437
503
  tracks: VizijAnimationTrackData[];
438
504
  }
439
505
 
506
+ interface VizijProps {
507
+ style?: CSSProperties;
508
+ className?: string;
509
+ rootId: string;
510
+ namespace?: string;
511
+ showSafeArea?: boolean;
512
+ showSelectionGlow?: boolean;
513
+ /**
514
+ * View-transform applied by the WebGL renderer. Defaults to `"none"`
515
+ * (no tone mapping — matches plain web/canvas rendering). Faces authored in
516
+ * Blender typically want `"agx"` to compress over-driven emissive. Applied
517
+ * reactively, so it can be changed at runtime without remounting the canvas.
518
+ */
519
+ toneMapping?: ToneMappingMode;
520
+ onPointerMissed?: ComponentProps<typeof Canvas>["onPointerMissed"];
521
+ }
522
+ /**
523
+ * Renders the Vizij component.
524
+ *
525
+ * @param style - The style object for the Vizij component.
526
+ *
527
+ * @param className - The CSS class name for the Vizij component
528
+ *
529
+ * @param rootId - The root identifier for the Vizij component.
530
+ *
531
+ * @param namespace - The namespace for the Vizij component
532
+ *
533
+ * @param showSafeArea - Whether to show the safe area.
534
+ *
535
+ * @returns The rendered ReactNode.
536
+ */
537
+ declare function Vizij({ style, className, rootId, namespace, showSafeArea, showSelectionGlow, toneMapping, onPointerMissed, }: VizijProps): ReactNode;
538
+ interface InnerVizijProps {
539
+ rootId: string;
540
+ namespace: string;
541
+ container?: {
542
+ width: number;
543
+ height: number;
544
+ resolution: number;
545
+ };
546
+ showSafeArea?: boolean;
547
+ showSelectionGlow?: boolean;
548
+ toneMapping?: ToneMappingMode;
549
+ }
550
+ declare function InnerVizij({ rootId, namespace, container, showSafeArea, showSelectionGlow, toneMapping, }: InnerVizijProps): react_jsx_runtime.JSX.Element;
551
+
440
552
  interface VizijData {
441
553
  world: World;
554
+ /**
555
+ * The mounted three.js object of each world element, by element id and then
556
+ * namespace. It lives beside `world` so that the world stays plain data.
557
+ */
558
+ refs: Record<string, Record<string, RefObject<Group$1 | Mesh | null>>>;
442
559
  animatables: Record<string, AnimatableValue>;
443
560
  values: Map<string, RawValue | undefined>;
444
561
  renderHit: boolean;
@@ -481,7 +598,7 @@ interface VizijActions {
481
598
  setChildren: (id: string, children: string[]) => void;
482
599
  setGeometry: (id: string, geometry: THREE.BufferGeometry) => void;
483
600
  setMaterial: (id: string, material: string) => void;
484
- setReference: (id: string, namespace: string, object: RefObject<Group$1 | Mesh>) => void;
601
+ setReference: (id: string, namespace: string, object: RefObject<Group$1 | Mesh | null>) => void;
485
602
  createGroup: (root: boolean) => void;
486
603
  createAnimatable: (elementId: string, featureName: string, value: Partial<AnimatableValue>) => void;
487
604
  createStatic: (elementId: string, featureName: string, value: RawValue) => void;
@@ -491,6 +608,7 @@ type VizijStoreGetter = () => VizijData & VizijActions;
491
608
 
492
609
  declare const VizijSlice: (set: VizijStoreSetter, get: VizijStoreGetter) => {
493
610
  world: {};
611
+ refs: {};
494
612
  animatables: {};
495
613
  values: Map<any, any>;
496
614
  renderHit: boolean;
@@ -534,7 +652,7 @@ declare const VizijSlice: (set: VizijStoreSetter, get: VizijStoreGetter) => {
534
652
  setVizij: (scene: World, animatables: Record<string, AnimatableValue>) => void;
535
653
  addWorldElements(world: World, animatables: Record<string, AnimatableValue>, replace?: boolean): void;
536
654
  setPreferences: (preferences: Partial<VizijData["preferences"]>) => void;
537
- setReference: (id: string, namespace: string, ref: RefObject<Group$1 | Mesh>) => void;
655
+ setReference: (id: string, namespace: string, ref: RefObject<Group$1 | Mesh | null>) => void;
538
656
  };
539
657
  declare const useDefaultVizijStore: zustand.UseBoundStore<Omit<zustand.StoreApi<VizijData & VizijActions>, "subscribe"> & {
540
658
  subscribe: {
@@ -601,15 +719,14 @@ declare class EmptyModelError extends Error {
601
719
  }
602
720
  type ParserJsonFallbackSource = {
603
721
  url?: string;
604
- blob?: Blob;
605
722
  arrayBuffer?: ArrayBuffer;
606
723
  };
607
724
  declare function parseGlbJsonChunk(buffer: ArrayBuffer): unknown | undefined;
608
- declare function loadGLTF(url: string, namespaces: string[], aggressiveImport?: boolean, rootBounds?: {
725
+ declare function loadGLTF(url: string, aggressiveImport?: boolean, rootBounds?: {
609
726
  center: RawVector2;
610
727
  size: RawVector2;
611
728
  }): Promise<[World, Record<string, AnimatableValue>, VizijAnimationClipData[]]>;
612
- declare function loadGLTFFromBlob(blob: Blob, namespaces: string[], aggressiveImport?: boolean, rootBounds?: {
729
+ declare function loadGLTFFromBlob(blob: Blob, aggressiveImport?: boolean, rootBounds?: {
613
730
  center: RawVector2;
614
731
  size: RawVector2;
615
732
  }): Promise<[World, Record<string, AnimatableValue>, VizijAnimationClipData[]]>;
@@ -620,34 +737,121 @@ type LoadedVizijAsset = {
620
737
  animations: VizijAnimationClipData[];
621
738
  scene: Group$1;
622
739
  };
623
- declare function loadGLTFWithBundle(url: string, namespaces: string[], aggressiveImport?: boolean, rootBounds?: {
740
+ declare function loadGLTFWithBundle(url: string, aggressiveImport?: boolean, rootBounds?: {
624
741
  center: RawVector2;
625
742
  size: RawVector2;
626
743
  }, parserJsonFallback?: ParserJsonFallbackSource): Promise<LoadedVizijAsset>;
627
- declare function loadGLTFFromBlobWithBundle(blob: Blob, namespaces: string[], aggressiveImport?: boolean, rootBounds?: {
744
+ /**
745
+ * Load a GLB or self-contained glTF from `blob`.
746
+ *
747
+ * The bytes are read into memory and parsed there; nothing is fetched, so this
748
+ * runs the same in a browser and in Node.
749
+ */
750
+ declare function loadGLTFFromBlobWithBundle(blob: Blob, aggressiveImport?: boolean, rootBounds?: {
628
751
  center: RawVector2;
629
752
  size: RawVector2;
630
753
  }): Promise<LoadedVizijAsset>;
631
754
 
632
- /**
633
- * Loads a GLTF model from a Blob and returns the Three.js scene containing the model.
634
- *
635
- * @param blob - The Blob containing the GLTF data.
636
- * @returns A Promise that resolves with the THREE.Scene containing the loaded model.
637
- */
638
- declare const loadGltfFromBlob: (blob: Blob, namespaces: string[]) => Promise<[World, Record<string, AnimatableValue>]>;
755
+ declare function deriveRootBounds(group: Group$1): {
756
+ center: RawVector2;
757
+ size: RawVector2;
758
+ } | null;
639
759
 
640
760
  type ExportSceneOptions = {
641
- fileName?: string;
761
+ /** Written into the GLB as the `VIZIJ_bundle` extension of the root node. */
642
762
  bundle?: VizijBundleExtension | null;
763
+ /** Baked clips, written as glTF animations. */
643
764
  animations?: AnimationClip[];
644
- binary?: boolean;
645
- onError?: (error: Error) => void;
646
- onComplete?: () => void;
647
765
  };
648
- declare function exportScene(data: Group$1, fileNameOrOptions?: string | ExportSceneOptions): void;
766
+ /**
767
+ * Rewrite a GLB's JSON chunk in place.
768
+ *
769
+ * `mutate` returns whether it changed anything; when it did not, the original
770
+ * buffer is handed back untouched rather than re-encoded. Any malformed input
771
+ * — wrong magic, missing JSON chunk, unparseable payload — returns the buffer
772
+ * as-is, since a patch is never worth corrupting an export over.
773
+ *
774
+ * Exists so a caller can amend an already-exported GLB instead of exporting
775
+ * twice: `GLTFExporter` is the expensive part, and running it again to change
776
+ * a few bytes of metadata froze the UI thread on real assets.
777
+ */
778
+ declare function patchGlbJson(buffer: ArrayBuffer, mutate: (json: Record<string, unknown>) => boolean): ArrayBuffer;
779
+ /**
780
+ * Merge `metadata` into the `VIZIJ_bundle` extension already written into
781
+ * `glb`, wherever it landed — the exporter attaches it to a node, but a
782
+ * root-level extension is read back too, so both are handled.
783
+ */
784
+ declare function patchVizijBundleMetadata(glb: ArrayBuffer, metadata: Record<string, unknown>): ArrayBuffer;
785
+ /**
786
+ * Encode `root` and its descendants as a GLB.
787
+ *
788
+ * Every node is written with its local translation, rotation and scale, every
789
+ * mesh with its morph weights, and each object's `userData` as glTF
790
+ * extensions and extras, which is where `RobotData` travels. A root that is
791
+ * not a `Scene` is cloned into one, so the caller's graph is left as it was.
792
+ *
793
+ * Only textures need a DOM; a scene without images encodes in Node.
794
+ */
795
+ declare function exportScene(root: THREE.Object3D, options?: ExportSceneOptions): Promise<ArrayBuffer>;
796
+
797
+ /**
798
+ * Build the three.js graph of the world element `rootId` and its descendants,
799
+ * for `exportScene`.
800
+ *
801
+ * Each group becomes a `THREE.Group` and each shape a `THREE.Mesh` carrying a
802
+ * copy of its geometry and a material of its kind, as the renderer mounts
803
+ * them, with the element's `RobotData` in `userData`. No renderer is involved,
804
+ * so this runs in Node.
805
+ *
806
+ * Every feature takes its authored value: a static feature its value, an
807
+ * animated one its animatable's `default` in `animatables`. Node translation,
808
+ * rotation and scale, morph weights and material factors in the exported file
809
+ * are therefore the same numbers as the `RobotData` defaults, never a runtime
810
+ * pose. A caller that wants other values in the file passes them as the
811
+ * defaults of `animatables`.
812
+ *
813
+ * Throws when an element is missing from `world`, when an animated feature
814
+ * names an animatable missing from `animatables`, and for ellipse and
815
+ * rectangle elements, which have no exported form.
816
+ */
817
+ declare function buildSceneGraph(world: World, animatables: Record<string, AnimatableValue>, rootId: string): THREE.Object3D;
649
818
 
650
819
  declare function extractVizijBundle(object: Object3D, parserJson?: unknown): VizijBundleExtension | null;
651
820
  declare function applyVizijBundle(object: Object3D, bundle: VizijBundleExtension | null): () => void;
652
821
 
653
- export { type AnimatedFeature, type Ellipse, type EllipseFeature, EmptyModelError, type ExportSceneOptions, type Feature, type Group, type GroupFeature, InnerVizij, type InnerVizijProps, type LoadedVizijAsset, type Rectangle, type RectangleFeature, type RenderableBase, type RenderableFeature, type Selection, type Shape, type ShapeFeature, ShapeMaterial, type StaticFeature, type Stored, type StoredAnimatedFeature, type StoredEllipse, type StoredFeatures, type StoredGroup, type StoredRectangle, type StoredRenderable, type StoredShape, Vizij, type VizijActions, type VizijAnimationClipData, type VizijAnimationId, type VizijAnimationTrackData, type VizijBundleAnimationClip, type VizijBundleAnimationEntry, type VizijBundleAnimationKeyframe, type VizijBundleAnimationTrack, type VizijBundleExtension, type VizijBundleGraphEntry, type VizijBundleGraphKind, type VizijBundleGraphMetadata, type VizijBundlePoseSection, type VizijBundleVersion, VizijContext, type VizijData, type VizijGraphId, type VizijPoseDefinition, type VizijPoseId, type VizijPoseRigConfig, type VizijProps, VizijSlice, type VizijSpeechConfig, type VizijStore, type VizijStoreGetter, type VizijStoreSetter, type World, applyVizijBundle, createVizijStore, exportScene, extractVizijBundle, loadGLTF, loadGLTFFromBlob, loadGLTFFromBlobWithBundle, loadGLTFWithBundle, loadGltfFromBlob, parseGlbJsonChunk, useDefaultVizijStore, useFeatures, useVizijStore, useVizijStoreGetter, useVizijStoreSetter, useVizijStoreSubscription };
822
+ /**
823
+ * Canonical morph-target key derivation.
824
+ *
825
+ * Morph feature keys are part of the animation binding contract: a propsrig
826
+ * input path is built from `(elementName, featureKey, component)`, and for a
827
+ * morph the feature key is derived from the morph's name. Import (building
828
+ * animatables from geometry) and animation channel resolution must therefore
829
+ * agree exactly, so both use the helpers here rather than re-deriving the rule.
830
+ *
831
+ * Note the slug is normalized twice on the path route: keys produced here are
832
+ * later passed through `normalizeStandardRigGroup` when the propsrig path is
833
+ * built, which independently lowercases and collapses separators. Casing here
834
+ * is therefore not load-bearing for path resolution — but it *is* the stored
835
+ * feature key on the renderable (and in exported `RobotData`), so changing it
836
+ * still changes the shape of authored data. Unit tests pin the rule directly;
837
+ * the corpus test cannot see a casing change because of the double pass.
838
+ */
839
+ /**
840
+ * Allocates the feature key for a single morph target, deduplicating against
841
+ * keys already handed out for the same mesh.
842
+ *
843
+ * `used` is mutated: callers iterating a mesh's morph targets must share one
844
+ * set so collisions resolve deterministically in iteration order.
845
+ */
846
+ declare function sanitizeMorphKey(name: string, fallbackIndex: number, used: Set<string>): string;
847
+ /**
848
+ * Derives feature keys for a mesh's morph targets in order, applying the same
849
+ * dedupe sequence `sanitizeMorphKey` applies during import.
850
+ *
851
+ * Pass morph names in the mesh's own target order (glTF
852
+ * `meshes[].extras.targetNames`, or `morphTargetDictionary` insertion order)
853
+ * so the result matches the keys import produced for that mesh.
854
+ */
855
+ declare function deriveMorphFeatureKeys(names: ReadonlyArray<string>): string[];
856
+
857
+ export { type AnimatedFeature, DEFAULT_TONE_MAPPING_MODE, type Ellipse, type EllipseFeature, EmptyModelError, type ExportSceneOptions, type Feature, type Group, type GroupFeature, InnerVizij, type InnerVizijProps, type LoadedVizijAsset, type Rectangle, type RectangleFeature, type RenderableBase, type RenderableFeature, type Selection, type Shape, type ShapeFeature, ShapeMaterial, type StaticFeature, type Stored, type StoredAnimatedFeature, type StoredEllipse, type StoredFeatures, type StoredGroup, type StoredRectangle, type StoredRenderable, type StoredShape, TONE_MAPPING_LABELS, TONE_MAPPING_MODES, type ToneMappingMode, Vizij, type VizijActions, type VizijAnimationClipData, type VizijAnimationId, type VizijAnimationTrackData, type VizijBundleAnimationClip, type VizijBundleAnimationEntry, type VizijBundleAnimationKeyframe, type VizijBundleAnimationTrack, type VizijBundleExtension, type VizijBundleGraphEntry, type VizijBundleGraphKind, type VizijBundleGraphMetadata, type VizijBundlePoseSection, type VizijBundleProfile, type VizijBundleStarredSection, type VizijBundleVersion, VizijContext, type VizijData, type VizijGraphId, type VizijPoseDefinition, type VizijPoseId, type VizijPoseRigConfig, type VizijProfileKey, type VizijProps, VizijSlice, type VizijSpeechConfig, type VizijStarredItem, type VizijStarredKind, type VizijStore, type VizijStoreGetter, type VizijStoreSetter, type World, applyVizijBundle, buildSceneGraph, createVizijStore, deriveMorphFeatureKeys, deriveRootBounds, exportScene, extractVizijBundle, isToneMappingMode, loadGLTF, loadGLTFFromBlob, loadGLTFFromBlobWithBundle, loadGLTFWithBundle, normalizeToneMappingMode, parseGlbJsonChunk, patchGlbJson, patchVizijBundleMetadata, resolveToneMapping, sanitizeMorphKey, useDefaultVizijStore, useFeatures, useVizijStore, useVizijStoreGetter, useVizijStoreSetter, useVizijStoreSubscription };