@tsparticles/engine 3.0.3 → 3.1.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.
Files changed (124) hide show
  1. package/README.md +265 -145
  2. package/browser/Core/Canvas.js +19 -19
  3. package/browser/Core/Container.js +45 -34
  4. package/browser/Core/Engine.js +36 -20
  5. package/browser/Core/Particle.js +35 -36
  6. package/browser/Core/Particles.js +30 -24
  7. package/browser/Core/Retina.js +5 -4
  8. package/browser/Core/Utils/Circle.js +4 -3
  9. package/browser/Core/Utils/Constants.js +3 -0
  10. package/browser/Core/Utils/EventListeners.js +18 -15
  11. package/browser/Core/Utils/ExternalInteractorBase.js +1 -1
  12. package/browser/Core/Utils/InteractionManager.js +14 -6
  13. package/browser/Core/Utils/ParticlesInteractorBase.js +1 -1
  14. package/browser/Core/Utils/QuadTree.js +5 -3
  15. package/browser/Core/Utils/Vector.js +7 -2
  16. package/browser/Core/Utils/Vector3d.js +14 -9
  17. package/browser/Options/Classes/ManualParticle.js +3 -2
  18. package/browser/Options/Classes/Options.js +3 -0
  19. package/browser/Utils/CanvasUtils.js +36 -26
  20. package/browser/Utils/ColorUtils.js +124 -45
  21. package/browser/Utils/EventDispatcher.js +6 -5
  22. package/browser/Utils/HslColorManager.js +5 -5
  23. package/browser/Utils/NumberUtils.js +35 -23
  24. package/browser/Utils/RgbColorManager.js +5 -5
  25. package/browser/Utils/Utils.js +102 -19
  26. package/cjs/Core/Canvas.js +19 -19
  27. package/cjs/Core/Container.js +45 -34
  28. package/cjs/Core/Engine.js +36 -20
  29. package/cjs/Core/Particle.js +34 -35
  30. package/cjs/Core/Particles.js +30 -24
  31. package/cjs/Core/Retina.js +5 -4
  32. package/cjs/Core/Utils/Circle.js +4 -3
  33. package/cjs/Core/Utils/Constants.js +4 -1
  34. package/cjs/Core/Utils/EventListeners.js +17 -14
  35. package/cjs/Core/Utils/ExternalInteractorBase.js +1 -1
  36. package/cjs/Core/Utils/InteractionManager.js +14 -6
  37. package/cjs/Core/Utils/ParticlesInteractorBase.js +1 -1
  38. package/cjs/Core/Utils/QuadTree.js +5 -3
  39. package/cjs/Core/Utils/Vector.js +7 -2
  40. package/cjs/Core/Utils/Vector3d.js +14 -9
  41. package/cjs/Options/Classes/ManualParticle.js +3 -2
  42. package/cjs/Options/Classes/Options.js +3 -0
  43. package/cjs/Utils/CanvasUtils.js +36 -26
  44. package/cjs/Utils/ColorUtils.js +126 -45
  45. package/cjs/Utils/EventDispatcher.js +6 -5
  46. package/cjs/Utils/HslColorManager.js +5 -5
  47. package/cjs/Utils/NumberUtils.js +37 -24
  48. package/cjs/Utils/RgbColorManager.js +5 -5
  49. package/cjs/Utils/Utils.js +103 -19
  50. package/esm/Core/Canvas.js +19 -19
  51. package/esm/Core/Container.js +45 -34
  52. package/esm/Core/Engine.js +36 -20
  53. package/esm/Core/Particle.js +35 -36
  54. package/esm/Core/Particles.js +30 -24
  55. package/esm/Core/Retina.js +5 -4
  56. package/esm/Core/Utils/Circle.js +4 -3
  57. package/esm/Core/Utils/Constants.js +3 -0
  58. package/esm/Core/Utils/EventListeners.js +18 -15
  59. package/esm/Core/Utils/ExternalInteractorBase.js +1 -1
  60. package/esm/Core/Utils/InteractionManager.js +14 -6
  61. package/esm/Core/Utils/ParticlesInteractorBase.js +1 -1
  62. package/esm/Core/Utils/QuadTree.js +5 -3
  63. package/esm/Core/Utils/Vector.js +7 -2
  64. package/esm/Core/Utils/Vector3d.js +14 -9
  65. package/esm/Options/Classes/ManualParticle.js +3 -2
  66. package/esm/Options/Classes/Options.js +3 -0
  67. package/esm/Utils/CanvasUtils.js +36 -26
  68. package/esm/Utils/ColorUtils.js +124 -45
  69. package/esm/Utils/EventDispatcher.js +6 -5
  70. package/esm/Utils/HslColorManager.js +5 -5
  71. package/esm/Utils/NumberUtils.js +35 -23
  72. package/esm/Utils/RgbColorManager.js +5 -5
  73. package/esm/Utils/Utils.js +102 -19
  74. package/package.json +1 -1
  75. package/report.html +2 -2
  76. package/tsparticles.engine.js +693 -334
  77. package/tsparticles.engine.min.js +1 -1
  78. package/tsparticles.engine.min.js.LICENSE.txt +1 -1
  79. package/types/Core/Interfaces/IParticleHslAnimation.d.ts +4 -4
  80. package/types/Core/Interfaces/IParticleValueAnimation.d.ts +4 -0
  81. package/types/Core/Interfaces/IShapeDrawData.d.ts +2 -2
  82. package/types/Core/Utils/Constants.d.ts +3 -0
  83. package/types/Core/Utils/ExternalInteractorBase.d.ts +1 -1
  84. package/types/Core/Utils/InteractionManager.d.ts +1 -1
  85. package/types/Core/Utils/ParticlesInteractorBase.d.ts +1 -1
  86. package/types/Core/Utils/Point.d.ts +1 -1
  87. package/types/Options/Classes/Options.d.ts +1 -0
  88. package/types/Options/Classes/Particles/Move/Move.d.ts +1 -2
  89. package/types/Options/Classes/Particles/Move/OutModes.d.ts +1 -2
  90. package/types/Options/Interfaces/IOptions.d.ts +1 -0
  91. package/types/Options/Interfaces/Interactivity/Modes/IModes.d.ts +1 -3
  92. package/types/Types/CustomEventArgs.d.ts +2 -2
  93. package/types/Types/ExportResult.d.ts +2 -2
  94. package/types/Types/ParticlesGroups.d.ts +1 -3
  95. package/types/Types/PathOptions.d.ts +1 -3
  96. package/types/Types/ShapeData.d.ts +1 -3
  97. package/types/Utils/CanvasUtils.d.ts +3 -2
  98. package/types/Utils/ColorUtils.d.ts +5 -0
  99. package/types/Utils/NumberUtils.d.ts +2 -2
  100. package/types/Utils/Utils.d.ts +9 -6
  101. package/umd/Core/Canvas.js +19 -19
  102. package/umd/Core/Container.js +46 -35
  103. package/umd/Core/Engine.js +36 -20
  104. package/umd/Core/Particle.js +35 -36
  105. package/umd/Core/Particles.js +30 -24
  106. package/umd/Core/Retina.js +5 -4
  107. package/umd/Core/Utils/Circle.js +4 -3
  108. package/umd/Core/Utils/Constants.js +4 -1
  109. package/umd/Core/Utils/EventListeners.js +17 -14
  110. package/umd/Core/Utils/ExternalInteractorBase.js +1 -1
  111. package/umd/Core/Utils/InteractionManager.js +14 -6
  112. package/umd/Core/Utils/ParticlesInteractorBase.js +1 -1
  113. package/umd/Core/Utils/QuadTree.js +5 -3
  114. package/umd/Core/Utils/Vector.js +7 -2
  115. package/umd/Core/Utils/Vector3d.js +14 -9
  116. package/umd/Options/Classes/ManualParticle.js +3 -2
  117. package/umd/Options/Classes/Options.js +3 -0
  118. package/umd/Utils/CanvasUtils.js +36 -26
  119. package/umd/Utils/ColorUtils.js +127 -46
  120. package/umd/Utils/EventDispatcher.js +6 -5
  121. package/umd/Utils/HslColorManager.js +5 -5
  122. package/umd/Utils/NumberUtils.js +38 -25
  123. package/umd/Utils/RgbColorManager.js +5 -5
  124. package/umd/Utils/Utils.js +104 -20
