@vizij/runtime-react 0.0.2 → 0.0.4
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 +8 -7
- package/dist/index.d.mts +4 -2
- package/dist/index.d.ts +4 -2
- package/dist/index.js +179 -15
- package/dist/index.mjs +179 -10
- package/package.json +4 -4
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`:
|
|
61
|
-
- `pose`: optional.
|
|
62
|
-
- `animations`: optional array.
|
|
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.
|
|
122
|
-
3.
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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:
|
|
666
|
+
id: rigAsset.id,
|
|
502
667
|
spec: rigSpec,
|
|
503
|
-
subs:
|
|
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
|
|
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
|
-
|
|
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
|
|
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,
|
|
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
|
|
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,
|
|
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 {
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
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:
|
|
659
|
+
id: rigAsset.id,
|
|
490
660
|
spec: rigSpec,
|
|
491
|
-
subs:
|
|
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.
|
|
4
|
+
"version": "0.0.4",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.mjs",
|
|
7
7
|
"types": "dist/index.d.ts",
|
|
@@ -38,9 +38,9 @@
|
|
|
38
38
|
"prepack": "pnpm run build && pnpm run test && pnpm run typecheck && pnpm run lint"
|
|
39
39
|
},
|
|
40
40
|
"dependencies": {
|
|
41
|
-
"@vizij/orchestrator-react": "
|
|
42
|
-
"@vizij/render": "
|
|
43
|
-
"@vizij/utils": "
|
|
41
|
+
"@vizij/orchestrator-react": "^0.0.2",
|
|
42
|
+
"@vizij/render": "^0.0.4",
|
|
43
|
+
"@vizij/utils": "^0.0.2",
|
|
44
44
|
"@vizij/value-json": "^0.1.0"
|
|
45
45
|
},
|
|
46
46
|
"peerDependencies": {
|