@tsparticles/basic 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
- /* tsParticles v4.2.1 */
2
+ /* tsParticles 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) :
@@ -398,29 +398,27 @@
398
398
  }
399
399
  }
400
400
  else if (!isObject(destination) || Array.isArray(destination)) {
401
- destination = {};
401
+ destination = Object.create(null);
402
402
  }
403
- const sourceKeys = Object.keys(source), dangerousKeys = new Set(["__proto__", "constructor", "prototype"]), hasNested = sourceKeys.some(k => {
403
+ const sourceKeys = Object.keys(source), hasNested = sourceKeys.some(k => {
404
404
  const v = source[k];
405
405
  return isObject(v) || Array.isArray(v);
406
406
  });
407
407
  if (!hasNested) {
408
408
  const sourceDict = source, destDict = destination;
409
409
  for (const key of sourceKeys) {
410
- if (dangerousKeys.has(key)) {
410
+ if (key === "__proto__" || key === "constructor" || key === "prototype") {
411
411
  continue;
412
412
  }
413
- if (key in sourceDict) {
414
- const v = sourceDict[key];
415
- if (v !== undefined) {
416
- destDict[key] = v;
417
- }
413
+ const v = sourceDict[key];
414
+ if (v !== undefined) {
415
+ destDict[key] = v;
418
416
  }
419
417
  }
420
418
  continue;
421
419
  }
422
420
  for (const key of sourceKeys) {
423
- if (dangerousKeys.has(key)) {
421
+ if (key === "__proto__" || key === "constructor" || key === "prototype") {
424
422
  continue;
425
423
  }
426
424
  const sourceDict = source, destDict = destination, value = sourceDict[key];
@@ -879,7 +877,7 @@
879
877
  return this.#domArray;
880
878
  }
881
879
  get version() {
882
- return "4.2.1";
880
+ return "4.3.0";
883
881
  }
884
882
  addEventListener(type, listener) {
885
883
  this.#eventDispatcher.addEventListener(type, listener);
@@ -1112,6 +1110,18 @@
1112
1110
  AnimationStatus["decreasing"] = "decreasing";
1113
1111
  })(exports.AnimationStatus || (exports.AnimationStatus = {}));
1114
1112
 
1113
+ exports.DrawLayer = void 0;
1114
+ (function (DrawLayer) {
1115
+ DrawLayer[DrawLayer["BackgroundElement"] = 0] = "BackgroundElement";
1116
+ DrawLayer[DrawLayer["BackgroundDraw"] = 1] = "BackgroundDraw";
1117
+ DrawLayer[DrawLayer["BackgroundMask"] = 2] = "BackgroundMask";
1118
+ DrawLayer[DrawLayer["CanvasSetup"] = 3] = "CanvasSetup";
1119
+ DrawLayer[DrawLayer["PluginContent"] = 4] = "PluginContent";
1120
+ DrawLayer[DrawLayer["Particles"] = 5] = "Particles";
1121
+ DrawLayer[DrawLayer["CanvasCleanup"] = 6] = "CanvasCleanup";
1122
+ DrawLayer[DrawLayer["Foreground"] = 7] = "Foreground";
1123
+ })(exports.DrawLayer || (exports.DrawLayer = {}));
1124
+
1115
1125
  class OptionLoader {
1116
1126
  load(data) {
1117
1127
  if (isNull(data)) {
@@ -1270,6 +1280,8 @@
1270
1280
 
1271
1281
  class Background extends OptionLoader {
1272
1282
  color;
1283
+ draw;
1284
+ element;
1273
1285
  image = "";
1274
1286
  opacity = 1;
1275
1287
  position = "";
@@ -1284,6 +1296,8 @@
1284
1296
  if (data.color !== undefined) {
1285
1297
  this.color = OptionsColor.create(this.color, data.color);
1286
1298
  }
1299
+ loadProperty(this, "element", data.element);
1300
+ loadProperty(this, "draw", data.draw);
1287
1301
  loadProperty(this, "image", data.image);
1288
1302
  loadProperty(this, "position", data.position);
1289
1303
  loadProperty(this, "repeat", data.repeat);
@@ -1829,7 +1843,7 @@
1829
1843
  }
1830
1844
  }
1831
1845
 
1832
- const styleCache = new Map(), maxStyleCacheSize = 2000, rgbFixedPrecision = 2, hslFixedPrecision = 2, sdrReferenceWhiteNits = 203;
1846
+ const styleCache = new Map(), maxStyleCacheSize = 2000, rgbFixedPrecision = 2, hslFixedPrecision = 2, hdrRgbFixedPrecision = 4, hdrHslFixedPrecision = 4, sdrReferenceWhiteNits = 203, hdrAnimationScale = sdrReferenceWhiteNits / maxNits;
1833
1847
  function getCachedStyle(key, generator) {
1834
1848
  let cached = styleCache.get(key);
1835
1849
  if (!cached) {
@@ -1972,6 +1986,17 @@
1972
1986
  : 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));
1973
1987
  return { r: Math.round(red), g: Math.round(green), b: Math.round(blue) };
1974
1988
  }
1989
+ function hslToRgbFloat(hsl) {
1990
+ 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;
1991
+ if (s === sMin) {
1992
+ const grayscaleValue = lNormalized * rgbMax;
1993
+ return { r: grayscaleValue, g: grayscaleValue, b: grayscaleValue };
1994
+ }
1995
+ const temp1 = lNormalized < half
1996
+ ? lNormalized * (sNormalizedOffset + sNormalized)
1997
+ : 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));
1998
+ return { r: red, g: green, b: blue };
1999
+ }
1975
2000
  function hslaToRgba(hsla) {
1976
2001
  const rgbResult = hslToRgb(hsla);
1977
2002
  return {
@@ -1981,8 +2006,16 @@
1981
2006
  r: rgbResult.r,
1982
2007
  };
1983
2008
  }
1984
- function getRandomRgbColor(min) {
1985
- const fixedMin = min ?? defaultRgbMin, fixedMax = rgbMax + identity, getRgbInRangeValue = () => Math.floor(getRandomInRange(fixedMin, fixedMax));
2009
+ function getRandomRgbColor(min, hdr) {
2010
+ const fixedMin = min ?? defaultRgbMin;
2011
+ if (hdr) {
2012
+ return {
2013
+ r: getRandomInRange(fixedMin, rgbMax),
2014
+ g: getRandomInRange(fixedMin, rgbMax),
2015
+ b: getRandomInRange(fixedMin, rgbMax),
2016
+ };
2017
+ }
2018
+ const fixedMax = rgbMax + identity, getRgbInRangeValue = () => Math.floor(getRandomInRange(fixedMin, fixedMax));
1986
2019
  return {
1987
2020
  b: getRgbInRangeValue(),
1988
2021
  g: getRgbInRangeValue(),
@@ -1990,7 +2023,7 @@
1990
2023
  };
1991
2024
  }
1992
2025
  function getStyleFromRgb(color, hdr, opacity) {
1993
- const op = opacity ?? defaultOpacity$1, key = `rgb-${color.r.toFixed(rgbFixedPrecision)}-${color.g.toFixed(rgbFixedPrecision)}-${color.b.toFixed(rgbFixedPrecision)}-${hdr ? "hdr" : "sdr"}-${op.toString()}`;
2026
+ 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()}`;
1994
2027
  return getCachedStyle(key, () => (hdr ? getHdrStyleFromRgb(color, opacity) : getSdrStyleFromRgb(color, opacity)));
1995
2028
  }
1996
2029
  function getHdrStyleFromRgb(color, opacity, peakNits = maxNits) {
@@ -2001,9 +2034,9 @@
2001
2034
  return `rgba(${color.r.toString()}, ${color.g.toString()}, ${color.b.toString()}, ${(opacity ?? defaultOpacity$1).toString()})`;
2002
2035
  }
2003
2036
  function getStyleFromHsl(color, hdr, opacity) {
2004
- const op = opacity ?? defaultOpacity$1, key = `hsl-${color.h.toFixed(hslFixedPrecision)}-${color.s.toFixed(hslFixedPrecision)}-${color.l.toFixed(hslFixedPrecision)}-${hdr ? "hdr" : "sdr"}-${op.toString()}`;
2037
+ 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()}`;
2005
2038
  return getCachedStyle(key, () => hdr
2006
- ? getStyleFromRgb(hslToRgb(color), true, opacity)
2039
+ ? getStyleFromRgb(hslToRgbFloat(color), true, opacity)
2007
2040
  : `hsla(${color.h.toString()}, ${color.s.toString()}%, ${color.l.toString()}%, ${op.toString()})`);
2008
2041
  }
2009
2042
  function colorMix(color1, color2, size1, size2) {
@@ -2123,7 +2156,7 @@
2123
2156
  colorValue.velocity = defaultVelocity;
2124
2157
  }
2125
2158
  }
2126
- function updateColorValue(data, decrease, delta) {
2159
+ function updateColorValue(data, decrease, delta, hdr) {
2127
2160
  const minLoops = 0, minDelay = 0, identity = 1, minVelocity = 0, minOffset = 0, velocityFactor = 3.6;
2128
2161
  if (!data.enable ||
2129
2162
  ((data.maxLoops ?? minLoops) > minLoops && (data.loops ?? minLoops) > (data.maxLoops ?? minLoops))) {
@@ -2136,7 +2169,7 @@
2136
2169
  if ((data.delayTime ?? minDelay) > minDelay && data.time < (data.delayTime ?? minDelay)) {
2137
2170
  return;
2138
2171
  }
2139
- 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;
2172
+ 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;
2140
2173
  if (!decrease || data.status === exports.AnimationStatus.increasing) {
2141
2174
  data.value += velocity;
2142
2175
  if (data.value > max) {
@@ -2163,14 +2196,14 @@
2163
2196
  }
2164
2197
  data.value = clamp(data.value, min, max);
2165
2198
  }
2166
- function updateColor(color, delta) {
2199
+ function updateColor(color, delta, hdr) {
2167
2200
  if (!color) {
2168
2201
  return;
2169
2202
  }
2170
2203
  const { h, s, l } = color;
2171
- updateColorValue(h, false, delta);
2172
- updateColorValue(s, true, delta);
2173
- updateColorValue(l, true, delta);
2204
+ updateColorValue(h, false, delta, hdr);
2205
+ updateColorValue(s, true, delta, hdr);
2206
+ updateColorValue(l, true, delta, hdr);
2174
2207
  }
2175
2208
  function alterHsl(color, type, value) {
2176
2209
  return {
@@ -2220,7 +2253,7 @@
2220
2253
  }
2221
2254
 
2222
2255
  async function loadBlendPlugin(engine) {
2223
- engine.checkVersion("4.2.1");
2256
+ engine.checkVersion("4.3.0");
2224
2257
  await engine.pluginManager.register(e => {
2225
2258
  e.pluginManager.addPlugin(new BlendPlugin());
2226
2259
  });
@@ -2257,7 +2290,7 @@
2257
2290
  }
2258
2291
 
2259
2292
  async function loadCircleShape(engine) {
2260
- engine.checkVersion("4.2.1");
2293
+ engine.checkVersion("4.3.0");
2261
2294
  await engine.pluginManager.register(e => {
2262
2295
  e.pluginManager.addShape(["circle"], () => {
2263
2296
  return Promise.resolve(new CircleDrawer());
@@ -2305,7 +2338,7 @@
2305
2338
  }
2306
2339
 
2307
2340
  async function loadHexColorPlugin(engine) {
2308
- engine.checkVersion("4.2.1");
2341
+ engine.checkVersion("4.3.0");
2309
2342
  await engine.pluginManager.register(e => {
2310
2343
  e.pluginManager.addColorManager("hex", new HexColorManager());
2311
2344
  });
@@ -2358,7 +2391,7 @@
2358
2391
  }
2359
2392
 
2360
2393
  async function loadHslColorPlugin(engine) {
2361
- engine.checkVersion("4.2.1");
2394
+ engine.checkVersion("4.3.0");
2362
2395
  await engine.pluginManager.register(e => {
2363
2396
  e.pluginManager.addColorManager("hsl", new HslColorManager());
2364
2397
  });
@@ -2382,7 +2415,7 @@
2382
2415
  }
2383
2416
 
2384
2417
  async function loadMovePlugin(engine) {
2385
- engine.checkVersion("4.2.1");
2418
+ engine.checkVersion("4.3.0");
2386
2419
  await engine.pluginManager.register(e => {
2387
2420
  const moveEngine = e, movePluginManager = moveEngine.pluginManager;
2388
2421
  movePluginManager.initializers.pathGenerators ??= new Map();
@@ -2592,7 +2625,7 @@
2592
2625
  }
2593
2626
 
2594
2627
  async function loadOpacityUpdater(engine) {
2595
- engine.checkVersion("4.2.1");
2628
+ engine.checkVersion("4.3.0");
2596
2629
  await engine.pluginManager.register(e => {
2597
2630
  e.pluginManager.addParticleUpdater("opacity", container => {
2598
2631
  return Promise.resolve(new OpacityUpdater(container));
@@ -2937,7 +2970,7 @@
2937
2970
  }
2938
2971
 
2939
2972
  async function loadOutModesUpdater(engine) {
2940
- engine.checkVersion("4.2.1");
2973
+ engine.checkVersion("4.3.0");
2941
2974
  await engine.pluginManager.register(e => {
2942
2975
  e.pluginManager.addParticleUpdater("outModes", container => {
2943
2976
  return Promise.resolve(new OutOfCanvasUpdater(container));
@@ -3002,13 +3035,13 @@
3002
3035
  if (!this.isEnabled(particle)) {
3003
3036
  return;
3004
3037
  }
3005
- updateColor(particle.fillColor, delta);
3006
- updateColor(particle.strokeColor, delta);
3038
+ updateColor(particle.fillColor, delta, this.#container.hdr);
3039
+ updateColor(particle.strokeColor, delta, this.#container.hdr);
3007
3040
  }
3008
3041
  }
3009
3042
 
3010
3043
  async function loadPaintUpdater(engine) {
3011
- engine.checkVersion("4.2.1");
3044
+ engine.checkVersion("4.3.0");
3012
3045
  await engine.pluginManager.register(e => {
3013
3046
  e.pluginManager.addParticleUpdater("paint", container => {
3014
3047
  return Promise.resolve(new PaintUpdater(e.pluginManager, container));
@@ -3063,7 +3096,7 @@
3063
3096
  }
3064
3097
 
3065
3098
  async function loadRgbColorPlugin(engine) {
3066
- engine.checkVersion("4.2.1");
3099
+ engine.checkVersion("4.3.0");
3067
3100
  await engine.pluginManager.register(e => {
3068
3101
  e.pluginManager.addColorManager("rgb", new RgbColorManager());
3069
3102
  });
@@ -3148,7 +3181,7 @@
3148
3181
  }
3149
3182
 
3150
3183
  async function loadSizeUpdater(engine) {
3151
- engine.checkVersion("4.2.1");
3184
+ engine.checkVersion("4.3.0");
3152
3185
  await engine.pluginManager.register(e => {
3153
3186
  e.pluginManager.addParticleUpdater("size", container => {
3154
3187
  return Promise.resolve(new SizeUpdater(container));
@@ -3157,7 +3190,7 @@
3157
3190
  }
3158
3191
 
3159
3192
  async function loadBasic(engine) {
3160
- engine.checkVersion("4.2.1");
3193
+ engine.checkVersion("4.3.0");
3161
3194
  await engine.pluginManager.register(async (e) => {
3162
3195
  await Promise.all([
3163
3196
  loadBlendPlugin(e),
@@ -3186,10 +3219,10 @@
3186
3219
  }
3187
3220
  }
3188
3221
  class RenderManager {
3222
+ #backgroundElement;
3223
+ #backgroundWarnings;
3189
3224
  #canvasClearPlugins;
3190
3225
  #canvasManager;
3191
- #canvasPaintPlugins;
3192
- #clearDrawPlugins;
3193
3226
  #colorPlugins;
3194
3227
  #container;
3195
3228
  #context;
@@ -3197,9 +3230,7 @@
3197
3230
  #drawParticlePlugins;
3198
3231
  #drawParticlesCleanupPlugins;
3199
3232
  #drawParticlesSetupPlugins;
3200
- #drawPlugins;
3201
- #drawSettingsCleanupPlugins;
3202
- #drawSettingsSetupPlugins;
3233
+ #layers;
3203
3234
  #pluginManager;
3204
3235
  #postDrawUpdaters;
3205
3236
  #preDrawUpdaters;
@@ -3211,18 +3242,25 @@
3211
3242
  this.#container = container;
3212
3243
  this.#canvasManager = canvasManager;
3213
3244
  this.#context = null;
3245
+ this.#backgroundElement = null;
3246
+ this.#backgroundWarnings = new Set();
3214
3247
  this.#preDrawUpdaters = [];
3215
3248
  this.#postDrawUpdaters = [];
3216
- this.#colorPlugins = [];
3217
3249
  this.#canvasClearPlugins = [];
3218
- this.#canvasPaintPlugins = [];
3219
- this.#clearDrawPlugins = [];
3250
+ this.#colorPlugins = [];
3220
3251
  this.#drawParticlePlugins = [];
3221
3252
  this.#drawParticlesCleanupPlugins = [];
3222
3253
  this.#drawParticlesSetupPlugins = [];
3223
- this.#drawPlugins = [];
3224
- this.#drawSettingsSetupPlugins = [];
3225
- this.#drawSettingsCleanupPlugins = [];
3254
+ this.#layers = {
3255
+ 0: [],
3256
+ 1: [],
3257
+ 2: [],
3258
+ 3: [],
3259
+ 4: [],
3260
+ 5: [],
3261
+ 6: [],
3262
+ 7: [],
3263
+ };
3226
3264
  }
3227
3265
  get settings() {
3228
3266
  return this.#contextSettings;
@@ -3236,32 +3274,38 @@
3236
3274
  });
3237
3275
  }
3238
3276
  clear() {
3239
- let pluginHandled = false;
3240
3277
  for (const plugin of this.#canvasClearPlugins) {
3241
- pluginHandled = plugin.canvasClear?.() ?? false;
3242
- if (pluginHandled) {
3243
- break;
3278
+ if (plugin.canvasClear?.() ?? false) {
3279
+ return;
3244
3280
  }
3245
3281
  }
3246
- if (pluginHandled) {
3247
- return;
3282
+ for (const layer of Object.values(exports.DrawLayer)) {
3283
+ if (typeof layer === "number") {
3284
+ for (const plugin of this.#getLayerPlugins(layer)) {
3285
+ if (plugin.canvasClear?.() ?? false) {
3286
+ return;
3287
+ }
3288
+ }
3289
+ }
3248
3290
  }
3249
3291
  this.canvasClear();
3250
3292
  }
3251
3293
  destroy() {
3252
3294
  this.stop();
3295
+ this.#backgroundElement = null;
3296
+ this.#backgroundWarnings.clear();
3253
3297
  this.#preDrawUpdaters = [];
3254
3298
  this.#postDrawUpdaters = [];
3255
- this.#colorPlugins = [];
3256
3299
  this.#canvasClearPlugins = [];
3257
- this.#canvasPaintPlugins = [];
3258
- this.#clearDrawPlugins = [];
3300
+ this.#colorPlugins = [];
3259
3301
  this.#drawParticlePlugins = [];
3260
3302
  this.#drawParticlesCleanupPlugins = [];
3261
3303
  this.#drawParticlesSetupPlugins = [];
3262
- this.#drawPlugins = [];
3263
- this.#drawSettingsSetupPlugins = [];
3264
- this.#drawSettingsCleanupPlugins = [];
3304
+ for (const layer of Object.values(exports.DrawLayer)) {
3305
+ if (typeof layer === "number") {
3306
+ this.#layers[layer] = [];
3307
+ }
3308
+ }
3265
3309
  }
3266
3310
  draw(cb) {
3267
3311
  const ctx = this.#context;
@@ -3318,21 +3362,40 @@
3318
3362
  });
3319
3363
  }
3320
3364
  drawParticles(delta) {
3321
- const { particles } = this.#container;
3365
+ const { particles, actualOptions } = this.#container;
3322
3366
  this.clear();
3323
3367
  particles.update(delta);
3324
3368
  this.draw(ctx => {
3325
- for (const plugin of this.#drawSettingsSetupPlugins) {
3369
+ const width = this.#canvasManager.size.width, height = this.#canvasManager.size.height;
3370
+ if (this.#backgroundElement) {
3371
+ try {
3372
+ ctx.drawImage(this.#backgroundElement, originPoint.x, originPoint.y, width, height);
3373
+ }
3374
+ catch {
3375
+ this.#warnOnce("background-element-draw-error", "Error drawing background element onto canvas");
3376
+ }
3377
+ }
3378
+ const background = actualOptions.background;
3379
+ if (background.draw) {
3380
+ try {
3381
+ background.draw(ctx, delta);
3382
+ }
3383
+ catch {
3384
+ this.#warnOnce("background-draw-error", "Error in background.draw callback");
3385
+ }
3386
+ }
3387
+ for (const plugin of this.#getLayerPlugins(exports.DrawLayer.BackgroundMask)) {
3388
+ plugin.canvasPaint?.();
3389
+ }
3390
+ for (const plugin of this.#getLayerPlugins(exports.DrawLayer.CanvasSetup)) {
3326
3391
  plugin.drawSettingsSetup?.(ctx, delta);
3327
3392
  }
3328
- for (const plugin of this.#drawPlugins) {
3393
+ for (const plugin of this.#getLayerPlugins(exports.DrawLayer.PluginContent)) {
3329
3394
  plugin.draw?.(ctx, delta);
3330
3395
  }
3331
3396
  particles.drawParticles(delta);
3332
- for (const plugin of this.#clearDrawPlugins) {
3397
+ for (const plugin of this.#getLayerPlugins(exports.DrawLayer.CanvasCleanup)) {
3333
3398
  plugin.clearDraw?.(ctx, delta);
3334
- }
3335
- for (const plugin of this.#drawSettingsCleanupPlugins) {
3336
3399
  plugin.drawSettingsCleanup?.(ctx, delta);
3337
3400
  }
3338
3401
  });
@@ -3340,29 +3403,24 @@
3340
3403
  init() {
3341
3404
  this.initUpdaters();
3342
3405
  this.initPlugins();
3406
+ this.#resolveBackgroundElement();
3343
3407
  this.paint();
3344
3408
  }
3345
3409
  initPlugins() {
3346
- this.#colorPlugins = [];
3347
3410
  this.#canvasClearPlugins = [];
3348
- this.#canvasPaintPlugins = [];
3349
- this.#clearDrawPlugins = [];
3411
+ this.#colorPlugins = [];
3350
3412
  this.#drawParticlePlugins = [];
3351
3413
  this.#drawParticlesSetupPlugins = [];
3352
3414
  this.#drawParticlesCleanupPlugins = [];
3353
- this.#drawPlugins = [];
3354
- this.#drawSettingsSetupPlugins = [];
3355
- this.#drawSettingsCleanupPlugins = [];
3415
+ for (const layer of Object.values(exports.DrawLayer)) {
3416
+ if (typeof layer === "number") {
3417
+ this.#layers[layer] = [];
3418
+ }
3419
+ }
3356
3420
  for (const plugin of this.#container.plugins) {
3357
3421
  if (plugin.particleFillColor ?? plugin.particleStrokeColor) {
3358
3422
  this.#colorPlugins.push(plugin);
3359
3423
  }
3360
- if (plugin.canvasClear) {
3361
- this.#canvasClearPlugins.push(plugin);
3362
- }
3363
- if (plugin.canvasPaint) {
3364
- this.#canvasPaintPlugins.push(plugin);
3365
- }
3366
3424
  if (plugin.drawParticle) {
3367
3425
  this.#drawParticlePlugins.push(plugin);
3368
3426
  }
@@ -3372,17 +3430,20 @@
3372
3430
  if (plugin.drawParticleCleanup) {
3373
3431
  this.#drawParticlesCleanupPlugins.push(plugin);
3374
3432
  }
3375
- if (plugin.draw) {
3376
- this.#drawPlugins.push(plugin);
3433
+ if (plugin.canvasClear) {
3434
+ this.#canvasClearPlugins.push(plugin);
3435
+ }
3436
+ if (plugin.canvasPaint) {
3437
+ this.#getLayerPlugins(exports.DrawLayer.BackgroundMask).push(plugin);
3377
3438
  }
3378
3439
  if (plugin.drawSettingsSetup) {
3379
- this.#drawSettingsSetupPlugins.push(plugin);
3440
+ this.#getLayerPlugins(exports.DrawLayer.CanvasSetup).push(plugin);
3380
3441
  }
3381
- if (plugin.drawSettingsCleanup) {
3382
- this.#drawSettingsCleanupPlugins.push(plugin);
3442
+ if (plugin.draw) {
3443
+ this.#getLayerPlugins(exports.DrawLayer.PluginContent).push(plugin);
3383
3444
  }
3384
- if (plugin.clearDraw) {
3385
- this.#clearDrawPlugins.push(plugin);
3445
+ if (plugin.clearDraw ?? plugin.drawSettingsCleanup) {
3446
+ this.#getLayerPlugins(exports.DrawLayer.CanvasCleanup).push(plugin);
3386
3447
  }
3387
3448
  }
3388
3449
  }
@@ -3400,7 +3461,7 @@
3400
3461
  }
3401
3462
  paint() {
3402
3463
  let handled = false;
3403
- for (const plugin of this.#canvasPaintPlugins) {
3464
+ for (const plugin of this.#getLayerPlugins(exports.DrawLayer.BackgroundMask)) {
3404
3465
  handled = plugin.canvasPaint?.() ?? false;
3405
3466
  if (handled) {
3406
3467
  break;
@@ -3573,6 +3634,9 @@
3573
3634
  }
3574
3635
  drawer.beforeDraw(data);
3575
3636
  }
3637
+ #getLayerPlugins(layer) {
3638
+ return this.#layers[layer];
3639
+ }
3576
3640
  #getPluginParticleColors(particle) {
3577
3641
  let fColor, sColor;
3578
3642
  for (const plugin of this.#colorPlugins) {
@@ -3590,6 +3654,39 @@
3590
3654
  this.#reusablePluginColors[sColorIndex] = sColor;
3591
3655
  return this.#reusablePluginColors;
3592
3656
  }
3657
+ #resolveBackgroundElement() {
3658
+ const background = this.#container.actualOptions.background;
3659
+ this.#backgroundElement = null;
3660
+ if (!background.element) {
3661
+ return;
3662
+ }
3663
+ if (typeof background.element === "string") {
3664
+ if (typeof document !== "undefined") {
3665
+ const node = document.querySelector(background.element);
3666
+ if (node instanceof HTMLCanvasElement || node instanceof HTMLVideoElement || node instanceof HTMLImageElement) {
3667
+ this.#backgroundElement = node;
3668
+ }
3669
+ else if (node) {
3670
+ this.#warnOnce("background-element-not-supported", `Background element "${background.element}" is not a supported drawable element (canvas, video, or img)`);
3671
+ }
3672
+ else {
3673
+ this.#warnOnce("background-element-not-found", `Background element selector "${background.element}" not found`);
3674
+ }
3675
+ }
3676
+ }
3677
+ else if (background.element instanceof HTMLCanvasElement ||
3678
+ background.element instanceof OffscreenCanvas ||
3679
+ background.element instanceof HTMLVideoElement ||
3680
+ background.element instanceof HTMLImageElement) {
3681
+ this.#backgroundElement = background.element;
3682
+ }
3683
+ }
3684
+ #warnOnce(key, message) {
3685
+ if (!this.#backgroundWarnings.has(key)) {
3686
+ this.#backgroundWarnings.add(key);
3687
+ getLogger().warning(message);
3688
+ }
3689
+ }
3593
3690
  }
3594
3691
 
3595
3692
  const transferredCanvases = new WeakMap(), getTransferredCanvas = (canvas) => {
@@ -4166,7 +4263,6 @@
4166
4263
  }
4167
4264
  class Particle {
4168
4265
  backColor;
4169
- bubble;
4170
4266
  destroyed;
4171
4267
  direction;
4172
4268
  effect;
@@ -4200,7 +4296,6 @@
4200
4296
  shapeData;
4201
4297
  sides;
4202
4298
  size;
4203
- slow;
4204
4299
  spawning;
4205
4300
  strokeColor;
4206
4301
  strokeOpacity;
@@ -4222,18 +4317,25 @@
4222
4317
  d: 1,
4223
4318
  };
4224
4319
  #container;
4320
+ #modifiers = [];
4225
4321
  #pluginManager;
4226
4322
  constructor(pluginManager, container) {
4227
4323
  this.#pluginManager = pluginManager;
4228
4324
  this.#container = container;
4229
4325
  }
4326
+ addModifier(modifier) {
4327
+ this.#modifiers.push(modifier);
4328
+ this.#modifiers.sort((a, b) => a.priority - b.priority);
4329
+ }
4330
+ clearModifiers() {
4331
+ this.#modifiers.length = 0;
4332
+ }
4230
4333
  destroy(override) {
4231
4334
  if (this.unbreakable || this.destroyed) {
4232
4335
  return;
4233
4336
  }
4234
4337
  this.destroyed = true;
4235
- this.bubble.inRange = false;
4236
- this.slow.inRange = false;
4338
+ this.clearModifiers();
4237
4339
  const container = this.#container, shapeDrawer = this.shape ? container.shapeDrawers.get(this.shape) : undefined;
4238
4340
  shapeDrawer?.particleDestroy?.(this);
4239
4341
  for (const plugin of container.particleDestroyedPlugins) {
@@ -4255,13 +4357,16 @@
4255
4357
  return this.rotation + (this.pathRotation ? this.velocity.angle : defaultAngle);
4256
4358
  }
4257
4359
  getFillColor() {
4258
- return this.#getRollColor(this.bubble.color ?? getHslFromAnimation(this.fillColor));
4360
+ return this.#getRollColor(this.#applyModifiers(getHslFromAnimation(this.fillColor), m => m.fillColor));
4259
4361
  }
4260
4362
  getMass() {
4261
4363
  return this.getRadius() ** squareExp * Math.PI * half;
4262
4364
  }
4365
+ getModifier(id) {
4366
+ return this.#modifiers.find(m => m.id === id);
4367
+ }
4263
4368
  getOpacity() {
4264
- 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;
4369
+ 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;
4265
4370
  this.#cachedOpacityData.fillOpacity = opacity * fillOpacity * zOpacityFactor;
4266
4371
  this.#cachedOpacityData.opacity = opacity * zOpacityFactor;
4267
4372
  this.#cachedOpacityData.strokeOpacity = opacity * strokeOpacity * zOpacityFactor;
@@ -4274,7 +4379,7 @@
4274
4379
  return this.#cachedPosition;
4275
4380
  }
4276
4381
  getRadius() {
4277
- return this.bubble.radius ?? this.size.value;
4382
+ return this.#applyModifiers(this.size.value, m => m.radius);
4278
4383
  }
4279
4384
  getRotateData() {
4280
4385
  const angle = this.getAngle();
@@ -4283,7 +4388,7 @@
4283
4388
  return this.#cachedRotateData;
4284
4389
  }
4285
4390
  getStrokeColor() {
4286
- return this.#getRollColor(this.bubble.color ?? getHslFromAnimation(this.strokeColor));
4391
+ return this.#getRollColor(this.#applyModifiers(getHslFromAnimation(this.strokeColor), m => m.strokeColor));
4287
4392
  }
4288
4393
  getTransformData(externalTransform) {
4289
4394
  const rotateData = this.getRotateData(), rotating = this.isRotating;
@@ -4303,13 +4408,6 @@
4303
4408
  this.options = resolveParticleOptions(this, container, this.#pluginManager, overrideOptions);
4304
4409
  container.retina.initParticle(this);
4305
4410
  runUpdaterPreInit(container.particleUpdaters, this);
4306
- this.bubble = {
4307
- inRange: false,
4308
- };
4309
- this.slow = {
4310
- inRange: false,
4311
- factor: 1,
4312
- };
4313
4411
  this.#initPosition(position);
4314
4412
  this.initialVelocity = this.#calculateVelocity();
4315
4413
  this.velocity = this.initialVelocity.copy();
@@ -4349,11 +4447,29 @@
4349
4447
  isVisible() {
4350
4448
  return !this.destroyed && !this.spawning && this.isInsideCanvas();
4351
4449
  }
4450
+ removeModifier(id) {
4451
+ const idx = this.#modifiers.findIndex(m => m.id === id);
4452
+ if (idx >= defaultAngle) {
4453
+ this.#modifiers.splice(idx, identity);
4454
+ }
4455
+ }
4352
4456
  reset() {
4353
4457
  for (const updater of this.#container.particleUpdaters) {
4354
4458
  updater.reset?.(this);
4355
4459
  }
4356
4460
  }
4461
+ #applyModifiers(base, getter) {
4462
+ let value = base;
4463
+ for (const mod of this.#modifiers) {
4464
+ if (mod.enabled) {
4465
+ const override = getter(mod);
4466
+ if (override !== undefined) {
4467
+ value = override;
4468
+ }
4469
+ }
4470
+ }
4471
+ return value;
4472
+ }
4357
4473
  #calcPosition(position, zIndex) {
4358
4474
  let tryCount = defaultRetryCount, posVec = position ? Vector3d.create(position.x, position.y, zIndex) : undefined;
4359
4475
  const container = this.#container, plugins = container.particlePositionPlugins, outModes = this.options.move.outModes, radius = this.getRadius(), canvasSize = container.canvas.size;
@@ -5455,6 +5571,7 @@
5455
5571
  });
5456
5572
 
5457
5573
  class BlendPluginInstance {
5574
+ layer = exports.DrawLayer.CanvasSetup;
5458
5575
  #container;
5459
5576
  #defaultCompositeValue;
5460
5577
  constructor(container) {
@@ -5600,7 +5717,8 @@
5600
5717
  particle.lastPathTime -= pathDelay;
5601
5718
  }
5602
5719
  function getProximitySpeedFactor(particle) {
5603
- return particle.slow.inRange ? particle.slow.factor : identity;
5720
+ const mod = particle.getModifier("slow");
5721
+ return mod?.enabled ? (mod.speedFactor ?? identity) : identity;
5604
5722
  }
5605
5723
  function initSpin(container, particle) {
5606
5724
  const options = particle.options, spinOptions = options.move.spin;
@@ -5823,6 +5941,7 @@
5823
5941
  exports.hPhase = hPhase;
5824
5942
  exports.half = half;
5825
5943
  exports.hslToRgb = hslToRgb;
5944
+ exports.hslToRgbFloat = hslToRgbFloat;
5826
5945
  exports.hslaToRgba = hslaToRgba;
5827
5946
  exports.identity = identity;
5828
5947
  exports.inverseFactorNumerator = inverseFactorNumerator;