@tsparticles/preset-links 4.3.2 → 4.5.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,21 +1,35 @@
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 */
3
- (function (global, factory) {
4
- typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
5
- typeof define === 'function' && define.amd ? define(['exports'], factory) :
6
- (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory((global.__tsParticlesInternals = global.__tsParticlesInternals || {}, global.__tsParticlesInternals.presets = global.__tsParticlesInternals.presets || {}, global.__tsParticlesInternals.presets.links = global.__tsParticlesInternals.presets.links || {})));
7
- })(this, (function (exports) { 'use strict';
8
-
9
- const generatedAttribute = "generated", defaultCompositeValue = "source-over", resizeEvent = "resize", visibilityChangeEvent = "visibilitychange", percentDenominator = 100, half = 0.5, millisecondsToSeconds = 1000, originPoint = {
10
- x: 0,
11
- y: 0,
12
- z: 0,
13
- }, defaultTransform = {
14
- a: 1,
15
- b: 0,
16
- c: 0,
17
- d: 1,
18
- }, randomColorValue = "random", midColorValue = "mid", double = 2, doublePI = Math.PI * double, defaultFps = 60, generatedTrue = "true", generatedFalse = "false", canvasTag = "canvas", defaultRetryCount = 0, squareExp = 2, spatialHashGridCellSize = 100, defaultRemoveQuantity = 1, defaultRatio = 1, defaultReduceFactor = 1, inverseFactorNumerator = 1, rgbMax = 255, hMax = 360, sMax = 100, lMax = 100, hMin = 0, sMin = 0, hPhase = 60, empty = 0, quarter = 0.25, threeQuarter = half + quarter, minVelocity = 0, minDistance$2 = 0, defaultTransformValue = 1, minimumSize = 0, zIndexFactorOffset = 1, defaultOpacity$1 = 1, removeDeleteCount = 1, removeMinIndex = 0, defaultFpsLimit = 120, minFpsLimit = 0, canvasFirstIndex = 0, loadRandomFactor = 10000, loadMinIndex = 0, one = 1, none = 0, decayOffset = 1, tryCountIncrement = 1, minZ = 0, minLimit = 0, countOffset = 1, minCount = 0, minIndex = 0, lengthOffset = 1, defaultDensityFactor = 1, deleteCount = 1, defaultAngle = 0, identity = 1, minStrokeWidth = 0, lFactor = 1, lMin = 0, maxNits = 400, triple = 3, sextuple = 6, sNormalizedOffset = 1, phaseNumerator = 1, defaultRgbMin = 0, defaultVelocity = 0, defaultLoops = 0, defaultTime = 0, defaultZoom = 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);})(typeof globalThis!=="undefined"?globalThis:typeof window!=="undefined"?window:this);
2
+ (function (g) {
3
+ /* Preset v4.5.0 */
4
+ g.__tsParticlesInternals = g.__tsParticlesInternals || {};
5
+ g.__tsParticlesInternals.presets = g.__tsParticlesInternals.presets || {};
6
+ (function (exports) {
7
+ 'use strict';
8
+
9
+ const errorPrefix = "tsParticles - Error", codedErrorPattern = /^\[tsParticles Error (TSP-\d+)\]\s*/, fullMatchIndex = 0, codeIndex = 1;
10
+ const wrap = (fn) => (...args) => {
11
+ fn(...args);
12
+ }, _logger = {
13
+ debug: wrap(console.debug),
14
+ error: (message, ...optionalParams) => {
15
+ if (typeof message === "string") {
16
+ const match = codedErrorPattern.exec(message);
17
+ if (match?.[codeIndex]) {
18
+ console.error(`tsParticles - ${match[codeIndex]} - ${message.slice(match[fullMatchIndex].length)}`, ...optionalParams);
19
+ return;
20
+ }
21
+ }
22
+ console.error(`${errorPrefix} - ${message}`, ...optionalParams);
23
+ },
24
+ info: wrap(console.info),
25
+ log: wrap(console.log),
26
+ trace: wrap(console.trace),
27
+ verbose: wrap(console.log),
28
+ warning: wrap(console.warn),
29
+ };
30
+ function getLogger() {
31
+ return _logger;
32
+ }
19
33
 
20
34
  var MoveDirection;
21
35
  (function (MoveDirection) {
@@ -32,6 +46,17 @@
32
46
  MoveDirection["inside"] = "inside";
33
47
  })(MoveDirection || (MoveDirection = {}));
34
48
 
49
+ const generatedAttribute = "generated", fullPercent = "100%", defaultCompositeValue = "source-over", resizeEvent = "resize", visibilityChangeEvent = "visibilitychange", percentDenominator = 100, half = 0.5, millisecondsToSeconds = 1000, originPoint = {
50
+ x: 0,
51
+ y: 0,
52
+ z: 0,
53
+ }, defaultTransform = {
54
+ a: 1,
55
+ b: 0,
56
+ c: 0,
57
+ d: 1,
58
+ }, randomColorValue = "random", midColorValue = "mid", double = 2, doublePI = Math.PI * double, defaultFps = 60, defaultAlpha = 1, generatedTrue = "true", generatedFalse = "false", canvasTag = "canvas", defaultRetryCount = 0, squareExp = 2, spatialHashGridCellSize = 100, defaultRemoveQuantity = 1, defaultRatio = 1, defaultReduceFactor = 1, inverseFactorNumerator = 1, rgbMax = 255, hMax = 360, sMax = 100, lMax = 100, hMin = 0, sMin = 0, hPhase = 60, empty = 0, quarter = 0.25, threeQuarter = half + quarter, minVelocity = 0, minDistance$2 = 0, minRadius = 0, defaultTransformValue = 1, minimumSize = 0, zIndexFactorOffset = 1, defaultOpacity$1 = 1, removeDeleteCount = 1, removeMinIndex = 0, defaultFpsLimit = 120, minFpsLimit = 0, canvasFirstIndex = 0, loadRandomFactor = 10000, loadMinIndex = 0, one = 1, none = 0, decayOffset = 1, tryCountIncrement = 1, minZ = 0, minLimit = 0, countOffset = 1, minCount = 0, minIndex = 0, lengthOffset = 1, defaultDensityFactor = 1, deleteCount = 1, defaultAngle = 0, identity = 1, minStrokeWidth = 0, lFactor = 1, lMin = 0, maxNits = 400, triple = 3, sextuple = 6, sNormalizedOffset = 1, phaseNumerator = 1, defaultRgbMin = 0, defaultVelocity = 0, defaultLoops = 0, defaultTime = 0, defaultZoom = 1;
59
+
35
60
  function getZ(source) {
36
61
  return "z" in source ? source.z : originPoint.z;
37
62
  }
@@ -147,6 +172,12 @@
147
172
  function isNumber(arg) {
148
173
  return typeof arg === "number";
149
174
  }
175
+ function isEnumValue(enumObject, arg) {
176
+ return Object.values(enumObject).some(enumValue => enumValue === arg);
177
+ }
178
+ function toEnumValue(enumObject, arg, defaultValue) {
179
+ return isEnumValue(enumObject, arg) ? arg : defaultValue;
180
+ }
150
181
  function isObject(arg) {
151
182
  return typeof arg === "object" && arg !== null;
152
183
  }
@@ -273,11 +304,61 @@
273
304
  };
274
305
  }
275
306
  function parseAlpha(input) {
276
- const defaultAlpha = 1;
277
307
  if (!input) {
278
308
  return defaultAlpha;
279
309
  }
280
- return input.endsWith("%") ? parseFloat(input) / percentDenominator : parseFloat(input);
310
+ return input.endsWith("%") ? Number.parseFloat(input) / percentDenominator : Number.parseFloat(input);
311
+ }
312
+
313
+ const ErrorCodes$2 = {
314
+ engineVersionMismatch: "TSP-1001",
315
+ particlePositionNotFound: "TSP-1002",
316
+ pluginRegisterAfterLoad: "TSP-1003",
317
+ offscreenCanvasUnsupported: "TSP-1101",
318
+ offscreenCanvasTransferFailed: "TSP-1102",
319
+ hdrEnableInvalid: "TSP-1201",
320
+ hdrModeInvalid: "TSP-1202",
321
+ hdrPeakNitsInvalid: "TSP-1203",
322
+ };
323
+
324
+ const messages = {
325
+ [ErrorCodes$2.engineVersionMismatch]: "The tsParticles version is different from the loaded plugins version. Engine version: {0}. Plugin version: {1}",
326
+ [ErrorCodes$2.particlePositionNotFound]: "a valid position cannot be found for particle",
327
+ [ErrorCodes$2.pluginRegisterAfterLoad]: "Register plugins can only be done before calling tsParticles.load()",
328
+ [ErrorCodes$2.offscreenCanvasUnsupported]: "OffscreenCanvas is required but not supported by this browser",
329
+ [ErrorCodes$2.offscreenCanvasTransferFailed]: "OffscreenCanvas transfer failed",
330
+ [ErrorCodes$2.hdrEnableInvalid]: 'Invalid HDR "enable" value: expected a boolean, got "{0}"',
331
+ [ErrorCodes$2.hdrModeInvalid]: 'Invalid HDR "mode" value: expected one of {0}, got "{1}"',
332
+ [ErrorCodes$2.hdrPeakNitsInvalid]: 'Invalid HDR "peakNits" value: expected a positive number, got "{0}"',
333
+ };
334
+
335
+ let registeredMessages;
336
+ const ensureRegisteredMessages = () => {
337
+ registeredMessages ??= new Map(Object.entries(messages));
338
+ return registeredMessages;
339
+ }, toStringValue$1 = (value) => String(value), format = (template, args) => {
340
+ return template.replace(/\{(\d+)\}/g, (match, index) => {
341
+ const arg = args[Number(index)];
342
+ return arg === undefined ? match : toStringValue$1(arg);
343
+ });
344
+ };
345
+ function addErrorMessages(extraMessages) {
346
+ if (typeof process !== "undefined" && process.env.NODE_ENV === "production") {
347
+ return;
348
+ }
349
+ const catalog = ensureRegisteredMessages();
350
+ for (const [code, message] of Object.entries(extraMessages)) {
351
+ if (message !== undefined) {
352
+ catalog.set(code, message);
353
+ }
354
+ }
355
+ }
356
+ function getErrorMessage(code, ...args) {
357
+ if (typeof process !== "undefined" && process.env.NODE_ENV === "production") {
358
+ return `[tsParticles Error ${code}] https://particles.js.org/errors/#${code}`;
359
+ }
360
+ const template = ensureRegisteredMessages().get(code) ?? `Unknown error code ${code}`;
361
+ return format(template, args);
281
362
  }
282
363
 
283
364
  var OutModeDirection;
@@ -294,7 +375,6 @@
294
375
  PixelMode["percent"] = "percent";
295
376
  })(PixelMode || (PixelMode = {}));
296
377
 
297
- const minRadius = 0;
298
378
  function isForbiddenKey(key) {
299
379
  return key === "__proto__" || key === "constructor" || key === "prototype";
300
380
  }
@@ -490,22 +570,84 @@
490
570
  element.removeEventListener(event, handler, removeOptions);
491
571
  }
492
572
  }
