@tsparticles/preset-links 4.3.1 → 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
- /* Preset v4.3.1 */
2
+ /* Preset 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) :
@@ -295,6 +295,9 @@
295
295
  })(PixelMode || (PixelMode = {}));
296
296
 
297
297
  const minRadius = 0;
298
+ function isForbiddenKey(key) {
299
+ return key === "__proto__" || key === "constructor" || key === "prototype";
300
+ }
298
301
  function hasMatchMedia() {
299
302
  return typeof matchMedia !== "undefined";
300
303
  }
@@ -370,7 +373,7 @@
370
373
  if (!hasNested) {
371
374
  const sourceDict = source, destDict = destination;
372
375
  for (const key of sourceKeys) {
373
- if (key === "__proto__" || key === "constructor" || key === "prototype") {
376
+ if (isForbiddenKey(key)) {
374
377
  continue;
375
378
  }
376
379
  const v = sourceDict[key];
@@ -381,7 +384,7 @@
381
384
  continue;
382
385
  }
383
386
  for (const key of sourceKeys) {
384
- if (key === "__proto__" || key === "constructor" || key === "prototype") {
387
+ if (isForbiddenKey(key)) {
385
388
  continue;
386
389
  }
387
390
  const sourceDict = source, destDict = destination, value = sourceDict[key];
@@ -797,7 +800,7 @@
797
800
  return this.#domArray;
798
801
  }
799
802
  get version() {
800
- return "4.3.1";
803
+ return "4.4.0";
801
804
  }
802
805
  addEventListener(type, listener) {
803
806
  this.#eventDispatcher.addEventListener(type, listener);
@@ -878,6 +881,10 @@
878
881
  }
879
882
 
880
883
  function initEngine() {
884
+ const existing = globalThis.tsParticles;
885
+ if (existing?.pluginManager) {
886
+ return existing;
887
+ }
881
888
  return new Engine();
882
889
  }
883
890
 
@@ -975,6 +982,15 @@
975
982
  AnimationMode["random"] = "random";
976
983
  })(AnimationMode || (AnimationMode = {}));
977
984
 
985
+ var HdrMode;
986
+ (function (HdrMode) {
987
+ HdrMode["standard"] = "standard";
988
+ HdrMode["natural"] = "natural";
989
+ HdrMode["vivid"] = "vivid";
990
+ HdrMode["cinematic"] = "cinematic";
991
+ HdrMode["dynamic"] = "dynamic";
992
+ })(HdrMode || (HdrMode = {}));
993
+
978
994
  var LimitMode;
979
995
  (function (LimitMode) {
980
996
  LimitMode["delete"] = "delete";
@@ -1230,6 +1246,29 @@
1230
1246
  }
1231
1247
  }
1232
1248
 
1249
+ const defaultPeakNits = 400, minPeakNits = 0, toStringValue = (value) => String(value);
1250
+ class HDROptions extends OptionLoader {
1251
+ enable = true;
1252
+ mode = HdrMode.standard;
1253
+ peakNits = defaultPeakNits;
1254
+ doLoad(data) {
1255
+ if (data.enable !== undefined && !isBoolean(data.enable)) {
1256
+ throw new Error(`Invalid HDR "enable" value: expected a boolean, got "${String(data.enable)}"`);
1257
+ }
1258
+ if (data.mode !== undefined &&
1259
+ (typeof data.mode !== "string" || !Object.values(HdrMode).includes(data.mode))) {
1260
+ throw new Error(`Invalid HDR "mode" value: expected one of ${Object.values(HdrMode).join(", ")}, got "${toStringValue(data.mode)}"`);
1261
+ }
1262
+ if (data.peakNits !== undefined &&
1263
+ (!isNumber(data.peakNits) || !Number.isFinite(data.peakNits) || data.peakNits <= minPeakNits)) {
1264
+ throw new Error(`Invalid HDR "peakNits" value: expected a positive number, got "${String(data.peakNits)}"`);
1265
+ }
1266
+ loadProperty(this, "enable", data.enable);
1267
+ loadProperty(this, "mode", data.mode);
1268
+ loadProperty(this, "peakNits", data.peakNits);
1269
+ }
1270
+ }
1271
+
1233
1272
  class ResizeEvent extends OptionLoader {
1234
1273
  delay = 0.5;
1235
1274
  enable = true;
@@ -1673,7 +1712,7 @@
1673
1712
  duration = 0;
1674
1713
  fpsLimit = 120;
1675
1714
  fullScreen;
1676
- hdr = true;
1715
+ hdr;
1677
1716
  key;
1678
1717
  name;
1679
1718
  palette;
@@ -1693,6 +1732,7 @@
1693
1732
  this.#container = container;
1694
1733
  this.background = new Background();
1695
1734
  this.fullScreen = new FullScreen();
1735
+ this.hdr = new HDROptions();
1696
1736
  this.particles = loadParticlesOptions(this.#pluginManager, this.#container);
1697
1737
  this.resize = new ResizeEvent();
1698
1738
  }
@@ -1715,7 +1755,15 @@
1715
1755
  loadProperty(this, "detectRetina", data.detectRetina);
1716
1756
  loadRangeProperty(this, "duration", data.duration);
1717
1757
  loadProperty(this, "fpsLimit", data.fpsLimit);
1718
- loadProperty(this, "hdr", data.hdr);
1758
+ const hdrData = data.hdr;
1759
+ if (isBoolean(hdrData)) {
1760
+ this.hdr.enable = hdrData;
1761
+ this.hdr.mode = HdrMode.standard;
1762
+ this.hdr.peakNits = 400;
1763
+ }
1764
+ else {
1765
+ this.hdr.load(hdrData);
1766
+ }
1719
1767
  loadProperty(this, "pauseOnBlur", data.pauseOnBlur);
1720
1768
  loadProperty(this, "pauseOnOutsideViewport", data.pauseOnOutsideViewport);
1721
1769
  loadProperty(this, "zLayers", data.zLayers);
@@ -1758,7 +1806,7 @@
1758
1806
  }
1759
1807
  }
1760
1808
 
1761
- const styleCache = new Map(), maxStyleCacheSize = 2000, rgbFixedPrecision = 2, hslFixedPrecision = 2, hdrRgbFixedPrecision = 4, hdrHslFixedPrecision = 4, sdrReferenceWhiteNits = 203, hdrAnimationScale = sdrReferenceWhiteNits / maxNits;
1809
+ 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;
1762
1810
  function getCachedStyle(key, generator) {
1763
1811
  let cached = styleCache.get(key);
1764
1812
  if (!cached) {
@@ -1770,6 +1818,48 @@
1770
1818
  }
1771
1819
  return cached;
1772
1820
  }
1821
+ function acesFilmic(x) {
1822
+ return clamp((x * (acesA * x + acesB)) / (x * (acesC * x + acesD) + acesE), none, one);
1823
+ }
1824
+ function srgbToLinear(c) {
1825
+ return c <= srgbThreshold ? c / srgbDivisor : Math.pow((c + srgbOffset) / srgbScale, srgbExponent);
1826
+ }
1827
+ function linearToSrgb(c) {
1828
+ return c <= linearThreshold ? c * linearScale : srgbScale * Math.pow(c, one / srgbExponent) - srgbOffset;
1829
+ }
1830
+ function applyHdrModeAdjustments(r, g, b, mode, maxChannel) {
1831
+ switch (mode) {
1832
+ case HdrMode.vivid: {
1833
+ const avg = (r + g + b) / channelCount;
1834
+ return {
1835
+ b: clamp(clamp(avg + (b - avg) * saturationBoost, none, maxChannel) * lightnessBoost, none, maxChannel),
1836
+ g: clamp(clamp(avg + (g - avg) * saturationBoost, none, maxChannel) * lightnessBoost, none, maxChannel),
1837
+ r: clamp(clamp(avg + (r - avg) * saturationBoost, none, maxChannel) * lightnessBoost, none, maxChannel),
1838
+ };
1839
+ }
1840
+ case HdrMode.cinematic: {
1841
+ const tempR = r * temperatureR, tempB = b * temperatureB, avg = (tempR + g + tempB) / channelCount;
1842
+ return {
1843
+ b: clamp(avg + (tempB - avg) * contrastFactor, none, maxChannel),
1844
+ g: clamp(avg + (g - avg) * contrastFactor, none, maxChannel),
1845
+ r: clamp(avg + (tempR - avg) * contrastFactor, none, maxChannel),
1846
+ };
1847
+ }
1848
+ case HdrMode.dynamic: {
1849
+ 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;
1850
+ return {
1851
+ b: clamp(b * naturalWeight + vividB * vividWeight, none, maxChannel),
1852
+ g: clamp(g * naturalWeight + vividG * vividWeight, none, maxChannel),
1853
+ r: clamp(r * naturalWeight + vividR * vividWeight, none, maxChannel),
1854
+ };
1855
+ }
1856
+ case HdrMode.standard:
1857
+ return { b, g, r };
1858
+ case HdrMode.natural:
1859
+ default:
1860
+ return { b, g, r };
1861
+ }
1862
+ }
1773
1863
  function stringToRgba(pluginManager, input) {
1774
1864
  if (!input) {
1775
1865
  return;
@@ -1927,30 +2017,65 @@
1927
2017
  r: getRgbInRangeValue(),
1928
2018
  };
1929
2019
  }
1930
- function getStyleFromRgb(color, hdr, opacity) {
1931
- const rgbPrecision = hdr ? hdrRgbFixedPrecision : rgbFixedPrecision, op = opacity ?? defaultOpacity$1, key = `rgb-${color.r.toFixed(rgbPrecision)}-${color.g.toFixed(rgbPrecision)}-${color.b.toFixed(rgbPrecision)}-${hdr ? "hdr" : "sdr"}-${op.toString()}`;
1932
- return getCachedStyle(key, () => (hdr ? getHdrStyleFromRgb(color, opacity) : getSdrStyleFromRgb(color, opacity)));
2020
+ function getStyleFromRgb(color, hdr, opacity, peakNits, mode) {
2021
+ const rgbPrecision = hdr ? hdrRgbFixedPrecision : rgbFixedPrecision, op = opacity ?? defaultOpacity$1, key = hdr
2022
+ ? `rgb-${color.r.toFixed(rgbPrecision)}-${color.g.toFixed(rgbPrecision)}-${color.b.toFixed(rgbPrecision)}-hdr-${op.toString()}-${(peakNits ?? maxNits).toString()}-${mode ?? HdrMode.standard}`
2023
+ : `rgb-${color.r.toFixed(rgbPrecision)}-${color.g.toFixed(rgbPrecision)}-${color.b.toFixed(rgbPrecision)}-sdr-${op.toString()}`;
2024
+ return getCachedStyle(key, () => hdr ? getHdrStyleFromRgb(color, opacity, peakNits, mode) : getSdrStyleFromRgb(color, opacity));
1933
2025
  }
1934
- function getHdrStyleFromRgb(color, opacity, peakNits = maxNits) {
1935
- const headroom = peakNits / sdrReferenceWhiteNits;
1936
- return `color(display-p3 ${((color.r / rgbMax) * headroom).toString()} ${((color.g / rgbMax) * headroom).toString()} ${((color.b / rgbMax) * headroom).toString()} / ${(opacity ?? defaultOpacity$1).toString()})`;
2026
+ function getHdrStyleFromRgb(color, opacity, peakNits = maxNits, mode = HdrMode.standard) {
2027
+ const headroom = peakNits / sdrReferenceWhiteNits, middleGray = 0.18, mapped = hdrToneMapColor(color, headroom, middleGray, mode);
2028
+ return `color(display-p3 ${mapped.r.toString()} ${mapped.g.toString()} ${mapped.b.toString()} / ${(opacity ?? defaultOpacity$1).toString()})`;
2029
+ }
2030
+ function hdrToneMapColor(color, headroom, middleGray, mode) {
2031
+ const rNorm = color.r / rgbMax, gNorm = color.g / rgbMax, bNorm = color.b / rgbMax;
2032
+ if (mode !== HdrMode.natural && mode !== HdrMode.vivid && mode !== HdrMode.cinematic && mode !== HdrMode.dynamic) {
2033
+ return { b: bNorm, g: gNorm, r: rNorm };
2034
+ }
2035
+ const maxChannel = Math.max(one, headroom), luminance = luminanceR * rNorm + luminanceG * gNorm + luminanceB * bNorm, mappedLuminance = hdrToneMap(luminance, headroom, middleGray), scale = luminance > none ? mappedLuminance / luminance : one;
2036
+ return applyHdrModeAdjustments(clamp(rNorm * scale, none, maxChannel), clamp(gNorm * scale, none, maxChannel), clamp(bNorm * scale, none, maxChannel), mode, maxChannel);
2037
+ }
2038
+ function hdrToneMap(normalized, headroom, middleGray) {
2039
+ if (normalized <= middleGray) {
2040
+ return acesFilmic(normalized);
2041
+ }
2042
+ const expanded = normalized + (normalized - middleGray) * (headroom - one);
2043
+ return acesFilmic(expanded);
1937
2044
  }
1938
2045
  function getSdrStyleFromRgb(color, opacity) {
1939
2046
  return `rgba(${color.r.toString()}, ${color.g.toString()}, ${color.b.toString()}, ${(opacity ?? defaultOpacity$1).toString()})`;
1940
2047
  }
1941
- function getStyleFromHsl(color, hdr, opacity) {
1942
- const hslPrecision = hdr ? hdrHslFixedPrecision : hslFixedPrecision, op = opacity ?? defaultOpacity$1, key = `hsl-${color.h.toFixed(hslPrecision)}-${color.s.toFixed(hslPrecision)}-${color.l.toFixed(hslPrecision)}-${hdr ? "hdr" : "sdr"}-${op.toString()}`;
2048
+ function getStyleFromHsl(color, hdr, opacity, peakNits, mode) {
2049
+ const hslPrecision = hdr ? hdrHslFixedPrecision : hslFixedPrecision, op = opacity ?? defaultOpacity$1, key = hdr
2050
+ ? `hsl-${color.h.toFixed(hslPrecision)}-${color.s.toFixed(hslPrecision)}-${color.l.toFixed(hslPrecision)}-hdr-${op.toString()}-${(peakNits ?? maxNits).toString()}-${mode ?? HdrMode.standard}`
2051
+ : `hsl-${color.h.toFixed(hslPrecision)}-${color.s.toFixed(hslPrecision)}-${color.l.toFixed(hslPrecision)}-sdr-${op.toString()}`;
1943
2052
  return getCachedStyle(key, () => hdr
1944
- ? getStyleFromRgb(hslToRgbFloat(color), true, opacity)
2053
+ ? getStyleFromRgb(hslToRgbFloat(color), true, opacity, peakNits, mode)
1945
2054
  : `hsla(${color.h.toString()}, ${color.s.toString()}%, ${color.l.toString()}%, ${op.toString()})`);
1946
2055
  }
1947
- function colorMix(color1, color2, size1, size2) {
2056
+ function colorMix(color1, color2, size1, size2, hdr) {
1948
2057
  let rgb1 = color1, rgb2 = color2;
1949
2058
  if (!("r" in rgb1)) {
1950
- rgb1 = hslToRgb(color1);
2059
+ rgb1 = hdr ? hslToRgbFloat(color1) : hslToRgb(color1);
1951
2060
  }
1952
2061
  if (!("r" in rgb2)) {
1953
- rgb2 = hslToRgb(color2);
2062
+ rgb2 = hdr ? hslToRgbFloat(color2) : hslToRgb(color2);
2063
+ }
2064
+ if (hdr) {
2065
+ const lin1 = {
2066
+ b: srgbToLinear(rgb1.b / rgbMax),
2067
+ g: srgbToLinear(rgb1.g / rgbMax),
2068
+ r: srgbToLinear(rgb1.r / rgbMax),
2069
+ }, lin2 = {
2070
+ b: srgbToLinear(rgb2.b / rgbMax),
2071
+ g: srgbToLinear(rgb2.g / rgbMax),
2072
+ r: srgbToLinear(rgb2.r / rgbMax),
2073
+ }, totalWeight = size1 + size2;
2074
+ return {
2075
+ b: linearToSrgb((lin1.b * size1 + lin2.b * size2) / totalWeight) * rgbMax,
2076
+ g: linearToSrgb((lin1.g * size1 + lin2.g * size2) / totalWeight) * rgbMax,
2077
+ r: linearToSrgb((lin1.r * size1 + lin2.r * size2) / totalWeight) * rgbMax,
2078
+ };
1954
2079
  }
1955
2080
  return {
1956
2081
  b: mix(rgb1.b, rgb2.b, size1, size2),
@@ -1958,14 +2083,14 @@
1958
2083
  r: mix(rgb1.r, rgb2.r, size1, size2),
1959
2084
  };
1960
2085
  }
1961
- function getLinkColor(p1, p2, linkColor) {
2086
+ function getLinkColor(p1, p2, linkColor, hdr) {
1962
2087
  if (linkColor === randomColorValue) {
1963
2088
  return getRandomRgbColor();
1964
2089
  }
1965
2090
  else if (linkColor === midColorValue) {
1966
2091
  const sourceColor = p1.getFillColor() ?? p1.getStrokeColor(), destColor = p2?.getFillColor() ?? p2?.getStrokeColor();
1967
2092
  if (sourceColor && destColor && p2) {
1968
- return colorMix(sourceColor, destColor, p1.getRadius(), p2.getRadius());
2093
+ return colorMix(sourceColor, destColor, p1.getRadius(), p2.getRadius(), hdr);
1969
2094
  }
1970
2095
  else {
1971
2096
  const hslColor = sourceColor ?? destColor;
@@ -2061,7 +2186,7 @@
2061
2186
  colorValue.velocity = defaultVelocity;
2062
2187
  }
2063
2188
  }
2064
- function updateColorValue(data, decrease, delta, hdr) {
2189
+ function updateColorValue(data, decrease, delta, _hdr) {
2065
2190
  const minLoops = 0, minDelay = 0, identity = 1, minVelocity = 0, minOffset = 0, velocityFactor = 3.6;
2066
2191
  if (!data.enable ||
2067
2192
  ((data.maxLoops ?? minLoops) > minLoops && (data.loops ?? minLoops) > (data.maxLoops ?? minLoops))) {
@@ -2074,7 +2199,7 @@
2074
2199
  if ((data.delayTime ?? minDelay) > minDelay && data.time < (data.delayTime ?? minDelay)) {
2075
2200
  return;
2076
2201
  }
2077
- 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;
2202
+ 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;
2078
2203
  if (!decrease || data.status === AnimationStatus.increasing) {
2079
2204
  data.value += velocity;
2080
2205
  if (data.value > max) {
@@ -2106,9 +2231,9 @@
2106
2231
  return;
2107
2232
  }
2108
2233
  const { h, s, l } = color;
2109
- updateColorValue(h, false, delta, hdr);
2110
- updateColorValue(s, true, delta, hdr);
2111
- updateColorValue(l, true, delta, hdr);
2234
+ updateColorValue(h, false, delta);
2235
+ updateColorValue(s, true, delta);
2236
+ updateColorValue(l, true, delta);
2112
2237
  }
2113
2238
  function alterHsl(color, type, value) {
2114
2239
  return {
@@ -2158,7 +2283,7 @@
2158
2283
  }
2159
2284
 
2160
2285
  async function loadBlendPlugin(engine) {
2161
- engine.checkVersion("4.3.1");
2286
+ engine.checkVersion("4.4.0");
2162
2287
  await engine.pluginManager.register(e => {
2163
2288
  e.pluginManager.addPlugin(new BlendPlugin());
2164
2289
  });
@@ -2195,7 +2320,7 @@
2195
2320
  }
2196
2321
 
2197
2322
  async function loadCircleShape(engine) {
2198
- engine.checkVersion("4.3.1");
2323
+ engine.checkVersion("4.4.0");
2199
2324
  await engine.pluginManager.register(e => {
2200
2325
  e.pluginManager.addShape(["circle"], () => {
2201
2326
  return Promise.resolve(new CircleDrawer());
@@ -2243,7 +2368,7 @@
2243
2368
  }
2244
2369
 
2245
2370
  async function loadHexColorPlugin(engine) {
2246
- engine.checkVersion("4.3.1");
2371
+ engine.checkVersion("4.4.0");
2247
2372
  await engine.pluginManager.register(e => {
2248
2373
  e.pluginManager.addColorManager("hex", new HexColorManager());
2249
2374
  });
@@ -2296,7 +2421,7 @@
2296
2421
  }
2297
2422
 
2298
2423
  async function loadHslColorPlugin(engine) {
2299
- engine.checkVersion("4.3.1");
2424
+ engine.checkVersion("4.4.0");
2300
2425
  await engine.pluginManager.register(e => {
2301
2426
  e.pluginManager.addColorManager("hsl", new HslColorManager());
2302
2427
  });
@@ -2320,7 +2445,7 @@
2320
2445
  }
2321
2446
 
2322
2447
  async function loadMovePlugin(engine) {
2323
- engine.checkVersion("4.3.1");
2448
+ engine.checkVersion("4.4.0");
2324
2449
  await engine.pluginManager.register(e => {
2325
2450
  const moveEngine = e, movePluginManager = moveEngine.pluginManager;
2326
2451
  movePluginManager.initializers.pathGenerators ??= new Map();
@@ -2530,7 +2655,7 @@
2530
2655
  }
2531
2656
 
2532
2657
  async function loadOpacityUpdater(engine) {
2533
- engine.checkVersion("4.3.1");
2658
+ engine.checkVersion("4.4.0");
2534
2659
  await engine.pluginManager.register(e => {
2535
2660
  e.pluginManager.addParticleUpdater("opacity", container => {
2536
2661
  return Promise.resolve(new OpacityUpdater(container));
@@ -2875,7 +3000,7 @@
2875
3000
  }
2876
3001
 
2877
3002
  async function loadOutModesUpdater(engine) {
2878
- engine.checkVersion("4.3.1");
3003
+ engine.checkVersion("4.4.0");
2879
3004
  await engine.pluginManager.register(e => {
2880
3005
  e.pluginManager.addParticleUpdater("outModes", container => {
2881
3006
  return Promise.resolve(new OutOfCanvasUpdater(container));
@@ -2946,7 +3071,7 @@
2946
3071
  }
2947
3072
 
2948
3073
  async function loadPaintUpdater(engine) {
2949
- engine.checkVersion("4.3.1");
3074
+ engine.checkVersion("4.4.0");
2950
3075
  await engine.pluginManager.register(e => {
2951
3076
  e.pluginManager.addParticleUpdater("paint", container => {
2952
3077
  return Promise.resolve(new PaintUpdater(e.pluginManager, container));
@@ -3001,7 +3126,7 @@
3001
3126
  }
3002
3127
 
3003
3128
  async function loadRgbColorPlugin(engine) {
3004
- engine.checkVersion("4.3.1");
3129
+ engine.checkVersion("4.4.0");
3005
3130
  await engine.pluginManager.register(e => {
3006
3131
  e.pluginManager.addColorManager("rgb", new RgbColorManager());
3007
3132
  });
@@ -3086,7 +3211,7 @@
3086
3211
  }
3087
3212
 
3088
3213
  async function loadSizeUpdater(engine) {
3089
- engine.checkVersion("4.3.1");
3214
+ engine.checkVersion("4.4.0");
3090
3215
  await engine.pluginManager.register(e => {
3091
3216
  e.pluginManager.addParticleUpdater("size", container => {
3092
3217
  return Promise.resolve(new SizeUpdater(container));
@@ -3095,7 +3220,7 @@
3095
3220
  }
3096
3221
 
3097
3222
  async function loadBasic(engine) {
3098
- engine.checkVersion("4.3.1");
3223
+ engine.checkVersion("4.4.0");
3099
3224
  await engine.pluginManager.register(async (e) => {
3100
3225
  await Promise.all([
3101
3226
  loadBlendPlugin(e),
@@ -3296,7 +3421,7 @@
3296
3421
  const clickEvent = "click", mouseDownEvent = "pointerdown", mouseUpEvent = "pointerup", mouseLeaveEvent = "pointerleave", mouseMoveEvent = "pointermove", touchStartEvent = "touchstart", touchEndEvent = "touchend", touchMoveEvent = "touchmove", touchCancelEvent = "touchcancel";
3297
3422
 
3298
3423
  async function loadInteractivityPlugin(engine) {
3299
- engine.checkVersion("4.3.1");
3424
+ engine.checkVersion("4.4.0");
3300
3425
  await engine.pluginManager.register(e => {
3301
3426
  const interactivityEngine = e, interactivityPluginManager = interactivityEngine.pluginManager;
3302
3427
  interactivityPluginManager.addPlugin(new InteractivityPlugin(interactivityPluginManager));
@@ -3532,7 +3657,7 @@
3532
3657
  const linkColor = linksOptions.id !== undefined
3533
3658
  ? container.particles.linksColors.get(linksOptions.id)
3534
3659
  : container.particles.linksColor;
3535
- return getLinkColor(p1, p2, linkColor);
3660
+ return getLinkColor(p1, p2, linkColor, container.hdr);
3536
3661
  }
3537
3662
  #setColor(p1) {
3538
3663
  if (!p1.options.links) {
@@ -3573,7 +3698,7 @@
3573
3698
  }
3574
3699
 
3575
3700
  async function loadParticlesLinksInteraction(engine) {
3576
- engine.checkVersion("4.3.1");
3701
+ engine.checkVersion("4.4.0");
3577
3702
  await engine.pluginManager.register((e) => {
3578
3703
  const pluginManager = e.pluginManager;
3579
3704
  ensureInteractivityPluginLoaded(e);
@@ -3751,7 +3876,11 @@
3751
3876
  if (!fColor && !sColor) {
3752
3877
  return;
3753
3878
  }
3754
- 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;
3879
+ 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
3880
+ ? getStyleFromHsl(fColor, container.hdr, fillOpacity * opacity, container.peakNits, container.hdrMode)
3881
+ : undefined, stroke = sColor
3882
+ ? getStyleFromHsl(sColor, container.hdr, strokeOpacity * opacity, container.peakNits, container.hdrMode)
3883
+ : fill;
3755
3884
  transform.a = transform.b = transform.c = transform.d = undefined;
3756
3885
  colorStyles.fill = fill;
3757
3886
  colorStyles.stroke = stroke;
@@ -4085,7 +4214,9 @@
4085
4214
  if (typeof background.element === "string") {
4086
4215
  if (typeof document !== "undefined") {
4087
4216
  const node = document.querySelector(background.element);
4088
- if (node instanceof HTMLCanvasElement || node instanceof HTMLVideoElement || node instanceof HTMLImageElement) {
4217
+ if ((typeof HTMLCanvasElement !== "undefined" && node instanceof HTMLCanvasElement) ||
4218
+ (typeof HTMLVideoElement !== "undefined" && node instanceof HTMLVideoElement) ||
4219
+ (typeof HTMLImageElement !== "undefined" && node instanceof HTMLImageElement)) {
4089
4220
  this.#backgroundElement = node;
4090
4221
  }
4091
4222
  else if (node) {
@@ -4096,10 +4227,10 @@
4096
4227
  }
4097
4228
  }
4098
4229
  }
4099
- else if (background.element instanceof HTMLCanvasElement ||
4100
- background.element instanceof OffscreenCanvas ||
4101
- background.element instanceof HTMLVideoElement ||
4102
- background.element instanceof HTMLImageElement) {
4230
+ else if ((typeof HTMLCanvasElement !== "undefined" && background.element instanceof HTMLCanvasElement) ||
4231
+ (typeof OffscreenCanvas !== "undefined" && background.element instanceof OffscreenCanvas) ||
4232
+ (typeof HTMLVideoElement !== "undefined" && background.element instanceof HTMLVideoElement) ||
4233
+ (typeof HTMLImageElement !== "undefined" && background.element instanceof HTMLImageElement)) {
4103
4234
  this.#backgroundElement = background.element;
4104
4235
  }
4105
4236
  }
@@ -4167,6 +4298,7 @@
4167
4298
  zoom = defaultZoom;
4168
4299
  #container;
4169
4300
  #generated;
4301
+ #hdrMediaListeners;
4170
4302
  #mutationObserver;
4171
4303
  #originalStyle;
4172
4304
  #pluginManager;
@@ -4231,7 +4363,6 @@
4231
4363
  });
4232
4364
  this.resize();
4233
4365
  this.#initStyle();
4234
- this.initBackground();
4235
4366
  this.#safeMutationObserver(obs => {
4236
4367
  const element = this.domElement;
4237
4368
  if (!element || !(element instanceof Node)) {
@@ -4241,6 +4372,8 @@
4241
4372
  });
4242
4373
  this.initPlugins();
4243
4374
  this.#initContext();
4375
+ this.initBackground();
4376
+ this.#initHdrListeners();
4244
4377
  this.render.init();
4245
4378
  }
4246
4379
  initBackground() {
@@ -4250,7 +4383,8 @@
4250
4383
  }
4251
4384
  const elementStyle = element.style, color = rangeColorToRgb(this.#pluginManager, background.color);
4252
4385
  if (color) {
4253
- elementStyle.backgroundColor = getStyleFromRgb(color, container.actualOptions.hdr, background.opacity);
4386
+ const hdrOptions = container.actualOptions.hdr;
4387
+ elementStyle.backgroundColor = getStyleFromRgb(color, container.hdr, background.opacity, hdrOptions.peakNits, hdrOptions.mode);
4254
4388
  }
4255
4389
  else {
4256
4390
  elementStyle.backgroundColor = "";
@@ -4347,6 +4481,7 @@
4347
4481
  obs.disconnect();
4348
4482
  });
4349
4483
  this.#mutationObserver = undefined;
4484
+ this.#removeHdrListeners();
4350
4485
  this.render.stop();
4351
4486
  }
4352
4487
  async windowResize() {
@@ -4366,9 +4501,16 @@
4366
4501
  }
4367
4502
  }
4368
4503
  #initContext() {
4369
- const container = this.#container, canSupportHdr = container.actualOptions.hdr &&
4504
+ const container = this.#container, canSupportHdr = container.actualOptions.hdr.enable &&
4370
4505
  safeMatchMedia("(color-gamut: p3)")?.matches &&
4371
4506
  safeMatchMedia("(dynamic-range: high)")?.matches;
4507
+ container.hdr = canSupportHdr ?? false;
4508
+ container.hdrMode = container.actualOptions.hdr.mode;
4509
+ container.peakNits = container.actualOptions.hdr.peakNits;
4510
+ const renderCanvas = this.renderCanvas;
4511
+ if (!renderCanvas) {
4512
+ return;
4513
+ }
4372
4514
  this.render.setContextSettings({
4373
4515
  alpha: true,
4374
4516
  desynchronized: true,
@@ -4377,11 +4519,47 @@
4377
4519
  ? { colorSpace: "display-p3", colorType: "float16" }
4378
4520
  : { colorSpace: "srgb" }),
4379
4521
  });
4380
- const renderCanvas = this.renderCanvas;
4381
- if (!renderCanvas) {
4382
- return;
4522
+ let context;
4523
+ try {
4524
+ context = renderCanvas.getContext("2d", this.render.settings);
4525
+ }
4526
+ catch {
4527
+ context = null;
4528
+ }
4529
+ if (canSupportHdr && !context) {
4530
+ container.hdr = false;
4531
+ const sdrSettings = {
4532
+ alpha: true,
4533
+ desynchronized: true,
4534
+ willReadFrequently: false,
4535
+ colorSpace: "srgb",
4536
+ };
4537
+ this.render.setContextSettings(sdrSettings);
4538
+ try {
4539
+ context = renderCanvas.getContext("2d", sdrSettings);
4540
+ }
4541
+ catch {
4542
+ context = null;
4543
+ }
4544
+ }
4545
+ this.render.setContext(context);
4546
+ }
4547
+ #initHdrListeners() {
4548
+ this.#removeHdrListeners();
4549
+ const p3Query = safeMatchMedia("(color-gamut: p3)"), hdrQuery = safeMatchMedia("(dynamic-range: high)"), handleChange = () => {
4550
+ this.#recreateRenderCanvas();
4551
+ this.#initContext();
4552
+ this.initBackground();
4553
+ }, listeners = [];
4554
+ if (p3Query) {
4555
+ p3Query.addEventListener("change", handleChange);
4556
+ listeners.push({ handler: handleChange, mql: p3Query });
4383
4557
  }
4384
- this.render.setContext(renderCanvas.getContext("2d", this.render.settings));
4558
+ if (hdrQuery) {
4559
+ hdrQuery.addEventListener("change", handleChange);
4560
+ listeners.push({ handler: handleChange, mql: hdrQuery });
4561
+ }
4562
+ this.#hdrMediaListeners = listeners;
4385
4563
  }
4386
4564
  #initStyle() {
4387
4565
  const element = this.domElement, options = this.#container.actualOptions;
@@ -4405,6 +4583,25 @@
4405
4583
  element.style.setProperty(key, value, "important");
4406
4584
  }
4407
4585
  }
4586
+ #recreateRenderCanvas() {
4587
+ const renderCanvas = this.renderCanvas;
4588
+ if (!renderCanvas) {
4589
+ return;
4590
+ }
4591
+ if (this.domElement) {
4592
+ return;
4593
+ }
4594
+ this.renderCanvas = new OffscreenCanvas(renderCanvas.width, renderCanvas.height);
4595
+ }
4596
+ #removeHdrListeners() {
4597
+ if (!this.#hdrMediaListeners) {
4598
+ return;
4599
+ }
4600
+ for (const { handler, mql } of this.#hdrMediaListeners) {
4601
+ mql.removeEventListener("change", handler);
4602
+ }
4603
+ this.#hdrMediaListeners = undefined;
4604
+ }
4408
4605
  #repairStyle() {
4409
4606
  const element = this.domElement;
4410
4607
  if (!element) {
@@ -4789,9 +4986,9 @@
4789
4986
  }
4790
4987
  getOpacity() {
4791
4988
  const zIndexOptions = this.options.zIndex, zIndexFactor = zIndexFactorOffset - this.zIndexFactor, zOpacityFactor = zIndexFactor ** zIndexOptions.opacityRate, baseOpacity = getRangeValue(this.opacity?.value ?? defaultOpacity$1), modifierOpacity = this.#applyModifiers(undefined, m => m.opacity), opacity = modifierOpacity ?? baseOpacity, fillOpacity = this.fillOpacity ?? defaultOpacity$1, strokeOpacity = this.strokeOpacity ?? defaultOpacity$1;
4792
- this.#cachedOpacityData.fillOpacity = opacity * fillOpacity * zOpacityFactor;
4989
+ this.#cachedOpacityData.fillOpacity = fillOpacity;
4793
4990
  this.#cachedOpacityData.opacity = opacity * zOpacityFactor;
4794
- this.#cachedOpacityData.strokeOpacity = opacity * strokeOpacity * zOpacityFactor;
4991
+ this.#cachedOpacityData.strokeOpacity = strokeOpacity;
4795
4992
  return this.#cachedOpacityData;
4796
4993
  }
4797
4994
  getPosition() {
@@ -5646,6 +5843,7 @@
5646
5843
  effectDrawers;
5647
5844
  fpsLimit;
5648
5845
  hdr;
5846
+ hdrMode;
5649
5847
  id;
5650
5848
  pageHidden;
5651
5849
  particleCreatedPlugins;
@@ -5653,6 +5851,7 @@
5653
5851
  particlePositionPlugins;
5654
5852
  particleUpdaters;
5655
5853
  particles;
5854
+ peakNits;
5656
5855
  plugins;
5657
5856
  retina;
5658
5857
  shapeDrawers;
@@ -5683,6 +5882,8 @@
5683
5882
  this.id = Symbol(id);
5684
5883
  this.fpsLimit = 120;
5685
5884
  this.hdr = false;
5885
+ this.hdrMode = HdrMode.standard;
5886
+ this.peakNits = 400;
5686
5887
  this.#smooth = false;
5687
5888
  this.#delay = 0;
5688
5889
  this.#duration = 0;
@@ -5822,8 +6023,9 @@
5822
6023
  this.updateActualOptions();
5823
6024
  this.canvas.initBackground();
5824
6025
  this.canvas.resize();
5825
- const { delay, duration, fpsLimit, hdr, smooth, zLayers } = this.actualOptions;
5826
- this.hdr = hdr;
6026
+ const { delay, duration, fpsLimit, smooth, zLayers } = this.actualOptions, hdrOptions = this.actualOptions.hdr;
6027
+ this.hdrMode = hdrOptions.mode;
6028
+ this.peakNits = hdrOptions.peakNits;
5827
6029
  this.zLayers = zLayers;
5828
6030
  this.#duration = getRangeValue(duration) * millisecondsToSeconds;
5829
6031
  this.#delay = getRangeValue(delay) * millisecondsToSeconds;
@@ -6949,10 +7151,10 @@
6949
7151
  }
6950
7152
  }
6951
7153
  #getCachedStyle(rgb) {
6952
- const key = `${rgb.r},${rgb.g},${rgb.b}`;
7154
+ const key = `${rgb.r},${rgb.g},${rgb.b}-${this.#container.hdr}-${this.#container.peakNits}-${this.#container.hdrMode}`;
6953
7155
  let style = this.#colorCache.get(key);
6954
7156
  if (!style) {
6955
- style = getStyleFromRgb(rgb, this.#container.hdr);
7157
+ style = getStyleFromRgb(rgb, this.#container.hdr, undefined, this.#container.peakNits, this.#container.hdrMode);
6956
7158
  this.#colorCache.set(key, style);
6957
7159
  }
6958
7160
  return style;