@tsparticles/preset-squares 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.squares = global.__tsParticlesInternals.presets.squares || {})));
7
- })(this, (function (exports) { 'use strict';
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
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, 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;
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, 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
  }
@@ -276,6 +307,57 @@
276
307
  };
277
308
  }
278
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);
359
+ }
360
+
279
361
  var OutModeDirection;
280
362
  (function (OutModeDirection) {
281
363
  OutModeDirection["bottom"] = "bottom";
@@ -290,7 +372,6 @@
290
372
  PixelMode["percent"] = "percent";
291
373
  })(PixelMode || (PixelMode = {}));
292
374
 
293
- const minRadius = 0;
294
375
  function isForbiddenKey(key) {
295
376
  return key === "__proto__" || key === "constructor" || key === "prototype";
296
377
  }
@@ -486,22 +567,84 @@
486
567
  element.removeEventListener(event, handler, removeOptions);
487
568
  }
488
569
  }
489
- async function getItemsFromInitializer(container, map, initializers, force = false) {
490
- let res = map.get(container);
491
- if (!res || force) {
492
- res = await Promise.all([...initializers.values()].map(t => t(container)));
493
- 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;
494
581
  }
495
- 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;
496
599
  }
497
- async function getItemMapFromInitializer(container, map, initializers, force = false) {
498
- let res = map.get(container);
499
- if (!res || force) {
500
- const entries = await Promise.all([...initializers.entries()].map(([key, initializer]) => initializer(container).then(item => [key, item])));
501
- res = new Map(entries);
502
- map.set(container, res);
600
+ function isSourceOptionsValue(value) {
601
+ if (isArray(value)) {
602
+ return value.every((entry) => isObject(entry) && !isArray(entry));
503
603
  }
504
- 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;
505
648
  }
506
649
 
507
650
  class EventDispatcher {
@@ -572,7 +715,6 @@
572
715
  class PluginManager {
573
716
  colorManagers = new Map();
574
717
  easingFunctions = new Map();
575
- effectDrawers = new Map();
576
718
  initializers = {
577
719
  effects: new Map(),
578
720
  shapes: new Map(),
@@ -581,8 +723,6 @@
581
723
  palettes = new Map();
582
724
  plugins = [];
583
725
  presets = new Map();
584
- shapeDrawers = new Map();
585
- updaters = new Map();
586
726
  #allLoadersSet = new Set();
587
727
  #configs = new Map();
588
728
  #engine;
@@ -600,57 +740,79 @@
600
740
  }
601
741
  return res;
602
742
  }
743
+ get initialized() {
744
+ return this.#initialized;
745
+ }
603
746
  addColorManager(name, manager) {
747
+ if (this.#initialized) {
748
+ return;
749
+ }
604
750
  this.colorManagers.set(name, manager);
605
751
  }
606
752
  addConfig(config) {
753
+ if (this.#initialized) {
754
+ return;
755
+ }
607
756
  const key = config.key ?? config.name ?? "default";
608
757
  this.#configs.set(key, config);
609
758
  this.#engine.dispatchEvent(EventType.configAdded, { data: { name: key, config } });
610
759
  }
611
760
  addEasing(name, easing) {
761
+ if (this.#initialized) {
762
+ return;
763
+ }
612
764
  if (this.easingFunctions.get(name)) {
613
765
  return;
614
766
  }
615
767
  this.easingFunctions.set(name, easing);
616
768
  }
617
769
  addEffect(effect, drawer) {
770
+ if (this.#initialized) {
771
+ return;
772
+ }
618
773
  this.initializers.effects.set(effect, drawer);
619
774
  }
620
775
  addPalette(name, palette) {
776
+ if (this.#initialized) {
777
+ return;
778
+ }
621
779
  this.palettes.set(name, palette);
622
780
  }
623
781
  addParticleUpdater(name, updaterInitializer) {
782
+ if (this.#initialized) {
783
+ return;
784
+ }
624
785
  this.initializers.updaters.set(name, updaterInitializer);
625
786
  }
626
787
  addPlugin(plugin) {
788
+ if (this.#initialized) {
789
+ return;
790
+ }
627
791
  if (this.getPlugin(plugin.id)) {
628
792
  return;
629
793
  }
630
794
  this.plugins.push(plugin);
631
795
  }
632
796
  addPreset(preset, options, override = false) {
797
+ if (this.#initialized) {
798
+ return;
799
+ }
633
800
  if (!(override || !this.getPreset(preset))) {
634
801
  return;
635
802
  }
636
803
  this.presets.set(preset, options);
637
804
  }
638
805
  addShape(shapes, drawer) {
806
+ if (this.#initialized) {
807
+ return;
808
+ }
639
809
  for (const shape of shapes) {
640
810
  this.initializers.shapes.set(shape, drawer);
641
811
  }
642
812
  }
643
- clearPlugins(container) {
644
- this.effectDrawers.delete(container);
645
- this.shapeDrawers.delete(container);
646
- this.updaters.delete(container);
647
- }
648
813
  getEasing(name) {
649
814
  return this.easingFunctions.get(name) ?? ((value) => value);
650
815
  }
651
- getEffectDrawers(container, force = false) {
652
- return getItemMapFromInitializer(container, this.effectDrawers, this.initializers.effects, force);
653
- }
654
816
  getPalette(name) {
655
817
  return this.palettes.get(name);
656
818
  }
@@ -660,12 +822,6 @@
660
822
  getPreset(preset) {
661
823
  return this.presets.get(preset);
662
824
  }
663
- async getShapeDrawers(container, force = false) {
664
- return getItemMapFromInitializer(container, this.shapeDrawers, this.initializers.shapes, force);
665
- }
666
- async getUpdaters(container, force = false) {
667
- return getItemsFromInitializer(container, this.updaters, this.initializers.updaters, force);
668
- }
669
825
  async init() {
670
826
  if (this.#initialized || this.#isRunningLoaders) {
671
827
  return;
@@ -684,16 +840,9 @@
684
840
  this.#initialized = true;
685
841
  }
686
842
  }
687
- loadParticlesOptions(container, options, ...sourceOptions) {
688
- const updaters = this.updaters.get(container);
689
- if (!updaters) {
690
- return;
691
- }
692
- updaters.forEach(updater => updater.loadOptions?.(options, ...sourceOptions));
693
- }
694
843
  async register(...loaders) {
695
844
  if (this.#initialized) {
696
- throw new Error("Register plugins can only be done before calling tsParticles.load()");
845
+ throw new Error(getErrorMessage(ErrorCodes$1.pluginRegisterAfterLoad));
697
846
  }
698
847
  for (const loader of loaders) {
699
848
  if (this.#isRunningLoaders) {
@@ -705,88 +854,15 @@
705
854
  }
706
855
  }
707
856
  async #runLoader(loader, executed, allLoaders) {
708
- if (executed.has(loader))
857
+ if (executed.has(loader)) {
709
858
  return;
859
+ }
710
860
  executed.add(loader);
711
861
  allLoaders.add(loader);
712
862
  await loader(this.#engine);
713
863
  }
714
864
  }
715
865
 
716
- const errorPrefix = "tsParticles - Error";
717
- const wrap = (fn) => (...args) => {
718
- fn(...args);
719
- }, _logger = {
720
- debug: wrap(console.debug),
721
- error: (message, ...optionalParams) => {
722
- console.error(`${errorPrefix} - ${message}`, ...optionalParams);
723
- },
724
- info: wrap(console.info),
725
- log: wrap(console.log),
726
- trace: wrap(console.trace),
727
- verbose: wrap(console.log),
728
- warning: wrap(console.warn),
729
- };
730
- function getLogger() {
731
- return _logger;
732
- }
733
-
734
- const fullPercent = "100%";
735
- async function getDataFromUrl(data) {
736
- const url = itemFromSingleOrMultiple(data.url, data.index);
737
- if (!url) {
738
- return data.fallback;
739
- }
740
- const response = await fetch(url);
741
- if (response.ok) {
742
- return (await response.json());
743
- }
744
- getLogger().error(`${response.status.toString()} while retrieving config file`);
745
- return data.fallback;
746
- }
747
- const getCanvasFromContainer = (domContainer) => {
748
- const documentSafe = safeDocument();
749
- let canvasEl;
750
- const isCanvas = domContainer instanceof HTMLCanvasElement || domContainer.tagName.toLowerCase() === canvasTag;
751
- if (isCanvas) {
752
- canvasEl = domContainer;
753
- canvasEl.dataset[generatedAttribute] ??= generatedFalse;
754
- if (canvasEl.dataset[generatedAttribute] === generatedTrue) {
755
- canvasEl.style.width ||= fullPercent;
756
- canvasEl.style.height ||= fullPercent;
757
- canvasEl.style.pointerEvents = "none";
758
- canvasEl.style.setProperty("pointer-events", "none");
759
- }
760
- }
761
- else {
762
- const existingCanvases = domContainer.getElementsByTagName(canvasTag), foundCanvas = existingCanvases.item(canvasFirstIndex);
763
- if (foundCanvas) {
764
- canvasEl = foundCanvas;
765
- canvasEl.dataset[generatedAttribute] = generatedFalse;
766
- }
767
- else {
768
- canvasEl = documentSafe.createElement(canvasTag);
769
- canvasEl.dataset[generatedAttribute] = generatedTrue;
770
- domContainer.appendChild(canvasEl);
771
- }
772
- canvasEl.style.width ||= fullPercent;
773
- canvasEl.style.height ||= fullPercent;
774
- canvasEl.style.pointerEvents = "none";
775
- canvasEl.style.setProperty("pointer-events", "none");
776
- }
777
- return canvasEl;
778
- }, getDomContainer = (id, source) => {
779
- const documentSafe = safeDocument();
780
- let domContainer = source ?? documentSafe.getElementById(id);
781
- if (domContainer) {
782
- return domContainer;
783
- }
784
- domContainer = documentSafe.createElement("canvas");
785
- domContainer.id = id;
786
- domContainer.dataset[generatedAttribute] = generatedTrue;
787
- documentSafe.body.append(domContainer);
788
- return domContainer;
789
- };
790
866
  class Engine {
791
867
  pluginManager = new PluginManager(this);
792
868
  #domArray = [];
@@ -796,7 +872,7 @@
796
872
  return this.#domArray;
797
873
  }
798
874
  get version() {
799
- return "4.4.0";
875
+ return "4.5.0";
800
876
  }
801
877
  addEventListener(type, listener) {
802
878
  this.#eventDispatcher.addEventListener(type, listener);
@@ -805,7 +881,7 @@
805
881
  if (this.version === pluginVersion) {
806
882
  return;
807
883
  }
808
- 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));
809
885
  }
810
886
  dispatchEvent(type, args) {
811
887
  this.#eventDispatcher.dispatchEvent(type, args);
@@ -1054,20 +1130,6 @@
1054
1130
  DrawLayer[DrawLayer["Foreground"] = 7] = "Foreground";
1055
1131
  })(DrawLayer || (DrawLayer = {}));
