@tsparticles/preset-squares 4.2.1 → 4.3.1

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.
@@ -1,5 +1,5 @@
1
1
  (function(g){g.__tsParticlesInternals=g.__tsParticlesInternals||{};g.__tsParticlesInternals.bundles=g.__tsParticlesInternals.bundles||{};g.__tsParticlesInternals.effects=g.__tsParticlesInternals.effects||{};g.__tsParticlesInternals.engine=g.__tsParticlesInternals.engine||{};g.__tsParticlesInternals.interactions=g.__tsParticlesInternals.interactions||{};g.__tsParticlesInternals.palettes=g.__tsParticlesInternals.palettes||{};g.__tsParticlesInternals.paths=g.__tsParticlesInternals.paths||{};g.__tsParticlesInternals.plugins=g.__tsParticlesInternals.plugins||{};g.__tsParticlesInternals.plugins=g.__tsParticlesInternals.plugins||{};g.__tsParticlesInternals.plugins.emittersShapes=g.__tsParticlesInternals.plugins.emittersShapes||{};g.__tsParticlesInternals.presets=g.__tsParticlesInternals.presets||{};g.__tsParticlesInternals.shapes=g.__tsParticlesInternals.shapes||{};g.__tsParticlesInternals.updaters=g.__tsParticlesInternals.updaters||{};g.__tsParticlesInternals.utils=g.__tsParticlesInternals.utils||{};g.__tsParticlesInternals.canvas=g.__tsParticlesInternals.canvas||{};g.__tsParticlesInternals.canvas=g.__tsParticlesInternals.canvas||{};g.__tsParticlesInternals.canvas.utils=g.__tsParticlesInternals.canvas.utils||{};g.__tsParticlesInternals.path=g.__tsParticlesInternals.path||{};g.__tsParticlesInternals.path=g.__tsParticlesInternals.path||{};g.__tsParticlesInternals.path.utils=g.__tsParticlesInternals.path.utils||{};var __tsProxyFactory=typeof Proxy!=="undefined"?function(obj){return new Proxy(obj,{get:function(target,key){if(!(key in target)){target[key]={};}return target[key];}});}:function(obj){return obj;};g.__tsParticlesInternals.bundles=__tsProxyFactory(g.__tsParticlesInternals.bundles);g.__tsParticlesInternals.effects=__tsProxyFactory(g.__tsParticlesInternals.effects);g.__tsParticlesInternals.interactions=__tsProxyFactory(g.__tsParticlesInternals.interactions);g.__tsParticlesInternals.palettes=__tsProxyFactory(g.__tsParticlesInternals.palettes);g.__tsParticlesInternals.paths=__tsProxyFactory(g.__tsParticlesInternals.paths);g.__tsParticlesInternals.plugins=__tsProxyFactory(g.__tsParticlesInternals.plugins);g.__tsParticlesInternals.plugins.emittersShapes=__tsProxyFactory(g.__tsParticlesInternals.plugins.emittersShapes);g.__tsParticlesInternals.presets=__tsProxyFactory(g.__tsParticlesInternals.presets);g.__tsParticlesInternals.shapes=__tsProxyFactory(g.__tsParticlesInternals.shapes);g.__tsParticlesInternals.updaters=__tsProxyFactory(g.__tsParticlesInternals.updaters);g.__tsParticlesInternals.utils=__tsProxyFactory(g.__tsParticlesInternals.utils);g.__tsParticlesInternals.canvas=__tsProxyFactory(g.__tsParticlesInternals.canvas);g.__tsParticlesInternals.path=__tsProxyFactory(g.__tsParticlesInternals.path);g.tsparticlesInternalExports=g.tsparticlesInternalExports||{};})(typeof globalThis!=="undefined"?globalThis:typeof window!=="undefined"?window:this);
2
- /* Preset v4.2.1 */
2
+ /* Preset v4.3.1 */
3
3
  (function (global, factory) {
4
4
  typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
5
5
  typeof define === 'function' && define.amd ? define(['exports'], factory) :
@@ -357,29 +357,27 @@
357
357
  }
358
358
  }
359
359
  else if (!isObject(destination) || Array.isArray(destination)) {
360
- destination = {};
360
+ destination = Object.create(null);
361
361
  }