493
- async function getItemsFromInitializer(container, map, initializers, force = false) {
494
- let res = map.get(container);
495
- if (!res || force) {
496
- res = await Promise.all([...initializers.values()].map(t => t(container)));
497
- map.set(container, res);
573
+ async function getItemsFromInitializer(container, initializers) {
574
+ return await Promise.all([...initializers.values()].map(t => t(container)));
575
+ }
576
+ async function getItemMapFromInitializer(container, initializers) {
577
+ const entries = await Promise.all([...initializers.entries()].map(([key, initializer]) => initializer(container).then(item => [key, item])));
578
+ return new Map(entries);
579
+ }
580
+ async function getDataFromUrl(data) {
581
+ const url = itemFromSingleOrMultiple(data.url, data.index);
582
+ if (!url) {
583
+ return data.fallback;
584
+ }
585
+ try {
586
+ const response = await fetch(url);
587
+ if (response.ok) {
588
+ const current = (await response.json());
589
+ if (isSourceOptionsValue(current)) {
590
+ return current;
591
+ }
592
+ getLogger().error("invalid configuration data while retrieving config file");
593
+ }
594
+ else {
595
+ getLogger().error(`${response.status.toString()} while retrieving config file`);
596
+ }
597
+ }
598
+ catch (error) {
599
+ getLogger().error(`error while retrieving config file: ${error}`);
600
+ }
601
+ return data.fallback;
602
+ }
603
+ function isSourceOptionsValue(value) {
604
+ if (isArray(value)) {
605
+ return value.every((entry) => isObject(entry) && !isArray(entry));
498
606
  }
499
- return res;
607
+ return isObject(value) && !isArray(value);
500
608
  }
501
- async function getItemMapFromInitializer(container, map, initializers, force = false) {
502
- let res = map.get(container);
503
- if (!res || force) {
504
- const entries = await Promise.all([...initializers.entries()].map(([key, initializer]) => initializer(container).then(item => [key, item])));
505
- res = new Map(entries);
506
- map.set(container, res);
609
+ function getCanvasFromContainer(domContainer) {
610
+ let canvasEl;
611
+ const documentSafe = safeDocument(), isCanvas = domContainer instanceof HTMLCanvasElement || domContainer.tagName.toLowerCase() === canvasTag;
612
+ if (isCanvas) {
613
+ canvasEl = domContainer;
614
+ canvasEl.dataset[generatedAttribute] ??= generatedFalse;
615
+ if (canvasEl.dataset[generatedAttribute] === generatedTrue) {
616
+ canvasEl.style.width ||= fullPercent;
617
+ canvasEl.style.height ||= fullPercent;
618
+ canvasEl.style.pointerEvents = "none";
619
+ canvasEl.style.setProperty("pointer-events", "none");
620
+ }
507
621
  }
508
- return res;
622
+ else {
623
+ const existingCanvases = domContainer.getElementsByTagName(canvasTag), foundCanvas = existingCanvases.item(canvasFirstIndex);
624
+ if (foundCanvas) {
625
+ canvasEl = foundCanvas;
626
+ canvasEl.dataset[generatedAttribute] = generatedFalse;
627
+ }
628
+ else {
629
+ canvasEl = documentSafe.createElement(canvasTag);
630
+ canvasEl.dataset[generatedAttribute] = generatedTrue;
631
+ domContainer.appendChild(canvasEl);
632
+ }
633
+ canvasEl.style.width ||= fullPercent;
634
+ canvasEl.style.height ||= fullPercent;
635
+ canvasEl.style.pointerEvents = "none";
636
+ canvasEl.style.setProperty("pointer-events", "none");
637
+ }
638
+ return canvasEl;
639
+ }
640
+ function getDomContainer(id, source) {
641
+ const documentSafe = safeDocument();
642
+ let domContainer = source ?? documentSafe.getElementById(id);
643
+ if (domContainer) {
644
+ return domContainer;
645
+ }
646
+ domContainer = documentSafe.createElement("canvas");
647
+ domContainer.id = id;
648
+ domContainer.dataset[generatedAttribute] = generatedTrue;
649
+ documentSafe.body.append(domContainer);
650
+ return domContainer;
509
651
  }
510
652
 
511
653
  class EventDispatcher {
@@ -576,7 +718,6 @@
576
718
  class PluginManager {
577
719
  colorManagers = new Map();
578
720
  easingFunctions = new Map();
579
- effectDrawers = new Map();
580
721
  initializers = {
581
722
  effects: new Map(),
582
723
  shapes: new Map(),
@@ -585,8 +726,6 @@
585
726
  palettes = new Map();
586
727
  plugins = [];
587
728
  presets = new Map();
588
- shapeDrawers = new Map();
589
- updaters = new Map();
590
729
  #allLoadersSet = new Set();
591
730
  #configs = new Map();
592
731
  #engine;
@@ -604,57 +743,79 @@
604
743
  }
605
744
  return res;
606
745
  }
746
+ get initialized() {
747
+ return this.#initialized;
748
+ }
607
749
  addColorManager(name, manager) {
750
+ if (this.#initialized) {
751
+ return;
752
+ }
608
753
  this.colorManagers.set(name, manager);
609
754
  }
610
755
  addConfig(config) {
756
+ if (this.#initialized) {
757
+ return;
758
+ }
611
759
  const key = config.key ?? config.name ?? "default";
612
760
  this.#configs.set(key, config);
613
761
  this.#engine.dispatchEvent(EventType.configAdded, { data: { name: key, config } });
614
762
  }
615
763
  addEasing(name, easing) {
764
+ if (this.#initialized) {
765
+ return;
766
+ }
616
767
  if (this.easingFunctions.get(name)) {
617
768
  return;
618
769
  }
619
770
  this.easingFunctions.set(name, easing);
620
771
  }
621
772
  addEffect(effect, drawer) {
773
+ if (this.#initialized) {
774
+ return;
775
+ }
622
776
  this.initializers.effects.set(effect, drawer);
623
777
  }
624
778
  addPalette(name, palette) {
779
+ if (this.#initialized) {
780
+ return;
781
+ }
625
782
  this.palettes.set(name, palette);
626
783
  }
627
784
  addParticleUpdater(name, updaterInitializer) {
785
+ if (this.#initialized) {
786
+ return;
787
+ }
628
788
  this.initializers.updaters.set(name, updaterInitializer);
629
789
  }
630
790
  addPlugin(plugin) {
791
+ if (this.#initialized) {
792
+ return;
793
+ }
631
794
  if (this.getPlugin(plugin.id)) {
632
795
  return;
633
796
  }
634
797
  this.plugins.push(plugin);
635
798
  }
636
799
  addPreset(preset, options, override = false) {
800
+ if (this.#initialized) {
801
+ return;
802
+ }
637
803
  if (!(override || !this.getPreset(preset))) {
638
804
  return;
639
805
  }
640
806
  this.presets.set(preset, options);
641
807
  }
642
808
  addShape(shapes, drawer) {
809
+ if (this.#initialized) {
810
+ return;
811
+ }
643
812
  for (const shape of shapes) {
644
813
  this.initializers.shapes.set(shape, drawer);
645
814
  }
646
815
  }
647
- clearPlugins(container) {
648
- this.effectDrawers.delete(container);
649
- this.shapeDrawers.delete(container);
650
- this.updaters.delete(container);
651
- }
652
816
  getEasing(name) {
653
817
  return this.easingFunctions.get(name) ?? ((value) => value);
654
818
  }
655
- getEffectDrawers(container, force = false) {
656
- return getItemMapFromInitializer(container, this.effectDrawers, this.initializers.effects, force);
657
- }
658
819
  getPalette(name) {
659
820
  return this.palettes.get(name);
660
821
  }
@@ -664,12 +825,6 @@
664
825
  getPreset(preset) {
665
826
  return this.presets.get(preset);
666
827
  }
667
- async getShapeDrawers(container, force = false) {
668
- return getItemMapFromInitializer(container, this.shapeDrawers, this.initializers.shapes, force);
669
- }
670
- async getUpdaters(container, force = false) {
671
- return getItemsFromInitializer(container, this.updaters, this.initializers.updaters, force);
672
- }
673
828
  async init() {
674
829
  if (this.#initialized || this.#isRunningLoaders) {
675
830
  return;
@@ -688,16 +843,9 @@
688
843
  this.#initialized = true;
689
844
  }
690
845
  }
691
- loadParticlesOptions(container, options, ...sourceOptions) {
692
- const updaters = this.updaters.get(container);
693
- if (!updaters) {
694
- return;
695
- }
696
- updaters.forEach(updater => updater.loadOptions?.(options, ...sourceOptions));
697
- }
698
846
  async register(...loaders) {
699
847
  if (this.#initialized) {
700
- throw new Error("Register plugins can only be done before calling tsParticles.load()");
848
+ throw new Error(getErrorMessage(ErrorCodes$2.pluginRegisterAfterLoad));
701
849
  }
702
850
  for (const loader of loaders) {
703
851
  if (this.#isRunningLoaders) {
@@ -709,88 +857,15 @@
709
857
  }
710
858
  }
711
859
  async #runLoader(loader, executed, allLoaders) {
712
- if (executed.has(loader))
860
+ if (executed.has(loader)) {
713
861
  return;
862
+ }
714
863
  executed.add(loader);
715
864
  allLoaders.add(loader);
716
865
  await loader(this.#engine);
717
866
  }
718
867
  }
719
868
 
720
- const errorPrefix = "tsParticles - Error";
721
- const wrap = (fn) => (...args) => {
722
- fn(...args);
723
- }, _logger = {
724
- debug: wrap(console.debug),
725
- error: (message, ...optionalParams) => {
726
- console.error(`${errorPrefix} - ${message}`, ...optionalParams);
727
- },
728
- info: wrap(console.info),
729
- log: wrap(console.log),
730
- trace: wrap(console.trace),
731
- verbose: wrap(console.log),
732
- warning: wrap(console.warn),
733
- };
734
- function getLogger() {
735
- return _logger;
736
- }
737
-
738
- const fullPercent = "100%";
739
- async function getDataFromUrl(data) {
740
- const url = itemFromSingleOrMultiple(data.url, data.index);
741
- if (!url) {
742
- return data.fallback;
743
- }
744
- const response = await fetch(url);
745
- if (response.ok) {
746
- return (await response.json());
747
- }
748
- getLogger().error(`${response.status.toString()} while retrieving config file`);
749
- return data.fallback;
750
- }
751
- const getCanvasFromContainer = (domContainer) => {
752
- const documentSafe = safeDocument();
753
- let canvasEl;
754
- const isCanvas = domContainer instanceof HTMLCanvasElement || domContainer.tagName.toLowerCase() === canvasTag;
755
- if (isCanvas) {
756
- canvasEl = domContainer;
757
- canvasEl.dataset[generatedAttribute] ??= generatedFalse;
758
- if (canvasEl.dataset[generatedAttribute] === generatedTrue) {
759
- canvasEl.style.width ||= fullPercent;
760
- canvasEl.style.height ||= fullPercent;
761
- canvasEl.style.pointerEvents = "none";
762
- canvasEl.style.setProperty("pointer-events", "none");
763
- }
764
- }
765
- else {
766
- const existingCanvases = domContainer.getElementsByTagName(canvasTag), foundCanvas = existingCanvases.item(canvasFirstIndex);
767
- if (foundCanvas) {
768
- canvasEl = foundCanvas;
769
- canvasEl.dataset[generatedAttribute] = generatedFalse;
770
- }
771
- else {
772
- canvasEl = documentSafe.createElement(canvasTag);
773
- canvasEl.dataset[generatedAttribute] = generatedTrue;
774
- domContainer.appendChild(canvasEl);
775
- }
776
- canvasEl.style.width ||= fullPercent;
777
- canvasEl.style.height ||= fullPercent;
778
- canvasEl.style.pointerEvents = "none";
779
- canvasEl.style.setProperty("pointer-events", "none");
780
- }
781
- return canvasEl;
782
- }, getDomContainer = (id, source) => {
783
- const documentSafe = safeDocument();
784
- let domContainer = source ?? documentSafe.getElementById(id);
785
- if (domContainer) {
786
- return domContainer;
787
- }
788
- domContainer = documentSafe.createElement("canvas");
789
- domContainer.id = id;
790
- domContainer.dataset[generatedAttribute] = generatedTrue;
791
- documentSafe.body.append(domContainer);
792
- return domContainer;
793
- };
794
869
  class Engine {
795
870
  pluginManager = new PluginManager(this);
796
871
  #domArray = [];
@@ -800,7 +875,7 @@
800
875
  return this.#domArray;
801
876
  }
802
877
  get version() {
803
- return "4.3.2";
878
+ return "4.5.0";
804
879
  }
805
880
  addEventListener(type, listener) {
806
881
  this.#eventDispatcher.addEventListener(type, listener);
@@ -809,7 +884,7 @@
809
884
  if (this.version === pluginVersion) {
810
885
  return;
811
886
  }
812
- throw new Error(`The tsParticles version is different from the loaded plugins version. Engine version: ${this.version}. Plugin version: ${pluginVersion}`);
887
+ throw new Error(getErrorMessage(ErrorCodes$2.engineVersionMismatch, this.version, pluginVersion));
813
888
  }
814
889
  dispatchEvent(type, args) {
815
890
  this.#eventDispatcher.dispatchEvent(type, args);
@@ -881,6 +956,10 @@
881
956
  }
882
957
 
883
958
  function initEngine() {
959
+ const existing = globalThis.tsParticles;
960
+ if (existing?.pluginManager) {
961
+ return existing;
962
+ }
884
963
  return new Engine();
885
964
  }
886
965
 
@@ -978,6 +1057,15 @@
978
1057
  AnimationMode["random"] = "random";
979
1058
  })(AnimationMode || (AnimationMode = {}));
980
1059
 
1060
+ var HdrMode;
1061
+ (function (HdrMode) {
1062
+ HdrMode["standard"] = "standard";
1063
+ HdrMode["natural"] = "natural";
1064
+ HdrMode["vivid"] = "vivid";
1065
+ HdrMode["cinematic"] = "cinematic";
1066
+ HdrMode["dynamic"] = "dynamic";
1067
+ })(HdrMode || (HdrMode = {}));
1068
+
981
1069
  var LimitMode;
982
1070
  (function (LimitMode) {
983
1071
  LimitMode["delete"] = "delete";
@@ -1045,20 +1133,6 @@
1045
1133
  DrawLayer[DrawLayer["Foreground"] = 7] = "Foreground";
1046
1134
  })(DrawLayer || (DrawLayer = {}));
1047
1135
 
1048
- class OptionLoader {
1049
- load(data) {
1050
- if (isNull(data)) {
1051
- return;
1052
- }
1053
- this.doLoad(data);
1054
- }
1055
- }
1056
- function loadOptions(options, ...sourceOptionsArr) {
1057
- for (const sourceOptions of sourceOptionsArr) {
1058
- options.load(sourceOptions);
1059
- }
1060
- }
1061
-
1062
1136
  function loadProperty(obj, key, value) {
1063
1137
  if (value !== undefined) {
1064
1138
  obj[key] = value;
@@ -1090,6 +1164,20 @@
1090
1164
  }
1091
1165
  }
1092
1166
 
1167
+ class OptionLoader {
1168
+ load(data) {
1169
+ if (isNull(data)) {
1170
+ return;
1171
+ }
1172
+ this.doLoad(data);
1173
+ }
1174
+ }
1175
+ function loadOptions(options, ...sourceOptionsArr) {
1176
+ for (const sourceOptions of sourceOptionsArr) {
1177
+ options.load(sourceOptions);
1178
+ }
1179
+ }
1180
+
1093
1181
  class AnimationOptions extends OptionLoader {
1094
1182
  count = 0;
1095
1183
  decay = 0;
@@ -1233,6 +1321,28 @@
1233
1321
  }
1234
1322
  }
1235
1323
 
1324
+ const defaultPeakNits = 400, minPeakNits = 0, toStringValue = (value) => String(value);
1325
+ class HDROptions extends OptionLoader {
1326
+ enable = true;
1327
+ mode = HdrMode.standard;
1328
+ peakNits = defaultPeakNits;
1329
+ doLoad(data) {
1330
+ if (data.enable !== undefined && !isBoolean(data.enable)) {
1331
+ throw new Error(getErrorMessage(ErrorCodes$2.hdrEnableInvalid, String(data.enable)));
1332
+ }
1333
+ if (data.mode !== undefined && !isEnumValue(HdrMode, data.mode)) {
1334
+ throw new Error(getErrorMessage(ErrorCodes$2.hdrModeInvalid, Object.values(HdrMode).join(", "), toStringValue(data.mode)));
1335
+ }
1336
+ if (data.peakNits !== undefined &&
1337
+ (!isNumber(data.peakNits) || !Number.isFinite(data.peakNits) || data.peakNits <= minPeakNits)) {
1338
+ throw new Error(getErrorMessage(ErrorCodes$2.hdrPeakNitsInvalid, String(data.peakNits)));
1339
+ }
1340
+ loadProperty(this, "enable", data.enable);
1341
+ loadProperty(this, "mode", data.mode);
1342
+ loadProperty(this, "peakNits", data.peakNits);
1343
+ }
1344
+ }
1345
+
1236
1346
  class ResizeEvent extends OptionLoader {
1237
1347
  delay = 0.5;
1238
1348
  enable = true;
@@ -1603,12 +1713,10 @@
1603
1713
  plugin.loadParticlesOptions(this.#container, this, data);
1604
1714
  }
1605
1715
  }
1606
- const updaters = this.#pluginManager.updaters.get(this.#container);
1607
- if (updaters) {
1608
- for (const updater of updaters) {
1609
- if (updater.loadOptions) {
1610
- updater.loadOptions(this, data);
1611
- }
1716
+ const updaters = this.#container.particleUpdaters;
1717
+ for (const updater of updaters) {
1718
+ if (updater.loadOptions) {
1719
+ updater.loadOptions(this, data);
1612
1720
  }
1613
1721
  }
1614
1722
  }
@@ -1676,7 +1784,7 @@
1676
1784
  duration = 0;
1677
1785
  fpsLimit = 120;
1678
1786
  fullScreen;
1679
- hdr = true;
1787
+ hdr;
1680
1788
  key;
1681
1789
  name;
1682
1790
  palette;
@@ -1696,6 +1804,7 @@
1696
1804
  this.#container = container;
1697
1805
  this.background = new Background();
1698
1806
  this.fullScreen = new FullScreen();
1807
+ this.hdr = new HDROptions();
1699
1808
  this.particles = loadParticlesOptions(this.#pluginManager, this.#container);
1700
1809
  this.resize = new ResizeEvent();
1701
1810
  }
@@ -1718,7 +1827,15 @@
1718
1827
  loadProperty(this, "detectRetina", data.detectRetina);
1719
1828
  loadRangeProperty(this, "duration", data.duration);
1720
1829
  loadProperty(this, "fpsLimit", data.fpsLimit);
1721
- loadProperty(this, "hdr", data.hdr);
1830
+ const hdrData = data.hdr;
1831
+ if (isBoolean(hdrData)) {
1832
+ this.hdr.enable = hdrData;
1833
+ this.hdr.mode = HdrMode.standard;
1834
+ this.hdr.peakNits = 400;
1835
+ }
1836
+ else {
1837
+ this.hdr.load(hdrData);
1838
+ }
1722
1839
  loadProperty(this, "pauseOnBlur", data.pauseOnBlur);
1723
1840
  loadProperty(this, "pauseOnOutsideViewport", data.pauseOnOutsideViewport);
1724
1841
  loadProperty(this, "zLayers", data.zLayers);
@@ -1761,7 +1878,7 @@
1761
1878
  }
1762
1879
  }
1763
1880
 
1764
- const styleCache = new Map(), maxStyleCacheSize = 2000, rgbFixedPrecision = 2, hslFixedPrecision = 2, hdrRgbFixedPrecision = 4, hdrHslFixedPrecision = 4, sdrReferenceWhiteNits = 203, hdrAnimationScale = sdrReferenceWhiteNits / maxNits;
1881
+ 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
1882
  function getCachedStyle(key, generator) {
1766
1883
  let cached = styleCache.get(key);
1767
1884
  if (!cached) {
@@ -1773,6 +1890,48 @@
1773
1890
  }
1774
1891
  return cached;
1775
1892
  }
1893
+ function acesFilmic(x) {
1894
+ return clamp((x * (acesA * x + acesB)) / (x * (acesC * x + acesD) + acesE), none, one);
1895
+ }
1896
+ function srgbToLinear(c) {
1897
+ return c <= srgbThreshold ? c / srgbDivisor : Math.pow((c + srgbOffset) / srgbScale, srgbExponent);
1898
+ }
1899
+ function linearToSrgb(c) {
1900
+ return c <= linearThreshold ? c * linearScale : srgbScale * Math.pow(c, one / srgbExponent) - srgbOffset;
1901
+ }
1902
+ function applyHdrModeAdjustments(r, g, b, mode, maxChannel) {
1903
+ switch (mode) {
1904
+ case HdrMode.vivid: {
1905
+ const avg = (r + g + b) / channelCount;
1906
+ return {
1907
+ b: clamp(clamp(avg + (b - avg) * saturationBoost, none, maxChannel) * lightnessBoost, none, maxChannel),
1908
+ g: clamp(clamp(avg + (g - avg) * saturationBoost, none, maxChannel) * lightnessBoost, none, maxChannel),
1909
+ r: clamp(clamp(avg + (r - avg) * saturationBoost, none, maxChannel) * lightnessBoost, none, maxChannel),
1910
+ };
1911
+ }
1912
+ case HdrMode.cinematic: {
1913
+ const tempR = r * temperatureR, tempB = b * temperatureB, avg = (tempR + g + tempB) / channelCount;
1914
+ return {
1915
+ b: clamp(avg + (tempB - avg) * contrastFactor, none, maxChannel),
1916
+ g: clamp(avg + (g - avg) * contrastFactor, none, maxChannel),
1917
+ r: clamp(avg + (tempR - avg) * contrastFactor, none, maxChannel),
1918
+ };
1919
+ }
1920
+ case HdrMode.dynamic: {
1921
+ 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;
1922
+ return {
1923
+ b: clamp(b * naturalWeight + vividB * vividWeight, none, maxChannel),
1924
+ g: clamp(g * naturalWeight + vividG * vividWeight, none, maxChannel),
1925
+ r: clamp(r * naturalWeight + vividR * vividWeight, none, maxChannel),
1926
+ };
1927
+ }
1928
+ case HdrMode.standard:
1929
+ return { b, g, r };
1930
+ case HdrMode.natural:
1931
+ default:
1932
+ return { b, g, r };
1933
+ }
1934
+ }
1776
1935
  function stringToRgba(pluginManager, input) {
1777
1936
  if (!input) {
1778
1937
  return;
@@ -1896,9 +2055,9 @@
1896
2055
  const grayscaleValue = Math.round(lNormalized * rgbMax);
1897
2056
  return { r: grayscaleValue, g: grayscaleValue, b: grayscaleValue };
1898
2057
  }
1899
- const temp1 = lNormalized < half
2058
+ const temp2 = lNormalized < half
1900
2059
  ? lNormalized * (sNormalizedOffset + sNormalized)
1901
- : lNormalized + sNormalized - lNormalized * sNormalized, temp2 = double * lNormalized - temp1, phaseThird = phaseNumerator / triple, red = Math.min(rgbMax, rgbMax * hslChannel(temp2, temp1, hNormalized + phaseThird)), green = Math.min(rgbMax, rgbMax * hslChannel(temp2, temp1, hNormalized)), blue = Math.min(rgbMax, rgbMax * hslChannel(temp2, temp1, hNormalized - phaseThird));
2060
+ : lNormalized + sNormalized - lNormalized * sNormalized, temp1 = double * lNormalized - temp2, phaseThird = phaseNumerator / triple, red = Math.min(rgbMax, rgbMax * hslChannel(temp1, temp2, hNormalized + phaseThird)), green = Math.min(rgbMax, rgbMax * hslChannel(temp1, temp2, hNormalized)), blue = Math.min(rgbMax, rgbMax * hslChannel(temp1, temp2, hNormalized - phaseThird));
1902
2061
  return { r: Math.round(red), g: Math.round(green), b: Math.round(blue) };
1903
2062
  }
1904
2063
  function hslToRgbFloat(hsl) {
@@ -1907,9 +2066,9 @@
1907
2066
  const grayscaleValue = lNormalized * rgbMax;
1908
2067
  return { r: grayscaleValue, g: grayscaleValue, b: grayscaleValue };
1909
2068
  }
1910
- const temp1 = lNormalized < half
2069
+ const temp2 = lNormalized < half
1911
2070
  ? lNormalized * (sNormalizedOffset + sNormalized)
1912
- : lNormalized + sNormalized - lNormalized * sNormalized, temp2 = double * lNormalized - temp1, phaseThird = phaseNumerator / triple, red = Math.min(rgbMax, rgbMax * hslChannel(temp2, temp1, hNormalized + phaseThird)), green = Math.min(rgbMax, rgbMax * hslChannel(temp2, temp1, hNormalized)), blue = Math.min(rgbMax, rgbMax * hslChannel(temp2, temp1, hNormalized - phaseThird));
2071
+ : lNormalized + sNormalized - lNormalized * sNormalized, temp1 = double * lNormalized - temp2, phaseThird = phaseNumerator / triple, red = Math.min(rgbMax, rgbMax * hslChannel(temp1, temp2, hNormalized + phaseThird)), green = Math.min(rgbMax, rgbMax * hslChannel(temp1, temp2, hNormalized)), blue = Math.min(rgbMax, rgbMax * hslChannel(temp1, temp2, hNormalized - phaseThird));
1913
2072
  return { r: red, g: green, b: blue };
1914
2073
  }