1056
1132
 
1057
- class OptionLoader {
1058
- load(data) {
1059
- if (isNull(data)) {
1060
- return;
1061
- }
1062
- this.doLoad(data);
1063
- }
1064
- }
1065
- function loadOptions(options, ...sourceOptionsArr) {
1066
- for (const sourceOptions of sourceOptionsArr) {
1067
- options.load(sourceOptions);
1068
- }
1069
- }
1070
-
1071
1133
  function loadProperty(obj, key, value) {
1072
1134
  if (value !== undefined) {
1073
1135
  obj[key] = value;
@@ -1099,6 +1161,20 @@
1099
1161
  }
1100
1162
  }
1101
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
+
1102
1178
  class AnimationOptions extends OptionLoader {
1103
1179
  count = 0;
1104
1180
  decay = 0;
@@ -1249,15 +1325,14 @@
1249
1325
  peakNits = defaultPeakNits;
1250
1326
  doLoad(data) {
1251
1327
  if (data.enable !== undefined && !isBoolean(data.enable)) {
1252
- 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)));
1253
1329
  }
1254
- if (data.mode !== undefined &&
1255
- (typeof data.mode !== "string" || !Object.values(HdrMode).includes(data.mode))) {
1256
- 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)));
1257
1332
  }
1258
1333
  if (data.peakNits !== undefined &&
1259
1334
  (!isNumber(data.peakNits) || !Number.isFinite(data.peakNits) || data.peakNits <= minPeakNits)) {
1260
- 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)));
1261
1336
  }
1262
1337
  loadProperty(this, "enable", data.enable);
1263
1338
  loadProperty(this, "mode", data.mode);
@@ -1635,12 +1710,10 @@
1635
1710
  plugin.loadParticlesOptions(this.#container, this, data);
1636
1711
  }
1637
1712
  }
1638
- const updaters = this.#pluginManager.updaters.get(this.#container);
1639
- if (updaters) {
1640
- for (const updater of updaters) {
1641
- if (updater.loadOptions) {
1642
- updater.loadOptions(this, data);
1643
- }
1713
+ const updaters = this.#container.particleUpdaters;
1714
+ for (const updater of updaters) {
1715
+ if (updater.loadOptions) {
1716
+ updater.loadOptions(this, data);
1644
1717
  }
1645
1718
  }
1646
1719
  }
@@ -1973,9 +2046,9 @@
1973
2046
  const grayscaleValue = lNormalized * rgbMax;
1974
2047
  return { r: grayscaleValue, g: grayscaleValue, b: grayscaleValue };
1975
2048
  }
1976
- const temp1 = lNormalized < half
2049
+ const temp2 = lNormalized < half
1977
2050
  ? lNormalized * (sNormalizedOffset + sNormalized)
1978
- : 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));
1979
2052
  return { r: red, g: green, b: blue };
1980
2053
  }
1981
2054
  function getRandomRgbColor(min, hdr) {
@@ -2234,6 +2307,8 @@
2234
2307
  autoPlay = true;
2235
2308
  direction;
2236
2309
  domId;
2310
+ draggable = false;
2311
+ draw = true;
2237
2312
  fill = true;
2238
2313
  life = new EmitterLife();
2239
2314
  name;
@@ -2257,6 +2332,8 @@
2257
2332
  }
2258
2333
  loadProperty(this, "direction", data.direction);
2259
2334
  loadProperty(this, "domId", data.domId);
2335
+ loadProperty(this, "draggable", data.draggable);
2336
+ loadProperty(this, "draw", data.draw);
2260
2337
  loadProperty(this, "fill", data.fill);
2261
2338
  this.life.load(data.life);
2262
2339
  loadProperty(this, "name", data.name);
@@ -2318,6 +2395,14 @@
2318
2395
  }
2319
2396
  }
2320
2397
 
2398
+ const ErrorCodes = {
2399
+ emittersPluginNotLoaded: "TSP-3101",
2400
+ };
2401
+
2402
+ const ErrorMessages = {
2403
+ [ErrorCodes.emittersPluginNotLoaded]: "tsParticles Emitters Plugin is not loaded",
2404
+ };
2405
+
2321
2406
  async function addEmittersShapesManager(e) {
2322
2407
  const { ShapeManager } = await Promise.resolve().then(function () { return ShapeManager$1; }), pluginManager = e.pluginManager;
2323
2408
  pluginManager.emitterShapeManager ??= new ShapeManager();
@@ -2348,7 +2433,10 @@
2348
2433
  })(EmitterClickMode || (EmitterClickMode = {}));
2349
2434
 
