@tsparticles/particles 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,58 @@
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
- /* tsParticles 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.bundles = global.__tsParticlesInternals.bundles || {}, global.__tsParticlesInternals.bundles.particles = global.__tsParticlesInternals.bundles.particles || {})));
7
- })(this, (function (exports) { 'use strict';
8
-
9
- const generatedAttribute = "generated", defaultCompositeValue = "source-over", resizeEvent = "resize", visibilityChangeEvent = "visibilitychange", percentDenominator = 100, half = 0.5, millisecondsToSeconds = 1000, originPoint = {
10
- x: 0,
11
- y: 0,
12
- z: 0,
13
- }, defaultTransform = {
14
- a: 1,
15
- b: 0,
16
- c: 0,
17
- d: 1,
18
- }, randomColorValue = "random", midColorValue = "mid", double = 2, doublePI = Math.PI * double, defaultFps = 60, defaultAlpha$1 = 1, generatedTrue = "true", generatedFalse = "false", canvasTag = "canvas", defaultRetryCount = 0, squareExp = 2, spatialHashGridCellSize = 100, defaultRemoveQuantity = 1, defaultRatio = 1, defaultReduceFactor = 1, inverseFactorNumerator = 1, rgbMax = 255, hMax = 360, sMax = 100, lMax = 100, hMin = 0, sMin = 0, hPhase = 60, empty = 0, quarter = 0.25, threeQuarter = half + quarter, minVelocity = 0, minDistance$2 = 0, minRadius$1 = 0, defaultTransformValue = 1, minimumSize = 0, zIndexFactorOffset = 1, defaultOpacity$2 = 1, removeDeleteCount = 1, removeMinIndex = 0, defaultFpsLimit = 120, minFpsLimit = 0, canvasFirstIndex = 0, loadRandomFactor = 10000, loadMinIndex = 0, one = 1, none = 0, decayOffset = 1, tryCountIncrement = 1, minZ = 0, minLimit = 0, countOffset = 1, minCount = 0, minIndex = 0, lengthOffset = 1, defaultDensityFactor = 1, deleteCount = 1, defaultAngle = 0, identity = 1, minStrokeWidth = 0, lFactor = 1, lMin = 0, maxNits = 400, triple = 3, sextuple = 6, sNormalizedOffset = 1, phaseNumerator = 1, defaultRgbMin = 0, defaultVelocity = 0, defaultLoops = 0, defaultTime = 0, defaultZoom = 1;
1
+ (function(g){g.__tsParticlesInternals=g.__tsParticlesInternals||{};g.__tsParticlesInternals.bundles=g.__tsParticlesInternals.bundles||{};g.__tsParticlesInternals.effects=g.__tsParticlesInternals.effects||{};g.__tsParticlesInternals.engine=g.__tsParticlesInternals.engine||{};g.__tsParticlesInternals.interactions=g.__tsParticlesInternals.interactions||{};g.__tsParticlesInternals.palettes=g.__tsParticlesInternals.palettes||{};g.__tsParticlesInternals.paths=g.__tsParticlesInternals.paths||{};g.__tsParticlesInternals.plugins=g.__tsParticlesInternals.plugins||{};g.__tsParticlesInternals.plugins=g.__tsParticlesInternals.plugins||{};g.__tsParticlesInternals.plugins.emittersShapes=g.__tsParticlesInternals.plugins.emittersShapes||{};g.__tsParticlesInternals.presets=g.__tsParticlesInternals.presets||{};g.__tsParticlesInternals.shapes=g.__tsParticlesInternals.shapes||{};g.__tsParticlesInternals.updaters=g.__tsParticlesInternals.updaters||{};g.__tsParticlesInternals.utils=g.__tsParticlesInternals.utils||{};g.__tsParticlesInternals.canvas=g.__tsParticlesInternals.canvas||{};g.__tsParticlesInternals.canvas=g.__tsParticlesInternals.canvas||{};g.__tsParticlesInternals.canvas.utils=g.__tsParticlesInternals.canvas.utils||{};g.__tsParticlesInternals.path=g.__tsParticlesInternals.path||{};g.__tsParticlesInternals.path=g.__tsParticlesInternals.path||{};g.__tsParticlesInternals.path.utils=g.__tsParticlesInternals.path.utils||{};var __tsProxyFactory=typeof Proxy!=="undefined"?function(obj){return new Proxy(obj,{get:function(target,key){if(!(key in target)){target[key]={};}return target[key];}});}:function(obj){return obj;};g.__tsParticlesInternals.bundles=__tsProxyFactory(g.__tsParticlesInternals.bundles);g.__tsParticlesInternals.effects=__tsProxyFactory(g.__tsParticlesInternals.effects);g.__tsParticlesInternals.interactions=__tsProxyFactory(g.__tsParticlesInternals.interactions);g.__tsParticlesInternals.palettes=__tsProxyFactory(g.__tsParticlesInternals.palettes);g.__tsParticlesInternals.paths=__tsProxyFactory(g.__tsParticlesInternals.paths);g.__tsParticlesInternals.plugins=__tsProxyFactory(g.__tsParticlesInternals.plugins);g.__tsParticlesInternals.plugins.emittersShapes=__tsProxyFactory(g.__tsParticlesInternals.plugins.emittersShapes);g.__tsParticlesInternals.presets=__tsProxyFactory(g.__tsParticlesInternals.presets);g.__tsParticlesInternals.shapes=__tsProxyFactory(g.__tsParticlesInternals.shapes);g.__tsParticlesInternals.updaters=__tsProxyFactory(g.__tsParticlesInternals.updaters);g.__tsParticlesInternals.utils=__tsProxyFactory(g.__tsParticlesInternals.utils);g.__tsParticlesInternals.canvas=__tsProxyFactory(g.__tsParticlesInternals.canvas);g.__tsParticlesInternals.path=__tsProxyFactory(g.__tsParticlesInternals.path);})(typeof globalThis!=="undefined"?globalThis:typeof window!=="undefined"?window:this);
2
+ (function (g) {
3
+ /* tsParticles v4.5.0 */
4
+ g.__tsParticlesInternals = g.__tsParticlesInternals || {};
5
+ g.__tsParticlesInternals.bundles = g.__tsParticlesInternals.bundles || {};
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 setLogger(logger) {
31
+ if (logger.debug) {
32
+ _logger.debug = wrap(logger.debug);
33
+ }
34
+ if (logger.error) {
35
+ _logger.error = wrap(logger.error);
36
+ }
37
+ if (logger.info) {
38
+ _logger.info = wrap(logger.info);
39
+ }
40
+ if (logger.log) {
41
+ _logger.log = wrap(logger.log);
42
+ }
43
+ if (logger.trace) {
44
+ _logger.trace = wrap(logger.trace);
45
+ }
46
+ if (logger.verbose) {
47
+ _logger.verbose = wrap(logger.verbose);
48
+ }
49
+ if (logger.warning) {
50
+ _logger.warning = wrap(logger.warning);
51
+ }
52
+ }
53
+ function getLogger() {
54
+ return _logger;
55
+ }
19
56
 
20
57
  exports.MoveDirection = void 0;
21
58
  (function (MoveDirection) {
@@ -32,6 +69,17 @@
32
69
  MoveDirection["inside"] = "inside";
33
70
  })(exports.MoveDirection || (exports.MoveDirection = {}));
34
71
 
72
+ const generatedAttribute = "generated", fullPercent = "100%", defaultCompositeValue = "source-over", resizeEvent = "resize", visibilityChangeEvent = "visibilitychange", percentDenominator = 100, half = 0.5, millisecondsToSeconds = 1000, originPoint = {
73
+ x: 0,
74
+ y: 0,
75
+ z: 0,
76
+ }, defaultTransform = {
77
+ a: 1,
78
+ b: 0,
79
+ c: 0,
80
+ d: 1,
81
+ }, randomColorValue = "random", midColorValue = "mid", double = 2, doublePI = Math.PI * double, defaultFps = 60, defaultAlpha = 1, generatedTrue = "true", generatedFalse = "false", canvasTag = "canvas", defaultRetryCount = 0, squareExp = 2, spatialHashGridCellSize = 100, defaultRemoveQuantity = 1, defaultRatio = 1, defaultReduceFactor = 1, inverseFactorNumerator = 1, rgbMax = 255, hMax = 360, sMax = 100, lMax = 100, hMin = 0, sMin = 0, hPhase = 60, empty = 0, quarter = 0.25, threeQuarter = half + quarter, minVelocity = 0, minDistance$2 = 0, minRadius = 0, defaultTransformValue = 1, minimumSize = 0, zIndexFactorOffset = 1, defaultOpacity$2 = 1, removeDeleteCount = 1, removeMinIndex = 0, defaultFpsLimit = 120, minFpsLimit = 0, canvasFirstIndex = 0, loadRandomFactor = 10000, loadMinIndex = 0, one = 1, none = 0, decayOffset = 1, tryCountIncrement = 1, minZ = 0, minLimit = 0, countOffset = 1, minCount = 0, minIndex = 0, lengthOffset = 1, defaultDensityFactor = 1, deleteCount = 1, defaultAngle = 0, identity = 1, minStrokeWidth = 0, lFactor = 1, lMin = 0, maxNits = 400, triple = 3, sextuple = 6, sNormalizedOffset = 1, phaseNumerator = 1, defaultRgbMin = 0, defaultVelocity = 0, defaultLoops = 0, defaultTime = 0, defaultZoom = 1;
82
+
35
83
  function getZ(source) {
36
84
  return "z" in source ? source.z : originPoint.z;
37
85
  }
@@ -150,6 +198,12 @@
150
198
  function isFunction(arg) {
151
199
  return typeof arg === "function";
152
200
  }
201
+ function isEnumValue(enumObject, arg) {
202
+ return Object.values(enumObject).some(enumValue => enumValue === arg);
203
+ }
204
+ function toEnumValue(enumObject, arg, defaultValue) {
205
+ return isEnumValue(enumObject, arg) ? arg : defaultValue;
206
+ }
153
207
  function isObject(arg) {
154
208
  return typeof arg === "object" && arg !== null;
155
209
  }
@@ -310,11 +364,61 @@
310
364
  };
311
365
  }
312
366
  function parseAlpha(input) {
313
- const defaultAlpha = 1;
314
367
  if (!input) {
315
368
  return defaultAlpha;
316
369
  }
317
- return input.endsWith("%") ? parseFloat(input) / percentDenominator : parseFloat(input);
370
+ return input.endsWith("%") ? Number.parseFloat(input) / percentDenominator : Number.parseFloat(input);
371
+ }
372
+
373
+ const ErrorCodes$3 = {
374
+ engineVersionMismatch: "TSP-1001",
375
+ particlePositionNotFound: "TSP-1002",
376
+ pluginRegisterAfterLoad: "TSP-1003",
377
+ offscreenCanvasUnsupported: "TSP-1101",
378
+ offscreenCanvasTransferFailed: "TSP-1102",
379
+ hdrEnableInvalid: "TSP-1201",
380
+ hdrModeInvalid: "TSP-1202",
381
+ hdrPeakNitsInvalid: "TSP-1203",
382
+ };
383
+
384
+ const messages = {
385
+ [ErrorCodes$3.engineVersionMismatch]: "The tsParticles version is different from the loaded plugins version. Engine version: {0}. Plugin version: {1}",
386
+ [ErrorCodes$3.particlePositionNotFound]: "a valid position cannot be found for particle",
387
+ [ErrorCodes$3.pluginRegisterAfterLoad]: "Register plugins can only be done before calling tsParticles.load()",
388
+ [ErrorCodes$3.offscreenCanvasUnsupported]: "OffscreenCanvas is required but not supported by this browser",
389
+ [ErrorCodes$3.offscreenCanvasTransferFailed]: "OffscreenCanvas transfer failed",
390
+ [ErrorCodes$3.hdrEnableInvalid]: 'Invalid HDR "enable" value: expected a boolean, got "{0}"',
391
+ [ErrorCodes$3.hdrModeInvalid]: 'Invalid HDR "mode" value: expected one of {0}, got "{1}"',
392
+ [ErrorCodes$3.hdrPeakNitsInvalid]: 'Invalid HDR "peakNits" value: expected a positive number, got "{0}"',
393
+ };
394
+
395
+ let registeredMessages;
396
+ const ensureRegisteredMessages = () => {
397
+ registeredMessages ??= new Map(Object.entries(messages));
398
+ return registeredMessages;
399
+ }, toStringValue$1 = (value) => String(value), format = (template, args) => {
400
+ return template.replace(/\{(\d+)\}/g, (match, index) => {
401
+ const arg = args[Number(index)];
402
+ return arg === undefined ? match : toStringValue$1(arg);
403
+ });
404
+ };
405
+ function addErrorMessages(extraMessages) {
406
+ if (typeof process !== "undefined" && process.env.NODE_ENV === "production") {
407
+ return;
408
+ }
409
+ const catalog = ensureRegisteredMessages();
410
+ for (const [code, message] of Object.entries(extraMessages)) {
411
+ if (message !== undefined) {
412
+ catalog.set(code, message);
413
+ }
414
+ }
415
+ }
416
+ function getErrorMessage(code, ...args) {
417
+ if (typeof process !== "undefined" && process.env.NODE_ENV === "production") {
418
+ return `[tsParticles Error ${code}] https://particles.js.org/errors/#${code}`;
419
+ }
420
+ const template = ensureRegisteredMessages().get(code) ?? `Unknown error code ${code}`;
421
+ return format(template, args);
318
422
  }
319
423
 
320
424
  exports.OutModeDirection = void 0;
@@ -331,7 +435,6 @@
331
435
  PixelMode["percent"] = "percent";
332
436
  })(exports.PixelMode || (exports.PixelMode = {}));
333
437
 
334
- const minRadius = 0;
335
438
  function isForbiddenKey(key) {
336
439
  return key === "__proto__" || key === "constructor" || key === "prototype";
337
440
  }
@@ -547,22 +650,84 @@
547
650
  element.removeEventListener(event, handler, removeOptions);
548
651
  }
549
652
  }
