@tsparticles/preset-links 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
- /* Preset v4.3.2 */
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) :
@@ -800,7 +800,7 @@
800
800
  return this.#domArray;
801
801
  }
802
802
  get version() {
803
- return "4.3.2";
803
+ return "4.4.0";
804
804
  }
805
805
  addEventListener(type, listener) {
806
806
  this.#eventDispatcher.addEventListener(type, listener);
@@ -881,6 +881,10 @@
881
881
  }
882
882
 
883
883
  function initEngine() {
884
+ const existing = globalThis.tsParticles;
885
+ if (existing?.pluginManager) {
886
+ return existing;
887
+ }
884
888
  return new Engine();
885
889
  }
886
890
 
@@ -978,6 +982,15 @@
978
982
  AnimationMode["random"] = "random";
979
983
  })(AnimationMode || (AnimationMode = {}));
980
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
+
981
994
  var LimitMode;
982
995
  (function (LimitMode) {
983
996
  LimitMode["delete"] = "delete";
@@ -1233,6 +1246,29 @@
1233
1246
  }
1234
1247
  }
1235
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
+
1236
1272
  class ResizeEvent extends OptionLoader {
1237
1273
  delay = 0.5;
1238
1274
  enable = true;
@@ -1676,7 +1712,7 @@
1676
1712
  duration = 0;
1677
1713
  fpsLimit = 120;
1678
1714
  fullScreen;
1679
- hdr = true;
1715
+ hdr;
1680
1716
  key;
1681
1717
  name;
1682
1718
  palette;
@@ -1696,6 +1732,7 @@
1696
1732
  this.#container = container;
1697
1733
  this.background = new Background();
1698
1734
  this.fullScreen = new FullScreen();
1735
+ this.hdr = new HDROptions();
1699
1736
  this.particles = loadParticlesOptions(this.#pluginManager, this.#container);
1700
1737
  this.resize = new ResizeEvent();
1701
1738
  }
@@ -1718,7 +1755,15 @@
1718
1755
  loadProperty(this, "detectRetina", data.detectRetina);
1719
1756
  loadRangeProperty(this, "duration", data.duration);
1720
1757
  loadProperty(this, "fpsLimit", data.fpsLimit);
1721
- 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
+ }
1722
1767
  loadProperty(this, "pauseOnBlur", data.pauseOnBlur);
1723
1768
  loadProperty(this, "pauseOnOutsideViewport", data.pauseOnOutsideViewport);
1724
1769
  loadProperty(this, "zLayers", data.zLayers);
@@ -1761,7 +1806,7 @@
1761
1806
  }
1762
1807
  }
1763
1808
 
1764
- 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;
1765
1810
  function getCachedStyle(key, generator) {
1766
1811
  let cached = styleCache.get(key);
1767
1812
  if (!cached) {
@@ -1773,6 +1818,48 @@
1773
1818
  }
1774
1819
  return cached;
1775
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
+ }
1776
1863
  function stringToRgba(pluginManager, input) {
1777
1864
  if (!input) {
1778
1865
  return;
@@ -1930,30 +2017,65 @@
1930
2017
  r: getRgbInRangeValue(),
1931
2018
  };
1932
2019
  }
1933
- function getStyleFromRgb(color, hdr, opacity) {
1934
- 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()}`;
1935
- 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));
2025
+ }
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()})`;
1936
2029
  }
1937
- function getHdrStyleFromRgb(color, opacity, peakNits = maxNits) {
1938
- const headroom = peakNits / sdrReferenceWhiteNits;
1939
- return `color(display-p3 ${((color.r / rgbMax) * headroom).toString()} ${((color.g / rgbMax) * headroom).toString()} ${((color.b / rgbMax) * headroom).toString()} / ${(opacity ?? defaultOpacity$1).toString()})`;
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);
1940
2044
  }
1941
2045
  function getSdrStyleFromRgb(color, opacity) {
1942
2046
  return `rgba(${color.r.toString()}, ${color.g.toString()}, ${color.b.toString()}, ${(opacity ?? defaultOpacity$1).toString()})`;
1943
2047
  }