2350
2435
  async function loadEmittersPluginSimple(engine) {
2351
- engine.checkVersion("4.4.0");
2436
+ engine.checkVersion("4.5.0");
2437
+ if (typeof process !== "undefined" && process.env.NODE_ENV !== "production") {
2438
+ addErrorMessages(ErrorMessages);
2439
+ }
2352
2440
  await engine.pluginManager.register(async (e) => {
2353
2441
  const instancesManager = await getEmittersInstancesManager(e);
2354
2442
  await addEmittersShapesManager(e);
@@ -2363,7 +2451,7 @@
2363
2451
  RgbIndexes[RgbIndexes["b"] = 3] = "b";
2364
2452
  RgbIndexes[RgbIndexes["a"] = 4] = "a";
2365
2453
  })(RgbIndexes || (RgbIndexes = {}));
2366
- 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;
2454
+ 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;
2367
2455
  class HexColorManager {
2368
2456
  accepts(input) {
2369
2457
  return input.startsWith("#");
@@ -2396,7 +2484,7 @@
2396
2484
  }
2397
2485
 
2398
2486
  async function loadHexColorPlugin(engine) {
2399
- engine.checkVersion("4.4.0");
2487
+ engine.checkVersion("4.5.0");
2400
2488
  await engine.pluginManager.register(e => {
2401
2489
  e.pluginManager.addColorManager("hex", new HexColorManager());
2402
2490
  });
@@ -2411,39 +2499,9 @@
2411
2499
  this.#pluginManager = pluginManager;
2412
2500
  }
2413
2501
  init(particle) {
2414
- 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;
2415
- if (fill) {
2416
- const fillColor = AnimatableColor.create(paintColor === undefined ? undefined : AnimatableColor.create(undefined, paintColor), fill.color);
2417
- particle.fillEnabled = fill.enable;
2418
- particle.fillOpacity = getRangeValue(fill.opacity);
2419
- particle.fillAnimation = fillColor.animation;
2420
- const fillHslColor = rangeColorToHsl(this.#pluginManager, fillColor);
2421
- if (fillHslColor) {
2422
- particle.fillColor = getHslAnimationFromHsl(fillHslColor, particle.fillAnimation, container.retina.reduceFactor);
2423
- }
2424
- }
2425
- else {
2426
- particle.fillEnabled = false;
2427
- particle.fillAnimation = undefined;
2428
- particle.fillColor = undefined;
2429
- particle.fillOpacity = defaultOpacity;
2430
- }
2431
- if (stroke) {
2432
- const strokeColor = AnimatableColor.create(paintColor === undefined ? undefined : AnimatableColor.create(undefined, paintColor), stroke.color);
2433
- particle.strokeWidth = getRangeValue(stroke.width) * container.retina.pixelRatio;
2434
- particle.strokeOpacity = getRangeValue(stroke.opacity ?? defaultOpacity);
2435
- particle.strokeAnimation = strokeColor.animation;
2436
- const strokeHslColor = rangeColorToHsl(this.#pluginManager, strokeColor) ?? particle.getFillColor();
2437
- if (strokeHslColor) {
2438
- particle.strokeColor = getHslAnimationFromHsl(strokeHslColor, particle.strokeAnimation, container.retina.reduceFactor);
2439
- }
2440
- }
2441
- else {
2442
- particle.strokeAnimation = undefined;
2443
- particle.strokeColor = undefined;
2444
- particle.strokeOpacity = defaultOpacity;
2445
- particle.strokeWidth = 0;
2446
- }
2502
+ const container = this.#container, options = particle.options, paint = itemFromSingleOrMultiple(options.paint, particle.id, options.reduceDuplicates);
2503
+ this.#initFill(paint, particle, container);
2504
+ this.#initStroke(paint, particle, container);
2447
2505
  }
2448
2506
  isEnabled(particle) {
2449
2507
  const { fillAnimation, fillColor, strokeAnimation, strokeColor } = particle, fillEnabled = !!fillAnimation &&
@@ -2455,17 +2513,55 @@
2455
2513
  (strokeColor?.l.value !== undefined && strokeColor.l.enable));
2456
2514
  return !particle.destroyed && !particle.spawning && (fillEnabled || strokeEnabled);
2457
2515
  }
2458
- update(particle, delta) {
2459
- if (!this.isEnabled(particle)) {
2516
+ update(particle, delta) {
2517
+ if (!this.isEnabled(particle)) {
2518
+ return;
2519
+ }
2520
+ updateColor(particle.fillColor, delta, this.#container.hdr);
2521
+ updateColor(particle.strokeColor, delta, this.#container.hdr);
2522
+ }
2523
+ #initFill(paint, particle, container) {
2524
+ const fill = paint?.fill, color = paint?.color, paintColor = color ?? undefined;
2525
+ if (!fill) {
2526
+ particle.fillEnabled = false;
2527
+ particle.fillAnimation = undefined;
2528
+ particle.fillColor = undefined;
2529
+ particle.fillOpacity = defaultOpacity;
2530
+ return;
2531
+ }
2532
+ const fillColor = AnimatableColor.create(paintColor === undefined ? undefined : AnimatableColor.create(undefined, paintColor), fill.color);
2533
+ particle.fillEnabled = fill.enable;
2534
+ particle.fillOpacity = getRangeValue(fill.opacity);
2535
+ particle.fillAnimation = fillColor.animation;
2536
+ const fillHslColor = rangeColorToHsl(this.#pluginManager, fillColor);
2537
+ if (!fillHslColor) {
2538
+ return;
2539
+ }
2540
+ particle.fillColor = getHslAnimationFromHsl(fillHslColor, particle.fillAnimation, container.retina.reduceFactor);
2541
+ }
2542
+ #initStroke(paint, particle, container) {
2543
+ const stroke = paint?.stroke, color = paint?.color, paintColor = color ?? undefined;
2544
+ if (!stroke) {
2545
+ particle.strokeAnimation = undefined;
2546
+ particle.strokeColor = undefined;
2547
+ particle.strokeOpacity = defaultOpacity;
2548
+ particle.strokeWidth = 0;
2460
2549
  return;
2461
2550
  }
2462
- updateColor(particle.fillColor, delta, this.#container.hdr);
2463
- updateColor(particle.strokeColor, delta, this.#container.hdr);
2551
+ const strokeColor = AnimatableColor.create(paintColor === undefined ? undefined : AnimatableColor.create(undefined, paintColor), stroke.color);
2552
+ particle.strokeWidth = getRangeValue(stroke.width) * container.retina.pixelRatio;
2553
+ particle.strokeOpacity = getRangeValue(stroke.opacity ?? defaultOpacity);
2554
+ particle.strokeAnimation = strokeColor.animation;
2555
+ const strokeHslColor = rangeColorToHsl(this.#pluginManager, strokeColor) ?? particle.getFillColor();
2556
+ if (!strokeHslColor) {
2557
+ return;
2558
+ }
2559
+ particle.strokeColor = getHslAnimationFromHsl(strokeHslColor, particle.strokeAnimation, container.retina.reduceFactor);
2464
2560
  }
2465
2561
  }
2466
2562
 
2467
2563
  async function loadPaintUpdater(engine) {
2468
- engine.checkVersion("4.4.0");
2564
+ engine.checkVersion("4.5.0");
2469
2565
  await engine.pluginManager.register(e => {
2470
2566
  e.pluginManager.addParticleUpdater("paint", container => {
2471
2567
  return Promise.resolve(new PaintUpdater(e.pluginManager, container));
@@ -2647,7 +2743,7 @@
2647
2743
  particle.pathRotation = rotateOptions.path;
2648
2744
  let rotateDirection = rotateOptions.direction;
2649
2745
  if (rotateDirection === RotateDirection.random) {
2650
- const index = Math.floor(getRandom() * double), minIndex = 0;
2746
+ const index = Math.floor(getRandom() * double);
2651
2747
  rotateDirection = index > minIndex ? RotateDirection.counterClockwise : RotateDirection.clockwise;
2652
2748
  }
2653
2749
  switch (rotateDirection) {
@@ -2694,7 +2790,7 @@
2694
2790
  }
2695
2791
 
2696
2792
  async function loadRotateUpdater(engine) {
2697
- engine.checkVersion("4.4.0");
2793
+ engine.checkVersion("4.5.0");
2698
2794
  await engine.pluginManager.register(e => {
2699
2795
  e.pluginManager.addParticleUpdater("rotate", container => {
2700
2796
  return Promise.resolve(new RotateUpdater(container));
@@ -2781,7 +2877,7 @@
2781
2877
  }
2782
2878
 
2783
2879
  async function loadSizeUpdater(engine) {
2784
- engine.checkVersion("4.4.0");
2880
+ engine.checkVersion("4.5.0");
2785
2881
  await engine.pluginManager.register(e => {
2786
2882
  e.pluginManager.addParticleUpdater("size", container => {
2787
2883
  return Promise.resolve(new SizeUpdater(container));
@@ -2805,7 +2901,7 @@
2805
2901
  }
2806
2902
 
2807
2903
  async function loadSquareShape(engine) {
2808
- engine.checkVersion("4.4.0");
2904
+ engine.checkVersion("4.5.0");
2809
2905
  await engine.pluginManager.register(e => {
2810
2906
  e.pluginManager.addShape(["edge", "square"], () => Promise.resolve(new SquareDrawer()));
2811
2907
  });
@@ -2944,21 +3040,28 @@
2944
3040
  });
2945
3041
  }
2946
3042
  clear() {
3043
+ const visited = new Set();
2947
3044
  for (const plugin of this.#canvasClearPlugins) {
3045
+ visited.add(plugin);
2948
3046
  if (plugin.canvasClear?.() ?? false) {
2949
- return;
3047
+ return plugin;
2950
3048
  }
2951
3049
  }
2952
3050
  for (const layer of Object.values(DrawLayer)) {
2953
3051
  if (typeof layer === "number") {
2954
3052
  for (const plugin of this.#getLayerPlugins(layer)) {
3053
+ if (visited.has(plugin)) {
3054
+ continue;
3055
+ }
3056
+ visited.add(plugin);
2955
3057
  if (plugin.canvasClear?.() ?? false) {
2956
- return;
3058
+ return plugin;
2957
3059
  }
2958
3060
  }
2959
3061
  }
2960
3062
  }
2961
3063
  this.canvasClear();
3064
+ return undefined;
2962
3065
  }
2963
3066
  destroy() {
2964
3067
  this.stop();
@@ -3036,8 +3139,7 @@
3036
3139
  });
3037
3140
  }
3038
3141
  drawParticles(delta) {
3039
- const { particles, actualOptions } = this.#container;
3040
- this.clear();
3142
+ const { particles, actualOptions } = this.#container, clearedPlugin = this.clear();
3041
3143
  particles.update(delta);
3042
3144
  this.draw(ctx => {
3043
3145
  const width = this.#canvasManager.size.width, height = this.#canvasManager.size.height;
@@ -3059,7 +3161,9 @@
3059
3161
  }
3060
3162
  }
3061
3163
  for (const plugin of this.#getLayerPlugins(DrawLayer.BackgroundMask)) {
3062
- plugin.canvasPaint?.();
3164
+ if (plugin !== clearedPlugin) {
3165
+ plugin.canvasPaint?.();
3166
+ }
3063
3167
  }
3064
3168
  for (const plugin of this.#getLayerPlugins(DrawLayer.CanvasSetup)) {
3065
3169
  plugin.drawSettingsSetup?.(ctx, delta);
@@ -3091,35 +3195,7 @@
3091
3195
  this.#layers[layer] = [];
3092
3196
  }
3093
3197
  }
3094
- for (const plugin of this.#container.plugins) {
3095
- if (plugin.particleFillColor ?? plugin.particleStrokeColor) {
3096
- this.#colorPlugins.push(plugin);
3097
- }
3098
- if (plugin.drawParticle) {
3099
- this.#drawParticlePlugins.push(plugin);
3100
- }
3101
- if (plugin.drawParticleSetup) {
3102
- this.#drawParticlesSetupPlugins.push(plugin);
3103
- }
3104
- if (plugin.drawParticleCleanup) {
3105
- this.#drawParticlesCleanupPlugins.push(plugin);
3106
- }
3107
- if (plugin.canvasClear) {
3108
- this.#canvasClearPlugins.push(plugin);
3109
- }
3110
- if (plugin.canvasPaint) {
3111
- this.#getLayerPlugins(DrawLayer.BackgroundMask).push(plugin);
3112
- }
3113
- if (plugin.drawSettingsSetup) {
3114
- this.#getLayerPlugins(DrawLayer.CanvasSetup).push(plugin);
3115
- }
3116
- if (plugin.draw) {
3117
- this.#getLayerPlugins(DrawLayer.PluginContent).push(plugin);
3118
- }
3119
- if (plugin.clearDraw ?? plugin.drawSettingsCleanup) {
3120
- this.#getLayerPlugins(DrawLayer.CanvasCleanup).push(plugin);
3121
- }
3122
- }
3198
+ this.#initPluginsArray();
3123
3199
  }
3124
3200
  initUpdaters() {
3125
3201
  this.#preDrawUpdaters = [];
@@ -3328,6 +3404,45 @@
3328
3404
  this.#reusablePluginColors[sColorIndex] = sColor;
3329
3405
  return this.#reusablePluginColors;
3330
3406
  }
3407
+ #initLayerPlugin(plugin) {
3408
+ const layerMap = [
3409
+ [DrawLayer.BackgroundMask, !!plugin.canvasPaint],
3410
+ [DrawLayer.CanvasSetup, !!plugin.drawSettingsSetup],
3411
+ [DrawLayer.PluginContent, !!plugin.draw],
3412
+ [DrawLayer.CanvasCleanup, !!(plugin.clearDraw ?? plugin.drawSettingsCleanup)],
3413
+ ];
3414
+ for (const [layer, active] of layerMap) {
3415
+ if (active) {
3416
+ this.#layers[layer].push(plugin);
3417
+ }
3418
+ }
3419
+ }
3420
+ #initPluginsArray() {
3421
+ for (const plugin of this.#container.plugins) {
3422
+ if (plugin.particleFillColor ?? plugin.particleStrokeColor) {
3423
+ this.#colorPlugins.push(plugin);
3424
+ }
3425
+ if (plugin.drawParticle) {
3426
+ this.#drawParticlePlugins.push(plugin);
3427
+ }
3428
+ if (plugin.drawParticleSetup) {
3429
+ this.#drawParticlesSetupPlugins.push(plugin);
3430
+ }
3431
+ if (plugin.drawParticleCleanup) {
3432
+ this.#drawParticlesCleanupPlugins.push(plugin);
3433
+ }
3434
+ if (plugin.canvasClear) {
3435
+ this.#canvasClearPlugins.push(plugin);
3436
+ }
3437
+ this.#initLayerPlugin(plugin);
3438
+ }
3439
+ }
3440
+ #isSupportedElement(element) {
3441
+ return ((typeof HTMLCanvasElement !== "undefined" && element instanceof HTMLCanvasElement) ||
3442
+ (typeof OffscreenCanvas !== "undefined" && element instanceof OffscreenCanvas) ||
3443
+ (typeof HTMLVideoElement !== "undefined" && element instanceof HTMLVideoElement) ||
3444
+ (typeof HTMLImageElement !== "undefined" && element instanceof HTMLImageElement));
3445
+ }
3331
3446
  #resolveBackgroundElement() {
3332
3447
  const background = this.#container.actualOptions.background;
3333
3448
  this.#backgroundElement = null;
@@ -3337,9 +3452,7 @@
3337
3452
  if (typeof background.element === "string") {
3338
3453
  if (typeof document !== "undefined") {
3339
3454
  const node = document.querySelector(background.element);
3340
- if ((typeof HTMLCanvasElement !== "undefined" && node instanceof HTMLCanvasElement) ||
3341
- (typeof HTMLVideoElement !== "undefined" && node instanceof HTMLVideoElement) ||
3342
- (typeof HTMLImageElement !== "undefined" && node instanceof HTMLImageElement)) {
3455
+ if (node && this.#isSupportedElement(node)) {
3343
3456
  this.#backgroundElement = node;
3344
3457
  }
3345
3458
  else if (node) {
@@ -3350,10 +3463,7 @@
3350
3463
  }
3351
3464
  }
3352
3465
  }
3353
- else if ((typeof HTMLCanvasElement !== "undefined" && background.element instanceof HTMLCanvasElement) ||
3354
- (typeof OffscreenCanvas !== "undefined" && background.element instanceof OffscreenCanvas) ||
3355
- (typeof HTMLVideoElement !== "undefined" && background.element instanceof HTMLVideoElement) ||
3356
- (typeof HTMLImageElement !== "undefined" && background.element instanceof HTMLImageElement)) {
3466
+ else if (this.#isSupportedElement(background.element)) {
3357
3467
  this.#backgroundElement = background.element;
3358
3468
  }
3359
3469
  }
@@ -3371,7 +3481,7 @@
3371
3481
  return transferredCanvas;
3372
3482
  }
3373
3483
  if (typeof canvas.transferControlToOffscreen !== "function") {
3374
- throw new TypeError("OffscreenCanvas is required but not supported by this browser");
3484
+ throw new TypeError(getErrorMessage(ErrorCodes$1.offscreenCanvasUnsupported));
3375
3485
  }
3376
3486
  try {
3377
3487
  const offscreenCanvas = canvas.transferControlToOffscreen();
@@ -3379,10 +3489,16 @@
3379
3489
  return offscreenCanvas;
3380
3490
  }
3381
3491
  catch {
3382
- throw new TypeError("OffscreenCanvas transfer failed");
3492
+ throw new TypeError(getErrorMessage(ErrorCodes$1.offscreenCanvasTransferFailed));
3383
3493
  }
3384
3494
  }, isHtmlCanvasElement = (canvas) => {
3385
3495
  return typeof HTMLCanvasElement !== "undefined" && canvas instanceof HTMLCanvasElement;
3496
+ }, getEffectiveColorSpace = (context) => {
3497
+ if (!context) {
3498
+ return undefined;
3499
+ }
3500
+ const colorInfo = context;
3501
+ return colorInfo.getContextAttributes?.().colorSpace ?? undefined;
3386
3502
  };
3387
3503
  function setStyle(canvas, style, important = false) {
3388
3504
  if (!style) {
@@ -3507,7 +3623,7 @@
3507
3623
  const elementStyle = element.style, color = rangeColorToRgb(this.#pluginManager, background.color);
3508
3624
  if (color) {
3509
3625
  const hdrOptions = container.actualOptions.hdr;
3510
- elementStyle.backgroundColor = getStyleFromRgb(color, container.hdr, background.opacity, hdrOptions.peakNits, hdrOptions.mode);
3626
+ elementStyle.backgroundColor = getStyleFromRgb(color, container.hdr, background.opacity, hdrOptions.peakNits, toEnumValue(HdrMode, hdrOptions.mode, HdrMode.standard));
3511
3627
  }
3512
3628
  else {
3513
3629
  elementStyle.backgroundColor = "";
@@ -3627,11 +3743,11 @@
3627
3743
  const container = this.#container, canSupportHdr = container.actualOptions.hdr.enable &&
3628
3744
  safeMatchMedia("(color-gamut: p3)")?.matches &&
3629
3745
  safeMatchMedia("(dynamic-range: high)")?.matches;
3630
- container.hdr = canSupportHdr ?? false;
3631
- container.hdrMode = container.actualOptions.hdr.mode;
3746
+ container.hdrMode = toEnumValue(HdrMode, container.actualOptions.hdr.mode, HdrMode.standard);
3632
3747
  container.peakNits = container.actualOptions.hdr.peakNits;
3633
3748
  const renderCanvas = this.renderCanvas;
3634
3749
  if (!renderCanvas) {
3750
+ container.hdr = canSupportHdr ?? false;
3635
3751
  return;
3636
3752
  }
3637
3753
  this.render.setContextSettings({
@@ -3650,7 +3766,6 @@
3650
3766
  context = null;
3651
3767
  }
3652
3768
  if (canSupportHdr && !context) {
3653
- container.hdr = false;
3654
3769
  const sdrSettings = {
3655
3770
  alpha: true,
3656
3771
  desynchronized: true,
@@ -3666,11 +3781,16 @@
3666
3781
  }
3667
3782
  }
3668
3783
  this.render.setContext(context);
3784
+ if (context) {
3785
+ const effectiveColorSpace = getEffectiveColorSpace(context);
3786
+ if (effectiveColorSpace !== undefined) {
3787
+ container.hdr = effectiveColorSpace === "display-p3";
3788
+ }
3789
+ }
3669
3790
  }
3670
3791
  #initHdrListeners() {
3671
3792
  this.#removeHdrListeners();
3672
3793
  const p3Query = safeMatchMedia("(color-gamut: p3)"), hdrQuery = safeMatchMedia("(dynamic-range: high)"), handleChange = () => {
3673
- this.#recreateRenderCanvas();
3674
3794
  this.#initContext();
3675
3795
  this.initBackground();
3676
3796
  }, listeners = [];
@@ -3706,16 +3826,6 @@
3706
3826
  element.style.setProperty(key, value, "important");
3707
3827
  }
3708
3828
  }
3709
- #recreateRenderCanvas() {
3710
- const renderCanvas = this.renderCanvas;
3711
- if (!renderCanvas) {
3712
- return;
3713
- }
3714
- if (this.domElement) {
3715
- return;
3716
- }
3717
- this.renderCanvas = new OffscreenCanvas(renderCanvas.width, renderCanvas.height);
3718
- }
3719
3829
  #removeHdrListeners() {
3720
3830
  if (!this.#hdrMediaListeners) {
3721
3831
  return;
@@ -3814,8 +3924,7 @@
3814
3924
  this.#resizeTimeout = undefined;
3815
3925
  }
3816
3926
  const handleResize = async () => {
3817
- const canvas = this.#container.canvas;
3818
- await canvas.windowResize();
3927
+ await this.#container.canvas.windowResize();
3819
3928
  };
3820
3929
  this.#resizeTimeout = setTimeout(() => void handleResize(), this.#container.actualOptions.resize.delay * millisecondsToSeconds);
3821
3930
  }
@@ -3843,8 +3952,8 @@
3843
3952
  }
3844
3953
  else if (!this.#resizeObserver && add && canvasEl) {
3845
3954
  this.#resizeObserver = new ResizeObserver((entries) => {
3846
- const entry = entries.find(e => e.target === canvasEl);
3847
- if (!entry) {
3955
+ const res = entries.some(e => e.target === canvasEl);
3956
+ if (!res) {
3848
3957
  return;
3849
3958
  }
3850
3959
  this.#handleWindowResize();
@@ -4108,10 +4217,10 @@
4108
4217
  return this.#modifiers.find(m => m.id === id);
4109
4218
  }
4110
4219
  getOpacity() {
4111
- 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;
4112
- this.#cachedOpacityData.fillOpacity = fillOpacity;
4220
+ 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;
4221
+ this.#cachedOpacityData.fillOpacity = this.fillOpacity ?? defaultOpacity$1;
4113
4222
  this.#cachedOpacityData.opacity = opacity * zOpacityFactor;
4114
- this.#cachedOpacityData.strokeOpacity = strokeOpacity;
4223
+ this.#cachedOpacityData.strokeOpacity = this.strokeOpacity ?? defaultOpacity$1;
4115
4224
  return this.#cachedOpacityData;
4116
4225
  }
4117
4226
  getPosition() {
@@ -4358,7 +4467,7 @@
4358
4467
  #initPosition(position) {
4359
4468
  const container = this.#container, zIndexValue = Math.floor(getRangeValue(this.options.zIndex.value)), initialPosition = this.#calcPosition(position, clamp(zIndexValue, minZ, container.zLayers));
4360
4469
  if (!initialPosition) {
4361
- throw new Error("a valid position cannot be found for particle");
4470
+ throw new Error(getErrorMessage(ErrorCodes$1.particlePositionNotFound));
4362
4471
  }
4363
4472
  this.position = initialPosition;
4364
4473
  this.initialPosition = this.position.copy();
@@ -4407,6 +4516,12 @@
4407
4516
  this.#circlePoolIdx = 0;
4408
4517
  this.#rectanglePoolIdx = 0;
4409
4518
  }
4519
+ get cellSize() {
4520
+ return this.#cellSize;
4521
+ }
4522
+ set cellSize(value) {
4523
+ this.#pendingCellSize = value;
4524
+ }
4410
4525
  clear() {
4411
4526
  this.#cells.clear();
4412
4527
  const pendingCellSize = this.#pendingCellSize;
@@ -4430,18 +4545,7 @@
4430
4545
  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);
4431
4546
  for (let cx = minCellX; cx <= maxCellX; cx++) {
4432
4547
  for (let cy = minCellY; cy <= maxCellY; cy++) {
4433
- const key = `${cx}_${cy}`, cellParticles = this.#cells.get(key);
4434
- if (!cellParticles) {
4435
- continue;
4436
- }
4437
- for (const p of cellParticles) {
4438
- if (check && !check(p)) {
4439
- continue;
4440
- }
4441
- if (range.contains(p.getPosition())) {
4442
- out.push(p);
4443
- }
4444
- }
4548
+ this.#queryCell(cx, cy, range, check, out);
4445
4549
  }
4446
4550
  }
4447
4551
  return out;
@@ -4456,14 +4560,23 @@
4456
4560
  this.#releaseShapes();
4457
4561
  return result;
4458
4562
  }
4459
- setCellSize(cellSize) {
4460
- this.#pendingCellSize = cellSize;
4461
- }
4462
4563
  #acquireCircle(x, y, r) {
4463
- return (this.#circlePool[this.#circlePoolIdx++] ??= new Circle(x, y, r)).reset(x, y, r);
4564
+ const idx = this.#circlePoolIdx++;
4565
+ let circle = this.#circlePool[idx];
4566
+ if (!circle) {
4567
+ circle = new Circle(x, y, r);
4568
+ this.#circlePool[idx] = circle;
4569
+ }
4570
+ return circle.reset(x, y, r);
4464
4571
  }
4465
4572
  #acquireRectangle(x, y, w, h) {
4466
- return (this.#rectanglePool[this.#rectanglePoolIdx++] ??= new Rectangle(x, y, w, h)).reset(x, y, w, h);
4573
+ const idx = this.#rectanglePoolIdx++;
4574
+ let rectangle = this.#rectanglePool[idx];
4575
+ if (!rectangle) {
4576
+ rectangle = new Rectangle(x, y, w, h);
4577
+ this.#rectanglePool[idx] = rectangle;
4578
+ }
4579
+ return rectangle.reset(x, y, w, h);
4467
4580
  }
4468
4581
  #cellKeyFromCoords(x, y) {
4469
4582
  const cellX = Math.floor(x / this.#cellSize), cellY = Math.floor(y / this.#cellSize);
@@ -4490,6 +4603,20 @@
4490
4603
  }
4491
4604
  return null;
4492
4605
  }
4606
+ #queryCell(cx, cy, range, check, out) {
4607
+ const cellParticles = this.#cells.get(`${cx}_${cy}`);
4608
+ if (!cellParticles) {
4609
+ return;
4610
+ }
4611
+ for (const p of cellParticles) {
4612
+ if (check && !check(p)) {
4613
+ continue;
4614
+ }
4615
+ if (range.contains(p.getPosition())) {
4616
+ out.push(p);
4617
+ }
4618
+ }
4619
+ }
4493
4620
  #releaseShapes() {
4494
4621
  this.#circlePoolIdx = 0;
4495
4622
  this.#rectanglePoolIdx = 0;
@@ -4498,9 +4625,9 @@
4498
4625
 
4499
4626
  class ParticlesManager {
4500
4627
  checkParticlePositionPlugins;
4501
- grid;
4502
4628
  #array;
4503
4629
  #container;
4630
+ #grid;
4504
4631
  #groupLimits;
4505
4632
  #limit;
4506
4633
  #nextId;
@@ -4524,7 +4651,7 @@
4524
4651
  this.#groupLimits = new Map();
4525
4652
  this.#particleBuckets = new Map();
4526
4653
  this.#zBuckets = this.#createBuckets(this.#container.zLayers);
4527
- this.grid = new SpatialHashGrid(spatialHashGridCellSize);
4654
+ this.#grid = new SpatialHashGrid(spatialHashGridCellSize);
4528
4655
  this.checkParticlePositionPlugins = [];
4529
4656
  this.#particleResetPlugins = [];
4530
4657
  this.#particleUpdatePlugins = [];
@@ -4535,23 +4662,12 @@
4535
4662
  get count() {
4536
4663
  return this.#array.length;
4537
4664
  }
4665
+ get grid() {
4666
+ return this.#grid;
4667
+ }
4538
4668
  addParticle(position, overrideOptions, group, initializer) {
4539
- const limitMode = this.#container.actualOptions.particles.number.limit.mode, limit = group === undefined ? this.#limit : (this.#groupLimits.get(group) ?? this.#limit), currentCount = this.count;
4540
- if (limit > minLimit) {
4541
- switch (limitMode) {
4542
- case LimitMode.delete: {
4543
- const countToRemove = currentCount + countOffset - limit;
4544
- if (countToRemove > minCount) {
4545
- this.removeQuantity(countToRemove);
4546
- }
4547
- break;
4548
- }
4549
- case LimitMode.wait:
4550
- if (currentCount >= limit) {
4551
- return;
4552
- }
4553
- break;
4554
- }
4669
+ if (this.#checkAndApplyLimits(group, this.count)) {
4670
+ return;
4555
4671
  }
4556
4672
  try {
4557
4673
  const particle = this.#pool.pop() ?? new Particle(this.#pluginManager, this.#container);
@@ -4615,7 +4731,7 @@
4615
4731
  return this.#array[index];
4616
4732
  }
4617
4733
  async init() {
4618
- const container = this.#container, options = container.actualOptions;
4734
+ const container = this.#container;
4619
4735
  this.checkParticlePositionPlugins = [];
4620
4736
  this.#updatePlugins = [];
4621
4737
  this.#particleUpdatePlugins = [];
@@ -4624,59 +4740,16 @@
4624
4740
  this.#postParticleUpdatePlugins = [];
4625
4741
  this.#particleBuckets.clear();
4626
4742
  this.#resetBuckets(container.zLayers);
4627
- this.grid = new SpatialHashGrid(spatialHashGridCellSize * container.retina.pixelRatio);
4628
- for (const plugin of container.plugins) {
4629
- if (plugin.redrawInit) {
4630
- await plugin.redrawInit();
4631
- }
4632
- if (plugin.checkParticlePosition) {
4633
- this.checkParticlePositionPlugins.push(plugin);
4634
- }
4635
- if (plugin.update) {
4636
- this.#updatePlugins.push(plugin);
4637
- }
4638
- if (plugin.particleUpdate) {
4639
- this.#particleUpdatePlugins.push(plugin);
4640
- }
4641
- if (plugin.postUpdate) {
4642
- this.#postUpdatePlugins.push(plugin);
4643
- }
4644
- if (plugin.particleReset) {
4645
- this.#particleResetPlugins.push(plugin);
4646
- }
4647
- if (plugin.postParticleUpdate) {
4648
- this.#postParticleUpdatePlugins.push(plugin);
4649
- }
4650
- }
4651
- await this.#container.initDrawersAndUpdaters();
4652
- for (const drawer of this.#container.effectDrawers.values()) {
4653
- await drawer.init?.(container);
4654
- }
4655
- for (const drawer of this.#container.shapeDrawers.values()) {
4656
- await drawer.init?.(container);
4657
- }
4658
- let handled = false;
4659
- for (const plugin of container.plugins) {
4660
- handled = plugin.particlesInitialization?.() ?? handled;
4661
- if (handled) {
4662
- break;
4663
- }
4664
- }
4665
- if (!handled) {
4666
- const particlesOptions = options.particles, groups = particlesOptions.groups;
4667
- for (const group in groups) {
4668
- const groupOptions = groups[group];
4669
- if (!groupOptions) {
4670
- continue;
4671
- }
4672
- for (let i = this.count, j = 0; j < groupOptions.number.value && i < particlesOptions.number.value; i++, j++) {
4673
- this.addParticle(undefined, groupOptions, group);
4674
- }
4675
- }
4676
- for (let i = this.count; i < particlesOptions.number.value; i++) {
4677
- this.addParticle();
4743
+ this.#grid = new SpatialHashGrid(spatialHashGridCellSize * container.retina.pixelRatio);
4744
+ this.#applyLimits(container.actualOptions.particles);
4745
+ const particlesOptions = container.actualOptions.particles, groups = particlesOptions.groups;
4746
+ for (const group in groups) {
4747
+ const groupData = groups[group];
4748
+ if (groupData) {
4749
+ this.#applyLimits(loadParticlesOptions(this.#pluginManager, this.#container, groupData), group, groupData);
4678
4750
  }
4679
4751
  }
4752
+ await this.#initPlugins();
4680
4753
  }
4681
4754
  push(nb, position, overrideOptions, group) {
4682
4755
  for (let i = 0; i < nb; i++) {
@@ -4691,13 +4764,13 @@
4691
4764
  remove(particle, group, override) {
4692
4765
  this.removeAt(this.#array.indexOf(particle), undefined, group, override);
4693
4766
  }
4694
- removeAt(index, quantity = defaultRemoveQuantity, group, override) {
4767
+ removeAt(index, quantity = defaultRemoveQuantity, group, override, matchGroup = true) {
4695
4768
  if (index < minIndex || index > this.count) {
4696
4769
  return;
4697
4770
  }
4698
4771
  let deleted = 0;
4699
4772
  for (let i = index; deleted < quantity && i < this.count; i++) {
4700
- if (this.#removeParticle(i, group, override)) {
4773
+ if (this.#removeParticle(i, group, override, matchGroup)) {
4701
4774
  i--;
4702
4775
  deleted++;
4703
4776
  }
@@ -4728,7 +4801,7 @@
4728
4801
  this.#resizeFactor = factor;
4729
4802
  }
4730
4803
  update(delta) {
4731
- this.grid.clear();
4804
+ this.#grid.clear();
4732
4805
  for (const plugin of this.#updatePlugins) {
4733
4806
  plugin.update?.(delta);
4734
4807
  }
@@ -4739,7 +4812,7 @@
4739
4812
  this.#updateParticlesPhase2(delta, particlesToDelete);
4740
4813
  if (particlesToDelete.size) {
4741
4814
  for (const particle of particlesToDelete) {
4742
- this.remove(particle);
4815
+ this.remove(particle, particle.group);
4743
4816
  }
4744
4817
  }
4745
4818
  this.#resizeFactor = undefined;
@@ -4750,12 +4823,7 @@
4750
4823
  #applyDensity(options, pluginsCount, group, groupOptions) {
4751
4824
  const numberOptions = options.number;
4752
4825
  if (!numberOptions.density.enable) {
4753
- if (group === undefined) {
4754
- this.#limit = numberOptions.limit.value;
4755
- }
4756
- else if (groupOptions?.number.limit.value ?? numberOptions.limit.value) {
4757
- this.#groupLimits.set(group, groupOptions?.number.limit.value ?? numberOptions.limit.value);
4758
- }
4826
+ this.#applyLimits(options, group, groupOptions);
4759
4827
  return;
4760
4828
  }
4761
4829
  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);
@@ -4763,7 +4831,10 @@
4763
4831
  this.#limit = numberOptions.limit.value * densityFactor;
4764
4832
  }
4765
4833
  else {
4766
- this.#groupLimits.set(group, numberOptions.limit.value * densityFactor);
4834
+ this.#groupLimits.set(group, {
4835
+ limit: numberOptions.limit.value * densityFactor,
4836
+ mode: toEnumValue(LimitMode, numberOptions.limit.mode, LimitMode.delete),
4837
+ });
4767
4838
  }
4768
4839
  if (particlesCount < particlesNumber) {
4769
4840
  this.push(Math.abs(particlesNumber - particlesCount), undefined, options, group);
@@ -4772,6 +4843,55 @@
4772
4843
  this.removeQuantity(particlesCount - particlesNumber, group);
4773
4844
  }
4774
4845
  }
4846
+ #applyLimits(options, group, groupOptions) {
4847
+ if (group === undefined) {
4848
+ this.#limit = options.number.limit.value;
4849
+ const groups = this.#container.actualOptions.particles.groups;
4850
+ for (const existingGroup of this.#groupLimits.keys()) {
4851
+ if (!(existingGroup in groups)) {
4852
+ this.#groupLimits.delete(existingGroup);
4853
+ }
4854
+ }
4855
+ }
4856
+ else {
4857
+ const limitValue = groupOptions?.number?.limit?.value ?? options.number.limit.value;
4858
+ if (limitValue > minLimit) {
4859
+ this.#groupLimits.set(group, {
4860
+ limit: limitValue,
4861
+ mode: toEnumValue(LimitMode, groupOptions?.number?.limit?.mode ?? options.number.limit.mode, LimitMode.delete),
4862
+ });
4863
+ }
4864
+ else {
4865
+ this.#groupLimits.delete(group);
4866
+ }
4867
+ }
4868
+ }
4869
+ #checkAndApplyLimits(group, currentCount) {
4870
+ const globalLimit = this.#limit, globalMode = this.#container.actualOptions.particles.number.limit.mode;
4871
+ if (globalLimit > minLimit && globalMode === LimitMode.wait && currentCount >= globalLimit) {
4872
+ return true;
4873
+ }
4874
+ const groupLimitEntry = group === undefined ? undefined : this.#groupLimits.get(group);
4875
+ if (groupLimitEntry && groupLimitEntry.limit > minLimit && groupLimitEntry.mode === LimitMode.wait) {
4876
+ const groupCount = this.filter(t => t.group === group).length;
4877
+ if (groupCount >= groupLimitEntry.limit) {
4878
+ return true;
4879
+ }
4880
+ }
4881
+ if (groupLimitEntry && groupLimitEntry.limit > minLimit && groupLimitEntry.mode === LimitMode.delete) {
4882
+ const groupCountToRemove = this.filter(t => t.group === group).length + countOffset - groupLimitEntry.limit;
4883
+ if (groupCountToRemove > minCount) {
4884
+ this.removeQuantity(groupCountToRemove, group);
4885
+ }
4886
+ }
4887
+ if (globalLimit > minLimit && globalMode === LimitMode.delete) {
4888
+ const globalCountToRemove = this.count + countOffset - globalLimit;
4889
+ if (globalCountToRemove > minCount) {
4890
+ this.#removeAny(globalCountToRemove);
4891
+ }
4892
+ }
4893
+ return false;
4894
+ }
4775
4895
  #createBuckets(zLayers) {
4776
4896
  const bucketCount = Math.max(Math.floor(zLayers), one);
4777
4897
  return Array.from({ length: bucketCount }, () => []);
@@ -4794,6 +4914,70 @@
4794
4914
  }
4795
4915
  return ((canvasSize.width * canvasSize.height) / (densityOptions.height * densityOptions.width * pxRatio ** squareExp));
4796
4916
  }
4917
+ async #initDrawersAndUpdaters() {
4918
+ const container = this.#container;
4919
+ await container.initDrawersAndUpdaters();
4920
+ for (const drawer of container.effectDrawers.values()) {
4921
+ await drawer.init?.(container);
4922
+ }
4923
+ for (const drawer of container.shapeDrawers.values()) {
4924
+ await drawer.init?.(container);
4925
+ }
4926
+ }
4927
+ async #initPlugins() {
4928
+ await this.#initPluginsArrays();
4929
+ await this.#initDrawersAndUpdaters();
4930
+ let handled = false;
4931
+ const container = this.#container;
4932
+ for (const plugin of container.plugins) {
4933
+ handled = plugin.particlesInitialization?.() ?? handled;
4934
+ if (handled) {
4935
+ break;
4936
+ }
4937
+ }
4938
+ if (handled) {
4939
+ return;
4940
+ }
4941
+ const particlesOptions = container.actualOptions.particles, groups = particlesOptions.groups;
4942
+ for (const group in groups) {
4943
+ const groupOptions = groups[group];
4944
+ if (!groupOptions) {
4945
+ continue;
4946
+ }
4947
+ for (let i = this.count, j = 0; j < groupOptions.number.value && i < particlesOptions.number.value; i++, j++) {
4948
+ this.addParticle(undefined, groupOptions, group);
4949
+ }
4950
+ }
4951
+ for (let i = this.count; i < particlesOptions.number.value; i++) {
4952
+ this.addParticle();
4953
+ }
4954
+ }
4955
+ async #initPluginsArrays() {
4956
+ const container = this.#container;
4957
+ for (const plugin of container.plugins) {
4958
+ if (plugin.redrawInit) {
4959
+ await plugin.redrawInit();
4960
+ }
4961
+ if (plugin.checkParticlePosition) {
4962
+ this.checkParticlePositionPlugins.push(plugin);
4963
+ }
4964
+ if (plugin.update) {
4965
+ this.#updatePlugins.push(plugin);
4966
+ }
4967
+ if (plugin.particleUpdate) {
4968
+ this.#particleUpdatePlugins.push(plugin);
4969
+ }
4970
+ if (plugin.postUpdate) {
4971
+ this.#postUpdatePlugins.push(plugin);
4972
+ }
4973
+ if (plugin.particleReset) {
4974
+ this.#particleResetPlugins.push(plugin);
4975
+ }
4976
+ if (plugin.postParticleUpdate) {
4977
+ this.#postParticleUpdatePlugins.push(plugin);
4978
+ }
4979
+ }
4980
+ }
4797
4981
  #insertParticleIntoBucket(particle) {
4798
4982
  const bucketIndex = this.#getBucketIndex(particle.position.z), bucket = this.#zBuckets[bucketIndex];
4799
4983
  if (!bucket) {
@@ -4802,12 +4986,15 @@
4802
4986
  bucket.push(particle);
4803
4987
  this.#particleBuckets.set(particle.id, bucketIndex);
4804
4988
  }
4805
- #removeParticle(index, group, override) {
4989
+ #removeAny(quantity) {
4990
+ this.removeAt(minIndex, quantity, undefined, undefined, false);
4991
+ }
4992
+ #removeParticle(index, group, override, matchGroup = true) {
4806
4993
  const particle = this.#array[index];
4807
4994
  if (!particle) {
4808
4995
  return false;
4809
4996
  }
4810
- if (particle.group !== group) {
4997
+ if (matchGroup && particle.group !== group) {
4811
4998
  return false;
4812
4999
  }
4813
5000
  this.#array.splice(index, deleteCount);
@@ -4894,7 +5081,7 @@
4894
5081
  particlesToDelete.add(particle);
4895
5082
  continue;
4896
5083
  }
4897
- this.grid.insert(particle);
5084
+ this.#grid.insert(particle);
4898
5085
  }
4899
5086
  return particlesToDelete;
4900
5087
  }
@@ -5070,7 +5257,6 @@
5070
5257
  this.shapeDrawers = new Map();
5071
5258
  this.particleUpdaters = [];
5072
5259
  this.plugins.length = 0;
5073
- this.#pluginManager.clearPlugins(this);
5074
5260
  this.destroyed = true;
5075
5261
  this.#onDestroy(remove);
5076
5262
  this.dispatchEvent(EventType.containerDestroyed);
@@ -5123,31 +5309,14 @@
5123
5309
  await this.initDrawersAndUpdaters();
5124
5310
  this.#options = loadContainerOptions(this.#pluginManager, this, this.#initialSourceOptions, this.sourceOptions);
5125
5311
  this.actualOptions = loadContainerOptions(this.#pluginManager, this, this.#options);
5126
- this.plugins.length = 0;
5127
- this.particleDestroyedPlugins.length = 0;
5128
- this.particleCreatedPlugins.length = 0;
5129
- this.particlePositionPlugins.length = 0;
5130
- for (const [plugin, containerPlugin] of allContainerPlugins) {
5131
- if (plugin.needsPlugin(this.actualOptions)) {
5132
- this.plugins.push(containerPlugin);
5133
- if (containerPlugin.particleCreated) {
5134
- this.particleCreatedPlugins.push(containerPlugin);
5135
- }
5136
- if (containerPlugin.particleDestroyed) {
5137
- this.particleDestroyedPlugins.push(containerPlugin);
5138
- }
5139
- if (containerPlugin.particlePosition) {
5140
- this.particlePositionPlugins.push(containerPlugin);
5141
- }
5142
- }
5143
- }
5312
+ this.#initPlugins(allContainerPlugins);
5144
5313
  this.retina.init();
5145
5314
  this.canvas.init();
5146
5315
  this.updateActualOptions();
5147
5316
  this.canvas.initBackground();
5148
5317
  this.canvas.resize();
5149
5318
  const { delay, duration, fpsLimit, smooth, zLayers } = this.actualOptions, hdrOptions = this.actualOptions.hdr;
5150
- this.hdrMode = hdrOptions.mode;
5319
+ this.hdrMode = toEnumValue(HdrMode, hdrOptions.mode, HdrMode.standard);
5151
5320
  this.peakNits = hdrOptions.peakNits;
5152
5321
  this.zLayers = zLayers;
5153
5322
  this.#duration = getRangeValue(duration) * millisecondsToSeconds;
@@ -5168,9 +5337,9 @@
5168
5337
  }
5169
5338
  async initDrawersAndUpdaters() {
5170
5339
  const pluginManager = this.#pluginManager;
5171
- this.effectDrawers = await pluginManager.getEffectDrawers(this, true);
5172
- this.shapeDrawers = await pluginManager.getShapeDrawers(this, true);
5173
- this.particleUpdaters = await pluginManager.getUpdaters(this, true);
5340
+ this.effectDrawers = await getItemMapFromInitializer(this, pluginManager.initializers.effects);
5341
+ this.shapeDrawers = await getItemMapFromInitializer(this, pluginManager.initializers.shapes);
5342
+ this.particleUpdaters = await getItemsFromInitializer(this, pluginManager.initializers.updaters);
5174
5343
  }
5175
5344
  pause() {
5176
5345
  if (!guardCheck(this)) {
@@ -5281,6 +5450,27 @@
5281
5450
  }
5282
5451
  return refresh;
5283
5452
  }
5453
+ #initPlugins(allContainerPlugins) {
5454
+ this.plugins.length = 0;
5455
+ this.particleDestroyedPlugins.length = 0;
5456
+ this.particleCreatedPlugins.length = 0;
5457
+ this.particlePositionPlugins.length = 0;
5458
+ for (const [plugin, containerPlugin] of allContainerPlugins) {
5459
+ if (!plugin.needsPlugin(this.actualOptions)) {
5460
+ continue;
5461
+ }
5462
+ this.plugins.push(containerPlugin);
5463
+ if (containerPlugin.particleCreated) {
5464
+ this.particleCreatedPlugins.push(containerPlugin);
5465
+ }
5466
+ if (containerPlugin.particleDestroyed) {
5467
+ this.particleDestroyedPlugins.push(containerPlugin);
5468
+ }
5469
+ if (containerPlugin.particlePosition) {
5470
+ this.particlePositionPlugins.push(containerPlugin);
5471
+ }
5472
+ }
5473
+ }
5284
5474
  #nextFrame(timestamp) {
5285
5475
  try {
5286
5476
  if (!this.#smooth &&
@@ -5325,6 +5515,11 @@
5325
5515
  this.#container = container;
5326
5516
  this.#instancesManager.initContainer(container);
5327
5517
  }
5518
+ draw(context, _delta) {
5519
+ for (const emitter of this.#instancesManager.getArray(this.#container)) {
5520
+ emitter.draw(context);
5521
+ }
5522
+ }
5328
5523
  async init() {
5329
5524
  const emittersOptions = this.#container.actualOptions.emitters;
5330
5525
  if (isArray(emittersOptions)) {
@@ -5395,14 +5590,21 @@
5395
5590
  this.#pluginManager = pluginManager;
5396
5591
  }
5397
5592
  async addEmitter(container, options, position) {
5398
- const emitterOptions = new Emitter();
5399
- emitterOptions.load(options);
5400
- const { EmitterInstance } = await Promise.resolve().then(function () { return EmitterInstance$1; }), emitter = new EmitterInstance(this.#pluginManager, container, (emitter) => {
5401
- this.removeEmitter(container, emitter);
5402
- }, emitterOptions, position);
5403
- await emitter.init();
5404
- this.getArray(container).push(emitter);
5405
- return emitter;
5593
+ return this.addEmitters(container, [{ options, position }]).then(t => t[defaultIndex]);
5594
+ }
5595
+ async addEmitters(container, emitters) {
5596
+ const { EmitterInstance } = await Promise.resolve().then(function () { return EmitterInstance$1; }), res = [];
5597
+ for (const { options, position } of emitters) {
5598
+ const emitterOptions = new Emitter();
5599
+ emitterOptions.load(options);
5600
+ const emitter = new EmitterInstance(this.#pluginManager, container, (emitter) => {
5601
+ this.removeEmitter(container, emitter);
5602
+ }, emitterOptions, position);
5603
+ await emitter.init();
5604
+ this.getArray(container).push(emitter);
5605
+ res.push(emitter);
5606
+ }
5607
+ return res;
5406
5608
  }
5407
5609
  clear(container) {
5408
5610
  this.initContainer(container);
@@ -5429,6 +5631,7 @@
5429
5631
  : array.find(t => t.name === idxOrName);
5430
5632
  };
5431
5633
  container.addEmitter = async (options, position) => this.addEmitter(container, options, position);
5634
+ container.addEmitters = async (emitters) => this.addEmitters(container, emitters);
5432
5635
  container.removeEmitter = (idxOrName) => {
5433
5636
  const emitter = container.getEmitter?.(idxOrName);
5434
5637
  if (emitter) {
@@ -5449,7 +5652,7 @@
5449
5652
  };
5450
5653
  }
5451
5654
  removeEmitter(container, emitter) {
5452
- const index = this.getArray(container).indexOf(emitter), minIndex = 0, deleteCount = 1;
5655
+ const index = this.getArray(container).indexOf(emitter), deleteCount = 1;
5453
5656
  if (index >= minIndex) {
5454
5657
  this.getArray(container).splice(index, deleteCount);
5455
5658
  }
@@ -5504,6 +5707,7 @@
5504
5707
  #particlesOptions;
5505
5708
  #paused;
5506
5709
  #pluginManager;
5710
+ #positionOverride = false;
5507
5711
  #removeCallback;
5508
5712
  #resizeObserver;
5509
5713
  #shape;
@@ -5580,6 +5784,31 @@
5580
5784
  });
5581
5785
  this.play();
5582
5786
  }
5787
+ draw(context) {
5788
+ if (!this.options.draw || !this.#shape) {
5789
+ return;
5790
+ }
5791
+ const container = this.#container, fillEnabled = this.options.spawn.fill?.enable ?? true;
5792
+ context.save();
5793
+ context.beginPath();
5794
+ if (fillEnabled) {
5795
+ context.fillStyle = this.spawnFillColor
5796
+ ? getStyleFromHsl(this.spawnFillColor, container.hdr, this.spawnFillOpacity ?? defaultOpacity$1, container.peakNits, container.hdrMode)
5797
+ : getStyleFromRgb({ r: 0, g: 0, b: 0 }, container.hdr, defaultOpacity$1, container.peakNits, container.hdrMode);
5798
+ }
5799
+ if (this.spawnStrokeColor) {
5800
+ context.strokeStyle = getStyleFromHsl(this.spawnStrokeColor, container.hdr, this.spawnStrokeOpacity ?? defaultOpacity$1, container.peakNits, container.hdrMode);
5801
+ context.lineWidth = this.spawnStrokeWidth ?? defaultStrokeWidth;
5802
+ }
5803
+ this.#shape.draw?.(context);
5804
+ if (fillEnabled) {
5805
+ context.fill();
5806
+ }
5807
+ if (this.spawnStrokeColor) {
5808
+ context.stroke();
5809
+ }
5810
+ context.restore();
5811
+ }
5583
5812
  externalPause() {
5584
5813
  this.#paused = true;
5585
5814
  this.pause();
@@ -5617,11 +5846,14 @@
5617
5846
  }
5618
5847
  }
