@tsparticles/preset-firefly 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) :
@@ -358,29 +358,27 @@
358
358
  }
359
359
  }
360
360
  else if (!isObject(destination) || Array.isArray(destination)) {
361
- destination = {};
361
+ destination = Object.create(null);
362
362
  }
363
- const sourceKeys = Object.keys(source), dangerousKeys = new Set(["__proto__", "constructor", "prototype"]), hasNested = sourceKeys.some(k => {
363
+ const sourceKeys = Object.keys(source), hasNested = sourceKeys.some(k => {
364
364
  const v = source[k];
365
365
  return isObject(v) || Array.isArray(v);
366
366
  });
367
367
  if (!hasNested) {
368
368
  const sourceDict = source, destDict = destination;
369
369
  for (const key of sourceKeys) {
370
- if (dangerousKeys.has(key)) {
370
+ if (key === "__proto__" || key === "constructor" || key === "prototype") {
371
371
  continue;
372
372
  }
373
- if (key in sourceDict) {
374
- const v = sourceDict[key];
375
- if (v !== undefined) {
376
- destDict[key] = v;
377
- }
373
+ const v = sourceDict[key];
374
+ if (v !== undefined) {
375
+ destDict[key] = v;
378
376
  }
379
377
  }
380
378
  continue;
381
379
  }
382
380
  for (const key of sourceKeys) {
383
- if (dangerousKeys.has(key)) {
381
+ if (key === "__proto__" || key === "constructor" || key === "prototype") {
384
382
  continue;
385
383
  }
386
384
  const sourceDict = source, destDict = destination, value = sourceDict[key];
@@ -796,7 +794,7 @@
796
794
  return this.#domArray;
797
795
  }
798
796
  get version() {
799
- return "4.2.1";
797
+ return "4.3.1";
800
798
  }
801
799
  addEventListener(type, listener) {
802
800
  this.#eventDispatcher.addEventListener(type, listener);
@@ -1029,6 +1027,18 @@
1029
1027
  AnimationStatus["decreasing"] = "decreasing";
1030
1028
  })(AnimationStatus || (AnimationStatus = {}));
1031
1029
 
1030
+ var DrawLayer;
1031
+ (function (DrawLayer) {
1032
+ DrawLayer[DrawLayer["BackgroundElement"] = 0] = "BackgroundElement";
1033
+ DrawLayer[DrawLayer["BackgroundDraw"] = 1] = "BackgroundDraw";
1034
+ DrawLayer[DrawLayer["BackgroundMask"] = 2] = "BackgroundMask";
1035
+ DrawLayer[DrawLayer["CanvasSetup"] = 3] = "CanvasSetup";
1036
+ DrawLayer[DrawLayer["PluginContent"] = 4] = "PluginContent";
1037
+ DrawLayer[DrawLayer["Particles"] = 5] = "Particles";
1038
+ DrawLayer[DrawLayer["CanvasCleanup"] = 6] = "CanvasCleanup";
1039
+ DrawLayer[DrawLayer["Foreground"] = 7] = "Foreground";
1040
+ })(DrawLayer || (DrawLayer = {}));
1041
+
1032
1042
  class OptionLoader {
1033
1043
  load(data) {
1034
1044
  if (isNull(data)) {
@@ -1182,6 +1192,8 @@
1182
1192
 
1183
1193
  class Background extends OptionLoader {
1184
1194
  color;
1195
+ draw;
1196
+ element;
1185
1197
  image = "";
1186
1198
  opacity = 1;
1187
1199
  position = "";
@@ -1196,6 +1208,8 @@
1196
1208
  if (data.color !== undefined) {
1197
1209
  this.color = OptionsColor.create(this.color, data.color);
1198
1210
  }
1211
+ loadProperty(this, "element", data.element);
1212
+ loadProperty(this, "draw", data.draw);
1199
1213
  loadProperty(this, "image", data.image);
1200
1214
  loadProperty(this, "position", data.position);
1201
1215
  loadProperty(this, "repeat", data.repeat);
@@ -1741,7 +1755,7 @@
1741
1755
  }
1742
1756
  }
1743
1757
 
1744
- const styleCache = new Map(), maxStyleCacheSize = 2000, rgbFixedPrecision = 2, hslFixedPrecision = 2, sdrReferenceWhiteNits = 203;
1758
+ const styleCache = new Map(), maxStyleCacheSize = 2000, rgbFixedPrecision = 2, hslFixedPrecision = 2, hdrRgbFixedPrecision = 4, hdrHslFixedPrecision = 4, sdrReferenceWhiteNits = 203, hdrAnimationScale = sdrReferenceWhiteNits / maxNits;
1745
1759
  function getCachedStyle(key, generator) {
1746
1760
  let cached = styleCache.get(key);
1747
1761
  if (!cached) {
@@ -1881,6 +1895,17 @@
1881
1895
  : 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));
1882
1896
  return { r: Math.round(red), g: Math.round(green), b: Math.round(blue) };
1883
1897
  }
1898
+ function hslToRgbFloat(hsl) {
1899
+ 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;
1900
+ if (s === sMin) {
1901
+ const grayscaleValue = lNormalized * rgbMax;
1902
+ return { r: grayscaleValue, g: grayscaleValue, b: grayscaleValue };
1903
+ }
1904
+ const temp1 = lNormalized < half
1905
+ ? lNormalized * (sNormalizedOffset + sNormalized)
1906
+ : 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));
1907
+ return { r: red, g: green, b: blue };
1908
+ }
1884
1909
  function hslaToRgba(hsla) {
1885
1910
  const rgbResult = hslToRgb(hsla);
1886
1911
  return {
@@ -1890,8 +1915,9 @@
1890
1915
  r: rgbResult.r,
1891
1916
  };
1892
1917
  }
1893
- function getRandomRgbColor(min) {
1894
- const fixedMin = defaultRgbMin, fixedMax = rgbMax + identity$1, getRgbInRangeValue = () => Math.floor(getRandomInRange(fixedMin, fixedMax));
1918
+ function getRandomRgbColor(min, hdr) {
1919
+ const fixedMin = defaultRgbMin;
1920
+ const fixedMax = rgbMax + identity$1, getRgbInRangeValue = () => Math.floor(getRandomInRange(fixedMin, fixedMax));
1895
1921
  return {
1896
1922
  b: getRgbInRangeValue(),
1897
1923
  g: getRgbInRangeValue(),
@@ -1899,7 +1925,7 @@
1899
1925
  };
1900
1926
  }
1901
1927
  function getStyleFromRgb(color, hdr, opacity) {
1902
- const op = opacity ?? defaultOpacity$1, key = `rgb-${color.r.toFixed(rgbFixedPrecision)}-${color.g.toFixed(rgbFixedPrecision)}-${color.b.toFixed(rgbFixedPrecision)}-${hdr ? "hdr" : "sdr"}-${op.toString()}`;
1928
+ 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()}`;
1903
1929
  return getCachedStyle(key, () => (hdr ? getHdrStyleFromRgb(color, opacity) : getSdrStyleFromRgb(color, opacity)));
1904
1930
  }
1905
1931
  function getHdrStyleFromRgb(color, opacity, peakNits = maxNits) {
@@ -1910,9 +1936,9 @@
1910
1936
  return `rgba(${color.r.toString()}, ${color.g.toString()}, ${color.b.toString()}, ${(opacity ?? defaultOpacity$1).toString()})`;
1911
1937
  }
1912
1938
  function getStyleFromHsl(color, hdr, opacity) {
1913
- const op = opacity ?? defaultOpacity$1, key = `hsl-${color.h.toFixed(hslFixedPrecision)}-${color.s.toFixed(hslFixedPrecision)}-${color.l.toFixed(hslFixedPrecision)}-${hdr ? "hdr" : "sdr"}-${op.toString()}`;
1939
+ 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()}`;
1914
1940
  return getCachedStyle(key, () => hdr
1915
- ? getStyleFromRgb(hslToRgb(color), true, opacity)
1941
+ ? getStyleFromRgb(hslToRgbFloat(color), true, opacity)
1916
1942
  : `hsla(${color.h.toString()}, ${color.s.toString()}%, ${color.l.toString()}%, ${op.toString()})`);
1917
1943
  }
1918
1944
  function getHslFromAnimation(animation) {
@@ -1975,7 +2001,7 @@
1975
2001
  colorValue.velocity = defaultVelocity;
1976
2002
  }
1977
2003
  }
1978
- function updateColorValue(data, decrease, delta) {
2004
+ function updateColorValue(data, decrease, delta, hdr) {
1979
2005
  const minLoops = 0, minDelay = 0, identity = 1, minVelocity = 0, minOffset = 0, velocityFactor = 3.6;
1980
2006
  if (!data.enable ||
1981
2007
  ((data.maxLoops ?? minLoops) > minLoops && (data.loops ?? minLoops) > (data.maxLoops ?? minLoops))) {
@@ -1988,7 +2014,7 @@
1988
2014
  if ((data.delayTime ?? minDelay) > minDelay && data.time < (data.delayTime ?? minDelay)) {
1989
2015
  return;
1990
2016
  }
1991
- 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;
2017
+ 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;
1992
2018
  if (!decrease || data.status === AnimationStatus.increasing) {
1993
2019
  data.value += velocity;
1994
2020
  if (data.value > max) {
@@ -2015,14 +2041,14 @@
2015
2041
  }
2016
2042
  data.value = clamp(data.value, min, max);
2017
2043
  }
2018
- function updateColor(color, delta) {
2044
+ function updateColor(color, delta, hdr) {
2019
2045
  if (!color) {
2020
2046
  return;
2021
2047
  }
2022
2048
  const { h, s, l } = color;
2023
- updateColorValue(h, false, delta);
2024
- updateColorValue(s, true, delta);
2025
- updateColorValue(l, true, delta);
2049
+ updateColorValue(h, false, delta, hdr);
2050
+ updateColorValue(s, true, delta, hdr);
2051
+ updateColorValue(l, true, delta, hdr);
2026
2052
  }
2027
2053
  function alterHsl(color, type, value) {
2028
2054
  return {
@@ -2072,7 +2098,7 @@
2072
2098
  }
2073
2099
 
2074
2100
  async function loadBlendPlugin(engine) {
2075
- engine.checkVersion("4.2.1");
2101
+ engine.checkVersion("4.3.1");
2076
2102
  await engine.pluginManager.register(e => {
2077
2103
  e.pluginManager.addPlugin(new BlendPlugin());
2078
2104
  });
@@ -2109,7 +2135,7 @@
2109
2135
  }
2110
2136
 
2111
2137
  async function loadCircleShape(engine) {
2112
- engine.checkVersion("4.2.1");
2138
+ engine.checkVersion("4.3.1");
2113
2139
  await engine.pluginManager.register(e => {
2114
2140
  e.pluginManager.addShape(["circle"], () => {
2115
2141
  return Promise.resolve(new CircleDrawer());
@@ -2157,7 +2183,7 @@
2157
2183
  }
2158
2184
 
2159
2185
  async function loadHexColorPlugin(engine) {
2160
- engine.checkVersion("4.2.1");
2186
+ engine.checkVersion("4.3.1");
2161
2187
  await engine.pluginManager.register(e => {
2162
2188
  e.pluginManager.addColorManager("hex", new HexColorManager());
2163
2189
  });
@@ -2210,7 +2236,7 @@
2210
2236
  }
2211
2237
 
2212
2238
  async function loadHslColorPlugin(engine) {
2213
- engine.checkVersion("4.2.1");
2239
+ engine.checkVersion("4.3.1");
2214
2240
  await engine.pluginManager.register(e => {
2215
2241
  e.pluginManager.addColorManager("hsl", new HslColorManager());
2216
2242
  });
@@ -2234,7 +2260,7 @@
2234
2260
  }
2235
2261
 
2236
2262
  async function loadMovePlugin(engine) {
2237
- engine.checkVersion("4.2.1");
2263
+ engine.checkVersion("4.3.1");
2238
2264
  await engine.pluginManager.register(e => {
2239
2265
  const moveEngine = e, movePluginManager = moveEngine.pluginManager;
2240
2266
  movePluginManager.initializers.pathGenerators ??= new Map();
@@ -2444,7 +2470,7 @@
2444
2470
  }
2445
2471
 
2446
2472
  async function loadOpacityUpdater(engine) {
2447
- engine.checkVersion("4.2.1");
2473
+ engine.checkVersion("4.3.1");
2448
2474
  await engine.pluginManager.register(e => {
2449
2475
  e.pluginManager.addParticleUpdater("opacity", container => {
2450
2476
  return Promise.resolve(new OpacityUpdater(container));
@@ -2789,7 +2815,7 @@
2789
2815
  }
2790
2816
 
2791
2817
  async function loadOutModesUpdater(engine) {
2792
- engine.checkVersion("4.2.1");
2818
+ engine.checkVersion("4.3.1");
2793
2819
  await engine.pluginManager.register(e => {
2794
2820
  e.pluginManager.addParticleUpdater("outModes", container => {
2795
2821
  return Promise.resolve(new OutOfCanvasUpdater(container));
@@ -2854,13 +2880,13 @@
2854
2880
  if (!this.isEnabled(particle)) {
2855
2881
  return;
2856
2882
  }
2857
- updateColor(particle.fillColor, delta);
2858
- updateColor(particle.strokeColor, delta);
2883
+ updateColor(particle.fillColor, delta, this.#container.hdr);
2884
+ updateColor(particle.strokeColor, delta, this.#container.hdr);
2859
2885
  }
2860
2886
  }
2861
2887
 
2862
2888
  async function loadPaintUpdater(engine) {
2863
- engine.checkVersion("4.2.1");
2889
+ engine.checkVersion("4.3.1");
2864
2890
  await engine.pluginManager.register(e => {
2865
2891
  e.pluginManager.addParticleUpdater("paint", container => {
2866
2892
  return Promise.resolve(new PaintUpdater(e.pluginManager, container));
@@ -2915,7 +2941,7 @@
2915
2941
  }
2916
2942
 
2917
2943
  async function loadRgbColorPlugin(engine) {
2918
- engine.checkVersion("4.2.1");
2944
+ engine.checkVersion("4.3.1");
2919
2945
  await engine.pluginManager.register(e => {
2920
2946
  e.pluginManager.addColorManager("rgb", new RgbColorManager());
2921
2947
  });
@@ -3000,7 +3026,7 @@
3000
3026
  }
3001
3027
 
3002
3028
  async function loadSizeUpdater(engine) {
3003
- engine.checkVersion("4.2.1");
3029
+ engine.checkVersion("4.3.1");
3004
3030
  await engine.pluginManager.register(e => {
3005
3031
  e.pluginManager.addParticleUpdater("size", container => {
3006
3032
  return Promise.resolve(new SizeUpdater(container));
@@ -3009,7 +3035,7 @@
3009
3035
  }
3010
3036
 
3011
3037
  async function loadBasic(engine) {
3012
- engine.checkVersion("4.2.1");
3038
+ engine.checkVersion("4.3.1");
3013
3039
  await engine.pluginManager.register(async (e) => {
3014
3040
  await Promise.all([
3015
3041
  loadBlendPlugin(e),
@@ -3210,7 +3236,7 @@
3210
3236
  const clickEvent = "click", mouseDownEvent = "pointerdown", mouseUpEvent = "pointerup", mouseLeaveEvent = "pointerleave", mouseMoveEvent = "pointermove", touchStartEvent = "touchstart", touchEndEvent = "touchend", touchMoveEvent = "touchmove", touchCancelEvent = "touchcancel";
3211
3237
 
3212
3238
  async function loadInteractivityPlugin(engine) {
3213
- engine.checkVersion("4.2.1");
3239
+ engine.checkVersion("4.3.1");
3214
3240
  await engine.pluginManager.register(e => {
3215
3241
  const interactivityEngine = e, interactivityPluginManager = interactivityEngine.pluginManager;
3216
3242
  interactivityPluginManager.addPlugin(new InteractivityPlugin(interactivityPluginManager));
@@ -3407,7 +3433,7 @@
3407
3433
  }
3408
3434
 
3409
3435
  async function loadExternalTrailInteraction(engine) {
3410
- engine.checkVersion("4.2.1");
3436
+ engine.checkVersion("4.3.1");
3411
3437
  await engine.pluginManager.register((e) => {
3412
3438
  ensureInteractivityPluginLoaded(e);
3413
3439
  e.pluginManager.addInteractor?.("externalTrail", container => {
@@ -3553,7 +3579,7 @@
3553
3579
  }
3554
3580
 
3555
3581
  async function loadLifeUpdater(engine) {
3556
- engine.checkVersion("4.2.1");
3582
+ engine.checkVersion("4.3.1");
3557
3583
  await engine.pluginManager.register(e => {
3558
3584
  e.pluginManager.addParticleUpdater("life", container => {
3559
3585
  return Promise.resolve(new LifeUpdater(container));
@@ -3652,10 +3678,10 @@
3652
3678
  }
3653
3679
  }
3654
3680
  class RenderManager {
3681
+ #backgroundElement;
3682
+ #backgroundWarnings;
3655
3683
  #canvasClearPlugins;
3656
3684
  #canvasManager;
3657
- #canvasPaintPlugins;
3658
- #clearDrawPlugins;
3659
3685
  #colorPlugins;
3660
3686
  #container;
3661
3687
  #context;
@@ -3663,9 +3689,7 @@
3663
3689
  #drawParticlePlugins;
3664
3690
  #drawParticlesCleanupPlugins;
3665
3691
  #drawParticlesSetupPlugins;
3666
- #drawPlugins;
3667
- #drawSettingsCleanupPlugins;
3668
- #drawSettingsSetupPlugins;
3692
+ #layers;
3669
3693
  #pluginManager;
3670
3694
  #postDrawUpdaters;
3671
3695
  #preDrawUpdaters;
@@ -3677,18 +3701,25 @@
3677
3701
  this.#container = container;
3678
3702
  this.#canvasManager = canvasManager;
3679
3703
  this.#context = null;
3704
+ this.#backgroundElement = null;
3705
+ this.#backgroundWarnings = new Set();
3680
3706
  this.#preDrawUpdaters = [];
3681
3707
  this.#postDrawUpdaters = [];
3682
- this.#colorPlugins = [];
3683
3708
  this.#canvasClearPlugins = [];
3684
- this.#canvasPaintPlugins = [];
3685
- this.#clearDrawPlugins = [];
3709
+ this.#colorPlugins = [];
3686
3710
  this.#drawParticlePlugins = [];
3687
3711
  this.#drawParticlesCleanupPlugins = [];
3688
3712
  this.#drawParticlesSetupPlugins = [];
3689
- this.#drawPlugins = [];
3690
- this.#drawSettingsSetupPlugins = [];
3691
- this.#drawSettingsCleanupPlugins = [];
3713
+ this.#layers = {
3714
+ 0: [],
3715
+ 1: [],
3716
+ 2: [],
3717
+ 3: [],
3718
+ 4: [],
3719
+ 5: [],
3720
+ 6: [],
3721
+ 7: [],
3722
+ };
3692
3723
  }
3693
3724
  get settings() {
3694
3725
  return this.#contextSettings;
@@ -3702,32 +3733,38 @@
3702
3733
  });
3703
3734
  }
3704
3735
  clear() {
3705
- let pluginHandled = false;
3706
3736
  for (const plugin of this.#canvasClearPlugins) {
3707
- pluginHandled = plugin.canvasClear?.() ?? false;
3708
- if (pluginHandled) {
3709
- break;
3737
+ if (plugin.canvasClear?.() ?? false) {
3738
+ return;
3710
3739
  }
3711
3740
  }
3712
- if (pluginHandled) {
3713
- return;
3741
+ for (const layer of Object.values(DrawLayer)) {
3742
+ if (typeof layer === "number") {
3743
+ for (const plugin of this.#getLayerPlugins(layer)) {
3744
+ if (plugin.canvasClear?.() ?? false) {
3745
+ return;
3746
+ }
3747
+ }
3748
+ }
3714
3749
  }
3715
3750
  this.canvasClear();
3716
3751
  }
3717
3752
  destroy() {
3718
3753
  this.stop();
3754
+ this.#backgroundElement = null;
3755
+ this.#backgroundWarnings.clear();
3719
3756
  this.#preDrawUpdaters = [];
3720
3757
  this.#postDrawUpdaters = [];
3721
- this.#colorPlugins = [];
3722
3758
  this.#canvasClearPlugins = [];
3723
- this.#canvasPaintPlugins = [];
3724
- this.#clearDrawPlugins = [];
3759
+ this.#colorPlugins = [];
3725
3760
  this.#drawParticlePlugins = [];
3726
3761
  this.#drawParticlesCleanupPlugins = [];
3727
3762
  this.#drawParticlesSetupPlugins = [];
3728
- this.#drawPlugins = [];
3729
- this.#drawSettingsSetupPlugins = [];
3730
- this.#drawSettingsCleanupPlugins = [];
3763
+ for (const layer of Object.values(DrawLayer)) {
3764
+ if (typeof layer === "number") {
3765
+ this.#layers[layer] = [];
3766
+ }
3767
+ }
3731
3768
  }
3732
3769
  draw(cb) {
3733
3770
  const ctx = this.#context;
@@ -3784,21 +3821,40 @@
3784
3821
  });
3785
3822
  }
3786
3823
  drawParticles(delta) {
3787
- const { particles } = this.#container;
3824
+ const { particles, actualOptions } = this.#container;
3788
3825
  this.clear();
3789
3826
  particles.update(delta);
3790
3827
  this.draw(ctx => {
3791
- for (const plugin of this.#drawSettingsSetupPlugins) {
3828
+ const width = this.#canvasManager.size.width, height = this.#canvasManager.size.height;
3829
+ if (this.#backgroundElement) {
3830
+ try {
3831
+ ctx.drawImage(this.#backgroundElement, originPoint.x, originPoint.y, width, height);
3832
+ }
3833
+ catch {
3834
+ this.#warnOnce("background-element-draw-error", "Error drawing background element onto canvas");
3835
+ }
3836
+ }
3837
+ const background = actualOptions.background;
3838
+ if (background.draw) {
3839
+ try {
3840
+ background.draw(ctx, delta);
3841
+ }
3842
+ catch {
3843
+ this.#warnOnce("background-draw-error", "Error in background.draw callback");
3844
+ }
3845
+ }
3846
+ for (const plugin of this.#getLayerPlugins(DrawLayer.BackgroundMask)) {
3847
+ plugin.canvasPaint?.();
3848
+ }
3849
+ for (const plugin of this.#getLayerPlugins(DrawLayer.CanvasSetup)) {
3792
3850
  plugin.drawSettingsSetup?.(ctx, delta);
3793
3851
  }
3794
- for (const plugin of this.#drawPlugins) {
3852
+ for (const plugin of this.#getLayerPlugins(DrawLayer.PluginContent)) {
3795
3853
  plugin.draw?.(ctx, delta);
3796
3854
  }
3797
3855
  particles.drawParticles(delta);
3798
- for (const plugin of this.#clearDrawPlugins) {
3856
+ for (const plugin of this.#getLayerPlugins(DrawLayer.CanvasCleanup)) {
3799
3857
  plugin.clearDraw?.(ctx, delta);
3800
- }
3801
- for (const plugin of this.#drawSettingsCleanupPlugins) {
3802
3858
  plugin.drawSettingsCleanup?.(ctx, delta);
3803
3859
  }
3804
3860
  });
@@ -3806,29 +3862,24 @@
3806
3862
  init() {
3807
3863
  this.initUpdaters();
3808
3864
  this.initPlugins();
3865
+ this.#resolveBackgroundElement();
3809
3866
  this.paint();
3810
3867
  }
3811
3868
  initPlugins() {
3812
- this.#colorPlugins = [];
3813
3869
  this.#canvasClearPlugins = [];
3814
- this.#canvasPaintPlugins = [];
3815
- this.#clearDrawPlugins = [];
3870
+ this.#colorPlugins = [];
3816
3871
  this.#drawParticlePlugins = [];
3817
3872
  this.#drawParticlesSetupPlugins = [];
3818
3873
  this.#drawParticlesCleanupPlugins = [];
3819
- this.#drawPlugins = [];
3820
- this.#drawSettingsSetupPlugins = [];
3821
- this.#drawSettingsCleanupPlugins = [];
3874
+ for (const layer of Object.values(DrawLayer)) {
3875
+ if (typeof layer === "number") {
3876
+ this.#layers[layer] = [];
3877
+ }
3878
+ }
3822
3879
  for (const plugin of this.#container.plugins) {
3823
3880
  if (plugin.particleFillColor ?? plugin.particleStrokeColor) {
3824
3881
  this.#colorPlugins.push(plugin);
3825
3882
  }
3826
- if (plugin.canvasClear) {
3827
- this.#canvasClearPlugins.push(plugin);
3828
- }
3829
- if (plugin.canvasPaint) {
3830
- this.#canvasPaintPlugins.push(plugin);
3831
- }
3832
3883
  if (plugin.drawParticle) {
3833
3884
  this.#drawParticlePlugins.push(plugin);
3834
3885
  }
@@ -3838,17 +3889,20 @@
3838
3889
  if (plugin.drawParticleCleanup) {
3839
3890
  this.#drawParticlesCleanupPlugins.push(plugin);
3840
3891
  }
3841
- if (plugin.draw) {
3842
- this.#drawPlugins.push(plugin);
3892
+ if (plugin.canvasClear) {
3893
+ this.#canvasClearPlugins.push(plugin);
3894
+ }
3895
+ if (plugin.canvasPaint) {
3896
+ this.#getLayerPlugins(DrawLayer.BackgroundMask).push(plugin);
3843
3897
  }
3844
3898
  if (plugin.drawSettingsSetup) {
3845
- this.#drawSettingsSetupPlugins.push(plugin);
3899
+ this.#getLayerPlugins(DrawLayer.CanvasSetup).push(plugin);
3846
3900
  }
3847
- if (plugin.drawSettingsCleanup) {
3848
- this.#drawSettingsCleanupPlugins.push(plugin);
3901
+ if (plugin.draw) {
3902
+ this.#getLayerPlugins(DrawLayer.PluginContent).push(plugin);
3849
3903
  }
3850
- if (plugin.clearDraw) {
3851
- this.#clearDrawPlugins.push(plugin);
3904
+ if (plugin.clearDraw ?? plugin.drawSettingsCleanup) {
3905
+ this.#getLayerPlugins(DrawLayer.CanvasCleanup).push(plugin);
3852
3906
  }
3853
3907
  }
3854
3908
  }
@@ -3866,7 +3920,7 @@
3866
3920
  }
3867
3921
  paint() {
3868
3922
  let handled = false;
3869
- for (const plugin of this.#canvasPaintPlugins) {
3923
+ for (const plugin of this.#getLayerPlugins(DrawLayer.BackgroundMask)) {
3870
3924
  handled = plugin.canvasPaint?.() ?? false;
3871
3925
  if (handled) {
3872
3926
  break;
@@ -4039,6 +4093,9 @@
4039
4093
  }
4040
4094
  drawer.beforeDraw(data);
4041
4095
  }
4096
+ #getLayerPlugins(layer) {
4097
+ return this.#layers[layer];
4098
+ }
4042
4099
  #getPluginParticleColors(particle) {
4043
4100
  let fColor, sColor;
4044
4101
  for (const plugin of this.#colorPlugins) {
@@ -4056,6 +4113,39 @@
4056
4113
  this.#reusablePluginColors[sColorIndex] = sColor;
4057
4114
  return this.#reusablePluginColors;
4058
4115
  }
4116
+ #resolveBackgroundElement() {
4117
+ const background = this.#container.actualOptions.background;
4118
+ this.#backgroundElement = null;
4119
+ if (!background.element) {
4120
+ return;
4121
+ }
4122
+ if (typeof background.element === "string") {
4123
+ if (typeof document !== "undefined") {
4124
+ const node = document.querySelector(background.element);
4125
+ if (node instanceof HTMLCanvasElement || node instanceof HTMLVideoElement || node instanceof HTMLImageElement) {
4126
+ this.#backgroundElement = node;
4127
+ }
4128
+ else if (node) {
4129
+ this.#warnOnce("background-element-not-supported", `Background element "${background.element}" is not a supported drawable element (canvas, video, or img)`);
4130
+ }
4131
+ else {
4132
+ this.#warnOnce("background-element-not-found", `Background element selector "${background.element}" not found`);
4133
+ }
4134
+ }
4135
+ }
4136
+ else if (background.element instanceof HTMLCanvasElement ||
4137
+ background.element instanceof OffscreenCanvas ||
4138
+ background.element instanceof HTMLVideoElement ||
4139
+ background.element instanceof HTMLImageElement) {
4140
+ this.#backgroundElement = background.element;
4141
+ }
4142
+ }
4143
+ #warnOnce(key, message) {
4144
+ if (!this.#backgroundWarnings.has(key)) {
4145
+ this.#backgroundWarnings.add(key);
4146
+ getLogger().warning(message);
4147
+ }
4148
+ }
4059
4149
  }
4060
4150
 
4061
4151
  const transferredCanvases = new WeakMap(), getTransferredCanvas = (canvas) => {
@@ -4632,7 +4722,6 @@
4632
4722
  }
4633
4723
  class Particle {
4634
4724
  backColor;
4635
- bubble;
4636
4725
  destroyed;
4637
4726
  direction;
4638
4727
  effect;
@@ -4666,7 +4755,6 @@
4666
4755
  shapeData;
4667
4756
  sides;
4668
4757
  size;
4669
- slow;
4670
4758
  spawning;
4671
4759
  strokeColor;
4672
4760
  strokeOpacity;
@@ -4688,18 +4776,25 @@
4688
4776
  d: 1,
4689
4777
  };
4690
4778
  #container;
4779
+ #modifiers = [];
4691
4780
  #pluginManager;
4692
4781
  constructor(pluginManager, container) {
4693
4782
  this.#pluginManager = pluginManager;
4694
4783
  this.#container = container;
4695
4784
  }
4785
+ addModifier(modifier) {
4786
+ this.#modifiers.push(modifier);
4787
+ this.#modifiers.sort((a, b) => a.priority - b.priority);
4788
+ }
4789
+ clearModifiers() {
4790
+ this.#modifiers.length = 0;
4791
+ }
4696
4792
  destroy(override) {
4697
4793
  if (this.unbreakable || this.destroyed) {
4698
4794
  return;
4699
4795
  }
4700
4796
  this.destroyed = true;
4701
- this.bubble.inRange = false;
4702
- this.slow.inRange = false;
4797
+ this.clearModifiers();
4703
4798
  const container = this.#container, shapeDrawer = this.shape ? container.shapeDrawers.get(this.shape) : undefined;
4704
4799
  shapeDrawer?.particleDestroy?.(this);
4705
4800
  for (const plugin of container.particleDestroyedPlugins) {
@@ -4721,13 +4816,16 @@
4721
4816
  return this.rotation + (this.pathRotation ? this.velocity.angle : defaultAngle);
4722
4817
  }
4723
4818
  getFillColor() {
4724
- return this.#getRollColor(this.bubble.color ?? getHslFromAnimation(this.fillColor));
4819
+ return this.#getRollColor(this.#applyModifiers(getHslFromAnimation(this.fillColor), m => m.fillColor));
4725
4820
  }
4726
4821
  getMass() {
4727
4822
  return this.getRadius() ** squareExp * Math.PI * half;
4728
4823
  }
4824
+ getModifier(id) {
4825
+ return this.#modifiers.find(m => m.id === id);
4826
+ }
4729
4827
  getOpacity() {
4730
- 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;
4828
+ 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;
4731
4829
  this.#cachedOpacityData.fillOpacity = opacity * fillOpacity * zOpacityFactor;
4732
4830
  this.#cachedOpacityData.opacity = opacity * zOpacityFactor;
4733
4831
  this.#cachedOpacityData.strokeOpacity = opacity * strokeOpacity * zOpacityFactor;
@@ -4740,7 +4838,7 @@
4740
4838
  return this.#cachedPosition;
4741
4839
  }
4742
4840
  getRadius() {
4743
- return this.bubble.radius ?? this.size.value;
4841
+ return this.#applyModifiers(this.size.value, m => m.radius);
4744
4842
  }
4745
4843
  getRotateData() {
4746
4844
  const angle = this.getAngle();
@@ -4749,7 +4847,7 @@
4749
4847
  return this.#cachedRotateData;
4750
4848
  }
4751
4849
  getStrokeColor() {
4752
- return this.#getRollColor(this.bubble.color ?? getHslFromAnimation(this.strokeColor));
4850
+ return this.#getRollColor(this.#applyModifiers(getHslFromAnimation(this.strokeColor), m => m.strokeColor));
4753
4851
  }
4754
4852
  getTransformData(externalTransform) {
4755
4853
  const rotateData = this.getRotateData(), rotating = this.isRotating;
@@ -4769,13 +4867,6 @@
4769
4867
  this.options = resolveParticleOptions(this, container, this.#pluginManager, overrideOptions);
4770
4868
  container.retina.initParticle(this);
4771
4869
  runUpdaterPreInit(container.particleUpdaters, this);
4772
- this.bubble = {
4773
- inRange: false,
4774
- };
4775
- this.slow = {
4776
- inRange: false,
4777
- factor: 1,
4778
- };
4779
4870
  this.#initPosition(position);
4780
4871
  this.initialVelocity = this.#calculateVelocity();
4781
4872
  this.velocity = this.initialVelocity.copy();
@@ -4815,11 +4906,29 @@
4815
4906
  isVisible() {
4816
4907
  return !this.destroyed && !this.spawning && this.isInsideCanvas();
4817
4908
  }
4909
+ removeModifier(id) {
4910
+ const idx = this.#modifiers.findIndex(m => m.id === id);
4911
+ if (idx >= defaultAngle) {
4912
+ this.#modifiers.splice(idx, identity$1);
4913
+ }
4914
+ }
4818
4915
  reset() {
4819
4916
  for (const updater of this.#container.particleUpdaters) {
4820
4917
  updater.reset?.(this);
4821
4918
  }
4822
4919
  }
4920
+ #applyModifiers(base, getter) {
4921
+ let value = base;
4922
+ for (const mod of this.#modifiers) {
4923
+ if (mod.enabled) {
4924
+ const override = getter(mod);
4925
+ if (override !== undefined) {
4926
+ value = override;
4927
+ }
4928
+ }
4929
+ }
4930
+ return value;
4931
+ }
4823
4932
  #calcPosition(position, zIndex) {
4824
4933
  let tryCount = defaultRetryCount, posVec = position ? Vector3d.create(position.x, position.y, zIndex) : undefined;
4825
4934
  const container = this.#container, plugins = container.particlePositionPlugins, outModes = this.options.move.outModes, radius = this.getRadius(), canvasSize = container.canvas.size;
@@ -5921,6 +6030,7 @@
5921
6030
  });
5922
6031
 
5923
6032
  class BlendPluginInstance {
6033
+ layer = DrawLayer.CanvasSetup;
5924
6034
  #container;
5925
6035
  #defaultCompositeValue;
5926
6036
  constructor(container) {
@@ -6066,7 +6176,8 @@
6066
6176
  particle.lastPathTime -= pathDelay;
6067
6177
  }
6068
6178
  function getProximitySpeedFactor(particle) {
6069
- return particle.slow.inRange ? particle.slow.factor : identity$1;
6179
+ const mod = particle.getModifier("slow");
6180
+ return mod?.enabled ? (mod.speedFactor ?? identity$1) : identity$1;
6070
6181
  }
6071
6182
  function initSpin(container, particle) {
6072
6183
  const options = particle.options, spinOptions = options.move.spin;