@tsparticles/preset-triangles 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,35 @@
1
- (function(g){g.__tsParticlesInternals=g.__tsParticlesInternals||{};g.__tsParticlesInternals.bundles=g.__tsParticlesInternals.bundles||{};g.__tsParticlesInternals.effects=g.__tsParticlesInternals.effects||{};g.__tsParticlesInternals.engine=g.__tsParticlesInternals.engine||{};g.__tsParticlesInternals.interactions=g.__tsParticlesInternals.interactions||{};g.__tsParticlesInternals.palettes=g.__tsParticlesInternals.palettes||{};g.__tsParticlesInternals.paths=g.__tsParticlesInternals.paths||{};g.__tsParticlesInternals.plugins=g.__tsParticlesInternals.plugins||{};g.__tsParticlesInternals.plugins=g.__tsParticlesInternals.plugins||{};g.__tsParticlesInternals.plugins.emittersShapes=g.__tsParticlesInternals.plugins.emittersShapes||{};g.__tsParticlesInternals.presets=g.__tsParticlesInternals.presets||{};g.__tsParticlesInternals.shapes=g.__tsParticlesInternals.shapes||{};g.__tsParticlesInternals.updaters=g.__tsParticlesInternals.updaters||{};g.__tsParticlesInternals.utils=g.__tsParticlesInternals.utils||{};g.__tsParticlesInternals.canvas=g.__tsParticlesInternals.canvas||{};g.__tsParticlesInternals.canvas=g.__tsParticlesInternals.canvas||{};g.__tsParticlesInternals.canvas.utils=g.__tsParticlesInternals.canvas.utils||{};g.__tsParticlesInternals.path=g.__tsParticlesInternals.path||{};g.__tsParticlesInternals.path=g.__tsParticlesInternals.path||{};g.__tsParticlesInternals.path.utils=g.__tsParticlesInternals.path.utils||{};var __tsProxyFactory=typeof Proxy!=="undefined"?function(obj){return new Proxy(obj,{get:function(target,key){if(!(key in target)){target[key]={};}return target[key];}});}:function(obj){return obj;};g.__tsParticlesInternals.bundles=__tsProxyFactory(g.__tsParticlesInternals.bundles);g.__tsParticlesInternals.effects=__tsProxyFactory(g.__tsParticlesInternals.effects);g.__tsParticlesInternals.interactions=__tsProxyFactory(g.__tsParticlesInternals.interactions);g.__tsParticlesInternals.palettes=__tsProxyFactory(g.__tsParticlesInternals.palettes);g.__tsParticlesInternals.paths=__tsProxyFactory(g.__tsParticlesInternals.paths);g.__tsParticlesInternals.plugins=__tsProxyFactory(g.__tsParticlesInternals.plugins);g.__tsParticlesInternals.plugins.emittersShapes=__tsProxyFactory(g.__tsParticlesInternals.plugins.emittersShapes);g.__tsParticlesInternals.presets=__tsProxyFactory(g.__tsParticlesInternals.presets);g.__tsParticlesInternals.shapes=__tsProxyFactory(g.__tsParticlesInternals.shapes);g.__tsParticlesInternals.updaters=__tsProxyFactory(g.__tsParticlesInternals.updaters);g.__tsParticlesInternals.utils=__tsProxyFactory(g.__tsParticlesInternals.utils);g.__tsParticlesInternals.canvas=__tsProxyFactory(g.__tsParticlesInternals.canvas);g.__tsParticlesInternals.path=__tsProxyFactory(g.__tsParticlesInternals.path);g.tsparticlesInternalExports=g.tsparticlesInternalExports||{};})(typeof globalThis!=="undefined"?globalThis:typeof window!=="undefined"?window:this);
2
- /* Preset v4.4.0 */
3
- (function (global, factory) {
4
- typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
5
- typeof define === 'function' && define.amd ? define(['exports'], factory) :
6
- (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory((global.__tsParticlesInternals = global.__tsParticlesInternals || {}, global.__tsParticlesInternals.presets = global.__tsParticlesInternals.presets || {}, global.__tsParticlesInternals.presets.triangles = global.__tsParticlesInternals.presets.triangles || {})));
7
- })(this, (function (exports) { 'use strict';
8
-
9
- const generatedAttribute = "generated", defaultCompositeValue = "source-over", resizeEvent = "resize", visibilityChangeEvent = "visibilitychange", percentDenominator = 100, half = 0.5, millisecondsToSeconds = 1000, originPoint = {
10
- x: 0,
11
- y: 0,
12
- z: 0,
13
- }, defaultTransform = {
14
- a: 1,
15
- b: 0,
16
- c: 0,
17
- d: 1,
18
- }, randomColorValue = "random", midColorValue = "mid", double = 2, doublePI = Math.PI * double, defaultFps = 60, generatedTrue = "true", generatedFalse = "false", canvasTag = "canvas", defaultRetryCount = 0, squareExp = 2, spatialHashGridCellSize = 100, defaultRemoveQuantity = 1, defaultRatio = 1, defaultReduceFactor = 1, inverseFactorNumerator = 1, rgbMax = 255, hMax = 360, sMax = 100, lMax = 100, hMin = 0, sMin = 0, hPhase = 60, empty = 0, quarter = 0.25, threeQuarter = half + quarter, minVelocity = 0, minDistance$2 = 0, defaultTransformValue = 1, minimumSize = 0, zIndexFactorOffset = 1, defaultOpacity$1 = 1, removeDeleteCount = 1, removeMinIndex = 0, defaultFpsLimit = 120, minFpsLimit = 0, canvasFirstIndex = 0, loadRandomFactor = 10000, loadMinIndex = 0, one = 1, none = 0, decayOffset = 1, tryCountIncrement = 1, minZ = 0, minLimit = 0, countOffset = 1, minCount = 0, minIndex = 0, lengthOffset = 1, defaultDensityFactor = 1, deleteCount = 1, defaultAngle = 0, identity = 1, minStrokeWidth = 0, lFactor = 1, lMin = 0, maxNits = 400, triple = 3, sextuple = 6, sNormalizedOffset = 1, phaseNumerator = 1, defaultRgbMin = 0, defaultVelocity = 0, defaultLoops = 0, defaultTime = 0, defaultZoom = 1;
1
+ (function(g){g.__tsParticlesInternals=g.__tsParticlesInternals||{};g.__tsParticlesInternals.bundles=g.__tsParticlesInternals.bundles||{};g.__tsParticlesInternals.effects=g.__tsParticlesInternals.effects||{};g.__tsParticlesInternals.engine=g.__tsParticlesInternals.engine||{};g.__tsParticlesInternals.interactions=g.__tsParticlesInternals.interactions||{};g.__tsParticlesInternals.palettes=g.__tsParticlesInternals.palettes||{};g.__tsParticlesInternals.paths=g.__tsParticlesInternals.paths||{};g.__tsParticlesInternals.plugins=g.__tsParticlesInternals.plugins||{};g.__tsParticlesInternals.plugins=g.__tsParticlesInternals.plugins||{};g.__tsParticlesInternals.plugins.emittersShapes=g.__tsParticlesInternals.plugins.emittersShapes||{};g.__tsParticlesInternals.presets=g.__tsParticlesInternals.presets||{};g.__tsParticlesInternals.shapes=g.__tsParticlesInternals.shapes||{};g.__tsParticlesInternals.updaters=g.__tsParticlesInternals.updaters||{};g.__tsParticlesInternals.utils=g.__tsParticlesInternals.utils||{};g.__tsParticlesInternals.canvas=g.__tsParticlesInternals.canvas||{};g.__tsParticlesInternals.canvas=g.__tsParticlesInternals.canvas||{};g.__tsParticlesInternals.canvas.utils=g.__tsParticlesInternals.canvas.utils||{};g.__tsParticlesInternals.path=g.__tsParticlesInternals.path||{};g.__tsParticlesInternals.path=g.__tsParticlesInternals.path||{};g.__tsParticlesInternals.path.utils=g.__tsParticlesInternals.path.utils||{};var __tsProxyFactory=typeof Proxy!=="undefined"?function(obj){return new Proxy(obj,{get:function(target,key){if(!(key in target)){target[key]={};}return target[key];}});}:function(obj){return obj;};g.__tsParticlesInternals.bundles=__tsProxyFactory(g.__tsParticlesInternals.bundles);g.__tsParticlesInternals.effects=__tsProxyFactory(g.__tsParticlesInternals.effects);g.__tsParticlesInternals.interactions=__tsProxyFactory(g.__tsParticlesInternals.interactions);g.__tsParticlesInternals.palettes=__tsProxyFactory(g.__tsParticlesInternals.palettes);g.__tsParticlesInternals.paths=__tsProxyFactory(g.__tsParticlesInternals.paths);g.__tsParticlesInternals.plugins=__tsProxyFactory(g.__tsParticlesInternals.plugins);g.__tsParticlesInternals.plugins.emittersShapes=__tsProxyFactory(g.__tsParticlesInternals.plugins.emittersShapes);g.__tsParticlesInternals.presets=__tsProxyFactory(g.__tsParticlesInternals.presets);g.__tsParticlesInternals.shapes=__tsProxyFactory(g.__tsParticlesInternals.shapes);g.__tsParticlesInternals.updaters=__tsProxyFactory(g.__tsParticlesInternals.updaters);g.__tsParticlesInternals.utils=__tsProxyFactory(g.__tsParticlesInternals.utils);g.__tsParticlesInternals.canvas=__tsProxyFactory(g.__tsParticlesInternals.canvas);g.__tsParticlesInternals.path=__tsProxyFactory(g.__tsParticlesInternals.path);})(typeof globalThis!=="undefined"?globalThis:typeof window!=="undefined"?window:this);
2
+ (function (g) {
3
+ /* Preset v4.5.1 */
4
+ g.__tsParticlesInternals = g.__tsParticlesInternals || {};
5
+ g.__tsParticlesInternals.presets = g.__tsParticlesInternals.presets || {};
6
+ (function (exports) {
7
+ 'use strict';
8
+
9
+ const errorPrefix = "tsParticles - Error", codedErrorPattern = /^\[tsParticles Error (TSP-\d+)\]\s*/, fullMatchIndex = 0, codeIndex = 1;
10
+ const wrap = (fn) => (...args) => {
11
+ fn(...args);
12
+ }, _logger = {
13
+ debug: wrap(console.debug),
14
+ error: (message, ...optionalParams) => {
15
+ if (typeof message === "string") {
16
+ const match = codedErrorPattern.exec(message);
17
+ if (match?.[codeIndex]) {
18
+ console.error(`tsParticles - ${match[codeIndex]} - ${message.slice(match[fullMatchIndex].length)}`, ...optionalParams);
19
+ return;
20
+ }
21
+ }
22
+ console.error(`${errorPrefix} - ${message}`, ...optionalParams);
23
+ },
24
+ info: wrap(console.info),
25
+ log: wrap(console.log),
26
+ trace: wrap(console.trace),
27
+ verbose: wrap(console.log),
28
+ warning: wrap(console.warn),
29
+ };
30
+ function getLogger() {
31
+ return _logger;
32
+ }
19
33
 
20
34
  var MoveDirection;
21
35
  (function (MoveDirection) {
@@ -32,6 +46,17 @@
32
46
  MoveDirection["inside"] = "inside";
33
47
  })(MoveDirection || (MoveDirection = {}));
34
48
 
49
+ const generatedAttribute = "generated", fullPercent = "100%", defaultCompositeValue = "source-over", resizeEvent = "resize", visibilityChangeEvent = "visibilitychange", percentDenominator = 100, half = 0.5, millisecondsToSeconds = 1000, originPoint = {
50
+ x: 0,
51
+ y: 0,
52
+ z: 0,
53
+ }, defaultTransform = {
54
+ a: 1,
55
+ b: 0,
56
+ c: 0,
57
+ d: 1,
58
+ }, randomColorValue = "random", midColorValue = "mid", double = 2, doublePI = Math.PI * double, defaultFps = 60, defaultAlpha = 1, generatedTrue = "true", generatedFalse = "false", canvasTag = "canvas", defaultRetryCount = 0, squareExp = 2, spatialHashGridCellSize = 100, defaultRemoveQuantity = 1, defaultRatio = 1, defaultReduceFactor = 1, inverseFactorNumerator = 1, rgbMax = 255, hMax = 360, sMax = 100, lMax = 100, hMin = 0, sMin = 0, hPhase = 60, empty = 0, quarter = 0.25, threeQuarter = half + quarter, minVelocity = 0, minDistance$2 = 0, minRadius = 0, defaultTransformValue = 1, minimumSize = 0, zIndexFactorOffset = 1, defaultOpacity$1 = 1, removeDeleteCount = 1, removeMinIndex = 0, defaultFpsLimit = 120, minFpsLimit = 0, canvasFirstIndex = 0, loadRandomFactor = 10000, loadMinIndex = 0, one = 1, none = 0, decayOffset = 1, tryCountIncrement = 1, minZ = 0, minLimit = 0, countOffset = 1, minCount = 0, minIndex = 0, lengthOffset = 1, defaultDensityFactor = 1, deleteCount = 1, defaultAngle = 0, identity = 1, minStrokeWidth = 0, lFactor = 1, lMin = 0, maxNits = 400, triple = 3, sextuple = 6, sNormalizedOffset = 1, phaseNumerator = 1, defaultRgbMin = 0, defaultVelocity = 0, defaultLoops = 0, defaultTime = 0, defaultZoom = 1;
59
+
35
60
  function getZ(source) {
36
61
  return "z" in source ? source.z : originPoint.z;
37
62
  }
@@ -147,6 +172,12 @@
147
172
  function isNumber(arg) {
148
173
  return typeof arg === "number";
149
174
  }
175
+ function isEnumValue(enumObject, arg) {
176
+ return Object.values(enumObject).some(enumValue => enumValue === arg);
177
+ }
178
+ function toEnumValue(enumObject, arg, defaultValue) {
179
+ return isEnumValue(enumObject, arg) ? arg : defaultValue;
180
+ }
150
181
  function isObject(arg) {
151
182
  return typeof arg === "object" && arg !== null;
152
183
  }
@@ -273,11 +304,61 @@
273
304
  };
274
305
  }
275
306
  function parseAlpha(input) {
276
- const defaultAlpha = 1;
277
307
  if (!input) {
278
308
  return defaultAlpha;
279
309
  }
280
- return input.endsWith("%") ? parseFloat(input) / percentDenominator : parseFloat(input);
310
+ return input.endsWith("%") ? Number.parseFloat(input) / percentDenominator : Number.parseFloat(input);
311
+ }
312
+
313
+ const ErrorCodes$2 = {
314
+ engineVersionMismatch: "TSP-1001",
315
+ particlePositionNotFound: "TSP-1002",
316
+ pluginRegisterAfterLoad: "TSP-1003",
317
+ offscreenCanvasUnsupported: "TSP-1101",
318
+ offscreenCanvasTransferFailed: "TSP-1102",
319
+ hdrEnableInvalid: "TSP-1201",
320
+ hdrModeInvalid: "TSP-1202",
321
+ hdrPeakNitsInvalid: "TSP-1203",
322
+ };
323
+
324
+ const messages = {
325
+ [ErrorCodes$2.engineVersionMismatch]: "The tsParticles version is different from the loaded plugins version. Engine version: {0}. Plugin version: {1}",
326
+ [ErrorCodes$2.particlePositionNotFound]: "a valid position cannot be found for particle",
327
+ [ErrorCodes$2.pluginRegisterAfterLoad]: "Register plugins can only be done before calling tsParticles.load()",
328
+ [ErrorCodes$2.offscreenCanvasUnsupported]: "OffscreenCanvas is required but not supported by this browser",
329
+ [ErrorCodes$2.offscreenCanvasTransferFailed]: "OffscreenCanvas transfer failed",
330
+ [ErrorCodes$2.hdrEnableInvalid]: 'Invalid HDR "enable" value: expected a boolean, got "{0}"',
331
+ [ErrorCodes$2.hdrModeInvalid]: 'Invalid HDR "mode" value: expected one of {0}, got "{1}"',
332
+ [ErrorCodes$2.hdrPeakNitsInvalid]: 'Invalid HDR "peakNits" value: expected a positive number, got "{0}"',
333
+ };
334
+
335
+ let registeredMessages;
336
+ const ensureRegisteredMessages = () => {
337
+ registeredMessages ??= new Map(Object.entries(messages));
338
+ return registeredMessages;
339
+ }, toStringValue$1 = (value) => String(value), format = (template, args) => {
340
+ return template.replace(/\{(\d+)\}/g, (match, index) => {
341
+ const arg = args[Number(index)];
342
+ return arg === undefined ? match : toStringValue$1(arg);
343
+ });
344
+ };
345
+ function addErrorMessages(extraMessages) {
346
+ if (typeof process !== "undefined" && process.env.NODE_ENV === "production") {
347
+ return;
348
+ }
349
+ const catalog = ensureRegisteredMessages();
350
+ for (const [code, message] of Object.entries(extraMessages)) {
351
+ if (message !== undefined) {
352
+ catalog.set(code, message);
353
+ }
354
+ }
355
+ }
356
+ function getErrorMessage(code, ...args) {
357
+ if (typeof process !== "undefined" && process.env.NODE_ENV === "production") {
358
+ return `[tsParticles Error ${code}] https://particles.js.org/errors/#${code}`;
359
+ }
360
+ const template = ensureRegisteredMessages().get(code) ?? `Unknown error code ${code}`;
361
+ return format(template, args);
281
362
  }
282
363
 
283
364
  var OutModeDirection;
@@ -294,7 +375,6 @@
294
375
  PixelMode["percent"] = "percent";
295
376
  })(PixelMode || (PixelMode = {}));
296
377
 
297
- const minRadius = 0;
298
378
  function isForbiddenKey(key) {
299
379
  return key === "__proto__" || key === "constructor" || key === "prototype";
300
380
  }
@@ -490,22 +570,84 @@
490
570
  element.removeEventListener(event, handler, removeOptions);
491
571
  }
492
572
  }
493
- async function getItemsFromInitializer(container, map, initializers, force = false) {
494
- let res = map.get(container);
495
- if (!res || force) {
496
- res = await Promise.all([...initializers.values()].map(t => t(container)));
497
- map.set(container, res);
573
+ async function getItemsFromInitializer(container, initializers) {
574
+ return await Promise.all([...initializers.values()].map(t => t(container)));
575
+ }
576
+ async function getItemMapFromInitializer(container, initializers) {
577
+ const entries = await Promise.all([...initializers.entries()].map(([key, initializer]) => initializer(container).then(item => [key, item])));
578
+ return new Map(entries);
579
+ }
580
+ async function getDataFromUrl(data) {
581
+ const url = itemFromSingleOrMultiple(data.url, data.index);
582
+ if (!url) {
583
+ return data.fallback;
498
584
  }
499
- return res;
585
+ try {
586
+ const response = await fetch(url);
587
+ if (response.ok) {
588
+ const current = (await response.json());
589
+ if (isSourceOptionsValue(current)) {
590
+ return current;
591
+ }
592
+ getLogger().error("invalid configuration data while retrieving config file");
593
+ }
594
+ else {
595
+ getLogger().error(`${response.status.toString()} while retrieving config file`);
596
+ }
597
+ }
598
+ catch (error) {
599
+ getLogger().error(`error while retrieving config file: ${error}`);
600
+ }
601
+ return data.fallback;
500
602
  }
501
- async function getItemMapFromInitializer(container, map, initializers, force = false) {
502
- let res = map.get(container);
503
- if (!res || force) {
504
- const entries = await Promise.all([...initializers.entries()].map(([key, initializer]) => initializer(container).then(item => [key, item])));
505
- res = new Map(entries);
506
- map.set(container, res);
603
+ function isSourceOptionsValue(value) {
604
+ if (isArray(value)) {
605
+ return value.every((entry) => isObject(entry) && !isArray(entry));
507
606
  }
508
- return res;
607
+ return isObject(value) && !isArray(value);
608
+ }
609
+ function getCanvasFromContainer(domContainer) {
610
+ let canvasEl;
611
+ const documentSafe = safeDocument(), isCanvas = domContainer instanceof HTMLCanvasElement || domContainer.tagName.toLowerCase() === canvasTag;
612
+ if (isCanvas) {
613
+ canvasEl = domContainer;
614
+ canvasEl.dataset[generatedAttribute] ??= generatedFalse;
615
+ if (canvasEl.dataset[generatedAttribute] === generatedTrue) {
616
+ canvasEl.style.width ||= fullPercent;
617
+ canvasEl.style.height ||= fullPercent;
618
+ canvasEl.style.pointerEvents = "none";
619
+ canvasEl.style.setProperty("pointer-events", "none");
620
+ }
621
+ }
622
+ else {
623
+ const existingCanvases = domContainer.getElementsByTagName(canvasTag), foundCanvas = existingCanvases.item(canvasFirstIndex);
624
+ if (foundCanvas) {
625
+ canvasEl = foundCanvas;
626
+ canvasEl.dataset[generatedAttribute] = generatedFalse;
627
+ }
628
+ else {
629
+ canvasEl = documentSafe.createElement(canvasTag);
630
+ canvasEl.dataset[generatedAttribute] = generatedTrue;
631
+ domContainer.appendChild(canvasEl);
632
+ }
633
+ canvasEl.style.width ||= fullPercent;
634
+ canvasEl.style.height ||= fullPercent;
635
+ canvasEl.style.pointerEvents = "none";
636
+ canvasEl.style.setProperty("pointer-events", "none");
637
+ }
638
+ return canvasEl;
639
+ }
640
+ function getDomContainer(id, source) {
641
+ const documentSafe = safeDocument();
642
+ let domContainer = source ?? documentSafe.getElementById(id);
643
+ if (domContainer) {
644
+ return domContainer;
645
+ }
646
+ domContainer = documentSafe.createElement("canvas");
647
+ domContainer.id = id;
648
+ domContainer.dataset[generatedAttribute] = generatedTrue;
649
+ documentSafe.body.append(domContainer);
650
+ return domContainer;
509
651
  }
510
652
 
511
653
  class EventDispatcher {
@@ -515,12 +657,8 @@
515
657
  }
516
658
  addEventListener(type, listener) {
517
659
  this.removeEventListener(type, listener);
518
- let arr = this.#listeners.get(type);
519
- if (!arr) {
520
- arr = [];
521
- this.#listeners.set(type, arr);
522
- }
523
- arr.push(listener);
660
+ const arr = this.#listeners.get(type);
661
+ this.#listeners.set(type, arr ? [...arr, listener] : [listener]);
524
662
  }
525
663
  dispatchEvent(type, args) {
526
664
  const listeners = this.#listeners.get(type);
@@ -552,7 +690,7 @@
552
690
  this.#listeners.delete(type);
553
691
  }
554
692
  else {
555
- arr.splice(idx, deleteCount);
693
+ this.#listeners.set(type, [...arr.slice(minIndex, idx), ...arr.slice(idx + deleteCount)]);
556
694
  }
557
695
  }
558
696
  }
@@ -576,7 +714,6 @@
576
714
  class PluginManager {
577
715
  colorManagers = new Map();
578
716
  easingFunctions = new Map();
579
- effectDrawers = new Map();
580
717
  initializers = {
581
718
  effects: new Map(),
582
719
  shapes: new Map(),
@@ -585,8 +722,6 @@
585
722
  palettes = new Map();
586
723
  plugins = [];
587
724
  presets = new Map();
588
- shapeDrawers = new Map();
589
- updaters = new Map();
590
725
  #allLoadersSet = new Set();
591
726
  #configs = new Map();
592
727
  #engine;
@@ -604,57 +739,79 @@
604
739
  }
605
740
  return res;
606
741
  }
742
+ get initialized() {
743
+ return this.#initialized;
744
+ }
607
745
  addColorManager(name, manager) {
746
+ if (this.#initialized) {
747
+ return;
748
+ }
608
749
  this.colorManagers.set(name, manager);
609
750
  }
610
751
  addConfig(config) {
752
+ if (this.#initialized) {
753
+ return;
754
+ }
611
755
  const key = config.key ?? config.name ?? "default";
612
756
  this.#configs.set(key, config);
613
757
  this.#engine.dispatchEvent(EventType.configAdded, { data: { name: key, config } });
614
758
  }
615
759
  addEasing(name, easing) {
760
+ if (this.#initialized) {
761
+ return;
762
+ }
616
763
  if (this.easingFunctions.get(name)) {
617
764
  return;
618
765
  }
619
766
  this.easingFunctions.set(name, easing);
620
767
  }
621
768
  addEffect(effect, drawer) {
769
+ if (this.#initialized) {
770
+ return;
771
+ }
622
772
  this.initializers.effects.set(effect, drawer);
623
773
  }
624
774
  addPalette(name, palette) {
775
+ if (this.#initialized) {
776
+ return;
777
+ }
625
778
  this.palettes.set(name, palette);
626
779
  }
627
780
  addParticleUpdater(name, updaterInitializer) {
781
+ if (this.#initialized) {
782
+ return;
783
+ }
628
784
  this.initializers.updaters.set(name, updaterInitializer);
629
785
  }
630
786
  addPlugin(plugin) {
787
+ if (this.#initialized) {
788
+ return;
789
+ }
631
790
  if (this.getPlugin(plugin.id)) {
632
791
  return;
633
792
  }
634
793
  this.plugins.push(plugin);
635
794
  }
636
795
  addPreset(preset, options, override = false) {
796
+ if (this.#initialized) {
797
+ return;
798
+ }
637
799
  if (!(override || !this.getPreset(preset))) {
638
800
  return;
639
801
  }
640
802
  this.presets.set(preset, options);
641
803
  }
642
804
  addShape(shapes, drawer) {
805
+ if (this.#initialized) {
806
+ return;
807
+ }
643
808
  for (const shape of shapes) {
644
809
  this.initializers.shapes.set(shape, drawer);
645
810
  }
646
811
  }
647
- clearPlugins(container) {
648
- this.effectDrawers.delete(container);
649
- this.shapeDrawers.delete(container);
650
- this.updaters.delete(container);
651
- }
652
812
  getEasing(name) {
653
813
  return this.easingFunctions.get(name) ?? ((value) => value);
654
814
  }
655
- getEffectDrawers(container, force = false) {
656
- return getItemMapFromInitializer(container, this.effectDrawers, this.initializers.effects, force);
657
- }
658
815
  getPalette(name) {
659
816
  return this.palettes.get(name);
660
817
  }
@@ -664,12 +821,6 @@
664
821
  getPreset(preset) {
665
822
  return this.presets.get(preset);
666
823
  }
667
- async getShapeDrawers(container, force = false) {
668
- return getItemMapFromInitializer(container, this.shapeDrawers, this.initializers.shapes, force);
669
- }
670
- async getUpdaters(container, force = false) {
671
- return getItemsFromInitializer(container, this.updaters, this.initializers.updaters, force);
672
- }
673
824
  async init() {
674
825
  if (this.#initialized || this.#isRunningLoaders) {
675
826
  return;
@@ -688,16 +839,9 @@
688
839
  this.#initialized = true;
689
840
  }
690
841
  }
691
- loadParticlesOptions(container, options, ...sourceOptions) {
692
- const updaters = this.updaters.get(container);
693
- if (!updaters) {
694
- return;
695
- }
696
- updaters.forEach(updater => updater.loadOptions?.(options, ...sourceOptions));
697
- }
698
842
  async register(...loaders) {
699
843
  if (this.#initialized) {
700
- throw new Error("Register plugins can only be done before calling tsParticles.load()");
844
+ throw new Error(getErrorMessage(ErrorCodes$2.pluginRegisterAfterLoad));
701
845
  }
702
846
  for (const loader of loaders) {
703
847
  if (this.#isRunningLoaders) {
@@ -709,88 +853,15 @@
709
853
  }
710
854
  }
711
855
  async #runLoader(loader, executed, allLoaders) {
712
- if (executed.has(loader))
856
+ if (executed.has(loader)) {
713
857
  return;
858
+ }
714
859
  executed.add(loader);
715
860
  allLoaders.add(loader);
716
861
  await loader(this.#engine);
717
862
  }
718
863
  }
719
864
 
720
- const errorPrefix = "tsParticles - Error";
721
- const wrap = (fn) => (...args) => {
722
- fn(...args);
723
- }, _logger = {
724
- debug: wrap(console.debug),
725
- error: (message, ...optionalParams) => {
726
- console.error(`${errorPrefix} - ${message}`, ...optionalParams);
727
- },
728
- info: wrap(console.info),
729
- log: wrap(console.log),
730
- trace: wrap(console.trace),
731
- verbose: wrap(console.log),
732
- warning: wrap(console.warn),
733
- };
734
- function getLogger() {
735
- return _logger;
736
- }
737
-
738
- const fullPercent = "100%";
739
- async function getDataFromUrl(data) {
740
- const url = itemFromSingleOrMultiple(data.url, data.index);
741
- if (!url) {
742
- return data.fallback;
743
- }
744
- const response = await fetch(url);
745
- if (response.ok) {
746
- return (await response.json());
747
- }
748
- getLogger().error(`${response.status.toString()} while retrieving config file`);
749
- return data.fallback;
750
- }
751
- const getCanvasFromContainer = (domContainer) => {
752
- const documentSafe = safeDocument();
753
- let canvasEl;
754
- const isCanvas = domContainer instanceof HTMLCanvasElement || domContainer.tagName.toLowerCase() === canvasTag;
755
- if (isCanvas) {
756
- canvasEl = domContainer;
757
- canvasEl.dataset[generatedAttribute] ??= generatedFalse;
758
- if (canvasEl.dataset[generatedAttribute] === generatedTrue) {
759
- canvasEl.style.width ||= fullPercent;
760
- canvasEl.style.height ||= fullPercent;
761
- canvasEl.style.pointerEvents = "none";
762
- canvasEl.style.setProperty("pointer-events", "none");
763
- }
764
- }
765
- else {
766
- const existingCanvases = domContainer.getElementsByTagName(canvasTag), foundCanvas = existingCanvases.item(canvasFirstIndex);
767
- if (foundCanvas) {
768
- canvasEl = foundCanvas;
769
- canvasEl.dataset[generatedAttribute] = generatedFalse;
770
- }
771
- else {
772
- canvasEl = documentSafe.createElement(canvasTag);
773
- canvasEl.dataset[generatedAttribute] = generatedTrue;
774
- domContainer.appendChild(canvasEl);
775
- }
776
- canvasEl.style.width ||= fullPercent;
777
- canvasEl.style.height ||= fullPercent;
778
- canvasEl.style.pointerEvents = "none";
779
- canvasEl.style.setProperty("pointer-events", "none");
780
- }
781
- return canvasEl;
782
- }, getDomContainer = (id, source) => {
783
- const documentSafe = safeDocument();
784
- let domContainer = source ?? documentSafe.getElementById(id);
785
- if (domContainer) {
786
- return domContainer;
787
- }
788
- domContainer = documentSafe.createElement("canvas");
789
- domContainer.id = id;
790
- domContainer.dataset[generatedAttribute] = generatedTrue;
791
- documentSafe.body.append(domContainer);
792
- return domContainer;
793
- };
794
865
  class Engine {
795
866
  pluginManager = new PluginManager(this);
796
867
  #domArray = [];
@@ -800,7 +871,7 @@
800
871
  return this.#domArray;
801
872
  }
802
873
  get version() {
803
- return "4.4.0";
874
+ return "4.5.1";
804
875
  }
805
876
  addEventListener(type, listener) {
806
877
  this.#eventDispatcher.addEventListener(type, listener);
@@ -809,7 +880,7 @@
809
880
  if (this.version === pluginVersion) {
810
881
  return;
811
882
  }
812
- throw new Error(`The tsParticles version is different from the loaded plugins version. Engine version: ${this.version}. Plugin version: ${pluginVersion}`);
883
+ throw new Error(getErrorMessage(ErrorCodes$2.engineVersionMismatch, this.version, pluginVersion));
813
884
  }
814
885
  dispatchEvent(type, args) {
815
886
  this.#eventDispatcher.dispatchEvent(type, args);
@@ -1058,20 +1129,6 @@
1058
1129
  DrawLayer[DrawLayer["Foreground"] = 7] = "Foreground";
1059
1130
  })(DrawLayer || (DrawLayer = {}));
1060
1131
 
1061
- class OptionLoader {
1062
- load(data) {
1063
- if (isNull(data)) {
1064
- return;
1065
- }
1066
- this.doLoad(data);
1067
- }
1068
- }
1069
- function loadOptions(options, ...sourceOptionsArr) {
1070
- for (const sourceOptions of sourceOptionsArr) {
1071
- options.load(sourceOptions);
1072
- }
1073
- }
1074
-
1075
1132
  function loadProperty(obj, key, value) {
1076
1133
  if (value !== undefined) {
1077
1134
  obj[key] = value;
@@ -1103,6 +1160,20 @@
1103
1160
  }
1104
1161
  }
1105
1162
 
1163
+ class OptionLoader {
1164
+ load(data) {
1165
+ if (isNull(data)) {
1166
+ return;
1167
+ }
1168
+ this.doLoad(data);
1169
+ }
1170
+ }
1171
+ function loadOptions(options, ...sourceOptionsArr) {
1172
+ for (const sourceOptions of sourceOptionsArr) {
1173
+ options.load(sourceOptions);
1174
+ }
1175
+ }
1176
+
1106
1177
  class AnimationOptions extends OptionLoader {
1107
1178
  count = 0;
1108
1179
  decay = 0;
@@ -1253,15 +1324,14 @@
1253
1324
  peakNits = defaultPeakNits;
1254
1325
  doLoad(data) {
1255
1326
  if (data.enable !== undefined && !isBoolean(data.enable)) {
1256
- throw new Error(`Invalid HDR "enable" value: expected a boolean, got "${String(data.enable)}"`);
1327
+ throw new Error(getErrorMessage(ErrorCodes$2.hdrEnableInvalid, String(data.enable)));
1257
1328
  }
1258
- if (data.mode !== undefined &&
1259
- (typeof data.mode !== "string" || !Object.values(HdrMode).includes(data.mode))) {
1260
- throw new Error(`Invalid HDR "mode" value: expected one of ${Object.values(HdrMode).join(", ")}, got "${toStringValue(data.mode)}"`);
1329
+ if (data.mode !== undefined && !isEnumValue(HdrMode, data.mode)) {
1330
+ throw new Error(getErrorMessage(ErrorCodes$2.hdrModeInvalid, Object.values(HdrMode).join(", "), toStringValue(data.mode)));
1261
1331
  }
1262
1332
  if (data.peakNits !== undefined &&
1263
1333
  (!isNumber(data.peakNits) || !Number.isFinite(data.peakNits) || data.peakNits <= minPeakNits)) {
1264
- throw new Error(`Invalid HDR "peakNits" value: expected a positive number, got "${String(data.peakNits)}"`);
1334
+ throw new Error(getErrorMessage(ErrorCodes$2.hdrPeakNitsInvalid, String(data.peakNits)));
1265
1335
  }
1266
1336
  loadProperty(this, "enable", data.enable);
1267
1337
  loadProperty(this, "mode", data.mode);
@@ -1639,12 +1709,10 @@
1639
1709
  plugin.loadParticlesOptions(this.#container, this, data);
1640
1710
  }
1641
1711
  }
1642
- const updaters = this.#pluginManager.updaters.get(this.#container);
1643
- if (updaters) {
1644
- for (const updater of updaters) {
1645
- if (updater.loadOptions) {
1646
- updater.loadOptions(this, data);
1647
- }
1712
+ const updaters = this.#container.particleUpdaters;
1713
+ for (const updater of updaters) {
1714
+ if (updater.loadOptions) {
1715
+ updater.loadOptions(this, data);
1648
1716
  }
1649
1717
  }
1650
1718
  }
@@ -1983,9 +2051,9 @@
1983
2051
  const grayscaleValue = Math.round(lNormalized * rgbMax);
1984
2052
  return { r: grayscaleValue, g: grayscaleValue, b: grayscaleValue };
1985
2053
  }
1986
- const temp1 = lNormalized < half
2054
+ const temp2 = lNormalized < half
1987
2055
  ? lNormalized * (sNormalizedOffset + sNormalized)
1988
- : lNormalized + sNormalized - lNormalized * sNormalized, temp2 = double * lNormalized - temp1, phaseThird = phaseNumerator / triple, red = Math.min(rgbMax, rgbMax * hslChannel(temp2, temp1, hNormalized + phaseThird)), green = Math.min(rgbMax, rgbMax * hslChannel(temp2, temp1, hNormalized)), blue = Math.min(rgbMax, rgbMax * hslChannel(temp2, temp1, hNormalized - phaseThird));
2056
+ : lNormalized + sNormalized - lNormalized * sNormalized, temp1 = double * lNormalized - temp2, phaseThird = phaseNumerator / triple, red = Math.min(rgbMax, rgbMax * hslChannel(temp1, temp2, hNormalized + phaseThird)), green = Math.min(rgbMax, rgbMax * hslChannel(temp1, temp2, hNormalized)), blue = Math.min(rgbMax, rgbMax * hslChannel(temp1, temp2, hNormalized - phaseThird));
1989
2057
  return { r: Math.round(red), g: Math.round(green), b: Math.round(blue) };
1990
2058
  }
1991
2059
  function hslToRgbFloat(hsl) {
@@ -1994,9 +2062,9 @@
1994
2062
  const grayscaleValue = lNormalized * rgbMax;
1995
2063
  return { r: grayscaleValue, g: grayscaleValue, b: grayscaleValue };
1996
2064
  }
1997
- const temp1 = lNormalized < half
2065
+ const temp2 = lNormalized < half
1998
2066
  ? lNormalized * (sNormalizedOffset + sNormalized)
1999
- : lNormalized + sNormalized - lNormalized * sNormalized, temp2 = double * lNormalized - temp1, phaseThird = phaseNumerator / triple, red = Math.min(rgbMax, rgbMax * hslChannel(temp2, temp1, hNormalized + phaseThird)), green = Math.min(rgbMax, rgbMax * hslChannel(temp2, temp1, hNormalized)), blue = Math.min(rgbMax, rgbMax * hslChannel(temp2, temp1, hNormalized - phaseThird));
2067
+ : lNormalized + sNormalized - lNormalized * sNormalized, temp1 = double * lNormalized - temp2, phaseThird = phaseNumerator / triple, red = Math.min(rgbMax, rgbMax * hslChannel(temp1, temp2, hNormalized + phaseThird)), green = Math.min(rgbMax, rgbMax * hslChannel(temp1, temp2, hNormalized)), blue = Math.min(rgbMax, rgbMax * hslChannel(temp1, temp2, hNormalized - phaseThird));
2000
2068
  return { r: red, g: green, b: blue };
2001
2069
  }
2002
2070
  function hslaToRgba(hsla) {
@@ -2283,7 +2351,7 @@
2283
2351
  }
2284
2352
 
2285
2353
  async function loadBlendPlugin(engine) {
2286
- engine.checkVersion("4.4.0");
2354
+ engine.checkVersion("4.5.1");
2287
2355
  await engine.pluginManager.register(e => {
2288
2356
  e.pluginManager.addPlugin(new BlendPlugin());
2289
2357
  });
@@ -2320,7 +2388,7 @@
2320
2388
  }
2321
2389
 
2322
2390
  async function loadCircleShape(engine) {
2323
- engine.checkVersion("4.4.0");
2391
+ engine.checkVersion("4.5.1");
2324
2392
  await engine.pluginManager.register(e => {
2325
2393
  e.pluginManager.addShape(["circle"], () => {
2326
2394
  return Promise.resolve(new CircleDrawer());
@@ -2335,7 +2403,7 @@
2335
2403
  RgbIndexes[RgbIndexes["b"] = 3] = "b";
2336
2404
  RgbIndexes[RgbIndexes["a"] = 4] = "a";
2337
2405
  })(RgbIndexes$1 || (RgbIndexes$1 = {}));
2338
- const shorthandHexRegex = /^#?([a-f\d])([a-f\d])([a-f\d])([a-f\d])?$/i, hexRegex = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})?$/i, hexRadix = 16, defaultAlpha = 1, alphaFactor = 0xff;
2406
+ const shorthandHexRegex = /^#?([a-f\d])([a-f\d])([a-f\d])([a-f\d])?$/i, hexRegex = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})?$/i, hexRadix = 16, alphaFactor = 0xff;
2339
2407
  class HexColorManager {
2340
2408
  accepts(input) {
2341
2409
  return input.startsWith("#");
@@ -2368,7 +2436,7 @@
2368
2436
  }
2369
2437
 
2370
2438
  async function loadHexColorPlugin(engine) {
2371
- engine.checkVersion("4.4.0");
2439
+ engine.checkVersion("4.5.1");
2372
2440
  await engine.pluginManager.register(e => {
2373
2441
  e.pluginManager.addColorManager("hex", new HexColorManager());
2374
2442
  });
@@ -2408,7 +2476,7 @@
2408
2476
  if (!this.accepts(input)) {
2409
2477
  return;
2410
2478
  }
2411
- const result = hslRegex.exec(input), minLength = 4, defaultAlpha = 1, radix = 10;
2479
+ const result = hslRegex.exec(input), minLength = 4, radix = 10;
2412
2480
  return result
2413
2481
  ? hslaToRgba({
2414
2482
  a: result.length > minLength ? parseAlpha(result[HslIndexes.a]) : defaultAlpha,
@@ -2421,12 +2489,20 @@
2421
2489
  }
2422
2490
 
2423
2491
  async function loadHslColorPlugin(engine) {
2424
- engine.checkVersion("4.4.0");
2492
+ engine.checkVersion("4.5.1");
2425
2493
  await engine.pluginManager.register(e => {
2426
2494
  e.pluginManager.addColorManager("hsl", new HslColorManager());
2427
2495
  });
2428
2496
  }
2429
2497
 
2498
+ const ErrorCodes$1 = {
2499
+ baseMoverNotLoaded: "TSP-3203",
2500
+ };
2501
+
2502
+ const ErrorMessages$1 = {
2503
+ [ErrorCodes$1.baseMoverNotLoaded]: "tsParticles Base Mover is not loaded",
2504
+ };
2505
+
2430
2506
  class MovePlugin {
2431
2507
  id = "move";
2432
2508
  #pluginManager;
@@ -2445,20 +2521,20 @@
2445
2521
  }
2446
2522
 
2447
2523
  async function loadMovePlugin(engine) {
2448
- engine.checkVersion("4.4.0");
2524
+ engine.checkVersion("4.5.1");
2525
+ if (typeof process !== "undefined" && process.env.NODE_ENV !== "production") {
2526
+ addErrorMessages(ErrorMessages$1);
2527
+ }
2449
2528
  await engine.pluginManager.register(e => {
2450
2529
  const moveEngine = e, movePluginManager = moveEngine.pluginManager;
2451
2530
  movePluginManager.initializers.pathGenerators ??= new Map();
2452
- movePluginManager.pathGenerators ??= new Map();
2453
2531
  movePluginManager.addPathGenerator = (name, generator) => {
2532
+ if (movePluginManager.initialized) {
2533
+ return;
2534
+ }
2454
2535
  movePluginManager.initializers.pathGenerators ??= new Map();
2455
2536
  movePluginManager.initializers.pathGenerators.set(name, generator);
2456
2537
  };
2457
- movePluginManager.getPathGenerators = async (container, force = false) => {
2458
- movePluginManager.initializers.pathGenerators ??= new Map();
2459
- movePluginManager.pathGenerators ??= new Map();
2460
- return getItemMapFromInitializer(container, movePluginManager.pathGenerators, movePluginManager.initializers.pathGenerators, force);
2461
- };
2462
2538
  e.pluginManager.addPlugin(new MovePlugin(e.pluginManager));
2463
2539
  });
2464
2540
  }
@@ -2655,7 +2731,7 @@
2655
2731
  }
2656
2732
 
2657
2733
  async function loadOpacityUpdater(engine) {
2658
- engine.checkVersion("4.4.0");
2734
+ engine.checkVersion("4.5.1");
2659
2735
  await engine.pluginManager.register(e => {
2660
2736
  e.pluginManager.addParticleUpdater("opacity", container => {
2661
2737
  return Promise.resolve(new OpacityUpdater(container));
@@ -2664,70 +2740,60 @@
2664
2740
  }
2665
2741
 
2666
2742
  const boundsMin = 0;
2667
- function bounceHorizontal(data) {
2668
- if ((data.outMode !== OutMode.bounce && data.outMode !== OutMode.split) ||
2669
- (data.direction !== OutModeDirection.left && data.direction !== OutModeDirection.right)) {
2670
- return;
2671
- }
2672
- if (data.bounds.right < boundsMin && data.direction === OutModeDirection.left) {
2673
- data.particle.position.x = data.size + data.offset.x;
2674
- }
2675
- else if (data.bounds.left > data.canvasSize.width && data.direction === OutModeDirection.right) {
2676
- data.particle.position.x = data.canvasSize.width - data.size - data.offset.x;
2677
- }
2678
- const velocity = data.particle.velocity.x;
2679
- let bounced = false;
2680
- if (data.outOfCanvas &&
2681
- ((data.direction === OutModeDirection.right && velocity > minVelocity) ||
2682
- (data.direction === OutModeDirection.left && velocity < minVelocity))) {
2683
- const newVelocity = getRangeValue(data.particle.options.bounce.horizontal.value);
2684
- data.particle.velocity.x *= -newVelocity;
2685
- bounced = true;
2686
- }
2687
- if (!bounced) {
2688
- return;
2689
- }
2690
- const minPos = data.offset.x + data.size;
2691
- if (data.outOfCanvas && data.direction === OutModeDirection.right) {
2692
- data.particle.position.x = data.canvasSize.width - minPos;
2693
- }
2694
- else if (data.outOfCanvas && data.direction === OutModeDirection.left) {
2695
- data.particle.position.x = minPos;
2696
- }
2697
- if (data.outMode === OutMode.split) {
2698
- data.particle.destroy();
2699
- }
2700
- }
2701
- function bounceVertical(data) {
2702
- if ((data.outMode !== OutMode.bounce && data.outMode !== OutMode.split) ||
2703
- (data.direction !== OutModeDirection.bottom && data.direction !== OutModeDirection.top)) {
2743
+ const bounceAxisConfigs = {
2744
+ [OutModeDirection.left]: {
2745
+ axis: "x",
2746
+ canvas: "width",
2747
+ bounce: "horizontal",
2748
+ negativeEdge: "right",
2749
+ positiveEdge: "left",
2750
+ negative: true,
2751
+ },
2752
+ [OutModeDirection.right]: {
2753
+ axis: "x",
2754
+ canvas: "width",
2755
+ bounce: "horizontal",
2756
+ negativeEdge: "right",
2757
+ positiveEdge: "left",
2758
+ negative: false,
2759
+ },
2760
+ [OutModeDirection.top]: {
2761
+ axis: "y",
2762
+ canvas: "height",
2763
+ bounce: "vertical",
2764
+ negativeEdge: "bottom",
2765
+ positiveEdge: "top",
2766
+ negative: true,
2767
+ },
2768
+ [OutModeDirection.bottom]: {
2769
+ axis: "y",
2770
+ canvas: "height",
2771
+ bounce: "vertical",
2772
+ negativeEdge: "bottom",
2773
+ positiveEdge: "top",
2774
+ negative: false,
2775
+ },
2776
+ };
2777
+ function bounce(data) {
2778
+ if ((data.outMode !== OutMode.bounce && data.outMode !== OutMode.split) || !(data.direction in bounceAxisConfigs)) {
2704
2779
  return;
2705
2780
  }
2706
- if (data.bounds.bottom < boundsMin && data.direction === OutModeDirection.top) {
2707
- data.particle.position.y = data.size + data.offset.y;
2781
+ const config = bounceAxisConfigs[data.direction], bounds = data.bounds, canvasDim = data.canvasSize[config.canvas], position = data.particle.position, velocity = data.particle.velocity[config.axis];
2782
+ if (config.negative && bounds[config.negativeEdge] < boundsMin) {
2783
+ position[config.axis] = data.size + data.offset[config.axis];
2708
2784
  }
2709
- else if (data.bounds.top > data.canvasSize.height && data.direction === OutModeDirection.bottom) {
2710
- data.particle.position.y = data.canvasSize.height - data.size - data.offset.y;
2785
+ else if (!config.negative && bounds[config.positiveEdge] > canvasDim) {
2786
+ position[config.axis] = canvasDim - data.size - data.offset[config.axis];
2711
2787
  }
2712
- const velocity = data.particle.velocity.y;
2713
- let bounced = false;
2714
2788
  if (data.outOfCanvas &&
2715
- ((data.direction === OutModeDirection.bottom && velocity > minVelocity) ||
2716
- (data.direction === OutModeDirection.top && velocity < minVelocity))) {
2717
- const newVelocity = getRangeValue(data.particle.options.bounce.vertical.value);
2718
- data.particle.velocity.y *= -newVelocity;
2719
- bounced = true;
2789
+ ((config.negative && velocity < minVelocity) || (!config.negative && velocity > minVelocity))) {
2790
+ data.particle.velocity[config.axis] *= -getRangeValue(data.particle.options.bounce[config.bounce].value);
2720
2791
  }
2721
- if (!bounced) {
2792
+ else {
2722
2793
  return;
2723
2794
  }
2724
- const minPos = data.offset.y + data.size;
2725
- if (data.outOfCanvas && data.direction === OutModeDirection.bottom) {
2726
- data.particle.position.y = data.canvasSize.height - minPos;
2727
- }
2728
- else if (data.outOfCanvas && data.direction === OutModeDirection.top) {
2729
- data.particle.position.y = minPos;
2730
- }
2795
+ const minPos = data.offset[config.axis] + data.size;
2796
+ position[config.axis] = config.negative ? minPos : canvasDim - minPos;
2731
2797
  if (data.outMode === OutMode.split) {
2732
2798
  data.particle.destroy();
2733
2799
  }
@@ -2743,26 +2809,19 @@
2743
2809
  OutMode.bounce,
2744
2810
  OutMode.split,
2745
2811
  ];
2746
- this.#particleBouncePlugins = container.plugins.filter(p => p.particleBounce !== undefined);
2812
+ this.#particleBouncePlugins = container.plugins.filter(p => !!p.particleBounce);
2747
2813
  }
2748
2814
  update(particle, direction, delta, outMode) {
2749
2815
  if (!this.modes.includes(outMode)) {
2750
2816
  return;
2751
2817
  }
2752
- const container = this.#container;
2753
- let handled = false;
2754
2818
  for (const plugin of this.#particleBouncePlugins) {
2755
- handled = plugin.particleBounce?.(particle, delta, direction) ?? false;
2756
- if (handled) {
2757
- break;
2819
+ if (plugin.particleBounce?.(particle, delta, direction)) {
2820
+ return;
2758
2821
  }
2759
2822
  }
2760
- if (handled) {
2761
- return;
2762
- }
2763
- const pos = particle.getPosition(), offset = particle.offset, size = particle.getRadius(), bounds = calculateBounds(pos, size), canvasSize = container.canvas.size, outOfCanvas = !particle.isInsideCanvasForOutMode(outMode, direction);
2764
- bounceHorizontal({ particle, outMode, direction, bounds, canvasSize, offset, outOfCanvas, size });
2765
- bounceVertical({ particle, outMode, direction, bounds, canvasSize, offset, outOfCanvas, size });
2823
+ const pos = particle.getPosition(), offset = particle.offset, size = particle.getRadius(), bounds = calculateBounds(pos, size), canvasSize = this.#container.canvas.size, outOfCanvas = !particle.isInsideCanvasForOutMode(outMode, direction);
2824
+ bounce({ particle, outMode, direction, bounds, canvasSize, offset, outOfCanvas, size });
2766
2825
  }
2767
2826
  }
2768
2827
 
@@ -2851,107 +2910,108 @@
2851
2910
  return;
2852
2911
  }
2853
2912
  const container = this.#container;
2854
- switch (particle.outType) {
2855
- case ParticleOutType.inside: {
2856
- const { x: vx, y: vy } = particle.velocity;
2857
- updateVector.setTo(originPoint);
2858
- updateVector.length = particle.moveCenter.radius;
2859
- updateVector.angle = particle.velocity.angle + Math.PI;
2860
- updateVector.addTo(particle.moveCenter);
2861
- const { dx, dy } = getDistances(particle.position, updateVector);
2862
- if ((vx <= minVelocity && dx >= minDistance$2) ||
2863
- (vy <= minVelocity && dy >= minDistance$2) ||
2864
- (vx >= minVelocity && dx <= minDistance$2) ||
2865
- (vy >= minVelocity && dy <= minDistance$2)) {
2866
- return;
2867
- }
2868
- particle.position.x = Math.floor(randomInRangeValue({
2869
- min: 0,
2870
- max: container.canvas.size.width,
2871
- }));
2872
- particle.position.y = Math.floor(randomInRangeValue({
2873
- min: 0,
2874
- max: container.canvas.size.height,
2875
- }));
2876
- const { dx: newDx, dy: newDy } = getDistances(particle.position, particle.moveCenter);
2877
- particle.direction = Math.atan2(-newDy, -newDx);
2878
- particle.velocity.angle = particle.direction;
2879
- particle.justWarped = true;
2880
- break;
2913
+ if (particle.outType === ParticleOutType.inside) {
2914
+ this.#applyOutModeInside(particle, container);
2915
+ }
2916
+ else {
2917
+ if (particle.isInsideCanvasForOutMode(outMode, direction)) {
2918
+ return;
2881
2919
  }
2882
- default: {
2883
- if (particle.isInsideCanvasForOutMode(outMode, direction)) {
2884
- return;
2885
- }
2886
- switch (particle.outType) {
2887
- case ParticleOutType.outside: {
2888
- particle.position.x =
2889
- Math.floor(randomInRangeValue({
2890
- min: -particle.moveCenter.radius,
2891
- max: particle.moveCenter.radius,
2892
- })) + particle.moveCenter.x;
2893
- particle.position.y =
2894
- Math.floor(randomInRangeValue({
2895
- min: -particle.moveCenter.radius,
2896
- max: particle.moveCenter.radius,
2897
- })) + particle.moveCenter.y;
2898
- const { dx, dy } = getDistances(particle.position, particle.moveCenter);
2899
- if (particle.moveCenter.radius) {
2900
- particle.direction = Math.atan2(dy, dx);
2901
- particle.velocity.angle = particle.direction;
2902
- }
2903
- particle.justWarped = true;
2904
- break;
2905
- }
2906
- case ParticleOutType.normal: {
2907
- const warp = particle.options.move.warp, canvasSize = container.canvas.size, newPos = {
2908
- bottom: canvasSize.height + particle.getRadius() + particle.offset.y,
2909
- left: -particle.getRadius() - particle.offset.x,
2910
- right: canvasSize.width + particle.getRadius() + particle.offset.x,
2911
- top: -particle.getRadius() - particle.offset.y,
2912
- }, sizeValue = particle.getRadius(), nextBounds = calculateBounds(particle.position, sizeValue);
2913
- if (direction === OutModeDirection.right && nextBounds.left > canvasSize.width + particle.offset.x) {
2914
- particle.position.x = newPos.left;
2915
- particle.initialPosition.x = particle.position.x;
2916
- if (!warp) {
2917
- particle.position.y = getRandom() * canvasSize.height;
2918
- particle.initialPosition.y = particle.position.y;
2919
- }
2920
- particle.justWarped = true;
2921
- }
2922
- else if (direction === OutModeDirection.left && nextBounds.right < -particle.offset.x) {
2923
- particle.position.x = newPos.right;
2924
- particle.initialPosition.x = particle.position.x;
2925
- if (!warp) {
2926
- particle.position.y = getRandom() * canvasSize.height;
2927
- particle.initialPosition.y = particle.position.y;
2928
- }
2929
- particle.justWarped = true;
2930
- }
2931
- if (direction === OutModeDirection.bottom && nextBounds.top > canvasSize.height + particle.offset.y) {
2932
- if (!warp) {
2933
- particle.position.x = getRandom() * canvasSize.width;
2934
- particle.initialPosition.x = particle.position.x;
2935
- }
2936
- particle.position.y = newPos.top;
2937
- particle.initialPosition.y = particle.position.y;
2938
- particle.justWarped = true;
2939
- }
2940
- else if (direction === OutModeDirection.top && nextBounds.bottom < -particle.offset.y) {
2941
- if (!warp) {
2942
- particle.position.x = getRandom() * canvasSize.width;
2943
- particle.initialPosition.x = particle.position.x;
2944
- }
2945
- particle.position.y = newPos.bottom;
2946
- particle.initialPosition.y = particle.position.y;
2947
- particle.justWarped = true;
2948
- }
2949
- break;
2950
- }
2951
- }
2952
- break;
2920
+ if (particle.outType === ParticleOutType.outside) {
2921
+ this.#applyParticleModeOutside(particle);
2953
2922
  }
2954
- }
2923
+ else {
2924
+ this.#applyOutModeNormal(particle, container, direction);
2925
+ }
2926
+ }
2927
+ }
2928
+ #applyOutModeInside(particle, container) {
2929
+ const { x: vx, y: vy } = particle.velocity;
2930
+ updateVector.setTo(originPoint);
2931
+ updateVector.length = particle.moveCenter.radius;
2932
+ updateVector.angle = particle.velocity.angle + Math.PI;
2933
+ updateVector.addTo(particle.moveCenter);
2934
+ const { dx, dy } = getDistances(particle.position, updateVector);
2935
+ if ((vx <= minVelocity && dx >= minDistance$2) ||
2936
+ (vy <= minVelocity && dy >= minDistance$2) ||
2937
+ (vx >= minVelocity && dx <= minDistance$2) ||
2938
+ (vy >= minVelocity && dy <= minDistance$2)) {
2939
+ return;
2940
+ }
2941
+ particle.position.x = Math.floor(randomInRangeValue({
2942
+ min: 0,
2943
+ max: container.canvas.size.width,
2944
+ }));
2945
+ particle.position.y = Math.floor(randomInRangeValue({
2946
+ min: 0,
2947
+ max: container.canvas.size.height,
2948
+ }));
2949
+ const { dx: newDx, dy: newDy } = getDistances(particle.position, particle.moveCenter);
2950
+ particle.direction = Math.atan2(-newDy, -newDx);
2951
+ particle.velocity.angle = particle.direction;
2952
+ particle.justWarped = true;
2953
+ }
2954
+ #applyOutModeNormal(particle, container, direction) {
2955
+ const warp = particle.options.move.warp, canvasSize = container.canvas.size, sizeValue = particle.getRadius(), newPos = {
2956
+ bottom: canvasSize.height + sizeValue + particle.offset.y,
2957
+ left: -sizeValue - particle.offset.x,
2958
+ right: canvasSize.width + sizeValue + particle.offset.x,
2959
+ top: -sizeValue - particle.offset.y,
2960
+ }, nextBounds = calculateBounds(particle.position, sizeValue);
2961
+ if (direction === OutModeDirection.right && nextBounds.left > canvasSize.width + particle.offset.x) {
2962
+ particle.position.x = newPos.left;
2963
+ particle.initialPosition.x = particle.position.x;
2964
+ if (!warp) {
2965
+ particle.position.y = getRandom() * canvasSize.height;
2966
+ particle.initialPosition.y = particle.position.y;
2967
+ }
2968
+ particle.justWarped = true;
2969
+ }
2970
+ else if (direction === OutModeDirection.left && nextBounds.right < -particle.offset.x) {
2971
+ particle.position.x = newPos.right;
2972
+ particle.initialPosition.x = particle.position.x;
2973
+ if (!warp) {
2974
+ particle.position.y = getRandom() * canvasSize.height;
2975
+ particle.initialPosition.y = particle.position.y;
2976
+ }
2977
+ particle.justWarped = true;
2978
+ }
2979
+ if (direction === OutModeDirection.bottom && nextBounds.top > canvasSize.height + particle.offset.y) {
2980
+ if (!warp) {
2981
+ particle.position.x = getRandom() * canvasSize.width;
2982
+ particle.initialPosition.x = particle.position.x;
2983
+ }
2984
+ particle.position.y = newPos.top;
2985
+ particle.initialPosition.y = particle.position.y;
2986
+ particle.justWarped = true;
2987
+ }
2988
+ else if (direction === OutModeDirection.top && nextBounds.bottom < -particle.offset.y) {
2989
+ if (!warp) {
2990
+ particle.position.x = getRandom() * canvasSize.width;
2991
+ particle.initialPosition.x = particle.position.x;
2992
+ }
2993
+ particle.position.y = newPos.bottom;
2994
+ particle.initialPosition.y = particle.position.y;
2995
+ particle.justWarped = true;
2996
+ }
2997
+ }
2998
+ #applyParticleModeOutside(particle) {
2999
+ particle.position.x =
3000
+ Math.floor(randomInRangeValue({
3001
+ min: -particle.moveCenter.radius,
3002
+ max: particle.moveCenter.radius,
3003
+ })) + particle.moveCenter.x;
3004
+ particle.position.y =
3005
+ Math.floor(randomInRangeValue({
3006
+ min: -particle.moveCenter.radius,
3007
+ max: particle.moveCenter.radius,
3008
+ })) + particle.moveCenter.y;
3009
+ const { dx, dy } = getDistances(particle.position, particle.moveCenter);
3010
+ if (particle.moveCenter.radius) {
3011
+ particle.direction = Math.atan2(dy, dx);
3012
+ particle.velocity.angle = particle.direction;
3013
+ }
3014
+ particle.justWarped = true;
2955
3015
  }
2956
3016
  }
2957
3017
 
@@ -3000,7 +3060,7 @@
3000
3060
  }
3001
3061
 
3002
3062
  async function loadOutModesUpdater(engine) {
3003
- engine.checkVersion("4.4.0");
3063
+ engine.checkVersion("4.5.1");
3004
3064
  await engine.pluginManager.register(e => {
3005
3065
  e.pluginManager.addParticleUpdater("outModes", container => {
3006
3066
  return Promise.resolve(new OutOfCanvasUpdater(container));
@@ -3017,39 +3077,9 @@
3017
3077
  this.#pluginManager = pluginManager;
3018
3078
  }
3019
3079
  init(particle) {
3020
- const container = this.#container, options = particle.options, paint = itemFromSingleOrMultiple(options.paint, particle.id, options.reduceDuplicates), color = paint?.color, paintColor = color ?? undefined, fill = paint?.fill, stroke = paint?.stroke;
3021
- if (fill) {
3022
- const fillColor = AnimatableColor.create(paintColor === undefined ? undefined : AnimatableColor.create(undefined, paintColor), fill.color);
3023
- particle.fillEnabled = fill.enable;
3024
- particle.fillOpacity = getRangeValue(fill.opacity);
3025
- particle.fillAnimation = fillColor.animation;
3026
- const fillHslColor = rangeColorToHsl(this.#pluginManager, fillColor);
3027
- if (fillHslColor) {
3028
- particle.fillColor = getHslAnimationFromHsl(fillHslColor, particle.fillAnimation, container.retina.reduceFactor);
3029
- }
3030
- }
3031
- else {
3032
- particle.fillEnabled = false;
3033
- particle.fillAnimation = undefined;
3034
- particle.fillColor = undefined;
3035
- particle.fillOpacity = defaultOpacity;
3036
- }
3037
- if (stroke) {
3038
- const strokeColor = AnimatableColor.create(paintColor === undefined ? undefined : AnimatableColor.create(undefined, paintColor), stroke.color);
3039
- particle.strokeWidth = getRangeValue(stroke.width) * container.retina.pixelRatio;
3040
- particle.strokeOpacity = getRangeValue(stroke.opacity ?? defaultOpacity);
3041
- particle.strokeAnimation = strokeColor.animation;
3042
- const strokeHslColor = rangeColorToHsl(this.#pluginManager, strokeColor) ?? particle.getFillColor();
3043
- if (strokeHslColor) {
3044
- particle.strokeColor = getHslAnimationFromHsl(strokeHslColor, particle.strokeAnimation, container.retina.reduceFactor);
3045
- }
3046
- }
3047
- else {
3048
- particle.strokeAnimation = undefined;
3049
- particle.strokeColor = undefined;
3050
- particle.strokeOpacity = defaultOpacity;
3051
- particle.strokeWidth = 0;
3052
- }
3080
+ const container = this.#container, options = particle.options, paint = itemFromSingleOrMultiple(options.paint, particle.id, options.reduceDuplicates);
3081
+ this.#initFill(paint, particle, container);
3082
+ this.#initStroke(paint, particle, container);
3053
3083
  }
3054
3084
  isEnabled(particle) {
3055
3085
  const { fillAnimation, fillColor, strokeAnimation, strokeColor } = particle, fillEnabled = !!fillAnimation &&
@@ -3068,10 +3098,48 @@
3068
3098
  updateColor(particle.fillColor, delta, this.#container.hdr);
3069
3099
  updateColor(particle.strokeColor, delta, this.#container.hdr);
3070
3100
  }
3101
+ #initFill(paint, particle, container) {
3102
+ const fill = paint?.fill, color = paint?.color, paintColor = color ?? undefined;
3103
+ if (!fill) {
3104
+ particle.fillEnabled = false;
3105
+ particle.fillAnimation = undefined;
3106
+ particle.fillColor = undefined;
3107
+ particle.fillOpacity = defaultOpacity;
3108
+ return;
3109
+ }
3110
+ const fillColor = AnimatableColor.create(paintColor === undefined ? undefined : AnimatableColor.create(undefined, paintColor), fill.color);
3111
+ particle.fillEnabled = fill.enable;
3112
+ particle.fillOpacity = getRangeValue(fill.opacity);
3113
+ particle.fillAnimation = fillColor.animation;
3114
+ const fillHslColor = rangeColorToHsl(this.#pluginManager, fillColor);
3115
+ if (!fillHslColor) {
3116
+ return;
3117
+ }
3118
+ particle.fillColor = getHslAnimationFromHsl(fillHslColor, particle.fillAnimation, container.retina.reduceFactor);
3119
+ }
3120
+ #initStroke(paint, particle, container) {
3121
+ const stroke = paint?.stroke, color = paint?.color, paintColor = color ?? undefined;
3122
+ if (!stroke) {
3123
+ particle.strokeAnimation = undefined;
3124
+ particle.strokeColor = undefined;
3125
+ particle.strokeOpacity = defaultOpacity;
3126
+ particle.strokeWidth = 0;
3127
+ return;
3128
+ }
3129
+ const strokeColor = AnimatableColor.create(paintColor === undefined ? undefined : AnimatableColor.create(undefined, paintColor), stroke.color);
3130
+ particle.strokeWidth = getRangeValue(stroke.width) * container.retina.pixelRatio;
3131
+ particle.strokeOpacity = getRangeValue(stroke.opacity ?? defaultOpacity);
3132
+ particle.strokeAnimation = strokeColor.animation;
3133
+ const strokeHslColor = rangeColorToHsl(this.#pluginManager, strokeColor) ?? particle.getFillColor();
3134
+ if (!strokeHslColor) {
3135
+ return;
3136
+ }
3137
+ particle.strokeColor = getHslAnimationFromHsl(strokeHslColor, particle.strokeAnimation, container.retina.reduceFactor);
3138
+ }
3071
3139
  }
3072
3140
 
3073
3141
  async function loadPaintUpdater(engine) {
3074
- engine.checkVersion("4.4.0");
3142
+ engine.checkVersion("4.5.1");
3075
3143
  await engine.pluginManager.register(e => {
3076
3144
  e.pluginManager.addParticleUpdater("paint", container => {
3077
3145
  return Promise.resolve(new PaintUpdater(e.pluginManager, container));
@@ -3113,7 +3181,7 @@
3113
3181
  if (!this.accepts(input)) {
3114
3182
  return;
3115
3183
  }
3116
- const result = rgbRegex.exec(input), radix = 10, minLength = 4, defaultAlpha = 1;
3184
+ const result = rgbRegex.exec(input), radix = 10, minLength = 4;
3117
3185
  return result
3118
3186
  ? {
3119
3187
  a: result.length > minLength ? parseAlpha(result[RgbIndexes.a]) : defaultAlpha,
@@ -3126,7 +3194,7 @@
3126
3194
  }
3127
3195
 
3128
3196
  async function loadRgbColorPlugin(engine) {
3129
- engine.checkVersion("4.4.0");
3197
+ engine.checkVersion("4.5.1");
3130
3198
  await engine.pluginManager.register(e => {
3131
3199
  e.pluginManager.addColorManager("rgb", new RgbColorManager());
3132
3200
  });
@@ -3211,7 +3279,7 @@
3211
3279
  }
3212
3280
 
3213
3281
  async function loadSizeUpdater(engine) {
3214
- engine.checkVersion("4.4.0");
3282
+ engine.checkVersion("4.5.1");
3215
3283
  await engine.pluginManager.register(e => {
3216
3284
  e.pluginManager.addParticleUpdater("size", container => {
3217
3285
  return Promise.resolve(new SizeUpdater(container));
@@ -3220,7 +3288,7 @@
3220
3288
  }
3221
3289
 
3222
3290
  async function loadBasic(engine) {
3223
- engine.checkVersion("4.4.0");
3291
+ engine.checkVersion("4.5.1");
3224
3292
  await engine.pluginManager.register(async (e) => {
3225
3293
  await Promise.all([
3226
3294
  loadBlendPlugin(e),
@@ -3237,6 +3305,16 @@
3237
3305
  });
3238
3306
  }
3239
3307
 
3308
+ const ErrorCodes = {
3309
+ interactivityPluginNotLoaded: "TSP-3201",
3310
+ interactivityClickHandlerNotSet: "TSP-3202",
3311
+ };
3312
+
3313
+ const ErrorMessages = {
3314
+ [ErrorCodes.interactivityPluginNotLoaded]: "tsParticles Interactivity Plugin is not loaded",
3315
+ [ErrorCodes.interactivityClickHandlerNotSet]: "Click handlers can only be set after calling tsParticles.load()",
3316
+ };
3317
+
3240
3318
  class ClickEvent {
3241
3319
  enable = false;
3242
3320
  mode = [];
@@ -3313,9 +3391,7 @@
3313
3391
 
3314
3392
  class Modes {
3315
3393
  #container;
3316
- #pluginManager;
3317
- constructor(pluginManager, container) {
3318
- this.#pluginManager = pluginManager;
3394
+ constructor(container) {
3319
3395
  this.#container = container;
3320
3396
  }
3321
3397
  load(data) {
@@ -3325,10 +3401,7 @@
3325
3401
  if (!this.#container) {
3326
3402
  return;
3327
3403
  }
3328
- const interactors = this.#pluginManager.interactors?.get(this.#container);
3329
- if (!interactors) {
3330
- return;
3331
- }
3404
+ const interactors = this.#container.interactionManager?.interactors ?? [];
3332
3405
  for (const interactor of interactors) {
3333
3406
  if (!interactor.loadModeOptions) {
3334
3407
  continue;
@@ -3342,8 +3415,8 @@
3342
3415
  detectsOn = InteractivityDetect.window;
3343
3416
  events = new Events();
3344
3417
  modes;
3345
- constructor(pluginManager, container) {
3346
- this.modes = new Modes(pluginManager, container);
3418
+ constructor(container) {
3419
+ this.modes = new Modes(container);
3347
3420
  }
3348
3421
  load(data) {
3349
3422
  if (isNull(data)) {
@@ -3374,10 +3447,10 @@
3374
3447
  }
3375
3448
  let interactivityOptions = options.interactivity;
3376
3449
  if (!interactivityOptions?.load) {
3377
- options.interactivity = interactivityOptions = new Interactivity(this.#pluginManager, container);
3450
+ options.interactivity = interactivityOptions = new Interactivity(container);
3378
3451
  }
3379
3452
  interactivityOptions.load(source?.interactivity);
3380
- const interactors = this.#pluginManager.interactors?.get(container);
3453
+ const interactors = container.interactionManager?.interactors;
3381
3454
  if (!interactors) {
3382
3455
  return;
3383
3456
  }
@@ -3391,7 +3464,7 @@
3391
3464
  if (source?.interactivity) {
3392
3465
  options.interactivity = deepExtend({}, source.interactivity);
3393
3466
  }
3394
- const interactors = this.#pluginManager.interactors?.get(container);
3467
+ const interactors = container.interactionManager?.interactors;
3395
3468
  if (!interactors) {
3396
3469
  return;
3397
3470
  }
@@ -3421,25 +3494,25 @@
3421
3494
  const clickEvent = "click", mouseDownEvent = "pointerdown", mouseUpEvent = "pointerup", mouseLeaveEvent = "pointerleave", mouseMoveEvent = "pointermove", touchStartEvent = "touchstart", touchEndEvent = "touchend", touchMoveEvent = "touchmove", touchCancelEvent = "touchcancel";
3422
3495
 
3423
3496
  async function loadInteractivityPlugin(engine) {
3424
- engine.checkVersion("4.4.0");
3497
+ engine.checkVersion("4.5.1");
3498
+ if (typeof process !== "undefined" && process.env.NODE_ENV !== "production") {
3499
+ addErrorMessages(ErrorMessages);
3500
+ }
3425
3501
  await engine.pluginManager.register(e => {
3426
3502
  const interactivityEngine = e, interactivityPluginManager = interactivityEngine.pluginManager;
3427
3503
  interactivityPluginManager.addPlugin(new InteractivityPlugin(interactivityPluginManager));
3428
3504
  interactivityPluginManager.initializers.interactors ??= new Map();
3429
- interactivityPluginManager.interactors ??= new Map();
3430
3505
  interactivityPluginManager.addInteractor = (name, interactorInitializer) => {
3506
+ if (interactivityPluginManager.initialized) {
3507
+ return;
3508
+ }
3431
3509
  interactivityPluginManager.initializers.interactors ??= new Map();
3432
3510
  interactivityPluginManager.initializers.interactors.set(name, interactorInitializer);
3433
3511
  };
3434
- interactivityPluginManager.getInteractors = async (container, force = false) => {
3435
- interactivityPluginManager.interactors ??= new Map();
3436
- interactivityPluginManager.initializers.interactors ??= new Map();
3437
- return getItemsFromInitializer(container, interactivityPluginManager.interactors, interactivityPluginManager.initializers.interactors, force);
3438
- };
3439
3512
  interactivityPluginManager.setOnClickHandler = (callback) => {
3440
3513
  const { items } = interactivityEngine;
3441
3514
  if (!items.length) {
3442
- throw new Error("Click handlers can only be set after calling tsParticles.load()");
3515
+ throw new Error(getErrorMessage(ErrorCodes.interactivityClickHandlerNotSet));
3443
3516
  }
3444
3517
  items.forEach(item => {
3445
3518
  const interactivityContainer = item;
@@ -3450,7 +3523,7 @@
3450
3523
  }
3451
3524
  function ensureInteractivityPluginLoaded(e) {
3452
3525
  if (!e.pluginManager.addInteractor) {
3453
- throw new Error("tsParticles Interactivity Plugin is not loaded");
3526
+ throw new Error(getErrorMessage(ErrorCodes.interactivityPluginNotLoaded));
3454
3527
  }
3455
3528
  }
3456
3529
 
@@ -3501,6 +3574,30 @@
3501
3574
  }
3502
3575
  return false;
3503
3576
  }
3577
+ query(grid) {
3578
+ 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;
3579
+ if (!crossesLeft && !crossesRight && !crossesTop && !crossesBottom) {
3580
+ return grid.query(this);
3581
+ }
3582
+ const xShifts = [originPoint.x], yShifts = [originPoint.y];
3583
+ if (crossesLeft)
3584
+ xShifts.push(width);
3585
+ if (crossesRight)
3586
+ xShifts.push(-width);
3587
+ if (crossesTop)
3588
+ yShifts.push(height);
3589
+ if (crossesBottom)
3590
+ yShifts.push(-height);
3591
+ const particles = new Set();
3592
+ for (const dx of xShifts) {
3593
+ for (const dy of yShifts) {
3594
+ for (const particle of grid.queryCircle({ x: x + dx, y: y + dy }, radius)) {
3595
+ particles.add(particle);
3596
+ }
3597
+ }
3598
+ }
3599
+ return [...particles];
3600
+ }
3504
3601
  }
3505
3602
 
3506
3603
  class LinksShadow {
@@ -3610,7 +3707,9 @@
3610
3707
  if (pos1.x < originPoint.x || pos1.y < originPoint.y || pos1.x > canvasSize.width || pos1.y > canvasSize.height) {
3611
3708
  return;
3612
3709
  }
3613
- 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);
3710
+ const linkOpt1 = p1.options.links, optOpacity = linkOpt1.opacity, optDistance = p1.retina.linksDistance ?? minDistance$1, warp = linkOpt1.warp, query = (warp
3711
+ ? new CircleWarp(pos1.x, pos1.y, optDistance, canvasSize).query(container.particles.grid)
3712
+ : container.particles.grid.queryCircle(pos1, optDistance));
3614
3713
  for (const p2 of query) {
3615
3714
  const linkOpt2 = p2.options.links;
3616
3715
  if (p1 === p2 ||
@@ -3698,7 +3797,7 @@
3698
3797
  }
3699
3798
 
3700
3799
  async function loadParticlesLinksInteraction(engine) {
3701
- engine.checkVersion("4.4.0");
3800
+ engine.checkVersion("4.5.1");
3702
3801
  await engine.pluginManager.register((e) => {
3703
3802
  const pluginManager = e.pluginManager;
3704
3803
  ensureInteractivityPluginLoaded(e);
@@ -3827,21 +3926,28 @@
3827
3926
  });
3828
3927
  }
3829
3928
  clear() {
3929
+ const visited = new Set();
3830
3930
  for (const plugin of this.#canvasClearPlugins) {
3931
+ visited.add(plugin);
3831
3932
  if (plugin.canvasClear?.() ?? false) {
3832
- return;
3933
+ return plugin;
3833
3934
  }
3834
3935
  }
3835
3936
  for (const layer of Object.values(DrawLayer)) {
3836
3937
  if (typeof layer === "number") {
3837
3938
  for (const plugin of this.#getLayerPlugins(layer)) {
3939
+ if (visited.has(plugin)) {
3940
+ continue;
3941
+ }
3942
+ visited.add(plugin);
3838
3943
  if (plugin.canvasClear?.() ?? false) {
3839
- return;
3944
+ return plugin;
3840
3945
  }
3841
3946
  }
3842
3947
  }
3843
3948
  }
3844
3949
  this.canvasClear();
3950
+ return undefined;
3845
3951
  }
3846
3952
  destroy() {
3847
3953
  this.stop();
@@ -3919,8 +4025,7 @@
3919
4025
  });
3920
4026
  }
3921
4027
  drawParticles(delta) {
3922
- const { particles, actualOptions } = this.#container;
3923
- this.clear();
4028
+ const { particles, actualOptions } = this.#container, clearedPlugin = this.clear();
3924
4029
  particles.update(delta);
3925
4030
  this.draw(ctx => {
3926
4031
  const width = this.#canvasManager.size.width, height = this.#canvasManager.size.height;
@@ -3942,7 +4047,9 @@
3942
4047
  }
3943
4048
  }
3944
4049
  for (const plugin of this.#getLayerPlugins(DrawLayer.BackgroundMask)) {
3945
- plugin.canvasPaint?.();
4050
+ if (plugin !== clearedPlugin) {
4051
+ plugin.canvasPaint?.();
4052
+ }
3946
4053
  }
3947
4054
  for (const plugin of this.#getLayerPlugins(DrawLayer.CanvasSetup)) {
3948
4055
  plugin.drawSettingsSetup?.(ctx, delta);
@@ -3958,51 +4065,23 @@
3958
4065
  });
3959
4066
  }
3960
4067
  init() {
3961
- this.initUpdaters();
3962
- this.initPlugins();
3963
- this.#resolveBackgroundElement();
3964
- this.paint();
3965
- }
3966
- initPlugins() {
3967
- this.#canvasClearPlugins = [];
3968
- this.#colorPlugins = [];
3969
- this.#drawParticlePlugins = [];
3970
- this.#drawParticlesSetupPlugins = [];
3971
- this.#drawParticlesCleanupPlugins = [];
3972
- for (const layer of Object.values(DrawLayer)) {
3973
- if (typeof layer === "number") {
3974
- this.#layers[layer] = [];
3975
- }
3976
- }
3977
- for (const plugin of this.#container.plugins) {
3978
- if (plugin.particleFillColor ?? plugin.particleStrokeColor) {
3979
- this.#colorPlugins.push(plugin);
3980
- }
3981
- if (plugin.drawParticle) {
3982
- this.#drawParticlePlugins.push(plugin);
3983
- }
3984
- if (plugin.drawParticleSetup) {
3985
- this.#drawParticlesSetupPlugins.push(plugin);
3986
- }
3987
- if (plugin.drawParticleCleanup) {
3988
- this.#drawParticlesCleanupPlugins.push(plugin);
3989
- }
3990
- if (plugin.canvasClear) {
3991
- this.#canvasClearPlugins.push(plugin);
3992
- }
3993
- if (plugin.canvasPaint) {
3994
- this.#getLayerPlugins(DrawLayer.BackgroundMask).push(plugin);
3995
- }
3996
- if (plugin.drawSettingsSetup) {
3997
- this.#getLayerPlugins(DrawLayer.CanvasSetup).push(plugin);
3998
- }
3999
- if (plugin.draw) {
4000
- this.#getLayerPlugins(DrawLayer.PluginContent).push(plugin);
4001
- }
4002
- if (plugin.clearDraw ?? plugin.drawSettingsCleanup) {
4003
- this.#getLayerPlugins(DrawLayer.CanvasCleanup).push(plugin);
4068
+ this.initUpdaters();
4069
+ this.initPlugins();
4070
+ this.#resolveBackgroundElement();
4071
+ this.paint();
4072
+ }
4073
+ initPlugins() {
4074
+ this.#canvasClearPlugins = [];
4075
+ this.#colorPlugins = [];
4076
+ this.#drawParticlePlugins = [];
4077
+ this.#drawParticlesSetupPlugins = [];
4078
+ this.#drawParticlesCleanupPlugins = [];
4079
+ for (const layer of Object.values(DrawLayer)) {
4080
+ if (typeof layer === "number") {
4081
+ this.#layers[layer] = [];
4004
4082
  }
4005
4083
  }
4084
+ this.#initPluginsArray();
4006
4085
  }
4007
4086
  initUpdaters() {
4008
4087
  this.#preDrawUpdaters = [];
@@ -4211,6 +4290,45 @@
4211
4290
  this.#reusablePluginColors[sColorIndex] = sColor;
4212
4291
  return this.#reusablePluginColors;
4213
4292
  }
4293
+ #initLayerPlugin(plugin) {
4294
+ const layerMap = [
4295
+ [DrawLayer.BackgroundMask, !!plugin.canvasPaint],
4296
+ [DrawLayer.CanvasSetup, !!plugin.drawSettingsSetup],
4297
+ [DrawLayer.PluginContent, !!plugin.draw],
4298
+ [DrawLayer.CanvasCleanup, !!(plugin.clearDraw ?? plugin.drawSettingsCleanup)],
4299
+ ];
4300
+ for (const [layer, active] of layerMap) {
4301
+ if (active) {
4302
+ this.#layers[layer].push(plugin);
4303
+ }
4304
+ }
4305
+ }
4306
+ #initPluginsArray() {
4307
+ for (const plugin of this.#container.plugins) {
4308
+ if (plugin.particleFillColor ?? plugin.particleStrokeColor) {
4309
+ this.#colorPlugins.push(plugin);
4310
+ }
4311
+ if (plugin.drawParticle) {
4312
+ this.#drawParticlePlugins.push(plugin);
4313
+ }
4314
+ if (plugin.drawParticleSetup) {
4315
+ this.#drawParticlesSetupPlugins.push(plugin);
4316
+ }
4317
+ if (plugin.drawParticleCleanup) {
4318
+ this.#drawParticlesCleanupPlugins.push(plugin);
4319
+ }
4320
+ if (plugin.canvasClear) {
4321
+ this.#canvasClearPlugins.push(plugin);
4322
+ }
4323
+ this.#initLayerPlugin(plugin);
4324
+ }
4325
+ }
4326
+ #isSupportedElement(element) {
4327
+ return ((typeof HTMLCanvasElement !== "undefined" && element instanceof HTMLCanvasElement) ||
4328
+ (typeof OffscreenCanvas !== "undefined" && element instanceof OffscreenCanvas) ||
4329
+ (typeof HTMLVideoElement !== "undefined" && element instanceof HTMLVideoElement) ||
4330
+ (typeof HTMLImageElement !== "undefined" && element instanceof HTMLImageElement));
4331
+ }
4214
4332
  #resolveBackgroundElement() {
4215
4333
  const background = this.#container.actualOptions.background;
4216
4334
  this.#backgroundElement = null;
@@ -4220,9 +4338,7 @@
4220
4338
  if (typeof background.element === "string") {
4221
4339
  if (typeof document !== "undefined") {
4222
4340
  const node = document.querySelector(background.element);
4223
- if ((typeof HTMLCanvasElement !== "undefined" && node instanceof HTMLCanvasElement) ||
4224
- (typeof HTMLVideoElement !== "undefined" && node instanceof HTMLVideoElement) ||
4225
- (typeof HTMLImageElement !== "undefined" && node instanceof HTMLImageElement)) {
4341
+ if (node && this.#isSupportedElement(node)) {
4226
4342
  this.#backgroundElement = node;
4227
4343
  }
4228
4344
  else if (node) {
@@ -4233,10 +4349,7 @@
4233
4349
  }
4234
4350
  }
4235
4351
  }
4236
- else if ((typeof HTMLCanvasElement !== "undefined" && background.element instanceof HTMLCanvasElement) ||
4237
- (typeof OffscreenCanvas !== "undefined" && background.element instanceof OffscreenCanvas) ||
4238
- (typeof HTMLVideoElement !== "undefined" && background.element instanceof HTMLVideoElement) ||
4239
- (typeof HTMLImageElement !== "undefined" && background.element instanceof HTMLImageElement)) {
4352
+ else if (this.#isSupportedElement(background.element)) {
4240
4353
  this.#backgroundElement = background.element;
4241
4354
  }
4242
4355
  }
@@ -4254,7 +4367,7 @@
4254
4367
  return transferredCanvas;
4255
4368
  }
4256
4369
  if (typeof canvas.transferControlToOffscreen !== "function") {
4257
- throw new TypeError("OffscreenCanvas is required but not supported by this browser");
4370
+ throw new TypeError(getErrorMessage(ErrorCodes$2.offscreenCanvasUnsupported));
4258
4371
  }
4259
4372
  try {
4260
4373
  const offscreenCanvas = canvas.transferControlToOffscreen();
@@ -4262,10 +4375,16 @@
4262
4375
  return offscreenCanvas;
4263
4376
  }
4264
4377
  catch {
4265
- throw new TypeError("OffscreenCanvas transfer failed");
4378
+ throw new TypeError(getErrorMessage(ErrorCodes$2.offscreenCanvasTransferFailed));
4266
4379
  }
4267
4380
  }, isHtmlCanvasElement = (canvas) => {
4268
4381
  return typeof HTMLCanvasElement !== "undefined" && canvas instanceof HTMLCanvasElement;
4382
+ }, getEffectiveColorSpace = (context) => {
4383
+ if (!context) {
4384
+ return undefined;
4385
+ }
4386
+ const colorInfo = context;
4387
+ return colorInfo.getContextAttributes?.().colorSpace ?? undefined;
4269
4388
  };
4270
4389
  function setStyle(canvas, style, important = false) {
4271
4390
  if (!style) {
@@ -4390,7 +4509,7 @@
4390
4509
  const elementStyle = element.style, color = rangeColorToRgb(this.#pluginManager, background.color);
4391
4510
  if (color) {
4392
4511
  const hdrOptions = container.actualOptions.hdr;
4393
- elementStyle.backgroundColor = getStyleFromRgb(color, container.hdr, background.opacity, hdrOptions.peakNits, hdrOptions.mode);
4512
+ elementStyle.backgroundColor = getStyleFromRgb(color, container.hdr, background.opacity, hdrOptions.peakNits, toEnumValue(HdrMode, hdrOptions.mode, HdrMode.standard));
4394
4513
  }
4395
4514
  else {
4396
4515
  elementStyle.backgroundColor = "";
@@ -4510,11 +4629,11 @@
4510
4629
  const container = this.#container, canSupportHdr = container.actualOptions.hdr.enable &&
4511
4630
  safeMatchMedia("(color-gamut: p3)")?.matches &&
4512
4631
  safeMatchMedia("(dynamic-range: high)")?.matches;
4513
- container.hdr = canSupportHdr ?? false;
4514
- container.hdrMode = container.actualOptions.hdr.mode;
4632
+ container.hdrMode = toEnumValue(HdrMode, container.actualOptions.hdr.mode, HdrMode.standard);
4515
4633
  container.peakNits = container.actualOptions.hdr.peakNits;
4516
4634
  const renderCanvas = this.renderCanvas;
4517
4635
  if (!renderCanvas) {
4636
+ container.hdr = canSupportHdr ?? false;
4518
4637
  return;
4519
4638
  }
4520
4639
  this.render.setContextSettings({
@@ -4533,7 +4652,6 @@
4533
4652
  context = null;
4534
4653
  }
4535
4654
  if (canSupportHdr && !context) {
4536
- container.hdr = false;
4537
4655
  const sdrSettings = {
4538
4656
  alpha: true,
4539
4657
  desynchronized: true,
@@ -4549,11 +4667,16 @@
4549
4667
  }
4550
4668
  }
4551
4669
  this.render.setContext(context);
4670
+ if (context) {
4671
+ const effectiveColorSpace = getEffectiveColorSpace(context);
4672
+ if (effectiveColorSpace !== undefined) {
4673
+ container.hdr = effectiveColorSpace === "display-p3";
4674
+ }
4675
+ }
4552
4676
  }
4553
4677
  #initHdrListeners() {
4554
4678
  this.#removeHdrListeners();
4555
4679
  const p3Query = safeMatchMedia("(color-gamut: p3)"), hdrQuery = safeMatchMedia("(dynamic-range: high)"), handleChange = () => {
4556
- this.#recreateRenderCanvas();
4557
4680
  this.#initContext();
4558
4681
  this.initBackground();
4559
4682
  }, listeners = [];
@@ -4589,16 +4712,6 @@
4589
4712
  element.style.setProperty(key, value, "important");
4590
4713
  }
4591
4714
  }
4592
- #recreateRenderCanvas() {
4593
- const renderCanvas = this.renderCanvas;
4594
- if (!renderCanvas) {
4595
- return;
4596
- }
4597
- if (this.domElement) {
4598
- return;
4599
- }
4600
- this.renderCanvas = new OffscreenCanvas(renderCanvas.width, renderCanvas.height);
4601
- }
4602
4715
  #removeHdrListeners() {
4603
4716
  if (!this.#hdrMediaListeners) {
4604
4717
  return;
@@ -4670,6 +4783,10 @@
4670
4783
  this.#manageListeners(true);
4671
4784
  }
4672
4785
  removeListeners() {
4786
+ if (this.#resizeTimeout !== undefined) {
4787
+ clearTimeout(this.#resizeTimeout);
4788
+ this.#resizeTimeout = undefined;
4789
+ }
4673
4790
  this.#manageListeners(false);
4674
4791
  }
4675
4792
  #handleVisibilityChange() {
@@ -4697,8 +4814,7 @@
4697
4814
  this.#resizeTimeout = undefined;
4698
4815
  }
4699
4816
  const handleResize = async () => {
4700
- const canvas = this.#container.canvas;
4701
- await canvas.windowResize();
4817
+ await this.#container.canvas.windowResize();
4702
4818
  };
4703
4819
  this.#resizeTimeout = setTimeout(() => void handleResize(), this.#container.actualOptions.resize.delay * millisecondsToSeconds);
4704
4820
  }
@@ -4726,8 +4842,8 @@
4726
4842
  }
4727
4843
  else if (!this.#resizeObserver && add && canvasEl) {
4728
4844
  this.#resizeObserver = new ResizeObserver((entries) => {
4729
- const entry = entries.find(e => e.target === canvasEl);
4730
- if (!entry) {
4845
+ const res = entries.some(e => e.target === canvasEl);
4846
+ if (!res) {
4731
4847
  return;
4732
4848
  }
4733
4849
  this.#handleWindowResize();
@@ -4991,10 +5107,10 @@
4991
5107
  return this.#modifiers.find(m => m.id === id);
4992
5108
  }
4993
5109
  getOpacity() {
4994
- const zIndexOptions = this.options.zIndex, zIndexFactor = zIndexFactorOffset - this.zIndexFactor, zOpacityFactor = zIndexFactor ** zIndexOptions.opacityRate, baseOpacity = getRangeValue(this.opacity?.value ?? defaultOpacity$1), modifierOpacity = this.#applyModifiers(undefined, m => m.opacity), opacity = modifierOpacity ?? baseOpacity, fillOpacity = this.fillOpacity ?? defaultOpacity$1, strokeOpacity = this.strokeOpacity ?? defaultOpacity$1;
4995
- this.#cachedOpacityData.fillOpacity = fillOpacity;
5110
+ const zIndexOptions = this.options.zIndex, zIndexFactor = zIndexFactorOffset - this.zIndexFactor, zOpacityFactor = zIndexFactor ** zIndexOptions.opacityRate, baseOpacity = getRangeValue(this.opacity?.value ?? defaultOpacity$1), modifierOpacity = this.#applyModifiers(undefined, m => m.opacity), opacity = modifierOpacity ?? baseOpacity;
5111
+ this.#cachedOpacityData.fillOpacity = this.fillOpacity ?? defaultOpacity$1;
4996
5112
  this.#cachedOpacityData.opacity = opacity * zOpacityFactor;
4997
- this.#cachedOpacityData.strokeOpacity = strokeOpacity;
5113
+ this.#cachedOpacityData.strokeOpacity = this.strokeOpacity ?? defaultOpacity$1;
4998
5114
  return this.#cachedOpacityData;
4999
5115
  }
5000
5116
  getPosition() {
@@ -5241,7 +5357,7 @@
5241
5357
  #initPosition(position) {
5242
5358
  const container = this.#container, zIndexValue = Math.floor(getRangeValue(this.options.zIndex.value)), initialPosition = this.#calcPosition(position, clamp(zIndexValue, minZ, container.zLayers));
5243
5359
  if (!initialPosition) {
5244
- throw new Error("a valid position cannot be found for particle");
5360
+ throw new Error(getErrorMessage(ErrorCodes$2.particlePositionNotFound));
5245
5361
  }
5246
5362
  this.position = initialPosition;
5247
5363
  this.initialPosition = this.position.copy();
@@ -5290,6 +5406,12 @@
5290
5406
  this.#circlePoolIdx = 0;
5291
5407
  this.#rectanglePoolIdx = 0;
5292
5408
  }
5409
+ get cellSize() {
5410
+ return this.#cellSize;
5411
+ }
5412
+ set cellSize(value) {
5413
+ this.#pendingCellSize = value;
5414
+ }
5293
5415
  clear() {
5294
5416
  this.#cells.clear();
5295
5417
  const pendingCellSize = this.#pendingCellSize;
@@ -5313,40 +5435,46 @@
5313
5435
  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);
5314
5436
  for (let cx = minCellX; cx <= maxCellX; cx++) {
5315
5437
  for (let cy = minCellY; cy <= maxCellY; cy++) {
5316
- const key = `${cx}_${cy}`, cellParticles = this.#cells.get(key);
5317
- if (!cellParticles) {
5318
- continue;
5319
- }
5320
- for (const p of cellParticles) {
5321
- if (check && !check(p)) {
5322
- continue;
5323
- }
5324
- if (range.contains(p.getPosition())) {
5325
- out.push(p);
5326
- }
5327
- }
5438
+ this.#queryCell(cx, cy, range, check, out);
5328
5439
  }
5329
5440
  }
5330
5441
  return out;
5331
5442
  }
5332
5443
  queryCircle(position, radius, check, out = []) {
5333
- const circle = this.#acquireCircle(position.x, position.y, radius), result = this.query(circle, check, out);
5334
- this.#releaseShapes();
5335
- return result;
5444
+ const circle = this.#acquireCircle(position.x, position.y, radius);
5445
+ try {
5446
+ return this.query(circle, check, out);
5447
+ }
5448
+ finally {
5449
+ this.#circlePoolIdx--;
5450
+ }
5336
5451
  }
5337
5452
  queryRectangle(position, size, check, out = []) {
5338
- const rect = this.#acquireRectangle(position.x, position.y, size.width, size.height), result = this.query(rect, check, out);
5339
- this.#releaseShapes();
5340
- return result;
5341
- }
5342
- setCellSize(cellSize) {
5343
- this.#pendingCellSize = cellSize;
5453
+ const rect = this.#acquireRectangle(position.x, position.y, size.width, size.height);
5454
+ try {
5455
+ return this.query(rect, check, out);
5456
+ }
5457
+ finally {
5458
+ this.#rectanglePoolIdx--;
5459
+ }
5344
5460
  }
5345
5461
  #acquireCircle(x, y, r) {
5346
- return (this.#circlePool[this.#circlePoolIdx++] ??= new Circle(x, y, r)).reset(x, y, r);
5462
+ const idx = this.#circlePoolIdx++;
5463
+ let circle = this.#circlePool[idx];
5464
+ if (!circle) {
5465
+ circle = new Circle(x, y, r);
5466
+ this.#circlePool[idx] = circle;
5467
+ }
5468
+ return circle.reset(x, y, r);
5347
5469
  }
5348
5470
  #acquireRectangle(x, y, w, h) {
5349
- return (this.#rectanglePool[this.#rectanglePoolIdx++] ??= new Rectangle(x, y, w, h)).reset(x, y, w, h);
5471
+ const idx = this.#rectanglePoolIdx++;
5472
+ let rectangle = this.#rectanglePool[idx];
5473
+ if (!rectangle) {
5474
+ rectangle = new Rectangle(x, y, w, h);
5475
+ this.#rectanglePool[idx] = rectangle;
5476
+ }
5477
+ return rectangle.reset(x, y, w, h);
5350
5478
  }
5351
5479
  #cellKeyFromCoords(x, y) {
5352
5480
  const cellX = Math.floor(x / this.#cellSize), cellY = Math.floor(y / this.#cellSize);
@@ -5373,17 +5501,27 @@
5373
5501
  }
5374
5502
  return null;
5375
5503
  }
5376
- #releaseShapes() {
5377
- this.#circlePoolIdx = 0;
5378
- this.#rectanglePoolIdx = 0;
5504
+ #queryCell(cx, cy, range, check, out) {
5505
+ const cellParticles = this.#cells.get(`${cx}_${cy}`);
5506
+ if (!cellParticles) {
5507
+ return;
5508
+ }
5509
+ for (const p of cellParticles) {
5510
+ if (check && !check(p)) {
5511
+ continue;
5512
+ }
5513
+ if (range.contains(p.getPosition())) {
5514
+ out.push(p);
5515
+ }
5516
+ }
5379
5517
  }
5380
5518
  }
5381
5519
 
5382
5520
  class ParticlesManager {
5383
5521
  checkParticlePositionPlugins;
5384
- grid;
5385
5522
  #array;
5386
5523
  #container;
5524
+ #grid;
5387
5525
  #groupLimits;
5388
5526
  #limit;
5389
5527
  #nextId;
@@ -5407,7 +5545,7 @@
5407
5545
  this.#groupLimits = new Map();
5408
5546
  this.#particleBuckets = new Map();
5409
5547
  this.#zBuckets = this.#createBuckets(this.#container.zLayers);
5410
- this.grid = new SpatialHashGrid(spatialHashGridCellSize);
5548
+ this.#grid = new SpatialHashGrid(spatialHashGridCellSize);
5411
5549
  this.checkParticlePositionPlugins = [];
5412
5550
  this.#particleResetPlugins = [];
5413
5551
  this.#particleUpdatePlugins = [];
@@ -5418,23 +5556,12 @@
5418
5556
  get count() {
5419
5557
  return this.#array.length;
5420
5558
  }
5559
+ get grid() {
5560
+ return this.#grid;
5561
+ }
5421
5562
  addParticle(position, overrideOptions, group, initializer) {
5422
- const limitMode = this.#container.actualOptions.particles.number.limit.mode, limit = group === undefined ? this.#limit : (this.#groupLimits.get(group) ?? this.#limit), currentCount = this.count;
5423
- if (limit > minLimit) {
5424
- switch (limitMode) {
5425
- case LimitMode.delete: {
5426
- const countToRemove = currentCount + countOffset - limit;
5427
- if (countToRemove > minCount) {
5428
- this.removeQuantity(countToRemove);
5429
- }
5430
- break;
5431
- }
5432
- case LimitMode.wait:
5433
- if (currentCount >= limit) {
5434
- return;
5435
- }
5436
- break;
5437
- }
5563
+ if (this.#checkAndApplyLimits(group, this.count)) {
5564
+ return;
5438
5565
  }
5439
5566
  try {
5440
5567
  const particle = this.#pool.pop() ?? new Particle(this.#pluginManager, this.#container);
@@ -5498,7 +5625,7 @@
5498
5625
  return this.#array[index];
5499
5626
  }
5500
5627
  async init() {
5501
- const container = this.#container, options = container.actualOptions;
5628
+ const container = this.#container;
5502
5629
  this.checkParticlePositionPlugins = [];
5503
5630
  this.#updatePlugins = [];
5504
5631
  this.#particleUpdatePlugins = [];
@@ -5507,59 +5634,16 @@
5507
5634
  this.#postParticleUpdatePlugins = [];
5508
5635
  this.#particleBuckets.clear();
5509
5636
  this.#resetBuckets(container.zLayers);
5510
- this.grid = new SpatialHashGrid(spatialHashGridCellSize * container.retina.pixelRatio);
5511
- for (const plugin of container.plugins) {
5512
- if (plugin.redrawInit) {
5513
- await plugin.redrawInit();
5514
- }
5515
- if (plugin.checkParticlePosition) {
5516
- this.checkParticlePositionPlugins.push(plugin);
5517
- }
5518
- if (plugin.update) {
5519
- this.#updatePlugins.push(plugin);
5520
- }
5521
- if (plugin.particleUpdate) {
5522
- this.#particleUpdatePlugins.push(plugin);
5523
- }
5524
- if (plugin.postUpdate) {
5525
- this.#postUpdatePlugins.push(plugin);
5526
- }
5527
- if (plugin.particleReset) {
5528
- this.#particleResetPlugins.push(plugin);
5529
- }
5530
- if (plugin.postParticleUpdate) {
5531
- this.#postParticleUpdatePlugins.push(plugin);
5532
- }
5533
- }
5534
- await this.#container.initDrawersAndUpdaters();
5535
- for (const drawer of this.#container.effectDrawers.values()) {
5536
- await drawer.init?.(container);
5537
- }
5538
- for (const drawer of this.#container.shapeDrawers.values()) {
5539
- await drawer.init?.(container);
5540
- }
5541
- let handled = false;
5542
- for (const plugin of container.plugins) {
5543
- handled = plugin.particlesInitialization?.() ?? handled;
5544
- if (handled) {
5545
- break;
5546
- }
5547
- }
5548
- if (!handled) {
5549
- const particlesOptions = options.particles, groups = particlesOptions.groups;
5550
- for (const group in groups) {
5551
- const groupOptions = groups[group];
5552
- if (!groupOptions) {
5553
- continue;
5554
- }
5555
- for (let i = this.count, j = 0; j < groupOptions.number.value && i < particlesOptions.number.value; i++, j++) {
5556
- this.addParticle(undefined, groupOptions, group);
5557
- }
5558
- }
5559
- for (let i = this.count; i < particlesOptions.number.value; i++) {
5560
- this.addParticle();
5637
+ this.#grid = new SpatialHashGrid(spatialHashGridCellSize * container.retina.pixelRatio);
5638
+ this.#applyLimits(container.actualOptions.particles);
5639
+ const particlesOptions = container.actualOptions.particles, groups = particlesOptions.groups;
5640
+ for (const group in groups) {
5641
+ const groupData = groups[group];
5642
+ if (groupData) {
5643
+ this.#applyLimits(loadParticlesOptions(this.#pluginManager, this.#container, groupData), group, groupData);
5561
5644
  }
5562
5645
  }
5646
+ await this.#initPlugins();
5563
5647
  }
5564
5648
  push(nb, position, overrideOptions, group) {
5565
5649
  for (let i = 0; i < nb; i++) {
@@ -5574,13 +5658,13 @@
5574
5658
  remove(particle, group, override) {
5575
5659
  this.removeAt(this.#array.indexOf(particle), undefined, group, override);
5576
5660
  }
5577
- removeAt(index, quantity = defaultRemoveQuantity, group, override) {
5661
+ removeAt(index, quantity = defaultRemoveQuantity, group, override, matchGroup = true) {
5578
5662
  if (index < minIndex || index > this.count) {
5579
5663
  return;
5580
5664
  }
5581
5665
  let deleted = 0;
5582
5666
  for (let i = index; deleted < quantity && i < this.count; i++) {
5583
- if (this.#removeParticle(i, group, override)) {
5667
+ if (this.#removeParticle(i, group, override, matchGroup)) {
5584
5668
  i--;
5585
5669
  deleted++;
5586
5670
  }
@@ -5611,7 +5695,7 @@
5611
5695
  this.#resizeFactor = factor;
5612
5696
  }
5613
5697
  update(delta) {
5614
- this.grid.clear();
5698
+ this.#grid.clear();
5615
5699
  for (const plugin of this.#updatePlugins) {
5616
5700
  plugin.update?.(delta);
5617
5701
  }
@@ -5622,7 +5706,7 @@
5622
5706
  this.#updateParticlesPhase2(delta, particlesToDelete);
5623
5707
  if (particlesToDelete.size) {
5624
5708
  for (const particle of particlesToDelete) {
5625
- this.remove(particle);
5709
+ this.remove(particle, particle.group);
5626
5710
  }
5627
5711
  }
5628
5712
  this.#resizeFactor = undefined;
@@ -5633,12 +5717,7 @@
5633
5717
  #applyDensity(options, pluginsCount, group, groupOptions) {
5634
5718
  const numberOptions = options.number;
5635
5719
  if (!numberOptions.density.enable) {
5636
- if (group === undefined) {
5637
- this.#limit = numberOptions.limit.value;
5638
- }
5639
- else if (groupOptions?.number.limit.value ?? numberOptions.limit.value) {
5640
- this.#groupLimits.set(group, groupOptions?.number.limit.value ?? numberOptions.limit.value);
5641
- }
5720
+ this.#applyLimits(options, group, groupOptions);
5642
5721
  return;
5643
5722
  }
5644
5723
  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);
@@ -5646,7 +5725,10 @@
5646
5725
  this.#limit = numberOptions.limit.value * densityFactor;
5647
5726
  }
5648
5727
  else {
5649
- this.#groupLimits.set(group, numberOptions.limit.value * densityFactor);
5728
+ this.#groupLimits.set(group, {
5729
+ limit: numberOptions.limit.value * densityFactor,
5730
+ mode: toEnumValue(LimitMode, numberOptions.limit.mode, LimitMode.delete),
5731
+ });
5650
5732
  }
5651
5733
  if (particlesCount < particlesNumber) {
5652
5734
  this.push(Math.abs(particlesNumber - particlesCount), undefined, options, group);
@@ -5655,6 +5737,55 @@
5655
5737
  this.removeQuantity(particlesCount - particlesNumber, group);
5656
5738
  }
5657
5739
  }
5740
+ #applyLimits(options, group, groupOptions) {
5741
+ if (group === undefined) {
5742
+ this.#limit = options.number.limit.value;
5743
+ const groups = this.#container.actualOptions.particles.groups;
5744
+ for (const existingGroup of this.#groupLimits.keys()) {
5745
+ if (!(existingGroup in groups)) {
5746
+ this.#groupLimits.delete(existingGroup);
5747
+ }
5748
+ }
5749
+ }
5750
+ else {
5751
+ const limitValue = groupOptions?.number?.limit?.value ?? options.number.limit.value;
5752
+ if (limitValue > minLimit) {
5753
+ this.#groupLimits.set(group, {
5754
+ limit: limitValue,
5755
+ mode: toEnumValue(LimitMode, groupOptions?.number?.limit?.mode ?? options.number.limit.mode, LimitMode.delete),
5756
+ });
5757
+ }
5758
+ else {
5759
+ this.#groupLimits.delete(group);
5760
+ }
5761
+ }
5762
+ }
5763
+ #checkAndApplyLimits(group, currentCount) {
5764
+ const globalLimit = this.#limit, globalMode = this.#container.actualOptions.particles.number.limit.mode;
5765
+ if (globalLimit > minLimit && globalMode === LimitMode.wait && currentCount >= globalLimit) {
5766
+ return true;
5767
+ }
5768
+ const groupLimitEntry = group === undefined ? undefined : this.#groupLimits.get(group);
5769
+ if (groupLimitEntry && groupLimitEntry.limit > minLimit && groupLimitEntry.mode === LimitMode.wait) {
5770
+ const groupCount = this.filter(t => t.group === group).length;
5771
+ if (groupCount >= groupLimitEntry.limit) {
5772
+ return true;
5773
+ }
5774
+ }
5775
+ if (groupLimitEntry && groupLimitEntry.limit > minLimit && groupLimitEntry.mode === LimitMode.delete) {
5776
+ const groupCountToRemove = this.filter(t => t.group === group).length + countOffset - groupLimitEntry.limit;
5777
+ if (groupCountToRemove > minCount) {
5778
+ this.removeQuantity(groupCountToRemove, group);
5779
+ }
5780
+ }
5781
+ if (globalLimit > minLimit && globalMode === LimitMode.delete) {
5782
+ const globalCountToRemove = this.count + countOffset - globalLimit;
5783
+ if (globalCountToRemove > minCount) {
5784
+ this.#removeAny(globalCountToRemove);
5785
+ }
5786
+ }
5787
+ return false;
5788
+ }
5658
5789
  #createBuckets(zLayers) {
5659
5790
  const bucketCount = Math.max(Math.floor(zLayers), one);
5660
5791
  return Array.from({ length: bucketCount }, () => []);
@@ -5677,6 +5808,70 @@
5677
5808
  }
5678
5809
  return ((canvasSize.width * canvasSize.height) / (densityOptions.height * densityOptions.width * pxRatio ** squareExp));
5679
5810
  }
5811
+ async #initDrawersAndUpdaters() {
5812
+ const container = this.#container;
5813
+ await container.initDrawersAndUpdaters();
5814
+ for (const drawer of container.effectDrawers.values()) {
5815
+ await drawer.init?.(container);
5816
+ }
5817
+ for (const drawer of container.shapeDrawers.values()) {
5818
+ await drawer.init?.(container);
5819
+ }
5820
+ }
5821
+ async #initPlugins() {
5822
+ await this.#initPluginsArrays();
5823
+ await this.#initDrawersAndUpdaters();
5824
+ let handled = false;
5825
+ const container = this.#container;
5826
+ for (const plugin of container.plugins) {
5827
+ handled = plugin.particlesInitialization?.() ?? handled;
5828
+ if (handled) {
5829
+ break;
5830
+ }
5831
+ }
5832
+ if (handled) {
5833
+ return;
5834
+ }
5835
+ const particlesOptions = container.actualOptions.particles, groups = particlesOptions.groups;
5836
+ for (const group in groups) {
5837
+ const groupOptions = groups[group];
5838
+ if (!groupOptions) {
5839
+ continue;
5840
+ }
5841
+ for (let i = this.count, j = 0; j < groupOptions.number.value && i < particlesOptions.number.value; i++, j++) {
5842
+ this.addParticle(undefined, groupOptions, group);
5843
+ }
5844
+ }
5845
+ for (let i = this.count; i < particlesOptions.number.value; i++) {
5846
+ this.addParticle();
5847
+ }
5848
+ }
5849
+ async #initPluginsArrays() {
5850
+ const container = this.#container;
5851
+ for (const plugin of container.plugins) {
5852
+ if (plugin.redrawInit) {
5853
+ await plugin.redrawInit();
5854
+ }
5855
+ if (plugin.checkParticlePosition) {
5856
+ this.checkParticlePositionPlugins.push(plugin);
5857
+ }
5858
+ if (plugin.update) {
5859
+ this.#updatePlugins.push(plugin);
5860
+ }
5861
+ if (plugin.particleUpdate) {
5862
+ this.#particleUpdatePlugins.push(plugin);
5863
+ }
5864
+ if (plugin.postUpdate) {
5865
+ this.#postUpdatePlugins.push(plugin);
5866
+ }
5867
+ if (plugin.particleReset) {
5868
+ this.#particleResetPlugins.push(plugin);
5869
+ }
5870
+ if (plugin.postParticleUpdate) {
5871
+ this.#postParticleUpdatePlugins.push(plugin);
5872
+ }
5873
+ }
5874
+ }
5680
5875
  #insertParticleIntoBucket(particle) {
5681
5876
  const bucketIndex = this.#getBucketIndex(particle.position.z), bucket = this.#zBuckets[bucketIndex];
5682
5877
  if (!bucket) {
@@ -5685,12 +5880,15 @@
5685
5880
  bucket.push(particle);
5686
5881
  this.#particleBuckets.set(particle.id, bucketIndex);
5687
5882
  }
5688
- #removeParticle(index, group, override) {
5883
+ #removeAny(quantity) {
5884
+ this.removeAt(minIndex, quantity, undefined, undefined, false);
5885
+ }
5886
+ #removeParticle(index, group, override, matchGroup = true) {
5689
5887
  const particle = this.#array[index];
5690
5888
  if (!particle) {
5691
5889
  return false;
5692
5890
  }
5693
- if (particle.group !== group) {
5891
+ if (matchGroup && particle.group !== group) {
5694
5892
  return false;
5695
5893
  }
5696
5894
  this.#array.splice(index, deleteCount);
@@ -5777,7 +5975,7 @@
5777
5975
  particlesToDelete.add(particle);
5778
5976
  continue;
5779
5977
  }
5780
- this.grid.insert(particle);
5978
+ this.#grid.insert(particle);
5781
5979
  }
5782
5980
  return particlesToDelete;
5783
5981
  }
@@ -5864,6 +6062,7 @@
5864
6062
  started;
5865
6063
  zLayers;
5866
6064
  #delay;
6065
+ #delayResolve;
5867
6066
  #delayTimeout;
5868
6067
  #delta = { value: 0, factor: 0 };
5869
6068
  #dispatchCallback;
@@ -5953,7 +6152,6 @@
5953
6152
  this.shapeDrawers = new Map();
5954
6153
  this.particleUpdaters = [];
5955
6154
  this.plugins.length = 0;
5956
- this.#pluginManager.clearPlugins(this);
5957
6155
  this.destroyed = true;
5958
6156
  this.#onDestroy(remove);
5959
6157
  this.dispatchEvent(EventType.containerDestroyed);
@@ -6006,31 +6204,14 @@
6006
6204
  await this.initDrawersAndUpdaters();
6007
6205
  this.#options = loadContainerOptions(this.#pluginManager, this, this.#initialSourceOptions, this.sourceOptions);
6008
6206
  this.actualOptions = loadContainerOptions(this.#pluginManager, this, this.#options);
6009
- this.plugins.length = 0;
6010
- this.particleDestroyedPlugins.length = 0;
6011
- this.particleCreatedPlugins.length = 0;
6012
- this.particlePositionPlugins.length = 0;
6013
- for (const [plugin, containerPlugin] of allContainerPlugins) {
6014
- if (plugin.needsPlugin(this.actualOptions)) {
6015
- this.plugins.push(containerPlugin);
6016
- if (containerPlugin.particleCreated) {
6017
- this.particleCreatedPlugins.push(containerPlugin);
6018
- }
6019
- if (containerPlugin.particleDestroyed) {
6020
- this.particleDestroyedPlugins.push(containerPlugin);
6021
- }
6022
- if (containerPlugin.particlePosition) {
6023
- this.particlePositionPlugins.push(containerPlugin);
6024
- }
6025
- }
6026
- }
6207
+ this.#initPlugins(allContainerPlugins);
6027
6208
  this.retina.init();
6028
6209
  this.canvas.init();
6029
6210
  this.updateActualOptions();
6030
6211
  this.canvas.initBackground();
6031
6212
  this.canvas.resize();
6032
6213
  const { delay, duration, fpsLimit, smooth, zLayers } = this.actualOptions, hdrOptions = this.actualOptions.hdr;
6033
- this.hdrMode = hdrOptions.mode;
6214
+ this.hdrMode = toEnumValue(HdrMode, hdrOptions.mode, HdrMode.standard);
6034
6215
  this.peakNits = hdrOptions.peakNits;
6035
6216
  this.zLayers = zLayers;
6036
6217
  this.#duration = getRangeValue(duration) * millisecondsToSeconds;
@@ -6051,9 +6232,9 @@
6051
6232
  }
6052
6233
  async initDrawersAndUpdaters() {
6053
6234
  const pluginManager = this.#pluginManager;
6054
- this.effectDrawers = await pluginManager.getEffectDrawers(this, true);
6055
- this.shapeDrawers = await pluginManager.getShapeDrawers(this, true);
6056
- this.particleUpdaters = await pluginManager.getUpdaters(this, true);
6235
+ this.effectDrawers = await getItemMapFromInitializer(this, pluginManager.initializers.effects);
6236
+ this.shapeDrawers = await getItemMapFromInitializer(this, pluginManager.initializers.shapes);
6237
+ this.particleUpdaters = await getItemsFromInitializer(this, pluginManager.initializers.updaters);
6057
6238
  }
6058
6239
  pause() {
6059
6240
  if (!guardCheck(this)) {
@@ -6120,7 +6301,10 @@
6120
6301
  await this.init();
6121
6302
  this.started = true;
6122
6303
  await new Promise(resolve => {
6304
+ this.#delayResolve = resolve;
6123
6305
  const start = async () => {
6306
+ this.#delayTimeout = undefined;
6307
+ this.#delayResolve = undefined;
6124
6308
  this.#eventListeners.addListeners();
6125
6309
  for (const plugin of this.plugins) {
6126
6310
  await plugin.start?.();
@@ -6136,9 +6320,11 @@
6136
6320
  if (!guardCheck(this) || !this.started) {
6137
6321
  return;
6138
6322
  }
6139
- if (this.#delayTimeout) {
6323
+ if (this.#delayTimeout !== undefined) {
6140
6324
  clearTimeout(this.#delayTimeout);
6141
6325
  this.#delayTimeout = undefined;
6326
+ this.#delayResolve?.();
6327
+ this.#delayResolve = undefined;
6142
6328
  }
6143
6329
  this.#firstStart = true;
6144
6330
  this.started = false;
@@ -6164,6 +6350,27 @@
6164
6350
  }
6165
6351
  return refresh;
6166
6352
  }
6353
+ #initPlugins(allContainerPlugins) {
6354
+ this.plugins.length = 0;
6355
+ this.particleDestroyedPlugins.length = 0;
6356
+ this.particleCreatedPlugins.length = 0;
6357
+ this.particlePositionPlugins.length = 0;
6358
+ for (const [plugin, containerPlugin] of allContainerPlugins) {
6359
+ if (!plugin.needsPlugin(this.actualOptions)) {
6360
+ continue;
6361
+ }
6362
+ this.plugins.push(containerPlugin);
6363
+ if (containerPlugin.particleCreated) {
6364
+ this.particleCreatedPlugins.push(containerPlugin);
6365
+ }
6366
+ if (containerPlugin.particleDestroyed) {
6367
+ this.particleDestroyedPlugins.push(containerPlugin);
6368
+ }
6369
+ if (containerPlugin.particlePosition) {
6370
+ this.particlePositionPlugins.push(containerPlugin);
6371
+ }
6372
+ }
6373
+ }
6167
6374
  #nextFrame(timestamp) {
6168
6375
  try {
6169
6376
  if (!this.#smooth &&
@@ -6440,11 +6647,11 @@
6440
6647
  }
6441
6648
  }
6442
6649
  async #init() {
6443
- const availablePathGenerators = await this.#pluginManager.getPathGenerators?.(this.#container, true);
6444
- if (!availablePathGenerators) {
6650
+ const pluginManager = this.#pluginManager;
6651
+ if (!pluginManager.initializers.pathGenerators) {
6445
6652
  return;
6446
6653
  }
6447
- this.availablePathGenerators = availablePathGenerators;
6654
+ this.availablePathGenerators = await getItemMapFromInitializer(this.#container, pluginManager.initializers.pathGenerators);
6448
6655
  this.pathGenerators = new Map();
6449
6656
  for (const pathGenerator of this.pathGenerators.values()) {
6450
6657
  pathGenerator.init();
@@ -6548,28 +6755,14 @@
6548
6755
  }
6549
6756
  const html = interactivityEl, canvas = container.canvas;
6550
6757
  canvas.setPointerEvents(html === canvas.domElement ? "initial" : "none");
6551
- if (add && !(options.interactivity?.events.onHover.enable || options.interactivity?.events.onClick.enable)) {
6552
- return;
6553
- }
6554
6758
  manageListener(interactivityEl, mouseMoveEvent, handlers.mouseMove, add);
6555
6759
  manageListener(interactivityEl, touchStartEvent, handlers.touchStart, add);
6556
6760
  manageListener(interactivityEl, touchMoveEvent, handlers.touchMove, add);
6557
- if (add) {
6558
- if (options.interactivity?.events.onClick.enable) {
6559
- manageListener(interactivityEl, touchEndEvent, handlers.touchEndClick, add);
6560
- manageListener(interactivityEl, mouseUpEvent, handlers.mouseUp, add);
6561
- manageListener(interactivityEl, mouseDownEvent, handlers.mouseDown, add);
6562
- }
6563
- else {
6564
- manageListener(interactivityEl, touchEndEvent, handlers.touchEnd, add);
6565
- }
6566
- }
6567
- else {
6568
- manageListener(interactivityEl, touchEndEvent, handlers.touchEndClick, add);
6569
- manageListener(interactivityEl, mouseUpEvent, handlers.mouseUp, add);
6570
- manageListener(interactivityEl, mouseDownEvent, handlers.mouseDown, add);
6571
- manageListener(interactivityEl, touchEndEvent, handlers.touchEnd, add);
6572
- }
6761
+ const onClickEnabled = !!options.interactivity?.events.onClick.enable;
6762
+ manageListener(interactivityEl, touchEndEvent, handlers.touchEndClick, add && onClickEnabled);
6763
+ manageListener(interactivityEl, touchEndEvent, handlers.touchEnd, add && !onClickEnabled);
6764
+ manageListener(interactivityEl, mouseUpEvent, handlers.mouseUp, add);
6765
+ manageListener(interactivityEl, mouseDownEvent, handlers.mouseDown, add);
6573
6766
  manageListener(interactivityEl, mouseLeaveEvent, handlers.mouseLeave, add);
6574
6767
  manageListener(interactivityEl, touchCancelEvent, handlers.touchCancel, add);
6575
6768
  }
@@ -6595,19 +6788,18 @@
6595
6788
  #mouseTouchClick(e) {
6596
6789
  const container = this.#container, interactionManager = this.#interactionManager, options = container.actualOptions, { mouse } = interactionManager.interactivityData;
6597
6790
  mouse.inside = true;
6598
- let handled = false;
6599
6791
  const mousePosition = mouse.position;
6600
- if (!mousePosition || !options.interactivity?.events.onClick.enable) {
6601
- return;
6602
- }
6603
- for (const plugin of this.#clickPositionPlugins) {
6604
- handled = plugin.clickPositionValid?.(mousePosition) ?? false;
6605
- if (handled) {
6606
- break;
6792
+ if (mousePosition && options.interactivity?.events.onClick.enable) {
6793
+ let handled = false;
6794
+ for (const plugin of this.#clickPositionPlugins) {
6795
+ handled = plugin.clickPositionValid?.(mousePosition) ?? false;
6796
+ if (handled) {
6797
+ break;
6798
+ }
6799
+ }
6800
+ if (!handled) {
6801
+ this.#doMouseTouchClick(e);
6607
6802
  }
6608
- }
6609
- if (!handled) {
6610
- this.#doMouseTouchClick(e);
6611
6803
  }
6612
6804
  mouse.clicking = false;
6613
6805
  }
@@ -6703,6 +6895,9 @@
6703
6895
  this.#touches.set(touch.identifier, performance.now());
6704
6896
  }
6705
6897
  this.#mouseTouchMove(e);
6898
+ const { mouse } = this.#interactionManager.interactivityData;
6899
+ mouse.clicking = true;
6900
+ mouse.downPosition = mouse.position;
6706
6901
  }
6707
6902
  }
6708
6903
 
@@ -6715,18 +6910,18 @@
6715
6910
  }
6716
6911
  class InteractionManager {
6717
6912
  interactivityData;
6913
+ interactors;
6718
6914
  #clickHandlers;
6719
6915
  #container;
6720
6916
  #eventListeners;
6721
6917
  #externalInteractors;
6722
- #interactors;
6723
6918
  #intersectionObserver;
6724
6919
  #particleInteractors;
6725
6920
  #pluginManager;
6726
6921
  constructor(pluginManager, container) {
6727
6922
  this.#container = container;
6728
6923
  this.#pluginManager = pluginManager;
6729
- this.#interactors = [];
6924
+ this.interactors = [];
6730
6925
  this.#externalInteractors = [];
6731
6926
  this.#particleInteractors = [];
6732
6927
  this.#clickHandlers = new Map();
@@ -6845,7 +7040,7 @@
6845
7040
  }
6846
7041
  init() {
6847
7042
  this.#eventListeners.init();
6848
- for (const interactor of this.#interactors) {
7043
+ for (const interactor of this.interactors) {
6849
7044
  switch (interactor.type) {
6850
7045
  case InteractorType.external:
6851
7046
  this.#externalInteractors.push(interactor);
@@ -6858,11 +7053,11 @@
6858
7053
  }
6859
7054
  }
6860
7055
  async initInteractors() {
6861
- const interactors = await this.#pluginManager.getInteractors?.(this.#container, true);
6862
- if (!interactors) {
7056
+ const pluginManager = this.#pluginManager;
7057
+ if (!pluginManager.initializers.interactors) {
6863
7058
  return;
6864
7059
  }
6865
- this.#interactors = interactors;
7060
+ this.interactors = await getItemsFromInitializer(this.#container, pluginManager.initializers.interactors);
6866
7061
  this.#externalInteractors = [];
6867
7062
  this.#particleInteractors = [];
6868
7063
  }
@@ -6907,13 +7102,13 @@
6907
7102
  }
6908
7103
  updateMaxDistance() {
6909
7104
  let maxTotalDistance = 0;
6910
- for (const interactor of this.#interactors) {
7105
+ for (const interactor of this.interactors) {
6911
7106
  if (interactor.maxDistance > maxTotalDistance) {
6912
7107
  maxTotalDistance = interactor.maxDistance;
6913
7108
  }
6914
7109
  }
6915
7110
  const container = this.#container;
6916
- container.particles.grid.setCellSize(maxTotalDistance * container.retina.pixelRatio);
7111
+ container.particles.grid.cellSize = maxTotalDistance * container.retina.pixelRatio;
6917
7112
  }
6918
7113
  #intersectionManager(entries) {
6919
7114
  const container = this.#container;
@@ -6935,59 +7130,59 @@
6935
7130
  }
6936
7131
 
6937
7132
  class InteractivityPluginInstance {
6938
- interactionManager;
6939
7133
  #container;
6940
- #pluginManager;
6941
7134
  constructor(pluginManager, container) {
6942
- this.#container = container;
6943
- this.#pluginManager = pluginManager;
6944
- this.interactionManager = new InteractionManager(pluginManager, container);
6945
- this.#container.addClickHandler = (callback) => {
6946
- this.interactionManager.addClickHandler(callback);
7135
+ container.addClickHandler = (callback) => {
7136
+ container.interactionManager?.addClickHandler(callback);
6947
7137
  };
7138
+ container.interactionManager = new InteractionManager(pluginManager, container);
7139
+ this.#container = container;
6948
7140
  }
6949
7141
  addClickHandler(callback) {
6950
- this.interactionManager.addClickHandler(callback);
7142
+ this.#container.interactionManager?.addClickHandler(callback);
6951
7143
  }
6952
7144
  clearClickHandlers() {
6953
- this.interactionManager.clearClickHandlers();
7145
+ this.#container.interactionManager?.clearClickHandlers();
6954
7146
  }
6955
7147
  destroy() {
6956
7148
  this.clearClickHandlers();
6957
- this.#pluginManager.interactors?.delete(this.#container);
6958
7149
  }
6959
7150
  particleCreated(particle) {
6960
- const interactivityParticle = particle, interactivity = new Interactivity(this.#pluginManager, this.#container);
6961
- interactivity.load(this.#container.actualOptions.interactivity);
7151
+ const interactivityParticle = particle, container = this.#container, interactivity = new Interactivity(container);
7152
+ interactivity.load(container.actualOptions.interactivity);
6962
7153
  interactivity.load(interactivityParticle.options.interactivity);
6963
7154
  interactivityParticle.interactivity = interactivity;
6964
7155
  }
6965
7156
  particleReset(particle) {
6966
- this.interactionManager.reset(particle);
7157
+ this.#container.interactionManager?.reset(particle);
6967
7158
  }
6968
7159
  postParticleUpdate(particle, delta) {
6969
- this.interactionManager.particlesInteract(particle, delta);
7160
+ this.#container.interactionManager?.particlesInteract(particle, delta);
6970
7161
  }
6971
7162
  postUpdate(delta) {
6972
- this.interactionManager.externalInteract(delta);
6973
- this.interactionManager.updateMaxDistance();
7163
+ const container = this.#container;
7164
+ container.interactionManager?.externalInteract(delta);
7165
+ container.interactionManager?.updateMaxDistance();
6974
7166
  }
6975
7167
  async preInit() {
6976
- await this.interactionManager.initInteractors();
6977
- this.interactionManager.init();
7168
+ const container = this.#container;
7169
+ await container.interactionManager?.initInteractors();
7170
+ container.interactionManager?.init();
6978
7171
  }
6979
7172
  async redrawInit() {
6980
- await this.interactionManager.initInteractors();
6981
- this.interactionManager.init();
7173
+ const container = this.#container;
7174
+ await container.interactionManager?.initInteractors();
7175
+ container.interactionManager?.init();
6982
7176
  }
6983
7177
  start() {
6984
- this.interactionManager.addListeners();
6985
- this.interactionManager.startObserving();
7178
+ const container = this.#container;
7179
+ container.interactionManager?.addListeners();
7180
+ container.interactionManager?.startObserving();
6986
7181
  return Promise.resolve();
6987
7182
  }
6988
7183
  stop() {
6989
- this.interactionManager.removeListeners();
6990
- this.interactionManager.stopObserving();
7184
+ this.#container.interactionManager?.removeListeners();
7185
+ this.#container.interactionManager?.stopObserving();
6991
7186
  }
6992
7187
  }
6993
7188
 
@@ -7181,6 +7376,7 @@
7181
7376
  exports.loadTrianglesPreset = loadTrianglesPreset;
7182
7377
  exports.tsParticles = tsParticles;
7183
7378
 
7184
- }));
7379
+ })(g.__tsParticlesInternals.presets.triangles = g.__tsParticlesInternals.presets.triangles || {});
7380
+ })(typeof globalThis !== "undefined" ? globalThis : typeof window !== "undefined" ? window : self);
7381
+
7185
7382
  Object.assign(globalThis.window || globalThis, { loadTrianglesPreset: (globalThis.__tsParticlesInternals.presets.triangles || {}).loadTrianglesPreset });
7186
- delete (globalThis.window || globalThis).tsparticlesInternalExports;