@tsparticles/preset-triangles 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.triangles = global.__tsParticlesInternals.presets.triangles || {})));
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);
@@ -3705,21 +3904,28 @@
3705
3904
  });
3706
3905
  }
3707
3906
  clear() {
3907
+ const visited = new Set();
3708
3908
  for (const plugin of this.#canvasClearPlugins) {
3909
+ visited.add(plugin);
3709
3910
  if (plugin.canvasClear?.() ?? false) {
3710
- return;
3911
+ return plugin;
3711
3912
  }
3712
3913
  }
3713
3914
  for (const layer of Object.values(DrawLayer)) {
3714
3915
  if (typeof layer === "number") {
3715
3916
  for (const plugin of this.#getLayerPlugins(layer)) {
3917
+ if (visited.has(plugin)) {
3918
+ continue;
3919
+ }
3920
+ visited.add(plugin);
3716
3921
  if (plugin.canvasClear?.() ?? false) {
3717
- return;
3922
+ return plugin;
3718
3923
  }
3719
3924
  }
3720
3925
  }
3721
3926
  }
3722
3927
  this.canvasClear();
3928
+ return undefined;
3723
3929
  }
3724
3930
  destroy() {
3725
3931
  this.stop();
@@ -3760,7 +3966,11 @@
3760
3966
  if (!fColor && !sColor) {
3761
3967
  return;
3762
3968
  }
3763
- 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;
3969
+ 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
3970
+ ? getStyleFromHsl(fColor, container.hdr, fillOpacity * opacity, container.peakNits, container.hdrMode)
3971
+ : undefined, stroke = sColor
3972
+ ? getStyleFromHsl(sColor, container.hdr, strokeOpacity * opacity, container.peakNits, container.hdrMode)
3973
+ : fill;
3764
3974
  transform.a = transform.b = transform.c = transform.d = undefined;
3765
3975
  colorStyles.fill = fill;
3766
3976
  colorStyles.stroke = stroke;
@@ -3793,8 +4003,7 @@
3793
4003
  });
3794
4004
  }
3795
4005
  drawParticles(delta) {
3796
- const { particles, actualOptions } = this.#container;
3797
- this.clear();
4006
+ const { particles, actualOptions } = this.#container, clearedPlugin = this.clear();
3798
4007
  particles.update(delta);
3799
4008
  this.draw(ctx => {
3800
4009
  const width = this.#canvasManager.size.width, height = this.#canvasManager.size.height;
@@ -3816,7 +4025,9 @@
3816
4025
  }
3817
4026
  }
3818
4027
  for (const plugin of this.#getLayerPlugins(DrawLayer.BackgroundMask)) {
3819
- plugin.canvasPaint?.();
4028
+ if (plugin !== clearedPlugin) {
4029
+ plugin.canvasPaint?.();
4030
+ }
3820
4031
  }
3821
4032
  for (const plugin of this.#getLayerPlugins(DrawLayer.CanvasSetup)) {
3822
4033
  plugin.drawSettingsSetup?.(ctx, delta);
@@ -3835,48 +4046,20 @@
3835
4046
  this.initUpdaters();
3836
4047
  this.initPlugins();
3837
4048
  this.#resolveBackgroundElement();
3838
- this.paint();
3839
- }
3840
- initPlugins() {
3841
- this.#canvasClearPlugins = [];
3842
- this.#colorPlugins = [];
3843
- this.#drawParticlePlugins = [];
3844
- this.#drawParticlesSetupPlugins = [];
3845
- this.#drawParticlesCleanupPlugins = [];
3846
- for (const layer of Object.values(DrawLayer)) {
3847
- if (typeof layer === "number") {
3848
- this.#layers[layer] = [];
3849
- }
3850
- }
3851
- for (const plugin of this.#container.plugins) {
3852
- if (plugin.particleFillColor ?? plugin.particleStrokeColor) {
3853
- this.#colorPlugins.push(plugin);
3854
- }
3855
- if (plugin.drawParticle) {
3856
- this.#drawParticlePlugins.push(plugin);
3857
- }
3858
- if (plugin.drawParticleSetup) {
3859
- this.#drawParticlesSetupPlugins.push(plugin);
3860
- }
3861
- if (plugin.drawParticleCleanup) {
3862
- this.#drawParticlesCleanupPlugins.push(plugin);
3863
- }
3864
- if (plugin.canvasClear) {
3865
- this.#canvasClearPlugins.push(plugin);
3866
- }
3867
- if (plugin.canvasPaint) {
3868
- this.#getLayerPlugins(DrawLayer.BackgroundMask).push(plugin);
3869
- }
3870
- if (plugin.drawSettingsSetup) {
3871
- this.#getLayerPlugins(DrawLayer.CanvasSetup).push(plugin);
3872
- }
3873
- if (plugin.draw) {
3874
- this.#getLayerPlugins(DrawLayer.PluginContent).push(plugin);
3875
- }
3876
- if (plugin.clearDraw ?? plugin.drawSettingsCleanup) {
3877
- this.#getLayerPlugins(DrawLayer.CanvasCleanup).push(plugin);
4049
+ this.paint();
4050
+ }
4051
+ initPlugins() {
4052
+ this.#canvasClearPlugins = [];
4053
+ this.#colorPlugins = [];
4054
+ this.#drawParticlePlugins = [];
4055
+ this.#drawParticlesSetupPlugins = [];
4056
+ this.#drawParticlesCleanupPlugins = [];
4057
+ for (const layer of Object.values(DrawLayer)) {
4058
+ if (typeof layer === "number") {
4059
+ this.#layers[layer] = [];
3878
4060
  }
3879
4061
  }
4062
+ this.#initPluginsArray();
3880
4063
  }
3881
4064
  initUpdaters() {
3882
4065
  this.#preDrawUpdaters = [];
@@ -4085,6 +4268,45 @@
4085
4268
  this.#reusablePluginColors[sColorIndex] = sColor;
4086
4269
  return this.#reusablePluginColors;
4087
4270
  }
4271
+ #initLayerPlugin(plugin) {
4272
+ const layerMap = [
4273
+ [DrawLayer.BackgroundMask, !!plugin.canvasPaint],
4274
+ [DrawLayer.CanvasSetup, !!plugin.drawSettingsSetup],
4275
+ [DrawLayer.PluginContent, !!plugin.draw],
4276
+ [DrawLayer.CanvasCleanup, !!(plugin.clearDraw ?? plugin.drawSettingsCleanup)],
4277
+ ];
4278
+ for (const [layer, active] of layerMap) {
4279
+ if (active) {
4280
+ this.#layers[layer].push(plugin);
4281
+ }
4282
+ }
4283
+ }
4284
+ #initPluginsArray() {
4285
+ for (const plugin of this.#container.plugins) {
4286
+ if (plugin.particleFillColor ?? plugin.particleStrokeColor) {
4287
+ this.#colorPlugins.push(plugin);
4288
+ }
4289
+ if (plugin.drawParticle) {
4290
+ this.#drawParticlePlugins.push(plugin);
4291
+ }
4292
+ if (plugin.drawParticleSetup) {
4293
+ this.#drawParticlesSetupPlugins.push(plugin);
4294
+ }
4295
+ if (plugin.drawParticleCleanup) {
4296
+ this.#drawParticlesCleanupPlugins.push(plugin);
4297
+ }
4298
+ if (plugin.canvasClear) {
4299
+ this.#canvasClearPlugins.push(plugin);
4300
+ }
4301
+ this.#initLayerPlugin(plugin);
4302
+ }
4303
+ }
4304
+ #isSupportedElement(element) {
4305
+ return ((typeof HTMLCanvasElement !== "undefined" && element instanceof HTMLCanvasElement) ||
4306
+ (typeof OffscreenCanvas !== "undefined" && element instanceof OffscreenCanvas) ||
4307
+ (typeof HTMLVideoElement !== "undefined" && element instanceof HTMLVideoElement) ||
4308
+ (typeof HTMLImageElement !== "undefined" && element instanceof HTMLImageElement));
4309
+ }
4088
4310
  #resolveBackgroundElement() {
