@tsparticles/particles 4.3.2 → 4.4.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.3.2 */
2
+ /* tsParticles v4.4.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) :
@@ -880,7 +880,7 @@
880
880
  return this.#domArray;
881
881
  }
882
882
  get version() {
883
- return "4.3.2";
883
+ return "4.4.0";
884
884
  }
885
885
  addEventListener(type, listener) {
886
886
  this.#eventDispatcher.addEventListener(type, listener);
@@ -961,6 +961,10 @@
961
961
  }
962
962
 
963
963
  function initEngine() {
964
+ const existing = globalThis.tsParticles;
965
+ if (existing?.pluginManager) {
966
+ return existing;
967
+ }
964
968
  return new Engine();
965
969
  }
966
970
 
@@ -1058,6 +1062,15 @@
1058
1062
  AnimationMode["random"] = "random";
1059
1063
  })(exports.AnimationMode || (exports.AnimationMode = {}));
1060
1064
 
1065
+ exports.HdrMode = void 0;
1066
+ (function (HdrMode) {
1067
+ HdrMode["standard"] = "standard";
1068
+ HdrMode["natural"] = "natural";
1069
+ HdrMode["vivid"] = "vivid";
1070
+ HdrMode["cinematic"] = "cinematic";
1071
+ HdrMode["dynamic"] = "dynamic";
1072
+ })(exports.HdrMode || (exports.HdrMode = {}));
1073
+
1061
1074
  exports.LimitMode = void 0;
1062
1075
  (function (LimitMode) {
1063
1076
  LimitMode["delete"] = "delete";
@@ -1323,6 +1336,29 @@
1323
1336
  }
1324
1337
  }
1325
1338
 
1339
+ const defaultPeakNits = 400, minPeakNits = 0, toStringValue = (value) => String(value);
1340
+ class HDROptions extends OptionLoader {
1341
+ enable = true;
1342
+ mode = exports.HdrMode.standard;
1343
+ peakNits = defaultPeakNits;
1344
+ doLoad(data) {
1345
+ if (data.enable !== undefined && !isBoolean(data.enable)) {
1346
+ throw new Error(`Invalid HDR "enable" value: expected a boolean, got "${String(data.enable)}"`);
1347
+ }
1348
+ if (data.mode !== undefined &&
1349
+ (typeof data.mode !== "string" || !Object.values(exports.HdrMode).includes(data.mode))) {
1350
+ throw new Error(`Invalid HDR "mode" value: expected one of ${Object.values(exports.HdrMode).join(", ")}, got "${toStringValue(data.mode)}"`);
1351
+ }
1352
+ if (data.peakNits !== undefined &&
1353
+ (!isNumber(data.peakNits) || !Number.isFinite(data.peakNits) || data.peakNits <= minPeakNits)) {
1354
+ throw new Error(`Invalid HDR "peakNits" value: expected a positive number, got "${String(data.peakNits)}"`);
1355
+ }
1356
+ loadProperty(this, "enable", data.enable);
1357
+ loadProperty(this, "mode", data.mode);
1358
+ loadProperty(this, "peakNits", data.peakNits);
1359
+ }
1360
+ }
1361
+
1326
1362
  class ResizeEvent extends OptionLoader {
1327
1363
  delay = 0.5;
1328
1364
  enable = true;
@@ -1766,7 +1802,7 @@
1766
1802
  duration = 0;
1767
1803
  fpsLimit = 120;
1768
1804
  fullScreen;
1769
- hdr = true;
1805
+ hdr;
1770
1806
  key;
1771
1807
  name;
1772
1808
  palette;
@@ -1786,6 +1822,7 @@
1786
1822
  this.#container = container;
1787
1823
  this.background = new Background();
1788
1824
  this.fullScreen = new FullScreen();
1825
+ this.hdr = new HDROptions();
1789
1826
  this.particles = loadParticlesOptions(this.#pluginManager, this.#container);
1790
1827
  this.resize = new ResizeEvent();
1791
1828
  }
@@ -1808,7 +1845,15 @@
1808
1845
  loadProperty(this, "detectRetina", data.detectRetina);
1809
1846
  loadRangeProperty(this, "duration", data.duration);
1810
1847
  loadProperty(this, "fpsLimit", data.fpsLimit);
1811
- loadProperty(this, "hdr", data.hdr);
1848
+ const hdrData = data.hdr;
1849
+ if (isBoolean(hdrData)) {
1850
+ this.hdr.enable = hdrData;
1851
+ this.hdr.mode = exports.HdrMode.standard;
1852
+ this.hdr.peakNits = 400;
1853
+ }
1854
+ else {
1855
+ this.hdr.load(hdrData);
1856
+ }
1812
1857
  loadProperty(this, "pauseOnBlur", data.pauseOnBlur);
1813
1858
  loadProperty(this, "pauseOnOutsideViewport", data.pauseOnOutsideViewport);
1814
1859
  loadProperty(this, "zLayers", data.zLayers);
@@ -1851,7 +1896,7 @@
1851
1896
  }
1852
1897
  }
1853
1898
 
1854
- const styleCache = new Map(), maxStyleCacheSize = 2000, rgbFixedPrecision = 2, hslFixedPrecision = 2, hdrRgbFixedPrecision = 4, hdrHslFixedPrecision = 4, sdrReferenceWhiteNits = 203, hdrAnimationScale = sdrReferenceWhiteNits / maxNits;
1899
+ const styleCache = new Map(), maxStyleCacheSize = 2000, rgbFixedPrecision = 2, hslFixedPrecision = 2, hdrRgbFixedPrecision = 4, hdrHslFixedPrecision = 4, sdrReferenceWhiteNits = 203, acesA = 2.51, acesB = 0.03, acesC = 2.43, acesD = 0.59, acesE = 0.14, saturationBoost = 1.15, lightnessBoost = 1.05, temperatureR = 1.05, temperatureB = 0.95, contrastFactor = 1.1, luminanceR = 0.2126, luminanceG = 0.7152, luminanceB = 0.0722, dynamicLuminanceFactor = 2, channelCount = 3, srgbThreshold = 0.04045, srgbDivisor = 12.92, srgbOffset = 0.055, srgbScale = 1.055, srgbExponent = 2.4, linearThreshold = 0.0031308, linearScale = 12.92;
1855
1900
  function getCachedStyle(key, generator) {
1856
1901
  let cached = styleCache.get(key);
1857
1902
  if (!cached) {
@@ -1863,6 +1908,48 @@
1863
1908
  }
1864
1909
  return cached;
1865
1910
  }
1911
+ function acesFilmic(x) {
1912
+ return clamp((x * (acesA * x + acesB)) / (x * (acesC * x + acesD) + acesE), none, one);
1913
+ }
1914
+ function srgbToLinear(c) {
1915
+ return c <= srgbThreshold ? c / srgbDivisor : Math.pow((c + srgbOffset) / srgbScale, srgbExponent);
1916
+ }
1917
+ function linearToSrgb(c) {
1918
+ return c <= linearThreshold ? c * linearScale : srgbScale * Math.pow(c, one / srgbExponent) - srgbOffset;
1919
+ }
1920
+ function applyHdrModeAdjustments(r, g, b, mode, maxChannel) {
1921
+ switch (mode) {
1922
+ case exports.HdrMode.vivid: {
1923
+ const avg = (r + g + b) / channelCount;
1924
+ return {
1925
+ b: clamp(clamp(avg + (b - avg) * saturationBoost, none, maxChannel) * lightnessBoost, none, maxChannel),
1926
+ g: clamp(clamp(avg + (g - avg) * saturationBoost, none, maxChannel) * lightnessBoost, none, maxChannel),
1927
+ r: clamp(clamp(avg + (r - avg) * saturationBoost, none, maxChannel) * lightnessBoost, none, maxChannel),
1928
+ };
1929
+ }
1930
+ case exports.HdrMode.cinematic: {
1931
+ const tempR = r * temperatureR, tempB = b * temperatureB, avg = (tempR + g + tempB) / channelCount;
1932
+ return {
1933
+ b: clamp(avg + (tempB - avg) * contrastFactor, none, maxChannel),
1934
+ g: clamp(avg + (g - avg) * contrastFactor, none, maxChannel),
1935
+ r: clamp(avg + (tempR - avg) * contrastFactor, none, maxChannel),
1936
+ };
1937
+ }
1938
+ case exports.HdrMode.dynamic: {
1939
+ const luminance = luminanceR * r + luminanceG * g + luminanceB * b, vividWeight = Math.min(one, luminance * dynamicLuminanceFactor), naturalWeight = one - vividWeight, avg = (r + g + b) / channelCount, vividR = clamp(avg + (r - avg) * saturationBoost, none, maxChannel) * lightnessBoost, vividG = clamp(avg + (g - avg) * saturationBoost, none, maxChannel) * lightnessBoost, vividB = clamp(avg + (b - avg) * saturationBoost, none, maxChannel) * lightnessBoost;
1940
+ return {
1941
+ b: clamp(b * naturalWeight + vividB * vividWeight, none, maxChannel),
1942
+ g: clamp(g * naturalWeight + vividG * vividWeight, none, maxChannel),
1943
+ r: clamp(r * naturalWeight + vividR * vividWeight, none, maxChannel),
1944
+ };
1945
+ }
1946
+ case exports.HdrMode.standard:
1947
+ return { b, g, r };
1948
+ case exports.HdrMode.natural:
1949
+ default:
1950
+ return { b, g, r };
1951
+ }
1952
+ }
1866
1953
  function stringToRgba(pluginManager, input) {
1867
1954
  if (!input) {
1868
1955
  return;
@@ -2030,30 +2117,65 @@
2030
2117
  r: getRgbInRangeValue(),
2031
2118
  };
2032
2119
  }
2033
- function getStyleFromRgb(color, hdr, opacity) {
2034
- 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()}`;
2035
- return getCachedStyle(key, () => (hdr ? getHdrStyleFromRgb(color, opacity) : getSdrStyleFromRgb(color, opacity)));
2120
+ function getStyleFromRgb(color, hdr, opacity, peakNits, mode) {
2121
+ const rgbPrecision = hdr ? hdrRgbFixedPrecision : rgbFixedPrecision, op = opacity ?? defaultOpacity$2, key = hdr
2122
+ ? `rgb-${color.r.toFixed(rgbPrecision)}-${color.g.toFixed(rgbPrecision)}-${color.b.toFixed(rgbPrecision)}-hdr-${op.toString()}-${(peakNits ?? maxNits).toString()}-${mode ?? exports.HdrMode.standard}`
2123
+ : `rgb-${color.r.toFixed(rgbPrecision)}-${color.g.toFixed(rgbPrecision)}-${color.b.toFixed(rgbPrecision)}-sdr-${op.toString()}`;
2124
+ return getCachedStyle(key, () => hdr ? getHdrStyleFromRgb(color, opacity, peakNits, mode) : getSdrStyleFromRgb(color, opacity));
2036
2125
  }
2037
- function getHdrStyleFromRgb(color, opacity, peakNits = maxNits) {
2038
- const headroom = peakNits / sdrReferenceWhiteNits;
2039
- return `color(display-p3 ${((color.r / rgbMax) * headroom).toString()} ${((color.g / rgbMax) * headroom).toString()} ${((color.b / rgbMax) * headroom).toString()} / ${(opacity ?? defaultOpacity$2).toString()})`;
2126
+ function getHdrStyleFromRgb(color, opacity, peakNits = maxNits, mode = exports.HdrMode.standard) {
2127
+ const headroom = peakNits / sdrReferenceWhiteNits, middleGray = 0.18, mapped = hdrToneMapColor(color, headroom, middleGray, mode);
2128
+ return `color(display-p3 ${mapped.r.toString()} ${mapped.g.toString()} ${mapped.b.toString()} / ${(opacity ?? defaultOpacity$2).toString()})`;
2129
+ }
2130
+ function hdrToneMapColor(color, headroom, middleGray, mode) {
2131
+ const rNorm = color.r / rgbMax, gNorm = color.g / rgbMax, bNorm = color.b / rgbMax;
2132
+ if (mode !== exports.HdrMode.natural && mode !== exports.HdrMode.vivid && mode !== exports.HdrMode.cinematic && mode !== exports.HdrMode.dynamic) {
2133
+ return { b: bNorm, g: gNorm, r: rNorm };
2134
+ }
2135
+ const maxChannel = Math.max(one, headroom), luminance = luminanceR * rNorm + luminanceG * gNorm + luminanceB * bNorm, mappedLuminance = hdrToneMap(luminance, headroom, middleGray), scale = luminance > none ? mappedLuminance / luminance : one;
2136
+ return applyHdrModeAdjustments(clamp(rNorm * scale, none, maxChannel), clamp(gNorm * scale, none, maxChannel), clamp(bNorm * scale, none, maxChannel), mode, maxChannel);
2137
+ }
2138
+ function hdrToneMap(normalized, headroom, middleGray) {
2139
+ if (normalized <= middleGray) {
2140
+ return acesFilmic(normalized);
2141
+ }
2142
+ const expanded = normalized + (normalized - middleGray) * (headroom - one);
2143
+ return acesFilmic(expanded);
2040
2144
  }
2041
2145
  function getSdrStyleFromRgb(color, opacity) {
2042
2146
  return `rgba(${color.r.toString()}, ${color.g.toString()}, ${color.b.toString()}, ${(opacity ?? defaultOpacity$2).toString()})`;
2043
2147
  }
2044
- function getStyleFromHsl(color, hdr, opacity) {
2045
- 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()}`;
2148
+ function getStyleFromHsl(color, hdr, opacity, peakNits, mode) {
2149
+ const hslPrecision = hdr ? hdrHslFixedPrecision : hslFixedPrecision, op = opacity ?? defaultOpacity$2, key = hdr
2150
+ ? `hsl-${color.h.toFixed(hslPrecision)}-${color.s.toFixed(hslPrecision)}-${color.l.toFixed(hslPrecision)}-hdr-${op.toString()}-${(peakNits ?? maxNits).toString()}-${mode ?? exports.HdrMode.standard}`
2151
+ : `hsl-${color.h.toFixed(hslPrecision)}-${color.s.toFixed(hslPrecision)}-${color.l.toFixed(hslPrecision)}-sdr-${op.toString()}`;
2046
2152
  return getCachedStyle(key, () => hdr
2047
- ? getStyleFromRgb(hslToRgbFloat(color), true, opacity)
2153
+ ? getStyleFromRgb(hslToRgbFloat(color), true, opacity, peakNits, mode)
2048
2154
  : `hsla(${color.h.toString()}, ${color.s.toString()}%, ${color.l.toString()}%, ${op.toString()})`);
2049
2155
  }
2050
- function colorMix(color1, color2, size1, size2) {
2156
+ function colorMix(color1, color2, size1, size2, hdr) {
2051
2157
  let rgb1 = color1, rgb2 = color2;
2052
2158
  if (!("r" in rgb1)) {
2053
- rgb1 = hslToRgb(color1);
2159
+ rgb1 = hdr ? hslToRgbFloat(color1) : hslToRgb(color1);
2054
2160
  }
2055
2161
  if (!("r" in rgb2)) {
2056
- rgb2 = hslToRgb(color2);
2162
+ rgb2 = hdr ? hslToRgbFloat(color2) : hslToRgb(color2);
2163
+ }
2164
+ if (hdr) {
2165
+ const lin1 = {
2166
+ b: srgbToLinear(rgb1.b / rgbMax),
2167
+ g: srgbToLinear(rgb1.g / rgbMax),
2168
+ r: srgbToLinear(rgb1.r / rgbMax),
2169
+ }, lin2 = {
2170
+ b: srgbToLinear(rgb2.b / rgbMax),
2171
+ g: srgbToLinear(rgb2.g / rgbMax),
2172
+ r: srgbToLinear(rgb2.r / rgbMax),
2173
+ }, totalWeight = size1 + size2;
2174
+ return {
2175
+ b: linearToSrgb((lin1.b * size1 + lin2.b * size2) / totalWeight) * rgbMax,
2176
+ g: linearToSrgb((lin1.g * size1 + lin2.g * size2) / totalWeight) * rgbMax,
2177
+ r: linearToSrgb((lin1.r * size1 + lin2.r * size2) / totalWeight) * rgbMax,
2178
+ };
2057
2179
  }
2058
2180
  return {
2059
2181
  b: mix(rgb1.b, rgb2.b, size1, size2),
@@ -2061,14 +2183,14 @@
2061
2183
  r: mix(rgb1.r, rgb2.r, size1, size2),
2062
2184
  };
2063
2185
  }
2064
- function getLinkColor(p1, p2, linkColor) {
2186
+ function getLinkColor(p1, p2, linkColor, hdr) {
2065
2187
  if (linkColor === randomColorValue) {
2066
2188
  return getRandomRgbColor();
2067
2189
  }
2068
2190
  else if (linkColor === midColorValue) {
2069
2191
  const sourceColor = p1.getFillColor() ?? p1.getStrokeColor(), destColor = p2?.getFillColor() ?? p2?.getStrokeColor();
2070
2192
  if (sourceColor && destColor && p2) {
2071
- return colorMix(sourceColor, destColor, p1.getRadius(), p2.getRadius());
2193
+ return colorMix(sourceColor, destColor, p1.getRadius(), p2.getRadius(), hdr);
2072
2194
  }
2073
2195
  else {
2074
2196
  const hslColor = sourceColor ?? destColor;
@@ -2164,7 +2286,7 @@
2164
2286
  colorValue.velocity = defaultVelocity;
2165
2287
  }
2166
2288
  }
2167
- function updateColorValue(data, decrease, delta, hdr) {
2289
+ function updateColorValue(data, decrease, delta, _hdr) {
2168
2290
  const minLoops = 0, minDelay = 0, identity = 1, minVelocity = 0, minOffset = 0, velocityFactor = 3.6;
2169
2291
  if (!data.enable ||
2170
2292
  ((data.maxLoops ?? minLoops) > minLoops && (data.loops ?? minLoops) > (data.maxLoops ?? minLoops))) {
@@ -2177,7 +2299,7 @@
2177
2299
  if ((data.delayTime ?? minDelay) > minDelay && data.time < (data.delayTime ?? minDelay)) {
2178
2300
  return;
2179
2301
  }
2180
- 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;
2302
+ 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;
2181
2303
  if (!decrease || data.status === exports.AnimationStatus.increasing) {
2182
2304
  data.value += velocity;
2183
2305
  if (data.value > max) {
@@ -2209,9 +2331,9 @@
2209
2331
  return;
2210
2332
  }
2211
2333
  const { h, s, l } = color;
2212
- updateColorValue(h, false, delta, hdr);
2213
- updateColorValue(s, true, delta, hdr);
2214
- updateColorValue(l, true, delta, hdr);
2334
+ updateColorValue(h, false, delta);
2335
+ updateColorValue(s, true, delta);
2336
+ updateColorValue(l, true, delta);
2215
2337
  }
2216
2338
  function alterHsl(color, type, value) {
2217
2339
  return {
@@ -2327,7 +2449,7 @@
2327
2449
  }
2328
2450
 
2329
2451
  async function loadBlendPlugin(engine) {
2330
- engine.checkVersion("4.3.2");
2452
+ engine.checkVersion("4.4.0");
2331
2453
  await engine.pluginManager.register(e => {
2332
2454
  e.pluginManager.addPlugin(new BlendPlugin());
2333
2455
  });
@@ -2364,7 +2486,7 @@
2364
2486
  }
2365
2487
 
2366
2488
  async function loadCircleShape(engine) {
2367
- engine.checkVersion("4.3.2");
2489
+ engine.checkVersion("4.4.0");
2368
2490
  await engine.pluginManager.register(e => {
2369
2491
  e.pluginManager.addShape(["circle"], () => {
2370
2492
  return Promise.resolve(new CircleDrawer());
@@ -2412,7 +2534,7 @@
2412
2534
  }
2413
2535
 
2414
2536
  async function loadHexColorPlugin(engine) {
2415
- engine.checkVersion("4.3.2");
2537
+ engine.checkVersion("4.4.0");
2416
2538
  await engine.pluginManager.register(e => {
2417
2539
  e.pluginManager.addColorManager("hex", new HexColorManager());
2418
2540
  });
@@ -2465,7 +2587,7 @@
2465
2587
  }
2466
2588
 
2467
2589
  async function loadHslColorPlugin(engine) {
2468
- engine.checkVersion("4.3.2");
2590
+ engine.checkVersion("4.4.0");
2469
2591
  await engine.pluginManager.register(e => {
2470
2592
  e.pluginManager.addColorManager("hsl", new HslColorManager());
2471
2593
  });
@@ -2489,7 +2611,7 @@
2489
2611
  }
2490
2612
 
2491
2613
  async function loadMovePlugin(engine) {
2492
- engine.checkVersion("4.3.2");
2614
+ engine.checkVersion("4.4.0");
2493
2615
  await engine.pluginManager.register(e => {
2494
2616
  const moveEngine = e, movePluginManager = moveEngine.pluginManager;
2495
2617
  movePluginManager.initializers.pathGenerators ??= new Map();
@@ -2699,7 +2821,7 @@
2699
2821
  }
2700
2822
 
2701
2823
  async function loadOpacityUpdater(engine) {
2702
- engine.checkVersion("4.3.2");
2824
+ engine.checkVersion("4.4.0");
2703
2825
  await engine.pluginManager.register(e => {
2704
2826
  e.pluginManager.addParticleUpdater("opacity", container => {
2705
2827
  return Promise.resolve(new OpacityUpdater(container));
@@ -3044,7 +3166,7 @@
3044
3166
  }
3045
3167
 
3046
3168
  async function loadOutModesUpdater(engine) {
3047
- engine.checkVersion("4.3.2");
3169
+ engine.checkVersion("4.4.0");
3048
3170
  await engine.pluginManager.register(e => {
3049
3171
  e.pluginManager.addParticleUpdater("outModes", container => {
3050
3172
  return Promise.resolve(new OutOfCanvasUpdater(container));
@@ -3115,7 +3237,7 @@
3115
3237
  }
3116
3238
 
3117
3239
  async function loadPaintUpdater(engine) {
3118
- engine.checkVersion("4.3.2");
3240
+ engine.checkVersion("4.4.0");
3119
3241
  await engine.pluginManager.register(e => {
3120
3242
  e.pluginManager.addParticleUpdater("paint", container => {
3121
3243
  return Promise.resolve(new PaintUpdater(e.pluginManager, container));
@@ -3170,7 +3292,7 @@
3170
3292
  }
3171
3293
 
3172
3294
  async function loadRgbColorPlugin(engine) {
3173
- engine.checkVersion("4.3.2");
3295
+ engine.checkVersion("4.4.0");
3174
3296
  await engine.pluginManager.register(e => {
3175
3297
  e.pluginManager.addColorManager("rgb", new RgbColorManager());
3176
3298
  });
@@ -3255,7 +3377,7 @@
3255
3377
  }
3256
3378
 
3257
3379
  async function loadSizeUpdater(engine) {
3258
- engine.checkVersion("4.3.2");
3380
+ engine.checkVersion("4.4.0");
3259
3381
  await engine.pluginManager.register(e => {
3260
3382
  e.pluginManager.addParticleUpdater("size", container => {
3261
3383
  return Promise.resolve(new SizeUpdater(container));
@@ -3264,7 +3386,7 @@
3264
3386
  }
3265
3387
 
3266
3388
  async function loadBasic(engine) {
3267
- engine.checkVersion("4.3.2");
3389
+ engine.checkVersion("4.4.0");
3268
3390
  await engine.pluginManager.register(async (e) => {
3269
3391
  await Promise.all([
3270
3392
  loadBlendPlugin(e),
@@ -3465,7 +3587,7 @@
3465
3587
  const clickEvent = "click", mouseDownEvent = "pointerdown", mouseUpEvent = "pointerup", mouseLeaveEvent = "pointerleave", mouseMoveEvent = "pointermove", touchStartEvent = "touchstart", touchEndEvent = "touchend", touchMoveEvent = "touchmove", touchCancelEvent = "touchcancel";
3466
3588
 
3467
3589
  async function loadInteractivityPlugin(engine) {
3468
- engine.checkVersion("4.3.2");
3590
+ engine.checkVersion("4.4.0");
3469
3591
  await engine.pluginManager.register(e => {
3470
3592
  const interactivityEngine = e, interactivityPluginManager = interactivityEngine.pluginManager;
3471
3593
  interactivityPluginManager.addPlugin(new InteractivityPlugin(interactivityPluginManager));
@@ -3699,7 +3821,7 @@
3699
3821
  }
3700
3822
 
3701
3823
  async function loadParticlesCollisionsInteraction(engine) {
3702
- engine.checkVersion("4.3.2");
3824
+ engine.checkVersion("4.4.0");
3703
3825
  await engine.pluginManager.register((e) => {
3704
3826
  ensureInteractivityPluginLoaded(e);
3705
3827
  e.pluginManager.addPlugin(new OverlapPlugin());
@@ -3912,7 +4034,7 @@
3912
4034
  const linkColor = linksOptions.id !== undefined
3913
4035
  ? container.particles.linksColors.get(linksOptions.id)
3914
4036
  : container.particles.linksColor;
3915
- return getLinkColor(p1, p2, linkColor);
4037
+ return getLinkColor(p1, p2, linkColor, container.hdr);
3916
4038
  }
3917
4039
  #setColor(p1) {
3918
4040
  if (!p1.options.links) {
@@ -3953,7 +4075,7 @@
3953
4075
  }
3954
4076
 
3955
4077
  async function loadParticlesLinksInteraction(engine) {
3956
- engine.checkVersion("4.3.2");
4078
+ engine.checkVersion("4.4.0");
3957
4079
  await engine.pluginManager.register((e) => {
3958
4080
  const pluginManager = e.pluginManager;
3959
4081
  ensureInteractivityPluginLoaded(e);
@@ -3966,7 +4088,7 @@
3966
4088
 
3967
4089
  let initPromise = null;
3968
4090
  async function doInitPlugins(engine) {
3969
- engine.checkVersion("4.3.2");
4091
+ engine.checkVersion("4.4.0");
3970
4092
  await engine.pluginManager.register(async (e) => {
3971
4093
  const loadParticlesInteractivity = async (e) => {
3972
4094
  await loadInteractivityPlugin(e);
@@ -4009,7 +4131,7 @@
4009
4131
  particles.init = async () => {
4010
4132
  await initPlugins(tsParticles);
4011
4133
  };
4012
- particles.version = "4.3.2";
4134
+ particles.version = "4.4.0";
4013
4135
  globalThis.particles = particles;
4014
4136
 
4015
4137
  const globalObject = globalThis;
@@ -4134,7 +4256,11 @@
4134
4256
  if (!fColor && !sColor) {
4135
4257
  return;
4136
4258
  }
4137
- const container = this.#container, zIndexOptions = particle.options.zIndex, zIndexFactor = zIndexFactorOffset - particle.zIndexFactor, { fillOpacity, opacity, strokeOpacity } = particle.getOpacity(), transform = this.#reusableTransform, colorStyles = this.#reusableColorStyles, fill = fColor ? getStyleFromHsl(fColor, container.hdr, fillOpacity * opacity) : undefined, stroke = sColor ? getStyleFromHsl(sColor, container.hdr, strokeOpacity * opacity) : fill;
4259
+ const container = this.#container, zIndexOptions = particle.options.zIndex, zIndexFactor = zIndexFactorOffset - particle.zIndexFactor, { fillOpacity, opacity, strokeOpacity } = particle.getOpacity(), transform = this.#reusableTransform, colorStyles = this.#reusableColorStyles, fill = fColor
4260
+ ? getStyleFromHsl(fColor, container.hdr, fillOpacity * opacity, container.peakNits, container.hdrMode)
4261
+ : undefined, stroke = sColor
4262
+ ? getStyleFromHsl(sColor, container.hdr, strokeOpacity * opacity, container.peakNits, container.hdrMode)
4263
+ : fill;
4138
4264
  transform.a = transform.b = transform.c = transform.d = undefined;
4139
4265
  colorStyles.fill = fill;
4140
4266
  colorStyles.stroke = stroke;
@@ -4468,7 +4594,9 @@
4468
4594
  if (typeof background.element === "string") {
4469
4595
  if (typeof document !== "undefined") {
4470
4596
  const node = document.querySelector(background.element);
4471
- if (node instanceof HTMLCanvasElement || node instanceof HTMLVideoElement || node instanceof HTMLImageElement) {
4597
+ if ((typeof HTMLCanvasElement !== "undefined" && node instanceof HTMLCanvasElement) ||
4598
+ (typeof HTMLVideoElement !== "undefined" && node instanceof HTMLVideoElement) ||
4599
+ (typeof HTMLImageElement !== "undefined" && node instanceof HTMLImageElement)) {
4472
4600
  this.#backgroundElement = node;
4473
4601
  }
4474
4602
  else if (node) {
@@ -4479,10 +4607,10 @@
4479
4607
  }
4480
4608
  }
4481
4609
  }
4482
- else if (background.element instanceof HTMLCanvasElement ||
4483
- background.element instanceof OffscreenCanvas ||
4484
- background.element instanceof HTMLVideoElement ||
4485
- background.element instanceof HTMLImageElement) {
4610
+ else if ((typeof HTMLCanvasElement !== "undefined" && background.element instanceof HTMLCanvasElement) ||
4611
+ (typeof OffscreenCanvas !== "undefined" && background.element instanceof OffscreenCanvas) ||
4612
+ (typeof HTMLVideoElement !== "undefined" && background.element instanceof HTMLVideoElement) ||
4613
+ (typeof HTMLImageElement !== "undefined" && background.element instanceof HTMLImageElement)) {
4486
4614
  this.#backgroundElement = background.element;
4487
4615
  }
4488
4616
  }
@@ -4550,6 +4678,7 @@
4550
4678
  zoom = defaultZoom;
4551
4679
  #container;
4552
4680
  #generated;
4681
+ #hdrMediaListeners;
4553
4682
  #mutationObserver;
4554
4683
  #originalStyle;
4555
4684
  #pluginManager;
@@ -4614,7 +4743,6 @@
4614
4743
  });
4615
4744
  this.resize();
4616
4745
  this.#initStyle();
4617
- this.initBackground();
4618
4746
  this.#safeMutationObserver(obs => {
4619
4747
  const element = this.domElement;
4620
4748
  if (!element || !(element instanceof Node)) {
@@ -4624,6 +4752,8 @@
4624
4752
  });
4625
4753
  this.initPlugins();
4626
4754
  this.#initContext();
4755
+ this.initBackground();
4756
+ this.#initHdrListeners();
4627
4757
  this.render.init();
4628
4758
  }
4629
4759
  initBackground() {
@@ -4633,7 +4763,8 @@
4633
4763
  }
4634
4764
  const elementStyle = element.style, color = rangeColorToRgb(this.#pluginManager, background.color);
4635
4765
  if (color) {
4636
- elementStyle.backgroundColor = getStyleFromRgb(color, container.actualOptions.hdr, background.opacity);
4766
+ const hdrOptions = container.actualOptions.hdr;
4767
+ elementStyle.backgroundColor = getStyleFromRgb(color, container.hdr, background.opacity, hdrOptions.peakNits, hdrOptions.mode);
4637
4768
  }
4638
4769
  else {
4639
4770
  elementStyle.backgroundColor = "";
@@ -4730,6 +4861,7 @@
4730
4861
  obs.disconnect();
4731
4862
  });
4732
4863
  this.#mutationObserver = undefined;
4864
+ this.#removeHdrListeners();
4733
4865
  this.render.stop();
4734
4866
  }
4735
4867
  async windowResize() {
@@ -4749,9 +4881,16 @@
4749
4881
  }
4750
4882
  }
4751
4883
  #initContext() {
4752
- const container = this.#container, canSupportHdr = container.actualOptions.hdr &&
4884
+ const container = this.#container, canSupportHdr = container.actualOptions.hdr.enable &&
4753
4885
  safeMatchMedia("(color-gamut: p3)")?.matches &&
4754
4886
  safeMatchMedia("(dynamic-range: high)")?.matches;
4887
+ container.hdr = canSupportHdr ?? false;
4888
+ container.hdrMode = container.actualOptions.hdr.mode;
4889
+ container.peakNits = container.actualOptions.hdr.peakNits;
4890
+ const renderCanvas = this.renderCanvas;
4891
+ if (!renderCanvas) {
4892
+ return;
4893
+ }
4755
4894
  this.render.setContextSettings({
4756
4895
  alpha: true,
4757
4896
  desynchronized: true,
@@ -4760,11 +4899,47 @@
4760
4899
  ? { colorSpace: "display-p3", colorType: "float16" }
4761
4900
  : { colorSpace: "srgb" }),
4762
4901
  });
4763
- const renderCanvas = this.renderCanvas;
4764
- if (!renderCanvas) {
4765
- return;
4902
+ let context;
4903
+ try {
4904
+ context = renderCanvas.getContext("2d", this.render.settings);
4905
+ }
4906
+ catch {
4907
+ context = null;
4908
+ }
4909
+ if (canSupportHdr && !context) {
4910
+ container.hdr = false;
4911
+ const sdrSettings = {
4912
+ alpha: true,
4913
+ desynchronized: true,
4914
+ willReadFrequently: false,
4915
+ colorSpace: "srgb",
4916
+ };
4917
+ this.render.setContextSettings(sdrSettings);
4918
+ try {
4919
+ context = renderCanvas.getContext("2d", sdrSettings);
4920
+ }
4921
+ catch {
4922
+ context = null;
4923
+ }
4924
+ }
4925
+ this.render.setContext(context);
4926
+ }
4927
+ #initHdrListeners() {
4928
+ this.#removeHdrListeners();
4929
+ const p3Query = safeMatchMedia("(color-gamut: p3)"), hdrQuery = safeMatchMedia("(dynamic-range: high)"), handleChange = () => {
4930
+ this.#recreateRenderCanvas();
4931
+ this.#initContext();
4932
+ this.initBackground();
4933
+ }, listeners = [];
4934
+ if (p3Query) {
4935
+ p3Query.addEventListener("change", handleChange);
4936
+ listeners.push({ handler: handleChange, mql: p3Query });
4766
4937
  }
4767
- this.render.setContext(renderCanvas.getContext("2d", this.render.settings));
4938
+ if (hdrQuery) {
4939
+ hdrQuery.addEventListener("change", handleChange);
4940
+ listeners.push({ handler: handleChange, mql: hdrQuery });
4941
+ }
4942
+ this.#hdrMediaListeners = listeners;
4768
4943
  }
4769
4944
  #initStyle() {
4770
4945
  const element = this.domElement, options = this.#container.actualOptions;
@@ -4788,6 +4963,25 @@
4788
4963
  element.style.setProperty(key, value, "important");
4789
4964
  }
4790
4965
  }
4966
+ #recreateRenderCanvas() {
4967
+ const renderCanvas = this.renderCanvas;
4968
+ if (!renderCanvas) {
4969
+ return;
4970
+ }
4971
+ if (this.domElement) {
4972
+ return;
4973
+ }
4974
+ this.renderCanvas = new OffscreenCanvas(renderCanvas.width, renderCanvas.height);
4975
+ }
4976
+ #removeHdrListeners() {
4977
+ if (!this.#hdrMediaListeners) {
4978
+ return;
4979
+ }
4980
+ for (const { handler, mql } of this.#hdrMediaListeners) {
4981
+ mql.removeEventListener("change", handler);
4982
+ }
4983
+ this.#hdrMediaListeners = undefined;
4984
+ }
4791
4985
  #repairStyle() {
4792
4986
  const element = this.domElement;
4793
4987
  if (!element) {
@@ -5172,9 +5366,9 @@
5172
5366
  }
5173
5367
  getOpacity() {
5174
5368
  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;
5175
- this.#cachedOpacityData.fillOpacity = opacity * fillOpacity * zOpacityFactor;
5369
+ this.#cachedOpacityData.fillOpacity = fillOpacity;
5176
5370
  this.#cachedOpacityData.opacity = opacity * zOpacityFactor;
5177
- this.#cachedOpacityData.strokeOpacity = opacity * strokeOpacity * zOpacityFactor;
5371
+ this.#cachedOpacityData.strokeOpacity = strokeOpacity;
5178
5372
  return this.#cachedOpacityData;
5179
5373
  }
5180
5374
  getPosition() {
@@ -6029,6 +6223,7 @@
6029
6223
  effectDrawers;
6030
6224
  fpsLimit;
6031
6225
  hdr;
6226
+ hdrMode;
6032
6227
  id;
6033
6228
  pageHidden;
6034
6229
  particleCreatedPlugins;
@@ -6036,6 +6231,7 @@
6036
6231
  particlePositionPlugins;
6037
6232
  particleUpdaters;
6038
6233
  particles;
6234
+ peakNits;
6039
6235
  plugins;
6040
6236
  retina;
6041
6237
  shapeDrawers;
@@ -6066,6 +6262,8 @@
6066
6262
  this.id = Symbol(id);
6067
6263
  this.fpsLimit = 120;
6068
6264
  this.hdr = false;
6265
+ this.hdrMode = exports.HdrMode.standard;
6266
+ this.peakNits = 400;
6069
6267
  this.#smooth = false;
6070
6268
  this.#delay = 0;
6071
6269
  this.#duration = 0;
@@ -6205,8 +6403,9 @@
6205
6403
  this.updateActualOptions();
6206
6404
  this.canvas.initBackground();
6207
6405
  this.canvas.resize();
6208
- const { delay, duration, fpsLimit, hdr, smooth, zLayers } = this.actualOptions;
6209
- this.hdr = hdr;
6406
+ const { delay, duration, fpsLimit, smooth, zLayers } = this.actualOptions, hdrOptions = this.actualOptions.hdr;
6407
+ this.hdrMode = hdrOptions.mode;
6408
+ this.peakNits = hdrOptions.peakNits;
6210
6409
  this.zLayers = zLayers;
6211
6410
  this.#duration = getRangeValue(duration) * millisecondsToSeconds;
6212
6411
  this.#delay = getRangeValue(delay) * millisecondsToSeconds;
@@ -7393,10 +7592,10 @@
7393
7592
  }
7394
7593
  }
7395
7594
  #getCachedStyle(rgb) {
7396
- const key = `${rgb.r},${rgb.g},${rgb.b}`;
7595
+ const key = `${rgb.r},${rgb.g},${rgb.b}-${this.#container.hdr}-${this.#container.peakNits}-${this.#container.hdrMode}`;
7397
7596
  let style = this.#colorCache.get(key);
7398
7597
  if (!style) {
7399
- style = getStyleFromRgb(rgb, this.#container.hdr);
7598
+ style = getStyleFromRgb(rgb, this.#container.hdr, undefined, this.#container.peakNits, this.#container.hdrMode);
7400
7599
  this.#colorCache.set(key, style);
7401
7600
  }
7402
7601
  return style;
@@ -7423,6 +7622,7 @@
7423
7622
  exports.ColorAnimation = ColorAnimation;
7424
7623
  exports.Fill = Fill;
7425
7624
  exports.FullScreen = FullScreen;
7625
+ exports.HDROptions = HDROptions;
7426
7626
  exports.HslAnimation = HslAnimation;
7427
7627
  exports.Move = Move;
7428
7628
  exports.MoveAngle = MoveAngle;