@tsparticles/preset-matrix 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.matrix = global.__tsParticlesInternals.presets.matrix || {})));
7
- })(this, (function (exports) { 'use strict';
8
-
9
- const generatedAttribute = "generated", defaultCompositeValue = "source-over", resizeEvent = "resize", visibilityChangeEvent = "visibilitychange", percentDenominator = 100, half = 0.5, millisecondsToSeconds = 1000, originPoint = {
10
- x: 0,
11
- y: 0,
12
- z: 0,
13
- }, defaultTransform = {
14
- a: 1,
15
- b: 0,
16
- c: 0,
17
- d: 1,
18
- }, randomColorValue = "random", double = 2, doublePI = Math.PI * double, defaultFps = 60, generatedTrue = "true", generatedFalse = "false", canvasTag = "canvas", defaultRetryCount = 0, squareExp = 2, spatialHashGridCellSize = 100, defaultRemoveQuantity = 1, defaultRatio = 1, defaultReduceFactor = 1, inverseFactorNumerator = 1, rgbMax = 255, hMax = 360, sMax = 100, lMax = 100, hMin = 0, sMin = 0, hPhase = 60, empty = 0, quarter = 0.25, threeQuarter = half + quarter, minVelocity = 0, minDistance = 0, defaultTransformValue = 1, minimumSize = 0, zIndexFactorOffset = 1, defaultOpacity$1 = 1, removeDeleteCount = 1, removeMinIndex = 0, defaultFpsLimit = 120, minFpsLimit = 0, canvasFirstIndex = 0, loadRandomFactor = 10000, loadMinIndex = 0, one = 1, none = 0, decayOffset = 1, tryCountIncrement = 1, minZ = 0, minLimit = 0, countOffset = 1, minCount = 0, minIndex = 0, 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", double = 2, doublePI = Math.PI * double, defaultFps = 60, defaultAlpha = 1, generatedTrue = "true", generatedFalse = "false", canvasTag = "canvas", defaultRetryCount = 0, squareExp = 2, spatialHashGridCellSize = 100, defaultRemoveQuantity = 1, defaultRatio = 1, defaultReduceFactor = 1, inverseFactorNumerator = 1, rgbMax = 255, hMax = 360, sMax = 100, lMax = 100, hMin = 0, sMin = 0, hPhase = 60, empty = 0, quarter = 0.25, threeQuarter = half + quarter, minVelocity = 0, minDistance = 0, minRadius = 0, defaultTransformValue = 1, minimumSize = 0, zIndexFactorOffset = 1, defaultOpacity$1 = 1, removeDeleteCount = 1, removeMinIndex = 0, defaultFpsLimit = 120, minFpsLimit = 0, canvasFirstIndex = 0, loadRandomFactor = 10000, loadMinIndex = 0, one = 1, none = 0, decayOffset = 1, tryCountIncrement = 1, minZ = 0, minLimit = 0, countOffset = 1, minCount = 0, minIndex = 0, 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
  }
@@ -270,11 +301,61 @@
270
301
  };
271
302
  }
272
303
  function parseAlpha(input) {
273
- const defaultAlpha = 1;
274
304
  if (!input) {
275
305
  return defaultAlpha;
276
306
  }
277
- return input.endsWith("%") ? parseFloat(input) / percentDenominator : parseFloat(input);
307
+ return input.endsWith("%") ? Number.parseFloat(input) / percentDenominator : Number.parseFloat(input);
308
+ }
309
+
310
+ const ErrorCodes$1 = {
311
+ engineVersionMismatch: "TSP-1001",
312
+ particlePositionNotFound: "TSP-1002",
313
+ pluginRegisterAfterLoad: "TSP-1003",
314
+ offscreenCanvasUnsupported: "TSP-1101",
315
+ offscreenCanvasTransferFailed: "TSP-1102",
316
+ hdrEnableInvalid: "TSP-1201",
317
+ hdrModeInvalid: "TSP-1202",
318
+ hdrPeakNitsInvalid: "TSP-1203",
319
+ };
320
+
321
+ const messages = {
322
+ [ErrorCodes$1.engineVersionMismatch]: "The tsParticles version is different from the loaded plugins version. Engine version: {0}. Plugin version: {1}",
323
+ [ErrorCodes$1.particlePositionNotFound]: "a valid position cannot be found for particle",
324
+ [ErrorCodes$1.pluginRegisterAfterLoad]: "Register plugins can only be done before calling tsParticles.load()",
325
+ [ErrorCodes$1.offscreenCanvasUnsupported]: "OffscreenCanvas is required but not supported by this browser",
326
+ [ErrorCodes$1.offscreenCanvasTransferFailed]: "OffscreenCanvas transfer failed",
327
+ [ErrorCodes$1.hdrEnableInvalid]: 'Invalid HDR "enable" value: expected a boolean, got "{0}"',
328
+ [ErrorCodes$1.hdrModeInvalid]: 'Invalid HDR "mode" value: expected one of {0}, got "{1}"',
329
+ [ErrorCodes$1.hdrPeakNitsInvalid]: 'Invalid HDR "peakNits" value: expected a positive number, got "{0}"',
330
+ };
331
+
332
+ let registeredMessages;
333
+ const ensureRegisteredMessages = () => {
334
+ registeredMessages ??= new Map(Object.entries(messages));
335
+ return registeredMessages;
336
+ }, toStringValue$1 = (value) => String(value), format = (template, args) => {
337
+ return template.replace(/\{(\d+)\}/g, (match, index) => {
338
+ const arg = args[Number(index)];
339
+ return arg === undefined ? match : toStringValue$1(arg);
340
+ });
341
+ };
342
+ function addErrorMessages(extraMessages) {
343
+ if (typeof process !== "undefined" && process.env.NODE_ENV === "production") {
344
+ return;
345
+ }
346
+ const catalog = ensureRegisteredMessages();
347
+ for (const [code, message] of Object.entries(extraMessages)) {
348
+ if (message !== undefined) {
349
+ catalog.set(code, message);
350
+ }
351
+ }
352
+ }
353
+ function getErrorMessage(code, ...args) {
354
+ if (typeof process !== "undefined" && process.env.NODE_ENV === "production") {
355
+ return `[tsParticles Error ${code}] https://particles.js.org/errors/#${code}`;
356
+ }
357
+ const template = ensureRegisteredMessages().get(code) ?? `Unknown error code ${code}`;
358
+ return format(template, args);
278
359
  }
279
360
 
280
361
  var OutModeDirection;
@@ -291,7 +372,6 @@
291
372
  PixelMode["percent"] = "percent";
292
373
  })(PixelMode || (PixelMode = {}));
293
374
 
294
- const minRadius = 0;
295
375
  function isForbiddenKey(key) {
296
376
  return key === "__proto__" || key === "constructor" || key === "prototype";
297
377
  }
@@ -487,22 +567,84 @@
487
567
  element.removeEventListener(event, handler, removeOptions);
488
568
  }
489
569
  }