4089
4311
  const background = this.#container.actualOptions.background;
4090
4312
  this.#backgroundElement = null;
@@ -4094,7 +4316,7 @@
4094
4316
  if (typeof background.element === "string") {
4095
4317
  if (typeof document !== "undefined") {
4096
4318
  const node = document.querySelector(background.element);
4097
- if (node instanceof HTMLCanvasElement || node instanceof HTMLVideoElement || node instanceof HTMLImageElement) {
4319
+ if (node && this.#isSupportedElement(node)) {
4098
4320
  this.#backgroundElement = node;
4099
4321
  }
4100
4322
  else if (node) {
@@ -4105,10 +4327,7 @@
4105
4327
  }
4106
4328
  }
4107
4329
  }
4108
- else if (background.element instanceof HTMLCanvasElement ||
4109
- background.element instanceof OffscreenCanvas ||
4110
- background.element instanceof HTMLVideoElement ||
4111
- background.element instanceof HTMLImageElement) {
4330
+ else if (this.#isSupportedElement(background.element)) {
4112
4331
  this.#backgroundElement = background.element;
4113
4332
  }
4114
4333
  }
@@ -4126,7 +4345,7 @@
4126
4345
  return transferredCanvas;
4127
4346
  }
4128
4347
  if (typeof canvas.transferControlToOffscreen !== "function") {
4129
- throw new TypeError("OffscreenCanvas is required but not supported by this browser");
4348
+ throw new TypeError(getErrorMessage(ErrorCodes$2.offscreenCanvasUnsupported));
4130
4349
  }
4131
4350
  try {
4132
4351
  const offscreenCanvas = canvas.transferControlToOffscreen();
@@ -4134,10 +4353,16 @@
4134
4353
  return offscreenCanvas;
4135
4354
  }
4136
4355
  catch {
4137
- throw new TypeError("OffscreenCanvas transfer failed");
4356
+ throw new TypeError(getErrorMessage(ErrorCodes$2.offscreenCanvasTransferFailed));
4138
4357
  }
4139
4358
  }, isHtmlCanvasElement = (canvas) => {
4140
4359
  return typeof HTMLCanvasElement !== "undefined" && canvas instanceof HTMLCanvasElement;
4360
+ }, getEffectiveColorSpace = (context) => {
4361
+ if (!context) {
4362
+ return undefined;
4363
+ }
4364
+ const colorInfo = context;
4365
+ return colorInfo.getContextAttributes?.().colorSpace ?? undefined;
4141
4366
  };
4142
4367
  function setStyle(canvas, style, important = false) {
4143
4368
  if (!style) {
@@ -4176,6 +4401,7 @@
4176
4401
  zoom = defaultZoom;
4177
4402
  #container;
4178
4403
  #generated;
4404
+ #hdrMediaListeners;
4179
4405
  #mutationObserver;
4180
4406
  #originalStyle;
4181
4407
  #pluginManager;
@@ -4240,7 +4466,6 @@
4240
4466
  });
4241
4467
  this.resize();
4242
4468
  this.#initStyle();
4243
- this.initBackground();
4244
4469
  this.#safeMutationObserver(obs => {
4245
4470
  const element = this.domElement;
4246
4471
  if (!element || !(element instanceof Node)) {
@@ -4250,6 +4475,8 @@
4250
4475
  });
4251
4476
  this.initPlugins();
4252
4477
  this.#initContext();
4478
+ this.initBackground();
4479
+ this.#initHdrListeners();
4253
4480
  this.render.init();
4254
4481
  }
4255
4482
  initBackground() {
@@ -4259,7 +4486,8 @@
4259
4486
  }
4260
4487
  const elementStyle = element.style, color = rangeColorToRgb(this.#pluginManager, background.color);
4261
4488
  if (color) {
4262
- elementStyle.backgroundColor = getStyleFromRgb(color, container.actualOptions.hdr, background.opacity);
4489
+ const hdrOptions = container.actualOptions.hdr;
4490
+ elementStyle.backgroundColor = getStyleFromRgb(color, container.hdr, background.opacity, hdrOptions.peakNits, toEnumValue(HdrMode, hdrOptions.mode, HdrMode.standard));
4263
4491
  }
4264
4492
  else {
4265
4493
  elementStyle.backgroundColor = "";
@@ -4356,6 +4584,7 @@
4356
4584
  obs.disconnect();
4357
4585
  });
4358
4586
  this.#mutationObserver = undefined;
4587
+ this.#removeHdrListeners();
4359
4588
  this.render.stop();
4360
4589
  }
4361
4590
  async windowResize() {
@@ -4375,9 +4604,16 @@
4375
4604
  }
4376
4605
  }
4377
4606
  #initContext() {
4378
- const container = this.#container, canSupportHdr = container.actualOptions.hdr &&
4607
+ const container = this.#container, canSupportHdr = container.actualOptions.hdr.enable &&
4379
4608
  safeMatchMedia("(color-gamut: p3)")?.matches &&
4380
4609
  safeMatchMedia("(dynamic-range: high)")?.matches;
4610
+ container.hdrMode = toEnumValue(HdrMode, container.actualOptions.hdr.mode, HdrMode.standard);
4611
+ container.peakNits = container.actualOptions.hdr.peakNits;
4612
+ const renderCanvas = this.renderCanvas;
4613
+ if (!renderCanvas) {
4614
+ container.hdr = canSupportHdr ?? false;
4615
+ return;
4616
+ }
4381
4617
  this.render.setContextSettings({
4382
4618
  alpha: true,
4383
4619
  desynchronized: true,
@@ -4386,11 +4622,51 @@
4386
4622
  ? { colorSpace: "display-p3", colorType: "float16" }
4387
4623
  : { colorSpace: "srgb" }),
4388
4624
  });
