@tsparticles/preset-snow 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, 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.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),
@@ -3145,7 +3171,7 @@
3145
3171
  }
3146
3172
 
3147
3173
  async function loadWobbleUpdater(engine) {
3148
- engine.checkVersion("4.2.1");
3174
+ engine.checkVersion("4.3.1");
3149
3175
  await engine.pluginManager.register(e => {
3150
3176
  e.pluginManager.addParticleUpdater("wobble", container => {
3151
3177
  return Promise.resolve(new WobbleUpdater(container));
@@ -3202,10 +3228,10 @@
3202
3228
  }
3203
3229
  }
3204
3230
  class RenderManager {
3231
+ #backgroundElement;
3232
+ #backgroundWarnings;
3205
3233
  #canvasClearPlugins;
3206
3234
  #canvasManager;
3207
- #canvasPaintPlugins;
3208
- #clearDrawPlugins;
3209
3235
  #colorPlugins;
3210
3236
  #container;
3211
3237
  #context;
@@ -3213,9 +3239,7 @@
3213
3239
  #drawParticlePlugins;
3214
3240
  #drawParticlesCleanupPlugins;
3215
3241
  #drawParticlesSetupPlugins;
3216
- #drawPlugins;
3217
- #drawSettingsCleanupPlugins;
3218
- #drawSettingsSetupPlugins;
3242
+ #layers;
3219
3243
  #pluginManager;
3220
3244
  #postDrawUpdaters;
3221
3245
  #preDrawUpdaters;
@@ -3227,18 +3251,25 @@
3227
3251
  this.#container = container;
3228
3252
  this.#canvasManager = canvasManager;
3229
3253
  this.#context = null;
3254
+ this.#backgroundElement = null;
3255
+ this.#backgroundWarnings = new Set();
3230
3256
  this.#preDrawUpdaters = [];
3231
3257
  this.#postDrawUpdaters = [];
3232
- this.#colorPlugins = [];
3233
3258
  this.#canvasClearPlugins = [];
3234
- this.#canvasPaintPlugins = [];
3235
- this.#clearDrawPlugins = [];
3259
+ this.#colorPlugins = [];
3236
3260
  this.#drawParticlePlugins = [];
3237
3261
  this.#drawParticlesCleanupPlugins = [];
3238
3262
  this.#drawParticlesSetupPlugins = [];
3239
- this.#drawPlugins = [];
3240
- this.#drawSettingsSetupPlugins = [];
3241
- this.#drawSettingsCleanupPlugins = [];
3263
+ this.#layers = {
3264
+ 0: [],
3265
+ 1: [],
3266
+ 2: [],
3267
+ 3: [],
3268
+ 4: [],
3269
+ 5: [],
3270
+ 6: [],
3271
+ 7: [],
3272
+ };
3242
3273
  }
3243
3274
  get settings() {
3244
3275
  return this.#contextSettings;
@@ -3252,32 +3283,38 @@
3252
3283
  });
3253
3284
  }
