@vizij/runtime-react 0.0.1 → 0.0.3

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
@@ -56,12 +56,13 @@ The provider creates a renderer store, boots the orchestrator, registers the sup
56
56
 
57
57
  `VizijRuntimeProvider` expects a `VizijAssetBundle`:
58
58
 
59
- - `glb`: required. Either `{ kind: "url", src }`, `{ kind: "blob", blob }`, or `{ kind: "world", world, animatables }`. URL/blob variants can opt into `aggressiveImport` for tooling builds and provide `rootBounds` overrides when the GLB lacks metadata.
60
- - `rig`: required. Graph specification describing inputs/outputs for the orchestrator (`id` must be unique within the namespace).
61
- - `pose`: optional. Supply authoring pose graph/config so the runtime can neutralise the rig before you drive it.
62
- - `animations`: optional array. Each item defines channels that map to runtime input paths. Use `playAnimation` to trigger them.
59
+ - `glb`: required. Either `{ kind: "url", src }`, `{ kind: "blob", blob }`, or `{ kind: "world", world, animatables, bundle? }`. URL/blob variants can opt into `aggressiveImport` for tooling builds and provide `rootBounds` overrides when the GLB lacks metadata.
60
+ - `rig`: optional. When omitted, the runtime looks for a `VIZIJ_bundle` extension inside the GLB and registers the first rig graph it finds.
61
+ - `pose`: optional. Provide your own pose graph/config or just a `stageNeutralFilter`; bundled pose data is pulled from the GLB when present.
62
+ - `animations`: optional array. Explicit entries merge with animations discovered in the GLB bundle (deduped by id). Use `playAnimation` to trigger them.
63
63
  - `initialInputs`: optional map of ValueJSON that seeds inputs before autostart.
64
64
  - `metadata`: free-form dictionary you can read back through `useVizijRuntime().assetBundle.metadata`.
65
+ - `bundle`: optional. Supply pre-parsed bundle metadata when you manage world loading yourself. When loading from GLB/Blob the runtime fills this with the extracted `VizijBundleExtension`.
65
66
 
66
67
  Namespace defaults to `assetBundle.namespace ?? "default"`. Face id falls back to the bundle pose config when omitted.
67
68
 
@@ -117,9 +118,9 @@ For ad-hoc gestures, use `animateValue` with duration/easing. If you need custom
117
118
 
118
119
  ## Asset Bundling Workflow
119
120
 
120
- 1. Export an authoring scene to GLB with Vizij metadata intact (bounds, animatable ids).
121
- 2. Export orchestrator graphs (rig, pose, optional animation graphs) to JSON.
122
- 3. Package everything under a namespace in a `VizijAssetBundle`.
121
+ 1. Export an authoring scene to GLB with Vizij metadata intact (bounds, animatable ids). Enable “Embed Vizij bundle” in vizij-authoring to persist rig graphs, pose rig data, and animations inside the GLB.
122
+ 2. Drop the GLB into a `VizijAssetBundle` and let the runtime extract rig/pose/animation data automatically.
123
+ 3. Optionally override or extend bundle contents by setting `rig`, `pose`, or `animations` manually (useful for tooling builds or custom staging).
123
124
  4. Host GLB URLs or include them via bundler asset imports (`new URL("./face.glb", import.meta.url).href`).
124
125
 
125
126
  The runtime tolerates incremental bundles; swap `assetBundle` props to hot-reload assets in dev builds.
package/dist/index.d.mts CHANGED
@@ -3,7 +3,7 @@ import * as react from 'react';
3
3
  import { ReactNode, PropsWithChildren } from 'react';
4
4
  import { GraphRegistrationConfig, GraphSubscriptions, AnimationSetup, ValueJSON, CreateOrchOptions, MergeStrategyOptions, ShapeJSON } from '@vizij/orchestrator-react';
5
5
  import { AnimatableValue, RawValue } from '@vizij/utils';
6
- import { World, VizijProps } from '@vizij/render';
6
+ import { World, VizijBundleExtension, VizijProps } from '@vizij/render';
7
7
 
