@tsparticles/preset-fountain 4.2.0 → 4.3.0

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.0 */
2
+ /* Preset v4.3.0 */
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) :
@@ -371,29 +371,27 @@
371
371
  }
372
372
  }
373
373
  else if (!isObject(destination) || Array.isArray(destination)) {
374
- destination = {};
374
+ destination = Object.create(null);
375
375
  }
376
- const sourceKeys = Object.keys(source), dangerousKeys = new Set(["__proto__", "constructor", "prototype"]), hasNested = sourceKeys.some(k => {
376
+ const sourceKeys = Object.keys(source), hasNested = sourceKeys.some(k => {
377
377
  const v = source[k];
378
378
  return isObject(v) || Array.isArray(v);
379
379
  });
380
380
  if (!hasNested) {
381
381
  const sourceDict = source, destDict = destination;
382
382
  for (const key of sourceKeys) {
383
- if (dangerousKeys.has(key)) {
383
+ if (key === "__proto__" || key === "constructor" || key === "prototype") {
384
384
  continue;
385
385
  }
386
- if (key in sourceDict) {
387
- const v = sourceDict[key];
388
- if (v !== undefined) {
389
- destDict[key] = v;
390
- }
386
+ const v = sourceDict[key];
387
+ if (v !== undefined) {
388
+ destDict[key] = v;
391
389
  }
392
390
  }
393
391
  continue;
394
392
  }
395
393
  for (const key of sourceKeys) {
396
- if (dangerousKeys.has(key)) {
394
+ if (key === "__proto__" || key === "constructor" || key === "prototype") {
397
395
  continue;
398
396
  }
399
397
  const sourceDict = source, destDict = destination, value = sourceDict[key];
@@ -809,7 +807,7 @@
809
807
  return this.#domArray;
810
808
  }
811
809
  get version() {
812
- return "4.2.0";
810
+ return "4.3.0";
813
811
  }
814
812
  addEventListener(type, listener) {
815
813
  this.#eventDispatcher.addEventListener(type, listener);
@@ -1042,6 +1040,18 @@
1042
1040
  AnimationStatus["decreasing"] = "decreasing";
1043
1041
  })(AnimationStatus || (AnimationStatus = {}));
1044
1042
 
1043
+ var DrawLayer;
1044
+ (function (DrawLayer) {
1045
+ DrawLayer[DrawLayer["BackgroundElement"] = 0] = "BackgroundElement";
1046
+ DrawLayer[DrawLayer["BackgroundDraw"] = 1] = "BackgroundDraw";
1047
+ DrawLayer[DrawLayer["BackgroundMask"] = 2] = "BackgroundMask";
1048
+ DrawLayer[DrawLayer["CanvasSetup"] = 3] = "CanvasSetup";
1049
+ DrawLayer[DrawLayer["PluginContent"] = 4] = "PluginContent";
1050
+ DrawLayer[DrawLayer["Particles"] = 5] = "Particles";
1051
+ DrawLayer[DrawLayer["CanvasCleanup"] = 6] = "CanvasCleanup";
1052
+ DrawLayer[DrawLayer["Foreground"] = 7] = "Foreground";
1053
+ })(DrawLayer || (DrawLayer = {}));
1054
+
1045
1055
  class OptionLoader {
1046
1056
  load(data) {
1047
1057
  if (isNull(data)) {
@@ -1195,6 +1205,8 @@
1195
1205
 
1196
1206
  class Background extends OptionLoader {
1197
1207
  color;
1208
+ draw;
1209
+ element;
1198
1210
  image = "";
1199
1211
  opacity = 1;
1200
1212
  position = "";
@@ -1209,6 +1221,8 @@
1209
1221
  if (data.color !== undefined) {
1210
1222
  this.color = OptionsColor.create(this.color, data.color);
1211
1223
  }
1224
+ loadProperty(this, "element", data.element);
1225
+ loadProperty(this, "draw", data.draw);
1212
1226
  loadProperty(this, "image", data.image);
1213
1227
  loadProperty(this, "position", data.position);
1214
1228
  loadProperty(this, "repeat", data.repeat);
@@ -1754,7 +1768,7 @@
1754
1768
  }
1755
1769
  }
1756
1770
 
1757
- const styleCache = new Map(), maxStyleCacheSize = 2000, rgbFixedPrecision = 2, hslFixedPrecision = 2, sdrReferenceWhiteNits = 203;
1771
+ const styleCache = new Map(), maxStyleCacheSize = 2000, rgbFixedPrecision = 2, hslFixedPrecision = 2, hdrRgbFixedPrecision = 4, hdrHslFixedPrecision = 4, sdrReferenceWhiteNits = 203, hdrAnimationScale = sdrReferenceWhiteNits / maxNits;
1758
1772
  function getCachedStyle(key, generator) {
1759
1773
  let cached = styleCache.get(key);
1760
1774
  if (!cached) {
@@ -1894,6 +1908,17 @@
1894
1908
  : 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));
1895
1909
  return { r: Math.round(red), g: Math.round(green), b: Math.round(blue) };
1896
1910
  }
1911
+ function hslToRgbFloat(hsl) {
1912
+ 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;
1913
+ if (s === sMin) {
1914
+ const grayscaleValue = lNormalized * rgbMax;
1915
+ return { r: grayscaleValue, g: grayscaleValue, b: grayscaleValue };
1916
+ }
1917
+ const temp1 = lNormalized < half
1918
+ ? lNormalized * (sNormalizedOffset + sNormalized)
1919
+ : 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));
1920
+ return { r: red, g: green, b: blue };
1921
+ }
1897
1922
  function hslaToRgba(hsla) {
1898
1923
  const rgbResult = hslToRgb(hsla);
1899
1924
  return {
@@ -1903,8 +1928,9 @@
1903
1928
  r: rgbResult.r,
1904
1929
  };
1905
1930
  }
1906
- function getRandomRgbColor(min) {
1907
- const fixedMin = defaultRgbMin, fixedMax = rgbMax + identity, getRgbInRangeValue = () => Math.floor(getRandomInRange(fixedMin, fixedMax));
1931
+ function getRandomRgbColor(min, hdr) {
1932
+ const fixedMin = defaultRgbMin;
1933
+ const fixedMax = rgbMax + identity, getRgbInRangeValue = () => Math.floor(getRandomInRange(fixedMin, fixedMax));
1908
1934
  return {
1909
1935
  b: getRgbInRangeValue(),
1910
1936
  g: getRgbInRangeValue(),
@@ -1912,7 +1938,7 @@
1912
1938
  };
1913
1939
  }
1914
1940
  function getStyleFromRgb(color, hdr, opacity) {
1915
- const op = opacity ?? defaultOpacity$1, key = `rgb-${color.r.toFixed(rgbFixedPrecision)}-${color.g.toFixed(rgbFixedPrecision)}-${color.b.toFixed(rgbFixedPrecision)}-${hdr ? "hdr" : "sdr"}-${op.toString()}`;
1941
+ 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()}`;
1916
1942
  return getCachedStyle(key, () => (hdr ? getHdrStyleFromRgb(color, opacity) : getSdrStyleFromRgb(color, opacity)));
1917
1943
  }
1918
1944
  function getHdrStyleFromRgb(color, opacity, peakNits = maxNits) {
@@ -1923,9 +1949,9 @@
1923
1949
  return `rgba(${color.r.toString()}, ${color.g.toString()}, ${color.b.toString()}, ${(opacity ?? defaultOpacity$1).toString()})`;
1924
1950
  }
1925
1951
  function getStyleFromHsl(color, hdr, opacity) {
1926
- const op = opacity ?? defaultOpacity$1, key = `hsl-${color.h.toFixed(hslFixedPrecision)}-${color.s.toFixed(hslFixedPrecision)}-${color.l.toFixed(hslFixedPrecision)}-${hdr ? "hdr" : "sdr"}-${op.toString()}`;
1952
+ 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()}`;
1927
1953
  return getCachedStyle(key, () => hdr
1928
- ? getStyleFromRgb(hslToRgb(color), true, opacity)
1954
+ ? getStyleFromRgb(hslToRgbFloat(color), true, opacity)
1929
1955
  : `hsla(${color.h.toString()}, ${color.s.toString()}%, ${color.l.toString()}%, ${op.toString()})`);
1930
1956
  }
1931
1957
  function getHslFromAnimation(animation) {
@@ -1988,7 +2014,7 @@
1988
2014
  colorValue.velocity = defaultVelocity;
1989
2015
  }
1990
2016
  }
1991
- function updateColorValue(data, decrease, delta) {
2017
+ function updateColorValue(data, decrease, delta, hdr) {
1992
2018
  const minLoops = 0, minDelay = 0, identity = 1, minVelocity = 0, minOffset = 0, velocityFactor = 3.6;
1993
2019
  if (!data.enable ||
1994
2020
  ((data.maxLoops ?? minLoops) > minLoops && (data.loops ?? minLoops) > (data.maxLoops ?? minLoops))) {
@@ -2001,7 +2027,7 @@
2001
2027
  if ((data.delayTime ?? minDelay) > minDelay && data.time < (data.delayTime ?? minDelay)) {
2002
2028
  return;
2003
2029
  }
2004
- 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;
2030
+ 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;
2005
2031
  if (!decrease || data.status === AnimationStatus.increasing) {
2006
2032
  data.value += velocity;
2007
2033
  if (data.value > max) {
@@ -2028,14 +2054,14 @@
2028
2054
  }
2029
2055
  data.value = clamp(data.value, min, max);
2030
2056
  }
2031
- function updateColor(color, delta) {
2057
+ function updateColor(color, delta, hdr) {
2032
2058
  if (!color) {
2033
2059
  return;
2034
2060
  }
2035
2061
  const { h, s, l } = color;
2036
- updateColorValue(h, false, delta);
2037
- updateColorValue(s, true, delta);
2038
- updateColorValue(l, true, delta);
2062
+ updateColorValue(h, false, delta, hdr);
2063
+ updateColorValue(s, true, delta, hdr);
2064
+ updateColorValue(l, true, delta, hdr);
2039
2065
  }
2040
2066
  function alterHsl(color, type, value) {
2041
2067
  return {
@@ -2085,7 +2111,7 @@
2085
2111
  }
2086
2112
 
2087
2113
  async function loadBlendPlugin(engine) {
2088
- engine.checkVersion("4.2.0");
2114
+ engine.checkVersion("4.3.0");
2089
2115
  await engine.pluginManager.register(e => {
2090
2116
  e.pluginManager.addPlugin(new BlendPlugin());
2091
2117
  });
@@ -2122,7 +2148,7 @@
2122
2148
  }
2123
2149
 
2124
2150
  async function loadCircleShape(engine) {
2125
- engine.checkVersion("4.2.0");
2151
+ engine.checkVersion("4.3.0");
2126
2152
  await engine.pluginManager.register(e => {
2127
2153
  e.pluginManager.addShape(["circle"], () => {
2128
2154
  return Promise.resolve(new CircleDrawer());
@@ -2170,7 +2196,7 @@
2170
2196
  }
2171
2197
 
2172
2198
  async function loadHexColorPlugin(engine) {
2173
- engine.checkVersion("4.2.0");
2199
+ engine.checkVersion("4.3.0");
2174
2200
  await engine.pluginManager.register(e => {
2175
2201
  e.pluginManager.addColorManager("hex", new HexColorManager());
2176
2202
  });
@@ -2223,7 +2249,7 @@
2223
2249
  }
2224
2250
 
2225
2251
  async function loadHslColorPlugin(engine) {
2226
- engine.checkVersion("4.2.0");
2252
+ engine.checkVersion("4.3.0");
2227
2253
  await engine.pluginManager.register(e => {
2228
2254
  e.pluginManager.addColorManager("hsl", new HslColorManager());
2229
2255
  });
@@ -2247,7 +2273,7 @@
2247
2273
  }
2248
2274
 
2249
2275
  async function loadMovePlugin(engine) {
2250
- engine.checkVersion("4.2.0");
2276
+ engine.checkVersion("4.3.0");
2251
2277
  await engine.pluginManager.register(e => {
2252
2278
  const moveEngine = e, movePluginManager = moveEngine.pluginManager;
2253
2279
  movePluginManager.initializers.pathGenerators ??= new Map();
@@ -2457,7 +2483,7 @@
2457
2483
  }
2458
2484
 
2459
2485
  async function loadOpacityUpdater(engine) {
2460
- engine.checkVersion("4.2.0");
2486
+ engine.checkVersion("4.3.0");
2461
2487
  await engine.pluginManager.register(e => {
2462
2488
  e.pluginManager.addParticleUpdater("opacity", container => {
2463
2489
  return Promise.resolve(new OpacityUpdater(container));
@@ -2802,7 +2828,7 @@
2802
2828
  }
2803
2829
 
2804
2830
  async function loadOutModesUpdater(engine) {
2805
- engine.checkVersion("4.2.0");
2831
+ engine.checkVersion("4.3.0");
2806
2832
  await engine.pluginManager.register(e => {
2807
2833
  e.pluginManager.addParticleUpdater("outModes", container => {
2808
2834
  return Promise.resolve(new OutOfCanvasUpdater(container));
@@ -2867,13 +2893,13 @@
2867
2893
  if (!this.isEnabled(particle)) {
2868
2894
  return;
2869
2895
  }
2870
- updateColor(particle.fillColor, delta);
2871
- updateColor(particle.strokeColor, delta);
2896
+ updateColor(particle.fillColor, delta, this.#container.hdr);
2897
+ updateColor(particle.strokeColor, delta, this.#container.hdr);
2872
2898
  }
2873
2899
  }
2874
2900
 
2875
2901
  async function loadPaintUpdater(engine) {
2876
- engine.checkVersion("4.2.0");
2902
+ engine.checkVersion("4.3.0");
2877
2903
  await engine.pluginManager.register(e => {
2878
2904
  e.pluginManager.addParticleUpdater("paint", container => {
2879
2905
  return Promise.resolve(new PaintUpdater(e.pluginManager, container));
@@ -2928,7 +2954,7 @@
2928
2954
  }
2929
2955
 
2930
2956
  async function loadRgbColorPlugin(engine) {
2931
- engine.checkVersion("4.2.0");
2957
+ engine.checkVersion("4.3.0");
2932
2958
  await engine.pluginManager.register(e => {
2933
2959
  e.pluginManager.addColorManager("rgb", new RgbColorManager());
2934
2960
  });
@@ -3013,7 +3039,7 @@
3013
3039
  }
3014
3040
 
3015
3041
  async function loadSizeUpdater(engine) {
3016
- engine.checkVersion("4.2.0");
3042
+ engine.checkVersion("4.3.0");
3017
3043
  await engine.pluginManager.register(e => {
3018
3044
  e.pluginManager.addParticleUpdater("size", container => {
3019
3045
  return Promise.resolve(new SizeUpdater(container));
@@ -3022,7 +3048,7 @@
3022
3048
  }
3023
3049
 
3024
3050
  async function loadBasic(engine) {
3025
- engine.checkVersion("4.2.0");
3051
+ engine.checkVersion("4.3.0");
3026
3052
  await engine.pluginManager.register(async (e) => {
3027
3053
  await Promise.all([
3028
3054
  loadBlendPlugin(e),
@@ -3353,7 +3379,7 @@
3353
3379
  }
3354
3380
 
3355
3381
  async function loadDestroyUpdater(engine) {
3356
- engine.checkVersion("4.2.0");
3382
+ engine.checkVersion("4.3.0");
3357
3383
  await engine.pluginManager.register(e => {
3358
3384
  e.pluginManager.addParticleUpdater("destroy", container => {
3359
3385
  return Promise.resolve(new DestroyUpdater(e.pluginManager, container));
@@ -3567,7 +3593,7 @@
3567
3593
  })(EmitterClickMode || (EmitterClickMode = {}));
3568
3594
 
3569
3595
  async function loadEmittersPluginSimple(engine) {
3570
- engine.checkVersion("4.2.0");
3596
+ engine.checkVersion("4.3.0");
3571
3597
  await engine.pluginManager.register(async (e) => {
3572
3598
  const instancesManager = await getEmittersInstancesManager(e);
3573
3599
  await addEmittersShapesManager(e);
@@ -3631,7 +3657,7 @@
3631
3657
  }
3632
3658
 
3633
3659
  async function loadTrailPlugin(engine) {
3634
- engine.checkVersion("4.2.0");
3660
+ engine.checkVersion("4.3.0");
3635
3661
  await engine.pluginManager.register(e => {
3636
3662
  e.pluginManager.addPlugin(new TrailPlugin(e.pluginManager));
3637
3663
  });
@@ -3760,10 +3786,10 @@
3760
3786
  }
3761
3787
  }
3762
3788
  class RenderManager {
3789
+ #backgroundElement;
3790
+ #backgroundWarnings;
3763
3791
  #canvasClearPlugins;
3764
3792
  #canvasManager;
3765
- #canvasPaintPlugins;
3766
- #clearDrawPlugins;
3767
3793
  #colorPlugins;
3768
3794
  #container;
3769
3795
  #context;
@@ -3771,9 +3797,7 @@
3771
3797
  #drawParticlePlugins;
3772
3798
  #drawParticlesCleanupPlugins;
3773
3799
  #drawParticlesSetupPlugins;
3774
- #drawPlugins;
3775
- #drawSettingsCleanupPlugins;
3776
- #drawSettingsSetupPlugins;
3800
+ #layers;
3777
3801
  #pluginManager;
3778
3802
  #postDrawUpdaters;
3779
3803
  #preDrawUpdaters;
@@ -3785,18 +3809,25 @@
3785
3809
  this.#container = container;
3786
3810
  this.#canvasManager = canvasManager;
3787
3811
  this.#context = null;
3812
+ this.#backgroundElement = null;
3813
+ this.#backgroundWarnings = new Set();
3788
3814
  this.#preDrawUpdaters = [];
3789
3815
  this.#postDrawUpdaters = [];
3790
- this.#colorPlugins = [];
3791
3816
  this.#canvasClearPlugins = [];
3792
- this.#canvasPaintPlugins = [];
3793
- this.#clearDrawPlugins = [];
3817
+ this.#colorPlugins = [];
3794
3818
  this.#drawParticlePlugins = [];
3795
3819
  this.#drawParticlesCleanupPlugins = [];
3796
3820
  this.#drawParticlesSetupPlugins = [];
3797
- this.#drawPlugins = [];
3798
- this.#drawSettingsSetupPlugins = [];
3799
- this.#drawSettingsCleanupPlugins = [];
3821
+ this.#layers = {
3822
+ 0: [],
3823
+ 1: [],
3824
+ 2: [],
3825
+ 3: [],
3826
+ 4: [],
3827
+ 5: [],
3828
+ 6: [],
3829
+ 7: [],
3830
+ };
3800
3831
  }
3801
3832
  get settings() {
3802
3833
  return this.#contextSettings;
@@ -3810,32 +3841,38 @@
3810
3841
  });
3811
3842
  }
3812
3843
  clear() {
3813
- let pluginHandled = false;
3814
3844
  for (const plugin of this.#canvasClearPlugins) {
3815
- pluginHandled = plugin.canvasClear?.() ?? false;
3816
- if (pluginHandled) {
3817
- break;
3845
+ if (plugin.canvasClear?.() ?? false) {
3846
+ return;
3818
3847
  }
3819
3848
  }
3820
- if (pluginHandled) {
3821
- return;
3849
+ for (const layer of Object.values(DrawLayer)) {
3850
+ if (typeof layer === "number") {
3851
+ for (const plugin of this.#getLayerPlugins(layer)) {
3852
+ if (plugin.canvasClear?.() ?? false) {
3853
+ return;
3854
+ }
3855
+ }
3856
+ }
3822
3857
  }
3823
3858
  this.canvasClear();
3824
3859
  }
3825
3860
  destroy() {
3826
3861
  this.stop();
3862
+ this.#backgroundElement = null;
3863
+ this.#backgroundWarnings.clear();
3827
3864
  this.#preDrawUpdaters = [];
3828
3865
  this.#postDrawUpdaters = [];
3829
- this.#colorPlugins = [];
3830
3866
  this.#canvasClearPlugins = [];
3831
- this.#canvasPaintPlugins = [];
3832
- this.#clearDrawPlugins = [];
3867
+ this.#colorPlugins = [];
3833
3868
  this.#drawParticlePlugins = [];
3834
3869
  this.#drawParticlesCleanupPlugins = [];
3835
3870
  this.#drawParticlesSetupPlugins = [];
3836
- this.#drawPlugins = [];
3837
- this.#drawSettingsSetupPlugins = [];
3838
- this.#drawSettingsCleanupPlugins = [];
3871
+ for (const layer of Object.values(DrawLayer)) {
3872
+ if (typeof layer === "number") {
3873
+ this.#layers[layer] = [];
3874
+ }
3875
+ }
3839
3876
  }
3840
3877
  draw(cb) {
3841
3878
  const ctx = this.#context;
@@ -3892,21 +3929,40 @@
3892
3929
  });
3893
3930
  }
3894
3931
  drawParticles(delta) {
3895
- const { particles } = this.#container;
3932
+ const { particles, actualOptions } = this.#container;
3896
3933
  this.clear();
3897
3934
  particles.update(delta);
3898
3935
  this.draw(ctx => {
3899
- for (const plugin of this.#drawSettingsSetupPlugins) {
3936
+ const width = this.#canvasManager.size.width, height = this.#canvasManager.size.height;
3937
+ if (this.#backgroundElement) {
3938
+ try {
3939
+ ctx.drawImage(this.#backgroundElement, originPoint.x, originPoint.y, width, height);
3940
+ }
3941
+ catch {
3942
+ this.#warnOnce("background-element-draw-error", "Error drawing background element onto canvas");
3943
+ }
3944
+ }
3945
+ const background = actualOptions.background;
3946
+ if (background.draw) {
3947
+ try {
3948
+ background.draw(ctx, delta);
3949
+ }
3950
+ catch {
3951
+ this.#warnOnce("background-draw-error", "Error in background.draw callback");
3952
+ }
3953
+ }
3954
+ for (const plugin of this.#getLayerPlugins(DrawLayer.BackgroundMask)) {
3955
+ plugin.canvasPaint?.();
3956
+ }
3957
+ for (const plugin of this.#getLayerPlugins(DrawLayer.CanvasSetup)) {
3900
3958
  plugin.drawSettingsSetup?.(ctx, delta);
3901
3959
  }
3902
- for (const plugin of this.#drawPlugins) {
3960
+ for (const plugin of this.#getLayerPlugins(DrawLayer.PluginContent)) {
3903
3961
  plugin.draw?.(ctx, delta);
3904
3962
  }
3905
3963
  particles.drawParticles(delta);
3906
- for (const plugin of this.#clearDrawPlugins) {
3964
+ for (const plugin of this.#getLayerPlugins(DrawLayer.CanvasCleanup)) {
3907
3965
  plugin.clearDraw?.(ctx, delta);
3908
- }
3909
- for (const plugin of this.#drawSettingsCleanupPlugins) {
3910
3966
  plugin.drawSettingsCleanup?.(ctx, delta);
3911
3967
  }
3912
3968
  });
@@ -3914,29 +3970,24 @@
3914
3970
  init() {
3915
3971
  this.initUpdaters();
3916
3972
  this.initPlugins();
3973
+ this.#resolveBackgroundElement();
3917
3974
  this.paint();
3918
3975
  }
3919
3976
  initPlugins() {
3920
- this.#colorPlugins = [];
3921
3977
  this.#canvasClearPlugins = [];
3922
- this.#canvasPaintPlugins = [];
3923
- this.#clearDrawPlugins = [];
3978
+ this.#colorPlugins = [];
3924
3979
  this.#drawParticlePlugins = [];
3925
3980
  this.#drawParticlesSetupPlugins = [];
3926
3981
  this.#drawParticlesCleanupPlugins = [];
3927
- this.#drawPlugins = [];
3928
- this.#drawSettingsSetupPlugins = [];
3929
- this.#drawSettingsCleanupPlugins = [];
3982
+ for (const layer of Object.values(DrawLayer)) {
3983
+ if (typeof layer === "number") {
3984
+ this.#layers[layer] = [];
3985
+ }
3986
+ }
3930
3987
  for (const plugin of this.#container.plugins) {
3931
3988
  if (plugin.particleFillColor ?? plugin.particleStrokeColor) {
3932
3989
  this.#colorPlugins.push(plugin);
3933
3990
  }
3934
- if (plugin.canvasClear) {
3935
- this.#canvasClearPlugins.push(plugin);
3936
- }
3937
- if (plugin.canvasPaint) {
3938
- this.#canvasPaintPlugins.push(plugin);
3939
- }
3940
3991
  if (plugin.drawParticle) {
3941
3992
  this.#drawParticlePlugins.push(plugin);
3942
3993
  }
@@ -3946,17 +3997,20 @@
3946
3997
  if (plugin.drawParticleCleanup) {
3947
3998
  this.#drawParticlesCleanupPlugins.push(plugin);
3948
3999
  }
3949
- if (plugin.draw) {
3950
- this.#drawPlugins.push(plugin);
4000
+ if (plugin.canvasClear) {
4001
+ this.#canvasClearPlugins.push(plugin);
4002
+ }
4003
+ if (plugin.canvasPaint) {
4004
+ this.#getLayerPlugins(DrawLayer.BackgroundMask).push(plugin);
3951
4005
  }
3952
4006
  if (plugin.drawSettingsSetup) {
3953
- this.#drawSettingsSetupPlugins.push(plugin);
4007
+ this.#getLayerPlugins(DrawLayer.CanvasSetup).push(plugin);
3954
4008
  }
3955
- if (plugin.drawSettingsCleanup) {
3956
- this.#drawSettingsCleanupPlugins.push(plugin);
4009
+ if (plugin.draw) {
4010
+ this.#getLayerPlugins(DrawLayer.PluginContent).push(plugin);
3957
4011
  }
3958
- if (plugin.clearDraw) {
3959
- this.#clearDrawPlugins.push(plugin);
4012
+ if (plugin.clearDraw ?? plugin.drawSettingsCleanup) {
4013
+ this.#getLayerPlugins(DrawLayer.CanvasCleanup).push(plugin);
3960
4014
  }
3961
4015
  }
3962
4016
  }
@@ -3974,7 +4028,7 @@
3974
4028
  }
3975
4029
  paint() {
3976
4030
  let handled = false;
3977
- for (const plugin of this.#canvasPaintPlugins) {
4031
+ for (const plugin of this.#getLayerPlugins(DrawLayer.BackgroundMask)) {
3978
4032
  handled = plugin.canvasPaint?.() ?? false;
3979
4033
  if (handled) {
3980
4034
  break;
@@ -4147,6 +4201,9 @@
4147
4201
  }
4148
4202
  drawer.beforeDraw(data);
4149
4203
  }
4204
+ #getLayerPlugins(layer) {
4205
+ return this.#layers[layer];
4206
+ }
4150
4207
  #getPluginParticleColors(particle) {
4151
4208
  let fColor, sColor;
4152
4209
  for (const plugin of this.#colorPlugins) {
@@ -4164,6 +4221,39 @@
4164
4221
  this.#reusablePluginColors[sColorIndex] = sColor;
4165
4222
  return this.#reusablePluginColors;
4166
4223
  }
4224
+ #resolveBackgroundElement() {
4225
+ const background = this.#container.actualOptions.background;
4226
+ this.#backgroundElement = null;
4227
+ if (!background.element) {
4228
+ return;
4229
+ }
4230
+ if (typeof background.element === "string") {
4231
+ if (typeof document !== "undefined") {
4232
+ const node = document.querySelector(background.element);
4233
+ if (node instanceof HTMLCanvasElement || node instanceof HTMLVideoElement || node instanceof HTMLImageElement) {
4234
+ this.#backgroundElement = node;
4235
+ }
4236
+ else if (node) {
4237
+ this.#warnOnce("background-element-not-supported", `Background element "${background.element}" is not a supported drawable element (canvas, video, or img)`);
4238
+ }
4239
+ else {
4240
+ this.#warnOnce("background-element-not-found", `Background element selector "${background.element}" not found`);
4241
+ }
4242
+ }
4243
+ }
4244
+ else if (background.element instanceof HTMLCanvasElement ||
4245
+ background.element instanceof OffscreenCanvas ||
4246
+ background.element instanceof HTMLVideoElement ||
4247
+ background.element instanceof HTMLImageElement) {
4248
+ this.#backgroundElement = background.element;
4249
+ }
4250
+ }
4251
+ #warnOnce(key, message) {
4252
+ if (!this.#backgroundWarnings.has(key)) {
4253
+ this.#backgroundWarnings.add(key);
4254
+ getLogger().warning(message);
4255
+ }
4256
+ }
4167
4257
  }
4168
4258
 
4169
4259
  const transferredCanvases = new WeakMap(), getTransferredCanvas = (canvas) => {
@@ -4740,7 +4830,6 @@
4740
4830
  }
4741
4831
  class Particle {
4742
4832
  backColor;
4743
- bubble;
4744
4833
  destroyed;
4745
4834
  direction;
4746
4835
  effect;
@@ -4774,7 +4863,6 @@
4774
4863
  shapeData;
4775
4864
  sides;
4776
4865
  size;
4777
- slow;
4778
4866
  spawning;
4779
4867
  strokeColor;
4780
4868
  strokeOpacity;
@@ -4796,18 +4884,25 @@
4796
4884
  d: 1,
4797
4885
  };
4798
4886
  #container;
4887
+ #modifiers = [];
4799
4888
  #pluginManager;
4800
4889
  constructor(pluginManager, container) {
4801
4890
  this.#pluginManager = pluginManager;
4802
4891
  this.#container = container;
4803
4892
  }
4893
+ addModifier(modifier) {
4894
+ this.#modifiers.push(modifier);
4895
+ this.#modifiers.sort((a, b) => a.priority - b.priority);
4896
+ }
4897
+ clearModifiers() {
4898
+ this.#modifiers.length = 0;
4899
+ }
4804
4900
  destroy(override) {
4805
4901
  if (this.unbreakable || this.destroyed) {
4806
4902
  return;
4807
4903
  }
4808
4904
  this.destroyed = true;
4809
- this.bubble.inRange = false;
4810
- this.slow.inRange = false;
4905
+ this.clearModifiers();
4811
4906
  const container = this.#container, shapeDrawer = this.shape ? container.shapeDrawers.get(this.shape) : undefined;
4812
4907
  shapeDrawer?.particleDestroy?.(this);
4813
4908
  for (const plugin of container.particleDestroyedPlugins) {
@@ -4829,13 +4924,16 @@
4829
4924
  return this.rotation + (this.pathRotation ? this.velocity.angle : defaultAngle);
4830
4925
  }
4831
4926
  getFillColor() {
4832
- return this.#getRollColor(this.bubble.color ?? getHslFromAnimation(this.fillColor));
4927
+ return this.#getRollColor(this.#applyModifiers(getHslFromAnimation(this.fillColor), m => m.fillColor));
4833
4928
  }
4834
4929
  getMass() {
4835
4930
  return this.getRadius() ** squareExp * Math.PI * half;
4836
4931
  }
4932
+ getModifier(id) {
4933
+ return this.#modifiers.find(m => m.id === id);
4934
+ }
4837
4935
  getOpacity() {
4838
- 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;
4936
+ 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;
4839
4937
  this.#cachedOpacityData.fillOpacity = opacity * fillOpacity * zOpacityFactor;
4840
4938
  this.#cachedOpacityData.opacity = opacity * zOpacityFactor;
4841
4939
  this.#cachedOpacityData.strokeOpacity = opacity * strokeOpacity * zOpacityFactor;
@@ -4848,7 +4946,7 @@
4848
4946
  return this.#cachedPosition;
4849
4947
  }
4850
4948
  getRadius() {
4851
- return this.bubble.radius ?? this.size.value;
4949
+ return this.#applyModifiers(this.size.value, m => m.radius);
4852
4950
  }
4853
4951
  getRotateData() {
4854
4952
  const angle = this.getAngle();
@@ -4857,7 +4955,7 @@
4857
4955
  return this.#cachedRotateData;
4858
4956
  }
4859
4957
  getStrokeColor() {
4860
- return this.#getRollColor(this.bubble.color ?? getHslFromAnimation(this.strokeColor));
4958
+ return this.#getRollColor(this.#applyModifiers(getHslFromAnimation(this.strokeColor), m => m.strokeColor));
4861
4959
  }
4862
4960
  getTransformData(externalTransform) {
4863
4961
  const rotateData = this.getRotateData(), rotating = this.isRotating;
@@ -4877,13 +4975,6 @@
4877
4975
  this.options = resolveParticleOptions(this, container, this.#pluginManager, overrideOptions);
4878
4976
  container.retina.initParticle(this);
4879
4977
  runUpdaterPreInit(container.particleUpdaters, this);
4880
- this.bubble = {
4881
- inRange: false,
4882
- };
4883
- this.slow = {
4884
- inRange: false,
4885
- factor: 1,
4886
- };
4887
4978
  this.#initPosition(position);
4888
4979
  this.initialVelocity = this.#calculateVelocity();
4889
4980
  this.velocity = this.initialVelocity.copy();
@@ -4923,11 +5014,29 @@
4923
5014
  isVisible() {
4924
5015
  return !this.destroyed && !this.spawning && this.isInsideCanvas();
4925
5016
  }
5017
+ removeModifier(id) {
5018
+ const idx = this.#modifiers.findIndex(m => m.id === id);
5019
+ if (idx >= defaultAngle) {
5020
+ this.#modifiers.splice(idx, identity);
5021
+ }
5022
+ }
4926
5023
  reset() {
4927
5024
  for (const updater of this.#container.particleUpdaters) {
4928
5025
  updater.reset?.(this);
4929
5026
  }
4930
5027
  }
5028
+ #applyModifiers(base, getter) {
5029
+ let value = base;
5030
+ for (const mod of this.#modifiers) {
5031
+ if (mod.enabled) {
5032
+ const override = getter(mod);
5033
+ if (override !== undefined) {
5034
+ value = override;
5035
+ }
5036
+ }
5037
+ }
5038
+ return value;
5039
+ }
4931
5040
  #calcPosition(position, zIndex) {
4932
5041
  let tryCount = defaultRetryCount, posVec = position ? Vector3d.create(position.x, position.y, zIndex) : undefined;
4933
5042
  const container = this.#container, plugins = container.particlePositionPlugins, outModes = this.options.move.outModes, radius = this.getRadius(), canvasSize = container.canvas.size;
@@ -6029,6 +6138,7 @@
6029
6138
  });
6030
6139
 
6031
6140
  class BlendPluginInstance {
6141
+ layer = DrawLayer.CanvasSetup;
6032
6142
  #container;
6033
6143
  #defaultCompositeValue;
6034
6144
  constructor(container) {
@@ -6174,7 +6284,8 @@
6174
6284
  particle.lastPathTime -= pathDelay;
6175
6285
  }
6176
6286
  function getProximitySpeedFactor(particle) {
6177
- return particle.slow.inRange ? particle.slow.factor : identity;
6287
+ const mod = particle.getModifier("slow");
6288
+ return mod?.enabled ? (mod.speedFactor ?? identity) : identity;
6178
6289
  }
6179
6290
  function initSpin(container, particle) {
6180
6291
  const options = particle.options, spinOptions = options.move.spin;
@@ -6429,6 +6540,7 @@
6429
6540
 
6430
6541
  const minimumLength = 0;
6431
6542
  class TrailPluginInstance {
6543
+ layer = DrawLayer.PluginContent;
6432
6544
  #container;
6433
6545
  #pluginManager;
6434
6546
  #trailFill;