@vizij/animation-react 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs ADDED
@@ -0,0 +1,919 @@
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
+ AnimationProvider: () => AnimationProvider,
24
+ listAnimationFixtures: () => import_animation_wasm2.listAnimationFixtures,
25
+ loadAnimationFixture: () => import_animation_wasm2.loadAnimationFixture,
26
+ loadAnimationJson: () => import_animation_wasm2.loadAnimationJson,
27
+ resolveAnimationPath: () => import_animation_wasm2.resolveAnimationPath,
28
+ samples: () => samples,
29
+ useAnimDerivative: () => useAnimDerivative,
30
+ useAnimTarget: () => useAnimTarget,
31
+ useAnimation: () => useAnimation,
32
+ valueAsNumber: () => valueAsNumber,
33
+ valueAsNumericArray: () => valueAsNumericArray,
34
+ valueAsTransform: () => valueAsTransform
35
+ });
36
+ module.exports = __toCommonJS(index_exports);
37
+
38
+ // src/AnimationProvider.tsx
39
+ var import_react2 = require("react");
40
+ var import_animation_wasm = require("@vizij/animation-wasm");
41
+
42
+ // src/context.ts
43
+ var import_react = require("react");
44
+ var AnimationContext = (0, import_react.createContext)(
45
+ null
46
+ );
47
+
48
+ // src/store.ts
49
+ var noop = () => {
50
+ };
51
+ var makeSubKey = (playerId, key) => `${playerId}|${key}`;
52
+ function addSubscriber(map, key, cb) {
53
+ let set = map.get(key);
54
+ if (!set) {
55
+ set = /* @__PURE__ */ new Set();
56
+ map.set(key, set);
57
+ }
58
+ set.add(cb);
59
+ return () => {
60
+ const current = map.get(key);
61
+ if (!current) return;
62
+ current.delete(cb);
63
+ if (current.size === 0) {
64
+ map.delete(key);
65
+ }
66
+ };
67
+ }
68
+ function notify(map, key) {
69
+ const subs = map.get(key);
70
+ if (!subs || subs.size === 0) return;
71
+ [...subs].forEach((cb) => {
72
+ try {
73
+ cb();
74
+ } catch (err) {
75
+ console.error("Animation store subscriber error", err);
76
+ }
77
+ });
78
+ }
79
+ function createAnimationStore() {
80
+ let values = {};
81
+ let derivatives = {};
82
+ let valuesByPlayer = {};
83
+ let derivativesByPlayer = {};
84
+ const keySubscribers = /* @__PURE__ */ new Map();
85
+ const derivativeKeySubscribers = /* @__PURE__ */ new Map();
86
+ const playerKeySubscribers = /* @__PURE__ */ new Map();
87
+ const playerDerivativeSubscribers = /* @__PURE__ */ new Map();
88
+ return {
89
+ reset() {
90
+ values = {};
91
+ derivatives = {};
92
+ valuesByPlayer = {};
93
+ derivativesByPlayer = {};
94
+ },
95
+ applyOutputs(out) {
96
+ if (!out || !Array.isArray(out.changes) || out.changes.length === 0) {
97
+ return;
98
+ }
99
+ const keyChanges = /* @__PURE__ */ new Set();
100
+ const derivativeKeyChanges = /* @__PURE__ */ new Set();
101
+ const playerKeyChanges = [];
102
+ const playerDerivativeChanges = [];
103
+ for (const change of out.changes) {
104
+ const key = change.key;
105
+ const value = change.value ?? void 0;
106
+ const playerId = change.player ?? void 0;
107
+ if (value == null) {
108
+ delete values[key];
109
+ } else {
110
+ values[key] = value;
111
+ }
112
+ if (typeof playerId !== "undefined") {
113
+ if (!valuesByPlayer[playerId]) valuesByPlayer[playerId] = {};
114
+ if (value == null) {
115
+ delete valuesByPlayer[playerId][key];
116
+ } else {
117
+ valuesByPlayer[playerId][key] = value;
118
+ }
119
+ }
120
+ if (typeof change.derivative !== "undefined") {
121
+ const derivative = change.derivative ?? void 0;
122
+ if (derivative == null) {
123
+ delete derivatives[key];
124
+ } else {
125
+ derivatives[key] = derivative;
126
+ }
127
+ if (typeof playerId !== "undefined") {
128
+ if (!derivativesByPlayer[playerId]) {
129
+ derivativesByPlayer[playerId] = {};
130
+ }
131
+ if (derivative == null) {
132
+ delete derivativesByPlayer[playerId][key];
133
+ } else {
134
+ derivativesByPlayer[playerId][key] = derivative;
135
+ }
136
+ }
137
+ derivativeKeyChanges.add(key);
138
+ playerDerivativeChanges.push({ playerId, key });
139
+ }
140
+ keyChanges.add(key);
141
+ playerKeyChanges.push({ playerId, key });
142
+ }
143
+ keyChanges.forEach((key) => notify(keySubscribers, key));
144
+ derivativeKeyChanges.forEach(
145
+ (key) => notify(derivativeKeySubscribers, key)
146
+ );
147
+ playerKeyChanges.forEach(
148
+ ({ playerId, key }) => notify(playerKeySubscribers, makeSubKey(playerId, key))
149
+ );
150
+ playerDerivativeChanges.forEach(
151
+ ({ playerId, key }) => notify(playerDerivativeSubscribers, makeSubKey(playerId, key))
152
+ );
153
+ },
154
+ subscribeToKey(key, cb) {
155
+ if (!key) return noop;
156
+ return addSubscriber(keySubscribers, key, cb);
157
+ },
158
+ getKeySnapshot(key) {
159
+ return values[key];
160
+ },
161
+ subscribeToDerivativeKey(key, cb) {
162
+ if (!key) return noop;
163
+ return addSubscriber(derivativeKeySubscribers, key, cb);
164
+ },
165
+ getKeyDerivativeSnapshot(key) {
166
+ return derivatives[key];
167
+ },
168
+ subscribeToPlayerKey(playerId, key, cb) {
169
+ if (typeof playerId === "undefined" || !key) return noop;
170
+ return addSubscriber(playerKeySubscribers, makeSubKey(playerId, key), cb);
171
+ },
172
+ getPlayerKeySnapshot(playerId, key) {
173
+ return valuesByPlayer[playerId]?.[key];
174
+ },
175
+ subscribeToPlayerDerivative(playerId, key, cb) {
176
+ if (typeof playerId === "undefined" || !key) return noop;
177
+ return addSubscriber(
178
+ playerDerivativeSubscribers,
179
+ makeSubKey(playerId, key),
180
+ cb
181
+ );
182
+ },
183
+ getPlayerDerivativeSnapshot(playerId, key) {
184
+ return derivativesByPlayer[playerId]?.[key];
185
+ },
186
+ getValuesByPlayer() {
187
+ const snapshot = {};
188
+ for (const [pid, mapping] of Object.entries(valuesByPlayer)) {
189
+ snapshot[Number(pid)] = { ...mapping };
190
+ }
191
+ return snapshot;
192
+ },
193
+ getDerivativesByPlayer() {
194
+ const snapshot = {};
195
+ for (const [pid, mapping] of Object.entries(derivativesByPlayer)) {
196
+ snapshot[Number(pid)] = { ...mapping };
197
+ }
198
+ return snapshot;
199
+ }
200
+ };
201
+ }
202
+
203
+ // src/AnimationProvider.tsx
204
+ var import_jsx_runtime = require("react/jsx-runtime");
205
+ var DEFAULT_PLAYER_NAME = "default";
206
+ var DEFAULT_INSTANCE_CFG = {
207
+ weight: 1,
208
+ time_scale: 1,
209
+ start_offset: 0,
210
+ enabled: true
211
+ };
212
+ function normalizeAnimations(animations) {
213
+ return Array.isArray(animations) ? animations : [animations];
214
+ }
215
+ function AnimationProvider({
216
+ children,
217
+ animations,
218
+ instances,
219
+ prebind,
220
+ autostart = true,
221
+ updateHz,
222
+ engineConfig,
223
+ onOutputs
224
+ }) {
225
+ const engineRef = (0, import_react2.useRef)(null);
226
+ const storeRef = (0, import_react2.useRef)(createAnimationStore());
227
+ const rafRef = (0, import_react2.useRef)(null);
228
+ const lastTimeRef = (0, import_react2.useRef)(0);
229
+ const lastNotifyRef = (0, import_react2.useRef)(0);
230
+ const onOutputsRef = (0, import_react2.useRef)(onOutputs);
231
+ const animsCacheRef = (0, import_react2.useRef)(null);
232
+ const animIdsRef = (0, import_react2.useRef)([]);
233
+ const instancesRef = (0, import_react2.useRef)({});
234
+ (0, import_react2.useEffect)(() => {
235
+ onOutputsRef.current = onOutputs;
236
+ }, [onOutputs]);
237
+ const animKey = (0, import_react2.useMemo)(() => {
238
+ try {
239
+ return JSON.stringify(
240
+ Array.isArray(animations) ? animations : [animations]
241
+ );
242
+ } catch {
243
+ return String(Math.random());
244
+ }
245
+ }, [animations]);
246
+ const instKey = (0, import_react2.useMemo)(() => {
247
+ try {
248
+ return JSON.stringify(instances ?? []);
249
+ } catch {
250
+ return String(Math.random());
251
+ }
252
+ }, [instances]);
253
+ const [ready, setReady] = (0, import_react2.useState)(false);
254
+ const [players, setPlayers] = (0, import_react2.useState)({});
255
+ const applyOutputs = (0, import_react2.useCallback)(
256
+ (out) => {
257
+ storeRef.current.applyOutputs(out);
258
+ if (!out) return;
259
+ try {
260
+ onOutputsRef.current?.(out);
261
+ } catch (err) {
262
+ console.error("Animation onOutputs callback error", err);
263
+ }
264
+ },
265
+ []
266
+ );
267
+ const refreshPlayersAndInstances = (0, import_react2.useCallback)((eng) => {
268
+ try {
269
+ const playersInfo = eng.listPlayers();
270
+ const nextPlayers = {};
271
+ const nextInstances = {};
272
+ for (const info of playersInfo) {
273
+ const playerId = info.id;
274
+ nextPlayers[info.name] = playerId;
275
+ try {
276
+ const instInfos = eng.listInstances(
277
+ playerId
278
+ );
279
+ nextInstances[info.name] = instInfos.map(
280
+ (inst) => inst.id
281
+ );
282
+ } catch {
283
+ nextInstances[info.name] = [];
284
+ }
285
+ }
286
+ setPlayers(nextPlayers);
287
+ instancesRef.current = nextInstances;
288
+ } catch (err) {
289
+ console.warn("Animation refreshPlayersAndInstances failed", err);
290
+ }
291
+ }, []);
292
+ const resolveAnimId = (0, import_react2.useCallback)(
293
+ (animIndexOrId) => {
294
+ if (Number.isInteger(animIndexOrId) && animIndexOrId >= 0) {
295
+ const byIndex = animIdsRef.current[animIndexOrId];
296
+ if (typeof byIndex !== "undefined") {
297
+ return byIndex;
298
+ }
299
+ }
300
+ if (typeof animIndexOrId === "number") {
301
+ return animIndexOrId;
302
+ }
303
+ return void 0;
304
+ },
305
+ []
306
+ );
307
+ const loadAnimationsAndInstances = (0, import_react2.useCallback)(
308
+ (eng, animList, instSpecs) => {
309
+ const serialized = JSON.stringify(animList);
310
+ if (!animsCacheRef.current || animsCacheRef.current.json !== serialized) {
311
+ const ids = [];
312
+ for (const anim of animList) {
313
+ const id = eng.loadAnimation(anim, { format: "stored" });
314
+ ids.push(id);
315
+ }
316
+ animIdsRef.current = ids;
317
+ animsCacheRef.current = { json: serialized, count: animList.length };
318
+ }
319
+ instancesRef.current = {};
320
+ if (instSpecs && instSpecs.length > 0) {
321
+ for (const spec of instSpecs) {
322
+ const playerId = eng.createPlayer(spec.playerName);
323
+ const animIndex = spec.animIndex ?? 0;
324
+ const animId = animIdsRef.current[animIndex] ?? animIdsRef.current[0] ?? 0;
325
+ const cfgFinal = {
326
+ ...DEFAULT_INSTANCE_CFG,
327
+ ...spec.cfg
328
+ };
329
+ const instId = eng.addInstance(
330
+ playerId,
331
+ animId,
332
+ cfgFinal
333
+ );
334
+ if (!instancesRef.current[spec.playerName]) {
335
+ instancesRef.current[spec.playerName] = [];
336
+ }
337
+ instancesRef.current[spec.playerName].push(instId);
338
+ }
339
+ } else {
340
+ const playerId = eng.createPlayer(DEFAULT_PLAYER_NAME);
341
+ const animId = animIdsRef.current[0] ?? 0;
342
+ const instId = eng.addInstance(
343
+ playerId,
344
+ animId,
345
+ { ...DEFAULT_INSTANCE_CFG }
346
+ );
347
+ instancesRef.current[DEFAULT_PLAYER_NAME] = [instId];
348
+ }
349
+ },
350
+ []
351
+ );
352
+ (0, import_react2.useEffect)(() => {
353
+ let cancelled = false;
354
+ (async () => {
355
+ try {
356
+ await (0, import_animation_wasm.init)();
357
+ } catch (err) {
358
+ console.error("Failed to init @vizij/animation-wasm", err);
359
+ return;
360
+ }
361
+ if (cancelled) return;
362
+ const store = storeRef.current;
363
+ store.reset();
364
+ animsCacheRef.current = null;
365
+ animIdsRef.current = [];
366
+ instancesRef.current = {};
367
+ lastTimeRef.current = 0;
368
+ lastNotifyRef.current = 0;
369
+ const engine = new import_animation_wasm.Engine(engineConfig);
370
+ engineRef.current = engine;
371
+ if (prebind) {
372
+ try {
373
+ engine.prebind(prebind);
374
+ } catch (err) {
375
+ console.error("Animation prebind failed", err);
376
+ }
377
+ }
378
+ const list = normalizeAnimations(animations);
379
+ loadAnimationsAndInstances(engine, list, instances);
380
+ if (autostart) {
381
+ applyOutputs(engine.updateValuesAndDerivatives(0));
382
+ }
383
+ refreshPlayersAndInstances(engine);
384
+ setReady(true);
385
+ if (!autostart) return;
386
+ const loop = (time) => {
387
+ if (cancelled) return;
388
+ const eng = engineRef.current;
389
+ if (!eng) return;
390
+ const last = lastTimeRef.current || time;
391
+ const dt = (time - last) / 1e3;
392
+ lastTimeRef.current = time;
393
+ const now = performance.now();
394
+ const interval = updateHz && updateHz > 0 ? 1e3 / updateHz : 0;
395
+ if (!interval || now - lastNotifyRef.current >= interval) {
396
+ const out = eng.updateValuesAndDerivatives(dt);
397
+ applyOutputs(out);
398
+ lastNotifyRef.current = now;
399
+ } else {
400
+ eng.updateValues(dt);
401
+ }
402
+ rafRef.current = requestAnimationFrame(loop);
403
+ };
404
+ rafRef.current = requestAnimationFrame(loop);
405
+ })();
406
+ return () => {
407
+ cancelled = true;
408
+ if (rafRef.current) {
409
+ cancelAnimationFrame(rafRef.current);
410
+ }
411
+ rafRef.current = null;
412
+ engineRef.current = null;
413
+ };
414
+ }, [autostart, updateHz, prebind, engineConfig, animKey, instKey]);
415
+ const resolvePlayerId = (0, import_react2.useCallback)(
416
+ (player) => {
417
+ if (typeof player === "number") return player;
418
+ return players[player];
419
+ },
420
+ [players]
421
+ );
422
+ const step = (0, import_react2.useCallback)(
423
+ (dt, inputs) => {
424
+ const eng = engineRef.current;
425
+ if (!eng) return;
426
+ applyOutputs(eng.updateValuesAndDerivatives(dt, inputs));
427
+ },
428
+ [applyOutputs]
429
+ );
430
+ const reload = (0, import_react2.useCallback)(
431
+ (animPayload, instSpecs) => {
432
+ const eng = engineRef.current;
433
+ if (!eng) return;
434
+ try {
435
+ const playersInfo = eng.listPlayers();
436
+ for (const playerInfo of playersInfo) {
437
+ const playerId = playerInfo.id;
438
+ try {
439
+ const instInfos = eng.listInstances(
440
+ playerId
441
+ );
442
+ for (const inst of instInfos) {
443
+ try {
444
+ eng.removeInstance(playerId, inst.id);
445
+ } catch (err) {
446
+ console.warn("Failed to remove instance during reload", err);
447
+ }
448
+ }
449
+ } catch (err) {
450
+ console.warn("Failed to enumerate instances during reload", err);
451
+ }
452
+ try {
453
+ eng.removePlayer(playerId);
454
+ } catch (err) {
455
+ console.warn("Failed to remove player during reload", err);
456
+ }
457
+ }
458
+ } catch (err) {
459
+ console.warn("Engine state cleanup failed before reload", err);
460
+ }
461
+ if (animIdsRef.current.length > 0) {
462
+ for (const animId of animIdsRef.current) {
463
+ try {
464
+ eng.unloadAnimation(animId);
465
+ } catch (err) {
466
+ console.warn("Failed to unload animation during reload", err);
467
+ }
468
+ }
469
+ }
470
+ storeRef.current.reset();
471
+ animsCacheRef.current = null;
472
+ animIdsRef.current = [];
473
+ instancesRef.current = {};
474
+ setPlayers({});
475
+ const list = normalizeAnimations(animPayload);
476
+ loadAnimationsAndInstances(eng, list, instSpecs);
477
+ applyOutputs(eng.updateValuesAndDerivatives(0));
478
+ refreshPlayersAndInstances(eng);
479
+ },
480
+ [applyOutputs, loadAnimationsAndInstances, refreshPlayersAndInstances]
481
+ );
482
+ const addPlayer = (0, import_react2.useCallback)(
483
+ (name) => {
484
+ const eng = engineRef.current;
485
+ if (!eng) return -1;
486
+ if (typeof players[name] !== "undefined") return players[name];
487
+ const playerId = eng.createPlayer(name);
488
+ setPlayers((prev) => ({ ...prev, [name]: playerId }));
489
+ if (!instancesRef.current[name]) instancesRef.current[name] = [];
490
+ return playerId;
491
+ },
492
+ [players]
493
+ );
494
+ const addAnimations = (0, import_react2.useCallback)(
495
+ (anims) => {
496
+ const eng = engineRef.current;
497
+ if (!eng) return [];
498
+ const list = normalizeAnimations(anims);
499
+ const newIds = [];
500
+ for (const anim of list) {
501
+ const id = eng.loadAnimation(anim, { format: "stored" });
502
+ animIdsRef.current.push(id);
503
+ newIds.push(id);
504
+ }
505
+ try {
506
+ const prev = animsCacheRef.current ? JSON.parse(animsCacheRef.current.json) : [];
507
+ const merged = [...prev, ...list];
508
+ animsCacheRef.current = {
509
+ json: JSON.stringify(merged),
510
+ count: merged.length
511
+ };
512
+ } catch {
513
+ }
514
+ applyOutputs(eng.updateValuesAndDerivatives(0));
515
+ refreshPlayersAndInstances(eng);
516
+ return newIds;
517
+ },
518
+ [applyOutputs, refreshPlayersAndInstances]
519
+ );
520
+ const addInstances = (0, import_react2.useCallback)(
521
+ (specs) => {
522
+ const eng = engineRef.current;
523
+ if (!eng || !specs || specs.length === 0) return [];
524
+ const results = [];
525
+ const nextPlayers = { ...players };
526
+ for (const spec of specs) {
527
+ let playerId = nextPlayers[spec.playerName];
528
+ if (typeof playerId === "undefined") {
529
+ playerId = eng.createPlayer(spec.playerName);
530
+ nextPlayers[spec.playerName] = playerId;
531
+ if (!instancesRef.current[spec.playerName]) {
532
+ instancesRef.current[spec.playerName] = [];
533
+ }
534
+ }
535
+ const idx = spec.animIndexOrId;
536
+ const animId = idx >= 0 && idx < animIdsRef.current.length ? animIdsRef.current[idx] : idx;
537
+ const cfgFinal = {
538
+ ...DEFAULT_INSTANCE_CFG,
539
+ ...spec.cfg
540
+ };
541
+ const instId = eng.addInstance(
542
+ playerId,
543
+ animId,
544
+ cfgFinal
545
+ );
546
+ instancesRef.current[spec.playerName].push(instId);
547
+ results.push({ playerName: spec.playerName, instId });
548
+ }
549
+ setPlayers(nextPlayers);
550
+ applyOutputs(eng.updateValuesAndDerivatives(0));
551
+ refreshPlayersAndInstances(eng);
552
+ return results;
553
+ },
554
+ [applyOutputs, players, refreshPlayersAndInstances]
555
+ );
556
+ const getInstances = (0, import_react2.useCallback)((playerName) => {
557
+ return instancesRef.current[playerName]?.slice() ?? [];
558
+ }, []);
559
+ const updateInstances = (0, import_react2.useCallback)(
560
+ (updates) => {
561
+ const eng = engineRef.current;
562
+ if (!eng || !updates || updates.length === 0) return;
563
+ applyOutputs(
564
+ eng.updateValuesAndDerivatives(0, { instance_updates: updates })
565
+ );
566
+ },
567
+ [applyOutputs]
568
+ );
569
+ const bakeAnimation = (0, import_react2.useCallback)(
570
+ (animIndexOrId, cfg) => {
571
+ const eng = engineRef.current;
572
+ if (!eng) return null;
573
+ const animId = resolveAnimId(animIndexOrId);
574
+ if (typeof animId === "undefined") return null;
575
+ try {
576
+ return eng.bakeAnimation(animId, cfg);
577
+ } catch (err) {
578
+ console.error("Animation bakeAnimation failed", err);
579
+ return null;
580
+ }
581
+ },
582
+ [resolveAnimId]
583
+ );
584
+ const bakeAnimationWithDerivatives = (0, import_react2.useCallback)(
585
+ (animIndexOrId, cfg) => {
586
+ const eng = engineRef.current;
587
+ if (!eng) return null;
588
+ const animId = resolveAnimId(animIndexOrId);
589
+ if (typeof animId === "undefined") return null;
590
+ try {
591
+ return eng.bakeAnimationWithDerivatives(animId, cfg);
592
+ } catch (err) {
593
+ console.error("Animation bakeAnimationWithDerivatives failed", err);
594
+ return null;
595
+ }
596
+ },
597
+ [resolveAnimId]
598
+ );
599
+ const subscribeToKey = (0, import_react2.useCallback)((key, cb) => {
600
+ return storeRef.current.subscribeToKey(key, cb);
601
+ }, []);
602
+ const getKeySnapshot = (0, import_react2.useCallback)((key) => {
603
+ return storeRef.current.getKeySnapshot(key);
604
+ }, []);
605
+ const subscribeToDerivativeKey = (0, import_react2.useCallback)(
606
+ (key, cb) => {
607
+ return storeRef.current.subscribeToDerivativeKey(key, cb);
608
+ },
609
+ []
610
+ );
611
+ const getKeyDerivativeSnapshot = (0, import_react2.useCallback)((key) => {
612
+ return storeRef.current.getKeyDerivativeSnapshot(key);
613
+ }, []);
614
+ const subscribeToPlayerKey = (0, import_react2.useCallback)(
615
+ (player, key, cb) => {
616
+ const playerId = resolvePlayerId(player);
617
+ if (typeof playerId === "undefined") return () => {
618
+ };
619
+ return storeRef.current.subscribeToPlayerKey(playerId, key, cb);
620
+ },
621
+ [resolvePlayerId]
622
+ );
623
+ const getPlayerKeySnapshot = (0, import_react2.useCallback)(
624
+ (player, key) => {
625
+ const playerId = resolvePlayerId(player);
626
+ if (typeof playerId === "undefined") return void 0;
627
+ return storeRef.current.getPlayerKeySnapshot(playerId, key);
628
+ },
629
+ [resolvePlayerId]
630
+ );
631
+ const subscribeToPlayerDerivative = (0, import_react2.useCallback)(
632
+ (player, key, cb) => {
633
+ const playerId = resolvePlayerId(player);
634
+ if (typeof playerId === "undefined") return () => {
635
+ };
636
+ return storeRef.current.subscribeToPlayerDerivative(playerId, key, cb);
637
+ },
638
+ [resolvePlayerId]
639
+ );
640
+ const getPlayerDerivativeSnapshot = (0, import_react2.useCallback)(
641
+ (player, key) => {
642
+ const playerId = resolvePlayerId(player);
643
+ if (typeof playerId === "undefined") return void 0;
644
+ return storeRef.current.getPlayerDerivativeSnapshot(playerId, key);
645
+ },
646
+ [resolvePlayerId]
647
+ );
648
+ const getLatestValuesByPlayer = (0, import_react2.useCallback)(() => {
649
+ const snapshot = storeRef.current.getValuesByPlayer();
650
+ const result = {};
651
+ const nameById = Object.fromEntries(
652
+ Object.entries(players).map(([name, id]) => [String(id), name])
653
+ );
654
+ for (const [idStr, valuesForPlayer] of Object.entries(snapshot)) {
655
+ const canonicalName = nameById[idStr] ?? idStr;
656
+ result[canonicalName] = { ...valuesForPlayer };
657
+ }
658
+ return result;
659
+ }, [players]);
660
+ const getLatestDerivativesByPlayer = (0, import_react2.useCallback)(() => {
661
+ const snapshot = storeRef.current.getDerivativesByPlayer();
662
+ const result = {};
663
+ const nameById = Object.fromEntries(
664
+ Object.entries(players).map(([name, id]) => [String(id), name])
665
+ );
666
+ for (const [idStr, valuesForPlayer] of Object.entries(snapshot)) {
667
+ const canonicalName = nameById[idStr] ?? idStr;
668
+ result[canonicalName] = { ...valuesForPlayer };
669
+ }
670
+ return result;
671
+ }, [players]);
672
+ const listAnimations = (0, import_react2.useCallback)(() => {
673
+ const eng = engineRef.current;
674
+ if (!eng) return [];
675
+ try {
676
+ return eng.listAnimations();
677
+ } catch {
678
+ return [];
679
+ }
680
+ }, []);
681
+ const listPlayers = (0, import_react2.useCallback)(() => {
682
+ const eng = engineRef.current;
683
+ if (!eng) return [];
684
+ try {
685
+ return eng.listPlayers();
686
+ } catch {
687
+ return [];
688
+ }
689
+ }, []);
690
+ const listInstances = (0, import_react2.useCallback)(
691
+ (player) => {
692
+ const eng = engineRef.current;
693
+ if (!eng) return [];
694
+ const playerId = resolvePlayerId(player);
695
+ if (typeof playerId === "undefined") return [];
696
+ try {
697
+ return eng.listInstances(playerId);
698
+ } catch {
699
+ return [];
700
+ }
701
+ },
702
+ [resolvePlayerId]
703
+ );
704
+ const listPlayerKeys = (0, import_react2.useCallback)(
705
+ (player) => {
706
+ const eng = engineRef.current;
707
+ if (!eng) return [];
708
+ const playerId = resolvePlayerId(player);
709
+ if (typeof playerId === "undefined") return [];
710
+ try {
711
+ return eng.listPlayerKeys(playerId);
712
+ } catch {
713
+ return [];
714
+ }
715
+ },
716
+ [resolvePlayerId]
717
+ );
718
+ const removePlayer = (0, import_react2.useCallback)(
719
+ (player) => {
720
+ const eng = engineRef.current;
721
+ if (!eng) return false;
722
+ const playerId = resolvePlayerId(player);
723
+ if (typeof playerId === "undefined") return false;
724
+ const ok = eng.removePlayer(playerId);
725
+ applyOutputs(eng.updateValuesAndDerivatives(0));
726
+ refreshPlayersAndInstances(eng);
727
+ return ok;
728
+ },
729
+ [applyOutputs, refreshPlayersAndInstances, resolvePlayerId]
730
+ );
731
+ const removeInstances = (0, import_react2.useCallback)(
732
+ (specs) => {
733
+ const eng = engineRef.current;
734
+ if (!eng || specs.length === 0) return [];
735
+ const removed = [];
736
+ for (const spec of specs) {
737
+ const playerId = resolvePlayerId(spec.playerName);
738
+ if (typeof playerId === "undefined") continue;
739
+ try {
740
+ const ok = eng.removeInstance(playerId, spec.instId);
741
+ if (ok) removed.push(spec);
742
+ } catch (err) {
743
+ console.warn("Failed to remove instance", err);
744
+ }
745
+ }
746
+ applyOutputs(eng.updateValuesAndDerivatives(0));
747
+ refreshPlayersAndInstances(eng);
748
+ return removed;
749
+ },
750
+ [applyOutputs, refreshPlayersAndInstances, resolvePlayerId]
751
+ );
752
+ const unloadAnimations = (0, import_react2.useCallback)(
753
+ (animIds) => {
754
+ const eng = engineRef.current;
755
+ if (!eng || animIds.length === 0) return [];
756
+ const removed = [];
757
+ for (const animId of animIds) {
758
+ const ok = eng.unloadAnimation(animId);
759
+ if (ok) removed.push(animId);
760
+ }
761
+ if (removed.length > 0) {
762
+ animIdsRef.current = animIdsRef.current.filter(
763
+ (id) => !removed.includes(id)
764
+ );
765
+ }
766
+ applyOutputs(eng.updateValuesAndDerivatives(0));
767
+ refreshPlayersAndInstances(eng);
768
+ return removed;
769
+ },
770
+ [applyOutputs, refreshPlayersAndInstances]
771
+ );
772
+ const contextValue = (0, import_react2.useMemo)(
773
+ () => ({
774
+ ready,
775
+ subscribeToKey,
776
+ getKeySnapshot,
777
+ subscribeToDerivativeKey,
778
+ getKeyDerivativeSnapshot,
779
+ subscribeToPlayerKey,
780
+ getPlayerKeySnapshot,
781
+ subscribeToPlayerDerivative,
782
+ getPlayerDerivativeSnapshot,
783
+ getLatestValuesByPlayer,
784
+ getLatestDerivativesByPlayer,
785
+ step,
786
+ reload,
787
+ addAnimations,
788
+ addPlayer,
789
+ addInstances,
790
+ getInstances,
791
+ updateInstances,
792
+ listAnimations,
793
+ listPlayers,
794
+ listInstances,
795
+ listPlayerKeys,
796
+ removePlayer,
797
+ removeInstances,
798
+ unloadAnimations,
799
+ bakeAnimation,
800
+ bakeAnimationWithDerivatives,
801
+ players
802
+ }),
803
+ [
804
+ ready,
805
+ subscribeToKey,
806
+ getKeySnapshot,
807
+ subscribeToDerivativeKey,
808
+ getKeyDerivativeSnapshot,
809
+ subscribeToPlayerKey,
810
+ getPlayerKeySnapshot,
811
+ subscribeToPlayerDerivative,
812
+ getPlayerDerivativeSnapshot,
813
+ getLatestValuesByPlayer,
814
+ getLatestDerivativesByPlayer,
815
+ step,
816
+ reload,
817
+ addAnimations,
818
+ addPlayer,
819
+ addInstances,
820
+ getInstances,
821
+ updateInstances,
822
+ listAnimations,
823
+ listPlayers,
824
+ listInstances,
825
+ listPlayerKeys,
826
+ removePlayer,
827
+ removeInstances,
828
+ unloadAnimations,
829
+ bakeAnimation,
830
+ bakeAnimationWithDerivatives,
831
+ players
832
+ ]
833
+ );
834
+ return /* @__PURE__ */ (0, import_jsx_runtime.jsx)(AnimationContext.Provider, { value: contextValue, children });
835
+ }
836
+
837
+ // src/hooks/useAnimation.ts
838
+ var import_react3 = require("react");
839
+ function useAnimation() {
840
+ const ctx = (0, import_react3.useContext)(AnimationContext);
841
+ if (!ctx) {
842
+ throw new Error("useAnimation must be used within AnimationProvider");
843
+ }
844
+ return ctx;
845
+ }
846
+
847
+ // src/hooks/useAnimTarget.ts
848
+ var import_react4 = require("react");
849
+ function useAnimTarget(key) {
850
+ const { subscribeToKey, getKeySnapshot } = useAnimation();
851
+ const subscribe = (0, import_react4.useCallback)(
852
+ (cb) => {
853
+ if (!key) return () => {
854
+ };
855
+ return subscribeToKey(key, cb);
856
+ },
857
+ [subscribeToKey, key]
858
+ );
859
+ const getSnapshot = (0, import_react4.useCallback)(
860
+ () => key ? getKeySnapshot(key) : void 0,
861
+ [getKeySnapshot, key]
862
+ );
863
+ return (0, import_react4.useSyncExternalStore)(subscribe, getSnapshot, () => void 0);
864
+ }
865
+
866
+ // src/hooks/useAnimDerivative.ts
867
+ var import_react5 = require("react");
868
+ function useAnimDerivative(key) {
869
+ const { subscribeToDerivativeKey, getKeyDerivativeSnapshot } = useAnimation();
870
+ const subscribe = (0, import_react5.useCallback)(
871
+ (cb) => {
872
+ if (!key) return () => {
873
+ };
874
+ return subscribeToDerivativeKey(key, cb);
875
+ },
876
+ [subscribeToDerivativeKey, key]
877
+ );
878
+ const getSnapshot = (0, import_react5.useCallback)(
879
+ () => key ? getKeyDerivativeSnapshot(key) : void 0,
880
+ [getKeyDerivativeSnapshot, key]
881
+ );
882
+ return (0, import_react5.useSyncExternalStore)(subscribe, getSnapshot, () => void 0);
883
+ }
884
+
885
+ // src/valueHelpers.ts
886
+ var import_value_json = require("@vizij/value-json");
887
+ function valueAsNumber(v) {
888
+ return (0, import_value_json.valueAsNumber)(v);
889
+ }
890
+ function valueAsNumericArray(v, fallback = 0) {
891
+ return (0, import_value_json.valueAsNumericArray)(v, fallback);
892
+ }
893
+ function valueAsTransform(v) {
894
+ return (0, import_value_json.valueAsTransform)(v);
895
+ }
896
+
897
+ // src/samples.ts
898
+ var import_animation_wasm2 = require("@vizij/animation-wasm");
899
+ var samples = {
900
+ list: import_animation_wasm2.listAnimationFixtures,
901
+ load: import_animation_wasm2.loadAnimationFixture,
902
+ loadJson: import_animation_wasm2.loadAnimationJson,
903
+ resolvePath: import_animation_wasm2.resolveAnimationPath
904
+ };
905
+ // Annotate the CommonJS export names for ESM import in node:
906
+ 0 && (module.exports = {
907
+ AnimationProvider,
908
+ listAnimationFixtures,
909
+ loadAnimationFixture,
910
+ loadAnimationJson,
911
+ resolveAnimationPath,
912
+ samples,
913
+ useAnimDerivative,
914
+ useAnimTarget,
915
+ useAnimation,
916
+ valueAsNumber,
917
+ valueAsNumericArray,
918
+ valueAsTransform
919
+ });