@hology/core 0.0.230 → 0.0.232
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE.md +14 -14
- package/README.md +2 -2
- package/dist/effects/sequence/sequence-action.d.ts +2 -1
- package/dist/effects/sequence/sequence-actor.d.ts +2 -1
- package/dist/effects/sequence/sequence-player.d.ts +1 -0
- package/dist/effects/sequence/sequence-player.js +1 -1
- package/dist/gameplay/actors/component.d.ts +6 -1
- package/dist/gameplay/index.d.ts +1 -1
- package/dist/rendering/webgpu-experimental-backend.js +1 -1
- package/dist/scene/asset-resource-loader.d.ts +6 -1
- package/dist/scene/asset-resource-loader.js +1 -1
- package/dist/scene/materializer.d.ts +1 -0
- package/dist/scene/materializer.js +1 -1
- package/dist/test/sequence-vfx.test.js +1 -1
- package/package.json +1 -1
- package/tsconfig.tsbuildinfo +1 -1
package/LICENSE.md
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
# Hology Interactive AB Limited License
|
|
2
|
-
|
|
3
|
-
This software package, including all associated files and documentation (the "Software"), is licensed to you (the "Licensee") by Hology Interactive AB for use exclusively with the product "Hology Engine."
|
|
4
|
-
|
|
5
|
-
By using, copying, modifying, or distributing the Software, Licensee agrees to be bound by the terms of this license.
|
|
6
|
-
|
|
7
|
-
1. License Grant: Hology Interactive AB grants Licensee a limited, non-exclusive, non-transferable license to use the Software solely for the purpose of developing and running software developed with "Hology Engine."
|
|
8
|
-
|
|
9
|
-
2. Restrictions: Licensee may not use, copy, modify, or distribute the Software for any other purpose, including but not limited to the creation of derivative works, standalone applications, or any products not directly associated with "Hology Engine."
|
|
10
|
-
|
|
11
|
-
3. Ownership: Hology Interactive AB retains all intellectual property rights to the Software. This license does not transfer ownership of the Software to Licensee.
|
|
12
|
-
|
|
13
|
-
4. Warranty Disclaimer: THE SOFTWARE IS PROVIDED "AS IS," WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NONINFRINGEMENT. IN NO EVENT SHALL THE CREATOR OF THIS PACKAGE BE LIABLE FOR ANY CLAIM, DAMAGES, OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT, OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION WITH THE SOFTWARE.
|
|
14
|
-
|
|
1
|
+
# Hology Interactive AB Limited License
|
|
2
|
+
|
|
3
|
+
This software package, including all associated files and documentation (the "Software"), is licensed to you (the "Licensee") by Hology Interactive AB for use exclusively with the product "Hology Engine."
|
|
4
|
+
|
|
5
|
+
By using, copying, modifying, or distributing the Software, Licensee agrees to be bound by the terms of this license.
|
|
6
|
+
|
|
7
|
+
1. License Grant: Hology Interactive AB grants Licensee a limited, non-exclusive, non-transferable license to use the Software solely for the purpose of developing and running software developed with "Hology Engine."
|
|
8
|
+
|
|
9
|
+
2. Restrictions: Licensee may not use, copy, modify, or distribute the Software for any other purpose, including but not limited to the creation of derivative works, standalone applications, or any products not directly associated with "Hology Engine."
|
|
10
|
+
|
|
11
|
+
3. Ownership: Hology Interactive AB retains all intellectual property rights to the Software. This license does not transfer ownership of the Software to Licensee.
|
|
12
|
+
|
|
13
|
+
4. Warranty Disclaimer: THE SOFTWARE IS PROVIDED "AS IS," WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, AND NONINFRINGEMENT. IN NO EVENT SHALL THE CREATOR OF THIS PACKAGE BE LIABLE FOR ANY CLAIM, DAMAGES, OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT, OR OTHERWISE, ARISING FROM, OUT OF, OR IN CONNECTION WITH THE SOFTWARE.
|
|
14
|
+
|
|
15
15
|
6. Contact: For any inquiries regarding this license, please email hello@hology.app
|
package/README.md
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
# Hology Engine Core
|
|
2
|
-
|
|
1
|
+
# Hology Engine Core
|
|
2
|
+
|
|
3
3
|
For the development with Hology Engine (https://hology.app/)
|
|
@@ -11,7 +11,8 @@ export interface SequenceAction extends SequenceLocatorReader {
|
|
|
11
11
|
/** Bind a role to a runtime target for dynamic actor binding */
|
|
12
12
|
bindRole(role: SequenceRole, target: BaseActor | Object3D): void;
|
|
13
13
|
/**
|
|
14
|
-
* Resolve and preload resources
|
|
14
|
+
* Resolve and preload resources used by this sequence, including animation
|
|
15
|
+
* variants that depend on runtime role bindings and VFX render resources.
|
|
15
16
|
* Call this before latency-sensitive playback after all roles are bound.
|
|
16
17
|
*/
|
|
17
18
|
prepare(): Promise<void>;
|
|
@@ -122,7 +122,8 @@ export declare class SequenceActor extends BaseActor implements SequenceAction {
|
|
|
122
122
|
*/
|
|
123
123
|
bindRole(role: SequenceRole, target: BaseActor | Object3D): void;
|
|
124
124
|
/**
|
|
125
|
-
* Preload binding-dependent animation variants
|
|
125
|
+
* Preload binding-dependent animation variants and VFX render resources before
|
|
126
|
+
* latency-sensitive playback.
|
|
126
127
|
*/
|
|
127
128
|
prepare(): Promise<void>;
|
|
128
129
|
/**
|
|
@@ -233,6 +233,7 @@ export declare class SequencePlayer implements SequenceLocatorReader {
|
|
|
233
233
|
* Resolve and preload animation variants after role/spawn targets are known.
|
|
234
234
|
*/
|
|
235
235
|
prepare(): Promise<void>;
|
|
236
|
+
private preloadVisualEffectsForSequence;
|
|
236
237
|
private prepareAnimationClipsForBindings;
|
|
237
238
|
/**
|
|
238
239
|
* Bind a role to a runtime target.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{BehaviorSubject as e,Subject as t}from"rxjs";import*as a from"three";import{AnimationMixer as s,Color as i,Euler as r,Object3D as n,Quaternion as o,Vector2 as l,Vector3 as c,Vector4 as h}from"three";import{VisualEffect as u}from"../../effects/vfx/vfx-param.js";import{BaseActor as p}from"../../gameplay/actors/actor.js";import d from"../../gameplay/actors/builtin/index.js";import{Prefab as f,PrefabOf as m}from"../../scene/objects/prefab.js";import{SerializedParamType as y}from"../../scene/model.js";import{customParamValueNeedsAsyncResolution as v,deserializeCustomParamValue as C,deserializeCustomParamValueSync as g}from"../../scene/custom-param-deserialize.js";import{getAudioParameterDefinition as A}from"./audio-parameters.js";import{getMaterialSubTrackMatchMode as S,getMaterialSubTrackTarget as w,Sequence as P,isSequenceData as b}from"./sequence-data.js";import{getSequenceSubTrackDefinition as k,getSequenceTrackDefinition as x}from"./sequence-definitions.js";import{applyInterpolation as T,evaluateCustomParamValueKeyframes as I,evaluateNumericKeyframes as M,findKeyframeSpan as B}from"./sequence-value-lane.js";import{evaluateTransformPositionSpan as q}from"./sequence-transform.js";import{applyAnimationClipRootMotionAxisMask as O,buildRetimedAnimationClip as F,getAnimationClipRetimingSignature as E,isAnimationClipUsingRetiming as j}from"./sequence-animation-retiming.js";import*as R from"three/addons/utils/SkeletonUtils.js";import{CharacterAnimationComponent as V,getCharacterMovementLike as _}from"../../gameplay/actors/index.js";import{RootMotionClip as L}from"../../gameplay/animation/root-motion.js";import{markMaterialUniformValuesNeedUpdate as D}from"../../rendering/node-material-webgpu-resolver.js";import{getAnimationClipRigId as K,getAnimationRigIdFromObject as $,setAnimationClipRigId as G}from"../../gameplay/animation/retarget.js";import{hashCameraShakeSeed as N}from"../../gameplay/services/camera-shake.js";import{buildShaderGraphPostProcessMaterial as U,shaderGraphPostProcessWeightUniformName as W}from"../../shader/graph/index.js";export var SequencePlaybackState;!function(e){e.Stopped="stopped",e.Playing="playing",e.Paused="paused"}(SequencePlaybackState||(SequencePlaybackState={}));export class SequencePlayer{constructor(){this._state=new e(SequencePlaybackState.Stopped),this._time=new e(0),this._duration=0,this._timescale=1,this._loop=!1,this._externalTimeControl=!1,this._inEditor=!1,this.bindings=new Map,this.roleBindings=new Map,this.sequenceData=null,this.onComplete=new t,this.onLoop=new t,this.onTimeUpdate=this._time.asObservable(),this.onStateChange=this._state.asObservable(),this.loopCount=0,this.viewController=null,this._cameraControlEnabled=!1,this._cameraControlTrackId=null,this.sequenceCameras=new Map,this.cameraPlayables=new Map,this.cameraBlendCamera=null,this.cameraBlendSource=null,this.cameraBlendOutSource=null,this.cameraOverrideHandle=null,this.activeCameraClipKey=null,this.cameraBlendOutClipKey=null,this.activeCameraShakeClipKeys=new Set,this.nextCameraShakeClipKeys=new Set,this.activePostProcessClips=new Map,this.nextPostProcessClipKeys=new Set,this.audioListener=null,this.audioBuffers=new Map,this.loadingAudioBuffers=new Map,this.animationClips=new Map,this.loadingAnimationClips=new Map,this.retimedAnimationClips=new Map,this.externalRootMotionInterpolants=new WeakMap,this.audioByClip=new Map,this.activeAudioClips=new Set,this.audioGainNodes=new Map,this.audioStartInFlight=new Map,this.lastAudioStartAttemptTime=new Map,this.audioStartRetryIntervalSeconds=.25,this.world=null,this.assetLoader=null,this.actorFactory=null,this.vfxService=null,this.spawnedInstances=new Map,this.activeClips=new Set,this.pendingSpawns=new Set,this.vfxActors=new Map,this.activeVfxClips=new Set,this.locatorMarkers=new Map,this.clearCounter=0,this.propertyPathSegments=new Map,this.propertyResolutionCache=new Map,this.propertySnapshots=new Map,this.materialResolutionCache=new Map,this.materialSnapshots=new Map,this.audioFilters=new Map,this.audioPannerNodes=new Map,this.firedEvents=new Set,this.sequenceEventSyncResolvers={actor:e=>this.resolveSequenceEventActorReference(e)},this.sequenceEventAsyncResolvers={actor:e=>this.resolveSequenceEventActorReference(e),texture:e=>this.assetLoader?.getTextureByAssetId(e)??null,sampler2DNode:e=>this.assetLoader?.getTextureByAssetId(e)??null,object3D:async e=>{const t=await(this.assetLoader?.getModelByAssetId(e));return t?.scene??null},material:e=>this.assetLoader?.getMaterialByAssetId(e)??null,audioBuffer:e=>this.assetLoader?.getAudioByAssetId(e)??null,visualEffect:async e=>{if(!this.assetLoader||!this.actorFactory)return null;const t=await this.assetLoader.getAsset(e);return t?new u(this.actorFactory,t):null},prefab:async e=>{const t=await(this.assetLoader?.getPrefabById(e));return t?new f(t.asset):null},prefabActor:async e=>{const t=await(this.assetLoader?.getPrefabById(e));return t?new m(new f(t.asset)):null},sequence:e=>this.resolveSequenceEventSequence(e),animationClip:e=>this.resolveSequenceEventAnimationClip(e)},this.trackRuntimeEvaluators={object:(e,t,a)=>{t&&this.evaluateObjectTrack(e,t,a)},locator:(e,t,a)=>{t&&this.evaluateLocatorTrack(e,t,a)},camera:(e,t,a)=>this.evaluateCameraTrack(e,a),cameraShake:(e,t,a)=>this.evaluateCameraShakeTrack(e,a),postProcess:(e,t,a)=>this.evaluatePostProcessTrack(e,a),audio:(e,t,a)=>this.evaluateAudioTrack(e,a),vfx:(e,t,a)=>this.evaluateVfxTrack(e,a),spawn:(e,t,a)=>this.evaluateSpawnTrack(e,t,a),group:(e,t,a)=>{if("group"===e.type)for(const t of e.childTracks)this.evaluateTrack(t,a)}},this.subTrackRuntimeEvaluators={transform:(e,t,a)=>{const s=this.getPlayableObject(t);s&&this.evaluateTransformSubTrack(e,s,a)},animation:(e,t,a)=>this.evaluateAnimationSubTrack(e,t,a),visibility:(e,t,a)=>{const s=this.getPlayableObject(t);s&&this.evaluateVisibilitySubTrack(e,s,a)},parameter:(e,t,a)=>this.evaluateParameterSubTrack(e,t.target||null,a),event:(e,t,a)=>this.evaluateEventSubTrack(e,t.target||null,a)}}get state(){return this._state.value}get time(){return this._time.value}get duration(){return this._duration}get timescale(){return this._timescale}set timescale(e){this._timescale=Math.max(.01,e)}get loop(){return this._loop}set loop(e){this._loop=e}get externalTimeControl(){return this._externalTimeControl}set externalTimeControl(e){this._externalTimeControl=e}get inEditor(){return this._inEditor}set inEditor(e){this._inEditor=e,this.updateLocatorMarkerVisibility()}get cameraControlEnabled(){return this._cameraControlEnabled}set cameraControlEnabled(e){this._cameraControlEnabled=e,e||this.releaseCameraOverride()}get cameraControlTrackId(){return this._cameraControlTrackId}set cameraControlTrackId(e){this._cameraControlTrackId!==e&&(this._cameraControlTrackId=e,this.releaseCameraOverride())}setViewController(e){this.viewController&&this.viewController!==e&&this.viewController.clearCameraShakeContributionsForOwner(this),this.viewController=e}setWorld(e){this.world!==e&&(this.restoreAllPropertySnapshots(),this.restoreAllMaterialSnapshots(),this.clearLocatorBindings(),this.clearSequenceCameras(),this.clearCameraShakeContributions(),this.clearPostProcessEffects(),this.world=e,this.clearCounter++,this.vfxActors.clear(),this.spawnedInstances.clear(),this.bindings.clear(),this.activeClips.clear(),this.activeVfxClips.clear(),this.activeAudioClips.clear(),this.audioStartInFlight.clear(),this.lastAudioStartAttemptTime.clear(),this.loadingAudioBuffers.clear(),this.audioFilters.clear(),this.audioPannerNodes.clear(),this.pendingSpawns.clear(),this.propertyResolutionCache.clear(),this.materialResolutionCache.clear(),this.clearRetimedAnimationClipCache(),this._state.next(SequencePlaybackState.Stopped),this.sequenceData&&this.initializeLocatorBindings())}setAudioListener(e){this.audioListener=e}setAssetLoader(e){if(this.assetLoader=e,this.sequenceData){const e=this.clearCounter;this.preloadSequenceResources(this.sequenceData,e)}}setActorFactory(e){this.actorFactory=e}setVfxService(e){this.vfxService=e}load(e){if(this.stop(),this.clearCounter++,this.clearLocatorBindings(),this.clearSequenceCameras(),this.sequenceData=e,this._duration=e.duration,this._loop=e.loop,this._timescale=e.playbackRate,this.clearRetimedAnimationClipCache(),this.bindings.clear(),this.initializeLocatorBindings(),this.loopCount=0,this.assetLoader){const t=this.clearCounter;this.preloadSequenceResources(e,t)}}preloadSequenceResources(e,t){return Promise.all([this.preloadAudioBuffersForSequence(e,t),this.preloadAnimationClipsForSequence(e,t)]).then(()=>{})}getAudioAssetIdsForSequence(e){const t=new Set;for(const a of e.tracks){if("audio"!==a.type)continue;const e=a;for(const a of e.clips??[])a.audioAssetId&&t.add(a.audioAssetId)}return[...t]}async preloadAudioBuffersForSequence(e,t){if(!this.assetLoader)return;const a=this.getAudioAssetIdsForSequence(e);0!==a.length&&await Promise.all(a.map(async e=>{if(t!==this.clearCounter)return;if(this.audioBuffers.has(e))return;let a=this.loadingAudioBuffers.get(e);a||(a=this.assetLoader.getAudioByAssetId(e),this.loadingAudioBuffers.set(e,a));try{const s=await a;if(t!==this.clearCounter)return;this.audioBuffers.set(e,s)}catch(e){}finally{this.loadingAudioBuffers.get(e)===a&&this.loadingAudioBuffers.delete(e)}}))}async preloadAnimationClipsForSequence(e,t){this.assetLoader&&t===this.clearCounter&&await this.prepareAnimationClipsForBindings(e,t)}async prepare(){if(!this.sequenceData||!this.assetLoader)return;this.resolveBindings();const e=this.clearCounter;await this.prepareAnimationClipsForBindings(this.sequenceData,e)}async prepareAnimationClipsForBindings(e,t){const a=[];for(const s of ne(e.tracks)){if(!("subTracks"in s))continue;const e=this.bindings.get(s.id),i=null==e?null:this.getPlayableObject(e);if(null==i)continue;const r=$(i);for(const e of s.subTracks)if("animation"===e.type)for(const s of e.clips){if(t!==this.clearCounter)return;if(null!=s.animationClipAssetId){const e=this.animationClipCacheKey(s.animationClipAssetId,r);a.push(this.ensureAnimationClip(s.animationClipAssetId,r).then(a=>{null!=a&&t===this.clearCounter&&j(s)&&(this.getPlayableAnimationClip(e,a,s,!1),s.rootMotion&&this.getPlayableAnimationClip(e,a,s,!0))}))}}}await Promise.all(a)}bindRole(e,t){this.roleBindings.set(e,t),this.sequenceData&&this.resolveBindings()}bindObject(e,t){if(this.sequenceData)for(const a of ne(this.sequenceData.tracks))"object"!==a.type||a.targetId!==e||a.role||this.createBinding(a,t)}unbindObject(e){if(this.sequenceData)for(const t of ne(this.sequenceData.tracks))"object"!==t.type||t.targetId!==e||t.role||this.removeBinding(t.id)}getLocator(e){return this.getLocators(e)[0]??null}getLocators(e){const t=oe(e);if(!t||!this.sequenceData)return[];const a=[];for(const e of ne(this.sequenceData.tracks)){if("locator"!==e.type)continue;if(oe(e.bindingId)!==t)continue;const s=this.bindings.get(e.id),i=s?this.getPlayableObject(s):null;i&&(i.updateWorldMatrix(!0,!1),a.push({trackId:e.id,name:e.name,bindingId:e.bindingId,position:i.getWorldPosition(new c),rotation:i.getWorldQuaternion(new o),scale:i.getWorldScale(new c)}))}return a}resolveBindings(){if(this.sequenceData)for(const e of this.sequenceData.tracks)this.resolveTrackBinding(e)}initializeLocatorBindings(){if(this.sequenceData)for(const e of ne(this.sequenceData.tracks)){if("locator"!==e.type||this.bindings.has(e.id))continue;const t=new n;t.name=e.name||"Locator",t.userData.sequenceLocatorTrackId=e.id,this.world?.scene&&null==t.parent&&this.world.scene.add(t);const a=le(e.name);a.visible=this._inEditor,t.add(a),this.locatorMarkers.set(e.id,a),this.disableLocatorInteraction(t),this.createBinding(e,t)}}clearLocatorBindings(){for(const e of this.locatorMarkers.values())ce(e);for(const e of this.bindings.values()){if("locator"!==e.track.type)continue;const t=this.getPlayableObject(e);t?.parent&&t.removeFromParent()}this.locatorMarkers.clear()}updateLocatorMarkerVisibility(){for(const e of this.locatorMarkers.values())e.visible=this._inEditor}disableLocatorInteraction(e){e.traverse(e=>{e.raycast=()=>{}})}resolveTrackBinding(e){if("object"===e.type){const t=e;t.role&&this.roleBindings.has(t.role)&&this.createBinding(e,this.roleBindings.get(t.role))}else if("spawn"===e.type){const t=e;t.role&&this.roleBindings.has(t.role)&&this.createBinding(e,this.roleBindings.get(t.role))}else if("group"===e.type)for(const t of e.childTracks)this.resolveTrackBinding(t)}createBinding(e,t){const a=t instanceof p?t.object:t,i=this.bindings.get(e.id),r=null!=i?i.target instanceof p?i.target.object:i.target:null,n=null!=i&&i.target===t&&r===a,o=e.subTracks.some(e=>"animation"===e.type);null==i||n||this.releaseBinding(i);const l=n?i:{track:e,target:t,activeActions:new Map};l.track=e,l.target=t,n||(l.originalTransform={position:a.position.clone(),rotation:a.rotation.clone(),scale:a.scale.clone()},l.originalParent=a.parent),o&&null==l.mixer?l.mixer=new s(a):o||(l.mixer=void 0),this.bindings.set(e.id,l)}removeBinding(e){const t=this.bindings.get(e);t&&(this.releaseBinding(t),this.bindings.delete(e))}releaseBinding(e){this.clearExternalRootMotionPreview(e);for(const t of e.activeActions.values())t.stop();e.activeActions.clear(),e.mixer?.stopAllAction(),e.charAnimComponent?.stopSequenceAnimation(),e.charAnimComponent=void 0,e.charAnimActionKeys?.clear()}play(){this._state.value!==SequencePlaybackState.Playing&&this.sequenceData&&(this._state.value===SequencePlaybackState.Stopped&&(this._time.next(0),this.loopCount=0,this.resolveBindings(),this.captureOriginalTransforms()),this._state.next(SequencePlaybackState.Playing),this.evaluate(this._time.value),this.resumeVfx())}pause(){this._state.value===SequencePlaybackState.Playing&&(this._state.next(SequencePlaybackState.Paused),this.pauseAudio(),this.pauseVfx())}pauseAudio(){for(const e of this.audioByClip.values())e.pause()}pauseVfx(){for(const e of this.vfxActors.values())e.pause()}resumeVfx(){for(const[e,t]of this.vfxActors.entries())(this.activeVfxClips.has(e)||t.getParticleCount()>0)&&t.play()}cancel(){this._state.next(SequencePlaybackState.Stopped),this._time.next(0),this.clearCounter++,this.loopCount=0,this.pauseAudio(),this.releaseCameraOverride(),this.restoreAllPropertySnapshots(),this.restoreAllMaterialSnapshots(),this.stopAllAudio(),this.stopAllAnimations(),this.despawnAll(),this.stopAllVfx(),this.firedEvents.clear(),this.clearCameraShakeContributions(),this.clearPostProcessEffects()}stop(){this._state.next(SequencePlaybackState.Stopped),this._time.next(0),this.clearCounter++,this.loopCount=0,this.pauseAudio(),this.releaseCameraOverride(),this.restoreAllPropertySnapshots(),this.restoreAllMaterialSnapshots(),this.restoreOriginalTransforms(),this.restoreOriginalParents(),this.stopAllAudio(),this.stopAllAnimations(),this.despawnAll(),this.stopAllVfx(),this.firedEvents.clear(),this.clearCameraShakeContributions(),this.clearPostProcessEffects()}restart(){this.stop(),this.play()}seek(e){const t=Math.max(0,Math.min(e,this._duration));t<this._time.value&&this.resetVfxForTimeReset(t),this._time.next(t),this.evaluate(t)}update(e){if(this._state.value!==SequencePlaybackState.Playing)return;if(!this.sequenceData)return;if(this._externalTimeControl){for(const t of this.bindings.values())t.mixer&&t.mixer.update(e*this._timescale);for(const t of this.spawnedInstances.values())t.mixer&&t.mixer.update(e*this._timescale);return}const t=this._time.value+e*this._timescale;if(t>=this._duration){if(!this._loop)return this._time.next(this._duration),this.evaluate(this._duration),this.releaseCameraOverride(),this.clearCameraShakeContributions(),this.clearPostProcessEffects(),this.restoreAllPropertySnapshots(),this.restoreAllMaterialSnapshots(),this._state.next(SequencePlaybackState.Stopped),void this.onComplete.next();{this.loopCount++;const e=t%this._duration;this.resetVfxForTimeReset(e),this._time.next(e),this.firedEvents.clear(),this.onLoop.next(this.loopCount)}}else this._time.next(t);this.evaluate(this._time.value);for(const t of this.bindings.values())t.mixer&&t.mixer.update(e*this._timescale);for(const t of this.spawnedInstances.values())t.mixer&&t.mixer.update(e*this._timescale)}evaluate(e){if(this.sequenceData){this.nextCameraShakeClipKeys.clear(),this.nextPostProcessClipKeys.clear();for(const t of this.sequenceData.tracks){if(!t.muted&&("object"===t.type||"locator"===t.type||"camera"===t.type||"spawn"===t.type||"vfx"===t.type)){const e=this.bindings.get(t.id);this.updateTrackParenting(t,e)}this.evaluateTrack(t,e)}this.updateCameraControl(e),this.syncCameraShakeContributions(),this.syncPostProcessEffects()}}evaluateTrack(e,t){if(e.muted)return;const a=this.bindings.get(e.id);(0,this.trackRuntimeEvaluators[x(e.type).runtimeEvaluator])(e,a,t)}evaluateObjectTrack(e,t,a){this.evaluateSubTracks(e.subTracks,t,a)}evaluateLocatorTrack(e,t,a){this.evaluateSubTracks(e.subTracks,t,a)}getActiveTrackObjects(e){if(!this.sequenceData)return[];const t=ne(this.sequenceData.tracks).find(t=>t.id===e);return t?this.getActiveObjectsForTrack(t):[]}evaluateSubTracks(e,t,a){this._externalTimeControl&&this.beginExternalRootMotionPreview(t);for(const s of e){if(s.muted)continue;(0,this.subTrackRuntimeEvaluators[k(s.type).runtimeEvaluator])(s,t,a)}this._externalTimeControl&&this.applyExternalRootMotionPreview(t)}beginExternalRootMotionPreview(e){const t=e.externalRootMotionPreview;if(!t)return;const a=this.getPlayableObject(e);a&&a.position.sub(t.appliedOffset),t.appliedOffset.set(0,0,0),t.sampledOffset.set(0,0,0),t.root=null}sampleExternalRootMotionPreview(e,t,s,i){if(!t.motionTrack)return;let r=this.externalRootMotionInterpolants.get(t);r||(r=t.motionTrack.InterpolantFactoryMethodSmooth([]),this.externalRootMotionInterpolants.set(t,r));const n=e.externalRootMotionPreview??(e.externalRootMotionPreview={appliedOffset:new c,sampledOffset:new c,root:null}),o=Math.max(0,Math.min(i,t.duration)),l=Math.max(o,Math.min(s,t.duration));de.fromArray(r.evaluate(o)),fe.fromArray(r.evaluate(l)),n.sampledOffset.subVectors(fe,de),n.sampledOffset.y=0;const h=this.getPlayableObject(e),u=a.PropertyBinding.parseTrackName(t.motionTrack.name);n.root=h?.getObjectByName(u.nodeName)??h}applyExternalRootMotionPreview(e){const t=e.externalRootMotionPreview,a=this.getPlayableObject(e);t&&a&&t.root&&(t.root.getWorldScale(me),t.appliedOffset.copy(t.sampledOffset).multiply(me).applyQuaternion(a.quaternion),a.position.add(t.appliedOffset))}clearExternalRootMotionPreview(e){const t=e.externalRootMotionPreview,a=this.getPlayableObject(e);t&&a&&a.position.sub(t.appliedOffset),e.externalRootMotionPreview=void 0}evaluateTransformSubTrack(e,t,a){const s=e.keyframes;if(0===s.length)return;const{prev:i,next:r,prevIndex:n,nextIndex:o,t:l}=B(s,a);if(i)if(e.components.position&&q(s,n,o,l,t.position),r&&i!==r){const a=T(l,i.interpolation);e.components.rotation&&i.rotation&&r.rotation&&(ye.setFromEuler(Ce.fromArray([...i.rotation,"XYZ"])),ve.setFromEuler(ge.fromArray([...r.rotation,"XYZ"])),t.quaternion.slerpQuaternions(ye,ve,a)),e.components.scale&&i.scale&&r.scale&&t.scale.lerpVectors(he.fromArray(i.scale),ue.fromArray(r.scale),a)}else e.components.rotation&&i.rotation&&t.rotation.fromArray([...i.rotation,"XYZ"]),e.components.scale&&i.scale&&t.scale.fromArray(i.scale)}evaluateAnimationSubTrack(e,t,s){if(!t.mixer||!t.activeActions)return;const i=t.target instanceof p?t.target.object:t.target;if(i)for(const r of e.clips){const n=r.startTime+r.duration,o=s>=r.startTime&&s<n,l=`${e.id}-${r.id}`;let c=t.activeActions.get(l),h=!1;if(o){if(!c){h=!0;const e=r.animationClipAssetId;if(null==e)continue;const s=$(i),n=this.animationClipCacheKey(e,s),o=this.animationClips.get(n);if(null==o){this.ensureAnimationClip(e,s);continue}const u=this.prepareAnimationPlayback(n,o,r),d=t;let f=!1;if(t.target instanceof p){d.charAnimComponent||(d.charAnimComponent=t.target.getComponent(V)??void 0);const e=d.charAnimComponent;if(null!=e){const a=r.rootMotion?j(r)?this.getPlayableAnimationClip(n,o,r,!0):L.fromClip(u.clip,!1):u.clip;if(this._externalTimeControl)c=e.beginExternalAnimationControl(a,{timeScale:u.timeScale});else if(e.play(a,{inPlace:!r.rootMotion,loop:!1,priority:20,timeScale:u.timeScale,fadeTime:r.fadeInDuration??.2,offset:u.startOffset}),c=e.getFullBodyAction(),r.rootMotion){const e=_(t.target);e&&e.setRootMotionAction(c,{cancelWithJump:e.allowRootMotionJumpCancel,onJumpCancel:()=>this.cancel()})}t.activeActions.set(l,c),d.charAnimActionKeys||(d.charAnimActionKeys=new Set),d.charAnimActionKeys.add(l),f=!0}}f||(c=t.mixer.clipAction(u.clip),c.setLoop(a.LoopOnce,1),c.clampWhenFinished=!0,c.timeScale=u.timeScale,u.startOffset>0&&(c.time=u.startOffset),t.activeActions.set(l,c),c.play())}if(c){const e=t;if(this._externalTimeControl){e.charAnimComponent?.beginExternalControl();const a=this.getAnimationPlaybackLocalTime(r,s),i=Math.min(a,c.getClip().duration);(h||Math.abs(c.time-i)>.001)&&(c.time=i,c.paused=!1,c.play(),e.charAnimComponent?e.charAnimComponent.getMixer()?.update(0):t.mixer&&t.mixer.update(0)),r.rootMotion&&c.getClip()instanceof L&&this.sampleExternalRootMotionPreview(t,c.getClip(),i,j(r)?0:r.clipStartOffset)}else e.charAnimComponent?.endExternalControl()}}else if(c){t.activeActions.delete(l);const e=t;e.charAnimActionKeys?.has(l)?(e.charAnimActionKeys.delete(l),c.stop(),0===e.charAnimActionKeys.size&&e.charAnimComponent&&(e.charAnimComponent.stopSequenceAnimation(),e.charAnimComponent=void 0)):(c.stop(),this._externalTimeControl&&t.mixer&&t.mixer.update(0))}}}evaluateVisibilitySubTrack(e,t,a){const s=e.keyframes;if(0===s.length)return;let i=s[0];for(const e of s){if(!(e.time<=a))break;i=e}t.visible=i.visible}evaluatePropertySubTrack(e,t,a){const s=I(e.keyframes,a,{min:e.range?.[0],max:e.range?.[1],stepOnly:Q(e)});s&&this.applyResolvedPropertyValue(e,t,s)}evaluateParameterSubTrack(e,t,a){if("audioParameter"===e.type)return;const s=I(e.keyframes,a,"property"===e.type?{min:e.range?.[0],max:e.range?.[1],stepOnly:Q(e)}:"material"===e.type?{min:e.range?.[0],max:e.range?.[1],stepOnly:X(e)}:{});s&&("property"!==e.type?this.applyResolvedMaterialValue(e,t,s):this.applyResolvedPropertyValue(e,t,s))}evaluateEventSubTrack(e,t,a){if(t instanceof p&&this._state.value===SequencePlaybackState.Playing)for(const s of e.events){const i=`${e.id}-${s.id}`;if(a>=s.time&&!this.firedEvents.has(i)){if(this.firedEvents.add(i),s.editorOnly&&!this._inEditor)continue;if(!s.functionName)continue;const e=t[s.functionName];"function"==typeof e?this.invokeSequenceEvent(t,s.functionName,e,s.arguments??[]):console.warn(`Sequence event method '${s.functionName}' not found on actor`)}else s.time>a&&this.firedEvents.delete(i)}}evaluateCameraTrack(e,t){const a=this.ensureSequenceCamera(e);this.applyCameraTrackSettings(e,a),this.evaluateSubTracks(e.subTracks,this.getCameraPlayable(e,a),t),a.updateProjectionMatrix()}evaluateCameraShakeTrack(e,t){if(this.viewController)for(const a of e.clips??[]){if(!this.isCameraShakeClipActive(a,t))continue;const e=t-a.startTime,s=a.id;this.nextCameraShakeClipKeys.add(s),this.viewController.setCameraShakeContribution(this,s,a,e,a.seed??N(a.id))}}evaluatePostProcessTrack(e,t){if(this.viewController&&this.assetLoader){for(const a of e.clips??[]){if(!this.isPostProcessClipActive(a,t))continue;const s=this.getPostProcessClipKey(e,a);this.nextPostProcessClipKeys.add(s),this.ensurePostProcessClipEffect(e,a,s);const i=this.activePostProcessClips.get(s);i?.handle&&(i.handle.stage=e.stage,i.handle.priority=e.priority,i.handle.enabled=!0,this.applyPostProcessClipWeight(i.handle,a,t))}this.evaluatePostProcessMaterialSubTracks(e,t)}}evaluatePostProcessMaterialSubTracks(e,t){for(const a of e.subTracks){if(a.muted||"material"!==a.type)continue;const s=I(a.keyframes,t,{min:a.range?.[0],max:a.range?.[1],stepOnly:X(a)});s&&this.applyPostProcessMaterialValue(e.id,a,s)}}applyPostProcessMaterialValue(e,t,a){if("shaderUniform"===w(t)&&t.uniformName)for(const s of this.activePostProcessClips.values()){if(s.trackId!==e||!s.handle)continue;const i=s.handle.material,r=i.uniforms?.[t.uniformName];if(!r)continue;const n=Z(r.value,a);n.applied&&(r.value=n.value,i.uniformsNeedUpdate=!0,D(i))}}isPostProcessClipActive(e,t){return t>=e.startTime&&t<e.startTime+e.duration}getPostProcessClipKey(e,t){return`${e.id}-${t.id}`}ensurePostProcessClipEffect(e,t,a){const s=t.shaderGraphAssetId;if(!s)return void this.releasePostProcessClipEffect(a);const i=JSON.stringify(t.shaderGraphParams??{}),r=this.activePostProcessClips.get(a);if(r?.assetId===s&&r.paramsSignature===i)return;this.releasePostProcessClipEffect(a);const n={key:a,trackId:e.id,clipId:t.id,assetId:s,paramsSignature:i,version:this.clearCounter};this.activePostProcessClips.set(a,n),this.loadPostProcessClipEffect(e,t,n)}async loadPostProcessClipEffect(e,t,a){if(this.assetLoader&&this.viewController)try{const s=await this.assetLoader.getShaderGraphByAssetId(a.assetId);if(!this.isPostProcessClipEntryCurrent(a))return;if("postProcess"!==s.target)return console.warn(`Sequence post-process clip references shader graph "${a.assetId}" with target "${s.target}"`),void this.releasePostProcessClipEffect(a.key);const i=await this.assetLoader.prepareShaderGraphParameters(s,t.shaderGraphParams??{});if(!this.isPostProcessClipEntryCurrent(a))return;const r=U(s,{parameters:i});if(!this.isPostProcessClipEntryCurrent(a))return void r.dispose();a.handle=this.viewController.addPostProcessEffect(r,{stage:e.stage,priority:e.priority,enabled:!0}),this.applyPostProcessClipWeight(a.handle,t,this._time.value)}catch(e){this.isPostProcessClipEntryCurrent(a)&&this.releasePostProcessClipEffect(a.key),console.error(`Failed to create post-process effect for clip ${t.id}:`,e)}}isPostProcessClipEntryCurrent(e){return this.clearCounter===e.version&&this.activePostProcessClips.get(e.key)===e}applyPostProcessClipWeight(e,t,a){const s=e.material.uniforms?.[W];null!=s&&(s.value=this.getPostProcessClipWeight(t,a),e.material.uniformsNeedUpdate=!0)}getPostProcessClipWeight(e,t){const a=Math.max(0,t-e.startTime),s=Math.max(0,e.startTime+e.duration-t);let i=1;const r=Math.max(0,e.fadeInDuration??0);r>0&&(i=Math.min(i,a/r));const n=Math.max(0,e.fadeOutDuration??0);return n>0&&(i=Math.min(i,s/n)),Math.max(0,Math.min(1,i))}syncPostProcessEffects(){for(const e of Array.from(this.activePostProcessClips.keys()))this.nextPostProcessClipKeys.has(e)||this.releasePostProcessClipEffect(e);this.nextPostProcessClipKeys.clear()}clearPostProcessEffects(){for(const e of Array.from(this.activePostProcessClips.keys()))this.releasePostProcessClipEffect(e);this.nextPostProcessClipKeys.clear()}releasePostProcessClipEffect(e){const t=this.activePostProcessClips.get(e);if(t&&(this.activePostProcessClips.delete(e),t.handle)){const e=t.handle.material;t.handle.dispose(),e.dispose()}}getCameraPlayable(e,t){let a=this.cameraPlayables.get(e.id);return a?a.target=t:(a={target:t},this.cameraPlayables.set(e.id,a)),a}ensureSequenceCamera(e){let t=this.sequenceCameras.get(e.id);if(t)null==t.parent&&this.world?.scene.add(t);else{const s=e.cameraSettings??{fov:60,near:.1,far:1e3};t=new a.PerspectiveCamera(s.fov??60,this.getCurrentCameraAspect(),s.near??.1,s.far??1e3),t.name=e.name||"Sequence Camera",t.userData.sequenceCameraTrackId=e.id,t.layers.mask=this.viewController?.getBaseCamera().layers.mask??t.layers.mask,this.sequenceCameras.set(e.id,t),this.world?.scene.add(t)}return t}clearSequenceCameras(){this.releaseCameraOverride();for(const e of this.sequenceCameras.values())e.removeFromParent();this.sequenceCameras.clear(),this.cameraPlayables.clear()}applyCameraTrackSettings(e,t){const a=e.cameraSettings??{fov:60,near:.1,far:1e3};t.fov=a.fov??60,t.near=a.near??.1,t.far=a.far??1e3,t.aspect=this.getCurrentCameraAspect()}getCurrentCameraAspect(){const e=this.viewController?.getBaseCamera();if(e instanceof a.PerspectiveCamera&&Number.isFinite(e.aspect)&&e.aspect>0)return e.aspect;const t=this.viewController?.getSourceCamera();return t instanceof a.PerspectiveCamera&&Number.isFinite(t.aspect)&&t.aspect>0?t.aspect:1}updateCameraControl(e){if(!this._cameraControlEnabled||!this.viewController||!this.sequenceData)return void this.releaseCameraOverride();const t=this.findActiveCameraShot(e);if(t)return void this.updateActiveCameraShot(t,e);const a=this.findBlendOutCameraShot(e);a?this.updateCameraBlendOut(a,e):this.releaseCameraOverride()}findActiveCameraShot(e){if(!this.sequenceData)return null;let t=null;for(const a of ne(this.sequenceData.tracks)){if("camera"!==a.type||a.muted||!this.isCameraControlTrackEligible(a))continue;const s=a.clips??[];for(const i of s)this.isCameraClipActive(i,e)&&(t={track:a,clip:i,camera:this.ensureSequenceCamera(a),key:this.getCameraClipKey(a,i)})}return t}findBlendOutCameraShot(e){if(!this.sequenceData)return null;let t=null;for(const a of ne(this.sequenceData.tracks)){if("camera"!==a.type||a.muted||!this.isCameraControlTrackEligible(a))continue;const s=a.clips??[];for(const i of s){const s=Math.max(0,i.blendOutDuration??0);if(s<=0)continue;const r=this.getCameraClipEnd(i);e>=r&&e<r+s&&(t={track:a,clip:i,camera:this.ensureSequenceCamera(a),key:this.getCameraClipKey(a,i)})}}return t}isCameraControlTrackEligible(e){return null==this._cameraControlTrackId||e.id===this._cameraControlTrackId}updateActiveCameraShot(e,t){if(!this.viewController)return;const a=this.ensureCameraBlendCamera();this.activeCameraClipKey!==e.key&&(this.copyCameraState(this.viewController.getSourceCamera(),this.ensureCameraBlendSource()),this.activeCameraClipKey=e.key,this.cameraBlendOutClipKey=null);const s=Math.max(0,e.clip.blendInDuration??0),i=s<=0?1:this.evaluateCameraBlendAlpha((t-e.clip.startTime)/s,e.clip);i>=1?this.copyCameraState(e.camera,a):this.blendCameraState(this.ensureCameraBlendSource(),e.camera,a,i),a.updateProjectionMatrix(),this.ensureCameraOverride()}updateCameraBlendOut(e,t){if(!this.viewController)return;const a=this.ensureCameraBlendCamera();if(this.cameraBlendOutClipKey!==e.key){const t=this.activeCameraClipKey===e.key?this.viewController.getSourceCamera():e.camera;this.copyCameraState(t,this.ensureCameraBlendOutSource()),this.activeCameraClipKey=null,this.cameraBlendOutClipKey=e.key}const s=this.getCameraClipEnd(e.clip),i=Math.max(0,e.clip.blendOutDuration??0),r=i<=0?1:this.evaluateCameraBlendAlpha((t-s)/i,e.clip);this.blendCameraState(this.ensureCameraBlendOutSource(),this.viewController.getBaseCamera(),a,r),a.updateProjectionMatrix(),this.ensureCameraOverride()}ensureCameraBlendCamera(){return this.cameraBlendCamera||(this.cameraBlendCamera=new a.PerspectiveCamera(60,this.getCurrentCameraAspect(),.1,1e3),this.cameraBlendCamera.name="Sequence Camera Blend"),this.cameraBlendCamera}ensureCameraBlendSource(){return this.cameraBlendSource||(this.cameraBlendSource=new a.PerspectiveCamera),this.cameraBlendSource}ensureCameraBlendOutSource(){return this.cameraBlendOutSource||(this.cameraBlendOutSource=new a.PerspectiveCamera),this.cameraBlendOutSource}ensureCameraOverride(){this.viewController&&!this.cameraOverrideHandle&&(this.cameraOverrideHandle=this.viewController.pushCameraOverride(this.ensureCameraBlendCamera(),this))}releaseCameraOverride(){this.cameraOverrideHandle?.release(),this.cameraOverrideHandle=null,this.viewController?.releaseCameraOverridesForOwner(this),this.activeCameraClipKey=null,this.cameraBlendOutClipKey=null}isCameraClipActive(e,t){return t>=e.startTime&&t<this.getCameraClipEnd(e)}getCameraClipEnd(e){return e.startTime+Math.max(0,e.duration)}isCameraShakeClipActive(e,t){return t>=e.startTime&&t<this.getCameraShakeClipEnd(e)}getCameraShakeClipEnd(e){return e.startTime+Math.max(0,e.duration)}getCameraClipKey(e,t){return`${e.id}-${t.id}`}evaluateCameraBlendAlpha(e,t){return T(Math.max(0,Math.min(1,e)),t.blendInterpolation??"cubic")}syncCameraShakeContributions(){if(!this.viewController)return this.activeCameraShakeClipKeys.clear(),void this.nextCameraShakeClipKeys.clear();for(const e of this.activeCameraShakeClipKeys)this.nextCameraShakeClipKeys.has(e)||this.viewController.removeCameraShakeContribution(this,e);this.activeCameraShakeClipKeys.clear();for(const e of this.nextCameraShakeClipKeys)this.activeCameraShakeClipKeys.add(e);this.nextCameraShakeClipKeys.clear()}clearCameraShakeContributions(){this.activeCameraShakeClipKeys.clear(),this.nextCameraShakeClipKeys.clear(),this.viewController?.clearCameraShakeContributionsForOwner(this)}copyCameraState(e,t){e.updateWorldMatrix(!0,!1),t.position.copy(e.getWorldPosition(he)),t.quaternion.copy(e.getWorldQuaternion(ye)),t.scale.copy(e.getWorldScale(ue)),e instanceof a.PerspectiveCamera?(t.fov=e.fov,t.near=e.near,t.far=e.far,t.aspect=e.aspect):t.aspect=this.getCurrentCameraAspect(),t.layers.mask=e.layers.mask}blendCameraState(e,t,s,i){e.updateWorldMatrix(!0,!1),t.updateWorldMatrix(!0,!1),s.position.lerpVectors(e.getWorldPosition(he),t.getWorldPosition(ue),i),s.quaternion.slerpQuaternions(e.getWorldQuaternion(ye),t.getWorldQuaternion(ve),i),s.scale.lerpVectors(e.getWorldScale(he),t.getWorldScale(ue),i),e instanceof a.PerspectiveCamera&&t instanceof a.PerspectiveCamera?(s.fov=e.fov+(t.fov-e.fov)*i,s.near=e.near+(t.near-e.near)*i,s.far=e.far+(t.far-e.far)*i,s.aspect=t.aspect):t instanceof a.PerspectiveCamera?(s.fov=t.fov,s.near=t.near,s.far=t.far,s.aspect=t.aspect):s.aspect=this.getCurrentCameraAspect(),s.layers.mask=t.layers.mask}evaluateAudioTrack(e,t){if(!this.assetLoader||!e.clips||0===e.clips.length)return;const a=this._state.value===SequencePlaybackState.Playing,s=this.evaluateAudioSubTracks(e,t);e.volume;for(const i of e.clips){const r=i.startTime+i.duration,n=t>=i.startTime&&t<r,o=`${e.id}-${i.id}`;if(n){if(this.activeAudioClips.has(o)||this.activeAudioClips.add(o),a){const a=this.audioByClip.get(o);a&&a.isPlaying||this.tryStartAudioClip(e,i,o,t,s)}const r=this.audioByClip.get(o);r&&this.applyAudioParameters(r,e,i,o,t,s)}else this.activeAudioClips.has(o)&&(this.activeAudioClips.delete(o),this.lastAudioStartAttemptTime.delete(o),this.audioStartInFlight.delete(o),this.stopAudioClip(o))}}tryStartAudioClip(e,t,a,s,i){if(this.audioStartInFlight.has(a))return;const r=this.lastAudioStartAttemptTime.get(a);if(void 0!==r&&s-r<this.audioStartRetryIntervalSeconds)return;this.lastAudioStartAttemptTime.set(a,s);const n=this.playAudioClip(e,t,a,s,i).catch(()=>{}).finally(()=>{this.audioStartInFlight.get(a)===n&&this.audioStartInFlight.delete(a)});this.audioStartInFlight.set(a,n)}applyAudioParameters(e,t,s,i,r,n){const o=n.volume??1,l=Math.random(),c=s.volumeRandomization?(2*l-1)*s.volumeRandomization:0;let h=1;const u=r-s.startTime;u<s.fadeInDuration&&s.fadeInDuration>0?h=u/s.fadeInDuration:u>s.duration-s.fadeOutDuration&&s.fadeOutDuration>0&&(h=(s.duration-u)/s.fadeOutDuration);const p=Math.max(0,(t.volume??1)*o*(s.volume+c)*h);e.setVolume(p);let d=n.detune??0;if(s.pitchRandomization){d+=(2*Math.random()-1)*s.pitchRandomization}if(e.setDetune(d),e.hasPlaybackControl&&e.setPlaybackRate(s.playbackRate*this.timescale),this.audioListener&&this.audioListener.context){const s=this.audioListener.context,r=[],o=n.lowpass,l=n.highpass;let c=this.audioFilters.get(i);if(void 0!==o||void 0!==l)c||(c=s.createBiquadFilter(),this.audioFilters.set(i,c)),void 0!==o?(c.type="lowpass",c.frequency.value=o):void 0!==l&&(c.type="highpass",c.frequency.value=l),r.push(c);else if(c){try{c.disconnect()}catch{}this.audioFilters.delete(i)}const h=n.pan;if(!t.spatial&&e instanceof a.Audio&&void 0!==h&&"function"==typeof s.createStereoPanner){let e=this.audioPannerNodes.get(i);e||(e=s.createStereoPanner(),this.audioPannerNodes.set(i,e)),e.pan.value=h,r.push(e)}else{const e=this.audioPannerNodes.get(i);if(e){try{e.disconnect()}catch{}this.audioPannerNodes.delete(i)}}e.setFilters(r)}t.spatial&&e instanceof a.PositionalAudio?this.updatePositionalAudioTransform(e,t,s,n.spatialBlend):void 0!==n.pan&&this.audioListener}updatePositionalAudioTransform(e,t,s,i){let r=null,n=null;const o=s.attachedToTrackId||t.parent?.trackId,l=s.attachmentSocketName||t.parent?.socketName;if(o){const e=this.sequenceData?.tracks.find(e=>e.id===o);if(e){const t=this.getActiveObjectsForTrack(e);if(t.length>0){const e=t[0];if(r=he,n=ye,e.getWorldPosition(r),e.getWorldQuaternion(n),l){const t=this.findSocket(e,l);t&&(t.getWorldPosition(r),t.getWorldQuaternion(n))}}}}if(r&&n){const t="number"==typeof i?a.MathUtils.clamp(i,0,1):1;if(t<1&&this.audioListener){const e=pe;this.audioListener.getWorldPosition(e),r=r.clone().lerp(e,1-t)}e.position.copy(r),e.quaternion.copy(n),e.updateMatrixWorld()}}async playAudioClip(e,t,s,i,r){if(!this.assetLoader||!t.audioAssetId||null==this.audioListener)return;if("suspended"===this.audioListener.context.state)try{await this.audioListener.context.resume()}catch(e){return void console.warn("Failed to resume audio context:",e)}this.stopAudioClip(s);const n=this.clearCounter;try{let i=this.audioBuffers.get(t.audioAssetId);if(!i){let e=this.loadingAudioBuffers.get(t.audioAssetId);e||(e=this.assetLoader.getAudioByAssetId(t.audioAssetId),this.loadingAudioBuffers.set(t.audioAssetId,e));try{i=await e,this.audioBuffers.set(t.audioAssetId,i)}finally{this.loadingAudioBuffers.delete(t.audioAssetId)}}if(n!==this.clearCounter)return;const o=this._time.value,l=t.startTime+t.duration;if(!(o>=t.startTime&&o<l))return;const c=Math.max(0,o-t.startTime),h=t.clipStartOffset+c*t.playbackRate;if(h>=i.duration||c>=t.duration)return;let u=this.audioByClip.get(s);const p=!0===e.spatial,d=u&&!0===u.isPositionalAudio;if(u&&p!==d&&(u.isPlaying&&u.stop(),u.disconnect(),this.audioByClip.delete(s),u=void 0),!u){if(p){const e=new a.PositionalAudio(this.audioListener);e.setRefDistance(10),e.setRolloffFactor(1),u=e}else u=new a.Audio(this.audioListener);this.world&&this.world.scene.add(u),this.audioByClip.set(s,u)}Math.min((t.duration-c)/t.playbackRate,(i.duration-h)/t.playbackRate);u.setLoopStart(t.clipStartOffset),u.setLoopEnd(Math.min(t.clipStartOffset+t.duration,i.duration)),u.setLoop(!0),u.setBuffer(i),this.applyAudioParameters(u,e,t,s,o,r),u.isPlaying||u.play()}catch(e){console.error(`Failed to play audio clip ${t.id}:`,e)}}stopAudioClip(e){const t=this.audioByClip.get(e);if(t){try{t.isPlaying&&t.stop()}catch(e){}t.parent&&t.parent.remove(t),this.audioByClip.delete(e)}const a=this.audioGainNodes.get(e);a&&(a.disconnect(),this.audioGainNodes.delete(e));const s=this.audioFilters.get(e);if(s){try{s.disconnect()}catch{}this.audioFilters.delete(e)}const i=this.audioPannerNodes.get(e);if(i){try{i.disconnect()}catch{}this.audioPannerNodes.delete(e)}}stopAllAudio(){for(const e of this.audioByClip.keys())this.stopAudioClip(e);this.activeAudioClips.clear(),this.audioStartInFlight.clear(),this.lastAudioStartAttemptTime.clear()}evaluateVfxTrack(e,t){if(!this.vfxService||!this.world||!e.clips||0===e.clips.length)return;if(this.shouldPreviewVfxAtSeekTime())return void this.previewVfxTrackAtSeekTime(e,t);const a=new Set,s=new Map;for(const i of e.clips){const r=this.getVfxClipKey(e,i);s.set(r,i),this.isVfxClipActiveAtTime(i,t)&&a.add(r)}const i=[];for(const t of this.activeVfxClips)t.startsWith(`${e.id}-`)&&(a.has(t)||i.push(t));for(const e of i)this.activeVfxClips.delete(e);for(const[i,r]of s.entries()){const s=this.vfxActors.get(i);a.has(i)&&!this.activeVfxClips.has(i)?(this.activeVfxClips.add(i),this.ensureVfxActor(e,r,i)):a.has(i)&&s?(this.updateVfxTransform(e,s,t),this._state.value===SequencePlaybackState.Playing&&s.play()):s&&this.applyInactiveVfxClipBehavior(r,s,t)}}getVfxClipKey(e,t){return`${e.id}-${t.id}-${t.vfxAssetId}`}isVfxClipActiveAtTime(e,t){const a=e.startTime+e.duration;return t>=e.startTime&&t<a}shouldPreviewVfxAtSeekTime(){return this._externalTimeControl&&this._inEditor&&this._state.value!==SequencePlaybackState.Playing}previewVfxTrackAtSeekTime(e,t){const a=new Set;for(const s of e.clips){const i=this.getVfxClipKey(e,s),r=this.vfxActors.get(i);this.isVfxClipActiveAtTime(s,t)&&a.add(i),t<s.startTime?r?.clearPreview():r?this.previewVfxActorAtSeekTime(e,s,r,t):this.ensureVfxActor(e,s,i)}for(const t of[...this.activeVfxClips])t.startsWith(`${e.id}-`)&&!a.has(t)&&this.activeVfxClips.delete(t);for(const e of a)this.activeVfxClips.add(e)}previewVfxActorAtSeekTime(e,t,a,s){const i=t.startTime+t.duration;this.updateVfxTransform(e,a,Math.min(s,i)),a.previewAt(s-t.startTime,t.duration,t.endBehavior,t.expireWithinSeconds)}resetVfxForTimeReset(e){const t=new Set;if(this.sequenceData)for(const a of ne(this.sequenceData.tracks))if("vfx"===a.type)for(const s of a.clips??[])this.isVfxClipActiveAtTime(s,e)&&t.add(this.getVfxClipKey(a,s));this.activeVfxClips.clear();for(const[e,a]of this.vfxActors.entries())t.has(e)||(a.restart(),a.stop(),a.pause())}applyInactiveVfxClipBehavior(e,t,a){const s=e.endBehavior??"finish";if("finish"===s)return void t.stop();if("kill"===s)return void t.applyClipEndBehavior(s);const i=e.startTime+e.duration,r=Math.max(a-i,0),n=Math.max(0,e.expireWithinSeconds??.25),o=Math.max(0,n-r);t.applyClipEndBehavior(s,o)}async ensureVfxActor(e,t,a){if(!this.vfxService||!t.vfxAssetId)return;if(this.vfxActors.has(a)){const e=this.vfxActors.get(a);return e.restart(),void e.play()}const s=this.clearCounter;try{const i=await this.vfxService.createFromAssetId(t.vfxAssetId,this.world.scene);if(s!==this.clearCounter)return void(this.world&&this.world.removeActor(i));const{position:r,rotation:n,scale:o}=this.getVfxTransform(e,t.startTime);i.object.position.copy(r),i.object.rotation.copy(n),i.object.scale.copy(o),this.vfxActors.set(a,i),this.shouldPreviewVfxAtSeekTime()?this.previewVfxActorAtSeekTime(e,t,i,this._time.value):this._state.value===SequencePlaybackState.Playing&&i.play()}catch(e){console.error(`Failed to create VFX actor for clip ${t.id}:`,e)}}getVfxTransform(e,t){const a=new c,s=new r,i=new c(1,1,1),n=e.subTracks.find(e=>"transform"===e.type);if(n&&n.keyframes.length>0){const{prev:e,next:r,prevIndex:l,nextIndex:c,t:h}=B(n.keyframes,t);if(n.components.position&&q(n.keyframes,l,c,h,a),e&&(e.rotation&&s.fromArray([...e.rotation,"XYZ"]),e.scale&&i.fromArray(e.scale)),r&&e!==r&&e.time!==r.time){const t=T(h,e.interpolation);if(e.rotation&&r.rotation){ye.setFromEuler(Ce.fromArray([...e.rotation,"XYZ"])),ve.setFromEuler(ge.fromArray([...r.rotation,"XYZ"]));const a=new o;a.slerpQuaternions(ye,ve,t),s.setFromQuaternion(a)}e.scale&&r.scale&&i.lerpVectors(he.fromArray(e.scale),ue.fromArray(r.scale),t)}}else a.fromArray(e.position),s.fromArray([...e.rotation,"XYZ"]),i.fromArray(e.scale);return{position:a,rotation:s,scale:i}}updateVfxTransform(e,t,a){const{position:s,rotation:i,scale:r}=this.getVfxTransform(e,a);t.object.position.copy(s),t.object.rotation.copy(i),t.object.scale.copy(r)}resolveActorType(e){const t=this.actorFactory.classes[e];if(null!=t)return t;const a=d[e];return a||(console.warn(`Could not resolve actor type: ${e}`),null)}async spawnActorForClip(e,t,a,s){if(!this.world||!e.actorType)return null;const i=this.resolveActorType(e.actorType);if(!i)return null;try{return await this.world.spawnActor(i,a,s)}catch(t){return console.error(`Failed to spawn actor ${e.actorType}:`,t),null}}async spawnPrefabForClip(e,t,a,s){if(!this.world||!this.assetLoader||!e.prefabId)return null;try{const t=await this.assetLoader.getPrefabById(e.prefabId);if(!t)return null;return await this.world.spawnPrefab(t,a,s)}catch(t){return console.error(`Failed to spawn prefab ${e.prefabId}:`,t),null}}async spawnMeshForClip(e,t,a,s){if(!this.world||!this.assetLoader||!e.meshId)return null;try{const t=await this.assetLoader.getAsset(e.meshId),i=await this.assetLoader.getModelByAssetId(e.meshId),r=R.clone(i.scene);if(r.position.copy(a),r.rotation.copy(s),t){await this.assetLoader.applyMaterials(t,r);const e=t.mesh?.rescale;null!=e&&1!==e&&r.scale.multiplyScalar(e)}return this.world.scene.add(r),r}catch(t){return console.error(`Failed to spawn mesh ${e.meshId}:`,t),null}}despawnInstance(e){if(this.restorePropertySnapshotsForInstance(e),this.restoreMaterialSnapshotsForInstance(e),this.world)switch(e?.type){case"actor":this.world.removeActor(e.instance);break;case"prefab":this.world.removePrefab(e.instance);break;case"mesh":this.world.scene.remove(e.instance)}}despawnAll(){for(const e of this.spawnedInstances.values())this.despawnInstance(e);this.spawnedInstances.clear(),this.activeClips.clear(),this.pendingSpawns.clear()}getInitialTransform(e,t,a){const s=new c,i=new r,n=e.subTracks.find(e=>"transform"===e.type);if(n&&n.keyframes.length>0){const{prev:e,prevIndex:t,nextIndex:r,t:o}=B(n.keyframes,a);n.components.position&&q(n.keyframes,t,r,o,s),e&&e.rotation&&i.fromArray([...e.rotation,"XYZ"])}else t.initialPosition&&s.fromArray(t.initialPosition),t.initialRotation&&i.fromArray([...t.initialRotation,"XYZ"]);return{position:s,rotation:i}}evaluateSpawnTrack(e,t,a){if(!e.clips||0===e.clips.length)return;const s=t||this.bindings.get(e.id);if(s&&s.target)for(const t of e.clips){const i=t.startTime+t.duration,r=a>=t.startTime&&a<i,n=`${e.id}-${t.id}`;if(r){this.activeClips.has(n)||(this.activeClips.add(n),this.spawnedInstances.set(n,{type:"proxy",target:s.target}));(s.target instanceof p?s.target.object:s.target)&&this.evaluateSubTracks(e.subTracks,s,a)}else this.activeClips.has(n)&&(this.clearExternalRootMotionPreview(s),this.restorePropertySnapshotsForTarget(s.target),this.restoreMaterialSnapshotsForTarget(s.target),this.activeClips.delete(n),this.spawnedInstances.delete(n))}else for(const t of e.clips){const s=t.startTime+t.duration,i=a>=t.startTime&&a<s,r=`${e.id}-${t.id}`,n=this.spawnedInstances.has(r),o=this.pendingSpawns.has(r);if(!i||n||o){if(i&&n){const t=this.spawnedInstances.get(r);t&&"proxy"!==t.type&&this.evaluateSubTracks(e.subTracks,t,a)}else if(!i&&n){const e=this.spawnedInstances.get(r);e&&(this.despawnInstance(e),this.spawnedInstances.delete(r),this.activeClips.delete(r))}}else{const{position:a,rotation:s}=this.getInitialTransform(e,t,t.startTime);this.pendingSpawns.add(r),this.spawnForClip(e,t,a,s,r)}}}getInstanceObject(e){switch(e.type){case"actor":return e.instance.object;case"prefab":return e.instance.mainActor?.object||e.instance.object;case"mesh":return e.instance;case"proxy":return e.target instanceof p?e.target.object:e.target;default:return null}}async spawnForClip(e,t,a,i,r){const n=this.clearCounter;let o=null;try{switch(e.spawnType){case"actor":const s=await this.spawnActorForClip(e,t,a,i);s&&(o={type:"actor",instance:s});break;case"prefab":const r=await this.spawnPrefabForClip(e,t,a,i);r&&(o={type:"prefab",instance:r});break;case"mesh":const n=await this.spawnMeshForClip(e,t,a,i);n&&(o={type:"mesh",instance:n})}if(n!==this.clearCounter)return void(o&&this.despawnInstance(o));const l=this._time.value,c=l>=t.startTime&&l<t.startTime+t.duration;if(o&&c){const t=this.getInstanceObject(o);"proxy"===o.type||("actor"===o.type?o.target=o.instance:"prefab"===o.type?o.target=o.instance.mainActor||o.instance.object:o.target=t);e.subTracks.some(e=>"animation"===e.type)&&t&&(o.mixer=new s(t),o.activeActions=new Map),this.spawnedInstances.set(r,o),this.activeClips.add(r)}else o&&this.despawnInstance(o)}finally{this.pendingSpawns.delete(r)}}getPlayableObject(e){return e.target instanceof p?e.target.object:e.target??null}applyResolvedPropertyValue(e,t,a){if(!t||!e.propertyPath)return;const s=this.getPropertyResolution(t,e);if(!s)return;const i=this.getPropertySnapshotKey(e);this.capturePropertySnapshot(t,i,s);const n=function(e,t){switch(t.type){case y.Number:return"number"==typeof t.value?{applied:!0,value:t.value}:{applied:!1};case y.Boolean:return"boolean"==typeof t.value?{applied:!0,value:t.value}:{applied:!1};case y.String:return"string"==typeof t.value?{applied:!0,value:t.value}:{applied:!1};case y.Vector2:return H(e,t.value);case y.Vector3:return J(e,t.value);case y.Vector4:return ee(e,t.value);case y.Euler:return function(e,t){const a=ae(t,3);if(!a)return{applied:!1};const s=Array.isArray(t)&&"string"==typeof t[3]?t[3]:"XYZ";if(e instanceof r)return e.set(a[0],a[1],a[2],s),{applied:!0,value:e};return{applied:!0,value:new r(a[0],a[1],a[2],s)}}(e,t.value);case y.Color:return te(e,t.value);default:return{applied:!1}}}(s.owner[s.key],a);n.applied&&(s.owner[s.key]=n.value)}getPropertyResolution(e,t){const a=e,s=this.getPropertySnapshotKey(t);let i=this.propertyResolutionCache.get(a);if(i||(i=new Map,this.propertyResolutionCache.set(a,i)),i.has(s))return i.get(s)??null;const r=this.getPropertyPathSegments(t.propertyPath);if(0===r.length)return i.set(s,null),null;let n=e;for(let e=0;e<r.length-1;e++){if(!Y(n))return i.set(s,null),null;n=n[r[e]]}if(!Y(n))return i.set(s,null),null;const o={owner:n,key:r[r.length-1]};return i.set(s,o),o}getPropertyPathSegments(e){const t=this.propertyPathSegments.get(e);if(t)return t;const a=e.split(".").map(e=>e.trim()).filter(Boolean);return this.propertyPathSegments.set(e,a),a}getPropertySnapshotKey(e){return`${e.id}:${e.propertyPath}`}capturePropertySnapshot(e,t,a){const s=e;let i=this.propertySnapshots.get(s);if(i||(i=new Map,this.propertySnapshots.set(s,i)),i.has(t))return;const r=a.owner[a.key];i.set(t,{resolution:a,hadOwnProperty:Object.prototype.hasOwnProperty.call(a.owner,a.key),value:r,valueSnapshot:ie(r)})}restorePropertySnapshotsForInstance(e){switch(e.type){case"actor":case"mesh":this.restorePropertySnapshotsForTarget(e.instance);break;case"prefab":this.restorePropertySnapshotsForTarget(e.target??null),this.restorePropertySnapshotsForTarget(e.instance.mainActor??null),this.restorePropertySnapshotsForTarget(e.instance.object);break;case"proxy":this.restorePropertySnapshotsForTarget(e.target)}}restorePropertySnapshotsForTarget(e){if(!e)return;const t=e,a=this.propertySnapshots.get(t);if(a){for(const e of a.values())re(e);this.propertySnapshots.delete(t),this.propertyResolutionCache.delete(t)}}restoreAllPropertySnapshots(){for(const e of Array.from(this.propertySnapshots.keys()))this.restorePropertySnapshotsForTarget(e)}restoreMaterialSnapshotsForInstance(e){switch(e.type){case"actor":case"mesh":this.restoreMaterialSnapshotsForTarget(e.instance);break;case"prefab":this.restoreMaterialSnapshotsForTarget(e.target??null),this.restoreMaterialSnapshotsForTarget(e.instance.mainActor??null),this.restoreMaterialSnapshotsForTarget(e.instance.object);break;case"proxy":this.restoreMaterialSnapshotsForTarget(e.target)}}restoreMaterialSnapshotsForTarget(e){if(!e)return;const t=e;this.materialResolutionCache.delete(t);const a=this.materialSnapshots.get(t);if(a){for(const e of a.values())null==e.materialIndex?e.owner.material=e.originalMaterial:Array.isArray(e.owner.material)&&(e.owner.material[e.materialIndex]=e.originalMaterial),e.controlledMaterial!==e.originalMaterial&&e.controlledMaterial.dispose();this.materialSnapshots.delete(t)}}restoreAllMaterialSnapshots(){for(const e of Array.from(this.materialSnapshots.keys()))this.restoreMaterialSnapshotsForTarget(e)}applyResolvedMaterialValue(e,t,a){if(!t)return;if("asset"===S(e)&&!e.materialAssetId)return;if("outlineVisibility"===w(e))return void this.applyResolvedMaterialOutlineVisibility(e,t,a);if(!e.uniformName)return;const s=this.getMaterialSlotResolutions(t,e);for(const i of s){const s=this.ensureSequenceControlledMaterial(t,i),r=s.uniforms?.[e.uniformName];if(!r)continue;const n=Z(r.value,a);n.applied&&(r.value=n.value,s.uniformsNeedUpdate=!0,D(s))}}applyResolvedMaterialOutlineVisibility(e,t,a){if(a.type!==y.Boolean||"boolean"!=typeof a.value)return;const s=this.getMaterialSlotResolutions(t,e);for(const e of s){const s=this.ensureSequenceControlledMaterial(t,e),i=s.userData?.outlineParameters;null!=i&&(i.visible=a.value)}}getMaterialSlotResolutions(e,t){const a=e,s=S(t),i=w(t),r=`${t.id}:${i}:${s}:${t.materialAssetId??""}:${t.uniformName}`;let n=this.materialResolutionCache.get(a);n||(n=new Map,this.materialResolutionCache.set(a,n));const o=n.get(r);if(o)return o;const l=e instanceof p?e.object:e,c=[];return l.traverse(e=>{const a=e.material;if(Array.isArray(a))for(let s=0;s<a.length;s++){const i=a[s];z(i,t)&&c.push({owner:e,materialIndex:s,material:i,key:`${e.uuid}:${s}`})}else z(a,t)&&c.push({owner:e,materialIndex:null,material:a,key:`${e.uuid}:material`})}),n.set(r,c),c}ensureSequenceControlledMaterial(e,t){const a=e;let s=this.materialSnapshots.get(a);s||(s=new Map,this.materialSnapshots.set(a,s));const i=s.get(t.key);if(i)return i.controlledMaterial;const r=t.material.clone();return r.userData={...t.material.userData??{}},null!=t.material.userData?.outlineParameters&&(r.userData.outlineParameters={...t.material.userData.outlineParameters}),null==t.materialIndex?t.owner.material=r:Array.isArray(t.owner.material)&&(t.owner.material[t.materialIndex]=r),s.set(t.key,{owner:t.owner,materialIndex:t.materialIndex,originalMaterial:t.material,controlledMaterial:r}),r}animationClipCacheKey(e,t){return`${e}|${t??""}`}async ensureAnimationClip(e,t){if(!this.assetLoader)return null;const a=this.animationClipCacheKey(e,t),s=this.animationClips.get(a);if(s)return s;const i=this.loadingAnimationClips.get(a);if(i)return i;const r=(async()=>{try{const s=await this.assetLoader.getAnimationClipForTargetByAssetId(e,t);return s&&this.animationClips.set(a,s),s}catch(a){return console.error(`Failed to load animation clip for asset ${e}`+(null==t?"":` and target rig ${t}`)+":",a),null}finally{this.loadingAnimationClips.get(a)===r&&this.loadingAnimationClips.delete(a)}})();return this.loadingAnimationClips.set(a,r),r}prepareAnimationPlayback(e,t,a){if(!j(a)){let e=t;return a.clipEndOffset>0&&(e=e.clone(),G(e,K(t)),e.duration=Math.max(0,e.duration-a.clipEndOffset)),a.rootMotion&&(e=O(e,a)),{clip:e,timeScale:a.playbackRate*this._timescale,startOffset:a.clipStartOffset}}return{clip:this.getPlayableAnimationClip(e,t,a,!1),timeScale:1*this._timescale,startOffset:0}}getPlayableAnimationClip(e,t,a,s){if(!j(a)){const e=a.rootMotion?O(t,a):t;return s?L.fromClip(e,!1):e}const i=`${a.id}:${s?"root":"base"}`,r=`${E(a)}|${s?"root":"base"}`,n=this.retimedAnimationClips.get(i);if(n&&n.assetId===e&&n.signature===r)return n.clip;const o=F(t,a),l=a.rootMotion?O(o,a):o,c=s?L.fromClip(l,!1):l;return this.retimedAnimationClips.set(i,{assetId:e,signature:r,clip:c}),c}getAnimationPlaybackLocalTime(e,t){const a=Math.max(0,t-e.startTime);return j(e)?a:a*e.playbackRate+e.clipStartOffset}clearRetimedAnimationClipCache(e){if(null!=e)for(const[t,a]of this.retimedAnimationClips.entries())a.assetId===e&&this.retimedAnimationClips.delete(t);else this.retimedAnimationClips.clear()}captureOriginalTransforms(){for(const e of this.bindings.values()){const t=e.target instanceof p?e.target.object:e.target;t&&(e.originalTransform={position:t.position.clone(),rotation:t.rotation.clone(),scale:t.scale.clone()})}}restoreOriginalTransforms(){for(const e of this.bindings.values())if(e.originalTransform){const t=e.target instanceof p?e.target.object:e.target;t&&(t.position.copy(e.originalTransform.position),t.rotation.copy(e.originalTransform.rotation),t.scale.copy(e.originalTransform.scale))}}stopAllAnimations(){for(const e of this.bindings.values()){for(const t of e.activeActions.values())t.stop();e.activeActions.clear(),e.mixer&&e.mixer.stopAllAction(),e.charAnimComponent&&(e.charAnimComponent.stopSequenceAnimation(),e.charAnimComponent=void 0),e.charAnimActionKeys?.clear()}}stopAllVfx(){for(const e of this.vfxActors.values())e.paused||e.stop();this.activeVfxClips.clear()}dispose(){if(this.stop(),this.clearLocatorBindings(),this.clearSequenceCameras(),this.bindings.clear(),this.roleBindings.clear(),this.sequenceData=null,this.world)for(const e of this.vfxActors.values())this.world.removeActor(e);this.vfxActors.clear(),this.stopAllAudio(),this.audioBuffers.clear(),this.loadingAudioBuffers.clear(),this.animationClips.clear(),this.loadingAnimationClips.clear(),this.clearRetimedAnimationClipCache(),this.audioByClip.clear()}updateTrackParenting(e,t){const a=this.getActiveObjectsForTrack(e);if(0===a.length)return;let s=null;const i=e.parent?.trackId;if(i){const t=this.sequenceData?ne(this.sequenceData.tracks).find(e=>e.id===i):void 0;if(t){const a=this.getActiveObjectsForTrack(t);if(a.length>0&&(s=a[0],e.parent?.socketName)){const t=this.findSocket(s,e.parent.socketName);t&&(s=t)}}}if(!s&&"camera"===e.type&&e.parentRole&&this.roleBindings.has(e.parentRole)){const t=this.roleBindings.get(e.parentRole);if(s=t instanceof p?t.object:t,e.parentRoleSocketName){const t=this.findSocket(s,e.parentRoleSocketName);t&&(s=t)}}for(const i of a)s?i.parent!==s&&(s.add(i),!t||"object"!==e.type&&"locator"!==e.type||(t.currentParent=s)):t?.currentParent&&t.currentParent===i.parent?this.restoreObjectParent(t,i):i.parent&&i.parent!==this.world?.scene&&"object"!==e.type&&"locator"!==e.type&&this.world?.scene.add(i)}findSocket(e,t){if(e.name===t)return e;if(e instanceof a.SkinnedMesh){const a=e.skeleton.bones.find(e=>e.name===t);if(a)return a}return e.getObjectByName(t)||null}getActiveObjectsForTrack(e){if("object"===e.type){const t=this.bindings.get(e.id);if(t&&t.target)return[t.target instanceof p?t.target.object:t.target]}else if("locator"===e.type){const t=this.bindings.get(e.id);if(t&&t.target instanceof n)return[t.target]}else{if("camera"===e.type)return[this.ensureSequenceCamera(e)];if("spawn"===e.type){const t=[];for(const[a,s]of this.spawnedInstances)if(a.startsWith(e.id+"-")&&this.activeClips.has(a)){const e=this.getInstanceObject(s);e&&t.push(e)}return t}if("vfx"===e.type){const t=[];for(const a of this.activeVfxClips)if(a.startsWith(e.id+"-")){const e=this.vfxActors.get(a);e&&t.push(e.object)}return t}}return[]}restoreObjectParent(e,t){e.originalParent?e.originalParent.add(t):this.world&&this.world.scene.add(t),e.currentParent=void 0}restoreOriginalParents(){for(const e of this.bindings.values())if(e.currentParent){const t=e.target instanceof p?e.target.object:e.target;t&&this.restoreObjectParent(e,t)}}evaluateAudioSubTracks(e,t){const a={};for(const s of e.subTracks)if("audioParameter"===s.type){const e=s,i=A(e.parameter),r=M(e.keyframes,t,{min:i.min,max:i.max});void 0!==r&&(a[e.parameter]=r)}return a}stringToRandom(e){let t=0;for(let a=0;a<e.length;a++){t=(t<<5)-t+e.charCodeAt(a),t&=t}const a=1e4*Math.sin(t);return a-Math.floor(a)}async refreshAsset(e){let t=!1;this.assetLoader?.clearCacheById(e),this.animationClips.delete(e),this.loadingAnimationClips.delete(e),this.clearRetimedAnimationClipCache(e),this.vfxService?.clearPool(e),t=this.refreshVfxActorsForAssetIds(new Set([e]))||t;for(const[a,s]of this.activePostProcessClips.entries())s.assetId===e&&(this.releasePostProcessClipEffect(a),t=!0);t=this.refreshSpawnedInstancesForClipKeys(this.getSpawnClipKeysForAsset(e))||t;const a=await this.getAssetOrNull(e);return"shaderGraph"===a?.type&&(t=await this.refreshShaderGraphDependentAssets(e)||t),t}refreshVfxActorsForAssetIds(e){let t=!1;for(const[a,s]of this.vfxActors.entries())this.vfxClipKeyUsesAnyAsset(a,e)&&(this.world&&this.world.removeActor(s),this.vfxActors.delete(a),this.activeVfxClips.delete(a),t=!0);return t}vfxClipKeyUsesAnyAsset(e,t){for(const a of t)if(e.endsWith(`-${a}`))return!0;return!1}refreshSpawnedInstancesForClipKeys(e){let t=!1;for(const[a,s]of this.spawnedInstances.entries())e.has(a)&&(this.despawnInstance(s),this.spawnedInstances.delete(a),this.activeClips.delete(a),t=!0);return t}getSpawnClipKeysForAsset(e){const t=new Set;if(!this.sequenceData)return t;for(const a of ne(this.sequenceData.tracks))if("spawn"===a.type&&(a.prefabId===e||a.meshId===e))for(const e of a.clips)t.add(`${a.id}-${e.id}`);return t}async refreshShaderGraphDependentAssets(e){const t=await this.findSequenceVfxAssetIdsUsingShaderGraph(e);for(const e of t)this.vfxService?.clearPool(e);const a=this.refreshVfxActorsForAssetIds(t),s=this.refreshSpawnedInstancesForClipKeys(await this.findSpawnClipKeysUsingShaderGraph(e));return a||s}async findSequenceVfxAssetIdsUsingShaderGraph(e){const t=new Set;if(!this.sequenceData)return t;const a=new Map;for(const s of ne(this.sequenceData.tracks))if("vfx"===s.type)for(const i of s.clips)null==i.vfxAssetId||t.has(i.vfxAssetId)||await this.assetUsesShaderGraph(i.vfxAssetId,e,a)&&t.add(i.vfxAssetId);return t}async findSpawnClipKeysUsingShaderGraph(e){const t=new Set;if(!this.sequenceData)return t;const a=new Map;for(const s of ne(this.sequenceData.tracks))if("spawn"===s.type&&await this.spawnTrackUsesShaderGraph(s,e,a))for(const e of s.clips)t.add(`${s.id}-${e.id}`);return t}async spawnTrackUsesShaderGraph(e,t,a){if(null!=e.meshId&&await this.assetUsesShaderGraph(e.meshId,t,a))return!0;if(null!=e.prefabId&&await this.assetUsesShaderGraph(e.prefabId,t,a))return!0;for(const s of e.subTracks??[])if("material"===s.type&&null!=s.materialAssetId&&await this.assetUsesShaderGraph(s.materialAssetId,t,a))return!0;return!1}assetUsesShaderGraph(e,t,a,s=new Set){if(e===t)return Promise.resolve(!0);if(s.has(e))return Promise.resolve(!1);if(a.has(e))return a.get(e);const i=this.assetUsesShaderGraphUncached(e,t,a,s);return a.set(e,i),i}async assetUsesShaderGraphUncached(e,t,a,s){if(s.has(e))return!1;const i=await this.getAssetOrNull(e);if(null==i)return!1;const r=new Set(s);return r.add(e),!!this.materialAssetUsesShaderGraph(i,t)||("mesh"===i.type?this.materialAssignmentsUseShaderGraph(i.materialAssignments,t,a,r):"prefab"===i.type?this.sceneObjectsUseShaderGraph(i.prefab?.objects,t,a,r):"vfx"===i.type&&this.vfxAssetUsesShaderGraph(i,t,a,r))}materialAssetUsesShaderGraph(e,t){return"shaderGraph"===e.type?e.id===t:"asset"===e.material?.shaderGraph?.source&&e.material.shaderGraph.assetId===t}async materialAssignmentsUseShaderGraph(e,t,a,s){for(const i of e??[])if(null!=i.materialId&&"null"!==i.materialId&&await this.assetUsesShaderGraph(i.materialId,t,a,s))return!0;return!1}async sceneObjectsUseShaderGraph(e,t,a,s){for(const i of e??[]){if(await this.materialAssignmentsUseShaderGraph(i.materialAssignments,t,a,s))return!0;if(null!=i.assetId&&("asset_mesh"===i.type||"prefab"===i.type||"vfx"===i.type)&&await this.assetUsesShaderGraph(i.assetId,t,a,s))return!0;if(await this.sceneObjectsUseShaderGraph(i.children,t,a,s))return!0}return!1}async vfxAssetUsesShaderGraph(e,t,a,s){for(const i of e.vfx?.emitters??[])if(await this.emitterUsesShaderGraph(i,t,a,s))return!0;return!1}async emitterUsesShaderGraph(e,t,a,s){if(await this.emitterOutputUsesShaderGraph(e.output,t,a,s))return!0;for(const i of e.children??[])if(await this.emitterUsesShaderGraph(i,t,a,s))return!0;return!1}async emitterOutputUsesShaderGraph(e,t,a,s){const i=e.materialSource??("asset"===e.shaderGraph?.source?"shaderGraph":void 0);return"shaderGraph"===i&&"asset"===e.shaderGraph?.source&&e.shaderGraph.assetId===t||!("material"!==i||!("material"in e)||null==e.material||!await this.assetUsesShaderGraph(e.material,t,a,s))}async getAssetOrNull(e){if(!this.assetLoader)return null;try{return await this.assetLoader.getAsset(e)??null}catch{return null}}async invokeSequenceEvent(e,t,a,s){let i=!1;for(let e=0;e<s.length;e++)if(v(s[e])){i=!0;break}if(i)try{const t=new Array(s.length);for(let e=0;e<s.length;e++)t[e]=C(s[e],this.sequenceEventAsyncResolvers);const i=await Promise.all(t);await a.call(e,...i)}catch(e){console.error(`Failed to call sequence event ${t}:`,e)}else try{const t=new Array(s.length);for(let e=0;e<s.length;e++)t[e]=g(s[e],this.sequenceEventSyncResolvers);a.call(e,...t)}catch(e){console.error(`Failed to call sequence event ${t}:`,e)}}resolveSequenceEventActorReference(e){if(!this.world||null==e)return null;const t=e,a="object"==typeof t&&null!=t?.id?t.id:"string"==typeof t?t:null;if(null==a)return null;for(const e of this.world.actors){const t=e.object.userData.src??e.object.userData._src;if(t?.id===a)return e}return null}resolveSequenceEventSequence(e){return b(e)?new P(e):this.assetLoader&&"string"==typeof e?this.assetLoader.getSequenceById(e):null}async resolveSequenceEventAnimationClip(e){const t="string"==typeof e?e:"object"==typeof e&&null!=e?e.assetId??null:null;return null!=t&&this.assetLoader?this.assetLoader.getAnimationClipByAssetId(t):null}}function Q(e){return e.options?.length>0||e.propertyType===y.Boolean||e.propertyType===y.String}function X(e){return"outlineVisibility"===w(e)||e.valueType===y.Boolean||e.valueType===y.String}function Y(e){return"object"==typeof e&&null!=e||"function"==typeof e}function Z(e,t){switch(t.type){case y.Number:return function(e){if("number"==typeof e)return Number.isFinite(e)?{applied:!0,value:e}:{applied:!1};if("string"==typeof e){const t=parseFloat(e);return Number.isFinite(t)?{applied:!0,value:t}:{applied:!1}}return{applied:!1}}(t.value);case y.Boolean:return"boolean"==typeof t.value?{applied:!0,value:t.value}:{applied:!1};case y.Vector2:return H(e,t.value);case y.Vector3:return J(e,t.value);case y.Vector4:return ee(e,t.value);case y.Color:return function(e,t){if(e instanceof c){const a=Ae.set(0);return se(a,t)?(e.set(a.r,a.g,a.b),{applied:!0,value:e}):{applied:!1}}if(e instanceof h){const a=Ae.set(0);return se(a,t)?(e.set(a.r,a.g,a.b,e.w),{applied:!0,value:e}):{applied:!1}}return te(e,t)}(e,t.value);default:return{applied:!1}}}function z(e,t){const s=S(t);return!!function(e){return e instanceof a.Material||!0===e?.isMaterial}(e)&&(("asset"!==s||e.userData?.assetId===t.materialAssetId)&&("outlineVisibility"===w(t)?null!=e.userData?.outlineParameters:null!=e.uniforms?.[t.uniformName]))}function H(e,t){const a=ae(t,2);return a?e instanceof l?(e.fromArray(a),{applied:!0,value:e}):{applied:!0,value:new l(a[0],a[1])}:{applied:!1}}function J(e,t){const a=ae(t,3);return a?e instanceof c?(e.fromArray(a),{applied:!0,value:e}):{applied:!0,value:new c(a[0],a[1],a[2])}:{applied:!1}}function ee(e,t){const a=ae(t,4);return a?e instanceof h?(e.fromArray(a),{applied:!0,value:e}):{applied:!0,value:new h(a[0],a[1],a[2],a[3])}:{applied:!1}}function te(e,t){if(e instanceof i)return se(e,t)?{applied:!0,value:e}:{applied:!1};const a=new i;return se(a,t)?{applied:!0,value:a}:{applied:!1}}function ae(e,t){if(!Array.isArray(e)||e.length<t)return null;const a=new Array(t);for(let s=0;s<t;s++){if("number"!=typeof e[s])return null;a[s]=e[s]}return a}function se(e,t){return t instanceof i||"string"==typeof t||"number"==typeof t?(e.set(t),!0):!!(Array.isArray(t)&&t.length>=3)&&(e.setRGB("number"==typeof t[0]?t[0]:0,"number"==typeof t[1]?t[1]:0,"number"==typeof t[2]?t[2]:0),!0)}function ie(e){if(e instanceof l||e instanceof c||e instanceof h||e instanceof i||e instanceof r)return e.clone()}function re(e){const{owner:t,key:a}=e.resolution;e.hadOwnProperty?(!function(e,t){if(e instanceof l&&t instanceof l)return e.copy(t),!0;if(e instanceof c&&t instanceof c)return e.copy(t),!0;if(e instanceof h&&t instanceof h)return e.copy(t),!0;if(e instanceof i&&t instanceof i)return e.copy(t),!0;if(e instanceof r&&t instanceof r)return e.copy(t),!0}(e.value,e.valueSnapshot),t[a]=e.value):delete t[a]}function ne(e){const t=[];for(const a of e)t.push(a),"group"===a.type&&t.push(...ne(a.childTracks));return t}function oe(e){if("string"!=typeof e)return null;const t=e.trim();return t.length>0?t:null}function le(e){const t=new a.Group;t.name=`SequenceLocatorMarker:${e}`,t.renderOrder=1e3;const s=new a.AxesHelper(.35);s.renderOrder=1e3;const i=Array.isArray(s.material)?s.material:[s.material];for(const e of i)e.depthTest=!1,e.transparent=!0,e.opacity=.9,e.toneMapped=!1;t.add(s);const r=function(e){if("undefined"==typeof document)return null;const t=document.createElement("canvas");t.width=256,t.height=64;const s=t.getContext("2d");if(!s)return null;s.clearRect(0,0,t.width,t.height),s.fillStyle="rgba(16, 18, 24, 0.78)",function(e,t,a,s,i,r){const n=t+s,o=a+i;e.beginPath(),e.moveTo(t+r,a),e.lineTo(n-r,a),e.quadraticCurveTo(n,a,n,a+r),e.lineTo(n,o-r),e.quadraticCurveTo(n,o,n-r,o),e.lineTo(t+r,o),e.quadraticCurveTo(t,o,t,o-r),e.lineTo(t,a+r),e.quadraticCurveTo(t,a,t+r,a),e.closePath()}(s,0,8,t.width,48,8),s.fill(),s.font="24px sans-serif",s.textAlign="center",s.textBaseline="middle",s.fillStyle="#f8fafc",s.fillText(e||"Locator",t.width/2,t.height/2);const i=new a.CanvasTexture(t);i.needsUpdate=!0;const r=new a.SpriteMaterial({map:i,transparent:!0,depthTest:!1});r.toneMapped=!1;const n=new a.Sprite(r);return n.scale.set(.9,.225,1),n}(e);return r&&(r.position.set(0,.45,0),r.renderOrder=1001,t.add(r)),t.traverse(e=>{e.raycast=()=>{}}),t}function ce(e){e.traverse(e=>{const t=e.material;if(Array.isArray(t))for(const e of t)e?.dispose?.(),e?.map?.dispose?.();else t?.dispose?.(),t?.map?.dispose?.()})}const he=new c,ue=new c,pe=new c,de=new c,fe=new c,me=new c,ye=new o,ve=new o,Ce=new r,ge=new r,Ae=new i;/*
|
|
1
|
+
import{BehaviorSubject as e,Subject as t}from"rxjs";import*as a from"three";import{AnimationMixer as s,Color as i,Euler as r,Object3D as n,Quaternion as o,Vector2 as l,Vector3 as c,Vector4 as h}from"three";import{VisualEffect as u}from"../../effects/vfx/vfx-param.js";import{BaseActor as p}from"../../gameplay/actors/actor.js";import d from"../../gameplay/actors/builtin/index.js";import{Prefab as f,PrefabOf as m}from"../../scene/objects/prefab.js";import{SerializedParamType as y}from"../../scene/model.js";import{customParamValueNeedsAsyncResolution as v,deserializeCustomParamValue as C,deserializeCustomParamValueSync as g}from"../../scene/custom-param-deserialize.js";import{getAudioParameterDefinition as A}from"./audio-parameters.js";import{getMaterialSubTrackMatchMode as S,getMaterialSubTrackTarget as w,Sequence as P,isSequenceData as b}from"./sequence-data.js";import{getSequenceSubTrackDefinition as k,getSequenceTrackDefinition as x}from"./sequence-definitions.js";import{applyInterpolation as T,evaluateCustomParamValueKeyframes as I,evaluateNumericKeyframes as M,findKeyframeSpan as B}from"./sequence-value-lane.js";import{evaluateTransformPositionSpan as q}from"./sequence-transform.js";import{applyAnimationClipRootMotionAxisMask as O,buildRetimedAnimationClip as F,getAnimationClipRetimingSignature as E,isAnimationClipUsingRetiming as j}from"./sequence-animation-retiming.js";import*as V from"three/addons/utils/SkeletonUtils.js";import{CharacterAnimationComponent as R,getCharacterMovementLike as _}from"../../gameplay/actors/index.js";import{RootMotionClip as L}from"../../gameplay/animation/root-motion.js";import{markMaterialUniformValuesNeedUpdate as D}from"../../rendering/node-material-webgpu-resolver.js";import{getAnimationClipRigId as K,getAnimationRigIdFromObject as $,setAnimationClipRigId as G}from"../../gameplay/animation/retarget.js";import{hashCameraShakeSeed as N}from"../../gameplay/services/camera-shake.js";import{buildShaderGraphPostProcessMaterial as U,shaderGraphPostProcessWeightUniformName as W}from"../../shader/graph/index.js";export var SequencePlaybackState;!function(e){e.Stopped="stopped",e.Playing="playing",e.Paused="paused"}(SequencePlaybackState||(SequencePlaybackState={}));export class SequencePlayer{constructor(){this._state=new e(SequencePlaybackState.Stopped),this._time=new e(0),this._duration=0,this._timescale=1,this._loop=!1,this._externalTimeControl=!1,this._inEditor=!1,this.bindings=new Map,this.roleBindings=new Map,this.sequenceData=null,this.onComplete=new t,this.onLoop=new t,this.onTimeUpdate=this._time.asObservable(),this.onStateChange=this._state.asObservable(),this.loopCount=0,this.viewController=null,this._cameraControlEnabled=!1,this._cameraControlTrackId=null,this.sequenceCameras=new Map,this.cameraPlayables=new Map,this.cameraBlendCamera=null,this.cameraBlendSource=null,this.cameraBlendOutSource=null,this.cameraOverrideHandle=null,this.activeCameraClipKey=null,this.cameraBlendOutClipKey=null,this.activeCameraShakeClipKeys=new Set,this.nextCameraShakeClipKeys=new Set,this.activePostProcessClips=new Map,this.nextPostProcessClipKeys=new Set,this.audioListener=null,this.audioBuffers=new Map,this.loadingAudioBuffers=new Map,this.animationClips=new Map,this.loadingAnimationClips=new Map,this.retimedAnimationClips=new Map,this.externalRootMotionInterpolants=new WeakMap,this.audioByClip=new Map,this.activeAudioClips=new Set,this.audioGainNodes=new Map,this.audioStartInFlight=new Map,this.lastAudioStartAttemptTime=new Map,this.audioStartRetryIntervalSeconds=.25,this.world=null,this.assetLoader=null,this.actorFactory=null,this.vfxService=null,this.spawnedInstances=new Map,this.activeClips=new Set,this.pendingSpawns=new Set,this.vfxActors=new Map,this.activeVfxClips=new Set,this.locatorMarkers=new Map,this.clearCounter=0,this.propertyPathSegments=new Map,this.propertyResolutionCache=new Map,this.propertySnapshots=new Map,this.materialResolutionCache=new Map,this.materialSnapshots=new Map,this.audioFilters=new Map,this.audioPannerNodes=new Map,this.firedEvents=new Set,this.sequenceEventSyncResolvers={actor:e=>this.resolveSequenceEventActorReference(e)},this.sequenceEventAsyncResolvers={actor:e=>this.resolveSequenceEventActorReference(e),texture:e=>this.assetLoader?.getTextureByAssetId(e)??null,sampler2DNode:e=>this.assetLoader?.getTextureByAssetId(e)??null,object3D:async e=>{const t=await(this.assetLoader?.getModelByAssetId(e));return t?.scene??null},material:e=>this.assetLoader?.getMaterialByAssetId(e)??null,audioBuffer:e=>this.assetLoader?.getAudioByAssetId(e)??null,visualEffect:async e=>{if(!this.assetLoader||!this.actorFactory)return null;const t=await this.assetLoader.getAsset(e);return t?new u(this.actorFactory,t):null},prefab:async e=>{const t=await(this.assetLoader?.getPrefabById(e));return t?new f(t.asset):null},prefabActor:async e=>{const t=await(this.assetLoader?.getPrefabById(e));return t?new m(new f(t.asset)):null},sequence:e=>this.resolveSequenceEventSequence(e),animationClip:e=>this.resolveSequenceEventAnimationClip(e)},this.trackRuntimeEvaluators={object:(e,t,a)=>{t&&this.evaluateObjectTrack(e,t,a)},locator:(e,t,a)=>{t&&this.evaluateLocatorTrack(e,t,a)},camera:(e,t,a)=>this.evaluateCameraTrack(e,a),cameraShake:(e,t,a)=>this.evaluateCameraShakeTrack(e,a),postProcess:(e,t,a)=>this.evaluatePostProcessTrack(e,a),audio:(e,t,a)=>this.evaluateAudioTrack(e,a),vfx:(e,t,a)=>this.evaluateVfxTrack(e,a),spawn:(e,t,a)=>this.evaluateSpawnTrack(e,t,a),group:(e,t,a)=>{if("group"===e.type)for(const t of e.childTracks)this.evaluateTrack(t,a)}},this.subTrackRuntimeEvaluators={transform:(e,t,a)=>{const s=this.getPlayableObject(t);s&&this.evaluateTransformSubTrack(e,s,a)},animation:(e,t,a)=>this.evaluateAnimationSubTrack(e,t,a),visibility:(e,t,a)=>{const s=this.getPlayableObject(t);s&&this.evaluateVisibilitySubTrack(e,s,a)},parameter:(e,t,a)=>this.evaluateParameterSubTrack(e,t.target||null,a),event:(e,t,a)=>this.evaluateEventSubTrack(e,t.target||null,a)}}get state(){return this._state.value}get time(){return this._time.value}get duration(){return this._duration}get timescale(){return this._timescale}set timescale(e){this._timescale=Math.max(.01,e)}get loop(){return this._loop}set loop(e){this._loop=e}get externalTimeControl(){return this._externalTimeControl}set externalTimeControl(e){this._externalTimeControl=e}get inEditor(){return this._inEditor}set inEditor(e){this._inEditor=e,this.updateLocatorMarkerVisibility()}get cameraControlEnabled(){return this._cameraControlEnabled}set cameraControlEnabled(e){this._cameraControlEnabled=e,e||this.releaseCameraOverride()}get cameraControlTrackId(){return this._cameraControlTrackId}set cameraControlTrackId(e){this._cameraControlTrackId!==e&&(this._cameraControlTrackId=e,this.releaseCameraOverride())}setViewController(e){this.viewController&&this.viewController!==e&&this.viewController.clearCameraShakeContributionsForOwner(this),this.viewController=e}setWorld(e){this.world!==e&&(this.restoreAllPropertySnapshots(),this.restoreAllMaterialSnapshots(),this.clearLocatorBindings(),this.clearSequenceCameras(),this.clearCameraShakeContributions(),this.clearPostProcessEffects(),this.world=e,this.clearCounter++,this.vfxActors.clear(),this.spawnedInstances.clear(),this.bindings.clear(),this.activeClips.clear(),this.activeVfxClips.clear(),this.activeAudioClips.clear(),this.audioStartInFlight.clear(),this.lastAudioStartAttemptTime.clear(),this.loadingAudioBuffers.clear(),this.audioFilters.clear(),this.audioPannerNodes.clear(),this.pendingSpawns.clear(),this.propertyResolutionCache.clear(),this.materialResolutionCache.clear(),this.clearRetimedAnimationClipCache(),this._state.next(SequencePlaybackState.Stopped),this.sequenceData&&this.initializeLocatorBindings())}setAudioListener(e){this.audioListener=e}setAssetLoader(e){if(this.assetLoader=e,this.sequenceData){const e=this.clearCounter;this.preloadSequenceResources(this.sequenceData,e)}}setActorFactory(e){this.actorFactory=e}setVfxService(e){this.vfxService=e}load(e){if(this.stop(),this.clearCounter++,this.clearLocatorBindings(),this.clearSequenceCameras(),this.sequenceData=e,this._duration=e.duration,this._loop=e.loop,this._timescale=e.playbackRate,this.clearRetimedAnimationClipCache(),this.bindings.clear(),this.initializeLocatorBindings(),this.loopCount=0,this.assetLoader){const t=this.clearCounter;this.preloadSequenceResources(e,t)}}preloadSequenceResources(e,t){return Promise.all([this.preloadAudioBuffersForSequence(e,t),this.preloadAnimationClipsForSequence(e,t)]).then(()=>{})}getAudioAssetIdsForSequence(e){const t=new Set;for(const a of e.tracks){if("audio"!==a.type)continue;const e=a;for(const a of e.clips??[])a.audioAssetId&&t.add(a.audioAssetId)}return[...t]}async preloadAudioBuffersForSequence(e,t){if(!this.assetLoader)return;const a=this.getAudioAssetIdsForSequence(e);0!==a.length&&await Promise.all(a.map(async e=>{if(t!==this.clearCounter)return;if(this.audioBuffers.has(e))return;let a=this.loadingAudioBuffers.get(e);a||(a=this.assetLoader.getAudioByAssetId(e),this.loadingAudioBuffers.set(e,a));try{const s=await a;if(t!==this.clearCounter)return;this.audioBuffers.set(e,s)}catch(e){}finally{this.loadingAudioBuffers.get(e)===a&&this.loadingAudioBuffers.delete(e)}}))}async preloadAnimationClipsForSequence(e,t){this.assetLoader&&t===this.clearCounter&&await this.prepareAnimationClipsForBindings(e,t)}async prepare(){if(!this.sequenceData||!this.assetLoader)return;this.resolveBindings();const e=this.clearCounter;await Promise.all([this.prepareAnimationClipsForBindings(this.sequenceData,e),this.preloadVisualEffectsForSequence(this.sequenceData,e)])}async preloadVisualEffectsForSequence(e,t){if(!this.world||!this.actorFactory)return;const a=new Set;for(const t of ne(e.tracks))if("vfx"===t.type)for(const e of t.clips??[])null!=e.vfxAssetId&&a.add(e.vfxAssetId);if(0===a.size)return;const s=await Promise.all([...a].map(e=>this.assetLoader.getAsset(e)));if(t!==this.clearCounter)return;const i=s.filter(e=>null!=e&&null!=e.vfx).map(e=>new u(this.actorFactory,e));await this.world.preloadVisualEffects(i)}async prepareAnimationClipsForBindings(e,t){const a=[];for(const s of ne(e.tracks)){if(!("subTracks"in s))continue;const e=this.bindings.get(s.id),i=null==e?null:this.getPlayableObject(e);if(null==i)continue;const r=$(i);for(const e of s.subTracks)if("animation"===e.type)for(const s of e.clips){if(t!==this.clearCounter)return;if(null!=s.animationClipAssetId){const e=this.animationClipCacheKey(s.animationClipAssetId,r);a.push(this.ensureAnimationClip(s.animationClipAssetId,r).then(a=>{null!=a&&t===this.clearCounter&&j(s)&&(this.getPlayableAnimationClip(e,a,s,!1),s.rootMotion&&this.getPlayableAnimationClip(e,a,s,!0))}))}}}await Promise.all(a)}bindRole(e,t){this.roleBindings.set(e,t),this.sequenceData&&this.resolveBindings()}bindObject(e,t){if(this.sequenceData)for(const a of ne(this.sequenceData.tracks))"object"!==a.type||a.targetId!==e||a.role||this.createBinding(a,t)}unbindObject(e){if(this.sequenceData)for(const t of ne(this.sequenceData.tracks))"object"!==t.type||t.targetId!==e||t.role||this.removeBinding(t.id)}getLocator(e){return this.getLocators(e)[0]??null}getLocators(e){const t=oe(e);if(!t||!this.sequenceData)return[];const a=[];for(const e of ne(this.sequenceData.tracks)){if("locator"!==e.type)continue;if(oe(e.bindingId)!==t)continue;const s=this.bindings.get(e.id),i=s?this.getPlayableObject(s):null;i&&(i.updateWorldMatrix(!0,!1),a.push({trackId:e.id,name:e.name,bindingId:e.bindingId,position:i.getWorldPosition(new c),rotation:i.getWorldQuaternion(new o),scale:i.getWorldScale(new c)}))}return a}resolveBindings(){if(this.sequenceData)for(const e of this.sequenceData.tracks)this.resolveTrackBinding(e)}initializeLocatorBindings(){if(this.sequenceData)for(const e of ne(this.sequenceData.tracks)){if("locator"!==e.type||this.bindings.has(e.id))continue;const t=new n;t.name=e.name||"Locator",t.userData.sequenceLocatorTrackId=e.id,this.world?.scene&&null==t.parent&&this.world.scene.add(t);const a=le(e.name);a.visible=this._inEditor,t.add(a),this.locatorMarkers.set(e.id,a),this.disableLocatorInteraction(t),this.createBinding(e,t)}}clearLocatorBindings(){for(const e of this.locatorMarkers.values())ce(e);for(const e of this.bindings.values()){if("locator"!==e.track.type)continue;const t=this.getPlayableObject(e);t?.parent&&t.removeFromParent()}this.locatorMarkers.clear()}updateLocatorMarkerVisibility(){for(const e of this.locatorMarkers.values())e.visible=this._inEditor}disableLocatorInteraction(e){e.traverse(e=>{e.raycast=()=>{}})}resolveTrackBinding(e){if("object"===e.type){const t=e;t.role&&this.roleBindings.has(t.role)&&this.createBinding(e,this.roleBindings.get(t.role))}else if("spawn"===e.type){const t=e;t.role&&this.roleBindings.has(t.role)&&this.createBinding(e,this.roleBindings.get(t.role))}else if("group"===e.type)for(const t of e.childTracks)this.resolveTrackBinding(t)}createBinding(e,t){const a=t instanceof p?t.object:t,i=this.bindings.get(e.id),r=null!=i?i.target instanceof p?i.target.object:i.target:null,n=null!=i&&i.target===t&&r===a,o=e.subTracks.some(e=>"animation"===e.type);null==i||n||this.releaseBinding(i);const l=n?i:{track:e,target:t,activeActions:new Map};l.track=e,l.target=t,n||(l.originalTransform={position:a.position.clone(),rotation:a.rotation.clone(),scale:a.scale.clone()},l.originalParent=a.parent),o&&null==l.mixer?l.mixer=new s(a):o||(l.mixer=void 0),this.bindings.set(e.id,l)}removeBinding(e){const t=this.bindings.get(e);t&&(this.releaseBinding(t),this.bindings.delete(e))}releaseBinding(e){this.clearExternalRootMotionPreview(e);for(const t of e.activeActions.values())t.stop();e.activeActions.clear(),e.mixer?.stopAllAction(),e.charAnimComponent?.stopSequenceAnimation(),e.charAnimComponent=void 0,e.charAnimActionKeys?.clear()}play(){this._state.value!==SequencePlaybackState.Playing&&this.sequenceData&&(this._state.value===SequencePlaybackState.Stopped&&(this._time.next(0),this.loopCount=0,this.resolveBindings(),this.captureOriginalTransforms()),this._state.next(SequencePlaybackState.Playing),this.evaluate(this._time.value),this.resumeVfx())}pause(){this._state.value===SequencePlaybackState.Playing&&(this._state.next(SequencePlaybackState.Paused),this.pauseAudio(),this.pauseVfx())}pauseAudio(){for(const e of this.audioByClip.values())e.pause()}pauseVfx(){for(const e of this.vfxActors.values())e.pause()}resumeVfx(){for(const[e,t]of this.vfxActors.entries())(this.activeVfxClips.has(e)||t.getParticleCount()>0)&&t.play()}cancel(){this._state.next(SequencePlaybackState.Stopped),this._time.next(0),this.clearCounter++,this.loopCount=0,this.pauseAudio(),this.releaseCameraOverride(),this.restoreAllPropertySnapshots(),this.restoreAllMaterialSnapshots(),this.stopAllAudio(),this.stopAllAnimations(),this.despawnAll(),this.stopAllVfx(),this.firedEvents.clear(),this.clearCameraShakeContributions(),this.clearPostProcessEffects()}stop(){this._state.next(SequencePlaybackState.Stopped),this._time.next(0),this.clearCounter++,this.loopCount=0,this.pauseAudio(),this.releaseCameraOverride(),this.restoreAllPropertySnapshots(),this.restoreAllMaterialSnapshots(),this.restoreOriginalTransforms(),this.restoreOriginalParents(),this.stopAllAudio(),this.stopAllAnimations(),this.despawnAll(),this.stopAllVfx(),this.firedEvents.clear(),this.clearCameraShakeContributions(),this.clearPostProcessEffects()}restart(){this.stop(),this.play()}seek(e){const t=Math.max(0,Math.min(e,this._duration));t<this._time.value&&this.resetVfxForTimeReset(t),this._time.next(t),this.evaluate(t)}update(e){if(this._state.value!==SequencePlaybackState.Playing)return;if(!this.sequenceData)return;if(this._externalTimeControl){for(const t of this.bindings.values())t.mixer&&t.mixer.update(e*this._timescale);for(const t of this.spawnedInstances.values())t.mixer&&t.mixer.update(e*this._timescale);return}const t=this._time.value+e*this._timescale;if(t>=this._duration){if(!this._loop)return this._time.next(this._duration),this.evaluate(this._duration),this.releaseCameraOverride(),this.clearCameraShakeContributions(),this.clearPostProcessEffects(),this.restoreAllPropertySnapshots(),this.restoreAllMaterialSnapshots(),this._state.next(SequencePlaybackState.Stopped),void this.onComplete.next();{this.loopCount++;const e=t%this._duration;this.resetVfxForTimeReset(e),this._time.next(e),this.firedEvents.clear(),this.onLoop.next(this.loopCount)}}else this._time.next(t);this.evaluate(this._time.value);for(const t of this.bindings.values())t.mixer&&t.mixer.update(e*this._timescale);for(const t of this.spawnedInstances.values())t.mixer&&t.mixer.update(e*this._timescale)}evaluate(e){if(this.sequenceData){this.nextCameraShakeClipKeys.clear(),this.nextPostProcessClipKeys.clear();for(const t of this.sequenceData.tracks){if(!t.muted&&("object"===t.type||"locator"===t.type||"camera"===t.type||"spawn"===t.type||"vfx"===t.type)){const e=this.bindings.get(t.id);this.updateTrackParenting(t,e)}this.evaluateTrack(t,e)}this.updateCameraControl(e),this.syncCameraShakeContributions(),this.syncPostProcessEffects()}}evaluateTrack(e,t){if(e.muted)return;const a=this.bindings.get(e.id);(0,this.trackRuntimeEvaluators[x(e.type).runtimeEvaluator])(e,a,t)}evaluateObjectTrack(e,t,a){this.evaluateSubTracks(e.subTracks,t,a)}evaluateLocatorTrack(e,t,a){this.evaluateSubTracks(e.subTracks,t,a)}getActiveTrackObjects(e){if(!this.sequenceData)return[];const t=ne(this.sequenceData.tracks).find(t=>t.id===e);return t?this.getActiveObjectsForTrack(t):[]}evaluateSubTracks(e,t,a){this._externalTimeControl&&this.beginExternalRootMotionPreview(t);for(const s of e){if(s.muted)continue;(0,this.subTrackRuntimeEvaluators[k(s.type).runtimeEvaluator])(s,t,a)}this._externalTimeControl&&this.applyExternalRootMotionPreview(t)}beginExternalRootMotionPreview(e){const t=e.externalRootMotionPreview;if(!t)return;const a=this.getPlayableObject(e);a&&a.position.sub(t.appliedOffset),t.appliedOffset.set(0,0,0),t.sampledOffset.set(0,0,0),t.root=null}sampleExternalRootMotionPreview(e,t,s,i){if(!t.motionTrack)return;let r=this.externalRootMotionInterpolants.get(t);r||(r=t.motionTrack.InterpolantFactoryMethodSmooth([]),this.externalRootMotionInterpolants.set(t,r));const n=e.externalRootMotionPreview??(e.externalRootMotionPreview={appliedOffset:new c,sampledOffset:new c,root:null}),o=Math.max(0,Math.min(i,t.duration)),l=Math.max(o,Math.min(s,t.duration));de.fromArray(r.evaluate(o)),fe.fromArray(r.evaluate(l)),n.sampledOffset.subVectors(fe,de),n.sampledOffset.y=0;const h=this.getPlayableObject(e),u=a.PropertyBinding.parseTrackName(t.motionTrack.name);n.root=h?.getObjectByName(u.nodeName)??h}applyExternalRootMotionPreview(e){const t=e.externalRootMotionPreview,a=this.getPlayableObject(e);t&&a&&t.root&&(t.root.getWorldScale(me),t.appliedOffset.copy(t.sampledOffset).multiply(me).applyQuaternion(a.quaternion),a.position.add(t.appliedOffset))}clearExternalRootMotionPreview(e){const t=e.externalRootMotionPreview,a=this.getPlayableObject(e);t&&a&&a.position.sub(t.appliedOffset),e.externalRootMotionPreview=void 0}evaluateTransformSubTrack(e,t,a){const s=e.keyframes;if(0===s.length)return;const{prev:i,next:r,prevIndex:n,nextIndex:o,t:l}=B(s,a);if(i)if(e.components.position&&q(s,n,o,l,t.position),r&&i!==r){const a=T(l,i.interpolation);e.components.rotation&&i.rotation&&r.rotation&&(ye.setFromEuler(Ce.fromArray([...i.rotation,"XYZ"])),ve.setFromEuler(ge.fromArray([...r.rotation,"XYZ"])),t.quaternion.slerpQuaternions(ye,ve,a)),e.components.scale&&i.scale&&r.scale&&t.scale.lerpVectors(he.fromArray(i.scale),ue.fromArray(r.scale),a)}else e.components.rotation&&i.rotation&&t.rotation.fromArray([...i.rotation,"XYZ"]),e.components.scale&&i.scale&&t.scale.fromArray(i.scale)}evaluateAnimationSubTrack(e,t,s){if(!t.mixer||!t.activeActions)return;const i=t.target instanceof p?t.target.object:t.target;if(i)for(const r of e.clips){const n=r.startTime+r.duration,o=s>=r.startTime&&s<n,l=`${e.id}-${r.id}`;let c=t.activeActions.get(l),h=!1;if(o){if(!c){h=!0;const e=r.animationClipAssetId;if(null==e)continue;const s=$(i),n=this.animationClipCacheKey(e,s),o=this.animationClips.get(n);if(null==o){this.ensureAnimationClip(e,s);continue}const u=this.prepareAnimationPlayback(n,o,r),d=t;let f=!1;if(t.target instanceof p){d.charAnimComponent||(d.charAnimComponent=t.target.getComponent(R)??void 0);const e=d.charAnimComponent;if(null!=e){const a=r.rootMotion?j(r)?this.getPlayableAnimationClip(n,o,r,!0):L.fromClip(u.clip,!1):u.clip;if(this._externalTimeControl)c=e.beginExternalAnimationControl(a,{timeScale:u.timeScale});else if(e.play(a,{inPlace:!r.rootMotion,loop:!1,priority:20,timeScale:u.timeScale,fadeTime:r.fadeInDuration??.2,offset:u.startOffset}),c=e.getFullBodyAction(),r.rootMotion){const e=_(t.target);e&&e.setRootMotionAction(c,{cancelWithJump:e.allowRootMotionJumpCancel,onJumpCancel:()=>this.cancel()})}t.activeActions.set(l,c),d.charAnimActionKeys||(d.charAnimActionKeys=new Set),d.charAnimActionKeys.add(l),f=!0}}f||(c=t.mixer.clipAction(u.clip),c.setLoop(a.LoopOnce,1),c.clampWhenFinished=!0,c.timeScale=u.timeScale,u.startOffset>0&&(c.time=u.startOffset),t.activeActions.set(l,c),c.play())}if(c){const e=t;if(this._externalTimeControl){e.charAnimComponent?.beginExternalControl();const a=this.getAnimationPlaybackLocalTime(r,s),i=Math.min(a,c.getClip().duration);(h||Math.abs(c.time-i)>.001)&&(c.time=i,c.paused=!1,c.play(),e.charAnimComponent?e.charAnimComponent.getMixer()?.update(0):t.mixer&&t.mixer.update(0)),r.rootMotion&&c.getClip()instanceof L&&this.sampleExternalRootMotionPreview(t,c.getClip(),i,j(r)?0:r.clipStartOffset)}else e.charAnimComponent?.endExternalControl()}}else if(c){t.activeActions.delete(l);const e=t;e.charAnimActionKeys?.has(l)?(e.charAnimActionKeys.delete(l),c.stop(),0===e.charAnimActionKeys.size&&e.charAnimComponent&&(e.charAnimComponent.stopSequenceAnimation(),e.charAnimComponent=void 0)):(c.stop(),this._externalTimeControl&&t.mixer&&t.mixer.update(0))}}}evaluateVisibilitySubTrack(e,t,a){const s=e.keyframes;if(0===s.length)return;let i=s[0];for(const e of s){if(!(e.time<=a))break;i=e}t.visible=i.visible}evaluatePropertySubTrack(e,t,a){const s=I(e.keyframes,a,{min:e.range?.[0],max:e.range?.[1],stepOnly:Q(e)});s&&this.applyResolvedPropertyValue(e,t,s)}evaluateParameterSubTrack(e,t,a){if("audioParameter"===e.type)return;const s=I(e.keyframes,a,"property"===e.type?{min:e.range?.[0],max:e.range?.[1],stepOnly:Q(e)}:"material"===e.type?{min:e.range?.[0],max:e.range?.[1],stepOnly:X(e)}:{});s&&("property"!==e.type?this.applyResolvedMaterialValue(e,t,s):this.applyResolvedPropertyValue(e,t,s))}evaluateEventSubTrack(e,t,a){if(t instanceof p&&this._state.value===SequencePlaybackState.Playing)for(const s of e.events){const i=`${e.id}-${s.id}`;if(a>=s.time&&!this.firedEvents.has(i)){if(this.firedEvents.add(i),s.editorOnly&&!this._inEditor)continue;if(!s.functionName)continue;const e=t[s.functionName];"function"==typeof e?this.invokeSequenceEvent(t,s.functionName,e,s.arguments??[]):console.warn(`Sequence event method '${s.functionName}' not found on actor`)}else s.time>a&&this.firedEvents.delete(i)}}evaluateCameraTrack(e,t){const a=this.ensureSequenceCamera(e);this.applyCameraTrackSettings(e,a),this.evaluateSubTracks(e.subTracks,this.getCameraPlayable(e,a),t),a.updateProjectionMatrix()}evaluateCameraShakeTrack(e,t){if(this.viewController)for(const a of e.clips??[]){if(!this.isCameraShakeClipActive(a,t))continue;const e=t-a.startTime,s=a.id;this.nextCameraShakeClipKeys.add(s),this.viewController.setCameraShakeContribution(this,s,a,e,a.seed??N(a.id))}}evaluatePostProcessTrack(e,t){if(this.viewController&&this.assetLoader){for(const a of e.clips??[]){if(!this.isPostProcessClipActive(a,t))continue;const s=this.getPostProcessClipKey(e,a);this.nextPostProcessClipKeys.add(s),this.ensurePostProcessClipEffect(e,a,s);const i=this.activePostProcessClips.get(s);i?.handle&&(i.handle.stage=e.stage,i.handle.priority=e.priority,i.handle.enabled=!0,this.applyPostProcessClipWeight(i.handle,a,t))}this.evaluatePostProcessMaterialSubTracks(e,t)}}evaluatePostProcessMaterialSubTracks(e,t){for(const a of e.subTracks){if(a.muted||"material"!==a.type)continue;const s=I(a.keyframes,t,{min:a.range?.[0],max:a.range?.[1],stepOnly:X(a)});s&&this.applyPostProcessMaterialValue(e.id,a,s)}}applyPostProcessMaterialValue(e,t,a){if("shaderUniform"===w(t)&&t.uniformName)for(const s of this.activePostProcessClips.values()){if(s.trackId!==e||!s.handle)continue;const i=s.handle.material,r=i.uniforms?.[t.uniformName];if(!r)continue;const n=Y(r.value,a);n.applied&&(r.value=n.value,i.uniformsNeedUpdate=!0,D(i))}}isPostProcessClipActive(e,t){return t>=e.startTime&&t<e.startTime+e.duration}getPostProcessClipKey(e,t){return`${e.id}-${t.id}`}ensurePostProcessClipEffect(e,t,a){const s=t.shaderGraphAssetId;if(!s)return void this.releasePostProcessClipEffect(a);const i=JSON.stringify(t.shaderGraphParams??{}),r=this.activePostProcessClips.get(a);if(r?.assetId===s&&r.paramsSignature===i)return;this.releasePostProcessClipEffect(a);const n={key:a,trackId:e.id,clipId:t.id,assetId:s,paramsSignature:i,version:this.clearCounter};this.activePostProcessClips.set(a,n),this.loadPostProcessClipEffect(e,t,n)}async loadPostProcessClipEffect(e,t,a){if(this.assetLoader&&this.viewController)try{const s=await this.assetLoader.getShaderGraphByAssetId(a.assetId);if(!this.isPostProcessClipEntryCurrent(a))return;if("postProcess"!==s.target)return console.warn(`Sequence post-process clip references shader graph "${a.assetId}" with target "${s.target}"`),void this.releasePostProcessClipEffect(a.key);const i=await this.assetLoader.prepareShaderGraphParameters(s,t.shaderGraphParams??{});if(!this.isPostProcessClipEntryCurrent(a))return;const r=U(s,{parameters:i});if(!this.isPostProcessClipEntryCurrent(a))return void r.dispose();a.handle=this.viewController.addPostProcessEffect(r,{stage:e.stage,priority:e.priority,enabled:!0}),this.applyPostProcessClipWeight(a.handle,t,this._time.value)}catch(e){this.isPostProcessClipEntryCurrent(a)&&this.releasePostProcessClipEffect(a.key),console.error(`Failed to create post-process effect for clip ${t.id}:`,e)}}isPostProcessClipEntryCurrent(e){return this.clearCounter===e.version&&this.activePostProcessClips.get(e.key)===e}applyPostProcessClipWeight(e,t,a){const s=e.material.uniforms?.[W];null!=s&&(s.value=this.getPostProcessClipWeight(t,a),e.material.uniformsNeedUpdate=!0)}getPostProcessClipWeight(e,t){const a=Math.max(0,t-e.startTime),s=Math.max(0,e.startTime+e.duration-t);let i=1;const r=Math.max(0,e.fadeInDuration??0);r>0&&(i=Math.min(i,a/r));const n=Math.max(0,e.fadeOutDuration??0);return n>0&&(i=Math.min(i,s/n)),Math.max(0,Math.min(1,i))}syncPostProcessEffects(){for(const e of Array.from(this.activePostProcessClips.keys()))this.nextPostProcessClipKeys.has(e)||this.releasePostProcessClipEffect(e);this.nextPostProcessClipKeys.clear()}clearPostProcessEffects(){for(const e of Array.from(this.activePostProcessClips.keys()))this.releasePostProcessClipEffect(e);this.nextPostProcessClipKeys.clear()}releasePostProcessClipEffect(e){const t=this.activePostProcessClips.get(e);if(t&&(this.activePostProcessClips.delete(e),t.handle)){const e=t.handle.material;t.handle.dispose(),e.dispose()}}getCameraPlayable(e,t){let a=this.cameraPlayables.get(e.id);return a?a.target=t:(a={target:t},this.cameraPlayables.set(e.id,a)),a}ensureSequenceCamera(e){let t=this.sequenceCameras.get(e.id);if(t)null==t.parent&&this.world?.scene.add(t);else{const s=e.cameraSettings??{fov:60,near:.1,far:1e3};t=new a.PerspectiveCamera(s.fov??60,this.getCurrentCameraAspect(),s.near??.1,s.far??1e3),t.name=e.name||"Sequence Camera",t.userData.sequenceCameraTrackId=e.id,t.layers.mask=this.viewController?.getBaseCamera().layers.mask??t.layers.mask,this.sequenceCameras.set(e.id,t),this.world?.scene.add(t)}return t}clearSequenceCameras(){this.releaseCameraOverride();for(const e of this.sequenceCameras.values())e.removeFromParent();this.sequenceCameras.clear(),this.cameraPlayables.clear()}applyCameraTrackSettings(e,t){const a=e.cameraSettings??{fov:60,near:.1,far:1e3};t.fov=a.fov??60,t.near=a.near??.1,t.far=a.far??1e3,t.aspect=this.getCurrentCameraAspect()}getCurrentCameraAspect(){const e=this.viewController?.getBaseCamera();if(e instanceof a.PerspectiveCamera&&Number.isFinite(e.aspect)&&e.aspect>0)return e.aspect;const t=this.viewController?.getSourceCamera();return t instanceof a.PerspectiveCamera&&Number.isFinite(t.aspect)&&t.aspect>0?t.aspect:1}updateCameraControl(e){if(!this._cameraControlEnabled||!this.viewController||!this.sequenceData)return void this.releaseCameraOverride();const t=this.findActiveCameraShot(e);if(t)return void this.updateActiveCameraShot(t,e);const a=this.findBlendOutCameraShot(e);a?this.updateCameraBlendOut(a,e):this.releaseCameraOverride()}findActiveCameraShot(e){if(!this.sequenceData)return null;let t=null;for(const a of ne(this.sequenceData.tracks)){if("camera"!==a.type||a.muted||!this.isCameraControlTrackEligible(a))continue;const s=a.clips??[];for(const i of s)this.isCameraClipActive(i,e)&&(t={track:a,clip:i,camera:this.ensureSequenceCamera(a),key:this.getCameraClipKey(a,i)})}return t}findBlendOutCameraShot(e){if(!this.sequenceData)return null;let t=null;for(const a of ne(this.sequenceData.tracks)){if("camera"!==a.type||a.muted||!this.isCameraControlTrackEligible(a))continue;const s=a.clips??[];for(const i of s){const s=Math.max(0,i.blendOutDuration??0);if(s<=0)continue;const r=this.getCameraClipEnd(i);e>=r&&e<r+s&&(t={track:a,clip:i,camera:this.ensureSequenceCamera(a),key:this.getCameraClipKey(a,i)})}}return t}isCameraControlTrackEligible(e){return null==this._cameraControlTrackId||e.id===this._cameraControlTrackId}updateActiveCameraShot(e,t){if(!this.viewController)return;const a=this.ensureCameraBlendCamera();this.activeCameraClipKey!==e.key&&(this.copyCameraState(this.viewController.getSourceCamera(),this.ensureCameraBlendSource()),this.activeCameraClipKey=e.key,this.cameraBlendOutClipKey=null);const s=Math.max(0,e.clip.blendInDuration??0),i=s<=0?1:this.evaluateCameraBlendAlpha((t-e.clip.startTime)/s,e.clip);i>=1?this.copyCameraState(e.camera,a):this.blendCameraState(this.ensureCameraBlendSource(),e.camera,a,i),a.updateProjectionMatrix(),this.ensureCameraOverride()}updateCameraBlendOut(e,t){if(!this.viewController)return;const a=this.ensureCameraBlendCamera();if(this.cameraBlendOutClipKey!==e.key){const t=this.activeCameraClipKey===e.key?this.viewController.getSourceCamera():e.camera;this.copyCameraState(t,this.ensureCameraBlendOutSource()),this.activeCameraClipKey=null,this.cameraBlendOutClipKey=e.key}const s=this.getCameraClipEnd(e.clip),i=Math.max(0,e.clip.blendOutDuration??0),r=i<=0?1:this.evaluateCameraBlendAlpha((t-s)/i,e.clip);this.blendCameraState(this.ensureCameraBlendOutSource(),this.viewController.getBaseCamera(),a,r),a.updateProjectionMatrix(),this.ensureCameraOverride()}ensureCameraBlendCamera(){return this.cameraBlendCamera||(this.cameraBlendCamera=new a.PerspectiveCamera(60,this.getCurrentCameraAspect(),.1,1e3),this.cameraBlendCamera.name="Sequence Camera Blend"),this.cameraBlendCamera}ensureCameraBlendSource(){return this.cameraBlendSource||(this.cameraBlendSource=new a.PerspectiveCamera),this.cameraBlendSource}ensureCameraBlendOutSource(){return this.cameraBlendOutSource||(this.cameraBlendOutSource=new a.PerspectiveCamera),this.cameraBlendOutSource}ensureCameraOverride(){this.viewController&&!this.cameraOverrideHandle&&(this.cameraOverrideHandle=this.viewController.pushCameraOverride(this.ensureCameraBlendCamera(),this))}releaseCameraOverride(){this.cameraOverrideHandle?.release(),this.cameraOverrideHandle=null,this.viewController?.releaseCameraOverridesForOwner(this),this.activeCameraClipKey=null,this.cameraBlendOutClipKey=null}isCameraClipActive(e,t){return t>=e.startTime&&t<this.getCameraClipEnd(e)}getCameraClipEnd(e){return e.startTime+Math.max(0,e.duration)}isCameraShakeClipActive(e,t){return t>=e.startTime&&t<this.getCameraShakeClipEnd(e)}getCameraShakeClipEnd(e){return e.startTime+Math.max(0,e.duration)}getCameraClipKey(e,t){return`${e.id}-${t.id}`}evaluateCameraBlendAlpha(e,t){return T(Math.max(0,Math.min(1,e)),t.blendInterpolation??"cubic")}syncCameraShakeContributions(){if(!this.viewController)return this.activeCameraShakeClipKeys.clear(),void this.nextCameraShakeClipKeys.clear();for(const e of this.activeCameraShakeClipKeys)this.nextCameraShakeClipKeys.has(e)||this.viewController.removeCameraShakeContribution(this,e);this.activeCameraShakeClipKeys.clear();for(const e of this.nextCameraShakeClipKeys)this.activeCameraShakeClipKeys.add(e);this.nextCameraShakeClipKeys.clear()}clearCameraShakeContributions(){this.activeCameraShakeClipKeys.clear(),this.nextCameraShakeClipKeys.clear(),this.viewController?.clearCameraShakeContributionsForOwner(this)}copyCameraState(e,t){e.updateWorldMatrix(!0,!1),t.position.copy(e.getWorldPosition(he)),t.quaternion.copy(e.getWorldQuaternion(ye)),t.scale.copy(e.getWorldScale(ue)),e instanceof a.PerspectiveCamera?(t.fov=e.fov,t.near=e.near,t.far=e.far,t.aspect=e.aspect):t.aspect=this.getCurrentCameraAspect(),t.layers.mask=e.layers.mask}blendCameraState(e,t,s,i){e.updateWorldMatrix(!0,!1),t.updateWorldMatrix(!0,!1),s.position.lerpVectors(e.getWorldPosition(he),t.getWorldPosition(ue),i),s.quaternion.slerpQuaternions(e.getWorldQuaternion(ye),t.getWorldQuaternion(ve),i),s.scale.lerpVectors(e.getWorldScale(he),t.getWorldScale(ue),i),e instanceof a.PerspectiveCamera&&t instanceof a.PerspectiveCamera?(s.fov=e.fov+(t.fov-e.fov)*i,s.near=e.near+(t.near-e.near)*i,s.far=e.far+(t.far-e.far)*i,s.aspect=t.aspect):t instanceof a.PerspectiveCamera?(s.fov=t.fov,s.near=t.near,s.far=t.far,s.aspect=t.aspect):s.aspect=this.getCurrentCameraAspect(),s.layers.mask=t.layers.mask}evaluateAudioTrack(e,t){if(!this.assetLoader||!e.clips||0===e.clips.length)return;const a=this._state.value===SequencePlaybackState.Playing,s=this.evaluateAudioSubTracks(e,t);e.volume;for(const i of e.clips){const r=i.startTime+i.duration,n=t>=i.startTime&&t<r,o=`${e.id}-${i.id}`;if(n){if(this.activeAudioClips.has(o)||this.activeAudioClips.add(o),a){const a=this.audioByClip.get(o);a&&a.isPlaying||this.tryStartAudioClip(e,i,o,t,s)}const r=this.audioByClip.get(o);r&&this.applyAudioParameters(r,e,i,o,t,s)}else this.activeAudioClips.has(o)&&(this.activeAudioClips.delete(o),this.lastAudioStartAttemptTime.delete(o),this.audioStartInFlight.delete(o),this.stopAudioClip(o))}}tryStartAudioClip(e,t,a,s,i){if(this.audioStartInFlight.has(a))return;const r=this.lastAudioStartAttemptTime.get(a);if(void 0!==r&&s-r<this.audioStartRetryIntervalSeconds)return;this.lastAudioStartAttemptTime.set(a,s);const n=this.playAudioClip(e,t,a,s,i).catch(()=>{}).finally(()=>{this.audioStartInFlight.get(a)===n&&this.audioStartInFlight.delete(a)});this.audioStartInFlight.set(a,n)}applyAudioParameters(e,t,s,i,r,n){const o=n.volume??1,l=Math.random(),c=s.volumeRandomization?(2*l-1)*s.volumeRandomization:0;let h=1;const u=r-s.startTime;u<s.fadeInDuration&&s.fadeInDuration>0?h=u/s.fadeInDuration:u>s.duration-s.fadeOutDuration&&s.fadeOutDuration>0&&(h=(s.duration-u)/s.fadeOutDuration);const p=Math.max(0,(t.volume??1)*o*(s.volume+c)*h);e.setVolume(p);let d=n.detune??0;if(s.pitchRandomization){d+=(2*Math.random()-1)*s.pitchRandomization}if(e.setDetune(d),e.hasPlaybackControl&&e.setPlaybackRate(s.playbackRate*this.timescale),this.audioListener&&this.audioListener.context){const s=this.audioListener.context,r=[],o=n.lowpass,l=n.highpass;let c=this.audioFilters.get(i);if(void 0!==o||void 0!==l)c||(c=s.createBiquadFilter(),this.audioFilters.set(i,c)),void 0!==o?(c.type="lowpass",c.frequency.value=o):void 0!==l&&(c.type="highpass",c.frequency.value=l),r.push(c);else if(c){try{c.disconnect()}catch{}this.audioFilters.delete(i)}const h=n.pan;if(!t.spatial&&e instanceof a.Audio&&void 0!==h&&"function"==typeof s.createStereoPanner){let e=this.audioPannerNodes.get(i);e||(e=s.createStereoPanner(),this.audioPannerNodes.set(i,e)),e.pan.value=h,r.push(e)}else{const e=this.audioPannerNodes.get(i);if(e){try{e.disconnect()}catch{}this.audioPannerNodes.delete(i)}}e.setFilters(r)}t.spatial&&e instanceof a.PositionalAudio?this.updatePositionalAudioTransform(e,t,s,n.spatialBlend):void 0!==n.pan&&this.audioListener}updatePositionalAudioTransform(e,t,s,i){let r=null,n=null;const o=s.attachedToTrackId||t.parent?.trackId,l=s.attachmentSocketName||t.parent?.socketName;if(o){const e=this.sequenceData?.tracks.find(e=>e.id===o);if(e){const t=this.getActiveObjectsForTrack(e);if(t.length>0){const e=t[0];if(r=he,n=ye,e.getWorldPosition(r),e.getWorldQuaternion(n),l){const t=this.findSocket(e,l);t&&(t.getWorldPosition(r),t.getWorldQuaternion(n))}}}}if(r&&n){const t="number"==typeof i?a.MathUtils.clamp(i,0,1):1;if(t<1&&this.audioListener){const e=pe;this.audioListener.getWorldPosition(e),r=r.clone().lerp(e,1-t)}e.position.copy(r),e.quaternion.copy(n),e.updateMatrixWorld()}}async playAudioClip(e,t,s,i,r){if(!this.assetLoader||!t.audioAssetId||null==this.audioListener)return;if("suspended"===this.audioListener.context.state)try{await this.audioListener.context.resume()}catch(e){return void console.warn("Failed to resume audio context:",e)}this.stopAudioClip(s);const n=this.clearCounter;try{let i=this.audioBuffers.get(t.audioAssetId);if(!i){let e=this.loadingAudioBuffers.get(t.audioAssetId);e||(e=this.assetLoader.getAudioByAssetId(t.audioAssetId),this.loadingAudioBuffers.set(t.audioAssetId,e));try{i=await e,this.audioBuffers.set(t.audioAssetId,i)}finally{this.loadingAudioBuffers.delete(t.audioAssetId)}}if(n!==this.clearCounter)return;const o=this._time.value,l=t.startTime+t.duration;if(!(o>=t.startTime&&o<l))return;const c=Math.max(0,o-t.startTime),h=t.clipStartOffset+c*t.playbackRate;if(h>=i.duration||c>=t.duration)return;let u=this.audioByClip.get(s);const p=!0===e.spatial,d=u&&!0===u.isPositionalAudio;if(u&&p!==d&&(u.isPlaying&&u.stop(),u.disconnect(),this.audioByClip.delete(s),u=void 0),!u){if(p){const e=new a.PositionalAudio(this.audioListener);e.setRefDistance(10),e.setRolloffFactor(1),u=e}else u=new a.Audio(this.audioListener);this.world&&this.world.scene.add(u),this.audioByClip.set(s,u)}Math.min((t.duration-c)/t.playbackRate,(i.duration-h)/t.playbackRate);u.setLoopStart(t.clipStartOffset),u.setLoopEnd(Math.min(t.clipStartOffset+t.duration,i.duration)),u.setLoop(!0),u.setBuffer(i),this.applyAudioParameters(u,e,t,s,o,r),u.isPlaying||u.play()}catch(e){console.error(`Failed to play audio clip ${t.id}:`,e)}}stopAudioClip(e){const t=this.audioByClip.get(e);if(t){try{t.isPlaying&&t.stop()}catch(e){}t.parent&&t.parent.remove(t),this.audioByClip.delete(e)}const a=this.audioGainNodes.get(e);a&&(a.disconnect(),this.audioGainNodes.delete(e));const s=this.audioFilters.get(e);if(s){try{s.disconnect()}catch{}this.audioFilters.delete(e)}const i=this.audioPannerNodes.get(e);if(i){try{i.disconnect()}catch{}this.audioPannerNodes.delete(e)}}stopAllAudio(){for(const e of this.audioByClip.keys())this.stopAudioClip(e);this.activeAudioClips.clear(),this.audioStartInFlight.clear(),this.lastAudioStartAttemptTime.clear()}evaluateVfxTrack(e,t){if(!this.vfxService||!this.world||!e.clips||0===e.clips.length)return;if(this.shouldPreviewVfxAtSeekTime())return void this.previewVfxTrackAtSeekTime(e,t);const a=new Set,s=new Map;for(const i of e.clips){const r=this.getVfxClipKey(e,i);s.set(r,i),this.isVfxClipActiveAtTime(i,t)&&a.add(r)}const i=[];for(const t of this.activeVfxClips)t.startsWith(`${e.id}-`)&&(a.has(t)||i.push(t));for(const e of i)this.activeVfxClips.delete(e);for(const[i,r]of s.entries()){const s=this.vfxActors.get(i);a.has(i)&&!this.activeVfxClips.has(i)?(this.activeVfxClips.add(i),this.ensureVfxActor(e,r,i)):a.has(i)&&s?(this.updateVfxTransform(e,s,t),this._state.value===SequencePlaybackState.Playing&&s.play()):s&&this.applyInactiveVfxClipBehavior(r,s,t)}}getVfxClipKey(e,t){return`${e.id}-${t.id}-${t.vfxAssetId}`}isVfxClipActiveAtTime(e,t){const a=e.startTime+e.duration;return t>=e.startTime&&t<a}shouldPreviewVfxAtSeekTime(){return this._externalTimeControl&&this._inEditor&&this._state.value!==SequencePlaybackState.Playing}previewVfxTrackAtSeekTime(e,t){const a=new Set;for(const s of e.clips){const i=this.getVfxClipKey(e,s),r=this.vfxActors.get(i);this.isVfxClipActiveAtTime(s,t)&&a.add(i),t<s.startTime?r?.clearPreview():r?this.previewVfxActorAtSeekTime(e,s,r,t):this.ensureVfxActor(e,s,i)}for(const t of[...this.activeVfxClips])t.startsWith(`${e.id}-`)&&!a.has(t)&&this.activeVfxClips.delete(t);for(const e of a)this.activeVfxClips.add(e)}previewVfxActorAtSeekTime(e,t,a,s){const i=t.startTime+t.duration;this.updateVfxTransform(e,a,Math.min(s,i)),a.previewAt(s-t.startTime,t.duration,t.endBehavior,t.expireWithinSeconds)}resetVfxForTimeReset(e){const t=new Set;if(this.sequenceData)for(const a of ne(this.sequenceData.tracks))if("vfx"===a.type)for(const s of a.clips??[])this.isVfxClipActiveAtTime(s,e)&&t.add(this.getVfxClipKey(a,s));this.activeVfxClips.clear();for(const[e,a]of this.vfxActors.entries())t.has(e)||(a.restart(),a.stop(),a.pause())}applyInactiveVfxClipBehavior(e,t,a){const s=e.endBehavior??"finish";if("finish"===s)return void t.stop();if("kill"===s)return void t.applyClipEndBehavior(s);const i=e.startTime+e.duration,r=Math.max(a-i,0),n=Math.max(0,e.expireWithinSeconds??.25),o=Math.max(0,n-r);t.applyClipEndBehavior(s,o)}async ensureVfxActor(e,t,a){if(!this.vfxService||!t.vfxAssetId)return;if(this.vfxActors.has(a)){const e=this.vfxActors.get(a);return e.restart(),void e.play()}const s=this.clearCounter;try{const i=await this.vfxService.createFromAssetId(t.vfxAssetId,this.world.scene);if(s!==this.clearCounter)return void(this.world&&this.world.removeActor(i));const{position:r,rotation:n,scale:o}=this.getVfxTransform(e,t.startTime);i.object.position.copy(r),i.object.rotation.copy(n),i.object.scale.copy(o),this.vfxActors.set(a,i),this.shouldPreviewVfxAtSeekTime()?this.previewVfxActorAtSeekTime(e,t,i,this._time.value):this._state.value===SequencePlaybackState.Playing&&i.play()}catch(e){console.error(`Failed to create VFX actor for clip ${t.id}:`,e)}}getVfxTransform(e,t){const a=new c,s=new r,i=new c(1,1,1),n=e.subTracks.find(e=>"transform"===e.type);if(n&&n.keyframes.length>0){const{prev:e,next:r,prevIndex:l,nextIndex:c,t:h}=B(n.keyframes,t);if(n.components.position&&q(n.keyframes,l,c,h,a),e&&(e.rotation&&s.fromArray([...e.rotation,"XYZ"]),e.scale&&i.fromArray(e.scale)),r&&e!==r&&e.time!==r.time){const t=T(h,e.interpolation);if(e.rotation&&r.rotation){ye.setFromEuler(Ce.fromArray([...e.rotation,"XYZ"])),ve.setFromEuler(ge.fromArray([...r.rotation,"XYZ"]));const a=new o;a.slerpQuaternions(ye,ve,t),s.setFromQuaternion(a)}e.scale&&r.scale&&i.lerpVectors(he.fromArray(e.scale),ue.fromArray(r.scale),t)}}else a.fromArray(e.position),s.fromArray([...e.rotation,"XYZ"]),i.fromArray(e.scale);return{position:a,rotation:s,scale:i}}updateVfxTransform(e,t,a){const{position:s,rotation:i,scale:r}=this.getVfxTransform(e,a);t.object.position.copy(s),t.object.rotation.copy(i),t.object.scale.copy(r)}resolveActorType(e){const t=this.actorFactory.classes[e];if(null!=t)return t;const a=d[e];return a||(console.warn(`Could not resolve actor type: ${e}`),null)}async spawnActorForClip(e,t,a,s){if(!this.world||!e.actorType)return null;const i=this.resolveActorType(e.actorType);if(!i)return null;try{return await this.world.spawnActor(i,a,s)}catch(t){return console.error(`Failed to spawn actor ${e.actorType}:`,t),null}}async spawnPrefabForClip(e,t,a,s){if(!this.world||!this.assetLoader||!e.prefabId)return null;try{const t=await this.assetLoader.getPrefabById(e.prefabId);if(!t)return null;return await this.world.spawnPrefab(t,a,s)}catch(t){return console.error(`Failed to spawn prefab ${e.prefabId}:`,t),null}}async spawnMeshForClip(e,t,a,s){if(!this.world||!this.assetLoader||!e.meshId)return null;try{const t=await this.assetLoader.getAsset(e.meshId),i=await this.assetLoader.getModelByAssetId(e.meshId),r=V.clone(i.scene);if(r.position.copy(a),r.rotation.copy(s),t){await this.assetLoader.applyMaterials(t,r);const e=t.mesh?.rescale;null!=e&&1!==e&&r.scale.multiplyScalar(e)}return this.world.scene.add(r),r}catch(t){return console.error(`Failed to spawn mesh ${e.meshId}:`,t),null}}despawnInstance(e){if(this.restorePropertySnapshotsForInstance(e),this.restoreMaterialSnapshotsForInstance(e),this.world)switch(e?.type){case"actor":this.world.removeActor(e.instance);break;case"prefab":this.world.removePrefab(e.instance);break;case"mesh":this.world.scene.remove(e.instance)}}despawnAll(){for(const e of this.spawnedInstances.values())this.despawnInstance(e);this.spawnedInstances.clear(),this.activeClips.clear(),this.pendingSpawns.clear()}getInitialTransform(e,t,a){const s=new c,i=new r,n=e.subTracks.find(e=>"transform"===e.type);if(n&&n.keyframes.length>0){const{prev:e,prevIndex:t,nextIndex:r,t:o}=B(n.keyframes,a);n.components.position&&q(n.keyframes,t,r,o,s),e&&e.rotation&&i.fromArray([...e.rotation,"XYZ"])}else t.initialPosition&&s.fromArray(t.initialPosition),t.initialRotation&&i.fromArray([...t.initialRotation,"XYZ"]);return{position:s,rotation:i}}evaluateSpawnTrack(e,t,a){if(!e.clips||0===e.clips.length)return;const s=t||this.bindings.get(e.id);if(s&&s.target)for(const t of e.clips){const i=t.startTime+t.duration,r=a>=t.startTime&&a<i,n=`${e.id}-${t.id}`;if(r){this.activeClips.has(n)||(this.activeClips.add(n),this.spawnedInstances.set(n,{type:"proxy",target:s.target}));(s.target instanceof p?s.target.object:s.target)&&this.evaluateSubTracks(e.subTracks,s,a)}else this.activeClips.has(n)&&(this.clearExternalRootMotionPreview(s),this.restorePropertySnapshotsForTarget(s.target),this.restoreMaterialSnapshotsForTarget(s.target),this.activeClips.delete(n),this.spawnedInstances.delete(n))}else for(const t of e.clips){const s=t.startTime+t.duration,i=a>=t.startTime&&a<s,r=`${e.id}-${t.id}`,n=this.spawnedInstances.has(r),o=this.pendingSpawns.has(r);if(!i||n||o){if(i&&n){const t=this.spawnedInstances.get(r);t&&"proxy"!==t.type&&this.evaluateSubTracks(e.subTracks,t,a)}else if(!i&&n){const e=this.spawnedInstances.get(r);e&&(this.despawnInstance(e),this.spawnedInstances.delete(r),this.activeClips.delete(r))}}else{const{position:a,rotation:s}=this.getInitialTransform(e,t,t.startTime);this.pendingSpawns.add(r),this.spawnForClip(e,t,a,s,r)}}}getInstanceObject(e){switch(e.type){case"actor":return e.instance.object;case"prefab":return e.instance.mainActor?.object||e.instance.object;case"mesh":return e.instance;case"proxy":return e.target instanceof p?e.target.object:e.target;default:return null}}async spawnForClip(e,t,a,i,r){const n=this.clearCounter;let o=null;try{switch(e.spawnType){case"actor":const s=await this.spawnActorForClip(e,t,a,i);s&&(o={type:"actor",instance:s});break;case"prefab":const r=await this.spawnPrefabForClip(e,t,a,i);r&&(o={type:"prefab",instance:r});break;case"mesh":const n=await this.spawnMeshForClip(e,t,a,i);n&&(o={type:"mesh",instance:n})}if(n!==this.clearCounter)return void(o&&this.despawnInstance(o));const l=this._time.value,c=l>=t.startTime&&l<t.startTime+t.duration;if(o&&c){const t=this.getInstanceObject(o);"proxy"===o.type||("actor"===o.type?o.target=o.instance:"prefab"===o.type?o.target=o.instance.mainActor||o.instance.object:o.target=t);e.subTracks.some(e=>"animation"===e.type)&&t&&(o.mixer=new s(t),o.activeActions=new Map),this.spawnedInstances.set(r,o),this.activeClips.add(r)}else o&&this.despawnInstance(o)}finally{this.pendingSpawns.delete(r)}}getPlayableObject(e){return e.target instanceof p?e.target.object:e.target??null}applyResolvedPropertyValue(e,t,a){if(!t||!e.propertyPath)return;const s=this.getPropertyResolution(t,e);if(!s)return;const i=this.getPropertySnapshotKey(e);this.capturePropertySnapshot(t,i,s);const n=function(e,t){switch(t.type){case y.Number:return"number"==typeof t.value?{applied:!0,value:t.value}:{applied:!1};case y.Boolean:return"boolean"==typeof t.value?{applied:!0,value:t.value}:{applied:!1};case y.String:return"string"==typeof t.value?{applied:!0,value:t.value}:{applied:!1};case y.Vector2:return H(e,t.value);case y.Vector3:return J(e,t.value);case y.Vector4:return ee(e,t.value);case y.Euler:return function(e,t){const a=ae(t,3);if(!a)return{applied:!1};const s=Array.isArray(t)&&"string"==typeof t[3]?t[3]:"XYZ";if(e instanceof r)return e.set(a[0],a[1],a[2],s),{applied:!0,value:e};return{applied:!0,value:new r(a[0],a[1],a[2],s)}}(e,t.value);case y.Color:return te(e,t.value);default:return{applied:!1}}}(s.owner[s.key],a);n.applied&&(s.owner[s.key]=n.value)}getPropertyResolution(e,t){const a=e,s=this.getPropertySnapshotKey(t);let i=this.propertyResolutionCache.get(a);if(i||(i=new Map,this.propertyResolutionCache.set(a,i)),i.has(s))return i.get(s)??null;const r=this.getPropertyPathSegments(t.propertyPath);if(0===r.length)return i.set(s,null),null;let n=e;for(let e=0;e<r.length-1;e++){if(!z(n))return i.set(s,null),null;n=n[r[e]]}if(!z(n))return i.set(s,null),null;const o={owner:n,key:r[r.length-1]};return i.set(s,o),o}getPropertyPathSegments(e){const t=this.propertyPathSegments.get(e);if(t)return t;const a=e.split(".").map(e=>e.trim()).filter(Boolean);return this.propertyPathSegments.set(e,a),a}getPropertySnapshotKey(e){return`${e.id}:${e.propertyPath}`}capturePropertySnapshot(e,t,a){const s=e;let i=this.propertySnapshots.get(s);if(i||(i=new Map,this.propertySnapshots.set(s,i)),i.has(t))return;const r=a.owner[a.key];i.set(t,{resolution:a,hadOwnProperty:Object.prototype.hasOwnProperty.call(a.owner,a.key),value:r,valueSnapshot:ie(r)})}restorePropertySnapshotsForInstance(e){switch(e.type){case"actor":case"mesh":this.restorePropertySnapshotsForTarget(e.instance);break;case"prefab":this.restorePropertySnapshotsForTarget(e.target??null),this.restorePropertySnapshotsForTarget(e.instance.mainActor??null),this.restorePropertySnapshotsForTarget(e.instance.object);break;case"proxy":this.restorePropertySnapshotsForTarget(e.target)}}restorePropertySnapshotsForTarget(e){if(!e)return;const t=e,a=this.propertySnapshots.get(t);if(a){for(const e of a.values())re(e);this.propertySnapshots.delete(t),this.propertyResolutionCache.delete(t)}}restoreAllPropertySnapshots(){for(const e of Array.from(this.propertySnapshots.keys()))this.restorePropertySnapshotsForTarget(e)}restoreMaterialSnapshotsForInstance(e){switch(e.type){case"actor":case"mesh":this.restoreMaterialSnapshotsForTarget(e.instance);break;case"prefab":this.restoreMaterialSnapshotsForTarget(e.target??null),this.restoreMaterialSnapshotsForTarget(e.instance.mainActor??null),this.restoreMaterialSnapshotsForTarget(e.instance.object);break;case"proxy":this.restoreMaterialSnapshotsForTarget(e.target)}}restoreMaterialSnapshotsForTarget(e){if(!e)return;const t=e;this.materialResolutionCache.delete(t);const a=this.materialSnapshots.get(t);if(a){for(const e of a.values())null==e.materialIndex?e.owner.material=e.originalMaterial:Array.isArray(e.owner.material)&&(e.owner.material[e.materialIndex]=e.originalMaterial),e.controlledMaterial!==e.originalMaterial&&e.controlledMaterial.dispose();this.materialSnapshots.delete(t)}}restoreAllMaterialSnapshots(){for(const e of Array.from(this.materialSnapshots.keys()))this.restoreMaterialSnapshotsForTarget(e)}applyResolvedMaterialValue(e,t,a){if(!t)return;if("asset"===S(e)&&!e.materialAssetId)return;if("outlineVisibility"===w(e))return void this.applyResolvedMaterialOutlineVisibility(e,t,a);if(!e.uniformName)return;const s=this.getMaterialSlotResolutions(t,e);for(const i of s){const s=this.ensureSequenceControlledMaterial(t,i),r=s.uniforms?.[e.uniformName];if(!r)continue;const n=Y(r.value,a);n.applied&&(r.value=n.value,s.uniformsNeedUpdate=!0,D(s))}}applyResolvedMaterialOutlineVisibility(e,t,a){if(a.type!==y.Boolean||"boolean"!=typeof a.value)return;const s=this.getMaterialSlotResolutions(t,e);for(const e of s){const s=this.ensureSequenceControlledMaterial(t,e),i=s.userData?.outlineParameters;null!=i&&(i.visible=a.value)}}getMaterialSlotResolutions(e,t){const a=e,s=S(t),i=w(t),r=`${t.id}:${i}:${s}:${t.materialAssetId??""}:${t.uniformName}`;let n=this.materialResolutionCache.get(a);n||(n=new Map,this.materialResolutionCache.set(a,n));const o=n.get(r);if(o)return o;const l=e instanceof p?e.object:e,c=[];return l.traverse(e=>{const a=e.material;if(Array.isArray(a))for(let s=0;s<a.length;s++){const i=a[s];Z(i,t)&&c.push({owner:e,materialIndex:s,material:i,key:`${e.uuid}:${s}`})}else Z(a,t)&&c.push({owner:e,materialIndex:null,material:a,key:`${e.uuid}:material`})}),n.set(r,c),c}ensureSequenceControlledMaterial(e,t){const a=e;let s=this.materialSnapshots.get(a);s||(s=new Map,this.materialSnapshots.set(a,s));const i=s.get(t.key);if(i)return i.controlledMaterial;const r=t.material.clone();return r.userData={...t.material.userData??{}},null!=t.material.userData?.outlineParameters&&(r.userData.outlineParameters={...t.material.userData.outlineParameters}),null==t.materialIndex?t.owner.material=r:Array.isArray(t.owner.material)&&(t.owner.material[t.materialIndex]=r),s.set(t.key,{owner:t.owner,materialIndex:t.materialIndex,originalMaterial:t.material,controlledMaterial:r}),r}animationClipCacheKey(e,t){return`${e}|${t??""}`}async ensureAnimationClip(e,t){if(!this.assetLoader)return null;const a=this.animationClipCacheKey(e,t),s=this.animationClips.get(a);if(s)return s;const i=this.loadingAnimationClips.get(a);if(i)return i;const r=(async()=>{try{const s=await this.assetLoader.getAnimationClipForTargetByAssetId(e,t);return s&&this.animationClips.set(a,s),s}catch(a){return console.error(`Failed to load animation clip for asset ${e}`+(null==t?"":` and target rig ${t}`)+":",a),null}finally{this.loadingAnimationClips.get(a)===r&&this.loadingAnimationClips.delete(a)}})();return this.loadingAnimationClips.set(a,r),r}prepareAnimationPlayback(e,t,a){if(!j(a)){let e=t;return a.clipEndOffset>0&&(e=e.clone(),G(e,K(t)),e.duration=Math.max(0,e.duration-a.clipEndOffset)),a.rootMotion&&(e=O(e,a)),{clip:e,timeScale:a.playbackRate*this._timescale,startOffset:a.clipStartOffset}}return{clip:this.getPlayableAnimationClip(e,t,a,!1),timeScale:1*this._timescale,startOffset:0}}getPlayableAnimationClip(e,t,a,s){if(!j(a)){const e=a.rootMotion?O(t,a):t;return s?L.fromClip(e,!1):e}const i=`${a.id}:${s?"root":"base"}`,r=`${E(a)}|${s?"root":"base"}`,n=this.retimedAnimationClips.get(i);if(n&&n.assetId===e&&n.signature===r)return n.clip;const o=F(t,a),l=a.rootMotion?O(o,a):o,c=s?L.fromClip(l,!1):l;return this.retimedAnimationClips.set(i,{assetId:e,signature:r,clip:c}),c}getAnimationPlaybackLocalTime(e,t){const a=Math.max(0,t-e.startTime);return j(e)?a:a*e.playbackRate+e.clipStartOffset}clearRetimedAnimationClipCache(e){if(null!=e)for(const[t,a]of this.retimedAnimationClips.entries())a.assetId===e&&this.retimedAnimationClips.delete(t);else this.retimedAnimationClips.clear()}captureOriginalTransforms(){for(const e of this.bindings.values()){const t=e.target instanceof p?e.target.object:e.target;t&&(e.originalTransform={position:t.position.clone(),rotation:t.rotation.clone(),scale:t.scale.clone()})}}restoreOriginalTransforms(){for(const e of this.bindings.values())if(e.originalTransform){const t=e.target instanceof p?e.target.object:e.target;t&&(t.position.copy(e.originalTransform.position),t.rotation.copy(e.originalTransform.rotation),t.scale.copy(e.originalTransform.scale))}}stopAllAnimations(){for(const e of this.bindings.values()){for(const t of e.activeActions.values())t.stop();e.activeActions.clear(),e.mixer&&e.mixer.stopAllAction(),e.charAnimComponent&&(e.charAnimComponent.stopSequenceAnimation(),e.charAnimComponent=void 0),e.charAnimActionKeys?.clear()}}stopAllVfx(){for(const e of this.vfxActors.values())e.paused||e.stop();this.activeVfxClips.clear()}dispose(){if(this.stop(),this.clearLocatorBindings(),this.clearSequenceCameras(),this.bindings.clear(),this.roleBindings.clear(),this.sequenceData=null,this.world)for(const e of this.vfxActors.values())this.world.removeActor(e);this.vfxActors.clear(),this.stopAllAudio(),this.audioBuffers.clear(),this.loadingAudioBuffers.clear(),this.animationClips.clear(),this.loadingAnimationClips.clear(),this.clearRetimedAnimationClipCache(),this.audioByClip.clear()}updateTrackParenting(e,t){const a=this.getActiveObjectsForTrack(e);if(0===a.length)return;let s=null;const i=e.parent?.trackId;if(i){const t=this.sequenceData?ne(this.sequenceData.tracks).find(e=>e.id===i):void 0;if(t){const a=this.getActiveObjectsForTrack(t);if(a.length>0&&(s=a[0],e.parent?.socketName)){const t=this.findSocket(s,e.parent.socketName);t&&(s=t)}}}if(!s&&"camera"===e.type&&e.parentRole&&this.roleBindings.has(e.parentRole)){const t=this.roleBindings.get(e.parentRole);if(s=t instanceof p?t.object:t,e.parentRoleSocketName){const t=this.findSocket(s,e.parentRoleSocketName);t&&(s=t)}}for(const i of a)s?i.parent!==s&&(s.add(i),!t||"object"!==e.type&&"locator"!==e.type||(t.currentParent=s)):t?.currentParent&&t.currentParent===i.parent?this.restoreObjectParent(t,i):i.parent&&i.parent!==this.world?.scene&&"object"!==e.type&&"locator"!==e.type&&this.world?.scene.add(i)}findSocket(e,t){if(e.name===t)return e;if(e instanceof a.SkinnedMesh){const a=e.skeleton.bones.find(e=>e.name===t);if(a)return a}return e.getObjectByName(t)||null}getActiveObjectsForTrack(e){if("object"===e.type){const t=this.bindings.get(e.id);if(t&&t.target)return[t.target instanceof p?t.target.object:t.target]}else if("locator"===e.type){const t=this.bindings.get(e.id);if(t&&t.target instanceof n)return[t.target]}else{if("camera"===e.type)return[this.ensureSequenceCamera(e)];if("spawn"===e.type){const t=[];for(const[a,s]of this.spawnedInstances)if(a.startsWith(e.id+"-")&&this.activeClips.has(a)){const e=this.getInstanceObject(s);e&&t.push(e)}return t}if("vfx"===e.type){const t=[];for(const a of this.activeVfxClips)if(a.startsWith(e.id+"-")){const e=this.vfxActors.get(a);e&&t.push(e.object)}return t}}return[]}restoreObjectParent(e,t){e.originalParent?e.originalParent.add(t):this.world&&this.world.scene.add(t),e.currentParent=void 0}restoreOriginalParents(){for(const e of this.bindings.values())if(e.currentParent){const t=e.target instanceof p?e.target.object:e.target;t&&this.restoreObjectParent(e,t)}}evaluateAudioSubTracks(e,t){const a={};for(const s of e.subTracks)if("audioParameter"===s.type){const e=s,i=A(e.parameter),r=M(e.keyframes,t,{min:i.min,max:i.max});void 0!==r&&(a[e.parameter]=r)}return a}stringToRandom(e){let t=0;for(let a=0;a<e.length;a++){t=(t<<5)-t+e.charCodeAt(a),t&=t}const a=1e4*Math.sin(t);return a-Math.floor(a)}async refreshAsset(e){let t=!1;this.assetLoader?.clearCacheById(e),this.animationClips.delete(e),this.loadingAnimationClips.delete(e),this.clearRetimedAnimationClipCache(e),this.vfxService?.clearPool(e),t=this.refreshVfxActorsForAssetIds(new Set([e]))||t;for(const[a,s]of this.activePostProcessClips.entries())s.assetId===e&&(this.releasePostProcessClipEffect(a),t=!0);t=this.refreshSpawnedInstancesForClipKeys(this.getSpawnClipKeysForAsset(e))||t;const a=await this.getAssetOrNull(e);return"shaderGraph"===a?.type&&(t=await this.refreshShaderGraphDependentAssets(e)||t),t}refreshVfxActorsForAssetIds(e){let t=!1;for(const[a,s]of this.vfxActors.entries())this.vfxClipKeyUsesAnyAsset(a,e)&&(this.world&&this.world.removeActor(s),this.vfxActors.delete(a),this.activeVfxClips.delete(a),t=!0);return t}vfxClipKeyUsesAnyAsset(e,t){for(const a of t)if(e.endsWith(`-${a}`))return!0;return!1}refreshSpawnedInstancesForClipKeys(e){let t=!1;for(const[a,s]of this.spawnedInstances.entries())e.has(a)&&(this.despawnInstance(s),this.spawnedInstances.delete(a),this.activeClips.delete(a),t=!0);return t}getSpawnClipKeysForAsset(e){const t=new Set;if(!this.sequenceData)return t;for(const a of ne(this.sequenceData.tracks))if("spawn"===a.type&&(a.prefabId===e||a.meshId===e))for(const e of a.clips)t.add(`${a.id}-${e.id}`);return t}async refreshShaderGraphDependentAssets(e){const t=await this.findSequenceVfxAssetIdsUsingShaderGraph(e);for(const e of t)this.vfxService?.clearPool(e);const a=this.refreshVfxActorsForAssetIds(t),s=this.refreshSpawnedInstancesForClipKeys(await this.findSpawnClipKeysUsingShaderGraph(e));return a||s}async findSequenceVfxAssetIdsUsingShaderGraph(e){const t=new Set;if(!this.sequenceData)return t;const a=new Map;for(const s of ne(this.sequenceData.tracks))if("vfx"===s.type)for(const i of s.clips)null==i.vfxAssetId||t.has(i.vfxAssetId)||await this.assetUsesShaderGraph(i.vfxAssetId,e,a)&&t.add(i.vfxAssetId);return t}async findSpawnClipKeysUsingShaderGraph(e){const t=new Set;if(!this.sequenceData)return t;const a=new Map;for(const s of ne(this.sequenceData.tracks))if("spawn"===s.type&&await this.spawnTrackUsesShaderGraph(s,e,a))for(const e of s.clips)t.add(`${s.id}-${e.id}`);return t}async spawnTrackUsesShaderGraph(e,t,a){if(null!=e.meshId&&await this.assetUsesShaderGraph(e.meshId,t,a))return!0;if(null!=e.prefabId&&await this.assetUsesShaderGraph(e.prefabId,t,a))return!0;for(const s of e.subTracks??[])if("material"===s.type&&null!=s.materialAssetId&&await this.assetUsesShaderGraph(s.materialAssetId,t,a))return!0;return!1}assetUsesShaderGraph(e,t,a,s=new Set){if(e===t)return Promise.resolve(!0);if(s.has(e))return Promise.resolve(!1);if(a.has(e))return a.get(e);const i=this.assetUsesShaderGraphUncached(e,t,a,s);return a.set(e,i),i}async assetUsesShaderGraphUncached(e,t,a,s){if(s.has(e))return!1;const i=await this.getAssetOrNull(e);if(null==i)return!1;const r=new Set(s);return r.add(e),!!this.materialAssetUsesShaderGraph(i,t)||("mesh"===i.type?this.materialAssignmentsUseShaderGraph(i.materialAssignments,t,a,r):"prefab"===i.type?this.sceneObjectsUseShaderGraph(i.prefab?.objects,t,a,r):"vfx"===i.type&&this.vfxAssetUsesShaderGraph(i,t,a,r))}materialAssetUsesShaderGraph(e,t){return"shaderGraph"===e.type?e.id===t:"asset"===e.material?.shaderGraph?.source&&e.material.shaderGraph.assetId===t}async materialAssignmentsUseShaderGraph(e,t,a,s){for(const i of e??[])if(null!=i.materialId&&"null"!==i.materialId&&await this.assetUsesShaderGraph(i.materialId,t,a,s))return!0;return!1}async sceneObjectsUseShaderGraph(e,t,a,s){for(const i of e??[]){if(await this.materialAssignmentsUseShaderGraph(i.materialAssignments,t,a,s))return!0;if(null!=i.assetId&&("asset_mesh"===i.type||"prefab"===i.type||"vfx"===i.type)&&await this.assetUsesShaderGraph(i.assetId,t,a,s))return!0;if(await this.sceneObjectsUseShaderGraph(i.children,t,a,s))return!0}return!1}async vfxAssetUsesShaderGraph(e,t,a,s){for(const i of e.vfx?.emitters??[])if(await this.emitterUsesShaderGraph(i,t,a,s))return!0;return!1}async emitterUsesShaderGraph(e,t,a,s){if(await this.emitterOutputUsesShaderGraph(e.output,t,a,s))return!0;for(const i of e.children??[])if(await this.emitterUsesShaderGraph(i,t,a,s))return!0;return!1}async emitterOutputUsesShaderGraph(e,t,a,s){const i=e.materialSource??("asset"===e.shaderGraph?.source?"shaderGraph":void 0);return"shaderGraph"===i&&"asset"===e.shaderGraph?.source&&e.shaderGraph.assetId===t||!("material"!==i||!("material"in e)||null==e.material||!await this.assetUsesShaderGraph(e.material,t,a,s))}async getAssetOrNull(e){if(!this.assetLoader)return null;try{return await this.assetLoader.getAsset(e)??null}catch{return null}}async invokeSequenceEvent(e,t,a,s){let i=!1;for(let e=0;e<s.length;e++)if(v(s[e])){i=!0;break}if(i)try{const t=new Array(s.length);for(let e=0;e<s.length;e++)t[e]=C(s[e],this.sequenceEventAsyncResolvers);const i=await Promise.all(t);await a.call(e,...i)}catch(e){console.error(`Failed to call sequence event ${t}:`,e)}else try{const t=new Array(s.length);for(let e=0;e<s.length;e++)t[e]=g(s[e],this.sequenceEventSyncResolvers);a.call(e,...t)}catch(e){console.error(`Failed to call sequence event ${t}:`,e)}}resolveSequenceEventActorReference(e){if(!this.world||null==e)return null;const t=e,a="object"==typeof t&&null!=t?.id?t.id:"string"==typeof t?t:null;if(null==a)return null;for(const e of this.world.actors){const t=e.object.userData.src??e.object.userData._src;if(t?.id===a)return e}return null}resolveSequenceEventSequence(e){return b(e)?new P(e):this.assetLoader&&"string"==typeof e?this.assetLoader.getSequenceById(e):null}async resolveSequenceEventAnimationClip(e){const t="string"==typeof e?e:"object"==typeof e&&null!=e?e.assetId??null:null;return null!=t&&this.assetLoader?this.assetLoader.getAnimationClipByAssetId(t):null}}function Q(e){return e.options?.length>0||e.propertyType===y.Boolean||e.propertyType===y.String}function X(e){return"outlineVisibility"===w(e)||e.valueType===y.Boolean||e.valueType===y.String}function z(e){return"object"==typeof e&&null!=e||"function"==typeof e}function Y(e,t){switch(t.type){case y.Number:return function(e){if("number"==typeof e)return Number.isFinite(e)?{applied:!0,value:e}:{applied:!1};if("string"==typeof e){const t=parseFloat(e);return Number.isFinite(t)?{applied:!0,value:t}:{applied:!1}}return{applied:!1}}(t.value);case y.Boolean:return"boolean"==typeof t.value?{applied:!0,value:t.value}:{applied:!1};case y.Vector2:return H(e,t.value);case y.Vector3:return J(e,t.value);case y.Vector4:return ee(e,t.value);case y.Color:return function(e,t){if(e instanceof c){const a=Ae.set(0);return se(a,t)?(e.set(a.r,a.g,a.b),{applied:!0,value:e}):{applied:!1}}if(e instanceof h){const a=Ae.set(0);return se(a,t)?(e.set(a.r,a.g,a.b,e.w),{applied:!0,value:e}):{applied:!1}}return te(e,t)}(e,t.value);default:return{applied:!1}}}function Z(e,t){const s=S(t);return!!function(e){return e instanceof a.Material||!0===e?.isMaterial}(e)&&(("asset"!==s||e.userData?.assetId===t.materialAssetId)&&("outlineVisibility"===w(t)?null!=e.userData?.outlineParameters:null!=e.uniforms?.[t.uniformName]))}function H(e,t){const a=ae(t,2);return a?e instanceof l?(e.fromArray(a),{applied:!0,value:e}):{applied:!0,value:new l(a[0],a[1])}:{applied:!1}}function J(e,t){const a=ae(t,3);return a?e instanceof c?(e.fromArray(a),{applied:!0,value:e}):{applied:!0,value:new c(a[0],a[1],a[2])}:{applied:!1}}function ee(e,t){const a=ae(t,4);return a?e instanceof h?(e.fromArray(a),{applied:!0,value:e}):{applied:!0,value:new h(a[0],a[1],a[2],a[3])}:{applied:!1}}function te(e,t){if(e instanceof i)return se(e,t)?{applied:!0,value:e}:{applied:!1};const a=new i;return se(a,t)?{applied:!0,value:a}:{applied:!1}}function ae(e,t){if(!Array.isArray(e)||e.length<t)return null;const a=new Array(t);for(let s=0;s<t;s++){if("number"!=typeof e[s])return null;a[s]=e[s]}return a}function se(e,t){return t instanceof i||"string"==typeof t||"number"==typeof t?(e.set(t),!0):!!(Array.isArray(t)&&t.length>=3)&&(e.setRGB("number"==typeof t[0]?t[0]:0,"number"==typeof t[1]?t[1]:0,"number"==typeof t[2]?t[2]:0),!0)}function ie(e){if(e instanceof l||e instanceof c||e instanceof h||e instanceof i||e instanceof r)return e.clone()}function re(e){const{owner:t,key:a}=e.resolution;e.hadOwnProperty?(!function(e,t){if(e instanceof l&&t instanceof l)return e.copy(t),!0;if(e instanceof c&&t instanceof c)return e.copy(t),!0;if(e instanceof h&&t instanceof h)return e.copy(t),!0;if(e instanceof i&&t instanceof i)return e.copy(t),!0;if(e instanceof r&&t instanceof r)return e.copy(t),!0}(e.value,e.valueSnapshot),t[a]=e.value):delete t[a]}function ne(e){const t=[];for(const a of e)t.push(a),"group"===a.type&&t.push(...ne(a.childTracks));return t}function oe(e){if("string"!=typeof e)return null;const t=e.trim();return t.length>0?t:null}function le(e){const t=new a.Group;t.name=`SequenceLocatorMarker:${e}`,t.renderOrder=1e3;const s=new a.AxesHelper(.35);s.renderOrder=1e3;const i=Array.isArray(s.material)?s.material:[s.material];for(const e of i)e.depthTest=!1,e.transparent=!0,e.opacity=.9,e.toneMapped=!1;t.add(s);const r=function(e){if("undefined"==typeof document)return null;const t=document.createElement("canvas");t.width=256,t.height=64;const s=t.getContext("2d");if(!s)return null;s.clearRect(0,0,t.width,t.height),s.fillStyle="rgba(16, 18, 24, 0.78)",function(e,t,a,s,i,r){const n=t+s,o=a+i;e.beginPath(),e.moveTo(t+r,a),e.lineTo(n-r,a),e.quadraticCurveTo(n,a,n,a+r),e.lineTo(n,o-r),e.quadraticCurveTo(n,o,n-r,o),e.lineTo(t+r,o),e.quadraticCurveTo(t,o,t,o-r),e.lineTo(t,a+r),e.quadraticCurveTo(t,a,t+r,a),e.closePath()}(s,0,8,t.width,48,8),s.fill(),s.font="24px sans-serif",s.textAlign="center",s.textBaseline="middle",s.fillStyle="#f8fafc",s.fillText(e||"Locator",t.width/2,t.height/2);const i=new a.CanvasTexture(t);i.needsUpdate=!0;const r=new a.SpriteMaterial({map:i,transparent:!0,depthTest:!1});r.toneMapped=!1;const n=new a.Sprite(r);return n.scale.set(.9,.225,1),n}(e);return r&&(r.position.set(0,.45,0),r.renderOrder=1001,t.add(r)),t.traverse(e=>{e.raycast=()=>{}}),t}function ce(e){e.traverse(e=>{const t=e.material;if(Array.isArray(t))for(const e of t)e?.dispose?.(),e?.map?.dispose?.();else t?.dispose?.(),t?.map?.dispose?.()})}const he=new c,ue=new c,pe=new c,de=new c,fe=new c,me=new c,ye=new o,ve=new o,Ce=new r,ge=new r,Ae=new i;/*
|
|
2
2
|
* Copyright (©) 2026 Hology Interactive AB. All rights reserved.
|
|
3
3
|
* See the LICENSE.md file for details.
|
|
4
4
|
*/
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
import { Constructable } from 'typedi';
|
|
2
2
|
import { BaseActor } from './actor.js';
|
|
3
3
|
export { getComponentClassById, getComponentClassId, getRegisteredComponentClasses, } from './type-registry.js';
|
|
4
|
+
export type ActorComponentParams<T extends ActorComponent> = {
|
|
5
|
+
[K in Exclude<keyof T, keyof ActorComponent> as T[K] extends (...args: any[]) => any ? never : K]: T[K];
|
|
6
|
+
};
|
|
7
|
+
type ActorComponentParamKey<T extends ActorComponent> = Extract<keyof ActorComponentParams<T>, string>;
|
|
8
|
+
export type ActorComponentParamSet<T extends ActorComponent> = Set<ActorComponentParamKey<T>>;
|
|
4
9
|
export declare abstract class ActorComponent<ActorType extends BaseActor = BaseActor> {
|
|
5
10
|
actor: ActorType;
|
|
6
11
|
constructor();
|
|
@@ -12,7 +17,7 @@ export declare abstract class ActorComponent<ActorType extends BaseActor = BaseA
|
|
|
12
17
|
* actor. Return true only when every supplied change was applied. Returning
|
|
13
18
|
* false means unsupported and must leave the component unchanged.
|
|
14
19
|
*/
|
|
15
|
-
applySceneParameters(parameters:
|
|
20
|
+
applySceneParameters(parameters: ActorComponentParams<ActorComponent>, changedParameters: ActorComponentParamSet<ActorComponent>): boolean | Promise<boolean>;
|
|
16
21
|
/**
|
|
17
22
|
* Code that has to run before every rendered frame. This will run after the
|
|
18
23
|
* actor's onInit method has run.
|
package/dist/gameplay/index.d.ts
CHANGED
|
@@ -5,7 +5,7 @@ export * from './inject.js';
|
|
|
5
5
|
export { Service, Inject } from 'typedi';
|
|
6
6
|
export { ActorFactory } from './actors/factory.js';
|
|
7
7
|
export { Actor, BaseActor, getActorClassById, getActorClassId, getRegisteredActorClasses } from './actors/actor.js';
|
|
8
|
-
export { Component, ActorComponent, type ComponentOptions, attach, Attach, getComponentClassById, getComponentClassId, getRegisteredComponentClasses } from './actors/component.js';
|
|
8
|
+
export { Component, ActorComponent, type ComponentOptions, type ActorComponentParams, type ActorComponentParamSet, attach, Attach, getComponentClassById, getComponentClassId, getRegisteredComponentClasses, } from './actors/component.js';
|
|
9
9
|
export * from './services/world.js';
|
|
10
10
|
export * from './services/game-time-scheduler.js';
|
|
11
11
|
export * from './services/camera-shake.js';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import*as e from"three";import{NodeMaterialWebGpuResolver as t}from"./node-material-webgpu-resolver.js";import{float as n,varyingTransformed as i,vec4 as r}from"three-shader-graph";import{NodeShaderMaterial as o}from"../shader-nodes/index.js";import{sceneMapUniformName as s}from"../shader-nodes/scene-sample.js";export class ExperimentalWebGpuBackend{constructor(e,t,n,i,r,o,s,a,l,d,c,u,h,p,m,g){this.renderer=e,this.fallbackMaterial=t,this.nodeMaterialResolver=n,this.gBufferFallbackSource=i,this.bloom=r,this.fxaa=o,this.smaa=s,this.gtao=a,this.ssr=l,this.taa=d,this.volumetricFog=c,this.colorGrading=u,this.depthOfField=h,this.outline=p,this.postProcessEffects=m,this.pmremGenerator=null,this.pmremResults=new WeakMap,this.ownedPmremResults=new Set,this.warnedUnsupportedPostProcessStages=new Set,this.canvas=g}static async create(d={}){const c=await import("@hology/webgpu-renderer"),u=document.createElement("canvas");u.dataset.hologyRenderer="webgpu-experimental";const h=new c.WGSLShaderMaterial({vertexShader:a,fragmentShader:l});h.side=c.DoubleSide;const p=new t(c,(e,t)=>"opaque"===t?[e.outputColor.xyz.rgba(e.alphaTest),r((e.outputNormal??i.normal).multiplyScalar(.5).addScalar(.5),e.outputRoughness??n(1))]:void 0),m=new e.MeshStandardMaterial({color:8688803,roughness:1});if(null==p.resolve(m,"opaque"))throw h.dispose(),m.dispose(),new Error("Failed to compile the WebGPU G-buffer fallback material.");const g=!1===d.gtao?null:new c.GTAOEffect({normalSpace:"view",resolutionScale:.5,...d.gtao??{}}),f=!1===d.ssr||null==d.ssr?null:new c.SSREffect({normalSpace:"view",resolutionScale:.5,...d.ssr??{}}),P=!1===d.bloom?null:new c.BloomEffect({threshold:1,strength:.9,radius:.2,...d.bloom??{}}),S=!1===d.fxaa||null==d.fxaa?null:new c.FXAAEffect(d.fxaa),x=!1===d.smaa||null==d.smaa?null:new c.SMAAEffect(d.smaa),w=!1===d.taa||null!=d.smaa&&!1!==d.smaa&&null==d.taa?null:new c.TemporalAAEffect({renderScale:.9,...d.taa??{}}),b=d.volumetricFog||void 0,v=!1===d.volumetricFog?null:new c.VolumetricFogEffect(void 0,{froxelPixelSize:8,maxDistance:64,depthSlices:64,integrationSubsteps:2,temporalJitter:!0,spatialJitter:!0,scatteringIntensity:Math.PI,...b,blur:!1!==b?.blur&&{depthAwareUpsample:!0,...b?.blur}}),C=!1===d.colorGrading?null:new c.ColorGradingEffect({enabled:!1,...d.colorGrading??{}}),L=!1===d.depthOfField?null:new c.DepthOfFieldEffect({enabled:!1,...d.depthOfField??{}}),y=!1===d.outline?null:new c.OutlineEffect({enabled:!1,...d.outline??{}}),F=[],M=new WeakMap,G=new Set,O=(e,t,n)=>{let i=n;const r=F.filter(e=>e.enabled&&e.stage===t).sort((e,t)=>e.priority-t.priority||e.id-t.id);for(const t of r){if(!(t.material instanceof o)){const e=`${t.id}:material`;G.has(e)||(G.add(e),console.warn(`[Hology WebGPU experiment] Skipping custom post-process effect ${t.id}: only NodeShaderMaterial effects are supported.`));continue}try{let n=M.get(t.material);null!=n&&n.version===t.material.version||(n={version:t.material.version,shader:p.compileFullscreen(t.material)},M.set(t.material,n));const r=e.createColorTarget(`hologyCustomPostProcess${t.id}`);e.addNodeFullscreenPass({name:`HologyCustomPostProcess${t.id}`,shader:n.shader,inputOverrides:{[s]:i},outputs:r}),i=r}catch(e){const n=`${t.id}:compile:${t.material.version}`;G.has(n)||(G.add(n),console.warn(`[Hology WebGPU experiment] Skipping custom post-process effect ${t.id}: ${e instanceof Error?e.message:String(e)}`,e))}}return i},R=new c.WebGpuRenderer({canvas:u,fallbackMaterial:h,materialResolver:(e,t)=>p.resolve(e,t),invokeObjectRenderCallbacks:!1,hiZOcclusionCulling:!0,renderGraphProfiling:!1,sampleCount:1,multiDrawIndirect:!1});R.setRenderScale(w?.renderScale??1),R.setRenderGraphBuilder((e,t)=>{const n=new c.FrameGraphBuilder(t),i=n.createColorTarget("hologyNormalRoughness",{format:"rgba16float"});n.addDirectionalShadowPass(),n.addPointShadowPass(),n.addSpotShadowPass(),n.addDepthPrepass(),n.addHiZPasses(),n.addVisibilityPass(),n.addMaterialPass({name:"OpaqueGBufferPass",outputs:[n.sceneColor,i],drawStage:"opaque",loadDepth:!0}),n.addHiZHistoryPass("OpaqueGBufferPass");let r=n.sceneColor;if(null!=g){const e=g.addPasses(n,{depth:n.mainDepth,normal:i});r=g.addCompositePass(n,r,e)}null!=f&&(r=f.addPasses(n,{sceneColor:r,depth:n.mainDepth,normalRoughness:i})),n.addSceneTextureCopyPass(r),n.addLatePass(r),r=O(n,"beforeFog",r),null!=v&&(r=v.addPasses(n,{sceneColor:r,depth:n.mainDepth,volumeObjects:t.fogVolumeObjects})),null!=P&&(r=P.addPass(n,r)),r=O(n,"beforeOutline",r),null!=y&&(r=y.addPass(n,r)),r=O(n,"beforeDepthOfField",r),null!=L&&(r=L.addPass(n,r,n.mainDepth)),r=O(n,"beforeColorAdjustment",r),null!=C&&(r=C.addPass(n,r)),r=O(n,"beforeAntiAliasing",r);let o=w?.addPass(n,r,n.mainDepth)??r;null!=x?o=x.addPass(n,o):null!=S&&(o=S.addPass(n,o)),o=O(n,"beforeOutput",o),n.present(o)});try{return await R.initialize(),new ExperimentalWebGpuBackend(R,h,p,m,P,S,x,g,f,w,v,C,L,y,F,u)}catch(e){throw R.destroy(),h.dispose(),p.dispose(),m.dispose(),g?.dispose(),x?.dispose(),v?.dispose(),y?.dispose(),e}}static supportsCamera(t){return t instanceof e.PerspectiveCamera||t instanceof e.OrthographicCamera}setSize(e,t,n){this.renderer.setSize(e,t,n)}initTexture(e){this.renderer.initTexture(e)}setPostProcessEffects(e){this.postProcessEffects.splice(0,this.postProcessEffects.length,...e);for(const t of e){if("beforeLut"!==t.stage)continue;const e=`${t.id}:${t.stage}`;this.warnedUnsupportedPostProcessStages.has(e)||(this.warnedUnsupportedPostProcessStages.add(e),console.warn(`[Hology WebGPU experiment] Skipping custom post-process effect ${t.id}: stage "${t.stage}" has no native WebGPU anchor.`))}}setEnableOutlines(e){null!=this.outline&&(this.outline.enabled=e)}setDynamicBatchingEnabled(e){this.renderer.setDynamicBatchingEnabled(e)}setSelectedObjects(e){this.outline?.setSelectedObjects(e)}setSelectedObjectInstances(e){this.outline?.setSelectedInstances(e)}setCascadedShadowRanges(e,t=[]){this.renderer.setCascadedShadowRanges(e,t),this.volumetricFog?.setCascadedDirectionalLights(t)}setWorldEnvironment(t){if(null==t)return void this.nodeMaterialResolver.setWorldEnvironment(null);let n=t.source;if(n.mapping!==e.CubeUVReflectionMapping){let e=this.pmremResults.get(n);null==e&&(this.pmremGenerator??(this.pmremGenerator=this.renderer.createPMREMGenerator()),e=this.pmremGenerator.fromEquirectangular(n),this.pmremResults.set(n,e),this.ownedPmremResults.add(e)),n=e.texture}this.nodeMaterialResolver.setWorldEnvironment({texture:n,intensity:t.intensity})}resetViewHistory(){this.renderer.resetViewHistory(),this.taa?.reset()}async compile(e,t){await this.renderer.compileAsync(e,t)}createStaticDrawSet(e,t){this.renderer.setHiZOcclusionCullingEnabled(!0);const n=this.renderer.createStaticDrawSet(e,{label:t,onUnsupported:"skip"});return 0===n.drawCount?(n.dispose(),null):n}render(e,t,n){this.volumetricFog?.setScene(e),this.taa?.prepareCamera(t,this.canvas.width,this.canvas.height);try{this.renderer.render(e,t,n)}finally{this.taa?.finishCamera(t)}}getLastFrameProfile(){return this.renderer.getLastFrameProfile()}setPostProcessState(e){null!=this.colorGrading&&(Object.assign(this.colorGrading.options,e??{enabled:!1}),this.colorGrading.options.enabled=!0===e?.enabled),null!=this.depthOfField&&(this.depthOfField.options.enabled=null!=e?.depthFocus||null!=e?.depthAperture||null!=e?.depthMaxBlur,this.depthOfField.options.focus=e?.depthFocus,this.depthOfField.options.aperture=e?.depthAperture,this.depthOfField.options.maxBlur=e?.depthMaxBlur)}setProfilingEnabled(e){this.renderer.setRenderGraphProfilingEnabled(e)}resetTemporalHistory(){this.taa?.reset()}inspect(e,t){return inspectWebGpuScene(e,t,this.nodeMaterialResolver)}destroy(){this.nodeMaterialResolver.dispose(),this.gBufferFallbackSource.dispose(),this.gtao?.dispose(),this.smaa?.dispose(),this.volumetricFog?.dispose();for(const e of this.ownedPmremResults)e.dispose();this.ownedPmremResults.clear(),this.renderer.destroy(),this.fallbackMaterial.dispose()}}export function inspectWebGpuScene(e,t,n){const i={meshes:0,skinnedMeshes:0,instancedMeshes:0,batchedMeshes:0,sprites:0,points:0,lines:0,missingPositionGeometry:0,transparentMaterials:0,shaderMaterialsReplaced:0,materialsReplaced:0,unsupportedCamera:ExperimentalWebGpuBackend.supportsCamera(t)?0:1};return e.traverse(e=>{if(e.isSprite)return void i.sprites++;if(e.isPoints)return void i.points++;if(e.isLine)return void i.lines++;if(!e.isMesh)return;const t=e;t.isBatchedMesh?i.batchedMeshes++:t.isInstancedMesh?i.instancedMeshes++:t.isSkinnedMesh?i.skinnedMeshes++:i.meshes++,null==t.geometry?.getAttribute("position")&&i.missingPositionGeometry++;const r=Array.isArray(t.material)?t.material:[t.material];for(const e of r){if(null==e)continue;e.transparent&&i.transparentMaterials++;const t=!0===e.isWGSLShaderMaterial||!0===e.isLineMaterial,r=!t&&!0===n?.canResolve(e);t||r||(i.materialsReplaced++,e.isShaderMaterial&&i.shaderMaterialsReplaced++)}}),i}export function formatWebGpuSceneCapabilitySummary(e){return`[Hology WebGPU experiment] ${JSON.stringify(e)}`}const a="\nstruct VertexInput {\n @location(0) position: vec3<f32>,\n @location(1) normal: vec3<f32>,\n @location(2) uv: vec2<f32>,\n @location(3) color: vec4<f32>,\n#ifdef USE_SKINNING\n @location(4) skinIndex: vec4<u32>,\n @location(5) skinWeight: vec4<f32>,\n#endif\n @builtin(instance_index) instanceIndex: u32,\n};\n\nstruct VertexOutput {\n @builtin(position) position: vec4<f32>,\n @location(0) worldPosition: vec3<f32>,\n @location(1) worldNormal: vec3<f32>,\n @location(2) color: vec4<f32>,\n};\n\n@vertex\nfn vsMain(input: VertexInput) -> VertexOutput {\n var output: VertexOutput;\n#ifdef USE_SKINNING\n let localPosition = rendererSkinPosition(input.position, input.skinIndex, input.skinWeight);\n let localNormal = rendererSkinNormal(input.normal, input.skinIndex, input.skinWeight);\n#else\n let localPosition = input.position;\n let localNormal = input.normal;\n#endif\n let world = rendererWorldPosition(localPosition, input.instanceIndex);\n output.position = rendererClipPosition(localPosition, input.instanceIndex);\n output.worldPosition = world.xyz;\n output.worldNormal = rendererWorldNormal(localNormal, input.instanceIndex);\n output.color = input.color * rendererObjectColor(input.instanceIndex);\n return output;\n}\n",l="\nstruct VertexOutput {\n @builtin(position) position: vec4<f32>,\n @location(0) worldPosition: vec3<f32>,\n @location(1) worldNormal: vec3<f32>,\n @location(2) color: vec4<f32>,\n};\n\nfn distanceAttenuation(distanceToLight: f32, range: f32) -> f32 {\n let linear = max(0.0, 1.0 - distanceToLight / max(range, 0.001));\n return linear * linear;\n}\n\n@fragment\nfn fsMain(input: VertexOutput) -> @location(0) vec4<f32> {\n let normal = normalize(input.worldNormal);\n let normalTint = normal * 0.5 + vec3<f32>(0.5);\n let base = mix(vec3<f32>(0.52, 0.58, 0.64), normalTint, 0.22) * input.color.rgb;\n var lighting = rendererIndirectDiffuse(normal) + vec3<f32>(0.08);\n var directionalLighting = vec3<f32>(0.0);\n let directionalCount = rendererDirectionalLightCount();\n\n for (var index: u32 = 0u; index < directionalCount; index = index + 1u) {\n let lightDirection = rendererDirectionalLightDirectionForLight(index);\n let shadow = rendererSampleDirectionalShadowForLightWithNormal(index, input.worldPosition, normal);\n directionalLighting += rendererDirectionalLightColorForLight(index) * max(dot(normal, lightDirection), 0.0) * shadow;\n }\n if (directionalCount > 0u) {\n lighting += directionalLighting / f32(directionalCount);\n }\n\n for (var index: u32 = 0u; index < rendererPointLightCount(); index = index + 1u) {\n let lightVector = rendererPointLightPositionForLight(index) - input.worldPosition;\n let distanceToLight = length(lightVector);\n let lightDirection = normalize(lightVector);\n let shadow = rendererSamplePointShadowForLightWithNormal(index, input.worldPosition, normal);\n lighting += rendererPointLightColorForLight(index) * max(dot(normal, lightDirection), 0.0) * distanceAttenuation(distanceToLight, rendererPointLightRangeForLight(index)) * shadow;\n }\n\n for (var index: u32 = 0u; index < rendererSpotLightCount(); index = index + 1u) {\n let lightVector = rendererSpotLightPositionForLight(index) - input.worldPosition;\n let distanceToLight = length(lightVector);\n let lightDirection = normalize(lightVector);\n let angleCos = dot(-lightDirection, rendererSpotLightDirectionForLight(index));\n let cone = smoothstep(rendererSpotLightConeCosForLight(index), rendererSpotLightPenumbraCosForLight(index), angleCos);\n let shadow = rendererSampleSpotShadowForLightWithNormal(index, input.worldPosition, normal);\n lighting += rendererSpotLightColorForLight(index) * max(dot(normal, lightDirection), 0.0) * cone * distanceAttenuation(distanceToLight, rendererSpotLightRangeForLight(index)) * shadow;\n }\n\n return vec4<f32>(base * max(lighting, vec3<f32>(0.08)), input.color.a);\n}\n";/*
|
|
1
|
+
import*as e from"three";import{NodeMaterialWebGpuResolver as t}from"./node-material-webgpu-resolver.js";import{float as n,varyingTransformed as i,vec4 as r}from"three-shader-graph";import{NodeShaderMaterial as o}from"../shader-nodes/index.js";import{sceneMapUniformName as s}from"../shader-nodes/scene-sample.js";export class ExperimentalWebGpuBackend{constructor(e,t,n,i,r,o,s,a,l,d,c,u,h,p,m,g){this.renderer=e,this.fallbackMaterial=t,this.nodeMaterialResolver=n,this.gBufferFallbackSource=i,this.bloom=r,this.fxaa=o,this.smaa=s,this.gtao=a,this.ssr=l,this.taa=d,this.volumetricFog=c,this.colorGrading=u,this.depthOfField=h,this.outline=p,this.postProcessEffects=m,this.pmremGenerator=null,this.pmremResults=new WeakMap,this.ownedPmremResults=new Set,this.warnedUnsupportedPostProcessStages=new Set,this.canvas=g}static async create(d={}){const c=await import("@hology/webgpu-renderer"),u=document.createElement("canvas");u.dataset.hologyRenderer="webgpu-experimental";const h=new c.WGSLShaderMaterial({vertexShader:a,fragmentShader:l});h.side=c.DoubleSide;const p=new t(c,(e,t)=>"opaque"===t?[e.outputColor.xyz.rgba(e.alphaTest),r((e.outputNormal??i.normal).multiplyScalar(.5).addScalar(.5),e.outputRoughness??n(1))]:void 0),m=new e.MeshStandardMaterial({color:8688803,roughness:1});if(null==p.resolve(m,"opaque"))throw h.dispose(),m.dispose(),new Error("Failed to compile the WebGPU G-buffer fallback material.");const g=!1===d.gtao?null:new c.GTAOEffect({normalSpace:"view",resolutionScale:.5,...d.gtao??{}}),f=!1===d.ssr||null==d.ssr?null:new c.SSREffect({normalSpace:"view",resolutionScale:.5,...d.ssr??{}}),P=!1===d.bloom?null:new c.BloomEffect({threshold:1,strength:.9,radius:.2,...d.bloom??{}}),S=!1===d.fxaa||null==d.fxaa?null:new c.FXAAEffect(d.fxaa),x=!1===d.smaa||null==d.smaa?null:new c.SMAAEffect(d.smaa),w=!1===d.taa||null!=d.smaa&&!1!==d.smaa&&null==d.taa?null:new c.TemporalAAEffect({renderScale:.9,...d.taa??{}}),b=d.volumetricFog||void 0,v=!1===d.volumetricFog?null:new c.VolumetricFogEffect(void 0,{froxelPixelSize:8,maxDistance:64,depthSlices:64,integrationSubsteps:2,temporalJitter:!0,spatialJitter:!0,scatteringIntensity:Math.PI,...b,blur:!1!==b?.blur&&{depthAwareUpsample:!0,...b?.blur}}),C=!1===d.colorGrading?null:new c.ColorGradingEffect({enabled:!1,...d.colorGrading??{}}),L=!1===d.depthOfField?null:new c.DepthOfFieldEffect({enabled:!1,...d.depthOfField??{}}),y=!1===d.outline?null:new c.OutlineEffect({enabled:!1,...d.outline??{}}),F=[],M=new WeakMap,G=new Set,O=(e,t,n)=>{let i=n;const r=F.filter(e=>e.enabled&&e.stage===t).sort((e,t)=>e.priority-t.priority||e.id-t.id);for(const t of r){if(!(t.material instanceof o)){const e=`${t.id}:material`;G.has(e)||(G.add(e),console.warn(`[Hology WebGPU experiment] Skipping custom post-process effect ${t.id}: only NodeShaderMaterial effects are supported.`));continue}try{let n=M.get(t.material);null!=n&&n.version===t.material.version||(n={version:t.material.version,shader:p.compileFullscreen(t.material)},M.set(t.material,n));const r=e.createColorTarget(`hologyCustomPostProcess${t.id}`);e.addNodeFullscreenPass({name:`HologyCustomPostProcess${t.id}`,shader:n.shader,inputOverrides:{[s]:i},outputs:r}),i=r}catch(e){const n=`${t.id}:compile:${t.material.version}`;G.has(n)||(G.add(n),console.warn(`[Hology WebGPU experiment] Skipping custom post-process effect ${t.id}: ${e instanceof Error?e.message:String(e)}`,e))}}return i},R=new c.WebGpuRenderer({canvas:u,fallbackMaterial:h,materialResolver:(e,t)=>p.resolve(e,t),invokeObjectRenderCallbacks:!1,hiZOcclusionCulling:!0,renderGraphProfiling:!1,sampleCount:1,multiDrawIndirect:!1});R.setRenderScale(w?.renderScale??1),R.setRenderGraphBuilder((e,t)=>{const n=new c.FrameGraphBuilder(t),i=n.createColorTarget("hologyNormalRoughness",{format:"rgba16float"});n.addDirectionalShadowPass(),n.addPointShadowPass(),n.addSpotShadowPass(),n.addDepthPrepass(),n.addHiZPasses(),n.addVisibilityPass(),n.addMaterialPass({name:"OpaqueGBufferPass",outputs:[n.sceneColor,i],drawStage:"opaque",loadDepth:!0}),n.addHiZHistoryPass("OpaqueGBufferPass");let r=n.sceneColor;if(null!=g){const e=g.addPasses(n,{depth:n.mainDepth,normal:i});r=g.addCompositePass(n,r,e)}null!=f&&(r=f.addPasses(n,{sceneColor:r,depth:n.mainDepth,normalRoughness:i})),n.addSceneTextureCopyPass(r),n.addLatePass(r),r=O(n,"beforeFog",r),null!=v&&(r=v.addPasses(n,{sceneColor:r,depth:n.mainDepth,volumeObjects:t.fogVolumeObjects,lights:t.extractedLights})),null!=P&&(r=P.addPass(n,r)),r=O(n,"beforeOutline",r),null!=y&&(r=y.addPass(n,r)),r=O(n,"beforeDepthOfField",r),null!=L&&(r=L.addPass(n,r,n.mainDepth)),r=O(n,"beforeColorAdjustment",r),null!=C&&(r=C.addPass(n,r)),r=O(n,"beforeAntiAliasing",r);let o=w?.addPass(n,r,n.mainDepth)??r;null!=x?o=x.addPass(n,o):null!=S&&(o=S.addPass(n,o)),o=O(n,"beforeOutput",o),n.present(o)});try{return await R.initialize(),new ExperimentalWebGpuBackend(R,h,p,m,P,S,x,g,f,w,v,C,L,y,F,u)}catch(e){throw R.destroy(),h.dispose(),p.dispose(),m.dispose(),g?.dispose(),x?.dispose(),v?.dispose(),y?.dispose(),e}}static supportsCamera(t){return t instanceof e.PerspectiveCamera||t instanceof e.OrthographicCamera}setSize(e,t,n){this.renderer.setSize(e,t,n)}initTexture(e){this.renderer.initTexture(e)}setPostProcessEffects(e){this.postProcessEffects.splice(0,this.postProcessEffects.length,...e);for(const t of e){if("beforeLut"!==t.stage)continue;const e=`${t.id}:${t.stage}`;this.warnedUnsupportedPostProcessStages.has(e)||(this.warnedUnsupportedPostProcessStages.add(e),console.warn(`[Hology WebGPU experiment] Skipping custom post-process effect ${t.id}: stage "${t.stage}" has no native WebGPU anchor.`))}}setEnableOutlines(e){null!=this.outline&&(this.outline.enabled=e)}setDynamicBatchingEnabled(e){this.renderer.setDynamicBatchingEnabled(e)}setSelectedObjects(e){this.outline?.setSelectedObjects(e)}setSelectedObjectInstances(e){this.outline?.setSelectedInstances(e)}setCascadedShadowRanges(e,t=[]){this.renderer.setCascadedShadowRanges(e,t),this.volumetricFog?.setCascadedDirectionalLights(t)}setWorldEnvironment(t){if(null==t)return void this.nodeMaterialResolver.setWorldEnvironment(null);let n=t.source;if(n.mapping!==e.CubeUVReflectionMapping){let e=this.pmremResults.get(n);null==e&&(this.pmremGenerator??(this.pmremGenerator=this.renderer.createPMREMGenerator()),e=this.pmremGenerator.fromEquirectangular(n),this.pmremResults.set(n,e),this.ownedPmremResults.add(e)),n=e.texture}this.nodeMaterialResolver.setWorldEnvironment({texture:n,intensity:t.intensity})}resetViewHistory(){this.renderer.resetViewHistory(),this.taa?.reset()}async compile(e,t){await this.renderer.compileAsync(e,t)}createStaticDrawSet(e,t){this.renderer.setHiZOcclusionCullingEnabled(!0);const n=this.renderer.createStaticDrawSet(e,{label:t,onUnsupported:"skip"});return 0===n.drawCount?(n.dispose(),null):n}render(e,t,n){this.volumetricFog?.setScene(e),this.taa?.prepareCamera(t,this.canvas.width,this.canvas.height);try{this.renderer.render(e,t,n)}finally{this.taa?.finishCamera(t)}}getLastFrameProfile(){return this.renderer.getLastFrameProfile()}setPostProcessState(e){null!=this.colorGrading&&(Object.assign(this.colorGrading.options,e??{enabled:!1}),this.colorGrading.options.enabled=!0===e?.enabled),null!=this.depthOfField&&(this.depthOfField.options.enabled=null!=e?.depthFocus||null!=e?.depthAperture||null!=e?.depthMaxBlur,this.depthOfField.options.focus=e?.depthFocus,this.depthOfField.options.aperture=e?.depthAperture,this.depthOfField.options.maxBlur=e?.depthMaxBlur)}setProfilingEnabled(e){this.renderer.setRenderGraphProfilingEnabled(e)}resetTemporalHistory(){this.taa?.reset()}inspect(e,t){return inspectWebGpuScene(e,t,this.nodeMaterialResolver)}destroy(){this.nodeMaterialResolver.dispose(),this.gBufferFallbackSource.dispose(),this.gtao?.dispose(),this.smaa?.dispose(),this.volumetricFog?.dispose();for(const e of this.ownedPmremResults)e.dispose();this.ownedPmremResults.clear(),this.renderer.destroy(),this.fallbackMaterial.dispose()}}export function inspectWebGpuScene(e,t,n){const i={meshes:0,skinnedMeshes:0,instancedMeshes:0,batchedMeshes:0,sprites:0,points:0,lines:0,missingPositionGeometry:0,transparentMaterials:0,shaderMaterialsReplaced:0,materialsReplaced:0,unsupportedCamera:ExperimentalWebGpuBackend.supportsCamera(t)?0:1};return e.traverse(e=>{if(e.isSprite)return void i.sprites++;if(e.isPoints)return void i.points++;if(e.isLine)return void i.lines++;if(!e.isMesh)return;const t=e;t.isBatchedMesh?i.batchedMeshes++:t.isInstancedMesh?i.instancedMeshes++:t.isSkinnedMesh?i.skinnedMeshes++:i.meshes++,null==t.geometry?.getAttribute("position")&&i.missingPositionGeometry++;const r=Array.isArray(t.material)?t.material:[t.material];for(const e of r){if(null==e)continue;e.transparent&&i.transparentMaterials++;const t=!0===e.isWGSLShaderMaterial||!0===e.isLineMaterial,r=!t&&!0===n?.canResolve(e);t||r||(i.materialsReplaced++,e.isShaderMaterial&&i.shaderMaterialsReplaced++)}}),i}export function formatWebGpuSceneCapabilitySummary(e){return`[Hology WebGPU experiment] ${JSON.stringify(e)}`}const a="\nstruct VertexInput {\n @location(0) position: vec3<f32>,\n @location(1) normal: vec3<f32>,\n @location(2) uv: vec2<f32>,\n @location(3) color: vec4<f32>,\n#ifdef USE_SKINNING\n @location(4) skinIndex: vec4<u32>,\n @location(5) skinWeight: vec4<f32>,\n#endif\n @builtin(instance_index) instanceIndex: u32,\n};\n\nstruct VertexOutput {\n @builtin(position) position: vec4<f32>,\n @location(0) worldPosition: vec3<f32>,\n @location(1) worldNormal: vec3<f32>,\n @location(2) color: vec4<f32>,\n};\n\n@vertex\nfn vsMain(input: VertexInput) -> VertexOutput {\n var output: VertexOutput;\n#ifdef USE_SKINNING\n let localPosition = rendererSkinPosition(input.position, input.skinIndex, input.skinWeight);\n let localNormal = rendererSkinNormal(input.normal, input.skinIndex, input.skinWeight);\n#else\n let localPosition = input.position;\n let localNormal = input.normal;\n#endif\n let world = rendererWorldPosition(localPosition, input.instanceIndex);\n output.position = rendererClipPosition(localPosition, input.instanceIndex);\n output.worldPosition = world.xyz;\n output.worldNormal = rendererWorldNormal(localNormal, input.instanceIndex);\n output.color = input.color * rendererObjectColor(input.instanceIndex);\n return output;\n}\n",l="\nstruct VertexOutput {\n @builtin(position) position: vec4<f32>,\n @location(0) worldPosition: vec3<f32>,\n @location(1) worldNormal: vec3<f32>,\n @location(2) color: vec4<f32>,\n};\n\nfn distanceAttenuation(distanceToLight: f32, range: f32) -> f32 {\n let linear = max(0.0, 1.0 - distanceToLight / max(range, 0.001));\n return linear * linear;\n}\n\n@fragment\nfn fsMain(input: VertexOutput) -> @location(0) vec4<f32> {\n let normal = normalize(input.worldNormal);\n let normalTint = normal * 0.5 + vec3<f32>(0.5);\n let base = mix(vec3<f32>(0.52, 0.58, 0.64), normalTint, 0.22) * input.color.rgb;\n var lighting = rendererIndirectDiffuse(normal) + vec3<f32>(0.08);\n var directionalLighting = vec3<f32>(0.0);\n let directionalCount = rendererDirectionalLightCount();\n\n for (var index: u32 = 0u; index < directionalCount; index = index + 1u) {\n let lightDirection = rendererDirectionalLightDirectionForLight(index);\n let shadow = rendererSampleDirectionalShadowForLightWithNormal(index, input.worldPosition, normal);\n directionalLighting += rendererDirectionalLightColorForLight(index) * max(dot(normal, lightDirection), 0.0) * shadow;\n }\n if (directionalCount > 0u) {\n lighting += directionalLighting / f32(directionalCount);\n }\n\n for (var index: u32 = 0u; index < rendererPointLightCount(); index = index + 1u) {\n let lightVector = rendererPointLightPositionForLight(index) - input.worldPosition;\n let distanceToLight = length(lightVector);\n let lightDirection = normalize(lightVector);\n let shadow = rendererSamplePointShadowForLightWithNormal(index, input.worldPosition, normal);\n lighting += rendererPointLightColorForLight(index) * max(dot(normal, lightDirection), 0.0) * distanceAttenuation(distanceToLight, rendererPointLightRangeForLight(index)) * shadow;\n }\n\n for (var index: u32 = 0u; index < rendererSpotLightCount(); index = index + 1u) {\n let lightVector = rendererSpotLightPositionForLight(index) - input.worldPosition;\n let distanceToLight = length(lightVector);\n let lightDirection = normalize(lightVector);\n let angleCos = dot(-lightDirection, rendererSpotLightDirectionForLight(index));\n let cone = smoothstep(rendererSpotLightConeCosForLight(index), rendererSpotLightPenumbraCosForLight(index), angleCos);\n let shadow = rendererSampleSpotShadowForLightWithNormal(index, input.worldPosition, normal);\n lighting += rendererSpotLightColorForLight(index) * max(dot(normal, lightDirection), 0.0) * cone * distanceAttenuation(distanceToLight, rendererSpotLightRangeForLight(index)) * shadow;\n }\n\n return vec4<f32>(base * max(lighting, vec3<f32>(0.08)), input.color.a);\n}\n";/*
|
|
2
2
|
* Copyright (©) 2026 Hology Interactive AB. All rights reserved.
|
|
3
3
|
* See the LICENSE.md file for details.
|
|
4
4
|
*/
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Material, Object3D, Texture } from 'three';
|
|
1
|
+
import { BufferGeometry, Material, Object3D, Texture } from 'three';
|
|
2
2
|
import { AnimationRigData, Asset, AssetId, ModelColliderData } from './model.js';
|
|
3
3
|
import { CollisionShape } from './collision/collision-shape.js';
|
|
4
4
|
import * as THREE from 'three';
|
|
@@ -108,6 +108,11 @@ export declare class AssetMeshInstance extends Object3D {
|
|
|
108
108
|
}
|
|
109
109
|
export declare function createAuthoredCollisionShapes(colliders: ModelColliderData[], assetRescale?: number): CollisionShape[];
|
|
110
110
|
export declare function getElectronArg(name: string): string;
|
|
111
|
+
/**
|
|
112
|
+
* Removes triangles that contain non-finite positions or have effectively no
|
|
113
|
+
* area. Rebuilding only the index preserves all vertex, skin and morph data.
|
|
114
|
+
*/
|
|
115
|
+
export declare function removeInvalidFaces(geometry: BufferGeometry): number;
|
|
111
116
|
export type GetMeshOptions = {
|
|
112
117
|
/**
|
|
113
118
|
* Meshes can be optimized by merging geometries. This is appropriate for most static objects
|