@zephyr3d/editor 0.3.5 → 0.3.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/assets/{index-DlnbO59X.js → index-ySiLtSxz.js} +2 -2
- package/dist/assistant/zephyr-types-index.json +14215 -7892
- package/dist/index.html +1 -1
- package/dist/modules/zephyr3d_backend-webgl.js.map +1 -1
- package/dist/modules/zephyr3d_backend-webgpu.js.map +1 -1
- package/dist/modules/zephyr3d_base.js +152 -152
- package/dist/modules/zephyr3d_base.js.map +1 -1
- package/dist/modules/zephyr3d_imgui.js.map +1 -1
- package/dist/modules/zephyr3d_loaders.js +6 -6
- package/dist/modules/zephyr3d_loaders.js.map +1 -1
- package/dist/modules/zephyr3d_scene.js +2538 -348
- package/dist/modules/zephyr3d_scene.js.map +1 -1
- package/dist/vendor/zephyr3d/backend-webgl/dist/index.js.map +1 -1
- package/dist/vendor/zephyr3d/backend-webgpu/dist/index.js.map +1 -1
- package/dist/vendor/zephyr3d/base/dist/vfs/common.js +152 -152
- package/dist/vendor/zephyr3d/base/dist/vfs/common.js.map +1 -1
- package/dist/vendor/zephyr3d/imgui/dist/index.d.ts +7 -0
- package/dist/vendor/zephyr3d/imgui/dist/index.js.map +1 -1
- package/dist/vendor/zephyr3d/loaders/dist/gltf/gltf_importer.js +6 -6
- package/dist/vendor/zephyr3d/loaders/dist/gltf/gltf_importer.js.map +1 -1
- package/dist/vendor/zephyr3d/scene/dist/animation/animation.js +87 -0
- package/dist/vendor/zephyr3d/scene/dist/animation/animation.js.map +1 -1
- package/dist/vendor/zephyr3d/scene/dist/animation/animationcontroller.js +503 -0
- package/dist/vendor/zephyr3d/scene/dist/animation/animationcontroller.js.map +1 -0
- package/dist/vendor/zephyr3d/scene/dist/animation/animationset.js +782 -156
- package/dist/vendor/zephyr3d/scene/dist/animation/animationset.js.map +1 -1
- package/dist/vendor/zephyr3d/scene/dist/animation/animationtimeline.js +974 -0
- package/dist/vendor/zephyr3d/scene/dist/animation/animationtimeline.js.map +1 -0
- package/dist/vendor/zephyr3d/scene/dist/animation/joint_dynamics/convex_collider.js +320 -0
- package/dist/vendor/zephyr3d/scene/dist/animation/joint_dynamics/convex_collider.js.map +1 -0
- package/dist/vendor/zephyr3d/scene/dist/app/scriptregistry.js +130 -125
- package/dist/vendor/zephyr3d/scene/dist/app/scriptregistry.js.map +1 -1
- package/dist/vendor/zephyr3d/scene/dist/asset/model.js +64 -63
- package/dist/vendor/zephyr3d/scene/dist/asset/model.js.map +1 -1
- package/dist/vendor/zephyr3d/scene/dist/index.d.ts +1270 -9
- package/dist/vendor/zephyr3d/scene/dist/index.js +3 -1
- package/dist/vendor/zephyr3d/scene/dist/index.js.map +1 -1
- package/dist/vendor/zephyr3d/scene/dist/material/mixins/lit.js +7 -3
- package/dist/vendor/zephyr3d/scene/dist/material/mixins/lit.js.map +1 -1
- package/dist/vendor/zephyr3d/scene/dist/utility/serialization/manager.js +1 -0
- package/dist/vendor/zephyr3d/scene/dist/utility/serialization/manager.js.map +1 -1
- package/dist/vendor/zephyr3d/scene/dist/utility/serialization/scene/animation.js +4 -3
- package/dist/vendor/zephyr3d/scene/dist/utility/serialization/scene/animation.js.map +1 -1
- package/dist/vendor/zephyr3d/scene/dist/utility/serialization/scene/camera.js +1 -1
- package/dist/vendor/zephyr3d/scene/dist/utility/serialization/scene/camera.js.map +1 -1
- package/dist/vendor/zephyr3d/scene/dist/utility/serialization/scene/node.js +3 -2
- package/dist/vendor/zephyr3d/scene/dist/utility/serialization/scene/node.js.map +1 -1
- package/package.json +8 -8
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Disposable, makeObservable, releaseObject, retainObject, Vector4, Vector3, DRef, AABB, Frustum, ClipState, Interpolator, Quaternion, randomUUID, DWeakRef, Matrix4x4, nextPowerOf2, weightedAverage, ObservableVector3, ObservableQuaternion, ASSERT, Ray, Vector2, applyMixins, float2half,
|
|
1
|
+
import { Disposable, makeObservable, releaseObject, retainObject, Vector4, Vector3, DRef, AABB, Frustum, ClipState, Interpolator, Quaternion, randomUUID, DWeakRef, Matrix4x4, nextPowerOf2, Observable, weightedAverage, ObservableVector3, ObservableQuaternion, ASSERT, Ray, Vector2, applyMixins, float2half, objectKeys, halton23, CubeFace, ObservableVector4, castObservable, radian2degree, degree2radian, uint8ArrayToBase64, base64ToUint8Array, mimeTypeOf, clamp01 as clamp01$1, smoothStep, InterpolatorScalar, applyPatch, guessMimeType, diff, PRNG, splitStringByGraphemes, packFloat3, isPowerOf2, clamp as clamp$1, Matrix3x3, PathUtils, textToBase64, HttpFS, MemoryFS, objectEntries, flushPendingDisposals } from '@zephyr3d/base';
|
|
2
2
|
import { PBPrimitiveType, matchVertexBuffer, PBInsideFunctionScope, ProgramBuilder, PBShaderExp, isFloatTextureFormat, getVertexAttributeIndex, VERTEX_ATTRIB_POSITION, VERTEX_ATTRIB_TEXCOORD0, getVertexAttributeFormat, hasDepthChannel, PBStructTypeInfo, PBArrayTypeInfo, PBPrimitiveTypeInfo, getVertexFormatComponentCount, TextureAtlasManager } from '@zephyr3d/device';
|
|
3
3
|
|
|
4
4
|
/** @internal */ let appInstance;
|
|
@@ -2645,6 +2645,8 @@ const debugFrameBuffer = {};
|
|
|
2645
2645
|
/** @internal */ _tracks;
|
|
2646
2646
|
_weight;
|
|
2647
2647
|
/** @internal */ _skeletons;
|
|
2648
|
+
/** @internal */ _frameRate;
|
|
2649
|
+
/** @internal */ _markers;
|
|
2648
2650
|
/**
|
|
2649
2651
|
* Creates an animation instance
|
|
2650
2652
|
* @param name - Name of the animation
|
|
@@ -2659,6 +2661,8 @@ const debugFrameBuffer = {};
|
|
|
2659
2661
|
this._weight = 1;
|
|
2660
2662
|
this._autoPlay = false;
|
|
2661
2663
|
this._skeletons = new Set();
|
|
2664
|
+
this._frameRate = 30;
|
|
2665
|
+
this._markers = [];
|
|
2662
2666
|
}
|
|
2663
2667
|
/**
|
|
2664
2668
|
* Whether this clip is embedded (owned inline by its container/resource).
|
|
@@ -2709,6 +2713,21 @@ const debugFrameBuffer = {};
|
|
|
2709
2713
|
this._skeletons = val;
|
|
2710
2714
|
}
|
|
2711
2715
|
/**
|
|
2716
|
+
* Default frame rate used to convert frame-based marker references.
|
|
2717
|
+
*/ get frameRate() {
|
|
2718
|
+
return this._frameRate;
|
|
2719
|
+
}
|
|
2720
|
+
set frameRate(val) {
|
|
2721
|
+
if (Number.isFinite(val) && val > 0) {
|
|
2722
|
+
this._frameRate = val;
|
|
2723
|
+
}
|
|
2724
|
+
}
|
|
2725
|
+
/**
|
|
2726
|
+
* Timeline markers stored on this clip.
|
|
2727
|
+
*/ get markers() {
|
|
2728
|
+
return this._markers;
|
|
2729
|
+
}
|
|
2730
|
+
/**
|
|
2712
2731
|
* Total time span of the clip in seconds.
|
|
2713
2732
|
*
|
|
2714
2733
|
* Automatically extended when adding tracks with longer duration.
|
|
@@ -2719,6 +2738,74 @@ const debugFrameBuffer = {};
|
|
|
2719
2738
|
this._duration = val;
|
|
2720
2739
|
}
|
|
2721
2740
|
/**
|
|
2741
|
+
* Add a serializable marker to this clip.
|
|
2742
|
+
*
|
|
2743
|
+
* @param marker - Marker metadata. If `id` is omitted, `name` is used as the id.
|
|
2744
|
+
* @returns The normalized marker.
|
|
2745
|
+
*/ addMarker(marker) {
|
|
2746
|
+
if (!marker?.name) {
|
|
2747
|
+
console.error('Animation marker must have a name');
|
|
2748
|
+
return null;
|
|
2749
|
+
}
|
|
2750
|
+
const normalized = {
|
|
2751
|
+
...marker,
|
|
2752
|
+
id: marker.id || marker.name
|
|
2753
|
+
};
|
|
2754
|
+
if (this.resolveMarkerTime(normalized) === null) {
|
|
2755
|
+
console.error('Animation marker must have either time or frame');
|
|
2756
|
+
return null;
|
|
2757
|
+
}
|
|
2758
|
+
this._markers.push(normalized);
|
|
2759
|
+
this._markers.sort((a, b)=>(this.resolveMarkerTime(a) ?? 0) - (this.resolveMarkerTime(b) ?? 0));
|
|
2760
|
+
return normalized;
|
|
2761
|
+
}
|
|
2762
|
+
/**
|
|
2763
|
+
* Remove markers matching the marker id or name.
|
|
2764
|
+
*/ removeMarker(idOrName) {
|
|
2765
|
+
const oldLength = this._markers.length;
|
|
2766
|
+
this._markers = this._markers.filter((marker)=>marker.id !== idOrName && marker.name !== idOrName);
|
|
2767
|
+
return this._markers.length !== oldLength;
|
|
2768
|
+
}
|
|
2769
|
+
/**
|
|
2770
|
+
* Get the first marker matching the marker id or name.
|
|
2771
|
+
*/ getMarker(idOrName) {
|
|
2772
|
+
return this._markers.find((marker)=>marker.id === idOrName || marker.name === idOrName) ?? null;
|
|
2773
|
+
}
|
|
2774
|
+
/**
|
|
2775
|
+
* Resolve a marker to seconds on this clip's timeline.
|
|
2776
|
+
*/ resolveMarkerTime(marker) {
|
|
2777
|
+
if (typeof marker.time === 'number' && Number.isFinite(marker.time)) {
|
|
2778
|
+
return marker.time;
|
|
2779
|
+
}
|
|
2780
|
+
if (typeof marker.frame === 'number' && Number.isFinite(marker.frame)) {
|
|
2781
|
+
const fps = marker.fps ?? this._frameRate;
|
|
2782
|
+
return fps > 0 ? marker.frame / fps : null;
|
|
2783
|
+
}
|
|
2784
|
+
return null;
|
|
2785
|
+
}
|
|
2786
|
+
/**
|
|
2787
|
+
* Resolve a time reference to seconds on this clip's timeline.
|
|
2788
|
+
*/ resolveTimeRef(ref) {
|
|
2789
|
+
if (ref === null || ref === undefined) {
|
|
2790
|
+
return null;
|
|
2791
|
+
}
|
|
2792
|
+
if (typeof ref === 'number') {
|
|
2793
|
+
return Number.isFinite(ref) ? ref : null;
|
|
2794
|
+
}
|
|
2795
|
+
if ('time' in ref) {
|
|
2796
|
+
return Number.isFinite(ref.time) ? ref.time : null;
|
|
2797
|
+
}
|
|
2798
|
+
if ('frame' in ref) {
|
|
2799
|
+
const fps = ref.fps ?? this._frameRate;
|
|
2800
|
+
return Number.isFinite(ref.frame) && fps > 0 ? ref.frame / fps : null;
|
|
2801
|
+
}
|
|
2802
|
+
if ('marker' in ref) {
|
|
2803
|
+
const marker = this.getMarker(ref.marker);
|
|
2804
|
+
return marker ? this.resolveMarkerTime(marker) : null;
|
|
2805
|
+
}
|
|
2806
|
+
return null;
|
|
2807
|
+
}
|
|
2808
|
+
/**
|
|
2722
2809
|
* Add a skeleton used by this clip.
|
|
2723
2810
|
*
|
|
2724
2811
|
* @param skeletonId - Persistent ID of Skeleton to register for this clip.
|
|
@@ -5756,6 +5843,224 @@ function copySkeletonReferences(sourceClip, targetClip) {
|
|
|
5756
5843
|
return targetClip;
|
|
5757
5844
|
}
|
|
5758
5845
|
|
|
5846
|
+
let nextAnimationPlaybackId = 1;
|
|
5847
|
+
/**
|
|
5848
|
+
* Runtime handle for one playback of an AnimationClip.
|
|
5849
|
+
* @public
|
|
5850
|
+
*/ class AnimationPlayback extends Observable {
|
|
5851
|
+
/** @internal */ _animationSet;
|
|
5852
|
+
/** @internal */ _clip;
|
|
5853
|
+
/** @internal */ _options;
|
|
5854
|
+
/** @internal */ _id;
|
|
5855
|
+
/** @internal */ _frameWaiters;
|
|
5856
|
+
/** @internal */ _state;
|
|
5857
|
+
/** @internal */ _time;
|
|
5858
|
+
/** @internal */ _weight;
|
|
5859
|
+
/** @internal */ _speedRatio;
|
|
5860
|
+
/** @internal */ _layer;
|
|
5861
|
+
/** @internal */ _priority;
|
|
5862
|
+
/** @internal */ _interruptible;
|
|
5863
|
+
constructor(animationSet, clip, options){
|
|
5864
|
+
super();
|
|
5865
|
+
this._animationSet = animationSet;
|
|
5866
|
+
this._clip = clip;
|
|
5867
|
+
this._options = {
|
|
5868
|
+
...options ?? {}
|
|
5869
|
+
};
|
|
5870
|
+
this._id = this._options.id ?? `animation-playback-${nextAnimationPlaybackId++}`;
|
|
5871
|
+
this._state = 'scheduled';
|
|
5872
|
+
this._speedRatio = this._options.speedRatio ?? 1;
|
|
5873
|
+
this._weight = this._options.weight ?? clip.weight ?? 1;
|
|
5874
|
+
this._time = this._speedRatio < 0 ? clip.timeDuration : 0;
|
|
5875
|
+
this._layer = this._options.layer ?? 'default';
|
|
5876
|
+
this._priority = this._options.priority ?? 0;
|
|
5877
|
+
this._interruptible = this._options.interruptible ?? true;
|
|
5878
|
+
this._frameWaiters = new Map();
|
|
5879
|
+
}
|
|
5880
|
+
get id() {
|
|
5881
|
+
return this._id;
|
|
5882
|
+
}
|
|
5883
|
+
get animationSet() {
|
|
5884
|
+
return this._animationSet;
|
|
5885
|
+
}
|
|
5886
|
+
get clip() {
|
|
5887
|
+
return this._clip;
|
|
5888
|
+
}
|
|
5889
|
+
get state() {
|
|
5890
|
+
return this._state;
|
|
5891
|
+
}
|
|
5892
|
+
get time() {
|
|
5893
|
+
return this._time;
|
|
5894
|
+
}
|
|
5895
|
+
set time(value) {
|
|
5896
|
+
this.seek(value);
|
|
5897
|
+
}
|
|
5898
|
+
get normalizedTime() {
|
|
5899
|
+
return this._clip.timeDuration > 0 ? this._time / this._clip.timeDuration : 0;
|
|
5900
|
+
}
|
|
5901
|
+
set normalizedTime(value) {
|
|
5902
|
+
this.seek(value * this._clip.timeDuration);
|
|
5903
|
+
}
|
|
5904
|
+
get weight() {
|
|
5905
|
+
return this._weight;
|
|
5906
|
+
}
|
|
5907
|
+
set weight(value) {
|
|
5908
|
+
this._animationSet.setPlaybackWeight(this, value);
|
|
5909
|
+
}
|
|
5910
|
+
get speedRatio() {
|
|
5911
|
+
return this._speedRatio;
|
|
5912
|
+
}
|
|
5913
|
+
set speedRatio(value) {
|
|
5914
|
+
this._animationSet.setPlaybackSpeedRatio(this, value);
|
|
5915
|
+
}
|
|
5916
|
+
get layer() {
|
|
5917
|
+
return this._layer;
|
|
5918
|
+
}
|
|
5919
|
+
get priority() {
|
|
5920
|
+
return this._priority;
|
|
5921
|
+
}
|
|
5922
|
+
get interruptible() {
|
|
5923
|
+
return this._interruptible;
|
|
5924
|
+
}
|
|
5925
|
+
play() {
|
|
5926
|
+
this._animationSet.startPlayback(this);
|
|
5927
|
+
return this;
|
|
5928
|
+
}
|
|
5929
|
+
pause() {
|
|
5930
|
+
this._animationSet.pausePlayback(this);
|
|
5931
|
+
return this;
|
|
5932
|
+
}
|
|
5933
|
+
resume() {
|
|
5934
|
+
this._animationSet.resumePlayback(this);
|
|
5935
|
+
return this;
|
|
5936
|
+
}
|
|
5937
|
+
stop(options) {
|
|
5938
|
+
this._animationSet.stopPlayback(this, options);
|
|
5939
|
+
return this;
|
|
5940
|
+
}
|
|
5941
|
+
seek(time, options) {
|
|
5942
|
+
this._animationSet.seekPlayback(this, time, options);
|
|
5943
|
+
return this;
|
|
5944
|
+
}
|
|
5945
|
+
fadeTo(weight, duration) {
|
|
5946
|
+
this._animationSet.fadePlaybackTo(this, weight, duration);
|
|
5947
|
+
return this;
|
|
5948
|
+
}
|
|
5949
|
+
crossFadeTo(name, options) {
|
|
5950
|
+
const duration = Math.max(options?.duration ?? 0, 0);
|
|
5951
|
+
this.stop({
|
|
5952
|
+
fadeOut: duration,
|
|
5953
|
+
reason: 'interrupted'
|
|
5954
|
+
});
|
|
5955
|
+
return this._animationSet.play(name, {
|
|
5956
|
+
...options,
|
|
5957
|
+
fadeIn: duration
|
|
5958
|
+
});
|
|
5959
|
+
}
|
|
5960
|
+
waitForComplete() {
|
|
5961
|
+
return new Promise((resolve)=>{
|
|
5962
|
+
this.once('complete', ()=>resolve(this));
|
|
5963
|
+
});
|
|
5964
|
+
}
|
|
5965
|
+
waitForMarker(idOrName) {
|
|
5966
|
+
if (this._state === 'stopped' || this._state === 'completed') {
|
|
5967
|
+
return Promise.resolve(undefined);
|
|
5968
|
+
}
|
|
5969
|
+
return new Promise((resolve)=>{
|
|
5970
|
+
const handler = (event)=>{
|
|
5971
|
+
if (event.marker.id === idOrName || event.marker.name === idOrName) {
|
|
5972
|
+
this.off('marker', handler);
|
|
5973
|
+
this.off('stop', stop);
|
|
5974
|
+
resolve(event);
|
|
5975
|
+
}
|
|
5976
|
+
};
|
|
5977
|
+
const stop = ()=>{
|
|
5978
|
+
this.off('marker', handler);
|
|
5979
|
+
this.off('stop', stop);
|
|
5980
|
+
resolve(undefined);
|
|
5981
|
+
};
|
|
5982
|
+
this.on('marker', handler);
|
|
5983
|
+
this.on('stop', stop);
|
|
5984
|
+
});
|
|
5985
|
+
}
|
|
5986
|
+
waitForFrame(frame) {
|
|
5987
|
+
if (this._state === 'stopped' || this._state === 'completed') {
|
|
5988
|
+
return Promise.resolve(undefined);
|
|
5989
|
+
}
|
|
5990
|
+
return new Promise((resolve)=>{
|
|
5991
|
+
const waiters = this._frameWaiters.get(frame) ?? [];
|
|
5992
|
+
let settled = false;
|
|
5993
|
+
let stop;
|
|
5994
|
+
const wrappedResolve = (event)=>{
|
|
5995
|
+
if (settled) {
|
|
5996
|
+
return;
|
|
5997
|
+
}
|
|
5998
|
+
settled = true;
|
|
5999
|
+
this.off('stop', stop);
|
|
6000
|
+
resolve(event);
|
|
6001
|
+
};
|
|
6002
|
+
stop = ()=>{
|
|
6003
|
+
const current = this._frameWaiters.get(frame);
|
|
6004
|
+
if (current) {
|
|
6005
|
+
this._frameWaiters.set(frame, current.filter((item)=>item !== wrappedResolve));
|
|
6006
|
+
}
|
|
6007
|
+
wrappedResolve(undefined);
|
|
6008
|
+
};
|
|
6009
|
+
waiters.push(wrappedResolve);
|
|
6010
|
+
this._frameWaiters.set(frame, waiters);
|
|
6011
|
+
this.on('stop', stop);
|
|
6012
|
+
});
|
|
6013
|
+
}
|
|
6014
|
+
/** @internal */ _getOptions() {
|
|
6015
|
+
return this._options;
|
|
6016
|
+
}
|
|
6017
|
+
/** @internal */ _setState(state) {
|
|
6018
|
+
this._state = state;
|
|
6019
|
+
}
|
|
6020
|
+
/** @internal */ _setTime(time) {
|
|
6021
|
+
this._time = time;
|
|
6022
|
+
}
|
|
6023
|
+
/** @internal */ _setWeight(weight) {
|
|
6024
|
+
this._weight = weight;
|
|
6025
|
+
}
|
|
6026
|
+
/** @internal */ _setSpeedRatio(speedRatio) {
|
|
6027
|
+
this._speedRatio = speedRatio;
|
|
6028
|
+
}
|
|
6029
|
+
/** @internal */ _getWatchedFrames() {
|
|
6030
|
+
return [
|
|
6031
|
+
...this._frameWaiters.keys()
|
|
6032
|
+
];
|
|
6033
|
+
}
|
|
6034
|
+
/** @internal */ _emitStart(event) {
|
|
6035
|
+
this.dispatchEvent('start', event);
|
|
6036
|
+
}
|
|
6037
|
+
/** @internal */ _emitLoop(event) {
|
|
6038
|
+
this.dispatchEvent('loop', event);
|
|
6039
|
+
}
|
|
6040
|
+
/** @internal */ _emitMarker(event) {
|
|
6041
|
+
this.dispatchEvent('marker', event);
|
|
6042
|
+
}
|
|
6043
|
+
/** @internal */ _emitFrame(event) {
|
|
6044
|
+
this.dispatchEvent('frame', event);
|
|
6045
|
+
const waiters = this._frameWaiters.get(event.frame);
|
|
6046
|
+
if (waiters) {
|
|
6047
|
+
this._frameWaiters.delete(event.frame);
|
|
6048
|
+
waiters.forEach((resolve)=>resolve(event));
|
|
6049
|
+
}
|
|
6050
|
+
}
|
|
6051
|
+
/** @internal */ _emitComplete(event) {
|
|
6052
|
+
this.dispatchEvent('complete', event);
|
|
6053
|
+
}
|
|
6054
|
+
/** @internal */ _emitStop(event) {
|
|
6055
|
+
this.dispatchEvent('stop', event);
|
|
6056
|
+
}
|
|
6057
|
+
/** @internal */ _emitPause(event) {
|
|
6058
|
+
this.dispatchEvent('pause', event);
|
|
6059
|
+
}
|
|
6060
|
+
/** @internal */ _emitResume(event) {
|
|
6061
|
+
this.dispatchEvent('resume', event);
|
|
6062
|
+
}
|
|
6063
|
+
}
|
|
5759
6064
|
function cloneInterpolator(src) {
|
|
5760
6065
|
return new Interpolator(src.mode, src.target, src.inputs instanceof Float32Array ? new Float32Array(src.inputs) : [
|
|
5761
6066
|
...src.inputs
|
|
@@ -6137,26 +6442,26 @@ function bakeHumanoidRotationTracks(sourceClip, srcSkeleton, dstSkeleton, srcRoo
|
|
|
6137
6442
|
dstClip.addTrack(remap.dstNode, track);
|
|
6138
6443
|
}
|
|
6139
6444
|
}
|
|
6140
|
-
/**
|
|
6141
|
-
* Animation set
|
|
6142
|
-
*
|
|
6143
|
-
* Manages a collection of named animation clips for a model and orchestrates:
|
|
6144
|
-
* - Playback state (time, loops, speed, weights, fade-in/out).
|
|
6145
|
-
* - Blending across multiple tracks targeting the same property via weighted averages.
|
|
6146
|
-
* - Skeleton usage and application for clips that drive skeletal animation.
|
|
6147
|
-
* - Active track registration and cleanup as clips start/stop.
|
|
6148
|
-
*
|
|
6149
|
-
* Usage:
|
|
6150
|
-
* - Create or retrieve `AnimationClip`s by name.
|
|
6151
|
-
* - Start playback with `playAnimation(name, options)`.
|
|
6152
|
-
* - Advance animation with `update(deltaSeconds)`.
|
|
6153
|
-
* - Optionally adjust weight while playing with `setAnimationWeight(name, weight)`.
|
|
6154
|
-
*
|
|
6155
|
-
* Lifetime:
|
|
6156
|
-
* - Disposing the set releases references to the model, clips, and clears active state.
|
|
6157
|
-
*
|
|
6158
|
-
* @public
|
|
6159
|
-
*/ class AnimationSet extends Disposable {
|
|
6445
|
+
/**
|
|
6446
|
+
* Animation set
|
|
6447
|
+
*
|
|
6448
|
+
* Manages a collection of named animation clips for a model and orchestrates:
|
|
6449
|
+
* - Playback state (time, loops, speed, weights, fade-in/out).
|
|
6450
|
+
* - Blending across multiple tracks targeting the same property via weighted averages.
|
|
6451
|
+
* - Skeleton usage and application for clips that drive skeletal animation.
|
|
6452
|
+
* - Active track registration and cleanup as clips start/stop.
|
|
6453
|
+
*
|
|
6454
|
+
* Usage:
|
|
6455
|
+
* - Create or retrieve `AnimationClip`s by name.
|
|
6456
|
+
* - Start playback with `playAnimation(name, options)`.
|
|
6457
|
+
* - Advance animation with `update(deltaSeconds)`.
|
|
6458
|
+
* - Optionally adjust weight while playing with `setAnimationWeight(name, weight)`.
|
|
6459
|
+
*
|
|
6460
|
+
* Lifetime:
|
|
6461
|
+
* - Disposing the set releases references to the model, clips, and clears active state.
|
|
6462
|
+
*
|
|
6463
|
+
* @public
|
|
6464
|
+
*/ class AnimationSet extends makeObservable(Disposable)() {
|
|
6160
6465
|
/** @internal */ _model;
|
|
6161
6466
|
/** @internal */ _animations;
|
|
6162
6467
|
/** @internal */ _skeletons;
|
|
@@ -6165,10 +6470,18 @@ function bakeHumanoidRotationTracks(sourceClip, srcSkeleton, dstSkeleton, srcRoo
|
|
|
6165
6470
|
/** @internal */ _activeSkinBindings;
|
|
6166
6471
|
/** @internal */ _activeRigs;
|
|
6167
6472
|
/** @internal */ _activeAnimations;
|
|
6168
|
-
/**
|
|
6169
|
-
*
|
|
6170
|
-
*
|
|
6171
|
-
*
|
|
6473
|
+
/**
|
|
6474
|
+
* Callbacks driven by the same logical clock as the animations (see {@link update}).
|
|
6475
|
+
*
|
|
6476
|
+
* Used by higher-level constructs (e.g. timeline runners) that need to advance
|
|
6477
|
+
* wall-clock-independent timers in sync with playback, so they pause/scale with the
|
|
6478
|
+
* game clock instead of running on real time.
|
|
6479
|
+
* @internal
|
|
6480
|
+
*/ _timelineTickers;
|
|
6481
|
+
/**
|
|
6482
|
+
* Create an AnimationSet controlling the provided model.
|
|
6483
|
+
*
|
|
6484
|
+
* @param model - The SceneNode (model root) controlled by this animation set.
|
|
6172
6485
|
*/ constructor(model){
|
|
6173
6486
|
super();
|
|
6174
6487
|
this._model = model;
|
|
@@ -6179,29 +6492,42 @@ function bakeHumanoidRotationTracks(sourceClip, srcSkeleton, dstSkeleton, srcRoo
|
|
|
6179
6492
|
this._activeAnimations = new Map();
|
|
6180
6493
|
this._skeletons = [];
|
|
6181
6494
|
this._rigs = [];
|
|
6495
|
+
this._timelineTickers = new Set();
|
|
6182
6496
|
}
|
|
6183
|
-
/**
|
|
6184
|
-
*
|
|
6497
|
+
/**
|
|
6498
|
+
* Register a callback advanced by {@link update} using the same delta time as the animations.
|
|
6499
|
+
* @internal
|
|
6500
|
+
*/ _registerTimelineTicker(ticker) {
|
|
6501
|
+
this._timelineTickers.add(ticker);
|
|
6502
|
+
}
|
|
6503
|
+
/**
|
|
6504
|
+
* Unregister a callback previously registered with {@link _registerTimelineTicker}.
|
|
6505
|
+
* @internal
|
|
6506
|
+
*/ _unregisterTimelineTicker(ticker) {
|
|
6507
|
+
this._timelineTickers.delete(ticker);
|
|
6508
|
+
}
|
|
6509
|
+
/**
|
|
6510
|
+
* The model (SceneNode) controlled by this animation set.
|
|
6185
6511
|
*/ get model() {
|
|
6186
6512
|
return this._model;
|
|
6187
6513
|
}
|
|
6188
|
-
/**
|
|
6189
|
-
* Number of animation clips registered in this set.
|
|
6514
|
+
/**
|
|
6515
|
+
* Number of animation clips registered in this set.
|
|
6190
6516
|
*/ get numAnimations() {
|
|
6191
6517
|
return Object.getOwnPropertyNames(this._animations).length;
|
|
6192
6518
|
}
|
|
6193
|
-
/**
|
|
6194
|
-
* The skeletons used by animations in this set.
|
|
6519
|
+
/**
|
|
6520
|
+
* The skeletons used by animations in this set.
|
|
6195
6521
|
*/ get skeletons() {
|
|
6196
6522
|
return this._skeletons;
|
|
6197
6523
|
}
|
|
6198
|
-
/**
|
|
6199
|
-
* The shared rigs used by animations in this set.
|
|
6524
|
+
/**
|
|
6525
|
+
* The shared rigs used by animations in this set.
|
|
6200
6526
|
*/ get rigs() {
|
|
6201
6527
|
return this._rigs;
|
|
6202
6528
|
}
|
|
6203
|
-
/**
|
|
6204
|
-
* Per-skin bindings used by skinned meshes in this set.
|
|
6529
|
+
/**
|
|
6530
|
+
* Per-skin bindings used by skinned meshes in this set.
|
|
6205
6531
|
*/ get skinBindings() {
|
|
6206
6532
|
return this._skeletons;
|
|
6207
6533
|
}
|
|
@@ -6223,20 +6549,20 @@ function bakeHumanoidRotationTracks(sourceClip, srcSkeleton, dstSkeleton, srcRoo
|
|
|
6223
6549
|
}
|
|
6224
6550
|
return rig;
|
|
6225
6551
|
}
|
|
6226
|
-
/**
|
|
6227
|
-
* Retrieve an animation clip by name.
|
|
6228
|
-
*
|
|
6229
|
-
* @param name - Name of the animation.
|
|
6230
|
-
* @returns The clip if present; otherwise null.
|
|
6552
|
+
/**
|
|
6553
|
+
* Retrieve an animation clip by name.
|
|
6554
|
+
*
|
|
6555
|
+
* @param name - Name of the animation.
|
|
6556
|
+
* @returns The clip if present; otherwise null.
|
|
6231
6557
|
*/ get(name) {
|
|
6232
6558
|
return this._animations[name] ?? null;
|
|
6233
6559
|
}
|
|
6234
|
-
/**
|
|
6235
|
-
* Create and register a new animation clip.
|
|
6236
|
-
*
|
|
6237
|
-
* @param name - Unique name for the animation clip.
|
|
6238
|
-
* @param embedded - Whether the clip is embedded/owned (implementation-specific). Default false.
|
|
6239
|
-
* @returns The created clip, or null if the name is empty or not unique.
|
|
6560
|
+
/**
|
|
6561
|
+
* Create and register a new animation clip.
|
|
6562
|
+
*
|
|
6563
|
+
* @param name - Unique name for the animation clip.
|
|
6564
|
+
* @param embedded - Whether the clip is embedded/owned (implementation-specific). Default false.
|
|
6565
|
+
* @returns The created clip, or null if the name is empty or not unique.
|
|
6240
6566
|
*/ createAnimation(name, embedded = false) {
|
|
6241
6567
|
if (!name || this._animations[name]) {
|
|
6242
6568
|
console.error('Animation must have unique name');
|
|
@@ -6248,12 +6574,12 @@ function bakeHumanoidRotationTracks(sourceClip, srcSkeleton, dstSkeleton, srcRoo
|
|
|
6248
6574
|
return animation;
|
|
6249
6575
|
}
|
|
6250
6576
|
}
|
|
6251
|
-
/**
|
|
6252
|
-
* Delete and dispose an animation clip by name.
|
|
6253
|
-
*
|
|
6254
|
-
* - If the animation is currently playing, it is first stopped (immediately).
|
|
6255
|
-
*
|
|
6256
|
-
* @param name - Name of the animation to remove.
|
|
6577
|
+
/**
|
|
6578
|
+
* Delete and dispose an animation clip by name.
|
|
6579
|
+
*
|
|
6580
|
+
* - If the animation is currently playing, it is first stopped (immediately).
|
|
6581
|
+
*
|
|
6582
|
+
* @param name - Name of the animation to remove.
|
|
6257
6583
|
*/ deleteAnimation(name) {
|
|
6258
6584
|
const animation = this._animations[name];
|
|
6259
6585
|
if (animation) {
|
|
@@ -6262,50 +6588,119 @@ function bakeHumanoidRotationTracks(sourceClip, srcSkeleton, dstSkeleton, srcRoo
|
|
|
6262
6588
|
animation.dispose();
|
|
6263
6589
|
}
|
|
6264
6590
|
}
|
|
6265
|
-
/**
|
|
6266
|
-
* Get the list of all registered animation names.
|
|
6267
|
-
*
|
|
6268
|
-
* @returns An array of clip names.
|
|
6591
|
+
/**
|
|
6592
|
+
* Get the list of all registered animation names.
|
|
6593
|
+
*
|
|
6594
|
+
* @returns An array of clip names.
|
|
6269
6595
|
*/ getAnimationNames() {
|
|
6270
6596
|
return Object.keys(this._animations);
|
|
6271
6597
|
}
|
|
6272
|
-
/**
|
|
6273
|
-
* Advance and apply active animations.
|
|
6274
|
-
*
|
|
6275
|
-
* Responsibilities per call:
|
|
6276
|
-
* - Update time cursor for each active clip (respecting speedRatio and looping).
|
|
6277
|
-
* - Enforce repeat limits and apply fade-out termination if configured.
|
|
6278
|
-
* - For each animated target, blend active tracks (weighted by clip weight × fade-in × fade-out)
|
|
6279
|
-
* and apply the resulting state to the target.
|
|
6280
|
-
* - Apply shared rig modifiers once, then update skin binding palettes.
|
|
6281
|
-
*
|
|
6282
|
-
* @param deltaInSeconds - Time step in seconds since last update.
|
|
6598
|
+
/**
|
|
6599
|
+
* Advance and apply active animations.
|
|
6600
|
+
*
|
|
6601
|
+
* Responsibilities per call:
|
|
6602
|
+
* - Update time cursor for each active clip (respecting speedRatio and looping).
|
|
6603
|
+
* - Enforce repeat limits and apply fade-out termination if configured.
|
|
6604
|
+
* - For each animated target, blend active tracks (weighted by clip weight × fade-in × fade-out)
|
|
6605
|
+
* and apply the resulting state to the target.
|
|
6606
|
+
* - Apply shared rig modifiers once, then update skin binding palettes.
|
|
6607
|
+
*
|
|
6608
|
+
* @param deltaInSeconds - Time step in seconds since last update.
|
|
6283
6609
|
*/ update(deltaInSeconds) {
|
|
6284
6610
|
this._activeAnimations.forEach((v, k)=>{
|
|
6611
|
+
if (!v.started) {
|
|
6612
|
+
v.started = true;
|
|
6613
|
+
const event = this.createPlaybackEvent(v, k);
|
|
6614
|
+
v.playback._emitStart(event);
|
|
6615
|
+
this.dispatchEvent('playbackstart', event);
|
|
6616
|
+
}
|
|
6617
|
+
if (v.paused) {
|
|
6618
|
+
return;
|
|
6619
|
+
}
|
|
6285
6620
|
if (v.fadeOut > 0 && v.fadeOutStart < 0) {
|
|
6286
6621
|
v.fadeOutStart = v.animateTime;
|
|
6287
6622
|
}
|
|
6623
|
+
if (v.completed) {
|
|
6624
|
+
v.animateTime += Math.abs(deltaInSeconds * v.speedRatio);
|
|
6625
|
+
if (v.fadeOut > 0 && v.animateTime - v.fadeOutStart >= v.fadeOut) {
|
|
6626
|
+
this.stopAnimation(k.name, {
|
|
6627
|
+
reason: v.stopReason
|
|
6628
|
+
});
|
|
6629
|
+
}
|
|
6630
|
+
return;
|
|
6631
|
+
}
|
|
6288
6632
|
// Update animation time
|
|
6289
6633
|
if (v.firstFrame) {
|
|
6290
6634
|
v.firstFrame = false;
|
|
6291
6635
|
} else {
|
|
6636
|
+
const previousTime = v.currentTime;
|
|
6292
6637
|
const timeAdvance = deltaInSeconds * v.speedRatio;
|
|
6293
6638
|
v.currentTime += timeAdvance;
|
|
6294
6639
|
v.animateTime += timeAdvance;
|
|
6640
|
+
const direction = timeAdvance >= 0 ? 1 : -1;
|
|
6295
6641
|
if (k.timeDuration > 0) {
|
|
6296
|
-
if (v.currentTime
|
|
6297
|
-
v.
|
|
6642
|
+
if (v.rangeEnd !== null && v.speedRatio >= 0 && v.currentTime >= v.rangeEnd) {
|
|
6643
|
+
v.currentTime = v.rangeEnd;
|
|
6644
|
+
v.playback._setTime(v.currentTime);
|
|
6645
|
+
this.completePlayback(k, v);
|
|
6646
|
+
return;
|
|
6647
|
+
} else if (v.rangeStart !== null && v.speedRatio < 0 && v.currentTime <= v.rangeStart) {
|
|
6648
|
+
v.currentTime = v.rangeStart;
|
|
6649
|
+
v.playback._setTime(v.currentTime);
|
|
6650
|
+
this.completePlayback(k, v);
|
|
6651
|
+
return;
|
|
6652
|
+
} else if (v.currentTime > k.timeDuration) {
|
|
6653
|
+
const loops = Math.max(1, Math.floor(v.currentTime / k.timeDuration));
|
|
6654
|
+
if (v.repeat !== 0 && v.repeatCounter + loops >= v.repeat) {
|
|
6655
|
+
v.repeatCounter += loops;
|
|
6656
|
+
v.currentTime = k.timeDuration;
|
|
6657
|
+
v.playback._setTime(v.currentTime);
|
|
6658
|
+
this.emitCrossedMarkers(v, k, previousTime, v.currentTime, direction);
|
|
6659
|
+
this.emitCrossedFrames(v, k, previousTime, v.currentTime, direction);
|
|
6660
|
+
this.completePlayback(k, v);
|
|
6661
|
+
return;
|
|
6662
|
+
}
|
|
6663
|
+
v.repeatCounter += loops;
|
|
6298
6664
|
v.currentTime %= k.timeDuration;
|
|
6665
|
+
const event = this.createPlaybackEvent(v, k);
|
|
6666
|
+
v.playback._emitLoop(event);
|
|
6667
|
+
this.dispatchEvent('playbackloop', event);
|
|
6299
6668
|
} else if (v.currentTime < 0) {
|
|
6300
|
-
|
|
6669
|
+
const loops = Math.max(1, Math.ceil(-v.currentTime / k.timeDuration));
|
|
6670
|
+
if (v.repeat !== 0 && v.repeatCounter + loops >= v.repeat) {
|
|
6671
|
+
v.repeatCounter += loops;
|
|
6672
|
+
v.currentTime = 0;
|
|
6673
|
+
v.playback._setTime(v.currentTime);
|
|
6674
|
+
this.emitCrossedMarkers(v, k, previousTime, v.currentTime, direction);
|
|
6675
|
+
this.emitCrossedFrames(v, k, previousTime, v.currentTime, direction);
|
|
6676
|
+
this.completePlayback(k, v);
|
|
6677
|
+
return;
|
|
6678
|
+
}
|
|
6679
|
+
v.repeatCounter += loops;
|
|
6301
6680
|
v.currentTime = (v.currentTime % k.timeDuration + k.timeDuration) % k.timeDuration;
|
|
6681
|
+
const event = this.createPlaybackEvent(v, k);
|
|
6682
|
+
v.playback._emitLoop(event);
|
|
6683
|
+
this.dispatchEvent('playbackloop', event);
|
|
6302
6684
|
}
|
|
6303
6685
|
}
|
|
6686
|
+
v.playback._setTime(v.currentTime);
|
|
6687
|
+
this.emitCrossedMarkers(v, k, previousTime, v.currentTime, direction);
|
|
6688
|
+
this.emitCrossedFrames(v, k, previousTime, v.currentTime, direction);
|
|
6304
6689
|
if (v.repeat !== 0 && v.repeatCounter >= v.repeat) {
|
|
6305
|
-
this.
|
|
6690
|
+
this.completePlayback(k, v);
|
|
6306
6691
|
} else if (v.fadeOut > 0) {
|
|
6307
6692
|
if (v.animateTime - v.fadeOutStart >= v.fadeOut) {
|
|
6308
|
-
this.stopAnimation(k.name
|
|
6693
|
+
this.stopAnimation(k.name, {
|
|
6694
|
+
reason: v.stopReason
|
|
6695
|
+
});
|
|
6696
|
+
}
|
|
6697
|
+
}
|
|
6698
|
+
if (v.fadeToDuration > 0) {
|
|
6699
|
+
const t = Math.min(1, (v.animateTime - v.fadeToStart) / v.fadeToDuration);
|
|
6700
|
+
v.weight = v.fadeFromWeight + (v.fadeTargetWeight - v.fadeFromWeight) * t;
|
|
6701
|
+
v.playback._setWeight(v.weight);
|
|
6702
|
+
if (t >= 1) {
|
|
6703
|
+
v.fadeToDuration = 0;
|
|
6309
6704
|
}
|
|
6310
6705
|
}
|
|
6311
6706
|
}
|
|
@@ -6345,12 +6740,17 @@ function bakeHumanoidRotationTracks(sourceClip, srcSkeleton, dstSkeleton, srcRoo
|
|
|
6345
6740
|
this._skeletons.forEach((v)=>{
|
|
6346
6741
|
v.get()?.apply();
|
|
6347
6742
|
});
|
|
6743
|
+
// Advance logical-clock timers (e.g. timeline `wait` steps) with the same delta time,
|
|
6744
|
+
// so they stay in sync with playback and pause/scale with the game clock.
|
|
6745
|
+
if (this._timelineTickers.size > 0) {
|
|
6746
|
+
this._timelineTickers.forEach((ticker)=>ticker(deltaInSeconds));
|
|
6747
|
+
}
|
|
6348
6748
|
}
|
|
6349
|
-
/**
|
|
6350
|
-
* Check whether an animation is currently playing.
|
|
6351
|
-
*
|
|
6352
|
-
* @param name - Optional animation name. If omitted, returns true if any animation is playing.
|
|
6353
|
-
* @returns True if playing; otherwise false.
|
|
6749
|
+
/**
|
|
6750
|
+
* Check whether an animation is currently playing.
|
|
6751
|
+
*
|
|
6752
|
+
* @param name - Optional animation name. If omitted, returns true if any animation is playing.
|
|
6753
|
+
* @returns True if playing; otherwise false.
|
|
6354
6754
|
*/ isPlayingAnimation(name) {
|
|
6355
6755
|
if (name) {
|
|
6356
6756
|
const animation = this._animations[name];
|
|
@@ -6358,23 +6758,23 @@ function bakeHumanoidRotationTracks(sourceClip, srcSkeleton, dstSkeleton, srcRoo
|
|
|
6358
6758
|
}
|
|
6359
6759
|
return this._activeAnimations.size > 0;
|
|
6360
6760
|
}
|
|
6361
|
-
/**
|
|
6362
|
-
* Get an animation clip by name.
|
|
6363
|
-
*
|
|
6364
|
-
* Alias of `get(name)` returning a nullable type.
|
|
6365
|
-
*
|
|
6366
|
-
* @param name - Name of the animation.
|
|
6367
|
-
* @returns The clip if present; otherwise null.
|
|
6761
|
+
/**
|
|
6762
|
+
* Get an animation clip by name.
|
|
6763
|
+
*
|
|
6764
|
+
* Alias of `get(name)` returning a nullable type.
|
|
6765
|
+
*
|
|
6766
|
+
* @param name - Name of the animation.
|
|
6767
|
+
* @returns The clip if present; otherwise null.
|
|
6368
6768
|
*/ getAnimationClip(name) {
|
|
6369
6769
|
return this._animations[name] ?? null;
|
|
6370
6770
|
}
|
|
6371
|
-
/**
|
|
6372
|
-
* Set the runtime blend weight for a currently playing animation.
|
|
6373
|
-
*
|
|
6374
|
-
* Has no effect if the clip is not active.
|
|
6375
|
-
*
|
|
6376
|
-
* @param name - Name of the playing animation.
|
|
6377
|
-
* @param weight - New weight value used during blending.
|
|
6771
|
+
/**
|
|
6772
|
+
* Set the runtime blend weight for a currently playing animation.
|
|
6773
|
+
*
|
|
6774
|
+
* Has no effect if the clip is not active.
|
|
6775
|
+
*
|
|
6776
|
+
* @param name - Name of the playing animation.
|
|
6777
|
+
* @param weight - New weight value used during blending.
|
|
6378
6778
|
*/ setAnimationWeight(name, weight) {
|
|
6379
6779
|
const ani = this._animations[name];
|
|
6380
6780
|
if (!ani) {
|
|
@@ -6384,42 +6784,104 @@ function bakeHumanoidRotationTracks(sourceClip, srcSkeleton, dstSkeleton, srcRoo
|
|
|
6384
6784
|
const info = this._activeAnimations.get(ani);
|
|
6385
6785
|
if (info) {
|
|
6386
6786
|
info.weight = weight;
|
|
6787
|
+
info.targetWeight = weight;
|
|
6788
|
+
info.playback._setWeight(weight);
|
|
6387
6789
|
}
|
|
6388
6790
|
}
|
|
6389
|
-
/**
|
|
6390
|
-
*
|
|
6391
|
-
|
|
6392
|
-
* Behavior:
|
|
6393
|
-
* - If the clip is already playing, stops it first.
|
|
6394
|
-
* - Otherwise initializes playback state (repeat counter, speed, weight, initial time).
|
|
6395
|
-
* - Registers clip tracks and skeletons into the active sets for blending and application.
|
|
6396
|
-
*
|
|
6397
|
-
* @param name - Name of the animation to play.
|
|
6398
|
-
* @param options - Playback options (repeat, speedRatio, fadeIn).
|
|
6399
|
-
*/ playAnimation(name, options) {
|
|
6791
|
+
/**
|
|
6792
|
+
* Create a playback handle without starting it.
|
|
6793
|
+
*/ createPlayback(name, options) {
|
|
6400
6794
|
const ani = this._animations[name];
|
|
6401
6795
|
if (!ani) {
|
|
6402
6796
|
console.error(`Animation ${name} not exists`);
|
|
6403
|
-
return;
|
|
6797
|
+
return null;
|
|
6404
6798
|
}
|
|
6405
|
-
|
|
6406
|
-
|
|
6799
|
+
return new AnimationPlayback(this, ani, options);
|
|
6800
|
+
}
|
|
6801
|
+
/**
|
|
6802
|
+
* Start an animation and return its playback handle.
|
|
6803
|
+
*/ play(name, options) {
|
|
6804
|
+
const playback = this.createPlayback(name, options);
|
|
6805
|
+
playback?.play();
|
|
6806
|
+
return playback;
|
|
6807
|
+
}
|
|
6808
|
+
/**
|
|
6809
|
+
* Get currently active playbacks.
|
|
6810
|
+
*/ getPlaybacks(name) {
|
|
6811
|
+
const playbacks = [];
|
|
6812
|
+
this._activeAnimations.forEach((info, clip)=>{
|
|
6813
|
+
if (!name || clip.name === name) {
|
|
6814
|
+
playbacks.push(info.playback);
|
|
6815
|
+
}
|
|
6816
|
+
});
|
|
6817
|
+
return playbacks;
|
|
6818
|
+
}
|
|
6819
|
+
/**
|
|
6820
|
+
* Get the currently active playback for a clip.
|
|
6821
|
+
*/ getPlayback(name) {
|
|
6822
|
+
const clip = this._animations[name];
|
|
6823
|
+
return clip ? this._activeAnimations.get(clip)?.playback ?? null : null;
|
|
6824
|
+
}
|
|
6825
|
+
/**
|
|
6826
|
+
* Start (or update) playback of an animation clip.
|
|
6827
|
+
*
|
|
6828
|
+
* Behavior:
|
|
6829
|
+
* - If the clip is already playing, stops it first.
|
|
6830
|
+
* - Otherwise initializes playback state (repeat counter, speed, weight, initial time).
|
|
6831
|
+
* - Registers clip tracks and skeletons into the active sets for blending and application.
|
|
6832
|
+
*
|
|
6833
|
+
* @param name - Name of the animation to play.
|
|
6834
|
+
* @param options - Playback options (repeat, speedRatio, fadeIn).
|
|
6835
|
+
*/ playAnimation(name, options) {
|
|
6836
|
+
this.play(name, options);
|
|
6837
|
+
}
|
|
6838
|
+
/**
|
|
6839
|
+
* Start a previously created playback.
|
|
6840
|
+
* @internal
|
|
6841
|
+
*/ startPlayback(playback) {
|
|
6842
|
+
const ani = playback.clip;
|
|
6843
|
+
if (!ani) {
|
|
6844
|
+
return;
|
|
6407
6845
|
}
|
|
6846
|
+
const options = playback._getOptions();
|
|
6408
6847
|
const fadeIn = Math.max(options?.fadeIn ?? 0, 0);
|
|
6409
6848
|
const repeat = options?.repeat ?? 0;
|
|
6410
|
-
const speedRatio =
|
|
6411
|
-
const weight =
|
|
6849
|
+
const speedRatio = playback.speedRatio;
|
|
6850
|
+
const weight = playback.weight;
|
|
6851
|
+
const rangeStart = ani.resolveTimeRef(options?.range?.start);
|
|
6852
|
+
const rangeEnd = ani.resolveTimeRef(options?.range?.end);
|
|
6853
|
+
const syncSource = this.resolvePlaybackSyncSource(options?.sync);
|
|
6854
|
+
const initialTime = this.computePlaybackInitialTime(ani, speedRatio, rangeStart, rangeEnd, options?.sync, syncSource);
|
|
6855
|
+
if (this.isPlayingAnimation(ani.name)) {
|
|
6856
|
+
this.stopAnimation(ani.name, {
|
|
6857
|
+
reason: 'replaced'
|
|
6858
|
+
});
|
|
6859
|
+
}
|
|
6860
|
+
playback._setState('playing');
|
|
6861
|
+
playback._setTime(initialTime);
|
|
6412
6862
|
this._activeAnimations.set(ani, {
|
|
6863
|
+
playback,
|
|
6413
6864
|
repeat,
|
|
6414
6865
|
weight,
|
|
6866
|
+
targetWeight: weight,
|
|
6415
6867
|
speedRatio,
|
|
6416
6868
|
fadeIn,
|
|
6417
6869
|
fadeOut: 0,
|
|
6418
6870
|
repeatCounter: 0,
|
|
6419
|
-
currentTime:
|
|
6871
|
+
currentTime: initialTime,
|
|
6420
6872
|
animateTime: 0,
|
|
6421
6873
|
fadeOutStart: 0,
|
|
6422
|
-
|
|
6874
|
+
fadeToStart: 0,
|
|
6875
|
+
fadeToDuration: 0,
|
|
6876
|
+
fadeFromWeight: weight,
|
|
6877
|
+
fadeTargetWeight: weight,
|
|
6878
|
+
firstFrame: true,
|
|
6879
|
+
started: false,
|
|
6880
|
+
paused: false,
|
|
6881
|
+
stopReason: 'manual',
|
|
6882
|
+
completed: false,
|
|
6883
|
+
rangeStart,
|
|
6884
|
+
rangeEnd
|
|
6423
6885
|
});
|
|
6424
6886
|
ani.tracks?.forEach((v, k)=>{
|
|
6425
6887
|
let nodeTracks = this._activeTracks.get(k);
|
|
@@ -6456,18 +6918,257 @@ function bakeHumanoidRotationTracks(sourceClip, srcSkeleton, dstSkeleton, srcRoo
|
|
|
6456
6918
|
}
|
|
6457
6919
|
});
|
|
6458
6920
|
}
|
|
6459
|
-
|
|
6460
|
-
|
|
6461
|
-
|
|
6462
|
-
|
|
6463
|
-
|
|
6464
|
-
|
|
6465
|
-
|
|
6466
|
-
|
|
6467
|
-
|
|
6468
|
-
|
|
6469
|
-
|
|
6470
|
-
|
|
6921
|
+
resolvePlaybackSyncSource(sync) {
|
|
6922
|
+
if (!sync?.target) {
|
|
6923
|
+
return null;
|
|
6924
|
+
}
|
|
6925
|
+
const playback = this.resolveActivePlayback(sync.target);
|
|
6926
|
+
if (!playback) {
|
|
6927
|
+
return null;
|
|
6928
|
+
}
|
|
6929
|
+
const info = this._activeAnimations.get(playback.clip);
|
|
6930
|
+
return info?.playback === playback ? {
|
|
6931
|
+
playback,
|
|
6932
|
+
info,
|
|
6933
|
+
clip: playback.clip
|
|
6934
|
+
} : null;
|
|
6935
|
+
}
|
|
6936
|
+
resolveActivePlayback(target) {
|
|
6937
|
+
const named = this.getPlayback(target);
|
|
6938
|
+
if (named) {
|
|
6939
|
+
return named;
|
|
6940
|
+
}
|
|
6941
|
+
for (const info of this._activeAnimations.values()){
|
|
6942
|
+
if (info.playback.id === target) {
|
|
6943
|
+
return info.playback;
|
|
6944
|
+
}
|
|
6945
|
+
}
|
|
6946
|
+
return null;
|
|
6947
|
+
}
|
|
6948
|
+
computePlaybackInitialTime(clip, speedRatio, rangeStart, rangeEnd, sync, syncSource) {
|
|
6949
|
+
const fallback = speedRatio < 0 ? rangeEnd ?? rangeStart ?? clip.timeDuration : rangeStart ?? 0;
|
|
6950
|
+
if (!sync || !syncSource) {
|
|
6951
|
+
return fallback;
|
|
6952
|
+
}
|
|
6953
|
+
const destination = this.getPlaybackEffectiveRange(clip, rangeStart, rangeEnd);
|
|
6954
|
+
if (destination.duration <= 0) {
|
|
6955
|
+
return fallback;
|
|
6956
|
+
}
|
|
6957
|
+
const offset = Number.isFinite(sync.offset) ? sync.offset ?? 0 : 0;
|
|
6958
|
+
const wrap = sync.wrap ?? true;
|
|
6959
|
+
if ((sync.mode ?? 'normalized') === 'time') {
|
|
6960
|
+
return this.constrainPlaybackTime(syncSource.info.currentTime + offset, destination, wrap);
|
|
6961
|
+
}
|
|
6962
|
+
const source = this.getPlaybackEffectiveRange(syncSource.clip, syncSource.info.rangeStart, syncSource.info.rangeEnd);
|
|
6963
|
+
if (source.duration <= 0) {
|
|
6964
|
+
return fallback;
|
|
6965
|
+
}
|
|
6966
|
+
const phase = (syncSource.info.currentTime - source.start) / source.duration + offset;
|
|
6967
|
+
return this.constrainPlaybackTime(destination.start + phase * destination.duration, destination, wrap);
|
|
6968
|
+
}
|
|
6969
|
+
getPlaybackEffectiveRange(clip, rangeStart, rangeEnd) {
|
|
6970
|
+
const start = rangeStart ?? 0;
|
|
6971
|
+
const end = rangeEnd ?? clip.timeDuration;
|
|
6972
|
+
return start <= end ? {
|
|
6973
|
+
start,
|
|
6974
|
+
end,
|
|
6975
|
+
duration: end - start
|
|
6976
|
+
} : {
|
|
6977
|
+
start: end,
|
|
6978
|
+
end: start,
|
|
6979
|
+
duration: start - end
|
|
6980
|
+
};
|
|
6981
|
+
}
|
|
6982
|
+
constrainPlaybackTime(time, range, wrap) {
|
|
6983
|
+
if (!Number.isFinite(time)) {
|
|
6984
|
+
return range.start;
|
|
6985
|
+
}
|
|
6986
|
+
if (!wrap) {
|
|
6987
|
+
return Math.max(range.start, Math.min(range.end, time));
|
|
6988
|
+
}
|
|
6989
|
+
if (time >= range.start && time < range.end) {
|
|
6990
|
+
return time;
|
|
6991
|
+
}
|
|
6992
|
+
const offset = ((time - range.start) % range.duration + range.duration) % range.duration;
|
|
6993
|
+
return range.start + offset;
|
|
6994
|
+
}
|
|
6995
|
+
/**
|
|
6996
|
+
* Stop a playback handle.
|
|
6997
|
+
* @internal
|
|
6998
|
+
*/ stopPlayback(playback, options) {
|
|
6999
|
+
if (this._activeAnimations.get(playback.clip)?.playback === playback) {
|
|
7000
|
+
this.stopAnimation(playback.clip.name, options);
|
|
7001
|
+
}
|
|
7002
|
+
}
|
|
7003
|
+
/**
|
|
7004
|
+
* Pause a playback handle.
|
|
7005
|
+
* @internal
|
|
7006
|
+
*/ pausePlayback(playback) {
|
|
7007
|
+
const info = this._activeAnimations.get(playback.clip);
|
|
7008
|
+
if (info?.playback === playback && !info.paused) {
|
|
7009
|
+
info.paused = true;
|
|
7010
|
+
playback._setState('paused');
|
|
7011
|
+
const event = this.createPlaybackEvent(info, playback.clip);
|
|
7012
|
+
playback._emitPause(event);
|
|
7013
|
+
this.dispatchEvent('playbackpause', event);
|
|
7014
|
+
}
|
|
7015
|
+
}
|
|
7016
|
+
/**
|
|
7017
|
+
* Resume a playback handle.
|
|
7018
|
+
* @internal
|
|
7019
|
+
*/ resumePlayback(playback) {
|
|
7020
|
+
const info = this._activeAnimations.get(playback.clip);
|
|
7021
|
+
if (info?.playback === playback && info.paused) {
|
|
7022
|
+
info.paused = false;
|
|
7023
|
+
playback._setState('playing');
|
|
7024
|
+
const event = this.createPlaybackEvent(info, playback.clip);
|
|
7025
|
+
playback._emitResume(event);
|
|
7026
|
+
this.dispatchEvent('playbackresume', event);
|
|
7027
|
+
}
|
|
7028
|
+
}
|
|
7029
|
+
/**
|
|
7030
|
+
* Seek a playback handle.
|
|
7031
|
+
* @internal
|
|
7032
|
+
*/ seekPlayback(playback, time, options) {
|
|
7033
|
+
const clip = playback.clip;
|
|
7034
|
+
const info = this._activeAnimations.get(clip);
|
|
7035
|
+
const duration = clip.timeDuration;
|
|
7036
|
+
const clampedTime = duration > 0 ? Math.max(0, Math.min(duration, time)) : Math.max(0, time);
|
|
7037
|
+
const previousTime = info?.currentTime ?? playback.time;
|
|
7038
|
+
playback._setTime(clampedTime);
|
|
7039
|
+
if (info?.playback === playback) {
|
|
7040
|
+
info.currentTime = clampedTime;
|
|
7041
|
+
if (options?.emitEvents) {
|
|
7042
|
+
const direction = clampedTime >= previousTime ? 1 : -1;
|
|
7043
|
+
this.emitCrossedMarkers(info, clip, previousTime, clampedTime, direction);
|
|
7044
|
+
this.emitCrossedFrames(info, clip, previousTime, clampedTime, direction);
|
|
7045
|
+
}
|
|
7046
|
+
if (options?.apply) {
|
|
7047
|
+
this.update(0);
|
|
7048
|
+
}
|
|
7049
|
+
}
|
|
7050
|
+
}
|
|
7051
|
+
/**
|
|
7052
|
+
* Set playback weight.
|
|
7053
|
+
* @internal
|
|
7054
|
+
*/ setPlaybackWeight(playback, weight) {
|
|
7055
|
+
playback._setWeight(weight);
|
|
7056
|
+
const info = this._activeAnimations.get(playback.clip);
|
|
7057
|
+
if (info?.playback === playback) {
|
|
7058
|
+
info.weight = weight;
|
|
7059
|
+
info.targetWeight = weight;
|
|
7060
|
+
}
|
|
7061
|
+
}
|
|
7062
|
+
/**
|
|
7063
|
+
* Set playback speed ratio.
|
|
7064
|
+
* @internal
|
|
7065
|
+
*/ setPlaybackSpeedRatio(playback, speedRatio) {
|
|
7066
|
+
playback._setSpeedRatio(speedRatio);
|
|
7067
|
+
const info = this._activeAnimations.get(playback.clip);
|
|
7068
|
+
if (info?.playback === playback) {
|
|
7069
|
+
info.speedRatio = speedRatio;
|
|
7070
|
+
}
|
|
7071
|
+
}
|
|
7072
|
+
/**
|
|
7073
|
+
* Fade playback weight to a target value.
|
|
7074
|
+
* @internal
|
|
7075
|
+
*/ fadePlaybackTo(playback, weight, duration) {
|
|
7076
|
+
const info = this._activeAnimations.get(playback.clip);
|
|
7077
|
+
if (info?.playback === playback) {
|
|
7078
|
+
info.fadeFromWeight = info.weight;
|
|
7079
|
+
info.fadeTargetWeight = weight;
|
|
7080
|
+
info.targetWeight = weight;
|
|
7081
|
+
info.fadeToStart = info.animateTime;
|
|
7082
|
+
info.fadeToDuration = Math.max(duration, 0);
|
|
7083
|
+
if (info.fadeToDuration === 0) {
|
|
7084
|
+
info.weight = weight;
|
|
7085
|
+
playback._setWeight(weight);
|
|
7086
|
+
}
|
|
7087
|
+
} else {
|
|
7088
|
+
playback._setWeight(weight);
|
|
7089
|
+
}
|
|
7090
|
+
}
|
|
7091
|
+
createPlaybackEvent(info, clip) {
|
|
7092
|
+
return {
|
|
7093
|
+
playback: info.playback,
|
|
7094
|
+
animationSet: this,
|
|
7095
|
+
clip,
|
|
7096
|
+
time: info.currentTime,
|
|
7097
|
+
normalizedTime: clip.timeDuration > 0 ? info.currentTime / clip.timeDuration : 0
|
|
7098
|
+
};
|
|
7099
|
+
}
|
|
7100
|
+
completePlayback(clip, info) {
|
|
7101
|
+
if (info.completed) {
|
|
7102
|
+
return;
|
|
7103
|
+
}
|
|
7104
|
+
const event = this.createPlaybackEvent(info, clip);
|
|
7105
|
+
const completionFadeOut = Math.max(info.playback._getOptions().completionFadeOut ?? 0, 0);
|
|
7106
|
+
info.playback._setState('completed');
|
|
7107
|
+
info.playback._emitComplete(event);
|
|
7108
|
+
this.dispatchEvent('playbackcomplete', event);
|
|
7109
|
+
if (completionFadeOut > 0) {
|
|
7110
|
+
info.completed = true;
|
|
7111
|
+
info.fadeOut = completionFadeOut;
|
|
7112
|
+
info.fadeOutStart = info.animateTime;
|
|
7113
|
+
info.stopReason = 'completed';
|
|
7114
|
+
return;
|
|
7115
|
+
}
|
|
7116
|
+
this.stopAnimation(clip.name, {
|
|
7117
|
+
reason: 'completed'
|
|
7118
|
+
});
|
|
7119
|
+
}
|
|
7120
|
+
emitCrossedMarkers(info, clip, fromTime, toTime, direction) {
|
|
7121
|
+
for (const marker of this.getCrossedMarkers(clip, fromTime, toTime, direction)){
|
|
7122
|
+
const event = {
|
|
7123
|
+
...this.createPlaybackEvent(info, clip),
|
|
7124
|
+
marker,
|
|
7125
|
+
direction
|
|
7126
|
+
};
|
|
7127
|
+
info.playback._emitMarker(event);
|
|
7128
|
+
this.dispatchEvent('marker', event);
|
|
7129
|
+
}
|
|
7130
|
+
}
|
|
7131
|
+
emitCrossedFrames(info, clip, fromTime, toTime, direction) {
|
|
7132
|
+
for (const frame of info.playback._getWatchedFrames()){
|
|
7133
|
+
const frameTime = frame / clip.frameRate;
|
|
7134
|
+
const crossed = direction >= 0 ? this.crossedForward(fromTime, toTime, frameTime, clip.timeDuration) : this.crossedBackward(fromTime, toTime, frameTime, clip.timeDuration);
|
|
7135
|
+
if (crossed) {
|
|
7136
|
+
const event = {
|
|
7137
|
+
...this.createPlaybackEvent(info, clip),
|
|
7138
|
+
frame
|
|
7139
|
+
};
|
|
7140
|
+
info.playback._emitFrame(event);
|
|
7141
|
+
this.dispatchEvent('frame', event);
|
|
7142
|
+
}
|
|
7143
|
+
}
|
|
7144
|
+
}
|
|
7145
|
+
getCrossedMarkers(clip, fromTime, toTime, direction) {
|
|
7146
|
+
return clip.markers.filter((marker)=>{
|
|
7147
|
+
const markerTime = clip.resolveMarkerTime(marker);
|
|
7148
|
+
if (markerTime === null) {
|
|
7149
|
+
return false;
|
|
7150
|
+
}
|
|
7151
|
+
return direction >= 0 ? this.crossedForward(fromTime, toTime, markerTime, clip.timeDuration) : this.crossedBackward(fromTime, toTime, markerTime, clip.timeDuration);
|
|
7152
|
+
});
|
|
7153
|
+
}
|
|
7154
|
+
crossedForward(fromTime, toTime, targetTime, duration) {
|
|
7155
|
+
return toTime >= fromTime ? targetTime > fromTime && targetTime <= toTime : duration > 0 && targetTime > fromTime && targetTime <= duration || targetTime <= toTime;
|
|
7156
|
+
}
|
|
7157
|
+
crossedBackward(fromTime, toTime, targetTime, duration) {
|
|
7158
|
+
return toTime <= fromTime ? targetTime < fromTime && targetTime >= toTime : duration > 0 && targetTime < fromTime && targetTime >= 0 || targetTime >= toTime;
|
|
7159
|
+
}
|
|
7160
|
+
/**
|
|
7161
|
+
* Stop playback of an animation clip.
|
|
7162
|
+
*
|
|
7163
|
+
* Behavior:
|
|
7164
|
+
* - If `options.fadeOut > 0`, marks the clip for fade-out; actual removal occurs after fade completes.
|
|
7165
|
+
* - If `fadeOut` is 0 or omitted, immediately:
|
|
7166
|
+
* - Removes the clip from active animations.
|
|
7167
|
+
* - Unregisters its tracks from active track maps.
|
|
7168
|
+
* - Decrements skeleton reference counts; resets and removes skeletons when refcount reaches 0.
|
|
7169
|
+
*
|
|
7170
|
+
* @param name - Name of the animation to stop.
|
|
7171
|
+
* @param options - Optional fade-out configuration.
|
|
6471
7172
|
*/ stopAnimation(name, options) {
|
|
6472
7173
|
const ani = this._animations[name];
|
|
6473
7174
|
if (!ani) {
|
|
@@ -6477,9 +7178,12 @@ function bakeHumanoidRotationTracks(sourceClip, srcSkeleton, dstSkeleton, srcRoo
|
|
|
6477
7178
|
const info = this._activeAnimations.get(ani);
|
|
6478
7179
|
if (info) {
|
|
6479
7180
|
const fadeOut = Math.max(options?.fadeOut ?? 0, 0);
|
|
7181
|
+
const reason = options?.reason ?? 'manual';
|
|
6480
7182
|
if (fadeOut !== 0) {
|
|
6481
7183
|
info.fadeOut = fadeOut;
|
|
6482
7184
|
info.fadeOutStart = -1;
|
|
7185
|
+
info.stopReason = reason;
|
|
7186
|
+
info.playback._setState('stopping');
|
|
6483
7187
|
} else {
|
|
6484
7188
|
this._activeAnimations.delete(ani);
|
|
6485
7189
|
this._activeTracks.forEach((v)=>{
|
|
@@ -6517,20 +7221,29 @@ function bakeHumanoidRotationTracks(sourceClip, srcSkeleton, dstSkeleton, srcRoo
|
|
|
6517
7221
|
}
|
|
6518
7222
|
}
|
|
6519
7223
|
});
|
|
7224
|
+
const event = {
|
|
7225
|
+
...this.createPlaybackEvent(info, ani),
|
|
7226
|
+
reason
|
|
7227
|
+
};
|
|
7228
|
+
if (reason !== 'completed') {
|
|
7229
|
+
info.playback._setState('stopped');
|
|
7230
|
+
}
|
|
7231
|
+
info.playback._emitStop(event);
|
|
7232
|
+
this.dispatchEvent('playbackstop', event);
|
|
6520
7233
|
}
|
|
6521
7234
|
}
|
|
6522
7235
|
}
|
|
6523
|
-
/**
|
|
6524
|
-
* Create a skeletal-only masked clip from an existing clip in this set.
|
|
6525
|
-
*
|
|
6526
|
-
* The generated clip is a regular `AnimationClip`: it contains cloned node transform tracks
|
|
6527
|
-
* for the selected rig joints and can be played/blended through the normal animation system.
|
|
6528
|
-
* Non-skeletal tracks are skipped by default.
|
|
6529
|
-
*
|
|
6530
|
-
* @param sourceName - Name of the source clip.
|
|
6531
|
-
* @param targetName - Name of the generated clip.
|
|
6532
|
-
* @param options - Humanoid semantic or joint-name based mask options.
|
|
6533
|
-
* @returns The generated clip, or null on failure.
|
|
7236
|
+
/**
|
|
7237
|
+
* Create a skeletal-only masked clip from an existing clip in this set.
|
|
7238
|
+
*
|
|
7239
|
+
* The generated clip is a regular `AnimationClip`: it contains cloned node transform tracks
|
|
7240
|
+
* for the selected rig joints and can be played/blended through the normal animation system.
|
|
7241
|
+
* Non-skeletal tracks are skipped by default.
|
|
7242
|
+
*
|
|
7243
|
+
* @param sourceName - Name of the source clip.
|
|
7244
|
+
* @param targetName - Name of the generated clip.
|
|
7245
|
+
* @param options - Humanoid semantic or joint-name based mask options.
|
|
7246
|
+
* @returns The generated clip, or null on failure.
|
|
6534
7247
|
*/ createSkeletalMaskedAnimation(sourceName, targetName, options) {
|
|
6535
7248
|
const sourceClip = this.get(sourceName);
|
|
6536
7249
|
if (!sourceClip) {
|
|
@@ -6737,21 +7450,21 @@ function bakeHumanoidRotationTracks(sourceClip, srcSkeleton, dstSkeleton, srcRoo
|
|
|
6737
7450
|
}
|
|
6738
7451
|
return dstClip;
|
|
6739
7452
|
}
|
|
6740
|
-
/**
|
|
6741
|
-
* Copy an animation clip from another AnimationSet into this one.
|
|
6742
|
-
*
|
|
6743
|
-
* Prerequisites:
|
|
6744
|
-
* - Both sets must reference skeletons with identical joint names and counts.
|
|
6745
|
-
* - The source clip must exist in `sourceSet`.
|
|
6746
|
-
*
|
|
6747
|
-
* @param sourceSet - The AnimationSet to copy from.
|
|
6748
|
-
* @param animationName - Name of the clip to copy.
|
|
6749
|
-
* @param targetName - Name for the new clip in this set. Defaults to `animationName`.
|
|
6750
|
-
* @param excludeJoint - Optional predicate; joints whose name returns true are excluded from
|
|
6751
|
-
* skeleton structure matching.
|
|
6752
|
-
* @returns The newly created AnimationClip, or null on failure.
|
|
6753
|
-
*
|
|
6754
|
-
* @deprecated Use AnimationSet.copyHumanoidAnimationFrom instead.
|
|
7453
|
+
/**
|
|
7454
|
+
* Copy an animation clip from another AnimationSet into this one.
|
|
7455
|
+
*
|
|
7456
|
+
* Prerequisites:
|
|
7457
|
+
* - Both sets must reference skeletons with identical joint names and counts.
|
|
7458
|
+
* - The source clip must exist in `sourceSet`.
|
|
7459
|
+
*
|
|
7460
|
+
* @param sourceSet - The AnimationSet to copy from.
|
|
7461
|
+
* @param animationName - Name of the clip to copy.
|
|
7462
|
+
* @param targetName - Name for the new clip in this set. Defaults to `animationName`.
|
|
7463
|
+
* @param excludeJoint - Optional predicate; joints whose name returns true are excluded from
|
|
7464
|
+
* skeleton structure matching.
|
|
7465
|
+
* @returns The newly created AnimationClip, or null on failure.
|
|
7466
|
+
*
|
|
7467
|
+
* @deprecated Use AnimationSet.copyHumanoidAnimationFrom instead.
|
|
6755
7468
|
*/ copyAnimationFrom(sourceSet, animationName, targetName, excludeJoint) {
|
|
6756
7469
|
const destName = targetName ?? animationName;
|
|
6757
7470
|
const sourceClip = sourceSet.get(animationName);
|
|
@@ -6897,8 +7610,8 @@ function bakeHumanoidRotationTracks(sourceClip, srcSkeleton, dstSkeleton, srcRoo
|
|
|
6897
7610
|
return ordered;
|
|
6898
7611
|
}
|
|
6899
7612
|
}
|
|
6900
|
-
/**
|
|
6901
|
-
* Reset all skeleton modifiers
|
|
7613
|
+
/**
|
|
7614
|
+
* Reset all skeleton modifiers
|
|
6902
7615
|
*/ resetSkeletonModifiers() {
|
|
6903
7616
|
for (const sk of this._skeletons){
|
|
6904
7617
|
for (const modifier of sk.get().modifiers){
|
|
@@ -6906,12 +7619,12 @@ function bakeHumanoidRotationTracks(sourceClip, srcSkeleton, dstSkeleton, srcRoo
|
|
|
6906
7619
|
}
|
|
6907
7620
|
}
|
|
6908
7621
|
}
|
|
6909
|
-
/**
|
|
6910
|
-
* Dispose the animation set and release owned resources.
|
|
6911
|
-
*
|
|
6912
|
-
* - Disposes the weak reference to the model.
|
|
6913
|
-
* - Disposes all registered animation clips.
|
|
6914
|
-
* - Clears active animations, tracks, and skeleton references.
|
|
7622
|
+
/**
|
|
7623
|
+
* Dispose the animation set and release owned resources.
|
|
7624
|
+
*
|
|
7625
|
+
* - Disposes the weak reference to the model.
|
|
7626
|
+
* - Disposes all registered animation clips.
|
|
7627
|
+
* - Clears active animations, tracks, and skeleton references.
|
|
6915
7628
|
*/ onDispose() {
|
|
6916
7629
|
super.onDispose();
|
|
6917
7630
|
for(const k in this._animations){
|
|
@@ -13718,9 +14431,13 @@ FEATURE_DISABLE_TAA = MeshMaterial.defineFeature();
|
|
|
13718
14431
|
pb.vec3('worldPos'),
|
|
13719
14432
|
pb.vec4('posRange')
|
|
13720
14433
|
], function() {
|
|
13721
|
-
this.$l.
|
|
13722
|
-
this.$l.
|
|
13723
|
-
this.$
|
|
14434
|
+
this.$l.d = pb.sub(this.worldPos, this.posRange.xyz);
|
|
14435
|
+
this.$l.dist2 = pb.dot(this.d, this.d);
|
|
14436
|
+
this.$l.lightAtten = pb.div(1, pb.max(this.dist2, 0.0001));
|
|
14437
|
+
this.$l.range2 = pb.mul(this.posRange.w, this.posRange.w);
|
|
14438
|
+
this.$l.f = pb.div(this.dist2, pb.max(this.range2, 0.0001));
|
|
14439
|
+
this.$l.f2 = pb.clamp(pb.sub(1, pb.mul(this.f, this.f)), 0, 1);
|
|
14440
|
+
this.$return(pb.mul(this.lightAtten, pb.mul(this.f2, this.f2)));
|
|
13724
14441
|
});
|
|
13725
14442
|
return pb.getGlobalScope()[funcName](worldPos, posRange);
|
|
13726
14443
|
}
|
|
@@ -55763,7 +56480,7 @@ class HeightBoundingGenerator extends RenderMipmap {
|
|
|
55763
56480
|
name: 'FXAAEnabled',
|
|
55764
56481
|
type: 'bool',
|
|
55765
56482
|
phase: 0,
|
|
55766
|
-
default:
|
|
56483
|
+
default: false,
|
|
55767
56484
|
options: {
|
|
55768
56485
|
label: 'Enabled',
|
|
55769
56486
|
group: 'PostProcessing/FXAA'
|
|
@@ -81681,6 +82398,1474 @@ function dot(ax, ay, bx, by) {
|
|
|
81681
82398
|
return ax * bx + ay * by;
|
|
81682
82399
|
}
|
|
81683
82400
|
|
|
82401
|
+
/**
|
|
82402
|
+
* Serializable animation timeline definition.
|
|
82403
|
+
* @public
|
|
82404
|
+
*/ class AnimationTimeline {
|
|
82405
|
+
/**
|
|
82406
|
+
* Root step sequence executed by runners created from this timeline.
|
|
82407
|
+
*/ steps;
|
|
82408
|
+
/**
|
|
82409
|
+
* Event responses declared on this timeline.
|
|
82410
|
+
*/ responses;
|
|
82411
|
+
/**
|
|
82412
|
+
* Create a timeline from a definition object or a root step array.
|
|
82413
|
+
*
|
|
82414
|
+
* @param definition - Timeline definition, or a shorthand array used as the root steps.
|
|
82415
|
+
*/ constructor(definition){
|
|
82416
|
+
if (Array.isArray(definition)) {
|
|
82417
|
+
this.steps = definition;
|
|
82418
|
+
this.responses = [];
|
|
82419
|
+
} else {
|
|
82420
|
+
this.steps = definition.steps;
|
|
82421
|
+
this.responses = definition.responses ?? [];
|
|
82422
|
+
}
|
|
82423
|
+
}
|
|
82424
|
+
/**
|
|
82425
|
+
* Create a runtime runner for this timeline.
|
|
82426
|
+
*
|
|
82427
|
+
* @param animationSet - Animation set used to create and update playbacks.
|
|
82428
|
+
* @returns A new stopped runner bound to this timeline and animation set.
|
|
82429
|
+
*/ createRunner(animationSet) {
|
|
82430
|
+
return new AnimationTimelineRunner(animationSet, this);
|
|
82431
|
+
}
|
|
82432
|
+
}
|
|
82433
|
+
/**
|
|
82434
|
+
* Runtime interpreter for an AnimationTimeline.
|
|
82435
|
+
*
|
|
82436
|
+
* The interpreter is a synchronous frame-stack state machine advanced by {@link AnimationTimelineRunner.tick}, which is
|
|
82437
|
+
* driven by `AnimationSet.update(dt)` on the same logical clock as the animations. There is no
|
|
82438
|
+
* `async`/`await` in the control flow, so the runtime state can be serialized and replayed.
|
|
82439
|
+
* @public
|
|
82440
|
+
*/ class AnimationTimelineRunner extends Observable {
|
|
82441
|
+
/**
|
|
82442
|
+
* Animation set used to start, stop, and query animation playbacks.
|
|
82443
|
+
*/ animationSet;
|
|
82444
|
+
/**
|
|
82445
|
+
* Timeline definition interpreted by this runner.
|
|
82446
|
+
*/ timeline;
|
|
82447
|
+
_stack;
|
|
82448
|
+
_concurrent;
|
|
82449
|
+
_queued;
|
|
82450
|
+
_pendingEvents;
|
|
82451
|
+
_stopped;
|
|
82452
|
+
_ticking;
|
|
82453
|
+
_lastCompletedPlaybackId;
|
|
82454
|
+
_onTick;
|
|
82455
|
+
/** Tracks playbacks created by this runner so `stop()` can tear them down. */ _ownedPlaybacks;
|
|
82456
|
+
/** Local playback refs that survive after the sequence frame that declared them drains. */ _playbackRefs;
|
|
82457
|
+
/** Ids of playbacks owned by concurrent (keep-active) branches; preserved across main-flow stops. */ _concurrentPlaybackIds;
|
|
82458
|
+
/** Marker/frame crossings observed since the last tick, keyed by playback id. */ _crossedMarkers;
|
|
82459
|
+
_crossedFrames;
|
|
82460
|
+
/**
|
|
82461
|
+
* Create a stopped runner for a timeline.
|
|
82462
|
+
*
|
|
82463
|
+
* @param animationSet - Animation set that owns clips and playbacks referenced by the timeline.
|
|
82464
|
+
* @param timeline - Timeline definition to interpret.
|
|
82465
|
+
*/ constructor(animationSet, timeline){
|
|
82466
|
+
super();
|
|
82467
|
+
this.animationSet = animationSet;
|
|
82468
|
+
this.timeline = timeline;
|
|
82469
|
+
this._stack = [];
|
|
82470
|
+
this._concurrent = [];
|
|
82471
|
+
this._queued = [];
|
|
82472
|
+
this._pendingEvents = [];
|
|
82473
|
+
this._stopped = true;
|
|
82474
|
+
this._ticking = false;
|
|
82475
|
+
this._lastCompletedPlaybackId = null;
|
|
82476
|
+
this._onTick = (deltaInSeconds)=>this.tick(deltaInSeconds);
|
|
82477
|
+
this._ownedPlaybacks = new Map();
|
|
82478
|
+
this._playbackRefs = new Map();
|
|
82479
|
+
this._concurrentPlaybackIds = new Set();
|
|
82480
|
+
this._crossedMarkers = new Map();
|
|
82481
|
+
this._crossedFrames = new Map();
|
|
82482
|
+
}
|
|
82483
|
+
/**
|
|
82484
|
+
* Playback currently referenced by the active main-flow scope.
|
|
82485
|
+
*
|
|
82486
|
+
* @returns The current playback, or null when the main flow has no active playback reference.
|
|
82487
|
+
*/ get currentPlayback() {
|
|
82488
|
+
const scope = this.activeScope();
|
|
82489
|
+
if (!scope?.currentPlaybackId) {
|
|
82490
|
+
return null;
|
|
82491
|
+
}
|
|
82492
|
+
return this._ownedPlaybacks.get(scope.currentPlaybackId) ?? null;
|
|
82493
|
+
}
|
|
82494
|
+
/**
|
|
82495
|
+
* Whether this runner is stopped.
|
|
82496
|
+
*
|
|
82497
|
+
* @returns True when the runner is stopped; otherwise false.
|
|
82498
|
+
*/ get stopped() {
|
|
82499
|
+
return this._stopped;
|
|
82500
|
+
}
|
|
82501
|
+
/**
|
|
82502
|
+
* Playback id for the most recent playback that completed naturally.
|
|
82503
|
+
*
|
|
82504
|
+
* @returns The playback id, or null when no owned playback has completed.
|
|
82505
|
+
*/ get lastCompletedPlaybackId() {
|
|
82506
|
+
return this._lastCompletedPlaybackId;
|
|
82507
|
+
}
|
|
82508
|
+
/**
|
|
82509
|
+
* Start or restart the runner from the beginning of the timeline.
|
|
82510
|
+
*
|
|
82511
|
+
* @returns This runner for chaining.
|
|
82512
|
+
*/ start() {
|
|
82513
|
+
this._stopped = false;
|
|
82514
|
+
this._stack = [
|
|
82515
|
+
this.makeSeqFrame(this.timeline.steps)
|
|
82516
|
+
];
|
|
82517
|
+
this._concurrent = [];
|
|
82518
|
+
this._queued.length = 0;
|
|
82519
|
+
this._pendingEvents = [];
|
|
82520
|
+
this._lastCompletedPlaybackId = null;
|
|
82521
|
+
this._playbackRefs.clear();
|
|
82522
|
+
this.animationSet._registerTimelineTicker(this._onTick);
|
|
82523
|
+
// Drain any leading non-blocking steps immediately so e.g. an initial `play` starts now.
|
|
82524
|
+
this.flush();
|
|
82525
|
+
return this;
|
|
82526
|
+
}
|
|
82527
|
+
/**
|
|
82528
|
+
* Stop the runner and all playbacks it owns.
|
|
82529
|
+
*
|
|
82530
|
+
* @param options - Optional stop behavior applied to owned playbacks.
|
|
82531
|
+
* @returns This runner for chaining.
|
|
82532
|
+
*/ stop(options) {
|
|
82533
|
+
const wasStopped = this._stopped;
|
|
82534
|
+
this._stopped = true;
|
|
82535
|
+
this._stack = [];
|
|
82536
|
+
this._concurrent = [];
|
|
82537
|
+
this._queued.length = 0;
|
|
82538
|
+
this._pendingEvents = [];
|
|
82539
|
+
this._crossedMarkers.clear();
|
|
82540
|
+
this._crossedFrames.clear();
|
|
82541
|
+
this._lastCompletedPlaybackId = null;
|
|
82542
|
+
const stopOptions = options ?? {
|
|
82543
|
+
reason: 'interrupted'
|
|
82544
|
+
};
|
|
82545
|
+
// Always tear down owned playbacks, even if the control flow already drained: a state whose
|
|
82546
|
+
// script finished may still have a looping clip playing that a transition must stop.
|
|
82547
|
+
this._ownedPlaybacks.forEach((playback)=>{
|
|
82548
|
+
this.detachPlayback(playback);
|
|
82549
|
+
playback.stop(stopOptions);
|
|
82550
|
+
});
|
|
82551
|
+
this._ownedPlaybacks.clear();
|
|
82552
|
+
this._playbackRefs.clear();
|
|
82553
|
+
this._concurrentPlaybackIds.clear();
|
|
82554
|
+
this.animationSet._unregisterTimelineTicker(this._onTick);
|
|
82555
|
+
if (!wasStopped) {
|
|
82556
|
+
this.dispatchEvent('stop', this);
|
|
82557
|
+
}
|
|
82558
|
+
return this;
|
|
82559
|
+
}
|
|
82560
|
+
/**
|
|
82561
|
+
* Append a batch of steps to run after the main stack drains.
|
|
82562
|
+
*
|
|
82563
|
+
* If the runner has already completed, enqueueing steps revives it and registers it for ticking.
|
|
82564
|
+
*
|
|
82565
|
+
* @param steps - Steps to run as the next queued batch.
|
|
82566
|
+
* @returns void
|
|
82567
|
+
*/ enqueue(steps) {
|
|
82568
|
+
if (steps.length === 0) {
|
|
82569
|
+
return;
|
|
82570
|
+
}
|
|
82571
|
+
this._queued.push(steps);
|
|
82572
|
+
// Revive a runner that already drained so queued steps are not silently dropped.
|
|
82573
|
+
if (this._stopped) {
|
|
82574
|
+
this._stopped = false;
|
|
82575
|
+
this._stack = [];
|
|
82576
|
+
this.animationSet._registerTimelineTicker(this._onTick);
|
|
82577
|
+
}
|
|
82578
|
+
this.flush();
|
|
82579
|
+
}
|
|
82580
|
+
/**
|
|
82581
|
+
* Run `steps` concurrently with the current control flow (a true parallel branch). Unlike
|
|
82582
|
+
* {@link AnimationTimelineRunner.enqueue}, these do not wait for the main stack to drain.
|
|
82583
|
+
*
|
|
82584
|
+
* @param steps - Steps to run immediately in an independent concurrent branch.
|
|
82585
|
+
* @returns void
|
|
82586
|
+
* @public
|
|
82587
|
+
*/ runConcurrent(steps) {
|
|
82588
|
+
if (steps.length === 0) {
|
|
82589
|
+
return;
|
|
82590
|
+
}
|
|
82591
|
+
this._concurrent.push(this.makeSeqFrame(steps, 'concurrent'));
|
|
82592
|
+
if (this._stopped) {
|
|
82593
|
+
this._stopped = false;
|
|
82594
|
+
this.animationSet._registerTimelineTicker(this._onTick);
|
|
82595
|
+
} else {
|
|
82596
|
+
this.ensureTicking();
|
|
82597
|
+
}
|
|
82598
|
+
this.flush();
|
|
82599
|
+
}
|
|
82600
|
+
/**
|
|
82601
|
+
* Dispatch an event to this runner.
|
|
82602
|
+
*
|
|
82603
|
+
* Waiting `waitEvent` frames consume matching events first. If no waiter consumes the event,
|
|
82604
|
+
* the timeline response table is evaluated.
|
|
82605
|
+
*
|
|
82606
|
+
* @param event - Event name to dispatch.
|
|
82607
|
+
* @param payload - Optional payload returned in the result.
|
|
82608
|
+
* @returns The resolved handling result for the event.
|
|
82609
|
+
*/ dispatch(event, payload) {
|
|
82610
|
+
// A waiting `waitEvent` frame consumes the event; flush advances past it synchronously.
|
|
82611
|
+
if (this.hasWaiterFor(event)) {
|
|
82612
|
+
this._pendingEvents.push(event);
|
|
82613
|
+
this.flush();
|
|
82614
|
+
return {
|
|
82615
|
+
handled: true,
|
|
82616
|
+
policy: 'consume',
|
|
82617
|
+
event,
|
|
82618
|
+
payload
|
|
82619
|
+
};
|
|
82620
|
+
}
|
|
82621
|
+
const response = this.timeline.responses.find((item)=>item.event === event);
|
|
82622
|
+
if (!response || response.target.ignore) {
|
|
82623
|
+
return {
|
|
82624
|
+
handled: false,
|
|
82625
|
+
policy: response ? 'ignore' : 'none',
|
|
82626
|
+
event,
|
|
82627
|
+
payload
|
|
82628
|
+
};
|
|
82629
|
+
}
|
|
82630
|
+
if (response.target.consume) {
|
|
82631
|
+
return {
|
|
82632
|
+
handled: true,
|
|
82633
|
+
policy: 'consume',
|
|
82634
|
+
event,
|
|
82635
|
+
payload
|
|
82636
|
+
};
|
|
82637
|
+
}
|
|
82638
|
+
if (response.target.targetState !== undefined) {
|
|
82639
|
+
// Only the controller can switch states; bubble up so it can act on its own table.
|
|
82640
|
+
return {
|
|
82641
|
+
handled: false,
|
|
82642
|
+
policy: 'transition',
|
|
82643
|
+
event,
|
|
82644
|
+
payload
|
|
82645
|
+
};
|
|
82646
|
+
}
|
|
82647
|
+
const steps = response.target.steps;
|
|
82648
|
+
if (!steps?.length) {
|
|
82649
|
+
return {
|
|
82650
|
+
handled: false,
|
|
82651
|
+
policy: 'none',
|
|
82652
|
+
event,
|
|
82653
|
+
payload
|
|
82654
|
+
};
|
|
82655
|
+
}
|
|
82656
|
+
if (response.enqueue) {
|
|
82657
|
+
this.enqueue(steps);
|
|
82658
|
+
return {
|
|
82659
|
+
handled: true,
|
|
82660
|
+
policy: 'enqueue',
|
|
82661
|
+
event,
|
|
82662
|
+
payload
|
|
82663
|
+
};
|
|
82664
|
+
}
|
|
82665
|
+
const disposition = response.onActive ?? 'stop';
|
|
82666
|
+
if (disposition === 'keep') {
|
|
82667
|
+
// Run the new steps concurrently with the existing control flow (true parallel branch).
|
|
82668
|
+
this.runConcurrent(steps);
|
|
82669
|
+
} else {
|
|
82670
|
+
const stopOptions = typeof disposition === 'object' ? {
|
|
82671
|
+
...disposition,
|
|
82672
|
+
reason: 'interrupted'
|
|
82673
|
+
} : undefined;
|
|
82674
|
+
this.stopMainFlow(stopOptions);
|
|
82675
|
+
this._stopped = false;
|
|
82676
|
+
this._stack = [
|
|
82677
|
+
this.makeSeqFrame(steps)
|
|
82678
|
+
];
|
|
82679
|
+
this.ensureTicking();
|
|
82680
|
+
this.flush();
|
|
82681
|
+
}
|
|
82682
|
+
return {
|
|
82683
|
+
handled: true,
|
|
82684
|
+
policy: 'steps',
|
|
82685
|
+
event,
|
|
82686
|
+
payload
|
|
82687
|
+
};
|
|
82688
|
+
}
|
|
82689
|
+
/**
|
|
82690
|
+
* Run pending non-blocking work synchronously (a zero-delta tick), without advancing any
|
|
82691
|
+
* time-based waits. Lets `start()`/`dispatch()` take effect immediately while keeping all
|
|
82692
|
+
* runtime state in the serializable frame stack.
|
|
82693
|
+
*
|
|
82694
|
+
* @returns This runner for chaining.
|
|
82695
|
+
* @public
|
|
82696
|
+
*/ flush() {
|
|
82697
|
+
// Guard against re-entrancy: an `emit` listener firing during a tick may dispatch again.
|
|
82698
|
+
if (!this._ticking) {
|
|
82699
|
+
this.tick(0);
|
|
82700
|
+
}
|
|
82701
|
+
return this;
|
|
82702
|
+
}
|
|
82703
|
+
/**
|
|
82704
|
+
* Advance the timeline by `deltaInSeconds`. Called by `AnimationSet.update`.
|
|
82705
|
+
*
|
|
82706
|
+
* @param deltaInSeconds - Elapsed time in seconds for this tick.
|
|
82707
|
+
* @returns void
|
|
82708
|
+
* @public
|
|
82709
|
+
*/ tick(deltaInSeconds) {
|
|
82710
|
+
if (this._stopped && this._queued.length === 0) {
|
|
82711
|
+
return;
|
|
82712
|
+
}
|
|
82713
|
+
this._ticking = true;
|
|
82714
|
+
// Advance the main control-flow stack.
|
|
82715
|
+
if (this._stack.length === 0 && this._queued.length > 0) {
|
|
82716
|
+
const next = this._queued.shift();
|
|
82717
|
+
this._stack = [
|
|
82718
|
+
this.makeSeqFrame(next)
|
|
82719
|
+
];
|
|
82720
|
+
}
|
|
82721
|
+
if (this._stack.length > 0) {
|
|
82722
|
+
this.tickFrames(this._stack, deltaInSeconds);
|
|
82723
|
+
}
|
|
82724
|
+
// Advance any concurrent (keep-active) branches; drop the ones that finished.
|
|
82725
|
+
if (this._concurrent.length > 0) {
|
|
82726
|
+
this._concurrent = this._concurrent.filter((frame)=>{
|
|
82727
|
+
const stack = [
|
|
82728
|
+
frame
|
|
82729
|
+
];
|
|
82730
|
+
this.tickFrames(stack, deltaInSeconds);
|
|
82731
|
+
return stack.length > 0;
|
|
82732
|
+
});
|
|
82733
|
+
}
|
|
82734
|
+
// Consumed this tick.
|
|
82735
|
+
this._pendingEvents = [];
|
|
82736
|
+
this._crossedMarkers.clear();
|
|
82737
|
+
this._crossedFrames.clear();
|
|
82738
|
+
this._ticking = false;
|
|
82739
|
+
// Pull queued batches once the stack drains.
|
|
82740
|
+
while(this._stack.length === 0 && this._queued.length > 0){
|
|
82741
|
+
const next = this._queued.shift();
|
|
82742
|
+
this._stack = [
|
|
82743
|
+
this.makeSeqFrame(next)
|
|
82744
|
+
];
|
|
82745
|
+
this.tickFrames(this._stack, 0);
|
|
82746
|
+
}
|
|
82747
|
+
if (!this._stopped && this._stack.length === 0 && this._concurrent.length === 0 && this._queued.length === 0) {
|
|
82748
|
+
this._stopped = true;
|
|
82749
|
+
this.animationSet._unregisterTimelineTicker(this._onTick);
|
|
82750
|
+
this.dispatchEvent('complete', this);
|
|
82751
|
+
}
|
|
82752
|
+
}
|
|
82753
|
+
/**
|
|
82754
|
+
* Export the runtime state as plain data.
|
|
82755
|
+
*
|
|
82756
|
+
* @returns A serializable snapshot of the runner state.
|
|
82757
|
+
* @public
|
|
82758
|
+
*/ serialize() {
|
|
82759
|
+
return {
|
|
82760
|
+
stack: this._stack.map((frame)=>this.cloneFrame(frame)),
|
|
82761
|
+
concurrent: this._concurrent.map((frame)=>this.cloneFrame(frame)),
|
|
82762
|
+
queued: this._queued.map((steps)=>steps.slice()),
|
|
82763
|
+
concurrentPlaybackIds: [
|
|
82764
|
+
...this._concurrentPlaybackIds
|
|
82765
|
+
],
|
|
82766
|
+
playbackRefs: Object.fromEntries(this._playbackRefs),
|
|
82767
|
+
stopped: this._stopped
|
|
82768
|
+
};
|
|
82769
|
+
}
|
|
82770
|
+
/**
|
|
82771
|
+
* Restore runtime state previously produced by {@link AnimationTimelineRunner.serialize}.
|
|
82772
|
+
*
|
|
82773
|
+
* Re-create the relevant active playbacks on the AnimationSet before calling this so that
|
|
82774
|
+
* playback-bound frames (play-wait, waitMarker, waitFrame) can re-attach by id.
|
|
82775
|
+
*
|
|
82776
|
+
* @param animationSet - Animation set containing any live playbacks referenced by the state.
|
|
82777
|
+
* @param timeline - Timeline definition to bind to the restored runner.
|
|
82778
|
+
* @param state - Serialized state previously returned by {@link AnimationTimelineRunner.serialize}.
|
|
82779
|
+
* @returns A runner restored to the supplied runtime state.
|
|
82780
|
+
* @public
|
|
82781
|
+
*/ static deserialize(animationSet, timeline, state) {
|
|
82782
|
+
const runner = new AnimationTimelineRunner(animationSet, timeline);
|
|
82783
|
+
runner._stack = state.stack.map((frame)=>runner.cloneFrame(frame));
|
|
82784
|
+
runner._concurrent = state.concurrent.map((frame)=>runner.cloneFrame(frame));
|
|
82785
|
+
state.queued.forEach((steps)=>runner._queued.push(steps.slice()));
|
|
82786
|
+
state.concurrentPlaybackIds?.forEach((id)=>runner._concurrentPlaybackIds.add(id));
|
|
82787
|
+
Object.entries(state.playbackRefs ?? {}).forEach(([ref, id])=>runner._playbackRefs.set(ref, id));
|
|
82788
|
+
runner._stopped = state.stopped;
|
|
82789
|
+
// Re-attach to any live playbacks referenced by the restored frames.
|
|
82790
|
+
runner.reattachPlaybacks(runner._stack);
|
|
82791
|
+
runner._concurrent.forEach((frame)=>runner.reattachPlaybacks([
|
|
82792
|
+
frame
|
|
82793
|
+
]));
|
|
82794
|
+
// Re-attach drained concurrent playbacks tracked only by id, so they survive future stops.
|
|
82795
|
+
runner._concurrentPlaybackIds.forEach((id)=>{
|
|
82796
|
+
if (!runner._ownedPlaybacks.has(id)) {
|
|
82797
|
+
const playback = runner.findLivePlayback(id);
|
|
82798
|
+
if (playback) {
|
|
82799
|
+
runner.attachPlayback(playback);
|
|
82800
|
+
}
|
|
82801
|
+
}
|
|
82802
|
+
});
|
|
82803
|
+
runner._playbackRefs.forEach((id)=>{
|
|
82804
|
+
if (!runner._ownedPlaybacks.has(id)) {
|
|
82805
|
+
const playback = runner.findLivePlayback(id);
|
|
82806
|
+
if (playback) {
|
|
82807
|
+
runner.attachPlayback(playback);
|
|
82808
|
+
}
|
|
82809
|
+
}
|
|
82810
|
+
});
|
|
82811
|
+
if (!runner._stopped) {
|
|
82812
|
+
animationSet._registerTimelineTicker(runner._onTick);
|
|
82813
|
+
}
|
|
82814
|
+
return runner;
|
|
82815
|
+
}
|
|
82816
|
+
// --- internals -------------------------------------------------------------
|
|
82817
|
+
ensureTicking() {
|
|
82818
|
+
if (!this._ticking) {
|
|
82819
|
+
this.animationSet._registerTimelineTicker(this._onTick);
|
|
82820
|
+
}
|
|
82821
|
+
}
|
|
82822
|
+
makeSeqFrame(steps, owner = 'main') {
|
|
82823
|
+
return {
|
|
82824
|
+
kind: 'seq',
|
|
82825
|
+
steps,
|
|
82826
|
+
index: 0,
|
|
82827
|
+
scope: {
|
|
82828
|
+
currentPlaybackId: null,
|
|
82829
|
+
refs: {},
|
|
82830
|
+
owner
|
|
82831
|
+
},
|
|
82832
|
+
child: null
|
|
82833
|
+
};
|
|
82834
|
+
}
|
|
82835
|
+
/** The scope of the innermost active sequence on the main stack (for currentPlayback). */ activeScope() {
|
|
82836
|
+
for(let i = this._stack.length - 1; i >= 0; i--){
|
|
82837
|
+
const scope = this.deepestScope(this._stack[i]);
|
|
82838
|
+
if (scope) {
|
|
82839
|
+
return scope;
|
|
82840
|
+
}
|
|
82841
|
+
}
|
|
82842
|
+
return null;
|
|
82843
|
+
}
|
|
82844
|
+
deepestScope(frame) {
|
|
82845
|
+
if (frame.kind === 'seq') {
|
|
82846
|
+
return frame.child ? this.deepestScope(frame.child) ?? frame.scope : frame.scope;
|
|
82847
|
+
}
|
|
82848
|
+
return null;
|
|
82849
|
+
}
|
|
82850
|
+
/**
|
|
82851
|
+
* Advance a frame stack in place. The top frame runs until it blocks or completes; completed
|
|
82852
|
+
* frames pop and the parent sequence advances. Returns when the stack blocks or empties.
|
|
82853
|
+
*/ tickFrames(stack, deltaInSeconds) {
|
|
82854
|
+
this.tickFramesWithLeftover(stack, deltaInSeconds);
|
|
82855
|
+
}
|
|
82856
|
+
/**
|
|
82857
|
+
* Same as {@link AnimationTimelineRunner.tickFrames} but returns the time left unconsumed when the stack drains
|
|
82858
|
+
* completely (so a parent sequence can hand it to its next step).
|
|
82859
|
+
*/ tickFramesWithLeftover(stack, deltaInSeconds) {
|
|
82860
|
+
let guard = 0;
|
|
82861
|
+
while(stack.length > 0){
|
|
82862
|
+
if (++guard > 10000) {
|
|
82863
|
+
break;
|
|
82864
|
+
}
|
|
82865
|
+
const frame = stack[stack.length - 1];
|
|
82866
|
+
const result = this.tickFrame(frame, stack, deltaInSeconds);
|
|
82867
|
+
if (result.status === 'block') {
|
|
82868
|
+
return 0;
|
|
82869
|
+
}
|
|
82870
|
+
if (result.status === 'pop') {
|
|
82871
|
+
stack.pop();
|
|
82872
|
+
// Carry any unused time (e.g. a `wait` that overshot its duration this tick) to the next
|
|
82873
|
+
// step so a sequence of waits/actions tracks logical time regardless of frame rate.
|
|
82874
|
+
deltaInSeconds = result.leftover ?? 0;
|
|
82875
|
+
continue;
|
|
82876
|
+
}
|
|
82877
|
+
// 'advanced': the frame pushed a child or moved its cursor; loop again with delta 0 so a
|
|
82878
|
+
// single tick can drain consecutive non-blocking steps.
|
|
82879
|
+
deltaInSeconds = 0;
|
|
82880
|
+
}
|
|
82881
|
+
return deltaInSeconds;
|
|
82882
|
+
}
|
|
82883
|
+
tickFrame(frame, stack, deltaInSeconds) {
|
|
82884
|
+
switch(frame.kind){
|
|
82885
|
+
case 'seq':
|
|
82886
|
+
return this.tickSeq(frame, stack, deltaInSeconds);
|
|
82887
|
+
case 'parallel':
|
|
82888
|
+
return this.tickParallel(frame, deltaInSeconds);
|
|
82889
|
+
case 'wait':
|
|
82890
|
+
frame.remaining -= deltaInSeconds;
|
|
82891
|
+
// On completion, hand back the overshoot (negative remaining) as leftover time.
|
|
82892
|
+
return frame.remaining <= 0 ? {
|
|
82893
|
+
status: 'pop',
|
|
82894
|
+
leftover: -frame.remaining
|
|
82895
|
+
} : {
|
|
82896
|
+
status: 'block'
|
|
82897
|
+
};
|
|
82898
|
+
case 'waitEvent':
|
|
82899
|
+
return this._pendingEvents.includes(frame.event) ? {
|
|
82900
|
+
status: 'pop'
|
|
82901
|
+
} : {
|
|
82902
|
+
status: 'block'
|
|
82903
|
+
};
|
|
82904
|
+
case 'waitMarker':
|
|
82905
|
+
return this.tickWaitMarker(frame);
|
|
82906
|
+
case 'waitFrame':
|
|
82907
|
+
return this.tickWaitFrame(frame);
|
|
82908
|
+
case 'playWait':
|
|
82909
|
+
return this.tickPlayWait(frame);
|
|
82910
|
+
}
|
|
82911
|
+
}
|
|
82912
|
+
tickSeq(frame, _stack, deltaInSeconds) {
|
|
82913
|
+
// Drain steps in a loop so unconsumed time (e.g. a `wait` that overshot) flows into the next
|
|
82914
|
+
// step within the same tick instead of being dropped.
|
|
82915
|
+
let guard = 0;
|
|
82916
|
+
for(;;){
|
|
82917
|
+
if (++guard > 10000) {
|
|
82918
|
+
return {
|
|
82919
|
+
status: 'block'
|
|
82920
|
+
};
|
|
82921
|
+
}
|
|
82922
|
+
if (frame.child) {
|
|
82923
|
+
const childStack = [
|
|
82924
|
+
frame.child
|
|
82925
|
+
];
|
|
82926
|
+
const leftover = this.tickFramesWithLeftover(childStack, deltaInSeconds);
|
|
82927
|
+
if (childStack.length > 0) {
|
|
82928
|
+
return {
|
|
82929
|
+
status: 'block'
|
|
82930
|
+
};
|
|
82931
|
+
}
|
|
82932
|
+
frame.child = null;
|
|
82933
|
+
frame.index++;
|
|
82934
|
+
deltaInSeconds = leftover;
|
|
82935
|
+
}
|
|
82936
|
+
if (frame.index >= frame.steps.length) {
|
|
82937
|
+
return {
|
|
82938
|
+
status: 'pop',
|
|
82939
|
+
leftover: deltaInSeconds
|
|
82940
|
+
};
|
|
82941
|
+
}
|
|
82942
|
+
const step = frame.steps[frame.index];
|
|
82943
|
+
const blocking = this.beginStep(step, frame);
|
|
82944
|
+
if (blocking) {
|
|
82945
|
+
// Tick the freshly-pushed child immediately with the carried time on the next loop turn.
|
|
82946
|
+
frame.child = blocking;
|
|
82947
|
+
continue;
|
|
82948
|
+
}
|
|
82949
|
+
frame.index++;
|
|
82950
|
+
// A non-blocking step consumes no time; keep the remaining delta for the following step.
|
|
82951
|
+
}
|
|
82952
|
+
}
|
|
82953
|
+
tickParallel(frame, deltaInSeconds) {
|
|
82954
|
+
frame.branches = frame.branches.filter((branch)=>{
|
|
82955
|
+
const branchStack = [
|
|
82956
|
+
branch
|
|
82957
|
+
];
|
|
82958
|
+
this.tickFrames(branchStack, deltaInSeconds);
|
|
82959
|
+
return branchStack.length > 0;
|
|
82960
|
+
});
|
|
82961
|
+
// Parallel branches may finish at different times; we do not attempt to reconcile a single
|
|
82962
|
+
// leftover across them, so the join simply consumes the whole tick.
|
|
82963
|
+
return frame.branches.length > 0 ? {
|
|
82964
|
+
status: 'block'
|
|
82965
|
+
} : {
|
|
82966
|
+
status: 'pop'
|
|
82967
|
+
};
|
|
82968
|
+
}
|
|
82969
|
+
/**
|
|
82970
|
+
* Execute a non-blocking step immediately and return null, or return a frame to block on.
|
|
82971
|
+
*/ beginStep(step, scopeFrame) {
|
|
82972
|
+
const scope = scopeFrame.scope;
|
|
82973
|
+
switch(step.type){
|
|
82974
|
+
case 'sequence':
|
|
82975
|
+
{
|
|
82976
|
+
const child = this.makeSeqFrame(step.steps);
|
|
82977
|
+
// Inherit the parent scope so refs/currentPlayback carry into the nested sequence.
|
|
82978
|
+
child.scope = scope;
|
|
82979
|
+
return child;
|
|
82980
|
+
}
|
|
82981
|
+
case 'parallel':
|
|
82982
|
+
{
|
|
82983
|
+
// Each branch gets an isolated scope so currentPlayback/refs don't race (#7), but inherits
|
|
82984
|
+
// the parent's owner so concurrent branches stay concurrent through nested parallels.
|
|
82985
|
+
const branches = step.steps.map((child)=>{
|
|
82986
|
+
const branchScope = {
|
|
82987
|
+
currentPlaybackId: scope.currentPlaybackId,
|
|
82988
|
+
refs: {
|
|
82989
|
+
...scope.refs
|
|
82990
|
+
},
|
|
82991
|
+
owner: scope.owner
|
|
82992
|
+
};
|
|
82993
|
+
const seq = this.makeSeqFrame([
|
|
82994
|
+
child
|
|
82995
|
+
]);
|
|
82996
|
+
seq.scope = branchScope;
|
|
82997
|
+
return seq;
|
|
82998
|
+
});
|
|
82999
|
+
return {
|
|
83000
|
+
kind: 'parallel',
|
|
83001
|
+
branches
|
|
83002
|
+
};
|
|
83003
|
+
}
|
|
83004
|
+
case 'play':
|
|
83005
|
+
{
|
|
83006
|
+
const playback = this.animationSet.play(step.clip, this.resolvePlayOptions(step.options, scope));
|
|
83007
|
+
if (!playback) {
|
|
83008
|
+
return null;
|
|
83009
|
+
}
|
|
83010
|
+
this.attachPlayback(playback);
|
|
83011
|
+
if (scope.owner === 'concurrent') {
|
|
83012
|
+
// Remember concurrent ownership independently of the frames: a non-blocking keep-active
|
|
83013
|
+
// play drains out of `_concurrent` immediately, but its playback must still survive a
|
|
83014
|
+
// later main-flow replacement (#2).
|
|
83015
|
+
this._concurrentPlaybackIds.add(playback.id);
|
|
83016
|
+
}
|
|
83017
|
+
scope.currentPlaybackId = playback.id;
|
|
83018
|
+
if (step.id) {
|
|
83019
|
+
scope.refs[step.id] = playback.id;
|
|
83020
|
+
this._playbackRefs.set(step.id, playback.id);
|
|
83021
|
+
}
|
|
83022
|
+
scope.refs[playback.id] = playback.id;
|
|
83023
|
+
this._playbackRefs.set(playback.id, playback.id);
|
|
83024
|
+
if (step.wait === 'complete') {
|
|
83025
|
+
return {
|
|
83026
|
+
kind: 'playWait',
|
|
83027
|
+
playbackId: playback.id
|
|
83028
|
+
};
|
|
83029
|
+
}
|
|
83030
|
+
return null;
|
|
83031
|
+
}
|
|
83032
|
+
case 'stop':
|
|
83033
|
+
{
|
|
83034
|
+
const playback = this.resolvePlayback(step.target, scope);
|
|
83035
|
+
if (playback) {
|
|
83036
|
+
playback.stop(step.options);
|
|
83037
|
+
} else if (!step.target) {
|
|
83038
|
+
this._ownedPlaybacks.forEach((item)=>item.stop(step.options));
|
|
83039
|
+
}
|
|
83040
|
+
return null;
|
|
83041
|
+
}
|
|
83042
|
+
case 'wait':
|
|
83043
|
+
return step.seconds > 0 ? {
|
|
83044
|
+
kind: 'wait',
|
|
83045
|
+
remaining: step.seconds
|
|
83046
|
+
} : null;
|
|
83047
|
+
case 'waitEvent':
|
|
83048
|
+
return {
|
|
83049
|
+
kind: 'waitEvent',
|
|
83050
|
+
event: step.event
|
|
83051
|
+
};
|
|
83052
|
+
case 'waitMarker':
|
|
83053
|
+
{
|
|
83054
|
+
const playback = this.resolvePlayback(step.target, scope) ?? this.scopeCurrentPlayback(scope);
|
|
83055
|
+
if (!playback) {
|
|
83056
|
+
return null;
|
|
83057
|
+
}
|
|
83058
|
+
return {
|
|
83059
|
+
kind: 'waitMarker',
|
|
83060
|
+
marker: step.marker,
|
|
83061
|
+
playbackId: playback.id,
|
|
83062
|
+
satisfied: false
|
|
83063
|
+
};
|
|
83064
|
+
}
|
|
83065
|
+
case 'waitFrame':
|
|
83066
|
+
{
|
|
83067
|
+
const playback = this.resolvePlayback(step.target, scope) ?? this.scopeCurrentPlayback(scope);
|
|
83068
|
+
if (!playback) {
|
|
83069
|
+
return null;
|
|
83070
|
+
}
|
|
83071
|
+
return {
|
|
83072
|
+
kind: 'waitFrame',
|
|
83073
|
+
frame: step.frame,
|
|
83074
|
+
playbackId: playback.id,
|
|
83075
|
+
satisfied: false
|
|
83076
|
+
};
|
|
83077
|
+
}
|
|
83078
|
+
case 'emit':
|
|
83079
|
+
this.dispatchEvent('emit', step.event, step.payload);
|
|
83080
|
+
return null;
|
|
83081
|
+
}
|
|
83082
|
+
}
|
|
83083
|
+
resolvePlayOptions(options, scope) {
|
|
83084
|
+
const target = options?.sync?.target;
|
|
83085
|
+
if (!target) {
|
|
83086
|
+
return options;
|
|
83087
|
+
}
|
|
83088
|
+
const mapped = this.resolvePlaybackRef(target, scope);
|
|
83089
|
+
if (!mapped) {
|
|
83090
|
+
return options;
|
|
83091
|
+
}
|
|
83092
|
+
return {
|
|
83093
|
+
...options,
|
|
83094
|
+
sync: {
|
|
83095
|
+
...options.sync,
|
|
83096
|
+
target: mapped
|
|
83097
|
+
}
|
|
83098
|
+
};
|
|
83099
|
+
}
|
|
83100
|
+
resolvePlaybackRef(target, scope) {
|
|
83101
|
+
return scope.refs[target] ?? this._playbackRefs.get(target) ?? null;
|
|
83102
|
+
}
|
|
83103
|
+
tickWaitMarker(frame) {
|
|
83104
|
+
if (frame.satisfied || !frame.playbackId) {
|
|
83105
|
+
return {
|
|
83106
|
+
status: 'pop'
|
|
83107
|
+
};
|
|
83108
|
+
}
|
|
83109
|
+
const playback = this._ownedPlaybacks.get(frame.playbackId);
|
|
83110
|
+
if (!playback || playback.state === 'stopped' || playback.state === 'completed') {
|
|
83111
|
+
return {
|
|
83112
|
+
status: 'pop'
|
|
83113
|
+
};
|
|
83114
|
+
}
|
|
83115
|
+
const crossed = this._crossedMarkers.get(frame.playbackId);
|
|
83116
|
+
if (crossed && crossed.has(frame.marker)) {
|
|
83117
|
+
return {
|
|
83118
|
+
status: 'pop'
|
|
83119
|
+
};
|
|
83120
|
+
}
|
|
83121
|
+
return {
|
|
83122
|
+
status: 'block'
|
|
83123
|
+
};
|
|
83124
|
+
}
|
|
83125
|
+
tickWaitFrame(frame) {
|
|
83126
|
+
if (frame.satisfied || frame.playbackId === null) {
|
|
83127
|
+
return {
|
|
83128
|
+
status: 'pop'
|
|
83129
|
+
};
|
|
83130
|
+
}
|
|
83131
|
+
const playback = this._ownedPlaybacks.get(frame.playbackId);
|
|
83132
|
+
if (!playback || playback.state === 'stopped' || playback.state === 'completed') {
|
|
83133
|
+
return {
|
|
83134
|
+
status: 'pop'
|
|
83135
|
+
};
|
|
83136
|
+
}
|
|
83137
|
+
const crossed = this._crossedFrames.get(frame.playbackId);
|
|
83138
|
+
if (crossed && crossed.has(frame.frame)) {
|
|
83139
|
+
return {
|
|
83140
|
+
status: 'pop'
|
|
83141
|
+
};
|
|
83142
|
+
}
|
|
83143
|
+
return {
|
|
83144
|
+
status: 'block'
|
|
83145
|
+
};
|
|
83146
|
+
}
|
|
83147
|
+
tickPlayWait(frame) {
|
|
83148
|
+
const playback = this._ownedPlaybacks.get(frame.playbackId);
|
|
83149
|
+
if (!playback || playback.state === 'stopped' || playback.state === 'completed') {
|
|
83150
|
+
return {
|
|
83151
|
+
status: 'pop'
|
|
83152
|
+
};
|
|
83153
|
+
}
|
|
83154
|
+
return {
|
|
83155
|
+
status: 'block'
|
|
83156
|
+
};
|
|
83157
|
+
}
|
|
83158
|
+
attachPlayback(playback) {
|
|
83159
|
+
this._ownedPlaybacks.set(playback.id, playback);
|
|
83160
|
+
playback.on('marker', this.onPlaybackMarker);
|
|
83161
|
+
playback.on('frame', this.onPlaybackFrame);
|
|
83162
|
+
playback.on('stop', this.onPlaybackEnd);
|
|
83163
|
+
playback.on('complete', this.onPlaybackComplete);
|
|
83164
|
+
}
|
|
83165
|
+
detachPlayback(playback) {
|
|
83166
|
+
playback.off('marker', this.onPlaybackMarker);
|
|
83167
|
+
playback.off('frame', this.onPlaybackFrame);
|
|
83168
|
+
playback.off('stop', this.onPlaybackEnd);
|
|
83169
|
+
playback.off('complete', this.onPlaybackComplete);
|
|
83170
|
+
}
|
|
83171
|
+
forgetPlayback(playback) {
|
|
83172
|
+
this.detachPlayback(playback);
|
|
83173
|
+
this._ownedPlaybacks.delete(playback.id);
|
|
83174
|
+
this._concurrentPlaybackIds.delete(playback.id);
|
|
83175
|
+
this.forgetPlaybackRefs(playback.id);
|
|
83176
|
+
}
|
|
83177
|
+
/**
|
|
83178
|
+
* Cleanup when an owned playback ends (externally or naturally). Only touches runner-local
|
|
83179
|
+
* bookkeeping, so it is safe to run inside `AnimationSet.update`'s playback loop. Frames blocked
|
|
83180
|
+
* on this playback observe its absence on the next tick and unblock.
|
|
83181
|
+
*/ onPlaybackEnd = (event)=>{
|
|
83182
|
+
const playback = this._ownedPlaybacks.get(event.playback.id);
|
|
83183
|
+
if (playback) {
|
|
83184
|
+
this.forgetPlayback(playback);
|
|
83185
|
+
}
|
|
83186
|
+
};
|
|
83187
|
+
onPlaybackComplete = (event)=>{
|
|
83188
|
+
this._lastCompletedPlaybackId = event.playback.id;
|
|
83189
|
+
const playback = this._ownedPlaybacks.get(event.playback.id);
|
|
83190
|
+
if (playback) {
|
|
83191
|
+
this.forgetPlayback(playback);
|
|
83192
|
+
}
|
|
83193
|
+
};
|
|
83194
|
+
onPlaybackMarker = (event)=>{
|
|
83195
|
+
const id = event.playback.id;
|
|
83196
|
+
let set = this._crossedMarkers.get(id);
|
|
83197
|
+
if (!set) {
|
|
83198
|
+
set = new Set();
|
|
83199
|
+
this._crossedMarkers.set(id, set);
|
|
83200
|
+
}
|
|
83201
|
+
if (event.marker.id !== undefined) {
|
|
83202
|
+
set.add(event.marker.id);
|
|
83203
|
+
}
|
|
83204
|
+
set.add(event.marker.name);
|
|
83205
|
+
};
|
|
83206
|
+
onPlaybackFrame = (event)=>{
|
|
83207
|
+
const id = event.playback.id;
|
|
83208
|
+
let set = this._crossedFrames.get(id);
|
|
83209
|
+
if (!set) {
|
|
83210
|
+
set = new Set();
|
|
83211
|
+
this._crossedFrames.set(id, set);
|
|
83212
|
+
}
|
|
83213
|
+
set.add(event.frame);
|
|
83214
|
+
};
|
|
83215
|
+
resolvePlayback(target, scope) {
|
|
83216
|
+
if (!target) {
|
|
83217
|
+
return null;
|
|
83218
|
+
}
|
|
83219
|
+
const mapped = this.resolvePlaybackRef(target, scope);
|
|
83220
|
+
if (mapped) {
|
|
83221
|
+
const owned = this._ownedPlaybacks.get(mapped);
|
|
83222
|
+
if (owned) {
|
|
83223
|
+
return owned;
|
|
83224
|
+
}
|
|
83225
|
+
}
|
|
83226
|
+
return this._ownedPlaybacks.get(target) ?? this.animationSet.getPlayback(target);
|
|
83227
|
+
}
|
|
83228
|
+
forgetPlaybackRefs(playbackId) {
|
|
83229
|
+
[
|
|
83230
|
+
...this._playbackRefs.entries()
|
|
83231
|
+
].forEach(([ref, id])=>{
|
|
83232
|
+
if (id === playbackId) {
|
|
83233
|
+
this._playbackRefs.delete(ref);
|
|
83234
|
+
}
|
|
83235
|
+
});
|
|
83236
|
+
}
|
|
83237
|
+
scopeCurrentPlayback(scope) {
|
|
83238
|
+
return scope.currentPlaybackId ? this._ownedPlaybacks.get(scope.currentPlaybackId) ?? null : null;
|
|
83239
|
+
}
|
|
83240
|
+
hasWaiterFor(event) {
|
|
83241
|
+
const inFrame = (frame)=>{
|
|
83242
|
+
switch(frame.kind){
|
|
83243
|
+
case 'waitEvent':
|
|
83244
|
+
return frame.event === event;
|
|
83245
|
+
case 'seq':
|
|
83246
|
+
return frame.child ? inFrame(frame.child) : false;
|
|
83247
|
+
case 'parallel':
|
|
83248
|
+
return frame.branches.some(inFrame);
|
|
83249
|
+
default:
|
|
83250
|
+
return false;
|
|
83251
|
+
}
|
|
83252
|
+
};
|
|
83253
|
+
return this._stack.some(inFrame) || this._concurrent.some(inFrame);
|
|
83254
|
+
}
|
|
83255
|
+
/** Stop only the main control flow (used when a response replaces it). */ stopMainFlow(options) {
|
|
83256
|
+
const stopOptions = options ?? {
|
|
83257
|
+
reason: 'interrupted'
|
|
83258
|
+
};
|
|
83259
|
+
// Stop every playback owned by the main flow, not just those still referenced by `_stack`:
|
|
83260
|
+
// a sequence that already drained may have left a looping clip playing (e.g. `play idle` with
|
|
83261
|
+
// `repeat: 0`), and replacing the main flow must stop it. Playbacks owned by concurrent
|
|
83262
|
+
// (keep-active) branches are independent parallel tracks and are preserved — tracked by id so
|
|
83263
|
+
// they survive even after their branch frames drained.
|
|
83264
|
+
this._ownedPlaybacks.forEach((playback, id)=>{
|
|
83265
|
+
if (this._concurrentPlaybackIds.has(id)) {
|
|
83266
|
+
return;
|
|
83267
|
+
}
|
|
83268
|
+
this.detachPlayback(playback);
|
|
83269
|
+
playback.stop(stopOptions);
|
|
83270
|
+
this._ownedPlaybacks.delete(id);
|
|
83271
|
+
this.forgetPlaybackRefs(id);
|
|
83272
|
+
});
|
|
83273
|
+
this._stack = [];
|
|
83274
|
+
}
|
|
83275
|
+
collectScopePlaybackIds(frames) {
|
|
83276
|
+
const ids = new Set();
|
|
83277
|
+
const visit = (frame)=>{
|
|
83278
|
+
if (frame.kind === 'seq') {
|
|
83279
|
+
Object.values(frame.scope.refs).forEach((id)=>ids.add(id));
|
|
83280
|
+
if (frame.scope.currentPlaybackId) {
|
|
83281
|
+
ids.add(frame.scope.currentPlaybackId);
|
|
83282
|
+
}
|
|
83283
|
+
if (frame.child) {
|
|
83284
|
+
visit(frame.child);
|
|
83285
|
+
}
|
|
83286
|
+
} else if (frame.kind === 'parallel') {
|
|
83287
|
+
frame.branches.forEach(visit);
|
|
83288
|
+
}
|
|
83289
|
+
};
|
|
83290
|
+
frames.forEach(visit);
|
|
83291
|
+
return ids;
|
|
83292
|
+
}
|
|
83293
|
+
cloneFrame(frame) {
|
|
83294
|
+
switch(frame.kind){
|
|
83295
|
+
case 'seq':
|
|
83296
|
+
return {
|
|
83297
|
+
kind: 'seq',
|
|
83298
|
+
steps: frame.steps,
|
|
83299
|
+
index: frame.index,
|
|
83300
|
+
scope: {
|
|
83301
|
+
currentPlaybackId: frame.scope.currentPlaybackId,
|
|
83302
|
+
refs: {
|
|
83303
|
+
...frame.scope.refs
|
|
83304
|
+
},
|
|
83305
|
+
owner: frame.scope.owner
|
|
83306
|
+
},
|
|
83307
|
+
child: frame.child ? this.cloneFrame(frame.child) : null
|
|
83308
|
+
};
|
|
83309
|
+
case 'parallel':
|
|
83310
|
+
return {
|
|
83311
|
+
kind: 'parallel',
|
|
83312
|
+
branches: frame.branches.map((b)=>this.cloneFrame(b))
|
|
83313
|
+
};
|
|
83314
|
+
case 'wait':
|
|
83315
|
+
return {
|
|
83316
|
+
kind: 'wait',
|
|
83317
|
+
remaining: frame.remaining
|
|
83318
|
+
};
|
|
83319
|
+
case 'waitEvent':
|
|
83320
|
+
return {
|
|
83321
|
+
kind: 'waitEvent',
|
|
83322
|
+
event: frame.event
|
|
83323
|
+
};
|
|
83324
|
+
case 'waitMarker':
|
|
83325
|
+
return {
|
|
83326
|
+
...frame
|
|
83327
|
+
};
|
|
83328
|
+
case 'waitFrame':
|
|
83329
|
+
return {
|
|
83330
|
+
...frame
|
|
83331
|
+
};
|
|
83332
|
+
case 'playWait':
|
|
83333
|
+
return {
|
|
83334
|
+
...frame
|
|
83335
|
+
};
|
|
83336
|
+
}
|
|
83337
|
+
}
|
|
83338
|
+
reattachPlaybacks(frames) {
|
|
83339
|
+
const ids = this.collectAllPlaybackIds(frames);
|
|
83340
|
+
ids.forEach((id)=>{
|
|
83341
|
+
if (this._ownedPlaybacks.has(id)) {
|
|
83342
|
+
return;
|
|
83343
|
+
}
|
|
83344
|
+
const playback = this.findLivePlayback(id);
|
|
83345
|
+
if (playback) {
|
|
83346
|
+
this.attachPlayback(playback);
|
|
83347
|
+
}
|
|
83348
|
+
});
|
|
83349
|
+
}
|
|
83350
|
+
collectAllPlaybackIds(frames) {
|
|
83351
|
+
const ids = this.collectScopePlaybackIds(frames);
|
|
83352
|
+
const visit = (frame)=>{
|
|
83353
|
+
if (frame.kind === 'playWait') {
|
|
83354
|
+
ids.add(frame.playbackId);
|
|
83355
|
+
} else if ((frame.kind === 'waitMarker' || frame.kind === 'waitFrame') && frame.playbackId) {
|
|
83356
|
+
ids.add(frame.playbackId);
|
|
83357
|
+
} else if (frame.kind === 'seq' && frame.child) {
|
|
83358
|
+
visit(frame.child);
|
|
83359
|
+
} else if (frame.kind === 'parallel') {
|
|
83360
|
+
frame.branches.forEach(visit);
|
|
83361
|
+
}
|
|
83362
|
+
};
|
|
83363
|
+
frames.forEach(visit);
|
|
83364
|
+
return ids;
|
|
83365
|
+
}
|
|
83366
|
+
findLivePlayback(id) {
|
|
83367
|
+
return this.animationSet.getPlaybacks().find((playback)=>playback.id === id) ?? null;
|
|
83368
|
+
}
|
|
83369
|
+
}
|
|
83370
|
+
|
|
83371
|
+
/**
|
|
83372
|
+
* Event-driven animation state controller.
|
|
83373
|
+
*
|
|
83374
|
+
* Each state owns one serializable timeline. External gameplay events are dispatched to the
|
|
83375
|
+
* current timeline first, then to the current state's response table, so different states can
|
|
83376
|
+
* respond to the same event differently.
|
|
83377
|
+
* @public
|
|
83378
|
+
*/ class AnimationController extends Observable {
|
|
83379
|
+
/**
|
|
83380
|
+
* Animation set used to create playbacks for all state timelines.
|
|
83381
|
+
*/ animationSet;
|
|
83382
|
+
_states;
|
|
83383
|
+
_currentState;
|
|
83384
|
+
_runner;
|
|
83385
|
+
_onRunnerComplete;
|
|
83386
|
+
_onRunnerEmit;
|
|
83387
|
+
/**
|
|
83388
|
+
* Create a controller for an animation set.
|
|
83389
|
+
*
|
|
83390
|
+
* @param animationSet - Animation set that owns the clips and active playbacks.
|
|
83391
|
+
*/ constructor(animationSet){
|
|
83392
|
+
super();
|
|
83393
|
+
this.animationSet = animationSet;
|
|
83394
|
+
this._states = new Map();
|
|
83395
|
+
this._currentState = null;
|
|
83396
|
+
this._runner = null;
|
|
83397
|
+
this._onRunnerComplete = null;
|
|
83398
|
+
this._onRunnerEmit = null;
|
|
83399
|
+
}
|
|
83400
|
+
/**
|
|
83401
|
+
* Current state name.
|
|
83402
|
+
*
|
|
83403
|
+
* @returns The active state name, or null when the controller is stopped or has not entered a state.
|
|
83404
|
+
*/ get currentState() {
|
|
83405
|
+
return this._currentState;
|
|
83406
|
+
}
|
|
83407
|
+
/**
|
|
83408
|
+
* Current timeline runner.
|
|
83409
|
+
*
|
|
83410
|
+
* @returns The active timeline runner, or null when no state is running.
|
|
83411
|
+
*/ get runner() {
|
|
83412
|
+
return this._runner;
|
|
83413
|
+
}
|
|
83414
|
+
/**
|
|
83415
|
+
* Register or replace a named state definition.
|
|
83416
|
+
*
|
|
83417
|
+
* @param name - Unique state name.
|
|
83418
|
+
* @param definition - Timeline and event response configuration for the state.
|
|
83419
|
+
* @returns This controller for chaining.
|
|
83420
|
+
*/ addState(name, definition) {
|
|
83421
|
+
if (this._states.has(name)) {
|
|
83422
|
+
console.warn(`AnimationController state ${name} already exists; overwriting`);
|
|
83423
|
+
}
|
|
83424
|
+
this._states.set(name, definition);
|
|
83425
|
+
return this;
|
|
83426
|
+
}
|
|
83427
|
+
/**
|
|
83428
|
+
* Test whether a state has been registered.
|
|
83429
|
+
*
|
|
83430
|
+
* @param name - State name to look up.
|
|
83431
|
+
* @returns True if the controller contains a state with the given name; otherwise false.
|
|
83432
|
+
*/ hasState(name) {
|
|
83433
|
+
return this._states.has(name);
|
|
83434
|
+
}
|
|
83435
|
+
/**
|
|
83436
|
+
* Enter a registered state.
|
|
83437
|
+
*
|
|
83438
|
+
* If the requested state is already current and `options.force` is not set, this returns the
|
|
83439
|
+
* existing runner without restarting the timeline. When a transition duration is provided, the
|
|
83440
|
+
* previous runner fades out while the entry plays of the new state fade in.
|
|
83441
|
+
*
|
|
83442
|
+
* @param name - State name to enter.
|
|
83443
|
+
* @param options - Optional transition, re-entry, and stop behavior.
|
|
83444
|
+
* @returns The active runner for the entered state, or null if the state does not exist.
|
|
83445
|
+
*/ setState(name, options) {
|
|
83446
|
+
const definition = this._states.get(name);
|
|
83447
|
+
if (!definition) {
|
|
83448
|
+
console.error(`AnimationController state ${name} not exists`);
|
|
83449
|
+
return null;
|
|
83450
|
+
}
|
|
83451
|
+
if (!options?.force && this._currentState === name) {
|
|
83452
|
+
return this._runner;
|
|
83453
|
+
}
|
|
83454
|
+
const previousState = this._currentState;
|
|
83455
|
+
const transition = Math.max(options?.transition ?? definition.transition ?? 0, 0);
|
|
83456
|
+
const returnTarget = this.resolveReturnTarget(options?.returnTo, previousState, options?.returnTransition);
|
|
83457
|
+
this.detachRunner();
|
|
83458
|
+
if (transition > 0) {
|
|
83459
|
+
this._runner?.stop({
|
|
83460
|
+
fadeOut: transition,
|
|
83461
|
+
reason: 'interrupted'
|
|
83462
|
+
});
|
|
83463
|
+
} else {
|
|
83464
|
+
this._runner?.stop(options?.stop ?? {
|
|
83465
|
+
reason: 'interrupted'
|
|
83466
|
+
});
|
|
83467
|
+
}
|
|
83468
|
+
const timeline = new AnimationTimeline(prepareTimelineForTransition(definition.timeline, transition, returnTarget?.transition, options?.sync));
|
|
83469
|
+
this._runner = timeline.createRunner(this.animationSet);
|
|
83470
|
+
const runner = this._runner;
|
|
83471
|
+
this.attachRunner(runner, name, returnTarget);
|
|
83472
|
+
// Enter the new state *before* starting the runner: start() flushes synchronously, so any
|
|
83473
|
+
// initial `emit`/`statecomplete` must observe the controller already in `name`. Otherwise a
|
|
83474
|
+
// listener calling dispatch() would route against the previous state.
|
|
83475
|
+
this._currentState = name;
|
|
83476
|
+
this.dispatchEvent('statechange', name, previousState);
|
|
83477
|
+
// The statechange listener may have re-entered (stop() or another setState()), swapping out or
|
|
83478
|
+
// clearing `_runner`. Only start the runner we created if it is still the active one.
|
|
83479
|
+
if (this._runner === runner && this._currentState === name) {
|
|
83480
|
+
runner.start();
|
|
83481
|
+
}
|
|
83482
|
+
// If a reentrant listener superseded us, `_runner` is the now-active runner (or null after a
|
|
83483
|
+
// reentrant stop()); return that rather than a runner we never started.
|
|
83484
|
+
return this._runner;
|
|
83485
|
+
}
|
|
83486
|
+
/**
|
|
83487
|
+
* Dispatch a gameplay event to the active state.
|
|
83488
|
+
*
|
|
83489
|
+
* The active timeline receives the event first. If it does not handle the event, the current
|
|
83490
|
+
* state's response table may consume it, enqueue or run steps, or transition to another state.
|
|
83491
|
+
*
|
|
83492
|
+
* @param event - Event name to dispatch.
|
|
83493
|
+
* @param payload - Optional event payload passed through result notifications.
|
|
83494
|
+
* @returns The resolved handling result for the event.
|
|
83495
|
+
*/ dispatch(event, payload) {
|
|
83496
|
+
if (!this._currentState || !this._runner) {
|
|
83497
|
+
return this.emitResult({
|
|
83498
|
+
handled: false,
|
|
83499
|
+
policy: 'none',
|
|
83500
|
+
event,
|
|
83501
|
+
payload
|
|
83502
|
+
});
|
|
83503
|
+
}
|
|
83504
|
+
const timelineResult = this._runner.dispatch(event, payload);
|
|
83505
|
+
if (timelineResult.handled) {
|
|
83506
|
+
return this.emitResult(timelineResult);
|
|
83507
|
+
}
|
|
83508
|
+
const response = this._states.get(this._currentState)?.responses?.find((item)=>item.event === event);
|
|
83509
|
+
if (!response || response.target.ignore) {
|
|
83510
|
+
return this.emitResult({
|
|
83511
|
+
handled: false,
|
|
83512
|
+
policy: response ? 'ignore' : 'none',
|
|
83513
|
+
event,
|
|
83514
|
+
payload
|
|
83515
|
+
});
|
|
83516
|
+
}
|
|
83517
|
+
if (response.target.consume) {
|
|
83518
|
+
return this.emitResult({
|
|
83519
|
+
handled: true,
|
|
83520
|
+
policy: 'consume',
|
|
83521
|
+
event,
|
|
83522
|
+
payload
|
|
83523
|
+
});
|
|
83524
|
+
}
|
|
83525
|
+
if (response.target.targetState !== undefined) {
|
|
83526
|
+
const transition = typeof response.onActive === 'object' ? response.onActive.fadeOut : undefined;
|
|
83527
|
+
const runner = this.setState(response.target.targetState, {
|
|
83528
|
+
transition,
|
|
83529
|
+
returnTo: response.target.returnTo,
|
|
83530
|
+
returnTransition: response.target.returnTransition
|
|
83531
|
+
});
|
|
83532
|
+
// setState returns null when the target state is not registered: a config error must not be
|
|
83533
|
+
// reported as a successfully handled transition.
|
|
83534
|
+
if (!runner) {
|
|
83535
|
+
return this.emitResult({
|
|
83536
|
+
handled: false,
|
|
83537
|
+
policy: 'transition',
|
|
83538
|
+
event,
|
|
83539
|
+
payload
|
|
83540
|
+
});
|
|
83541
|
+
}
|
|
83542
|
+
return this.emitResult({
|
|
83543
|
+
handled: true,
|
|
83544
|
+
policy: 'transition',
|
|
83545
|
+
event,
|
|
83546
|
+
payload
|
|
83547
|
+
});
|
|
83548
|
+
}
|
|
83549
|
+
const steps = response.target.steps;
|
|
83550
|
+
if (!steps?.length) {
|
|
83551
|
+
return this.emitResult({
|
|
83552
|
+
handled: false,
|
|
83553
|
+
policy: 'none',
|
|
83554
|
+
event,
|
|
83555
|
+
payload
|
|
83556
|
+
});
|
|
83557
|
+
}
|
|
83558
|
+
if (response.enqueue) {
|
|
83559
|
+
this._runner.enqueue(steps);
|
|
83560
|
+
return this.emitResult({
|
|
83561
|
+
handled: true,
|
|
83562
|
+
policy: 'enqueue',
|
|
83563
|
+
event,
|
|
83564
|
+
payload
|
|
83565
|
+
});
|
|
83566
|
+
}
|
|
83567
|
+
const disposition = response.onActive ?? 'stop';
|
|
83568
|
+
if (disposition === 'keep') {
|
|
83569
|
+
this._runner.runConcurrent(steps);
|
|
83570
|
+
} else {
|
|
83571
|
+
const stopOptions = typeof disposition === 'object' ? {
|
|
83572
|
+
...disposition,
|
|
83573
|
+
reason: 'interrupted'
|
|
83574
|
+
} : undefined;
|
|
83575
|
+
this.detachRunner();
|
|
83576
|
+
this._runner.stop(stopOptions);
|
|
83577
|
+
this._runner = new AnimationTimeline(steps).createRunner(this.animationSet);
|
|
83578
|
+
this.attachRunner(this._runner, this._currentState);
|
|
83579
|
+
this._runner.start();
|
|
83580
|
+
}
|
|
83581
|
+
return this.emitResult({
|
|
83582
|
+
handled: true,
|
|
83583
|
+
policy: 'steps',
|
|
83584
|
+
event,
|
|
83585
|
+
payload
|
|
83586
|
+
});
|
|
83587
|
+
}
|
|
83588
|
+
/**
|
|
83589
|
+
* Stop the active state and clear the current state.
|
|
83590
|
+
*
|
|
83591
|
+
* @param options - Optional stop behavior applied to playbacks owned by the active runner.
|
|
83592
|
+
* @returns void
|
|
83593
|
+
*/ stop(options) {
|
|
83594
|
+
const previousState = this._currentState;
|
|
83595
|
+
this.detachRunner();
|
|
83596
|
+
this._runner?.stop(options);
|
|
83597
|
+
this._runner = null;
|
|
83598
|
+
this._currentState = null;
|
|
83599
|
+
if (previousState !== null) {
|
|
83600
|
+
this.dispatchEvent('statechange', null, previousState);
|
|
83601
|
+
}
|
|
83602
|
+
}
|
|
83603
|
+
/**
|
|
83604
|
+
* Stop playback and remove all registered states.
|
|
83605
|
+
*
|
|
83606
|
+
* @returns void
|
|
83607
|
+
*/ dispose() {
|
|
83608
|
+
this.stop();
|
|
83609
|
+
this._states.clear();
|
|
83610
|
+
}
|
|
83611
|
+
emitResult(result) {
|
|
83612
|
+
this.dispatchEvent('event', result.event, result.payload, result);
|
|
83613
|
+
return result;
|
|
83614
|
+
}
|
|
83615
|
+
resolveReturnTarget(returnTo, previousState, returnTransition) {
|
|
83616
|
+
if (returnTo === undefined) {
|
|
83617
|
+
return null;
|
|
83618
|
+
}
|
|
83619
|
+
const state = returnTo === true ? previousState : returnTo;
|
|
83620
|
+
if (!state) {
|
|
83621
|
+
return null;
|
|
83622
|
+
}
|
|
83623
|
+
const definition = this._states.get(state);
|
|
83624
|
+
if (!definition) {
|
|
83625
|
+
console.error(`AnimationController return state ${state} not exists`);
|
|
83626
|
+
return null;
|
|
83627
|
+
}
|
|
83628
|
+
return {
|
|
83629
|
+
state,
|
|
83630
|
+
transition: returnTransition ?? definition.transition
|
|
83631
|
+
};
|
|
83632
|
+
}
|
|
83633
|
+
attachRunner(runner, state, returnTarget) {
|
|
83634
|
+
this._onRunnerComplete = ()=>{
|
|
83635
|
+
this.dispatchEvent('statecomplete', state);
|
|
83636
|
+
if (returnTarget && this._runner === runner && this._currentState === state) {
|
|
83637
|
+
const sync = returnTarget.transition && runner.lastCompletedPlaybackId ? {
|
|
83638
|
+
target: runner.lastCompletedPlaybackId,
|
|
83639
|
+
mode: 'normalized'
|
|
83640
|
+
} : undefined;
|
|
83641
|
+
this.setState(returnTarget.state, {
|
|
83642
|
+
transition: returnTarget.transition,
|
|
83643
|
+
sync
|
|
83644
|
+
});
|
|
83645
|
+
}
|
|
83646
|
+
};
|
|
83647
|
+
this._onRunnerEmit = (event, payload)=>{
|
|
83648
|
+
this.dispatchEvent('emit', event, payload);
|
|
83649
|
+
};
|
|
83650
|
+
runner.on('complete', this._onRunnerComplete);
|
|
83651
|
+
runner.on('emit', this._onRunnerEmit);
|
|
83652
|
+
}
|
|
83653
|
+
detachRunner() {
|
|
83654
|
+
if (this._runner) {
|
|
83655
|
+
if (this._onRunnerComplete) {
|
|
83656
|
+
this._runner.off('complete', this._onRunnerComplete);
|
|
83657
|
+
}
|
|
83658
|
+
if (this._onRunnerEmit) {
|
|
83659
|
+
this._runner.off('emit', this._onRunnerEmit);
|
|
83660
|
+
}
|
|
83661
|
+
}
|
|
83662
|
+
this._onRunnerComplete = null;
|
|
83663
|
+
this._onRunnerEmit = null;
|
|
83664
|
+
}
|
|
83665
|
+
}
|
|
83666
|
+
function prepareTimelineForTransition(definition, entryTransition, returnTransition, entrySync) {
|
|
83667
|
+
let timeline = definition;
|
|
83668
|
+
if (entrySync) {
|
|
83669
|
+
timeline = withEntrySync(timeline, entrySync);
|
|
83670
|
+
}
|
|
83671
|
+
const completionFadeOut = Math.max(returnTransition ?? 0, 0);
|
|
83672
|
+
if (completionFadeOut > 0) {
|
|
83673
|
+
timeline = withCompletionFadeOut(timeline, completionFadeOut);
|
|
83674
|
+
}
|
|
83675
|
+
return entryTransition > 0 ? withFadeIn(timeline, entryTransition) : timeline;
|
|
83676
|
+
}
|
|
83677
|
+
/**
|
|
83678
|
+
* Return a copy of the timeline definition whose entry plays use `sync` unless they already
|
|
83679
|
+
* declare a more specific synchronization source.
|
|
83680
|
+
*/ function withEntrySync(definition, sync) {
|
|
83681
|
+
const def = Array.isArray(definition) ? {
|
|
83682
|
+
steps: definition
|
|
83683
|
+
} : definition;
|
|
83684
|
+
return {
|
|
83685
|
+
steps: injectEntrySync(def.steps, sync).steps,
|
|
83686
|
+
responses: def.responses
|
|
83687
|
+
};
|
|
83688
|
+
}
|
|
83689
|
+
function injectEntrySync(steps, sync) {
|
|
83690
|
+
let blocked = false;
|
|
83691
|
+
const out = steps.map((step)=>{
|
|
83692
|
+
if (blocked) {
|
|
83693
|
+
return step;
|
|
83694
|
+
}
|
|
83695
|
+
switch(step.type){
|
|
83696
|
+
case 'play':
|
|
83697
|
+
if (step.wait === 'complete') {
|
|
83698
|
+
blocked = true;
|
|
83699
|
+
}
|
|
83700
|
+
return {
|
|
83701
|
+
...step,
|
|
83702
|
+
options: {
|
|
83703
|
+
...step.options,
|
|
83704
|
+
sync: step.options?.sync ?? sync
|
|
83705
|
+
}
|
|
83706
|
+
};
|
|
83707
|
+
case 'sequence':
|
|
83708
|
+
{
|
|
83709
|
+
const result = injectEntrySync(step.steps, sync);
|
|
83710
|
+
blocked = result.blocked;
|
|
83711
|
+
return {
|
|
83712
|
+
...step,
|
|
83713
|
+
steps: result.steps
|
|
83714
|
+
};
|
|
83715
|
+
}
|
|
83716
|
+
case 'parallel':
|
|
83717
|
+
{
|
|
83718
|
+
let anyBranchBlocked = false;
|
|
83719
|
+
const branches = step.steps.map((branch)=>{
|
|
83720
|
+
const result = injectEntrySync([
|
|
83721
|
+
branch
|
|
83722
|
+
], sync);
|
|
83723
|
+
anyBranchBlocked = anyBranchBlocked || result.blocked;
|
|
83724
|
+
return result.steps[0];
|
|
83725
|
+
});
|
|
83726
|
+
blocked = anyBranchBlocked;
|
|
83727
|
+
return {
|
|
83728
|
+
...step,
|
|
83729
|
+
steps: branches
|
|
83730
|
+
};
|
|
83731
|
+
}
|
|
83732
|
+
case 'wait':
|
|
83733
|
+
case 'waitEvent':
|
|
83734
|
+
case 'waitMarker':
|
|
83735
|
+
case 'waitFrame':
|
|
83736
|
+
blocked = true;
|
|
83737
|
+
return step;
|
|
83738
|
+
default:
|
|
83739
|
+
return step;
|
|
83740
|
+
}
|
|
83741
|
+
});
|
|
83742
|
+
return {
|
|
83743
|
+
steps: out,
|
|
83744
|
+
blocked
|
|
83745
|
+
};
|
|
83746
|
+
}
|
|
83747
|
+
/**
|
|
83748
|
+
* Return a copy of the timeline definition whose entry plays fade in over `duration`, so a state
|
|
83749
|
+
* transition cross-fades against the previous state's fade-out.
|
|
83750
|
+
*
|
|
83751
|
+
* "Entry plays" are every `play` that starts before the control flow first blocks: plays before a
|
|
83752
|
+
* `wait`/`waitEvent`/`waitMarker`/`waitFrame`, before a blocking `play` (`wait: 'complete'`), and
|
|
83753
|
+
* every branch of a leading `parallel` (all branches start simultaneously). This covers parallel
|
|
83754
|
+
* states whose branches would otherwise snap in at full weight while only the first faded.
|
|
83755
|
+
*/ function withFadeIn(definition, duration) {
|
|
83756
|
+
const def = Array.isArray(definition) ? {
|
|
83757
|
+
steps: definition
|
|
83758
|
+
} : definition;
|
|
83759
|
+
return {
|
|
83760
|
+
steps: injectEntryFadeIn(def.steps, duration).steps,
|
|
83761
|
+
responses: def.responses
|
|
83762
|
+
};
|
|
83763
|
+
}
|
|
83764
|
+
/**
|
|
83765
|
+
* Inject `fadeIn` into every entry play in `steps`. Returns the rewritten steps and whether the
|
|
83766
|
+
* flow blocks before reaching the end (so callers stop injecting into later, non-entry steps).
|
|
83767
|
+
*/ function injectEntryFadeIn(steps, duration) {
|
|
83768
|
+
let blocked = false;
|
|
83769
|
+
const out = steps.map((step)=>{
|
|
83770
|
+
if (blocked) {
|
|
83771
|
+
return step;
|
|
83772
|
+
}
|
|
83773
|
+
switch(step.type){
|
|
83774
|
+
case 'play':
|
|
83775
|
+
if (step.wait === 'complete') {
|
|
83776
|
+
blocked = true;
|
|
83777
|
+
}
|
|
83778
|
+
return {
|
|
83779
|
+
...step,
|
|
83780
|
+
options: {
|
|
83781
|
+
...step.options,
|
|
83782
|
+
fadeIn: duration
|
|
83783
|
+
}
|
|
83784
|
+
};
|
|
83785
|
+
case 'sequence':
|
|
83786
|
+
{
|
|
83787
|
+
const result = injectEntryFadeIn(step.steps, duration);
|
|
83788
|
+
blocked = result.blocked;
|
|
83789
|
+
return {
|
|
83790
|
+
...step,
|
|
83791
|
+
steps: result.steps
|
|
83792
|
+
};
|
|
83793
|
+
}
|
|
83794
|
+
case 'parallel':
|
|
83795
|
+
{
|
|
83796
|
+
// Every branch starts simultaneously, so inject into all of them. The parallel join only
|
|
83797
|
+
// blocks the steps that follow it if at least one branch blocks; if all branches are
|
|
83798
|
+
// non-blocking they drain in the same flush, so the following steps are still entry plays.
|
|
83799
|
+
let anyBranchBlocked = false;
|
|
83800
|
+
const branches = step.steps.map((branch)=>{
|
|
83801
|
+
const result = injectEntryFadeIn([
|
|
83802
|
+
branch
|
|
83803
|
+
], duration);
|
|
83804
|
+
anyBranchBlocked = anyBranchBlocked || result.blocked;
|
|
83805
|
+
return result.steps[0];
|
|
83806
|
+
});
|
|
83807
|
+
blocked = anyBranchBlocked;
|
|
83808
|
+
return {
|
|
83809
|
+
...step,
|
|
83810
|
+
steps: branches
|
|
83811
|
+
};
|
|
83812
|
+
}
|
|
83813
|
+
case 'wait':
|
|
83814
|
+
case 'waitEvent':
|
|
83815
|
+
case 'waitMarker':
|
|
83816
|
+
case 'waitFrame':
|
|
83817
|
+
blocked = true;
|
|
83818
|
+
return step;
|
|
83819
|
+
default:
|
|
83820
|
+
return step;
|
|
83821
|
+
}
|
|
83822
|
+
});
|
|
83823
|
+
return {
|
|
83824
|
+
steps: out,
|
|
83825
|
+
blocked
|
|
83826
|
+
};
|
|
83827
|
+
}
|
|
83828
|
+
/**
|
|
83829
|
+
* Return a copy of the timeline definition whose play steps keep completed playbacks alive long
|
|
83830
|
+
* enough to cross-fade into the automatic return state.
|
|
83831
|
+
*/ function withCompletionFadeOut(definition, duration) {
|
|
83832
|
+
const def = Array.isArray(definition) ? {
|
|
83833
|
+
steps: definition
|
|
83834
|
+
} : definition;
|
|
83835
|
+
return {
|
|
83836
|
+
steps: injectCompletionFadeOut(def.steps, duration),
|
|
83837
|
+
responses: def.responses
|
|
83838
|
+
};
|
|
83839
|
+
}
|
|
83840
|
+
function injectCompletionFadeOut(steps, duration) {
|
|
83841
|
+
return steps.map((step)=>{
|
|
83842
|
+
switch(step.type){
|
|
83843
|
+
case 'play':
|
|
83844
|
+
return {
|
|
83845
|
+
...step,
|
|
83846
|
+
options: {
|
|
83847
|
+
...step.options,
|
|
83848
|
+
completionFadeOut: step.options?.completionFadeOut ?? duration
|
|
83849
|
+
}
|
|
83850
|
+
};
|
|
83851
|
+
case 'sequence':
|
|
83852
|
+
return {
|
|
83853
|
+
...step,
|
|
83854
|
+
steps: injectCompletionFadeOut(step.steps, duration)
|
|
83855
|
+
};
|
|
83856
|
+
case 'parallel':
|
|
83857
|
+
return {
|
|
83858
|
+
...step,
|
|
83859
|
+
steps: step.steps.map((branch)=>injectCompletionFadeOut([
|
|
83860
|
+
branch
|
|
83861
|
+
], duration)[0])
|
|
83862
|
+
};
|
|
83863
|
+
default:
|
|
83864
|
+
return step;
|
|
83865
|
+
}
|
|
83866
|
+
});
|
|
83867
|
+
}
|
|
83868
|
+
|
|
81684
83869
|
/**
|
|
81685
83870
|
* Skeleton modifier for IK solvers.
|
|
81686
83871
|
*
|
|
@@ -88373,21 +90558,21 @@ class GPUClothWrapBinding {
|
|
|
88373
90558
|
}
|
|
88374
90559
|
}
|
|
88375
90560
|
|
|
88376
|
-
/**
|
|
88377
|
-
* Named object interface for model loading
|
|
88378
|
-
* @public
|
|
90561
|
+
/**
|
|
90562
|
+
* Named object interface for model loading
|
|
90563
|
+
* @public
|
|
88379
90564
|
*/ class NamedObject {
|
|
88380
90565
|
name;
|
|
88381
|
-
/**
|
|
88382
|
-
* Creates an instance of NamedObject
|
|
88383
|
-
* @param name - Name of the object
|
|
90566
|
+
/**
|
|
90567
|
+
* Creates an instance of NamedObject
|
|
90568
|
+
* @param name - Name of the object
|
|
88384
90569
|
*/ constructor(name){
|
|
88385
90570
|
this.name = name;
|
|
88386
90571
|
}
|
|
88387
90572
|
}
|
|
88388
|
-
/**
|
|
88389
|
-
* Heirarchical node interface for model loading
|
|
88390
|
-
* @public
|
|
90573
|
+
/**
|
|
90574
|
+
* Heirarchical node interface for model loading
|
|
90575
|
+
* @public
|
|
88391
90576
|
*/ class AssetHierarchyNode extends NamedObject {
|
|
88392
90577
|
_parent;
|
|
88393
90578
|
_position;
|
|
@@ -88401,10 +90586,10 @@ class GPUClothWrapBinding {
|
|
|
88401
90586
|
_weights;
|
|
88402
90587
|
_children;
|
|
88403
90588
|
_instances;
|
|
88404
|
-
/**
|
|
88405
|
-
* Creates an instance of AssetHierarchyNode
|
|
88406
|
-
* @param name - Name of the node
|
|
88407
|
-
* @param parent - Parent of the node
|
|
90589
|
+
/**
|
|
90590
|
+
* Creates an instance of AssetHierarchyNode
|
|
90591
|
+
* @param name - Name of the node
|
|
90592
|
+
* @param parent - Parent of the node
|
|
88408
90593
|
*/ constructor(name, model, parent){
|
|
88409
90594
|
super(name);
|
|
88410
90595
|
model.nodes.push(this);
|
|
@@ -88492,9 +90677,9 @@ class GPUClothWrapBinding {
|
|
|
88492
90677
|
child.computeTransforms(this._worldMatrix);
|
|
88493
90678
|
}
|
|
88494
90679
|
}
|
|
88495
|
-
/**
|
|
88496
|
-
* Adds a child to this node
|
|
88497
|
-
* @param child - The child node to be added
|
|
90680
|
+
/**
|
|
90681
|
+
* Adds a child to this node
|
|
90682
|
+
* @param child - The child node to be added
|
|
88498
90683
|
*/ addChild(child) {
|
|
88499
90684
|
if (!child || child.parent) {
|
|
88500
90685
|
throw new Error('AssetHierarchyNode.addChild(): invalid child node');
|
|
@@ -88502,9 +90687,9 @@ class GPUClothWrapBinding {
|
|
|
88502
90687
|
this._children.push(child);
|
|
88503
90688
|
child._parent = this;
|
|
88504
90689
|
}
|
|
88505
|
-
/**
|
|
88506
|
-
* Removes a child of this node
|
|
88507
|
-
* @param child - The child node to be removed
|
|
90690
|
+
/**
|
|
90691
|
+
* Removes a child of this node
|
|
90692
|
+
* @param child - The child node to be removed
|
|
88508
90693
|
*/ removeChild(child) {
|
|
88509
90694
|
const index = this._children.indexOf(child);
|
|
88510
90695
|
if (index < 0) {
|
|
@@ -88513,10 +90698,10 @@ class GPUClothWrapBinding {
|
|
|
88513
90698
|
this._children[index]._parent = null;
|
|
88514
90699
|
this._children.splice(index, 1);
|
|
88515
90700
|
}
|
|
88516
|
-
/**
|
|
88517
|
-
* Attach this node to a skeleton
|
|
88518
|
-
* @param skeleton - The skeleton to which to node will attach
|
|
88519
|
-
* @param index - The joint index
|
|
90701
|
+
/**
|
|
90702
|
+
* Attach this node to a skeleton
|
|
90703
|
+
* @param skeleton - The skeleton to which to node will attach
|
|
90704
|
+
* @param index - The joint index
|
|
88520
90705
|
*/ attachToSkeleton(skeleton) {
|
|
88521
90706
|
if (!this._attachToSkeleton) {
|
|
88522
90707
|
this._attachToSkeleton = new Set();
|
|
@@ -88524,18 +90709,18 @@ class GPUClothWrapBinding {
|
|
|
88524
90709
|
this._attachToSkeleton.add(skeleton);
|
|
88525
90710
|
}
|
|
88526
90711
|
}
|
|
88527
|
-
/**
|
|
88528
|
-
* Skeleton information for model loading
|
|
88529
|
-
* @public
|
|
90712
|
+
/**
|
|
90713
|
+
* Skeleton information for model loading
|
|
90714
|
+
* @public
|
|
88530
90715
|
*/ class AssetSkeleton extends NamedObject {
|
|
88531
90716
|
/** The pivot node */ pivot;
|
|
88532
90717
|
/** Joints of the skeleton */ joints;
|
|
88533
90718
|
/** Inverse of the binding matrices of the joints */ inverseBindMatrices;
|
|
88534
90719
|
/** Binding pose matrices of the joints */ bindPose;
|
|
88535
90720
|
/** Explicit humanoid joint mapping, when supplied by the source asset. */ humanoidJointMapping;
|
|
88536
|
-
/**
|
|
88537
|
-
* Creates an instance of AssetSkeleton
|
|
88538
|
-
* @param name - Name of the skeleton
|
|
90721
|
+
/**
|
|
90722
|
+
* Creates an instance of AssetSkeleton
|
|
90723
|
+
* @param name - Name of the skeleton
|
|
88539
90724
|
*/ constructor(name){
|
|
88540
90725
|
super(name);
|
|
88541
90726
|
this.name = name;
|
|
@@ -88545,10 +90730,10 @@ class GPUClothWrapBinding {
|
|
|
88545
90730
|
this.bindPose = [];
|
|
88546
90731
|
this.humanoidJointMapping = null;
|
|
88547
90732
|
}
|
|
88548
|
-
/**
|
|
88549
|
-
* Adds a joint to the skeleton
|
|
88550
|
-
* @param joint - The joint node
|
|
88551
|
-
* @param inverseBindMatrix - Inverse binding matrix of the joint
|
|
90733
|
+
/**
|
|
90734
|
+
* Adds a joint to the skeleton
|
|
90735
|
+
* @param joint - The joint node
|
|
90736
|
+
* @param inverseBindMatrix - Inverse binding matrix of the joint
|
|
88552
90737
|
*/ addJoint(joint, inverseBindMatrix) {
|
|
88553
90738
|
joint.attachToSkeleton(this);
|
|
88554
90739
|
this.joints.push(joint);
|
|
@@ -88572,22 +90757,22 @@ class GPUClothWrapBinding {
|
|
|
88572
90757
|
return root;
|
|
88573
90758
|
}
|
|
88574
90759
|
}
|
|
88575
|
-
/**
|
|
88576
|
-
* Scene for model loading
|
|
88577
|
-
* @public
|
|
90760
|
+
/**
|
|
90761
|
+
* Scene for model loading
|
|
90762
|
+
* @public
|
|
88578
90763
|
*/ class AssetScene extends NamedObject {
|
|
88579
90764
|
/** Root nodes of the scene */ rootNodes;
|
|
88580
|
-
/**
|
|
88581
|
-
* Creates an instance of AssetScene
|
|
88582
|
-
* @param name - Name of the scene
|
|
90765
|
+
/**
|
|
90766
|
+
* Creates an instance of AssetScene
|
|
90767
|
+
* @param name - Name of the scene
|
|
88583
90768
|
*/ constructor(name){
|
|
88584
90769
|
super(name);
|
|
88585
90770
|
this.rootNodes = [];
|
|
88586
90771
|
}
|
|
88587
90772
|
}
|
|
88588
|
-
/**
|
|
88589
|
-
* Model information that can be shared by multiple model nodes
|
|
88590
|
-
* @public
|
|
90773
|
+
/**
|
|
90774
|
+
* Model information that can be shared by multiple model nodes
|
|
90775
|
+
* @public
|
|
88591
90776
|
*/ class SharedModel extends Disposable {
|
|
88592
90777
|
/** @internal */ _nodes;
|
|
88593
90778
|
/** @internal */ _skeletons;
|
|
@@ -88605,8 +90790,8 @@ class GPUClothWrapBinding {
|
|
|
88605
90790
|
/** @internal */ _morphTargetGroups;
|
|
88606
90791
|
/** @internal */ _textureMap;
|
|
88607
90792
|
/** @internal */ _primitiveMap;
|
|
88608
|
-
/**
|
|
88609
|
-
* Creates an instance of SharedModel
|
|
90793
|
+
/**
|
|
90794
|
+
* Creates an instance of SharedModel
|
|
88610
90795
|
*/ constructor(){
|
|
88611
90796
|
super();
|
|
88612
90797
|
this._nodes = [];
|
|
@@ -88876,29 +91061,29 @@ class GPUClothWrapBinding {
|
|
|
88876
91061
|
getPrimitiveBaseName(info, index, fallback) {
|
|
88877
91062
|
return info?.name?.trim() || `${fallback}_mesh_${index}`;
|
|
88878
91063
|
}
|
|
88879
|
-
/**
|
|
88880
|
-
* Adds a model-level morph target group.
|
|
88881
|
-
* @param group - Morph target group to add
|
|
91064
|
+
/**
|
|
91065
|
+
* Adds a model-level morph target group.
|
|
91066
|
+
* @param group - Morph target group to add
|
|
88882
91067
|
*/ addMorphTargetGroup(group) {
|
|
88883
91068
|
if (group?.name && group.bindings?.length > 0) {
|
|
88884
91069
|
this._morphTargetGroups.push(group);
|
|
88885
91070
|
}
|
|
88886
91071
|
}
|
|
88887
|
-
/**
|
|
88888
|
-
* Removes all model-level morph target groups.
|
|
91072
|
+
/**
|
|
91073
|
+
* Removes all model-level morph target groups.
|
|
88889
91074
|
*/ clearMorphTargetGroups() {
|
|
88890
91075
|
this._morphTargetGroups = [];
|
|
88891
91076
|
}
|
|
88892
|
-
/**
|
|
88893
|
-
* Finds a model-level morph target group by name.
|
|
88894
|
-
* @param name - Group name
|
|
88895
|
-
* @returns The matching group, or null if not found
|
|
91077
|
+
/**
|
|
91078
|
+
* Finds a model-level morph target group by name.
|
|
91079
|
+
* @param name - Group name
|
|
91080
|
+
* @returns The matching group, or null if not found
|
|
88896
91081
|
*/ getMorphTargetGroup(name) {
|
|
88897
91082
|
return this._morphTargetGroups.find((group)=>group.name === name) ?? null;
|
|
88898
91083
|
}
|
|
88899
|
-
/**
|
|
88900
|
-
* Builds morph target groups by collecting morph target names from every mesh.
|
|
88901
|
-
* @returns Generated morph target groups
|
|
91084
|
+
/**
|
|
91085
|
+
* Builds morph target groups by collecting morph target names from every mesh.
|
|
91086
|
+
* @returns Generated morph target groups
|
|
88902
91087
|
*/ buildMorphTargetGroupsByName() {
|
|
88903
91088
|
this.clearMorphTargetGroups();
|
|
88904
91089
|
const groups = new Map();
|
|
@@ -88931,15 +91116,15 @@ class GPUClothWrapBinding {
|
|
|
88931
91116
|
this._morphTargetGroups = Array.from(groups.values());
|
|
88932
91117
|
return this._morphTargetGroups;
|
|
88933
91118
|
}
|
|
88934
|
-
/**
|
|
88935
|
-
* Adds a skeleton to the scene
|
|
88936
|
-
* @param skeleton - The skeleton to be added
|
|
91119
|
+
/**
|
|
91120
|
+
* Adds a skeleton to the scene
|
|
91121
|
+
* @param skeleton - The skeleton to be added
|
|
88937
91122
|
*/ addSkeleton(skeleton) {
|
|
88938
91123
|
this._skeletons.push(skeleton);
|
|
88939
91124
|
}
|
|
88940
|
-
/**
|
|
88941
|
-
* Adds an animation to the scene
|
|
88942
|
-
* @param animation - The animation to be added
|
|
91125
|
+
/**
|
|
91126
|
+
* Adds an animation to the scene
|
|
91127
|
+
* @param animation - The animation to be added
|
|
88943
91128
|
*/ addAnimation(animation) {
|
|
88944
91129
|
this._animations.push(animation);
|
|
88945
91130
|
}
|
|
@@ -91174,32 +93359,32 @@ let outfitInstanceId = 0;
|
|
|
91174
93359
|
/* es-module-lexer 1.7.0 */
|
|
91175
93360
|
var ImportType;!function(A){A[A.Static=1]="Static",A[A.Dynamic=2]="Dynamic",A[A.ImportMeta=3]="ImportMeta",A[A.StaticSourcePhase=4]="StaticSourcePhase",A[A.DynamicSourcePhase=5]="DynamicSourcePhase",A[A.StaticDeferPhase=6]="StaticDeferPhase",A[A.DynamicDeferPhase=7]="DynamicDeferPhase";}(ImportType||(ImportType={}));const A=1===new Uint8Array(new Uint16Array([1]).buffer)[0];function parse(E,g="@"){if(!C)return init.then((()=>parse(E)));const I=E.length+1,w=(C.__heap_base.value||C.__heap_base)+4*I-C.memory.buffer.byteLength;w>0&&C.memory.grow(Math.ceil(w/65536));const K=C.sa(I-1);if((A?B:Q)(E,new Uint16Array(C.memory.buffer,K,I)),!C.parse())throw Object.assign(new Error(`Parse error ${g}:${E.slice(0,C.e()).split("\n").length}:${C.e()-E.lastIndexOf("\n",C.e()-1)}`),{idx:C.e()});const o=[],D=[];for(;C.ri();){const A=C.is(),Q=C.ie(),B=C.it(),g=C.ai(),I=C.id(),w=C.ss(),K=C.se();let D;C.ip()&&(D=k(E.slice(-1===I?A-1:A,-1===I?Q+1:Q))),o.push({n:D,t:B,s:A,e:Q,ss:w,se:K,d:I,a:g});}for(;C.re();){const A=C.es(),Q=C.ee(),B=C.els(),g=C.ele(),I=E.slice(A,Q),w=I[0],K=B<0?undefined:E.slice(B,g),o=K?K[0]:"";D.push({s:A,e:Q,ls:B,le:g,n:'"'===w||"'"===w?k(I):I,ln:'"'===o||"'"===o?k(K):K});}function k(A){try{return (0,eval)(A)}catch(A){}}return [o,D,!!C.f(),!!C.ms()]}function Q(A,Q){const B=A.length;let C=0;for(;C<B;){const B=A.charCodeAt(C);Q[C++]=(255&B)<<8|B>>>8;}}function B(A,Q){const B=A.length;let C=0;for(;C<B;)Q[C]=A.charCodeAt(C++);}let C;const E=()=>{return A="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GzYCHAtBAEEAKAKwCkECajYCsAoCQAJAAkACQEEAECkiAUHhAEYNACABQfcARg0BQQAoArAKIQEMAgtBACgCsAoiAUECakHACEEKEC8NAUEGIQIMAgtBACgCsAoiAS8BAkHpAEcNACABLwEEQfQARw0AQQQhAiABLwEGQegARg0BC0EAIAFBfmo2ArAKDwtBACABIAJBAXRqNgKwCgJAQQEQKUH7AEYNAEEAIAE2ArAKDwtBACgCsAoiACECA0BBACACQQJqNgKwCgJAAkACQEEBECkiAkEiRg0AIAJBJ0cNAUEnEBpBAEEAKAKwCkECajYCsApBARApIQIMAgtBIhAaQQBBACgCsApBAmo2ArAKQQEQKSECDAELIAIQLCECCwJAIAJBOkYNAEEAIAE2ArAKDwtBAEEAKAKwCkECajYCsAoCQEEBECkiAkEiRg0AIAJBJ0YNAEEAIAE2ArAKDwsgAhAaQQBBACgCsApBAmo2ArAKAkACQEEBECkiAkEsRg0AIAJB/QBGDQFBACABNgKwCg8LQQBBACgCsApBAmo2ArAKQQEQKUH9AEYNAEEAKAKwCiECDAELC0EAKALwCSIBIAA2AhAgAUEAKAKwCkECajYCDAttAQJ/AkACQANAAkAgAEH//wNxIgFBd2oiAkEXSw0AQQEgAnRBn4CABHENAgsgAUGgAUYNASAAIQIgARAoDQJBACECQQBBACgCsAoiAEECajYCsAogAC8BAiIADQAMAgsLIAAhAgsgAkH//wNxC6sBAQR/AkACQEEAKAKwCiICLwEAIgNB4QBGDQAgASEEIAAhBQwBC0EAIAJBBGo2ArAKQQEQKSECQQAoArAKIQUCQAJAIAJBIkYNACACQSdGDQAgAhAsGkEAKAKwCiEEDAELIAIQGkEAQQAoArAKQQJqIgQ2ArAKC0EBECkhA0EAKAKwCiECCwJAIAIgBUYNACAFIARBACAAIAAgAUYiAhtBACABIAIbEAILIAMLcgEEf0EAKAKwCiEAQQAoArQKIQECQAJAA0AgAEECaiECIAAgAU8NAQJAAkAgAi8BACIDQaR/ag4CAQQACyACIQAgA0F2ag4EAgEBAgELIABBBGohAAwACwtBACACNgKwChAlQQAPC0EAIAI2ArAKQd0AC0kBA39BACEDAkAgAkUNAAJAA0AgAC0AACIEIAEtAAAiBUcNASABQQFqIQEgAEEBaiEAIAJBf2oiAg0ADAILCyAEIAVrIQMLIAMLC+wBAgBBgAgLzgEAAHgAcABvAHIAdABtAHAAbwByAHQAZgBvAHIAZQB0AGEAbwB1AHIAYwBlAHIAbwBtAHUAbgBjAHQAaQBvAG4AcwBzAGUAcgB0AHYAbwB5AGkAZQBkAGUAbABlAGMAbwBuAHQAaQBuAGkAbgBzAHQAYQBuAHQAeQBiAHIAZQBhAHIAZQB0AHUAcgBkAGUAYgB1AGcAZwBlAGEAdwBhAGkAdABoAHIAdwBoAGkAbABlAGkAZgBjAGEAdABjAGYAaQBuAGEAbABsAGUAbABzAABB0AkLEAEAAAACAAAAAAQAAEA5AAA=","undefined"!=typeof Buffer?Buffer.from(A,"base64"):Uint8Array.from(atob(A),(A=>A.charCodeAt(0)));var A;};const init=WebAssembly.compile(E()).then(WebAssembly.instantiate).then((({exports:A})=>{C=A;}));
|
|
91176
93361
|
|
|
91177
|
-
/**
|
|
91178
|
-
* Converts JavaScript source to a data URL tied to a logical module id.
|
|
91179
|
-
*
|
|
91180
|
-
* @param js - The JavaScript source code to embed.
|
|
91181
|
-
* @param id - Logical module identifier (used only for sourceURL tagging).
|
|
91182
|
-
* @returns A `data:text/javascript;base64,...` URL with an encoded `#id` suffix.
|
|
91183
|
-
* @internal
|
|
93362
|
+
/**
|
|
93363
|
+
* Converts JavaScript source to a data URL tied to a logical module id.
|
|
93364
|
+
*
|
|
93365
|
+
* @param js - The JavaScript source code to embed.
|
|
93366
|
+
* @param id - Logical module identifier (used only for sourceURL tagging).
|
|
93367
|
+
* @returns A `data:text/javascript;base64,...` URL with an encoded `#id` suffix.
|
|
93368
|
+
* @internal
|
|
91184
93369
|
*/ function toDataUrl(js, id) {
|
|
91185
93370
|
const b64 = textToBase64(js);
|
|
91186
93371
|
return `data:text/javascript;base64,${b64}#${encodeURIComponent(String(id))}`;
|
|
91187
93372
|
}
|
|
91188
|
-
/**
|
|
91189
|
-
* Checks whether a specifier is an absolute HTTP(S) URL.
|
|
91190
|
-
* @internal
|
|
93373
|
+
/**
|
|
93374
|
+
* Checks whether a specifier is an absolute HTTP(S) URL.
|
|
93375
|
+
* @internal
|
|
91191
93376
|
*/ function isAbsoluteUrl(spec) {
|
|
91192
93377
|
return /^https?:\/\//i.test(spec);
|
|
91193
93378
|
}
|
|
91194
|
-
/**
|
|
91195
|
-
* Checks whether a specifier is a special URL (data: or blob:).
|
|
91196
|
-
* @internal
|
|
93379
|
+
/**
|
|
93380
|
+
* Checks whether a specifier is a special URL (data: or blob:).
|
|
93381
|
+
* @internal
|
|
91197
93382
|
*/ function isSpecialUrl(spec) {
|
|
91198
93383
|
return /^(data|blob):/i.test(spec);
|
|
91199
93384
|
}
|
|
91200
|
-
/**
|
|
91201
|
-
* Checks whether a specifier is a bare module (not starting with ./, ../, /, or #/).
|
|
91202
|
-
* @internal
|
|
93385
|
+
/**
|
|
93386
|
+
* Checks whether a specifier is a bare module (not starting with ./, ../, /, or #/).
|
|
93387
|
+
* @internal
|
|
91203
93388
|
*/ function isBareModule(spec) {
|
|
91204
93389
|
return !spec.startsWith('./') && !spec.startsWith('../') && !spec.startsWith('/') && !spec.startsWith('#/');
|
|
91205
93390
|
}
|
|
@@ -91230,32 +93415,32 @@ function hasRawQuery(spec) {
|
|
|
91230
93415
|
}
|
|
91231
93416
|
return query.split('&').some((part)=>part.trim() === 'raw');
|
|
91232
93417
|
}
|
|
91233
|
-
/**
|
|
91234
|
-
* Resolves, builds, and serves runtime modules using a VFS.
|
|
91235
|
-
*
|
|
91236
|
-
* Responsibilities:
|
|
91237
|
-
* - Resolve logical module IDs to physical paths or URLs.
|
|
91238
|
-
* - In editor mode, bundle local script modules into a single data URL after transpile.
|
|
91239
|
-
* - Transpile TypeScript to JavaScript on the fly (requires `window.ts` TypeScript runtime).
|
|
91240
|
-
* - Gather static and dynamic import dependencies for tooling.
|
|
91241
|
-
*
|
|
91242
|
-
* Modes:
|
|
91243
|
-
* - Editor mode (`editorMode === true`): local script graphs are bundled to data URLs.
|
|
91244
|
-
* - Runtime mode (`editorMode === false`): returns .js URLs directly (with .ts -\> .js mapping).
|
|
91245
|
-
*
|
|
91246
|
-
* Caching:
|
|
91247
|
-
* - Built bundles are memoized in `_built` map keyed by canonical source path.
|
|
91248
|
-
*
|
|
91249
|
-
* @public
|
|
93418
|
+
/**
|
|
93419
|
+
* Resolves, builds, and serves runtime modules using a VFS.
|
|
93420
|
+
*
|
|
93421
|
+
* Responsibilities:
|
|
93422
|
+
* - Resolve logical module IDs to physical paths or URLs.
|
|
93423
|
+
* - In editor mode, bundle local script modules into a single data URL after transpile.
|
|
93424
|
+
* - Transpile TypeScript to JavaScript on the fly (requires `window.ts` TypeScript runtime).
|
|
93425
|
+
* - Gather static and dynamic import dependencies for tooling.
|
|
93426
|
+
*
|
|
93427
|
+
* Modes:
|
|
93428
|
+
* - Editor mode (`editorMode === true`): local script graphs are bundled to data URLs.
|
|
93429
|
+
* - Runtime mode (`editorMode === false`): returns .js/.mjs URLs directly (with .ts -\> .js mapping).
|
|
93430
|
+
*
|
|
93431
|
+
* Caching:
|
|
93432
|
+
* - Built bundles are memoized in `_built` map keyed by canonical source path.
|
|
93433
|
+
*
|
|
93434
|
+
* @public
|
|
91250
93435
|
*/ class ScriptRegistry {
|
|
91251
93436
|
_vfs;
|
|
91252
93437
|
_scriptsRoot;
|
|
91253
93438
|
_built;
|
|
91254
93439
|
_building;
|
|
91255
93440
|
_builtDeps;
|
|
91256
|
-
/**
|
|
91257
|
-
* @param vfs - The virtual file system for existence checks, reads, and path ops.
|
|
91258
|
-
* @param scriptsRoot - Root directory for script resolution (used with `#/` specifiers).
|
|
93441
|
+
/**
|
|
93442
|
+
* @param vfs - The virtual file system for existence checks, reads, and path ops.
|
|
93443
|
+
* @param scriptsRoot - Root directory for script resolution (used with `#/` specifiers).
|
|
91259
93444
|
*/ constructor(vfs, scriptsRoot){
|
|
91260
93445
|
this._vfs = vfs;
|
|
91261
93446
|
this._scriptsRoot = scriptsRoot;
|
|
@@ -91263,10 +93448,10 @@ function hasRawQuery(spec) {
|
|
|
91263
93448
|
this._building = new Map();
|
|
91264
93449
|
this._builtDeps = new Map();
|
|
91265
93450
|
}
|
|
91266
|
-
/**
|
|
91267
|
-
* The active virtual file system.
|
|
91268
|
-
*
|
|
91269
|
-
* Assigning a new VFS clears the build cache.
|
|
93451
|
+
/**
|
|
93452
|
+
* The active virtual file system.
|
|
93453
|
+
*
|
|
93454
|
+
* Assigning a new VFS clears the build cache.
|
|
91270
93455
|
*/ get VFS() {
|
|
91271
93456
|
return this._vfs;
|
|
91272
93457
|
}
|
|
@@ -91278,21 +93463,21 @@ function hasRawQuery(spec) {
|
|
|
91278
93463
|
this._builtDeps.clear();
|
|
91279
93464
|
}
|
|
91280
93465
|
}
|
|
91281
|
-
/**
|
|
91282
|
-
* The root path used by `#/` specifiers.
|
|
93466
|
+
/**
|
|
93467
|
+
* The root path used by `#/` specifiers.
|
|
91283
93468
|
*/ get scriptsRoot() {
|
|
91284
93469
|
return this._scriptsRoot;
|
|
91285
93470
|
}
|
|
91286
93471
|
set scriptsRoot(path) {
|
|
91287
93472
|
this._scriptsRoot = path;
|
|
91288
93473
|
}
|
|
91289
|
-
/**
|
|
91290
|
-
* Invalidates cached built module output for one logical module id, or clears the full cache.
|
|
91291
|
-
*
|
|
91292
|
-
* Pass the same logical id shape that callers use with {@link ScriptRegistry.resolveRuntimeUrl},
|
|
91293
|
-
* for example `/assets/scripts/foo.ts`, `/assets/scripts/foo.js`, or `/assets/scripts/foo`.
|
|
91294
|
-
*
|
|
91295
|
-
* @param moduleId - Optional logical module id to invalidate. Omit to clear the entire build cache.
|
|
93474
|
+
/**
|
|
93475
|
+
* Invalidates cached built module output for one logical module id, or clears the full cache.
|
|
93476
|
+
*
|
|
93477
|
+
* Pass the same logical id shape that callers use with {@link ScriptRegistry.resolveRuntimeUrl},
|
|
93478
|
+
* for example `/assets/scripts/foo.ts`, `/assets/scripts/foo.js`, or `/assets/scripts/foo`.
|
|
93479
|
+
*
|
|
93480
|
+
* @param moduleId - Optional logical module id to invalidate. Omit to clear the entire build cache.
|
|
91296
93481
|
*/ invalidate(moduleId) {
|
|
91297
93482
|
if (!moduleId) {
|
|
91298
93483
|
this._built.clear();
|
|
@@ -91331,22 +93516,22 @@ function hasRawQuery(spec) {
|
|
|
91331
93516
|
}
|
|
91332
93517
|
}
|
|
91333
93518
|
}
|
|
91334
|
-
/**
|
|
91335
|
-
* Fetches raw source for a logical module id by probing known extensions.
|
|
91336
|
-
*
|
|
91337
|
-
* Search order:
|
|
91338
|
-
* - If `id` already ends with `.ts
|
|
91339
|
-
* - Else try `.id.ts`, then `.id.js`.
|
|
91340
|
-
*
|
|
91341
|
-
* @param id - Logical module identifier (absolute or logical path-like).
|
|
91342
|
-
* @returns Source code, resolved path, and type (`'js' | 'ts'`), or `undefined` if not found.
|
|
93519
|
+
/**
|
|
93520
|
+
* Fetches raw source for a logical module id by probing known extensions.
|
|
93521
|
+
*
|
|
93522
|
+
* Search order:
|
|
93523
|
+
* - If `id` already ends with `.ts`, `.js`, or `.mjs` and is a file -\> return it.
|
|
93524
|
+
* - Else try `.id.ts`, then `.id.js`, then `.id.mjs`.
|
|
93525
|
+
*
|
|
93526
|
+
* @param id - Logical module identifier (absolute or logical path-like).
|
|
93527
|
+
* @returns Source code, resolved path, and type (`'js' | 'ts'`), or `undefined` if not found.
|
|
91343
93528
|
*/ async fetchSource(id) {
|
|
91344
93529
|
let type = null;
|
|
91345
93530
|
let pathWithExt = '';
|
|
91346
93531
|
if (id.endsWith('.ts')) {
|
|
91347
93532
|
pathWithExt = id;
|
|
91348
93533
|
type = 'ts';
|
|
91349
|
-
} else if (id.endsWith('.js')) {
|
|
93534
|
+
} else if (id.endsWith('.js') || id.endsWith('.mjs')) {
|
|
91350
93535
|
pathWithExt = id;
|
|
91351
93536
|
type = 'js';
|
|
91352
93537
|
}
|
|
@@ -91365,13 +93550,16 @@ function hasRawQuery(spec) {
|
|
|
91365
93550
|
'js'
|
|
91366
93551
|
];
|
|
91367
93552
|
if (!type) {
|
|
91368
|
-
for (const t of
|
|
93553
|
+
for (const t of [
|
|
93554
|
+
...types,
|
|
93555
|
+
'mjs'
|
|
93556
|
+
]){
|
|
91369
93557
|
pathWithExt = `${id}.${t}`;
|
|
91370
93558
|
const exists = await this._vfs.exists(pathWithExt);
|
|
91371
93559
|
if (exists) {
|
|
91372
93560
|
const stats = await this._vfs.stat(pathWithExt);
|
|
91373
93561
|
if (stats.isFile) {
|
|
91374
|
-
type = t;
|
|
93562
|
+
type = t === 'ts' ? 'ts' : 'js';
|
|
91375
93563
|
break;
|
|
91376
93564
|
}
|
|
91377
93565
|
}
|
|
@@ -91388,34 +93576,35 @@ function hasRawQuery(spec) {
|
|
|
91388
93576
|
};
|
|
91389
93577
|
}
|
|
91390
93578
|
}
|
|
91391
|
-
/**
|
|
91392
|
-
* Resolves a module entry to a URL suitable for dynamic import.
|
|
91393
|
-
*
|
|
91394
|
-
* Behavior:
|
|
91395
|
-
* - In editor mode, builds the module to a data URL.
|
|
91396
|
-
* - Otherwise, returns `.js` URL directly:
|
|
91397
|
-
* - If `id` ends with `.js`: return as-is.
|
|
91398
|
-
* - If `id` ends with `.
|
|
91399
|
-
* -
|
|
91400
|
-
*
|
|
91401
|
-
*
|
|
91402
|
-
* @
|
|
93579
|
+
/**
|
|
93580
|
+
* Resolves a module entry to a URL suitable for dynamic import.
|
|
93581
|
+
*
|
|
93582
|
+
* Behavior:
|
|
93583
|
+
* - In editor mode, builds the module to a data URL.
|
|
93584
|
+
* - Otherwise, returns `.js` or `.mjs` URL directly:
|
|
93585
|
+
* - If `id` ends with `.js`: return as-is.
|
|
93586
|
+
* - If `id` ends with `.mjs`: return as-is.
|
|
93587
|
+
* - If `id` ends with `.ts`: map to `.js` (assumes pre-built file exists).
|
|
93588
|
+
* - Else: append `.js`.
|
|
93589
|
+
*
|
|
93590
|
+
* @param entryId - Entry module identifier (logical or path-like).
|
|
93591
|
+
* @returns A URL string that can be used in `import(...)`.
|
|
91403
93592
|
*/ async resolveRuntimeUrl(entryId) {
|
|
91404
93593
|
const id = await this.resolveLogicalId(entryId);
|
|
91405
93594
|
if (id.startsWith('/assets/@builtins/')) {
|
|
91406
93595
|
return await this.build(String(id));
|
|
91407
93596
|
}
|
|
91408
|
-
return getApp().editorMode !== 'none' ? await this.build(String(id)) : id.endsWith('.js') ? id : id.endsWith('.ts') ? `${id.slice(0, -3)}.js` : `${id}.js`;
|
|
91409
|
-
}
|
|
91410
|
-
/**
|
|
91411
|
-
* Recursively gathers direct static and dynamic import dependencies for a module.
|
|
91412
|
-
*
|
|
91413
|
-
* Only relative specifiers (`./` or `../`) are followed. Absolute, special, and bare
|
|
91414
|
-
* module specifiers are ignored here.
|
|
91415
|
-
*
|
|
91416
|
-
* @param entryId - The starting (possibly relative) specifier from `fromId`.
|
|
91417
|
-
* @param fromId - The logical id of the module containing `entryId`.
|
|
91418
|
-
* @param dependencies - Output map of `resolvedSourcePath -\> file contents`.
|
|
93597
|
+
return getApp().editorMode !== 'none' ? await this.build(String(id)) : id.endsWith('.js') || id.endsWith('.mjs') ? id : id.endsWith('.ts') ? `${id.slice(0, -3)}.js` : `${id}.js`;
|
|
93598
|
+
}
|
|
93599
|
+
/**
|
|
93600
|
+
* Recursively gathers direct static and dynamic import dependencies for a module.
|
|
93601
|
+
*
|
|
93602
|
+
* Only relative specifiers (`./` or `../`) are followed. Absolute, special, and bare
|
|
93603
|
+
* module specifiers are ignored here.
|
|
93604
|
+
*
|
|
93605
|
+
* @param entryId - The starting (possibly relative) specifier from `fromId`.
|
|
93606
|
+
* @param fromId - The logical id of the module containing `entryId`.
|
|
93607
|
+
* @param dependencies - Output map of `resolvedSourcePath -\> file contents`.
|
|
91419
93608
|
*/ async getDependencies(entryId, fromId, dependencies) {
|
|
91420
93609
|
const reStatic = /\b(?:import|export)\s+[^"']*?from\s+(['"])([^'"]+)\1/g;
|
|
91421
93610
|
const reDynamic = /\bimport\s*\(\s*(['"])([^'"]+)\1\s*\)/g;
|
|
@@ -91443,17 +93632,17 @@ function hasRawQuery(spec) {
|
|
|
91443
93632
|
await gather(code, reStatic);
|
|
91444
93633
|
await gather(code, reDynamic);
|
|
91445
93634
|
}
|
|
91446
|
-
/**
|
|
91447
|
-
* Builds a logical module id into a bundled data URL (editor mode pipeline).
|
|
91448
|
-
*
|
|
91449
|
-
* Steps:
|
|
91450
|
-
* - Resolve source path (.ts/.js) via {@link ScriptRegistry.resolveSourcePath}.
|
|
91451
|
-
* - Collect reachable local imports without recursively building data URLs.
|
|
91452
|
-
* - Transpile local modules to `System.register`.
|
|
91453
|
-
* - Emit a single `data:` URL with a small module loader and memoize it in `_built`.
|
|
91454
|
-
*
|
|
91455
|
-
* @param id - Logical module id to build.
|
|
91456
|
-
* @returns Data URL string for dynamic import, or empty string if not found.
|
|
93635
|
+
/**
|
|
93636
|
+
* Builds a logical module id into a bundled data URL (editor mode pipeline).
|
|
93637
|
+
*
|
|
93638
|
+
* Steps:
|
|
93639
|
+
* - Resolve source path (.ts/.js) via {@link ScriptRegistry.resolveSourcePath}.
|
|
93640
|
+
* - Collect reachable local imports without recursively building data URLs.
|
|
93641
|
+
* - Transpile local modules to `System.register`.
|
|
93642
|
+
* - Emit a single `data:` URL with a small module loader and memoize it in `_built`.
|
|
93643
|
+
*
|
|
93644
|
+
* @param id - Logical module id to build.
|
|
93645
|
+
* @returns Data URL string for dynamic import, or empty string if not found.
|
|
91457
93646
|
*/ async build(id) {
|
|
91458
93647
|
const entry = await this.resolveModuleInfo(String(id));
|
|
91459
93648
|
if (!entry) {
|
|
@@ -91548,7 +93737,7 @@ function hasRawQuery(spec) {
|
|
|
91548
93737
|
const ts = this.getTypeScriptRuntime();
|
|
91549
93738
|
const res = ts.transpileModule(code, {
|
|
91550
93739
|
compilerOptions: {
|
|
91551
|
-
target: ts.ScriptTarget.
|
|
93740
|
+
target: ts.ScriptTarget.ES2020,
|
|
91552
93741
|
module: ts.ModuleKind.ESNext,
|
|
91553
93742
|
experimentalDecorators: true,
|
|
91554
93743
|
useDefineForClassFields: false
|
|
@@ -91563,19 +93752,20 @@ function hasRawQuery(spec) {
|
|
|
91563
93752
|
const res = ts.transpileModule(code, {
|
|
91564
93753
|
compilerOptions: {
|
|
91565
93754
|
allowJs: true,
|
|
91566
|
-
|
|
93755
|
+
// Keep modern syntax such as async generators, class fields, and private fields intact.
|
|
93756
|
+
target: ts.ScriptTarget.ES2022,
|
|
91567
93757
|
module: ts.ModuleKind.System,
|
|
91568
93758
|
esModuleInterop: true,
|
|
91569
93759
|
experimentalDecorators: true,
|
|
91570
|
-
useDefineForClassFields:
|
|
93760
|
+
useDefineForClassFields: true
|
|
91571
93761
|
},
|
|
91572
93762
|
fileName: logicalId
|
|
91573
93763
|
});
|
|
91574
93764
|
return res.outputText || '';
|
|
91575
93765
|
}
|
|
91576
|
-
/**
|
|
91577
|
-
* Rewrites local ESM specifiers to canonical source paths and records local deps.
|
|
91578
|
-
* External URLs and package imports are left for the native dynamic import path.
|
|
93766
|
+
/**
|
|
93767
|
+
* Rewrites local ESM specifiers to canonical source paths and records local deps.
|
|
93768
|
+
* External URLs and package imports are left for the native dynamic import path.
|
|
91579
93769
|
*/ async rewriteImportsToLogicalIds(code, fromId) {
|
|
91580
93770
|
await init;
|
|
91581
93771
|
const [imports] = parse(code);
|
|
@@ -91723,21 +93913,21 @@ async function __z3dLoad(spec, parentId = '') {
|
|
|
91723
93913
|
}
|
|
91724
93914
|
`;
|
|
91725
93915
|
}
|
|
91726
|
-
/**
|
|
91727
|
-
* Resolves a specifier to a logical id suitable for further processing.
|
|
91728
|
-
*
|
|
91729
|
-
* Resolution rules:
|
|
91730
|
-
* - `#/path`: resolved against `scriptsRoot` via VFS join/normalize.
|
|
91731
|
-
* - `./` or `../`: resolved relative to `fromId` directory (requires `fromId`).
|
|
91732
|
-
* - `/absolute`: treated as absolute from root (normalized).
|
|
91733
|
-
* - Bare module in editor mode: if `/deps.lock.json` exists and contains an entry,
|
|
91734
|
-
* map to the dependency's `entry` path; otherwise return as-is.
|
|
91735
|
-
* - Else (non-editor bare module): return `spec` unchanged (external).
|
|
91736
|
-
*
|
|
91737
|
-
* @param spec - Import specifier string.
|
|
91738
|
-
* @param fromId - Optional base logical id used for relative resolution.
|
|
91739
|
-
* @returns A normalized logical id or an external specifier string.
|
|
91740
|
-
* @throws If a relative import is provided without `fromId`.
|
|
93916
|
+
/**
|
|
93917
|
+
* Resolves a specifier to a logical id suitable for further processing.
|
|
93918
|
+
*
|
|
93919
|
+
* Resolution rules:
|
|
93920
|
+
* - `#/path`: resolved against `scriptsRoot` via VFS join/normalize.
|
|
93921
|
+
* - `./` or `../`: resolved relative to `fromId` directory (requires `fromId`).
|
|
93922
|
+
* - `/absolute`: treated as absolute from root (normalized).
|
|
93923
|
+
* - Bare module in editor mode: if `/deps.lock.json` exists and contains an entry,
|
|
93924
|
+
* map to the dependency's `entry` path; otherwise return as-is.
|
|
93925
|
+
* - Else (non-editor bare module): return `spec` unchanged (external).
|
|
93926
|
+
*
|
|
93927
|
+
* @param spec - Import specifier string.
|
|
93928
|
+
* @param fromId - Optional base logical id used for relative resolution.
|
|
93929
|
+
* @returns A normalized logical id or an external specifier string.
|
|
93930
|
+
* @throws If a relative import is provided without `fromId`.
|
|
91741
93931
|
*/ async resolveLogicalId(spec, fromId) {
|
|
91742
93932
|
const { path: baseSpec, suffix } = splitSpecifierQuery(spec);
|
|
91743
93933
|
if (baseSpec.startsWith('#/')) {
|
|
@@ -91767,16 +93957,16 @@ async function __z3dLoad(spec, parentId = '') {
|
|
|
91767
93957
|
}
|
|
91768
93958
|
return spec;
|
|
91769
93959
|
}
|
|
91770
|
-
/**
|
|
91771
|
-
* Resolves a logical id to a concrete source path and type by probing extensions.
|
|
91772
|
-
*
|
|
91773
|
-
* Rules:
|
|
91774
|
-
* - If `logicalId` ends with `.ts` or `.js`/`.mjs` and is a file, return it.
|
|
91775
|
-
* - Else probe `logicalId.ts`, `logicalId.js`, `logicalId.mjs` in that order.
|
|
91776
|
-
* - Maps `.mjs` to type `'js'`.
|
|
91777
|
-
*
|
|
91778
|
-
* @param logicalId - The normalized logical module id (path-like).
|
|
91779
|
-
* @returns `{ type, path }` or `null` if not found.
|
|
93960
|
+
/**
|
|
93961
|
+
* Resolves a logical id to a concrete source path and type by probing extensions.
|
|
93962
|
+
*
|
|
93963
|
+
* Rules:
|
|
93964
|
+
* - If `logicalId` ends with `.ts` or `.js`/`.mjs` and is a file, return it.
|
|
93965
|
+
* - Else probe `logicalId.ts`, `logicalId.js`, `logicalId.mjs` in that order.
|
|
93966
|
+
* - Maps `.mjs` to type `'js'`.
|
|
93967
|
+
*
|
|
93968
|
+
* @param logicalId - The normalized logical module id (path-like).
|
|
93969
|
+
* @returns `{ type, path }` or `null` if not found.
|
|
91780
93970
|
*/ async resolveSourcePath(logicalId) {
|
|
91781
93971
|
const { path: normalizedLogicalId } = splitSpecifierQuery(logicalId);
|
|
91782
93972
|
let type = null;
|
|
@@ -93030,5 +95220,5 @@ const DEFAULT_PADDING = 6;
|
|
|
93030
95220
|
}
|
|
93031
95221
|
}
|
|
93032
95222
|
|
|
93033
|
-
export { AABBTree, ABufferOIT, ATMOSPHERIC_FOG_BIT, AbsNode, AbstractPostEffect, AllConditionNode, AnimationClip, AnimationSet, AnimationTrack, AnyConditionNode, Application, ArcCosNode, ArcSinNode, ArcTan2Node, ArcTanNode, ArccosineHNode, ArcsineHNode, ArctangentHNode, AssetHierarchyNode, AssetManager, AssetScene, AssetSkeleton, AvatarOutfitInstance, AvatarWardrobe, BUILTIN_ASSET_TEST_CUBEMAP, BUILTIN_ASSET_TEXTURE_SHEEN_LUT, BaseCameraController, BaseGraphNode, BaseLight, BaseSprite, BaseTextureNode, BatchGroup, BillboardMatrixNode, BlinnMaterial, Blitter, Bloom, BoundingBox, BoxFilterBlitter, BoxFrameShape, BoxShape, CAMERA_POS_Y, CCDSolver, Camera, CameraNearFarNode, CameraPositionNode, CameraVectorNode, CapsuleShape, CeilNode, ClampNode, Clipmap, ClipmapTerrain, ClipmapTerrainMaterial, ColliderForce, ColorAdjust, CompAddNode, CompComparisonNode, CompDivNode, CompMulNode, CompSubNode, Compositor, ConstantBVec2Node, ConstantBVec3Node, ConstantBVec4Node, ConstantBooleanNode, ConstantScalarNode, ConstantTexture2DArrayNode, ConstantTexture2DNode, ConstantTextureCubeNode, ConstantVec2Node, ConstantVec3Node, ConstantVec4Node, ConstraintType, CopyBlitter, CosHNode, CosNode, CrossProductNode, CubemapSHProjector, CullVisitor, CylinderShape, DDXNode, DDYNode, Degrees2RadiansNode, DepthPass, DirectionalLight, DistanceNode, DotProductNode, DracoMeshDecoder, EPSILON$1 as EPSILON, ESM, ElapsedTimeNode, Engine, EnvConstantAmbient, EnvHemisphericAmbient, EnvLightWrapper, EnvShIBL, Environment, EnvironmentLighting, EqualNode, Exp2Node, ExpNode, FABRIKSolver, FBMWaveGenerator, FFTWaveGenerator, FPSCameraController, FWidthNode, FXAA, FaceForwardNode, FixedGeometryCacheTrack, FloorNode, FmaNode, Fog, FontAsset, FractNode, FunctionCallNode, FunctionInputNode, FunctionOutputNode, GPUClothSystem, GaussianBlurBlitter, GenericMathNode, GerstnerWaveGenerator, GraphNode, GrassInstances, GrassLayer, GrassMaterial, GrassQuadtreeNode, GrassRenderer, Grayscale, HEIGHT_FOG_BIT, Hash1Node, Hash2Node, Hash3Node, HistoryResourceManager, HumanoidBodyRig, HumanoidHandRig, IKAngleConstraint, IKChain, IKConstraint, IKModifier, IKSolver, InputManager, InstanceBindGroupAllocator, InstanceIndexNode, InvProjMatrixNode, InvSqrtNode, InvViewProjMatrixNode, JointDynamicsModifier, JointDynamicsSystem, JointDynamicsSystemController, LIGHT_TYPE_DIRECTIONAL, LIGHT_TYPE_NONE, LIGHT_TYPE_POINT, LIGHT_TYPE_RECT, LIGHT_TYPE_SPOT, LambertMaterial, LengthNode, LightPass, Log2Node, LogNode, LogicallyAndNode, LogicallyOrNode, MAX_CLUSTERED_LIGHTS, MAX_GERSTNER_WAVE_COUNT, MAX_MORPH_ATTRIBUTES, MAX_MORPH_TARGETS, MAX_TERRAIN_MIPMAP_LEVELS, MORPH_ATTRIBUTE_VECTOR_COUNT, MORPH_TARGET_COLOR, MORPH_TARGET_NORMAL, MORPH_TARGET_POSITION, MORPH_TARGET_TANGENT, MORPH_TARGET_TEX0, MORPH_TARGET_TEX1, MORPH_TARGET_TEX2, MORPH_TARGET_TEX3, MORPH_WEIGHTS_VECTOR_COUNT, MSDFText, MSDFTextAtlasManager, MSDFTextSprite, MToonMaterial, MakeVectorNode, Material, MaterialBlueprintIR, MaterialVaryingFlags, MaxNode, Mesh, MeshMaterial, MinNode, MixNode, ModNode, MorphTargetTrack, MultiChainSpringSystem, NamedObject, NodeEulerRotationTrack, NodeRotationTrack, NodeScaleTrack, NodeTranslationTrack, NormalizeNode, NotEqualNode, Octree, OctreeNode, OctreeNodeChunk, OctreePlacement, OrbitCameraController, OrthoCamera, PBRBlockNode, PBRBluePrintMaterial, PBRMetallicRoughnessMaterial, PBRSpecularGlossinessMaterial, PCAGeometryCacheTrack, PCFOPT, PCFPD, PannerNode, ParticleMaterial, ParticleSystem, PerlinNoise2DNode, PerspectiveCamera, PixelNormalNode, PixelWorldPositionNode, PlaneShape, PointLight, PostEffectLayer, PowNode, Primitive, ProjectionMatrixNode, PropertyTrack, PunctualLight, QUEUE_OPAQUE, QUEUE_TRANSPARENT, RENDER_PASS_TYPE_DEPTH, RENDER_PASS_TYPE_LIGHT, RENDER_PASS_TYPE_OBJECT_COLOR, RENDER_PASS_TYPE_SHADOWMAP, Radians2DegreesNode, RaycastVisitor, RectLight, ReflectNode, RefractNode, RenderPass, RenderQueue, RenderTarget, ResolveVertexNormalNode, ResolveVertexPositionNode, ResolveVertexTangentNode, ResourceManager, RotateAboutAxisNode, RuntimeScript, SAO, SSS, SaturateNode, Scene, SceneNode, SceneRenderer, ScreenAdapter, ScreenRenderTarget, ScriptAttachment, ScriptRegistry, ScriptingSystem, SelectionNode, ShaderHelper, ShadowMapPass, ShadowMapper, ShadowRegion, Shape, SharedModel, SignNode, SimplexNoise2DNode, SinHNode, SinNode, Skeleton, SkeletonModifier, SkeletonRig, SkinBinding, SkyEnvTextureNode, SkyRenderer, SmoothStepNode, SphereShape, SpotLight, SpringChain, SpringModifier, SpringSystem, Sprite, SpriteBlockNode, SpriteBlueprintMaterial, SpriteMaterial, SqrtNode, StandardSpriteMaterial, StepNode, SubsurfaceProfile, SwizzleNode, TAA, TAA_DEBUG_ALAPH, TAA_DEBUG_CURRENT_COLOR, TAA_DEBUG_EDGE, TAA_DEBUG_HISTORY_COLOR, TAA_DEBUG_MOTION_VECTOR, TAA_DEBUG_NONE, TAA_DEBUG_STRENGTH, TAA_DEBUG_VELOCITY, TanHNode, TanNode, TetrahedronFrameShape, TetrahedronShape, TextSprite, TextureSampleGrad, TextureSampleNode, Tonemap, TorusShape, TransformNode, TwoBoneIKSolver, UnlitMaterial, VSM, VertexBinormalNode, VertexBlockNode, VertexColorNode, VertexIndexNode, VertexNormalNode, VertexOutputNode, VertexPositionNode, VertexTangentNode, VertexUVNode, ViewMatrixNode, ViewProjMatrixNode, Water, WaterShaderImpl, WeightedBlendedOIT, aerialPerspective, aerialPerspectiveLut, appInstance, applyAngleLimits, applyMaterialMixins, applyResult, applyRuntimeScriptConfig, atmosphereLUTRendered, buildConstraints, buildMSDFShape, buildSurfaceFaces, checkSurfaceCollision, collisionDetection, collisionDetectionCapsule, collisionDetectionSphere, computeMaxDepth, computeNearestPoints, copyTexture, createAPLutProgram, createCapsuleCollider, createGPUClothWrapBindingData, createGeometryCacheState, createGradientNoiseTexture, createMultiScatteringLutProgram, createPlaneCollider, createProgramFFT2H, createProgramFFT2V, createProgramH0, createProgramHk, createProgramOcean, createProgramPostFFT2, createRandomNoiseTexture, createSkyViewLutProgram, createSphereCollider, createSpringConstraint, createSpringParticle, createTransformAccess, createTransmittanceLutProgram, debugTexture, decode2HalfFromRGBA, decodeFloatFromRGBA, decodeNormalizedFloatFromRGBA, decodeRGBM, defineProps, encode2HalfToRGBA, encodeFloatToRGBA, encodeNormalizedFloatToRGBA, encodeRGBM, ensureGeometryCacheMeshBinding, extractLocalTwist, fetchNormalizedFloatForDevice, fetchSampler, gammaToLinear, generateMSDF, getAerialPerspectiveLut, getApp, getAtmosphereParamsStruct, getBatchGroupClass, getCameraClass, getDefaultAtmosphereParams, getDefaultTexture2D, getDefaultTexture2DArray, getDefaultTextureCube, getDevice, getDirectionalLightClass, getEngine, getGraphNodeClass, getInput, getMeshClass, getMultiScattering, getMultiScatteringLut, getNodeTypeComponents, getOrthoCameraClass, getParticleNodeClass, getPerspectiveCameraClass, getPointLightClass, getPunctualLightClass, getRectLightClass, getRuntimeScriptProperties, getSceneNodeClass, getSkyView, getSkyViewLut, getSpotLightClass, getTransmittanceLut, gradient, hash11, hash12, hash13, hash21, hash22, hash23, hash31, hash32, hash33, integralMultiScattering, interleavedGradientNoise, isGPUClothSupported, linearToGamma, mieAbsorption, mieCoefficient, miePhase, mixGeometryCacheBoundingBox, mixinAlbedoColor, mixinBlinnPhong, mixinFoliage, mixinLambert, mixinLight, mixinPBRBluePrint, mixinPBRCommon, mixinPBRMetallicRoughness, mixinPBRSpecularGlossness, mixinTextureProps, mixinVertexColor, multiScatteringLut, noise3D, normalizeRuntimeScriptConfig, normalizeScriptAttachmentConfig, normalizeScriptAttachments, ozoneAbsorption, panoramaToCubemap, perlinNoise2D, perlinNoise3D, prefilterCubemap, pushInCollisionDetection, pushInFromCapsule, pushInFromCollider, pushInFromSphere, pushoutFromCapsule, pushoutFromCollider, pushoutFromSphere, rayIntersectSphere, rayleighCoefficient, rayleighPhase, renderAPLut, renderAtmosphereLUTs, renderMultiScatteringLut, renderSkyViewLut, renderTransmittanceLut, resolveCapsuleCollision, resolvePlaneCollision, resolveSphereCollision, restoreGeometryCacheMeshBinding, scattering, scriptProp, setApp, setSceneMeshAssetBinding, simulate, skyBox, skyViewLut, smoothNoise3D, sortRootPointsByProximity, temporalResolve, transmittance, transmittanceLut, transmittanceLutToUV, transmittanceToSky, tryGetApp, uniformSphereSamples, updateColliderFromNode, uvToTransmittanceLut, uvToViewDir, valueNoise, viewDirToUV, whiteNoise, worleyFBM, worleyNoise };
|
|
95223
|
+
export { AABBTree, ABufferOIT, ATMOSPHERIC_FOG_BIT, AbsNode, AbstractPostEffect, AllConditionNode, AnimationClip, AnimationController, AnimationPlayback, AnimationSet, AnimationTimeline, AnimationTimelineRunner, AnimationTrack, AnyConditionNode, Application, ArcCosNode, ArcSinNode, ArcTan2Node, ArcTanNode, ArccosineHNode, ArcsineHNode, ArctangentHNode, AssetHierarchyNode, AssetManager, AssetScene, AssetSkeleton, AvatarOutfitInstance, AvatarWardrobe, BUILTIN_ASSET_TEST_CUBEMAP, BUILTIN_ASSET_TEXTURE_SHEEN_LUT, BaseCameraController, BaseGraphNode, BaseLight, BaseSprite, BaseTextureNode, BatchGroup, BillboardMatrixNode, BlinnMaterial, Blitter, Bloom, BoundingBox, BoxFilterBlitter, BoxFrameShape, BoxShape, CAMERA_POS_Y, CCDSolver, Camera, CameraNearFarNode, CameraPositionNode, CameraVectorNode, CapsuleShape, CeilNode, ClampNode, Clipmap, ClipmapTerrain, ClipmapTerrainMaterial, ColliderForce, ColorAdjust, CompAddNode, CompComparisonNode, CompDivNode, CompMulNode, CompSubNode, Compositor, ConstantBVec2Node, ConstantBVec3Node, ConstantBVec4Node, ConstantBooleanNode, ConstantScalarNode, ConstantTexture2DArrayNode, ConstantTexture2DNode, ConstantTextureCubeNode, ConstantVec2Node, ConstantVec3Node, ConstantVec4Node, ConstraintType, CopyBlitter, CosHNode, CosNode, CrossProductNode, CubemapSHProjector, CullVisitor, CylinderShape, DDXNode, DDYNode, Degrees2RadiansNode, DepthPass, DirectionalLight, DistanceNode, DotProductNode, DracoMeshDecoder, EPSILON$1 as EPSILON, ESM, ElapsedTimeNode, Engine, EnvConstantAmbient, EnvHemisphericAmbient, EnvLightWrapper, EnvShIBL, Environment, EnvironmentLighting, EqualNode, Exp2Node, ExpNode, FABRIKSolver, FBMWaveGenerator, FFTWaveGenerator, FPSCameraController, FWidthNode, FXAA, FaceForwardNode, FixedGeometryCacheTrack, FloorNode, FmaNode, Fog, FontAsset, FractNode, FunctionCallNode, FunctionInputNode, FunctionOutputNode, GPUClothSystem, GaussianBlurBlitter, GenericMathNode, GerstnerWaveGenerator, GraphNode, GrassInstances, GrassLayer, GrassMaterial, GrassQuadtreeNode, GrassRenderer, Grayscale, HEIGHT_FOG_BIT, Hash1Node, Hash2Node, Hash3Node, HistoryResourceManager, HumanoidBodyRig, HumanoidHandRig, IKAngleConstraint, IKChain, IKConstraint, IKModifier, IKSolver, InputManager, InstanceBindGroupAllocator, InstanceIndexNode, InvProjMatrixNode, InvSqrtNode, InvViewProjMatrixNode, JointDynamicsModifier, JointDynamicsSystem, JointDynamicsSystemController, LIGHT_TYPE_DIRECTIONAL, LIGHT_TYPE_NONE, LIGHT_TYPE_POINT, LIGHT_TYPE_RECT, LIGHT_TYPE_SPOT, LambertMaterial, LengthNode, LightPass, Log2Node, LogNode, LogicallyAndNode, LogicallyOrNode, MAX_CLUSTERED_LIGHTS, MAX_GERSTNER_WAVE_COUNT, MAX_MORPH_ATTRIBUTES, MAX_MORPH_TARGETS, MAX_TERRAIN_MIPMAP_LEVELS, MORPH_ATTRIBUTE_VECTOR_COUNT, MORPH_TARGET_COLOR, MORPH_TARGET_NORMAL, MORPH_TARGET_POSITION, MORPH_TARGET_TANGENT, MORPH_TARGET_TEX0, MORPH_TARGET_TEX1, MORPH_TARGET_TEX2, MORPH_TARGET_TEX3, MORPH_WEIGHTS_VECTOR_COUNT, MSDFText, MSDFTextAtlasManager, MSDFTextSprite, MToonMaterial, MakeVectorNode, Material, MaterialBlueprintIR, MaterialVaryingFlags, MaxNode, Mesh, MeshMaterial, MinNode, MixNode, ModNode, MorphTargetTrack, MultiChainSpringSystem, NamedObject, NodeEulerRotationTrack, NodeRotationTrack, NodeScaleTrack, NodeTranslationTrack, NormalizeNode, NotEqualNode, Octree, OctreeNode, OctreeNodeChunk, OctreePlacement, OrbitCameraController, OrthoCamera, PBRBlockNode, PBRBluePrintMaterial, PBRMetallicRoughnessMaterial, PBRSpecularGlossinessMaterial, PCAGeometryCacheTrack, PCFOPT, PCFPD, PannerNode, ParticleMaterial, ParticleSystem, PerlinNoise2DNode, PerspectiveCamera, PixelNormalNode, PixelWorldPositionNode, PlaneShape, PointLight, PostEffectLayer, PowNode, Primitive, ProjectionMatrixNode, PropertyTrack, PunctualLight, QUEUE_OPAQUE, QUEUE_TRANSPARENT, RENDER_PASS_TYPE_DEPTH, RENDER_PASS_TYPE_LIGHT, RENDER_PASS_TYPE_OBJECT_COLOR, RENDER_PASS_TYPE_SHADOWMAP, Radians2DegreesNode, RaycastVisitor, RectLight, ReflectNode, RefractNode, RenderPass, RenderQueue, RenderTarget, ResolveVertexNormalNode, ResolveVertexPositionNode, ResolveVertexTangentNode, ResourceManager, RotateAboutAxisNode, RuntimeScript, SAO, SSS, SaturateNode, Scene, SceneNode, SceneRenderer, ScreenAdapter, ScreenRenderTarget, ScriptAttachment, ScriptRegistry, ScriptingSystem, SelectionNode, ShaderHelper, ShadowMapPass, ShadowMapper, ShadowRegion, Shape, SharedModel, SignNode, SimplexNoise2DNode, SinHNode, SinNode, Skeleton, SkeletonModifier, SkeletonRig, SkinBinding, SkyEnvTextureNode, SkyRenderer, SmoothStepNode, SphereShape, SpotLight, SpringChain, SpringModifier, SpringSystem, Sprite, SpriteBlockNode, SpriteBlueprintMaterial, SpriteMaterial, SqrtNode, StandardSpriteMaterial, StepNode, SubsurfaceProfile, SwizzleNode, TAA, TAA_DEBUG_ALAPH, TAA_DEBUG_CURRENT_COLOR, TAA_DEBUG_EDGE, TAA_DEBUG_HISTORY_COLOR, TAA_DEBUG_MOTION_VECTOR, TAA_DEBUG_NONE, TAA_DEBUG_STRENGTH, TAA_DEBUG_VELOCITY, TanHNode, TanNode, TetrahedronFrameShape, TetrahedronShape, TextSprite, TextureSampleGrad, TextureSampleNode, Tonemap, TorusShape, TransformNode, TwoBoneIKSolver, UnlitMaterial, VSM, VertexBinormalNode, VertexBlockNode, VertexColorNode, VertexIndexNode, VertexNormalNode, VertexOutputNode, VertexPositionNode, VertexTangentNode, VertexUVNode, ViewMatrixNode, ViewProjMatrixNode, Water, WaterShaderImpl, WeightedBlendedOIT, aerialPerspective, aerialPerspectiveLut, appInstance, applyAngleLimits, applyMaterialMixins, applyResult, applyRuntimeScriptConfig, atmosphereLUTRendered, buildConstraints, buildMSDFShape, buildSurfaceFaces, checkSurfaceCollision, collisionDetection, collisionDetectionCapsule, collisionDetectionSphere, computeMaxDepth, computeNearestPoints, copyTexture, createAPLutProgram, createCapsuleCollider, createGPUClothWrapBindingData, createGeometryCacheState, createGradientNoiseTexture, createMultiScatteringLutProgram, createPlaneCollider, createProgramFFT2H, createProgramFFT2V, createProgramH0, createProgramHk, createProgramOcean, createProgramPostFFT2, createRandomNoiseTexture, createSkyViewLutProgram, createSphereCollider, createSpringConstraint, createSpringParticle, createTransformAccess, createTransmittanceLutProgram, debugTexture, decode2HalfFromRGBA, decodeFloatFromRGBA, decodeNormalizedFloatFromRGBA, decodeRGBM, defineProps, encode2HalfToRGBA, encodeFloatToRGBA, encodeNormalizedFloatToRGBA, encodeRGBM, ensureGeometryCacheMeshBinding, extractLocalTwist, fetchNormalizedFloatForDevice, fetchSampler, gammaToLinear, generateMSDF, getAerialPerspectiveLut, getApp, getAtmosphereParamsStruct, getBatchGroupClass, getCameraClass, getDefaultAtmosphereParams, getDefaultTexture2D, getDefaultTexture2DArray, getDefaultTextureCube, getDevice, getDirectionalLightClass, getEngine, getGraphNodeClass, getInput, getMeshClass, getMultiScattering, getMultiScatteringLut, getNodeTypeComponents, getOrthoCameraClass, getParticleNodeClass, getPerspectiveCameraClass, getPointLightClass, getPunctualLightClass, getRectLightClass, getRuntimeScriptProperties, getSceneNodeClass, getSkyView, getSkyViewLut, getSpotLightClass, getTransmittanceLut, gradient, hash11, hash12, hash13, hash21, hash22, hash23, hash31, hash32, hash33, integralMultiScattering, interleavedGradientNoise, isGPUClothSupported, linearToGamma, mieAbsorption, mieCoefficient, miePhase, mixGeometryCacheBoundingBox, mixinAlbedoColor, mixinBlinnPhong, mixinFoliage, mixinLambert, mixinLight, mixinPBRBluePrint, mixinPBRCommon, mixinPBRMetallicRoughness, mixinPBRSpecularGlossness, mixinTextureProps, mixinVertexColor, multiScatteringLut, noise3D, normalizeRuntimeScriptConfig, normalizeScriptAttachmentConfig, normalizeScriptAttachments, ozoneAbsorption, panoramaToCubemap, perlinNoise2D, perlinNoise3D, prefilterCubemap, pushInCollisionDetection, pushInFromCapsule, pushInFromCollider, pushInFromSphere, pushoutFromCapsule, pushoutFromCollider, pushoutFromSphere, rayIntersectSphere, rayleighCoefficient, rayleighPhase, renderAPLut, renderAtmosphereLUTs, renderMultiScatteringLut, renderSkyViewLut, renderTransmittanceLut, resolveCapsuleCollision, resolvePlaneCollision, resolveSphereCollision, restoreGeometryCacheMeshBinding, scattering, scriptProp, setApp, setSceneMeshAssetBinding, simulate, skyBox, skyViewLut, smoothNoise3D, sortRootPointsByProximity, temporalResolve, transmittance, transmittanceLut, transmittanceLutToUV, transmittanceToSky, tryGetApp, uniformSphereSamples, updateColliderFromNode, uvToTransmittanceLut, uvToViewDir, valueNoise, viewDirToUV, whiteNoise, worleyFBM, worleyNoise };
|
|
93034
95224
|
//# sourceMappingURL=zephyr3d_scene.js.map
|