@vizij/render 0.1.2 → 1.0.1

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/README.md CHANGED
@@ -23,7 +23,7 @@ This package exposes the `Vizij` canvas component along with hooks, stores, and
23
23
 
24
24
  - `Vizij` renders a fully managed `@react-three/fiber` canvas with sensible defaults for orthographic cameras and safe-area overlays.
25
25
  - A Zustand-powered store (`useVizijStore`) tracks renderables, controllers, and transient state. Hooks let you read or mutate slices without re-rendering entire scenes.
26
- - Utilities (`loadGLTF`, `loadGLTFBlob`, export helpers) streamline loading rigged GLTF assets and exporting scene snapshots. The tuple helpers now return `[world, animatables, animations]`, where `animations` contains parsed clip metadata for any channels embedded in the GLB.
26
+ - The loader (`loadGLTF`, `loadGLTFFromBlob` and their `WithBundle` forms) turns a rigged GLB into the world model; `buildSceneGraph` and `exportScene` turn the world model back into GLB bytes. Both run in Node as well as in a browser. The tuple helpers return `[world, animatables, animations]`, where `animations` contains parsed clip metadata for any channels embedded in the GLB.
27
27
  - Controllers wrap common behaviours (e.g., pointer interaction, safe-area visualisation) so you can compose features quickly.
28
28
 
29
29
  ---
@@ -96,8 +96,8 @@ The store tracks world graph entries, controllers, debug overlays, and renderabl
96
96
  ## Controllers & Helpers
97
97
 
98
98
  - Controllers under `src/controllers` encapsulate input handling, camera logic, and other behaviours. Compose them with your own React components.
99
- - `loadGLTF` / `loadGLTFBlob` simplify loading rig assets and extract animatable metadata used by `@vizij/runtime-react`.
100
- - `export` helpers produce snapshots of the current scene (useful for tooling or exporting frames).
99
+ - `loadGLTF` / `loadGLTFFromBlob` load rig assets and extract the animatable metadata used by `@vizij/runtime-react`. A blob is parsed in memory, with nothing fetched.
100
+ - `buildSceneGraph(world, animatables, rootId)` builds the three.js graph of a world element with no renderer, and `exportScene(root, { bundle, animations })` encodes a graph as GLB bytes. Saving or uploading the bytes is the caller's job.
101
101
 
102
102
  All exports are re-exported through `src/index.tsx`, so a simple `import { loadGLTF } from "@vizij/render"` works.
103
103
 
@@ -107,7 +107,8 @@ Vizij scenes persist authoring metadata inside GLBs so third-party tools see bak
107
107
 
108
108
  - Every renderable still carries a `RobotData` extension in `userData` describing features and animatable bindings.
109
109
  - The exporter now writes a root-level `extensions.VIZIJ_bundle` block following the schema in [`src/types/vizij-bundle.ts`](./src/types/vizij-bundle.ts). It contains rig graphs, pose configs, stored Vizij clips, and provenance hashes.
110
- - Use `exportScene(group, { bundle, animations })` to embed both the Vizij bundle and optional baked `THREE.AnimationClip` instances. The helper attaches the bundle only for the export call and restores the original object.
110
+ - Use `exportScene(root, { bundle, animations })` to embed both the Vizij bundle and optional baked `THREE.AnimationClip` instances; it resolves to the GLB as an `ArrayBuffer`. The helper attaches the bundle only for the export call and restores the original object.
111
+ - A graph from `buildSceneGraph` carries each element's authored values: node translation, rotation and scale, morph weights and material factors equal the `RobotData` defaults written beside them, not a runtime pose.
111
112
  - When loading assets, prefer `loadGLTFWithBundle` / `loadGLTFFromBlobWithBundle` to retrieve `{ world, animatables, bundle, animations }`. The legacy tuple helpers return `[world, animatables, animations]` if you only need the renderer state.
