@tsparticles/slim 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.
@@ -4,7 +4,7 @@
4
4
  * Demo / Generator : https://particles.js.org/
5
5
  * GitHub : https://www.github.com/matteobruni/tsparticles
6
6
  * How to use? : Check the GitHub README
7
- * v3.0.0-beta.3
7
+ * v3.0.0-beta.4
8
8
  */
9
9
  (function webpackUniversalModuleDefinition(root, factory) {
10
10
  if(typeof exports === 'object' && typeof module === 'object')
@@ -97,6 +97,7 @@ __webpack_require__.d(__webpack_exports__, {
97
97
  ParticlesDensity: () => (/* reexport */ ParticlesDensity),
98
98
  ParticlesInteractorBase: () => (/* reexport */ ParticlesInteractorBase),
99
99
  ParticlesNumber: () => (/* reexport */ ParticlesNumber),
100
+ ParticlesNumberLimit: () => (/* reexport */ ParticlesNumberLimit),
100
101
  ParticlesOptions: () => (/* reexport */ ParticlesOptions),
101
102
  Point: () => (/* reexport */ Point),
102
103
  Range: () => (/* reexport */ Range),
@@ -140,13 +141,13 @@ __webpack_require__.d(__webpack_exports__, {
140
141
  deepExtend: () => (/* reexport */ deepExtend),
141
142
  divMode: () => (/* reexport */ divMode),
142
143
  divModeExecute: () => (/* reexport */ divModeExecute),
144
+ drawEffect: () => (/* reexport */ drawEffect),
143
145
  drawLine: () => (/* reexport */ drawLine),
144
146
  drawParticle: () => (/* reexport */ drawParticle),
145
147
  drawParticlePlugin: () => (/* reexport */ drawParticlePlugin),
146
148
  drawPlugin: () => (/* reexport */ drawPlugin),
147
149
  drawShape: () => (/* reexport */ drawShape),
148
- drawShapeAfterEffect: () => (/* reexport */ drawShapeAfterEffect),
149
- drawTriangle: () => (/* reexport */ drawTriangle),
150
+ drawShapeAfterDraw: () => (/* reexport */ drawShapeAfterDraw),
150
151
  errorPrefix: () => (/* reexport */ errorPrefix),
151
152
  executeOnSingleOrMultiple: () => (/* reexport */ executeOnSingleOrMultiple),
152
153
  findItemFromSingleOrMultiple: () => (/* reexport */ findItemFromSingleOrMultiple),
@@ -170,7 +171,6 @@ __webpack_require__.d(__webpack_exports__, {
170
171
  getSize: () => (/* reexport */ getSize),
171
172
  getStyleFromHsl: () => (/* reexport */ getStyleFromHsl),
172
173
  getStyleFromRgb: () => (/* reexport */ getStyleFromRgb),
173
- getValue: () => (/* reexport */ getValue),
174
174
  hasMatchMedia: () => (/* reexport */ hasMatchMedia),
175
175
  hslToRgb: () => (/* reexport */ hslToRgb),
176
176
  hslaToRgba: () => (/* reexport */ hslaToRgba),
@@ -410,17 +410,6 @@ function setRangeValue(source, value) {
410
410
  max: Math.max(max, value)
411
411
  } : setRangeValue(min, max);
412
412
  }
413
- function getValue(options) {
414
- const random = options.random,
415
- {
416
- enable,
417
- minimumValue
418
- } = isBoolean(random) ? {
419
- enable: random,
420
- minimumValue: 0
421
- } : random;
422
- return enable ? getRangeValue(setRangeValue(options.value, minimumValue)) : getRangeValue(options.value);
423
- }
424
413
  function getDistances(pointA, pointB) {
425
414
  const dx = pointA.x - pointB.x,
426
415
  dy = pointA.y - pointB.y;
@@ -439,21 +428,21 @@ function getParticleDirectionAngle(direction, position, center) {
439
428
  }
440
429
  switch (direction) {
441
430
  case "top":
442
- return -Math.PI / 2;
431
+ return -Math.PI * 0.5;
443
432
  case "top-right":
444
- return -Math.PI / 4;
433
+ return -Math.PI * 0.25;
445
434
  case "right":
446
435
  return 0;
447
436
  case "bottom-right":
448
- return Math.PI / 4;
437
+ return Math.PI * 0.25;
449
438
  case "bottom":
450
- return Math.PI / 2;
439
+ return Math.PI * 0.5;
451
440
  case "bottom-left":
452
- return 3 * Math.PI / 4;
441
+ return Math.PI * 0.75;
453
442
  case "left":
454
443
  return Math.PI;
455
444
  case "top-left":
456
- return -3 * Math.PI / 4;
445
+ return -Math.PI * 0.75;
457
446
  case "inside":
458
447
  return Math.atan2(center.y - position.y, center.x - position.x);
459
448
  case "outside":
@@ -549,7 +538,7 @@ function rectSideBounce(data) {
549
538
  if (pOtherSide.min < rectOtherSide.min || pOtherSide.min > rectOtherSide.max || pOtherSide.max < rectOtherSide.min || pOtherSide.max > rectOtherSide.max) {
550
539
  return res;
551
540
  }
552
- 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) {
541
+ 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) {
553
542
  res.velocity = velocity * -factor;
554
543
  res.bounced = true;
555
544
  }
@@ -685,7 +674,7 @@ function circleBounceDataFromParticle(p) {
685
674
  radius: p.getRadius(),
686
675
  mass: p.getMass(),
687
676
  velocity: p.velocity,
688
- factor: Vector.create(getValue(p.options.bounce.horizontal), getValue(p.options.bounce.vertical))
677
+ factor: Vector.create(getRangeValue(p.options.bounce.horizontal.value), getRangeValue(p.options.bounce.vertical.value))
689
678
  };
690
679
  }
691
680
  function circleBounce(p1, p2) {
@@ -719,6 +708,7 @@ function rectBounce(particle, divBounds) {
719
708
  const pPos = particle.getPosition(),
720
709
  size = particle.getRadius(),
721
710
  bounds = calculateBounds(pPos, size),
711
+ bounceOptions = particle.options.bounce,
722
712
  resH = rectSideBounce({
723
713
  pSide: {
724
714
  min: bounds.left,
@@ -737,7 +727,7 @@ function rectBounce(particle, divBounds) {
737
727
  max: divBounds.bottom
738
728
  },
739
729
  velocity: particle.velocity.x,
740
- factor: getValue(particle.options.bounce.horizontal)
730
+ factor: getRangeValue(bounceOptions.horizontal.value)
741
731
  });
742
732
  if (resH.bounced) {
743
733
  if (resH.velocity !== undefined) {
@@ -765,7 +755,7 @@ function rectBounce(particle, divBounds) {
765
755
  max: divBounds.right
766
756
  },
767
757
  velocity: particle.velocity.y,
768
- factor: getValue(particle.options.bounce.vertical)
758
+ factor: getRangeValue(bounceOptions.vertical.value)
769
759
  });
770
760
  if (resV.bounced) {
771
761
  if (resV.velocity !== undefined) {
@@ -892,24 +882,6 @@ const randomColorValue = "random",
892
882
  function addColorManager(manager) {
893
883
  colorManagers.set(manager.key, manager);
894
884
  }
895
- function hue2rgb(p, q, t) {
896
- if (t < 0) {
897
- t += 1;
898
- }
899
- if (t > 1) {
900
- t -= 1;
901
- }
902
- if (t < 1 / 6) {
903
- return p + (q - p) * 6 * t;
904
- }
905
- if (t < 1 / 2) {
906
- return q;
907
- }
908
- if (t < 2 / 3) {
909
- return p + (q - p) * (2 / 3 - t) * 6;
910
- }
911
- return p;
912
- }
913
885
  function stringToRgba(input) {
914
886
  for (const [, manager] of colorManagers) {
915
887
  if (input.startsWith(manager.stringPrefix)) {
@@ -989,7 +961,7 @@ function rgbToHsl(color) {
989
961
  min = Math.min(r1, g1, b1),
990
962
  res = {
991
963
  h: 0,
992
- l: (max + min) / 2,
964
+ l: (max + min) * 0.5,
993
965
  s: 0
994
966
  };
995
967
  if (max !== min) {
@@ -1014,29 +986,48 @@ function stringToRgb(input) {
1014
986
  return stringToRgba(input);
1015
987
  }
1016
988
  function hslToRgb(hsl) {
1017
- const result = {
1018
- b: 0,
1019
- g: 0,
1020
- r: 0
1021
- },
1022
- hslPercent = {
1023
- h: hsl.h / 360,
1024
- l: hsl.l / 100,
1025
- s: hsl.s / 100
989
+ const h = (hsl.h % 360 + 360) % 360,
990
+ s = Math.max(0, Math.min(100, hsl.s)),
991
+ l = Math.max(0, Math.min(100, hsl.l)),
992
+ hNormalized = h / 360,
993
+ sNormalized = s / 100,
994
+ lNormalized = l / 100;
995
+ if (s === 0) {
996
+ const grayscaleValue = Math.round(lNormalized * 255);
997
+ return {
998
+ r: grayscaleValue,
999
+ g: grayscaleValue,
1000
+ b: grayscaleValue
1026
1001
  };
1027
- if (!hslPercent.s) {
1028
- result.r = result.g = result.b = hslPercent.l;
1029
- } else {
1030
- const q = hslPercent.l < 0.5 ? hslPercent.l * (1 + hslPercent.s) : hslPercent.l + hslPercent.s - hslPercent.l * hslPercent.s,
1031
- p = 2 * hslPercent.l - q;
1032
- result.r = hue2rgb(p, q, hslPercent.h + 1 / 3);
1033
- result.g = hue2rgb(p, q, hslPercent.h);
1034
- result.b = hue2rgb(p, q, hslPercent.h - 1 / 3);
1035
1002
  }
1036
- result.r = Math.floor(result.r * 255);
1037
- result.g = Math.floor(result.g * 255);
1038
- result.b = Math.floor(result.b * 255);
1039
- return result;
1003
+ const channel = (temp1, temp2, temp3) => {
1004
+ if (temp3 < 0) {
1005
+ temp3 += 1;
1006
+ }
1007
+ if (temp3 > 1) {
1008
+ temp3 -= 1;
1009
+ }
1010
+ if (temp3 * 6 < 1) {
1011
+ return temp1 + (temp2 - temp1) * 6 * temp3;
1012
+ }
1013
+ if (temp3 * 2 < 1) {
1014
+ return temp2;
1015
+ }
1016
+ if (temp3 * 3 < 2) {
1017
+ return temp1 + (temp2 - temp1) * (2 / 3 - temp3) * 6;
1018
+ }
1019
+ return temp1;
1020
+ },
1021
+ temp1 = lNormalized < 0.5 ? lNormalized * (1 + sNormalized) : lNormalized + sNormalized - lNormalized * sNormalized,
1022
+ temp2 = 2 * lNormalized - temp1,
1023
+ red = Math.min(255, 255 * channel(temp2, temp1, hNormalized + 1 / 3)),
1024
+ green = Math.min(255, 255 * channel(temp2, temp1, hNormalized)),
1025
+ blue = Math.min(255, 255 * channel(temp2, temp1, hNormalized - 1 / 3));
1026
+ return {
1027
+ r: Math.round(red),
1028
+ g: Math.round(green),
1029
+ b: Math.round(blue)
1030
+ };
1040
1031
  }
1041
1032
  function hslaToRgba(hsla) {
1042
1033
  const rgbResult = hslToRgb(hsla);
@@ -1170,13 +1161,6 @@ function drawLine(context, begin, end) {
1170
1161
  context.lineTo(end.x, end.y);
1171
1162
  context.closePath();
1172
1163
  }
1173
- function drawTriangle(context, p1, p2, p3) {
1174
- context.beginPath();
1175
- context.moveTo(p1.x, p1.y);
1176
- context.lineTo(p2.x, p2.y);
1177
- context.lineTo(p3.x, p3.y);
1178
- context.closePath();
1179
- }
1180
1164
  function paintBase(context, dimension, baseColor) {
1181
1165
  context.fillStyle = baseColor ?? "rgba(0,0,0,0)";
1182
1166
  context.fillRect(0, 0, dimension.width, dimension.height);
@@ -1219,7 +1203,6 @@ function drawParticle(data) {
1219
1203
  d: rotateData.cos * (transform.d ?? 1)
1220
1204
  };
1221
1205
  context.setTransform(transformData.a, transformData.b, transformData.c, transformData.d, pos.x, pos.y);
1222
- context.beginPath();
1223
1206
  if (backgroundMask) {
1224
1207
  context.globalCompositeOperation = composite;
1225
1208
  }
@@ -1246,20 +1229,47 @@ function drawParticle(data) {
1246
1229
  opacity,
1247
1230
  delta
1248
1231
  };
1232
+ context.beginPath();
1249
1233
  drawShape(drawData);
1234
+ if (particle.shapeClose) {
1235
+ context.closePath();
1236
+ }
1250
1237
  if (strokeWidth > 0) {
1251
1238
  context.stroke();
1252
1239
  }
1253
- if (particle.close) {
1254
- context.closePath();
1255
- }
1256
- if (particle.fill) {
1240
+ if (particle.shapeFill) {
1257
1241
  context.fill();
1258
1242
  }
1259
- drawShapeAfterEffect(drawData);
1243
+ drawShapeAfterDraw(drawData);
1244
+ drawEffect(drawData);
1260
1245
  context.globalCompositeOperation = "source-over";
1261
1246
  context.setTransform(1, 0, 0, 1, 0, 0);
1262
1247
  }
1248
+ function drawEffect(data) {
1249
+ const {
1250
+ container,
1251
+ context,
1252
+ particle,
1253
+ radius,
1254
+ opacity,
1255
+ delta
1256
+ } = data;
1257
+ if (!particle.effect) {
1258
+ return;
1259
+ }
1260
+ const drawer = container.effectDrawers.get(particle.effect);
1261
+ if (!drawer) {
1262
+ return;
1263
+ }
1264
+ drawer.draw({
1265
+ context,
1266
+ particle,
1267
+ radius,
1268
+ opacity,
1269
+ delta,
1270
+ pixelRatio: container.retina.pixelRatio
1271
+ });
1272
+ }
1263
1273
  function drawShape(data) {
1264
1274
  const {
1265
1275
  container,
@@ -1272,7 +1282,7 @@ function drawShape(data) {
1272
1282
  if (!particle.shape) {
1273
1283
  return;
1274
1284
  }
1275
- const drawer = container.drawers.get(particle.shape);
1285
+ const drawer = container.shapeDrawers.get(particle.shape);
1276
1286
  if (!drawer) {
1277
1287
  return;
1278
1288
  }
@@ -1285,7 +1295,7 @@ function drawShape(data) {
1285
1295
  pixelRatio: container.retina.pixelRatio
1286
1296
  });
1287
1297
  }
1288
- function drawShapeAfterEffect(data) {
1298
+ function drawShapeAfterDraw(data) {
1289
1299
  const {
1290
1300
  container,
1291
1301
  context,
@@ -1297,11 +1307,11 @@ function drawShapeAfterEffect(data) {
1297
1307
  if (!particle.shape) {
1298
1308
  return;
1299
1309
  }
1300
- const drawer = container.drawers.get(particle.shape);
1301
- if (!drawer || !drawer.afterEffect) {
1310
+ const drawer = container.shapeDrawers.get(particle.shape);
1311
+ if (!drawer || !drawer.afterDraw) {
1302
1312
  return;
1303
1313
  }
1304
- drawer.afterEffect({
1314
+ drawer.afterDraw({
1305
1315
  context,
1306
1316
  particle,
1307
1317
  radius,
@@ -1755,10 +1765,10 @@ class Canvas {
1755
1765
  this.element.width = size.width = this.element.offsetWidth * pxRatio;
1756
1766
  this.element.height = size.height = this.element.offsetHeight * pxRatio;
1757
1767
  if (this.container.started) {
1758
- this.resizeFactor = {
1768
+ container.particles.setResizeFactor({
1759
1769
  width: size.width / oldSize.width,
1760
1770
  height: size.height / oldSize.height
1761
- };
1771
+ });
1762
1772
  }
1763
1773
  return true;
1764
1774
  }
@@ -2228,10 +2238,10 @@ class BackgroundMask {
2228
2238
  this.composite = data.composite;
2229
2239
  }
2230
2240
  if (data.cover !== undefined) {
2231
- const cover = data.cover;
2232
- const color = isString(data.cover) ? {
2233
- color: data.cover
2234
- } : data.cover;
2241
+ const cover = data.cover,
2242
+ color = isString(data.cover) ? {
2243
+ color: data.cover
2244
+ } : data.cover;
2235
2245
  this.cover.load(cover.color !== undefined ? cover : {
2236
2246
  color: color
2237
2247
  });
@@ -2533,17 +2543,16 @@ class Theme {
2533
2543
  }
2534
2544
  }
2535
2545
  }
2536
- ;// CONCATENATED MODULE: ../../engine/dist/browser/Options/Classes/ColorAnimation.js
2546
+ ;// CONCATENATED MODULE: ../../engine/dist/browser/Options/Classes/AnimationOptions.js
2537
2547
 
2538
- class ColorAnimation {
2548
+ class AnimationOptions {
2539
2549
  constructor() {
2540
2550
  this.count = 0;
2541
2551
  this.enable = false;
2542
- this.offset = 0;
2543
2552
  this.speed = 1;
2544
- this.delay = 0;
2545
2553
  this.decay = 0;
2546
- this.sync = true;
2554
+ this.delay = 0;
2555
+ this.sync = false;
2547
2556
  }
2548
2557
  load(data) {
2549
2558
  if (!data) {
@@ -2555,9 +2564,6 @@ class ColorAnimation {
2555
2564
  if (data.enable !== undefined) {
2556
2565
  this.enable = data.enable;
2557
2566
  }
2558
- if (data.offset !== undefined) {
2559
- this.offset = setRangeValue(data.offset);
2560
- }
2561
2567
  if (data.speed !== undefined) {
2562
2568
  this.speed = setRangeValue(data.speed);
2563
2569
  }
@@ -2572,6 +2578,44 @@ class ColorAnimation {
2572
2578
  }
2573
2579
  }
2574
2580
  }
2581
+ class RangedAnimationOptions extends AnimationOptions {
2582
+ constructor() {
2583
+ super();
2584
+ this.mode = "auto";
2585
+ this.startValue = "random";
2586
+ }
2587
+ load(data) {
2588
+ super.load(data);
2589
+ if (!data) {
2590
+ return;
2591
+ }
2592
+ if (data.mode !== undefined) {
2593
+ this.mode = data.mode;
2594
+ }
2595
+ if (data.startValue !== undefined) {
2596
+ this.startValue = data.startValue;
2597
+ }
2598
+ }
2599
+ }
2600
+ ;// CONCATENATED MODULE: ../../engine/dist/browser/Options/Classes/ColorAnimation.js
2601
+
2602
+
2603
+ class ColorAnimation extends AnimationOptions {
2604
+ constructor() {
2605
+ super();
2606
+ this.offset = 0;
2607
+ this.sync = true;
2608
+ }
2609
+ load(data) {
2610
+ super.load(data);
2611
+ if (!data) {
2612
+ return;
2613
+ }
2614
+ if (data.offset !== undefined) {
2615
+ this.offset = setRangeValue(data.offset);
2616
+ }
2617
+ }
2618
+ }
2575
2619
  ;// CONCATENATED MODULE: ../../engine/dist/browser/Options/Classes/HslAnimation.js
2576
2620
 
2577
2621
  class HslAnimation {
@@ -2659,99 +2703,19 @@ class CollisionsOverlap {
2659
2703
  }
2660
2704
  }
2661
2705
  }
2662
- ;// CONCATENATED MODULE: ../../engine/dist/browser/Options/Classes/AnimationOptions.js
2663
-
2664
- class AnimationOptions {
2665
- constructor() {
2666
- this.count = 0;
2667
- this.enable = false;
2668
- this.speed = 1;
2669
- this.decay = 0;
2670
- this.delay = 0;
2671
- this.sync = false;
2672
- }
2673
- load(data) {
2674
- if (!data) {
2675
- return;
2676
- }
2677
- if (data.count !== undefined) {
2678
- this.count = setRangeValue(data.count);
2679
- }
2680
- if (data.enable !== undefined) {
2681
- this.enable = data.enable;
2682
- }
2683
- if (data.speed !== undefined) {
2684
- this.speed = setRangeValue(data.speed);
2685
- }
2686
- if (data.decay !== undefined) {
2687
- this.decay = setRangeValue(data.decay);
2688
- }
2689
- if (data.delay !== undefined) {
2690
- this.delay = setRangeValue(data.delay);
2691
- }
2692
- if (data.sync !== undefined) {
2693
- this.sync = data.sync;
2694
- }
2695
- }
2696
- }
2697
- class RangedAnimationOptions extends AnimationOptions {
2698
- constructor() {
2699
- super();
2700
- this.mode = "auto";
2701
- this.startValue = "random";
2702
- }
2703
- load(data) {
2704
- super.load(data);
2705
- if (!data) {
2706
- return;
2707
- }
2708
- if (data.mode !== undefined) {
2709
- this.mode = data.mode;
2710
- }
2711
- if (data.startValue !== undefined) {
2712
- this.startValue = data.startValue;
2713
- }
2714
- }
2715
- }
2716
- ;// CONCATENATED MODULE: ../../engine/dist/browser/Options/Classes/Random.js
2717
- class Random {
2718
- constructor() {
2719
- this.enable = false;
2720
- this.minimumValue = 0;
2721
- }
2722
- load(data) {
2723
- if (!data) {
2724
- return;
2725
- }
2726
- if (data.enable !== undefined) {
2727
- this.enable = data.enable;
2728
- }
2729
- if (data.minimumValue !== undefined) {
2730
- this.minimumValue = data.minimumValue;
2731
- }
2732
- }
2733
- }
2734
2706
  ;// CONCATENATED MODULE: ../../engine/dist/browser/Options/Classes/ValueWithRandom.js
2735
2707
 
2736
2708
 
2737
-
2738
-
2739
2709
  class ValueWithRandom {
2740
2710
  constructor() {
2741
- this.random = new Random();
2742
2711
  this.value = 0;
2743
2712
  }
2744
2713
  load(data) {
2745
2714
  if (!data) {
2746
2715
  return;
2747
2716
  }
2748
- if (isBoolean(data.random)) {
2749
- this.random.enable = data.random;
2750
- } else {
2751
- this.random.load(data.random);
2752
- }
2753
2717
  if (data.value !== undefined) {
2754
- this.value = setRangeValue(data.value, this.random.enable ? this.random.minimumValue : undefined);
2718
+ this.value = setRangeValue(data.value);
2755
2719
  }
2756
2720
  }
2757
2721
  }
@@ -2785,7 +2749,6 @@ class RangedAnimationValueWithRandom extends AnimationValueWithRandom {
2785
2749
  class ParticlesBounceFactor extends ValueWithRandom {
2786
2750
  constructor() {
2787
2751
  super();
2788
- this.random.minimumValue = 0.1;
2789
2752
  this.value = 1;
2790
2753
  }
2791
2754
  }
@@ -2836,6 +2799,39 @@ class Collisions {
2836
2799
  this.overlap.load(data.overlap);
2837
2800
  }
2838
2801
  }
2802
+ ;// CONCATENATED MODULE: ../../engine/dist/browser/Options/Classes/Particles/Effect/Effect.js
2803
+
2804
+ class Effect {
2805
+ constructor() {
2806
+ this.close = true;
2807
+ this.fill = true;
2808
+ this.options = {};
2809
+ this.type = [];
2810
+ }
2811
+ load(data) {
2812
+ if (!data) {
2813
+ return;
2814
+ }
2815
+ const options = data.options;
2816
+ if (options !== undefined) {
2817
+ for (const effect in options) {
2818
+ const item = options[effect];
2819
+ if (item) {
2820
+ this.options[effect] = deepExtend(this.options[effect] ?? {}, item);
2821
+ }
2822
+ }
2823
+ }
2824
+ if (data.close !== undefined) {
2825
+ this.close = data.close;
2826
+ }
2827
+ if (data.fill !== undefined) {
2828
+ this.fill = data.fill;
2829
+ }
2830
+ if (data.type !== undefined) {
2831
+ this.type = data.type;
2832
+ }
2833
+ }
2834
+ }
2839
2835
  ;// CONCATENATED MODULE: ../../engine/dist/browser/Options/Classes/Particles/Move/MoveAngle.js
2840
2836
 
2841
2837
  class MoveAngle {
@@ -3164,11 +3160,10 @@ class OpacityAnimation extends RangedAnimationOptions {
3164
3160
  ;// CONCATENATED MODULE: ../../engine/dist/browser/Options/Classes/Particles/Opacity/Opacity.js
3165
3161
 
3166
3162
 
3167
- class Opacity extends ValueWithRandom {
3163
+ class Opacity extends RangedAnimationValueWithRandom {
3168
3164
  constructor() {
3169
3165
  super();
3170
3166
  this.animation = new OpacityAnimation();
3171
- this.random.minimumValue = 0.1;
3172
3167
  this.value = 1;
3173
3168
  }
3174
3169
  load(data) {
@@ -3206,12 +3201,31 @@ class ParticlesDensity {
3206
3201
  }
3207
3202
  }
3208
3203
  }
3204
+ ;// CONCATENATED MODULE: ../../engine/dist/browser/Options/Classes/Particles/Number/ParticlesNumberLimit.js
3205
+ class ParticlesNumberLimit {
3206
+ constructor() {
3207
+ this.mode = "delete";
3208
+ this.value = 0;
3209
+ }
3210
+ load(data) {
3211
+ if (!data) {
3212
+ return;
3213
+ }
3214
+ if (data.mode !== undefined) {
3215
+ this.mode = data.mode;
3216
+ }
3217
+ if (data.value !== undefined) {
3218
+ this.value = data.value;
3219
+ }
3220
+ }
3221
+ }
3209
3222
  ;// CONCATENATED MODULE: ../../engine/dist/browser/Options/Classes/Particles/Number/ParticlesNumber.js
3210
3223
 
3224
+
3211
3225
  class ParticlesNumber {
3212
3226
  constructor() {
3213
3227
  this.density = new ParticlesDensity();
3214
- this.limit = 0;
3228
+ this.limit = new ParticlesNumberLimit();
3215
3229
  this.value = 0;
3216
3230
  }
3217
3231
  load(data) {
@@ -3219,10 +3233,7 @@ class ParticlesNumber {
3219
3233
  return;
3220
3234
  }
3221
3235
  this.density.load(data.density);
3222
- const limit = data.limit;
3223
- if (limit !== undefined) {
3224
- this.limit = limit;
3225
- }
3236
+ this.limit.load(data.limit);
3226
3237
  if (data.value !== undefined) {
3227
3238
  this.value = data.value;
3228
3239
  }
@@ -3317,11 +3328,10 @@ class SizeAnimation extends RangedAnimationOptions {
3317
3328
  ;// CONCATENATED MODULE: ../../engine/dist/browser/Options/Classes/Particles/Size/Size.js
3318
3329
 
3319
3330
 
3320
- class Size extends ValueWithRandom {
3331
+ class Size extends RangedAnimationValueWithRandom {
3321
3332
  constructor() {
3322
3333
  super();
3323
3334
  this.animation = new SizeAnimation();
3324
- this.random.minimumValue = 1;
3325
3335
  this.value = 3;
3326
3336
  }
3327
3337
  load(data) {
@@ -3395,6 +3405,7 @@ class ZIndex extends ValueWithRandom {
3395
3405
 
3396
3406
 
3397
3407
 
3408
+
3398
3409
  class ParticlesOptions {
3399
3410
  constructor(engine, container) {
3400
3411
  this._engine = engine;
@@ -3403,6 +3414,7 @@ class ParticlesOptions {
3403
3414
  this.collisions = new Collisions();
3404
3415
  this.color = new AnimatableColor();
3405
3416
  this.color.value = "#fff";
3417
+ this.effect = new Effect();
3406
3418
  this.groups = {};
3407
3419
  this.move = new Move();
3408
3420
  this.number = new ParticlesNumber();
@@ -3420,6 +3432,7 @@ class ParticlesOptions {
3420
3432
  }
3421
3433
  this.bounce.load(data.bounce);
3422
3434
  this.color.load(AnimatableColor.create(this.color, data.color));
3435
+ this.effect.load(data.effect);
3423
3436
  if (data.groups !== undefined) {
3424
3437
  for (const group in data.groups) {
3425
3438
  const item = data.groups[group];
@@ -3692,6 +3705,16 @@ class InteractionManager {
3692
3705
 
3693
3706
 
3694
3707
 
3708
+ function loadEffectData(effect, effectOptions, id, reduceDuplicates) {
3709
+ const effectData = effectOptions.options[effect];
3710
+ if (!effectData) {
3711
+ return;
3712
+ }
3713
+ return deepExtend({
3714
+ close: effectOptions.close,
3715
+ fill: effectOptions.fill
3716
+ }, itemFromSingleOrMultiple(effectData, id, reduceDuplicates));
3717
+ }
3695
3718
  function loadShapeData(shape, shapeOptions, id, reduceDuplicates) {
3696
3719
  const shapeData = shapeOptions.options[shape];
3697
3720
  if (!shapeData) {
@@ -3770,8 +3793,8 @@ class Particle {
3770
3793
  const rad = Math.PI / 180 * getRangeValue(moveOptions.angle.value),
3771
3794
  radOffset = Math.PI / 180 * getRangeValue(moveOptions.angle.offset),
3772
3795
  range = {
3773
- left: radOffset - rad / 2,
3774
- right: radOffset + rad / 2
3796
+ left: radOffset - rad * 0.5,
3797
+ right: radOffset + rad * 0.5
3775
3798
  };
3776
3799
  if (!moveOptions.straight) {
3777
3800
  res.angle += randomInRange(setRangeValue(range.left, range.right));
@@ -3802,7 +3825,7 @@ class Particle {
3802
3825
  return color;
3803
3826
  }
3804
3827
  const backFactor = this.roll.horizontal && this.roll.vertical ? 2 : 1,
3805
- backSum = this.roll.horizontal ? Math.PI / 2 : 0,
3828
+ backSum = this.roll.horizontal ? Math.PI * 0.5 : 0,
3806
3829
  rolled = Math.floor(((this.roll.angle ?? 0) + backSum) / (Math.PI / backFactor)) % 2;
3807
3830
  if (!rolled) {
3808
3831
  return color;
@@ -3850,18 +3873,12 @@ class Particle {
3850
3873
  const container = this.container,
3851
3874
  pathGenerator = this.pathGenerator;
3852
3875
  for (const [, plugin] of container.plugins) {
3853
- if (plugin.particleDestroyed) {
3854
- plugin.particleDestroyed(this, override);
3855
- }
3876
+ plugin.particleDestroyed && plugin.particleDestroyed(this, override);
3856
3877
  }
3857
3878
  for (const updater of container.particles.updaters) {
3858
- if (updater.particleDestroyed) {
3859
- updater.particleDestroyed(this, override);
3860
- }
3861
- }
3862
- if (pathGenerator) {
3863
- pathGenerator.reset(this);
3879
+ updater.particleDestroyed && updater.particleDestroyed(this, override);
3864
3880
  }
3881
+ pathGenerator && pathGenerator.reset(this);
3865
3882
  }
3866
3883
  draw(delta) {
3867
3884
  const container = this.container,
@@ -3875,7 +3892,7 @@ class Particle {
3875
3892
  return this._getRollColor(this.bubble.color ?? getHslFromAnimation(this.color));
3876
3893
  }
3877
3894
  getMass() {
3878
- return this.getRadius() ** 2 * Math.PI / 2;
3895
+ return this.getRadius() ** 2 * Math.PI * 0.5;
3879
3896
  }
3880
3897
  getPosition() {
3881
3898
  return {
@@ -3895,9 +3912,11 @@ class Particle {
3895
3912
  engine = this._engine;
3896
3913
  this.id = id;
3897
3914
  this.group = group;
3898
- this.fill = true;
3915
+ this.effectClose = true;
3916
+ this.effectFill = true;
3917
+ this.shapeClose = true;
3918
+ this.shapeFill = true;
3899
3919
  this.pathRotation = false;
3900
- this.close = true;
3901
3920
  this.lastPathTime = 0;
3902
3921
  this.destroyed = false;
3903
3922
  this.unbreakable = false;
@@ -3911,22 +3930,40 @@ class Particle {
3911
3930
  const pxRatio = container.retina.pixelRatio,
3912
3931
  mainOptions = container.actualOptions,
3913
3932
  particlesOptions = loadParticlesOptions(this._engine, container, mainOptions.particles),
3933
+ effectType = particlesOptions.effect.type,
3914
3934
  shapeType = particlesOptions.shape.type,
3915
3935
  {
3916
3936
  reduceDuplicates
3917
3937
  } = particlesOptions;
3938
+ this.effect = itemFromSingleOrMultiple(effectType, this.id, reduceDuplicates);
3918
3939
  this.shape = itemFromSingleOrMultiple(shapeType, this.id, reduceDuplicates);
3919
- const shapeOptions = particlesOptions.shape;
3920
- if (overrideOptions && overrideOptions.shape && overrideOptions.shape.type) {
3921
- const overrideShapeType = overrideOptions.shape.type,
3922
- shape = itemFromSingleOrMultiple(overrideShapeType, this.id, reduceDuplicates);
3923
- if (shape) {
3924
- this.shape = shape;
3925
- shapeOptions.load(overrideOptions.shape);
3940
+ const effectOptions = particlesOptions.effect,
3941
+ shapeOptions = particlesOptions.shape;
3942
+ if (overrideOptions) {
3943
+ if (overrideOptions.effect && overrideOptions.effect.type) {
3944
+ const overrideEffectType = overrideOptions.effect.type,
3945
+ effect = itemFromSingleOrMultiple(overrideEffectType, this.id, reduceDuplicates);
3946
+ if (effect) {
3947
+ this.effect = effect;
3948
+ effectOptions.load(overrideOptions.effect);
3949
+ }
3950
+ }
3951
+ if (overrideOptions.shape && overrideOptions.shape.type) {
3952
+ const overrideShapeType = overrideOptions.shape.type,
3953
+ shape = itemFromSingleOrMultiple(overrideShapeType, this.id, reduceDuplicates);
3954
+ if (shape) {
3955
+ this.shape = shape;
3956
+ shapeOptions.load(overrideOptions.shape);
3957
+ }
3926
3958
  }
3927
3959
  }
3960
+ this.effectData = loadEffectData(this.effect, effectOptions, this.id, reduceDuplicates);
3928
3961
  this.shapeData = loadShapeData(this.shape, shapeOptions, this.id, reduceDuplicates);
3929
3962
  particlesOptions.load(overrideOptions);
3963
+ const effectData = this.effectData;
3964
+ if (effectData) {
3965
+ particlesOptions.load(effectData.particles);
3966
+ }
3930
3967
  const shapeData = this.shapeData;
3931
3968
  if (shapeData) {
3932
3969
  particlesOptions.load(shapeData.particles);
@@ -3935,11 +3972,13 @@ class Particle {
3935
3972
  interactivity.load(container.actualOptions.interactivity);
3936
3973
  interactivity.load(particlesOptions.interactivity);
3937
3974
  this.interactivity = interactivity;
3938
- this.fill = shapeData?.fill ?? particlesOptions.shape.fill;
3939
- this.close = shapeData?.close ?? particlesOptions.shape.close;
3975
+ this.effectFill = effectData?.fill ?? particlesOptions.effect.fill;
3976
+ this.effectClose = effectData?.close ?? particlesOptions.effect.close;
3977
+ this.shapeFill = shapeData?.fill ?? particlesOptions.shape.fill;
3978
+ this.shapeClose = shapeData?.close ?? particlesOptions.shape.close;
3940
3979
  this.options = particlesOptions;
3941
3980
  const pathOptions = this.options.move.path;
3942
- this.pathDelay = getValue(pathOptions.delay) * 1000;
3981
+ this.pathDelay = getRangeValue(pathOptions.delay.value) * 1000;
3943
3982
  if (pathOptions.generator) {
3944
3983
  this.pathGenerator = this._engine.getPathGenerator(pathOptions.generator);
3945
3984
  if (this.pathGenerator && container.addPath(pathOptions.generator, this.pathGenerator)) {
@@ -3960,34 +3999,46 @@ class Particle {
3960
3999
  this.velocity = this.initialVelocity.copy();
3961
4000
  this.moveDecay = 1 - getRangeValue(this.options.move.decay);
3962
4001
  const particles = container.particles;
3963
- particles.needsSort = particles.needsSort || particles.lastZIndex < this.position.z;
3964
- particles.lastZIndex = this.position.z;
4002
+ particles.setLastZIndex(this.position.z);
3965
4003
  this.zIndexFactor = this.position.z / container.zLayers;
3966
4004
  this.sides = 24;
3967
- let drawer = container.drawers.get(this.shape);
3968
- if (!drawer) {
3969
- drawer = this._engine.getShapeDrawer(this.shape);
3970
- if (drawer) {
3971
- container.drawers.set(this.shape, drawer);
4005
+ let effectDrawer = container.effectDrawers.get(this.effect);
4006
+ if (!effectDrawer) {
4007
+ effectDrawer = this._engine.getEffectDrawer(this.effect);
4008
+ if (effectDrawer) {
4009
+ container.effectDrawers.set(this.effect, effectDrawer);
4010
+ }
4011
+ }
4012
+ if (effectDrawer && effectDrawer.loadEffect) {
4013
+ effectDrawer.loadEffect(this);
4014
+ }
4015
+ let shapeDrawer = container.shapeDrawers.get(this.shape);
4016
+ if (!shapeDrawer) {
4017
+ shapeDrawer = this._engine.getShapeDrawer(this.shape);
4018
+ if (shapeDrawer) {
4019
+ container.shapeDrawers.set(this.shape, shapeDrawer);
3972
4020
  }
3973
4021
  }
3974
- if (drawer && drawer.loadShape) {
3975
- drawer.loadShape(this);
4022
+ if (shapeDrawer && shapeDrawer.loadShape) {
4023
+ shapeDrawer.loadShape(this);
3976
4024
  }
3977
- const sideCountFunc = drawer?.getSidesCount;
4025
+ const sideCountFunc = shapeDrawer?.getSidesCount;
3978
4026
  if (sideCountFunc) {
3979
4027
  this.sides = sideCountFunc(this);
3980
4028
  }
3981
4029
  this.spawning = false;
3982
4030
  this.shadowColor = rangeColorToRgb(this.options.shadow.color);
3983
- for (const updater of container.particles.updaters) {
4031
+ for (const updater of particles.updaters) {
3984
4032
  updater.init(this);
3985
4033
  }
3986
- for (const mover of container.particles.movers) {
4034
+ for (const mover of particles.movers) {
3987
4035
  mover.init && mover.init(this);
3988
4036
  }
3989
- if (drawer && drawer.particleInit) {
3990
- drawer.particleInit(container, this);
4037
+ if (effectDrawer && effectDrawer.particleInit) {
4038
+ effectDrawer.particleInit(container, this);
4039
+ }
4040
+ if (shapeDrawer && shapeDrawer.particleInit) {
4041
+ shapeDrawer.particleInit(container, this);
3991
4042
  }
3992
4043
  for (const [, plugin] of container.plugins) {
3993
4044
  plugin.particleCreated && plugin.particleCreated(this);
@@ -4114,7 +4165,7 @@ class QuadTree {
4114
4165
  capacity
4115
4166
  } = this;
4116
4167
  for (let i = 0; i < 4; i++) {
4117
- 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));
4168
+ 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));
4118
4169
  }
4119
4170
  this._divided = true;
4120
4171
  };
@@ -4170,21 +4221,36 @@ class QuadTree {
4170
4221
 
4171
4222
  const qTreeCapacity = 4;
4172
4223
  const qTreeRectangle = canvasSize => {
4173
- return new Rectangle(-canvasSize.width / 4, -canvasSize.height / 4, canvasSize.width * 3 / 2, canvasSize.height * 3 / 2);
4224
+ const {
4225
+ height,
4226
+ width
4227
+ } = canvasSize,
4228
+ posOffset = -0.25,
4229
+ sizeFactor = 1.5;
4230
+ return new Rectangle(posOffset * width, posOffset * height, sizeFactor * width, sizeFactor * height);
4174
4231
  };
4175
4232
  class Particles {
4176
4233
  constructor(engine, container) {
4177
4234
  this._applyDensity = (options, manualCount, group) => {
4235
+ const numberOptions = options.number;
4178
4236
  if (!options.number.density?.enable) {
4237
+ if (group === undefined) {
4238
+ this._limit = numberOptions.limit.value;
4239
+ } else {
4240
+ this._groupLimits.set(group, numberOptions.limit.value);
4241
+ }
4179
4242
  return;
4180
4243
  }
4181
- const numberOptions = options.number,
4182
- densityFactor = this._initDensityFactor(numberOptions.density),
4244
+ const densityFactor = this._initDensityFactor(numberOptions.density),
4183
4245
  optParticlesNumber = numberOptions.value,
4184
- optParticlesLimit = numberOptions.limit > 0 ? numberOptions.limit : optParticlesNumber,
4246
+ optParticlesLimit = numberOptions.limit.value > 0 ? numberOptions.limit.value : optParticlesNumber,
4185
4247
  particlesNumber = Math.min(optParticlesNumber, optParticlesLimit) * densityFactor + manualCount,
4186
4248
  particlesCount = Math.min(this.count, this.filter(t => t.group === group).length);
4187
- this.limit = numberOptions.limit * densityFactor;
4249
+ if (group === undefined) {
4250
+ this._limit = numberOptions.limit.value * densityFactor;
4251
+ } else {
4252
+ this._groupLimits.set(group, numberOptions.limit.value * densityFactor);
4253
+ }
4188
4254
  if (particlesCount < particlesNumber) {
4189
4255
  this.push(Math.abs(particlesNumber - particlesCount), undefined, options, group);
4190
4256
  } else if (particlesCount > particlesNumber) {
@@ -4202,7 +4268,7 @@ class Particles {
4202
4268
  };
4203
4269
  this._pushParticle = (position, overrideOptions, group, initializer) => {
4204
4270
  try {
4205
- let particle = this.pool.pop();
4271
+ let particle = this._pool.pop();
4206
4272
  if (particle) {
4207
4273
  particle.init(this._nextId, position, overrideOptions, group);
4208
4274
  } else {
@@ -4239,7 +4305,7 @@ class Particles {
4239
4305
  const zIdx = this._zArray.indexOf(particle);
4240
4306
  this._array.splice(index, 1);
4241
4307
  this._zArray.splice(zIdx, 1);
4242
- this.pool.push(particle);
4308
+ this._pool.push(particle);
4243
4309
  this._engine.dispatchEvent("particleRemoved", {
4244
4310
  container: this._container,
4245
4311
  data: {
@@ -4253,10 +4319,11 @@ class Particles {
4253
4319
  this._nextId = 0;
4254
4320
  this._array = [];
4255
4321
  this._zArray = [];
4256
- this.pool = [];
4257
- this.limit = 0;
4258
- this.needsSort = false;
4259
- this.lastZIndex = 0;
4322
+ this._pool = [];
4323
+ this._limit = 0;
4324
+ this._groupLimits = new Map();
4325
+ this._needsSort = false;
4326
+ this._lastZIndex = 0;
4260
4327
  this._interactionManager = new InteractionManager(engine, container);
4261
4328
  const canvasSize = container.canvas.size;
4262
4329
  this.quadTree = new QuadTree(qTreeRectangle(canvasSize), qTreeCapacity);
@@ -4274,19 +4341,22 @@ class Particles {
4274
4341
  }
4275
4342
  }
4276
4343
  addParticle(position, overrideOptions, group, initializer) {
4277
- this.pushing = true;
4278
- const container = this._container,
4279
- options = container.actualOptions,
4280
- limit = options.particles.number.limit;
4344
+ const limitOptions = this._container.actualOptions.particles.number.limit,
4345
+ limit = group === undefined ? this._limit : this._groupLimits.get(group) ?? this._limit,
4346
+ currentCount = this.count;
4281
4347
  if (limit > 0) {
4282
- const countToRemove = this.count + 1 - limit;
4283
- if (countToRemove > 0) {
4284
- this.removeQuantity(countToRemove);
4348
+ if (limitOptions.mode === "delete") {
4349
+ const countToRemove = currentCount + 1 - limit;
4350
+ if (countToRemove > 0) {
4351
+ this.removeQuantity(countToRemove);
4352
+ }
4353
+ } else if (limitOptions.mode === "wait") {
4354
+ if (currentCount >= limit) {
4355
+ return;
4356
+ }
4285
4357
  }
4286
4358
  }
4287
- const res = this._pushParticle(position, overrideOptions, group, initializer);
4288
- this.pushing = false;
4289
- return res;
4359
+ return this._pushParticle(position, overrideOptions, group, initializer);
4290
4360
  }
4291
4361
  clear() {
4292
4362
  this._array = [];
@@ -4325,8 +4395,8 @@ class Particles {
4325
4395
  init() {
4326
4396
  const container = this._container,
4327
4397
  options = container.actualOptions;
4328
- this.lastZIndex = 0;
4329
- this.needsSort = false;
4398
+ this._lastZIndex = 0;
4399
+ this._needsSort = false;
4330
4400
  let handled = false;
4331
4401
  this.updaters = this._engine.getUpdaters(container, true);
4332
4402
  this._interactionManager.init();
@@ -4393,6 +4463,13 @@ class Particles {
4393
4463
  }
4394
4464
  this._applyDensity(options.particles, options.manualParticles.length);
4395
4465
  }
4466
+ setLastZIndex(zIndex) {
4467
+ this._lastZIndex = zIndex;
4468
+ this._needsSort = this._needsSort || this._lastZIndex < zIndex;
4469
+ }
4470
+ setResizeFactor(factor) {
4471
+ this._resizeFactor = factor;
4472
+ }
4396
4473
  async update(delta) {
4397
4474
  const container = this._container,
4398
4475
  particlesToDelete = new Set();
@@ -4401,10 +4478,10 @@ class Particles {
4401
4478
  pathGenerator.update();
4402
4479
  }
4403
4480
  for (const [, plugin] of container.plugins) {
4404
- plugin.update && plugin.update(delta);
4481
+ plugin.update && (await plugin.update(delta));
4405
4482
  }
4483
+ const resizeFactor = this._resizeFactor;
4406
4484
  for (const particle of this._array) {
4407
- const resizeFactor = container.canvas.resizeFactor;
4408
4485
  if (resizeFactor && !particle.ignoresResizeRatio) {
4409
4486
  particle.position.x *= resizeFactor.width;
4410
4487
  particle.position.y *= resizeFactor.height;
@@ -4432,7 +4509,7 @@ class Particles {
4432
4509
  const checkDelete = p => !particlesToDelete.has(p);
4433
4510
  this._array = this.filter(checkDelete);
4434
4511
  this._zArray = this._zArray.filter(checkDelete);
4435
- this.pool.push(...particlesToDelete);
4512
+ this._pool.push(...particlesToDelete);
4436
4513
  }
4437
4514
  await this._interactionManager.externalInteract(delta);
4438
4515
  for (const particle of this._array) {
@@ -4443,12 +4520,12 @@ class Particles {
4443
4520
  await this._interactionManager.particlesInteract(particle, delta);
4444
4521
  }
4445
4522
  }
4446
- delete container.canvas.resizeFactor;
4447
- if (this.needsSort) {
4523
+ delete this._resizeFactor;
4524
+ if (this._needsSort) {
4448
4525
  const zArray = this._zArray;
4449
4526
  zArray.sort((a, b) => b.position.z - a.position.z || a.id - b.id);
4450
- this.lastZIndex = zArray[zArray.length - 1].position.z;
4451
- this.needsSort = false;
4527
+ this._lastZIndex = zArray[zArray.length - 1].position.z;
4528
+ this._needsSort = false;
4452
4529
  }
4453
4530
  }
4454
4531
  }
@@ -4475,7 +4552,6 @@ class Retina {
4475
4552
  }
4476
4553
  const particles = options.particles,
4477
4554
  moveOptions = particles.move;
4478
- this.attractDistance = getRangeValue(moveOptions.attract.distance) * ratio;
4479
4555
  this.maxSpeed = getRangeValue(moveOptions.gravity.maxSpeed) * ratio;
4480
4556
  this.sizeAnimationSpeed = getRangeValue(particles.size.animation.speed) * ratio;
4481
4557
  }
@@ -4485,7 +4561,6 @@ class Retina {
4485
4561
  moveOptions = options.move,
4486
4562
  moveDistance = moveOptions.distance,
4487
4563
  props = particle.retina;
4488
- props.attractDistance = getRangeValue(moveOptions.attract.distance) * ratio;
4489
4564
  props.moveDrift = getRangeValue(moveOptions.drift) * ratio;
4490
4565
  props.moveSpeed = getRangeValue(moveOptions.speed) * ratio;
4491
4566
  props.sizeAnimationSpeed = getRangeValue(options.size.animation.speed) * ratio;
@@ -4534,14 +4609,14 @@ class Container {
4534
4609
  };
4535
4610
  this._nextFrame = async timestamp => {
4536
4611
  try {
4537
- if (!this.smooth && this.lastFrameTime !== undefined && timestamp < this.lastFrameTime + 1000 / this.fpsLimit) {
4612
+ if (!this._smooth && this._lastFrameTime !== undefined && timestamp < this._lastFrameTime + 1000 / this.fpsLimit) {
4538
4613
  this.draw(false);
4539
4614
  return;
4540
4615
  }
4541
- this.lastFrameTime ??= timestamp;
4542
- const delta = initDelta(timestamp - this.lastFrameTime, this.fpsLimit, this.smooth);
4616
+ this._lastFrameTime ??= timestamp;
4617
+ const delta = initDelta(timestamp - this._lastFrameTime, this.fpsLimit, this._smooth);
4543
4618
  this.addLifeTime(delta.value);
4544
- this.lastFrameTime = timestamp;
4619
+ this._lastFrameTime = timestamp;
4545
4620
  if (delta.value > 1000) {
4546
4621
  this.draw(false);
4547
4622
  return;
@@ -4561,7 +4636,7 @@ class Container {
4561
4636
  this._engine = engine;
4562
4637
  this.id = Symbol(id);
4563
4638
  this.fpsLimit = 120;
4564
- this.smooth = false;
4639
+ this._smooth = false;
4565
4640
  this._delay = 0;
4566
4641
  this._duration = 0;
4567
4642
  this._lifeTime = 0;
@@ -4569,7 +4644,7 @@ class Container {
4569
4644
  this.started = false;
4570
4645
  this.destroyed = false;
4571
4646
  this._paused = true;
4572
- this.lastFrameTime = 0;
4647
+ this._lastFrameTime = 0;
4573
4648
  this.zLayers = 100;
4574
4649
  this.pageHidden = false;
4575
4650
  this._sourceOptions = sourceOptions;
@@ -4585,7 +4660,8 @@ class Container {
4585
4660
  }
4586
4661
  };
4587
4662
  this.plugins = new Map();
4588
- this.drawers = new Map();
4663
+ this.effectDrawers = new Map();
4664
+ this.shapeDrawers = new Map();
4589
4665
  this._options = loadContainerOptions(this._engine, this);
4590
4666
  this.actualOptions = loadContainerOptions(this._engine, this);
4591
4667
  this._eventListeners = new EventListeners(this);
@@ -4703,11 +4779,17 @@ class Container {
4703
4779
  this.stop();
4704
4780
  this.particles.destroy();
4705
4781
  this.canvas.destroy();
4706
- for (const [, drawer] of this.drawers) {
4707
- drawer.destroy && drawer.destroy(this);
4782
+ for (const [, effectDrawer] of this.effectDrawers) {
4783
+ effectDrawer.destroy && effectDrawer.destroy(this);
4784
+ }
4785
+ for (const [, shapeDrawer] of this.shapeDrawers) {
4786
+ shapeDrawer.destroy && shapeDrawer.destroy(this);
4787
+ }
4788
+ for (const key of this.effectDrawers.keys()) {
4789
+ this.effectDrawers.delete(key);
4708
4790
  }
4709
- for (const key of this.drawers.keys()) {
4710
- this.drawers.delete(key);
4791
+ for (const key of this.shapeDrawers.keys()) {
4792
+ this.shapeDrawers.delete(key);
4711
4793
  }
4712
4794
  this._engine.clearPlugins(this);
4713
4795
  this.destroyed = true;
@@ -4727,7 +4809,7 @@ class Container {
4727
4809
  let refreshTime = force;
4728
4810
  this._drawAnimationFrame = requestAnimationFrame(async timestamp => {
4729
4811
  if (refreshTime) {
4730
- this.lastFrameTime = undefined;
4812
+ this._lastFrameTime = undefined;
4731
4813
  refreshTime = false;
4732
4814
  }
4733
4815
  await this._nextFrame(timestamp);
@@ -4762,11 +4844,18 @@ class Container {
4762
4844
  if (!guardCheck(this)) {
4763
4845
  return;
4764
4846
  }
4847
+ const effects = this._engine.getSupportedEffects();
4848
+ for (const type of effects) {
4849
+ const drawer = this._engine.getEffectDrawer(type);
4850
+ if (drawer) {
4851
+ this.effectDrawers.set(type, drawer);
4852
+ }
4853
+ }
4765
4854
  const shapes = this._engine.getSupportedShapes();
4766
4855
  for (const type of shapes) {
4767
4856
  const drawer = this._engine.getShapeDrawer(type);
4768
4857
  if (drawer) {
4769
- this.drawers.set(type, drawer);
4858
+ this.shapeDrawers.set(type, drawer);
4770
4859
  }
4771
4860
  }
4772
4861
  this._options = loadContainerOptions(this._engine, this, this._initialSourceOptions, this.sourceOptions);
@@ -4785,8 +4874,11 @@ class Container {
4785
4874
  this._delay = getRangeValue(this.actualOptions.delay) * 1000;
4786
4875
  this._lifeTime = 0;
4787
4876
  this.fpsLimit = this.actualOptions.fpsLimit > 0 ? this.actualOptions.fpsLimit : 120;
4788
- this.smooth = this.actualOptions.smooth;
4789
- for (const [, drawer] of this.drawers) {
4877
+ this._smooth = this.actualOptions.smooth;
4878
+ for (const [, drawer] of this.effectDrawers) {
4879
+ drawer.init && (await drawer.init(this));
4880
+ }
4881
+ for (const [, drawer] of this.shapeDrawers) {
4790
4882
  drawer.init && (await drawer.init(this));
4791
4883
  }
4792
4884
  for (const [, plugin] of this.plugins) {
@@ -4927,10 +5019,10 @@ class Container {
4927
5019
  this.actualOptions.responsive = [];
4928
5020
  const newMaxWidth = this.actualOptions.setResponsive(this.canvas.size.width, this.retina.pixelRatio, this._options);
4929
5021
  this.actualOptions.setTheme(this._currentTheme);
4930
- if (this.responsiveMaxWidth === newMaxWidth) {
5022
+ if (this._responsiveMaxWidth === newMaxWidth) {
4931
5023
  return false;
4932
5024
  }
4933
- this.responsiveMaxWidth = newMaxWidth;
5025
+ this._responsiveMaxWidth = newMaxWidth;
4934
5026
  return true;
4935
5027
  }
4936
5028
  }
@@ -5021,7 +5113,8 @@ class Engine {
5021
5113
  this.movers = new Map();
5022
5114
  this.updaters = new Map();
5023
5115
  this.presets = new Map();
5024
- this.drawers = new Map();
5116
+ this.effectDrawers = new Map();
5117
+ this.shapeDrawers = new Map();
5025
5118
  this.pathGenerators = new Map();
5026
5119
  }
5027
5120
  get configs() {
@@ -5032,7 +5125,7 @@ class Engine {
5032
5125
  return res;
5033
5126
  }
5034
5127
  get version() {
5035
- return "3.0.0-beta.3";
5128
+ return "3.0.0-beta.4";
5036
5129
  }
5037
5130
  addConfig(config) {
5038
5131
  const name = config.name ?? "default";
@@ -5044,6 +5137,12 @@ class Engine {
5044
5137
  }
5045
5138
  });
5046
5139
  }
5140
+ async addEffect(effect, drawer, refresh = true) {
5141
+ executeOnSingleOrMultiple(effect, type => {
5142
+ !this.getEffectDrawer(type) && this.effectDrawers.set(type, drawer);
5143
+ });
5144
+ await this.refresh(refresh);
5145
+ }
5047
5146
  addEventListener(type, listener) {
5048
5147
  this._eventDispatcher.addEventListener(type, listener);
5049
5148
  }
@@ -5073,7 +5172,7 @@ class Engine {
5073
5172
  }
5074
5173
  async addShape(shape, drawer, refresh = true) {
5075
5174
  executeOnSingleOrMultiple(shape, type => {
5076
- !this.getShapeDrawer(type) && this.drawers.set(type, drawer);
5175
+ !this.getShapeDrawer(type) && this.shapeDrawers.set(type, drawer);
5077
5176
  });
5078
5177
  await this.refresh(refresh);
5079
5178
  }
@@ -5104,6 +5203,9 @@ class Engine {
5104
5203
  }
5105
5204
  return res;
5106
5205
  }
5206
+ getEffectDrawer(type) {
5207
+ return this.effectDrawers.get(type);
5208
+ }
5107
5209
  getInteractors(container, force = false) {
5108
5210
  return getItemsFromInitializer(container, this.interactors, this._initializers.interactors, force);
5109
5211
  }
@@ -5120,10 +5222,13 @@ class Engine {
5120
5222
  return this.presets.get(preset);
5121
5223
  }
5122
5224
  getShapeDrawer(type) {
5123
- return this.drawers.get(type);
5225
+ return this.shapeDrawers.get(type);
5226
+ }
5227
+ getSupportedEffects() {
5228
+ return this.effectDrawers.keys();
5124
5229
  }
5125
5230
  getSupportedShapes() {
5126
- return this.drawers.keys();
5231
+ return this.shapeDrawers.keys();
5127
5232
  }
5128
5233
  getUpdaters(container, force = false) {
5129
5234
  return getItemsFromInitializer(container, this.updaters, this._initializers.updaters, force);
@@ -5419,7 +5524,6 @@ class ParticlesInteractorBase {
5419
5524
 
5420
5525
 
5421
5526
 
5422
-
5423
5527
 
5424
5528
 
5425
5529
  ;// CONCATENATED MODULE: ../../engine/dist/browser/index.js
@@ -5587,10 +5691,10 @@ function applyDistance(particle) {
5587
5691
  if ((hDistance && dxFixed >= hDistance || vDistance && dyFixed >= vDistance) && !particle.misplaced) {
5588
5692
  particle.misplaced = !!hDistance && dxFixed > hDistance || !!vDistance && dyFixed > vDistance;
5589
5693
  if (hDistance) {
5590
- particle.velocity.x = particle.velocity.y / 2 - particle.velocity.x;
5694
+ particle.velocity.x = particle.velocity.y * 0.5 - particle.velocity.x;
5591
5695
  }
5592
5696
  if (vDistance) {
5593
- particle.velocity.y = particle.velocity.x / 2 - particle.velocity.y;
5697
+ particle.velocity.y = particle.velocity.x * 0.5 - particle.velocity.y;
5594
5698
  }
5595
5699
  } else if ((!hDistance || dxFixed < hDistance) && (!vDistance || dyFixed < vDistance) && particle.misplaced) {
5596
5700
  particle.misplaced = false;
@@ -5648,15 +5752,16 @@ function spin(particle, moveSpeed) {
5648
5752
  particle.position.x = particle.spin.center.x + particle.spin.radius * updateFunc.x(particle.spin.angle);
5649
5753
  particle.position.y = particle.spin.center.y + particle.spin.radius * updateFunc.y(particle.spin.angle);
5650
5754
  particle.spin.radius += particle.spin.acceleration;
5651
- const maxCanvasSize = Math.max(container.canvas.size.width, container.canvas.size.height);
5652
- if (particle.spin.radius > maxCanvasSize / 2) {
5653
- particle.spin.radius = maxCanvasSize / 2;
5755
+ const maxCanvasSize = Math.max(container.canvas.size.width, container.canvas.size.height),
5756
+ halfMaxSize = maxCanvasSize * 0.5;
5757
+ if (particle.spin.radius > halfMaxSize) {
5758
+ particle.spin.radius = halfMaxSize;
5654
5759
  particle.spin.acceleration *= -1;
5655
5760
  } else if (particle.spin.radius < 0) {
5656
5761
  particle.spin.radius = 0;
5657
5762
  particle.spin.acceleration *= -1;
5658
5763
  }
5659
- particle.spin.angle += moveSpeed / 100 * (1 - particle.spin.radius / maxCanvasSize);
5764
+ particle.spin.angle += moveSpeed * 0.01 * (1 - particle.spin.radius / maxCanvasSize);
5660
5765
  }
5661
5766
  function applyPath(particle, delta) {
5662
5767
  const particlesOptions = particle.options,
@@ -5700,8 +5805,8 @@ class BaseMover {
5700
5805
  y: 50
5701
5806
  },
5702
5807
  spinCenter = {
5703
- x: spinPos.x / 100 * container.canvas.size.width,
5704
- y: spinPos.y / 100 * container.canvas.size.height
5808
+ x: spinPos.x * 0.01 * container.canvas.size.width,
5809
+ y: spinPos.y * 0.01 * container.canvas.size.height
5705
5810
  },
5706
5811
  pos = particle.getPosition(),
5707
5812
  distance = getDistance(pos, spinCenter),
@@ -6024,7 +6129,7 @@ function bounceHorizontal(data) {
6024
6129
  const velocity = data.particle.velocity.x;
6025
6130
  let bounced = false;
6026
6131
  if (data.direction === "right" && data.bounds.right >= data.canvasSize.width && velocity > 0 || data.direction === "left" && data.bounds.left <= 0 && velocity < 0) {
6027
- const newVelocity = getValue(data.particle.options.bounce.horizontal);
6132
+ const newVelocity = getRangeValue(data.particle.options.bounce.horizontal.value);
6028
6133
  data.particle.velocity.x *= -newVelocity;
6029
6134
  bounced = true;
6030
6135
  }
@@ -6053,7 +6158,7 @@ function bounceVertical(data) {
6053
6158
  const velocity = data.particle.velocity.y;
6054
6159
  let bounced = false;
6055
6160
  if (data.direction === "bottom" && data.bounds.bottom >= data.canvasSize.height && velocity > 0 || data.direction === "top" && data.bounds.top <= 0 && velocity < 0) {
6056
- const newVelocity = getValue(data.particle.options.bounce.vertical);
6161
+ const newVelocity = getRangeValue(data.particle.options.bounce.vertical.value);
6057
6162
  data.particle.velocity.y *= -newVelocity;
6058
6163
  bounced = true;
6059
6164
  }
@@ -6503,6 +6608,7 @@ class Attract {
6503
6608
  ;// CONCATENATED MODULE: ../../interactions/external/attract/dist/browser/Attractor.js
6504
6609
 
6505
6610
 
6611
+ const attractMode = "attract";
6506
6612
  class Attractor extends ExternalInteractorBase {
6507
6613
  constructor(engine, container) {
6508
6614
  super(container);
@@ -6574,7 +6680,7 @@ class Attractor extends ExternalInteractorBase {
6574
6680
  this.handleClickMode = mode => {
6575
6681
  const options = this.container.actualOptions,
6576
6682
  attract = options.interactivity.modes.attract;
6577
- if (!attract || mode !== "attract") {
6683
+ if (!attract || mode !== attractMode) {
6578
6684
  return;
6579
6685
  }
6580
6686
  if (!container.attract) {
@@ -6623,9 +6729,9 @@ class Attractor extends ExternalInteractorBase {
6623
6729
  hoverMode = events.onHover.mode,
6624
6730
  clickEnabled = events.onClick.enable,
6625
6731
  clickMode = events.onClick.mode;
6626
- if (mouseMoveStatus && hoverEnabled && isInArray("attract", hoverMode)) {
6732
+ if (mouseMoveStatus && hoverEnabled && isInArray(attractMode, hoverMode)) {
6627
6733
  this._hoverAttract();
6628
- } else if (clickEnabled && isInArray("attract", clickMode)) {
6734
+ } else if (clickEnabled && isInArray(attractMode, clickMode)) {
6629
6735
  this._clickAttract();
6630
6736
  }
6631
6737
  }
@@ -6639,7 +6745,7 @@ class Attractor extends ExternalInteractorBase {
6639
6745
  }
6640
6746
  const hoverMode = events.onHover.mode,
6641
6747
  clickMode = events.onClick.mode;
6642
- return isInArray("attract", hoverMode) || isInArray("attract", clickMode);
6748
+ return isInArray(attractMode, hoverMode) || isInArray(attractMode, clickMode);
6643
6749
  }
6644
6750
  loadModeOptions(options, ...sources) {
6645
6751
  if (!options.attract) {
@@ -6675,6 +6781,7 @@ class Bounce {
6675
6781
  ;// CONCATENATED MODULE: ../../interactions/external/bounce/dist/browser/Bouncer.js
6676
6782
 
6677
6783
 
6784
+ const bounceMode = "bounce";
6678
6785
  class Bouncer extends ExternalInteractorBase {
6679
6786
  constructor(container) {
6680
6787
  super(container);
@@ -6742,10 +6849,10 @@ class Bouncer extends ExternalInteractorBase {
6742
6849
  hoverEnabled = events.onHover.enable,
6743
6850
  hoverMode = events.onHover.mode,
6744
6851
  divs = events.onDiv;
6745
- if (mouseMoveStatus && hoverEnabled && isInArray("bounce", hoverMode)) {
6852
+ if (mouseMoveStatus && hoverEnabled && isInArray(bounceMode, hoverMode)) {
6746
6853
  this._processMouseBounce();
6747
6854
  } else {
6748
- divModeExecute("bounce", divs, (selector, div) => this._singleSelectorBounce(selector, div));
6855
+ divModeExecute(bounceMode, divs, (selector, div) => this._singleSelectorBounce(selector, div));
6749
6856
  }
6750
6857
  }
6751
6858
  isEnabled(particle) {
@@ -6754,7 +6861,7 @@ class Bouncer extends ExternalInteractorBase {
6754
6861
  mouse = container.interactivity.mouse,
6755
6862
  events = (particle?.interactivity ?? options.interactivity).events,
6756
6863
  divs = events.onDiv;
6757
- return mouse.position && events.onHover.enable && isInArray("bounce", events.onHover.mode) || isDivModeEnabled("bounce", divs);
6864
+ return mouse.position && events.onHover.enable && isInArray(bounceMode, events.onHover.mode) || isDivModeEnabled(bounceMode, divs);
6758
6865
  }
6759
6866
  loadModeOptions(options, ...sources) {
6760
6867
  if (!options.bounce) {
@@ -6857,6 +6964,7 @@ function calculateBubbleValue(particleValue, modeValue, optionsValue, ratio) {
6857
6964
 
6858
6965
 
6859
6966
 
6967
+ const bubbleMode = "bubble";
6860
6968
  class Bubbler extends ExternalInteractorBase {
6861
6969
  constructor(container) {
6862
6970
  super(container);
@@ -7093,7 +7201,7 @@ class Bubbler extends ExternalInteractorBase {
7093
7201
  container.bubble = {};
7094
7202
  }
7095
7203
  this.handleClickMode = mode => {
7096
- if (mode !== "bubble") {
7204
+ if (mode !== bubbleMode) {
7097
7205
  return;
7098
7206
  }
7099
7207
  if (!container.bubble) {
@@ -7132,12 +7240,12 @@ class Bubbler extends ExternalInteractorBase {
7132
7240
  clickEnabled = onClick.enable,
7133
7241
  clickMode = onClick.mode,
7134
7242
  divs = events.onDiv;
7135
- if (hoverEnabled && isInArray("bubble", hoverMode)) {
7243
+ if (hoverEnabled && isInArray(bubbleMode, hoverMode)) {
7136
7244
  this._hoverBubble();
7137
- } else if (clickEnabled && isInArray("bubble", clickMode)) {
7245
+ } else if (clickEnabled && isInArray(bubbleMode, clickMode)) {
7138
7246
  this._clickBubble();
7139
7247
  } else {
7140
- divModeExecute("bubble", divs, (selector, div) => this._singleSelectorHover(delta, selector, div));
7248
+ divModeExecute(bubbleMode, divs, (selector, div) => this._singleSelectorHover(delta, selector, div));
7141
7249
  }
7142
7250
  }
7143
7251
  isEnabled(particle) {
@@ -7150,11 +7258,11 @@ class Bubbler extends ExternalInteractorBase {
7150
7258
  onDiv,
7151
7259
  onHover
7152
7260
  } = events,
7153
- divBubble = isDivModeEnabled("bubble", onDiv);
7261
+ divBubble = isDivModeEnabled(bubbleMode, onDiv);
7154
7262
  if (!(divBubble || onHover.enable && mouse.position || onClick.enable && mouse.clickPosition)) {
7155
7263
  return false;
7156
7264
  }
7157
- return isInArray("bubble", onHover.mode) || isInArray("bubble", onClick.mode) || divBubble;
7265
+ return isInArray(bubbleMode, onHover.mode) || isInArray(bubbleMode, onClick.mode) || divBubble;
7158
7266
  }
7159
7267
  loadModeOptions(options, ...sources) {
7160
7268
  if (!options.bubble) {
@@ -7261,6 +7369,7 @@ function drawConnection(container, p1, p2) {
7261
7369
 
7262
7370
 
7263
7371
 
7372
+ const connectMode = "connect";
7264
7373
  class Connector extends ExternalInteractorBase {
7265
7374
  constructor(container) {
7266
7375
  super(container);
@@ -7308,7 +7417,7 @@ class Connector extends ExternalInteractorBase {
7308
7417
  if (!(events.onHover.enable && mouse.position)) {
7309
7418
  return false;
7310
7419
  }
7311
- return isInArray("connect", events.onHover.mode);
7420
+ return isInArray(connectMode, events.onHover.mode);
7312
7421
  }
7313
7422
  loadModeOptions(options, ...sources) {
7314
7423
  if (!options.connect) {
@@ -7402,6 +7511,7 @@ function drawGrab(container, particle, lineColor, opacity, mousePos) {
7402
7511
 
7403
7512
 
7404
7513
 
7514
+ const grabMode = "grab";
7405
7515
  class Grabber extends ExternalInteractorBase {
7406
7516
  constructor(container) {
7407
7517
  super(container);
@@ -7459,7 +7569,7 @@ class Grabber extends ExternalInteractorBase {
7459
7569
  const container = this.container,
7460
7570
  mouse = container.interactivity.mouse,
7461
7571
  events = (particle?.interactivity ?? container.actualOptions.interactivity).events;
7462
- return events.onHover.enable && !!mouse.position && isInArray("grab", events.onHover.mode);
7572
+ return events.onHover.enable && !!mouse.position && isInArray(grabMode, events.onHover.mode);
7463
7573
  }
7464
7574
  loadModeOptions(options, ...sources) {
7465
7575
  if (!options.grab) {
@@ -7482,11 +7592,12 @@ async function loadExternalGrabInteraction(engine, refresh = true) {
7482
7592
 
7483
7593
  ;// CONCATENATED MODULE: ../../interactions/external/pause/dist/browser/Pauser.js
7484
7594
 
7595
+ const pauseMode = "pause";
7485
7596
  class Pauser extends ExternalInteractorBase {
7486
7597
  constructor(container) {
7487
7598
  super(container);
7488
7599
  this.handleClickMode = mode => {
7489
- if (mode !== "pause") {
7600
+ if (mode !== pauseMode) {
7490
7601
  return;
7491
7602
  }
7492
7603
  const container = this.container;
@@ -7546,11 +7657,12 @@ class Push {
7546
7657
  ;// CONCATENATED MODULE: ../../interactions/external/push/dist/browser/Pusher.js
7547
7658
 
7548
7659
 
7660
+ const pushMode = "push";
7549
7661
  class Pusher extends ExternalInteractorBase {
7550
7662
  constructor(container) {
7551
7663
  super(container);
7552
7664
  this.handleClickMode = mode => {
7553
- if (mode !== "push") {
7665
+ if (mode !== pushMode) {
7554
7666
  return;
7555
7667
  }
7556
7668
  const container = this.container,
@@ -7616,13 +7728,14 @@ class Remove {
7616
7728
  ;// CONCATENATED MODULE: ../../interactions/external/remove/dist/browser/Remover.js
7617
7729
 
7618
7730
 
7731
+ const removeMode = "remove";
7619
7732
  class Remover extends ExternalInteractorBase {
7620
7733
  constructor(container) {
7621
7734
  super(container);
7622
7735
  this.handleClickMode = mode => {
7623
7736
  const container = this.container,
7624
7737
  options = container.actualOptions;
7625
- if (!options.interactivity.modes.remove || mode !== "remove") {
7738
+ if (!options.interactivity.modes.remove || mode !== removeMode) {
7626
7739
  return;
7627
7740
  }
7628
7741
  const removeNb = getRangeValue(options.interactivity.modes.remove.quantity);
@@ -7723,6 +7836,7 @@ class Repulse extends RepulseBase {
7723
7836
  ;// CONCATENATED MODULE: ../../interactions/external/repulse/dist/browser/Repulser.js
7724
7837
 
7725
7838
 
7839
+ const repulseMode = "repulse";
7726
7840
  class Repulser extends ExternalInteractorBase {
7727
7841
  constructor(engine, container) {
7728
7842
  super(container);
@@ -7795,14 +7909,21 @@ class Repulser extends ExternalInteractorBase {
7795
7909
  if (!repulseOptions) {
7796
7910
  return;
7797
7911
  }
7912
+ const {
7913
+ easing,
7914
+ speed,
7915
+ factor,
7916
+ maxSpeed
7917
+ } = repulseOptions,
7918
+ easingFunc = getEasing(easing),
7919
+ velocity = (divRepulse?.speed ?? speed) * factor;
7798
7920
  for (const particle of query) {
7799
7921
  const {
7800
7922
  dx,
7801
7923
  dy,
7802
7924
  distance
7803
7925
  } = getDistances(particle.position, position),
7804
- velocity = (divRepulse?.speed ?? repulseOptions.speed) * repulseOptions.factor,
7805
- repulseFactor = clamp(getEasing(repulseOptions.easing)(1 - distance / repulseRadius) * velocity, 0, repulseOptions.maxSpeed),
7926
+ repulseFactor = clamp(easingFunc(1 - distance / repulseRadius) * velocity, 0, maxSpeed),
7806
7927
  normVec = Vector.create(distance === 0 ? velocity : dx / distance * repulseFactor, distance === 0 ? velocity : dy / distance * repulseFactor);
7807
7928
  particle.position.addTo(normVec);
7808
7929
  }
@@ -7840,7 +7961,7 @@ class Repulser extends ExternalInteractorBase {
7840
7961
  this.handleClickMode = mode => {
7841
7962
  const options = this.container.actualOptions,
7842
7963
  repulseOpts = options.interactivity.modes.repulse;
7843
- if (!repulseOpts || mode !== "repulse") {
7964
+ if (!repulseOpts || mode !== repulseMode) {
7844
7965
  return;
7845
7966
  }
7846
7967
  if (!container.repulse) {
@@ -7888,12 +8009,12 @@ class Repulser extends ExternalInteractorBase {
7888
8009
  clickEnabled = click.enable,
7889
8010
  clickMode = click.mode,
7890
8011
  divs = events.onDiv;
7891
- if (mouseMoveStatus && hoverEnabled && isInArray("repulse", hoverMode)) {
8012
+ if (mouseMoveStatus && hoverEnabled && isInArray(repulseMode, hoverMode)) {
7892
8013
  this._hoverRepulse();
7893
- } else if (clickEnabled && isInArray("repulse", clickMode)) {
8014
+ } else if (clickEnabled && isInArray(repulseMode, clickMode)) {
7894
8015
  this._clickRepulse();
7895
8016
  } else {
7896
- divModeExecute("repulse", divs, (selector, div) => this._singleSelectorRepulse(selector, div));
8017
+ divModeExecute(repulseMode, divs, (selector, div) => this._singleSelectorRepulse(selector, div));
7897
8018
  }
7898
8019
  }
7899
8020
  isEnabled(particle) {
@@ -7904,13 +8025,13 @@ class Repulser extends ExternalInteractorBase {
7904
8025
  divs = events.onDiv,
7905
8026
  hover = events.onHover,
7906
8027
  click = events.onClick,
7907
- divRepulse = isDivModeEnabled("repulse", divs);
8028
+ divRepulse = isDivModeEnabled(repulseMode, divs);
7908
8029
  if (!(divRepulse || hover.enable && mouse.position || click.enable && mouse.clickPosition)) {
7909
8030
  return false;
7910
8031
  }
7911
8032
  const hoverMode = hover.mode,
7912
8033
  clickMode = click.mode;
7913
- return isInArray("repulse", hoverMode) || isInArray("repulse", clickMode) || divRepulse;
8034
+ return isInArray(repulseMode, hoverMode) || isInArray(repulseMode, clickMode) || divRepulse;
7914
8035
  }
7915
8036
  loadModeOptions(options, ...sources) {
7916
8037
  if (!options.repulse) {
@@ -7954,6 +8075,7 @@ class Slow {
7954
8075
  ;// CONCATENATED MODULE: ../../interactions/external/slow/dist/browser/Slower.js
7955
8076
 
7956
8077
 
8078
+ const slowMode = "slow";
7957
8079
  class Slower extends ExternalInteractorBase {
7958
8080
  constructor(container) {
7959
8081
  super(container);
@@ -7977,7 +8099,7 @@ class Slower extends ExternalInteractorBase {
7977
8099
  const container = this.container,
7978
8100
  mouse = container.interactivity.mouse,
7979
8101
  events = (particle?.interactivity ?? container.actualOptions.interactivity).events;
7980
- return events.onHover.enable && !!mouse.position && isInArray("slow", events.onHover.mode);
8102
+ return events.onHover.enable && !!mouse.position && isInArray(slowMode, events.onHover.mode);
7981
8103
  }
7982
8104
  loadModeOptions(options, ...sources) {
7983
8105
  if (!options.slow) {
@@ -8684,8 +8806,11 @@ class ImageDrawer {
8684
8806
  if (!this._engine.images) {
8685
8807
  this._engine.images = [];
8686
8808
  }
8687
- const imageData = particle.shapeData,
8688
- image = this._engine.images.find(t => t.name === imageData.name || t.source === imageData.src);
8809
+ const imageData = particle.shapeData;
8810
+ if (!imageData) {
8811
+ return;
8812
+ }
8813
+ const image = this._engine.images.find(t => t.name === imageData.name || t.source === imageData.src);
8689
8814
  if (!image) {
8690
8815
  this.loadImageShape(imageData).then(() => {
8691
8816
  this.loadShape(particle);
@@ -8700,8 +8825,11 @@ class ImageDrawer {
8700
8825
  this._engine.images = [];
8701
8826
  }
8702
8827
  const images = this._engine.images,
8703
- imageData = particle.shapeData,
8704
- color = particle.getFillColor(),
8828
+ imageData = particle.shapeData;
8829
+ if (!imageData) {
8830
+ return;
8831
+ }
8832
+ const color = particle.getFillColor(),
8705
8833
  image = images.find(t => t.name === imageData.name || t.source === imageData.src);
8706
8834
  if (!image) {
8707
8835
  return;
@@ -8734,16 +8862,16 @@ class ImageDrawer {
8734
8862
  if (!imageRes.ratio) {
8735
8863
  imageRes.ratio = 1;
8736
8864
  }
8737
- const fill = imageData.fill ?? particle.fill,
8738
- close = imageData.close ?? particle.close,
8865
+ const fill = imageData.fill ?? particle.shapeFill,
8866
+ close = imageData.close ?? particle.shapeClose,
8739
8867
  imageShape = {
8740
8868
  image: imageRes,
8741
8869
  fill,
8742
8870
  close
8743
8871
  };
8744
8872
  particle.image = imageShape.image;
8745
- particle.fill = imageShape.fill;
8746
- particle.close = imageShape.close;
8873
+ particle.shapeFill = imageShape.fill;
8874
+ particle.shapeClose = imageShape.close;
8747
8875
  })();
8748
8876
  }
8749
8877
  }
@@ -8876,7 +9004,6 @@ class LifeDelay extends ValueWithRandom {
8876
9004
  class LifeDuration extends ValueWithRandom {
8877
9005
  constructor() {
8878
9006
  super();
8879
- this.random.minimumValue = 0.0001;
8880
9007
  this.sync = false;
8881
9008
  }
8882
9009
  load(data) {
@@ -9054,8 +9181,8 @@ class ParallaxMover {
9054
9181
  }
9055
9182
  const canvasSize = container.canvas.size,
9056
9183
  canvasCenter = {
9057
- x: canvasSize.width / 2,
9058
- y: canvasSize.height / 2
9184
+ x: canvasSize.width * 0.5,
9185
+ y: canvasSize.height * 0.5
9059
9186
  },
9060
9187
  parallaxSmooth = parallaxOptions.smooth,
9061
9188
  factor = particle.getRadius() / parallaxForce,
@@ -9084,8 +9211,11 @@ class Attractor_Attractor extends ParticlesInteractorBase {
9084
9211
  clear() {}
9085
9212
  init() {}
9086
9213
  async interact(p1) {
9087
- const container = this.container,
9088
- distance = p1.retina.attractDistance ?? container.retina.attractDistance,
9214
+ const container = this.container;
9215
+ if (p1.attractDistance === undefined) {
9216
+ p1.attractDistance = getRangeValue(p1.options.move.attract.distance) * container.retina.pixelRatio;
9217
+ }
9218
+ const distance = p1.attractDistance,
9089
9219
  pos1 = p1.getPosition(),
9090
9220
  query = container.particles.quadTree.queryCircle(pos1, distance);
9091
9221
  for (const p2 of query) {
@@ -9502,6 +9632,13 @@ async function loadLinksInteraction(engine, refresh = true) {
9502
9632
  }
9503
9633
  ;// CONCATENATED MODULE: ../../interactions/particles/links/dist/browser/Utils.js
9504
9634
 
9635
+ function drawTriangle(context, p1, p2, p3) {
9636
+ context.beginPath();
9637
+ context.moveTo(p1.x, p1.y);
9638
+ context.lineTo(p2.x, p2.y);
9639
+ context.lineTo(p3.x, p3.y);
9640
+ context.closePath();
9641
+ }
9505
9642
  function drawLinkLine(params) {
9506
9643
  let drawn = false;
9507
9644
  const {
@@ -10238,8 +10375,22 @@ async function loadStrokeColorUpdater(engine, refresh = true) {
10238
10375
  }
10239
10376
  ;// CONCATENATED MODULE: ../../shapes/text/dist/browser/TextDrawer.js
10240
10377
 
10241
- const validTypes = ["text", "character", "char"];
10378
+ const validTypes = ["text", "character", "char", "multiline-text"];
10242
10379
  class TextDrawer {
10380
+ constructor() {
10381
+ this._drawLine = (context, line, radius, opacity, index, fill) => {
10382
+ const offsetX = line.length * radius / 2,
10383
+ pos = {
10384
+ x: -offsetX,
10385
+ y: radius / 2
10386
+ };
10387
+ if (fill) {
10388
+ context.fillText(line, pos.x, pos.y + radius * 2 * index);
10389
+ } else {
10390
+ context.strokeText(line, pos.x, pos.y + radius * 2 * index);
10391
+ }
10392
+ };
10393
+ }
10243
10394
  draw(data) {
10244
10395
  const {
10245
10396
  context,
@@ -10248,7 +10399,7 @@ class TextDrawer {
10248
10399
  opacity
10249
10400
  } = data,
10250
10401
  character = particle.shapeData;
10251
- if (character === undefined) {
10402
+ if (!character) {
10252
10403
  return;
10253
10404
  }
10254
10405
  const textData = character.value;
@@ -10263,24 +10414,18 @@ class TextDrawer {
10263
10414
  weight = character.weight ?? "400",
10264
10415
  size = Math.round(radius) * 2,
10265
10416
  font = character.font ?? "Verdana",
10266
- fill = particle.fill,
10267
- offsetX = text.length * radius / 2;
10417
+ fill = particle.shapeFill;
10418
+ const lines = text?.split("\n");
10419
+ if (!lines) {
10420
+ return;
10421
+ }
10268
10422
  context.font = `${style} ${weight} ${size}px "${font}"`;
10269
- const pos = {
10270
- x: -offsetX,
10271
- y: radius / 2
10272
- };
10273
10423
  context.globalAlpha = opacity;
10274
- if (fill) {
10275
- context.fillText(text, pos.x, pos.y);
10276
- } else {
10277
- context.strokeText(text, pos.x, pos.y);
10424
+ for (let i = 0; i < lines.length; i++) {
10425
+ this._drawLine(context, lines[i], radius, opacity, i, fill);
10278
10426
  }
10279
10427
  context.globalAlpha = 1;
10280
10428
  }
10281
- getSidesCount() {
10282
- return 12;
10283
- }
10284
10429
  async init(container) {
10285
10430
  const options = container.actualOptions;
10286
10431
  if (validTypes.find(t => isInArray(t, options.particles.shape.type))) {