@tsparticles/preset-fire 4.2.1 → 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.1 */
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) :
@@ -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.0";
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, getRgbInRangeValue = () => Math.floor(getRandomInRange(fixedMin, fixedMax));
1918
+ function getRandomRgbColor(min, hdr) {
1919
+ const fixedMin = defaultRgbMin;
1920
+ const fixedMax = rgbMax + identity, 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.0");
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.0");
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.0");
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.0");
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.0");
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.0");
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.0");
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.0");
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.0");
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.0");
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.0");
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.0");
3214
3240
  await engine.pluginManager.register(e => {
3215
3241
  const interactivityEngine = e, interactivityPluginManager = interactivityEngine.pluginManager;
3216
3242
  interactivityPluginManager.addPlugin(new InteractivityPlugin(interactivityPluginManager));
@@ -3306,7 +3332,7 @@
3306
3332
  }
3307
3333
 
3308
3334
  async function loadExternalPushInteraction(engine) {
3309
- engine.checkVersion("4.2.1");
3335
+ engine.checkVersion("4.3.0");
3310
3336
  await engine.pluginManager.register((e) => {
3311
3337
  ensureInteractivityPluginLoaded(e);
3312
3338
  e.pluginManager.addInteractor?.("externalPush", container => {
@@ -3384,10 +3410,10 @@
3384
3410
  }
3385
3411
  }
3386
3412
  class RenderManager {
3413
+ #backgroundElement;
3414
+ #backgroundWarnings;
3387
3415
  #canvasClearPlugins;
3388
3416
  #canvasManager;
3389
- #canvasPaintPlugins;
3390
- #clearDrawPlugins;
3391
3417
  #colorPlugins;
3392
3418
  #container;
3393
3419
  #context;
@@ -3395,9 +3421,7 @@
3395
3421
  #drawParticlePlugins;
3396
3422
  #drawParticlesCleanupPlugins;
3397
3423
  #drawParticlesSetupPlugins;
3398
- #drawPlugins;
3399
- #drawSettingsCleanupPlugins;
3400
- #drawSettingsSetupPlugins;
3424
+ #layers;
3401
3425
  #pluginManager;
3402
3426
  #postDrawUpdaters;
3403
3427
  #preDrawUpdaters;
@@ -3409,18 +3433,25 @@
3409
3433
  this.#container = container;
3410
3434
  this.#canvasManager = canvasManager;
3411
3435
  this.#context = null;
3436
+ this.#backgroundElement = null;
3437
+ this.#backgroundWarnings = new Set();
3412
3438
  this.#preDrawUpdaters = [];
3413
3439
  this.#postDrawUpdaters = [];
3414
- this.#colorPlugins = [];
3415
3440
  this.#canvasClearPlugins = [];
3416
- this.#canvasPaintPlugins = [];
3417
- this.#clearDrawPlugins = [];
3441
+ this.#colorPlugins = [];
3418
3442
  this.#drawParticlePlugins = [];
3419
3443
  this.#drawParticlesCleanupPlugins = [];
3420
3444
  this.#drawParticlesSetupPlugins = [];
3421
- this.#drawPlugins = [];
3422
- this.#drawSettingsSetupPlugins = [];
3423
- this.#drawSettingsCleanupPlugins = [];
3445
+ this.#layers = {
3446
+ 0: [],
3447
+ 1: [],
3448
+ 2: [],
3449
+ 3: [],
3450
+ 4: [],
3451
+ 5: [],
3452
+ 6: [],
3453
+ 7: [],
3454
+ };
3424
3455
  }
3425
3456
  get settings() {
3426
3457
  return this.#contextSettings;
@@ -3434,32 +3465,38 @@
3434
3465
  });
3435
3466
  }
3436
3467
  clear() {
3437
- let pluginHandled = false;
3438
3468
  for (const plugin of this.#canvasClearPlugins) {
3439
- pluginHandled = plugin.canvasClear?.() ?? false;
3440
- if (pluginHandled) {
3441
- break;
3469
+ if (plugin.canvasClear?.() ?? false) {
3470
+ return;
3442
3471
  }
3443
3472
  }
3444
- if (pluginHandled) {
3445
- return;
3473
+ for (const layer of Object.values(DrawLayer)) {
3474
+ if (typeof layer === "number") {
3475
+ for (const plugin of this.#getLayerPlugins(layer)) {
3476
+ if (plugin.canvasClear?.() ?? false) {
3477
+ return;
3478
+ }
3479
+ }
3480
+ }
3446
3481
  }
3447
3482
  this.canvasClear();
3448
3483
  }
3449
3484
  destroy() {
3450
3485
  this.stop();
3486
+ this.#backgroundElement = null;
3487
+ this.#backgroundWarnings.clear();
3451
3488
  this.#preDrawUpdaters = [];
3452
3489
  this.#postDrawUpdaters = [];
3453
- this.#colorPlugins = [];
3454
3490
  this.#canvasClearPlugins = [];
3455
- this.#canvasPaintPlugins = [];
3456
- this.#clearDrawPlugins = [];
3491
+ this.#colorPlugins = [];
3457
3492
  this.#drawParticlePlugins = [];
3458
3493
  this.#drawParticlesCleanupPlugins = [];
3459
3494
  this.#drawParticlesSetupPlugins = [];
3460
- this.#drawPlugins = [];
3461
- this.#drawSettingsSetupPlugins = [];
3462
- this.#drawSettingsCleanupPlugins = [];
3495
+ for (const layer of Object.values(DrawLayer)) {
3496
+ if (typeof layer === "number") {
3497
+ this.#layers[layer] = [];
3498
+ }
3499
+ }
3463
3500
  }
3464
3501
  draw(cb) {
3465
3502
  const ctx = this.#context;
@@ -3516,21 +3553,40 @@
3516
3553
  });
3517
3554
  }
3518
3555
  drawParticles(delta) {
3519
- const { particles } = this.#container;
3556
+ const { particles, actualOptions } = this.#container;
3520
3557
  this.clear();
3521
3558
  particles.update(delta);
3522
3559
  this.draw(ctx => {
3523
- for (const plugin of this.#drawSettingsSetupPlugins) {
3560
+ const width = this.#canvasManager.size.width, height = this.#canvasManager.size.height;
3561
+ if (this.#backgroundElement) {
3562
+ try {
3563
+ ctx.drawImage(this.#backgroundElement, originPoint.x, originPoint.y, width, height);
3564
+ }
3565
+ catch {
3566
+ this.#warnOnce("background-element-draw-error", "Error drawing background element onto canvas");
3567
+ }
3568
+ }
3569
+ const background = actualOptions.background;
3570
+ if (background.draw) {
3571
+ try {
3572
+ background.draw(ctx, delta);
3573
+ }
3574
+ catch {
3575
+ this.#warnOnce("background-draw-error", "Error in background.draw callback");
3576
+ }
3577
+ }
3578
+ for (const plugin of this.#getLayerPlugins(DrawLayer.BackgroundMask)) {
3579
+ plugin.canvasPaint?.();
3580
+ }
3581
+ for (const plugin of this.#getLayerPlugins(DrawLayer.CanvasSetup)) {
3524
3582
  plugin.drawSettingsSetup?.(ctx, delta);
3525
3583
  }
3526
- for (const plugin of this.#drawPlugins) {
3584
+ for (const plugin of this.#getLayerPlugins(DrawLayer.PluginContent)) {
3527
3585
  plugin.draw?.(ctx, delta);
3528
3586
  }
3529
3587
  particles.drawParticles(delta);
3530
- for (const plugin of this.#clearDrawPlugins) {
3588
+ for (const plugin of this.#getLayerPlugins(DrawLayer.CanvasCleanup)) {
3531
3589
  plugin.clearDraw?.(ctx, delta);
3532
- }
3533
- for (const plugin of this.#drawSettingsCleanupPlugins) {
3534
3590
  plugin.drawSettingsCleanup?.(ctx, delta);
3535
3591
  }
3536
3592
  });
@@ -3538,29 +3594,24 @@
3538
3594
  init() {
3539
3595
  this.initUpdaters();
3540
3596
  this.initPlugins();
3597
+ this.#resolveBackgroundElement();
3541
3598
  this.paint();
3542
3599
  }
3543
3600
  initPlugins() {
3544
- this.#colorPlugins = [];
3545
3601
  this.#canvasClearPlugins = [];
3546
- this.#canvasPaintPlugins = [];
3547
- this.#clearDrawPlugins = [];
3602
+ this.#colorPlugins = [];
3548
3603
  this.#drawParticlePlugins = [];
3549
3604
  this.#drawParticlesSetupPlugins = [];
3550
3605
  this.#drawParticlesCleanupPlugins = [];
3551
- this.#drawPlugins = [];
3552
- this.#drawSettingsSetupPlugins = [];
3553
- this.#drawSettingsCleanupPlugins = [];
3606
+ for (const layer of Object.values(DrawLayer)) {
3607
+ if (typeof layer === "number") {
3608
+ this.#layers[layer] = [];
3609
+ }
3610
+ }
3554
3611
  for (const plugin of this.#container.plugins) {
3555
3612
  if (plugin.particleFillColor ?? plugin.particleStrokeColor) {
3556
3613
  this.#colorPlugins.push(plugin);
3557
3614
  }
3558
- if (plugin.canvasClear) {
3559
- this.#canvasClearPlugins.push(plugin);
3560
- }
3561
- if (plugin.canvasPaint) {
3562
- this.#canvasPaintPlugins.push(plugin);
3563
- }
3564
3615
  if (plugin.drawParticle) {
3565
3616
  this.#drawParticlePlugins.push(plugin);
3566
3617
  }
@@ -3570,17 +3621,20 @@
3570
3621
  if (plugin.drawParticleCleanup) {
3571
3622
  this.#drawParticlesCleanupPlugins.push(plugin);
3572
3623
  }
3573
- if (plugin.draw) {
3574
- this.#drawPlugins.push(plugin);
3624
+ if (plugin.canvasClear) {
3625
+ this.#canvasClearPlugins.push(plugin);
3626
+ }
3627
+ if (plugin.canvasPaint) {
3628
+ this.#getLayerPlugins(DrawLayer.BackgroundMask).push(plugin);
3575
3629
  }
3576
3630
  if (plugin.drawSettingsSetup) {
3577
- this.#drawSettingsSetupPlugins.push(plugin);
3631
+ this.#getLayerPlugins(DrawLayer.CanvasSetup).push(plugin);
3578
3632
  }
3579
- if (plugin.drawSettingsCleanup) {
3580
- this.#drawSettingsCleanupPlugins.push(plugin);
3633
+ if (plugin.draw) {
3634
+ this.#getLayerPlugins(DrawLayer.PluginContent).push(plugin);
3581
3635
  }
3582
- if (plugin.clearDraw) {
3583
- this.#clearDrawPlugins.push(plugin);
3636
+ if (plugin.clearDraw ?? plugin.drawSettingsCleanup) {
3637
+ this.#getLayerPlugins(DrawLayer.CanvasCleanup).push(plugin);
3584
3638
  }
3585
3639
  }
3586
3640
  }
@@ -3598,7 +3652,7 @@
3598
3652
  }
3599
3653
  paint() {
3600
3654
  let handled = false;
3601
- for (const plugin of this.#canvasPaintPlugins) {
3655
+ for (const plugin of this.#getLayerPlugins(DrawLayer.BackgroundMask)) {
3602
3656
  handled = plugin.canvasPaint?.() ?? false;
3603
3657
  if (handled) {
3604
3658
  break;
@@ -3771,6 +3825,9 @@
3771
3825
  }
3772
3826
  drawer.beforeDraw(data);
3773
3827
  }
3828
+ #getLayerPlugins(layer) {
3829
+ return this.#layers[layer];
3830
+ }
3774
3831
  #getPluginParticleColors(particle) {
3775
3832
  let fColor, sColor;
3776
3833
  for (const plugin of this.#colorPlugins) {
@@ -3788,6 +3845,39 @@
3788
3845
  this.#reusablePluginColors[sColorIndex] = sColor;
3789
3846
  return this.#reusablePluginColors;
3790
3847
  }
3848
+ #resolveBackgroundElement() {
3849
+ const background = this.#container.actualOptions.background;
3850
+ this.#backgroundElement = null;
3851
+ if (!background.element) {
3852
+ return;
3853
+ }
3854
+ if (typeof background.element === "string") {
3855
+ if (typeof document !== "undefined") {
3856
+ const node = document.querySelector(background.element);
3857
+ if (node instanceof HTMLCanvasElement || node instanceof HTMLVideoElement || node instanceof HTMLImageElement) {
3858
+ this.#backgroundElement = node;
3859
+ }
3860
+ else if (node) {
3861
+ this.#warnOnce("background-element-not-supported", `Background element "${background.element}" is not a supported drawable element (canvas, video, or img)`);
3862
+ }
3863
+ else {
3864
+ this.#warnOnce("background-element-not-found", `Background element selector "${background.element}" not found`);
3865
+ }
3866
+ }
3867
+ }
3868
+ else if (background.element instanceof HTMLCanvasElement ||
3869
+ background.element instanceof OffscreenCanvas ||
3870
+ background.element instanceof HTMLVideoElement ||
3871
+ background.element instanceof HTMLImageElement) {
3872
+ this.#backgroundElement = background.element;
3873
+ }
3874
+ }
3875
+ #warnOnce(key, message) {
3876
+ if (!this.#backgroundWarnings.has(key)) {
3877
+ this.#backgroundWarnings.add(key);
3878
+ getLogger().warning(message);
3879
+ }
3880
+ }
3791
3881
  }
3792
3882
 
3793
3883
  const transferredCanvases = new WeakMap(), getTransferredCanvas = (canvas) => {
@@ -4364,7 +4454,6 @@
4364
4454
  }
4365
4455
  class Particle {
4366
4456
  backColor;
4367
- bubble;
4368
4457
  destroyed;
4369
4458
  direction;
4370
4459
  effect;
@@ -4398,7 +4487,6 @@
4398
4487
  shapeData;
4399
4488
  sides;
4400
4489
  size;
4401
- slow;
4402
4490
  spawning;
4403
4491
  strokeColor;
4404
4492
  strokeOpacity;
@@ -4420,18 +4508,25 @@
4420
4508
  d: 1,
4421
4509
  };
4422
4510
  #container;
4511
+ #modifiers = [];
4423
4512
  #pluginManager;
4424
4513
  constructor(pluginManager, container) {
4425
4514
  this.#pluginManager = pluginManager;
4426
4515
  this.#container = container;
4427
4516
  }
4517
+ addModifier(modifier) {
4518
+ this.#modifiers.push(modifier);
4519
+ this.#modifiers.sort((a, b) => a.priority - b.priority);
4520
+ }
4521
+ clearModifiers() {
4522
+ this.#modifiers.length = 0;
4523
+ }
4428
4524
  destroy(override) {
4429
4525
  if (this.unbreakable || this.destroyed) {
4430
4526
  return;
4431
4527
  }
4432
4528
  this.destroyed = true;
4433
- this.bubble.inRange = false;
4434
- this.slow.inRange = false;
4529
+ this.clearModifiers();
4435
4530
  const container = this.#container, shapeDrawer = this.shape ? container.shapeDrawers.get(this.shape) : undefined;
4436
4531
  shapeDrawer?.particleDestroy?.(this);
4437
4532
  for (const plugin of container.particleDestroyedPlugins) {
@@ -4453,13 +4548,16 @@
4453
4548
  return this.rotation + (this.pathRotation ? this.velocity.angle : defaultAngle);
4454
4549
  }
4455
4550
  getFillColor() {
4456
- return this.#getRollColor(this.bubble.color ?? getHslFromAnimation(this.fillColor));
4551
+ return this.#getRollColor(this.#applyModifiers(getHslFromAnimation(this.fillColor), m => m.fillColor));
4457
4552
  }
4458
4553
  getMass() {
4459
4554
  return this.getRadius() ** squareExp * Math.PI * half;
4460
4555
  }
4556
+ getModifier(id) {
4557
+ return this.#modifiers.find(m => m.id === id);
4558
+ }
4461
4559
  getOpacity() {
4462
- 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;
4560
+ 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;
4463
4561
  this.#cachedOpacityData.fillOpacity = opacity * fillOpacity * zOpacityFactor;
4464
4562
  this.#cachedOpacityData.opacity = opacity * zOpacityFactor;
4465
4563
  this.#cachedOpacityData.strokeOpacity = opacity * strokeOpacity * zOpacityFactor;
@@ -4472,7 +4570,7 @@
4472
4570
  return this.#cachedPosition;
4473
4571
  }
4474
4572
  getRadius() {
4475
- return this.bubble.radius ?? this.size.value;
4573
+ return this.#applyModifiers(this.size.value, m => m.radius);
4476
4574
  }
4477
4575
  getRotateData() {
4478
4576
  const angle = this.getAngle();
@@ -4481,7 +4579,7 @@
4481
4579
  return this.#cachedRotateData;
4482
4580
  }
4483
4581
  getStrokeColor() {
4484
- return this.#getRollColor(this.bubble.color ?? getHslFromAnimation(this.strokeColor));
4582
+ return this.#getRollColor(this.#applyModifiers(getHslFromAnimation(this.strokeColor), m => m.strokeColor));
4485
4583
  }
4486
4584
  getTransformData(externalTransform) {
4487
4585
  const rotateData = this.getRotateData(), rotating = this.isRotating;
@@ -4501,13 +4599,6 @@
4501
4599
  this.options = resolveParticleOptions(this, container, this.#pluginManager, overrideOptions);
4502
4600
  container.retina.initParticle(this);
4503
4601
  runUpdaterPreInit(container.particleUpdaters, this);
4504
- this.bubble = {
4505
- inRange: false,
4506
- };
4507
- this.slow = {
4508
- inRange: false,
4509
- factor: 1,
4510
- };
4511
4602
  this.#initPosition(position);
4512
4603
  this.initialVelocity = this.#calculateVelocity();
4513
4604
  this.velocity = this.initialVelocity.copy();
@@ -4547,11 +4638,29 @@
4547
4638
  isVisible() {
4548
4639
  return !this.destroyed && !this.spawning && this.isInsideCanvas();
4549
4640
  }
4641
+ removeModifier(id) {
4642
+ const idx = this.#modifiers.findIndex(m => m.id === id);
4643
+ if (idx >= defaultAngle) {
4644
+ this.#modifiers.splice(idx, identity);
4645
+ }
4646
+ }
4550
4647
  reset() {
4551
4648
  for (const updater of this.#container.particleUpdaters) {
4552
4649
  updater.reset?.(this);
4553
4650
  }
4554
4651
  }
4652
+ #applyModifiers(base, getter) {
4653
+ let value = base;
4654
+ for (const mod of this.#modifiers) {
4655
+ if (mod.enabled) {
4656
+ const override = getter(mod);
4657
+ if (override !== undefined) {
4658
+ value = override;
4659
+ }
4660
+ }
4661
+ }
4662
+ return value;
4663
+ }
4555
4664
  #calcPosition(position, zIndex) {
4556
4665
  let tryCount = defaultRetryCount, posVec = position ? Vector3d.create(position.x, position.y, zIndex) : undefined;
4557
4666
  const container = this.#container, plugins = container.particlePositionPlugins, outModes = this.options.move.outModes, radius = this.getRadius(), canvasSize = container.canvas.size;
@@ -5653,6 +5762,7 @@
5653
5762
  });
5654
5763
 
5655
5764
  class BlendPluginInstance {
5765
+ layer = DrawLayer.CanvasSetup;
5656
5766
  #container;
5657
5767
  #defaultCompositeValue;
5658
5768
  constructor(container) {
@@ -5798,7 +5908,8 @@
5798
5908
  particle.lastPathTime -= pathDelay;
5799
5909
  }
5800
5910
  function getProximitySpeedFactor(particle) {
5801
- return particle.slow.inRange ? particle.slow.factor : identity;
5911
+ const mod = particle.getModifier("slow");
5912
+ return mod?.enabled ? (mod.speedFactor ?? identity) : identity;
5802
5913
  }
5803
5914
  function initSpin(container, particle) {
5804
5915
  const options = particle.options, spinOptions = options.move.spin;