@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
@@ -6,9 +6,9 @@ const Utils_js_1 = require("../Utils/Utils.js");
6
6
  const ColorUtils_js_1 = require("../Utils/ColorUtils.js");
7
7
  const Constants_js_1 = require("./Utils/Constants.js");
8
8
  function setTransformValue(factor, newFactor, key) {
9
- const newValue = newFactor[key];
9
+ const newValue = newFactor[key], defaultValue = 1;
10
10
  if (newValue !== undefined) {
11
- factor[key] = (factor[key] ?? 1) * newValue;
11
+ factor[key] = (factor[key] ?? defaultValue) * newValue;
12
12
  }
13
13
  }
14
14
  class Canvas {
@@ -16,7 +16,7 @@ class Canvas {
16
16
  this.container = container;
17
17
  this._applyPostDrawUpdaters = (particle) => {
18
18
  for (const updater of this._postDrawUpdaters) {
19
- updater.afterDraw && updater.afterDraw(particle);
19
+ updater.afterDraw?.(particle);
20
20
  }
21
21
  };
22
22
  this._applyPreDrawUpdaters = (ctx, particle, radius, zOpacity, colorStyles, transform) => {
@@ -36,12 +36,12 @@ class Canvas {
36
36
  setTransformValue(transform, updaterTransform, key);
37
37
  }
38
38
  }
39
- updater.beforeDraw && updater.beforeDraw(particle);
39
+ updater.beforeDraw?.(particle);
40
40
  }
41
41
  };
42
42
  this._applyResizePlugins = () => {
43
43
  for (const plugin of this._resizePlugins) {
44
- plugin.resize && plugin.resize();
44
+ plugin.resize?.();
45
45
  }
46
46
  };
