@tsparticles/preset-matrix 4.4.0 → 4.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,21 +1,35 @@
1
- (function(g){g.__tsParticlesInternals=g.__tsParticlesInternals||{};g.__tsParticlesInternals.bundles=g.__tsParticlesInternals.bundles||{};g.__tsParticlesInternals.effects=g.__tsParticlesInternals.effects||{};g.__tsParticlesInternals.engine=g.__tsParticlesInternals.engine||{};g.__tsParticlesInternals.interactions=g.__tsParticlesInternals.interactions||{};g.__tsParticlesInternals.palettes=g.__tsParticlesInternals.palettes||{};g.__tsParticlesInternals.paths=g.__tsParticlesInternals.paths||{};g.__tsParticlesInternals.plugins=g.__tsParticlesInternals.plugins||{};g.__tsParticlesInternals.plugins=g.__tsParticlesInternals.plugins||{};g.__tsParticlesInternals.plugins.emittersShapes=g.__tsParticlesInternals.plugins.emittersShapes||{};g.__tsParticlesInternals.presets=g.__tsParticlesInternals.presets||{};g.__tsParticlesInternals.shapes=g.__tsParticlesInternals.shapes||{};g.__tsParticlesInternals.updaters=g.__tsParticlesInternals.updaters||{};g.__tsParticlesInternals.utils=g.__tsParticlesInternals.utils||{};g.__tsParticlesInternals.canvas=g.__tsParticlesInternals.canvas||{};g.__tsParticlesInternals.canvas=g.__tsParticlesInternals.canvas||{};g.__tsParticlesInternals.canvas.utils=g.__tsParticlesInternals.canvas.utils||{};g.__tsParticlesInternals.path=g.__tsParticlesInternals.path||{};g.__tsParticlesInternals.path=g.__tsParticlesInternals.path||{};g.__tsParticlesInternals.path.utils=g.__tsParticlesInternals.path.utils||{};var __tsProxyFactory=typeof Proxy!=="undefined"?function(obj){return new Proxy(obj,{get:function(target,key){if(!(key in target)){target[key]={};}return target[key];}});}:function(obj){return obj;};g.__tsParticlesInternals.bundles=__tsProxyFactory(g.__tsParticlesInternals.bundles);g.__tsParticlesInternals.effects=__tsProxyFactory(g.__tsParticlesInternals.effects);g.__tsParticlesInternals.interactions=__tsProxyFactory(g.__tsParticlesInternals.interactions);g.__tsParticlesInternals.palettes=__tsProxyFactory(g.__tsParticlesInternals.palettes);g.__tsParticlesInternals.paths=__tsProxyFactory(g.__tsParticlesInternals.paths);g.__tsParticlesInternals.plugins=__tsProxyFactory(g.__tsParticlesInternals.plugins);g.__tsParticlesInternals.plugins.emittersShapes=__tsProxyFactory(g.__tsParticlesInternals.plugins.emittersShapes);g.__tsParticlesInternals.presets=__tsProxyFactory(g.__tsParticlesInternals.presets);g.__tsParticlesInternals.shapes=__tsProxyFactory(g.__tsParticlesInternals.shapes);g.__tsParticlesInternals.updaters=__tsProxyFactory(g.__tsParticlesInternals.updaters);g.__tsParticlesInternals.utils=__tsProxyFactory(g.__tsParticlesInternals.utils);g.__tsParticlesInternals.canvas=__tsProxyFactory(g.__tsParticlesInternals.canvas);g.__tsParticlesInternals.path=__tsProxyFactory(g.__tsParticlesInternals.path);g.tsparticlesInternalExports=g.tsparticlesInternalExports||{};})(typeof globalThis!=="undefined"?globalThis:typeof window!=="undefined"?window:this);
2
- /* Preset v4.4.0 */
3
- (function (global, factory) {
4
- typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
5
- typeof define === 'function' && define.amd ? define(['exports'], factory) :
6
- (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory((global.__tsParticlesInternals = global.__tsParticlesInternals || {}, global.__tsParticlesInternals.presets = global.__tsParticlesInternals.presets || {}, global.__tsParticlesInternals.presets.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.0 */
4
+ g.__tsParticlesInternals = g.__tsParticlesInternals || {};
5
+ g.__tsParticlesInternals.presets = g.__tsParticlesInternals.presets || {};
6
+ (function (exports) {
7
+ 'use strict';
8
+
9
+ const errorPrefix = "tsParticles - Error", codedErrorPattern = /^\[tsParticles Error (TSP-\d+)\]\s*/, fullMatchIndex = 0, codeIndex = 1;
10
+ const wrap = (fn) => (...args) => {
11
+ fn(...args);
12
+ }, _logger = {
13
+ debug: wrap(console.debug),
14
+ error: (message, ...optionalParams) => {
15
+ if (typeof message === "string") {
16
+ const match = codedErrorPattern.exec(message);
17
+ if (match?.[codeIndex]) {
18
+ console.error(`tsParticles - ${match[codeIndex]} - ${message.slice(match[fullMatchIndex].length)}`, ...optionalParams);
19
+ return;
20
+ }
21
+ }
22
+ console.error(`${errorPrefix} - ${message}`, ...optionalParams);
23
+ },
24
+ info: wrap(console.info),
25
+ log: wrap(console.log),
26
+ trace: wrap(console.trace),
27
+ verbose: wrap(console.log),
28
+ warning: wrap(console.warn),
29
+ };
30
+ function getLogger() {
31
+ return _logger;
32
+ }
19
33
 
20
34
  var MoveDirection;
21
35
  (function (MoveDirection) {
@@ -32,6 +46,17 @@
32
46
  MoveDirection["inside"] = "inside";
33
47
  })(MoveDirection || (MoveDirection = {}));
34
48
 
49
+ const generatedAttribute = "generated", fullPercent = "100%", defaultCompositeValue = "source-over", resizeEvent = "resize", visibilityChangeEvent = "visibilitychange", percentDenominator = 100, half = 0.5, millisecondsToSeconds = 1000, originPoint = {
50
+ x: 0,
51
+ y: 0,
52
+ z: 0,
53
+ }, defaultTransform = {
54
+ a: 1,
55
+ b: 0,
56
+ c: 0,
57
+ d: 1,
58
+ }, randomColorValue = "random", double = 2, doublePI = Math.PI * double, defaultFps = 60, defaultAlpha = 1, generatedTrue = "true", generatedFalse = "false", canvasTag = "canvas", defaultRetryCount = 0, squareExp = 2, spatialHashGridCellSize = 100, defaultRemoveQuantity = 1, defaultRatio = 1, defaultReduceFactor = 1, inverseFactorNumerator = 1, rgbMax = 255, hMax = 360, sMax = 100, lMax = 100, hMin = 0, sMin = 0, hPhase = 60, empty = 0, quarter = 0.25, threeQuarter = half + quarter, minVelocity = 0, minDistance = 0, minRadius = 0, defaultTransformValue = 1, minimumSize = 0, zIndexFactorOffset = 1, defaultOpacity$1 = 1, removeDeleteCount = 1, removeMinIndex = 0, defaultFpsLimit = 120, minFpsLimit = 0, canvasFirstIndex = 0, loadRandomFactor = 10000, loadMinIndex = 0, one = 1, none = 0, decayOffset = 1, tryCountIncrement = 1, minZ = 0, minLimit = 0, countOffset = 1, minCount = 0, minIndex = 0, 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 {
@@ -573,7 +715,6 @@
573
715
  class PluginManager {
574
716
  colorManagers = new Map();
575
717
  easingFunctions = new Map();
576
- effectDrawers = new Map();
577
718
  initializers = {
578
719
  effects: new Map(),
579
720
  shapes: new Map(),
@@ -582,8 +723,6 @@
582
723
  palettes = new Map();
583
724
  plugins = [];
584
725
  presets = new Map();
585
- shapeDrawers = new Map();
586
- updaters = new Map();
587
726
  #allLoadersSet = new Set();
588
727
  #configs = new Map();
589
728
  #engine;
@@ -601,57 +740,79 @@
601
740
  }
602
741
  return res;
603
742
  }
743
+ get initialized() {
744
+ return this.#initialized;
745
+ }
604
746
  addColorManager(name, manager) {
747
+ if (this.#initialized) {
748
+ return;
749
+ }
605
750
  this.colorManagers.set(name, manager);
606
751
  }
607
752
  addConfig(config) {
753
+ if (this.#initialized) {
754
+ return;
755
+ }
608
756
  const key = config.key ?? config.name ?? "default";
609
757
  this.#configs.set(key, config);
610
758
  this.#engine.dispatchEvent(EventType.configAdded, { data: { name: key, config } });
611
759
  }
612
760
  addEasing(name, easing) {
761
+ if (this.#initialized) {
762
+ return;
763
+ }
613
764
  if (this.easingFunctions.get(name)) {
614
765
  return;
615
766
  }
616
767
  this.easingFunctions.set(name, easing);
617
768
  }
618
769
  addEffect(effect, drawer) {
770
+ if (this.#initialized) {
771
+ return;
772
+ }
619
773
  this.initializers.effects.set(effect, drawer);
620
774
  }
621
775
  addPalette(name, palette) {
776
+ if (this.#initialized) {
777
+ return;
778
+ }
622
779
  this.palettes.set(name, palette);
623
780
  }
624
781
  addParticleUpdater(name, updaterInitializer) {
782
+ if (this.#initialized) {
783
+ return;
784
+ }
625
785
  this.initializers.updaters.set(name, updaterInitializer);
626
786
  }
627
787
  addPlugin(plugin) {
788
+ if (this.#initialized) {
789
+ return;
790
+ }
628
791
  if (this.getPlugin(plugin.id)) {
629
792
  return;
630
793
  }
631
794
  this.plugins.push(plugin);
632
795
  }
633
796
  addPreset(preset, options, override = false) {
797
+ if (this.#initialized) {
798
+ return;
799
+ }
634
800
  if (!(override || !this.getPreset(preset))) {
635
801
  return;
636
802
  }
637
803
  this.presets.set(preset, options);
638
804
  }
639
805
  addShape(shapes, drawer) {
806
+ if (this.#initialized) {
807
+ return;
808
+ }
640
809
  for (const shape of shapes) {
641
810
  this.initializers.shapes.set(shape, drawer);
642
811
  }
643
812
  }
644
- clearPlugins(container) {
645
- this.effectDrawers.delete(container);
646
- this.shapeDrawers.delete(container);
647
- this.updaters.delete(container);
648
- }
649
813
  getEasing(name) {
650
814
  return this.easingFunctions.get(name) ?? ((value) => value);
651
815
  }
652
- getEffectDrawers(container, force = false) {
653
- return getItemMapFromInitializer(container, this.effectDrawers, this.initializers.effects, force);
654
- }
655
816
  getPalette(name) {
656
817
  return this.palettes.get(name);
657
818
  }
@@ -661,12 +822,6 @@
661
822
  getPreset(preset) {
662
823
  return this.presets.get(preset);
663
824
  }
664
- async getShapeDrawers(container, force = false) {
665
- return getItemMapFromInitializer(container, this.shapeDrawers, this.initializers.shapes, force);
666
- }
667
- async getUpdaters(container, force = false) {
668
- return getItemsFromInitializer(container, this.updaters, this.initializers.updaters, force);
669
- }
670
825
  async init() {
671
826
  if (this.#initialized || this.#isRunningLoaders) {
672
827
  return;
@@ -685,16 +840,9 @@
685
840
  this.#initialized = true;
686
841
  }
687
842
  }
688
- loadParticlesOptions(container, options, ...sourceOptions) {
689
- const updaters = this.updaters.get(container);
690
- if (!updaters) {
691
- return;
692
- }
693
- updaters.forEach(updater => updater.loadOptions?.(options, ...sourceOptions));
694
- }
695
843
  async register(...loaders) {
696
844
  if (this.#initialized) {
697
- throw new Error("Register plugins can only be done before calling tsParticles.load()");
845
+ throw new Error(getErrorMessage(ErrorCodes$1.pluginRegisterAfterLoad));
698
846
  }
699
847
  for (const loader of loaders) {
700
848
  if (this.#isRunningLoaders) {
@@ -706,88 +854,15 @@
706
854
  }
707
855
  }
708
856
  async #runLoader(loader, executed, allLoaders) {
709
- if (executed.has(loader))
857
+ if (executed.has(loader)) {
710
858
  return;
859
+ }
711
860
  executed.add(loader);
712
861
  allLoaders.add(loader);
713
862
  await loader(this.#engine);
714
863
  }
715
864
  }
716
865
 
717
- const errorPrefix = "tsParticles - Error";
718
- const wrap = (fn) => (...args) => {
719
- fn(...args);
720
- }, _logger = {
721
- debug: wrap(console.debug),
722
- error: (message, ...optionalParams) => {
723
- console.error(`${errorPrefix} - ${message}`, ...optionalParams);
724
- },
725
- info: wrap(console.info),
726
- log: wrap(console.log),
727
- trace: wrap(console.trace),
728
- verbose: wrap(console.log),
729
- warning: wrap(console.warn),
730
- };
731
- function getLogger() {
732
- return _logger;
733
- }
734
-
735
- const fullPercent = "100%";
736
- async function getDataFromUrl(data) {
737
- const url = itemFromSingleOrMultiple(data.url, data.index);
738
- if (!url) {
739
- return data.fallback;
740
- }
741
- const response = await fetch(url);
742
- if (response.ok) {
743
- return (await response.json());
744
- }
745
- getLogger().error(`${response.status.toString()} while retrieving config file`);
746
- return data.fallback;
747
- }
748
- const getCanvasFromContainer = (domContainer) => {
749
- const documentSafe = safeDocument();
750
- let canvasEl;
751
- const isCanvas = domContainer instanceof HTMLCanvasElement || domContainer.tagName.toLowerCase() === canvasTag;
752
- if (isCanvas) {
753
- canvasEl = domContainer;
754
- canvasEl.dataset[generatedAttribute] ??= generatedFalse;
755
- if (canvasEl.dataset[generatedAttribute] === generatedTrue) {
756
- canvasEl.style.width ||= fullPercent;
757
- canvasEl.style.height ||= fullPercent;
758
- canvasEl.style.pointerEvents = "none";
759
- canvasEl.style.setProperty("pointer-events", "none");
760
- }
761
- }
762
- else {
763
- const existingCanvases = domContainer.getElementsByTagName(canvasTag), foundCanvas = existingCanvases.item(canvasFirstIndex);
764
- if (foundCanvas) {
765
- canvasEl = foundCanvas;
766
- canvasEl.dataset[generatedAttribute] = generatedFalse;
767
- }
768
- else {
769
- canvasEl = documentSafe.createElement(canvasTag);
770
- canvasEl.dataset[generatedAttribute] = generatedTrue;
771
- domContainer.appendChild(canvasEl);
772
- }
773
- canvasEl.style.width ||= fullPercent;
774
- canvasEl.style.height ||= fullPercent;
775
- canvasEl.style.pointerEvents = "none";
776
- canvasEl.style.setProperty("pointer-events", "none");
777
- }
778
- return canvasEl;
779
- }, getDomContainer = (id, source) => {
780
- const documentSafe = safeDocument();
781
- let domContainer = source ?? documentSafe.getElementById(id);
782
- if (domContainer) {
783
- return domContainer;
784
- }
785
- domContainer = documentSafe.createElement("canvas");
786
- domContainer.id = id;
787
- domContainer.dataset[generatedAttribute] = generatedTrue;
788
- documentSafe.body.append(domContainer);
789
- return domContainer;
790
- };
791
866
  class Engine {
792
867
  pluginManager = new PluginManager(this);
793
868
  #domArray = [];
@@ -797,7 +872,7 @@
797
872
  return this.#domArray;
798
873
  }
799
874
  get version() {
800
- return "4.4.0";
875
+ return "4.5.0";
801
876
  }
802
877
  addEventListener(type, listener) {
803
878
  this.#eventDispatcher.addEventListener(type, listener);
@@ -806,7 +881,7 @@
806
881
  if (this.version === pluginVersion) {
807
882
  return;
808
883
  }
809
- throw new Error(`The tsParticles version is different from the loaded plugins version. Engine version: ${this.version}. Plugin version: ${pluginVersion}`);
884
+ throw new Error(getErrorMessage(ErrorCodes$1.engineVersionMismatch, this.version, pluginVersion));
810
885
  }
811
886
  dispatchEvent(type, args) {
812
887
  this.#eventDispatcher.dispatchEvent(type, args);
@@ -1055,20 +1130,6 @@
1055
1130
  DrawLayer[DrawLayer["Foreground"] = 7] = "Foreground";
1056
1131
  })(DrawLayer || (DrawLayer = {}));
1057
1132
 
1058
- class OptionLoader {
1059
- load(data) {
1060
- if (isNull(data)) {
1061
- return;
1062
- }
1063
- this.doLoad(data);
1064
- }
1065
- }
1066
- function loadOptions(options, ...sourceOptionsArr) {
1067
- for (const sourceOptions of sourceOptionsArr) {
1068
- options.load(sourceOptions);
1069
- }
1070
- }
1071
-
1072
1133
  function loadProperty(obj, key, value) {
1073
1134
  if (value !== undefined) {
1074
1135
  obj[key] = value;
@@ -1100,6 +1161,20 @@
1100
1161
  }
1101
1162
  }
1102
1163
 
1164
+ class OptionLoader {
1165
+ load(data) {
1166
+ if (isNull(data)) {
1167
+ return;
1168
+ }
1169
+ this.doLoad(data);
1170
+ }
1171
+ }
1172
+ function loadOptions(options, ...sourceOptionsArr) {
1173
+ for (const sourceOptions of sourceOptionsArr) {
1174
+ options.load(sourceOptions);
1175
+ }
1176
+ }
1177
+
1103
1178
  class AnimationOptions extends OptionLoader {
1104
1179
  count = 0;
1105
1180
  decay = 0;
@@ -1250,15 +1325,14 @@
1250
1325
  peakNits = defaultPeakNits;
1251
1326
  doLoad(data) {
1252
1327
  if (data.enable !== undefined && !isBoolean(data.enable)) {
1253
- throw new Error(`Invalid HDR "enable" value: expected a boolean, got "${String(data.enable)}"`);
1328
+ throw new Error(getErrorMessage(ErrorCodes$1.hdrEnableInvalid, String(data.enable)));
1254
1329
  }
1255
- if (data.mode !== undefined &&
1256
- (typeof data.mode !== "string" || !Object.values(HdrMode).includes(data.mode))) {
1257
- throw new Error(`Invalid HDR "mode" value: expected one of ${Object.values(HdrMode).join(", ")}, got "${toStringValue(data.mode)}"`);
1330
+ if (data.mode !== undefined && !isEnumValue(HdrMode, data.mode)) {
1331
+ throw new Error(getErrorMessage(ErrorCodes$1.hdrModeInvalid, Object.values(HdrMode).join(", "), toStringValue(data.mode)));
1258
1332
  }
1259
1333
  if (data.peakNits !== undefined &&
1260
1334
  (!isNumber(data.peakNits) || !Number.isFinite(data.peakNits) || data.peakNits <= minPeakNits)) {
1261
- throw new Error(`Invalid HDR "peakNits" value: expected a positive number, got "${String(data.peakNits)}"`);
1335
+ throw new Error(getErrorMessage(ErrorCodes$1.hdrPeakNitsInvalid, String(data.peakNits)));
1262
1336
  }
1263
1337
  loadProperty(this, "enable", data.enable);
1264
1338
  loadProperty(this, "mode", data.mode);
@@ -1636,12 +1710,10 @@
1636
1710
  plugin.loadParticlesOptions(this.#container, this, data);
1637
1711
  }
1638
1712
  }
1639
- const updaters = this.#pluginManager.updaters.get(this.#container);
1640
- if (updaters) {
1641
- for (const updater of updaters) {
1642
- if (updater.loadOptions) {
1643
- updater.loadOptions(this, data);
1644
- }
1713
+ const updaters = this.#container.particleUpdaters;
1714
+ for (const updater of updaters) {
1715
+ if (updater.loadOptions) {
1716
+ updater.loadOptions(this, data);
1645
1717
  }
1646
1718
  }
1647
1719
  }
@@ -1974,9 +2046,9 @@
1974
2046
  const grayscaleValue = Math.round(lNormalized * rgbMax);
1975
2047
  return { r: grayscaleValue, g: grayscaleValue, b: grayscaleValue };
1976
2048
  }
1977
- const temp1 = lNormalized < half
2049
+ const temp2 = lNormalized < half
1978
2050
  ? lNormalized * (sNormalizedOffset + sNormalized)
1979
- : lNormalized + sNormalized - lNormalized * sNormalized, temp2 = double * lNormalized - temp1, phaseThird = phaseNumerator / triple, red = Math.min(rgbMax, rgbMax * hslChannel(temp2, temp1, hNormalized + phaseThird)), green = Math.min(rgbMax, rgbMax * hslChannel(temp2, temp1, hNormalized)), blue = Math.min(rgbMax, rgbMax * hslChannel(temp2, temp1, hNormalized - phaseThird));
2051
+ : lNormalized + sNormalized - lNormalized * sNormalized, temp1 = double * lNormalized - temp2, phaseThird = phaseNumerator / triple, red = Math.min(rgbMax, rgbMax * hslChannel(temp1, temp2, hNormalized + phaseThird)), green = Math.min(rgbMax, rgbMax * hslChannel(temp1, temp2, hNormalized)), blue = Math.min(rgbMax, rgbMax * hslChannel(temp1, temp2, hNormalized - phaseThird));
1980
2052
  return { r: Math.round(red), g: Math.round(green), b: Math.round(blue) };
1981
2053
  }
1982
2054
  function hslToRgbFloat(hsl) {
@@ -1985,9 +2057,9 @@
1985
2057
  const grayscaleValue = lNormalized * rgbMax;
1986
2058
  return { r: grayscaleValue, g: grayscaleValue, b: grayscaleValue };
1987
2059
  }
1988
- const temp1 = lNormalized < half
2060
+ const temp2 = lNormalized < half
1989
2061
  ? lNormalized * (sNormalizedOffset + sNormalized)
1990
- : lNormalized + sNormalized - lNormalized * sNormalized, temp2 = double * lNormalized - temp1, phaseThird = phaseNumerator / triple, red = Math.min(rgbMax, rgbMax * hslChannel(temp2, temp1, hNormalized + phaseThird)), green = Math.min(rgbMax, rgbMax * hslChannel(temp2, temp1, hNormalized)), blue = Math.min(rgbMax, rgbMax * hslChannel(temp2, temp1, hNormalized - phaseThird));
2062
+ : lNormalized + sNormalized - lNormalized * sNormalized, temp1 = double * lNormalized - temp2, phaseThird = phaseNumerator / triple, red = Math.min(rgbMax, rgbMax * hslChannel(temp1, temp2, hNormalized + phaseThird)), green = Math.min(rgbMax, rgbMax * hslChannel(temp1, temp2, hNormalized)), blue = Math.min(rgbMax, rgbMax * hslChannel(temp1, temp2, hNormalized - phaseThird));
1991
2063
  return { r: red, g: green, b: blue };
1992
2064
  }
1993
2065
  function hslaToRgba(hsla) {
@@ -2201,7 +2273,7 @@
2201
2273
  }
2202
2274
 
2203
2275
  async function loadBlendPlugin(engine) {
2204
- engine.checkVersion("4.4.0");
2276
+ engine.checkVersion("4.5.0");
2205
2277
  await engine.pluginManager.register(e => {
2206
2278
  e.pluginManager.addPlugin(new BlendPlugin());
2207
2279
  });
@@ -2238,7 +2310,7 @@
2238
2310
  }
2239
2311
 
2240
2312
  async function loadCircleShape(engine) {
2241
- engine.checkVersion("4.4.0");
2313
+ engine.checkVersion("4.5.0");
2242
2314
  await engine.pluginManager.register(e => {
2243
2315
  e.pluginManager.addShape(["circle"], () => {
2244
2316
  return Promise.resolve(new CircleDrawer());
@@ -2253,7 +2325,7 @@
2253
2325
  RgbIndexes[RgbIndexes["b"] = 3] = "b";
2254
2326
  RgbIndexes[RgbIndexes["a"] = 4] = "a";
2255
2327
  })(RgbIndexes$1 || (RgbIndexes$1 = {}));
2256
- const shorthandHexRegex = /^#?([a-f\d])([a-f\d])([a-f\d])([a-f\d])?$/i, hexRegex = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})?$/i, hexRadix = 16, defaultAlpha = 1, alphaFactor = 0xff;
2328
+ const shorthandHexRegex = /^#?([a-f\d])([a-f\d])([a-f\d])([a-f\d])?$/i, hexRegex = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})?$/i, hexRadix = 16, alphaFactor = 0xff;
2257
2329
  class HexColorManager {
2258
2330
  accepts(input) {
2259
2331
  return input.startsWith("#");
@@ -2286,7 +2358,7 @@
2286
2358
  }
2287
2359
 
2288
2360
  async function loadHexColorPlugin(engine) {
2289
- engine.checkVersion("4.4.0");
2361
+ engine.checkVersion("4.5.0");
2290
2362
  await engine.pluginManager.register(e => {
2291
2363
  e.pluginManager.addColorManager("hex", new HexColorManager());
2292
2364
  });
@@ -2326,7 +2398,7 @@
2326
2398
  if (!this.accepts(input)) {
2327
2399
  return;
2328
2400
  }
2329
- const result = hslRegex.exec(input), minLength = 4, defaultAlpha = 1, radix = 10;
2401
+ const result = hslRegex.exec(input), minLength = 4, radix = 10;
2330
2402
  return result
2331
2403
  ? hslaToRgba({
2332
2404
  a: result.length > minLength ? parseAlpha(result[HslIndexes.a]) : defaultAlpha,
@@ -2339,12 +2411,20 @@
2339
2411
  }
2340
2412
 
2341
2413
  async function loadHslColorPlugin(engine) {
2342
- engine.checkVersion("4.4.0");
2414
+ engine.checkVersion("4.5.0");
2343
2415
  await engine.pluginManager.register(e => {
2344
2416
  e.pluginManager.addColorManager("hsl", new HslColorManager());
2345
2417
  });
2346
2418
  }
2347
2419
 
2420
+ const ErrorCodes = {
2421
+ baseMoverNotLoaded: "TSP-3203",
2422
+ };
2423
+
2424
+ const ErrorMessages = {
2425
+ [ErrorCodes.baseMoverNotLoaded]: "tsParticles Base Mover is not loaded",
2426
+ };
2427
+
2348
2428
  class MovePlugin {
2349
2429
  id = "move";
2350
2430
  #pluginManager;
@@ -2363,20 +2443,20 @@
2363
2443
  }
2364
2444
 
2365
2445
  async function loadMovePlugin(engine) {
2366
- engine.checkVersion("4.4.0");
2446
+ engine.checkVersion("4.5.0");
2447
+ if (typeof process !== "undefined" && process.env.NODE_ENV !== "production") {
2448
+ addErrorMessages(ErrorMessages);
2449
+ }
2367
2450
  await engine.pluginManager.register(e => {
2368
2451
  const moveEngine = e, movePluginManager = moveEngine.pluginManager;
2369
2452
  movePluginManager.initializers.pathGenerators ??= new Map();
2370
- movePluginManager.pathGenerators ??= new Map();
2371
2453
  movePluginManager.addPathGenerator = (name, generator) => {
2454
+ if (movePluginManager.initialized) {
2455
+ return;
2456
+ }
2372
2457
  movePluginManager.initializers.pathGenerators ??= new Map();
2373
2458
  movePluginManager.initializers.pathGenerators.set(name, generator);
2374
2459
  };
2375
- movePluginManager.getPathGenerators = async (container, force = false) => {
2376
- movePluginManager.initializers.pathGenerators ??= new Map();
2377
- movePluginManager.pathGenerators ??= new Map();
2378
- return getItemMapFromInitializer(container, movePluginManager.pathGenerators, movePluginManager.initializers.pathGenerators, force);
2379
- };
2380
2460
  e.pluginManager.addPlugin(new MovePlugin(e.pluginManager));
2381
2461
  });
2382
2462
  }
@@ -2573,7 +2653,7 @@
2573
2653
  }
2574
2654
 
2575
2655
  async function loadOpacityUpdater(engine) {
2576
- engine.checkVersion("4.4.0");
2656
+ engine.checkVersion("4.5.0");
2577
2657
  await engine.pluginManager.register(e => {
2578
2658
  e.pluginManager.addParticleUpdater("opacity", container => {
2579
2659
  return Promise.resolve(new OpacityUpdater(container));
@@ -2582,70 +2662,60 @@
2582
2662
  }
2583
2663
 
2584
2664
  const boundsMin = 0;
2585
- function bounceHorizontal(data) {
2586
- if ((data.outMode !== OutMode.bounce && data.outMode !== OutMode.split) ||
2587
- (data.direction !== OutModeDirection.left && data.direction !== OutModeDirection.right)) {
2588
- return;
2589
- }
2590
- if (data.bounds.right < boundsMin && data.direction === OutModeDirection.left) {
2591
- data.particle.position.x = data.size + data.offset.x;
2592
- }
2593
- else if (data.bounds.left > data.canvasSize.width && data.direction === OutModeDirection.right) {
2594
- data.particle.position.x = data.canvasSize.width - data.size - data.offset.x;
2595
- }
2596
- const velocity = data.particle.velocity.x;
2597
- let bounced = false;
2598
- if (data.outOfCanvas &&
2599
- ((data.direction === OutModeDirection.right && velocity > minVelocity) ||
2600
- (data.direction === OutModeDirection.left && velocity < minVelocity))) {
2601
- const newVelocity = getRangeValue(data.particle.options.bounce.horizontal.value);
2602
- data.particle.velocity.x *= -newVelocity;
2603
- bounced = true;
2604
- }
2605
- if (!bounced) {
2606
- return;
2607
- }
2608
- const minPos = data.offset.x + data.size;
2609
- if (data.outOfCanvas && data.direction === OutModeDirection.right) {
2610
- data.particle.position.x = data.canvasSize.width - minPos;
2611
- }
2612
- else if (data.outOfCanvas && data.direction === OutModeDirection.left) {
2613
- data.particle.position.x = minPos;
2614
- }
2615
- if (data.outMode === OutMode.split) {
2616
- data.particle.destroy();
2617
- }
2618
- }
2619
- function bounceVertical(data) {
2620
- if ((data.outMode !== OutMode.bounce && data.outMode !== OutMode.split) ||
2621
- (data.direction !== OutModeDirection.bottom && data.direction !== OutModeDirection.top)) {
2665
+ const bounceAxisConfigs = {
2666
+ [OutModeDirection.left]: {
2667
+ axis: "x",
2668
+ canvas: "width",
2669
+ bounce: "horizontal",
2670
+ negativeEdge: "right",
2671
+ positiveEdge: "left",
2672
+ negative: true,
2673
+ },
2674
+ [OutModeDirection.right]: {
2675
+ axis: "x",
2676
+ canvas: "width",
2677
+ bounce: "horizontal",
2678
+ negativeEdge: "right",
2679
+ positiveEdge: "left",
2680
+ negative: false,
2681
+ },
2682
+ [OutModeDirection.top]: {
2683
+ axis: "y",
2684
+ canvas: "height",
2685
+ bounce: "vertical",
2686
+ negativeEdge: "bottom",
2687
+ positiveEdge: "top",
2688
+ negative: true,
2689
+ },
2690
+ [OutModeDirection.bottom]: {
2691
+ axis: "y",
2692
+ canvas: "height",
2693
+ bounce: "vertical",
2694
+ negativeEdge: "bottom",
2695
+ positiveEdge: "top",
2696
+ negative: false,
2697
+ },
2698
+ };
2699
+ function bounce(data) {
2700
+ if ((data.outMode !== OutMode.bounce && data.outMode !== OutMode.split) || !(data.direction in bounceAxisConfigs)) {
2622
2701
  return;
2623
2702
  }
2624
- if (data.bounds.bottom < boundsMin && data.direction === OutModeDirection.top) {
2625
- data.particle.position.y = data.size + data.offset.y;
2703
+ const config = bounceAxisConfigs[data.direction], bounds = data.bounds, canvasDim = data.canvasSize[config.canvas], position = data.particle.position, velocity = data.particle.velocity[config.axis];
2704
+ if (config.negative && bounds[config.negativeEdge] < boundsMin) {
2705
+ position[config.axis] = data.size + data.offset[config.axis];
2626
2706
  }
2627
- else if (data.bounds.top > data.canvasSize.height && data.direction === OutModeDirection.bottom) {
2628
- data.particle.position.y = data.canvasSize.height - data.size - data.offset.y;
2707
+ else if (!config.negative && bounds[config.positiveEdge] > canvasDim) {
2708
+ position[config.axis] = canvasDim - data.size - data.offset[config.axis];
2629
2709
  }
2630
- const velocity = data.particle.velocity.y;
2631
- let bounced = false;
2632
2710
  if (data.outOfCanvas &&
2633
- ((data.direction === OutModeDirection.bottom && velocity > minVelocity) ||
2634
- (data.direction === OutModeDirection.top && velocity < minVelocity))) {
2635
- const newVelocity = getRangeValue(data.particle.options.bounce.vertical.value);
2636
- data.particle.velocity.y *= -newVelocity;
2637
- bounced = true;
2711
+ ((config.negative && velocity < minVelocity) || (!config.negative && velocity > minVelocity))) {
2712
+ data.particle.velocity[config.axis] *= -getRangeValue(data.particle.options.bounce[config.bounce].value);
2638
2713
  }
2639
- if (!bounced) {
2714
+ else {
2640
2715
  return;
2641
2716
  }
2642
- const minPos = data.offset.y + data.size;
2643
- if (data.outOfCanvas && data.direction === OutModeDirection.bottom) {
2644
- data.particle.position.y = data.canvasSize.height - minPos;
2645
- }
2646
- else if (data.outOfCanvas && data.direction === OutModeDirection.top) {
2647
- data.particle.position.y = minPos;
2648
- }
2717
+ const minPos = data.offset[config.axis] + data.size;
2718
+ position[config.axis] = config.negative ? minPos : canvasDim - minPos;
2649
2719
  if (data.outMode === OutMode.split) {
2650
2720
  data.particle.destroy();
2651
2721
  }
@@ -2661,26 +2731,19 @@
2661
2731
  OutMode.bounce,
2662
2732
  OutMode.split,
2663
2733
  ];
2664
- this.#particleBouncePlugins = container.plugins.filter(p => p.particleBounce !== undefined);
2734
+ this.#particleBouncePlugins = container.plugins.filter(p => !!p.particleBounce);
2665
2735
  }
2666
2736
  update(particle, direction, delta, outMode) {
2667
2737
  if (!this.modes.includes(outMode)) {
2668
2738
  return;
2669
2739
  }
2670
- const container = this.#container;
2671
- let handled = false;
2672
2740
  for (const plugin of this.#particleBouncePlugins) {
2673
- handled = plugin.particleBounce?.(particle, delta, direction) ?? false;
2674
- if (handled) {
2675
- break;
2741
+ if (plugin.particleBounce?.(particle, delta, direction)) {
2742
+ return;
2676
2743
  }
2677
2744
  }
2678
- if (handled) {
2679
- return;
2680
- }
2681
- const pos = particle.getPosition(), offset = particle.offset, size = particle.getRadius(), bounds = calculateBounds(pos, size), canvasSize = container.canvas.size, outOfCanvas = !particle.isInsideCanvasForOutMode(outMode, direction);
2682
- bounceHorizontal({ particle, outMode, direction, bounds, canvasSize, offset, outOfCanvas, size });
2683
- bounceVertical({ particle, outMode, direction, bounds, canvasSize, offset, outOfCanvas, size });
2745
+ const pos = particle.getPosition(), offset = particle.offset, size = particle.getRadius(), bounds = calculateBounds(pos, size), canvasSize = this.#container.canvas.size, outOfCanvas = !particle.isInsideCanvasForOutMode(outMode, direction);
2746
+ bounce({ particle, outMode, direction, bounds, canvasSize, offset, outOfCanvas, size });
2684
2747
  }
2685
2748
  }
2686
2749
 
@@ -2769,107 +2832,108 @@
2769
2832
  return;
2770
2833
  }
2771
2834
  const container = this.#container;
2772
- switch (particle.outType) {
2773
- case ParticleOutType.inside: {
2774
- const { x: vx, y: vy } = particle.velocity;
2775
- updateVector.setTo(originPoint);
2776
- updateVector.length = particle.moveCenter.radius;
2777
- updateVector.angle = particle.velocity.angle + Math.PI;
2778
- updateVector.addTo(particle.moveCenter);
2779
- const { dx, dy } = getDistances(particle.position, updateVector);
2780
- if ((vx <= minVelocity && dx >= minDistance) ||
2781
- (vy <= minVelocity && dy >= minDistance) ||
2782
- (vx >= minVelocity && dx <= minDistance) ||
2783
- (vy >= minVelocity && dy <= minDistance)) {
2784
- return;
2785
- }
2786
- particle.position.x = Math.floor(randomInRangeValue({
2787
- min: 0,
2788
- max: container.canvas.size.width,
2789
- }));
2790
- particle.position.y = Math.floor(randomInRangeValue({
2791
- min: 0,
2792
- max: container.canvas.size.height,
2793
- }));
2794
- const { dx: newDx, dy: newDy } = getDistances(particle.position, particle.moveCenter);
2795
- particle.direction = Math.atan2(-newDy, -newDx);
2796
- particle.velocity.angle = particle.direction;
2797
- particle.justWarped = true;
2798
- break;
2835
+ if (particle.outType === ParticleOutType.inside) {
2836
+ this.#applyOutModeInside(particle, container);
2837
+ }
2838
+ else {
2839
+ if (particle.isInsideCanvasForOutMode(outMode, direction)) {
2840
+ return;
2799
2841
  }
2800
- default: {
2801
- if (particle.isInsideCanvasForOutMode(outMode, direction)) {
2802
- return;
2803
- }
2804
- switch (particle.outType) {
2805
- case ParticleOutType.outside: {
2806
- particle.position.x =
2807
- Math.floor(randomInRangeValue({
2808
- min: -particle.moveCenter.radius,
2809
- max: particle.moveCenter.radius,
2810
- })) + particle.moveCenter.x;
2811
- particle.position.y =
2812
- Math.floor(randomInRangeValue({
2813
- min: -particle.moveCenter.radius,
2814
- max: particle.moveCenter.radius,
2815
- })) + particle.moveCenter.y;
2816
- const { dx, dy } = getDistances(particle.position, particle.moveCenter);
2817
- if (particle.moveCenter.radius) {
2818
- particle.direction = Math.atan2(dy, dx);
2819
- particle.velocity.angle = particle.direction;
2820
- }
2821
- particle.justWarped = true;
2822
- break;
2823
- }
2824
- case ParticleOutType.normal: {
2825
- const warp = particle.options.move.warp, canvasSize = container.canvas.size, newPos = {
2826
- bottom: canvasSize.height + particle.getRadius() + particle.offset.y,
2827
- left: -particle.getRadius() - particle.offset.x,
2828
- right: canvasSize.width + particle.getRadius() + particle.offset.x,
2829
- top: -particle.getRadius() - particle.offset.y,
2830
- }, sizeValue = particle.getRadius(), nextBounds = calculateBounds(particle.position, sizeValue);
2831
- if (direction === OutModeDirection.right && nextBounds.left > canvasSize.width + particle.offset.x) {
2832
- particle.position.x = newPos.left;
2833
- particle.initialPosition.x = particle.position.x;
2834
- if (!warp) {
2835
- particle.position.y = getRandom() * canvasSize.height;
2836
- particle.initialPosition.y = particle.position.y;
2837
- }
2838
- particle.justWarped = true;
2839
- }
2840
- else if (direction === OutModeDirection.left && nextBounds.right < -particle.offset.x) {
2841
- particle.position.x = newPos.right;
2842
- particle.initialPosition.x = particle.position.x;
2843
- if (!warp) {
2844
- particle.position.y = getRandom() * canvasSize.height;
2845
- particle.initialPosition.y = particle.position.y;
2846
- }
2847
- particle.justWarped = true;
2848
- }
2849
- if (direction === OutModeDirection.bottom && nextBounds.top > canvasSize.height + particle.offset.y) {
2850
- if (!warp) {
2851
- particle.position.x = getRandom() * canvasSize.width;
2852
- particle.initialPosition.x = particle.position.x;
2853
- }
2854
- particle.position.y = newPos.top;
2855
- particle.initialPosition.y = particle.position.y;
2856
- particle.justWarped = true;
2857
- }
2858
- else if (direction === OutModeDirection.top && nextBounds.bottom < -particle.offset.y) {
2859
- if (!warp) {
2860
- particle.position.x = getRandom() * canvasSize.width;
2861
- particle.initialPosition.x = particle.position.x;
2862
- }
2863
- particle.position.y = newPos.bottom;
2864
- particle.initialPosition.y = particle.position.y;
2865
- particle.justWarped = true;
2866
- }
2867
- break;
2868
- }
2869
- }
2870
- break;
2842
+ if (particle.outType === ParticleOutType.outside) {
2843
+ this.#applyParticleModeOutside(particle);
2871
2844
  }
2845
+ else {
2846
+ this.#applyOutModeNormal(particle, container, direction);
2847
+ }
2848
+ }
2849
+ }
2850
+ #applyOutModeInside(particle, container) {
2851
+ const { x: vx, y: vy } = particle.velocity;
2852
+ updateVector.setTo(originPoint);
2853
+ updateVector.length = particle.moveCenter.radius;
2854
+ updateVector.angle = particle.velocity.angle + Math.PI;
2855
+ updateVector.addTo(particle.moveCenter);
2856
+ const { dx, dy } = getDistances(particle.position, updateVector);
2857
+ if ((vx <= minVelocity && dx >= minDistance) ||
2858
+ (vy <= minVelocity && dy >= minDistance) ||
2859
+ (vx >= minVelocity && dx <= minDistance) ||
2860
+ (vy >= minVelocity && dy <= minDistance)) {
2861
+ return;
2872
2862
  }
2863
+ particle.position.x = Math.floor(randomInRangeValue({
2864
+ min: 0,
2865
+ max: container.canvas.size.width,
2866
+ }));
2867
+ particle.position.y = Math.floor(randomInRangeValue({
2868
+ min: 0,
2869
+ max: container.canvas.size.height,
2870
+ }));
2871
+ const { dx: newDx, dy: newDy } = getDistances(particle.position, particle.moveCenter);
2872
+ particle.direction = Math.atan2(-newDy, -newDx);
2873
+ particle.velocity.angle = particle.direction;
2874
+ particle.justWarped = true;
2875
+ }
2876
+ #applyOutModeNormal(particle, container, direction) {
2877
+ const warp = particle.options.move.warp, canvasSize = container.canvas.size, sizeValue = particle.getRadius(), newPos = {
2878
+ bottom: canvasSize.height + sizeValue + particle.offset.y,
2879
+ left: -sizeValue - particle.offset.x,
2880
+ right: canvasSize.width + sizeValue + particle.offset.x,
2881
+ top: -sizeValue - particle.offset.y,
2882
+ }, nextBounds = calculateBounds(particle.position, sizeValue);
2883
+ if (direction === OutModeDirection.right && nextBounds.left > canvasSize.width + particle.offset.x) {
2884
+ particle.position.x = newPos.left;
2885
+ particle.initialPosition.x = particle.position.x;
2886
+ if (!warp) {
2887
+ particle.position.y = getRandom() * canvasSize.height;
2888
+ particle.initialPosition.y = particle.position.y;
2889
+ }
2890
+ particle.justWarped = true;
2891
+ }
2892
+ else if (direction === OutModeDirection.left && nextBounds.right < -particle.offset.x) {
2893
+ particle.position.x = newPos.right;
2894
+ particle.initialPosition.x = particle.position.x;
2895
+ if (!warp) {
2896
+ particle.position.y = getRandom() * canvasSize.height;
2897
+ particle.initialPosition.y = particle.position.y;
2898
+ }
2899
+ particle.justWarped = true;
2900
+ }
2901
+ if (direction === OutModeDirection.bottom && nextBounds.top > canvasSize.height + particle.offset.y) {
2902
+ if (!warp) {
2903
+ particle.position.x = getRandom() * canvasSize.width;
2904
+ particle.initialPosition.x = particle.position.x;
2905
+ }
2906
+ particle.position.y = newPos.top;
2907
+ particle.initialPosition.y = particle.position.y;
2908
+ particle.justWarped = true;
2909
+ }
2910
+ else if (direction === OutModeDirection.top && nextBounds.bottom < -particle.offset.y) {
2911
+ if (!warp) {
2912
+ particle.position.x = getRandom() * canvasSize.width;
2913
+ particle.initialPosition.x = particle.position.x;
2914
+ }
2915
+ particle.position.y = newPos.bottom;
2916
+ particle.initialPosition.y = particle.position.y;
2917
+ particle.justWarped = true;
2918
+ }
2919
+ }
2920
+ #applyParticleModeOutside(particle) {
2921
+ particle.position.x =
2922
+ Math.floor(randomInRangeValue({
2923
+ min: -particle.moveCenter.radius,
2924
+ max: particle.moveCenter.radius,
2925
+ })) + particle.moveCenter.x;
2926
+ particle.position.y =
2927
+ Math.floor(randomInRangeValue({
2928
+ min: -particle.moveCenter.radius,
2929
+ max: particle.moveCenter.radius,
2930
+ })) + particle.moveCenter.y;
2931
+ const { dx, dy } = getDistances(particle.position, particle.moveCenter);
2932
+ if (particle.moveCenter.radius) {
2933
+ particle.direction = Math.atan2(dy, dx);
2934
+ particle.velocity.angle = particle.direction;
2935
+ }
2936
+ particle.justWarped = true;
2873
2937
  }
2874
2938
  }
2875
2939
 
@@ -2918,56 +2982,26 @@
2918
2982
  }
2919
2983
 
2920
2984
  async function loadOutModesUpdater(engine) {
2921
- engine.checkVersion("4.4.0");
2985
+ engine.checkVersion("4.5.0");
2922
2986
  await engine.pluginManager.register(e => {
2923
2987
  e.pluginManager.addParticleUpdater("outModes", container => {
2924
2988
  return Promise.resolve(new OutOfCanvasUpdater(container));
2925
2989
  });
2926
2990
  });
2927
2991
  }
2928
-
2929
- const defaultOpacity = 1;
2930
- class PaintUpdater {
2931
- #container;
2932
- #pluginManager;
2933
- constructor(pluginManager, container) {
2934
- this.#container = container;
2935
- this.#pluginManager = pluginManager;
2936
- }
2937
- init(particle) {
2938
- const container = this.#container, options = particle.options, paint = itemFromSingleOrMultiple(options.paint, particle.id, options.reduceDuplicates), color = paint?.color, paintColor = color ?? undefined, fill = paint?.fill, stroke = paint?.stroke;
2939
- if (fill) {
2940
- const fillColor = AnimatableColor.create(paintColor === undefined ? undefined : AnimatableColor.create(undefined, paintColor), fill.color);
2941
- particle.fillEnabled = fill.enable;
2942
- particle.fillOpacity = getRangeValue(fill.opacity);
2943
- particle.fillAnimation = fillColor.animation;
2944
- const fillHslColor = rangeColorToHsl(this.#pluginManager, fillColor);
2945
- if (fillHslColor) {
2946
- particle.fillColor = getHslAnimationFromHsl(fillHslColor, particle.fillAnimation, container.retina.reduceFactor);
2947
- }
2948
- }
2949
- else {
2950
- particle.fillEnabled = false;
2951
- particle.fillAnimation = undefined;
2952
- particle.fillColor = undefined;
2953
- particle.fillOpacity = defaultOpacity;
2954
- }
2955
- if (stroke) {
2956
- const strokeColor = AnimatableColor.create(paintColor === undefined ? undefined : AnimatableColor.create(undefined, paintColor), stroke.color);
2957
- particle.strokeWidth = getRangeValue(stroke.width) * container.retina.pixelRatio;
2958
- particle.strokeOpacity = getRangeValue(stroke.opacity ?? defaultOpacity);
2959
- particle.strokeAnimation = strokeColor.animation;
2960
- const strokeHslColor = rangeColorToHsl(this.#pluginManager, strokeColor) ?? particle.getFillColor();
2961
- if (strokeHslColor) {
2962
- particle.strokeColor = getHslAnimationFromHsl(strokeHslColor, particle.strokeAnimation, container.retina.reduceFactor);
2963
- }
2964
- }
2965
- else {
2966
- particle.strokeAnimation = undefined;
2967
- particle.strokeColor = undefined;
2968
- particle.strokeOpacity = defaultOpacity;
2969
- particle.strokeWidth = 0;
2970
- }
2992
+
2993
+ const defaultOpacity = 1;
2994
+ class PaintUpdater {
2995
+ #container;
2996
+ #pluginManager;
2997
+ constructor(pluginManager, container) {
2998
+ this.#container = container;
2999
+ this.#pluginManager = pluginManager;
3000
+ }
3001
+ init(particle) {
3002
+ const container = this.#container, options = particle.options, paint = itemFromSingleOrMultiple(options.paint, particle.id, options.reduceDuplicates);
3003
+ this.#initFill(paint, particle, container);
3004
+ this.#initStroke(paint, particle, container);
2971
3005
  }
2972
3006
  isEnabled(particle) {
2973
3007
  const { fillAnimation, fillColor, strokeAnimation, strokeColor } = particle, fillEnabled = !!fillAnimation &&
@@ -2986,10 +3020,48 @@
2986
3020
  updateColor(particle.fillColor, delta, this.#container.hdr);
2987
3021
  updateColor(particle.strokeColor, delta, this.#container.hdr);
2988
3022
  }
3023
+ #initFill(paint, particle, container) {
3024
+ const fill = paint?.fill, color = paint?.color, paintColor = color ?? undefined;
3025
+ if (!fill) {
3026
+ particle.fillEnabled = false;
3027
+ particle.fillAnimation = undefined;
3028
+ particle.fillColor = undefined;
3029
+ particle.fillOpacity = defaultOpacity;
3030
+ return;
3031
+ }
3032
+ const fillColor = AnimatableColor.create(paintColor === undefined ? undefined : AnimatableColor.create(undefined, paintColor), fill.color);
3033
+ particle.fillEnabled = fill.enable;
3034
+ particle.fillOpacity = getRangeValue(fill.opacity);
3035
+ particle.fillAnimation = fillColor.animation;
3036
+ const fillHslColor = rangeColorToHsl(this.#pluginManager, fillColor);
3037
+ if (!fillHslColor) {
3038
+ return;
3039
+ }
3040
+ particle.fillColor = getHslAnimationFromHsl(fillHslColor, particle.fillAnimation, container.retina.reduceFactor);
3041
+ }
3042
+ #initStroke(paint, particle, container) {
3043
+ const stroke = paint?.stroke, color = paint?.color, paintColor = color ?? undefined;
3044
+ if (!stroke) {
3045
+ particle.strokeAnimation = undefined;
3046
+ particle.strokeColor = undefined;
3047
+ particle.strokeOpacity = defaultOpacity;
3048
+ particle.strokeWidth = 0;
3049
+ return;
3050
+ }
3051
+ const strokeColor = AnimatableColor.create(paintColor === undefined ? undefined : AnimatableColor.create(undefined, paintColor), stroke.color);
3052
+ particle.strokeWidth = getRangeValue(stroke.width) * container.retina.pixelRatio;
3053
+ particle.strokeOpacity = getRangeValue(stroke.opacity ?? defaultOpacity);
3054
+ particle.strokeAnimation = strokeColor.animation;
3055
+ const strokeHslColor = rangeColorToHsl(this.#pluginManager, strokeColor) ?? particle.getFillColor();
3056
+ if (!strokeHslColor) {
3057
+ return;
3058
+ }
3059
+ particle.strokeColor = getHslAnimationFromHsl(strokeHslColor, particle.strokeAnimation, container.retina.reduceFactor);
3060
+ }
2989
3061
  }
2990
3062
 
2991
3063
  async function loadPaintUpdater(engine) {
2992
- engine.checkVersion("4.4.0");
3064
+ engine.checkVersion("4.5.0");
2993
3065
  await engine.pluginManager.register(e => {
2994
3066
  e.pluginManager.addParticleUpdater("paint", container => {
2995
3067
  return Promise.resolve(new PaintUpdater(e.pluginManager, container));
@@ -3031,7 +3103,7 @@
3031
3103
  if (!this.accepts(input)) {
3032
3104
  return;
3033
3105
  }
3034
- const result = rgbRegex.exec(input), radix = 10, minLength = 4, defaultAlpha = 1;
3106
+ const result = rgbRegex.exec(input), radix = 10, minLength = 4;
3035
3107
  return result
3036
3108
  ? {
3037
3109
  a: result.length > minLength ? parseAlpha(result[RgbIndexes.a]) : defaultAlpha,
@@ -3044,7 +3116,7 @@
3044
3116
  }
3045
3117
 
3046
3118
  async function loadRgbColorPlugin(engine) {
3047
- engine.checkVersion("4.4.0");
3119
+ engine.checkVersion("4.5.0");
3048
3120
  await engine.pluginManager.register(e => {
3049
3121
  e.pluginManager.addColorManager("rgb", new RgbColorManager());
3050
3122
  });
@@ -3129,7 +3201,7 @@
3129
3201
  }
3130
3202
 
3131
3203
  async function loadSizeUpdater(engine) {
3132
- engine.checkVersion("4.4.0");
3204
+ engine.checkVersion("4.5.0");
3133
3205
  await engine.pluginManager.register(e => {
3134
3206
  e.pluginManager.addParticleUpdater("size", container => {
3135
3207
  return Promise.resolve(new SizeUpdater(container));
@@ -3138,7 +3210,7 @@
3138
3210
  }
3139
3211
 
3140
3212
  async function loadBasic(engine) {
3141
- engine.checkVersion("4.4.0");
3213
+ engine.checkVersion("4.5.0");
3142
3214
  await engine.pluginManager.register(async (e) => {
3143
3215
  await Promise.all([
3144
3216
  loadBlendPlugin(e),
@@ -3370,7 +3442,7 @@
3370
3442
  }
3371
3443
 
3372
3444
  async function loadMatrixShape(engine) {
3373
- engine.checkVersion("4.4.0");
3445
+ engine.checkVersion("4.5.0");
3374
3446
  await engine.pluginManager.register(e => {
3375
3447
  e.pluginManager.addShape(["matrix"], () => Promise.resolve(new MatrixDrawer()));
3376
3448
  });
@@ -3415,12 +3487,16 @@
3415
3487
  }
3416
3488
 
3417
3489
  async function loadPoissonDiscPlugin(engine) {
3418
- engine.checkVersion("4.4.0");
3490
+ engine.checkVersion("4.5.0");
3419
3491
  await engine.pluginManager.register(e => {
3420
3492
  e.pluginManager.addPlugin(new PoissonDiscPlugin());
3421
3493
  });
3422
3494
  }
3423
3495
 
3496
+ const globalObject$1 = globalThis;
3497
+ globalObject$1.__tsParticlesInternals = globalObject$1.__tsParticlesInternals ?? {};
3498
+ globalObject$1.loadPoissonDiscPlugin = loadPoissonDiscPlugin;
3499
+
3424
3500
  const defaultShadowBlur = 0, defaultShadowOffsetValue = 0;
3425
3501
  class ShadowDrawer {
3426
3502
  #container;
@@ -3453,7 +3529,7 @@
3453
3529
  }
3454
3530
 
3455
3531
  async function loadShadowEffect(engine) {
3456
- engine.checkVersion("4.4.0");
3532
+ engine.checkVersion("4.5.0");
3457
3533
  await engine.pluginManager.register(e => {
3458
3534
  e.pluginManager.addEffect("shadow", container => {
3459
3535
  return Promise.resolve(new ShadowDrawer(e.pluginManager, container));
@@ -3517,7 +3593,7 @@
3517
3593
  }
3518
3594
 
3519
3595
  async function loadTrailPlugin(engine) {
3520
- engine.checkVersion("4.4.0");
3596
+ engine.checkVersion("4.5.0");
3521
3597
  await engine.pluginManager.register(e => {
3522
3598
  e.pluginManager.addPlugin(new TrailPlugin(e.pluginManager));
3523
3599
  });
@@ -3682,21 +3758,28 @@
3682
3758
  });
3683
3759
  }
3684
3760
  clear() {
3761
+ const visited = new Set();
3685
3762
  for (const plugin of this.#canvasClearPlugins) {
3763
+ visited.add(plugin);
3686
3764
  if (plugin.canvasClear?.() ?? false) {
3687
- return;
3765
+ return plugin;
3688
3766
  }
3689
3767
  }
3690
3768
  for (const layer of Object.values(DrawLayer)) {
3691
3769
  if (typeof layer === "number") {
3692
3770
  for (const plugin of this.#getLayerPlugins(layer)) {
3771
+ if (visited.has(plugin)) {
3772
+ continue;
3773
+ }
3774
+ visited.add(plugin);
3693
3775
  if (plugin.canvasClear?.() ?? false) {
3694
- return;
3776
+ return plugin;
3695
3777
  }
3696
3778
  }
3697
3779
  }
3698
3780
  }
3699
3781
  this.canvasClear();
3782
+ return undefined;
3700
3783
  }
3701
3784
  destroy() {
3702
3785
  this.stop();
@@ -3774,8 +3857,7 @@
3774
3857
  });
3775
3858
  }
3776
3859
  drawParticles(delta) {
3777
- const { particles, actualOptions } = this.#container;
3778
- this.clear();
3860
+ const { particles, actualOptions } = this.#container, clearedPlugin = this.clear();
3779
3861
  particles.update(delta);
3780
3862
  this.draw(ctx => {
3781
3863
  const width = this.#canvasManager.size.width, height = this.#canvasManager.size.height;
@@ -3797,7 +3879,9 @@
3797
3879
  }
3798
3880
  }
3799
3881
  for (const plugin of this.#getLayerPlugins(DrawLayer.BackgroundMask)) {
3800
- plugin.canvasPaint?.();
3882
+ if (plugin !== clearedPlugin) {
3883
+ plugin.canvasPaint?.();
3884
+ }
3801
3885
  }
3802
3886
  for (const plugin of this.#getLayerPlugins(DrawLayer.CanvasSetup)) {
3803
3887
  plugin.drawSettingsSetup?.(ctx, delta);
@@ -3829,35 +3913,7 @@
3829
3913
  this.#layers[layer] = [];
3830
3914
  }
3831
3915
  }
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
- }
3916
+ this.#initPluginsArray();
3861
3917
  }
3862
3918
  initUpdaters() {
3863
3919
  this.#preDrawUpdaters = [];
@@ -4066,6 +4122,45 @@
4066
4122
  this.#reusablePluginColors[sColorIndex] = sColor;
4067
4123
  return this.#reusablePluginColors;
4068
4124
  }
4125
+ #initLayerPlugin(plugin) {
4126
+ const layerMap = [
4127
+ [DrawLayer.BackgroundMask, !!plugin.canvasPaint],
4128
+ [DrawLayer.CanvasSetup, !!plugin.drawSettingsSetup],
4129
+ [DrawLayer.PluginContent, !!plugin.draw],
4130
+ [DrawLayer.CanvasCleanup, !!(plugin.clearDraw ?? plugin.drawSettingsCleanup)],
4131
+ ];
4132
+ for (const [layer, active] of layerMap) {
4133
+ if (active) {
4134
+ this.#layers[layer].push(plugin);
4135
+ }
4136
+ }
4137
+ }
4138
+ #initPluginsArray() {
4139
+ for (const plugin of this.#container.plugins) {
4140
+ if (plugin.particleFillColor ?? plugin.particleStrokeColor) {
4141
+ this.#colorPlugins.push(plugin);
4142
+ }
4143
+ if (plugin.drawParticle) {
4144
+ this.#drawParticlePlugins.push(plugin);
4145
+ }
4146
+ if (plugin.drawParticleSetup) {
4147
+ this.#drawParticlesSetupPlugins.push(plugin);
4148
+ }
4149
+ if (plugin.drawParticleCleanup) {
4150
+ this.#drawParticlesCleanupPlugins.push(plugin);
4151
+ }
4152
+ if (plugin.canvasClear) {
4153
+ this.#canvasClearPlugins.push(plugin);
4154
+ }
4155
+ this.#initLayerPlugin(plugin);
4156
+ }
4157
+ }
4158
+ #isSupportedElement(element) {
4159
+ return ((typeof HTMLCanvasElement !== "undefined" && element instanceof HTMLCanvasElement) ||
4160
+ (typeof OffscreenCanvas !== "undefined" && element instanceof OffscreenCanvas) ||
4161
+ (typeof HTMLVideoElement !== "undefined" && element instanceof HTMLVideoElement) ||
4162
+ (typeof HTMLImageElement !== "undefined" && element instanceof HTMLImageElement));
4163
+ }
4069
4164
  #resolveBackgroundElement() {
4070
4165
  const background = this.#container.actualOptions.background;
4071
4166
  this.#backgroundElement = null;
@@ -4075,9 +4170,7 @@
4075
4170
  if (typeof background.element === "string") {
4076
4171
  if (typeof document !== "undefined") {
4077
4172
  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)) {
4173
+ if (node && this.#isSupportedElement(node)) {
4081
4174
  this.#backgroundElement = node;
4082
4175
  }
4083
4176
  else if (node) {
@@ -4088,10 +4181,7 @@
4088
4181
  }
4089
4182
  }
4090
4183
  }
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)) {
4184
+ else if (this.#isSupportedElement(background.element)) {
4095
4185
  this.#backgroundElement = background.element;
4096
4186
  }
4097
4187
  }
@@ -4109,7 +4199,7 @@
4109
4199
  return transferredCanvas;
4110
4200
  }
4111
4201
  if (typeof canvas.transferControlToOffscreen !== "function") {
4112
- throw new TypeError("OffscreenCanvas is required but not supported by this browser");
4202
+ throw new TypeError(getErrorMessage(ErrorCodes$1.offscreenCanvasUnsupported));
4113
4203
  }
4114
4204
  try {
4115
4205
  const offscreenCanvas = canvas.transferControlToOffscreen();
@@ -4117,10 +4207,16 @@
4117
4207
  return offscreenCanvas;
4118
4208
  }
4119
4209
  catch {
4120
- throw new TypeError("OffscreenCanvas transfer failed");
4210
+ throw new TypeError(getErrorMessage(ErrorCodes$1.offscreenCanvasTransferFailed));
4121
4211
  }
4122
4212
  }, isHtmlCanvasElement = (canvas) => {
4123
4213
  return typeof HTMLCanvasElement !== "undefined" && canvas instanceof HTMLCanvasElement;
4214
+ }, getEffectiveColorSpace = (context) => {
4215
+ if (!context) {
4216
+ return undefined;
4217
+ }
4218
+ const colorInfo = context;
4219
+ return colorInfo.getContextAttributes?.().colorSpace ?? undefined;
4124
4220
  };
4125
4221
  function setStyle(canvas, style, important = false) {
4126
4222
  if (!style) {
@@ -4245,7 +4341,7 @@
4245
4341
  const elementStyle = element.style, color = rangeColorToRgb(this.#pluginManager, background.color);
4246
4342
  if (color) {
4247
4343
  const hdrOptions = container.actualOptions.hdr;
4248
- elementStyle.backgroundColor = getStyleFromRgb(color, container.hdr, background.opacity, hdrOptions.peakNits, hdrOptions.mode);
4344
+ elementStyle.backgroundColor = getStyleFromRgb(color, container.hdr, background.opacity, hdrOptions.peakNits, toEnumValue(HdrMode, hdrOptions.mode, HdrMode.standard));
4249
4345
  }
4250
4346
  else {
4251
4347
  elementStyle.backgroundColor = "";
@@ -4365,11 +4461,11 @@
4365
4461
  const container = this.#container, canSupportHdr = container.actualOptions.hdr.enable &&
4366
4462
  safeMatchMedia("(color-gamut: p3)")?.matches &&
4367
4463
  safeMatchMedia("(dynamic-range: high)")?.matches;
4368
- container.hdr = canSupportHdr ?? false;
4369
- container.hdrMode = container.actualOptions.hdr.mode;
4464
+ container.hdrMode = toEnumValue(HdrMode, container.actualOptions.hdr.mode, HdrMode.standard);
4370
4465
  container.peakNits = container.actualOptions.hdr.peakNits;
4371
4466
  const renderCanvas = this.renderCanvas;
4372
4467
  if (!renderCanvas) {
4468
+ container.hdr = canSupportHdr ?? false;
4373
4469
  return;
4374
4470
  }
4375
4471
  this.render.setContextSettings({
@@ -4388,7 +4484,6 @@
4388
4484
  context = null;
4389
4485
  }
4390
4486
  if (canSupportHdr && !context) {
4391
- container.hdr = false;
4392
4487
  const sdrSettings = {
4393
4488
  alpha: true,
4394
4489
  desynchronized: true,
@@ -4404,11 +4499,16 @@
4404
4499
  }
4405
4500
  }
4406
4501
  this.render.setContext(context);
4502
+ if (context) {
4503
+ const effectiveColorSpace = getEffectiveColorSpace(context);
4504
+ if (effectiveColorSpace !== undefined) {
4505
+ container.hdr = effectiveColorSpace === "display-p3";
4506
+ }
4507
+ }
4407
4508
  }
4408
4509
  #initHdrListeners() {
4409
4510
  this.#removeHdrListeners();
4410
4511
  const p3Query = safeMatchMedia("(color-gamut: p3)"), hdrQuery = safeMatchMedia("(dynamic-range: high)"), handleChange = () => {
4411
- this.#recreateRenderCanvas();
4412
4512
  this.#initContext();
4413
4513
  this.initBackground();
4414
4514
  }, listeners = [];
@@ -4444,16 +4544,6 @@
4444
4544
  element.style.setProperty(key, value, "important");
4445
4545
  }
4446
4546
  }
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
4547
  #removeHdrListeners() {
4458
4548
  if (!this.#hdrMediaListeners) {
4459
4549
  return;
@@ -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,18 +5263,7 @@
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;
@@ -5194,14 +5278,23 @@
5194
5278
  this.#releaseShapes();
5195
5279
  return result;
5196
5280
  }
5197
- setCellSize(cellSize) {
5198
- this.#pendingCellSize = cellSize;
5199
- }
5200
5281
  #acquireCircle(x, y, r) {
5201
- return (this.#circlePool[this.#circlePoolIdx++] ??= new Circle(x, y, r)).reset(x, y, r);
5282
+ const idx = this.#circlePoolIdx++;
5283
+ let circle = this.#circlePool[idx];
5284
+ if (!circle) {
5285
+ circle = new Circle(x, y, r);
5286
+ this.#circlePool[idx] = circle;
5287
+ }
5288
+ return circle.reset(x, y, r);
5202
5289
  }
5203
5290
  #acquireRectangle(x, y, w, h) {
5204
- return (this.#rectanglePool[this.#rectanglePoolIdx++] ??= new Rectangle(x, y, w, h)).reset(x, y, w, h);
5291
+ const idx = this.#rectanglePoolIdx++;
5292
+ let rectangle = this.#rectanglePool[idx];
5293
+ if (!rectangle) {
5294
+ rectangle = new Rectangle(x, y, w, h);
5295
+ this.#rectanglePool[idx] = rectangle;
5296
+ }
5297
+ return rectangle.reset(x, y, w, h);
5205
5298
  }
5206
5299
  #cellKeyFromCoords(x, y) {
5207
5300
  const cellX = Math.floor(x / this.#cellSize), cellY = Math.floor(y / this.#cellSize);
@@ -5228,6 +5321,20 @@
5228
5321
  }
5229
5322
  return null;
5230
5323
  }
5324
+ #queryCell(cx, cy, range, check, out) {
5325
+ const cellParticles = this.#cells.get(`${cx}_${cy}`);
5326
+ if (!cellParticles) {
5327
+ return;
5328
+ }
5329
+ for (const p of cellParticles) {
5330
+ if (check && !check(p)) {
5331
+ continue;
5332
+ }
5333
+ if (range.contains(p.getPosition())) {
5334
+ out.push(p);
5335
+ }
5336
+ }
5337
+ }
5231
5338
  #releaseShapes() {
5232
5339
  this.#circlePoolIdx = 0;
5233
5340
  this.#rectanglePoolIdx = 0;
@@ -5236,9 +5343,9 @@
5236
5343
 
5237
5344
  class ParticlesManager {
5238
5345
  checkParticlePositionPlugins;
5239
- grid;
5240
5346
  #array;
5241
5347
  #container;
5348
+ #grid;
5242
5349
  #groupLimits;
5243
5350
  #limit;
5244
5351
  #nextId;
@@ -5262,7 +5369,7 @@
5262
5369
  this.#groupLimits = new Map();
5263
5370
  this.#particleBuckets = new Map();
5264
5371
  this.#zBuckets = this.#createBuckets(this.#container.zLayers);
5265
- this.grid = new SpatialHashGrid(spatialHashGridCellSize);
5372
+ this.#grid = new SpatialHashGrid(spatialHashGridCellSize);
5266
5373
  this.checkParticlePositionPlugins = [];
5267
5374
  this.#particleResetPlugins = [];
5268
5375
  this.#particleUpdatePlugins = [];
@@ -5273,23 +5380,12 @@
5273
5380
  get count() {
5274
5381
  return this.#array.length;
5275
5382
  }
5383
+ get grid() {
5384
+ return this.#grid;
5385
+ }
5276
5386
  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
- }
5387
+ if (this.#checkAndApplyLimits(group, this.count)) {
5388
+ return;
5293
5389
  }
5294
5390
  try {
5295
5391
  const particle = this.#pool.pop() ?? new Particle(this.#pluginManager, this.#container);
@@ -5353,7 +5449,7 @@
5353
5449
  return this.#array[index];
5354
5450
  }
5355
5451
  async init() {
5356
- const container = this.#container, options = container.actualOptions;
5452
+ const container = this.#container;
5357
5453
  this.checkParticlePositionPlugins = [];
5358
5454
  this.#updatePlugins = [];
5359
5455
  this.#particleUpdatePlugins = [];
@@ -5362,59 +5458,16 @@
5362
5458
  this.#postParticleUpdatePlugins = [];
5363
5459
  this.#particleBuckets.clear();
5364
5460
  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();
5461
+ this.#grid = new SpatialHashGrid(spatialHashGridCellSize * container.retina.pixelRatio);
5462
+ this.#applyLimits(container.actualOptions.particles);
5463
+ const particlesOptions = container.actualOptions.particles, groups = particlesOptions.groups;
5464
+ for (const group in groups) {
5465
+ const groupData = groups[group];
5466
+ if (groupData) {
5467
+ this.#applyLimits(loadParticlesOptions(this.#pluginManager, this.#container, groupData), group, groupData);
5416
5468
  }
5417
5469
  }
5470
+ await this.#initPlugins();
5418
5471
  }
5419
5472
  push(nb, position, overrideOptions, group) {
5420
5473
  for (let i = 0; i < nb; i++) {
@@ -5429,13 +5482,13 @@
5429
5482
  remove(particle, group, override) {
5430
5483
  this.removeAt(this.#array.indexOf(particle), undefined, group, override);
5431
5484
  }
5432
- removeAt(index, quantity = defaultRemoveQuantity, group, override) {
5485
+ removeAt(index, quantity = defaultRemoveQuantity, group, override, matchGroup = true) {
5433
5486
  if (index < minIndex || index > this.count) {
5434
5487
  return;
5435
5488
  }
5436
5489
  let deleted = 0;
5437
5490
  for (let i = index; deleted < quantity && i < this.count; i++) {
5438
- if (this.#removeParticle(i, group, override)) {
5491
+ if (this.#removeParticle(i, group, override, matchGroup)) {
5439
5492
  i--;
5440
5493
  deleted++;
5441
5494
  }
@@ -5466,7 +5519,7 @@
5466
5519
  this.#resizeFactor = factor;
5467
5520
  }
5468
5521
  update(delta) {
5469
- this.grid.clear();
5522
+ this.#grid.clear();
5470
5523
  for (const plugin of this.#updatePlugins) {
5471
5524
  plugin.update?.(delta);
5472
5525
  }
@@ -5477,7 +5530,7 @@
5477
5530
  this.#updateParticlesPhase2(delta, particlesToDelete);
5478
5531
  if (particlesToDelete.size) {
5479
5532
  for (const particle of particlesToDelete) {
5480
- this.remove(particle);
5533
+ this.remove(particle, particle.group);
5481
5534
  }
5482
5535
  }
5483
5536
  this.#resizeFactor = undefined;
@@ -5488,12 +5541,7 @@
5488
5541
  #applyDensity(options, pluginsCount, group, groupOptions) {
5489
5542
  const numberOptions = options.number;
5490
5543
  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
- }
5544
+ this.#applyLimits(options, group, groupOptions);
5497
5545
  return;
5498
5546
  }
5499
5547
  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 +5549,10 @@
5501
5549
  this.#limit = numberOptions.limit.value * densityFactor;
5502
5550
  }
5503
5551
  else {
5504
- this.#groupLimits.set(group, numberOptions.limit.value * densityFactor);
5552
+ this.#groupLimits.set(group, {
5553
+ limit: numberOptions.limit.value * densityFactor,
5554
+ mode: toEnumValue(LimitMode, numberOptions.limit.mode, LimitMode.delete),
5555
+ });
5505
5556
  }
5506
5557
  if (particlesCount < particlesNumber) {
5507
5558
  this.push(Math.abs(particlesNumber - particlesCount), undefined, options, group);
@@ -5510,6 +5561,55 @@
5510
5561
  this.removeQuantity(particlesCount - particlesNumber, group);
5511
5562
  }
5512
5563
  }
5564
+ #applyLimits(options, group, groupOptions) {
5565
+ if (group === undefined) {
5566
+ this.#limit = options.number.limit.value;
5567
+ const groups = this.#container.actualOptions.particles.groups;
5568
+ for (const existingGroup of this.#groupLimits.keys()) {
5569
+ if (!(existingGroup in groups)) {
5570
+ this.#groupLimits.delete(existingGroup);
5571
+ }
5572
+ }
5573
+ }
5574
+ else {
5575
+ const limitValue = groupOptions?.number?.limit?.value ?? options.number.limit.value;
5576
+ if (limitValue > minLimit) {
5577
+ this.#groupLimits.set(group, {
5578
+ limit: limitValue,
5579
+ mode: toEnumValue(LimitMode, groupOptions?.number?.limit?.mode ?? options.number.limit.mode, LimitMode.delete),
5580
+ });
5581
+ }
5582
+ else {
5583
+ this.#groupLimits.delete(group);
5584
+ }
5585
+ }
5586
+ }
5587
+ #checkAndApplyLimits(group, currentCount) {
5588
+ const globalLimit = this.#limit, globalMode = this.#container.actualOptions.particles.number.limit.mode;
5589
+ if (globalLimit > minLimit && globalMode === LimitMode.wait && currentCount >= globalLimit) {
5590
+ return true;
5591
+ }
5592
+ const groupLimitEntry = group === undefined ? undefined : this.#groupLimits.get(group);
5593
+ if (groupLimitEntry && groupLimitEntry.limit > minLimit && groupLimitEntry.mode === LimitMode.wait) {
5594
+ const groupCount = this.filter(t => t.group === group).length;
5595
+ if (groupCount >= groupLimitEntry.limit) {
5596
+ return true;
5597
+ }
5598
+ }
5599
+ if (groupLimitEntry && groupLimitEntry.limit > minLimit && groupLimitEntry.mode === LimitMode.delete) {
5600
+ const groupCountToRemove = this.filter(t => t.group === group).length + countOffset - groupLimitEntry.limit;
5601
+ if (groupCountToRemove > minCount) {
5602
+ this.removeQuantity(groupCountToRemove, group);
5603
+ }
5604
+ }
5605
+ if (globalLimit > minLimit && globalMode === LimitMode.delete) {
5606
+ const globalCountToRemove = this.count + countOffset - globalLimit;
5607
+ if (globalCountToRemove > minCount) {
5608
+ this.#removeAny(globalCountToRemove);
5609
+ }
5610
+ }
5611
+ return false;
5612
+ }
5513
5613
  #createBuckets(zLayers) {
5514
5614
  const bucketCount = Math.max(Math.floor(zLayers), one);
5515
5615
  return Array.from({ length: bucketCount }, () => []);
@@ -5532,6 +5632,70 @@
5532
5632
  }
5533
5633
  return ((canvasSize.width * canvasSize.height) / (densityOptions.height * densityOptions.width * pxRatio ** squareExp));
5534
5634
  }
5635
+ async #initDrawersAndUpdaters() {
5636
+ const container = this.#container;
5637
+ await container.initDrawersAndUpdaters();
5638
+ for (const drawer of container.effectDrawers.values()) {
5639
+ await drawer.init?.(container);
5640
+ }
5641
+ for (const drawer of container.shapeDrawers.values()) {
5642
+ await drawer.init?.(container);
5643
+ }
5644
+ }
5645
+ async #initPlugins() {
5646
+ await this.#initPluginsArrays();
5647
+ await this.#initDrawersAndUpdaters();
5648
+ let handled = false;
5649
+ const container = this.#container;
5650
+ for (const plugin of container.plugins) {
5651
+ handled = plugin.particlesInitialization?.() ?? handled;
5652
+ if (handled) {
5653
+ break;
5654
+ }
5655
+ }
5656
+ if (handled) {
5657
+ return;
5658
+ }
5659
+ const particlesOptions = container.actualOptions.particles, groups = particlesOptions.groups;
5660
+ for (const group in groups) {
5661
+ const groupOptions = groups[group];
5662
+ if (!groupOptions) {
5663
+ continue;
5664
+ }
5665
+ for (let i = this.count, j = 0; j < groupOptions.number.value && i < particlesOptions.number.value; i++, j++) {
5666
+ this.addParticle(undefined, groupOptions, group);
5667
+ }
5668
+ }
5669
+ for (let i = this.count; i < particlesOptions.number.value; i++) {
5670
+ this.addParticle();
5671
+ }
5672
+ }
5673
+ async #initPluginsArrays() {
5674
+ const container = this.#container;
5675
+ for (const plugin of container.plugins) {
5676
+ if (plugin.redrawInit) {
5677
+ await plugin.redrawInit();
5678
+ }
5679
+ if (plugin.checkParticlePosition) {
5680
+ this.checkParticlePositionPlugins.push(plugin);
5681
+ }
5682
+ if (plugin.update) {
5683
+ this.#updatePlugins.push(plugin);
5684
+ }
5685
+ if (plugin.particleUpdate) {
5686
+ this.#particleUpdatePlugins.push(plugin);
5687
+ }
5688
+ if (plugin.postUpdate) {
5689
+ this.#postUpdatePlugins.push(plugin);
5690
+ }
5691
+ if (plugin.particleReset) {
5692
+ this.#particleResetPlugins.push(plugin);
5693
+ }
5694
+ if (plugin.postParticleUpdate) {
5695
+ this.#postParticleUpdatePlugins.push(plugin);
5696
+ }
5697
+ }
5698
+ }
5535
5699
  #insertParticleIntoBucket(particle) {
5536
5700
  const bucketIndex = this.#getBucketIndex(particle.position.z), bucket = this.#zBuckets[bucketIndex];
5537
5701
  if (!bucket) {
@@ -5540,12 +5704,15 @@
5540
5704
  bucket.push(particle);
5541
5705
  this.#particleBuckets.set(particle.id, bucketIndex);
5542
5706
  }
5543
- #removeParticle(index, group, override) {
5707
+ #removeAny(quantity) {
5708
+ this.removeAt(minIndex, quantity, undefined, undefined, false);
5709
+ }
5710
+ #removeParticle(index, group, override, matchGroup = true) {
5544
5711
  const particle = this.#array[index];
5545
5712
  if (!particle) {
5546
5713
  return false;
5547
5714
  }
5548
- if (particle.group !== group) {
5715
+ if (matchGroup && particle.group !== group) {
5549
5716
  return false;
5550
5717
  }
5551
5718
  this.#array.splice(index, deleteCount);
@@ -5632,7 +5799,7 @@
5632
5799
  particlesToDelete.add(particle);
5633
5800
  continue;
5634
5801
  }
5635
- this.grid.insert(particle);
5802
+ this.#grid.insert(particle);
5636
5803
  }
5637
5804
  return particlesToDelete;
5638
5805
  }
@@ -5808,7 +5975,6 @@
5808
5975
  this.shapeDrawers = new Map();
5809
5976
  this.particleUpdaters = [];
5810
5977
  this.plugins.length = 0;
5811
- this.#pluginManager.clearPlugins(this);
5812
5978
  this.destroyed = true;
5813
5979
  this.#onDestroy(remove);
5814
5980
  this.dispatchEvent(EventType.containerDestroyed);
@@ -5861,31 +6027,14 @@
5861
6027
  await this.initDrawersAndUpdaters();
5862
6028
  this.#options = loadContainerOptions(this.#pluginManager, this, this.#initialSourceOptions, this.sourceOptions);
5863
6029
  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
- }
6030
+ this.#initPlugins(allContainerPlugins);
5882
6031
  this.retina.init();
5883
6032
  this.canvas.init();
5884
6033
  this.updateActualOptions();
5885
6034
  this.canvas.initBackground();
5886
6035
  this.canvas.resize();
5887
6036
  const { delay, duration, fpsLimit, smooth, zLayers } = this.actualOptions, hdrOptions = this.actualOptions.hdr;
5888
- this.hdrMode = hdrOptions.mode;
6037
+ this.hdrMode = toEnumValue(HdrMode, hdrOptions.mode, HdrMode.standard);
5889
6038
  this.peakNits = hdrOptions.peakNits;
5890
6039
  this.zLayers = zLayers;
5891
6040
  this.#duration = getRangeValue(duration) * millisecondsToSeconds;
@@ -5906,9 +6055,9 @@
5906
6055
  }
5907
6056
  async initDrawersAndUpdaters() {
5908
6057
  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);
6058
+ this.effectDrawers = await getItemMapFromInitializer(this, pluginManager.initializers.effects);
6059
+ this.shapeDrawers = await getItemMapFromInitializer(this, pluginManager.initializers.shapes);
6060
+ this.particleUpdaters = await getItemsFromInitializer(this, pluginManager.initializers.updaters);
5912
6061
  }
5913
6062
  pause() {
5914
6063
  if (!guardCheck(this)) {
@@ -6019,6 +6168,27 @@
6019
6168
  }
6020
6169
  return refresh;
6021
6170
  }
6171
+ #initPlugins(allContainerPlugins) {
6172
+ this.plugins.length = 0;
6173
+ this.particleDestroyedPlugins.length = 0;
6174
+ this.particleCreatedPlugins.length = 0;
6175
+ this.particlePositionPlugins.length = 0;
6176
+ for (const [plugin, containerPlugin] of allContainerPlugins) {
6177
+ if (!plugin.needsPlugin(this.actualOptions)) {
6178
+ continue;
6179
+ }
6180
+ this.plugins.push(containerPlugin);
6181
+ if (containerPlugin.particleCreated) {
6182
+ this.particleCreatedPlugins.push(containerPlugin);
6183
+ }
6184
+ if (containerPlugin.particleDestroyed) {
6185
+ this.particleDestroyedPlugins.push(containerPlugin);
6186
+ }
6187
+ if (containerPlugin.particlePosition) {
6188
+ this.particlePositionPlugins.push(containerPlugin);
6189
+ }
6190
+ }
6191
+ }
6022
6192
  #nextFrame(timestamp) {
6023
6193
  try {
6024
6194
  if (!this.#smooth &&
@@ -6295,11 +6465,11 @@
6295
6465
  }
6296
6466
  }
6297
6467
  async #init() {
6298
- const availablePathGenerators = await this.#pluginManager.getPathGenerators?.(this.#container, true);
6299
- if (!availablePathGenerators) {
6468
+ const pluginManager = this.#pluginManager;
6469
+ if (!pluginManager.initializers.pathGenerators) {
6300
6470
  return;
6301
6471
  }
6302
- this.availablePathGenerators = availablePathGenerators;
6472
+ this.availablePathGenerators = await getItemMapFromInitializer(this.#container, pluginManager.initializers.pathGenerators);
6303
6473
  this.pathGenerators = new Map();
6304
6474
  for (const pathGenerator of this.pathGenerators.values()) {
6305
6475
  pathGenerator.init();
@@ -6534,7 +6704,7 @@
6534
6704
  }
6535
6705
  async run() {
6536
6706
  this.reset();
6537
- const minCount = 0, step = 1, yieldEvery = 100, yieldStepModule = 0;
6707
+ const step = 1, yieldEvery = 100, yieldStepModule = 0;
6538
6708
  let iterations = 0;
6539
6709
  while (this.active.length > minCount) {
6540
6710
  this.steps(step);
@@ -6544,7 +6714,6 @@
6544
6714
  }
6545
6715
  }
6546
6716
  steps(steps) {
6547
- const minCount = 0;
6548
6717
  for (let i = 0; i < steps; i++) {
6549
6718
  if (this.active.length <= minCount) {
6550
6719
  continue;
@@ -6611,7 +6780,7 @@
6611
6780
  return newPoint;
6612
6781
  }
6613
6782
  #step() {
6614
- const minCount = 0, randomActive = this.getRandom(minCount, this.active.length);
6783
+ const randomActive = this.getRandom(minCount, this.active.length);
6615
6784
  let foundNewPoint = false;
6616
6785
  for (let tries = 0; tries < this.retries; tries++) {
6617
6786
  const randomActivePointIndex = this.active[randomActive];
@@ -6644,6 +6813,7 @@
6644
6813
  exports.loadMatrixPreset = loadMatrixPreset;
6645
6814
  exports.tsParticles = tsParticles;
6646
6815
 
6647
- }));
6816
+ })(g.__tsParticlesInternals.presets.matrix = g.__tsParticlesInternals.presets.matrix || {});
6817
+ })(typeof globalThis !== "undefined" ? globalThis : typeof window !== "undefined" ? window : self);
6818
+
6648
6819
  Object.assign(globalThis.window || globalThis, { loadMatrixPreset: (globalThis.__tsParticlesInternals.presets.matrix || {}).loadMatrixPreset });
6649
- delete (globalThis.window || globalThis).tsparticlesInternalExports;