3254
3285
  clear() {
3255
- let pluginHandled = false;
3256
3286
  for (const plugin of this.#canvasClearPlugins) {
3257
- pluginHandled = plugin.canvasClear?.() ?? false;
3258
- if (pluginHandled) {
3259
- break;
3287
+ if (plugin.canvasClear?.() ?? false) {
3288
+ return;
3260
3289
  }
3261
3290
  }
3262
- if (pluginHandled) {
3263
- return;
3291
+ for (const layer of Object.values(DrawLayer)) {
3292
+ if (typeof layer === "number") {
3293
+ for (const plugin of this.#getLayerPlugins(layer)) {
3294
+ if (plugin.canvasClear?.() ?? false) {
3295
+ return;
3296
+ }
3297
+ }
3298
+ }
3264
3299
  }
3265
3300
  this.canvasClear();
3266
3301
  }
3267
3302
  destroy() {
3268
3303
  this.stop();
3304
+ this.#backgroundElement = null;
3305
+ this.#backgroundWarnings.clear();
3269
3306
  this.#preDrawUpdaters = [];
3270
3307
  this.#postDrawUpdaters = [];
3271
- this.#colorPlugins = [];
3272
3308
  this.#canvasClearPlugins = [];
3273
- this.#canvasPaintPlugins = [];
3274
- this.#clearDrawPlugins = [];
3309
+ this.#colorPlugins = [];
3275
3310
  this.#drawParticlePlugins = [];
3276
3311
  this.#drawParticlesCleanupPlugins = [];
3277
3312
  this.#drawParticlesSetupPlugins = [];
3278
- this.#drawPlugins = [];
3279
- this.#drawSettingsSetupPlugins = [];
3280
- this.#drawSettingsCleanupPlugins = [];
3313
+ for (const layer of Object.values(DrawLayer)) {
3314
+ if (typeof layer === "number") {
3315
+ this.#layers[layer] = [];
3316
+ }
3317
+ }
3281
3318
  }
3282
3319
  draw(cb) {
3283
3320
  const ctx = this.#context;
@@ -3334,21 +3371,40 @@
3334
3371
  });
3335
3372
  }