5619
5848
  resize() {
5620
- const initialPosition = this.#initialPosition, container = this.#container;
5621
- this.position =
5622
- initialPosition && isPointInside(initialPosition, container.canvas.size, Vector.origin)
5623
- ? initialPosition
5624
- : this.#calcPosition();
5849
+ const container = this.#container;
5850
+ if (!this.#positionOverride) {
5851
+ const initialPosition = this.#initialPosition;
5852
+ this.position =
5853
+ initialPosition && isPointInside(initialPosition, container.canvas.size, Vector.origin)
5854
+ ? initialPosition
5855
+ : this.#calcPosition();
5856
+ }
5625
5857
  this.#size = this.#calcSize();
5626
5858
  this.size =
5627
5859
  this.#size.mode === PixelMode.percent
@@ -5632,6 +5864,11 @@
5632
5864
  : { width: this.#size.width, height: this.#size.height };
5633
5865
  this.#shape?.resize(this.position, this.size);
5634
5866
  }
5867
+ setPosition(position) {
5868
+ this.#positionOverride = true;
5869
+ this.position = { ...position };
5870
+ this.#shape?.resize(this.position, this.size);
5871
+ }
5635
5872
  update(delta) {
5636
5873
  if (this.#paused) {
5637
5874
  return;
@@ -5827,6 +6064,7 @@
5827
6064
  exports.loadSquaresPreset = loadSquaresPreset;
5828
6065
  exports.tsParticles = tsParticles;
5829
6066
 
5830
- }));
6067
+ })(g.__tsParticlesInternals.presets.squares = g.__tsParticlesInternals.presets.squares || {});
6068
+ })(typeof globalThis !== "undefined" ? globalThis : typeof window !== "undefined" ? window : self);
6069
+
5831
6070
  Object.assign(globalThis.window || globalThis, { loadSquaresPreset: (globalThis.__tsParticlesInternals.presets.squares || {}).loadSquaresPreset });
5832
- delete (globalThis.window || globalThis).tsparticlesInternalExports;