@tsparticles/engine 3.0.0-beta.2 → 3.0.0-beta.4

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 (186) hide show
  1. package/browser/Core/Canvas.js +2 -2
  2. package/browser/Core/Container.js +39 -24
  3. package/browser/Core/Engine.js +26 -53
  4. package/browser/Core/Particle.js +88 -53
  5. package/browser/Core/Particles.js +51 -26
  6. package/browser/Core/Retina.js +0 -2
  7. package/browser/Core/Utils/QuadTree.js +1 -1
  8. package/browser/Options/Classes/BackgroundMask/BackgroundMask.js +1 -2
  9. package/browser/Options/Classes/ColorAnimation.js +4 -24
  10. package/browser/Options/Classes/Particles/Bounce/ParticlesBounceFactor.js +0 -1
  11. package/browser/Options/Classes/Particles/Effect/Effect.js +32 -0
  12. package/browser/Options/Classes/Particles/Number/ParticlesNumber.js +3 -5
  13. package/browser/Options/Classes/Particles/Number/ParticlesNumberLimit.js +17 -0
  14. package/browser/Options/Classes/Particles/Opacity/Opacity.js +2 -3
  15. package/browser/Options/Classes/Particles/ParticlesOptions.js +3 -0
  16. package/browser/Options/Classes/Particles/Size/Size.js +2 -3
  17. package/browser/Options/Classes/ValueWithRandom.js +1 -10
  18. package/browser/Utils/CanvasUtils.js +29 -21
  19. package/browser/Utils/ColorUtils.js +24 -38
  20. package/browser/Utils/NumberUtils.js +7 -16
  21. package/browser/Utils/Utils.js +13 -7
  22. package/browser/export-types.js +4 -2
  23. package/browser/exports.js +2 -3
  24. package/cjs/Core/Canvas.js +2 -2
  25. package/cjs/Core/Container.js +39 -24
  26. package/cjs/Core/Engine.js +25 -52
  27. package/cjs/Core/Particle.js +87 -52
  28. package/cjs/Core/Particles.js +51 -26
  29. package/cjs/Core/Retina.js +0 -2
  30. package/cjs/Core/Utils/QuadTree.js +1 -1
  31. package/cjs/Options/Classes/BackgroundMask/BackgroundMask.js +1 -2
  32. package/cjs/Options/Classes/ColorAnimation.js +4 -24
  33. package/cjs/Options/Classes/Particles/Bounce/ParticlesBounceFactor.js +0 -1
  34. package/cjs/Options/Classes/Particles/Effect/Effect.js +36 -0
  35. package/cjs/Options/Classes/Particles/Number/ParticlesNumber.js +3 -5
  36. package/cjs/Options/Classes/Particles/Number/ParticlesNumberLimit.js +21 -0
  37. package/cjs/Options/Classes/Particles/Opacity/Opacity.js +1 -2
  38. package/cjs/Options/Classes/Particles/ParticlesOptions.js +3 -0
  39. package/cjs/Options/Classes/Particles/Size/Size.js +2 -3
  40. package/cjs/Options/Classes/ValueWithRandom.js +1 -10
  41. package/cjs/Utils/CanvasUtils.js +32 -24
  42. package/cjs/Utils/ColorUtils.js +24 -38
  43. package/cjs/Utils/NumberUtils.js +8 -18
  44. package/cjs/Utils/Utils.js +14 -7
  45. package/cjs/export-types.js +4 -2
  46. package/cjs/exports.js +2 -3
  47. package/esm/Core/Canvas.js +2 -2
  48. package/esm/Core/Container.js +39 -24
  49. package/esm/Core/Engine.js +26 -53
  50. package/esm/Core/Particle.js +88 -53
  51. package/esm/Core/Particles.js +51 -26
  52. package/esm/Core/Retina.js +0 -2
  53. package/esm/Core/Utils/QuadTree.js +1 -1
  54. package/esm/Options/Classes/BackgroundMask/BackgroundMask.js +1 -2
  55. package/esm/Options/Classes/ColorAnimation.js +4 -24
  56. package/esm/Options/Classes/Particles/Bounce/ParticlesBounceFactor.js +0 -1
  57. package/esm/Options/Classes/Particles/Effect/Effect.js +32 -0
  58. package/esm/Options/Classes/Particles/Number/ParticlesNumber.js +3 -5
  59. package/esm/Options/Classes/Particles/Number/ParticlesNumberLimit.js +17 -0
  60. package/esm/Options/Classes/Particles/Opacity/Opacity.js +2 -3
  61. package/esm/Options/Classes/Particles/ParticlesOptions.js +3 -0
  62. package/esm/Options/Classes/Particles/Size/Size.js +2 -3
  63. package/esm/Options/Classes/ValueWithRandom.js +1 -10
  64. package/esm/Utils/CanvasUtils.js +29 -21
  65. package/esm/Utils/ColorUtils.js +24 -38
  66. package/esm/Utils/NumberUtils.js +7 -16
  67. package/esm/Utils/Utils.js +13 -7
  68. package/esm/export-types.js +4 -2
  69. package/esm/exports.js +2 -3
  70. package/package.json +1 -1
  71. package/report.html +4 -22
  72. package/tsparticles.engine.js +461 -347
  73. package/tsparticles.engine.min.js +1 -1
  74. package/tsparticles.engine.min.js.LICENSE.txt +1 -1
  75. package/types/Core/Canvas.d.ts +0 -1
  76. package/types/Core/Container.d.ts +9 -8
  77. package/types/Core/Engine.d.ts +9 -5
  78. package/types/Core/Interfaces/IContainerPlugin.d.ts +2 -3
  79. package/types/Core/Interfaces/IEffectDrawer.d.ts +10 -0
  80. package/types/Core/Interfaces/IExternalInteractor.d.ts +3 -4
  81. package/types/Core/Interfaces/IInteractor.d.ts +3 -3
  82. package/types/Core/Interfaces/IParticleRetinaProps.d.ts +0 -1
  83. package/types/Core/Interfaces/IParticlesInteractor.d.ts +3 -3
  84. package/types/Core/Interfaces/IShapeDrawData.d.ts +10 -0
  85. package/types/Core/Interfaces/IShapeDrawer.d.ts +11 -9
  86. package/types/Core/Particle.d.ts +7 -5
  87. package/types/Core/Particles.d.ts +10 -7
  88. package/types/Core/Retina.d.ts +0 -1
  89. package/types/Core/Utils/ExternalInteractorBase.d.ts +4 -4
  90. package/types/Core/Utils/InteractionManager.d.ts +1 -2
  91. package/types/Core/Utils/ParticlesInteractorBase.d.ts +5 -5
  92. package/types/Enums/Modes/LimitMode.d.ts +4 -0
  93. package/types/Enums/Types/EasingType.d.ts +3 -0
  94. package/types/Enums/Types/EventType.d.ts +1 -0
  95. package/types/Options/Classes/BackgroundMask/BackgroundMask.d.ts +1 -1
  96. package/types/Options/Classes/ColorAnimation.d.ts +2 -7
  97. package/types/Options/Classes/Interactivity/Events/ClickEvent.d.ts +1 -2
  98. package/types/Options/Classes/Interactivity/Events/DivEvent.d.ts +1 -2
  99. package/types/Options/Classes/Interactivity/Events/Events.d.ts +3 -3
  100. package/types/Options/Classes/Interactivity/Events/HoverEvent.d.ts +2 -3
  101. package/types/Options/Classes/Interactivity/Interactivity.d.ts +2 -2
  102. package/types/Options/Classes/Options.d.ts +6 -6
  103. package/types/Options/Classes/Particles/Bounce/ParticlesBounce.d.ts +2 -2
  104. package/types/Options/Classes/Particles/Collisions/Collisions.d.ts +3 -3
  105. package/types/Options/Classes/Particles/Effect/Effect.d.ts +13 -0
  106. package/types/Options/Classes/Particles/Move/Move.d.ts +8 -8
  107. package/types/Options/Classes/Particles/Move/MoveTrail.d.ts +1 -1
  108. package/types/Options/Classes/Particles/Number/ParticlesNumber.d.ts +3 -2
  109. package/types/Options/Classes/Particles/Number/ParticlesNumberLimit.d.ts +10 -0
  110. package/types/Options/Classes/Particles/Opacity/Opacity.d.ts +3 -3
  111. package/types/Options/Classes/Particles/ParticlesOptions.d.ts +12 -10
  112. package/types/Options/Classes/Particles/Size/Size.d.ts +3 -3
  113. package/types/Options/Classes/Theme/Theme.d.ts +1 -1
  114. package/types/Options/Classes/ValueWithRandom.d.ts +2 -4
  115. package/types/Options/Interfaces/IValueWithRandom.d.ts +0 -2
  116. package/types/Options/Interfaces/Interactivity/Events/IClickEvent.d.ts +1 -2
  117. package/types/Options/Interfaces/Interactivity/Events/IDivEvent.d.ts +1 -2
  118. package/types/Options/Interfaces/Interactivity/Events/IHoverEvent.d.ts +1 -2
  119. package/types/Options/Interfaces/Particles/Effect/IEffect.d.ts +8 -0
  120. package/types/Options/Interfaces/Particles/IParticlesOptions.d.ts +2 -0
  121. package/types/Options/Interfaces/Particles/Number/IParticlesNumber.d.ts +2 -1
  122. package/types/Options/Interfaces/Particles/Number/IParticlesNumberLimit.d.ts +5 -0
  123. package/types/Types/CustomEventArgs.d.ts +1 -1
  124. package/types/Utils/CanvasUtils.d.ts +12 -3
  125. package/types/Utils/ColorUtils.d.ts +2 -2
  126. package/types/Utils/NumberUtils.d.ts +0 -2
  127. package/types/Utils/Utils.d.ts +6 -6
  128. package/types/export-types.d.ts +5 -2
  129. package/types/exports.d.ts +2 -3
  130. package/umd/Core/Canvas.js +2 -2
  131. package/umd/Core/Container.js +40 -25
  132. package/umd/Core/Engine.js +25 -52
  133. package/umd/Core/Particle.js +87 -52
  134. package/umd/Core/Particles.js +51 -26
  135. package/umd/Core/Retina.js +0 -2
  136. package/umd/Core/Utils/QuadTree.js +1 -1
  137. package/umd/Options/Classes/BackgroundMask/BackgroundMask.js +1 -2
  138. package/umd/Options/Classes/ColorAnimation.js +5 -25
  139. package/umd/Options/Classes/Particles/Bounce/ParticlesBounceFactor.js +0 -1
  140. package/umd/Options/Classes/Particles/Effect/Effect.js +46 -0
  141. package/umd/Options/Classes/Particles/Number/ParticlesNumber.js +4 -6
  142. package/umd/Options/Classes/{Random.js → Particles/Number/ParticlesNumberLimit.js} +9 -9
  143. package/umd/Options/Classes/Particles/Opacity/Opacity.js +1 -2
  144. package/umd/Options/Classes/Particles/ParticlesOptions.js +4 -1
  145. package/umd/Options/Classes/Particles/Size/Size.js +3 -4
  146. package/umd/Options/Classes/ValueWithRandom.js +2 -11
  147. package/umd/Utils/CanvasUtils.js +32 -24
  148. package/umd/Utils/ColorUtils.js +24 -38
  149. package/umd/Utils/NumberUtils.js +9 -19
  150. package/umd/Utils/Utils.js +14 -7
  151. package/umd/export-types.js +5 -3
  152. package/umd/exports.js +3 -4
  153. package/browser/Options/Classes/Random.js +0 -17
  154. package/cjs/Options/Classes/Random.js +0 -21
  155. package/cjs/Types/ShapeDrawerFunctions.js +0 -2
  156. package/esm/Options/Classes/Random.js +0 -17
  157. package/esm/Options/Interfaces/IRandom.js +0 -1
  158. package/esm/Types/ShapeDrawerFunctions.js +0 -1
  159. package/types/Core/Interfaces/IParticle.d.ts +0 -48
  160. package/types/Enums/Modes/ClickMode.d.ts +0 -9
  161. package/types/Enums/Modes/DivMode.d.ts +0 -5
  162. package/types/Enums/Modes/HoverMode.d.ts +0 -11
  163. package/types/Options/Classes/Random.d.ts +0 -9
  164. package/types/Options/Interfaces/IRandom.d.ts +0 -4
  165. package/types/Types/ShapeDrawerFunctions.d.ts +0 -10
  166. package/umd/Types/ShapeDrawerFunctions.js +0 -12
  167. /package/browser/Core/Interfaces/{IParticle.js → IEffectDrawer.js} +0 -0
  168. /package/browser/{Enums/Modes/ClickMode.js → Core/Interfaces/IShapeDrawData.js} +0 -0
  169. /package/browser/Enums/Modes/{DivMode.js → LimitMode.js} +0 -0
  170. /package/browser/{Enums/Modes/HoverMode.js → Options/Interfaces/Particles/Effect/IEffect.js} +0 -0
  171. /package/browser/Options/Interfaces/{IRandom.js → Particles/Number/IParticlesNumberLimit.js} +0 -0
  172. /package/cjs/Core/Interfaces/{IParticle.js → IEffectDrawer.js} +0 -0
  173. /package/cjs/{Enums/Modes/ClickMode.js → Core/Interfaces/IShapeDrawData.js} +0 -0
  174. /package/cjs/Enums/Modes/{DivMode.js → LimitMode.js} +0 -0
  175. /package/cjs/{Enums/Modes/HoverMode.js → Options/Interfaces/Particles/Effect/IEffect.js} +0 -0
  176. /package/cjs/Options/Interfaces/{IRandom.js → Particles/Number/IParticlesNumberLimit.js} +0 -0
  177. /package/{browser/Types/ShapeDrawerFunctions.js → esm/Core/Interfaces/IEffectDrawer.js} +0 -0
  178. /package/esm/Core/Interfaces/{IParticle.js → IShapeDrawData.js} +0 -0
  179. /package/esm/Enums/Modes/{ClickMode.js → LimitMode.js} +0 -0
  180. /package/esm/{Enums/Modes/DivMode.js → Options/Interfaces/Particles/Effect/IEffect.js} +0 -0
  181. /package/esm/{Enums/Modes/HoverMode.js → Options/Interfaces/Particles/Number/IParticlesNumberLimit.js} +0 -0
  182. /package/umd/Core/Interfaces/{IParticle.js → IEffectDrawer.js} +0 -0
  183. /package/umd/{Enums/Modes/ClickMode.js → Core/Interfaces/IShapeDrawData.js} +0 -0
  184. /package/umd/Enums/Modes/{DivMode.js → LimitMode.js} +0 -0
  185. /package/umd/{Enums/Modes/HoverMode.js → Options/Interfaces/Particles/Effect/IEffect.js} +0 -0
  186. /package/umd/Options/Interfaces/{IRandom.js → Particles/Number/IParticlesNumberLimit.js} +0 -0