3336
3373
  drawParticles(delta) {
3337
- const { particles } = this.#container;
3374
+ const { particles, actualOptions } = this.#container;
3338
3375
  this.clear();
3339
3376
  particles.update(delta);
3340
3377
  this.draw(ctx => {
3341
- for (const plugin of this.#drawSettingsSetupPlugins) {
3378
+ const width = this.#canvasManager.size.width, height = this.#canvasManager.size.height;
3379
+ if (this.#backgroundElement) {
3380
+ try {
3381
+ ctx.drawImage(this.#backgroundElement, originPoint.x, originPoint.y, width, height);
3382
+ }
3383
+ catch {
3384
+ this.#warnOnce("background-element-draw-error", "Error drawing background element onto canvas");
3385
+ }
3386
+ }
3387
+ const background = actualOptions.background;
3388
+ if (background.draw) {
3389
+ try {
3390
+ background.draw(ctx, delta);
3391
+ }
3392
+ catch {
3393
+ this.#warnOnce("background-draw-error", "Error in background.draw callback");
3394
+ }
3395
+ }
3396
+ for (const plugin of this.#getLayerPlugins(DrawLayer.BackgroundMask)) {
3397
+ plugin.canvasPaint?.();
3398
+ }
3399
+ for (const plugin of this.#getLayerPlugins(DrawLayer.CanvasSetup)) {
3342
3400
  plugin.drawSettingsSetup?.(ctx, delta);
3343
3401
  }
3344
- for (const plugin of this.#drawPlugins) {
3402
+ for (const plugin of this.#getLayerPlugins(DrawLayer.PluginContent)) {
3345
3403
  plugin.draw?.(ctx, delta);
3346
3404
  }
3347
3405
  particles.drawParticles(delta);
3348
- for (const plugin of this.#clearDrawPlugins) {
3406
+ for (const plugin of this.#getLayerPlugins(DrawLayer.CanvasCleanup)) {
3349
3407
  plugin.clearDraw?.(ctx, delta);
3350
- }
3351
- for (const plugin of this.#drawSettingsCleanupPlugins) {
3352
3408
  plugin.drawSettingsCleanup?.(ctx, delta);
3353
3409
  }
3354
3410
  });
@@ -3356,29 +3412,24 @@
3356
3412
  init() {
3357
3413
  this.initUpdaters();
3358
3414
  this.initPlugins();
3415
+ this.#resolveBackgroundElement();
3359
3416
  this.paint();
3360
3417
  }
3361
3418
  initPlugins() {
3362
- this.#colorPlugins = [];
3363
3419
  this.#canvasClearPlugins = [];
3364
- this.#canvasPaintPlugins = [];
3365
- this.#clearDrawPlugins = [];
3420
+ this.#colorPlugins = [];
3366
3421
  this.#drawParticlePlugins = [];
3367
3422
  this.#drawParticlesSetupPlugins = [];
3368
3423
  this.#drawParticlesCleanupPlugins = [];
3369
- this.#drawPlugins = [];
3370
- this.#drawSettingsSetupPlugins = [];
3371
- this.#drawSettingsCleanupPlugins = [];
3424
+ for (const layer of Object.values(DrawLayer)) {
3425
+ if (typeof layer === "number") {
3426
+ this.#layers[layer] = [];
3427
+ }
3428
+ }
3372
3429
  for (const plugin of this.#container.plugins) {
3373
3430
  if (plugin.particleFillColor ?? plugin.particleStrokeColor) {
3374
3431
  this.#colorPlugins.push(plugin);
3375
3432
  }
3376
- if (plugin.canvasClear) {
3377
- this.#canvasClearPlugins.push(plugin);
3378
- }
3379
- if (plugin.canvasPaint) {
3380
- this.#canvasPaintPlugins.push(plugin);
3381
- }
3382
3433
  if (plugin.drawParticle) {
3383
3434
  this.#drawParticlePlugins.push(plugin);
3384
3435
  }
@@ -3388,17 +3439,20 @@
3388
3439
  if (plugin.drawParticleCleanup) {
3389
3440
  this.#drawParticlesCleanupPlugins.push(plugin);
3390
3441
  }
3391
- if (plugin.draw) {
3392
- this.#drawPlugins.push(plugin);
3442
+ if (plugin.canvasClear) {
3443
+ this.#canvasClearPlugins.push(plugin);
3444
+ }
3445
+ if (plugin.canvasPaint) {
3446
+ this.#getLayerPlugins(DrawLayer.BackgroundMask).push(plugin);
3393
3447
  }
3394
3448
  if (plugin.drawSettingsSetup) {
3395
- this.#drawSettingsSetupPlugins.push(plugin);
3449
+ this.#getLayerPlugins(DrawLayer.CanvasSetup).push(plugin);
3396
3450
  }
3397
- if (plugin.drawSettingsCleanup) {
3398
- this.#drawSettingsCleanupPlugins.push(plugin);
3451
+ if (plugin.draw) {
3452
+ this.#getLayerPlugins(DrawLayer.PluginContent).push(plugin);
3399
3453
  }
3400
- if (plugin.clearDraw) {
3401
- this.#clearDrawPlugins.push(plugin);
3454
+ if (plugin.clearDraw ?? plugin.drawSettingsCleanup) {
3455
+ this.#getLayerPlugins(DrawLayer.CanvasCleanup).push(plugin);
3402
3456
  }
3403
3457
  }
3404
3458
  }
@@ -3416,7 +3470,7 @@
3416
3470
  }
3417
3471
  paint() {
3418
3472
  let handled = false;
3419
- for (const plugin of this.#canvasPaintPlugins) {
3473
+ for (const plugin of this.#getLayerPlugins(DrawLayer.BackgroundMask)) {
3420
3474
  handled = plugin.canvasPaint?.() ?? false;
3421
3475
  if (handled) {
3422
3476
  break;
@@ -3589,6 +3643,9 @@
3589
3643
  }
3590
3644
  drawer.beforeDraw(data);
3591
3645
  }
3646
+ #getLayerPlugins(layer) {
3647
+ return this.#layers[layer];
3648
+ }
3592
3649
  #getPluginParticleColors(particle) {
3593
3650
  let fColor, sColor;
3594
3651
  for (const plugin of this.#colorPlugins) {
@@ -3606,6 +3663,39 @@
3606
3663
  this.#reusablePluginColors[sColorIndex] = sColor;
3607
3664
  return this.#reusablePluginColors;
3608
3665
  }
3666
+ #resolveBackgroundElement() {
3667
+ const background = this.#container.actualOptions.background;
3668
+ this.#backgroundElement = null;
3669
+ if (!background.element) {
3670
+ return;
3671
+ }
3672
+ if (typeof background.element === "string") {
3673
+ if (typeof document !== "undefined") {
3674
+ const node = document.querySelector(background.element);
3675
+ if (node instanceof HTMLCanvasElement || node instanceof HTMLVideoElement || node instanceof HTMLImageElement) {
3676
+ this.#backgroundElement = node;
3677
+ }
3678
+ else if (node) {
3679
+ this.#warnOnce("background-element-not-supported", `Background element "${background.element}" is not a supported drawable element (canvas, video, or img)`);
3680
+ }
3681
+ else {
3682
+ this.#warnOnce("background-element-not-found", `Background element selector "${background.element}" not found`);
3683
+ }
3684
+ }
3685
+ }
3686
+ else if (background.element instanceof HTMLCanvasElement ||
3687
+ background.element instanceof OffscreenCanvas ||
3688
+ background.element instanceof HTMLVideoElement ||
3689
+ background.element instanceof HTMLImageElement) {
3690
+ this.#backgroundElement = background.element;
3691
+ }
3692
+ }
3693
+ #warnOnce(key, message) {
3694
+ if (!this.#backgroundWarnings.has(key)) {
3695
+ this.#backgroundWarnings.add(key);
3696
+ getLogger().warning(message);
3697
+ }
3698
+ }
3609
3699
  }
3610
3700
 
3611
3701
  const transferredCanvases = new WeakMap(), getTransferredCanvas = (canvas) => {
@@ -4182,7 +4272,6 @@
4182
4272
  }
4183
4273
  class Particle {
4184
4274
  backColor;
4185
- bubble;
4186
4275
  destroyed;
4187
4276
  direction;
4188
4277
  effect;
@@ -4216,7 +4305,6 @@
4216
4305
  shapeData;
4217
4306
  sides;
4218
4307
  size;
4219
- slow;
4220
4308
  spawning;
4221
4309
  strokeColor;
4222
4310
  strokeOpacity;
@@ -4238,18 +4326,25 @@
4238
4326
  d: 1,
4239
4327
  };
4240
4328
  #container;
4329
+ #modifiers = [];
4241
4330
  #pluginManager;
4242
4331
  constructor(pluginManager, container) {
4243
4332
  this.#pluginManager = pluginManager;
4244
4333
  this.#container = container;
4245
4334
  }
4335
+ addModifier(modifier) {
4336
+ this.#modifiers.push(modifier);
4337
+ this.#modifiers.sort((a, b) => a.priority - b.priority);
4338
+ }
4339
+ clearModifiers() {
4340
+ this.#modifiers.length = 0;
4341
+ }
4246
4342
  destroy(override) {
4247
4343
  if (this.unbreakable || this.destroyed) {
4248
4344
  return;
4249
4345
  }
4250
4346
  this.destroyed = true;
4251
- this.bubble.inRange = false;
4252
- this.slow.inRange = false;
4347
+ this.clearModifiers();
4253
4348
  const container = this.#container, shapeDrawer = this.shape ? container.shapeDrawers.get(this.shape) : undefined;
4254
4349
  shapeDrawer?.particleDestroy?.(this);
4255
4350
  for (const plugin of container.particleDestroyedPlugins) {
@@ -4271,13 +4366,16 @@
4271
4366
  return this.rotation + (this.pathRotation ? this.velocity.angle : defaultAngle);
4272
4367
  }
4273
4368
  getFillColor() {
4274
- return this.#getRollColor(this.bubble.color ?? getHslFromAnimation(this.fillColor));
4369
+ return this.#getRollColor(this.#applyModifiers(getHslFromAnimation(this.fillColor), m => m.fillColor));
4275
4370
  }
4276
4371
  getMass() {
4277
4372
  return this.getRadius() ** squareExp * Math.PI * half;
4278
4373
  }
4374
+ getModifier(id) {
4375
+ return this.#modifiers.find(m => m.id === id);
4376
+ }
4279
4377
  getOpacity() {
4280
- 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;
4378
+ 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;
4281
4379
  this.#cachedOpacityData.fillOpacity = opacity * fillOpacity * zOpacityFactor;
4282
4380
  this.#cachedOpacityData.opacity = opacity * zOpacityFactor;
4283
4381
  this.#cachedOpacityData.strokeOpacity = opacity * strokeOpacity * zOpacityFactor;
@@ -4290,7 +4388,7 @@
4290
4388
  return this.#cachedPosition;
4291
4389
  }
4292
4390
  getRadius() {
4293
- return this.bubble.radius ?? this.size.value;
4391
+ return this.#applyModifiers(this.size.value, m => m.radius);
4294
4392
  }
4295
4393
  getRotateData() {
4296
4394
  const angle = this.getAngle();
@@ -4299,7 +4397,7 @@
4299
4397
  return this.#cachedRotateData;
4300
4398
  }
4301
4399
  getStrokeColor() {
4302
- return this.#getRollColor(this.bubble.color ?? getHslFromAnimation(this.strokeColor));
4400
+ return this.#getRollColor(this.#applyModifiers(getHslFromAnimation(this.strokeColor), m => m.strokeColor));
4303
4401
  }
4304
4402
  getTransformData(externalTransform) {
4305
4403
  const rotateData = this.getRotateData(), rotating = this.isRotating;
@@ -4319,13 +4417,6 @@
4319
4417
  this.options = resolveParticleOptions(this, container, this.#pluginManager, overrideOptions);
4320
4418
  container.retina.initParticle(this);
4321
4419
  runUpdaterPreInit(container.particleUpdaters, this);
4322
- this.bubble = {
4323
- inRange: false,
4324
- };
4325
- this.slow = {
4326
- inRange: false,
4327
- factor: 1,
4328
- };
4329
4420
  this.#initPosition(position);
4330
4421
  this.initialVelocity = this.#calculateVelocity();
4331
4422
  this.velocity = this.initialVelocity.copy();
@@ -4365,11 +4456,29 @@
4365
4456
  isVisible() {
4366
4457
  return !this.destroyed && !this.spawning && this.isInsideCanvas();
4367
4458
  }
4459
+ removeModifier(id) {
4460
+ const idx = this.#modifiers.findIndex(m => m.id === id);
4461
+ if (idx >= defaultAngle) {
4462
+ this.#modifiers.splice(idx, identity);
4463
+ }
4464
+ }
4368
4465
  reset() {
4369
4466
  for (const updater of this.#container.particleUpdaters) {
4370
4467
  updater.reset?.(this);
4371
4468
  }
4372
4469
  }
4470
+ #applyModifiers(base, getter) {
4471
+ let value = base;
4472
+ for (const mod of this.#modifiers) {
4473
+ if (mod.enabled) {
4474
+ const override = getter(mod);
4475
+ if (override !== undefined) {
4476
+ value = override;
4477
+ }
4478
+ }
4479
+ }
4480
+ return value;
4481
+ }
4373
4482
  #calcPosition(position, zIndex) {
4374
4483
  let tryCount = defaultRetryCount, posVec = position ? Vector3d.create(position.x, position.y, zIndex) : undefined;
4375
4484
  const container = this.#container, plugins = container.particlePositionPlugins, outModes = this.options.move.outModes, radius = this.getRadius(), canvasSize = container.canvas.size;
@@ -5471,6 +5580,7 @@
5471
5580
  });
5472
5581
 
5473
5582
  class BlendPluginInstance {
5583
+ layer = DrawLayer.CanvasSetup;
5474
5584
  #container;
5475
5585
  #defaultCompositeValue;
5476
5586
  constructor(container) {
@@ -5616,7 +5726,8 @@
5616
5726
  particle.lastPathTime -= pathDelay;
5617
5727
  }
5618
5728
  function getProximitySpeedFactor(particle) {
5619
- return particle.slow.inRange ? particle.slow.factor : identity;
5729
+ const mod = particle.getModifier("slow");
5730
+ return mod?.enabled ? (mod.speedFactor ?? identity) : identity;
5620
5731
  }
5621
5732
  function initSpin(container, particle) {
5622
5733
  const options = particle.options, spinOptions = options.move.spin;