4389
- const renderCanvas = this.renderCanvas;
4390
- if (!renderCanvas) {
4391
- return;
4625
+ let context;
4626
+ try {
4627
+ context = renderCanvas.getContext("2d", this.render.settings);
4628
+ }
4629
+ catch {
4630
+ context = null;
4631
+ }
4632
+ if (canSupportHdr && !context) {
4633
+ const sdrSettings = {
4634
+ alpha: true,
4635
+ desynchronized: true,
4636
+ willReadFrequently: false,
4637
+ colorSpace: "srgb",
4638
+ };
4639
+ this.render.setContextSettings(sdrSettings);
4640
+ try {
4641
+ context = renderCanvas.getContext("2d", sdrSettings);
4642
+ }
4643
+ catch {
4644
+ context = null;
4645
+ }
4646
+ }
4647
+ this.render.setContext(context);
4648
+ if (context) {
4649
+ const effectiveColorSpace = getEffectiveColorSpace(context);
4650
+ if (effectiveColorSpace !== undefined) {
4651
+ container.hdr = effectiveColorSpace === "display-p3";
4652
+ }
4653
+ }
4654
+ }
4655
+ #initHdrListeners() {
4656
+ this.#removeHdrListeners();
4657
+ const p3Query = safeMatchMedia("(color-gamut: p3)"), hdrQuery = safeMatchMedia("(dynamic-range: high)"), handleChange = () => {
4658
+ this.#initContext();
4659
+ this.initBackground();
4660
+ }, listeners = [];
4661
+ if (p3Query) {
4662
+ p3Query.addEventListener("change", handleChange);
4663
+ listeners.push({ handler: handleChange, mql: p3Query });
4664
+ }
4665
+ if (hdrQuery) {
4666
+ hdrQuery.addEventListener("change", handleChange);
4667
+ listeners.push({ handler: handleChange, mql: hdrQuery });
4392
4668
  }
4393
- this.render.setContext(renderCanvas.getContext("2d", this.render.settings));
4669
+ this.#hdrMediaListeners = listeners;
4394
4670
  }
4395
4671
  #initStyle() {
4396
4672
  const element = this.domElement, options = this.#container.actualOptions;
@@ -4414,6 +4690,15 @@
4414
4690
  element.style.setProperty(key, value, "important");
4415
4691
  }
4416
4692
  }
4693
+ #removeHdrListeners() {
4694
+ if (!this.#hdrMediaListeners) {
4695
+ return;
4696
+ }
4697
+ for (const { handler, mql } of this.#hdrMediaListeners) {
4698
+ mql.removeEventListener("change", handler);
4699
+ }
4700
+ this.#hdrMediaListeners = undefined;
4701
+ }
4417
4702
  #repairStyle() {
4418
4703
  const element = this.domElement;
4419
4704
  if (!element) {
@@ -4503,8 +4788,7 @@
4503
4788
  this.#resizeTimeout = undefined;
4504
4789
  }
4505
4790
  const handleResize = async () => {
4506
- const canvas = this.#container.canvas;
4507
- await canvas.windowResize();
4791
+ await this.#container.canvas.windowResize();
4508
4792
  };
4509
4793
  this.#resizeTimeout = setTimeout(() => void handleResize(), this.#container.actualOptions.resize.delay * millisecondsToSeconds);
4510
4794
  }
@@ -4532,8 +4816,8 @@
4532
4816
  }
4533
4817
  else if (!this.#resizeObserver && add && canvasEl) {
4534
4818
  this.#resizeObserver = new ResizeObserver((entries) => {
4535
- const entry = entries.find(e => e.target === canvasEl);
4536
- if (!entry) {
4819
+ const res = entries.some(e => e.target === canvasEl);
4820
+ if (!res) {
4537
4821
  return;
4538
4822
  }
4539
4823
  this.#handleWindowResize();
@@ -4797,10 +5081,10 @@
4797
5081
  return this.#modifiers.find(m => m.id === id);
4798
5082
  }
4799
5083
  getOpacity() {
4800
- 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;
4801
- this.#cachedOpacityData.fillOpacity = opacity * fillOpacity * zOpacityFactor;
5084
+ 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;
5085
+ this.#cachedOpacityData.fillOpacity = this.fillOpacity ?? defaultOpacity$1;
4802
5086
  this.#cachedOpacityData.opacity = opacity * zOpacityFactor;
4803
- this.#cachedOpacityData.strokeOpacity = opacity * strokeOpacity * zOpacityFactor;
5087
+ this.#cachedOpacityData.strokeOpacity = this.strokeOpacity ?? defaultOpacity$1;
4804
5088
  return this.#cachedOpacityData;
4805
5089
  }
4806
5090
  getPosition() {
@@ -5047,7 +5331,7 @@
5047
5331
  #initPosition(position) {
5048
5332
  const container = this.#container, zIndexValue = Math.floor(getRangeValue(this.options.zIndex.value)), initialPosition = this.#calcPosition(position, clamp(zIndexValue, minZ, container.zLayers));
5049
5333
  if (!initialPosition) {
5050
- throw new Error("a valid position cannot be found for particle");
5334
+ throw new Error(getErrorMessage(ErrorCodes$2.particlePositionNotFound));
5051
5335
  }
5052
5336
  this.position = initialPosition;
5053
5337
  this.initialPosition = this.position.copy();
@@ -5096,6 +5380,12 @@
5096
5380
  this.#circlePoolIdx = 0;
5097
5381
  this.#rectanglePoolIdx = 0;
5098
5382
  }
5383
+ get cellSize() {
5384
+ return this.#cellSize;
5385
+ }
5386
+ set cellSize(value) {
5387
+ this.#pendingCellSize = value;
5388
+ }
5099
5389
  clear() {
5100
5390
  this.#cells.clear();
5101
5391
  const pendingCellSize = this.#pendingCellSize;
@@ -5119,18 +5409,7 @@
5119
5409
  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);
5120
5410
  for (let cx = minCellX; cx <= maxCellX; cx++) {
5121
5411
  for (let cy = minCellY; cy <= maxCellY; cy++) {
5122
- const key = `${cx}_${cy}`, cellParticles = this.#cells.get(key);
5123
- if (!cellParticles) {
5124
- continue;
5125
- }
5126
- for (const p of cellParticles) {
5127
- if (check && !check(p)) {
5128
- continue;
5129
- }
5130
- if (range.contains(p.getPosition())) {
5131
- out.push(p);
5132
- }
5133
- }
5412
+ this.#queryCell(cx, cy, range, check, out);
5134
5413
  }
5135
5414
  }
5136
5415
  return out;
@@ -5145,14 +5424,23 @@
5145
5424
  this.#releaseShapes();
5146
5425
  return result;
5147
5426
  }
5148
- setCellSize(cellSize) {
5149
- this.#pendingCellSize = cellSize;
5150
- }
5151
5427
  #acquireCircle(x, y, r) {
5152
- return (this.#circlePool[this.#circlePoolIdx++] ??= new Circle(x, y, r)).reset(x, y, r);
5428
+ const idx = this.#circlePoolIdx++;
5429
+ let circle = this.#circlePool[idx];
5430
+ if (!circle) {
5431
+ circle = new Circle(x, y, r);
5432
+ this.#circlePool[idx] = circle;
5433
+ }
5434
+ return circle.reset(x, y, r);
5153
5435
  }
5154
5436
  #acquireRectangle(x, y, w, h) {
