@vizij/render 0.0.4 → 0.0.6
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 +3 -2
- package/dist/index.d.mts +47 -3
- package/dist/index.d.ts +47 -3
- package/dist/index.js +393 -9
- package/dist/index.mjs +398 -10
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -23,7 +23,7 @@ This package exposes the `Vizij` canvas component along with hooks, stores, and
|
|
|
23
23
|
|
|
24
24
|
- `Vizij` renders a fully managed `@react-three/fiber` canvas with sensible defaults for orthographic cameras and safe-area overlays.
|
|
25
25
|
- A Zustand-powered store (`useVizijStore`) tracks renderables, controllers, and transient state. Hooks let you read or mutate slices without re-rendering entire scenes.
|
|
26
|
-
- Utilities (`loadGLTF`, `loadGLTFBlob`, export helpers) streamline loading rigged GLTF assets and exporting scene snapshots.
|
|
26
|
+
- Utilities (`loadGLTF`, `loadGLTFBlob`, export helpers) streamline loading rigged GLTF assets and exporting scene snapshots. The tuple helpers now return `[world, animatables, animations]`, where `animations` contains parsed clip metadata for any channels embedded in the GLB.
|
|
27
27
|
- Controllers wrap common behaviours (e.g., pointer interaction, safe-area visualisation) so you can compose features quickly.
|
|
28
28
|
|
|
29
29
|
---
|
|
@@ -108,7 +108,8 @@ Vizij scenes persist authoring metadata inside GLBs so third-party tools see bak
|
|
|
108
108
|
- Every renderable still carries a `RobotData` extension in `userData` describing features and animatable bindings.
|
|
109
109
|
- The exporter now writes a root-level `extensions.VIZIJ_bundle` block following the schema in [`src/types/vizij-bundle.ts`](./src/types/vizij-bundle.ts). It contains rig graphs, pose configs, stored Vizij clips, and provenance hashes.
|
|
110
110
|
- Use `exportScene(group, { bundle, animations })` to embed both the Vizij bundle and optional baked `THREE.AnimationClip` instances. The helper attaches the bundle only for the export call and restores the original object.
|
|
111
|
-
- When loading assets, prefer `loadGLTFWithBundle` / `loadGLTFFromBlobWithBundle` to retrieve `{ world, animatables, bundle }`. The legacy tuple helpers
|
|
111
|
+
- When loading assets, prefer `loadGLTFWithBundle` / `loadGLTFFromBlobWithBundle` to retrieve `{ world, animatables, bundle, animations }`. The legacy tuple helpers return `[world, animatables, animations]` if you only need the renderer state.
|
|
112
|
+
- The new `animations` field exposes `VizijAnimationClipData[]`, which maps each glTF animation channel back to Vizij animatable ids (`RobotData.features.*.value.id`). Each track provides component-aware `times`/`values` arrays so runtimes can register clips without re-parsing the GLB.
|
|
112
113
|
- `extractVizijBundle(scene)` and `applyVizijBundle(scene, bundle)` (under `src/functions/vizij-bundle.ts`) let advanced tooling inspect or mutate bundles without triggering a fresh export.
|
|
113
114
|
|
|
114
115
|
With this structure, authoring tools can round-trip orchestrator assets while shipping native glTF animations for viewers that do not understand Vizij.
|
package/dist/index.d.mts
CHANGED
|
@@ -362,6 +362,49 @@ interface VizijBundleExtension {
|
|
|
362
362
|
metadata?: Record<string, unknown>;
|
|
363
363
|
}
|
|
364
364
|
|
|
365
|
+
interface VizijAnimationTrackData {
|
|
366
|
+
/** Vizij animatable id extracted from RobotData.features.*.value.id */
|
|
367
|
+
componentId: string;
|
|
368
|
+
/** Feature key (e.g. translation, chin, etc.) */
|
|
369
|
+
feature: string;
|
|
370
|
+
/** Vizij renderable id that owns the feature. */
|
|
371
|
+
renderableId: string;
|
|
372
|
+
/** glTF node index referenced by the channel. */
|
|
373
|
+
nodeIndex: number;
|
|
374
|
+
/** Optional glTF node name for debugging. */
|
|
375
|
+
nodeName?: string;
|
|
376
|
+
/** Original glTF channel path (translation, rotation, etc.). */
|
|
377
|
+
path?: string;
|
|
378
|
+
/** Optional feature component label (e.g. x, y, z) if provided by the glTF channel. */
|
|
379
|
+
component?: string;
|
|
380
|
+
/** Index within the output accessor for multi-component values. */
|
|
381
|
+
componentIndex?: number;
|
|
382
|
+
/** Numeric type reported by the Vizij animatable (number, vector3, etc.). */
|
|
383
|
+
valueType?: string;
|
|
384
|
+
/** Number of numeric entries per keyframe within `values`. */
|
|
385
|
+
valueSize: number;
|
|
386
|
+
/** Interpolation declared on the glTF sampler. */
|
|
387
|
+
interpolation?: string;
|
|
388
|
+
/** Keyframe times extracted from the GLTF animation sampler. */
|
|
389
|
+
times: number[];
|
|
390
|
+
/** Keyframe values (flattened, length === times.length * valueSize). */
|
|
391
|
+
values: number[];
|
|
392
|
+
}
|
|
393
|
+
interface VizijAnimationClipData {
|
|
394
|
+
/** Stable identifier derived from glTF animation name or index. */
|
|
395
|
+
id: string;
|
|
396
|
+
/** Human readable name (mirrors glTF animation name when available). */
|
|
397
|
+
name?: string;
|
|
398
|
+
/** Duration in seconds resolved from the THREE.AnimationClip. */
|
|
399
|
+
duration: number;
|
|
400
|
+
/** Raw glTF animation index in the asset. */
|
|
401
|
+
index: number;
|
|
402
|
+
/** Optional metadata copied from glTF animation extras. */
|
|
403
|
+
metadata?: Record<string, unknown>;
|
|
404
|
+
/** Extracted per-channel track data for Vizij animatables. */
|
|
405
|
+
tracks: VizijAnimationTrackData[];
|
|
406
|
+
}
|
|
407
|
+
|
|
365
408
|
interface VizijData {
|
|
366
409
|
world: World;
|
|
367
410
|
animatables: Record<string, AnimatableValue>;
|
|
@@ -517,15 +560,16 @@ declare class EmptyModelError extends Error {
|
|
|
517
560
|
declare function loadGLTF(url: string, namespaces: string[], aggressiveImport?: boolean, rootBounds?: {
|
|
518
561
|
center: RawVector2;
|
|
519
562
|
size: RawVector2;
|
|
520
|
-
}): Promise<[World, Record<string, AnimatableValue
|
|
563
|
+
}): Promise<[World, Record<string, AnimatableValue>, VizijAnimationClipData[]]>;
|
|
521
564
|
declare function loadGLTFFromBlob(blob: Blob, namespaces: string[], aggressiveImport?: boolean, rootBounds?: {
|
|
522
565
|
center: RawVector2;
|
|
523
566
|
size: RawVector2;
|
|
524
|
-
}): Promise<[World, Record<string, AnimatableValue
|
|
567
|
+
}): Promise<[World, Record<string, AnimatableValue>, VizijAnimationClipData[]]>;
|
|
525
568
|
type LoadedVizijAsset = {
|
|
526
569
|
world: World;
|
|
527
570
|
animatables: Record<string, AnimatableValue>;
|
|
528
571
|
bundle: VizijBundleExtension | null;
|
|
572
|
+
animations: VizijAnimationClipData[];
|
|
529
573
|
};
|
|
530
574
|
declare function loadGLTFWithBundle(url: string, namespaces: string[], aggressiveImport?: boolean, rootBounds?: {
|
|
531
575
|
center: RawVector2;
|
|
@@ -555,4 +599,4 @@ declare function exportScene(data: Group$1, fileNameOrOptions?: string | ExportS
|
|
|
555
599
|
declare function extractVizijBundle(object: Object3D, parserJson?: unknown): VizijBundleExtension | null;
|
|
556
600
|
declare function applyVizijBundle(object: Object3D, bundle: VizijBundleExtension | null): () => void;
|
|
557
601
|
|
|
558
|
-
export { type AnimatedFeature, type Ellipse, type EllipseFeature, EmptyModelError, type ExportSceneOptions, type Feature, type Group, type GroupFeature, InnerVizij, type InnerVizijProps, type LoadedVizijAsset, type Rectangle, type RectangleFeature, type RenderableBase, type RenderableFeature, type Selection, type Shape, type ShapeFeature, ShapeMaterial, type StaticFeature, type Stored, type StoredAnimatedFeature, type StoredEllipse, type StoredFeatures, type StoredGroup, type StoredRectangle, type StoredRenderable, type StoredShape, Vizij, type VizijActions, type VizijAnimationId, type VizijBundleAnimationClip, type VizijBundleAnimationEntry, type VizijBundleAnimationKeyframe, type VizijBundleAnimationTrack, type VizijBundleExtension, type VizijBundleGraphEntry, type VizijBundleGraphKind, type VizijBundleGraphMetadata, type VizijBundlePoseSection, type VizijBundleVersion, VizijContext, type VizijData, type VizijGraphId, type VizijPoseDefinition, type VizijPoseId, type VizijPoseRigConfig, type VizijProps, VizijSlice, type VizijStore, type VizijStoreGetter, type VizijStoreSetter, type World, applyVizijBundle, createVizijStore, exportScene, extractVizijBundle, loadGLTF, loadGLTFFromBlob, loadGLTFFromBlobWithBundle, loadGLTFWithBundle, loadGltfFromBlob, useDefaultVizijStore, useFeatures, useVizijStore, useVizijStoreGetter, useVizijStoreSetter, useVizijStoreSubscription };
|
|
602
|
+
export { type AnimatedFeature, type Ellipse, type EllipseFeature, EmptyModelError, type ExportSceneOptions, type Feature, type Group, type GroupFeature, InnerVizij, type InnerVizijProps, type LoadedVizijAsset, type Rectangle, type RectangleFeature, type RenderableBase, type RenderableFeature, type Selection, type Shape, type ShapeFeature, ShapeMaterial, type StaticFeature, type Stored, type StoredAnimatedFeature, type StoredEllipse, type StoredFeatures, type StoredGroup, type StoredRectangle, type StoredRenderable, type StoredShape, Vizij, type VizijActions, type VizijAnimationClipData, type VizijAnimationId, type VizijAnimationTrackData, type VizijBundleAnimationClip, type VizijBundleAnimationEntry, type VizijBundleAnimationKeyframe, type VizijBundleAnimationTrack, type VizijBundleExtension, type VizijBundleGraphEntry, type VizijBundleGraphKind, type VizijBundleGraphMetadata, type VizijBundlePoseSection, type VizijBundleVersion, VizijContext, type VizijData, type VizijGraphId, type VizijPoseDefinition, type VizijPoseId, type VizijPoseRigConfig, type VizijProps, VizijSlice, type VizijStore, type VizijStoreGetter, type VizijStoreSetter, type World, applyVizijBundle, createVizijStore, exportScene, extractVizijBundle, loadGLTF, loadGLTFFromBlob, loadGLTFFromBlobWithBundle, loadGLTFWithBundle, loadGltfFromBlob, useDefaultVizijStore, useFeatures, useVizijStore, useVizijStoreGetter, useVizijStoreSetter, useVizijStoreSubscription };
|
package/dist/index.d.ts
CHANGED
|
@@ -362,6 +362,49 @@ interface VizijBundleExtension {
|
|
|
362
362
|
metadata?: Record<string, unknown>;
|
|
363
363
|
}
|
|
364
364
|
|
|
365
|
+
interface VizijAnimationTrackData {
|
|
366
|
+
/** Vizij animatable id extracted from RobotData.features.*.value.id */
|
|
367
|
+
componentId: string;
|
|
368
|
+
/** Feature key (e.g. translation, chin, etc.) */
|
|
369
|
+
feature: string;
|
|
370
|
+
/** Vizij renderable id that owns the feature. */
|
|
371
|
+
renderableId: string;
|
|
372
|
+
/** glTF node index referenced by the channel. */
|
|
373
|
+
nodeIndex: number;
|
|
374
|
+
/** Optional glTF node name for debugging. */
|
|
375
|
+
nodeName?: string;
|
|
376
|
+
/** Original glTF channel path (translation, rotation, etc.). */
|
|
377
|
+
path?: string;
|
|
378
|
+
/** Optional feature component label (e.g. x, y, z) if provided by the glTF channel. */
|
|
379
|
+
component?: string;
|
|
380
|
+
/** Index within the output accessor for multi-component values. */
|
|
381
|
+
componentIndex?: number;
|
|
382
|
+
/** Numeric type reported by the Vizij animatable (number, vector3, etc.). */
|
|
383
|
+
valueType?: string;
|
|
384
|
+
/** Number of numeric entries per keyframe within `values`. */
|
|
385
|
+
valueSize: number;
|
|
386
|
+
/** Interpolation declared on the glTF sampler. */
|
|
387
|
+
interpolation?: string;
|
|
388
|
+
/** Keyframe times extracted from the GLTF animation sampler. */
|
|
389
|
+
times: number[];
|
|
390
|
+
/** Keyframe values (flattened, length === times.length * valueSize). */
|
|
391
|
+
values: number[];
|
|
392
|
+
}
|
|
393
|
+
interface VizijAnimationClipData {
|
|
394
|
+
/** Stable identifier derived from glTF animation name or index. */
|
|
395
|
+
id: string;
|
|
396
|
+
/** Human readable name (mirrors glTF animation name when available). */
|
|
397
|
+
name?: string;
|
|
398
|
+
/** Duration in seconds resolved from the THREE.AnimationClip. */
|
|
399
|
+
duration: number;
|
|
400
|
+
/** Raw glTF animation index in the asset. */
|
|
401
|
+
index: number;
|
|
402
|
+
/** Optional metadata copied from glTF animation extras. */
|
|
403
|
+
metadata?: Record<string, unknown>;
|
|
404
|
+
/** Extracted per-channel track data for Vizij animatables. */
|
|
405
|
+
tracks: VizijAnimationTrackData[];
|
|
406
|
+
}
|
|
407
|
+
|
|
365
408
|
interface VizijData {
|
|
366
409
|
world: World;
|
|
367
410
|
animatables: Record<string, AnimatableValue>;
|
|
@@ -517,15 +560,16 @@ declare class EmptyModelError extends Error {
|
|
|
517
560
|
declare function loadGLTF(url: string, namespaces: string[], aggressiveImport?: boolean, rootBounds?: {
|
|
518
561
|
center: RawVector2;
|
|
519
562
|
size: RawVector2;
|
|
520
|
-
}): Promise<[World, Record<string, AnimatableValue
|
|
563
|
+
}): Promise<[World, Record<string, AnimatableValue>, VizijAnimationClipData[]]>;
|
|
521
564
|
declare function loadGLTFFromBlob(blob: Blob, namespaces: string[], aggressiveImport?: boolean, rootBounds?: {
|
|
522
565
|
center: RawVector2;
|
|
523
566
|
size: RawVector2;
|
|
524
|
-
}): Promise<[World, Record<string, AnimatableValue
|
|
567
|
+
}): Promise<[World, Record<string, AnimatableValue>, VizijAnimationClipData[]]>;
|
|
525
568
|
type LoadedVizijAsset = {
|
|
526
569
|
world: World;
|
|
527
570
|
animatables: Record<string, AnimatableValue>;
|
|
528
571
|
bundle: VizijBundleExtension | null;
|
|
572
|
+
animations: VizijAnimationClipData[];
|
|
529
573
|
};
|
|
530
574
|
declare function loadGLTFWithBundle(url: string, namespaces: string[], aggressiveImport?: boolean, rootBounds?: {
|
|
531
575
|
center: RawVector2;
|
|
@@ -555,4 +599,4 @@ declare function exportScene(data: Group$1, fileNameOrOptions?: string | ExportS
|
|
|
555
599
|
declare function extractVizijBundle(object: Object3D, parserJson?: unknown): VizijBundleExtension | null;
|
|
556
600
|
declare function applyVizijBundle(object: Object3D, bundle: VizijBundleExtension | null): () => void;
|
|
557
601
|
|
|
558
|
-
export { type AnimatedFeature, type Ellipse, type EllipseFeature, EmptyModelError, type ExportSceneOptions, type Feature, type Group, type GroupFeature, InnerVizij, type InnerVizijProps, type LoadedVizijAsset, type Rectangle, type RectangleFeature, type RenderableBase, type RenderableFeature, type Selection, type Shape, type ShapeFeature, ShapeMaterial, type StaticFeature, type Stored, type StoredAnimatedFeature, type StoredEllipse, type StoredFeatures, type StoredGroup, type StoredRectangle, type StoredRenderable, type StoredShape, Vizij, type VizijActions, type VizijAnimationId, type VizijBundleAnimationClip, type VizijBundleAnimationEntry, type VizijBundleAnimationKeyframe, type VizijBundleAnimationTrack, type VizijBundleExtension, type VizijBundleGraphEntry, type VizijBundleGraphKind, type VizijBundleGraphMetadata, type VizijBundlePoseSection, type VizijBundleVersion, VizijContext, type VizijData, type VizijGraphId, type VizijPoseDefinition, type VizijPoseId, type VizijPoseRigConfig, type VizijProps, VizijSlice, type VizijStore, type VizijStoreGetter, type VizijStoreSetter, type World, applyVizijBundle, createVizijStore, exportScene, extractVizijBundle, loadGLTF, loadGLTFFromBlob, loadGLTFFromBlobWithBundle, loadGLTFWithBundle, loadGltfFromBlob, useDefaultVizijStore, useFeatures, useVizijStore, useVizijStoreGetter, useVizijStoreSetter, useVizijStoreSubscription };
|
|
602
|
+
export { type AnimatedFeature, type Ellipse, type EllipseFeature, EmptyModelError, type ExportSceneOptions, type Feature, type Group, type GroupFeature, InnerVizij, type InnerVizijProps, type LoadedVizijAsset, type Rectangle, type RectangleFeature, type RenderableBase, type RenderableFeature, type Selection, type Shape, type ShapeFeature, ShapeMaterial, type StaticFeature, type Stored, type StoredAnimatedFeature, type StoredEllipse, type StoredFeatures, type StoredGroup, type StoredRectangle, type StoredRenderable, type StoredShape, Vizij, type VizijActions, type VizijAnimationClipData, type VizijAnimationId, type VizijAnimationTrackData, type VizijBundleAnimationClip, type VizijBundleAnimationEntry, type VizijBundleAnimationKeyframe, type VizijBundleAnimationTrack, type VizijBundleExtension, type VizijBundleGraphEntry, type VizijBundleGraphKind, type VizijBundleGraphMetadata, type VizijBundlePoseSection, type VizijBundleVersion, VizijContext, type VizijData, type VizijGraphId, type VizijPoseDefinition, type VizijPoseId, type VizijPoseRigConfig, type VizijProps, VizijSlice, type VizijStore, type VizijStoreGetter, type VizijStoreSetter, type World, applyVizijBundle, createVizijStore, exportScene, extractVizijBundle, loadGLTF, loadGLTFFromBlob, loadGLTFFromBlobWithBundle, loadGLTFWithBundle, loadGltfFromBlob, useDefaultVizijStore, useFeatures, useVizijStore, useVizijStoreGetter, useVizijStoreSetter, useVizijStoreSubscription };
|
package/dist/index.js
CHANGED
|
@@ -1769,6 +1769,11 @@ function Vizij({
|
|
|
1769
1769
|
style,
|
|
1770
1770
|
className,
|
|
1771
1771
|
onPointerMissed,
|
|
1772
|
+
gl: {
|
|
1773
|
+
outputColorSpace: import_three.SRGBColorSpace,
|
|
1774
|
+
toneMapping: import_three.NoToneMapping,
|
|
1775
|
+
antialias: true
|
|
1776
|
+
},
|
|
1772
1777
|
children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1773
1778
|
MemoizedInnerVizij,
|
|
1774
1779
|
{
|
|
@@ -1786,6 +1791,11 @@ function Vizij({
|
|
|
1786
1791
|
style,
|
|
1787
1792
|
className,
|
|
1788
1793
|
onPointerMissed,
|
|
1794
|
+
gl: {
|
|
1795
|
+
outputColorSpace: import_three.SRGBColorSpace,
|
|
1796
|
+
toneMapping: import_three.NoToneMapping,
|
|
1797
|
+
antialias: true
|
|
1798
|
+
},
|
|
1789
1799
|
children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
1790
1800
|
MemoizedInnerVizij,
|
|
1791
1801
|
{
|
|
@@ -2674,6 +2684,375 @@ function applyVizijBundle(object, bundle) {
|
|
|
2674
2684
|
};
|
|
2675
2685
|
}
|
|
2676
2686
|
|
|
2687
|
+
// src/functions/gltf-loading/extract-animations.ts
|
|
2688
|
+
var CHANNEL_PATH_TO_TRACK_PROPERTY = {
|
|
2689
|
+
translation: "position",
|
|
2690
|
+
rotation: "quaternion",
|
|
2691
|
+
scale: "scale",
|
|
2692
|
+
weights: "morphTargetInfluences"
|
|
2693
|
+
};
|
|
2694
|
+
function isPlainObject(value) {
|
|
2695
|
+
return Boolean(
|
|
2696
|
+
value && typeof value === "object" && !Array.isArray(value) && Object.prototype.toString.call(value) === "[object Object]"
|
|
2697
|
+
);
|
|
2698
|
+
}
|
|
2699
|
+
function clonePlainObject(value) {
|
|
2700
|
+
if (!value) {
|
|
2701
|
+
return void 0;
|
|
2702
|
+
}
|
|
2703
|
+
return JSON.parse(JSON.stringify(value));
|
|
2704
|
+
}
|
|
2705
|
+
function inferValueSize(valueType) {
|
|
2706
|
+
switch (valueType) {
|
|
2707
|
+
case "boolean":
|
|
2708
|
+
case "number":
|
|
2709
|
+
case "string":
|
|
2710
|
+
return 1;
|
|
2711
|
+
case "vector2":
|
|
2712
|
+
return 2;
|
|
2713
|
+
case "vector3":
|
|
2714
|
+
case "euler":
|
|
2715
|
+
case "rgb":
|
|
2716
|
+
case "hsl":
|
|
2717
|
+
return 3;
|
|
2718
|
+
case "vector4":
|
|
2719
|
+
case "quaternion":
|
|
2720
|
+
return 4;
|
|
2721
|
+
default:
|
|
2722
|
+
return 1;
|
|
2723
|
+
}
|
|
2724
|
+
}
|
|
2725
|
+
function componentNameToIndex(component) {
|
|
2726
|
+
if (!component || typeof component !== "string") {
|
|
2727
|
+
return void 0;
|
|
2728
|
+
}
|
|
2729
|
+
const normalized = component.trim().toLowerCase();
|
|
2730
|
+
if (normalized.length === 0) {
|
|
2731
|
+
return void 0;
|
|
2732
|
+
}
|
|
2733
|
+
const componentOrder = {
|
|
2734
|
+
x: 0,
|
|
2735
|
+
y: 1,
|
|
2736
|
+
z: 2,
|
|
2737
|
+
w: 3,
|
|
2738
|
+
r: 0,
|
|
2739
|
+
g: 1,
|
|
2740
|
+
b: 2,
|
|
2741
|
+
a: 3,
|
|
2742
|
+
u: 0,
|
|
2743
|
+
v: 1
|
|
2744
|
+
};
|
|
2745
|
+
return componentOrder[normalized];
|
|
2746
|
+
}
|
|
2747
|
+
function readComponentInfo(target) {
|
|
2748
|
+
if (!target || typeof target !== "object") {
|
|
2749
|
+
return {};
|
|
2750
|
+
}
|
|
2751
|
+
const sources = [];
|
|
2752
|
+
const record = target;
|
|
2753
|
+
const extensions = record.extensions;
|
|
2754
|
+
if (extensions && typeof extensions === "object") {
|
|
2755
|
+
const vizijChannel = extensions.VizijChannel;
|
|
2756
|
+
if (isPlainObject(vizijChannel)) {
|
|
2757
|
+
sources.push(vizijChannel);
|
|
2758
|
+
}
|
|
2759
|
+
const robotChannel = extensions.RobotChannel;
|
|
2760
|
+
if (isPlainObject(robotChannel)) {
|
|
2761
|
+
sources.push(robotChannel);
|
|
2762
|
+
}
|
|
2763
|
+
}
|
|
2764
|
+
const extras = record.extras;
|
|
2765
|
+
if (isPlainObject(extras)) {
|
|
2766
|
+
sources.push(extras);
|
|
2767
|
+
}
|
|
2768
|
+
let component;
|
|
2769
|
+
let componentIndex;
|
|
2770
|
+
for (const source of sources) {
|
|
2771
|
+
if (!isPlainObject(source)) {
|
|
2772
|
+
continue;
|
|
2773
|
+
}
|
|
2774
|
+
if (typeof source.component === "string" && !component) {
|
|
2775
|
+
component = source.component;
|
|
2776
|
+
}
|
|
2777
|
+
if (typeof source.axis === "string" && !component) {
|
|
2778
|
+
component = source.axis;
|
|
2779
|
+
}
|
|
2780
|
+
if (typeof source.channel === "string" && !component) {
|
|
2781
|
+
component = source.channel;
|
|
2782
|
+
}
|
|
2783
|
+
if (Object.prototype.hasOwnProperty.call(source, "componentIndex") && componentIndex == null) {
|
|
2784
|
+
const value = source.componentIndex;
|
|
2785
|
+
if (typeof value === "number") {
|
|
2786
|
+
componentIndex = value;
|
|
2787
|
+
}
|
|
2788
|
+
}
|
|
2789
|
+
if (Object.prototype.hasOwnProperty.call(source, "axisIndex") && componentIndex == null) {
|
|
2790
|
+
const value = source.axisIndex;
|
|
2791
|
+
if (typeof value === "number") {
|
|
2792
|
+
componentIndex = value;
|
|
2793
|
+
}
|
|
2794
|
+
}
|
|
2795
|
+
}
|
|
2796
|
+
if (componentIndex == null) {
|
|
2797
|
+
componentIndex = componentNameToIndex(component);
|
|
2798
|
+
}
|
|
2799
|
+
return { component, componentIndex };
|
|
2800
|
+
}
|
|
2801
|
+
function resolveRobotNodeIndex(parserJson) {
|
|
2802
|
+
const indexMap = /* @__PURE__ */ new Map();
|
|
2803
|
+
if (!parserJson || typeof parserJson !== "object") {
|
|
2804
|
+
return indexMap;
|
|
2805
|
+
}
|
|
2806
|
+
const json = parserJson;
|
|
2807
|
+
const nodes = Array.isArray(json.nodes) ? json.nodes : [];
|
|
2808
|
+
nodes.forEach((node, nodeIndex) => {
|
|
2809
|
+
if (!node || typeof node !== "object") {
|
|
2810
|
+
return;
|
|
2811
|
+
}
|
|
2812
|
+
const extensions = node.extensions;
|
|
2813
|
+
if (!extensions || typeof extensions !== "object") {
|
|
2814
|
+
return;
|
|
2815
|
+
}
|
|
2816
|
+
const robotData = extensions.RobotData;
|
|
2817
|
+
if (!robotData || typeof robotData !== "object") {
|
|
2818
|
+
return;
|
|
2819
|
+
}
|
|
2820
|
+
const renderableId = typeof robotData.id === "string" ? robotData.id : void 0;
|
|
2821
|
+
if (!renderableId) {
|
|
2822
|
+
return;
|
|
2823
|
+
}
|
|
2824
|
+
const nodeName = typeof node.name === "string" && node.name.length > 0 ? node.name : void 0;
|
|
2825
|
+
const features = {};
|
|
2826
|
+
const robotFeatures = robotData.features;
|
|
2827
|
+
if (robotFeatures && typeof robotFeatures === "object") {
|
|
2828
|
+
Object.entries(robotFeatures).forEach(
|
|
2829
|
+
([featureKey, featureValue]) => {
|
|
2830
|
+
if (!featureValue || typeof featureValue !== "object" || !featureValue.animated) {
|
|
2831
|
+
return;
|
|
2832
|
+
}
|
|
2833
|
+
const value = featureValue.value;
|
|
2834
|
+
const componentId = value && typeof value === "object" && typeof value.id === "string" ? value.id : void 0;
|
|
2835
|
+
if (!componentId) {
|
|
2836
|
+
return;
|
|
2837
|
+
}
|
|
2838
|
+
const valueType = value && typeof value === "object" && typeof value.type === "string" ? value.type : void 0;
|
|
2839
|
+
features[featureKey] = {
|
|
2840
|
+
feature: featureKey,
|
|
2841
|
+
componentId,
|
|
2842
|
+
valueType
|
|
2843
|
+
};
|
|
2844
|
+
}
|
|
2845
|
+
);
|
|
2846
|
+
}
|
|
2847
|
+
indexMap.set(nodeIndex, {
|
|
2848
|
+
renderableId,
|
|
2849
|
+
nodeName,
|
|
2850
|
+
features
|
|
2851
|
+
});
|
|
2852
|
+
});
|
|
2853
|
+
return indexMap;
|
|
2854
|
+
}
|
|
2855
|
+
function mapChannelPathToProperty(path) {
|
|
2856
|
+
if (typeof path !== "string") {
|
|
2857
|
+
return void 0;
|
|
2858
|
+
}
|
|
2859
|
+
return CHANNEL_PATH_TO_TRACK_PROPERTY[path] ?? path;
|
|
2860
|
+
}
|
|
2861
|
+
function resolveFeatureKey(channelTarget) {
|
|
2862
|
+
if (!channelTarget || typeof channelTarget !== "object") {
|
|
2863
|
+
return void 0;
|
|
2864
|
+
}
|
|
2865
|
+
const target = channelTarget;
|
|
2866
|
+
const extensions = target.extensions;
|
|
2867
|
+
if (extensions && typeof extensions === "object") {
|
|
2868
|
+
const vizij = extensions.VizijChannel;
|
|
2869
|
+
if (isPlainObject(vizij)) {
|
|
2870
|
+
const feature = vizij.feature;
|
|
2871
|
+
if (typeof feature === "string") {
|
|
2872
|
+
return feature;
|
|
2873
|
+
}
|
|
2874
|
+
}
|
|
2875
|
+
const robot = extensions.RobotChannel;
|
|
2876
|
+
if (isPlainObject(robot)) {
|
|
2877
|
+
const feature = robot.feature;
|
|
2878
|
+
if (typeof feature === "string") {
|
|
2879
|
+
return feature;
|
|
2880
|
+
}
|
|
2881
|
+
}
|
|
2882
|
+
}
|
|
2883
|
+
const extras = target.extras;
|
|
2884
|
+
if (isPlainObject(extras)) {
|
|
2885
|
+
const feature = extras.feature;
|
|
2886
|
+
if (typeof feature === "string") {
|
|
2887
|
+
return feature;
|
|
2888
|
+
}
|
|
2889
|
+
const channel = extras.channel;
|
|
2890
|
+
if (typeof channel === "string") {
|
|
2891
|
+
return channel;
|
|
2892
|
+
}
|
|
2893
|
+
}
|
|
2894
|
+
const path = target.path;
|
|
2895
|
+
return typeof path === "string" ? path : void 0;
|
|
2896
|
+
}
|
|
2897
|
+
function resolveTrackForChannel(clip, channelIndex, expectedProperty, nodeName) {
|
|
2898
|
+
if (!clip) {
|
|
2899
|
+
return void 0;
|
|
2900
|
+
}
|
|
2901
|
+
const orderedTrack = clip.tracks[channelIndex];
|
|
2902
|
+
if (orderedTrack) {
|
|
2903
|
+
return orderedTrack;
|
|
2904
|
+
}
|
|
2905
|
+
if (!expectedProperty) {
|
|
2906
|
+
return void 0;
|
|
2907
|
+
}
|
|
2908
|
+
const property = expectedProperty;
|
|
2909
|
+
const matches = (track) => {
|
|
2910
|
+
const name = track?.name ?? "";
|
|
2911
|
+
if (!name) {
|
|
2912
|
+
return false;
|
|
2913
|
+
}
|
|
2914
|
+
if (nodeName && name === `${nodeName}.${property}`) {
|
|
2915
|
+
return true;
|
|
2916
|
+
}
|
|
2917
|
+
if (nodeName && name.startsWith(`${nodeName}.`) && name.endsWith(property)) {
|
|
2918
|
+
return true;
|
|
2919
|
+
}
|
|
2920
|
+
if (!nodeName && name.endsWith(property)) {
|
|
2921
|
+
return true;
|
|
2922
|
+
}
|
|
2923
|
+
return false;
|
|
2924
|
+
};
|
|
2925
|
+
return clip.tracks.find(matches);
|
|
2926
|
+
}
|
|
2927
|
+
function toNumberArray(arrayLike) {
|
|
2928
|
+
if (!arrayLike) {
|
|
2929
|
+
return [];
|
|
2930
|
+
}
|
|
2931
|
+
return Array.from(arrayLike, (value) => Number(value));
|
|
2932
|
+
}
|
|
2933
|
+
function resolveClipDuration(clip, tracks) {
|
|
2934
|
+
if (clip && Number.isFinite(clip.duration) && clip.duration >= 0) {
|
|
2935
|
+
return clip.duration;
|
|
2936
|
+
}
|
|
2937
|
+
let maxTime = 0;
|
|
2938
|
+
tracks.forEach((track) => {
|
|
2939
|
+
if (!track.times.length) {
|
|
2940
|
+
return;
|
|
2941
|
+
}
|
|
2942
|
+
const lastTime = track.times[track.times.length - 1] ?? 0;
|
|
2943
|
+
if (lastTime > maxTime) {
|
|
2944
|
+
maxTime = lastTime;
|
|
2945
|
+
}
|
|
2946
|
+
});
|
|
2947
|
+
return maxTime;
|
|
2948
|
+
}
|
|
2949
|
+
function resolveClipId(animation, clip, index) {
|
|
2950
|
+
if (typeof animation.name === "string" && animation.name.length > 0) {
|
|
2951
|
+
return animation.name;
|
|
2952
|
+
}
|
|
2953
|
+
if (clip?.name && clip.name.length > 0) {
|
|
2954
|
+
return clip.name;
|
|
2955
|
+
}
|
|
2956
|
+
return `gltf-animation-${index}`;
|
|
2957
|
+
}
|
|
2958
|
+
function extractVizijAnimations(parserJson, clips) {
|
|
2959
|
+
const animations = [];
|
|
2960
|
+
if (!parserJson || typeof parserJson !== "object") {
|
|
2961
|
+
return animations;
|
|
2962
|
+
}
|
|
2963
|
+
const robotNodeIndex = resolveRobotNodeIndex(parserJson);
|
|
2964
|
+
if (robotNodeIndex.size === 0) {
|
|
2965
|
+
return animations;
|
|
2966
|
+
}
|
|
2967
|
+
const json = parserJson;
|
|
2968
|
+
const gltfAnimations = Array.isArray(json.animations) ? json.animations : [];
|
|
2969
|
+
if (gltfAnimations.length === 0) {
|
|
2970
|
+
return animations;
|
|
2971
|
+
}
|
|
2972
|
+
gltfAnimations.forEach((animation, animationIndex) => {
|
|
2973
|
+
if (!animation || typeof animation !== "object") {
|
|
2974
|
+
return;
|
|
2975
|
+
}
|
|
2976
|
+
const animationRecord = animation;
|
|
2977
|
+
const channels = Array.isArray(animationRecord.channels) ? animationRecord.channels : [];
|
|
2978
|
+
if (channels.length === 0) {
|
|
2979
|
+
return;
|
|
2980
|
+
}
|
|
2981
|
+
const samplers = Array.isArray(animationRecord.samplers) ? animationRecord.samplers : [];
|
|
2982
|
+
const clip = Array.isArray(clips) ? clips[animationIndex] : void 0;
|
|
2983
|
+
const trackData = [];
|
|
2984
|
+
channels.forEach((channel, channelIndex) => {
|
|
2985
|
+
if (!channel || typeof channel !== "object") {
|
|
2986
|
+
return;
|
|
2987
|
+
}
|
|
2988
|
+
const channelRecord = channel;
|
|
2989
|
+
const target = channelRecord.target;
|
|
2990
|
+
const nodeIndex = target && typeof target === "object" && typeof target.node === "number" ? target.node : void 0;
|
|
2991
|
+
if (nodeIndex == null || !robotNodeIndex.has(nodeIndex)) {
|
|
2992
|
+
return;
|
|
2993
|
+
}
|
|
2994
|
+
const robotNode = robotNodeIndex.get(nodeIndex);
|
|
2995
|
+
const featureKey = resolveFeatureKey(target);
|
|
2996
|
+
if (!featureKey) {
|
|
2997
|
+
return;
|
|
2998
|
+
}
|
|
2999
|
+
const featureInfo = robotNode.features[featureKey];
|
|
3000
|
+
if (!featureInfo) {
|
|
3001
|
+
return;
|
|
3002
|
+
}
|
|
3003
|
+
const propertyName = mapChannelPathToProperty(
|
|
3004
|
+
target && typeof target === "object" ? target.path : void 0
|
|
3005
|
+
);
|
|
3006
|
+
const track = resolveTrackForChannel(
|
|
3007
|
+
clip,
|
|
3008
|
+
channelIndex,
|
|
3009
|
+
propertyName,
|
|
3010
|
+
robotNode.nodeName
|
|
3011
|
+
);
|
|
3012
|
+
if (!track) {
|
|
3013
|
+
return;
|
|
3014
|
+
}
|
|
3015
|
+
const samplerIndex = typeof channelRecord.sampler === "number" ? channelRecord.sampler : -1;
|
|
3016
|
+
const sampler = samplerIndex >= 0 && samplerIndex < samplers.length ? samplers[samplerIndex] : void 0;
|
|
3017
|
+
const interpolation = sampler && typeof sampler.interpolation === "string" ? sampler.interpolation : void 0;
|
|
3018
|
+
let valueSize = typeof track.getValueSize === "function" ? track.getValueSize() : inferValueSize(featureInfo.valueType);
|
|
3019
|
+
if (!Number.isFinite(valueSize) || valueSize <= 0) {
|
|
3020
|
+
valueSize = inferValueSize(featureInfo.valueType);
|
|
3021
|
+
}
|
|
3022
|
+
const { component, componentIndex } = readComponentInfo(target);
|
|
3023
|
+
trackData.push({
|
|
3024
|
+
componentId: featureInfo.componentId,
|
|
3025
|
+
feature: featureInfo.feature,
|
|
3026
|
+
renderableId: robotNode.renderableId,
|
|
3027
|
+
nodeIndex,
|
|
3028
|
+
nodeName: robotNode.nodeName,
|
|
3029
|
+
path: target && typeof target === "object" && typeof target.path === "string" ? target.path : void 0,
|
|
3030
|
+
component,
|
|
3031
|
+
componentIndex,
|
|
3032
|
+
valueType: featureInfo.valueType,
|
|
3033
|
+
valueSize,
|
|
3034
|
+
interpolation,
|
|
3035
|
+
times: toNumberArray(track.times),
|
|
3036
|
+
values: toNumberArray(track.values)
|
|
3037
|
+
});
|
|
3038
|
+
});
|
|
3039
|
+
if (trackData.length === 0) {
|
|
3040
|
+
return;
|
|
3041
|
+
}
|
|
3042
|
+
animations.push({
|
|
3043
|
+
id: resolveClipId(animationRecord, clip, animationIndex),
|
|
3044
|
+
name: typeof animationRecord.name === "string" && animationRecord.name.length > 0 ? animationRecord.name : clip?.name,
|
|
3045
|
+
duration: resolveClipDuration(clip, trackData),
|
|
3046
|
+
index: animationIndex,
|
|
3047
|
+
metadata: clonePlainObject(
|
|
3048
|
+
animationRecord.extras
|
|
3049
|
+
),
|
|
3050
|
+
tracks: trackData
|
|
3051
|
+
});
|
|
3052
|
+
});
|
|
3053
|
+
return animations;
|
|
3054
|
+
}
|
|
3055
|
+
|
|
2677
3056
|
// src/functions/load-gltf.ts
|
|
2678
3057
|
THREE5.Object3D.DEFAULT_UP.set(0, 0, 1);
|
|
2679
3058
|
var EmptyModelError = class extends Error {
|
|
@@ -2692,9 +3071,10 @@ async function loadGLTF(url, namespaces, aggressiveImport = false, rootBounds) {
|
|
|
2692
3071
|
actualizedNamespaces,
|
|
2693
3072
|
aggressiveImport,
|
|
2694
3073
|
rootBounds,
|
|
2695
|
-
modelData?.parser?.json
|
|
3074
|
+
modelData?.parser?.json,
|
|
3075
|
+
modelData.animations
|
|
2696
3076
|
);
|
|
2697
|
-
return [asset.world, asset.animatables];
|
|
3077
|
+
return [asset.world, asset.animatables, asset.animations];
|
|
2698
3078
|
}
|
|
2699
3079
|
async function loadGLTFFromBlob(blob, namespaces, aggressiveImport = false, rootBounds) {
|
|
2700
3080
|
const actualizedNamespaces = namespaces.length > 0 ? namespaces : ["default"];
|
|
@@ -2707,7 +3087,7 @@ async function loadGLTFFromBlob(blob, namespaces, aggressiveImport = false, root
|
|
|
2707
3087
|
aggressiveImport,
|
|
2708
3088
|
rootBounds
|
|
2709
3089
|
);
|
|
2710
|
-
return [asset.world, asset.animatables];
|
|
3090
|
+
return [asset.world, asset.animatables, asset.animations];
|
|
2711
3091
|
} finally {
|
|
2712
3092
|
URL.revokeObjectURL(objectUrl);
|
|
2713
3093
|
}
|
|
@@ -2726,9 +3106,10 @@ async function loadGLTFFromBlob(blob, namespaces, aggressiveImport = false, root
|
|
|
2726
3106
|
actualizedNamespaces,
|
|
2727
3107
|
aggressiveImport,
|
|
2728
3108
|
rootBounds,
|
|
2729
|
-
gltf?.parser?.json
|
|
3109
|
+
gltf?.parser?.json,
|
|
3110
|
+
gltf.animations
|
|
2730
3111
|
);
|
|
2731
|
-
resolve([asset.world, asset.animatables]);
|
|
3112
|
+
resolve([asset.world, asset.animatables, asset.animations]);
|
|
2732
3113
|
} catch (error) {
|
|
2733
3114
|
if (error instanceof Error) {
|
|
2734
3115
|
reject(error);
|
|
@@ -2743,7 +3124,7 @@ async function loadGLTFFromBlob(blob, namespaces, aggressiveImport = false, root
|
|
|
2743
3124
|
);
|
|
2744
3125
|
});
|
|
2745
3126
|
}
|
|
2746
|
-
function parseScene(scene, namespaces, aggressiveImport, rootBounds, parserJson) {
|
|
3127
|
+
function parseScene(scene, namespaces, aggressiveImport, rootBounds, parserJson, clips) {
|
|
2747
3128
|
const [world, animatables] = traverseThree(
|
|
2748
3129
|
scene,
|
|
2749
3130
|
namespaces,
|
|
@@ -2751,7 +3132,8 @@ function parseScene(scene, namespaces, aggressiveImport, rootBounds, parserJson)
|
|
|
2751
3132
|
rootBounds
|
|
2752
3133
|
);
|
|
2753
3134
|
const bundle = extractVizijBundle(scene, parserJson);
|
|
2754
|
-
|
|
3135
|
+
const animations = extractVizijAnimations(parserJson, clips);
|
|
3136
|
+
return { world, animatables, bundle, animations };
|
|
2755
3137
|
}
|
|
2756
3138
|
async function loadGLTFWithBundle(url, namespaces, aggressiveImport = false, rootBounds) {
|
|
2757
3139
|
const modelLoader = new import_three_stdlib.GLTFLoader();
|
|
@@ -2763,7 +3145,8 @@ async function loadGLTFWithBundle(url, namespaces, aggressiveImport = false, roo
|
|
|
2763
3145
|
actualizedNamespaces,
|
|
2764
3146
|
aggressiveImport,
|
|
2765
3147
|
rootBounds,
|
|
2766
|
-
modelData?.parser?.json
|
|
3148
|
+
modelData?.parser?.json,
|
|
3149
|
+
modelData.animations
|
|
2767
3150
|
);
|
|
2768
3151
|
}
|
|
2769
3152
|
async function loadGLTFFromBlobWithBundle(blob, namespaces, aggressiveImport = false, rootBounds) {
|
|
@@ -2795,7 +3178,8 @@ async function loadGLTFFromBlobWithBundle(blob, namespaces, aggressiveImport = f
|
|
|
2795
3178
|
actualizedNamespaces,
|
|
2796
3179
|
aggressiveImport,
|
|
2797
3180
|
rootBounds,
|
|
2798
|
-
gltf?.parser?.json
|
|
3181
|
+
gltf?.parser?.json,
|
|
3182
|
+
gltf.animations
|
|
2799
3183
|
);
|
|
2800
3184
|
resolve(asset);
|
|
2801
3185
|
} catch (error) {
|
package/dist/index.mjs
CHANGED
|
@@ -6,7 +6,11 @@ import {
|
|
|
6
6
|
useEffect as useEffect6
|
|
7
7
|
} from "react";
|
|
8
8
|
import { ErrorBoundary } from "react-error-boundary";
|
|
9
|
-
import {
|
|
9
|
+
import {
|
|
10
|
+
Object3D as Object3D4,
|
|
11
|
+
SRGBColorSpace,
|
|
12
|
+
NoToneMapping
|
|
13
|
+
} from "three";
|
|
10
14
|
import { Canvas, useThree } from "@react-three/fiber";
|
|
11
15
|
import { Line as Line3, OrthographicCamera, Text } from "@react-three/drei";
|
|
12
16
|
import { useShallow as useShallow6 } from "zustand/react/shallow";
|
|
@@ -1767,6 +1771,11 @@ function Vizij({
|
|
|
1767
1771
|
style,
|
|
1768
1772
|
className,
|
|
1769
1773
|
onPointerMissed,
|
|
1774
|
+
gl: {
|
|
1775
|
+
outputColorSpace: SRGBColorSpace,
|
|
1776
|
+
toneMapping: NoToneMapping,
|
|
1777
|
+
antialias: true
|
|
1778
|
+
},
|
|
1770
1779
|
children: /* @__PURE__ */ jsx6(
|
|
1771
1780
|
MemoizedInnerVizij,
|
|
1772
1781
|
{
|
|
@@ -1784,6 +1793,11 @@ function Vizij({
|
|
|
1784
1793
|
style,
|
|
1785
1794
|
className,
|
|
1786
1795
|
onPointerMissed,
|
|
1796
|
+
gl: {
|
|
1797
|
+
outputColorSpace: SRGBColorSpace,
|
|
1798
|
+
toneMapping: NoToneMapping,
|
|
1799
|
+
antialias: true
|
|
1800
|
+
},
|
|
1787
1801
|
children: /* @__PURE__ */ jsx6(
|
|
1788
1802
|
MemoizedInnerVizij,
|
|
1789
1803
|
{
|
|
@@ -2674,6 +2688,375 @@ function applyVizijBundle(object, bundle) {
|
|
|
2674
2688
|
};
|
|
2675
2689
|
}
|
|
2676
2690
|
|
|
2691
|
+
// src/functions/gltf-loading/extract-animations.ts
|
|
2692
|
+
var CHANNEL_PATH_TO_TRACK_PROPERTY = {
|
|
2693
|
+
translation: "position",
|
|
2694
|
+
rotation: "quaternion",
|
|
2695
|
+
scale: "scale",
|
|
2696
|
+
weights: "morphTargetInfluences"
|
|
2697
|
+
};
|
|
2698
|
+
function isPlainObject(value) {
|
|
2699
|
+
return Boolean(
|
|
2700
|
+
value && typeof value === "object" && !Array.isArray(value) && Object.prototype.toString.call(value) === "[object Object]"
|
|
2701
|
+
);
|
|
2702
|
+
}
|
|
2703
|
+
function clonePlainObject(value) {
|
|
2704
|
+
if (!value) {
|
|
2705
|
+
return void 0;
|
|
2706
|
+
}
|
|
2707
|
+
return JSON.parse(JSON.stringify(value));
|
|
2708
|
+
}
|
|
2709
|
+
function inferValueSize(valueType) {
|
|
2710
|
+
switch (valueType) {
|
|
2711
|
+
case "boolean":
|
|
2712
|
+
case "number":
|
|
2713
|
+
case "string":
|
|
2714
|
+
return 1;
|
|
2715
|
+
case "vector2":
|
|
2716
|
+
return 2;
|
|
2717
|
+
case "vector3":
|
|
2718
|
+
case "euler":
|
|
2719
|
+
case "rgb":
|
|
2720
|
+
case "hsl":
|
|
2721
|
+
return 3;
|
|
2722
|
+
case "vector4":
|
|
2723
|
+
case "quaternion":
|
|
2724
|
+
return 4;
|
|
2725
|
+
default:
|
|
2726
|
+
return 1;
|
|
2727
|
+
}
|
|
2728
|
+
}
|
|
2729
|
+
function componentNameToIndex(component) {
|
|
2730
|
+
if (!component || typeof component !== "string") {
|
|
2731
|
+
return void 0;
|
|
2732
|
+
}
|
|
2733
|
+
const normalized = component.trim().toLowerCase();
|
|
2734
|
+
if (normalized.length === 0) {
|
|
2735
|
+
return void 0;
|
|
2736
|
+
}
|
|
2737
|
+
const componentOrder = {
|
|
2738
|
+
x: 0,
|
|
2739
|
+
y: 1,
|
|
2740
|
+
z: 2,
|
|
2741
|
+
w: 3,
|
|
2742
|
+
r: 0,
|
|
2743
|
+
g: 1,
|
|
2744
|
+
b: 2,
|
|
2745
|
+
a: 3,
|
|
2746
|
+
u: 0,
|
|
2747
|
+
v: 1
|
|
2748
|
+
};
|
|
2749
|
+
return componentOrder[normalized];
|
|
2750
|
+
}
|
|
2751
|
+
function readComponentInfo(target) {
|
|
2752
|
+
if (!target || typeof target !== "object") {
|
|
2753
|
+
return {};
|
|
2754
|
+
}
|
|
2755
|
+
const sources = [];
|
|
2756
|
+
const record = target;
|
|
2757
|
+
const extensions = record.extensions;
|
|
2758
|
+
if (extensions && typeof extensions === "object") {
|
|
2759
|
+
const vizijChannel = extensions.VizijChannel;
|
|
2760
|
+
if (isPlainObject(vizijChannel)) {
|
|
2761
|
+
sources.push(vizijChannel);
|
|
2762
|
+
}
|
|
2763
|
+
const robotChannel = extensions.RobotChannel;
|
|
2764
|
+
if (isPlainObject(robotChannel)) {
|
|
2765
|
+
sources.push(robotChannel);
|
|
2766
|
+
}
|
|
2767
|
+
}
|
|
2768
|
+
const extras = record.extras;
|
|
2769
|
+
if (isPlainObject(extras)) {
|
|
2770
|
+
sources.push(extras);
|
|
2771
|
+
}
|
|
2772
|
+
let component;
|
|
2773
|
+
let componentIndex;
|
|
2774
|
+
for (const source of sources) {
|
|
2775
|
+
if (!isPlainObject(source)) {
|
|
2776
|
+
continue;
|
|
2777
|
+
}
|
|
2778
|
+
if (typeof source.component === "string" && !component) {
|
|
2779
|
+
component = source.component;
|
|
2780
|
+
}
|
|
2781
|
+
if (typeof source.axis === "string" && !component) {
|
|
2782
|
+
component = source.axis;
|
|
2783
|
+
}
|
|
2784
|
+
if (typeof source.channel === "string" && !component) {
|
|
2785
|
+
component = source.channel;
|
|
2786
|
+
}
|
|
2787
|
+
if (Object.prototype.hasOwnProperty.call(source, "componentIndex") && componentIndex == null) {
|
|
2788
|
+
const value = source.componentIndex;
|
|
2789
|
+
if (typeof value === "number") {
|
|
2790
|
+
componentIndex = value;
|
|
2791
|
+
}
|
|
2792
|
+
}
|
|
2793
|
+
if (Object.prototype.hasOwnProperty.call(source, "axisIndex") && componentIndex == null) {
|
|
2794
|
+
const value = source.axisIndex;
|
|
2795
|
+
if (typeof value === "number") {
|
|
2796
|
+
componentIndex = value;
|
|
2797
|
+
}
|
|
2798
|
+
}
|
|
2799
|
+
}
|
|
2800
|
+
if (componentIndex == null) {
|
|
2801
|
+
componentIndex = componentNameToIndex(component);
|
|
2802
|
+
}
|
|
2803
|
+
return { component, componentIndex };
|
|
2804
|
+
}
|
|
2805
|
+
function resolveRobotNodeIndex(parserJson) {
|
|
2806
|
+
const indexMap = /* @__PURE__ */ new Map();
|
|
2807
|
+
if (!parserJson || typeof parserJson !== "object") {
|
|
2808
|
+
return indexMap;
|
|
2809
|
+
}
|
|
2810
|
+
const json = parserJson;
|
|
2811
|
+
const nodes = Array.isArray(json.nodes) ? json.nodes : [];
|
|
2812
|
+
nodes.forEach((node, nodeIndex) => {
|
|
2813
|
+
if (!node || typeof node !== "object") {
|
|
2814
|
+
return;
|
|
2815
|
+
}
|
|
2816
|
+
const extensions = node.extensions;
|
|
2817
|
+
if (!extensions || typeof extensions !== "object") {
|
|
2818
|
+
return;
|
|
2819
|
+
}
|
|
2820
|
+
const robotData = extensions.RobotData;
|
|
2821
|
+
if (!robotData || typeof robotData !== "object") {
|
|
2822
|
+
return;
|
|
2823
|
+
}
|
|
2824
|
+
const renderableId = typeof robotData.id === "string" ? robotData.id : void 0;
|
|
2825
|
+
if (!renderableId) {
|
|
2826
|
+
return;
|
|
2827
|
+
}
|
|
2828
|
+
const nodeName = typeof node.name === "string" && node.name.length > 0 ? node.name : void 0;
|
|
2829
|
+
const features = {};
|
|
2830
|
+
const robotFeatures = robotData.features;
|
|
2831
|
+
if (robotFeatures && typeof robotFeatures === "object") {
|
|
2832
|
+
Object.entries(robotFeatures).forEach(
|
|
2833
|
+
([featureKey, featureValue]) => {
|
|
2834
|
+
if (!featureValue || typeof featureValue !== "object" || !featureValue.animated) {
|
|
2835
|
+
return;
|
|
2836
|
+
}
|
|
2837
|
+
const value = featureValue.value;
|
|
2838
|
+
const componentId = value && typeof value === "object" && typeof value.id === "string" ? value.id : void 0;
|
|
2839
|
+
if (!componentId) {
|
|
2840
|
+
return;
|
|
2841
|
+
}
|
|
2842
|
+
const valueType = value && typeof value === "object" && typeof value.type === "string" ? value.type : void 0;
|
|
2843
|
+
features[featureKey] = {
|
|
2844
|
+
feature: featureKey,
|
|
2845
|
+
componentId,
|
|
2846
|
+
valueType
|
|
2847
|
+
};
|
|
2848
|
+
}
|
|
2849
|
+
);
|
|
2850
|
+
}
|
|
2851
|
+
indexMap.set(nodeIndex, {
|
|
2852
|
+
renderableId,
|
|
2853
|
+
nodeName,
|
|
2854
|
+
features
|
|
2855
|
+
});
|
|
2856
|
+
});
|
|
2857
|
+
return indexMap;
|
|
2858
|
+
}
|
|
2859
|
+
function mapChannelPathToProperty(path) {
|
|
2860
|
+
if (typeof path !== "string") {
|
|
2861
|
+
return void 0;
|
|
2862
|
+
}
|
|
2863
|
+
return CHANNEL_PATH_TO_TRACK_PROPERTY[path] ?? path;
|
|
2864
|
+
}
|
|
2865
|
+
function resolveFeatureKey(channelTarget) {
|
|
2866
|
+
if (!channelTarget || typeof channelTarget !== "object") {
|
|
2867
|
+
return void 0;
|
|
2868
|
+
}
|
|
2869
|
+
const target = channelTarget;
|
|
2870
|
+
const extensions = target.extensions;
|
|
2871
|
+
if (extensions && typeof extensions === "object") {
|
|
2872
|
+
const vizij = extensions.VizijChannel;
|
|
2873
|
+
if (isPlainObject(vizij)) {
|
|
2874
|
+
const feature = vizij.feature;
|
|
2875
|
+
if (typeof feature === "string") {
|
|
2876
|
+
return feature;
|
|
2877
|
+
}
|
|
2878
|
+
}
|
|
2879
|
+
const robot = extensions.RobotChannel;
|
|
2880
|
+
if (isPlainObject(robot)) {
|
|
2881
|
+
const feature = robot.feature;
|
|
2882
|
+
if (typeof feature === "string") {
|
|
2883
|
+
return feature;
|
|
2884
|
+
}
|
|
2885
|
+
}
|
|
2886
|
+
}
|
|
2887
|
+
const extras = target.extras;
|
|
2888
|
+
if (isPlainObject(extras)) {
|
|
2889
|
+
const feature = extras.feature;
|
|
2890
|
+
if (typeof feature === "string") {
|
|
2891
|
+
return feature;
|
|
2892
|
+
}
|
|
2893
|
+
const channel = extras.channel;
|
|
2894
|
+
if (typeof channel === "string") {
|
|
2895
|
+
return channel;
|
|
2896
|
+
}
|
|
2897
|
+
}
|
|
2898
|
+
const path = target.path;
|
|
2899
|
+
return typeof path === "string" ? path : void 0;
|
|
2900
|
+
}
|
|
2901
|
+
function resolveTrackForChannel(clip, channelIndex, expectedProperty, nodeName) {
|
|
2902
|
+
if (!clip) {
|
|
2903
|
+
return void 0;
|
|
2904
|
+
}
|
|
2905
|
+
const orderedTrack = clip.tracks[channelIndex];
|
|
2906
|
+
if (orderedTrack) {
|
|
2907
|
+
return orderedTrack;
|
|
2908
|
+
}
|
|
2909
|
+
if (!expectedProperty) {
|
|
2910
|
+
return void 0;
|
|
2911
|
+
}
|
|
2912
|
+
const property = expectedProperty;
|
|
2913
|
+
const matches = (track) => {
|
|
2914
|
+
const name = track?.name ?? "";
|
|
2915
|
+
if (!name) {
|
|
2916
|
+
return false;
|
|
2917
|
+
}
|
|
2918
|
+
if (nodeName && name === `${nodeName}.${property}`) {
|
|
2919
|
+
return true;
|
|
2920
|
+
}
|
|
2921
|
+
if (nodeName && name.startsWith(`${nodeName}.`) && name.endsWith(property)) {
|
|
2922
|
+
return true;
|
|
2923
|
+
}
|
|
2924
|
+
if (!nodeName && name.endsWith(property)) {
|
|
2925
|
+
return true;
|
|
2926
|
+
}
|
|
2927
|
+
return false;
|
|
2928
|
+
};
|
|
2929
|
+
return clip.tracks.find(matches);
|
|
2930
|
+
}
|
|
2931
|
+
function toNumberArray(arrayLike) {
|
|
2932
|
+
if (!arrayLike) {
|
|
2933
|
+
return [];
|
|
2934
|
+
}
|
|
2935
|
+
return Array.from(arrayLike, (value) => Number(value));
|
|
2936
|
+
}
|
|
2937
|
+
function resolveClipDuration(clip, tracks) {
|
|
2938
|
+
if (clip && Number.isFinite(clip.duration) && clip.duration >= 0) {
|
|
2939
|
+
return clip.duration;
|
|
2940
|
+
}
|
|
2941
|
+
let maxTime = 0;
|
|
2942
|
+
tracks.forEach((track) => {
|
|
2943
|
+
if (!track.times.length) {
|
|
2944
|
+
return;
|
|
2945
|
+
}
|
|
2946
|
+
const lastTime = track.times[track.times.length - 1] ?? 0;
|
|
2947
|
+
if (lastTime > maxTime) {
|
|
2948
|
+
maxTime = lastTime;
|
|
2949
|
+
}
|
|
2950
|
+
});
|
|
2951
|
+
return maxTime;
|
|
2952
|
+
}
|
|
2953
|
+
function resolveClipId(animation, clip, index) {
|
|
2954
|
+
if (typeof animation.name === "string" && animation.name.length > 0) {
|
|
2955
|
+
return animation.name;
|
|
2956
|
+
}
|
|
2957
|
+
if (clip?.name && clip.name.length > 0) {
|
|
2958
|
+
return clip.name;
|
|
2959
|
+
}
|
|
2960
|
+
return `gltf-animation-${index}`;
|
|
2961
|
+
}
|
|
2962
|
+
function extractVizijAnimations(parserJson, clips) {
|
|
2963
|
+
const animations = [];
|
|
2964
|
+
if (!parserJson || typeof parserJson !== "object") {
|
|
2965
|
+
return animations;
|
|
2966
|
+
}
|
|
2967
|
+
const robotNodeIndex = resolveRobotNodeIndex(parserJson);
|
|
2968
|
+
if (robotNodeIndex.size === 0) {
|
|
2969
|
+
return animations;
|
|
2970
|
+
}
|
|
2971
|
+
const json = parserJson;
|
|
2972
|
+
const gltfAnimations = Array.isArray(json.animations) ? json.animations : [];
|
|
2973
|
+
if (gltfAnimations.length === 0) {
|
|
2974
|
+
return animations;
|
|
2975
|
+
}
|
|
2976
|
+
gltfAnimations.forEach((animation, animationIndex) => {
|
|
2977
|
+
if (!animation || typeof animation !== "object") {
|
|
2978
|
+
return;
|
|
2979
|
+
}
|
|
2980
|
+
const animationRecord = animation;
|
|
2981
|
+
const channels = Array.isArray(animationRecord.channels) ? animationRecord.channels : [];
|
|
2982
|
+
if (channels.length === 0) {
|
|
2983
|
+
return;
|
|
2984
|
+
}
|
|
2985
|
+
const samplers = Array.isArray(animationRecord.samplers) ? animationRecord.samplers : [];
|
|
2986
|
+
const clip = Array.isArray(clips) ? clips[animationIndex] : void 0;
|
|
2987
|
+
const trackData = [];
|
|
2988
|
+
channels.forEach((channel, channelIndex) => {
|
|
2989
|
+
if (!channel || typeof channel !== "object") {
|
|
2990
|
+
return;
|
|
2991
|
+
}
|
|
2992
|
+
const channelRecord = channel;
|
|
2993
|
+
const target = channelRecord.target;
|
|
2994
|
+
const nodeIndex = target && typeof target === "object" && typeof target.node === "number" ? target.node : void 0;
|
|
2995
|
+
if (nodeIndex == null || !robotNodeIndex.has(nodeIndex)) {
|
|
2996
|
+
return;
|
|
2997
|
+
}
|
|
2998
|
+
const robotNode = robotNodeIndex.get(nodeIndex);
|
|
2999
|
+
const featureKey = resolveFeatureKey(target);
|
|
3000
|
+
if (!featureKey) {
|
|
3001
|
+
return;
|
|
3002
|
+
}
|
|
3003
|
+
const featureInfo = robotNode.features[featureKey];
|
|
3004
|
+
if (!featureInfo) {
|
|
3005
|
+
return;
|
|
3006
|
+
}
|
|
3007
|
+
const propertyName = mapChannelPathToProperty(
|
|
3008
|
+
target && typeof target === "object" ? target.path : void 0
|
|
3009
|
+
);
|
|
3010
|
+
const track = resolveTrackForChannel(
|
|
3011
|
+
clip,
|
|
3012
|
+
channelIndex,
|
|
3013
|
+
propertyName,
|
|
3014
|
+
robotNode.nodeName
|
|
3015
|
+
);
|
|
3016
|
+
if (!track) {
|
|
3017
|
+
return;
|
|
3018
|
+
}
|
|
3019
|
+
const samplerIndex = typeof channelRecord.sampler === "number" ? channelRecord.sampler : -1;
|
|
3020
|
+
const sampler = samplerIndex >= 0 && samplerIndex < samplers.length ? samplers[samplerIndex] : void 0;
|
|
3021
|
+
const interpolation = sampler && typeof sampler.interpolation === "string" ? sampler.interpolation : void 0;
|
|
3022
|
+
let valueSize = typeof track.getValueSize === "function" ? track.getValueSize() : inferValueSize(featureInfo.valueType);
|
|
3023
|
+
if (!Number.isFinite(valueSize) || valueSize <= 0) {
|
|
3024
|
+
valueSize = inferValueSize(featureInfo.valueType);
|
|
3025
|
+
}
|
|
3026
|
+
const { component, componentIndex } = readComponentInfo(target);
|
|
3027
|
+
trackData.push({
|
|
3028
|
+
componentId: featureInfo.componentId,
|
|
3029
|
+
feature: featureInfo.feature,
|
|
3030
|
+
renderableId: robotNode.renderableId,
|
|
3031
|
+
nodeIndex,
|
|
3032
|
+
nodeName: robotNode.nodeName,
|
|
3033
|
+
path: target && typeof target === "object" && typeof target.path === "string" ? target.path : void 0,
|
|
3034
|
+
component,
|
|
3035
|
+
componentIndex,
|
|
3036
|
+
valueType: featureInfo.valueType,
|
|
3037
|
+
valueSize,
|
|
3038
|
+
interpolation,
|
|
3039
|
+
times: toNumberArray(track.times),
|
|
3040
|
+
values: toNumberArray(track.values)
|
|
3041
|
+
});
|
|
3042
|
+
});
|
|
3043
|
+
if (trackData.length === 0) {
|
|
3044
|
+
return;
|
|
3045
|
+
}
|
|
3046
|
+
animations.push({
|
|
3047
|
+
id: resolveClipId(animationRecord, clip, animationIndex),
|
|
3048
|
+
name: typeof animationRecord.name === "string" && animationRecord.name.length > 0 ? animationRecord.name : clip?.name,
|
|
3049
|
+
duration: resolveClipDuration(clip, trackData),
|
|
3050
|
+
index: animationIndex,
|
|
3051
|
+
metadata: clonePlainObject(
|
|
3052
|
+
animationRecord.extras
|
|
3053
|
+
),
|
|
3054
|
+
tracks: trackData
|
|
3055
|
+
});
|
|
3056
|
+
});
|
|
3057
|
+
return animations;
|
|
3058
|
+
}
|
|
3059
|
+
|
|
2677
3060
|
// src/functions/load-gltf.ts
|
|
2678
3061
|
THREE5.Object3D.DEFAULT_UP.set(0, 0, 1);
|
|
2679
3062
|
var EmptyModelError = class extends Error {
|
|
@@ -2692,9 +3075,10 @@ async function loadGLTF(url, namespaces, aggressiveImport = false, rootBounds) {
|
|
|
2692
3075
|
actualizedNamespaces,
|
|
2693
3076
|
aggressiveImport,
|
|
2694
3077
|
rootBounds,
|
|
2695
|
-
modelData?.parser?.json
|
|
3078
|
+
modelData?.parser?.json,
|
|
3079
|
+
modelData.animations
|
|
2696
3080
|
);
|
|
2697
|
-
return [asset.world, asset.animatables];
|
|
3081
|
+
return [asset.world, asset.animatables, asset.animations];
|
|
2698
3082
|
}
|
|
2699
3083
|
async function loadGLTFFromBlob(blob, namespaces, aggressiveImport = false, rootBounds) {
|
|
2700
3084
|
const actualizedNamespaces = namespaces.length > 0 ? namespaces : ["default"];
|
|
@@ -2707,7 +3091,7 @@ async function loadGLTFFromBlob(blob, namespaces, aggressiveImport = false, root
|
|
|
2707
3091
|
aggressiveImport,
|
|
2708
3092
|
rootBounds
|
|
2709
3093
|
);
|
|
2710
|
-
return [asset.world, asset.animatables];
|
|
3094
|
+
return [asset.world, asset.animatables, asset.animations];
|
|
2711
3095
|
} finally {
|
|
2712
3096
|
URL.revokeObjectURL(objectUrl);
|
|
2713
3097
|
}
|
|
@@ -2726,9 +3110,10 @@ async function loadGLTFFromBlob(blob, namespaces, aggressiveImport = false, root
|
|
|
2726
3110
|
actualizedNamespaces,
|
|
2727
3111
|
aggressiveImport,
|
|
2728
3112
|
rootBounds,
|
|
2729
|
-
gltf?.parser?.json
|
|
3113
|
+
gltf?.parser?.json,
|
|
3114
|
+
gltf.animations
|
|
2730
3115
|
);
|
|
2731
|
-
resolve([asset.world, asset.animatables]);
|
|
3116
|
+
resolve([asset.world, asset.animatables, asset.animations]);
|
|
2732
3117
|
} catch (error) {
|
|
2733
3118
|
if (error instanceof Error) {
|
|
2734
3119
|
reject(error);
|
|
@@ -2743,7 +3128,7 @@ async function loadGLTFFromBlob(blob, namespaces, aggressiveImport = false, root
|
|
|
2743
3128
|
);
|
|
2744
3129
|
});
|
|
2745
3130
|
}
|
|
2746
|
-
function parseScene(scene, namespaces, aggressiveImport, rootBounds, parserJson) {
|
|
3131
|
+
function parseScene(scene, namespaces, aggressiveImport, rootBounds, parserJson, clips) {
|
|
2747
3132
|
const [world, animatables] = traverseThree(
|
|
2748
3133
|
scene,
|
|
2749
3134
|
namespaces,
|
|
@@ -2751,7 +3136,8 @@ function parseScene(scene, namespaces, aggressiveImport, rootBounds, parserJson)
|
|
|
2751
3136
|
rootBounds
|
|
2752
3137
|
);
|
|
2753
3138
|
const bundle = extractVizijBundle(scene, parserJson);
|
|
2754
|
-
|
|
3139
|
+
const animations = extractVizijAnimations(parserJson, clips);
|
|
3140
|
+
return { world, animatables, bundle, animations };
|
|
2755
3141
|
}
|
|
2756
3142
|
async function loadGLTFWithBundle(url, namespaces, aggressiveImport = false, rootBounds) {
|
|
2757
3143
|
const modelLoader = new GLTFLoader();
|
|
@@ -2763,7 +3149,8 @@ async function loadGLTFWithBundle(url, namespaces, aggressiveImport = false, roo
|
|
|
2763
3149
|
actualizedNamespaces,
|
|
2764
3150
|
aggressiveImport,
|
|
2765
3151
|
rootBounds,
|
|
2766
|
-
modelData?.parser?.json
|
|
3152
|
+
modelData?.parser?.json,
|
|
3153
|
+
modelData.animations
|
|
2767
3154
|
);
|
|
2768
3155
|
}
|
|
2769
3156
|
async function loadGLTFFromBlobWithBundle(blob, namespaces, aggressiveImport = false, rootBounds) {
|
|
@@ -2795,7 +3182,8 @@ async function loadGLTFFromBlobWithBundle(blob, namespaces, aggressiveImport = f
|
|
|
2795
3182
|
actualizedNamespaces,
|
|
2796
3183
|
aggressiveImport,
|
|
2797
3184
|
rootBounds,
|
|
2798
|
-
gltf?.parser?.json
|
|
3185
|
+
gltf?.parser?.json,
|
|
3186
|
+
gltf.animations
|
|
2799
3187
|
);
|
|
2800
3188
|
resolve(asset);
|
|
2801
3189
|
} catch (error) {
|
package/package.json
CHANGED