47
47
  this._getPluginParticleColors = (particle) => {
@@ -97,17 +97,17 @@ class Canvas {
97
97
  if (!trail.enable) {
98
98
  return;
99
99
  }
100
+ const factorNumerator = 1, opacity = factorNumerator / trail.length;
100
101
  if (trailFill.color) {
101
102
  const fillColor = (0, ColorUtils_js_1.rangeColorToRgb)(trailFill.color);
102
103
  if (!fillColor) {
103
104
  return;
104
105
  }
105
- const trail = options.particles.move.trail;
106
106
  this._trailFill = {
107
107
  color: {
108
108
  ...fillColor,
109
109
  },
110
- opacity: 1 / trail.length,
110
+ opacity,
111
111
  };
112
112
  }
113
113
  else {
@@ -119,7 +119,7 @@ class Canvas {
119
119
  img.addEventListener("load", () => {
120
120
  this._trailFill = {
121
121
  image: img,
122
- opacity: 1 / trail.length,
122
+ opacity,
123
123
  };
124
124
  resolve();
125
125
  });
@@ -170,9 +170,9 @@ class Canvas {
170
170
  if (!element) {
171
171
  return;
172
172
  }
173
- const priority = "important", style = element.style;
173
+ const priority = "important", style = element.style, radix = 10;
174
174
  style.setProperty("position", "fixed", priority);
175
- style.setProperty("z-index", this.container.actualOptions.fullScreen.zIndex.toString(10), priority);
175
+ style.setProperty("z-index", this.container.actualOptions.fullScreen.zIndex.toString(radix), priority);
176
176
  style.setProperty("top", "0", priority);
177
177
  style.setProperty("left", "0", priority);
178
178
  style.setProperty("width", "100%", priority);
@@ -193,11 +193,11 @@ class Canvas {
193
193
  return this.container.actualOptions.fullScreen.enable;
194
194
  }
195
195
  clear() {
196
- const options = this.container.actualOptions, trail = options.particles.move.trail, trailFill = this._trailFill;
196
+ const options = this.container.actualOptions, trail = options.particles.move.trail, trailFill = this._trailFill, minimumLength = 0;
197
197
  if (options.backgroundMask.enable) {
198
198
  this.paint();
199
199
  }
200
- else if (trail.enable && trail.length > 0 && trailFill) {
200
+ else if (trail.enable && trail.length > minimumLength && trailFill) {
201
201
  if (trailFill.color) {
202
202
  this._paintBase((0, ColorUtils_js_1.getStyleFromRgb)(trailFill.color, trailFill.opacity));
203
203
  }
@@ -215,7 +215,7 @@ class Canvas {
215
215
  this.stop();
216
216
  if (this._generated) {
217
217
  const element = this.element;
218
- element && element.remove();
218
+ element?.remove();
219
219
  }
220
220
  else {
221
221
  this._resetOriginalStyle();
@@ -236,8 +236,8 @@ class Canvas {
236
236
  if (particle.spawning || particle.destroyed) {
237
237
  return;
238
238
  }
239
- const radius = particle.getRadius();
240
- if (radius <= 0) {
239
+ const radius = particle.getRadius(), minimumSize = 0;
240
+ if (radius <= minimumSize) {
241
241
  return;
242
242
  }
243
243
  const pfColor = particle.getFillColor(), psColor = particle.getStrokeColor() ?? pfColor;
@@ -252,7 +252,7 @@ class Canvas {
252
252
  return;
253
253
  }
254
254
  this.draw((ctx) => {
255
- 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 = {
255
+ 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 = {
256
256
  fill: fColor ? (0, ColorUtils_js_1.getStyleFromHsl)(fColor, zOpacity) : undefined,
257
257
  };
258
258
  colorStyles.stroke = sColor ? (0, ColorUtils_js_1.getStyleFromHsl)(sColor, zStrokeOpacity) : colorStyles.fill;
@@ -265,7 +265,7 @@ class Canvas {
265
265
  colorStyles,
266
266
  backgroundMask: options.backgroundMask.enable,
267
267
  composite: options.backgroundMask.composite,
268
- radius: radius * (1 - particle.zIndexFactor) ** zIndexOptions.sizeRate,
268
+ radius: radius * zIndexFactor ** zIndexOptions.sizeRate,
269
269
  opacity: zOpacity,
270
270
  shadow: particle.options.shadow,
271
271
  transform,
@@ -335,7 +335,7 @@ class Canvas {
335
335
  if (plugin.resize) {
336
336
  this._resizePlugins.push(plugin);
337
337
  }
338
- if (plugin.particleFillColor || plugin.particleStrokeColor) {
338
+ if (plugin.particleFillColor ?? plugin.particleStrokeColor) {
339
339
  this._colorPlugins.push(plugin);
340
340
  }
341
341
  }
@@ -347,7 +347,7 @@ class Canvas {
347
347
  if (updater.afterDraw) {
348
348
  this._postDrawUpdaters.push(updater);
349
349
  }
350
- if (updater.getColorStyles || updater.getTransformValues || updater.beforeDraw) {
350
+ if (updater.getColorStyles ?? updater.getTransformValues ?? updater.beforeDraw) {
351
351
  this._preDrawUpdaters.push(updater);
352
352
  }
353
353
  }
@@ -1,22 +1,23 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.Container = void 0;
4
+ const Constants_js_1 = require("./Utils/Constants.js");
4
5
  const Utils_js_1 = require("../Utils/Utils.js");
5
6
  const Canvas_js_1 = require("./Canvas.js");
6
7
  const EventListeners_js_1 = require("./Utils/EventListeners.js");
7
8
  const Options_js_1 = require("../Options/Classes/Options.js");
8
9
  const Particles_js_1 = require("./Particles.js");
9
10
  const Retina_js_1 = require("./Retina.js");
10
- const Constants_js_1 = require("./Utils/Constants.js");
11
11
  const NumberUtils_js_1 = require("../Utils/NumberUtils.js");
12
12
  const OptionsUtils_js_1 = require("../Utils/OptionsUtils.js");
13
13
  function guardCheck(container) {
14
14
  return container && !container.destroyed;
15
15
  }
16
- function initDelta(value, fpsLimit = 60, smooth = false) {
16
+ const defaultFps = 60;
17
+ function initDelta(value, fpsLimit = defaultFps, smooth = false) {
17
18
  return {
18
19
  value,
19
- factor: smooth ? 60 / fpsLimit : (60 * value) / 1000,
20
+ factor: smooth ? defaultFps / fpsLimit : (defaultFps * value) / Constants_js_1.millisecondsToSeconds,
20
21
  };
21
22
  }
22
23
  function loadContainerOptions(engine, container, ...sourceOptionsArr) {
@@ -34,14 +35,19 @@ class Container {
34
35
  if (entry.target !== this.interactivity.element) {
35
36
  continue;
36
37
  }
37
- (entry.isIntersecting ? this.play : this.pause)();
38
+ if (entry.isIntersecting) {
39
+ this.play();
40
+ }
41
+ else {
42
+ this.pause();
43
+ }
38
44
  }
39
45
  };
40
46
  this._nextFrame = async (timestamp) => {
41
47
  try {
42
48
  if (!this._smooth &&
43
49
  this._lastFrameTime !== undefined &&
44
- timestamp < this._lastFrameTime + 1000 / this.fpsLimit) {
50
+ timestamp < this._lastFrameTime + Constants_js_1.millisecondsToSeconds / this.fpsLimit) {
45
51
  this.draw(false);
46
52
  return;
47
53
  }
@@ -49,7 +55,7 @@ class Container {
49
55
  const delta = initDelta(timestamp - this._lastFrameTime, this.fpsLimit, this._smooth);
50
56
  this.addLifeTime(delta.value);
51
57
  this._lastFrameTime = timestamp;
52
- if (delta.value > 1000) {
58
+ if (delta.value > Constants_js_1.millisecondsToSeconds) {
53
59
  this.draw(false);
54
60
  return;
55
61
  }
@@ -132,8 +138,8 @@ class Container {
132
138
  const mouseEvent = e, pos = {
133
139
  x: mouseEvent.offsetX || mouseEvent.clientX,
134
140
  y: mouseEvent.offsetY || mouseEvent.clientY,
135
- };
136
- clickOrTouchHandler(e, pos, 1);
141
+ }, radius = 1;
142
+ clickOrTouchHandler(e, pos, radius);
137
143
  };
138
144
  const touchStartHandler = () => {
139
145
  if (!guardCheck(this)) {
@@ -154,16 +160,17 @@ class Container {
154
160
  }
155
161
  if (touched && !touchMoved) {
156
162
  const touchEvent = e;
157
- let lastTouch = touchEvent.touches[touchEvent.touches.length - 1];
163
+ const lengthOffset = 1;
164
+ let lastTouch = touchEvent.touches[touchEvent.touches.length - lengthOffset];
158
165
  if (!lastTouch) {
159
- lastTouch = touchEvent.changedTouches[touchEvent.changedTouches.length - 1];
166
+ lastTouch = touchEvent.changedTouches[touchEvent.changedTouches.length - lengthOffset];
160
167
  if (!lastTouch) {
161
168
  return;
162
169
  }
163
170
  }
164
- const element = this.canvas.element, canvasRect = element ? element.getBoundingClientRect() : undefined, pos = {
165
- x: lastTouch.clientX - (canvasRect ? canvasRect.left : 0),
166
- y: lastTouch.clientY - (canvasRect ? canvasRect.top : 0),
171
+ const element = this.canvas.element, canvasRect = element ? element.getBoundingClientRect() : undefined, minCoordinate = 0, pos = {
172
+ x: lastTouch.clientX - (canvasRect ? canvasRect.left : minCoordinate),
173
+ y: lastTouch.clientY - (canvasRect ? canvasRect.top : minCoordinate),
167
174
  };
168
175
  clickOrTouchHandler(e, pos, Math.max(lastTouch.radiusX, lastTouch.radiusY));
169
176
  }
@@ -205,10 +212,10 @@ class Container {
205
212
  this.particles.destroy();
206
213
  this.canvas.destroy();
207
214
  for (const [, effectDrawer] of this.effectDrawers) {
208
- effectDrawer.destroy && effectDrawer.destroy(this);
215
+ effectDrawer.destroy?.(this);
209
216
  }
210
217
  for (const [, shapeDrawer] of this.shapeDrawers) {
211
- shapeDrawer.destroy && shapeDrawer.destroy(this);
218
+ shapeDrawer.destroy?.(this);
212
219
  }
213
220
  for (const key of this.effectDrawers.keys()) {
214
221
  this.effectDrawers.delete(key);
@@ -218,9 +225,10 @@ class Container {
218
225
  }
219
226
  this._engine.clearPlugins(this);
220
227
  this.destroyed = true;
221
- const mainArr = this._engine.dom(), idx = mainArr.findIndex((t) => t === this);
222
- if (idx >= 0) {
223
- mainArr.splice(idx, 1);
228
+ const mainArr = this._engine.dom(), idx = mainArr.findIndex((t) => t === this), minIndex = 0;
229
+ if (idx >= minIndex) {
230
+ const deleteCount = 1;
231
+ mainArr.splice(idx, deleteCount);
224
232
  }
225
233
  this._engine.dispatchEvent("containerDestroyed", { container: this });
226
234
  }
@@ -229,13 +237,14 @@ class Container {
229
237
  return;
230
238
  }
231
239
  let refreshTime = force;
232
- this._drawAnimationFrame = requestAnimationFrame(async (timestamp) => {
240
+ const frame = async (timestamp) => {
233
241
  if (refreshTime) {
234
242
  this._lastFrameTime = undefined;
235
243
  refreshTime = false;
236
244
  }
237
245
  await this._nextFrame(timestamp);
238
- });
246
+ };
247
+ this._drawAnimationFrame = requestAnimationFrame((timestamp) => void frame(timestamp));
239
248
  }
240
249
  async export(type, options = {}) {
241
250
  for (const [, plugin] of this.plugins) {
@@ -259,7 +268,7 @@ class Container {
259
268
  }
260
269
  this.particles.handleClickMode(mode);
261
270
  for (const [, plugin] of this.plugins) {
262
- plugin.handleClickMode && plugin.handleClickMode(mode);
271
+ plugin.handleClickMode?.(mode);
263
272
  }
264
273
  }
265
274
  async init() {
@@ -292,25 +301,26 @@ class Container {
292
301
  this.canvas.initBackground();
293
302
  this.canvas.resize();
294
303
  this.zLayers = this.actualOptions.zLayers;
295
- this._duration = (0, NumberUtils_js_1.getRangeValue)(this.actualOptions.duration) * 1000;
296
- this._delay = (0, NumberUtils_js_1.getRangeValue)(this.actualOptions.delay) * 1000;
304
+ this._duration = (0, NumberUtils_js_1.getRangeValue)(this.actualOptions.duration) * Constants_js_1.millisecondsToSeconds;
305
+ this._delay = (0, NumberUtils_js_1.getRangeValue)(this.actualOptions.delay) * Constants_js_1.millisecondsToSeconds;
297
306
  this._lifeTime = 0;
298
- this.fpsLimit = this.actualOptions.fpsLimit > 0 ? this.actualOptions.fpsLimit : 120;
307
+ const defaultFpsLimit = 120, minFpsLimit = 0;
308
+ this.fpsLimit = this.actualOptions.fpsLimit > minFpsLimit ? this.actualOptions.fpsLimit : defaultFpsLimit;
299
309
  this._smooth = this.actualOptions.smooth;
300
310
  for (const [, drawer] of this.effectDrawers) {
301
- drawer.init && (await drawer.init(this));
311
+ await drawer.init?.(this);
302
312
  }
303
313
  for (const [, drawer] of this.shapeDrawers) {
304
- drawer.init && (await drawer.init(this));
314
+ await drawer.init?.(this);
305
315
  }
306
316
  for (const [, plugin] of this.plugins) {
307
- plugin.init && (await plugin.init());
317
+ await plugin.init?.();
308
318
  }
309
319
  this._engine.dispatchEvent("containerInit", { container: this });
310
320
  this.particles.init();
311
321
  this.particles.setDensity();
312
322
  for (const [, plugin] of this.plugins) {
313
- plugin.particlesSetup && plugin.particlesSetup();
323
+ plugin.particlesSetup?.();
314
324
  }
315
325
  this._engine.dispatchEvent("particlesSetup", { container: this });
316
326
  }
@@ -333,7 +343,7 @@ class Container {
333
343
  return;
334
344
  }
335
345
  for (const [, plugin] of this.plugins) {
336
- plugin.pause && plugin.pause();
346
+ plugin.pause?.();
337
347
  }
338
348
  if (!this.pageHidden) {
339
349
  this._paused = true;
@@ -360,7 +370,7 @@ class Container {
360
370
  }
361
371
  }
362
372
  this._engine.dispatchEvent("containerPlay", { container: this });
363
- this.draw(needsUpdate || false);
373
+ this.draw(needsUpdate ?? false);
364
374
  }
365
375
  async refresh() {
366
376
  if (!guardCheck(this)) {
@@ -385,18 +395,19 @@ class Container {
385
395
  await this.init();
386
396
  this.started = true;
387
397
  await new Promise((resolve) => {
388
- this._delayTimeout = setTimeout(async () => {
398
+ const start = async () => {
389
399
  this._eventListeners.addListeners();
390
400
  if (this.interactivity.element instanceof HTMLElement && this._intersectionObserver) {
391
401
  this._intersectionObserver.observe(this.interactivity.element);
392
402
  }
393
403
  for (const [, plugin] of this.plugins) {
394
- plugin.start && (await plugin.start());
404
+ await plugin.start?.();
395
405
  }
396
406
  this._engine.dispatchEvent("containerStarted", { container: this });
397
407
  this.play();
398
408
  resolve();
399
- }, this._delay);
409
+ };
410
+ this._delayTimeout = setTimeout(() => void start(), this._delay);
400
411
  });
401
412
  }
402
413
  stop() {
@@ -417,7 +428,7 @@ class Container {
417
428
  this._intersectionObserver.unobserve(this.interactivity.element);
418
429
  }
419
430
  for (const [, plugin] of this.plugins) {
420
- plugin.stop && plugin.stop();
431
+ plugin.stop?.();
421
432
  }
422
433
  for (const key of this.plugins.keys()) {
423
434
  this.plugins.delete(key);
@@ -54,16 +54,18 @@ class Engine {
54
54
  return res;
55
55
  }
56
56
  get version() {
57
- return "3.0.3";
57
+ return "3.1.0";
58
58
  }
59
59
  addConfig(config) {
60
- const name = config.name ?? "default";
61
- this._configs.set(name, config);
62
- this._eventDispatcher.dispatchEvent("configAdded", { data: { name, config } });
60
+ const key = config.key ?? config.name ?? "default";
61
+ this._configs.set(key, config);
62
+ this._eventDispatcher.dispatchEvent("configAdded", { data: { name: key, config } });
63
63
  }
64
64
  async addEffect(effect, drawer, refresh = true) {
65
65
  (0, Utils_js_1.executeOnSingleOrMultiple)(effect, (type) => {
66
- !this.getEffectDrawer(type) && this.effectDrawers.set(type, drawer);
66
+ if (!this.getEffectDrawer(type)) {
67
+ this.effectDrawers.set(type, drawer);
68
+ }
67
69
  });
68
70
  await this.refresh(refresh);
69
71
  }
@@ -83,20 +85,28 @@ class Engine {
83
85
  await this.refresh(refresh);
84
86
  }
85
87
  async addPathGenerator(name, generator, refresh = true) {
86
- !this.getPathGenerator(name) && this.pathGenerators.set(name, generator);
88
+ if (!this.getPathGenerator(name)) {
89
+ this.pathGenerators.set(name, generator);
90
+ }
87
91
  await this.refresh(refresh);
88
92
  }
89
93
  async addPlugin(plugin, refresh = true) {
90
- !this.getPlugin(plugin.id) && this.plugins.push(plugin);
94
+ if (!this.getPlugin(plugin.id)) {
95
+ this.plugins.push(plugin);
96
+ }
91
97
  await this.refresh(refresh);
92
98
  }
93
99
  async addPreset(preset, options, override = false, refresh = true) {
94
- (override || !this.getPreset(preset)) && this.presets.set(preset, options);
100
+ if (override || !this.getPreset(preset)) {
101
+ this.presets.set(preset, options);
102
+ }
95
103
  await this.refresh(refresh);
96
104
  }
97
105
  async addShape(shape, drawer, refresh = true) {
98
106
  (0, Utils_js_1.executeOnSingleOrMultiple)(shape, (type) => {
99
- !this.getShapeDrawer(type) && this.shapeDrawers.set(type, drawer);
107
+ if (!this.getShapeDrawer(type)) {
108
+ this.shapeDrawers.set(type, drawer);
109
+ }
100
110
  });
101
111
  await this.refresh(refresh);
102
112
  }
@@ -114,7 +124,8 @@ class Engine {
114
124
  domItem(index) {
115
125
  const dom = this.dom(), item = dom[index];
116
126
  if (!item || item.destroyed) {
117
- dom.splice(index, 1);
127
+ const deleteCount = 1;
128
+ dom.splice(index, deleteCount);
118
129
  return;
119
130
  }
120
131
  return item;
@@ -122,7 +133,9 @@ class Engine {
122
133
  getAvailablePlugins(container) {
123
134
  const res = new Map();
124
135
  for (const plugin of this.plugins) {
125
- plugin.needsPlugin(container.actualOptions) && res.set(plugin.id, plugin.getPlugin(container));
136
+ if (plugin.needsPlugin(container.actualOptions)) {
137
+ res.set(plugin.id, plugin.getPlugin(container));
138
+ }
126
139
  }
127
140
  return res;
128
141
  }
@@ -163,19 +176,20 @@ class Engine {
163
176
  this._initialized = true;
164
177
  }
165
178
  async load(params) {
166
- 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;
179
+ 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;
167
180
  let domContainer = params.element ?? document.getElementById(id);
168
181
  if (!domContainer) {
169
182
  domContainer = document.createElement("div");
170
183
  domContainer.id = id;
171
184
  document.body.append(domContainer);
172
185
  }
173
- const currentOptions = (0, Utils_js_1.itemFromSingleOrMultiple)(options, index), dom = this.dom(), oldIndex = dom.findIndex((v) => v.id.description === id);
174
- if (oldIndex >= 0) {
186
+ const currentOptions = (0, Utils_js_1.itemFromSingleOrMultiple)(options, index), dom = this.dom(), oldIndex = dom.findIndex((v) => v.id.description === id), minIndex = 0;
187
+ if (oldIndex >= minIndex) {
175
188
  const old = this.domItem(oldIndex);
176
189
  if (old && !old.destroyed) {
177
190
  old.destroy();
178
- dom.splice(oldIndex, 1);
191
+ const deleteCount = 1;
192
+ dom.splice(oldIndex, deleteCount);
179
193
  }
180
194
  }
181
195
  let canvasEl;
@@ -186,7 +200,8 @@ class Engine {
186
200
  else {
187
201
  const existingCanvases = domContainer.getElementsByTagName("canvas");
188
202
  if (existingCanvases.length) {
189
- canvasEl = existingCanvases[0];
203
+ const firstIndex = 0;
204
+ canvasEl = existingCanvases[firstIndex];
190
205
  canvasEl.dataset[Constants_js_1.generatedAttribute] = "false";
191
206
  }
192
207
  else {
@@ -202,8 +217,9 @@ class Engine {
202
217
  canvasEl.style.height = "100%";
203
218
  }
204
219
  const newItem = new Container_js_1.Container(this, id, currentOptions);
205
- if (oldIndex >= 0) {
206
- dom.splice(oldIndex, 0, newItem);
220
+ if (oldIndex >= minIndex) {
221
+ const deleteCount = 0;
222
+ dom.splice(oldIndex, deleteCount, newItem);
207
223
  }
208
224
  else {
209
225
  dom.push(newItem);
@@ -223,14 +239,14 @@ class Engine {
223
239
  return;
224
240
  }
225
241
  for (const updater of updaters) {
226
- updater.loadOptions && updater.loadOptions(options, ...sourceOptions);
242
+ updater.loadOptions?.(options, ...sourceOptions);
227
243
  }
228
244
  }
229
245
  async refresh(refresh = true) {
230
246
  if (!refresh) {
231
247
  return;
232
248
  }
233
- this.dom().forEach((t) => t.refresh());
249
+ await Promise.allSettled(this.dom().map((t) => t.refresh()));
234
250
  }
235
251
  removeEventListener(type, listener) {
236
252
  this._eventDispatcher.removeEventListener(type, listener);