@newkrok/three-particles 2.9.0 → 2.10.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/README.md CHANGED
@@ -16,6 +16,9 @@ Particle system for ThreeJS.
16
16
  * Visual editor for creating and fine-tuning effects: [THREE Particles Editor](https://github.com/NewKrok/three-particles-editor)
17
17
  * Highly customizable particle properties (position, velocity, size, color, alpha, rotation, etc.).
18
18
  * Support for various emitter shapes and parameters.
19
+ * Force fields and attractors for dynamic particle behavior (point attraction/repulsion, directional wind).
20
+ * Sub-emitters triggered on particle birth or death events.
21
+ * Serialization support for saving and loading particle system configs.
19
22
  * TypeDoc API documentation available.
20
23
 
21
24
  # Live Demo & Examples
package/dist/index.d.ts CHANGED
@@ -133,6 +133,45 @@ declare const enum SubEmitterTrigger {
133
133
  */
134
134
  DEATH = "DEATH"
135
135
  }
136
+ /**
137
+ * Defines the type of force field that affects particles.
138
+ *
139
+ * @enum {string}
140
+ */
141
+ declare const enum ForceFieldType {
142
+ /**
143
+ * Attract or repel particles toward/from a point in space.
144
+ * Positive strength attracts, negative strength repels.
145
+ * Configure with position, strength, range, and falloff.
146
+ */
147
+ POINT = "POINT",
148
+ /**
149
+ * Apply a constant directional force to all particles (like wind).
150
+ * Configure with direction and strength.
151
+ */
152
+ DIRECTIONAL = "DIRECTIONAL"
153
+ }
154
+ /**
155
+ * Defines how force diminishes with distance from a POINT force field center.
156
+ * Only applicable to {@link ForceFieldType.POINT} force fields.
157
+ *
158
+ * @enum {string}
159
+ */
160
+ declare const enum ForceFieldFalloff {
161
+ /**
162
+ * No falloff — force is constant within range.
163
+ */
164
+ NONE = "NONE",
165
+ /**
166
+ * Force decreases linearly with distance: `1 - d/range`.
167
+ */
168
+ LINEAR = "LINEAR",
169
+ /**
170
+ * Force decreases with the square of distance: `1 - (d/range)²`.
171
+ * More physically realistic than linear falloff.
172
+ */
173
+ QUADRATIC = "QUADRATIC"
174
+ }
136
175
 
137
176
  /**
138
177
  * A fixed numerical value.
@@ -753,6 +792,78 @@ type SubEmitterConfig = {
753
792
  */
754
793
  maxInstances?: number;
755
794
  };
795
+ /**
796
+ * Configuration for a force field that affects particle velocities.
797
+ * Force fields can attract, repel, or push particles in a direction.
798
+ *
799
+ * @example
800
+ * ```typescript
801
+ * // Point attractor at origin
802
+ * const attractor: ForceFieldConfig = {
803
+ * type: ForceFieldType.POINT,
804
+ * position: new THREE.Vector3(0, 0, 0),
805
+ * strength: 5.0,
806
+ * range: 10,
807
+ * falloff: ForceFieldFalloff.QUADRATIC,
808
+ * };
809
+ *
810
+ * // Repulsion shield
811
+ * const shield: ForceFieldConfig = {
812
+ * type: ForceFieldType.POINT,
813
+ * position: new THREE.Vector3(0, 0, 0),
814
+ * strength: -3.0,
815
+ * range: 5,
816
+ * falloff: ForceFieldFalloff.LINEAR,
817
+ * };
818
+ *
819
+ * // Wind effect
820
+ * const wind: ForceFieldConfig = {
821
+ * type: ForceFieldType.DIRECTIONAL,
822
+ * direction: new THREE.Vector3(1, 0, 0),
823
+ * strength: 2.0,
824
+ * };
825
+ * ```
826
+ */
827
+ type ForceFieldConfig = {
828
+ /** Whether this force field is active. @default true */
829
+ isActive?: boolean;
830
+ /** Type of the force field. @default ForceFieldType.POINT */
831
+ type?: ForceFieldType;
832
+ /** Position in 3D space for POINT type force fields. @default (0,0,0) */
833
+ position?: THREE.Vector3;
834
+ /** Direction vector for DIRECTIONAL type force fields. @default (0,1,0) */
835
+ direction?: THREE.Vector3;
836
+ /**
837
+ * Force strength. Positive = attract (POINT) or push along direction (DIRECTIONAL).
838
+ * Negative = repel (POINT) or push against direction (DIRECTIONAL).
839
+ * Supports constant, random range, or lifetime curve (evaluated against system lifetime).
840
+ * @default 1
841
+ */
842
+ strength?: Constant | RandomBetweenTwoConstants | LifetimeCurve;
843
+ /**
844
+ * Maximum effective range for POINT type. Particles beyond this distance are unaffected.
845
+ * @default Infinity
846
+ */
847
+ range?: number;
848
+ /**
849
+ * How force diminishes with distance for POINT type.
850
+ * @default ForceFieldFalloff.LINEAR
851
+ */
852
+ falloff?: ForceFieldFalloff;
853
+ };
854
+ /**
855
+ * Internal normalized force field configuration where all properties are required.
856
+ * Created during particle system initialization from user-provided {@link ForceFieldConfig}.
857
+ */
858
+ type NormalizedForceFieldConfig = {
859
+ isActive: boolean;
860
+ type: ForceFieldType;
861
+ position: THREE.Vector3;
862
+ direction: THREE.Vector3;
863
+ strength: Constant | RandomBetweenTwoConstants | LifetimeCurve;
864
+ range: number;
865
+ falloff: ForceFieldFalloff;
866
+ };
756
867
  /**
757
868
  * Configuration object for the particle system.
758
869
  * Defines all aspects of the particle system, including its appearance, behavior, and runtime events.
@@ -1256,6 +1367,27 @@ type ParticleSystemConfig = {
1256
1367
  * ```
1257
1368
  */
