@tsparticles/preset-links 4.4.0 → 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.4.0 */
3
- (function (global, factory) {
4
- typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
5
- typeof define === 'function' && define.amd ? define(['exports'], factory) :
6
- (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory((global.__tsParticlesInternals = global.__tsParticlesInternals || {}, global.__tsParticlesInternals.presets = global.__tsParticlesInternals.presets || {}, global.__tsParticlesInternals.presets.links = global.__tsParticlesInternals.presets.links || {})));
7
- })(this, (function (exports) { 'use strict';
8
-
9
- const generatedAttribute = "generated", defaultCompositeValue = "source-over", resizeEvent = "resize", visibilityChangeEvent = "visibilitychange", percentDenominator = 100, half = 0.5, millisecondsToSeconds = 1000, originPoint = {
10
- x: 0,
11
- y: 0,
12
- z: 0,
13
- }, defaultTransform = {
14
- a: 1,
15
- b: 0,
16
- c: 0,
17
- d: 1,
18
- }, randomColorValue = "random", midColorValue = "mid", double = 2, doublePI = Math.PI * double, defaultFps = 60, generatedTrue = "true", generatedFalse = "false", canvasTag = "canvas", defaultRetryCount = 0, squareExp = 2, spatialHashGridCellSize = 100, defaultRemoveQuantity = 1, defaultRatio = 1, defaultReduceFactor = 1, inverseFactorNumerator = 1, rgbMax = 255, hMax = 360, sMax = 100, lMax = 100, hMin = 0, sMin = 0, hPhase = 60, empty = 0, quarter = 0.25, threeQuarter = half + quarter, minVelocity = 0, minDistance$2 = 0, defaultTransformValue = 1, minimumSize = 0, zIndexFactorOffset = 1, defaultOpacity$1 = 1, removeDeleteCount = 1, removeMinIndex = 0, defaultFpsLimit = 120, minFpsLimit = 0, canvasFirstIndex = 0, loadRandomFactor = 10000, loadMinIndex = 0, one = 1, none = 0, decayOffset = 1, tryCountIncrement = 1, minZ = 0, minLimit = 0, countOffset = 1, minCount = 0, minIndex = 0, lengthOffset = 1, defaultDensityFactor = 1, deleteCount = 1, defaultAngle = 0, identity = 1, minStrokeWidth = 0, lFactor = 1, lMin = 0, maxNits = 400, triple = 3, sextuple = 6, sNormalizedOffset = 1, phaseNumerator = 1, defaultRgbMin = 0, defaultVelocity = 0, defaultLoops = 0, defaultTime = 0, defaultZoom = 1;
1
+ (function(g){g.__tsParticlesInternals=g.__tsParticlesInternals||{};g.__tsParticlesInternals.bundles=g.__tsParticlesInternals.bundles||{};g.__tsParticlesInternals.effects=g.__tsParticlesInternals.effects||{};g.__tsParticlesInternals.engine=g.__tsParticlesInternals.engine||{};g.__tsParticlesInternals.interactions=g.__tsParticlesInternals.interactions||{};g.__tsParticlesInternals.palettes=g.__tsParticlesInternals.palettes||{};g.__tsParticlesInternals.paths=g.__tsParticlesInternals.paths||{};g.__tsParticlesInternals.plugins=g.__tsParticlesInternals.plugins||{};g.__tsParticlesInternals.plugins=g.__tsParticlesInternals.plugins||{};g.__tsParticlesInternals.plugins.emittersShapes=g.__tsParticlesInternals.plugins.emittersShapes||{};g.__tsParticlesInternals.presets=g.__tsParticlesInternals.presets||{};g.__tsParticlesInternals.shapes=g.__tsParticlesInternals.shapes||{};g.__tsParticlesInternals.updaters=g.__tsParticlesInternals.updaters||{};g.__tsParticlesInternals.utils=g.__tsParticlesInternals.utils||{};g.__tsParticlesInternals.canvas=g.__tsParticlesInternals.canvas||{};g.__tsParticlesInternals.canvas=g.__tsParticlesInternals.canvas||{};g.__tsParticlesInternals.canvas.utils=g.__tsParticlesInternals.canvas.utils||{};g.__tsParticlesInternals.path=g.__tsParticlesInternals.path||{};g.__tsParticlesInternals.path=g.__tsParticlesInternals.path||{};g.__tsParticlesInternals.path.utils=g.__tsParticlesInternals.path.utils||{};var __tsProxyFactory=typeof Proxy!=="undefined"?function(obj){return new Proxy(obj,{get:function(target,key){if(!(key in target)){target[key]={};}return target[key];}});}:function(obj){return obj;};g.__tsParticlesInternals.bundles=__tsProxyFactory(g.__tsParticlesInternals.bundles);g.__tsParticlesInternals.effects=__tsProxyFactory(g.__tsParticlesInternals.effects);g.__tsParticlesInternals.interactions=__tsProxyFactory(g.__tsParticlesInternals.interactions);g.__tsParticlesInternals.palettes=__tsProxyFactory(g.__tsParticlesInternals.palettes);g.__tsParticlesInternals.paths=__tsProxyFactory(g.__tsParticlesInternals.paths);g.__tsParticlesInternals.plugins=__tsProxyFactory(g.__tsParticlesInternals.plugins);g.__tsParticlesInternals.plugins.emittersShapes=__tsProxyFactory(g.__tsParticlesInternals.plugins.emittersShapes);g.__tsParticlesInternals.presets=__tsProxyFactory(g.__tsParticlesInternals.presets);g.__tsParticlesInternals.shapes=__tsProxyFactory(g.__tsParticlesInternals.shapes);g.__tsParticlesInternals.updaters=__tsProxyFactory(g.__tsParticlesInternals.updaters);g.__tsParticlesInternals.utils=__tsProxyFactory(g.__tsParticlesInternals.utils);g.__tsParticlesInternals.canvas=__tsProxyFactory(g.__tsParticlesInternals.canvas);g.__tsParticlesInternals.path=__tsProxyFactory(g.__tsParticlesInternals.path);})(typeof globalThis!=="undefined"?globalThis:typeof window!=="undefined"?window:this);
2
+ (function (g) {
3
+ /* Preset v4.5.0 */
4
+ g.__tsParticlesInternals = g.__tsParticlesInternals || {};
5
+ g.__tsParticlesInternals.presets = g.__tsParticlesInternals.presets || {};
6
+ (function (exports) {
7
+ 'use strict';
8
+
9
+ const errorPrefix = "tsParticles - Error", codedErrorPattern = /^\[tsParticles Error (TSP-\d+)\]\s*/, fullMatchIndex = 0, codeIndex = 1;
10
+ const wrap = (fn) => (...args) => {
11
+ fn(...args);
12
+ }, _logger = {
13
+ debug: wrap(console.debug),
14
+ error: (message, ...optionalParams) => {
15
+ if (typeof message === "string") {
16
+ const match = codedErrorPattern.exec(message);
17
+ if (match?.[codeIndex]) {
18
+ console.error(`tsParticles - ${match[codeIndex]} - ${message.slice(match[fullMatchIndex].length)}`, ...optionalParams);
19
+ return;
20
+ }
21
+ }
22
+ console.error(`${errorPrefix} - ${message}`, ...optionalParams);
23
+ },
24
+ info: wrap(console.info),
25
+ log: wrap(console.log),
26
+ trace: wrap(console.trace),
27
+ verbose: wrap(console.log),
28
+ warning: wrap(console.warn),
29
+ };
30
+ function getLogger() {
31
+ return _logger;
32
+ }
19
33
 
20
34
  var MoveDirection;
21
35
  (function (MoveDirection) {
@@ -32,6 +46,17 @@
32
46
  MoveDirection["inside"] = "inside";
33
47
  })(MoveDirection || (MoveDirection = {}));
34
48
 
49
+ const generatedAttribute = "generated", fullPercent = "100%", defaultCompositeValue = "source-over", resizeEvent = "resize", visibilityChangeEvent = "visibilitychange", percentDenominator = 100, half = 0.5, millisecondsToSeconds = 1000, originPoint = {
50
+ x: 0,
51
+ y: 0,
52
+ z: 0,
53
+ }, defaultTransform = {
54
+ a: 1,
55
+ b: 0,
56
+ c: 0,
57
+ d: 1,
58
+ }, randomColorValue = "random", midColorValue = "mid", double = 2, doublePI = Math.PI * double, defaultFps = 60, defaultAlpha = 1, generatedTrue = "true", generatedFalse = "false", canvasTag = "canvas", defaultRetryCount = 0, squareExp = 2, spatialHashGridCellSize = 100, defaultRemoveQuantity = 1, defaultRatio = 1, defaultReduceFactor = 1, inverseFactorNumerator = 1, rgbMax = 255, hMax = 360, sMax = 100, lMax = 100, hMin = 0, sMin = 0, hPhase = 60, empty = 0, quarter = 0.25, threeQuarter = half + quarter, minVelocity = 0, minDistance$2 = 0, minRadius = 0, defaultTransformValue = 1, minimumSize = 0, zIndexFactorOffset = 1, defaultOpacity$1 = 1, removeDeleteCount = 1, removeMinIndex = 0, defaultFpsLimit = 120, minFpsLimit = 0, canvasFirstIndex = 0, loadRandomFactor = 10000, loadMinIndex = 0, one = 1, none = 0, decayOffset = 1, tryCountIncrement = 1, minZ = 0, minLimit = 0, countOffset = 1, minCount = 0, minIndex = 0, lengthOffset = 1, defaultDensityFactor = 1, deleteCount = 1, defaultAngle = 0, identity = 1, minStrokeWidth = 0, lFactor = 1, lMin = 0, maxNits = 400, triple = 3, sextuple = 6, sNormalizedOffset = 1, phaseNumerator = 1, defaultRgbMin = 0, defaultVelocity = 0, defaultLoops = 0, defaultTime = 0, defaultZoom = 1;
59
+
35
60
  function getZ(source) {
36
61
  return "z" in source ? source.z : originPoint.z;
37
62
  }
@@ -147,6 +172,12 @@
147
172
  function isNumber(arg) {
148
173
  return typeof arg === "number";
149
174
  }
175
+ function isEnumValue(enumObject, arg) {
176
+ return Object.values(enumObject).some(enumValue => enumValue === arg);
177
+ }
178
+ function toEnumValue(enumObject, arg, defaultValue) {
179
+ return isEnumValue(enumObject, arg) ? arg : defaultValue;
180
+ }
150
181
  function isObject(arg) {
151
182
  return typeof arg === "object" && arg !== null;
152
183
  }
@@ -273,11 +304,61 @@
273
304
  };
274
305
  }
275
306
  function parseAlpha(input) {
276
- const defaultAlpha = 1;
277
307
  if (!input) {
278
308
  return defaultAlpha;
279
309
  }
280
- return input.endsWith("%") ? parseFloat(input) / percentDenominator : parseFloat(input);
310
+ return input.endsWith("%") ? Number.parseFloat(input) / percentDenominator : Number.parseFloat(input);
311
+ }
312
+
313
+ const ErrorCodes$2 = {
314
+ engineVersionMismatch: "TSP-1001",
315
+ particlePositionNotFound: "TSP-1002",
316
+ pluginRegisterAfterLoad: "TSP-1003",
317
+ offscreenCanvasUnsupported: "TSP-1101",
318
+ offscreenCanvasTransferFailed: "TSP-1102",
319
+ hdrEnableInvalid: "TSP-1201",
320
+ hdrModeInvalid: "TSP-1202",
321
+ hdrPeakNitsInvalid: "TSP-1203",
322
+ };
323
+
324
+ const messages = {
325
+ [ErrorCodes$2.engineVersionMismatch]: "The tsParticles version is different from the loaded plugins version. Engine version: {0}. Plugin version: {1}",
326
+ [ErrorCodes$2.particlePositionNotFound]: "a valid position cannot be found for particle",
327
+ [ErrorCodes$2.pluginRegisterAfterLoad]: "Register plugins can only be done before calling tsParticles.load()",
328
+ [ErrorCodes$2.offscreenCanvasUnsupported]: "OffscreenCanvas is required but not supported by this browser",
329
+ [ErrorCodes$2.offscreenCanvasTransferFailed]: "OffscreenCanvas transfer failed",
330
+ [ErrorCodes$2.hdrEnableInvalid]: 'Invalid HDR "enable" value: expected a boolean, got "{0}"',
331
+ [ErrorCodes$2.hdrModeInvalid]: 'Invalid HDR "mode" value: expected one of {0}, got "{1}"',
332
+ [ErrorCodes$2.hdrPeakNitsInvalid]: 'Invalid HDR "peakNits" value: expected a positive number, got "{0}"',
333
+ };
334
+
335
+ let registeredMessages;
336
+ const ensureRegisteredMessages = () => {
337
+ registeredMessages ??= new Map(Object.entries(messages));
338
+ return registeredMessages;
339
+ }, toStringValue$1 = (value) => String(value), format = (template, args) => {
340
+ return template.replace(/\{(\d+)\}/g, (match, index) => {
341
+ const arg = args[Number(index)];
342
+ return arg === undefined ? match : toStringValue$1(arg);
343
+ });
344
+ };
345
+ function addErrorMessages(extraMessages) {
346
+ if (typeof process !== "undefined" && process.env.NODE_ENV === "production") {
347
+ return;
348
+ }
349
+ const catalog = ensureRegisteredMessages();
350
+ for (const [code, message] of Object.entries(extraMessages)) {
351
+ if (message !== undefined) {
352
+ catalog.set(code, message);
353
+ }
354
+ }
355
+ }
356
+ function getErrorMessage(code, ...args) {
357
+ if (typeof process !== "undefined" && process.env.NODE_ENV === "production") {
358
+ return `[tsParticles Error ${code}] https://particles.js.org/errors/#${code}`;
359
+ }
360
+ const template = ensureRegisteredMessages().get(code) ?? `Unknown error code ${code}`;
361
+ return format(template, args);
281
362
  }
282
363
 
283
364
  var OutModeDirection;
@@ -294,7 +375,6 @@
294
375
  PixelMode["percent"] = "percent";
295
376
  })(PixelMode || (PixelMode = {}));
296
377
 
297
- const minRadius = 0;
298
378
  function isForbiddenKey(key) {
299
379
  return key === "__proto__" || key === "constructor" || key === "prototype";
300
380
  }
@@ -490,22 +570,84 @@
490
570
  element.removeEventListener(event, handler, removeOptions);
491
571
  }
492
572
  }
493
- async function getItemsFromInitializer(container, map, initializers, force = false) {
494
- let res = map.get(container);
495
- if (!res || force) {
496
- res = await Promise.all([...initializers.values()].map(t => t(container)));
497
- map.set(container, res);
573
+ async function getItemsFromInitializer(container, initializers) {
574
+ return await Promise.all([...initializers.values()].map(t => t(container)));
575
+ }
576
+ async function getItemMapFromInitializer(container, initializers) {
577
+ const entries = await Promise.all([...initializers.entries()].map(([key, initializer]) => initializer(container).then(item => [key, item])));
578
+ return new Map(entries);
579
+ }
580
+ async function getDataFromUrl(data) {
581
+ const url = itemFromSingleOrMultiple(data.url, data.index);
582
+ if (!url) {
583
+ return data.fallback;
498
584
  }
499
- return res;
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;
500
602
  }
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);
603
+ function isSourceOptionsValue(value) {
604
+ if (isArray(value)) {
605
+ return value.every((entry) => isObject(entry) && !isArray(entry));
507
606
  }
508
- return res;
607
+ return isObject(value) && !isArray(value);
608
+ }
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
+ }
621
+ }
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.4.0";
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);
@@ -1058,20 +1133,6 @@
1058
1133
  DrawLayer[DrawLayer["Foreground"] = 7] = "Foreground";
