@tsparticles/particles 4.4.0 → 4.5.1

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.1 */
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 {
@@ -572,12 +737,8 @@
572
737
  }
573
738
  addEventListener(type, listener) {
574
739
  this.removeEventListener(type, listener);
575
- let arr = this.#listeners.get(type);
576
- if (!arr) {
577
- arr = [];
578
- this.#listeners.set(type, arr);
579
- }
580
- arr.push(listener);
740
+ const arr = this.#listeners.get(type);
741
+ this.#listeners.set(type, arr ? [...arr, listener] : [listener]);
581
742
  }
582
743
  dispatchEvent(type, args) {
583
744
  const listeners = this.#listeners.get(type);
@@ -609,7 +770,7 @@
609
770
  this.#listeners.delete(type);
610
771
  }
611
772
  else {
612
- arr.splice(idx, deleteCount);
773
+ this.#listeners.set(type, [...arr.slice(minIndex, idx), ...arr.slice(idx + deleteCount)]);
613
774
  }
614
775
  }
615
776
  }
@@ -633,7 +794,6 @@
633
794
  class PluginManager {
634
795
  colorManagers = new Map();
635
796
  easingFunctions = new Map();
636
- effectDrawers = new Map();
637
797
  initializers = {
638
798
  effects: new Map(),
639
799
  shapes: new Map(),
@@ -642,8 +802,6 @@
642
802
  palettes = new Map();
643
803
  plugins = [];
644
804
  presets = new Map();
645
- shapeDrawers = new Map();
646
- updaters = new Map();
647
805
  #allLoadersSet = new Set();
648
806
  #configs = new Map();
649
807
  #engine;
@@ -661,57 +819,79 @@
661
819
  }
662
820
  return res;
663
821
  }
822
+ get initialized() {
823
+ return this.#initialized;
824
+ }
664
825
  addColorManager(name, manager) {
826
+ if (this.#initialized) {
827
+ return;
828
+ }
665
829
  this.colorManagers.set(name, manager);
666
830
  }
667
831
  addConfig(config) {
832
+ if (this.#initialized) {
833
+ return;
834
+ }
668
835
  const key = config.key ?? config.name ?? "default";
669
836
  this.#configs.set(key, config);
670
837
  this.#engine.dispatchEvent(exports.EventType.configAdded, { data: { name: key, config } });
671
838
  }
672
839
  addEasing(name, easing) {
840
+ if (this.#initialized) {
841
+ return;
842
+ }
673
843
  if (this.easingFunctions.get(name)) {
674
844
  return;
675
845
  }
676
846
  this.easingFunctions.set(name, easing);
677
847
  }
678
848
  addEffect(effect, drawer) {
849
+ if (this.#initialized) {
850
+ return;
851
+ }
679
852
  this.initializers.effects.set(effect, drawer);
680
853
  }
681
854
  addPalette(name, palette) {
855
+ if (this.#initialized) {
856
+ return;
857
+ }
682
858
  this.palettes.set(name, palette);
683
859
  }
684
860
  addParticleUpdater(name, updaterInitializer) {
861
+ if (this.#initialized) {
862
+ return;
863
+ }
685
864
  this.initializers.updaters.set(name, updaterInitializer);
686
865
  }
687
866
  addPlugin(plugin) {
867
+ if (this.#initialized) {
868
+ return;
869
+ }
688
870
  if (this.getPlugin(plugin.id)) {
689
871
  return;
690
872
  }
691
873
  this.plugins.push(plugin);
692
874
  }
693
875
  addPreset(preset, options, override = false) {
876
+ if (this.#initialized) {
877
+ return;
878
+ }
694
879
  if (!(override || !this.getPreset(preset))) {
695
880
  return;
696
881
  }
697
882
  this.presets.set(preset, options);
698
883
  }
699
884
  addShape(shapes, drawer) {
885
+ if (this.#initialized) {
886
+ return;
887
+ }
700
888
  for (const shape of shapes) {
701
889
  this.initializers.shapes.set(shape, drawer);
702
890
  }
703
891
  }
704
- clearPlugins(container) {
705
- this.effectDrawers.delete(container);
706
- this.shapeDrawers.delete(container);
707
- this.updaters.delete(container);
708
- }
709
892
  getEasing(name) {
710
893
  return this.easingFunctions.get(name) ?? ((value) => value);
711
894
  }
712
- getEffectDrawers(container, force = false) {
713
- return getItemMapFromInitializer(container, this.effectDrawers, this.initializers.effects, force);
714
- }
715
895
  getPalette(name) {
716
896
  return this.palettes.get(name);
717
897
  }
@@ -721,12 +901,6 @@
721
901
  getPreset(preset) {
722
902
  return this.presets.get(preset);
723
903
  }
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
904
  async init() {
731
905
  if (this.#initialized || this.#isRunningLoaders) {
732
906
  return;
@@ -745,16 +919,9 @@
745
919
  this.#initialized = true;
746
920
  }
747
921
  }
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
922
  async register(...loaders) {
756
923
  if (this.#initialized) {
757
- throw new Error("Register plugins can only be done before calling tsParticles.load()");
924
+ throw new Error(getErrorMessage(ErrorCodes$3.pluginRegisterAfterLoad));
758
925
  }
759
926
  for (const loader of loaders) {
760
927
  if (this.#isRunningLoaders) {
@@ -766,111 +933,15 @@
766
933
  }
767
934
  }
768
935
  async #runLoader(loader, executed, allLoaders) {
769
- if (executed.has(loader))
936
+ if (executed.has(loader)) {
770
937
  return;
938
+ }
771
939
  executed.add(loader);
772
940
  allLoaders.add(loader);
773
941
  await loader(this.#engine);
774
942
  }
775
943
  }
776
944
 
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
945
  class Engine {
875
946
  pluginManager = new PluginManager(this);
876
947
  #domArray = [];
@@ -880,7 +951,7 @@
880
951
  return this.#domArray;
881
952
  }
882
953
  get version() {
883
- return "4.4.0";
954
+ return "4.5.1";
884
955
  }
885
956
  addEventListener(type, listener) {
886
957
  this.#eventDispatcher.addEventListener(type, listener);
@@ -889,7 +960,7 @@
889
960
  if (this.version === pluginVersion) {
890
961
  return;
891
962
  }
892
- throw new Error(`The tsParticles version is different from the loaded plugins version. Engine version: ${this.version}. Plugin version: ${pluginVersion}`);
963
+ throw new Error(getErrorMessage(ErrorCodes$3.engineVersionMismatch, this.version, pluginVersion));
893
964
  }
894
965
  dispatchEvent(type, args) {
895
966
  this.#eventDispatcher.dispatchEvent(type, args);
@@ -1126,31 +1197,17 @@
1126
1197
  AnimationStatus["decreasing"] = "decreasing";
1127
1198
  })(exports.AnimationStatus || (exports.AnimationStatus = {}));
1128
1199
 
1129
- exports.DrawLayer = void 0;
1130
- (function (DrawLayer) {
1131
- DrawLayer[DrawLayer["BackgroundElement"] = 0] = "BackgroundElement";
1132
- DrawLayer[DrawLayer["BackgroundDraw"] = 1] = "BackgroundDraw";
1133
- DrawLayer[DrawLayer["BackgroundMask"] = 2] = "BackgroundMask";
1134
- DrawLayer[DrawLayer["CanvasSetup"] = 3] = "CanvasSetup";
1135
- DrawLayer[DrawLayer["PluginContent"] = 4] = "PluginContent";
1136
- DrawLayer[DrawLayer["Particles"] = 5] = "Particles";
1137
- DrawLayer[DrawLayer["CanvasCleanup"] = 6] = "CanvasCleanup";
1138
- DrawLayer[DrawLayer["Foreground"] = 7] = "Foreground";
1139
- })(exports.DrawLayer || (exports.DrawLayer = {}));
1140
-
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
- }
1200
+ exports.DrawLayer = void 0;
1201
+ (function (DrawLayer) {
1202
+ DrawLayer[DrawLayer["BackgroundElement"] = 0] = "BackgroundElement";
1203
+ DrawLayer[DrawLayer["BackgroundDraw"] = 1] = "BackgroundDraw";
1204
+ DrawLayer[DrawLayer["BackgroundMask"] = 2] = "BackgroundMask";
1205
+ DrawLayer[DrawLayer["CanvasSetup"] = 3] = "CanvasSetup";
1206
+ DrawLayer[DrawLayer["PluginContent"] = 4] = "PluginContent";
1207
+ DrawLayer[DrawLayer["Particles"] = 5] = "Particles";
1208
+ DrawLayer[DrawLayer["CanvasCleanup"] = 6] = "CanvasCleanup";
1209
+ DrawLayer[DrawLayer["Foreground"] = 7] = "Foreground";
1210
+ })(exports.DrawLayer || (exports.DrawLayer = {}));
1154
1211
 
1155
1212
  function loadProperty(obj, key, value) {
1156
1213
  if (value !== undefined) {
@@ -1180,7 +1237,7 @@
1180
1237
  if (keyStr === "__proto__" || keyStr === "constructor" || keyStr === "prototype") {
1181
1238
  return;
1182
1239
  }
1183
- const objRecord = obj, currentValue = Object.prototype.hasOwnProperty.call(objRecord, keyStr) ? objRecord[keyStr] : {};
1240
+ const objRecord = obj, currentValue = Object.hasOwn(objRecord, keyStr) ? objRecord[keyStr] : {};
1184
1241
  objRecord[keyStr] = deepExtend(currentValue, value);
1185
1242
  }
1186
1243
  }
@@ -1193,6 +1250,20 @@
1193
1250
  }
1194
1251
  }
1195
1252
 
1253
+ class OptionLoader {
1254
+ load(data) {
1255
+ if (isNull(data)) {
1256
+ return;
1257
+ }
1258
+ this.doLoad(data);
1259
+ }
1260
+ }
1261
+ function loadOptions(options, ...sourceOptionsArr) {
1262
+ for (const sourceOptions of sourceOptionsArr) {
1263
+ options.load(sourceOptions);
1264
+ }
1265
+ }
1266
+
1196
1267
  class AnimationOptions extends OptionLoader {
1197
1268
  count = 0;
1198
1269
  decay = 0;
@@ -1343,15 +1414,14 @@
1343
1414
  peakNits = defaultPeakNits;
1344
1415
  doLoad(data) {
1345
1416
  if (data.enable !== undefined && !isBoolean(data.enable)) {
1346
- throw new Error(`Invalid HDR "enable" value: expected a boolean, got "${String(data.enable)}"`);
1417
+ throw new Error(getErrorMessage(ErrorCodes$3.hdrEnableInvalid, String(data.enable)));
1347
1418
  }
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)}"`);
1419
+ if (data.mode !== undefined && !isEnumValue(exports.HdrMode, data.mode)) {
1420
+ throw new Error(getErrorMessage(ErrorCodes$3.hdrModeInvalid, Object.values(exports.HdrMode).join(", "), toStringValue(data.mode)));
1351
1421
  }
1352
1422
  if (data.peakNits !== undefined &&
1353
1423
  (!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)}"`);
1424
+ throw new Error(getErrorMessage(ErrorCodes$3.hdrPeakNitsInvalid, String(data.peakNits)));
1355
1425
  }
1356
1426
  loadProperty(this, "enable", data.enable);
1357
1427
  loadProperty(this, "mode", data.mode);
@@ -1729,12 +1799,10 @@
1729
1799
  plugin.loadParticlesOptions(this.#container, this, data);
1730
1800
  }
1731
1801
  }
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
- }
1802
+ const updaters = this.#container.particleUpdaters;
1803
+ for (const updater of updaters) {
1804
+ if (updater.loadOptions) {
1805
+ updater.loadOptions(this, data);
1738
1806
  }
1739
1807
  }
1740
1808
  }
@@ -2076,9 +2144,9 @@
2076
2144
  const grayscaleValue = Math.round(lNormalized * rgbMax);
2077
2145
  return { r: grayscaleValue, g: grayscaleValue, b: grayscaleValue };
2078
2146
  }
2079
- const temp1 = lNormalized < half
2147
+ const temp2 = lNormalized < half
2080
2148
  ? 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));
2149
+ : 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
2150
  return { r: Math.round(red), g: Math.round(green), b: Math.round(blue) };
2083
2151
  }
2084
2152
  function hslToRgbFloat(hsl) {
@@ -2087,9 +2155,9 @@
2087
2155
  const grayscaleValue = lNormalized * rgbMax;
2088
2156
  return { r: grayscaleValue, g: grayscaleValue, b: grayscaleValue };
2089
2157
  }
2090
- const temp1 = lNormalized < half
2158
+ const temp2 = lNormalized < half
2091
2159
  ? 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));
2160
+ : 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
2161
  return { r: red, g: green, b: blue };
2094
2162
  }
2095
2163
  function hslaToRgba(hsla) {
@@ -2449,7 +2517,7 @@
2449
2517
  }
2450
2518
 
2451
2519
  async function loadBlendPlugin(engine) {
2452
- engine.checkVersion("4.4.0");
2520
+ engine.checkVersion("4.5.1");
2453
2521
  await engine.pluginManager.register(e => {
2454
2522
  e.pluginManager.addPlugin(new BlendPlugin());
2455
2523
  });
@@ -2486,7 +2554,7 @@
2486
2554
  }
2487
2555
 