1944
- function getStyleFromHsl(color, hdr, opacity) {
1945
- 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()}`;
1946
2052
  return getCachedStyle(key, () => hdr
1947
- ? getStyleFromRgb(hslToRgbFloat(color), true, opacity)
2053
+ ? getStyleFromRgb(hslToRgbFloat(color), true, opacity, peakNits, mode)
1948
2054
  : `hsla(${color.h.toString()}, ${color.s.toString()}%, ${color.l.toString()}%, ${op.toString()})`);
1949
2055
  }
1950
- function colorMix(color1, color2, size1, size2) {
2056
+ function colorMix(color1, color2, size1, size2, hdr) {
1951
2057
  let rgb1 = color1, rgb2 = color2;
1952
2058
  if (!("r" in rgb1)) {
1953
- rgb1 = hslToRgb(color1);
2059
+ rgb1 = hdr ? hslToRgbFloat(color1) : hslToRgb(color1);
1954
2060
  }
1955
2061
  if (!("r" in rgb2)) {
1956
- 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
+ };
1957
2079
  }
1958
2080
  return {
1959
2081
  b: mix(rgb1.b, rgb2.b, size1, size2),
@@ -1961,14 +2083,14 @@
1961
2083
  r: mix(rgb1.r, rgb2.r, size1, size2),
1962
2084
  };
1963
2085
  }
1964
- function getLinkColor(p1, p2, linkColor) {
2086
+ function getLinkColor(p1, p2, linkColor, hdr) {
1965
2087
  if (linkColor === randomColorValue) {
1966
2088
  return getRandomRgbColor();
1967
2089
  }
1968
2090
  else if (linkColor === midColorValue) {
1969
2091
  const sourceColor = p1.getFillColor() ?? p1.getStrokeColor(), destColor = p2?.getFillColor() ?? p2?.getStrokeColor();
1970
2092
  if (sourceColor && destColor && p2) {
1971
- return colorMix(sourceColor, destColor, p1.getRadius(), p2.getRadius());
2093
+ return colorMix(sourceColor, destColor, p1.getRadius(), p2.getRadius(), hdr);
1972
2094
  }
1973
2095
  else {
1974
2096
  const hslColor = sourceColor ?? destColor;
@@ -2064,7 +2186,7 @@
2064
2186
  colorValue.velocity = defaultVelocity;
2065
2187
  }
2066
2188
  }
2067
- function updateColorValue(data, decrease, delta, hdr) {
2189
+ function updateColorValue(data, decrease, delta, _hdr) {
2068
2190
  const minLoops = 0, minDelay = 0, identity = 1, minVelocity = 0, minOffset = 0, velocityFactor = 3.6;
2069
2191
  if (!data.enable ||
2070
2192
  ((data.maxLoops ?? minLoops) > minLoops && (data.loops ?? minLoops) > (data.maxLoops ?? minLoops))) {
@@ -2077,7 +2199,7 @@
2077
2199
  if ((data.delayTime ?? minDelay) > minDelay && data.time < (data.delayTime ?? minDelay)) {
2078
2200
  return;
2079
2201
  }
2080
- 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;
2081
2203
  if (!decrease || data.status === AnimationStatus.increasing) {
2082
2204
  data.value += velocity;
2083
2205
  if (data.value > max) {
@@ -2109,9 +2231,9 @@
2109
2231
  return;
2110
2232
  }
2111
2233
  const { h, s, l } = color;
2112
- updateColorValue(h, false, delta, hdr);
2113
- updateColorValue(s, true, delta, hdr);
2114
- updateColorValue(l, true, delta, hdr);
2234
+ updateColorValue(h, false, delta);
2235
+ updateColorValue(s, true, delta);
2236
+ updateColorValue(l, true, delta);
2115
2237
  }
2116
2238
  function alterHsl(color, type, value) {
2117
2239
  return {
@@ -2161,7 +2283,7 @@
2161
2283
  }
2162
2284
 
2163
2285
  async function loadBlendPlugin(engine) {
2164
- engine.checkVersion("4.3.2");
2286
+ engine.checkVersion("4.4.0");
2165
2287
  await engine.pluginManager.register(e => {
2166
2288
  e.pluginManager.addPlugin(new BlendPlugin());
2167
2289
  });
@@ -2198,7 +2320,7 @@
2198
2320
  }
2199
2321
 
2200
2322
  async function loadCircleShape(engine) {
2201
- engine.checkVersion("4.3.2");
2323
+ engine.checkVersion("4.4.0");
2202
2324
  await engine.pluginManager.register(e => {
2203
2325
  e.pluginManager.addShape(["circle"], () => {
2204
2326
  return Promise.resolve(new CircleDrawer());
@@ -2246,7 +2368,7 @@
2246
2368
  }
2247
2369
 
2248
2370
  async function loadHexColorPlugin(engine) {
2249
- engine.checkVersion("4.3.2");
2371
+ engine.checkVersion("4.4.0");
2250
2372
  await engine.pluginManager.register(e => {
2251
2373
  e.pluginManager.addColorManager("hex", new HexColorManager());
2252
2374
  });
@@ -2299,7 +2421,7 @@
2299
2421
  }
2300
2422
 
2301
2423
  async function loadHslColorPlugin(engine) {
2302
- engine.checkVersion("4.3.2");
2424
+ engine.checkVersion("4.4.0");
2303
2425
  await engine.pluginManager.register(e => {
2304
2426
  e.pluginManager.addColorManager("hsl", new HslColorManager());
2305
2427
  });
@@ -2323,7 +2445,7 @@
2323
2445
  }
2324
2446
 
2325
2447
  async function loadMovePlugin(engine) {
2326
- engine.checkVersion("4.3.2");
2448
+ engine.checkVersion("4.4.0");
2327
2449
  await engine.pluginManager.register(e => {
2328
2450
  const moveEngine = e, movePluginManager = moveEngine.pluginManager;
2329
2451
  movePluginManager.initializers.pathGenerators ??= new Map();
@@ -2533,7 +2655,7 @@
2533
2655
  }
2534
2656
 
2535
2657
  async function loadOpacityUpdater(engine) {
2536
- engine.checkVersion("4.3.2");
2658
+ engine.checkVersion("4.4.0");
2537
2659
  await engine.pluginManager.register(e => {
2538
2660
  e.pluginManager.addParticleUpdater("opacity", container => {
2539
2661
  return Promise.resolve(new OpacityUpdater(container));
@@ -2878,7 +3000,7 @@
2878
3000
  }
2879
3001
 
2880
3002
  async function loadOutModesUpdater(engine) {
2881
- engine.checkVersion("4.3.2");
3003
+ engine.checkVersion("4.4.0");
2882
3004
  await engine.pluginManager.register(e => {
2883
3005
  e.pluginManager.addParticleUpdater("outModes", container => {
2884
3006
  return Promise.resolve(new OutOfCanvasUpdater(container));
@@ -2949,7 +3071,7 @@
2949
3071
  }
2950
3072
 
2951
3073
  async function loadPaintUpdater(engine) {
2952
- engine.checkVersion("4.3.2");
3074
+ engine.checkVersion("4.4.0");
2953
3075
  await engine.pluginManager.register(e => {
2954
3076
  e.pluginManager.addParticleUpdater("paint", container => {
2955
3077
  return Promise.resolve(new PaintUpdater(e.pluginManager, container));
@@ -3004,7 +3126,7 @@
3004
3126
  }
3005
3127
 
3006
3128
  async function loadRgbColorPlugin(engine) {
3007
- engine.checkVersion("4.3.2");
3129
+ engine.checkVersion("4.4.0");
3008
3130
  await engine.pluginManager.register(e => {
3009
3131
  e.pluginManager.addColorManager("rgb", new RgbColorManager());
3010
3132
  });
@@ -3089,7 +3211,7 @@
3089
3211
  }
3090
3212
 
3091
3213
  async function loadSizeUpdater(engine) {
3092
- engine.checkVersion("4.3.2");
3214
+ engine.checkVersion("4.4.0");
3093
3215
  await engine.pluginManager.register(e => {
3094
3216
  e.pluginManager.addParticleUpdater("size", container => {
3095
3217
  return Promise.resolve(new SizeUpdater(container));
@@ -3098,7 +3220,7 @@
3098
3220
  }
3099
3221
 
3100
3222
  async function loadBasic(engine) {
3101
- engine.checkVersion("4.3.2");
3223
+ engine.checkVersion("4.4.0");
3102
3224
  await engine.pluginManager.register(async (e) => {
3103
3225
  await Promise.all([
3104
3226
  loadBlendPlugin(e),
@@ -3299,7 +3421,7 @@
3299
3421
  const clickEvent = "click", mouseDownEvent = "pointerdown", mouseUpEvent = "pointerup", mouseLeaveEvent = "pointerleave", mouseMoveEvent = "pointermove", touchStartEvent = "touchstart", touchEndEvent = "touchend", touchMoveEvent = "touchmove", touchCancelEvent = "touchcancel";
3300
3422
 
3301
3423
  async function loadInteractivityPlugin(engine) {
3302
- engine.checkVersion("4.3.2");
3424
+ engine.checkVersion("4.4.0");
3303
3425
  await engine.pluginManager.register(e => {
3304
3426
  const interactivityEngine = e, interactivityPluginManager = interactivityEngine.pluginManager;
3305
3427
  interactivityPluginManager.addPlugin(new InteractivityPlugin(interactivityPluginManager));
@@ -3535,7 +3657,7 @@
3535
3657
  const linkColor = linksOptions.id !== undefined
3536
3658
  ? container.particles.linksColors.get(linksOptions.id)
3537
3659
  : container.particles.linksColor;
3538
- return getLinkColor(p1, p2, linkColor);
3660
+ return getLinkColor(p1, p2, linkColor, container.hdr);
3539
3661
  }
3540
3662
  #setColor(p1) {
3541
3663
  if (!p1.options.links) {
@@ -3576,7 +3698,7 @@
3576
3698
  }
3577
3699
 
3578
3700
  async function loadParticlesLinksInteraction(engine) {
3579
- engine.checkVersion("4.3.2");
3701
+ engine.checkVersion("4.4.0");
3580
3702
  await engine.pluginManager.register((e) => {
3581
3703
  const pluginManager = e.pluginManager;
3582
3704
  ensureInteractivityPluginLoaded(e);
@@ -3754,7 +3876,11 @@
3754
3876
  if (!fColor && !sColor) {
3755
3877
  return;
3756
3878
  }
3757
- 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;
3758
3884
  transform.a = transform.b = transform.c = transform.d = undefined;
3759
3885
  colorStyles.fill = fill;
3760
3886
  colorStyles.stroke = stroke;
@@ -4088,7 +4214,9 @@
4088
4214
  if (typeof background.element === "string") {
4089
4215
  if (typeof document !== "undefined") {
4090
4216
  const node = document.querySelector(background.element);
4091
- 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)) {
4092
4220
  this.#backgroundElement = node;
4093
4221
  }
4094
4222
  else if (node) {
@@ -4099,10 +4227,10 @@
4099
4227
  }
4100
4228
  }
4101
4229
  }
4102
- else if (background.element instanceof HTMLCanvasElement ||
4103
- background.element instanceof OffscreenCanvas ||
4104
- background.element instanceof HTMLVideoElement ||
4105
- 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)) {
4106
4234
  this.#backgroundElement = background.element;
4107
4235
  }
4108
4236
  }
@@ -4170,6 +4298,7 @@
4170
4298
  zoom = defaultZoom;
4171
4299
  #container;
4172
4300
  #generated;
4301
+ #hdrMediaListeners;
4173
4302
  #mutationObserver;
4174
4303
  #originalStyle;
4175
4304
  #pluginManager;
@@ -4234,7 +4363,6 @@
4234
4363
  });
4235
4364
  this.resize();
4236
4365
  this.#initStyle();
4237
- this.initBackground();
4238
4366
  this.#safeMutationObserver(obs => {
4239
4367
  const element = this.domElement;
4240
4368
  if (!element || !(element instanceof Node)) {
@@ -4244,6 +4372,8 @@
4244
4372
  });
4245
4373
  this.initPlugins();
4246
4374
  this.#initContext();
4375
+ this.initBackground();
4376
+ this.#initHdrListeners();
4247
4377
  this.render.init();
4248
4378
  }
4249
4379
  initBackground() {
@@ -4253,7 +4383,8 @@
4253
4383
  }
4254
4384
  const elementStyle = element.style, color = rangeColorToRgb(this.#pluginManager, background.color);
4255
4385
  if (color) {
4256
- 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);
4257
4388
  }
4258
4389
  else {
4259
4390
  elementStyle.backgroundColor = "";
@@ -4350,6 +4481,7 @@
4350
4481
  obs.disconnect();
4351
4482
  });
4352
4483
  this.#mutationObserver = undefined;
4484
+ this.#removeHdrListeners();
4353
4485
  this.render.stop();
4354
4486
  }
4355
4487
  async windowResize() {
@@ -4369,9 +4501,16 @@
4369
4501
  }
4370
4502
  }
4371
4503
  #initContext() {
4372
- const container = this.#container, canSupportHdr = container.actualOptions.hdr &&
4504
+ const container = this.#container, canSupportHdr = container.actualOptions.hdr.enable &&
4373
4505
  safeMatchMedia("(color-gamut: p3)")?.matches &&
4374
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
+ }
4375
4514
  this.render.setContextSettings({
4376
4515
  alpha: true,
4377
4516
  desynchronized: true,
@@ -4380,11 +4519,47 @@
4380
4519
  ? { colorSpace: "display-p3", colorType: "float16" }
4381
4520
  : { colorSpace: "srgb" }),
4382
4521
  });
4383
- const renderCanvas = this.renderCanvas;
4384
- if (!renderCanvas) {
4385
- 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 });
4386
4557
  }
4387
- 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;
4388
4563
  }
4389
4564
  #initStyle() {
4390
4565
  const element = this.domElement, options = this.#container.actualOptions;
@@ -4408,6 +4583,25 @@
4408
4583
  element.style.setProperty(key, value, "important");
4409
4584
  }
4410
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
+ }
4411
4605
  #repairStyle() {
4412
4606
  const element = this.domElement;
4413
4607
  if (!element) {
@@ -4792,9 +4986,9 @@
4792
4986
  }
4793
4987
  getOpacity() {
4794
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;
4795
- this.#cachedOpacityData.fillOpacity = opacity * fillOpacity * zOpacityFactor;
4989
+ this.#cachedOpacityData.fillOpacity = fillOpacity;
4796
4990
  this.#cachedOpacityData.opacity = opacity * zOpacityFactor;
4797
- this.#cachedOpacityData.strokeOpacity = opacity * strokeOpacity * zOpacityFactor;
4991
+ this.#cachedOpacityData.strokeOpacity = strokeOpacity;
4798
4992
  return this.#cachedOpacityData;
4799
4993
  }
4800
4994
  getPosition() {
@@ -5649,6 +5843,7 @@
5649
5843
  effectDrawers;
5650
5844
  fpsLimit;
5651
5845
  hdr;
5846
+ hdrMode;
5652
5847
  id;
5653
5848
  pageHidden;
5654
5849
  particleCreatedPlugins;
@@ -5656,6 +5851,7 @@
5656
5851
  particlePositionPlugins;
5657
5852
  particleUpdaters;
5658
5853
  particles;
5854
+ peakNits;
5659
5855
  plugins;
5660
5856
  retina;
5661
5857
  shapeDrawers;
@@ -5686,6 +5882,8 @@
5686
5882
  this.id = Symbol(id);
5687
5883
  this.fpsLimit = 120;
5688
5884
  this.hdr = false;
5885
+ this.hdrMode = HdrMode.standard;
5886
+ this.peakNits = 400;
5689
5887
  this.#smooth = false;
5690
5888
  this.#delay = 0;
5691
5889
  this.#duration = 0;
@@ -5825,8 +6023,9 @@
5825
6023
  this.updateActualOptions();
5826
6024
  this.canvas.initBackground();
5827
6025
  this.canvas.resize();
5828
- const { delay, duration, fpsLimit, hdr, smooth, zLayers } = this.actualOptions;
5829
- 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;
5830
6029
  this.zLayers = zLayers;
5831
6030
  this.#duration = getRangeValue(duration) * millisecondsToSeconds;
5832
6031
  this.#delay = getRangeValue(delay) * millisecondsToSeconds;
@@ -6952,10 +7151,10 @@
6952
7151
  }
6953
7152
  }
6954
7153
  #getCachedStyle(rgb) {
6955
- 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}`;
6956
7155
  let style = this.#colorCache.get(key);
6957
7156
  if (!style) {
6958
- style = getStyleFromRgb(rgb, this.#container.hdr);
7157
+ style = getStyleFromRgb(rgb, this.#container.hdr, undefined, this.#container.peakNits, this.#container.hdrMode);
6959
7158
  this.#colorCache.set(key, style);
6960
7159
  }
6961
7160
  return style;