@tsparticles/engine 3.0.0-beta.3 → 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 (177) hide show
  1. package/browser/Core/Canvas.js +2 -2
  2. package/browser/Core/Container.js +36 -19
  3. package/browser/Core/Engine.js +18 -5
  4. package/browser/Core/Particle.js +75 -40
  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 +23 -18
  19. package/browser/Utils/ColorUtils.js +24 -38
  20. package/browser/Utils/NumberUtils.js +7 -16
  21. package/browser/Utils/Utils.js +7 -7
  22. package/browser/export-types.js +4 -0
  23. package/browser/exports.js +2 -3
  24. package/cjs/Core/Canvas.js +2 -2
  25. package/cjs/Core/Container.js +36 -19
  26. package/cjs/Core/Engine.js +18 -5
  27. package/cjs/Core/Particle.js +74 -39
  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/Options/Interfaces/Particles/Number/IParticlesNumberLimit.js +2 -0
  42. package/cjs/Utils/CanvasUtils.js +26 -21
  43. package/cjs/Utils/ColorUtils.js +24 -38
  44. package/cjs/Utils/NumberUtils.js +8 -18
  45. package/cjs/Utils/Utils.js +6 -6
  46. package/cjs/export-types.js +4 -0
  47. package/cjs/exports.js +2 -3
  48. package/esm/Core/Canvas.js +2 -2
  49. package/esm/Core/Container.js +36 -19
  50. package/esm/Core/Engine.js +18 -5
  51. package/esm/Core/Particle.js +75 -40
  52. package/esm/Core/Particles.js +51 -26
  53. package/esm/Core/Retina.js +0 -2
  54. package/esm/Core/Utils/QuadTree.js +1 -1
  55. package/esm/Options/Classes/BackgroundMask/BackgroundMask.js +1 -2
  56. package/esm/Options/Classes/ColorAnimation.js +4 -24
  57. package/esm/Options/Classes/Particles/Bounce/ParticlesBounceFactor.js +0 -1
  58. package/esm/Options/Classes/Particles/Effect/Effect.js +32 -0
  59. package/esm/Options/Classes/Particles/Number/ParticlesNumber.js +3 -5
  60. package/esm/Options/Classes/Particles/Number/ParticlesNumberLimit.js +17 -0
  61. package/esm/Options/Classes/Particles/Opacity/Opacity.js +2 -3
  62. package/esm/Options/Classes/Particles/ParticlesOptions.js +3 -0
  63. package/esm/Options/Classes/Particles/Size/Size.js +2 -3
  64. package/esm/Options/Classes/ValueWithRandom.js +1 -10
  65. package/esm/Options/Interfaces/Particles/Effect/IEffect.js +1 -0
  66. package/esm/Options/Interfaces/Particles/Number/IParticlesNumberLimit.js +1 -0
  67. package/esm/Utils/CanvasUtils.js +23 -18
  68. package/esm/Utils/ColorUtils.js +24 -38
  69. package/esm/Utils/NumberUtils.js +7 -16
  70. package/esm/Utils/Utils.js +7 -7
  71. package/esm/export-types.js +4 -0
  72. package/esm/exports.js +2 -3
  73. package/package.json +1 -1
  74. package/report.html +4 -22
  75. package/tsparticles.engine.js +387 -283
  76. package/tsparticles.engine.min.js +1 -1
  77. package/tsparticles.engine.min.js.LICENSE.txt +1 -1
  78. package/types/Core/Canvas.d.ts +0 -1
  79. package/types/Core/Container.d.ts +8 -7
  80. package/types/Core/Engine.d.ts +7 -2
  81. package/types/Core/Interfaces/IContainerPlugin.d.ts +2 -3
  82. package/types/Core/Interfaces/IEffectDrawer.d.ts +10 -0
  83. package/types/Core/Interfaces/IExternalInteractor.d.ts +3 -4
  84. package/types/Core/Interfaces/IInteractor.d.ts +3 -3
  85. package/types/Core/Interfaces/IParticleRetinaProps.d.ts +0 -1
  86. package/types/Core/Interfaces/IParticlesInteractor.d.ts +3 -3
  87. package/types/Core/Interfaces/IShapeDrawData.d.ts +10 -0
  88. package/types/Core/Interfaces/IShapeDrawer.d.ts +2 -10
  89. package/types/Core/Particle.d.ts +6 -2
  90. package/types/Core/Particles.d.ts +10 -7
  91. package/types/Core/Retina.d.ts +0 -1
  92. package/types/Core/Utils/ExternalInteractorBase.d.ts +4 -4
  93. package/types/Core/Utils/InteractionManager.d.ts +1 -2
  94. package/types/Core/Utils/ParticlesInteractorBase.d.ts +5 -5
  95. package/types/Enums/Modes/LimitMode.d.ts +4 -0
  96. package/types/Enums/Types/EasingType.d.ts +3 -0
  97. package/types/Options/Classes/BackgroundMask/BackgroundMask.d.ts +1 -1
  98. package/types/Options/Classes/ColorAnimation.d.ts +2 -7
  99. package/types/Options/Classes/Interactivity/Events/ClickEvent.d.ts +1 -2
  100. package/types/Options/Classes/Interactivity/Events/DivEvent.d.ts +1 -2
  101. package/types/Options/Classes/Interactivity/Events/Events.d.ts +3 -3
  102. package/types/Options/Classes/Interactivity/Events/HoverEvent.d.ts +2 -3
  103. package/types/Options/Classes/Interactivity/Interactivity.d.ts +2 -2
  104. package/types/Options/Classes/Options.d.ts +6 -6
  105. package/types/Options/Classes/Particles/Bounce/ParticlesBounce.d.ts +2 -2
  106. package/types/Options/Classes/Particles/Collisions/Collisions.d.ts +3 -3
  107. package/types/Options/Classes/Particles/Effect/Effect.d.ts +13 -0
  108. package/types/Options/Classes/Particles/Move/Move.d.ts +8 -8
  109. package/types/Options/Classes/Particles/Move/MoveTrail.d.ts +1 -1
  110. package/types/Options/Classes/Particles/Number/ParticlesNumber.d.ts +3 -2
  111. package/types/Options/Classes/Particles/Number/ParticlesNumberLimit.d.ts +10 -0
  112. package/types/Options/Classes/Particles/Opacity/Opacity.d.ts +3 -3
  113. package/types/Options/Classes/Particles/ParticlesOptions.d.ts +12 -10
  114. package/types/Options/Classes/Particles/Size/Size.d.ts +3 -3
  115. package/types/Options/Classes/Theme/Theme.d.ts +1 -1
  116. package/types/Options/Classes/ValueWithRandom.d.ts +2 -4
  117. package/types/Options/Interfaces/IValueWithRandom.d.ts +0 -2
  118. package/types/Options/Interfaces/Interactivity/Events/IClickEvent.d.ts +1 -2
  119. package/types/Options/Interfaces/Interactivity/Events/IDivEvent.d.ts +1 -2
  120. package/types/Options/Interfaces/Interactivity/Events/IHoverEvent.d.ts +1 -2
  121. package/types/Options/Interfaces/Particles/Effect/IEffect.d.ts +8 -0
  122. package/types/Options/Interfaces/Particles/IParticlesOptions.d.ts +2 -0
  123. package/types/Options/Interfaces/Particles/Number/IParticlesNumber.d.ts +2 -1
  124. package/types/Options/Interfaces/Particles/Number/IParticlesNumberLimit.d.ts +5 -0
  125. package/types/Utils/CanvasUtils.d.ts +2 -2
  126. package/types/Utils/NumberUtils.d.ts +0 -2
  127. package/types/Utils/Utils.d.ts +2 -3
  128. package/types/export-types.d.ts +5 -0
  129. package/types/exports.d.ts +2 -3
  130. package/umd/Core/Canvas.js +2 -2
  131. package/umd/Core/Container.js +36 -19
  132. package/umd/Core/Engine.js +18 -5
  133. package/umd/Core/Particle.js +74 -39
  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/Options/Interfaces/Particles/Number/IParticlesNumberLimit.js +12 -0
  148. package/umd/Utils/CanvasUtils.js +26 -21
  149. package/umd/Utils/ColorUtils.js +24 -38
  150. package/umd/Utils/NumberUtils.js +9 -19
  151. package/umd/Utils/Utils.js +6 -6
  152. package/umd/export-types.js +5 -1
  153. package/umd/exports.js +3 -4
  154. package/browser/Options/Classes/Random.js +0 -17
  155. package/cjs/Options/Classes/Random.js +0 -21
  156. package/esm/Options/Classes/Random.js +0 -17
  157. package/types/Enums/Modes/ClickMode.d.ts +0 -9
  158. package/types/Enums/Modes/DivMode.d.ts +0 -5
  159. package/types/Enums/Modes/HoverMode.d.ts +0 -11
  160. package/types/Options/Classes/Random.d.ts +0 -9
  161. package/types/Options/Interfaces/IRandom.d.ts +0 -4
  162. /package/browser/{Enums/Modes/ClickMode.js → Core/Interfaces/IEffectDrawer.js} +0 -0
  163. /package/browser/{Enums/Modes/DivMode.js → Core/Interfaces/IShapeDrawData.js} +0 -0
  164. /package/browser/Enums/Modes/{HoverMode.js → LimitMode.js} +0 -0
  165. /package/browser/Options/Interfaces/{IRandom.js → Particles/Effect/IEffect.js} +0 -0
  166. /package/{esm/Enums/Modes/ClickMode.js → browser/Options/Interfaces/Particles/Number/IParticlesNumberLimit.js} +0 -0
  167. /package/cjs/{Enums/Modes/ClickMode.js → Core/Interfaces/IEffectDrawer.js} +0 -0
  168. /package/cjs/{Enums/Modes/DivMode.js → Core/Interfaces/IShapeDrawData.js} +0 -0
  169. /package/cjs/Enums/Modes/{HoverMode.js → LimitMode.js} +0 -0
  170. /package/cjs/Options/Interfaces/{IRandom.js → Particles/Effect/IEffect.js} +0 -0
  171. /package/esm/{Enums/Modes/DivMode.js → Core/Interfaces/IEffectDrawer.js} +0 -0
  172. /package/esm/{Enums/Modes/HoverMode.js → Core/Interfaces/IShapeDrawData.js} +0 -0
  173. /package/esm/{Options/Interfaces/IRandom.js → Enums/Modes/LimitMode.js} +0 -0
  174. /package/umd/{Enums/Modes/ClickMode.js → Core/Interfaces/IEffectDrawer.js} +0 -0
  175. /package/umd/{Enums/Modes/DivMode.js → Core/Interfaces/IShapeDrawData.js} +0 -0
  176. /package/umd/Enums/Modes/{HoverMode.js → LimitMode.js} +0 -0
  177. /package/umd/Options/Interfaces/{IRandom.js → Particles/Effect/IEffect.js} +0 -0
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * tsParticles Engine v3.0.0-beta.3
2
+ * tsParticles Engine v3.0.0-beta.4
3
3
  * Author: Matteo Bruni
