@polarfront-lab/ionian 1.6.0 → 1.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -2,6 +2,11 @@
2
2
 
3
3
  import * as THREE from 'three';
4
4
 
5
+ export type AssetEvents = {
6
+ assetRegistered: {
7
+ id: string;
8
+ };
9
+ };
5
10
  /**
6
11
  * Represents the data of a mesh, including its position, normal, and scale.
7
12
  */
@@ -26,7 +31,7 @@ export type DataTextureEntry = {
26
31
  };
27
32
  export type ServiceType = "data-texture" | "matcap" | "instanced-mesh" | "simulation" | "asset";
28
33
  export type ServiceState = "created" | "initializing" | "ready" | "disposed" | "error" | "loading";
29
- export type TransitionType = "data-texture" | "matcap";
34
+ export type TransitionType = "data-texture" | "matcap" | "mesh-sequence";
30
35
  export interface TransitionDetail {
31
36
  duration: number;
32
37
  easing: EasingFunction;
@@ -39,6 +44,84 @@ export type TransitionOptions = {
39
44
  onTransitionFinished?: Callback;
40
45
  onTransitionCancelled?: Callback;
41
46
  };
47
+ export type TransitionEvents = {
48
+ /** transition started */
49
+ transitionStarted: {
50
+ type: TransitionType;
51
+ };
52
+ /** transition progressed */
53
+ transitionProgressed: {
54
+ type: TransitionType;
55
+ progress: number;
56
+ };
57
+ /** transition finished */
58
+ transitionFinished: {
59
+ type: TransitionType;
60
+ };
61
+ /** transition cancelled */
62
+ transitionCancelled: {
63
+ type: TransitionType;
64
+ };
65
+ };
66
+ export type DataTextureEvents = {
67
+ meshRegistered: {
68
+ id: string;
69
+ };
70
+ };
71
+ export type GlobalEvents = {
72
+ serviceStateUpdated: {
73
+ type: ServiceType;
74
+ state: ServiceState;
75
+ };
76
+ interactionPositionUpdated: {
77
+ position: THREE.Vector4Like;
78
+ };
79
+ invalidRequest: {
80
+ message: string;
81
+ };
82
+ };
83
+ export type MatcapEvents = {
84
+ matcapRegistered: {
85
+ id: string;
86
+ };
87
+ matcapReplaced: {
88
+ id: string;
89
+ };
90
+ };
91
+ export type SimulationEvents = {};
92
+ export type Events = GlobalEvents & SimulationEvents & DataTextureEvents & MatcapEvents & TransitionEvents & AssetEvents;
93
+ export interface EngineEventEmitter<EventMap extends Record<string, unknown>> {
94
+ emit<Key extends keyof EventMap>(type: Key, payload: EventMap[Key]): void;
95
+ off<Key extends keyof EventMap>(type: Key, handler?: (payload: EventMap[Key]) => void): void;
96
+ on<Key extends keyof EventMap>(type: Key, handler: (payload: EventMap[Key]) => void): void;
97
+ once<Key extends keyof EventMap>(type: Key, handler: (payload: EventMap[Key]) => void): void;
98
+ dispose(): void;
99
+ }
100
+ declare class DefaultEventEmitter implements EngineEventEmitter<Events> {
101
+ private readonly emitter;
102
+ emit<Key extends keyof Events>(type: Key, payload: Events[Key]): void;
103
+ off<Key extends keyof Events>(type: Key, handler?: (payload: Events[Key]) => void): void;
104
+ on<Key extends keyof Events>(type: Key, handler: (payload: Events[Key]) => void): void;
105
+ once<Key extends keyof Events>(type: Key, handler: (payload: Events[Key]) => void): void;
106
+ dispose(): void;
107
+ }
108
+ /**
109
+ * Represents the current state of the system.
110
+ */
111
+ export interface EngineState {
112
+ pointerPosition: THREE.Vector2Like;
113
+ textureSize: number;
114
+ meshSequence: string[];
115
+ overallProgress: number;
116
+ velocityTractionForce: number;
117
+ positionalTractionForce: number;
118
+ maxRepelDistance: number;
119
+ originMatcapID: string;
120
+ destinationMatcapID: string;
121
+ matcapTransitionProgress: number;
122
+ instanceGeometryScale: THREE.Vector3Like;
123
+ useIntersect: boolean;
124
+ }
42
125
  /**
43
126
  * Parameters for creating a ParticlesEngine instance.
44
127
  */
@@ -54,7 +137,6 @@ export type ParticlesEngineParameters = {
54
137
  */
55
138
  export declare class ParticlesEngine {
56
139
  private simulationRendererService;
57
- private eventEmitter;
58
140
  private renderer;
59
141
  private scene;
60
142
  private serviceStates;
@@ -64,6 +146,8 @@ export declare class ParticlesEngine {
64
146
  private transitionService;
65
147
  private engineState;
66
148
  private intersectionService;
149
+ private meshSequenceAtlasTexture;
150
+ eventEmitter: DefaultEventEmitter;
67
151
  /**
68
152
  * Creates a new ParticlesEngine instance.
69
153
  * @param params The parameters for creating the instance.
@@ -74,9 +158,6 @@ export declare class ParticlesEngine {
74
158
  * @param elapsedTime The elapsed time since the last frame.
75
159
  */
76
160
  render(elapsedTime: number): void;
77
- setOriginDataTexture(meshID: string, override?: boolean): void;
78
- setDestinationDataTexture(meshID: string, override?: boolean): void;
79
- setDataTextureTransitionProgress(progress: number, override?: boolean): void;
80
161
  setOriginMatcap(matcapID: string, override?: boolean): void;
81
162
  setDestinationMatcap(matcapID: string, override?: boolean): void;
82
163
  setOriginColor(color: THREE.ColorRepresentation, override?: boolean): void;
@@ -95,13 +176,37 @@ export declare class ParticlesEngine {
95
176
  setVelocityTractionForce(force: number): void;
96
177
  setPositionalTractionForce(force: number): void;
97
178
  setMaxRepelDistance(distance: number): void;
98
- scheduleMeshTransition(originMeshID: string, destinationMeshID: string, easing?: EasingFunction, duration?: number, override?: boolean): void;
99
- scheduleMatcapTransition(originMatcapID: string, destinationMatcapID: string, easing?: EasingFunction, duration?: number, override?: boolean): void;
100
- scheduleTextureTransition(origin: string, destination: string, options?: {
179
+ /**
180
+ * Sets the sequence of meshes for particle transitions.
181
+ * This will generate a texture atlas containing position data for all meshes.
182
+ * @param meshIDs An array of registered mesh IDs in the desired sequence order.
183
+ */
184
+ setMeshSequence(meshIDs: string[]): Promise<void>;
185
+ /**
186
+ * Sets the overall progress through the mesh sequence.
187
+ * @param progress A value between 0.0 (first mesh) and 1.0 (last mesh).
188
+ * @param override If true, cancels any ongoing mesh sequence transition before setting the value. Defaults to true.
189
+ */
190
+ setOverallProgress(progress: number, override?: boolean): void;
191
+ scheduleMatcapTransition(originMatcapID: string, destinationMatcapID: string, easing?: EasingFunction, duration?: number, override?: boolean, options?: TransitionOptions): void;
192
+ scheduleTextureTransition(origin: string | THREE.ColorRepresentation, destination: string | THREE.ColorRepresentation, options?: {
101
193
  easing?: EasingFunction;
102
194
  duration?: number;
103
195
  override?: boolean;
196
+ onTransitionBegin?: Callback;
197
+ onTransitionProgress?: TransitionCallback;
198
+ onTransitionFinished?: Callback;
199
+ onTransitionCancelled?: Callback;
104
200
  }): void;
201
+ /**
202
+ * Schedules a smooth transition for the overall mesh sequence progress.
203
+ * @param targetProgress The final progress value (0.0 to 1.0) to transition to.
204
+ * @param duration Duration of the transition in milliseconds.
205
+ * @param easing Easing function to use.
206
+ * @param options Transition options (onBegin, onProgress, onFinished, onCancelled).
207
+ * @param override If true, cancels any ongoing mesh sequence transitions.
208
+ */
209
+ scheduleMeshSequenceTransition(targetProgress: number, duration?: number, easing?: EasingFunction, options?: TransitionOptions, override?: boolean): void;
105
210
  handleServiceStateUpdated({ type, state }: {
106
211
  type: ServiceType;
107
212
  state: ServiceState;
@@ -111,65 +216,16 @@ export declare class ParticlesEngine {
111
216
  getMatcapIDs(): string[];
112
217
  getMeshes(): THREE.Mesh<THREE.BufferGeometry<THREE.NormalBufferAttributes>, THREE.Material | THREE.Material[], THREE.Object3DEventMap>[];
113
218
  getTextures(): THREE.Texture[];
219
+ getTextureSize(): number;
220
+ getUseIntersect(): boolean;
221
+ getEngineStateSnapshot(): Readonly<EngineState>;
114
222
  /**
115
223
  * Disposes the resources used by the engine.
116
224
  */
117
225
  dispose(): void;
118
226
  private initialEngineState;
119
227
  private getInitialServiceStates;
120
- private handleTransitionProgress;
121
228
  private handleInteractionPositionUpdated;
122
229
  }
123
- export type AssetEvents = {
124
- assetRegistered: {
125
- id: string;
126
- };
127
- };
128
- export type TransitionEvents = {
129
- /** transition started */
130
- transitionStarted: {
131
- type: TransitionType;
132
- };
133
- /** transition progressed */
134
- transitionProgressed: {
135
- type: TransitionType;
136
- progress: number;
137
- };
138
- /** transition finished */
139
- transitionFinished: {
140
- type: TransitionType;
141
- };
142
- /** transition cancelled */
143
- transitionCancelled: {
144
- type: TransitionType;
145
- };
146
- };
147
- export type DataTextureEvents = {
148
- meshRegistered: {
149
- id: string;
150
- };
151
- };
152
- export type GlobalEvents = {
153
- serviceStateUpdated: {
154
- type: ServiceType;
155
- state: ServiceState;
156
- };
157
- interactionPositionUpdated: {
158
- position: THREE.Vector4Like;
159
- };
160
- invalidRequest: {
161
- message: string;
162
- };
163
- };
164
- export type MatcapEvents = {
165
- matcapRegistered: {
166
- id: string;
167
- };
168
- matcapReplaced: {
169
- id: string;
170
- };
171
- };
172
- export type SimulationEvents = {};
173
- export type Events = GlobalEvents & SimulationEvents & DataTextureEvents & MatcapEvents & TransitionEvents & AssetEvents;
174
230
 
175
231
  export {};
@@ -1,2 +1,2 @@
1
- var ionian=function(e,t,i){"use strict";var s=Object.defineProperty,r=(e,t,i)=>((e,t,i)=>t in e?s(e,t,{enumerable:!0,configurable:!0,writable:!0,value:i}):e[t]=i)(e,"symbol"!=typeof t?t+"":t,i);function n(e){const t=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(e)for(const i in e)if("default"!==i){const s=Object.getOwnPropertyDescriptor(e,i);Object.defineProperty(t,i,s.get?s:{enumerable:!0,get:()=>e[i]})}return t.default=e,Object.freeze(t)}const a=n(t),o=e=>e;class u{constructor(){var e;r(this,"emitter",{all:e=e||new Map,on:function(t,i){var s=e.get(t);s?s.push(i):e.set(t,[i])},off:function(t,i){var s=e.get(t);s&&(i?s.splice(s.indexOf(i)>>>0,1):e.set(t,[]))},emit:function(t,i){var s=e.get(t);s&&s.slice().map((function(e){e(i)})),(s=e.get("*"))&&s.slice().map((function(e){e(t,i)}))}})}emit(e,t){this.emitter.emit(e,t)}off(e,t){this.emitter.off(e,t)}on(e,t){this.emitter.on(e,t)}once(e,t){this.emitter.on(e,(i=>{this.emitter.off(e,t),t(i)}))}dispose(){this.emitter.all.clear()}}function h(e,t){const i=new a.DataTexture(e,t,t,a.RGBAFormat,a.FloatType);return i.needsUpdate=!0,i}function c(e){e.geometry.dispose(),e.material instanceof a.Material?e.material.dispose():e.material.forEach((e=>e.dispose()))}function l(e,t,i){return e=Math.min(e,i),e=Math.max(e,t)}class d{constructor(e){r(this,"serviceState","created"),r(this,"eventEmitter"),r(this,"meshes",new Map),r(this,"textures",new Map),r(this,"gltfLoader",new i.GLTFLoader),r(this,"textureLoader",new a.TextureLoader),r(this,"dracoLoader",new i.DRACOLoader),r(this,"solidColorTexture",new a.DataTexture(new Uint8Array([127,127,127,255]),1,1,a.RGBAFormat)),this.eventEmitter=e,this.dracoLoader.setDecoderPath("https://www.gstatic.com/draco/versioned/decoders/1.5.7/"),this.gltfLoader.setDRACOLoader(this.dracoLoader),this.updateServiceState("ready")}register(e,t){if(t.name=e,t instanceof a.Mesh){const i=this.meshes.get(e);i&&c(i),this.meshes.set(e,t)}else{const i=this.textures.get(e);i&&i.dispose(),this.textures.set(e,t)}this.eventEmitter.emit("assetRegistered",{id:e})}setSolidColor(e){this.changeColor(e)}getSolidColorTexture(){return this.solidColorTexture}getMesh(e){return this.meshes.get(e)??null}getMatcap(e){const t=this.textures.get(e);return t||this.eventEmitter.emit("invalidRequest",{message:`texture with id "${e}" not found. using solid color texture instead...`}),t??this.solidColorTexture}getMeshIDs(){return Array.from(this.meshes.keys())}getTextureIDs(){return Array.from(this.textures.keys())}getMeshes(){return Array.from(this.meshes.values())}getTextures(){return Array.from(this.textures.values())}hasMatcap(e){return this.textures.has(e)}async loadMeshAsync(e,t,i={}){const s=await this.gltfLoader.loadAsync(t);try{if(i.meshName){const t=s.scene.getObjectByName(i.meshName);return this.register(e,t),t}{const t=s.scene.children[0];return this.register(e,t),t}}catch(r){return this.eventEmitter.emit("invalidRequest",{message:`failed to load mesh: ${e}. ${r}`}),null}}async loadTextureAsync(e,t){try{const i=await this.textureLoader.loadAsync(t);return this.register(e,i),i}catch(i){return this.eventEmitter.emit("invalidRequest",{message:`failed to load texture: ${e}. ${i}`}),null}}dispose(){this.updateServiceState("disposed"),this.meshes.forEach((e=>c(e))),this.meshes.clear(),this.textures.forEach((e=>e.dispose())),this.textures.clear()}changeColor(e){const t=new a.Color(e);this.solidColorTexture=new a.DataTexture(new Uint8Array([t.r,t.g,t.b,255]),1,1,a.RGBAFormat),this.solidColorTexture.needsUpdate=!0}updateServiceState(e){this.serviceState=e,this.eventEmitter.emit("serviceStateUpdated",{type:"asset",state:e})}}const m=new t.Triangle,g=new t.Vector3,p=new t.Vector2,v=new t.Vector2,x=new t.Vector2;class T{constructor(e){this.geometry=e.geometry,this.randomFunction=Math.random,this.indexAttribute=this.geometry.index,this.positionAttribute=this.geometry.getAttribute("position"),this.normalAttribute=this.geometry.getAttribute("normal"),this.colorAttribute=this.geometry.getAttribute("color"),this.uvAttribute=this.geometry.getAttribute("uv"),this.weightAttribute=null,this.distribution=null}setWeightAttribute(e){return this.weightAttribute=e?this.geometry.getAttribute(e):null,this}build(){const e=this.indexAttribute,t=this.positionAttribute,i=this.weightAttribute,s=e?e.count/3:t.count/3,r=new Float32Array(s);for(let o=0;o<s;o++){let s=1,n=3*o,a=3*o+1,u=3*o+2;e&&(n=e.getX(n),a=e.getX(a),u=e.getX(u)),i&&(s=i.getX(n)+i.getX(a)+i.getX(u)),m.a.fromBufferAttribute(t,n),m.b.fromBufferAttribute(t,a),m.c.fromBufferAttribute(t,u),s*=m.getArea(),r[o]=s}const n=new Float32Array(s);let a=0;for(let o=0;o<s;o++)a+=r[o],n[o]=a;return this.distribution=n,this}setRandomGenerator(e){return this.randomFunction=e,this}sample(e,t,i,s){const r=this.sampleFaceIndex();return this.sampleFace(r,e,t,i,s)}sampleFaceIndex(){const e=this.distribution[this.distribution.length-1];return this.binarySearch(this.randomFunction()*e)}binarySearch(e){const t=this.distribution;let i=0,s=t.length-1,r=-1;for(;i<=s;){const n=Math.ceil((i+s)/2);if(0===n||t[n-1]<=e&&t[n]>e){r=n;break}e<t[n]?s=n-1:i=n+1}return r}sampleFace(e,t,i,s,r){let n=this.randomFunction(),a=this.randomFunction();n+a>1&&(n=1-n,a=1-a);const o=this.indexAttribute;let u=3*e,h=3*e+1,c=3*e+2;return o&&(u=o.getX(u),h=o.getX(h),c=o.getX(c)),m.a.fromBufferAttribute(this.positionAttribute,u),m.b.fromBufferAttribute(this.positionAttribute,h),m.c.fromBufferAttribute(this.positionAttribute,c),t.set(0,0,0).addScaledVector(m.a,n).addScaledVector(m.b,a).addScaledVector(m.c,1-(n+a)),void 0!==i&&(void 0!==this.normalAttribute?(m.a.fromBufferAttribute(this.normalAttribute,u),m.b.fromBufferAttribute(this.normalAttribute,h),m.c.fromBufferAttribute(this.normalAttribute,c),i.set(0,0,0).addScaledVector(m.a,n).addScaledVector(m.b,a).addScaledVector(m.c,1-(n+a)).normalize()):m.getNormal(i)),void 0!==s&&void 0!==this.colorAttribute&&(m.a.fromBufferAttribute(this.colorAttribute,u),m.b.fromBufferAttribute(this.colorAttribute,h),m.c.fromBufferAttribute(this.colorAttribute,c),g.set(0,0,0).addScaledVector(m.a,n).addScaledVector(m.b,a).addScaledVector(m.c,1-(n+a)),s.r=g.x,s.g=g.y,s.b=g.z),void 0!==r&&void 0!==this.uvAttribute&&(p.fromBufferAttribute(this.uvAttribute,u),v.fromBufferAttribute(this.uvAttribute,h),x.fromBufferAttribute(this.uvAttribute,c),r.set(0,0).addScaledVector(p,n).addScaledVector(v,a).addScaledVector(x,1-(n+a))),this}}class f{constructor(e,t){r(this,"textureSize"),r(this,"dataTextures"),r(this,"eventEmitter"),this.eventEmitter=e,this.textureSize=t,this.dataTextures=new Map,this.updateServiceState("ready")}setTextureSize(e){this.textureSize!==e&&(this.textureSize=e,this.dataTextures.forEach((e=>e.dispose())),this.dataTextures.clear())}async getDataTexture(e){const t=this.dataTextures.get(e.name);if(t)return t;var i,s;const r=function(e,t){const i=new a.BufferGeometry;i.setAttribute("position",new a.BufferAttribute(new Float32Array(e.position),3)),e.normal&&i.setAttribute("normal",new a.BufferAttribute(new Float32Array(e.normal),3));const s=new a.MeshBasicMaterial,r=new a.Mesh(i,s);r.scale.set(e.scale.x,e.scale.y,e.scale.z);const n=new T(r).build(),o=new Float32Array(t*t*4),u=new a.Vector3;for(let a=0;a<t;a++)for(let i=0;i<t;i++){const s=a*t+i;n.sample(u),o[4*s]=u.x*e.scale.x,o[4*s+1]=u.y*e.scale.y,o[4*s+2]=u.z*e.scale.z,o[4*s+3]=.01*(Math.random()-.5)}return o}({position:(i=e).geometry.attributes.position.array,normal:null==(s=i.geometry.attributes.normal)?void 0:s.array,scale:{x:i.scale.x,y:i.scale.y,z:i.scale.z}},this.textureSize),n=h(r,this.textureSize);return n.name=e.name,n}async dispose(){this.dataTextures.clear(),this.updateServiceState("disposed")}updateServiceState(e){this.eventEmitter.emit("serviceStateUpdated",{type:"data-texture",state:e})}}class y{constructor(e){r(this,"size"),r(this,"mesh"),r(this,"matcapMaterial"),r(this,"fallbackGeometry"),r(this,"uniforms"),r(this,"originColor"),r(this,"destinationColor"),r(this,"geometries"),r(this,"uvRefsCache"),r(this,"previousScale"),this.size=e,this.geometries=new Map,this.uvRefsCache=new Map,this.previousScale={x:1,y:1,z:1},this.originColor="grey",this.destinationColor="grey",this.uniforms={uTime:{value:0},uProgress:{value:0},uTexture:{value:null},uVelocity:{value:null},uOriginTexture:{value:null},uDestinationTexture:{value:null}},this.matcapMaterial=new a.ShaderMaterial({uniforms:this.uniforms,vertexShader:"\nvarying vec2 vUv;\nuniform sampler2D uTexture;\nuniform sampler2D uVelocity;\nuniform float uTime;\nvarying vec3 vNormal;\nattribute vec2 uvRef;\nvarying vec3 vViewPosition;\n\nvec3 rotate3D(vec3 v, vec3 vel) {\n vec3 pos = v;\n vec3 up = vec3(0, 1, 0);\n vec3 axis = normalize(cross(up, vel));\n float angle = acos(dot(up, normalize(vel)));\n pos = pos * cos(angle) + cross(axis, pos) * sin(angle) + axis * dot(axis, pos) * (1. - cos(angle));\n return pos;\n}\n\nvoid main() {\n vUv = uv;\n vNormal = normal;\n\n vec4 color = texture2D(uTexture, uvRef);\n vec4 velocity = texture2D(uVelocity, uvRef);\n vec3 pos = color.xyz;// apply the texture to the vertex distribution.\n\n vec3 localPosition = position.xyz;\n if (length (velocity.xyz) < 0.0001) {\n velocity.xyz = vec3(0.0, 0.0001, 0.0001);\n }\n localPosition.y *= max(1.0, length(velocity.xyz) * 1000.0);\n localPosition = rotate3D(localPosition, velocity.xyz);\n vNormal = rotate3D(normal, velocity.xyz);\n\n mat4 instanceMat = instanceMatrix;\n instanceMat[3].xyz = pos.xyz;\n\n // unlike the traditional mvMatrix * position, we need to additional multiplication with the instance matrix.\n vec4 modelViewPosition = modelViewMatrix * instanceMat * vec4(localPosition, 1.0);\n\n vViewPosition = - modelViewPosition.xyz;\n\n gl_Position = projectionMatrix * modelViewPosition;\n}\n",fragmentShader:"\nvarying vec2 vUv;\nuniform sampler2D uTexture;\n\nuniform sampler2D uOriginTexture;\nuniform sampler2D uDestinationTexture;\n\nuniform float uProgress;\nvarying vec3 vNormal;\nvarying vec3 vViewPosition;\nvoid main() {\n vec3 viewDir = normalize( vViewPosition );\n vec3 x = normalize( vec3( viewDir.z, 0.0, - viewDir.x ) );\n vec3 y = cross( viewDir, x );\n vec2 uv = vec2( dot( x, vNormal ), dot( y, vNormal ) ) * 0.495 + 0.5; // 0.495 to remove artifacts caused by undersized matcap disks\n\n vec4 sourceMatcap = texture2D( uOriginTexture, uv );\n vec4 targetMatcap = texture2D( uDestinationTexture, uv );\n\n vec4 matcap = mix(sourceMatcap, targetMatcap, uProgress);\n gl_FragColor = matcap;\n}\n"}),this.setOriginColor(this.originColor),this.setDestinationColor(this.destinationColor),this.fallbackGeometry=new a.BoxGeometry(.001,.001,.001),this.mesh=this.createInstancedMesh(e,this.fallbackGeometry,this.matcapMaterial)}getMesh(){return this.mesh}update(e){const t=this.mesh.material;(t instanceof a.ShaderMaterial||t instanceof a.RawShaderMaterial)&&(t.uniforms.uTime.value=e)}setOriginMatcap(e){this.disposeSolidColorOriginTexture(),this.matcapMaterial.uniforms.uOriginTexture.value=e}setDestinationMatcap(e){this.disposeSolidColorDestinationTexture(),this.matcapMaterial.uniforms.uDestinationTexture.value=e}setProgress(e){e=Math.max(0,e),e=Math.min(1,e),this.matcapMaterial.uniforms.uProgress.value=e}setGeometrySize(e){this.mesh.geometry.scale(1/this.previousScale.x,1/this.previousScale.y,1/this.previousScale.z),this.mesh.geometry.scale(e.x,e.y,e.z),this.previousScale=e}useMatcapMaterial(){this.mesh.material=this.matcapMaterial}useGeometry(e){const t=this.geometries.get(e);t&&(this.mesh.geometry=t)}updateVelocityTexture(e){this.matcapMaterial.uniforms.uVelocity.value=e}updatePositionTexture(e){this.matcapMaterial.uniforms.uTexture.value=e}resize(e){if(this.size===e)return{current:this.mesh,previous:this.mesh};this.size=e;const t=this.mesh;return this.mesh=this.createInstancedMesh(e,t.geometry,t.material),{current:this.mesh,previous:t}}dispose(){this.mesh.dispose(),this.geometries.forEach((e=>e.dispose())),this.disposeSolidColorOriginTexture(),this.disposeSolidColorDestinationTexture(),this.matcapMaterial.dispose(),this.uvRefsCache.clear(),this.geometries.clear()}registerGeometry(e,t){const i=this.geometries.get(e);if(i&&i===t)return;const s=this.createUVRefs(this.size);t.setAttribute("uvRef",s),this.geometries.set(e,t),this.mesh.geometry===i&&(this.mesh.geometry=t),null==i||i.dispose()}setOriginColor(e){this.disposeSolidColorOriginTexture(),this.originColor=e,this.uniforms.uOriginTexture.value=this.createSolidColorDataTexture(e)}setDestinationColor(e){this.disposeSolidColorDestinationTexture(),this.destinationColor=e,this.uniforms.uDestinationTexture.value=this.createSolidColorDataTexture(e)}createUVRefs(e){const t=this.uvRefsCache.get(e);if(t)return t;const i=new Float32Array(e*e*2);for(let r=0;r<e;r++)for(let t=0;t<e;t++){const s=r*e+t;i[2*s]=t/(e-1),i[2*s+1]=r/(e-1)}const s=new a.InstancedBufferAttribute(i,2);return this.uvRefsCache.set(e,s),s}createInstancedMesh(e,t,i){(t=t||this.fallbackGeometry).setAttribute("uvRef",this.createUVRefs(e));const s=e*e;return new a.InstancedMesh(t,i,s)}createSolidColorDataTexture(e,t=16){const i=new a.Color(e),s=t,r=t,n=new Uint8Array(s*r*4),o=Math.floor(255*i.r),u=Math.floor(255*i.g),h=Math.floor(255*i.b);for(let a=0;a<s*r;a++){const e=4*a;n[e]=o,n[e+1]=u,n[e+2]=h,n[e+3]=255}const c=new a.DataTexture(n,s,r,a.RGBAFormat);return c.type=a.UnsignedByteType,c.wrapS=a.RepeatWrapping,c.wrapT=a.RepeatWrapping,c.minFilter=a.NearestFilter,c.magFilter=a.NearestFilter,c.needsUpdate=!0,c}disposeSolidColorOriginTexture(){this.originColor&&(this.originColor=null,this.uniforms.uOriginTexture.value&&this.uniforms.uOriginTexture.value.dispose())}disposeSolidColorDestinationTexture(){this.destinationColor&&(this.destinationColor=null,this.uniforms.uDestinationTexture.value&&this.uniforms.uDestinationTexture.value.dispose())}}class M{constructor(e,t,i,s){r(this,"active",!0),r(this,"raycaster",new a.Raycaster),r(this,"mousePosition",new a.Vector2),r(this,"camera"),r(this,"originGeometry"),r(this,"destinationGeometry"),r(this,"progress",0),r(this,"intersectionMesh",new a.Mesh),r(this,"geometryNeedsUpdate"),r(this,"eventEmitter"),r(this,"blendedGeometry"),r(this,"intersection"),r(this,"lastKnownOriginMeshID"),r(this,"lastKnownDestinationMeshID"),this.camera=t,this.originGeometry=i,this.eventEmitter=e,this.destinationGeometry=s,this.geometryNeedsUpdate=!0}setActive(e){this.active=e}getIntersectionMesh(){return this.intersectionMesh}setCamera(e){this.camera=e}setOriginGeometry(e){this.lastKnownOriginMeshID!==e.uuid&&(this.originGeometry&&this.originGeometry.dispose(),this.lastKnownOriginMeshID=e.uuid,this.originGeometry=e.geometry.clone(),this.originGeometry.applyMatrix4(e.matrixWorld),this.geometryNeedsUpdate=!0)}setDestinationGeometry(e){this.lastKnownDestinationMeshID!==e.uuid&&(this.destinationGeometry&&this.destinationGeometry.dispose(),this.lastKnownDestinationMeshID=e.uuid,this.destinationGeometry=e.geometry.clone(),this.destinationGeometry.applyMatrix4(e.matrixWorld),this.geometryNeedsUpdate=!0)}setProgress(e){this.progress=e,this.geometryNeedsUpdate=!0}setPointerPosition(e){e&&this.mousePosition.copy(e)}calculate(e){if(this.active&&(this.updateIntersectionMesh(e),this.camera))return this.geometryNeedsUpdate&&(this.geometryNeedsUpdate=!1,this.blendedGeometry=this.getBlendedGeometry()),this.blendedGeometry?this.intersection=this.getFirstIntersection(this.camera,e):this.intersection=void 0,this.intersection?this.eventEmitter.emit("interactionPositionUpdated",{position:this.intersection}):this.eventEmitter.emit("interactionPositionUpdated",{position:{x:0,y:0,z:0,w:0}}),this.intersection}dispose(){var e;null==(e=this.blendedGeometry)||e.dispose(),this.intersectionMesh.geometry.dispose()}updateIntersectionMesh(e){this.blendedGeometry&&this.blendedGeometry.uuid!==this.intersectionMesh.geometry.uuid&&(this.intersectionMesh.geometry.dispose(),this.intersectionMesh.geometry=this.blendedGeometry),this.intersectionMesh.matrix.copy(e.matrixWorld),this.intersectionMesh.matrixWorld.copy(e.matrixWorld),this.intersectionMesh.matrixAutoUpdate=!1,this.intersectionMesh.updateMatrixWorld(!0)}getFirstIntersection(e,t){this.raycaster.setFromCamera(this.mousePosition,e);const i=this.raycaster.intersectObject(this.intersectionMesh,!1)[0];if(i){const e=i.point.clone(),s=t.worldToLocal(e);return new a.Vector4(s.x,s.y,s.z,1)}}getBlendedGeometry(){return 0===this.progress?this.originGeometry:1===this.progress?this.destinationGeometry:this.originGeometry&&this.destinationGeometry?this.originGeometry===this.destinationGeometry?this.originGeometry:this.blendGeometry(this.originGeometry,this.destinationGeometry,this.progress):void 0}blendGeometry(e,t,i){const s=new a.BufferGeometry,r=e.attributes.position.array,n=t.attributes.position.array,o=new Float32Array(r.length);for(let u=0;u<r.length;u+=3){const e=new a.Vector3(r[u],r[u+1],r[u+2]),t=new a.Vector3(n[u],n[u+1],n[u+2]),s=(new a.Vector3).lerpVectors(e,t,i);o[u]=s.x,o[u+1]=s.y,o[u+2]=s.z}return s.setAttribute("position",new a.BufferAttribute(o,3)),e.attributes.normal&&s.setAttribute("normal",e.attributes.normal.clone()),e.attributes.uv&&s.setAttribute("uv",e.attributes.uv.clone()),e.index&&s.setIndex(e.index.clone()),s}}const S=new t.OrthographicCamera(-1,1,1,-1,0,1);class D extends t.BufferGeometry{constructor(){super(),this.setAttribute("position",new t.Float32BufferAttribute([-1,3,0,-1,-1,0,3,-1,0],3)),this.setAttribute("uv",new t.Float32BufferAttribute([0,2,0,0,2,0],2))}}const w=new D;class P{constructor(e){this._mesh=new t.Mesh(w,e)}dispose(){this._mesh.geometry.dispose()}render(e){e.render(this._mesh,S)}get material(){return this._mesh.material}set material(e){this._mesh.material=e}}class b{constructor(e,i,s){this.variables=[],this.currentTextureIndex=0;let r=t.FloatType;const n={passThruTexture:{value:null}},a=h("uniform sampler2D passThruTexture;\n\nvoid main() {\n\n\tvec2 uv = gl_FragCoord.xy / resolution.xy;\n\n\tgl_FragColor = texture2D( passThruTexture, uv );\n\n}\n",n),o=new P(a);function u(t){t.defines.resolution="vec2( "+e.toFixed(1)+", "+i.toFixed(1)+" )"}function h(e,i){i=i||{};const s=new t.ShaderMaterial({name:"GPUComputationShader",uniforms:i,vertexShader:"void main()\t{\n\n\tgl_Position = vec4( position, 1.0 );\n\n}\n",fragmentShader:e});return u(s),s}this.setDataType=function(e){return r=e,this},this.addVariable=function(e,i,s){const r={name:e,initialValueTexture:s,material:this.createShaderMaterial(i),dependencies:null,renderTargets:[],wrapS:null,wrapT:null,minFilter:t.NearestFilter,magFilter:t.NearestFilter};return this.variables.push(r),r},this.setVariableDependencies=function(e,t){e.dependencies=t},this.init=function(){if(0===s.capabilities.maxVertexTextures)return"No support for vertex shader textures.";for(let t=0;t<this.variables.length;t++){const s=this.variables[t];s.renderTargets[0]=this.createRenderTarget(e,i,s.wrapS,s.wrapT,s.minFilter,s.magFilter),s.renderTargets[1]=this.createRenderTarget(e,i,s.wrapS,s.wrapT,s.minFilter,s.magFilter),this.renderTexture(s.initialValueTexture,s.renderTargets[0]),this.renderTexture(s.initialValueTexture,s.renderTargets[1]);const r=s.material,n=r.uniforms;if(null!==s.dependencies)for(let e=0;e<s.dependencies.length;e++){const t=s.dependencies[e];if(t.name!==s.name){let e=!1;for(let i=0;i<this.variables.length;i++)if(t.name===this.variables[i].name){e=!0;break}if(!e)return"Variable dependency not found. Variable="+s.name+", dependency="+t.name}n[t.name]={value:null},r.fragmentShader="\nuniform sampler2D "+t.name+";\n"+r.fragmentShader}}return this.currentTextureIndex=0,null},this.compute=function(){const e=this.currentTextureIndex,t=0===this.currentTextureIndex?1:0;for(let i=0,s=this.variables.length;i<s;i++){const s=this.variables[i];if(null!==s.dependencies){const t=s.material.uniforms;for(let i=0,r=s.dependencies.length;i<r;i++){const r=s.dependencies[i];t[r.name].value=r.renderTargets[e].texture}}this.doRenderTarget(s.material,s.renderTargets[t])}this.currentTextureIndex=t},this.getCurrentRenderTarget=function(e){return e.renderTargets[this.currentTextureIndex]},this.getAlternateRenderTarget=function(e){return e.renderTargets[0===this.currentTextureIndex?1:0]},this.dispose=function(){o.dispose();const e=this.variables;for(let t=0;t<e.length;t++){const i=e[t];i.initialValueTexture&&i.initialValueTexture.dispose();const s=i.renderTargets;for(let e=0;e<s.length;e++){s[e].dispose()}}},this.addResolutionDefine=u,this.createShaderMaterial=h,this.createRenderTarget=function(s,n,a,o,u,h){s=s||e,n=n||i,a=a||t.ClampToEdgeWrapping,o=o||t.ClampToEdgeWrapping,u=u||t.NearestFilter,h=h||t.NearestFilter;return new t.WebGLRenderTarget(s,n,{wrapS:a,wrapT:o,minFilter:u,magFilter:h,format:t.RGBAFormat,type:r,depthBuffer:!1})},this.createTexture=function(){const s=new Float32Array(e*i*4),r=new t.DataTexture(s,e,i,t.RGBAFormat,t.FloatType);return r.needsUpdate=!0,r},this.renderTexture=function(e,t){n.passThruTexture.value=e,this.doRenderTarget(a,t),n.passThruTexture.value=null},this.doRenderTarget=function(e,t){const i=s.getRenderTarget(),r=s.xr.enabled,n=s.shadowMap.autoUpdate;s.xr.enabled=!1,s.shadowMap.autoUpdate=!1,o.material=e,s.setRenderTarget(t),o.render(s),o.material=a,s.xr.enabled=r,s.shadowMap.autoUpdate=n,s.setRenderTarget(i)}}}class R{constructor(e,t,i){r(this,"gpuComputationRenderer"),r(this,"webGLRenderer"),r(this,"positionDataTexture"),r(this,"velocityDataTexture"),r(this,"mixPositionsVar"),r(this,"velocityVar"),r(this,"positionVar"),r(this,"interactionPosition"),r(this,"lastKnownPositionDataTexture"),r(this,"lastKnownVelocityDataTexture"),r(this,"lastKnownMixProgress"),r(this,"initialDataTexture"),this.initialDataTexture=i??function(e){const t=new Float32Array(e*e*4);for(let i=0;i<e;i++)for(let s=0;s<e;s++){const r=i*e+s;let n=Math.random()*Math.PI*2,a=Math.acos(2*Math.random()-1),o=Math.sin(a)*Math.cos(n),u=Math.sin(a)*Math.sin(n),h=Math.cos(a);t[4*r]=o,t[4*r+1]=u,t[4*r+2]=h,t[4*r+3]=.01*(Math.random()-.5)}return h(t,e)}(e),this.positionDataTexture=this.initialDataTexture,this.webGLRenderer=t,this.gpuComputationRenderer=new b(e,e,this.webGLRenderer),this.lastKnownMixProgress=0,t.capabilities.isWebGL2||this.gpuComputationRenderer.setDataType(a.HalfFloatType),this.velocityDataTexture=function(e){return h(new Float32Array(4*e*e),e)}(e),this.interactionPosition=new a.Vector4(0,0,0,0),this.mixPositionsVar=this.gpuComputationRenderer.addVariable("uMixedPosition","\nuniform sampler2D uPositionA;\nuniform sampler2D uPositionB;\nuniform float uProgress;\n\nvoid main() {\n vec2 uv = gl_FragCoord.xy / resolution.xy;\n vec3 positionA = texture2D(uPositionA, uv).xyz;\n vec3 positionB = texture2D(uPositionB, uv).xyz;\n vec3 mixedPosition = mix(positionA, positionB, uProgress);\n gl_FragColor = vec4(mixedPosition, 1.0);\n}\n",this.positionDataTexture),this.velocityVar=this.gpuComputationRenderer.addVariable("uCurrentVelocity","\nuniform float uProgress;\nuniform vec4 uInteractionPosition;\nuniform float uTime;\nuniform float uTractionForce;\nuniform float uMaxRepelDistance;\n\nfloat rand(vec2 co) {\n return fract(sin(dot(co, vec2(12.9898, 78.233))) * 43758.5453);\n}\n\nvoid main() {\n vec2 uv = gl_FragCoord.xy / resolution.xy;\n float offset = rand(uv);\n\n vec3 position = texture2D(uCurrentPosition, uv).xyz;\n vec3 velocity = texture2D(uCurrentVelocity, uv).xyz;\n vec3 mixedPosition = texture2D(uMixedPosition, uv).xyz;\n\n velocity *= 0.9;\n\n // particle traction\n vec3 direction = normalize(mixedPosition - position); // direction vector\n float dist = length ( mixedPosition - position ); // distance from where it was supposed to be, and currently are.\n if (dist > 0.01) {\n position += direction * 0.1 * uTractionForce; // uTractionForce defaults to 0.1\n }\n\n // mouse repel force\n float pointerDistance = distance(position, uInteractionPosition.xyz);\n float mouseRepelModifier = clamp(uMaxRepelDistance - pointerDistance, 0.0, 1.0);\n float normalizedDistance = pointerDistance / uMaxRepelDistance;\n float repulsionStrength = (1.0 - normalizedDistance) * uInteractionPosition.w;\n direction = normalize(position - uInteractionPosition.xyz);\n velocity += (direction * 0.01 * repulsionStrength) * mouseRepelModifier;\n\n float lifespan = 20.0;\n float age = mod(uTime + lifespan * offset, lifespan);\n\n if (age < 0.1) {\n position.xyz = mixedPosition;\n }\n\n gl_FragColor = vec4(velocity, 1.0);\n}\n",this.velocityDataTexture),this.positionVar=this.gpuComputationRenderer.addVariable("uCurrentPosition","\nuniform float uProgress;\nuniform vec4 uInteractionPosition;\nuniform float uTime;\nuniform float uTractionForce;\n\nfloat rand(vec2 co) {\n return fract(sin(dot(co, vec2(12.9898, 78.233))) * 43758.5453);\n}\n\nvoid main() {\n\n // in GPGPU, we calculate the uv on each fragment shader, not using the static varying passed over from the v shader.\n vec2 uv = gl_FragCoord.xy / resolution.xy;\n float offset = rand(uv);\n\n vec3 position = texture2D(uCurrentPosition, uv).xyz;\n vec3 velocity = texture2D(uCurrentVelocity, uv).xyz;\n vec3 mixedPosition = texture2D(uMixedPosition, uv).xyz;\n\n // particle attraction to original position.\n vec3 direction = normalize(mixedPosition - position); // direction vector\n float dist = length ( mixedPosition - position ); // distance from where it was supposed to be, and currently are.\n\n if (dist > 0.01) {\n position = mix(position, mixedPosition, 0.1 * uTractionForce); // 0.1 ~ 0.001 (faster, slower)\n }\n\n position += velocity;\n gl_FragColor = vec4(position, 1.0);\n}\n",this.positionDataTexture),this.mixPositionsVar.material.uniforms.uProgress={value:0},this.mixPositionsVar.material.uniforms.uPositionA={value:this.initialDataTexture},this.mixPositionsVar.material.uniforms.uPositionB={value:this.initialDataTexture},this.velocityVar.material.uniforms.uTime={value:0},this.velocityVar.material.uniforms.uInteractionPosition={value:this.interactionPosition},this.velocityVar.material.uniforms.uCurrentPosition={value:this.positionDataTexture},this.velocityVar.material.uniforms.uTractionForce={value:.1},this.velocityVar.material.uniforms.uMaxRepelDistance={value:.3},this.positionVar.material.uniforms.uTime={value:0},this.positionVar.material.uniforms.uProgress={value:0},this.positionVar.material.uniforms.uTractionForce={value:.1},this.positionVar.material.uniforms.uInteractionPosition={value:this.interactionPosition},this.positionVar.material.uniforms.uCurrentPosition={value:this.positionDataTexture},this.gpuComputationRenderer.setVariableDependencies(this.positionVar,[this.velocityVar,this.positionVar,this.mixPositionsVar]),this.gpuComputationRenderer.setVariableDependencies(this.velocityVar,[this.velocityVar,this.positionVar,this.mixPositionsVar]);const s=this.gpuComputationRenderer.init();if(s)throw new Error("failed to initialize SimulationRenderer: "+s);this.lastKnownVelocityDataTexture=this.getVelocityTexture(),this.lastKnownPositionDataTexture=this.getPositionTexture()}setMorphSourceDataTexture(e){this.mixPositionsVar.material.uniforms.uPositionA.value=e}setMorphDestinationDataTexture(e){this.mixPositionsVar.material.uniforms.uPositionB.value=e}setMaxRepelDistance(e){this.velocityVar.material.uniforms.uMaxRepelDistance.value=e}setProgress(e){this.lastKnownMixProgress=l(e,0,1),this.mixPositionsVar.material.uniforms.uProgress.value=this.lastKnownMixProgress}setVelocityTractionForce(e){this.velocityVar.material.uniforms.uTractionForce.value=e}setPositionalTractionForce(e){this.positionVar.material.uniforms.uTractionForce.value=e}setInteractionPosition(e){this.interactionPosition.copy(e)}dispose(){this.mixPositionsVar.renderTargets.forEach((e=>e.dispose())),this.positionVar.renderTargets.forEach((e=>e.dispose())),this.velocityVar.renderTargets.forEach((e=>e.dispose())),this.positionDataTexture.dispose(),this.velocityDataTexture.dispose(),this.gpuComputationRenderer.dispose()}compute(e){this.velocityVar.material.uniforms.uTime.value=e,this.positionVar.material.uniforms.uTime.value=e,this.gpuComputationRenderer.compute()}getVelocityTexture(){return this.lastKnownVelocityDataTexture=this.gpuComputationRenderer.getCurrentRenderTarget(this.velocityVar).texture,this.lastKnownVelocityDataTexture}getPositionTexture(){return this.lastKnownPositionDataTexture=this.gpuComputationRenderer.getCurrentRenderTarget(this.positionVar).texture,this.lastKnownPositionDataTexture}}class V{constructor(e,t,i){r(this,"state"),r(this,"textureSize"),r(this,"dataTextureTransitionProgress"),r(this,"velocityTractionForce"),r(this,"positionalTractionForce"),r(this,"simulationRenderer"),r(this,"webGLRenderer"),r(this,"eventEmitter"),r(this,"lastKnownVelocityDataTexture"),r(this,"lastKnownPositionDataTexture"),this.eventEmitter=e,this.webGLRenderer=i,this.textureSize=t,this.dataTextureTransitionProgress=0,this.velocityTractionForce=.1,this.positionalTractionForce=.1,this.updateServiceState("initializing"),this.simulationRenderer=new R(this.textureSize,this.webGLRenderer),this.lastKnownVelocityDataTexture=this.simulationRenderer.getVelocityTexture(),this.lastKnownPositionDataTexture=this.simulationRenderer.getPositionTexture(),this.updateServiceState("ready")}setTextureSize(e){this.updateServiceState("initializing"),this.simulationRenderer.dispose(),this.textureSize=e,this.simulationRenderer=new R(e,this.webGLRenderer),this.updateServiceState("ready")}setOriginDataTexture(e){this.textureSize!==e.textureSize?this.eventEmitter.emit("invalidRequest",{message:`Texture size mismatch: ${e.textureSize} vs ${this.textureSize}`}):this.simulationRenderer.setMorphSourceDataTexture(e.dataTexture)}setDestinationDataTexture(e){this.textureSize!==e.textureSize?this.eventEmitter.emit("invalidRequest",{message:`Texture size mismatch: ${e.textureSize} vs ${this.textureSize}`}):this.simulationRenderer.setMorphDestinationDataTexture(e.dataTexture)}setDataTextureTransitionProgress(e){this.dataTextureTransitionProgress=e,this.simulationRenderer.setProgress(this.dataTextureTransitionProgress)}setVelocityTractionForce(e){this.velocityTractionForce=e,this.simulationRenderer.setVelocityTractionForce(this.velocityTractionForce)}setPositionalTractionForce(e){this.positionalTractionForce=e,this.simulationRenderer.setPositionalTractionForce(this.positionalTractionForce)}compute(e){this.simulationRenderer.compute(e)}getVelocityTexture(){return"ready"===this.state&&(this.lastKnownVelocityDataTexture=this.simulationRenderer.getVelocityTexture()),this.lastKnownVelocityDataTexture}getPositionTexture(){return"ready"===this.state&&(this.lastKnownPositionDataTexture=this.simulationRenderer.getPositionTexture()),this.lastKnownPositionDataTexture}dispose(){this.updateServiceState("disposed"),this.simulationRenderer.dispose(),this.lastKnownVelocityDataTexture.dispose(),this.lastKnownPositionDataTexture.dispose()}updateServiceState(e){this.state=e,this.eventEmitter.emit("serviceStateUpdated",{type:"simulation",state:e})}setInteractionPosition(e){this.simulationRenderer.setInteractionPosition(e)}setMaxRepelDistance(e){this.simulationRenderer.setMaxRepelDistance(e)}}class A{constructor(){r(this,"execStatus",new Map)}get(e){const t=this.execStatus.get(e);return t||(this.execStatus.set(e,"idle"),"idle")}set(e,t){this.execStatus.set(e,t)}}class C{constructor(e){r(this,"eventEmitter"),r(this,"transitions",new Map),r(this,"execStatus"),r(this,"ongoingTransitions",new Map),this.eventEmitter=e,this.execStatus=new A,this.eventEmitter.on("transitionCancelled",this.handleTransitionCancelledEvent.bind(this))}enqueue(e,t,i={}){const s={...t,...i,cancelled:!1,duration:.001*t.duration};this.getQueue(e).push(s)}compute(e){this.transitions.forEach(((t,i)=>{var s;if(t.length&&!this.ongoingTransitions.has(i)){const r=t.shift();r&&(this.ongoingTransitions.set(i,{...r,startTime:e}),null==(s=r.onTransitionBegin)||s.call(r))}})),this.ongoingTransitions.forEach(((t,i)=>{var s,r,n;if(t.cancelled)return null==(s=t.onTransitionCancelled)||s.call(t),void this.ongoingTransitions.delete(i);const{startTime:a,duration:o,easing:u}=t,h=e-a,c=l(u(Math.min(1,h/o)),0,1);this.emitTransitionProgress(i,c),null==(r=t.onTransitionProgress)||r.call(t,c),c>=1&&(this.emitTransitionFinished(i),null==(n=t.onTransitionFinished)||n.call(t),this.ongoingTransitions.delete(i))}))}getQueue(e){const t=this.transitions.get(e);return t||(this.transitions.set(e,[]),this.transitions.get(e)??[])}handleTransitionCancelledEvent({type:e}){var t;const i=this.getQueue(e);for(;i.length;)i.pop();const s=this.ongoingTransitions.get(e);s&&(s.cancelled=!0,null==(t=s.onTransitionCancelled)||t.call(s))}emitTransitionProgress(e,t){this.eventEmitter.emit("transitionProgressed",{type:e,progress:t})}emitTransitionFinished(e){this.eventEmitter.emit("transitionFinished",{type:e})}}return e.ParticlesEngine=class{constructor(e){r(this,"simulationRendererService"),r(this,"eventEmitter"),r(this,"renderer"),r(this,"scene"),r(this,"serviceStates"),r(this,"assetService"),r(this,"dataTextureManager"),r(this,"instancedMeshManager"),r(this,"transitionService"),r(this,"engineState"),r(this,"intersectionService");const{scene:t,renderer:i,camera:s,textureSize:n,useIntersection:a=!0}=e;this.eventEmitter=new u,this.serviceStates=this.getInitialServiceStates(),this.eventEmitter.on("serviceStateUpdated",this.handleServiceStateUpdated.bind(this)),this.scene=t,this.renderer=i,this.engineState=this.initialEngineState(e),this.assetService=new d(this.eventEmitter),this.transitionService=new C(this.eventEmitter),this.dataTextureManager=new f(this.eventEmitter,n),this.simulationRendererService=new V(this.eventEmitter,n,this.renderer),this.instancedMeshManager=new y(n),this.instancedMeshManager.useMatcapMaterial(),this.scene.add(this.instancedMeshManager.getMesh()),this.intersectionService=new M(this.eventEmitter,s),a||this.intersectionService.setActive(!1),this.eventEmitter.on("transitionProgressed",this.handleTransitionProgress.bind(this)),this.eventEmitter.on("interactionPositionUpdated",this.handleInteractionPositionUpdated.bind(this))}render(e){this.intersectionService.calculate(this.instancedMeshManager.getMesh()),this.transitionService.compute(e),this.simulationRendererService.compute(e),this.instancedMeshManager.update(e),this.instancedMeshManager.updateVelocityTexture(this.simulationRendererService.getVelocityTexture()),this.instancedMeshManager.updatePositionTexture(this.simulationRendererService.getPositionTexture())}setOriginDataTexture(e,t=!1){t&&this.eventEmitter.emit("transitionCancelled",{type:"data-texture"});const i=this.assetService.getMesh(e);i?this.dataTextureManager.getDataTexture(i).then((t=>{this.engineState.originMeshID=e,this.simulationRendererService.setOriginDataTexture({dataTexture:t,textureSize:this.engineState.textureSize}),this.intersectionService.setOriginGeometry(i)})):this.eventEmitter.emit("invalidRequest",{message:`Mesh with id "${e}" does not exist`})}setDestinationDataTexture(e,t=!1){t&&this.eventEmitter.emit("transitionCancelled",{type:"data-texture"});const i=this.assetService.getMesh(e);i?this.dataTextureManager.getDataTexture(i).then((t=>{this.engineState.destinationMeshID=e,this.simulationRendererService.setDestinationDataTexture({dataTexture:t,textureSize:this.engineState.textureSize}),this.intersectionService.setDestinationGeometry(i)})):this.eventEmitter.emit("invalidRequest",{message:`Mesh with id "${e}" does not exist`})}setDataTextureTransitionProgress(e,t=!1){t&&this.eventEmitter.emit("transitionCancelled",{type:"data-texture"}),this.engineState.dataTextureTransitionProgress=e,this.simulationRendererService.setDataTextureTransitionProgress(e),this.intersectionService.setProgress(e)}setOriginMatcap(e,t=!1){t&&this.eventEmitter.emit("transitionCancelled",{type:"matcap"}),this.engineState.originMatcapID=e,this.instancedMeshManager.setOriginMatcap(this.assetService.getMatcap(e))}setDestinationMatcap(e,t=!1){t&&this.eventEmitter.emit("transitionCancelled",{type:"matcap"}),this.engineState.destinationMatcapID=e,this.instancedMeshManager.setDestinationMatcap(this.assetService.getMatcap(e))}setOriginColor(e,t=!1){t&&this.eventEmitter.emit("transitionCancelled",{type:"matcap"}),this.instancedMeshManager.setOriginColor(e)}setDestinationColor(e,t=!1){t&&this.eventEmitter.emit("transitionCancelled",{type:"matcap"}),this.instancedMeshManager.setDestinationColor(e)}setOriginTexture(e,t=!1){t&&this.eventEmitter.emit("transitionCancelled",{type:"matcap"}),"string"==typeof e&&this.assetService.hasMatcap(e)?this.setOriginMatcap(e):this.setOriginColor(e)}setDestinationTexture(e,t=!1){t&&this.eventEmitter.emit("transitionCancelled",{type:"matcap"}),"string"==typeof e&&this.assetService.hasMatcap(e)?this.setDestinationMatcap(e):this.setDestinationColor(e)}setMatcapProgress(e,t=!1){t&&this.eventEmitter.emit("transitionCancelled",{type:"matcap"}),this.engineState.matcapTransitionProgress=e,this.instancedMeshManager.setProgress(e)}async setTextureSize(e){this.engineState.textureSize=e,this.dataTextureManager.setTextureSize(e),this.simulationRendererService.setTextureSize(e),this.instancedMeshManager.resize(e);const t=this.assetService.getMesh(this.engineState.originMeshID);if(!t)return void this.eventEmitter.emit("invalidRequest",{message:`Mesh with id "${this.engineState.originMeshID}" does not exist`});const i=this.assetService.getMesh(this.engineState.destinationMeshID);i?(this.dataTextureManager.getDataTexture(t).then((t=>this.simulationRendererService.setOriginDataTexture({dataTexture:t,textureSize:e}))),this.dataTextureManager.getDataTexture(i).then((t=>this.simulationRendererService.setDestinationDataTexture({dataTexture:t,textureSize:e}))),this.simulationRendererService.setDataTextureTransitionProgress(this.engineState.dataTextureTransitionProgress),this.simulationRendererService.setVelocityTractionForce(this.engineState.velocityTractionForce),this.simulationRendererService.setPositionalTractionForce(this.engineState.positionalTractionForce),this.instancedMeshManager.setOriginMatcap(this.assetService.getMatcap(this.engineState.originMatcapID)),this.instancedMeshManager.setDestinationMatcap(this.assetService.getMatcap(this.engineState.destinationMatcapID)),this.instancedMeshManager.setProgress(this.engineState.matcapTransitionProgress),this.instancedMeshManager.setGeometrySize(this.engineState.instanceGeometryScale)):this.eventEmitter.emit("invalidRequest",{message:`Mesh with id "${this.engineState.destinationMeshID}" does not exist`})}registerMesh(e,t){this.assetService.register(e,t)}registerMatcap(e,t){this.assetService.register(e,t)}async fetchAndRegisterMesh(e,t){return await this.assetService.loadMeshAsync(e,t)}async fetchAndRegisterMatcap(e,t){return await this.assetService.loadTextureAsync(e,t)}useIntersect(e){this.intersectionService.setActive(e),this.engineState.useIntersect=e,e||(this.engineState.pointerPosition={x:-99999999,y:-99999999},this.intersectionService.setPointerPosition(this.engineState.pointerPosition))}setPointerPosition(e){this.engineState.useIntersect&&(this.engineState.pointerPosition=e,this.intersectionService.setPointerPosition(e))}setGeometrySize(e){this.engineState.instanceGeometryScale=e,this.instancedMeshManager.setGeometrySize(e)}setVelocityTractionForce(e){this.engineState.velocityTractionForce=e,this.simulationRendererService.setVelocityTractionForce(e)}setPositionalTractionForce(e){this.engineState.positionalTractionForce=e,this.simulationRendererService.setPositionalTractionForce(e)}setMaxRepelDistance(e){this.engineState.maxRepelDistance=e,this.simulationRendererService.setMaxRepelDistance(e)}scheduleMeshTransition(e,t,i=o,s=1e3,r=!1){this.transitionService.enqueue("data-texture",{easing:i,duration:s},{onTransitionBegin:()=>{this.setOriginDataTexture(e,r),this.setDestinationDataTexture(t,r),this.setDataTextureTransitionProgress(0)}})}scheduleMatcapTransition(e,t,i=o,s=1e3,r=!1){this.transitionService.enqueue("matcap",{easing:i,duration:s},{onTransitionBegin:()=>{this.setOriginMatcap(e,r),this.setDestinationMatcap(t,r),this.setMatcapProgress(0)}})}scheduleTextureTransition(e,t,i){const s=(null==i?void 0:i.easing)??o,r=(null==i?void 0:i.duration)??1e3;(null==i?void 0:i.override)&&this.eventEmitter.emit("transitionCancelled",{type:"matcap"}),this.transitionService.enqueue("matcap",{easing:s,duration:r},{onTransitionBegin:()=>{this.setOriginTexture(e),this.setDestinationTexture(t),this.setMatcapProgress(0)}})}handleServiceStateUpdated({type:e,state:t}){this.serviceStates[e]=t}getObject(){return this.instancedMeshManager.getMesh()}getMeshIDs(){return this.assetService.getMeshIDs()}getMatcapIDs(){return this.assetService.getTextureIDs()}getMeshes(){return this.assetService.getMeshes()}getTextures(){return this.assetService.getTextures()}dispose(){this.scene.remove(this.instancedMeshManager.getMesh()),this.simulationRendererService.dispose(),this.instancedMeshManager.dispose(),this.intersectionService.dispose(),this.assetService.dispose(),this.dataTextureManager.dispose()}initialEngineState(e){return{textureSize:e.textureSize,originMeshID:"",destinationMeshID:"",dataTextureTransitionProgress:0,originMatcapID:"",destinationMatcapID:"",matcapTransitionProgress:0,velocityTractionForce:.1,positionalTractionForce:.1,maxRepelDistance:.3,pointerPosition:{x:0,y:0},instanceGeometryScale:{x:1,y:1,z:1},useIntersect:e.useIntersection??!0}}getInitialServiceStates(){return{"data-texture":"created","instanced-mesh":"created",matcap:"created",simulation:"created",asset:"created"}}handleTransitionProgress({type:e,progress:t}){switch(e){case"data-texture":this.setDataTextureTransitionProgress(t);break;case"matcap":this.setMatcapProgress(t)}}handleInteractionPositionUpdated({position:e}){this.simulationRendererService.setInteractionPosition(e)}},Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),e}({},THREE,three-stdlib);
1
+ var ionian=function(e,t,i){"use strict";var s=Object.defineProperty,n=(e,t,i)=>((e,t,i)=>t in e?s(e,t,{enumerable:!0,configurable:!0,writable:!0,value:i}):e[t]=i)(e,"symbol"!=typeof t?t+"":t,i);function r(e){const t=Object.create(null,{[Symbol.toStringTag]:{value:"Module"}});if(e)for(const i in e)if("default"!==i){const s=Object.getOwnPropertyDescriptor(e,i);Object.defineProperty(t,i,s.get?s:{enumerable:!0,get:()=>e[i]})}return t.default=e,Object.freeze(t)}const a=r(t),o=e=>e;class l{constructor(){var e;n(this,"emitter",{all:e=e||new Map,on:function(t,i){var s=e.get(t);s?s.push(i):e.set(t,[i])},off:function(t,i){var s=e.get(t);s&&(i?s.splice(s.indexOf(i)>>>0,1):e.set(t,[]))},emit:function(t,i){var s=e.get(t);s&&s.slice().map((function(e){e(i)})),(s=e.get("*"))&&s.slice().map((function(e){e(t,i)}))}})}emit(e,t){this.emitter.emit(e,t)}off(e,t){this.emitter.off(e,t)}on(e,t){this.emitter.on(e,t)}once(e,t){this.emitter.on(e,(i=>{this.emitter.off(e,t),t(i)}))}dispose(){this.emitter.all.clear()}}function u(e,t){const i=new a.DataTexture(e,t,t,a.RGBAFormat,a.FloatType);return i.needsUpdate=!0,i}function c(e){e.geometry.dispose(),e.material instanceof a.Material?e.material.dispose():e.material.forEach((e=>e.dispose()))}function h(e,t,i){return e=Math.min(e,i),e=Math.max(e,t)}class d{constructor(e){n(this,"serviceState","created"),n(this,"eventEmitter"),n(this,"meshes",new Map),n(this,"textures",new Map),n(this,"gltfLoader",new i.GLTFLoader),n(this,"textureLoader",new a.TextureLoader),n(this,"dracoLoader",new i.DRACOLoader),n(this,"solidColorTexture",new a.DataTexture(new Uint8Array([127,127,127,255]),1,1,a.RGBAFormat)),this.eventEmitter=e,this.dracoLoader.setDecoderPath("https://www.gstatic.com/draco/versioned/decoders/1.5.7/"),this.gltfLoader.setDRACOLoader(this.dracoLoader),this.updateServiceState("ready")}register(e,t){if(t.name=e,t instanceof a.Mesh){const i=this.meshes.get(e);i&&c(i),this.meshes.set(e,t)}else{const i=this.textures.get(e);i&&i.dispose(),this.textures.set(e,t)}this.eventEmitter.emit("assetRegistered",{id:e})}setSolidColor(e){this.changeColor(e)}getSolidColorTexture(){return this.solidColorTexture}getMesh(e){return this.meshes.get(e)??null}getMatcap(e){const t=this.textures.get(e);return t||this.eventEmitter.emit("invalidRequest",{message:`texture with id "${e}" not found. using solid color texture instead...`}),t??this.solidColorTexture}getMeshIDs(){return Array.from(this.meshes.keys())}getTextureIDs(){return Array.from(this.textures.keys())}getMeshes(){return Array.from(this.meshes.values())}getTextures(){return Array.from(this.textures.values())}hasMatcap(e){return this.textures.has(e)}async loadMeshAsync(e,t,i={}){const s=await this.gltfLoader.loadAsync(t);try{if(i.meshName){const t=s.scene.getObjectByName(i.meshName);return this.register(e,t),t}{const t=s.scene.children[0];return this.register(e,t),t}}catch(n){return this.eventEmitter.emit("invalidRequest",{message:`failed to load mesh: ${e}. ${n}`}),null}}async loadTextureAsync(e,t){try{const i=await this.textureLoader.loadAsync(t);return this.register(e,i),i}catch(i){return this.eventEmitter.emit("invalidRequest",{message:`failed to load texture: ${e}. ${i}`}),null}}dispose(){this.updateServiceState("disposed"),this.meshes.forEach((e=>c(e))),this.meshes.clear(),this.textures.forEach((e=>e.dispose())),this.textures.clear()}changeColor(e){const t=new a.Color(e);this.solidColorTexture=new a.DataTexture(new Uint8Array([t.r,t.g,t.b,255]),1,1,a.RGBAFormat),this.solidColorTexture.needsUpdate=!0}updateServiceState(e){this.serviceState=e,this.eventEmitter.emit("serviceStateUpdated",{type:"asset",state:e})}}const m=new t.Triangle,g=new t.Vector3,p=new t.Vector2,v=new t.Vector2,f=new t.Vector2;class x{constructor(e){this.geometry=e.geometry,this.randomFunction=Math.random,this.indexAttribute=this.geometry.index,this.positionAttribute=this.geometry.getAttribute("position"),this.normalAttribute=this.geometry.getAttribute("normal"),this.colorAttribute=this.geometry.getAttribute("color"),this.uvAttribute=this.geometry.getAttribute("uv"),this.weightAttribute=null,this.distribution=null}setWeightAttribute(e){return this.weightAttribute=e?this.geometry.getAttribute(e):null,this}build(){const e=this.indexAttribute,t=this.positionAttribute,i=this.weightAttribute,s=e?e.count/3:t.count/3,n=new Float32Array(s);for(let o=0;o<s;o++){let s=1,r=3*o,a=3*o+1,l=3*o+2;e&&(r=e.getX(r),a=e.getX(a),l=e.getX(l)),i&&(s=i.getX(r)+i.getX(a)+i.getX(l)),m.a.fromBufferAttribute(t,r),m.b.fromBufferAttribute(t,a),m.c.fromBufferAttribute(t,l),s*=m.getArea(),n[o]=s}const r=new Float32Array(s);let a=0;for(let o=0;o<s;o++)a+=n[o],r[o]=a;return this.distribution=r,this}setRandomGenerator(e){return this.randomFunction=e,this}sample(e,t,i,s){const n=this.sampleFaceIndex();return this.sampleFace(n,e,t,i,s)}sampleFaceIndex(){const e=this.distribution[this.distribution.length-1];return this.binarySearch(this.randomFunction()*e)}binarySearch(e){const t=this.distribution;let i=0,s=t.length-1,n=-1;for(;i<=s;){const r=Math.ceil((i+s)/2);if(0===r||t[r-1]<=e&&t[r]>e){n=r;break}e<t[r]?s=r-1:i=r+1}return n}sampleFace(e,t,i,s,n){let r=this.randomFunction(),a=this.randomFunction();r+a>1&&(r=1-r,a=1-a);const o=this.indexAttribute;let l=3*e,u=3*e+1,c=3*e+2;return o&&(l=o.getX(l),u=o.getX(u),c=o.getX(c)),m.a.fromBufferAttribute(this.positionAttribute,l),m.b.fromBufferAttribute(this.positionAttribute,u),m.c.fromBufferAttribute(this.positionAttribute,c),t.set(0,0,0).addScaledVector(m.a,r).addScaledVector(m.b,a).addScaledVector(m.c,1-(r+a)),void 0!==i&&(void 0!==this.normalAttribute?(m.a.fromBufferAttribute(this.normalAttribute,l),m.b.fromBufferAttribute(this.normalAttribute,u),m.c.fromBufferAttribute(this.normalAttribute,c),i.set(0,0,0).addScaledVector(m.a,r).addScaledVector(m.b,a).addScaledVector(m.c,1-(r+a)).normalize()):m.getNormal(i)),void 0!==s&&void 0!==this.colorAttribute&&(m.a.fromBufferAttribute(this.colorAttribute,l),m.b.fromBufferAttribute(this.colorAttribute,u),m.c.fromBufferAttribute(this.colorAttribute,c),g.set(0,0,0).addScaledVector(m.a,r).addScaledVector(m.b,a).addScaledVector(m.c,1-(r+a)),s.r=g.x,s.g=g.y,s.b=g.z),void 0!==n&&void 0!==this.uvAttribute&&(p.fromBufferAttribute(this.uvAttribute,l),v.fromBufferAttribute(this.uvAttribute,u),f.fromBufferAttribute(this.uvAttribute,c),n.set(0,0).addScaledVector(p,r).addScaledVector(v,a).addScaledVector(f,1-(r+a))),this}}class y{constructor(e,t){n(this,"textureSize"),n(this,"dataTextures"),n(this,"eventEmitter"),n(this,"currentAtlas",null),this.eventEmitter=e,this.textureSize=t,this.dataTextures=new Map,this.updateServiceState("ready")}setTextureSize(e){this.textureSize!==e&&(this.textureSize=e,this.dataTextures.forEach((e=>e.dispose())),this.dataTextures.clear(),this.currentAtlas&&(this.currentAtlas.dispose(),this.currentAtlas=null))}async getDataTexture(e){const t=this.dataTextures.get(e.uuid);if(t)return t;var i,s;const n=function(e,t){const i=new a.BufferGeometry;i.setAttribute("position",new a.BufferAttribute(new Float32Array(e.position),3)),e.normal&&i.setAttribute("normal",new a.BufferAttribute(new Float32Array(e.normal),3));const s=new a.MeshBasicMaterial,n=new a.Mesh(i,s);n.scale.set(e.scale.x,e.scale.y,e.scale.z);const r=new x(n).build(),o=new Float32Array(t*t*4),l=new a.Vector3;for(let a=0;a<t;a++)for(let i=0;i<t;i++){const s=a*t+i;r.sample(l),o[4*s]=l.x*e.scale.x,o[4*s+1]=l.y*e.scale.y,o[4*s+2]=l.z*e.scale.z,o[4*s+3]=.01*(Math.random()-.5)}return o}({position:(i=e).geometry.attributes.position.array,normal:null==(s=i.geometry.attributes.normal)?void 0:s.array,scale:{x:i.scale.x,y:i.scale.y,z:i.scale.z}},this.textureSize),r=u(n,this.textureSize);return r.name=e.name,this.dataTextures.set(e.uuid,r),r}async dispose(){this.dataTextures.forEach((e=>e.dispose())),this.dataTextures.clear(),this.currentAtlas&&(this.currentAtlas.dispose(),this.currentAtlas=null),this.updateServiceState("disposed")}updateServiceState(e){this.eventEmitter.emit("serviceStateUpdated",{type:"data-texture",state:e})}async createSequenceDataTextureAtlas(e,t){this.updateServiceState("loading"),this.currentAtlas&&(this.currentAtlas.dispose(),this.currentAtlas=null);const i=e.length;if(0===i)throw new Error("Mesh array cannot be empty.");const s=t*i,n=t,r=new Float32Array(s*n*4);try{for(let n=0;n<i;n++){const i=e[n],a=(await this.getDataTexture(i)).image.data;for(let e=0;e<t;e++)for(let i=0;i<t;i++){const o=4*(e*t+i),l=4*(e*s+(i+n*t));r[l]=a[o],r[l+1]=a[o+1],r[l+2]=a[o+2],r[l+3]=a[o+3]}}const o=new a.DataTexture(r,s,n,a.RGBAFormat,a.FloatType);return o.needsUpdate=!0,o.name=`atlas-${e.map((e=>e.name)).join("-")}`,this.currentAtlas=o,this.updateServiceState("ready"),o}catch(o){throw this.updateServiceState("error"),o}}}class T{constructor(e){n(this,"size"),n(this,"mesh"),n(this,"matcapMaterial"),n(this,"fallbackGeometry"),n(this,"uniforms"),n(this,"originColor"),n(this,"destinationColor"),n(this,"geometries"),n(this,"uvRefsCache"),n(this,"previousScale"),this.size=e,this.geometries=new Map,this.uvRefsCache=new Map,this.previousScale={x:1,y:1,z:1},this.originColor="grey",this.destinationColor="grey",this.uniforms={uTime:{value:0},uProgress:{value:0},uTexture:{value:null},uVelocity:{value:null},uOriginTexture:{value:null},uDestinationTexture:{value:null}},this.matcapMaterial=new a.ShaderMaterial({uniforms:this.uniforms,vertexShader:"\nvarying vec2 vUv;\nuniform sampler2D uTexture;\nuniform sampler2D uVelocity;\nuniform float uTime;\nvarying vec3 vNormal;\nattribute vec2 uvRef;\nvarying vec3 vViewPosition;\n\nvec3 rotate3D(vec3 v, vec3 vel) {\n vec3 pos = v;\n vec3 up = vec3(0, 1, 0);\n vec3 axis = normalize(cross(up, vel));\n float angle = acos(dot(up, normalize(vel)));\n pos = pos * cos(angle) + cross(axis, pos) * sin(angle) + axis * dot(axis, pos) * (1. - cos(angle));\n return pos;\n}\n\nvoid main() {\n vUv = uv;\n vNormal = normal;\n\n vec4 color = texture2D(uTexture, uvRef);\n vec4 velocity = texture2D(uVelocity, uvRef);\n vec3 pos = color.xyz;// apply the texture to the vertex distribution.\n\n vec3 localPosition = position.xyz;\n if (length (velocity.xyz) < 0.0001) {\n velocity.xyz = vec3(0.0, 0.0001, 0.0001);\n }\n localPosition.y *= max(1.0, length(velocity.xyz) * 1000.0);\n localPosition = rotate3D(localPosition, velocity.xyz);\n vNormal = rotate3D(normal, velocity.xyz);\n\n mat4 instanceMat = instanceMatrix;\n instanceMat[3].xyz = pos.xyz;\n\n // unlike the traditional mvMatrix * position, we need to additional multiplication with the instance matrix.\n vec4 modelViewPosition = modelViewMatrix * instanceMat * vec4(localPosition, 1.0);\n\n vViewPosition = - modelViewPosition.xyz;\n\n gl_Position = projectionMatrix * modelViewPosition;\n}\n",fragmentShader:"\nvarying vec2 vUv;\nuniform sampler2D uTexture;\n\nuniform sampler2D uOriginTexture;\nuniform sampler2D uDestinationTexture;\n\nuniform float uProgress;\nvarying vec3 vNormal;\nvarying vec3 vViewPosition;\nvoid main() {\n vec3 viewDir = normalize( vViewPosition );\n vec3 x = normalize( vec3( viewDir.z, 0.0, - viewDir.x ) );\n vec3 y = cross( viewDir, x );\n vec2 uv = vec2( dot( x, vNormal ), dot( y, vNormal ) ) * 0.495 + 0.5; // 0.495 to remove artifacts caused by undersized matcap disks\n\n vec4 sourceMatcap = texture2D( uOriginTexture, uv );\n vec4 targetMatcap = texture2D( uDestinationTexture, uv );\n\n vec4 matcap = mix(sourceMatcap, targetMatcap, uProgress);\n gl_FragColor = matcap;\n}\n"}),this.setOriginColor(this.originColor),this.setDestinationColor(this.destinationColor),this.fallbackGeometry=new a.BoxGeometry(.001,.001,.001),this.mesh=this.createInstancedMesh(e,this.fallbackGeometry,this.matcapMaterial)}getMesh(){return this.mesh}update(e){const t=this.mesh.material;(t instanceof a.ShaderMaterial||t instanceof a.RawShaderMaterial)&&(t.uniforms.uTime.value=e)}setOriginMatcap(e){this.disposeSolidColorOriginTexture(),this.matcapMaterial.uniforms.uOriginTexture.value=e}setDestinationMatcap(e){this.disposeSolidColorDestinationTexture(),this.matcapMaterial.uniforms.uDestinationTexture.value=e}setProgress(e){e=Math.max(0,e),e=Math.min(1,e),this.matcapMaterial.uniforms.uProgress.value=e}setGeometrySize(e){this.mesh.geometry.scale(1/this.previousScale.x,1/this.previousScale.y,1/this.previousScale.z),this.mesh.geometry.scale(e.x,e.y,e.z),this.previousScale=e}useMatcapMaterial(){this.mesh.material=this.matcapMaterial}useGeometry(e){const t=this.geometries.get(e);t&&(this.mesh.geometry=t)}updateVelocityTexture(e){this.matcapMaterial.uniforms.uVelocity.value=e}updatePositionTexture(e){this.matcapMaterial.uniforms.uTexture.value=e}resize(e){if(this.size===e)return{current:this.mesh,previous:this.mesh};this.size=e;const t=this.mesh;return this.mesh=this.createInstancedMesh(e,t.geometry,t.material),{current:this.mesh,previous:t}}dispose(){this.mesh.dispose(),this.geometries.forEach((e=>e.dispose())),this.disposeSolidColorOriginTexture(),this.disposeSolidColorDestinationTexture(),this.matcapMaterial.dispose(),this.uvRefsCache.clear(),this.geometries.clear()}registerGeometry(e,t){const i=this.geometries.get(e);if(i&&i===t)return;const s=this.createUVRefs(this.size);t.setAttribute("uvRef",s),this.geometries.set(e,t),this.mesh.geometry===i&&(this.mesh.geometry=t),null==i||i.dispose()}setOriginColor(e){this.disposeSolidColorOriginTexture(),this.originColor=e,this.uniforms.uOriginTexture.value=this.createSolidColorDataTexture(e)}setDestinationColor(e){this.disposeSolidColorDestinationTexture(),this.destinationColor=e,this.uniforms.uDestinationTexture.value=this.createSolidColorDataTexture(e)}createUVRefs(e){const t=this.uvRefsCache.get(e);if(t)return t;const i=new Float32Array(e*e*2);for(let n=0;n<e;n++)for(let t=0;t<e;t++){const s=n*e+t;i[2*s]=t/(e-1),i[2*s+1]=n/(e-1)}const s=new a.InstancedBufferAttribute(i,2);return this.uvRefsCache.set(e,s),s}createInstancedMesh(e,t,i){(t=t||this.fallbackGeometry).setAttribute("uvRef",this.createUVRefs(e));const s=e*e;return new a.InstancedMesh(t,i,s)}createSolidColorDataTexture(e,t=16){const i=new a.Color(e),s=t,n=t,r=new Uint8Array(s*n*4),o=Math.floor(255*i.r),l=Math.floor(255*i.g),u=Math.floor(255*i.b);for(let a=0;a<s*n;a++){const e=4*a;r[e]=o,r[e+1]=l,r[e+2]=u,r[e+3]=255}const c=new a.DataTexture(r,s,n,a.RGBAFormat);return c.type=a.UnsignedByteType,c.wrapS=a.RepeatWrapping,c.wrapT=a.RepeatWrapping,c.minFilter=a.NearestFilter,c.magFilter=a.NearestFilter,c.needsUpdate=!0,c}disposeSolidColorOriginTexture(){this.originColor&&(this.originColor=null,this.uniforms.uOriginTexture.value&&this.uniforms.uOriginTexture.value.dispose())}disposeSolidColorDestinationTexture(){this.destinationColor&&(this.destinationColor=null,this.uniforms.uDestinationTexture.value&&this.uniforms.uDestinationTexture.value.dispose())}}class S{constructor(e,t){n(this,"active",!0),n(this,"raycaster",new a.Raycaster),n(this,"mousePosition",new a.Vector2),n(this,"camera"),n(this,"meshSequenceGeometries",[]),n(this,"meshSequenceUUIDs",[]),n(this,"overallProgress",0),n(this,"intersectionMesh",new a.Mesh),n(this,"geometryNeedsUpdate"),n(this,"eventEmitter"),n(this,"blendedGeometry"),n(this,"intersection"),this.camera=t,this.eventEmitter=e,this.geometryNeedsUpdate=!0}setActive(e){this.active=e,e||(this.intersection=void 0,this.eventEmitter.emit("interactionPositionUpdated",{position:{x:0,y:0,z:0,w:0}}))}getIntersectionMesh(){return this.intersectionMesh}setCamera(e){this.camera=e}setMeshSequence(e){this.meshSequenceGeometries.forEach((e=>e.dispose())),this.meshSequenceGeometries=[],this.meshSequenceUUIDs=[],e&&0!==e.length?(e.forEach((e=>{if(e&&e.geometry){const t=e.geometry.clone();t.applyMatrix4(e.matrixWorld),this.meshSequenceGeometries.push(t),this.meshSequenceUUIDs.push(e.uuid)}else console.warn("Invalid mesh provided to IntersectionService sequence.")})),this.geometryNeedsUpdate=!0):this.geometryNeedsUpdate=!0}setOverallProgress(e){const t=a.MathUtils.clamp(e,0,1);this.overallProgress!==t&&(this.overallProgress=t,this.geometryNeedsUpdate=!0)}setPointerPosition(e){e&&this.mousePosition.copy(e)}calculate(e){var t,i,s;if(!this.active||!this.camera||0===this.meshSequenceGeometries.length)return void(this.intersection&&(this.intersection=void 0,this.eventEmitter.emit("interactionPositionUpdated",{position:{x:0,y:0,z:0,w:0}})));let n;this.geometryNeedsUpdate&&(this.blendedGeometry&&this.blendedGeometry!==this.intersectionMesh.geometry&&this.blendedGeometry.dispose(),this.blendedGeometry=this.getBlendedGeometry(),this.geometryNeedsUpdate=!1,this.blendedGeometry?this.intersectionMesh.geometry!==this.blendedGeometry&&(this.intersectionMesh.geometry&&this.intersectionMesh.geometry.dispose(),this.intersectionMesh.geometry=this.blendedGeometry):(this.intersectionMesh.geometry&&this.intersectionMesh.geometry.dispose(),this.intersectionMesh.geometry=new a.BufferGeometry)),this.intersectionMesh.matrixWorld.copy(e.matrixWorld),this.blendedGeometry&&this.blendedGeometry.attributes.position&&(n=this.getFirstIntersection(this.camera,this.intersectionMesh));if((null==(t=this.intersection)?void 0:t.x)!==(null==n?void 0:n.x)||(null==(i=this.intersection)?void 0:i.y)!==(null==n?void 0:n.y)||(null==(s=this.intersection)?void 0:s.z)!==(null==n?void 0:n.z)||this.intersection&&!n||!this.intersection&&n)if(this.intersection=n,this.intersection){const t=new a.Vector3(this.intersection.x,this.intersection.y,this.intersection.z),i=e.worldToLocal(t.clone());this.intersection.set(i.x,i.y,i.z,1),this.eventEmitter.emit("interactionPositionUpdated",{position:this.intersection})}else this.eventEmitter.emit("interactionPositionUpdated",{position:{x:0,y:0,z:0,w:0}});return this.intersection}dispose(){var e;this.meshSequenceGeometries.forEach((e=>e.dispose())),this.meshSequenceGeometries=[],this.meshSequenceUUIDs=[],this.blendedGeometry&&this.blendedGeometry!==this.intersectionMesh.geometry&&this.blendedGeometry.dispose(),null==(e=this.intersectionMesh.geometry)||e.dispose()}updateIntersectionMesh(e){this.blendedGeometry&&this.blendedGeometry.uuid!==this.intersectionMesh.geometry.uuid&&(this.intersectionMesh.geometry.dispose(),this.intersectionMesh.geometry=this.blendedGeometry),this.intersectionMesh.matrix.copy(e.matrixWorld),this.intersectionMesh.matrixWorld.copy(e.matrixWorld),this.intersectionMesh.matrixAutoUpdate=!1,this.intersectionMesh.updateMatrixWorld(!0)}getFirstIntersection(e,t){this.raycaster.setFromCamera(this.mousePosition,e);const i=this.raycaster.intersectObject(t,!1);if(i.length>0&&i[0].point){const e=i[0].point;return new a.Vector4(e.x,e.y,e.z,1)}}getBlendedGeometry(){const e=this.meshSequenceGeometries.length;if(0===e)return;if(1===e)return this.meshSequenceGeometries[0];const t=e-1,i=1/t,s=this.overallProgress*t;let n=Math.floor(s),r=n+1;n=a.MathUtils.clamp(n,0,t),r=a.MathUtils.clamp(r,0,t);let o=0;i>0&&(o=s-n),this.overallProgress>=1&&(n=t,r=t,o=1),o=a.MathUtils.clamp(o,0,1);const l=this.meshSequenceGeometries[n],u=this.meshSequenceGeometries[r];return l&&u?n===r?l:this.blendGeometry(l,u,o):(console.error("IntersectionService: Invalid geometries found for blending at indices",n,r),this.meshSequenceGeometries[0])}blendGeometry(e,t,i){const s=new a.BufferGeometry,n=e.attributes.position.array,r=t.attributes.position.array,o=new Float32Array(n.length);for(let l=0;l<n.length;l+=3){const e=new a.Vector3(n[l],n[l+1],n[l+2]),t=new a.Vector3(r[l],r[l+1],r[l+2]),s=(new a.Vector3).lerpVectors(e,t,i);o[l]=s.x,o[l+1]=s.y,o[l+2]=s.z}return s.setAttribute("position",new a.BufferAttribute(o,3)),e.attributes.normal&&s.setAttribute("normal",e.attributes.normal.clone()),e.attributes.uv&&s.setAttribute("uv",e.attributes.uv.clone()),e.index&&s.setIndex(e.index.clone()),s}}const M=new t.OrthographicCamera(-1,1,1,-1,0,1);class P extends t.BufferGeometry{constructor(){super(),this.setAttribute("position",new t.Float32BufferAttribute([-1,3,0,-1,-1,0,3,-1,0],3)),this.setAttribute("uv",new t.Float32BufferAttribute([0,2,0,0,2,0],2))}}const w=new P;class A{constructor(e){this._mesh=new t.Mesh(w,e)}dispose(){this._mesh.geometry.dispose()}render(e){e.render(this._mesh,M)}get material(){return this._mesh.material}set material(e){this._mesh.material=e}}class b{constructor(e,i,s){this.variables=[],this.currentTextureIndex=0;let n=t.FloatType;const r={passThruTexture:{value:null}},a=u("uniform sampler2D passThruTexture;\n\nvoid main() {\n\n\tvec2 uv = gl_FragCoord.xy / resolution.xy;\n\n\tgl_FragColor = texture2D( passThruTexture, uv );\n\n}\n",r),o=new A(a);function l(t){t.defines.resolution="vec2( "+e.toFixed(1)+", "+i.toFixed(1)+" )"}function u(e,i){i=i||{};const s=new t.ShaderMaterial({name:"GPUComputationShader",uniforms:i,vertexShader:"void main()\t{\n\n\tgl_Position = vec4( position, 1.0 );\n\n}\n",fragmentShader:e});return l(s),s}this.setDataType=function(e){return n=e,this},this.addVariable=function(e,i,s){const n={name:e,initialValueTexture:s,material:this.createShaderMaterial(i),dependencies:null,renderTargets:[],wrapS:null,wrapT:null,minFilter:t.NearestFilter,magFilter:t.NearestFilter};return this.variables.push(n),n},this.setVariableDependencies=function(e,t){e.dependencies=t},this.init=function(){if(0===s.capabilities.maxVertexTextures)return"No support for vertex shader textures.";for(let t=0;t<this.variables.length;t++){const s=this.variables[t];s.renderTargets[0]=this.createRenderTarget(e,i,s.wrapS,s.wrapT,s.minFilter,s.magFilter),s.renderTargets[1]=this.createRenderTarget(e,i,s.wrapS,s.wrapT,s.minFilter,s.magFilter),this.renderTexture(s.initialValueTexture,s.renderTargets[0]),this.renderTexture(s.initialValueTexture,s.renderTargets[1]);const n=s.material,r=n.uniforms;if(null!==s.dependencies)for(let e=0;e<s.dependencies.length;e++){const t=s.dependencies[e];if(t.name!==s.name){let e=!1;for(let i=0;i<this.variables.length;i++)if(t.name===this.variables[i].name){e=!0;break}if(!e)return"Variable dependency not found. Variable="+s.name+", dependency="+t.name}r[t.name]={value:null},n.fragmentShader="\nuniform sampler2D "+t.name+";\n"+n.fragmentShader}}return this.currentTextureIndex=0,null},this.compute=function(){const e=this.currentTextureIndex,t=0===this.currentTextureIndex?1:0;for(let i=0,s=this.variables.length;i<s;i++){const s=this.variables[i];if(null!==s.dependencies){const t=s.material.uniforms;for(let i=0,n=s.dependencies.length;i<n;i++){const n=s.dependencies[i];t[n.name].value=n.renderTargets[e].texture}}this.doRenderTarget(s.material,s.renderTargets[t])}this.currentTextureIndex=t},this.getCurrentRenderTarget=function(e){return e.renderTargets[this.currentTextureIndex]},this.getAlternateRenderTarget=function(e){return e.renderTargets[0===this.currentTextureIndex?1:0]},this.dispose=function(){o.dispose();const e=this.variables;for(let t=0;t<e.length;t++){const i=e[t];i.initialValueTexture&&i.initialValueTexture.dispose();const s=i.renderTargets;for(let e=0;e<s.length;e++){s[e].dispose()}}},this.addResolutionDefine=l,this.createShaderMaterial=u,this.createRenderTarget=function(s,r,a,o,l,u){s=s||e,r=r||i,a=a||t.ClampToEdgeWrapping,o=o||t.ClampToEdgeWrapping,l=l||t.NearestFilter,u=u||t.NearestFilter;return new t.WebGLRenderTarget(s,r,{wrapS:a,wrapT:o,minFilter:l,magFilter:u,format:t.RGBAFormat,type:n,depthBuffer:!1})},this.createTexture=function(){const s=new Float32Array(e*i*4),n=new t.DataTexture(s,e,i,t.RGBAFormat,t.FloatType);return n.needsUpdate=!0,n},this.renderTexture=function(e,t){r.passThruTexture.value=e,this.doRenderTarget(a,t),r.passThruTexture.value=null},this.doRenderTarget=function(e,t){const i=s.getRenderTarget(),n=s.xr.enabled,r=s.shadowMap.autoUpdate;s.xr.enabled=!1,s.shadowMap.autoUpdate=!1,o.material=e,s.setRenderTarget(t),o.render(s),o.material=a,s.xr.enabled=n,s.shadowMap.autoUpdate=r,s.setRenderTarget(i)}}}class V{constructor(e,t,i){n(this,"gpuComputationRenderer"),n(this,"webGLRenderer"),n(this,"velocityVar"),n(this,"positionVar"),n(this,"initialPositionDataTexture"),n(this,"initialVelocityDataTexture"),n(this,"positionAtlasTexture",null),n(this,"interactionPosition"),n(this,"lastKnownPositionDataTexture"),n(this,"lastKnownVelocityDataTexture"),this.webGLRenderer=t,this.gpuComputationRenderer=new b(e,e,this.webGLRenderer),!t.capabilities.isWebGL2&&t.extensions.get("OES_texture_float")?this.gpuComputationRenderer.setDataType(a.FloatType):t.capabilities.isWebGL2||this.gpuComputationRenderer.setDataType(a.HalfFloatType),this.initialPositionDataTexture=i??function(e){const t=new Float32Array(e*e*4);for(let i=0;i<e;i++)for(let s=0;s<e;s++){const n=i*e+s;let r=Math.random()*Math.PI*2,a=Math.acos(2*Math.random()-1),o=Math.sin(a)*Math.cos(r),l=Math.sin(a)*Math.sin(r),u=Math.cos(a);t[4*n]=o,t[4*n+1]=l,t[4*n+2]=u,t[4*n+3]=.01*(Math.random()-.5)}return u(t,e)}(e),this.initialVelocityDataTexture=function(e){return u(new Float32Array(4*e*e),e)}(e),this.interactionPosition=new a.Vector4(0,0,0,0),this.velocityVar=this.gpuComputationRenderer.addVariable("uCurrentVelocity",'\nuniform vec4 uInteractionPosition;\nuniform float uTime;\nuniform float uTractionForce;\nuniform float uMaxRepelDistance;\nuniform sampler2D uPositionAtlas;\nuniform float uOverallProgress;\nuniform int uNumMeshes;\nuniform float uSingleTextureSize;\n\nfloat rand(vec2 co) {\n return fract(sin(dot(co, vec2(12.9898, 78.233))) * 43758.5453);\n}\n\n// Helper function (same as in position shader)\nvec3 getAtlasPosition(vec2 uv, int meshIndex) {\n float atlasWidth = uSingleTextureSize * float(uNumMeshes);\n float atlasHeight = uSingleTextureSize;\n float segmentWidthRatio = uSingleTextureSize / atlasWidth;\n vec2 atlasUV = vec2(uv.x * segmentWidthRatio + segmentWidthRatio * float(meshIndex), uv.y);\n return texture2D(uPositionAtlas, atlasUV).xyz;\n}\n\nvoid main() {\n vec2 uv = gl_FragCoord.xy / resolution.xy;\n float offset = rand(uv);\n\n vec3 currentPosition = texture2D(uCurrentPosition, uv).xyz;\n vec3 currentVelocity = texture2D(uCurrentVelocity, uv).xyz;\n\n // --- Calculate Target Position from Atlas (same logic as position shader) ---\n vec3 targetPosition;\n if (uNumMeshes <= 1) {\n targetPosition = getAtlasPosition(uv, 0);\n } else {\n float totalSegments = float(uNumMeshes - 1);\n float progressPerSegment = 1.0 / totalSegments;\n float scaledProgress = uOverallProgress * totalSegments;\n int indexA = int(floor(scaledProgress));\n int indexB = min(indexA + 1, uNumMeshes - 1);\n indexA = min(indexA, uNumMeshes - 1);\n float localProgress = fract(scaledProgress);\n if (uOverallProgress == 1.0) {\n indexA = uNumMeshes - 1;\n indexB = uNumMeshes - 1;\n localProgress = 1.0;\n }\n vec3 positionA = getAtlasPosition(uv, indexA);\n vec3 positionB = getAtlasPosition(uv, indexB);\n targetPosition = mix(positionA, positionB, localProgress);\n }\n // --- End Target Position Calculation ---\n\n vec3 finalVelocity = currentVelocity * 0.9; // Dampening\n\n // Particle traction force towards target (influences velocity)\n vec3 direction = normalize(targetPosition - currentPosition);\n float dist = length(targetPosition - currentPosition);\n if (dist > 0.01) {\n // Add force proportional to distance and traction setting\n finalVelocity += direction * dist * 0.01 * uTractionForce; // Adjust multiplier as needed\n }\n\n // Mouse repel force\n if (uInteractionPosition.w > 0.0) { // Check if interaction is active (w component)\n float pointerDistance = distance(currentPosition, uInteractionPosition.xyz);\n if (pointerDistance < uMaxRepelDistance) {\n float mouseRepelModifier = smoothstep(uMaxRepelDistance, 0.0, pointerDistance); // Smoother falloff\n vec3 repelDirection = normalize(currentPosition - uInteractionPosition.xyz);\n // Apply force based on proximity and interaction strength (w)\n finalVelocity += repelDirection * mouseRepelModifier * uInteractionPosition.w * 0.01; // Adjust multiplier\n }\n }\n\n // Optional: Reset position if particle "dies" and respawns (lifespan logic)\n float lifespan = 20.0;\n float age = mod(uTime * 0.1 + lifespan * offset, lifespan); // Adjust time scale\n if (age < 0.05) { // Small window for reset\n finalVelocity = vec3(0.0); // Reset velocity on respawn\n // Note: Resetting position directly here might cause jumps.\n // It\'s often better handled in the position shader or by ensuring\n // strong attraction force when dist is large.\n }\n\n\n gl_FragColor = vec4(finalVelocity, 1.0);\n}\n',this.initialVelocityDataTexture),this.positionVar=this.gpuComputationRenderer.addVariable("uCurrentPosition","\nuniform vec4 uInteractionPosition;\nuniform float uTime;\nuniform float uTractionForce;\nuniform sampler2D uPositionAtlas;\nuniform float uOverallProgress; // (0.0 to 1.0)\nuniform int uNumMeshes;\nuniform float uSingleTextureSize;\n\nfloat rand(vec2 co) {\n return fract(sin(dot(co, vec2(12.9898, 78.233))) * 43758.5453);\n}\n\n// Helper function to get position from atlas\nvec3 getAtlasPosition(vec2 uv, int meshIndex) {\n float atlasWidth = uSingleTextureSize * float(uNumMeshes);\n float atlasHeight = uSingleTextureSize; // Assuming height is single texture size\n\n // Calculate UV within the specific mesh's section of the atlas\n float segmentWidthRatio = uSingleTextureSize / atlasWidth;\n vec2 atlasUV = vec2(\n uv.x * segmentWidthRatio + segmentWidthRatio * float(meshIndex),\n uv.y // Assuming vertical layout doesn't change y\n );\n\n return texture2D(uPositionAtlas, atlasUV).xyz;\n}\n\nvoid main() {\n // GPGPU UV calculation\n vec2 uv = gl_FragCoord.xy / resolution.xy; // resolution is the size of the *output* texture (e.g., 256x256)\n\n vec3 currentPosition = texture2D(uCurrentPosition, uv).xyz;\n vec3 currentVelocity = texture2D(uCurrentVelocity, uv).xyz;\n\n // --- Calculate Target Position from Atlas ---\n vec3 targetPosition;\n if (uNumMeshes <= 1) {\n targetPosition = getAtlasPosition(uv, 0);\n } else {\n float totalSegments = float(uNumMeshes - 1);\n float progressPerSegment = 1.0 / totalSegments;\n float scaledProgress = uOverallProgress * totalSegments;\n\n int indexA = int(floor(scaledProgress));\n // Clamp indexB to avoid going out of bounds\n int indexB = min(indexA + 1, uNumMeshes - 1);\n\n // Ensure indexA is also within bounds (important if uOverallProgress is exactly 1.0)\n indexA = min(indexA, uNumMeshes - 1);\n\n\n float localProgress = fract(scaledProgress);\n\n // Handle edge case where progress is exactly 1.0\n if (uOverallProgress == 1.0) {\n indexA = uNumMeshes - 1;\n indexB = uNumMeshes - 1;\n localProgress = 1.0; // or 0.0 depending on how you want to handle it\n }\n\n\n vec3 positionA = getAtlasPosition(uv, indexA);\n vec3 positionB = getAtlasPosition(uv, indexB);\n\n targetPosition = mix(positionA, positionB, localProgress);\n }\n // --- End Target Position Calculation ---\n\n // Particle attraction to target position\n vec3 direction = normalize(targetPosition - currentPosition);\n float dist = length(targetPosition - currentPosition);\n\n vec3 finalPosition = currentPosition;\n\n // Apply attraction force (simplified mix)\n if (dist > 0.01) { // Only apply if significantly far\n finalPosition = mix(currentPosition, targetPosition, 0.1 * uTractionForce);\n }\n\n finalPosition += currentVelocity;\n gl_FragColor = vec4(finalPosition, 1.0);\n}\n",this.initialPositionDataTexture),this.velocityVar.material.uniforms.uTime={value:0},this.velocityVar.material.uniforms.uInteractionPosition={value:this.interactionPosition},this.velocityVar.material.uniforms.uCurrentPosition={value:null},this.velocityVar.material.uniforms.uTractionForce={value:.1},this.velocityVar.material.uniforms.uMaxRepelDistance={value:.3},this.velocityVar.material.uniforms.uPositionAtlas={value:null},this.velocityVar.material.uniforms.uOverallProgress={value:0},this.velocityVar.material.uniforms.uNumMeshes={value:1},this.velocityVar.material.uniforms.uSingleTextureSize={value:e},this.positionVar.material.uniforms.uTime={value:0},this.positionVar.material.uniforms.uTractionForce={value:.1},this.positionVar.material.uniforms.uInteractionPosition={value:this.interactionPosition},this.positionVar.material.uniforms.uCurrentPosition={value:null},this.positionVar.material.uniforms.uCurrentVelocity={value:null},this.positionVar.material.uniforms.uPositionAtlas={value:null},this.positionVar.material.uniforms.uOverallProgress={value:0},this.positionVar.material.uniforms.uNumMeshes={value:1},this.positionVar.material.uniforms.uSingleTextureSize={value:e},this.gpuComputationRenderer.setVariableDependencies(this.positionVar,[this.positionVar,this.velocityVar]),this.gpuComputationRenderer.setVariableDependencies(this.velocityVar,[this.velocityVar,this.positionVar]);const s=this.gpuComputationRenderer.init();if(null!==s)throw new Error("Failed to initialize SimulationRenderer: "+s);this.positionVar.material.uniforms.uPositionAtlas.value=this.initialPositionDataTexture,this.positionVar.material.uniforms.uNumMeshes.value=1,this.velocityVar.material.uniforms.uNumMeshes.value=1,this.positionVar.material.uniforms.uSingleTextureSize.value=e,this.velocityVar.material.uniforms.uSingleTextureSize.value=e,this.positionVar.material.uniforms.uCurrentVelocity.value=this.gpuComputationRenderer.getCurrentRenderTarget(this.velocityVar).texture,this.velocityVar.material.uniforms.uCurrentPosition.value=this.gpuComputationRenderer.getCurrentRenderTarget(this.positionVar).texture,this.lastKnownVelocityDataTexture=this.gpuComputationRenderer.getCurrentRenderTarget(this.velocityVar).texture,this.lastKnownPositionDataTexture=this.gpuComputationRenderer.getCurrentRenderTarget(this.positionVar).texture}setPositionAtlas(e){const t=e.singleTextureSize*e.numMeshes;e.dataTexture.image.width===t&&e.dataTexture.image.height===e.singleTextureSize||console.error(`SimulationRenderer: Atlas texture dimension mismatch! Expected ${t}x${e.singleTextureSize}, Got ${e.dataTexture.image.width}x${e.dataTexture.image.height}`),this.positionAtlasTexture=e.dataTexture;const i=e.numMeshes>0?e.numMeshes:1;this.positionVar.material.uniforms.uPositionAtlas.value=this.positionAtlasTexture,this.positionVar.material.uniforms.uNumMeshes.value=i,this.positionVar.material.uniforms.uSingleTextureSize.value=e.singleTextureSize,this.velocityVar.material.uniforms.uPositionAtlas.value=this.positionAtlasTexture,this.velocityVar.material.uniforms.uNumMeshes.value=i,this.velocityVar.material.uniforms.uSingleTextureSize.value=e.singleTextureSize,this.positionVar.material.uniforms.uCurrentVelocity.value=this.gpuComputationRenderer.getCurrentRenderTarget(this.velocityVar).texture,this.velocityVar.material.uniforms.uCurrentPosition.value=this.gpuComputationRenderer.getCurrentRenderTarget(this.positionVar).texture}setOverallProgress(e){const t=h(e,0,1);this.positionVar.material.uniforms.uOverallProgress.value=t,this.velocityVar.material.uniforms.uOverallProgress.value=t}setMaxRepelDistance(e){this.velocityVar.material.uniforms.uMaxRepelDistance.value=e}setVelocityTractionForce(e){this.velocityVar.material.uniforms.uTractionForce.value=e}setPositionalTractionForce(e){this.positionVar.material.uniforms.uTractionForce.value=e}setInteractionPosition(e){this.interactionPosition.copy(e)}dispose(){var e,t;this.gpuComputationRenderer.dispose(),null==(e=this.initialPositionDataTexture)||e.dispose(),null==(t=this.initialVelocityDataTexture)||t.dispose(),this.positionAtlasTexture=null}compute(e){this.velocityVar.material.uniforms.uTime.value+=e,this.positionVar.material.uniforms.uTime.value+=e,this.positionVar.material.uniforms.uCurrentVelocity.value=this.gpuComputationRenderer.getCurrentRenderTarget(this.velocityVar).texture,this.velocityVar.material.uniforms.uCurrentPosition.value=this.gpuComputationRenderer.getCurrentRenderTarget(this.positionVar).texture,this.gpuComputationRenderer.compute(),this.lastKnownVelocityDataTexture=this.gpuComputationRenderer.getCurrentRenderTarget(this.velocityVar).texture,this.lastKnownPositionDataTexture=this.gpuComputationRenderer.getCurrentRenderTarget(this.positionVar).texture}getVelocityTexture(){return this.lastKnownVelocityDataTexture}getPositionTexture(){return this.lastKnownPositionDataTexture}}class R{constructor(e,t,i){n(this,"state"),n(this,"textureSize"),n(this,"overallProgress"),n(this,"velocityTractionForce"),n(this,"positionalTractionForce"),n(this,"simulationRenderer"),n(this,"webGLRenderer"),n(this,"eventEmitter"),n(this,"currentAtlasEntry",null),n(this,"lastKnownVelocityDataTexture"),n(this,"lastKnownPositionDataTexture"),this.eventEmitter=e,this.webGLRenderer=i,this.textureSize=t,this.overallProgress=0,this.velocityTractionForce=.1,this.positionalTractionForce=.1,this.updateServiceState("initializing"),this.simulationRenderer=new V(this.textureSize,this.webGLRenderer),this.lastKnownVelocityDataTexture=this.simulationRenderer.getVelocityTexture(),this.lastKnownPositionDataTexture=this.simulationRenderer.getPositionTexture(),this.updateServiceState("ready")}setPositionAtlas(e){const t=e.singleTextureSize*e.numMeshes;e.dataTexture.image.width===t?(this.currentAtlasEntry=e,this.simulationRenderer.setPositionAtlas(e)):this.eventEmitter.emit("invalidRequest",{message:"Atlas texture width mismatch."})}setOverallProgress(e){this.overallProgress=e,this.simulationRenderer.setOverallProgress(this.overallProgress)}setTextureSize(e){this.updateServiceState("initializing"),this.simulationRenderer.dispose(),this.textureSize=e,this.simulationRenderer=new V(e,this.webGLRenderer),this.updateServiceState("ready")}setVelocityTractionForce(e){this.velocityTractionForce=e,this.simulationRenderer.setVelocityTractionForce(this.velocityTractionForce)}setPositionalTractionForce(e){this.positionalTractionForce=e,this.simulationRenderer.setPositionalTractionForce(this.positionalTractionForce)}compute(e){"ready"===this.state&&(this.simulationRenderer.compute(e),this.lastKnownVelocityDataTexture=this.simulationRenderer.getVelocityTexture(),this.lastKnownPositionDataTexture=this.simulationRenderer.getPositionTexture())}getVelocityTexture(){return this.lastKnownVelocityDataTexture}getPositionTexture(){return this.lastKnownPositionDataTexture}dispose(){this.updateServiceState("disposed"),this.simulationRenderer.dispose(),this.currentAtlasEntry=null}updateServiceState(e){this.state=e,this.eventEmitter.emit("serviceStateUpdated",{type:"simulation",state:e})}setInteractionPosition(e){this.simulationRenderer.setInteractionPosition(e)}setMaxRepelDistance(e){this.simulationRenderer.setMaxRepelDistance(e)}}class C{constructor(){n(this,"execStatus",new Map)}get(e){const t=this.execStatus.get(e);return t||(this.execStatus.set(e,"idle"),"idle")}set(e,t){this.execStatus.set(e,t)}}class D{constructor(e){n(this,"eventEmitter"),n(this,"transitions",new Map),n(this,"execStatus"),n(this,"ongoingTransitions",new Map),this.eventEmitter=e,this.execStatus=new C,this.eventEmitter.on("transitionCancelled",this.handleTransitionCancelledEvent.bind(this))}enqueue(e,t,i={}){const s={...t,...i,cancelled:!1,duration:.001*t.duration};this.getQueue(e).push(s)}compute(e){this.transitions.forEach(((t,i)=>{var s;if(t.length&&!this.ongoingTransitions.has(i)){const n=t.shift();n&&(this.ongoingTransitions.set(i,{...n,startTime:e}),null==(s=n.onTransitionBegin)||s.call(n))}})),this.ongoingTransitions.forEach(((t,i)=>{var s,n,r;if(t.cancelled)return null==(s=t.onTransitionCancelled)||s.call(t),void this.ongoingTransitions.delete(i);const{startTime:a,duration:o,easing:l}=t,u=e-a,c=h(l(Math.min(1,u/o)),0,1);this.emitTransitionProgress(i,c),null==(n=t.onTransitionProgress)||n.call(t,c),c>=1&&(this.emitTransitionFinished(i),null==(r=t.onTransitionFinished)||r.call(t),this.ongoingTransitions.delete(i))}))}getQueue(e){const t=this.transitions.get(e);return t||(this.transitions.set(e,[]),this.transitions.get(e)??[])}handleTransitionCancelledEvent({type:e}){var t;const i=this.getQueue(e);for(;i.length;)i.pop();const s=this.ongoingTransitions.get(e);s&&(s.cancelled=!0,null==(t=s.onTransitionCancelled)||t.call(s))}emitTransitionProgress(e,t){this.eventEmitter.emit("transitionProgressed",{type:e,progress:t})}emitTransitionFinished(e){this.eventEmitter.emit("transitionFinished",{type:e})}}return e.ParticlesEngine=class{constructor(e){n(this,"simulationRendererService"),n(this,"renderer"),n(this,"scene"),n(this,"serviceStates"),n(this,"assetService"),n(this,"dataTextureManager"),n(this,"instancedMeshManager"),n(this,"transitionService"),n(this,"engineState"),n(this,"intersectionService"),n(this,"meshSequenceAtlasTexture",null),n(this,"eventEmitter");const{scene:t,renderer:i,camera:s,textureSize:r,useIntersection:a=!0}=e;this.eventEmitter=new l,this.serviceStates=this.getInitialServiceStates(),this.eventEmitter.on("serviceStateUpdated",this.handleServiceStateUpdated.bind(this)),this.scene=t,this.renderer=i,this.engineState=this.initialEngineState(e),this.assetService=new d(this.eventEmitter),this.transitionService=new D(this.eventEmitter),this.dataTextureManager=new y(this.eventEmitter,r),this.simulationRendererService=new R(this.eventEmitter,r,this.renderer),this.instancedMeshManager=new T(r),this.instancedMeshManager.useMatcapMaterial(),this.scene.add(this.instancedMeshManager.getMesh()),this.intersectionService=new S(this.eventEmitter,s),a||this.intersectionService.setActive(!1),this.eventEmitter.on("interactionPositionUpdated",this.handleInteractionPositionUpdated.bind(this))}render(e){const t=e/1e3;this.transitionService.compute(t),this.intersectionService.calculate(this.instancedMeshManager.getMesh()),this.simulationRendererService.compute(t),this.instancedMeshManager.update(t),this.instancedMeshManager.updateVelocityTexture(this.simulationRendererService.getVelocityTexture()),this.instancedMeshManager.updatePositionTexture(this.simulationRendererService.getPositionTexture())}setOriginMatcap(e,t=!1){t&&this.eventEmitter.emit("transitionCancelled",{type:"matcap"}),this.engineState.originMatcapID=e,this.instancedMeshManager.setOriginMatcap(this.assetService.getMatcap(e))}setDestinationMatcap(e,t=!1){t&&this.eventEmitter.emit("transitionCancelled",{type:"matcap"}),this.engineState.destinationMatcapID=e,this.instancedMeshManager.setDestinationMatcap(this.assetService.getMatcap(e))}setOriginColor(e,t=!1){t&&this.eventEmitter.emit("transitionCancelled",{type:"matcap"}),this.instancedMeshManager.setOriginColor(e)}setDestinationColor(e,t=!1){t&&this.eventEmitter.emit("transitionCancelled",{type:"matcap"}),this.instancedMeshManager.setDestinationColor(e)}setOriginTexture(e,t=!1){t&&this.eventEmitter.emit("transitionCancelled",{type:"matcap"}),"string"==typeof e&&this.assetService.hasMatcap(e)?this.setOriginMatcap(e):this.setOriginColor(e)}setDestinationTexture(e,t=!1){t&&this.eventEmitter.emit("transitionCancelled",{type:"matcap"}),"string"==typeof e&&this.assetService.hasMatcap(e)?this.setDestinationMatcap(e):this.setDestinationColor(e)}setMatcapProgress(e,t=!1){const i=h(e,0,1);t&&this.eventEmitter.emit("transitionCancelled",{type:"matcap"}),this.engineState.matcapTransitionProgress=i,this.instancedMeshManager.setProgress(i)}async setTextureSize(e){this.engineState.textureSize!==e&&(this.engineState.textureSize=e,this.dataTextureManager.setTextureSize(e),this.simulationRendererService.setTextureSize(e),this.instancedMeshManager.resize(e),this.engineState.meshSequence.length>0&&await this.setMeshSequence(this.engineState.meshSequence),this.engineState.meshSequence.length>0&&await this.setMeshSequence(this.engineState.meshSequence),this.simulationRendererService.setVelocityTractionForce(this.engineState.velocityTractionForce),this.simulationRendererService.setPositionalTractionForce(this.engineState.positionalTractionForce),this.simulationRendererService.setMaxRepelDistance(this.engineState.maxRepelDistance),this.simulationRendererService.setOverallProgress(this.engineState.overallProgress),this.intersectionService.setOverallProgress(this.engineState.overallProgress),this.instancedMeshManager.setOriginMatcap(this.assetService.getMatcap(this.engineState.originMatcapID)),this.instancedMeshManager.setDestinationMatcap(this.assetService.getMatcap(this.engineState.destinationMatcapID)),this.instancedMeshManager.setProgress(this.engineState.matcapTransitionProgress),this.instancedMeshManager.setGeometrySize(this.engineState.instanceGeometryScale))}registerMesh(e,t){this.assetService.register(e,t)}registerMatcap(e,t){this.assetService.register(e,t)}async fetchAndRegisterMesh(e,t){return await this.assetService.loadMeshAsync(e,t)}async fetchAndRegisterMatcap(e,t){return await this.assetService.loadTextureAsync(e,t)}useIntersect(e){this.intersectionService.setActive(e),this.engineState.useIntersect=e,e||(this.engineState.pointerPosition={x:-99999999,y:-99999999},this.simulationRendererService.setInteractionPosition({x:0,y:0,z:0,w:0}))}setPointerPosition(e){this.engineState.useIntersect&&(this.engineState.pointerPosition=e,this.intersectionService.setPointerPosition(e))}setGeometrySize(e){this.engineState.instanceGeometryScale=e,this.instancedMeshManager.setGeometrySize(e)}setVelocityTractionForce(e){this.engineState.velocityTractionForce=e,this.simulationRendererService.setVelocityTractionForce(e)}setPositionalTractionForce(e){this.engineState.positionalTractionForce=e,this.simulationRendererService.setPositionalTractionForce(e)}setMaxRepelDistance(e){this.engineState.maxRepelDistance=e,this.simulationRendererService.setMaxRepelDistance(e)}async setMeshSequence(e){if(!e||e.length<1)return this.eventEmitter.emit("invalidRequest",{message:"Mesh sequence must contain at least one mesh ID."}),this.engineState.meshSequence=[],void this.intersectionService.setMeshSequence([]);this.engineState.meshSequence=e,this.engineState.overallProgress=0;const t=e.map((e=>this.assetService.getMesh(e))).filter((e=>null!==e));if(t.length!==e.length){const i=e.filter((e=>!this.assetService.getMesh(e)));if(console.warn(`Could not find meshes for IDs: ${i.join(", ")}. Proceeding with ${t.length} found meshes.`),this.eventEmitter.emit("invalidRequest",{message:`Could not find meshes for IDs: ${i.join(", ")}`}),t.length<1)return this.engineState.meshSequence=[],void this.intersectionService.setMeshSequence([]);this.engineState.meshSequence=t.map((e=>e.name))}try{this.meshSequenceAtlasTexture=await this.dataTextureManager.createSequenceDataTextureAtlas(t,this.engineState.textureSize),this.simulationRendererService.setPositionAtlas({dataTexture:this.meshSequenceAtlasTexture,textureSize:this.engineState.textureSize,numMeshes:this.engineState.meshSequence.length,singleTextureSize:this.engineState.textureSize}),this.simulationRendererService.setOverallProgress(this.engineState.overallProgress),this.intersectionService.setMeshSequence(t),this.intersectionService.setOverallProgress(this.engineState.overallProgress)}catch(i){console.error("Failed during mesh sequence setup:",i),this.meshSequenceAtlasTexture=null}}setOverallProgress(e,t=!0){t&&this.eventEmitter.emit("transitionCancelled",{type:"mesh-sequence"});const i=h(e,0,1);this.engineState.overallProgress=i,this.simulationRendererService.setOverallProgress(i),this.intersectionService.setOverallProgress(i)}scheduleMatcapTransition(e,t,i=o,s=1e3,n=!1,r={}){n&&this.eventEmitter.emit("transitionCancelled",{type:"matcap"});this.transitionService.enqueue("matcap",{easing:i,duration:s},{...r,onTransitionProgress:e=>{var t;this.setMatcapProgress(e,!1),null==(t=r.onTransitionProgress)||t.call(r,e)},onTransitionBegin:()=>{var i;this.setOriginMatcap(e,!1),this.setDestinationMatcap(t,!1),this.setMatcapProgress(0,!1),null==(i=r.onTransitionBegin)||i.call(r)},onTransitionFinished:()=>{var e;this.setMatcapProgress(1,!1),null==(e=r.onTransitionFinished)||e.call(r)},onTransitionCancelled:r.onTransitionCancelled})}scheduleTextureTransition(e,t,i={}){const s=(null==i?void 0:i.easing)??o,n=(null==i?void 0:i.duration)??1e3,r={onTransitionBegin:null==i?void 0:i.onTransitionBegin,onTransitionProgress:null==i?void 0:i.onTransitionProgress,onTransitionFinished:null==i?void 0:i.onTransitionFinished,onTransitionCancelled:null==i?void 0:i.onTransitionCancelled};(null==i?void 0:i.override)&&this.eventEmitter.emit("transitionCancelled",{type:"matcap"});this.transitionService.enqueue("matcap",{easing:s,duration:n},{...r,onTransitionProgress:e=>{var t;this.setMatcapProgress(e,!1),null==(t=r.onTransitionProgress)||t.call(r,e)},onTransitionBegin:()=>{var i;this.setOriginTexture(e),this.setDestinationTexture(t),this.setMatcapProgress(0),null==(i=r.onTransitionBegin)||i.call(r)},onTransitionFinished:()=>{var e;this.setMatcapProgress(1),null==(e=r.onTransitionFinished)||e.call(r)},onTransitionCancelled:()=>{var e;null==(e=r.onTransitionCancelled)||e.call(r)}})}scheduleMeshSequenceTransition(e,t=1e3,i=o,s={},n=!0){n&&this.eventEmitter.emit("transitionCancelled",{type:"mesh-sequence"});const r=this.engineState.overallProgress,a=e-r,l={duration:t,easing:i},u={...s,onTransitionProgress:e=>{var t;const i=r+a*e;this.setOverallProgress(i,!1),null==(t=s.onTransitionProgress)||t.call(s,i)},onTransitionBegin:s.onTransitionBegin,onTransitionFinished:()=>{var t;this.setOverallProgress(e,!1),null==(t=s.onTransitionFinished)||t.call(s)},onTransitionCancelled:s.onTransitionCancelled};this.transitionService.enqueue("mesh-sequence",l,u)}handleServiceStateUpdated({type:e,state:t}){this.serviceStates[e]=t}getObject(){return this.instancedMeshManager.getMesh()}getMeshIDs(){return this.assetService.getMeshIDs()}getMatcapIDs(){return this.assetService.getTextureIDs()}getMeshes(){return this.assetService.getMeshes()}getTextures(){return this.assetService.getTextures()}getTextureSize(){return this.engineState.textureSize}getUseIntersect(){return this.engineState.useIntersect}getEngineStateSnapshot(){return{...this.engineState}}dispose(){var e,t,i,s,n,r;this.scene&&this.instancedMeshManager&&this.scene.remove(this.instancedMeshManager.getMesh()),null==(e=this.simulationRendererService)||e.dispose(),null==(t=this.instancedMeshManager)||t.dispose(),null==(i=this.intersectionService)||i.dispose(),null==(s=this.assetService)||s.dispose(),null==(n=this.dataTextureManager)||n.dispose(),null==(r=this.eventEmitter)||r.dispose()}initialEngineState(e){return{textureSize:e.textureSize,meshSequence:[],overallProgress:0,originMatcapID:"",destinationMatcapID:"",matcapTransitionProgress:0,velocityTractionForce:.1,positionalTractionForce:.1,maxRepelDistance:.3,pointerPosition:{x:0,y:0},instanceGeometryScale:{x:1,y:1,z:1},useIntersect:e.useIntersection??!0}}getInitialServiceStates(){return{"data-texture":"created","instanced-mesh":"created",matcap:"created",simulation:"created",asset:"created"}}handleInteractionPositionUpdated({position:e}){this.simulationRendererService.setInteractionPosition(e)}},Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),e}({},THREE,three-stdlib);
2
2
  //# sourceMappingURL=ionian.iife.js.map