tsparticles 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),
@@ -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: ../../engine/dist/browser/Options/Classes/ColorAnimation.js
2547
+ ;// CONCATENATED MODULE: ../../engine/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: ../../engine/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: ../../engine/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: ../../engine/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: ../../engine/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: ../../engine/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: ../../engine/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: ../../engine/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: ../../engine/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: ../../engine/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: ../../engine/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: ../../engine/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);
3973
4011
  }
3974
4012
  }
3975
- if (drawer && drawer.loadShape) {
3976
- drawer.loadShape(this);
4013
+ if (effectDrawer && effectDrawer.loadEffect) {
4014
+ effectDrawer.loadEffect(this);
3977
4015
  }
3978
- const sideCountFunc = drawer?.getSidesCount;
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);
4021
+ }
4022
+ }
4023
+ if (shapeDrawer && shapeDrawer.loadShape) {
4024
+ shapeDrawer.loadShape(this);
4025
+ }
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: ../../engine/dist/browser/index.js
@@ -5896,7 +6000,7 @@ function addSplitParticle(engine, container, parent, splitParticlesOptions) {
5896
6000
  }
5897
6001
  const splitOptions = destroyOptions.split,
5898
6002
  options = loadParticlesOptions(engine, container, parent.options),
5899
- factor = getValue(splitOptions.factor),
6003
+ factor = getRangeValue(splitOptions.factor.value),
5900
6004
  parentColor = parent.getFillColor();
