@tsparticles/preset-firefly 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.firefly = global.__tsParticlesInternals.presets.firefly || {})));
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", 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 = 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 = 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", 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 = 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 = 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
  }
@@ -270,11 +301,61 @@
270
301
  };
271
302
  }
272
303
  function parseAlpha(input) {
273
- const defaultAlpha = 1;
274
304
  if (!input) {
275
305
  return defaultAlpha;
276
306
  }
277
- return input.endsWith("%") ? parseFloat(input) / percentDenominator : parseFloat(input);
307
+ return input.endsWith("%") ? Number.parseFloat(input) / percentDenominator : Number.parseFloat(input);
308
+ }
309
+
310
+ const ErrorCodes$2 = {
311
+ engineVersionMismatch: "TSP-1001",
312
+ particlePositionNotFound: "TSP-1002",
313
+ pluginRegisterAfterLoad: "TSP-1003",
314
+ offscreenCanvasUnsupported: "TSP-1101",
315
+ offscreenCanvasTransferFailed: "TSP-1102",
316
+ hdrEnableInvalid: "TSP-1201",
317
+ hdrModeInvalid: "TSP-1202",
318
+ hdrPeakNitsInvalid: "TSP-1203",
319
+ };
320
+
321
+ const messages = {
322
+ [ErrorCodes$2.engineVersionMismatch]: "The tsParticles version is different from the loaded plugins version. Engine version: {0}. Plugin version: {1}",
323
+ [ErrorCodes$2.particlePositionNotFound]: "a valid position cannot be found for particle",
324
+ [ErrorCodes$2.pluginRegisterAfterLoad]: "Register plugins can only be done before calling tsParticles.load()",
325
+ [ErrorCodes$2.offscreenCanvasUnsupported]: "OffscreenCanvas is required but not supported by this browser",
326
+ [ErrorCodes$2.offscreenCanvasTransferFailed]: "OffscreenCanvas transfer failed",
327
+ [ErrorCodes$2.hdrEnableInvalid]: 'Invalid HDR "enable" value: expected a boolean, got "{0}"',
328
+ [ErrorCodes$2.hdrModeInvalid]: 'Invalid HDR "mode" value: expected one of {0}, got "{1}"',
329
+ [ErrorCodes$2.hdrPeakNitsInvalid]: 'Invalid HDR "peakNits" value: expected a positive number, got "{0}"',
330
+ };
331
+
332
+ let registeredMessages;
333
+ const ensureRegisteredMessages = () => {
334
+ registeredMessages ??= new Map(Object.entries(messages));
335
+ return registeredMessages;
336
+ }, toStringValue$1 = (value) => String(value), format = (template, args) => {
337
+ return template.replace(/\{(\d+)\}/g, (match, index) => {
338
+ const arg = args[Number(index)];
339
+ return arg === undefined ? match : toStringValue$1(arg);
340
+ });
341
+ };
342
+ function addErrorMessages(extraMessages) {
343
+ if (typeof process !== "undefined" && process.env.NODE_ENV === "production") {
344
+ return;
345
+ }
346
+ const catalog = ensureRegisteredMessages();
347
+ for (const [code, message] of Object.entries(extraMessages)) {
348
+ if (message !== undefined) {
349
+ catalog.set(code, message);
350
+ }
351
+ }
352
+ }
353
+ function getErrorMessage(code, ...args) {
354
+ if (typeof process !== "undefined" && process.env.NODE_ENV === "production") {
355
+ return `[tsParticles Error ${code}] https://particles.js.org/errors/#${code}`;
356
+ }
357
+ const template = ensureRegisteredMessages().get(code) ?? `Unknown error code ${code}`;
358
+ return format(template, args);
278
359
  }
279
360
 
280
361
  var OutModeDirection;
@@ -291,7 +372,6 @@
291
372
  PixelMode["percent"] = "percent";
292
373
  })(PixelMode || (PixelMode = {}));
293
374
 
294
- const minRadius = 0;
295
375
  function isForbiddenKey(key) {
296
376
  return key === "__proto__" || key === "constructor" || key === "prototype";
297
377
  }
@@ -487,22 +567,84 @@
487
567
  element.removeEventListener(event, handler, removeOptions);
488
568
  }
489
569
  }
490
- async function getItemsFromInitializer(container, map, initializers, force = false) {
491
- let res = map.get(container);
492
- if (!res || force) {
493
- res = await Promise.all([...initializers.values()].map(t => t(container)));
494
- map.set(container, res);
570
+ async function getItemsFromInitializer(container, initializers) {
571
+ return await Promise.all([...initializers.values()].map(t => t(container)));
572
+ }
573
+ async function getItemMapFromInitializer(container, initializers) {
574
+ const entries = await Promise.all([...initializers.entries()].map(([key, initializer]) => initializer(container).then(item => [key, item])));
575
+ return new Map(entries);
576
+ }
577
+ async function getDataFromUrl(data) {
578
+ const url = itemFromSingleOrMultiple(data.url, data.index);
579
+ if (!url) {
580
+ return data.fallback;
495
581
  }
496
- return res;
582
+ try {
583
+ const response = await fetch(url);
584
+ if (response.ok) {
585
+ const current = (await response.json());
586
+ if (isSourceOptionsValue(current)) {
587
+ return current;
588
+ }
589
+ getLogger().error("invalid configuration data while retrieving config file");
590
+ }
591
+ else {
592
+ getLogger().error(`${response.status.toString()} while retrieving config file`);
593
+ }
594
+ }
595
+ catch (error) {
596
+ getLogger().error(`error while retrieving config file: ${error}`);
597
+ }
598
+ return data.fallback;
497
599
  }
498
- async function getItemMapFromInitializer(container, map, initializers, force = false) {
499
- let res = map.get(container);
500
- if (!res || force) {
501
- const entries = await Promise.all([...initializers.entries()].map(([key, initializer]) => initializer(container).then(item => [key, item])));
502
- res = new Map(entries);
503
- map.set(container, res);
600
+ function isSourceOptionsValue(value) {
601
+ if (isArray(value)) {
602
+ return value.every((entry) => isObject(entry) && !isArray(entry));
504
603
  }
505
- return res;
604
+ return isObject(value) && !isArray(value);
605
+ }
606
+ function getCanvasFromContainer(domContainer) {
607
+ let canvasEl;
608
+ const documentSafe = safeDocument(), isCanvas = domContainer instanceof HTMLCanvasElement || domContainer.tagName.toLowerCase() === canvasTag;
609
+ if (isCanvas) {
610
+ canvasEl = domContainer;
611
+ canvasEl.dataset[generatedAttribute] ??= generatedFalse;
612
+ if (canvasEl.dataset[generatedAttribute] === generatedTrue) {
613
+ canvasEl.style.width ||= fullPercent;
614
+ canvasEl.style.height ||= fullPercent;
615
+ canvasEl.style.pointerEvents = "none";
616
+ canvasEl.style.setProperty("pointer-events", "none");
617
+ }
618
+ }
619
+ else {
620
+ const existingCanvases = domContainer.getElementsByTagName(canvasTag), foundCanvas = existingCanvases.item(canvasFirstIndex);
621
+ if (foundCanvas) {
622
+ canvasEl = foundCanvas;
623
+ canvasEl.dataset[generatedAttribute] = generatedFalse;
624
+ }
625
+ else {
626
+ canvasEl = documentSafe.createElement(canvasTag);
627
+ canvasEl.dataset[generatedAttribute] = generatedTrue;
628
+ domContainer.appendChild(canvasEl);
629
+ }
630
+ canvasEl.style.width ||= fullPercent;
631
+ canvasEl.style.height ||= fullPercent;
632
+ canvasEl.style.pointerEvents = "none";
633
+ canvasEl.style.setProperty("pointer-events", "none");
634
+ }
635
+ return canvasEl;
636
+ }
637
+ function getDomContainer(id, source) {
638
+ const documentSafe = safeDocument();
639
+ let domContainer = source ?? documentSafe.getElementById(id);
640
+ if (domContainer) {
641
+ return domContainer;
642
+ }
643
+ domContainer = documentSafe.createElement("canvas");
644
+ domContainer.id = id;
645
+ domContainer.dataset[generatedAttribute] = generatedTrue;
646
+ documentSafe.body.append(domContainer);
647
+ return domContainer;
506
648
  }
507
649
 
508
650
  class EventDispatcher {
@@ -573,7 +715,6 @@
573
715
  class PluginManager {
574
716
  colorManagers = new Map();
575
717
  easingFunctions = new Map();
576
- effectDrawers = new Map();
577
718
  initializers = {
578
719
  effects: new Map(),
579
720
  shapes: new Map(),
@@ -582,8 +723,6 @@
582
723
  palettes = new Map();
583
724
  plugins = [];
584
725
  presets = new Map();
585
- shapeDrawers = new Map();
586
- updaters = new Map();
587
726
  #allLoadersSet = new Set();
588
727
  #configs = new Map();
589
728
  #engine;
@@ -601,57 +740,79 @@
601
740
  }
602
741
  return res;
603
742
  }
743
+ get initialized() {
744
+ return this.#initialized;
745
+ }
604
746
  addColorManager(name, manager) {
747
+ if (this.#initialized) {
748
+ return;
749
+ }
605
750
  this.colorManagers.set(name, manager);
606
751
  }
607
752
  addConfig(config) {
753
+ if (this.#initialized) {
754
+ return;
755
+ }
608
756
  const key = config.key ?? config.name ?? "default";
609
757
  this.#configs.set(key, config);
610
758
  this.#engine.dispatchEvent(EventType.configAdded, { data: { name: key, config } });
611
759
  }
612
760
  addEasing(name, easing) {
761
+ if (this.#initialized) {
762
+ return;
763
+ }
613
764
  if (this.easingFunctions.get(name)) {
614
765
  return;
615
766
  }
616
767
  this.easingFunctions.set(name, easing);
617
768
  }
618
769
  addEffect(effect, drawer) {
770
+ if (this.#initialized) {
771
+ return;
772
+ }
619
773
  this.initializers.effects.set(effect, drawer);
620
774
  }
621
775
  addPalette(name, palette) {
776
+ if (this.#initialized) {
777
+ return;
778
+ }
622
779
  this.palettes.set(name, palette);
623
780
  }
624
781
  addParticleUpdater(name, updaterInitializer) {
782
+ if (this.#initialized) {
783
+ return;
784
+ }
625
785
  this.initializers.updaters.set(name, updaterInitializer);
626
786
  }
627
787
  addPlugin(plugin) {
788
+ if (this.#initialized) {
789
+ return;
790
+ }
628
791
  if (this.getPlugin(plugin.id)) {
629
792
  return;
630
793
  }
631
794
  this.plugins.push(plugin);
632
795
  }
633
796
  addPreset(preset, options, override = false) {
797
+ if (this.#initialized) {
798
+ return;
799
+ }
634
800
  if (!(override || !this.getPreset(preset))) {
635
801
  return;
636
802
  }
637
803
  this.presets.set(preset, options);
638
804
  }
639
805
  addShape(shapes, drawer) {
806
+ if (this.#initialized) {
807
+ return;
808
+ }
640
809
  for (const shape of shapes) {
641
810
  this.initializers.shapes.set(shape, drawer);
642
811
  }
643
812
  }
644
- clearPlugins(container) {
645
- this.effectDrawers.delete(container);
646
- this.shapeDrawers.delete(container);
647
- this.updaters.delete(container);
648
- }
649
813
  getEasing(name) {
650
814
  return this.easingFunctions.get(name) ?? ((value) => value);
651
815
  }
652
- getEffectDrawers(container, force = false) {
653
- return getItemMapFromInitializer(container, this.effectDrawers, this.initializers.effects, force);
654
- }
655
816
  getPalette(name) {
656
817
  return this.palettes.get(name);
657
818
  }
@@ -661,12 +822,6 @@
661
822
  getPreset(preset) {
662
823
  return this.presets.get(preset);
663
824
  }
664
- async getShapeDrawers(container, force = false) {
665
- return getItemMapFromInitializer(container, this.shapeDrawers, this.initializers.shapes, force);
666
- }
667
- async getUpdaters(container, force = false) {
668
- return getItemsFromInitializer(container, this.updaters, this.initializers.updaters, force);
669
- }
670
825
  async init() {
671
826
  if (this.#initialized || this.#isRunningLoaders) {
672
827
  return;
@@ -685,16 +840,9 @@
685
840
  this.#initialized = true;
686
841
  }
687
842
  }
688
- loadParticlesOptions(container, options, ...sourceOptions) {
689
- const updaters = this.updaters.get(container);
690
- if (!updaters) {
691
- return;
692
- }
693
- updaters.forEach(updater => updater.loadOptions?.(options, ...sourceOptions));
694
- }
695
843
  async register(...loaders) {
696
844
  if (this.#initialized) {
697
- throw new Error("Register plugins can only be done before calling tsParticles.load()");
845
+ throw new Error(getErrorMessage(ErrorCodes$2.pluginRegisterAfterLoad));
698
846
  }
699
847
  for (const loader of loaders) {
700
848
  if (this.#isRunningLoaders) {
@@ -706,88 +854,15 @@
706
854
  }
707
855
  }
708
856
  async #runLoader(loader, executed, allLoaders) {
709
- if (executed.has(loader))
857
+ if (executed.has(loader)) {
710
858
  return;
859
+ }
711
860
  executed.add(loader);
712
861
  allLoaders.add(loader);
713
862
  await loader(this.#engine);
714
863
  }
715
864
  }
716
865
 
717
- const errorPrefix = "tsParticles - Error";
718
- const wrap = (fn) => (...args) => {
719
- fn(...args);
720
- }, _logger = {
721
- debug: wrap(console.debug),
722
- error: (message, ...optionalParams) => {
723
- console.error(`${errorPrefix} - ${message}`, ...optionalParams);
724
- },
725
- info: wrap(console.info),
726
- log: wrap(console.log),
727
- trace: wrap(console.trace),
728
- verbose: wrap(console.log),
729
- warning: wrap(console.warn),
730
- };
731
- function getLogger() {
732
- return _logger;
733
- }
734
-
735
- const fullPercent = "100%";
736
- async function getDataFromUrl(data) {
737
- const url = itemFromSingleOrMultiple(data.url, data.index);
738
- if (!url) {
739
- return data.fallback;
740
- }
741
- const response = await fetch(url);
742
- if (response.ok) {
743
- return (await response.json());
744
- }
745
- getLogger().error(`${response.status.toString()} while retrieving config file`);
746
- return data.fallback;
747
- }
748
- const getCanvasFromContainer = (domContainer) => {
749
- const documentSafe = safeDocument();
750
- let canvasEl;
751
- const isCanvas = domContainer instanceof HTMLCanvasElement || domContainer.tagName.toLowerCase() === canvasTag;
752
- if (isCanvas) {
753
- canvasEl = domContainer;
754
- canvasEl.dataset[generatedAttribute] ??= generatedFalse;
755
- if (canvasEl.dataset[generatedAttribute] === generatedTrue) {
756
- canvasEl.style.width ||= fullPercent;
757
- canvasEl.style.height ||= fullPercent;
758
- canvasEl.style.pointerEvents = "none";
759
- canvasEl.style.setProperty("pointer-events", "none");
760
- }
761
- }
762
- else {
763
- const existingCanvases = domContainer.getElementsByTagName(canvasTag), foundCanvas = existingCanvases.item(canvasFirstIndex);
764
- if (foundCanvas) {
765
- canvasEl = foundCanvas;
766
- canvasEl.dataset[generatedAttribute] = generatedFalse;
767
- }
768
- else {
769
- canvasEl = documentSafe.createElement(canvasTag);
770
- canvasEl.dataset[generatedAttribute] = generatedTrue;
771
- domContainer.appendChild(canvasEl);
772
- }
773
- canvasEl.style.width ||= fullPercent;
774
- canvasEl.style.height ||= fullPercent;
775
- canvasEl.style.pointerEvents = "none";
776
- canvasEl.style.setProperty("pointer-events", "none");
777
- }
778
- return canvasEl;
779
- }, getDomContainer = (id, source) => {
780
- const documentSafe = safeDocument();
781
- let domContainer = source ?? documentSafe.getElementById(id);
782
- if (domContainer) {
783
- return domContainer;
784
- }
785
- domContainer = documentSafe.createElement("canvas");
786
- domContainer.id = id;
787
- domContainer.dataset[generatedAttribute] = generatedTrue;
788
- documentSafe.body.append(domContainer);
789
- return domContainer;
790
- };
791
866
  class Engine {
792
867
  pluginManager = new PluginManager(this);
793
868
  #domArray = [];
@@ -797,7 +872,7 @@
797
872
  return this.#domArray;
798
873
  }
799
874
  get version() {
800
- return "4.4.0";
875
+ return "4.5.0";
801
876
  }
802
877
  addEventListener(type, listener) {
803
878
  this.#eventDispatcher.addEventListener(type, listener);
@@ -806,7 +881,7 @@
806
881
  if (this.version === pluginVersion) {
807
882
  return;
808
883
  }
809
- throw new Error(`The tsParticles version is different from the loaded plugins version. Engine version: ${this.version}. Plugin version: ${pluginVersion}`);
884
+ throw new Error(getErrorMessage(ErrorCodes$2.engineVersionMismatch, this.version, pluginVersion));
810
885
  }
811
886
  dispatchEvent(type, args) {
812
887
  this.#eventDispatcher.dispatchEvent(type, args);
@@ -1055,20 +1130,6 @@
1055
1130
  DrawLayer[DrawLayer["Foreground"] = 7] = "Foreground";
1056
1131
  })(DrawLayer || (DrawLayer = {}));
1057
1132
 
1058
- class OptionLoader {
1059
- load(data) {
1060
- if (isNull(data)) {
1061
- return;
1062
- }
1063
- this.doLoad(data);
1064
- }
1065
- }
1066
- function loadOptions(options, ...sourceOptionsArr) {
1067
- for (const sourceOptions of sourceOptionsArr) {
1068
- options.load(sourceOptions);
1069
- }
1070
- }
1071
-
1072
1133
  function loadProperty(obj, key, value) {
1073
1134
  if (value !== undefined) {
1074
1135
  obj[key] = value;
@@ -1100,6 +1161,20 @@
1100
1161
  }
1101
1162
  }
1102
1163
 
1164
+ class OptionLoader {
1165
+ load(data) {
1166
+ if (isNull(data)) {
1167
+ return;
1168
+ }
1169
+ this.doLoad(data);
1170
+ }
1171
+ }
1172
+ function loadOptions(options, ...sourceOptionsArr) {
1173
+ for (const sourceOptions of sourceOptionsArr) {
1174
+ options.load(sourceOptions);
1175
+ }
1176
+ }
1177
+
1103
1178
  class AnimationOptions extends OptionLoader {
1104
1179
  count = 0;
1105
1180
  decay = 0;
@@ -1250,15 +1325,14 @@
1250
1325
  peakNits = defaultPeakNits;
1251
1326
  doLoad(data) {
1252
1327
  if (data.enable !== undefined && !isBoolean(data.enable)) {
1253
- throw new Error(`Invalid HDR "enable" value: expected a boolean, got "${String(data.enable)}"`);
1328
+ throw new Error(getErrorMessage(ErrorCodes$2.hdrEnableInvalid, String(data.enable)));
1254
1329
  }
1255
- if (data.mode !== undefined &&
1256
- (typeof data.mode !== "string" || !Object.values(HdrMode).includes(data.mode))) {
1257
- throw new Error(`Invalid HDR "mode" value: expected one of ${Object.values(HdrMode).join(", ")}, got "${toStringValue(data.mode)}"`);
1330
+ if (data.mode !== undefined && !isEnumValue(HdrMode, data.mode)) {
1331
+ throw new Error(getErrorMessage(ErrorCodes$2.hdrModeInvalid, Object.values(HdrMode).join(", "), toStringValue(data.mode)));
1258
1332
  }
1259
1333
  if (data.peakNits !== undefined &&
1260
1334
  (!isNumber(data.peakNits) || !Number.isFinite(data.peakNits) || data.peakNits <= minPeakNits)) {
1261
- throw new Error(`Invalid HDR "peakNits" value: expected a positive number, got "${String(data.peakNits)}"`);
1335
+ throw new Error(getErrorMessage(ErrorCodes$2.hdrPeakNitsInvalid, String(data.peakNits)));
1262
1336
  }
1263
1337
  loadProperty(this, "enable", data.enable);
1264
1338
  loadProperty(this, "mode", data.mode);
@@ -1636,12 +1710,10 @@
1636
1710
  plugin.loadParticlesOptions(this.#container, this, data);
1637
1711
  }
1638
1712
  }
1639
- const updaters = this.#pluginManager.updaters.get(this.#container);
1640
- if (updaters) {
1641
- for (const updater of updaters) {
1642
- if (updater.loadOptions) {
1643
- updater.loadOptions(this, data);
1644
- }
1713
+ const updaters = this.#container.particleUpdaters;
1714
+ for (const updater of updaters) {
1715
+ if (updater.loadOptions) {
1716
+ updater.loadOptions(this, data);
1645
1717
  }
1646
1718
  }
1647
1719
  }
@@ -1974,9 +2046,9 @@
1974
2046
  const grayscaleValue = Math.round(lNormalized * rgbMax);
1975
2047
  return { r: grayscaleValue, g: grayscaleValue, b: grayscaleValue };
1976
2048
  }
1977
- const temp1 = lNormalized < half
2049
+ const temp2 = lNormalized < half
1978
2050
  ? lNormalized * (sNormalizedOffset + sNormalized)
1979
- : 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));
2051
+ : 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));
1980
2052
  return { r: Math.round(red), g: Math.round(green), b: Math.round(blue) };
1981
2053
  }
1982
2054
  function hslToRgbFloat(hsl) {
@@ -1985,9 +2057,9 @@
1985
2057
  const grayscaleValue = lNormalized * rgbMax;
1986
2058
  return { r: grayscaleValue, g: grayscaleValue, b: grayscaleValue };
1987
2059
  }
1988
- const temp1 = lNormalized < half
2060
+ const temp2 = lNormalized < half
1989
2061
  ? lNormalized * (sNormalizedOffset + sNormalized)
1990
- : 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));
2062
+ : 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));
1991
2063
  return { r: red, g: green, b: blue };