@@ -1,8 +1,11 @@
1
1
  import type { IColor, IHsl, IHsla, IRangeColor, IRgb, IRgba } from "../Core/Interfaces/Colors.js";
2
2
  import type { HslAnimation } from "../Options/Classes/HslAnimation.js";
3
3
  import type { IColorManager } from "../Core/Interfaces/IColorManager.js";
4
+ import type { IDelta } from "../Core/Interfaces/IDelta.js";
4
5
  import type { IOptionsColor } from "../Options/Interfaces/IOptionsColor.js";
6
+ import type { IParticleColorAnimation } from "../Core/Interfaces/IParticleValueAnimation.js";
5
7
  import type { IParticleHslAnimation } from "../Core/Interfaces/IParticleHslAnimation.js";
8
+ import type { IRangeValue } from "../Core/Interfaces/IRangeValue.js";
6
9
  import type { Particle } from "../Core/Particle.js";
7
10
  export declare function addColorManager(manager: IColorManager): void;
8
11
  export declare function rangeColorToRgb(input?: string | IRangeColor, index?: number, useIndex?: boolean): IRgb | undefined;
@@ -22,3 +25,5 @@ export declare function getLinkColor(p1: Particle, p2?: Particle, linkColor?: st
22
25
  export declare function getLinkRandomColor(optColor: string | IOptionsColor, blink: boolean, consent: boolean): IRgb | string | undefined;
23
26
  export declare function getHslFromAnimation(animation?: IParticleHslAnimation): IHsl | undefined;
24
27
  export declare function getHslAnimationFromHsl(hsl: IHsl, animationOptions: HslAnimation | undefined, reduceFactor: number): IParticleHslAnimation;
28
+ export declare function updateColorValue(data: IParticleColorAnimation, range: IRangeValue, decrease: boolean, delta: IDelta): void;
29
+ export declare function updateColor(color: IParticleHslAnimation | undefined, delta: IDelta): void;
@@ -1,8 +1,7 @@
1
1
  import type { EasingType, EasingTypeAlt } from "../Enums/Types/EasingType.js";
2
2
  import type { IPositionFromSizeParams, IRangedPositionFromSizeParams } from "../Core/Interfaces/IPositionFromSizeParams.js";
3
+ import { MoveDirection, type MoveDirectionAlt } from "../Enums/Directions/MoveDirection.js";
3
4
  import type { ICoordinates } from "../Core/Interfaces/ICoordinates.js";
4
- import { MoveDirection } from "../Enums/Directions/MoveDirection.js";
5
- import type { MoveDirectionAlt } from "../Enums/Directions/MoveDirection.js";
6
5
  import type { RangeValue } from "../Types/RangeValue.js";
7
6
  import { Vector } from "../Core/Utils/Vector.js";
8
7
  type EasingFunction = (value: number) => number;
@@ -23,6 +22,7 @@ export declare function getDistances(pointA: ICoordinates, pointB: ICoordinates)
23
22
  dy: number;
24
23
  };