2488
2556
  async function loadCircleShape(engine) {
2489
- engine.checkVersion("4.4.0");
2557
+ engine.checkVersion("4.5.1");
2490
2558
  await engine.pluginManager.register(e => {
2491
2559
  e.pluginManager.addShape(["circle"], () => {
2492
2560
  return Promise.resolve(new CircleDrawer());
@@ -2501,7 +2569,7 @@
2501
2569
  RgbIndexes[RgbIndexes["b"] = 3] = "b";
2502
2570
  RgbIndexes[RgbIndexes["a"] = 4] = "a";
2503
2571
  })(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;
2572
+ 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
2573
  class HexColorManager {
2506
2574
  accepts(input) {
2507
2575
  return input.startsWith("#");
@@ -2534,7 +2602,7 @@
2534
2602
  }
2535
2603
 
2536
2604
  async function loadHexColorPlugin(engine) {
2537
- engine.checkVersion("4.4.0");
2605
+ engine.checkVersion("4.5.1");
2538
2606
  await engine.pluginManager.register(e => {
2539
2607
  e.pluginManager.addColorManager("hex", new HexColorManager());
2540
2608
  });
@@ -2574,7 +2642,7 @@
2574
2642
  if (!this.accepts(input)) {
2575
2643
  return;
2576
2644
  }
2577
- const result = hslRegex.exec(input), minLength = 4, defaultAlpha = 1, radix = 10;
2645
+ const result = hslRegex.exec(input), minLength = 4, radix = 10;
2578
2646
  return result
2579
2647
  ? hslaToRgba({
2580
2648
  a: result.length > minLength ? parseAlpha(result[HslIndexes.a]) : defaultAlpha,
@@ -2587,12 +2655,20 @@
2587
2655
  }
2588
2656
 
2589
2657
  async function loadHslColorPlugin(engine) {
2590
- engine.checkVersion("4.4.0");
2658
+ engine.checkVersion("4.5.1");
2591
2659
  await engine.pluginManager.register(e => {
2592
2660
  e.pluginManager.addColorManager("hsl", new HslColorManager());
2593
2661
  });
2594
2662
  }
2595
2663
 
2664
+ const ErrorCodes$2 = {
2665
+ baseMoverNotLoaded: "TSP-3203",
2666
+ };
2667
+
2668
+ const ErrorMessages$2 = {
2669
+ [ErrorCodes$2.baseMoverNotLoaded]: "tsParticles Base Mover is not loaded",
2670
+ };
2671
+
2596
2672
  class MovePlugin {
2597
2673
  id = "move";
2598
2674
  #pluginManager;
@@ -2611,20 +2687,20 @@
2611
2687
  }
2612
2688
 
2613
2689
  async function loadMovePlugin(engine) {
2614
- engine.checkVersion("4.4.0");
2690
+ engine.checkVersion("4.5.1");
2691
+ if (typeof process !== "undefined" && process.env.NODE_ENV !== "production") {
2692
+ addErrorMessages(ErrorMessages$2);
2693
+ }
2615
2694
  await engine.pluginManager.register(e => {
2616
2695
  const moveEngine = e, movePluginManager = moveEngine.pluginManager;
2617
2696
  movePluginManager.initializers.pathGenerators ??= new Map();
2618
- movePluginManager.pathGenerators ??= new Map();
2619
2697
  movePluginManager.addPathGenerator = (name, generator) => {
2698
+ if (movePluginManager.initialized) {
2699
+ return;
2700
+ }
2620
2701
  movePluginManager.initializers.pathGenerators ??= new Map();
2621
2702
  movePluginManager.initializers.pathGenerators.set(name, generator);
2622
2703
  };
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
2704
  e.pluginManager.addPlugin(new MovePlugin(e.pluginManager));
2629
2705
  });
2630
2706
  }
@@ -2821,7 +2897,7 @@
2821
2897
  }
2822
2898
 
2823
2899
  async function loadOpacityUpdater(engine) {
2824
- engine.checkVersion("4.4.0");
2900
+ engine.checkVersion("4.5.1");
2825
2901
  await engine.pluginManager.register(e => {
2826
2902
  e.pluginManager.addParticleUpdater("opacity", container => {
2827
2903
  return Promise.resolve(new OpacityUpdater(container));
@@ -2830,70 +2906,60 @@
2830
2906
  }
2831
2907
 
2832
2908
  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)) {
2909
+ const bounceAxisConfigs = {
2910
+ [exports.OutModeDirection.left]: {
2911
+ axis: "x",
2912
+ canvas: "width",
2913
+ bounce: "horizontal",
2914
+ negativeEdge: "right",
2915
+ positiveEdge: "left",
2916
+ negative: true,
2917
+ },
2918
+ [exports.OutModeDirection.right]: {
2919
+ axis: "x",
2920
+ canvas: "width",
2921
+ bounce: "horizontal",
2922
+ negativeEdge: "right",
2923
+ positiveEdge: "left",
2924
+ negative: false,
2925
+ },
2926
+ [exports.OutModeDirection.top]: {
2927
+ axis: "y",
2928
+ canvas: "height",
2929
+ bounce: "vertical",
2930
+ negativeEdge: "bottom",
2931
+ positiveEdge: "top",
2932
+ negative: true,
2933
+ },
2934
+ [exports.OutModeDirection.bottom]: {
2935
+ axis: "y",
2936
+ canvas: "height",
2937
+ bounce: "vertical",
2938
+ negativeEdge: "bottom",
2939
+ positiveEdge: "top",
2940
+ negative: false,
2941
+ },
2942
+ };
2943
+ function bounce$1(data) {
2944
+ if ((data.outMode !== exports.OutMode.bounce && data.outMode !== exports.OutMode.split) || !(data.direction in bounceAxisConfigs)) {
2870
2945
  return;
2871
2946
  }
2872
- if (data.bounds.bottom < boundsMin && data.direction === exports.OutModeDirection.top) {
2873
- data.particle.position.y = data.size + data.offset.y;
2947
+ const config = bounceAxisConfigs[data.direction], bounds = data.bounds, canvasDim = data.canvasSize[config.canvas], position = data.particle.position, velocity = data.particle.velocity[config.axis];
2948
+ if (config.negative && bounds[config.negativeEdge] < boundsMin) {
2949
+ position[config.axis] = data.size + data.offset[config.axis];
2874
2950
  }
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;
2951
+ else if (!config.negative && bounds[config.positiveEdge] > canvasDim) {
2952
+ position[config.axis] = canvasDim - data.size - data.offset[config.axis];
2877
2953
  }
2878
- const velocity = data.particle.velocity.y;
2879
- let bounced = false;
2880
2954
  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;
2955
+ ((config.negative && velocity < minVelocity) || (!config.negative && velocity > minVelocity))) {
2956
+ data.particle.velocity[config.axis] *= -getRangeValue(data.particle.options.bounce[config.bounce].value);
2886
2957
  }
2887
- if (!bounced) {
2958
+ else {
2888
2959
  return;
2889
2960
  }
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
- }
2961
+ const minPos = data.offset[config.axis] + data.size;
2962
+ position[config.axis] = config.negative ? minPos : canvasDim - minPos;
2897
2963
  if (data.outMode === exports.OutMode.split) {
2898
2964
  data.particle.destroy();
2899
2965
  }
@@ -2909,26 +2975,19 @@
2909
2975
  exports.OutMode.bounce,
2910
2976
  exports.OutMode.split,
2911
2977
  ];
2912
- this.#particleBouncePlugins = container.plugins.filter(p => p.particleBounce !== undefined);
2978
+ this.#particleBouncePlugins = container.plugins.filter(p => !!p.particleBounce);
2913
2979
  }
2914
2980
  update(particle, direction, delta, outMode) {
2915
2981
  if (!this.modes.includes(outMode)) {
2916
2982
  return;
2917
2983
  }
2918
- const container = this.#container;
2919
- let handled = false;
2920
2984
  for (const plugin of this.#particleBouncePlugins) {
2921
- handled = plugin.particleBounce?.(particle, delta, direction) ?? false;
2922
- if (handled) {
2923
- break;
2985
+ if (plugin.particleBounce?.(particle, delta, direction)) {
2986
+ return;
2924
2987
  }
2925
2988
  }
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 });
2989
+ const pos = particle.getPosition(), offset = particle.offset, size = particle.getRadius(), bounds = calculateBounds(pos, size), canvasSize = this.#container.canvas.size, outOfCanvas = !particle.isInsideCanvasForOutMode(outMode, direction);
2990
+ bounce$1({ particle, outMode, direction, bounds, canvasSize, offset, outOfCanvas, size });
2932
2991
  }
2933
2992
  }
2934
2993
 
@@ -3017,107 +3076,108 @@
3017
3076
  return;
3018
3077
  }
3019
3078
  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;
3079
+ if (particle.outType === exports.ParticleOutType.inside) {
3080
+ this.#applyOutModeInside(particle, container);
3081
+ }
3082
+ else {
3083
+ if (particle.isInsideCanvasForOutMode(outMode, direction)) {
3084
+ return;
3047
3085
  }
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;
3086
+ if (particle.outType === exports.ParticleOutType.outside) {
3087
+ this.#applyParticleModeOutside(particle);
3119
3088
  }
3120
- }
3089
+ else {
3090
+ this.#applyOutModeNormal(particle, container, direction);
3091
+ }
3092
+ }
3093
+ }
3094
+ #applyOutModeInside(particle, container) {
3095
+ const { x: vx, y: vy } = particle.velocity;
3096
+ updateVector.setTo(originPoint);
3097
+ updateVector.length = particle.moveCenter.radius;
3098
+ updateVector.angle = particle.velocity.angle + Math.PI;
3099
+ updateVector.addTo(particle.moveCenter);
3100
+ const { dx, dy } = getDistances(particle.position, updateVector);
3101
+ if ((vx <= minVelocity && dx >= minDistance$2) ||
3102
+ (vy <= minVelocity && dy >= minDistance$2) ||
3103
+ (vx >= minVelocity && dx <= minDistance$2) ||
3104
+ (vy >= minVelocity && dy <= minDistance$2)) {
3105
+ return;
3106
+ }
3107
+ particle.position.x = Math.floor(randomInRangeValue({
3108
+ min: 0,
3109
+ max: container.canvas.size.width,
3110
+ }));
3111
+ particle.position.y = Math.floor(randomInRangeValue({
3112
+ min: 0,
3113
+ max: container.canvas.size.height,
3114
+ }));
3115
+ const { dx: newDx, dy: newDy } = getDistances(particle.position, particle.moveCenter);
3116
+ particle.direction = Math.atan2(-newDy, -newDx);
3117
+ particle.velocity.angle = particle.direction;
3118
+ particle.justWarped = true;
3119
+ }
3120
+ #applyOutModeNormal(particle, container, direction) {
3121
+ const warp = particle.options.move.warp, canvasSize = container.canvas.size, sizeValue = particle.getRadius(), newPos = {
3122
+ bottom: canvasSize.height + sizeValue + particle.offset.y,
3123
+ left: -sizeValue - particle.offset.x,
3124
+ right: canvasSize.width + sizeValue + particle.offset.x,
3125
+ top: -sizeValue - particle.offset.y,
3126
+ }, nextBounds = calculateBounds(particle.position, sizeValue);
3127
+ if (direction === exports.OutModeDirection.right && nextBounds.left > canvasSize.width + particle.offset.x) {
3128
+ particle.position.x = newPos.left;
3129
+ particle.initialPosition.x = particle.position.x;
3130
+ if (!warp) {
3131
+ particle.position.y = getRandom() * canvasSize.height;
3132
+ particle.initialPosition.y = particle.position.y;
3133
+ }
3134
+ particle.justWarped = true;
3135
+ }
3136
+ else if (direction === exports.OutModeDirection.left && nextBounds.right < -particle.offset.x) {
3137
+ particle.position.x = newPos.right;
3138
+ particle.initialPosition.x = particle.position.x;
3139
+ if (!warp) {
3140
+ particle.position.y = getRandom() * canvasSize.height;
3141
+ particle.initialPosition.y = particle.position.y;
3142
+ }
3143
+ particle.justWarped = true;
3144
+ }
3145
+ if (direction === exports.OutModeDirection.bottom && nextBounds.top > canvasSize.height + particle.offset.y) {
3146
+ if (!warp) {
3147
+ particle.position.x = getRandom() * canvasSize.width;
3148
+ particle.initialPosition.x = particle.position.x;
3149
+ }
3150
+ particle.position.y = newPos.top;
3151
+ particle.initialPosition.y = particle.position.y;
3152
+ particle.justWarped = true;
3153
+ }
3154
+ else if (direction === exports.OutModeDirection.top && nextBounds.bottom < -particle.offset.y) {
3155
+ if (!warp) {
3156
+ particle.position.x = getRandom() * canvasSize.width;
3157
+ particle.initialPosition.x = particle.position.x;
3158
+ }
3159
+ particle.position.y = newPos.bottom;
3160
+ particle.initialPosition.y = particle.position.y;
3161
+ particle.justWarped = true;
3162
+ }
3163
+ }
3164
+ #applyParticleModeOutside(particle) {
3165
+ particle.position.x =
3166
+ Math.floor(randomInRangeValue({
3167
+ min: -particle.moveCenter.radius,
3168
+ max: particle.moveCenter.radius,
3169
+ })) + particle.moveCenter.x;
3170
+ particle.position.y =
3171
+ Math.floor(randomInRangeValue({
3172
+ min: -particle.moveCenter.radius,
3173
+ max: particle.moveCenter.radius,
3174
+ })) + particle.moveCenter.y;
3175
+ const { dx, dy } = getDistances(particle.position, particle.moveCenter);
3176
+ if (particle.moveCenter.radius) {
3177
+ particle.direction = Math.atan2(dy, dx);
3178
+ particle.velocity.angle = particle.direction;
3179
+ }
3180
+ particle.justWarped = true;
3121
3181
  }