5155
- return (this.#rectanglePool[this.#rectanglePoolIdx++] ??= new Rectangle(x, y, w, h)).reset(x, y, w, h);
5437
+ const idx = this.#rectanglePoolIdx++;
5438
+ let rectangle = this.#rectanglePool[idx];
5439
+ if (!rectangle) {
5440
+ rectangle = new Rectangle(x, y, w, h);
5441
+ this.#rectanglePool[idx] = rectangle;
5442
+ }
5443
+ return rectangle.reset(x, y, w, h);
5156
5444
  }
5157
5445
  #cellKeyFromCoords(x, y) {
5158
5446
  const cellX = Math.floor(x / this.#cellSize), cellY = Math.floor(y / this.#cellSize);
@@ -5179,6 +5467,20 @@
5179
5467
  }
5180
5468
  return null;
5181
5469
  }
5470
+ #queryCell(cx, cy, range, check, out) {
5471
+ const cellParticles = this.#cells.get(`${cx}_${cy}`);
5472
+ if (!cellParticles) {
5473
+ return;
5474
+ }
5475
+ for (const p of cellParticles) {
5476
+ if (check && !check(p)) {
5477
+ continue;
5478
+ }
5479
+ if (range.contains(p.getPosition())) {
5480
+ out.push(p);
5481
+ }
5482
+ }
5483
+ }
5182
5484
  #releaseShapes() {
5183
5485
  this.#circlePoolIdx = 0;
5184
5486
  this.#rectanglePoolIdx = 0;
@@ -5187,9 +5489,9 @@
5187
5489
 