550
- async function getItemsFromInitializer(container, map, initializers, force = false) {
551
- let res = map.get(container);
552
- if (!res || force) {
553
- res = await Promise.all([...initializers.values()].map(t => t(container)));
554
- map.set(container, res);
653
+ async function getItemsFromInitializer(container, initializers) {
654
+ return await Promise.all([...initializers.values()].map(t => t(container)));
655
+ }
656
+ async function getItemMapFromInitializer(container, initializers) {
657
+ const entries = await Promise.all([...initializers.entries()].map(([key, initializer]) => initializer(container).then(item => [key, item])));
658
+ return new Map(entries);
659
+ }
660
+ async function getDataFromUrl(data) {
661
+ const url = itemFromSingleOrMultiple(data.url, data.index);
662
+ if (!url) {
663
+ return data.fallback;
555
664
  }
556
- return res;
665
+ try {
666
+ const response = await fetch(url);
667
+ if (response.ok) {
668
+ const current = (await response.json());
669
+ if (isSourceOptionsValue(current)) {
670
+ return current;
671
+ }
672
+ getLogger().error("invalid configuration data while retrieving config file");
673
+ }
674
+ else {
675
+ getLogger().error(`${response.status.toString()} while retrieving config file`);
676
+ }
677
+ }
678
+ catch (error) {
679
+ getLogger().error(`error while retrieving config file: ${error}`);
680
+ }
681
+ return data.fallback;
557
682
  }
558
- async function getItemMapFromInitializer(container, map, initializers, force = false) {
559
- let res = map.get(container);
560
- if (!res || force) {
561
- const entries = await Promise.all([...initializers.entries()].map(([key, initializer]) => initializer(container).then(item => [key, item])));
562
- res = new Map(entries);
563
- map.set(container, res);
683
+ function isSourceOptionsValue(value) {
684
+ if (isArray(value)) {
685
+ return value.every((entry) => isObject(entry) && !isArray(entry));
564
686
  }
565
- return res;
687
+ return isObject(value) && !isArray(value);
688
+ }
689
+ function getCanvasFromContainer(domContainer) {
690
+ let canvasEl;
691
+ const documentSafe = safeDocument(), isCanvas = domContainer instanceof HTMLCanvasElement || domContainer.tagName.toLowerCase() === canvasTag;
692
+ if (isCanvas) {
693
+ canvasEl = domContainer;
694
+ canvasEl.dataset[generatedAttribute] ??= generatedFalse;
695
+ if (canvasEl.dataset[generatedAttribute] === generatedTrue) {
696
+ canvasEl.style.width ||= fullPercent;
697
+ canvasEl.style.height ||= fullPercent;
698
+ canvasEl.style.pointerEvents = "none";
699
+ canvasEl.style.setProperty("pointer-events", "none");
700
+ }
701
+ }
702
+ else {
703
+ const existingCanvases = domContainer.getElementsByTagName(canvasTag), foundCanvas = existingCanvases.item(canvasFirstIndex);
704
+ if (foundCanvas) {
705
+ canvasEl = foundCanvas;
706
+ canvasEl.dataset[generatedAttribute] = generatedFalse;
707
+ }
708
+ else {
709
+ canvasEl = documentSafe.createElement(canvasTag);
710
+ canvasEl.dataset[generatedAttribute] = generatedTrue;
711
+ domContainer.appendChild(canvasEl);
712
+ }
713
+ canvasEl.style.width ||= fullPercent;
714
+ canvasEl.style.height ||= fullPercent;
715
+ canvasEl.style.pointerEvents = "none";
716
+ canvasEl.style.setProperty("pointer-events", "none");
717
+ }
718
+ return canvasEl;
719
+ }
720
+ function getDomContainer(id, source) {
721
+ const documentSafe = safeDocument();
722
+ let domContainer = source ?? documentSafe.getElementById(id);
723
+ if (domContainer) {
724
+ return domContainer;
725
+ }
726
+ domContainer = documentSafe.createElement("canvas");
727
+ domContainer.id = id;
728
+ domContainer.dataset[generatedAttribute] = generatedTrue;
729
+ documentSafe.body.append(domContainer);
730
+ return domContainer;
566
731
  }
567
732
 
568
733
  class EventDispatcher {
@@ -633,7 +798,6 @@
633
798
  class PluginManager {
634
799
  colorManagers = new Map();
635
800
  easingFunctions = new Map();
636
- effectDrawers = new Map();
637
801
  initializers = {
638
802
  effects: new Map(),
639
803
  shapes: new Map(),
@@ -642,8 +806,6 @@
642
806
  palettes = new Map();
643
807
  plugins = [];
644
808
  presets = new Map();
645
- shapeDrawers = new Map();
646
- updaters = new Map();
647
809
  #allLoadersSet = new Set();
648
810
  #configs = new Map();
649
811
  #engine;
@@ -661,57 +823,79 @@
661
823
  }
662
824
  return res;
663
825
  }
826
+ get initialized() {
827
+ return this.#initialized;
828
+ }
664
829
  addColorManager(name, manager) {
830
+ if (this.#initialized) {
831
+ return;
832
+ }
665
833
  this.colorManagers.set(name, manager);
666
834
  }
667
835
  addConfig(config) {
836
+ if (this.#initialized) {
837
+ return;
838
+ }
668
839
  const key = config.key ?? config.name ?? "default";
669
840
  this.#configs.set(key, config);
670
841
  this.#engine.dispatchEvent(exports.EventType.configAdded, { data: { name: key, config } });
671
842
  }
672
843
  addEasing(name, easing) {
844
+ if (this.#initialized) {
845
+ return;
846
+ }
673
847
  if (this.easingFunctions.get(name)) {
674
848
  return;
675
849
  }
676
850
  this.easingFunctions.set(name, easing);
677
851
  }
678
852
  addEffect(effect, drawer) {
853
+ if (this.#initialized) {
854
+ return;
855
+ }
679
856
  this.initializers.effects.set(effect, drawer);
680
857
  }
681
858
  addPalette(name, palette) {
859
+ if (this.#initialized) {
860
+ return;
861
+ }
682
862
  this.palettes.set(name, palette);
683
863
  }
684
864
  addParticleUpdater(name, updaterInitializer) {
865
+ if (this.#initialized) {
866
+ return;
867
+ }
685
868
  this.initializers.updaters.set(name, updaterInitializer);
686
869
  }
687
870
  addPlugin(plugin) {
871
+ if (this.#initialized) {
872
+ return;
873
+ }
688
874
  if (this.getPlugin(plugin.id)) {
689
875
  return;
690
876
  }
691
877
  this.plugins.push(plugin);
692
878
  }
693
879
  addPreset(preset, options, override = false) {
880
+ if (this.#initialized) {
881
+ return;
882
+ }
694
883
  if (!(override || !this.getPreset(preset))) {
695
884
  return;
696
885
  }
697
886
  this.presets.set(preset, options);
698
887
  }
699
888
  addShape(shapes, drawer) {
889
+ if (this.#initialized) {
890
+ return;
891
+ }
700
892
  for (const shape of shapes) {
701
893
  this.initializers.shapes.set(shape, drawer);
702
894
  }
703
895
  }
704
- clearPlugins(container) {
705
- this.effectDrawers.delete(container);
706
- this.shapeDrawers.delete(container);
707
- this.updaters.delete(container);
708
- }
709
896
  getEasing(name) {
710
897
  return this.easingFunctions.get(name) ?? ((value) => value);
711
898
  }
712
- getEffectDrawers(container, force = false) {
713
- return getItemMapFromInitializer(container, this.effectDrawers, this.initializers.effects, force);
714
- }
715
899
  getPalette(name) {
716
900
  return this.palettes.get(name);
717
901
  }
@@ -721,12 +905,6 @@
721
905
  getPreset(preset) {
722
906
  return this.presets.get(preset);
723
907
  }
724
- async getShapeDrawers(container, force = false) {
725
- return getItemMapFromInitializer(container, this.shapeDrawers, this.initializers.shapes, force);
726
- }
727
- async getUpdaters(container, force = false) {
728
- return getItemsFromInitializer(container, this.updaters, this.initializers.updaters, force);
729
- }
730
908
  async init() {
731
909
  if (this.#initialized || this.#isRunningLoaders) {
732
910
  return;
@@ -745,16 +923,9 @@
745
923
  this.#initialized = true;
746
924
  }
747
925
  }
748
- loadParticlesOptions(container, options, ...sourceOptions) {
749
- const updaters = this.updaters.get(container);
750
- if (!updaters) {
751
- return;
752
- }
753
- updaters.forEach(updater => updater.loadOptions?.(options, ...sourceOptions));
754
- }
755
926
  async register(...loaders) {
756
927
  if (this.#initialized) {
757
- throw new Error("Register plugins can only be done before calling tsParticles.load()");
928
+ throw new Error(getErrorMessage(ErrorCodes$3.pluginRegisterAfterLoad));
758
929
  }
759
930
  for (const loader of loaders) {
760
931
  if (this.#isRunningLoaders) {
@@ -766,111 +937,15 @@
766
937
  }
767
938
  }
768
939
  async #runLoader(loader, executed, allLoaders) {
769
- if (executed.has(loader))
940
+ if (executed.has(loader)) {
770
941
  return;
942
+ }
771
943
  executed.add(loader);
772
944
  allLoaders.add(loader);
773
945
  await loader(this.#engine);
774
946
  }
775
947
  }
776
948
 
777
- const errorPrefix = "tsParticles - Error";
778
- const wrap = (fn) => (...args) => {
779
- fn(...args);
780
- }, _logger = {
781
- debug: wrap(console.debug),
782
- error: (message, ...optionalParams) => {
783
- console.error(`${errorPrefix} - ${message}`, ...optionalParams);
784
- },
785
- info: wrap(console.info),
786
- log: wrap(console.log),
787
- trace: wrap(console.trace),
788
- verbose: wrap(console.log),
789
- warning: wrap(console.warn),
790
- };
791
- function setLogger(logger) {
792
- if (logger.debug) {
793
- _logger.debug = wrap(logger.debug);
794
- }
795
- if (logger.error) {
796
- _logger.error = wrap(logger.error);
797
- }
798
- if (logger.info) {
799
- _logger.info = wrap(logger.info);
800
- }
801
- if (logger.log) {
802
- _logger.log = wrap(logger.log);
803
- }
804
- if (logger.trace) {
805
- _logger.trace = wrap(logger.trace);
806
- }
807
- if (logger.verbose) {
808
- _logger.verbose = wrap(logger.verbose);
809
- }
810
- if (logger.warning) {
811
- _logger.warning = wrap(logger.warning);
812
- }
813
- }
814
- function getLogger() {
815
- return _logger;
816
- }
817
-
818
- const fullPercent = "100%";
819
- async function getDataFromUrl(data) {
820
- const url = itemFromSingleOrMultiple(data.url, data.index);
821
- if (!url) {
822
- return data.fallback;
823
- }
824
- const response = await fetch(url);
825
- if (response.ok) {
826
- return (await response.json());
827
- }
828
- getLogger().error(`${response.status.toString()} while retrieving config file`);
829
- return data.fallback;
830
- }
831
- const getCanvasFromContainer = (domContainer) => {
832
- const documentSafe = safeDocument();
833
- let canvasEl;
834
- const isCanvas = domContainer instanceof HTMLCanvasElement || domContainer.tagName.toLowerCase() === canvasTag;
835
- if (isCanvas) {
836
- canvasEl = domContainer;
837
- canvasEl.dataset[generatedAttribute] ??= generatedFalse;
838
- if (canvasEl.dataset[generatedAttribute] === generatedTrue) {
839
- canvasEl.style.width ||= fullPercent;
840
- canvasEl.style.height ||= fullPercent;
841
- canvasEl.style.pointerEvents = "none";
842
- canvasEl.style.setProperty("pointer-events", "none");
843
- }
844
- }
845
- else {
846
- const existingCanvases = domContainer.getElementsByTagName(canvasTag), foundCanvas = existingCanvases.item(canvasFirstIndex);
847
- if (foundCanvas) {
848
- canvasEl = foundCanvas;
849
- canvasEl.dataset[generatedAttribute] = generatedFalse;
850
- }
851
- else {
852
- canvasEl = documentSafe.createElement(canvasTag);
853
- canvasEl.dataset[generatedAttribute] = generatedTrue;
854
- domContainer.appendChild(canvasEl);
855
- }
856
- canvasEl.style.width ||= fullPercent;
857
- canvasEl.style.height ||= fullPercent;
858
- canvasEl.style.pointerEvents = "none";
859
- canvasEl.style.setProperty("pointer-events", "none");
860
- }
861
- return canvasEl;
862
- }, getDomContainer = (id, source) => {
863
- const documentSafe = safeDocument();
864
- let domContainer = source ?? documentSafe.getElementById(id);
865
- if (domContainer) {
866
- return domContainer;
867
- }
868
- domContainer = documentSafe.createElement("canvas");
869
- domContainer.id = id;
870
- domContainer.dataset[generatedAttribute] = generatedTrue;
871
- documentSafe.body.append(domContainer);
872
- return domContainer;
873
- };
874
949
  class Engine {
875
950
  pluginManager = new PluginManager(this);
876
951
  #domArray = [];
@@ -880,7 +955,7 @@
880
955
  return this.#domArray;
881
956
  }
882
957
  get version() {
883
- return "4.4.0";
958
+ return "4.5.0";
884
959
  }
885
960
  addEventListener(type, listener) {
886
961
  this.#eventDispatcher.addEventListener(type, listener);
@@ -889,7 +964,7 @@
889
964
  if (this.version === pluginVersion) {
890
965
  return;
891
966
  }
892
- throw new Error(`The tsParticles version is different from the loaded plugins version. Engine version: ${this.version}. Plugin version: ${pluginVersion}`);
967
+ throw new Error(getErrorMessage(ErrorCodes$3.engineVersionMismatch, this.version, pluginVersion));
893
968
  }
894
969
  dispatchEvent(type, args) {
895
970
  this.#eventDispatcher.dispatchEvent(type, args);
@@ -1138,20 +1213,6 @@
1138
1213
  DrawLayer[DrawLayer["Foreground"] = 7] = "Foreground";
1139
1214
  })(exports.DrawLayer || (exports.DrawLayer = {}));
1140
1215
 
1141
- class OptionLoader {
1142
- load(data) {
1143
- if (isNull(data)) {
1144
- return;
1145
- }
1146
- this.doLoad(data);
1147
- }
1148
- }
1149
- function loadOptions(options, ...sourceOptionsArr) {
1150
- for (const sourceOptions of sourceOptionsArr) {
1151
- options.load(sourceOptions);
1152
- }
1153
- }
1154
-
1155
1216
  function loadProperty(obj, key, value) {
1156
1217
  if (value !== undefined) {
1157
1218
  obj[key] = value;
@@ -1180,7 +1241,7 @@
1180
1241
  if (keyStr === "__proto__" || keyStr === "constructor" || keyStr === "prototype") {
1181
1242
  return;
1182
1243
  }
1183
- const objRecord = obj, currentValue = Object.prototype.hasOwnProperty.call(objRecord, keyStr) ? objRecord[keyStr] : {};
1244
+ const objRecord = obj, currentValue = Object.hasOwn(objRecord, keyStr) ? objRecord[keyStr] : {};
1184
1245
  objRecord[keyStr] = deepExtend(currentValue, value);
1185
1246
  }
1186
1247
  }
@@ -1193,6 +1254,20 @@
1193
1254
  }
1194
1255
  }
1195
1256
 
1257
+ class OptionLoader {
1258
+ load(data) {
1259
+ if (isNull(data)) {
1260
+ return;
1261
+ }
1262
+ this.doLoad(data);
1263
+ }
1264
+ }
1265
+ function loadOptions(options, ...sourceOptionsArr) {
1266
+ for (const sourceOptions of sourceOptionsArr) {
1267
+ options.load(sourceOptions);
1268
+ }
1269
+ }
1270
+
1196
1271
  class AnimationOptions extends OptionLoader {
1197
1272
  count = 0;
1198
1273
  decay = 0;
@@ -1343,15 +1418,14 @@
1343
1418
  peakNits = defaultPeakNits;
1344
1419
  doLoad(data) {
1345
1420
  if (data.enable !== undefined && !isBoolean(data.enable)) {
1346
- throw new Error(`Invalid HDR "enable" value: expected a boolean, got "${String(data.enable)}"`);
1421
+ throw new Error(getErrorMessage(ErrorCodes$3.hdrEnableInvalid, String(data.enable)));
1347
1422
  }
1348
- if (data.mode !== undefined &&
1349
- (typeof data.mode !== "string" || !Object.values(exports.HdrMode).includes(data.mode))) {
1350
- throw new Error(`Invalid HDR "mode" value: expected one of ${Object.values(exports.HdrMode).join(", ")}, got "${toStringValue(data.mode)}"`);
1423
+ if (data.mode !== undefined && !isEnumValue(exports.HdrMode, data.mode)) {
1424
+ throw new Error(getErrorMessage(ErrorCodes$3.hdrModeInvalid, Object.values(exports.HdrMode).join(", "), toStringValue(data.mode)));
1351
1425
  }
1352
1426
  if (data.peakNits !== undefined &&
1353
1427
  (!isNumber(data.peakNits) || !Number.isFinite(data.peakNits) || data.peakNits <= minPeakNits)) {
1354
- throw new Error(`Invalid HDR "peakNits" value: expected a positive number, got "${String(data.peakNits)}"`);
1428
+ throw new Error(getErrorMessage(ErrorCodes$3.hdrPeakNitsInvalid, String(data.peakNits)));
1355
1429
  }
1356
1430
  loadProperty(this, "enable", data.enable);
1357
1431
  loadProperty(this, "mode", data.mode);
@@ -1729,12 +1803,10 @@
1729
1803
  plugin.loadParticlesOptions(this.#container, this, data);
1730
1804
  }
1731
1805
  }
1732
- const updaters = this.#pluginManager.updaters.get(this.#container);
1733
- if (updaters) {
1734
- for (const updater of updaters) {
1735
- if (updater.loadOptions) {
1736
- updater.loadOptions(this, data);
1737
- }
1806
+ const updaters = this.#container.particleUpdaters;
1807
+ for (const updater of updaters) {
1808
+ if (updater.loadOptions) {
1809
+ updater.loadOptions(this, data);
1738
1810
  }
1739
1811
  }
1740
1812
  }
@@ -2076,9 +2148,9 @@
2076
2148
  const grayscaleValue = Math.round(lNormalized * rgbMax);
2077
2149
  return { r: grayscaleValue, g: grayscaleValue, b: grayscaleValue };
2078
2150
  }
2079
- const temp1 = lNormalized < half
2151
+ const temp2 = lNormalized < half
2080
2152
  ? lNormalized * (sNormalizedOffset + sNormalized)
2081
- : 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));
2153
+ : 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));
2082
2154
  return { r: Math.round(red), g: Math.round(green), b: Math.round(blue) };
2083
2155
  }
2084
2156
  function hslToRgbFloat(hsl) {
@@ -2087,9 +2159,9 @@
2087
2159
  const grayscaleValue = lNormalized * rgbMax;
2088
2160
  return { r: grayscaleValue, g: grayscaleValue, b: grayscaleValue };
2089
2161
  }
2090
- const temp1 = lNormalized < half
2162
+ const temp2 = lNormalized < half
2091
2163
  ? lNormalized * (sNormalizedOffset + sNormalized)
2092
- : 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));
2164
+ : 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));
2093
2165
  return { r: red, g: green, b: blue };
2094
2166
  }
2095
2167
  function hslaToRgba(hsla) {
@@ -2449,7 +2521,7 @@
2449
2521
  }
2450
2522
 
2451
2523
  async function loadBlendPlugin(engine) {
2452
- engine.checkVersion("4.4.0");
2524
+ engine.checkVersion("4.5.0");
2453
2525
  await engine.pluginManager.register(e => {
2454
2526
  e.pluginManager.addPlugin(new BlendPlugin());
2455
2527
  });
@@ -2486,7 +2558,7 @@
2486
2558
  }
2487
2559
 