3122
3182
  }
3123
3183
 
@@ -3166,7 +3226,7 @@
3166
3226
  }
3167
3227
 
3168
3228
  async function loadOutModesUpdater(engine) {
3169
- engine.checkVersion("4.4.0");
3229
+ engine.checkVersion("4.5.1");
3170
3230
  await engine.pluginManager.register(e => {
3171
3231
  e.pluginManager.addParticleUpdater("outModes", container => {
3172
3232
  return Promise.resolve(new OutOfCanvasUpdater(container));
@@ -3183,39 +3243,9 @@
3183
3243
  this.#pluginManager = pluginManager;
3184
3244
  }
3185
3245
  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
- }
3246
+ const container = this.#container, options = particle.options, paint = itemFromSingleOrMultiple(options.paint, particle.id, options.reduceDuplicates);
3247
+ this.#initFill(paint, particle, container);
3248
+ this.#initStroke(paint, particle, container);
3219
3249
  }
3220
3250
  isEnabled(particle) {
3221
3251
  const { fillAnimation, fillColor, strokeAnimation, strokeColor } = particle, fillEnabled = !!fillAnimation &&
@@ -3234,10 +3264,48 @@
3234
3264
  updateColor(particle.fillColor, delta, this.#container.hdr);
3235
3265
  updateColor(particle.strokeColor, delta, this.#container.hdr);
3236
3266
  }
3267
+ #initFill(paint, particle, container) {
3268
+ const fill = paint?.fill, color = paint?.color, paintColor = color ?? undefined;
3269
+ if (!fill) {
3270
+ particle.fillEnabled = false;
3271
+ particle.fillAnimation = undefined;
3272
+ particle.fillColor = undefined;
3273
+ particle.fillOpacity = defaultOpacity;
3274
+ return;
3275
+ }
3276
+ const fillColor = AnimatableColor.create(paintColor === undefined ? undefined : AnimatableColor.create(undefined, paintColor), fill.color);
3277
+ particle.fillEnabled = fill.enable;
3278
+ particle.fillOpacity = getRangeValue(fill.opacity);
3279
+ particle.fillAnimation = fillColor.animation;
3280
+ const fillHslColor = rangeColorToHsl(this.#pluginManager, fillColor);
3281
+ if (!fillHslColor) {
3282
+ return;
3283
+ }
3284
+ particle.fillColor = getHslAnimationFromHsl(fillHslColor, particle.fillAnimation, container.retina.reduceFactor);
3285
+ }
3286
+ #initStroke(paint, particle, container) {
3287
+ const stroke = paint?.stroke, color = paint?.color, paintColor = color ?? undefined;
3288
+ if (!stroke) {
3289
+ particle.strokeAnimation = undefined;
3290
+ particle.strokeColor = undefined;
3291
+ particle.strokeOpacity = defaultOpacity;
3292
+ particle.strokeWidth = 0;
3293
+ return;
3294
+ }
3295
+ const strokeColor = AnimatableColor.create(paintColor === undefined ? undefined : AnimatableColor.create(undefined, paintColor), stroke.color);
3296
+ particle.strokeWidth = getRangeValue(stroke.width) * container.retina.pixelRatio;
3297
+ particle.strokeOpacity = getRangeValue(stroke.opacity ?? defaultOpacity);
3298
+ particle.strokeAnimation = strokeColor.animation;
3299
+ const strokeHslColor = rangeColorToHsl(this.#pluginManager, strokeColor) ?? particle.getFillColor();
3300
+ if (!strokeHslColor) {
3301
+ return;
3302
+ }
3303
+ particle.strokeColor = getHslAnimationFromHsl(strokeHslColor, particle.strokeAnimation, container.retina.reduceFactor);
3304
+ }
3237
3305
  }
3238
3306
 
3239
3307
  async function loadPaintUpdater(engine) {
3240
- engine.checkVersion("4.4.0");
3308
+ engine.checkVersion("4.5.1");
3241
3309
  await engine.pluginManager.register(e => {
3242
3310
  e.pluginManager.addParticleUpdater("paint", container => {
3243
3311
  return Promise.resolve(new PaintUpdater(e.pluginManager, container));
@@ -3279,7 +3347,7 @@
3279
3347
  if (!this.accepts(input)) {
3280
3348
  return;
3281
3349
  }
3282
- const result = rgbRegex.exec(input), radix = 10, minLength = 4, defaultAlpha = 1;
3350
+ const result = rgbRegex.exec(input), radix = 10, minLength = 4;
3283
3351
  return result
3284
3352
  ? {
3285
3353
  a: result.length > minLength ? parseAlpha(result[RgbIndexes.a]) : defaultAlpha,
@@ -3292,7 +3360,7 @@
3292
3360
  }
3293
3361
 
3294
3362
  async function loadRgbColorPlugin(engine) {
3295
- engine.checkVersion("4.4.0");
3363
+ engine.checkVersion("4.5.1");
3296
3364
  await engine.pluginManager.register(e => {
3297
3365
  e.pluginManager.addColorManager("rgb", new RgbColorManager());
3298
3366
  });
@@ -3377,7 +3445,7 @@
3377
3445
  }
3378
3446
 
3379
3447
  async function loadSizeUpdater(engine) {
3380
- engine.checkVersion("4.4.0");
3448
+ engine.checkVersion("4.5.1");
3381
3449
  await engine.pluginManager.register(e => {
3382
3450
  e.pluginManager.addParticleUpdater("size", container => {
3383
3451
  return Promise.resolve(new SizeUpdater(container));
@@ -3386,7 +3454,7 @@
3386
3454
  }
3387
3455
 
3388
3456
  async function loadBasic(engine) {
3389
- engine.checkVersion("4.4.0");
3457
+ engine.checkVersion("4.5.1");
3390
3458
  await engine.pluginManager.register(async (e) => {
3391
3459
  await Promise.all([
3392
3460
  loadBlendPlugin(e),
@@ -3403,6 +3471,16 @@
3403
3471
  });
3404
3472
  }
3405
3473
 
3474
+ const ErrorCodes$1 = {
3475
+ interactivityPluginNotLoaded: "TSP-3201",
3476
+ interactivityClickHandlerNotSet: "TSP-3202",
3477
+ };
3478
+
3479
+ const ErrorMessages$1 = {
3480
+ [ErrorCodes$1.interactivityPluginNotLoaded]: "tsParticles Interactivity Plugin is not loaded",
3481
+ [ErrorCodes$1.interactivityClickHandlerNotSet]: "Click handlers can only be set after calling tsParticles.load()",
3482
+ };
3483
+
3406
3484
  class ClickEvent {
3407
3485
  enable = false;
3408
3486
  mode = [];
@@ -3479,9 +3557,7 @@
3479
3557
 
3480
3558
  class Modes {
3481
3559
  #container;
3482
- #pluginManager;
3483
- constructor(pluginManager, container) {
3484
- this.#pluginManager = pluginManager;
3560
+ constructor(container) {
3485
3561
  this.#container = container;
3486
3562
  }
3487
3563
  load(data) {
@@ -3491,10 +3567,7 @@
3491
3567
  if (!this.#container) {
3492
3568
  return;
3493
3569
  }
3494
- const interactors = this.#pluginManager.interactors?.get(this.#container);
3495
- if (!interactors) {
3496
- return;
3497
- }
3570
+ const interactors = this.#container.interactionManager?.interactors ?? [];
3498
3571
  for (const interactor of interactors) {
3499
3572
  if (!interactor.loadModeOptions) {
3500
3573
  continue;
@@ -3508,8 +3581,8 @@
3508
3581
  detectsOn = InteractivityDetect.window;
3509
3582
  events = new Events();
3510
3583
  modes;
3511
- constructor(pluginManager, container) {
3512
- this.modes = new Modes(pluginManager, container);
3584
+ constructor(container) {
3585
+ this.modes = new Modes(container);
3513
3586
  }
3514
3587
  load(data) {
3515
3588
  if (isNull(data)) {
@@ -3540,10 +3613,10 @@
3540
3613
  }
3541
3614
  let interactivityOptions = options.interactivity;
3542
3615
  if (!interactivityOptions?.load) {
3543
- options.interactivity = interactivityOptions = new Interactivity(this.#pluginManager, container);
3616
+ options.interactivity = interactivityOptions = new Interactivity(container);
3544
3617
  }
3545
3618
  interactivityOptions.load(source?.interactivity);
3546
- const interactors = this.#pluginManager.interactors?.get(container);
3619
+ const interactors = container.interactionManager?.interactors;
3547
3620
  if (!interactors) {
3548
3621
  return;
3549
3622
  }
@@ -3557,7 +3630,7 @@
3557
3630
  if (source?.interactivity) {
3558
3631
  options.interactivity = deepExtend({}, source.interactivity);
3559
3632
  }
3560
- const interactors = this.#pluginManager.interactors?.get(container);
3633
+ const interactors = container.interactionManager?.interactors;
3561
3634
  if (!interactors) {
3562
3635
  return;
3563
3636
  }
@@ -3587,25 +3660,25 @@
3587
3660
  const clickEvent = "click", mouseDownEvent = "pointerdown", mouseUpEvent = "pointerup", mouseLeaveEvent = "pointerleave", mouseMoveEvent = "pointermove", touchStartEvent = "touchstart", touchEndEvent = "touchend", touchMoveEvent = "touchmove", touchCancelEvent = "touchcancel";
3588
3661
 
3589
3662
  async function loadInteractivityPlugin(engine) {
3590
- engine.checkVersion("4.4.0");
3663
+ engine.checkVersion("4.5.1");
3664
+ if (typeof process !== "undefined" && process.env.NODE_ENV !== "production") {
3665
+ addErrorMessages(ErrorMessages$1);
3666
+ }
3591
3667
  await engine.pluginManager.register(e => {
3592
3668
  const interactivityEngine = e, interactivityPluginManager = interactivityEngine.pluginManager;
3593
3669
  interactivityPluginManager.addPlugin(new InteractivityPlugin(interactivityPluginManager));
3594
3670
  interactivityPluginManager.initializers.interactors ??= new Map();
3595
- interactivityPluginManager.interactors ??= new Map();
3596
3671
  interactivityPluginManager.addInteractor = (name, interactorInitializer) => {
3672
+ if (interactivityPluginManager.initialized) {
3673
+ return;
3674
+ }
3597
3675
  interactivityPluginManager.initializers.interactors ??= new Map();
3598
3676
  interactivityPluginManager.initializers.interactors.set(name, interactorInitializer);
3599
3677
  };
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
3678
  interactivityPluginManager.setOnClickHandler = (callback) => {
3606
3679
  const { items } = interactivityEngine;
3607
3680
  if (!items.length) {
3608
- throw new Error("Click handlers can only be set after calling tsParticles.load()");
3681
+ throw new Error(getErrorMessage(ErrorCodes$1.interactivityClickHandlerNotSet));
3609
3682
  }
3610
3683
  items.forEach(item => {
3611
3684
  const interactivityContainer = item;
@@ -3616,7 +3689,7 @@
3616
3689
  }
3617
3690
  function ensureInteractivityPluginLoaded(e) {
3618
3691
  if (!e.pluginManager.addInteractor) {
3619
- throw new Error("tsParticles Interactivity Plugin is not loaded");
3692
+ throw new Error(getErrorMessage(ErrorCodes$1.interactivityPluginNotLoaded));
3620
3693
  }
3621
3694
  }
3622
3695
 
@@ -3625,6 +3698,7 @@
3625
3698
  CollisionMode["absorb"] = "absorb";
3626
3699
  CollisionMode["bounce"] = "bounce";
3627
3700
  CollisionMode["destroy"] = "destroy";
3701
+ CollisionMode["fluid"] = "fluid";
3628
3702
  })(CollisionMode || (CollisionMode = {}));
3629
3703
 
3630
3704
  class CollisionsAbsorb {
@@ -3637,6 +3711,26 @@
3637
3711
  }
3638
3712
  }
3639
3713
 
3714
+ class CollisionsFluid {
3715
+ maxForce = 2.5;
3716
+ maxNeighbors = 64;
3717
+ nearStiffness = 0.5;
3718
+ radius = 30;
3719
+ restDensity = 3;
3720
+ stiffness = 0.5;
3721
+ load(data) {
3722
+ if (isNull(data)) {
3723
+ return;
3724
+ }
3725
+ loadRangeProperty(this, "maxForce", data.maxForce);
3726
+ loadProperty(this, "maxNeighbors", data.maxNeighbors);
3727
+ loadRangeProperty(this, "nearStiffness", data.nearStiffness);
3728
+ loadRangeProperty(this, "radius", data.radius);
3729
+ loadRangeProperty(this, "restDensity", data.restDensity);
3730
+ loadRangeProperty(this, "stiffness", data.stiffness);
3731
+ }
3732
+ }
3733
+
3640
3734
  class CollisionsOverlap {
3641
3735
  enable = true;
3642
3736
  retries = 0;
@@ -3653,6 +3747,7 @@
3653
3747
  absorb = new CollisionsAbsorb();
3654
3748
  bounce = new ParticlesBounce();
3655
3749
  enable = false;
3750
+ fluid = new CollisionsFluid();
3656
3751
  maxSpeed = 50;
3657
3752
  mode = CollisionMode.bounce;
3658
3753
  overlap = new CollisionsOverlap();
@@ -3663,12 +3758,181 @@
3663
3758
  this.absorb.load(data.absorb);
3664
3759
  this.bounce.load(data.bounce);
3665
3760
  loadProperty(this, "enable", data.enable);
3761
+ this.fluid.load(data.fluid);
3666
3762
  loadRangeProperty(this, "maxSpeed", data.maxSpeed);
3667
3763
  loadProperty(this, "mode", data.mode);
3668
3764
  this.overlap.load(data.overlap);
3669
3765
  }
3670
3766
  }
3671
3767
 
3768
+ const wallMarginFactor = 0.15, restRetention = 0.1, supportContacts = 5, wallSpringFactor = half, minNeighborDistance = 0.0001, solverIterations = 3, separationIterations = 3;
3769
+ function applyWallSpring(position, margin, maxX, maxY) {
3770
+ if (position.x < margin) {
3771
+ position.x += (margin - position.x) * wallSpringFactor;
3772
+ }
3773
+ else if (position.x > maxX) {
3774
+ position.x -= (position.x - maxX) * wallSpringFactor;
3775
+ }
3776
+ if (position.y < margin) {
3777
+ position.y += (margin - position.y) * wallSpringFactor;
3778
+ }
3779
+ else if (position.y > maxY) {
3780
+ position.y -= (position.y - maxY) * wallSpringFactor;
3781
+ }
3782
+ }
3783
+ function clampToWalls(position, margin, maxX, maxY) {
3784
+ if (position.x < margin) {
3785
+ position.x = margin;
3786
+ }
3787
+ else if (position.x > maxX) {
3788
+ position.x = maxX;
3789
+ }
3790
+ if (position.y < margin) {
3791
+ position.y = margin;
3792
+ }
3793
+ else if (position.y > maxY) {
3794
+ position.y = maxY;
3795
+ }
3796
+ }
3797
+ class FluidSolver {
3798
+ #dir = Vector.origin;
3799
+ #isNeighbor;
3800
+ #maxNeighbors = minCount;
3801
+ #neighbors = [];
3802
+ #owner;
3803
+ #ownerZ = defaultAngle;
3804
+ constructor() {
3805
+ this.#isNeighbor = (particle) => {
3806
+ const owner = this.#owner, neighbor = particle;
3807
+ if (!owner ||
3808
+ this.#neighbors.length >= this.#maxNeighbors ||
3809
+ neighbor === owner ||
3810
+ neighbor.destroyed ||
3811
+ neighbor.spawning ||
3812
+ !neighbor.options.collisions?.enable ||
3813
+ neighbor.options.collisions.mode !== CollisionMode.fluid) {
3814
+ return false;
3815
+ }
3816
+ const ownerRadius = owner.getRadius();
3817
+ return (Math.abs(Math.round(this.#ownerZ) - Math.round(neighbor.getPosition().z)) <= ownerRadius + neighbor.getRadius());
3818
+ };
3819
+ }
3820
+ separateOverlaps(particle, position) {
3821
+ const neighbors = this.#neighbors, particlePosition = particle.position;
3822
+ particlePosition.setTo(position);
3823
+ for (let iteration = 0; iteration < separationIterations; iteration++) {
3824
+ for (const neighbor of neighbors) {
3825
+ this.#projectPair(particle, neighbor);
3826
+ }
3827
+ }
3828
+ }
3829
+ solve(container, particle) {
3830
+ const collisionsOptions = particle.options.collisions;
3831
+ if (!collisionsOptions) {
3832
+ return;
3833
+ }
3834
+ 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;
3835
+ this.#owner = particle;
3836
+ this.#maxNeighbors = maxNeighbors;
3837
+ this.#ownerZ = particle.getPosition().z;
3838
+ this.#queryNeighbors(container, particle, radius, maxNeighbors);
3839
+ for (let iteration = 0; iteration < solverIterations; iteration++) {
3840
+ const focalPosition = particle.getPosition();
3841
+ let density = 0, densityNear = 0;
3842
+ for (const neighbor of neighbors) {
3843
+ const dist = getDistance(focalPosition, neighbor.getPosition()), q = identity - dist / radius, q2 = q * q;
3844
+ density += q2;
3845
+ densityNear += q2 * q;
3846
+ }
3847
+ const pressure = (density - restDensity) * stiffness * half, pressureNear = densityNear * nearStiffness * half;
3848
+ if (hasBounds) {
3849
+ applyWallSpring(position, margin, maxX, maxY);
3850
+ }
3851
+ for (const neighbor of neighbors) {
3852
+ const neighborPosition = neighbor.getPosition(), dx = neighborPosition.x - focalPosition.x, dy = neighborPosition.y - focalPosition.y, dist = Math.sqrt(dx * dx + dy * dy);
3853
+ if (dist > radius) {
3854
+ continue;
3855
+ }
3856
+ const q = identity - dist / radius, force = clamp(pressure + pressureNear * q, -maxForce, maxForce), contactDistance = particleRadius + neighbor.getRadius(), push = Math.max(q * force * half, contactDistance - dist);
3857
+ if (dist > minNeighborDistance) {
3858
+ const inverseDist = inverseFactorNumerator / dist;
3859
+ this.#dir.x = dx * inverseDist * push;
3860
+ this.#dir.y = dy * inverseDist * push;
3861
+ }
3862
+ else {
3863
+ this.#dir.x = (particle.id + neighbor.id) % double === minCount ? identity : -identity;
3864
+ this.#dir.y = defaultAngle;
3865
+ this.#dir.multTo(push);
3866
+ }
3867
+ position.x -= this.#dir.x;
3868
+ position.y -= this.#dir.y;
3869
+ }
3870
+ }
3871
+ this.#queryNeighbors(container, particle, radius, maxNeighbors);
3872
+ if (hasBounds) {
3873
+ clampToWalls(position, margin, maxX, maxY);
3874
+ }
3875
+ this.separateOverlaps(particle, position);
3876
+ this.#dampContacts(particle);
3877
+ if (hasBounds) {
3878
+ this.#cancelWallVelocity(particle, margin, maxX, maxY);
3879
+ }
3880
+ }
3881
+ #cancelWallVelocity(particle, margin, maxX, maxY) {
3882
+ const position = particle.position, velocity = particle.velocity;
3883
+ if (position.x <= margin) {
3884
+ velocity.x = defaultAngle;
3885
+ }
3886
+ else if (position.x >= maxX) {
3887
+ velocity.x = defaultAngle;
3888
+ }
3889
+ if (position.y <= margin) {
3890
+ velocity.y = defaultAngle;
3891
+ }
3892
+ else if (position.y >= maxY) {
3893
+ velocity.y = defaultAngle;
3894
+ }
3895
+ }
3896
+ #dampContacts(particle) {
3897
+ const neighbors = this.#neighbors, position = particle.position, velocity = particle.velocity;
3898
+ let touching = minCount;
3899
+ for (const neighbor of neighbors) {
3900
+ const neighborPosition = neighbor.getPosition(), dx = position.x - neighborPosition.x, dy = position.y - neighborPosition.y, distanceSq = dx * dx + dy * dy, contactDistance = particle.getRadius() + neighbor.getRadius();
3901
+ if (distanceSq >= contactDistance * contactDistance || distanceSq <= minNeighborDistance) {
3902
+ continue;
3903
+ }
3904
+ if (++touching < supportContacts) {
3905
+ continue;
3906
+ }
3907
+ velocity.x *= restRetention;
3908
+ velocity.y *= restRetention;
3909
+ return;
3910
+ }
3911
+ }
3912
+ #projectPair(p1, p2) {
3913
+ 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();
3914
+ if (distanceSq >= minDistance * minDistance) {
3915
+ return;
3916
+ }
3917
+ if (distanceSq > minNeighborDistance) {
3918
+ const distance = Math.sqrt(distanceSq), inverseDistance = inverseFactorNumerator / distance, correction = minDistance - distance;
3919
+ pos1.x += dx * inverseDistance * correction;
3920
+ pos1.y += dy * inverseDistance * correction;
3921
+ }
3922
+ else {
3923
+ const direction = (p1.id + p2.id) % double === minCount ? identity : -identity;
3924
+ pos1.x += direction * minDistance;
3925
+ }
3926
+ }
3927
+ #queryNeighbors(container, particle, radius, maxNeighbors) {
3928
+ if (radius <= minRadius || maxNeighbors <= minCount) {
3929
+ return;
3930
+ }
3931
+ this.#neighbors.length = 0;
3932
+ container.particles.grid.queryCircle(particle.getPosition(), radius, this.#isNeighbor, this.#neighbors);
3933
+ }
3934
+ }
3935
+
3672
3936
  const minAbsorbAmount = 0;
3673
3937
  function updateAbsorb(p1, r1, p2, r2, delta, pixelRatio) {
3674
3938
  if (!p1.options.collisions || !p2.options.collisions) {
@@ -3758,14 +4022,22 @@
3758
4022
  destroy(p1, p2);
3759
4023
  break;
3760
4024
  }
4025
+ case CollisionMode.fluid: {
4026
+ break;
4027
+ }
3761
4028
  }
3762
4029
  }
3763
4030
 
3764
4031
  class Collider extends ParticlesInteractorBase {
3765
- maxDistance;
4032
+ #fluidSolver;
4033
+ #maxDistance;
3766
4034
  constructor(container) {
3767
4035
  super(container);
3768
- this.maxDistance = 0;
4036
+ this.#fluidSolver = new FluidSolver();
4037
+ this.#maxDistance = 0;
4038
+ }
4039
+ get maxDistance() {
4040
+ return this.#maxDistance;
3769
4041
  }
3770
4042
  clear() {
3771
4043
  }
@@ -3775,13 +4047,24 @@
3775
4047
  if (p1.destroyed || p1.spawning) {
3776
4048
  return;
3777
4049
  }
4050
+ const collisions = p1.options.collisions;
4051
+ if (!collisions?.enable) {
4052
+ return;
4053
+ }
4054
+ if (collisions.mode === CollisionMode.fluid) {
4055
+ const fluidRadius = getRangeValue(collisions.fluid.radius);
4056
+ if (fluidRadius > this.#maxDistance) {
4057
+ this.#maxDistance = fluidRadius;
4058
+ }
4059
+ this.#fluidSolver.solve(this.container, p1);
4060
+ return;
4061
+ }
3778
4062
  const container = this.container, pos1 = p1.getPosition(), radius1 = p1.getRadius(), query = container.particles.grid.queryCircle(pos1, radius1 * double);
3779
4063
  for (const p2 of query) {
3780
4064
  if (p1 === p2 ||
3781
4065
  p1.id >= p2.id ||
3782
- !p1.options.collisions?.enable ||
3783
4066
  !p2.options.collisions?.enable ||
3784
- p1.options.collisions.mode !== p2.options.collisions.mode ||
4067
+ collisions.mode !== p2.options.collisions.mode ||
3785
4068
  p2.destroyed ||
3786
4069
  p2.spawning) {
3787
4070
  continue;
@@ -3803,10 +4086,18 @@
3803
4086
  loadParticlesOptions(options, ...sources) {
3804
4087
  loadOptionProperty(options, "collisions", Collisions, ...sources);
3805
4088
  }
3806
- reset() {
4089
+ reset(_interactivityData, _particle) {
3807
4090
  }
3808
4091
  }
3809
4092
 
4093
+ const ErrorCodes = {
4094
+ overlapNotPlaced: "TSP-4001",
4095
+ };
4096
+
4097
+ const ErrorMessages = {
4098
+ [ErrorCodes.overlapNotPlaced]: "Particle is overlapping and can't be placed",
4099
+ };
4100
+
3810
4101
  class OverlapPlugin {
3811
4102
  id = "overlap";
3812
4103
  async getPlugin(container) {
@@ -3821,7 +4112,10 @@
3821
4112
  }
3822
4113
 
3823
4114
  async function loadParticlesCollisionsInteraction(engine) {
3824
- engine.checkVersion("4.4.0");
4115
+ engine.checkVersion("4.5.1");
4116
+ if (typeof process !== "undefined" && process.env.NODE_ENV !== "production") {
4117
+ addErrorMessages(ErrorMessages);
4118
+ }
3825
4119
  await engine.pluginManager.register((e) => {
3826
4120
  ensureInteractivityPluginLoaded(e);
3827
4121
  e.pluginManager.addPlugin(new OverlapPlugin());
@@ -3878,6 +4172,30 @@
3878
4172
  }
3879
4173
  return false;
3880
4174
  }
4175
+ query(grid) {
4176
+ const { x, y } = this.position, { width, height } = this.#canvasSize, radius = this.radius, crossesLeft = x - radius <= originPoint.x, crossesRight = x + radius >= width, crossesTop = y - radius <= originPoint.y, crossesBottom = y + radius >= height;
4177
+ if (!crossesLeft && !crossesRight && !crossesTop && !crossesBottom) {
4178
+ return grid.query(this);
4179
+ }
4180
+ const xShifts = [originPoint.x], yShifts = [originPoint.y];
4181
+ if (crossesLeft)
4182
+ xShifts.push(width);
4183
+ if (crossesRight)
4184
+ xShifts.push(-width);
4185
+ if (crossesTop)
4186
+ yShifts.push(height);
4187
+ if (crossesBottom)
4188
+ yShifts.push(-height);
4189
+ const particles = new Set();
4190
+ for (const dx of xShifts) {
4191
+ for (const dy of yShifts) {
4192
+ for (const particle of grid.queryCircle({ x: x + dx, y: y + dy }, radius)) {
4193
+ particles.add(particle);
4194
+ }
4195
+ }
4196
+ }
4197
+ return [...particles];
4198
+ }
3881
4199
  }
3882
4200
 
3883
4201
  class LinksShadow {
@@ -3987,7 +4305,9 @@
3987
4305
  if (pos1.x < originPoint.x || pos1.y < originPoint.y || pos1.x > canvasSize.width || pos1.y > canvasSize.height) {
3988
4306
  return;
3989
4307
  }
3990
- const linkOpt1 = p1.options.links, optOpacity = linkOpt1.opacity, optDistance = p1.retina.linksDistance ?? minDistance$1, warp = linkOpt1.warp, range = warp ? new CircleWarp(pos1.x, pos1.y, optDistance, canvasSize) : new Circle(pos1.x, pos1.y, optDistance), query = container.particles.grid.query(range);
4308
+ const linkOpt1 = p1.options.links, optOpacity = linkOpt1.opacity, optDistance = p1.retina.linksDistance ?? minDistance$1, warp = linkOpt1.warp, query = (warp
4309
+ ? new CircleWarp(pos1.x, pos1.y, optDistance, canvasSize).query(container.particles.grid)
4310
+ : container.particles.grid.queryCircle(pos1, optDistance));
3991
4311
  for (const p2 of query) {
3992
4312
  const linkOpt2 = p2.options.links;
3993
4313
  if (p1 === p2 ||
@@ -4075,7 +4395,7 @@
4075
4395
  }
4076
4396
 
4077
4397
  async function loadParticlesLinksInteraction(engine) {
4078
- engine.checkVersion("4.4.0");
4398
+ engine.checkVersion("4.5.1");
4079
4399
  await engine.pluginManager.register((e) => {
4080
4400
  const pluginManager = e.pluginManager;
4081
4401
  ensureInteractivityPluginLoaded(e);
@@ -4088,7 +4408,7 @@
4088
4408
 
4089
4409
  let initPromise = null;
4090
4410
  async function doInitPlugins(engine) {
4091
- engine.checkVersion("4.4.0");
4411
+ engine.checkVersion("4.5.1");
4092
4412
  await engine.pluginManager.register(async (e) => {
4093
4413
  const loadParticlesInteractivity = async (e) => {
4094
4414
  await loadInteractivityPlugin(e);
@@ -4131,7 +4451,7 @@
4131
4451
  particles.init = async () => {
4132
4452
  await initPlugins(tsParticles);
4133
4453
  };
4134
- particles.version = "4.4.0";
4454
+ particles.version = "4.5.1";
4135
4455
  globalThis.particles = particles;
4136
4456
 
4137
4457
  const globalObject = globalThis;
@@ -4201,21 +4521,28 @@
4201
4521
  });
4202
4522
  }
4203
4523
  clear() {
4524
+ const visited = new Set();
4204
4525
  for (const plugin of this.#canvasClearPlugins) {
4526
+ visited.add(plugin);
4205
4527
  if (plugin.canvasClear?.() ?? false) {
4206
- return;
4528
+ return plugin;
4207
4529
  }
4208
4530
  }
4209
4531
  for (const layer of Object.values(exports.DrawLayer)) {
4210
4532
  if (typeof layer === "number") {
4211
4533
  for (const plugin of this.#getLayerPlugins(layer)) {
4534
+ if (visited.has(plugin)) {
4535
+ continue;
4536
+ }
4537
+ visited.add(plugin);
4212
4538
  if (plugin.canvasClear?.() ?? false) {
4213
- return;
4539
+ return plugin;
4214
4540
  }
4215
4541
  }
4216
4542
  }
4217
4543
  }
4218
4544
  this.canvasClear();
4545
+ return undefined;
4219
4546
  }
4220
4547
  destroy() {
4221
4548
  this.stop();
@@ -4293,8 +4620,7 @@
4293
4620
  });
4294
4621
  }
4295
4622
  drawParticles(delta) {
4296
- const { particles, actualOptions } = this.#container;
4297
- this.clear();
4623
+ const { particles, actualOptions } = this.#container, clearedPlugin = this.clear();
4298
4624
  particles.update(delta);
4299
4625
  this.draw(ctx => {
4300
4626
  const width = this.#canvasManager.size.width, height = this.#canvasManager.size.height;
@@ -4316,7 +4642,9 @@
4316
4642
  }
4317
4643
  }
4318
4644
  for (const plugin of this.#getLayerPlugins(exports.DrawLayer.BackgroundMask)) {
4319
- plugin.canvasPaint?.();
4645
+ if (plugin !== clearedPlugin) {
4646
+ plugin.canvasPaint?.();
4647
+ }
4320
4648
  }
4321
4649
  for (const plugin of this.#getLayerPlugins(exports.DrawLayer.CanvasSetup)) {
4322
4650
  plugin.drawSettingsSetup?.(ctx, delta);
@@ -4332,51 +4660,23 @@
4332
4660
  });
4333
4661
  }
4334
4662
  init() {
4335
- this.initUpdaters();
4336
- this.initPlugins();
4337
- this.#resolveBackgroundElement();
4338
- this.paint();
4339
- }
4340
- initPlugins() {
4341
- this.#canvasClearPlugins = [];
4342
- this.#colorPlugins = [];
4343
- this.#drawParticlePlugins = [];
4344
- this.#drawParticlesSetupPlugins = [];
4345
- this.#drawParticlesCleanupPlugins = [];
4346
- for (const layer of Object.values(exports.DrawLayer)) {
4347
- if (typeof layer === "number") {
4348
- this.#layers[layer] = [];
4349
- }
4350
- }
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);
4663
+ this.initUpdaters();
4664
+ this.initPlugins();
4665
+ this.#resolveBackgroundElement();
4666
+ this.paint();
4667
+ }
4668
+ initPlugins() {
4669
+ this.#canvasClearPlugins = [];
4670
+ this.#colorPlugins = [];
4671
+ this.#drawParticlePlugins = [];
4672
+ this.#drawParticlesSetupPlugins = [];
4673
+ this.#drawParticlesCleanupPlugins = [];
4674
+ for (const layer of Object.values(exports.DrawLayer)) {
4675
+ if (typeof layer === "number") {
4676
+ this.#layers[layer] = [];
4378
4677
  }
4379
4678
  }
4679
+ this.#initPluginsArray();
4380
4680
  }
4381
4681
  initUpdaters() {
4382
4682
  this.#preDrawUpdaters = [];
@@ -4585,6 +4885,45 @@
4585
4885
  this.#reusablePluginColors[sColorIndex] = sColor;
4586
4886
  return this.#reusablePluginColors;
4587
4887
  }
4888
+ #initLayerPlugin(plugin) {
4889
+ const layerMap = [
4890
+ [exports.DrawLayer.BackgroundMask, !!plugin.canvasPaint],
4891
+ [exports.DrawLayer.CanvasSetup, !!plugin.drawSettingsSetup],
4892
+ [exports.DrawLayer.PluginContent, !!plugin.draw],
4893
+ [exports.DrawLayer.CanvasCleanup, !!(plugin.clearDraw ?? plugin.drawSettingsCleanup)],
4894
+ ];
4895
+ for (const [layer, active] of layerMap) {
4896
+ if (active) {
4897
+ this.#layers[layer].push(plugin);
4898
+ }
4899
+ }
4900
+ }
4901
+ #initPluginsArray() {
4902
+ for (const plugin of this.#container.plugins) {
4903
+ if (plugin.particleFillColor ?? plugin.particleStrokeColor) {
4904
+ this.#colorPlugins.push(plugin);
4905
+ }
4906
+ if (plugin.drawParticle) {
4907
+ this.#drawParticlePlugins.push(plugin);
4908
+ }
4909
+ if (plugin.drawParticleSetup) {
4910
+ this.#drawParticlesSetupPlugins.push(plugin);
4911
+ }
4912
+ if (plugin.drawParticleCleanup) {
4913
+ this.#drawParticlesCleanupPlugins.push(plugin);
4914
+ }
4915
+ if (plugin.canvasClear) {
4916
+ this.#canvasClearPlugins.push(plugin);
4917
+ }
4918
+ this.#initLayerPlugin(plugin);
4919
+ }
4920
+ }
4921
+ #isSupportedElement(element) {
4922
+ return ((typeof HTMLCanvasElement !== "undefined" && element instanceof HTMLCanvasElement) ||
4923
+ (typeof OffscreenCanvas !== "undefined" && element instanceof OffscreenCanvas) ||
4924
+ (typeof HTMLVideoElement !== "undefined" && element instanceof HTMLVideoElement) ||
4925
+ (typeof HTMLImageElement !== "undefined" && element instanceof HTMLImageElement));
4926
+ }
4588
4927
  #resolveBackgroundElement() {
4589
4928
  const background = this.#container.actualOptions.background;
4590
4929
  this.#backgroundElement = null;
@@ -4594,9 +4933,7 @@
4594
4933
  if (typeof background.element === "string") {
4595
4934
  if (typeof document !== "undefined") {
4596
4935
  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)) {
4936
+ if (node && this.#isSupportedElement(node)) {
4600
4937
  this.#backgroundElement = node;
4601
4938
  }
4602
4939
  else if (node) {
@@ -4607,10 +4944,7 @@
4607
4944
  }
4608
4945
  }
4609
4946
  }
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)) {
4947
+ else if (this.#isSupportedElement(background.element)) {
4614
4948
  this.#backgroundElement = background.element;
4615
4949
  }
4616
4950
  }
@@ -4628,7 +4962,7 @@
4628
4962
  return transferredCanvas;
4629
4963
  }
4630
4964
  if (typeof canvas.transferControlToOffscreen !== "function") {
4631
- throw new TypeError("OffscreenCanvas is required but not supported by this browser");
4965
+ throw new TypeError(getErrorMessage(ErrorCodes$3.offscreenCanvasUnsupported));
4632
4966
  }
4633
4967
  try {
4634
4968
  const offscreenCanvas = canvas.transferControlToOffscreen();
@@ -4636,10 +4970,16 @@
4636
4970
  return offscreenCanvas;
4637
4971
  }
4638
4972
  catch {
4639
- throw new TypeError("OffscreenCanvas transfer failed");
4973
+ throw new TypeError(getErrorMessage(ErrorCodes$3.offscreenCanvasTransferFailed));
4640
4974
  }
4641
4975
  }, isHtmlCanvasElement = (canvas) => {
4642
4976
  return typeof HTMLCanvasElement !== "undefined" && canvas instanceof HTMLCanvasElement;
4977
+ }, getEffectiveColorSpace = (context) => {
4978
+ if (!context) {
4979
+ return undefined;
4980
+ }
4981
+ const colorInfo = context;
4982
+ return colorInfo.getContextAttributes?.().colorSpace ?? undefined;
4643
4983
  };
4644
4984
  function setStyle(canvas, style, important = false) {
4645
4985
  if (!style) {
@@ -4764,7 +5104,7 @@
4764
5104
  const elementStyle = element.style, color = rangeColorToRgb(this.#pluginManager, background.color);
4765
5105
  if (color) {
4766
5106
  const hdrOptions = container.actualOptions.hdr;
4767
- elementStyle.backgroundColor = getStyleFromRgb(color, container.hdr, background.opacity, hdrOptions.peakNits, hdrOptions.mode);
5107
+ elementStyle.backgroundColor = getStyleFromRgb(color, container.hdr, background.opacity, hdrOptions.peakNits, toEnumValue(exports.HdrMode, hdrOptions.mode, exports.HdrMode.standard));
4768
5108
  }
4769
5109
  else {
4770
5110
  elementStyle.backgroundColor = "";
@@ -4884,11 +5224,11 @@
4884
5224
  const container = this.#container, canSupportHdr = container.actualOptions.hdr.enable &&
4885
5225
  safeMatchMedia("(color-gamut: p3)")?.matches &&
4886
5226
  safeMatchMedia("(dynamic-range: high)")?.matches;
4887
- container.hdr = canSupportHdr ?? false;
4888
- container.hdrMode = container.actualOptions.hdr.mode;
5227
+ container.hdrMode = toEnumValue(exports.HdrMode, container.actualOptions.hdr.mode, exports.HdrMode.standard);
4889
5228
  container.peakNits = container.actualOptions.hdr.peakNits;
4890
5229
  const renderCanvas = this.renderCanvas;
4891
5230
  if (!renderCanvas) {
5231
+ container.hdr = canSupportHdr ?? false;
4892
5232
  return;
4893
5233
  }
4894
5234
  this.render.setContextSettings({
@@ -4907,7 +5247,6 @@
4907
5247
  context = null;
4908
5248
  }
4909
5249
  if (canSupportHdr && !context) {
4910
- container.hdr = false;
4911
5250
  const sdrSettings = {
4912
5251
  alpha: true,
4913
5252
  desynchronized: true,
@@ -4923,11 +5262,16 @@
4923
5262
  }
4924
5263
  }
4925
5264
  this.render.setContext(context);
5265
+ if (context) {
5266
+ const effectiveColorSpace = getEffectiveColorSpace(context);
5267
+ if (effectiveColorSpace !== undefined) {
5268
+ container.hdr = effectiveColorSpace === "display-p3";
5269
+ }
5270
+ }
4926
5271
  }
4927
5272
  #initHdrListeners() {
4928
5273
  this.#removeHdrListeners();
4929
5274
  const p3Query = safeMatchMedia("(color-gamut: p3)"), hdrQuery = safeMatchMedia("(dynamic-range: high)"), handleChange = () => {
4930
- this.#recreateRenderCanvas();
4931
5275
  this.#initContext();
4932
5276
  this.initBackground();
4933
5277
  }, listeners = [];
@@ -4963,16 +5307,6 @@
4963
5307
  element.style.setProperty(key, value, "important");
4964
5308
  }
4965
5309
  }
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
5310
  #removeHdrListeners() {
4977
5311
  if (!this.#hdrMediaListeners) {
4978
5312
  return;
@@ -5044,6 +5378,10 @@
5044
5378
  this.#manageListeners(true);
5045
5379
  }
5046
5380
  removeListeners() {
5381
+ if (this.#resizeTimeout !== undefined) {
5382
+ clearTimeout(this.#resizeTimeout);
5383
+ this.#resizeTimeout = undefined;
5384
+ }
5047
5385
  this.#manageListeners(false);
5048
5386
  }
5049
5387
  #handleVisibilityChange() {
@@ -5071,8 +5409,7 @@
5071
5409
  this.#resizeTimeout = undefined;
5072
5410
  }
5073
5411
  const handleResize = async () => {
5074
- const canvas = this.#container.canvas;
5075
- await canvas.windowResize();
5412
+ await this.#container.canvas.windowResize();
5076
5413
  };
5077
5414
  this.#resizeTimeout = setTimeout(() => void handleResize(), this.#container.actualOptions.resize.delay * millisecondsToSeconds);
5078
5415
  }
@@ -5100,8 +5437,8 @@
5100
5437
  }
5101
5438
  else if (!this.#resizeObserver && add && canvasEl) {
5102
5439
  this.#resizeObserver = new ResizeObserver((entries) => {
5103
- const entry = entries.find(e => e.target === canvasEl);
5104
- if (!entry) {
5440
+ const res = entries.some(e => e.target === canvasEl);
5441
+ if (!res) {
5105
5442
  return;
5106
5443
  }
5107
5444
  this.#handleWindowResize();
@@ -5365,10 +5702,10 @@
5365
5702
  return this.#modifiers.find(m => m.id === id);
5366
5703
  }
5367
5704
  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;
5705
+ 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;
5706
+ this.#cachedOpacityData.fillOpacity = this.fillOpacity ?? defaultOpacity$2;
5370
5707
  this.#cachedOpacityData.opacity = opacity * zOpacityFactor;
5371
- this.#cachedOpacityData.strokeOpacity = strokeOpacity;
5708
+ this.#cachedOpacityData.strokeOpacity = this.strokeOpacity ?? defaultOpacity$2;
5372
5709
  return this.#cachedOpacityData;
5373
5710
  }
5374
5711
  getPosition() {
@@ -5615,7 +5952,7 @@
5615
5952
  #initPosition(position) {
5616
5953
  const container = this.#container, zIndexValue = Math.floor(getRangeValue(this.options.zIndex.value)), initialPosition = this.#calcPosition(position, clamp(zIndexValue, minZ, container.zLayers));
5617
5954
  if (!initialPosition) {
5618
- throw new Error("a valid position cannot be found for particle");
5955
+ throw new Error(getErrorMessage(ErrorCodes$3.particlePositionNotFound));
5619
5956
  }
5620
5957
  this.position = initialPosition;
5621
5958
  this.initialPosition = this.position.copy();
@@ -5664,6 +6001,12 @@
5664
6001
  this.#circlePoolIdx = 0;
5665
6002
  this.#rectanglePoolIdx = 0;
5666
6003
  }
6004
+ get cellSize() {
6005
+ return this.#cellSize;
6006
+ }
6007
+ set cellSize(value) {
6008
+ this.#pendingCellSize = value;
6009
+ }
5667
6010
  clear() {
5668
6011
  this.#cells.clear();
5669
6012
  const pendingCellSize = this.#pendingCellSize;
@@ -5687,40 +6030,46 @@
5687
6030
  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
6031
  for (let cx = minCellX; cx <= maxCellX; cx++) {
5689
6032
  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
- }
6033
+ this.#queryCell(cx, cy, range, check, out);
5702
6034
  }
5703
6035
  }
5704
6036
  return out;
5705
6037
  }
5706
6038
  queryCircle(position, radius, check, out = []) {
5707
- const circle = this.#acquireCircle(position.x, position.y, radius), result = this.query(circle, check, out);
5708
- this.#releaseShapes();
5709
- return result;
6039
+ const circle = this.#acquireCircle(position.x, position.y, radius);
6040
+ try {
6041
+ return this.query(circle, check, out);
6042
+ }
6043
+ finally {
6044
+ this.#circlePoolIdx--;
6045
+ }
5710
6046
  }
5711
6047
  queryRectangle(position, size, check, out = []) {
5712
- const rect = this.#acquireRectangle(position.x, position.y, size.width, size.height), result = this.query(rect, check, out);
5713
- this.#releaseShapes();
5714
- return result;
5715
- }
5716
- setCellSize(cellSize) {
5717
- this.#pendingCellSize = cellSize;
6048
+ const rect = this.#acquireRectangle(position.x, position.y, size.width, size.height);
6049
+ try {
6050
+ return this.query(rect, check, out);
6051
+ }
6052
+ finally {
6053
+ this.#rectanglePoolIdx--;
6054
+ }
5718
6055
  }
5719
6056
  #acquireCircle(x, y, r) {
5720
- return (this.#circlePool[this.#circlePoolIdx++] ??= new Circle(x, y, r)).reset(x, y, r);
6057
+ const idx = this.#circlePoolIdx++;
6058
+ let circle = this.#circlePool[idx];
6059
+ if (!circle) {
6060
+ circle = new Circle(x, y, r);
6061
+ this.#circlePool[idx] = circle;
6062
+ }
6063
+ return circle.reset(x, y, r);
5721
6064
  }
5722
6065
  #acquireRectangle(x, y, w, h) {
5723
- return (this.#rectanglePool[this.#rectanglePoolIdx++] ??= new Rectangle(x, y, w, h)).reset(x, y, w, h);
6066
+ const idx = this.#rectanglePoolIdx++;
6067
+ let rectangle = this.#rectanglePool[idx];
6068
+ if (!rectangle) {
6069
+ rectangle = new Rectangle(x, y, w, h);
6070
+ this.#rectanglePool[idx] = rectangle;
6071
+ }
6072
+ return rectangle.reset(x, y, w, h);
5724
6073
  }
5725
6074
  #cellKeyFromCoords(x, y) {
5726
6075
  const cellX = Math.floor(x / this.#cellSize), cellY = Math.floor(y / this.#cellSize);
@@ -5747,17 +6096,27 @@
5747
6096
  }
5748
6097
  return null;
5749
6098
  }
5750
- #releaseShapes() {
5751
- this.#circlePoolIdx = 0;
5752
- this.#rectanglePoolIdx = 0;
6099
+ #queryCell(cx, cy, range, check, out) {
6100
+ const cellParticles = this.#cells.get(`${cx}_${cy}`);
6101
+ if (!cellParticles) {
6102
+ return;
6103
+ }
6104
+ for (const p of cellParticles) {
6105
+ if (check && !check(p)) {
6106
+ continue;
6107
+ }
6108
+ if (range.contains(p.getPosition())) {
6109
+ out.push(p);
6110
+ }
6111
+ }
5753
6112
  }
5754
6113
  }
5755
6114
 
5756
6115
  class ParticlesManager {
5757
6116
  checkParticlePositionPlugins;
5758
- grid;
5759
6117
  #array;
5760
6118
  #container;
6119
+ #grid;
5761
6120
  #groupLimits;
5762
6121
  #limit;
5763
6122
  #nextId;
@@ -5781,7 +6140,7 @@
5781
6140
  this.#groupLimits = new Map();
5782
6141
  this.#particleBuckets = new Map();
5783
6142
  this.#zBuckets = this.#createBuckets(this.#container.zLayers);
5784
- this.grid = new SpatialHashGrid(spatialHashGridCellSize);
6143
+ this.#grid = new SpatialHashGrid(spatialHashGridCellSize);
5785
6144
  this.checkParticlePositionPlugins = [];
5786
6145
  this.#particleResetPlugins = [];
5787
6146
  this.#particleUpdatePlugins = [];
@@ -5792,23 +6151,12 @@
5792
6151
  get count() {
5793
6152
  return this.#array.length;
5794
6153
  }
6154
+ get grid() {
6155
+ return this.#grid;
6156
+ }
5795
6157
  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
- }
6158
+ if (this.#checkAndApplyLimits(group, this.count)) {
6159
+ return;
5812
6160
  }
5813
6161
  try {
5814
6162
  const particle = this.#pool.pop() ?? new Particle(this.#pluginManager, this.#container);
@@ -5872,7 +6220,7 @@
5872
6220
  return this.#array[index];
5873
6221
  }
5874
6222
  async init() {
5875
- const container = this.#container, options = container.actualOptions;
6223
+ const container = this.#container;
5876
6224
  this.checkParticlePositionPlugins = [];
5877
6225
  this.#updatePlugins = [];
5878
6226
  this.#particleUpdatePlugins = [];
@@ -5881,59 +6229,16 @@
5881
6229
  this.#postParticleUpdatePlugins = [];
5882
6230
  this.#particleBuckets.clear();
5883
6231
  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();
6232
+ this.#grid = new SpatialHashGrid(spatialHashGridCellSize * container.retina.pixelRatio);
6233
+ this.#applyLimits(container.actualOptions.particles);
6234
+ const particlesOptions = container.actualOptions.particles, groups = particlesOptions.groups;
6235
+ for (const group in groups) {
6236
+ const groupData = groups[group];
6237
+ if (groupData) {
6238
+ this.#applyLimits(loadParticlesOptions(this.#pluginManager, this.#container, groupData), group, groupData);
5935
6239
  }
5936
6240
  }
6241
+ await this.#initPlugins();
5937
6242
  }
5938
6243
  push(nb, position, overrideOptions, group) {
5939
6244
  for (let i = 0; i < nb; i++) {
@@ -5948,13 +6253,13 @@
5948
6253
  remove(particle, group, override) {
5949
6254
  this.removeAt(this.#array.indexOf(particle), undefined, group, override);
5950
6255
  }
5951
- removeAt(index, quantity = defaultRemoveQuantity, group, override) {
6256
+ removeAt(index, quantity = defaultRemoveQuantity, group, override, matchGroup = true) {
5952
6257
  if (index < minIndex || index > this.count) {
5953
6258
  return;
5954
6259
  }
5955
6260
  let deleted = 0;
5956
6261
  for (let i = index; deleted < quantity && i < this.count; i++) {
5957
- if (this.#removeParticle(i, group, override)) {
6262
+ if (this.#removeParticle(i, group, override, matchGroup)) {
5958
6263
  i--;
5959
6264
  deleted++;
5960
6265
  }
@@ -5985,7 +6290,7 @@
5985
6290
  this.#resizeFactor = factor;
5986
6291
  }
5987
6292
  update(delta) {
5988
- this.grid.clear();
6293
+ this.#grid.clear();
5989
6294
  for (const plugin of this.#updatePlugins) {
5990
6295
  plugin.update?.(delta);
5991
6296
  }
@@ -5996,7 +6301,7 @@
5996
6301
  this.#updateParticlesPhase2(delta, particlesToDelete);
5997
6302
  if (particlesToDelete.size) {
5998
6303
  for (const particle of particlesToDelete) {
5999
- this.remove(particle);
6304
+ this.remove(particle, particle.group);
6000
6305
  }
6001
6306
  }
6002
6307
  this.#resizeFactor = undefined;
@@ -6007,12 +6312,7 @@
6007
6312
  #applyDensity(options, pluginsCount, group, groupOptions) {
6008
6313
  const numberOptions = options.number;
6009
6314
  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
- }
6315
+ this.#applyLimits(options, group, groupOptions);
6016
6316
  return;
6017
6317
  }
6018
6318
  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 +6320,10 @@
6020
6320
  this.#limit = numberOptions.limit.value * densityFactor;
6021
6321
  }
6022
6322
  else {
6023
- this.#groupLimits.set(group, numberOptions.limit.value * densityFactor);
6323
+ this.#groupLimits.set(group, {
6324
+ limit: numberOptions.limit.value * densityFactor,
6325
+ mode: toEnumValue(exports.LimitMode, numberOptions.limit.mode, exports.LimitMode.delete),
6326
+ });
6024
6327
  }
6025
6328
  if (particlesCount < particlesNumber) {
6026
6329
  this.push(Math.abs(particlesNumber - particlesCount), undefined, options, group);
@@ -6029,6 +6332,55 @@
6029
6332
  this.removeQuantity(particlesCount - particlesNumber, group);
6030
6333
  }
6031
6334
  }
6335
+ #applyLimits(options, group, groupOptions) {
6336
+ if (group === undefined) {
6337
+ this.#limit = options.number.limit.value;
6338
+ const groups = this.#container.actualOptions.particles.groups;
6339
+ for (const existingGroup of this.#groupLimits.keys()) {
6340
+ if (!(existingGroup in groups)) {
6341
+ this.#groupLimits.delete(existingGroup);
6342
+ }
6343
+ }
6344
+ }
6345
+ else {
6346
+ const limitValue = groupOptions?.number?.limit?.value ?? options.number.limit.value;
6347
+ if (limitValue > minLimit) {
6348
+ this.#groupLimits.set(group, {
6349
+ limit: limitValue,
6350
+ mode: toEnumValue(exports.LimitMode, groupOptions?.number?.limit?.mode ?? options.number.limit.mode, exports.LimitMode.delete),
6351
+ });
6352
+ }
6353
+ else {
6354
+ this.#groupLimits.delete(group);
6355
+ }
6356
+ }
6357
+ }
6358
+ #checkAndApplyLimits(group, currentCount) {
6359
+ const globalLimit = this.#limit, globalMode = this.#container.actualOptions.particles.number.limit.mode;
6360
+ if (globalLimit > minLimit && globalMode === exports.LimitMode.wait && currentCount >= globalLimit) {
6361
+ return true;
6362
+ }
6363
+ const groupLimitEntry = group === undefined ? undefined : this.#groupLimits.get(group);
6364
+ if (groupLimitEntry && groupLimitEntry.limit > minLimit && groupLimitEntry.mode === exports.LimitMode.wait) {
6365
+ const groupCount = this.filter(t => t.group === group).length;
6366
+ if (groupCount >= groupLimitEntry.limit) {
6367
+ return true;
6368
+ }
6369
+ }
6370
+ if (groupLimitEntry && groupLimitEntry.limit > minLimit && groupLimitEntry.mode === exports.LimitMode.delete) {
6371
+ const groupCountToRemove = this.filter(t => t.group === group).length + countOffset - groupLimitEntry.limit;
6372
+ if (groupCountToRemove > minCount) {
6373
+ this.removeQuantity(groupCountToRemove, group);
6374
+ }
6375
+ }
6376
+ if (globalLimit > minLimit && globalMode === exports.LimitMode.delete) {
6377
+ const globalCountToRemove = this.count + countOffset - globalLimit;
6378
+ if (globalCountToRemove > minCount) {
6379
+ this.#removeAny(globalCountToRemove);
6380
+ }
6381
+ }
6382
+ return false;
6383
+ }
6032
6384
  #createBuckets(zLayers) {
6033
6385
  const bucketCount = Math.max(Math.floor(zLayers), one);
6034
6386
  return Array.from({ length: bucketCount }, () => []);
@@ -6051,6 +6403,70 @@
6051
6403
  }
6052
6404
  return ((canvasSize.width * canvasSize.height) / (densityOptions.height * densityOptions.width * pxRatio ** squareExp));
6053
6405
  }
6406
+ async #initDrawersAndUpdaters() {
6407
+ const container = this.#container;
6408
+ await container.initDrawersAndUpdaters();
6409
+ for (const drawer of container.effectDrawers.values()) {
6410
+ await drawer.init?.(container);
6411
+ }
6412
+ for (const drawer of container.shapeDrawers.values()) {
6413
+ await drawer.init?.(container);
6414
+ }
6415
+ }
6416
+ async #initPlugins() {
6417
+ await this.#initPluginsArrays();
6418
+ await this.#initDrawersAndUpdaters();
6419
+ let handled = false;
6420
+ const container = this.#container;
6421
+ for (const plugin of container.plugins) {
6422
+ handled = plugin.particlesInitialization?.() ?? handled;
6423
+ if (handled) {
6424
+ break;
6425
+ }
6426
+ }
6427
+ if (handled) {
6428
+ return;
6429
+ }
6430
+ const particlesOptions = container.actualOptions.particles, groups = particlesOptions.groups;
6431
+ for (const group in groups) {
6432
+ const groupOptions = groups[group];
6433
+ if (!groupOptions) {
6434
+ continue;
6435
+ }
6436
+ for (let i = this.count, j = 0; j < groupOptions.number.value && i < particlesOptions.number.value; i++, j++) {
6437
+ this.addParticle(undefined, groupOptions, group);
6438
+ }
6439
+ }
6440
+ for (let i = this.count; i < particlesOptions.number.value; i++) {
6441
+ this.addParticle();
6442
+ }
6443
+ }
6444
+ async #initPluginsArrays() {
6445
+ const container = this.#container;
6446
+ for (const plugin of container.plugins) {
6447
+ if (plugin.redrawInit) {
6448
+ await plugin.redrawInit();
6449
+ }
6450
+ if (plugin.checkParticlePosition) {
6451
+ this.checkParticlePositionPlugins.push(plugin);
6452
+ }
6453
+ if (plugin.update) {
6454
+ this.#updatePlugins.push(plugin);
6455
+ }
6456
+ if (plugin.particleUpdate) {
6457
+ this.#particleUpdatePlugins.push(plugin);
6458
+ }
6459
+ if (plugin.postUpdate) {
6460
+ this.#postUpdatePlugins.push(plugin);
6461
+ }
6462
+ if (plugin.particleReset) {
6463
+ this.#particleResetPlugins.push(plugin);
6464
+ }
6465
+ if (plugin.postParticleUpdate) {
6466
+ this.#postParticleUpdatePlugins.push(plugin);
6467
+ }
6468
+ }
6469
+ }
6054
6470
  #insertParticleIntoBucket(particle) {
6055
6471
  const bucketIndex = this.#getBucketIndex(particle.position.z), bucket = this.#zBuckets[bucketIndex];
6056
6472
  if (!bucket) {
@@ -6059,12 +6475,15 @@
6059
6475
  bucket.push(particle);
6060
6476
  this.#particleBuckets.set(particle.id, bucketIndex);
6061
6477
  }
6062
- #removeParticle(index, group, override) {
6478
+ #removeAny(quantity) {
6479
+ this.removeAt(minIndex, quantity, undefined, undefined, false);
6480
+ }
6481
+ #removeParticle(index, group, override, matchGroup = true) {
6063
6482
  const particle = this.#array[index];
6064
6483
  if (!particle) {
6065
6484
  return false;
6066
6485
  }
6067
- if (particle.group !== group) {
6486
+ if (matchGroup && particle.group !== group) {
6068
6487
  return false;
6069
6488
  }
6070
6489
  this.#array.splice(index, deleteCount);
@@ -6151,7 +6570,7 @@
6151
6570
  particlesToDelete.add(particle);
6152
6571
  continue;
6153
6572
  }
6154
- this.grid.insert(particle);
6573
+ this.#grid.insert(particle);
6155
6574
  }
6156
6575
  return particlesToDelete;
6157
6576
  }
@@ -6238,6 +6657,7 @@
6238
6657
  started;
6239
6658
  zLayers;
6240
6659
  #delay;
6660
+ #delayResolve;
6241
6661
  #delayTimeout;
6242
6662
  #delta = { value: 0, factor: 0 };
6243
6663
  #dispatchCallback;
@@ -6327,7 +6747,6 @@
6327
6747
  this.shapeDrawers = new Map();
6328
6748
  this.particleUpdaters = [];
6329
6749
  this.plugins.length = 0;
6330
- this.#pluginManager.clearPlugins(this);
6331
6750
  this.destroyed = true;
6332
6751
  this.#onDestroy(remove);
6333
6752
  this.dispatchEvent(exports.EventType.containerDestroyed);
@@ -6380,31 +6799,14 @@
6380
6799
  await this.initDrawersAndUpdaters();
6381
6800
  this.#options = loadContainerOptions(this.#pluginManager, this, this.#initialSourceOptions, this.sourceOptions);
6382
6801
  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
- }
6802
+ this.#initPlugins(allContainerPlugins);
6401
6803
  this.retina.init();
6402
6804
  this.canvas.init();
6403
6805
  this.updateActualOptions();
6404
6806
  this.canvas.initBackground();
6405
6807
  this.canvas.resize();
6406
6808
  const { delay, duration, fpsLimit, smooth, zLayers } = this.actualOptions, hdrOptions = this.actualOptions.hdr;
6407
- this.hdrMode = hdrOptions.mode;
6809
+ this.hdrMode = toEnumValue(exports.HdrMode, hdrOptions.mode, exports.HdrMode.standard);
6408
6810
  this.peakNits = hdrOptions.peakNits;
6409
6811
  this.zLayers = zLayers;
6410
6812
  this.#duration = getRangeValue(duration) * millisecondsToSeconds;
@@ -6425,9 +6827,9 @@
6425
6827
  }
6426
6828
  async initDrawersAndUpdaters() {
6427
6829
  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);
6830
+ this.effectDrawers = await getItemMapFromInitializer(this, pluginManager.initializers.effects);
6831
+ this.shapeDrawers = await getItemMapFromInitializer(this, pluginManager.initializers.shapes);
6832
+ this.particleUpdaters = await getItemsFromInitializer(this, pluginManager.initializers.updaters);
6431
6833
  }
6432
6834
  pause() {
6433
6835
  if (!guardCheck(this)) {
@@ -6494,7 +6896,10 @@
6494
6896
  await this.init();
6495
6897
  this.started = true;
6496
6898
  await new Promise(resolve => {
6899
+ this.#delayResolve = resolve;
6497
6900
  const start = async () => {
6901
+ this.#delayTimeout = undefined;
6902
+ this.#delayResolve = undefined;
6498
6903
  this.#eventListeners.addListeners();
6499
6904
  for (const plugin of this.plugins) {
6500
6905
  await plugin.start?.();
@@ -6510,9 +6915,11 @@
6510
6915
  if (!guardCheck(this) || !this.started) {
6511
6916
  return;
6512
6917
  }
6513
- if (this.#delayTimeout) {
6918
+ if (this.#delayTimeout !== undefined) {
6514
6919
  clearTimeout(this.#delayTimeout);
6515
6920
  this.#delayTimeout = undefined;
6921
+ this.#delayResolve?.();
6922
+ this.#delayResolve = undefined;
6516
6923
  }
6517
6924
  this.#firstStart = true;
6518
6925
  this.started = false;
@@ -6538,6 +6945,27 @@
6538
6945
  }
6539
6946
  return refresh;
6540
6947
  }
6948
+ #initPlugins(allContainerPlugins) {
6949
+ this.plugins.length = 0;
6950
+ this.particleDestroyedPlugins.length = 0;
6951
+ this.particleCreatedPlugins.length = 0;
6952
+ this.particlePositionPlugins.length = 0;
6953
+ for (const [plugin, containerPlugin] of allContainerPlugins) {
6954
+ if (!plugin.needsPlugin(this.actualOptions)) {
6955
+ continue;
6956
+ }
6957
+ this.plugins.push(containerPlugin);
6958
+ if (containerPlugin.particleCreated) {
6959
+ this.particleCreatedPlugins.push(containerPlugin);
6960
+ }
6961
+ if (containerPlugin.particleDestroyed) {
6962
+ this.particleDestroyedPlugins.push(containerPlugin);
6963
+ }
6964
+ if (containerPlugin.particlePosition) {
6965
+ this.particlePositionPlugins.push(containerPlugin);
6966
+ }
6967
+ }
6968
+ }
6541
6969
  #nextFrame(timestamp) {
6542
6970
  try {
6543
6971
  if (!this.#smooth &&
@@ -6844,11 +7272,11 @@
6844
7272
  }
6845
7273
  }
6846
7274
  async #init() {
6847
- const availablePathGenerators = await this.#pluginManager.getPathGenerators?.(this.#container, true);
6848
- if (!availablePathGenerators) {
7275
+ const pluginManager = this.#pluginManager;
7276
+ if (!pluginManager.initializers.pathGenerators) {
6849
7277
  return;
6850
7278
  }
6851
- this.availablePathGenerators = availablePathGenerators;
7279
+ this.availablePathGenerators = await getItemMapFromInitializer(this.#container, pluginManager.initializers.pathGenerators);
6852
7280
  this.pathGenerators = new Map();
6853
7281
  for (const pathGenerator of this.pathGenerators.values()) {
6854
7282
  pathGenerator.init();
@@ -6952,28 +7380,14 @@
6952
7380
  }
6953
7381
  const html = interactivityEl, canvas = container.canvas;
6954
7382
  canvas.setPointerEvents(html === canvas.domElement ? "initial" : "none");
6955
- if (add && !(options.interactivity?.events.onHover.enable || options.interactivity?.events.onClick.enable)) {
6956
- return;
6957
- }
6958
7383
  manageListener(interactivityEl, mouseMoveEvent, handlers.mouseMove, add);
6959
7384
  manageListener(interactivityEl, touchStartEvent, handlers.touchStart, add);
6960
7385
  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
- }
7386
+ const onClickEnabled = !!options.interactivity?.events.onClick.enable;
7387
+ manageListener(interactivityEl, touchEndEvent, handlers.touchEndClick, add && onClickEnabled);
7388
+ manageListener(interactivityEl, touchEndEvent, handlers.touchEnd, add && !onClickEnabled);
7389
+ manageListener(interactivityEl, mouseUpEvent, handlers.mouseUp, add);
7390
+ manageListener(interactivityEl, mouseDownEvent, handlers.mouseDown, add);
6977
7391
  manageListener(interactivityEl, mouseLeaveEvent, handlers.mouseLeave, add);
6978
7392
  manageListener(interactivityEl, touchCancelEvent, handlers.touchCancel, add);
6979
7393
  }
@@ -6999,19 +7413,18 @@
6999
7413
  #mouseTouchClick(e) {
7000
7414
  const container = this.#container, interactionManager = this.#interactionManager, options = container.actualOptions, { mouse } = interactionManager.interactivityData;
7001
7415
  mouse.inside = true;
7002
- let handled = false;
7003
7416
  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;
7417
+ if (mousePosition && options.interactivity?.events.onClick.enable) {
7418
+ let handled = false;
7419
+ for (const plugin of this.#clickPositionPlugins) {
7420
+ handled = plugin.clickPositionValid?.(mousePosition) ?? false;
7421
+ if (handled) {
7422
+ break;
7423
+ }
7424
+ }
7425
+ if (!handled) {
7426
+ this.#doMouseTouchClick(e);
7011
7427
  }
7012
- }
7013
- if (!handled) {
7014
- this.#doMouseTouchClick(e);
7015
7428
  }
7016
7429
  mouse.clicking = false;
7017
7430
  }
@@ -7107,6 +7520,9 @@
7107
7520
  this.#touches.set(touch.identifier, performance.now());
7108
7521
  }
7109
7522
  this.#mouseTouchMove(e);
7523
+ const { mouse } = this.#interactionManager.interactivityData;
7524
+ mouse.clicking = true;
7525
+ mouse.downPosition = mouse.position;
7110
7526
  }
7111
7527
  }
7112
7528
 
@@ -7119,18 +7535,18 @@
7119
7535
  }
7120
7536
  class InteractionManager {
7121
7537
  interactivityData;
7538
+ interactors;
7122
7539
  #clickHandlers;
7123
7540
  #container;
7124
7541
  #eventListeners;
7125
7542
  #externalInteractors;
7126
- #interactors;
7127
7543
  #intersectionObserver;
7128
7544
  #particleInteractors;
7129
7545
  #pluginManager;
7130
7546
  constructor(pluginManager, container) {
7131
7547
  this.#container = container;
7132
7548
  this.#pluginManager = pluginManager;
7133
- this.#interactors = [];
7549
+ this.interactors = [];
7134
7550
  this.#externalInteractors = [];
7135
7551
  this.#particleInteractors = [];
7136
7552
  this.#clickHandlers = new Map();
@@ -7249,7 +7665,7 @@
7249
7665
  }
7250
7666
  init() {
7251
7667
  this.#eventListeners.init();
7252
- for (const interactor of this.#interactors) {
7668
+ for (const interactor of this.interactors) {
7253
7669
  switch (interactor.type) {
7254
7670
  case InteractorType.external:
7255
7671
  this.#externalInteractors.push(interactor);
@@ -7262,11 +7678,11 @@
7262
7678
  }
7263
7679
  }
7264
7680
  async initInteractors() {
7265
- const interactors = await this.#pluginManager.getInteractors?.(this.#container, true);
7266
- if (!interactors) {
7681
+ const pluginManager = this.#pluginManager;
7682
+ if (!pluginManager.initializers.interactors) {
7267
7683
  return;
7268
7684
  }
7269
- this.#interactors = interactors;
7685
+ this.interactors = await getItemsFromInitializer(this.#container, pluginManager.initializers.interactors);
7270
7686
  this.#externalInteractors = [];
7271
7687
  this.#particleInteractors = [];
7272
7688
  }
@@ -7311,13 +7727,13 @@
7311
7727
  }
7312
7728
  updateMaxDistance() {
7313
7729
  let maxTotalDistance = 0;
7314
- for (const interactor of this.#interactors) {
7730
+ for (const interactor of this.interactors) {
7315
7731
  if (interactor.maxDistance > maxTotalDistance) {
7316
7732
  maxTotalDistance = interactor.maxDistance;
7317
7733
  }
7318
7734
  }
7319
7735
  const container = this.#container;
7320
- container.particles.grid.setCellSize(maxTotalDistance * container.retina.pixelRatio);
7736
+ container.particles.grid.cellSize = maxTotalDistance * container.retina.pixelRatio;
7321
7737
  }
7322
7738
  #intersectionManager(entries) {
7323
7739
  const container = this.#container;
@@ -7339,59 +7755,59 @@
7339
7755
  }
7340
7756
 
7341
7757
  class InteractivityPluginInstance {
7342
- interactionManager;
7343
7758
  #container;
7344
- #pluginManager;
7345
7759
  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);
7760
+ container.addClickHandler = (callback) => {
7761
+ container.interactionManager?.addClickHandler(callback);
7351
7762
  };
7763
+ container.interactionManager = new InteractionManager(pluginManager, container);
7764
+ this.#container = container;
7352
7765
  }
7353
7766
  addClickHandler(callback) {
7354
- this.interactionManager.addClickHandler(callback);
7767
+ this.#container.interactionManager?.addClickHandler(callback);
7355
7768
  }
7356
7769
  clearClickHandlers() {
7357
- this.interactionManager.clearClickHandlers();
7770
+ this.#container.interactionManager?.clearClickHandlers();
7358
7771
  }
7359
7772
  destroy() {
7360
7773
  this.clearClickHandlers();
7361
- this.#pluginManager.interactors?.delete(this.#container);
7362
7774
  }
7363
7775
  particleCreated(particle) {
7364
- const interactivityParticle = particle, interactivity = new Interactivity(this.#pluginManager, this.#container);
7365
- interactivity.load(this.#container.actualOptions.interactivity);
7776
+ const interactivityParticle = particle, container = this.#container, interactivity = new Interactivity(container);
7777
+ interactivity.load(container.actualOptions.interactivity);
7366
7778
  interactivity.load(interactivityParticle.options.interactivity);
7367
7779
  interactivityParticle.interactivity = interactivity;
7368
7780
  }
7369
7781
  particleReset(particle) {
7370
- this.interactionManager.reset(particle);
7782
+ this.#container.interactionManager?.reset(particle);
7371
7783
  }
7372
7784
  postParticleUpdate(particle, delta) {
7373
- this.interactionManager.particlesInteract(particle, delta);
7785
+ this.#container.interactionManager?.particlesInteract(particle, delta);
7374
7786
  }
7375
7787
  postUpdate(delta) {
7376
- this.interactionManager.externalInteract(delta);
7377
- this.interactionManager.updateMaxDistance();
7788
+ const container = this.#container;
7789
+ container.interactionManager?.externalInteract(delta);
7790
+ container.interactionManager?.updateMaxDistance();
7378
7791
  }
7379
7792
  async preInit() {
7380
- await this.interactionManager.initInteractors();
7381
- this.interactionManager.init();
7793
+ const container = this.#container;
7794
+ await container.interactionManager?.initInteractors();
7795
+ container.interactionManager?.init();
7382
7796
  }
7383
7797
  async redrawInit() {
7384
- await this.interactionManager.initInteractors();
7385
- this.interactionManager.init();
7798
+ const container = this.#container;
7799
+ await container.interactionManager?.initInteractors();
7800
+ container.interactionManager?.init();
7386
7801
  }
7387
7802
  start() {
7388
- this.interactionManager.addListeners();
7389
- this.interactionManager.startObserving();
7803
+ const container = this.#container;
7804
+ container.interactionManager?.addListeners();
7805
+ container.interactionManager?.startObserving();
7390
7806
  return Promise.resolve();
7391
7807
  }
7392
7808
  stop() {
7393
- this.interactionManager.removeListeners();
7394
- this.interactionManager.stopObserving();
7809
+ this.#container.interactionManager?.removeListeners();
7810
+ this.#container.interactionManager?.stopObserving();
7395
7811
  }
7396
7812
  }
7397
7813
 
@@ -7420,7 +7836,7 @@
7420
7836
  }
7421
7837
  const retries = overlapOptions.retries;
7422
7838
  if (retries >= minRetries && tryCount > retries) {
7423
- throw new Error(`Particle is overlapping and can't be placed`);
7839
+ throw new Error(getErrorMessage(ErrorCodes.overlapNotPlaced));
7424
7840
  }
7425
7841
  return !!this.#container.particles.find(p => getDistance(pos, p.position) < particle.getRadius() + p.getRadius());
7426
7842
  }
@@ -7620,6 +8036,7 @@
7620
8036
  exports.BaseRange = BaseRange;
7621
8037
  exports.Circle = Circle;
7622
8038
  exports.ColorAnimation = ColorAnimation;
8039
+ exports.ErrorCodes = ErrorCodes$3;
7623
8040
  exports.Fill = Fill;
7624
8041
  exports.FullScreen = FullScreen;
7625
8042
  exports.HDROptions = HDROptions;
@@ -7651,6 +8068,7 @@
7651
8068
  exports.Vector = Vector;
7652
8069
  exports.Vector3d = Vector3d;
7653
8070
  exports.ZIndex = ZIndex;
8071
+ exports.addErrorMessages = addErrorMessages;
7654
8072
  exports.alterHsl = alterHsl;
7655
8073
  exports.animate = animate;
7656
8074
  exports.areBoundsInside = areBoundsInside;
@@ -7673,7 +8091,7 @@
7673
8091
  exports.countOffset = countOffset;
7674
8092
  exports.decayOffset = decayOffset;
7675
8093
  exports.deepExtend = deepExtend;
7676
- exports.defaultAlpha = defaultAlpha$1;
8094
+ exports.defaultAlpha = defaultAlpha;
7677
8095
  exports.defaultAngle = defaultAngle;
7678
8096
  exports.defaultCompositeValue = defaultCompositeValue;
7679
8097
  exports.defaultDensityFactor = defaultDensityFactor;
@@ -7697,12 +8115,17 @@
7697
8115
  exports.doublePI = doublePI;
7698
8116
  exports.empty = empty;
7699
8117
  exports.executeOnSingleOrMultiple = executeOnSingleOrMultiple;
8118
+ exports.fullPercent = fullPercent;
7700
8119
  exports.generatedAttribute = generatedAttribute;
7701
8120
  exports.generatedFalse = generatedFalse;
7702
8121
  exports.generatedTrue = generatedTrue;
8122
+ exports.getCanvasFromContainer = getCanvasFromContainer;
8123
+ exports.getDataFromUrl = getDataFromUrl;
7703
8124
  exports.getDistance = getDistance;
7704
8125
  exports.getDistanceSq = getDistanceSq;
7705
8126
  exports.getDistances = getDistances;
8127
+ exports.getDomContainer = getDomContainer;
8128
+ exports.getErrorMessage = getErrorMessage;
7706
8129
  exports.getFullScreenStyle = getFullScreenStyle;
7707
8130
  exports.getHslAnimationFromHsl = getHslAnimationFromHsl;
7708
8131
  exports.getHslFromAnimation = getHslFromAnimation;
@@ -7734,6 +8157,7 @@
7734
8157
  exports.inverseFactorNumerator = inverseFactorNumerator;
7735
8158
  exports.isArray = isArray;
7736
8159
  exports.isBoolean = isBoolean;
8160
+ exports.isEnumValue = isEnumValue;
7737
8161
  exports.isFunction = isFunction;
7738
8162
  exports.isInArray = isInArray;
7739
8163
  exports.isNull = isNull;
@@ -7766,7 +8190,7 @@
7766
8190
  exports.minFpsLimit = minFpsLimit;
7767
8191
  exports.minIndex = minIndex;
7768
8192
  exports.minLimit = minLimit;
7769
- exports.minRadius = minRadius$1;
8193
+ exports.minRadius = minRadius;
7770
8194
  exports.minStrokeWidth = minStrokeWidth;
7771
8195
  exports.minVelocity = minVelocity;
7772
8196
  exports.minZ = minZ;
@@ -7805,6 +8229,7 @@
7805
8229
  exports.stringToAlpha = stringToAlpha;
7806
8230
  exports.stringToRgb = stringToRgb;
7807
8231
  exports.threeQuarter = threeQuarter;
8232
+ exports.toEnumValue = toEnumValue;
7808
8233
  exports.triple = triple;
7809
8234
  exports.tryCountIncrement = tryCountIncrement;
7810
8235
  exports.tsParticles = tsParticles;
@@ -7813,10 +8238,11 @@
7813
8238
  exports.visibilityChangeEvent = visibilityChangeEvent;
7814
8239
  exports.zIndexFactorOffset = zIndexFactorOffset;
7815
8240
 
7816
- }));
8241
+ })(g.__tsParticlesInternals.bundles.particles = g.__tsParticlesInternals.bundles.particles || {});
8242
+ })(typeof globalThis !== "undefined" ? globalThis : typeof window !== "undefined" ? window : self);
8243
+
7817
8244
  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
8245
  globalThis.__tsParticlesInternals = globalThis.__tsParticlesInternals || {};
7819
8246
  if (!globalThis.__tsParticlesInternals.engine || !globalThis.__tsParticlesInternals.engine.tsParticles) {
7820
8247
  globalThis.__tsParticlesInternals.engine = globalThis.__tsParticlesInternals.bundles.particles || {};
7821
8248
  }
7822
- delete (globalThis.window || globalThis).tsparticlesInternalExports;