5188
5490
  class ParticlesManager {
5189
5491
  checkParticlePositionPlugins;
5190
- grid;
5191
5492
  #array;
5192
5493
  #container;
5494
+ #grid;
5193
5495
  #groupLimits;
5194
5496
  #limit;
5195
5497
  #nextId;
@@ -5213,7 +5515,7 @@
5213
5515
  this.#groupLimits = new Map();
5214
5516
  this.#particleBuckets = new Map();
5215
5517
  this.#zBuckets = this.#createBuckets(this.#container.zLayers);
5216
- this.grid = new SpatialHashGrid(spatialHashGridCellSize);
5518
+ this.#grid = new SpatialHashGrid(spatialHashGridCellSize);
5217
5519
  this.checkParticlePositionPlugins = [];
5218
5520
  this.#particleResetPlugins = [];
5219
5521
  this.#particleUpdatePlugins = [];
@@ -5224,23 +5526,12 @@
5224
5526
  get count() {
5225
5527
  return this.#array.length;
5226
5528
  }
5529
+ get grid() {
5530
+ return this.#grid;
5531
+ }
5227
5532
  addParticle(position, overrideOptions, group, initializer) {
5228
- const limitMode = this.#container.actualOptions.particles.number.limit.mode, limit = group === undefined ? this.#limit : (this.#groupLimits.get(group) ?? this.#limit), currentCount = this.count;
5229
- if (limit > minLimit) {
5230
- switch (limitMode) {
5231
- case LimitMode.delete: {
5232
- const countToRemove = currentCount + countOffset - limit;
5233
- if (countToRemove > minCount) {
5234
- this.removeQuantity(countToRemove);
5235
- }
5236
- break;
5237
- }
5238
- case LimitMode.wait:
5239
- if (currentCount >= limit) {
5240
- return;
5241
- }
5242
- break;
5243
- }
5533
+ if (this.#checkAndApplyLimits(group, this.count)) {
5534
+ return;
5244
5535
  }
5245
5536
  try {
5246
5537
  const particle = this.#pool.pop() ?? new Particle(this.#pluginManager, this.#container);
@@ -5304,7 +5595,7 @@
5304
5595
  return this.#array[index];
5305
5596
  }
5306
5597
  async init() {
5307
- const container = this.#container, options = container.actualOptions;
5598
+ const container = this.#container;
5308
5599
  this.checkParticlePositionPlugins = [];
5309
5600
  this.#updatePlugins = [];
5310
5601
  this.#particleUpdatePlugins = [];
@@ -5313,59 +5604,16 @@
5313
5604
  this.#postParticleUpdatePlugins = [];
5314
5605
  this.#particleBuckets.clear();
5315
5606
  this.#resetBuckets(container.zLayers);
5316
- this.grid = new SpatialHashGrid(spatialHashGridCellSize * container.retina.pixelRatio);
5317
- for (const plugin of container.plugins) {
5318
- if (plugin.redrawInit) {
5319
- await plugin.redrawInit();
5320
- }
5321
- if (plugin.checkParticlePosition) {
5322
- this.checkParticlePositionPlugins.push(plugin);
5323
- }
5324
- if (plugin.update) {
5325
- this.#updatePlugins.push(plugin);
5326
- }
5327
- if (plugin.particleUpdate) {
5328
- this.#particleUpdatePlugins.push(plugin);
5329
- }
5330
- if (plugin.postUpdate) {
5331
- this.#postUpdatePlugins.push(plugin);
5332
- }
5333
- if (plugin.particleReset) {
5334
- this.#particleResetPlugins.push(plugin);
5335
- }
5336
- if (plugin.postParticleUpdate) {
5337
- this.#postParticleUpdatePlugins.push(plugin);
5338
- }
5339
- }
5340
- await this.#container.initDrawersAndUpdaters();
5341
- for (const drawer of this.#container.effectDrawers.values()) {
5342
- await drawer.init?.(container);
5343
- }
5344
- for (const drawer of this.#container.shapeDrawers.values()) {
5345
- await drawer.init?.(container);
5346
- }
5347
- let handled = false;
5348
- for (const plugin of container.plugins) {
5349
- handled = plugin.particlesInitialization?.() ?? handled;
5350
- if (handled) {
5351
- break;
5352
- }
5353
- }
5354
- if (!handled) {
5355
- const particlesOptions = options.particles, groups = particlesOptions.groups;
5356
- for (const group in groups) {
5357
- const groupOptions = groups[group];
5358
- if (!groupOptions) {
5359
- continue;
5360
- }
5361
- for (let i = this.count, j = 0; j < groupOptions.number.value && i < particlesOptions.number.value; i++, j++) {
5362
- this.addParticle(undefined, groupOptions, group);
5363
- }
5364
- }
5365
- for (let i = this.count; i < particlesOptions.number.value; i++) {
5366
- this.addParticle();
5607
+ this.#grid = new SpatialHashGrid(spatialHashGridCellSize * container.retina.pixelRatio);
5608
+ this.#applyLimits(container.actualOptions.particles);
5609
+ const particlesOptions = container.actualOptions.particles, groups = particlesOptions.groups;
5610
+ for (const group in groups) {
5611
+ const groupData = groups[group];
5612
+ if (groupData) {
5613
+ this.#applyLimits(loadParticlesOptions(this.#pluginManager, this.#container, groupData), group, groupData);
5367
5614
  }
5368
5615
  }
5616
+ await this.#initPlugins();
5369
5617
  }
5370
5618
  push(nb, position, overrideOptions, group) {
5371
5619
  for (let i = 0; i < nb; i++) {
@@ -5380,13 +5628,13 @@
5380
5628
  remove(particle, group, override) {
5381
5629
  this.removeAt(this.#array.indexOf(particle), undefined, group, override);
5382
5630
  }
5383
- removeAt(index, quantity = defaultRemoveQuantity, group, override) {
5631
+ removeAt(index, quantity = defaultRemoveQuantity, group, override, matchGroup = true) {
5384
5632
  if (index < minIndex || index > this.count) {
5385
5633
  return;
5386
5634
  }
5387
5635
  let deleted = 0;
5388
5636
  for (let i = index; deleted < quantity && i < this.count; i++) {
5389
- if (this.#removeParticle(i, group, override)) {
5637
+ if (this.#removeParticle(i, group, override, matchGroup)) {
5390
5638
  i--;
5391
5639
  deleted++;
5392
5640
  }
@@ -5417,7 +5665,7 @@
5417
5665
  this.#resizeFactor = factor;
5418
5666
  }
5419
5667
  update(delta) {
5420
- this.grid.clear();
5668
+ this.#grid.clear();
5421
5669
  for (const plugin of this.#updatePlugins) {
5422
5670
  plugin.update?.(delta);
5423
5671
  }
@@ -5428,7 +5676,7 @@
5428
5676
  this.#updateParticlesPhase2(delta, particlesToDelete);
5429
5677
  if (particlesToDelete.size) {
5430
5678
  for (const particle of particlesToDelete) {
5431
- this.remove(particle);
5679
+ this.remove(particle, particle.group);
5432
5680
  }
5433
5681
  }
5434
5682
  this.#resizeFactor = undefined;
@@ -5439,12 +5687,7 @@
5439
5687
  #applyDensity(options, pluginsCount, group, groupOptions) {
5440
5688
  const numberOptions = options.number;
5441
5689
  if (!numberOptions.density.enable) {
5442
- if (group === undefined) {
5443
- this.#limit = numberOptions.limit.value;
5444
- }
5445
- else if (groupOptions?.number.limit.value ?? numberOptions.limit.value) {
5446
- this.#groupLimits.set(group, groupOptions?.number.limit.value ?? numberOptions.limit.value);
5447
- }
5690
+ this.#applyLimits(options, group, groupOptions);
5448
5691
  return;
5449
5692
  }
5450
5693
  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);
@@ -5452,7 +5695,10 @@
5452
5695
  this.#limit = numberOptions.limit.value * densityFactor;
5453
5696
  }
5454
5697
  else {
5455
- this.#groupLimits.set(group, numberOptions.limit.value * densityFactor);
5698
+ this.#groupLimits.set(group, {
5699
+ limit: numberOptions.limit.value * densityFactor,
5700
+ mode: toEnumValue(LimitMode, numberOptions.limit.mode, LimitMode.delete),
5701
+ });
5456
5702
  }
5457
5703
  if (particlesCount < particlesNumber) {
5458
5704
  this.push(Math.abs(particlesNumber - particlesCount), undefined, options, group);
@@ -5461,6 +5707,55 @@
5461
5707
  this.removeQuantity(particlesCount - particlesNumber, group);
5462
5708
  }
5463
5709
  }
5710
+ #applyLimits(options, group, groupOptions) {
5711
+ if (group === undefined) {
5712
+ this.#limit = options.number.limit.value;
5713
+ const groups = this.#container.actualOptions.particles.groups;
5714
+ for (const existingGroup of this.#groupLimits.keys()) {
5715
+ if (!(existingGroup in groups)) {
5716
+ this.#groupLimits.delete(existingGroup);
5717
+ }
5718
+ }
5719
+ }
5720
+ else {
5721
+ const limitValue = groupOptions?.number?.limit?.value ?? options.number.limit.value;
5722
+ if (limitValue > minLimit) {
5723
+ this.#groupLimits.set(group, {
5724
+ limit: limitValue,
5725
+ mode: toEnumValue(LimitMode, groupOptions?.number?.limit?.mode ?? options.number.limit.mode, LimitMode.delete),
5726
+ });
5727
+ }
5728
+ else {
5729
+ this.#groupLimits.delete(group);
5730
+ }
5731
+ }
5732
+ }
5733
+ #checkAndApplyLimits(group, currentCount) {
5734
+ const globalLimit = this.#limit, globalMode = this.#container.actualOptions.particles.number.limit.mode;
5735
+ if (globalLimit > minLimit && globalMode === LimitMode.wait && currentCount >= globalLimit) {
5736
+ return true;
5737
+ }
5738
+ const groupLimitEntry = group === undefined ? undefined : this.#groupLimits.get(group);
5739
+ if (groupLimitEntry && groupLimitEntry.limit > minLimit && groupLimitEntry.mode === LimitMode.wait) {
5740
+ const groupCount = this.filter(t => t.group === group).length;
5741
+ if (groupCount >= groupLimitEntry.limit) {
5742
+ return true;
5743
+ }
5744
+ }
5745
+ if (groupLimitEntry && groupLimitEntry.limit > minLimit && groupLimitEntry.mode === LimitMode.delete) {
5746
+ const groupCountToRemove = this.filter(t => t.group === group).length + countOffset - groupLimitEntry.limit;
5747
+ if (groupCountToRemove > minCount) {
5748
+ this.removeQuantity(groupCountToRemove, group);
5749
+ }
5750
+ }
5751
+ if (globalLimit > minLimit && globalMode === LimitMode.delete) {
5752
+ const globalCountToRemove = this.count + countOffset - globalLimit;
5753
+ if (globalCountToRemove > minCount) {
5754
+ this.#removeAny(globalCountToRemove);
5755
+ }
5756
+ }
5757
+ return false;
5758
+ }
5464
5759
  #createBuckets(zLayers) {
5465
5760
  const bucketCount = Math.max(Math.floor(zLayers), one);
5466
5761
  return Array.from({ length: bucketCount }, () => []);
@@ -5483,6 +5778,70 @@
5483
5778
  }
5484
5779
  return ((canvasSize.width * canvasSize.height) / (densityOptions.height * densityOptions.width * pxRatio ** squareExp));
5485
5780
  }
5781
+ async #initDrawersAndUpdaters() {
5782
+ const container = this.#container;
5783
+ await container.initDrawersAndUpdaters();
5784
+ for (const drawer of container.effectDrawers.values()) {
5785
+ await drawer.init?.(container);
5786
+ }
5787
+ for (const drawer of container.shapeDrawers.values()) {
5788
+ await drawer.init?.(container);
5789
+ }
5790
+ }
5791
+ async #initPlugins() {
5792
+ await this.#initPluginsArrays();
5793
+ await this.#initDrawersAndUpdaters();
5794
+ let handled = false;
5795
+ const container = this.#container;
5796
+ for (const plugin of container.plugins) {
5797
+ handled = plugin.particlesInitialization?.() ?? handled;
5798
+ if (handled) {
5799
+ break;
5800
+ }
5801
+ }
5802
+ if (handled) {
5803
+ return;
5804
+ }
5805
+ const particlesOptions = container.actualOptions.particles, groups = particlesOptions.groups;
5806
+ for (const group in groups) {
5807
+ const groupOptions = groups[group];
5808
+ if (!groupOptions) {
5809
+ continue;
5810
+ }
5811
+ for (let i = this.count, j = 0; j < groupOptions.number.value && i < particlesOptions.number.value; i++, j++) {
5812
+ this.addParticle(undefined, groupOptions, group);
5813
+ }
5814
+ }
5815
+ for (let i = this.count; i < particlesOptions.number.value; i++) {
5816
+ this.addParticle();
5817
+ }
5818
+ }
5819
+ async #initPluginsArrays() {
5820
+ const container = this.#container;
5821
+ for (const plugin of container.plugins) {
5822
+ if (plugin.redrawInit) {
5823
+ await plugin.redrawInit();
5824
+ }
5825
+ if (plugin.checkParticlePosition) {
5826
+ this.checkParticlePositionPlugins.push(plugin);
5827
+ }
5828
+ if (plugin.update) {
5829
+ this.#updatePlugins.push(plugin);
5830
+ }
5831
+ if (plugin.particleUpdate) {
5832
+ this.#particleUpdatePlugins.push(plugin);
5833
+ }
5834
+ if (plugin.postUpdate) {
5835
+ this.#postUpdatePlugins.push(plugin);
5836
+ }
5837
+ if (plugin.particleReset) {
5838
+ this.#particleResetPlugins.push(plugin);
5839
+ }
5840
+ if (plugin.postParticleUpdate) {
5841
+ this.#postParticleUpdatePlugins.push(plugin);
5842
+ }
5843
+ }
5844
+ }
5486
5845
  #insertParticleIntoBucket(particle) {
