@vizij/runtime-react 0.0.4 → 0.0.7
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/LICENSE +201 -0
- package/README.md +21 -0
- package/dist/index.js +156 -18
- package/dist/index.mjs +156 -18
- package/package.json +18 -19
package/LICENSE
ADDED
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
Apache License
|
|
2
|
+
Version 2.0, January 2004
|
|
3
|
+
http://www.apache.org/licenses/
|
|
4
|
+
|
|
5
|
+
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
|
6
|
+
|
|
7
|
+
1. Definitions.
|
|
8
|
+
|
|
9
|
+
"License" shall mean the terms and conditions for use, reproduction,
|
|
10
|
+
and distribution as defined by Sections 1 through 9 of this document.
|
|
11
|
+
|
|
12
|
+
"Licensor" shall mean the copyright owner or entity authorized by
|
|
13
|
+
the copyright owner that is granting the License.
|
|
14
|
+
|
|
15
|
+
"Legal Entity" shall mean the union of the acting entity and all
|
|
16
|
+
other entities that control, are controlled by, or are under common
|
|
17
|
+
control with that entity. For the purposes of this definition,
|
|
18
|
+
"control" means (i) the power, direct or indirect, to cause the
|
|
19
|
+
direction or management of such entity, whether by contract or
|
|
20
|
+
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
|
21
|
+
outstanding shares, or (iii) beneficial ownership of such entity.
|
|
22
|
+
|
|
23
|
+
"You" (or "Your") shall mean an individual or Legal Entity
|
|
24
|
+
exercising permissions granted by this License.
|
|
25
|
+
|
|
26
|
+
"Source" form shall mean the preferred form for making modifications,
|
|
27
|
+
including but not limited to software source code, documentation
|
|
28
|
+
source, and configuration files.
|
|
29
|
+
|
|
30
|
+
"Object" form shall mean any form resulting from mechanical
|
|
31
|
+
transformation or translation of a Source form, including but
|
|
32
|
+
not limited to compiled object code, generated documentation,
|
|
33
|
+
and conversions to other media types.
|
|
34
|
+
|
|
35
|
+
"Work" shall mean the work of authorship, whether in Source or
|
|
36
|
+
Object form, made available under the License, as indicated by a
|
|
37
|
+
copyright notice that is included in or attached to the work
|
|
38
|
+
(an example is provided in the Appendix below).
|
|
39
|
+
|
|
40
|
+
"Derivative Works" shall mean any work, whether in Source or Object
|
|
41
|
+
form, that is based on (or derived from) the Work and for which the
|
|
42
|
+
editorial revisions, annotations, elaborations, or other modifications
|
|
43
|
+
represent, as a whole, an original work of authorship. For the purposes
|
|
44
|
+
of this License, Derivative Works shall not include works that remain
|
|
45
|
+
separable from, or merely link (or bind by name) to the interfaces of,
|
|
46
|
+
the Work and Derivative Works thereof.
|
|
47
|
+
|
|
48
|
+
"Contribution" shall mean any work of authorship, including
|
|
49
|
+
the original version of the Work and any modifications or additions
|
|
50
|
+
to that Work or Derivative Works thereof, that is intentionally
|
|
51
|
+
submitted to Licensor for inclusion in the Work by the copyright owner
|
|
52
|
+
or by an individual or Legal Entity authorized to submit on behalf of
|
|
53
|
+
the copyright owner. For the purposes of this definition, "submitted"
|
|
54
|
+
means any form of electronic, verbal, or written communication sent
|
|
55
|
+
to the Licensor or its representatives, including but not limited to
|
|
56
|
+
communication on electronic mailing lists, source code control systems,
|
|
57
|
+
and issue tracking systems that are managed by, or on behalf of, the
|
|
58
|
+
Licensor for the purpose of discussing and improving the Work, but
|
|
59
|
+
excluding communication that is conspicuously marked or otherwise
|
|
60
|
+
designated in writing by the copyright owner as "Not a Contribution."
|
|
61
|
+
|
|
62
|
+
"Contributor" shall mean Licensor and any individual or Legal Entity
|
|
63
|
+
on behalf of whom a Contribution has been received by Licensor and
|
|
64
|
+
subsequently incorporated within the Work.
|
|
65
|
+
|
|
66
|
+
2. Grant of Copyright License. Subject to the terms and conditions of
|
|
67
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
68
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
69
|
+
copyright license to reproduce, prepare Derivative Works of,
|
|
70
|
+
publicly display, publicly perform, sublicense, and distribute the
|
|
71
|
+
Work and such Derivative Works in Source or Object form.
|
|
72
|
+
|
|
73
|
+
3. Grant of Patent License. Subject to the terms and conditions of
|
|
74
|
+
this License, each Contributor hereby grants to You a perpetual,
|
|
75
|
+
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
|
76
|
+
(except as stated in this section) patent license to make, have made,
|
|
77
|
+
use, offer to sell, sell, import, and otherwise transfer the Work,
|
|
78
|
+
where such license applies only to those patent claims licensable
|
|
79
|
+
by such Contributor that are necessarily infringed by their
|
|
80
|
+
Contribution(s) alone or by combination of their Contribution(s)
|
|
81
|
+
with the Work to which such Contribution(s) was submitted. If You
|
|
82
|
+
institute patent litigation against any entity (including a
|
|
83
|
+
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
|
84
|
+
or a Contribution incorporated within the Work constitutes direct
|
|
85
|
+
or contributory patent infringement, then any patent licenses
|
|
86
|
+
granted to You under this License for that Work shall terminate
|
|
87
|
+
as of the date such litigation is filed.
|
|
88
|
+
|
|
89
|
+
4. Redistribution. You may reproduce and distribute copies of the
|
|
90
|
+
Work or Derivative Works thereof in any medium, with or without
|
|
91
|
+
modifications, and in Source or Object form, provided that You
|
|
92
|
+
meet the following conditions:
|
|
93
|
+
|
|
94
|
+
(a) You must give any other recipients of the Work or
|
|
95
|
+
Derivative Works a copy of this License; and
|
|
96
|
+
|
|
97
|
+
(b) You must cause any modified files to carry prominent notices
|
|
98
|
+
stating that You changed the files; and
|
|
99
|
+
|
|
100
|
+
(c) You must retain, in the Source form of any Derivative Works
|
|
101
|
+
that You distribute, all copyright, patent, trademark, and
|
|
102
|
+
attribution notices from the Source form of the Work,
|
|
103
|
+
excluding those notices that do not pertain to any part of
|
|
104
|
+
the Derivative Works; and
|
|
105
|
+
|
|
106
|
+
(d) If the Work includes a "NOTICE" text file as part of its
|
|
107
|
+
distribution, then any Derivative Works that You distribute must
|
|
108
|
+
include a readable copy of the attribution notices contained
|
|
109
|
+
within such NOTICE file, excluding those notices that do not
|
|
110
|
+
pertain to any part of the Derivative Works, in at least one
|
|
111
|
+
of the following places: within a NOTICE text file distributed
|
|
112
|
+
as part of the Derivative Works; within the Source form or
|
|
113
|
+
documentation, if provided along with the Derivative Works; or,
|
|
114
|
+
within a display generated by the Derivative Works, if and
|
|
115
|
+
wherever such third-party notices normally appear. The contents
|
|
116
|
+
of the NOTICE file are for informational purposes only and
|
|
117
|
+
do not modify the License. You may add Your own attribution
|
|
118
|
+
notices within Derivative Works that You distribute, alongside
|
|
119
|
+
or as an addendum to the NOTICE text from the Work, provided
|
|
120
|
+
that such additional attribution notices cannot be construed
|
|
121
|
+
as modifying the License.
|
|
122
|
+
|
|
123
|
+
You may add Your own copyright statement to Your modifications and
|
|
124
|
+
may provide additional or different license terms and conditions
|
|
125
|
+
for use, reproduction, or distribution of Your modifications, or
|
|
126
|
+
for any such Derivative Works as a whole, provided Your use,
|
|
127
|
+
reproduction, and distribution of the Work otherwise complies with
|
|
128
|
+
the conditions stated in this License.
|
|
129
|
+
|
|
130
|
+
5. Submission of Contributions. Unless You explicitly state otherwise,
|
|
131
|
+
any Contribution intentionally submitted for inclusion in the Work
|
|
132
|
+
by You to the Licensor shall be under the terms and conditions of
|
|
133
|
+
this License, without any additional terms or conditions.
|
|
134
|
+
Notwithstanding the above, nothing herein shall supersede or modify
|
|
135
|
+
the terms of any separate license agreement you may have executed
|
|
136
|
+
with Licensor regarding such Contributions.
|
|
137
|
+
|
|
138
|
+
6. Trademarks. This License does not grant permission to use the trade
|
|
139
|
+
names, trademarks, service marks, or product names of the Licensor,
|
|
140
|
+
except as required for reasonable and customary use in describing the
|
|
141
|
+
origin of the Work and reproducing the content of the NOTICE file.
|
|
142
|
+
|
|
143
|
+
7. Disclaimer of Warranty. Unless required by applicable law or
|
|
144
|
+
agreed to in writing, Licensor provides the Work (and each
|
|
145
|
+
Contributor provides its Contributions) on an "AS IS" BASIS,
|
|
146
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
|
147
|
+
implied, including, without limitation, any warranties or conditions
|
|
148
|
+
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
|
149
|
+
PARTICULAR PURPOSE. You are solely responsible for determining the
|
|
150
|
+
appropriateness of using or redistributing the Work and assume any
|
|
151
|
+
risks associated with Your exercise of permissions under this License.
|
|
152
|
+
|
|
153
|
+
8. Limitation of Liability. In no event and under no legal theory,
|
|
154
|
+
whether in tort (including negligence), contract, or otherwise,
|
|
155
|
+
unless required by applicable law (such as deliberate and grossly
|
|
156
|
+
negligent acts) or agreed to in writing, shall any Contributor be
|
|
157
|
+
liable to You for damages, including any direct, indirect, special,
|
|
158
|
+
incidental, or consequential damages of any character arising as a
|
|
159
|
+
result of this License or out of the use or inability to use the
|
|
160
|
+
Work (including but not limited to damages for loss of goodwill,
|
|
161
|
+
work stoppage, computer failure or malfunction, or any and all
|
|
162
|
+
other commercial damages or losses), even if such Contributor
|
|
163
|
+
has been advised of the possibility of such damages.
|
|
164
|
+
|
|
165
|
+
9. Accepting Warranty or Additional Liability. While redistributing
|
|
166
|
+
the Work or Derivative Works thereof, You may choose to offer,
|
|
167
|
+
and charge a fee for, acceptance of support, warranty, indemnity,
|
|
168
|
+
or other liability obligations and/or rights consistent with this
|
|
169
|
+
License. However, in accepting such obligations, You may act only
|
|
170
|
+
on Your own behalf and on Your sole responsibility, not on behalf
|
|
171
|
+
of any other Contributor, and only if You agree to indemnify,
|
|
172
|
+
defend, and hold each Contributor harmless for any liability
|
|
173
|
+
incurred by, or claims asserted against, such Contributor by reason
|
|
174
|
+
of your accepting any such warranty or additional liability.
|
|
175
|
+
|
|
176
|
+
END OF TERMS AND CONDITIONS
|
|
177
|
+
|
|
178
|
+
APPENDIX: How to apply the Apache License to your work.
|
|
179
|
+
|
|
180
|
+
To apply the Apache License to your work, attach the following
|
|
181
|
+
boilerplate notice, with the fields enclosed by brackets "[]"
|
|
182
|
+
replaced with your own identifying information. (Don't include
|
|
183
|
+
the brackets!) The text should be enclosed in the appropriate
|
|
184
|
+
comment syntax for the file format. We also recommend that a
|
|
185
|
+
file or class name and description of purpose be included on the
|
|
186
|
+
same "printed page" as the copyright notice for easier
|
|
187
|
+
identification within third-party archives.
|
|
188
|
+
|
|
189
|
+
Copyright [yyyy] [name of copyright owner]
|
|
190
|
+
|
|
191
|
+
Licensed under the Apache License, Version 2.0 (the "License");
|
|
192
|
+
you may not use this file except in compliance with the License.
|
|
193
|
+
You may obtain a copy of the License at
|
|
194
|
+
|
|
195
|
+
http://www.apache.org/licenses/LICENSE-2.0
|
|
196
|
+
|
|
197
|
+
Unless required by applicable law or agreed to in writing, software
|
|
198
|
+
distributed under the License is distributed on an "AS IS" BASIS,
|
|
199
|
+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
200
|
+
See the License for the specific language governing permissions and
|
|
201
|
+
limitations under the License.
|
package/README.md
CHANGED
|
@@ -12,6 +12,27 @@ pnpm add @vizij/runtime-react @vizij/render @vizij/orchestrator-react react reac
|
|
|
12
12
|
|
|
13
13
|
Those three Vizij packages must stay in lock-step; always upgrade them together.
|
|
14
14
|
|
|
15
|
+
> **Bundler configuration:** The runtime depends on `@vizij/orchestrator-wasm`, `@vizij/node-graph-wasm`, and `@vizij/animation-wasm`, all of which emit `.wasm` assets. Enable async WebAssembly and treat `.wasm` files as emitted resources in your bundler. For Next.js:
|
|
16
|
+
>
|
|
17
|
+
> ```js
|
|
18
|
+
> // next.config.js
|
|
19
|
+
> module.exports = {
|
|
20
|
+
> webpack: (config) => {
|
|
21
|
+
> config.experiments = {
|
|
22
|
+
> ...(config.experiments ?? {}),
|
|
23
|
+
> asyncWebAssembly: true,
|
|
24
|
+
> };
|
|
25
|
+
> config.module.rules.push({
|
|
26
|
+
> test: /\.wasm$/,
|
|
27
|
+
> type: "asset/resource",
|
|
28
|
+
> });
|
|
29
|
+
> return config;
|
|
30
|
+
> },
|
|
31
|
+
> };
|
|
32
|
+
> ```
|
|
33
|
+
|
|
34
|
+
When overriding the default wasm location, pass string URLs to the underlying `init()` helpers so Webpack doesn’t wrap them in `RelativeURL`.
|
|
35
|
+
|
|
15
36
|
## Getting Started
|
|
16
37
|
|
|
17
38
|
```tsx
|
package/dist/index.js
CHANGED
|
@@ -291,6 +291,122 @@ function convertBundleAnimations(entries) {
|
|
|
291
291
|
clip: entry.clip
|
|
292
292
|
}));
|
|
293
293
|
}
|
|
294
|
+
function resolveChannelId(track) {
|
|
295
|
+
if (typeof track.componentId !== "string" || track.componentId.length === 0) {
|
|
296
|
+
return null;
|
|
297
|
+
}
|
|
298
|
+
if (typeof track.component === "string" && track.component.length > 0) {
|
|
299
|
+
return `${track.componentId}:${track.component}`;
|
|
300
|
+
}
|
|
301
|
+
const rawIndex = track.componentIndex != null ? Number(track.componentIndex) : void 0;
|
|
302
|
+
const valueSize = track.valueSize != null ? Number(track.valueSize) : void 0;
|
|
303
|
+
if (Number.isInteger(rawIndex) && Number.isFinite(rawIndex) && rawIndex >= 0 && Number.isFinite(valueSize) && valueSize > 1) {
|
|
304
|
+
return `${track.componentId}:${rawIndex}`;
|
|
305
|
+
}
|
|
306
|
+
return track.componentId;
|
|
307
|
+
}
|
|
308
|
+
function convertExtractedAnimations(clips) {
|
|
309
|
+
if (!Array.isArray(clips) || clips.length === 0) {
|
|
310
|
+
return [];
|
|
311
|
+
}
|
|
312
|
+
const assets = [];
|
|
313
|
+
clips.forEach((clip) => {
|
|
314
|
+
const clipTracks = Array.isArray(clip.tracks) ? clip.tracks : [];
|
|
315
|
+
if (clipTracks.length === 0) {
|
|
316
|
+
return;
|
|
317
|
+
}
|
|
318
|
+
const convertedTracks = [];
|
|
319
|
+
clipTracks.forEach((track) => {
|
|
320
|
+
const channelId = resolveChannelId(track);
|
|
321
|
+
if (!channelId) {
|
|
322
|
+
return;
|
|
323
|
+
}
|
|
324
|
+
const rawTimes = Array.isArray(track.times) ? track.times : [];
|
|
325
|
+
const rawValues = Array.isArray(track.values) ? track.values : [];
|
|
326
|
+
if (rawTimes.length === 0 || rawValues.length === 0) {
|
|
327
|
+
return;
|
|
328
|
+
}
|
|
329
|
+
const times = [];
|
|
330
|
+
for (const entry of rawTimes) {
|
|
331
|
+
const time = Number(entry);
|
|
332
|
+
if (!Number.isFinite(time)) {
|
|
333
|
+
return;
|
|
334
|
+
}
|
|
335
|
+
times.push(time);
|
|
336
|
+
}
|
|
337
|
+
const values = [];
|
|
338
|
+
for (const entry of rawValues) {
|
|
339
|
+
const value = Number(entry);
|
|
340
|
+
if (!Number.isFinite(value)) {
|
|
341
|
+
return;
|
|
342
|
+
}
|
|
343
|
+
values.push(value);
|
|
344
|
+
}
|
|
345
|
+
const parsedValueSize = track.valueSize != null ? Number(track.valueSize) : NaN;
|
|
346
|
+
const valueSize = Number.isFinite(parsedValueSize) && parsedValueSize > 0 ? parsedValueSize : 1;
|
|
347
|
+
if (values.length !== times.length * valueSize) {
|
|
348
|
+
return;
|
|
349
|
+
}
|
|
350
|
+
const rawIndex = track.componentIndex != null ? Number(track.componentIndex) : 0;
|
|
351
|
+
const componentIndex = Number.isInteger(rawIndex) && rawIndex >= 0 ? Math.min(rawIndex, valueSize - 1) : 0;
|
|
352
|
+
const keyframes = [];
|
|
353
|
+
times.forEach((time, index) => {
|
|
354
|
+
const base = index * valueSize + componentIndex;
|
|
355
|
+
const value = values[base];
|
|
356
|
+
if (!Number.isFinite(value)) {
|
|
357
|
+
return;
|
|
358
|
+
}
|
|
359
|
+
keyframes.push({ time, value });
|
|
360
|
+
});
|
|
361
|
+
if (keyframes.length === 0) {
|
|
362
|
+
return;
|
|
363
|
+
}
|
|
364
|
+
convertedTracks.push({
|
|
365
|
+
channel: channelId,
|
|
366
|
+
keyframes
|
|
367
|
+
});
|
|
368
|
+
});
|
|
369
|
+
if (convertedTracks.length === 0) {
|
|
370
|
+
return;
|
|
371
|
+
}
|
|
372
|
+
const durationFromTracks = convertedTracks.reduce((maxTime, track) => {
|
|
373
|
+
const keyframes = Array.isArray(track.keyframes) ? track.keyframes : [];
|
|
374
|
+
if (keyframes.length === 0) {
|
|
375
|
+
return maxTime;
|
|
376
|
+
}
|
|
377
|
+
const lastKeyframe = keyframes[keyframes.length - 1];
|
|
378
|
+
const time = Number(lastKeyframe?.time ?? 0);
|
|
379
|
+
if (!Number.isFinite(time)) {
|
|
380
|
+
return maxTime;
|
|
381
|
+
}
|
|
382
|
+
return time > maxTime ? time : maxTime;
|
|
383
|
+
}, 0);
|
|
384
|
+
const duration = typeof clip.duration === "number" && Number.isFinite(clip.duration) ? clip.duration : durationFromTracks;
|
|
385
|
+
const clipId = typeof clip.id === "string" && clip.id.length > 0 ? clip.id : typeof clip.name === "string" && clip.name.length > 0 ? clip.name : `gltf-animation-${assets.length}`;
|
|
386
|
+
const metadata = clip.metadata && typeof clip.metadata === "object" && !Array.isArray(clip.metadata) ? clip.metadata : void 0;
|
|
387
|
+
assets.push({
|
|
388
|
+
id: clipId,
|
|
389
|
+
clip: {
|
|
390
|
+
id: clipId,
|
|
391
|
+
name: typeof clip.name === "string" ? clip.name : clipId,
|
|
392
|
+
duration,
|
|
393
|
+
tracks: convertedTracks,
|
|
394
|
+
metadata
|
|
395
|
+
}
|
|
396
|
+
});
|
|
397
|
+
});
|
|
398
|
+
return assets;
|
|
399
|
+
}
|
|
400
|
+
function pickExtractedAnimations(asset) {
|
|
401
|
+
if (!asset || typeof asset !== "object") {
|
|
402
|
+
return void 0;
|
|
403
|
+
}
|
|
404
|
+
const animations = asset.animations;
|
|
405
|
+
if (!Array.isArray(animations)) {
|
|
406
|
+
return void 0;
|
|
407
|
+
}
|
|
408
|
+
return animations;
|
|
409
|
+
}
|
|
294
410
|
function mergeAnimationLists(explicit, fromBundle) {
|
|
295
411
|
if (!explicit?.length && fromBundle.length === 0) {
|
|
296
412
|
return void 0;
|
|
@@ -314,7 +430,7 @@ function mergeAnimationLists(explicit, fromBundle) {
|
|
|
314
430
|
}
|
|
315
431
|
return changed ? merged : explicit;
|
|
316
432
|
}
|
|
317
|
-
function mergeAssetBundle(base, extracted) {
|
|
433
|
+
function mergeAssetBundle(base, extracted, extractedAnimations) {
|
|
318
434
|
const resolvedBundle = base.bundle ?? extracted ?? null;
|
|
319
435
|
const rigFromBundle = convertBundleGraph(
|
|
320
436
|
pickBundleGraph(resolvedBundle, ["rig"])
|
|
@@ -354,10 +470,17 @@ function mergeAssetBundle(base, extracted) {
|
|
|
354
470
|
const animationsFromBundle = convertBundleAnimations(
|
|
355
471
|
resolvedBundle?.animations
|
|
356
472
|
);
|
|
357
|
-
|
|
473
|
+
let resolvedAnimations = mergeAnimationLists(
|
|
358
474
|
base.animations,
|
|
359
475
|
animationsFromBundle
|
|
360
476
|
);
|
|
477
|
+
const animationsFromAsset = extractedAnimations && extractedAnimations.length > 0 ? extractedAnimations : [];
|
|
478
|
+
if (animationsFromAsset.length > 0) {
|
|
479
|
+
resolvedAnimations = mergeAnimationLists(
|
|
480
|
+
resolvedAnimations,
|
|
481
|
+
animationsFromAsset
|
|
482
|
+
);
|
|
483
|
+
}
|
|
361
484
|
const merged = {
|
|
362
485
|
...base
|
|
363
486
|
};
|
|
@@ -430,6 +553,7 @@ function VizijRuntimeProviderInner({
|
|
|
430
553
|
}
|
|
431
554
|
return null;
|
|
432
555
|
});
|
|
556
|
+
const [extractedAnimations, setExtractedAnimations] = (0, import_react2.useState)([]);
|
|
433
557
|
(0, import_react2.useEffect)(() => {
|
|
434
558
|
if (initialAssetBundle.bundle) {
|
|
435
559
|
setExtractedBundle(initialAssetBundle.bundle);
|
|
@@ -442,8 +566,12 @@ function VizijRuntimeProviderInner({
|
|
|
442
566
|
}
|
|
443
567
|
}, [initialAssetBundle]);
|
|
444
568
|
const assetBundle = (0, import_react2.useMemo)(
|
|
445
|
-
() => mergeAssetBundle(
|
|
446
|
-
|
|
569
|
+
() => mergeAssetBundle(
|
|
570
|
+
initialAssetBundle,
|
|
571
|
+
extractedBundle,
|
|
572
|
+
extractedAnimations
|
|
573
|
+
),
|
|
574
|
+
[initialAssetBundle, extractedBundle, extractedAnimations]
|
|
447
575
|
);
|
|
448
576
|
const {
|
|
449
577
|
ready,
|
|
@@ -549,6 +677,8 @@ function VizijRuntimeProviderInner({
|
|
|
549
677
|
faceId
|
|
550
678
|
}));
|
|
551
679
|
}, [namespace, faceId, reportStatus]);
|
|
680
|
+
const glbAsset = initialAssetBundle.glb;
|
|
681
|
+
const baseBundle = initialAssetBundle.bundle ?? null;
|
|
552
682
|
(0, import_react2.useEffect)(() => {
|
|
553
683
|
let cancelled = false;
|
|
554
684
|
resetErrors();
|
|
@@ -560,40 +690,46 @@ function VizijRuntimeProviderInner({
|
|
|
560
690
|
outputPaths: [],
|
|
561
691
|
controllers: { graphs: [], anims: [] }
|
|
562
692
|
}));
|
|
693
|
+
setExtractedAnimations([]);
|
|
563
694
|
const loadAssets = async () => {
|
|
564
695
|
try {
|
|
565
696
|
let world;
|
|
566
697
|
let animatables;
|
|
567
|
-
let bundle =
|
|
568
|
-
|
|
698
|
+
let bundle = baseBundle;
|
|
699
|
+
let gltfAnimations;
|
|
700
|
+
if (glbAsset.kind === "url") {
|
|
569
701
|
const loaded = await (0, import_render.loadGLTFWithBundle)(
|
|
570
|
-
|
|
702
|
+
glbAsset.src,
|
|
571
703
|
[namespace],
|
|
572
|
-
|
|
573
|
-
|
|
704
|
+
glbAsset.aggressiveImport ?? false,
|
|
705
|
+
glbAsset.rootBounds
|
|
574
706
|
);
|
|
575
707
|
world = loaded.world;
|
|
576
708
|
animatables = loaded.animatables;
|
|
577
709
|
bundle = loaded.bundle ?? bundle;
|
|
578
|
-
|
|
710
|
+
gltfAnimations = pickExtractedAnimations(loaded);
|
|
711
|
+
} else if (glbAsset.kind === "blob") {
|
|
579
712
|
const loaded = await (0, import_render.loadGLTFFromBlobWithBundle)(
|
|
580
|
-
|
|
713
|
+
glbAsset.blob,
|
|
581
714
|
[namespace],
|
|
582
|
-
|
|
583
|
-
|
|
715
|
+
glbAsset.aggressiveImport ?? false,
|
|
716
|
+
glbAsset.rootBounds
|
|
584
717
|
);
|
|
585
718
|
world = loaded.world;
|
|
586
719
|
animatables = loaded.animatables;
|
|
587
720
|
bundle = loaded.bundle ?? bundle;
|
|
721
|
+
gltfAnimations = pickExtractedAnimations(loaded);
|
|
588
722
|
} else {
|
|
589
|
-
world =
|
|
590
|
-
animatables =
|
|
591
|
-
bundle =
|
|
723
|
+
world = glbAsset.world;
|
|
724
|
+
animatables = glbAsset.animatables;
|
|
725
|
+
bundle = glbAsset.bundle ?? bundle;
|
|
726
|
+
gltfAnimations = void 0;
|
|
592
727
|
}
|
|
593
728
|
if (cancelled) {
|
|
594
729
|
return;
|
|
595
730
|
}
|
|
596
731
|
setExtractedBundle(bundle ?? null);
|
|
732
|
+
setExtractedAnimations(convertExtractedAnimations(gltfAnimations));
|
|
597
733
|
const rootId = findRootId(world);
|
|
598
734
|
store.getState().addWorldElements(world, animatables, true);
|
|
599
735
|
reportStatus((prev) => ({
|
|
@@ -624,14 +760,16 @@ function VizijRuntimeProviderInner({
|
|
|
624
760
|
cancelled = true;
|
|
625
761
|
};
|
|
626
762
|
}, [
|
|
627
|
-
|
|
763
|
+
glbAsset,
|
|
764
|
+
baseBundle,
|
|
628
765
|
namespace,
|
|
629
766
|
faceId,
|
|
630
767
|
store,
|
|
631
768
|
pushError,
|
|
632
769
|
reportStatus,
|
|
633
770
|
resetErrors,
|
|
634
|
-
setExtractedBundle
|
|
771
|
+
setExtractedBundle,
|
|
772
|
+
setExtractedAnimations
|
|
635
773
|
]);
|
|
636
774
|
(0, import_react2.useEffect)(() => {
|
|
637
775
|
if (!ready && autoCreate) {
|
package/dist/index.mjs
CHANGED
|
@@ -284,6 +284,122 @@ function convertBundleAnimations(entries) {
|
|
|
284
284
|
clip: entry.clip
|
|
285
285
|
}));
|
|
286
286
|
}
|
|
287
|
+
function resolveChannelId(track) {
|
|
288
|
+
if (typeof track.componentId !== "string" || track.componentId.length === 0) {
|
|
289
|
+
return null;
|
|
290
|
+
}
|
|
291
|
+
if (typeof track.component === "string" && track.component.length > 0) {
|
|
292
|
+
return `${track.componentId}:${track.component}`;
|
|
293
|
+
}
|
|
294
|
+
const rawIndex = track.componentIndex != null ? Number(track.componentIndex) : void 0;
|
|
295
|
+
const valueSize = track.valueSize != null ? Number(track.valueSize) : void 0;
|
|
296
|
+
if (Number.isInteger(rawIndex) && Number.isFinite(rawIndex) && rawIndex >= 0 && Number.isFinite(valueSize) && valueSize > 1) {
|
|
297
|
+
return `${track.componentId}:${rawIndex}`;
|
|
298
|
+
}
|
|
299
|
+
return track.componentId;
|
|
300
|
+
}
|
|
301
|
+
function convertExtractedAnimations(clips) {
|
|
302
|
+
if (!Array.isArray(clips) || clips.length === 0) {
|
|
303
|
+
return [];
|
|
304
|
+
}
|
|
305
|
+
const assets = [];
|
|
306
|
+
clips.forEach((clip) => {
|
|
307
|
+
const clipTracks = Array.isArray(clip.tracks) ? clip.tracks : [];
|
|
308
|
+
if (clipTracks.length === 0) {
|
|
309
|
+
return;
|
|
310
|
+
}
|
|
311
|
+
const convertedTracks = [];
|
|
312
|
+
clipTracks.forEach((track) => {
|
|
313
|
+
const channelId = resolveChannelId(track);
|
|
314
|
+
if (!channelId) {
|
|
315
|
+
return;
|
|
316
|
+
}
|
|
317
|
+
const rawTimes = Array.isArray(track.times) ? track.times : [];
|
|
318
|
+
const rawValues = Array.isArray(track.values) ? track.values : [];
|
|
319
|
+
if (rawTimes.length === 0 || rawValues.length === 0) {
|
|
320
|
+
return;
|
|
321
|
+
}
|
|
322
|
+
const times = [];
|
|
323
|
+
for (const entry of rawTimes) {
|
|
324
|
+
const time = Number(entry);
|
|
325
|
+
if (!Number.isFinite(time)) {
|
|
326
|
+
return;
|
|
327
|
+
}
|
|
328
|
+
times.push(time);
|
|
329
|
+
}
|
|
330
|
+
const values = [];
|
|
331
|
+
for (const entry of rawValues) {
|
|
332
|
+
const value = Number(entry);
|
|
333
|
+
if (!Number.isFinite(value)) {
|
|
334
|
+
return;
|
|
335
|
+
}
|
|
336
|
+
values.push(value);
|
|
337
|
+
}
|
|
338
|
+
const parsedValueSize = track.valueSize != null ? Number(track.valueSize) : NaN;
|
|
339
|
+
const valueSize = Number.isFinite(parsedValueSize) && parsedValueSize > 0 ? parsedValueSize : 1;
|
|
340
|
+
if (values.length !== times.length * valueSize) {
|
|
341
|
+
return;
|
|
342
|
+
}
|
|
343
|
+
const rawIndex = track.componentIndex != null ? Number(track.componentIndex) : 0;
|
|
344
|
+
const componentIndex = Number.isInteger(rawIndex) && rawIndex >= 0 ? Math.min(rawIndex, valueSize - 1) : 0;
|
|
345
|
+
const keyframes = [];
|
|
346
|
+
times.forEach((time, index) => {
|
|
347
|
+
const base = index * valueSize + componentIndex;
|
|
348
|
+
const value = values[base];
|
|
349
|
+
if (!Number.isFinite(value)) {
|
|
350
|
+
return;
|
|
351
|
+
}
|
|
352
|
+
keyframes.push({ time, value });
|
|
353
|
+
});
|
|
354
|
+
if (keyframes.length === 0) {
|
|
355
|
+
return;
|
|
356
|
+
}
|
|
357
|
+
convertedTracks.push({
|
|
358
|
+
channel: channelId,
|
|
359
|
+
keyframes
|
|
360
|
+
});
|
|
361
|
+
});
|
|
362
|
+
if (convertedTracks.length === 0) {
|
|
363
|
+
return;
|
|
364
|
+
}
|
|
365
|
+
const durationFromTracks = convertedTracks.reduce((maxTime, track) => {
|
|
366
|
+
const keyframes = Array.isArray(track.keyframes) ? track.keyframes : [];
|
|
367
|
+
if (keyframes.length === 0) {
|
|
368
|
+
return maxTime;
|
|
369
|
+
}
|
|
370
|
+
const lastKeyframe = keyframes[keyframes.length - 1];
|
|
371
|
+
const time = Number(lastKeyframe?.time ?? 0);
|
|
372
|
+
if (!Number.isFinite(time)) {
|
|
373
|
+
return maxTime;
|
|
374
|
+
}
|
|
375
|
+
return time > maxTime ? time : maxTime;
|
|
376
|
+
}, 0);
|
|
377
|
+
const duration = typeof clip.duration === "number" && Number.isFinite(clip.duration) ? clip.duration : durationFromTracks;
|
|
378
|
+
const clipId = typeof clip.id === "string" && clip.id.length > 0 ? clip.id : typeof clip.name === "string" && clip.name.length > 0 ? clip.name : `gltf-animation-${assets.length}`;
|
|
379
|
+
const metadata = clip.metadata && typeof clip.metadata === "object" && !Array.isArray(clip.metadata) ? clip.metadata : void 0;
|
|
380
|
+
assets.push({
|
|
381
|
+
id: clipId,
|
|
382
|
+
clip: {
|
|
383
|
+
id: clipId,
|
|
384
|
+
name: typeof clip.name === "string" ? clip.name : clipId,
|
|
385
|
+
duration,
|
|
386
|
+
tracks: convertedTracks,
|
|
387
|
+
metadata
|
|
388
|
+
}
|
|
389
|
+
});
|
|
390
|
+
});
|
|
391
|
+
return assets;
|
|
392
|
+
}
|
|
393
|
+
function pickExtractedAnimations(asset) {
|
|
394
|
+
if (!asset || typeof asset !== "object") {
|
|
395
|
+
return void 0;
|
|
396
|
+
}
|
|
397
|
+
const animations = asset.animations;
|
|
398
|
+
if (!Array.isArray(animations)) {
|
|
399
|
+
return void 0;
|
|
400
|
+
}
|
|
401
|
+
return animations;
|
|
402
|
+
}
|
|
287
403
|
function mergeAnimationLists(explicit, fromBundle) {
|
|
288
404
|
if (!explicit?.length && fromBundle.length === 0) {
|
|
289
405
|
return void 0;
|
|
@@ -307,7 +423,7 @@ function mergeAnimationLists(explicit, fromBundle) {
|
|
|
307
423
|
}
|
|
308
424
|
return changed ? merged : explicit;
|
|
309
425
|
}
|
|
310
|
-
function mergeAssetBundle(base, extracted) {
|
|
426
|
+
function mergeAssetBundle(base, extracted, extractedAnimations) {
|
|
311
427
|
const resolvedBundle = base.bundle ?? extracted ?? null;
|
|
312
428
|
const rigFromBundle = convertBundleGraph(
|
|
313
429
|
pickBundleGraph(resolvedBundle, ["rig"])
|
|
@@ -347,10 +463,17 @@ function mergeAssetBundle(base, extracted) {
|
|
|
347
463
|
const animationsFromBundle = convertBundleAnimations(
|
|
348
464
|
resolvedBundle?.animations
|
|
349
465
|
);
|
|
350
|
-
|
|
466
|
+
let resolvedAnimations = mergeAnimationLists(
|
|
351
467
|
base.animations,
|
|
352
468
|
animationsFromBundle
|
|
353
469
|
);
|
|
470
|
+
const animationsFromAsset = extractedAnimations && extractedAnimations.length > 0 ? extractedAnimations : [];
|
|
471
|
+
if (animationsFromAsset.length > 0) {
|
|
472
|
+
resolvedAnimations = mergeAnimationLists(
|
|
473
|
+
resolvedAnimations,
|
|
474
|
+
animationsFromAsset
|
|
475
|
+
);
|
|
476
|
+
}
|
|
354
477
|
const merged = {
|
|
355
478
|
...base
|
|
356
479
|
};
|
|
@@ -423,6 +546,7 @@ function VizijRuntimeProviderInner({
|
|
|
423
546
|
}
|
|
424
547
|
return null;
|
|
425
548
|
});
|
|
549
|
+
const [extractedAnimations, setExtractedAnimations] = useState([]);
|
|
426
550
|
useEffect(() => {
|
|
427
551
|
if (initialAssetBundle.bundle) {
|
|
428
552
|
setExtractedBundle(initialAssetBundle.bundle);
|
|
@@ -435,8 +559,12 @@ function VizijRuntimeProviderInner({
|
|
|
435
559
|
}
|
|
436
560
|
}, [initialAssetBundle]);
|
|
437
561
|
const assetBundle = useMemo(
|
|
438
|
-
() => mergeAssetBundle(
|
|
439
|
-
|
|
562
|
+
() => mergeAssetBundle(
|
|
563
|
+
initialAssetBundle,
|
|
564
|
+
extractedBundle,
|
|
565
|
+
extractedAnimations
|
|
566
|
+
),
|
|
567
|
+
[initialAssetBundle, extractedBundle, extractedAnimations]
|
|
440
568
|
);
|
|
441
569
|
const {
|
|
442
570
|
ready,
|
|
@@ -542,6 +670,8 @@ function VizijRuntimeProviderInner({
|
|
|
542
670
|
faceId
|
|
543
671
|
}));
|
|
544
672
|
}, [namespace, faceId, reportStatus]);
|
|
673
|
+
const glbAsset = initialAssetBundle.glb;
|
|
674
|
+
const baseBundle = initialAssetBundle.bundle ?? null;
|
|
545
675
|
useEffect(() => {
|
|
546
676
|
let cancelled = false;
|
|
547
677
|
resetErrors();
|
|
@@ -553,40 +683,46 @@ function VizijRuntimeProviderInner({
|
|
|
553
683
|
outputPaths: [],
|
|
554
684
|
controllers: { graphs: [], anims: [] }
|
|
555
685
|
}));
|
|
686
|
+
setExtractedAnimations([]);
|
|
556
687
|
const loadAssets = async () => {
|
|
557
688
|
try {
|
|
558
689
|
let world;
|
|
559
690
|
let animatables;
|
|
560
|
-
let bundle =
|
|
561
|
-
|
|
691
|
+
let bundle = baseBundle;
|
|
692
|
+
let gltfAnimations;
|
|
693
|
+
if (glbAsset.kind === "url") {
|
|
562
694
|
const loaded = await loadGLTFWithBundle(
|
|
563
|
-
|
|
695
|
+
glbAsset.src,
|
|
564
696
|
[namespace],
|
|
565
|
-
|
|
566
|
-
|
|
697
|
+
glbAsset.aggressiveImport ?? false,
|
|
698
|
+
glbAsset.rootBounds
|
|
567
699
|
);
|
|
568
700
|
world = loaded.world;
|
|
569
701
|
animatables = loaded.animatables;
|
|
570
702
|
bundle = loaded.bundle ?? bundle;
|
|
571
|
-
|
|
703
|
+
gltfAnimations = pickExtractedAnimations(loaded);
|
|
704
|
+
} else if (glbAsset.kind === "blob") {
|
|
572
705
|
const loaded = await loadGLTFFromBlobWithBundle(
|
|
573
|
-
|
|
706
|
+
glbAsset.blob,
|
|
574
707
|
[namespace],
|
|
575
|
-
|
|
576
|
-
|
|
708
|
+
glbAsset.aggressiveImport ?? false,
|
|
709
|
+
glbAsset.rootBounds
|
|
577
710
|
);
|
|
578
711
|
world = loaded.world;
|
|
579
712
|
animatables = loaded.animatables;
|
|
580
713
|
bundle = loaded.bundle ?? bundle;
|
|
714
|
+
gltfAnimations = pickExtractedAnimations(loaded);
|
|
581
715
|
} else {
|
|
582
|
-
world =
|
|
583
|
-
animatables =
|
|
584
|
-
bundle =
|
|
716
|
+
world = glbAsset.world;
|
|
717
|
+
animatables = glbAsset.animatables;
|
|
718
|
+
bundle = glbAsset.bundle ?? bundle;
|
|
719
|
+
gltfAnimations = void 0;
|
|
585
720
|
}
|
|
586
721
|
if (cancelled) {
|
|
587
722
|
return;
|
|
588
723
|
}
|
|
589
724
|
setExtractedBundle(bundle ?? null);
|
|
725
|
+
setExtractedAnimations(convertExtractedAnimations(gltfAnimations));
|
|
590
726
|
const rootId = findRootId(world);
|
|
591
727
|
store.getState().addWorldElements(world, animatables, true);
|
|
592
728
|
reportStatus((prev) => ({
|
|
@@ -617,14 +753,16 @@ function VizijRuntimeProviderInner({
|
|
|
617
753
|
cancelled = true;
|
|
618
754
|
};
|
|
619
755
|
}, [
|
|
620
|
-
|
|
756
|
+
glbAsset,
|
|
757
|
+
baseBundle,
|
|
621
758
|
namespace,
|
|
622
759
|
faceId,
|
|
623
760
|
store,
|
|
624
761
|
pushError,
|
|
625
762
|
reportStatus,
|
|
626
763
|
resetErrors,
|
|
627
|
-
setExtractedBundle
|
|
764
|
+
setExtractedBundle,
|
|
765
|
+
setExtractedAnimations
|
|
628
766
|
]);
|
|
629
767
|
useEffect(() => {
|
|
630
768
|
if (!ready && autoCreate) {
|
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.7",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"module": "dist/index.mjs",
|
|
7
7
|
"types": "dist/index.d.ts",
|
|
@@ -23,25 +23,11 @@
|
|
|
23
23
|
"dist",
|
|
24
24
|
"README.md"
|
|
25
25
|
],
|
|
26
|
-
"scripts": {
|
|
27
|
-
"build": "tsup src/index.ts --format esm,cjs --dts src/index.ts --external react,react-dom",
|
|
28
|
-
"dev": "tsup src/index.ts --format esm,cjs --watch --dts src/index.ts --external react,react-dom",
|
|
29
|
-
"typecheck": "tsc --noEmit",
|
|
30
|
-
"lint": "pnpm --filter \"$npm_package_name\" exec eslint --ext .js,.jsx,.ts,.tsx -- .",
|
|
31
|
-
"lint:fix": "pnpm --filter \"$npm_package_name\" exec eslint --ext .js,.jsx,.ts,.tsx --fix -- .",
|
|
32
|
-
"prettier:check": "prettier --check .",
|
|
33
|
-
"prettier:write": "prettier --write .",
|
|
34
|
-
"test": "vitest --run --passWithNoTests",
|
|
35
|
-
"clean": "rm -rf dist .turbo coverage tsconfig.tsbuildinfo",
|
|
36
|
-
"reset": "rm -rf node_modules",
|
|
37
|
-
"reset:hard": "pnpm run reset && rm -f pnpm-lock.yaml package-lock.json yarn.lock",
|
|
38
|
-
"prepack": "pnpm run build && pnpm run test && pnpm run typecheck && pnpm run lint"
|
|
39
|
-
},
|
|
40
26
|
"dependencies": {
|
|
41
|
-
"@vizij/
|
|
42
|
-
"@vizij/render": "^0.0.4",
|
|
27
|
+
"@vizij/value-json": "^0.1.0",
|
|
43
28
|
"@vizij/utils": "^0.0.2",
|
|
44
|
-
"@vizij/
|
|
29
|
+
"@vizij/orchestrator-react": "^0.0.2",
|
|
30
|
+
"@vizij/render": "^0.0.4"
|
|
45
31
|
},
|
|
46
32
|
"peerDependencies": {
|
|
47
33
|
"react": ">=18",
|
|
@@ -57,5 +43,18 @@
|
|
|
57
43
|
},
|
|
58
44
|
"publishConfig": {
|
|
59
45
|
"access": "public"
|
|
46
|
+
},
|
|
47
|
+
"scripts": {
|
|
48
|
+
"build": "tsup src/index.ts --format esm,cjs --dts src/index.ts --external react,react-dom",
|
|
49
|
+
"dev": "tsup src/index.ts --format esm,cjs --watch --dts src/index.ts --external react,react-dom",
|
|
50
|
+
"typecheck": "tsc --noEmit",
|
|
51
|
+
"lint": "pnpm --filter \"$npm_package_name\" exec eslint --ext .js,.jsx,.ts,.tsx -- .",
|
|
52
|
+
"lint:fix": "pnpm --filter \"$npm_package_name\" exec eslint --ext .js,.jsx,.ts,.tsx --fix -- .",
|
|
53
|
+
"prettier:check": "prettier --check .",
|
|
54
|
+
"prettier:write": "prettier --write .",
|
|
55
|
+
"test": "vitest --run --passWithNoTests",
|
|
56
|
+
"clean": "rm -rf dist .turbo coverage tsconfig.tsbuildinfo",
|
|
57
|
+
"reset": "rm -rf node_modules",
|
|
58
|
+
"reset:hard": "pnpm run reset && rm -f pnpm-lock.yaml package-lock.json yarn.lock"
|
|
60
59
|
}
|
|
61
|
-
}
|
|
60
|
+
}
|