2488
2560
  async function loadCircleShape(engine) {
2489
- engine.checkVersion("4.4.0");
2561
+ engine.checkVersion("4.5.0");
2490
2562
  await engine.pluginManager.register(e => {
2491
2563
  e.pluginManager.addShape(["circle"], () => {
2492
2564
  return Promise.resolve(new CircleDrawer());
@@ -2501,7 +2573,7 @@
2501
2573
  RgbIndexes[RgbIndexes["b"] = 3] = "b";
2502
2574
  RgbIndexes[RgbIndexes["a"] = 4] = "a";
2503
2575
  })(RgbIndexes$1 || (RgbIndexes$1 = {}));
2504
- 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;
2576
+ 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;
2505
2577
  class HexColorManager {
2506
2578
  accepts(input) {
2507
2579
  return input.startsWith("#");
@@ -2534,7 +2606,7 @@
2534
2606
  }
2535
2607
 
2536
2608
  async function loadHexColorPlugin(engine) {
2537
- engine.checkVersion("4.4.0");
2609
+ engine.checkVersion("4.5.0");
2538
2610
  await engine.pluginManager.register(e => {
2539
2611
  e.pluginManager.addColorManager("hex", new HexColorManager());
2540
2612
  });
@@ -2574,7 +2646,7 @@
2574
2646
  if (!this.accepts(input)) {
2575
2647
  return;
2576
2648
  }
2577
- const result = hslRegex.exec(input), minLength = 4, defaultAlpha = 1, radix = 10;
2649
+ const result = hslRegex.exec(input), minLength = 4, radix = 10;
2578
2650
  return result
2579
2651
  ? hslaToRgba({
2580
2652
  a: result.length > minLength ? parseAlpha(result[HslIndexes.a]) : defaultAlpha,
@@ -2587,12 +2659,20 @@
2587
2659
  }
2588
2660
 
2589
2661
  async function loadHslColorPlugin(engine) {
2590
- engine.checkVersion("4.4.0");
2662
+ engine.checkVersion("4.5.0");
2591
2663
  await engine.pluginManager.register(e => {
2592
2664
  e.pluginManager.addColorManager("hsl", new HslColorManager());
2593
2665
  });
2594
2666
  }
2595
2667
 
2668
+ const ErrorCodes$2 = {
2669
+ baseMoverNotLoaded: "TSP-3203",
2670
+ };
2671
+
2672
+ const ErrorMessages$2 = {
2673
+ [ErrorCodes$2.baseMoverNotLoaded]: "tsParticles Base Mover is not loaded",
2674
+ };
2675
+
2596
2676
  class MovePlugin {
2597
2677
  id = "move";
2598
2678
  #pluginManager;
@@ -2611,20 +2691,20 @@
2611
2691
  }
2612
2692
 
2613
2693
  async function loadMovePlugin(engine) {
2614
- engine.checkVersion("4.4.0");
2694
+ engine.checkVersion("4.5.0");
2695
+ if (typeof process !== "undefined" && process.env.NODE_ENV !== "production") {
2696
+ addErrorMessages(ErrorMessages$2);
2697
+ }
2615
2698
  await engine.pluginManager.register(e => {
2616
2699
  const moveEngine = e, movePluginManager = moveEngine.pluginManager;
2617
2700
  movePluginManager.initializers.pathGenerators ??= new Map();
2618
- movePluginManager.pathGenerators ??= new Map();
2619
2701
  movePluginManager.addPathGenerator = (name, generator) => {
2702
+ if (movePluginManager.initialized) {
2703
+ return;
2704
+ }
2620
2705
  movePluginManager.initializers.pathGenerators ??= new Map();
2621
2706
  movePluginManager.initializers.pathGenerators.set(name, generator);
2622
2707
  };
2623
- movePluginManager.getPathGenerators = async (container, force = false) => {
2624
- movePluginManager.initializers.pathGenerators ??= new Map();
2625
- movePluginManager.pathGenerators ??= new Map();
2626
- return getItemMapFromInitializer(container, movePluginManager.pathGenerators, movePluginManager.initializers.pathGenerators, force);
2627
- };
2628
2708
  e.pluginManager.addPlugin(new MovePlugin(e.pluginManager));
2629
2709
  });
2630
2710
  }
@@ -2821,7 +2901,7 @@
2821
2901
  }
2822
2902
 
2823
2903
  async function loadOpacityUpdater(engine) {
2824
- engine.checkVersion("4.4.0");
2904
+ engine.checkVersion("4.5.0");
2825
2905
  await engine.pluginManager.register(e => {
2826
2906
  e.pluginManager.addParticleUpdater("opacity", container => {
2827
2907
  return Promise.resolve(new OpacityUpdater(container));
@@ -2830,70 +2910,60 @@
2830
2910
  }
2831
2911
 
2832
2912
  const boundsMin = 0;
2833
- function bounceHorizontal(data) {
2834
- if ((data.outMode !== exports.OutMode.bounce && data.outMode !== exports.OutMode.split) ||
2835
- (data.direction !== exports.OutModeDirection.left && data.direction !== exports.OutModeDirection.right)) {
2836
- return;
2837
- }
2838
- if (data.bounds.right < boundsMin && data.direction === exports.OutModeDirection.left) {
2839
- data.particle.position.x = data.size + data.offset.x;
2840
- }
2841
- else if (data.bounds.left > data.canvasSize.width && data.direction === exports.OutModeDirection.right) {
2842
- data.particle.position.x = data.canvasSize.width - data.size - data.offset.x;
2843
- }
2844
- const velocity = data.particle.velocity.x;
2845
- let bounced = false;
2846
- if (data.outOfCanvas &&
2847
- ((data.direction === exports.OutModeDirection.right && velocity > minVelocity) ||
2848
- (data.direction === exports.OutModeDirection.left && velocity < minVelocity))) {
2849
- const newVelocity = getRangeValue(data.particle.options.bounce.horizontal.value);
2850
- data.particle.velocity.x *= -newVelocity;
2851
- bounced = true;
2852
- }
2853
- if (!bounced) {
2854
- return;
2855
- }
2856
- const minPos = data.offset.x + data.size;
2857
- if (data.outOfCanvas && data.direction === exports.OutModeDirection.right) {
2858
- data.particle.position.x = data.canvasSize.width - minPos;
2859
- }
2860
- else if (data.outOfCanvas && data.direction === exports.OutModeDirection.left) {
2861
- data.particle.position.x = minPos;
2862
- }
2863
- if (data.outMode === exports.OutMode.split) {
2864
- data.particle.destroy();
2865
- }
2866
- }
2867
- function bounceVertical(data) {
2868
- if ((data.outMode !== exports.OutMode.bounce && data.outMode !== exports.OutMode.split) ||
2869
- (data.direction !== exports.OutModeDirection.bottom && data.direction !== exports.OutModeDirection.top)) {
2913
+ const bounceAxisConfigs = {
2914
+ [exports.OutModeDirection.left]: {
2915
+ axis: "x",
2916
+ canvas: "width",
2917
+ bounce: "horizontal",
2918
+ negativeEdge: "right",
2919
+ positiveEdge: "left",
2920
+ negative: true,
2921
+ },
2922
+ [exports.OutModeDirection.right]: {
2923
+ axis: "x",
2924
+ canvas: "width",
2925
+ bounce: "horizontal",
2926
+ negativeEdge: "right",
2927
+ positiveEdge: "left",
2928
+ negative: false,
2929
+ },
2930
+ [exports.OutModeDirection.top]: {
2931
+ axis: "y",
2932
+ canvas: "height",
2933
+ bounce: "vertical",
2934
+ negativeEdge: "bottom",
2935
+ positiveEdge: "top",
2936
+ negative: true,
2937
+ },
2938
+ [exports.OutModeDirection.bottom]: {
2939
+ axis: "y",
2940
+ canvas: "height",
2941
+ bounce: "vertical",
2942
+ negativeEdge: "bottom",
2943
+ positiveEdge: "top",
2944
+ negative: false,
2945
+ },
2946
+ };
2947
+ function bounce$1(data) {
2948
+ if ((data.outMode !== exports.OutMode.bounce && data.outMode !== exports.OutMode.split) || !(data.direction in bounceAxisConfigs)) {
2870
2949
  return;
2871
2950
  }
2872
- if (data.bounds.bottom < boundsMin && data.direction === exports.OutModeDirection.top) {
2873
- data.particle.position.y = data.size + data.offset.y;
2951
+ const config = bounceAxisConfigs[data.direction], bounds = data.bounds, canvasDim = data.canvasSize[config.canvas], position = data.particle.position, velocity = data.particle.velocity[config.axis];
2952
+ if (config.negative && bounds[config.negativeEdge] < boundsMin) {
2953
+ position[config.axis] = data.size + data.offset[config.axis];
2874
2954
  }
2875
- else if (data.bounds.top > data.canvasSize.height && data.direction === exports.OutModeDirection.bottom) {
2876
- data.particle.position.y = data.canvasSize.height - data.size - data.offset.y;
2955
+ else if (!config.negative && bounds[config.positiveEdge] > canvasDim) {
2956
+ position[config.axis] = canvasDim - data.size - data.offset[config.axis];
2877
2957
  }
2878
- const velocity = data.particle.velocity.y;
2879
- let bounced = false;
2880
2958
  if (data.outOfCanvas &&
2881
- ((data.direction === exports.OutModeDirection.bottom && velocity > minVelocity) ||
2882
- (data.direction === exports.OutModeDirection.top && velocity < minVelocity))) {
2883
- const newVelocity = getRangeValue(data.particle.options.bounce.vertical.value);
2884
- data.particle.velocity.y *= -newVelocity;
2885
- bounced = true;
2959
+ ((config.negative && velocity < minVelocity) || (!config.negative && velocity > minVelocity))) {
2960
+ data.particle.velocity[config.axis] *= -getRangeValue(data.particle.options.bounce[config.bounce].value);
2886
2961
  }
2887
- if (!bounced) {
2962
+ else {
2888
2963
  return;
2889
2964
  }
2890
- const minPos = data.offset.y + data.size;
2891
- if (data.outOfCanvas && data.direction === exports.OutModeDirection.bottom) {
2892
- data.particle.position.y = data.canvasSize.height - minPos;
2893
- }
2894
- else if (data.outOfCanvas && data.direction === exports.OutModeDirection.top) {
2895
- data.particle.position.y = minPos;
2896
- }
2965
+ const minPos = data.offset[config.axis] + data.size;
2966
+ position[config.axis] = config.negative ? minPos : canvasDim - minPos;
2897
2967
  if (data.outMode === exports.OutMode.split) {
2898
2968
  data.particle.destroy();
2899
2969
  }
@@ -2909,26 +2979,19 @@
2909
2979
  exports.OutMode.bounce,
2910
2980
  exports.OutMode.split,
2911
2981
  ];
2912
- this.#particleBouncePlugins = container.plugins.filter(p => p.particleBounce !== undefined);
2982
+ this.#particleBouncePlugins = container.plugins.filter(p => !!p.particleBounce);
2913
2983
  }
2914
2984
  update(particle, direction, delta, outMode) {
2915
2985
  if (!this.modes.includes(outMode)) {
2916
2986
  return;
2917
2987
  }
2918
- const container = this.#container;
2919
- let handled = false;
2920
2988
  for (const plugin of this.#particleBouncePlugins) {
2921
- handled = plugin.particleBounce?.(particle, delta, direction) ?? false;
2922
- if (handled) {
2923
- break;
2989
+ if (plugin.particleBounce?.(particle, delta, direction)) {
2990
+ return;
2924
2991
  }
2925
2992
  }
2926
- if (handled) {
2927
- return;
2928
- }
2929
- const pos = particle.getPosition(), offset = particle.offset, size = particle.getRadius(), bounds = calculateBounds(pos, size), canvasSize = container.canvas.size, outOfCanvas = !particle.isInsideCanvasForOutMode(outMode, direction);
2930
- bounceHorizontal({ particle, outMode, direction, bounds, canvasSize, offset, outOfCanvas, size });
2931
- bounceVertical({ particle, outMode, direction, bounds, canvasSize, offset, outOfCanvas, size });
2993
+ const pos = particle.getPosition(), offset = particle.offset, size = particle.getRadius(), bounds = calculateBounds(pos, size), canvasSize = this.#container.canvas.size, outOfCanvas = !particle.isInsideCanvasForOutMode(outMode, direction);
2994
+ bounce$1({ particle, outMode, direction, bounds, canvasSize, offset, outOfCanvas, size });
2932
2995
  }
2933
2996
  }
2934
2997
 
@@ -3017,107 +3080,108 @@
3017
3080
  return;
3018
3081
  }
3019
3082
  const container = this.#container;
3020
- switch (particle.outType) {
3021
- case exports.ParticleOutType.inside: {
3022
- const { x: vx, y: vy } = particle.velocity;
3023
- updateVector.setTo(originPoint);
3024
- updateVector.length = particle.moveCenter.radius;
3025
- updateVector.angle = particle.velocity.angle + Math.PI;
3026
- updateVector.addTo(particle.moveCenter);
3027
- const { dx, dy } = getDistances(particle.position, updateVector);
3028
- if ((vx <= minVelocity && dx >= minDistance$2) ||
3029
- (vy <= minVelocity && dy >= minDistance$2) ||
3030
- (vx >= minVelocity && dx <= minDistance$2) ||
3031
- (vy >= minVelocity && dy <= minDistance$2)) {
3032
- return;
3033
- }
3034
- particle.position.x = Math.floor(randomInRangeValue({
3035
- min: 0,
3036
- max: container.canvas.size.width,
3037
- }));
3038
- particle.position.y = Math.floor(randomInRangeValue({
3039
- min: 0,
3040
- max: container.canvas.size.height,
3041
- }));
3042
- const { dx: newDx, dy: newDy } = getDistances(particle.position, particle.moveCenter);
3043
- particle.direction = Math.atan2(-newDy, -newDx);
3044
- particle.velocity.angle = particle.direction;
3045
- particle.justWarped = true;
3046
- break;
3083
+ if (particle.outType === exports.ParticleOutType.inside) {
3084
+ this.#applyOutModeInside(particle, container);
3085
+ }
3086
+ else {
3087
+ if (particle.isInsideCanvasForOutMode(outMode, direction)) {
3088
+ return;
3047
3089
  }
3048
- default: {
3049
- if (particle.isInsideCanvasForOutMode(outMode, direction)) {
3050
- return;
3051
- }
3052
- switch (particle.outType) {
3053
- case exports.ParticleOutType.outside: {
3054
- particle.position.x =
3055
- Math.floor(randomInRangeValue({
3056
- min: -particle.moveCenter.radius,
3057
- max: particle.moveCenter.radius,
3058
- })) + particle.moveCenter.x;
3059
- particle.position.y =
3060
- Math.floor(randomInRangeValue({
3061
- min: -particle.moveCenter.radius,
3062
- max: particle.moveCenter.radius,
3063
- })) + particle.moveCenter.y;
3064
- const { dx, dy } = getDistances(particle.position, particle.moveCenter);
3065
- if (particle.moveCenter.radius) {
3066
- particle.direction = Math.atan2(dy, dx);
3067
- particle.velocity.angle = particle.direction;
3068
- }
3069
- particle.justWarped = true;
3070
- break;
3071
- }
3072
- case exports.ParticleOutType.normal: {
3073
- const warp = particle.options.move.warp, canvasSize = container.canvas.size, newPos = {
3074
- bottom: canvasSize.height + particle.getRadius() + particle.offset.y,
3075
- left: -particle.getRadius() - particle.offset.x,
3076
- right: canvasSize.width + particle.getRadius() + particle.offset.x,
3077
- top: -particle.getRadius() - particle.offset.y,
3078
- }, sizeValue = particle.getRadius(), nextBounds = calculateBounds(particle.position, sizeValue);
3079
- if (direction === exports.OutModeDirection.right && nextBounds.left > canvasSize.width + particle.offset.x) {
3080
- particle.position.x = newPos.left;
3081
- particle.initialPosition.x = particle.position.x;
3082
- if (!warp) {
3083
- particle.position.y = getRandom() * canvasSize.height;
3084
- particle.initialPosition.y = particle.position.y;
3085
- }
3086
- particle.justWarped = true;
3087
- }
3088
- else if (direction === exports.OutModeDirection.left && nextBounds.right < -particle.offset.x) {
3089
- particle.position.x = newPos.right;
3090
- particle.initialPosition.x = particle.position.x;
3091
- if (!warp) {
3092
- particle.position.y = getRandom() * canvasSize.height;
3093
- particle.initialPosition.y = particle.position.y;
3094
- }
3095
- particle.justWarped = true;
3096
- }
3097
- if (direction === exports.OutModeDirection.bottom && nextBounds.top > canvasSize.height + particle.offset.y) {
3098
- if (!warp) {
3099
- particle.position.x = getRandom() * canvasSize.width;
3100
- particle.initialPosition.x = particle.position.x;
3101
- }
3102
- particle.position.y = newPos.top;
3103
- particle.initialPosition.y = particle.position.y;
3104
- particle.justWarped = true;
3105
- }
3106
- else if (direction === exports.OutModeDirection.top && nextBounds.bottom < -particle.offset.y) {
3107
- if (!warp) {
3108
- particle.position.x = getRandom() * canvasSize.width;
3109
- particle.initialPosition.x = particle.position.x;
3110
- }
3111
- particle.position.y = newPos.bottom;
3112
- particle.initialPosition.y = particle.position.y;
3113
- particle.justWarped = true;
3114
- }
3115
- break;
3116
- }
3117
- }
3118
- break;
3090
+ if (particle.outType === exports.ParticleOutType.outside) {
3091
+ this.#applyParticleModeOutside(particle);
3119
3092
  }
3120
- }
3093
+ else {
3094
+ this.#applyOutModeNormal(particle, container, direction);
3095
+ }
3096
+ }
3097
+ }
3098
+ #applyOutModeInside(particle, container) {
3099
+ const { x: vx, y: vy } = particle.velocity;
3100
+ updateVector.setTo(originPoint);
3101
+ updateVector.length = particle.moveCenter.radius;
3102
+ updateVector.angle = particle.velocity.angle + Math.PI;
3103
+ updateVector.addTo(particle.moveCenter);
3104
+ const { dx, dy } = getDistances(particle.position, updateVector);
3105
+ if ((vx <= minVelocity && dx >= minDistance$2) ||
3106
+ (vy <= minVelocity && dy >= minDistance$2) ||
3107
+ (vx >= minVelocity && dx <= minDistance$2) ||
3108
+ (vy >= minVelocity && dy <= minDistance$2)) {
3109
+ return;
3110
+ }
3111
+ particle.position.x = Math.floor(randomInRangeValue({
3112
+ min: 0,
3113
+ max: container.canvas.size.width,
3114
+ }));
3115
+ particle.position.y = Math.floor(randomInRangeValue({
3116
+ min: 0,
3117
+ max: container.canvas.size.height,
3118
+ }));
3119
+ const { dx: newDx, dy: newDy } = getDistances(particle.position, particle.moveCenter);
3120
+ particle.direction = Math.atan2(-newDy, -newDx);
3121
+ particle.velocity.angle = particle.direction;
3122
+ particle.justWarped = true;
3123
+ }
3124
+ #applyOutModeNormal(particle, container, direction) {
3125
+ const warp = particle.options.move.warp, canvasSize = container.canvas.size, sizeValue = particle.getRadius(), newPos = {
3126
+ bottom: canvasSize.height + sizeValue + particle.offset.y,
3127
+ left: -sizeValue - particle.offset.x,
3128
+ right: canvasSize.width + sizeValue + particle.offset.x,
3129
+ top: -sizeValue - particle.offset.y,
3130
+ }, nextBounds = calculateBounds(particle.position, sizeValue);
3131
+ if (direction === exports.OutModeDirection.right && nextBounds.left > canvasSize.width + particle.offset.x) {
3132
+ particle.position.x = newPos.left;
3133
+ particle.initialPosition.x = particle.position.x;
3134
+ if (!warp) {
3135
+ particle.position.y = getRandom() * canvasSize.height;
3136
+ particle.initialPosition.y = particle.position.y;
3137
+ }
3138
+ particle.justWarped = true;
3139
+ }
3140
+ else if (direction === exports.OutModeDirection.left && nextBounds.right < -particle.offset.x) {
3141
+ particle.position.x = newPos.right;
3142
+ particle.initialPosition.x = particle.position.x;
3143
+ if (!warp) {
3144
+ particle.position.y = getRandom() * canvasSize.height;
3145
+ particle.initialPosition.y = particle.position.y;
3146
+ }
3147
+ particle.justWarped = true;
3148
+ }
3149
+ if (direction === exports.OutModeDirection.bottom && nextBounds.top > canvasSize.height + particle.offset.y) {
3150
+ if (!warp) {
3151
+ particle.position.x = getRandom() * canvasSize.width;
3152
+ particle.initialPosition.x = particle.position.x;
3153
+ }
3154
+ particle.position.y = newPos.top;
3155
+ particle.initialPosition.y = particle.position.y;
3156
+ particle.justWarped = true;
3157
+ }
3158
+ else if (direction === exports.OutModeDirection.top && nextBounds.bottom < -particle.offset.y) {
3159
+ if (!warp) {
3160
+ particle.position.x = getRandom() * canvasSize.width;
3161
+ particle.initialPosition.x = particle.position.x;
3162
+ }
3163
+ particle.position.y = newPos.bottom;
3164
+ particle.initialPosition.y = particle.position.y;
3165
+ particle.justWarped = true;
3166
+ }
3167
+ }
3168
+ #applyParticleModeOutside(particle) {
3169
+ particle.position.x =
3170
+ Math.floor(randomInRangeValue({
3171
+ min: -particle.moveCenter.radius,
3172
+ max: particle.moveCenter.radius,
3173
+ })) + particle.moveCenter.x;
3174
+ particle.position.y =
3175
+ Math.floor(randomInRangeValue({
3176
+ min: -particle.moveCenter.radius,
3177
+ max: particle.moveCenter.radius,
3178
+ })) + particle.moveCenter.y;
3179
+ const { dx, dy } = getDistances(particle.position, particle.moveCenter);
3180
+ if (particle.moveCenter.radius) {
3181
+ particle.direction = Math.atan2(dy, dx);
3182
+ particle.velocity.angle = particle.direction;
3183
+ }
3184
+ particle.justWarped = true;
3121
3185
  }
3122
3186
  }
3123
3187
 
@@ -3166,7 +3230,7 @@
3166
3230
  }
3167
3231
 
3168
3232
  async function loadOutModesUpdater(engine) {
3169
- engine.checkVersion("4.4.0");
3233
+ engine.checkVersion("4.5.0");
3170
3234
  await engine.pluginManager.register(e => {
3171
3235
  e.pluginManager.addParticleUpdater("outModes", container => {
3172
3236
  return Promise.resolve(new OutOfCanvasUpdater(container));
@@ -3183,39 +3247,9 @@
3183
3247
  this.#pluginManager = pluginManager;
3184
3248
  }
3185
3249
  init(particle) {
3186
- 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;
3187
- if (fill) {
3188
- const fillColor = AnimatableColor.create(paintColor === undefined ? undefined : AnimatableColor.create(undefined, paintColor), fill.color);
3189
- particle.fillEnabled = fill.enable;
3190
- particle.fillOpacity = getRangeValue(fill.opacity);
3191
- particle.fillAnimation = fillColor.animation;
3192
- const fillHslColor = rangeColorToHsl(this.#pluginManager, fillColor);
3193
- if (fillHslColor) {
3194
- particle.fillColor = getHslAnimationFromHsl(fillHslColor, particle.fillAnimation, container.retina.reduceFactor);
3195
- }
3196
- }
3197
- else {
3198
- particle.fillEnabled = false;
3199
- particle.fillAnimation = undefined;
3200
- particle.fillColor = undefined;
3201
- particle.fillOpacity = defaultOpacity;
3202
- }
3203
- if (stroke) {
3204
- const strokeColor = AnimatableColor.create(paintColor === undefined ? undefined : AnimatableColor.create(undefined, paintColor), stroke.color);
3205
- particle.strokeWidth = getRangeValue(stroke.width) * container.retina.pixelRatio;
3206
- particle.strokeOpacity = getRangeValue(stroke.opacity ?? defaultOpacity);
3207
- particle.strokeAnimation = strokeColor.animation;
3208
- const strokeHslColor = rangeColorToHsl(this.#pluginManager, strokeColor) ?? particle.getFillColor();
3209
- if (strokeHslColor) {
3210
- particle.strokeColor = getHslAnimationFromHsl(strokeHslColor, particle.strokeAnimation, container.retina.reduceFactor);
3211
- }
3212
- }
3213
- else {
3214
- particle.strokeAnimation = undefined;
3215
- particle.strokeColor = undefined;
3216
- particle.strokeOpacity = defaultOpacity;
3217
- particle.strokeWidth = 0;
3218
- }
3250
+ const container = this.#container, options = particle.options, paint = itemFromSingleOrMultiple(options.paint, particle.id, options.reduceDuplicates);
3251
+ this.#initFill(paint, particle, container);
3252
+ this.#initStroke(paint, particle, container);
3219
3253
  }
3220
3254
  isEnabled(particle) {
3221
3255
  const { fillAnimation, fillColor, strokeAnimation, strokeColor } = particle, fillEnabled = !!fillAnimation &&
@@ -3234,10 +3268,48 @@
3234
3268
  updateColor(particle.fillColor, delta, this.#container.hdr);
3235
3269
  updateColor(particle.strokeColor, delta, this.#container.hdr);
3236
3270
  }
3271
+ #initFill(paint, particle, container) {
3272
+ const fill = paint?.fill, color = paint?.color, paintColor = color ?? undefined;
3273
+ if (!fill) {
3274
+ particle.fillEnabled = false;
3275
+ particle.fillAnimation = undefined;
3276
+ particle.fillColor = undefined;
3277
+ particle.fillOpacity = defaultOpacity;
3278
+ return;
3279
+ }
3280
+ const fillColor = AnimatableColor.create(paintColor === undefined ? undefined : AnimatableColor.create(undefined, paintColor), fill.color);
3281
+ particle.fillEnabled = fill.enable;
3282
+ particle.fillOpacity = getRangeValue(fill.opacity);
3283
+ particle.fillAnimation = fillColor.animation;
3284
+ const fillHslColor = rangeColorToHsl(this.#pluginManager, fillColor);
3285
+ if (!fillHslColor) {
3286
+ return;
3287
+ }
3288
+ particle.fillColor = getHslAnimationFromHsl(fillHslColor, particle.fillAnimation, container.retina.reduceFactor);
3289
+ }
3290
+ #initStroke(paint, particle, container) {
3291
+ const stroke = paint?.stroke, color = paint?.color, paintColor = color ?? undefined;
3292
+ if (!stroke) {
3293
+ particle.strokeAnimation = undefined;
3294
+ particle.strokeColor = undefined;
3295
+ particle.strokeOpacity = defaultOpacity;
3296
+ particle.strokeWidth = 0;
3297
+ return;
3298
+ }
3299
+ const strokeColor = AnimatableColor.create(paintColor === undefined ? undefined : AnimatableColor.create(undefined, paintColor), stroke.color);
3300
+ particle.strokeWidth = getRangeValue(stroke.width) * container.retina.pixelRatio;
3301
+ particle.strokeOpacity = getRangeValue(stroke.opacity ?? defaultOpacity);
3302
+ particle.strokeAnimation = strokeColor.animation;
3303
+ const strokeHslColor = rangeColorToHsl(this.#pluginManager, strokeColor) ?? particle.getFillColor();
3304
+ if (!strokeHslColor) {
3305
+ return;
3306
+ }
3307
+ particle.strokeColor = getHslAnimationFromHsl(strokeHslColor, particle.strokeAnimation, container.retina.reduceFactor);
3308
+ }
3237
3309
  }
3238
3310
 
3239
3311
  async function loadPaintUpdater(engine) {
3240
- engine.checkVersion("4.4.0");
3312
+ engine.checkVersion("4.5.0");
3241
3313
  await engine.pluginManager.register(e => {
3242
3314
  e.pluginManager.addParticleUpdater("paint", container => {
3243
3315
  return Promise.resolve(new PaintUpdater(e.pluginManager, container));
@@ -3279,7 +3351,7 @@
3279
3351
  if (!this.accepts(input)) {
3280
3352
  return;
3281
3353
  }
3282
- const result = rgbRegex.exec(input), radix = 10, minLength = 4, defaultAlpha = 1;
3354
+ const result = rgbRegex.exec(input), radix = 10, minLength = 4;
3283
3355
  return result
3284
3356
  ? {
3285
3357
  a: result.length > minLength ? parseAlpha(result[RgbIndexes.a]) : defaultAlpha,
@@ -3292,7 +3364,7 @@
3292
3364
  }
3293
3365
 
3294
3366
  async function loadRgbColorPlugin(engine) {
3295
- engine.checkVersion("4.4.0");
3367
+ engine.checkVersion("4.5.0");
3296
3368
  await engine.pluginManager.register(e => {
3297
3369
  e.pluginManager.addColorManager("rgb", new RgbColorManager());
3298
3370
  });
@@ -3377,7 +3449,7 @@
3377
3449
  }
3378
3450
 
3379
3451
  async function loadSizeUpdater(engine) {
3380
- engine.checkVersion("4.4.0");
3452
+ engine.checkVersion("4.5.0");
3381
3453
  await engine.pluginManager.register(e => {
3382
3454
  e.pluginManager.addParticleUpdater("size", container => {
3383
3455
  return Promise.resolve(new SizeUpdater(container));
@@ -3386,7 +3458,7 @@
3386
3458
  }
3387
3459
 
3388
3460
  async function loadBasic(engine) {
3389
- engine.checkVersion("4.4.0");
3461
+ engine.checkVersion("4.5.0");
3390
3462
  await engine.pluginManager.register(async (e) => {
3391
3463
  await Promise.all([
3392
3464
  loadBlendPlugin(e),
@@ -3403,6 +3475,16 @@
3403
3475
  });
3404
3476
  }
3405
3477
 
3478
+ const ErrorCodes$1 = {
3479
+ interactivityPluginNotLoaded: "TSP-3201",
3480
+ interactivityClickHandlerNotSet: "TSP-3202",
3481
+ };
3482
+
3483
+ const ErrorMessages$1 = {
3484
+ [ErrorCodes$1.interactivityPluginNotLoaded]: "tsParticles Interactivity Plugin is not loaded",
3485
+ [ErrorCodes$1.interactivityClickHandlerNotSet]: "Click handlers can only be set after calling tsParticles.load()",
3486
+ };
3487
+
3406
3488
  class ClickEvent {
3407
3489
  enable = false;
3408
3490
  mode = [];
@@ -3479,9 +3561,7 @@
3479
3561
 
3480
3562
  class Modes {
3481
3563
  #container;
3482
- #pluginManager;
3483
- constructor(pluginManager, container) {
3484
- this.#pluginManager = pluginManager;
3564
+ constructor(container) {
3485
3565
  this.#container = container;
3486
3566
  }
3487
3567
  load(data) {
@@ -3491,10 +3571,7 @@
3491
3571
  if (!this.#container) {
3492
3572
  return;
3493
3573
  }
3494
- const interactors = this.#pluginManager.interactors?.get(this.#container);
3495
- if (!interactors) {
3496
- return;
3497
- }
3574
+ const interactors = this.#container.interactionManager?.interactors ?? [];
3498
3575
  for (const interactor of interactors) {
3499
3576
  if (!interactor.loadModeOptions) {
3500
3577
  continue;
@@ -3508,8 +3585,8 @@
3508
3585
  detectsOn = InteractivityDetect.window;
3509
3586
  events = new Events();
3510
3587
  modes;
3511
- constructor(pluginManager, container) {
3512
- this.modes = new Modes(pluginManager, container);
3588
+ constructor(container) {
3589
+ this.modes = new Modes(container);
3513
3590
  }
3514
3591
  load(data) {
3515
3592
  if (isNull(data)) {
@@ -3540,10 +3617,10 @@
3540
3617
  }
3541
3618
  let interactivityOptions = options.interactivity;
3542
3619
  if (!interactivityOptions?.load) {
3543
- options.interactivity = interactivityOptions = new Interactivity(this.#pluginManager, container);
3620
+ options.interactivity = interactivityOptions = new Interactivity(container);
3544
3621
  }
3545
3622
  interactivityOptions.load(source?.interactivity);
3546
- const interactors = this.#pluginManager.interactors?.get(container);
3623
+ const interactors = container.interactionManager?.interactors;
3547
3624
  if (!interactors) {
3548
3625
  return;
3549
3626
  }
@@ -3557,7 +3634,7 @@
3557
3634
  if (source?.interactivity) {
3558
3635
  options.interactivity = deepExtend({}, source.interactivity);
3559
3636
  }
3560
- const interactors = this.#pluginManager.interactors?.get(container);
3637
+ const interactors = container.interactionManager?.interactors;
3561
3638
  if (!interactors) {
3562
3639
  return;
3563
3640
  }
@@ -3587,25 +3664,25 @@
3587
3664
  const clickEvent = "click", mouseDownEvent = "pointerdown", mouseUpEvent = "pointerup", mouseLeaveEvent = "pointerleave", mouseMoveEvent = "pointermove", touchStartEvent = "touchstart", touchEndEvent = "touchend", touchMoveEvent = "touchmove", touchCancelEvent = "touchcancel";
3588
3665
 
3589
3666
  async function loadInteractivityPlugin(engine) {
3590
- engine.checkVersion("4.4.0");
3667
+ engine.checkVersion("4.5.0");
3668
+ if (typeof process !== "undefined" && process.env.NODE_ENV !== "production") {
3669
+ addErrorMessages(ErrorMessages$1);
3670
+ }
3591
3671
  await engine.pluginManager.register(e => {
3592
3672
  const interactivityEngine = e, interactivityPluginManager = interactivityEngine.pluginManager;
3593
3673
  interactivityPluginManager.addPlugin(new InteractivityPlugin(interactivityPluginManager));
3594
3674
  interactivityPluginManager.initializers.interactors ??= new Map();
3595
- interactivityPluginManager.interactors ??= new Map();
3596
3675
  interactivityPluginManager.addInteractor = (name, interactorInitializer) => {
3676
+ if (interactivityPluginManager.initialized) {
3677
+ return;
3678
+ }
3597
3679
  interactivityPluginManager.initializers.interactors ??= new Map();
3598
3680
  interactivityPluginManager.initializers.interactors.set(name, interactorInitializer);
3599
3681
  };
3600
- interactivityPluginManager.getInteractors = async (container, force = false) => {
3601
- interactivityPluginManager.interactors ??= new Map();
3602
- interactivityPluginManager.initializers.interactors ??= new Map();
3603
- return getItemsFromInitializer(container, interactivityPluginManager.interactors, interactivityPluginManager.initializers.interactors, force);
3604
- };
3605
3682
  interactivityPluginManager.setOnClickHandler = (callback) => {
3606
3683
  const { items } = interactivityEngine;
3607
3684
  if (!items.length) {
3608
- throw new Error("Click handlers can only be set after calling tsParticles.load()");
3685
+ throw new Error(getErrorMessage(ErrorCodes$1.interactivityClickHandlerNotSet));
3609
3686
  }
3610
3687
  items.forEach(item => {
3611
3688
  const interactivityContainer = item;
@@ -3616,7 +3693,7 @@
3616
3693
  }
3617
3694
  function ensureInteractivityPluginLoaded(e) {
3618
3695
  if (!e.pluginManager.addInteractor) {
3619
- throw new Error("tsParticles Interactivity Plugin is not loaded");
3696
+ throw new Error(getErrorMessage(ErrorCodes$1.interactivityPluginNotLoaded));
3620
3697
  }
3621
3698
  }
3622
3699
 
@@ -3625,6 +3702,7 @@
3625
3702
  CollisionMode["absorb"] = "absorb";
3626
3703
  CollisionMode["bounce"] = "bounce";
3627
3704
  CollisionMode["destroy"] = "destroy";
3705
+ CollisionMode["fluid"] = "fluid";
3628
3706
  })(CollisionMode || (CollisionMode = {}));
3629
3707
 
3630
3708
  class CollisionsAbsorb {
@@ -3637,6 +3715,26 @@
3637
3715
  }
3638
3716
  }
3639
3717
 
3718
+ class CollisionsFluid {
3719
+ maxForce = 2.5;
3720
+ maxNeighbors = 64;
3721
+ nearStiffness = 0.5;
3722
+ radius = 30;
3723
+ restDensity = 3;
3724
+ stiffness = 0.5;
3725
+ load(data) {
3726
+ if (isNull(data)) {
3727
+ return;
3728
+ }
3729
+ loadRangeProperty(this, "maxForce", data.maxForce);
3730
+ loadProperty(this, "maxNeighbors", data.maxNeighbors);
3731
+ loadRangeProperty(this, "nearStiffness", data.nearStiffness);
3732
+ loadRangeProperty(this, "radius", data.radius);
3733
+ loadRangeProperty(this, "restDensity", data.restDensity);
3734
+ loadRangeProperty(this, "stiffness", data.stiffness);
3735
+ }
3736
+ }
3737
+
3640
3738
  class CollisionsOverlap {
3641
3739
  enable = true;
3642
3740
  retries = 0;
@@ -3653,6 +3751,7 @@
3653
3751
  absorb = new CollisionsAbsorb();
3654
3752
  bounce = new ParticlesBounce();
3655
3753
  enable = false;
3754
+ fluid = new CollisionsFluid();
3656
3755
  maxSpeed = 50;
3657
3756
  mode = CollisionMode.bounce;
3658
3757
  overlap = new CollisionsOverlap();
@@ -3663,12 +3762,181 @@
3663
3762
  this.absorb.load(data.absorb);
3664
3763
  this.bounce.load(data.bounce);
3665
3764
  loadProperty(this, "enable", data.enable);
3765
+ this.fluid.load(data.fluid);
3666
3766
  loadRangeProperty(this, "maxSpeed", data.maxSpeed);
3667
3767
  loadProperty(this, "mode", data.mode);
3668
3768
  this.overlap.load(data.overlap);
3669
3769
  }
3670
3770
  }
3671
3771
 
3772
+ const wallMarginFactor = 0.15, restRetention = 0.1, supportContacts = 5, wallSpringFactor = half, minNeighborDistance = 0.0001, solverIterations = 3, separationIterations = 3;
3773
+ function applyWallSpring(position, margin, maxX, maxY) {
3774
+ if (position.x < margin) {
3775
+ position.x += (margin - position.x) * wallSpringFactor;
3776
+ }
3777
+ else if (position.x > maxX) {
3778
+ position.x -= (position.x - maxX) * wallSpringFactor;
3779
+ }
3780
+ if (position.y < margin) {
3781
+ position.y += (margin - position.y) * wallSpringFactor;
3782
+ }
3783
+ else if (position.y > maxY) {
3784
+ position.y -= (position.y - maxY) * wallSpringFactor;
3785
+ }
3786
+ }
3787
+ function clampToWalls(position, margin, maxX, maxY) {
3788
+ if (position.x < margin) {
3789
+ position.x = margin;
3790
+ }
3791
+ else if (position.x > maxX) {
3792
+ position.x = maxX;
3793
+ }
3794
+ if (position.y < margin) {
3795
+ position.y = margin;
3796
+ }
3797
+ else if (position.y > maxY) {
3798
+ position.y = maxY;
3799
+ }
3800
+ }
3801
+ class FluidSolver {
3802
+ #dir = Vector.origin;
3803
+ #isNeighbor;
3804
+ #maxNeighbors = minCount;
3805
+ #neighbors = [];
3806
+ #owner;
3807
+ #ownerZ = defaultAngle;
3808
+ constructor() {
3809
+ this.#isNeighbor = (particle) => {
3810
+ const owner = this.#owner, neighbor = particle;
3811
+ if (!owner ||
3812
+ this.#neighbors.length >= this.#maxNeighbors ||
3813
+ neighbor === owner ||
3814
+ neighbor.destroyed ||
3815
+ neighbor.spawning ||
3816
+ !neighbor.options.collisions?.enable ||
3817
+ neighbor.options.collisions.mode !== CollisionMode.fluid) {
3818
+ return false;
3819
+ }
3820
+ const ownerRadius = owner.getRadius();
3821
+ return (Math.abs(Math.round(this.#ownerZ) - Math.round(neighbor.getPosition().z)) <= ownerRadius + neighbor.getRadius());
3822
+ };
3823
+ }
3824
+ separateOverlaps(particle, position) {
3825
+ const neighbors = this.#neighbors, particlePosition = particle.position;
3826
+ particlePosition.setTo(position);
3827
+ for (let iteration = 0; iteration < separationIterations; iteration++) {
3828
+ for (const neighbor of neighbors) {
3829
+ this.#projectPair(particle, neighbor);
3830
+ }
3831
+ }
3832
+ }
3833
+ solve(container, particle) {
3834
+ const collisionsOptions = particle.options.collisions;
3835
+ if (!collisionsOptions) {
3836
+ return;
3837
+ }
3838
+ const fluidOptions = collisionsOptions.fluid, pixelRatio = container.retina.pixelRatio, radius = getRangeValue(fluidOptions.radius) * pixelRatio, stiffness = getRangeValue(fluidOptions.stiffness), nearStiffness = getRangeValue(fluidOptions.nearStiffness), restDensity = getRangeValue(fluidOptions.restDensity), maxForce = getRangeValue(fluidOptions.maxForce), maxNeighbors = fluidOptions.maxNeighbors, particleRadius = particle.getRadius(), position = particle.position, canvasSize = container.canvas.size, hasBounds = canvasSize.width > minRadius && canvasSize.height > minRadius, margin = hasBounds ? particleRadius * wallMarginFactor : minRadius, maxX = canvasSize.width - margin, maxY = canvasSize.height - margin, neighbors = this.#neighbors;
3839
+ this.#owner = particle;
3840
+ this.#maxNeighbors = maxNeighbors;
3841
+ this.#ownerZ = particle.getPosition().z;
3842
+ this.#queryNeighbors(container, particle, radius, maxNeighbors);
3843
+ for (let iteration = 0; iteration < solverIterations; iteration++) {
3844
+ const focalPosition = particle.getPosition();
3845
+ let density = 0, densityNear = 0;
3846
+ for (const neighbor of neighbors) {
3847
+ const dist = getDistance(focalPosition, neighbor.getPosition()), q = identity - dist / radius, q2 = q * q;
3848
+ density += q2;
3849
+ densityNear += q2 * q;
3850
+ }
3851
+ const pressure = (density - restDensity) * stiffness * half, pressureNear = densityNear * nearStiffness * half;
3852
+ if (hasBounds) {
3853
+ applyWallSpring(position, margin, maxX, maxY);
3854
+ }
3855
+ for (const neighbor of neighbors) {
3856
+ const neighborPosition = neighbor.getPosition(), dx = neighborPosition.x - focalPosition.x, dy = neighborPosition.y - focalPosition.y, dist = Math.sqrt(dx * dx + dy * dy);
3857
+ if (dist > radius) {
3858
+ continue;
3859
+ }
3860
+ const q = identity - dist / radius, force = clamp(pressure + pressureNear * q, -maxForce, maxForce), contactDistance = particleRadius + neighbor.getRadius(), push = Math.max(q * force * half, contactDistance - dist);
3861
+ if (dist > minNeighborDistance) {
3862
+ const inverseDist = inverseFactorNumerator / dist;
3863
+ this.#dir.x = dx * inverseDist * push;
3864
+ this.#dir.y = dy * inverseDist * push;
3865
+ }
3866
+ else {
3867
+ this.#dir.x = (particle.id + neighbor.id) % double === minCount ? identity : -identity;
3868
+ this.#dir.y = defaultAngle;
3869
+ this.#dir.multTo(push);
3870
+ }
3871
+ position.x -= this.#dir.x;
3872
+ position.y -= this.#dir.y;
3873
+ }
3874
+ }
3875
+ this.#queryNeighbors(container, particle, radius, maxNeighbors);
3876
+ if (hasBounds) {
3877
+ clampToWalls(position, margin, maxX, maxY);
3878
+ }
3879
+ this.separateOverlaps(particle, position);
3880
+ this.#dampContacts(particle);
3881
+ if (hasBounds) {
3882
+ this.#cancelWallVelocity(particle, margin, maxX, maxY);
3883
+ }
3884
+ }
3885
+ #cancelWallVelocity(particle, margin, maxX, maxY) {
3886
+ const position = particle.position, velocity = particle.velocity;
3887
+ if (position.x <= margin) {
3888
+ velocity.x = defaultAngle;
3889
+ }
3890
+ else if (position.x >= maxX) {
3891
+ velocity.x = defaultAngle;
3892
+ }
3893
+ if (position.y <= margin) {
3894
+ velocity.y = defaultAngle;
3895
+ }
3896
+ else if (position.y >= maxY) {
3897
+ velocity.y = defaultAngle;
3898
+ }
3899
+ }
3900
+ #dampContacts(particle) {
3901
+ const neighbors = this.#neighbors, position = particle.position, velocity = particle.velocity;
3902
+ let touching = minCount;
3903
+ for (const neighbor of neighbors) {
3904
+ const neighborPosition = neighbor.getPosition(), dx = position.x - neighborPosition.x, dy = position.y - neighborPosition.y, distanceSq = dx * dx + dy * dy, contactDistance = particle.getRadius() + neighbor.getRadius();
3905
+ if (distanceSq >= contactDistance * contactDistance || distanceSq <= minNeighborDistance) {
3906
+ continue;
3907
+ }
3908
+ if (++touching < supportContacts) {
3909
+ continue;
3910
+ }
3911
+ velocity.x *= restRetention;
3912
+ velocity.y *= restRetention;
3913
+ return;
3914
+ }
3915
+ }
3916
+ #projectPair(p1, p2) {
3917
+ const pos1 = p1.position, pos2 = p2.position, dx = pos1.x - pos2.x, dy = pos1.y - pos2.y, distanceSq = dx * dx + dy * dy, minDistance = p1.getRadius() + p2.getRadius();
3918
+ if (distanceSq >= minDistance * minDistance) {
3919
+ return;
3920
+ }
3921
+ if (distanceSq > minNeighborDistance) {
3922
+ const distance = Math.sqrt(distanceSq), inverseDistance = inverseFactorNumerator / distance, correction = minDistance - distance;
3923
+ pos1.x += dx * inverseDistance * correction;
3924
+ pos1.y += dy * inverseDistance * correction;
3925
+ }
3926
+ else {
3927
+ const direction = (p1.id + p2.id) % double === minCount ? identity : -identity;
3928
+ pos1.x += direction * minDistance;
3929
+ }
3930
+ }
3931
+ #queryNeighbors(container, particle, radius, maxNeighbors) {
3932
+ if (radius <= minRadius || maxNeighbors <= minCount) {
3933
+ return;
3934
+ }
3935
+ this.#neighbors.length = 0;
3936
+ container.particles.grid.queryCircle(particle.getPosition(), radius, this.#isNeighbor, this.#neighbors);
3937
+ }
3938
+ }
3939
+
3672
3940
  const minAbsorbAmount = 0;
3673
3941
  function updateAbsorb(p1, r1, p2, r2, delta, pixelRatio) {
3674
3942
  if (!p1.options.collisions || !p2.options.collisions) {
@@ -3758,14 +4026,22 @@
3758
4026
  destroy(p1, p2);
3759
4027
  break;
3760
4028
  }
4029
+ case CollisionMode.fluid: {
4030
+ break;
4031
+ }
3761
4032
  }
3762
4033
  }
3763
4034
 
3764
4035
  class Collider extends ParticlesInteractorBase {
3765
- maxDistance;
4036
+ #fluidSolver;
4037
+ #maxDistance;
3766
4038
  constructor(container) {
3767
4039
  super(container);
3768
- this.maxDistance = 0;
4040
+ this.#fluidSolver = new FluidSolver();
4041
+ this.#maxDistance = 0;
4042
+ }
4043
+ get maxDistance() {
4044
+ return this.#maxDistance;
3769
4045
  }
3770
4046
  clear() {
3771
4047
  }
@@ -3775,13 +4051,24 @@
3775
4051
  if (p1.destroyed || p1.spawning) {
3776
4052
  return;
3777
4053
  }
4054
+ const collisions = p1.options.collisions;
4055
+ if (!collisions?.enable) {
4056
+ return;
4057
+ }
4058
+ if (collisions.mode === CollisionMode.fluid) {
4059
+ const fluidRadius = getRangeValue(collisions.fluid.radius);
4060
+ if (fluidRadius > this.#maxDistance) {
4061
+ this.#maxDistance = fluidRadius;
4062
+ }
4063
+ this.#fluidSolver.solve(this.container, p1);
4064
+ return;
4065
+ }
3778
4066
  const container = this.container, pos1 = p1.getPosition(), radius1 = p1.getRadius(), query = container.particles.grid.queryCircle(pos1, radius1 * double);
3779
4067
  for (const p2 of query) {
3780
4068
  if (p1 === p2 ||
3781
4069
  p1.id >= p2.id ||
3782
- !p1.options.collisions?.enable ||
3783
4070
  !p2.options.collisions?.enable ||
3784
- p1.options.collisions.mode !== p2.options.collisions.mode ||
4071
+ collisions.mode !== p2.options.collisions.mode ||
3785
4072
  p2.destroyed ||
3786
4073
  p2.spawning) {
3787
4074
  continue;
@@ -3803,10 +4090,18 @@
3803
4090
  loadParticlesOptions(options, ...sources) {
3804
4091
  loadOptionProperty(options, "collisions", Collisions, ...sources);
3805
4092
  }
3806
- reset() {
4093
+ reset(_interactivityData, _particle) {
3807
4094
  }
3808
4095
  }
3809
4096
 
4097
+ const ErrorCodes = {
4098
+ overlapNotPlaced: "TSP-4001",
4099
+ };
4100
+
4101
+ const ErrorMessages = {
4102
+ [ErrorCodes.overlapNotPlaced]: "Particle is overlapping and can't be placed",
4103
+ };
4104
+
3810
4105
  class OverlapPlugin {
3811
4106
  id = "overlap";
3812
4107
  async getPlugin(container) {
@@ -3821,7 +4116,10 @@
3821
4116
  }
3822
4117
 
3823
4118
  async function loadParticlesCollisionsInteraction(engine) {
3824
- engine.checkVersion("4.4.0");
4119
+ engine.checkVersion("4.5.0");
4120
+ if (typeof process !== "undefined" && process.env.NODE_ENV !== "production") {
4121
+ addErrorMessages(ErrorMessages);
4122
+ }
3825
4123
  await engine.pluginManager.register((e) => {
3826
4124
  ensureInteractivityPluginLoaded(e);
3827
4125
  e.pluginManager.addPlugin(new OverlapPlugin());
@@ -4075,7 +4373,7 @@
4075
4373
  }
4076
4374
 
4077
4375
  async function loadParticlesLinksInteraction(engine) {
4078
- engine.checkVersion("4.4.0");
4376
+ engine.checkVersion("4.5.0");
4079
4377
  await engine.pluginManager.register((e) => {
4080
4378
  const pluginManager = e.pluginManager;
4081
4379
  ensureInteractivityPluginLoaded(e);
@@ -4088,7 +4386,7 @@
4088
4386
 
4089
4387
  let initPromise = null;
4090
4388
  async function doInitPlugins(engine) {
4091
- engine.checkVersion("4.4.0");
4389
+ engine.checkVersion("4.5.0");
4092
4390
  await engine.pluginManager.register(async (e) => {
4093
4391
  const loadParticlesInteractivity = async (e) => {
4094
4392
  await loadInteractivityPlugin(e);
@@ -4131,7 +4429,7 @@
4131
4429
  particles.init = async () => {
4132
4430
  await initPlugins(tsParticles);
4133
4431
  };
4134
- particles.version = "4.4.0";
4432
+ particles.version = "4.5.0";
4135
4433
  globalThis.particles = particles;
4136
4434
 
4137
4435
  const globalObject = globalThis;
@@ -4201,21 +4499,28 @@
4201
4499
  });
4202
4500
  }
4203
4501
  clear() {
4502
+ const visited = new Set();
4204
4503
  for (const plugin of this.#canvasClearPlugins) {
4504
+ visited.add(plugin);
4205
4505
  if (plugin.canvasClear?.() ?? false) {
4206
- return;
4506
+ return plugin;
4207
4507
  }
4208
4508
  }
4209
4509
  for (const layer of Object.values(exports.DrawLayer)) {
4210
4510
  if (typeof layer === "number") {
4211
4511
  for (const plugin of this.#getLayerPlugins(layer)) {
4512
+ if (visited.has(plugin)) {
4513
+ continue;
4514
+ }
4515
+ visited.add(plugin);
4212
4516
  if (plugin.canvasClear?.() ?? false) {
4213
- return;
4517
+ return plugin;
4214
4518
  }
4215
4519
  }
4216
4520
  }
4217
4521
  }
4218
4522
  this.canvasClear();
4523
+ return undefined;
4219
4524
  }
4220
4525
  destroy() {
4221
4526
  this.stop();
@@ -4293,8 +4598,7 @@
4293
4598
  });
4294
4599
  }
4295
4600
  drawParticles(delta) {
4296
- const { particles, actualOptions } = this.#container;
4297
- this.clear();
4601
+ const { particles, actualOptions } = this.#container, clearedPlugin = this.clear();
4298
4602
  particles.update(delta);
4299
4603
  this.draw(ctx => {
4300
4604
  const width = this.#canvasManager.size.width, height = this.#canvasManager.size.height;
@@ -4316,7 +4620,9 @@
4316
4620
  }
4317
4621
  }
4318
4622
  for (const plugin of this.#getLayerPlugins(exports.DrawLayer.BackgroundMask)) {
4319
- plugin.canvasPaint?.();
4623
+ if (plugin !== clearedPlugin) {
4624
+ plugin.canvasPaint?.();
4625
+ }
4320
4626
  }
4321
4627
  for (const plugin of this.#getLayerPlugins(exports.DrawLayer.CanvasSetup)) {
4322
4628
  plugin.drawSettingsSetup?.(ctx, delta);
@@ -4348,35 +4654,7 @@
4348
4654
  this.#layers[layer] = [];
4349
4655
  }
4350
4656
  }
4351
- for (const plugin of this.#container.plugins) {
4352
- if (plugin.particleFillColor ?? plugin.particleStrokeColor) {
4353
- this.#colorPlugins.push(plugin);
4354
- }
4355
- if (plugin.drawParticle) {
4356
- this.#drawParticlePlugins.push(plugin);
4357
- }
4358
- if (plugin.drawParticleSetup) {
4359
- this.#drawParticlesSetupPlugins.push(plugin);
4360
- }
4361
- if (plugin.drawParticleCleanup) {
4362
- this.#drawParticlesCleanupPlugins.push(plugin);
4363
- }
4364
- if (plugin.canvasClear) {
4365
- this.#canvasClearPlugins.push(plugin);
4366
- }
4367
- if (plugin.canvasPaint) {
4368
- this.#getLayerPlugins(exports.DrawLayer.BackgroundMask).push(plugin);
4369
- }
4370
- if (plugin.drawSettingsSetup) {
4371
- this.#getLayerPlugins(exports.DrawLayer.CanvasSetup).push(plugin);
4372
- }
4373
- if (plugin.draw) {
4374
- this.#getLayerPlugins(exports.DrawLayer.PluginContent).push(plugin);
4375
- }
4376
- if (plugin.clearDraw ?? plugin.drawSettingsCleanup) {
4377
- this.#getLayerPlugins(exports.DrawLayer.CanvasCleanup).push(plugin);
4378
- }
4379
- }
4657
+ this.#initPluginsArray();
4380
4658
  }
4381
4659
  initUpdaters() {
4382
4660
  this.#preDrawUpdaters = [];
@@ -4585,6 +4863,45 @@
4585
4863
  this.#reusablePluginColors[sColorIndex] = sColor;
4586
4864
  return this.#reusablePluginColors;
4587
4865
  }
4866
+ #initLayerPlugin(plugin) {
4867
+ const layerMap = [
4868
+ [exports.DrawLayer.BackgroundMask, !!plugin.canvasPaint],
4869
+ [exports.DrawLayer.CanvasSetup, !!plugin.drawSettingsSetup],
4870
+ [exports.DrawLayer.PluginContent, !!plugin.draw],
4871
+ [exports.DrawLayer.CanvasCleanup, !!(plugin.clearDraw ?? plugin.drawSettingsCleanup)],
4872
+ ];
4873
+ for (const [layer, active] of layerMap) {
4874
+ if (active) {
4875
+ this.#layers[layer].push(plugin);
4876
+ }
4877
+ }
4878
+ }
4879
+ #initPluginsArray() {
4880
+ for (const plugin of this.#container.plugins) {
4881
+ if (plugin.particleFillColor ?? plugin.particleStrokeColor) {
4882
+ this.#colorPlugins.push(plugin);
4883
+ }
4884
+ if (plugin.drawParticle) {
4885
+ this.#drawParticlePlugins.push(plugin);
4886
+ }
4887
+ if (plugin.drawParticleSetup) {
4888
+ this.#drawParticlesSetupPlugins.push(plugin);
4889
+ }
4890
+ if (plugin.drawParticleCleanup) {
4891
+ this.#drawParticlesCleanupPlugins.push(plugin);
4892
+ }
4893
+ if (plugin.canvasClear) {
4894
+ this.#canvasClearPlugins.push(plugin);
4895
+ }
4896
+ this.#initLayerPlugin(plugin);
4897
+ }
4898
+ }
4899
+ #isSupportedElement(element) {
4900
+ return ((typeof HTMLCanvasElement !== "undefined" && element instanceof HTMLCanvasElement) ||
4901
+ (typeof OffscreenCanvas !== "undefined" && element instanceof OffscreenCanvas) ||
4902
+ (typeof HTMLVideoElement !== "undefined" && element instanceof HTMLVideoElement) ||
4903
+ (typeof HTMLImageElement !== "undefined" && element instanceof HTMLImageElement));
4904
+ }
4588
4905
  #resolveBackgroundElement() {
4589
4906
  const background = this.#container.actualOptions.background;
4590
4907
  this.#backgroundElement = null;
@@ -4594,9 +4911,7 @@
4594
4911
  if (typeof background.element === "string") {
4595
4912
  if (typeof document !== "undefined") {
4596
4913
  const node = document.querySelector(background.element);
4597
- if ((typeof HTMLCanvasElement !== "undefined" && node instanceof HTMLCanvasElement) ||
4598
- (typeof HTMLVideoElement !== "undefined" && node instanceof HTMLVideoElement) ||
4599
- (typeof HTMLImageElement !== "undefined" && node instanceof HTMLImageElement)) {
4914
+ if (node && this.#isSupportedElement(node)) {
4600
4915
  this.#backgroundElement = node;
4601
4916
  }
4602
4917
  else if (node) {
@@ -4607,10 +4922,7 @@
4607
4922
  }
4608
4923
  }
4609
4924
  }
4610
- else if ((typeof HTMLCanvasElement !== "undefined" && background.element instanceof HTMLCanvasElement) ||
4611
- (typeof OffscreenCanvas !== "undefined" && background.element instanceof OffscreenCanvas) ||
4612
- (typeof HTMLVideoElement !== "undefined" && background.element instanceof HTMLVideoElement) ||
4613
- (typeof HTMLImageElement !== "undefined" && background.element instanceof HTMLImageElement)) {
4925
+ else if (this.#isSupportedElement(background.element)) {
4614
4926
  this.#backgroundElement = background.element;
4615
4927
  }
4616
4928
  }
@@ -4628,7 +4940,7 @@
4628
4940
  return transferredCanvas;
4629
4941
  }
4630
4942
  if (typeof canvas.transferControlToOffscreen !== "function") {
4631
- throw new TypeError("OffscreenCanvas is required but not supported by this browser");
4943
+ throw new TypeError(getErrorMessage(ErrorCodes$3.offscreenCanvasUnsupported));
4632
4944
  }
4633
4945
  try {
4634
4946
  const offscreenCanvas = canvas.transferControlToOffscreen();
@@ -4636,10 +4948,16 @@
4636
4948
  return offscreenCanvas;
4637
4949
  }
4638
4950
  catch {
4639
- throw new TypeError("OffscreenCanvas transfer failed");
4951
+ throw new TypeError(getErrorMessage(ErrorCodes$3.offscreenCanvasTransferFailed));
4640
4952
  }
4641
4953
  }, isHtmlCanvasElement = (canvas) => {
4642
4954
  return typeof HTMLCanvasElement !== "undefined" && canvas instanceof HTMLCanvasElement;
4955
+ }, getEffectiveColorSpace = (context) => {
4956
+ if (!context) {
4957
+ return undefined;
4958
+ }
4959
+ const colorInfo = context;
4960
+ return colorInfo.getContextAttributes?.().colorSpace ?? undefined;
4643
4961
  };
4644
4962
  function setStyle(canvas, style, important = false) {
4645
4963
  if (!style) {
@@ -4764,7 +5082,7 @@
4764
5082
  const elementStyle = element.style, color = rangeColorToRgb(this.#pluginManager, background.color);
4765
5083
  if (color) {
4766
5084
  const hdrOptions = container.actualOptions.hdr;
4767
- elementStyle.backgroundColor = getStyleFromRgb(color, container.hdr, background.opacity, hdrOptions.peakNits, hdrOptions.mode);
5085
+ elementStyle.backgroundColor = getStyleFromRgb(color, container.hdr, background.opacity, hdrOptions.peakNits, toEnumValue(exports.HdrMode, hdrOptions.mode, exports.HdrMode.standard));
4768
5086
  }
4769
5087
  else {
4770
5088
  elementStyle.backgroundColor = "";
@@ -4884,11 +5202,11 @@
4884
5202
  const container = this.#container, canSupportHdr = container.actualOptions.hdr.enable &&
4885
5203
  safeMatchMedia("(color-gamut: p3)")?.matches &&
4886
5204
  safeMatchMedia("(dynamic-range: high)")?.matches;
4887
- container.hdr = canSupportHdr ?? false;
4888
- container.hdrMode = container.actualOptions.hdr.mode;
5205
+ container.hdrMode = toEnumValue(exports.HdrMode, container.actualOptions.hdr.mode, exports.HdrMode.standard);
4889
5206
  container.peakNits = container.actualOptions.hdr.peakNits;
4890
5207
  const renderCanvas = this.renderCanvas;
4891
5208
  if (!renderCanvas) {
5209
+ container.hdr = canSupportHdr ?? false;
4892
5210
  return;
4893
5211
  }
4894
5212
  this.render.setContextSettings({
@@ -4907,7 +5225,6 @@
4907
5225
  context = null;
4908
5226
  }
4909
5227
  if (canSupportHdr && !context) {
4910
- container.hdr = false;
4911
5228
  const sdrSettings = {
4912
5229
  alpha: true,
4913
5230
  desynchronized: true,
@@ -4923,11 +5240,16 @@
4923
5240
  }
4924
5241
  }
4925
5242
  this.render.setContext(context);
5243
+ if (context) {
5244
+ const effectiveColorSpace = getEffectiveColorSpace(context);
5245
+ if (effectiveColorSpace !== undefined) {
5246
+ container.hdr = effectiveColorSpace === "display-p3";
5247
+ }
5248
+ }
4926
5249
  }
4927
5250
  #initHdrListeners() {
4928
5251
  this.#removeHdrListeners();
4929
5252
  const p3Query = safeMatchMedia("(color-gamut: p3)"), hdrQuery = safeMatchMedia("(dynamic-range: high)"), handleChange = () => {
4930
- this.#recreateRenderCanvas();
4931
5253
  this.#initContext();
4932
5254
  this.initBackground();
4933
5255
  }, listeners = [];
@@ -4963,16 +5285,6 @@
4963
5285
  element.style.setProperty(key, value, "important");
4964
5286
  }
4965
5287
  }
4966
- #recreateRenderCanvas() {
4967
- const renderCanvas = this.renderCanvas;
4968
- if (!renderCanvas) {
4969
- return;
4970
- }
4971
- if (this.domElement) {
4972
- return;
4973
- }
4974
- this.renderCanvas = new OffscreenCanvas(renderCanvas.width, renderCanvas.height);
4975
- }
4976
5288
  #removeHdrListeners() {
4977
5289
  if (!this.#hdrMediaListeners) {
4978
5290
  return;
@@ -5071,8 +5383,7 @@
5071
5383
  this.#resizeTimeout = undefined;
5072
5384
  }
5073
5385
  const handleResize = async () => {
5074
- const canvas = this.#container.canvas;
5075
- await canvas.windowResize();
5386
+ await this.#container.canvas.windowResize();
5076
5387
  };
5077
5388
  this.#resizeTimeout = setTimeout(() => void handleResize(), this.#container.actualOptions.resize.delay * millisecondsToSeconds);
5078
5389
  }
@@ -5100,8 +5411,8 @@
5100
5411
  }
5101
5412
  else if (!this.#resizeObserver && add && canvasEl) {
5102
5413
  this.#resizeObserver = new ResizeObserver((entries) => {
5103
- const entry = entries.find(e => e.target === canvasEl);
5104
- if (!entry) {
5414
+ const res = entries.some(e => e.target === canvasEl);
5415
+ if (!res) {
5105
5416
  return;
5106
5417
  }
5107
5418
  this.#handleWindowResize();
@@ -5365,10 +5676,10 @@
5365
5676
  return this.#modifiers.find(m => m.id === id);
5366
5677
  }
5367
5678
  getOpacity() {
5368
- const zIndexOptions = this.options.zIndex, zIndexFactor = zIndexFactorOffset - this.zIndexFactor, zOpacityFactor = zIndexFactor ** zIndexOptions.opacityRate, baseOpacity = getRangeValue(this.opacity?.value ?? defaultOpacity$2), modifierOpacity = this.#applyModifiers(undefined, m => m.opacity), opacity = modifierOpacity ?? baseOpacity, fillOpacity = this.fillOpacity ?? defaultOpacity$2, strokeOpacity = this.strokeOpacity ?? defaultOpacity$2;
5369
- this.#cachedOpacityData.fillOpacity = fillOpacity;
5679
+ const zIndexOptions = this.options.zIndex, zIndexFactor = zIndexFactorOffset - this.zIndexFactor, zOpacityFactor = zIndexFactor ** zIndexOptions.opacityRate, baseOpacity = getRangeValue(this.opacity?.value ?? defaultOpacity$2), modifierOpacity = this.#applyModifiers(undefined, m => m.opacity), opacity = modifierOpacity ?? baseOpacity;
5680
+ this.#cachedOpacityData.fillOpacity = this.fillOpacity ?? defaultOpacity$2;
5370
5681
  this.#cachedOpacityData.opacity = opacity * zOpacityFactor;
5371
- this.#cachedOpacityData.strokeOpacity = strokeOpacity;
5682
+ this.#cachedOpacityData.strokeOpacity = this.strokeOpacity ?? defaultOpacity$2;
5372
5683
  return this.#cachedOpacityData;
5373
5684
  }
5374
5685
  getPosition() {
@@ -5615,7 +5926,7 @@
5615
5926
  #initPosition(position) {
5616
5927
  const container = this.#container, zIndexValue = Math.floor(getRangeValue(this.options.zIndex.value)), initialPosition = this.#calcPosition(position, clamp(zIndexValue, minZ, container.zLayers));
5617
5928
  if (!initialPosition) {
5618
- throw new Error("a valid position cannot be found for particle");
5929
+ throw new Error(getErrorMessage(ErrorCodes$3.particlePositionNotFound));
5619
5930
  }
5620
5931
  this.position = initialPosition;
5621
5932
  this.initialPosition = this.position.copy();
@@ -5664,6 +5975,12 @@
5664
5975
  this.#circlePoolIdx = 0;
5665
5976
  this.#rectanglePoolIdx = 0;
5666
5977
  }
5978
+ get cellSize() {
5979
+ return this.#cellSize;
5980
+ }
5981
+ set cellSize(value) {
5982
+ this.#pendingCellSize = value;
5983
+ }
5667
5984
  clear() {
5668
5985
  this.#cells.clear();
5669
5986
  const pendingCellSize = this.#pendingCellSize;
@@ -5687,18 +6004,7 @@
5687
6004
  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);
5688
6005
  for (let cx = minCellX; cx <= maxCellX; cx++) {
5689
6006
  for (let cy = minCellY; cy <= maxCellY; cy++) {
5690
- const key = `${cx}_${cy}`, cellParticles = this.#cells.get(key);
5691
- if (!cellParticles) {
5692
- continue;
5693
- }
5694
- for (const p of cellParticles) {
5695
- if (check && !check(p)) {
5696
- continue;
5697
- }
5698
- if (range.contains(p.getPosition())) {
5699
- out.push(p);
5700
- }
5701
- }
6007
+ this.#queryCell(cx, cy, range, check, out);
5702
6008
  }
5703
6009
  }
5704
6010
  return out;
@@ -5713,14 +6019,23 @@
5713
6019
  this.#releaseShapes();
5714
6020
  return result;
5715
6021
  }
5716
- setCellSize(cellSize) {
5717
- this.#pendingCellSize = cellSize;
5718
- }
5719
6022
  #acquireCircle(x, y, r) {
5720
- return (this.#circlePool[this.#circlePoolIdx++] ??= new Circle(x, y, r)).reset(x, y, r);
6023
+ const idx = this.#circlePoolIdx++;
6024
+ let circle = this.#circlePool[idx];
6025
+ if (!circle) {
6026
+ circle = new Circle(x, y, r);
6027
+ this.#circlePool[idx] = circle;
6028
+ }
6029
+ return circle.reset(x, y, r);
5721
6030
  }
5722
6031
  #acquireRectangle(x, y, w, h) {
5723
- return (this.#rectanglePool[this.#rectanglePoolIdx++] ??= new Rectangle(x, y, w, h)).reset(x, y, w, h);
6032
+ const idx = this.#rectanglePoolIdx++;
6033
+ let rectangle = this.#rectanglePool[idx];
6034
+ if (!rectangle) {
6035
+ rectangle = new Rectangle(x, y, w, h);
6036
+ this.#rectanglePool[idx] = rectangle;
6037
+ }
6038
+ return rectangle.reset(x, y, w, h);
5724
6039
  }
5725
6040
  #cellKeyFromCoords(x, y) {
5726
6041
  const cellX = Math.floor(x / this.#cellSize), cellY = Math.floor(y / this.#cellSize);
@@ -5747,6 +6062,20 @@
5747
6062
  }
5748
6063
  return null;
5749
6064
  }
6065
+ #queryCell(cx, cy, range, check, out) {
6066
+ const cellParticles = this.#cells.get(`${cx}_${cy}`);
6067
+ if (!cellParticles) {
6068
+ return;
6069
+ }
6070
+ for (const p of cellParticles) {
6071
+ if (check && !check(p)) {
6072
+ continue;
6073
+ }
6074
+ if (range.contains(p.getPosition())) {
6075
+ out.push(p);
6076
+ }
6077
+ }
6078
+ }
5750
6079
  #releaseShapes() {
5751
6080
  this.#circlePoolIdx = 0;
5752
6081
  this.#rectanglePoolIdx = 0;
@@ -5755,9 +6084,9 @@
5755
6084
 
5756
6085
  class ParticlesManager {
5757
6086
  checkParticlePositionPlugins;
5758
- grid;
5759
6087
  #array;
5760
6088
  #container;
6089
+ #grid;
5761
6090
  #groupLimits;
5762
6091
  #limit;
5763
6092
  #nextId;
@@ -5781,7 +6110,7 @@
5781
6110
  this.#groupLimits = new Map();
5782
6111
  this.#particleBuckets = new Map();
5783
6112
  this.#zBuckets = this.#createBuckets(this.#container.zLayers);
5784
- this.grid = new SpatialHashGrid(spatialHashGridCellSize);
6113
+ this.#grid = new SpatialHashGrid(spatialHashGridCellSize);
5785
6114
  this.checkParticlePositionPlugins = [];
5786
6115
  this.#particleResetPlugins = [];
5787
6116
  this.#particleUpdatePlugins = [];
@@ -5792,23 +6121,12 @@
5792
6121
  get count() {
5793
6122
  return this.#array.length;
5794
6123
  }
6124
+ get grid() {
6125
+ return this.#grid;
6126
+ }
5795
6127
  addParticle(position, overrideOptions, group, initializer) {
5796
- const limitMode = this.#container.actualOptions.particles.number.limit.mode, limit = group === undefined ? this.#limit : (this.#groupLimits.get(group) ?? this.#limit), currentCount = this.count;
5797
- if (limit > minLimit) {
5798
- switch (limitMode) {
5799
- case exports.LimitMode.delete: {
5800
- const countToRemove = currentCount + countOffset - limit;
5801
- if (countToRemove > minCount) {
5802
- this.removeQuantity(countToRemove);
5803
- }
5804
- break;
5805
- }
5806
- case exports.LimitMode.wait:
5807
- if (currentCount >= limit) {
5808
- return;
5809
- }
5810
- break;
5811
- }
6128
+ if (this.#checkAndApplyLimits(group, this.count)) {
6129
+ return;
5812
6130
  }
5813
6131
  try {
5814
6132
  const particle = this.#pool.pop() ?? new Particle(this.#pluginManager, this.#container);
@@ -5872,7 +6190,7 @@
5872
6190
  return this.#array[index];
5873
6191
  }
5874
6192
  async init() {
5875
- const container = this.#container, options = container.actualOptions;
6193
+ const container = this.#container;
5876
6194
  this.checkParticlePositionPlugins = [];
5877
6195
  this.#updatePlugins = [];
5878
6196
  this.#particleUpdatePlugins = [];
@@ -5881,59 +6199,16 @@
5881
6199
  this.#postParticleUpdatePlugins = [];
5882
6200
  this.#particleBuckets.clear();
5883
6201
  this.#resetBuckets(container.zLayers);
5884
- this.grid = new SpatialHashGrid(spatialHashGridCellSize * container.retina.pixelRatio);
5885
- for (const plugin of container.plugins) {
5886
- if (plugin.redrawInit) {
5887
- await plugin.redrawInit();
5888
- }
5889
- if (plugin.checkParticlePosition) {
5890
- this.checkParticlePositionPlugins.push(plugin);
5891
- }
5892
- if (plugin.update) {
5893
- this.#updatePlugins.push(plugin);
5894
- }
5895
- if (plugin.particleUpdate) {
5896
- this.#particleUpdatePlugins.push(plugin);
5897
- }
5898
- if (plugin.postUpdate) {
5899
- this.#postUpdatePlugins.push(plugin);
5900
- }
5901
- if (plugin.particleReset) {
5902
- this.#particleResetPlugins.push(plugin);
5903
- }
5904
- if (plugin.postParticleUpdate) {
5905
- this.#postParticleUpdatePlugins.push(plugin);
5906
- }
5907
- }
5908
- await this.#container.initDrawersAndUpdaters();
5909
- for (const drawer of this.#container.effectDrawers.values()) {
5910
- await drawer.init?.(container);
5911
- }
5912
- for (const drawer of this.#container.shapeDrawers.values()) {
5913
- await drawer.init?.(container);
5914
- }
5915
- let handled = false;
5916
- for (const plugin of container.plugins) {
5917
- handled = plugin.particlesInitialization?.() ?? handled;
5918
- if (handled) {
5919
- break;
5920
- }
5921
- }
5922
- if (!handled) {
5923
- const particlesOptions = options.particles, groups = particlesOptions.groups;
5924
- for (const group in groups) {
5925
- const groupOptions = groups[group];
5926
- if (!groupOptions) {
5927
- continue;
5928
- }
5929
- for (let i = this.count, j = 0; j < groupOptions.number.value && i < particlesOptions.number.value; i++, j++) {
5930
- this.addParticle(undefined, groupOptions, group);
5931
- }
5932
- }
5933
- for (let i = this.count; i < particlesOptions.number.value; i++) {
5934
- this.addParticle();
6202
+ this.#grid = new SpatialHashGrid(spatialHashGridCellSize * container.retina.pixelRatio);
6203
+ this.#applyLimits(container.actualOptions.particles);
6204
+ const particlesOptions = container.actualOptions.particles, groups = particlesOptions.groups;
6205
+ for (const group in groups) {
6206
+ const groupData = groups[group];
6207
+ if (groupData) {
6208
+ this.#applyLimits(loadParticlesOptions(this.#pluginManager, this.#container, groupData), group, groupData);
5935
6209
  }
5936
6210
  }
6211
+ await this.#initPlugins();
5937
6212
  }
5938
6213
  push(nb, position, overrideOptions, group) {
5939
6214
  for (let i = 0; i < nb; i++) {
@@ -5948,13 +6223,13 @@
5948
6223
  remove(particle, group, override) {
5949
6224
  this.removeAt(this.#array.indexOf(particle), undefined, group, override);
5950
6225
  }
5951
- removeAt(index, quantity = defaultRemoveQuantity, group, override) {
6226
+ removeAt(index, quantity = defaultRemoveQuantity, group, override, matchGroup = true) {
5952
6227
  if (index < minIndex || index > this.count) {
5953
6228
  return;
5954
6229
  }
5955
6230
  let deleted = 0;
5956
6231
  for (let i = index; deleted < quantity && i < this.count; i++) {
5957
- if (this.#removeParticle(i, group, override)) {
6232
+ if (this.#removeParticle(i, group, override, matchGroup)) {
5958
6233
  i--;
5959
6234
  deleted++;
5960
6235
  }
@@ -5985,7 +6260,7 @@
5985
6260
  this.#resizeFactor = factor;
5986
6261
  }
5987
6262
  update(delta) {
5988
- this.grid.clear();
6263
+ this.#grid.clear();
5989
6264
  for (const plugin of this.#updatePlugins) {
5990
6265
  plugin.update?.(delta);
5991
6266
  }
@@ -5996,7 +6271,7 @@
5996
6271
  this.#updateParticlesPhase2(delta, particlesToDelete);
5997
6272
  if (particlesToDelete.size) {
5998
6273
  for (const particle of particlesToDelete) {
5999
- this.remove(particle);
6274
+ this.remove(particle, particle.group);
6000
6275
  }
6001
6276
  }
6002
6277
  this.#resizeFactor = undefined;
@@ -6007,12 +6282,7 @@
6007
6282
  #applyDensity(options, pluginsCount, group, groupOptions) {
6008
6283
  const numberOptions = options.number;
6009
6284
  if (!numberOptions.density.enable) {
6010
- if (group === undefined) {
6011
- this.#limit = numberOptions.limit.value;
6012
- }
6013
- else if (groupOptions?.number.limit.value ?? numberOptions.limit.value) {
6014
- this.#groupLimits.set(group, groupOptions?.number.limit.value ?? numberOptions.limit.value);
6015
- }
6285
+ this.#applyLimits(options, group, groupOptions);
6016
6286
  return;
6017
6287
  }
6018
6288
  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);
@@ -6020,7 +6290,10 @@
6020
6290
  this.#limit = numberOptions.limit.value * densityFactor;
6021
6291
  }
6022
6292
  else {
6023
- this.#groupLimits.set(group, numberOptions.limit.value * densityFactor);
6293
+ this.#groupLimits.set(group, {
6294
+ limit: numberOptions.limit.value * densityFactor,
6295
+ mode: toEnumValue(exports.LimitMode, numberOptions.limit.mode, exports.LimitMode.delete),
6296
+ });
6024
6297
  }
6025
6298
  if (particlesCount < particlesNumber) {
6026
6299
  this.push(Math.abs(particlesNumber - particlesCount), undefined, options, group);
@@ -6029,6 +6302,55 @@
6029
6302
  this.removeQuantity(particlesCount - particlesNumber, group);
6030
6303
  }
6031
6304
  }
6305
+ #applyLimits(options, group, groupOptions) {
6306
+ if (group === undefined) {
6307
+ this.#limit = options.number.limit.value;
6308
+ const groups = this.#container.actualOptions.particles.groups;
6309
+ for (const existingGroup of this.#groupLimits.keys()) {
6310
+ if (!(existingGroup in groups)) {
6311
+ this.#groupLimits.delete(existingGroup);
6312
+ }
6313
+ }
6314
+ }
6315
+ else {
6316
+ const limitValue = groupOptions?.number?.limit?.value ?? options.number.limit.value;
6317
+ if (limitValue > minLimit) {
6318
+ this.#groupLimits.set(group, {
6319
+ limit: limitValue,
6320
+ mode: toEnumValue(exports.LimitMode, groupOptions?.number?.limit?.mode ?? options.number.limit.mode, exports.LimitMode.delete),
6321
+ });
6322
+ }
6323
+ else {
6324
+ this.#groupLimits.delete(group);
6325
+ }
6326
+ }
6327
+ }
6328
+ #checkAndApplyLimits(group, currentCount) {
6329
+ const globalLimit = this.#limit, globalMode = this.#container.actualOptions.particles.number.limit.mode;
6330
+ if (globalLimit > minLimit && globalMode === exports.LimitMode.wait && currentCount >= globalLimit) {
6331
+ return true;
6332
+ }
6333
+ const groupLimitEntry = group === undefined ? undefined : this.#groupLimits.get(group);
6334
+ if (groupLimitEntry && groupLimitEntry.limit > minLimit && groupLimitEntry.mode === exports.LimitMode.wait) {
6335
+ const groupCount = this.filter(t => t.group === group).length;
6336
+ if (groupCount >= groupLimitEntry.limit) {
6337
+ return true;
6338
+ }
6339
+ }
6340
+ if (groupLimitEntry && groupLimitEntry.limit > minLimit && groupLimitEntry.mode === exports.LimitMode.delete) {
6341
+ const groupCountToRemove = this.filter(t => t.group === group).length + countOffset - groupLimitEntry.limit;
6342
+ if (groupCountToRemove > minCount) {
6343
+ this.removeQuantity(groupCountToRemove, group);
6344
+ }
6345
+ }
6346
+ if (globalLimit > minLimit && globalMode === exports.LimitMode.delete) {
6347
+ const globalCountToRemove = this.count + countOffset - globalLimit;
6348
+ if (globalCountToRemove > minCount) {
6349
+ this.#removeAny(globalCountToRemove);
6350
+ }
6351
+ }
6352
+ return false;
6353
+ }
6032
6354
  #createBuckets(zLayers) {
6033
6355
  const bucketCount = Math.max(Math.floor(zLayers), one);
6034
6356
  return Array.from({ length: bucketCount }, () => []);
@@ -6051,6 +6373,70 @@
6051
6373
  }
6052
6374
  return ((canvasSize.width * canvasSize.height) / (densityOptions.height * densityOptions.width * pxRatio ** squareExp));
6053
6375
  }
6376
+ async #initDrawersAndUpdaters() {
6377
+ const container = this.#container;
6378
+ await container.initDrawersAndUpdaters();
6379
+ for (const drawer of container.effectDrawers.values()) {
6380
+ await drawer.init?.(container);
6381
+ }
6382
+ for (const drawer of container.shapeDrawers.values()) {
6383
+ await drawer.init?.(container);
6384
+ }
6385
+ }
6386
+ async #initPlugins() {
6387
+ await this.#initPluginsArrays();
6388
+ await this.#initDrawersAndUpdaters();
6389
+ let handled = false;
6390
+ const container = this.#container;
6391
+ for (const plugin of container.plugins) {
6392
+ handled = plugin.particlesInitialization?.() ?? handled;
6393
+ if (handled) {
6394
+ break;
6395
+ }
6396
+ }
6397
+ if (handled) {
6398
+ return;
6399
+ }
6400
+ const particlesOptions = container.actualOptions.particles, groups = particlesOptions.groups;
6401
+ for (const group in groups) {
6402
+ const groupOptions = groups[group];
6403
+ if (!groupOptions) {
6404
+ continue;
6405
+ }
6406
+ for (let i = this.count, j = 0; j < groupOptions.number.value && i < particlesOptions.number.value; i++, j++) {
6407
+ this.addParticle(undefined, groupOptions, group);
6408
+ }
6409
+ }
6410
+ for (let i = this.count; i < particlesOptions.number.value; i++) {
6411
+ this.addParticle();
6412
+ }
6413
+ }
6414
+ async #initPluginsArrays() {
6415
+ const container = this.#container;
6416
+ for (const plugin of container.plugins) {
6417
+ if (plugin.redrawInit) {
6418
+ await plugin.redrawInit();
6419
+ }
6420
+ if (plugin.checkParticlePosition) {
6421
+ this.checkParticlePositionPlugins.push(plugin);
6422
+ }
6423
+ if (plugin.update) {
6424
+ this.#updatePlugins.push(plugin);
6425
+ }
6426
+ if (plugin.particleUpdate) {
6427
+ this.#particleUpdatePlugins.push(plugin);
6428
+ }
6429
+ if (plugin.postUpdate) {
6430
+ this.#postUpdatePlugins.push(plugin);
6431
+ }
6432
+ if (plugin.particleReset) {
6433
+ this.#particleResetPlugins.push(plugin);
6434
+ }
6435
+ if (plugin.postParticleUpdate) {
6436
+ this.#postParticleUpdatePlugins.push(plugin);
6437
+ }
6438
+ }
6439
+ }
6054
6440
  #insertParticleIntoBucket(particle) {
6055
6441
  const bucketIndex = this.#getBucketIndex(particle.position.z), bucket = this.#zBuckets[bucketIndex];
6056
6442
  if (!bucket) {
@@ -6059,12 +6445,15 @@
6059
6445
  bucket.push(particle);
6060
6446
  this.#particleBuckets.set(particle.id, bucketIndex);
6061
6447
  }
6062
- #removeParticle(index, group, override) {
6448
+ #removeAny(quantity) {
6449
+ this.removeAt(minIndex, quantity, undefined, undefined, false);
6450
+ }
6451
+ #removeParticle(index, group, override, matchGroup = true) {
6063
6452
  const particle = this.#array[index];
6064
6453
  if (!particle) {
6065
6454
  return false;
6066
6455
  }
6067
- if (particle.group !== group) {
6456
+ if (matchGroup && particle.group !== group) {
6068
6457
  return false;
6069
6458
  }
6070
6459
  this.#array.splice(index, deleteCount);
@@ -6151,7 +6540,7 @@
6151
6540
  particlesToDelete.add(particle);
6152
6541
  continue;
6153
6542
  }
6154
- this.grid.insert(particle);
6543
+ this.#grid.insert(particle);
6155
6544
  }
6156
6545
  return particlesToDelete;
6157
6546
  }
@@ -6327,7 +6716,6 @@
6327
6716
  this.shapeDrawers = new Map();
6328
6717
  this.particleUpdaters = [];
6329
6718
  this.plugins.length = 0;
6330
- this.#pluginManager.clearPlugins(this);
6331
6719
  this.destroyed = true;
6332
6720
  this.#onDestroy(remove);
6333
6721
  this.dispatchEvent(exports.EventType.containerDestroyed);
@@ -6380,31 +6768,14 @@
6380
6768
  await this.initDrawersAndUpdaters();
6381
6769
  this.#options = loadContainerOptions(this.#pluginManager, this, this.#initialSourceOptions, this.sourceOptions);
6382
6770
  this.actualOptions = loadContainerOptions(this.#pluginManager, this, this.#options);
6383
- this.plugins.length = 0;
6384
- this.particleDestroyedPlugins.length = 0;
6385
- this.particleCreatedPlugins.length = 0;
6386
- this.particlePositionPlugins.length = 0;
6387
- for (const [plugin, containerPlugin] of allContainerPlugins) {
6388
- if (plugin.needsPlugin(this.actualOptions)) {
6389
- this.plugins.push(containerPlugin);
6390
- if (containerPlugin.particleCreated) {
6391
- this.particleCreatedPlugins.push(containerPlugin);
6392
- }
6393
- if (containerPlugin.particleDestroyed) {
6394
- this.particleDestroyedPlugins.push(containerPlugin);
6395
- }
6396
- if (containerPlugin.particlePosition) {
6397
- this.particlePositionPlugins.push(containerPlugin);
6398
- }
6399
- }
6400
- }
6771
+ this.#initPlugins(allContainerPlugins);
6401
6772
  this.retina.init();
6402
6773
  this.canvas.init();
6403
6774
  this.updateActualOptions();
6404
6775
  this.canvas.initBackground();
6405
6776
  this.canvas.resize();
6406
6777
  const { delay, duration, fpsLimit, smooth, zLayers } = this.actualOptions, hdrOptions = this.actualOptions.hdr;
6407
- this.hdrMode = hdrOptions.mode;
6778
+ this.hdrMode = toEnumValue(exports.HdrMode, hdrOptions.mode, exports.HdrMode.standard);
6408
6779
  this.peakNits = hdrOptions.peakNits;
6409
6780
  this.zLayers = zLayers;
6410
6781
  this.#duration = getRangeValue(duration) * millisecondsToSeconds;
@@ -6425,9 +6796,9 @@
6425
6796
  }
6426
6797
  async initDrawersAndUpdaters() {
6427
6798
  const pluginManager = this.#pluginManager;
6428
- this.effectDrawers = await pluginManager.getEffectDrawers(this, true);
6429
- this.shapeDrawers = await pluginManager.getShapeDrawers(this, true);
6430
- this.particleUpdaters = await pluginManager.getUpdaters(this, true);
6799
+ this.effectDrawers = await getItemMapFromInitializer(this, pluginManager.initializers.effects);
6800
+ this.shapeDrawers = await getItemMapFromInitializer(this, pluginManager.initializers.shapes);
6801
+ this.particleUpdaters = await getItemsFromInitializer(this, pluginManager.initializers.updaters);
6431
6802
  }
6432
6803
  pause() {
6433
6804
  if (!guardCheck(this)) {
@@ -6538,6 +6909,27 @@
6538
6909
  }
6539
6910
  return refresh;
6540
6911
  }
6912
+ #initPlugins(allContainerPlugins) {
6913
+ this.plugins.length = 0;
6914
+ this.particleDestroyedPlugins.length = 0;
6915
+ this.particleCreatedPlugins.length = 0;
6916
+ this.particlePositionPlugins.length = 0;
6917
+ for (const [plugin, containerPlugin] of allContainerPlugins) {
6918
+ if (!plugin.needsPlugin(this.actualOptions)) {
6919
+ continue;
6920
+ }
6921
+ this.plugins.push(containerPlugin);
6922
+ if (containerPlugin.particleCreated) {
6923
+ this.particleCreatedPlugins.push(containerPlugin);
6924
+ }
6925
+ if (containerPlugin.particleDestroyed) {
6926
+ this.particleDestroyedPlugins.push(containerPlugin);
6927
+ }
6928
+ if (containerPlugin.particlePosition) {
6929
+ this.particlePositionPlugins.push(containerPlugin);
6930
+ }
6931
+ }
6932
+ }
6541
6933
  #nextFrame(timestamp) {
6542
6934
  try {
6543
6935
  if (!this.#smooth &&
@@ -6844,11 +7236,11 @@
6844
7236
  }
6845
7237
  }
6846
7238
  async #init() {
6847
- const availablePathGenerators = await this.#pluginManager.getPathGenerators?.(this.#container, true);
6848
- if (!availablePathGenerators) {
7239
+ const pluginManager = this.#pluginManager;
7240
+ if (!pluginManager.initializers.pathGenerators) {
6849
7241
  return;
6850
7242
  }
6851
- this.availablePathGenerators = availablePathGenerators;
7243
+ this.availablePathGenerators = await getItemMapFromInitializer(this.#container, pluginManager.initializers.pathGenerators);
6852
7244
  this.pathGenerators = new Map();
6853
7245
  for (const pathGenerator of this.pathGenerators.values()) {
6854
7246
  pathGenerator.init();
@@ -6952,28 +7344,12 @@
6952
7344
  }
6953
7345
  const html = interactivityEl, canvas = container.canvas;
6954
7346
  canvas.setPointerEvents(html === canvas.domElement ? "initial" : "none");
6955
- if (add && !(options.interactivity?.events.onHover.enable || options.interactivity?.events.onClick.enable)) {
6956
- return;
6957
- }
6958
7347
  manageListener(interactivityEl, mouseMoveEvent, handlers.mouseMove, add);
6959
7348
  manageListener(interactivityEl, touchStartEvent, handlers.touchStart, add);
6960
7349
  manageListener(interactivityEl, touchMoveEvent, handlers.touchMove, add);
6961
- if (add) {
6962
- if (options.interactivity?.events.onClick.enable) {
6963
- manageListener(interactivityEl, touchEndEvent, handlers.touchEndClick, add);
6964
- manageListener(interactivityEl, mouseUpEvent, handlers.mouseUp, add);
6965
- manageListener(interactivityEl, mouseDownEvent, handlers.mouseDown, add);
6966
- }
6967
- else {
6968
- manageListener(interactivityEl, touchEndEvent, handlers.touchEnd, add);
6969
- }
6970
- }
6971
- else {
6972
- manageListener(interactivityEl, touchEndEvent, handlers.touchEndClick, add);
6973
- manageListener(interactivityEl, mouseUpEvent, handlers.mouseUp, add);
6974
- manageListener(interactivityEl, mouseDownEvent, handlers.mouseDown, add);
6975
- manageListener(interactivityEl, touchEndEvent, handlers.touchEnd, add);
6976
- }
7350
+ manageListener(interactivityEl, touchEndEvent, options.interactivity?.events.onClick.enable ? handlers.touchEndClick : handlers.touchEnd, add);
7351
+ manageListener(interactivityEl, mouseUpEvent, handlers.mouseUp, add);
7352
+ manageListener(interactivityEl, mouseDownEvent, handlers.mouseDown, add);
6977
7353
  manageListener(interactivityEl, mouseLeaveEvent, handlers.mouseLeave, add);
6978
7354
  manageListener(interactivityEl, touchCancelEvent, handlers.touchCancel, add);
6979
7355
  }
@@ -6999,19 +7375,18 @@
6999
7375
  #mouseTouchClick(e) {
7000
7376
  const container = this.#container, interactionManager = this.#interactionManager, options = container.actualOptions, { mouse } = interactionManager.interactivityData;
7001
7377
  mouse.inside = true;
7002
- let handled = false;
7003
7378
  const mousePosition = mouse.position;
7004
- if (!mousePosition || !options.interactivity?.events.onClick.enable) {
7005
- return;
7006
- }
7007
- for (const plugin of this.#clickPositionPlugins) {
7008
- handled = plugin.clickPositionValid?.(mousePosition) ?? false;
7009
- if (handled) {
7010
- break;
7379
+ if (mousePosition && options.interactivity?.events.onClick.enable) {
7380
+ let handled = false;
7381
+ for (const plugin of this.#clickPositionPlugins) {
7382
+ handled = plugin.clickPositionValid?.(mousePosition) ?? false;
7383
+ if (handled) {
7384
+ break;
7385
+ }
7386
+ }
7387
+ if (!handled) {
7388
+ this.#doMouseTouchClick(e);
7011
7389
  }
7012
- }
7013
- if (!handled) {
7014
- this.#doMouseTouchClick(e);
7015
7390
  }
7016
7391
  mouse.clicking = false;
7017
7392
  }
@@ -7107,6 +7482,9 @@
7107
7482
  this.#touches.set(touch.identifier, performance.now());
7108
7483
  }
7109
7484
  this.#mouseTouchMove(e);
7485
+ const { mouse } = this.#interactionManager.interactivityData;
7486
+ mouse.clicking = true;
7487
+ mouse.downPosition = mouse.position;
7110
7488
  }
7111
7489
  }
7112
7490
 
@@ -7119,18 +7497,18 @@
7119
7497
  }
7120
7498
  class InteractionManager {
7121
7499
  interactivityData;
7500
+ interactors;
7122
7501
  #clickHandlers;
7123
7502
  #container;
7124
7503
  #eventListeners;
7125
7504
  #externalInteractors;
7126
- #interactors;
7127
7505
  #intersectionObserver;
7128
7506
  #particleInteractors;
7129
7507
  #pluginManager;
7130
7508
  constructor(pluginManager, container) {
7131
7509
  this.#container = container;
7132
7510
  this.#pluginManager = pluginManager;
7133
- this.#interactors = [];
7511
+ this.interactors = [];
7134
7512
  this.#externalInteractors = [];
7135
7513
  this.#particleInteractors = [];
7136
7514
  this.#clickHandlers = new Map();
@@ -7249,7 +7627,7 @@
7249
7627
  }
7250
7628
  init() {
7251
7629
  this.#eventListeners.init();
7252
- for (const interactor of this.#interactors) {
7630
+ for (const interactor of this.interactors) {
7253
7631
  switch (interactor.type) {
7254
7632
  case InteractorType.external:
7255
7633
  this.#externalInteractors.push(interactor);
@@ -7262,11 +7640,11 @@
7262
7640
  }
7263
7641
  }
7264
7642
  async initInteractors() {
7265
- const interactors = await this.#pluginManager.getInteractors?.(this.#container, true);
7266
- if (!interactors) {
7643
+ const pluginManager = this.#pluginManager;
7644
+ if (!pluginManager.initializers.interactors) {
7267
7645
  return;
7268
7646
  }
7269
- this.#interactors = interactors;
7647
+ this.interactors = await getItemsFromInitializer(this.#container, pluginManager.initializers.interactors);
7270
7648
  this.#externalInteractors = [];
7271
7649
  this.#particleInteractors = [];
7272
7650
  }
@@ -7311,13 +7689,13 @@
7311
7689
  }
7312
7690
  updateMaxDistance() {
7313
7691
  let maxTotalDistance = 0;
7314
- for (const interactor of this.#interactors) {
7692
+ for (const interactor of this.interactors) {
7315
7693
  if (interactor.maxDistance > maxTotalDistance) {
7316
7694
  maxTotalDistance = interactor.maxDistance;
7317
7695
  }
7318
7696
  }
7319
7697
  const container = this.#container;
7320
- container.particles.grid.setCellSize(maxTotalDistance * container.retina.pixelRatio);
7698
+ container.particles.grid.cellSize = maxTotalDistance * container.retina.pixelRatio;
7321
7699
  }
7322
7700
  #intersectionManager(entries) {
7323
7701
  const container = this.#container;
@@ -7339,59 +7717,59 @@
7339
7717
  }
7340
7718
 
7341
7719
  class InteractivityPluginInstance {
7342
- interactionManager;
7343
7720
  #container;
7344
- #pluginManager;
7345
7721
  constructor(pluginManager, container) {
7346
- this.#container = container;
7347
- this.#pluginManager = pluginManager;
7348
- this.interactionManager = new InteractionManager(pluginManager, container);
7349
- this.#container.addClickHandler = (callback) => {
7350
- this.interactionManager.addClickHandler(callback);
7722
+ container.addClickHandler = (callback) => {
7723
+ container.interactionManager?.addClickHandler(callback);
7351
7724
  };
7725
+ container.interactionManager = new InteractionManager(pluginManager, container);
7726
+ this.#container = container;
7352
7727
  }
7353
7728
  addClickHandler(callback) {
7354
- this.interactionManager.addClickHandler(callback);
7729
+ this.#container.interactionManager?.addClickHandler(callback);
7355
7730
  }
7356
7731
  clearClickHandlers() {
7357
- this.interactionManager.clearClickHandlers();
7732
+ this.#container.interactionManager?.clearClickHandlers();
7358
7733
  }
7359
7734
  destroy() {
7360
7735
  this.clearClickHandlers();
7361
- this.#pluginManager.interactors?.delete(this.#container);
7362
7736
  }
7363
7737
  particleCreated(particle) {
7364
- const interactivityParticle = particle, interactivity = new Interactivity(this.#pluginManager, this.#container);
7365
- interactivity.load(this.#container.actualOptions.interactivity);
7738
+ const interactivityParticle = particle, container = this.#container, interactivity = new Interactivity(container);
7739
+ interactivity.load(container.actualOptions.interactivity);
7366
7740
  interactivity.load(interactivityParticle.options.interactivity);
7367
7741
  interactivityParticle.interactivity = interactivity;
7368
7742
  }
7369
7743
  particleReset(particle) {
7370
- this.interactionManager.reset(particle);
7744
+ this.#container.interactionManager?.reset(particle);
7371
7745
  }
7372
7746
  postParticleUpdate(particle, delta) {
7373
- this.interactionManager.particlesInteract(particle, delta);
7747
+ this.#container.interactionManager?.particlesInteract(particle, delta);
7374
7748
  }
7375
7749
  postUpdate(delta) {
7376
- this.interactionManager.externalInteract(delta);
7377
- this.interactionManager.updateMaxDistance();
7750
+ const container = this.#container;
7751
+ container.interactionManager?.externalInteract(delta);
7752
+ container.interactionManager?.updateMaxDistance();
7378
7753
  }
7379
7754
  async preInit() {
7380
- await this.interactionManager.initInteractors();
7381
- this.interactionManager.init();
7755
+ const container = this.#container;
7756
+ await container.interactionManager?.initInteractors();
7757
+ container.interactionManager?.init();
7382
7758
  }
7383
7759
  async redrawInit() {
7384
- await this.interactionManager.initInteractors();
7385
- this.interactionManager.init();
7760
+ const container = this.#container;
7761
+ await container.interactionManager?.initInteractors();
7762
+ container.interactionManager?.init();
7386
7763
  }
7387
7764
  start() {
7388
- this.interactionManager.addListeners();
7389
- this.interactionManager.startObserving();
7765
+ const container = this.#container;
7766
+ container.interactionManager?.addListeners();
7767
+ container.interactionManager?.startObserving();
7390
7768
  return Promise.resolve();
7391
7769
  }
7392
7770
  stop() {
7393
- this.interactionManager.removeListeners();
7394
- this.interactionManager.stopObserving();
7771
+ this.#container.interactionManager?.removeListeners();
7772
+ this.#container.interactionManager?.stopObserving();
7395
7773
  }
7396
7774
  }
7397
7775
 
@@ -7420,7 +7798,7 @@
7420
7798
  }
7421
7799
  const retries = overlapOptions.retries;
7422
7800
  if (retries >= minRetries && tryCount > retries) {
7423
- throw new Error(`Particle is overlapping and can't be placed`);
7801
+ throw new Error(getErrorMessage(ErrorCodes.overlapNotPlaced));
7424
7802
  }
7425
7803
  return !!this.#container.particles.find(p => getDistance(pos, p.position) < particle.getRadius() + p.getRadius());
7426
7804
  }
@@ -7620,6 +7998,7 @@
7620
7998
  exports.BaseRange = BaseRange;
7621
7999
  exports.Circle = Circle;
7622
8000
  exports.ColorAnimation = ColorAnimation;
8001
+ exports.ErrorCodes = ErrorCodes$3;
7623
8002
  exports.Fill = Fill;
7624
8003
  exports.FullScreen = FullScreen;
7625
8004
  exports.HDROptions = HDROptions;
@@ -7651,6 +8030,7 @@
7651
8030
  exports.Vector = Vector;
7652
8031
  exports.Vector3d = Vector3d;
7653
8032
  exports.ZIndex = ZIndex;
8033
+ exports.addErrorMessages = addErrorMessages;
7654
8034
  exports.alterHsl = alterHsl;
7655
8035
  exports.animate = animate;
7656
8036
  exports.areBoundsInside = areBoundsInside;
@@ -7673,7 +8053,7 @@
7673
8053
  exports.countOffset = countOffset;
7674
8054
  exports.decayOffset = decayOffset;
7675
8055
  exports.deepExtend = deepExtend;
7676
- exports.defaultAlpha = defaultAlpha$1;
8056
+ exports.defaultAlpha = defaultAlpha;
7677
8057
  exports.defaultAngle = defaultAngle;
7678
8058
  exports.defaultCompositeValue = defaultCompositeValue;
7679
8059
  exports.defaultDensityFactor = defaultDensityFactor;
@@ -7697,12 +8077,17 @@
7697
8077
  exports.doublePI = doublePI;
7698
8078
  exports.empty = empty;
7699
8079
  exports.executeOnSingleOrMultiple = executeOnSingleOrMultiple;
8080
+ exports.fullPercent = fullPercent;
7700
8081
  exports.generatedAttribute = generatedAttribute;
7701
8082
  exports.generatedFalse = generatedFalse;
7702
8083
  exports.generatedTrue = generatedTrue;
8084
+ exports.getCanvasFromContainer = getCanvasFromContainer;
8085
+ exports.getDataFromUrl = getDataFromUrl;
7703
8086
  exports.getDistance = getDistance;
7704
8087
  exports.getDistanceSq = getDistanceSq;
7705
8088
  exports.getDistances = getDistances;
8089
+ exports.getDomContainer = getDomContainer;
8090
+ exports.getErrorMessage = getErrorMessage;
7706
8091
  exports.getFullScreenStyle = getFullScreenStyle;
7707
8092
  exports.getHslAnimationFromHsl = getHslAnimationFromHsl;
7708
8093
  exports.getHslFromAnimation = getHslFromAnimation;
@@ -7734,6 +8119,7 @@
7734
8119
  exports.inverseFactorNumerator = inverseFactorNumerator;
7735
8120
  exports.isArray = isArray;
7736
8121
  exports.isBoolean = isBoolean;
8122
+ exports.isEnumValue = isEnumValue;
7737
8123
  exports.isFunction = isFunction;
7738
8124
  exports.isInArray = isInArray;
7739
8125
  exports.isNull = isNull;
@@ -7766,7 +8152,7 @@
7766
8152
  exports.minFpsLimit = minFpsLimit;
7767
8153
  exports.minIndex = minIndex;
7768
8154
  exports.minLimit = minLimit;
7769
- exports.minRadius = minRadius$1;
8155
+ exports.minRadius = minRadius;
7770
8156
  exports.minStrokeWidth = minStrokeWidth;
7771
8157
  exports.minVelocity = minVelocity;
7772
8158
  exports.minZ = minZ;
@@ -7805,6 +8191,7 @@
7805
8191
  exports.stringToAlpha = stringToAlpha;
7806
8192
  exports.stringToRgb = stringToRgb;
7807
8193
  exports.threeQuarter = threeQuarter;
8194
+ exports.toEnumValue = toEnumValue;
7808
8195
  exports.triple = triple;
7809
8196
  exports.tryCountIncrement = tryCountIncrement;
7810
8197
  exports.tsParticles = tsParticles;
@@ -7813,10 +8200,11 @@
7813
8200
  exports.visibilityChangeEvent = visibilityChangeEvent;
7814
8201
  exports.zIndexFactorOffset = zIndexFactorOffset;
7815
8202
 
7816
- }));
8203
+ })(g.__tsParticlesInternals.bundles.particles = g.__tsParticlesInternals.bundles.particles || {});
8204
+ })(typeof globalThis !== "undefined" ? globalThis : typeof window !== "undefined" ? window : self);
8205
+
7817
8206
  Object.assign(globalThis.window || globalThis, { loadExtendProperty: (globalThis.__tsParticlesInternals.bundles.particles || {}).loadExtendProperty, loadLazyProperty: (globalThis.__tsParticlesInternals.bundles.particles || {}).loadLazyProperty, loadMinIndex: (globalThis.__tsParticlesInternals.bundles.particles || {}).loadMinIndex, loadNestedProperty: (globalThis.__tsParticlesInternals.bundles.particles || {}).loadNestedProperty, loadOptionProperty: (globalThis.__tsParticlesInternals.bundles.particles || {}).loadOptionProperty, loadOptions: (globalThis.__tsParticlesInternals.bundles.particles || {}).loadOptions, loadParticlesOptions: (globalThis.__tsParticlesInternals.bundles.particles || {}).loadParticlesOptions, loadProperty: (globalThis.__tsParticlesInternals.bundles.particles || {}).loadProperty, loadRandomFactor: (globalThis.__tsParticlesInternals.bundles.particles || {}).loadRandomFactor, loadRangeProperty: (globalThis.__tsParticlesInternals.bundles.particles || {}).loadRangeProperty, tsParticles: (globalThis.__tsParticlesInternals.bundles.particles || {}).tsParticles });
7818
8207
  globalThis.__tsParticlesInternals = globalThis.__tsParticlesInternals || {};
7819
8208
  if (!globalThis.__tsParticlesInternals.engine || !globalThis.__tsParticlesInternals.engine.tsParticles) {
7820
8209
  globalThis.__tsParticlesInternals.engine = globalThis.__tsParticlesInternals.bundles.particles || {};
7821
8210
  }
7822
- delete (globalThis.window || globalThis).tsparticlesInternalExports;