5487
5846
  const bucketIndex = this.#getBucketIndex(particle.position.z), bucket = this.#zBuckets[bucketIndex];
5488
5847
  if (!bucket) {
@@ -5491,12 +5850,15 @@
5491
5850
  bucket.push(particle);
5492
5851
  this.#particleBuckets.set(particle.id, bucketIndex);
5493
5852
  }
5494
- #removeParticle(index, group, override) {
5853
+ #removeAny(quantity) {
5854
+ this.removeAt(minIndex, quantity, undefined, undefined, false);
5855
+ }
5856
+ #removeParticle(index, group, override, matchGroup = true) {
5495
5857
  const particle = this.#array[index];
5496
5858
  if (!particle) {
5497
5859
  return false;
5498
5860
  }
5499
- if (particle.group !== group) {
5861
+ if (matchGroup && particle.group !== group) {
5500
5862
  return false;
5501
5863
  }
5502
5864
  this.#array.splice(index, deleteCount);
@@ -5583,7 +5945,7 @@
5583
5945
  particlesToDelete.add(particle);
5584
5946
  continue;
5585
5947
  }
5586
- this.grid.insert(particle);
5948
+ this.#grid.insert(particle);
5587
5949
  }
5588
5950
  return particlesToDelete;
5589
5951
  }
@@ -5655,6 +6017,7 @@
5655
6017
  effectDrawers;
5656
6018
  fpsLimit;
5657
6019
  hdr;
6020
+ hdrMode;
5658
6021
  id;
5659
6022
  pageHidden;
5660
6023
  particleCreatedPlugins;
@@ -5662,6 +6025,7 @@
5662
6025
  particlePositionPlugins;
5663
6026
  particleUpdaters;
5664
6027
  particles;
6028
+ peakNits;
5665
6029
  plugins;
5666
6030
  retina;
5667
6031
  shapeDrawers;
@@ -5692,6 +6056,8 @@
5692
6056
  this.id = Symbol(id);
5693
6057
  this.fpsLimit = 120;
5694
6058
  this.hdr = false;
6059
+ this.hdrMode = HdrMode.standard;
6060
+ this.peakNits = 400;
5695
6061
  this.#smooth = false;
5696
6062
  this.#delay = 0;
5697
6063
  this.#duration = 0;
@@ -5755,7 +6121,6 @@
5755
6121
  this.shapeDrawers = new Map();
5756
6122
  this.particleUpdaters = [];
5757
6123
  this.plugins.length = 0;
5758
- this.#pluginManager.clearPlugins(this);
5759
6124
  this.destroyed = true;
5760
6125
  this.#onDestroy(remove);
5761
6126
  this.dispatchEvent(EventType.containerDestroyed);
@@ -5808,31 +6173,15 @@
5808
6173
  await this.initDrawersAndUpdaters();
5809
6174
  this.#options = loadContainerOptions(this.#pluginManager, this, this.#initialSourceOptions, this.sourceOptions);
5810
6175
  this.actualOptions = loadContainerOptions(this.#pluginManager, this, this.#options);
5811
- this.plugins.length = 0;
5812
- this.particleDestroyedPlugins.length = 0;
5813
- this.particleCreatedPlugins.length = 0;
5814
- this.particlePositionPlugins.length = 0;
5815
- for (const [plugin, containerPlugin] of allContainerPlugins) {
5816
- if (plugin.needsPlugin(this.actualOptions)) {
5817
- this.plugins.push(containerPlugin);
5818
- if (containerPlugin.particleCreated) {
5819
- this.particleCreatedPlugins.push(containerPlugin);
5820
- }
5821
- if (containerPlugin.particleDestroyed) {
5822
- this.particleDestroyedPlugins.push(containerPlugin);
5823
- }
5824
- if (containerPlugin.particlePosition) {
5825
- this.particlePositionPlugins.push(containerPlugin);
5826
- }
5827
- }
5828
- }
6176
+ this.#initPlugins(allContainerPlugins);
5829
6177
  this.retina.init();
5830
6178
  this.canvas.init();
5831
6179
  this.updateActualOptions();
5832
6180
  this.canvas.initBackground();
5833
6181
  this.canvas.resize();
5834
- const { delay, duration, fpsLimit, hdr, smooth, zLayers } = this.actualOptions;
5835
- this.hdr = hdr;
6182
+ const { delay, duration, fpsLimit, smooth, zLayers } = this.actualOptions, hdrOptions = this.actualOptions.hdr;
6183
+ this.hdrMode = toEnumValue(HdrMode, hdrOptions.mode, HdrMode.standard);
6184
+ this.peakNits = hdrOptions.peakNits;
5836
6185
  this.zLayers = zLayers;
5837
6186
  this.#duration = getRangeValue(duration) * millisecondsToSeconds;
5838
6187
  this.#delay = getRangeValue(delay) * millisecondsToSeconds;
@@ -5852,9 +6201,9 @@
5852
6201
  }
5853
6202
  async initDrawersAndUpdaters() {
5854
6203
  const pluginManager = this.#pluginManager;
5855
- this.effectDrawers = await pluginManager.getEffectDrawers(this, true);
5856
- this.shapeDrawers = await pluginManager.getShapeDrawers(this, true);
5857
- this.particleUpdaters = await pluginManager.getUpdaters(this, true);
6204
+ this.effectDrawers = await getItemMapFromInitializer(this, pluginManager.initializers.effects);
6205
+ this.shapeDrawers = await getItemMapFromInitializer(this, pluginManager.initializers.shapes);
6206
+ this.particleUpdaters = await getItemsFromInitializer(this, pluginManager.initializers.updaters);
5858
6207
  }
