@tsparticles/confetti 4.2.1 → 4.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
1
1
  (function(g){g.__tsParticlesInternals=g.__tsParticlesInternals||{};g.__tsParticlesInternals.bundles=g.__tsParticlesInternals.bundles||{};g.__tsParticlesInternals.effects=g.__tsParticlesInternals.effects||{};g.__tsParticlesInternals.engine=g.__tsParticlesInternals.engine||{};g.__tsParticlesInternals.interactions=g.__tsParticlesInternals.interactions||{};g.__tsParticlesInternals.palettes=g.__tsParticlesInternals.palettes||{};g.__tsParticlesInternals.paths=g.__tsParticlesInternals.paths||{};g.__tsParticlesInternals.plugins=g.__tsParticlesInternals.plugins||{};g.__tsParticlesInternals.plugins=g.__tsParticlesInternals.plugins||{};g.__tsParticlesInternals.plugins.emittersShapes=g.__tsParticlesInternals.plugins.emittersShapes||{};g.__tsParticlesInternals.presets=g.__tsParticlesInternals.presets||{};g.__tsParticlesInternals.shapes=g.__tsParticlesInternals.shapes||{};g.__tsParticlesInternals.updaters=g.__tsParticlesInternals.updaters||{};g.__tsParticlesInternals.utils=g.__tsParticlesInternals.utils||{};g.__tsParticlesInternals.canvas=g.__tsParticlesInternals.canvas||{};g.__tsParticlesInternals.canvas=g.__tsParticlesInternals.canvas||{};g.__tsParticlesInternals.canvas.utils=g.__tsParticlesInternals.canvas.utils||{};g.__tsParticlesInternals.path=g.__tsParticlesInternals.path||{};g.__tsParticlesInternals.path=g.__tsParticlesInternals.path||{};g.__tsParticlesInternals.path.utils=g.__tsParticlesInternals.path.utils||{};var __tsProxyFactory=typeof Proxy!=="undefined"?function(obj){return new Proxy(obj,{get:function(target,key){if(!(key in target)){target[key]={};}return target[key];}});}:function(obj){return obj;};g.__tsParticlesInternals.bundles=__tsProxyFactory(g.__tsParticlesInternals.bundles);g.__tsParticlesInternals.effects=__tsProxyFactory(g.__tsParticlesInternals.effects);g.__tsParticlesInternals.interactions=__tsProxyFactory(g.__tsParticlesInternals.interactions);g.__tsParticlesInternals.palettes=__tsProxyFactory(g.__tsParticlesInternals.palettes);g.__tsParticlesInternals.paths=__tsProxyFactory(g.__tsParticlesInternals.paths);g.__tsParticlesInternals.plugins=__tsProxyFactory(g.__tsParticlesInternals.plugins);g.__tsParticlesInternals.plugins.emittersShapes=__tsProxyFactory(g.__tsParticlesInternals.plugins.emittersShapes);g.__tsParticlesInternals.presets=__tsProxyFactory(g.__tsParticlesInternals.presets);g.__tsParticlesInternals.shapes=__tsProxyFactory(g.__tsParticlesInternals.shapes);g.__tsParticlesInternals.updaters=__tsProxyFactory(g.__tsParticlesInternals.updaters);g.__tsParticlesInternals.utils=__tsProxyFactory(g.__tsParticlesInternals.utils);g.__tsParticlesInternals.canvas=__tsProxyFactory(g.__tsParticlesInternals.canvas);g.__tsParticlesInternals.path=__tsProxyFactory(g.__tsParticlesInternals.path);g.tsparticlesInternalExports=g.tsparticlesInternalExports||{};})(typeof globalThis!=="undefined"?globalThis:typeof window!=="undefined"?window:this);
2
- /* tsParticles v4.2.1 */
2
+ /* tsParticles v4.3.0 */
3
3
  (function (global, factory) {
4
4
  typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
5
5
  typeof define === 'function' && define.amd ? define(['exports'], factory) :
@@ -398,29 +398,27 @@
398
398
  }
399
399
  }
400
400
  else if (!isObject(destination) || Array.isArray(destination)) {
401
- destination = {};
401
+ destination = Object.create(null);
402
402
  }