112
113
  - The new `animations` field exposes `VizijAnimationClipData[]`, which maps each glTF animation channel back to Vizij animatable ids (`RobotData.features.*.value.id`). Each track provides component-aware `times`/`values` arrays so runtimes can register clips without re-parsing the GLB.
113
114
  - `extractVizijBundle(scene)` and `applyVizijBundle(scene, bundle)` (under `src/functions/vizij-bundle.ts`) let advanced tooling inspect or mutate bundles without triggering a fresh export.
package/dist/index.d.mts 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,7 +174,6 @@ 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;
@@ -255,8 +208,6 @@ declare enum ShapeMaterial {
255
208
  type ShapeFeature = keyof Shape["features"];
256
209
  type StoredShape = Stored<Omit<Shape, "geometry">>;
257
210
 
258
- type World = Record<string, Group | Ellipse | Rectangle | Shape>;
259
-
260
211
  type RenderableFeature = GroupFeature | EllipseFeature;
261
212
 
262
213
  /**
@@ -279,6 +230,57 @@ interface Selection {
279
230
  };
280
231
  }
281
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
+
282
284
  type VizijBundleVersion = 1;
283
285
  type VizijBundleGraphKind = "rig" | "pose" | "pose-driver" | "animation-bridge" | "low-level" | string;
284
286
  type VizijPoseId = string;
@@ -291,6 +293,40 @@ interface VizijBundleGraphMetadata {
291
293
  exportedAt?: string;
292
294
  [key: string]: unknown;
293
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
+ }
294
330
  interface VizijBundleGraphEntry {
295
331
  id: VizijGraphId;
296
332
  kind: VizijBundleGraphKind;
@@ -360,6 +396,19 @@ interface VizijBundleAnimationEntry {
360
396
  [key: string]: unknown;
361
397
  };
362
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
+ }
363
412
  interface VizijSpeechConfig {
364
413
  /** TTS voice name (e.g., "Ruth") */
365
414
  voice?: string;
@@ -388,8 +437,22 @@ interface VizijBundleExtension {
388
437
  version: VizijBundleVersion;
389
438
  exportedAt?: string;
390
439
  graphs?: VizijBundleGraphEntry[];
440
+ /** The profiles this face declares it speaks (see {@link VizijBundleProfile}). */
441
+ profiles?: VizijBundleProfile[];
391
442
  poses?: VizijBundlePoseSection | null;
392
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;
393
456
  /**
394
457
  * Bundle-level metadata. May include `speechConfig: VizijSpeechConfig`
395
458
  * for configuring the STT/LLM/TTS speech pipeline.
@@ -440,8 +503,59 @@ interface VizijAnimationClipData {
440
503
  tracks: VizijAnimationTrackData[];
441
504
  }
442
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
+
443
552
  interface VizijData {
444
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>>>;
445
559
  animatables: Record<string, AnimatableValue>;
446
560
  values: Map<string, RawValue | undefined>;
447
561
  renderHit: boolean;
@@ -484,7 +598,7 @@ interface VizijActions {
484
598
  setChildren: (id: string, children: string[]) => void;
485
599
  setGeometry: (id: string, geometry: THREE.BufferGeometry) => void;
486
600
  setMaterial: (id: string, material: string) => void;
487
- setReference: (id: string, namespace: string, object: RefObject<Group$1 | Mesh>) => void;
601
+ setReference: (id: string, namespace: string, object: RefObject<Group$1 | Mesh | null>) => void;
488
602
  createGroup: (root: boolean) => void;
489
603
  createAnimatable: (elementId: string, featureName: string, value: Partial<AnimatableValue>) => void;
490
604
  createStatic: (elementId: string, featureName: string, value: RawValue) => void;
@@ -494,6 +608,7 @@ type VizijStoreGetter = () => VizijData & VizijActions;
494
608
 
495
609
  declare const VizijSlice: (set: VizijStoreSetter, get: VizijStoreGetter) => {
496
610
  world: {};
611
+ refs: {};
497
612
  animatables: {};
498
613
  values: Map<any, any>;
499
614
  renderHit: boolean;
@@ -537,7 +652,7 @@ declare const VizijSlice: (set: VizijStoreSetter, get: VizijStoreGetter) => {
537
652
  setVizij: (scene: World, animatables: Record<string, AnimatableValue>) => void;
538
653
  addWorldElements(world: World, animatables: Record<string, AnimatableValue>, replace?: boolean): void;
539
654
  setPreferences: (preferences: Partial<VizijData["preferences"]>) => void;
540
- setReference: (id: string, namespace: string, ref: RefObject<Group$1 | Mesh>) => void;
655
+ setReference: (id: string, namespace: string, ref: RefObject<Group$1 | Mesh | null>) => void;
541
656
  };
542
657
  declare const useDefaultVizijStore: zustand.UseBoundStore<Omit<zustand.StoreApi<VizijData & VizijActions>, "subscribe"> & {
543
658
  subscribe: {
@@ -604,15 +719,14 @@ declare class EmptyModelError extends Error {
604
719
  }
605
720
  type ParserJsonFallbackSource = {
606
721
  url?: string;
607
- blob?: Blob;
608
722
  arrayBuffer?: ArrayBuffer;
609
723
  };
610
724
  declare function parseGlbJsonChunk(buffer: ArrayBuffer): unknown | undefined;
611
- declare function loadGLTF(url: string, namespaces: string[], aggressiveImport?: boolean, rootBounds?: {
725
+ declare function loadGLTF(url: string, aggressiveImport?: boolean, rootBounds?: {
612
726
  center: RawVector2;
613
727
  size: RawVector2;
614
728
  }): Promise<[World, Record<string, AnimatableValue>, VizijAnimationClipData[]]>;
615
- declare function loadGLTFFromBlob(blob: Blob, namespaces: string[], aggressiveImport?: boolean, rootBounds?: {
729
+ declare function loadGLTFFromBlob(blob: Blob, aggressiveImport?: boolean, rootBounds?: {
616
730
  center: RawVector2;
617
731
  size: RawVector2;
618
732
  }): Promise<[World, Record<string, AnimatableValue>, VizijAnimationClipData[]]>;
@@ -623,34 +737,121 @@ type LoadedVizijAsset = {
623
737
  animations: VizijAnimationClipData[];
624
738
  scene: Group$1;
625
739
  };
626
- declare function loadGLTFWithBundle(url: string, namespaces: string[], aggressiveImport?: boolean, rootBounds?: {
740
+ declare function loadGLTFWithBundle(url: string, aggressiveImport?: boolean, rootBounds?: {
627
741
  center: RawVector2;
628
742
  size: RawVector2;
629
743
  }, parserJsonFallback?: ParserJsonFallbackSource): Promise<LoadedVizijAsset>;
630
- 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?: {
631
751
  center: RawVector2;
632
752
  size: RawVector2;
633
753
  }): Promise<LoadedVizijAsset>;
634
754
 
635
- /**
636
- * Loads a GLTF model from a Blob and returns the Three.js scene containing the model.
637
- *
638
- * @param blob - The Blob containing the GLTF data.
639
- * @returns A Promise that resolves with the THREE.Scene containing the loaded model.
640
- */
641
- 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;
642
759
 
643
760
  type ExportSceneOptions = {
644
- fileName?: string;
761
+ /** Written into the GLB as the `VIZIJ_bundle` extension of the root node. */
645
762
  bundle?: VizijBundleExtension | null;
763
+ /** Baked clips, written as glTF animations. */
646
764
  animations?: AnimationClip[];
647
- binary?: boolean;
648
- onError?: (error: Error) => void;
649
- onComplete?: () => void;
650
765
  };
651
- 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;
652
818
 
653
819
  declare function extractVizijBundle(object: Object3D, parserJson?: unknown): VizijBundleExtension | null;
654
820
  declare function applyVizijBundle(object: Object3D, bundle: VizijBundleExtension | null): () => void;
655
821
 
656
- 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 };