1059
1134
  })(DrawLayer || (DrawLayer = {}));
1060
1135
 
1061
- class OptionLoader {
1062
- load(data) {
1063
- if (isNull(data)) {
1064
- return;
1065
- }
1066
- this.doLoad(data);
1067
- }
1068
- }
1069
- function loadOptions(options, ...sourceOptionsArr) {
1070
- for (const sourceOptions of sourceOptionsArr) {
1071
- options.load(sourceOptions);
1072
- }
1073
- }
1074
-
1075
1136
  function loadProperty(obj, key, value) {
1076
1137
  if (value !== undefined) {
1077
1138
  obj[key] = value;
@@ -1103,6 +1164,20 @@
1103
1164
  }
1104
1165
  }
1105
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
+
1106
1181
  class AnimationOptions extends OptionLoader {
1107
1182
  count = 0;
1108
1183
  decay = 0;
@@ -1253,15 +1328,14 @@
1253
1328
  peakNits = defaultPeakNits;
1254
1329
  doLoad(data) {
1255
1330
  if (data.enable !== undefined && !isBoolean(data.enable)) {
1256
- throw new Error(`Invalid HDR "enable" value: expected a boolean, got "${String(data.enable)}"`);
1331
+ throw new Error(getErrorMessage(ErrorCodes$2.hdrEnableInvalid, String(data.enable)));
1257
1332
  }
1258
- if (data.mode !== undefined &&
1259
- (typeof data.mode !== "string" || !Object.values(HdrMode).includes(data.mode))) {
1260
- throw new Error(`Invalid HDR "mode" value: expected one of ${Object.values(HdrMode).join(", ")}, got "${toStringValue(data.mode)}"`);
1333
+ if (data.mode !== undefined && !isEnumValue(HdrMode, data.mode)) {
1334
+ throw new Error(getErrorMessage(ErrorCodes$2.hdrModeInvalid, Object.values(HdrMode).join(", "), toStringValue(data.mode)));
1261
1335
  }
1262
1336
  if (data.peakNits !== undefined &&
1263
1337
  (!isNumber(data.peakNits) || !Number.isFinite(data.peakNits) || data.peakNits <= minPeakNits)) {
1264
- throw new Error(`Invalid HDR "peakNits" value: expected a positive number, got "${String(data.peakNits)}"`);
1338
+ throw new Error(getErrorMessage(ErrorCodes$2.hdrPeakNitsInvalid, String(data.peakNits)));
1265
1339
  }
1266
1340
  loadProperty(this, "enable", data.enable);
1267
1341
  loadProperty(this, "mode", data.mode);
@@ -1639,12 +1713,10 @@
1639
1713
  plugin.loadParticlesOptions(this.#container, this, data);
1640
1714
  }
1641
1715
  }
1642
- const updaters = this.#pluginManager.updaters.get(this.#container);
1643
- if (updaters) {
1644
- for (const updater of updaters) {
1645
- if (updater.loadOptions) {
1646
- updater.loadOptions(this, data);
1647
- }
1716
+ const updaters = this.#container.particleUpdaters;
1717
+ for (const updater of updaters) {
1718
+ if (updater.loadOptions) {
1719
+ updater.loadOptions(this, data);
1648
1720
  }
1649
1721
  }
1650
1722
  }
@@ -1983,9 +2055,9 @@
1983
2055
  const grayscaleValue = Math.round(lNormalized * rgbMax);
1984
2056
  return { r: grayscaleValue, g: grayscaleValue, b: grayscaleValue };
1985
2057
  }
1986
- const temp1 = lNormalized < half
2058
+ const temp2 = lNormalized < half
1987
2059
  ? lNormalized * (sNormalizedOffset + sNormalized)
1988
- : 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));
1989
2061
  return { r: Math.round(red), g: Math.round(green), b: Math.round(blue) };
1990
2062
  }
1991
2063
  function hslToRgbFloat(hsl) {
@@ -1994,9 +2066,9 @@
1994
2066
  const grayscaleValue = lNormalized * rgbMax;
1995
2067
  return { r: grayscaleValue, g: grayscaleValue, b: grayscaleValue };
1996
2068
  }
1997
- const temp1 = lNormalized < half
2069
+ const temp2 = lNormalized < half
1998
2070
  ? lNormalized * (sNormalizedOffset + sNormalized)
1999
- : 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));
2000
2072
  return { r: red, g: green, b: blue };
2001
2073
  }
2002
2074
  function hslaToRgba(hsla) {
@@ -2283,7 +2355,7 @@
2283
2355
  }
2284
2356
 
2285
2357
  async function loadBlendPlugin(engine) {
2286
- engine.checkVersion("4.4.0");
2358
+ engine.checkVersion("4.5.0");
2287
2359
  await engine.pluginManager.register(e => {
2288
2360
  e.pluginManager.addPlugin(new BlendPlugin());
2289
2361
  });
@@ -2320,7 +2392,7 @@
2320
2392
  }
2321
2393
 