1915
2074
  function hslaToRgba(hsla) {
@@ -1930,30 +2089,65 @@
1930
2089
  r: getRgbInRangeValue(),
1931
2090
  };
1932
2091
  }
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)));
2092
+ function getStyleFromRgb(color, hdr, opacity, peakNits, mode) {
2093
+ const rgbPrecision = hdr ? hdrRgbFixedPrecision : rgbFixedPrecision, op = opacity ?? defaultOpacity$1, key = hdr
2094
+ ? `rgb-${color.r.toFixed(rgbPrecision)}-${color.g.toFixed(rgbPrecision)}-${color.b.toFixed(rgbPrecision)}-hdr-${op.toString()}-${(peakNits ?? maxNits).toString()}-${mode ?? HdrMode.standard}`
2095
+ : `rgb-${color.r.toFixed(rgbPrecision)}-${color.g.toFixed(rgbPrecision)}-${color.b.toFixed(rgbPrecision)}-sdr-${op.toString()}`;
2096
+ return getCachedStyle(key, () => hdr ? getHdrStyleFromRgb(color, opacity, peakNits, mode) : getSdrStyleFromRgb(color, opacity));
2097
+ }
2098
+ function getHdrStyleFromRgb(color, opacity, peakNits = maxNits, mode = HdrMode.standard) {
2099
+ const headroom = peakNits / sdrReferenceWhiteNits, middleGray = 0.18, mapped = hdrToneMapColor(color, headroom, middleGray, mode);
2100
+ return `color(display-p3 ${mapped.r.toString()} ${mapped.g.toString()} ${mapped.b.toString()} / ${(opacity ?? defaultOpacity$1).toString()})`;
2101
+ }
2102
+ function hdrToneMapColor(color, headroom, middleGray, mode) {
2103
+ const rNorm = color.r / rgbMax, gNorm = color.g / rgbMax, bNorm = color.b / rgbMax;
2104
+ if (mode !== HdrMode.natural && mode !== HdrMode.vivid && mode !== HdrMode.cinematic && mode !== HdrMode.dynamic) {
2105
+ return { b: bNorm, g: gNorm, r: rNorm };
2106
+ }
2107
+ const maxChannel = Math.max(one, headroom), luminance = luminanceR * rNorm + luminanceG * gNorm + luminanceB * bNorm, mappedLuminance = hdrToneMap(luminance, headroom, middleGray), scale = luminance > none ? mappedLuminance / luminance : one;
2108
+ return applyHdrModeAdjustments(clamp(rNorm * scale, none, maxChannel), clamp(gNorm * scale, none, maxChannel), clamp(bNorm * scale, none, maxChannel), mode, maxChannel);
1936
2109
  }
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()})`;
2110
+ function hdrToneMap(normalized, headroom, middleGray) {
2111
+ if (normalized <= middleGray) {
2112
+ return acesFilmic(normalized);
2113
+ }
2114
+ const expanded = normalized + (normalized - middleGray) * (headroom - one);
2115
+ return acesFilmic(expanded);
1940
2116
  }
1941
2117
  function getSdrStyleFromRgb(color, opacity) {
1942
2118
  return `rgba(${color.r.toString()}, ${color.g.toString()}, ${color.b.toString()}, ${(opacity ?? defaultOpacity$1).toString()})`;
1943
2119
  }
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()}`;
2120
+ function getStyleFromHsl(color, hdr, opacity, peakNits, mode) {
2121
+ const hslPrecision = hdr ? hdrHslFixedPrecision : hslFixedPrecision, op = opacity ?? defaultOpacity$1, key = hdr
2122
+ ? `hsl-${color.h.toFixed(hslPrecision)}-${color.s.toFixed(hslPrecision)}-${color.l.toFixed(hslPrecision)}-hdr-${op.toString()}-${(peakNits ?? maxNits).toString()}-${mode ?? HdrMode.standard}`
2123
+ : `hsl-${color.h.toFixed(hslPrecision)}-${color.s.toFixed(hslPrecision)}-${color.l.toFixed(hslPrecision)}-sdr-${op.toString()}`;
1946
2124
  return getCachedStyle(key, () => hdr
1947
- ? getStyleFromRgb(hslToRgbFloat(color), true, opacity)
2125
+ ? getStyleFromRgb(hslToRgbFloat(color), true, opacity, peakNits, mode)
1948
2126
  : `hsla(${color.h.toString()}, ${color.s.toString()}%, ${color.l.toString()}%, ${op.toString()})`);
1949
2127
  }