4
4
  * MIT license: https://opensource.org/licenses/MIT
5
5
  * Website: https://particles.js.org/
@@ -99,6 +99,7 @@ __webpack_require__.d(__webpack_exports__, {
99
99
  ParticlesDensity: () => (/* reexport */ ParticlesDensity),
100
100
  ParticlesInteractorBase: () => (/* reexport */ ParticlesInteractorBase),
101
101
  ParticlesNumber: () => (/* reexport */ ParticlesNumber),
102
+ ParticlesNumberLimit: () => (/* reexport */ ParticlesNumberLimit),
102
103
  ParticlesOptions: () => (/* reexport */ ParticlesOptions),
103
104
  Point: () => (/* reexport */ Point),
104
105
  Range: () => (/* reexport */ Range),
@@ -142,13 +143,13 @@ __webpack_require__.d(__webpack_exports__, {
142
143
  deepExtend: () => (/* reexport */ deepExtend),
143
144
  divMode: () => (/* reexport */ divMode),
144
145
  divModeExecute: () => (/* reexport */ divModeExecute),
146
+ drawEffect: () => (/* reexport */ drawEffect),
145
147
  drawLine: () => (/* reexport */ drawLine),
146
148
  drawParticle: () => (/* reexport */ drawParticle),
147
149
  drawParticlePlugin: () => (/* reexport */ drawParticlePlugin),
148
150
  drawPlugin: () => (/* reexport */ drawPlugin),
149
151
  drawShape: () => (/* reexport */ drawShape),
150
- drawShapeAfterEffect: () => (/* reexport */ drawShapeAfterEffect),
151
- drawTriangle: () => (/* reexport */ drawTriangle),
152
+ drawShapeAfterDraw: () => (/* reexport */ drawShapeAfterDraw),
152
153
  errorPrefix: () => (/* reexport */ errorPrefix),
153
154
  executeOnSingleOrMultiple: () => (/* reexport */ executeOnSingleOrMultiple),
154
155
  findItemFromSingleOrMultiple: () => (/* reexport */ findItemFromSingleOrMultiple),
@@ -172,7 +173,6 @@ __webpack_require__.d(__webpack_exports__, {
172
173
  getSize: () => (/* reexport */ getSize),
173
174
  getStyleFromHsl: () => (/* reexport */ getStyleFromHsl),
174
175
  getStyleFromRgb: () => (/* reexport */ getStyleFromRgb),
175
- getValue: () => (/* reexport */ getValue),
176
176
  hasMatchMedia: () => (/* reexport */ hasMatchMedia),
177
177
  hslToRgb: () => (/* reexport */ hslToRgb),
178
178
  hslaToRgba: () => (/* reexport */ hslaToRgba),
@@ -411,17 +411,6 @@ function setRangeValue(source, value) {
411
411
  max: Math.max(max, value)
412
412
  } : setRangeValue(min, max);
413
413
  }
414
- function getValue(options) {
415
- const random = options.random,
416
- {
417
- enable,
418
- minimumValue
419
- } = isBoolean(random) ? {
420
- enable: random,
421
- minimumValue: 0
422
- } : random;
423
- return enable ? getRangeValue(setRangeValue(options.value, minimumValue)) : getRangeValue(options.value);
424
- }
425
414
  function getDistances(pointA, pointB) {
426
415
  const dx = pointA.x - pointB.x,
427
416
  dy = pointA.y - pointB.y;
@@ -440,21 +429,21 @@ function getParticleDirectionAngle(direction, position, center) {
440
429
  }
441
430
  switch (direction) {
442
431
  case "top":
443
- return -Math.PI / 2;
432
+ return -Math.PI * 0.5;
444
433
  case "top-right":
445
- return -Math.PI / 4;
434
+ return -Math.PI * 0.25;
446
435
  case "right":
447
436
  return 0;
448
437
  case "bottom-right":
449
- return Math.PI / 4;
438
+ return Math.PI * 0.25;
450
439
  case "bottom":
451
- return Math.PI / 2;
440
+ return Math.PI * 0.5;
452
441
  case "bottom-left":
453
- return 3 * Math.PI / 4;
442
+ return Math.PI * 0.75;
454
443
  case "left":
455
444
  return Math.PI;
456
445
  case "top-left":
457
- return -3 * Math.PI / 4;
446
+ return -Math.PI * 0.75;
458
447
  case "inside":
459
448
  return Math.atan2(center.y - position.y, center.x - position.x);
460
449
  case "outside":
@@ -550,7 +539,7 @@ function rectSideBounce(data) {
550
539
  if (pOtherSide.min < rectOtherSide.min || pOtherSide.min > rectOtherSide.max || pOtherSide.max < rectOtherSide.min || pOtherSide.max > rectOtherSide.max) {
551
540
  return res;
552
541
  }
553
- if (pSide.max >= rectSide.min && pSide.max <= (rectSide.max + rectSide.min) / 2 && velocity > 0 || pSide.min <= rectSide.max && pSide.min > (rectSide.max + rectSide.min) / 2 && velocity < 0) {
542
+ if (pSide.max >= rectSide.min && pSide.max <= (rectSide.max + rectSide.min) * 0.5 && velocity > 0 || pSide.min <= rectSide.max && pSide.min > (rectSide.max + rectSide.min) * 0.5 && velocity < 0) {
554
543
  res.velocity = velocity * -factor;
555
544
  res.bounced = true;
556
545
  }
@@ -686,7 +675,7 @@ function circleBounceDataFromParticle(p) {
686
675
  radius: p.getRadius(),
687
676
  mass: p.getMass(),
688
677
  velocity: p.velocity,
689
- factor: Vector.create(getValue(p.options.bounce.horizontal), getValue(p.options.bounce.vertical))
678
+ factor: Vector.create(getRangeValue(p.options.bounce.horizontal.value), getRangeValue(p.options.bounce.vertical.value))
690
679
  };
691
680
  }
692
681
  function circleBounce(p1, p2) {
@@ -720,6 +709,7 @@ function rectBounce(particle, divBounds) {
720
709
  const pPos = particle.getPosition(),
721
710
  size = particle.getRadius(),
722
711
  bounds = calculateBounds(pPos, size),
712
+ bounceOptions = particle.options.bounce,
723
713
  resH = rectSideBounce({
724
714
  pSide: {
725
715
  min: bounds.left,
@@ -738,7 +728,7 @@ function rectBounce(particle, divBounds) {
738
728
  max: divBounds.bottom
739
729
  },
740
730
  velocity: particle.velocity.x,
741
- factor: getValue(particle.options.bounce.horizontal)
731
+ factor: getRangeValue(bounceOptions.horizontal.value)
742
732
  });
743
733
  if (resH.bounced) {
744
734
  if (resH.velocity !== undefined) {
@@ -766,7 +756,7 @@ function rectBounce(particle, divBounds) {
766
756
  max: divBounds.right
767
757
  },
768
758
  velocity: particle.velocity.y,
769
- factor: getValue(particle.options.bounce.vertical)
759
+ factor: getRangeValue(bounceOptions.vertical.value)
770
760
  });
771
761
  if (resV.bounced) {
772
762
  if (resV.velocity !== undefined) {
@@ -893,24 +883,6 @@ const randomColorValue = "random",
893
883
  function addColorManager(manager) {
894
884
  colorManagers.set(manager.key, manager);
895
885
  }
896
- function hue2rgb(p, q, t) {
897
- if (t < 0) {
898
- t += 1;
899
- }
900
- if (t > 1) {
901
- t -= 1;
902
- }
903
- if (t < 1 / 6) {
904
- return p + (q - p) * 6 * t;
905
- }
906
- if (t < 1 / 2) {
907
- return q;
908
- }
909
- if (t < 2 / 3) {
910
- return p + (q - p) * (2 / 3 - t) * 6;
911
- }
912
- return p;
913
- }
914
886
  function stringToRgba(input) {
915
887
  for (const [, manager] of colorManagers) {
916
888
  if (input.startsWith(manager.stringPrefix)) {
@@ -990,7 +962,7 @@ function rgbToHsl(color) {
990
962
  min = Math.min(r1, g1, b1),
991
963
  res = {
992
964
  h: 0,
993
- l: (max + min) / 2,
965
+ l: (max + min) * 0.5,
994
966
  s: 0
995
967
  };
996
968
  if (max !== min) {
@@ -1015,29 +987,48 @@ function stringToRgb(input) {
1015
987
  return stringToRgba(input);
1016
988
  }
1017
989
  function hslToRgb(hsl) {
1018
- const result = {
1019
- b: 0,
1020
- g: 0,
1021
- r: 0
1022
- },
1023
- hslPercent = {
1024
- h: hsl.h / 360,
1025
- l: hsl.l / 100,
1026
- s: hsl.s / 100
990
+ const h = (hsl.h % 360 + 360) % 360,
991
+ s = Math.max(0, Math.min(100, hsl.s)),
992
+ l = Math.max(0, Math.min(100, hsl.l)),
993
+ hNormalized = h / 360,
994
+ sNormalized = s / 100,
995
+ lNormalized = l / 100;
996
+ if (s === 0) {
997
+ const grayscaleValue = Math.round(lNormalized * 255);
998
+ return {
999
+ r: grayscaleValue,
1000
+ g: grayscaleValue,
1001
+ b: grayscaleValue
1027
1002
  };
1028
- if (!hslPercent.s) {
1029
- result.r = result.g = result.b = hslPercent.l;
1030
- } else {
1031
- const q = hslPercent.l < 0.5 ? hslPercent.l * (1 + hslPercent.s) : hslPercent.l + hslPercent.s - hslPercent.l * hslPercent.s,
1032
- p = 2 * hslPercent.l - q;
1033
- result.r = hue2rgb(p, q, hslPercent.h + 1 / 3);
1034
- result.g = hue2rgb(p, q, hslPercent.h);
1035
- result.b = hue2rgb(p, q, hslPercent.h - 1 / 3);
1036
1003
  }
1037
- result.r = Math.floor(result.r * 255);
1038
- result.g = Math.floor(result.g * 255);
1039
- result.b = Math.floor(result.b * 255);
1040
- return result;
1004
+ const channel = (temp1, temp2, temp3) => {
1005
+ if (temp3 < 0) {
1006
+ temp3 += 1;
1007
+ }
1008
+ if (temp3 > 1) {
1009
+ temp3 -= 1;
1010
+ }
1011
+ if (temp3 * 6 < 1) {
1012
+ return temp1 + (temp2 - temp1) * 6 * temp3;
1013
+ }
1014
+ if (temp3 * 2 < 1) {
1015
+ return temp2;
1016
+ }
1017
+ if (temp3 * 3 < 2) {
1018
+ return temp1 + (temp2 - temp1) * (2 / 3 - temp3) * 6;
1019
+ }
1020
+ return temp1;
1021
+ },
1022
+ temp1 = lNormalized < 0.5 ? lNormalized * (1 + sNormalized) : lNormalized + sNormalized - lNormalized * sNormalized,
1023
+ temp2 = 2 * lNormalized - temp1,
1024
+ red = Math.min(255, 255 * channel(temp2, temp1, hNormalized + 1 / 3)),
1025
+ green = Math.min(255, 255 * channel(temp2, temp1, hNormalized)),
1026
+ blue = Math.min(255, 255 * channel(temp2, temp1, hNormalized - 1 / 3));
1027
+ return {
1028
+ r: Math.round(red),
1029
+ g: Math.round(green),
1030
+ b: Math.round(blue)
1031
+ };
1041
1032
  }
1042
1033
  function hslaToRgba(hsla) {
1043
1034
  const rgbResult = hslToRgb(hsla);
@@ -1171,13 +1162,6 @@ function drawLine(context, begin, end) {
1171
1162
  context.lineTo(end.x, end.y);
1172
1163
  context.closePath();
1173
1164
  }
1174
- function drawTriangle(context, p1, p2, p3) {
1175
- context.beginPath();
1176
- context.moveTo(p1.x, p1.y);
1177
- context.lineTo(p2.x, p2.y);
1178
- context.lineTo(p3.x, p3.y);
1179
- context.closePath();
1180
- }
1181
1165
  function paintBase(context, dimension, baseColor) {
1182
1166
  context.fillStyle = baseColor ?? "rgba(0,0,0,0)";
1183
1167
  context.fillRect(0, 0, dimension.width, dimension.height);
@@ -1220,7 +1204,6 @@ function drawParticle(data) {
1220
1204
  d: rotateData.cos * (transform.d ?? 1)
1221
1205
  };
1222
1206
  context.setTransform(transformData.a, transformData.b, transformData.c, transformData.d, pos.x, pos.y);
1223
- context.beginPath();
1224
1207
  if (backgroundMask) {
1225
1208
  context.globalCompositeOperation = composite;
1226
1209
  }
@@ -1247,20 +1230,47 @@ function drawParticle(data) {
1247
1230
  opacity,
1248
1231
  delta
1249
1232
  };
1233
+ context.beginPath();
1250
1234
  drawShape(drawData);
1235
+ if (particle.shapeClose) {
1236
+ context.closePath();
1237
+ }
1251
1238
  if (strokeWidth > 0) {
1252
1239
  context.stroke();
1253
1240
  }
1254
- if (particle.close) {
1255
- context.closePath();
1256
- }
1257
- if (particle.fill) {
1241
+ if (particle.shapeFill) {
1258
1242
  context.fill();
1259
1243
  }
1260
- drawShapeAfterEffect(drawData);
1244
+ drawShapeAfterDraw(drawData);
1245
+ drawEffect(drawData);
1261
1246
  context.globalCompositeOperation = "source-over";
1262
1247
  context.setTransform(1, 0, 0, 1, 0, 0);
1263
1248
  }
1249
+ function drawEffect(data) {
1250
+ const {
1251
+ container,
1252
+ context,
1253
+ particle,
1254
+ radius,
1255
+ opacity,
1256
+ delta
1257
+ } = data;
1258
+ if (!particle.effect) {
1259
+ return;
1260
+ }
1261
+ const drawer = container.effectDrawers.get(particle.effect);
1262
+ if (!drawer) {
1263
+ return;
1264
+ }
1265
+ drawer.draw({
1266
+ context,
1267
+ particle,
1268
+ radius,
1269
+ opacity,
1270
+ delta,
1271
+ pixelRatio: container.retina.pixelRatio
1272
+ });
1273
+ }
1264
1274
  function drawShape(data) {
1265
1275
  const {
1266
1276
  container,
@@ -1273,7 +1283,7 @@ function drawShape(data) {
1273
1283
  if (!particle.shape) {
1274
1284
  return;
1275
1285
  }
1276
- const drawer = container.drawers.get(particle.shape);
1286
+ const drawer = container.shapeDrawers.get(particle.shape);
1277
1287
  if (!drawer) {
1278
1288
  return;
1279
1289
  }
@@ -1286,7 +1296,7 @@ function drawShape(data) {
1286
1296
  pixelRatio: container.retina.pixelRatio
1287
1297
  });
1288
1298
  }
1289
- function drawShapeAfterEffect(data) {
1299
+ function drawShapeAfterDraw(data) {
1290
1300
  const {
1291
1301
  container,
1292
1302
  context,
@@ -1298,11 +1308,11 @@ function drawShapeAfterEffect(data) {
1298
1308
  if (!particle.shape) {
1299
1309
  return;
1300
1310
  }
1301
- const drawer = container.drawers.get(particle.shape);
1302
- if (!drawer || !drawer.afterEffect) {
1311
+ const drawer = container.shapeDrawers.get(particle.shape);
1312
+ if (!drawer || !drawer.afterDraw) {
1303
1313
  return;
1304
1314
  }
1305
- drawer.afterEffect({
1315
+ drawer.afterDraw({
1306
1316
  context,
1307
1317
  particle,
1308
1318
  radius,
@@ -1756,10 +1766,10 @@ class Canvas {
1756
1766
  this.element.width = size.width = this.element.offsetWidth * pxRatio;
1757
1767
  this.element.height = size.height = this.element.offsetHeight * pxRatio;
1758
1768
  if (this.container.started) {
1759
- this.resizeFactor = {
1769
+ container.particles.setResizeFactor({
1760
1770
  width: size.width / oldSize.width,
1761
1771
  height: size.height / oldSize.height
1762
- };
1772
+ });
1763
1773
  }
1764
1774
  return true;
1765
1775
  }
@@ -2229,10 +2239,10 @@ class BackgroundMask {
2229
2239
  this.composite = data.composite;
2230
2240
  }
2231
2241
  if (data.cover !== undefined) {
2232
- const cover = data.cover;
2233
- const color = isString(data.cover) ? {
2234
- color: data.cover
2235
- } : data.cover;
2242
+ const cover = data.cover,
2243
+ color = isString(data.cover) ? {
2244
+ color: data.cover
2245
+ } : data.cover;
2236
2246
  this.cover.load(cover.color !== undefined ? cover : {
2237
2247
  color: color
2238
2248
  });
@@ -2534,17 +2544,16 @@ class Theme {
2534
2544
  }
2535
2545
  }
2536
2546
  }
2537
- ;// CONCATENATED MODULE: ./dist/browser/Options/Classes/ColorAnimation.js
2547
+ ;// CONCATENATED MODULE: ./dist/browser/Options/Classes/AnimationOptions.js
2538
2548
 
2539
- class ColorAnimation {
2549
+ class AnimationOptions {
2540
2550
  constructor() {
2541
2551
  this.count = 0;
2542
2552
  this.enable = false;
2543
- this.offset = 0;
2544
2553
  this.speed = 1;
2545
- this.delay = 0;
2546
2554
  this.decay = 0;
2547
- this.sync = true;
2555
+ this.delay = 0;
2556
+ this.sync = false;
2548
2557
  }
2549
2558
  load(data) {
2550
2559
  if (!data) {
@@ -2556,9 +2565,6 @@ class ColorAnimation {
2556
2565
  if (data.enable !== undefined) {
2557
2566
  this.enable = data.enable;
2558
2567
  }
2559
- if (data.offset !== undefined) {
2560
- this.offset = setRangeValue(data.offset);
2561
- }
2562
2568
  if (data.speed !== undefined) {
2563
2569
  this.speed = setRangeValue(data.speed);
2564
2570
  }
@@ -2573,6 +2579,44 @@ class ColorAnimation {
2573
2579
  }
2574
2580
  }
2575
2581
  }
2582
+ class RangedAnimationOptions extends AnimationOptions {
2583
+ constructor() {
2584
+ super();
2585
+ this.mode = "auto";
2586
+ this.startValue = "random";
2587
+ }
2588
+ load(data) {
2589
+ super.load(data);
2590
+ if (!data) {
2591
+ return;
2592
+ }
2593
+ if (data.mode !== undefined) {
2594
+ this.mode = data.mode;
2595
+ }
2596
+ if (data.startValue !== undefined) {
2597
+ this.startValue = data.startValue;
2598
+ }
2599
+ }
2600
+ }
2601
+ ;// CONCATENATED MODULE: ./dist/browser/Options/Classes/ColorAnimation.js
2602
+
2603
+
2604
+ class ColorAnimation extends AnimationOptions {
2605
+ constructor() {
2606
+ super();
2607
+ this.offset = 0;
2608
+ this.sync = true;
2609
+ }
2610
+ load(data) {
2611
+ super.load(data);
2612
+ if (!data) {
2613
+ return;
2614
+ }
2615
+ if (data.offset !== undefined) {
2616
+ this.offset = setRangeValue(data.offset);
2617
+ }
2618
+ }
2619
+ }
2576
2620
  ;// CONCATENATED MODULE: ./dist/browser/Options/Classes/HslAnimation.js
2577
2621
 
2578
2622
  class HslAnimation {
@@ -2660,99 +2704,19 @@ class CollisionsOverlap {
2660
2704
  }
2661
2705
  }
2662
2706
  }
2663
- ;// CONCATENATED MODULE: ./dist/browser/Options/Classes/AnimationOptions.js
2664
-
2665
- class AnimationOptions {
2666
- constructor() {
2667
- this.count = 0;
2668
- this.enable = false;
2669
- this.speed = 1;
2670
- this.decay = 0;
2671
- this.delay = 0;
2672
- this.sync = false;
2673
- }
2674
- load(data) {
2675
- if (!data) {
2676
- return;
2677
- }
2678
- if (data.count !== undefined) {
2679
- this.count = setRangeValue(data.count);
2680
- }
2681
- if (data.enable !== undefined) {
2682
- this.enable = data.enable;
2683
- }
2684
- if (data.speed !== undefined) {
2685
- this.speed = setRangeValue(data.speed);
2686
- }
2687
- if (data.decay !== undefined) {
2688
- this.decay = setRangeValue(data.decay);
2689
- }
2690
- if (data.delay !== undefined) {
2691
- this.delay = setRangeValue(data.delay);
2692
- }
2693
- if (data.sync !== undefined) {
2694
- this.sync = data.sync;
2695
- }
2696
- }
2697
- }
2698
- class RangedAnimationOptions extends AnimationOptions {
2699
- constructor() {
2700
- super();
2701
- this.mode = "auto";
2702
- this.startValue = "random";
2703
- }
2704
- load(data) {
2705
- super.load(data);
2706
- if (!data) {
2707
- return;
2708
- }
2709
- if (data.mode !== undefined) {
2710
- this.mode = data.mode;
2711
- }
2712
- if (data.startValue !== undefined) {
2713
- this.startValue = data.startValue;
2714
- }
2715
- }
2716
- }
2717
- ;// CONCATENATED MODULE: ./dist/browser/Options/Classes/Random.js
2718
- class Random {
2719
- constructor() {
2720
- this.enable = false;
2721
- this.minimumValue = 0;
2722
- }
2723
- load(data) {
2724
- if (!data) {
2725
- return;
2726
- }
2727
- if (data.enable !== undefined) {
2728
- this.enable = data.enable;
2729
- }
2730
- if (data.minimumValue !== undefined) {
2731
- this.minimumValue = data.minimumValue;
2732
- }
2733
- }
2734
- }
2735
2707
  ;// CONCATENATED MODULE: ./dist/browser/Options/Classes/ValueWithRandom.js
2736
2708
 
2737
2709
 
2738
-
2739
-
2740
2710
  class ValueWithRandom {
2741
2711
  constructor() {
2742
- this.random = new Random();
2743
2712
  this.value = 0;
2744
2713
  }
2745
2714
  load(data) {
2746
2715
  if (!data) {
2747
2716
  return;
2748
2717
  }
2749
- if (isBoolean(data.random)) {
2750
- this.random.enable = data.random;
2751
- } else {
2752
- this.random.load(data.random);
2753
- }
2754
2718
  if (data.value !== undefined) {
2755
- this.value = setRangeValue(data.value, this.random.enable ? this.random.minimumValue : undefined);
2719
+ this.value = setRangeValue(data.value);
2756
2720
  }
2757
2721
  }
2758
2722
  }
@@ -2786,7 +2750,6 @@ class RangedAnimationValueWithRandom extends AnimationValueWithRandom {
2786
2750
  class ParticlesBounceFactor extends ValueWithRandom {
2787
2751
  constructor() {
2788
2752
  super();
2789
- this.random.minimumValue = 0.1;
2790
2753
  this.value = 1;
2791
2754
  }
2792
2755
  }
@@ -2837,6 +2800,39 @@ class Collisions {
2837
2800
  this.overlap.load(data.overlap);
2838
2801
  }
2839
2802
  }
2803
+ ;// CONCATENATED MODULE: ./dist/browser/Options/Classes/Particles/Effect/Effect.js
2804
+
2805
+ class Effect {
2806
+ constructor() {
2807
+ this.close = true;
2808
+ this.fill = true;
2809
+ this.options = {};
2810
+ this.type = [];
2811
+ }
2812
+ load(data) {
2813
+ if (!data) {
2814
+ return;
2815
+ }
2816
+ const options = data.options;
2817
+ if (options !== undefined) {
2818
+ for (const effect in options) {
2819
+ const item = options[effect];
2820
+ if (item) {
2821
+ this.options[effect] = deepExtend(this.options[effect] ?? {}, item);
2822
+ }
2823
+ }
2824
+ }
2825
+ if (data.close !== undefined) {
2826
+ this.close = data.close;
2827
+ }
2828
+ if (data.fill !== undefined) {
2829
+ this.fill = data.fill;
2830
+ }
2831
+ if (data.type !== undefined) {
2832
+ this.type = data.type;
2833
+ }
2834
+ }
2835
+ }
2840
2836
  ;// CONCATENATED MODULE: ./dist/browser/Options/Classes/Particles/Move/MoveAngle.js
2841
2837
 
2842
2838
  class MoveAngle {
@@ -3165,11 +3161,10 @@ class OpacityAnimation extends RangedAnimationOptions {
3165
3161
  ;// CONCATENATED MODULE: ./dist/browser/Options/Classes/Particles/Opacity/Opacity.js
3166
3162
 
3167
3163
 
3168
- class Opacity extends ValueWithRandom {
3164
+ class Opacity extends RangedAnimationValueWithRandom {
3169
3165
  constructor() {
3170
3166
  super();
3171
3167
  this.animation = new OpacityAnimation();
3172
- this.random.minimumValue = 0.1;
3173
3168
  this.value = 1;
3174
3169
  }
3175
3170
  load(data) {
@@ -3207,12 +3202,31 @@ class ParticlesDensity {
3207
3202
  }
3208
3203
  }
3209
3204
  }
3205
+ ;// CONCATENATED MODULE: ./dist/browser/Options/Classes/Particles/Number/ParticlesNumberLimit.js
3206
+ class ParticlesNumberLimit {
3207
+ constructor() {
3208
+ this.mode = "delete";
3209
+ this.value = 0;
3210
+ }
3211
+ load(data) {
3212
+ if (!data) {
3213
+ return;
3214
+ }
3215
+ if (data.mode !== undefined) {
3216
+ this.mode = data.mode;
3217
+ }
3218
+ if (data.value !== undefined) {
3219
+ this.value = data.value;
3220
+ }
3221
+ }
3222
+ }
3210
3223
  ;// CONCATENATED MODULE: ./dist/browser/Options/Classes/Particles/Number/ParticlesNumber.js
3211
3224
 
3225
+
3212
3226
  class ParticlesNumber {
3213
3227
  constructor() {
3214
3228
  this.density = new ParticlesDensity();
3215
- this.limit = 0;
3229
+ this.limit = new ParticlesNumberLimit();
3216
3230
  this.value = 0;
3217
3231
  }
3218
3232
  load(data) {
@@ -3220,10 +3234,7 @@ class ParticlesNumber {
3220
3234
  return;
3221
3235
  }
3222
3236
  this.density.load(data.density);
3223
- const limit = data.limit;
3224
- if (limit !== undefined) {
3225
- this.limit = limit;
3226
- }
3237
+ this.limit.load(data.limit);
3227
3238
  if (data.value !== undefined) {
3228
3239
  this.value = data.value;
3229
3240
  }
@@ -3318,11 +3329,10 @@ class SizeAnimation extends RangedAnimationOptions {
3318
3329
  ;// CONCATENATED MODULE: ./dist/browser/Options/Classes/Particles/Size/Size.js
3319
3330
 
3320
3331
 
3321
- class Size extends ValueWithRandom {
3332
+ class Size extends RangedAnimationValueWithRandom {
3322
3333
  constructor() {
3323
3334
  super();
3324
3335
  this.animation = new SizeAnimation();
3325
- this.random.minimumValue = 1;
3326
3336
  this.value = 3;
3327
3337
  }
3328
3338
  load(data) {
@@ -3396,6 +3406,7 @@ class ZIndex extends ValueWithRandom {
3396
3406
 
3397
3407
 
3398
3408
 
3409
+
3399
3410
  class ParticlesOptions {
3400
3411
  constructor(engine, container) {
3401
3412
  this._engine = engine;
@@ -3404,6 +3415,7 @@ class ParticlesOptions {
3404
3415
  this.collisions = new Collisions();
3405
3416
  this.color = new AnimatableColor();
3406
3417
  this.color.value = "#fff";
3418
+ this.effect = new Effect();
3407
3419
  this.groups = {};
3408
3420
  this.move = new Move();
3409
3421
  this.number = new ParticlesNumber();
@@ -3421,6 +3433,7 @@ class ParticlesOptions {
3421
3433
  }
3422
3434
  this.bounce.load(data.bounce);
3423
3435
  this.color.load(AnimatableColor.create(this.color, data.color));
3436
+ this.effect.load(data.effect);
3424
3437
  if (data.groups !== undefined) {
3425
3438
  for (const group in data.groups) {
3426
3439
  const item = data.groups[group];
@@ -3693,6 +3706,16 @@ class InteractionManager {
3693
3706
 
3694
3707
 
3695
3708
 
3709
+ function loadEffectData(effect, effectOptions, id, reduceDuplicates) {
3710
+ const effectData = effectOptions.options[effect];
3711
+ if (!effectData) {
3712
+ return;
3713
+ }
3714
+ return deepExtend({
3715
+ close: effectOptions.close,
3716
+ fill: effectOptions.fill
3717
+ }, itemFromSingleOrMultiple(effectData, id, reduceDuplicates));
3718
+ }
3696
3719
  function loadShapeData(shape, shapeOptions, id, reduceDuplicates) {
3697
3720
  const shapeData = shapeOptions.options[shape];
3698
3721
  if (!shapeData) {
@@ -3771,8 +3794,8 @@ class Particle {
3771
3794
  const rad = Math.PI / 180 * getRangeValue(moveOptions.angle.value),
3772
3795
  radOffset = Math.PI / 180 * getRangeValue(moveOptions.angle.offset),
3773
3796
  range = {
3774
- left: radOffset - rad / 2,
3775
- right: radOffset + rad / 2
3797
+ left: radOffset - rad * 0.5,
3798
+ right: radOffset + rad * 0.5
3776
3799
  };
3777
3800
  if (!moveOptions.straight) {
3778
3801
  res.angle += randomInRange(setRangeValue(range.left, range.right));
@@ -3803,7 +3826,7 @@ class Particle {
3803
3826
  return color;
3804
3827
  }
3805
3828
  const backFactor = this.roll.horizontal && this.roll.vertical ? 2 : 1,
3806
- backSum = this.roll.horizontal ? Math.PI / 2 : 0,
3829
+ backSum = this.roll.horizontal ? Math.PI * 0.5 : 0,
3807
3830
  rolled = Math.floor(((this.roll.angle ?? 0) + backSum) / (Math.PI / backFactor)) % 2;
3808
3831
  if (!rolled) {
3809
3832
  return color;
@@ -3851,18 +3874,12 @@ class Particle {
3851
3874
  const container = this.container,
3852
3875
  pathGenerator = this.pathGenerator;
3853
3876
  for (const [, plugin] of container.plugins) {
3854
- if (plugin.particleDestroyed) {
3855
- plugin.particleDestroyed(this, override);
3856
- }
3877
+ plugin.particleDestroyed && plugin.particleDestroyed(this, override);
3857
3878
  }
3858
3879
  for (const updater of container.particles.updaters) {
3859
- if (updater.particleDestroyed) {
3860
- updater.particleDestroyed(this, override);
3861
- }
3862
- }
3863
- if (pathGenerator) {
3864
- pathGenerator.reset(this);
3880
+ updater.particleDestroyed && updater.particleDestroyed(this, override);
3865
3881
  }
3882
+ pathGenerator && pathGenerator.reset(this);
3866
3883
  }
3867
3884
  draw(delta) {
3868
3885
  const container = this.container,
@@ -3876,7 +3893,7 @@ class Particle {
3876
3893
  return this._getRollColor(this.bubble.color ?? getHslFromAnimation(this.color));
3877
3894
  }
3878
3895
  getMass() {
3879
- return this.getRadius() ** 2 * Math.PI / 2;
3896
+ return this.getRadius() ** 2 * Math.PI * 0.5;
3880
3897
  }
3881
3898
  getPosition() {
3882
3899
  return {
@@ -3896,9 +3913,11 @@ class Particle {
3896
3913
  engine = this._engine;
3897
3914
  this.id = id;
3898
3915
  this.group = group;
3899
- this.fill = true;
3916
+ this.effectClose = true;
3917
+ this.effectFill = true;
3918
+ this.shapeClose = true;
3919
+ this.shapeFill = true;
3900
3920
  this.pathRotation = false;
3901
- this.close = true;
3902
3921
  this.lastPathTime = 0;
3903
3922
  this.destroyed = false;
3904
3923
  this.unbreakable = false;
@@ -3912,22 +3931,40 @@ class Particle {
3912
3931
  const pxRatio = container.retina.pixelRatio,
3913
3932
  mainOptions = container.actualOptions,
3914
3933
  particlesOptions = loadParticlesOptions(this._engine, container, mainOptions.particles),
3934
+ effectType = particlesOptions.effect.type,
3915
3935
  shapeType = particlesOptions.shape.type,
3916
3936
  {
3917
3937
  reduceDuplicates
3918
3938
  } = particlesOptions;
3939
+ this.effect = itemFromSingleOrMultiple(effectType, this.id, reduceDuplicates);
3919
3940
  this.shape = itemFromSingleOrMultiple(shapeType, this.id, reduceDuplicates);
3920
- const shapeOptions = particlesOptions.shape;
3921
- if (overrideOptions && overrideOptions.shape && overrideOptions.shape.type) {
3922
- const overrideShapeType = overrideOptions.shape.type,
3923
- shape = itemFromSingleOrMultiple(overrideShapeType, this.id, reduceDuplicates);
3924
- if (shape) {
3925
- this.shape = shape;
3926
- shapeOptions.load(overrideOptions.shape);
3941
+ const effectOptions = particlesOptions.effect,
3942
+ shapeOptions = particlesOptions.shape;
3943
+ if (overrideOptions) {
3944
+ if (overrideOptions.effect && overrideOptions.effect.type) {
3945
+ const overrideEffectType = overrideOptions.effect.type,
3946
+ effect = itemFromSingleOrMultiple(overrideEffectType, this.id, reduceDuplicates);
3947
+ if (effect) {
3948
+ this.effect = effect;
3949
+ effectOptions.load(overrideOptions.effect);
3950
+ }
3951
+ }
3952
+ if (overrideOptions.shape && overrideOptions.shape.type) {
3953
+ const overrideShapeType = overrideOptions.shape.type,
3954
+ shape = itemFromSingleOrMultiple(overrideShapeType, this.id, reduceDuplicates);
3955
+ if (shape) {
3956
+ this.shape = shape;
3957
+ shapeOptions.load(overrideOptions.shape);
3958
+ }
3927
3959
  }
3928
3960
  }
3961
+ this.effectData = loadEffectData(this.effect, effectOptions, this.id, reduceDuplicates);
3929
3962
  this.shapeData = loadShapeData(this.shape, shapeOptions, this.id, reduceDuplicates);
3930
3963
  particlesOptions.load(overrideOptions);
3964
+ const effectData = this.effectData;
3965
+ if (effectData) {
3966
+ particlesOptions.load(effectData.particles);
3967
+ }
3931
3968
  const shapeData = this.shapeData;
3932
3969
  if (shapeData) {
3933
3970
  particlesOptions.load(shapeData.particles);
@@ -3936,11 +3973,13 @@ class Particle {
3936
3973
  interactivity.load(container.actualOptions.interactivity);
3937
3974
  interactivity.load(particlesOptions.interactivity);
3938
3975
  this.interactivity = interactivity;
3939
- this.fill = shapeData?.fill ?? particlesOptions.shape.fill;
3940
- this.close = shapeData?.close ?? particlesOptions.shape.close;
3976
+ this.effectFill = effectData?.fill ?? particlesOptions.effect.fill;
3977
+ this.effectClose = effectData?.close ?? particlesOptions.effect.close;
3978
+ this.shapeFill = shapeData?.fill ?? particlesOptions.shape.fill;
3979
+ this.shapeClose = shapeData?.close ?? particlesOptions.shape.close;
3941
3980
  this.options = particlesOptions;
3942
3981
  const pathOptions = this.options.move.path;
3943
- this.pathDelay = getValue(pathOptions.delay) * 1000;
3982
+ this.pathDelay = getRangeValue(pathOptions.delay.value) * 1000;
3944
3983
  if (pathOptions.generator) {
3945
3984
  this.pathGenerator = this._engine.getPathGenerator(pathOptions.generator);
3946
3985
  if (this.pathGenerator && container.addPath(pathOptions.generator, this.pathGenerator)) {
@@ -3961,34 +4000,46 @@ class Particle {
3961
4000
  this.velocity = this.initialVelocity.copy();
3962
4001
  this.moveDecay = 1 - getRangeValue(this.options.move.decay);
3963
4002
  const particles = container.particles;
3964
- particles.needsSort = particles.needsSort || particles.lastZIndex < this.position.z;
3965
- particles.lastZIndex = this.position.z;
4003
+ particles.setLastZIndex(this.position.z);
3966
4004
  this.zIndexFactor = this.position.z / container.zLayers;
3967
4005
  this.sides = 24;
3968
- let drawer = container.drawers.get(this.shape);
3969
- if (!drawer) {
3970
- drawer = this._engine.getShapeDrawer(this.shape);
3971
- if (drawer) {
3972
- container.drawers.set(this.shape, drawer);
4006
+ let effectDrawer = container.effectDrawers.get(this.effect);
4007
+ if (!effectDrawer) {
4008
+ effectDrawer = this._engine.getEffectDrawer(this.effect);
4009
+ if (effectDrawer) {
4010
+ container.effectDrawers.set(this.effect, effectDrawer);
4011
+ }
4012
+ }
4013
+ if (effectDrawer && effectDrawer.loadEffect) {
4014
+ effectDrawer.loadEffect(this);
4015
+ }
4016
+ let shapeDrawer = container.shapeDrawers.get(this.shape);
4017
+ if (!shapeDrawer) {
4018
+ shapeDrawer = this._engine.getShapeDrawer(this.shape);
4019
+ if (shapeDrawer) {
4020
+ container.shapeDrawers.set(this.shape, shapeDrawer);
3973
4021
  }
3974
4022
  }
3975
- if (drawer && drawer.loadShape) {
3976
- drawer.loadShape(this);
4023
+ if (shapeDrawer && shapeDrawer.loadShape) {
4024
+ shapeDrawer.loadShape(this);
3977
4025
  }
3978
- const sideCountFunc = drawer?.getSidesCount;
4026
+ const sideCountFunc = shapeDrawer?.getSidesCount;
3979
4027
  if (sideCountFunc) {
3980
4028
  this.sides = sideCountFunc(this);
3981
4029
  }
3982
4030
  this.spawning = false;
3983
4031
  this.shadowColor = rangeColorToRgb(this.options.shadow.color);
3984
- for (const updater of container.particles.updaters) {
4032
+ for (const updater of particles.updaters) {
3985
4033
  updater.init(this);
3986
4034
  }
3987
- for (const mover of container.particles.movers) {
4035
+ for (const mover of particles.movers) {
3988
4036
  mover.init && mover.init(this);
3989
4037
  }
3990
- if (drawer && drawer.particleInit) {
3991
- drawer.particleInit(container, this);
4038
+ if (effectDrawer && effectDrawer.particleInit) {
4039
+ effectDrawer.particleInit(container, this);
4040
+ }
4041
+ if (shapeDrawer && shapeDrawer.particleInit) {
4042
+ shapeDrawer.particleInit(container, this);
3992
4043
  }
3993
4044
  for (const [, plugin] of container.plugins) {
3994
4045
  plugin.particleCreated && plugin.particleCreated(this);
@@ -4115,7 +4166,7 @@ class QuadTree {
4115
4166
  capacity
4116
4167
  } = this;
4117
4168
  for (let i = 0; i < 4; i++) {
4118
- this._subs.push(new QuadTree(new Rectangle(x + width / 2 * (i % 2), y + height / 2 * (Math.round(i / 2) - i % 2), width / 2, height / 2), capacity));
4169
+ this._subs.push(new QuadTree(new Rectangle(x + width * 0.5 * (i % 2), y + height * 0.5 * (Math.round(i * 0.5) - i % 2), width * 0.5, height * 0.5), capacity));
4119
4170
  }
4120
4171
  this._divided = true;
4121
4172
  };
@@ -4171,21 +4222,36 @@ class QuadTree {
4171
4222
 
4172
4223
  const qTreeCapacity = 4;
4173
4224
  const qTreeRectangle = canvasSize => {
4174
- return new Rectangle(-canvasSize.width / 4, -canvasSize.height / 4, canvasSize.width * 3 / 2, canvasSize.height * 3 / 2);
4225
+ const {
4226
+ height,
4227
+ width
4228
+ } = canvasSize,
4229
+ posOffset = -0.25,
4230
+ sizeFactor = 1.5;
4231
+ return new Rectangle(posOffset * width, posOffset * height, sizeFactor * width, sizeFactor * height);
4175
4232
  };
4176
4233
  class Particles {
4177
4234
  constructor(engine, container) {
4178
4235
  this._applyDensity = (options, manualCount, group) => {
4236
+ const numberOptions = options.number;
4179
4237
  if (!options.number.density?.enable) {
4238
+ if (group === undefined) {
4239
+ this._limit = numberOptions.limit.value;
4240
+ } else {
4241
+ this._groupLimits.set(group, numberOptions.limit.value);
4242
+ }
4180
4243
  return;
4181
4244
  }
4182
- const numberOptions = options.number,
4183
- densityFactor = this._initDensityFactor(numberOptions.density),
4245
+ const densityFactor = this._initDensityFactor(numberOptions.density),
4184
4246
  optParticlesNumber = numberOptions.value,
4185
- optParticlesLimit = numberOptions.limit > 0 ? numberOptions.limit : optParticlesNumber,
4247
+ optParticlesLimit = numberOptions.limit.value > 0 ? numberOptions.limit.value : optParticlesNumber,
4186
4248
  particlesNumber = Math.min(optParticlesNumber, optParticlesLimit) * densityFactor + manualCount,
4187
4249
  particlesCount = Math.min(this.count, this.filter(t => t.group === group).length);
4188
- this.limit = numberOptions.limit * densityFactor;
4250
+ if (group === undefined) {
4251
+ this._limit = numberOptions.limit.value * densityFactor;
4252
+ } else {
4253
+ this._groupLimits.set(group, numberOptions.limit.value * densityFactor);
4254
+ }
4189
4255
  if (particlesCount < particlesNumber) {
4190
4256
  this.push(Math.abs(particlesNumber - particlesCount), undefined, options, group);
4191
4257
  } else if (particlesCount > particlesNumber) {
@@ -4203,7 +4269,7 @@ class Particles {
4203
4269
  };
4204
4270
  this._pushParticle = (position, overrideOptions, group, initializer) => {
4205
4271
  try {
4206
- let particle = this.pool.pop();
4272
+ let particle = this._pool.pop();
4207
4273
  if (particle) {
4208
4274
  particle.init(this._nextId, position, overrideOptions, group);
4209
4275
  } else {
@@ -4240,7 +4306,7 @@ class Particles {
4240
4306
  const zIdx = this._zArray.indexOf(particle);
4241
4307
  this._array.splice(index, 1);
4242
4308
  this._zArray.splice(zIdx, 1);
4243
- this.pool.push(particle);
4309
+ this._pool.push(particle);
4244
4310
  this._engine.dispatchEvent("particleRemoved", {
4245
4311
  container: this._container,
4246
4312
  data: {
@@ -4254,10 +4320,11 @@ class Particles {
4254
4320
  this._nextId = 0;
4255
4321
  this._array = [];
4256
4322
  this._zArray = [];
4257
- this.pool = [];
4258
- this.limit = 0;
4259
- this.needsSort = false;
4260
- this.lastZIndex = 0;
4323
+ this._pool = [];
4324
+ this._limit = 0;
4325
+ this._groupLimits = new Map();
4326
+ this._needsSort = false;
4327
+ this._lastZIndex = 0;
4261
4328
  this._interactionManager = new InteractionManager(engine, container);
4262
4329
  const canvasSize = container.canvas.size;
4263
4330
  this.quadTree = new QuadTree(qTreeRectangle(canvasSize), qTreeCapacity);
@@ -4275,19 +4342,22 @@ class Particles {
4275
4342
  }
4276
4343
  }
4277
4344
  addParticle(position, overrideOptions, group, initializer) {
4278
- this.pushing = true;
4279
- const container = this._container,
4280
- options = container.actualOptions,
4281
- limit = options.particles.number.limit;
4345
+ const limitOptions = this._container.actualOptions.particles.number.limit,
4346
+ limit = group === undefined ? this._limit : this._groupLimits.get(group) ?? this._limit,
4347
+ currentCount = this.count;
4282
4348
  if (limit > 0) {
4283
- const countToRemove = this.count + 1 - limit;
4284
- if (countToRemove > 0) {
4285
- this.removeQuantity(countToRemove);
4349
+ if (limitOptions.mode === "delete") {
4350
+ const countToRemove = currentCount + 1 - limit;
4351
+ if (countToRemove > 0) {
4352
+ this.removeQuantity(countToRemove);
4353
+ }
4354
+ } else if (limitOptions.mode === "wait") {
4355
+ if (currentCount >= limit) {
4356
+ return;
4357
+ }
4286
4358
  }
4287
4359
  }
4288
- const res = this._pushParticle(position, overrideOptions, group, initializer);
4289
- this.pushing = false;
4290
- return res;
4360
+ return this._pushParticle(position, overrideOptions, group, initializer);
4291
4361
  }
4292
4362
  clear() {
4293
4363
  this._array = [];
@@ -4326,8 +4396,8 @@ class Particles {
4326
4396
  init() {
4327
4397
  const container = this._container,
4328
4398
  options = container.actualOptions;
4329
- this.lastZIndex = 0;
4330
- this.needsSort = false;
4399
+ this._lastZIndex = 0;
4400
+ this._needsSort = false;
4331
4401
  let handled = false;
4332
4402
  this.updaters = this._engine.getUpdaters(container, true);
4333
4403
  this._interactionManager.init();
@@ -4394,6 +4464,13 @@ class Particles {
4394
4464
  }
4395
4465
  this._applyDensity(options.particles, options.manualParticles.length);
4396
4466
  }
4467
+ setLastZIndex(zIndex) {
4468
+ this._lastZIndex = zIndex;
4469
+ this._needsSort = this._needsSort || this._lastZIndex < zIndex;
4470
+ }
4471
+ setResizeFactor(factor) {
4472
+ this._resizeFactor = factor;
4473
+ }
4397
4474
  async update(delta) {
4398
4475
  const container = this._container,
4399
4476
  particlesToDelete = new Set();
@@ -4402,10 +4479,10 @@ class Particles {
4402
4479
  pathGenerator.update();
4403
4480
  }
4404
4481
  for (const [, plugin] of container.plugins) {
4405
- plugin.update && plugin.update(delta);
4482
+ plugin.update && (await plugin.update(delta));
4406
4483
  }
4484
+ const resizeFactor = this._resizeFactor;
4407
4485
  for (const particle of this._array) {
4408
- const resizeFactor = container.canvas.resizeFactor;
4409
4486
  if (resizeFactor && !particle.ignoresResizeRatio) {
4410
4487
  particle.position.x *= resizeFactor.width;
4411
4488
  particle.position.y *= resizeFactor.height;
@@ -4433,7 +4510,7 @@ class Particles {
4433
4510
  const checkDelete = p => !particlesToDelete.has(p);
4434
4511
  this._array = this.filter(checkDelete);
4435
4512
  this._zArray = this._zArray.filter(checkDelete);
4436
- this.pool.push(...particlesToDelete);
4513
+ this._pool.push(...particlesToDelete);
4437
4514
  }
4438
4515
  await this._interactionManager.externalInteract(delta);
4439
4516
  for (const particle of this._array) {
@@ -4444,12 +4521,12 @@ class Particles {
4444
4521
  await this._interactionManager.particlesInteract(particle, delta);
4445
4522
  }
4446
4523
  }
4447
- delete container.canvas.resizeFactor;
4448
- if (this.needsSort) {
4524
+ delete this._resizeFactor;
4525
+ if (this._needsSort) {
4449
4526
  const zArray = this._zArray;
4450
4527
  zArray.sort((a, b) => b.position.z - a.position.z || a.id - b.id);
4451
- this.lastZIndex = zArray[zArray.length - 1].position.z;
4452
- this.needsSort = false;
4528
+ this._lastZIndex = zArray[zArray.length - 1].position.z;
4529
+ this._needsSort = false;
4453
4530
  }
4454
4531
  }
4455
4532
  }
@@ -4476,7 +4553,6 @@ class Retina {
4476
4553
  }
4477
4554
  const particles = options.particles,
4478
4555
  moveOptions = particles.move;
4479
- this.attractDistance = getRangeValue(moveOptions.attract.distance) * ratio;
4480
4556
  this.maxSpeed = getRangeValue(moveOptions.gravity.maxSpeed) * ratio;
4481
4557
  this.sizeAnimationSpeed = getRangeValue(particles.size.animation.speed) * ratio;
4482
4558
  }
@@ -4486,7 +4562,6 @@ class Retina {
4486
4562
  moveOptions = options.move,
4487
4563
  moveDistance = moveOptions.distance,
4488
4564
  props = particle.retina;
4489
- props.attractDistance = getRangeValue(moveOptions.attract.distance) * ratio;
4490
4565
  props.moveDrift = getRangeValue(moveOptions.drift) * ratio;
4491
4566
  props.moveSpeed = getRangeValue(moveOptions.speed) * ratio;
4492
4567
  props.sizeAnimationSpeed = getRangeValue(options.size.animation.speed) * ratio;
@@ -4535,14 +4610,14 @@ class Container {
4535
4610
  };
4536
4611
  this._nextFrame = async timestamp => {
4537
4612
  try {
4538
- if (!this.smooth && this.lastFrameTime !== undefined && timestamp < this.lastFrameTime + 1000 / this.fpsLimit) {
4613
+ if (!this._smooth && this._lastFrameTime !== undefined && timestamp < this._lastFrameTime + 1000 / this.fpsLimit) {
4539
4614
  this.draw(false);
4540
4615
  return;
4541
4616
  }
4542
- this.lastFrameTime ??= timestamp;
4543
- const delta = initDelta(timestamp - this.lastFrameTime, this.fpsLimit, this.smooth);
4617
+ this._lastFrameTime ??= timestamp;
4618
+ const delta = initDelta(timestamp - this._lastFrameTime, this.fpsLimit, this._smooth);
4544
4619
  this.addLifeTime(delta.value);
4545
- this.lastFrameTime = timestamp;
4620
+ this._lastFrameTime = timestamp;
4546
4621
  if (delta.value > 1000) {
4547
4622
  this.draw(false);
4548
4623
  return;
@@ -4562,7 +4637,7 @@ class Container {
4562
4637
  this._engine = engine;
4563
4638
  this.id = Symbol(id);
4564
4639
  this.fpsLimit = 120;
4565
- this.smooth = false;
4640
+ this._smooth = false;
4566
4641
  this._delay = 0;
4567
4642
  this._duration = 0;
4568
4643
  this._lifeTime = 0;
@@ -4570,7 +4645,7 @@ class Container {
4570
4645
  this.started = false;
4571
4646
  this.destroyed = false;
4572
4647
  this._paused = true;
4573
- this.lastFrameTime = 0;
4648
+ this._lastFrameTime = 0;
4574
4649
  this.zLayers = 100;
4575
4650
  this.pageHidden = false;
4576
4651
  this._sourceOptions = sourceOptions;
@@ -4586,7 +4661,8 @@ class Container {
4586
4661
  }
4587
4662
  };
4588
4663
  this.plugins = new Map();
4589
- this.drawers = new Map();
4664
+ this.effectDrawers = new Map();
4665
+ this.shapeDrawers = new Map();
4590
4666
  this._options = loadContainerOptions(this._engine, this);
4591
4667
  this.actualOptions = loadContainerOptions(this._engine, this);
4592
4668
  this._eventListeners = new EventListeners(this);
@@ -4704,11 +4780,17 @@ class Container {
4704
4780
  this.stop();
4705
4781
  this.particles.destroy();
4706
4782
  this.canvas.destroy();
4707
- for (const [, drawer] of this.drawers) {
4708
- drawer.destroy && drawer.destroy(this);
4783
+ for (const [, effectDrawer] of this.effectDrawers) {
4784
+ effectDrawer.destroy && effectDrawer.destroy(this);
4785
+ }
4786
+ for (const [, shapeDrawer] of this.shapeDrawers) {
4787
+ shapeDrawer.destroy && shapeDrawer.destroy(this);
4709
4788
  }
4710
- for (const key of this.drawers.keys()) {
4711
- this.drawers.delete(key);
4789
+ for (const key of this.effectDrawers.keys()) {
4790
+ this.effectDrawers.delete(key);
4791
+ }
4792
+ for (const key of this.shapeDrawers.keys()) {
4793
+ this.shapeDrawers.delete(key);
4712
4794
  }
4713
4795
  this._engine.clearPlugins(this);
4714
4796
  this.destroyed = true;
@@ -4728,7 +4810,7 @@ class Container {
4728
4810
  let refreshTime = force;
4729
4811
  this._drawAnimationFrame = requestAnimationFrame(async timestamp => {
4730
4812
  if (refreshTime) {
4731
- this.lastFrameTime = undefined;
4813
+ this._lastFrameTime = undefined;
4732
4814
  refreshTime = false;
4733
4815
  }
4734
4816
  await this._nextFrame(timestamp);
@@ -4763,11 +4845,18 @@ class Container {
4763
4845
  if (!guardCheck(this)) {
4764
4846
  return;
4765
4847
  }
4848
+ const effects = this._engine.getSupportedEffects();
4849
+ for (const type of effects) {
4850
+ const drawer = this._engine.getEffectDrawer(type);
4851
+ if (drawer) {
4852
+ this.effectDrawers.set(type, drawer);
4853
+ }
4854
+ }
4766
4855
  const shapes = this._engine.getSupportedShapes();
4767
4856
  for (const type of shapes) {
4768
4857
  const drawer = this._engine.getShapeDrawer(type);
4769
4858
  if (drawer) {
4770
- this.drawers.set(type, drawer);
4859
+ this.shapeDrawers.set(type, drawer);
4771
4860
  }
4772
4861
  }
4773
4862
  this._options = loadContainerOptions(this._engine, this, this._initialSourceOptions, this.sourceOptions);
@@ -4786,8 +4875,11 @@ class Container {
4786
4875
  this._delay = getRangeValue(this.actualOptions.delay) * 1000;
4787
4876
  this._lifeTime = 0;
4788
4877
  this.fpsLimit = this.actualOptions.fpsLimit > 0 ? this.actualOptions.fpsLimit : 120;
4789
- this.smooth = this.actualOptions.smooth;
4790
- for (const [, drawer] of this.drawers) {
4878
+ this._smooth = this.actualOptions.smooth;
4879
+ for (const [, drawer] of this.effectDrawers) {
4880
+ drawer.init && (await drawer.init(this));
4881
+ }
4882
+ for (const [, drawer] of this.shapeDrawers) {
4791
4883
  drawer.init && (await drawer.init(this));
4792
4884
  }
4793
4885
  for (const [, plugin] of this.plugins) {
@@ -4928,10 +5020,10 @@ class Container {
4928
5020
  this.actualOptions.responsive = [];
4929
5021
  const newMaxWidth = this.actualOptions.setResponsive(this.canvas.size.width, this.retina.pixelRatio, this._options);
4930
5022
  this.actualOptions.setTheme(this._currentTheme);
4931
- if (this.responsiveMaxWidth === newMaxWidth) {
5023
+ if (this._responsiveMaxWidth === newMaxWidth) {
4932
5024
  return false;
4933
5025
  }
4934
- this.responsiveMaxWidth = newMaxWidth;
5026
+ this._responsiveMaxWidth = newMaxWidth;
4935
5027
  return true;
4936
5028
  }
4937
5029
  }
@@ -5022,7 +5114,8 @@ class Engine {
5022
5114
  this.movers = new Map();
5023
5115
  this.updaters = new Map();
5024
5116
  this.presets = new Map();
5025
- this.drawers = new Map();
5117
+ this.effectDrawers = new Map();
5118
+ this.shapeDrawers = new Map();
5026
5119
  this.pathGenerators = new Map();
5027
5120
  }
5028
5121
  get configs() {
@@ -5033,7 +5126,7 @@ class Engine {
5033
5126
  return res;
5034
5127
  }
5035
5128
  get version() {
5036
- return "3.0.0-beta.3";
5129
+ return "3.0.0-beta.4";
5037
5130
  }
5038
5131
  addConfig(config) {
5039
5132
  const name = config.name ?? "default";
@@ -5045,6 +5138,12 @@ class Engine {
5045
5138
  }
5046
5139
  });
5047
5140
  }
5141
+ async addEffect(effect, drawer, refresh = true) {
5142
+ executeOnSingleOrMultiple(effect, type => {
5143
+ !this.getEffectDrawer(type) && this.effectDrawers.set(type, drawer);
5144
+ });
5145
+ await this.refresh(refresh);
5146
+ }
5048
5147
  addEventListener(type, listener) {
5049
5148
  this._eventDispatcher.addEventListener(type, listener);
5050
5149
  }
@@ -5074,7 +5173,7 @@ class Engine {
5074
5173
  }
5075
5174
  async addShape(shape, drawer, refresh = true) {
5076
5175
  executeOnSingleOrMultiple(shape, type => {
5077
- !this.getShapeDrawer(type) && this.drawers.set(type, drawer);
5176
+ !this.getShapeDrawer(type) && this.shapeDrawers.set(type, drawer);
5078
5177
  });
5079
5178
  await this.refresh(refresh);
5080
5179
  }
@@ -5105,6 +5204,9 @@ class Engine {
5105
5204
  }
5106
5205
  return res;
5107
5206
  }
5207
+ getEffectDrawer(type) {
5208
+ return this.effectDrawers.get(type);
5209
+ }
5108
5210
  getInteractors(container, force = false) {
5109
5211
  return getItemsFromInitializer(container, this.interactors, this._initializers.interactors, force);
5110
5212
  }
@@ -5121,10 +5223,13 @@ class Engine {
5121
5223
  return this.presets.get(preset);
5122
5224
  }
5123
5225
  getShapeDrawer(type) {
5124
- return this.drawers.get(type);
5226
+ return this.shapeDrawers.get(type);
5227
+ }
5228
+ getSupportedEffects() {
5229
+ return this.effectDrawers.keys();
5125
5230
  }
5126
5231
  getSupportedShapes() {
5127
- return this.drawers.keys();
5232
+ return this.shapeDrawers.keys();
5128
5233
  }
5129
5234
  getUpdaters(container, force = false) {
5130
5235
  return getItemsFromInitializer(container, this.updaters, this._initializers.updaters, force);
@@ -5420,7 +5525,6 @@ class ParticlesInteractorBase {
5420
5525
 
5421
5526
 
5422
5527
 
5423
-
5424
5528
 
5425
5529
 
5426
5530
  ;// CONCATENATED MODULE: ./dist/browser/index.js