2322
2394
  async function loadCircleShape(engine) {
2323
- engine.checkVersion("4.4.0");
2395
+ engine.checkVersion("4.5.0");
2324
2396
  await engine.pluginManager.register(e => {
2325
2397
  e.pluginManager.addShape(["circle"], () => {
2326
2398
  return Promise.resolve(new CircleDrawer());
@@ -2335,7 +2407,7 @@
2335
2407
  RgbIndexes[RgbIndexes["b"] = 3] = "b";
2336
2408
  RgbIndexes[RgbIndexes["a"] = 4] = "a";
2337
2409
  })(RgbIndexes$1 || (RgbIndexes$1 = {}));
2338
- 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;
2339
2411
  class HexColorManager {
2340
2412
  accepts(input) {
2341
2413
  return input.startsWith("#");
@@ -2368,7 +2440,7 @@
2368
2440
  }
2369
2441
 
2370
2442
  async function loadHexColorPlugin(engine) {
2371
- engine.checkVersion("4.4.0");
2443
+ engine.checkVersion("4.5.0");
2372
2444
  await engine.pluginManager.register(e => {
2373
2445
  e.pluginManager.addColorManager("hex", new HexColorManager());
2374
2446
  });
@@ -2408,7 +2480,7 @@
2408
2480
  if (!this.accepts(input)) {
2409
2481
  return;
2410
2482
  }
2411
- const result = hslRegex.exec(input), minLength = 4, defaultAlpha = 1, radix = 10;
2483
+ const result = hslRegex.exec(input), minLength = 4, radix = 10;
2412
2484
  return result
2413
2485
  ? hslaToRgba({
2414
2486
  a: result.length > minLength ? parseAlpha(result[HslIndexes.a]) : defaultAlpha,
@@ -2421,12 +2493,20 @@
2421
2493
  }
2422
2494
 
2423
2495
  async function loadHslColorPlugin(engine) {
2424
- engine.checkVersion("4.4.0");
2496
+ engine.checkVersion("4.5.0");
2425
2497
  await engine.pluginManager.register(e => {
2426
2498
  e.pluginManager.addColorManager("hsl", new HslColorManager());
2427
2499
  });
2428
2500
  }
2429
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
+
2430
2510
  class MovePlugin {
2431
2511
  id = "move";
2432
2512
  #pluginManager;
@@ -2445,20 +2525,20 @@
2445
2525
  }
2446
2526
 
2447
2527
  async function loadMovePlugin(engine) {
2448
- engine.checkVersion("4.4.0");
2528
+ engine.checkVersion("4.5.0");
2529
+ if (typeof process !== "undefined" && process.env.NODE_ENV !== "production") {
2530
+ addErrorMessages(ErrorMessages$1);
2531
+ }
2449
2532
  await engine.pluginManager.register(e => {
2450
2533
  const moveEngine = e, movePluginManager = moveEngine.pluginManager;
2451
2534
  movePluginManager.initializers.pathGenerators ??= new Map();
2452
- movePluginManager.pathGenerators ??= new Map();
2453
2535
  movePluginManager.addPathGenerator = (name, generator) => {
2536
+ if (movePluginManager.initialized) {
2537
+ return;
2538
+ }
2454
2539
  movePluginManager.initializers.pathGenerators ??= new Map();
2455
2540
  movePluginManager.initializers.pathGenerators.set(name, generator);
2456
2541
  };
2457
- movePluginManager.getPathGenerators = async (container, force = false) => {
2458
- movePluginManager.initializers.pathGenerators ??= new Map();
2459
- movePluginManager.pathGenerators ??= new Map();
2460
- return getItemMapFromInitializer(container, movePluginManager.pathGenerators, movePluginManager.initializers.pathGenerators, force);
2461
- };
2462
2542
  e.pluginManager.addPlugin(new MovePlugin(e.pluginManager));
2463
2543
  });
2464
2544
  }
@@ -2655,7 +2735,7 @@
2655
2735
  }
2656
2736
 
2657
2737
  async function loadOpacityUpdater(engine) {
2658
- engine.checkVersion("4.4.0");
2738
+ engine.checkVersion("4.5.0");
2659
2739
  await engine.pluginManager.register(e => {
2660
2740
  e.pluginManager.addParticleUpdater("opacity", container => {
2661
2741
  return Promise.resolve(new OpacityUpdater(container));
@@ -2664,70 +2744,60 @@
2664
2744
  }
2665
2745
 
2666
2746
  const boundsMin = 0;
2667
- function bounceHorizontal(data) {
2668
- if ((data.outMode !== OutMode.bounce && data.outMode !== OutMode.split) ||
2669
- (data.direction !== OutModeDirection.left && data.direction !== OutModeDirection.right)) {
2670
- return;
2671
- }
2672
- if (data.bounds.right < boundsMin && data.direction === OutModeDirection.left) {
2673
- data.particle.position.x = data.size + data.offset.x;
2674
- }
2675
- else if (data.bounds.left > data.canvasSize.width && data.direction === OutModeDirection.right) {
2676
- data.particle.position.x = data.canvasSize.width - data.size - data.offset.x;
2677
- }
2678
- const velocity = data.particle.velocity.x;
2679
- let bounced = false;
2680
- if (data.outOfCanvas &&
2681
- ((data.direction === OutModeDirection.right && velocity > minVelocity) ||
2682
- (data.direction === OutModeDirection.left && velocity < minVelocity))) {
2683
- const newVelocity = getRangeValue(data.particle.options.bounce.horizontal.value);
2684
- data.particle.velocity.x *= -newVelocity;
2685
- bounced = true;
2686
- }
2687
- if (!bounced) {
2688
- return;
2689
- }
2690
- const minPos = data.offset.x + data.size;
2691
- if (data.outOfCanvas && data.direction === OutModeDirection.right) {
2692
- data.particle.position.x = data.canvasSize.width - minPos;
2693
- }
2694
- else if (data.outOfCanvas && data.direction === OutModeDirection.left) {
2695
- data.particle.position.x = minPos;
2696
- }
2697
- if (data.outMode === OutMode.split) {
2698
- data.particle.destroy();
2699
- }
2700
- }
2701
- function bounceVertical(data) {
2702
- if ((data.outMode !== OutMode.bounce && data.outMode !== OutMode.split) ||
2703
- (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)) {
2704
2783
  return;
2705
2784
  }
2706
- if (data.bounds.bottom < boundsMin && data.direction === OutModeDirection.top) {
2707
- 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];
2708
2788
  }
2709
- else if (data.bounds.top > data.canvasSize.height && data.direction === OutModeDirection.bottom) {
2710
- 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];
2711
2791
  }
2712
- const velocity = data.particle.velocity.y;
2713
- let bounced = false;
2714
2792
  if (data.outOfCanvas &&
2715
- ((data.direction === OutModeDirection.bottom && velocity > minVelocity) ||
2716
- (data.direction === OutModeDirection.top && velocity < minVelocity))) {
2717
- const newVelocity = getRangeValue(data.particle.options.bounce.vertical.value);
2718
- data.particle.velocity.y *= -newVelocity;
2719
- 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);
2720
2795
  }
2721
- if (!bounced) {
2796
+ else {
2722
2797
  return;
2723
2798
  }
2724
- const minPos = data.offset.y + data.size;
2725
- if (data.outOfCanvas && data.direction === OutModeDirection.bottom) {
2726
- data.particle.position.y = data.canvasSize.height - minPos;
2727
- }
2728
- else if (data.outOfCanvas && data.direction === OutModeDirection.top) {
2729
- data.particle.position.y = minPos;
2730
- }
2799
+ const minPos = data.offset[config.axis] + data.size;
2800
+ position[config.axis] = config.negative ? minPos : canvasDim - minPos;
2731
2801
  if (data.outMode === OutMode.split) {
2732
2802
  data.particle.destroy();
2733
2803
  }
@@ -2743,26 +2813,19 @@
2743
2813
  OutMode.bounce,
2744
2814
  OutMode.split,
2745
2815
  ];
2746
- this.#particleBouncePlugins = container.plugins.filter(p => p.particleBounce !== undefined);
2816
+ this.#particleBouncePlugins = container.plugins.filter(p => !!p.particleBounce);
2747
2817
  }
2748
2818
  update(particle, direction, delta, outMode) {
2749
2819
  if (!this.modes.includes(outMode)) {
2750
2820
  return;
2751
2821
  }
2752
- const container = this.#container;
2753
- let handled = false;
2754
2822
  for (const plugin of this.#particleBouncePlugins) {
2755
- handled = plugin.particleBounce?.(particle, delta, direction) ?? false;
2756
- if (handled) {
2757
- break;
2823
+ if (plugin.particleBounce?.(particle, delta, direction)) {
2824
+ return;
2758
2825
  }
2759
2826
  }
2760
- if (handled) {
2761
- return;
2762
- }
2763
- const pos = particle.getPosition(), offset = particle.offset, size = particle.getRadius(), bounds = calculateBounds(pos, size), canvasSize = container.canvas.size, outOfCanvas = !particle.isInsideCanvasForOutMode(outMode, direction);
2764
- bounceHorizontal({ particle, outMode, direction, bounds, canvasSize, offset, outOfCanvas, size });
2765
- 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 });
2766
2829
  }
2767
2830
  }
2768
2831
 
@@ -2851,107 +2914,108 @@
2851
2914
  return;
2852
2915
  }
2853
2916
  const container = this.#container;
2854
- switch (particle.outType) {
2855
- case ParticleOutType.inside: {
2856
- const { x: vx, y: vy } = particle.velocity;
2857
- updateVector.setTo(originPoint);
2858
- updateVector.length = particle.moveCenter.radius;
2859
- updateVector.angle = particle.velocity.angle + Math.PI;
2860
- updateVector.addTo(particle.moveCenter);
2861
- const { dx, dy } = getDistances(particle.position, updateVector);
2862
- if ((vx <= minVelocity && dx >= minDistance$2) ||
2863
- (vy <= minVelocity && dy >= minDistance$2) ||
2864
- (vx >= minVelocity && dx <= minDistance$2) ||
2865
- (vy >= minVelocity && dy <= minDistance$2)) {
2866
- return;
2867
- }
2868
- particle.position.x = Math.floor(randomInRangeValue({
2869
- min: 0,
2870
- max: container.canvas.size.width,
2871
- }));
2872
- particle.position.y = Math.floor(randomInRangeValue({
2873
- min: 0,
2874
- max: container.canvas.size.height,
2875
- }));
2876
- const { dx: newDx, dy: newDy } = getDistances(particle.position, particle.moveCenter);
2877
- particle.direction = Math.atan2(-newDy, -newDx);
2878
- particle.velocity.angle = particle.direction;
2879
- particle.justWarped = true;
2880
- break;
2917
+ if (particle.outType === ParticleOutType.inside) {
2918
+ this.#applyOutModeInside(particle, container);
2919
+ }
2920
+ else {
2921
+ if (particle.isInsideCanvasForOutMode(outMode, direction)) {
2922
+ return;
2881
2923
  }
2882
- default: {
2883
- if (particle.isInsideCanvasForOutMode(outMode, direction)) {
2884
- return;
2885
- }
2886
- switch (particle.outType) {
2887
- case ParticleOutType.outside: {
2888
- particle.position.x =
2889
- Math.floor(randomInRangeValue({
2890
- min: -particle.moveCenter.radius,
2891
- max: particle.moveCenter.radius,
2892
- })) + particle.moveCenter.x;
2893
- particle.position.y =
2894
- Math.floor(randomInRangeValue({
2895
- min: -particle.moveCenter.radius,
2896
- max: particle.moveCenter.radius,
2897
- })) + particle.moveCenter.y;
2898
- const { dx, dy } = getDistances(particle.position, particle.moveCenter);
2899
- if (particle.moveCenter.radius) {
2900
- particle.direction = Math.atan2(dy, dx);
2901
- particle.velocity.angle = particle.direction;
2902
- }
2903
- particle.justWarped = true;
2904
- break;
2905
- }
2906
- case ParticleOutType.normal: {
2907
- const warp = particle.options.move.warp, canvasSize = container.canvas.size, newPos = {
2908
- bottom: canvasSize.height + particle.getRadius() + particle.offset.y,
2909
- left: -particle.getRadius() - particle.offset.x,
2910
- right: canvasSize.width + particle.getRadius() + particle.offset.x,
2911
- top: -particle.getRadius() - particle.offset.y,
2912
- }, sizeValue = particle.getRadius(), nextBounds = calculateBounds(particle.position, sizeValue);
2913
- if (direction === OutModeDirection.right && nextBounds.left > canvasSize.width + particle.offset.x) {
2914
- particle.position.x = newPos.left;
2915
- particle.initialPosition.x = particle.position.x;
2916
- if (!warp) {
2917
- particle.position.y = getRandom() * canvasSize.height;
2918
- particle.initialPosition.y = particle.position.y;
2919
- }
2920
- particle.justWarped = true;
2921
- }
2922
- else if (direction === OutModeDirection.left && nextBounds.right < -particle.offset.x) {
2923
- particle.position.x = newPos.right;
2924
- particle.initialPosition.x = particle.position.x;
2925
- if (!warp) {
2926
- particle.position.y = getRandom() * canvasSize.height;
2927
- particle.initialPosition.y = particle.position.y;
2928
- }
2929
- particle.justWarped = true;
2930
- }
2931
- if (direction === OutModeDirection.bottom && nextBounds.top > canvasSize.height + particle.offset.y) {
2932
- if (!warp) {
2933
- particle.position.x = getRandom() * canvasSize.width;
2934
- particle.initialPosition.x = particle.position.x;
2935
- }
2936
- particle.position.y = newPos.top;
2937
- particle.initialPosition.y = particle.position.y;
2938
- particle.justWarped = true;
2939
- }
2940
- else if (direction === OutModeDirection.top && nextBounds.bottom < -particle.offset.y) {
2941
- if (!warp) {
2942
- particle.position.x = getRandom() * canvasSize.width;
2943
- particle.initialPosition.x = particle.position.x;
2944
- }
2945
- particle.position.y = newPos.bottom;
2946
- particle.initialPosition.y = particle.position.y;
2947
- particle.justWarped = true;
2948
- }
2949
- break;
2950
- }
2951
- }
2952
- break;
2924
+ if (particle.outType === ParticleOutType.outside) {
2925
+ this.#applyParticleModeOutside(particle);
2953
2926
  }
2954
- }
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;
2955
3019
  }
2956
3020
  }
2957
3021
 
@@ -3000,7 +3064,7 @@
3000
3064
  }
3001
3065
 
3002
3066
  async function loadOutModesUpdater(engine) {
3003
- engine.checkVersion("4.4.0");
3067
+ engine.checkVersion("4.5.0");
3004
3068
  await engine.pluginManager.register(e => {
3005
3069
  e.pluginManager.addParticleUpdater("outModes", container => {
3006
3070
  return Promise.resolve(new OutOfCanvasUpdater(container));
@@ -3017,39 +3081,9 @@
3017
3081
  this.#pluginManager = pluginManager;
3018
3082
  }
3019
3083
  init(particle) {
3020
- 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;
3021
- if (fill) {
3022
- const fillColor = AnimatableColor.create(paintColor === undefined ? undefined : AnimatableColor.create(undefined, paintColor), fill.color);
3023
- particle.fillEnabled = fill.enable;
3024
- particle.fillOpacity = getRangeValue(fill.opacity);
3025
- particle.fillAnimation = fillColor.animation;
3026
- const fillHslColor = rangeColorToHsl(this.#pluginManager, fillColor);
3027
- if (fillHslColor) {
3028
- particle.fillColor = getHslAnimationFromHsl(fillHslColor, particle.fillAnimation, container.retina.reduceFactor);
3029
- }
3030
- }
3031
- else {
3032
- particle.fillEnabled = false;
3033
- particle.fillAnimation = undefined;
3034
- particle.fillColor = undefined;
3035
- particle.fillOpacity = defaultOpacity;
3036
- }
3037
- if (stroke) {
3038
- const strokeColor = AnimatableColor.create(paintColor === undefined ? undefined : AnimatableColor.create(undefined, paintColor), stroke.color);
3039
- particle.strokeWidth = getRangeValue(stroke.width) * container.retina.pixelRatio;
3040
- particle.strokeOpacity = getRangeValue(stroke.opacity ?? defaultOpacity);
3041
- particle.strokeAnimation = strokeColor.animation;
3042
- const strokeHslColor = rangeColorToHsl(this.#pluginManager, strokeColor) ?? particle.getFillColor();
3043
- if (strokeHslColor) {
3044
- particle.strokeColor = getHslAnimationFromHsl(strokeHslColor, particle.strokeAnimation, container.retina.reduceFactor);
3045
- }
3046
- }
3047
- else {
3048
- particle.strokeAnimation = undefined;
3049
- particle.strokeColor = undefined;
3050
- particle.strokeOpacity = defaultOpacity;
3051
- particle.strokeWidth = 0;
3052
- }
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);
3053
3087
  }
3054
3088
  isEnabled(particle) {
3055
3089
  const { fillAnimation, fillColor, strokeAnimation, strokeColor } = particle, fillEnabled = !!fillAnimation &&
@@ -3068,10 +3102,48 @@
3068
3102
  updateColor(particle.fillColor, delta, this.#container.hdr);
3069
3103
  updateColor(particle.strokeColor, delta, this.#container.hdr);
3070
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
+ }
3071
3143
  }
3072
3144
 
3073
3145
  async function loadPaintUpdater(engine) {
3074
- engine.checkVersion("4.4.0");
3146
+ engine.checkVersion("4.5.0");
3075
3147
  await engine.pluginManager.register(e => {
3076
3148
  e.pluginManager.addParticleUpdater("paint", container => {
3077
3149
  return Promise.resolve(new PaintUpdater(e.pluginManager, container));
@@ -3113,7 +3185,7 @@
3113
3185
  if (!this.accepts(input)) {
3114
3186
  return;
3115
3187
  }
3116
- const result = rgbRegex.exec(input), radix = 10, minLength = 4, defaultAlpha = 1;
3188
+ const result = rgbRegex.exec(input), radix = 10, minLength = 4;
3117
3189
  return result
3118
3190
  ? {
3119
3191
  a: result.length > minLength ? parseAlpha(result[RgbIndexes.a]) : defaultAlpha,
@@ -3126,7 +3198,7 @@
3126
3198
  }
3127
3199
 
3128
3200
  async function loadRgbColorPlugin(engine) {
3129
- engine.checkVersion("4.4.0");
3201
+ engine.checkVersion("4.5.0");
3130
3202
  await engine.pluginManager.register(e => {
3131
3203
  e.pluginManager.addColorManager("rgb", new RgbColorManager());
3132
3204
  });
@@ -3211,7 +3283,7 @@
3211
3283
  }
3212
3284
 
3213
3285
  async function loadSizeUpdater(engine) {
3214
- engine.checkVersion("4.4.0");
3286
+ engine.checkVersion("4.5.0");
3215
3287
  await engine.pluginManager.register(e => {
3216
3288
  e.pluginManager.addParticleUpdater("size", container => {
3217
3289
  return Promise.resolve(new SizeUpdater(container));
@@ -3220,7 +3292,7 @@
3220
3292
  }
3221
3293
 
3222
3294
  async function loadBasic(engine) {
3223
- engine.checkVersion("4.4.0");
3295
+ engine.checkVersion("4.5.0");
3224
3296
  await engine.pluginManager.register(async (e) => {
3225
3297
  await Promise.all([
3226
3298
  loadBlendPlugin(e),
@@ -3237,6 +3309,16 @@
3237
3309
  });
3238
3310
  }
3239
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
+
3240
3322
  class ClickEvent {
3241
3323
  enable = false;
3242
3324
  mode = [];
@@ -3313,9 +3395,7 @@
3313
3395
 
3314
3396
  class Modes {
3315
3397
  #container;
3316
- #pluginManager;
3317
- constructor(pluginManager, container) {
3318
- this.#pluginManager = pluginManager;
3398
+ constructor(container) {
3319
3399
  this.#container = container;
3320
3400
  }
3321
3401
  load(data) {
@@ -3325,10 +3405,7 @@
3325
3405
  if (!this.#container) {
3326
3406
  return;
3327
3407
  }
3328
- const interactors = this.#pluginManager.interactors?.get(this.#container);
3329
- if (!interactors) {
3330
- return;
3331
- }
3408
+ const interactors = this.#container.interactionManager?.interactors ?? [];
3332
3409
  for (const interactor of interactors) {
3333
3410
  if (!interactor.loadModeOptions) {
3334
3411
  continue;
@@ -3342,8 +3419,8 @@
3342
3419
  detectsOn = InteractivityDetect.window;
3343
3420
  events = new Events();
3344
3421
  modes;
3345
- constructor(pluginManager, container) {
3346
- this.modes = new Modes(pluginManager, container);
3422
+ constructor(container) {
3423
+ this.modes = new Modes(container);
3347
3424
  }
3348
3425
  load(data) {
3349
3426
  if (isNull(data)) {
@@ -3374,10 +3451,10 @@
3374
3451
  }
3375
3452
  let interactivityOptions = options.interactivity;
3376
3453
  if (!interactivityOptions?.load) {
3377
- options.interactivity = interactivityOptions = new Interactivity(this.#pluginManager, container);
3454
+ options.interactivity = interactivityOptions = new Interactivity(container);
3378
3455
  }
3379
3456
  interactivityOptions.load(source?.interactivity);
3380
- const interactors = this.#pluginManager.interactors?.get(container);
3457
+ const interactors = container.interactionManager?.interactors;
3381
3458
  if (!interactors) {
3382
3459
  return;
3383
3460
  }
@@ -3391,7 +3468,7 @@
3391
3468
  if (source?.interactivity) {
3392
3469
  options.interactivity = deepExtend({}, source.interactivity);
3393
3470
  }
3394
- const interactors = this.#pluginManager.interactors?.get(container);
3471
+ const interactors = container.interactionManager?.interactors;
3395
3472
  if (!interactors) {
3396
3473
  return;
3397
3474
  }
@@ -3421,25 +3498,25 @@
3421
3498
  const clickEvent = "click", mouseDownEvent = "pointerdown", mouseUpEvent = "pointerup", mouseLeaveEvent = "pointerleave", mouseMoveEvent = "pointermove", touchStartEvent = "touchstart", touchEndEvent = "touchend", touchMoveEvent = "touchmove", touchCancelEvent = "touchcancel";
3422
3499
 
3423
3500
  async function loadInteractivityPlugin(engine) {
3424
- engine.checkVersion("4.4.0");
3501
+ engine.checkVersion("4.5.0");
3502
+ if (typeof process !== "undefined" && process.env.NODE_ENV !== "production") {
3503
+ addErrorMessages(ErrorMessages);
3504
+ }
3425
3505
  await engine.pluginManager.register(e => {
3426
3506
  const interactivityEngine = e, interactivityPluginManager = interactivityEngine.pluginManager;
3427
3507
  interactivityPluginManager.addPlugin(new InteractivityPlugin(interactivityPluginManager));
3428
3508
  interactivityPluginManager.initializers.interactors ??= new Map();
3429
- interactivityPluginManager.interactors ??= new Map();
3430
3509
  interactivityPluginManager.addInteractor = (name, interactorInitializer) => {
3510
+ if (interactivityPluginManager.initialized) {
3511
+ return;
3512
+ }
3431
3513
  interactivityPluginManager.initializers.interactors ??= new Map();
3432
3514
  interactivityPluginManager.initializers.interactors.set(name, interactorInitializer);
3433
3515
  };
3434
- interactivityPluginManager.getInteractors = async (container, force = false) => {
3435
- interactivityPluginManager.interactors ??= new Map();
3436
- interactivityPluginManager.initializers.interactors ??= new Map();
3437
- return getItemsFromInitializer(container, interactivityPluginManager.interactors, interactivityPluginManager.initializers.interactors, force);
3438
- };
3439
3516
  interactivityPluginManager.setOnClickHandler = (callback) => {
3440
3517
  const { items } = interactivityEngine;
3441
3518
  if (!items.length) {
3442
- throw new Error("Click handlers can only be set after calling tsParticles.load()");
3519
+ throw new Error(getErrorMessage(ErrorCodes.interactivityClickHandlerNotSet));
3443
3520
  }
3444
3521
  items.forEach(item => {
3445
3522
  const interactivityContainer = item;
@@ -3450,7 +3527,7 @@
3450
3527
  }
3451
3528
  function ensureInteractivityPluginLoaded(e) {
3452
3529
  if (!e.pluginManager.addInteractor) {
3453
- throw new Error("tsParticles Interactivity Plugin is not loaded");
3530
+ throw new Error(getErrorMessage(ErrorCodes.interactivityPluginNotLoaded));
3454
3531
  }
3455
3532
  }
3456
3533
 
@@ -3698,7 +3775,7 @@
3698
3775
  }
3699
3776
 
3700
3777
  async function loadParticlesLinksInteraction(engine) {
3701
- engine.checkVersion("4.4.0");
3778
+ engine.checkVersion("4.5.0");
3702
3779
  await engine.pluginManager.register((e) => {
3703
3780
  const pluginManager = e.pluginManager;
3704
3781
  ensureInteractivityPluginLoaded(e);
@@ -3821,21 +3898,28 @@
3821
3898
  });
3822
3899
  }
3823
3900
  clear() {
3901
+ const visited = new Set();
3824
3902
  for (const plugin of this.#canvasClearPlugins) {
3903
+ visited.add(plugin);
3825
3904
  if (plugin.canvasClear?.() ?? false) {
3826
- return;
3905
+ return plugin;
3827
3906
  }
3828
3907
  }
3829
3908
  for (const layer of Object.values(DrawLayer)) {
3830
3909
  if (typeof layer === "number") {
3831
3910
  for (const plugin of this.#getLayerPlugins(layer)) {
3911
+ if (visited.has(plugin)) {
3912
+ continue;
3913
+ }
3914
+ visited.add(plugin);
3832
3915
  if (plugin.canvasClear?.() ?? false) {
3833
- return;
3916
+ return plugin;
3834
3917
  }
3835
3918
  }
3836
3919
  }
3837
3920
  }
3838
3921
  this.canvasClear();
3922
+ return undefined;
3839
3923
  }
3840
3924
  destroy() {
3841
3925
  this.stop();
@@ -3913,8 +3997,7 @@
3913
3997
  });
3914
3998
  }
3915
3999
  drawParticles(delta) {
3916
- const { particles, actualOptions } = this.#container;
3917
- this.clear();
4000
+ const { particles, actualOptions } = this.#container, clearedPlugin = this.clear();
3918
4001
  particles.update(delta);
3919
4002
  this.draw(ctx => {
3920
4003
  const width = this.#canvasManager.size.width, height = this.#canvasManager.size.height;
@@ -3936,7 +4019,9 @@
3936
4019
  }
3937
4020
  }
3938
4021
  for (const plugin of this.#getLayerPlugins(DrawLayer.BackgroundMask)) {
3939
- plugin.canvasPaint?.();
4022
+ if (plugin !== clearedPlugin) {
4023
+ plugin.canvasPaint?.();
4024
+ }
3940
4025
  }
3941
4026
  for (const plugin of this.#getLayerPlugins(DrawLayer.CanvasSetup)) {
3942
4027
  plugin.drawSettingsSetup?.(ctx, delta);
@@ -3968,35 +4053,7 @@
3968
4053
  this.#layers[layer] = [];
3969
4054
  }
3970
4055
  }
3971
- for (const plugin of this.#container.plugins) {
3972
- if (plugin.particleFillColor ?? plugin.particleStrokeColor) {
3973
- this.#colorPlugins.push(plugin);
3974
- }
3975
- if (plugin.drawParticle) {
3976
- this.#drawParticlePlugins.push(plugin);
3977
- }
3978
- if (plugin.drawParticleSetup) {
3979
- this.#drawParticlesSetupPlugins.push(plugin);
3980
- }
3981
- if (plugin.drawParticleCleanup) {
3982
- this.#drawParticlesCleanupPlugins.push(plugin);
3983
- }
3984
- if (plugin.canvasClear) {
3985
- this.#canvasClearPlugins.push(plugin);
3986
- }
3987
- if (plugin.canvasPaint) {
3988
- this.#getLayerPlugins(DrawLayer.BackgroundMask).push(plugin);
3989
- }
3990
- if (plugin.drawSettingsSetup) {
3991
- this.#getLayerPlugins(DrawLayer.CanvasSetup).push(plugin);
3992
- }
3993
- if (plugin.draw) {
3994
- this.#getLayerPlugins(DrawLayer.PluginContent).push(plugin);
3995
- }
3996
- if (plugin.clearDraw ?? plugin.drawSettingsCleanup) {
3997
- this.#getLayerPlugins(DrawLayer.CanvasCleanup).push(plugin);
3998
- }
3999
- }
4056
+ this.#initPluginsArray();
4000
4057
  }
4001
4058
  initUpdaters() {
4002
4059
  this.#preDrawUpdaters = [];
@@ -4205,6 +4262,45 @@
4205
4262
  this.#reusablePluginColors[sColorIndex] = sColor;
4206
4263
  return this.#reusablePluginColors;
4207
4264
  }
4265
+ #initLayerPlugin(plugin) {
4266
+ const layerMap = [
4267
+ [DrawLayer.BackgroundMask, !!plugin.canvasPaint],
4268
+ [DrawLayer.CanvasSetup, !!plugin.drawSettingsSetup],
4269
+ [DrawLayer.PluginContent, !!plugin.draw],
4270
+ [DrawLayer.CanvasCleanup, !!(plugin.clearDraw ?? plugin.drawSettingsCleanup)],
4271
+ ];
4272
+ for (const [layer, active] of layerMap) {
4273
+ if (active) {
4274
+ this.#layers[layer].push(plugin);
4275
+ }
4276
+ }
4277
+ }
4278
+ #initPluginsArray() {
4279
+ for (const plugin of this.#container.plugins) {
4280
+ if (plugin.particleFillColor ?? plugin.particleStrokeColor) {
4281
+ this.#colorPlugins.push(plugin);
4282
+ }
4283
+ if (plugin.drawParticle) {
4284
+ this.#drawParticlePlugins.push(plugin);
4285
+ }
4286
+ if (plugin.drawParticleSetup) {
4287
+ this.#drawParticlesSetupPlugins.push(plugin);
4288
+ }
4289
+ if (plugin.drawParticleCleanup) {
4290
+ this.#drawParticlesCleanupPlugins.push(plugin);
4291
+ }
4292
+ if (plugin.canvasClear) {
4293
+ this.#canvasClearPlugins.push(plugin);
4294
+ }
4295
+ this.#initLayerPlugin(plugin);
4296
+ }
4297
+ }
4298
+ #isSupportedElement(element) {
4299
+ return ((typeof HTMLCanvasElement !== "undefined" && element instanceof HTMLCanvasElement) ||
4300
+ (typeof OffscreenCanvas !== "undefined" && element instanceof OffscreenCanvas) ||
4301
+ (typeof HTMLVideoElement !== "undefined" && element instanceof HTMLVideoElement) ||
4302
+ (typeof HTMLImageElement !== "undefined" && element instanceof HTMLImageElement));
4303
+ }
4208
4304
  #resolveBackgroundElement() {
4209
4305
  const background = this.#container.actualOptions.background;
4210
4306
  this.#backgroundElement = null;
@@ -4214,9 +4310,7 @@
4214
4310
  if (typeof background.element === "string") {
4215
4311
  if (typeof document !== "undefined") {
4216
4312
  const node = document.querySelector(background.element);
4217
- if ((typeof HTMLCanvasElement !== "undefined" && node instanceof HTMLCanvasElement) ||
4218
- (typeof HTMLVideoElement !== "undefined" && node instanceof HTMLVideoElement) ||
4219
- (typeof HTMLImageElement !== "undefined" && node instanceof HTMLImageElement)) {
4313
+ if (node && this.#isSupportedElement(node)) {
4220
4314
  this.#backgroundElement = node;
4221
4315
  }
4222
4316
  else if (node) {
@@ -4227,10 +4321,7 @@
4227
4321
  }
4228
4322
  }
4229
4323
  }
4230
- else if ((typeof HTMLCanvasElement !== "undefined" && background.element instanceof HTMLCanvasElement) ||
4231
- (typeof OffscreenCanvas !== "undefined" && background.element instanceof OffscreenCanvas) ||
4232
- (typeof HTMLVideoElement !== "undefined" && background.element instanceof HTMLVideoElement) ||
4233
- (typeof HTMLImageElement !== "undefined" && background.element instanceof HTMLImageElement)) {
4324
+ else if (this.#isSupportedElement(background.element)) {
4234
4325
  this.#backgroundElement = background.element;
4235
4326
  }
4236
4327
  }
@@ -4248,7 +4339,7 @@
4248
4339
  return transferredCanvas;
4249
4340
  }
4250
4341
  if (typeof canvas.transferControlToOffscreen !== "function") {
4251
- throw new TypeError("OffscreenCanvas is required but not supported by this browser");
4342
+ throw new TypeError(getErrorMessage(ErrorCodes$2.offscreenCanvasUnsupported));
4252
4343
  }
4253
4344
  try {
4254
4345
  const offscreenCanvas = canvas.transferControlToOffscreen();
@@ -4256,10 +4347,16 @@
4256
4347
  return offscreenCanvas;
4257
4348
  }
4258
4349
  catch {
4259
- throw new TypeError("OffscreenCanvas transfer failed");
4350
+ throw new TypeError(getErrorMessage(ErrorCodes$2.offscreenCanvasTransferFailed));
4260
4351
  }
4261
4352
  }, isHtmlCanvasElement = (canvas) => {
4262
4353
  return typeof HTMLCanvasElement !== "undefined" && canvas instanceof HTMLCanvasElement;
4354
+ }, getEffectiveColorSpace = (context) => {
4355
+ if (!context) {
4356
+ return undefined;
4357
+ }
4358
+ const colorInfo = context;
4359
+ return colorInfo.getContextAttributes?.().colorSpace ?? undefined;
4263
4360
  };
4264
4361
  function setStyle(canvas, style, important = false) {
4265
4362
  if (!style) {
@@ -4384,7 +4481,7 @@
4384
4481
  const elementStyle = element.style, color = rangeColorToRgb(this.#pluginManager, background.color);
4385
4482
  if (color) {
4386
4483
  const hdrOptions = container.actualOptions.hdr;
4387
- elementStyle.backgroundColor = getStyleFromRgb(color, container.hdr, background.opacity, hdrOptions.peakNits, hdrOptions.mode);
4484
+ elementStyle.backgroundColor = getStyleFromRgb(color, container.hdr, background.opacity, hdrOptions.peakNits, toEnumValue(HdrMode, hdrOptions.mode, HdrMode.standard));
4388
4485
  }
4389
4486
  else {
4390
4487
  elementStyle.backgroundColor = "";
@@ -4504,11 +4601,11 @@
4504
4601
  const container = this.#container, canSupportHdr = container.actualOptions.hdr.enable &&
4505
4602
  safeMatchMedia("(color-gamut: p3)")?.matches &&
4506
4603
  safeMatchMedia("(dynamic-range: high)")?.matches;
4507
- container.hdr = canSupportHdr ?? false;
4508
- container.hdrMode = container.actualOptions.hdr.mode;
4604
+ container.hdrMode = toEnumValue(HdrMode, container.actualOptions.hdr.mode, HdrMode.standard);
4509
4605
  container.peakNits = container.actualOptions.hdr.peakNits;
4510
4606
  const renderCanvas = this.renderCanvas;
4511
4607
  if (!renderCanvas) {
4608
+ container.hdr = canSupportHdr ?? false;
4512
4609
  return;
4513
4610
  }
4514
4611
  this.render.setContextSettings({
@@ -4527,7 +4624,6 @@
4527
4624
  context = null;
4528
4625
  }
4529
4626
  if (canSupportHdr && !context) {
4530
- container.hdr = false;
4531
4627
  const sdrSettings = {
4532
4628
  alpha: true,
4533
4629
  desynchronized: true,
@@ -4543,11 +4639,16 @@
4543
4639
  }
4544
4640
  }
4545
4641
  this.render.setContext(context);
4642
+ if (context) {
4643
+ const effectiveColorSpace = getEffectiveColorSpace(context);
4644
+ if (effectiveColorSpace !== undefined) {
4645
+ container.hdr = effectiveColorSpace === "display-p3";
4646
+ }
4647
+ }
4546
4648
  }
4547
4649
  #initHdrListeners() {
4548
4650
  this.#removeHdrListeners();
4549
4651
  const p3Query = safeMatchMedia("(color-gamut: p3)"), hdrQuery = safeMatchMedia("(dynamic-range: high)"), handleChange = () => {
4550
- this.#recreateRenderCanvas();
4551
4652
  this.#initContext();
4552
4653
  this.initBackground();
4553
4654
  }, listeners = [];
@@ -4583,16 +4684,6 @@
4583
4684
  element.style.setProperty(key, value, "important");
4584
4685
  }
4585
4686
  }
4586
- #recreateRenderCanvas() {
4587
- const renderCanvas = this.renderCanvas;
4588
- if (!renderCanvas) {
4589
- return;
4590
- }
4591
- if (this.domElement) {
4592
- return;
4593
- }
4594
- this.renderCanvas = new OffscreenCanvas(renderCanvas.width, renderCanvas.height);
4595
- }
4596
4687
  #removeHdrListeners() {
4597
4688
  if (!this.#hdrMediaListeners) {
4598
4689
  return;
@@ -4691,8 +4782,7 @@
4691
4782
  this.#resizeTimeout = undefined;
4692
4783
  }
4693
4784
  const handleResize = async () => {
4694
- const canvas = this.#container.canvas;
4695
- await canvas.windowResize();
4785
+ await this.#container.canvas.windowResize();
4696
4786
  };
4697
4787
  this.#resizeTimeout = setTimeout(() => void handleResize(), this.#container.actualOptions.resize.delay * millisecondsToSeconds);
4698
4788
  }
@@ -4720,8 +4810,8 @@
4720
4810
  }
4721
4811
  else if (!this.#resizeObserver && add && canvasEl) {
4722
4812
  this.#resizeObserver = new ResizeObserver((entries) => {
4723
- const entry = entries.find(e => e.target === canvasEl);
4724
- if (!entry) {
4813
+ const res = entries.some(e => e.target === canvasEl);
4814
+ if (!res) {
4725
4815
  return;
4726
4816
  }
4727
4817
  this.#handleWindowResize();
@@ -4985,10 +5075,10 @@
4985
5075
  return this.#modifiers.find(m => m.id === id);
4986
5076
  }
4987
5077
  getOpacity() {
4988
- const zIndexOptions = this.options.zIndex, zIndexFactor = zIndexFactorOffset - this.zIndexFactor, zOpacityFactor = zIndexFactor ** zIndexOptions.opacityRate, baseOpacity = getRangeValue(this.opacity?.value ?? defaultOpacity$1), modifierOpacity = this.#applyModifiers(undefined, m => m.opacity), opacity = modifierOpacity ?? baseOpacity, fillOpacity = this.fillOpacity ?? defaultOpacity$1, strokeOpacity = this.strokeOpacity ?? defaultOpacity$1;
4989
- this.#cachedOpacityData.fillOpacity = fillOpacity;
5078
+ const zIndexOptions = this.options.zIndex, zIndexFactor = zIndexFactorOffset - this.zIndexFactor, zOpacityFactor = zIndexFactor ** zIndexOptions.opacityRate, baseOpacity = getRangeValue(this.opacity?.value ?? defaultOpacity$1), modifierOpacity = this.#applyModifiers(undefined, m => m.opacity), opacity = modifierOpacity ?? baseOpacity;
5079
+ this.#cachedOpacityData.fillOpacity = this.fillOpacity ?? defaultOpacity$1;
4990
5080
  this.#cachedOpacityData.opacity = opacity * zOpacityFactor;
4991
- this.#cachedOpacityData.strokeOpacity = strokeOpacity;
5081
+ this.#cachedOpacityData.strokeOpacity = this.strokeOpacity ?? defaultOpacity$1;
4992
5082
  return this.#cachedOpacityData;
4993
5083
  }
4994
5084
  getPosition() {
@@ -5235,7 +5325,7 @@
5235
5325
  #initPosition(position) {
5236
5326
  const container = this.#container, zIndexValue = Math.floor(getRangeValue(this.options.zIndex.value)), initialPosition = this.#calcPosition(position, clamp(zIndexValue, minZ, container.zLayers));
5237
5327
  if (!initialPosition) {
5238
- throw new Error("a valid position cannot be found for particle");
5328
+ throw new Error(getErrorMessage(ErrorCodes$2.particlePositionNotFound));
5239
5329
  }
5240
5330
  this.position = initialPosition;
5241
5331
  this.initialPosition = this.position.copy();
@@ -5284,6 +5374,12 @@
5284
5374
  this.#circlePoolIdx = 0;
5285
5375
  this.#rectanglePoolIdx = 0;
5286
5376
  }
5377
+ get cellSize() {
5378
+ return this.#cellSize;
5379
+ }
5380
+ set cellSize(value) {
5381
+ this.#pendingCellSize = value;
5382
+ }
5287
5383
  clear() {
5288
5384
  this.#cells.clear();
5289
5385
  const pendingCellSize = this.#pendingCellSize;
@@ -5307,18 +5403,7 @@
5307
5403
  const minCellX = Math.floor(bounds.minX / this.#cellSize), maxCellX = Math.floor(bounds.maxX / this.#cellSize), minCellY = Math.floor(bounds.minY / this.#cellSize), maxCellY = Math.floor(bounds.maxY / this.#cellSize);
5308
5404
  for (let cx = minCellX; cx <= maxCellX; cx++) {
5309
5405
  for (let cy = minCellY; cy <= maxCellY; cy++) {
5310
- const key = `${cx}_${cy}`, cellParticles = this.#cells.get(key);
5311
- if (!cellParticles) {
5312
- continue;
5313
- }
5314
- for (const p of cellParticles) {
5315
- if (check && !check(p)) {
5316
- continue;
5317
- }
5318
- if (range.contains(p.getPosition())) {
5319
- out.push(p);
5320
- }
5321
- }
5406
+ this.#queryCell(cx, cy, range, check, out);
5322
5407
  }
5323
5408
  }
5324
5409
  return out;
@@ -5333,14 +5418,23 @@
5333
5418
  this.#releaseShapes();
5334
5419
  return result;
5335
5420
  }
5336
- setCellSize(cellSize) {
5337
- this.#pendingCellSize = cellSize;
5338
- }
5339
5421
  #acquireCircle(x, y, r) {
5340
- return (this.#circlePool[this.#circlePoolIdx++] ??= new Circle(x, y, r)).reset(x, y, r);
5422
+ const idx = this.#circlePoolIdx++;
5423
+ let circle = this.#circlePool[idx];
5424
+ if (!circle) {
5425
+ circle = new Circle(x, y, r);
5426
+ this.#circlePool[idx] = circle;
5427
+ }
5428
+ return circle.reset(x, y, r);
5341
5429
  }
5342
5430
  #acquireRectangle(x, y, w, h) {
5343
- return (this.#rectanglePool[this.#rectanglePoolIdx++] ??= new Rectangle(x, y, w, h)).reset(x, y, w, h);
5431
+ const idx = this.#rectanglePoolIdx++;
5432
+ let rectangle = this.#rectanglePool[idx];
5433
+ if (!rectangle) {
5434
+ rectangle = new Rectangle(x, y, w, h);
5435
+ this.#rectanglePool[idx] = rectangle;
5436
+ }
5437
+ return rectangle.reset(x, y, w, h);
5344
5438
  }
5345
5439
  #cellKeyFromCoords(x, y) {
5346
5440
  const cellX = Math.floor(x / this.#cellSize), cellY = Math.floor(y / this.#cellSize);
@@ -5367,6 +5461,20 @@
5367
5461
  }
5368
5462
  return null;
5369
5463
  }
5464
+ #queryCell(cx, cy, range, check, out) {
5465
+ const cellParticles = this.#cells.get(`${cx}_${cy}`);
5466
+ if (!cellParticles) {
5467
+ return;
5468
+ }
5469
+ for (const p of cellParticles) {
5470
+ if (check && !check(p)) {
5471
+ continue;
5472
+ }
5473
+ if (range.contains(p.getPosition())) {
5474
+ out.push(p);
5475
+ }
5476
+ }
5477
+ }
5370
5478
  #releaseShapes() {
5371
5479
  this.#circlePoolIdx = 0;
5372
5480
  this.#rectanglePoolIdx = 0;
@@ -5375,9 +5483,9 @@
5375
5483
 
5376
5484
  class ParticlesManager {
5377
5485
  checkParticlePositionPlugins;
5378
- grid;
5379
5486
  #array;
5380
5487
  #container;
5488
+ #grid;
5381
5489
  #groupLimits;
5382
5490
  #limit;
5383
5491
  #nextId;
@@ -5401,7 +5509,7 @@
5401
5509
  this.#groupLimits = new Map();
5402
5510
  this.#particleBuckets = new Map();
5403
5511
  this.#zBuckets = this.#createBuckets(this.#container.zLayers);
5404
- this.grid = new SpatialHashGrid(spatialHashGridCellSize);
5512
+ this.#grid = new SpatialHashGrid(spatialHashGridCellSize);
5405
5513
  this.checkParticlePositionPlugins = [];
5406
5514
  this.#particleResetPlugins = [];
5407
5515
  this.#particleUpdatePlugins = [];
@@ -5412,23 +5520,12 @@
5412
5520
  get count() {
5413
5521
  return this.#array.length;
5414
5522
  }
5523
+ get grid() {
5524
+ return this.#grid;
5525
+ }
5415
5526
  addParticle(position, overrideOptions, group, initializer) {
5416
- const limitMode = this.#container.actualOptions.particles.number.limit.mode, limit = group === undefined ? this.#limit : (this.#groupLimits.get(group) ?? this.#limit), currentCount = this.count;
5417
- if (limit > minLimit) {
5418
- switch (limitMode) {
5419
- case LimitMode.delete: {
5420
- const countToRemove = currentCount + countOffset - limit;
5421
- if (countToRemove > minCount) {
5422
- this.removeQuantity(countToRemove);
5423
- }
5424
- break;
5425
- }
5426
- case LimitMode.wait:
5427
- if (currentCount >= limit) {
5428
- return;
5429
- }
5430
- break;
5431
- }
5527
+ if (this.#checkAndApplyLimits(group, this.count)) {
5528
+ return;
5432
5529
  }
5433
5530
  try {
5434
5531
  const particle = this.#pool.pop() ?? new Particle(this.#pluginManager, this.#container);
@@ -5492,7 +5589,7 @@
5492
5589
  return this.#array[index];
5493
5590
  }
5494
5591
  async init() {
5495
- const container = this.#container, options = container.actualOptions;
5592
+ const container = this.#container;
5496
5593
  this.checkParticlePositionPlugins = [];
5497
5594
  this.#updatePlugins = [];
5498
5595
  this.#particleUpdatePlugins = [];
@@ -5501,59 +5598,16 @@
5501
5598
  this.#postParticleUpdatePlugins = [];
5502
5599
  this.#particleBuckets.clear();
5503
5600
  this.#resetBuckets(container.zLayers);
5504
- this.grid = new SpatialHashGrid(spatialHashGridCellSize * container.retina.pixelRatio);
5505
- for (const plugin of container.plugins) {
5506
- if (plugin.redrawInit) {
5507
- await plugin.redrawInit();
5508
- }
5509
- if (plugin.checkParticlePosition) {
5510
- this.checkParticlePositionPlugins.push(plugin);
5511
- }
5512
- if (plugin.update) {
5513
- this.#updatePlugins.push(plugin);
5514
- }
5515
- if (plugin.particleUpdate) {
5516
- this.#particleUpdatePlugins.push(plugin);
5517
- }
5518
- if (plugin.postUpdate) {
5519
- this.#postUpdatePlugins.push(plugin);
5520
- }
5521
- if (plugin.particleReset) {
5522
- this.#particleResetPlugins.push(plugin);
5523
- }
5524
- if (plugin.postParticleUpdate) {
5525
- this.#postParticleUpdatePlugins.push(plugin);
5526
- }
5527
- }
5528
- await this.#container.initDrawersAndUpdaters();
5529
- for (const drawer of this.#container.effectDrawers.values()) {
5530
- await drawer.init?.(container);
5531
- }
5532
- for (const drawer of this.#container.shapeDrawers.values()) {
5533
- await drawer.init?.(container);
5534
- }
5535
- let handled = false;
5536
- for (const plugin of container.plugins) {
5537
- handled = plugin.particlesInitialization?.() ?? handled;
5538
- if (handled) {
5539
- break;
5540
- }
5541
- }
5542
- if (!handled) {
5543
- const particlesOptions = options.particles, groups = particlesOptions.groups;
5544
- for (const group in groups) {
5545
- const groupOptions = groups[group];
5546
- if (!groupOptions) {
5547
- continue;
5548
- }
5549
- for (let i = this.count, j = 0; j < groupOptions.number.value && i < particlesOptions.number.value; i++, j++) {
5550
- this.addParticle(undefined, groupOptions, group);
5551
- }
5552
- }
5553
- for (let i = this.count; i < particlesOptions.number.value; i++) {
5554
- this.addParticle();
5601
+ this.#grid = new SpatialHashGrid(spatialHashGridCellSize * container.retina.pixelRatio);
5602
+ this.#applyLimits(container.actualOptions.particles);
5603
+ const particlesOptions = container.actualOptions.particles, groups = particlesOptions.groups;
5604
+ for (const group in groups) {
5605
+ const groupData = groups[group];
5606
+ if (groupData) {
5607
+ this.#applyLimits(loadParticlesOptions(this.#pluginManager, this.#container, groupData), group, groupData);
5555
5608
  }
5556
5609
  }
5610
+ await this.#initPlugins();
5557
5611
  }
5558
5612
  push(nb, position, overrideOptions, group) {
5559
5613
  for (let i = 0; i < nb; i++) {
@@ -5568,13 +5622,13 @@
5568
5622
  remove(particle, group, override) {
5569
5623
  this.removeAt(this.#array.indexOf(particle), undefined, group, override);
5570
5624
  }
5571
- removeAt(index, quantity = defaultRemoveQuantity, group, override) {
5625
+ removeAt(index, quantity = defaultRemoveQuantity, group, override, matchGroup = true) {
5572
5626
  if (index < minIndex || index > this.count) {
5573
5627
  return;
5574
5628
  }
5575
5629
  let deleted = 0;
5576
5630
  for (let i = index; deleted < quantity && i < this.count; i++) {
5577
- if (this.#removeParticle(i, group, override)) {
5631
+ if (this.#removeParticle(i, group, override, matchGroup)) {
5578
5632
  i--;
5579
5633
  deleted++;
5580
5634
  }
@@ -5605,7 +5659,7 @@
5605
5659
  this.#resizeFactor = factor;
5606
5660
  }
5607
5661
  update(delta) {
5608
- this.grid.clear();
5662
+ this.#grid.clear();
5609
5663
  for (const plugin of this.#updatePlugins) {
5610
5664
  plugin.update?.(delta);
5611
5665
  }
@@ -5616,7 +5670,7 @@
5616
5670
  this.#updateParticlesPhase2(delta, particlesToDelete);
5617
5671
  if (particlesToDelete.size) {
5618
5672
  for (const particle of particlesToDelete) {
5619
- this.remove(particle);
5673
+ this.remove(particle, particle.group);
5620
5674
  }
5621
5675
  }
5622
5676
  this.#resizeFactor = undefined;
@@ -5627,12 +5681,7 @@
5627
5681
  #applyDensity(options, pluginsCount, group, groupOptions) {
5628
5682
  const numberOptions = options.number;
5629
5683
  if (!numberOptions.density.enable) {
5630
- if (group === undefined) {
5631
- this.#limit = numberOptions.limit.value;
5632
- }
5633
- else if (groupOptions?.number.limit.value ?? numberOptions.limit.value) {
5634
- this.#groupLimits.set(group, groupOptions?.number.limit.value ?? numberOptions.limit.value);
5635
- }
5684
+ this.#applyLimits(options, group, groupOptions);
5636
5685
  return;
5637
5686
  }
5638
5687
  const densityFactor = this.#initDensityFactor(numberOptions.density), optParticlesNumber = numberOptions.value, optParticlesLimit = numberOptions.limit.value > minLimit ? numberOptions.limit.value : optParticlesNumber, particlesNumber = Math.min(optParticlesNumber, optParticlesLimit) * densityFactor + pluginsCount, particlesCount = Math.min(this.count, this.filter(t => t.group === group).length);
@@ -5640,7 +5689,10 @@
5640
5689
  this.#limit = numberOptions.limit.value * densityFactor;
5641
5690
  }
5642
5691
  else {
5643
- this.#groupLimits.set(group, numberOptions.limit.value * densityFactor);
5692
+ this.#groupLimits.set(group, {
5693
+ limit: numberOptions.limit.value * densityFactor,
5694
+ mode: toEnumValue(LimitMode, numberOptions.limit.mode, LimitMode.delete),
5695
+ });
5644
5696
  }
5645
5697
  if (particlesCount < particlesNumber) {
5646
5698
  this.push(Math.abs(particlesNumber - particlesCount), undefined, options, group);
@@ -5649,6 +5701,55 @@
5649
5701
  this.removeQuantity(particlesCount - particlesNumber, group);
5650
5702
  }
5651
5703
  }
5704
+ #applyLimits(options, group, groupOptions) {
5705
+ if (group === undefined) {
5706
+ this.#limit = options.number.limit.value;
5707
+ const groups = this.#container.actualOptions.particles.groups;
5708
+ for (const existingGroup of this.#groupLimits.keys()) {
5709
+ if (!(existingGroup in groups)) {
5710
+ this.#groupLimits.delete(existingGroup);
5711
+ }
5712
+ }
5713
+ }
5714
+ else {
5715
+ const limitValue = groupOptions?.number?.limit?.value ?? options.number.limit.value;
5716
+ if (limitValue > minLimit) {
5717
+ this.#groupLimits.set(group, {
5718
+ limit: limitValue,
5719
+ mode: toEnumValue(LimitMode, groupOptions?.number?.limit?.mode ?? options.number.limit.mode, LimitMode.delete),
5720
+ });
5721
+ }
5722
+ else {
5723
+ this.#groupLimits.delete(group);
5724
+ }
5725
+ }
5726
+ }
5727
+ #checkAndApplyLimits(group, currentCount) {
5728
+ const globalLimit = this.#limit, globalMode = this.#container.actualOptions.particles.number.limit.mode;
5729
+ if (globalLimit > minLimit && globalMode === LimitMode.wait && currentCount >= globalLimit) {
5730
+ return true;
5731
+ }
5732
+ const groupLimitEntry = group === undefined ? undefined : this.#groupLimits.get(group);
5733
+ if (groupLimitEntry && groupLimitEntry.limit > minLimit && groupLimitEntry.mode === LimitMode.wait) {
5734
+ const groupCount = this.filter(t => t.group === group).length;
5735
+ if (groupCount >= groupLimitEntry.limit) {
5736
+ return true;
5737
+ }
5738
+ }
5739
+ if (groupLimitEntry && groupLimitEntry.limit > minLimit && groupLimitEntry.mode === LimitMode.delete) {
5740
+ const groupCountToRemove = this.filter(t => t.group === group).length + countOffset - groupLimitEntry.limit;
5741
+ if (groupCountToRemove > minCount) {
5742
+ this.removeQuantity(groupCountToRemove, group);
5743
+ }
5744
+ }
5745
+ if (globalLimit > minLimit && globalMode === LimitMode.delete) {
5746
+ const globalCountToRemove = this.count + countOffset - globalLimit;
5747
+ if (globalCountToRemove > minCount) {
5748
+ this.#removeAny(globalCountToRemove);
5749
+ }
5750
+ }
5751
+ return false;
5752
+ }
5652
5753
  #createBuckets(zLayers) {
5653
5754
  const bucketCount = Math.max(Math.floor(zLayers), one);
5654
5755
  return Array.from({ length: bucketCount }, () => []);
@@ -5671,6 +5772,70 @@
5671
5772
  }
5672
5773
  return ((canvasSize.width * canvasSize.height) / (densityOptions.height * densityOptions.width * pxRatio ** squareExp));
5673
5774
  }
5775
+ async #initDrawersAndUpdaters() {
5776
+ const container = this.#container;
5777
+ await container.initDrawersAndUpdaters();
5778
+ for (const drawer of container.effectDrawers.values()) {
5779
+ await drawer.init?.(container);
5780
+ }
5781
+ for (const drawer of container.shapeDrawers.values()) {
5782
+ await drawer.init?.(container);
5783
+ }
5784
+ }
5785
+ async #initPlugins() {
5786
+ await this.#initPluginsArrays();
5787
+ await this.#initDrawersAndUpdaters();
5788
+ let handled = false;
5789
+ const container = this.#container;
5790
+ for (const plugin of container.plugins) {
5791
+ handled = plugin.particlesInitialization?.() ?? handled;
5792
+ if (handled) {
5793
+ break;
5794
+ }
5795
+ }
5796
+ if (handled) {
5797
+ return;
5798
+ }
5799
+ const particlesOptions = container.actualOptions.particles, groups = particlesOptions.groups;
5800
+ for (const group in groups) {
5801
+ const groupOptions = groups[group];
5802
+ if (!groupOptions) {
5803
+ continue;
5804
+ }
5805
+ for (let i = this.count, j = 0; j < groupOptions.number.value && i < particlesOptions.number.value; i++, j++) {
5806
+ this.addParticle(undefined, groupOptions, group);
5807
+ }
5808
+ }
5809
+ for (let i = this.count; i < particlesOptions.number.value; i++) {
5810
+ this.addParticle();
5811
+ }
5812
+ }
5813
+ async #initPluginsArrays() {
5814
+ const container = this.#container;
5815
+ for (const plugin of container.plugins) {
5816
+ if (plugin.redrawInit) {
5817
+ await plugin.redrawInit();
5818
+ }
5819
+ if (plugin.checkParticlePosition) {
5820
+ this.checkParticlePositionPlugins.push(plugin);
5821
+ }
5822
+ if (plugin.update) {
5823
+ this.#updatePlugins.push(plugin);
5824
+ }
5825
+ if (plugin.particleUpdate) {
5826
+ this.#particleUpdatePlugins.push(plugin);
5827
+ }
5828
+ if (plugin.postUpdate) {
5829
+ this.#postUpdatePlugins.push(plugin);
5830
+ }
5831
+ if (plugin.particleReset) {
5832
+ this.#particleResetPlugins.push(plugin);
5833
+ }
5834
+ if (plugin.postParticleUpdate) {
5835
+ this.#postParticleUpdatePlugins.push(plugin);
5836
+ }
5837
+ }
5838
+ }
5674
5839
  #insertParticleIntoBucket(particle) {
5675
5840
  const bucketIndex = this.#getBucketIndex(particle.position.z), bucket = this.#zBuckets[bucketIndex];
5676
5841
  if (!bucket) {
@@ -5679,12 +5844,15 @@
5679
5844
  bucket.push(particle);
5680
5845
  this.#particleBuckets.set(particle.id, bucketIndex);
5681
5846
  }
5682
- #removeParticle(index, group, override) {
5847
+ #removeAny(quantity) {
5848
+ this.removeAt(minIndex, quantity, undefined, undefined, false);
5849
+ }
5850
+ #removeParticle(index, group, override, matchGroup = true) {
5683
5851
  const particle = this.#array[index];
5684
5852
  if (!particle) {
5685
5853
  return false;
5686
5854
  }
5687
- if (particle.group !== group) {
5855
+ if (matchGroup && particle.group !== group) {
5688
5856
  return false;
5689
5857
  }
5690
5858
  this.#array.splice(index, deleteCount);
@@ -5771,7 +5939,7 @@
5771
5939
  particlesToDelete.add(particle);
5772
5940
  continue;
5773
5941
  }
5774
- this.grid.insert(particle);
5942
+ this.#grid.insert(particle);
5775
5943
  }
5776
5944
  return particlesToDelete;
5777
5945
  }
@@ -5947,7 +6115,6 @@
5947
6115
  this.shapeDrawers = new Map();
5948
6116
  this.particleUpdaters = [];
5949
6117
  this.plugins.length = 0;
5950
- this.#pluginManager.clearPlugins(this);
5951
6118
  this.destroyed = true;
5952
6119
  this.#onDestroy(remove);
5953
6120
  this.dispatchEvent(EventType.containerDestroyed);
@@ -6000,31 +6167,14 @@
6000
6167
  await this.initDrawersAndUpdaters();
6001
6168
  this.#options = loadContainerOptions(this.#pluginManager, this, this.#initialSourceOptions, this.sourceOptions);
6002
6169
  this.actualOptions = loadContainerOptions(this.#pluginManager, this, this.#options);
6003
- this.plugins.length = 0;
6004
- this.particleDestroyedPlugins.length = 0;
6005
- this.particleCreatedPlugins.length = 0;
6006
- this.particlePositionPlugins.length = 0;
6007
- for (const [plugin, containerPlugin] of allContainerPlugins) {
6008
- if (plugin.needsPlugin(this.actualOptions)) {
6009
- this.plugins.push(containerPlugin);
6010
- if (containerPlugin.particleCreated) {
6011
- this.particleCreatedPlugins.push(containerPlugin);
6012
- }
6013
- if (containerPlugin.particleDestroyed) {
6014
- this.particleDestroyedPlugins.push(containerPlugin);
6015
- }
6016
- if (containerPlugin.particlePosition) {
6017
- this.particlePositionPlugins.push(containerPlugin);
6018
- }
6019
- }
6020
- }
6170
+ this.#initPlugins(allContainerPlugins);
6021
6171
  this.retina.init();
6022
6172
  this.canvas.init();
6023
6173
  this.updateActualOptions();
6024
6174
  this.canvas.initBackground();
6025
6175
  this.canvas.resize();
6026
6176
  const { delay, duration, fpsLimit, smooth, zLayers } = this.actualOptions, hdrOptions = this.actualOptions.hdr;
6027
- this.hdrMode = hdrOptions.mode;
6177
+ this.hdrMode = toEnumValue(HdrMode, hdrOptions.mode, HdrMode.standard);
6028
6178
  this.peakNits = hdrOptions.peakNits;
6029
6179
  this.zLayers = zLayers;
6030
6180
  this.#duration = getRangeValue(duration) * millisecondsToSeconds;
@@ -6045,9 +6195,9 @@
6045
6195
  }
6046
6196
  async initDrawersAndUpdaters() {
6047
6197
  const pluginManager = this.#pluginManager;
6048
- this.effectDrawers = await pluginManager.getEffectDrawers(this, true);
6049
- this.shapeDrawers = await pluginManager.getShapeDrawers(this, true);
6050
- this.particleUpdaters = await pluginManager.getUpdaters(this, true);
6198
+ this.effectDrawers = await getItemMapFromInitializer(this, pluginManager.initializers.effects);
6199
+ this.shapeDrawers = await getItemMapFromInitializer(this, pluginManager.initializers.shapes);
6200
+ this.particleUpdaters = await getItemsFromInitializer(this, pluginManager.initializers.updaters);
6051
6201
  }
6052
6202
  pause() {
6053
6203
  if (!guardCheck(this)) {
@@ -6158,6 +6308,27 @@
6158
6308
  }
6159
6309
  return refresh;
6160
6310
  }
6311
+ #initPlugins(allContainerPlugins) {
6312
+ this.plugins.length = 0;
6313
+ this.particleDestroyedPlugins.length = 0;
6314
+ this.particleCreatedPlugins.length = 0;
6315
+ this.particlePositionPlugins.length = 0;
6316
+ for (const [plugin, containerPlugin] of allContainerPlugins) {
6317
+ if (!plugin.needsPlugin(this.actualOptions)) {
6318
+ continue;
6319
+ }
6320
+ this.plugins.push(containerPlugin);
6321
+ if (containerPlugin.particleCreated) {
6322
+ this.particleCreatedPlugins.push(containerPlugin);
6323
+ }
6324
+ if (containerPlugin.particleDestroyed) {
6325
+ this.particleDestroyedPlugins.push(containerPlugin);
6326
+ }
6327
+ if (containerPlugin.particlePosition) {
6328
+ this.particlePositionPlugins.push(containerPlugin);
6329
+ }
6330
+ }
6331
+ }
6161
6332
  #nextFrame(timestamp) {
6162
6333
  try {
6163
6334
  if (!this.#smooth &&
@@ -6434,11 +6605,11 @@
6434
6605
  }
6435
6606
  }
6436
6607
  async #init() {
6437
- const availablePathGenerators = await this.#pluginManager.getPathGenerators?.(this.#container, true);
6438
- if (!availablePathGenerators) {
6608
+ const pluginManager = this.#pluginManager;
6609
+ if (!pluginManager.initializers.pathGenerators) {
6439
6610
  return;
6440
6611
  }
6441
- this.availablePathGenerators = availablePathGenerators;
6612
+ this.availablePathGenerators = await getItemMapFromInitializer(this.#container, pluginManager.initializers.pathGenerators);
6442
6613
  this.pathGenerators = new Map();
6443
6614
  for (const pathGenerator of this.pathGenerators.values()) {
6444
6615
  pathGenerator.init();
@@ -6542,28 +6713,12 @@
6542
6713
  }
6543
6714
  const html = interactivityEl, canvas = container.canvas;
6544
6715
  canvas.setPointerEvents(html === canvas.domElement ? "initial" : "none");
6545
- if (add && !(options.interactivity?.events.onHover.enable || options.interactivity?.events.onClick.enable)) {
6546
- return;
6547
- }
6548
6716
  manageListener(interactivityEl, mouseMoveEvent, handlers.mouseMove, add);
6549
6717
  manageListener(interactivityEl, touchStartEvent, handlers.touchStart, add);
6550
6718
  manageListener(interactivityEl, touchMoveEvent, handlers.touchMove, add);
6551
- if (add) {
6552
- if (options.interactivity?.events.onClick.enable) {
6553
- manageListener(interactivityEl, touchEndEvent, handlers.touchEndClick, add);
6554
- manageListener(interactivityEl, mouseUpEvent, handlers.mouseUp, add);
6555
- manageListener(interactivityEl, mouseDownEvent, handlers.mouseDown, add);
6556
- }
6557
- else {
6558
- manageListener(interactivityEl, touchEndEvent, handlers.touchEnd, add);
6559
- }
6560
- }
6561
- else {
6562
- manageListener(interactivityEl, touchEndEvent, handlers.touchEndClick, add);
6563
- manageListener(interactivityEl, mouseUpEvent, handlers.mouseUp, add);
6564
- manageListener(interactivityEl, mouseDownEvent, handlers.mouseDown, add);
6565
- manageListener(interactivityEl, touchEndEvent, handlers.touchEnd, add);
6566
- }
6719
+ manageListener(interactivityEl, touchEndEvent, options.interactivity?.events.onClick.enable ? handlers.touchEndClick : handlers.touchEnd, add);
6720
+ manageListener(interactivityEl, mouseUpEvent, handlers.mouseUp, add);
6721
+ manageListener(interactivityEl, mouseDownEvent, handlers.mouseDown, add);
6567
6722
  manageListener(interactivityEl, mouseLeaveEvent, handlers.mouseLeave, add);
6568
6723
  manageListener(interactivityEl, touchCancelEvent, handlers.touchCancel, add);
6569
6724
  }
@@ -6589,19 +6744,18 @@
6589
6744
  #mouseTouchClick(e) {
6590
6745
  const container = this.#container, interactionManager = this.#interactionManager, options = container.actualOptions, { mouse } = interactionManager.interactivityData;
6591
6746
  mouse.inside = true;
6592
- let handled = false;
6593
6747
  const mousePosition = mouse.position;
6594
- if (!mousePosition || !options.interactivity?.events.onClick.enable) {
6595
- return;
6596
- }
6597
- for (const plugin of this.#clickPositionPlugins) {
6598
- handled = plugin.clickPositionValid?.(mousePosition) ?? false;
6599
- if (handled) {
6600
- break;
6748
+ if (mousePosition && options.interactivity?.events.onClick.enable) {
6749
+ let handled = false;
6750
+ for (const plugin of this.#clickPositionPlugins) {
6751
+ handled = plugin.clickPositionValid?.(mousePosition) ?? false;
6752
+ if (handled) {
6753
+ break;
6754
+ }
6755
+ }
6756
+ if (!handled) {
6757
+ this.#doMouseTouchClick(e);
6601
6758
  }
6602
- }
6603
- if (!handled) {
6604
- this.#doMouseTouchClick(e);
6605
6759
  }
6606
6760
  mouse.clicking = false;
6607
6761
  }
@@ -6697,6 +6851,9 @@
6697
6851
  this.#touches.set(touch.identifier, performance.now());
6698
6852
  }
6699
6853
  this.#mouseTouchMove(e);
6854
+ const { mouse } = this.#interactionManager.interactivityData;
6855
+ mouse.clicking = true;
6856
+ mouse.downPosition = mouse.position;
6700
6857
  }
6701
6858
  }
6702
6859
 
@@ -6709,18 +6866,18 @@
6709
6866
  }
6710
6867
  class InteractionManager {
6711
6868
  interactivityData;
6869
+ interactors;
6712
6870
  #clickHandlers;
6713
6871
  #container;
6714
6872
  #eventListeners;
6715
6873
  #externalInteractors;
6716
- #interactors;
6717
6874
  #intersectionObserver;
6718
6875
  #particleInteractors;
6719
6876
  #pluginManager;
6720
6877
  constructor(pluginManager, container) {
6721
6878
  this.#container = container;
6722
6879
  this.#pluginManager = pluginManager;
6723
- this.#interactors = [];
6880
+ this.interactors = [];
6724
6881
  this.#externalInteractors = [];
6725
6882
  this.#particleInteractors = [];
6726
6883
  this.#clickHandlers = new Map();
@@ -6839,7 +6996,7 @@
6839
6996
  }
6840
6997
  init() {
6841
6998
  this.#eventListeners.init();
6842
- for (const interactor of this.#interactors) {
6999
+ for (const interactor of this.interactors) {
6843
7000
  switch (interactor.type) {
6844
7001
  case InteractorType.external:
6845
7002
  this.#externalInteractors.push(interactor);
@@ -6852,11 +7009,11 @@
6852
7009
  }
6853
7010
  }
6854
7011
  async initInteractors() {
6855
- const interactors = await this.#pluginManager.getInteractors?.(this.#container, true);
6856
- if (!interactors) {
7012
+ const pluginManager = this.#pluginManager;
7013
+ if (!pluginManager.initializers.interactors) {
6857
7014
  return;
6858
7015
  }
6859
- this.#interactors = interactors;
7016
+ this.interactors = await getItemsFromInitializer(this.#container, pluginManager.initializers.interactors);
6860
7017
  this.#externalInteractors = [];
6861
7018
  this.#particleInteractors = [];
6862
7019
  }
@@ -6901,13 +7058,13 @@
6901
7058
  }
6902
7059
  updateMaxDistance() {
6903
7060
  let maxTotalDistance = 0;
6904
- for (const interactor of this.#interactors) {
7061
+ for (const interactor of this.interactors) {
6905
7062
  if (interactor.maxDistance > maxTotalDistance) {
6906
7063
  maxTotalDistance = interactor.maxDistance;
6907
7064
  }
6908
7065
  }
6909
7066
  const container = this.#container;
6910
- container.particles.grid.setCellSize(maxTotalDistance * container.retina.pixelRatio);
7067
+ container.particles.grid.cellSize = maxTotalDistance * container.retina.pixelRatio;
6911
7068
  }
6912
7069
  #intersectionManager(entries) {
6913
7070
  const container = this.#container;
@@ -6929,59 +7086,59 @@
6929
7086
  }
6930
7087
 
6931
7088
  class InteractivityPluginInstance {
6932
- interactionManager;
6933
7089
  #container;
6934
- #pluginManager;
6935
7090
  constructor(pluginManager, container) {
6936
- this.#container = container;
6937
- this.#pluginManager = pluginManager;
6938
- this.interactionManager = new InteractionManager(pluginManager, container);
6939
- this.#container.addClickHandler = (callback) => {
6940
- this.interactionManager.addClickHandler(callback);
7091
+ container.addClickHandler = (callback) => {
7092
+ container.interactionManager?.addClickHandler(callback);
6941
7093
  };
7094
+ container.interactionManager = new InteractionManager(pluginManager, container);
7095
+ this.#container = container;
6942
7096
  }
6943
7097
  addClickHandler(callback) {
6944
- this.interactionManager.addClickHandler(callback);
7098
+ this.#container.interactionManager?.addClickHandler(callback);
6945
7099
  }
6946
7100
  clearClickHandlers() {
6947
- this.interactionManager.clearClickHandlers();
7101
+ this.#container.interactionManager?.clearClickHandlers();
6948
7102
  }
6949
7103
  destroy() {
6950
7104
  this.clearClickHandlers();
6951
- this.#pluginManager.interactors?.delete(this.#container);
6952
7105
  }
6953
7106
  particleCreated(particle) {
6954
- const interactivityParticle = particle, interactivity = new Interactivity(this.#pluginManager, this.#container);
6955
- interactivity.load(this.#container.actualOptions.interactivity);
7107
+ const interactivityParticle = particle, container = this.#container, interactivity = new Interactivity(container);
7108
+ interactivity.load(container.actualOptions.interactivity);
6956
7109
  interactivity.load(interactivityParticle.options.interactivity);
6957
7110
  interactivityParticle.interactivity = interactivity;
6958
7111
  }
6959
7112
  particleReset(particle) {
6960
- this.interactionManager.reset(particle);
7113
+ this.#container.interactionManager?.reset(particle);
6961
7114
  }
6962
7115
  postParticleUpdate(particle, delta) {
6963
- this.interactionManager.particlesInteract(particle, delta);
7116
+ this.#container.interactionManager?.particlesInteract(particle, delta);
6964
7117
  }
6965
7118
  postUpdate(delta) {
6966
- this.interactionManager.externalInteract(delta);
6967
- this.interactionManager.updateMaxDistance();
7119
+ const container = this.#container;
7120
+ container.interactionManager?.externalInteract(delta);
7121
+ container.interactionManager?.updateMaxDistance();
6968
7122
  }
6969
7123
  async preInit() {
6970
- await this.interactionManager.initInteractors();
6971
- this.interactionManager.init();
7124
+ const container = this.#container;
7125
+ await container.interactionManager?.initInteractors();
7126
+ container.interactionManager?.init();
6972
7127
  }
6973
7128
  async redrawInit() {
6974
- await this.interactionManager.initInteractors();
6975
- this.interactionManager.init();
7129
+ const container = this.#container;
7130
+ await container.interactionManager?.initInteractors();
7131
+ container.interactionManager?.init();
6976
7132
  }
6977
7133
  start() {
6978
- this.interactionManager.addListeners();
6979
- this.interactionManager.startObserving();
7134
+ const container = this.#container;
7135
+ container.interactionManager?.addListeners();
7136
+ container.interactionManager?.startObserving();
6980
7137
  return Promise.resolve();
6981
7138
  }
6982
7139
  stop() {
6983
- this.interactionManager.removeListeners();
6984
- this.interactionManager.stopObserving();
7140
+ this.#container.interactionManager?.removeListeners();
7141
+ this.#container.interactionManager?.stopObserving();
6985
7142
  }
6986
7143
  }
6987
7144
 
@@ -7175,6 +7332,7 @@
7175
7332
  exports.loadLinksPreset = loadLinksPreset;
7176
7333
  exports.tsParticles = tsParticles;
7177
7334
 
7178
- }));
7335
+ })(g.__tsParticlesInternals.presets.links = g.__tsParticlesInternals.presets.links || {});
7336
+ })(typeof globalThis !== "undefined" ? globalThis : typeof window !== "undefined" ? window : self);
7337
+
7179
7338
  Object.assign(globalThis.window || globalThis, { loadLinksPreset: (globalThis.__tsParticlesInternals.presets.links || {}).loadLinksPreset });
7180
- delete (globalThis.window || globalThis).tsparticlesInternalExports;