5859
6208
  pause() {
5860
6209
  if (!guardCheck(this)) {
@@ -5965,6 +6314,27 @@
5965
6314
  }
5966
6315
  return refresh;
5967
6316
  }
6317
+ #initPlugins(allContainerPlugins) {
6318
+ this.plugins.length = 0;
6319
+ this.particleDestroyedPlugins.length = 0;
6320
+ this.particleCreatedPlugins.length = 0;
6321
+ this.particlePositionPlugins.length = 0;
6322
+ for (const [plugin, containerPlugin] of allContainerPlugins) {
6323
+ if (!plugin.needsPlugin(this.actualOptions)) {
6324
+ continue;
6325
+ }
6326
+ this.plugins.push(containerPlugin);
6327
+ if (containerPlugin.particleCreated) {
6328
+ this.particleCreatedPlugins.push(containerPlugin);
6329
+ }
6330
+ if (containerPlugin.particleDestroyed) {
6331
+ this.particleDestroyedPlugins.push(containerPlugin);
6332
+ }
6333
+ if (containerPlugin.particlePosition) {
6334
+ this.particlePositionPlugins.push(containerPlugin);
6335
+ }
6336
+ }
6337
+ }
5968
6338
  #nextFrame(timestamp) {
5969
6339
  try {
5970
6340
  if (!this.#smooth &&
@@ -6241,11 +6611,11 @@
6241
6611
  }
6242
6612
  }
6243
6613
  async #init() {
6244
- const availablePathGenerators = await this.#pluginManager.getPathGenerators?.(this.#container, true);
6245
- if (!availablePathGenerators) {
6614
+ const pluginManager = this.#pluginManager;
6615
+ if (!pluginManager.initializers.pathGenerators) {
6246
6616
  return;
6247
6617
  }
6248
- this.availablePathGenerators = availablePathGenerators;
6618
+ this.availablePathGenerators = await getItemMapFromInitializer(this.#container, pluginManager.initializers.pathGenerators);
6249
6619
  this.pathGenerators = new Map();
6250
6620
  for (const pathGenerator of this.pathGenerators.values()) {
6251
6621
  pathGenerator.init();
@@ -6349,28 +6719,12 @@
6349
6719
  }
6350
6720
  const html = interactivityEl, canvas = container.canvas;
6351
6721
  canvas.setPointerEvents(html === canvas.domElement ? "initial" : "none");
6352
- if (add && !(options.interactivity?.events.onHover.enable || options.interactivity?.events.onClick.enable)) {
6353
- return;
6354
- }
6355
6722
  manageListener(interactivityEl, mouseMoveEvent, handlers.mouseMove, add);
6356
6723
  manageListener(interactivityEl, touchStartEvent, handlers.touchStart, add);
6357
6724
  manageListener(interactivityEl, touchMoveEvent, handlers.touchMove, add);
6358
- if (add) {
6359
- if (options.interactivity?.events.onClick.enable) {
6360
- manageListener(interactivityEl, touchEndEvent, handlers.touchEndClick, add);
6361
- manageListener(interactivityEl, mouseUpEvent, handlers.mouseUp, add);
6362
- manageListener(interactivityEl, mouseDownEvent, handlers.mouseDown, add);
6363
- }
6364
- else {
6365
- manageListener(interactivityEl, touchEndEvent, handlers.touchEnd, add);
6366
- }
6367
- }
6368
- else {
6369
- manageListener(interactivityEl, touchEndEvent, handlers.touchEndClick, add);
6370
- manageListener(interactivityEl, mouseUpEvent, handlers.mouseUp, add);
6371
- manageListener(interactivityEl, mouseDownEvent, handlers.mouseDown, add);
6372
- manageListener(interactivityEl, touchEndEvent, handlers.touchEnd, add);
6373
- }
6725
+ manageListener(interactivityEl, touchEndEvent, options.interactivity?.events.onClick.enable ? handlers.touchEndClick : handlers.touchEnd, add);
6726
+ manageListener(interactivityEl, mouseUpEvent, handlers.mouseUp, add);
6727
+ manageListener(interactivityEl, mouseDownEvent, handlers.mouseDown, add);
6374
6728
  manageListener(interactivityEl, mouseLeaveEvent, handlers.mouseLeave, add);
6375
6729
  manageListener(interactivityEl, touchCancelEvent, handlers.touchCancel, add);
6376
6730
  }
@@ -6396,19 +6750,18 @@
6396
6750
  #mouseTouchClick(e) {
6397
6751
  const container = this.#container, interactionManager = this.#interactionManager, options = container.actualOptions, { mouse } = interactionManager.interactivityData;
6398
6752
  mouse.inside = true;
6399
- let handled = false;
6400
6753
  const mousePosition = mouse.position;
6401
- if (!mousePosition || !options.interactivity?.events.onClick.enable) {
6402
- return;
6403
- }
6404
- for (const plugin of this.#clickPositionPlugins) {
6405
- handled = plugin.clickPositionValid?.(mousePosition) ?? false;
6406
- if (handled) {
6407
- break;
6754
+ if (mousePosition && options.interactivity?.events.onClick.enable) {
6755
+ let handled = false;
6756
+ for (const plugin of this.#clickPositionPlugins) {
6757
+ handled = plugin.clickPositionValid?.(mousePosition) ?? false;
6758
+ if (handled) {
6759
+ break;
6760
+ }
6761
+ }
6762
+ if (!handled) {
6763
+ this.#doMouseTouchClick(e);
6408
6764
  }
6409
- }
6410
- if (!handled) {
6411
- this.#doMouseTouchClick(e);
6412
6765
  }
6413
6766
  mouse.clicking = false;
6414
6767
  }
@@ -6504,6 +6857,9 @@
6504
6857
  this.#touches.set(touch.identifier, performance.now());
6505
6858
  }
6506
6859
  this.#mouseTouchMove(e);
6860
+ const { mouse } = this.#interactionManager.interactivityData;
6861
+ mouse.clicking = true;
6862
+ mouse.downPosition = mouse.position;
6507
6863
  }
6508
6864
  }
6509
6865
 
@@ -6516,18 +6872,18 @@
6516
6872
  }