8
8
  type PoseDefinition = {
9
9
  id: string;
@@ -45,6 +45,7 @@ type VizijGlbAsset = {
45
45
  kind: "world";
46
46
  world: World;
47
47
  animatables: Record<string, AnimatableValue>;
48
+ bundle?: VizijBundleExtension | null;
48
49
  };
49
50
  type VizijGraphAsset = {
50
51
  id: string;
@@ -76,7 +77,7 @@ type VizijAssetBundle = {
76
77
  namespace?: string;
77
78
  faceId?: string;
78
79
  glb: VizijGlbAsset;
79
- rig: VizijGraphAsset;
80
+ rig?: VizijGraphAsset;
80
81
  pose?: {
81
82
  graph?: VizijGraphAsset;
82
83
  config?: PoseRigConfig;
@@ -85,6 +86,7 @@ type VizijAssetBundle = {
85
86
  animations?: VizijAnimationAsset[];
86
87
  initialInputs?: Record<string, ValueJSON>;
87
88
  metadata?: Record<string, unknown>;
89
+ bundle?: VizijBundleExtension | null;
88
90
  };
89
91
  type RuntimeError = {
90
92
  message: string;
package/dist/index.d.ts CHANGED
@@ -3,7 +3,7 @@ import * as react from 'react';
3
3
  import { ReactNode, PropsWithChildren } from 'react';
4
4
  import { GraphRegistrationConfig, GraphSubscriptions, AnimationSetup, ValueJSON, CreateOrchOptions, MergeStrategyOptions, ShapeJSON } from '@vizij/orchestrator-react';
5
5
  import { AnimatableValue, RawValue } from '@vizij/utils';
6
- import { World, VizijProps } from '@vizij/render';
6
+ import { World, VizijBundleExtension, VizijProps } from '@vizij/render';
7
7
 
8
8
  type PoseDefinition = {
9
9
  id: string;
@@ -45,6 +45,7 @@ type VizijGlbAsset = {
45
45
  kind: "world";
46
46
  world: World;
47
47
  animatables: Record<string, AnimatableValue>;
48
+ bundle?: VizijBundleExtension | null;
48
49
  };
49
50
  type VizijGraphAsset = {
50
51
  id: string;
@@ -76,7 +77,7 @@ type VizijAssetBundle = {
76
77
  namespace?: string;
77
78
  faceId?: string;
78
79
  glb: VizijGlbAsset;
79
- rig: VizijGraphAsset;
80
+ rig?: VizijGraphAsset;
80
81
  pose?: {
81
82
  graph?: VizijGraphAsset;
82
83
  config?: PoseRigConfig;
@@ -85,6 +86,7 @@ type VizijAssetBundle = {
85
86
  animations?: VizijAnimationAsset[];
86
87
  initialInputs?: Record<string, ValueJSON>;
87
88
  metadata?: Record<string, unknown>;
89
+ bundle?: VizijBundleExtension | null;
88
90
  };
89
91
  type RuntimeError = {
90
92
  message: string;
package/dist/index.js CHANGED
@@ -214,7 +214,6 @@ function valueJSONToRaw(value) {
214
214
  }
215
215
 
216
216
  // src/VizijRuntimeProvider.tsx
217
- var import_render2 = require("@vizij/render");
218
217
  var import_jsx_runtime = require("react/jsx-runtime");
219
218
  var DEFAULT_MERGE = {
220
219
  outputs: "add",
@@ -250,6 +249,128 @@ function normalisePath(path) {
250
249
  }
251
250
  return path.startsWith("debug/") ? path.slice("debug/".length) : path;
252
251
  }
252
+ function normaliseBundleKind(kind) {
253
+ return typeof kind === "string" ? kind.toLowerCase() : "";
254
+ }
255
+ function pickBundleGraph(bundle, preferredKinds) {
256
+ if (!bundle?.graphs || bundle.graphs.length === 0) {
257
+ return null;
258
+ }
259
+ const preferred = preferredKinds.map((kind) => kind.toLowerCase());
260
+ for (const entry of bundle.graphs) {
261
+ if (!entry || typeof entry !== "object") {
262
+ continue;
263
+ }
264
+ const kind = normaliseBundleKind(entry.kind);
265
+ if (preferred.includes(kind)) {
266
+ return entry;
267
+ }
268
+ }
269
+ if (bundle.graphs.length === 1) {
270
+ return bundle.graphs[0] ?? null;
271
+ }
272
+ return null;
273
+ }
274
+ function convertBundleGraph(entry) {
275
+ if (!entry || !entry.id || !entry.spec) {
276
+ return null;
277
+ }
278
+ return {
279
+ id: entry.id,
280
+ spec: entry.spec
281
+ };
282
+ }
283
+ function convertBundleAnimations(entries) {
284
+ if (!Array.isArray(entries) || entries.length === 0) {
285
+ return [];
286
+ }
287
+ return entries.filter(
288
+ (entry) => Boolean(entry && typeof entry.id === "string" && entry.clip)
289
+ ).map((entry) => ({
290
+ id: entry.id,
291
+ clip: entry.clip
292
+ }));
293
+ }
294
+ function mergeAnimationLists(explicit, fromBundle) {
295
+ if (!explicit?.length && fromBundle.length === 0) {
296
+ return void 0;
297
+ }
298
+ if (!explicit?.length) {
299
+ return fromBundle.length > 0 ? fromBundle : void 0;
300
+ }
301
+ if (fromBundle.length === 0) {
302
+ return explicit;
303
+ }
304
+ const seen = new Set(explicit.map((anim) => anim.id));
305
+ let changed = false;
306
+ const merged = [...explicit];
307
+ for (const anim of fromBundle) {
308
+ if (!anim.id || seen.has(anim.id)) {
309
+ continue;
310
+ }
311
+ merged.push(anim);
312
+ seen.add(anim.id);
313
+ changed = true;
314
+ }
315
+ return changed ? merged : explicit;
316
+ }
317
+ function mergeAssetBundle(base, extracted) {
318
+ const resolvedBundle = base.bundle ?? extracted ?? null;
319
+ const rigFromBundle = convertBundleGraph(
320
+ pickBundleGraph(resolvedBundle, ["rig"])
321
+ );
322
+ const resolvedRig = base.rig ?? rigFromBundle ?? void 0;
323
+ const basePose = base.pose;
324
+ const poseStageFilter = basePose?.stageNeutralFilter;
325
+ const poseGraphFromBundle = basePose?.graph ? null : convertBundleGraph(
326
+ pickBundleGraph(resolvedBundle, ["pose-driver", "pose"])
327
+ );
328
+ const resolvedPoseGraph = basePose?.graph ?? poseGraphFromBundle ?? void 0;
329
+ const resolvedPoseConfig = basePose?.config ?? resolvedBundle?.poses?.config ?? void 0;
330
+ let resolvedPose = basePose;
331
+ if (basePose) {
332
+ const nextPose = { ...basePose };
333
+ let changed = false;
334
+ if (resolvedPoseGraph && basePose.graph !== resolvedPoseGraph) {
335
+ nextPose.graph = resolvedPoseGraph;
336
+ changed = true;
337
+ }
338
+ if (resolvedPoseConfig && basePose.config !== resolvedPoseConfig) {
339
+ nextPose.config = resolvedPoseConfig;
340
+ changed = true;
341
+ }
342
+ if (!resolvedPoseGraph && !basePose.graph) {
343
+ }
344
+ if (!resolvedPoseConfig && !basePose.config) {
345
+ }
346
+ resolvedPose = changed ? nextPose : basePose;
347
+ } else if (resolvedPoseGraph || resolvedPoseConfig || typeof poseStageFilter === "function") {
348
+ resolvedPose = {
349
+ ...resolvedPoseGraph ? { graph: resolvedPoseGraph } : {},
350
+ ...resolvedPoseConfig ? { config: resolvedPoseConfig } : {},
351
+ ...typeof poseStageFilter === "function" ? { stageNeutralFilter: poseStageFilter } : {}
352
+ };
353
+ }
354
+ const animationsFromBundle = convertBundleAnimations(
355
+ resolvedBundle?.animations
356
+ );
357
+ const resolvedAnimations = mergeAnimationLists(
358
+ base.animations,
359
+ animationsFromBundle
360
+ );
361
+ const merged = {
362
+ ...base
363
+ };
364
+ if (resolvedRig) {
365
+ merged.rig = resolvedRig;
366
+ } else {
367
+ merged.rig = void 0;
368
+ }
369
+ merged.pose = resolvedPose;
370
+ merged.animations = resolvedAnimations;
371
+ merged.bundle = resolvedBundle;
372
+ return merged;
373
+ }
253
374
  function VizijRuntimeProvider({
254
375
  assetBundle,
255
376
  children,
@@ -290,7 +411,7 @@ function VizijRuntimeProvider({
290
411
  ) });
291
412
  }
292
413
  function VizijRuntimeProviderInner({
293
- assetBundle,
414
+ assetBundle: initialAssetBundle,
294
415
  namespace: namespaceProp,
295
416
  faceId: faceIdProp,
296
417
  mergeStrategy,
@@ -300,6 +421,30 @@ function VizijRuntimeProviderInner({
300
421
  children,
301
422
  autoCreate
302
423
  }) {
424
+ const [extractedBundle, setExtractedBundle] = (0, import_react2.useState)(() => {
425
+ if (initialAssetBundle.bundle) {
426
+ return initialAssetBundle.bundle;
427
+ }
428
+ if (initialAssetBundle.glb.kind === "world" && initialAssetBundle.glb.bundle) {
429
+ return initialAssetBundle.glb.bundle;
430
+ }
431
+ return null;
432
+ });
433
+ (0, import_react2.useEffect)(() => {
434
+ if (initialAssetBundle.bundle) {
435
+ setExtractedBundle(initialAssetBundle.bundle);
436
+ return;
437
+ }
438
+ if (initialAssetBundle.glb.kind === "world") {
439
+ setExtractedBundle(initialAssetBundle.glb.bundle ?? null);
440
+ } else {
441
+ setExtractedBundle(null);
442
+ }
443
+ }, [initialAssetBundle]);
444
+ const assetBundle = (0, import_react2.useMemo)(
445
+ () => mergeAssetBundle(initialAssetBundle, extractedBundle),
446
+ [initialAssetBundle, extractedBundle]
447
+ );
303
448
  const {
304
449
  ready,
305
450
  createOrchestrator,
@@ -419,27 +564,36 @@ function VizijRuntimeProviderInner({
419
564
  try {
420
565
  let world;
421
566
  let animatables;
567
+ let bundle = assetBundle.bundle ?? null;
422
568
  if (assetBundle.glb.kind === "url") {
423
- [world, animatables] = await (0, import_render2.loadGLTF)(
569
+ const loaded = await (0, import_render.loadGLTFWithBundle)(
424
570
  assetBundle.glb.src,
425
571
  [namespace],
426
572
  assetBundle.glb.aggressiveImport ?? false,
427
573
  assetBundle.glb.rootBounds
428
574
  );
575
+ world = loaded.world;
576
+ animatables = loaded.animatables;
577
+ bundle = loaded.bundle ?? bundle;
429
578
  } else if (assetBundle.glb.kind === "blob") {
430
- [world, animatables] = await (0, import_render2.loadGLTFFromBlob)(
579
+ const loaded = await (0, import_render.loadGLTFFromBlobWithBundle)(
431
580
  assetBundle.glb.blob,
432
581
  [namespace],
433
582
  assetBundle.glb.aggressiveImport ?? false,
434
583
  assetBundle.glb.rootBounds
435
584
  );
585
+ world = loaded.world;
586
+ animatables = loaded.animatables;
587
+ bundle = loaded.bundle ?? bundle;
436
588
  } else {
437
589
  world = assetBundle.glb.world;
438
590
  animatables = assetBundle.glb.animatables;
591
+ bundle = assetBundle.glb.bundle ?? bundle;
439
592
  }
440
593
  if (cancelled) {
441
594
  return;
442
595
  }
596
+ setExtractedBundle(bundle ?? null);
443
597
  const rootId = findRootId(world);
444
598
  store.getState().addWorldElements(world, animatables, true);
445
599
  reportStatus((prev) => ({
@@ -476,7 +630,8 @@ function VizijRuntimeProviderInner({
476
630
  store,
477
631
  pushError,
478
632
  reportStatus,
479
- resetErrors
633
+ resetErrors,
634
+ setExtractedBundle
480
635
  ]);
481
636
  (0, import_react2.useEffect)(() => {
482
637
  if (!ready && autoCreate) {
@@ -492,15 +647,25 @@ function VizijRuntimeProviderInner({
492
647
  }, [ready, autoCreate, createOrchestrator, pushError]);
493
648
  const registerControllers = (0, import_react2.useCallback)(async () => {
494
649
  const normalize = (spec) => spec;
495
- const rigSpec = normalize(assetBundle.rig.spec);
650
+ clearControllers();
651
+ const rigAsset = assetBundle.rig;
652
+ if (!rigAsset) {
653
+ pushError({
654
+ message: "Asset bundle is missing a rig graph.",
655
+ phase: "registration",
656
+ timestamp: performance.now()
657
+ });
658
+ return;
659
+ }
660
+ const rigSpec = normalize(rigAsset.spec);
496
661
  const rigOutputs = collectOutputPaths(rigSpec);
497
662
  const rigInputs = collectInputPaths(rigSpec);
498
663
  rigInputMapRef.current = collectInputPathMap(rigSpec);
499
664
  outputPathsRef.current = new Set(rigOutputs);
500
665
  const rigConfig = {
501
- id: assetBundle.rig.id,
666
+ id: rigAsset.id,
502
667
  spec: rigSpec,
503
- subs: assetBundle.rig.subscriptions ?? {
668
+ subs: rigAsset.subscriptions ?? {
504
669
  inputs: rigInputs,
505
670
  outputs: rigOutputs
506
671
  }
@@ -519,7 +684,6 @@ function VizijRuntimeProviderInner({
519
684
  }
520
685
  });
521
686
  }
522
- clearControllers();
523
687
  const graphIds = [];
524
688
  try {
525
689
  if (graphConfigs.length > 1) {
@@ -988,7 +1152,7 @@ function VizijRuntimeProviderInner({
988
1152
 
989
1153
  // src/VizijRuntimeFace.tsx
990
1154
  var import_react4 = require("react");
991
- var import_render3 = require("@vizij/render");
1155
+ var import_render2 = require("@vizij/render");
992
1156
 
993
1157
  // src/hooks/useVizijRuntime.ts
994
1158
  var import_react3 = require("react");
@@ -1013,7 +1177,7 @@ function VizijRuntimeFaceInner({
1013
1177
  return null;
1014
1178
  }
1015
1179
  return /* @__PURE__ */ (0, import_jsx_runtime2.jsx)(
1016
- import_render3.Vizij,
1180
+ import_render2.Vizij,
1017
1181
  {
1018
1182
  ...props,
1019
1183
  rootId,
@@ -1024,11 +1188,11 @@ function VizijRuntimeFaceInner({
1024
1188
  var VizijRuntimeFace = (0, import_react4.memo)(VizijRuntimeFaceInner);
1025
1189
 
1026
1190
  // src/hooks/useVizijOutputs.ts
1027
- var import_render4 = require("@vizij/render");
1191
+ var import_render3 = require("@vizij/render");
1028
1192
  var import_utils = require("@vizij/utils");
1029
1193
  function useVizijOutputs(paths) {
1030
1194
  const { namespace } = useVizijRuntime();
1031
- return (0, import_render4.useVizijStore)((state) => {
1195
+ return (0, import_render3.useVizijStore)((state) => {
1032
1196
  const result = {};
1033
1197
  paths.forEach((path) => {
1034
1198
  const lookup = (0, import_utils.getLookup)(namespace, path);
@@ -1040,11 +1204,11 @@ function useVizijOutputs(paths) {
1040
1204
 
1041
1205
  // src/hooks/useRigInput.ts
1042
1206
  var import_react5 = require("react");
1043
- var import_render5 = require("@vizij/render");
1207
+ var import_render4 = require("@vizij/render");
1044
1208
  var import_utils2 = require("@vizij/utils");
1045
1209
  function useRigInput(path) {
1046
1210
  const { namespace, setInput } = useVizijRuntime();
1047
- const value = (0, import_render5.useVizijStore)(
1211
+ const value = (0, import_render4.useVizijStore)(
1048
1212
  (state) => state.values.get((0, import_utils2.getLookup)(namespace, path))
1049
1213
  );
1050
1214
  const setter = (0, import_react5.useCallback)(
package/dist/index.mjs CHANGED
@@ -6,7 +6,12 @@ import {
6
6
  useRef,
7
7
  useState
8
8
  } from "react";
9
- import { VizijContext, createVizijStore } from "@vizij/render";
9
+ import {
10
+ VizijContext,
11
+ createVizijStore,
12
+ loadGLTFWithBundle,
13
+ loadGLTFFromBlobWithBundle
14
+ } from "@vizij/render";
10
15
  import {
11
16
  OrchestratorProvider,
12
17
  useOrchestrator,
@@ -202,7 +207,6 @@ function valueJSONToRaw(value) {
202
207
  }
203
208
 
204
209
  // src/VizijRuntimeProvider.tsx
205
- import { loadGLTF, loadGLTFFromBlob } from "@vizij/render";
206
210
  import { jsx } from "react/jsx-runtime";
207
211
  var DEFAULT_MERGE = {
208
212
  outputs: "add",
@@ -238,6 +242,128 @@ function normalisePath(path) {
238
242
  }
239
243
  return path.startsWith("debug/") ? path.slice("debug/".length) : path;
240
244
  }
245
+ function normaliseBundleKind(kind) {
246
+ return typeof kind === "string" ? kind.toLowerCase() : "";
247
+ }
248
+ function pickBundleGraph(bundle, preferredKinds) {
249
+ if (!bundle?.graphs || bundle.graphs.length === 0) {
250
+ return null;
251
+ }
252
+ const preferred = preferredKinds.map((kind) => kind.toLowerCase());
253
+ for (const entry of bundle.graphs) {
254
+ if (!entry || typeof entry !== "object") {
255
+ continue;
256
+ }
257
+ const kind = normaliseBundleKind(entry.kind);
258
+ if (preferred.includes(kind)) {
259
+ return entry;
260
+ }
261
+ }
262
+ if (bundle.graphs.length === 1) {
263
+ return bundle.graphs[0] ?? null;
264
+ }
265
+ return null;
266
+ }
267
+ function convertBundleGraph(entry) {
268
+ if (!entry || !entry.id || !entry.spec) {
269
+ return null;
270
+ }
271
+ return {
272
+ id: entry.id,
273
+ spec: entry.spec
274
+ };
275
+ }
276
+ function convertBundleAnimations(entries) {
277
+ if (!Array.isArray(entries) || entries.length === 0) {
278
+ return [];
279
+ }
280
+ return entries.filter(
281
+ (entry) => Boolean(entry && typeof entry.id === "string" && entry.clip)
282
+ ).map((entry) => ({
283
+ id: entry.id,
284
+ clip: entry.clip
285
+ }));
286
+ }
287
+ function mergeAnimationLists(explicit, fromBundle) {
288
+ if (!explicit?.length && fromBundle.length === 0) {
289
+ return void 0;
290
+ }
291
+ if (!explicit?.length) {
292
+ return fromBundle.length > 0 ? fromBundle : void 0;
293
+ }
294
+ if (fromBundle.length === 0) {
295
+ return explicit;
296
+ }
297
+ const seen = new Set(explicit.map((anim) => anim.id));
298
+ let changed = false;
299
+ const merged = [...explicit];
300
+ for (const anim of fromBundle) {
301
+ if (!anim.id || seen.has(anim.id)) {
302
+ continue;
303
+ }
304
+ merged.push(anim);
305
+ seen.add(anim.id);
306
+ changed = true;
307
+ }
308
+ return changed ? merged : explicit;
309
+ }
310
+ function mergeAssetBundle(base, extracted) {
311
+ const resolvedBundle = base.bundle ?? extracted ?? null;
312
+ const rigFromBundle = convertBundleGraph(
313
+ pickBundleGraph(resolvedBundle, ["rig"])
314
+ );
315
+ const resolvedRig = base.rig ?? rigFromBundle ?? void 0;
316
+ const basePose = base.pose;
317
+ const poseStageFilter = basePose?.stageNeutralFilter;
318
+ const poseGraphFromBundle = basePose?.graph ? null : convertBundleGraph(
319
+ pickBundleGraph(resolvedBundle, ["pose-driver", "pose"])
320
+ );
321
+ const resolvedPoseGraph = basePose?.graph ?? poseGraphFromBundle ?? void 0;
322
+ const resolvedPoseConfig = basePose?.config ?? resolvedBundle?.poses?.config ?? void 0;
323
+ let resolvedPose = basePose;
324
+ if (basePose) {
325
+ const nextPose = { ...basePose };
326
+ let changed = false;
327
+ if (resolvedPoseGraph && basePose.graph !== resolvedPoseGraph) {
328
+ nextPose.graph = resolvedPoseGraph;
329
+ changed = true;
330
+ }
331
+ if (resolvedPoseConfig && basePose.config !== resolvedPoseConfig) {
332
+ nextPose.config = resolvedPoseConfig;
333
+ changed = true;
334
+ }
335
+ if (!resolvedPoseGraph && !basePose.graph) {
336
+ }
337
+ if (!resolvedPoseConfig && !basePose.config) {
338
+ }
339
+ resolvedPose = changed ? nextPose : basePose;
340
+ } else if (resolvedPoseGraph || resolvedPoseConfig || typeof poseStageFilter === "function") {
341
+ resolvedPose = {
342
+ ...resolvedPoseGraph ? { graph: resolvedPoseGraph } : {},
343
+ ...resolvedPoseConfig ? { config: resolvedPoseConfig } : {},
344
+ ...typeof poseStageFilter === "function" ? { stageNeutralFilter: poseStageFilter } : {}
345
+ };
346
+ }
347
+ const animationsFromBundle = convertBundleAnimations(
348
+ resolvedBundle?.animations
349
+ );
350
+ const resolvedAnimations = mergeAnimationLists(
351
+ base.animations,
352
+ animationsFromBundle
353
+ );
354
+ const merged = {
355
+ ...base
356
+ };
357
+ if (resolvedRig) {
358
+ merged.rig = resolvedRig;
359
+ } else {
360
+ merged.rig = void 0;
361
+ }
362
+ merged.pose = resolvedPose;
363
+ merged.animations = resolvedAnimations;
364
+ merged.bundle = resolvedBundle;
365
+ return merged;
366
+ }
241
367
  function VizijRuntimeProvider({
242
368
  assetBundle,
243
369
  children,
@@ -278,7 +404,7 @@ function VizijRuntimeProvider({
278
404
  ) });
279
405
  }
280
406
  function VizijRuntimeProviderInner({
281
- assetBundle,
407
+ assetBundle: initialAssetBundle,
282
408
  namespace: namespaceProp,
283
409
  faceId: faceIdProp,
284
410
  mergeStrategy,
@@ -288,6 +414,30 @@ function VizijRuntimeProviderInner({
288
414
  children,
289
415
  autoCreate
290
416
  }) {
417
+ const [extractedBundle, setExtractedBundle] = useState(() => {
418
+ if (initialAssetBundle.bundle) {
419
+ return initialAssetBundle.bundle;
420
+ }
421
+ if (initialAssetBundle.glb.kind === "world" && initialAssetBundle.glb.bundle) {
422
+ return initialAssetBundle.glb.bundle;
423
+ }
424
+ return null;
425
+ });
426
+ useEffect(() => {
427
+ if (initialAssetBundle.bundle) {
428
+ setExtractedBundle(initialAssetBundle.bundle);
429
+ return;
430
+ }
431
+ if (initialAssetBundle.glb.kind === "world") {
432
+ setExtractedBundle(initialAssetBundle.glb.bundle ?? null);
433
+ } else {
434
+ setExtractedBundle(null);
435
+ }
436
+ }, [initialAssetBundle]);
437
+ const assetBundle = useMemo(
438
+ () => mergeAssetBundle(initialAssetBundle, extractedBundle),
439
+ [initialAssetBundle, extractedBundle]
440
+ );
291
441
  const {
292
442
  ready,
293
443
  createOrchestrator,
@@ -407,27 +557,36 @@ function VizijRuntimeProviderInner({
407
557
  try {
408
558
  let world;
409
559
  let animatables;
560
+ let bundle = assetBundle.bundle ?? null;
410
561
  if (assetBundle.glb.kind === "url") {
411
- [world, animatables] = await loadGLTF(
562
+ const loaded = await loadGLTFWithBundle(
412
563
  assetBundle.glb.src,
413
564
  [namespace],
414
565
  assetBundle.glb.aggressiveImport ?? false,
415
566
  assetBundle.glb.rootBounds
416
567
  );
568
+ world = loaded.world;
569
+ animatables = loaded.animatables;
570
+ bundle = loaded.bundle ?? bundle;
417
571
  } else if (assetBundle.glb.kind === "blob") {
418
- [world, animatables] = await loadGLTFFromBlob(
572
+ const loaded = await loadGLTFFromBlobWithBundle(
419
573
  assetBundle.glb.blob,
420
574
  [namespace],
421
575
  assetBundle.glb.aggressiveImport ?? false,
422
576
  assetBundle.glb.rootBounds
423
577
  );
578
+ world = loaded.world;
579
+ animatables = loaded.animatables;
580
+ bundle = loaded.bundle ?? bundle;
424
581
  } else {
425
582
  world = assetBundle.glb.world;
426
583
  animatables = assetBundle.glb.animatables;
584
+ bundle = assetBundle.glb.bundle ?? bundle;
427
585
  }
428
586
  if (cancelled) {
429
587
  return;
430
588
  }
589
+ setExtractedBundle(bundle ?? null);
431
590
  const rootId = findRootId(world);
432
591
  store.getState().addWorldElements(world, animatables, true);
433
592
  reportStatus((prev) => ({
@@ -464,7 +623,8 @@ function VizijRuntimeProviderInner({
464
623
  store,
465
624
  pushError,
466
625
  reportStatus,
467
- resetErrors
626
+ resetErrors,
627
+ setExtractedBundle
468
628
  ]);
469
629
  useEffect(() => {
470
630
  if (!ready && autoCreate) {
@@ -480,15 +640,25 @@ function VizijRuntimeProviderInner({
480
640
  }, [ready, autoCreate, createOrchestrator, pushError]);
481
641
  const registerControllers = useCallback(async () => {
482
642
  const normalize = (spec) => spec;
483
- const rigSpec = normalize(assetBundle.rig.spec);
643
+ clearControllers();
644
+ const rigAsset = assetBundle.rig;
645
+ if (!rigAsset) {
646
+ pushError({
647
+ message: "Asset bundle is missing a rig graph.",
648
+ phase: "registration",
649
+ timestamp: performance.now()
650
+ });
651
+ return;
652
+ }
653
+ const rigSpec = normalize(rigAsset.spec);
484
654
  const rigOutputs = collectOutputPaths(rigSpec);
485
655
  const rigInputs = collectInputPaths(rigSpec);
486
656
  rigInputMapRef.current = collectInputPathMap(rigSpec);
487
657
  outputPathsRef.current = new Set(rigOutputs);
488
658
  const rigConfig = {
489
- id: assetBundle.rig.id,
659
+ id: rigAsset.id,
490
660
  spec: rigSpec,
491
- subs: assetBundle.rig.subscriptions ?? {
661
+ subs: rigAsset.subscriptions ?? {
492
662
  inputs: rigInputs,
493
663
  outputs: rigOutputs
494
664
  }
@@ -507,7 +677,6 @@ function VizijRuntimeProviderInner({
507
677
  }
508
678
  });
509
679
  }
510
- clearControllers();
511
680
  const graphIds = [];
512
681
  try {
513
682
  if (graphConfigs.length > 1) {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@vizij/runtime-react",
3
3
  "description": "Runtime provider that bridges Vizij renderer assets with orchestrator controllers for React apps.",
4
- "version": "0.0.1",
4
+ "version": "0.0.3",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
7
7
  "types": "dist/index.d.ts",