@polarfront-lab/ionian 2.0.0 → 3.0.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/ionian.js CHANGED
@@ -92,10 +92,12 @@ class AssetService {
92
92
  __publicField(this, "gltfLoader", new GLTFLoader());
93
93
  __publicField(this, "textureLoader", new THREE.TextureLoader());
94
94
  __publicField(this, "dracoLoader", new DRACOLoader());
95
- __publicField(this, "solidColorTexture", new THREE.DataTexture(new Uint8Array([127, 127, 127, 255]), 1, 1, THREE.RGBAFormat));
95
+ __publicField(this, "solidColorTextures", /* @__PURE__ */ new Map());
96
+ __publicField(this, "fallbackTexture", new THREE.DataTexture(new Uint8Array([127, 127, 127, 255]), 1, 1, THREE.RGBAFormat));
96
97
  this.eventEmitter = eventEmitter;
97
98
  this.dracoLoader.setDecoderPath("https://www.gstatic.com/draco/versioned/decoders/1.5.7/");
98
99
  this.gltfLoader.setDRACOLoader(this.dracoLoader);
100
+ this.fallbackTexture.name = "default-fallback-texture";
99
101
  this.updateServiceState("ready");
100
102
  }
101
103
  /**
@@ -116,19 +118,32 @@ class AssetService {
116
118
  }
117
119
  this.eventEmitter.emit("assetRegistered", { id });
118
120
  }
119
- setSolidColor(color) {
120
- this.changeColor(color);
121
- }
122
- getSolidColorTexture() {
123
- return this.solidColorTexture;
124
- }
125
121
  getMesh(id) {
126
122
  return this.meshes.get(id) ?? null;
127
123
  }
128
- getMatcap(id) {
124
+ getMatcapTexture(id) {
129
125
  const texture = this.textures.get(id);
130
126
  if (!texture) this.eventEmitter.emit("invalidRequest", { message: `texture with id "${id}" not found. using solid color texture instead...` });
131
- return texture ?? this.solidColorTexture;
127
+ return texture ?? this.fallbackTexture;
128
+ }
129
+ getSolidColorTexture(colorValue) {
130
+ const colorKey = new THREE.Color(colorValue).getHexString();
131
+ let texture = this.solidColorTextures.get(colorKey);
132
+ if (texture) {
133
+ return texture;
134
+ }
135
+ try {
136
+ const texture2 = this.createSolidColorDataTexture(new THREE.Color(colorValue));
137
+ this.solidColorTextures.set(colorKey, texture2);
138
+ return texture2;
139
+ } catch (error) {
140
+ console.error(`Invalid color value provided to getSolidColorTexture: ${colorValue}`, error);
141
+ this.eventEmitter.emit("invalidRequest", { message: `Invalid color value: ${colorValue}. Using fallback texture.` });
142
+ return this.fallbackTexture;
143
+ }
144
+ }
145
+ getFallbackTexture() {
146
+ return this.fallbackTexture;
132
147
  }
133
148
  getMeshIDs() {
134
149
  return Array.from(this.meshes.keys());
@@ -142,8 +157,29 @@ class AssetService {
142
157
  getTextures() {
143
158
  return Array.from(this.textures.values());
144
159
  }
145
- hasMatcap(id) {
146
- return this.textures.has(id);
160
+ createSolidColorDataTexture(color, size = 16) {
161
+ const col = new THREE.Color(color);
162
+ const width = size;
163
+ const height = size;
164
+ const data = new Uint8Array(width * height * 4);
165
+ const r = Math.floor(col.r * 255);
166
+ const g = Math.floor(col.g * 255);
167
+ const b = Math.floor(col.b * 255);
168
+ for (let i = 0; i < width * height; i++) {
169
+ const index = i * 4;
170
+ data[index] = r;
171
+ data[index + 1] = g;
172
+ data[index + 2] = b;
173
+ data[index + 3] = 255;
174
+ }
175
+ const texture = new THREE.DataTexture(data, width, height, THREE.RGBAFormat);
176
+ texture.type = THREE.UnsignedByteType;
177
+ texture.wrapS = THREE.RepeatWrapping;
178
+ texture.wrapT = THREE.RepeatWrapping;
179
+ texture.minFilter = THREE.NearestFilter;
180
+ texture.magFilter = THREE.NearestFilter;
181
+ texture.needsUpdate = true;
182
+ return texture;
147
183
  }
148
184
  /**
149
185
  * Loads a mesh asynchronously.
@@ -191,11 +227,9 @@ class AssetService {
191
227
  this.meshes.clear();
192
228
  this.textures.forEach((texture) => texture.dispose());
193
229
  this.textures.clear();
194
- }
195
- changeColor(color) {
196
- const actual = new THREE.Color(color);
197
- this.solidColorTexture = new THREE.DataTexture(new Uint8Array([actual.r, actual.g, actual.b, 255]), 1, 1, THREE.RGBAFormat);
198
- this.solidColorTexture.needsUpdate = true;
230
+ this.solidColorTextures.forEach((texture) => texture.dispose());
231
+ this.solidColorTextures.clear();
232
+ this.fallbackTexture.dispose();
199
233
  }
200
234
  updateServiceState(serviceState) {
201
235
  this.serviceState = serviceState;
@@ -511,7 +545,6 @@ function sampleMesh(meshData, size) {
511
545
  }
512
546
  const instanceFragmentShader = `
513
547
  varying vec2 vUv;
514
- uniform sampler2D uTexture;
515
548
 
516
549
  uniform sampler2D uOriginTexture;
517
550
  uniform sampler2D uDestinationTexture;
@@ -525,11 +558,11 @@ void main() {
525
558
  vec3 y = cross( viewDir, x );
526
559
  vec2 uv = vec2( dot( x, vNormal ), dot( y, vNormal ) ) * 0.495 + 0.5; // 0.495 to remove artifacts caused by undersized matcap disks
527
560
 
528
- vec4 sourceMatcap = texture2D( uOriginTexture, uv );
529
- vec4 targetMatcap = texture2D( uDestinationTexture, uv );
561
+ vec4 textureA = texture2D( uOriginTexture, uv );
562
+ vec4 textureB = texture2D( uDestinationTexture, uv );
530
563
 
531
- vec4 matcap = mix(sourceMatcap, targetMatcap, uProgress);
532
- gl_FragColor = matcap;
564
+ vec4 finalColor = mix(textureA, textureB, uProgress);
565
+ gl_FragColor = finalColor;
533
566
  }
534
567
  `;
535
568
  const instanceVertexShader = `
@@ -585,11 +618,9 @@ class InstancedMeshManager {
585
618
  constructor(initialSize) {
586
619
  __publicField(this, "size");
587
620
  __publicField(this, "mesh");
588
- __publicField(this, "matcapMaterial");
621
+ __publicField(this, "shaderMaterial");
589
622
  __publicField(this, "fallbackGeometry");
590
623
  __publicField(this, "uniforms");
591
- __publicField(this, "originColor");
592
- __publicField(this, "destinationColor");
593
624
  __publicField(this, "geometries");
594
625
  __publicField(this, "uvRefsCache");
595
626
  __publicField(this, "previousScale");
@@ -597,8 +628,6 @@ class InstancedMeshManager {
597
628
  this.geometries = /* @__PURE__ */ new Map();