25
24
  export declare function getDistance(pointA: ICoordinates, pointB: ICoordinates): number;
25
+ export declare function degToRad(degrees: number): number;
26
26
  export declare function getParticleDirectionAngle(direction: MoveDirection | keyof typeof MoveDirection | MoveDirectionAlt | number, position: ICoordinates, center: ICoordinates): number;
27
27
  export declare function getParticleBaseVelocity(direction: number): Vector;
28
28
  export declare function collisionVelocity(v1: Vector, v2: Vector, m1: number, m2: number): Vector;
@@ -1,8 +1,10 @@
1
1
  import type { ICoordinates, ICoordinatesWithMode } from "../Core/Interfaces/ICoordinates.js";
2
2
  import type { IDimension, IDimensionWithMode } from "../Core/Interfaces/IDimension.js";
3
+ import { DestroyType } from "../Enums/Types/DestroyType.js";
3
4
  import type { DivEvent } from "../Options/Classes/Interactivity/Events/DivEvent.js";
4
5
  import type { IBounds } from "../Core/Interfaces/IBounds.js";
5
6
  import type { ICircleBouncer } from "../Core/Interfaces/ICircleBouncer.js";
7
+ import type { IDelta } from "../Core/Interfaces/IDelta.js";
6
8
  import type { IModeDiv } from "../Options/Interfaces/Interactivity/Modes/IModeDiv.js";
7
9
  import type { IParticleNumericValueAnimation } from "../Core/Interfaces/IParticleValueAnimation.js";
8
10
  import { OutModeDirection } from "../Enums/Directions/OutModeDirection.js";
@@ -10,12 +12,12 @@ import type { Particle } from "../Core/Particle.js";
10
12
  import type { RangedAnimationValueWithRandom } from "../Options/Classes/ValueWithRandom.js";
11
13
  import type { SingleOrMultiple } from "../Types/SingleOrMultiple.js";
12
14
  interface ILogger {
13
- debug(message?: unknown, ...optionalParams: unknown[]): void;
14
- error(message?: unknown, ...optionalParams: unknown[]): void;
15
- info(message?: unknown, ...optionalParams: unknown[]): void;
16
- log(message?: unknown, ...optionalParams: unknown[]): void;
17
- verbose(message?: unknown, ...optionalParams: unknown[]): void;
18
- warning(message?: unknown, ...optionalParams: unknown[]): void;
15
+ debug(this: void, message?: unknown, ...optionalParams: unknown[]): void;
16
+ error(this: void, message?: unknown, ...optionalParams: unknown[]): void;
17
+ info(this: void, message?: unknown, ...optionalParams: unknown[]): void;
18
+ log(this: void, message?: unknown, ...optionalParams: unknown[]): void;
19
+ verbose(this: void, message?: unknown, ...optionalParams: unknown[]): void;
20
+ warning(this: void, message?: unknown, ...optionalParams: unknown[]): void;
19
21
  }
20
22
  export declare function setLogger(logger: ILogger): void;
21
23
  export declare function getLogger(): ILogger;
@@ -51,4 +53,5 @@ export declare function isNumber(arg: unknown): arg is number;
51
53
  export declare function isFunction(arg: unknown): arg is Function;
52
54
  export declare function isObject<T extends object>(arg: unknown): arg is T;
53
55
  export declare function isArray<T>(arg: unknown): arg is T[];
56
+ export declare function updateAnimation(particle: Particle, data: IParticleNumericValueAnimation, changeDirection: boolean, destroyType: DestroyType | keyof typeof DestroyType, delta: IDelta): void;
54
57
  export {};
@@ -15,9 +15,9 @@
15
15
  const ColorUtils_js_1 = require("../Utils/ColorUtils.js");
16
16
  const Constants_js_1 = require("./Utils/Constants.js");
17
17
  function setTransformValue(factor, newFactor, key) {
18
- const newValue = newFactor[key];
18
+ const newValue = newFactor[key], defaultValue = 1;
19
19
  if (newValue !== undefined) {
20
- factor[key] = (factor[key] ?? 1) * newValue;
20
+ factor[key] = (factor[key] ?? defaultValue) * newValue;
21
21
  }
22
22
  }
