@hology/core 0.0.187 → 0.0.190

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.
Files changed (88) hide show
  1. package/dist/effects/sequence/audio-parameters.d.ts +25 -0
  2. package/dist/effects/sequence/audio-parameters.js +4 -0
  3. package/dist/effects/sequence/index.d.ts +8 -0
  4. package/dist/effects/sequence/index.js +4 -0
  5. package/dist/effects/sequence/sequence-action.d.ts +17 -0
  6. package/dist/effects/sequence/sequence-action.js +4 -0
  7. package/dist/effects/sequence/sequence-actor.d.ts +135 -0
  8. package/dist/effects/sequence/sequence-actor.js +4 -0
  9. package/dist/effects/sequence/sequence-data.d.ts +458 -0
  10. package/dist/effects/sequence/sequence-data.js +4 -0
  11. package/dist/effects/sequence/sequence-event.d.ts +37 -0
  12. package/dist/effects/sequence/sequence-event.js +4 -0
  13. package/dist/effects/sequence/sequence-player.d.ts +323 -0
  14. package/dist/effects/sequence/sequence-player.js +4 -0
  15. package/dist/effects/sequence/sequencer.d.ts +7 -0
  16. package/dist/effects/sequence/sequencer.js +4 -0
  17. package/dist/effects/vfx/trail-renderer.d.ts +19 -15
  18. package/dist/effects/vfx/trail-renderer.js +1 -1
  19. package/dist/gameplay/actors/actor.js +1 -1
  20. package/dist/gameplay/actors/builtin/components/character/character-animation.d.ts +151 -0
  21. package/dist/gameplay/actors/builtin/components/character/character-animation.js +1 -1
  22. package/dist/gameplay/actors/builtin/components/character/character-movement.d.ts +4 -0
  23. package/dist/gameplay/actors/builtin/components/character/character-movement.js +1 -1
  24. package/dist/gameplay/actors/builtin/components/mesh-component.js +1 -1
  25. package/dist/gameplay/actors/builtin/index.d.ts +5 -0
  26. package/dist/gameplay/actors/builtin/index.js +1 -1
  27. package/dist/gameplay/actors/camera/third-person-camera-component.d.ts +6 -0
  28. package/dist/gameplay/actors/camera/third-person-camera-component.js +1 -1
  29. package/dist/gameplay/actors/factory.d.ts +3 -0
  30. package/dist/gameplay/actors/factory.js +1 -1
  31. package/dist/gameplay/actors/internal/component-init.d.ts +1 -0
  32. package/dist/gameplay/actors/internal/component-init.js +1 -1
  33. package/dist/gameplay/index.d.ts +1 -1
  34. package/dist/gameplay/index.js +1 -1
  35. package/dist/gameplay/initiate.js +1 -1
  36. package/dist/gameplay/input/input-service.d.ts +16 -2
  37. package/dist/gameplay/input/input-service.js +1 -1
  38. package/dist/gameplay/input/input.d.ts +3 -0
  39. package/dist/gameplay/input/input.js +1 -1
  40. package/dist/gameplay/input/keybind.d.ts +37 -0
  41. package/dist/gameplay/input/keybind.js +1 -1
  42. package/dist/gameplay/services/asset-loader.d.ts +4 -1
  43. package/dist/gameplay/services/asset-loader.js +1 -1
  44. package/dist/gameplay/services/physics/physics-system.d.ts +7 -1
  45. package/dist/gameplay/services/physics/physics-system.js +1 -1
  46. package/dist/gameplay/services/render.js +1 -1
  47. package/dist/gameplay/services/world.js +1 -1
  48. package/dist/index.d.ts +1 -0
  49. package/dist/index.js +1 -1
  50. package/dist/rendering/fog/fog-volume-actor.d.ts +1 -1
  51. package/dist/rendering/fog/fog-volume-actor.js +1 -1
  52. package/dist/rendering/fog/volumetric-fog-pass.d.ts +1 -0
  53. package/dist/rendering/fog/volumetric-fog-pass.js +1 -1
  54. package/dist/rendering/light-probes/light-probe-volume-actor.d.ts +14 -0
  55. package/dist/rendering/light-probes/light-probe-volume-actor.js +4 -0
  56. package/dist/rendering/light-probes/light-volume-capture.d.ts +16 -0
  57. package/dist/rendering/light-probes/light-volume-capture.js +4 -0
  58. package/dist/rendering.d.ts +5 -1
  59. package/dist/rendering.js +1 -1
  60. package/dist/scene/asset-resource-loader.d.ts +11 -1
  61. package/dist/scene/asset-resource-loader.js +1 -1
  62. package/dist/scene/bootstrap.d.ts +1 -2
  63. package/dist/scene/collision/collision-shape-import.js +1 -1
  64. package/dist/scene/landscape/landscape.d.ts +1 -1
  65. package/dist/scene/landscape/landscape.js +1 -1
  66. package/dist/scene/materializer.d.ts +4 -1
  67. package/dist/scene/materializer.js +1 -1
  68. package/dist/scene/model.d.ts +21 -3
  69. package/dist/scene/model.js +1 -1
  70. package/dist/scene/runtime-backend-service.js +1 -1
  71. package/dist/scene/storage/storage.d.ts +3 -2
  72. package/dist/scene/storage/storage.js +1 -1
  73. package/dist/shader/builtin/index.js +1 -1
  74. package/dist/shader/color-layer.d.ts +7 -2
  75. package/dist/shader/color-layer.js +1 -1
  76. package/dist/shader/parameter.d.ts +3 -2
  77. package/dist/shader/shader.d.ts +4 -2
  78. package/dist/shader/sprite-shader.d.ts +13 -3
  79. package/dist/shader/sprite-shader.js +1 -1
  80. package/dist/shader-nodes/dither.d.ts +8 -0
  81. package/dist/shader-nodes/dither.js +4 -0
  82. package/dist/shader-nodes/glsl-node.d.ts +1 -1
  83. package/dist/shader-nodes/index.d.ts +1 -0
  84. package/dist/shader-nodes/index.js +1 -1
  85. package/dist/test/injection.test.js +1 -1
  86. package/dist/utils/three/outline-pass.js +1 -1
  87. package/package.json +4 -1
  88. package/tsconfig.tsbuildinfo +1 -1