@@ -402,10 +402,10 @@ export class Canvas {
402
402
  this.element.width = size.width = this.element.offsetWidth * pxRatio;
403
403
  this.element.height = size.height = this.element.offsetHeight * pxRatio;
404
404
  if (this.container.started) {
405
- this.resizeFactor = {
405
+ container.particles.setResizeFactor({
406
406
  width: size.width / oldSize.width,
407
407
  height: size.height / oldSize.height,
408
- };
408
+ });
409
409
  }
410
410
  return true;
411
411
  }
@@ -1,10 +1,10 @@
1
+ import { getLogger, safeIntersectionObserver } from "../Utils/Utils.js";
1
2
  import { Canvas } from "./Canvas.js";
2
3
  import { EventListeners } from "./Utils/EventListeners.js";
3
4
  import { Options } from "../Options/Classes/Options.js";
4
5
  import { Particles } from "./Particles.js";
5
6
  import { Retina } from "./Retina.js";
6
7
  import { errorPrefix } from "./Utils/Constants.js";
7
- import { getLogger } from "../Utils/Utils.js";
8
8
  import { getRangeValue } from "../Utils/NumberUtils.js";
9
9
  import { loadOptions } from "../Utils/OptionsUtils.js";
10
10
  function guardCheck(container) {
@@ -23,7 +23,6 @@ function loadContainerOptions(engine, container, ...sourceOptionsArr) {
23
23
  }
24
24
  export class Container {
25
25
  constructor(engine, id, sourceOptions) {
26
- this.id = id;
27
26
  this._intersectionManager = (entries) => {
28
27
  if (!guardCheck(this) || !this.actualOptions.pauseOnOutsideViewport) {
29
28
  return;
@@ -37,16 +36,16 @@ export class Container {
37
36
  };
38
37
  this._nextFrame = async (timestamp) => {
39
38
  try {
40
- if (!this.smooth &&
41
- this.lastFrameTime !== undefined &&
42
- timestamp < this.lastFrameTime + 1000 / this.fpsLimit) {
39
+ if (!this._smooth &&
40
+ this._lastFrameTime !== undefined &&
41
+ timestamp < this._lastFrameTime + 1000 / this.fpsLimit) {
43
42
  this.draw(false);
44
43
  return;
45
44
  }
46
- this.lastFrameTime ??= timestamp;
47
- const delta = initDelta(timestamp - this.lastFrameTime, this.fpsLimit, this.smooth);
45
+ this._lastFrameTime ??= timestamp;
46
+ const delta = initDelta(timestamp - this._lastFrameTime, this.fpsLimit, this._smooth);
48
47
  this.addLifeTime(delta.value);
49
- this.lastFrameTime = timestamp;
48
+ this._lastFrameTime = timestamp;
50
49
  if (delta.value > 1000) {
51
50
  this.draw(false);
52
51
  return;
@@ -65,8 +64,9 @@ export class Container {
65
64
  }
66
65
  };
67
66
  this._engine = engine;
67
+ this.id = Symbol(id);
68
68
  this.fpsLimit = 120;
69
- this.smooth = false;
69
+ this._smooth = false;
70
70
  this._delay = 0;
71
71
  this._duration = 0;
72
72
  this._lifeTime = 0;
@@ -74,7 +74,7 @@ export class Container {
74
74
  this.started = false;
75
75
  this.destroyed = false;
76
76
  this._paused = true;
77
- this.lastFrameTime = 0;
77
+ this._lastFrameTime = 0;
78
78
  this.zLayers = 100;
79
79
  this.pageHidden = false;
80
80
  this._sourceOptions = sourceOptions;
@@ -90,13 +90,12 @@ export class Container {
90
90
  },
91
91
  };
92
92
  this.plugins = new Map();
93
- this.drawers = new Map();
93
+ this.effectDrawers = new Map();
94
+ this.shapeDrawers = new Map();
94
95
  this._options = loadContainerOptions(this._engine, this);
95
96
  this.actualOptions = loadContainerOptions(this._engine, this);
96
97
  this._eventListeners = new EventListeners(this);
97
- if (typeof IntersectionObserver !== "undefined" && IntersectionObserver) {
98
- this._intersectionObserver = new IntersectionObserver((entries) => this._intersectionManager(entries));
99
- }
98
+ this._intersectionObserver = safeIntersectionObserver((entries) => this._intersectionManager(entries));
100
99
  this._engine.dispatchEvent("containerBuilt", { container: this });
101
100
  }
102
101
  get options() {
@@ -202,11 +201,17 @@ export class Container {
202
201
  this.stop();
203
202
  this.particles.destroy();
204
203
  this.canvas.destroy();
205
- for (const [, drawer] of this.drawers) {
206
- drawer.destroy && drawer.destroy(this);
204
+ for (const [, effectDrawer] of this.effectDrawers) {
205
+ effectDrawer.destroy && effectDrawer.destroy(this);
206
+ }
207
+ for (const [, shapeDrawer] of this.shapeDrawers) {
208
+ shapeDrawer.destroy && shapeDrawer.destroy(this);
207
209
  }
208
- for (const key of this.drawers.keys()) {
209
- this.drawers.delete(key);
210
+ for (const key of this.effectDrawers.keys()) {
211
+ this.effectDrawers.delete(key);
212
+ }
213
+ for (const key of this.shapeDrawers.keys()) {
214
+ this.shapeDrawers.delete(key);
210
215
  }
211
216
  this._engine.clearPlugins(this);
212
217
  this.destroyed = true;
@@ -223,7 +228,7 @@ export class Container {
223
228
  let refreshTime = force;
224
229
  this._drawAnimationFrame = requestAnimationFrame(async (timestamp) => {
225
230
  if (refreshTime) {
226
- this.lastFrameTime = undefined;
231
+ this._lastFrameTime = undefined;
227
232
  refreshTime = false;
228
233
  }
229
234
  await this._nextFrame(timestamp);
@@ -258,11 +263,18 @@ export class Container {
258
263
  if (!guardCheck(this)) {
259
264
  return;
260
265
  }
266
+ const effects = this._engine.getSupportedEffects();
267
+ for (const type of effects) {
268
+ const drawer = this._engine.getEffectDrawer(type);
269
+ if (drawer) {
270
+ this.effectDrawers.set(type, drawer);
271
+ }
272
+ }
261
273
  const shapes = this._engine.getSupportedShapes();
262
274
  for (const type of shapes) {
263
275
  const drawer = this._engine.getShapeDrawer(type);
264
276
  if (drawer) {
265
- this.drawers.set(type, drawer);
277
+ this.shapeDrawers.set(type, drawer);
266
278
  }
267
279
  }
268
280
  this._options = loadContainerOptions(this._engine, this, this._initialSourceOptions, this.sourceOptions);
@@ -281,8 +293,11 @@ export class Container {
281
293
  this._delay = getRangeValue(this.actualOptions.delay) * 1000;
282
294
  this._lifeTime = 0;
283
295
  this.fpsLimit = this.actualOptions.fpsLimit > 0 ? this.actualOptions.fpsLimit : 120;
284
- this.smooth = this.actualOptions.smooth;
285
- for (const [, drawer] of this.drawers) {
296
+ this._smooth = this.actualOptions.smooth;
297
+ for (const [, drawer] of this.effectDrawers) {
298
+ drawer.init && (await drawer.init(this));
299
+ }
300
+ for (const [, drawer] of this.shapeDrawers) {
286
301
  drawer.init && (await drawer.init(this));
287
302
  }
288
303
  for (const [, plugin] of this.plugins) {
@@ -411,10 +426,10 @@ export class Container {
411
426
  this.actualOptions.responsive = [];
412
427
  const newMaxWidth = this.actualOptions.setResponsive(this.canvas.size.width, this.retina.pixelRatio, this._options);
413
428
  this.actualOptions.setTheme(this._currentTheme);
414
- if (this.responsiveMaxWidth === newMaxWidth) {
429
+ if (this._responsiveMaxWidth === newMaxWidth) {
415
430
  return false;
416
431
  }
417
- this.responsiveMaxWidth = newMaxWidth;
432
+ this._responsiveMaxWidth = newMaxWidth;
418
433
  return true;
419
434
  }
420
435
  }
@@ -1,5 +1,5 @@
1
1
  import { errorPrefix, generatedAttribute } from "./Utils/Constants.js";
2
- import { executeOnSingleOrMultiple, getLogger, isBoolean, isFunction, isString, itemFromSingleOrMultiple, } from "../Utils/Utils.js";
2
+ import { executeOnSingleOrMultiple, getLogger, itemFromSingleOrMultiple } from "../Utils/Utils.js";
3
3
  import { Container } from "./Container.js";
4
4
  import { EventDispatcher } from "../Utils/EventDispatcher.js";
5
5
  import { getRandom } from "../Utils/NumberUtils.js";
@@ -39,7 +39,8 @@ export class Engine {
39
39
  this.movers = new Map();
40
40
  this.updaters = new Map();
41
41
  this.presets = new Map();
42
- this.drawers = new Map();
42
+ this.effectDrawers = new Map();
43
+ this.shapeDrawers = new Map();
43
44
  this.pathGenerators = new Map();
44
45
  }
45
46
  get configs() {
@@ -50,18 +51,18 @@ export class Engine {
50
51
  return res;
51
52
  }
52
53
  get version() {
53
- return "3.0.0-beta.2";
54
+ return "3.0.0-beta.4";
54
55
  }
55
- addConfig(nameOrConfig, config) {
56
- if (isString(nameOrConfig)) {
57
- if (config) {
58
- config.name = nameOrConfig;
59
- this._configs.set(nameOrConfig, config);
60
- }
61
- }
62
- else {
63
- this._configs.set(nameOrConfig.name ?? "default", nameOrConfig);
64
- }
56
+ addConfig(config) {
57
+ const name = config.name ?? "default";
58
+ this._configs.set(name, config);
59
+ this._eventDispatcher.dispatchEvent("configAdded", { data: { name, config } });
60
+ }
61
+ async addEffect(effect, drawer, refresh = true) {
62
+ executeOnSingleOrMultiple(effect, (type) => {
63
+ !this.getEffectDrawer(type) && this.effectDrawers.set(type, drawer);
64
+ });
65
+ await this.refresh(refresh);
65
66
  }
66
67
  addEventListener(type, listener) {
67
68
  this._eventDispatcher.addEventListener(type, listener);
@@ -90,45 +91,11 @@ export class Engine {
90
91
  (override || !this.getPreset(preset)) && this.presets.set(preset, options);
91
92
  await this.refresh(refresh);
92
93
  }
93
- async addShape(shape, drawer, initOrRefresh, afterEffectOrRefresh, destroyOrRefresh, refresh = true) {
94
- let customDrawer;
95
- let realRefresh = refresh, realInit, realAfterEffect, realDestroy;
96
- if (isBoolean(initOrRefresh)) {
97
- realRefresh = initOrRefresh;
98
- realInit = undefined;
99
- }
100
- else {
101
- realInit = initOrRefresh;
102
- }
103
- if (isBoolean(afterEffectOrRefresh)) {
104
- realRefresh = afterEffectOrRefresh;
105
- realAfterEffect = undefined;
106
- }
107
- else {
108
- realAfterEffect = afterEffectOrRefresh;
109
- }
110
- if (isBoolean(destroyOrRefresh)) {
111
- realRefresh = destroyOrRefresh;
112
- realDestroy = undefined;
113
- }
114
- else {
115
- realDestroy = destroyOrRefresh;
116
- }
117
- if (isFunction(drawer)) {
118
- customDrawer = {
119
- afterEffect: realAfterEffect,
120
- destroy: realDestroy,
121
- draw: drawer,
122
- init: realInit,
123
- };
124
- }
125
- else {
126
- customDrawer = drawer;
127
- }
94
+ async addShape(shape, drawer, refresh = true) {
128
95
  executeOnSingleOrMultiple(shape, (type) => {
129
- !this.getShapeDrawer(type) && this.drawers.set(type, customDrawer);
96
+ !this.getShapeDrawer(type) && this.shapeDrawers.set(type, drawer);
130
97
  });
131
- await this.refresh(realRefresh);
98
+ await this.refresh(refresh);
132
99
  }
133
100
  clearPlugins(container) {
134
101
  this.updaters.delete(container);
@@ -156,6 +123,9 @@ export class Engine {
156
123
  }
157
124
  return res;
158
125
  }
126
+ getEffectDrawer(type) {
127
+ return this.effectDrawers.get(type);
128
+ }
159
129
  getInteractors(container, force = false) {
160
130
  return getItemsFromInitializer(container, this.interactors, this._initializers.interactors, force);
161
131
  }
@@ -172,10 +142,13 @@ export class Engine {
172
142
  return this.presets.get(preset);
173
143
  }
174
144
  getShapeDrawer(type) {
175
- return this.drawers.get(type);
145
+ return this.shapeDrawers.get(type);
146
+ }
147
+ getSupportedEffects() {
148
+ return this.effectDrawers.keys();
176
149
  }
177
150
  getSupportedShapes() {
178
- return this.drawers.keys();
151
+ return this.shapeDrawers.keys();
179
152
  }
180
153
  getUpdaters(container, force = false) {
181
154
  return getItemsFromInitializer(container, this.updaters, this._initializers.updaters, force);
@@ -194,7 +167,7 @@ export class Engine {
194
167
  domContainer.id = id;
195
168
  document.body.append(domContainer);
196
169
  }
197
- const currentOptions = itemFromSingleOrMultiple(options, index), dom = this.dom(), oldIndex = dom.findIndex((v) => v.id === id);
170
+ const currentOptions = itemFromSingleOrMultiple(options, index), dom = this.dom(), oldIndex = dom.findIndex((v) => v.id.description === id);
198
171
  if (oldIndex >= 0) {
199
172
  const old = this.domItem(oldIndex);
200
173
  if (old && !old.destroyed) {
@@ -1,4 +1,4 @@
1
- import { calcExactPositionOrRandomFromSize, clamp, getDistance, getParticleBaseVelocity, getParticleDirectionAngle, getRandom, getRangeValue, getValue, randomInRange, setRangeValue, } from "../Utils/NumberUtils.js";
1
+ import { calcExactPositionOrRandomFromSize, clamp, getDistance, getParticleBaseVelocity, getParticleDirectionAngle, getRandom, getRangeValue, randomInRange, setRangeValue, } from "../Utils/NumberUtils.js";
2
2
  import { deepExtend, getPosition, initParticleNumericAnimationValue, isInArray, itemFromSingleOrMultiple, } from "../Utils/Utils.js";
3
3
  import { getHslFromAnimation, rangeColorToRgb } from "../Utils/ColorUtils.js";
4
4
  import { Interactivity } from "../Options/Classes/Interactivity/Interactivity.js";
@@ -7,7 +7,27 @@ import { Vector3d } from "./Utils/Vector3d.js";
7
7
  import { alterHsl } from "../Utils/CanvasUtils.js";
8
8
  import { errorPrefix } from "./Utils/Constants.js";
9
9
  import { loadParticlesOptions } from "../Utils/OptionsUtils.js";
10
- const fixOutMode = (data) => {
10
+ function loadEffectData(effect, effectOptions, id, reduceDuplicates) {
11
+ const effectData = effectOptions.options[effect];
12
+ if (!effectData) {
13
+ return;
14
+ }
15
+ return deepExtend({
16
+ close: effectOptions.close,
17
+ fill: effectOptions.fill,
18
+ }, itemFromSingleOrMultiple(effectData, id, reduceDuplicates));
19
+ }
20
+ function loadShapeData(shape, shapeOptions, id, reduceDuplicates) {
21
+ const shapeData = shapeOptions.options[shape];
22
+ if (!shapeData) {
23
+ return;
24
+ }
25
+ return deepExtend({
26
+ close: shapeOptions.close,
27
+ fill: shapeOptions.fill,
28
+ }, itemFromSingleOrMultiple(shapeData, id, reduceDuplicates));
29
+ }
30
+ function fixOutMode(data) {
11
31
  if (!isInArray(data.outMode, data.checkModes)) {
12
32
  return;
13
33
  }
@@ -18,7 +38,7 @@ const fixOutMode = (data) => {
18
38
  else if (data.coord < diameter) {
19
39
  data.setCb(data.radius);
20
40
  }
21
- };
41
+ }
22
42
  export class Particle {
23
43
  constructor(engine, id, container, position, overrideOptions, group) {
24
44
  this.container = container;
@@ -66,8 +86,8 @@ export class Particle {
66
86
  return res;
67
87
  }
68
88
  const rad = (Math.PI / 180) * getRangeValue(moveOptions.angle.value), radOffset = (Math.PI / 180) * getRangeValue(moveOptions.angle.offset), range = {
69
- left: radOffset - rad / 2,
70
- right: radOffset + rad / 2,
89
+ left: radOffset - rad * 0.5,
90
+ right: radOffset + rad * 0.5,
71
91
  };
72
92
  if (!moveOptions.straight) {
73
93
  res.angle += randomInRange(setRangeValue(range.left, range.right));
@@ -96,7 +116,7 @@ export class Particle {
96
116
  if (!color || !this.roll || (!this.backColor && !this.roll.alter)) {
97
117
  return color;
98
118
  }
99
- const backFactor = this.roll.horizontal && this.roll.vertical ? 2 : 1, backSum = this.roll.horizontal ? Math.PI / 2 : 0, rolled = Math.floor(((this.roll.angle ?? 0) + backSum) / (Math.PI / backFactor)) % 2;
119
+ const backFactor = this.roll.horizontal && this.roll.vertical ? 2 : 1, backSum = this.roll.horizontal ? Math.PI * 0.5 : 0, rolled = Math.floor(((this.roll.angle ?? 0) + backSum) / (Math.PI / backFactor)) % 2;
100
120
  if (!rolled) {
101
121
  return color;
102
122
  }
@@ -129,16 +149,6 @@ export class Particle {
129
149
  }
130
150
  this.offset = Vector.origin;
131
151
  };
132
- this._loadShapeData = (shapeOptions, reduceDuplicates) => {
133
- const shapeData = shapeOptions.options[this.shape];
134
- if (!shapeData) {
135
- return;
136
- }
137
- return deepExtend({
138
- close: shapeOptions.close,
139
- fill: shapeOptions.fill,
140
- }, itemFromSingleOrMultiple(shapeData, this.id, reduceDuplicates));
141
- };
142
152
  this._engine = engine;
143
153
  this.init(id, position, overrideOptions, group);
144
154
  }
@@ -151,18 +161,12 @@ export class Particle {
151
161
  this.slow.inRange = false;
152
162
  const container = this.container, pathGenerator = this.pathGenerator;
153
163
  for (const [, plugin] of container.plugins) {
154
- if (plugin.particleDestroyed) {
155
- plugin.particleDestroyed(this, override);
156
- }
164
+ plugin.particleDestroyed && plugin.particleDestroyed(this, override);
157
165
  }
158
166
  for (const updater of container.particles.updaters) {
159
- if (updater.particleDestroyed) {
160
- updater.particleDestroyed(this, override);
161
- }
162
- }
163
- if (pathGenerator) {
164
- pathGenerator.reset(this);
167
+ updater.particleDestroyed && updater.particleDestroyed(this, override);
165
168
  }
169
+ pathGenerator && pathGenerator.reset(this);
166
170
  }
167
171
  draw(delta) {
168
172
  const container = this.container, canvas = container.canvas;
@@ -175,7 +179,7 @@ export class Particle {
175
179
  return this._getRollColor(this.bubble.color ?? getHslFromAnimation(this.color));
176
180
  }
177
181
  getMass() {
178
- return (this.getRadius() ** 2 * Math.PI) / 2;
182
+ return this.getRadius() ** 2 * Math.PI * 0.5;
179
183
  }
180
184
  getPosition() {
181
185
  return {
@@ -194,9 +198,11 @@ export class Particle {
194
198
  const container = this.container, engine = this._engine;
195
199
  this.id = id;
196
200
  this.group = group;
197
- this.fill = true;
201
+ this.effectClose = true;
202
+ this.effectFill = true;
203
+ this.shapeClose = true;
204
+ this.shapeFill = true;
198
205
  this.pathRotation = false;
199
- this.close = true;
200
206
  this.lastPathTime = 0;
201
207
  this.destroyed = false;
202
208
  this.unbreakable = false;
@@ -207,18 +213,33 @@ export class Particle {
207
213
  };
208
214
  this.outType = "normal";
209
215
  this.ignoresResizeRatio = true;
210
- const pxRatio = container.retina.pixelRatio, mainOptions = container.actualOptions, particlesOptions = loadParticlesOptions(this._engine, container, mainOptions.particles), shapeType = particlesOptions.shape.type, { reduceDuplicates } = particlesOptions;
216
+ const pxRatio = container.retina.pixelRatio, mainOptions = container.actualOptions, particlesOptions = loadParticlesOptions(this._engine, container, mainOptions.particles), effectType = particlesOptions.effect.type, shapeType = particlesOptions.shape.type, { reduceDuplicates } = particlesOptions;
217
+ this.effect = itemFromSingleOrMultiple(effectType, this.id, reduceDuplicates);
211
218
  this.shape = itemFromSingleOrMultiple(shapeType, this.id, reduceDuplicates);
212
- const shapeOptions = particlesOptions.shape;
213
- if (overrideOptions && overrideOptions.shape && overrideOptions.shape.type) {
214
- const overrideShapeType = overrideOptions.shape.type, shape = itemFromSingleOrMultiple(overrideShapeType, this.id, reduceDuplicates);
215
- if (shape) {
216
- this.shape = shape;
217
- shapeOptions.load(overrideOptions.shape);
219
+ const effectOptions = particlesOptions.effect, shapeOptions = particlesOptions.shape;
220
+ if (overrideOptions) {
221
+ if (overrideOptions.effect && overrideOptions.effect.type) {
222
+ const overrideEffectType = overrideOptions.effect.type, effect = itemFromSingleOrMultiple(overrideEffectType, this.id, reduceDuplicates);
223
+ if (effect) {
224
+ this.effect = effect;
225
+ effectOptions.load(overrideOptions.effect);
226
+ }
227
+ }
228
+ if (overrideOptions.shape && overrideOptions.shape.type) {
229
+ const overrideShapeType = overrideOptions.shape.type, shape = itemFromSingleOrMultiple(overrideShapeType, this.id, reduceDuplicates);
230
+ if (shape) {
231
+ this.shape = shape;
232
+ shapeOptions.load(overrideOptions.shape);
233
+ }
218
234
  }
219
235
  }
220
- this.shapeData = this._loadShapeData(shapeOptions, reduceDuplicates);
236
+ this.effectData = loadEffectData(this.effect, effectOptions, this.id, reduceDuplicates);
237
+ this.shapeData = loadShapeData(this.shape, shapeOptions, this.id, reduceDuplicates);
221
238
  particlesOptions.load(overrideOptions);
239
+ const effectData = this.effectData;
240
+ if (effectData) {
241
+ particlesOptions.load(effectData.particles);
242
+ }
222
243
  const shapeData = this.shapeData;
223
244
  if (shapeData) {
224
245
  particlesOptions.load(shapeData.particles);
@@ -227,11 +248,13 @@ export class Particle {
227
248
  interactivity.load(container.actualOptions.interactivity);
228
249
  interactivity.load(particlesOptions.interactivity);
229
250
  this.interactivity = interactivity;
230
- this.fill = shapeData?.fill ?? particlesOptions.shape.fill;
231
- this.close = shapeData?.close ?? particlesOptions.shape.close;
251
+ this.effectFill = effectData?.fill ?? particlesOptions.effect.fill;
252
+ this.effectClose = effectData?.close ?? particlesOptions.effect.close;
253
+ this.shapeFill = shapeData?.fill ?? particlesOptions.shape.fill;
254
+ this.shapeClose = shapeData?.close ?? particlesOptions.shape.close;
232
255
  this.options = particlesOptions;
233
256
  const pathOptions = this.options.move.path;
234
- this.pathDelay = getValue(pathOptions.delay) * 1000;
257
+ this.pathDelay = getRangeValue(pathOptions.delay.value) * 1000;
235
258
  if (pathOptions.generator) {
236
259
  this.pathGenerator = this._engine.getPathGenerator(pathOptions.generator);
237
260
  if (this.pathGenerator && container.addPath(pathOptions.generator, this.pathGenerator)) {
@@ -252,34 +275,46 @@ export class Particle {
252
275
  this.velocity = this.initialVelocity.copy();
253
276
  this.moveDecay = 1 - getRangeValue(this.options.move.decay);
254
277
  const particles = container.particles;
255
- particles.needsSort = particles.needsSort || particles.lastZIndex < this.position.z;
256
- particles.lastZIndex = this.position.z;
278
+ particles.setLastZIndex(this.position.z);
257
279
  this.zIndexFactor = this.position.z / container.zLayers;
258
280
  this.sides = 24;
259
- let drawer = container.drawers.get(this.shape);
260
- if (!drawer) {
261
- drawer = this._engine.getShapeDrawer(this.shape);
262
- if (drawer) {
263
- container.drawers.set(this.shape, drawer);
281
+ let effectDrawer = container.effectDrawers.get(this.effect);
282
+ if (!effectDrawer) {
283
+ effectDrawer = this._engine.getEffectDrawer(this.effect);
284
+ if (effectDrawer) {
285
+ container.effectDrawers.set(this.effect, effectDrawer);
264
286
  }
265
287
  }
266
- if (drawer && drawer.loadShape) {
267
- drawer.loadShape(this);
288
+ if (effectDrawer && effectDrawer.loadEffect) {
289
+ effectDrawer.loadEffect(this);
268
290
  }
269
- const sideCountFunc = drawer?.getSidesCount;
291
+ let shapeDrawer = container.shapeDrawers.get(this.shape);
292
+ if (!shapeDrawer) {
293
+ shapeDrawer = this._engine.getShapeDrawer(this.shape);
294
+ if (shapeDrawer) {
295
+ container.shapeDrawers.set(this.shape, shapeDrawer);
296
+ }
297
+ }
298
+ if (shapeDrawer && shapeDrawer.loadShape) {
299
+ shapeDrawer.loadShape(this);
300
+ }
301
+ const sideCountFunc = shapeDrawer?.getSidesCount;
270
302
  if (sideCountFunc) {
271
303
  this.sides = sideCountFunc(this);
272
304
  }
273
305
  this.spawning = false;
274
306
  this.shadowColor = rangeColorToRgb(this.options.shadow.color);
275
- for (const updater of container.particles.updaters) {
307
+ for (const updater of particles.updaters) {
276
308
  updater.init(this);
277
309
  }
278
- for (const mover of container.particles.movers) {
310
+ for (const mover of particles.movers) {
279
311
  mover.init && mover.init(this);
280
312
  }
281
- if (drawer && drawer.particleInit) {
282
- drawer.particleInit(container, this);
313
+ if (effectDrawer && effectDrawer.particleInit) {
314
+ effectDrawer.particleInit(container, this);
315
+ }
316
+ if (shapeDrawer && shapeDrawer.particleInit) {
317
+ shapeDrawer.particleInit(container, this);
283
318
  }
284
319
  for (const [, plugin] of container.plugins) {
285
320
  plugin.particleCreated && plugin.particleCreated(this);