362
- const sourceKeys = Object.keys(source), dangerousKeys = new Set(["__proto__", "constructor", "prototype"]), hasNested = sourceKeys.some(k => {
362
+ const sourceKeys = Object.keys(source), hasNested = sourceKeys.some(k => {
363
363
  const v = source[k];
364
364
  return isObject(v) || Array.isArray(v);
365
365
  });
366
366
  if (!hasNested) {
367
367
  const sourceDict = source, destDict = destination;
368
368
  for (const key of sourceKeys) {
369
- if (dangerousKeys.has(key)) {
369
+ if (key === "__proto__" || key === "constructor" || key === "prototype") {
370
370
  continue;
371
371
  }
372
- if (key in sourceDict) {
373
- const v = sourceDict[key];
374
- if (v !== undefined) {
375
- destDict[key] = v;
376
- }
372
+ const v = sourceDict[key];
373
+ if (v !== undefined) {
374
+ destDict[key] = v;
377
375
  }
378
376
  }
379
377
  continue;
380
378
  }
381
379
  for (const key of sourceKeys) {
382
- if (dangerousKeys.has(key)) {
380
+ if (key === "__proto__" || key === "constructor" || key === "prototype") {
383
381
  continue;
384
382
  }
385
383
  const sourceDict = source, destDict = destination, value = sourceDict[key];
@@ -795,7 +793,7 @@
795
793
  return this.#domArray;
796
794
  }
797
795
  get version() {
798
- return "4.2.1";
796
+ return "4.3.1";
799
797
  }
800
798
  addEventListener(type, listener) {
801
799
  this.#eventDispatcher.addEventListener(type, listener);
@@ -1028,6 +1026,18 @@
1028
1026
  AnimationStatus["decreasing"] = "decreasing";
1029
1027
  })(AnimationStatus || (AnimationStatus = {}));
1030
1028
 
1029
+ var DrawLayer;
1030
+ (function (DrawLayer) {
1031
+ DrawLayer[DrawLayer["BackgroundElement"] = 0] = "BackgroundElement";
1032
+ DrawLayer[DrawLayer["BackgroundDraw"] = 1] = "BackgroundDraw";
1033
+ DrawLayer[DrawLayer["BackgroundMask"] = 2] = "BackgroundMask";
1034
+ DrawLayer[DrawLayer["CanvasSetup"] = 3] = "CanvasSetup";
1035
+ DrawLayer[DrawLayer["PluginContent"] = 4] = "PluginContent";
1036
+ DrawLayer[DrawLayer["Particles"] = 5] = "Particles";
1037
+ DrawLayer[DrawLayer["CanvasCleanup"] = 6] = "CanvasCleanup";
1038
+ DrawLayer[DrawLayer["Foreground"] = 7] = "Foreground";
1039
+ })(DrawLayer || (DrawLayer = {}));
1040
+
1031
1041
  class OptionLoader {
1032
1042
  load(data) {
1033
1043
  if (isNull(data)) {
@@ -1181,6 +1191,8 @@
1181
1191
 
1182
1192
  class Background extends OptionLoader {
1183
1193
  color;
1194
+ draw;
1195
+ element;
1184
1196
  image = "";
1185
1197
  opacity = 1;
1186
1198
  position = "";
@@ -1195,6 +1207,8 @@
1195
1207
  if (data.color !== undefined) {
1196
1208
  this.color = OptionsColor.create(this.color, data.color);
1197
1209
  }
1210
+ loadProperty(this, "element", data.element);
1211
+ loadProperty(this, "draw", data.draw);
1198
1212
  loadProperty(this, "image", data.image);
1199
1213
  loadProperty(this, "position", data.position);
1200
1214
  loadProperty(this, "repeat", data.repeat);
@@ -1740,7 +1754,7 @@
1740
1754
  }
1741
1755
  }
1742
1756
 
1743
- const styleCache = new Map(), maxStyleCacheSize = 2000, rgbFixedPrecision = 2, hslFixedPrecision = 2, sdrReferenceWhiteNits = 203;
1757
+ const styleCache = new Map(), maxStyleCacheSize = 2000, rgbFixedPrecision = 2, hslFixedPrecision = 2, hdrRgbFixedPrecision = 4, hdrHslFixedPrecision = 4, sdrReferenceWhiteNits = 203, hdrAnimationScale = sdrReferenceWhiteNits / maxNits;
1744
1758
  function getCachedStyle(key, generator) {
1745
1759
  let cached = styleCache.get(key);
1746
1760
  if (!cached) {
@@ -1869,19 +1883,20 @@
1869
1883
  }
1870
1884
  return temp1;
1871
1885
  }
1872
- function hslToRgb(hsl) {
1886
+ function hslToRgbFloat(hsl) {
1873
1887
  const h = ((hsl.h % hMax) + hMax) % hMax, s = Math.max(sMin, Math.min(sMax, hsl.s)), l = Math.max(lMin, Math.min(lMax, hsl.l)), hNormalized = h / hMax, sNormalized = s / sMax, lNormalized = l / lMax;
1874
1888
  if (s === sMin) {
1875
- const grayscaleValue = Math.round(lNormalized * rgbMax);
1889
+ const grayscaleValue = lNormalized * rgbMax;
1876
1890
  return { r: grayscaleValue, g: grayscaleValue, b: grayscaleValue };
1877
1891
  }
1878
1892
  const temp1 = lNormalized < half
1879
1893
  ? lNormalized * (sNormalizedOffset + sNormalized)
1880
1894
  : lNormalized + sNormalized - lNormalized * sNormalized, temp2 = double * lNormalized - temp1, phaseThird = phaseNumerator / triple, red = Math.min(rgbMax, rgbMax * hslChannel(temp2, temp1, hNormalized + phaseThird)), green = Math.min(rgbMax, rgbMax * hslChannel(temp2, temp1, hNormalized)), blue = Math.min(rgbMax, rgbMax * hslChannel(temp2, temp1, hNormalized - phaseThird));
1881
- return { r: Math.round(red), g: Math.round(green), b: Math.round(blue) };
1895
+ return { r: red, g: green, b: blue };
1882
1896
  }
1883
- function getRandomRgbColor(min) {
1884
- const fixedMin = defaultRgbMin, fixedMax = rgbMax + identity, getRgbInRangeValue = () => Math.floor(getRandomInRange(fixedMin, fixedMax));
1897
+ function getRandomRgbColor(min, hdr) {
1898
+ const fixedMin = defaultRgbMin;
1899
+ const fixedMax = rgbMax + identity, getRgbInRangeValue = () => Math.floor(getRandomInRange(fixedMin, fixedMax));
1885
1900
  return {
1886
1901
  b: getRgbInRangeValue(),
1887
1902
  g: getRgbInRangeValue(),
@@ -1889,7 +1904,7 @@
1889
1904
  };
1890
1905
  }
1891
1906
  function getStyleFromRgb(color, hdr, opacity) {
1892
- const op = opacity ?? defaultOpacity$1, key = `rgb-${color.r.toFixed(rgbFixedPrecision)}-${color.g.toFixed(rgbFixedPrecision)}-${color.b.toFixed(rgbFixedPrecision)}-${hdr ? "hdr" : "sdr"}-${op.toString()}`;
1907
+ const rgbPrecision = hdr ? hdrRgbFixedPrecision : rgbFixedPrecision, op = opacity ?? defaultOpacity$1, key = `rgb-${color.r.toFixed(rgbPrecision)}-${color.g.toFixed(rgbPrecision)}-${color.b.toFixed(rgbPrecision)}-${hdr ? "hdr" : "sdr"}-${op.toString()}`;
1893
1908
  return getCachedStyle(key, () => (hdr ? getHdrStyleFromRgb(color, opacity) : getSdrStyleFromRgb(color, opacity)));
1894
1909
  }
1895
1910
  function getHdrStyleFromRgb(color, opacity, peakNits = maxNits) {
@@ -1900,9 +1915,9 @@
1900
1915
  return `rgba(${color.r.toString()}, ${color.g.toString()}, ${color.b.toString()}, ${(opacity ?? defaultOpacity$1).toString()})`;
1901
1916
  }
1902
1917
  function getStyleFromHsl(color, hdr, opacity) {
1903
- const op = opacity ?? defaultOpacity$1, key = `hsl-${color.h.toFixed(hslFixedPrecision)}-${color.s.toFixed(hslFixedPrecision)}-${color.l.toFixed(hslFixedPrecision)}-${hdr ? "hdr" : "sdr"}-${op.toString()}`;
1918
+ const hslPrecision = hdr ? hdrHslFixedPrecision : hslFixedPrecision, op = opacity ?? defaultOpacity$1, key = `hsl-${color.h.toFixed(hslPrecision)}-${color.s.toFixed(hslPrecision)}-${color.l.toFixed(hslPrecision)}-${hdr ? "hdr" : "sdr"}-${op.toString()}`;
1904
1919
  return getCachedStyle(key, () => hdr
1905
- ? getStyleFromRgb(hslToRgb(color), true, opacity)
1920
+ ? getStyleFromRgb(hslToRgbFloat(color), true, opacity)
1906
1921
  : `hsla(${color.h.toString()}, ${color.s.toString()}%, ${color.l.toString()}%, ${op.toString()})`);
1907
1922
  }
1908
1923
  function getHslFromAnimation(animation) {
@@ -1965,7 +1980,7 @@
1965
1980
  colorValue.velocity = defaultVelocity;
1966
1981
  }
1967
1982
  }
1968
- function updateColorValue(data, decrease, delta) {
1983
+ function updateColorValue(data, decrease, delta, hdr) {
1969
1984
  const minLoops = 0, minDelay = 0, identity = 1, minVelocity = 0, minOffset = 0, velocityFactor = 3.6;
1970
1985
  if (!data.enable ||
1971
1986
  ((data.maxLoops ?? minLoops) > minLoops && (data.loops ?? minLoops) > (data.maxLoops ?? minLoops))) {
@@ -1978,7 +1993,7 @@
1978
1993
  if ((data.delayTime ?? minDelay) > minDelay && data.time < (data.delayTime ?? minDelay)) {
1979
1994
  return;
1980
1995
  }
1981
- const offset = data.offset ? randomInRangeValue(data.offset) : minOffset, velocity = (data.velocity ?? minVelocity) * delta.factor + offset * velocityFactor, decay = data.decay ?? identity, max = data.max, min = data.min;
1996
+ const offset = data.offset ? randomInRangeValue(data.offset) : minOffset, velocity = ((data.velocity ?? minVelocity) * delta.factor + offset * velocityFactor) * (hdr ? hdrAnimationScale : identity), decay = data.decay ?? identity, max = data.max, min = data.min;
1982
1997
  if (!decrease || data.status === AnimationStatus.increasing) {
1983
1998
  data.value += velocity;
1984
1999
  if (data.value > max) {
@@ -2005,14 +2020,14 @@
2005
2020
  }
2006
2021
  data.value = clamp(data.value, min, max);
2007
2022
  }
2008
- function updateColor(color, delta) {
2023
+ function updateColor(color, delta, hdr) {
2009
2024
  if (!color) {
2010
2025
  return;
2011
2026
  }
2012
2027
  const { h, s, l } = color;
2013
- updateColorValue(h, false, delta);
2014
- updateColorValue(s, true, delta);
2015
- updateColorValue(l, true, delta);
2028
+ updateColorValue(h, false, delta, hdr);
2029
+ updateColorValue(s, true, delta, hdr);
2030
+ updateColorValue(l, true, delta, hdr);
2016
2031
  }
2017
2032
  function alterHsl(color, type, value) {
2018
2033
  return {
@@ -2230,7 +2245,7 @@
2230
2245
  })(EmitterClickMode || (EmitterClickMode = {}));
2231
2246
 
2232
2247
  async function loadEmittersPluginSimple(engine) {
2233
- engine.checkVersion("4.2.1");
2248
+ engine.checkVersion("4.3.1");
2234
2249
  await engine.pluginManager.register(async (e) => {
2235
2250
  const instancesManager = await getEmittersInstancesManager(e);
2236
2251
  await addEmittersShapesManager(e);
@@ -2278,7 +2293,7 @@
2278
2293
  }
2279
2294
 
2280
2295
  async function loadHexColorPlugin(engine) {
2281
- engine.checkVersion("4.2.1");
2296
+ engine.checkVersion("4.3.1");
2282
2297
  await engine.pluginManager.register(e => {
2283
2298
  e.pluginManager.addColorManager("hex", new HexColorManager());
2284
2299
  });
@@ -2341,13 +2356,13 @@
2341
2356
  if (!this.isEnabled(particle)) {
2342
2357
  return;
2343
2358
  }
2344
- updateColor(particle.fillColor, delta);
2345
- updateColor(particle.strokeColor, delta);
2359
+ updateColor(particle.fillColor, delta, this.#container.hdr);
2360
+ updateColor(particle.strokeColor, delta, this.#container.hdr);
2346
2361
  }
2347
2362
  }
2348
2363
 
2349
2364
  async function loadPaintUpdater(engine) {
2350
- engine.checkVersion("4.2.1");
2365
+ engine.checkVersion("4.3.1");
2351
2366
  await engine.pluginManager.register(e => {
2352
2367
  e.pluginManager.addParticleUpdater("paint", container => {
2353
2368
  return Promise.resolve(new PaintUpdater(e.pluginManager, container));
@@ -2576,7 +2591,7 @@
2576
2591
  }
2577
2592
 
2578
2593
  async function loadRotateUpdater(engine) {
2579
- engine.checkVersion("4.2.1");
2594
+ engine.checkVersion("4.3.1");
2580
2595
  await engine.pluginManager.register(e => {
2581
2596
  e.pluginManager.addParticleUpdater("rotate", container => {
2582
2597
  return Promise.resolve(new RotateUpdater(container));
@@ -2663,7 +2678,7 @@
2663
2678
  }
2664
2679
 
2665
2680
  async function loadSizeUpdater(engine) {
2666
- engine.checkVersion("4.2.1");
2681
+ engine.checkVersion("4.3.1");
2667
2682
  await engine.pluginManager.register(e => {
2668
2683
  e.pluginManager.addParticleUpdater("size", container => {
2669
2684
  return Promise.resolve(new SizeUpdater(container));
@@ -2687,7 +2702,7 @@
2687
2702
  }
2688
2703
 
2689
2704
  async function loadSquareShape(engine) {
2690
- engine.checkVersion("4.2.1");
2705
+ engine.checkVersion("4.3.1");
2691
2706
  await engine.pluginManager.register(e => {
2692
2707
  e.pluginManager.addShape(["edge", "square"], () => Promise.resolve(new SquareDrawer()));
2693
2708
  });
@@ -2771,10 +2786,10 @@
2771
2786
  }
2772
2787
  }
2773
2788
  class RenderManager {
2789
+ #backgroundElement;
2790
+ #backgroundWarnings;
2774
2791
  #canvasClearPlugins;
2775
2792
  #canvasManager;
2776
- #canvasPaintPlugins;
2777
- #clearDrawPlugins;
2778
2793
  #colorPlugins;
2779
2794
  #container;
2780
2795
  #context;
@@ -2782,9 +2797,7 @@
2782
2797
  #drawParticlePlugins;
2783
2798
  #drawParticlesCleanupPlugins;
2784
2799
  #drawParticlesSetupPlugins;
2785
- #drawPlugins;
2786
- #drawSettingsCleanupPlugins;
2787
- #drawSettingsSetupPlugins;
2800
+ #layers;
2788
2801
  #pluginManager;
2789
2802
  #postDrawUpdaters;
2790
2803
  #preDrawUpdaters;
@@ -2796,18 +2809,25 @@
2796
2809
  this.#container = container;
2797
2810
  this.#canvasManager = canvasManager;
2798
2811
  this.#context = null;
2812
+ this.#backgroundElement = null;
2813
+ this.#backgroundWarnings = new Set();
2799
2814
  this.#preDrawUpdaters = [];
2800
2815
  this.#postDrawUpdaters = [];
2801
- this.#colorPlugins = [];
2802
2816
  this.#canvasClearPlugins = [];
2803
- this.#canvasPaintPlugins = [];
2804
- this.#clearDrawPlugins = [];
2817
+ this.#colorPlugins = [];
2805
2818
  this.#drawParticlePlugins = [];
2806
2819
  this.#drawParticlesCleanupPlugins = [];
2807
2820
  this.#drawParticlesSetupPlugins = [];
2808
- this.#drawPlugins = [];
2809
- this.#drawSettingsSetupPlugins = [];
2810
- this.#drawSettingsCleanupPlugins = [];
2821
+ this.#layers = {
2822
+ 0: [],
2823
+ 1: [],
2824
+ 2: [],
2825
+ 3: [],
2826
+ 4: [],
2827
+ 5: [],
2828
+ 6: [],
2829
+ 7: [],
2830
+ };
2811
2831
  }
2812
2832
  get settings() {
2813
2833
  return this.#contextSettings;
@@ -2821,32 +2841,38 @@
2821
2841
  });
2822
2842
  }
2823
2843
  clear() {
2824
- let pluginHandled = false;
2825
2844
  for (const plugin of this.#canvasClearPlugins) {
2826
- pluginHandled = plugin.canvasClear?.() ?? false;
2827
- if (pluginHandled) {
2828
- break;
2845
+ if (plugin.canvasClear?.() ?? false) {
2846
+ return;
2829
2847
  }
2830
2848
  }
2831
- if (pluginHandled) {
2832
- return;
2849
+ for (const layer of Object.values(DrawLayer)) {
2850
+ if (typeof layer === "number") {
2851
+ for (const plugin of this.#getLayerPlugins(layer)) {
2852
+ if (plugin.canvasClear?.() ?? false) {
2853
+ return;
2854
+ }
2855
+ }
2856
+ }
2833
2857
  }
2834
2858
  this.canvasClear();
2835
2859
  }
2836
2860
  destroy() {
2837
2861
  this.stop();
2862
+ this.#backgroundElement = null;
2863
+ this.#backgroundWarnings.clear();
2838
2864
  this.#preDrawUpdaters = [];
2839
2865
  this.#postDrawUpdaters = [];
2840
- this.#colorPlugins = [];
2841
2866
  this.#canvasClearPlugins = [];
2842
- this.#canvasPaintPlugins = [];
2843
- this.#clearDrawPlugins = [];
2867
+ this.#colorPlugins = [];
2844
2868
  this.#drawParticlePlugins = [];
2845
2869
  this.#drawParticlesCleanupPlugins = [];
2846
2870
  this.#drawParticlesSetupPlugins = [];
2847
- this.#drawPlugins = [];
2848
- this.#drawSettingsSetupPlugins = [];
2849
- this.#drawSettingsCleanupPlugins = [];
2871
+ for (const layer of Object.values(DrawLayer)) {
2872
+ if (typeof layer === "number") {
2873
+ this.#layers[layer] = [];
2874
+ }
2875
+ }
2850
2876
  }
2851
2877
  draw(cb) {
2852
2878
  const ctx = this.#context;
@@ -2903,21 +2929,40 @@
2903
2929
  });
2904
2930
  }
2905
2931
  drawParticles(delta) {
2906
- const { particles } = this.#container;
2932
+ const { particles, actualOptions } = this.#container;
2907
2933
  this.clear();
2908
2934
  particles.update(delta);
2909
2935
  this.draw(ctx => {
2910
- for (const plugin of this.#drawSettingsSetupPlugins) {
2936
+ const width = this.#canvasManager.size.width, height = this.#canvasManager.size.height;
2937
+ if (this.#backgroundElement) {
2938
+ try {
2939
+ ctx.drawImage(this.#backgroundElement, originPoint.x, originPoint.y, width, height);
2940
+ }
2941
+ catch {
2942
+ this.#warnOnce("background-element-draw-error", "Error drawing background element onto canvas");
2943
+ }
2944
+ }
2945
+ const background = actualOptions.background;
2946
+ if (background.draw) {
2947
+ try {
2948
+ background.draw(ctx, delta);
2949
+ }
2950
+ catch {
2951
+ this.#warnOnce("background-draw-error", "Error in background.draw callback");
2952
+ }
2953
+ }
2954
+ for (const plugin of this.#getLayerPlugins(DrawLayer.BackgroundMask)) {
2955
+ plugin.canvasPaint?.();
2956
+ }
2957
+ for (const plugin of this.#getLayerPlugins(DrawLayer.CanvasSetup)) {
2911
2958
  plugin.drawSettingsSetup?.(ctx, delta);
2912
2959
  }
2913
- for (const plugin of this.#drawPlugins) {
2960
+ for (const plugin of this.#getLayerPlugins(DrawLayer.PluginContent)) {
2914
2961
  plugin.draw?.(ctx, delta);
2915
2962
  }
2916
2963
  particles.drawParticles(delta);
2917
- for (const plugin of this.#clearDrawPlugins) {
2964
+ for (const plugin of this.#getLayerPlugins(DrawLayer.CanvasCleanup)) {
2918
2965
  plugin.clearDraw?.(ctx, delta);
2919
- }
2920
- for (const plugin of this.#drawSettingsCleanupPlugins) {
2921
2966
  plugin.drawSettingsCleanup?.(ctx, delta);
2922
2967
  }
2923
2968
  });
@@ -2925,29 +2970,24 @@
2925
2970
  init() {
2926
2971
  this.initUpdaters();
2927
2972
  this.initPlugins();
2973
+ this.#resolveBackgroundElement();
2928
2974
  this.paint();
2929
2975
  }
2930
2976
  initPlugins() {
2931
- this.#colorPlugins = [];
2932
2977
  this.#canvasClearPlugins = [];
2933
- this.#canvasPaintPlugins = [];
2934
- this.#clearDrawPlugins = [];
2978
+ this.#colorPlugins = [];
2935
2979
  this.#drawParticlePlugins = [];
2936
2980
  this.#drawParticlesSetupPlugins = [];
2937
2981
  this.#drawParticlesCleanupPlugins = [];
2938
- this.#drawPlugins = [];
2939
- this.#drawSettingsSetupPlugins = [];
2940
- this.#drawSettingsCleanupPlugins = [];
2982
+ for (const layer of Object.values(DrawLayer)) {
2983
+ if (typeof layer === "number") {
2984
+ this.#layers[layer] = [];
2985
+ }
2986
+ }
2941
2987
  for (const plugin of this.#container.plugins) {
2942
2988
  if (plugin.particleFillColor ?? plugin.particleStrokeColor) {
2943
2989
  this.#colorPlugins.push(plugin);
2944
2990
  }
2945
- if (plugin.canvasClear) {
2946
- this.#canvasClearPlugins.push(plugin);
2947
- }
2948
- if (plugin.canvasPaint) {
2949
- this.#canvasPaintPlugins.push(plugin);
2950
- }
2951
2991
  if (plugin.drawParticle) {
2952
2992
  this.#drawParticlePlugins.push(plugin);
2953
2993
  }
@@ -2957,17 +2997,20 @@
2957
2997
  if (plugin.drawParticleCleanup) {
2958
2998
  this.#drawParticlesCleanupPlugins.push(plugin);
2959
2999
  }
2960
- if (plugin.draw) {
2961
- this.#drawPlugins.push(plugin);
3000
+ if (plugin.canvasClear) {
3001
+ this.#canvasClearPlugins.push(plugin);
3002
+ }
3003
+ if (plugin.canvasPaint) {
3004
+ this.#getLayerPlugins(DrawLayer.BackgroundMask).push(plugin);
2962
3005
  }
2963
3006
  if (plugin.drawSettingsSetup) {
2964
- this.#drawSettingsSetupPlugins.push(plugin);
3007
+ this.#getLayerPlugins(DrawLayer.CanvasSetup).push(plugin);
2965
3008
  }
2966
- if (plugin.drawSettingsCleanup) {
2967
- this.#drawSettingsCleanupPlugins.push(plugin);
3009
+ if (plugin.draw) {
3010
+ this.#getLayerPlugins(DrawLayer.PluginContent).push(plugin);
2968
3011
  }
2969
- if (plugin.clearDraw) {
2970
- this.#clearDrawPlugins.push(plugin);
3012
+ if (plugin.clearDraw ?? plugin.drawSettingsCleanup) {
3013
+ this.#getLayerPlugins(DrawLayer.CanvasCleanup).push(plugin);
2971
3014
  }
2972
3015
  }
2973
3016
  }
@@ -2985,7 +3028,7 @@
2985
3028
  }
2986
3029
  paint() {
2987
3030
  let handled = false;
2988
- for (const plugin of this.#canvasPaintPlugins) {
3031
+ for (const plugin of this.#getLayerPlugins(DrawLayer.BackgroundMask)) {
2989
3032
  handled = plugin.canvasPaint?.() ?? false;
2990
3033
  if (handled) {
2991
3034
  break;
@@ -3158,6 +3201,9 @@
3158
3201
  }
3159
3202
  drawer.beforeDraw(data);
3160
3203
  }
3204
+ #getLayerPlugins(layer) {
3205
+ return this.#layers[layer];
3206
+ }
3161
3207
  #getPluginParticleColors(particle) {
3162
3208
  let fColor, sColor;
3163
3209
  for (const plugin of this.#colorPlugins) {
@@ -3175,6 +3221,39 @@
3175
3221
  this.#reusablePluginColors[sColorIndex] = sColor;
3176
3222
  return this.#reusablePluginColors;
3177
3223
  }
3224
+ #resolveBackgroundElement() {
3225
+ const background = this.#container.actualOptions.background;
3226
+ this.#backgroundElement = null;
3227
+ if (!background.element) {
3228
+ return;
3229
+ }
3230
+ if (typeof background.element === "string") {
3231
+ if (typeof document !== "undefined") {
3232
+ const node = document.querySelector(background.element);
3233
+ if (node instanceof HTMLCanvasElement || node instanceof HTMLVideoElement || node instanceof HTMLImageElement) {
3234
+ this.#backgroundElement = node;
3235
+ }
3236
+ else if (node) {
3237
+ this.#warnOnce("background-element-not-supported", `Background element "${background.element}" is not a supported drawable element (canvas, video, or img)`);
3238
+ }
3239
+ else {
3240
+ this.#warnOnce("background-element-not-found", `Background element selector "${background.element}" not found`);
3241
+ }
3242
+ }
3243
+ }
3244
+ else if (background.element instanceof HTMLCanvasElement ||
3245
+ background.element instanceof OffscreenCanvas ||
3246
+ background.element instanceof HTMLVideoElement ||
3247
+ background.element instanceof HTMLImageElement) {
3248
+ this.#backgroundElement = background.element;
3249
+ }
3250
+ }
3251
+ #warnOnce(key, message) {
3252
+ if (!this.#backgroundWarnings.has(key)) {
3253
+ this.#backgroundWarnings.add(key);
3254
+ getLogger().warning(message);
3255
+ }
3256
+ }
3178
3257
  }
3179
3258
 
3180
3259
  const transferredCanvases = new WeakMap(), getTransferredCanvas = (canvas) => {
@@ -3751,7 +3830,6 @@
3751
3830
  }
3752
3831
  class Particle {
3753
3832
  backColor;
3754
- bubble;
3755
3833
  destroyed;
3756
3834
  direction;
3757
3835
  effect;
@@ -3785,7 +3863,6 @@
3785
3863
  shapeData;
3786
3864
  sides;
3787
3865
  size;
3788
- slow;
3789
3866
  spawning;
3790
3867
  strokeColor;
3791
3868
  strokeOpacity;
@@ -3807,18 +3884,25 @@
3807
3884
  d: 1,
3808
3885
  };
3809
3886
  #container;
3887
+ #modifiers = [];
3810
3888
  #pluginManager;
3811
3889
  constructor(pluginManager, container) {
3812
3890
  this.#pluginManager = pluginManager;
3813
3891
  this.#container = container;
3814
3892
  }
3893
+ addModifier(modifier) {
3894
+ this.#modifiers.push(modifier);
3895
+ this.#modifiers.sort((a, b) => a.priority - b.priority);
3896
+ }
3897
+ clearModifiers() {
3898
+ this.#modifiers.length = 0;
3899
+ }
3815
3900
  destroy(override) {
3816
3901
  if (this.unbreakable || this.destroyed) {
3817
3902
  return;
3818
3903
  }
3819
3904
  this.destroyed = true;
3820
- this.bubble.inRange = false;
3821
- this.slow.inRange = false;
3905
+ this.clearModifiers();
3822
3906
  const container = this.#container, shapeDrawer = this.shape ? container.shapeDrawers.get(this.shape) : undefined;
3823
3907
  shapeDrawer?.particleDestroy?.(this);
3824
3908
  for (const plugin of container.particleDestroyedPlugins) {
@@ -3840,13 +3924,16 @@
3840
3924
  return this.rotation + (this.pathRotation ? this.velocity.angle : defaultAngle);
3841
3925
  }
3842
3926
  getFillColor() {
3843
- return this.#getRollColor(this.bubble.color ?? getHslFromAnimation(this.fillColor));
3927
+ return this.#getRollColor(this.#applyModifiers(getHslFromAnimation(this.fillColor), m => m.fillColor));
3844
3928
  }
3845
3929
  getMass() {
3846
3930
  return this.getRadius() ** squareExp * Math.PI * half;
3847
3931
  }
3932
+ getModifier(id) {
3933
+ return this.#modifiers.find(m => m.id === id);
3934
+ }
3848
3935
  getOpacity() {
3849
- const zIndexOptions = this.options.zIndex, zIndexFactor = zIndexFactorOffset - this.zIndexFactor, zOpacityFactor = zIndexFactor ** zIndexOptions.opacityRate, opacity = this.bubble.opacity ?? getRangeValue(this.opacity?.value ?? defaultOpacity$1), fillOpacity = this.fillOpacity ?? defaultOpacity$1, strokeOpacity = this.strokeOpacity ?? defaultOpacity$1;
3936
+ const zIndexOptions = this.options.zIndex, zIndexFactor = zIndexFactorOffset - this.zIndexFactor, zOpacityFactor = zIndexFactor ** zIndexOptions.opacityRate, baseOpacity = getRangeValue(this.opacity?.value ?? defaultOpacity$1), modifierOpacity = this.#applyModifiers(undefined, m => m.opacity), opacity = modifierOpacity ?? baseOpacity, fillOpacity = this.fillOpacity ?? defaultOpacity$1, strokeOpacity = this.strokeOpacity ?? defaultOpacity$1;
3850
3937
  this.#cachedOpacityData.fillOpacity = opacity * fillOpacity * zOpacityFactor;
3851
3938
  this.#cachedOpacityData.opacity = opacity * zOpacityFactor;
3852
3939
  this.#cachedOpacityData.strokeOpacity = opacity * strokeOpacity * zOpacityFactor;
@@ -3859,7 +3946,7 @@
3859
3946
  return this.#cachedPosition;
3860
3947
  }
3861
3948
  getRadius() {
3862
- return this.bubble.radius ?? this.size.value;
3949
+ return this.#applyModifiers(this.size.value, m => m.radius);
3863
3950
  }
3864
3951
  getRotateData() {
3865
3952
  const angle = this.getAngle();
@@ -3868,7 +3955,7 @@
3868
3955
  return this.#cachedRotateData;
3869
3956
  }
3870
3957
  getStrokeColor() {
3871
- return this.#getRollColor(this.bubble.color ?? getHslFromAnimation(this.strokeColor));
3958
+ return this.#getRollColor(this.#applyModifiers(getHslFromAnimation(this.strokeColor), m => m.strokeColor));
3872
3959
  }
3873
3960
  getTransformData(externalTransform) {
3874
3961
  const rotateData = this.getRotateData(), rotating = this.isRotating;
@@ -3888,13 +3975,6 @@
3888
3975
  this.options = resolveParticleOptions(this, container, this.#pluginManager, overrideOptions);
3889
3976
  container.retina.initParticle(this);
3890
3977
  runUpdaterPreInit(container.particleUpdaters, this);
3891
- this.bubble = {
3892
- inRange: false,
3893
- };
3894
- this.slow = {
3895
- inRange: false,
3896
- factor: 1,
3897
- };
3898
3978
  this.#initPosition(position);
3899
3979
  this.initialVelocity = this.#calculateVelocity();
3900
3980
  this.velocity = this.initialVelocity.copy();
@@ -3934,11 +4014,29 @@
3934
4014
  isVisible() {
3935
4015
  return !this.destroyed && !this.spawning && this.isInsideCanvas();
3936
4016
  }
4017
+ removeModifier(id) {
4018
+ const idx = this.#modifiers.findIndex(m => m.id === id);
4019
+ if (idx >= defaultAngle) {
4020
+ this.#modifiers.splice(idx, identity);
4021
+ }
4022
+ }
3937
4023
  reset() {
3938
4024
  for (const updater of this.#container.particleUpdaters) {
3939
4025
  updater.reset?.(this);
3940
4026
  }
3941
4027
  }
4028
+ #applyModifiers(base, getter) {
4029
+ let value = base;
4030
+ for (const mod of this.#modifiers) {
4031
+ if (mod.enabled) {
4032
+ const override = getter(mod);
4033
+ if (override !== undefined) {
4034
+ value = override;
4035
+ }
4036
+ }
4037
+ }
4038
+ return value;
4039
+ }
3942
4040
  #calcPosition(position, zIndex) {
3943
4041
  let tryCount = defaultRetryCount, posVec = position ? Vector3d.create(position.x, position.y, zIndex) : undefined;
3944
4042
  const container = this.#container, plugins = container.particlePositionPlugins, outModes = this.options.move.outModes, radius = this.getRadius(), canvasSize = container.canvas.size;