23
23
  class Canvas {
@@ -25,7 +25,7 @@
25
25
  this.container = container;
26
26
  this._applyPostDrawUpdaters = (particle) => {
27
27
  for (const updater of this._postDrawUpdaters) {
28
- updater.afterDraw && updater.afterDraw(particle);
28
+ updater.afterDraw?.(particle);
29
29
  }
30
30
  };
31
31
  this._applyPreDrawUpdaters = (ctx, particle, radius, zOpacity, colorStyles, transform) => {
@@ -45,12 +45,12 @@
45
45
  setTransformValue(transform, updaterTransform, key);
46
46
  }
47
47
  }
48
- updater.beforeDraw && updater.beforeDraw(particle);
48
+ updater.beforeDraw?.(particle);
49
49
  }
50
50
  };
51
51
  this._applyResizePlugins = () => {
52
52
  for (const plugin of this._resizePlugins) {
53
- plugin.resize && plugin.resize();
53
+ plugin.resize?.();
54
54
  }
55
55
  };
56
56
  this._getPluginParticleColors = (particle) => {
@@ -106,17 +106,17 @@
106
106
  if (!trail.enable) {
107
107
  return;
108
108
  }
109
+ const factorNumerator = 1, opacity = factorNumerator / trail.length;
109
110
  if (trailFill.color) {
110
111
  const fillColor = (0, ColorUtils_js_1.rangeColorToRgb)(trailFill.color);
111
112
  if (!fillColor) {
112
113
  return;
113
114
  }
114
- const trail = options.particles.move.trail;
115
115
  this._trailFill = {
116
116
  color: {
117
117
  ...fillColor,
118
118
  },
119
- opacity: 1 / trail.length,
119
+ opacity,
120
120
  };
121
121
  }
122
122
  else {
@@ -128,7 +128,7 @@
128
128
  img.addEventListener("load", () => {
129
129
  this._trailFill = {
130
130
  image: img,
131
- opacity: 1 / trail.length,
131
+ opacity,
132
132
  };
133
133
  resolve();
134
134
  });
@@ -179,9 +179,9 @@
179
179
  if (!element) {
180
180
  return;
181
181
  }
182
- const priority = "important", style = element.style;
182
+ const priority = "important", style = element.style, radix = 10;
183
183
  style.setProperty("position", "fixed", priority);
184
- style.setProperty("z-index", this.container.actualOptions.fullScreen.zIndex.toString(10), priority);
184
+ style.setProperty("z-index", this.container.actualOptions.fullScreen.zIndex.toString(radix), priority);
185
185
  style.setProperty("top", "0", priority);
186
186
  style.setProperty("left", "0", priority);
187
187
  style.setProperty("width", "100%", priority);
@@ -202,11 +202,11 @@
202
202
  return this.container.actualOptions.fullScreen.enable;
203
203
  }
204
204
  clear() {
205
- const options = this.container.actualOptions, trail = options.particles.move.trail, trailFill = this._trailFill;
205
+ const options = this.container.actualOptions, trail = options.particles.move.trail, trailFill = this._trailFill, minimumLength = 0;
206
206
  if (options.backgroundMask.enable) {
207
207
  this.paint();
208
208
  }
209
- else if (trail.enable && trail.length > 0 && trailFill) {
209
+ else if (trail.enable && trail.length > minimumLength && trailFill) {
210
210
  if (trailFill.color) {
211
211
  this._paintBase((0, ColorUtils_js_1.getStyleFromRgb)(trailFill.color, trailFill.opacity));
212
212
  }
@@ -224,7 +224,7 @@
224
224
  this.stop();
225
225
  if (this._generated) {
226
226
  const element = this.element;
227
- element && element.remove();
227
+ element?.remove();
228
228
  }
229
229
  else {
230
230
  this._resetOriginalStyle();
@@ -245,8 +245,8 @@
245
245
  if (particle.spawning || particle.destroyed) {
246
246
  return;
247
247
  }
248
- const radius = particle.getRadius();
249
- if (radius <= 0) {
248
+ const radius = particle.getRadius(), minimumSize = 0;
249
+ if (radius <= minimumSize) {
250
250
  return;
251
251
  }
252
252
  const pfColor = particle.getFillColor(), psColor = particle.getStrokeColor() ?? pfColor;
@@ -261,7 +261,7 @@
261
261
  return;
262
262
  }
263
263
  this.draw((ctx) => {
264
- const container = this.container, options = container.actualOptions, zIndexOptions = particle.options.zIndex, zOpacityFactor = (1 - particle.zIndexFactor) ** zIndexOptions.opacityRate, opacity = particle.bubble.opacity ?? particle.opacity?.value ?? 1, strokeOpacity = particle.strokeOpacity ?? opacity, zOpacity = opacity * zOpacityFactor, zStrokeOpacity = strokeOpacity * zOpacityFactor, transform = {}, colorStyles = {
264
+ const container = this.container, options = container.actualOptions, zIndexOptions = particle.options.zIndex, zIndexFactorOffset = 1, zIndexFactor = zIndexFactorOffset - particle.zIndexFactor, zOpacityFactor = zIndexFactor ** zIndexOptions.opacityRate, defaultOpacity = 1, opacity = particle.bubble.opacity ?? particle.opacity?.value ?? defaultOpacity, strokeOpacity = particle.strokeOpacity ?? opacity, zOpacity = opacity * zOpacityFactor, zStrokeOpacity = strokeOpacity * zOpacityFactor, transform = {}, colorStyles = {
265
265
  fill: fColor ? (0, ColorUtils_js_1.getStyleFromHsl)(fColor, zOpacity) : undefined,
266
266
  };
267
267
  colorStyles.stroke = sColor ? (0, ColorUtils_js_1.getStyleFromHsl)(sColor, zStrokeOpacity) : colorStyles.fill;
@@ -274,7 +274,7 @@
274
274
  colorStyles,
275
275
  backgroundMask: options.backgroundMask.enable,
276
276
  composite: options.backgroundMask.composite,
277
- radius: radius * (1 - particle.zIndexFactor) ** zIndexOptions.sizeRate,
277
+ radius: radius * zIndexFactor ** zIndexOptions.sizeRate,
278
278
  opacity: zOpacity,
279
279
  shadow: particle.options.shadow,
280
280
  transform,
@@ -344,7 +344,7 @@
344
344
  if (plugin.resize) {
345
345
  this._resizePlugins.push(plugin);
346
346
  }
347
- if (plugin.particleFillColor || plugin.particleStrokeColor) {
347
+ if (plugin.particleFillColor ?? plugin.particleStrokeColor) {
348
348
  this._colorPlugins.push(plugin);
349
349
  }
350
350
  }
@@ -356,7 +356,7 @@
356
356
  if (updater.afterDraw) {
357
357
  this._postDrawUpdaters.push(updater);
358
358
  }
359
- if (updater.getColorStyles || updater.getTransformValues || updater.beforeDraw) {
359
+ if (updater.getColorStyles ?? updater.getTransformValues ?? updater.beforeDraw) {
360
360
  this._preDrawUpdaters.push(updater);
361
361
  }
362
362
  }
@@ -4,28 +4,29 @@
4
4
  if (v !== undefined) module.exports = v;
5
5
  }
6
6
  else if (typeof define === "function" && define.amd) {
7
- define(["require", "exports", "../Utils/Utils.js", "./Canvas.js", "./Utils/EventListeners.js", "../Options/Classes/Options.js", "./Particles.js", "./Retina.js", "./Utils/Constants.js", "../Utils/NumberUtils.js", "../Utils/OptionsUtils.js"], factory);
7
+ define(["require", "exports", "./Utils/Constants.js", "../Utils/Utils.js", "./Canvas.js", "./Utils/EventListeners.js", "../Options/Classes/Options.js", "./Particles.js", "./Retina.js", "../Utils/NumberUtils.js", "../Utils/OptionsUtils.js"], factory);
8
8
  }
9
9
  })(function (require, exports) {
10
10
  "use strict";
11
11
  Object.defineProperty(exports, "__esModule", { value: true });
12
12
  exports.Container = void 0;
13
+ const Constants_js_1 = require("./Utils/Constants.js");
13
14
  const Utils_js_1 = require("../Utils/Utils.js");
14
15
  const Canvas_js_1 = require("./Canvas.js");
15
16
  const EventListeners_js_1 = require("./Utils/EventListeners.js");
16
17
  const Options_js_1 = require("../Options/Classes/Options.js");
17
18
  const Particles_js_1 = require("./Particles.js");
18
19
  const Retina_js_1 = require("./Retina.js");
19
- const Constants_js_1 = require("./Utils/Constants.js");
20
20
  const NumberUtils_js_1 = require("../Utils/NumberUtils.js");
21
21
  const OptionsUtils_js_1 = require("../Utils/OptionsUtils.js");
22
22
  function guardCheck(container) {
23
23
  return container && !container.destroyed;
24
24
  }
25
- function initDelta(value, fpsLimit = 60, smooth = false) {
25
+ const defaultFps = 60;
26
+ function initDelta(value, fpsLimit = defaultFps, smooth = false) {
26
27
  return {
27
28
  value,
28
- factor: smooth ? 60 / fpsLimit : (60 * value) / 1000,
29
+ factor: smooth ? defaultFps / fpsLimit : (defaultFps * value) / Constants_js_1.millisecondsToSeconds,
29
30
  };
30
31
  }
31
32
  function loadContainerOptions(engine, container, ...sourceOptionsArr) {
@@ -43,14 +44,19 @@
43
44
  if (entry.target !== this.interactivity.element) {
44
45
  continue;
45
46
  }
46
- (entry.isIntersecting ? this.play : this.pause)();
47
+ if (entry.isIntersecting) {
48
+ this.play();
49
+ }
50
+ else {
51
+ this.pause();
52
+ }
47
53
  }
48
54
  };
49
55
  this._nextFrame = async (timestamp) => {
50
56
  try {
51
57
  if (!this._smooth &&
52
58
  this._lastFrameTime !== undefined &&
53
- timestamp < this._lastFrameTime + 1000 / this.fpsLimit) {
59
+ timestamp < this._lastFrameTime + Constants_js_1.millisecondsToSeconds / this.fpsLimit) {
54
60
  this.draw(false);
55
61
  return;
56
62
  }
@@ -58,7 +64,7 @@
58
64
  const delta = initDelta(timestamp - this._lastFrameTime, this.fpsLimit, this._smooth);
59
65
  this.addLifeTime(delta.value);
60
66
  this._lastFrameTime = timestamp;
61
- if (delta.value > 1000) {
67
+ if (delta.value > Constants_js_1.millisecondsToSeconds) {
62
68
  this.draw(false);
63
69
  return;
64
70
  }
@@ -141,8 +147,8 @@
141
147
  const mouseEvent = e, pos = {
142
148
  x: mouseEvent.offsetX || mouseEvent.clientX,
143
149
  y: mouseEvent.offsetY || mouseEvent.clientY,
144
- };
145
- clickOrTouchHandler(e, pos, 1);
150
+ }, radius = 1;
151
+ clickOrTouchHandler(e, pos, radius);
146
152
  };
147
153
  const touchStartHandler = () => {
148
154
  if (!guardCheck(this)) {
@@ -163,16 +169,17 @@
163
169
  }
164
170
  if (touched && !touchMoved) {
165
171
  const touchEvent = e;
166
- let lastTouch = touchEvent.touches[touchEvent.touches.length - 1];
172
+ const lengthOffset = 1;
173
+ let lastTouch = touchEvent.touches[touchEvent.touches.length - lengthOffset];
167
174
  if (!lastTouch) {
168
- lastTouch = touchEvent.changedTouches[touchEvent.changedTouches.length - 1];
175
+ lastTouch = touchEvent.changedTouches[touchEvent.changedTouches.length - lengthOffset];
169
176
  if (!lastTouch) {
170
177
  return;
171
178
  }
172
179
  }
173
- const element = this.canvas.element, canvasRect = element ? element.getBoundingClientRect() : undefined, pos = {
174
- x: lastTouch.clientX - (canvasRect ? canvasRect.left : 0),
175
- y: lastTouch.clientY - (canvasRect ? canvasRect.top : 0),
180
+ const element = this.canvas.element, canvasRect = element ? element.getBoundingClientRect() : undefined, minCoordinate = 0, pos = {
181
+ x: lastTouch.clientX - (canvasRect ? canvasRect.left : minCoordinate),
182
+ y: lastTouch.clientY - (canvasRect ? canvasRect.top : minCoordinate),
176
183
  };
177
184
  clickOrTouchHandler(e, pos, Math.max(lastTouch.radiusX, lastTouch.radiusY));
178
185
  }
@@ -214,10 +221,10 @@
214
221
  this.particles.destroy();
215
222
  this.canvas.destroy();
216
223
  for (const [, effectDrawer] of this.effectDrawers) {
217
- effectDrawer.destroy && effectDrawer.destroy(this);
224
+ effectDrawer.destroy?.(this);
218
225
  }
219
226
  for (const [, shapeDrawer] of this.shapeDrawers) {
220
- shapeDrawer.destroy && shapeDrawer.destroy(this);
227
+ shapeDrawer.destroy?.(this);
221
228
  }
222
229
  for (const key of this.effectDrawers.keys()) {
223
230
  this.effectDrawers.delete(key);
@@ -227,9 +234,10 @@
227
234
  }
228
235
  this._engine.clearPlugins(this);
229
236
  this.destroyed = true;
230
- const mainArr = this._engine.dom(), idx = mainArr.findIndex((t) => t === this);
231
- if (idx >= 0) {
232
- mainArr.splice(idx, 1);
237
+ const mainArr = this._engine.dom(), idx = mainArr.findIndex((t) => t === this), minIndex = 0;
238
+ if (idx >= minIndex) {
239
+ const deleteCount = 1;
240
+ mainArr.splice(idx, deleteCount);
233
241
  }
234
242
  this._engine.dispatchEvent("containerDestroyed", { container: this });
235
243
  }
@@ -238,13 +246,14 @@
238
246
  return;
239
247
  }
240
248
  let refreshTime = force;
241
- this._drawAnimationFrame = requestAnimationFrame(async (timestamp) => {
249
+ const frame = async (timestamp) => {
242
250
  if (refreshTime) {
243
251
  this._lastFrameTime = undefined;
244
252
  refreshTime = false;
245
253
  }
246
254
  await this._nextFrame(timestamp);
247
- });
255
+ };
256
+ this._drawAnimationFrame = requestAnimationFrame((timestamp) => void frame(timestamp));
248
257
  }
249
258
  async export(type, options = {}) {
250
259
  for (const [, plugin] of this.plugins) {
@@ -268,7 +277,7 @@
268
277
  }
269
278
  this.particles.handleClickMode(mode);
270
279
  for (const [, plugin] of this.plugins) {
271
- plugin.handleClickMode && plugin.handleClickMode(mode);
280
+ plugin.handleClickMode?.(mode);
272
281
  }
273
282
  }
274
283
  async init() {
@@ -301,25 +310,26 @@
301
310
  this.canvas.initBackground();
302
311
  this.canvas.resize();
303
312
  this.zLayers = this.actualOptions.zLayers;
304
- this._duration = (0, NumberUtils_js_1.getRangeValue)(this.actualOptions.duration) * 1000;
305
- this._delay = (0, NumberUtils_js_1.getRangeValue)(this.actualOptions.delay) * 1000;
313
+ this._duration = (0, NumberUtils_js_1.getRangeValue)(this.actualOptions.duration) * Constants_js_1.millisecondsToSeconds;
314
+ this._delay = (0, NumberUtils_js_1.getRangeValue)(this.actualOptions.delay) * Constants_js_1.millisecondsToSeconds;
306
315
  this._lifeTime = 0;
307
- this.fpsLimit = this.actualOptions.fpsLimit > 0 ? this.actualOptions.fpsLimit : 120;
316
+ const defaultFpsLimit = 120, minFpsLimit = 0;
317
+ this.fpsLimit = this.actualOptions.fpsLimit > minFpsLimit ? this.actualOptions.fpsLimit : defaultFpsLimit;
308
318
  this._smooth = this.actualOptions.smooth;
309
319
  for (const [, drawer] of this.effectDrawers) {
310
- drawer.init && (await drawer.init(this));
320
+ await drawer.init?.(this);
311
321
  }
312
322
  for (const [, drawer] of this.shapeDrawers) {
313
- drawer.init && (await drawer.init(this));
323
+ await drawer.init?.(this);
314
324
  }
315
325
  for (const [, plugin] of this.plugins) {
316
- plugin.init && (await plugin.init());
326
+ await plugin.init?.();
317
327
  }
318
328
  this._engine.dispatchEvent("containerInit", { container: this });
319
329
  this.particles.init();
320
330
  this.particles.setDensity();
321
331
  for (const [, plugin] of this.plugins) {
322
- plugin.particlesSetup && plugin.particlesSetup();
332
+ plugin.particlesSetup?.();
323
333
  }
324
334
  this._engine.dispatchEvent("particlesSetup", { container: this });
325
335
  }
@@ -342,7 +352,7 @@
342
352
  return;
343
353
  }
344
354
  for (const [, plugin] of this.plugins) {
345
- plugin.pause && plugin.pause();
355
+ plugin.pause?.();
346
356
  }
347
357
  if (!this.pageHidden) {
348
358
  this._paused = true;
@@ -369,7 +379,7 @@
369
379
  }
370
380
  }
371
381
  this._engine.dispatchEvent("containerPlay", { container: this });
372
- this.draw(needsUpdate || false);
382
+ this.draw(needsUpdate ?? false);
373
383
  }
374
384
  async refresh() {
375
385
  if (!guardCheck(this)) {
@@ -394,18 +404,19 @@
394
404
  await this.init();
395
405
  this.started = true;
396
406
  await new Promise((resolve) => {
397
- this._delayTimeout = setTimeout(async () => {
407
+ const start = async () => {
398
408
  this._eventListeners.addListeners();
399
409
  if (this.interactivity.element instanceof HTMLElement && this._intersectionObserver) {
400
410
  this._intersectionObserver.observe(this.interactivity.element);
401
411
  }
402
412
  for (const [, plugin] of this.plugins) {
403
- plugin.start && (await plugin.start());
413
+ await plugin.start?.();
404
414
  }
405
415
  this._engine.dispatchEvent("containerStarted", { container: this });
406
416
  this.play();
407
417
  resolve();
408
- }, this._delay);
418
+ };
419
+ this._delayTimeout = setTimeout(() => void start(), this._delay);
409
420
  });
410
421
  }
411
422
  stop() {
@@ -426,7 +437,7 @@
426
437
  this._intersectionObserver.unobserve(this.interactivity.element);
427
438
  }
428
439
  for (const [, plugin] of this.plugins) {
429
- plugin.stop && plugin.stop();
440
+ plugin.stop?.();
430
441
  }
431
442
  for (const key of this.plugins.keys()) {
432
443
  this.plugins.delete(key);
@@ -63,16 +63,18 @@
63
63
  return res;
64
64
  }
65
65
  get version() {
66
- return "3.0.3";
66
+ return "3.1.0";
67
67
  }
68
68
  addConfig(config) {
69
- const name = config.name ?? "default";
70
- this._configs.set(name, config);
71
- this._eventDispatcher.dispatchEvent("configAdded", { data: { name, config } });
69
+ const key = config.key ?? config.name ?? "default";
70
+ this._configs.set(key, config);
71
+ this._eventDispatcher.dispatchEvent("configAdded", { data: { name: key, config } });
72
72
  }
73
73
  async addEffect(effect, drawer, refresh = true) {
74
74
  (0, Utils_js_1.executeOnSingleOrMultiple)(effect, (type) => {
75
- !this.getEffectDrawer(type) && this.effectDrawers.set(type, drawer);
75
+ if (!this.getEffectDrawer(type)) {
76
+ this.effectDrawers.set(type, drawer);
77
+ }
76
78
  });
77
79
  await this.refresh(refresh);
78
80
  }
@@ -92,20 +94,28 @@
92
94
  await this.refresh(refresh);
93
95
  }
94
96
  async addPathGenerator(name, generator, refresh = true) {
95
- !this.getPathGenerator(name) && this.pathGenerators.set(name, generator);
97
+ if (!this.getPathGenerator(name)) {
98
+ this.pathGenerators.set(name, generator);
99
+ }
96
100
  await this.refresh(refresh);
97
101
  }
98
102
  async addPlugin(plugin, refresh = true) {
99
- !this.getPlugin(plugin.id) && this.plugins.push(plugin);
103
+ if (!this.getPlugin(plugin.id)) {
104
+ this.plugins.push(plugin);
105
+ }
100
106
  await this.refresh(refresh);
101
107
  }
102
108
  async addPreset(preset, options, override = false, refresh = true) {
103
- (override || !this.getPreset(preset)) && this.presets.set(preset, options);
109
+ if (override || !this.getPreset(preset)) {
110
+ this.presets.set(preset, options);
111
+ }
104
112
  await this.refresh(refresh);
105
113
  }
106
114
  async addShape(shape, drawer, refresh = true) {
107
115
  (0, Utils_js_1.executeOnSingleOrMultiple)(shape, (type) => {
108
- !this.getShapeDrawer(type) && this.shapeDrawers.set(type, drawer);
116
+ if (!this.getShapeDrawer(type)) {
117
+ this.shapeDrawers.set(type, drawer);
118
+ }
109
119
  });
110
120
  await this.refresh(refresh);
111
121
  }
@@ -123,7 +133,8 @@
123
133
  domItem(index) {
124
134
  const dom = this.dom(), item = dom[index];
125
135
  if (!item || item.destroyed) {
126
- dom.splice(index, 1);
136
+ const deleteCount = 1;
137
+ dom.splice(index, deleteCount);
127
138
  return;
128
139
  }
129
140
  return item;
@@ -131,7 +142,9 @@
131
142
  getAvailablePlugins(container) {
132
143
  const res = new Map();
133
144
  for (const plugin of this.plugins) {
134
- plugin.needsPlugin(container.actualOptions) && res.set(plugin.id, plugin.getPlugin(container));
145
+ if (plugin.needsPlugin(container.actualOptions)) {
146
+ res.set(plugin.id, plugin.getPlugin(container));
147
+ }
135
148
  }
136
149
  return res;
137
150
  }
@@ -172,19 +185,20 @@
172
185
  this._initialized = true;
173
186
  }
174
187
  async load(params) {
175
- const id = params.id ?? params.element?.id ?? `tsparticles${Math.floor((0, NumberUtils_js_1.getRandom)() * 10000)}`, { index, url } = params, options = url ? await getDataFromUrl({ fallback: params.options, url, index }) : params.options;
188
+ const randomFactor = 10000, id = params.id ?? params.element?.id ?? `tsparticles${Math.floor((0, NumberUtils_js_1.getRandom)() * randomFactor)}`, { index, url } = params, options = url ? await getDataFromUrl({ fallback: params.options, url, index }) : params.options;
176
189
  let domContainer = params.element ?? document.getElementById(id);
177
190
  if (!domContainer) {
178
191
  domContainer = document.createElement("div");
179
192
  domContainer.id = id;
180
193
  document.body.append(domContainer);
181
194
  }
182
- const currentOptions = (0, Utils_js_1.itemFromSingleOrMultiple)(options, index), dom = this.dom(), oldIndex = dom.findIndex((v) => v.id.description === id);
183
- if (oldIndex >= 0) {
195
+ const currentOptions = (0, Utils_js_1.itemFromSingleOrMultiple)(options, index), dom = this.dom(), oldIndex = dom.findIndex((v) => v.id.description === id), minIndex = 0;
196
+ if (oldIndex >= minIndex) {
184
197
  const old = this.domItem(oldIndex);
185
198
  if (old && !old.destroyed) {
186
199
  old.destroy();
187
- dom.splice(oldIndex, 1);
200
+ const deleteCount = 1;
201
+ dom.splice(oldIndex, deleteCount);
188
202
  }
189
203
  }
190
204
  let canvasEl;
@@ -195,7 +209,8 @@
195
209
  else {
196
210
  const existingCanvases = domContainer.getElementsByTagName("canvas");
197
211
  if (existingCanvases.length) {
198
- canvasEl = existingCanvases[0];
212
+ const firstIndex = 0;
213
+ canvasEl = existingCanvases[firstIndex];
199
214
  canvasEl.dataset[Constants_js_1.generatedAttribute] = "false";
200
215
  }
201
216
  else {
@@ -211,8 +226,9 @@
211
226
  canvasEl.style.height = "100%";
212
227
  }
213
228
  const newItem = new Container_js_1.Container(this, id, currentOptions);
214
- if (oldIndex >= 0) {
215
- dom.splice(oldIndex, 0, newItem);
229
+ if (oldIndex >= minIndex) {
230
+ const deleteCount = 0;
231
+ dom.splice(oldIndex, deleteCount, newItem);
216
232
  }
217
233
  else {
218
234
  dom.push(newItem);
@@ -232,14 +248,14 @@
232
248
  return;
233
249
  }
234
250
  for (const updater of updaters) {
235
- updater.loadOptions && updater.loadOptions(options, ...sourceOptions);
251
+ updater.loadOptions?.(options, ...sourceOptions);
236
252
  }
237
253
  }
238
254
  async refresh(refresh = true) {
239
255
  if (!refresh) {
240
256
  return;
241
257
  }
242
- this.dom().forEach((t) => t.refresh());
258
+ await Promise.allSettled(this.dom().map((t) => t.refresh()));
243
259
  }
244
260
  removeEventListener(type, listener) {
245
261
  this._eventDispatcher.removeEventListener(type, listener);