@@ -0,0 +1,37 @@
1
+ import 'reflect-metadata';
2
+ import { Type } from '../../utils/type.js';
3
+ /**
4
+ * Metadata about a sequence event method on an actor
5
+ */
6
+ export interface SequenceEventInfo {
7
+ /** Display name shown in the editor */
8
+ name: string;
9
+ /** Actual method name on the actor class */
10
+ methodName: string;
11
+ }
12
+ /**
13
+ * Decorator to mark an actor method as callable from sequences.
14
+ *
15
+ * @example
16
+ * class Character extends BaseActor {
17
+ * @SequenceEvent('Attack End')
18
+ * onAttackEnd() {
19
+ * // Handle attack end
20
+ * }
21
+ *
22
+ * @SequenceEvent('Hit')
23
+ * onSequenceHit() {
24
+ * // Handle hit event
25
+ * }
26
+ * }
27
+ */
28
+ export declare function SequenceEvent(displayName?: string): (target: Object, methodName: string) => void;
29
+ /**
30
+ * Extract all sequence events from an actor class and its parent classes.
31
+ * This is used by the editor to populate the event function dropdown.
32
+ *
33
+ * @param actorType - The actor class to extract events from
34
+ * @returns Array of sequence event info objects
35
+ */
36
+ export declare function extractSequenceEvents(actorType: Type<any>): SequenceEventInfo[];
37
+ //# sourceMappingURL=sequence-event.d.ts.map
@@ -0,0 +1,4 @@
1
+ import"reflect-metadata";import{ArrayMap as e}from"../../utils/collections.js";const t=new e;export function SequenceEvent(e){return function(n,o){null!=n&&t.push(n.constructor,{name:e??o?.replace(/^on/,""),methodName:o})}}export function extractSequenceEvents(e){if(null==e)return[];const n=t.get(e)||[];return[...extractSequenceEvents(Object.getPrototypeOf(e)).filter(e=>n.every(t=>t.methodName!==e.methodName)),...n]}/*
2
+ * Copyright (©) 2026 Hology Interactive AB. All rights reserved.
3
+ * See the LICENSE.md file for details.
4
+ */
@@ -0,0 +1,323 @@
1
+ import { Subject } from 'rxjs';
2
+ import * as THREE from 'three';
3
+ import { AnimationAction, AnimationMixer, Euler, Object3D, Vector3 } from 'three';
4
+ import { VfxService } from '../../effects/vfx/vfx-service.js';
5
+ import { BaseActor } from '../../gameplay/actors/actor.js';
6
+ import { ActorFactory } from '../../gameplay/actors/factory.js';
7
+ import { AssetLoader } from '../../gameplay/services/asset-loader.js';
8
+ import { World } from '../../gameplay/services/world.js';
9
+ import { PrefabInstance } from '../../scene/objects/prefab.js';
10
+ import { SequenceData, SequenceRole, SequenceTrack } from './sequence-data.js';
11
+ import { CharacterAnimationComponent } from '../../gameplay/actors/index.js';
12
+ /**
13
+ * Playback state of the sequence
14
+ */
15
+ export declare enum SequencePlaybackState {
16
+ Stopped = "stopped",
17
+ Playing = "playing",
18
+ Paused = "paused"
19
+ }
20
+ /**
21
+ * Interface for targets that can play animations
22
+ */
23
+ export interface AnimationPlayable {
24
+ /** The target object (actor, object3d, etc.) */
25
+ target: Object3D | BaseActor | null;
26
+ /** Animation mixer for skeletal animations on this target */
27
+ mixer?: AnimationMixer;
28
+ /** Currently active animation actions */
29
+ activeActions: Map<string, AnimationAction>;
30
+ }
31
+ /**
32
+ * Binding between a track and its runtime target
33
+ */
34
+ export interface TrackBinding extends AnimationPlayable {
35
+ track: SequenceTrack;
36
+ /** Original transform before sequence started (for restoration) */
37
+ originalTransform?: {
38
+ position: Vector3;
39
+ rotation: Euler;
40
+ scale: Vector3;
41
+ };
42
+ /** The parent object before any parenting sequences applied */
43
+ originalParent?: Object3D | null;
44
+ /** The current parent object assigned by sequence parenting */
45
+ currentParent?: Object3D;
46
+ /**
47
+ * The CharacterAnimationComponent (if any) associated with this binding's target.
48
+ * Stored so we can call lifecycle methods (beginExternalControl / stopSequenceAnimation)
49
+ * without re-querying the actor every frame.
50
+ */
51
+ charAnimComponent?: CharacterAnimationComponent;
52
+ /**
53
+ * Set of actionKeys (from activeActions) whose AnimationAction lives inside
54
+ * charAnimComponent's mixer rather than our own binding.mixer.
55
+ */
56
+ charAnimActionKeys?: Set<string>;
57
+ }
58
+ /**
59
+ * Role bindings map - binds predefined roles to runtime targets
60
+ */
61
+ export type RoleBindings = Map<SequenceRole, BaseActor | Object3D>;
62
+ /**
63
+ * Spawned instance tracking
64
+ */
65
+ export type SpawnedInstance = ({
66
+ type: 'actor';
67
+ instance: BaseActor;
68
+ } | {
69
+ type: 'prefab';
70
+ instance: PrefabInstance;
71
+ } | {
72
+ type: 'mesh';
73
+ instance: Object3D;
74
+ } | {
75
+ type: 'proxy';
76
+ target: BaseActor | Object3D;
77
+ }) & Partial<AnimationPlayable>;
78
+ /**
79
+ * SequencePlayer is the runtime system that plays a sequence.
80
+ * It manages track bindings, playback state, and updates.
81
+ */
82
+ export declare class SequencePlayer {
83
+ private _state;
84
+ private _time;
85
+ private _duration;
86
+ private _timescale;
87
+ private _loop;
88
+ private _externalTimeControl;
89
+ private bindings;
90
+ private roleBindings;
91
+ private sequenceData;
92
+ readonly onComplete: Subject<void>;
93
+ readonly onLoop: Subject<number>;
94
+ readonly onTimeUpdate: import("rxjs").Observable<number>;
95
+ readonly onStateChange: import("rxjs").Observable<SequencePlaybackState>;
96
+ private loopCount;
97
+ private sequenceCamera;
98
+ private originalCamera;
99
+ private audioListener;
100
+ private audioBuffers;
101
+ private loadingAudioBuffers;
102
+ private animationClips;
103
+ private loadingAnimationClips;
104
+ private audioByClip;
105
+ private activeAudioClips;
106
+ private audioGainNodes;
107
+ private audioStartInFlight;
108
+ private lastAudioStartAttemptTime;
109
+ private readonly audioStartRetryIntervalSeconds;
110
+ private world;
111
+ private assetLoader;
112
+ private actorFactory;
113
+ private vfxService;
114
+ private spawnedInstances;
115
+ private activeClips;
116
+ private pendingSpawns;
117
+ private vfxActors;
118
+ private activeVfxClips;
119
+ private clearCounter;
120
+ private audioFilters;
121
+ private audioPannerNodes;
122
+ private firedEvents;
123
+ constructor();
124
+ /**
125
+ * Current playback state
126
+ */
127
+ get state(): SequencePlaybackState;
128
+ /**
129
+ * Current playback time in seconds
130
+ */
131
+ get time(): number;
132
+ /**
133
+ * Total duration of the sequence
134
+ */
135
+ get duration(): number;
136
+ /**
137
+ * Playback rate multiplier
138
+ */
139
+ get timescale(): number;
140
+ set timescale(value: number);
141
+ /**
142
+ * Whether the sequence loops
143
+ */
144
+ get loop(): boolean;
145
+ set loop(value: boolean);
146
+ /**
147
+ * When true, the update() method will not advance time internally.
148
+ * Time must be controlled externally via seek().
149
+ * This is useful for editor preview where the UI controls playback position.
150
+ */
151
+ get externalTimeControl(): boolean;
152
+ set externalTimeControl(value: boolean);
153
+ /**
154
+ * Set world dependency
155
+ */
156
+ setWorld(world: World): void;
157
+ setAudioListener(audioListener: THREE.AudioListener): void;
158
+ /**
159
+ * Set asset loader dependency
160
+ */
161
+ setAssetLoader(assetLoader: AssetLoader): void;
162
+ /**
163
+ * Set actor factory dependency
164
+ */
165
+ setActorFactory(actorFactory: ActorFactory): void;
166
+ /**
167
+ * Set VFX service dependency
168
+ */
169
+ setVfxService(vfxService: VfxService): void;
170
+ /**
171
+ * Load sequence data and prepare for playback
172
+ */
173
+ load(data: SequenceData): void;
174
+ private getAudioAssetIdsForSequence;
175
+ private preloadAudioBuffersForSequence;
176
+ /**
177
+ * Bind a role to a runtime target.
178
+ * This allows tracks with a role to target a different actor at runtime.
179
+ *
180
+ * @example
181
+ * player.bindRole(SequenceRole.Self, playerActor)
182
+ * player.bindRole(SequenceRole.Target, enemyActor)
183
+ */
184
+ bindRole(role: SequenceRole, target: BaseActor | Object3D): void;
185
+ /**
186
+ * Bind a scene object by ID to a target
187
+ */
188
+ bindObject(objectId: string, target: Object3D | BaseActor): void;
189
+ /**
190
+ * Resolve all track bindings based on current proxy bindings and scene references
191
+ */
192
+ private resolveBindings;
193
+ private resolveTrackBinding;
194
+ private createBinding;
195
+ /**
196
+ * Start or resume playback
197
+ */
198
+ play(): void;
199
+ /**
200
+ * Pause playback
201
+ */
202
+ pause(): void;
203
+ private pauseAudio;
204
+ private pauseVfx;
205
+ private resumeVfx;
206
+ /**
207
+ * Stop playback and reset to beginning
208
+ */
209
+ stop(): void;
210
+ /**
211
+ * Restart playback from the beginning
212
+ */
213
+ restart(): void;
214
+ /**
215
+ * Seek to a specific time
216
+ */
217
+ seek(time: number): void;
218
+ /**
219
+ * Update the sequence player - should be called every frame
220
+ */
221
+ update(deltaTime: number): void;
222
+ /**
223
+ * Evaluate all tracks at the given time
224
+ */
225
+ private evaluate;
226
+ private evaluateTrack;
227
+ private evaluateObjectTrack;
228
+ private evaluateSubTracks;
229
+ private evaluateTransformSubTrack;
230
+ private evaluateAnimationSubTrack;
231
+ private evaluateVisibilitySubTrack;
232
+ private evaluatePropertySubTrack;
233
+ private evaluateEventSubTrack;
234
+ private evaluateCameraTrack;
235
+ private evaluateAudioTrack;
236
+ private tryStartAudioClip;
237
+ private applyAudioParameters;
238
+ private updatePositionalAudioTransform;
239
+ /**
240
+ * Play an audio clip
241
+ */
242
+ private playAudioClip;
243
+ /**
244
+ * Stop an audio clip
245
+ */
246
+ private stopAudioClip;
247
+ /**
248
+ * Stop all audio clips
249
+ */
250
+ private stopAllAudio;
251
+ private evaluateVfxTrack;
252
+ /**
253
+ * Ensure VFX actor exists for a clip (create if needed, reuse if exists)
254
+ */
255
+ private ensureVfxActor;
256
+ /**
257
+ * Get transform for VFX actor from track or transform sub-track
258
+ */
259
+ private getVfxTransform;
260
+ /**
261
+ * Update VFX actor transform during playback
262
+ */
263
+ private updateVfxTransform;
264
+ /**
265
+ * Resolve actor type from string name
266
+ */
267
+ private resolveActorType;
268
+ /**
269
+ * Spawn an actor for a clip
270
+ */
271
+ private spawnActorForClip;
272
+ /**
273
+ * Spawn a prefab for a clip
274
+ */
275
+ private spawnPrefabForClip;
276
+ /**
277
+ * Spawn a mesh for a clip
278
+ */
279
+ private spawnMeshForClip;
280
+ /**
281
+ * Despawn an instance
282
+ */
283
+ private despawnInstance;
284
+ /**
285
+ * Despawn all instances
286
+ */
287
+ private despawnAll;
288
+ /**
289
+ * Get initial transform from transform sub-track or clip defaults
290
+ */
291
+ private getInitialTransform;
292
+ private evaluateSpawnTrack;
293
+ /**
294
+ * Get Object3D from spawned instance
295
+ */
296
+ private getInstanceObject;
297
+ /**
298
+ * Spawn for clip (async wrapper)
299
+ */
300
+ private spawnForClip;
301
+ private findKeyframes;
302
+ private applyInterpolation;
303
+ private ensureAnimationClip;
304
+ private captureOriginalTransforms;
305
+ private restoreOriginalTransforms;
306
+ private stopAllAnimations;
307
+ /**
308
+ * Stop all VFX actors (but don't remove from world - they're reused)
309
+ */
310
+ private stopAllVfx;
311
+ /**
312
+ * Dispose of all resources
313
+ */
314
+ dispose(): void;
315
+ private updateTrackParenting;
316
+ private findSocket;
317
+ private getActiveObjectsForTrack;
318
+ private restoreObjectParent;
319
+ private restoreOriginalParents;
320
+ private evaluateAudioSubTracks;
321
+ private stringToRandom;
322
+ }
323
+ //# sourceMappingURL=sequence-player.d.ts.map
@@ -0,0 +1,4 @@
1
+ import{BehaviorSubject as t,Subject as e}from"rxjs";import*as i from"three";import{AnimationMixer as s,Euler as a,Quaternion as o,Vector3 as n}from"three";import{BaseActor as r}from"../../gameplay/actors/actor.js";import c from"../../gameplay/actors/builtin/index.js";import{getAudioParameterDefinition as l}from"./audio-parameters.js";import{SkeletonUtils as u}from"three-stdlib";import{CharacterAnimationComponent as h,CharacterMovementComponent as d}from"../../gameplay/actors/index.js";import{RootMotionClip as p}from"../../gameplay/animation/root-motion.js";export var SequencePlaybackState;!function(t){t.Stopped="stopped",t.Playing="playing",t.Paused="paused"}(SequencePlaybackState||(SequencePlaybackState={}));export class SequencePlayer{constructor(){this._state=new t(SequencePlaybackState.Stopped),this._time=new t(0),this._duration=0,this._timescale=1,this._loop=!1,this._externalTimeControl=!1,this.bindings=new Map,this.roleBindings=new Map,this.sequenceData=null,this.onComplete=new e,this.onLoop=new e,this.onTimeUpdate=this._time.asObservable(),this.onStateChange=this._state.asObservable(),this.loopCount=0,this.sequenceCamera=null,this.originalCamera=null,this.audioListener=null,this.audioBuffers=new Map,this.loadingAudioBuffers=new Map,this.animationClips=new Map,this.loadingAnimationClips=new Set,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.clearCounter=0,this.audioFilters=new Map,this.audioPannerNodes=new Map,this.firedEvents=new Set}get state(){return this._state.value}get time(){return this._time.value}get duration(){return this._duration}get timescale(){return this._timescale}set timescale(t){this._timescale=Math.max(.01,t)}get loop(){return this._loop}set loop(t){this._loop=t}get externalTimeControl(){return this._externalTimeControl}set externalTimeControl(t){this._externalTimeControl=t}setWorld(t){this.world!==t&&(this.world=t,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._state.next(SequencePlaybackState.Stopped))}setAudioListener(t){this.audioListener=t}setAssetLoader(t){if(this.assetLoader=t,this.sequenceData){const t=this.clearCounter;this.preloadAudioBuffersForSequence(this.sequenceData,t)}}setActorFactory(t){this.actorFactory=t}setVfxService(t){this.vfxService=t}load(t){if(this.stop(),this.clearCounter++,this.sequenceData=t,this._duration=t.duration,this._loop=t.loop,this._timescale=t.playbackRate,this.bindings.clear(),this.loopCount=0,this.assetLoader){const e=this.clearCounter;this.preloadAudioBuffersForSequence(t,e)}}getAudioAssetIdsForSequence(t){const e=new Set;for(const i of t.tracks){if("audio"!==i.type)continue;const t=i;for(const i of t.clips??[])i.audioAssetId&&e.add(i.audioAssetId)}return[...e]}async preloadAudioBuffersForSequence(t,e){if(!this.assetLoader)return;const i=this.getAudioAssetIdsForSequence(t);0!==i.length&&await Promise.all(i.map(async t=>{if(e!==this.clearCounter)return;if(this.audioBuffers.has(t))return;let i=this.loadingAudioBuffers.get(t);i||(i=this.assetLoader.getAudioByAssetId(t),this.loadingAudioBuffers.set(t,i));try{const s=await i;if(e!==this.clearCounter)return;this.audioBuffers.set(t,s)}catch(t){}finally{this.loadingAudioBuffers.get(t)===i&&this.loadingAudioBuffers.delete(t)}}))}bindRole(t,e){this.roleBindings.set(t,e),this.sequenceData&&this.resolveBindings()}bindObject(t,e){if(this.sequenceData)for(const i of this.sequenceData.tracks)"object"===i.type&&i.targetId===t&&this.createBinding(i,e)}resolveBindings(){if(this.sequenceData)for(const t of this.sequenceData.tracks)this.resolveTrackBinding(t)}resolveTrackBinding(t){if("object"===t.type){const e=t;e.role&&this.roleBindings.has(e.role)&&this.createBinding(t,this.roleBindings.get(e.role))}else if("spawn"===t.type){const e=t;e.role&&this.roleBindings.has(e.role)&&this.createBinding(t,this.roleBindings.get(e.role))}else if("group"===t.type)for(const e of t.childTracks)this.resolveTrackBinding(e)}createBinding(t,e){const i=e instanceof r?e.object:e,a={track:t,target:e,activeActions:new Map,originalTransform:{position:i.position.clone(),rotation:i.rotation.clone(),scale:i.scale.clone()},originalParent:i.parent};t.subTracks.some(t=>"animation"===t.type)&&(a.mixer=new s(i)),this.bindings.set(t.id,a)}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.resumeVfx())}pause(){this._state.value===SequencePlaybackState.Playing&&(this._state.next(SequencePlaybackState.Paused),this.pauseAudio(),this.pauseVfx())}pauseAudio(){for(const t of this.audioByClip.values())t.pause()}pauseVfx(){for(const t of this.vfxActors.values())t.pause()}resumeVfx(){for(const[t,e]of this.vfxActors.entries())(this.activeVfxClips.has(t)||e.getParticleCount()>0)&&e.play()}stop(){this._state.next(SequencePlaybackState.Stopped),this._time.next(0),this.clearCounter++,this.loopCount=0,this.pauseAudio(),this.restoreOriginalTransforms(),this.restoreOriginalParents(),this.stopAllAudio(),this.stopAllAnimations(),this.despawnAll(),this.stopAllVfx(),this.firedEvents.clear()}restart(){this.stop(),this.play()}seek(t){const e=Math.max(0,Math.min(t,this._duration));this._time.next(e),this.evaluate(e)}update(t){if(this._state.value!==SequencePlaybackState.Playing)return;if(!this.sequenceData)return;if(this._externalTimeControl){for(const e of this.bindings.values())e.mixer&&e.mixer.update(t*this._timescale);for(const e of this.spawnedInstances.values())e.mixer&&e.mixer.update(t*this._timescale);return}const e=this._time.value+t*this._timescale;if(e>=this._duration){if(!this._loop)return this._time.next(this._duration),this.evaluate(this._duration),this._state.next(SequencePlaybackState.Stopped),void this.onComplete.next();this.loopCount++,this._time.next(e%this._duration),this.firedEvents.clear(),this.onLoop.next(this.loopCount)}else this._time.next(e);this.evaluate(this._time.value);for(const e of this.bindings.values())e.mixer&&e.mixer.update(t*this._timescale);for(const e of this.spawnedInstances.values())e.mixer&&e.mixer.update(t*this._timescale)}evaluate(t){if(this.sequenceData)for(const e of this.sequenceData.tracks){if(!e.muted&&("object"===e.type||"spawn"===e.type||"vfx"===e.type)){const t=this.bindings.get(e.id);this.updateTrackParenting(e,t)}this.evaluateTrack(e,t)}}evaluateTrack(t,e){if(t.muted)return;const i=this.bindings.get(t.id);switch(t.type){case"object":i&&this.evaluateObjectTrack(t,i,e);break;case"camera":this.evaluateCameraTrack(t,e);break;case"audio":this.evaluateAudioTrack(t,e);break;case"vfx":this.evaluateVfxTrack(t,e);break;case"spawn":this.evaluateSpawnTrack(t,i,e);break;case"group":for(const i of t.childTracks)this.evaluateTrack(i,e)}}evaluateObjectTrack(t,e,i){this.evaluateSubTracks(t.subTracks,e,i)}evaluateSubTracks(t,e,i){const s=e.target instanceof r?e.target.object:e.target;if(s)for(const a of t)if(!a.muted)switch(a.type){case"transform":this.evaluateTransformSubTrack(a,s,i);break;case"animation":this.evaluateAnimationSubTrack(a,e,i);break;case"visibility":this.evaluateVisibilitySubTrack(a,s,i);break;case"property":this.evaluatePropertySubTrack(a,e.target||null,i);break;case"event":this.evaluateEventSubTrack(a,e.target||null,i)}}evaluateTransformSubTrack(t,e,i){const s=t.keyframes;if(0===s.length)return;const{prev:a,next:o,t:n}=this.findKeyframes(s,i);if(a)if(o&&a!==o){const i=this.applyInterpolation(n,a.interpolation);t.components.position&&a.position&&o.position&&e.position.lerpVectors(f.fromArray(a.position),m.fromArray(o.position),i),t.components.rotation&&a.rotation&&o.rotation&&(g.setFromEuler(v.fromArray([...a.rotation,"XYZ"])),A.setFromEuler(b.fromArray([...o.rotation,"XYZ"])),e.quaternion.slerpQuaternions(g,A,i)),t.components.scale&&a.scale&&o.scale&&e.scale.lerpVectors(f.fromArray(a.scale),m.fromArray(o.scale),i)}else t.components.position&&a.position&&e.position.fromArray(a.position),t.components.rotation&&a.rotation&&e.rotation.fromArray([...a.rotation,"XYZ"]),t.components.scale&&a.scale&&e.scale.fromArray(a.scale)}evaluateAnimationSubTrack(t,e,s){if(!e.mixer||!e.activeActions)return;if(e.target instanceof r?e.target.object:e.target)for(const a of t.clips){const o=a.startTime+a.duration,n=s>=a.startTime&&s<o,c=`${t.id}-${a.id}`;let l=e.activeActions.get(c),u=!1;if(n){if(!l){u=!0;const t=a.animationClipAssetId;if(null==t)continue;const s=this.animationClips.get(t);if(null==s){this.ensureAnimationClip(t);continue}const o=e;let n=!1;if(e.target instanceof r){o.charAnimComponent||(o.charAnimComponent=e.target.getComponent(h)??void 0);let t=s;a.clipEndOffset>0&&(t=t.clone(),t.duration=Math.max(0,t.duration-a.clipEndOffset));const i=o.charAnimComponent;if(null!=i){const s=a.rootMotion?p.fromClip(t,!1):t;if(this._externalTimeControl)l=i.beginExternalAnimationControl(s,{timeScale:a.playbackRate});else if(i.play(s,{inPlace:!a.rootMotion,loop:!1,priority:20,timeScale:a.playbackRate,fadeTime:a.fadeInDuration??.2,offset:a.clipStartOffset}),l=i.getFullBodyAction(),a.rootMotion){const t=e.target.getComponent(d);t&&t.setRootMotionAction(l)}e.activeActions.set(c,l),o.charAnimActionKeys||(o.charAnimActionKeys=new Set),o.charAnimActionKeys.add(c),n=!0}}if(!n){let t=s;a.clipEndOffset>0&&(t=t.clone(),t.duration=Math.max(0,t.duration-a.clipEndOffset)),l=e.mixer.clipAction(t),l.setLoop(i.LoopOnce,1),l.clampWhenFinished=!0,l.timeScale=a.playbackRate,a.clipStartOffset>0&&(l.time=a.clipStartOffset),e.activeActions.set(c,l),l.play()}}if(l){const t=e;if(this._externalTimeControl){t.charAnimComponent?.beginExternalControl();const i=(s-a.startTime)*a.playbackRate+a.clipStartOffset,o=Math.min(i,l.getClip().duration);(u||Math.abs(l.time-o)>.001)&&(l.time=o,l.paused=!1,l.play(),t.charAnimComponent?t.charAnimComponent.getMixer()?.update(0):e.mixer&&e.mixer.update(0))}else t.charAnimComponent?.endExternalControl()}}else if(l){e.activeActions.delete(c);const t=e;t.charAnimActionKeys?.has(c)?(t.charAnimActionKeys.delete(c),0===t.charAnimActionKeys.size&&t.charAnimComponent&&(t.charAnimComponent.stopSequenceAnimation(),t.charAnimComponent=void 0)):(l.stop(),this._externalTimeControl&&e.mixer&&e.mixer.update(0))}}}evaluateVisibilitySubTrack(t,e,i){const s=t.keyframes;if(0===s.length)return;let a=s[0];for(const t of s){if(!(t.time<=i))break;a=t}e.visible=a.visible}evaluatePropertySubTrack(t,e,i){}evaluateEventSubTrack(t,e,i){if(e instanceof r&&this._state.value===SequencePlaybackState.Playing)for(const s of t.events){const a=`${t.id}-${s.id}`;if(i>=s.time&&!this.firedEvents.has(a)){if(this.firedEvents.add(a),!s.functionName)continue;const t=e[s.functionName];if("function"==typeof t)try{const i=s.arguments.map(t=>t.value);t.call(e,...i)}catch(t){console.error(`Failed to call sequence event ${s.functionName}:`,t)}else console.warn(`Sequence event method '${s.functionName}' not found on actor`)}else s.time>i&&this.firedEvents.delete(a)}}evaluateCameraTrack(t,e){}evaluateAudioTrack(t,e){if(!this.assetLoader||!t.clips||0===t.clips.length)return;const i=this._state.value===SequencePlaybackState.Playing,s=this.evaluateAudioSubTracks(t,e);t.volume;for(const a of t.clips){const o=a.startTime+a.duration,n=e>=a.startTime&&e<o,r=`${t.id}-${a.id}`;if(n){if(this.activeAudioClips.has(r)||this.activeAudioClips.add(r),i){const i=this.audioByClip.get(r);i&&i.isPlaying||this.tryStartAudioClip(t,a,r,e,s)}const o=this.audioByClip.get(r);o&&this.applyAudioParameters(o,t,a,r,e,s)}else this.activeAudioClips.has(r)&&(this.activeAudioClips.delete(r),this.lastAudioStartAttemptTime.delete(r),this.audioStartInFlight.delete(r),this.stopAudioClip(r))}}tryStartAudioClip(t,e,i,s,a){if(this.audioStartInFlight.has(i))return;const o=this.lastAudioStartAttemptTime.get(i);if(void 0!==o&&s-o<this.audioStartRetryIntervalSeconds)return;this.lastAudioStartAttemptTime.set(i,s);const n=this.playAudioClip(t,e,i,s,a).catch(()=>{}).finally(()=>{this.audioStartInFlight.get(i)===n&&this.audioStartInFlight.delete(i)});this.audioStartInFlight.set(i,n)}applyAudioParameters(t,e,s,a,o,n){const r=n.volume??1,c=this.stringToRandom(a+e.id),l=s.volumeRandomization?(2*c-1)*s.volumeRandomization:0;let u=1;const h=o-s.startTime;h<s.fadeInDuration&&s.fadeInDuration>0?u=h/s.fadeInDuration:h>s.duration-s.fadeOutDuration&&s.fadeOutDuration>0&&(u=(s.duration-h)/s.fadeOutDuration);const d=Math.max(0,(e.volume??1)*r*(s.volume+l)*u);t.setVolume(d);let p=n.detune??0;if(s.pitchRandomization){p+=(2*this.stringToRandom(a+"_pitch")-1)*s.pitchRandomization}if(t.setDetune(p),t.hasPlaybackControl&&t.setPlaybackRate(s.playbackRate*this.timescale),this.audioListener&&this.audioListener.context){const s=this.audioListener.context,o=[],r=n.lowpass,c=n.highpass;let l=this.audioFilters.get(a);if(void 0!==r||void 0!==c)l||(l=s.createBiquadFilter(),this.audioFilters.set(a,l)),void 0!==r?(l.type="lowpass",l.frequency.value=r):void 0!==c&&(l.type="highpass",l.frequency.value=c),o.push(l);else if(l){try{l.disconnect()}catch{}this.audioFilters.delete(a)}const u=n.pan;if(!e.spatial&&t instanceof i.Audio&&void 0!==u&&"function"==typeof s.createStereoPanner){let t=this.audioPannerNodes.get(a);t||(t=s.createStereoPanner(),this.audioPannerNodes.set(a,t)),t.pan.value=u,o.push(t)}else{const t=this.audioPannerNodes.get(a);if(t){try{t.disconnect()}catch{}this.audioPannerNodes.delete(a)}}t.setFilters(o)}e.spatial&&t instanceof i.PositionalAudio?this.updatePositionalAudioTransform(t,e,s,n.spatialBlend):void 0!==n.pan&&this.audioListener}updatePositionalAudioTransform(t,e,s,a){let o=null,n=null;const r=s.attachedToTrackId||e.parent?.trackId,c=s.attachmentSocketName||e.parent?.socketName;if(r){const t=this.sequenceData?.tracks.find(t=>t.id===r);if(t){const e=this.getActiveObjectsForTrack(t);if(e.length>0){const t=e[0];if(o=f,n=g,t.getWorldPosition(o),t.getWorldQuaternion(n),c){const e=this.findSocket(t,c);e&&(e.getWorldPosition(o),e.getWorldQuaternion(n))}}}}if(o&&n){const e="number"==typeof a?i.MathUtils.clamp(a,0,1):1;if(e<1&&this.audioListener){const t=y;this.audioListener.getWorldPosition(t),o=o.clone().lerp(t,1-e)}t.position.copy(o),t.quaternion.copy(n),t.updateMatrixWorld()}}async playAudioClip(t,e,s,a,o){if(!this.assetLoader||!e.audioAssetId||null==this.audioListener)return;if("suspended"===this.audioListener.context.state)try{await this.audioListener.context.resume()}catch(t){return void console.warn("Failed to resume audio context:",t)}this.stopAudioClip(s);const n=this.clearCounter;try{let a=this.audioBuffers.get(e.audioAssetId);if(!a){let t=this.loadingAudioBuffers.get(e.audioAssetId);t||(t=this.assetLoader.getAudioByAssetId(e.audioAssetId),this.loadingAudioBuffers.set(e.audioAssetId,t));try{a=await t,this.audioBuffers.set(e.audioAssetId,a)}finally{this.loadingAudioBuffers.delete(e.audioAssetId)}}if(n!==this.clearCounter)return;const r=this._time.value,c=e.startTime+e.duration;if(!(r>=e.startTime&&r<c))return;const l=Math.max(0,r-e.startTime),u=e.clipStartOffset+l*e.playbackRate;if(u>=a.duration||l>=e.duration)return;let h=this.audioByClip.get(s);const d=!0===t.spatial,p=h&&!0===h.isPositionalAudio;if(h&&d!==p&&(h.isPlaying&&h.stop(),h.disconnect(),this.audioByClip.delete(s),h=void 0),!h){if(d){const t=new i.PositionalAudio(this.audioListener);t.setRefDistance(10),t.setRolloffFactor(1),h=t}else h=new i.Audio(this.audioListener);this.world&&this.world.scene.add(h),this.audioByClip.set(s,h)}Math.min((e.duration-l)/e.playbackRate,(a.duration-u)/e.playbackRate);h.setLoopStart(e.clipStartOffset),h.setLoopEnd(Math.min(e.clipStartOffset+e.duration,a.duration)),h.setLoop(!0),h.setBuffer(a),this.applyAudioParameters(h,t,e,s,r,o),h.isPlaying||h.play()}catch(t){console.error(`Failed to play audio clip ${e.id}:`,t)}}stopAudioClip(t){const e=this.audioByClip.get(t);if(e){try{e.isPlaying&&e.stop()}catch(t){}e.parent&&e.parent.remove(e),this.audioByClip.delete(t)}const i=this.audioGainNodes.get(t);i&&(i.disconnect(),this.audioGainNodes.delete(t));const s=this.audioFilters.get(t);if(s){try{s.disconnect()}catch{}this.audioFilters.delete(t)}const a=this.audioPannerNodes.get(t);if(a){try{a.disconnect()}catch{}this.audioPannerNodes.delete(t)}}stopAllAudio(){for(const t of this.audioByClip.keys())this.stopAudioClip(t);this.activeAudioClips.clear(),this.audioStartInFlight.clear(),this.lastAudioStartAttemptTime.clear()}evaluateVfxTrack(t,e){if(!this.vfxService||!this.world||!t.clips||0===t.clips.length)return;const i=new Set,s=new Map;for(const a of t.clips){const o=a.startTime+a.duration;if(e>=a.startTime&&e<o){const e=`${t.id}-${a.id}-${a.vfxAssetId}`;i.add(e),s.has(e)||s.set(e,a)}}const a=[];for(const e of this.activeVfxClips)e.startsWith(`${t.id}-`)&&(i.has(e)||a.push(e));for(const t of a){this.activeVfxClips.delete(t);const e=this.vfxActors.get(t);e&&!e.paused&&e.stop()}for(const a of i){const i=this.vfxActors.get(a);if(this.activeVfxClips.has(a))i&&(this.updateVfxTransform(t,i,e),this._state.value===SequencePlaybackState.Playing&&i.play());else{this.activeVfxClips.add(a);const e=s.get(a);this.ensureVfxActor(t,e,a)}}}async ensureVfxActor(t,e,i){if(!this.vfxService||!e.vfxAssetId)return;if(this.vfxActors.has(i)){const t=this.vfxActors.get(i);return t.restart(),void t.play()}const s=this.clearCounter;try{const a=await this.vfxService.createFromAssetId(e.vfxAssetId,this.world.scene);if(s!==this.clearCounter)return void(this.world&&this.world.removeActor(a));const{position:o,rotation:n,scale:r}=this.getVfxTransform(t,e.startTime);a.object.position.copy(o),a.object.rotation.copy(n),a.object.scale.copy(r),this.vfxActors.set(i,a),this._state.value===SequencePlaybackState.Playing&&a.play()}catch(t){console.error(`Failed to create VFX actor for clip ${e.id}:`,t)}}getVfxTransform(t,e){const i=new n,s=new a,r=new n(1,1,1),c=t.subTracks.find(t=>"transform"===t.type);if(c&&c.keyframes.length>0){const{prev:t,next:a,t:n}=this.findKeyframes(c.keyframes,e);if(t&&(t.position&&i.fromArray(t.position),t.rotation&&s.fromArray([...t.rotation,"XYZ"]),t.scale&&r.fromArray(t.scale)),a&&t!==a&&t.time!==a.time){const e=this.applyInterpolation(n,t.interpolation);if(t.position&&a.position&&i.lerpVectors(f.fromArray(t.position),m.fromArray(a.position),e),t.rotation&&a.rotation){g.setFromEuler(v.fromArray([...t.rotation,"XYZ"])),A.setFromEuler(b.fromArray([...a.rotation,"XYZ"]));const i=new o;i.slerpQuaternions(g,A,e),s.setFromQuaternion(i)}t.scale&&a.scale&&r.lerpVectors(f.fromArray(t.scale),m.fromArray(a.scale),e)}}else i.fromArray(t.position),s.fromArray([...t.rotation,"XYZ"]),r.fromArray(t.scale);return{position:i,rotation:s,scale:r}}updateVfxTransform(t,e,i){const{position:s,rotation:a,scale:o}=this.getVfxTransform(t,i);e.object.position.copy(s),e.object.rotation.copy(a),e.object.scale.copy(o)}resolveActorType(t){const e=this.actorFactory.classes[t];if(null!=e)return e;const i=c[t];return i||(console.warn(`Could not resolve actor type: ${t}`),null)}async spawnActorForClip(t,e,i,s){if(!this.world||!t.actorType)return null;const a=this.resolveActorType(t.actorType);if(!a)return null;try{return await this.world.spawnActor(a,i,s)}catch(e){return console.error(`Failed to spawn actor ${t.actorType}:`,e),null}}async spawnPrefabForClip(t,e,i,s){if(!this.world||!this.assetLoader||!t.prefabId)return null;try{const e=await this.assetLoader.getPrefabById(t.prefabId);if(!e)return null;return await this.world.spawnPrefab(e,i,s)}catch(e){return console.error(`Failed to spawn prefab ${t.prefabId}:`,e),null}}async spawnMeshForClip(t,e,i,s){if(!this.world||!this.assetLoader||!t.meshId)return null;try{const e=await this.assetLoader.getAsset(t.meshId),a=await this.assetLoader.getModelByAssetId(t.meshId),o=u.clone(a.scene);if(o.position.copy(i),o.rotation.copy(s),e){await this.assetLoader.applyMaterials(e,o);const t=e.mesh?.rescale;null!=t&&1!==t&&o.scale.multiplyScalar(t)}return this.world.scene.add(o),o}catch(e){return console.error(`Failed to spawn mesh ${t.meshId}:`,e),null}}despawnInstance(t){if(this.world)switch(t?.type){case"actor":this.world.removeActor(t.instance);break;case"prefab":this.world.removePrefab(t.instance);break;case"mesh":this.world.scene.remove(t.instance)}}despawnAll(){for(const t of this.spawnedInstances.values())this.despawnInstance(t);this.spawnedInstances.clear(),this.activeClips.clear(),this.pendingSpawns.clear()}getInitialTransform(t,e,i){const s=new n,o=new a,r=t.subTracks.find(t=>"transform"===t.type);if(r&&r.keyframes.length>0){const{prev:t}=this.findKeyframes(r.keyframes,i);t&&(t.position&&s.fromArray(t.position),t.rotation&&o.fromArray([...t.rotation,"XYZ"]))}else e.initialPosition&&s.fromArray(e.initialPosition),e.initialRotation&&o.fromArray([...e.initialRotation,"XYZ"]);return{position:s,rotation:o}}evaluateSpawnTrack(t,e,i){if(!t.clips||0===t.clips.length)return;const s=e||this.bindings.get(t.id);if(s&&s.target)for(const e of t.clips){const a=e.startTime+e.duration,o=i>=e.startTime&&i<a,n=`${t.id}-${e.id}`;if(o){this.activeClips.has(n)||(this.activeClips.add(n),this.spawnedInstances.set(n,{type:"proxy",target:s.target}));(s.target instanceof r?s.target.object:s.target)&&this.evaluateSubTracks(t.subTracks,s,i)}else this.activeClips.has(n)&&(this.activeClips.delete(n),this.spawnedInstances.delete(n))}else for(const e of t.clips){const s=e.startTime+e.duration,a=i>=e.startTime&&i<s,o=`${t.id}-${e.id}`,n=this.spawnedInstances.has(o),r=this.pendingSpawns.has(o);if(!a||n||r){if(a&&n){const e=this.spawnedInstances.get(o);e&&"proxy"!==e.type&&this.evaluateSubTracks(t.subTracks,e,i)}else if(!a&&n){const t=this.spawnedInstances.get(o);t&&(this.despawnInstance(t),this.spawnedInstances.delete(o),this.activeClips.delete(o))}}else{const{position:i,rotation:s}=this.getInitialTransform(t,e,e.startTime);this.pendingSpawns.add(o),this.spawnForClip(t,e,i,s,o)}}}getInstanceObject(t){switch(t.type){case"actor":return t.instance.object;case"prefab":return t.instance.mainActor?.object||t.instance.object;case"mesh":return t.instance;case"proxy":return t.target instanceof r?t.target.object:t.target;default:return null}}async spawnForClip(t,e,i,a,o){const n=this.clearCounter;let r=null;try{switch(t.spawnType){case"actor":const s=await this.spawnActorForClip(t,e,i,a);s&&(r={type:"actor",instance:s});break;case"prefab":const o=await this.spawnPrefabForClip(t,e,i,a);o&&(r={type:"prefab",instance:o});break;case"mesh":const n=await this.spawnMeshForClip(t,e,i,a);n&&(r={type:"mesh",instance:n})}if(n!==this.clearCounter)return void(r&&this.despawnInstance(r));const c=this._time.value,l=c>=e.startTime&&c<e.startTime+e.duration;if(r&&l){const e=this.getInstanceObject(r);"proxy"===r.type||("actor"===r.type?r.target=r.instance:"prefab"===r.type?r.target=r.instance.mainActor||r.instance.object:r.target=e);t.subTracks.some(t=>"animation"===t.type)&&e&&(r.mixer=new s(e),r.activeActions=new Map),this.spawnedInstances.set(o,r),this.activeClips.add(o)}else r&&this.despawnInstance(r)}finally{this.pendingSpawns.delete(o)}}findKeyframes(t,e){if(0===t.length)return{prev:null,next:null,t:0};let i=null,s=null;for(let a=0;a<t.length;a++)if(t[a].time<=e&&(i=t[a]),t[a].time>e&&!s){s=t[a];break}if(i||(i=t[0]),s||(s=t[t.length-1]),i===s||i.time===s.time)return{prev:i,next:i,t:0};return{prev:i,next:s,t:(e-i.time)/(s.time-i.time)}}applyInterpolation(t,e){switch(e){case"linear":case"catmullRom":default:return t;case"step":return 0;case"cubic":return t<.5?4*t*t*t:1-Math.pow(-2*t+2,3)/2}}async ensureAnimationClip(t){if(this.assetLoader&&!this.animationClips.has(t)&&!this.loadingAnimationClips.has(t)){this.loadingAnimationClips.add(t);try{const e=await this.assetLoader.getAnimationClipByAssetId(t);e&&this.animationClips.set(t,e)}catch(e){console.error(`Failed to load animation clip for asset ${t}:`,e)}finally{this.loadingAnimationClips.delete(t)}}}captureOriginalTransforms(){for(const t of this.bindings.values()){const e=t.target instanceof r?t.target.object:t.target;e&&(t.originalTransform={position:e.position.clone(),rotation:e.rotation.clone(),scale:e.scale.clone()})}}restoreOriginalTransforms(){for(const t of this.bindings.values())if(t.originalTransform){const e=t.target instanceof r?t.target.object:t.target;e&&(e.position.copy(t.originalTransform.position),e.rotation.copy(t.originalTransform.rotation),e.scale.copy(t.originalTransform.scale))}}stopAllAnimations(){for(const t of this.bindings.values()){for(const e of t.activeActions.values())e.stop();t.activeActions.clear(),t.mixer&&t.mixer.stopAllAction(),t.charAnimComponent&&(t.charAnimComponent.stopSequenceAnimation(),t.charAnimComponent=void 0),t.charAnimActionKeys?.clear()}}stopAllVfx(){for(const t of this.vfxActors.values())t.paused||t.stop();this.activeVfxClips.clear()}dispose(){if(this.stop(),this.bindings.clear(),this.roleBindings.clear(),this.sequenceData=null,this.world)for(const t of this.vfxActors.values())this.world.removeActor(t);this.vfxActors.clear(),this.stopAllAudio(),this.audioBuffers.clear(),this.loadingAudioBuffers.clear(),this.animationClips.clear(),this.audioByClip.clear()}updateTrackParenting(t,e){const i=this.getActiveObjectsForTrack(t);if(0===i.length)return;let s=null;const a=t.parent?.trackId;if(a){const e=this.sequenceData?.tracks.find(t=>t.id===a);if(e){const i=this.getActiveObjectsForTrack(e);if(i.length>0&&(s=i[0],t.parent?.socketName)){const e=s.getObjectByName(t.parent.socketName);e&&(s=e)}}}for(const a of i)s?a.parent!==s&&(s.add(a),e&&"object"===t.type&&(e.currentParent=s)):e?.currentParent&&e.currentParent===a.parent?this.restoreObjectParent(e,a):a.parent&&a.parent!==this.world?.scene&&"object"!==t.type&&this.world?.scene.add(a)}findSocket(t,e){if(t.name===e)return t;if(t instanceof i.SkinnedMesh){const i=t.skeleton.bones.find(t=>t.name===e);if(i)return i}return t.getObjectByName(e)||null}getActiveObjectsForTrack(t){if("object"===t.type){const e=this.bindings.get(t.id);if(e&&e.target)return[e.target instanceof r?e.target.object:e.target]}else{if("spawn"===t.type){const e=[];for(const[i,s]of this.spawnedInstances)if(i.startsWith(t.id+"-")&&this.activeClips.has(i)){const t=this.getInstanceObject(s);t&&e.push(t)}return e}if("vfx"===t.type){const e=[];for(const i of this.activeVfxClips)if(i.startsWith(t.id+"-")){const t=this.vfxActors.get(i);t&&e.push(t.object)}return e}}return[]}restoreObjectParent(t,e){t.originalParent?t.originalParent.add(e):this.world&&this.world.scene.add(e),t.currentParent=void 0}restoreOriginalParents(){for(const t of this.bindings.values())if(t.currentParent){const e=t.target instanceof r?t.target.object:t.target;e&&this.restoreObjectParent(t,e)}}evaluateAudioSubTracks(t,e){const i={};for(const s of t.subTracks)if("audioParameter"===s.type){const t=s,a=s.keyframes;if(0===a.length)continue;const{prev:o,next:n,t:r}=this.findKeyframes(a,e);if(!o)continue;let c;if(n&&o!==n){const t=o.value.value,e=n.value.value;if("step"===o.interpolation)c=t;else if("cubic"===o.interpolation){c=t+(e-t)*(r*r*(3-2*r))}else c=t+(e-t)*r}else c=o.value.value;if("number"==typeof c){const e=l(t.parameter),i=e.min,s=e.max;"number"==typeof i&&(c=Math.max(i,c)),"number"==typeof s&&(c=Math.min(s,c))}void 0!==c&&(i[t.parameter]=c)}return i}stringToRandom(t){let e=0;for(let i=0;i<t.length;i++){e=(e<<5)-e+t.charCodeAt(i),e&=e}const i=1e4*Math.sin(e);return i-Math.floor(i)}}const f=new n,m=new n,y=new n,g=new o,A=new o,v=new a,b=new a;/*
2
+ * Copyright (©) 2026 Hology Interactive AB. All rights reserved.
3
+ * See the LICENSE.md file for details.
4
+ */
@@ -0,0 +1,7 @@
1
+ import { Sequence } from "./sequence-data.js";
2
+ import { SequenceAction } from "./sequence-action.js";
3
+ export declare class Sequencer {
4
+ private world;
5
+ action(sequence: Sequence): SequenceAction;
6
+ }
7
+ //# sourceMappingURL=sequencer.d.ts.map
@@ -0,0 +1,4 @@
1
+ import{__decorate as t}from"tslib";import{Service as r}from"typedi";import{inject as o}from"../../gameplay/inject.js";import{World as e}from"../../gameplay/services/world.js";import{SequenceActor as s}from"./sequence-actor.js";let a=class{constructor(){this.world=o(e)}action(t){const r=this.world.spawnActorSync(s);return r.setSequenceData(t.data),r}};a=t([r()],a);export{a as Sequencer};/*
2
+ * Copyright (©) 2026 Hology Interactive AB. All rights reserved.
3
+ * See the LICENSE.md file for details.
4
+ */
@@ -10,13 +10,16 @@ export declare class Trail extends THREE.Object3D {
10
10
  scene: any;
11
11
  geometry: THREE.BufferGeometry | null;
12
12
  mesh: THREE.Mesh | null;
13
- nodeCenters: Array<THREE.Vector3>;
14
- lastNodeCenter: THREE.Vector3 | null;
15
- currentNodeCenter: THREE.Vector3 | null;
16
- lastOrientationDir: THREE.Vector3 | null;
17
- nodeIDs: Array<number>;
18
- currentLength: number;
19
- currentEnd: number;
13
+ historyCount: number;
14
+ historyHeadIndex: number;
15
+ history: Array<{
16
+ position: THREE.Vector3;
17
+ tangent: THREE.Vector3;
18
+ transformMatrix: THREE.Matrix4;
19
+ id: number;
20
+ }>;
21
+ renderNodeCount: number;
22
+ subdivisions: number;
20
23
  currentNodeID: number;
21
24
  advanceFrequency: number;
22
25
  advancePeriod: number;
@@ -47,18 +50,19 @@ export declare class Trail extends THREE.Object3D {
47
50
  setAllNodesToCurrentTargetPosition(): void;
48
51
  updateUniforms(): void;
49
52
  advance: () => void;
50
- advanceWithPositionAndOrientation(nextPosition: any, orientationTangent: any): void;
51
- advanceWithTransform(transformMatrix: any): void;
52
- advanceGeometry: (positionAndOrientation: any, transformMatrix: any) => void;
53
+ advanceWithTransform(transformMatrix: THREE.Matrix4): void;
54
+ updateHead(): void;
55
+ getControlPoint(index: number): {
56
+ position: THREE.Vector3;
57
+ tangent: THREE.Vector3;
58
+ transformMatrix: THREE.Matrix4;
59
+ id: number;
60
+ };
61
+ rebuildGeometry(): void;
53
62
  currentTime(): number;
54
63
  pause(): void;
55
64
  resume(): void;
56
65
  update(): void;
57
- updateHead: () => void;
58
- updateNodeID(nodeIndex: any, id: any): void;
59
- updateNodeCenter(nodeIndex: any, nodeCenter: any): void;
60
- updateNodePositionsFromOrientationTangent: (nodeIndex: any, nodeCenter: any, orientationTangent: any) => void;
61
- updateNodePositionsFromTransformMatrix: (nodeIndex: any, transformMatrix: any) => void;
62
66
  connectNodes: (srcNodeIndex: number, destNodeIndex: number) => {
63
67
  attribute: any;
64
68
  offset: number;
@@ -1,4 +1,4 @@
1
- import{timeUniforms as e}from"../../shader-nodes";import*as t from"three";import{NodeShaderMaterial as r,uniformBool as i,uniformFloat as n,uniformVec2 as a,mix as s,uniformVec4 as o,attributeFloat as h,attributeVec3 as l,select as c,float as d,textureSampler2d as u,attributes as m,uniforms as g,rgba as y,vec4 as p,varying as f,vec2 as x,normalize as v,vec3 as T,cross as V,max as C,length as P}from"three-shader-graph";n("trailLength");const N=n("verticesPerNode"),b=n("minID"),D=n("maxID"),w=(n("dragTexture"),n("maxTrailLength")),F=a("textureTileFactor",new t.Vector2(1,1)),I=o("headColor",new t.Vector4),U=o("tailColor",new t.Vector4),A=i("taper",!1),L=(n("scale",1),h("nodeID")),O=h("nodeVertexID"),M=l("nodeCenter"),B=D.subtract(L).divide(D.subtract(b)),S=c(A,B,d(0)),z=f(d(1).subtract(B).multiplyVec4(I).add(B.multiplyVec4(U))),H=v(g.cameraPosition.subtract(M)),G=v(l("nodeTangent")),j=n("width",1),E=v(V(c(P(G).gt(d(.1)),G,T(1,0,0)),H)).multiplyScalar(O.subtract(d(.5))).multiplyScalar(j),R=p(d(1).subtract(S).multiplyVec3(E).add(C(S,d(1)).multiplyVec3(M)),1),W=p(d(1).subtract(S).multiplyVec3(m.position).add(S.multiplyVec3(M)),1),q=g.projectionMatrix.multiply(g.viewMatrix).multiplyVec(R),_=g.projectionMatrix.multiply(g.viewMatrix).multiplyVec(W);export const trailUV=f(x(B.multiply(F.x),O.divide(N).multiply(F.y).multiply(2)));export const trailDragUV=f(x(L.divide(w).multiply(F.x),O.divide(N).multiply(F.y).multiply(2)));export class Trail extends t.Object3D{constructor(e,r){super(),this.nodeCenters=[],this.nodeIDs=[],this.advance=function(){const e=new t.Matrix4;return function(){this.targetObject.updateMatrixWorld(),e.copy(this.targetObject.matrixWorld),this.advanceWithTransform(e),this.updateUniforms()}}(),this.advanceGeometry=function(e,t){const r=this.currentEnd+1>=this.length?0:this.currentEnd+1;if(t?this.updateNodePositionsFromTransformMatrix(r,t):this.updateNodePositionsFromOrientationTangent(r,e.position,e.tangent),this.currentLength>=1&&(this.connectNodes(this.currentEnd,r),this.currentLength>=this.length)){const e=this.currentEnd+1>=this.length?0:this.currentEnd+1;this.disconnectNodes(e)}this.currentLength<this.length&&this.currentLength++,this.currentEnd++,this.currentEnd>=this.length&&(this.currentEnd=0),this.currentLength>=1?(this.currentLength<this.length?this.geometry.setDrawRange(0,(this.currentLength-1)*this.FaceIndicesPerNode):this.geometry.setDrawRange(0,this.currentLength*this.FaceIndicesPerNode),this.mesh&&(this.mesh.visible=!0)):(this.geometry.setDrawRange(0,0),this.mesh&&(this.mesh.visible=!1)),this.updateNodeID(this.currentEnd,this.currentNodeID),this.currentNodeID++},this.updateHead=function(){const e=new t.Matrix4;return function(){this.currentEnd<0||(this.targetObject.updateMatrixWorld(),e.copy(this.targetObject.matrixWorld),this.updateNodePositionsFromTransformMatrix(this.currentEnd,e))}}(),this.updateNodePositionsFromOrientationTangent=function(){const e=new t.Quaternion,r=new t.Vector3,i=[];for(let e=0;e<Trail.MaxHeadVertices;e++){const e=new t.Vector3;i.push(e)}return function(t,n,a){const s=this.geometry.getAttribute("position");this.updateNodeCenter(t,n),r.copy(n),r.sub(Trail.LocalHeadOrigin),e.setFromUnitVectors(Trail.LocalOrientationTangent,a);for(let t=0;t<this.localHeadGeometry.length;t++){const n=i[t];n.copy(this.localHeadGeometry[t]),n.applyQuaternion(e),n.add(r)}for(let e=0;e<this.localHeadGeometry.length;e++){const r=(this.VerticesPerNode*t+e)*Trail.PositionComponentCount,n=i[e];s.array[r]=n.x,s.array[r+1]=n.y,s.array[r+2]=n.z}s.needsUpdate=!0}}(),this.updateNodePositionsFromTransformMatrix=function(){const e=new t.Matrix3,r=new t.Quaternion,i=new t.Vector3,n=new t.Vector3,a=new t.Vector3,s=new t.Vector3,o=new t.Box3,h=new t.Vector3,l=[];for(let e=0;e<Trail.MaxHeadVertices;e++){const e=new t.Vector3;l.push(e)}const c=new t.Vector3(1,0,0);return function(d,u){const m=this.geometry.getAttribute("position");i.set(0,0,0),i.applyMatrix4(u),this.updateNodeCenter(d,i);for(let e=0;e<this.localHeadGeometry.length;e++){l[e].copy(this.localHeadGeometry[e])}for(let e=0;e<this.localHeadGeometry.length;e++){l[e].applyMatrix4(u)}if(this.lastNodeCenter&&this.orientToMovement&&(function(e,t){const r=t.elements;e.set(r[0],r[1],r[2],r[4],r[5],r[6],r[8],r[9],r[10])}(e,u),a.set(0,0,-1),a.applyMatrix3(e),s.copy(this.currentNodeCenter),s.sub(this.lastNodeCenter),s.normalize(),s.lengthSq()<=1e-4&&this.lastOrientationDir&&s.copy(this.lastOrientationDir),s.lengthSq()>1e-4)){this.lastOrientationDir||(this.lastOrientationDir=new t.Vector3),r.setFromUnitVectors(a,s),n.copy(this.currentNodeCenter);for(let e=0;e<this.localHeadGeometry.length;e++){const t=l[e];t.sub(n),t.applyQuaternion(r),t.add(n)}}this.billboard&&(this.lastNodeCenter&&this.currentNodeCenter&&!this.currentNodeCenter.equals(this.lastNodeCenter)?(c.copy(this.currentNodeCenter).sub(this.lastNodeCenter),c.normalize(),this.lastOrientationDir||(this.lastOrientationDir=new t.Vector3),this.lastOrientationDir.copy(c)):this.lastOrientationDir?c.copy(this.lastOrientationDir):(c.set(1,0,0),c.applyMatrix4(u),c.normalize(),this.lastOrientationDir||(this.lastOrientationDir=new t.Vector3),this.lastOrientationDir.copy(c)));const g=this.geometry.getAttribute("nodeTangent");for(let e=0;e<this.localHeadGeometry.length;e++){const t=(this.VerticesPerNode*d+e)*Trail.PositionComponentCount,r=l[e];this.billboard?(g.array[t]=c.x,g.array[t+1]=c.y,g.array[t+2]=c.z):(m.array[t]=r.x,m.array[t+1]=r.y,m.array[t+2]=r.z)}if(this.billboard?(this.mesh.frustumCulled=!1,g.needsUpdate=!0,g.addUpdateRange(d*this.VerticesPerNode*Trail.PositionComponentCount,this.VerticesPerNode*Trail.PositionComponentCount)):(m.needsUpdate=!0,m.addUpdateRange(d*this.VerticesPerNode*Trail.PositionComponentCount,this.VerticesPerNode*Trail.PositionComponentCount)),o.makeEmpty(),this.billboard)for(let e=0;e<this.currentLength;e++){const r=(this.currentEnd-e+this.length)%this.length,i=this.nodeCenters[r];if(i){const e=this.material.uniforms.width?.5*this.material.uniforms.width.value:.5;o.expandByPoint(i.clone().add(new t.Vector3(e,e,e))),o.expandByPoint(i.clone().sub(new t.Vector3(e,e,e)))}}else for(let e=0;e<this.currentLength*this.VerticesPerNode;e++){const t=3*e;h.set(m.array[t],m.array[t+1],m.array[t+2]),o.expandByPoint(h)}this.mesh.visible=!o.isEmpty(),null==this.geometry.boundingBox&&(this.geometry.boundingBox=new t.Box3),this.geometry.boundingBox.copy(o),null==this.geometry.boundingSphere&&(this.geometry.boundingSphere=new t.Sphere),this.geometry.boundingBox.getBoundingSphere(this.geometry.boundingSphere)}}(),this.connectNodes=(()=>{const e={attribute:null,offset:0,count:-1};return(t,r)=>{const i=this.geometry.getIndex();for(let e=0;e<this.localHeadGeometry.length-1;e++){const n=this.VerticesPerNode*t+e,a=this.VerticesPerNode*r+e,s=(t*this.FacesPerNode+e*Trail.FacesPerQuad)*Trail.IndicesPerFace;i.array[s]=n,i.array[s+1]=a,i.array[s+2]=n+1,i.array[s+3]=a,i.array[s+4]=a+1,i.array[s+5]=n+1}return i.needsUpdate=!0,i.clearUpdateRanges(),e.attribute=i,e.offset=t*this.FacesPerNode*Trail.IndicesPerFace,e.count=this.FacesPerNode*Trail.IndicesPerFace,e}})(),this.disconnectNodes=(()=>{const e={attribute:null,offset:0,count:-1};return t=>{const r=this.geometry.getIndex();for(let e=0;e<this.localHeadGeometry.length-1;e++){const i=(t*this.FacesPerNode+e*Trail.FacesPerQuad)*Trail.IndicesPerFace;r.array[i]=0,r.array[i+1]=0,r.array[i+2]=0,r.array[i+3]=0,r.array[i+4]=0,r.array[i+5]=0}return r.needsUpdate=!0,r.clearUpdateRanges(),e.attribute=r,e.offset=t*this.FacesPerNode*Trail.IndicesPerFace,e.count=this.FacesPerNode*Trail.IndicesPerFace,e}})(),this.active=!1,this.orientToMovement=!1,r&&(this.orientToMovement=!0),this.scene=e,this.geometry=null,this.mesh=null,this.nodeCenters=[],this.lastNodeCenter=null,this.currentNodeCenter=null,this.lastOrientationDir=null,this.nodeIDs=[],this.currentLength=0,this.currentEnd=0,this.currentNodeID=0,this.advanceFrequency=60,this.advancePeriod=1/this.advanceFrequency,this.lastAdvanceTime=0,this.paused=!1,this.pauseAdvanceUpdateTimeDiff=0}setAdvanceFrequency(e){this.advanceFrequency=e,this.advancePeriod=1/this.advanceFrequency}initialize(e,r,i,n,a,s,o=!1){this.deactivate(),this.destroyMesh(),this.length=r>0?r+1:0,this.dragTexture=i?1:0,this.targetObject=s,this.billboard=o,this.initializeLocalHeadGeometry(n,a),null!=e.uniforms.width&&(e.uniforms.width.value=n),this.nodeIDs=[],this.nodeCenters=[];for(let e=0;e<this.length;e++)this.nodeIDs[e]=-1,this.nodeCenters[e]=new t.Vector3;this.setAllNodesToCurrentTargetPosition(),this.material=e,this.initializeGeometry(),this.initializeMesh(),this.material.uniforms.dragTexture&&(this.material.uniforms.trailLength.value=0),this.material.uniforms.minID.value=0,this.material.uniforms.maxID.value=0,this.material.uniforms.dragTexture&&(this.material.uniforms.dragTexture.value=this.dragTexture),this.material.uniforms.maxTrailLength&&(this.material.uniforms.maxTrailLength.value=this.length),this.material.uniforms.verticesPerNode&&(this.material.uniforms.verticesPerNode.value=this.VerticesPerNode),this.material.uniforms.textureTileFactor&&(this.material.uniforms.textureTileFactor.value=new t.Vector2(1,1)),this.material.uniforms.scale&&(this.material.uniforms.scale.value=1),this.reset()}initializeLocalHeadGeometry(e,r){if(this.localHeadGeometry=[],r){this.VerticesPerNode=0;for(let e=0;e<r.length&&e<Trail.MaxHeadVertices;e++){const i=r[e];if(i&&i instanceof t.Vector3){const e=new t.Vector3;e.copy(i),this.localHeadGeometry.push(e),this.VerticesPerNode++}}}else{const r=(e||1)/2;this.localHeadGeometry.push(new t.Vector3(-r,0,0)),this.localHeadGeometry.push(new t.Vector3(r,0,0)),this.VerticesPerNode=2}this.FacesPerNode=2*(this.VerticesPerNode-1),this.FaceIndicesPerNode=3*this.FacesPerNode}initializeGeometry(){this.vertexCount=this.length*this.VerticesPerNode,this.faceCount=this.length*this.FacesPerNode;const e=new t.BufferGeometry,r=new Float32Array(this.vertexCount),i=new Float32Array(this.vertexCount*this.VerticesPerNode),n=new Float32Array(this.vertexCount*Trail.PositionComponentCount),a=new Float32Array(this.vertexCount*Trail.PositionComponentCount),s=new Float32Array(this.vertexCount*Trail.UVComponentCount),o=new Uint32Array(this.faceCount*Trail.IndicesPerFace),h=new Float32Array(3*this.vertexCount),l=new t.BufferAttribute(h,3);l.setUsage(t.DynamicDrawUsage),e.setAttribute("nodeTangent",l);const c=new t.BufferAttribute(r,1);c.setUsage(t.DynamicDrawUsage),e.setAttribute("nodeID",c);const d=new t.BufferAttribute(i,1);d.setUsage(t.DynamicDrawUsage),e.setAttribute("nodeVertexID",d);const u=new t.BufferAttribute(a,Trail.PositionComponentCount);u.setUsage(t.DynamicDrawUsage),e.setAttribute("nodeCenter",u);const m=new t.BufferAttribute(n,Trail.PositionComponentCount);m.setUsage(t.DynamicDrawUsage),e.setAttribute("position",m);const g=new t.BufferAttribute(s,Trail.UVComponentCount);g.setUsage(t.DynamicDrawUsage),e.setAttribute("uv",g);const y=new t.BufferAttribute(o,1);y.setUsage(t.DynamicDrawUsage),e.setIndex(y),this.geometry=e}zeroVertices(){const e=this.geometry.getAttribute("position");for(let t=0;t<this.vertexCount;t++){const r=3*t;e.array[r]=0,e.array[r+1]=0,e.array[r+2]=0}e.needsUpdate=!0}zeroIndices(){if(null==this.geometry)throw"Geometry not initialized";const e=this.geometry.getIndex();for(let t=0;t<this.faceCount;t++){const r=3*t;e.array[r]=0,e.array[r+1]=0,e.array[r+2]=0}e.needsUpdate=!0,e.clearUpdateRanges()}formInitialFaces(){this.zeroIndices();const e=this.geometry.getIndex();for(let e=0;e<this.length-1;e++)this.connectNodes(e,e+1);e.needsUpdate=!0,e.clearUpdateRanges()}initializeMesh(){if(null==this.geometry)throw"Geometry not initialized";this.mesh=new t.Mesh(this.geometry,this.material),this.mesh.matrixAutoUpdate=!1,this.mesh.visible=!1}destroyMesh(){this.mesh&&(this.scene.remove(this.mesh),this.mesh=null)}reset(){this.currentLength=0,this.currentEnd=-1,this.lastNodeCenter=null,this.currentNodeCenter=null,this.lastOrientationDir=null,this.currentNodeID=0,this.formInitialFaces(),this.zeroVertices(),this.geometry.setDrawRange(0,0),this.setAllNodesToCurrentTargetPosition(),this.mesh&&(this.mesh.visible=!0)}setAllNodesToCurrentTargetPosition(){if(!this.targetObject)return;const e=new t.Vector3;this.targetObject.getWorldPosition(e);for(let t=0;t<this.length;t++)this.nodeCenters[t].copy(e);if(this.billboard&&this.geometry){const e=this.geometry.getAttribute("nodeTangent"),r=new t.Vector3(1,0,0);this.targetObject.matrixWorld&&(r.applyMatrix4(this.targetObject.matrixWorld),r.normalize());for(let t=0;t<this.vertexCount;t++){const i=3*t;e.array[i]=r.x,e.array[i+1]=r.y,e.array[i+2]=r.z}e.needsUpdate=!0}}updateUniforms(){this.currentLength<this.length?this.material.uniforms.minID.value=0:this.material.uniforms.minID.value=this.currentNodeID-this.length,this.material.uniforms.maxID.value=this.currentNodeID,this.material.uniforms.trailLength&&(this.material.uniforms.trailLength.value=this.currentLength),this.material.uniforms.maxTrailLength&&(this.material.uniforms.maxTrailLength.value=this.length),this.material.uniforms.verticesPerNode&&(this.material.uniforms.verticesPerNode.value=this.VerticesPerNode)}advanceWithPositionAndOrientation(e,t){this.advanceGeometry({position:e,tangent:t},null)}advanceWithTransform(e){this.advanceGeometry(null,e)}currentTime(){return performance.now()/1e3}pause(){this.paused||(this.paused=!0,this.pauseAdvanceUpdateTimeDiff=this.currentTime()-this.lastAdvanceTime)}resume(){this.paused&&(this.paused=!1,this.lastAdvanceTime=this.currentTime()-this.pauseAdvanceUpdateTimeDiff)}update(){if(!this.paused){const e=this.currentTime();this.lastAdvanceTime||(this.lastAdvanceTime=e),e-this.lastAdvanceTime>this.advancePeriod?(this.advance(),this.lastAdvanceTime=e):this.updateHead()}}updateNodeID(e,t){this.nodeIDs[e]=t;const r=this.geometry.getAttribute("nodeID"),i=this.geometry.getAttribute("nodeVertexID");for(let n=0;n<this.VerticesPerNode;n++){const a=e*this.VerticesPerNode+n;r.array[a]=t,i.array[a]=n}r.needsUpdate=!0,i.needsUpdate=!0,r.addUpdateRange(e*this.VerticesPerNode,this.VerticesPerNode),i.addUpdateRange(e*this.VerticesPerNode,this.VerticesPerNode)}updateNodeCenter(e,t){this.lastNodeCenter=this.currentNodeCenter,this.currentNodeCenter=this.nodeCenters[e],this.currentNodeCenter.copy(t);const r=this.geometry.getAttribute("nodeCenter");for(let i=0;i<this.VerticesPerNode;i++){const n=3*(e*this.VerticesPerNode+i);r.array[n]=t.x,r.array[n+1]=t.y,r.array[n+2]=t.z}r.needsUpdate=!0,r.updateRanges=[{start:e*this.VerticesPerNode*Trail.PositionComponentCount,count:this.VerticesPerNode*Trail.PositionComponentCount}]}deactivate(){this.active&&(this.scene.remove(this.mesh),this.active=!1)}activate(){this.active||(this.scene.add(this.mesh),this.active=!0)}static getTrailShaderNodes(e){return{position:e?q:_,color:z,fraction:B}}static applyTrailShaderParameters(e){e.transparent=!0,e.alphaTest=.5,e.blending=t.CustomBlending,e.blendSrc=t.SrcAlphaFactor,e.blendDst=t.OneMinusSrcAlphaFactor,e.blendEquation=t.AddEquation,e.depthTest=!0,e.depthWrite=!1,e.side=t.DoubleSide}static createBaseMaterial(t,i,n,a=!1){let{position:o}=Trail.getTrailShaderNodes(a),h=s(I,U,B).rgba,l=h.a;if(null!=t){let r=trailUV;null!=i&&(r=r.add(x(e.elapsed.multiply(-i),0)));const a=u(t).sample(r);switch(n??"red"){case"none":break;case"red":l=l.multiply(a.r);break;case"alpha":l=l.multiply(a.a)}h=y(h.rgb.multiply(a.rgb),l)}const c=new r({position:o,opacity:l,color:h});return Trail.applyTrailShaderParameters(c),c}static get MaxHeadVertices(){return 128}static get LocalOrientationTangent(){return Trail._LocalOrientationTangent}static get LocalHeadOrigin(){return Trail._LocalHeadOrigin}static get PositionComponentCount(){return 3}static get UVComponentCount(){return 2}static get IndicesPerFace(){return 3}static get FacesPerQuad(){return 2}}Trail._LocalOrientationTangent=new t.Vector3(1,0,0),Trail._LocalHeadOrigin=new t.Vector3(0,0,0),Trail.Shader={get BaseVertexVars(){return["attribute float nodeID;","attribute float nodeVertexID;","attribute vec3 nodeCenter;","uniform float minID;","uniform float maxID;","uniform float trailLength;","uniform float maxTrailLength;","uniform float verticesPerNode;","uniform vec2 textureTileFactor;","uniform bool taper;","uniform vec4 headColor;","uniform vec4 tailColor;","varying vec4 vColor;"].join("\n")},get TexturedVertexVars(){return[this.BaseVertexVars,"varying vec2 vUV;","uniform float dragTexture;"].join("\n")},BaseFragmentVars:["varying vec4 vColor;","uniform sampler2D trailTexture;"].join("\n"),get TexturedFragmentVars(){return[this.BaseFragmentVars,"varying vec2 vUV;"].join("\n")},get VertexShaderCore(){return["float fraction = (maxID - nodeID) / (maxID - minID);","float fractionSize = taper ? fraction : 0.0;","vColor = (1.0 - fraction) * headColor + fraction * tailColor;","vec4 realPosition = vec4((1.0 - fractionSize) * position.xyz + fractionSize * nodeCenter.xyz, 1.0); "].join("\n")},get BaseVertexShader(){return[this.BaseVertexVars,"void main() { ",this.VertexShaderCore,"gl_Position = projectionMatrix * viewMatrix * realPosition;","}"].join("\n")},get BaseFragmentShader(){return[this.BaseFragmentVars,"void main() { ","gl_FragColor = vColor;","}"].join("\n")},get TexturedVertexShader(){return[this.TexturedVertexVars,"void main() { ",this.VertexShaderCore,"float s = 0.0;","float t = 0.0;","if (dragTexture == 1.0) { "," s = fraction * textureTileFactor.s; "," t = (nodeVertexID / verticesPerNode) * textureTileFactor.t;","} else { "," s = nodeID / maxTrailLength * textureTileFactor.s;"," t = (nodeVertexID / verticesPerNode) * textureTileFactor.t;","}","vUV = vec2(s, t); ","gl_Position = projectionMatrix * viewMatrix * realPosition;","}"].join("\n")},get TexturedFragmentShader(){return[this.TexturedFragmentVars,"void main() { ","vec4 textureColor = texture2D(trailTexture, vUV);","gl_FragColor = vColor * textureColor;","}"].join("\n")}};/*
1
+ import{timeUniforms as t}from"../../shader-nodes/index.js";import*as e from"three";import{NodeShaderMaterial as i,uniformBool as r,uniformFloat as o,uniformVec2 as s,mix as a,uniformVec4 as n,attributeFloat as h,attributeVec3 as l,select as d,float as u,textureSampler2d as c,attributes as m,uniforms as y,rgba as g,vec4 as p,varying as x,vec2 as f,normalize as v,vec3 as b,cross as T,max as C,length as V}from"three-shader-graph";o("trailLength");const P=o("verticesPerNode"),w=o("minID"),F=o("maxID"),I=(o("dragTexture"),o("maxTrailLength")),D=s("textureTileFactor",new e.Vector2(1,1)),N=n("headColor",new e.Vector4),U=n("tailColor",new e.Vector4),A=r("taper",!1),M=(o("scale",1),h("nodeID")),z=h("nodeVertexID"),B=l("nodeCenter"),H=F.subtract(M).divide(F.subtract(w)),S=d(A,H,u(0)),j=x(u(1).subtract(H).multiplyVec4(N).add(H.multiplyVec4(U))),q=v(y.cameraPosition.subtract(B)),L=v(l("nodeTangent")),G=o("width",1),O=v(T(d(V(L).gt(u(.1)),L,b(1,0,0)),q)).multiplyScalar(z.subtract(u(.5))).multiplyScalar(G),Q=p(u(1).subtract(S).multiplyVec3(O).add(C(S,u(1)).multiplyVec3(B)),1),R=p(u(1).subtract(S).multiplyVec3(m.position).add(S.multiplyVec3(B)),1),W=y.projectionMatrix.multiply(y.viewMatrix).multiplyVec(Q),_=y.projectionMatrix.multiply(y.viewMatrix).multiplyVec(R);export const trailUV=x(f(H.multiply(D.x),z.divide(P).multiply(D.y).multiply(2)));export const trailDragUV=x(f(M.divide(I).multiply(D.x),z.divide(P).multiply(D.y).multiply(2)));const k={position:new e.Vector3,direction:new e.Vector3,offset:new e.Vector3,worldOrientation:new e.Vector3,matrix4:new e.Matrix4,quat1:new e.Quaternion,quat2:new e.Quaternion,quaternion:new e.Quaternion,quaternion2:new e.Quaternion,boundingBox:new e.Box3,localHeadGeometry:Array.from({length:128},()=>new e.Vector3)};export class Trail extends e.Object3D{constructor(t,i){super(),this.historyCount=0,this.historyHeadIndex=-1,this.history=[],this.renderNodeCount=0,this.subdivisions=4,this.currentNodeID=0,this.advance=function(){const t=new e.Matrix4;return function(){this.targetObject.updateMatrixWorld(),t.copy(this.targetObject.matrixWorld),this.advanceWithTransform(t),this.updateUniforms()}}(),this.connectNodes=(()=>{const t={attribute:null,offset:0,count:-1};return(e,i)=>{const r=this.geometry.getIndex();for(let t=0;t<this.localHeadGeometry.length-1;t++){const o=this.VerticesPerNode*e+t,s=this.VerticesPerNode*i+t,a=(e*this.FacesPerNode+t*Trail.FacesPerQuad)*Trail.IndicesPerFace;r.array[a]=o,r.array[a+1]=s,r.array[a+2]=o+1,r.array[a+3]=s,r.array[a+4]=s+1,r.array[a+5]=o+1}return r.needsUpdate=!0,r.clearUpdateRanges(),t.attribute=r,t.offset=e*this.FacesPerNode*Trail.IndicesPerFace,t.count=this.FacesPerNode*Trail.IndicesPerFace,t}})(),this.disconnectNodes=(()=>{const t={attribute:null,offset:0,count:-1};return e=>{const i=this.geometry.getIndex();for(let t=0;t<this.localHeadGeometry.length-1;t++){const r=(e*this.FacesPerNode+t*Trail.FacesPerQuad)*Trail.IndicesPerFace;i.array[r]=0,i.array[r+1]=0,i.array[r+2]=0,i.array[r+3]=0,i.array[r+4]=0,i.array[r+5]=0}return i.needsUpdate=!0,i.clearUpdateRanges(),t.attribute=i,t.offset=e*this.FacesPerNode*Trail.IndicesPerFace,t.count=this.FacesPerNode*Trail.IndicesPerFace,t}})(),this.active=!1,this.orientToMovement=!1,i&&(this.orientToMovement=!0),this.scene=t,this.geometry=null,this.mesh=null,this.historyCount=0,this.historyHeadIndex=-1,this.history=[],this.renderNodeCount=0,this.currentNodeID=0,this.advanceFrequency=60,this.advancePeriod=1/this.advanceFrequency,this.lastAdvanceTime=0,this.paused=!1,this.pauseAdvanceUpdateTimeDiff=0}setAdvanceFrequency(t){this.advanceFrequency=t,this.advancePeriod=1/this.advanceFrequency}initialize(t,i,r,o,s,a,n=!1){this.deactivate(),this.destroyMesh(),this.length=i>0?i+1:0,this.dragTexture=r?1:0,this.targetObject=a,this.billboard=n,this.initializeLocalHeadGeometry(o,s),null!=t.uniforms.width&&(t.uniforms.width.value=o),this.renderNodeCount=this.length*this.subdivisions,this.historyCount=0,this.historyHeadIndex=-1,this.history=[];for(let t=0;t<this.length;t++)this.history.push({position:new e.Vector3,tangent:new e.Vector3(1,0,0),transformMatrix:new e.Matrix4,id:-1});this.setAllNodesToCurrentTargetPosition(),this.material=t,this.initializeGeometry(),this.initializeMesh(),this.material.uniforms.dragTexture&&(this.material.uniforms.trailLength.value=0),this.material.uniforms.minID.value=0,this.material.uniforms.maxID.value=0,this.material.uniforms.dragTexture&&(this.material.uniforms.dragTexture.value=this.dragTexture),this.material.uniforms.maxTrailLength&&(this.material.uniforms.maxTrailLength.value=this.length),this.material.uniforms.verticesPerNode&&(this.material.uniforms.verticesPerNode.value=this.VerticesPerNode),this.material.uniforms.textureTileFactor&&(this.material.uniforms.textureTileFactor.value=new e.Vector2(1,1)),this.material.uniforms.scale&&(this.material.uniforms.scale.value=1),this.reset()}initializeLocalHeadGeometry(t,i){if(this.localHeadGeometry=[],i){this.VerticesPerNode=0;for(let t=0;t<i.length&&t<Trail.MaxHeadVertices;t++){const r=i[t];if(r&&r instanceof e.Vector3){const t=new e.Vector3;t.copy(r),this.localHeadGeometry.push(t),this.VerticesPerNode++}}}else{const i=(t||1)/2;this.localHeadGeometry.push(new e.Vector3(-i,0,0)),this.localHeadGeometry.push(new e.Vector3(i,0,0)),this.VerticesPerNode=2}this.FacesPerNode=2*(this.VerticesPerNode-1),this.FaceIndicesPerNode=3*this.FacesPerNode}initializeGeometry(){this.vertexCount=this.renderNodeCount*this.VerticesPerNode,this.faceCount=this.renderNodeCount*this.FacesPerNode;const t=new e.BufferGeometry,i=new Float32Array(this.vertexCount),r=new Float32Array(this.vertexCount*this.VerticesPerNode),o=new Float32Array(this.vertexCount*Trail.PositionComponentCount),s=new Float32Array(this.vertexCount*Trail.PositionComponentCount),a=new Float32Array(this.vertexCount*Trail.UVComponentCount),n=new Uint32Array(this.faceCount*Trail.IndicesPerFace),h=new Float32Array(3*this.vertexCount),l=new e.BufferAttribute(h,3);l.setUsage(e.DynamicDrawUsage),t.setAttribute("nodeTangent",l);const d=new e.BufferAttribute(i,1);d.setUsage(e.DynamicDrawUsage),t.setAttribute("nodeID",d);const u=new e.BufferAttribute(r,1);u.setUsage(e.DynamicDrawUsage),t.setAttribute("nodeVertexID",u);const c=new e.BufferAttribute(s,Trail.PositionComponentCount);c.setUsage(e.DynamicDrawUsage),t.setAttribute("nodeCenter",c);const m=new e.BufferAttribute(o,Trail.PositionComponentCount);m.setUsage(e.DynamicDrawUsage),t.setAttribute("position",m);const y=new e.BufferAttribute(a,Trail.UVComponentCount);y.setUsage(e.DynamicDrawUsage),t.setAttribute("uv",y);const g=new e.BufferAttribute(n,1);g.setUsage(e.DynamicDrawUsage),t.setIndex(g),this.geometry=t}zeroVertices(){const t=this.geometry.getAttribute("position");for(let e=0;e<this.vertexCount;e++){const i=3*e;t.array[i]=0,t.array[i+1]=0,t.array[i+2]=0}t.needsUpdate=!0}zeroIndices(){if(null==this.geometry)throw"Geometry not initialized";const t=this.geometry.getIndex();for(let e=0;e<this.faceCount;e++){const i=3*e;t.array[i]=0,t.array[i+1]=0,t.array[i+2]=0}t.needsUpdate=!0,t.clearUpdateRanges()}formInitialFaces(){this.zeroIndices();const t=this.geometry.getIndex();for(let t=0;t<this.renderNodeCount-1;t++)this.connectNodes(t,t+1);t.needsUpdate=!0,t.clearUpdateRanges()}initializeMesh(){if(null==this.geometry)throw"Geometry not initialized";this.mesh=new e.Mesh(this.geometry,this.material),this.mesh.matrixAutoUpdate=!1,this.mesh.visible=!1}destroyMesh(){this.mesh&&(this.scene.remove(this.mesh),this.mesh=null)}reset(){this.historyCount=0,this.historyHeadIndex=-1,this.currentNodeID=0,this.formInitialFaces(),this.zeroVertices(),this.geometry.setDrawRange(0,0),this.setAllNodesToCurrentTargetPosition(),this.mesh&&(this.mesh.visible=!0)}setAllNodesToCurrentTargetPosition(){if(!this.targetObject)return;this.targetObject.updateMatrixWorld();const t=this.targetObject.matrixWorld,i=(new e.Vector3).setFromMatrixPosition(t),r=new e.Vector3(1,0,0).applyMatrix4(t).normalize();for(let e=0;e<this.length;e++)this.history[e].position.copy(i),this.history[e].tangent.copy(r),this.history[e].transformMatrix.copy(t),this.history[e].id=-1;this.historyCount=0,this.historyHeadIndex=-1}updateUniforms(){if(0===this.historyCount)return;const t=this.getControlPoint(0).id,e=this.getControlPoint(this.historyCount-1).id;this.material.uniforms.minID.value=t,this.material.uniforms.maxID.value=e,this.material.uniforms.trailLength&&(this.material.uniforms.trailLength.value=this.historyCount),this.material.uniforms.maxTrailLength&&(this.material.uniforms.maxTrailLength.value=this.length),this.material.uniforms.verticesPerNode&&(this.material.uniforms.verticesPerNode.value=this.VerticesPerNode)}advanceWithTransform(t){this.historyCount<this.length&&this.historyCount++,this.historyHeadIndex=(this.historyHeadIndex+1)%this.length;const e=this.history[this.historyHeadIndex];if(e.id=this.currentNodeID++,k.position.set(0,0,0).applyMatrix4(t),e.position.copy(k.position),e.transformMatrix.copy(t),this.billboard){const i=this.getControlPoint(this.historyCount-2);i&&!i.position.equals(k.position)?e.tangent.copy(k.position).sub(i.position).normalize():e.tangent.set(1,0,0).applyMatrix4(t).normalize()}this.rebuildGeometry()}updateHead(){if(0===this.historyCount)return;this.targetObject.updateMatrixWorld();const t=this.targetObject.matrixWorld,e=this.history[this.historyHeadIndex];if(k.position.set(0,0,0).applyMatrix4(t),e.position.copy(k.position),e.transformMatrix.copy(t),this.billboard){const i=this.getControlPoint(this.historyCount-2);i&&!i.position.equals(k.position)?e.tangent.copy(k.position).sub(i.position).normalize():e.tangent.set(1,0,0).applyMatrix4(t).normalize()}this.rebuildGeometry()}getControlPoint(t){if(t<0)return this.history[(this.historyHeadIndex-this.historyCount+1+this.length)%this.length];t>=this.historyCount&&(t=this.historyCount-1);const e=(this.historyHeadIndex-this.historyCount+1+this.length)%this.length;return this.history[(e+t)%this.length]}rebuildGeometry(){if(this.historyCount<2)return this.geometry.setDrawRange(0,0),void(this.mesh&&(this.mesh.visible=!1));const t=this.geometry.getAttribute("position"),i=this.geometry.getAttribute("nodeID"),r=this.geometry.getAttribute("nodeVertexID"),o=this.geometry.getAttribute("nodeCenter"),s=this.geometry.getAttribute("nodeTangent"),a=this.historyCount-1,n=a*this.subdivisions+1;let h=0;k.boundingBox.makeEmpty();for(let e=0;e<a;e++){const n=this.getControlPoint(e-1),l=this.getControlPoint(e),d=this.getControlPoint(e+1),u=this.getControlPoint(e+2),c=e===a-1?this.subdivisions+1:this.subdivisions;for(let e=0;e<c;e++){const a=e/this.subdivisions,c=n.position,m=l.position,y=d.position,g=u.position,p=a*a,x=p*a,f=.5*(y.x-c.x),v=.5*(g.x-m.x),b=(2*(m.x-y.x)+f+v)*x+(-3*(m.x-y.x)-2*f-v)*p+f*a+m.x,T=.5*(y.y-c.y),C=.5*(g.y-m.y),V=(2*(m.y-y.y)+T+C)*x+(-3*(m.y-y.y)-2*T-C)*p+T*a+m.y,P=.5*(y.z-c.z),w=.5*(g.z-m.z),F=(2*(m.z-y.z)+P+w)*x+(-3*(m.z-y.z)-2*P-w)*p+P*a+m.z;k.position.set(b,V,F);const I=l.id+(d.id-l.id)*a,D=k.direction.copy(l.tangent).lerp(d.tangent,a).normalize();k.matrix4.copy(l.transformMatrix),k.quat1.setFromRotationMatrix(l.transformMatrix),k.quat2.setFromRotationMatrix(d.transformMatrix),k.quaternion.copy(k.quat1).slerp(k.quat2,a),k.matrix4.makeRotationFromQuaternion(k.quaternion),k.matrix4.setPosition(k.position);for(let e=0;e<this.VerticesPerNode;e++){const n=h*this.VerticesPerNode+e;i.array[n]=I,r.array[n]=e,o.array[3*n]=k.position.x,o.array[3*n+1]=k.position.y,o.array[3*n+2]=k.position.z;const l=k.localHeadGeometry[e].copy(this.localHeadGeometry[e]);if(this.billboard)s.array[3*n]=D.x,s.array[3*n+1]=D.y,s.array[3*n+2]=D.z,k.boundingBox.expandByPoint(k.position);else{if(l.applyMatrix4(k.matrix4),this.orientToMovement){k.worldOrientation.set(0,0,-1).applyQuaternion(k.quaternion);const t=(3*p-2*a)*(m.x-y.x)+(x-p)*v+(3*p-4*a+1)*f,e=(3*p-2*a)*(m.y-y.y)+(x-p)*C+(3*p-4*a+1)*T,i=(3*p-2*a)*(m.z-y.z)+(x-p)*w+(3*p-4*a+1)*P;k.direction.set(t,e,i).normalize(),k.direction.lengthSq()>1e-4&&(k.quaternion2.setFromUnitVectors(k.worldOrientation,k.direction),l.sub(k.position).applyQuaternion(k.quaternion2).add(k.position))}t.array[3*n]=l.x,t.array[3*n+1]=l.y,t.array[3*n+2]=l.z,k.boundingBox.expandByPoint(l)}}h++}}if(i.needsUpdate=!0,r.needsUpdate=!0,o.needsUpdate=!0,this.billboard){s.needsUpdate=!0,this.mesh.frustumCulled=!1;const t=this.material.uniforms.width?.5*this.material.uniforms.width.value:.5;k.boundingBox.min.subScalar(t),k.boundingBox.max.addScalar(t)}else t.needsUpdate=!0;this.geometry.boundingBox=this.geometry.boundingBox||new e.Box3,this.geometry.boundingBox.copy(k.boundingBox),this.geometry.boundingSphere=this.geometry.boundingSphere||new e.Sphere,this.geometry.boundingBox.getBoundingSphere(this.geometry.boundingSphere),this.mesh.visible=!k.boundingBox.isEmpty(),this.geometry.setDrawRange(0,(n-1)*this.FaceIndicesPerNode)}currentTime(){return performance.now()/1e3}pause(){this.paused||(this.paused=!0,this.pauseAdvanceUpdateTimeDiff=this.currentTime()-this.lastAdvanceTime)}resume(){this.paused&&(this.paused=!1,this.lastAdvanceTime=this.currentTime()-this.pauseAdvanceUpdateTimeDiff)}update(){if(!this.paused){const t=this.currentTime();this.lastAdvanceTime||(this.lastAdvanceTime=t),t-this.lastAdvanceTime>this.advancePeriod?(this.advance(),this.lastAdvanceTime=t):this.updateHead()}}deactivate(){this.active&&(this.scene.remove(this.mesh),this.active=!1)}activate(){this.active||(this.scene.add(this.mesh),this.active=!0)}static getTrailShaderNodes(t){return{position:t?W:_,color:j,fraction:H}}static applyTrailShaderParameters(t){t.transparent=!0,t.alphaTest=.5,t.blending=e.CustomBlending,t.blendSrc=e.SrcAlphaFactor,t.blendDst=e.OneMinusSrcAlphaFactor,t.blendEquation=e.AddEquation,t.depthTest=!0,t.depthWrite=!1,t.side=e.DoubleSide}static createBaseMaterial(e,r,o,s=!1){let{position:n}=Trail.getTrailShaderNodes(s),h=a(N,U,H).rgba,l=h.a;if(null!=e){let i=trailUV;null!=r&&(i=i.add(f(t.elapsed.multiply(-r),0)));const s=c(e).sample(i);switch(o??"red"){case"none":break;case"red":l=l.multiply(s.r);break;case"alpha":l=l.multiply(s.a)}h=g(h.rgb.multiply(s.rgb),l)}const d=new i({position:n,opacity:l,color:h});return Trail.applyTrailShaderParameters(d),d}static get MaxHeadVertices(){return 128}static get LocalOrientationTangent(){return Trail._LocalOrientationTangent}static get LocalHeadOrigin(){return Trail._LocalHeadOrigin}static get PositionComponentCount(){return 3}static get UVComponentCount(){return 2}static get IndicesPerFace(){return 3}static get FacesPerQuad(){return 2}}Trail._LocalOrientationTangent=new e.Vector3(1,0,0),Trail._LocalHeadOrigin=new e.Vector3(0,0,0),Trail.Shader={get BaseVertexVars(){return["attribute float nodeID;","attribute float nodeVertexID;","attribute vec3 nodeCenter;","uniform float minID;","uniform float maxID;","uniform float trailLength;","uniform float maxTrailLength;","uniform float verticesPerNode;","uniform vec2 textureTileFactor;","uniform bool taper;","uniform vec4 headColor;","uniform vec4 tailColor;","varying vec4 vColor;"].join("\n")},get TexturedVertexVars(){return[this.BaseVertexVars,"varying vec2 vUV;","uniform float dragTexture;"].join("\n")},BaseFragmentVars:["varying vec4 vColor;","uniform sampler2D trailTexture;"].join("\n"),get TexturedFragmentVars(){return[this.BaseFragmentVars,"varying vec2 vUV;"].join("\n")},get VertexShaderCore(){return["float fraction = (maxID - nodeID) / (maxID - minID);","float fractionSize = taper ? fraction : 0.0;","vColor = (1.0 - fraction) * headColor + fraction * tailColor;","vec4 realPosition = vec4((1.0 - fractionSize) * position.xyz + fractionSize * nodeCenter.xyz, 1.0); "].join("\n")},get BaseVertexShader(){return[this.BaseVertexVars,"void main() { ",this.VertexShaderCore,"gl_Position = projectionMatrix * viewMatrix * realPosition;","}"].join("\n")},get BaseFragmentShader(){return[this.BaseFragmentVars,"void main() { ","gl_FragColor = vColor;","}"].join("\n")},get TexturedVertexShader(){return[this.TexturedVertexVars,"void main() { ",this.VertexShaderCore,"float s = 0.0;","float t = 0.0;","if (dragTexture == 1.0) { "," s = fraction * textureTileFactor.s; "," t = (nodeVertexID / verticesPerNode) * textureTileFactor.t;","} else { "," s = nodeID / maxTrailLength * textureTileFactor.s;"," t = (nodeVertexID / verticesPerNode) * textureTileFactor.t;","}","vUV = vec2(s, t); ","gl_Position = projectionMatrix * viewMatrix * realPosition;","}"].join("\n")},get TexturedFragmentShader(){return[this.TexturedFragmentVars,"void main() { ","vec4 textureColor = texture2D(trailTexture, vUV);","gl_FragColor = vColor * textureColor;","}"].join("\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{__decorate as t,__metadata as e}from"tslib";import o,{ignore as i}from"@plumier/reflect";import{Subject as n,skipWhile as s}from"rxjs";import{Group as r}from"three";import a,{Service as p}from"typedi";import{ActorComponent as c}from"./component.js";import{initComponents as d}from"./internal/component-init.js";import{activeContainerInstance as h,containerRefMap as m}from"./internal/container-map.js";import{randomString as u}from"../../utils/math.js";import{inject as l}from"../inject.js";import{ViewController as f}from"../services/render.js";export function Actor(){const t=p({transient:!0});return function(e){e.__isActor=!0,t(e),o.noop()(e),o.parameterProperties()(e)}}let U=0;export class BaseActor{get position(){return this.object?.position}get quaternion(){return this.object?.quaternion}get rotation(){return this.object?.rotation}onInit(){}onBeginPlay(){}onEndPlay(){}onUpdate(t){}onLateUpdate(t){}constructor(){this.id=++U,this.__isInitialised=!1,this.object=new r,this.disposed=new n,this.attachedComponents=[],this.onUpdate!==BaseActor.prototype.onUpdate&&l(f).onUpdate(this).pipe(s(()=>!this.__isInitialised)).subscribe(t=>this.onUpdate(t)),this.onLateUpdate!==BaseActor.prototype.onLateUpdate&&l(f).onLateUpdate(this).pipe(s(()=>!this.__isInitialised)).subscribe(t=>this.onLateUpdate(t))}attach(t,e){const o=h.value,i=m.get(this)??h.value??a.of("default");h.value=i;const n=u();i.set({id:n,type:t,transient:!0});const s=i.get(n);if(h.value=o,null!=e)for(const t of Object.keys(e))s[t]=e[t];return this.__isInitialised&&(s.actor=this,s.onInit(),d(s,this)),this.attachedComponents.push(s),s}getComponent(t){for(const e of Object.values(this))if(e instanceof t)return e;for(const e of this.attachedComponents)if(e instanceof t)return e}}t([i(),e("design:type",Object),e("design:paramtypes",[])],BaseActor.prototype,"position",null),t([i(),e("design:type",Object),e("design:paramtypes",[])],BaseActor.prototype,"quaternion",null),t([i(),e("design:type",Object),e("design:paramtypes",[])],BaseActor.prototype,"rotation",null);export function _setupActorUpdateEventHandlers(){this.onUpdate!==c.prototype.onUpdate&&l(f).onUpdate(this.actor).pipe(s(()=>!this.actor?.__isInitialised)).subscribe(t=>this.onUpdate(t)),this.onLateUpdate!==c.prototype.onLateUpdate&&l(f).onLateUpdate(this.actor).pipe(s(()=>!this.actor?.__isInitialised)).subscribe(t=>this.onLateUpdate(t))}/*
1
+ import{__decorate as t,__metadata as e}from"tslib";import o,{ignore as i}from"@plumier/reflect";import{Subject as n,skipWhile as s}from"rxjs";import{Group as r}from"three";import a,{Service as p}from"typedi";import{ActorComponent as c}from"./component.js";import{initComponentsSync as d}from"./internal/component-init.js";import{activeContainerInstance as h,containerRefMap as m}from"./internal/container-map.js";import{randomString as u}from"../../utils/math.js";import{inject as l}from"../inject.js";import{ViewController as f}from"../services/render.js";export function Actor(){const t=p({transient:!0});return function(e){e.__isActor=!0,t(e),o.noop()(e),o.parameterProperties()(e)}}let U=0;export class BaseActor{get position(){return this.object?.position}get quaternion(){return this.object?.quaternion}get rotation(){return this.object?.rotation}onInit(){}onBeginPlay(){}onEndPlay(){}onUpdate(t){}onLateUpdate(t){}constructor(){this.id=++U,this.__isInitialised=!1,this.object=new r,this.disposed=new n,this.attachedComponents=[],this.onUpdate!==BaseActor.prototype.onUpdate&&l(f).onUpdate(this).pipe(s(()=>!this.__isInitialised)).subscribe(t=>this.onUpdate(t)),this.onLateUpdate!==BaseActor.prototype.onLateUpdate&&l(f).onLateUpdate(this).pipe(s(()=>!this.__isInitialised)).subscribe(t=>this.onLateUpdate(t))}attach(t,e){const o=h.value,i=m.get(this)??h.value??a.of("default");h.value=i;const n=u();i.set({id:n,type:t,transient:!0});const s=i.get(n);if(h.value=o,null!=e)for(const t of Object.keys(e))s[t]=e[t];return this.__isInitialised&&(s.actor=this,s.onInit(),d(s,this)),this.attachedComponents.push(s),s}getComponent(t){for(const e of Object.values(this))if(e instanceof t)return e;for(const e of this.attachedComponents)if(e instanceof t)return e}}t([i(),e("design:type",Object),e("design:paramtypes",[])],BaseActor.prototype,"position",null),t([i(),e("design:type",Object),e("design:paramtypes",[])],BaseActor.prototype,"quaternion",null),t([i(),e("design:type",Object),e("design:paramtypes",[])],BaseActor.prototype,"rotation",null);export function _setupActorUpdateEventHandlers(){this.onUpdate!==c.prototype.onUpdate&&l(f).onUpdate(this.actor).pipe(s(()=>!this.actor?.__isInitialised)).subscribe(t=>this.onUpdate(t)),this.onLateUpdate!==c.prototype.onLateUpdate&&l(f).onLateUpdate(this.actor).pipe(s(()=>!this.actor?.__isInitialised)).subscribe(t=>this.onLateUpdate(t))}/*
2
2
  * Copyright (©) 2026 Hology Interactive AB. All rights reserved.
3
3
  * See the LICENSE.md file for details.
4
4
  */