5901
6005
  if (splitOptions.color) {
5902
6006
  options.color.load(splitOptions.color);
@@ -5958,7 +6062,7 @@ function split(engine, container, particle) {
5958
6062
  if (splitOptions.count >= 0 && (particle.splitCount === undefined || particle.splitCount++ > splitOptions.count)) {
5959
6063
  return;
5960
6064
  }
5961
- const rate = getValue(splitOptions.rate),
6065
+ const rate = getRangeValue(splitOptions.rate.value),
5962
6066
  particlesSplitOptions = itemFromSingleOrMultiple(splitOptions.particles);
5963
6067
  for (let i = 0; i < rate; i++) {
5964
6068
  addSplitParticle(engine, container, particle, particlesSplitOptions);
@@ -6047,35 +6151,6 @@ class DestroyUpdater {
6047
6151
  async function loadDestroyUpdater(engine, refresh = true) {
6048
6152
  await engine.addParticleUpdater("destroy", container => new DestroyUpdater(engine, container), refresh);
6049
6153
  }
6050
- ;// CONCATENATED MODULE: ../../plugins/emitters/dist/browser/Shapes/Circle/CircleShape.js
6051
-
6052
- class CircleShape {
6053
- randomPosition(position, size, fill) {
6054
- const generateTheta = (x, y) => {
6055
- const u = getRandom() / 4.0,
6056
- theta = Math.atan(y / x * Math.tan(2 * Math.PI * u)),
6057
- v = getRandom();
6058
- if (v < 0.25) {
6059
- return theta;
6060
- } else if (v < 0.5) {
6061
- return Math.PI - theta;
6062
- } else if (v < 0.75) {
6063
- return Math.PI + theta;
6064
- } else {
6065
- return -theta;
6066
- }
6067
- },
6068
- radius = (x, y, theta) => x * y / Math.sqrt((y * Math.cos(theta)) ** 2 + (x * Math.sin(theta)) ** 2),
6069
- [a, b] = [size.width / 2, size.height / 2],
6070
- randomTheta = generateTheta(a, b),
6071
- maxRadius = radius(a, b, randomTheta),
6072
- randomRadius = fill ? maxRadius * Math.sqrt(getRandom()) : maxRadius;
6073
- return {
6074
- x: position.x + randomRadius * Math.cos(randomTheta),
6075
- y: position.y + randomRadius * Math.sin(randomTheta)
6076
- };
6077
- }
6078
- }
6079
6154
  ;// CONCATENATED MODULE: ../../plugins/emitters/dist/browser/Options/Classes/EmitterLife.js
6080
6155
 
6081
6156
  class EmitterLife {
@@ -6119,6 +6194,46 @@ class EmitterRate {
6119
6194
  }
6120
6195
  }
6121
6196
  }
6197
+ ;// CONCATENATED MODULE: ../../plugins/emitters/dist/browser/Options/Classes/EmitterShapeReplace.js
6198
+ class EmitterShapeReplace {
6199
+ constructor() {
6200
+ this.color = false;
6201
+ this.opacity = false;
6202
+ }
6203
+ load(data) {
6204
+ if (!data) {
6205
+ return;
6206
+ }
6207
+ if (data.color !== undefined) {
6208
+ this.color = data.color;
6209
+ }
6210
+ if (data.opacity !== undefined) {
6211
+ this.opacity = data.opacity;
6212
+ }
6213
+ }
6214
+ }
6215
+ ;// CONCATENATED MODULE: ../../plugins/emitters/dist/browser/Options/Classes/EmitterShape.js
6216
+
6217
+
6218
+ class EmitterShape {
6219
+ constructor() {
6220
+ this.options = {};
6221
+ this.replace = new EmitterShapeReplace();
6222
+ this.type = "square";
6223
+ }
6224
+ load(data) {
6225
+ if (!data) {
6226
+ return;
6227
+ }
6228
+ if (data.options !== undefined) {
6229
+ this.options = deepExtend({}, data.options ?? {});
6230
+ }
6231
+ this.replace.load(data.replace);
6232
+ if (data.type !== undefined) {
6233
+ this.type = data.type;
6234
+ }
6235
+ }
6236
+ }
6122
6237
  ;// CONCATENATED MODULE: ../../plugins/emitters/dist/browser/Options/Classes/EmitterSize.js
6123
6238
  class EmitterSize {
6124
6239
  constructor() {
@@ -6146,13 +6261,14 @@ class EmitterSize {
6146
6261
 
6147
6262
 
6148
6263
 
6264
+
6149
6265
  class Emitter {
6150
6266
  constructor() {
6151
6267
  this.autoPlay = true;
6152
6268
  this.fill = true;
6153
6269
  this.life = new EmitterLife();
6154
6270
  this.rate = new EmitterRate();
6155
- this.shape = "square";
6271
+ this.shape = new EmitterShape();
6156
6272
  this.startCount = 0;
6157
6273
  }
6158
6274
  load(data) {
@@ -6181,9 +6297,7 @@ class Emitter {
6181
6297
  return deepExtend({}, particles);
6182
6298
  });
6183
6299
  this.rate.load(data.rate);
6184
- if (data.shape !== undefined) {
6185
- this.shape = data.shape;
6186
- }
6300
+ this.shape.load(data.shape);
6187
6301
  if (data.position !== undefined) {
6188
6302
  this.position = {};
6189
6303
  if (data.position.x !== undefined) {
@@ -6208,17 +6322,24 @@ class Emitter {
6208
6322
 
6209
6323
 
6210
6324
 
6325
+ function setParticlesOptionsColor(particlesOptions, color) {
6326
+ if (particlesOptions.color) {
6327
+ particlesOptions.color.value = color;
6328
+ } else {
6329
+ particlesOptions.color = {
6330
+ value: color
6331
+ };
6332
+ }
6333
+ }
6211
6334
  class EmitterInstance {
6212
6335
  constructor(engine, emitters, container, options, position) {
6213
6336
  this.emitters = emitters;
6214
6337
  this.container = container;
6215
- this._calcPosition = () => {
6216
- return calcPositionOrRandomFromSizeRanged({
6217
- size: this.container.canvas.size,
6218
- position: this.options.position
6219
- });
6220
- };
6221
6338
  this._destroy = () => {
6339
+ this._mutationObserver?.disconnect();
6340
+ this._mutationObserver = undefined;
6341
+ this._resizeObserver?.disconnect();
6342
+ this._resizeObserver = undefined;
6222
6343
  this.emitters.removeEmitter(this);
6223
6344
  this._engine.dispatchEvent("emitterDestroyed", {
6224
6345
  container: this.container,
@@ -6227,41 +6348,6 @@ class EmitterInstance {
6227
6348
  }
6228
6349
  });
6229
6350
  };
6230
- this._emit = () => {
6231
- if (this._paused) {
6232
- return;
6233
- }
6234
- const quantity = getRangeValue(this.options.rate.quantity);
6235
- this._emitParticles(quantity);
6236
- };
6237
- this._emitParticles = quantity => {
6238
- const position = this.getPosition(),
6239
- size = this.getSize(),
6240
- singleParticlesOptions = itemFromSingleOrMultiple(this._particlesOptions);
6241
- for (let i = 0; i < quantity; i++) {
6242
- const particlesOptions = deepExtend({}, singleParticlesOptions);
6243
- if (this.spawnColor) {
6244
- const hslAnimation = this.options.spawnColor?.animation;
6245
- if (hslAnimation) {
6246
- this.spawnColor.h = this._setColorAnimation(hslAnimation.h, this.spawnColor.h, 360);
6247
- this.spawnColor.s = this._setColorAnimation(hslAnimation.s, this.spawnColor.s, 100);
6248
- this.spawnColor.l = this._setColorAnimation(hslAnimation.l, this.spawnColor.l, 100);
6249
- }
6250
- if (!particlesOptions.color) {
6251
- particlesOptions.color = {
6252
- value: this.spawnColor
6253
- };
6254
- } else {
6255
- particlesOptions.color.value = this.spawnColor;
6256
- }
6257
- }
6258
- if (!position) {
6259
- return;
6260
- }
6261
- const pPosition = this._shape?.randomPosition(position, size, this.fill) ?? position;
6262
- this.container.particles.addParticle(pPosition, particlesOptions);
6263
- }
6264
- };
6265
6351
  this._prepareToDie = () => {
6266
6352
  if (this._paused) {
6267
6353
  return;
@@ -6296,7 +6382,6 @@ class EmitterInstance {
6296
6382
  this._spawnDelay = getRangeValue(this.options.life.delay ?? 0) * 1000 / this.container.retina.reduceFactor;
6297
6383
  this.position = this._initialPosition ?? this._calcPosition();
6298
6384
  this.name = this.options.name;
6299
- this._shape = this._engine.emitterShapeManager?.getShape(this.options.shape);
6300
6385
  this.fill = this.options.fill;
6301
6386
  this._firstSpawn = !this.options.life.wait;
6302
6387
  this._startParticlesAdded = false;
@@ -6309,17 +6394,31 @@ class EmitterInstance {
6309
6394
  }
6310
6395
  this._paused = !this.options.autoPlay;
6311
6396
  this._particlesOptions = particlesOptions;
6312
- this.size = this.options.size ?? (() => {
6313
- const size = new EmitterSize();
6314
- size.load({
6315
- height: 0,
6316
- mode: "percent",
6317
- width: 0
6318
- });
6319
- return size;
6320
- })();
6397
+ this._size = this._calcSize();
6398
+ this.size = getSize(this._size, this.container.canvas.size);
6321
6399
  this._lifeCount = this.options.life.count ?? -1;
6322
6400
  this._immortal = this._lifeCount <= 0;
6401
+ if (this.options.domId) {
6402
+ const element = document.getElementById(this.options.domId);
6403
+ if (element) {
6404
+ this._mutationObserver = new MutationObserver(() => {
6405
+ this.resize();
6406
+ });
6407
+ this._resizeObserver = new ResizeObserver(() => {
6408
+ this.resize();
6409
+ });
6410
+ this._mutationObserver.observe(element, {
6411
+ attributes: true,
6412
+ attributeFilter: ["style", "width", "height"]
6413
+ });
6414
+ this._resizeObserver.observe(element);
6415
+ }
6416
+ }
6417
+ const shapeOptions = this.options.shape,
6418
+ shapeGenerator = this._engine.emitterShapeManager?.getShapeGenerator(shapeOptions.type);
6419
+ if (shapeGenerator) {
6420
+ this._shape = shapeGenerator.generate(this.position, this.size, this.fill, shapeOptions.options);
6421
+ }
6323
6422
  this._engine.dispatchEvent("emitterCreated", {
6324
6423
  container,
6325
6424
  data: {
@@ -6336,33 +6435,8 @@ class EmitterInstance {
6336
6435
  this._paused = false;
6337
6436
  this.play();
6338
6437
  }
6339
- getPosition() {
6340
- if (this.options.domId) {
6341
- const container = this.container,
6342
- element = document.getElementById(this.options.domId);
6343
- if (element) {
6344
- const elRect = element.getBoundingClientRect();
6345
- return {
6346
- x: (elRect.x + elRect.width / 2) * container.retina.pixelRatio,
6347
- y: (elRect.y + elRect.height / 2) * container.retina.pixelRatio
6348
- };
6349
- }
6350
- }
6351
- return this.position;
6352
- }
6353
- getSize() {
6354
- const container = this.container;
6355
- if (this.options.domId) {
6356
- const element = document.getElementById(this.options.domId);
6357
- if (element) {
6358
- const elRect = element.getBoundingClientRect();
6359
- return {
6360
- width: elRect.width * container.retina.pixelRatio,
6361
- height: elRect.height * container.retina.pixelRatio
6362
- };
6363
- }
6364
- }
6365
- return getSize(this.size, container.canvas.size);
6438
+ async init() {
6439
+ await this._shape?.init();
6366
6440
  }
6367
6441
  pause() {
6368
6442
  if (this._paused) {
@@ -6388,8 +6462,11 @@ class EmitterInstance {
6388
6462
  resize() {
6389
6463
  const initialPosition = this._initialPosition;
6390
6464
  this.position = initialPosition && isPointInside(initialPosition, this.container.canvas.size, Vector.origin) ? initialPosition : this._calcPosition();
6465
+ this._size = this._calcSize();
6466
+ this.size = getSize(this._size, this.container.canvas.size);
6467
+ this._shape?.resize(this.position, this.size);
6391
6468
  }
6392
- update(delta) {
6469
+ async update(delta) {
6393
6470
  if (this._paused) {
6394
6471
  return;
6395
6472
  }
@@ -6400,7 +6477,7 @@ class EmitterInstance {
6400
6477
  }
6401
6478
  if (!this._startParticlesAdded) {
6402
6479
  this._startParticlesAdded = true;
6403
- this._emitParticles(this.options.startCount);
6480
+ await this._emitParticles(this.options.startCount);
6404
6481
  }
6405
6482
  if (this._duration !== undefined) {
6406
6483
  this._currentDuration += delta.value;
@@ -6441,6 +6518,94 @@ class EmitterInstance {
6441
6518
  }
6442
6519
  }
6443
6520
  }
6521
+ _calcPosition() {
6522
+ if (this.options.domId) {
6523
+ const container = this.container,
6524
+ element = document.getElementById(this.options.domId);
6525
+ if (element) {
6526
+ const elRect = element.getBoundingClientRect();
6527
+ return {
6528
+ x: (elRect.x + elRect.width / 2) * container.retina.pixelRatio,
6529
+ y: (elRect.y + elRect.height / 2) * container.retina.pixelRatio
6530
+ };
6531
+ }
6532
+ }
6533
+ return calcPositionOrRandomFromSizeRanged({
6534
+ size: this.container.canvas.size,
6535
+ position: this.options.position
6536
+ });
6537
+ }
6538
+ _calcSize() {
6539
+ const container = this.container;
6540
+ if (this.options.domId) {
6541
+ const element = document.getElementById(this.options.domId);
6542
+ if (element) {
6543
+ const elRect = element.getBoundingClientRect();
6544
+ return {
6545
+ width: elRect.width * container.retina.pixelRatio,
6546
+ height: elRect.height * container.retina.pixelRatio,
6547
+ mode: "precise"
6548
+ };
6549
+ }
6550
+ }
6551
+ return this.options.size ?? (() => {
6552
+ const size = new EmitterSize();
6553
+ size.load({
6554
+ height: 0,
6555
+ mode: "percent",
6556
+ width: 0
6557
+ });
6558
+ return size;
6559
+ })();
6560
+ }
6561
+ async _emit() {
6562
+ if (this._paused) {
6563
+ return;
6564
+ }
6565
+ const quantity = getRangeValue(this.options.rate.quantity);
6566
+ await this._emitParticles(quantity);
6567
+ }
6568
+ async _emitParticles(quantity) {
6569
+ const singleParticlesOptions = itemFromSingleOrMultiple(this._particlesOptions);
6570
+ for (let i = 0; i < quantity; i++) {
6571
+ const particlesOptions = deepExtend({}, singleParticlesOptions);
6572
+ if (this.spawnColor) {
6573
+ const hslAnimation = this.options.spawnColor?.animation;
6574
+ if (hslAnimation) {
6575
+ this.spawnColor.h = this._setColorAnimation(hslAnimation.h, this.spawnColor.h, 360);
6576
+ this.spawnColor.s = this._setColorAnimation(hslAnimation.s, this.spawnColor.s, 100);
6577
+ this.spawnColor.l = this._setColorAnimation(hslAnimation.l, this.spawnColor.l, 100);
6578
+ }
6579
+ setParticlesOptionsColor(particlesOptions, this.spawnColor);
6580
+ }
6581
+ const shapeOptions = this.options.shape;
6582
+ let position = this.position;
6583
+ if (this._shape) {
6584
+ const shapePosData = await this._shape.randomPosition();
6585
+ if (shapePosData) {
6586
+ position = shapePosData.position;
6587
+ const replaceData = shapeOptions.replace;
6588
+ if (replaceData.color && shapePosData.color) {
6589
+ setParticlesOptionsColor(particlesOptions, shapePosData.color);
6590
+ }
6591
+ if (replaceData.opacity) {
6592
+ if (particlesOptions.opacity) {
6593
+ particlesOptions.opacity.value = shapePosData.opacity;
6594
+ } else {
6595
+ particlesOptions.opacity = {
6596
+ value: shapePosData.opacity
6597
+ };
6598
+ }
6599
+ }
6600
+ } else {
6601
+ position = null;
6602
+ }
6603
+ }
6604
+ if (position) {
6605
+ this.container.particles.addParticle(position, particlesOptions);
6606
+ }
6607
+ }
6608
+ }
6444
6609
  }
6445
6610
  ;// CONCATENATED MODULE: ../../plugins/emitters/dist/browser/Emitters.js
6446
6611
 
@@ -6460,7 +6625,7 @@ class Emitters {
6460
6625
  value: []
6461
6626
  };
6462
6627
  container.getEmitter = idxOrName => idxOrName === undefined || isNumber(idxOrName) ? this.array[idxOrName || 0] : this.array.find(t => t.name === idxOrName);
6463
- container.addEmitter = (options, position) => this.addEmitter(options, position);
6628
+ container.addEmitter = async (options, position) => this.addEmitter(options, position);
6464
6629
  container.removeEmitter = idxOrName => {
6465
6630
  const emitter = container.getEmitter(idxOrName);
6466
6631
  if (emitter) {
@@ -6480,10 +6645,11 @@ class Emitters {
6480
6645
  }
6481
6646
  };
6482
6647
  }
6483
- addEmitter(options, position) {
6648
+ async addEmitter(options, position) {
6484
6649
  const emitterOptions = new Emitter();
6485
6650
  emitterOptions.load(options);
6486
6651
  const emitter = new EmitterInstance(this._engine, this, this.container, emitterOptions, position);
6652
+ await emitter.init();
6487
6653
  this.array.push(emitter);
6488
6654
  return emitter;
6489
6655
  }
@@ -6527,10 +6693,10 @@ class Emitters {
6527
6693
  }
6528
6694
  if (isArray(this.emitters)) {
6529
6695
  for (const emitterOptions of this.emitters) {
6530
- this.addEmitter(emitterOptions);
6696
+ await this.addEmitter(emitterOptions);
6531
6697
  }
6532
6698
  } else {
6533
- this.addEmitter(this.emitters);
6699
+ await this.addEmitter(this.emitters);
6534
6700
  }
6535
6701
  }
6536
6702
  pause() {
@@ -6557,71 +6723,41 @@ class Emitters {
6557
6723
  stop() {
6558
6724
  this.array = [];
6559
6725
  }
6560
- update(delta) {
6726
+ async update(delta) {
6561
6727
  for (const emitter of this.array) {
6562
- emitter.update(delta);
6728
+ await emitter.update(delta);
6563
6729
  }
6564
6730
  }
6565
6731
  }
6566
6732
  ;// CONCATENATED MODULE: ../../plugins/emitters/dist/browser/ShapeManager.js
6567
- const shapes = new Map();
6733
+ const shapeGeneratorss = new Map();
6568
6734
  class ShapeManager {
6569
6735
  constructor(engine) {
6570
6736
  this._engine = engine;
6571
6737
  }
6572
- addShape(name, drawer) {
6573
- if (!this.getShape(name)) {
6574
- shapes.set(name, drawer);
6738
+ addShapeGenerator(name, generator) {
6739
+ if (!this.getShapeGenerator(name)) {
6740
+ shapeGeneratorss.set(name, generator);
6575
6741
  }
6576
6742
  }
6577
- getShape(name) {
6578
- return shapes.get(name);
6743
+ getShapeGenerator(name) {
6744
+ return shapeGeneratorss.get(name);
6579
6745
  }
6580
- getSupportedShapes() {
6581
- return shapes.keys();
6746
+ getSupportedShapeGenerators() {
6747
+ return shapeGeneratorss.keys();
6582
6748
  }
6583
6749
  }
6584
- ;// CONCATENATED MODULE: ../../plugins/emitters/dist/browser/Shapes/Square/SquareShape.js
6585
-
6586
- function randomSquareCoordinate(position, offset) {
6587
- return position + offset * (getRandom() - 0.5);
6588
- }
6589
- class SquareShape {
6590
- randomPosition(position, size, fill) {
6591
- if (fill) {
6592
- return {
6593
- x: randomSquareCoordinate(position.x, size.width),
6594
- y: randomSquareCoordinate(position.y, size.height)
6595
- };
6596
- } else {
6597
- const halfW = size.width / 2,
6598
- halfH = size.height / 2,
6599
- side = Math.floor(getRandom() * 4),
6600
- v = (getRandom() - 0.5) * 2;
6601
- switch (side) {
6602
- case 0:
6603
- return {
6604
- x: position.x + v * halfW,
6605
- y: position.y - halfH
6606
- };
6607
- case 1:
6608
- return {
6609
- x: position.x - halfW,
6610
- y: position.y + v * halfH
6611
- };
6612
- case 2:
6613
- return {
6614
- x: position.x + v * halfW,
6615
- y: position.y + halfH
6616
- };
6617
- case 3:
6618
- default:
6619
- return {
6620
- x: position.x + halfW,
6621
- y: position.y + v * halfH
6622
- };
6623
- }
6624
- }
6750
+ ;// CONCATENATED MODULE: ../../plugins/emitters/dist/browser/EmitterShapeBase.js
6751
+ class EmitterShapeBase {
6752
+ constructor(position, size, fill, options) {
6753
+ this.position = position;
6754
+ this.size = size;
6755
+ this.fill = fill;
6756
+ this.options = options;
6757
+ }
6758
+ resize(position, size) {
6759
+ this.position = position;
6760
+ this.size = size;
6625
6761
  }
6626
6762
  }
6627
6763
  ;// CONCATENATED MODULE: ../../plugins/emitters/dist/browser/index.js
@@ -6629,8 +6765,6 @@ class SquareShape {
6629
6765
 
6630
6766
 
6631
6767
 
6632
-
6633
-
6634
6768
  class EmittersPlugin {
6635
6769
  constructor(engine) {
6636
6770
  this._engine = engine;
@@ -6715,20 +6849,149 @@ async function loadEmittersPlugin(engine, refresh = true) {
6715
6849
  if (!engine.emitterShapeManager) {
6716
6850
  engine.emitterShapeManager = new ShapeManager(engine);
6717
6851
  }
6718
- if (!engine.addEmitterShape) {
6719
- engine.addEmitterShape = (name, shape) => {
6720
- engine.emitterShapeManager?.addShape(name, shape);
6852
+ if (!engine.addEmitterShapeGenerator) {
6853
+ engine.addEmitterShapeGenerator = (name, generator) => {
6854
+ engine.emitterShapeManager?.addShapeGenerator(name, generator);
6721
6855
  };
6722
6856
  }
6723
6857
  const plugin = new EmittersPlugin(engine);
6724
6858
  await engine.addPlugin(plugin, refresh);
6725
- engine.addEmitterShape("circle", new CircleShape());
6726
- engine.addEmitterShape("square", new SquareShape());
6727
6859
  }
6728
6860
 
6729
6861
 
6730
6862
 
6731
6863
 
6864
+
6865
+
6866
+
6867
+ ;// CONCATENATED MODULE: ../../plugins/emittersShapes/circle/dist/browser/EmittersCircleShape.js
6868
+
6869
+
6870
+ class EmittersCircleShape extends EmitterShapeBase {
6871
+ constructor(position, size, fill, options) {
6872
+ super(position, size, fill, options);
6873
+ }
6874
+ async init() {}
6875
+ async randomPosition() {
6876
+ const size = this.size,
6877
+ fill = this.fill,
6878
+ position = this.position,
6879
+ generateTheta = (x, y) => {
6880
+ const u = getRandom() / 4.0,
6881
+ theta = Math.atan(y / x * Math.tan(2 * Math.PI * u)),
6882
+ v = getRandom();
6883
+ if (v < 0.25) {
6884
+ return theta;
6885
+ } else if (v < 0.5) {
6886
+ return Math.PI - theta;
6887
+ } else if (v < 0.75) {
6888
+ return Math.PI + theta;
6889
+ } else {
6890
+ return -theta;
6891
+ }
6892
+ },
6893
+ radius = (x, y, theta) => x * y / Math.sqrt((y * Math.cos(theta)) ** 2 + (x * Math.sin(theta)) ** 2),
6894
+ [a, b] = [size.width / 2, size.height / 2],
6895
+ randomTheta = generateTheta(a, b),
6896
+ maxRadius = radius(a, b, randomTheta),
6897
+ randomRadius = fill ? maxRadius * Math.sqrt(getRandom()) : maxRadius;
6898
+ return {
6899
+ position: {
6900
+ x: position.x + randomRadius * Math.cos(randomTheta),
6901
+ y: position.y + randomRadius * Math.sin(randomTheta)
6902
+ }
6903
+ };
6904
+ }
6905
+ }
6906
+ ;// CONCATENATED MODULE: ../../plugins/emittersShapes/circle/dist/browser/EmittersCircleShapeGenerator.js
6907
+
6908
+ class EmittersCircleShapeGenerator {
6909
+ generate(position, size, fill, options) {
6910
+ return new EmittersCircleShape(position, size, fill, options);
6911
+ }
6912
+ }
6913
+ ;// CONCATENATED MODULE: ../../plugins/emittersShapes/circle/dist/browser/index.js
6914
+
6915
+ async function loadEmittersShapeCircle(engine, refresh = true) {
6916
+ const emittersEngine = engine;
6917
+ emittersEngine.addEmitterShapeGenerator && emittersEngine.addEmitterShapeGenerator("circle", new EmittersCircleShapeGenerator());
6918
+ await emittersEngine.refresh(refresh);
6919
+ }
6920
+ ;// CONCATENATED MODULE: ../../plugins/emittersShapes/square/dist/browser/EmittersSquareShape.js
6921
+
6922
+
6923
+ function randomSquareCoordinate(position, offset) {
6924
+ return position + offset * (getRandom() - 0.5);
6925
+ }
6926
+ class EmittersSquareShape extends EmitterShapeBase {
6927
+ constructor(position, size, fill, options) {
6928
+ super(position, size, fill, options);
6929
+ }
6930
+ async init() {}
6931
+ async randomPosition() {
6932
+ const fill = this.fill,
6933
+ position = this.position,
6934
+ size = this.size;
6935
+ if (fill) {
6936
+ return {
6937
+ position: {
6938
+ x: randomSquareCoordinate(position.x, size.width),
6939
+ y: randomSquareCoordinate(position.y, size.height)
6940
+ }
6941
+ };
6942
+ } else {
6943
+ const halfW = size.width / 2,
6944
+ halfH = size.height / 2,
6945
+ side = Math.floor(getRandom() * 4),
6946
+ v = (getRandom() - 0.5) * 2;
6947
+ switch (side) {
6948
+ case 0:
6949
+ return {
6950
+ position: {
6951
+ x: position.x + v * halfW,
6952
+ y: position.y - halfH
6953
+ }
6954
+ };
6955
+ case 1:
6956
+ return {
6957
+ position: {
6958
+ x: position.x - halfW,
6959
+ y: position.y + v * halfH
6960
+ }
6961
+ };
6962
+ case 2:
6963
+ return {
6964
+ position: {
6965
+ x: position.x + v * halfW,
6966
+ y: position.y + halfH
6967
+ }
6968
+ };
6969
+ case 3:
6970
+ default:
6971
+ return {
6972
+ position: {
6973
+ x: position.x + halfW,
6974
+ y: position.y + v * halfH
6975
+ }
6976
+ };
6977
+ }
6978
+ }
6979
+ }
6980
+ }
6981
+ ;// CONCATENATED MODULE: ../../plugins/emittersShapes/square/dist/browser/EmittersSquareShapeGenerator.js
6982
+
6983
+ class EmittersSquareShapeGenerator {
6984
+ generate(position, size, fill, options) {
6985
+ return new EmittersSquareShape(position, size, fill, options);
6986
+ }
6987
+ }
6988
+ ;// CONCATENATED MODULE: ../../plugins/emittersShapes/square/dist/browser/index.js
6989
+
6990
+ async function loadEmittersShapeSquare(engine, refresh = true) {
6991
+ const emittersEngine = engine;
6992
+ emittersEngine.addEmitterShapeGenerator && emittersEngine.addEmitterShapeGenerator("square", new EmittersSquareShapeGenerator());
6993
+ await emittersEngine.refresh(refresh);
6994
+ }
6732
6995
  ;// CONCATENATED MODULE: ../../interactions/external/trail/dist/browser/Options/Classes/Trail.js
6733
6996
 
6734
6997
  class Trail {
@@ -6758,6 +7021,7 @@ class Trail {
6758
7021
  ;// CONCATENATED MODULE: ../../interactions/external/trail/dist/browser/TrailMaker.js
6759
7022
 
6760
7023
 
7024
+ const trailMode = "trail";
6761
7025
  class TrailMaker extends ExternalInteractorBase {
6762
7026
  constructor(container) {
6763
7027
  super(container);
@@ -6804,7 +7068,7 @@ class TrailMaker extends ExternalInteractorBase {
6804
7068
  options = container.actualOptions,
6805
7069
  mouse = container.interactivity.mouse,
6806
7070
  events = (particle?.interactivity ?? options.interactivity).events;
6807
- return mouse.clicking && mouse.inside && !!mouse.position && isInArray("trail", events.onClick.mode) || mouse.inside && !!mouse.position && isInArray("trail", events.onHover.mode);
7071
+ return mouse.clicking && mouse.inside && !!mouse.position && isInArray(trailMode, events.onClick.mode) || mouse.inside && !!mouse.position && isInArray(trailMode, events.onHover.mode);
6808
7072
  }
6809
7073
  loadModeOptions(options, ...sources) {
6810
7074
  if (!options.trail) {
@@ -7122,10 +7386,10 @@ function applyDistance(particle) {
7122
7386
  if ((hDistance && dxFixed >= hDistance || vDistance && dyFixed >= vDistance) && !particle.misplaced) {
7123
7387
  particle.misplaced = !!hDistance && dxFixed > hDistance || !!vDistance && dyFixed > vDistance;
7124
7388
  if (hDistance) {
7125
- particle.velocity.x = particle.velocity.y / 2 - particle.velocity.x;
7389
+ particle.velocity.x = particle.velocity.y * 0.5 - particle.velocity.x;
7126
7390
  }
7127
7391
  if (vDistance) {
7128
- particle.velocity.y = particle.velocity.x / 2 - particle.velocity.y;
7392
+ particle.velocity.y = particle.velocity.x * 0.5 - particle.velocity.y;
7129
7393
  }
7130
7394
  } else if ((!hDistance || dxFixed < hDistance) && (!vDistance || dyFixed < vDistance) && particle.misplaced) {
7131
7395
  particle.misplaced = false;
@@ -7183,15 +7447,16 @@ function spin(particle, moveSpeed) {
7183
7447
  particle.position.x = particle.spin.center.x + particle.spin.radius * updateFunc.x(particle.spin.angle);
7184
7448
  particle.position.y = particle.spin.center.y + particle.spin.radius * updateFunc.y(particle.spin.angle);
7185
7449
  particle.spin.radius += particle.spin.acceleration;
7186
- const maxCanvasSize = Math.max(container.canvas.size.width, container.canvas.size.height);
7187
- if (particle.spin.radius > maxCanvasSize / 2) {
7188
- particle.spin.radius = maxCanvasSize / 2;
7450
+ const maxCanvasSize = Math.max(container.canvas.size.width, container.canvas.size.height),
7451
+ halfMaxSize = maxCanvasSize * 0.5;
7452
+ if (particle.spin.radius > halfMaxSize) {
7453
+ particle.spin.radius = halfMaxSize;
7189
7454
  particle.spin.acceleration *= -1;
7190
7455
  } else if (particle.spin.radius < 0) {
7191
7456
  particle.spin.radius = 0;
7192
7457
  particle.spin.acceleration *= -1;
7193
7458
  }
7194
- particle.spin.angle += moveSpeed / 100 * (1 - particle.spin.radius / maxCanvasSize);
7459
+ particle.spin.angle += moveSpeed * 0.01 * (1 - particle.spin.radius / maxCanvasSize);
7195
7460
  }
7196
7461
  function applyPath(particle, delta) {
7197
7462
  const particlesOptions = particle.options,
@@ -7235,8 +7500,8 @@ class BaseMover {
7235
7500
  y: 50
7236
7501
  },
7237
7502
  spinCenter = {
7238
- x: spinPos.x / 100 * container.canvas.size.width,
7239
- y: spinPos.y / 100 * container.canvas.size.height
7503
+ x: spinPos.x * 0.01 * container.canvas.size.width,
7504
+ y: spinPos.y * 0.01 * container.canvas.size.height
7240
7505
  },
7241
7506
  pos = particle.getPosition(),
7242
7507
  distance = getDistance(pos, spinCenter),
@@ -7559,7 +7824,7 @@ function bounceHorizontal(data) {
7559
7824
  const velocity = data.particle.velocity.x;
7560
7825
  let bounced = false;
7561
7826
  if (data.direction === "right" && data.bounds.right >= data.canvasSize.width && velocity > 0 || data.direction === "left" && data.bounds.left <= 0 && velocity < 0) {
7562
- const newVelocity = getValue(data.particle.options.bounce.horizontal);
7827
+ const newVelocity = getRangeValue(data.particle.options.bounce.horizontal.value);
7563
7828
  data.particle.velocity.x *= -newVelocity;
7564
7829
  bounced = true;
7565
7830
  }
@@ -7588,7 +7853,7 @@ function bounceVertical(data) {
7588
7853
  const velocity = data.particle.velocity.y;
7589
7854
  let bounced = false;
7590
7855
  if (data.direction === "bottom" && data.bounds.bottom >= data.canvasSize.height && velocity > 0 || data.direction === "top" && data.bounds.top <= 0 && velocity < 0) {
7591
- const newVelocity = getValue(data.particle.options.bounce.vertical);
7856
+ const newVelocity = getRangeValue(data.particle.options.bounce.vertical.value);
7592
7857
  data.particle.velocity.y *= -newVelocity;
7593
7858
  bounced = true;
7594
7859
  }
@@ -8038,6 +8303,7 @@ class Attract {
8038
8303
  ;// CONCATENATED MODULE: ../../interactions/external/attract/dist/browser/Attractor.js
8039
8304
 
8040
8305
 
8306
+ const attractMode = "attract";
8041
8307
  class Attractor extends ExternalInteractorBase {
8042
8308
  constructor(engine, container) {
8043
8309
  super(container);
@@ -8109,7 +8375,7 @@ class Attractor extends ExternalInteractorBase {
8109
8375
  this.handleClickMode = mode => {
8110
8376
  const options = this.container.actualOptions,
8111
8377
  attract = options.interactivity.modes.attract;
8112
- if (!attract || mode !== "attract") {
8378
+ if (!attract || mode !== attractMode) {
8113
8379
  return;
8114
8380
  }
8115
8381
  if (!container.attract) {
@@ -8158,9 +8424,9 @@ class Attractor extends ExternalInteractorBase {
8158
8424
  hoverMode = events.onHover.mode,
8159
8425
  clickEnabled = events.onClick.enable,
8160
8426
  clickMode = events.onClick.mode;
8161
- if (mouseMoveStatus && hoverEnabled && isInArray("attract", hoverMode)) {
8427
+ if (mouseMoveStatus && hoverEnabled && isInArray(attractMode, hoverMode)) {
8162
8428
  this._hoverAttract();
8163
- } else if (clickEnabled && isInArray("attract", clickMode)) {
8429
+ } else if (clickEnabled && isInArray(attractMode, clickMode)) {
8164
8430
  this._clickAttract();
8165
8431
  }
8166
8432
  }
@@ -8174,7 +8440,7 @@ class Attractor extends ExternalInteractorBase {
8174
8440
  }
8175
8441
  const hoverMode = events.onHover.mode,
8176
8442
  clickMode = events.onClick.mode;
8177
- return isInArray("attract", hoverMode) || isInArray("attract", clickMode);
8443
+ return isInArray(attractMode, hoverMode) || isInArray(attractMode, clickMode);
8178
8444
  }
8179
8445
  loadModeOptions(options, ...sources) {
8180
8446
  if (!options.attract) {
@@ -8210,6 +8476,7 @@ class Bounce {
8210
8476
  ;// CONCATENATED MODULE: ../../interactions/external/bounce/dist/browser/Bouncer.js
8211
8477
 
8212
8478
 
8479
+ const bounceMode = "bounce";
8213
8480
  class Bouncer extends ExternalInteractorBase {
8214
8481
  constructor(container) {
8215
8482
  super(container);
@@ -8277,10 +8544,10 @@ class Bouncer extends ExternalInteractorBase {
8277
8544
  hoverEnabled = events.onHover.enable,
8278
8545
  hoverMode = events.onHover.mode,
8279
8546
  divs = events.onDiv;
8280
- if (mouseMoveStatus && hoverEnabled && isInArray("bounce", hoverMode)) {
8547
+ if (mouseMoveStatus && hoverEnabled && isInArray(bounceMode, hoverMode)) {
8281
8548
  this._processMouseBounce();
8282
8549
  } else {
8283
- divModeExecute("bounce", divs, (selector, div) => this._singleSelectorBounce(selector, div));
8550
+ divModeExecute(bounceMode, divs, (selector, div) => this._singleSelectorBounce(selector, div));
8284
8551
  }
8285
8552
  }
8286
8553
  isEnabled(particle) {
@@ -8289,7 +8556,7 @@ class Bouncer extends ExternalInteractorBase {
8289
8556
  mouse = container.interactivity.mouse,
8290
8557
  events = (particle?.interactivity ?? options.interactivity).events,
8291
8558
  divs = events.onDiv;
8292
- return mouse.position && events.onHover.enable && isInArray("bounce", events.onHover.mode) || isDivModeEnabled("bounce", divs);
8559
+ return mouse.position && events.onHover.enable && isInArray(bounceMode, events.onHover.mode) || isDivModeEnabled(bounceMode, divs);
8293
8560
  }
8294
8561
  loadModeOptions(options, ...sources) {
8295
8562
  if (!options.bounce) {
@@ -8392,6 +8659,7 @@ function calculateBubbleValue(particleValue, modeValue, optionsValue, ratio) {
8392
8659
 
8393
8660
 
8394
8661
 
8662
+ const bubbleMode = "bubble";
8395
8663
  class Bubbler extends ExternalInteractorBase {
8396
8664
  constructor(container) {
8397
8665
  super(container);
@@ -8628,7 +8896,7 @@ class Bubbler extends ExternalInteractorBase {
8628
8896
  container.bubble = {};
8629
8897
  }
8630
8898
  this.handleClickMode = mode => {
8631
- if (mode !== "bubble") {
8899
+ if (mode !== bubbleMode) {
8632
8900
  return;
8633
8901
  }
8634
8902
  if (!container.bubble) {
@@ -8667,12 +8935,12 @@ class Bubbler extends ExternalInteractorBase {
8667
8935
  clickEnabled = onClick.enable,
8668
8936
  clickMode = onClick.mode,
8669
8937
  divs = events.onDiv;
8670
- if (hoverEnabled && isInArray("bubble", hoverMode)) {
8938
+ if (hoverEnabled && isInArray(bubbleMode, hoverMode)) {
8671
8939
  this._hoverBubble();
8672
- } else if (clickEnabled && isInArray("bubble", clickMode)) {
8940
+ } else if (clickEnabled && isInArray(bubbleMode, clickMode)) {
8673
8941
  this._clickBubble();
8674
8942
  } else {
8675
- divModeExecute("bubble", divs, (selector, div) => this._singleSelectorHover(delta, selector, div));
8943
+ divModeExecute(bubbleMode, divs, (selector, div) => this._singleSelectorHover(delta, selector, div));
8676
8944
  }
8677
8945
  }
8678
8946
  isEnabled(particle) {
@@ -8685,11 +8953,11 @@ class Bubbler extends ExternalInteractorBase {
8685
8953
  onDiv,
8686
8954
  onHover
8687
8955
  } = events,
8688
- divBubble = isDivModeEnabled("bubble", onDiv);
8956
+ divBubble = isDivModeEnabled(bubbleMode, onDiv);
8689
8957
  if (!(divBubble || onHover.enable && mouse.position || onClick.enable && mouse.clickPosition)) {
8690
8958
  return false;
8691
8959
  }
8692
- return isInArray("bubble", onHover.mode) || isInArray("bubble", onClick.mode) || divBubble;
8960
+ return isInArray(bubbleMode, onHover.mode) || isInArray(bubbleMode, onClick.mode) || divBubble;
8693
8961
  }
8694
8962
  loadModeOptions(options, ...sources) {
8695
8963
  if (!options.bubble) {
@@ -8796,6 +9064,7 @@ function drawConnection(container, p1, p2) {
8796
9064
 
8797
9065
 
8798
9066
 
9067
+ const connectMode = "connect";
8799
9068
  class Connector extends ExternalInteractorBase {
8800
9069
  constructor(container) {
8801
9070
  super(container);
@@ -8843,7 +9112,7 @@ class Connector extends ExternalInteractorBase {
8843
9112
  if (!(events.onHover.enable && mouse.position)) {
8844
9113
  return false;
8845
9114
  }
8846
- return isInArray("connect", events.onHover.mode);
9115
+ return isInArray(connectMode, events.onHover.mode);
8847
9116
  }
8848
9117
  loadModeOptions(options, ...sources) {
8849
9118
  if (!options.connect) {
@@ -8937,6 +9206,7 @@ function drawGrab(container, particle, lineColor, opacity, mousePos) {
8937
9206
 
8938
9207
 
8939
9208
 
9209
+ const grabMode = "grab";
8940
9210
  class Grabber extends ExternalInteractorBase {
8941
9211
  constructor(container) {
8942
9212
  super(container);
@@ -8994,7 +9264,7 @@ class Grabber extends ExternalInteractorBase {
8994
9264
  const container = this.container,
8995
9265
  mouse = container.interactivity.mouse,
8996
9266
  events = (particle?.interactivity ?? container.actualOptions.interactivity).events;
8997
- return events.onHover.enable && !!mouse.position && isInArray("grab", events.onHover.mode);
9267
+ return events.onHover.enable && !!mouse.position && isInArray(grabMode, events.onHover.mode);
8998
9268
  }
8999
9269
  loadModeOptions(options, ...sources) {
9000
9270
  if (!options.grab) {
@@ -9017,11 +9287,12 @@ async function loadExternalGrabInteraction(engine, refresh = true) {
9017
9287
 
9018
9288
  ;// CONCATENATED MODULE: ../../interactions/external/pause/dist/browser/Pauser.js
9019
9289
 
9290
+ const pauseMode = "pause";
9020
9291
  class Pauser extends ExternalInteractorBase {
9021
9292
  constructor(container) {
9022
9293
  super(container);
9023
9294
  this.handleClickMode = mode => {
9024
- if (mode !== "pause") {
9295
+ if (mode !== pauseMode) {
9025
9296
  return;
9026
9297
  }
9027
9298
  const container = this.container;
@@ -9081,11 +9352,12 @@ class Push {
9081
9352
  ;// CONCATENATED MODULE: ../../interactions/external/push/dist/browser/Pusher.js
9082
9353
 
9083
9354
 
9355
+ const pushMode = "push";
9084
9356
  class Pusher extends ExternalInteractorBase {
9085
9357
  constructor(container) {
9086
9358
  super(container);
9087
9359
  this.handleClickMode = mode => {
9088
- if (mode !== "push") {
9360
+ if (mode !== pushMode) {
9089
9361
  return;
9090
9362
  }
9091
9363
  const container = this.container,
@@ -9151,13 +9423,14 @@ class Remove {
9151
9423
  ;// CONCATENATED MODULE: ../../interactions/external/remove/dist/browser/Remover.js
9152
9424
 
9153
9425
 
9426
+ const removeMode = "remove";
9154
9427
  class Remover extends ExternalInteractorBase {
9155
9428
  constructor(container) {
9156
9429
  super(container);
9157
9430
  this.handleClickMode = mode => {
9158
9431
  const container = this.container,
9159
9432
  options = container.actualOptions;
9160
- if (!options.interactivity.modes.remove || mode !== "remove") {
9433
+ if (!options.interactivity.modes.remove || mode !== removeMode) {
9161
9434
  return;
9162
9435
  }
9163
9436
  const removeNb = getRangeValue(options.interactivity.modes.remove.quantity);
@@ -9258,6 +9531,7 @@ class Repulse extends RepulseBase {
9258
9531
  ;// CONCATENATED MODULE: ../../interactions/external/repulse/dist/browser/Repulser.js
9259
9532
 
9260
9533
 
9534
+ const repulseMode = "repulse";
9261
9535
  class Repulser extends ExternalInteractorBase {
9262
9536
  constructor(engine, container) {
9263
9537
  super(container);
@@ -9330,14 +9604,21 @@ class Repulser extends ExternalInteractorBase {
9330
9604
  if (!repulseOptions) {
9331
9605
  return;
9332
9606
  }
9607
+ const {
9608
+ easing,
9609
+ speed,
9610
+ factor,
9611
+ maxSpeed
9612
+ } = repulseOptions,
9613
+ easingFunc = getEasing(easing),
9614
+ velocity = (divRepulse?.speed ?? speed) * factor;
9333
9615
  for (const particle of query) {
9334
9616
  const {
9335
9617
  dx,
9336
9618
  dy,
9337
9619
  distance
9338
9620
  } = getDistances(particle.position, position),
9339
- velocity = (divRepulse?.speed ?? repulseOptions.speed) * repulseOptions.factor,
9340
- repulseFactor = clamp(getEasing(repulseOptions.easing)(1 - distance / repulseRadius) * velocity, 0, repulseOptions.maxSpeed),
9621
+ repulseFactor = clamp(easingFunc(1 - distance / repulseRadius) * velocity, 0, maxSpeed),
9341
9622
  normVec = Vector.create(distance === 0 ? velocity : dx / distance * repulseFactor, distance === 0 ? velocity : dy / distance * repulseFactor);
9342
9623
  particle.position.addTo(normVec);
9343
9624
  }
@@ -9375,7 +9656,7 @@ class Repulser extends ExternalInteractorBase {
9375
9656
  this.handleClickMode = mode => {
9376
9657
  const options = this.container.actualOptions,
9377
9658
  repulseOpts = options.interactivity.modes.repulse;
9378
- if (!repulseOpts || mode !== "repulse") {
9659
+ if (!repulseOpts || mode !== repulseMode) {
9379
9660
  return;
9380
9661
  }
9381
9662
  if (!container.repulse) {
@@ -9423,12 +9704,12 @@ class Repulser extends ExternalInteractorBase {
9423
9704
  clickEnabled = click.enable,
9424
9705
  clickMode = click.mode,
9425
9706
  divs = events.onDiv;
9426
- if (mouseMoveStatus && hoverEnabled && isInArray("repulse", hoverMode)) {
9707
+ if (mouseMoveStatus && hoverEnabled && isInArray(repulseMode, hoverMode)) {
9427
9708
  this._hoverRepulse();
9428
- } else if (clickEnabled && isInArray("repulse", clickMode)) {
9709
+ } else if (clickEnabled && isInArray(repulseMode, clickMode)) {
9429
9710
  this._clickRepulse();
9430
9711
  } else {
9431
- divModeExecute("repulse", divs, (selector, div) => this._singleSelectorRepulse(selector, div));
9712
+ divModeExecute(repulseMode, divs, (selector, div) => this._singleSelectorRepulse(selector, div));
9432
9713
  }
9433
9714
  }
9434
9715
  isEnabled(particle) {
@@ -9439,13 +9720,13 @@ class Repulser extends ExternalInteractorBase {
9439
9720
  divs = events.onDiv,
9440
9721
  hover = events.onHover,
9441
9722
  click = events.onClick,
9442
- divRepulse = isDivModeEnabled("repulse", divs);
9723
+ divRepulse = isDivModeEnabled(repulseMode, divs);
9443
9724
  if (!(divRepulse || hover.enable && mouse.position || click.enable && mouse.clickPosition)) {
9444
9725
  return false;
9445
9726
  }
9446
9727
  const hoverMode = hover.mode,
9447
9728
  clickMode = click.mode;
9448
- return isInArray("repulse", hoverMode) || isInArray("repulse", clickMode) || divRepulse;
9729
+ return isInArray(repulseMode, hoverMode) || isInArray(repulseMode, clickMode) || divRepulse;
9449
9730
  }
9450
9731
  loadModeOptions(options, ...sources) {
9451
9732
  if (!options.repulse) {
@@ -9489,6 +9770,7 @@ class Slow {
9489
9770
  ;// CONCATENATED MODULE: ../../interactions/external/slow/dist/browser/Slower.js
9490
9771
 
9491
9772
 
9773
+ const slowMode = "slow";
9492
9774
  class Slower extends ExternalInteractorBase {
9493
9775
  constructor(container) {
9494
9776
  super(container);
@@ -9512,7 +9794,7 @@ class Slower extends ExternalInteractorBase {
9512
9794
  const container = this.container,
9513
9795
  mouse = container.interactivity.mouse,
9514
9796
  events = (particle?.interactivity ?? container.actualOptions.interactivity).events;
9515
- return events.onHover.enable && !!mouse.position && isInArray("slow", events.onHover.mode);
9797
+ return events.onHover.enable && !!mouse.position && isInArray(slowMode, events.onHover.mode);
9516
9798
  }
9517
9799
  loadModeOptions(options, ...sources) {
9518
9800
  if (!options.slow) {
@@ -10219,8 +10501,11 @@ class ImageDrawer {
10219
10501
  if (!this._engine.images) {
10220
10502
  this._engine.images = [];
10221
10503
  }
10222
- const imageData = particle.shapeData,
10223
- image = this._engine.images.find(t => t.name === imageData.name || t.source === imageData.src);
10504
+ const imageData = particle.shapeData;
10505
+ if (!imageData) {
10506
+ return;
10507
+ }
10508
+ const image = this._engine.images.find(t => t.name === imageData.name || t.source === imageData.src);
10224
10509
  if (!image) {
10225
10510
  this.loadImageShape(imageData).then(() => {
10226
10511
  this.loadShape(particle);
@@ -10235,8 +10520,11 @@ class ImageDrawer {
10235
10520
  this._engine.images = [];
10236
10521
  }
10237
10522
  const images = this._engine.images,
10238
- imageData = particle.shapeData,
10239
- color = particle.getFillColor(),
10523
+ imageData = particle.shapeData;
10524
+ if (!imageData) {
10525
+ return;
10526
+ }
10527
+ const color = particle.getFillColor(),
10240
10528
  image = images.find(t => t.name === imageData.name || t.source === imageData.src);
10241
10529
  if (!image) {
10242
10530
  return;
@@ -10269,16 +10557,16 @@ class ImageDrawer {
10269
10557
  if (!imageRes.ratio) {
10270
10558
  imageRes.ratio = 1;
10271
10559
  }
10272
- const fill = imageData.fill ?? particle.fill,
10273
- close = imageData.close ?? particle.close,
10560
+ const fill = imageData.fill ?? particle.shapeFill,
10561
+ close = imageData.close ?? particle.shapeClose,
10274
10562
  imageShape = {
10275
10563
  image: imageRes,
10276
10564
  fill,
10277
10565
  close
10278
10566
  };
10279
10567
  particle.image = imageShape.image;
10280
- particle.fill = imageShape.fill;
10281
- particle.close = imageShape.close;
10568
+ particle.shapeFill = imageShape.fill;
10569
+ particle.shapeClose = imageShape.close;
10282
10570
  })();
10283
10571
  }
10284
10572
  }
@@ -10411,7 +10699,6 @@ class LifeDelay extends ValueWithRandom {
10411
10699
  class LifeDuration extends ValueWithRandom {
10412
10700
  constructor() {
10413
10701
  super();
10414
- this.random.minimumValue = 0.0001;
10415
10702
  this.sync = false;
10416
10703
  }
10417
10704
  load(data) {
@@ -10589,8 +10876,8 @@ class ParallaxMover {
10589
10876
  }
10590
10877
  const canvasSize = container.canvas.size,
10591
10878
  canvasCenter = {
10592
- x: canvasSize.width / 2,
10593
- y: canvasSize.height / 2
10879
+ x: canvasSize.width * 0.5,
10880
+ y: canvasSize.height * 0.5
10594
10881
  },
10595
10882
  parallaxSmooth = parallaxOptions.smooth,
10596
10883
  factor = particle.getRadius() / parallaxForce,
@@ -10619,8 +10906,11 @@ class Attractor_Attractor extends ParticlesInteractorBase {
10619
10906
  clear() {}
10620
10907
  init() {}
10621
10908
  async interact(p1) {
10622
- const container = this.container,
10623
- distance = p1.retina.attractDistance ?? container.retina.attractDistance,
10909
+ const container = this.container;
10910
+ if (p1.attractDistance === undefined) {
10911
+ p1.attractDistance = getRangeValue(p1.options.move.attract.distance) * container.retina.pixelRatio;
10912
+ }
10913
+ const distance = p1.attractDistance,
10624
10914
  pos1 = p1.getPosition(),
10625
10915
  query = container.particles.quadTree.queryCircle(pos1, distance);
10626
10916
  for (const p2 of query) {
@@ -11037,6 +11327,13 @@ async function loadLinksInteraction(engine, refresh = true) {
11037
11327
  }
11038
11328
  ;// CONCATENATED MODULE: ../../interactions/particles/links/dist/browser/Utils.js
11039
11329
 
11330
+ function drawTriangle(context, p1, p2, p3) {
11331
+ context.beginPath();
11332
+ context.moveTo(p1.x, p1.y);
11333
+ context.lineTo(p2.x, p2.y);
11334
+ context.lineTo(p3.x, p3.y);
11335
+ context.closePath();
11336
+ }
11040
11337
  function drawLinkLine(params) {
11041
11338
  let drawn = false;
11042
11339
  const {
@@ -11773,8 +12070,22 @@ async function loadStrokeColorUpdater(engine, refresh = true) {
11773
12070
  }
11774
12071
  ;// CONCATENATED MODULE: ../../shapes/text/dist/browser/TextDrawer.js
11775
12072
 
11776
- const validTypes = ["text", "character", "char"];
12073
+ const validTypes = ["text", "character", "char", "multiline-text"];
11777
12074
  class TextDrawer {
12075
+ constructor() {
12076
+ this._drawLine = (context, line, radius, opacity, index, fill) => {
12077
+ const offsetX = line.length * radius / 2,
12078
+ pos = {
12079
+ x: -offsetX,
12080
+ y: radius / 2
12081
+ };
12082
+ if (fill) {
12083
+ context.fillText(line, pos.x, pos.y + radius * 2 * index);
12084
+ } else {
12085
+ context.strokeText(line, pos.x, pos.y + radius * 2 * index);
12086
+ }
12087
+ };
12088
+ }
11778
12089
  draw(data) {
11779
12090
  const {
11780
12091
  context,
@@ -11783,7 +12094,7 @@ class TextDrawer {
11783
12094
  opacity
11784
12095
  } = data,
11785
12096
  character = particle.shapeData;
11786
- if (character === undefined) {
12097
+ if (!character) {
11787
12098
  return;
11788
12099
  }
11789
12100
  const textData = character.value;
@@ -11798,24 +12109,18 @@ class TextDrawer {
11798
12109
  weight = character.weight ?? "400",
11799
12110
  size = Math.round(radius) * 2,
11800
12111
  font = character.font ?? "Verdana",
11801
- fill = particle.fill,
11802
- offsetX = text.length * radius / 2;
12112
+ fill = particle.shapeFill;
12113
+ const lines = text?.split("\n");
12114
+ if (!lines) {
12115
+ return;
12116
+ }
11803
12117
  context.font = `${style} ${weight} ${size}px "${font}"`;
11804
- const pos = {
11805
- x: -offsetX,
11806
- y: radius / 2
11807
- };
11808
12118
  context.globalAlpha = opacity;
11809
- if (fill) {
11810
- context.fillText(text, pos.x, pos.y);
11811
- } else {
11812
- context.strokeText(text, pos.x, pos.y);
12119
+ for (let i = 0; i < lines.length; i++) {
12120
+ this._drawLine(context, lines[i], radius, opacity, i, fill);
11813
12121
  }
11814
12122
  context.globalAlpha = 1;
11815
12123
  }
11816
- getSidesCount() {
11817
- return 12;
11818
- }
11819
12124
  async init(container) {
11820
12125
  const options = container.actualOptions;
11821
12126
  if (validTypes.find(t => isInArray(t, options.particles.shape.type))) {
@@ -12286,6 +12591,8 @@ async function loadWobbleUpdater(engine, refresh = true) {
12286
12591
 
12287
12592
 
12288
12593
 
12594
+
12595
+
12289
12596
  async function loadFull(engine, refresh = true) {
12290
12597
  await loadDestroyUpdater(engine, false);
12291
12598
  await loadRollUpdater(engine, false);
@@ -12295,6 +12602,8 @@ async function loadFull(engine, refresh = true) {
12295
12602
  await loadExternalTrailInteraction(engine, false);
12296
12603
  await loadAbsorbersPlugin(engine, false);
12297
12604
  await loadEmittersPlugin(engine, false);
12605
+ await loadEmittersShapeCircle(engine, false);
12606
+ await loadEmittersShapeSquare(engine, false);
12298
12607
  await loadSlim(engine, refresh);
12299
12608
  }
12300
12609
  ;// CONCATENATED MODULE: ./dist/browser/bundle.js