6517
6873
  class InteractionManager {
6518
6874
  interactivityData;
6875
+ interactors;
6519
6876
  #clickHandlers;
6520
6877
  #container;
6521
6878
  #eventListeners;
6522
6879
  #externalInteractors;
6523
- #interactors;
6524
6880
  #intersectionObserver;
6525
6881
  #particleInteractors;
6526
6882
  #pluginManager;
6527
6883
  constructor(pluginManager, container) {
6528
6884
  this.#container = container;
6529
6885
  this.#pluginManager = pluginManager;
6530
- this.#interactors = [];
6886
+ this.interactors = [];
6531
6887
  this.#externalInteractors = [];
6532
6888
  this.#particleInteractors = [];
6533
6889
  this.#clickHandlers = new Map();
@@ -6646,7 +7002,7 @@
6646
7002
  }
6647
7003
  init() {
6648
7004
  this.#eventListeners.init();
6649
- for (const interactor of this.#interactors) {
7005
+ for (const interactor of this.interactors) {
6650
7006
  switch (interactor.type) {
6651
7007
  case InteractorType.external:
6652
7008
  this.#externalInteractors.push(interactor);
@@ -6659,11 +7015,11 @@
6659
7015
  }
6660
7016
  }
6661
7017
  async initInteractors() {
6662
- const interactors = await this.#pluginManager.getInteractors?.(this.#container, true);
6663
- if (!interactors) {
7018
+ const pluginManager = this.#pluginManager;
7019
+ if (!pluginManager.initializers.interactors) {
6664
7020
  return;
6665
7021
  }
6666
- this.#interactors = interactors;
7022
+ this.interactors = await getItemsFromInitializer(this.#container, pluginManager.initializers.interactors);
6667
7023
  this.#externalInteractors = [];
6668
7024
  this.#particleInteractors = [];
6669
7025
  }
@@ -6708,13 +7064,13 @@
6708
7064
  }
6709
7065
  updateMaxDistance() {
6710
7066
  let maxTotalDistance = 0;
6711
- for (const interactor of this.#interactors) {
7067
+ for (const interactor of this.interactors) {
6712
7068
  if (interactor.maxDistance > maxTotalDistance) {
6713
7069
  maxTotalDistance = interactor.maxDistance;
6714
7070
  }
6715
7071
  }
6716
7072
  const container = this.#container;
6717
- container.particles.grid.setCellSize(maxTotalDistance * container.retina.pixelRatio);
7073
+ container.particles.grid.cellSize = maxTotalDistance * container.retina.pixelRatio;
6718
7074
  }
6719
7075
  #intersectionManager(entries) {
6720
7076
  const container = this.#container;
@@ -6736,59 +7092,59 @@
6736
7092
  }
6737
7093
 
6738
7094
  class InteractivityPluginInstance {
6739
- interactionManager;
6740
7095
  #container;
6741
- #pluginManager;
6742
7096
  constructor(pluginManager, container) {
6743
- this.#container = container;
6744
- this.#pluginManager = pluginManager;
6745
- this.interactionManager = new InteractionManager(pluginManager, container);
6746
- this.#container.addClickHandler = (callback) => {
6747
- this.interactionManager.addClickHandler(callback);
7097
+ container.addClickHandler = (callback) => {
7098
+ container.interactionManager?.addClickHandler(callback);
6748
7099
  };
7100
+ container.interactionManager = new InteractionManager(pluginManager, container);
7101
+ this.#container = container;
6749
7102
  }
6750
7103
  addClickHandler(callback) {
6751
- this.interactionManager.addClickHandler(callback);
7104
+ this.#container.interactionManager?.addClickHandler(callback);
6752
7105
  }
6753
7106
  clearClickHandlers() {
6754
- this.interactionManager.clearClickHandlers();
7107
+ this.#container.interactionManager?.clearClickHandlers();
6755
7108
  }
6756
7109
  destroy() {
6757
7110
  this.clearClickHandlers();
6758
- this.#pluginManager.interactors?.delete(this.#container);
6759
7111
  }
6760
7112
  particleCreated(particle) {
6761
- const interactivityParticle = particle, interactivity = new Interactivity(this.#pluginManager, this.#container);
6762
- interactivity.load(this.#container.actualOptions.interactivity);
7113
+ const interactivityParticle = particle, container = this.#container, interactivity = new Interactivity(container);
7114
+ interactivity.load(container.actualOptions.interactivity);
6763
7115
  interactivity.load(interactivityParticle.options.interactivity);
6764
7116
  interactivityParticle.interactivity = interactivity;
6765
7117
  }
6766
7118
  particleReset(particle) {
6767
- this.interactionManager.reset(particle);
7119
+ this.#container.interactionManager?.reset(particle);
6768
7120
  }
6769
7121
  postParticleUpdate(particle, delta) {
6770
- this.interactionManager.particlesInteract(particle, delta);
7122
+ this.#container.interactionManager?.particlesInteract(particle, delta);
6771
7123
  }
6772
7124
  postUpdate(delta) {
6773
- this.interactionManager.externalInteract(delta);
6774
- this.interactionManager.updateMaxDistance();
7125
+ const container = this.#container;
7126
+ container.interactionManager?.externalInteract(delta);
7127
+ container.interactionManager?.updateMaxDistance();
6775
7128
  }
6776
7129
  async preInit() {
6777
- await this.interactionManager.initInteractors();
6778
- this.interactionManager.init();
7130
+ const container = this.#container;
7131
+ await container.interactionManager?.initInteractors();
7132
+ container.interactionManager?.init();
6779
7133
  }
6780
7134
  async redrawInit() {
6781
- await this.interactionManager.initInteractors();
6782
- this.interactionManager.init();
7135
+ const container = this.#container;
7136
+ await container.interactionManager?.initInteractors();
7137
+ container.interactionManager?.init();
6783
7138
  }
6784
7139
  start() {
6785
- this.interactionManager.addListeners();
6786
- this.interactionManager.startObserving();
7140
+ const container = this.#container;
7141
+ container.interactionManager?.addListeners();
7142
+ container.interactionManager?.startObserving();
6787
7143
  return Promise.resolve();
6788
7144
  }
6789
7145
  stop() {
6790
- this.interactionManager.removeListeners();
6791
- this.interactionManager.stopObserving();
7146
+ this.#container.interactionManager?.removeListeners();
7147
+ this.#container.interactionManager?.stopObserving();
6792
7148
  }
6793
7149
  }
6794
7150
 
@@ -6958,10 +7314,10 @@
6958
7314
  }
6959
7315
  }
6960
7316
  #getCachedStyle(rgb) {
6961
- const key = `${rgb.r},${rgb.g},${rgb.b}`;
7317
+ const key = `${rgb.r},${rgb.g},${rgb.b}-${this.#container.hdr}-${this.#container.peakNits}-${this.#container.hdrMode}`;
6962
7318
  let style = this.#colorCache.get(key);
6963
7319
  if (!style) {
6964
- style = getStyleFromRgb(rgb, this.#container.hdr);
7320
+ style = getStyleFromRgb(rgb, this.#container.hdr, undefined, this.#container.peakNits, this.#container.hdrMode);
6965
7321
  this.#colorCache.set(key, style);
6966
7322
  }
6967
7323
  return style;
@@ -6982,6 +7338,7 @@
6982
7338
  exports.loadTrianglesPreset = loadTrianglesPreset;
6983
7339
  exports.tsParticles = tsParticles;
6984
7340
 
6985
- }));
7341
+ })(g.__tsParticlesInternals.presets.triangles = g.__tsParticlesInternals.presets.triangles || {});
7342
+ })(typeof globalThis !== "undefined" ? globalThis : typeof window !== "undefined" ? window : self);
7343
+
6986
7344
  Object.assign(globalThis.window || globalThis, { loadTrianglesPreset: (globalThis.__tsParticlesInternals.presets.triangles || {}).loadTrianglesPreset });
6987
- delete (globalThis.window || globalThis).tsparticlesInternalExports;