403
- const sourceKeys = Object.keys(source), dangerousKeys = new Set(["__proto__", "constructor", "prototype"]), hasNested = sourceKeys.some(k => {
403
+ const sourceKeys = Object.keys(source), hasNested = sourceKeys.some(k => {
404
404
  const v = source[k];
405
405
  return isObject(v) || Array.isArray(v);
406
406
  });
407
407
  if (!hasNested) {
408
408
  const sourceDict = source, destDict = destination;
409
409
  for (const key of sourceKeys) {
410
- if (dangerousKeys.has(key)) {
410
+ if (key === "__proto__" || key === "constructor" || key === "prototype") {
411
411
  continue;
412
412
  }
413
- if (key in sourceDict) {
414
- const v = sourceDict[key];
415
- if (v !== undefined) {
416
- destDict[key] = v;
417
- }
413
+ const v = sourceDict[key];
414
+ if (v !== undefined) {
415
+ destDict[key] = v;
418
416
  }
419
417
  }
420
418
  continue;
421
419
  }
422
420
  for (const key of sourceKeys) {
423
- if (dangerousKeys.has(key)) {
421
+ if (key === "__proto__" || key === "constructor" || key === "prototype") {
424
422
  continue;
425
423
  }
426
424
  const sourceDict = source, destDict = destination, value = sourceDict[key];
@@ -879,7 +877,7 @@
879
877
  return this.#domArray;
880
878
  }
881
879
  get version() {
882
- return "4.2.1";
880
+ return "4.3.0";
883
881
  }
884
882
  addEventListener(type, listener) {
885
883
  this.#eventDispatcher.addEventListener(type, listener);
@@ -1112,6 +1110,18 @@
1112
1110
  AnimationStatus["decreasing"] = "decreasing";
1113
1111
  })(exports.AnimationStatus || (exports.AnimationStatus = {}));
1114
1112
 
1113
+ exports.DrawLayer = void 0;
1114
+ (function (DrawLayer) {
1115
+ DrawLayer[DrawLayer["BackgroundElement"] = 0] = "BackgroundElement";
1116
+ DrawLayer[DrawLayer["BackgroundDraw"] = 1] = "BackgroundDraw";
1117
+ DrawLayer[DrawLayer["BackgroundMask"] = 2] = "BackgroundMask";
1118
+ DrawLayer[DrawLayer["CanvasSetup"] = 3] = "CanvasSetup";
1119
+ DrawLayer[DrawLayer["PluginContent"] = 4] = "PluginContent";
1120
+ DrawLayer[DrawLayer["Particles"] = 5] = "Particles";
1121
+ DrawLayer[DrawLayer["CanvasCleanup"] = 6] = "CanvasCleanup";
1122
+ DrawLayer[DrawLayer["Foreground"] = 7] = "Foreground";
1123
+ })(exports.DrawLayer || (exports.DrawLayer = {}));
1124
+
1115
1125
  class OptionLoader {
1116
1126
  load(data) {
1117
1127
  if (isNull(data)) {
@@ -1270,6 +1280,8 @@
1270
1280
 
1271
1281
  class Background extends OptionLoader {
1272
1282
  color;
1283
+ draw;
1284
+ element;
1273
1285
  image = "";
1274
1286
  opacity = 1;
1275
1287
  position = "";
@@ -1284,6 +1296,8 @@
1284
1296
  if (data.color !== undefined) {
1285
1297
  this.color = OptionsColor.create(this.color, data.color);
1286
1298
  }
1299
+ loadProperty(this, "element", data.element);
1300
+ loadProperty(this, "draw", data.draw);
1287
1301
  loadProperty(this, "image", data.image);
1288
1302
  loadProperty(this, "position", data.position);
1289
1303
  loadProperty(this, "repeat", data.repeat);
@@ -1829,7 +1843,7 @@
1829
1843
  }
1830
1844
  }
1831
1845
 
1832
- const styleCache = new Map(), maxStyleCacheSize = 2000, rgbFixedPrecision = 2, hslFixedPrecision = 2, sdrReferenceWhiteNits = 203;
1846
+ const styleCache = new Map(), maxStyleCacheSize = 2000, rgbFixedPrecision = 2, hslFixedPrecision = 2, hdrRgbFixedPrecision = 4, hdrHslFixedPrecision = 4, sdrReferenceWhiteNits = 203, hdrAnimationScale = sdrReferenceWhiteNits / maxNits;
1833
1847
  function getCachedStyle(key, generator) {
1834
1848
  let cached = styleCache.get(key);
1835
1849
  if (!cached) {
@@ -1972,6 +1986,17 @@
1972
1986
  : lNormalized + sNormalized - lNormalized * sNormalized, temp2 = double * lNormalized - temp1, phaseThird = phaseNumerator / triple, red = Math.min(rgbMax, rgbMax * hslChannel(temp2, temp1, hNormalized + phaseThird)), green = Math.min(rgbMax, rgbMax * hslChannel(temp2, temp1, hNormalized)), blue = Math.min(rgbMax, rgbMax * hslChannel(temp2, temp1, hNormalized - phaseThird));
1973
1987
  return { r: Math.round(red), g: Math.round(green), b: Math.round(blue) };
1974
1988
  }
1989
+ function hslToRgbFloat(hsl) {
1990
+ const h = ((hsl.h % hMax) + hMax) % hMax, s = Math.max(sMin, Math.min(sMax, hsl.s)), l = Math.max(lMin, Math.min(lMax, hsl.l)), hNormalized = h / hMax, sNormalized = s / sMax, lNormalized = l / lMax;
1991
+ if (s === sMin) {
1992
+ const grayscaleValue = lNormalized * rgbMax;
1993
+ return { r: grayscaleValue, g: grayscaleValue, b: grayscaleValue };
1994
+ }
1995
+ const temp1 = lNormalized < half
1996
+ ? lNormalized * (sNormalizedOffset + sNormalized)
1997
+ : lNormalized + sNormalized - lNormalized * sNormalized, temp2 = double * lNormalized - temp1, phaseThird = phaseNumerator / triple, red = Math.min(rgbMax, rgbMax * hslChannel(temp2, temp1, hNormalized + phaseThird)), green = Math.min(rgbMax, rgbMax * hslChannel(temp2, temp1, hNormalized)), blue = Math.min(rgbMax, rgbMax * hslChannel(temp2, temp1, hNormalized - phaseThird));
1998
+ return { r: red, g: green, b: blue };
1999
+ }
1975
2000
  function hslaToRgba(hsla) {
1976
2001
  const rgbResult = hslToRgb(hsla);
1977
2002
  return {
@@ -1981,8 +2006,16 @@
1981
2006
  r: rgbResult.r,
1982
2007
  };
1983
2008
  }
1984
- function getRandomRgbColor(min) {
1985
- const fixedMin = min ?? defaultRgbMin, fixedMax = rgbMax + identity$2, 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$2, 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$2, 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$2, 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$2).toString()})`;
2002
2035
  }
2003
2036
  function getStyleFromHsl(color, hdr, opacity) {
2004
- const op = opacity ?? defaultOpacity$2, 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$2, key = `hsl-${color.h.toFixed(hslPrecision)}-${color.s.toFixed(hslPrecision)}-${color.l.toFixed(hslPrecision)}-${hdr ? "hdr" : "sdr"}-${op.toString()}`;
2005
2038
  return getCachedStyle(key, () => hdr
2006
- ? getStyleFromRgb(hslToRgb(color), true, opacity)
2039
+ ? getStyleFromRgb(hslToRgbFloat(color), true, opacity)
2007
2040
  : `hsla(${color.h.toString()}, ${color.s.toString()}%, ${color.l.toString()}%, ${op.toString()})`);
2008
2041
  }
2009
2042
  function colorMix(color1, color2, size1, size2) {
@@ -2123,7 +2156,7 @@
2123
2156
  colorValue.velocity = defaultVelocity;
2124
2157
  }
2125
2158
  }
2126
- function updateColorValue(data, decrease, delta) {
2159
+ function updateColorValue(data, decrease, delta, hdr) {
2127
2160
  const minLoops = 0, minDelay = 0, identity = 1, minVelocity = 0, minOffset = 0, velocityFactor = 3.6;
2128
2161
  if (!data.enable ||
2129
2162
  ((data.maxLoops ?? minLoops) > minLoops && (data.loops ?? minLoops) > (data.maxLoops ?? minLoops))) {
@@ -2136,7 +2169,7 @@
2136
2169
  if ((data.delayTime ?? minDelay) > minDelay && data.time < (data.delayTime ?? minDelay)) {
2137
2170
  return;
2138
2171
  }
2139
- const offset = data.offset ? randomInRangeValue(data.offset) : minOffset, velocity = (data.velocity ?? minVelocity) * delta.factor + offset * velocityFactor, decay = data.decay ?? identity, max = data.max, min = data.min;
2172
+ const offset = data.offset ? randomInRangeValue(data.offset) : minOffset, velocity = ((data.velocity ?? minVelocity) * delta.factor + offset * velocityFactor) * (hdr ? hdrAnimationScale : identity), decay = data.decay ?? identity, max = data.max, min = data.min;
2140
2173
  if (!decrease || data.status === exports.AnimationStatus.increasing) {
2141
2174
  data.value += velocity;
2142
2175
  if (data.value > max) {
@@ -2163,14 +2196,14 @@
2163
2196
  }
2164
2197
  data.value = clamp(data.value, min, max);
2165
2198
  }
2166
- function updateColor(color, delta) {
2199
+ function updateColor(color, delta, hdr) {
2167
2200
  if (!color) {
2168
2201
  return;
2169
2202
  }
2170
2203
  const { h, s, l } = color;
2171
- updateColorValue(h, false, delta);
2172
- updateColorValue(s, true, delta);
2173
- updateColorValue(l, true, delta);
2204
+ updateColorValue(h, false, delta, hdr);
2205
+ updateColorValue(s, true, delta, hdr);
2206
+ updateColorValue(l, true, delta, hdr);
2174
2207
  }
2175
2208
  function alterHsl(color, type, value) {
2176
2209
  return {
@@ -2220,7 +2253,7 @@
2220
2253
  }
2221
2254
 
2222
2255
  async function loadBlendPlugin(engine) {
2223
- engine.checkVersion("4.2.1");
2256
+ engine.checkVersion("4.3.0");
2224
2257
  await engine.pluginManager.register(e => {
2225
2258
  e.pluginManager.addPlugin(new BlendPlugin());
2226
2259
  });
@@ -2257,7 +2290,7 @@
2257
2290
  }
2258
2291
 
2259
2292
  async function loadCircleShape(engine) {
2260
- engine.checkVersion("4.2.1");
2293
+ engine.checkVersion("4.3.0");
2261
2294
  await engine.pluginManager.register(e => {
2262
2295
  e.pluginManager.addShape(["circle"], () => {
2263
2296
  return Promise.resolve(new CircleDrawer());
@@ -2305,7 +2338,7 @@
2305
2338
  }
2306
2339
 
2307
2340
  async function loadHexColorPlugin(engine) {
2308
- engine.checkVersion("4.2.1");
2341
+ engine.checkVersion("4.3.0");
2309
2342
  await engine.pluginManager.register(e => {
2310
2343
  e.pluginManager.addColorManager("hex", new HexColorManager());
2311
2344
  });
@@ -2358,7 +2391,7 @@
2358
2391
  }
2359
2392
 
2360
2393
  async function loadHslColorPlugin(engine) {
2361
- engine.checkVersion("4.2.1");
2394
+ engine.checkVersion("4.3.0");
2362
2395
  await engine.pluginManager.register(e => {
2363
2396
  e.pluginManager.addColorManager("hsl", new HslColorManager());
2364
2397
  });
@@ -2382,7 +2415,7 @@
2382
2415
  }
2383
2416
 
2384
2417
  async function loadMovePlugin(engine) {
2385
- engine.checkVersion("4.2.1");
2418
+ engine.checkVersion("4.3.0");
2386
2419
  await engine.pluginManager.register(e => {
2387
2420
  const moveEngine = e, movePluginManager = moveEngine.pluginManager;
2388
2421
  movePluginManager.initializers.pathGenerators ??= new Map();
@@ -2598,7 +2631,7 @@
2598
2631
  }
2599
2632
 
2600
2633
  async function loadOpacityUpdater(engine) {
2601
- engine.checkVersion("4.2.1");
2634
+ engine.checkVersion("4.3.0");
2602
2635
  await engine.pluginManager.register(e => {
2603
2636
  e.pluginManager.addParticleUpdater("opacity", container => {
2604
2637
  return Promise.resolve(new OpacityUpdater(container));
@@ -2943,7 +2976,7 @@
2943
2976
  }
2944
2977
 
2945
2978
  async function loadOutModesUpdater(engine) {
2946
- engine.checkVersion("4.2.1");
2979
+ engine.checkVersion("4.3.0");
2947
2980
  await engine.pluginManager.register(e => {
2948
2981
  e.pluginManager.addParticleUpdater("outModes", container => {
2949
2982
  return Promise.resolve(new OutOfCanvasUpdater(container));
@@ -3008,13 +3041,13 @@
3008
3041
  if (!this.isEnabled(particle)) {
3009
3042
  return;
3010
3043
  }
3011
- updateColor(particle.fillColor, delta);
3012
- updateColor(particle.strokeColor, delta);
3044
+ updateColor(particle.fillColor, delta, this.#container.hdr);
3045
+ updateColor(particle.strokeColor, delta, this.#container.hdr);
3013
3046
  }
3014
3047
  }
3015
3048
 
3016
3049
  async function loadPaintUpdater(engine) {
3017
- engine.checkVersion("4.2.1");
3050
+ engine.checkVersion("4.3.0");
3018
3051
  await engine.pluginManager.register(e => {
3019
3052
  e.pluginManager.addParticleUpdater("paint", container => {
3020
3053
  return Promise.resolve(new PaintUpdater(e.pluginManager, container));
@@ -3069,7 +3102,7 @@
3069
3102
  }
3070
3103
 
3071
3104
  async function loadRgbColorPlugin(engine) {
3072
- engine.checkVersion("4.2.1");
3105
+ engine.checkVersion("4.3.0");
3073
3106
  await engine.pluginManager.register(e => {
3074
3107
  e.pluginManager.addColorManager("rgb", new RgbColorManager());
3075
3108
  });
@@ -3154,7 +3187,7 @@
3154
3187
  }
3155
3188
 
3156
3189
  async function loadSizeUpdater(engine) {
3157
- engine.checkVersion("4.2.1");
3190
+ engine.checkVersion("4.3.0");
3158
3191
  await engine.pluginManager.register(e => {
3159
3192
  e.pluginManager.addParticleUpdater("size", container => {
3160
3193
  return Promise.resolve(new SizeUpdater(container));
@@ -3163,7 +3196,7 @@
3163
3196
  }
3164
3197
 
3165
3198
  async function loadBasic(engine) {
3166
- engine.checkVersion("4.2.1");
3199
+ engine.checkVersion("4.3.0");
3167
3200
  await engine.pluginManager.register(async (e) => {
3168
3201
  await Promise.all([
3169
3202
  loadBlendPlugin(e),
@@ -3190,19 +3223,19 @@
3190
3223
  SegmentType["ellipse"] = "ellipse";
3191
3224
  })(SegmentType || (SegmentType = {}));
3192
3225
 
3193
- const firstIndex$1 = 0, index2 = 1, index3 = 2, index4 = 3;
3226
+ const firstIndex = 0, index2 = 1, index3 = 2, index4 = 3;
3194
3227
  function drawPath(ctx, radius, path) {
3195
- const firstSegment = path.segments[firstIndex$1];
3228
+ const firstSegment = path.segments[firstIndex];
3196
3229
  if (!firstSegment) {
3197
3230
  return;
3198
3231
  }
3199
- const firstValue = firstSegment.values[firstIndex$1];
3232
+ const firstValue = firstSegment.values[firstIndex];
3200
3233
  if (!firstValue) {
3201
3234
  return;
3202
3235
  }
3203
3236
  ctx.moveTo(firstValue.x * radius, firstValue.y * radius);
3204
3237
  for (const segment of path.segments) {
3205
- const value = segment.values[firstIndex$1];
3238
+ const value = segment.values[firstIndex];
3206
3239
  if (!value) {
3207
3240
  continue;
3208
3241
  }
@@ -3249,7 +3282,7 @@
3249
3282
  if (!segment) {
3250
3283
  continue;
3251
3284
  }
3252
- const value = segment.values[firstIndex$1], index2 = 1, index3 = 2, segmentValue2 = segment.values[index2], segmentValue3 = segment.values[index3];
3285
+ const value = segment.values[firstIndex], index2 = 1, index3 = 2, segmentValue2 = segment.values[index2], segmentValue3 = segment.values[index3];
3253
3286
  switch (segment.type) {
3254
3287
  case SegmentType.line:
3255
3288
  if (!value) {
@@ -3463,7 +3496,7 @@
3463
3496
  }
3464
3497
 
3465
3498
  async function loadClubsSuitShape(engine) {
3466
- engine.checkVersion("4.2.1");
3499
+ engine.checkVersion("4.3.0");
3467
3500
  await engine.pluginManager.register(e => {
3468
3501
  e.pluginManager.addShape(["club", "clubs"], () => Promise.resolve(new ClubDrawer()));
3469
3502
  });
@@ -3477,7 +3510,7 @@
3477
3510
  }
3478
3511
 
3479
3512
  async function loadDiamondsSuitShape(engine) {
3480
- engine.checkVersion("4.2.1");
3513
+ engine.checkVersion("4.3.0");
3481
3514
  await engine.pluginManager.register(e => {
3482
3515
  e.pluginManager.addShape(["diamond", "diamonds"], () => Promise.resolve(new DiamondDrawer()));
3483
3516
  });
@@ -3491,7 +3524,7 @@
3491
3524
  };
3492
3525
 
3493
3526
  async function loadHeartsSuitShape(engine) {
3494
- engine.checkVersion("4.2.1");
3527
+ engine.checkVersion("4.3.0");
3495
3528
  await engine.pluginManager.register(e => {
3496
3529
  e.pluginManager.addShape(["heart", "hearts"], () => Promise.resolve(new HeartDrawer$1()));
3497
3530
  });
@@ -3505,14 +3538,14 @@
3505
3538
  }
3506
3539
 
3507
3540
  async function loadSpadesSuitShape(engine) {
3508
- engine.checkVersion("4.2.1");
3541
+ engine.checkVersion("4.3.0");
3509
3542
  await engine.pluginManager.register(e => {
3510
3543
  e.pluginManager.addShape(["spade", "spades"], () => Promise.resolve(new SpadeDrawer()));
3511
3544
  });
3512
3545
  }
3513
3546
 
3514
3547
  async function loadCardSuitsShape(engine) {
3515
- engine.checkVersion("4.2.1");
3548
+ engine.checkVersion("4.3.0");
3516
3549
  await Promise.all([
3517
3550
  loadClubsSuitShape(engine),
3518
3551
  loadDiamondsSuitShape(engine),
@@ -3727,7 +3760,7 @@
3727
3760
  })(EmitterClickMode || (EmitterClickMode = {}));
3728
3761
 
3729
3762
  async function loadEmittersPluginSimple(engine) {
3730
- engine.checkVersion("4.2.1");
3763
+ engine.checkVersion("4.3.0");
3731
3764
  await engine.pluginManager.register(async (e) => {
3732
3765
  const instancesManager = await getEmittersInstancesManager(e);
3733
3766
  await addEmittersShapesManager(e);
@@ -3829,7 +3862,7 @@
3829
3862
  }
3830
3863
 
3831
3864
  async function loadEmojiShape(engine) {
3832
- engine.checkVersion("4.2.1");
3865
+ engine.checkVersion("4.3.0");
3833
3866
  await engine.pluginManager.register(e => {
3834
3867
  e.pluginManager.addShape(validTypes, () => Promise.resolve(new EmojiDrawer()));
3835
3868
  });
@@ -3855,7 +3888,7 @@
3855
3888
  }
3856
3889
 
3857
3890
  async function loadHeartShape(engine) {
3858
- engine.checkVersion("4.2.1");
3891
+ engine.checkVersion("4.3.0");
3859
3892
  await engine.pluginManager.register(e => {
3860
3893
  e.pluginManager.addShape(["heart"], () => Promise.resolve(new HeartDrawer()));
3861
3894
  });
@@ -3914,7 +3947,6 @@
3914
3947
  function replaceImageColor(image, imageData, color, particle, hdr = false) {
3915
3948
  const svgColoredData = replaceColorSvg(image, color, particle.opacity?.value ?? defaultOpacity, hdr), imageRes = {
3916
3949
  color,
3917
- gif: imageData.gif,
3918
3950
  data: {
3919
3951
  ...image,
3920
3952
  svgData: svgColoredData,
@@ -3949,495 +3981,6 @@
3949
3981
  });
3950
3982
  }
3951
3983
 
3952
- const InterlaceOffsets = [0, 4, 2, 1];
3953
- const InterlaceSteps = [8, 8, 4, 2];
3954
-
3955
- class ByteStream {
3956
- data;
3957
- pos;
3958
- constructor(bytes) {
3959
- this.pos = 0;
3960
- this.data = new Uint8ClampedArray(bytes);
3961
- }
3962
- getString(count) {
3963
- const slice = this.data.slice(this.pos, this.pos + count);
3964
- this.pos += slice.length;
3965
- return slice.reduce((acc, curr) => acc + String.fromCharCode(curr), "");
3966
- }
3967
- nextByte() {
3968
- return this.data[this.pos++];
3969
- }
3970
- nextTwoBytes() {
3971
- const increment = 2, previous = 1, shift = 8;
3972
- this.pos += increment;
3973
- return this.data[this.pos - increment] + (this.data[this.pos - previous] << shift);
3974
- }
3975
- readSubBlocks() {
3976
- let blockString = "", size;
3977
- const minCount = 0, emptySize = 0;
3978
- do {
3979
- size = this.data[this.pos++];
3980
- for (let count = size; --count >= minCount; blockString += String.fromCharCode(this.data[this.pos++])) {
3981
- }
3982
- } while (size !== emptySize);
3983
- return blockString;
3984
- }
3985
- readSubBlocksBin() {
3986
- let size = this.data[this.pos], len = 0;
3987
- const emptySize = 0, increment = 1;
3988
- for (let offset = 0; size !== emptySize; offset += size + increment, size = this.data[this.pos + offset]) {
3989
- len += size;
3990
- }
3991
- const blockData = new Uint8Array(len);
3992
- size = this.data[this.pos++];
3993
- for (let i = 0; size !== emptySize; size = this.data[this.pos++]) {
3994
- for (let count = size; --count >= emptySize; blockData[i++] = this.data[this.pos++]) {
3995
- }
3996
- }
3997
- return blockData;
3998
- }
3999
- skipSubBlocks() {
4000
- for (const increment = 1, noData = 0; this.data[this.pos] !== noData; this.pos += this.data[this.pos] + increment) {
4001
- }
4002
- this.pos++;
4003
- }
4004
- }
4005
-
4006
- var DisposalMethod;
4007
- (function (DisposalMethod) {
4008
- DisposalMethod[DisposalMethod["Replace"] = 0] = "Replace";
4009
- DisposalMethod[DisposalMethod["Combine"] = 1] = "Combine";
4010
- DisposalMethod[DisposalMethod["RestoreBackground"] = 2] = "RestoreBackground";
4011
- DisposalMethod[DisposalMethod["RestorePrevious"] = 3] = "RestorePrevious";
4012
- DisposalMethod[DisposalMethod["UndefinedA"] = 4] = "UndefinedA";
4013
- DisposalMethod[DisposalMethod["UndefinedB"] = 5] = "UndefinedB";
4014
- DisposalMethod[DisposalMethod["UndefinedC"] = 6] = "UndefinedC";
4015
- DisposalMethod[DisposalMethod["UndefinedD"] = 7] = "UndefinedD";
4016
- })(DisposalMethod || (DisposalMethod = {}));
4017
-
4018
- var GIFDataHeaders;
4019
- (function (GIFDataHeaders) {
4020
- GIFDataHeaders[GIFDataHeaders["Extension"] = 33] = "Extension";
4021
- GIFDataHeaders[GIFDataHeaders["ApplicationExtension"] = 255] = "ApplicationExtension";
4022
- GIFDataHeaders[GIFDataHeaders["GraphicsControlExtension"] = 249] = "GraphicsControlExtension";
4023
- GIFDataHeaders[GIFDataHeaders["PlainTextExtension"] = 1] = "PlainTextExtension";
4024
- GIFDataHeaders[GIFDataHeaders["CommentExtension"] = 254] = "CommentExtension";
4025
- GIFDataHeaders[GIFDataHeaders["Image"] = 44] = "Image";
4026
- GIFDataHeaders[GIFDataHeaders["EndOfFile"] = 59] = "EndOfFile";
4027
- })(GIFDataHeaders || (GIFDataHeaders = {}));
4028
-
4029
- const defaultFrame = 0, initialTime = 0, firstIndex = 0, defaultLoopCount = 0;
4030
- function parseColorTable(byteStream, count) {
4031
- const colors = [];
4032
- for (let i = 0; i < count; i++) {
4033
- colors.push({
4034
- r: byteStream.data[byteStream.pos],
4035
- g: byteStream.data[byteStream.pos + 1],
4036
- b: byteStream.data[byteStream.pos + 2],
4037
- });
4038
- byteStream.pos += 3;
4039
- }
4040
- return colors;
4041
- }
4042
- function parseExtensionBlock(byteStream, gif, getFrameIndex, getTransparencyIndex) {
4043
- switch (byteStream.nextByte()) {
4044
- case GIFDataHeaders.GraphicsControlExtension: {
4045
- const frame = gif.frames[getFrameIndex(false)];
4046
- byteStream.pos++;
4047
- const packedByte = byteStream.nextByte();
4048
- frame.GCreserved = (packedByte & 0xe0) >>> 5;
4049
- frame.disposalMethod = (packedByte & 0x1c) >>> 2;
4050
- frame.userInputDelayFlag = (packedByte & 2) === 2;
4051
- const transparencyFlag = (packedByte & 1) === 1;
4052
- frame.delayTime = byteStream.nextTwoBytes() * 0xa;
4053
- const transparencyIndex = byteStream.nextByte();
4054
- if (transparencyFlag) {
4055
- getTransparencyIndex(transparencyIndex);
4056
- }
4057
- byteStream.pos++;
4058
- break;
4059
- }
4060
- case GIFDataHeaders.ApplicationExtension: {
4061
- byteStream.pos++;
4062
- const applicationExtension = {
4063
- identifier: byteStream.getString(8),
4064
- authenticationCode: byteStream.getString(3),
4065
- data: byteStream.readSubBlocksBin(),
4066
- };
4067
- gif.applicationExtensions.push(applicationExtension);
4068
- break;
4069
- }
4070
- case GIFDataHeaders.CommentExtension: {
4071
- gif.comments.push([getFrameIndex(false), byteStream.readSubBlocks()]);
4072
- break;
4073
- }
4074
- case GIFDataHeaders.PlainTextExtension: {
4075
- if (gif.globalColorTable.length === 0) {
4076
- throw new EvalError("plain text extension without global color table");
4077
- }
4078
- byteStream.pos++;
4079
- gif.frames[getFrameIndex(false)].plainTextData = {
4080
- left: byteStream.nextTwoBytes(),
4081
- top: byteStream.nextTwoBytes(),
4082
- width: byteStream.nextTwoBytes(),
4083
- height: byteStream.nextTwoBytes(),
4084
- charSize: {
4085
- width: byteStream.nextTwoBytes(),
4086
- height: byteStream.nextTwoBytes(),
4087
- },
4088
- foregroundColor: byteStream.nextByte(),
4089
- backgroundColor: byteStream.nextByte(),
4090
- text: byteStream.readSubBlocks(),
4091
- };
4092
- break;
4093
- }
4094
- default:
4095
- byteStream.skipSubBlocks();
4096
- break;
4097
- }
4098
- }
4099
- function readBits(imageData, pos, len) {
4100
- const bytePos = pos >>> 3, bitPos = pos & 7;
4101
- return (((imageData[bytePos] + (imageData[bytePos + 1] << 8) + (imageData[bytePos + 2] << 16)) &
4102
- (((1 << len) - 1) << bitPos)) >>>
4103
- bitPos);
4104
- }
4105
- async function parseImageBlock(byteStream, gif, avgAlpha, getFrameIndex, getTransparencyIndex, canvasSettings, progressCallback) {
4106
- const frame = gif.frames[getFrameIndex(true)];
4107
- frame.left = byteStream.nextTwoBytes();
4108
- frame.top = byteStream.nextTwoBytes();
4109
- frame.width = byteStream.nextTwoBytes();
4110
- frame.height = byteStream.nextTwoBytes();
4111
- const packedByte = byteStream.nextByte(), localColorTableFlag = (packedByte & 0x80) === 0x80, interlacedFlag = (packedByte & 0x40) === 0x40;
4112
- frame.sortFlag = (packedByte & 0x20) === 0x20;
4113
- frame.reserved = (packedByte & 0x18) >>> 3;
4114
- const localColorCount = 1 << ((packedByte & 7) + 1);
4115
- if (localColorTableFlag) {
4116
- frame.localColorTable = parseColorTable(byteStream, localColorCount);
4117
- }
4118
- const getColor = (index) => {
4119
- const { r, g, b } = (localColorTableFlag ? frame.localColorTable : gif.globalColorTable)[index];
4120
- if (index !== getTransparencyIndex(null)) {
4121
- return { r, g, b, a: 255 };
4122
- }
4123
- return { r, g, b, a: avgAlpha ? Math.trunc((r + g + b) / 3) : 0 };
4124
- }, image = (() => {
4125
- try {
4126
- return new ImageData(frame.width, frame.height, canvasSettings);
4127
- }
4128
- catch (error) {
4129
- if (error instanceof DOMException && error.name === "IndexSizeError") {
4130
- return null;
4131
- }
4132
- throw error;
4133
- }
4134
- })();
4135
- if (image == null) {
4136
- throw new EvalError("GIF frame size is to large");
4137
- }
4138
- const minCodeSize = byteStream.nextByte(), imageData = byteStream.readSubBlocksBin(), clearCode = 1 << minCodeSize;
4139
- if (interlacedFlag) {
4140
- for (let code = 0, size = minCodeSize + 1, pos = 0, dic = [[0]], pass = 0; pass < 4; pass++) {
4141
- if (InterlaceOffsets[pass] < frame.height) {
4142
- let pixelPos = 0, lineIndex = 0, exit = false;
4143
- while (!exit) {
4144
- const last = code;
4145
- code = readBits(imageData, pos, size);
4146
- pos += size + 1;
4147
- if (code === clearCode) {
4148
- size = minCodeSize + 1;
4149
- dic.length = clearCode + 2;
4150
- for (let i = 0; i < dic.length; i++) {
4151
- dic[i] = i < clearCode ? [i] : [];
4152
- }
4153
- }
4154
- else {
4155
- if (code >= dic.length) {
4156
- dic.push(dic[last].concat(dic[last][0]));
4157
- }
4158
- else if (last !== clearCode) {
4159
- dic.push(dic[last].concat(dic[code][0]));
4160
- }
4161
- for (const item of dic[code]) {
4162
- const { r, g, b, a } = getColor(item);
4163
- image.data.set([r, g, b, a], InterlaceOffsets[pass] * frame.width +
4164
- InterlaceSteps[pass] * lineIndex +
4165
- (pixelPos % (frame.width * 4)));
4166
- pixelPos += 4;
4167
- }
4168
- if (dic.length === 1 << size && size < 0xc) {
4169
- size++;
4170
- }
4171
- }
4172
- if (pixelPos === frame.width * 4 * (lineIndex + 1)) {
4173
- lineIndex++;
4174
- if (InterlaceOffsets[pass] + InterlaceSteps[pass] * lineIndex >= frame.height) {
4175
- exit = true;
4176
- }
4177
- }
4178
- }
4179
- }
4180
- }
4181
- frame.image = image;
4182
- frame.bitmap = await createImageBitmap(image);
4183
- }
4184
- else {
4185
- let code = 0, size = minCodeSize + 1, pos = 0, pixelPos = -4;
4186
- const dic = [[0]];
4187
- for (;;) {
4188
- const last = code;
4189
- code = readBits(imageData, pos, size);
4190
- pos += size;
4191
- if (code === clearCode) {
4192
- size = minCodeSize + 1;
4193
- dic.length = clearCode + 2;
4194
- for (let i = 0; i < dic.length; i++) {
4195
- dic[i] = i < clearCode ? [i] : [];
4196
- }
4197
- }
4198
- else {
4199
- if (code === clearCode + 1) {
4200
- break;
4201
- }
4202
- if (code >= dic.length) {
4203
- dic.push(dic[last].concat(dic[last][0]));
4204
- }
4205
- else if (last !== clearCode) {
4206
- dic.push(dic[last].concat(dic[code][0]));
4207
- }
4208
- for (const item of dic[code]) {
4209
- const { r, g, b, a } = getColor(item);
4210
- pixelPos += 4;
4211
- image.data.set([r, g, b, a], pixelPos);
4212
- }
4213
- if (dic.length >= 1 << size && size < 0xc) {
4214
- size++;
4215
- }
4216
- }
4217
- }
4218
- frame.image = image;
4219
- frame.bitmap = await createImageBitmap(image);
4220
- }
4221
- }
4222
- async function parseBlock(byteStream, gif, avgAlpha, getFrameIndex, getTransparencyIndex, canvasSettings, progressCallback) {
4223
- switch (byteStream.nextByte()) {
4224
- case GIFDataHeaders.EndOfFile:
4225
- return true;
4226
- case GIFDataHeaders.Image:
4227
- await parseImageBlock(byteStream, gif, avgAlpha, getFrameIndex, getTransparencyIndex, canvasSettings);
4228
- break;
4229
- case GIFDataHeaders.Extension:
4230
- parseExtensionBlock(byteStream, gif, getFrameIndex, getTransparencyIndex);
4231
- break;
4232
- default:
4233
- throw new EvalError("undefined block found");
4234
- }
4235
- return false;
4236
- }
4237
- function getGIFLoopAmount(gif) {
4238
- for (const extension of gif.applicationExtensions) {
4239
- if (extension.identifier + extension.authenticationCode !== "NETSCAPE2.0") {
4240
- continue;
4241
- }
4242
- return extension.data[1] + (extension.data[2] << 8);
4243
- }
4244
- return Number.NaN;
4245
- }
4246
- async function decodeGIF(gifURL, canvasSettings, progressCallback, avgAlpha) {
4247
- avgAlpha ??= false;
4248
- const res = await fetch(gifURL);
4249
- if (!res.ok && res.status === 404) {
4250
- throw new EvalError("file not found");
4251
- }
4252
- const buffer = await res.arrayBuffer(), gif = {
4253
- width: 0,
4254
- height: 0,
4255
- totalTime: 0,
4256
- colorRes: 0,
4257
- pixelAspectRatio: 0,
4258
- frames: [],
4259
- sortFlag: false,
4260
- globalColorTable: [],
4261
- backgroundImage: new ImageData(1, 1, canvasSettings),
4262
- comments: [],
4263
- applicationExtensions: [],
4264
- }, byteStream = new ByteStream(new Uint8ClampedArray(buffer));
4265
- if (byteStream.getString(6) !== "GIF89a") {
4266
- throw new Error("not a supported GIF file");
4267
- }
4268
- gif.width = byteStream.nextTwoBytes();
4269
- gif.height = byteStream.nextTwoBytes();
4270
- const packedByte = byteStream.nextByte(), globalColorTableFlag = (packedByte & 0x80) === 0x80;
4271
- gif.colorRes = (packedByte & 0x70) >>> 4;
4272
- gif.sortFlag = (packedByte & 8) === 8;
4273
- const globalColorCount = 1 << ((packedByte & 7) + 1), backgroundColorIndex = byteStream.nextByte();
4274
- gif.pixelAspectRatio = byteStream.nextByte();
4275
- if (gif.pixelAspectRatio !== 0) {
4276
- gif.pixelAspectRatio = (gif.pixelAspectRatio + 0xf) / 0x40;
4277
- }
4278
- if (globalColorTableFlag) {
4279
- gif.globalColorTable = parseColorTable(byteStream, globalColorCount);
4280
- }
4281
- const backgroundImage = (() => {
4282
- try {
4283
- return new ImageData(gif.width, gif.height, canvasSettings);
4284
- }
4285
- catch (error) {
4286
- if (error instanceof DOMException && error.name === "IndexSizeError") {
4287
- return null;
4288
- }
4289
- throw error;
4290
- }
4291
- })();
4292
- if (backgroundImage == null) {
4293
- throw new Error("GIF frame size is to large");
4294
- }
4295
- const { r, g, b } = gif.globalColorTable[backgroundColorIndex];
4296
- backgroundImage.data.set(globalColorTableFlag ? [r, g, b, 255] : [0, 0, 0, 0]);
4297
- for (let i = 4; i < backgroundImage.data.length; i *= 2) {
4298
- backgroundImage.data.copyWithin(i, 0, i);
4299
- }
4300
- gif.backgroundImage = backgroundImage;
4301
- let frameIndex = -1, incrementFrameIndex = true, transparencyIndex = -1;
4302
- const getframeIndex = (increment) => {
4303
- if (increment) {
4304
- incrementFrameIndex = true;
4305
- }
4306
- return frameIndex;
4307
- }, getTransparencyIndex = (newValue) => {
4308
- if (newValue != null) {
4309
- transparencyIndex = newValue;
4310
- }
4311
- return transparencyIndex;
4312
- };
4313
- try {
4314
- do {
4315
- if (incrementFrameIndex) {
4316
- gif.frames.push({
4317
- left: 0,
4318
- top: 0,
4319
- width: 0,
4320
- height: 0,
4321
- disposalMethod: DisposalMethod.Replace,
4322
- image: new ImageData(1, 1, canvasSettings),
4323
- plainTextData: null,
4324
- userInputDelayFlag: false,
4325
- delayTime: 0,
4326
- sortFlag: false,
4327
- localColorTable: [],
4328
- reserved: 0,
4329
- GCreserved: 0,
4330
- });
4331
- frameIndex++;
4332
- transparencyIndex = -1;
4333
- incrementFrameIndex = false;
4334
- }
4335
- } while (!(await parseBlock(byteStream, gif, avgAlpha, getframeIndex, getTransparencyIndex, canvasSettings, progressCallback)));
4336
- gif.frames.length--;
4337
- for (const frame of gif.frames) {
4338
- if (frame.userInputDelayFlag && frame.delayTime === 0) {
4339
- gif.totalTime = Infinity;
4340
- break;
4341
- }
4342
- gif.totalTime += frame.delayTime;
4343
- }
4344
- return gif;
4345
- }
4346
- catch (error) {
4347
- if (error instanceof EvalError) {
4348
- throw new Error(`error while parsing frame ${frameIndex.toString()} "${error.message}"`, { cause: error });
4349
- }
4350
- throw error;
4351
- }
4352
- }
4353
- function drawGif(data, canvasSettings) {
4354
- const { context, radius, particle, delta } = data, image = particle.image;
4355
- if (!image?.gifData || !image.gif) {
4356
- return;
4357
- }
4358
- const offscreenCanvas = new OffscreenCanvas(image.gifData.width, image.gifData.height), offscreenContext = offscreenCanvas.getContext("2d", canvasSettings);
4359
- if (!offscreenContext) {
4360
- throw new Error("could not create offscreen canvas context");
4361
- }
4362
- offscreenContext.imageSmoothingQuality = "low";
4363
- offscreenContext.imageSmoothingEnabled = false;
4364
- offscreenContext.clearRect(originPoint.x, originPoint.y, offscreenCanvas.width, offscreenCanvas.height);
4365
- particle.gifLoopCount ??= image.gifLoopCount ?? defaultLoopCount;
4366
- let frameIndex = particle.gifFrame ?? defaultFrame;
4367
- const pos = { x: -image.gifData.width * half, y: -image.gifData.height * half }, frame = image.gifData.frames[frameIndex];
4368
- particle.gifTime ??= initialTime;
4369
- if (!frame.bitmap) {
4370
- return;
4371
- }
4372
- context.scale(radius / image.gifData.width, radius / image.gifData.height);
4373
- switch (frame.disposalMethod) {
4374
- case DisposalMethod.UndefinedA:
4375
- case DisposalMethod.UndefinedB:
4376
- case DisposalMethod.UndefinedC:
4377
- case DisposalMethod.UndefinedD:
4378
- case DisposalMethod.Replace:
4379
- offscreenContext.drawImage(frame.bitmap, frame.left, frame.top);
4380
- context.drawImage(offscreenCanvas, pos.x, pos.y);
4381
- offscreenContext.clearRect(originPoint.x, originPoint.y, offscreenCanvas.width, offscreenCanvas.height);
4382
- break;
4383
- case DisposalMethod.Combine:
4384
- offscreenContext.drawImage(frame.bitmap, frame.left, frame.top);
4385
- context.drawImage(offscreenCanvas, pos.x, pos.y);
4386
- break;
4387
- case DisposalMethod.RestoreBackground:
4388
- offscreenContext.drawImage(frame.bitmap, frame.left, frame.top);
4389
- context.drawImage(offscreenCanvas, pos.x, pos.y);
4390
- offscreenContext.clearRect(originPoint.x, originPoint.y, offscreenCanvas.width, offscreenCanvas.height);
4391
- if (!image.gifData.globalColorTable.length) {
4392
- offscreenContext.putImageData(image.gifData.frames[firstIndex].image, pos.x + frame.left, pos.y + frame.top);
4393
- }
4394
- else {
4395
- offscreenContext.putImageData(image.gifData.backgroundImage, pos.x, pos.y);
4396
- }
4397
- break;
4398
- case DisposalMethod.RestorePrevious:
4399
- {
4400
- const previousImageData = offscreenContext.getImageData(originPoint.x, originPoint.y, offscreenCanvas.width, offscreenCanvas.height);
4401
- offscreenContext.drawImage(frame.bitmap, frame.left, frame.top);
4402
- context.drawImage(offscreenCanvas, pos.x, pos.y);
4403
- offscreenContext.clearRect(originPoint.x, originPoint.y, offscreenCanvas.width, offscreenCanvas.height);
4404
- offscreenContext.putImageData(previousImageData, originPoint.x, originPoint.y);
4405
- }
4406
- break;
4407
- }
4408
- particle.gifTime += delta.value;
4409
- if (particle.gifTime > frame.delayTime) {
4410
- particle.gifTime -= frame.delayTime;
4411
- if (++frameIndex >= image.gifData.frames.length) {
4412
- if (--particle.gifLoopCount <= defaultLoopCount) {
4413
- return;
4414
- }
4415
- frameIndex = firstIndex;
4416
- offscreenContext.clearRect(originPoint.x, originPoint.y, offscreenCanvas.width, offscreenCanvas.height);
4417
- }
4418
- particle.gifFrame = frameIndex;
4419
- }
4420
- context.scale(image.gifData.width / radius, image.gifData.height / radius);
4421
- }
4422
- async function loadGifImage(image, canvasSettings) {
4423
- if (image.type !== "gif") {
4424
- await loadImage(image);
4425
- return;
4426
- }
4427
- image.loading = true;
4428
- try {
4429
- image.gifData = await decodeGIF(image.source, canvasSettings);
4430
- image.gifLoopCount = getGIFLoopAmount(image.gifData);
4431
- if (!image.gifLoopCount) {
4432
- image.gifLoopCount = Infinity;
4433
- }
4434
- }
4435
- catch {
4436
- image.error = true;
4437
- }
4438
- image.loading = false;
4439
- }
4440
-
4441
3984
  const sides$2 = 12;
4442
3985
  class ImageDrawer {
4443
3986
  #container;
@@ -4452,10 +3995,7 @@
4452
3995
  return;
4453
3996
  }
4454
3997
  context.globalAlpha = opacity;
4455
- if (image.gif && image.gifData) {
4456
- drawGif(data, this.#container.canvas.render.settings);
4457
- }
4458
- else if (element) {
3998
+ if (element) {
4459
3999
  const ratio = image.ratio, pos = {
4460
4000
  x: -radius,
4461
4001
  y: -radius,
@@ -4524,9 +4064,6 @@
4524
4064
  color,
4525
4065
  data: image,
4526
4066
  element: image.element,
4527
- gif: image.gif,
4528
- gifData: image.gifData,
4529
- gifLoopCount: image.gifLoopCount,
4530
4067
  loaded: true,
4531
4068
  ratio: imageData.width && imageData.height ? imageData.width / imageData.height : (image.ratio ?? defaultRatio),
4532
4069
  replaceColor: replaceColor,
@@ -4549,7 +4086,6 @@
4549
4086
  throw new Error(`Image shape not initialized`);
4550
4087
  }
4551
4088
  await this.#engine.loadImage(container, {
4552
- gif: imageShape.gif,
4553
4089
  name: imageShape.name,
4554
4090
  replaceColor: imageShape.replaceColor,
4555
4091
  src: imageShape.src,
@@ -4558,7 +4094,6 @@
4558
4094
  }
4559
4095
 
4560
4096
  class Preload {
4561
- gif = false;
4562
4097
  height;
4563
4098
  name;
4564
4099
  replaceColor;
@@ -4568,7 +4103,6 @@
4568
4103
  if (isNull(data)) {
4569
4104
  return;
4570
4105
  }
4571
- loadProperty(this, "gif", data.gif);
4572
4106
  loadProperty(this, "height", data.height);
4573
4107
  loadProperty(this, "name", data.name);
4574
4108
  loadProperty(this, "replaceColor", data.replaceColor);
@@ -4635,7 +4169,6 @@
4635
4169
  }
4636
4170
  try {
4637
4171
  const image = {
4638
- gif: data.gif,
4639
4172
  name: data.name ?? data.src,
4640
4173
  source: data.src,
4641
4174
  type: data.src.substring(data.src.length - extLength),
@@ -4647,10 +4180,7 @@
4647
4180
  containerImages.push(image);
4648
4181
  engine.images.set(container, containerImages);
4649
4182
  let imageFunc;
4650
- if (data.gif) {
4651
- imageFunc = (img) => loadGifImage(img, { colorSpace: "srgb" });
4652
- }
4653
- else if (data.replaceColor) {
4183
+ if (data.replaceColor) {
4654
4184
  imageFunc = downloadSvgImage;
4655
4185
  }
4656
4186
  else {
@@ -4664,7 +4194,7 @@
4664
4194
  };
4665
4195
  }
4666
4196
  async function loadImageShape(engine) {
4667
- engine.checkVersion("4.2.1");
4197
+ engine.checkVersion("4.3.0");
4668
4198
  await engine.pluginManager.register(e => {
4669
4199
  addLoadImageToEngine(e);
4670
4200
  e.pluginManager.addPlugin(new ImagePreloaderPlugin(e));
@@ -4809,7 +4339,7 @@
4809
4339
  }
4810
4340
 
4811
4341
  async function loadLifeUpdater(engine) {
4812
- engine.checkVersion("4.2.1");
4342
+ engine.checkVersion("4.3.0");
4813
4343
  await engine.pluginManager.register(e => {
4814
4344
  e.pluginManager.addParticleUpdater("life", container => {
4815
4345
  return Promise.resolve(new LifeUpdater(container));
@@ -4863,7 +4393,7 @@
4863
4393
  }
4864
4394
 
4865
4395
  async function loadMotionPlugin(engine) {
4866
- engine.checkVersion("4.2.1");
4396
+ engine.checkVersion("4.3.0");
4867
4397
  await engine.pluginManager.register(e => {
4868
4398
  e.pluginManager.addPlugin(new MotionPlugin());
4869
4399
  });
@@ -4948,19 +4478,19 @@
4948
4478
  }
4949
4479
 
4950
4480
  async function loadGenericPolygonShape(engine) {
4951
- engine.checkVersion("4.2.1");
4481
+ engine.checkVersion("4.3.0");
4952
4482
  await engine.pluginManager.register(e => {
4953
4483
  e.pluginManager.addShape(["polygon"], () => Promise.resolve(new PolygonDrawer()));
4954
4484
  });
4955
4485
  }
4956
4486
  async function loadTriangleShape(engine) {
4957
- engine.checkVersion("4.2.1");
4487
+ engine.checkVersion("4.3.0");
4958
4488
  await engine.pluginManager.register(e => {
4959
4489
  e.pluginManager.addShape(["triangle"], () => Promise.resolve(new TriangleDrawer()));
4960
4490
  });
4961
4491
  }
4962
4492
  async function loadPolygonShape(engine) {
4963
- engine.checkVersion("4.2.1");
4493
+ engine.checkVersion("4.3.0");
4964
4494
  await Promise.all([
4965
4495
  loadGenericPolygonShape(engine),
4966
4496
  loadTriangleShape(engine),
@@ -5094,7 +4624,7 @@
5094
4624
  }
5095
4625
 
5096
4626
  async function loadRollUpdater(engine) {
5097
- engine.checkVersion("4.2.1");
4627
+ engine.checkVersion("4.3.0");
5098
4628
  await engine.pluginManager.register(e => {
5099
4629
  e.pluginManager.addParticleUpdater("roll", () => {
5100
4630
  return Promise.resolve(new RollUpdater(e.pluginManager));
@@ -5200,7 +4730,7 @@
5200
4730
  }
5201
4731
 
5202
4732
  async function loadRotateUpdater(engine) {
5203
- engine.checkVersion("4.2.1");
4733
+ engine.checkVersion("4.3.0");
5204
4734
  await engine.pluginManager.register(e => {
5205
4735
  e.pluginManager.addParticleUpdater("rotate", container => {
5206
4736
  return Promise.resolve(new RotateUpdater(container));
@@ -5224,7 +4754,7 @@
5224
4754
  }
5225
4755
 
5226
4756
  async function loadSquareShape(engine) {
5227
- engine.checkVersion("4.2.1");
4757
+ engine.checkVersion("4.3.0");
5228
4758
  await engine.pluginManager.register(e => {
5229
4759
  e.pluginManager.addShape(["edge", "square"], () => Promise.resolve(new SquareDrawer()));
5230
4760
  });
@@ -5258,7 +4788,7 @@
5258
4788
  }
5259
4789
 
5260
4790
  async function loadStarShape(engine) {
5261
- engine.checkVersion("4.2.1");
4791
+ engine.checkVersion("4.3.0");
5262
4792
  await engine.pluginManager.register(e => {
5263
4793
  e.pluginManager.addShape(["star"], () => Promise.resolve(new StarDrawer()));
5264
4794
  });
@@ -5367,7 +4897,7 @@
5367
4897
  }
5368
4898
 
5369
4899
  async function loadTiltUpdater(engine) {
5370
- engine.checkVersion("4.2.1");
4900
+ engine.checkVersion("4.3.0");
5371
4901
  await engine.pluginManager.register(e => {
5372
4902
  e.pluginManager.addParticleUpdater("tilt", container => {
5373
4903
  return Promise.resolve(new TiltUpdater(container));
@@ -5469,7 +4999,7 @@
5469
4999
  }
5470
5000
 
5471
5001
  async function loadWobbleUpdater(engine) {
5472
- engine.checkVersion("4.2.1");
5002
+ engine.checkVersion("4.3.0");
5473
5003
  await engine.pluginManager.register(e => {
5474
5004
  e.pluginManager.addParticleUpdater("wobble", container => {
5475
5005
  return Promise.resolve(new WobbleUpdater(container));
@@ -5874,7 +5404,7 @@
5874
5404
 
5875
5405
  let initPromise = null;
5876
5406
  async function doInitPlugins(engine) {
5877
- engine.checkVersion("4.2.1");
5407
+ engine.checkVersion("4.3.0");
5878
5408
  await engine.pluginManager.register(async (e) => {
5879
5409
  await Promise.all([
5880
5410
  loadBasic(e),
@@ -5947,7 +5477,7 @@
5947
5477
  confetti.init = async () => {
5948
5478
  await initPlugins(tsParticles);
5949
5479
  };
5950
- confetti.version = "4.2.1";
5480
+ confetti.version = "4.3.0";
5951
5481
  globalThis.confetti = confetti;
5952
5482
 
5953
5483
  const globalObject = globalThis;
@@ -5962,10 +5492,10 @@
5962
5492
  }
5963
5493
  }
5964
5494
  class RenderManager {
5495
+ #backgroundElement;
5496
+ #backgroundWarnings;
5965
5497
  #canvasClearPlugins;
5966
5498
  #canvasManager;
5967
- #canvasPaintPlugins;
5968
- #clearDrawPlugins;
5969
5499
  #colorPlugins;
5970
5500
  #container;
5971
5501
  #context;
@@ -5973,9 +5503,7 @@
5973
5503
  #drawParticlePlugins;
5974
5504
  #drawParticlesCleanupPlugins;
5975
5505
  #drawParticlesSetupPlugins;
5976
- #drawPlugins;
5977
- #drawSettingsCleanupPlugins;
5978
- #drawSettingsSetupPlugins;
5506
+ #layers;
5979
5507
  #pluginManager;
5980
5508
  #postDrawUpdaters;
5981
5509
  #preDrawUpdaters;
@@ -5987,18 +5515,25 @@
5987
5515
  this.#container = container;
5988
5516
  this.#canvasManager = canvasManager;
5989
5517
  this.#context = null;
5518
+ this.#backgroundElement = null;
5519
+ this.#backgroundWarnings = new Set();
5990
5520
  this.#preDrawUpdaters = [];
5991
5521
  this.#postDrawUpdaters = [];
5992
- this.#colorPlugins = [];
5993
5522
  this.#canvasClearPlugins = [];
5994
- this.#canvasPaintPlugins = [];
5995
- this.#clearDrawPlugins = [];
5523
+ this.#colorPlugins = [];
5996
5524
  this.#drawParticlePlugins = [];
5997
5525
  this.#drawParticlesCleanupPlugins = [];
5998
5526
  this.#drawParticlesSetupPlugins = [];
5999
- this.#drawPlugins = [];
6000
- this.#drawSettingsSetupPlugins = [];
6001
- this.#drawSettingsCleanupPlugins = [];
5527
+ this.#layers = {
5528
+ 0: [],
5529
+ 1: [],
5530
+ 2: [],
5531
+ 3: [],
5532
+ 4: [],
5533
+ 5: [],
5534
+ 6: [],
5535
+ 7: [],
5536
+ };
6002
5537
  }
6003
5538
  get settings() {
6004
5539
  return this.#contextSettings;
@@ -6012,32 +5547,38 @@
6012
5547
  });
6013
5548
  }
6014
5549
  clear() {
6015
- let pluginHandled = false;
6016
5550
  for (const plugin of this.#canvasClearPlugins) {
6017
- pluginHandled = plugin.canvasClear?.() ?? false;
6018
- if (pluginHandled) {
6019
- break;
5551
+ if (plugin.canvasClear?.() ?? false) {
5552
+ return;
6020
5553
  }
6021
5554
  }
6022
- if (pluginHandled) {
6023
- return;
5555
+ for (const layer of Object.values(exports.DrawLayer)) {
5556
+ if (typeof layer === "number") {
5557
+ for (const plugin of this.#getLayerPlugins(layer)) {
5558
+ if (plugin.canvasClear?.() ?? false) {
5559
+ return;
5560
+ }
5561
+ }
5562
+ }
6024
5563
  }
6025
5564
  this.canvasClear();
6026
5565
  }
6027
5566
  destroy() {
6028
5567
  this.stop();
5568
+ this.#backgroundElement = null;
5569
+ this.#backgroundWarnings.clear();
6029
5570
  this.#preDrawUpdaters = [];
6030
5571
  this.#postDrawUpdaters = [];
6031
- this.#colorPlugins = [];
6032
5572
  this.#canvasClearPlugins = [];
6033
- this.#canvasPaintPlugins = [];
6034
- this.#clearDrawPlugins = [];
5573
+ this.#colorPlugins = [];
6035
5574
  this.#drawParticlePlugins = [];
6036
5575
  this.#drawParticlesCleanupPlugins = [];
6037
5576
  this.#drawParticlesSetupPlugins = [];
6038
- this.#drawPlugins = [];
6039
- this.#drawSettingsSetupPlugins = [];
6040
- this.#drawSettingsCleanupPlugins = [];
5577
+ for (const layer of Object.values(exports.DrawLayer)) {
5578
+ if (typeof layer === "number") {
5579
+ this.#layers[layer] = [];
5580
+ }
5581
+ }
6041
5582
  }
6042
5583
  draw(cb) {
6043
5584
  const ctx = this.#context;
@@ -6094,21 +5635,40 @@
6094
5635
  });
6095
5636
  }
6096
5637
  drawParticles(delta) {
6097
- const { particles } = this.#container;
5638
+ const { particles, actualOptions } = this.#container;
6098
5639
  this.clear();
6099
5640
  particles.update(delta);
6100
5641
  this.draw(ctx => {
6101
- for (const plugin of this.#drawSettingsSetupPlugins) {
5642
+ const width = this.#canvasManager.size.width, height = this.#canvasManager.size.height;
5643
+ if (this.#backgroundElement) {
5644
+ try {
5645
+ ctx.drawImage(this.#backgroundElement, originPoint.x, originPoint.y, width, height);
5646
+ }
5647
+ catch {
5648
+ this.#warnOnce("background-element-draw-error", "Error drawing background element onto canvas");
5649
+ }
5650
+ }
5651
+ const background = actualOptions.background;
5652
+ if (background.draw) {
5653
+ try {
5654
+ background.draw(ctx, delta);
5655
+ }
5656
+ catch {
5657
+ this.#warnOnce("background-draw-error", "Error in background.draw callback");
5658
+ }
5659
+ }
5660
+ for (const plugin of this.#getLayerPlugins(exports.DrawLayer.BackgroundMask)) {
5661
+ plugin.canvasPaint?.();
5662
+ }
5663
+ for (const plugin of this.#getLayerPlugins(exports.DrawLayer.CanvasSetup)) {
6102
5664
  plugin.drawSettingsSetup?.(ctx, delta);
6103
5665
  }
6104
- for (const plugin of this.#drawPlugins) {
5666
+ for (const plugin of this.#getLayerPlugins(exports.DrawLayer.PluginContent)) {
6105
5667
  plugin.draw?.(ctx, delta);
6106
5668
  }
6107
5669
  particles.drawParticles(delta);
6108
- for (const plugin of this.#clearDrawPlugins) {
5670
+ for (const plugin of this.#getLayerPlugins(exports.DrawLayer.CanvasCleanup)) {
6109
5671
  plugin.clearDraw?.(ctx, delta);
6110
- }
6111
- for (const plugin of this.#drawSettingsCleanupPlugins) {
6112
5672
  plugin.drawSettingsCleanup?.(ctx, delta);
6113
5673
  }
6114
5674
  });
@@ -6116,29 +5676,24 @@
6116
5676
  init() {
6117
5677
  this.initUpdaters();
6118
5678
  this.initPlugins();
5679
+ this.#resolveBackgroundElement();
6119
5680
  this.paint();
6120
5681
  }
6121
5682
  initPlugins() {
6122
- this.#colorPlugins = [];
6123
5683
  this.#canvasClearPlugins = [];
6124
- this.#canvasPaintPlugins = [];
6125
- this.#clearDrawPlugins = [];
5684
+ this.#colorPlugins = [];
6126
5685
  this.#drawParticlePlugins = [];
6127
5686
  this.#drawParticlesSetupPlugins = [];
6128
5687
  this.#drawParticlesCleanupPlugins = [];
6129
- this.#drawPlugins = [];
6130
- this.#drawSettingsSetupPlugins = [];
6131
- this.#drawSettingsCleanupPlugins = [];
5688
+ for (const layer of Object.values(exports.DrawLayer)) {
5689
+ if (typeof layer === "number") {
5690
+ this.#layers[layer] = [];
5691
+ }
5692
+ }
6132
5693
  for (const plugin of this.#container.plugins) {
6133
5694
  if (plugin.particleFillColor ?? plugin.particleStrokeColor) {
6134
5695
  this.#colorPlugins.push(plugin);
6135
5696
  }
6136
- if (plugin.canvasClear) {
6137
- this.#canvasClearPlugins.push(plugin);
6138
- }
6139
- if (plugin.canvasPaint) {
6140
- this.#canvasPaintPlugins.push(plugin);
6141
- }
6142
5697
  if (plugin.drawParticle) {
6143
5698
  this.#drawParticlePlugins.push(plugin);
6144
5699
  }
@@ -6148,17 +5703,20 @@
6148
5703
  if (plugin.drawParticleCleanup) {
6149
5704
  this.#drawParticlesCleanupPlugins.push(plugin);
6150
5705
  }
6151
- if (plugin.draw) {
6152
- this.#drawPlugins.push(plugin);
5706
+ if (plugin.canvasClear) {
5707
+ this.#canvasClearPlugins.push(plugin);
5708
+ }
5709
+ if (plugin.canvasPaint) {
5710
+ this.#getLayerPlugins(exports.DrawLayer.BackgroundMask).push(plugin);
6153
5711
  }
6154
5712
  if (plugin.drawSettingsSetup) {
6155
- this.#drawSettingsSetupPlugins.push(plugin);
5713
+ this.#getLayerPlugins(exports.DrawLayer.CanvasSetup).push(plugin);
6156
5714
  }
6157
- if (plugin.drawSettingsCleanup) {
6158
- this.#drawSettingsCleanupPlugins.push(plugin);
5715
+ if (plugin.draw) {
5716
+ this.#getLayerPlugins(exports.DrawLayer.PluginContent).push(plugin);
6159
5717
  }
6160
- if (plugin.clearDraw) {
6161
- this.#clearDrawPlugins.push(plugin);
5718
+ if (plugin.clearDraw ?? plugin.drawSettingsCleanup) {
5719
+ this.#getLayerPlugins(exports.DrawLayer.CanvasCleanup).push(plugin);
6162
5720
  }
6163
5721
  }
6164
5722
  }
@@ -6176,7 +5734,7 @@
6176
5734
  }
6177
5735
  paint() {
6178
5736
  let handled = false;
6179
- for (const plugin of this.#canvasPaintPlugins) {
5737
+ for (const plugin of this.#getLayerPlugins(exports.DrawLayer.BackgroundMask)) {
6180
5738
  handled = plugin.canvasPaint?.() ?? false;
6181
5739
  if (handled) {
6182
5740
  break;
@@ -6349,6 +5907,9 @@
6349
5907
  }
6350
5908
  drawer.beforeDraw(data);
6351
5909
  }
5910
+ #getLayerPlugins(layer) {
5911
+ return this.#layers[layer];
5912
+ }
6352
5913
  #getPluginParticleColors(particle) {
6353
5914
  let fColor, sColor;
6354
5915
  for (const plugin of this.#colorPlugins) {
@@ -6366,6 +5927,39 @@
6366
5927
  this.#reusablePluginColors[sColorIndex] = sColor;
6367
5928
  return this.#reusablePluginColors;
6368
5929
  }
5930
+ #resolveBackgroundElement() {
5931
+ const background = this.#container.actualOptions.background;
5932
+ this.#backgroundElement = null;
5933
+ if (!background.element) {
5934
+ return;
5935
+ }
5936
+ if (typeof background.element === "string") {
5937
+ if (typeof document !== "undefined") {
5938
+ const node = document.querySelector(background.element);
5939
+ if (node instanceof HTMLCanvasElement || node instanceof HTMLVideoElement || node instanceof HTMLImageElement) {
5940
+ this.#backgroundElement = node;
5941
+ }
5942
+ else if (node) {
5943
+ this.#warnOnce("background-element-not-supported", `Background element "${background.element}" is not a supported drawable element (canvas, video, or img)`);
5944
+ }
5945
+ else {
5946
+ this.#warnOnce("background-element-not-found", `Background element selector "${background.element}" not found`);
5947
+ }
5948
+ }
5949
+ }
5950
+ else if (background.element instanceof HTMLCanvasElement ||
5951
+ background.element instanceof OffscreenCanvas ||
5952
+ background.element instanceof HTMLVideoElement ||
5953
+ background.element instanceof HTMLImageElement) {
5954
+ this.#backgroundElement = background.element;
5955
+ }
5956
+ }
5957
+ #warnOnce(key, message) {
5958
+ if (!this.#backgroundWarnings.has(key)) {
5959
+ this.#backgroundWarnings.add(key);
5960
+ getLogger().warning(message);
5961
+ }
5962
+ }
6369
5963
  }
6370
5964
 
6371
5965
  const transferredCanvases = new WeakMap(), getTransferredCanvas = (canvas) => {
@@ -6942,7 +6536,6 @@
6942
6536
  }
6943
6537
  class Particle {
6944
6538
  backColor;
6945
- bubble;
6946
6539
  destroyed;
6947
6540
  direction;
6948
6541
  effect;
@@ -6976,7 +6569,6 @@
6976
6569
  shapeData;
6977
6570
  sides;
6978
6571
  size;
6979
- slow;
6980
6572
  spawning;
6981
6573
  strokeColor;
6982
6574
  strokeOpacity;
@@ -6998,18 +6590,25 @@
6998
6590
  d: 1,
6999
6591
  };
7000
6592
  #container;
6593
+ #modifiers = [];
7001
6594
  #pluginManager;
7002
6595
  constructor(pluginManager, container) {
7003
6596
  this.#pluginManager = pluginManager;
7004
6597
  this.#container = container;
7005
6598
  }
6599
+ addModifier(modifier) {
6600
+ this.#modifiers.push(modifier);
6601
+ this.#modifiers.sort((a, b) => a.priority - b.priority);
6602
+ }
6603
+ clearModifiers() {
6604
+ this.#modifiers.length = 0;
6605
+ }
7006
6606
  destroy(override) {
7007
6607
  if (this.unbreakable || this.destroyed) {
7008
6608
  return;
7009
6609
  }
7010
6610
  this.destroyed = true;
7011
- this.bubble.inRange = false;
7012
- this.slow.inRange = false;
6611
+ this.clearModifiers();
7013
6612
  const container = this.#container, shapeDrawer = this.shape ? container.shapeDrawers.get(this.shape) : undefined;
7014
6613
  shapeDrawer?.particleDestroy?.(this);
7015
6614
  for (const plugin of container.particleDestroyedPlugins) {
@@ -7031,13 +6630,16 @@
7031
6630
  return this.rotation + (this.pathRotation ? this.velocity.angle : defaultAngle);
7032
6631
  }
7033
6632
  getFillColor() {
7034
- return this.#getRollColor(this.bubble.color ?? getHslFromAnimation(this.fillColor));
6633
+ return this.#getRollColor(this.#applyModifiers(getHslFromAnimation(this.fillColor), m => m.fillColor));
7035
6634
  }
7036
6635
  getMass() {
7037
6636
  return this.getRadius() ** squareExp * Math.PI * half;
7038
6637
  }
6638
+ getModifier(id) {
6639
+ return this.#modifiers.find(m => m.id === id);
6640
+ }
7039
6641
  getOpacity() {
7040
- const zIndexOptions = this.options.zIndex, zIndexFactor = zIndexFactorOffset - this.zIndexFactor, zOpacityFactor = zIndexFactor ** zIndexOptions.opacityRate, opacity = this.bubble.opacity ?? getRangeValue(this.opacity?.value ?? defaultOpacity$2), fillOpacity = this.fillOpacity ?? defaultOpacity$2, strokeOpacity = this.strokeOpacity ?? defaultOpacity$2;
6642
+ const zIndexOptions = this.options.zIndex, zIndexFactor = zIndexFactorOffset - this.zIndexFactor, zOpacityFactor = zIndexFactor ** zIndexOptions.opacityRate, baseOpacity = getRangeValue(this.opacity?.value ?? defaultOpacity$2), modifierOpacity = this.#applyModifiers(undefined, m => m.opacity), opacity = modifierOpacity ?? baseOpacity, fillOpacity = this.fillOpacity ?? defaultOpacity$2, strokeOpacity = this.strokeOpacity ?? defaultOpacity$2;
7041
6643
  this.#cachedOpacityData.fillOpacity = opacity * fillOpacity * zOpacityFactor;
7042
6644
  this.#cachedOpacityData.opacity = opacity * zOpacityFactor;
7043
6645
  this.#cachedOpacityData.strokeOpacity = opacity * strokeOpacity * zOpacityFactor;
@@ -7050,7 +6652,7 @@
7050
6652
  return this.#cachedPosition;
7051
6653
  }
7052
6654
  getRadius() {
7053
- return this.bubble.radius ?? this.size.value;
6655
+ return this.#applyModifiers(this.size.value, m => m.radius);
7054
6656
  }
7055
6657
  getRotateData() {
7056
6658
  const angle = this.getAngle();
@@ -7059,7 +6661,7 @@
7059
6661
  return this.#cachedRotateData;
7060
6662
  }
7061
6663
  getStrokeColor() {
7062
- return this.#getRollColor(this.bubble.color ?? getHslFromAnimation(this.strokeColor));
6664
+ return this.#getRollColor(this.#applyModifiers(getHslFromAnimation(this.strokeColor), m => m.strokeColor));
7063
6665
  }
7064
6666
  getTransformData(externalTransform) {
7065
6667
  const rotateData = this.getRotateData(), rotating = this.isRotating;
@@ -7079,13 +6681,6 @@
7079
6681
  this.options = resolveParticleOptions(this, container, this.#pluginManager, overrideOptions);
7080
6682
  container.retina.initParticle(this);
7081
6683
  runUpdaterPreInit(container.particleUpdaters, this);
7082
- this.bubble = {
7083
- inRange: false,
7084
- };
7085
- this.slow = {
7086
- inRange: false,
7087
- factor: 1,
7088
- };
7089
6684
  this.#initPosition(position);
7090
6685
  this.initialVelocity = this.#calculateVelocity();
7091
6686
  this.velocity = this.initialVelocity.copy();
@@ -7125,11 +6720,29 @@
7125
6720
  isVisible() {
7126
6721
  return !this.destroyed && !this.spawning && this.isInsideCanvas();
7127
6722
  }
6723
+ removeModifier(id) {
6724
+ const idx = this.#modifiers.findIndex(m => m.id === id);
6725
+ if (idx >= defaultAngle) {
6726
+ this.#modifiers.splice(idx, identity$2);
6727
+ }
6728
+ }
7128
6729
  reset() {
7129
6730
  for (const updater of this.#container.particleUpdaters) {
7130
6731
  updater.reset?.(this);
7131
6732
  }
7132
6733
  }
6734
+ #applyModifiers(base, getter) {
6735
+ let value = base;
6736
+ for (const mod of this.#modifiers) {
6737
+ if (mod.enabled) {
6738
+ const override = getter(mod);
6739
+ if (override !== undefined) {
6740
+ value = override;
6741
+ }
6742
+ }
6743
+ }
6744
+ return value;
6745
+ }
7133
6746
  #calcPosition(position, zIndex) {
7134
6747
  let tryCount = defaultRetryCount, posVec = position ? Vector3d.create(position.x, position.y, zIndex) : undefined;
7135
6748
  const container = this.#container, plugins = container.particlePositionPlugins, outModes = this.options.move.outModes, radius = this.getRadius(), canvasSize = container.canvas.size;
@@ -8231,6 +7844,7 @@
8231
7844
  });
8232
7845
 
8233
7846
  class BlendPluginInstance {
7847
+ layer = exports.DrawLayer.CanvasSetup;
8234
7848
  #container;
8235
7849
  #defaultCompositeValue;
8236
7850
  constructor(container) {
@@ -8376,7 +7990,8 @@
8376
7990
  particle.lastPathTime -= pathDelay;
8377
7991
  }
8378
7992
  function getProximitySpeedFactor(particle) {
8379
- return particle.slow.inRange ? particle.slow.factor : identity$2;
7993
+ const mod = particle.getModifier("slow");
7994
+ return mod?.enabled ? (mod.speedFactor ?? identity$2) : identity$2;
8380
7995
  }
8381
7996
  function initSpin(container, particle) {
8382
7997
  const options = particle.options, spinOptions = options.move.spin;
@@ -9179,6 +8794,7 @@
9179
8794
  exports.hPhase = hPhase;
9180
8795
  exports.half = half;
9181
8796
  exports.hslToRgb = hslToRgb;
8797
+ exports.hslToRgbFloat = hslToRgbFloat;
9182
8798
  exports.hslaToRgba = hslaToRgba;
9183
8799
  exports.identity = identity$2;
9184
8800
  exports.inverseFactorNumerator = inverseFactorNumerator;