@tsparticles/all 4.2.0 → 4.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
1
1
  (function(g){g.__tsParticlesInternals=g.__tsParticlesInternals||{};g.__tsParticlesInternals.bundles=g.__tsParticlesInternals.bundles||{};g.__tsParticlesInternals.effects=g.__tsParticlesInternals.effects||{};g.__tsParticlesInternals.engine=g.__tsParticlesInternals.engine||{};g.__tsParticlesInternals.interactions=g.__tsParticlesInternals.interactions||{};g.__tsParticlesInternals.palettes=g.__tsParticlesInternals.palettes||{};g.__tsParticlesInternals.paths=g.__tsParticlesInternals.paths||{};g.__tsParticlesInternals.plugins=g.__tsParticlesInternals.plugins||{};g.__tsParticlesInternals.plugins=g.__tsParticlesInternals.plugins||{};g.__tsParticlesInternals.plugins.emittersShapes=g.__tsParticlesInternals.plugins.emittersShapes||{};g.__tsParticlesInternals.presets=g.__tsParticlesInternals.presets||{};g.__tsParticlesInternals.shapes=g.__tsParticlesInternals.shapes||{};g.__tsParticlesInternals.updaters=g.__tsParticlesInternals.updaters||{};g.__tsParticlesInternals.utils=g.__tsParticlesInternals.utils||{};g.__tsParticlesInternals.canvas=g.__tsParticlesInternals.canvas||{};g.__tsParticlesInternals.canvas=g.__tsParticlesInternals.canvas||{};g.__tsParticlesInternals.canvas.utils=g.__tsParticlesInternals.canvas.utils||{};g.__tsParticlesInternals.path=g.__tsParticlesInternals.path||{};g.__tsParticlesInternals.path=g.__tsParticlesInternals.path||{};g.__tsParticlesInternals.path.utils=g.__tsParticlesInternals.path.utils||{};var __tsProxyFactory=typeof Proxy!=="undefined"?function(obj){return new Proxy(obj,{get:function(target,key){if(!(key in target)){target[key]={};}return target[key];}});}:function(obj){return obj;};g.__tsParticlesInternals.bundles=__tsProxyFactory(g.__tsParticlesInternals.bundles);g.__tsParticlesInternals.effects=__tsProxyFactory(g.__tsParticlesInternals.effects);g.__tsParticlesInternals.interactions=__tsProxyFactory(g.__tsParticlesInternals.interactions);g.__tsParticlesInternals.palettes=__tsProxyFactory(g.__tsParticlesInternals.palettes);g.__tsParticlesInternals.paths=__tsProxyFactory(g.__tsParticlesInternals.paths);g.__tsParticlesInternals.plugins=__tsProxyFactory(g.__tsParticlesInternals.plugins);g.__tsParticlesInternals.plugins.emittersShapes=__tsProxyFactory(g.__tsParticlesInternals.plugins.emittersShapes);g.__tsParticlesInternals.presets=__tsProxyFactory(g.__tsParticlesInternals.presets);g.__tsParticlesInternals.shapes=__tsProxyFactory(g.__tsParticlesInternals.shapes);g.__tsParticlesInternals.updaters=__tsProxyFactory(g.__tsParticlesInternals.updaters);g.__tsParticlesInternals.utils=__tsProxyFactory(g.__tsParticlesInternals.utils);g.__tsParticlesInternals.canvas=__tsProxyFactory(g.__tsParticlesInternals.canvas);g.__tsParticlesInternals.path=__tsProxyFactory(g.__tsParticlesInternals.path);g.tsparticlesInternalExports=g.tsparticlesInternalExports||{};})(typeof globalThis!=="undefined"?globalThis:typeof window!=="undefined"?window:this);