1258
1369
  subEmitters?: Array<SubEmitterConfig>;
1370
+ /**
1371
+ * Force fields that affect particle velocities.
1372
+ * Each force field can attract, repel, or push particles in a direction.
1373
+ * Multiple force fields are applied cumulatively.
1374
+ *
1375
+ * @default []
1376
+ *
1377
+ * @example
1378
+ * ```typescript
1379
+ * forceFields: [
1380
+ * {
1381
+ * type: ForceFieldType.POINT,
1382
+ * position: new THREE.Vector3(0, 0, 0),
1383
+ * strength: 5.0,
1384
+ * range: 10,
1385
+ * falloff: ForceFieldFalloff.QUADRATIC,
1386
+ * },
1387
+ * ]
1388
+ * ```
1389
+ */
1390
+ forceFields?: Array<ForceFieldConfig>;
1259
1391
  /**
1260
1392
  * Called on every update frame with particle system data.
1261
1393
  */
@@ -1345,6 +1477,7 @@ type ParticleSystemInstance = {
1345
1477
  looping: boolean;
1346
1478
  simulationSpace: SimulationSpace;
1347
1479
  gravity: number;
1480
+ normalizedForceFields: Array<NormalizedForceFieldConfig>;
1348
1481
  emission: Emission;
1349
1482
  normalizedConfig: NormalizedParticleSystemConfig;
1350
1483
  iterationCount: number;
@@ -1852,4 +1985,4 @@ declare const getDefaultParticleSystemConfig: () => any;
1852
1985
  declare const createParticleSystem: (config?: ParticleSystemConfig, externalNow?: number) => ParticleSystem;
1853
1986
  declare const updateParticleSystems: (cycleData: CycleData) => void;
1854
1987
 
1855
- export { type BezierCurve, type BezierPoint, type Box, type Burst, type BurstState, type Circle, type Cone, type Constant, type CurveBase, type CurveFunction, CurveFunctionId, type CycleData, type EasingCurve, type Emission, EmitFrom, type GeneralData, LifeTimeCurve, type LifetimeCurve, type MinMaxColor, type Noise, type NoiseConfig, type NormalizedParticleSystemConfig, type ParticleSystem, type ParticleSystemConfig, type ParticleSystemInstance, type Point3D, type RandomBetweenTwoConstants, type Rectangle, type Renderer, type Rgb, Shape, type ShapeConfig, SimulationSpace, type Sphere, type SubEmitterConfig, SubEmitterTrigger, type TextureSheetAnimation, TimeMode, type Transform, type VelocityOverLifetime, applyModifiers, blendingMap, calculateRandomPositionAndVelocityOnBox, calculateRandomPositionAndVelocityOnCircle, calculateRandomPositionAndVelocityOnCone, calculateRandomPositionAndVelocityOnRectangle, calculateRandomPositionAndVelocityOnSphere, calculateValue, createBezierCurveFunction, createDefaultParticleTexture, createParticleSystem, curveFunctionIdMap, getBezierCacheSize, getCurveFunction, getCurveFunctionFromConfig, getDefaultParticleSystemConfig, isLifeTimeCurve, removeBezierCurveFunction, updateParticleSystems };
1988
+ export { type BezierCurve, type BezierPoint, type Box, type Burst, type BurstState, type Circle, type Cone, type Constant, type CurveBase, type CurveFunction, CurveFunctionId, type CycleData, type EasingCurve, type Emission, EmitFrom, type ForceFieldConfig, ForceFieldFalloff, ForceFieldType, type GeneralData, LifeTimeCurve, type LifetimeCurve, type MinMaxColor, type Noise, type NoiseConfig, type NormalizedForceFieldConfig, type NormalizedParticleSystemConfig, type ParticleSystem, type ParticleSystemConfig, type ParticleSystemInstance, type Point3D, type RandomBetweenTwoConstants, type Rectangle, type Renderer, type Rgb, Shape, type ShapeConfig, SimulationSpace, type Sphere, type SubEmitterConfig, SubEmitterTrigger, type TextureSheetAnimation, TimeMode, type Transform, type VelocityOverLifetime, applyModifiers, blendingMap, calculateRandomPositionAndVelocityOnBox, calculateRandomPositionAndVelocityOnCircle, calculateRandomPositionAndVelocityOnCone, calculateRandomPositionAndVelocityOnRectangle, calculateRandomPositionAndVelocityOnSphere, calculateValue, createBezierCurveFunction, createDefaultParticleTexture, createParticleSystem, curveFunctionIdMap, getBezierCacheSize, getCurveFunction, getCurveFunctionFromConfig, getDefaultParticleSystemConfig, isLifeTimeCurve, removeBezierCurveFunction, updateParticleSystems };
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import Easing from 'easing-functions';
2
- import * as THREE3 from 'three';
2
+ import * as THREE4 from 'three';
3
3
  import { ObjectUtils } from '@newkrok/three-utils';
4
4
  import { Gyroscope } from 'three/examples/jsm/misc/Gyroscope.js';
5
5
  import { FBM } from 'three-noise/build/three-noise.module.js';
@@ -165,6 +165,17 @@ var SubEmitterTrigger = /* @__PURE__ */ ((SubEmitterTrigger2) => {
165
165
  SubEmitterTrigger2["DEATH"] = "DEATH";
166
166
  return SubEmitterTrigger2;
167
167
  })(SubEmitterTrigger || {});
168
+ var ForceFieldType = /* @__PURE__ */ ((ForceFieldType2) => {
169
+ ForceFieldType2["POINT"] = "POINT";
170
+ ForceFieldType2["DIRECTIONAL"] = "DIRECTIONAL";
171
+ return ForceFieldType2;
172
+ })(ForceFieldType || {});
173
+ var ForceFieldFalloff = /* @__PURE__ */ ((ForceFieldFalloff2) => {
174
+ ForceFieldFalloff2["NONE"] = "NONE";
175
+ ForceFieldFalloff2["LINEAR"] = "LINEAR";
176
+ ForceFieldFalloff2["QUADRATIC"] = "QUADRATIC";
177
+ return ForceFieldFalloff2;
178
+ })(ForceFieldFalloff || {});
168
179
  var calculateRandomPositionAndVelocityOnSphere = (position, quaternion, velocity, speed, {
169
180
  radius,
170
181
  radiusThickness,
@@ -209,7 +220,7 @@ var calculateRandomPositionAndVelocityOnCone = (position, quaternion, velocity,
209
220
  position.applyQuaternion(quaternion);
210
221
  const positionLength = position.length();
211
222
  const normalizedAngle = Math.abs(
212
- positionLength / radius * THREE3.MathUtils.degToRad(angle)
223
+ positionLength / radius * THREE4.MathUtils.degToRad(angle)
213
224
  );
214
225
  const sinNormalizedAngle = Math.sin(normalizedAngle);
215
226
  const speedMultiplierByPosition = 1 / positionLength;
@@ -284,8 +295,8 @@ var calculateRandomPositionAndVelocityOnRectangle = (position, quaternion, veloc
284
295
  const _rotation = rotation;
285
296
  const xOffset = Math.random() * _scale.x - _scale.x / 2;
286
297
  const yOffset = Math.random() * _scale.y - _scale.y / 2;
287
- const rotationX = THREE3.MathUtils.degToRad(_rotation.x);
288
- const rotationY = THREE3.MathUtils.degToRad(_rotation.y);
298
+ const rotationX = THREE4.MathUtils.degToRad(_rotation.x);
299
+ const rotationY = THREE4.MathUtils.degToRad(_rotation.y);
289
300
  position.x = xOffset * Math.cos(rotationY);
290
301
  position.y = yOffset * Math.cos(rotationX);
291
302
  position.z = xOffset * Math.sin(rotationY) - yOffset * Math.sin(rotationX);
@@ -308,7 +319,7 @@ var createDefaultParticleTexture = () => {
308
319
  context.arc(centerX, centerY, radius, 0, 2 * Math.PI, false);
309
320
  context.fillStyle = "white";
310
321
  context.fill();
311
- const texture = new THREE3.CanvasTexture(canvas);
322
+ const texture = new THREE4.CanvasTexture(canvas);
312
323
  texture.needsUpdate = true;
313
324
  return texture;
314
325
  } else {
@@ -345,15 +356,15 @@ var calculateValue = (particleSystemId, value, time = 0) => {
345
356
  if (value.min === value.max) {
346
357
  return value.min ?? 0;
347
358
  }
348
- return THREE3.MathUtils.randFloat(value.min ?? 0, value.max ?? 1);
359
+ return THREE4.MathUtils.randFloat(value.min ?? 0, value.max ?? 1);
349
360
  }
350
361
  const lifetimeCurve = value;
351
362
  return getCurveFunctionFromConfig(particleSystemId, lifetimeCurve)(time) * (lifetimeCurve.scale ?? 1);
352
363
  };
353
364
 
354
365
  // src/js/effects/three-particles/three-particles-modifiers.ts
355
- var noiseInput = new THREE3.Vector3(0, 0, 0);
356
- var orbitalEuler = new THREE3.Euler();
366
+ var noiseInput = new THREE4.Vector3(0, 0, 0);
367
+ var orbitalEuler = new THREE4.Euler();
357
368
  var applyModifiers = ({
358
369
  delta,
359
370
  generalData,
@@ -590,12 +601,81 @@ var ParticleSystemVertexShader = `
590
601
  }
591
602
  `;
592
603
  var particle_system_vertex_shader_glsl_default = ParticleSystemVertexShader;
604
+ var _forceDirection = new THREE4.Vector3();
605
+ var applyPointForce = (field, strength, velocity, positionArr, positionIndex, delta) => {
606
+ _forceDirection.set(
607
+ field.position.x - positionArr[positionIndex],
608
+ field.position.y - positionArr[positionIndex + 1],
609
+ field.position.z - positionArr[positionIndex + 2]
610
+ );
611
+ const distance = _forceDirection.length();
612
+ if (distance < 1e-4) return;
613
+ if (field.range !== Infinity && distance > field.range) return;
614
+ _forceDirection.divideScalar(distance);
615
+ let falloffMultiplier = 1;
616
+ if (field.range !== Infinity) {
617
+ const normalizedDistance = distance / field.range;
618
+ switch (field.falloff) {
619
+ case "LINEAR" /* LINEAR */:
620
+ falloffMultiplier = 1 - normalizedDistance;
621
+ break;
622
+ case "QUADRATIC" /* QUADRATIC */:
623
+ falloffMultiplier = 1 - normalizedDistance * normalizedDistance;
624
+ break;
625
+ case "NONE" /* NONE */:
626
+ falloffMultiplier = 1;
627
+ break;
628
+ }
629
+ }
630
+ const force = strength * falloffMultiplier * delta;
631
+ velocity.x += _forceDirection.x * force;
632
+ velocity.y += _forceDirection.y * force;
633
+ velocity.z += _forceDirection.z * force;
634
+ };
635
+ var applyDirectionalForce = (field, strength, velocity, delta) => {
636
+ const force = strength * delta;
637
+ velocity.x += field.direction.x * force;
638
+ velocity.y += field.direction.y * force;
639
+ velocity.z += field.direction.z * force;
640
+ };
641
+ var applyForceFields = ({
642
+ particleSystemId,
643
+ forceFields,
644
+ velocity,
645
+ positionArr,
646
+ positionIndex,
647
+ delta,
648
+ systemLifetimePercentage
649
+ }) => {
650
+ for (let i = 0; i < forceFields.length; i++) {
651
+ const field = forceFields[i];
652
+ if (!field.isActive) continue;
653
+ const strength = calculateValue(
654
+ particleSystemId,
655
+ field.strength,
656
+ systemLifetimePercentage
657
+ );
658
+ if (strength === 0) continue;
659
+ if (field.type === "POINT" /* POINT */) {
660
+ applyPointForce(
661
+ field,
662
+ strength,
663
+ velocity,
664
+ positionArr,
665
+ positionIndex,
666
+ delta
667
+ );
668
+ } else if (field.type === "DIRECTIONAL" /* DIRECTIONAL */) {
669
+ applyDirectionalForce(field, strength, velocity, delta);
670
+ }
671
+ }
672
+ };
593
673
 
594
674
  // src/js/effects/three-particles/three-particles.ts
595
675
  var _particleSystemId = 0;
596
676
  var createdParticleSystems = [];
597
- var _subEmitterPosition = new THREE3.Vector3();
598
- var _lastWorldPositionSnapshot = new THREE3.Vector3();
677
+ var _subEmitterPosition = new THREE4.Vector3();
678
+ var _lastWorldPositionSnapshot = new THREE4.Vector3();
599
679
  var _distanceStep = { x: 0, y: 0, z: 0 };
600
680
  var _tempPosition = { x: 0, y: 0, z: 0 };
601
681
  var _modifierParams = {
@@ -607,18 +687,18 @@ var _modifierParams = {
607
687
  particleIndex: 0
608
688
  };
609
689
  var blendingMap = {
610
- "THREE.NoBlending": THREE3.NoBlending,
611
- "THREE.NormalBlending": THREE3.NormalBlending,
612
- "THREE.AdditiveBlending": THREE3.AdditiveBlending,
613
- "THREE.SubtractiveBlending": THREE3.SubtractiveBlending,
614
- "THREE.MultiplyBlending": THREE3.MultiplyBlending
690
+ "THREE.NoBlending": THREE4.NoBlending,
691
+ "THREE.NormalBlending": THREE4.NormalBlending,
692
+ "THREE.AdditiveBlending": THREE4.AdditiveBlending,
693
+ "THREE.SubtractiveBlending": THREE4.SubtractiveBlending,
694
+ "THREE.MultiplyBlending": THREE4.MultiplyBlending
615
695
  };
616
696
  var getDefaultParticleSystemConfig = () => JSON.parse(JSON.stringify(DEFAULT_PARTICLE_SYSTEM_CONFIG));
617
697
  var DEFAULT_PARTICLE_SYSTEM_CONFIG = {
618
698
  transform: {
619
- position: new THREE3.Vector3(),
620
- rotation: new THREE3.Vector3(),
621
- scale: new THREE3.Vector3(1, 1, 1)
699
+ position: new THREE4.Vector3(),
700
+ rotation: new THREE4.Vector3(),
701
+ scale: new THREE4.Vector3(1, 1, 1)
622
702
  },
623
703
  duration: 5,
624
704
  looping: true,
@@ -670,7 +750,7 @@ var DEFAULT_PARTICLE_SYSTEM_CONFIG = {
670
750
  },
671
751
  map: void 0,
672
752
  renderer: {
673
- blending: THREE3.NormalBlending,
753
+ blending: THREE4.NormalBlending,
674
754
  discardBackgroundColor: false,
675
755
  backgroundColorTolerance: 1,
676
756
  backgroundColor: { r: 1, g: 1, b: 1 },
@@ -756,11 +836,12 @@ var DEFAULT_PARTICLE_SYSTEM_CONFIG = {
756
836
  sizeAmount: 0
757
837
  },
758
838
  textureSheetAnimation: {
759
- tiles: new THREE3.Vector2(1, 1),
839
+ tiles: new THREE4.Vector2(1, 1),
760
840
  timeMode: "LIFETIME" /* LIFETIME */,
761
841
  fps: 30,
762
842
  startFrame: 0
763
- }
843
+ },
844
+ forceFields: []
764
845
  };
765
846
  var createFloat32Attributes = ({
766
847
  geometry,
@@ -776,7 +857,7 @@ var createFloat32Attributes = ({
776
857
  } else {
777
858
  array.fill(factory);
778
859
  }
779
- geometry.setAttribute(propertyName, new THREE3.BufferAttribute(array, 1));
860
+ geometry.setAttribute(propertyName, new THREE4.BufferAttribute(array, 1));
780
861
  };
781
862
  var calculatePositionAndVelocity = (generalData, { shape, sphere, cone, circle, rectangle, box }, startSpeed, position, velocity) => {
782
863
  const calculatedStartSpeed = calculateValue(
@@ -860,14 +941,14 @@ var createParticleSystem = (config = DEFAULT_PARTICLE_SYSTEM_CONFIG, externalNow
860
941
  particleSystemId: _particleSystemId++,
861
942
  normalizedLifetimePercentage: 0,
862
943
  distanceFromLastEmitByDistance: 0,
863
- lastWorldPosition: new THREE3.Vector3(-99999),
864
- currentWorldPosition: new THREE3.Vector3(-99999),
865
- worldPositionChange: new THREE3.Vector3(),
866
- worldQuaternion: new THREE3.Quaternion(),
867
- wrapperQuaternion: new THREE3.Quaternion(),
868
- lastWorldQuaternion: new THREE3.Quaternion(-99999),
869
- worldEuler: new THREE3.Euler(),
870
- gravityVelocity: new THREE3.Vector3(0, 0, 0),
944
+ lastWorldPosition: new THREE4.Vector3(-99999),
945
+ currentWorldPosition: new THREE4.Vector3(-99999),
946
+ worldPositionChange: new THREE4.Vector3(),
947
+ worldQuaternion: new THREE4.Quaternion(),
948
+ wrapperQuaternion: new THREE4.Quaternion(),
949
+ lastWorldQuaternion: new THREE4.Quaternion(-99999),
950
+ worldEuler: new THREE4.Euler(),
951
+ gravityVelocity: new THREE4.Vector3(0, 0, 0),
871
952
  startValues: {},
872
953
  linearVelocityData: void 0,
873
954
  orbitalVelocityData: void 0,
@@ -911,17 +992,28 @@ var createParticleSystem = (config = DEFAULT_PARTICLE_SYSTEM_CONFIG, externalNow
911
992
  onUpdate,
912
993
  onComplete,
913
994
  textureSheetAnimation,
914
- subEmitters
995
+ subEmitters,
996
+ forceFields: rawForceFields
915
997
  } = normalizedConfig;
998
+ const toVector3 = (v, fallback) => v ? new THREE4.Vector3(v.x ?? 0, v.y ?? 0, v.z ?? 0) : fallback.clone();
999
+ const normalizedForceFields = (rawForceFields ?? []).map((ff) => ({
1000
+ isActive: ff.isActive ?? true,
1001
+ type: ff.type ?? "POINT" /* POINT */,
1002
+ position: toVector3(ff.position, new THREE4.Vector3(0, 0, 0)),
1003
+ direction: toVector3(ff.direction, new THREE4.Vector3(0, 1, 0)).normalize(),
1004
+ strength: ff.strength ?? 1,
1005
+ range: Math.max(0, ff.range ?? Infinity),
1006
+ falloff: ff.falloff ?? "LINEAR" /* LINEAR */
1007
+ }));
916
1008
  if (typeof renderer?.blending === "string")
917
1009
  renderer.blending = blendingMap[renderer.blending];
918
1010
  const startPositions = Array.from(
919
1011
  { length: maxParticles },
920
- () => new THREE3.Vector3()
1012
+ () => new THREE4.Vector3()
921
1013
  );
922
1014
  const velocities = Array.from(
923
1015
  { length: maxParticles },
924
- () => new THREE3.Vector3()
1016
+ () => new THREE4.Vector3()
925
1017
  );
926
1018
  generalData.creationTimes = Array.from({ length: maxParticles }, () => 0);
927
1019
  const freeList = Array.from(
@@ -932,7 +1024,7 @@ var createParticleSystem = (config = DEFAULT_PARTICLE_SYSTEM_CONFIG, externalNow
932
1024
  generalData.linearVelocityData = Array.from(
933
1025
  { length: maxParticles },
934
1026
  () => ({
935
- speed: new THREE3.Vector3(
1027
+ speed: new THREE4.Vector3(
936
1028
  velocityOverLifetime.linear.x ? calculateValue(
937
1029
  generalData.particleSystemId,
938
1030
  velocityOverLifetime.linear.x,
@@ -968,7 +1060,7 @@ var createParticleSystem = (config = DEFAULT_PARTICLE_SYSTEM_CONFIG, externalNow
968
1060
  generalData.orbitalVelocityData = Array.from(
969
1061
  { length: maxParticles },
970
1062
  () => ({
971
- speed: new THREE3.Vector3(
1063
+ speed: new THREE4.Vector3(
972
1064
  velocityOverLifetime.orbital.x ? calculateValue(
973
1065
  generalData.particleSystemId,
974
1066
  velocityOverLifetime.orbital.x,
@@ -999,7 +1091,7 @@ var createParticleSystem = (config = DEFAULT_PARTICLE_SYSTEM_CONFIG, externalNow
999
1091
  velocityOverLifetime.orbital.z
1000
1092
  ) : void 0
1001
1093
  },
1002
- positionOffset: new THREE3.Vector3()
1094
+ positionOffset: new THREE4.Vector3()
1003
1095
  })
1004
1096
  );
1005
1097
  }
@@ -1037,7 +1129,7 @@ var createParticleSystem = (config = DEFAULT_PARTICLE_SYSTEM_CONFIG, externalNow
1037
1129
  if (value.isActive)
1038
1130
  generalData.lifetimeValues[key] = Array.from(
1039
1131
  { length: maxParticles },
1040
- () => THREE3.MathUtils.randFloat(value.min, value.max)
1132
+ () => THREE4.MathUtils.randFloat(value.min, value.max)
1041
1133
  );
1042
1134
  });
1043
1135
  generalData.noise = {
@@ -1061,7 +1153,7 @@ var createParticleSystem = (config = DEFAULT_PARTICLE_SYSTEM_CONFIG, externalNow
1061
1153
  probabilityPassed: false
1062
1154
  }));
1063
1155
  }
1064
- const material = new THREE3.ShaderMaterial({
1156
+ const material = new THREE4.ShaderMaterial({
1065
1157
  uniforms: {
1066
1158
  elapsed: {
1067
1159
  value: 0
@@ -1095,7 +1187,7 @@ var createParticleSystem = (config = DEFAULT_PARTICLE_SYSTEM_CONFIG, externalNow
1095
1187
  depthTest: renderer.depthTest,
1096
1188
  depthWrite: renderer.depthWrite
1097
1189
  });
1098
- const geometry = new THREE3.BufferGeometry();
1190
+ const geometry = new THREE4.BufferGeometry();
1099
1191
  for (let i = 0; i < maxParticles; i++)
1100
1192
  calculatePositionAndVelocity(
1101
1193
  generalData,
@@ -1112,7 +1204,7 @@ var createParticleSystem = (config = DEFAULT_PARTICLE_SYSTEM_CONFIG, externalNow
1112
1204
  }
1113
1205
  geometry.setAttribute(
1114
1206
  "position",
1115
- new THREE3.BufferAttribute(positionArray, 3)
1207
+ new THREE4.BufferAttribute(positionArray, 3)
1116
1208
  );
1117
1209
  createFloat32Attributes({
1118
1210
  geometry,
@@ -1249,7 +1341,7 @@ var createParticleSystem = (config = DEFAULT_PARTICLE_SYSTEM_CONFIG, externalNow
1249
1341
  );
1250
1342
  geometry.attributes.rotation.needsUpdate = true;
1251
1343
  if (normalizedConfig.rotationOverLifetime.isActive)
1252
- generalData.lifetimeValues.rotationOverLifetime[particleIndex] = THREE3.MathUtils.randFloat(
1344
+ generalData.lifetimeValues.rotationOverLifetime[particleIndex] = THREE4.MathUtils.randFloat(
1253
1345
  normalizedConfig.rotationOverLifetime.min,
1254
1346
  normalizedConfig.rotationOverLifetime.max
1255
1347
  );
@@ -1333,7 +1425,7 @@ var createParticleSystem = (config = DEFAULT_PARTICLE_SYSTEM_CONFIG, externalNow
1333
1425
  const cleanupCompletedInstances = (instances) => {
1334
1426
  for (let i = instances.length - 1; i >= 0; i--) {
1335
1427
  const sub = instances[i];
1336
- const points = sub.instance instanceof THREE3.Points ? sub.instance : sub.instance.children[0];
1428
+ const points = sub.instance instanceof THREE4.Points ? sub.instance : sub.instance.children[0];
1337
1429
  const isActiveArr = points?.geometry?.attributes?.isActive?.array;
1338
1430
  if (!isActiveArr) {
1339
1431
  sub.dispose();
@@ -1368,7 +1460,7 @@ var createParticleSystem = (config = DEFAULT_PARTICLE_SYSTEM_CONFIG, externalNow
1368
1460
  looping: false,
1369
1461
  transform: {
1370
1462
  ...subConfig.config.transform,
1371
- position: new THREE3.Vector3(position.x, position.y, position.z)
1463
+ position: new THREE4.Vector3(position.x, position.y, position.z)
1372
1464
  },
1373
1465
  ...inheritVelocity > 0 ? {
1374
1466
  startSpeed: (typeof subConfig.config.startSpeed === "number" ? subConfig.config.startSpeed : typeof subConfig.config.startSpeed === "object" && subConfig.config.startSpeed !== null && "min" in subConfig.config.startSpeed ? subConfig.config.startSpeed.min ?? 0 : 0) + velocity.length() * inheritVelocity
@@ -1381,11 +1473,11 @@ var createParticleSystem = (config = DEFAULT_PARTICLE_SYSTEM_CONFIG, externalNow
1381
1473
  instances.push(subSystem);
1382
1474
  }
1383
1475
  };
1384
- let particleSystem = new THREE3.Points(geometry, material);
1476
+ let particleSystem = new THREE4.Points(geometry, material);
1385
1477
  particleSystem.position.copy(transform.position);
1386
- particleSystem.rotation.x = THREE3.MathUtils.degToRad(transform.rotation.x);
1387
- particleSystem.rotation.y = THREE3.MathUtils.degToRad(transform.rotation.y);
1388
- particleSystem.rotation.z = THREE3.MathUtils.degToRad(transform.rotation.z);
1478
+ particleSystem.rotation.x = THREE4.MathUtils.degToRad(transform.rotation.x);
1479
+ particleSystem.rotation.y = THREE4.MathUtils.degToRad(transform.rotation.y);
1480
+ particleSystem.rotation.z = THREE4.MathUtils.degToRad(transform.rotation.z);
1389
1481
  particleSystem.scale.copy(transform.scale);
1390
1482
  const calculatedCreationTime = now + calculateValue(generalData.particleSystemId, startDelay) * 1e3;
1391
1483
  let wrapper;
@@ -1436,6 +1528,7 @@ var createParticleSystem = (config = DEFAULT_PARTICLE_SYSTEM_CONFIG, externalNow
1436
1528
  looping,
1437
1529
  simulationSpace,
1438
1530
  gravity,
1531
+ normalizedForceFields,
1439
1532
  emission,
1440
1533
  normalizedConfig,
1441
1534
  iterationCount: 0,
@@ -1491,9 +1584,11 @@ var updateParticleSystemInstance = (props, { now, delta, elapsed }) => {
1491
1584
  activateParticle,
1492
1585
  simulationSpace,
1493
1586
  gravity,
1587
+ normalizedForceFields,
1494
1588
  onParticleDeath,
1495
1589
  onParticleBirth
1496
1590
  } = props;
1591
+ const hasForceFields = normalizedForceFields.length > 0;
1497
1592
  const lifetime = now - creationTime;
1498
1593
  const normalizedLifetime = lifetime % (duration * 1e3);
1499
1594
  generalData.normalizedLifetimePercentage = Math.max(
@@ -1562,6 +1657,17 @@ var updateParticleSystemInstance = (props, { now, delta, elapsed }) => {
1562
1657
  velocity.x -= gravityVelocity.x * delta;
1563
1658
  velocity.y -= gravityVelocity.y * delta;
1564
1659
  velocity.z -= gravityVelocity.z * delta;
1660
+ if (hasForceFields) {
1661
+ applyForceFields({
1662
+ particleSystemId: generalData.particleSystemId,
1663
+ forceFields: normalizedForceFields,
1664
+ velocity,
1665
+ positionArr,
1666
+ positionIndex: index * 3,
1667
+ delta,
1668
+ systemLifetimePercentage: generalData.normalizedLifetimePercentage
1669
+ });
1670
+ }
1565
1671
  if (gravity !== 0 || velocity.x !== 0 || velocity.y !== 0 || velocity.z !== 0 || worldPositionChange.x !== 0 || worldPositionChange.y !== 0 || worldPositionChange.z !== 0) {
1566
1672
  const positionIndex = index * 3;
1567
1673
  if (simulationSpace === "WORLD" /* WORLD */) {
@@ -1697,6 +1803,6 @@ var updateParticleSystems = (cycleData) => {
1697
1803
  );
1698
1804
  };
1699
1805
 
1700
- export { CurveFunctionId, EmitFrom, LifeTimeCurve, Shape, SimulationSpace, SubEmitterTrigger, TimeMode, applyModifiers, blendingMap, calculateRandomPositionAndVelocityOnBox, calculateRandomPositionAndVelocityOnCircle, calculateRandomPositionAndVelocityOnCone, calculateRandomPositionAndVelocityOnRectangle, calculateRandomPositionAndVelocityOnSphere, calculateValue, createBezierCurveFunction, createDefaultParticleTexture, createParticleSystem, curveFunctionIdMap, getBezierCacheSize, getCurveFunction, getCurveFunctionFromConfig, getDefaultParticleSystemConfig, isLifeTimeCurve, removeBezierCurveFunction, updateParticleSystems };
1806
+ export { CurveFunctionId, EmitFrom, ForceFieldFalloff, ForceFieldType, LifeTimeCurve, Shape, SimulationSpace, SubEmitterTrigger, TimeMode, applyModifiers, blendingMap, calculateRandomPositionAndVelocityOnBox, calculateRandomPositionAndVelocityOnCircle, calculateRandomPositionAndVelocityOnCone, calculateRandomPositionAndVelocityOnRectangle, calculateRandomPositionAndVelocityOnSphere, calculateValue, createBezierCurveFunction, createDefaultParticleTexture, createParticleSystem, curveFunctionIdMap, getBezierCacheSize, getCurveFunction, getCurveFunctionFromConfig, getDefaultParticleSystemConfig, isLifeTimeCurve, removeBezierCurveFunction, updateParticleSystems };
1701
1807
  //# sourceMappingURL=index.js.map
1702
1808
  //# sourceMappingURL=index.js.map