1950
- function colorMix(color1, color2, size1, size2) {
2128
+ function colorMix(color1, color2, size1, size2, hdr) {
1951
2129
  let rgb1 = color1, rgb2 = color2;
1952
2130
  if (!("r" in rgb1)) {
1953
- rgb1 = hslToRgb(color1);
2131
+ rgb1 = hdr ? hslToRgbFloat(color1) : hslToRgb(color1);
1954
2132
  }
1955
2133
  if (!("r" in rgb2)) {
1956
- rgb2 = hslToRgb(color2);
2134
+ rgb2 = hdr ? hslToRgbFloat(color2) : hslToRgb(color2);
2135
+ }
2136
+ if (hdr) {
2137
+ const lin1 = {
2138
+ b: srgbToLinear(rgb1.b / rgbMax),
2139
+ g: srgbToLinear(rgb1.g / rgbMax),
2140
+ r: srgbToLinear(rgb1.r / rgbMax),
2141
+ }, lin2 = {
2142
+ b: srgbToLinear(rgb2.b / rgbMax),
2143
+ g: srgbToLinear(rgb2.g / rgbMax),
2144
+ r: srgbToLinear(rgb2.r / rgbMax),
2145
+ }, totalWeight = size1 + size2;
2146
+ return {
2147
+ b: linearToSrgb((lin1.b * size1 + lin2.b * size2) / totalWeight) * rgbMax,
2148
+ g: linearToSrgb((lin1.g * size1 + lin2.g * size2) / totalWeight) * rgbMax,
2149
+ r: linearToSrgb((lin1.r * size1 + lin2.r * size2) / totalWeight) * rgbMax,
2150
+ };
1957
2151
  }
1958
2152
  return {
1959
2153
  b: mix(rgb1.b, rgb2.b, size1, size2),
@@ -1961,14 +2155,14 @@
1961
2155
  r: mix(rgb1.r, rgb2.r, size1, size2),
1962
2156
  };
1963
2157
  }
1964
- function getLinkColor(p1, p2, linkColor) {
2158
+ function getLinkColor(p1, p2, linkColor, hdr) {
1965
2159
  if (linkColor === randomColorValue) {
1966
2160
  return getRandomRgbColor();
1967
2161
  }
1968
2162
  else if (linkColor === midColorValue) {
1969
2163
  const sourceColor = p1.getFillColor() ?? p1.getStrokeColor(), destColor = p2?.getFillColor() ?? p2?.getStrokeColor();
1970
2164
  if (sourceColor && destColor && p2) {
1971
- return colorMix(sourceColor, destColor, p1.getRadius(), p2.getRadius());
2165
+ return colorMix(sourceColor, destColor, p1.getRadius(), p2.getRadius(), hdr);
1972
2166
  }
1973
2167
  else {
1974
2168
  const hslColor = sourceColor ?? destColor;
@@ -2064,7 +2258,7 @@
2064
2258
  colorValue.velocity = defaultVelocity;
2065
2259
  }
2066
2260
  }
2067
- function updateColorValue(data, decrease, delta, hdr) {
2261
+ function updateColorValue(data, decrease, delta, _hdr) {
2068
2262
  const minLoops = 0, minDelay = 0, identity = 1, minVelocity = 0, minOffset = 0, velocityFactor = 3.6;
2069
2263
  if (!data.enable ||
2070
2264
  ((data.maxLoops ?? minLoops) > minLoops && (data.loops ?? minLoops) > (data.maxLoops ?? minLoops))) {
@@ -2077,7 +2271,7 @@
2077
2271
  if ((data.delayTime ?? minDelay) > minDelay && data.time < (data.delayTime ?? minDelay)) {
2078
2272
  return;
2079
2273
  }
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;
2274
+ 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
2275
  if (!decrease || data.status === AnimationStatus.increasing) {
2082
2276
  data.value += velocity;
2083
2277
  if (data.value > max) {
@@ -2109,9 +2303,9 @@
2109
2303
  return;
2110
2304
  }
2111
2305
  const { h, s, l } = color;
2112
- updateColorValue(h, false, delta, hdr);
2113
- updateColorValue(s, true, delta, hdr);
2114
- updateColorValue(l, true, delta, hdr);
2306
+ updateColorValue(h, false, delta);
2307
+ updateColorValue(s, true, delta);
2308
+ updateColorValue(l, true, delta);
2115
2309
  }
2116
2310
  function alterHsl(color, type, value) {
2117
2311
  return {
@@ -2161,7 +2355,7 @@
2161
2355
  }
2162
2356
 
2163
2357
  async function loadBlendPlugin(engine) {
2164
- engine.checkVersion("4.3.2");
2358
+ engine.checkVersion("4.5.0");
2165
2359
  await engine.pluginManager.register(e => {
2166
2360
  e.pluginManager.addPlugin(new BlendPlugin());
2167
2361
  });
@@ -2198,7 +2392,7 @@
2198
2392
  }
2199
2393
 
2200
2394
  async function loadCircleShape(engine) {
2201
- engine.checkVersion("4.3.2");
2395
+ engine.checkVersion("4.5.0");
2202
2396
  await engine.pluginManager.register(e => {
2203
2397
  e.pluginManager.addShape(["circle"], () => {
2204
2398
  return Promise.resolve(new CircleDrawer());
@@ -2213,7 +2407,7 @@
2213
2407
  RgbIndexes[RgbIndexes["b"] = 3] = "b";
2214
2408
  RgbIndexes[RgbIndexes["a"] = 4] = "a";
2215
2409
  })(RgbIndexes$1 || (RgbIndexes$1 = {}));
2216
- const shorthandHexRegex = /^#?([a-f\d])([a-f\d])([a-f\d])([a-f\d])?$/i, hexRegex = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})?$/i, hexRadix = 16, defaultAlpha = 1, alphaFactor = 0xff;
2410
+ const shorthandHexRegex = /^#?([a-f\d])([a-f\d])([a-f\d])([a-f\d])?$/i, hexRegex = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})?$/i, hexRadix = 16, alphaFactor = 0xff;
2217
2411
  class HexColorManager {
2218
2412
  accepts(input) {
2219
2413
  return input.startsWith("#");
@@ -2246,7 +2440,7 @@
2246
2440
  }
2247
2441
 
2248
2442
  async function loadHexColorPlugin(engine) {
2249
- engine.checkVersion("4.3.2");
2443
+ engine.checkVersion("4.5.0");
2250
2444
  await engine.pluginManager.register(e => {
2251
2445
  e.pluginManager.addColorManager("hex", new HexColorManager());
2252
2446
  });
@@ -2286,7 +2480,7 @@
2286
2480
  if (!this.accepts(input)) {
2287
2481
  return;
2288
2482
  }
2289
- const result = hslRegex.exec(input), minLength = 4, defaultAlpha = 1, radix = 10;
2483
+ const result = hslRegex.exec(input), minLength = 4, radix = 10;
2290
2484
  return result
2291
2485
  ? hslaToRgba({
2292
2486
  a: result.length > minLength ? parseAlpha(result[HslIndexes.a]) : defaultAlpha,
@@ -2299,12 +2493,20 @@
2299
2493
  }
2300
2494
 
2301
2495
  async function loadHslColorPlugin(engine) {
2302
- engine.checkVersion("4.3.2");
2496
+ engine.checkVersion("4.5.0");
2303
2497
  await engine.pluginManager.register(e => {
2304
2498
  e.pluginManager.addColorManager("hsl", new HslColorManager());
2305
2499
  });
2306
2500
  }
2307
2501
 
2502
+ const ErrorCodes$1 = {
2503
+ baseMoverNotLoaded: "TSP-3203",
2504
+ };
2505
+
2506
+ const ErrorMessages$1 = {
2507
+ [ErrorCodes$1.baseMoverNotLoaded]: "tsParticles Base Mover is not loaded",
2508
+ };
2509
+
2308
2510
  class MovePlugin {
2309
2511
  id = "move";
2310
2512
  #pluginManager;
@@ -2323,20 +2525,20 @@
2323
2525
  }
2324
2526
 
2325
2527
  async function loadMovePlugin(engine) {
2326
- engine.checkVersion("4.3.2");
2528
+ engine.checkVersion("4.5.0");
2529
+ if (typeof process !== "undefined" && process.env.NODE_ENV !== "production") {
2530
+ addErrorMessages(ErrorMessages$1);
2531
+ }
2327
2532
  await engine.pluginManager.register(e => {
2328
2533
  const moveEngine = e, movePluginManager = moveEngine.pluginManager;
2329
2534
  movePluginManager.initializers.pathGenerators ??= new Map();
2330
- movePluginManager.pathGenerators ??= new Map();
2331
2535
  movePluginManager.addPathGenerator = (name, generator) => {
2536
+ if (movePluginManager.initialized) {
2537
+ return;
2538
+ }
2332
2539
  movePluginManager.initializers.pathGenerators ??= new Map();
2333
2540
  movePluginManager.initializers.pathGenerators.set(name, generator);
2334
2541
  };
2335
- movePluginManager.getPathGenerators = async (container, force = false) => {
2336
- movePluginManager.initializers.pathGenerators ??= new Map();
2337
- movePluginManager.pathGenerators ??= new Map();
2338
- return getItemMapFromInitializer(container, movePluginManager.pathGenerators, movePluginManager.initializers.pathGenerators, force);
2339
- };
2340
2542
  e.pluginManager.addPlugin(new MovePlugin(e.pluginManager));
2341
2543
  });
2342
2544
  }
@@ -2533,7 +2735,7 @@
2533
2735
  }
2534
2736
 
2535
2737
  async function loadOpacityUpdater(engine) {
2536
- engine.checkVersion("4.3.2");
2738
+ engine.checkVersion("4.5.0");
2537
2739
  await engine.pluginManager.register(e => {
2538
2740
  e.pluginManager.addParticleUpdater("opacity", container => {
2539
2741
  return Promise.resolve(new OpacityUpdater(container));
@@ -2542,70 +2744,60 @@
2542
2744
  }
2543
2745
 
2544
2746
  const boundsMin = 0;
2545
- function bounceHorizontal(data) {
2546
- if ((data.outMode !== OutMode.bounce && data.outMode !== OutMode.split) ||
2547
- (data.direction !== OutModeDirection.left && data.direction !== OutModeDirection.right)) {
2548
- return;
2549
- }
2550
- if (data.bounds.right < boundsMin && data.direction === OutModeDirection.left) {
2551
- data.particle.position.x = data.size + data.offset.x;
2552
- }
2553
- else if (data.bounds.left > data.canvasSize.width && data.direction === OutModeDirection.right) {
2554
- data.particle.position.x = data.canvasSize.width - data.size - data.offset.x;
2555
- }
2556
- const velocity = data.particle.velocity.x;
2557
- let bounced = false;
2558
- if (data.outOfCanvas &&
2559
- ((data.direction === OutModeDirection.right && velocity > minVelocity) ||
2560
- (data.direction === OutModeDirection.left && velocity < minVelocity))) {
2561
- const newVelocity = getRangeValue(data.particle.options.bounce.horizontal.value);
2562
- data.particle.velocity.x *= -newVelocity;
2563
- bounced = true;
2564
- }
2565
- if (!bounced) {
2566
- return;
2567
- }
2568
- const minPos = data.offset.x + data.size;
2569
- if (data.outOfCanvas && data.direction === OutModeDirection.right) {
2570
- data.particle.position.x = data.canvasSize.width - minPos;
2571
- }
2572
- else if (data.outOfCanvas && data.direction === OutModeDirection.left) {
2573
- data.particle.position.x = minPos;
2574
- }
2575
- if (data.outMode === OutMode.split) {
2576
- data.particle.destroy();
2577
- }
2578
- }
2579
- function bounceVertical(data) {
2580
- if ((data.outMode !== OutMode.bounce && data.outMode !== OutMode.split) ||
2581
- (data.direction !== OutModeDirection.bottom && data.direction !== OutModeDirection.top)) {
2747
+ const bounceAxisConfigs = {
2748
+ [OutModeDirection.left]: {
2749
+ axis: "x",
2750
+ canvas: "width",
2751
+ bounce: "horizontal",
2752
+ negativeEdge: "right",
2753
+ positiveEdge: "left",
2754
+ negative: true,
2755
+ },
2756
+ [OutModeDirection.right]: {
2757
+ axis: "x",
2758
+ canvas: "width",
2759
+ bounce: "horizontal",
2760
+ negativeEdge: "right",
2761
+ positiveEdge: "left",
2762
+ negative: false,
2763
+ },
2764
+ [OutModeDirection.top]: {
2765
+ axis: "y",
2766
+ canvas: "height",
2767
+ bounce: "vertical",
2768
+ negativeEdge: "bottom",
2769
+ positiveEdge: "top",
2770
+ negative: true,
2771
+ },
2772
+ [OutModeDirection.bottom]: {
2773
+ axis: "y",
2774
+ canvas: "height",
2775
+ bounce: "vertical",
2776
+ negativeEdge: "bottom",
2777
+ positiveEdge: "top",
2778
+ negative: false,
2779
+ },
2780
+ };
2781
+ function bounce(data) {
2782
+ if ((data.outMode !== OutMode.bounce && data.outMode !== OutMode.split) || !(data.direction in bounceAxisConfigs)) {
2582
2783
  return;
2583
2784
  }
2584
- if (data.bounds.bottom < boundsMin && data.direction === OutModeDirection.top) {
2585
- data.particle.position.y = data.size + data.offset.y;
2785
+ const config = bounceAxisConfigs[data.direction], bounds = data.bounds, canvasDim = data.canvasSize[config.canvas], position = data.particle.position, velocity = data.particle.velocity[config.axis];
2786
+ if (config.negative && bounds[config.negativeEdge] < boundsMin) {
2787
+ position[config.axis] = data.size + data.offset[config.axis];
2586
2788
  }
2587
- else if (data.bounds.top > data.canvasSize.height && data.direction === OutModeDirection.bottom) {
2588
- data.particle.position.y = data.canvasSize.height - data.size - data.offset.y;
2789
+ else if (!config.negative && bounds[config.positiveEdge] > canvasDim) {
2790
+ position[config.axis] = canvasDim - data.size - data.offset[config.axis];
2589
2791
  }
2590
- const velocity = data.particle.velocity.y;
2591
- let bounced = false;
2592
2792
  if (data.outOfCanvas &&
2593
- ((data.direction === OutModeDirection.bottom && velocity > minVelocity) ||
2594
- (data.direction === OutModeDirection.top && velocity < minVelocity))) {
2595
- const newVelocity = getRangeValue(data.particle.options.bounce.vertical.value);
2596
- data.particle.velocity.y *= -newVelocity;
2597
- bounced = true;
2793
+ ((config.negative && velocity < minVelocity) || (!config.negative && velocity > minVelocity))) {
2794
+ data.particle.velocity[config.axis] *= -getRangeValue(data.particle.options.bounce[config.bounce].value);
2598
2795
  }
2599
- if (!bounced) {
2796
+ else {
2600
2797
  return;
2601
2798
  }
2602
- const minPos = data.offset.y + data.size;
2603
- if (data.outOfCanvas && data.direction === OutModeDirection.bottom) {
2604
- data.particle.position.y = data.canvasSize.height - minPos;
2605
- }
2606
- else if (data.outOfCanvas && data.direction === OutModeDirection.top) {
2607
- data.particle.position.y = minPos;
2608
- }
2799
+ const minPos = data.offset[config.axis] + data.size;
2800
+ position[config.axis] = config.negative ? minPos : canvasDim - minPos;
2609
2801
  if (data.outMode === OutMode.split) {
2610
2802
  data.particle.destroy();
2611
2803
  }
@@ -2621,26 +2813,19 @@
2621
2813
  OutMode.bounce,
2622
2814
  OutMode.split,
2623
2815
  ];
2624
- this.#particleBouncePlugins = container.plugins.filter(p => p.particleBounce !== undefined);
2816
+ this.#particleBouncePlugins = container.plugins.filter(p => !!p.particleBounce);
2625
2817
  }
2626
2818
  update(particle, direction, delta, outMode) {
2627
2819
  if (!this.modes.includes(outMode)) {
2628
2820
  return;
2629
2821
  }
2630
- const container = this.#container;
2631
- let handled = false;
2632
2822
  for (const plugin of this.#particleBouncePlugins) {
2633
- handled = plugin.particleBounce?.(particle, delta, direction) ?? false;
2634
- if (handled) {
2635
- break;
2823
+ if (plugin.particleBounce?.(particle, delta, direction)) {
2824
+ return;
2636
2825
  }
2637
2826
  }
2638
- if (handled) {
2639
- return;
2640
- }
2641
- const pos = particle.getPosition(), offset = particle.offset, size = particle.getRadius(), bounds = calculateBounds(pos, size), canvasSize = container.canvas.size, outOfCanvas = !particle.isInsideCanvasForOutMode(outMode, direction);
2642
- bounceHorizontal({ particle, outMode, direction, bounds, canvasSize, offset, outOfCanvas, size });
2643
- bounceVertical({ particle, outMode, direction, bounds, canvasSize, offset, outOfCanvas, size });
2827
+ const pos = particle.getPosition(), offset = particle.offset, size = particle.getRadius(), bounds = calculateBounds(pos, size), canvasSize = this.#container.canvas.size, outOfCanvas = !particle.isInsideCanvasForOutMode(outMode, direction);
2828
+ bounce({ particle, outMode, direction, bounds, canvasSize, offset, outOfCanvas, size });
2644
2829
  }
2645
2830
  }
2646
2831
 
@@ -2729,107 +2914,108 @@
2729
2914
  return;
2730
2915
  }
2731
2916
  const container = this.#container;
2732
- switch (particle.outType) {
2733
- case ParticleOutType.inside: {
2734
- const { x: vx, y: vy } = particle.velocity;
2735
- updateVector.setTo(originPoint);
2736
- updateVector.length = particle.moveCenter.radius;
2737
- updateVector.angle = particle.velocity.angle + Math.PI;
2738
- updateVector.addTo(particle.moveCenter);
2739
- const { dx, dy } = getDistances(particle.position, updateVector);
2740
- if ((vx <= minVelocity && dx >= minDistance$2) ||
2741
- (vy <= minVelocity && dy >= minDistance$2) ||
2742
- (vx >= minVelocity && dx <= minDistance$2) ||
2743
- (vy >= minVelocity && dy <= minDistance$2)) {
2744
- return;
2745
- }
2746
- particle.position.x = Math.floor(randomInRangeValue({
2747
- min: 0,
2748
- max: container.canvas.size.width,
2749
- }));
2750
- particle.position.y = Math.floor(randomInRangeValue({
2751
- min: 0,
2752
- max: container.canvas.size.height,
2753
- }));
2754
- const { dx: newDx, dy: newDy } = getDistances(particle.position, particle.moveCenter);
2755
- particle.direction = Math.atan2(-newDy, -newDx);
2756
- particle.velocity.angle = particle.direction;
2757
- particle.justWarped = true;
2758
- break;
2917
+ if (particle.outType === ParticleOutType.inside) {
2918
+ this.#applyOutModeInside(particle, container);
2919
+ }
2920
+ else {
2921
+ if (particle.isInsideCanvasForOutMode(outMode, direction)) {
2922
+ return;
2759
2923
  }
2760
- default: {
2761
- if (particle.isInsideCanvasForOutMode(outMode, direction)) {
2762
- return;
2763
- }
2764
- switch (particle.outType) {
2765
- case ParticleOutType.outside: {
2766
- particle.position.x =
2767
- Math.floor(randomInRangeValue({
2768
- min: -particle.moveCenter.radius,
2769
- max: particle.moveCenter.radius,
2770
- })) + particle.moveCenter.x;
2771
- particle.position.y =
2772
- Math.floor(randomInRangeValue({
2773
- min: -particle.moveCenter.radius,
2774
- max: particle.moveCenter.radius,
2775
- })) + particle.moveCenter.y;
2776
- const { dx, dy } = getDistances(particle.position, particle.moveCenter);
2777
- if (particle.moveCenter.radius) {
2778
- particle.direction = Math.atan2(dy, dx);
2779
- particle.velocity.angle = particle.direction;
2780
- }
2781
- particle.justWarped = true;
2782
- break;
2783
- }
2784
- case ParticleOutType.normal: {
2785
- const warp = particle.options.move.warp, canvasSize = container.canvas.size, newPos = {
2786
- bottom: canvasSize.height + particle.getRadius() + particle.offset.y,
2787
- left: -particle.getRadius() - particle.offset.x,
2788
- right: canvasSize.width + particle.getRadius() + particle.offset.x,
2789
- top: -particle.getRadius() - particle.offset.y,
2790
- }, sizeValue = particle.getRadius(), nextBounds = calculateBounds(particle.position, sizeValue);
2791
- if (direction === OutModeDirection.right && nextBounds.left > canvasSize.width + particle.offset.x) {
2792
- particle.position.x = newPos.left;
2793
- particle.initialPosition.x = particle.position.x;
2794
- if (!warp) {
2795
- particle.position.y = getRandom() * canvasSize.height;
2796
- particle.initialPosition.y = particle.position.y;
2797
- }
2798
- particle.justWarped = true;
2799
- }
2800
- else if (direction === OutModeDirection.left && nextBounds.right < -particle.offset.x) {
2801
- particle.position.x = newPos.right;
2802
- particle.initialPosition.x = particle.position.x;
2803
- if (!warp) {
2804
- particle.position.y = getRandom() * canvasSize.height;
2805
- particle.initialPosition.y = particle.position.y;
2806
- }
2807
- particle.justWarped = true;
2808
- }
2809
- if (direction === OutModeDirection.bottom && nextBounds.top > canvasSize.height + particle.offset.y) {
2810
- if (!warp) {
2811
- particle.position.x = getRandom() * canvasSize.width;
2812
- particle.initialPosition.x = particle.position.x;
2813
- }
2814
- particle.position.y = newPos.top;
2815
- particle.initialPosition.y = particle.position.y;
2816
- particle.justWarped = true;
2817
- }
2818
- else if (direction === OutModeDirection.top && nextBounds.bottom < -particle.offset.y) {
2819
- if (!warp) {
2820
- particle.position.x = getRandom() * canvasSize.width;
2821
- particle.initialPosition.x = particle.position.x;
2822
- }
2823
- particle.position.y = newPos.bottom;
2824
- particle.initialPosition.y = particle.position.y;
2825
- particle.justWarped = true;
2826
- }
2827
- break;
2828
- }
2829
- }
2830
- break;
2924
+ if (particle.outType === ParticleOutType.outside) {
2925
+ this.#applyParticleModeOutside(particle);
2831
2926
  }
2832
- }
2927
+ else {
2928
+ this.#applyOutModeNormal(particle, container, direction);
2929
+ }
2930
+ }
2931
+ }
2932
+ #applyOutModeInside(particle, container) {
2933
+ const { x: vx, y: vy } = particle.velocity;
2934
+ updateVector.setTo(originPoint);
2935
+ updateVector.length = particle.moveCenter.radius;
2936
+ updateVector.angle = particle.velocity.angle + Math.PI;
2937
+ updateVector.addTo(particle.moveCenter);
2938
+ const { dx, dy } = getDistances(particle.position, updateVector);
2939
+ if ((vx <= minVelocity && dx >= minDistance$2) ||
2940
+ (vy <= minVelocity && dy >= minDistance$2) ||
2941
+ (vx >= minVelocity && dx <= minDistance$2) ||
2942
+ (vy >= minVelocity && dy <= minDistance$2)) {
2943
+ return;
2944
+ }
2945
+ particle.position.x = Math.floor(randomInRangeValue({
2946
+ min: 0,
2947
+ max: container.canvas.size.width,
2948
+ }));
2949
+ particle.position.y = Math.floor(randomInRangeValue({
2950
+ min: 0,
2951
+ max: container.canvas.size.height,
2952
+ }));
2953
+ const { dx: newDx, dy: newDy } = getDistances(particle.position, particle.moveCenter);
2954
+ particle.direction = Math.atan2(-newDy, -newDx);
2955
+ particle.velocity.angle = particle.direction;
2956
+ particle.justWarped = true;
2957
+ }
2958
+ #applyOutModeNormal(particle, container, direction) {
2959
+ const warp = particle.options.move.warp, canvasSize = container.canvas.size, sizeValue = particle.getRadius(), newPos = {
2960
+ bottom: canvasSize.height + sizeValue + particle.offset.y,
2961
+ left: -sizeValue - particle.offset.x,
2962
+ right: canvasSize.width + sizeValue + particle.offset.x,
2963
+ top: -sizeValue - particle.offset.y,
2964
+ }, nextBounds = calculateBounds(particle.position, sizeValue);
2965
+ if (direction === OutModeDirection.right && nextBounds.left > canvasSize.width + particle.offset.x) {
2966
+ particle.position.x = newPos.left;
2967
+ particle.initialPosition.x = particle.position.x;
2968
+ if (!warp) {
2969
+ particle.position.y = getRandom() * canvasSize.height;
2970
+ particle.initialPosition.y = particle.position.y;
2971
+ }
2972
+ particle.justWarped = true;
2973
+ }
2974
+ else if (direction === OutModeDirection.left && nextBounds.right < -particle.offset.x) {
2975
+ particle.position.x = newPos.right;
2976
+ particle.initialPosition.x = particle.position.x;
2977
+ if (!warp) {
2978
+ particle.position.y = getRandom() * canvasSize.height;
2979
+ particle.initialPosition.y = particle.position.y;
2980
+ }
2981
+ particle.justWarped = true;
2982
+ }
2983
+ if (direction === OutModeDirection.bottom && nextBounds.top > canvasSize.height + particle.offset.y) {
2984
+ if (!warp) {
2985
+ particle.position.x = getRandom() * canvasSize.width;
2986
+ particle.initialPosition.x = particle.position.x;
2987
+ }
2988
+ particle.position.y = newPos.top;
2989
+ particle.initialPosition.y = particle.position.y;
2990
+ particle.justWarped = true;
2991
+ }
2992
+ else if (direction === OutModeDirection.top && nextBounds.bottom < -particle.offset.y) {
2993
+ if (!warp) {
2994
+ particle.position.x = getRandom() * canvasSize.width;
2995
+ particle.initialPosition.x = particle.position.x;
2996
+ }
2997
+ particle.position.y = newPos.bottom;
2998
+ particle.initialPosition.y = particle.position.y;
2999
+ particle.justWarped = true;
3000
+ }
3001
+ }
3002
+ #applyParticleModeOutside(particle) {
3003
+ particle.position.x =
3004
+ Math.floor(randomInRangeValue({
3005
+ min: -particle.moveCenter.radius,
3006
+ max: particle.moveCenter.radius,
3007
+ })) + particle.moveCenter.x;
3008
+ particle.position.y =
3009
+ Math.floor(randomInRangeValue({
3010
+ min: -particle.moveCenter.radius,
3011
+ max: particle.moveCenter.radius,
3012
+ })) + particle.moveCenter.y;
3013
+ const { dx, dy } = getDistances(particle.position, particle.moveCenter);
3014
+ if (particle.moveCenter.radius) {
3015
+ particle.direction = Math.atan2(dy, dx);
3016
+ particle.velocity.angle = particle.direction;
3017
+ }
3018
+ particle.justWarped = true;
2833
3019
  }
2834
3020
  }
2835
3021
 
@@ -2878,7 +3064,7 @@
2878
3064
  }
2879
3065
 
2880
3066
  async function loadOutModesUpdater(engine) {
2881
- engine.checkVersion("4.3.2");
3067
+ engine.checkVersion("4.5.0");
2882
3068
  await engine.pluginManager.register(e => {
2883
3069
  e.pluginManager.addParticleUpdater("outModes", container => {
2884
3070
  return Promise.resolve(new OutOfCanvasUpdater(container));
@@ -2895,39 +3081,9 @@
2895
3081
  this.#pluginManager = pluginManager;
2896
3082
  }
2897
3083
  init(particle) {
2898
- const container = this.#container, options = particle.options, paint = itemFromSingleOrMultiple(options.paint, particle.id, options.reduceDuplicates), color = paint?.color, paintColor = color ?? undefined, fill = paint?.fill, stroke = paint?.stroke;
2899
- if (fill) {
2900
- const fillColor = AnimatableColor.create(paintColor === undefined ? undefined : AnimatableColor.create(undefined, paintColor), fill.color);
2901
- particle.fillEnabled = fill.enable;
2902
- particle.fillOpacity = getRangeValue(fill.opacity);
2903
- particle.fillAnimation = fillColor.animation;
2904
- const fillHslColor = rangeColorToHsl(this.#pluginManager, fillColor);
2905
- if (fillHslColor) {
2906
- particle.fillColor = getHslAnimationFromHsl(fillHslColor, particle.fillAnimation, container.retina.reduceFactor);
2907
- }
2908
- }
2909
- else {
2910
- particle.fillEnabled = false;
2911
- particle.fillAnimation = undefined;
2912
- particle.fillColor = undefined;
2913
- particle.fillOpacity = defaultOpacity;
2914
- }
2915
- if (stroke) {
2916
- const strokeColor = AnimatableColor.create(paintColor === undefined ? undefined : AnimatableColor.create(undefined, paintColor), stroke.color);
2917
- particle.strokeWidth = getRangeValue(stroke.width) * container.retina.pixelRatio;
2918
- particle.strokeOpacity = getRangeValue(stroke.opacity ?? defaultOpacity);
2919
- particle.strokeAnimation = strokeColor.animation;
2920
- const strokeHslColor = rangeColorToHsl(this.#pluginManager, strokeColor) ?? particle.getFillColor();
2921
- if (strokeHslColor) {
2922
- particle.strokeColor = getHslAnimationFromHsl(strokeHslColor, particle.strokeAnimation, container.retina.reduceFactor);
2923
- }
2924
- }
2925
- else {
2926
- particle.strokeAnimation = undefined;
2927
- particle.strokeColor = undefined;
2928
- particle.strokeOpacity = defaultOpacity;
2929
- particle.strokeWidth = 0;
2930
- }
3084
+ const container = this.#container, options = particle.options, paint = itemFromSingleOrMultiple(options.paint, particle.id, options.reduceDuplicates);
3085
+ this.#initFill(paint, particle, container);
3086
+ this.#initStroke(paint, particle, container);
2931
3087
  }
2932
3088
  isEnabled(particle) {
2933
3089
  const { fillAnimation, fillColor, strokeAnimation, strokeColor } = particle, fillEnabled = !!fillAnimation &&
@@ -2946,10 +3102,48 @@
2946
3102
  updateColor(particle.fillColor, delta, this.#container.hdr);
2947
3103
  updateColor(particle.strokeColor, delta, this.#container.hdr);
2948
3104
  }
3105
+ #initFill(paint, particle, container) {
3106
+ const fill = paint?.fill, color = paint?.color, paintColor = color ?? undefined;
3107
+ if (!fill) {
3108
+ particle.fillEnabled = false;
3109
+ particle.fillAnimation = undefined;
3110
+ particle.fillColor = undefined;
3111
+ particle.fillOpacity = defaultOpacity;
3112
+ return;
3113
+ }
3114
+ const fillColor = AnimatableColor.create(paintColor === undefined ? undefined : AnimatableColor.create(undefined, paintColor), fill.color);
3115
+ particle.fillEnabled = fill.enable;
3116
+ particle.fillOpacity = getRangeValue(fill.opacity);
3117
+ particle.fillAnimation = fillColor.animation;
3118
+ const fillHslColor = rangeColorToHsl(this.#pluginManager, fillColor);
3119
+ if (!fillHslColor) {
3120
+ return;
3121
+ }
3122
+ particle.fillColor = getHslAnimationFromHsl(fillHslColor, particle.fillAnimation, container.retina.reduceFactor);
3123
+ }
3124
+ #initStroke(paint, particle, container) {
3125
+ const stroke = paint?.stroke, color = paint?.color, paintColor = color ?? undefined;
3126
+ if (!stroke) {
3127
+ particle.strokeAnimation = undefined;
3128
+ particle.strokeColor = undefined;
3129
+ particle.strokeOpacity = defaultOpacity;
3130
+ particle.strokeWidth = 0;
3131
+ return;
3132
+ }
3133
+ const strokeColor = AnimatableColor.create(paintColor === undefined ? undefined : AnimatableColor.create(undefined, paintColor), stroke.color);
3134
+ particle.strokeWidth = getRangeValue(stroke.width) * container.retina.pixelRatio;
3135
+ particle.strokeOpacity = getRangeValue(stroke.opacity ?? defaultOpacity);
3136
+ particle.strokeAnimation = strokeColor.animation;
3137
+ const strokeHslColor = rangeColorToHsl(this.#pluginManager, strokeColor) ?? particle.getFillColor();
3138
+ if (!strokeHslColor) {
3139
+ return;
3140
+ }
3141
+ particle.strokeColor = getHslAnimationFromHsl(strokeHslColor, particle.strokeAnimation, container.retina.reduceFactor);
3142
+ }
2949
3143
  }
2950
3144
 
2951
3145
  async function loadPaintUpdater(engine) {
2952
- engine.checkVersion("4.3.2");
3146
+ engine.checkVersion("4.5.0");
2953
3147
  await engine.pluginManager.register(e => {
2954
3148
  e.pluginManager.addParticleUpdater("paint", container => {
2955
3149
  return Promise.resolve(new PaintUpdater(e.pluginManager, container));
@@ -2991,7 +3185,7 @@
2991
3185
  if (!this.accepts(input)) {
2992
3186
  return;
2993
3187
  }
2994
- const result = rgbRegex.exec(input), radix = 10, minLength = 4, defaultAlpha = 1;
3188
+ const result = rgbRegex.exec(input), radix = 10, minLength = 4;
2995
3189
  return result
2996
3190
  ? {
2997
3191
  a: result.length > minLength ? parseAlpha(result[RgbIndexes.a]) : defaultAlpha,
@@ -3004,7 +3198,7 @@
3004
3198
  }
3005
3199
 
3006
3200
  async function loadRgbColorPlugin(engine) {
3007
- engine.checkVersion("4.3.2");
3201
+ engine.checkVersion("4.5.0");
3008
3202
  await engine.pluginManager.register(e => {
3009
3203
  e.pluginManager.addColorManager("rgb", new RgbColorManager());
3010
3204
  });
@@ -3089,7 +3283,7 @@
3089
3283
  }
3090
3284
 
3091
3285
  async function loadSizeUpdater(engine) {
3092
- engine.checkVersion("4.3.2");
3286
+ engine.checkVersion("4.5.0");
3093
3287
  await engine.pluginManager.register(e => {
3094
3288
  e.pluginManager.addParticleUpdater("size", container => {
3095
3289
  return Promise.resolve(new SizeUpdater(container));
@@ -3098,7 +3292,7 @@
3098
3292
  }
3099
3293
 
3100
3294
  async function loadBasic(engine) {
3101
- engine.checkVersion("4.3.2");
3295
+ engine.checkVersion("4.5.0");
3102
3296
  await engine.pluginManager.register(async (e) => {
3103
3297
  await Promise.all([
3104
3298
  loadBlendPlugin(e),
@@ -3115,6 +3309,16 @@
3115
3309
  });
3116
3310
  }
3117
3311
 
3312
+ const ErrorCodes = {
3313
+ interactivityPluginNotLoaded: "TSP-3201",
3314
+ interactivityClickHandlerNotSet: "TSP-3202",
3315
+ };
3316
+
3317
+ const ErrorMessages = {
3318
+ [ErrorCodes.interactivityPluginNotLoaded]: "tsParticles Interactivity Plugin is not loaded",
3319
+ [ErrorCodes.interactivityClickHandlerNotSet]: "Click handlers can only be set after calling tsParticles.load()",
3320
+ };
3321
+
3118
3322
  class ClickEvent {
3119
3323
  enable = false;
3120
3324
  mode = [];
@@ -3191,9 +3395,7 @@
3191
3395
 
3192
3396
  class Modes {
3193
3397
  #container;
3194
- #pluginManager;
3195
- constructor(pluginManager, container) {
3196
- this.#pluginManager = pluginManager;
3398
+ constructor(container) {
3197
3399
  this.#container = container;
3198
3400
  }
3199
3401
  load(data) {
@@ -3203,10 +3405,7 @@
3203
3405
  if (!this.#container) {
3204
3406
  return;
3205
3407
  }
3206
- const interactors = this.#pluginManager.interactors?.get(this.#container);
3207
- if (!interactors) {
3208
- return;
3209
- }
3408
+ const interactors = this.#container.interactionManager?.interactors ?? [];
3210
3409
  for (const interactor of interactors) {
3211
3410
  if (!interactor.loadModeOptions) {
3212
3411
  continue;
@@ -3220,8 +3419,8 @@
3220
3419
  detectsOn = InteractivityDetect.window;
3221
3420
  events = new Events();
3222
3421
  modes;
3223
- constructor(pluginManager, container) {
3224
- this.modes = new Modes(pluginManager, container);
3422
+ constructor(container) {
3423
+ this.modes = new Modes(container);
3225
3424
  }
3226
3425
  load(data) {
3227
3426
  if (isNull(data)) {
@@ -3252,10 +3451,10 @@
3252
3451
  }
3253
3452
  let interactivityOptions = options.interactivity;
3254
3453
  if (!interactivityOptions?.load) {
3255
- options.interactivity = interactivityOptions = new Interactivity(this.#pluginManager, container);
3454
+ options.interactivity = interactivityOptions = new Interactivity(container);
3256
3455
  }
3257
3456
  interactivityOptions.load(source?.interactivity);
3258
- const interactors = this.#pluginManager.interactors?.get(container);
3457
+ const interactors = container.interactionManager?.interactors;
3259
3458
  if (!interactors) {
3260
3459
  return;
3261
3460
  }
@@ -3269,7 +3468,7 @@
3269
3468
  if (source?.interactivity) {
3270
3469
  options.interactivity = deepExtend({}, source.interactivity);
3271
3470
  }
3272
- const interactors = this.#pluginManager.interactors?.get(container);
3471
+ const interactors = container.interactionManager?.interactors;
3273
3472
  if (!interactors) {
3274
3473
  return;
3275
3474
  }
@@ -3299,25 +3498,25 @@
3299
3498
  const clickEvent = "click", mouseDownEvent = "pointerdown", mouseUpEvent = "pointerup", mouseLeaveEvent = "pointerleave", mouseMoveEvent = "pointermove", touchStartEvent = "touchstart", touchEndEvent = "touchend", touchMoveEvent = "touchmove", touchCancelEvent = "touchcancel";
3300
3499
 
3301
3500
  async function loadInteractivityPlugin(engine) {
3302
- engine.checkVersion("4.3.2");
3501
+ engine.checkVersion("4.5.0");
3502
+ if (typeof process !== "undefined" && process.env.NODE_ENV !== "production") {
3503
+ addErrorMessages(ErrorMessages);
3504
+ }
3303
3505
  await engine.pluginManager.register(e => {
3304
3506
  const interactivityEngine = e, interactivityPluginManager = interactivityEngine.pluginManager;
3305
3507
  interactivityPluginManager.addPlugin(new InteractivityPlugin(interactivityPluginManager));
3306
3508
  interactivityPluginManager.initializers.interactors ??= new Map();
3307
- interactivityPluginManager.interactors ??= new Map();
3308
3509
  interactivityPluginManager.addInteractor = (name, interactorInitializer) => {
3510
+ if (interactivityPluginManager.initialized) {
3511
+ return;
3512
+ }
3309
3513
  interactivityPluginManager.initializers.interactors ??= new Map();
3310
3514
  interactivityPluginManager.initializers.interactors.set(name, interactorInitializer);
3311
3515
  };
3312
- interactivityPluginManager.getInteractors = async (container, force = false) => {
3313
- interactivityPluginManager.interactors ??= new Map();
3314
- interactivityPluginManager.initializers.interactors ??= new Map();
3315
- return getItemsFromInitializer(container, interactivityPluginManager.interactors, interactivityPluginManager.initializers.interactors, force);
3316
- };
3317
3516
  interactivityPluginManager.setOnClickHandler = (callback) => {
3318
3517
  const { items } = interactivityEngine;
3319
3518
  if (!items.length) {
3320
- throw new Error("Click handlers can only be set after calling tsParticles.load()");
3519
+ throw new Error(getErrorMessage(ErrorCodes.interactivityClickHandlerNotSet));
3321
3520
  }
3322
3521
  items.forEach(item => {
3323
3522
  const interactivityContainer = item;
@@ -3328,7 +3527,7 @@
3328
3527
  }
3329
3528
  function ensureInteractivityPluginLoaded(e) {
3330
3529
  if (!e.pluginManager.addInteractor) {
3331
- throw new Error("tsParticles Interactivity Plugin is not loaded");
3530
+ throw new Error(getErrorMessage(ErrorCodes.interactivityPluginNotLoaded));
3332
3531
  }
3333
3532
  }
3334
3533
 
@@ -3535,7 +3734,7 @@
3535
3734
  const linkColor = linksOptions.id !== undefined
3536
3735
  ? container.particles.linksColors.get(linksOptions.id)
3537
3736
  : container.particles.linksColor;
3538
- return getLinkColor(p1, p2, linkColor);
3737
+ return getLinkColor(p1, p2, linkColor, container.hdr);
3539
3738
  }
3540
3739
  #setColor(p1) {
3541
3740
  if (!p1.options.links) {
@@ -3576,7 +3775,7 @@
3576
3775
  }
3577
3776
 
3578
3777
  async function loadParticlesLinksInteraction(engine) {
3579
- engine.checkVersion("4.3.2");
3778
+ engine.checkVersion("4.5.0");
3580
3779
  await engine.pluginManager.register((e) => {
3581
3780
  const pluginManager = e.pluginManager;
3582
3781
  ensureInteractivityPluginLoaded(e);
@@ -3699,21 +3898,28 @@
3699
3898
  });
3700
3899
  }
3701
3900
  clear() {
3901
+ const visited = new Set();
3702
3902
  for (const plugin of this.#canvasClearPlugins) {
3903
+ visited.add(plugin);
3703
3904
  if (plugin.canvasClear?.() ?? false) {
3704
- return;
3905
+ return plugin;
3705
3906
  }
3706
3907
  }
3707
3908
  for (const layer of Object.values(DrawLayer)) {
3708
3909
  if (typeof layer === "number") {
3709
3910
  for (const plugin of this.#getLayerPlugins(layer)) {
3911
+ if (visited.has(plugin)) {
3912
+ continue;
3913
+ }
3914
+ visited.add(plugin);
3710
3915
  if (plugin.canvasClear?.() ?? false) {
3711
- return;
3916
+ return plugin;
3712
3917
  }
3713
3918
  }
3714
3919
  }
3715
3920
  }
3716
3921
  this.canvasClear();
3922
+ return undefined;
3717
3923
  }
3718
3924
  destroy() {
3719
3925
  this.stop();
@@ -3754,7 +3960,11 @@
3754
3960
  if (!fColor && !sColor) {
3755
3961
  return;
3756
3962
  }
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;
3963
+ 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
3964
+ ? getStyleFromHsl(fColor, container.hdr, fillOpacity * opacity, container.peakNits, container.hdrMode)
3965
+ : undefined, stroke = sColor
3966
+ ? getStyleFromHsl(sColor, container.hdr, strokeOpacity * opacity, container.peakNits, container.hdrMode)
3967
+ : fill;
3758
3968
  transform.a = transform.b = transform.c = transform.d = undefined;
3759
3969
  colorStyles.fill = fill;
3760
3970
  colorStyles.stroke = stroke;
@@ -3787,8 +3997,7 @@
3787
3997
  });
3788
3998
  }
3789
3999
  drawParticles(delta) {
3790
- const { particles, actualOptions } = this.#container;
3791
- this.clear();
4000
+ const { particles, actualOptions } = this.#container, clearedPlugin = this.clear();
3792
4001
  particles.update(delta);
3793
4002
  this.draw(ctx => {
3794
4003
  const width = this.#canvasManager.size.width, height = this.#canvasManager.size.height;
@@ -3810,7 +4019,9 @@
3810
4019
  }
3811
4020
  }
3812
4021
  for (const plugin of this.#getLayerPlugins(DrawLayer.BackgroundMask)) {
3813
- plugin.canvasPaint?.();
4022
+ if (plugin !== clearedPlugin) {
4023
+ plugin.canvasPaint?.();
4024
+ }
3814
4025
  }
3815
4026
  for (const plugin of this.#getLayerPlugins(DrawLayer.CanvasSetup)) {
3816
4027
  plugin.drawSettingsSetup?.(ctx, delta);
@@ -3829,48 +4040,20 @@
3829
4040
  this.initUpdaters();
3830
4041
  this.initPlugins();
3831
4042
  this.#resolveBackgroundElement();
3832
- this.paint();
3833
- }
3834
- initPlugins() {
3835
- this.#canvasClearPlugins = [];
3836
- this.#colorPlugins = [];
3837
- this.#drawParticlePlugins = [];
3838
- this.#drawParticlesSetupPlugins = [];
3839
- this.#drawParticlesCleanupPlugins = [];
3840
- for (const layer of Object.values(DrawLayer)) {
3841
- if (typeof layer === "number") {
3842
- this.#layers[layer] = [];
3843
- }
3844
- }
3845
- for (const plugin of this.#container.plugins) {
3846
- if (plugin.particleFillColor ?? plugin.particleStrokeColor) {
3847
- this.#colorPlugins.push(plugin);
3848
- }
3849
- if (plugin.drawParticle) {
3850
- this.#drawParticlePlugins.push(plugin);
3851
- }
3852
- if (plugin.drawParticleSetup) {
3853
- this.#drawParticlesSetupPlugins.push(plugin);
3854
- }
3855
- if (plugin.drawParticleCleanup) {
3856
- this.#drawParticlesCleanupPlugins.push(plugin);
3857
- }
3858
- if (plugin.canvasClear) {
3859
- this.#canvasClearPlugins.push(plugin);
3860
- }
3861
- if (plugin.canvasPaint) {
3862
- this.#getLayerPlugins(DrawLayer.BackgroundMask).push(plugin);
3863
- }
3864
- if (plugin.drawSettingsSetup) {
3865
- this.#getLayerPlugins(DrawLayer.CanvasSetup).push(plugin);
3866
- }
3867
- if (plugin.draw) {
3868
- this.#getLayerPlugins(DrawLayer.PluginContent).push(plugin);
3869
- }
3870
- if (plugin.clearDraw ?? plugin.drawSettingsCleanup) {
3871
- this.#getLayerPlugins(DrawLayer.CanvasCleanup).push(plugin);
4043
+ this.paint();
4044
+ }
4045
+ initPlugins() {
4046
+ this.#canvasClearPlugins = [];
4047
+ this.#colorPlugins = [];
4048
+ this.#drawParticlePlugins = [];
4049
+ this.#drawParticlesSetupPlugins = [];
4050
+ this.#drawParticlesCleanupPlugins = [];
4051
+ for (const layer of Object.values(DrawLayer)) {
4052
+ if (typeof layer === "number") {
4053
+ this.#layers[layer] = [];
3872
4054
  }
3873
4055
  }
4056
+ this.#initPluginsArray();
3874
4057
  }
3875
4058
  initUpdaters() {
3876
4059
  this.#preDrawUpdaters = [];
@@ -4079,6 +4262,45 @@
4079
4262
  this.#reusablePluginColors[sColorIndex] = sColor;
4080
4263
  return this.#reusablePluginColors;
4081
4264
  }
4265
+ #initLayerPlugin(plugin) {
4266
+ const layerMap = [
4267
+ [DrawLayer.BackgroundMask, !!plugin.canvasPaint],
4268
+ [DrawLayer.CanvasSetup, !!plugin.drawSettingsSetup],
4269
+ [DrawLayer.PluginContent, !!plugin.draw],
4270
+ [DrawLayer.CanvasCleanup, !!(plugin.clearDraw ?? plugin.drawSettingsCleanup)],
4271
+ ];
4272
+ for (const [layer, active] of layerMap) {
4273
+ if (active) {
4274
+ this.#layers[layer].push(plugin);
4275
+ }
4276
+ }
4277
+ }
4278
+ #initPluginsArray() {
4279
+ for (const plugin of this.#container.plugins) {
4280
+ if (plugin.particleFillColor ?? plugin.particleStrokeColor) {
4281
+ this.#colorPlugins.push(plugin);
4282
+ }
4283
+ if (plugin.drawParticle) {
4284
+ this.#drawParticlePlugins.push(plugin);
4285
+ }
4286
+ if (plugin.drawParticleSetup) {
4287
+ this.#drawParticlesSetupPlugins.push(plugin);
4288
+ }
4289
+ if (plugin.drawParticleCleanup) {
4290
+ this.#drawParticlesCleanupPlugins.push(plugin);
4291
+ }
4292
+ if (plugin.canvasClear) {
4293
+ this.#canvasClearPlugins.push(plugin);
4294
+ }
4295
+ this.#initLayerPlugin(plugin);
4296
+ }
4297
+ }
4298
+ #isSupportedElement(element) {
4299
+ return ((typeof HTMLCanvasElement !== "undefined" && element instanceof HTMLCanvasElement) ||
4300
+ (typeof OffscreenCanvas !== "undefined" && element instanceof OffscreenCanvas) ||
4301
+ (typeof HTMLVideoElement !== "undefined" && element instanceof HTMLVideoElement) ||
4302
+ (typeof HTMLImageElement !== "undefined" && element instanceof HTMLImageElement));
4303
+ }
4082
4304
  #resolveBackgroundElement() {
4083
4305
  const background = this.#container.actualOptions.background;
4084
4306
  this.#backgroundElement = null;
@@ -4088,7 +4310,7 @@
4088
4310
  if (typeof background.element === "string") {
4089
4311
  if (typeof document !== "undefined") {
4090
4312
  const node = document.querySelector(background.element);
4091
- if (node instanceof HTMLCanvasElement || node instanceof HTMLVideoElement || node instanceof HTMLImageElement) {
4313
+ if (node && this.#isSupportedElement(node)) {
4092
4314
  this.#backgroundElement = node;
4093
4315
  }
4094
4316
  else if (node) {
@@ -4099,10 +4321,7 @@
4099
4321
  }
4100
4322
  }
4101
4323
  }
4102
- else if (background.element instanceof HTMLCanvasElement ||
4103
- background.element instanceof OffscreenCanvas ||
4104
- background.element instanceof HTMLVideoElement ||
4105
- background.element instanceof HTMLImageElement) {
4324
+ else if (this.#isSupportedElement(background.element)) {
4106
4325
  this.#backgroundElement = background.element;
4107
4326
  }
4108
4327
  }
@@ -4120,7 +4339,7 @@
4120
4339
  return transferredCanvas;
4121
4340
  }
4122
4341
  if (typeof canvas.transferControlToOffscreen !== "function") {
4123
- throw new TypeError("OffscreenCanvas is required but not supported by this browser");
4342
+ throw new TypeError(getErrorMessage(ErrorCodes$2.offscreenCanvasUnsupported));
4124
4343
  }
4125
4344
  try {
4126
4345
  const offscreenCanvas = canvas.transferControlToOffscreen();
@@ -4128,10 +4347,16 @@
4128
4347
  return offscreenCanvas;
4129
4348
  }
4130
4349
  catch {
4131
- throw new TypeError("OffscreenCanvas transfer failed");
4350
+ throw new TypeError(getErrorMessage(ErrorCodes$2.offscreenCanvasTransferFailed));
4132
4351
  }
4133
4352
  }, isHtmlCanvasElement = (canvas) => {
4134
4353
  return typeof HTMLCanvasElement !== "undefined" && canvas instanceof HTMLCanvasElement;
4354
+ }, getEffectiveColorSpace = (context) => {
4355
+ if (!context) {
4356
+ return undefined;
4357
+ }
4358
+ const colorInfo = context;
4359
+ return colorInfo.getContextAttributes?.().colorSpace ?? undefined;
4135
4360
  };
4136
4361
  function setStyle(canvas, style, important = false) {
4137
4362
  if (!style) {
@@ -4170,6 +4395,7 @@
4170
4395
  zoom = defaultZoom;
4171
4396
  #container;
4172
4397
  #generated;
4398
+ #hdrMediaListeners;
4173
4399
  #mutationObserver;
4174
4400
  #originalStyle;
4175
4401
  #pluginManager;
@@ -4234,7 +4460,6 @@
4234
4460
  });
4235
4461
  this.resize();
4236
4462
  this.#initStyle();
4237
- this.initBackground();
4238
4463
  this.#safeMutationObserver(obs => {
4239
4464
  const element = this.domElement;
4240
4465
  if (!element || !(element instanceof Node)) {
@@ -4244,6 +4469,8 @@
4244
4469
  });
4245
4470
  this.initPlugins();
4246
4471
  this.#initContext();
4472
+ this.initBackground();
4473
+ this.#initHdrListeners();
4247
4474
  this.render.init();
4248
4475
  }
4249
4476
  initBackground() {
@@ -4253,7 +4480,8 @@
4253
4480
  }
4254
4481
  const elementStyle = element.style, color = rangeColorToRgb(this.#pluginManager, background.color);
4255
4482
  if (color) {
4256
- elementStyle.backgroundColor = getStyleFromRgb(color, container.actualOptions.hdr, background.opacity);
4483
+ const hdrOptions = container.actualOptions.hdr;
4484
+ elementStyle.backgroundColor = getStyleFromRgb(color, container.hdr, background.opacity, hdrOptions.peakNits, toEnumValue(HdrMode, hdrOptions.mode, HdrMode.standard));
4257
4485
  }
4258
4486
  else {
4259
4487
  elementStyle.backgroundColor = "";
@@ -4350,6 +4578,7 @@
4350
4578
  obs.disconnect();
4351
4579
  });
4352
4580
  this.#mutationObserver = undefined;
4581
+ this.#removeHdrListeners();
4353
4582
  this.render.stop();
4354
4583
  }
4355
4584
  async windowResize() {
@@ -4369,9 +4598,16 @@
4369
4598
  }
4370
4599
  }
4371
4600
  #initContext() {
4372
- const container = this.#container, canSupportHdr = container.actualOptions.hdr &&
4601
+ const container = this.#container, canSupportHdr = container.actualOptions.hdr.enable &&
4373
4602
  safeMatchMedia("(color-gamut: p3)")?.matches &&
4374
4603
  safeMatchMedia("(dynamic-range: high)")?.matches;
4604
+ container.hdrMode = toEnumValue(HdrMode, container.actualOptions.hdr.mode, HdrMode.standard);
4605
+ container.peakNits = container.actualOptions.hdr.peakNits;
4606
+ const renderCanvas = this.renderCanvas;
4607
+ if (!renderCanvas) {
4608
+ container.hdr = canSupportHdr ?? false;
4609
+ return;
4610
+ }
4375
4611
  this.render.setContextSettings({
4376
4612
  alpha: true,
4377
4613
  desynchronized: true,
@@ -4380,11 +4616,51 @@
4380
4616
  ? { colorSpace: "display-p3", colorType: "float16" }
4381
4617
  : { colorSpace: "srgb" }),
4382
4618
  });
4383
- const renderCanvas = this.renderCanvas;
4384
- if (!renderCanvas) {
4385
- return;
4619
+ let context;
4620
+ try {
4621
+ context = renderCanvas.getContext("2d", this.render.settings);
4622
+ }
4623
+ catch {
4624
+ context = null;
4625
+ }
4626
+ if (canSupportHdr && !context) {
4627
+ const sdrSettings = {
4628
+ alpha: true,
4629
+ desynchronized: true,
4630
+ willReadFrequently: false,
4631
+ colorSpace: "srgb",
4632
+ };
4633
+ this.render.setContextSettings(sdrSettings);
4634
+ try {
4635
+ context = renderCanvas.getContext("2d", sdrSettings);
4636
+ }
4637
+ catch {
4638
+ context = null;
4639
+ }
4640
+ }
4641
+ this.render.setContext(context);
4642
+ if (context) {
4643
+ const effectiveColorSpace = getEffectiveColorSpace(context);
4644
+ if (effectiveColorSpace !== undefined) {
4645
+ container.hdr = effectiveColorSpace === "display-p3";
4646
+ }
4647
+ }
4648
+ }
4649
+ #initHdrListeners() {
4650
+ this.#removeHdrListeners();
4651
+ const p3Query = safeMatchMedia("(color-gamut: p3)"), hdrQuery = safeMatchMedia("(dynamic-range: high)"), handleChange = () => {
4652
+ this.#initContext();
4653
+ this.initBackground();
4654
+ }, listeners = [];
4655
+ if (p3Query) {
4656
+ p3Query.addEventListener("change", handleChange);
4657
+ listeners.push({ handler: handleChange, mql: p3Query });
4658
+ }
4659
+ if (hdrQuery) {
4660
+ hdrQuery.addEventListener("change", handleChange);
4661
+ listeners.push({ handler: handleChange, mql: hdrQuery });
4386
4662
  }
4387
- this.render.setContext(renderCanvas.getContext("2d", this.render.settings));
4663
+ this.#hdrMediaListeners = listeners;
4388
4664
  }
4389
4665
  #initStyle() {
4390
4666
  const element = this.domElement, options = this.#container.actualOptions;
@@ -4408,6 +4684,15 @@
4408
4684
  element.style.setProperty(key, value, "important");
4409
4685
  }
4410
4686
  }
4687
+ #removeHdrListeners() {
4688
+ if (!this.#hdrMediaListeners) {
4689
+ return;
4690
+ }
4691
+ for (const { handler, mql } of this.#hdrMediaListeners) {
4692
+ mql.removeEventListener("change", handler);
4693
+ }
4694
+ this.#hdrMediaListeners = undefined;
4695
+ }
4411
4696
  #repairStyle() {
4412
4697
  const element = this.domElement;
4413
4698
  if (!element) {
@@ -4497,8 +4782,7 @@
4497
4782
  this.#resizeTimeout = undefined;
4498
4783
  }
4499
4784
  const handleResize = async () => {
4500
- const canvas = this.#container.canvas;
4501
- await canvas.windowResize();
4785
+ await this.#container.canvas.windowResize();
4502
4786
  };
4503
4787
  this.#resizeTimeout = setTimeout(() => void handleResize(), this.#container.actualOptions.resize.delay * millisecondsToSeconds);
4504
4788
  }
@@ -4526,8 +4810,8 @@
4526
4810
  }
4527
4811
  else if (!this.#resizeObserver && add && canvasEl) {
4528
4812
  this.#resizeObserver = new ResizeObserver((entries) => {
4529
- const entry = entries.find(e => e.target === canvasEl);
4530
- if (!entry) {
4813
+ const res = entries.some(e => e.target === canvasEl);
4814
+ if (!res) {
4531
4815
  return;
4532
4816
  }
4533
4817
  this.#handleWindowResize();
@@ -4791,10 +5075,10 @@
4791
5075
  return this.#modifiers.find(m => m.id === id);
4792
5076
  }
4793
5077
  getOpacity() {
4794
- 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;
5078
+ 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;
5079
+ this.#cachedOpacityData.fillOpacity = this.fillOpacity ?? defaultOpacity$1;
4796
5080
  this.#cachedOpacityData.opacity = opacity * zOpacityFactor;
4797
- this.#cachedOpacityData.strokeOpacity = opacity * strokeOpacity * zOpacityFactor;
5081
+ this.#cachedOpacityData.strokeOpacity = this.strokeOpacity ?? defaultOpacity$1;
4798
5082
  return this.#cachedOpacityData;
4799
5083
  }
4800
5084
  getPosition() {
@@ -5041,7 +5325,7 @@
5041
5325
  #initPosition(position) {
5042
5326
  const container = this.#container, zIndexValue = Math.floor(getRangeValue(this.options.zIndex.value)), initialPosition = this.#calcPosition(position, clamp(zIndexValue, minZ, container.zLayers));
5043
5327
  if (!initialPosition) {
5044
- throw new Error("a valid position cannot be found for particle");
5328
+ throw new Error(getErrorMessage(ErrorCodes$2.particlePositionNotFound));
5045
5329
  }
5046
5330
  this.position = initialPosition;
5047
5331
  this.initialPosition = this.position.copy();
@@ -5090,6 +5374,12 @@
5090
5374
  this.#circlePoolIdx = 0;
5091
5375
  this.#rectanglePoolIdx = 0;
5092
5376
  }
5377
+ get cellSize() {
5378
+ return this.#cellSize;
5379
+ }
5380
+ set cellSize(value) {
5381
+ this.#pendingCellSize = value;
5382
+ }
5093
5383
  clear() {
5094
5384
  this.#cells.clear();
5095
5385
  const pendingCellSize = this.#pendingCellSize;
@@ -5113,18 +5403,7 @@
5113
5403
  const minCellX = Math.floor(bounds.minX / this.#cellSize), maxCellX = Math.floor(bounds.maxX / this.#cellSize), minCellY = Math.floor(bounds.minY / this.#cellSize), maxCellY = Math.floor(bounds.maxY / this.#cellSize);
5114
5404
  for (let cx = minCellX; cx <= maxCellX; cx++) {
5115
5405
  for (let cy = minCellY; cy <= maxCellY; cy++) {
5116
- const key = `${cx}_${cy}`, cellParticles = this.#cells.get(key);
5117
- if (!cellParticles) {
5118
- continue;
5119
- }
5120
- for (const p of cellParticles) {
5121
- if (check && !check(p)) {
5122
- continue;
5123
- }
5124
- if (range.contains(p.getPosition())) {
5125
- out.push(p);
5126
- }
5127
- }
5406
+ this.#queryCell(cx, cy, range, check, out);
5128
5407
  }
5129
5408
  }
5130
5409
  return out;
@@ -5139,14 +5418,23 @@
5139
5418
  this.#releaseShapes();
5140
5419
  return result;
5141
5420
  }
5142
- setCellSize(cellSize) {
5143
- this.#pendingCellSize = cellSize;
5144
- }
5145
5421
  #acquireCircle(x, y, r) {
5146
- return (this.#circlePool[this.#circlePoolIdx++] ??= new Circle(x, y, r)).reset(x, y, r);
5422
+ const idx = this.#circlePoolIdx++;
5423
+ let circle = this.#circlePool[idx];
5424
+ if (!circle) {
5425
+ circle = new Circle(x, y, r);
5426
+ this.#circlePool[idx] = circle;
5427
+ }
5428
+ return circle.reset(x, y, r);
5147
5429
  }
5148
5430
  #acquireRectangle(x, y, w, h) {
5149
- return (this.#rectanglePool[this.#rectanglePoolIdx++] ??= new Rectangle(x, y, w, h)).reset(x, y, w, h);
5431
+ const idx = this.#rectanglePoolIdx++;
5432
+ let rectangle = this.#rectanglePool[idx];
5433
+ if (!rectangle) {
5434
+ rectangle = new Rectangle(x, y, w, h);
5435
+ this.#rectanglePool[idx] = rectangle;
5436
+ }
5437
+ return rectangle.reset(x, y, w, h);
5150
5438
  }
5151
5439
  #cellKeyFromCoords(x, y) {
5152
5440
  const cellX = Math.floor(x / this.#cellSize), cellY = Math.floor(y / this.#cellSize);
@@ -5173,6 +5461,20 @@
5173
5461
  }
5174
5462
  return null;
5175
5463
  }
5464
+ #queryCell(cx, cy, range, check, out) {
5465
+ const cellParticles = this.#cells.get(`${cx}_${cy}`);
5466
+ if (!cellParticles) {
5467
+ return;
5468
+ }
5469
+ for (const p of cellParticles) {
5470
+ if (check && !check(p)) {
5471
+ continue;
5472
+ }
5473
+ if (range.contains(p.getPosition())) {
5474
+ out.push(p);
5475
+ }
5476
+ }
5477
+ }
5176
5478
  #releaseShapes() {
5177
5479
  this.#circlePoolIdx = 0;
5178
5480
  this.#rectanglePoolIdx = 0;
@@ -5181,9 +5483,9 @@
5181
5483
 
5182
5484
  class ParticlesManager {
5183
5485
  checkParticlePositionPlugins;
5184
- grid;
5185
5486
  #array;
5186
5487
  #container;
5488
+ #grid;
5187
5489
  #groupLimits;
5188
5490
  #limit;
5189
5491
  #nextId;
@@ -5207,7 +5509,7 @@
5207
5509
  this.#groupLimits = new Map();
5208
5510
  this.#particleBuckets = new Map();
5209
5511
  this.#zBuckets = this.#createBuckets(this.#container.zLayers);
5210
- this.grid = new SpatialHashGrid(spatialHashGridCellSize);
5512
+ this.#grid = new SpatialHashGrid(spatialHashGridCellSize);
5211
5513
  this.checkParticlePositionPlugins = [];
5212
5514
  this.#particleResetPlugins = [];
5213
5515
  this.#particleUpdatePlugins = [];
@@ -5218,23 +5520,12 @@
5218
5520
  get count() {
5219
5521
  return this.#array.length;
5220
5522
  }
5523
+ get grid() {
5524
+ return this.#grid;
5525
+ }
5221
5526
  addParticle(position, overrideOptions, group, initializer) {
5222
- const limitMode = this.#container.actualOptions.particles.number.limit.mode, limit = group === undefined ? this.#limit : (this.#groupLimits.get(group) ?? this.#limit), currentCount = this.count;
5223
- if (limit > minLimit) {
5224
- switch (limitMode) {
5225
- case LimitMode.delete: {
5226
- const countToRemove = currentCount + countOffset - limit;
5227
- if (countToRemove > minCount) {
5228
- this.removeQuantity(countToRemove);
5229
- }
5230
- break;
5231
- }
5232
- case LimitMode.wait:
5233
- if (currentCount >= limit) {
5234
- return;
5235
- }
5236
- break;
5237
- }
5527
+ if (this.#checkAndApplyLimits(group, this.count)) {
5528
+ return;
5238
5529
  }
5239
5530
  try {
5240
5531
  const particle = this.#pool.pop() ?? new Particle(this.#pluginManager, this.#container);
@@ -5298,7 +5589,7 @@
5298
5589
  return this.#array[index];
5299
5590
  }
5300
5591
  async init() {
5301
- const container = this.#container, options = container.actualOptions;
5592
+ const container = this.#container;
5302
5593
  this.checkParticlePositionPlugins = [];
5303
5594
  this.#updatePlugins = [];
5304
5595
  this.#particleUpdatePlugins = [];
@@ -5307,59 +5598,16 @@
5307
5598
  this.#postParticleUpdatePlugins = [];
5308
5599
  this.#particleBuckets.clear();
5309
5600
  this.#resetBuckets(container.zLayers);
5310
- this.grid = new SpatialHashGrid(spatialHashGridCellSize * container.retina.pixelRatio);
5311
- for (const plugin of container.plugins) {
5312
- if (plugin.redrawInit) {
5313
- await plugin.redrawInit();
5314
- }
5315
- if (plugin.checkParticlePosition) {
5316
- this.checkParticlePositionPlugins.push(plugin);
5317
- }
5318
- if (plugin.update) {
5319
- this.#updatePlugins.push(plugin);
5320
- }
5321
- if (plugin.particleUpdate) {
5322
- this.#particleUpdatePlugins.push(plugin);
5323
- }
5324
- if (plugin.postUpdate) {
5325
- this.#postUpdatePlugins.push(plugin);
5326
- }
5327
- if (plugin.particleReset) {
5328
- this.#particleResetPlugins.push(plugin);
5329
- }
5330
- if (plugin.postParticleUpdate) {
5331
- this.#postParticleUpdatePlugins.push(plugin);
5332
- }
5333
- }
5334
- await this.#container.initDrawersAndUpdaters();
5335
- for (const drawer of this.#container.effectDrawers.values()) {
5336
- await drawer.init?.(container);
5337
- }
5338
- for (const drawer of this.#container.shapeDrawers.values()) {
5339
- await drawer.init?.(container);
5340
- }
5341
- let handled = false;
5342
- for (const plugin of container.plugins) {
5343
- handled = plugin.particlesInitialization?.() ?? handled;
5344
- if (handled) {
5345
- break;
5346
- }
5347
- }
5348
- if (!handled) {
5349
- const particlesOptions = options.particles, groups = particlesOptions.groups;
5350
- for (const group in groups) {
5351
- const groupOptions = groups[group];
5352
- if (!groupOptions) {
5353
- continue;
5354
- }
5355
- for (let i = this.count, j = 0; j < groupOptions.number.value && i < particlesOptions.number.value; i++, j++) {
5356
- this.addParticle(undefined, groupOptions, group);
5357
- }
5358
- }
5359
- for (let i = this.count; i < particlesOptions.number.value; i++) {
5360
- this.addParticle();
5601
+ this.#grid = new SpatialHashGrid(spatialHashGridCellSize * container.retina.pixelRatio);
5602
+ this.#applyLimits(container.actualOptions.particles);
5603
+ const particlesOptions = container.actualOptions.particles, groups = particlesOptions.groups;
5604
+ for (const group in groups) {
5605
+ const groupData = groups[group];
5606
+ if (groupData) {
5607
+ this.#applyLimits(loadParticlesOptions(this.#pluginManager, this.#container, groupData), group, groupData);
5361
5608
  }
5362
5609
  }
5610
+ await this.#initPlugins();
5363
5611
  }
5364
5612
  push(nb, position, overrideOptions, group) {
5365
5613
  for (let i = 0; i < nb; i++) {
@@ -5374,13 +5622,13 @@
5374
5622
  remove(particle, group, override) {
5375
5623
  this.removeAt(this.#array.indexOf(particle), undefined, group, override);
5376
5624
  }
5377
- removeAt(index, quantity = defaultRemoveQuantity, group, override) {
5625
+ removeAt(index, quantity = defaultRemoveQuantity, group, override, matchGroup = true) {
5378
5626
  if (index < minIndex || index > this.count) {
5379
5627
  return;
5380
5628
  }
5381
5629
  let deleted = 0;
5382
5630
  for (let i = index; deleted < quantity && i < this.count; i++) {
5383
- if (this.#removeParticle(i, group, override)) {
5631
+ if (this.#removeParticle(i, group, override, matchGroup)) {
5384
5632
  i--;
5385
5633
  deleted++;
5386
5634
  }
@@ -5411,7 +5659,7 @@
5411
5659
  this.#resizeFactor = factor;
5412
5660
  }
5413
5661
  update(delta) {
5414
- this.grid.clear();
5662
+ this.#grid.clear();
5415
5663
  for (const plugin of this.#updatePlugins) {
5416
5664
  plugin.update?.(delta);
5417
5665
  }
@@ -5422,7 +5670,7 @@
5422
5670
  this.#updateParticlesPhase2(delta, particlesToDelete);
5423
5671
  if (particlesToDelete.size) {
5424
5672
  for (const particle of particlesToDelete) {
5425
- this.remove(particle);
5673
+ this.remove(particle, particle.group);
5426
5674
  }
5427
5675
  }
5428
5676
  this.#resizeFactor = undefined;
@@ -5433,12 +5681,7 @@
5433
5681
  #applyDensity(options, pluginsCount, group, groupOptions) {
5434
5682
  const numberOptions = options.number;
5435
5683
  if (!numberOptions.density.enable) {
5436
- if (group === undefined) {
5437
- this.#limit = numberOptions.limit.value;
5438
- }
5439
- else if (groupOptions?.number.limit.value ?? numberOptions.limit.value) {
5440
- this.#groupLimits.set(group, groupOptions?.number.limit.value ?? numberOptions.limit.value);
5441
- }
5684
+ this.#applyLimits(options, group, groupOptions);
5442
5685
  return;
5443
5686
  }
5444
5687
  const densityFactor = this.#initDensityFactor(numberOptions.density), optParticlesNumber = numberOptions.value, optParticlesLimit = numberOptions.limit.value > minLimit ? numberOptions.limit.value : optParticlesNumber, particlesNumber = Math.min(optParticlesNumber, optParticlesLimit) * densityFactor + pluginsCount, particlesCount = Math.min(this.count, this.filter(t => t.group === group).length);
@@ -5446,7 +5689,10 @@
5446
5689
  this.#limit = numberOptions.limit.value * densityFactor;
5447
5690
  }
5448
5691
  else {
5449
- this.#groupLimits.set(group, numberOptions.limit.value * densityFactor);
5692
+ this.#groupLimits.set(group, {
5693
+ limit: numberOptions.limit.value * densityFactor,
5694
+ mode: toEnumValue(LimitMode, numberOptions.limit.mode, LimitMode.delete),
5695
+ });
5450
5696
  }
5451
5697
  if (particlesCount < particlesNumber) {
5452
5698
  this.push(Math.abs(particlesNumber - particlesCount), undefined, options, group);
@@ -5455,6 +5701,55 @@
5455
5701
  this.removeQuantity(particlesCount - particlesNumber, group);
5456
5702
  }
5457
5703
  }
5704
+ #applyLimits(options, group, groupOptions) {
5705
+ if (group === undefined) {
5706
+ this.#limit = options.number.limit.value;
5707
+ const groups = this.#container.actualOptions.particles.groups;
5708
+ for (const existingGroup of this.#groupLimits.keys()) {
5709
+ if (!(existingGroup in groups)) {
5710
+ this.#groupLimits.delete(existingGroup);
5711
+ }
5712
+ }
5713
+ }
5714
+ else {
5715
+ const limitValue = groupOptions?.number?.limit?.value ?? options.number.limit.value;
5716
+ if (limitValue > minLimit) {
5717
+ this.#groupLimits.set(group, {
5718
+ limit: limitValue,
5719
+ mode: toEnumValue(LimitMode, groupOptions?.number?.limit?.mode ?? options.number.limit.mode, LimitMode.delete),
5720
+ });
5721
+ }
5722
+ else {
5723
+ this.#groupLimits.delete(group);
5724
+ }
5725
+ }
5726
+ }
5727
+ #checkAndApplyLimits(group, currentCount) {
5728
+ const globalLimit = this.#limit, globalMode = this.#container.actualOptions.particles.number.limit.mode;
5729
+ if (globalLimit > minLimit && globalMode === LimitMode.wait && currentCount >= globalLimit) {
5730
+ return true;
5731
+ }
5732
+ const groupLimitEntry = group === undefined ? undefined : this.#groupLimits.get(group);
5733
+ if (groupLimitEntry && groupLimitEntry.limit > minLimit && groupLimitEntry.mode === LimitMode.wait) {
5734
+ const groupCount = this.filter(t => t.group === group).length;
5735
+ if (groupCount >= groupLimitEntry.limit) {
5736
+ return true;
5737
+ }
5738
+ }
5739
+ if (groupLimitEntry && groupLimitEntry.limit > minLimit && groupLimitEntry.mode === LimitMode.delete) {
5740
+ const groupCountToRemove = this.filter(t => t.group === group).length + countOffset - groupLimitEntry.limit;
5741
+ if (groupCountToRemove > minCount) {
5742
+ this.removeQuantity(groupCountToRemove, group);
5743
+ }
5744
+ }
5745
+ if (globalLimit > minLimit && globalMode === LimitMode.delete) {
5746
+ const globalCountToRemove = this.count + countOffset - globalLimit;
5747
+ if (globalCountToRemove > minCount) {
5748
+ this.#removeAny(globalCountToRemove);
5749
+ }
5750
+ }
5751
+ return false;
5752
+ }
5458
5753
  #createBuckets(zLayers) {
5459
5754
  const bucketCount = Math.max(Math.floor(zLayers), one);
5460
5755
  return Array.from({ length: bucketCount }, () => []);
@@ -5477,6 +5772,70 @@
5477
5772
  }
5478
5773
  return ((canvasSize.width * canvasSize.height) / (densityOptions.height * densityOptions.width * pxRatio ** squareExp));
5479
5774
  }
5775
+ async #initDrawersAndUpdaters() {
5776
+ const container = this.#container;
5777
+ await container.initDrawersAndUpdaters();
5778
+ for (const drawer of container.effectDrawers.values()) {
5779
+ await drawer.init?.(container);
5780
+ }
5781
+ for (const drawer of container.shapeDrawers.values()) {
5782
+ await drawer.init?.(container);
5783
+ }
5784
+ }
5785
+ async #initPlugins() {
5786
+ await this.#initPluginsArrays();
5787
+ await this.#initDrawersAndUpdaters();
5788
+ let handled = false;
5789
+ const container = this.#container;
5790
+ for (const plugin of container.plugins) {
5791
+ handled = plugin.particlesInitialization?.() ?? handled;
5792
+ if (handled) {
5793
+ break;
5794
+ }
5795
+ }
5796
+ if (handled) {
5797
+ return;
5798
+ }
5799
+ const particlesOptions = container.actualOptions.particles, groups = particlesOptions.groups;
5800
+ for (const group in groups) {
5801
+ const groupOptions = groups[group];
5802
+ if (!groupOptions) {
5803
+ continue;
5804
+ }
5805
+ for (let i = this.count, j = 0; j < groupOptions.number.value && i < particlesOptions.number.value; i++, j++) {
5806
+ this.addParticle(undefined, groupOptions, group);
5807
+ }
5808
+ }
5809
+ for (let i = this.count; i < particlesOptions.number.value; i++) {
5810
+ this.addParticle();
5811
+ }
5812
+ }
5813
+ async #initPluginsArrays() {
5814
+ const container = this.#container;
5815
+ for (const plugin of container.plugins) {
5816
+ if (plugin.redrawInit) {
5817
+ await plugin.redrawInit();
5818
+ }
5819
+ if (plugin.checkParticlePosition) {
5820
+ this.checkParticlePositionPlugins.push(plugin);
5821
+ }
5822
+ if (plugin.update) {
5823
+ this.#updatePlugins.push(plugin);
5824
+ }
5825
+ if (plugin.particleUpdate) {
5826
+ this.#particleUpdatePlugins.push(plugin);
5827
+ }
5828
+ if (plugin.postUpdate) {
5829
+ this.#postUpdatePlugins.push(plugin);
5830
+ }
5831
+ if (plugin.particleReset) {
5832
+ this.#particleResetPlugins.push(plugin);
5833
+ }
5834
+ if (plugin.postParticleUpdate) {
5835
+ this.#postParticleUpdatePlugins.push(plugin);
5836
+ }
5837
+ }
5838
+ }
5480
5839
  #insertParticleIntoBucket(particle) {
5481
5840
  const bucketIndex = this.#getBucketIndex(particle.position.z), bucket = this.#zBuckets[bucketIndex];
5482
5841
  if (!bucket) {
@@ -5485,12 +5844,15 @@
5485
5844
  bucket.push(particle);
5486
5845
  this.#particleBuckets.set(particle.id, bucketIndex);
5487
5846
  }
5488
- #removeParticle(index, group, override) {
5847
+ #removeAny(quantity) {
5848
+ this.removeAt(minIndex, quantity, undefined, undefined, false);
5849
+ }
5850
+ #removeParticle(index, group, override, matchGroup = true) {
5489
5851
  const particle = this.#array[index];
5490
5852
  if (!particle) {
5491
5853
  return false;
5492
5854
  }
5493
- if (particle.group !== group) {
5855
+ if (matchGroup && particle.group !== group) {
5494
5856
  return false;
5495
5857
  }
5496
5858
  this.#array.splice(index, deleteCount);
@@ -5577,7 +5939,7 @@
5577
5939
  particlesToDelete.add(particle);
5578
5940
  continue;
5579
5941
  }
5580
- this.grid.insert(particle);
5942
+ this.#grid.insert(particle);
5581
5943
  }
5582
5944
  return particlesToDelete;
5583
5945
  }
@@ -5649,6 +6011,7 @@
5649
6011
  effectDrawers;
5650
6012
  fpsLimit;
5651
6013
  hdr;
6014
+ hdrMode;
5652
6015
  id;
5653
6016
  pageHidden;
5654
6017
  particleCreatedPlugins;
@@ -5656,6 +6019,7 @@
5656
6019
  particlePositionPlugins;
5657
6020
  particleUpdaters;
5658
6021
  particles;
6022
+ peakNits;
5659
6023
  plugins;
5660
6024
  retina;
5661
6025
  shapeDrawers;
@@ -5686,6 +6050,8 @@
5686
6050
  this.id = Symbol(id);
5687
6051
  this.fpsLimit = 120;
5688
6052
  this.hdr = false;
6053
+ this.hdrMode = HdrMode.standard;
6054
+ this.peakNits = 400;
5689
6055
  this.#smooth = false;
5690
6056
  this.#delay = 0;
5691
6057
  this.#duration = 0;
@@ -5749,7 +6115,6 @@
5749
6115
  this.shapeDrawers = new Map();
5750
6116
  this.particleUpdaters = [];
5751
6117
  this.plugins.length = 0;
5752
- this.#pluginManager.clearPlugins(this);
5753
6118
  this.destroyed = true;
5754
6119
  this.#onDestroy(remove);
5755
6120
  this.dispatchEvent(EventType.containerDestroyed);
@@ -5802,31 +6167,15 @@
5802
6167
  await this.initDrawersAndUpdaters();
5803
6168
  this.#options = loadContainerOptions(this.#pluginManager, this, this.#initialSourceOptions, this.sourceOptions);
5804
6169
  this.actualOptions = loadContainerOptions(this.#pluginManager, this, this.#options);
5805
- this.plugins.length = 0;
5806
- this.particleDestroyedPlugins.length = 0;
5807
- this.particleCreatedPlugins.length = 0;
5808
- this.particlePositionPlugins.length = 0;
5809
- for (const [plugin, containerPlugin] of allContainerPlugins) {
5810
- if (plugin.needsPlugin(this.actualOptions)) {
5811
- this.plugins.push(containerPlugin);
5812
- if (containerPlugin.particleCreated) {
5813
- this.particleCreatedPlugins.push(containerPlugin);
5814
- }
5815
- if (containerPlugin.particleDestroyed) {
5816
- this.particleDestroyedPlugins.push(containerPlugin);
5817
- }
5818
- if (containerPlugin.particlePosition) {
5819
- this.particlePositionPlugins.push(containerPlugin);
5820
- }
5821
- }
5822
- }
6170
+ this.#initPlugins(allContainerPlugins);
5823
6171
  this.retina.init();
5824
6172
  this.canvas.init();
5825
6173
  this.updateActualOptions();
5826
6174
  this.canvas.initBackground();
5827
6175
  this.canvas.resize();
5828
- const { delay, duration, fpsLimit, hdr, smooth, zLayers } = this.actualOptions;
5829
- this.hdr = hdr;
6176
+ const { delay, duration, fpsLimit, smooth, zLayers } = this.actualOptions, hdrOptions = this.actualOptions.hdr;
6177
+ this.hdrMode = toEnumValue(HdrMode, hdrOptions.mode, HdrMode.standard);
6178
+ this.peakNits = hdrOptions.peakNits;
5830
6179
  this.zLayers = zLayers;
5831
6180
  this.#duration = getRangeValue(duration) * millisecondsToSeconds;
5832
6181
  this.#delay = getRangeValue(delay) * millisecondsToSeconds;
@@ -5846,9 +6195,9 @@
5846
6195
  }
5847
6196
  async initDrawersAndUpdaters() {
5848
6197
  const pluginManager = this.#pluginManager;
5849
- this.effectDrawers = await pluginManager.getEffectDrawers(this, true);
5850
- this.shapeDrawers = await pluginManager.getShapeDrawers(this, true);
5851
- this.particleUpdaters = await pluginManager.getUpdaters(this, true);
6198
+ this.effectDrawers = await getItemMapFromInitializer(this, pluginManager.initializers.effects);
6199
+ this.shapeDrawers = await getItemMapFromInitializer(this, pluginManager.initializers.shapes);
6200
+ this.particleUpdaters = await getItemsFromInitializer(this, pluginManager.initializers.updaters);
5852
6201
  }
5853
6202
  pause() {
5854
6203
  if (!guardCheck(this)) {
@@ -5959,6 +6308,27 @@
5959
6308
  }
5960
6309
  return refresh;
5961
6310
  }
6311
+ #initPlugins(allContainerPlugins) {
6312
+ this.plugins.length = 0;
6313
+ this.particleDestroyedPlugins.length = 0;
6314
+ this.particleCreatedPlugins.length = 0;
6315
+ this.particlePositionPlugins.length = 0;
6316
+ for (const [plugin, containerPlugin] of allContainerPlugins) {
6317
+ if (!plugin.needsPlugin(this.actualOptions)) {
6318
+ continue;
6319
+ }
6320
+ this.plugins.push(containerPlugin);
6321
+ if (containerPlugin.particleCreated) {
6322
+ this.particleCreatedPlugins.push(containerPlugin);
6323
+ }
6324
+ if (containerPlugin.particleDestroyed) {
6325
+ this.particleDestroyedPlugins.push(containerPlugin);
6326
+ }
6327
+ if (containerPlugin.particlePosition) {
6328
+ this.particlePositionPlugins.push(containerPlugin);
6329
+ }
6330
+ }
6331
+ }
5962
6332
  #nextFrame(timestamp) {
5963
6333
  try {
5964
6334
  if (!this.#smooth &&
@@ -6235,11 +6605,11 @@
6235
6605
  }
6236
6606
  }
6237
6607
  async #init() {
6238
- const availablePathGenerators = await this.#pluginManager.getPathGenerators?.(this.#container, true);
6239
- if (!availablePathGenerators) {
6608
+ const pluginManager = this.#pluginManager;
6609
+ if (!pluginManager.initializers.pathGenerators) {
6240
6610
  return;
6241
6611
  }
6242
- this.availablePathGenerators = availablePathGenerators;
6612
+ this.availablePathGenerators = await getItemMapFromInitializer(this.#container, pluginManager.initializers.pathGenerators);
6243
6613
  this.pathGenerators = new Map();
6244
6614
  for (const pathGenerator of this.pathGenerators.values()) {
6245
6615
  pathGenerator.init();
@@ -6343,28 +6713,12 @@
6343
6713
  }
6344
6714
  const html = interactivityEl, canvas = container.canvas;
6345
6715
  canvas.setPointerEvents(html === canvas.domElement ? "initial" : "none");
6346
- if (add && !(options.interactivity?.events.onHover.enable || options.interactivity?.events.onClick.enable)) {
6347
- return;
6348
- }
6349
6716
  manageListener(interactivityEl, mouseMoveEvent, handlers.mouseMove, add);
6350
6717
  manageListener(interactivityEl, touchStartEvent, handlers.touchStart, add);
6351
6718
  manageListener(interactivityEl, touchMoveEvent, handlers.touchMove, add);
6352
- if (add) {
6353
- if (options.interactivity?.events.onClick.enable) {
6354
- manageListener(interactivityEl, touchEndEvent, handlers.touchEndClick, add);
6355
- manageListener(interactivityEl, mouseUpEvent, handlers.mouseUp, add);
6356
- manageListener(interactivityEl, mouseDownEvent, handlers.mouseDown, add);
6357
- }
6358
- else {
6359
- manageListener(interactivityEl, touchEndEvent, handlers.touchEnd, add);
6360
- }
6361
- }
6362
- else {
6363
- manageListener(interactivityEl, touchEndEvent, handlers.touchEndClick, add);
6364
- manageListener(interactivityEl, mouseUpEvent, handlers.mouseUp, add);
6365
- manageListener(interactivityEl, mouseDownEvent, handlers.mouseDown, add);
6366
- manageListener(interactivityEl, touchEndEvent, handlers.touchEnd, add);
6367
- }
6719
+ manageListener(interactivityEl, touchEndEvent, options.interactivity?.events.onClick.enable ? handlers.touchEndClick : handlers.touchEnd, add);
6720
+ manageListener(interactivityEl, mouseUpEvent, handlers.mouseUp, add);
6721
+ manageListener(interactivityEl, mouseDownEvent, handlers.mouseDown, add);
6368
6722
  manageListener(interactivityEl, mouseLeaveEvent, handlers.mouseLeave, add);
6369
6723
  manageListener(interactivityEl, touchCancelEvent, handlers.touchCancel, add);
6370
6724
  }
@@ -6390,19 +6744,18 @@
6390
6744
  #mouseTouchClick(e) {
6391
6745
  const container = this.#container, interactionManager = this.#interactionManager, options = container.actualOptions, { mouse } = interactionManager.interactivityData;
6392
6746
  mouse.inside = true;
6393
- let handled = false;
6394
6747
  const mousePosition = mouse.position;
6395
- if (!mousePosition || !options.interactivity?.events.onClick.enable) {
6396
- return;
6397
- }
6398
- for (const plugin of this.#clickPositionPlugins) {
6399
- handled = plugin.clickPositionValid?.(mousePosition) ?? false;
6400
- if (handled) {
6401
- break;
6748
+ if (mousePosition && options.interactivity?.events.onClick.enable) {
6749
+ let handled = false;
6750
+ for (const plugin of this.#clickPositionPlugins) {
6751
+ handled = plugin.clickPositionValid?.(mousePosition) ?? false;
6752
+ if (handled) {
6753
+ break;
6754
+ }
6755
+ }
6756
+ if (!handled) {
6757
+ this.#doMouseTouchClick(e);
6402
6758
  }
6403
- }
6404
- if (!handled) {
6405
- this.#doMouseTouchClick(e);
6406
6759
  }
6407
6760
  mouse.clicking = false;
6408
6761
  }
@@ -6498,6 +6851,9 @@
6498
6851
  this.#touches.set(touch.identifier, performance.now());
6499
6852
  }
6500
6853
  this.#mouseTouchMove(e);
6854
+ const { mouse } = this.#interactionManager.interactivityData;
6855
+ mouse.clicking = true;
6856
+ mouse.downPosition = mouse.position;
6501
6857
  }
6502
6858
  }
6503
6859
 
@@ -6510,18 +6866,18 @@
6510
6866
  }
6511
6867
  class InteractionManager {
6512
6868
  interactivityData;
6869
+ interactors;
6513
6870
  #clickHandlers;
6514
6871
  #container;
6515
6872
  #eventListeners;
6516
6873
  #externalInteractors;
6517
- #interactors;
6518
6874
  #intersectionObserver;
6519
6875
  #particleInteractors;
6520
6876
  #pluginManager;
6521
6877
  constructor(pluginManager, container) {
6522
6878
  this.#container = container;
6523
6879
  this.#pluginManager = pluginManager;
6524
- this.#interactors = [];
6880
+ this.interactors = [];
6525
6881
  this.#externalInteractors = [];
6526
6882
  this.#particleInteractors = [];
6527
6883
  this.#clickHandlers = new Map();
@@ -6640,7 +6996,7 @@
6640
6996
  }
6641
6997
  init() {
6642
6998
  this.#eventListeners.init();
6643
- for (const interactor of this.#interactors) {
6999
+ for (const interactor of this.interactors) {
6644
7000
  switch (interactor.type) {
6645
7001
  case InteractorType.external:
6646
7002
  this.#externalInteractors.push(interactor);
@@ -6653,11 +7009,11 @@
6653
7009
  }
6654
7010
  }
6655
7011
  async initInteractors() {
6656
- const interactors = await this.#pluginManager.getInteractors?.(this.#container, true);
6657
- if (!interactors) {
7012
+ const pluginManager = this.#pluginManager;
7013
+ if (!pluginManager.initializers.interactors) {
6658
7014
  return;
6659
7015
  }
6660
- this.#interactors = interactors;
7016
+ this.interactors = await getItemsFromInitializer(this.#container, pluginManager.initializers.interactors);
6661
7017
  this.#externalInteractors = [];
6662
7018
  this.#particleInteractors = [];
6663
7019
  }
@@ -6702,13 +7058,13 @@
6702
7058
  }
6703
7059
  updateMaxDistance() {
6704
7060
  let maxTotalDistance = 0;
6705
- for (const interactor of this.#interactors) {
7061
+ for (const interactor of this.interactors) {
6706
7062
  if (interactor.maxDistance > maxTotalDistance) {
6707
7063
  maxTotalDistance = interactor.maxDistance;
6708
7064
  }
6709
7065
  }
6710
7066
  const container = this.#container;
6711
- container.particles.grid.setCellSize(maxTotalDistance * container.retina.pixelRatio);
7067
+ container.particles.grid.cellSize = maxTotalDistance * container.retina.pixelRatio;
6712
7068
  }
6713
7069
  #intersectionManager(entries) {
6714
7070
  const container = this.#container;
@@ -6730,59 +7086,59 @@
6730
7086
  }
6731
7087
 
6732
7088
  class InteractivityPluginInstance {
6733
- interactionManager;
6734
7089
  #container;
6735
- #pluginManager;
6736
7090
  constructor(pluginManager, container) {
6737
- this.#container = container;
6738
- this.#pluginManager = pluginManager;
6739
- this.interactionManager = new InteractionManager(pluginManager, container);
6740
- this.#container.addClickHandler = (callback) => {
6741
- this.interactionManager.addClickHandler(callback);
7091
+ container.addClickHandler = (callback) => {
7092
+ container.interactionManager?.addClickHandler(callback);
6742
7093
  };
7094
+ container.interactionManager = new InteractionManager(pluginManager, container);
7095
+ this.#container = container;
6743
7096
  }
6744
7097
  addClickHandler(callback) {
6745
- this.interactionManager.addClickHandler(callback);
7098
+ this.#container.interactionManager?.addClickHandler(callback);
6746
7099
  }
6747
7100
  clearClickHandlers() {
6748
- this.interactionManager.clearClickHandlers();
7101
+ this.#container.interactionManager?.clearClickHandlers();
6749
7102
  }
6750
7103
  destroy() {
6751
7104
  this.clearClickHandlers();
6752
- this.#pluginManager.interactors?.delete(this.#container);
6753
7105
  }
6754
7106
  particleCreated(particle) {
6755
- const interactivityParticle = particle, interactivity = new Interactivity(this.#pluginManager, this.#container);
6756
- interactivity.load(this.#container.actualOptions.interactivity);
7107
+ const interactivityParticle = particle, container = this.#container, interactivity = new Interactivity(container);
7108
+ interactivity.load(container.actualOptions.interactivity);
6757
7109
  interactivity.load(interactivityParticle.options.interactivity);
6758
7110
  interactivityParticle.interactivity = interactivity;
6759
7111
  }
6760
7112
  particleReset(particle) {
6761
- this.interactionManager.reset(particle);
7113
+ this.#container.interactionManager?.reset(particle);
6762
7114
  }
6763
7115
  postParticleUpdate(particle, delta) {
6764
- this.interactionManager.particlesInteract(particle, delta);
7116
+ this.#container.interactionManager?.particlesInteract(particle, delta);
6765
7117
  }
6766
7118
  postUpdate(delta) {
6767
- this.interactionManager.externalInteract(delta);
6768
- this.interactionManager.updateMaxDistance();
7119
+ const container = this.#container;
7120
+ container.interactionManager?.externalInteract(delta);
7121
+ container.interactionManager?.updateMaxDistance();
6769
7122
  }
6770
7123
  async preInit() {
6771
- await this.interactionManager.initInteractors();
6772
- this.interactionManager.init();
7124
+ const container = this.#container;
7125
+ await container.interactionManager?.initInteractors();
7126
+ container.interactionManager?.init();
6773
7127
  }
6774
7128
  async redrawInit() {
6775
- await this.interactionManager.initInteractors();
6776
- this.interactionManager.init();
7129
+ const container = this.#container;
7130
+ await container.interactionManager?.initInteractors();
7131
+ container.interactionManager?.init();
6777
7132
  }
6778
7133
  start() {
6779
- this.interactionManager.addListeners();
6780
- this.interactionManager.startObserving();
7134
+ const container = this.#container;
7135
+ container.interactionManager?.addListeners();
7136
+ container.interactionManager?.startObserving();
6781
7137
  return Promise.resolve();
6782
7138
  }
6783
7139
  stop() {
6784
- this.interactionManager.removeListeners();
6785
- this.interactionManager.stopObserving();
7140
+ this.#container.interactionManager?.removeListeners();
7141
+ this.#container.interactionManager?.stopObserving();
6786
7142
  }
6787
7143
  }
6788
7144
 
@@ -6952,10 +7308,10 @@
6952
7308
  }
6953
7309
  }
6954
7310
  #getCachedStyle(rgb) {
6955
- const key = `${rgb.r},${rgb.g},${rgb.b}`;
7311
+ const key = `${rgb.r},${rgb.g},${rgb.b}-${this.#container.hdr}-${this.#container.peakNits}-${this.#container.hdrMode}`;
6956
7312
  let style = this.#colorCache.get(key);
6957
7313
  if (!style) {
6958
- style = getStyleFromRgb(rgb, this.#container.hdr);
7314
+ style = getStyleFromRgb(rgb, this.#container.hdr, undefined, this.#container.peakNits, this.#container.hdrMode);
6959
7315
  this.#colorCache.set(key, style);
6960
7316
  }
6961
7317
  return style;
@@ -6976,6 +7332,7 @@
6976
7332
  exports.loadLinksPreset = loadLinksPreset;
6977
7333
  exports.tsParticles = tsParticles;
6978
7334
 
6979
- }));
7335
+ })(g.__tsParticlesInternals.presets.links = g.__tsParticlesInternals.presets.links || {});
7336
+ })(typeof globalThis !== "undefined" ? globalThis : typeof window !== "undefined" ? window : self);
7337
+
6980
7338
  Object.assign(globalThis.window || globalThis, { loadLinksPreset: (globalThis.__tsParticlesInternals.presets.links || {}).loadLinksPreset });
6981
- delete (globalThis.window || globalThis).tsparticlesInternalExports;