598
629
  this.uvRefsCache = /* @__PURE__ */ new Map();
599
630
  this.previousScale = { x: 1, y: 1, z: 1 };
600
- this.originColor = "grey";
601
- this.destinationColor = "grey";
602
631
  this.uniforms = {
603
632
  uTime: { value: 0 },
604
633
  uProgress: { value: 0 },
@@ -607,15 +636,14 @@ class InstancedMeshManager {
607
636
  uOriginTexture: { value: null },
608
637
  uDestinationTexture: { value: null }
609
638
  };
610
- this.matcapMaterial = new THREE.ShaderMaterial({
639
+ this.shaderMaterial = new THREE.ShaderMaterial({
611
640
  uniforms: this.uniforms,
612
641
  vertexShader: instanceVertexShader,
613
642
  fragmentShader: instanceFragmentShader
614
643
  });
615
- this.setOriginColor(this.originColor);
616
- this.setDestinationColor(this.destinationColor);
617
644
  this.fallbackGeometry = new THREE.BoxGeometry(1e-3, 1e-3, 1e-3);
618
- this.mesh = this.createInstancedMesh(initialSize, this.fallbackGeometry, this.matcapMaterial);
645
+ this.mesh = this.createInstancedMesh(initialSize, this.fallbackGeometry, this.shaderMaterial);
646
+ this.mesh.material = this.shaderMaterial;
619
647
  }
620
648
  /**
621
649
  * Gets the instanced mesh.
@@ -634,22 +662,10 @@ class InstancedMeshManager {
634
662
  material.uniforms.uTime.value = elapsedTime;
635
663
  }
636
664
  }
637
- /**
638
- * Sets the matcap texture.
639
- * @param matcap The matcap texture to set.
640
- */
641
- setOriginMatcap(matcap) {
642
- this.disposeSolidColorOriginTexture();
643
- this.matcapMaterial.uniforms.uOriginTexture.value = matcap;
644
- }
645
- setDestinationMatcap(matcap) {
646
- this.disposeSolidColorDestinationTexture();
647
- this.matcapMaterial.uniforms.uDestinationTexture.value = matcap;
648
- }
649
- setProgress(float) {
650
- float = Math.max(0, float);
651
- float = Math.min(1, float);
652
- this.matcapMaterial.uniforms.uProgress.value = float;
665
+ updateTextureInterpolation(textureA, textureB, progress) {
666
+ this.uniforms.uOriginTexture.value = textureA;
667
+ this.uniforms.uDestinationTexture.value = textureB;
668
+ this.uniforms.uProgress.value = progress;
653
669
  }
654
670
  setGeometrySize(size) {
655
671
  this.mesh.geometry.scale(1 / this.previousScale.x, 1 / this.previousScale.y, 1 / this.previousScale.z);
@@ -660,7 +676,7 @@ class InstancedMeshManager {
660
676
  * Use the matcap material for the instanced mesh.
661
677
  */
662
678
  useMatcapMaterial() {
663
- this.mesh.material = this.matcapMaterial;
679
+ this.mesh.material = this.shaderMaterial;
664
680
  }
665
681
  /**
666
682
  * Use the specified geometry for the instanced mesh.
@@ -677,14 +693,14 @@ class InstancedMeshManager {
677
693
  * @param texture The velocity texture to update with.
678
694
  */
679
695
  updateVelocityTexture(texture) {
680
- this.matcapMaterial.uniforms.uVelocity.value = texture;
696
+ this.shaderMaterial.uniforms.uVelocity.value = texture;
681
697
  }
682
698
  /**
683
699
  * Updates the position texture.
684
700
  * @param texture The position texture to update with.
685
701
  */
686
702
  updatePositionTexture(texture) {
687
- this.matcapMaterial.uniforms.uTexture.value = texture;
703
+ this.shaderMaterial.uniforms.uTexture.value = texture;
688
704
  }
689
705
  /**
690
706
  * Resizes or replaces the instanced mesh.
@@ -704,9 +720,7 @@ class InstancedMeshManager {
704
720
  dispose() {
705
721
  this.mesh.dispose();
706
722
  this.geometries.forEach((geometry) => geometry.dispose());
707
- this.disposeSolidColorOriginTexture();
708
- this.disposeSolidColorDestinationTexture();
709
- this.matcapMaterial.dispose();
723
+ this.shaderMaterial.dispose();
710
724
  this.uvRefsCache.clear();
711
725
  this.geometries.clear();
712
726
  }
@@ -730,16 +744,6 @@ class InstancedMeshManager {
730
744
  }
731
745
  previous == null ? void 0 : previous.dispose();
732
746
  }
733
- setOriginColor(color) {
734
- this.disposeSolidColorOriginTexture();
735
- this.originColor = color;
736
- this.uniforms.uOriginTexture.value = this.createSolidColorDataTexture(color);
737
- }
738
- setDestinationColor(color) {
739
- this.disposeSolidColorDestinationTexture();
740
- this.destinationColor = color;
741
- this.uniforms.uDestinationTexture.value = this.createSolidColorDataTexture(color);
742
- }
743
747
  /**
744
748
  * Gets the UV references for the specified size.
745
749
  * @param size The size for which to generate UV references.
@@ -775,46 +779,6 @@ class InstancedMeshManager {
775
779
  const count = size * size;
776
780
  return new THREE.InstancedMesh(geometry, material, count);
777
781
  }
778
- createSolidColorDataTexture(color, size = 16) {
779
- const col = new THREE.Color(color);
780
- const width = size;
781
- const height = size;
782
- const data = new Uint8Array(width * height * 4);
783
- const r = Math.floor(col.r * 255);
784
- const g = Math.floor(col.g * 255);
785
- const b = Math.floor(col.b * 255);
786
- for (let i = 0; i < width * height; i++) {
787
- const index = i * 4;
788
- data[index] = r;
789
- data[index + 1] = g;
790
- data[index + 2] = b;
791
- data[index + 3] = 255;
792
- }
793
- const texture = new THREE.DataTexture(data, width, height, THREE.RGBAFormat);
794
- texture.type = THREE.UnsignedByteType;
795
- texture.wrapS = THREE.RepeatWrapping;
796
- texture.wrapT = THREE.RepeatWrapping;
797
- texture.minFilter = THREE.NearestFilter;
798
- texture.magFilter = THREE.NearestFilter;
799
- texture.needsUpdate = true;
800
- return texture;
801
- }
802
- disposeSolidColorOriginTexture() {
803
- if (this.originColor) {
804
- this.originColor = null;
805
- if (this.uniforms.uOriginTexture.value) {
806
- this.uniforms.uOriginTexture.value.dispose();
807
- }
808
- }
809
- }
810
- disposeSolidColorDestinationTexture() {
811
- if (this.destinationColor) {
812
- this.destinationColor = null;
813
- if (this.uniforms.uDestinationTexture.value) {
814
- this.uniforms.uDestinationTexture.value.dispose();
815
- }
816
- }
817
- }
818
782
  }
819
783
  class IntersectionService {
820
784
  /**
@@ -1803,10 +1767,10 @@ class ParticlesEngine {
1803
1767
  this.dataTextureManager = new DataTextureService(this.eventEmitter, textureSize);
1804
1768
  this.simulationRendererService = new SimulationRendererService(this.eventEmitter, textureSize, this.renderer);
1805
1769
  this.instancedMeshManager = new InstancedMeshManager(textureSize);
1806
- this.instancedMeshManager.useMatcapMaterial();
1807
1770
  this.scene.add(this.instancedMeshManager.getMesh());
1808
1771
  this.intersectionService = new IntersectionService(this.eventEmitter, camera);
1809
1772
  if (!useIntersection) this.intersectionService.setActive(false);
1773
+ this.setOverallProgress(0, false);
1810
1774
  this.eventEmitter.on("interactionPositionUpdated", this.handleInteractionPositionUpdated.bind(this));
1811
1775
  }
1812
1776
  /**
@@ -1822,45 +1786,10 @@ class ParticlesEngine {
1822
1786
  this.instancedMeshManager.updateVelocityTexture(this.simulationRendererService.getVelocityTexture());
1823
1787
  this.instancedMeshManager.updatePositionTexture(this.simulationRendererService.getPositionTexture());
1824
1788
  }
1825
- setOriginMatcap(matcapID, override = false) {
1826
- if (override) this.eventEmitter.emit("transitionCancelled", { type: "matcap" });
1827
- this.engineState.originMatcapID = matcapID;
1828
- this.instancedMeshManager.setOriginMatcap(this.assetService.getMatcap(matcapID));
1829
- }
1830
- setDestinationMatcap(matcapID, override = false) {
1831
- if (override) this.eventEmitter.emit("transitionCancelled", { type: "matcap" });
1832
- this.engineState.destinationMatcapID = matcapID;
1833
- this.instancedMeshManager.setDestinationMatcap(this.assetService.getMatcap(matcapID));
1834
- }
1835
- setOriginColor(color, override = false) {
1836
- if (override) this.eventEmitter.emit("transitionCancelled", { type: "matcap" });
1837
- this.instancedMeshManager.setOriginColor(color);
1838
- }
1839
- setDestinationColor(color, override = false) {
1840
- if (override) this.eventEmitter.emit("transitionCancelled", { type: "matcap" });
1841
- this.instancedMeshManager.setDestinationColor(color);
1842
- }
1843
- setOriginTexture(id, override = false) {
1844
- if (override) this.eventEmitter.emit("transitionCancelled", { type: "matcap" });
1845
- if (typeof id === "string" && this.assetService.hasMatcap(id)) {
1846
- this.setOriginMatcap(id);
1847
- } else {
1848
- this.setOriginColor(id);
1849
- }
1850
- }
1851
- setDestinationTexture(id, override = false) {
1852
- if (override) this.eventEmitter.emit("transitionCancelled", { type: "matcap" });
1853
- if (typeof id === "string" && this.assetService.hasMatcap(id)) {
1854
- this.setDestinationMatcap(id);
1855
- } else {
1856
- this.setDestinationColor(id);
1857
- }
1858
- }
1859
- setMatcapProgress(progress, override = false) {
1860
- const clampedProgress = clamp(progress, 0, 1);
1861
- if (override) this.eventEmitter.emit("transitionCancelled", { type: "matcap" });
1862
- this.engineState.matcapTransitionProgress = clampedProgress;
1863
- this.instancedMeshManager.setProgress(clampedProgress);
1789
+ setTextureSequence(sequence) {
1790
+ this.engineState.textureSequence = sequence;
1791
+ this.eventEmitter.emit("textureSequenceUpdated", { sequence });
1792
+ this.setOverallProgress(0, false);
1864
1793
  }
1865
1794
  // --- Update setTextureSize ---
1866
1795
  async setTextureSize(size) {
@@ -1882,10 +1811,8 @@ class ParticlesEngine {
1882
1811
  this.simulationRendererService.setMaxRepelDistance(this.engineState.maxRepelDistance);
1883
1812
  this.simulationRendererService.setOverallProgress(this.engineState.overallProgress);
1884
1813
  this.intersectionService.setOverallProgress(this.engineState.overallProgress);
1885
- this.instancedMeshManager.setOriginMatcap(this.assetService.getMatcap(this.engineState.originMatcapID));
1886
- this.instancedMeshManager.setDestinationMatcap(this.assetService.getMatcap(this.engineState.destinationMatcapID));
1887
- this.instancedMeshManager.setProgress(this.engineState.matcapTransitionProgress);
1888
1814
  this.instancedMeshManager.setGeometrySize(this.engineState.instanceGeometryScale);
1815
+ this.setOverallProgress(this.engineState.overallProgress, false);
1889
1816
  }
1890
1817
  registerMesh(id, mesh) {
1891
1818
  this.assetService.register(id, mesh);
@@ -1968,6 +1895,7 @@ class ParticlesEngine {
1968
1895
  this.simulationRendererService.setOverallProgress(this.engineState.overallProgress);
1969
1896
  this.intersectionService.setMeshSequence(meshes);
1970
1897
  this.intersectionService.setOverallProgress(this.engineState.overallProgress);
1898
+ this.setOverallProgress(0, false);
1971
1899
  } catch (error) {
1972
1900
  console.error("Failed during mesh sequence setup:", error);
1973
1901
  this.meshSequenceAtlasTexture = null;
@@ -1986,79 +1914,8 @@ class ParticlesEngine {
1986
1914
  this.engineState.overallProgress = clampedProgress;
1987
1915
  this.simulationRendererService.setOverallProgress(clampedProgress);
1988
1916
  this.intersectionService.setOverallProgress(clampedProgress);
1989
- }
1990
- // --- Transition scheduling methods remain the same ---
1991
- scheduleMatcapTransition(originMatcapID, destinationMatcapID, easing = linear, duration = 1e3, override = false, options = {}) {
1992
- if (override) this.eventEmitter.emit("transitionCancelled", { type: "matcap" });
1993
- const handleProgressUpdate = (transitionProgress) => {
1994
- var _a;
1995
- this.setMatcapProgress(transitionProgress, false);
1996
- (_a = options.onTransitionProgress) == null ? void 0 : _a.call(options, transitionProgress);
1997
- };
1998
- this.transitionService.enqueue(
1999
- "matcap",
2000
- { easing, duration },
2001
- {
2002
- ...options,
2003
- onTransitionProgress: handleProgressUpdate,
2004
- onTransitionBegin: () => {
2005
- var _a;
2006
- this.setOriginMatcap(originMatcapID, false);
2007
- this.setDestinationMatcap(destinationMatcapID, false);
2008
- this.setMatcapProgress(0, false);
2009
- (_a = options.onTransitionBegin) == null ? void 0 : _a.call(options);
2010
- },
2011
- onTransitionFinished: () => {
2012
- var _a;
2013
- this.setMatcapProgress(1, false);
2014
- (_a = options.onTransitionFinished) == null ? void 0 : _a.call(options);
2015
- },
2016
- onTransitionCancelled: options.onTransitionCancelled
2017
- }
2018
- );
2019
- }
2020
- scheduleTextureTransition(origin, destination, options = {}) {
2021
- const easing = (options == null ? void 0 : options.easing) ?? linear;
2022
- const duration = (options == null ? void 0 : options.duration) ?? 1e3;
2023
- const userCallbacks = {
2024
- // Extract user callbacks
2025
- onTransitionBegin: options == null ? void 0 : options.onTransitionBegin,
2026
- onTransitionProgress: options == null ? void 0 : options.onTransitionProgress,
2027
- onTransitionFinished: options == null ? void 0 : options.onTransitionFinished,
2028
- onTransitionCancelled: options == null ? void 0 : options.onTransitionCancelled
2029
- };
2030
- if (options == null ? void 0 : options.override) this.eventEmitter.emit("transitionCancelled", { type: "matcap" });
2031
- const handleProgressUpdate = (transitionProgress) => {
2032
- var _a;
2033
- this.setMatcapProgress(transitionProgress, false);
2034
- (_a = userCallbacks.onTransitionProgress) == null ? void 0 : _a.call(userCallbacks, transitionProgress);
2035
- };
2036
- this.transitionService.enqueue(
2037
- "matcap",
2038
- // Still uses matcap type internally
2039
- { easing, duration },
2040
- {
2041
- ...userCallbacks,
2042
- // Pass user callbacks
2043
- onTransitionProgress: handleProgressUpdate,
2044
- onTransitionBegin: () => {
2045
- var _a;
2046
- this.setOriginTexture(origin);
2047
- this.setDestinationTexture(destination);
2048
- this.setMatcapProgress(0);
2049
- (_a = userCallbacks.onTransitionBegin) == null ? void 0 : _a.call(userCallbacks);
2050
- },
2051
- onTransitionFinished: () => {
2052
- var _a;
2053
- this.setMatcapProgress(1);
2054
- (_a = userCallbacks.onTransitionFinished) == null ? void 0 : _a.call(userCallbacks);
2055
- },
2056
- onTransitionCancelled: () => {
2057
- var _a;
2058
- (_a = userCallbacks.onTransitionCancelled) == null ? void 0 : _a.call(userCallbacks);
2059
- }
2060
- }
2061
- );
1917
+ const { textureA, textureB, localProgress } = this.calculateTextureInterpolation(progress);
1918
+ this.instancedMeshManager.updateTextureInterpolation(textureA, textureB, localProgress);
2062
1919
  }
2063
1920
  /**
2064
1921
  * Schedules a smooth transition for the overall mesh sequence progress.
@@ -2141,9 +1998,7 @@ class ParticlesEngine {
2141
1998
  // ADDED
2142
1999
  overallProgress: 0,
2143
2000
  // ADDED
2144
- originMatcapID: "",
2145
- destinationMatcapID: "",
2146
- matcapTransitionProgress: 0,
2001
+ textureSequence: [],
2147
2002
  velocityTractionForce: 0.1,
2148
2003
  positionalTractionForce: 0.1,
2149
2004
  maxRepelDistance: 0.3,
@@ -2164,6 +2019,47 @@ class ParticlesEngine {
2164
2019
  handleInteractionPositionUpdated({ position }) {
2165
2020
  this.simulationRendererService.setInteractionPosition(position);
2166
2021
  }
2022
+ calculateTextureInterpolation(progress) {
2023
+ const sequence = this.engineState.textureSequence;
2024
+ const numItems = sequence.length;
2025
+ if (numItems === 0) {
2026
+ const defaultTex = this.assetService.getFallbackTexture();
2027
+ return { textureA: defaultTex, textureB: defaultTex, localProgress: 0 };
2028
+ }
2029
+ if (numItems === 1) {
2030
+ const tex = this.getTextureForSequenceItem(sequence[0]);
2031
+ return { textureA: tex, textureB: tex, localProgress: 0 };
2032
+ }
2033
+ const totalSegments = numItems - 1;
2034
+ const progressPerSegment = 1 / totalSegments;
2035
+ const scaledProgress = progress * totalSegments;
2036
+ let indexA = Math.floor(scaledProgress);
2037
+ let indexB = indexA + 1;
2038
+ indexA = Math.max(0, Math.min(indexA, totalSegments));
2039
+ indexB = Math.max(0, Math.min(indexB, totalSegments));
2040
+ let localProgress = 0;
2041
+ if (progressPerSegment > 0) {
2042
+ localProgress = (progress - indexA * progressPerSegment) / progressPerSegment;
2043
+ }
2044
+ if (progress >= 1) {
2045
+ indexA = totalSegments;
2046
+ indexB = totalSegments;
2047
+ localProgress = 1;
2048
+ }
2049
+ localProgress = Math.max(0, Math.min(localProgress, 1));
2050
+ const itemA = sequence[indexA];
2051
+ const itemB = sequence[indexB];
2052
+ const textureA = this.getTextureForSequenceItem(itemA);
2053
+ const textureB = this.getTextureForSequenceItem(itemB);
2054
+ return { textureA, textureB, localProgress };
2055
+ }
2056
+ getTextureForSequenceItem(item) {
2057
+ if (item.type === "matcap") {
2058
+ return this.assetService.getMatcapTexture(item.id);
2059
+ } else {
2060
+ return this.assetService.getSolidColorTexture(item.value);
2061
+ }
2062
+ }
2167
2063
  }
2168
2064
  export {
2169
2065
  ParticlesEngine