1992
2064
  }
1993
2065
  function hslaToRgba(hsla) {
@@ -2201,7 +2273,7 @@
2201
2273
  }
2202
2274
 
2203
2275
  async function loadBlendPlugin(engine) {
2204
- engine.checkVersion("4.4.0");
2276
+ engine.checkVersion("4.5.0");
2205
2277
  await engine.pluginManager.register(e => {
2206
2278
  e.pluginManager.addPlugin(new BlendPlugin());
2207
2279
  });
@@ -2238,7 +2310,7 @@
2238
2310
  }
2239
2311
 
2240
2312
  async function loadCircleShape(engine) {
2241
- engine.checkVersion("4.4.0");
2313
+ engine.checkVersion("4.5.0");
2242
2314
  await engine.pluginManager.register(e => {
2243
2315
  e.pluginManager.addShape(["circle"], () => {
2244
2316
  return Promise.resolve(new CircleDrawer());
@@ -2253,7 +2325,7 @@
2253
2325
  RgbIndexes[RgbIndexes["b"] = 3] = "b";
2254
2326
  RgbIndexes[RgbIndexes["a"] = 4] = "a";
2255
2327
  })(RgbIndexes$1 || (RgbIndexes$1 = {}));
2256
- 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;
2328
+ 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;
2257
2329
  class HexColorManager {
2258
2330
  accepts(input) {
2259
2331
  return input.startsWith("#");
@@ -2286,7 +2358,7 @@
2286
2358
  }
2287
2359
 
2288
2360
  async function loadHexColorPlugin(engine) {
2289
- engine.checkVersion("4.4.0");
2361
+ engine.checkVersion("4.5.0");
2290
2362
  await engine.pluginManager.register(e => {
2291
2363
  e.pluginManager.addColorManager("hex", new HexColorManager());
2292
2364
  });
@@ -2326,7 +2398,7 @@
2326
2398
  if (!this.accepts(input)) {
2327
2399
  return;
2328
2400
  }
2329
- const result = hslRegex.exec(input), minLength = 4, defaultAlpha = 1, radix = 10;
2401
+ const result = hslRegex.exec(input), minLength = 4, radix = 10;
2330
2402
  return result
2331
2403
  ? hslaToRgba({
2332
2404
  a: result.length > minLength ? parseAlpha(result[HslIndexes.a]) : defaultAlpha,
@@ -2339,12 +2411,20 @@
2339
2411
  }
2340
2412
 
2341
2413
  async function loadHslColorPlugin(engine) {
2342
- engine.checkVersion("4.4.0");
2414
+ engine.checkVersion("4.5.0");
2343
2415
  await engine.pluginManager.register(e => {
2344
2416
  e.pluginManager.addColorManager("hsl", new HslColorManager());
2345
2417
  });
2346
2418
  }
2347
2419
 
2420
+ const ErrorCodes$1 = {
2421
+ baseMoverNotLoaded: "TSP-3203",
2422
+ };
2423
+
2424
+ const ErrorMessages$1 = {
2425
+ [ErrorCodes$1.baseMoverNotLoaded]: "tsParticles Base Mover is not loaded",
2426
+ };
2427
+
2348
2428
  class MovePlugin {
2349
2429
  id = "move";
2350
2430
  #pluginManager;
@@ -2363,20 +2443,20 @@
2363
2443
  }
2364
2444
 
2365
2445
  async function loadMovePlugin(engine) {
2366
- engine.checkVersion("4.4.0");
2446
+ engine.checkVersion("4.5.0");
2447
+ if (typeof process !== "undefined" && process.env.NODE_ENV !== "production") {
2448
+ addErrorMessages(ErrorMessages$1);
2449
+ }
2367
2450
  await engine.pluginManager.register(e => {
2368
2451
  const moveEngine = e, movePluginManager = moveEngine.pluginManager;
2369
2452
  movePluginManager.initializers.pathGenerators ??= new Map();
2370
- movePluginManager.pathGenerators ??= new Map();
2371
2453
  movePluginManager.addPathGenerator = (name, generator) => {
2454
+ if (movePluginManager.initialized) {
2455
+ return;
2456
+ }
2372
2457
  movePluginManager.initializers.pathGenerators ??= new Map();
2373
2458
  movePluginManager.initializers.pathGenerators.set(name, generator);
2374
2459
  };
2375
- movePluginManager.getPathGenerators = async (container, force = false) => {
2376
- movePluginManager.initializers.pathGenerators ??= new Map();
2377
- movePluginManager.pathGenerators ??= new Map();
2378
- return getItemMapFromInitializer(container, movePluginManager.pathGenerators, movePluginManager.initializers.pathGenerators, force);
2379
- };
2380
2460
  e.pluginManager.addPlugin(new MovePlugin(e.pluginManager));
2381
2461
  });
2382
2462
  }
@@ -2573,7 +2653,7 @@
2573
2653
  }
2574
2654
 
2575
2655
  async function loadOpacityUpdater(engine) {
2576
- engine.checkVersion("4.4.0");
2656
+ engine.checkVersion("4.5.0");
2577
2657
  await engine.pluginManager.register(e => {
2578
2658
  e.pluginManager.addParticleUpdater("opacity", container => {
2579
2659
  return Promise.resolve(new OpacityUpdater(container));
@@ -2582,70 +2662,60 @@
2582
2662
  }
2583
2663
 
2584
2664
  const boundsMin = 0;
2585
- function bounceHorizontal(data) {
2586
- if ((data.outMode !== OutMode.bounce && data.outMode !== OutMode.split) ||
2587
- (data.direction !== OutModeDirection.left && data.direction !== OutModeDirection.right)) {
2588
- return;
2589
- }
2590
- if (data.bounds.right < boundsMin && data.direction === OutModeDirection.left) {
2591
- data.particle.position.x = data.size + data.offset.x;
2592
- }
2593
- else if (data.bounds.left > data.canvasSize.width && data.direction === OutModeDirection.right) {
2594
- data.particle.position.x = data.canvasSize.width - data.size - data.offset.x;
2595
- }
2596
- const velocity = data.particle.velocity.x;
2597
- let bounced = false;
2598
- if (data.outOfCanvas &&
2599
- ((data.direction === OutModeDirection.right && velocity > minVelocity) ||
2600
- (data.direction === OutModeDirection.left && velocity < minVelocity))) {
2601
- const newVelocity = getRangeValue(data.particle.options.bounce.horizontal.value);
2602
- data.particle.velocity.x *= -newVelocity;
2603
- bounced = true;
2604
- }
2605
- if (!bounced) {
2606
- return;
2607
- }
2608
- const minPos = data.offset.x + data.size;
2609
- if (data.outOfCanvas && data.direction === OutModeDirection.right) {
2610
- data.particle.position.x = data.canvasSize.width - minPos;
2611
- }
2612
- else if (data.outOfCanvas && data.direction === OutModeDirection.left) {
2613
- data.particle.position.x = minPos;
2614
- }
2615
- if (data.outMode === OutMode.split) {
2616
- data.particle.destroy();
2617
- }
2618
- }
2619
- function bounceVertical(data) {
2620
- if ((data.outMode !== OutMode.bounce && data.outMode !== OutMode.split) ||
2621
- (data.direction !== OutModeDirection.bottom && data.direction !== OutModeDirection.top)) {
2665
+ const bounceAxisConfigs = {
2666
+ [OutModeDirection.left]: {
2667
+ axis: "x",
2668
+ canvas: "width",
2669
+ bounce: "horizontal",
2670
+ negativeEdge: "right",
2671
+ positiveEdge: "left",
2672
+ negative: true,
2673
+ },
2674
+ [OutModeDirection.right]: {
2675
+ axis: "x",
2676
+ canvas: "width",
2677
+ bounce: "horizontal",
2678
+ negativeEdge: "right",
2679
+ positiveEdge: "left",
2680
+ negative: false,
2681
+ },
2682
+ [OutModeDirection.top]: {
2683
+ axis: "y",
2684
+ canvas: "height",
2685
+ bounce: "vertical",
2686
+ negativeEdge: "bottom",
2687
+ positiveEdge: "top",
2688
+ negative: true,
2689
+ },
2690
+ [OutModeDirection.bottom]: {
2691
+ axis: "y",
2692
+ canvas: "height",
2693
+ bounce: "vertical",
2694
+ negativeEdge: "bottom",
2695
+ positiveEdge: "top",
2696
+ negative: false,
2697
+ },
2698
+ };
2699
+ function bounce(data) {
2700
+ if ((data.outMode !== OutMode.bounce && data.outMode !== OutMode.split) || !(data.direction in bounceAxisConfigs)) {
2622
2701
  return;
2623
2702
  }
2624
- if (data.bounds.bottom < boundsMin && data.direction === OutModeDirection.top) {
2625
- data.particle.position.y = data.size + data.offset.y;
2703
+ const config = bounceAxisConfigs[data.direction], bounds = data.bounds, canvasDim = data.canvasSize[config.canvas], position = data.particle.position, velocity = data.particle.velocity[config.axis];
2704
+ if (config.negative && bounds[config.negativeEdge] < boundsMin) {
2705
+ position[config.axis] = data.size + data.offset[config.axis];
2626
2706
  }
2627
- else if (data.bounds.top > data.canvasSize.height && data.direction === OutModeDirection.bottom) {
2628
- data.particle.position.y = data.canvasSize.height - data.size - data.offset.y;
2707
+ else if (!config.negative && bounds[config.positiveEdge] > canvasDim) {
2708
+ position[config.axis] = canvasDim - data.size - data.offset[config.axis];
2629
2709
  }
2630
- const velocity = data.particle.velocity.y;
2631
- let bounced = false;
2632
2710
  if (data.outOfCanvas &&
2633
- ((data.direction === OutModeDirection.bottom && velocity > minVelocity) ||
2634
- (data.direction === OutModeDirection.top && velocity < minVelocity))) {
2635
- const newVelocity = getRangeValue(data.particle.options.bounce.vertical.value);
2636
- data.particle.velocity.y *= -newVelocity;
2637
- bounced = true;
2711
+ ((config.negative && velocity < minVelocity) || (!config.negative && velocity > minVelocity))) {
2712
+ data.particle.velocity[config.axis] *= -getRangeValue(data.particle.options.bounce[config.bounce].value);
2638
2713
  }
2639
- if (!bounced) {
2714
+ else {
2640
2715
  return;
2641
2716
  }
2642
- const minPos = data.offset.y + data.size;
2643
- if (data.outOfCanvas && data.direction === OutModeDirection.bottom) {
2644
- data.particle.position.y = data.canvasSize.height - minPos;
2645
- }
2646
- else if (data.outOfCanvas && data.direction === OutModeDirection.top) {
2647
- data.particle.position.y = minPos;
2648
- }
2717
+ const minPos = data.offset[config.axis] + data.size;
2718
+ position[config.axis] = config.negative ? minPos : canvasDim - minPos;
2649
2719
  if (data.outMode === OutMode.split) {
2650
2720
  data.particle.destroy();
2651
2721
  }
@@ -2661,26 +2731,19 @@
2661
2731
  OutMode.bounce,
2662
2732
  OutMode.split,
2663
2733
  ];
2664
- this.#particleBouncePlugins = container.plugins.filter(p => p.particleBounce !== undefined);
2734
+ this.#particleBouncePlugins = container.plugins.filter(p => !!p.particleBounce);
2665
2735
  }
2666
2736
  update(particle, direction, delta, outMode) {
2667
2737
  if (!this.modes.includes(outMode)) {
2668
2738
  return;
2669
2739
  }
2670
- const container = this.#container;
2671
- let handled = false;
2672
2740
  for (const plugin of this.#particleBouncePlugins) {
2673
- handled = plugin.particleBounce?.(particle, delta, direction) ?? false;
2674
- if (handled) {
2675
- break;
2741
+ if (plugin.particleBounce?.(particle, delta, direction)) {
2742
+ return;
2676
2743
  }
2677
2744
  }
2678
- if (handled) {
2679
- return;
2680
- }
2681
- const pos = particle.getPosition(), offset = particle.offset, size = particle.getRadius(), bounds = calculateBounds(pos, size), canvasSize = container.canvas.size, outOfCanvas = !particle.isInsideCanvasForOutMode(outMode, direction);
2682
- bounceHorizontal({ particle, outMode, direction, bounds, canvasSize, offset, outOfCanvas, size });
2683
- bounceVertical({ particle, outMode, direction, bounds, canvasSize, offset, outOfCanvas, size });
2745
+ const pos = particle.getPosition(), offset = particle.offset, size = particle.getRadius(), bounds = calculateBounds(pos, size), canvasSize = this.#container.canvas.size, outOfCanvas = !particle.isInsideCanvasForOutMode(outMode, direction);
2746
+ bounce({ particle, outMode, direction, bounds, canvasSize, offset, outOfCanvas, size });
2684
2747
  }
2685
2748
  }
2686
2749
 
@@ -2769,107 +2832,108 @@
2769
2832
  return;
2770
2833
  }
2771
2834
  const container = this.#container;
2772
- switch (particle.outType) {
2773
- case ParticleOutType.inside: {
2774
- const { x: vx, y: vy } = particle.velocity;
2775
- updateVector.setTo(originPoint);
2776
- updateVector.length = particle.moveCenter.radius;
2777
- updateVector.angle = particle.velocity.angle + Math.PI;
2778
- updateVector.addTo(particle.moveCenter);
2779
- const { dx, dy } = getDistances(particle.position, updateVector);
2780
- if ((vx <= minVelocity && dx >= minDistance) ||
2781
- (vy <= minVelocity && dy >= minDistance) ||
2782
- (vx >= minVelocity && dx <= minDistance) ||
2783
- (vy >= minVelocity && dy <= minDistance)) {
2784
- return;
2785
- }
2786
- particle.position.x = Math.floor(randomInRangeValue({
2787
- min: 0,
2788
- max: container.canvas.size.width,
2789
- }));
2790
- particle.position.y = Math.floor(randomInRangeValue({
2791
- min: 0,
2792
- max: container.canvas.size.height,
2793
- }));
2794
- const { dx: newDx, dy: newDy } = getDistances(particle.position, particle.moveCenter);
2795
- particle.direction = Math.atan2(-newDy, -newDx);
2796
- particle.velocity.angle = particle.direction;
2797
- particle.justWarped = true;
2798
- break;
2835
+ if (particle.outType === ParticleOutType.inside) {
2836
+ this.#applyOutModeInside(particle, container);
2837
+ }
2838
+ else {
2839
+ if (particle.isInsideCanvasForOutMode(outMode, direction)) {
2840
+ return;
2799
2841
  }
2800
- default: {
2801
- if (particle.isInsideCanvasForOutMode(outMode, direction)) {
2802
- return;
2803
- }
2804
- switch (particle.outType) {
2805
- case ParticleOutType.outside: {
2806
- particle.position.x =
2807
- Math.floor(randomInRangeValue({
2808
- min: -particle.moveCenter.radius,
2809
- max: particle.moveCenter.radius,
2810
- })) + particle.moveCenter.x;
2811
- particle.position.y =
2812
- Math.floor(randomInRangeValue({
2813
- min: -particle.moveCenter.radius,
2814
- max: particle.moveCenter.radius,
2815
- })) + particle.moveCenter.y;
2816
- const { dx, dy } = getDistances(particle.position, particle.moveCenter);
2817
- if (particle.moveCenter.radius) {
2818
- particle.direction = Math.atan2(dy, dx);
2819
- particle.velocity.angle = particle.direction;
2820
- }
2821
- particle.justWarped = true;
2822
- break;
2823
- }
2824
- case ParticleOutType.normal: {
2825
- const warp = particle.options.move.warp, canvasSize = container.canvas.size, newPos = {
2826
- bottom: canvasSize.height + particle.getRadius() + particle.offset.y,
2827
- left: -particle.getRadius() - particle.offset.x,
2828
- right: canvasSize.width + particle.getRadius() + particle.offset.x,
2829
- top: -particle.getRadius() - particle.offset.y,
2830
- }, sizeValue = particle.getRadius(), nextBounds = calculateBounds(particle.position, sizeValue);
2831
- if (direction === OutModeDirection.right && nextBounds.left > canvasSize.width + particle.offset.x) {
2832
- particle.position.x = newPos.left;
2833
- particle.initialPosition.x = particle.position.x;
2834
- if (!warp) {
2835
- particle.position.y = getRandom() * canvasSize.height;
2836
- particle.initialPosition.y = particle.position.y;
2837
- }
2838
- particle.justWarped = true;
2839
- }
2840
- else if (direction === OutModeDirection.left && nextBounds.right < -particle.offset.x) {
2841
- particle.position.x = newPos.right;
2842
- particle.initialPosition.x = particle.position.x;
2843
- if (!warp) {
2844
- particle.position.y = getRandom() * canvasSize.height;
2845
- particle.initialPosition.y = particle.position.y;
2846
- }
2847
- particle.justWarped = true;
2848
- }
2849
- if (direction === OutModeDirection.bottom && nextBounds.top > canvasSize.height + particle.offset.y) {
2850
- if (!warp) {
2851
- particle.position.x = getRandom() * canvasSize.width;
2852
- particle.initialPosition.x = particle.position.x;
2853
- }
2854
- particle.position.y = newPos.top;
2855
- particle.initialPosition.y = particle.position.y;
2856
- particle.justWarped = true;
2857
- }
2858
- else if (direction === OutModeDirection.top && nextBounds.bottom < -particle.offset.y) {
2859
- if (!warp) {
2860
- particle.position.x = getRandom() * canvasSize.width;
2861
- particle.initialPosition.x = particle.position.x;
2862
- }
2863
- particle.position.y = newPos.bottom;
2864
- particle.initialPosition.y = particle.position.y;
2865
- particle.justWarped = true;
2866
- }
2867
- break;
2868
- }
2869
- }
2870
- break;
2842
+ if (particle.outType === ParticleOutType.outside) {
2843
+ this.#applyParticleModeOutside(particle);
2871
2844
  }
2872
- }
2845
+ else {
2846
+ this.#applyOutModeNormal(particle, container, direction);
2847
+ }
2848
+ }
2849
+ }
2850
+ #applyOutModeInside(particle, container) {
2851
+ const { x: vx, y: vy } = particle.velocity;
2852
+ updateVector.setTo(originPoint);
2853
+ updateVector.length = particle.moveCenter.radius;
2854
+ updateVector.angle = particle.velocity.angle + Math.PI;
2855
+ updateVector.addTo(particle.moveCenter);
2856
+ const { dx, dy } = getDistances(particle.position, updateVector);
2857
+ if ((vx <= minVelocity && dx >= minDistance) ||
2858
+ (vy <= minVelocity && dy >= minDistance) ||
2859
+ (vx >= minVelocity && dx <= minDistance) ||
2860
+ (vy >= minVelocity && dy <= minDistance)) {
2861
+ return;
2862
+ }
2863
+ particle.position.x = Math.floor(randomInRangeValue({
2864
+ min: 0,
2865
+ max: container.canvas.size.width,
2866
+ }));
2867
+ particle.position.y = Math.floor(randomInRangeValue({
2868
+ min: 0,
2869
+ max: container.canvas.size.height,
2870
+ }));
2871
+ const { dx: newDx, dy: newDy } = getDistances(particle.position, particle.moveCenter);
2872
+ particle.direction = Math.atan2(-newDy, -newDx);
2873
+ particle.velocity.angle = particle.direction;
2874
+ particle.justWarped = true;
2875
+ }
2876
+ #applyOutModeNormal(particle, container, direction) {
2877
+ const warp = particle.options.move.warp, canvasSize = container.canvas.size, sizeValue = particle.getRadius(), newPos = {
2878
+ bottom: canvasSize.height + sizeValue + particle.offset.y,
2879
+ left: -sizeValue - particle.offset.x,
2880
+ right: canvasSize.width + sizeValue + particle.offset.x,
2881
+ top: -sizeValue - particle.offset.y,
2882
+ }, nextBounds = calculateBounds(particle.position, sizeValue);
2883
+ if (direction === OutModeDirection.right && nextBounds.left > canvasSize.width + particle.offset.x) {
2884
+ particle.position.x = newPos.left;
2885
+ particle.initialPosition.x = particle.position.x;
2886
+ if (!warp) {
2887
+ particle.position.y = getRandom() * canvasSize.height;
2888
+ particle.initialPosition.y = particle.position.y;
2889
+ }
2890
+ particle.justWarped = true;
2891
+ }
2892
+ else if (direction === OutModeDirection.left && nextBounds.right < -particle.offset.x) {
2893
+ particle.position.x = newPos.right;
2894
+ particle.initialPosition.x = particle.position.x;
2895
+ if (!warp) {
2896
+ particle.position.y = getRandom() * canvasSize.height;
2897
+ particle.initialPosition.y = particle.position.y;
2898
+ }
2899
+ particle.justWarped = true;
2900
+ }
2901
+ if (direction === OutModeDirection.bottom && nextBounds.top > canvasSize.height + particle.offset.y) {
2902
+ if (!warp) {
2903
+ particle.position.x = getRandom() * canvasSize.width;
2904
+ particle.initialPosition.x = particle.position.x;
2905
+ }
2906
+ particle.position.y = newPos.top;
2907
+ particle.initialPosition.y = particle.position.y;
2908
+ particle.justWarped = true;
2909
+ }
2910
+ else if (direction === OutModeDirection.top && nextBounds.bottom < -particle.offset.y) {
2911
+ if (!warp) {
2912
+ particle.position.x = getRandom() * canvasSize.width;
2913
+ particle.initialPosition.x = particle.position.x;
2914
+ }
2915
+ particle.position.y = newPos.bottom;
2916
+ particle.initialPosition.y = particle.position.y;
2917
+ particle.justWarped = true;
2918
+ }
2919
+ }
2920
+ #applyParticleModeOutside(particle) {
2921
+ particle.position.x =
2922
+ Math.floor(randomInRangeValue({
2923
+ min: -particle.moveCenter.radius,
2924
+ max: particle.moveCenter.radius,
2925
+ })) + particle.moveCenter.x;
2926
+ particle.position.y =
2927
+ Math.floor(randomInRangeValue({
2928
+ min: -particle.moveCenter.radius,
2929
+ max: particle.moveCenter.radius,
2930
+ })) + particle.moveCenter.y;
2931
+ const { dx, dy } = getDistances(particle.position, particle.moveCenter);
2932
+ if (particle.moveCenter.radius) {
2933
+ particle.direction = Math.atan2(dy, dx);
2934
+ particle.velocity.angle = particle.direction;
2935
+ }
2936
+ particle.justWarped = true;
2873
2937
  }
2874
2938
  }
2875
2939
 
@@ -2918,7 +2982,7 @@
2918
2982
  }
2919
2983
 
2920
2984
  async function loadOutModesUpdater(engine) {
2921
- engine.checkVersion("4.4.0");
2985
+ engine.checkVersion("4.5.0");
2922
2986
  await engine.pluginManager.register(e => {
2923
2987
  e.pluginManager.addParticleUpdater("outModes", container => {
2924
2988
  return Promise.resolve(new OutOfCanvasUpdater(container));
@@ -2935,39 +2999,9 @@
2935
2999
  this.#pluginManager = pluginManager;
2936
3000
  }
2937
3001
  init(particle) {
2938
- 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;
2939
- if (fill) {
2940
- const fillColor = AnimatableColor.create(paintColor === undefined ? undefined : AnimatableColor.create(undefined, paintColor), fill.color);
2941
- particle.fillEnabled = fill.enable;
2942
- particle.fillOpacity = getRangeValue(fill.opacity);
2943
- particle.fillAnimation = fillColor.animation;
2944
- const fillHslColor = rangeColorToHsl(this.#pluginManager, fillColor);
2945
- if (fillHslColor) {
2946
- particle.fillColor = getHslAnimationFromHsl(fillHslColor, particle.fillAnimation, container.retina.reduceFactor);
2947
- }
2948
- }
2949
- else {
2950
- particle.fillEnabled = false;
2951
- particle.fillAnimation = undefined;
2952
- particle.fillColor = undefined;
2953
- particle.fillOpacity = defaultOpacity;
2954
- }
2955
- if (stroke) {
2956
- const strokeColor = AnimatableColor.create(paintColor === undefined ? undefined : AnimatableColor.create(undefined, paintColor), stroke.color);
2957
- particle.strokeWidth = getRangeValue(stroke.width) * container.retina.pixelRatio;
2958
- particle.strokeOpacity = getRangeValue(stroke.opacity ?? defaultOpacity);
2959
- particle.strokeAnimation = strokeColor.animation;
2960
- const strokeHslColor = rangeColorToHsl(this.#pluginManager, strokeColor) ?? particle.getFillColor();
2961
- if (strokeHslColor) {
2962
- particle.strokeColor = getHslAnimationFromHsl(strokeHslColor, particle.strokeAnimation, container.retina.reduceFactor);
2963
- }
2964
- }
2965
- else {
2966
- particle.strokeAnimation = undefined;
2967
- particle.strokeColor = undefined;
2968
- particle.strokeOpacity = defaultOpacity;
2969
- particle.strokeWidth = 0;
2970
- }
3002
+ const container = this.#container, options = particle.options, paint = itemFromSingleOrMultiple(options.paint, particle.id, options.reduceDuplicates);
3003
+ this.#initFill(paint, particle, container);
3004
+ this.#initStroke(paint, particle, container);
2971
3005
  }
2972
3006
  isEnabled(particle) {
2973
3007
  const { fillAnimation, fillColor, strokeAnimation, strokeColor } = particle, fillEnabled = !!fillAnimation &&
@@ -2986,10 +3020,48 @@
2986
3020
  updateColor(particle.fillColor, delta, this.#container.hdr);
2987
3021
  updateColor(particle.strokeColor, delta, this.#container.hdr);
2988
3022
  }
3023
+ #initFill(paint, particle, container) {
3024
+ const fill = paint?.fill, color = paint?.color, paintColor = color ?? undefined;
3025
+ if (!fill) {
3026
+ particle.fillEnabled = false;
3027
+ particle.fillAnimation = undefined;
3028
+ particle.fillColor = undefined;
3029
+ particle.fillOpacity = defaultOpacity;
3030
+ return;
3031
+ }
3032
+ const fillColor = AnimatableColor.create(paintColor === undefined ? undefined : AnimatableColor.create(undefined, paintColor), fill.color);
3033
+ particle.fillEnabled = fill.enable;
3034
+ particle.fillOpacity = getRangeValue(fill.opacity);
3035
+ particle.fillAnimation = fillColor.animation;
3036
+ const fillHslColor = rangeColorToHsl(this.#pluginManager, fillColor);
3037
+ if (!fillHslColor) {
3038
+ return;
3039
+ }
3040
+ particle.fillColor = getHslAnimationFromHsl(fillHslColor, particle.fillAnimation, container.retina.reduceFactor);
3041
+ }
3042
+ #initStroke(paint, particle, container) {
3043
+ const stroke = paint?.stroke, color = paint?.color, paintColor = color ?? undefined;
3044
+ if (!stroke) {
3045
+ particle.strokeAnimation = undefined;
3046
+ particle.strokeColor = undefined;
3047
+ particle.strokeOpacity = defaultOpacity;
3048
+ particle.strokeWidth = 0;
3049
+ return;
3050
+ }
3051
+ const strokeColor = AnimatableColor.create(paintColor === undefined ? undefined : AnimatableColor.create(undefined, paintColor), stroke.color);
3052
+ particle.strokeWidth = getRangeValue(stroke.width) * container.retina.pixelRatio;
3053
+ particle.strokeOpacity = getRangeValue(stroke.opacity ?? defaultOpacity);
3054
+ particle.strokeAnimation = strokeColor.animation;
3055
+ const strokeHslColor = rangeColorToHsl(this.#pluginManager, strokeColor) ?? particle.getFillColor();
3056
+ if (!strokeHslColor) {
3057
+ return;
3058
+ }
3059
+ particle.strokeColor = getHslAnimationFromHsl(strokeHslColor, particle.strokeAnimation, container.retina.reduceFactor);
3060
+ }
2989
3061
  }
2990
3062
 
2991
3063
  async function loadPaintUpdater(engine) {
2992
- engine.checkVersion("4.4.0");
3064
+ engine.checkVersion("4.5.0");
2993
3065
  await engine.pluginManager.register(e => {
2994
3066
  e.pluginManager.addParticleUpdater("paint", container => {
2995
3067
  return Promise.resolve(new PaintUpdater(e.pluginManager, container));
@@ -3031,7 +3103,7 @@
3031
3103
  if (!this.accepts(input)) {
3032
3104
  return;
3033
3105
  }
3034
- const result = rgbRegex.exec(input), radix = 10, minLength = 4, defaultAlpha = 1;
3106
+ const result = rgbRegex.exec(input), radix = 10, minLength = 4;
3035
3107
  return result
3036
3108
  ? {
3037
3109
  a: result.length > minLength ? parseAlpha(result[RgbIndexes.a]) : defaultAlpha,
@@ -3044,7 +3116,7 @@
3044
3116
  }
3045
3117
 
3046
3118
  async function loadRgbColorPlugin(engine) {
3047
- engine.checkVersion("4.4.0");
3119
+ engine.checkVersion("4.5.0");
3048
3120
  await engine.pluginManager.register(e => {
3049
3121
  e.pluginManager.addColorManager("rgb", new RgbColorManager());
3050
3122
  });
@@ -3129,7 +3201,7 @@
3129
3201
  }
3130
3202
 
3131
3203
  async function loadSizeUpdater(engine) {
3132
- engine.checkVersion("4.4.0");
3204
+ engine.checkVersion("4.5.0");
3133
3205
  await engine.pluginManager.register(e => {
3134
3206
  e.pluginManager.addParticleUpdater("size", container => {
3135
3207
  return Promise.resolve(new SizeUpdater(container));
@@ -3138,7 +3210,7 @@
3138
3210
  }
3139
3211
 
3140
3212
  async function loadBasic(engine) {
3141
- engine.checkVersion("4.4.0");
3213
+ engine.checkVersion("4.5.0");
3142
3214
  await engine.pluginManager.register(async (e) => {
3143
3215
  await Promise.all([
3144
3216
  loadBlendPlugin(e),
@@ -3155,6 +3227,16 @@
3155
3227
  });
3156
3228
  }
3157
3229
 
3230
+ const ErrorCodes = {
3231
+ interactivityPluginNotLoaded: "TSP-3201",
3232
+ interactivityClickHandlerNotSet: "TSP-3202",
3233
+ };
3234
+
3235
+ const ErrorMessages = {
3236
+ [ErrorCodes.interactivityPluginNotLoaded]: "tsParticles Interactivity Plugin is not loaded",
3237
+ [ErrorCodes.interactivityClickHandlerNotSet]: "Click handlers can only be set after calling tsParticles.load()",
3238
+ };
3239
+
3158
3240
  class ClickEvent {
3159
3241
  enable = false;
3160
3242
  mode = [];
@@ -3231,9 +3313,7 @@
3231
3313
 
3232
3314
  class Modes {
3233
3315
  #container;
3234
- #pluginManager;
3235
- constructor(pluginManager, container) {
3236
- this.#pluginManager = pluginManager;
3316
+ constructor(container) {
3237
3317
  this.#container = container;
3238
3318
  }
3239
3319
  load(data) {
@@ -3243,10 +3323,7 @@
3243
3323
  if (!this.#container) {
3244
3324
  return;
3245
3325
  }
3246
- const interactors = this.#pluginManager.interactors?.get(this.#container);
3247
- if (!interactors) {
3248
- return;
3249
- }
3326
+ const interactors = this.#container.interactionManager?.interactors ?? [];
3250
3327
  for (const interactor of interactors) {
3251
3328
  if (!interactor.loadModeOptions) {
3252
3329
  continue;
@@ -3260,8 +3337,8 @@
3260
3337
  detectsOn = InteractivityDetect.window;
3261
3338
  events = new Events();
3262
3339
  modes;
3263
- constructor(pluginManager, container) {
3264
- this.modes = new Modes(pluginManager, container);
3340
+ constructor(container) {
3341
+ this.modes = new Modes(container);
3265
3342
  }
3266
3343
  load(data) {
3267
3344
  if (isNull(data)) {
@@ -3292,10 +3369,10 @@
3292
3369
  }
3293
3370
  let interactivityOptions = options.interactivity;
3294
3371
  if (!interactivityOptions?.load) {
3295
- options.interactivity = interactivityOptions = new Interactivity(this.#pluginManager, container);
3372
+ options.interactivity = interactivityOptions = new Interactivity(container);
3296
3373
  }
3297
3374
  interactivityOptions.load(source?.interactivity);
3298
- const interactors = this.#pluginManager.interactors?.get(container);
3375
+ const interactors = container.interactionManager?.interactors;
3299
3376
  if (!interactors) {
3300
3377
  return;
3301
3378
  }
@@ -3309,7 +3386,7 @@
3309
3386
  if (source?.interactivity) {
3310
3387
  options.interactivity = deepExtend({}, source.interactivity);
3311
3388
  }
3312
- const interactors = this.#pluginManager.interactors?.get(container);
3389
+ const interactors = container.interactionManager?.interactors;
3313
3390
  if (!interactors) {
3314
3391
  return;
3315
3392
  }
@@ -3339,25 +3416,25 @@
3339
3416
  const clickEvent = "click", mouseDownEvent = "pointerdown", mouseUpEvent = "pointerup", mouseLeaveEvent = "pointerleave", mouseMoveEvent = "pointermove", touchStartEvent = "touchstart", touchEndEvent = "touchend", touchMoveEvent = "touchmove", touchCancelEvent = "touchcancel";
3340
3417
 
3341
3418
  async function loadInteractivityPlugin(engine) {
3342
- engine.checkVersion("4.4.0");
3419
+ engine.checkVersion("4.5.0");
3420
+ if (typeof process !== "undefined" && process.env.NODE_ENV !== "production") {
3421
+ addErrorMessages(ErrorMessages);
3422
+ }
3343
3423
  await engine.pluginManager.register(e => {
3344
3424
  const interactivityEngine = e, interactivityPluginManager = interactivityEngine.pluginManager;
3345
3425
  interactivityPluginManager.addPlugin(new InteractivityPlugin(interactivityPluginManager));
3346
3426
  interactivityPluginManager.initializers.interactors ??= new Map();
3347
- interactivityPluginManager.interactors ??= new Map();
3348
3427
  interactivityPluginManager.addInteractor = (name, interactorInitializer) => {
3428
+ if (interactivityPluginManager.initialized) {
3429
+ return;
3430
+ }
3349
3431
  interactivityPluginManager.initializers.interactors ??= new Map();
3350
- interactivityPluginManager.initializers.interactors.set(name, interactorInitializer);
3351
- };
3352
- interactivityPluginManager.getInteractors = async (container, force = false) => {
3353
- interactivityPluginManager.interactors ??= new Map();
3354
- interactivityPluginManager.initializers.interactors ??= new Map();
3355
- return getItemsFromInitializer(container, interactivityPluginManager.interactors, interactivityPluginManager.initializers.interactors, force);
3432
+ interactivityPluginManager.initializers.interactors.set(name, interactorInitializer);
3356
3433
  };
3357
3434
  interactivityPluginManager.setOnClickHandler = (callback) => {
3358
3435
  const { items } = interactivityEngine;
3359
3436
  if (!items.length) {
3360
- throw new Error("Click handlers can only be set after calling tsParticles.load()");
3437
+ throw new Error(getErrorMessage(ErrorCodes.interactivityClickHandlerNotSet));
3361
3438
  }
3362
3439
  items.forEach(item => {
3363
3440
  const interactivityContainer = item;
@@ -3368,7 +3445,7 @@
3368
3445
  }
3369
3446
  function ensureInteractivityPluginLoaded(e) {
3370
3447
  if (!e.pluginManager.addInteractor) {
3371
- throw new Error("tsParticles Interactivity Plugin is not loaded");
3448
+ throw new Error(getErrorMessage(ErrorCodes.interactivityPluginNotLoaded));
3372
3449
  }
3373
3450
  }
3374
3451
 
@@ -3536,7 +3613,7 @@
3536
3613
  }
3537
3614
 
3538
3615
  async function loadExternalTrailInteraction(engine) {
3539
- engine.checkVersion("4.4.0");
3616
+ engine.checkVersion("4.5.0");
3540
3617
  await engine.pluginManager.register((e) => {
3541
3618
  ensureInteractivityPluginLoaded(e);
3542
3619
  e.pluginManager.addInteractor?.("externalTrail", container => {
@@ -3682,7 +3759,7 @@
3682
3759
  }
3683
3760
 
3684
3761
  async function loadLifeUpdater(engine) {
3685
- engine.checkVersion("4.4.0");
3762
+ engine.checkVersion("4.5.0");
3686
3763
  await engine.pluginManager.register(e => {
3687
3764
  e.pluginManager.addParticleUpdater("life", container => {
3688
3765
  return Promise.resolve(new LifeUpdater(container));
@@ -3836,21 +3913,28 @@
3836
3913
  });
3837
3914
  }
3838
3915
  clear() {
3916
+ const visited = new Set();
3839
3917
  for (const plugin of this.#canvasClearPlugins) {
3918
+ visited.add(plugin);
3840
3919
  if (plugin.canvasClear?.() ?? false) {
3841
- return;
3920
+ return plugin;
3842
3921
  }
3843
3922
  }
3844
3923
  for (const layer of Object.values(DrawLayer)) {
3845
3924
  if (typeof layer === "number") {
3846
3925
  for (const plugin of this.#getLayerPlugins(layer)) {
3926
+ if (visited.has(plugin)) {
3927
+ continue;
3928
+ }
3929
+ visited.add(plugin);
3847
3930
  if (plugin.canvasClear?.() ?? false) {
3848
- return;
3931
+ return plugin;
3849
3932
  }
3850
3933
  }
3851
3934
  }
3852
3935
  }
3853
3936
  this.canvasClear();
3937
+ return undefined;
3854
3938
  }
3855
3939
  destroy() {
3856
3940
  this.stop();
@@ -3928,8 +4012,7 @@
3928
4012
  });
3929
4013
  }
3930
4014
  drawParticles(delta) {
3931
- const { particles, actualOptions } = this.#container;
3932
- this.clear();
4015
+ const { particles, actualOptions } = this.#container, clearedPlugin = this.clear();
3933
4016
  particles.update(delta);
3934
4017
  this.draw(ctx => {
3935
4018
  const width = this.#canvasManager.size.width, height = this.#canvasManager.size.height;
@@ -3951,7 +4034,9 @@
3951
4034
  }
3952
4035
  }
3953
4036
  for (const plugin of this.#getLayerPlugins(DrawLayer.BackgroundMask)) {
3954
- plugin.canvasPaint?.();
4037
+ if (plugin !== clearedPlugin) {
4038
+ plugin.canvasPaint?.();
4039
+ }
3955
4040
  }
3956
4041
  for (const plugin of this.#getLayerPlugins(DrawLayer.CanvasSetup)) {
3957
4042
  plugin.drawSettingsSetup?.(ctx, delta);
@@ -3983,35 +4068,7 @@
3983
4068
  this.#layers[layer] = [];
3984
4069
  }
3985
4070
  }
3986
- for (const plugin of this.#container.plugins) {
3987
- if (plugin.particleFillColor ?? plugin.particleStrokeColor) {
3988
- this.#colorPlugins.push(plugin);
3989
- }
3990
- if (plugin.drawParticle) {
3991
- this.#drawParticlePlugins.push(plugin);
3992
- }
3993
- if (plugin.drawParticleSetup) {
3994
- this.#drawParticlesSetupPlugins.push(plugin);
3995
- }
3996
- if (plugin.drawParticleCleanup) {
3997
- this.#drawParticlesCleanupPlugins.push(plugin);
3998
- }
3999
- if (plugin.canvasClear) {
4000
- this.#canvasClearPlugins.push(plugin);
4001
- }
4002
- if (plugin.canvasPaint) {
4003
- this.#getLayerPlugins(DrawLayer.BackgroundMask).push(plugin);
4004
- }
4005
- if (plugin.drawSettingsSetup) {
4006
- this.#getLayerPlugins(DrawLayer.CanvasSetup).push(plugin);
4007
- }
4008
- if (plugin.draw) {
4009
- this.#getLayerPlugins(DrawLayer.PluginContent).push(plugin);
4010
- }
4011
- if (plugin.clearDraw ?? plugin.drawSettingsCleanup) {
4012
- this.#getLayerPlugins(DrawLayer.CanvasCleanup).push(plugin);
4013
- }
4014
- }
4071
+ this.#initPluginsArray();
4015
4072
  }
4016
4073
  initUpdaters() {
4017
4074
  this.#preDrawUpdaters = [];
@@ -4220,6 +4277,45 @@
4220
4277
  this.#reusablePluginColors[sColorIndex] = sColor;
4221
4278
  return this.#reusablePluginColors;
4222
4279
  }
4280
+ #initLayerPlugin(plugin) {
4281
+ const layerMap = [
4282
+ [DrawLayer.BackgroundMask, !!plugin.canvasPaint],
4283
+ [DrawLayer.CanvasSetup, !!plugin.drawSettingsSetup],
4284
+ [DrawLayer.PluginContent, !!plugin.draw],
4285
+ [DrawLayer.CanvasCleanup, !!(plugin.clearDraw ?? plugin.drawSettingsCleanup)],
4286
+ ];
4287
+ for (const [layer, active] of layerMap) {
4288
+ if (active) {
4289
+ this.#layers[layer].push(plugin);
4290
+ }
4291
+ }
4292
+ }
4293
+ #initPluginsArray() {
4294
+ for (const plugin of this.#container.plugins) {
4295
+ if (plugin.particleFillColor ?? plugin.particleStrokeColor) {
4296
+ this.#colorPlugins.push(plugin);
4297
+ }
4298
+ if (plugin.drawParticle) {
4299
+ this.#drawParticlePlugins.push(plugin);
4300
+ }
4301
+ if (plugin.drawParticleSetup) {
4302
+ this.#drawParticlesSetupPlugins.push(plugin);
4303
+ }
4304
+ if (plugin.drawParticleCleanup) {
4305
+ this.#drawParticlesCleanupPlugins.push(plugin);
4306
+ }
4307
+ if (plugin.canvasClear) {
4308
+ this.#canvasClearPlugins.push(plugin);
4309
+ }
4310
+ this.#initLayerPlugin(plugin);
4311
+ }
4312
+ }
4313
+ #isSupportedElement(element) {
4314
+ return ((typeof HTMLCanvasElement !== "undefined" && element instanceof HTMLCanvasElement) ||
4315
+ (typeof OffscreenCanvas !== "undefined" && element instanceof OffscreenCanvas) ||
4316
+ (typeof HTMLVideoElement !== "undefined" && element instanceof HTMLVideoElement) ||
4317
+ (typeof HTMLImageElement !== "undefined" && element instanceof HTMLImageElement));
4318
+ }
4223
4319
  #resolveBackgroundElement() {
4224
4320
  const background = this.#container.actualOptions.background;
4225
4321
  this.#backgroundElement = null;
@@ -4229,9 +4325,7 @@
4229
4325
  if (typeof background.element === "string") {
4230
4326
  if (typeof document !== "undefined") {
4231
4327
  const node = document.querySelector(background.element);
4232
- if ((typeof HTMLCanvasElement !== "undefined" && node instanceof HTMLCanvasElement) ||
4233
- (typeof HTMLVideoElement !== "undefined" && node instanceof HTMLVideoElement) ||
4234
- (typeof HTMLImageElement !== "undefined" && node instanceof HTMLImageElement)) {
4328
+ if (node && this.#isSupportedElement(node)) {
4235
4329
  this.#backgroundElement = node;
4236
4330
  }
4237
4331
  else if (node) {
@@ -4242,10 +4336,7 @@
4242
4336
  }
4243
4337
  }
4244
4338
  }
4245
- else if ((typeof HTMLCanvasElement !== "undefined" && background.element instanceof HTMLCanvasElement) ||
4246
- (typeof OffscreenCanvas !== "undefined" && background.element instanceof OffscreenCanvas) ||
4247
- (typeof HTMLVideoElement !== "undefined" && background.element instanceof HTMLVideoElement) ||
4248
- (typeof HTMLImageElement !== "undefined" && background.element instanceof HTMLImageElement)) {
4339
+ else if (this.#isSupportedElement(background.element)) {
4249
4340
  this.#backgroundElement = background.element;
4250
4341
  }
4251
4342
  }
@@ -4263,7 +4354,7 @@
4263
4354
  return transferredCanvas;
4264
4355
  }
4265
4356
  if (typeof canvas.transferControlToOffscreen !== "function") {
4266
- throw new TypeError("OffscreenCanvas is required but not supported by this browser");
4357
+ throw new TypeError(getErrorMessage(ErrorCodes$2.offscreenCanvasUnsupported));
4267
4358
  }
4268
4359
  try {
4269
4360
  const offscreenCanvas = canvas.transferControlToOffscreen();
@@ -4271,10 +4362,16 @@
4271
4362
  return offscreenCanvas;
4272
4363
  }
4273
4364
  catch {
4274
- throw new TypeError("OffscreenCanvas transfer failed");
4365
+ throw new TypeError(getErrorMessage(ErrorCodes$2.offscreenCanvasTransferFailed));
4275
4366
  }
4276
4367
  }, isHtmlCanvasElement = (canvas) => {
4277
4368
  return typeof HTMLCanvasElement !== "undefined" && canvas instanceof HTMLCanvasElement;
4369
+ }, getEffectiveColorSpace = (context) => {
4370
+ if (!context) {
4371
+ return undefined;
4372
+ }
4373
+ const colorInfo = context;
4374
+ return colorInfo.getContextAttributes?.().colorSpace ?? undefined;
4278
4375
  };
4279
4376
  function setStyle(canvas, style, important = false) {
4280
4377
  if (!style) {
@@ -4399,7 +4496,7 @@
4399
4496
  const elementStyle = element.style, color = rangeColorToRgb(this.#pluginManager, background.color);
4400
4497
  if (color) {
4401
4498
  const hdrOptions = container.actualOptions.hdr;
4402
- elementStyle.backgroundColor = getStyleFromRgb(color, container.hdr, background.opacity, hdrOptions.peakNits, hdrOptions.mode);
4499
+ elementStyle.backgroundColor = getStyleFromRgb(color, container.hdr, background.opacity, hdrOptions.peakNits, toEnumValue(HdrMode, hdrOptions.mode, HdrMode.standard));
4403
4500
  }
4404
4501
  else {
4405
4502
  elementStyle.backgroundColor = "";
@@ -4519,11 +4616,11 @@
4519
4616
  const container = this.#container, canSupportHdr = container.actualOptions.hdr.enable &&
4520
4617
  safeMatchMedia("(color-gamut: p3)")?.matches &&
4521
4618
  safeMatchMedia("(dynamic-range: high)")?.matches;
4522
- container.hdr = canSupportHdr ?? false;
4523
- container.hdrMode = container.actualOptions.hdr.mode;
4619
+ container.hdrMode = toEnumValue(HdrMode, container.actualOptions.hdr.mode, HdrMode.standard);
4524
4620
  container.peakNits = container.actualOptions.hdr.peakNits;
4525
4621
  const renderCanvas = this.renderCanvas;
4526
4622
  if (!renderCanvas) {
4623
+ container.hdr = canSupportHdr ?? false;
4527
4624
  return;
4528
4625
  }
4529
4626
  this.render.setContextSettings({
@@ -4542,7 +4639,6 @@
4542
4639
  context = null;
4543
4640
  }
4544
4641
  if (canSupportHdr && !context) {
4545
- container.hdr = false;
4546
4642
  const sdrSettings = {
4547
4643
  alpha: true,
4548
4644
  desynchronized: true,
@@ -4558,11 +4654,16 @@
4558
4654
  }
4559
4655
  }
4560
4656
  this.render.setContext(context);
4657
+ if (context) {
4658
+ const effectiveColorSpace = getEffectiveColorSpace(context);
4659
+ if (effectiveColorSpace !== undefined) {
4660
+ container.hdr = effectiveColorSpace === "display-p3";
4661
+ }
4662
+ }
4561
4663
  }
4562
4664
  #initHdrListeners() {
4563
4665
  this.#removeHdrListeners();
4564
4666
  const p3Query = safeMatchMedia("(color-gamut: p3)"), hdrQuery = safeMatchMedia("(dynamic-range: high)"), handleChange = () => {
4565
- this.#recreateRenderCanvas();
4566
4667
  this.#initContext();
4567
4668
  this.initBackground();
4568
4669
  }, listeners = [];
@@ -4598,16 +4699,6 @@
4598
4699
  element.style.setProperty(key, value, "important");
4599
4700
  }
4600
4701
  }
4601
- #recreateRenderCanvas() {
4602
- const renderCanvas = this.renderCanvas;
4603
- if (!renderCanvas) {
4604
- return;
4605
- }
4606
- if (this.domElement) {
4607
- return;
4608
- }
4609
- this.renderCanvas = new OffscreenCanvas(renderCanvas.width, renderCanvas.height);
4610
- }
4611
4702
  #removeHdrListeners() {
4612
4703
  if (!this.#hdrMediaListeners) {
4613
4704
  return;
@@ -4706,8 +4797,7 @@
4706
4797
  this.#resizeTimeout = undefined;
4707
4798
  }
4708
4799
  const handleResize = async () => {
4709
- const canvas = this.#container.canvas;
4710
- await canvas.windowResize();
4800
+ await this.#container.canvas.windowResize();
4711
4801
  };
4712
4802
  this.#resizeTimeout = setTimeout(() => void handleResize(), this.#container.actualOptions.resize.delay * millisecondsToSeconds);
4713
4803
  }
@@ -4735,8 +4825,8 @@
4735
4825
  }
4736
4826
  else if (!this.#resizeObserver && add && canvasEl) {
4737
4827
  this.#resizeObserver = new ResizeObserver((entries) => {
4738
- const entry = entries.find(e => e.target === canvasEl);
4739
- if (!entry) {
4828
+ const res = entries.some(e => e.target === canvasEl);
4829
+ if (!res) {
4740
4830
  return;
4741
4831
  }
4742
4832
  this.#handleWindowResize();
@@ -5000,10 +5090,10 @@
5000
5090
  return this.#modifiers.find(m => m.id === id);
5001
5091
  }
5002
5092
  getOpacity() {
5003
- 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;
5004
- this.#cachedOpacityData.fillOpacity = fillOpacity;
5093
+ 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;
5094
+ this.#cachedOpacityData.fillOpacity = this.fillOpacity ?? defaultOpacity$1;
5005
5095
  this.#cachedOpacityData.opacity = opacity * zOpacityFactor;
5006
- this.#cachedOpacityData.strokeOpacity = strokeOpacity;
5096
+ this.#cachedOpacityData.strokeOpacity = this.strokeOpacity ?? defaultOpacity$1;
5007
5097
  return this.#cachedOpacityData;
5008
5098
  }
5009
5099
  getPosition() {
@@ -5250,7 +5340,7 @@
5250
5340
  #initPosition(position) {
5251
5341
  const container = this.#container, zIndexValue = Math.floor(getRangeValue(this.options.zIndex.value)), initialPosition = this.#calcPosition(position, clamp(zIndexValue, minZ, container.zLayers));
5252
5342
  if (!initialPosition) {
5253
- throw new Error("a valid position cannot be found for particle");
5343
+ throw new Error(getErrorMessage(ErrorCodes$2.particlePositionNotFound));
5254
5344
  }
5255
5345
  this.position = initialPosition;
5256
5346
  this.initialPosition = this.position.copy();
@@ -5299,6 +5389,12 @@
5299
5389
  this.#circlePoolIdx = 0;
5300
5390
  this.#rectanglePoolIdx = 0;
5301
5391
  }
5392
+ get cellSize() {
5393
+ return this.#cellSize;
5394
+ }
5395
+ set cellSize(value) {
5396
+ this.#pendingCellSize = value;
5397
+ }
5302
5398
  clear() {
5303
5399
  this.#cells.clear();
5304
5400
  const pendingCellSize = this.#pendingCellSize;
@@ -5322,18 +5418,7 @@
5322
5418
  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);
5323
5419
  for (let cx = minCellX; cx <= maxCellX; cx++) {
5324
5420
  for (let cy = minCellY; cy <= maxCellY; cy++) {
5325
- const key = `${cx}_${cy}`, cellParticles = this.#cells.get(key);
5326
- if (!cellParticles) {
5327
- continue;
5328
- }
5329
- for (const p of cellParticles) {
5330
- if (check && !check(p)) {
5331
- continue;
5332
- }
5333
- if (range.contains(p.getPosition())) {
5334
- out.push(p);
5335
- }
5336
- }
5421
+ this.#queryCell(cx, cy, range, check, out);
5337
5422
  }
5338
5423
  }
5339
5424
  return out;
@@ -5348,14 +5433,23 @@
5348
5433
  this.#releaseShapes();
5349
5434
  return result;
5350
5435
  }
5351
- setCellSize(cellSize) {
5352
- this.#pendingCellSize = cellSize;
5353
- }
5354
5436
  #acquireCircle(x, y, r) {
5355
- return (this.#circlePool[this.#circlePoolIdx++] ??= new Circle(x, y, r)).reset(x, y, r);
5437
+ const idx = this.#circlePoolIdx++;
5438
+ let circle = this.#circlePool[idx];
5439
+ if (!circle) {
5440
+ circle = new Circle(x, y, r);
5441
+ this.#circlePool[idx] = circle;
5442
+ }
5443
+ return circle.reset(x, y, r);
5356
5444
  }
5357
5445
  #acquireRectangle(x, y, w, h) {
5358
- return (this.#rectanglePool[this.#rectanglePoolIdx++] ??= new Rectangle(x, y, w, h)).reset(x, y, w, h);
5446
+ const idx = this.#rectanglePoolIdx++;
5447
+ let rectangle = this.#rectanglePool[idx];
5448
+ if (!rectangle) {
5449
+ rectangle = new Rectangle(x, y, w, h);
5450
+ this.#rectanglePool[idx] = rectangle;
5451
+ }
5452
+ return rectangle.reset(x, y, w, h);
5359
5453
  }
5360
5454
  #cellKeyFromCoords(x, y) {
5361
5455
  const cellX = Math.floor(x / this.#cellSize), cellY = Math.floor(y / this.#cellSize);
@@ -5382,6 +5476,20 @@
5382
5476
  }
5383
5477
  return null;
5384
5478
  }
5479
+ #queryCell(cx, cy, range, check, out) {
5480
+ const cellParticles = this.#cells.get(`${cx}_${cy}`);
5481
+ if (!cellParticles) {
5482
+ return;
5483
+ }
5484
+ for (const p of cellParticles) {
5485
+ if (check && !check(p)) {
5486
+ continue;
5487
+ }
5488
+ if (range.contains(p.getPosition())) {
5489
+ out.push(p);
5490
+ }
5491
+ }
5492
+ }
5385
5493
  #releaseShapes() {
5386
5494
  this.#circlePoolIdx = 0;
5387
5495
  this.#rectanglePoolIdx = 0;
@@ -5390,9 +5498,9 @@
5390
5498
 
5391
5499
  class ParticlesManager {
5392
5500
  checkParticlePositionPlugins;
5393
- grid;
5394
5501
  #array;
5395
5502
  #container;
5503
+ #grid;
5396
5504
  #groupLimits;
5397
5505
  #limit;
5398
5506
  #nextId;
@@ -5416,7 +5524,7 @@
5416
5524
  this.#groupLimits = new Map();
5417
5525
  this.#particleBuckets = new Map();
5418
5526
  this.#zBuckets = this.#createBuckets(this.#container.zLayers);
5419
- this.grid = new SpatialHashGrid(spatialHashGridCellSize);
5527
+ this.#grid = new SpatialHashGrid(spatialHashGridCellSize);
5420
5528
  this.checkParticlePositionPlugins = [];
5421
5529
  this.#particleResetPlugins = [];
5422
5530
  this.#particleUpdatePlugins = [];
@@ -5427,23 +5535,12 @@
5427
5535
  get count() {
5428
5536
  return this.#array.length;
5429
5537
  }
5538
+ get grid() {
5539
+ return this.#grid;
5540
+ }
5430
5541
  addParticle(position, overrideOptions, group, initializer) {
5431
- const limitMode = this.#container.actualOptions.particles.number.limit.mode, limit = group === undefined ? this.#limit : (this.#groupLimits.get(group) ?? this.#limit), currentCount = this.count;
5432
- if (limit > minLimit) {
5433
- switch (limitMode) {
5434
- case LimitMode.delete: {
5435
- const countToRemove = currentCount + countOffset - limit;
5436
- if (countToRemove > minCount) {
5437
- this.removeQuantity(countToRemove);
5438
- }
5439
- break;
5440
- }
5441
- case LimitMode.wait:
5442
- if (currentCount >= limit) {
5443
- return;
5444
- }
5445
- break;
5446
- }
5542
+ if (this.#checkAndApplyLimits(group, this.count)) {
5543
+ return;
5447
5544
  }
5448
5545
  try {
5449
5546
  const particle = this.#pool.pop() ?? new Particle(this.#pluginManager, this.#container);
@@ -5507,7 +5604,7 @@
5507
5604
  return this.#array[index];
5508
5605
  }
5509
5606
  async init() {
5510
- const container = this.#container, options = container.actualOptions;
5607
+ const container = this.#container;
5511
5608
  this.checkParticlePositionPlugins = [];
5512
5609
  this.#updatePlugins = [];
5513
5610
  this.#particleUpdatePlugins = [];
@@ -5516,59 +5613,16 @@
5516
5613
  this.#postParticleUpdatePlugins = [];
5517
5614
  this.#particleBuckets.clear();
5518
5615
  this.#resetBuckets(container.zLayers);
5519
- this.grid = new SpatialHashGrid(spatialHashGridCellSize * container.retina.pixelRatio);
5520
- for (const plugin of container.plugins) {
5521
- if (plugin.redrawInit) {
5522
- await plugin.redrawInit();
5523
- }
5524
- if (plugin.checkParticlePosition) {
5525
- this.checkParticlePositionPlugins.push(plugin);
5526
- }
5527
- if (plugin.update) {
5528
- this.#updatePlugins.push(plugin);
5529
- }
5530
- if (plugin.particleUpdate) {
5531
- this.#particleUpdatePlugins.push(plugin);
5532
- }
5533
- if (plugin.postUpdate) {
5534
- this.#postUpdatePlugins.push(plugin);
5535
- }
5536
- if (plugin.particleReset) {
5537
- this.#particleResetPlugins.push(plugin);
5538
- }
5539
- if (plugin.postParticleUpdate) {
5540
- this.#postParticleUpdatePlugins.push(plugin);
5541
- }
5542
- }
5543
- await this.#container.initDrawersAndUpdaters();
5544
- for (const drawer of this.#container.effectDrawers.values()) {
5545
- await drawer.init?.(container);
5546
- }
5547
- for (const drawer of this.#container.shapeDrawers.values()) {
5548
- await drawer.init?.(container);
5549
- }
5550
- let handled = false;
5551
- for (const plugin of container.plugins) {
5552
- handled = plugin.particlesInitialization?.() ?? handled;
5553
- if (handled) {
5554
- break;
5555
- }
5556
- }
5557
- if (!handled) {
5558
- const particlesOptions = options.particles, groups = particlesOptions.groups;
5559
- for (const group in groups) {
5560
- const groupOptions = groups[group];
5561
- if (!groupOptions) {
5562
- continue;
5563
- }
5564
- for (let i = this.count, j = 0; j < groupOptions.number.value && i < particlesOptions.number.value; i++, j++) {
5565
- this.addParticle(undefined, groupOptions, group);
5566
- }
5567
- }
5568
- for (let i = this.count; i < particlesOptions.number.value; i++) {
5569
- this.addParticle();
5616
+ this.#grid = new SpatialHashGrid(spatialHashGridCellSize * container.retina.pixelRatio);
5617
+ this.#applyLimits(container.actualOptions.particles);
5618
+ const particlesOptions = container.actualOptions.particles, groups = particlesOptions.groups;
5619
+ for (const group in groups) {
5620
+ const groupData = groups[group];
5621
+ if (groupData) {
5622
+ this.#applyLimits(loadParticlesOptions(this.#pluginManager, this.#container, groupData), group, groupData);
5570
5623
  }
5571
5624
  }
5625
+ await this.#initPlugins();
5572
5626
  }
5573
5627
  push(nb, position, overrideOptions, group) {
5574
5628
  for (let i = 0; i < nb; i++) {
@@ -5583,13 +5637,13 @@
5583
5637
  remove(particle, group, override) {
5584
5638
  this.removeAt(this.#array.indexOf(particle), undefined, group, override);
5585
5639
  }
5586
- removeAt(index, quantity = defaultRemoveQuantity, group, override) {
5640
+ removeAt(index, quantity = defaultRemoveQuantity, group, override, matchGroup = true) {
5587
5641
  if (index < minIndex || index > this.count) {
5588
5642
  return;
5589
5643
  }
5590
5644
  let deleted = 0;
5591
5645
  for (let i = index; deleted < quantity && i < this.count; i++) {
5592
- if (this.#removeParticle(i, group, override)) {
5646
+ if (this.#removeParticle(i, group, override, matchGroup)) {
5593
5647
  i--;
5594
5648
  deleted++;
5595
5649
  }
@@ -5620,7 +5674,7 @@
5620
5674
  this.#resizeFactor = factor;
5621
5675
  }
5622
5676
  update(delta) {
5623
- this.grid.clear();
5677
+ this.#grid.clear();
5624
5678
  for (const plugin of this.#updatePlugins) {
5625
5679
  plugin.update?.(delta);
5626
5680
  }
@@ -5631,7 +5685,7 @@
5631
5685
  this.#updateParticlesPhase2(delta, particlesToDelete);
5632
5686
  if (particlesToDelete.size) {
5633
5687
  for (const particle of particlesToDelete) {
5634
- this.remove(particle);
5688
+ this.remove(particle, particle.group);
5635
5689
  }
5636
5690
  }
5637
5691
  this.#resizeFactor = undefined;
@@ -5642,12 +5696,7 @@
5642
5696
  #applyDensity(options, pluginsCount, group, groupOptions) {
5643
5697
  const numberOptions = options.number;
5644
5698
  if (!numberOptions.density.enable) {
5645
- if (group === undefined) {
5646
- this.#limit = numberOptions.limit.value;
5647
- }
5648
- else if (groupOptions?.number.limit.value ?? numberOptions.limit.value) {
5649
- this.#groupLimits.set(group, groupOptions?.number.limit.value ?? numberOptions.limit.value);
5650
- }
5699
+ this.#applyLimits(options, group, groupOptions);
5651
5700
  return;
5652
5701
  }
5653
5702
  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);
@@ -5655,7 +5704,10 @@
5655
5704
  this.#limit = numberOptions.limit.value * densityFactor;
5656
5705
  }
5657
5706
  else {
5658
- this.#groupLimits.set(group, numberOptions.limit.value * densityFactor);
5707
+ this.#groupLimits.set(group, {
5708
+ limit: numberOptions.limit.value * densityFactor,
5709
+ mode: toEnumValue(LimitMode, numberOptions.limit.mode, LimitMode.delete),
5710
+ });
5659
5711
  }
5660
5712
  if (particlesCount < particlesNumber) {
5661
5713
  this.push(Math.abs(particlesNumber - particlesCount), undefined, options, group);
@@ -5664,6 +5716,55 @@
5664
5716
  this.removeQuantity(particlesCount - particlesNumber, group);
5665
5717
  }
5666
5718
  }
5719
+ #applyLimits(options, group, groupOptions) {
5720
+ if (group === undefined) {
5721
+ this.#limit = options.number.limit.value;
5722
+ const groups = this.#container.actualOptions.particles.groups;
5723
+ for (const existingGroup of this.#groupLimits.keys()) {
5724
+ if (!(existingGroup in groups)) {
5725
+ this.#groupLimits.delete(existingGroup);
5726
+ }
5727
+ }
5728
+ }
5729
+ else {
5730
+ const limitValue = groupOptions?.number?.limit?.value ?? options.number.limit.value;
5731
+ if (limitValue > minLimit) {
5732
+ this.#groupLimits.set(group, {
5733
+ limit: limitValue,
5734
+ mode: toEnumValue(LimitMode, groupOptions?.number?.limit?.mode ?? options.number.limit.mode, LimitMode.delete),
5735
+ });
5736
+ }
5737
+ else {
5738
+ this.#groupLimits.delete(group);
5739
+ }
5740
+ }
5741
+ }
5742
+ #checkAndApplyLimits(group, currentCount) {
5743
+ const globalLimit = this.#limit, globalMode = this.#container.actualOptions.particles.number.limit.mode;
5744
+ if (globalLimit > minLimit && globalMode === LimitMode.wait && currentCount >= globalLimit) {
5745
+ return true;
5746
+ }
5747
+ const groupLimitEntry = group === undefined ? undefined : this.#groupLimits.get(group);
5748
+ if (groupLimitEntry && groupLimitEntry.limit > minLimit && groupLimitEntry.mode === LimitMode.wait) {
5749
+ const groupCount = this.filter(t => t.group === group).length;
5750
+ if (groupCount >= groupLimitEntry.limit) {
5751
+ return true;
5752
+ }
5753
+ }
5754
+ if (groupLimitEntry && groupLimitEntry.limit > minLimit && groupLimitEntry.mode === LimitMode.delete) {
5755
+ const groupCountToRemove = this.filter(t => t.group === group).length + countOffset - groupLimitEntry.limit;
5756
+ if (groupCountToRemove > minCount) {
5757
+ this.removeQuantity(groupCountToRemove, group);
5758
+ }
5759
+ }
5760
+ if (globalLimit > minLimit && globalMode === LimitMode.delete) {
5761
+ const globalCountToRemove = this.count + countOffset - globalLimit;
5762
+ if (globalCountToRemove > minCount) {
5763
+ this.#removeAny(globalCountToRemove);
5764
+ }
5765
+ }
5766
+ return false;
5767
+ }
5667
5768
  #createBuckets(zLayers) {
5668
5769
  const bucketCount = Math.max(Math.floor(zLayers), one);
5669
5770
  return Array.from({ length: bucketCount }, () => []);
@@ -5686,6 +5787,70 @@
5686
5787
  }
5687
5788
  return ((canvasSize.width * canvasSize.height) / (densityOptions.height * densityOptions.width * pxRatio ** squareExp));
5688
5789
  }
5790
+ async #initDrawersAndUpdaters() {
5791
+ const container = this.#container;
5792
+ await container.initDrawersAndUpdaters();
5793
+ for (const drawer of container.effectDrawers.values()) {
5794
+ await drawer.init?.(container);
5795
+ }
5796
+ for (const drawer of container.shapeDrawers.values()) {
5797
+ await drawer.init?.(container);
5798
+ }
5799
+ }
5800
+ async #initPlugins() {
5801
+ await this.#initPluginsArrays();
5802
+ await this.#initDrawersAndUpdaters();
5803
+ let handled = false;
5804
+ const container = this.#container;
5805
+ for (const plugin of container.plugins) {
5806
+ handled = plugin.particlesInitialization?.() ?? handled;
5807
+ if (handled) {
5808
+ break;
5809
+ }
5810
+ }
5811
+ if (handled) {
5812
+ return;
5813
+ }
5814
+ const particlesOptions = container.actualOptions.particles, groups = particlesOptions.groups;
5815
+ for (const group in groups) {
5816
+ const groupOptions = groups[group];
5817
+ if (!groupOptions) {
5818
+ continue;
5819
+ }
5820
+ for (let i = this.count, j = 0; j < groupOptions.number.value && i < particlesOptions.number.value; i++, j++) {
5821
+ this.addParticle(undefined, groupOptions, group);
5822
+ }
5823
+ }
5824
+ for (let i = this.count; i < particlesOptions.number.value; i++) {
5825
+ this.addParticle();
5826
+ }
5827
+ }
5828
+ async #initPluginsArrays() {
5829
+ const container = this.#container;
5830
+ for (const plugin of container.plugins) {
5831
+ if (plugin.redrawInit) {
5832
+ await plugin.redrawInit();
5833
+ }
5834
+ if (plugin.checkParticlePosition) {
5835
+ this.checkParticlePositionPlugins.push(plugin);
5836
+ }
5837
+ if (plugin.update) {
5838
+ this.#updatePlugins.push(plugin);
5839
+ }
5840
+ if (plugin.particleUpdate) {
5841
+ this.#particleUpdatePlugins.push(plugin);
5842
+ }
5843
+ if (plugin.postUpdate) {
5844
+ this.#postUpdatePlugins.push(plugin);
5845
+ }
5846
+ if (plugin.particleReset) {
5847
+ this.#particleResetPlugins.push(plugin);
5848
+ }
5849
+ if (plugin.postParticleUpdate) {
5850
+ this.#postParticleUpdatePlugins.push(plugin);
5851
+ }
5852
+ }
5853
+ }
5689
5854
  #insertParticleIntoBucket(particle) {
5690
5855
  const bucketIndex = this.#getBucketIndex(particle.position.z), bucket = this.#zBuckets[bucketIndex];
5691
5856
  if (!bucket) {
@@ -5694,12 +5859,15 @@
5694
5859
  bucket.push(particle);
5695
5860
  this.#particleBuckets.set(particle.id, bucketIndex);
5696
5861
  }
5697
- #removeParticle(index, group, override) {
5862
+ #removeAny(quantity) {
5863
+ this.removeAt(minIndex, quantity, undefined, undefined, false);
5864
+ }
5865
+ #removeParticle(index, group, override, matchGroup = true) {
5698
5866
  const particle = this.#array[index];
5699
5867
  if (!particle) {
5700
5868
  return false;
5701
5869
  }
5702
- if (particle.group !== group) {
5870
+ if (matchGroup && particle.group !== group) {
5703
5871
  return false;
5704
5872
  }
5705
5873
  this.#array.splice(index, deleteCount);
@@ -5786,7 +5954,7 @@
5786
5954
  particlesToDelete.add(particle);
5787
5955
  continue;
5788
5956
  }
5789
- this.grid.insert(particle);
5957
+ this.#grid.insert(particle);
5790
5958
  }
5791
5959
  return particlesToDelete;
5792
5960
  }
@@ -5962,7 +6130,6 @@
5962
6130
  this.shapeDrawers = new Map();
5963
6131
  this.particleUpdaters = [];
5964
6132
  this.plugins.length = 0;
5965
- this.#pluginManager.clearPlugins(this);
5966
6133
  this.destroyed = true;
5967
6134
  this.#onDestroy(remove);
5968
6135
  this.dispatchEvent(EventType.containerDestroyed);
@@ -6015,31 +6182,14 @@
6015
6182
  await this.initDrawersAndUpdaters();
6016
6183
  this.#options = loadContainerOptions(this.#pluginManager, this, this.#initialSourceOptions, this.sourceOptions);
6017
6184
  this.actualOptions = loadContainerOptions(this.#pluginManager, this, this.#options);
6018
- this.plugins.length = 0;
6019
- this.particleDestroyedPlugins.length = 0;
6020
- this.particleCreatedPlugins.length = 0;
6021
- this.particlePositionPlugins.length = 0;
6022
- for (const [plugin, containerPlugin] of allContainerPlugins) {
6023
- if (plugin.needsPlugin(this.actualOptions)) {
6024
- this.plugins.push(containerPlugin);
6025
- if (containerPlugin.particleCreated) {
6026
- this.particleCreatedPlugins.push(containerPlugin);
6027
- }
6028
- if (containerPlugin.particleDestroyed) {
6029
- this.particleDestroyedPlugins.push(containerPlugin);
6030
- }
6031
- if (containerPlugin.particlePosition) {
6032
- this.particlePositionPlugins.push(containerPlugin);
6033
- }
6034
- }
6035
- }
6185
+ this.#initPlugins(allContainerPlugins);
6036
6186
  this.retina.init();
6037
6187
  this.canvas.init();
6038
6188
  this.updateActualOptions();
6039
6189
  this.canvas.initBackground();
6040
6190
  this.canvas.resize();
6041
6191
  const { delay, duration, fpsLimit, smooth, zLayers } = this.actualOptions, hdrOptions = this.actualOptions.hdr;
6042
- this.hdrMode = hdrOptions.mode;
6192
+ this.hdrMode = toEnumValue(HdrMode, hdrOptions.mode, HdrMode.standard);
6043
6193
  this.peakNits = hdrOptions.peakNits;
6044
6194
  this.zLayers = zLayers;
6045
6195
  this.#duration = getRangeValue(duration) * millisecondsToSeconds;
@@ -6060,9 +6210,9 @@
6060
6210
  }
6061
6211
  async initDrawersAndUpdaters() {
6062
6212
  const pluginManager = this.#pluginManager;
6063
- this.effectDrawers = await pluginManager.getEffectDrawers(this, true);
6064
- this.shapeDrawers = await pluginManager.getShapeDrawers(this, true);
6065
- this.particleUpdaters = await pluginManager.getUpdaters(this, true);
6213
+ this.effectDrawers = await getItemMapFromInitializer(this, pluginManager.initializers.effects);
6214
+ this.shapeDrawers = await getItemMapFromInitializer(this, pluginManager.initializers.shapes);
6215
+ this.particleUpdaters = await getItemsFromInitializer(this, pluginManager.initializers.updaters);
6066
6216
  }
6067
6217
  pause() {
6068
6218
  if (!guardCheck(this)) {
@@ -6173,6 +6323,27 @@
6173
6323
  }
6174
6324
  return refresh;
6175
6325
  }
6326
+ #initPlugins(allContainerPlugins) {
6327
+ this.plugins.length = 0;
6328
+ this.particleDestroyedPlugins.length = 0;
6329
+ this.particleCreatedPlugins.length = 0;
6330
+ this.particlePositionPlugins.length = 0;
6331
+ for (const [plugin, containerPlugin] of allContainerPlugins) {
6332
+ if (!plugin.needsPlugin(this.actualOptions)) {
6333
+ continue;
6334
+ }
6335
+ this.plugins.push(containerPlugin);
6336
+ if (containerPlugin.particleCreated) {
6337
+ this.particleCreatedPlugins.push(containerPlugin);
6338
+ }
6339
+ if (containerPlugin.particleDestroyed) {
6340
+ this.particleDestroyedPlugins.push(containerPlugin);
6341
+ }
6342
+ if (containerPlugin.particlePosition) {
6343
+ this.particlePositionPlugins.push(containerPlugin);
6344
+ }
6345
+ }
6346
+ }
6176
6347
  #nextFrame(timestamp) {
6177
6348
  try {
6178
6349
  if (!this.#smooth &&
@@ -6449,11 +6620,11 @@
6449
6620
  }
6450
6621
  }
6451
6622
  async #init() {
6452
- const availablePathGenerators = await this.#pluginManager.getPathGenerators?.(this.#container, true);
6453
- if (!availablePathGenerators) {
6623
+ const pluginManager = this.#pluginManager;
6624
+ if (!pluginManager.initializers.pathGenerators) {
6454
6625
  return;
6455
6626
  }
6456
- this.availablePathGenerators = availablePathGenerators;
6627
+ this.availablePathGenerators = await getItemMapFromInitializer(this.#container, pluginManager.initializers.pathGenerators);
6457
6628
  this.pathGenerators = new Map();
6458
6629
  for (const pathGenerator of this.pathGenerators.values()) {
6459
6630
  pathGenerator.init();
@@ -6557,28 +6728,12 @@
6557
6728
  }
6558
6729
  const html = interactivityEl, canvas = container.canvas;
6559
6730
  canvas.setPointerEvents(html === canvas.domElement ? "initial" : "none");
6560
- if (add && !(options.interactivity?.events.onHover.enable || options.interactivity?.events.onClick.enable)) {
6561
- return;
6562
- }
6563
6731
  manageListener(interactivityEl, mouseMoveEvent, handlers.mouseMove, add);
6564
6732
  manageListener(interactivityEl, touchStartEvent, handlers.touchStart, add);
6565
6733
  manageListener(interactivityEl, touchMoveEvent, handlers.touchMove, add);
6566
- if (add) {
6567
- if (options.interactivity?.events.onClick.enable) {
6568
- manageListener(interactivityEl, touchEndEvent, handlers.touchEndClick, add);
6569
- manageListener(interactivityEl, mouseUpEvent, handlers.mouseUp, add);
6570
- manageListener(interactivityEl, mouseDownEvent, handlers.mouseDown, add);
6571
- }
6572
- else {
6573
- manageListener(interactivityEl, touchEndEvent, handlers.touchEnd, add);
6574
- }
6575
- }
6576
- else {
6577
- manageListener(interactivityEl, touchEndEvent, handlers.touchEndClick, add);
6578
- manageListener(interactivityEl, mouseUpEvent, handlers.mouseUp, add);
6579
- manageListener(interactivityEl, mouseDownEvent, handlers.mouseDown, add);
6580
- manageListener(interactivityEl, touchEndEvent, handlers.touchEnd, add);
6581
- }
6734
+ manageListener(interactivityEl, touchEndEvent, options.interactivity?.events.onClick.enable ? handlers.touchEndClick : handlers.touchEnd, add);
6735
+ manageListener(interactivityEl, mouseUpEvent, handlers.mouseUp, add);
6736
+ manageListener(interactivityEl, mouseDownEvent, handlers.mouseDown, add);
6582
6737
  manageListener(interactivityEl, mouseLeaveEvent, handlers.mouseLeave, add);
6583
6738
  manageListener(interactivityEl, touchCancelEvent, handlers.touchCancel, add);
6584
6739
  }
@@ -6604,19 +6759,18 @@
6604
6759
  #mouseTouchClick(e) {
6605
6760
  const container = this.#container, interactionManager = this.#interactionManager, options = container.actualOptions, { mouse } = interactionManager.interactivityData;
6606
6761
  mouse.inside = true;
6607
- let handled = false;
6608
6762
  const mousePosition = mouse.position;
6609
- if (!mousePosition || !options.interactivity?.events.onClick.enable) {
6610
- return;
6611
- }
6612
- for (const plugin of this.#clickPositionPlugins) {
6613
- handled = plugin.clickPositionValid?.(mousePosition) ?? false;
6614
- if (handled) {
6615
- break;
6763
+ if (mousePosition && options.interactivity?.events.onClick.enable) {
6764
+ let handled = false;
6765
+ for (const plugin of this.#clickPositionPlugins) {
6766
+ handled = plugin.clickPositionValid?.(mousePosition) ?? false;
6767
+ if (handled) {
6768
+ break;
6769
+ }
6770
+ }
6771
+ if (!handled) {
6772
+ this.#doMouseTouchClick(e);
6616
6773
  }
6617
- }
6618
- if (!handled) {
6619
- this.#doMouseTouchClick(e);
6620
6774
  }
6621
6775
  mouse.clicking = false;
6622
6776
  }
@@ -6712,6 +6866,9 @@
6712
6866
  this.#touches.set(touch.identifier, performance.now());
6713
6867
  }
6714
6868
  this.#mouseTouchMove(e);
6869
+ const { mouse } = this.#interactionManager.interactivityData;
6870
+ mouse.clicking = true;
6871
+ mouse.downPosition = mouse.position;
6715
6872
  }
6716
6873
  }
6717
6874
 
@@ -6724,18 +6881,18 @@
6724
6881
  }
6725
6882
  class InteractionManager {
6726
6883
  interactivityData;
6884
+ interactors;
6727
6885
  #clickHandlers;
6728
6886
  #container;
6729
6887
  #eventListeners;
6730
6888
  #externalInteractors;
6731
- #interactors;
6732
6889
  #intersectionObserver;
6733
6890
  #particleInteractors;
6734
6891
  #pluginManager;
6735
6892
  constructor(pluginManager, container) {
6736
6893
  this.#container = container;
6737
6894
  this.#pluginManager = pluginManager;
6738
- this.#interactors = [];
6895
+ this.interactors = [];
6739
6896
  this.#externalInteractors = [];
6740
6897
  this.#particleInteractors = [];
6741
6898
  this.#clickHandlers = new Map();
@@ -6854,7 +7011,7 @@
6854
7011
  }
6855
7012
  init() {
6856
7013
  this.#eventListeners.init();
6857
- for (const interactor of this.#interactors) {
7014
+ for (const interactor of this.interactors) {
6858
7015
  switch (interactor.type) {
6859
7016
  case InteractorType.external:
6860
7017
  this.#externalInteractors.push(interactor);
@@ -6867,11 +7024,11 @@
6867
7024
  }
6868
7025
  }
6869
7026
  async initInteractors() {
6870
- const interactors = await this.#pluginManager.getInteractors?.(this.#container, true);
6871
- if (!interactors) {
7027
+ const pluginManager = this.#pluginManager;
7028
+ if (!pluginManager.initializers.interactors) {
6872
7029
  return;
6873
7030
  }
6874
- this.#interactors = interactors;
7031
+ this.interactors = await getItemsFromInitializer(this.#container, pluginManager.initializers.interactors);
6875
7032
  this.#externalInteractors = [];
6876
7033
  this.#particleInteractors = [];
6877
7034
  }
@@ -6916,13 +7073,13 @@
6916
7073
  }
6917
7074
  updateMaxDistance() {
6918
7075
  let maxTotalDistance = 0;
6919
- for (const interactor of this.#interactors) {
7076
+ for (const interactor of this.interactors) {
6920
7077
  if (interactor.maxDistance > maxTotalDistance) {
6921
7078
  maxTotalDistance = interactor.maxDistance;
6922
7079
  }
6923
7080
  }
6924
7081
  const container = this.#container;
6925
- container.particles.grid.setCellSize(maxTotalDistance * container.retina.pixelRatio);
7082
+ container.particles.grid.cellSize = maxTotalDistance * container.retina.pixelRatio;
6926
7083
  }
6927
7084
  #intersectionManager(entries) {
6928
7085
  const container = this.#container;
@@ -6944,59 +7101,59 @@
6944
7101
  }
6945
7102
 
6946
7103
  class InteractivityPluginInstance {
6947
- interactionManager;
6948
7104
  #container;
6949
- #pluginManager;
6950
7105
  constructor(pluginManager, container) {
6951
- this.#container = container;
6952
- this.#pluginManager = pluginManager;
6953
- this.interactionManager = new InteractionManager(pluginManager, container);
6954
- this.#container.addClickHandler = (callback) => {
6955
- this.interactionManager.addClickHandler(callback);
7106
+ container.addClickHandler = (callback) => {
7107
+ container.interactionManager?.addClickHandler(callback);
6956
7108
  };
7109
+ container.interactionManager = new InteractionManager(pluginManager, container);
7110
+ this.#container = container;
6957
7111
  }
6958
7112
  addClickHandler(callback) {
6959
- this.interactionManager.addClickHandler(callback);
7113
+ this.#container.interactionManager?.addClickHandler(callback);
6960
7114
  }
6961
7115
  clearClickHandlers() {
6962
- this.interactionManager.clearClickHandlers();
7116
+ this.#container.interactionManager?.clearClickHandlers();
6963
7117
  }
6964
7118
  destroy() {
6965
7119
  this.clearClickHandlers();
6966
- this.#pluginManager.interactors?.delete(this.#container);
6967
7120
  }
6968
7121
  particleCreated(particle) {
6969
- const interactivityParticle = particle, interactivity = new Interactivity(this.#pluginManager, this.#container);
6970
- interactivity.load(this.#container.actualOptions.interactivity);
7122
+ const interactivityParticle = particle, container = this.#container, interactivity = new Interactivity(container);
7123
+ interactivity.load(container.actualOptions.interactivity);
6971
7124
  interactivity.load(interactivityParticle.options.interactivity);
6972
7125
  interactivityParticle.interactivity = interactivity;
6973
7126
  }
6974
7127
  particleReset(particle) {
6975
- this.interactionManager.reset(particle);
7128
+ this.#container.interactionManager?.reset(particle);
6976
7129
  }
6977
7130
  postParticleUpdate(particle, delta) {
6978
- this.interactionManager.particlesInteract(particle, delta);
7131
+ this.#container.interactionManager?.particlesInteract(particle, delta);
6979
7132
  }
6980
7133
  postUpdate(delta) {
6981
- this.interactionManager.externalInteract(delta);
6982
- this.interactionManager.updateMaxDistance();
7134
+ const container = this.#container;
7135
+ container.interactionManager?.externalInteract(delta);
7136
+ container.interactionManager?.updateMaxDistance();
6983
7137
  }
6984
7138
  async preInit() {
6985
- await this.interactionManager.initInteractors();
6986
- this.interactionManager.init();
7139
+ const container = this.#container;
7140
+ await container.interactionManager?.initInteractors();
7141
+ container.interactionManager?.init();
6987
7142
  }
6988
7143
  async redrawInit() {
6989
- await this.interactionManager.initInteractors();
6990
- this.interactionManager.init();
7144
+ const container = this.#container;
7145
+ await container.interactionManager?.initInteractors();
7146
+ container.interactionManager?.init();
6991
7147
  }
6992
7148
  start() {
6993
- this.interactionManager.addListeners();
6994
- this.interactionManager.startObserving();
7149
+ const container = this.#container;
7150
+ container.interactionManager?.addListeners();
7151
+ container.interactionManager?.startObserving();
6995
7152
  return Promise.resolve();
6996
7153
  }
6997
7154
  stop() {
6998
- this.interactionManager.removeListeners();
6999
- this.interactionManager.stopObserving();
7155
+ this.#container.interactionManager?.removeListeners();
7156
+ this.#container.interactionManager?.stopObserving();
7000
7157
  }
7001
7158
  }
7002
7159
 
@@ -7008,6 +7165,7 @@
7008
7165
  exports.loadFireflyPreset = loadFireflyPreset;
7009
7166
  exports.tsParticles = tsParticles;
7010
7167
 
7011
- }));
7168
+ })(g.__tsParticlesInternals.presets.firefly = g.__tsParticlesInternals.presets.firefly || {});
7169
+ })(typeof globalThis !== "undefined" ? globalThis : typeof window !== "undefined" ? window : self);
7170
+
7012
7171
  Object.assign(globalThis.window || globalThis, { loadFireflyPreset: (globalThis.__tsParticlesInternals.presets.firefly || {}).loadFireflyPreset });
7013
- delete (globalThis.window || globalThis).tsparticlesInternalExports;