@vizij/runtime-react 0.0.14 → 0.1.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/README.md +9 -1
- package/dist/{index.mjs → index.cjs} +661 -195
- package/dist/{index.d.mts → index.d.cts} +32 -3
- package/dist/index.d.ts +32 -3
- package/dist/index.js +659 -199
- package/package.json +12 -10
package/dist/index.js
CHANGED
|
@@ -1,42 +1,30 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
var __defProp = Object.defineProperty;
|
|
3
|
-
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
-
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
-
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
-
var __export = (target, all) => {
|
|
7
|
-
for (var name in all)
|
|
8
|
-
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
-
};
|
|
10
|
-
var __copyProps = (to, from, except, desc) => {
|
|
11
|
-
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
-
for (let key of __getOwnPropNames(from))
|
|
13
|
-
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
-
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
-
}
|
|
16
|
-
return to;
|
|
17
|
-
};
|
|
18
|
-
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
-
|
|
20
|
-
// src/index.ts
|
|
21
|
-
var index_exports = {};
|
|
22
|
-
__export(index_exports, {
|
|
23
|
-
VizijRuntimeFace: () => VizijRuntimeFace,
|
|
24
|
-
VizijRuntimeProvider: () => VizijRuntimeProvider,
|
|
25
|
-
useRigInput: () => useRigInput,
|
|
26
|
-
useVizijOutputs: () => useVizijOutputs,
|
|
27
|
-
useVizijRuntime: () => useVizijRuntime
|
|
28
|
-
});
|
|
29
|
-
module.exports = __toCommonJS(index_exports);
|
|
30
|
-
|
|
31
1
|
// src/VizijRuntimeProvider.tsx
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
2
|
+
import {
|
|
3
|
+
useCallback,
|
|
4
|
+
useContext,
|
|
5
|
+
useEffect,
|
|
6
|
+
useMemo,
|
|
7
|
+
useRef,
|
|
8
|
+
useState
|
|
9
|
+
} from "react";
|
|
10
|
+
import {
|
|
11
|
+
VizijContext,
|
|
12
|
+
createVizijStore,
|
|
13
|
+
loadGLTFWithBundle,
|
|
14
|
+
loadGLTFFromBlobWithBundle
|
|
15
|
+
} from "@vizij/render";
|
|
16
|
+
import {
|
|
17
|
+
OrchestratorProvider,
|
|
18
|
+
OrchestratorContext,
|
|
19
|
+
useOrchestrator,
|
|
20
|
+
useOrchFrame
|
|
21
|
+
} from "@vizij/orchestrator-react";
|
|
22
|
+
import { compileIrGraph } from "@vizij/node-graph-authoring";
|
|
23
|
+
import { valueAsNumber as valueAsNumber2 } from "@vizij/value-json";
|
|
36
24
|
|
|
37
25
|
// src/context.ts
|
|
38
|
-
|
|
39
|
-
var VizijRuntimeContext =
|
|
26
|
+
import { createContext } from "react";
|
|
27
|
+
var VizijRuntimeContext = createContext(null);
|
|
40
28
|
|
|
41
29
|
// src/utils/graph.ts
|
|
42
30
|
function getNodes(spec) {
|
|
@@ -99,7 +87,15 @@ function collectInputPathMap(spec) {
|
|
|
99
87
|
}
|
|
100
88
|
|
|
101
89
|
// src/utils/valueConversion.ts
|
|
102
|
-
|
|
90
|
+
import {
|
|
91
|
+
isNormalizedValue,
|
|
92
|
+
valueAsBool,
|
|
93
|
+
valueAsColorRgba,
|
|
94
|
+
valueAsNumber,
|
|
95
|
+
valueAsText,
|
|
96
|
+
valueAsTransform,
|
|
97
|
+
valueAsVector
|
|
98
|
+
} from "@vizij/value-json";
|
|
103
99
|
function numericArrayToRaw(arr) {
|
|
104
100
|
const normalised = arr.map((entry) => Number(entry ?? 0));
|
|
105
101
|
switch (normalised.length) {
|
|
@@ -151,20 +147,20 @@ function valueJSONToRaw(value) {
|
|
|
151
147
|
]);
|
|
152
148
|
return Object.fromEntries(entries);
|
|
153
149
|
}
|
|
154
|
-
if (!
|
|
150
|
+
if (!isNormalizedValue(value)) {
|
|
155
151
|
return void 0;
|
|
156
152
|
}
|
|
157
153
|
switch (value.type) {
|
|
158
154
|
case "float": {
|
|
159
|
-
const num =
|
|
155
|
+
const num = valueAsNumber(value);
|
|
160
156
|
return typeof num === "number" ? num : void 0;
|
|
161
157
|
}
|
|
162
158
|
case "bool": {
|
|
163
|
-
const boolVal =
|
|
159
|
+
const boolVal = valueAsBool(value);
|
|
164
160
|
return typeof boolVal === "boolean" ? boolVal : void 0;
|
|
165
161
|
}
|
|
166
162
|
case "text": {
|
|
167
|
-
const text =
|
|
163
|
+
const text = valueAsText(value);
|
|
168
164
|
return typeof text === "string" ? text : void 0;
|
|
169
165
|
}
|
|
170
166
|
case "vec2":
|
|
@@ -172,11 +168,11 @@ function valueJSONToRaw(value) {
|
|
|
172
168
|
case "vec4":
|
|
173
169
|
case "quat":
|
|
174
170
|
case "vector": {
|
|
175
|
-
const vec =
|
|
171
|
+
const vec = valueAsVector(value);
|
|
176
172
|
return vec ? numericArrayToRaw(vec) : void 0;
|
|
177
173
|
}
|
|
178
174
|
case "colorrgba": {
|
|
179
|
-
const color =
|
|
175
|
+
const color = valueAsColorRgba(value);
|
|
180
176
|
if (!color) {
|
|
181
177
|
return void 0;
|
|
182
178
|
}
|
|
@@ -184,7 +180,7 @@ function valueJSONToRaw(value) {
|
|
|
184
180
|
return { r, g, b, a };
|
|
185
181
|
}
|
|
186
182
|
case "transform": {
|
|
187
|
-
const transform =
|
|
183
|
+
const transform = valueAsTransform(value);
|
|
188
184
|
if (!transform) {
|
|
189
185
|
return void 0;
|
|
190
186
|
}
|
|
@@ -214,7 +210,10 @@ function valueJSONToRaw(value) {
|
|
|
214
210
|
}
|
|
215
211
|
|
|
216
212
|
// src/VizijRuntimeProvider.tsx
|
|
217
|
-
|
|
213
|
+
import { jsx } from "react/jsx-runtime";
|
|
214
|
+
var ACTIVE_GRACE_MS = 250;
|
|
215
|
+
var VISIBLE_IDLE_FPS = 30;
|
|
216
|
+
var HIDDEN_IDLE_FPS = 1;
|
|
218
217
|
var DEFAULT_MERGE = {
|
|
219
218
|
outputs: "add",
|
|
220
219
|
intermediate: "add"
|
|
@@ -252,6 +251,166 @@ function normalisePath(path) {
|
|
|
252
251
|
function normaliseBundleKind(kind) {
|
|
253
252
|
return typeof kind === "string" ? kind.toLowerCase() : "";
|
|
254
253
|
}
|
|
254
|
+
function addConstraintVariant(map, key, constraint) {
|
|
255
|
+
if (!key) return;
|
|
256
|
+
if (!map[key]) {
|
|
257
|
+
map[key] = constraint;
|
|
258
|
+
}
|
|
259
|
+
}
|
|
260
|
+
function stripRigFacePrefix(path) {
|
|
261
|
+
const trimmed = path.startsWith("/") ? path.slice(1) : path;
|
|
262
|
+
const match = /^rig\/[^/]+\/(.+)$/.exec(trimmed);
|
|
263
|
+
if (match && match[1]) {
|
|
264
|
+
return match[1];
|
|
265
|
+
}
|
|
266
|
+
if (trimmed.startsWith("rig/")) {
|
|
267
|
+
return trimmed.slice("rig/".length);
|
|
268
|
+
}
|
|
269
|
+
return trimmed;
|
|
270
|
+
}
|
|
271
|
+
function extractInputConstraints(spec, extraInputs, namespace) {
|
|
272
|
+
if (!spec || typeof spec !== "object") {
|
|
273
|
+
return {};
|
|
274
|
+
}
|
|
275
|
+
const inputs = [];
|
|
276
|
+
if (Array.isArray(extraInputs)) {
|
|
277
|
+
inputs.push(...extraInputs);
|
|
278
|
+
}
|
|
279
|
+
const entries = spec.metadata?.vizij?.inputs;
|
|
280
|
+
if (Array.isArray(entries)) {
|
|
281
|
+
entries.forEach((entry) => {
|
|
282
|
+
if (entry && typeof entry === "object") {
|
|
283
|
+
inputs.push(entry);
|
|
284
|
+
}
|
|
285
|
+
});
|
|
286
|
+
}
|
|
287
|
+
if (inputs.length === 0) {
|
|
288
|
+
return {};
|
|
289
|
+
}
|
|
290
|
+
const map = {};
|
|
291
|
+
inputs.forEach((entry) => {
|
|
292
|
+
const path = entry.path;
|
|
293
|
+
if (typeof path !== "string") return;
|
|
294
|
+
const namespaced = namespaceTypedPath(path, namespace);
|
|
295
|
+
const stripped = stripRigFacePrefix(path);
|
|
296
|
+
const strippedNamespaced = stripped ? namespaceTypedPath(stripped, namespace) : stripped;
|
|
297
|
+
const min = entry.range?.min;
|
|
298
|
+
const max = entry.range?.max;
|
|
299
|
+
const defaultValue = entry.defaultValue;
|
|
300
|
+
const constraint = {
|
|
301
|
+
...Number.isFinite(Number(min)) ? { min: Number(min) } : {},
|
|
302
|
+
...Number.isFinite(Number(max)) ? { max: Number(max) } : {},
|
|
303
|
+
...Number.isFinite(Number(defaultValue)) ? { defaultValue: Number(defaultValue) } : {}
|
|
304
|
+
};
|
|
305
|
+
addConstraintVariant(map, namespaced, constraint);
|
|
306
|
+
addConstraintVariant(map, path, constraint);
|
|
307
|
+
if (stripped) {
|
|
308
|
+
addConstraintVariant(map, stripped, constraint);
|
|
309
|
+
}
|
|
310
|
+
if (strippedNamespaced) {
|
|
311
|
+
addConstraintVariant(map, strippedNamespaced, constraint);
|
|
312
|
+
}
|
|
313
|
+
});
|
|
314
|
+
return map;
|
|
315
|
+
}
|
|
316
|
+
function namespaceTypedPath(path, namespace) {
|
|
317
|
+
const trimmed = typeof path === "string" ? path.trim() : "";
|
|
318
|
+
if (!trimmed) {
|
|
319
|
+
return trimmed;
|
|
320
|
+
}
|
|
321
|
+
const prefix = `${namespace}/`;
|
|
322
|
+
if (trimmed.startsWith(prefix)) {
|
|
323
|
+
return trimmed;
|
|
324
|
+
}
|
|
325
|
+
if (trimmed.startsWith("debug/")) {
|
|
326
|
+
const rest = trimmed.slice("debug/".length);
|
|
327
|
+
const namespacedRest = namespaceTypedPath(rest, namespace);
|
|
328
|
+
return namespacedRest.startsWith("debug/") ? namespacedRest : `debug/${namespacedRest}`;
|
|
329
|
+
}
|
|
330
|
+
return `${prefix}${trimmed}`;
|
|
331
|
+
}
|
|
332
|
+
function stripNamespace(path, namespace) {
|
|
333
|
+
const prefix = `${namespace}/`;
|
|
334
|
+
if (path.startsWith(prefix)) {
|
|
335
|
+
return path.slice(prefix.length);
|
|
336
|
+
}
|
|
337
|
+
const debugPrefix = `debug/${prefix}`;
|
|
338
|
+
if (path.startsWith(debugPrefix)) {
|
|
339
|
+
return path.slice(debugPrefix.length);
|
|
340
|
+
}
|
|
341
|
+
if (path.startsWith("debug/")) {
|
|
342
|
+
return path.slice("debug/".length);
|
|
343
|
+
}
|
|
344
|
+
return path;
|
|
345
|
+
}
|
|
346
|
+
function namespaceControllerId(id, namespace, kind = "graph") {
|
|
347
|
+
if (!id) {
|
|
348
|
+
return void 0;
|
|
349
|
+
}
|
|
350
|
+
const trimmed = id.trim();
|
|
351
|
+
if (!trimmed) {
|
|
352
|
+
return void 0;
|
|
353
|
+
}
|
|
354
|
+
const prefix = `${namespace}/${kind}/`;
|
|
355
|
+
if (trimmed.startsWith(prefix)) {
|
|
356
|
+
return trimmed;
|
|
357
|
+
}
|
|
358
|
+
return `${prefix}${trimmed}`;
|
|
359
|
+
}
|
|
360
|
+
function namespaceSubscriptions(subs, namespace) {
|
|
361
|
+
if (!subs) {
|
|
362
|
+
return void 0;
|
|
363
|
+
}
|
|
364
|
+
const inputs = Array.isArray(subs.inputs) ? subs.inputs.map((path) => namespaceTypedPath(path, namespace)) : void 0;
|
|
365
|
+
const outputs = Array.isArray(subs.outputs) ? subs.outputs.map((path) => namespaceTypedPath(path, namespace)) : void 0;
|
|
366
|
+
if (!inputs && !outputs) {
|
|
367
|
+
return subs;
|
|
368
|
+
}
|
|
369
|
+
return {
|
|
370
|
+
...subs,
|
|
371
|
+
...inputs ? { inputs } : {},
|
|
372
|
+
...outputs ? { outputs } : {}
|
|
373
|
+
};
|
|
374
|
+
}
|
|
375
|
+
function namespaceGraphSpec(spec, namespace) {
|
|
376
|
+
if (!spec || typeof spec !== "object") {
|
|
377
|
+
return spec;
|
|
378
|
+
}
|
|
379
|
+
const nodes = spec.nodes;
|
|
380
|
+
if (!Array.isArray(nodes)) {
|
|
381
|
+
return spec;
|
|
382
|
+
}
|
|
383
|
+
let changed = false;
|
|
384
|
+
const nextNodes = nodes.map((node) => {
|
|
385
|
+
if (!node || typeof node !== "object") {
|
|
386
|
+
return node;
|
|
387
|
+
}
|
|
388
|
+
const path = node.params?.path;
|
|
389
|
+
if (typeof path !== "string") {
|
|
390
|
+
return node;
|
|
391
|
+
}
|
|
392
|
+
const namespacedPath = namespaceTypedPath(path, namespace);
|
|
393
|
+
if (namespacedPath === path) {
|
|
394
|
+
return node;
|
|
395
|
+
}
|
|
396
|
+
changed = true;
|
|
397
|
+
return {
|
|
398
|
+
...node,
|
|
399
|
+
params: {
|
|
400
|
+
...node.params ?? {},
|
|
401
|
+
path: namespacedPath
|
|
402
|
+
}
|
|
403
|
+
};
|
|
404
|
+
});
|
|
405
|
+
if (!changed) {
|
|
406
|
+
return spec;
|
|
407
|
+
}
|
|
408
|
+
return {
|
|
409
|
+
...spec,
|
|
410
|
+
nodes: nextNodes
|
|
411
|
+
};
|
|
412
|
+
}
|
|
413
|
+
var now = () => typeof performance !== "undefined" ? performance.now() : Date.now();
|
|
255
414
|
function pickBundleGraph(bundle, preferredKinds) {
|
|
256
415
|
if (!bundle?.graphs || bundle.graphs.length === 0) {
|
|
257
416
|
return null;
|
|
@@ -271,14 +430,91 @@ function pickBundleGraph(bundle, preferredKinds) {
|
|
|
271
430
|
}
|
|
272
431
|
return null;
|
|
273
432
|
}
|
|
433
|
+
function extractIrGraph(payload) {
|
|
434
|
+
if (!payload || typeof payload !== "object") {
|
|
435
|
+
return void 0;
|
|
436
|
+
}
|
|
437
|
+
return payload;
|
|
438
|
+
}
|
|
274
439
|
function convertBundleGraph(entry) {
|
|
275
|
-
if (!entry || !entry.id
|
|
440
|
+
if (!entry || !entry.id) {
|
|
441
|
+
return null;
|
|
442
|
+
}
|
|
443
|
+
const rawSpec = entry.spec;
|
|
444
|
+
const inputMetadata = extractVizijInputMetadata(
|
|
445
|
+
rawSpec
|
|
446
|
+
);
|
|
447
|
+
const spec = rawSpec ? stripVizijMetadata(rawSpec) : void 0;
|
|
448
|
+
const ir = extractIrGraph(entry.ir);
|
|
449
|
+
if (!spec && !ir) {
|
|
276
450
|
return null;
|
|
277
451
|
}
|
|
278
452
|
return {
|
|
279
453
|
id: entry.id,
|
|
280
|
-
spec
|
|
454
|
+
spec,
|
|
455
|
+
ir: ir ?? null,
|
|
456
|
+
inputMetadata
|
|
457
|
+
};
|
|
458
|
+
}
|
|
459
|
+
function resolveGraphSpec(asset, context) {
|
|
460
|
+
if (asset.spec) {
|
|
461
|
+
return stripVizijMetadata(asset.spec);
|
|
462
|
+
}
|
|
463
|
+
if (asset.ir) {
|
|
464
|
+
try {
|
|
465
|
+
const compiled = compileIrGraph(asset.ir, { preferLegacySpec: false });
|
|
466
|
+
if (compiled.issues && compiled.issues.length > 0) {
|
|
467
|
+
console.warn(
|
|
468
|
+
`[vizij-runtime] IR compile for graph "${context}" reported issues`,
|
|
469
|
+
compiled.issues
|
|
470
|
+
);
|
|
471
|
+
}
|
|
472
|
+
return stripVizijMetadata(compiled.spec);
|
|
473
|
+
} catch (error) {
|
|
474
|
+
console.warn(
|
|
475
|
+
`[vizij-runtime] Failed to compile IR graph "${context}"`,
|
|
476
|
+
error
|
|
477
|
+
);
|
|
478
|
+
}
|
|
479
|
+
}
|
|
480
|
+
return null;
|
|
481
|
+
}
|
|
482
|
+
function stripVizijMetadata(spec) {
|
|
483
|
+
if (!spec || typeof spec !== "object") {
|
|
484
|
+
return spec;
|
|
485
|
+
}
|
|
486
|
+
const cloned = {
|
|
487
|
+
...spec,
|
|
488
|
+
nodes: spec.nodes ? spec.nodes.map((node) => ({ ...node })) : spec.nodes,
|
|
489
|
+
edges: spec.edges ? spec.edges.map((edge) => ({ ...edge })) : spec.edges
|
|
281
490
|
};
|
|
491
|
+
if (cloned.metadata && typeof cloned.metadata === "object") {
|
|
492
|
+
const metadata = { ...cloned.metadata };
|
|
493
|
+
if ("vizij" in metadata) {
|
|
494
|
+
delete metadata.vizij;
|
|
495
|
+
}
|
|
496
|
+
if (Object.keys(metadata).length === 0) {
|
|
497
|
+
delete cloned.metadata;
|
|
498
|
+
} else {
|
|
499
|
+
cloned.metadata = metadata;
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
return cloned;
|
|
503
|
+
}
|
|
504
|
+
function extractVizijInputMetadata(spec) {
|
|
505
|
+
if (!spec || typeof spec !== "object") {
|
|
506
|
+
return [];
|
|
507
|
+
}
|
|
508
|
+
const inputs = spec.metadata?.vizij?.inputs;
|
|
509
|
+
if (!Array.isArray(inputs)) {
|
|
510
|
+
return [];
|
|
511
|
+
}
|
|
512
|
+
return inputs.map((entry) => {
|
|
513
|
+
if (!entry || typeof entry !== "object") {
|
|
514
|
+
return null;
|
|
515
|
+
}
|
|
516
|
+
return entry;
|
|
517
|
+
}).filter(Boolean);
|
|
282
518
|
}
|
|
283
519
|
function convertBundleAnimations(entries) {
|
|
284
520
|
if (!Array.isArray(entries) || entries.length === 0) {
|
|
@@ -502,36 +738,53 @@ function VizijRuntimeProvider({
|
|
|
502
738
|
autoCreate = true,
|
|
503
739
|
createOptions,
|
|
504
740
|
autostart = false,
|
|
741
|
+
driveOrchestrator = true,
|
|
505
742
|
mergeStrategy,
|
|
506
743
|
onRegisterControllers,
|
|
507
|
-
onStatusChange
|
|
744
|
+
onStatusChange,
|
|
745
|
+
orchestratorScope = "auto"
|
|
508
746
|
}) {
|
|
509
|
-
const storeRef =
|
|
747
|
+
const storeRef = useRef(null);
|
|
510
748
|
if (!storeRef.current) {
|
|
511
|
-
storeRef.current =
|
|
749
|
+
storeRef.current = createVizijStore();
|
|
512
750
|
}
|
|
513
|
-
|
|
514
|
-
|
|
751
|
+
const parentOrchestrator = useContext(OrchestratorContext);
|
|
752
|
+
const hasParentOrchestrator = Boolean(parentOrchestrator);
|
|
753
|
+
const shouldProvideOrchestrator = orchestratorScope === "isolated" || !hasParentOrchestrator && orchestratorScope !== "shared";
|
|
754
|
+
if (orchestratorScope === "shared" && !hasParentOrchestrator) {
|
|
755
|
+
console.warn(
|
|
756
|
+
'[vizij-runtime] orchestratorScope="shared" requires an OrchestratorProvider higher in the tree; falling back to an isolated provider.'
|
|
757
|
+
);
|
|
758
|
+
}
|
|
759
|
+
const runtimeTree = /* @__PURE__ */ jsx(VizijContext.Provider, { value: storeRef.current, children: /* @__PURE__ */ jsx(
|
|
760
|
+
VizijRuntimeProviderInner,
|
|
515
761
|
{
|
|
762
|
+
assetBundle,
|
|
763
|
+
namespace: namespaceProp,
|
|
764
|
+
faceId: faceIdProp,
|
|
516
765
|
autoCreate,
|
|
517
|
-
createOptions,
|
|
518
766
|
autostart,
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
mergeStrategy,
|
|
527
|
-
onRegisterControllers,
|
|
528
|
-
onStatusChange,
|
|
529
|
-
store: storeRef.current,
|
|
530
|
-
children
|
|
531
|
-
}
|
|
532
|
-
)
|
|
767
|
+
driveOrchestrator,
|
|
768
|
+
createOptions,
|
|
769
|
+
mergeStrategy,
|
|
770
|
+
onRegisterControllers,
|
|
771
|
+
onStatusChange,
|
|
772
|
+
store: storeRef.current,
|
|
773
|
+
children
|
|
533
774
|
}
|
|
534
775
|
) });
|
|
776
|
+
if (!shouldProvideOrchestrator) {
|
|
777
|
+
return runtimeTree;
|
|
778
|
+
}
|
|
779
|
+
return /* @__PURE__ */ jsx(
|
|
780
|
+
OrchestratorProvider,
|
|
781
|
+
{
|
|
782
|
+
autoCreate,
|
|
783
|
+
createOptions,
|
|
784
|
+
autostart: false,
|
|
785
|
+
children: runtimeTree
|
|
786
|
+
}
|
|
787
|
+
);
|
|
535
788
|
}
|
|
536
789
|
function VizijRuntimeProviderInner({
|
|
537
790
|
assetBundle: initialAssetBundle,
|
|
@@ -542,9 +795,12 @@ function VizijRuntimeProviderInner({
|
|
|
542
795
|
onStatusChange,
|
|
543
796
|
store,
|
|
544
797
|
children,
|
|
545
|
-
autoCreate
|
|
798
|
+
autoCreate,
|
|
799
|
+
autostart,
|
|
800
|
+
createOptions,
|
|
801
|
+
driveOrchestrator
|
|
546
802
|
}) {
|
|
547
|
-
const [extractedBundle, setExtractedBundle] =
|
|
803
|
+
const [extractedBundle, setExtractedBundle] = useState(() => {
|
|
548
804
|
if (initialAssetBundle.bundle) {
|
|
549
805
|
return initialAssetBundle.bundle;
|
|
550
806
|
}
|
|
@@ -553,8 +809,8 @@ function VizijRuntimeProviderInner({
|
|
|
553
809
|
}
|
|
554
810
|
return null;
|
|
555
811
|
});
|
|
556
|
-
const [extractedAnimations, setExtractedAnimations] =
|
|
557
|
-
|
|
812
|
+
const [extractedAnimations, setExtractedAnimations] = useState([]);
|
|
813
|
+
useEffect(() => {
|
|
558
814
|
if (initialAssetBundle.bundle) {
|
|
559
815
|
setExtractedBundle(initialAssetBundle.bundle);
|
|
560
816
|
return;
|
|
@@ -565,7 +821,7 @@ function VizijRuntimeProviderInner({
|
|
|
565
821
|
setExtractedBundle(null);
|
|
566
822
|
}
|
|
567
823
|
}, [initialAssetBundle]);
|
|
568
|
-
const assetBundle =
|
|
824
|
+
const assetBundle = useMemo(
|
|
569
825
|
() => mergeAssetBundle(
|
|
570
826
|
initialAssetBundle,
|
|
571
827
|
extractedBundle,
|
|
@@ -582,14 +838,14 @@ function VizijRuntimeProviderInner({
|
|
|
582
838
|
removeGraph,
|
|
583
839
|
removeAnimation,
|
|
584
840
|
listControllers,
|
|
585
|
-
setInput,
|
|
841
|
+
setInput: orchestratorSetInput,
|
|
586
842
|
getPathSnapshot,
|
|
587
843
|
step: stepRuntime
|
|
588
|
-
} =
|
|
589
|
-
const frame =
|
|
844
|
+
} = useOrchestrator();
|
|
845
|
+
const frame = useOrchFrame();
|
|
590
846
|
const namespace = namespaceProp ?? assetBundle.namespace ?? "default";
|
|
591
847
|
const faceId = faceIdProp ?? assetBundle.faceId ?? assetBundle.pose?.config?.faceId ?? assetBundle.pose?.config?.faceId ?? void 0;
|
|
592
|
-
const [status, setStatus] =
|
|
848
|
+
const [status, setStatus] = useState({
|
|
593
849
|
loading: true,
|
|
594
850
|
ready: false,
|
|
595
851
|
error: null,
|
|
@@ -598,19 +854,98 @@ function VizijRuntimeProviderInner({
|
|
|
598
854
|
faceId,
|
|
599
855
|
rootId: null,
|
|
600
856
|
outputPaths: [],
|
|
857
|
+
stepHz: void 0,
|
|
601
858
|
controllers: { graphs: [], anims: [] }
|
|
602
859
|
});
|
|
603
|
-
const errorsRef =
|
|
604
|
-
const outputPathsRef =
|
|
605
|
-
const
|
|
606
|
-
const
|
|
607
|
-
const
|
|
608
|
-
const
|
|
609
|
-
const
|
|
610
|
-
const
|
|
611
|
-
const
|
|
612
|
-
const
|
|
613
|
-
const
|
|
860
|
+
const errorsRef = useRef([]);
|
|
861
|
+
const outputPathsRef = useRef(/* @__PURE__ */ new Set());
|
|
862
|
+
const baseOutputPathsRef = useRef(/* @__PURE__ */ new Set());
|
|
863
|
+
const namespacedOutputPathsRef = useRef(/* @__PURE__ */ new Set());
|
|
864
|
+
const namespaceRef = useRef(namespace);
|
|
865
|
+
const driveOrchestratorRef = useRef(driveOrchestrator);
|
|
866
|
+
const rigInputMapRef = useRef({});
|
|
867
|
+
const registeredGraphsRef = useRef([]);
|
|
868
|
+
const registeredAnimationsRef = useRef([]);
|
|
869
|
+
const mergedGraphRef = useRef(null);
|
|
870
|
+
const [inputConstraints, setInputConstraints] = useState({});
|
|
871
|
+
const avgStepDtRef = useRef(null);
|
|
872
|
+
const animationTweensRef = useRef(/* @__PURE__ */ new Map());
|
|
873
|
+
const clipPlaybackRef = useRef(/* @__PURE__ */ new Map());
|
|
874
|
+
const stagedInputsRef = useRef(/* @__PURE__ */ new Map());
|
|
875
|
+
const autostartRef = useRef(autostart);
|
|
876
|
+
const lastActivityTimeRef = useRef(now());
|
|
877
|
+
const [loopMode, setLoopMode] = useState("stopped");
|
|
878
|
+
const loopModeRef = useRef("stopped");
|
|
879
|
+
useEffect(() => {
|
|
880
|
+
loopModeRef.current = loopMode;
|
|
881
|
+
}, [loopMode]);
|
|
882
|
+
const runtimeMountedRef = useRef(true);
|
|
883
|
+
useEffect(() => {
|
|
884
|
+
return () => {
|
|
885
|
+
runtimeMountedRef.current = false;
|
|
886
|
+
};
|
|
887
|
+
}, []);
|
|
888
|
+
useEffect(() => {
|
|
889
|
+
const rigAsset = assetBundle.rig;
|
|
890
|
+
if (!rigAsset) {
|
|
891
|
+
setInputConstraints({});
|
|
892
|
+
return;
|
|
893
|
+
}
|
|
894
|
+
const rigSpec = resolveGraphSpec(
|
|
895
|
+
rigAsset,
|
|
896
|
+
`${rigAsset.id ?? "rig"} graph (constraints)`
|
|
897
|
+
);
|
|
898
|
+
const constraints = extractInputConstraints(
|
|
899
|
+
rigSpec,
|
|
900
|
+
rigAsset.inputMetadata,
|
|
901
|
+
namespace
|
|
902
|
+
);
|
|
903
|
+
setInputConstraints(constraints);
|
|
904
|
+
const isDevEnv = typeof globalThis !== "undefined" && Boolean(globalThis?.process?.env?.NODE_ENV !== "production");
|
|
905
|
+
if (isDevEnv) {
|
|
906
|
+
const size = Object.keys(constraints).length;
|
|
907
|
+
console.log("[vizij-runtime] input constraints computed", size, {
|
|
908
|
+
namespace,
|
|
909
|
+
rigId: rigAsset.id
|
|
910
|
+
});
|
|
911
|
+
}
|
|
912
|
+
}, [assetBundle.rig, namespace]);
|
|
913
|
+
const requestLoopMode = useCallback((mode) => {
|
|
914
|
+
if (!runtimeMountedRef.current) {
|
|
915
|
+
return;
|
|
916
|
+
}
|
|
917
|
+
setLoopMode((prev) => prev === mode ? prev : mode);
|
|
918
|
+
}, []);
|
|
919
|
+
const hasActiveAnimations = useCallback(() => {
|
|
920
|
+
return animationTweensRef.current.size > 0 || clipPlaybackRef.current.size > 0;
|
|
921
|
+
}, []);
|
|
922
|
+
const computeDesiredLoopMode = useCallback(() => {
|
|
923
|
+
const hasAnimations = hasActiveAnimations();
|
|
924
|
+
const recentlyActive = now() - lastActivityTimeRef.current <= ACTIVE_GRACE_MS;
|
|
925
|
+
if (autostartRef.current && (hasAnimations || recentlyActive)) {
|
|
926
|
+
return "active";
|
|
927
|
+
}
|
|
928
|
+
if (autostartRef.current) {
|
|
929
|
+
return "idle-visible";
|
|
930
|
+
}
|
|
931
|
+
return "idle-hidden";
|
|
932
|
+
}, [hasActiveAnimations]);
|
|
933
|
+
const updateLoopMode = useCallback(() => {
|
|
934
|
+
requestLoopMode(computeDesiredLoopMode());
|
|
935
|
+
}, [computeDesiredLoopMode, requestLoopMode]);
|
|
936
|
+
const markActivity = useCallback(() => {
|
|
937
|
+
lastActivityTimeRef.current = now();
|
|
938
|
+
updateLoopMode();
|
|
939
|
+
}, [updateLoopMode]);
|
|
940
|
+
const setInput = useCallback(
|
|
941
|
+
(path, value, shape) => {
|
|
942
|
+
markActivity();
|
|
943
|
+
const namespacedPath = namespaceTypedPath(path, namespaceRef.current);
|
|
944
|
+
stagedInputsRef.current.set(namespacedPath, { value, shape });
|
|
945
|
+
},
|
|
946
|
+
[markActivity]
|
|
947
|
+
);
|
|
948
|
+
const reportStatus = useCallback(
|
|
614
949
|
(updater) => {
|
|
615
950
|
setStatus((prev) => {
|
|
616
951
|
const next = updater(prev);
|
|
@@ -620,7 +955,7 @@ function VizijRuntimeProviderInner({
|
|
|
620
955
|
},
|
|
621
956
|
[onStatusChange]
|
|
622
957
|
);
|
|
623
|
-
const pushError =
|
|
958
|
+
const pushError = useCallback(
|
|
624
959
|
(error) => {
|
|
625
960
|
errorsRef.current = [...errorsRef.current, error];
|
|
626
961
|
reportStatus((prev) => ({
|
|
@@ -632,7 +967,7 @@ function VizijRuntimeProviderInner({
|
|
|
632
967
|
},
|
|
633
968
|
[reportStatus]
|
|
634
969
|
);
|
|
635
|
-
const resetErrors =
|
|
970
|
+
const resetErrors = useCallback(() => {
|
|
636
971
|
errorsRef.current = [];
|
|
637
972
|
reportStatus((prev) => ({
|
|
638
973
|
...prev,
|
|
@@ -640,7 +975,11 @@ function VizijRuntimeProviderInner({
|
|
|
640
975
|
errors: []
|
|
641
976
|
}));
|
|
642
977
|
}, [reportStatus]);
|
|
643
|
-
|
|
978
|
+
useEffect(() => {
|
|
979
|
+
autostartRef.current = autostart;
|
|
980
|
+
updateLoopMode();
|
|
981
|
+
}, [autostart, updateLoopMode]);
|
|
982
|
+
const clearControllers = useCallback(() => {
|
|
644
983
|
const existing = listControllers();
|
|
645
984
|
existing.graphs.forEach((id) => {
|
|
646
985
|
try {
|
|
@@ -669,17 +1008,24 @@ function VizijRuntimeProviderInner({
|
|
|
669
1008
|
registeredGraphsRef.current = [];
|
|
670
1009
|
registeredAnimationsRef.current = [];
|
|
671
1010
|
mergedGraphRef.current = null;
|
|
1011
|
+
outputPathsRef.current = /* @__PURE__ */ new Set();
|
|
1012
|
+
baseOutputPathsRef.current = /* @__PURE__ */ new Set();
|
|
1013
|
+
namespacedOutputPathsRef.current = /* @__PURE__ */ new Set();
|
|
672
1014
|
}, [listControllers, removeAnimation, removeGraph, pushError]);
|
|
673
|
-
|
|
1015
|
+
useEffect(() => {
|
|
1016
|
+
namespaceRef.current = namespace;
|
|
674
1017
|
reportStatus((prev) => ({
|
|
675
1018
|
...prev,
|
|
676
1019
|
namespace,
|
|
677
1020
|
faceId
|
|
678
1021
|
}));
|
|
679
1022
|
}, [namespace, faceId, reportStatus]);
|
|
1023
|
+
useEffect(() => {
|
|
1024
|
+
driveOrchestratorRef.current = driveOrchestrator;
|
|
1025
|
+
}, [driveOrchestrator]);
|
|
680
1026
|
const glbAsset = initialAssetBundle.glb;
|
|
681
1027
|
const baseBundle = initialAssetBundle.bundle ?? null;
|
|
682
|
-
|
|
1028
|
+
useEffect(() => {
|
|
683
1029
|
let cancelled = false;
|
|
684
1030
|
resetErrors();
|
|
685
1031
|
reportStatus((prev) => ({
|
|
@@ -698,7 +1044,7 @@ function VizijRuntimeProviderInner({
|
|
|
698
1044
|
let bundle = baseBundle;
|
|
699
1045
|
let gltfAnimations;
|
|
700
1046
|
if (glbAsset.kind === "url") {
|
|
701
|
-
const loaded = await
|
|
1047
|
+
const loaded = await loadGLTFWithBundle(
|
|
702
1048
|
glbAsset.src,
|
|
703
1049
|
[namespace],
|
|
704
1050
|
glbAsset.aggressiveImport ?? false,
|
|
@@ -709,7 +1055,7 @@ function VizijRuntimeProviderInner({
|
|
|
709
1055
|
bundle = loaded.bundle ?? bundle;
|
|
710
1056
|
gltfAnimations = pickExtractedAnimations(loaded);
|
|
711
1057
|
} else if (glbAsset.kind === "blob") {
|
|
712
|
-
const loaded = await
|
|
1058
|
+
const loaded = await loadGLTFFromBlobWithBundle(
|
|
713
1059
|
glbAsset.blob,
|
|
714
1060
|
[namespace],
|
|
715
1061
|
glbAsset.aggressiveImport ?? false,
|
|
@@ -771,9 +1117,9 @@ function VizijRuntimeProviderInner({
|
|
|
771
1117
|
setExtractedBundle,
|
|
772
1118
|
setExtractedAnimations
|
|
773
1119
|
]);
|
|
774
|
-
|
|
1120
|
+
useEffect(() => {
|
|
775
1121
|
if (!ready && autoCreate) {
|
|
776
|
-
createOrchestrator().catch((err) => {
|
|
1122
|
+
createOrchestrator(createOptions).catch((err) => {
|
|
777
1123
|
pushError({
|
|
778
1124
|
message: "Failed to create orchestrator runtime",
|
|
779
1125
|
cause: err,
|
|
@@ -782,10 +1128,20 @@ function VizijRuntimeProviderInner({
|
|
|
782
1128
|
});
|
|
783
1129
|
});
|
|
784
1130
|
}
|
|
785
|
-
}, [ready, autoCreate, createOrchestrator, pushError]);
|
|
786
|
-
const registerControllers =
|
|
787
|
-
const normalize = (spec) => spec;
|
|
1131
|
+
}, [ready, autoCreate, createOptions, createOrchestrator, pushError]);
|
|
1132
|
+
const registerControllers = useCallback(async () => {
|
|
788
1133
|
clearControllers();
|
|
1134
|
+
const baseOutputPaths = /* @__PURE__ */ new Set();
|
|
1135
|
+
const namespacedOutputPaths = /* @__PURE__ */ new Set();
|
|
1136
|
+
const recordOutputs = (paths) => {
|
|
1137
|
+
paths.forEach((path) => {
|
|
1138
|
+
const trimmed = path.trim();
|
|
1139
|
+
if (!trimmed) return;
|
|
1140
|
+
const basePath = stripNamespace(trimmed, namespace);
|
|
1141
|
+
baseOutputPaths.add(basePath);
|
|
1142
|
+
namespacedOutputPaths.add(namespaceTypedPath(trimmed, namespace));
|
|
1143
|
+
});
|
|
1144
|
+
};
|
|
789
1145
|
const rigAsset = assetBundle.rig;
|
|
790
1146
|
if (!rigAsset) {
|
|
791
1147
|
pushError({
|
|
@@ -795,37 +1151,67 @@ function VizijRuntimeProviderInner({
|
|
|
795
1151
|
});
|
|
796
1152
|
return;
|
|
797
1153
|
}
|
|
798
|
-
const rigSpec =
|
|
1154
|
+
const rigSpec = resolveGraphSpec(rigAsset, `${rigAsset.id ?? "rig"} graph`);
|
|
1155
|
+
if (!rigSpec) {
|
|
1156
|
+
pushError({
|
|
1157
|
+
message: "Rig graph is missing a usable spec or IR payload.",
|
|
1158
|
+
phase: "registration",
|
|
1159
|
+
timestamp: performance.now()
|
|
1160
|
+
});
|
|
1161
|
+
return;
|
|
1162
|
+
}
|
|
799
1163
|
const rigOutputs = collectOutputPaths(rigSpec);
|
|
800
1164
|
const rigInputs = collectInputPaths(rigSpec);
|
|
801
1165
|
rigInputMapRef.current = collectInputPathMap(rigSpec);
|
|
802
|
-
|
|
803
|
-
const
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
subs: rigAsset.subscriptions ?? {
|
|
807
|
-
inputs: rigInputs,
|
|
808
|
-
outputs: rigOutputs
|
|
809
|
-
}
|
|
1166
|
+
recordOutputs(rigOutputs);
|
|
1167
|
+
const rigSubs = rigAsset.subscriptions ?? {
|
|
1168
|
+
inputs: rigInputs,
|
|
1169
|
+
outputs: rigOutputs
|
|
810
1170
|
};
|
|
811
|
-
const graphConfigs = [
|
|
812
|
-
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
|
|
819
|
-
|
|
1171
|
+
const graphConfigs = [
|
|
1172
|
+
{
|
|
1173
|
+
id: namespaceControllerId(rigAsset.id, namespace, "graph"),
|
|
1174
|
+
spec: namespaceGraphSpec(rigSpec, namespace),
|
|
1175
|
+
subs: namespaceSubscriptions(rigSubs, namespace)
|
|
1176
|
+
}
|
|
1177
|
+
];
|
|
1178
|
+
const poseGraphAsset = assetBundle.pose?.graph;
|
|
1179
|
+
if (poseGraphAsset) {
|
|
1180
|
+
const poseSpec = resolveGraphSpec(
|
|
1181
|
+
poseGraphAsset,
|
|
1182
|
+
`${poseGraphAsset.id ?? "pose"} graph`
|
|
1183
|
+
);
|
|
1184
|
+
if (poseSpec) {
|
|
1185
|
+
const poseOutputs = collectOutputPaths(poseSpec);
|
|
1186
|
+
const poseInputs = collectInputPaths(poseSpec);
|
|
1187
|
+
recordOutputs(poseOutputs);
|
|
1188
|
+
const poseSubs = poseGraphAsset.subscriptions ?? {
|
|
820
1189
|
inputs: poseInputs,
|
|
821
1190
|
outputs: poseOutputs
|
|
822
|
-
}
|
|
823
|
-
|
|
1191
|
+
};
|
|
1192
|
+
graphConfigs.push({
|
|
1193
|
+
id: namespaceControllerId(poseGraphAsset.id, namespace, "graph"),
|
|
1194
|
+
spec: namespaceGraphSpec(poseSpec, namespace),
|
|
1195
|
+
subs: namespaceSubscriptions(poseSubs, namespace)
|
|
1196
|
+
});
|
|
1197
|
+
} else {
|
|
1198
|
+
console.warn(
|
|
1199
|
+
"[vizij-runtime] Pose graph is missing a usable spec or IR payload; skipping registration."
|
|
1200
|
+
);
|
|
1201
|
+
}
|
|
824
1202
|
}
|
|
1203
|
+
outputPathsRef.current = namespacedOutputPaths;
|
|
1204
|
+
baseOutputPathsRef.current = baseOutputPaths;
|
|
1205
|
+
namespacedOutputPathsRef.current = namespacedOutputPaths;
|
|
825
1206
|
const graphIds = [];
|
|
826
1207
|
try {
|
|
827
1208
|
if (graphConfigs.length > 1) {
|
|
828
1209
|
const mergedId = registerMergedGraph({
|
|
1210
|
+
id: namespaceControllerId(
|
|
1211
|
+
mergedGraphRef.current ?? `merged-${namespace}`,
|
|
1212
|
+
namespace,
|
|
1213
|
+
"merged"
|
|
1214
|
+
) ?? void 0,
|
|
829
1215
|
graphs: graphConfigs,
|
|
830
1216
|
strategy: mergeStrategy ?? DEFAULT_MERGE
|
|
831
1217
|
});
|
|
@@ -849,8 +1235,9 @@ function VizijRuntimeProviderInner({
|
|
|
849
1235
|
const animationIds = [];
|
|
850
1236
|
for (const anim of assetBundle.animations ?? []) {
|
|
851
1237
|
try {
|
|
1238
|
+
const controllerId = namespaceControllerId(anim.id, namespace, "animation") ?? anim.id;
|
|
852
1239
|
const config = {
|
|
853
|
-
id:
|
|
1240
|
+
id: controllerId,
|
|
854
1241
|
setup: {
|
|
855
1242
|
animation: anim.clip,
|
|
856
1243
|
...anim.setup ?? {}
|
|
@@ -895,6 +1282,7 @@ function VizijRuntimeProviderInner({
|
|
|
895
1282
|
clearControllers,
|
|
896
1283
|
listControllers,
|
|
897
1284
|
mergeStrategy,
|
|
1285
|
+
namespace,
|
|
898
1286
|
onRegisterControllers,
|
|
899
1287
|
pushError,
|
|
900
1288
|
registerAnimation,
|
|
@@ -903,7 +1291,7 @@ function VizijRuntimeProviderInner({
|
|
|
903
1291
|
reportStatus,
|
|
904
1292
|
setInput
|
|
905
1293
|
]);
|
|
906
|
-
|
|
1294
|
+
useEffect(() => {
|
|
907
1295
|
if (!ready || status.loading) {
|
|
908
1296
|
return;
|
|
909
1297
|
}
|
|
@@ -916,7 +1304,7 @@ function VizijRuntimeProviderInner({
|
|
|
916
1304
|
});
|
|
917
1305
|
});
|
|
918
1306
|
}, [ready, status.loading, registerControllers, pushError]);
|
|
919
|
-
|
|
1307
|
+
useEffect(() => {
|
|
920
1308
|
if (!frame) {
|
|
921
1309
|
return;
|
|
922
1310
|
}
|
|
@@ -924,21 +1312,29 @@ function VizijRuntimeProviderInner({
|
|
|
924
1312
|
if (!writes.length) {
|
|
925
1313
|
return;
|
|
926
1314
|
}
|
|
927
|
-
const
|
|
1315
|
+
const setWorldValues = store.getState().setValues;
|
|
928
1316
|
const namespaceValue = status.namespace;
|
|
1317
|
+
const batched = [];
|
|
1318
|
+
const namespacedOutputs = namespacedOutputPathsRef.current;
|
|
1319
|
+
const baseOutputs = baseOutputPathsRef.current;
|
|
929
1320
|
writes.forEach((write) => {
|
|
930
1321
|
const path = normalisePath(write.path);
|
|
931
|
-
if (!
|
|
1322
|
+
if (!namespacedOutputs.has(path)) {
|
|
932
1323
|
return;
|
|
933
1324
|
}
|
|
934
1325
|
const raw = valueJSONToRaw(write.value);
|
|
935
1326
|
if (raw === void 0) {
|
|
936
1327
|
return;
|
|
937
1328
|
}
|
|
938
|
-
|
|
1329
|
+
const basePath = stripNamespace(path, namespaceValue);
|
|
1330
|
+
const targetPath = baseOutputs.has(basePath) ? basePath : path;
|
|
1331
|
+
batched.push({ id: targetPath, namespace: namespaceValue, value: raw });
|
|
939
1332
|
});
|
|
1333
|
+
if (batched.length > 0) {
|
|
1334
|
+
setWorldValues(batched);
|
|
1335
|
+
}
|
|
940
1336
|
}, [frame, status.namespace, store]);
|
|
941
|
-
const stagePoseNeutral =
|
|
1337
|
+
const stagePoseNeutral = useCallback(
|
|
942
1338
|
(force = false) => {
|
|
943
1339
|
const neutral = assetBundle.pose?.config?.neutralInputs ?? {};
|
|
944
1340
|
const rigMap = rigInputMapRef.current;
|
|
@@ -970,41 +1366,20 @@ function VizijRuntimeProviderInner({
|
|
|
970
1366
|
},
|
|
971
1367
|
[assetBundle.pose?.config?.neutralInputs, setInput]
|
|
972
1368
|
);
|
|
973
|
-
const setRendererValue =
|
|
1369
|
+
const setRendererValue = useCallback(
|
|
974
1370
|
(id, ns, value) => {
|
|
975
1371
|
store.getState().setValue(id, ns, value);
|
|
976
1372
|
},
|
|
977
1373
|
[store]
|
|
978
1374
|
);
|
|
979
|
-
const cancelAnimation =
|
|
1375
|
+
const cancelAnimation = useCallback((path) => {
|
|
980
1376
|
if (animationTweensRef.current.has(path)) {
|
|
981
1377
|
const entry = animationTweensRef.current.get(path);
|
|
982
1378
|
animationTweensRef.current.delete(path);
|
|
983
1379
|
entry?.resolve();
|
|
984
1380
|
}
|
|
985
1381
|
}, []);
|
|
986
|
-
const
|
|
987
|
-
if (rafHandleRef.current !== null) {
|
|
988
|
-
return;
|
|
989
|
-
}
|
|
990
|
-
const tick = (timestamp) => {
|
|
991
|
-
if (lastFrameTimeRef.current == null) {
|
|
992
|
-
lastFrameTimeRef.current = timestamp;
|
|
993
|
-
}
|
|
994
|
-
const dt = Math.max(0, (timestamp - lastFrameTimeRef.current) / 1e3);
|
|
995
|
-
lastFrameTimeRef.current = timestamp;
|
|
996
|
-
advanceAnimationTweens(dt);
|
|
997
|
-
advanceClipPlayback(dt);
|
|
998
|
-
if (animationTweensRef.current.size > 0 || clipPlaybackRef.current.size > 0) {
|
|
999
|
-
rafHandleRef.current = requestAnimationFrame(tick);
|
|
1000
|
-
} else {
|
|
1001
|
-
rafHandleRef.current = null;
|
|
1002
|
-
lastFrameTimeRef.current = null;
|
|
1003
|
-
}
|
|
1004
|
-
};
|
|
1005
|
-
rafHandleRef.current = requestAnimationFrame(tick);
|
|
1006
|
-
}, []);
|
|
1007
|
-
const advanceAnimationTweens = (0, import_react2.useCallback)(
|
|
1382
|
+
const advanceAnimationTweens = useCallback(
|
|
1008
1383
|
(dt) => {
|
|
1009
1384
|
if (animationTweensRef.current.size === 0) {
|
|
1010
1385
|
return;
|
|
@@ -1026,7 +1401,7 @@ function VizijRuntimeProviderInner({
|
|
|
1026
1401
|
},
|
|
1027
1402
|
[setInput]
|
|
1028
1403
|
);
|
|
1029
|
-
const sampleTrack =
|
|
1404
|
+
const sampleTrack = useCallback(
|
|
1030
1405
|
(track, time) => {
|
|
1031
1406
|
const keyframes = Array.isArray(track.keyframes) ? track.keyframes : [];
|
|
1032
1407
|
if (!keyframes.length) {
|
|
@@ -1057,7 +1432,7 @@ function VizijRuntimeProviderInner({
|
|
|
1057
1432
|
},
|
|
1058
1433
|
[]
|
|
1059
1434
|
);
|
|
1060
|
-
const advanceClipPlayback =
|
|
1435
|
+
const advanceClipPlayback = useCallback(
|
|
1061
1436
|
(dt) => {
|
|
1062
1437
|
if (clipPlaybackRef.current.size === 0) {
|
|
1063
1438
|
return;
|
|
@@ -1106,21 +1481,22 @@ function VizijRuntimeProviderInner({
|
|
|
1106
1481
|
},
|
|
1107
1482
|
[assetBundle.animations, sampleTrack, setInput]
|
|
1108
1483
|
);
|
|
1109
|
-
const animateValue =
|
|
1484
|
+
const animateValue = useCallback(
|
|
1110
1485
|
(path, target, options) => {
|
|
1111
1486
|
const easing = resolveEasing(options?.easing);
|
|
1112
1487
|
const duration = Math.max(0, options?.duration ?? DEFAULT_DURATION);
|
|
1113
1488
|
cancelAnimation(path);
|
|
1114
|
-
const
|
|
1115
|
-
const
|
|
1116
|
-
const
|
|
1489
|
+
const namespacedPath = namespaceTypedPath(path, namespaceRef.current);
|
|
1490
|
+
const current = getPathSnapshot(namespacedPath);
|
|
1491
|
+
const fromValue = valueAsNumber2(current);
|
|
1492
|
+
const toValue = valueAsNumber2(target);
|
|
1117
1493
|
if (fromValue == null || toValue == null || duration === 0) {
|
|
1118
1494
|
setInput(path, target);
|
|
1119
1495
|
return Promise.resolve();
|
|
1120
1496
|
}
|
|
1121
1497
|
return new Promise((resolve) => {
|
|
1122
1498
|
animationTweensRef.current.set(path, {
|
|
1123
|
-
path,
|
|
1499
|
+
path: namespacedPath,
|
|
1124
1500
|
from: fromValue,
|
|
1125
1501
|
to: toValue,
|
|
1126
1502
|
duration,
|
|
@@ -1128,12 +1504,12 @@ function VizijRuntimeProviderInner({
|
|
|
1128
1504
|
easing,
|
|
1129
1505
|
resolve
|
|
1130
1506
|
});
|
|
1131
|
-
|
|
1507
|
+
markActivity();
|
|
1132
1508
|
});
|
|
1133
1509
|
},
|
|
1134
|
-
[cancelAnimation, getPathSnapshot,
|
|
1510
|
+
[cancelAnimation, getPathSnapshot, markActivity, setInput]
|
|
1135
1511
|
);
|
|
1136
|
-
const playAnimation =
|
|
1512
|
+
const playAnimation = useCallback(
|
|
1137
1513
|
(id, options) => {
|
|
1138
1514
|
const clip = assetBundle.animations?.find((anim) => anim.id === id);
|
|
1139
1515
|
if (!clip) {
|
|
@@ -1156,12 +1532,12 @@ function VizijRuntimeProviderInner({
|
|
|
1156
1532
|
weight,
|
|
1157
1533
|
resolve
|
|
1158
1534
|
});
|
|
1159
|
-
|
|
1535
|
+
markActivity();
|
|
1160
1536
|
});
|
|
1161
1537
|
},
|
|
1162
|
-
[assetBundle.animations,
|
|
1538
|
+
[assetBundle.animations, markActivity]
|
|
1163
1539
|
);
|
|
1164
|
-
const stopAnimation =
|
|
1540
|
+
const stopAnimation = useCallback(
|
|
1165
1541
|
(id) => {
|
|
1166
1542
|
const clip = assetBundle.animations?.find((anim) => anim.id === id);
|
|
1167
1543
|
const state = clipPlaybackRef.current.get(id);
|
|
@@ -1180,7 +1556,7 @@ function VizijRuntimeProviderInner({
|
|
|
1180
1556
|
},
|
|
1181
1557
|
[assetBundle.animations, setInput]
|
|
1182
1558
|
);
|
|
1183
|
-
const registerInputDriver =
|
|
1559
|
+
const registerInputDriver = useCallback(
|
|
1184
1560
|
(id, factory) => {
|
|
1185
1561
|
const driver = factory({
|
|
1186
1562
|
setInput,
|
|
@@ -1230,32 +1606,111 @@ function VizijRuntimeProviderInner({
|
|
|
1230
1606
|
},
|
|
1231
1607
|
[faceId, namespace, pushError, setInput, setRendererValue]
|
|
1232
1608
|
);
|
|
1233
|
-
const advanceAnimations =
|
|
1609
|
+
const advanceAnimations = useCallback(
|
|
1234
1610
|
(dt) => {
|
|
1235
1611
|
advanceAnimationTweens(dt);
|
|
1236
1612
|
advanceClipPlayback(dt);
|
|
1237
1613
|
},
|
|
1238
1614
|
[advanceAnimationTweens, advanceClipPlayback]
|
|
1239
1615
|
);
|
|
1240
|
-
const
|
|
1241
|
-
(
|
|
1616
|
+
const flushStagedInputs = useCallback(() => {
|
|
1617
|
+
if (stagedInputsRef.current.size === 0) {
|
|
1618
|
+
return;
|
|
1619
|
+
}
|
|
1620
|
+
stagedInputsRef.current.forEach(({ value, shape }, path) => {
|
|
1621
|
+
orchestratorSetInput(path, value, shape);
|
|
1622
|
+
});
|
|
1623
|
+
stagedInputsRef.current.clear();
|
|
1624
|
+
}, [orchestratorSetInput]);
|
|
1625
|
+
const step = useCallback(
|
|
1626
|
+
(dt, opts) => {
|
|
1627
|
+
if (dt > 0 && Number.isFinite(dt)) {
|
|
1628
|
+
const prev = avgStepDtRef.current ?? dt;
|
|
1629
|
+
const alpha = 0.1;
|
|
1630
|
+
avgStepDtRef.current = prev * (1 - alpha) + dt * alpha;
|
|
1631
|
+
}
|
|
1242
1632
|
advanceAnimations(dt);
|
|
1243
|
-
|
|
1633
|
+
flushStagedInputs();
|
|
1634
|
+
if (driveOrchestratorRef.current || opts?.forceRuntime) {
|
|
1635
|
+
stepRuntime(dt);
|
|
1636
|
+
}
|
|
1244
1637
|
},
|
|
1245
|
-
[advanceAnimations, stepRuntime]
|
|
1638
|
+
[advanceAnimations, flushStagedInputs, stepRuntime]
|
|
1246
1639
|
);
|
|
1247
|
-
|
|
1640
|
+
useEffect(() => {
|
|
1641
|
+
if (loopMode !== "active") {
|
|
1642
|
+
return;
|
|
1643
|
+
}
|
|
1644
|
+
let rafId = null;
|
|
1645
|
+
let lastTime = null;
|
|
1646
|
+
const tick = (timestamp) => {
|
|
1647
|
+
if (loopModeRef.current !== "active") {
|
|
1648
|
+
return;
|
|
1649
|
+
}
|
|
1650
|
+
if (lastTime == null) {
|
|
1651
|
+
lastTime = timestamp;
|
|
1652
|
+
}
|
|
1653
|
+
const dt = Math.max(0, (timestamp - lastTime) / 1e3);
|
|
1654
|
+
lastTime = timestamp;
|
|
1655
|
+
step(dt || 0);
|
|
1656
|
+
requestLoopMode(computeDesiredLoopMode());
|
|
1657
|
+
rafId = requestAnimationFrame(tick);
|
|
1658
|
+
};
|
|
1659
|
+
rafId = requestAnimationFrame(tick);
|
|
1248
1660
|
return () => {
|
|
1249
|
-
if (
|
|
1250
|
-
cancelAnimationFrame(
|
|
1251
|
-
|
|
1661
|
+
if (rafId !== null) {
|
|
1662
|
+
cancelAnimationFrame(rafId);
|
|
1663
|
+
}
|
|
1664
|
+
};
|
|
1665
|
+
}, [loopMode, computeDesiredLoopMode, requestLoopMode, step]);
|
|
1666
|
+
useEffect(() => {
|
|
1667
|
+
if (loopMode !== "idle-visible" && loopMode !== "idle-hidden") {
|
|
1668
|
+
return;
|
|
1669
|
+
}
|
|
1670
|
+
if (typeof window === "undefined") {
|
|
1671
|
+
return;
|
|
1672
|
+
}
|
|
1673
|
+
const fps = loopMode === "idle-visible" ? VISIBLE_IDLE_FPS : HIDDEN_IDLE_FPS;
|
|
1674
|
+
if (fps <= 0) {
|
|
1675
|
+
return;
|
|
1676
|
+
}
|
|
1677
|
+
let lastTime = now();
|
|
1678
|
+
const interval = 1e3 / fps;
|
|
1679
|
+
const tick = () => {
|
|
1680
|
+
if (loopModeRef.current !== "idle-visible" && loopModeRef.current !== "idle-hidden") {
|
|
1681
|
+
return;
|
|
1252
1682
|
}
|
|
1253
|
-
|
|
1683
|
+
const current = now();
|
|
1684
|
+
const dt = Math.max(0, (current - lastTime) / 1e3);
|
|
1685
|
+
lastTime = current;
|
|
1686
|
+
step(dt || 0);
|
|
1687
|
+
requestLoopMode(computeDesiredLoopMode());
|
|
1688
|
+
};
|
|
1689
|
+
const intervalId = window.setInterval(tick, interval);
|
|
1690
|
+
return () => {
|
|
1691
|
+
window.clearInterval(intervalId);
|
|
1692
|
+
};
|
|
1693
|
+
}, [loopMode, computeDesiredLoopMode, requestLoopMode, step]);
|
|
1694
|
+
useEffect(() => {
|
|
1695
|
+
return () => {
|
|
1254
1696
|
animationTweensRef.current.clear();
|
|
1255
1697
|
clipPlaybackRef.current.clear();
|
|
1256
1698
|
};
|
|
1257
1699
|
}, []);
|
|
1258
|
-
|
|
1700
|
+
useEffect(() => {
|
|
1701
|
+
if (typeof window === "undefined") {
|
|
1702
|
+
return;
|
|
1703
|
+
}
|
|
1704
|
+
const id = window.setInterval(() => {
|
|
1705
|
+
const avg = avgStepDtRef.current;
|
|
1706
|
+
const stepHz = avg && Number.isFinite(avg) && avg > 0 ? 1 / avg : void 0;
|
|
1707
|
+
reportStatus(
|
|
1708
|
+
(prev) => prev.stepHz === stepHz ? prev : { ...prev, stepHz }
|
|
1709
|
+
);
|
|
1710
|
+
}, 500);
|
|
1711
|
+
return () => window.clearInterval(id);
|
|
1712
|
+
}, [reportStatus]);
|
|
1713
|
+
const contextValue = useMemo(
|
|
1259
1714
|
() => ({
|
|
1260
1715
|
...status,
|
|
1261
1716
|
assetBundle,
|
|
@@ -1268,7 +1723,8 @@ function VizijRuntimeProviderInner({
|
|
|
1268
1723
|
playAnimation,
|
|
1269
1724
|
stopAnimation,
|
|
1270
1725
|
step,
|
|
1271
|
-
advanceAnimations
|
|
1726
|
+
advanceAnimations,
|
|
1727
|
+
inputConstraints
|
|
1272
1728
|
}),
|
|
1273
1729
|
[
|
|
1274
1730
|
status,
|
|
@@ -1282,20 +1738,21 @@ function VizijRuntimeProviderInner({
|
|
|
1282
1738
|
playAnimation,
|
|
1283
1739
|
stopAnimation,
|
|
1284
1740
|
step,
|
|
1285
|
-
advanceAnimations
|
|
1741
|
+
advanceAnimations,
|
|
1742
|
+
inputConstraints
|
|
1286
1743
|
]
|
|
1287
1744
|
);
|
|
1288
|
-
return /* @__PURE__ */
|
|
1745
|
+
return /* @__PURE__ */ jsx(VizijRuntimeContext.Provider, { value: contextValue, children });
|
|
1289
1746
|
}
|
|
1290
1747
|
|
|
1291
1748
|
// src/VizijRuntimeFace.tsx
|
|
1292
|
-
|
|
1293
|
-
|
|
1749
|
+
import { memo } from "react";
|
|
1750
|
+
import { Vizij } from "@vizij/render";
|
|
1294
1751
|
|
|
1295
1752
|
// src/hooks/useVizijRuntime.ts
|
|
1296
|
-
|
|
1753
|
+
import { useContext as useContext2 } from "react";
|
|
1297
1754
|
function useVizijRuntime() {
|
|
1298
|
-
const ctx = (
|
|
1755
|
+
const ctx = useContext2(VizijRuntimeContext);
|
|
1299
1756
|
if (!ctx) {
|
|
1300
1757
|
throw new Error(
|
|
1301
1758
|
"useVizijRuntime must be used within a VizijRuntimeProvider."
|
|
@@ -1305,7 +1762,7 @@ function useVizijRuntime() {
|
|
|
1305
1762
|
}
|
|
1306
1763
|
|
|
1307
1764
|
// src/VizijRuntimeFace.tsx
|
|
1308
|
-
|
|
1765
|
+
import { jsx as jsx2 } from "react/jsx-runtime";
|
|
1309
1766
|
function VizijRuntimeFaceInner({
|
|
1310
1767
|
namespaceOverride,
|
|
1311
1768
|
...props
|
|
@@ -1314,8 +1771,8 @@ function VizijRuntimeFaceInner({
|
|
|
1314
1771
|
if (!rootId) {
|
|
1315
1772
|
return null;
|
|
1316
1773
|
}
|
|
1317
|
-
return /* @__PURE__ */ (
|
|
1318
|
-
|
|
1774
|
+
return /* @__PURE__ */ jsx2(
|
|
1775
|
+
Vizij,
|
|
1319
1776
|
{
|
|
1320
1777
|
...props,
|
|
1321
1778
|
rootId,
|
|
@@ -1323,17 +1780,19 @@ function VizijRuntimeFaceInner({
|
|
|
1323
1780
|
}
|
|
1324
1781
|
);
|
|
1325
1782
|
}
|
|
1326
|
-
var VizijRuntimeFace =
|
|
1783
|
+
var VizijRuntimeFace = memo(VizijRuntimeFaceInner);
|
|
1327
1784
|
|
|
1328
1785
|
// src/hooks/useVizijOutputs.ts
|
|
1329
|
-
|
|
1330
|
-
|
|
1786
|
+
import {
|
|
1787
|
+
useVizijStore
|
|
1788
|
+
} from "@vizij/render";
|
|
1789
|
+
import { getLookup } from "@vizij/utils";
|
|
1331
1790
|
function useVizijOutputs(paths) {
|
|
1332
1791
|
const { namespace } = useVizijRuntime();
|
|
1333
|
-
return
|
|
1792
|
+
return useVizijStore((state) => {
|
|
1334
1793
|
const result = {};
|
|
1335
1794
|
paths.forEach((path) => {
|
|
1336
|
-
const lookup =
|
|
1795
|
+
const lookup = getLookup(namespace, path);
|
|
1337
1796
|
result[path] = state.values.get(lookup);
|
|
1338
1797
|
});
|
|
1339
1798
|
return result;
|
|
@@ -1341,15 +1800,17 @@ function useVizijOutputs(paths) {
|
|
|
1341
1800
|
}
|
|
1342
1801
|
|
|
1343
1802
|
// src/hooks/useRigInput.ts
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1803
|
+
import { useCallback as useCallback2 } from "react";
|
|
1804
|
+
import {
|
|
1805
|
+
useVizijStore as useVizijStore2
|
|
1806
|
+
} from "@vizij/render";
|
|
1807
|
+
import { getLookup as getLookup2 } from "@vizij/utils";
|
|
1347
1808
|
function useRigInput(path) {
|
|
1348
1809
|
const { namespace, setInput } = useVizijRuntime();
|
|
1349
|
-
const value = (
|
|
1350
|
-
return state.values.get((
|
|
1810
|
+
const value = useVizijStore2((state) => {
|
|
1811
|
+
return state.values.get(getLookup2(namespace, path));
|
|
1351
1812
|
});
|
|
1352
|
-
const setter = (
|
|
1813
|
+
const setter = useCallback2(
|
|
1353
1814
|
(next, shape) => {
|
|
1354
1815
|
setInput(path, next, shape);
|
|
1355
1816
|
},
|
|
@@ -1357,11 +1818,10 @@ function useRigInput(path) {
|
|
|
1357
1818
|
);
|
|
1358
1819
|
return [value, setter];
|
|
1359
1820
|
}
|
|
1360
|
-
|
|
1361
|
-
0 && (module.exports = {
|
|
1821
|
+
export {
|
|
1362
1822
|
VizijRuntimeFace,
|
|
1363
1823
|
VizijRuntimeProvider,
|
|
1364
1824
|
useRigInput,
|
|
1365
1825
|
useVizijOutputs,
|
|
1366
1826
|
useVizijRuntime
|
|
1367
|
-
}
|
|
1827
|
+
};
|