490
- async function getItemsFromInitializer(container, map, initializers, force = false) {
491
- let res = map.get(container);
492
- if (!res || force) {
493
- res = await Promise.all([...initializers.values()].map(t => t(container)));
494
- map.set(container, res);
570
+ async function getItemsFromInitializer(container, initializers) {
571
+ return await Promise.all([...initializers.values()].map(t => t(container)));
572
+ }
573
+ async function getItemMapFromInitializer(container, initializers) {
574
+ const entries = await Promise.all([...initializers.entries()].map(([key, initializer]) => initializer(container).then(item => [key, item])));
575
+ return new Map(entries);
576
+ }
577
+ async function getDataFromUrl(data) {
578
+ const url = itemFromSingleOrMultiple(data.url, data.index);
579
+ if (!url) {
580
+ return data.fallback;
495
581
  }
496
- return res;
582
+ try {
583
+ const response = await fetch(url);
584
+ if (response.ok) {
585
+ const current = (await response.json());
586
+ if (isSourceOptionsValue(current)) {
587
+ return current;
588
+ }
589
+ getLogger().error("invalid configuration data while retrieving config file");
590
+ }
591
+ else {
592
+ getLogger().error(`${response.status.toString()} while retrieving config file`);
593
+ }
594
+ }
595
+ catch (error) {
596
+ getLogger().error(`error while retrieving config file: ${error}`);
597
+ }
598
+ return data.fallback;
497
599
  }
498
- async function getItemMapFromInitializer(container, map, initializers, force = false) {
499
- let res = map.get(container);
500
- if (!res || force) {
501
- const entries = await Promise.all([...initializers.entries()].map(([key, initializer]) => initializer(container).then(item => [key, item])));
502
- res = new Map(entries);
503
- map.set(container, res);
600
+ function isSourceOptionsValue(value) {
601
+ if (isArray(value)) {
602
+ return value.every((entry) => isObject(entry) && !isArray(entry));
504
603
  }
505
- return res;
604
+ return isObject(value) && !isArray(value);
605
+ }
606
+ function getCanvasFromContainer(domContainer) {
607
+ let canvasEl;
608
+ const documentSafe = safeDocument(), isCanvas = domContainer instanceof HTMLCanvasElement || domContainer.tagName.toLowerCase() === canvasTag;
609
+ if (isCanvas) {
610
+ canvasEl = domContainer;
611
+ canvasEl.dataset[generatedAttribute] ??= generatedFalse;
612
+ if (canvasEl.dataset[generatedAttribute] === generatedTrue) {
613
+ canvasEl.style.width ||= fullPercent;
614
+ canvasEl.style.height ||= fullPercent;
615
+ canvasEl.style.pointerEvents = "none";
616
+ canvasEl.style.setProperty("pointer-events", "none");
617
+ }
618
+ }
619
+ else {
620
+ const existingCanvases = domContainer.getElementsByTagName(canvasTag), foundCanvas = existingCanvases.item(canvasFirstIndex);
621
+ if (foundCanvas) {
622
+ canvasEl = foundCanvas;
623
+ canvasEl.dataset[generatedAttribute] = generatedFalse;
624
+ }
625
+ else {
626
+ canvasEl = documentSafe.createElement(canvasTag);
627
+ canvasEl.dataset[generatedAttribute] = generatedTrue;
628
+ domContainer.appendChild(canvasEl);
629
+ }
630
+ canvasEl.style.width ||= fullPercent;
631
+ canvasEl.style.height ||= fullPercent;
632
+ canvasEl.style.pointerEvents = "none";
633
+ canvasEl.style.setProperty("pointer-events", "none");
634
+ }
635
+ return canvasEl;
636
+ }
637
+ function getDomContainer(id, source) {
638
+ const documentSafe = safeDocument();
639
+ let domContainer = source ?? documentSafe.getElementById(id);
640
+ if (domContainer) {
641
+ return domContainer;
642
+ }
643
+ domContainer = documentSafe.createElement("canvas");
644
+ domContainer.id = id;
645
+ domContainer.dataset[generatedAttribute] = generatedTrue;
646
+ documentSafe.body.append(domContainer);
647
+ return domContainer;
506
648
  }
507
649
 
508
650
  class EventDispatcher {
@@ -512,12 +654,8 @@
512
654
  }
513
655
  addEventListener(type, listener) {
514
656
  this.removeEventListener(type, listener);
515
- let arr = this.#listeners.get(type);
516
- if (!arr) {
517
- arr = [];
518
- this.#listeners.set(type, arr);
519
- }
520
- arr.push(listener);
657
+ const arr = this.#listeners.get(type);
658
+ this.#listeners.set(type, arr ? [...arr, listener] : [listener]);
521
659
  }
522
660
  dispatchEvent(type, args) {
523
661
  const listeners = this.#listeners.get(type);
@@ -549,7 +687,7 @@
549
687
  this.#listeners.delete(type);
550
688
  }
551
689
  else {
552
- arr.splice(idx, deleteCount);
690
+ this.#listeners.set(type, [...arr.slice(minIndex, idx), ...arr.slice(idx + deleteCount)]);
553
691
  }
554
692
  }
555
693
  }
@@ -573,7 +711,6 @@
573
711
  class PluginManager {
574
712
  colorManagers = new Map();
575
713
  easingFunctions = new Map();
576
- effectDrawers = new Map();
577
714
  initializers = {
578
715
  effects: new Map(),
579
716
  shapes: new Map(),
@@ -582,8 +719,6 @@
582
719
  palettes = new Map();
583
720
  plugins = [];
584
721
  presets = new Map();
585
- shapeDrawers = new Map();
586
- updaters = new Map();
587
722
  #allLoadersSet = new Set();
588
723
  #configs = new Map();
589
724
  #engine;
@@ -601,57 +736,79 @@
601
736
  }
602
737
  return res;
603
738
  }
739
+ get initialized() {
740
+ return this.#initialized;
741
+ }
604
742
  addColorManager(name, manager) {
743
+ if (this.#initialized) {
744
+ return;
745
+ }
605
746
  this.colorManagers.set(name, manager);
606
747
  }
607
748
  addConfig(config) {
749
+ if (this.#initialized) {
750
+ return;
751
+ }
608
752
  const key = config.key ?? config.name ?? "default";
609
753
  this.#configs.set(key, config);
610
754
  this.#engine.dispatchEvent(EventType.configAdded, { data: { name: key, config } });
611
755
  }
612
756
  addEasing(name, easing) {
757
+ if (this.#initialized) {
758
+ return;
759
+ }
613
760
  if (this.easingFunctions.get(name)) {
614
761
  return;
615
762
  }
616
763
  this.easingFunctions.set(name, easing);
617
764
  }
618
765
  addEffect(effect, drawer) {
766
+ if (this.#initialized) {
767
+ return;
768
+ }
619
769
  this.initializers.effects.set(effect, drawer);
620
770
  }
621
771
  addPalette(name, palette) {
772
+ if (this.#initialized) {
773
+ return;
774
+ }
622
775
  this.palettes.set(name, palette);
623
776
  }
624
777
  addParticleUpdater(name, updaterInitializer) {
778
+ if (this.#initialized) {
779
+ return;
780
+ }
625
781
  this.initializers.updaters.set(name, updaterInitializer);
626
782
  }
627
783
  addPlugin(plugin) {
784
+ if (this.#initialized) {
785
+ return;
786
+ }
628
787
  if (this.getPlugin(plugin.id)) {
629
788
  return;
630
789
  }
631
790
  this.plugins.push(plugin);
632
791
  }
633
792
  addPreset(preset, options, override = false) {
793
+ if (this.#initialized) {
794
+ return;
795
+ }
634
796
  if (!(override || !this.getPreset(preset))) {
635
797
  return;
636
798
  }
637
799
  this.presets.set(preset, options);
638
800
  }
639
801
  addShape(shapes, drawer) {
802
+ if (this.#initialized) {
803
+ return;
804
+ }
640
805
  for (const shape of shapes) {
641
806
  this.initializers.shapes.set(shape, drawer);
642
807
  }
643
808
  }
644
- clearPlugins(container) {
645
- this.effectDrawers.delete(container);
646
- this.shapeDrawers.delete(container);
647
- this.updaters.delete(container);
648
- }
649
809
  getEasing(name) {
650
810
  return this.easingFunctions.get(name) ?? ((value) => value);
651
811
  }
652
- getEffectDrawers(container, force = false) {
653
- return getItemMapFromInitializer(container, this.effectDrawers, this.initializers.effects, force);
654
- }
655
812
  getPalette(name) {
656
813
  return this.palettes.get(name);
657
814
  }
@@ -661,12 +818,6 @@
661
818
  getPreset(preset) {
662
819
  return this.presets.get(preset);
663
820
  }
664
- async getShapeDrawers(container, force = false) {
665
- return getItemMapFromInitializer(container, this.shapeDrawers, this.initializers.shapes, force);
666
- }
667
- async getUpdaters(container, force = false) {
668
- return getItemsFromInitializer(container, this.updaters, this.initializers.updaters, force);
669
- }
670
821
  async init() {
671
822
  if (this.#initialized || this.#isRunningLoaders) {
672
823
  return;
@@ -685,16 +836,9 @@
685
836
  this.#initialized = true;
686
837
  }
687
838
  }
688
- loadParticlesOptions(container, options, ...sourceOptions) {
689
- const updaters = this.updaters.get(container);
690
- if (!updaters) {
691
- return;
692
- }
693
- updaters.forEach(updater => updater.loadOptions?.(options, ...sourceOptions));
694
- }
695
839
  async register(...loaders) {
696
840
  if (this.#initialized) {
697
- throw new Error("Register plugins can only be done before calling tsParticles.load()");
841
+ throw new Error(getErrorMessage(ErrorCodes$1.pluginRegisterAfterLoad));
698
842
  }
699
843
  for (const loader of loaders) {
700
844
  if (this.#isRunningLoaders) {
@@ -706,88 +850,15 @@
706
850
  }
707
851
  }
708
852
  async #runLoader(loader, executed, allLoaders) {
709
- if (executed.has(loader))
853
+ if (executed.has(loader)) {
710
854
  return;
855
+ }
711
856
  executed.add(loader);
712
857
  allLoaders.add(loader);
713
858
  await loader(this.#engine);
714
859
  }
715
860
  }
716
861
 
717
- const errorPrefix = "tsParticles - Error";
718
- const wrap = (fn) => (...args) => {
719
- fn(...args);
720
- }, _logger = {
721
- debug: wrap(console.debug),
722
- error: (message, ...optionalParams) => {
723
- console.error(`${errorPrefix} - ${message}`, ...optionalParams);
724
- },
725
- info: wrap(console.info),
726
- log: wrap(console.log),
727
- trace: wrap(console.trace),
728
- verbose: wrap(console.log),
729
- warning: wrap(console.warn),
730
- };
731
- function getLogger() {
732
- return _logger;
733
- }
734
-
735
- const fullPercent = "100%";
736
- async function getDataFromUrl(data) {
737
- const url = itemFromSingleOrMultiple(data.url, data.index);
738
- if (!url) {
739
- return data.fallback;
740
- }
741
- const response = await fetch(url);
742
- if (response.ok) {
743
- return (await response.json());
744
- }
745
- getLogger().error(`${response.status.toString()} while retrieving config file`);
746
- return data.fallback;
747
- }
748
- const getCanvasFromContainer = (domContainer) => {
749
- const documentSafe = safeDocument();
750
- let canvasEl;
751
- const isCanvas = domContainer instanceof HTMLCanvasElement || domContainer.tagName.toLowerCase() === canvasTag;
752
- if (isCanvas) {
753
- canvasEl = domContainer;
754
- canvasEl.dataset[generatedAttribute] ??= generatedFalse;
755
- if (canvasEl.dataset[generatedAttribute] === generatedTrue) {
756
- canvasEl.style.width ||= fullPercent;
757
- canvasEl.style.height ||= fullPercent;
758
- canvasEl.style.pointerEvents = "none";
759
- canvasEl.style.setProperty("pointer-events", "none");
760
- }
761
- }
762
- else {
763
- const existingCanvases = domContainer.getElementsByTagName(canvasTag), foundCanvas = existingCanvases.item(canvasFirstIndex);
764
- if (foundCanvas) {
765
- canvasEl = foundCanvas;
766
- canvasEl.dataset[generatedAttribute] = generatedFalse;
767
- }
768
- else {
769
- canvasEl = documentSafe.createElement(canvasTag);
770
- canvasEl.dataset[generatedAttribute] = generatedTrue;
771
- domContainer.appendChild(canvasEl);
772
- }
773
- canvasEl.style.width ||= fullPercent;
774
- canvasEl.style.height ||= fullPercent;
775
- canvasEl.style.pointerEvents = "none";
776
- canvasEl.style.setProperty("pointer-events", "none");
777
- }
778
- return canvasEl;
779
- }, getDomContainer = (id, source) => {
780
- const documentSafe = safeDocument();
781
- let domContainer = source ?? documentSafe.getElementById(id);
782
- if (domContainer) {
783
- return domContainer;
784
- }
785
- domContainer = documentSafe.createElement("canvas");
786
- domContainer.id = id;
787
- domContainer.dataset[generatedAttribute] = generatedTrue;
788
- documentSafe.body.append(domContainer);
789
- return domContainer;
790
- };
791
862
  class Engine {
792
863
  pluginManager = new PluginManager(this);
793
864
  #domArray = [];
@@ -797,7 +868,7 @@
797
868
  return this.#domArray;
798
869
  }
799
870
  get version() {
800
- return "4.4.0";
871
+ return "4.5.1";
801
872
  }
802
873
  addEventListener(type, listener) {
803
874
  this.#eventDispatcher.addEventListener(type, listener);
@@ -806,7 +877,7 @@
806
877
  if (this.version === pluginVersion) {
807
878
  return;
808
879
  }
809
- throw new Error(`The tsParticles version is different from the loaded plugins version. Engine version: ${this.version}. Plugin version: ${pluginVersion}`);
880
+ throw new Error(getErrorMessage(ErrorCodes$1.engineVersionMismatch, this.version, pluginVersion));
810
881
  }
811
882
  dispatchEvent(type, args) {
812
883
  this.#eventDispatcher.dispatchEvent(type, args);
@@ -1055,20 +1126,6 @@
1055
1126
  DrawLayer[DrawLayer["Foreground"] = 7] = "Foreground";
1056
1127
  })(DrawLayer || (DrawLayer = {}));
1057
1128
 
1058
- class OptionLoader {
1059
- load(data) {
1060
- if (isNull(data)) {
1061
- return;
1062
- }
1063
- this.doLoad(data);
1064
- }
1065
- }
1066
- function loadOptions(options, ...sourceOptionsArr) {
1067
- for (const sourceOptions of sourceOptionsArr) {
1068
- options.load(sourceOptions);
1069
- }
1070
- }
1071
-
1072
1129
  function loadProperty(obj, key, value) {
1073
1130
  if (value !== undefined) {
1074
1131
  obj[key] = value;
@@ -1100,6 +1157,20 @@
1100
1157
  }
1101
1158
  }
1102
1159
 
1160
+ class OptionLoader {
1161
+ load(data) {
1162
+ if (isNull(data)) {
1163
+ return;
1164
+ }
1165
+ this.doLoad(data);
1166
+ }
1167
+ }
1168
+ function loadOptions(options, ...sourceOptionsArr) {
1169
+ for (const sourceOptions of sourceOptionsArr) {
1170
+ options.load(sourceOptions);
1171
+ }
1172
+ }
1173
+
1103
1174
  class AnimationOptions extends OptionLoader {
1104
1175
  count = 0;
1105
1176
  decay = 0;
@@ -1250,15 +1321,14 @@
1250
1321
  peakNits = defaultPeakNits;
1251
1322
  doLoad(data) {
1252
1323
  if (data.enable !== undefined && !isBoolean(data.enable)) {
1253
- throw new Error(`Invalid HDR "enable" value: expected a boolean, got "${String(data.enable)}"`);
1324
+ throw new Error(getErrorMessage(ErrorCodes$1.hdrEnableInvalid, String(data.enable)));
1254
1325
  }
1255
- if (data.mode !== undefined &&
1256
- (typeof data.mode !== "string" || !Object.values(HdrMode).includes(data.mode))) {
1257
- throw new Error(`Invalid HDR "mode" value: expected one of ${Object.values(HdrMode).join(", ")}, got "${toStringValue(data.mode)}"`);
1326
+ if (data.mode !== undefined && !isEnumValue(HdrMode, data.mode)) {
1327
+ throw new Error(getErrorMessage(ErrorCodes$1.hdrModeInvalid, Object.values(HdrMode).join(", "), toStringValue(data.mode)));
1258
1328
  }
1259
1329
  if (data.peakNits !== undefined &&
1260
1330
  (!isNumber(data.peakNits) || !Number.isFinite(data.peakNits) || data.peakNits <= minPeakNits)) {
1261
- throw new Error(`Invalid HDR "peakNits" value: expected a positive number, got "${String(data.peakNits)}"`);
1331
+ throw new Error(getErrorMessage(ErrorCodes$1.hdrPeakNitsInvalid, String(data.peakNits)));
1262
1332
  }
1263
1333
  loadProperty(this, "enable", data.enable);
1264
1334
  loadProperty(this, "mode", data.mode);
@@ -1636,12 +1706,10 @@
1636
1706
  plugin.loadParticlesOptions(this.#container, this, data);
1637
1707
  }
1638
1708
  }
1639
- const updaters = this.#pluginManager.updaters.get(this.#container);
1640
- if (updaters) {
1641
- for (const updater of updaters) {
1642
- if (updater.loadOptions) {
1643
- updater.loadOptions(this, data);
1644
- }
1709
+ const updaters = this.#container.particleUpdaters;
1710
+ for (const updater of updaters) {
1711
+ if (updater.loadOptions) {
1712
+ updater.loadOptions(this, data);
1645
1713
  }
1646
1714
  }
1647
1715
  }
@@ -1974,9 +2042,9 @@
1974
2042
  const grayscaleValue = Math.round(lNormalized * rgbMax);
1975
2043
  return { r: grayscaleValue, g: grayscaleValue, b: grayscaleValue };
1976
2044
  }
1977
- const temp1 = lNormalized < half
2045
+ const temp2 = lNormalized < half
1978
2046
  ? lNormalized * (sNormalizedOffset + sNormalized)
1979
- : lNormalized + sNormalized - lNormalized * sNormalized, temp2 = double * lNormalized - temp1, phaseThird = phaseNumerator / triple, red = Math.min(rgbMax, rgbMax * hslChannel(temp2, temp1, hNormalized + phaseThird)), green = Math.min(rgbMax, rgbMax * hslChannel(temp2, temp1, hNormalized)), blue = Math.min(rgbMax, rgbMax * hslChannel(temp2, temp1, hNormalized - phaseThird));
2047
+ : lNormalized + sNormalized - lNormalized * sNormalized, temp1 = double * lNormalized - temp2, phaseThird = phaseNumerator / triple, red = Math.min(rgbMax, rgbMax * hslChannel(temp1, temp2, hNormalized + phaseThird)), green = Math.min(rgbMax, rgbMax * hslChannel(temp1, temp2, hNormalized)), blue = Math.min(rgbMax, rgbMax * hslChannel(temp1, temp2, hNormalized - phaseThird));
1980
2048
  return { r: Math.round(red), g: Math.round(green), b: Math.round(blue) };
1981
2049
  }
1982
2050
  function hslToRgbFloat(hsl) {
@@ -1985,9 +2053,9 @@
1985
2053
  const grayscaleValue = lNormalized * rgbMax;
1986
2054
  return { r: grayscaleValue, g: grayscaleValue, b: grayscaleValue };
1987
2055
  }
1988
- const temp1 = lNormalized < half
2056
+ const temp2 = lNormalized < half
1989
2057
  ? lNormalized * (sNormalizedOffset + sNormalized)
1990
- : lNormalized + sNormalized - lNormalized * sNormalized, temp2 = double * lNormalized - temp1, phaseThird = phaseNumerator / triple, red = Math.min(rgbMax, rgbMax * hslChannel(temp2, temp1, hNormalized + phaseThird)), green = Math.min(rgbMax, rgbMax * hslChannel(temp2, temp1, hNormalized)), blue = Math.min(rgbMax, rgbMax * hslChannel(temp2, temp1, hNormalized - phaseThird));
2058
+ : lNormalized + sNormalized - lNormalized * sNormalized, temp1 = double * lNormalized - temp2, phaseThird = phaseNumerator / triple, red = Math.min(rgbMax, rgbMax * hslChannel(temp1, temp2, hNormalized + phaseThird)), green = Math.min(rgbMax, rgbMax * hslChannel(temp1, temp2, hNormalized)), blue = Math.min(rgbMax, rgbMax * hslChannel(temp1, temp2, hNormalized - phaseThird));
1991
2059
  return { r: red, g: green, b: blue };
1992
2060
  }
1993
2061
  function hslaToRgba(hsla) {
@@ -2201,7 +2269,7 @@
2201
2269
  }
2202
2270
 
2203
2271
  async function loadBlendPlugin(engine) {
2204
- engine.checkVersion("4.4.0");
2272
+ engine.checkVersion("4.5.1");
2205
2273
  await engine.pluginManager.register(e => {
2206
2274
  e.pluginManager.addPlugin(new BlendPlugin());
2207
2275
  });
@@ -2238,7 +2306,7 @@
2238
2306
  }
2239
2307
 
2240
2308
  async function loadCircleShape(engine) {
2241
- engine.checkVersion("4.4.0");
2309
+ engine.checkVersion("4.5.1");
2242
2310
  await engine.pluginManager.register(e => {
2243
2311
  e.pluginManager.addShape(["circle"], () => {
2244
2312
  return Promise.resolve(new CircleDrawer());
@@ -2253,7 +2321,7 @@
2253
2321
  RgbIndexes[RgbIndexes["b"] = 3] = "b";
2254
2322
  RgbIndexes[RgbIndexes["a"] = 4] = "a";
2255
2323
  })(RgbIndexes$1 || (RgbIndexes$1 = {}));
2256
- const shorthandHexRegex = /^#?([a-f\d])([a-f\d])([a-f\d])([a-f\d])?$/i, hexRegex = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})?$/i, hexRadix = 16, defaultAlpha = 1, alphaFactor = 0xff;
2324
+ const shorthandHexRegex = /^#?([a-f\d])([a-f\d])([a-f\d])([a-f\d])?$/i, hexRegex = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})?$/i, hexRadix = 16, alphaFactor = 0xff;
2257
2325
  class HexColorManager {
2258
2326
  accepts(input) {
2259
2327
  return input.startsWith("#");
@@ -2286,7 +2354,7 @@
2286
2354
  }
2287
2355
 
2288
2356
  async function loadHexColorPlugin(engine) {
2289
- engine.checkVersion("4.4.0");
2357
+ engine.checkVersion("4.5.1");
2290
2358
  await engine.pluginManager.register(e => {
2291
2359
  e.pluginManager.addColorManager("hex", new HexColorManager());
2292
2360
  });
@@ -2326,7 +2394,7 @@
2326
2394
  if (!this.accepts(input)) {
2327
2395
  return;
2328
2396
  }
2329
- const result = hslRegex.exec(input), minLength = 4, defaultAlpha = 1, radix = 10;
2397
+ const result = hslRegex.exec(input), minLength = 4, radix = 10;
2330
2398
  return result
2331
2399
  ? hslaToRgba({
2332
2400
  a: result.length > minLength ? parseAlpha(result[HslIndexes.a]) : defaultAlpha,
@@ -2339,12 +2407,20 @@
2339
2407
  }
2340
2408
 
2341
2409
  async function loadHslColorPlugin(engine) {
2342
- engine.checkVersion("4.4.0");
2410
+ engine.checkVersion("4.5.1");
2343
2411
  await engine.pluginManager.register(e => {
2344
2412
  e.pluginManager.addColorManager("hsl", new HslColorManager());
2345
2413
  });
2346
2414
  }
2347
2415
 
2416
+ const ErrorCodes = {
2417
+ baseMoverNotLoaded: "TSP-3203",
2418
+ };
2419
+
2420
+ const ErrorMessages = {
2421
+ [ErrorCodes.baseMoverNotLoaded]: "tsParticles Base Mover is not loaded",
2422
+ };
2423
+
2348
2424
  class MovePlugin {
2349
2425
  id = "move";
2350
2426
  #pluginManager;
@@ -2363,20 +2439,20 @@
2363
2439
  }
2364
2440
 
2365
2441
  async function loadMovePlugin(engine) {
2366
- engine.checkVersion("4.4.0");
2442
+ engine.checkVersion("4.5.1");
2443
+ if (typeof process !== "undefined" && process.env.NODE_ENV !== "production") {
2444
+ addErrorMessages(ErrorMessages);
2445
+ }
2367
2446
  await engine.pluginManager.register(e => {
2368
2447
  const moveEngine = e, movePluginManager = moveEngine.pluginManager;
2369
2448
  movePluginManager.initializers.pathGenerators ??= new Map();
2370
- movePluginManager.pathGenerators ??= new Map();
2371
2449
  movePluginManager.addPathGenerator = (name, generator) => {
2450
+ if (movePluginManager.initialized) {
2451
+ return;
2452
+ }
2372
2453
  movePluginManager.initializers.pathGenerators ??= new Map();
2373
2454
  movePluginManager.initializers.pathGenerators.set(name, generator);
2374
2455
  };
2375
- movePluginManager.getPathGenerators = async (container, force = false) => {
2376
- movePluginManager.initializers.pathGenerators ??= new Map();
2377
- movePluginManager.pathGenerators ??= new Map();
2378
- return getItemMapFromInitializer(container, movePluginManager.pathGenerators, movePluginManager.initializers.pathGenerators, force);
2379
- };
2380
2456
  e.pluginManager.addPlugin(new MovePlugin(e.pluginManager));
2381
2457
  });
2382
2458
  }
@@ -2573,7 +2649,7 @@
2573
2649
  }
2574
2650
 
2575
2651
  async function loadOpacityUpdater(engine) {
2576
- engine.checkVersion("4.4.0");
2652
+ engine.checkVersion("4.5.1");
2577
2653
  await engine.pluginManager.register(e => {
2578
2654
  e.pluginManager.addParticleUpdater("opacity", container => {
2579
2655
  return Promise.resolve(new OpacityUpdater(container));
@@ -2582,70 +2658,60 @@
2582
2658
  }
2583
2659
 
2584
2660
  const boundsMin = 0;
2585
- function bounceHorizontal(data) {
2586
- if ((data.outMode !== OutMode.bounce && data.outMode !== OutMode.split) ||
2587
- (data.direction !== OutModeDirection.left && data.direction !== OutModeDirection.right)) {
2588
- return;
2589
- }
2590
- if (data.bounds.right < boundsMin && data.direction === OutModeDirection.left) {
2591
- data.particle.position.x = data.size + data.offset.x;
2592
- }
2593
- else if (data.bounds.left > data.canvasSize.width && data.direction === OutModeDirection.right) {
2594
- data.particle.position.x = data.canvasSize.width - data.size - data.offset.x;
2595
- }
2596
- const velocity = data.particle.velocity.x;
2597
- let bounced = false;
2598
- if (data.outOfCanvas &&
2599
- ((data.direction === OutModeDirection.right && velocity > minVelocity) ||
2600
- (data.direction === OutModeDirection.left && velocity < minVelocity))) {
2601
- const newVelocity = getRangeValue(data.particle.options.bounce.horizontal.value);
2602
- data.particle.velocity.x *= -newVelocity;
2603
- bounced = true;
2604
- }
2605
- if (!bounced) {
2606
- return;
2607
- }
2608
- const minPos = data.offset.x + data.size;
2609
- if (data.outOfCanvas && data.direction === OutModeDirection.right) {
2610
- data.particle.position.x = data.canvasSize.width - minPos;
2611
- }
2612
- else if (data.outOfCanvas && data.direction === OutModeDirection.left) {
2613
- data.particle.position.x = minPos;
2614
- }
2615
- if (data.outMode === OutMode.split) {
2616
- data.particle.destroy();
2617
- }
2618
- }
2619
- function bounceVertical(data) {
2620
- if ((data.outMode !== OutMode.bounce && data.outMode !== OutMode.split) ||
2621
- (data.direction !== OutModeDirection.bottom && data.direction !== OutModeDirection.top)) {
2661
+ const bounceAxisConfigs = {
2662
+ [OutModeDirection.left]: {
2663
+ axis: "x",
2664
+ canvas: "width",
2665
+ bounce: "horizontal",
2666
+ negativeEdge: "right",
2667
+ positiveEdge: "left",
2668
+ negative: true,
2669
+ },
2670
+ [OutModeDirection.right]: {
2671
+ axis: "x",
2672
+ canvas: "width",
2673
+ bounce: "horizontal",
2674
+ negativeEdge: "right",
2675
+ positiveEdge: "left",
2676
+ negative: false,
2677
+ },
2678
+ [OutModeDirection.top]: {
2679
+ axis: "y",
2680
+ canvas: "height",
2681
+ bounce: "vertical",
2682
+ negativeEdge: "bottom",
2683
+ positiveEdge: "top",
2684
+ negative: true,
2685
+ },
2686
+ [OutModeDirection.bottom]: {
2687
+ axis: "y",
2688
+ canvas: "height",
2689
+ bounce: "vertical",
2690
+ negativeEdge: "bottom",
2691
+ positiveEdge: "top",
2692
+ negative: false,
2693
+ },
2694
+ };
2695
+ function bounce(data) {
2696
+ if ((data.outMode !== OutMode.bounce && data.outMode !== OutMode.split) || !(data.direction in bounceAxisConfigs)) {
2622
2697
  return;
2623
2698
  }
2624
- if (data.bounds.bottom < boundsMin && data.direction === OutModeDirection.top) {
2625
- data.particle.position.y = data.size + data.offset.y;
2699
+ const config = bounceAxisConfigs[data.direction], bounds = data.bounds, canvasDim = data.canvasSize[config.canvas], position = data.particle.position, velocity = data.particle.velocity[config.axis];
2700
+ if (config.negative && bounds[config.negativeEdge] < boundsMin) {
2701
+ position[config.axis] = data.size + data.offset[config.axis];
2626
2702
  }
2627
- else if (data.bounds.top > data.canvasSize.height && data.direction === OutModeDirection.bottom) {
2628
- data.particle.position.y = data.canvasSize.height - data.size - data.offset.y;
2703
+ else if (!config.negative && bounds[config.positiveEdge] > canvasDim) {
2704
+ position[config.axis] = canvasDim - data.size - data.offset[config.axis];
2629
2705
  }
2630
- const velocity = data.particle.velocity.y;
2631
- let bounced = false;
2632
2706
  if (data.outOfCanvas &&
2633
- ((data.direction === OutModeDirection.bottom && velocity > minVelocity) ||
2634
- (data.direction === OutModeDirection.top && velocity < minVelocity))) {
2635
- const newVelocity = getRangeValue(data.particle.options.bounce.vertical.value);
2636
- data.particle.velocity.y *= -newVelocity;
2637
- bounced = true;
2707
+ ((config.negative && velocity < minVelocity) || (!config.negative && velocity > minVelocity))) {
2708
+ data.particle.velocity[config.axis] *= -getRangeValue(data.particle.options.bounce[config.bounce].value);
2638
2709
  }
2639
- if (!bounced) {
2710
+ else {
2640
2711
  return;
2641
2712
  }
2642
- const minPos = data.offset.y + data.size;
2643
- if (data.outOfCanvas && data.direction === OutModeDirection.bottom) {
2644
- data.particle.position.y = data.canvasSize.height - minPos;
2645
- }
2646
- else if (data.outOfCanvas && data.direction === OutModeDirection.top) {
2647
- data.particle.position.y = minPos;
2648
- }
2713
+ const minPos = data.offset[config.axis] + data.size;
2714
+ position[config.axis] = config.negative ? minPos : canvasDim - minPos;
2649
2715
  if (data.outMode === OutMode.split) {
2650
2716
  data.particle.destroy();
2651
2717
  }
@@ -2661,26 +2727,19 @@
2661
2727
  OutMode.bounce,
2662
2728
  OutMode.split,
2663
2729
  ];
2664
- this.#particleBouncePlugins = container.plugins.filter(p => p.particleBounce !== undefined);
2730
+ this.#particleBouncePlugins = container.plugins.filter(p => !!p.particleBounce);
2665
2731
  }
2666
2732
  update(particle, direction, delta, outMode) {
2667
2733
  if (!this.modes.includes(outMode)) {
2668
2734
  return;
2669
2735
  }
2670
- const container = this.#container;
2671
- let handled = false;
2672
2736
  for (const plugin of this.#particleBouncePlugins) {
2673
- handled = plugin.particleBounce?.(particle, delta, direction) ?? false;
2674
- if (handled) {
2675
- break;
2737
+ if (plugin.particleBounce?.(particle, delta, direction)) {
2738
+ return;
2676
2739
  }
2677
2740
  }
2678
- if (handled) {
2679
- return;
2680
- }
2681
- const pos = particle.getPosition(), offset = particle.offset, size = particle.getRadius(), bounds = calculateBounds(pos, size), canvasSize = container.canvas.size, outOfCanvas = !particle.isInsideCanvasForOutMode(outMode, direction);
2682
- bounceHorizontal({ particle, outMode, direction, bounds, canvasSize, offset, outOfCanvas, size });
2683
- bounceVertical({ particle, outMode, direction, bounds, canvasSize, offset, outOfCanvas, size });
2741
+ const pos = particle.getPosition(), offset = particle.offset, size = particle.getRadius(), bounds = calculateBounds(pos, size), canvasSize = this.#container.canvas.size, outOfCanvas = !particle.isInsideCanvasForOutMode(outMode, direction);
2742
+ bounce({ particle, outMode, direction, bounds, canvasSize, offset, outOfCanvas, size });
2684
2743
  }
2685
2744
  }
2686
2745
 
@@ -2769,108 +2828,109 @@
2769
2828
  return;
2770
2829
  }
2771
2830
  const container = this.#container;
2772
- switch (particle.outType) {
2773
- case ParticleOutType.inside: {
2774
- const { x: vx, y: vy } = particle.velocity;
2775
- updateVector.setTo(originPoint);
2776
- updateVector.length = particle.moveCenter.radius;
2777
- updateVector.angle = particle.velocity.angle + Math.PI;
2778
- updateVector.addTo(particle.moveCenter);
2779
- const { dx, dy } = getDistances(particle.position, updateVector);
2780
- if ((vx <= minVelocity && dx >= minDistance) ||
2781
- (vy <= minVelocity && dy >= minDistance) ||
2782
- (vx >= minVelocity && dx <= minDistance) ||
2783
- (vy >= minVelocity && dy <= minDistance)) {
2784
- return;
2785
- }
2786
- particle.position.x = Math.floor(randomInRangeValue({
2787
- min: 0,
2788
- max: container.canvas.size.width,
2789
- }));
2790
- particle.position.y = Math.floor(randomInRangeValue({
2791
- min: 0,
2792
- max: container.canvas.size.height,
2793
- }));
2794
- const { dx: newDx, dy: newDy } = getDistances(particle.position, particle.moveCenter);
2795
- particle.direction = Math.atan2(-newDy, -newDx);
2796
- particle.velocity.angle = particle.direction;
2797
- particle.justWarped = true;
2798
- break;
2831
+ if (particle.outType === ParticleOutType.inside) {
2832
+ this.#applyOutModeInside(particle, container);
2833
+ }
2834
+ else {
2835
+ if (particle.isInsideCanvasForOutMode(outMode, direction)) {
2836
+ return;
2799
2837
  }
2800
- default: {
2801
- if (particle.isInsideCanvasForOutMode(outMode, direction)) {
2802
- return;
2803
- }
2804
- switch (particle.outType) {
2805
- case ParticleOutType.outside: {
2806
- particle.position.x =
2807
- Math.floor(randomInRangeValue({
2808
- min: -particle.moveCenter.radius,
2809
- max: particle.moveCenter.radius,
2810
- })) + particle.moveCenter.x;
2811
- particle.position.y =
2812
- Math.floor(randomInRangeValue({
2813
- min: -particle.moveCenter.radius,
2814
- max: particle.moveCenter.radius,
2815
- })) + particle.moveCenter.y;
2816
- const { dx, dy } = getDistances(particle.position, particle.moveCenter);
2817
- if (particle.moveCenter.radius) {
2818
- particle.direction = Math.atan2(dy, dx);
2819
- particle.velocity.angle = particle.direction;
2820
- }
2821
- particle.justWarped = true;
2822
- break;
2823
- }
2824
- case ParticleOutType.normal: {
2825
- const warp = particle.options.move.warp, canvasSize = container.canvas.size, newPos = {
2826
- bottom: canvasSize.height + particle.getRadius() + particle.offset.y,
2827
- left: -particle.getRadius() - particle.offset.x,
2828
- right: canvasSize.width + particle.getRadius() + particle.offset.x,
2829
- top: -particle.getRadius() - particle.offset.y,
2830
- }, sizeValue = particle.getRadius(), nextBounds = calculateBounds(particle.position, sizeValue);
2831
- if (direction === OutModeDirection.right && nextBounds.left > canvasSize.width + particle.offset.x) {
2832
- particle.position.x = newPos.left;
2833
- particle.initialPosition.x = particle.position.x;
2834
- if (!warp) {
2835
- particle.position.y = getRandom() * canvasSize.height;
2836
- particle.initialPosition.y = particle.position.y;
2837
- }
2838
- particle.justWarped = true;
2839
- }
2840
- else if (direction === OutModeDirection.left && nextBounds.right < -particle.offset.x) {
2841
- particle.position.x = newPos.right;
2842
- particle.initialPosition.x = particle.position.x;
2843
- if (!warp) {
2844
- particle.position.y = getRandom() * canvasSize.height;
2845
- particle.initialPosition.y = particle.position.y;
2846
- }
2847
- particle.justWarped = true;
2848
- }
2849
- if (direction === OutModeDirection.bottom && nextBounds.top > canvasSize.height + particle.offset.y) {
2850
- if (!warp) {
2851
- particle.position.x = getRandom() * canvasSize.width;
2852
- particle.initialPosition.x = particle.position.x;
2853
- }
2854
- particle.position.y = newPos.top;
2855
- particle.initialPosition.y = particle.position.y;
2856
- particle.justWarped = true;
2857
- }
2858
- else if (direction === OutModeDirection.top && nextBounds.bottom < -particle.offset.y) {
2859
- if (!warp) {
2860
- particle.position.x = getRandom() * canvasSize.width;
2861
- particle.initialPosition.x = particle.position.x;
2862
- }
2863
- particle.position.y = newPos.bottom;
2864
- particle.initialPosition.y = particle.position.y;
2865
- particle.justWarped = true;
2866
- }
2867
- break;
2868
- }
2869
- }
2870
- break;
2838
+ if (particle.outType === ParticleOutType.outside) {
2839
+ this.#applyParticleModeOutside(particle);
2840
+ }
2841
+ else {
2842
+ this.#applyOutModeNormal(particle, container, direction);
2871
2843
  }
2872
2844
  }
2873
2845
  }
2846
+ #applyOutModeInside(particle, container) {
2847
+ const { x: vx, y: vy } = particle.velocity;
2848
+ updateVector.setTo(originPoint);
2849
+ updateVector.length = particle.moveCenter.radius;
2850
+ updateVector.angle = particle.velocity.angle + Math.PI;
2851
+ updateVector.addTo(particle.moveCenter);
2852
+ const { dx, dy } = getDistances(particle.position, updateVector);
2853
+ if ((vx <= minVelocity && dx >= minDistance) ||
2854
+ (vy <= minVelocity && dy >= minDistance) ||
2855
+ (vx >= minVelocity && dx <= minDistance) ||
2856
+ (vy >= minVelocity && dy <= minDistance)) {
2857
+ return;
2858
+ }
2859
+ particle.position.x = Math.floor(randomInRangeValue({
2860
+ min: 0,
2861
+ max: container.canvas.size.width,
2862
+ }));
2863
+ particle.position.y = Math.floor(randomInRangeValue({
2864
+ min: 0,
2865
+ max: container.canvas.size.height,
2866
+ }));
2867
+ const { dx: newDx, dy: newDy } = getDistances(particle.position, particle.moveCenter);
2868
+ particle.direction = Math.atan2(-newDy, -newDx);
2869
+ particle.velocity.angle = particle.direction;
2870
+ particle.justWarped = true;
2871
+ }
2872
+ #applyOutModeNormal(particle, container, direction) {
2873
+ const warp = particle.options.move.warp, canvasSize = container.canvas.size, sizeValue = particle.getRadius(), newPos = {
2874
+ bottom: canvasSize.height + sizeValue + particle.offset.y,
2875
+ left: -sizeValue - particle.offset.x,
2876
+ right: canvasSize.width + sizeValue + particle.offset.x,
2877
+ top: -sizeValue - particle.offset.y,
2878
+ }, nextBounds = calculateBounds(particle.position, sizeValue);
2879
+ if (direction === OutModeDirection.right && nextBounds.left > canvasSize.width + particle.offset.x) {
2880
+ particle.position.x = newPos.left;
2881
+ particle.initialPosition.x = particle.position.x;
2882
+ if (!warp) {
2883
+ particle.position.y = getRandom() * canvasSize.height;
2884
+ particle.initialPosition.y = particle.position.y;
2885
+ }
2886
+ particle.justWarped = true;
2887
+ }
2888
+ else if (direction === OutModeDirection.left && nextBounds.right < -particle.offset.x) {
2889
+ particle.position.x = newPos.right;
2890
+ particle.initialPosition.x = particle.position.x;
2891
+ if (!warp) {
2892
+ particle.position.y = getRandom() * canvasSize.height;
2893
+ particle.initialPosition.y = particle.position.y;
2894
+ }
2895
+ particle.justWarped = true;
2896
+ }
2897
+ if (direction === OutModeDirection.bottom && nextBounds.top > canvasSize.height + particle.offset.y) {
2898
+ if (!warp) {
2899
+ particle.position.x = getRandom() * canvasSize.width;
2900
+ particle.initialPosition.x = particle.position.x;
2901
+ }
2902
+ particle.position.y = newPos.top;
2903
+ particle.initialPosition.y = particle.position.y;
2904
+ particle.justWarped = true;
2905
+ }
2906
+ else if (direction === OutModeDirection.top && nextBounds.bottom < -particle.offset.y) {
2907
+ if (!warp) {
2908
+ particle.position.x = getRandom() * canvasSize.width;
2909
+ particle.initialPosition.x = particle.position.x;
2910
+ }
2911
+ particle.position.y = newPos.bottom;
2912
+ particle.initialPosition.y = particle.position.y;
2913
+ particle.justWarped = true;
2914
+ }
2915
+ }
2916
+ #applyParticleModeOutside(particle) {
2917
+ particle.position.x =
2918
+ Math.floor(randomInRangeValue({
2919
+ min: -particle.moveCenter.radius,
2920
+ max: particle.moveCenter.radius,
2921
+ })) + particle.moveCenter.x;
2922
+ particle.position.y =
2923
+ Math.floor(randomInRangeValue({
2924
+ min: -particle.moveCenter.radius,
2925
+ max: particle.moveCenter.radius,
2926
+ })) + particle.moveCenter.y;
2927
+ const { dx, dy } = getDistances(particle.position, particle.moveCenter);
2928
+ if (particle.moveCenter.radius) {
2929
+ particle.direction = Math.atan2(dy, dx);
2930
+ particle.velocity.angle = particle.direction;
2931
+ }
2932
+ particle.justWarped = true;
2933
+ }
2874
2934
  }
2875
2935
 
2876
2936
  const checkOutMode = (outModes, outMode) => {
@@ -2918,7 +2978,7 @@
2918
2978
  }
2919
2979
 
2920
2980
  async function loadOutModesUpdater(engine) {
2921
- engine.checkVersion("4.4.0");
2981
+ engine.checkVersion("4.5.1");
2922
2982
  await engine.pluginManager.register(e => {
2923
2983
  e.pluginManager.addParticleUpdater("outModes", container => {
2924
2984
  return Promise.resolve(new OutOfCanvasUpdater(container));
@@ -2935,61 +2995,69 @@
2935
2995
  this.#pluginManager = pluginManager;
2936
2996
  }
2937
2997
  init(particle) {
2938
- const container = this.#container, options = particle.options, paint = itemFromSingleOrMultiple(options.paint, particle.id, options.reduceDuplicates), color = paint?.color, paintColor = color ?? undefined, fill = paint?.fill, stroke = paint?.stroke;
2939
- if (fill) {
2940
- const fillColor = AnimatableColor.create(paintColor === undefined ? undefined : AnimatableColor.create(undefined, paintColor), fill.color);
2941
- particle.fillEnabled = fill.enable;
2942
- particle.fillOpacity = getRangeValue(fill.opacity);
2943
- particle.fillAnimation = fillColor.animation;
2944
- const fillHslColor = rangeColorToHsl(this.#pluginManager, fillColor);
2945
- if (fillHslColor) {
2946
- particle.fillColor = getHslAnimationFromHsl(fillHslColor, particle.fillAnimation, container.retina.reduceFactor);
2947
- }
2998
+ const container = this.#container, options = particle.options, paint = itemFromSingleOrMultiple(options.paint, particle.id, options.reduceDuplicates);
2999
+ this.#initFill(paint, particle, container);
3000
+ this.#initStroke(paint, particle, container);
3001
+ }
3002
+ isEnabled(particle) {
3003
+ const { fillAnimation, fillColor, strokeAnimation, strokeColor } = particle, fillEnabled = !!fillAnimation &&
3004
+ ((fillColor?.h.value !== undefined && fillColor.h.enable) ||
3005
+ (fillColor?.s.value !== undefined && fillColor.s.enable) ||
3006
+ (fillColor?.l.value !== undefined && fillColor.l.enable)), strokeEnabled = !!strokeAnimation &&
3007
+ ((strokeColor?.h.value !== undefined && strokeColor.h.enable) ||
3008
+ (strokeColor?.s.value !== undefined && strokeColor.s.enable) ||
3009
+ (strokeColor?.l.value !== undefined && strokeColor.l.enable));
3010
+ return !particle.destroyed && !particle.spawning && (fillEnabled || strokeEnabled);
3011
+ }
3012
+ update(particle, delta) {
3013
+ if (!this.isEnabled(particle)) {
3014
+ return;
2948
3015
  }
2949
- else {
3016
+ updateColor(particle.fillColor, delta, this.#container.hdr);
3017
+ updateColor(particle.strokeColor, delta, this.#container.hdr);
3018
+ }
3019
+ #initFill(paint, particle, container) {
3020
+ const fill = paint?.fill, color = paint?.color, paintColor = color ?? undefined;
3021
+ if (!fill) {
2950
3022
  particle.fillEnabled = false;
2951
3023
  particle.fillAnimation = undefined;
2952
3024
  particle.fillColor = undefined;
2953
3025
  particle.fillOpacity = defaultOpacity;
3026
+ return;
2954
3027
  }
2955
- if (stroke) {
2956
- const strokeColor = AnimatableColor.create(paintColor === undefined ? undefined : AnimatableColor.create(undefined, paintColor), stroke.color);
2957
- particle.strokeWidth = getRangeValue(stroke.width) * container.retina.pixelRatio;
2958
- particle.strokeOpacity = getRangeValue(stroke.opacity ?? defaultOpacity);
2959
- particle.strokeAnimation = strokeColor.animation;
2960
- const strokeHslColor = rangeColorToHsl(this.#pluginManager, strokeColor) ?? particle.getFillColor();
2961
- if (strokeHslColor) {
2962
- particle.strokeColor = getHslAnimationFromHsl(strokeHslColor, particle.strokeAnimation, container.retina.reduceFactor);
2963
- }
3028
+ const fillColor = AnimatableColor.create(paintColor === undefined ? undefined : AnimatableColor.create(undefined, paintColor), fill.color);
3029
+ particle.fillEnabled = fill.enable;
3030
+ particle.fillOpacity = getRangeValue(fill.opacity);
3031
+ particle.fillAnimation = fillColor.animation;
3032
+ const fillHslColor = rangeColorToHsl(this.#pluginManager, fillColor);
3033
+ if (!fillHslColor) {
3034
+ return;
2964
3035
  }
2965
- else {
3036
+ particle.fillColor = getHslAnimationFromHsl(fillHslColor, particle.fillAnimation, container.retina.reduceFactor);
3037
+ }
3038
+ #initStroke(paint, particle, container) {
3039
+ const stroke = paint?.stroke, color = paint?.color, paintColor = color ?? undefined;
3040
+ if (!stroke) {
2966
3041
  particle.strokeAnimation = undefined;
2967
3042
  particle.strokeColor = undefined;
2968
3043
  particle.strokeOpacity = defaultOpacity;
2969
3044
  particle.strokeWidth = 0;
3045
+ return;
2970
3046
  }
2971
- }
2972
- isEnabled(particle) {
2973
- const { fillAnimation, fillColor, strokeAnimation, strokeColor } = particle, fillEnabled = !!fillAnimation &&
2974
- ((fillColor?.h.value !== undefined && fillColor.h.enable) ||
2975
- (fillColor?.s.value !== undefined && fillColor.s.enable) ||
2976
- (fillColor?.l.value !== undefined && fillColor.l.enable)), strokeEnabled = !!strokeAnimation &&
2977
- ((strokeColor?.h.value !== undefined && strokeColor.h.enable) ||
2978
- (strokeColor?.s.value !== undefined && strokeColor.s.enable) ||
2979
- (strokeColor?.l.value !== undefined && strokeColor.l.enable));
2980
- return !particle.destroyed && !particle.spawning && (fillEnabled || strokeEnabled);
2981
- }
2982
- update(particle, delta) {
2983
- if (!this.isEnabled(particle)) {
3047
+ const strokeColor = AnimatableColor.create(paintColor === undefined ? undefined : AnimatableColor.create(undefined, paintColor), stroke.color);
3048
+ particle.strokeWidth = getRangeValue(stroke.width) * container.retina.pixelRatio;
3049
+ particle.strokeOpacity = getRangeValue(stroke.opacity ?? defaultOpacity);
3050
+ particle.strokeAnimation = strokeColor.animation;
3051
+ const strokeHslColor = rangeColorToHsl(this.#pluginManager, strokeColor) ?? particle.getFillColor();
3052
+ if (!strokeHslColor) {
2984
3053
  return;
2985
3054
  }
2986
- updateColor(particle.fillColor, delta, this.#container.hdr);
2987
- updateColor(particle.strokeColor, delta, this.#container.hdr);
3055
+ particle.strokeColor = getHslAnimationFromHsl(strokeHslColor, particle.strokeAnimation, container.retina.reduceFactor);
2988
3056
  }
2989
3057
  }
2990
3058
 
2991
3059
  async function loadPaintUpdater(engine) {
2992
- engine.checkVersion("4.4.0");
3060
+ engine.checkVersion("4.5.1");
2993
3061
  await engine.pluginManager.register(e => {
2994
3062
  e.pluginManager.addParticleUpdater("paint", container => {
2995
3063
  return Promise.resolve(new PaintUpdater(e.pluginManager, container));
@@ -3031,7 +3099,7 @@
3031
3099
  if (!this.accepts(input)) {
3032
3100
  return;
3033
3101
  }
3034
- const result = rgbRegex.exec(input), radix = 10, minLength = 4, defaultAlpha = 1;
3102
+ const result = rgbRegex.exec(input), radix = 10, minLength = 4;
3035
3103
  return result
3036
3104
  ? {
3037
3105
  a: result.length > minLength ? parseAlpha(result[RgbIndexes.a]) : defaultAlpha,
@@ -3044,7 +3112,7 @@
3044
3112
  }
3045
3113
 
3046
3114
  async function loadRgbColorPlugin(engine) {
3047
- engine.checkVersion("4.4.0");
3115
+ engine.checkVersion("4.5.1");
3048
3116
  await engine.pluginManager.register(e => {
3049
3117
  e.pluginManager.addColorManager("rgb", new RgbColorManager());
3050
3118
  });
@@ -3129,7 +3197,7 @@
3129
3197
  }
3130
3198
 
3131
3199
  async function loadSizeUpdater(engine) {
3132
- engine.checkVersion("4.4.0");
3200
+ engine.checkVersion("4.5.1");
3133
3201
  await engine.pluginManager.register(e => {
3134
3202
  e.pluginManager.addParticleUpdater("size", container => {
3135
3203
  return Promise.resolve(new SizeUpdater(container));
@@ -3138,7 +3206,7 @@
3138
3206
  }
3139
3207
 
3140
3208
  async function loadBasic(engine) {
3141
- engine.checkVersion("4.4.0");
3209
+ engine.checkVersion("4.5.1");
3142
3210
  await engine.pluginManager.register(async (e) => {
3143
3211
  await Promise.all([
3144
3212
  loadBlendPlugin(e),
@@ -3370,7 +3438,7 @@
3370
3438
  }
3371
3439
 
3372
3440
  async function loadMatrixShape(engine) {
3373
- engine.checkVersion("4.4.0");
3441
+ engine.checkVersion("4.5.1");
3374
3442
  await engine.pluginManager.register(e => {
3375
3443
  e.pluginManager.addShape(["matrix"], () => Promise.resolve(new MatrixDrawer()));
3376
3444
  });
@@ -3415,12 +3483,16 @@
3415
3483
  }
3416
3484
 
3417
3485
  async function loadPoissonDiscPlugin(engine) {
3418
- engine.checkVersion("4.4.0");
3486
+ engine.checkVersion("4.5.1");
3419
3487
  await engine.pluginManager.register(e => {
3420
3488
  e.pluginManager.addPlugin(new PoissonDiscPlugin());
3421
3489
  });
3422
3490
  }
3423
3491
 
3492
+ const globalObject$1 = globalThis;
3493
+ globalObject$1.__tsParticlesInternals = globalObject$1.__tsParticlesInternals ?? {};
3494
+ globalObject$1.loadPoissonDiscPlugin = loadPoissonDiscPlugin;
3495
+
3424
3496
  const defaultShadowBlur = 0, defaultShadowOffsetValue = 0;
3425
3497
  class ShadowDrawer {
3426
3498
  #container;
@@ -3453,7 +3525,7 @@
3453
3525
  }
3454
3526
 
3455
3527
  async function loadShadowEffect(engine) {
3456
- engine.checkVersion("4.4.0");
3528
+ engine.checkVersion("4.5.1");
3457
3529
  await engine.pluginManager.register(e => {
3458
3530
  e.pluginManager.addEffect("shadow", container => {
3459
3531
  return Promise.resolve(new ShadowDrawer(e.pluginManager, container));
@@ -3517,7 +3589,7 @@
3517
3589
  }
3518
3590
 
3519
3591
  async function loadTrailPlugin(engine) {
3520
- engine.checkVersion("4.4.0");
3592
+ engine.checkVersion("4.5.1");
3521
3593
  await engine.pluginManager.register(e => {
3522
3594
  e.pluginManager.addPlugin(new TrailPlugin(e.pluginManager));
3523
3595
  });
@@ -3682,21 +3754,28 @@
3682
3754
  });
3683
3755
  }
3684
3756
  clear() {
3757
+ const visited = new Set();
3685
3758
  for (const plugin of this.#canvasClearPlugins) {
3759
+ visited.add(plugin);
3686
3760
  if (plugin.canvasClear?.() ?? false) {
3687
- return;
3761
+ return plugin;
3688
3762
  }
3689
3763
  }
3690
3764
  for (const layer of Object.values(DrawLayer)) {
3691
3765
  if (typeof layer === "number") {
3692
3766
  for (const plugin of this.#getLayerPlugins(layer)) {
3767
+ if (visited.has(plugin)) {
3768
+ continue;
3769
+ }
3770
+ visited.add(plugin);
3693
3771
  if (plugin.canvasClear?.() ?? false) {
3694
- return;
3772
+ return plugin;
3695
3773
  }
3696
3774
  }
3697
3775
  }
3698
3776
  }
3699
3777
  this.canvasClear();
3778
+ return undefined;
3700
3779
  }
3701
3780
  destroy() {
3702
3781
  this.stop();
@@ -3774,8 +3853,7 @@
3774
3853
  });
3775
3854
  }
3776
3855
  drawParticles(delta) {
3777
- const { particles, actualOptions } = this.#container;
3778
- this.clear();
3856
+ const { particles, actualOptions } = this.#container, clearedPlugin = this.clear();
3779
3857
  particles.update(delta);
3780
3858
  this.draw(ctx => {
3781
3859
  const width = this.#canvasManager.size.width, height = this.#canvasManager.size.height;
@@ -3797,7 +3875,9 @@
3797
3875
  }
3798
3876
  }
3799
3877
  for (const plugin of this.#getLayerPlugins(DrawLayer.BackgroundMask)) {
3800
- plugin.canvasPaint?.();
3878
+ if (plugin !== clearedPlugin) {
3879
+ plugin.canvasPaint?.();
3880
+ }
3801
3881
  }
3802
3882
  for (const plugin of this.#getLayerPlugins(DrawLayer.CanvasSetup)) {
3803
3883
  plugin.drawSettingsSetup?.(ctx, delta);
@@ -3829,35 +3909,7 @@
3829
3909
  this.#layers[layer] = [];
3830
3910
  }
3831
3911
  }
3832
- for (const plugin of this.#container.plugins) {
3833
- if (plugin.particleFillColor ?? plugin.particleStrokeColor) {
3834
- this.#colorPlugins.push(plugin);
3835
- }
3836
- if (plugin.drawParticle) {
3837
- this.#drawParticlePlugins.push(plugin);
3838
- }
3839
- if (plugin.drawParticleSetup) {
3840
- this.#drawParticlesSetupPlugins.push(plugin);
3841
- }
3842
- if (plugin.drawParticleCleanup) {
3843
- this.#drawParticlesCleanupPlugins.push(plugin);
3844
- }
3845
- if (plugin.canvasClear) {
3846
- this.#canvasClearPlugins.push(plugin);
3847
- }
3848
- if (plugin.canvasPaint) {
3849
- this.#getLayerPlugins(DrawLayer.BackgroundMask).push(plugin);
3850
- }
3851
- if (plugin.drawSettingsSetup) {
3852
- this.#getLayerPlugins(DrawLayer.CanvasSetup).push(plugin);
3853
- }
3854
- if (plugin.draw) {
3855
- this.#getLayerPlugins(DrawLayer.PluginContent).push(plugin);
3856
- }
3857
- if (plugin.clearDraw ?? plugin.drawSettingsCleanup) {
3858
- this.#getLayerPlugins(DrawLayer.CanvasCleanup).push(plugin);
3859
- }
3860
- }
3912
+ this.#initPluginsArray();
3861
3913
  }
3862
3914
  initUpdaters() {
3863
3915
  this.#preDrawUpdaters = [];
@@ -4066,6 +4118,45 @@
4066
4118
  this.#reusablePluginColors[sColorIndex] = sColor;
4067
4119
  return this.#reusablePluginColors;
4068
4120
  }
4121
+ #initLayerPlugin(plugin) {
4122
+ const layerMap = [
4123
+ [DrawLayer.BackgroundMask, !!plugin.canvasPaint],
4124
+ [DrawLayer.CanvasSetup, !!plugin.drawSettingsSetup],
4125
+ [DrawLayer.PluginContent, !!plugin.draw],
4126
+ [DrawLayer.CanvasCleanup, !!(plugin.clearDraw ?? plugin.drawSettingsCleanup)],
4127
+ ];
4128
+ for (const [layer, active] of layerMap) {
4129
+ if (active) {
4130
+ this.#layers[layer].push(plugin);
4131
+ }
4132
+ }
4133
+ }
4134
+ #initPluginsArray() {
4135
+ for (const plugin of this.#container.plugins) {
4136
+ if (plugin.particleFillColor ?? plugin.particleStrokeColor) {
4137
+ this.#colorPlugins.push(plugin);
4138
+ }
4139
+ if (plugin.drawParticle) {
4140
+ this.#drawParticlePlugins.push(plugin);
4141
+ }
4142
+ if (plugin.drawParticleSetup) {
4143
+ this.#drawParticlesSetupPlugins.push(plugin);
4144
+ }
4145
+ if (plugin.drawParticleCleanup) {
4146
+ this.#drawParticlesCleanupPlugins.push(plugin);
4147
+ }
4148
+ if (plugin.canvasClear) {
4149
+ this.#canvasClearPlugins.push(plugin);
4150
+ }
4151
+ this.#initLayerPlugin(plugin);
4152
+ }
4153
+ }
4154
+ #isSupportedElement(element) {
4155
+ return ((typeof HTMLCanvasElement !== "undefined" && element instanceof HTMLCanvasElement) ||
4156
+ (typeof OffscreenCanvas !== "undefined" && element instanceof OffscreenCanvas) ||
4157
+ (typeof HTMLVideoElement !== "undefined" && element instanceof HTMLVideoElement) ||
4158
+ (typeof HTMLImageElement !== "undefined" && element instanceof HTMLImageElement));
4159
+ }
4069
4160
  #resolveBackgroundElement() {
4070
4161
  const background = this.#container.actualOptions.background;
4071
4162
  this.#backgroundElement = null;
@@ -4075,9 +4166,7 @@
4075
4166
  if (typeof background.element === "string") {
4076
4167
  if (typeof document !== "undefined") {
4077
4168
  const node = document.querySelector(background.element);
4078
- if ((typeof HTMLCanvasElement !== "undefined" && node instanceof HTMLCanvasElement) ||
4079
- (typeof HTMLVideoElement !== "undefined" && node instanceof HTMLVideoElement) ||
4080
- (typeof HTMLImageElement !== "undefined" && node instanceof HTMLImageElement)) {
4169
+ if (node && this.#isSupportedElement(node)) {
4081
4170
  this.#backgroundElement = node;
4082
4171
  }
4083
4172
  else if (node) {
@@ -4088,10 +4177,7 @@
4088
4177
  }
4089
4178
  }
4090
4179
  }
4091
- else if ((typeof HTMLCanvasElement !== "undefined" && background.element instanceof HTMLCanvasElement) ||
4092
- (typeof OffscreenCanvas !== "undefined" && background.element instanceof OffscreenCanvas) ||
4093
- (typeof HTMLVideoElement !== "undefined" && background.element instanceof HTMLVideoElement) ||
4094
- (typeof HTMLImageElement !== "undefined" && background.element instanceof HTMLImageElement)) {
4180
+ else if (this.#isSupportedElement(background.element)) {
4095
4181
  this.#backgroundElement = background.element;
4096
4182
  }
4097
4183
  }
@@ -4109,7 +4195,7 @@
4109
4195
  return transferredCanvas;
4110
4196
  }
4111
4197
  if (typeof canvas.transferControlToOffscreen !== "function") {
4112
- throw new TypeError("OffscreenCanvas is required but not supported by this browser");
4198
+ throw new TypeError(getErrorMessage(ErrorCodes$1.offscreenCanvasUnsupported));
4113
4199
  }
4114
4200
  try {
4115
4201
  const offscreenCanvas = canvas.transferControlToOffscreen();
@@ -4117,10 +4203,16 @@
4117
4203
  return offscreenCanvas;
4118
4204
  }
4119
4205
  catch {
4120
- throw new TypeError("OffscreenCanvas transfer failed");
4206
+ throw new TypeError(getErrorMessage(ErrorCodes$1.offscreenCanvasTransferFailed));
4121
4207
  }
4122
4208
  }, isHtmlCanvasElement = (canvas) => {
4123
4209
  return typeof HTMLCanvasElement !== "undefined" && canvas instanceof HTMLCanvasElement;
4210
+ }, getEffectiveColorSpace = (context) => {
4211
+ if (!context) {
4212
+ return undefined;
4213
+ }
4214
+ const colorInfo = context;
4215
+ return colorInfo.getContextAttributes?.().colorSpace ?? undefined;
4124
4216
  };
4125
4217
  function setStyle(canvas, style, important = false) {
4126
4218
  if (!style) {
@@ -4245,7 +4337,7 @@
4245
4337
  const elementStyle = element.style, color = rangeColorToRgb(this.#pluginManager, background.color);
4246
4338
  if (color) {
4247
4339
  const hdrOptions = container.actualOptions.hdr;
4248
- elementStyle.backgroundColor = getStyleFromRgb(color, container.hdr, background.opacity, hdrOptions.peakNits, hdrOptions.mode);
4340
+ elementStyle.backgroundColor = getStyleFromRgb(color, container.hdr, background.opacity, hdrOptions.peakNits, toEnumValue(HdrMode, hdrOptions.mode, HdrMode.standard));
4249
4341
  }
4250
4342
  else {
4251
4343
  elementStyle.backgroundColor = "";
@@ -4365,11 +4457,11 @@
4365
4457
  const container = this.#container, canSupportHdr = container.actualOptions.hdr.enable &&
4366
4458
  safeMatchMedia("(color-gamut: p3)")?.matches &&
4367
4459
  safeMatchMedia("(dynamic-range: high)")?.matches;
4368
- container.hdr = canSupportHdr ?? false;
4369
- container.hdrMode = container.actualOptions.hdr.mode;
4460
+ container.hdrMode = toEnumValue(HdrMode, container.actualOptions.hdr.mode, HdrMode.standard);
4370
4461
  container.peakNits = container.actualOptions.hdr.peakNits;
4371
4462
  const renderCanvas = this.renderCanvas;
4372
4463
  if (!renderCanvas) {
4464
+ container.hdr = canSupportHdr ?? false;
4373
4465
  return;
4374
4466
  }
4375
4467
  this.render.setContextSettings({
@@ -4388,7 +4480,6 @@
4388
4480
  context = null;
4389
4481
  }
4390
4482
  if (canSupportHdr && !context) {
4391
- container.hdr = false;
4392
4483
  const sdrSettings = {
4393
4484
  alpha: true,
4394
4485
  desynchronized: true,
@@ -4404,11 +4495,16 @@
4404
4495
  }
4405
4496
  }
4406
4497
  this.render.setContext(context);
4498
+ if (context) {
4499
+ const effectiveColorSpace = getEffectiveColorSpace(context);
4500
+ if (effectiveColorSpace !== undefined) {
4501
+ container.hdr = effectiveColorSpace === "display-p3";
4502
+ }
4503
+ }
4407
4504
  }
4408
4505
  #initHdrListeners() {
4409
4506
  this.#removeHdrListeners();
4410
4507
  const p3Query = safeMatchMedia("(color-gamut: p3)"), hdrQuery = safeMatchMedia("(dynamic-range: high)"), handleChange = () => {
4411
- this.#recreateRenderCanvas();
4412
4508
  this.#initContext();
4413
4509
  this.initBackground();
4414
4510
  }, listeners = [];
@@ -4444,16 +4540,6 @@
4444
4540
  element.style.setProperty(key, value, "important");
4445
4541
  }
4446
4542
  }
4447
- #recreateRenderCanvas() {
4448
- const renderCanvas = this.renderCanvas;
4449
- if (!renderCanvas) {
4450
- return;
4451
- }
4452
- if (this.domElement) {
4453
- return;
4454
- }
4455
- this.renderCanvas = new OffscreenCanvas(renderCanvas.width, renderCanvas.height);
4456
- }
4457
4543
  #removeHdrListeners() {
4458
4544
  if (!this.#hdrMediaListeners) {
4459
4545
  return;
@@ -4525,6 +4611,10 @@
4525
4611
  this.#manageListeners(true);
4526
4612
  }
4527
4613
  removeListeners() {
4614
+ if (this.#resizeTimeout !== undefined) {
4615
+ clearTimeout(this.#resizeTimeout);
4616
+ this.#resizeTimeout = undefined;
4617
+ }
4528
4618
  this.#manageListeners(false);
4529
4619
  }
4530
4620
  #handleVisibilityChange() {
@@ -4552,8 +4642,7 @@
4552
4642
  this.#resizeTimeout = undefined;
4553
4643
  }
4554
4644
  const handleResize = async () => {
4555
- const canvas = this.#container.canvas;
4556
- await canvas.windowResize();
4645
+ await this.#container.canvas.windowResize();
4557
4646
  };
4558
4647
  this.#resizeTimeout = setTimeout(() => void handleResize(), this.#container.actualOptions.resize.delay * millisecondsToSeconds);
4559
4648
  }
@@ -4581,8 +4670,8 @@
4581
4670
  }
4582
4671
  else if (!this.#resizeObserver && add && canvasEl) {
4583
4672
  this.#resizeObserver = new ResizeObserver((entries) => {
4584
- const entry = entries.find(e => e.target === canvasEl);
4585
- if (!entry) {
4673
+ const res = entries.some(e => e.target === canvasEl);
4674
+ if (!res) {
4586
4675
  return;
4587
4676
  }
4588
4677
  this.#handleWindowResize();
@@ -4846,10 +4935,10 @@
4846
4935
  return this.#modifiers.find(m => m.id === id);
4847
4936
  }
4848
4937
  getOpacity() {
4849
- 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;
4850
- this.#cachedOpacityData.fillOpacity = fillOpacity;
4938
+ 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;
4939
+ this.#cachedOpacityData.fillOpacity = this.fillOpacity ?? defaultOpacity$1;
4851
4940
  this.#cachedOpacityData.opacity = opacity * zOpacityFactor;
4852
- this.#cachedOpacityData.strokeOpacity = strokeOpacity;
4941
+ this.#cachedOpacityData.strokeOpacity = this.strokeOpacity ?? defaultOpacity$1;
4853
4942
  return this.#cachedOpacityData;
4854
4943
  }
4855
4944
  getPosition() {
@@ -5096,7 +5185,7 @@
5096
5185
  #initPosition(position) {
5097
5186
  const container = this.#container, zIndexValue = Math.floor(getRangeValue(this.options.zIndex.value)), initialPosition = this.#calcPosition(position, clamp(zIndexValue, minZ, container.zLayers));
5098
5187
  if (!initialPosition) {
5099
- throw new Error("a valid position cannot be found for particle");
5188
+ throw new Error(getErrorMessage(ErrorCodes$1.particlePositionNotFound));
5100
5189
  }
5101
5190
  this.position = initialPosition;
5102
5191
  this.initialPosition = this.position.copy();
@@ -5145,6 +5234,12 @@
5145
5234
  this.#circlePoolIdx = 0;
5146
5235
  this.#rectanglePoolIdx = 0;
5147
5236
  }
5237
+ get cellSize() {
5238
+ return this.#cellSize;
5239
+ }
5240
+ set cellSize(value) {
5241
+ this.#pendingCellSize = value;
5242
+ }
5148
5243
  clear() {
5149
5244
  this.#cells.clear();
5150
5245
  const pendingCellSize = this.#pendingCellSize;
@@ -5168,40 +5263,46 @@
5168
5263
  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);
5169
5264
  for (let cx = minCellX; cx <= maxCellX; cx++) {
5170
5265
  for (let cy = minCellY; cy <= maxCellY; cy++) {
5171
- const key = `${cx}_${cy}`, cellParticles = this.#cells.get(key);
5172
- if (!cellParticles) {
5173
- continue;
5174
- }
5175
- for (const p of cellParticles) {
5176
- if (check && !check(p)) {
5177
- continue;
5178
- }
5179
- if (range.contains(p.getPosition())) {
5180
- out.push(p);
5181
- }
5182
- }
5266
+ this.#queryCell(cx, cy, range, check, out);
5183
5267
  }
5184
5268
  }
5185
5269
  return out;
5186
5270
  }
5187
5271
  queryCircle(position, radius, check, out = []) {
5188
- const circle = this.#acquireCircle(position.x, position.y, radius), result = this.query(circle, check, out);
5189
- this.#releaseShapes();
5190
- return result;
5272
+ const circle = this.#acquireCircle(position.x, position.y, radius);
5273
+ try {
5274
+ return this.query(circle, check, out);
5275
+ }
5276
+ finally {
5277
+ this.#circlePoolIdx--;
5278
+ }
5191
5279
  }
5192
5280
  queryRectangle(position, size, check, out = []) {
5193
- const rect = this.#acquireRectangle(position.x, position.y, size.width, size.height), result = this.query(rect, check, out);
5194
- this.#releaseShapes();
5195
- return result;
5196
- }
5197
- setCellSize(cellSize) {
5198
- this.#pendingCellSize = cellSize;
5281
+ const rect = this.#acquireRectangle(position.x, position.y, size.width, size.height);
5282
+ try {
5283
+ return this.query(rect, check, out);
5284
+ }
5285
+ finally {
5286
+ this.#rectanglePoolIdx--;
5287
+ }
5199
5288
  }
5200
5289
  #acquireCircle(x, y, r) {
5201
- return (this.#circlePool[this.#circlePoolIdx++] ??= new Circle(x, y, r)).reset(x, y, r);
5290
+ const idx = this.#circlePoolIdx++;
5291
+ let circle = this.#circlePool[idx];
5292
+ if (!circle) {
5293
+ circle = new Circle(x, y, r);
5294
+ this.#circlePool[idx] = circle;
5295
+ }
5296
+ return circle.reset(x, y, r);
5202
5297
  }
5203
5298
  #acquireRectangle(x, y, w, h) {
5204
- return (this.#rectanglePool[this.#rectanglePoolIdx++] ??= new Rectangle(x, y, w, h)).reset(x, y, w, h);
5299
+ const idx = this.#rectanglePoolIdx++;
5300
+ let rectangle = this.#rectanglePool[idx];
5301
+ if (!rectangle) {
5302
+ rectangle = new Rectangle(x, y, w, h);
5303
+ this.#rectanglePool[idx] = rectangle;
5304
+ }
5305
+ return rectangle.reset(x, y, w, h);
5205
5306
  }
5206
5307
  #cellKeyFromCoords(x, y) {
5207
5308
  const cellX = Math.floor(x / this.#cellSize), cellY = Math.floor(y / this.#cellSize);
@@ -5228,17 +5329,27 @@
5228
5329
  }
5229
5330
  return null;
5230
5331
  }
5231
- #releaseShapes() {
5232
- this.#circlePoolIdx = 0;
5233
- this.#rectanglePoolIdx = 0;
5332
+ #queryCell(cx, cy, range, check, out) {
5333
+ const cellParticles = this.#cells.get(`${cx}_${cy}`);
5334
+ if (!cellParticles) {
5335
+ return;
5336
+ }
5337
+ for (const p of cellParticles) {
5338
+ if (check && !check(p)) {
5339
+ continue;
5340
+ }
5341
+ if (range.contains(p.getPosition())) {
5342
+ out.push(p);
5343
+ }
5344
+ }
5234
5345
  }
5235
5346
  }
5236
5347
 
5237
5348
  class ParticlesManager {
5238
5349
  checkParticlePositionPlugins;
5239
- grid;
5240
5350
  #array;
5241
5351
  #container;
5352
+ #grid;
5242
5353
  #groupLimits;
5243
5354
  #limit;
5244
5355
  #nextId;
@@ -5262,7 +5373,7 @@
5262
5373
  this.#groupLimits = new Map();
5263
5374
  this.#particleBuckets = new Map();
5264
5375
  this.#zBuckets = this.#createBuckets(this.#container.zLayers);
5265
- this.grid = new SpatialHashGrid(spatialHashGridCellSize);
5376
+ this.#grid = new SpatialHashGrid(spatialHashGridCellSize);
5266
5377
  this.checkParticlePositionPlugins = [];
5267
5378
  this.#particleResetPlugins = [];
5268
5379
  this.#particleUpdatePlugins = [];
@@ -5273,23 +5384,12 @@
5273
5384
  get count() {
5274
5385
  return this.#array.length;
5275
5386
  }
5387
+ get grid() {
5388
+ return this.#grid;
5389
+ }
5276
5390
  addParticle(position, overrideOptions, group, initializer) {
5277
- const limitMode = this.#container.actualOptions.particles.number.limit.mode, limit = group === undefined ? this.#limit : (this.#groupLimits.get(group) ?? this.#limit), currentCount = this.count;
5278
- if (limit > minLimit) {
5279
- switch (limitMode) {
5280
- case LimitMode.delete: {
5281
- const countToRemove = currentCount + countOffset - limit;
5282
- if (countToRemove > minCount) {
5283
- this.removeQuantity(countToRemove);
5284
- }
5285
- break;
5286
- }
5287
- case LimitMode.wait:
5288
- if (currentCount >= limit) {
5289
- return;
5290
- }
5291
- break;
5292
- }
5391
+ if (this.#checkAndApplyLimits(group, this.count)) {
5392
+ return;
5293
5393
  }
5294
5394
  try {
5295
5395
  const particle = this.#pool.pop() ?? new Particle(this.#pluginManager, this.#container);
@@ -5353,7 +5453,7 @@
5353
5453
  return this.#array[index];
5354
5454
  }
5355
5455
  async init() {
5356
- const container = this.#container, options = container.actualOptions;
5456
+ const container = this.#container;
5357
5457
  this.checkParticlePositionPlugins = [];
5358
5458
  this.#updatePlugins = [];
5359
5459
  this.#particleUpdatePlugins = [];
@@ -5362,59 +5462,16 @@
5362
5462
  this.#postParticleUpdatePlugins = [];
5363
5463
  this.#particleBuckets.clear();
5364
5464
  this.#resetBuckets(container.zLayers);
5365
- this.grid = new SpatialHashGrid(spatialHashGridCellSize * container.retina.pixelRatio);
5366
- for (const plugin of container.plugins) {
5367
- if (plugin.redrawInit) {
5368
- await plugin.redrawInit();
5369
- }
5370
- if (plugin.checkParticlePosition) {
5371
- this.checkParticlePositionPlugins.push(plugin);
5372
- }
5373
- if (plugin.update) {
5374
- this.#updatePlugins.push(plugin);
5375
- }
5376
- if (plugin.particleUpdate) {
5377
- this.#particleUpdatePlugins.push(plugin);
5378
- }
5379
- if (plugin.postUpdate) {
5380
- this.#postUpdatePlugins.push(plugin);
5381
- }
5382
- if (plugin.particleReset) {
5383
- this.#particleResetPlugins.push(plugin);
5384
- }
5385
- if (plugin.postParticleUpdate) {
5386
- this.#postParticleUpdatePlugins.push(plugin);
5387
- }
5388
- }
5389
- await this.#container.initDrawersAndUpdaters();
5390
- for (const drawer of this.#container.effectDrawers.values()) {
5391
- await drawer.init?.(container);
5392
- }
5393
- for (const drawer of this.#container.shapeDrawers.values()) {
5394
- await drawer.init?.(container);
5395
- }
5396
- let handled = false;
5397
- for (const plugin of container.plugins) {
5398
- handled = plugin.particlesInitialization?.() ?? handled;
5399
- if (handled) {
5400
- break;
5401
- }
5402
- }
5403
- if (!handled) {
5404
- const particlesOptions = options.particles, groups = particlesOptions.groups;
5405
- for (const group in groups) {
5406
- const groupOptions = groups[group];
5407
- if (!groupOptions) {
5408
- continue;
5409
- }
5410
- for (let i = this.count, j = 0; j < groupOptions.number.value && i < particlesOptions.number.value; i++, j++) {
5411
- this.addParticle(undefined, groupOptions, group);
5412
- }
5413
- }
5414
- for (let i = this.count; i < particlesOptions.number.value; i++) {
5415
- this.addParticle();
5465
+ this.#grid = new SpatialHashGrid(spatialHashGridCellSize * container.retina.pixelRatio);
5466
+ this.#applyLimits(container.actualOptions.particles);
5467
+ const particlesOptions = container.actualOptions.particles, groups = particlesOptions.groups;
5468
+ for (const group in groups) {
5469
+ const groupData = groups[group];
5470
+ if (groupData) {
5471
+ this.#applyLimits(loadParticlesOptions(this.#pluginManager, this.#container, groupData), group, groupData);
5416
5472
  }
5417
5473
  }
5474
+ await this.#initPlugins();
5418
5475
  }
5419
5476
  push(nb, position, overrideOptions, group) {
5420
5477
  for (let i = 0; i < nb; i++) {
@@ -5429,13 +5486,13 @@
5429
5486
  remove(particle, group, override) {
5430
5487
  this.removeAt(this.#array.indexOf(particle), undefined, group, override);
5431
5488
  }
5432
- removeAt(index, quantity = defaultRemoveQuantity, group, override) {
5489
+ removeAt(index, quantity = defaultRemoveQuantity, group, override, matchGroup = true) {
5433
5490
  if (index < minIndex || index > this.count) {
5434
5491
  return;
5435
5492
  }
5436
5493
  let deleted = 0;
5437
5494
  for (let i = index; deleted < quantity && i < this.count; i++) {
5438
- if (this.#removeParticle(i, group, override)) {
5495
+ if (this.#removeParticle(i, group, override, matchGroup)) {
5439
5496
  i--;
5440
5497
  deleted++;
5441
5498
  }
@@ -5466,7 +5523,7 @@
5466
5523
  this.#resizeFactor = factor;
5467
5524
  }
5468
5525
  update(delta) {
5469
- this.grid.clear();
5526
+ this.#grid.clear();
5470
5527
  for (const plugin of this.#updatePlugins) {
5471
5528
  plugin.update?.(delta);
5472
5529
  }
@@ -5477,7 +5534,7 @@
5477
5534
  this.#updateParticlesPhase2(delta, particlesToDelete);
5478
5535
  if (particlesToDelete.size) {
5479
5536
  for (const particle of particlesToDelete) {
5480
- this.remove(particle);
5537
+ this.remove(particle, particle.group);
5481
5538
  }
5482
5539
  }
5483
5540
  this.#resizeFactor = undefined;
@@ -5488,12 +5545,7 @@
5488
5545
  #applyDensity(options, pluginsCount, group, groupOptions) {
5489
5546
  const numberOptions = options.number;
5490
5547
  if (!numberOptions.density.enable) {
5491
- if (group === undefined) {
5492
- this.#limit = numberOptions.limit.value;
5493
- }
5494
- else if (groupOptions?.number.limit.value ?? numberOptions.limit.value) {
5495
- this.#groupLimits.set(group, groupOptions?.number.limit.value ?? numberOptions.limit.value);
5496
- }
5548
+ this.#applyLimits(options, group, groupOptions);
5497
5549
  return;
5498
5550
  }
5499
5551
  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);
@@ -5501,7 +5553,10 @@
5501
5553
  this.#limit = numberOptions.limit.value * densityFactor;
5502
5554
  }
5503
5555
  else {
5504
- this.#groupLimits.set(group, numberOptions.limit.value * densityFactor);
5556
+ this.#groupLimits.set(group, {
5557
+ limit: numberOptions.limit.value * densityFactor,
5558
+ mode: toEnumValue(LimitMode, numberOptions.limit.mode, LimitMode.delete),
5559
+ });
5505
5560
  }
5506
5561
  if (particlesCount < particlesNumber) {
5507
5562
  this.push(Math.abs(particlesNumber - particlesCount), undefined, options, group);
@@ -5510,6 +5565,55 @@
5510
5565
  this.removeQuantity(particlesCount - particlesNumber, group);
5511
5566
  }
5512
5567
  }
5568
+ #applyLimits(options, group, groupOptions) {
5569
+ if (group === undefined) {
5570
+ this.#limit = options.number.limit.value;
5571
+ const groups = this.#container.actualOptions.particles.groups;
5572
+ for (const existingGroup of this.#groupLimits.keys()) {
5573
+ if (!(existingGroup in groups)) {
5574
+ this.#groupLimits.delete(existingGroup);
5575
+ }
5576
+ }
5577
+ }
5578
+ else {
5579
+ const limitValue = groupOptions?.number?.limit?.value ?? options.number.limit.value;
5580
+ if (limitValue > minLimit) {
5581
+ this.#groupLimits.set(group, {
5582
+ limit: limitValue,
5583
+ mode: toEnumValue(LimitMode, groupOptions?.number?.limit?.mode ?? options.number.limit.mode, LimitMode.delete),
5584
+ });
5585
+ }
5586
+ else {
5587
+ this.#groupLimits.delete(group);
5588
+ }
5589
+ }
5590
+ }
5591
+ #checkAndApplyLimits(group, currentCount) {
5592
+ const globalLimit = this.#limit, globalMode = this.#container.actualOptions.particles.number.limit.mode;
5593
+ if (globalLimit > minLimit && globalMode === LimitMode.wait && currentCount >= globalLimit) {
5594
+ return true;
5595
+ }
5596
+ const groupLimitEntry = group === undefined ? undefined : this.#groupLimits.get(group);
5597
+ if (groupLimitEntry && groupLimitEntry.limit > minLimit && groupLimitEntry.mode === LimitMode.wait) {
5598
+ const groupCount = this.filter(t => t.group === group).length;
5599
+ if (groupCount >= groupLimitEntry.limit) {
5600
+ return true;
5601
+ }
5602
+ }
5603
+ if (groupLimitEntry && groupLimitEntry.limit > minLimit && groupLimitEntry.mode === LimitMode.delete) {
5604
+ const groupCountToRemove = this.filter(t => t.group === group).length + countOffset - groupLimitEntry.limit;
5605
+ if (groupCountToRemove > minCount) {
5606
+ this.removeQuantity(groupCountToRemove, group);
5607
+ }
5608
+ }
5609
+ if (globalLimit > minLimit && globalMode === LimitMode.delete) {
5610
+ const globalCountToRemove = this.count + countOffset - globalLimit;
5611
+ if (globalCountToRemove > minCount) {
5612
+ this.#removeAny(globalCountToRemove);
5613
+ }
5614
+ }
5615
+ return false;
5616
+ }
5513
5617
  #createBuckets(zLayers) {
5514
5618
  const bucketCount = Math.max(Math.floor(zLayers), one);
5515
5619
  return Array.from({ length: bucketCount }, () => []);
@@ -5532,6 +5636,70 @@
5532
5636
  }
5533
5637
  return ((canvasSize.width * canvasSize.height) / (densityOptions.height * densityOptions.width * pxRatio ** squareExp));
5534
5638
  }
5639
+ async #initDrawersAndUpdaters() {
5640
+ const container = this.#container;
5641
+ await container.initDrawersAndUpdaters();
5642
+ for (const drawer of container.effectDrawers.values()) {
5643
+ await drawer.init?.(container);
5644
+ }
5645
+ for (const drawer of container.shapeDrawers.values()) {
5646
+ await drawer.init?.(container);
5647
+ }
5648
+ }
5649
+ async #initPlugins() {
5650
+ await this.#initPluginsArrays();
5651
+ await this.#initDrawersAndUpdaters();
5652
+ let handled = false;
5653
+ const container = this.#container;
5654
+ for (const plugin of container.plugins) {
5655
+ handled = plugin.particlesInitialization?.() ?? handled;
5656
+ if (handled) {
5657
+ break;
5658
+ }
5659
+ }
5660
+ if (handled) {
5661
+ return;
5662
+ }
5663
+ const particlesOptions = container.actualOptions.particles, groups = particlesOptions.groups;
5664
+ for (const group in groups) {
5665
+ const groupOptions = groups[group];
5666
+ if (!groupOptions) {
5667
+ continue;
5668
+ }
5669
+ for (let i = this.count, j = 0; j < groupOptions.number.value && i < particlesOptions.number.value; i++, j++) {
5670
+ this.addParticle(undefined, groupOptions, group);
5671
+ }
5672
+ }
5673
+ for (let i = this.count; i < particlesOptions.number.value; i++) {
5674
+ this.addParticle();
5675
+ }
5676
+ }
5677
+ async #initPluginsArrays() {
5678
+ const container = this.#container;
5679
+ for (const plugin of container.plugins) {
5680
+ if (plugin.redrawInit) {
5681
+ await plugin.redrawInit();
5682
+ }
5683
+ if (plugin.checkParticlePosition) {
5684
+ this.checkParticlePositionPlugins.push(plugin);
5685
+ }
5686
+ if (plugin.update) {
5687
+ this.#updatePlugins.push(plugin);
5688
+ }
5689
+ if (plugin.particleUpdate) {
5690
+ this.#particleUpdatePlugins.push(plugin);
5691
+ }
5692
+ if (plugin.postUpdate) {
5693
+ this.#postUpdatePlugins.push(plugin);
5694
+ }
5695
+ if (plugin.particleReset) {
5696
+ this.#particleResetPlugins.push(plugin);
5697
+ }
5698
+ if (plugin.postParticleUpdate) {
5699
+ this.#postParticleUpdatePlugins.push(plugin);
5700
+ }
5701
+ }
5702
+ }
5535
5703
  #insertParticleIntoBucket(particle) {
5536
5704
  const bucketIndex = this.#getBucketIndex(particle.position.z), bucket = this.#zBuckets[bucketIndex];
5537
5705
  if (!bucket) {
@@ -5540,12 +5708,15 @@
5540
5708
  bucket.push(particle);
5541
5709
  this.#particleBuckets.set(particle.id, bucketIndex);
5542
5710
  }
5543
- #removeParticle(index, group, override) {
5711
+ #removeAny(quantity) {
5712
+ this.removeAt(minIndex, quantity, undefined, undefined, false);
5713
+ }
5714
+ #removeParticle(index, group, override, matchGroup = true) {
5544
5715
  const particle = this.#array[index];
5545
5716
  if (!particle) {
5546
5717
  return false;
5547
5718
  }
5548
- if (particle.group !== group) {
5719
+ if (matchGroup && particle.group !== group) {
5549
5720
  return false;
5550
5721
  }
5551
5722
  this.#array.splice(index, deleteCount);
@@ -5632,7 +5803,7 @@
5632
5803
  particlesToDelete.add(particle);
5633
5804
  continue;
5634
5805
  }
5635
- this.grid.insert(particle);
5806
+ this.#grid.insert(particle);
5636
5807
  }
5637
5808
  return particlesToDelete;
5638
5809
  }
@@ -5719,6 +5890,7 @@
5719
5890
  started;
5720
5891
  zLayers;
5721
5892
  #delay;
5893
+ #delayResolve;
5722
5894
  #delayTimeout;
5723
5895
  #delta = { value: 0, factor: 0 };
5724
5896
  #dispatchCallback;
@@ -5808,7 +5980,6 @@
5808
5980
  this.shapeDrawers = new Map();
5809
5981
  this.particleUpdaters = [];
5810
5982
  this.plugins.length = 0;
5811
- this.#pluginManager.clearPlugins(this);
5812
5983
  this.destroyed = true;
5813
5984
  this.#onDestroy(remove);
5814
5985
  this.dispatchEvent(EventType.containerDestroyed);
@@ -5861,31 +6032,14 @@
5861
6032
  await this.initDrawersAndUpdaters();
5862
6033
  this.#options = loadContainerOptions(this.#pluginManager, this, this.#initialSourceOptions, this.sourceOptions);
5863
6034
  this.actualOptions = loadContainerOptions(this.#pluginManager, this, this.#options);
5864
- this.plugins.length = 0;
5865
- this.particleDestroyedPlugins.length = 0;
5866
- this.particleCreatedPlugins.length = 0;
5867
- this.particlePositionPlugins.length = 0;
5868
- for (const [plugin, containerPlugin] of allContainerPlugins) {
5869
- if (plugin.needsPlugin(this.actualOptions)) {
5870
- this.plugins.push(containerPlugin);
5871
- if (containerPlugin.particleCreated) {
5872
- this.particleCreatedPlugins.push(containerPlugin);
5873
- }
5874
- if (containerPlugin.particleDestroyed) {
5875
- this.particleDestroyedPlugins.push(containerPlugin);
5876
- }
5877
- if (containerPlugin.particlePosition) {
5878
- this.particlePositionPlugins.push(containerPlugin);
5879
- }
5880
- }
5881
- }
6035
+ this.#initPlugins(allContainerPlugins);
5882
6036
  this.retina.init();
5883
6037
  this.canvas.init();
5884
6038
  this.updateActualOptions();
5885
6039
  this.canvas.initBackground();
5886
6040
  this.canvas.resize();
5887
6041
  const { delay, duration, fpsLimit, smooth, zLayers } = this.actualOptions, hdrOptions = this.actualOptions.hdr;
5888
- this.hdrMode = hdrOptions.mode;
6042
+ this.hdrMode = toEnumValue(HdrMode, hdrOptions.mode, HdrMode.standard);
5889
6043
  this.peakNits = hdrOptions.peakNits;
5890
6044
  this.zLayers = zLayers;
5891
6045
  this.#duration = getRangeValue(duration) * millisecondsToSeconds;
@@ -5906,9 +6060,9 @@
5906
6060
  }
5907
6061
  async initDrawersAndUpdaters() {
5908
6062
  const pluginManager = this.#pluginManager;
5909
- this.effectDrawers = await pluginManager.getEffectDrawers(this, true);
5910
- this.shapeDrawers = await pluginManager.getShapeDrawers(this, true);
5911
- this.particleUpdaters = await pluginManager.getUpdaters(this, true);
6063
+ this.effectDrawers = await getItemMapFromInitializer(this, pluginManager.initializers.effects);
6064
+ this.shapeDrawers = await getItemMapFromInitializer(this, pluginManager.initializers.shapes);
6065
+ this.particleUpdaters = await getItemsFromInitializer(this, pluginManager.initializers.updaters);
5912
6066
  }
5913
6067
  pause() {
5914
6068
  if (!guardCheck(this)) {
@@ -5975,7 +6129,10 @@
5975
6129
  await this.init();
5976
6130
  this.started = true;
5977
6131
  await new Promise(resolve => {
6132
+ this.#delayResolve = resolve;
5978
6133
  const start = async () => {
6134
+ this.#delayTimeout = undefined;
6135
+ this.#delayResolve = undefined;
5979
6136
  this.#eventListeners.addListeners();
5980
6137
  for (const plugin of this.plugins) {
5981
6138
  await plugin.start?.();
@@ -5991,9 +6148,11 @@
5991
6148
  if (!guardCheck(this) || !this.started) {
5992
6149
  return;
5993
6150
  }
5994
- if (this.#delayTimeout) {
6151
+ if (this.#delayTimeout !== undefined) {
5995
6152
  clearTimeout(this.#delayTimeout);
5996
6153
  this.#delayTimeout = undefined;
6154
+ this.#delayResolve?.();
6155
+ this.#delayResolve = undefined;
5997
6156
  }
5998
6157
  this.#firstStart = true;
5999
6158
  this.started = false;
@@ -6019,6 +6178,27 @@
6019
6178
  }
6020
6179
  return refresh;
6021
6180
  }
6181
+ #initPlugins(allContainerPlugins) {
6182
+ this.plugins.length = 0;
6183
+ this.particleDestroyedPlugins.length = 0;
6184
+ this.particleCreatedPlugins.length = 0;
6185
+ this.particlePositionPlugins.length = 0;
6186
+ for (const [plugin, containerPlugin] of allContainerPlugins) {
6187
+ if (!plugin.needsPlugin(this.actualOptions)) {
6188
+ continue;
6189
+ }
6190
+ this.plugins.push(containerPlugin);
6191
+ if (containerPlugin.particleCreated) {
6192
+ this.particleCreatedPlugins.push(containerPlugin);
6193
+ }
6194
+ if (containerPlugin.particleDestroyed) {
6195
+ this.particleDestroyedPlugins.push(containerPlugin);
6196
+ }
6197
+ if (containerPlugin.particlePosition) {
6198
+ this.particlePositionPlugins.push(containerPlugin);
6199
+ }
6200
+ }
6201
+ }
6022
6202
  #nextFrame(timestamp) {
6023
6203
  try {
6024
6204
  if (!this.#smooth &&
@@ -6295,11 +6475,11 @@
6295
6475
  }
6296
6476
  }
6297
6477
  async #init() {
6298
- const availablePathGenerators = await this.#pluginManager.getPathGenerators?.(this.#container, true);
6299
- if (!availablePathGenerators) {
6478
+ const pluginManager = this.#pluginManager;
6479
+ if (!pluginManager.initializers.pathGenerators) {
6300
6480
  return;
6301
6481
  }
6302
- this.availablePathGenerators = availablePathGenerators;
6482
+ this.availablePathGenerators = await getItemMapFromInitializer(this.#container, pluginManager.initializers.pathGenerators);
6303
6483
  this.pathGenerators = new Map();
6304
6484
  for (const pathGenerator of this.pathGenerators.values()) {
6305
6485
  pathGenerator.init();
@@ -6534,7 +6714,7 @@
6534
6714
  }
6535
6715
  async run() {
6536
6716
  this.reset();
6537
- const minCount = 0, step = 1, yieldEvery = 100, yieldStepModule = 0;
6717
+ const step = 1, yieldEvery = 100, yieldStepModule = 0;
6538
6718
  let iterations = 0;
6539
6719
  while (this.active.length > minCount) {
6540
6720
  this.steps(step);
@@ -6544,7 +6724,6 @@
6544
6724
  }
6545
6725
  }
6546
6726
  steps(steps) {
6547
- const minCount = 0;
6548
6727
  for (let i = 0; i < steps; i++) {
6549
6728
  if (this.active.length <= minCount) {
6550
6729
  continue;
@@ -6611,7 +6790,7 @@
6611
6790
  return newPoint;
6612
6791
  }
6613
6792
  #step() {
6614
- const minCount = 0, randomActive = this.getRandom(minCount, this.active.length);
6793
+ const randomActive = this.getRandom(minCount, this.active.length);
6615
6794
  let foundNewPoint = false;
6616
6795
  for (let tries = 0; tries < this.retries; tries++) {
6617
6796
  const randomActivePointIndex = this.active[randomActive];
@@ -6644,6 +6823,7 @@
6644
6823
  exports.loadMatrixPreset = loadMatrixPreset;
6645
6824
  exports.tsParticles = tsParticles;
6646
6825
 
6647
- }));
6826
+ })(g.__tsParticlesInternals.presets.matrix = g.__tsParticlesInternals.presets.matrix || {});
6827
+ })(typeof globalThis !== "undefined" ? globalThis : typeof window !== "undefined" ? window : self);
6828
+
6648
6829
  Object.assign(globalThis.window || globalThis, { loadMatrixPreset: (globalThis.__tsParticlesInternals.presets.matrix || {}).loadMatrixPreset });
6649
- delete (globalThis.window || globalThis).tsparticlesInternalExports;