@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 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 remain available if you do not need bundle metadata.
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
- return { world, animatables, bundle };
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 { Object3D as Object3D4 } from "three";
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
- return { world, animatables, bundle };
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
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@vizij/render",
3
3
  "description": "Higher-level visualization and interaction components for robot and ai faces.",
4
- "version": "0.0.4",
4
+ "version": "0.0.6",
5
5
  "main": "dist/index.js",
6
6
  "module": "dist/index.mjs",
7
7
  "types": "dist/index.d.ts",