2
- /* tsParticles v4.2.0 */
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.0";
880
+ return "4.2.1";
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$2
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$3, 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$3, 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$3, 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$3, 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$3).toString()})`;
2002
2035
  }
2003
2036
  function getStyleFromHsl(color, hdr, opacity) {
2004
- const op = opacity ?? defaultOpacity$3, 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$3, 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 {
@@ -2210,7 +2243,7 @@
2210
2243
  }
2211
2244
 
2212
2245
  async function loadArrowShape(engine) {
2213
- engine.checkVersion("4.2.0");
2246
+ engine.checkVersion("4.2.1");
2214
2247
  await engine.pluginManager.register(e => {
2215
2248
  e.pluginManager.addShape(["arrow"], () => Promise.resolve(new ArrowDrawer()));
2216
2249
  });
@@ -2218,6 +2251,8 @@
2218
2251
 
2219
2252
  class BackgroundMaskCover {
2220
2253
  color;
2254
+ draw;
2255
+ element;
2221
2256
  image;
2222
2257
  opacity = 1;
2223
2258
  load(data) {
@@ -2227,6 +2262,8 @@
2227
2262
  if (data.color !== undefined) {
2228
2263
  this.color = OptionsColor.create(this.color, data.color);
2229
2264
  }
2265
+ loadProperty(this, "draw", data.draw);
2266
+ loadProperty(this, "element", data.element);
2230
2267
  loadProperty(this, "image", data.image);
2231
2268
  loadProperty(this, "opacity", data.opacity);
2232
2269
  }
@@ -2243,7 +2280,12 @@
2243
2280
  loadProperty(this, "composite", data.composite);
2244
2281
  if (data.cover !== undefined) {
2245
2282
  const cover = data.cover, color = (isString(data.cover) ? { color: data.cover } : data.cover);
2246
- this.cover.load(cover.color !== undefined || cover.image !== undefined ? cover : { color: color });
2283
+ this.cover.load(cover.color !== undefined ||
2284
+ cover.draw !== undefined ||
2285
+ cover.element !== undefined ||
2286
+ cover.image !== undefined
2287
+ ? cover
2288
+ : { color: color });
2247
2289
  }
2248
2290
  loadProperty(this, "enable", data.enable);
2249
2291
  }
@@ -2275,7 +2317,7 @@
2275
2317
  }
2276
2318
 
2277
2319
  async function loadBackgroundMaskPlugin(engine) {
2278
- engine.checkVersion("4.2.0");
2320
+ engine.checkVersion("4.2.1");
2279
2321
  await engine.pluginManager.register(e => {
2280
2322
  e.pluginManager.addPlugin(new BackgroundMaskPlugin(e.pluginManager));
2281
2323
  });
@@ -2299,7 +2341,7 @@
2299
2341
  }
2300
2342
 
2301
2343
  async function loadMovePlugin(engine) {
2302
- engine.checkVersion("4.2.0");
2344
+ engine.checkVersion("4.2.1");
2303
2345
  await engine.pluginManager.register(e => {
2304
2346
  const moveEngine = e, movePluginManager = moveEngine.pluginManager;
2305
2347
  movePluginManager.initializers.pathGenerators ??= new Map();
@@ -2400,7 +2442,7 @@
2400
2442
 
2401
2443
  const branchingPathName = "branchesPathGenerator";
2402
2444
  async function loadBranchesPath(engine) {
2403
- engine.checkVersion("4.2.0");
2445
+ engine.checkVersion("4.2.1");
2404
2446
  await engine.pluginManager.register((e) => {
2405
2447
  ensureBaseMoverLoaded(e);
2406
2448
  e.pluginManager.addPathGenerator?.(branchingPathName, container => {
@@ -2449,7 +2491,7 @@
2449
2491
 
2450
2492
  const brownianPathName = "brownianPathGenerator";
2451
2493
  async function loadBrownianPath(engine) {
2452
- engine.checkVersion("4.2.0");
2494
+ engine.checkVersion("4.2.1");
2453
2495
  await engine.pluginManager.register((e) => {
2454
2496
  ensureBaseMoverLoaded(e);
2455
2497
  e.pluginManager.addPathGenerator?.(brownianPathName, container => {
@@ -2471,7 +2513,7 @@
2471
2513
  }
2472
2514
 
2473
2515
  async function loadBubbleEffect(engine) {
2474
- engine.checkVersion("4.2.0");
2516
+ engine.checkVersion("4.2.1");
2475
2517
  await engine.pluginManager.register(e => {
2476
2518
  e.pluginManager.addEffect("bubble", () => {
2477
2519
  return Promise.resolve(new BubbleDrawer());
@@ -2641,7 +2683,7 @@
2641
2683
  }
2642
2684
 
2643
2685
  async function loadCanvasMaskPlugin(engine) {
2644
- engine.checkVersion("4.2.0");
2686
+ engine.checkVersion("4.2.1");
2645
2687
  await engine.pluginManager.register(e => {
2646
2688
  e.pluginManager.addPlugin(new CanvasMaskPlugin());
2647
2689
  });
@@ -2930,7 +2972,7 @@
2930
2972
  }
2931
2973
 
2932
2974
  async function loadClubsSuitShape(engine) {
2933
- engine.checkVersion("4.2.0");
2975
+ engine.checkVersion("4.2.1");
2934
2976
  await engine.pluginManager.register(e => {
2935
2977
  e.pluginManager.addShape(["club", "clubs"], () => Promise.resolve(new ClubDrawer()));
2936
2978
  });
@@ -2944,7 +2986,7 @@
2944
2986
  }
2945
2987
 
2946
2988
  async function loadDiamondsSuitShape(engine) {
2947
- engine.checkVersion("4.2.0");
2989
+ engine.checkVersion("4.2.1");
2948
2990
  await engine.pluginManager.register(e => {
2949
2991
  e.pluginManager.addShape(["diamond", "diamonds"], () => Promise.resolve(new DiamondDrawer()));
2950
2992
  });
@@ -2958,7 +3000,7 @@
2958
3000
  };
2959
3001
 
2960
3002
  async function loadHeartsSuitShape(engine) {
2961
- engine.checkVersion("4.2.0");
3003
+ engine.checkVersion("4.2.1");
2962
3004
  await engine.pluginManager.register(e => {
2963
3005
  e.pluginManager.addShape(["heart", "hearts"], () => Promise.resolve(new HeartDrawer$1()));
2964
3006
  });
@@ -2972,14 +3014,14 @@
2972
3014
  }
2973
3015
 
2974
3016
  async function loadSpadesSuitShape(engine) {
2975
- engine.checkVersion("4.2.0");
3017
+ engine.checkVersion("4.2.1");
2976
3018
  await engine.pluginManager.register(e => {
2977
3019
  e.pluginManager.addShape(["spade", "spades"], () => Promise.resolve(new SpadeDrawer()));
2978
3020
  });
2979
3021
  }
2980
3022
 
2981
3023
  async function loadCardSuitsShape(engine) {
2982
- engine.checkVersion("4.2.0");
3024
+ engine.checkVersion("4.2.1");
2983
3025
  await Promise.all([
2984
3026
  loadClubsSuitShape(engine),
2985
3027
  loadDiamondsSuitShape(engine),
@@ -3100,14 +3142,14 @@
3100
3142
  }
3101
3143
 
3102
3144
  async function loadFullCardsShape(engine) {
3103
- engine.checkVersion("4.2.0");
3145
+ engine.checkVersion("4.2.1");
3104
3146
  await engine.pluginManager.register(e => {
3105
3147
  e.pluginManager.addShape(["card"], container => Promise.resolve(new CardDrawer(container)));
3106
3148
  });
3107
3149
  }
3108
3150
 
3109
3151
  async function loadCardsShape(engine) {
3110
- engine.checkVersion("4.2.0");
3152
+ engine.checkVersion("4.2.1");
3111
3153
  await Promise.all([
3112
3154
  loadFullCardsShape(engine),
3113
3155
  loadCardSuitsShape(engine),
@@ -3177,7 +3219,7 @@
3177
3219
  }
3178
3220
 
3179
3221
  async function loadCogShape(engine) {
3180
- engine.checkVersion("4.2.0");
3222
+ engine.checkVersion("4.2.1");
3181
3223
  await engine.pluginManager.register(e => {
3182
3224
  e.pluginManager.addShape(["cog"], () => Promise.resolve(new CogDrawer()));
3183
3225
  });
@@ -6817,7 +6859,7 @@
6817
6859
 
6818
6860
  const curlNoisePathName = "curlNoise";
6819
6861
  async function loadCurlNoisePath(engine) {
6820
- engine.checkVersion("4.2.0");
6862
+ engine.checkVersion("4.2.1");
6821
6863
  await engine.pluginManager.register((e) => {
6822
6864
  ensureBaseMoverLoaded(e);
6823
6865
  e.pluginManager.addPathGenerator?.(curlNoisePathName, container => {
@@ -6920,7 +6962,7 @@
6920
6962
 
6921
6963
  const curvesPathName = "curvesPathGenerator";
6922
6964
  async function loadCurvesPath(engine) {
6923
- engine.checkVersion("4.2.0");
6965
+ engine.checkVersion("4.2.1");
6924
6966
  await engine.pluginManager.register((e) => {
6925
6967
  ensureBaseMoverLoaded(e);
6926
6968
  e.pluginManager.addPathGenerator?.(curvesPathName, container => {
@@ -6946,7 +6988,7 @@
6946
6988
  });
6947
6989
 
6948
6990
  async function loadEasingBackPlugin(engine) {
6949
- engine.checkVersion("4.2.0");
6991
+ engine.checkVersion("4.2.1");
6950
6992
  await engine.pluginManager.register(e => {
6951
6993
  for (const [easing, easingFn] of easingsFunctions$d) {
6952
6994
  e.pluginManager.addEasing(easing, easingFn);
@@ -6977,7 +7019,7 @@
6977
7019
  easingsFunctions$c.set("ease-in-out-bounce", value => value < 0.5 ? (1 - bounceOut(1 - value * 2)) / 2 : (1 + bounceOut(value * 2 - 1)) / 2);
6978
7020
 
6979
7021
  async function loadEasingBouncePlugin(engine) {
6980
- engine.checkVersion("4.2.0");
7022
+ engine.checkVersion("4.2.1");
6981
7023
  await engine.pluginManager.register(e => {
6982
7024
  for (const [easing, easingFn] of easingsFunctions$c) {
6983
7025
  e.pluginManager.addEasing(easing, easingFn);
@@ -6991,7 +7033,7 @@
6991
7033
  easingsFunctions$b.set("ease-in-out-circ", value => value < 0.5 ? (1 - Math.sqrt(1 - (2 * value) ** 2)) / 2 : (Math.sqrt(1 - (-2 * value + 2) ** 2) + 1) / 2);
6992
7034
 
6993
7035
  async function loadEasingCircPlugin(engine) {
6994
- engine.checkVersion("4.2.0");
7036
+ engine.checkVersion("4.2.1");
6995
7037
  await engine.pluginManager.register(e => {
6996
7038
  for (const [easing, easingFn] of easingsFunctions$b) {
6997
7039
  e.pluginManager.addEasing(easing, easingFn);
@@ -7005,7 +7047,7 @@
7005
7047
  easingsFunctions$a.set("ease-in-out-cubic", value => (value < 0.5 ? 4 * value ** 3 : 1 - (-2 * value + 2) ** 3 / 2));
7006
7048
 
7007
7049
  async function loadEasingCubicPlugin(engine) {
7008
- engine.checkVersion("4.2.0");
7050
+ engine.checkVersion("4.2.1");
7009
7051
  await engine.pluginManager.register(e => {
7010
7052
  for (const [easing, easingFn] of easingsFunctions$a) {
7011
7053
  e.pluginManager.addEasing(easing, easingFn);
@@ -7038,7 +7080,7 @@
7038
7080
  });
7039
7081
 
7040
7082
  async function loadEasingElasticPlugin(engine) {
7041
- engine.checkVersion("4.2.0");
7083
+ engine.checkVersion("4.2.1");
7042
7084
  await engine.pluginManager.register(e => {
7043
7085
  for (const [easing, easingFn] of easingsFunctions$9) {
7044
7086
  e.pluginManager.addEasing(easing, easingFn);
@@ -7062,7 +7104,7 @@
7062
7104
  });
7063
7105
 
7064
7106
  async function loadEasingExpoPlugin(engine) {
7065
- engine.checkVersion("4.2.0");
7107
+ engine.checkVersion("4.2.1");
7066
7108
  await engine.pluginManager.register(e => {
7067
7109
  for (const [easing, easingFn] of easingsFunctions$8) {
7068
7110
  e.pluginManager.addEasing(easing, easingFn);
@@ -7076,7 +7118,7 @@
7076
7118
  easingsFunctions$7.set("ease-in-out-gaussian", value => gaussian(value));
7077
7119
 
7078
7120
  async function loadEasingGaussianPlugin(engine) {
7079
- engine.checkVersion("4.2.0");
7121
+ engine.checkVersion("4.2.1");
7080
7122
  await engine.pluginManager.register(e => {
7081
7123
  for (const [easing, easingFn] of easingsFunctions$7) {
7082
7124
  e.pluginManager.addEasing(easing, easingFn);
@@ -7090,7 +7132,7 @@
7090
7132
  easingsFunctions$6.set("ease-in-out-linear", value => value);
7091
7133
 
7092
7134
  async function loadEasingLinearPlugin(engine) {
7093
- engine.checkVersion("4.2.0");
7135
+ engine.checkVersion("4.2.1");
7094
7136
  await engine.pluginManager.register(e => {
7095
7137
  for (const [easing, easingFn] of easingsFunctions$6) {
7096
7138
  e.pluginManager.addEasing(easing, easingFn);
@@ -7104,7 +7146,7 @@
7104
7146
  easingsFunctions$5.set("ease-in-out-quart", value => (value < 0.5 ? 8 * value ** 4 : 1 - (-2 * value + 2) ** 4 / 2));
7105
7147
 
7106
7148
  async function loadEasingQuartPlugin(engine) {
7107
- engine.checkVersion("4.2.0");
7149
+ engine.checkVersion("4.2.1");
7108
7150
  await engine.pluginManager.register(e => {
7109
7151
  for (const [easing, easingFn] of easingsFunctions$5) {
7110
7152
  e.pluginManager.addEasing(easing, easingFn);
@@ -7118,7 +7160,7 @@
7118
7160
  easingsFunctions$4.set("ease-in-out-quint", value => (value < 0.5 ? 16 * value ** 5 : 1 - (-2 * value + 2) ** 5 / 2));
7119
7161
 
7120
7162
  async function loadEasingQuintPlugin(engine) {
7121
- engine.checkVersion("4.2.0");
7163
+ engine.checkVersion("4.2.1");
7122
7164
  await engine.pluginManager.register(e => {
7123
7165
  for (const [easing, easingFn] of easingsFunctions$4) {
7124
7166
  e.pluginManager.addEasing(easing, easingFn);
@@ -7132,7 +7174,7 @@
7132
7174
  easingsFunctions$3.set("ease-in-out-sigmoid", value => sigmoid(value));
7133
7175
 
7134
7176
  async function loadEasingSigmoidPlugin(engine) {
7135
- engine.checkVersion("4.2.0");
7177
+ engine.checkVersion("4.2.1");
7136
7178
  await engine.pluginManager.register(e => {
7137
7179
  for (const [easing, easingFn] of easingsFunctions$3) {
7138
7180
  e.pluginManager.addEasing(easing, easingFn);
@@ -7146,7 +7188,7 @@
7146
7188
  easingsFunctions$2.set("ease-in-out-sine", value => -(Math.cos(Math.PI * value) - 1) / 2);
7147
7189
 
7148
7190
  async function loadEasingSinePlugin(engine) {
7149
- engine.checkVersion("4.2.0");
7191
+ engine.checkVersion("4.2.1");
7150
7192
  await engine.pluginManager.register(e => {
7151
7193
  for (const [easing, easingFn] of easingsFunctions$2) {
7152
7194
  e.pluginManager.addEasing(easing, easingFn);
@@ -7160,7 +7202,7 @@
7160
7202
  easingsFunctions$1.set("ease-in-out-smoothstep", value => smoothstep$1(value));
7161
7203
 
7162
7204
  async function loadEasingSmoothstepPlugin(engine) {
7163
- engine.checkVersion("4.2.0");
7205
+ engine.checkVersion("4.2.1");
7164
7206
  await engine.pluginManager.register(e => {
7165
7207
  for (const [easing, easingFn] of easingsFunctions$1) {
7166
7208
  e.pluginManager.addEasing(easing, easingFn);
@@ -7399,7 +7441,7 @@
7399
7441
  }
7400
7442
 
7401
7443
  async function loadInteractivityPlugin(engine) {
7402
- engine.checkVersion("4.2.0");
7444
+ engine.checkVersion("4.2.1");
7403
7445
  await engine.pluginManager.register(e => {
7404
7446
  const interactivityEngine = e, interactivityPluginManager = interactivityEngine.pluginManager;
7405
7447
  interactivityPluginManager.addPlugin(new InteractivityPlugin(interactivityPluginManager));
@@ -7742,7 +7784,7 @@
7742
7784
  })(EmitterClickMode || (EmitterClickMode = {}));
7743
7785
 
7744
7786
  async function loadEmittersInteraction(engine) {
7745
- engine.checkVersion("4.2.0");
7787
+ engine.checkVersion("4.2.1");
7746
7788
  await engine.pluginManager.register(async (e) => {
7747
7789
  const instancesManager = await getEmittersInstancesManager(e);
7748
7790
  ensureInteractivityPluginLoaded(e);
@@ -7785,7 +7827,7 @@
7785
7827
  }
7786
7828
 
7787
7829
  async function loadEmittersPluginSimple(engine) {
7788
- engine.checkVersion("4.2.0");
7830
+ engine.checkVersion("4.2.1");
7789
7831
  await engine.pluginManager.register(async (e) => {
7790
7832
  const instancesManager = await getEmittersInstancesManager(e);
7791
7833
  await addEmittersShapesManager(e);
@@ -8125,7 +8167,7 @@
8125
8167
  }
8126
8168
 
8127
8169
  async function loadEmittersShapeCanvas(engine) {
8128
- engine.checkVersion("4.2.0");
8170
+ engine.checkVersion("4.2.1");
8129
8171
  await engine.pluginManager.register((e) => {
8130
8172
  ensureEmittersPluginLoaded(e);
8131
8173
  e.pluginManager.addEmitterShapeGenerator?.("canvas", new EmittersCanvasShapeGenerator());
@@ -8262,7 +8304,7 @@
8262
8304
  }
8263
8305
 
8264
8306
  async function loadEmittersShapePath(engine) {
8265
- engine.checkVersion("4.2.0");
8307
+ engine.checkVersion("4.2.1");
8266
8308
  await engine.pluginManager.register((e) => {
8267
8309
  ensureEmittersPluginLoaded(e);
8268
8310
  e.pluginManager.addEmitterShapeGenerator?.("path", new EmittersPathShapeGenerator());
@@ -8389,7 +8431,7 @@
8389
8431
  }
8390
8432
 
8391
8433
  async function loadEmittersShapePolygon(engine) {
8392
- engine.checkVersion("4.2.0");
8434
+ engine.checkVersion("4.2.1");
8393
8435
  await engine.pluginManager.register((e) => {
8394
8436
  ensureEmittersPluginLoaded(e);
8395
8437
  e.pluginManager.addEmitterShapeGenerator?.("polygon", new EmittersPolygonShapeGenerator());
@@ -8410,7 +8452,7 @@
8410
8452
  }
8411
8453
 
8412
8454
  async function loadExportImagePlugin(engine) {
8413
- engine.checkVersion("4.2.0");
8455
+ engine.checkVersion("4.2.1");
8414
8456
  await engine.pluginManager.register(e => {
8415
8457
  e.pluginManager.addPlugin(new ExportImagePlugin());
8416
8458
  });
@@ -8430,7 +8472,7 @@
8430
8472
  }
8431
8473
 
8432
8474
  async function loadExportJSONPlugin(engine) {
8433
- engine.checkVersion("4.2.0");
8475
+ engine.checkVersion("4.2.1");
8434
8476
  await engine.pluginManager.register(e => {
8435
8477
  e.pluginManager.addPlugin(new ExportJSONPlugin());
8436
8478
  });
@@ -8450,7 +8492,7 @@
8450
8492
  }
8451
8493
 
8452
8494
  async function loadExportVideoPlugin(engine) {
8453
- engine.checkVersion("4.2.0");
8495
+ engine.checkVersion("4.2.1");
8454
8496
  await engine.pluginManager.register(e => {
8455
8497
  e.pluginManager.addPlugin(new ExportVideoPlugin());
8456
8498
  });
@@ -8602,7 +8644,7 @@
8602
8644
  }
8603
8645
 
8604
8646
  async function loadExternalCannonInteraction(engine) {
8605
- engine.checkVersion("4.2.0");
8647
+ engine.checkVersion("4.2.1");
8606
8648
  await engine.pluginManager.register((e) => {
8607
8649
  ensureInteractivityPluginLoaded(e);
8608
8650
  e.pluginManager.addInteractor?.("externalCannon", container => {
@@ -8731,7 +8773,7 @@
8731
8773
  }
8732
8774
 
8733
8775
  async function loadExternalParticleInteraction(engine) {
8734
- engine.checkVersion("4.2.0");
8776
+ engine.checkVersion("4.2.1");
8735
8777
  await engine.pluginManager.register((e) => {
8736
8778
  ensureInteractivityPluginLoaded(e);
8737
8779
  e.pluginManager.addInteractor?.("externalParticle", container => {
@@ -8779,7 +8821,7 @@
8779
8821
  }
8780
8822
 
8781
8823
  async function loadExternalPopInteraction(engine) {
8782
- engine.checkVersion("4.2.0");
8824
+ engine.checkVersion("4.2.1");
8783
8825
  await engine.pluginManager.register((e) => {
8784
8826
  ensureInteractivityPluginLoaded(e);
8785
8827
  e.pluginManager.addInteractor?.("externalPop", container => {
@@ -8820,7 +8862,7 @@
8820
8862
  }
8821
8863
 
8822
8864
  async function loadFilterEffect(engine) {
8823
- engine.checkVersion("4.2.0");
8865
+ engine.checkVersion("4.2.1");
8824
8866
  await engine.pluginManager.register(e => {
8825
8867
  e.pluginManager.addEffect("filter", () => {
8826
8868
  return Promise.resolve(new FilterDrawer());
@@ -9102,7 +9144,7 @@
9102
9144
 
9103
9145
  const fractalNoisePathName = "fractalNoise";
9104
9146
  async function loadFractalNoisePath(engine) {
9105
- engine.checkVersion("4.2.0");
9147
+ engine.checkVersion("4.2.1");
9106
9148
  await engine.pluginManager.register((e) => {
9107
9149
  ensureBaseMoverLoaded(e);
9108
9150
  e.pluginManager.addPathGenerator?.(fractalNoisePathName, container => {
@@ -9318,7 +9360,7 @@
9318
9360
  }
9319
9361
 
9320
9362
  async function loadAbsorbersInteraction(engine) {
9321
- engine.checkVersion("4.2.0");
9363
+ engine.checkVersion("4.2.1");
9322
9364
  await engine.pluginManager.register(async (e) => {
9323
9365
  const pluginManager = e.pluginManager, instancesManager = await getAbsorbersInstancesManager(e);
9324
9366
  ensureInteractivityPluginLoaded(e);
@@ -9366,7 +9408,7 @@
9366
9408
  }
9367
9409
 
9368
9410
  async function loadAbsorbersPluginSimple(engine) {
9369
- engine.checkVersion("4.2.0");
9411
+ engine.checkVersion("4.2.1");
9370
9412
  await engine.pluginManager.register(async (e) => {
9371
9413
  const pluginManager = e.pluginManager, instancesManager = await getAbsorbersInstancesManager(e);
9372
9414
  pluginManager.addPlugin(new AbsorbersPlugin(instancesManager));
@@ -9692,7 +9734,7 @@
9692
9734
  }
9693
9735
 
9694
9736
  async function loadDestroyUpdater(engine) {
9695
- engine.checkVersion("4.2.0");
9737
+ engine.checkVersion("4.2.1");
9696
9738
  await engine.pluginManager.register(e => {
9697
9739
  e.pluginManager.addParticleUpdater("destroy", container => {
9698
9740
  return Promise.resolve(new DestroyUpdater(e.pluginManager, container));
@@ -9738,7 +9780,7 @@
9738
9780
  }
9739
9781
 
9740
9782
  async function loadEmittersShapeCircle(engine) {
9741
- engine.checkVersion("4.2.0");
9783
+ engine.checkVersion("4.2.1");
9742
9784
  await engine.pluginManager.register((e) => {
9743
9785
  ensureEmittersPluginLoaded(e);
9744
9786
  e.pluginManager.addEmitterShapeGenerator?.("circle", new EmittersCircleShapeGenerator());
@@ -9819,7 +9861,7 @@
9819
9861
  }
9820
9862
 
9821
9863
  async function loadEmittersShapeSquare(engine) {
9822
- engine.checkVersion("4.2.0");
9864
+ engine.checkVersion("4.2.1");
9823
9865
  await engine.pluginManager.register((e) => {
9824
9866
  ensureEmittersPluginLoaded(e);
9825
9867
  e.pluginManager.addEmitterShapeGenerator?.("square", new EmittersSquareShapeGenerator());
@@ -10001,7 +10043,7 @@
10001
10043
  }
10002
10044
 
10003
10045
  async function loadExternalDragInteraction(engine) {
10004
- engine.checkVersion("4.2.0");
10046
+ engine.checkVersion("4.2.1");
10005
10047
  await engine.pluginManager.register((e) => {
10006
10048
  ensureInteractivityPluginLoaded(e);
10007
10049
  e.pluginManager.addInteractor?.("externalDrag", container => {
@@ -10174,7 +10216,7 @@
10174
10216
  }
10175
10217
 
10176
10218
  async function loadExternalTrailInteraction(engine) {
10177
- engine.checkVersion("4.2.0");
10219
+ engine.checkVersion("4.2.1");
10178
10220
  await engine.pluginManager.register((e) => {
10179
10221
  ensureInteractivityPluginLoaded(e);
10180
10222
  e.pluginManager.addInteractor?.("externalTrail", container => {
@@ -10310,7 +10352,7 @@
10310
10352
  }
10311
10353
 
10312
10354
  async function loadRollUpdater(engine) {
10313
- engine.checkVersion("4.2.0");
10355
+ engine.checkVersion("4.2.1");
10314
10356
  await engine.pluginManager.register(e => {
10315
10357
  e.pluginManager.addParticleUpdater("roll", () => {
10316
10358
  return Promise.resolve(new RollUpdater(e.pluginManager));
@@ -10356,7 +10398,7 @@
10356
10398
  }
10357
10399
 
10358
10400
  async function loadBlendPlugin(engine) {
10359
- engine.checkVersion("4.2.0");
10401
+ engine.checkVersion("4.2.1");
10360
10402
  await engine.pluginManager.register(e => {
10361
10403
  e.pluginManager.addPlugin(new BlendPlugin());
10362
10404
  });
@@ -10393,7 +10435,7 @@
10393
10435
  }
10394
10436
 
10395
10437
  async function loadCircleShape(engine) {
10396
- engine.checkVersion("4.2.0");
10438
+ engine.checkVersion("4.2.1");
10397
10439
  await engine.pluginManager.register(e => {
10398
10440
  e.pluginManager.addShape(["circle"], () => {
10399
10441
  return Promise.resolve(new CircleDrawer());
@@ -10441,7 +10483,7 @@
10441
10483
  }
10442
10484
 
10443
10485
  async function loadHexColorPlugin(engine) {
10444
- engine.checkVersion("4.2.0");
10486
+ engine.checkVersion("4.2.1");
10445
10487
  await engine.pluginManager.register(e => {
10446
10488
  e.pluginManager.addColorManager("hex", new HexColorManager());
10447
10489
  });
@@ -10494,7 +10536,7 @@
10494
10536
  }
10495
10537
 
10496
10538
  async function loadHslColorPlugin(engine) {
10497
- engine.checkVersion("4.2.0");
10539
+ engine.checkVersion("4.2.1");
10498
10540
  await engine.pluginManager.register(e => {
10499
10541
  e.pluginManager.addColorManager("hsl", new HslColorManager());
10500
10542
  });
@@ -10698,7 +10740,7 @@
10698
10740
  }
10699
10741
 
10700
10742
  async function loadOpacityUpdater(engine) {
10701
- engine.checkVersion("4.2.0");
10743
+ engine.checkVersion("4.2.1");
10702
10744
  await engine.pluginManager.register(e => {
10703
10745
  e.pluginManager.addParticleUpdater("opacity", container => {
10704
10746
  return Promise.resolve(new OpacityUpdater(container));
@@ -11043,7 +11085,7 @@
11043
11085
  }
11044
11086
 
11045
11087
  async function loadOutModesUpdater(engine) {
11046
- engine.checkVersion("4.2.0");
11088
+ engine.checkVersion("4.2.1");
11047
11089
  await engine.pluginManager.register(e => {
11048
11090
  e.pluginManager.addParticleUpdater("outModes", container => {
11049
11091
  return Promise.resolve(new OutOfCanvasUpdater(container));
@@ -11108,13 +11150,13 @@
11108
11150
  if (!this.isEnabled(particle)) {
11109
11151
  return;
11110
11152
  }
11111
- updateColor(particle.fillColor, delta);
11112
- updateColor(particle.strokeColor, delta);
11153
+ updateColor(particle.fillColor, delta, this.#container.hdr);
11154
+ updateColor(particle.strokeColor, delta, this.#container.hdr);
11113
11155
  }
11114
11156
  }
11115
11157
 
11116
11158
  async function loadPaintUpdater(engine) {
11117
- engine.checkVersion("4.2.0");
11159
+ engine.checkVersion("4.2.1");
11118
11160
  await engine.pluginManager.register(e => {
11119
11161
  e.pluginManager.addParticleUpdater("paint", container => {
11120
11162
  return Promise.resolve(new PaintUpdater(e.pluginManager, container));
@@ -11169,7 +11211,7 @@
11169
11211
  }
11170
11212
 
11171
11213
  async function loadRgbColorPlugin(engine) {
11172
- engine.checkVersion("4.2.0");
11214
+ engine.checkVersion("4.2.1");
11173
11215
  await engine.pluginManager.register(e => {
11174
11216
  e.pluginManager.addColorManager("rgb", new RgbColorManager());
11175
11217
  });
@@ -11254,7 +11296,7 @@
11254
11296
  }
11255
11297
 
11256
11298
  async function loadSizeUpdater(engine) {
11257
- engine.checkVersion("4.2.0");
11299
+ engine.checkVersion("4.2.1");
11258
11300
  await engine.pluginManager.register(e => {
11259
11301
  e.pluginManager.addParticleUpdater("size", container => {
11260
11302
  return Promise.resolve(new SizeUpdater(container));
@@ -11263,7 +11305,7 @@
11263
11305
  }
11264
11306
 
11265
11307
  async function loadBasic(engine) {
11266
- engine.checkVersion("4.2.0");
11308
+ engine.checkVersion("4.2.1");
11267
11309
  await engine.pluginManager.register(async (e) => {
11268
11310
  await Promise.all([
11269
11311
  loadBlendPlugin(e),
@@ -11286,7 +11328,7 @@
11286
11328
  easingsFunctions.set("ease-in-out-quad", value => (value < 0.5 ? 2 * value ** 2 : 1 - (-2 * value + 2) ** 2 / 2));
11287
11329
 
11288
11330
  async function loadEasingQuadPlugin(engine) {
11289
- engine.checkVersion("4.2.0");
11331
+ engine.checkVersion("4.2.1");
11290
11332
  await engine.pluginManager.register(e => {
11291
11333
  for (const [easing, easingFn] of easingsFunctions) {
11292
11334
  e.pluginManager.addEasing(easing, easingFn);
@@ -11380,7 +11422,7 @@
11380
11422
  }
11381
11423
 
11382
11424
  async function loadEmojiShape(engine) {
11383
- engine.checkVersion("4.2.0");
11425
+ engine.checkVersion("4.2.1");
11384
11426
  await engine.pluginManager.register(e => {
11385
11427
  e.pluginManager.addShape(validTypes$1, () => Promise.resolve(new EmojiDrawer()));
11386
11428
  });
@@ -11613,7 +11655,7 @@
11613
11655
  };
11614
11656
 
11615
11657
  async function loadExternalAttractInteraction(engine) {
11616
- engine.checkVersion("4.2.0");
11658
+ engine.checkVersion("4.2.1");
11617
11659
  await engine.pluginManager.register((e) => {
11618
11660
  ensureInteractivityPluginLoaded(e);
11619
11661
  e.pluginManager.addInteractor?.("externalAttract", container => {
@@ -11802,7 +11844,7 @@
11802
11844
  }
11803
11845
 
11804
11846
  async function loadExternalBounceInteraction(engine) {
11805
- engine.checkVersion("4.2.0");
11847
+ engine.checkVersion("4.2.1");
11806
11848
  await engine.pluginManager.register((e) => {
11807
11849
  ensureInteractivityPluginLoaded(e);
11808
11850
  e.pluginManager.addInteractor?.("externalBounce", container => {
@@ -11862,6 +11904,19 @@
11862
11904
  }
11863
11905
  }
11864
11906
 
11907
+ class BubbleModifier {
11908
+ div;
11909
+ enabled = false;
11910
+ fillColor;
11911
+ finalColor;
11912
+ id = "bubble";
11913
+ inRange = false;
11914
+ opacity;
11915
+ priority = 100;
11916
+ radius;
11917
+ strokeColor;
11918
+ }
11919
+
11865
11920
  var ProcessBubbleType;
11866
11921
  (function (ProcessBubbleType) {
11867
11922
  ProcessBubbleType["color"] = "color";
@@ -11885,6 +11940,7 @@
11885
11940
  class Bubbler extends ExternalInteractorBase {
11886
11941
  handleClickMode;
11887
11942
  #maxDistance;
11943
+ #modifiers = new WeakMap();
11888
11944
  #pluginManager;
11889
11945
  constructor(pluginManager, container) {
11890
11946
  super(container);
@@ -11903,13 +11959,21 @@
11903
11959
  return this.#maxDistance;
11904
11960
  }
11905
11961
  clear(particle, _delta, force) {
11906
- if (particle.bubble.inRange && !force) {
11962
+ const mod = this.#modifiers.get(particle);
11963
+ if (mod?.inRange && !force) {
11907
11964
  return;
11908
11965
  }
11909
- delete particle.bubble.div;
11910
- delete particle.bubble.opacity;
11911
- delete particle.bubble.radius;
11912
- delete particle.bubble.color;
11966
+ particle.removeModifier(bubbleMode);
11967
+ this.#modifiers.delete(particle);
11968
+ }
11969
+ getOrCreateModifier(particle) {
11970
+ let mod = this.#modifiers.get(particle);
11971
+ if (!mod) {
11972
+ mod = new BubbleModifier();
11973
+ this.#modifiers.set(particle, mod);
11974
+ particle.addModifier(mod);
11975
+ }
11976
+ return mod;
11913
11977
  }
11914
11978
  init() {
11915
11979
  const container = this.container, bubble = container.actualOptions.interactivity?.modes.bubble;
@@ -11955,7 +12019,11 @@
11955
12019
  loadOptionProperty(options, "bubble", Bubble, ...sources);
11956
12020
  }
11957
12021
  reset(_interactivityData, particle) {
11958
- particle.bubble.inRange = false;
12022
+ const mod = this.#modifiers.get(particle);
12023
+ if (mod) {
12024
+ mod.enabled = false;
12025
+ mod.inRange = false;
12026
+ }
11959
12027
  }
11960
12028
  #clickBubble(interactivityData) {
11961
12029
  const container = this.container, options = container.actualOptions, mouseClickPos = interactivityData.mouse.clickPosition, bubbleOptions = options.interactivity?.modes.bubble;
@@ -11972,7 +12040,9 @@
11972
12040
  if (!bubble.clicking) {
11973
12041
  continue;
11974
12042
  }
11975
- particle.bubble.inRange = !bubble.durationEnd;
12043
+ const mod = this.getOrCreateModifier(particle);
12044
+ mod.enabled = !bubble.durationEnd;
12045
+ mod.inRange = !bubble.durationEnd;
11976
12046
  const pos = particle.getPosition(), distMouse = getDistance(pos, mouseClickPos), timeSpent = (performance.now() - (interactivityData.mouse.clickTime ?? defaultClickTime)) / millisecondsToSeconds$1;
11977
12047
  if (timeSpent > bubbleOptions.duration) {
11978
12048
  bubble.durationEnd = true;
@@ -11984,7 +12054,7 @@
11984
12054
  const sizeData = {
11985
12055
  bubbleObj: {
11986
12056
  optValue: container.retina.bubbleModeSize,
11987
- value: particle.bubble.radius,
12057
+ value: mod.radius,
11988
12058
  },
11989
12059
  particlesObj: {
11990
12060
  optValue: particle.size.max,
@@ -11996,7 +12066,7 @@
11996
12066
  const opacityData = {
11997
12067
  bubbleObj: {
11998
12068
  optValue: bubbleOptions.opacity,
11999
- value: particle.bubble.opacity,
12069
+ value: mod.opacity,
12000
12070
  },
12001
12071
  particlesObj: {
12002
12072
  optValue: particle.opacity?.max ?? defaultOpacity$1,
@@ -12009,7 +12079,8 @@
12009
12079
  this.#hoverBubbleColor(particle, distMouse);
12010
12080
  }
12011
12081
  else {
12012
- delete particle.bubble.color;
12082
+ mod.fillColor = undefined;
12083
+ mod.strokeColor = undefined;
12013
12084
  }
12014
12085
  }
12015
12086
  }
@@ -12020,7 +12091,9 @@
12020
12091
  }
12021
12092
  const query = container.particles.grid.queryCircle(mousePos, distance, p => this.isEnabled(interactivityData, p));
12022
12093
  for (const particle of query) {
12023
- particle.bubble.inRange = true;
12094
+ const mod = this.getOrCreateModifier(particle);
12095
+ mod.enabled = true;
12096
+ mod.inRange = true;
12024
12097
  const pos = particle.getPosition(), pointDistance = getDistance(pos, mousePos), ratio = ratioOffset - pointDistance / distance;
12025
12098
  if (pointDistance <= distance) {
12026
12099
  if (ratio >= minRatio && interactivityData.status === mouseMoveEvent) {
@@ -12038,30 +12111,38 @@
12038
12111
  }
12039
12112
  }
12040
12113
  #hoverBubbleColor(particle, ratio, divBubble) {
12041
- const options = this.container.actualOptions, bubbleOptions = divBubble ?? options.interactivity?.modes.bubble;
12114
+ const options = this.container.actualOptions, bubbleOptions = divBubble ?? options.interactivity?.modes.bubble, mod = this.getOrCreateModifier(particle);
12042
12115
  if (!bubbleOptions) {
12043
12116
  return;
12044
12117
  }
12045
- if (!particle.bubble.finalColor) {
12118
+ if (!mod.finalColor) {
12046
12119
  const modeColor = bubbleOptions.color;
12047
12120
  if (!modeColor) {
12048
12121
  return;
12049
12122
  }
12050
12123
  const bubbleColor = itemFromSingleOrMultiple(modeColor);
12051
- particle.bubble.finalColor = rangeColorToHsl(this.#pluginManager, bubbleColor);
12124
+ mod.finalColor = rangeColorToHsl(this.#pluginManager, bubbleColor);
12052
12125
  }
12053
- if (!particle.bubble.finalColor) {
12126
+ if (!mod.finalColor) {
12054
12127
  return;
12055
12128
  }
12056
12129
  if (bubbleOptions.mix) {
12057
- particle.bubble.color = undefined;
12130
+ mod.fillColor = undefined;
12131
+ mod.strokeColor = undefined;
12058
12132
  const pColor = particle.getFillColor();
12059
- particle.bubble.color = pColor
12060
- ? rgbToHsl(colorMix(pColor, particle.bubble.finalColor, ratioOffset - ratio, ratio))
12061
- : particle.bubble.finalColor;
12133
+ if (pColor) {
12134
+ const mixedColor = rgbToHsl(colorMix(pColor, mod.finalColor, ratioOffset - ratio, ratio));
12135
+ mod.fillColor = mixedColor;
12136
+ mod.strokeColor = mixedColor;
12137
+ }
12138
+ else {
12139
+ mod.fillColor = mod.finalColor;
12140
+ mod.strokeColor = mod.finalColor;
12141
+ }
12062
12142
  }
12063
12143
  else {
12064
- particle.bubble.color = particle.bubble.finalColor;
12144
+ mod.fillColor = mod.finalColor;
12145
+ mod.strokeColor = mod.finalColor;
12065
12146
  }
12066
12147
  }
12067
12148
  #hoverBubbleOpacity(particle, ratio, divBubble) {
@@ -12071,7 +12152,8 @@
12071
12152
  }
12072
12153
  const pOpacity = particle.opacity?.value ?? defaultOpacity$1, opacity = calculateBubbleValue(pOpacity, modeOpacity, particle.opacity?.max ?? defaultOpacity$1, ratio);
12073
12154
  if (opacity !== undefined) {
12074
- particle.bubble.opacity = opacity;
12155
+ const mod = this.getOrCreateModifier(particle);
12156
+ mod.opacity = opacity;
12075
12157
  }
12076
12158
  }
12077
12159
  #hoverBubbleSize(particle, ratio, divBubble) {
@@ -12081,7 +12163,8 @@
12081
12163
  }
12082
12164
  const pSize = particle.size.value, size = calculateBubbleValue(pSize, modeSize, particle.size.max, ratio);
12083
12165
  if (size !== undefined) {
12084
- particle.bubble.radius = size;
12166
+ const mod = this.getOrCreateModifier(particle);
12167
+ mod.radius = size;
12085
12168
  }
12086
12169
  }
12087
12170
  #process(particle, distMouse, timeSpent, data) {
@@ -12094,13 +12177,14 @@
12094
12177
  return;
12095
12178
  }
12096
12179
  container.bubble ??= {};
12180
+ const mod = this.getOrCreateModifier(particle);
12097
12181
  if (container.bubble.durationEnd) {
12098
12182
  if (pObjBubble) {
12099
12183
  if (type === ProcessBubbleType.size) {
12100
- delete particle.bubble.radius;
12184
+ mod.radius = undefined;
12101
12185
  }
12102
12186
  if (type === ProcessBubbleType.opacity) {
12103
- delete particle.bubble.opacity;
12187
+ mod.opacity = undefined;
12104
12188
  }
12105
12189
  }
12106
12190
  }
@@ -12110,19 +12194,19 @@
12110
12194
  if (obj !== bubbleParam) {
12111
12195
  const value = pObj - (timeSpent * (pObj - bubbleParam)) / bubbleDuration;
12112
12196
  if (type === ProcessBubbleType.size) {
12113
- particle.bubble.radius = value;
12197
+ mod.radius = value;
12114
12198
  }
12115
12199
  if (type === ProcessBubbleType.opacity) {
12116
- particle.bubble.opacity = value;
12200
+ mod.opacity = value;
12117
12201
  }
12118
12202
  }
12119
12203
  }
12120
12204
  else {
12121
12205
  if (type === ProcessBubbleType.size) {
12122
- delete particle.bubble.radius;
12206
+ mod.radius = undefined;
12123
12207
  }
12124
12208
  if (type === ProcessBubbleType.opacity) {
12125
- delete particle.bubble.opacity;
12209
+ mod.opacity = undefined;
12126
12210
  }
12127
12211
  }
12128
12212
  }
@@ -12143,11 +12227,13 @@
12143
12227
  if (!area.contains(particle.getPosition())) {
12144
12228
  continue;
12145
12229
  }
12146
- particle.bubble.inRange = true;
12230
+ const mod = this.getOrCreateModifier(particle);
12231
+ mod.enabled = true;
12232
+ mod.inRange = true;
12147
12233
  const divs = bubble.divs, divBubble = divMode(divs, elem);
12148
- if (!particle.bubble.div || particle.bubble.div !== elem) {
12234
+ if (!mod.div || mod.div !== elem) {
12149
12235
  this.clear(particle, delta, true);
12150
- particle.bubble.div = elem;
12236
+ mod.div = elem;
12151
12237
  }
12152
12238
  this.#hoverBubbleSize(particle, defaultRatio, divBubble);
12153
12239
  this.#hoverBubbleOpacity(particle, defaultRatio, divBubble);
@@ -12158,7 +12244,7 @@
12158
12244
  }
12159
12245
 
12160
12246
  async function loadExternalBubbleInteraction(engine) {
12161
- engine.checkVersion("4.2.0");
12247
+ engine.checkVersion("4.2.1");
12162
12248
  await engine.pluginManager.register((e) => {
12163
12249
  ensureInteractivityPluginLoaded(e);
12164
12250
  e.pluginManager.addInteractor?.("externalBubble", container => {
@@ -12286,7 +12372,7 @@
12286
12372
  }
12287
12373
 
12288
12374
  async function loadExternalConnectInteraction(engine) {
12289
- engine.checkVersion("4.2.0");
12375
+ engine.checkVersion("4.2.1");
12290
12376
  await engine.pluginManager.register((e) => {
12291
12377
  ensureInteractivityPluginLoaded(e);
12292
12378
  e.pluginManager.addInteractor?.("externalConnect", container => {
@@ -12390,7 +12476,7 @@
12390
12476
  }
12391
12477
 
12392
12478
  async function loadExternalDestroyInteraction(engine) {
12393
- engine.checkVersion("4.2.0");
12479
+ engine.checkVersion("4.2.1");
12394
12480
  await engine.pluginManager.register((e) => {
12395
12481
  ensureInteractivityPluginLoaded(e);
12396
12482
  e.pluginManager.addInteractor?.("externalDestroy", async (container) => {
@@ -12514,7 +12600,7 @@
12514
12600
  }
12515
12601
 
12516
12602
  async function loadExternalGrabInteraction(engine) {
12517
- engine.checkVersion("4.2.0");
12603
+ engine.checkVersion("4.2.1");
12518
12604
  await engine.pluginManager.register((e) => {
12519
12605
  ensureInteractivityPluginLoaded(e);
12520
12606
  e.pluginManager.addInteractor?.("externalGrab", container => {
@@ -12584,7 +12670,7 @@
12584
12670
  }
12585
12671
 
12586
12672
  async function loadExternalParallaxInteraction(engine) {
12587
- engine.checkVersion("4.2.0");
12673
+ engine.checkVersion("4.2.1");
12588
12674
  await engine.pluginManager.register((e) => {
12589
12675
  ensureInteractivityPluginLoaded(e);
12590
12676
  e.pluginManager.addInteractor?.("externalParallax", container => {
@@ -12627,7 +12713,7 @@
12627
12713
  }
12628
12714
 
12629
12715
  async function loadExternalPauseInteraction(engine) {
12630
- engine.checkVersion("4.2.0");
12716
+ engine.checkVersion("4.2.1");
12631
12717
  await engine.pluginManager.register((e) => {
12632
12718
  ensureInteractivityPluginLoaded(e);
12633
12719
  e.pluginManager.addInteractor?.("externalPause", container => {
@@ -12699,7 +12785,7 @@
12699
12785
  }
12700
12786
 
12701
12787
  async function loadExternalPushInteraction(engine) {
12702
- engine.checkVersion("4.2.0");
12788
+ engine.checkVersion("4.2.1");
12703
12789
  await engine.pluginManager.register((e) => {
12704
12790
  ensureInteractivityPluginLoaded(e);
12705
12791
  e.pluginManager.addInteractor?.("externalPush", container => {
@@ -12753,7 +12839,7 @@
12753
12839
  }
12754
12840
 
12755
12841
  async function loadExternalRemoveInteraction(engine) {
12756
- engine.checkVersion("4.2.0");
12842
+ engine.checkVersion("4.2.1");
12757
12843
  await engine.pluginManager.register((e) => {
12758
12844
  ensureInteractivityPluginLoaded(e);
12759
12845
  e.pluginManager.addInteractor?.("externalRemove", container => {
@@ -13059,7 +13145,7 @@
13059
13145
  };
13060
13146
 
13061
13147
  async function loadExternalRepulseInteraction(engine) {
13062
- engine.checkVersion("4.2.0");
13148
+ engine.checkVersion("4.2.1");
13063
13149
  await engine.pluginManager.register((e) => {
13064
13150
  ensureInteractivityPluginLoaded(e);
13065
13151
  const pluginManager = e.pluginManager;
@@ -13081,9 +13167,17 @@
13081
13167
  }
13082
13168
  }
13083
13169
 
13170
+ class SlowModifier {
13171
+ enabled = false;
13172
+ id = "slow";
13173
+ priority = 100;
13174
+ speedFactor = 1;
13175
+ }
13176
+
13084
13177
  const slowMode = "slow", minRadius$3 = 0;
13085
13178
  class Slower extends ExternalInteractorBase {
13086
13179
  #maxDistance;
13180
+ #modifiers = new WeakMap();
13087
13181
  constructor(container) {
13088
13182
  super(container);
13089
13183
  this.#maxDistance = 0;
@@ -13092,10 +13186,21 @@
13092
13186
  return this.#maxDistance;
13093
13187
  }
13094
13188
  clear(particle, _delta, force) {
13095
- if (particle.slow.inRange && !force) {
13189
+ const mod = this.#modifiers.get(particle);
13190
+ if (mod?.enabled && !force) {
13096
13191
  return;
13097
13192
  }
13098
- particle.slow.factor = 1;
13193
+ particle.removeModifier(slowMode);
13194
+ this.#modifiers.delete(particle);
13195
+ }
13196
+ getOrCreateModifier(particle) {
13197
+ let mod = this.#modifiers.get(particle);
13198
+ if (!mod) {
13199
+ mod = new SlowModifier();
13200
+ this.#modifiers.set(particle, mod);
13201
+ particle.addModifier(mod);
13202
+ }
13203
+ return mod;
13099
13204
  }
13100
13205
  init() {
13101
13206
  const container = this.container, slow = container.actualOptions.interactivity?.modes.slow;
@@ -13115,22 +13220,26 @@
13115
13220
  loadOptionProperty(options, "slow", Slow, ...sources);
13116
13221
  }
13117
13222
  reset(interactivityData, particle) {
13118
- particle.slow.inRange = false;
13223
+ const mod = this.#modifiers.get(particle);
13224
+ if (mod) {
13225
+ mod.enabled = false;
13226
+ }
13119
13227
  const container = this.container, options = container.actualOptions, mousePos = interactivityData.mouse.position, radius = container.retina.slowModeRadius, slowOptions = options.interactivity?.modes.slow;
13120
13228
  if (!slowOptions || !radius || radius < minRadius$3 || !mousePos) {
13121
13229
  return;
13122
13230
  }
13123
- const particlePos = particle.getPosition(), dist = getDistance(mousePos, particlePos), proximityFactor = dist / radius, slowFactor = slowOptions.factor, { slow } = particle;
13231
+ const particlePos = particle.getPosition(), dist = getDistance(mousePos, particlePos), proximityFactor = dist / radius, slowFactor = slowOptions.factor;
13124
13232
  if (dist > radius) {
13125
13233
  return;
13126
13234
  }
13127
- slow.inRange = true;
13128
- slow.factor = proximityFactor / slowFactor;
13235
+ const activeMod = this.getOrCreateModifier(particle);
13236
+ activeMod.enabled = true;
13237
+ activeMod.speedFactor = proximityFactor / slowFactor;
13129
13238
  }
13130
13239
  }
13131
13240
 
13132
13241
  async function loadExternalSlowInteraction(engine) {
13133
- engine.checkVersion("4.2.0");
13242
+ engine.checkVersion("4.2.1");
13134
13243
  await engine.pluginManager.register((e) => {
13135
13244
  ensureInteractivityPluginLoaded(e);
13136
13245
  e.pluginManager.addInteractor?.("externalSlow", container => {
@@ -13192,7 +13301,6 @@
13192
13301
  function replaceImageColor(image, imageData, color, particle, hdr = false) {
13193
13302
  const svgColoredData = replaceColorSvg(image, color, particle.opacity?.value ?? defaultOpacity, hdr), imageRes = {
13194
13303
  color,
13195
- gif: imageData.gif,
13196
13304
  data: {
13197
13305
  ...image,
13198
13306
  svgData: svgColoredData,
@@ -13227,982 +13335,480 @@
13227
13335
  });
13228
13336
  }
13229
13337
 
13230
- const InterlaceOffsets = [0, 4, 2, 1];
13231
- const InterlaceSteps = [8, 8, 4, 2];
13232
-
13233
- class ByteStream {
13234
- data;
13235
- pos;
13236
- constructor(bytes) {
13237
- this.pos = 0;
13238
- this.data = new Uint8ClampedArray(bytes);
13239
- }
13240
- getString(count) {
13241
- const slice = this.data.slice(this.pos, this.pos + count);
13242
- this.pos += slice.length;
13243
- return slice.reduce((acc, curr) => acc + String.fromCharCode(curr), "");
13244
- }
13245
- nextByte() {
13246
- return this.data[this.pos++];
13338
+ const sides$3 = 12;
13339
+ class ImageDrawer {
13340
+ #container;
13341
+ #engine;
13342
+ constructor(engine, container) {
13343
+ this.#engine = engine;
13344
+ this.#container = container;
13247
13345
  }
13248
- nextTwoBytes() {
13249
- const increment = 2, previous = 1, shift = 8;
13250
- this.pos += increment;
13251
- return this.data[this.pos - increment] + (this.data[this.pos - previous] << shift);
13346
+ draw(data) {
13347
+ const { context, radius, particle, opacity } = data, image = particle.image, element = image?.element;
13348
+ if (!image) {
13349
+ return;
13350
+ }
13351
+ context.globalAlpha = opacity;
13352
+ if (element) {
13353
+ const ratio = image.ratio, pos = {
13354
+ x: -radius,
13355
+ y: -radius,
13356
+ }, diameter = radius * double;
13357
+ context.drawImage(element, pos.x, pos.y, diameter, diameter / ratio);
13358
+ }
13359
+ context.globalAlpha = defaultAlpha$1;
13252
13360
  }
13253
- readSubBlocks() {
13254
- let blockString = "", size;
13255
- const minCount = 0, emptySize = 0;
13256
- do {
13257
- size = this.data[this.pos++];
13258
- for (let count = size; --count >= minCount; blockString += String.fromCharCode(this.data[this.pos++])) {
13259
- }
13260
- } while (size !== emptySize);
13261
- return blockString;
13361
+ getSidesCount() {
13362
+ return sides$3;
13262
13363
  }
13263
- readSubBlocksBin() {
13264
- let size = this.data[this.pos], len = 0;
13265
- const emptySize = 0, increment = 1;
13266
- for (let offset = 0; size !== emptySize; offset += size + increment, size = this.data[this.pos + offset]) {
13267
- len += size;
13364
+ async init(container) {
13365
+ const options = container.actualOptions;
13366
+ if (!options.preload || !this.#engine.loadImage) {
13367
+ return;
13268
13368
  }
13269
- const blockData = new Uint8Array(len);
13270
- size = this.data[this.pos++];
13271
- for (let i = 0; size !== emptySize; size = this.data[this.pos++]) {
13272
- for (let count = size; --count >= emptySize; blockData[i++] = this.data[this.pos++]) {
13273
- }
13369
+ const promises = [];
13370
+ for (const imageData of options.preload) {
13371
+ promises.push(this.#engine.loadImage(container, imageData));
13274
13372
  }
13275
- return blockData;
13373
+ await Promise.all(promises);
13276
13374
  }
13277
- skipSubBlocks() {
13278
- for (const increment = 1, noData = 0; this.data[this.pos] !== noData; this.pos += this.data[this.pos] + increment) {
13375
+ loadShape(particle) {
13376
+ const container = this.#container;
13377
+ if (!particle.shape || !shapeTypes.includes(particle.shape)) {
13378
+ return;
13279
13379
  }
13280
- this.pos++;
13281
- }
13282
- }
13283
-
13284
- var DisposalMethod;
13285
- (function (DisposalMethod) {
13286
- DisposalMethod[DisposalMethod["Replace"] = 0] = "Replace";
13287
- DisposalMethod[DisposalMethod["Combine"] = 1] = "Combine";
13288
- DisposalMethod[DisposalMethod["RestoreBackground"] = 2] = "RestoreBackground";
13289
- DisposalMethod[DisposalMethod["RestorePrevious"] = 3] = "RestorePrevious";
13290
- DisposalMethod[DisposalMethod["UndefinedA"] = 4] = "UndefinedA";
13291
- DisposalMethod[DisposalMethod["UndefinedB"] = 5] = "UndefinedB";
13292
- DisposalMethod[DisposalMethod["UndefinedC"] = 6] = "UndefinedC";
13293
- DisposalMethod[DisposalMethod["UndefinedD"] = 7] = "UndefinedD";
13294
- })(DisposalMethod || (DisposalMethod = {}));
13295
-
13296
- var GIFDataHeaders;
13297
- (function (GIFDataHeaders) {
13298
- GIFDataHeaders[GIFDataHeaders["Extension"] = 33] = "Extension";
13299
- GIFDataHeaders[GIFDataHeaders["ApplicationExtension"] = 255] = "ApplicationExtension";
13300
- GIFDataHeaders[GIFDataHeaders["GraphicsControlExtension"] = 249] = "GraphicsControlExtension";
13301
- GIFDataHeaders[GIFDataHeaders["PlainTextExtension"] = 1] = "PlainTextExtension";
13302
- GIFDataHeaders[GIFDataHeaders["CommentExtension"] = 254] = "CommentExtension";
13303
- GIFDataHeaders[GIFDataHeaders["Image"] = 44] = "Image";
13304
- GIFDataHeaders[GIFDataHeaders["EndOfFile"] = 59] = "EndOfFile";
13305
- })(GIFDataHeaders || (GIFDataHeaders = {}));
13306
-
13307
- const defaultFrame = 0, initialTime = 0, firstIndex$3 = 0, defaultLoopCount = 0;
13308
- function parseColorTable(byteStream, count) {
13309
- const colors = [];
13310
- for (let i = 0; i < count; i++) {
13311
- colors.push({
13312
- r: byteStream.data[byteStream.pos],
13313
- g: byteStream.data[byteStream.pos + 1],
13314
- b: byteStream.data[byteStream.pos + 2],
13380
+ const imageData = particle.shapeData;
13381
+ if (!imageData) {
13382
+ return;
13383
+ }
13384
+ const images = this.#engine.getImages?.(container), image = images?.find((t) => t.name === imageData.name || t.source === imageData.src);
13385
+ if (image) {
13386
+ return;
13387
+ }
13388
+ void this.#loadImageShape(container, imageData).then(() => {
13389
+ this.loadShape(particle);
13315
13390
  });
13316
- byteStream.pos += 3;
13317
13391
  }
13318
- return colors;
13319
- }
13320
- function parseExtensionBlock(byteStream, gif, getFrameIndex, getTransparencyIndex) {
13321
- switch (byteStream.nextByte()) {
13322
- case GIFDataHeaders.GraphicsControlExtension: {
13323
- const frame = gif.frames[getFrameIndex(false)];
13324
- byteStream.pos++;
13325
- const packedByte = byteStream.nextByte();
13326
- frame.GCreserved = (packedByte & 0xe0) >>> 5;
13327
- frame.disposalMethod = (packedByte & 0x1c) >>> 2;
13328
- frame.userInputDelayFlag = (packedByte & 2) === 2;
13329
- const transparencyFlag = (packedByte & 1) === 1;
13330
- frame.delayTime = byteStream.nextTwoBytes() * 0xa;
13331
- const transparencyIndex = byteStream.nextByte();
13332
- if (transparencyFlag) {
13333
- getTransparencyIndex(transparencyIndex);
13334
- }
13335
- byteStream.pos++;
13336
- break;
13392
+ particleInit(container, particle) {
13393
+ if (particle.shape !== "image" && particle.shape !== "images") {
13394
+ return;
13337
13395
  }
13338
- case GIFDataHeaders.ApplicationExtension: {
13339
- byteStream.pos++;
13340
- const applicationExtension = {
13341
- identifier: byteStream.getString(8),
13342
- authenticationCode: byteStream.getString(3),
13343
- data: byteStream.readSubBlocksBin(),
13344
- };
13345
- gif.applicationExtensions.push(applicationExtension);
13346
- break;
13396
+ const images = this.#engine.getImages?.(container), imageData = particle.shapeData;
13397
+ if (!imageData) {
13398
+ return;
13347
13399
  }
13348
- case GIFDataHeaders.CommentExtension: {
13349
- gif.comments.push([getFrameIndex(false), byteStream.readSubBlocks()]);
13350
- break;
13400
+ const color = particle.getFillColor(), image = images?.find((t) => t.name === imageData.name || t.source === imageData.src);
13401
+ if (!image) {
13402
+ return;
13351
13403
  }
13352
- case GIFDataHeaders.PlainTextExtension: {
13353
- if (gif.globalColorTable.length === 0) {
13354
- throw new EvalError("plain text extension without global color table");
13404
+ const replaceColor = imageData.replaceColor;
13405
+ if (image.loading) {
13406
+ setTimeout(() => {
13407
+ this.particleInit(container, particle);
13408
+ });
13409
+ return;
13410
+ }
13411
+ void (async () => {
13412
+ let imageRes;
13413
+ if (image.svgData && color) {
13414
+ imageRes = await replaceImageColor(image, imageData, color, particle, container.hdr);
13355
13415
  }
13356
- byteStream.pos++;
13357
- gif.frames[getFrameIndex(false)].plainTextData = {
13358
- left: byteStream.nextTwoBytes(),
13359
- top: byteStream.nextTwoBytes(),
13360
- width: byteStream.nextTwoBytes(),
13361
- height: byteStream.nextTwoBytes(),
13362
- charSize: {
13363
- width: byteStream.nextTwoBytes(),
13364
- height: byteStream.nextTwoBytes(),
13365
- },
13366
- foregroundColor: byteStream.nextByte(),
13367
- backgroundColor: byteStream.nextByte(),
13368
- text: byteStream.readSubBlocks(),
13416
+ else {
13417
+ imageRes = {
13418
+ color,
13419
+ data: image,
13420
+ element: image.element,
13421
+ loaded: true,
13422
+ ratio: imageData.width && imageData.height ? imageData.width / imageData.height : (image.ratio ?? defaultRatio$1),
13423
+ replaceColor: replaceColor,
13424
+ source: imageData.src,
13425
+ };
13426
+ }
13427
+ if (!imageRes.ratio) {
13428
+ imageRes.ratio = 1;
13429
+ }
13430
+ const close = imageData.close ?? particle.shapeClose, imageShape = {
13431
+ image: imageRes,
13432
+ close,
13369
13433
  };
13370
- break;
13371
- }
13372
- default:
13373
- byteStream.skipSubBlocks();
13374
- break;
13434
+ particle.image = imageShape.image;
13435
+ particle.shapeClose = imageShape.close;
13436
+ })();
13375
13437
  }
13438
+ #loadImageShape = async (container, imageShape) => {
13439
+ if (!this.#engine.loadImage) {
13440
+ throw new Error(`Image shape not initialized`);
13441
+ }
13442
+ await this.#engine.loadImage(container, {
13443
+ name: imageShape.name,
13444
+ replaceColor: imageShape.replaceColor,
13445
+ src: imageShape.src,
13446
+ });
13447
+ };
13376
13448
  }
13377
- function readBits(imageData, pos, len) {
13378
- const bytePos = pos >>> 3, bitPos = pos & 7;
13379
- return (((imageData[bytePos] + (imageData[bytePos + 1] << 8) + (imageData[bytePos + 2] << 16)) &
13380
- (((1 << len) - 1) << bitPos)) >>>
13381
- bitPos);
13382
- }
13383
- async function parseImageBlock(byteStream, gif, avgAlpha, getFrameIndex, getTransparencyIndex, canvasSettings, progressCallback) {
13384
- const frame = gif.frames[getFrameIndex(true)];
13385
- frame.left = byteStream.nextTwoBytes();
13386
- frame.top = byteStream.nextTwoBytes();
13387
- frame.width = byteStream.nextTwoBytes();
13388
- frame.height = byteStream.nextTwoBytes();
13389
- const packedByte = byteStream.nextByte(), localColorTableFlag = (packedByte & 0x80) === 0x80, interlacedFlag = (packedByte & 0x40) === 0x40;
13390
- frame.sortFlag = (packedByte & 0x20) === 0x20;
13391
- frame.reserved = (packedByte & 0x18) >>> 3;
13392
- const localColorCount = 1 << ((packedByte & 7) + 1);
13393
- if (localColorTableFlag) {
13394
- frame.localColorTable = parseColorTable(byteStream, localColorCount);
13395
- }
13396
- const getColor = (index) => {
13397
- const { r, g, b } = (localColorTableFlag ? frame.localColorTable : gif.globalColorTable)[index];
13398
- if (index !== getTransparencyIndex(null)) {
13399
- return { r, g, b, a: 255 };
13449
+
13450
+ class Preload {
13451
+ height;
13452
+ name;
13453
+ replaceColor;
13454
+ src = "";
13455
+ width;
13456
+ load(data) {
13457
+ if (isNull(data)) {
13458
+ return;
13400
13459
  }
13401
- return { r, g, b, a: avgAlpha ? Math.trunc((r + g + b) / 3) : 0 };
13402
- }, image = (() => {
13403
- try {
13404
- return new ImageData(frame.width, frame.height, canvasSettings);
13460
+ loadProperty(this, "height", data.height);
13461
+ loadProperty(this, "name", data.name);
13462
+ loadProperty(this, "replaceColor", data.replaceColor);
13463
+ loadProperty(this, "src", data.src);
13464
+ loadProperty(this, "width", data.width);
13465
+ }
13466
+ }
13467
+
13468
+ class ImagePreloaderPlugin {
13469
+ id = "image-preloader";
13470
+ #engine;
13471
+ constructor(engine) {
13472
+ this.#engine = engine;
13473
+ }
13474
+ async getPlugin(container) {
13475
+ const { ImagePreloaderInstance } = await Promise.resolve().then(function () { return ImagePreloaderInstance$1; });
13476
+ return new ImagePreloaderInstance(this.#engine, container);
13477
+ }
13478
+ loadOptions(_container, options, source) {
13479
+ if (!source?.preload) {
13480
+ return;
13405
13481
  }
13406
- catch (error) {
13407
- if (error instanceof DOMException && error.name === "IndexSizeError") {
13408
- return null;
13482
+ options.preload ??= [];
13483
+ const preloadOptions = options.preload;
13484
+ for (const item of source.preload) {
13485
+ const existing = preloadOptions.find(t => t.name === item.name || t.src === item.src);
13486
+ if (existing) {
13487
+ existing.load(item);
13409
13488
  }
13410
- throw error;
13411
- }
13412
- })();
13413
- if (image == null) {
13414
- throw new EvalError("GIF frame size is to large");
13415
- }
13416
- const minCodeSize = byteStream.nextByte(), imageData = byteStream.readSubBlocksBin(), clearCode = 1 << minCodeSize;
13417
- if (interlacedFlag) {
13418
- for (let code = 0, size = minCodeSize + 1, pos = 0, dic = [[0]], pass = 0; pass < 4; pass++) {
13419
- if (InterlaceOffsets[pass] < frame.height) {
13420
- let pixelPos = 0, lineIndex = 0, exit = false;
13421
- while (!exit) {
13422
- const last = code;
13423
- code = readBits(imageData, pos, size);
13424
- pos += size + 1;
13425
- if (code === clearCode) {
13426
- size = minCodeSize + 1;
13427
- dic.length = clearCode + 2;
13428
- for (let i = 0; i < dic.length; i++) {
13429
- dic[i] = i < clearCode ? [i] : [];
13430
- }
13431
- }
13432
- else {
13433
- if (code >= dic.length) {
13434
- dic.push(dic[last].concat(dic[last][0]));
13435
- }
13436
- else if (last !== clearCode) {
13437
- dic.push(dic[last].concat(dic[code][0]));
13438
- }
13439
- for (const item of dic[code]) {
13440
- const { r, g, b, a } = getColor(item);
13441
- image.data.set([r, g, b, a], InterlaceOffsets[pass] * frame.width +
13442
- InterlaceSteps[pass] * lineIndex +
13443
- (pixelPos % (frame.width * 4)));
13444
- pixelPos += 4;
13445
- }
13446
- if (dic.length === 1 << size && size < 0xc) {
13447
- size++;
13448
- }
13449
- }
13450
- if (pixelPos === frame.width * 4 * (lineIndex + 1)) {
13451
- lineIndex++;
13452
- if (InterlaceOffsets[pass] + InterlaceSteps[pass] * lineIndex >= frame.height) {
13453
- exit = true;
13454
- }
13455
- }
13456
- }
13489
+ else {
13490
+ const preload = new Preload();
13491
+ preload.load(item);
13492
+ preloadOptions.push(preload);
13457
13493
  }
13458
13494
  }
13459
- frame.image = image;
13460
- frame.bitmap = await createImageBitmap(image);
13461
13495
  }
13462
- else {
13463
- let code = 0, size = minCodeSize + 1, pos = 0, pixelPos = -4;
13464
- const dic = [[0]];
13465
- for (;;) {
13466
- const last = code;
13467
- code = readBits(imageData, pos, size);
13468
- pos += size;
13469
- if (code === clearCode) {
13470
- size = minCodeSize + 1;
13471
- dic.length = clearCode + 2;
13472
- for (let i = 0; i < dic.length; i++) {
13473
- dic[i] = i < clearCode ? [i] : [];
13474
- }
13496
+ needsPlugin() {
13497
+ return true;
13498
+ }
13499
+ }
13500
+
13501
+ const extLength = 3;
13502
+ function addLoadImageToEngine(engine) {
13503
+ engine.getImages ??= (container) => {
13504
+ engine.images ??= new Map();
13505
+ let images = engine.images.get(container);
13506
+ if (!images) {
13507
+ images = [];
13508
+ engine.images.set(container, images);
13509
+ }
13510
+ return images;
13511
+ };
13512
+ engine.loadImage ??= async (container, data) => {
13513
+ if (!engine.getImages) {
13514
+ throw new Error("No images collection found");
13515
+ }
13516
+ if (!data.name && !data.src) {
13517
+ throw new Error("No image source provided");
13518
+ }
13519
+ engine.images ??= new Map();
13520
+ const containerImages = engine.getImages(container);
13521
+ if (containerImages.some((t) => t.name === data.name || t.source === data.src)) {
13522
+ return;
13523
+ }
13524
+ try {
13525
+ const image = {
13526
+ name: data.name ?? data.src,
13527
+ source: data.src,
13528
+ type: data.src.substring(data.src.length - extLength),
13529
+ error: false,
13530
+ loading: true,
13531
+ replaceColor: data.replaceColor,
13532
+ ratio: data.width && data.height ? data.width / data.height : undefined,
13533
+ };
13534
+ containerImages.push(image);
13535
+ engine.images.set(container, containerImages);
13536
+ let imageFunc;
13537
+ if (data.replaceColor) {
13538
+ imageFunc = downloadSvgImage;
13475
13539
  }
13476
13540
  else {
13477
- if (code === clearCode + 1) {
13478
- break;
13479
- }
13480
- if (code >= dic.length) {
13481
- dic.push(dic[last].concat(dic[last][0]));
13482
- }
13483
- else if (last !== clearCode) {
13484
- dic.push(dic[last].concat(dic[code][0]));
13485
- }
13486
- for (const item of dic[code]) {
13487
- const { r, g, b, a } = getColor(item);
13488
- pixelPos += 4;
13489
- image.data.set([r, g, b, a], pixelPos);
13490
- }
13491
- if (dic.length >= 1 << size && size < 0xc) {
13492
- size++;
13493
- }
13541
+ imageFunc = loadImage;
13494
13542
  }
13543
+ await imageFunc(image);
13495
13544
  }
13496
- frame.image = image;
13497
- frame.bitmap = await createImageBitmap(image);
13498
- }
13545
+ catch {
13546
+ throw new Error(`${data.name ?? data.src} not found`);
13547
+ }
13548
+ };
13499
13549
  }
13500
- async function parseBlock(byteStream, gif, avgAlpha, getFrameIndex, getTransparencyIndex, canvasSettings, progressCallback) {
13501
- switch (byteStream.nextByte()) {
13502
- case GIFDataHeaders.EndOfFile:
13503
- return true;
13504
- case GIFDataHeaders.Image:
13505
- await parseImageBlock(byteStream, gif, avgAlpha, getFrameIndex, getTransparencyIndex, canvasSettings);
13506
- break;
13507
- case GIFDataHeaders.Extension:
13508
- parseExtensionBlock(byteStream, gif, getFrameIndex, getTransparencyIndex);
13509
- break;
13510
- default:
13511
- throw new EvalError("undefined block found");
13512
- }
13513
- return false;
13550
+ async function loadImageShape(engine) {
13551
+ engine.checkVersion("4.2.1");
13552
+ await engine.pluginManager.register(e => {
13553
+ addLoadImageToEngine(e);
13554
+ e.pluginManager.addPlugin(new ImagePreloaderPlugin(e));
13555
+ e.pluginManager.addShape(shapeTypes, container => Promise.resolve(new ImageDrawer(e, container)));
13556
+ });
13514
13557
  }
13515
- function getGIFLoopAmount(gif) {
13516
- for (const extension of gif.applicationExtensions) {
13517
- if (extension.identifier + extension.authenticationCode !== "NETSCAPE2.0") {
13518
- continue;
13558
+
13559
+ class LifeDelay extends ValueWithRandom {
13560
+ sync = false;
13561
+ load(data) {
13562
+ if (isNull(data)) {
13563
+ return;
13519
13564
  }
13520
- return extension.data[1] + (extension.data[2] << 8);
13565
+ super.load(data);
13566
+ loadProperty(this, "sync", data.sync);
13521
13567
  }
13522
- return Number.NaN;
13523
13568
  }
13524
- async function decodeGIF(gifURL, canvasSettings, progressCallback, avgAlpha) {
13525
- avgAlpha ??= false;
13526
- const res = await fetch(gifURL);
13527
- if (!res.ok && res.status === 404) {
13528
- throw new EvalError("file not found");
13569
+
13570
+ class LifeDuration extends ValueWithRandom {
13571
+ sync = false;
13572
+ load(data) {
13573
+ if (isNull(data)) {
13574
+ return;
13575
+ }
13576
+ super.load(data);
13577
+ loadProperty(this, "sync", data.sync);
13529
13578
  }
13530
- const buffer = await res.arrayBuffer(), gif = {
13531
- width: 0,
13532
- height: 0,
13533
- totalTime: 0,
13534
- colorRes: 0,
13535
- pixelAspectRatio: 0,
13536
- frames: [],
13537
- sortFlag: false,
13538
- globalColorTable: [],
13539
- backgroundImage: new ImageData(1, 1, canvasSettings),
13540
- comments: [],
13541
- applicationExtensions: [],
13542
- }, byteStream = new ByteStream(new Uint8ClampedArray(buffer));
13543
- if (byteStream.getString(6) !== "GIF89a") {
13544
- throw new Error("not a supported GIF file");
13545
- }
13546
- gif.width = byteStream.nextTwoBytes();
13547
- gif.height = byteStream.nextTwoBytes();
13548
- const packedByte = byteStream.nextByte(), globalColorTableFlag = (packedByte & 0x80) === 0x80;
13549
- gif.colorRes = (packedByte & 0x70) >>> 4;
13550
- gif.sortFlag = (packedByte & 8) === 8;
13551
- const globalColorCount = 1 << ((packedByte & 7) + 1), backgroundColorIndex = byteStream.nextByte();
13552
- gif.pixelAspectRatio = byteStream.nextByte();
13553
- if (gif.pixelAspectRatio !== 0) {
13554
- gif.pixelAspectRatio = (gif.pixelAspectRatio + 0xf) / 0x40;
13555
- }
13556
- if (globalColorTableFlag) {
13557
- gif.globalColorTable = parseColorTable(byteStream, globalColorCount);
13558
- }
13559
- const backgroundImage = (() => {
13560
- try {
13561
- return new ImageData(gif.width, gif.height, canvasSettings);
13562
- }
13563
- catch (error) {
13564
- if (error instanceof DOMException && error.name === "IndexSizeError") {
13565
- return null;
13566
- }
13567
- throw error;
13579
+ }
13580
+
13581
+ class Life {
13582
+ count = 0;
13583
+ delay = new LifeDelay();
13584
+ duration = new LifeDuration();
13585
+ load(data) {
13586
+ if (isNull(data)) {
13587
+ return;
13568
13588
  }
13569
- })();
13570
- if (backgroundImage == null) {
13571
- throw new Error("GIF frame size is to large");
13589
+ loadProperty(this, "count", data.count);
13590
+ this.delay.load(data.delay);
13591
+ this.duration.load(data.duration);
13572
13592
  }
13573
- const { r, g, b } = gif.globalColorTable[backgroundColorIndex];
13574
- backgroundImage.data.set(globalColorTableFlag ? [r, g, b, 255] : [0, 0, 0, 0]);
13575
- for (let i = 4; i < backgroundImage.data.length; i *= 2) {
13576
- backgroundImage.data.copyWithin(i, 0, i);
13593
+ }
13594
+
13595
+ const noTime$1 = 0, infiniteValue$1 = -1, noLife = 0, minCanvasSize = 0;
13596
+ function updateLife(particle, delta, canvasSize) {
13597
+ if (!particle.life) {
13598
+ return;
13577
13599
  }
13578
- gif.backgroundImage = backgroundImage;
13579
- let frameIndex = -1, incrementFrameIndex = true, transparencyIndex = -1;
13580
- const getframeIndex = (increment) => {
13581
- if (increment) {
13582
- incrementFrameIndex = true;
13583
- }
13584
- return frameIndex;
13585
- }, getTransparencyIndex = (newValue) => {
13586
- if (newValue != null) {
13587
- transparencyIndex = newValue;
13588
- }
13589
- return transparencyIndex;
13590
- };
13591
- try {
13592
- do {
13593
- if (incrementFrameIndex) {
13594
- gif.frames.push({
13595
- left: 0,
13596
- top: 0,
13597
- width: 0,
13598
- height: 0,
13599
- disposalMethod: DisposalMethod.Replace,
13600
- image: new ImageData(1, 1, canvasSettings),
13601
- plainTextData: null,
13602
- userInputDelayFlag: false,
13603
- delayTime: 0,
13604
- sortFlag: false,
13605
- localColorTable: [],
13606
- reserved: 0,
13607
- GCreserved: 0,
13608
- });
13609
- frameIndex++;
13610
- transparencyIndex = -1;
13611
- incrementFrameIndex = false;
13612
- }
13613
- } while (!(await parseBlock(byteStream, gif, avgAlpha, getframeIndex, getTransparencyIndex, canvasSettings, progressCallback)));
13614
- gif.frames.length--;
13615
- for (const frame of gif.frames) {
13616
- if (frame.userInputDelayFlag && frame.delayTime === 0) {
13617
- gif.totalTime = Infinity;
13618
- break;
13619
- }
13620
- gif.totalTime += frame.delayTime;
13600
+ const life = particle.life;
13601
+ let justSpawned = false;
13602
+ if (particle.spawning) {
13603
+ life.delayTime += delta.value;
13604
+ if (life.delayTime >= particle.life.delay) {
13605
+ justSpawned = true;
13606
+ particle.spawning = false;
13607
+ life.delayTime = noTime$1;
13608
+ life.time = noTime$1;
13621
13609
  }
13622
- return gif;
13623
- }
13624
- catch (error) {
13625
- if (error instanceof EvalError) {
13626
- throw new Error(`error while parsing frame ${frameIndex.toString()} "${error.message}"`, { cause: error });
13610
+ else {
13611
+ return;
13627
13612
  }
13628
- throw error;
13629
13613
  }
13630
- }
13631
- function drawGif(data, canvasSettings) {
13632
- const { context, radius, particle, delta } = data, image = particle.image;
13633
- if (!image?.gifData || !image.gif) {
13614
+ if (life.duration === infiniteValue$1) {
13634
13615
  return;
13635
13616
  }
13636
- const offscreenCanvas = new OffscreenCanvas(image.gifData.width, image.gifData.height), offscreenContext = offscreenCanvas.getContext("2d", canvasSettings);
13637
- if (!offscreenContext) {
13638
- throw new Error("could not create offscreen canvas context");
13617
+ if (justSpawned) {
13618
+ life.time = noTime$1;
13639
13619
  }
13640
- offscreenContext.imageSmoothingQuality = "low";
13641
- offscreenContext.imageSmoothingEnabled = false;
13642
- offscreenContext.clearRect(originPoint.x, originPoint.y, offscreenCanvas.width, offscreenCanvas.height);
13643
- particle.gifLoopCount ??= image.gifLoopCount ?? defaultLoopCount;
13644
- let frameIndex = particle.gifFrame ?? defaultFrame;
13645
- const pos = { x: -image.gifData.width * half$2, y: -image.gifData.height * half$2 }, frame = image.gifData.frames[frameIndex];
13646
- particle.gifTime ??= initialTime;
13647
- if (!frame.bitmap) {
13648
- return;
13620
+ else {
13621
+ life.time += delta.value;
13649
13622
  }
13650
- context.scale(radius / image.gifData.width, radius / image.gifData.height);
13651
- switch (frame.disposalMethod) {
13652
- case DisposalMethod.UndefinedA:
13653
- case DisposalMethod.UndefinedB:
13654
- case DisposalMethod.UndefinedC:
13655
- case DisposalMethod.UndefinedD:
13656
- case DisposalMethod.Replace:
13657
- offscreenContext.drawImage(frame.bitmap, frame.left, frame.top);
13658
- context.drawImage(offscreenCanvas, pos.x, pos.y);
13659
- offscreenContext.clearRect(originPoint.x, originPoint.y, offscreenCanvas.width, offscreenCanvas.height);
13660
- break;
13661
- case DisposalMethod.Combine:
13662
- offscreenContext.drawImage(frame.bitmap, frame.left, frame.top);
13663
- context.drawImage(offscreenCanvas, pos.x, pos.y);
13664
- break;
13665
- case DisposalMethod.RestoreBackground:
13666
- offscreenContext.drawImage(frame.bitmap, frame.left, frame.top);
13667
- context.drawImage(offscreenCanvas, pos.x, pos.y);
13668
- offscreenContext.clearRect(originPoint.x, originPoint.y, offscreenCanvas.width, offscreenCanvas.height);
13669
- if (!image.gifData.globalColorTable.length) {
13670
- offscreenContext.putImageData(image.gifData.frames[firstIndex$3].image, pos.x + frame.left, pos.y + frame.top);
13671
- }
13672
- else {
13673
- offscreenContext.putImageData(image.gifData.backgroundImage, pos.x, pos.y);
13674
- }
13675
- break;
13676
- case DisposalMethod.RestorePrevious:
13677
- {
13678
- const previousImageData = offscreenContext.getImageData(originPoint.x, originPoint.y, offscreenCanvas.width, offscreenCanvas.height);
13679
- offscreenContext.drawImage(frame.bitmap, frame.left, frame.top);
13680
- context.drawImage(offscreenCanvas, pos.x, pos.y);
13681
- offscreenContext.clearRect(originPoint.x, originPoint.y, offscreenCanvas.width, offscreenCanvas.height);
13682
- offscreenContext.putImageData(previousImageData, originPoint.x, originPoint.y);
13683
- }
13684
- break;
13623
+ if (life.time < life.duration) {
13624
+ return;
13685
13625
  }
13686
- particle.gifTime += delta.value;
13687
- if (particle.gifTime > frame.delayTime) {
13688
- particle.gifTime -= frame.delayTime;
13689
- if (++frameIndex >= image.gifData.frames.length) {
13690
- if (--particle.gifLoopCount <= defaultLoopCount) {
13691
- return;
13692
- }
13693
- frameIndex = firstIndex$3;
13694
- offscreenContext.clearRect(originPoint.x, originPoint.y, offscreenCanvas.width, offscreenCanvas.height);
13695
- }
13696
- particle.gifFrame = frameIndex;
13626
+ life.time = noTime$1;
13627
+ if (particle.life.count > noLife) {
13628
+ particle.life.count--;
13697
13629
  }
13698
- context.scale(image.gifData.width / radius, image.gifData.height / radius);
13699
- }
13700
- async function loadGifImage(image, canvasSettings) {
13701
- if (image.type !== "gif") {
13702
- await loadImage(image);
13630
+ if (particle.life.count === noLife) {
13631
+ particle.destroy();
13703
13632
  return;
13704
13633
  }
13705
- image.loading = true;
13706
- try {
13707
- image.gifData = await decodeGIF(image.source, canvasSettings);
13708
- image.gifLoopCount = getGIFLoopAmount(image.gifData);
13709
- if (!image.gifLoopCount) {
13710
- image.gifLoopCount = Infinity;
13711
- }
13712
- }
13713
- catch {
13714
- image.error = true;
13634
+ const widthRange = setRangeValue(minCanvasSize, canvasSize.width), heightRange = setRangeValue(minCanvasSize, canvasSize.width);
13635
+ particle.position.x = randomInRangeValue(widthRange);
13636
+ particle.position.y = randomInRangeValue(heightRange);
13637
+ particle.spawning = true;
13638
+ life.delayTime = noTime$1;
13639
+ life.time = noTime$1;
13640
+ particle.reset();
13641
+ const lifeOptions = particle.options.life;
13642
+ if (lifeOptions) {
13643
+ life.delay = getRangeValue(lifeOptions.delay.value) * millisecondsToSeconds$1;
13644
+ life.duration = getRangeValue(lifeOptions.duration.value) * millisecondsToSeconds$1;
13715
13645
  }
13716
- image.loading = false;
13717
13646
  }
13718
13647
 
13719
- const sides$3 = 12;
13720
- class ImageDrawer {
13648
+ const noTime = 0, identity$2 = 1, infiniteValue = -1;
13649
+ class LifeUpdater {
13721
13650
  #container;
13722
- #engine;
13723
- constructor(engine, container) {
13724
- this.#engine = engine;
13651
+ constructor(container) {
13725
13652
  this.#container = container;
13726
13653
  }
13727
- draw(data) {
13728
- const { context, radius, particle, opacity } = data, image = particle.image, element = image?.element;
13729
- if (!image) {
13654
+ init(particle) {
13655
+ const container = this.#container, particlesOptions = particle.options, lifeOptions = particlesOptions.life;
13656
+ if (!lifeOptions) {
13730
13657
  return;
13731
13658
  }
13732
- context.globalAlpha = opacity;
13733
- if (image.gif && image.gifData) {
13734
- drawGif(data, this.#container.canvas.render.settings);
13659
+ const delayFactor = lifeOptions.delay.sync ? identity$2 : getRandom(), durationFactor = lifeOptions.duration.sync ? identity$2 : getRandom();
13660
+ particle.life = {
13661
+ delay: container.retina.reduceFactor
13662
+ ? ((getRangeValue(lifeOptions.delay.value) * delayFactor) / container.retina.reduceFactor) *
13663
+ millisecondsToSeconds$1
13664
+ : noTime,
13665
+ delayTime: noTime,
13666
+ duration: container.retina.reduceFactor
13667
+ ? ((getRangeValue(lifeOptions.duration.value) * durationFactor) / container.retina.reduceFactor) *
13668
+ millisecondsToSeconds$1
13669
+ : noTime,
13670
+ time: noTime,
13671
+ count: lifeOptions.count,
13672
+ };
13673
+ if (particle.life.duration <= noTime) {
13674
+ particle.life.duration = infiniteValue;
13735
13675
  }
13736
- else if (element) {
13737
- const ratio = image.ratio, pos = {
13738
- x: -radius,
13739
- y: -radius,
13740
- }, diameter = radius * double;
13741
- context.drawImage(element, pos.x, pos.y, diameter, diameter / ratio);
13676
+ if (particle.life.count <= noTime) {
13677
+ particle.life.count = infiniteValue;
13742
13678
  }
13743
- context.globalAlpha = defaultAlpha$1;
13679
+ particle.spawning = particle.life.delay > noTime;
13744
13680
  }
13745
- getSidesCount() {
13746
- return sides$3;
13681
+ isEnabled(particle) {
13682
+ return !particle.destroyed;
13747
13683
  }
13748
- async init(container) {
13749
- const options = container.actualOptions;
13750
- if (!options.preload || !this.#engine.loadImage) {
13684
+ loadOptions(options, ...sources) {
13685
+ loadOptionProperty(options, "life", Life, ...sources);
13686
+ }
13687
+ update(particle, delta) {
13688
+ if (!this.isEnabled(particle) || !particle.life) {
13751
13689
  return;
13752
13690
  }
13753
- const promises = [];
13754
- for (const imageData of options.preload) {
13755
- promises.push(this.#engine.loadImage(container, imageData));
13756
- }
13757
- await Promise.all(promises);
13691
+ updateLife(particle, delta, this.#container.canvas.size);
13758
13692
  }
13759
- loadShape(particle) {
13760
- const container = this.#container;
13761
- if (!particle.shape || !shapeTypes.includes(particle.shape)) {
13762
- return;
13763
- }
13764
- const imageData = particle.shapeData;
13765
- if (!imageData) {
13766
- return;
13767
- }
13768
- const images = this.#engine.getImages?.(container), image = images?.find((t) => t.name === imageData.name || t.source === imageData.src);
13769
- if (image) {
13770
- return;
13771
- }
13772
- void this.#loadImageShape(container, imageData).then(() => {
13773
- this.loadShape(particle);
13693
+ }
13694
+
13695
+ async function loadLifeUpdater(engine) {
13696
+ engine.checkVersion("4.2.1");
13697
+ await engine.pluginManager.register(e => {
13698
+ e.pluginManager.addParticleUpdater("life", container => {
13699
+ return Promise.resolve(new LifeUpdater(container));
13774
13700
  });
13701
+ });
13702
+ }
13703
+
13704
+ function drawLine(data) {
13705
+ const { context, particle, radius } = data, shapeData = particle.shapeData, centerY = 0;
13706
+ context.moveTo(-radius, centerY);
13707
+ context.lineTo(radius, centerY);
13708
+ context.lineCap = shapeData?.cap ?? "butt";
13709
+ }
13710
+
13711
+ const sides$2 = 1;
13712
+ class LineDrawer {
13713
+ draw(data) {
13714
+ drawLine(data);
13775
13715
  }
13776
- particleInit(container, particle) {
13777
- if (particle.shape !== "image" && particle.shape !== "images") {
13778
- return;
13779
- }
13780
- const images = this.#engine.getImages?.(container), imageData = particle.shapeData;
13781
- if (!imageData) {
13782
- return;
13783
- }
13784
- const color = particle.getFillColor(), image = images?.find((t) => t.name === imageData.name || t.source === imageData.src);
13785
- if (!image) {
13786
- return;
13787
- }
13788
- const replaceColor = imageData.replaceColor;
13789
- if (image.loading) {
13790
- setTimeout(() => {
13791
- this.particleInit(container, particle);
13792
- });
13793
- return;
13794
- }
13795
- void (async () => {
13796
- let imageRes;
13797
- if (image.svgData && color) {
13798
- imageRes = await replaceImageColor(image, imageData, color, particle, container.hdr);
13799
- }
13800
- else {
13801
- imageRes = {
13802
- color,
13803
- data: image,
13804
- element: image.element,
13805
- gif: image.gif,
13806
- gifData: image.gifData,
13807
- gifLoopCount: image.gifLoopCount,
13808
- loaded: true,
13809
- ratio: imageData.width && imageData.height ? imageData.width / imageData.height : (image.ratio ?? defaultRatio$1),
13810
- replaceColor: replaceColor,
13811
- source: imageData.src,
13812
- };
13813
- }
13814
- if (!imageRes.ratio) {
13815
- imageRes.ratio = 1;
13816
- }
13817
- const close = imageData.close ?? particle.shapeClose, imageShape = {
13818
- image: imageRes,
13819
- close,
13820
- };
13821
- particle.image = imageShape.image;
13822
- particle.shapeClose = imageShape.close;
13823
- })();
13716
+ getSidesCount() {
13717
+ return sides$2;
13824
13718
  }
13825
- #loadImageShape = async (container, imageShape) => {
13826
- if (!this.#engine.loadImage) {
13827
- throw new Error(`Image shape not initialized`);
13828
- }
13829
- await this.#engine.loadImage(container, {
13830
- gif: imageShape.gif,
13831
- name: imageShape.name,
13832
- replaceColor: imageShape.replaceColor,
13833
- src: imageShape.src,
13834
- });
13835
- };
13836
13719
  }
13837
13720
 
13838
- class Preload {
13839
- gif = false;
13840
- height;
13841
- name;
13842
- replaceColor;
13843
- src = "";
13844
- width;
13721
+ async function loadLineShape(engine) {
13722
+ engine.checkVersion("4.2.1");
13723
+ await engine.pluginManager.register(e => {
13724
+ e.pluginManager.addShape(["line"], () => Promise.resolve(new LineDrawer()));
13725
+ });
13726
+ }
13727
+
13728
+ class Attract {
13729
+ distance = 200;
13730
+ enable = false;
13731
+ rotate;
13732
+ constructor() {
13733
+ this.rotate = {
13734
+ x: 3000,
13735
+ y: 3000,
13736
+ };
13737
+ }
13845
13738
  load(data) {
13846
13739
  if (isNull(data)) {
13847
13740
  return;
13848
13741
  }
13849
- loadProperty(this, "gif", data.gif);
13850
- loadProperty(this, "height", data.height);
13851
- loadProperty(this, "name", data.name);
13852
- loadProperty(this, "replaceColor", data.replaceColor);
13853
- loadProperty(this, "src", data.src);
13854
- loadProperty(this, "width", data.width);
13742
+ loadRangeProperty(this, "distance", data.distance);
13743
+ loadProperty(this, "enable", data.enable);
13744
+ if (data.rotate) {
13745
+ const rotateX = data.rotate.x;
13746
+ if (rotateX !== undefined) {
13747
+ this.rotate.x = rotateX;
13748
+ }
13749
+ const rotateY = data.rotate.y;
13750
+ if (rotateY !== undefined) {
13751
+ this.rotate.y = rotateY;
13752
+ }
13753
+ }
13855
13754
  }
13856
13755
  }
13857
13756
 
13858
- class ImagePreloaderPlugin {
13859
- id = "image-preloader";
13860
- #engine;
13861
- constructor(engine) {
13862
- this.#engine = engine;
13757
+ const attractFactor = 1000, identity$1 = 1;
13758
+ class Attractor extends ParticlesInteractorBase {
13759
+ #maxDistance;
13760
+ constructor(container) {
13761
+ super(container);
13762
+ this.#maxDistance = 0;
13863
13763
  }
13864
- async getPlugin(container) {
13865
- const { ImagePreloaderInstance } = await Promise.resolve().then(function () { return ImagePreloaderInstance$1; });
13866
- return new ImagePreloaderInstance(this.#engine, container);
13764
+ get maxDistance() {
13765
+ return this.#maxDistance;
13867
13766
  }
13868
- loadOptions(_container, options, source) {
13869
- if (!source?.preload) {
13767
+ clear() {
13768
+ }
13769
+ init() {
13770
+ }
13771
+ interact(p1) {
13772
+ if (!p1.options.attract?.enable) {
13870
13773
  return;
13871
13774
  }
13872
- options.preload ??= [];
13873
- const preloadOptions = options.preload;
13874
- for (const item of source.preload) {
13875
- const existing = preloadOptions.find(t => t.name === item.name || t.src === item.src);
13876
- if (existing) {
13877
- existing.load(item);
13775
+ const container = this.container;
13776
+ if (isNull(p1.attractDistance)) {
13777
+ const attractDistance = getRangeValue(p1.options.attract.distance);
13778
+ if (attractDistance > this.#maxDistance) {
13779
+ this.#maxDistance = attractDistance;
13878
13780
  }
13879
- else {
13880
- const preload = new Preload();
13881
- preload.load(item);
13882
- preloadOptions.push(preload);
13781
+ p1.attractDistance = attractDistance * container.retina.pixelRatio;
13782
+ }
13783
+ const distance = p1.attractDistance, pos1 = p1.getPosition(), query = container.particles.grid.queryCircle(pos1, distance);
13784
+ for (const p2 of query) {
13785
+ if (p1 === p2 || !p2.options.attract?.enable || p2.destroyed || p2.spawning) {
13786
+ continue;
13883
13787
  }
13788
+ const pos2 = p2.getPosition(), { dx, dy } = getDistances(pos1, pos2), rotate = p1.options.attract.rotate, ax = dx / (rotate.x * attractFactor), ay = dy / (rotate.y * attractFactor), p1Factor = p2.size.value / p1.size.value, p2Factor = identity$1 / p1Factor;
13789
+ p1.velocity.x -= ax * p1Factor;
13790
+ p1.velocity.y -= ay * p1Factor;
13791
+ p2.velocity.x += ax * p2Factor;
13792
+ p2.velocity.y += ay * p2Factor;
13884
13793
  }
13885
13794
  }
13886
- needsPlugin() {
13887
- return true;
13795
+ isEnabled(particle) {
13796
+ return particle.options.attract?.enable ?? false;
13797
+ }
13798
+ loadParticlesOptions(options, ...sources) {
13799
+ loadOptionProperty(options, "attract", Attract, ...sources);
13800
+ }
13801
+ reset() {
13888
13802
  }
13889
13803
  }
13890
13804
 
13891
- const extLength = 3;
13892
- function addLoadImageToEngine(engine) {
13893
- engine.getImages ??= (container) => {
13894
- engine.images ??= new Map();
13895
- let images = engine.images.get(container);
13896
- if (!images) {
13897
- images = [];
13898
- engine.images.set(container, images);
13899
- }
13900
- return images;
13901
- };
13902
- engine.loadImage ??= async (container, data) => {
13903
- if (!engine.getImages) {
13904
- throw new Error("No images collection found");
13905
- }
13906
- if (!data.name && !data.src) {
13907
- throw new Error("No image source provided");
13908
- }
13909
- engine.images ??= new Map();
13910
- const containerImages = engine.getImages(container);
13911
- if (containerImages.some((t) => t.name === data.name || t.source === data.src)) {
13912
- return;
13913
- }
13914
- try {
13915
- const image = {
13916
- gif: data.gif,
13917
- name: data.name ?? data.src,
13918
- source: data.src,
13919
- type: data.src.substring(data.src.length - extLength),
13920
- error: false,
13921
- loading: true,
13922
- replaceColor: data.replaceColor,
13923
- ratio: data.width && data.height ? data.width / data.height : undefined,
13924
- };
13925
- containerImages.push(image);
13926
- engine.images.set(container, containerImages);
13927
- let imageFunc;
13928
- if (data.gif) {
13929
- imageFunc = (img) => loadGifImage(img, { colorSpace: "srgb" });
13930
- }
13931
- else if (data.replaceColor) {
13932
- imageFunc = downloadSvgImage;
13933
- }
13934
- else {
13935
- imageFunc = loadImage;
13936
- }
13937
- await imageFunc(image);
13938
- }
13939
- catch {
13940
- throw new Error(`${data.name ?? data.src} not found`);
13941
- }
13942
- };
13943
- }
13944
- async function loadImageShape(engine) {
13945
- engine.checkVersion("4.2.0");
13946
- await engine.pluginManager.register(e => {
13947
- addLoadImageToEngine(e);
13948
- e.pluginManager.addPlugin(new ImagePreloaderPlugin(e));
13949
- e.pluginManager.addShape(shapeTypes, container => Promise.resolve(new ImageDrawer(e, container)));
13950
- });
13951
- }
13952
-
13953
- class LifeDelay extends ValueWithRandom {
13954
- sync = false;
13955
- load(data) {
13956
- if (isNull(data)) {
13957
- return;
13958
- }
13959
- super.load(data);
13960
- loadProperty(this, "sync", data.sync);
13961
- }
13962
- }
13963
-
13964
- class LifeDuration extends ValueWithRandom {
13965
- sync = false;
13966
- load(data) {
13967
- if (isNull(data)) {
13968
- return;
13969
- }
13970
- super.load(data);
13971
- loadProperty(this, "sync", data.sync);
13972
- }
13973
- }
13974
-
13975
- class Life {
13976
- count = 0;
13977
- delay = new LifeDelay();
13978
- duration = new LifeDuration();
13979
- load(data) {
13980
- if (isNull(data)) {
13981
- return;
13982
- }
13983
- loadProperty(this, "count", data.count);
13984
- this.delay.load(data.delay);
13985
- this.duration.load(data.duration);
13986
- }
13987
- }
13988
-
13989
- const noTime$1 = 0, infiniteValue$1 = -1, noLife = 0, minCanvasSize = 0;
13990
- function updateLife(particle, delta, canvasSize) {
13991
- if (!particle.life) {
13992
- return;
13993
- }
13994
- const life = particle.life;
13995
- let justSpawned = false;
13996
- if (particle.spawning) {
13997
- life.delayTime += delta.value;
13998
- if (life.delayTime >= particle.life.delay) {
13999
- justSpawned = true;
14000
- particle.spawning = false;
14001
- life.delayTime = noTime$1;
14002
- life.time = noTime$1;
14003
- }
14004
- else {
14005
- return;
14006
- }
14007
- }
14008
- if (life.duration === infiniteValue$1) {
14009
- return;
14010
- }
14011
- if (justSpawned) {
14012
- life.time = noTime$1;
14013
- }
14014
- else {
14015
- life.time += delta.value;
14016
- }
14017
- if (life.time < life.duration) {
14018
- return;
14019
- }
14020
- life.time = noTime$1;
14021
- if (particle.life.count > noLife) {
14022
- particle.life.count--;
14023
- }
14024
- if (particle.life.count === noLife) {
14025
- particle.destroy();
14026
- return;
14027
- }
14028
- const widthRange = setRangeValue(minCanvasSize, canvasSize.width), heightRange = setRangeValue(minCanvasSize, canvasSize.width);
14029
- particle.position.x = randomInRangeValue(widthRange);
14030
- particle.position.y = randomInRangeValue(heightRange);
14031
- particle.spawning = true;
14032
- life.delayTime = noTime$1;
14033
- life.time = noTime$1;
14034
- particle.reset();
14035
- const lifeOptions = particle.options.life;
14036
- if (lifeOptions) {
14037
- life.delay = getRangeValue(lifeOptions.delay.value) * millisecondsToSeconds$1;
14038
- life.duration = getRangeValue(lifeOptions.duration.value) * millisecondsToSeconds$1;
14039
- }
14040
- }
14041
-
14042
- const noTime = 0, identity$2 = 1, infiniteValue = -1;
14043
- class LifeUpdater {
14044
- #container;
14045
- constructor(container) {
14046
- this.#container = container;
14047
- }
14048
- init(particle) {
14049
- const container = this.#container, particlesOptions = particle.options, lifeOptions = particlesOptions.life;
14050
- if (!lifeOptions) {
14051
- return;
14052
- }
14053
- const delayFactor = lifeOptions.delay.sync ? identity$2 : getRandom(), durationFactor = lifeOptions.duration.sync ? identity$2 : getRandom();
14054
- particle.life = {
14055
- delay: container.retina.reduceFactor
14056
- ? ((getRangeValue(lifeOptions.delay.value) * delayFactor) / container.retina.reduceFactor) *
14057
- millisecondsToSeconds$1
14058
- : noTime,
14059
- delayTime: noTime,
14060
- duration: container.retina.reduceFactor
14061
- ? ((getRangeValue(lifeOptions.duration.value) * durationFactor) / container.retina.reduceFactor) *
14062
- millisecondsToSeconds$1
14063
- : noTime,
14064
- time: noTime,
14065
- count: lifeOptions.count,
14066
- };
14067
- if (particle.life.duration <= noTime) {
14068
- particle.life.duration = infiniteValue;
14069
- }
14070
- if (particle.life.count <= noTime) {
14071
- particle.life.count = infiniteValue;
14072
- }
14073
- particle.spawning = particle.life.delay > noTime;
14074
- }
14075
- isEnabled(particle) {
14076
- return !particle.destroyed;
14077
- }
14078
- loadOptions(options, ...sources) {
14079
- loadOptionProperty(options, "life", Life, ...sources);
14080
- }
14081
- update(particle, delta) {
14082
- if (!this.isEnabled(particle) || !particle.life) {
14083
- return;
14084
- }
14085
- updateLife(particle, delta, this.#container.canvas.size);
14086
- }
14087
- }
14088
-
14089
- async function loadLifeUpdater(engine) {
14090
- engine.checkVersion("4.2.0");
14091
- await engine.pluginManager.register(e => {
14092
- e.pluginManager.addParticleUpdater("life", container => {
14093
- return Promise.resolve(new LifeUpdater(container));
14094
- });
14095
- });
14096
- }
14097
-
14098
- function drawLine(data) {
14099
- const { context, particle, radius } = data, shapeData = particle.shapeData, centerY = 0;
14100
- context.moveTo(-radius, centerY);
14101
- context.lineTo(radius, centerY);
14102
- context.lineCap = shapeData?.cap ?? "butt";
14103
- }
14104
-
14105
- const sides$2 = 1;
14106
- class LineDrawer {
14107
- draw(data) {
14108
- drawLine(data);
14109
- }
14110
- getSidesCount() {
14111
- return sides$2;
14112
- }
14113
- }
14114
-
14115
- async function loadLineShape(engine) {
14116
- engine.checkVersion("4.2.0");
14117
- await engine.pluginManager.register(e => {
14118
- e.pluginManager.addShape(["line"], () => Promise.resolve(new LineDrawer()));
14119
- });
14120
- }
14121
-
14122
- class Attract {
14123
- distance = 200;
14124
- enable = false;
14125
- rotate;
14126
- constructor() {
14127
- this.rotate = {
14128
- x: 3000,
14129
- y: 3000,
14130
- };
14131
- }
14132
- load(data) {
14133
- if (isNull(data)) {
14134
- return;
14135
- }
14136
- loadRangeProperty(this, "distance", data.distance);
14137
- loadProperty(this, "enable", data.enable);
14138
- if (data.rotate) {
14139
- const rotateX = data.rotate.x;
14140
- if (rotateX !== undefined) {
14141
- this.rotate.x = rotateX;
14142
- }
14143
- const rotateY = data.rotate.y;
14144
- if (rotateY !== undefined) {
14145
- this.rotate.y = rotateY;
14146
- }
14147
- }
14148
- }
14149
- }
14150
-
14151
- const attractFactor = 1000, identity$1 = 1;
14152
- class Attractor extends ParticlesInteractorBase {
14153
- #maxDistance;
14154
- constructor(container) {
14155
- super(container);
14156
- this.#maxDistance = 0;
14157
- }
14158
- get maxDistance() {
14159
- return this.#maxDistance;
14160
- }
14161
- clear() {
14162
- }
14163
- init() {
14164
- }
14165
- interact(p1) {
14166
- if (!p1.options.attract?.enable) {
14167
- return;
14168
- }
14169
- const container = this.container;
14170
- if (isNull(p1.attractDistance)) {
14171
- const attractDistance = getRangeValue(p1.options.attract.distance);
14172
- if (attractDistance > this.#maxDistance) {
14173
- this.#maxDistance = attractDistance;
14174
- }
14175
- p1.attractDistance = attractDistance * container.retina.pixelRatio;
14176
- }
14177
- const distance = p1.attractDistance, pos1 = p1.getPosition(), query = container.particles.grid.queryCircle(pos1, distance);
14178
- for (const p2 of query) {
14179
- if (p1 === p2 || !p2.options.attract?.enable || p2.destroyed || p2.spawning) {
14180
- continue;
14181
- }
14182
- const pos2 = p2.getPosition(), { dx, dy } = getDistances(pos1, pos2), rotate = p1.options.attract.rotate, ax = dx / (rotate.x * attractFactor), ay = dy / (rotate.y * attractFactor), p1Factor = p2.size.value / p1.size.value, p2Factor = identity$1 / p1Factor;
14183
- p1.velocity.x -= ax * p1Factor;
14184
- p1.velocity.y -= ay * p1Factor;
14185
- p2.velocity.x += ax * p2Factor;
14186
- p2.velocity.y += ay * p2Factor;
14187
- }
14188
- }
14189
- isEnabled(particle) {
14190
- return particle.options.attract?.enable ?? false;
14191
- }
14192
- loadParticlesOptions(options, ...sources) {
14193
- loadOptionProperty(options, "attract", Attract, ...sources);
14194
- }
14195
- reset() {
14196
- }
14197
- }
14198
-
14199
- async function loadParticlesAttractInteraction(engine) {
14200
- engine.checkVersion("4.2.0");
14201
- await engine.pluginManager.register((e) => {
14202
- ensureInteractivityPluginLoaded(e);
14203
- e.pluginManager.addInteractor?.("particlesAttract", container => {
14204
- return Promise.resolve(new Attractor(container));
14205
- });
13805
+ async function loadParticlesAttractInteraction(engine) {
13806
+ engine.checkVersion("4.2.1");
13807
+ await engine.pluginManager.register((e) => {
13808
+ ensureInteractivityPluginLoaded(e);
13809
+ e.pluginManager.addInteractor?.("particlesAttract", container => {
13810
+ return Promise.resolve(new Attractor(container));
13811
+ });
14206
13812
  });
14207
13813
  }
14208
13814
 
@@ -14407,7 +14013,7 @@
14407
14013
  }
14408
14014
 
14409
14015
  async function loadParticlesCollisionsInteraction(engine) {
14410
- engine.checkVersion("4.2.0");
14016
+ engine.checkVersion("4.2.1");
14411
14017
  await engine.pluginManager.register((e) => {
14412
14018
  ensureInteractivityPluginLoaded(e);
14413
14019
  e.pluginManager.addPlugin(new OverlapPlugin());
@@ -14661,7 +14267,7 @@
14661
14267
  }
14662
14268
 
14663
14269
  async function loadParticlesLinksInteraction(engine) {
14664
- engine.checkVersion("4.2.0");
14270
+ engine.checkVersion("4.2.1");
14665
14271
  await engine.pluginManager.register((e) => {
14666
14272
  const pluginManager = e.pluginManager;
14667
14273
  ensureInteractivityPluginLoaded(e);
@@ -14751,19 +14357,19 @@
14751
14357
  }
14752
14358
 
14753
14359
  async function loadGenericPolygonShape(engine) {
14754
- engine.checkVersion("4.2.0");
14360
+ engine.checkVersion("4.2.1");
14755
14361
  await engine.pluginManager.register(e => {
14756
14362
  e.pluginManager.addShape(["polygon"], () => Promise.resolve(new PolygonDrawer()));
14757
14363
  });
14758
14364
  }
14759
14365
  async function loadTriangleShape(engine) {
14760
- engine.checkVersion("4.2.0");
14366
+ engine.checkVersion("4.2.1");
14761
14367
  await engine.pluginManager.register(e => {
14762
14368
  e.pluginManager.addShape(["triangle"], () => Promise.resolve(new TriangleDrawer()));
14763
14369
  });
14764
14370
  }
14765
14371
  async function loadPolygonShape(engine) {
14766
- engine.checkVersion("4.2.0");
14372
+ engine.checkVersion("4.2.1");
14767
14373
  await Promise.all([
14768
14374
  loadGenericPolygonShape(engine),
14769
14375
  loadTriangleShape(engine),
@@ -14868,7 +14474,7 @@
14868
14474
  }
14869
14475
 
14870
14476
  async function loadRotateUpdater(engine) {
14871
- engine.checkVersion("4.2.0");
14477
+ engine.checkVersion("4.2.1");
14872
14478
  await engine.pluginManager.register(e => {
14873
14479
  e.pluginManager.addParticleUpdater("rotate", container => {
14874
14480
  return Promise.resolve(new RotateUpdater(container));
@@ -14892,7 +14498,7 @@
14892
14498
  }
14893
14499
 
14894
14500
  async function loadSquareShape(engine) {
14895
- engine.checkVersion("4.2.0");
14501
+ engine.checkVersion("4.2.1");
14896
14502
  await engine.pluginManager.register(e => {
14897
14503
  e.pluginManager.addShape(["edge", "square"], () => Promise.resolve(new SquareDrawer()));
14898
14504
  });
@@ -14926,14 +14532,14 @@
14926
14532
  }
14927
14533
 
14928
14534
  async function loadStarShape(engine) {
14929
- engine.checkVersion("4.2.0");
14535
+ engine.checkVersion("4.2.1");
14930
14536
  await engine.pluginManager.register(e => {
14931
14537
  e.pluginManager.addShape(["star"], () => Promise.resolve(new StarDrawer()));
14932
14538
  });
14933
14539
  }
14934
14540
 
14935
14541
  async function loadSlim(engine) {
14936
- engine.checkVersion("4.2.0");
14542
+ engine.checkVersion("4.2.1");
14937
14543
  await engine.pluginManager.register(async (e) => {
14938
14544
  const loadInteractivityForSlim = async (e) => {
14939
14545
  await loadInteractivityPlugin(e);
@@ -14973,7 +14579,7 @@
14973
14579
  }
14974
14580
 
14975
14581
  const validTypes = ["text", "character", "char", "multiline-text"];
14976
- const firstIndex$2 = 0, minLength$2 = 0;
14582
+ const firstIndex$3 = 0, minLength$2 = 0;
14977
14583
  function drawText(data) {
14978
14584
  const { context, particle, fill, stroke, radius, opacity } = data, character = particle.shapeData;
14979
14585
  if (!character) {
@@ -14983,7 +14589,7 @@
14983
14589
  particle.textLines ??= itemFromSingleOrMultiple(textData, particle.randomIndexData)?.split("\n") ?? [];
14984
14590
  particle.maxTextLength ??= particle.textLines.length
14985
14591
  ? Math.max(...particle.textLines.map(t => t.length))
14986
- : (particle.textLines[firstIndex$2]?.length ?? minLength$2);
14592
+ : (particle.textLines[firstIndex$3]?.length ?? minLength$2);
14987
14593
  if (!particle.textLines.length || !particle.maxTextLength) {
14988
14594
  return;
14989
14595
  }
@@ -15013,7 +14619,7 @@
15013
14619
  }
15014
14620
  }
15015
14621
 
15016
- const firstIndex$1 = 0, minLength$1 = 0;
14622
+ const firstIndex$2 = 0, minLength$1 = 0;
15017
14623
  class TextDrawer {
15018
14624
  draw(data) {
15019
14625
  drawText(data);
@@ -15045,12 +14651,12 @@
15045
14651
  particle.textLines = itemFromSingleOrMultiple(textData, particle.randomIndexData)?.split("\n") ?? [];
15046
14652
  particle.maxTextLength = particle.textLines.length
15047
14653
  ? Math.max(...particle.textLines.map(t => t.length))
15048
- : (particle.textLines[firstIndex$1]?.length ?? minLength$1);
14654
+ : (particle.textLines[firstIndex$2]?.length ?? minLength$1);
15049
14655
  }
15050
14656
  }
15051
14657
 
15052
14658
  async function loadTextShape(engine) {
15053
- engine.checkVersion("4.2.0");
14659
+ engine.checkVersion("4.2.1");
15054
14660
  await engine.pluginManager.register(e => {
15055
14661
  e.pluginManager.addShape(validTypes, () => Promise.resolve(new TextDrawer()));
15056
14662
  });
@@ -15143,263 +14749,792 @@
15143
14749
  }
15144
14750
  }
15145
14751
  }
15146
- isEnabled(particle) {
15147
- const tiltAnimation = particle.options.tilt?.animation;
15148
- return !particle.destroyed && !particle.spawning && !!tiltAnimation?.enable;
15149
- }
15150
- loadOptions(options, ...sources) {
15151
- loadOptionProperty(options, "tilt", Tilt, ...sources);
15152
- }
15153
- update(particle, delta) {
15154
- if (!this.isEnabled(particle) || !particle.tilt) {
15155
- return;
15156
- }
15157
- updateAnimation(particle, particle.tilt, false, exports.DestroyType.none, delta);
15158
- }
15159
- }
15160
-
15161
- async function loadTiltUpdater(engine) {
15162
- engine.checkVersion("4.2.0");
15163
- await engine.pluginManager.register(e => {
15164
- e.pluginManager.addParticleUpdater("tilt", container => {
15165
- return Promise.resolve(new TiltUpdater(container));
15166
- });
15167
- });
14752
+ isEnabled(particle) {
14753
+ const tiltAnimation = particle.options.tilt?.animation;
14754
+ return !particle.destroyed && !particle.spawning && !!tiltAnimation?.enable;
14755
+ }
14756
+ loadOptions(options, ...sources) {
14757
+ loadOptionProperty(options, "tilt", Tilt, ...sources);
14758
+ }
14759
+ update(particle, delta) {
14760
+ if (!this.isEnabled(particle) || !particle.tilt) {
14761
+ return;
14762
+ }
14763
+ updateAnimation(particle, particle.tilt, false, exports.DestroyType.none, delta);
14764
+ }
14765
+ }
14766
+
14767
+ async function loadTiltUpdater(engine) {
14768
+ engine.checkVersion("4.2.1");
14769
+ await engine.pluginManager.register(e => {
14770
+ e.pluginManager.addParticleUpdater("tilt", container => {
14771
+ return Promise.resolve(new TiltUpdater(container));
14772
+ });
14773
+ });
14774
+ }
14775
+
14776
+ class TwinkleLinksValues {
14777
+ color;
14778
+ enable = false;
14779
+ frequency = 0.05;
14780
+ opacity = 1;
14781
+ load(data) {
14782
+ if (isNull(data)) {
14783
+ return;
14784
+ }
14785
+ if (data.color !== undefined) {
14786
+ this.color = OptionsColor.create(this.color, data.color);
14787
+ }
14788
+ loadProperty(this, "enable", data.enable);
14789
+ loadProperty(this, "frequency", data.frequency);
14790
+ loadRangeProperty(this, "opacity", data.opacity);
14791
+ }
14792
+ }
14793
+
14794
+ class TwinkleParticlesValues {
14795
+ enable = false;
14796
+ fillColor;
14797
+ frequency = 0.05;
14798
+ opacity = 1;
14799
+ strokeColor;
14800
+ load(data) {
14801
+ if (isNull(data)) {
14802
+ return;
14803
+ }
14804
+ if (data.fillColor !== undefined) {
14805
+ this.fillColor = OptionsColor.create(this.fillColor, data.fillColor);
14806
+ }
14807
+ if (data.strokeColor !== undefined) {
14808
+ this.strokeColor = OptionsColor.create(this.strokeColor, data.strokeColor);
14809
+ }
14810
+ loadProperty(this, "enable", data.enable);
14811
+ loadProperty(this, "frequency", data.frequency);
14812
+ loadRangeProperty(this, "opacity", data.opacity);
14813
+ }
14814
+ }
14815
+
14816
+ class Twinkle {
14817
+ links = new TwinkleLinksValues();
14818
+ particles = new TwinkleParticlesValues();
14819
+ load(data) {
14820
+ if (isNull(data)) {
14821
+ return;
14822
+ }
14823
+ this.links.load(data.links);
14824
+ this.particles.load(data.particles);
14825
+ }
14826
+ }
14827
+
14828
+ class TwinkleUpdater {
14829
+ #container;
14830
+ #pluginManager;
14831
+ constructor(pluginManager, container) {
14832
+ this.#pluginManager = pluginManager;
14833
+ this.#container = container;
14834
+ }
14835
+ getColorStyles(particle, _context, _radius, opacity) {
14836
+ const pOptions = particle.options, container = this.#container, twinkleOptions = pOptions["twinkle"];
14837
+ if (!twinkleOptions) {
14838
+ return {};
14839
+ }
14840
+ const twinkle = twinkleOptions.particles, twinkling = twinkle.enable && getRandom() < twinkle.frequency, zIndexOptions = particle.options.zIndex, zOffset = 1, zOpacityFactor = (zOffset - particle.zIndexFactor) ** zIndexOptions.opacityRate, twinklingOpacity = twinkling ? getRangeValue(twinkle.opacity) * zOpacityFactor : opacity, twinkleFillRgb = rangeColorToHsl(this.#pluginManager, twinkle.fillColor), twinkleStrokeRgb = rangeColorToHsl(this.#pluginManager, twinkle.strokeColor), getTwinkleFillStyle = () => {
14841
+ if (!twinkleFillRgb) {
14842
+ return undefined;
14843
+ }
14844
+ return getStyleFromHsl(twinkleFillRgb, container.hdr, twinklingOpacity);
14845
+ }, getTwinkleStrokeStyle = () => {
14846
+ if (!twinkleStrokeRgb) {
14847
+ return undefined;
14848
+ }
14849
+ return getStyleFromHsl(twinkleStrokeRgb, container.hdr, twinklingOpacity);
14850
+ }, twinkleFillStyle = getTwinkleFillStyle(), twinkleStrokeStyle = getTwinkleStrokeStyle(), res = {}, needsTwinkle = twinkling && (!!twinkleFillStyle || !!twinkleStrokeStyle);
14851
+ res.fill = needsTwinkle ? twinkleFillStyle : undefined;
14852
+ res.stroke = needsTwinkle ? twinkleStrokeStyle : undefined;
14853
+ return res;
14854
+ }
14855
+ init() {
14856
+ }
14857
+ isEnabled(particle) {
14858
+ const pOptions = particle.options, twinkleOptions = pOptions.twinkle;
14859
+ if (!twinkleOptions) {
14860
+ return false;
14861
+ }
14862
+ return twinkleOptions.particles.enable;
14863
+ }
14864
+ loadOptions(options, ...sources) {
14865
+ loadOptionProperty(options, "twinkle", Twinkle, ...sources);
14866
+ }
14867
+ update() {
14868
+ }
14869
+ }
14870
+
14871
+ async function loadTwinkleUpdater(engine) {
14872
+ engine.checkVersion("4.2.1");
14873
+ await engine.pluginManager.register(e => {
14874
+ e.pluginManager.addParticleUpdater("twinkle", container => {
14875
+ return Promise.resolve(new TwinkleUpdater(e.pluginManager, container));
14876
+ });
14877
+ });
14878
+ }
14879
+
14880
+ class WobbleSpeed {
14881
+ angle = 50;
14882
+ move = 10;
14883
+ load(data) {
14884
+ if (isNull(data)) {
14885
+ return;
14886
+ }
14887
+ loadRangeProperty(this, "angle", data.angle);
14888
+ loadRangeProperty(this, "move", data.move);
14889
+ }
14890
+ }
14891
+
14892
+ class Wobble {
14893
+ distance = 5;
14894
+ enable = false;
14895
+ speed = new WobbleSpeed();
14896
+ load(data) {
14897
+ if (isNull(data)) {
14898
+ return;
14899
+ }
14900
+ loadRangeProperty(this, "distance", data.distance);
14901
+ loadProperty(this, "enable", data.enable);
14902
+ if (data.speed !== undefined) {
14903
+ if (isNumber(data.speed)) {
14904
+ this.speed.load({ angle: data.speed });
14905
+ }
14906
+ else {
14907
+ const rangeSpeed = data.speed;
14908
+ if ("min" in rangeSpeed) {
14909
+ this.speed.load({ angle: rangeSpeed });
14910
+ }
14911
+ else {
14912
+ this.speed.load(data.speed);
14913
+ }
14914
+ }
14915
+ }
14916
+ }
14917
+ }
14918
+
14919
+ const defaultDistance$1 = 0, distanceFactor = 60;
14920
+ function updateWobble(container, particle, delta) {
14921
+ const { wobble: wobbleOptions } = particle.options, { wobble } = particle;
14922
+ if (!wobbleOptions?.enable || !wobble) {
14923
+ return;
14924
+ }
14925
+ const reduceFactor = container.retina.reduceFactor, angleSpeed = wobble.angleSpeed * delta.factor * reduceFactor, moveSpeed = wobble.moveSpeed * delta.factor * reduceFactor, distance = (moveSpeed * (particle.retina.wobbleDistance ?? defaultDistance$1)) / (millisecondsToSeconds$1 / distanceFactor), max = doublePI, { position } = particle;
14926
+ wobble.angle += angleSpeed;
14927
+ if (wobble.angle > max) {
14928
+ wobble.angle -= max;
14929
+ }
14930
+ position.x += distance * Math.cos(wobble.angle);
14931
+ position.y += distance * Math.abs(Math.sin(wobble.angle));
14932
+ }
14933
+
14934
+ const maxAngle$1 = 360, moveSpeedFactor$1 = 10, defaultDistance = 0;
14935
+ class WobbleUpdater {
14936
+ #container;
14937
+ constructor(container) {
14938
+ this.#container = container;
14939
+ }
14940
+ init(particle) {
14941
+ const wobbleOpt = particle.options.wobble;
14942
+ if (wobbleOpt?.enable) {
14943
+ particle.wobble = {
14944
+ angle: getRandom() * doublePI,
14945
+ angleSpeed: getRangeValue(wobbleOpt.speed.angle) / maxAngle$1,
14946
+ moveSpeed: getRangeValue(wobbleOpt.speed.move) / moveSpeedFactor$1,
14947
+ };
14948
+ }
14949
+ else {
14950
+ particle.wobble = {
14951
+ angle: 0,
14952
+ angleSpeed: 0,
14953
+ moveSpeed: 0,
14954
+ };
14955
+ }
14956
+ particle.retina.wobbleDistance =
14957
+ getRangeValue(wobbleOpt?.distance ?? defaultDistance) * this.#container.retina.pixelRatio;
14958
+ }
14959
+ isEnabled(particle) {
14960
+ return !particle.destroyed && !particle.spawning && !!particle.options.wobble?.enable;
14961
+ }
14962
+ loadOptions(options, ...sources) {
14963
+ loadOptionProperty(options, "wobble", Wobble, ...sources);
14964
+ }
14965
+ update(particle, delta) {
14966
+ if (!this.isEnabled(particle)) {
14967
+ return;
14968
+ }
14969
+ updateWobble(this.#container, particle, delta);
14970
+ }
14971
+ }
14972
+
14973
+ async function loadWobbleUpdater(engine) {
14974
+ engine.checkVersion("4.2.1");
14975
+ await engine.pluginManager.register(e => {
14976
+ e.pluginManager.addParticleUpdater("wobble", container => {
14977
+ return Promise.resolve(new WobbleUpdater(container));
14978
+ });
14979
+ });
14980
+ }
14981
+
14982
+ async function loadFull(engine) {
14983
+ engine.checkVersion("4.2.1");
14984
+ await engine.pluginManager.register(async (e) => {
14985
+ const loadEmittersPluginBundle = async (e) => {
14986
+ await loadEmittersPlugin(e);
14987
+ await Promise.all([
14988
+ loadEmittersShapeCircle(e),
14989
+ loadEmittersShapeSquare(e),
14990
+ ]);
14991
+ }, loadInteractivityForFull = async (e) => {
14992
+ await loadSlim(e);
14993
+ await Promise.all([
14994
+ loadExternalDragInteraction(e),
14995
+ loadExternalTrailInteraction(e),
14996
+ loadAbsorbersPlugin(e),
14997
+ loadEmittersPluginBundle(e),
14998
+ ]);
14999
+ };
15000
+ await Promise.all([
15001
+ loadInteractivityForFull(e),
15002
+ loadDestroyUpdater(e),
15003
+ loadRollUpdater(e),
15004
+ loadTiltUpdater(e),
15005
+ loadTwinkleUpdater(e),
15006
+ loadWobbleUpdater(e),
15007
+ loadTextShape(e),
15008
+ ]);
15009
+ });
15010
+ }
15011
+
15012
+ const InterlaceOffsets = [0, 4, 2, 1];
15013
+ const InterlaceSteps = [8, 8, 4, 2];
15014
+
15015
+ class ByteStream {
15016
+ data;
15017
+ pos;
15018
+ constructor(bytes) {
15019
+ this.pos = 0;
15020
+ this.data = new Uint8ClampedArray(bytes);
15021
+ }
15022
+ getString(count) {
15023
+ const slice = this.data.slice(this.pos, this.pos + count);
15024
+ this.pos += slice.length;
15025
+ return slice.reduce((acc, curr) => acc + String.fromCharCode(curr), "");
15026
+ }
15027
+ nextByte() {
15028
+ return this.data[this.pos++];
15029
+ }
15030
+ nextTwoBytes() {
15031
+ const increment = 2, previous = 1, shift = 8;
15032
+ this.pos += increment;
15033
+ return this.data[this.pos - increment] + (this.data[this.pos - previous] << shift);
15034
+ }
15035
+ readSubBlocks() {
15036
+ let blockString = "", size;
15037
+ const minCount = 0, emptySize = 0;
15038
+ do {
15039
+ size = this.data[this.pos++];
15040
+ for (let count = size; --count >= minCount; blockString += String.fromCharCode(this.data[this.pos++])) {
15041
+ }
15042
+ } while (size !== emptySize);
15043
+ return blockString;
15044
+ }
15045
+ readSubBlocksBin() {
15046
+ let size = this.data[this.pos], len = 0;
15047
+ const emptySize = 0, increment = 1;
15048
+ for (let offset = 0; size !== emptySize; offset += size + increment, size = this.data[this.pos + offset]) {
15049
+ len += size;
15050
+ }
15051
+ const blockData = new Uint8Array(len);
15052
+ size = this.data[this.pos++];
15053
+ for (let i = 0; size !== emptySize; size = this.data[this.pos++]) {
15054
+ for (let count = size; --count >= emptySize; blockData[i++] = this.data[this.pos++]) {
15055
+ }
15056
+ }
15057
+ return blockData;
15058
+ }
15059
+ skipSubBlocks() {
15060
+ for (const increment = 1, noData = 0; this.data[this.pos] !== noData; this.pos += this.data[this.pos] + increment) {
15061
+ }
15062
+ this.pos++;
15063
+ }
15064
+ }
15065
+
15066
+ var DisposalMethod;
15067
+ (function (DisposalMethod) {
15068
+ DisposalMethod[DisposalMethod["Replace"] = 0] = "Replace";
15069
+ DisposalMethod[DisposalMethod["Combine"] = 1] = "Combine";
15070
+ DisposalMethod[DisposalMethod["RestoreBackground"] = 2] = "RestoreBackground";
15071
+ DisposalMethod[DisposalMethod["RestorePrevious"] = 3] = "RestorePrevious";
15072
+ DisposalMethod[DisposalMethod["UndefinedA"] = 4] = "UndefinedA";
15073
+ DisposalMethod[DisposalMethod["UndefinedB"] = 5] = "UndefinedB";
15074
+ DisposalMethod[DisposalMethod["UndefinedC"] = 6] = "UndefinedC";
15075
+ DisposalMethod[DisposalMethod["UndefinedD"] = 7] = "UndefinedD";
15076
+ })(DisposalMethod || (DisposalMethod = {}));
15077
+
15078
+ var GIFDataHeaders;
15079
+ (function (GIFDataHeaders) {
15080
+ GIFDataHeaders[GIFDataHeaders["Extension"] = 33] = "Extension";
15081
+ GIFDataHeaders[GIFDataHeaders["ApplicationExtension"] = 255] = "ApplicationExtension";
15082
+ GIFDataHeaders[GIFDataHeaders["GraphicsControlExtension"] = 249] = "GraphicsControlExtension";
15083
+ GIFDataHeaders[GIFDataHeaders["PlainTextExtension"] = 1] = "PlainTextExtension";
15084
+ GIFDataHeaders[GIFDataHeaders["CommentExtension"] = 254] = "CommentExtension";
15085
+ GIFDataHeaders[GIFDataHeaders["Image"] = 44] = "Image";
15086
+ GIFDataHeaders[GIFDataHeaders["EndOfFile"] = 59] = "EndOfFile";
15087
+ })(GIFDataHeaders || (GIFDataHeaders = {}));
15088
+
15089
+ const defaultFrame = 0, initialTime = 0, firstIndex$1 = 0, defaultLoopCount = 0;
15090
+ function parseColorTable(byteStream, count) {
15091
+ const colors = [];
15092
+ for (let i = 0; i < count; i++) {
15093
+ colors.push({
15094
+ r: byteStream.data[byteStream.pos],
15095
+ g: byteStream.data[byteStream.pos + 1],
15096
+ b: byteStream.data[byteStream.pos + 2],
15097
+ });
15098
+ byteStream.pos += 3;
15099
+ }
15100
+ return colors;
15101
+ }
15102
+ function parseExtensionBlock(byteStream, gif, getFrameIndex, getTransparencyIndex) {
15103
+ switch (byteStream.nextByte()) {
15104
+ case GIFDataHeaders.GraphicsControlExtension: {
15105
+ const frame = gif.frames[getFrameIndex(false)];
15106
+ byteStream.pos++;
15107
+ const packedByte = byteStream.nextByte();
15108
+ frame.GCreserved = (packedByte & 0xe0) >>> 5;
15109
+ frame.disposalMethod = (packedByte & 0x1c) >>> 2;
15110
+ frame.userInputDelayFlag = (packedByte & 2) === 2;
15111
+ const transparencyFlag = (packedByte & 1) === 1;
15112
+ frame.delayTime = byteStream.nextTwoBytes() * 0xa;
15113
+ const transparencyIndex = byteStream.nextByte();
15114
+ if (transparencyFlag) {
15115
+ getTransparencyIndex(transparencyIndex);
15116
+ }
15117
+ byteStream.pos++;
15118
+ break;
15119
+ }
15120
+ case GIFDataHeaders.ApplicationExtension: {
15121
+ byteStream.pos++;
15122
+ const applicationExtension = {
15123
+ identifier: byteStream.getString(8),
15124
+ authenticationCode: byteStream.getString(3),
15125
+ data: byteStream.readSubBlocksBin(),
15126
+ };
15127
+ gif.applicationExtensions.push(applicationExtension);
15128
+ break;
15129
+ }
15130
+ case GIFDataHeaders.CommentExtension: {
15131
+ gif.comments.push([getFrameIndex(false), byteStream.readSubBlocks()]);
15132
+ break;
15133
+ }
15134
+ case GIFDataHeaders.PlainTextExtension: {
15135
+ if (gif.globalColorTable.length === 0) {
15136
+ throw new EvalError("plain text extension without global color table");
15137
+ }
15138
+ byteStream.pos++;
15139
+ gif.frames[getFrameIndex(false)].plainTextData = {
15140
+ left: byteStream.nextTwoBytes(),
15141
+ top: byteStream.nextTwoBytes(),
15142
+ width: byteStream.nextTwoBytes(),
15143
+ height: byteStream.nextTwoBytes(),
15144
+ charSize: {
15145
+ width: byteStream.nextTwoBytes(),
15146
+ height: byteStream.nextTwoBytes(),
15147
+ },
15148
+ foregroundColor: byteStream.nextByte(),
15149
+ backgroundColor: byteStream.nextByte(),
15150
+ text: byteStream.readSubBlocks(),
15151
+ };
15152
+ break;
15153
+ }
15154
+ default:
15155
+ byteStream.skipSubBlocks();
15156
+ break;
15157
+ }
15158
+ }
15159
+ function readBits(imageData, pos, len) {
15160
+ const bytePos = pos >>> 3, bitPos = pos & 7;
15161
+ return (((imageData[bytePos] + (imageData[bytePos + 1] << 8) + (imageData[bytePos + 2] << 16)) &
15162
+ (((1 << len) - 1) << bitPos)) >>>
15163
+ bitPos);
15164
+ }
15165
+ async function parseImageBlock(byteStream, gif, avgAlpha, getFrameIndex, getTransparencyIndex, canvasSettings, progressCallback) {
15166
+ const frame = gif.frames[getFrameIndex(true)];
15167
+ frame.left = byteStream.nextTwoBytes();
15168
+ frame.top = byteStream.nextTwoBytes();
15169
+ frame.width = byteStream.nextTwoBytes();
15170
+ frame.height = byteStream.nextTwoBytes();
15171
+ const packedByte = byteStream.nextByte(), localColorTableFlag = (packedByte & 0x80) === 0x80, interlacedFlag = (packedByte & 0x40) === 0x40;
15172
+ frame.sortFlag = (packedByte & 0x20) === 0x20;
15173
+ frame.reserved = (packedByte & 0x18) >>> 3;
15174
+ const localColorCount = 1 << ((packedByte & 7) + 1);
15175
+ if (localColorTableFlag) {
15176
+ frame.localColorTable = parseColorTable(byteStream, localColorCount);
15177
+ }
15178
+ const getColor = (index) => {
15179
+ const { r, g, b } = (localColorTableFlag ? frame.localColorTable : gif.globalColorTable)[index];
15180
+ if (index !== getTransparencyIndex(null)) {
15181
+ return { r, g, b, a: 255 };
15182
+ }
15183
+ return { r, g, b, a: avgAlpha ? Math.trunc((r + g + b) / 3) : 0 };
15184
+ }, image = (() => {
15185
+ try {
15186
+ return new ImageData(frame.width, frame.height, canvasSettings);
15187
+ }
15188
+ catch (error) {
15189
+ if (error instanceof DOMException && error.name === "IndexSizeError") {
15190
+ return null;
15191
+ }
15192
+ throw error;
15193
+ }
15194
+ })();
15195
+ if (image == null) {
15196
+ throw new EvalError("GIF frame size is to large");
15197
+ }
15198
+ const minCodeSize = byteStream.nextByte(), imageData = byteStream.readSubBlocksBin(), clearCode = 1 << minCodeSize;
15199
+ if (interlacedFlag) {
15200
+ for (let code = 0, size = minCodeSize + 1, pos = 0, dic = [[0]], pass = 0; pass < 4; pass++) {
15201
+ if (InterlaceOffsets[pass] < frame.height) {
15202
+ let pixelPos = 0, lineIndex = 0, exit = false;
15203
+ while (!exit) {
15204
+ const last = code;
15205
+ code = readBits(imageData, pos, size);
15206
+ pos += size + 1;
15207
+ if (code === clearCode) {
15208
+ size = minCodeSize + 1;
15209
+ dic.length = clearCode + 2;
15210
+ for (let i = 0; i < dic.length; i++) {
15211
+ dic[i] = i < clearCode ? [i] : [];
15212
+ }
15213
+ }
15214
+ else {
15215
+ if (code >= dic.length) {
15216
+ dic.push(dic[last].concat(dic[last][0]));
15217
+ }
15218
+ else if (last !== clearCode) {
15219
+ dic.push(dic[last].concat(dic[code][0]));
15220
+ }
15221
+ for (const item of dic[code]) {
15222
+ const { r, g, b, a } = getColor(item);
15223
+ image.data.set([r, g, b, a], InterlaceOffsets[pass] * frame.width +
15224
+ InterlaceSteps[pass] * lineIndex +
15225
+ (pixelPos % (frame.width * 4)));
15226
+ pixelPos += 4;
15227
+ }
15228
+ if (dic.length === 1 << size && size < 0xc) {
15229
+ size++;
15230
+ }
15231
+ }
15232
+ if (pixelPos === frame.width * 4 * (lineIndex + 1)) {
15233
+ lineIndex++;
15234
+ if (InterlaceOffsets[pass] + InterlaceSteps[pass] * lineIndex >= frame.height) {
15235
+ exit = true;
15236
+ }
15237
+ }
15238
+ }
15239
+ }
15240
+ }
15241
+ frame.image = image;
15242
+ frame.bitmap = await createImageBitmap(image);
15243
+ }
15244
+ else {
15245
+ let code = 0, size = minCodeSize + 1, pos = 0, pixelPos = -4;
15246
+ const dic = [[0]];
15247
+ for (;;) {
15248
+ const last = code;
15249
+ code = readBits(imageData, pos, size);
15250
+ pos += size;
15251
+ if (code === clearCode) {
15252
+ size = minCodeSize + 1;
15253
+ dic.length = clearCode + 2;
15254
+ for (let i = 0; i < dic.length; i++) {
15255
+ dic[i] = i < clearCode ? [i] : [];
15256
+ }
15257
+ }
15258
+ else {
15259
+ if (code === clearCode + 1) {
15260
+ break;
15261
+ }
15262
+ if (code >= dic.length) {
15263
+ dic.push(dic[last].concat(dic[last][0]));
15264
+ }
15265
+ else if (last !== clearCode) {
15266
+ dic.push(dic[last].concat(dic[code][0]));
15267
+ }
15268
+ for (const item of dic[code]) {
15269
+ const { r, g, b, a } = getColor(item);
15270
+ pixelPos += 4;
15271
+ image.data.set([r, g, b, a], pixelPos);
15272
+ }
15273
+ if (dic.length >= 1 << size && size < 0xc) {
15274
+ size++;
15275
+ }
15276
+ }
15277
+ }
15278
+ frame.image = image;
15279
+ frame.bitmap = await createImageBitmap(image);
15280
+ }
15168
15281
  }
15169
-
15170
- class TwinkleLinksValues {
15171
- color;
15172
- enable = false;
15173
- frequency = 0.05;
15174
- opacity = 1;
15175
- load(data) {
15176
- if (isNull(data)) {
15177
- return;
15178
- }
15179
- if (data.color !== undefined) {
15180
- this.color = OptionsColor.create(this.color, data.color);
15181
- }
15182
- loadProperty(this, "enable", data.enable);
15183
- loadProperty(this, "frequency", data.frequency);
15184
- loadRangeProperty(this, "opacity", data.opacity);
15282
+ async function parseBlock(byteStream, gif, avgAlpha, getFrameIndex, getTransparencyIndex, canvasSettings, progressCallback) {
15283
+ switch (byteStream.nextByte()) {
15284
+ case GIFDataHeaders.EndOfFile:
15285
+ return true;
15286
+ case GIFDataHeaders.Image:
15287
+ await parseImageBlock(byteStream, gif, avgAlpha, getFrameIndex, getTransparencyIndex, canvasSettings);
15288
+ break;
15289
+ case GIFDataHeaders.Extension:
15290
+ parseExtensionBlock(byteStream, gif, getFrameIndex, getTransparencyIndex);
15291
+ break;
15292
+ default:
15293
+ throw new EvalError("undefined block found");
15185
15294
  }
15295
+ return false;
15186
15296
  }
15187
-
15188
- class TwinkleParticlesValues {
15189
- enable = false;
15190
- fillColor;
15191
- frequency = 0.05;
15192
- opacity = 1;
15193
- strokeColor;
15194
- load(data) {
15195
- if (isNull(data)) {
15196
- return;
15197
- }
15198
- if (data.fillColor !== undefined) {
15199
- this.fillColor = OptionsColor.create(this.fillColor, data.fillColor);
15200
- }
15201
- if (data.strokeColor !== undefined) {
15202
- this.strokeColor = OptionsColor.create(this.strokeColor, data.strokeColor);
15297
+ function getGIFLoopAmount(gif) {
15298
+ for (const extension of gif.applicationExtensions) {
15299
+ if (extension.identifier + extension.authenticationCode !== "NETSCAPE2.0") {
15300
+ continue;
15203
15301
  }
15204
- loadProperty(this, "enable", data.enable);
15205
- loadProperty(this, "frequency", data.frequency);
15206
- loadRangeProperty(this, "opacity", data.opacity);
15302
+ return extension.data[1] + (extension.data[2] << 8);
15207
15303
  }
15304
+ return Number.NaN;
15208
15305
  }
15209
-
15210
- class Twinkle {
15211
- links = new TwinkleLinksValues();
15212
- particles = new TwinkleParticlesValues();
15213
- load(data) {
15214
- if (isNull(data)) {
15215
- return;
15216
- }
15217
- this.links.load(data.links);
15218
- this.particles.load(data.particles);
15306
+ async function decodeGIF(gifURL, canvasSettings, progressCallback, avgAlpha) {
15307
+ avgAlpha ??= false;
15308
+ const res = await fetch(gifURL);
15309
+ if (!res.ok && res.status === 404) {
15310
+ throw new EvalError("file not found");
15219
15311
  }
15220
- }
15221
-
15222
- class TwinkleUpdater {
15223
- #container;
15224
- #pluginManager;
15225
- constructor(pluginManager, container) {
15226
- this.#pluginManager = pluginManager;
15227
- this.#container = container;
15312
+ const buffer = await res.arrayBuffer(), gif = {
15313
+ width: 0,
15314
+ height: 0,
15315
+ totalTime: 0,
15316
+ colorRes: 0,
15317
+ pixelAspectRatio: 0,
15318
+ frames: [],
15319
+ sortFlag: false,
15320
+ globalColorTable: [],
15321
+ backgroundImage: new ImageData(1, 1, canvasSettings),
15322
+ comments: [],
15323
+ applicationExtensions: [],
15324
+ }, byteStream = new ByteStream(new Uint8ClampedArray(buffer));
15325
+ if (byteStream.getString(6) !== "GIF89a") {
15326
+ throw new Error("not a supported GIF file");
15228
15327
  }
15229
- getColorStyles(particle, _context, _radius, opacity) {
15230
- const pOptions = particle.options, container = this.#container, twinkleOptions = pOptions["twinkle"];
15231
- if (!twinkleOptions) {
15232
- return {};
15233
- }
15234
- const twinkle = twinkleOptions.particles, twinkling = twinkle.enable && getRandom() < twinkle.frequency, zIndexOptions = particle.options.zIndex, zOffset = 1, zOpacityFactor = (zOffset - particle.zIndexFactor) ** zIndexOptions.opacityRate, twinklingOpacity = twinkling ? getRangeValue(twinkle.opacity) * zOpacityFactor : opacity, twinkleFillRgb = rangeColorToHsl(this.#pluginManager, twinkle.fillColor), twinkleStrokeRgb = rangeColorToHsl(this.#pluginManager, twinkle.strokeColor), getTwinkleFillStyle = () => {
15235
- if (!twinkleFillRgb) {
15236
- return undefined;
15237
- }
15238
- return getStyleFromHsl(twinkleFillRgb, container.hdr, twinklingOpacity);
15239
- }, getTwinkleStrokeStyle = () => {
15240
- if (!twinkleStrokeRgb) {
15241
- return undefined;
15242
- }
15243
- return getStyleFromHsl(twinkleStrokeRgb, container.hdr, twinklingOpacity);
15244
- }, twinkleFillStyle = getTwinkleFillStyle(), twinkleStrokeStyle = getTwinkleStrokeStyle(), res = {}, needsTwinkle = twinkling && (!!twinkleFillStyle || !!twinkleStrokeStyle);
15245
- res.fill = needsTwinkle ? twinkleFillStyle : undefined;
15246
- res.stroke = needsTwinkle ? twinkleStrokeStyle : undefined;
15247
- return res;
15328
+ gif.width = byteStream.nextTwoBytes();
15329
+ gif.height = byteStream.nextTwoBytes();
15330
+ const packedByte = byteStream.nextByte(), globalColorTableFlag = (packedByte & 0x80) === 0x80;
15331
+ gif.colorRes = (packedByte & 0x70) >>> 4;
15332
+ gif.sortFlag = (packedByte & 8) === 8;
15333
+ const globalColorCount = 1 << ((packedByte & 7) + 1), backgroundColorIndex = byteStream.nextByte();
15334
+ gif.pixelAspectRatio = byteStream.nextByte();
15335
+ if (gif.pixelAspectRatio !== 0) {
15336
+ gif.pixelAspectRatio = (gif.pixelAspectRatio + 0xf) / 0x40;
15248
15337
  }
15249
- init() {
15338
+ if (globalColorTableFlag) {
15339
+ gif.globalColorTable = parseColorTable(byteStream, globalColorCount);
15250
15340
  }
15251
- isEnabled(particle) {
15252
- const pOptions = particle.options, twinkleOptions = pOptions.twinkle;
15253
- if (!twinkleOptions) {
15254
- return false;
15341
+ const backgroundImage = (() => {
15342
+ try {
15343
+ return new ImageData(gif.width, gif.height, canvasSettings);
15255
15344
  }
15256
- return twinkleOptions.particles.enable;
15257
- }
15258
- loadOptions(options, ...sources) {
15259
- loadOptionProperty(options, "twinkle", Twinkle, ...sources);
15345
+ catch (error) {
15346
+ if (error instanceof DOMException && error.name === "IndexSizeError") {
15347
+ return null;
15348
+ }
15349
+ throw error;
15350
+ }
15351
+ })();
15352
+ if (backgroundImage == null) {
15353
+ throw new Error("GIF frame size is to large");
15260
15354
  }
15261
- update() {
15355
+ const { r, g, b } = gif.globalColorTable[backgroundColorIndex];
15356
+ backgroundImage.data.set(globalColorTableFlag ? [r, g, b, 255] : [0, 0, 0, 0]);
15357
+ for (let i = 4; i < backgroundImage.data.length; i *= 2) {
15358
+ backgroundImage.data.copyWithin(i, 0, i);
15262
15359
  }
15263
- }
15264
-
15265
- async function loadTwinkleUpdater(engine) {
15266
- engine.checkVersion("4.2.0");
15267
- await engine.pluginManager.register(e => {
15268
- e.pluginManager.addParticleUpdater("twinkle", container => {
15269
- return Promise.resolve(new TwinkleUpdater(e.pluginManager, container));
15270
- });
15271
- });
15272
- }
15273
-
15274
- class WobbleSpeed {
15275
- angle = 50;
15276
- move = 10;
15277
- load(data) {
15278
- if (isNull(data)) {
15279
- return;
15360
+ gif.backgroundImage = backgroundImage;
15361
+ let frameIndex = -1, incrementFrameIndex = true, transparencyIndex = -1;
15362
+ const getframeIndex = (increment) => {
15363
+ if (increment) {
15364
+ incrementFrameIndex = true;
15280
15365
  }
15281
- loadRangeProperty(this, "angle", data.angle);
15282
- loadRangeProperty(this, "move", data.move);
15283
- }
15284
- }
15285
-
15286
- class Wobble {
15287
- distance = 5;
15288
- enable = false;
15289
- speed = new WobbleSpeed();
15290
- load(data) {
15291
- if (isNull(data)) {
15292
- return;
15366
+ return frameIndex;
15367
+ }, getTransparencyIndex = (newValue) => {
15368
+ if (newValue != null) {
15369
+ transparencyIndex = newValue;
15293
15370
  }
15294
- loadRangeProperty(this, "distance", data.distance);
15295
- loadProperty(this, "enable", data.enable);
15296
- if (data.speed !== undefined) {
15297
- if (isNumber(data.speed)) {
15298
- this.speed.load({ angle: data.speed });
15299
- }
15300
- else {
15301
- const rangeSpeed = data.speed;
15302
- if ("min" in rangeSpeed) {
15303
- this.speed.load({ angle: rangeSpeed });
15304
- }
15305
- else {
15306
- this.speed.load(data.speed);
15307
- }
15371
+ return transparencyIndex;
15372
+ };
15373
+ try {
15374
+ do {
15375
+ if (incrementFrameIndex) {
15376
+ gif.frames.push({
15377
+ left: 0,
15378
+ top: 0,
15379
+ width: 0,
15380
+ height: 0,
15381
+ disposalMethod: DisposalMethod.Replace,
15382
+ image: new ImageData(1, 1, canvasSettings),
15383
+ plainTextData: null,
15384
+ userInputDelayFlag: false,
15385
+ delayTime: 0,
15386
+ sortFlag: false,
15387
+ localColorTable: [],
15388
+ reserved: 0,
15389
+ GCreserved: 0,
15390
+ });
15391
+ frameIndex++;
15392
+ transparencyIndex = -1;
15393
+ incrementFrameIndex = false;
15394
+ }
15395
+ } while (!(await parseBlock(byteStream, gif, avgAlpha, getframeIndex, getTransparencyIndex, canvasSettings, progressCallback)));
15396
+ gif.frames.length--;
15397
+ for (const frame of gif.frames) {
15398
+ if (frame.userInputDelayFlag && frame.delayTime === 0) {
15399
+ gif.totalTime = Infinity;
15400
+ break;
15308
15401
  }
15402
+ gif.totalTime += frame.delayTime;
15403
+ }
15404
+ return gif;
15405
+ }
15406
+ catch (error) {
15407
+ if (error instanceof EvalError) {
15408
+ throw new Error(`error while parsing frame ${frameIndex.toString()} "${error.message}"`, { cause: error });
15309
15409
  }
15410
+ throw error;
15310
15411
  }
15311
15412
  }
15312
-
15313
- const defaultDistance$1 = 0, distanceFactor = 60;
15314
- function updateWobble(container, particle, delta) {
15315
- const { wobble: wobbleOptions } = particle.options, { wobble } = particle;
15316
- if (!wobbleOptions?.enable || !wobble) {
15413
+ function drawGif(data, canvasSettings) {
15414
+ const { context, radius, particle, delta } = data, gifData = particle.gifData;
15415
+ if (!gifData) {
15317
15416
  return;
15318
15417
  }
15319
- const reduceFactor = container.retina.reduceFactor, angleSpeed = wobble.angleSpeed * delta.factor * reduceFactor, moveSpeed = wobble.moveSpeed * delta.factor * reduceFactor, distance = (moveSpeed * (particle.retina.wobbleDistance ?? defaultDistance$1)) / (millisecondsToSeconds$1 / distanceFactor), max = doublePI, { position } = particle;
15320
- wobble.angle += angleSpeed;
15321
- if (wobble.angle > max) {
15322
- wobble.angle -= max;
15418
+ const offscreenCanvas = new OffscreenCanvas(gifData.width, gifData.height), offscreenContext = offscreenCanvas.getContext("2d", canvasSettings);
15419
+ if (!offscreenContext) {
15420
+ throw new Error("could not create offscreen canvas context");
15323
15421
  }
15324
- position.x += distance * Math.cos(wobble.angle);
15325
- position.y += distance * Math.abs(Math.sin(wobble.angle));
15422
+ offscreenContext.imageSmoothingQuality = "low";
15423
+ offscreenContext.imageSmoothingEnabled = false;
15424
+ offscreenContext.clearRect(originPoint.x, originPoint.y, offscreenCanvas.width, offscreenCanvas.height);
15425
+ let frameIndex = particle.gifFrame ?? defaultFrame;
15426
+ const pos = { x: -gifData.width * half$2, y: -gifData.height * half$2 }, frame = gifData.frames[frameIndex];
15427
+ particle.gifTime ??= initialTime;
15428
+ if (!frame.bitmap) {
15429
+ return;
15430
+ }
15431
+ context.scale(radius / gifData.width, radius / gifData.height);
15432
+ switch (frame.disposalMethod) {
15433
+ case DisposalMethod.UndefinedA:
15434
+ case DisposalMethod.UndefinedB:
15435
+ case DisposalMethod.UndefinedC:
15436
+ case DisposalMethod.UndefinedD:
15437
+ case DisposalMethod.Replace:
15438
+ offscreenContext.drawImage(frame.bitmap, frame.left, frame.top);
15439
+ context.drawImage(offscreenCanvas, pos.x, pos.y);
15440
+ offscreenContext.clearRect(originPoint.x, originPoint.y, offscreenCanvas.width, offscreenCanvas.height);
15441
+ break;
15442
+ case DisposalMethod.Combine:
15443
+ offscreenContext.drawImage(frame.bitmap, frame.left, frame.top);
15444
+ context.drawImage(offscreenCanvas, pos.x, pos.y);
15445
+ break;
15446
+ case DisposalMethod.RestoreBackground:
15447
+ offscreenContext.drawImage(frame.bitmap, frame.left, frame.top);
15448
+ context.drawImage(offscreenCanvas, pos.x, pos.y);
15449
+ offscreenContext.clearRect(originPoint.x, originPoint.y, offscreenCanvas.width, offscreenCanvas.height);
15450
+ if (!gifData.globalColorTable.length) {
15451
+ offscreenContext.putImageData(gifData.frames[firstIndex$1].image, pos.x + frame.left, pos.y + frame.top);
15452
+ }
15453
+ else {
15454
+ offscreenContext.putImageData(gifData.backgroundImage, pos.x, pos.y);
15455
+ }
15456
+ break;
15457
+ case DisposalMethod.RestorePrevious:
15458
+ {
15459
+ const previousImageData = offscreenContext.getImageData(originPoint.x, originPoint.y, offscreenCanvas.width, offscreenCanvas.height);
15460
+ offscreenContext.drawImage(frame.bitmap, frame.left, frame.top);
15461
+ context.drawImage(offscreenCanvas, pos.x, pos.y);
15462
+ offscreenContext.clearRect(originPoint.x, originPoint.y, offscreenCanvas.width, offscreenCanvas.height);
15463
+ offscreenContext.putImageData(previousImageData, originPoint.x, originPoint.y);
15464
+ }
15465
+ break;
15466
+ }
15467
+ particle.gifTime += delta.value;
15468
+ if (particle.gifTime > frame.delayTime) {
15469
+ particle.gifTime -= frame.delayTime;
15470
+ if (++frameIndex >= gifData.frames.length) {
15471
+ if (particle.gifLoopCount == null || --particle.gifLoopCount <= defaultLoopCount) {
15472
+ return;
15473
+ }
15474
+ frameIndex = firstIndex$1;
15475
+ offscreenContext.clearRect(originPoint.x, originPoint.y, offscreenCanvas.width, offscreenCanvas.height);
15476
+ }
15477
+ particle.gifFrame = frameIndex;
15478
+ }
15479
+ context.scale(gifData.width / radius, gifData.height / radius);
15326
15480
  }
15327
15481
 
15328
- const maxAngle$1 = 360, moveSpeedFactor$1 = 10, defaultDistance = 0;
15329
- class WobbleUpdater {
15482
+ class GifDrawer {
15330
15483
  #container;
15484
+ #gifCache;
15331
15485
  constructor(container) {
15332
15486
  this.#container = container;
15487
+ this.#gifCache = new Map();
15333
15488
  }
15334
- init(particle) {
15335
- const wobbleOpt = particle.options.wobble;
15336
- if (wobbleOpt?.enable) {
15337
- particle.wobble = {
15338
- angle: getRandom() * doublePI,
15339
- angleSpeed: getRangeValue(wobbleOpt.speed.angle) / maxAngle$1,
15340
- moveSpeed: getRangeValue(wobbleOpt.speed.move) / moveSpeedFactor$1,
15341
- };
15342
- }
15343
- else {
15344
- particle.wobble = {
15345
- angle: 0,
15346
- angleSpeed: 0,
15347
- moveSpeed: 0,
15348
- };
15349
- }
15350
- particle.retina.wobbleDistance =
15351
- getRangeValue(wobbleOpt?.distance ?? defaultDistance) * this.#container.retina.pixelRatio;
15489
+ destroy() {
15490
+ this.#gifCache.clear();
15352
15491
  }
15353
- isEnabled(particle) {
15354
- return !particle.destroyed && !particle.spawning && !!particle.options.wobble?.enable;
15492
+ draw(data) {
15493
+ const { context, opacity } = data;
15494
+ if (!data.particle.gifData)
15495
+ return;
15496
+ context.globalAlpha = opacity;
15497
+ drawGif(data, this.#container.canvas.render.settings);
15498
+ context.globalAlpha = 1;
15355
15499
  }
15356
- loadOptions(options, ...sources) {
15357
- loadOptionProperty(options, "wobble", Wobble, ...sources);
15500
+ loadShape(particle) {
15501
+ const shapeData = particle.shapeData;
15502
+ if (!shapeData?.src)
15503
+ return;
15504
+ if (this.#gifCache.has(shapeData.src))
15505
+ return;
15506
+ void decodeGIF(shapeData.src, { colorSpace: "srgb" }).then(gifData => {
15507
+ this.#gifCache.set(shapeData.src, gifData);
15508
+ });
15358
15509
  }
15359
- update(particle, delta) {
15360
- if (!this.isEnabled(particle)) {
15510
+ particleInit(container, particle) {
15511
+ const shapeData = particle.shapeData;
15512
+ if (!shapeData?.src)
15513
+ return;
15514
+ const gifData = this.#gifCache.get(shapeData.src);
15515
+ if (!gifData) {
15516
+ setTimeout(() => {
15517
+ this.particleInit(container, particle);
15518
+ });
15361
15519
  return;
15362
15520
  }
15363
- updateWobble(this.#container, particle, delta);
15521
+ particle.gifData = gifData;
15522
+ particle.gifFrame = 0;
15523
+ particle.gifTime = 0;
15524
+ particle.gifLoopCount = getGIFLoopAmount(gifData);
15525
+ if (particle.gifLoopCount === 0) {
15526
+ particle.gifLoopCount = Number.POSITIVE_INFINITY;
15527
+ }
15528
+ if (shapeData.loopCount !== undefined) {
15529
+ particle.gifLoopCount = shapeData.loopCount;
15530
+ }
15364
15531
  }
15365
15532
  }
15366
15533
 
15367
- async function loadWobbleUpdater(engine) {
15368
- engine.checkVersion("4.2.0");
15534
+ async function loadGifShape(engine) {
15535
+ engine.checkVersion("4.3.0");
15369
15536
  await engine.pluginManager.register(e => {
15370
- e.pluginManager.addParticleUpdater("wobble", container => {
15371
- return Promise.resolve(new WobbleUpdater(container));
15372
- });
15373
- });
15374
- }
15375
-
15376
- async function loadFull(engine) {
15377
- engine.checkVersion("4.2.0");
15378
- await engine.pluginManager.register(async (e) => {
15379
- const loadEmittersPluginBundle = async (e) => {
15380
- await loadEmittersPlugin(e);
15381
- await Promise.all([
15382
- loadEmittersShapeCircle(e),
15383
- loadEmittersShapeSquare(e),
15384
- ]);
15385
- }, loadInteractivityForFull = async (e) => {
15386
- await loadSlim(e);
15387
- await Promise.all([
15388
- loadExternalDragInteraction(e),
15389
- loadExternalTrailInteraction(e),
15390
- loadAbsorbersPlugin(e),
15391
- loadEmittersPluginBundle(e),
15392
- ]);
15393
- };
15394
- await Promise.all([
15395
- loadInteractivityForFull(e),
15396
- loadDestroyUpdater(e),
15397
- loadRollUpdater(e),
15398
- loadTiltUpdater(e),
15399
- loadTwinkleUpdater(e),
15400
- loadWobbleUpdater(e),
15401
- loadTextShape(e),
15402
- ]);
15537
+ e.pluginManager.addShape(["gif", "gifs"], container => Promise.resolve(new GifDrawer(container)));
15403
15538
  });
15404
15539
  }
15405
15540
 
@@ -15513,14 +15648,14 @@
15513
15648
  }
15514
15649
  }
15515
15650
 
15516
- function updateGradient(particle, delta) {
15651
+ function updateGradient(particle, delta, hdr) {
15517
15652
  const { gradient } = particle;
15518
15653
  if (!gradient) {
15519
15654
  return;
15520
15655
  }
15521
15656
  updateAnimation(particle, gradient.angle, false, exports.DestroyType.none, delta);
15522
15657
  for (const color of gradient.colors) {
15523
- updateColor(color.value, delta);
15658
+ updateColor(color.value, delta, hdr);
15524
15659
  if (color.opacity) {
15525
15660
  updateAnimation(particle, color.opacity, true, exports.DestroyType.none, delta);
15526
15661
  }
@@ -15652,12 +15787,12 @@
15652
15787
  }
15653
15788
  }
15654
15789
  update(particle, delta) {
15655
- updateGradient(particle, delta);
15790
+ updateGradient(particle, delta, this.#container.hdr);
15656
15791
  }
15657
15792
  }
15658
15793
 
15659
15794
  async function loadGradientUpdater(engine) {
15660
- engine.checkVersion("4.2.0");
15795
+ engine.checkVersion("4.2.1");
15661
15796
  await engine.pluginManager.register(e => {
15662
15797
  e.pluginManager.addParticleUpdater("gradient", container => {
15663
15798
  return Promise.resolve(new GradientUpdater(e.pluginManager, container));
@@ -15777,7 +15912,7 @@
15777
15912
 
15778
15913
  const gridPathName = "gridPathGenerator";
15779
15914
  async function loadGridPath(engine) {
15780
- engine.checkVersion("4.2.0");
15915
+ engine.checkVersion("4.2.1");
15781
15916
  await engine.pluginManager.register((e) => {
15782
15917
  ensureBaseMoverLoaded(e);
15783
15918
  e.pluginManager.addPathGenerator?.(gridPathName, container => {
@@ -15806,7 +15941,7 @@
15806
15941
  }
15807
15942
 
15808
15943
  async function loadHeartShape(engine) {
15809
- engine.checkVersion("4.2.0");
15944
+ engine.checkVersion("4.2.1");
15810
15945
  await engine.pluginManager.register(e => {
15811
15946
  e.pluginManager.addShape(["heart"], () => Promise.resolve(new HeartDrawer()));
15812
15947
  });
@@ -15922,7 +16057,7 @@
15922
16057
  }
15923
16058
 
15924
16059
  async function loadHsvColorPlugin(engine) {
15925
- engine.checkVersion("4.2.0");
16060
+ engine.checkVersion("4.2.1");
15926
16061
  await engine.pluginManager.register(e => {
15927
16062
  e.pluginManager.addColorManager("hsv", new HsvColorManager());
15928
16063
  });
@@ -16007,7 +16142,7 @@
16007
16142
  }
16008
16143
 
16009
16144
  async function loadHwbColorPlugin(engine) {
16010
- engine.checkVersion("4.2.0");
16145
+ engine.checkVersion("4.2.1");
16011
16146
  await engine.pluginManager.register(e => {
16012
16147
  e.pluginManager.addColorManager("hwb", new HwbColorManager());
16013
16148
  });
@@ -16155,7 +16290,7 @@
16155
16290
  }
16156
16291
 
16157
16292
  async function loadInfectionPlugin(engine) {
16158
- engine.checkVersion("4.2.0");
16293
+ engine.checkVersion("4.2.1");
16159
16294
  await engine.pluginManager.register((e) => {
16160
16295
  ensureInteractivityPluginLoaded(e);
16161
16296
  e.pluginManager.addPlugin(new InfectionPlugin());
@@ -16181,7 +16316,7 @@
16181
16316
  }
16182
16317
 
16183
16318
  async function loadInfinityShape(engine) {
16184
- engine.checkVersion("4.2.0");
16319
+ engine.checkVersion("4.2.1");
16185
16320
  await engine.pluginManager.register(e => {
16186
16321
  e.pluginManager.addShape(["infinity"], () => Promise.resolve(new InfinityDrawer()));
16187
16322
  });
@@ -16282,7 +16417,7 @@
16282
16417
  }
16283
16418
 
16284
16419
  async function loadLabColorPlugin(engine) {
16285
- engine.checkVersion("4.2.0");
16420
+ engine.checkVersion("4.2.1");
16286
16421
  await engine.pluginManager.register(e => {
16287
16422
  e.pluginManager.addColorManager("lab", new LabColorManager());
16288
16423
  });
@@ -16383,7 +16518,7 @@
16383
16518
  }
16384
16519
 
16385
16520
  async function loadLchColorPlugin(engine) {
16386
- engine.checkVersion("4.2.0");
16521
+ engine.checkVersion("4.2.1");
16387
16522
  await engine.pluginManager.register(e => {
16388
16523
  e.pluginManager.addColorManager("lch", new LchColorManager());
16389
16524
  });
@@ -16437,7 +16572,7 @@
16437
16572
 
16438
16573
  const levyPathName = "levyPathGenerator";
16439
16574
  async function loadLevyPath(engine) {
16440
- engine.checkVersion("4.2.0");
16575
+ engine.checkVersion("4.2.1");
16441
16576
  await engine.pluginManager.register((e) => {
16442
16577
  ensureBaseMoverLoaded(e);
16443
16578
  e.pluginManager.addPathGenerator?.(levyPathName, container => {
@@ -16653,7 +16788,7 @@
16653
16788
  }
16654
16789
 
16655
16790
  async function loadLightInteraction(engine) {
16656
- engine.checkVersion("4.2.0");
16791
+ engine.checkVersion("4.2.1");
16657
16792
  await engine.pluginManager.register((e) => {
16658
16793
  ensureInteractivityPluginLoaded(e);
16659
16794
  e.pluginManager.addInteractor?.("externalLight", container => {
@@ -16711,7 +16846,7 @@
16711
16846
  }
16712
16847
 
16713
16848
  async function loadManualParticlesPlugin(engine) {
16714
- engine.checkVersion("4.2.0");
16849
+ engine.checkVersion("4.2.1");
16715
16850
  await engine.pluginManager.register(e => {
16716
16851
  e.pluginManager.addPlugin(new ManualParticlesPlugin());
16717
16852
  });
@@ -16932,7 +17067,7 @@
16932
17067
  }
16933
17068
 
16934
17069
  async function loadMatrixShape(engine) {
16935
- engine.checkVersion("4.2.0");
17070
+ engine.checkVersion("4.2.1");
16936
17071
  await engine.pluginManager.register(e => {
16937
17072
  e.pluginManager.addShape(["matrix"], () => Promise.resolve(new MatrixDrawer()));
16938
17073
  });
@@ -16984,7 +17119,7 @@
16984
17119
  }
16985
17120
 
16986
17121
  async function loadMotionPlugin(engine) {
16987
- engine.checkVersion("4.2.0");
17122
+ engine.checkVersion("4.2.1");
16988
17123
  await engine.pluginManager.register(e => {
16989
17124
  e.pluginManager.addPlugin(new MotionPlugin());
16990
17125
  });
@@ -17167,7 +17302,7 @@
17167
17302
  }
17168
17303
 
17169
17304
  async function loadNamedColorPlugin(engine) {
17170
- engine.checkVersion("4.2.0");
17305
+ engine.checkVersion("4.2.1");
17171
17306
  await engine.pluginManager.register(e => {
17172
17307
  e.pluginManager.addColorManager("named", new NamedColorManager());
17173
17308
  });
@@ -17263,7 +17398,7 @@
17263
17398
  }
17264
17399
 
17265
17400
  async function loadOklabColorPlugin(engine) {
17266
- engine.checkVersion("4.2.0");
17401
+ engine.checkVersion("4.2.1");
17267
17402
  await engine.pluginManager.register(e => {
17268
17403
  e.pluginManager.addColorManager("oklab", new OklabColorManager());
17269
17404
  });
@@ -17359,7 +17494,7 @@
17359
17494
  }
17360
17495
 
17361
17496
  async function loadOklchColorPlugin(engine) {
17362
- engine.checkVersion("4.2.0");
17497
+ engine.checkVersion("4.2.1");
17363
17498
  await engine.pluginManager.register(e => {
17364
17499
  e.pluginManager.addColorManager("oklch", new OklchColorManager());
17365
17500
  });
@@ -17494,7 +17629,7 @@
17494
17629
  }
17495
17630
 
17496
17631
  async function loadOrbitUpdater(engine) {
17497
- engine.checkVersion("4.2.0");
17632
+ engine.checkVersion("4.2.1");
17498
17633
  await engine.pluginManager.register(e => {
17499
17634
  e.pluginManager.addParticleUpdater("orbit", container => {
17500
17635
  return Promise.resolve(new OrbitUpdater(e.pluginManager, container));
@@ -17534,7 +17669,7 @@
17534
17669
  }
17535
17670
 
17536
17671
  async function loadParticlesEffect(engine) {
17537
- engine.checkVersion("4.2.0");
17672
+ engine.checkVersion("4.2.1");
17538
17673
  await engine.pluginManager.register(e => {
17539
17674
  e.pluginManager.addEffect("particles", container => {
17540
17675
  return Promise.resolve(new ParticlesDrawer(container));
@@ -17626,7 +17761,7 @@
17626
17761
  }
17627
17762
 
17628
17763
  async function loadParticlesRepulseInteraction(engine) {
17629
- engine.checkVersion("4.2.0");
17764
+ engine.checkVersion("4.2.1");
17630
17765
  await engine.pluginManager.register((e) => {
17631
17766
  ensureInteractivityPluginLoaded(e);
17632
17767
  e.pluginManager.addInteractor?.("particlesRepulse", container => {
@@ -17653,7 +17788,7 @@
17653
17788
  }
17654
17789
 
17655
17790
  async function loadPathShape(engine) {
17656
- engine.checkVersion("4.2.0");
17791
+ engine.checkVersion("4.2.1");
17657
17792
  await engine.pluginManager.register(e => {
17658
17793
  e.pluginManager.addShape(["path"], () => Promise.resolve(new PathDrawer()));
17659
17794
  });
@@ -18057,7 +18192,7 @@
18057
18192
 
18058
18193
  const perlinNoisePathName = "perlinNoise";
18059
18194
  async function loadPerlinNoisePath(engine) {
18060
- engine.checkVersion("4.2.0");
18195
+ engine.checkVersion("4.2.1");
18061
18196
  await engine.pluginManager.register((e) => {
18062
18197
  ensureBaseMoverLoaded(e);
18063
18198
  e.pluginManager.addPathGenerator?.(perlinNoisePathName, container => {
@@ -18105,7 +18240,7 @@
18105
18240
  }
18106
18241
 
18107
18242
  async function loadPoissonDiscPlugin(engine) {
18108
- engine.checkVersion("4.2.0");
18243
+ engine.checkVersion("4.2.1");
18109
18244
  await engine.pluginManager.register(e => {
18110
18245
  e.pluginManager.addPlugin(new PoissonDiscPlugin());
18111
18246
  });
@@ -18292,7 +18427,7 @@
18292
18427
  }
18293
18428
 
18294
18429
  async function loadPolygonMaskPlugin(engine) {
18295
- engine.checkVersion("4.2.0");
18430
+ engine.checkVersion("4.2.1");
18296
18431
  await engine.pluginManager.register(e => {
18297
18432
  e.pluginManager.addPlugin(new PolygonMaskPlugin(e.pluginManager));
18298
18433
  });
@@ -18358,7 +18493,7 @@
18358
18493
 
18359
18494
  const polygonPathName = "polygonPathGenerator";
18360
18495
  async function loadPolygonPath(engine) {
18361
- engine.checkVersion("4.2.0");
18496
+ engine.checkVersion("4.2.1");
18362
18497
  await engine.pluginManager.register((e) => {
18363
18498
  ensureBaseMoverLoaded(e);
18364
18499
  e.pluginManager.addPathGenerator?.(polygonPathName, container => {
@@ -18388,7 +18523,7 @@
18388
18523
 
18389
18524
  const randomPathName = "randomPathGenerator";
18390
18525
  async function loadRandomPath(engine) {
18391
- engine.checkVersion("4.2.0");
18526
+ engine.checkVersion("4.2.1");
18392
18527
  await engine.pluginManager.register((e) => {
18393
18528
  ensureBaseMoverLoaded(e);
18394
18529
  e.pluginManager.addPathGenerator?.(randomPathName, () => {
@@ -18468,7 +18603,7 @@
18468
18603
  }
18469
18604
 
18470
18605
  async function loadResponsivePlugin(engine) {
18471
- engine.checkVersion("4.2.0");
18606
+ engine.checkVersion("4.2.1");
18472
18607
  await engine.pluginManager.register(e => {
18473
18608
  e.pluginManager.addPlugin(new ResponsivePlugin());
18474
18609
  });
@@ -18866,7 +19001,7 @@
18866
19001
  }
18867
19002
 
18868
19003
  async function loadRibbonShape(engine) {
18869
- engine.checkVersion("4.2.0");
19004
+ engine.checkVersion("4.2.1");
18870
19005
  await engine.pluginManager.register(e => {
18871
19006
  e.pluginManager.addShape(["ribbon"], (container) => Promise.resolve(new RibbonDrawer(container)));
18872
19007
  });
@@ -18915,7 +19050,7 @@
18915
19050
  }
18916
19051
 
18917
19052
  async function loadRoundedPolygonShape(engine) {
18918
- engine.checkVersion("4.2.0");
19053
+ engine.checkVersion("4.2.1");
18919
19054
  await engine.pluginManager.register(e => {
18920
19055
  e.pluginManager.addShape(["rounded-polygon"], () => Promise.resolve(new RoundedPolygonDrawer()));
18921
19056
  });
@@ -18962,7 +19097,7 @@
18962
19097
  }
18963
19098
 
18964
19099
  async function loadRoundedRectShape(engine) {
18965
- engine.checkVersion("4.2.0");
19100
+ engine.checkVersion("4.2.1");
18966
19101
  await engine.pluginManager.register(e => {
18967
19102
  e.pluginManager.addShape(["rounded-rect"], () => Promise.resolve(new RoundedRectDrawer()));
18968
19103
  });
@@ -19120,7 +19255,7 @@
19120
19255
 
19121
19256
  const svgPathName = "svgPathGenerator";
19122
19257
  async function loadSVGPath(engine) {
19123
- engine.checkVersion("4.2.0");
19258
+ engine.checkVersion("4.2.1");
19124
19259
  await engine.pluginManager.register((e) => {
19125
19260
  ensureBaseMoverLoaded(e);
19126
19261
  e.pluginManager.addPathGenerator?.(svgPathName, container => {
@@ -19161,7 +19296,7 @@
19161
19296
  }
19162
19297
 
19163
19298
  async function loadShadowEffect(engine) {
19164
- engine.checkVersion("4.2.0");
19299
+ engine.checkVersion("4.2.1");
19165
19300
  await engine.pluginManager.register(e => {
19166
19301
  e.pluginManager.addEffect("shadow", container => {
19167
19302
  return Promise.resolve(new ShadowDrawer(e.pluginManager, container));
@@ -19183,7 +19318,7 @@
19183
19318
 
19184
19319
  const simplexNoisePathName = "simplexNoise";
19185
19320
  async function loadSimplexNoisePath(engine) {
19186
- engine.checkVersion("4.2.0");
19321
+ engine.checkVersion("4.2.1");
19187
19322
  await engine.pluginManager.register((e) => {
19188
19323
  ensureBaseMoverLoaded(e);
19189
19324
  e.pluginManager.addPathGenerator?.(simplexNoisePathName, container => {
@@ -19500,7 +19635,7 @@
19500
19635
  }
19501
19636
 
19502
19637
  async function loadSoundsPlugin(engine) {
19503
- engine.checkVersion("4.2.0");
19638
+ engine.checkVersion("4.2.1");
19504
19639
  await engine.pluginManager.register(e => {
19505
19640
  e.pluginManager.addPlugin(new SoundsPlugin(e));
19506
19641
  });
@@ -19569,7 +19704,7 @@
19569
19704
 
19570
19705
  const spiralPathName = "spiralPathGenerator";
19571
19706
  async function loadSpiralPath(engine) {
19572
- engine.checkVersion("4.2.0");
19707
+ engine.checkVersion("4.2.1");
19573
19708
  await engine.pluginManager.register((e) => {
19574
19709
  ensureBaseMoverLoaded(e);
19575
19710
  e.pluginManager.addPathGenerator?.(spiralPathName, container => {
@@ -19609,7 +19744,7 @@
19609
19744
  }
19610
19745
 
19611
19746
  async function loadSpiralShape(engine) {
19612
- engine.checkVersion("4.2.0");
19747
+ engine.checkVersion("4.2.1");
19613
19748
  await engine.pluginManager.register(e => {
19614
19749
  e.pluginManager.addShape(["spiral"], () => Promise.resolve(new SpiralDrawer()));
19615
19750
  });
@@ -19653,7 +19788,7 @@
19653
19788
  }
19654
19789
 
19655
19790
  async function loadSquircleShape(engine) {
19656
- engine.checkVersion("4.2.0");
19791
+ engine.checkVersion("4.2.1");
19657
19792
  await engine.pluginManager.register(e => {
19658
19793
  e.pluginManager.addShape(["squircle"], () => Promise.resolve(new SquircleDrawer()));
19659
19794
  });
@@ -19757,7 +19892,7 @@
19757
19892
  }
19758
19893
 
19759
19894
  async function loadThemesPlugin(engine) {
19760
- engine.checkVersion("4.2.0");
19895
+ engine.checkVersion("4.2.1");
19761
19896
  await engine.pluginManager.register(e => {
19762
19897
  e.pluginManager.addPlugin(new ThemesPlugin());
19763
19898
  });
@@ -19873,7 +20008,7 @@
19873
20008
  }
19874
20009
 
19875
20010
  async function loadTrailEffect(engine) {
19876
- engine.checkVersion("4.2.0");
20011
+ engine.checkVersion("4.2.1");
19877
20012
  await engine.pluginManager.register(e => {
19878
20013
  e.pluginManager.addEffect("trail", container => {
19879
20014
  return Promise.resolve(new TrailDrawer(container));
@@ -19937,7 +20072,7 @@
19937
20072
  }
19938
20073
 
19939
20074
  async function loadTrailPlugin(engine) {
19940
- engine.checkVersion("4.2.0");
20075
+ engine.checkVersion("4.2.1");
19941
20076
  await engine.pluginManager.register(e => {
19942
20077
  e.pluginManager.addPlugin(new TrailPlugin(e.pluginManager));
19943
20078
  });
@@ -19986,7 +20121,7 @@
19986
20121
 
19987
20122
  const zigZagPathName = "zigZagPathGenerator";
19988
20123
  async function loadZigZagPath(engine) {
19989
- engine.checkVersion("4.2.0");
20124
+ engine.checkVersion("4.2.1");
19990
20125
  await engine.pluginManager.register((e) => {
19991
20126
  ensureBaseMoverLoaded(e);
19992
20127
  e.pluginManager.addPathGenerator?.(zigZagPathName, container => {
@@ -20043,14 +20178,14 @@
20043
20178
  }
20044
20179
 
20045
20180
  async function loadZoomPlugin(engine) {
20046
- engine.checkVersion("4.2.0");
20181
+ engine.checkVersion("4.2.1");
20047
20182
  await engine.pluginManager.register(e => {
20048
20183
  e.pluginManager.addPlugin(new ZoomPlugin());
20049
20184
  });
20050
20185
  }
20051
20186
 
20052
20187
  async function loadAll(engine) {
20053
- engine.checkVersion("4.2.0");
20188
+ engine.checkVersion("4.3.0");
20054
20189
  await engine.pluginManager.register(async (e) => {
20055
20190
  const loadInteractionsForAll = async (e) => {
20056
20191
  await loadFull(e);
@@ -20126,6 +20261,7 @@
20126
20261
  loadArrowShape(e),
20127
20262
  loadCardsShape(e),
20128
20263
  loadCogShape(e),
20264
+ loadGifShape(e),
20129
20265
  loadHeartShape(e),
20130
20266
  loadInfinityShape(e),
20131
20267
  loadMatrixShape(e),
@@ -20151,10 +20287,10 @@
20151
20287
  }
20152
20288
  }
20153
20289
  class RenderManager {
20290
+ #backgroundElement;
20291
+ #backgroundWarnings;
20154
20292
  #canvasClearPlugins;
20155
20293
  #canvasManager;
20156
- #canvasPaintPlugins;
20157
- #clearDrawPlugins;
20158
20294
  #colorPlugins;
20159
20295
  #container;
20160
20296
  #context;
@@ -20162,9 +20298,7 @@
20162
20298
  #drawParticlePlugins;
20163
20299
  #drawParticlesCleanupPlugins;
20164
20300
  #drawParticlesSetupPlugins;
20165
- #drawPlugins;
20166
- #drawSettingsCleanupPlugins;
20167
- #drawSettingsSetupPlugins;
20301
+ #layers;
20168
20302
  #pluginManager;
20169
20303
  #postDrawUpdaters;
20170
20304
  #preDrawUpdaters;
@@ -20176,18 +20310,25 @@
20176
20310
  this.#container = container;
20177
20311
  this.#canvasManager = canvasManager;
20178
20312
  this.#context = null;
20313
+ this.#backgroundElement = null;
20314
+ this.#backgroundWarnings = new Set();
20179
20315
  this.#preDrawUpdaters = [];
20180
20316
  this.#postDrawUpdaters = [];
20181
- this.#colorPlugins = [];
20182
20317
  this.#canvasClearPlugins = [];
20183
- this.#canvasPaintPlugins = [];
20184
- this.#clearDrawPlugins = [];
20318
+ this.#colorPlugins = [];
20185
20319
  this.#drawParticlePlugins = [];
20186
20320
  this.#drawParticlesCleanupPlugins = [];
20187
20321
  this.#drawParticlesSetupPlugins = [];
20188
- this.#drawPlugins = [];
20189
- this.#drawSettingsSetupPlugins = [];
20190
- this.#drawSettingsCleanupPlugins = [];
20322
+ this.#layers = {
20323
+ 0: [],
20324
+ 1: [],
20325
+ 2: [],
20326
+ 3: [],
20327
+ 4: [],
20328
+ 5: [],
20329
+ 6: [],
20330
+ 7: [],
20331
+ };
20191
20332
  }
20192
20333
  get settings() {
20193
20334
  return this.#contextSettings;
@@ -20201,32 +20342,38 @@
20201
20342
  });
20202
20343
  }
20203
20344
  clear() {
20204
- let pluginHandled = false;
20205
20345
  for (const plugin of this.#canvasClearPlugins) {
20206
- pluginHandled = plugin.canvasClear?.() ?? false;
20207
- if (pluginHandled) {
20208
- break;
20346
+ if (plugin.canvasClear?.() ?? false) {
20347
+ return;
20209
20348
  }
20210
20349
  }
20211
- if (pluginHandled) {
20212
- return;
20350
+ for (const layer of Object.values(exports.DrawLayer)) {
20351
+ if (typeof layer === "number") {
20352
+ for (const plugin of this.#getLayerPlugins(layer)) {
20353
+ if (plugin.canvasClear?.() ?? false) {
20354
+ return;
20355
+ }
20356
+ }
20357
+ }
20213
20358
  }
20214
20359
  this.canvasClear();
20215
20360
  }
20216
20361
  destroy() {
20217
20362
  this.stop();
20363
+ this.#backgroundElement = null;
20364
+ this.#backgroundWarnings.clear();
20218
20365
  this.#preDrawUpdaters = [];
20219
20366
  this.#postDrawUpdaters = [];
20220
- this.#colorPlugins = [];
20221
20367
  this.#canvasClearPlugins = [];
20222
- this.#canvasPaintPlugins = [];
20223
- this.#clearDrawPlugins = [];
20368
+ this.#colorPlugins = [];
20224
20369
  this.#drawParticlePlugins = [];
20225
20370
  this.#drawParticlesCleanupPlugins = [];
20226
20371
  this.#drawParticlesSetupPlugins = [];
20227
- this.#drawPlugins = [];
20228
- this.#drawSettingsSetupPlugins = [];
20229
- this.#drawSettingsCleanupPlugins = [];
20372
+ for (const layer of Object.values(exports.DrawLayer)) {
20373
+ if (typeof layer === "number") {
20374
+ this.#layers[layer] = [];
20375
+ }
20376
+ }
20230
20377
  }
20231
20378
  draw(cb) {
20232
20379
  const ctx = this.#context;
@@ -20283,21 +20430,40 @@
20283
20430
  });
20284
20431
  }
20285
20432
  drawParticles(delta) {
20286
- const { particles } = this.#container;
20433
+ const { particles, actualOptions } = this.#container;
20287
20434
  this.clear();
20288
20435
  particles.update(delta);
20289
20436
  this.draw(ctx => {
20290
- for (const plugin of this.#drawSettingsSetupPlugins) {
20437
+ const width = this.#canvasManager.size.width, height = this.#canvasManager.size.height;
20438
+ if (this.#backgroundElement) {
20439
+ try {
20440
+ ctx.drawImage(this.#backgroundElement, originPoint.x, originPoint.y, width, height);
20441
+ }
20442
+ catch {
20443
+ this.#warnOnce("background-element-draw-error", "Error drawing background element onto canvas");
20444
+ }
20445
+ }
20446
+ const background = actualOptions.background;
20447
+ if (background.draw) {
20448
+ try {
20449
+ background.draw(ctx, delta);
20450
+ }
20451
+ catch {
20452
+ this.#warnOnce("background-draw-error", "Error in background.draw callback");
20453
+ }
20454
+ }
20455
+ for (const plugin of this.#getLayerPlugins(exports.DrawLayer.BackgroundMask)) {
20456
+ plugin.canvasPaint?.();
20457
+ }
20458
+ for (const plugin of this.#getLayerPlugins(exports.DrawLayer.CanvasSetup)) {
20291
20459
  plugin.drawSettingsSetup?.(ctx, delta);
20292
20460
  }
20293
- for (const plugin of this.#drawPlugins) {
20461
+ for (const plugin of this.#getLayerPlugins(exports.DrawLayer.PluginContent)) {
20294
20462
  plugin.draw?.(ctx, delta);
20295
20463
  }
20296
20464
  particles.drawParticles(delta);
20297
- for (const plugin of this.#clearDrawPlugins) {
20465
+ for (const plugin of this.#getLayerPlugins(exports.DrawLayer.CanvasCleanup)) {
20298
20466
  plugin.clearDraw?.(ctx, delta);
20299
- }
20300
- for (const plugin of this.#drawSettingsCleanupPlugins) {
20301
20467
  plugin.drawSettingsCleanup?.(ctx, delta);
20302
20468
  }
20303
20469
  });
@@ -20305,29 +20471,24 @@
20305
20471
  init() {
20306
20472
  this.initUpdaters();
20307
20473
  this.initPlugins();
20474
+ this.#resolveBackgroundElement();
20308
20475
  this.paint();
20309
20476
  }
20310
20477
  initPlugins() {
20311
- this.#colorPlugins = [];
20312
20478
  this.#canvasClearPlugins = [];
20313
- this.#canvasPaintPlugins = [];
20314
- this.#clearDrawPlugins = [];
20479
+ this.#colorPlugins = [];
20315
20480
  this.#drawParticlePlugins = [];
20316
20481
  this.#drawParticlesSetupPlugins = [];
20317
20482
  this.#drawParticlesCleanupPlugins = [];
20318
- this.#drawPlugins = [];
20319
- this.#drawSettingsSetupPlugins = [];
20320
- this.#drawSettingsCleanupPlugins = [];
20483
+ for (const layer of Object.values(exports.DrawLayer)) {
20484
+ if (typeof layer === "number") {
20485
+ this.#layers[layer] = [];
20486
+ }
20487
+ }
20321
20488
  for (const plugin of this.#container.plugins) {
20322
20489
  if (plugin.particleFillColor ?? plugin.particleStrokeColor) {
20323
20490
  this.#colorPlugins.push(plugin);
20324
20491
  }
20325
- if (plugin.canvasClear) {
20326
- this.#canvasClearPlugins.push(plugin);
20327
- }
20328
- if (plugin.canvasPaint) {
20329
- this.#canvasPaintPlugins.push(plugin);
20330
- }
20331
20492
  if (plugin.drawParticle) {
20332
20493
  this.#drawParticlePlugins.push(plugin);
20333
20494
  }
@@ -20337,17 +20498,20 @@
20337
20498
  if (plugin.drawParticleCleanup) {
20338
20499
  this.#drawParticlesCleanupPlugins.push(plugin);
20339
20500
  }
20340
- if (plugin.draw) {
20341
- this.#drawPlugins.push(plugin);
20501
+ if (plugin.canvasClear) {
20502
+ this.#canvasClearPlugins.push(plugin);
20503
+ }
20504
+ if (plugin.canvasPaint) {
20505
+ this.#getLayerPlugins(exports.DrawLayer.BackgroundMask).push(plugin);
20342
20506
  }
20343
20507
  if (plugin.drawSettingsSetup) {
20344
- this.#drawSettingsSetupPlugins.push(plugin);
20508
+ this.#getLayerPlugins(exports.DrawLayer.CanvasSetup).push(plugin);
20345
20509
  }
20346
- if (plugin.drawSettingsCleanup) {
20347
- this.#drawSettingsCleanupPlugins.push(plugin);
20510
+ if (plugin.draw) {
20511
+ this.#getLayerPlugins(exports.DrawLayer.PluginContent).push(plugin);
20348
20512
  }
20349
- if (plugin.clearDraw) {
20350
- this.#clearDrawPlugins.push(plugin);
20513
+ if (plugin.clearDraw ?? plugin.drawSettingsCleanup) {
20514
+ this.#getLayerPlugins(exports.DrawLayer.CanvasCleanup).push(plugin);
20351
20515
  }
20352
20516
  }
20353
20517
  }
@@ -20365,7 +20529,7 @@
20365
20529
  }
20366
20530
  paint() {
20367
20531
  let handled = false;
20368
- for (const plugin of this.#canvasPaintPlugins) {
20532
+ for (const plugin of this.#getLayerPlugins(exports.DrawLayer.BackgroundMask)) {
20369
20533
  handled = plugin.canvasPaint?.() ?? false;
20370
20534
  if (handled) {
20371
20535
  break;
@@ -20538,6 +20702,9 @@
20538
20702
  }
20539
20703
  drawer.beforeDraw(data);
20540
20704
  }
20705
+ #getLayerPlugins(layer) {
20706
+ return this.#layers[layer];
20707
+ }
20541
20708
  #getPluginParticleColors(particle) {
20542
20709
  let fColor, sColor;
20543
20710
  for (const plugin of this.#colorPlugins) {
@@ -20555,6 +20722,39 @@
20555
20722
  this.#reusablePluginColors[sColorIndex] = sColor;
20556
20723
  return this.#reusablePluginColors;
20557
20724
  }
20725
+ #resolveBackgroundElement() {
20726
+ const background = this.#container.actualOptions.background;
20727
+ this.#backgroundElement = null;
20728
+ if (!background.element) {
20729
+ return;
20730
+ }
20731
+ if (typeof background.element === "string") {
20732
+ if (typeof document !== "undefined") {
20733
+ const node = document.querySelector(background.element);
20734
+ if (node instanceof HTMLCanvasElement || node instanceof HTMLVideoElement || node instanceof HTMLImageElement) {
20735
+ this.#backgroundElement = node;
20736
+ }
20737
+ else if (node) {
20738
+ this.#warnOnce("background-element-not-supported", `Background element "${background.element}" is not a supported drawable element (canvas, video, or img)`);
20739
+ }
20740
+ else {
20741
+ this.#warnOnce("background-element-not-found", `Background element selector "${background.element}" not found`);
20742
+ }
20743
+ }
20744
+ }
20745
+ else if (background.element instanceof HTMLCanvasElement ||
20746
+ background.element instanceof OffscreenCanvas ||
20747
+ background.element instanceof HTMLVideoElement ||
20748
+ background.element instanceof HTMLImageElement) {
20749
+ this.#backgroundElement = background.element;
20750
+ }
20751
+ }
20752
+ #warnOnce(key, message) {
20753
+ if (!this.#backgroundWarnings.has(key)) {
20754
+ this.#backgroundWarnings.add(key);
20755
+ getLogger().warning(message);
20756
+ }
20757
+ }
20558
20758
  }
20559
20759
 
20560
20760
  const transferredCanvases = new WeakMap(), getTransferredCanvas = (canvas) => {
@@ -21131,7 +21331,6 @@
21131
21331
  }
21132
21332
  class Particle {
21133
21333
  backColor;
21134
- bubble;
21135
21334
  destroyed;
21136
21335
  direction;
21137
21336
  effect;
@@ -21165,7 +21364,6 @@
21165
21364
  shapeData;
21166
21365
  sides;
21167
21366
  size;
21168
- slow;
21169
21367
  spawning;
21170
21368
  strokeColor;
21171
21369
  strokeOpacity;
@@ -21187,18 +21385,25 @@
21187
21385
  d: 1,
21188
21386
  };
21189
21387
  #container;
21388
+ #modifiers = [];
21190
21389
  #pluginManager;
21191
21390
  constructor(pluginManager, container) {
21192
21391
  this.#pluginManager = pluginManager;
21193
21392
  this.#container = container;
21194
21393
  }
21394
+ addModifier(modifier) {
21395
+ this.#modifiers.push(modifier);
21396
+ this.#modifiers.sort((a, b) => a.priority - b.priority);
21397
+ }
21398
+ clearModifiers() {
21399
+ this.#modifiers.length = 0;
21400
+ }
21195
21401
  destroy(override) {
21196
21402
  if (this.unbreakable || this.destroyed) {
21197
21403
  return;
21198
21404
  }
21199
21405
  this.destroyed = true;
21200
- this.bubble.inRange = false;
21201
- this.slow.inRange = false;
21406
+ this.clearModifiers();
21202
21407
  const container = this.#container, shapeDrawer = this.shape ? container.shapeDrawers.get(this.shape) : undefined;
21203
21408
  shapeDrawer?.particleDestroy?.(this);
21204
21409
  for (const plugin of container.particleDestroyedPlugins) {
@@ -21220,13 +21425,16 @@
21220
21425
  return this.rotation + (this.pathRotation ? this.velocity.angle : defaultAngle$1);
21221
21426
  }
21222
21427
  getFillColor() {
21223
- return this.#getRollColor(this.bubble.color ?? getHslFromAnimation(this.fillColor));
21428
+ return this.#getRollColor(this.#applyModifiers(getHslFromAnimation(this.fillColor), m => m.fillColor));
21224
21429
  }
21225
21430
  getMass() {
21226
21431
  return this.getRadius() ** squareExp * Math.PI * half$2;
21227
21432
  }
21433
+ getModifier(id) {
21434
+ return this.#modifiers.find(m => m.id === id);
21435
+ }
21228
21436
  getOpacity() {
21229
- const zIndexOptions = this.options.zIndex, zIndexFactor = zIndexFactorOffset - this.zIndexFactor, zOpacityFactor = zIndexFactor ** zIndexOptions.opacityRate, opacity = this.bubble.opacity ?? getRangeValue(this.opacity?.value ?? defaultOpacity$3), fillOpacity = this.fillOpacity ?? defaultOpacity$3, strokeOpacity = this.strokeOpacity ?? defaultOpacity$3;
21437
+ const zIndexOptions = this.options.zIndex, zIndexFactor = zIndexFactorOffset - this.zIndexFactor, zOpacityFactor = zIndexFactor ** zIndexOptions.opacityRate, baseOpacity = getRangeValue(this.opacity?.value ?? defaultOpacity$3), modifierOpacity = this.#applyModifiers(undefined, m => m.opacity), opacity = modifierOpacity ?? baseOpacity, fillOpacity = this.fillOpacity ?? defaultOpacity$3, strokeOpacity = this.strokeOpacity ?? defaultOpacity$3;
21230
21438
  this.#cachedOpacityData.fillOpacity = opacity * fillOpacity * zOpacityFactor;
21231
21439
  this.#cachedOpacityData.opacity = opacity * zOpacityFactor;
21232
21440
  this.#cachedOpacityData.strokeOpacity = opacity * strokeOpacity * zOpacityFactor;
@@ -21239,7 +21447,7 @@
21239
21447
  return this.#cachedPosition;
21240
21448
  }
21241
21449
  getRadius() {
21242
- return this.bubble.radius ?? this.size.value;
21450
+ return this.#applyModifiers(this.size.value, m => m.radius);
21243
21451
  }
21244
21452
  getRotateData() {
21245
21453
  const angle = this.getAngle();
@@ -21248,7 +21456,7 @@
21248
21456
  return this.#cachedRotateData;
21249
21457
  }
21250
21458
  getStrokeColor() {
21251
- return this.#getRollColor(this.bubble.color ?? getHslFromAnimation(this.strokeColor));
21459
+ return this.#getRollColor(this.#applyModifiers(getHslFromAnimation(this.strokeColor), m => m.strokeColor));
21252
21460
  }
21253
21461
  getTransformData(externalTransform) {
21254
21462
  const rotateData = this.getRotateData(), rotating = this.isRotating;
@@ -21268,13 +21476,6 @@
21268
21476
  this.options = resolveParticleOptions(this, container, this.#pluginManager, overrideOptions);
21269
21477
  container.retina.initParticle(this);
21270
21478
  runUpdaterPreInit(container.particleUpdaters, this);
21271
- this.bubble = {
21272
- inRange: false,
21273
- };
21274
- this.slow = {
21275
- inRange: false,
21276
- factor: 1,
21277
- };
21278
21479
  this.#initPosition(position);
21279
21480
  this.initialVelocity = this.#calculateVelocity();
21280
21481
  this.velocity = this.initialVelocity.copy();
@@ -21314,11 +21515,29 @@
21314
21515
  isVisible() {
21315
21516
  return !this.destroyed && !this.spawning && this.isInsideCanvas();
21316
21517
  }
21518
+ removeModifier(id) {
21519
+ const idx = this.#modifiers.findIndex(m => m.id === id);
21520
+ if (idx >= defaultAngle$1) {
21521
+ this.#modifiers.splice(idx, identity$3);
21522
+ }
21523
+ }
21317
21524
  reset() {
21318
21525
  for (const updater of this.#container.particleUpdaters) {
21319
21526
  updater.reset?.(this);
21320
21527
  }
21321
21528
  }
21529
+ #applyModifiers(base, getter) {
21530
+ let value = base;
21531
+ for (const mod of this.#modifiers) {
21532
+ if (mod.enabled) {
21533
+ const override = getter(mod);
21534
+ if (override !== undefined) {
21535
+ value = override;
21536
+ }
21537
+ }
21538
+ }
21539
+ return value;
21540
+ }
21322
21541
  #calcPosition(position, zIndex) {
21323
21542
  let tryCount = defaultRetryCount, posVec = position ? Vector3d.create(position.x, position.y, zIndex) : undefined;
21324
21543
  const container = this.#container, plugins = container.particlePositionPlugins, outModes = this.options.move.outModes, radius = this.getRadius(), canvasSize = container.canvas.size;
@@ -22420,10 +22639,13 @@
22420
22639
  });
22421
22640
 
22422
22641
  class BackgroundMaskPluginInstance {
22642
+ layer = exports.DrawLayer.BackgroundMask;
22423
22643
  #container;
22424
22644
  #coverColorStyle;
22425
22645
  #coverImage;
22426
22646
  #defaultCompositeValue;
22647
+ #maskElement;
22648
+ #maskWarnings = new Set();
22427
22649
  #pluginManager;
22428
22650
  constructor(pluginManager, container) {
22429
22651
  this.#pluginManager = pluginManager;
@@ -22437,19 +22659,52 @@
22437
22659
  return this.canvasPaint();
22438
22660
  }
22439
22661
  canvasPaint() {
22440
- if (!this.#container.actualOptions.backgroundMask?.enable) {
22662
+ const { backgroundMask } = this.#container.actualOptions;
22663
+ if (!backgroundMask?.enable) {
22441
22664
  return false;
22442
22665
  }
22443
22666
  const canvas = this.#container.canvas;
22444
22667
  canvas.render.canvasClear();
22445
- if (this.#coverImage) {
22446
- canvas.render.paintImage(this.#coverImage.image, this.#coverImage.opacity);
22668
+ const cover = backgroundMask.cover;
22669
+ let dynamicUsed = false;
22670
+ const maskElement = this.#maskElement;
22671
+ if (maskElement) {
22672
+ dynamicUsed = true;
22673
+ canvas.render.draw(ctx => {
22674
+ try {
22675
+ ctx.drawImage(maskElement, originPoint.x, originPoint.y, canvas.size.width, canvas.size.height);
22676
+ }
22677
+ catch {
22678
+ this.#maskWarnOnce("mask-element-draw-error", "Error drawing background mask cover element onto canvas");
22679
+ }
22680
+ });
22447
22681
  }
22448
- else {
22449
- canvas.render.paintBase(this.#coverColorStyle);
22682
+ if (cover.draw) {
22683
+ dynamicUsed = true;
22684
+ const drawFn = cover.draw;
22685
+ canvas.render.draw(ctx => {
22686
+ try {
22687
+ drawFn(ctx, { value: 0, factor: 1 });
22688
+ }
22689
+ catch {
22690
+ this.#maskWarnOnce("mask-draw-error", "Error in mask cover.draw callback");
22691
+ }
22692
+ });
22693
+ }
22694
+ if (!dynamicUsed) {
22695
+ if (this.#coverImage) {
22696
+ canvas.render.paintImage(this.#coverImage.image, this.#coverImage.opacity);
22697
+ }
22698
+ else {
22699
+ canvas.render.paintBase(this.#coverColorStyle);
22700
+ }
22450
22701
  }
22451
22702
  return true;
22452
22703
  }
22704
+ destroy() {
22705
+ this.#maskElement = null;
22706
+ this.#maskWarnings.clear();
22707
+ }
22453
22708
  drawSettingsCleanup(context) {
22454
22709
  if (!this.#defaultCompositeValue) {
22455
22710
  return;
@@ -22462,7 +22717,9 @@
22462
22717
  context.globalCompositeOperation = backgroundMask?.enable ? backgroundMask.composite : previousComposite;
22463
22718
  }
22464
22719
  async init() {
22720
+ this.#maskWarnings.clear();
22465
22721
  await this.#initCover();
22722
+ this.#resolveMaskElement();
22466
22723
  }
22467
22724
  #initCover = async () => {
22468
22725
  const options = this.#container.actualOptions, cover = options.backgroundMask?.cover, color = cover?.color;
@@ -22476,11 +22733,9 @@
22476
22733
  this.#coverColorStyle = getStyleFromRgb(coverColor, this.#container.hdr, coverColor.a);
22477
22734
  }
22478
22735
  }
22479
- else {
22736
+ else if (cover?.image) {
22737
+ const coverImage = cover.image;
22480
22738
  await new Promise((resolve, reject) => {
22481
- if (!cover?.image) {
22482
- return;
22483
- }
22484
22739
  const img = safeDocument().createElement("img");
22485
22740
  img.addEventListener("load", () => {
22486
22741
  this.#coverImage = {
@@ -22492,10 +22747,44 @@
22492
22747
  img.addEventListener("error", () => {
22493
22748
  reject(new Error("Error loading image"));
22494
22749
  });
22495
- img.src = cover.image;
22750
+ img.src = coverImage;
22496
22751
  });
22497
22752
  }
22498
22753
  };
22754
+ #maskWarnOnce = (key, message) => {
22755
+ if (this.#maskWarnings.has(key)) {
22756
+ return;
22757
+ }
22758
+ this.#maskWarnings.add(key);
22759
+ getLogger().warning(`[tsParticles BackgroundMask] ${message}`);
22760
+ };
22761
+ #resolveMaskElement = () => {
22762
+ const cover = this.#container.actualOptions.backgroundMask?.cover;
22763
+ this.#maskElement = null;
22764
+ if (!cover?.element) {
22765
+ return;
22766
+ }
22767
+ if (typeof cover.element === "string") {
22768
+ if (typeof document !== "undefined") {
22769
+ const node = document.querySelector(cover.element);
22770
+ if (node instanceof HTMLCanvasElement || node instanceof HTMLVideoElement || node instanceof HTMLImageElement) {
22771
+ this.#maskElement = node;
22772
+ }
22773
+ else if (node) {
22774
+ this.#maskWarnOnce("mask-element-not-supported", `Mask cover element "${cover.element}" matched a non-drawable element (expected canvas, video, or img)`);
22775
+ }
22776
+ else {
22777
+ this.#maskWarnOnce("mask-element-not-found", `Mask cover element selector "${cover.element}" not found in the DOM`);
22778
+ }
22779
+ }
22780
+ }
22781
+ else if (cover.element instanceof HTMLCanvasElement ||
22782
+ cover.element instanceof OffscreenCanvas ||
22783
+ cover.element instanceof HTMLVideoElement ||
22784
+ cover.element instanceof HTMLImageElement) {
22785
+ this.#maskElement = cover.element;
22786
+ }
22787
+ };
22499
22788
  }
22500
22789
 
22501
22790
  var BackgroundMaskPluginInstance$1 = /*#__PURE__*/Object.freeze({
@@ -22611,7 +22900,8 @@
22611
22900
  particle.lastPathTime -= pathDelay;
22612
22901
  }
22613
22902
  function getProximitySpeedFactor(particle) {
22614
- return particle.slow.inRange ? particle.slow.factor : identity$3;
22903
+ const mod = particle.getModifier("slow");
22904
+ return mod?.enabled ? (mod.speedFactor ?? identity$3) : identity$3;
22615
22905
  }
22616
22906
  function initSpin(container, particle) {
22617
22907
  const options = particle.options, spinOptions = options.move.spin;
@@ -23775,6 +24065,7 @@
23775
24065
  });
23776
24066
 
23777
24067
  class BlendPluginInstance {
24068
+ layer = exports.DrawLayer.CanvasSetup;
23778
24069
  #container;
23779
24070
  #defaultCompositeValue;
23780
24071
  constructor(container) {
@@ -26880,6 +27171,7 @@
26880
27171
 
26881
27172
  const minimumLength = 0;
26882
27173
  class TrailPluginInstance {
27174
+ layer = exports.DrawLayer.PluginContent;
26883
27175
  #container;
26884
27176
  #pluginManager;
26885
27177
  #trailFill;
@@ -27133,6 +27425,7 @@
27133
27425
  }
27134
27426
 
27135
27427
  class ZoomPluginInstance {
27428
+ layer = exports.DrawLayer.CanvasSetup;
27136
27429
  #container;
27137
27430
  #listeners;
27138
27431
  constructor(container) {
@@ -28044,6 +28337,7 @@
28044
28337
  exports.hPhase = hPhase;
28045
28338
  exports.half = half$2;
28046
28339
  exports.hslToRgb = hslToRgb;
28340
+ exports.hslToRgbFloat = hslToRgbFloat;
28047
28341
  exports.hslaToRgba = hslaToRgba;
28048
28342
  exports.identity = identity$3;
28049
28343
  exports.inverseFactorNumerator = inverseFactorNumerator;