@tsparticles/preset-confetti-explosions 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.confettiExplosions = global.__tsParticlesInternals.presets.confettiExplosions || {})));
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 = 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 = 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
  }
@@ -283,11 +314,61 @@
283
314
  };
284
315
  }
285
316
  function parseAlpha(input) {
286
- const defaultAlpha = 1;
287
317
  if (!input) {
288
318
  return defaultAlpha;
289
319
  }
290
- return input.endsWith("%") ? parseFloat(input) / percentDenominator : parseFloat(input);
320
+ return input.endsWith("%") ? Number.parseFloat(input) / percentDenominator : Number.parseFloat(input);
321
+ }
322
+
323
+ const ErrorCodes$2 = {
324
+ engineVersionMismatch: "TSP-1001",
325
+ particlePositionNotFound: "TSP-1002",
326
+ pluginRegisterAfterLoad: "TSP-1003",
327
+ offscreenCanvasUnsupported: "TSP-1101",
328
+ offscreenCanvasTransferFailed: "TSP-1102",
329
+ hdrEnableInvalid: "TSP-1201",
330
+ hdrModeInvalid: "TSP-1202",
331
+ hdrPeakNitsInvalid: "TSP-1203",
332
+ };
333
+
334
+ const messages = {
335
+ [ErrorCodes$2.engineVersionMismatch]: "The tsParticles version is different from the loaded plugins version. Engine version: {0}. Plugin version: {1}",
336
+ [ErrorCodes$2.particlePositionNotFound]: "a valid position cannot be found for particle",
337
+ [ErrorCodes$2.pluginRegisterAfterLoad]: "Register plugins can only be done before calling tsParticles.load()",
338
+ [ErrorCodes$2.offscreenCanvasUnsupported]: "OffscreenCanvas is required but not supported by this browser",
339
+ [ErrorCodes$2.offscreenCanvasTransferFailed]: "OffscreenCanvas transfer failed",
340
+ [ErrorCodes$2.hdrEnableInvalid]: 'Invalid HDR "enable" value: expected a boolean, got "{0}"',
341
+ [ErrorCodes$2.hdrModeInvalid]: 'Invalid HDR "mode" value: expected one of {0}, got "{1}"',
342
+ [ErrorCodes$2.hdrPeakNitsInvalid]: 'Invalid HDR "peakNits" value: expected a positive number, got "{0}"',
343
+ };
344
+
345
+ let registeredMessages;
346
+ const ensureRegisteredMessages = () => {
347
+ registeredMessages ??= new Map(Object.entries(messages));
348
+ return registeredMessages;
349
+ }, toStringValue$1 = (value) => String(value), format = (template, args) => {
350
+ return template.replace(/\{(\d+)\}/g, (match, index) => {
351
+ const arg = args[Number(index)];
352
+ return arg === undefined ? match : toStringValue$1(arg);
353
+ });
354
+ };
355
+ function addErrorMessages(extraMessages) {
356
+ if (typeof process !== "undefined" && process.env.NODE_ENV === "production") {
357
+ return;
358
+ }
359
+ const catalog = ensureRegisteredMessages();
360
+ for (const [code, message] of Object.entries(extraMessages)) {
361
+ if (message !== undefined) {
362
+ catalog.set(code, message);
363
+ }
364
+ }
365
+ }
366
+ function getErrorMessage(code, ...args) {
367
+ if (typeof process !== "undefined" && process.env.NODE_ENV === "production") {
368
+ return `[tsParticles Error ${code}] https://particles.js.org/errors/#${code}`;
369
+ }
370
+ const template = ensureRegisteredMessages().get(code) ?? `Unknown error code ${code}`;
371
+ return format(template, args);
291
372
  }
292
373
 
293
374
  var OutModeDirection;
@@ -304,7 +385,6 @@
304
385
  PixelMode["percent"] = "percent";
305
386
  })(PixelMode || (PixelMode = {}));
306
387
 
307
- const minRadius = 0;
308
388
  function isForbiddenKey(key) {
309
389
  return key === "__proto__" || key === "constructor" || key === "prototype";
310
390
  }
@@ -500,22 +580,84 @@
500
580
  element.removeEventListener(event, handler, removeOptions);
501
581
  }
502
582
  }
503
- async function getItemsFromInitializer(container, map, initializers, force = false) {
504
- let res = map.get(container);
505
- if (!res || force) {
506
- res = await Promise.all([...initializers.values()].map(t => t(container)));
507
- map.set(container, res);
583
+ async function getItemsFromInitializer(container, initializers) {
584
+ return await Promise.all([...initializers.values()].map(t => t(container)));
585
+ }
586
+ async function getItemMapFromInitializer(container, initializers) {
587
+ const entries = await Promise.all([...initializers.entries()].map(([key, initializer]) => initializer(container).then(item => [key, item])));
588
+ return new Map(entries);
589
+ }
590
+ async function getDataFromUrl(data) {
591
+ const url = itemFromSingleOrMultiple(data.url, data.index);
592
+ if (!url) {
593
+ return data.fallback;
508
594
  }
509
- return res;
595
+ try {
596
+ const response = await fetch(url);
597
+ if (response.ok) {
598
+ const current = (await response.json());
599
+ if (isSourceOptionsValue(current)) {
600
+ return current;
601
+ }
602
+ getLogger().error("invalid configuration data while retrieving config file");
603
+ }
604
+ else {
605
+ getLogger().error(`${response.status.toString()} while retrieving config file`);
606
+ }
607
+ }
608
+ catch (error) {
609
+ getLogger().error(`error while retrieving config file: ${error}`);
610
+ }
611
+ return data.fallback;
510
612
  }
511
- async function getItemMapFromInitializer(container, map, initializers, force = false) {
512
- let res = map.get(container);
513
- if (!res || force) {
514
- const entries = await Promise.all([...initializers.entries()].map(([key, initializer]) => initializer(container).then(item => [key, item])));
515
- res = new Map(entries);
516
- map.set(container, res);
613
+ function isSourceOptionsValue(value) {
614
+ if (isArray(value)) {
615
+ return value.every((entry) => isObject(entry) && !isArray(entry));
517
616
  }
518
- return res;
617
+ return isObject(value) && !isArray(value);
618
+ }
619
+ function getCanvasFromContainer(domContainer) {
620
+ let canvasEl;
621
+ const documentSafe = safeDocument(), isCanvas = domContainer instanceof HTMLCanvasElement || domContainer.tagName.toLowerCase() === canvasTag;
622
+ if (isCanvas) {
623
+ canvasEl = domContainer;
624
+ canvasEl.dataset[generatedAttribute] ??= generatedFalse;
625
+ if (canvasEl.dataset[generatedAttribute] === generatedTrue) {
626
+ canvasEl.style.width ||= fullPercent;
627
+ canvasEl.style.height ||= fullPercent;
628
+ canvasEl.style.pointerEvents = "none";
629
+ canvasEl.style.setProperty("pointer-events", "none");
630
+ }
631
+ }
632
+ else {
633
+ const existingCanvases = domContainer.getElementsByTagName(canvasTag), foundCanvas = existingCanvases.item(canvasFirstIndex);
634
+ if (foundCanvas) {
635
+ canvasEl = foundCanvas;
636
+ canvasEl.dataset[generatedAttribute] = generatedFalse;
637
+ }
638
+ else {
639
+ canvasEl = documentSafe.createElement(canvasTag);
640
+ canvasEl.dataset[generatedAttribute] = generatedTrue;
641
+ domContainer.appendChild(canvasEl);
642
+ }
643
+ canvasEl.style.width ||= fullPercent;
644
+ canvasEl.style.height ||= fullPercent;
645
+ canvasEl.style.pointerEvents = "none";
646
+ canvasEl.style.setProperty("pointer-events", "none");
647
+ }
648
+ return canvasEl;
649
+ }
650
+ function getDomContainer(id, source) {
651
+ const documentSafe = safeDocument();
652
+ let domContainer = source ?? documentSafe.getElementById(id);
653
+ if (domContainer) {
654
+ return domContainer;
655
+ }
656
+ domContainer = documentSafe.createElement("canvas");
657
+ domContainer.id = id;
658
+ domContainer.dataset[generatedAttribute] = generatedTrue;
659
+ documentSafe.body.append(domContainer);
660
+ return domContainer;
519
661
  }
520
662
 
521
663
  class EventDispatcher {
@@ -586,7 +728,6 @@
586
728
  class PluginManager {
587
729
  colorManagers = new Map();
588
730
  easingFunctions = new Map();
589
- effectDrawers = new Map();
590
731
  initializers = {
591
732
  effects: new Map(),
592
733
  shapes: new Map(),
@@ -595,8 +736,6 @@
595
736
  palettes = new Map();
596
737
  plugins = [];
597
738
  presets = new Map();
598
- shapeDrawers = new Map();
599
- updaters = new Map();
600
739
  #allLoadersSet = new Set();
601
740
  #configs = new Map();
602
741
  #engine;
@@ -614,57 +753,79 @@
614
753
  }
615
754
  return res;
616
755
  }
756
+ get initialized() {
757
+ return this.#initialized;
758
+ }
617
759
  addColorManager(name, manager) {
760
+ if (this.#initialized) {
761
+ return;
762
+ }
618
763
  this.colorManagers.set(name, manager);
619
764
  }
620
765
  addConfig(config) {
766
+ if (this.#initialized) {
767
+ return;
768
+ }
621
769
  const key = config.key ?? config.name ?? "default";
622
770
  this.#configs.set(key, config);
623
771
  this.#engine.dispatchEvent(EventType.configAdded, { data: { name: key, config } });
624
772
  }
625
773
  addEasing(name, easing) {
774
+ if (this.#initialized) {
775
+ return;
776
+ }
626
777
  if (this.easingFunctions.get(name)) {
627
778
  return;
628
779
  }
629
780
  this.easingFunctions.set(name, easing);
630
781
  }
631
782
  addEffect(effect, drawer) {
783
+ if (this.#initialized) {
784
+ return;
785
+ }
632
786
  this.initializers.effects.set(effect, drawer);
633
787
  }
634
788
  addPalette(name, palette) {
789
+ if (this.#initialized) {
790
+ return;
791
+ }
635
792
  this.palettes.set(name, palette);
636
793
  }
637
794
  addParticleUpdater(name, updaterInitializer) {
795
+ if (this.#initialized) {
796
+ return;
797
+ }
638
798
  this.initializers.updaters.set(name, updaterInitializer);
639
799
  }
640
800
  addPlugin(plugin) {
801
+ if (this.#initialized) {
802
+ return;
803
+ }
641
804
  if (this.getPlugin(plugin.id)) {
642
805
  return;
643
806
  }
644
807
  this.plugins.push(plugin);
645
808
  }
646
809
  addPreset(preset, options, override = false) {
810
+ if (this.#initialized) {
811
+ return;
812
+ }
647
813
  if (!(override || !this.getPreset(preset))) {
648
814
  return;
649
815
  }
650
816
  this.presets.set(preset, options);
651
817
  }
652
818
  addShape(shapes, drawer) {
819
+ if (this.#initialized) {
820
+ return;
821
+ }
653
822
  for (const shape of shapes) {
654
823
  this.initializers.shapes.set(shape, drawer);
655
824
  }
656
825
  }
657
- clearPlugins(container) {
658
- this.effectDrawers.delete(container);
659
- this.shapeDrawers.delete(container);
660
- this.updaters.delete(container);
661
- }
662
826
  getEasing(name) {
663
827
  return this.easingFunctions.get(name) ?? ((value) => value);
664
828
  }
665
- getEffectDrawers(container, force = false) {
666
- return getItemMapFromInitializer(container, this.effectDrawers, this.initializers.effects, force);
667
- }
668
829
  getPalette(name) {
669
830
  return this.palettes.get(name);
670
831
  }
@@ -674,12 +835,6 @@
674
835
  getPreset(preset) {
675
836
  return this.presets.get(preset);
676
837
  }
677
- async getShapeDrawers(container, force = false) {
678
- return getItemMapFromInitializer(container, this.shapeDrawers, this.initializers.shapes, force);
679
- }
680
- async getUpdaters(container, force = false) {
681
- return getItemsFromInitializer(container, this.updaters, this.initializers.updaters, force);
682
- }
683
838
  async init() {
684
839
  if (this.#initialized || this.#isRunningLoaders) {
685
840
  return;
@@ -698,16 +853,9 @@
698
853
  this.#initialized = true;
699
854
  }
700
855
  }
701
- loadParticlesOptions(container, options, ...sourceOptions) {
702
- const updaters = this.updaters.get(container);
703
- if (!updaters) {
704
- return;
705
- }
706
- updaters.forEach(updater => updater.loadOptions?.(options, ...sourceOptions));
707
- }
708
856
  async register(...loaders) {
709
857
  if (this.#initialized) {
710
- throw new Error("Register plugins can only be done before calling tsParticles.load()");
858
+ throw new Error(getErrorMessage(ErrorCodes$2.pluginRegisterAfterLoad));
711
859
  }
712
860
  for (const loader of loaders) {
713
861
  if (this.#isRunningLoaders) {
@@ -719,88 +867,15 @@
719
867
  }
720
868
  }
721
869
  async #runLoader(loader, executed, allLoaders) {
722
- if (executed.has(loader))
870
+ if (executed.has(loader)) {
723
871
  return;
872
+ }
724
873
  executed.add(loader);
725
874
  allLoaders.add(loader);
726
875
  await loader(this.#engine);
727
876
  }
728
877
  }
729
878
 
730
- const errorPrefix = "tsParticles - Error";
731
- const wrap = (fn) => (...args) => {
732
- fn(...args);
733
- }, _logger = {
734
- debug: wrap(console.debug),
735
- error: (message, ...optionalParams) => {
736
- console.error(`${errorPrefix} - ${message}`, ...optionalParams);
737
- },
738
- info: wrap(console.info),
739
- log: wrap(console.log),
740
- trace: wrap(console.trace),
741
- verbose: wrap(console.log),
742
- warning: wrap(console.warn),
743
- };
744
- function getLogger() {
745
- return _logger;
746
- }
747
-
748
- const fullPercent = "100%";
749
- async function getDataFromUrl(data) {
750
- const url = itemFromSingleOrMultiple(data.url, data.index);
751
- if (!url) {
752
- return data.fallback;
753
- }
754
- const response = await fetch(url);
755
- if (response.ok) {
756
- return (await response.json());
757
- }
758
- getLogger().error(`${response.status.toString()} while retrieving config file`);
759
- return data.fallback;
760
- }
761
- const getCanvasFromContainer = (domContainer) => {
762
- const documentSafe = safeDocument();
763
- let canvasEl;
764
- const isCanvas = domContainer instanceof HTMLCanvasElement || domContainer.tagName.toLowerCase() === canvasTag;
765
- if (isCanvas) {
766
- canvasEl = domContainer;
767
- canvasEl.dataset[generatedAttribute] ??= generatedFalse;
768
- if (canvasEl.dataset[generatedAttribute] === generatedTrue) {
769
- canvasEl.style.width ||= fullPercent;
770
- canvasEl.style.height ||= fullPercent;
771
- canvasEl.style.pointerEvents = "none";
772
- canvasEl.style.setProperty("pointer-events", "none");
773
- }
774
- }
775
- else {
776
- const existingCanvases = domContainer.getElementsByTagName(canvasTag), foundCanvas = existingCanvases.item(canvasFirstIndex);
777
- if (foundCanvas) {
778
- canvasEl = foundCanvas;
779
- canvasEl.dataset[generatedAttribute] = generatedFalse;
780
- }
781
- else {
782
- canvasEl = documentSafe.createElement(canvasTag);
783
- canvasEl.dataset[generatedAttribute] = generatedTrue;
784
- domContainer.appendChild(canvasEl);
785
- }
786
- canvasEl.style.width ||= fullPercent;
787
- canvasEl.style.height ||= fullPercent;
788
- canvasEl.style.pointerEvents = "none";
789
- canvasEl.style.setProperty("pointer-events", "none");
790
- }
791
- return canvasEl;
792
- }, getDomContainer = (id, source) => {
793
- const documentSafe = safeDocument();
794
- let domContainer = source ?? documentSafe.getElementById(id);
795
- if (domContainer) {
796
- return domContainer;
797
- }
798
- domContainer = documentSafe.createElement("canvas");
799
- domContainer.id = id;
800
- domContainer.dataset[generatedAttribute] = generatedTrue;
801
- documentSafe.body.append(domContainer);
802
- return domContainer;
803
- };
804
879
  class Engine {
805
880
  pluginManager = new PluginManager(this);
806
881
  #domArray = [];
@@ -810,7 +885,7 @@
810
885
  return this.#domArray;
811
886
  }
812
887
  get version() {
813
- return "4.4.0";
888
+ return "4.5.0";
814
889
  }
815
890
  addEventListener(type, listener) {
816
891
  this.#eventDispatcher.addEventListener(type, listener);
@@ -819,7 +894,7 @@
819
894
  if (this.version === pluginVersion) {
820
895
  return;
821
896
  }
822
- throw new Error(`The tsParticles version is different from the loaded plugins version. Engine version: ${this.version}. Plugin version: ${pluginVersion}`);
897
+ throw new Error(getErrorMessage(ErrorCodes$2.engineVersionMismatch, this.version, pluginVersion));
823
898
  }
824
899
  dispatchEvent(type, args) {
825
900
  this.#eventDispatcher.dispatchEvent(type, args);
@@ -1068,20 +1143,6 @@
1068
1143
  DrawLayer[DrawLayer["Foreground"] = 7] = "Foreground";
1069
1144
  })(DrawLayer || (DrawLayer = {}));
1070
1145
 
1071
- class OptionLoader {
1072
- load(data) {
1073
- if (isNull(data)) {
1074
- return;
1075
- }
1076
- this.doLoad(data);
1077
- }
1078
- }
1079
- function loadOptions(options, ...sourceOptionsArr) {
1080
- for (const sourceOptions of sourceOptionsArr) {
1081
- options.load(sourceOptions);
1082
- }
1083
- }
1084
-
1085
1146
  function loadProperty(obj, key, value) {
1086
1147
  if (value !== undefined) {
1087
1148
  obj[key] = value;
@@ -1113,6 +1174,20 @@
1113
1174
  }
1114
1175
  }
1115
1176
 
1177
+ class OptionLoader {
1178
+ load(data) {
1179
+ if (isNull(data)) {
1180
+ return;
1181
+ }
1182
+ this.doLoad(data);
1183
+ }
1184
+ }
1185
+ function loadOptions(options, ...sourceOptionsArr) {
1186
+ for (const sourceOptions of sourceOptionsArr) {
1187
+ options.load(sourceOptions);
1188
+ }
1189
+ }
1190
+
1116
1191
  class AnimationOptions extends OptionLoader {
1117
1192
  count = 0;
1118
1193
  decay = 0;
@@ -1263,15 +1338,14 @@
1263
1338
  peakNits = defaultPeakNits;
1264
1339
  doLoad(data) {
1265
1340
  if (data.enable !== undefined && !isBoolean(data.enable)) {
1266
- throw new Error(`Invalid HDR "enable" value: expected a boolean, got "${String(data.enable)}"`);
1341
+ throw new Error(getErrorMessage(ErrorCodes$2.hdrEnableInvalid, String(data.enable)));
1267
1342
  }
1268
- if (data.mode !== undefined &&
1269
- (typeof data.mode !== "string" || !Object.values(HdrMode).includes(data.mode))) {
1270
- throw new Error(`Invalid HDR "mode" value: expected one of ${Object.values(HdrMode).join(", ")}, got "${toStringValue(data.mode)}"`);
1343
+ if (data.mode !== undefined && !isEnumValue(HdrMode, data.mode)) {
1344
+ throw new Error(getErrorMessage(ErrorCodes$2.hdrModeInvalid, Object.values(HdrMode).join(", "), toStringValue(data.mode)));
1271
1345
  }
1272
1346
  if (data.peakNits !== undefined &&
1273
1347
  (!isNumber(data.peakNits) || !Number.isFinite(data.peakNits) || data.peakNits <= minPeakNits)) {
1274
- throw new Error(`Invalid HDR "peakNits" value: expected a positive number, got "${String(data.peakNits)}"`);
1348
+ throw new Error(getErrorMessage(ErrorCodes$2.hdrPeakNitsInvalid, String(data.peakNits)));
1275
1349
  }
1276
1350
  loadProperty(this, "enable", data.enable);
1277
1351
  loadProperty(this, "mode", data.mode);
@@ -1649,12 +1723,10 @@
1649
1723
  plugin.loadParticlesOptions(this.#container, this, data);
1650
1724
  }
1651
1725
  }
1652
- const updaters = this.#pluginManager.updaters.get(this.#container);
1653
- if (updaters) {
1654
- for (const updater of updaters) {
1655
- if (updater.loadOptions) {
1656
- updater.loadOptions(this, data);
1657
- }
1726
+ const updaters = this.#container.particleUpdaters;
1727
+ for (const updater of updaters) {
1728
+ if (updater.loadOptions) {
1729
+ updater.loadOptions(this, data);
1658
1730
  }
1659
1731
  }
1660
1732
  }
@@ -1987,9 +2059,9 @@
1987
2059
  const grayscaleValue = Math.round(lNormalized * rgbMax);
1988
2060
  return { r: grayscaleValue, g: grayscaleValue, b: grayscaleValue };
1989
2061
  }
1990
- const temp1 = lNormalized < half
2062
+ const temp2 = lNormalized < half
1991
2063
  ? lNormalized * (sNormalizedOffset + sNormalized)
1992
- : 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));
2064
+ : 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));
1993
2065
  return { r: Math.round(red), g: Math.round(green), b: Math.round(blue) };
1994
2066
  }
1995
2067
  function hslToRgbFloat(hsl) {
@@ -1998,9 +2070,9 @@
1998
2070
  const grayscaleValue = lNormalized * rgbMax;
1999
2071
  return { r: grayscaleValue, g: grayscaleValue, b: grayscaleValue };
2000
2072
  }
2001
- const temp1 = lNormalized < half
2073
+ const temp2 = lNormalized < half
2002
2074
  ? lNormalized * (sNormalizedOffset + sNormalized)
2003
- : 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));
2075
+ : 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));
2004
2076
  return { r: red, g: green, b: blue };
2005
2077
  }
2006
2078
  function hslaToRgba(hsla) {
@@ -2214,7 +2286,7 @@
2214
2286
  }
2215
2287
 
2216
2288
  async function loadBlendPlugin(engine) {
2217
- engine.checkVersion("4.4.0");
2289
+ engine.checkVersion("4.5.0");
2218
2290
  await engine.pluginManager.register(e => {
2219
2291
  e.pluginManager.addPlugin(new BlendPlugin());
2220
2292
  });
@@ -2251,7 +2323,7 @@
2251
2323
  }
2252
2324
 
2253
2325
  async function loadCircleShape(engine) {
2254
- engine.checkVersion("4.4.0");
2326
+ engine.checkVersion("4.5.0");
2255
2327
  await engine.pluginManager.register(e => {
2256
2328
  e.pluginManager.addShape(["circle"], () => {
2257
2329
  return Promise.resolve(new CircleDrawer());
@@ -2266,7 +2338,7 @@
2266
2338
  RgbIndexes[RgbIndexes["b"] = 3] = "b";
2267
2339
  RgbIndexes[RgbIndexes["a"] = 4] = "a";
2268
2340
  })(RgbIndexes$1 || (RgbIndexes$1 = {}));
2269
- 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;
2341
+ 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;
2270
2342
  class HexColorManager {
2271
2343
  accepts(input) {
2272
2344
  return input.startsWith("#");
@@ -2299,7 +2371,7 @@
2299
2371
  }
2300
2372
 
2301
2373
  async function loadHexColorPlugin(engine) {
2302
- engine.checkVersion("4.4.0");
2374
+ engine.checkVersion("4.5.0");
2303
2375
  await engine.pluginManager.register(e => {
2304
2376
  e.pluginManager.addColorManager("hex", new HexColorManager());
2305
2377
  });
@@ -2339,7 +2411,7 @@
2339
2411
  if (!this.accepts(input)) {
2340
2412
  return;
2341
2413
  }
2342
- const result = hslRegex.exec(input), minLength = 4, defaultAlpha = 1, radix = 10;
2414
+ const result = hslRegex.exec(input), minLength = 4, radix = 10;
2343
2415
  return result
2344
2416
  ? hslaToRgba({
2345
2417
  a: result.length > minLength ? parseAlpha(result[HslIndexes.a]) : defaultAlpha,
@@ -2352,12 +2424,20 @@
2352
2424
  }
2353
2425
 
2354
2426
  async function loadHslColorPlugin(engine) {
2355
- engine.checkVersion("4.4.0");
2427
+ engine.checkVersion("4.5.0");
2356
2428
  await engine.pluginManager.register(e => {
2357
2429
  e.pluginManager.addColorManager("hsl", new HslColorManager());
2358
2430
  });
2359
2431
  }
2360
2432
 
2433
+ const ErrorCodes$1 = {
2434
+ baseMoverNotLoaded: "TSP-3203",
2435
+ };
2436
+
2437
+ const ErrorMessages$1 = {
2438
+ [ErrorCodes$1.baseMoverNotLoaded]: "tsParticles Base Mover is not loaded",
2439
+ };
2440
+
2361
2441
  class MovePlugin {
2362
2442
  id = "move";
2363
2443
  #pluginManager;
@@ -2376,20 +2456,20 @@
2376
2456
  }
2377
2457
 
2378
2458
  async function loadMovePlugin(engine) {
2379
- engine.checkVersion("4.4.0");
2459
+ engine.checkVersion("4.5.0");
2460
+ if (typeof process !== "undefined" && process.env.NODE_ENV !== "production") {
2461
+ addErrorMessages(ErrorMessages$1);
2462
+ }
2380
2463
  await engine.pluginManager.register(e => {
2381
2464
  const moveEngine = e, movePluginManager = moveEngine.pluginManager;
2382
2465
  movePluginManager.initializers.pathGenerators ??= new Map();
2383
- movePluginManager.pathGenerators ??= new Map();
2384
2466
  movePluginManager.addPathGenerator = (name, generator) => {
2467
+ if (movePluginManager.initialized) {
2468
+ return;
2469
+ }
2385
2470
  movePluginManager.initializers.pathGenerators ??= new Map();
2386
2471
  movePluginManager.initializers.pathGenerators.set(name, generator);
2387
2472
  };
2388
- movePluginManager.getPathGenerators = async (container, force = false) => {
2389
- movePluginManager.initializers.pathGenerators ??= new Map();
2390
- movePluginManager.pathGenerators ??= new Map();
2391
- return getItemMapFromInitializer(container, movePluginManager.pathGenerators, movePluginManager.initializers.pathGenerators, force);
2392
- };
2393
2473
  e.pluginManager.addPlugin(new MovePlugin(e.pluginManager));
2394
2474
  });
2395
2475
  }
@@ -2592,7 +2672,7 @@
2592
2672
  }
2593
2673
 
2594
2674
  async function loadOpacityUpdater(engine) {
2595
- engine.checkVersion("4.4.0");
2675
+ engine.checkVersion("4.5.0");
2596
2676
  await engine.pluginManager.register(e => {
2597
2677
  e.pluginManager.addParticleUpdater("opacity", container => {
2598
2678
  return Promise.resolve(new OpacityUpdater(container));
@@ -2601,70 +2681,60 @@
2601
2681
  }
2602
2682
 
2603
2683
  const boundsMin = 0;
2604
- function bounceHorizontal(data) {
2605
- if ((data.outMode !== OutMode.bounce && data.outMode !== OutMode.split) ||
2606
- (data.direction !== OutModeDirection.left && data.direction !== OutModeDirection.right)) {
2607
- return;
2608
- }
2609
- if (data.bounds.right < boundsMin && data.direction === OutModeDirection.left) {
2610
- data.particle.position.x = data.size + data.offset.x;
2611
- }
2612
- else if (data.bounds.left > data.canvasSize.width && data.direction === OutModeDirection.right) {
2613
- data.particle.position.x = data.canvasSize.width - data.size - data.offset.x;
2614
- }
2615
- const velocity = data.particle.velocity.x;
2616
- let bounced = false;
2617
- if (data.outOfCanvas &&
2618
- ((data.direction === OutModeDirection.right && velocity > minVelocity) ||
2619
- (data.direction === OutModeDirection.left && velocity < minVelocity))) {
2620
- const newVelocity = getRangeValue(data.particle.options.bounce.horizontal.value);
2621
- data.particle.velocity.x *= -newVelocity;
2622
- bounced = true;
2623
- }
2624
- if (!bounced) {
2625
- return;
2626
- }
2627
- const minPos = data.offset.x + data.size;
2628
- if (data.outOfCanvas && data.direction === OutModeDirection.right) {
2629
- data.particle.position.x = data.canvasSize.width - minPos;
2630
- }
2631
- else if (data.outOfCanvas && data.direction === OutModeDirection.left) {
2632
- data.particle.position.x = minPos;
2633
- }
2634
- if (data.outMode === OutMode.split) {
2635
- data.particle.destroy();
2636
- }
2637
- }
2638
- function bounceVertical(data) {
2639
- if ((data.outMode !== OutMode.bounce && data.outMode !== OutMode.split) ||
2640
- (data.direction !== OutModeDirection.bottom && data.direction !== OutModeDirection.top)) {
2684
+ const bounceAxisConfigs = {
2685
+ [OutModeDirection.left]: {
2686
+ axis: "x",
2687
+ canvas: "width",
2688
+ bounce: "horizontal",
2689
+ negativeEdge: "right",
2690
+ positiveEdge: "left",
2691
+ negative: true,
2692
+ },
2693
+ [OutModeDirection.right]: {
2694
+ axis: "x",
2695
+ canvas: "width",
2696
+ bounce: "horizontal",
2697
+ negativeEdge: "right",
2698
+ positiveEdge: "left",
2699
+ negative: false,
2700
+ },
2701
+ [OutModeDirection.top]: {
2702
+ axis: "y",
2703
+ canvas: "height",
2704
+ bounce: "vertical",
2705
+ negativeEdge: "bottom",
2706
+ positiveEdge: "top",
2707
+ negative: true,
2708
+ },
2709
+ [OutModeDirection.bottom]: {
2710
+ axis: "y",
2711
+ canvas: "height",
2712
+ bounce: "vertical",
2713
+ negativeEdge: "bottom",
2714
+ positiveEdge: "top",
2715
+ negative: false,
2716
+ },
2717
+ };
2718
+ function bounce(data) {
2719
+ if ((data.outMode !== OutMode.bounce && data.outMode !== OutMode.split) || !(data.direction in bounceAxisConfigs)) {
2641
2720
  return;
2642
2721
  }
2643
- if (data.bounds.bottom < boundsMin && data.direction === OutModeDirection.top) {
2644
- data.particle.position.y = data.size + data.offset.y;
2722
+ const config = bounceAxisConfigs[data.direction], bounds = data.bounds, canvasDim = data.canvasSize[config.canvas], position = data.particle.position, velocity = data.particle.velocity[config.axis];
2723
+ if (config.negative && bounds[config.negativeEdge] < boundsMin) {
2724
+ position[config.axis] = data.size + data.offset[config.axis];
2645
2725
  }
2646
- else if (data.bounds.top > data.canvasSize.height && data.direction === OutModeDirection.bottom) {
2647
- data.particle.position.y = data.canvasSize.height - data.size - data.offset.y;
2726
+ else if (!config.negative && bounds[config.positiveEdge] > canvasDim) {
2727
+ position[config.axis] = canvasDim - data.size - data.offset[config.axis];
2648
2728
  }
2649
- const velocity = data.particle.velocity.y;
2650
- let bounced = false;
2651
2729
  if (data.outOfCanvas &&
2652
- ((data.direction === OutModeDirection.bottom && velocity > minVelocity) ||
2653
- (data.direction === OutModeDirection.top && velocity < minVelocity))) {
2654
- const newVelocity = getRangeValue(data.particle.options.bounce.vertical.value);
2655
- data.particle.velocity.y *= -newVelocity;
2656
- bounced = true;
2730
+ ((config.negative && velocity < minVelocity) || (!config.negative && velocity > minVelocity))) {
2731
+ data.particle.velocity[config.axis] *= -getRangeValue(data.particle.options.bounce[config.bounce].value);
2657
2732
  }
2658
- if (!bounced) {
2733
+ else {
2659
2734
  return;
2660
2735
  }
2661
- const minPos = data.offset.y + data.size;
2662
- if (data.outOfCanvas && data.direction === OutModeDirection.bottom) {
2663
- data.particle.position.y = data.canvasSize.height - minPos;
2664
- }
2665
- else if (data.outOfCanvas && data.direction === OutModeDirection.top) {
2666
- data.particle.position.y = minPos;
2667
- }
2736
+ const minPos = data.offset[config.axis] + data.size;
2737
+ position[config.axis] = config.negative ? minPos : canvasDim - minPos;
2668
2738
  if (data.outMode === OutMode.split) {
2669
2739
  data.particle.destroy();
2670
2740
  }
@@ -2680,26 +2750,19 @@
2680
2750
  OutMode.bounce,
2681
2751
  OutMode.split,
2682
2752
  ];
2683
- this.#particleBouncePlugins = container.plugins.filter(p => p.particleBounce !== undefined);
2753
+ this.#particleBouncePlugins = container.plugins.filter(p => !!p.particleBounce);
2684
2754
  }
2685
2755
  update(particle, direction, delta, outMode) {
2686
2756
  if (!this.modes.includes(outMode)) {
2687
2757
  return;
2688
2758
  }
2689
- const container = this.#container;
2690
- let handled = false;
2691
2759
  for (const plugin of this.#particleBouncePlugins) {
2692
- handled = plugin.particleBounce?.(particle, delta, direction) ?? false;
2693
- if (handled) {
2694
- break;
2760
+ if (plugin.particleBounce?.(particle, delta, direction)) {
2761
+ return;
2695
2762
  }
2696
2763
  }
2697
- if (handled) {
2698
- return;
2699
- }
2700
- const pos = particle.getPosition(), offset = particle.offset, size = particle.getRadius(), bounds = calculateBounds(pos, size), canvasSize = container.canvas.size, outOfCanvas = !particle.isInsideCanvasForOutMode(outMode, direction);
2701
- bounceHorizontal({ particle, outMode, direction, bounds, canvasSize, offset, outOfCanvas, size });
2702
- bounceVertical({ particle, outMode, direction, bounds, canvasSize, offset, outOfCanvas, size });
2764
+ const pos = particle.getPosition(), offset = particle.offset, size = particle.getRadius(), bounds = calculateBounds(pos, size), canvasSize = this.#container.canvas.size, outOfCanvas = !particle.isInsideCanvasForOutMode(outMode, direction);
2765
+ bounce({ particle, outMode, direction, bounds, canvasSize, offset, outOfCanvas, size });
2703
2766
  }
2704
2767
  }
2705
2768
 
@@ -2788,108 +2851,109 @@
2788
2851
  return;
2789
2852
  }
2790
2853
  const container = this.#container;
2791
- switch (particle.outType) {
2792
- case ParticleOutType.inside: {
2793
- const { x: vx, y: vy } = particle.velocity;
2794
- updateVector.setTo(originPoint);
2795
- updateVector.length = particle.moveCenter.radius;
2796
- updateVector.angle = particle.velocity.angle + Math.PI;
2797
- updateVector.addTo(particle.moveCenter);
2798
- const { dx, dy } = getDistances(particle.position, updateVector);
2799
- if ((vx <= minVelocity && dx >= minDistance) ||
2800
- (vy <= minVelocity && dy >= minDistance) ||
2801
- (vx >= minVelocity && dx <= minDistance) ||
2802
- (vy >= minVelocity && dy <= minDistance)) {
2803
- return;
2804
- }
2805
- particle.position.x = Math.floor(randomInRangeValue({
2806
- min: 0,
2807
- max: container.canvas.size.width,
2808
- }));
2809
- particle.position.y = Math.floor(randomInRangeValue({
2810
- min: 0,
2811
- max: container.canvas.size.height,
2812
- }));
2813
- const { dx: newDx, dy: newDy } = getDistances(particle.position, particle.moveCenter);
2814
- particle.direction = Math.atan2(-newDy, -newDx);
2815
- particle.velocity.angle = particle.direction;
2816
- particle.justWarped = true;
2817
- break;
2854
+ if (particle.outType === ParticleOutType.inside) {
2855
+ this.#applyOutModeInside(particle, container);
2856
+ }
2857
+ else {
2858
+ if (particle.isInsideCanvasForOutMode(outMode, direction)) {
2859
+ return;
2818
2860
  }
2819
- default: {
2820
- if (particle.isInsideCanvasForOutMode(outMode, direction)) {
2821
- return;
2822
- }
2823
- switch (particle.outType) {
2824
- case ParticleOutType.outside: {
2825
- particle.position.x =
2826
- Math.floor(randomInRangeValue({
2827
- min: -particle.moveCenter.radius,
2828
- max: particle.moveCenter.radius,
2829
- })) + particle.moveCenter.x;
2830
- particle.position.y =
2831
- Math.floor(randomInRangeValue({
2832
- min: -particle.moveCenter.radius,
2833
- max: particle.moveCenter.radius,
2834
- })) + particle.moveCenter.y;
2835
- const { dx, dy } = getDistances(particle.position, particle.moveCenter);
2836
- if (particle.moveCenter.radius) {
2837
- particle.direction = Math.atan2(dy, dx);
2838
- particle.velocity.angle = particle.direction;
2839
- }
2840
- particle.justWarped = true;
2841
- break;
2842
- }
2843
- case ParticleOutType.normal: {
2844
- const warp = particle.options.move.warp, canvasSize = container.canvas.size, newPos = {
2845
- bottom: canvasSize.height + particle.getRadius() + particle.offset.y,
2846
- left: -particle.getRadius() - particle.offset.x,
2847
- right: canvasSize.width + particle.getRadius() + particle.offset.x,
2848
- top: -particle.getRadius() - particle.offset.y,
2849
- }, sizeValue = particle.getRadius(), nextBounds = calculateBounds(particle.position, sizeValue);
2850
- if (direction === OutModeDirection.right && nextBounds.left > canvasSize.width + particle.offset.x) {
2851
- particle.position.x = newPos.left;
2852
- particle.initialPosition.x = particle.position.x;
2853
- if (!warp) {
2854
- particle.position.y = getRandom() * canvasSize.height;
2855
- particle.initialPosition.y = particle.position.y;
2856
- }
2857
- particle.justWarped = true;
2858
- }
2859
- else if (direction === OutModeDirection.left && nextBounds.right < -particle.offset.x) {
2860
- particle.position.x = newPos.right;
2861
- particle.initialPosition.x = particle.position.x;
2862
- if (!warp) {
2863
- particle.position.y = getRandom() * canvasSize.height;
2864
- particle.initialPosition.y = particle.position.y;
2865
- }
2866
- particle.justWarped = true;
2867
- }
2868
- if (direction === OutModeDirection.bottom && nextBounds.top > canvasSize.height + particle.offset.y) {
2869
- if (!warp) {
2870
- particle.position.x = getRandom() * canvasSize.width;
2871
- particle.initialPosition.x = particle.position.x;
2872
- }
2873
- particle.position.y = newPos.top;
2874
- particle.initialPosition.y = particle.position.y;
2875
- particle.justWarped = true;
2876
- }
2877
- else if (direction === OutModeDirection.top && nextBounds.bottom < -particle.offset.y) {
2878
- if (!warp) {
2879
- particle.position.x = getRandom() * canvasSize.width;
2880
- particle.initialPosition.x = particle.position.x;
2881
- }
2882
- particle.position.y = newPos.bottom;
2883
- particle.initialPosition.y = particle.position.y;
2884
- particle.justWarped = true;
2885
- }
2886
- break;
2887
- }
2888
- }
2889
- break;
2861
+ if (particle.outType === ParticleOutType.outside) {
2862
+ this.#applyParticleModeOutside(particle);
2863
+ }
2864
+ else {
2865
+ this.#applyOutModeNormal(particle, container, direction);
2890
2866
  }
2891
2867
  }
2892
2868
  }
2869
+ #applyOutModeInside(particle, container) {
2870
+ const { x: vx, y: vy } = particle.velocity;
2871
+ updateVector.setTo(originPoint);
2872
+ updateVector.length = particle.moveCenter.radius;
2873
+ updateVector.angle = particle.velocity.angle + Math.PI;
2874
+ updateVector.addTo(particle.moveCenter);
2875
+ const { dx, dy } = getDistances(particle.position, updateVector);
2876
+ if ((vx <= minVelocity && dx >= minDistance) ||
2877
+ (vy <= minVelocity && dy >= minDistance) ||
2878
+ (vx >= minVelocity && dx <= minDistance) ||
2879
+ (vy >= minVelocity && dy <= minDistance)) {
2880
+ return;
2881
+ }
2882
+ particle.position.x = Math.floor(randomInRangeValue({
2883
+ min: 0,
2884
+ max: container.canvas.size.width,
2885
+ }));
2886
+ particle.position.y = Math.floor(randomInRangeValue({
2887
+ min: 0,
2888
+ max: container.canvas.size.height,
2889
+ }));
2890
+ const { dx: newDx, dy: newDy } = getDistances(particle.position, particle.moveCenter);
2891
+ particle.direction = Math.atan2(-newDy, -newDx);
2892
+ particle.velocity.angle = particle.direction;
2893
+ particle.justWarped = true;
2894
+ }
2895
+ #applyOutModeNormal(particle, container, direction) {
2896
+ const warp = particle.options.move.warp, canvasSize = container.canvas.size, sizeValue = particle.getRadius(), newPos = {
2897
+ bottom: canvasSize.height + sizeValue + particle.offset.y,
2898
+ left: -sizeValue - particle.offset.x,
2899
+ right: canvasSize.width + sizeValue + particle.offset.x,
2900
+ top: -sizeValue - particle.offset.y,
2901
+ }, nextBounds = calculateBounds(particle.position, sizeValue);
2902
+ if (direction === OutModeDirection.right && nextBounds.left > canvasSize.width + particle.offset.x) {
2903
+ particle.position.x = newPos.left;
2904
+ particle.initialPosition.x = particle.position.x;
2905
+ if (!warp) {
2906
+ particle.position.y = getRandom() * canvasSize.height;
2907
+ particle.initialPosition.y = particle.position.y;
2908
+ }
2909
+ particle.justWarped = true;
2910
+ }
2911
+ else if (direction === OutModeDirection.left && nextBounds.right < -particle.offset.x) {
2912
+ particle.position.x = newPos.right;
2913
+ particle.initialPosition.x = particle.position.x;
2914
+ if (!warp) {
2915
+ particle.position.y = getRandom() * canvasSize.height;
2916
+ particle.initialPosition.y = particle.position.y;
2917
+ }
2918
+ particle.justWarped = true;
2919
+ }
2920
+ if (direction === OutModeDirection.bottom && nextBounds.top > canvasSize.height + particle.offset.y) {
2921
+ if (!warp) {
2922
+ particle.position.x = getRandom() * canvasSize.width;
2923
+ particle.initialPosition.x = particle.position.x;
2924
+ }
2925
+ particle.position.y = newPos.top;
2926
+ particle.initialPosition.y = particle.position.y;
2927
+ particle.justWarped = true;
2928
+ }
2929
+ else if (direction === OutModeDirection.top && nextBounds.bottom < -particle.offset.y) {
2930
+ if (!warp) {
2931
+ particle.position.x = getRandom() * canvasSize.width;
2932
+ particle.initialPosition.x = particle.position.x;
2933
+ }
2934
+ particle.position.y = newPos.bottom;
2935
+ particle.initialPosition.y = particle.position.y;
2936
+ particle.justWarped = true;
2937
+ }
2938
+ }
2939
+ #applyParticleModeOutside(particle) {
2940
+ particle.position.x =
2941
+ Math.floor(randomInRangeValue({
2942
+ min: -particle.moveCenter.radius,
2943
+ max: particle.moveCenter.radius,
2944
+ })) + particle.moveCenter.x;
2945
+ particle.position.y =
2946
+ Math.floor(randomInRangeValue({
2947
+ min: -particle.moveCenter.radius,
2948
+ max: particle.moveCenter.radius,
2949
+ })) + particle.moveCenter.y;
2950
+ const { dx, dy } = getDistances(particle.position, particle.moveCenter);
2951
+ if (particle.moveCenter.radius) {
2952
+ particle.direction = Math.atan2(dy, dx);
2953
+ particle.velocity.angle = particle.direction;
2954
+ }
2955
+ particle.justWarped = true;
2956
+ }
2893
2957
  }
2894
2958
 
2895
2959
  const checkOutMode = (outModes, outMode) => {
@@ -2937,7 +3001,7 @@
2937
3001
  }
2938
3002
 
2939
3003
  async function loadOutModesUpdater(engine) {
2940
- engine.checkVersion("4.4.0");
3004
+ engine.checkVersion("4.5.0");
2941
3005
  await engine.pluginManager.register(e => {
2942
3006
  e.pluginManager.addParticleUpdater("outModes", container => {
2943
3007
  return Promise.resolve(new OutOfCanvasUpdater(container));
@@ -2954,39 +3018,9 @@
2954
3018
  this.#pluginManager = pluginManager;
2955
3019
  }
2956
3020
  init(particle) {
2957
- 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;
2958
- if (fill) {
2959
- const fillColor = AnimatableColor.create(paintColor === undefined ? undefined : AnimatableColor.create(undefined, paintColor), fill.color);
2960
- particle.fillEnabled = fill.enable;
2961
- particle.fillOpacity = getRangeValue(fill.opacity);
2962
- particle.fillAnimation = fillColor.animation;
2963
- const fillHslColor = rangeColorToHsl(this.#pluginManager, fillColor);
2964
- if (fillHslColor) {
2965
- particle.fillColor = getHslAnimationFromHsl(fillHslColor, particle.fillAnimation, container.retina.reduceFactor);
2966
- }
2967
- }
2968
- else {
2969
- particle.fillEnabled = false;
2970
- particle.fillAnimation = undefined;
2971
- particle.fillColor = undefined;
2972
- particle.fillOpacity = defaultOpacity;
2973
- }
2974
- if (stroke) {
2975
- const strokeColor = AnimatableColor.create(paintColor === undefined ? undefined : AnimatableColor.create(undefined, paintColor), stroke.color);
2976
- particle.strokeWidth = getRangeValue(stroke.width) * container.retina.pixelRatio;
2977
- particle.strokeOpacity = getRangeValue(stroke.opacity ?? defaultOpacity);
2978
- particle.strokeAnimation = strokeColor.animation;
2979
- const strokeHslColor = rangeColorToHsl(this.#pluginManager, strokeColor) ?? particle.getFillColor();
2980
- if (strokeHslColor) {
2981
- particle.strokeColor = getHslAnimationFromHsl(strokeHslColor, particle.strokeAnimation, container.retina.reduceFactor);
2982
- }
2983
- }
2984
- else {
2985
- particle.strokeAnimation = undefined;
2986
- particle.strokeColor = undefined;
2987
- particle.strokeOpacity = defaultOpacity;
2988
- particle.strokeWidth = 0;
2989
- }
3021
+ const container = this.#container, options = particle.options, paint = itemFromSingleOrMultiple(options.paint, particle.id, options.reduceDuplicates);
3022
+ this.#initFill(paint, particle, container);
3023
+ this.#initStroke(paint, particle, container);
2990
3024
  }
2991
3025
  isEnabled(particle) {
2992
3026
  const { fillAnimation, fillColor, strokeAnimation, strokeColor } = particle, fillEnabled = !!fillAnimation &&
@@ -3002,13 +3036,51 @@
3002
3036
  if (!this.isEnabled(particle)) {
3003
3037
  return;
3004
3038
  }
3005
- updateColor(particle.fillColor, delta, this.#container.hdr);
3006
- updateColor(particle.strokeColor, delta, this.#container.hdr);
3039
+ updateColor(particle.fillColor, delta, this.#container.hdr);
3040
+ updateColor(particle.strokeColor, delta, this.#container.hdr);
3041
+ }
3042
+ #initFill(paint, particle, container) {
3043
+ const fill = paint?.fill, color = paint?.color, paintColor = color ?? undefined;
3044
+ if (!fill) {
3045
+ particle.fillEnabled = false;
3046
+ particle.fillAnimation = undefined;
3047
+ particle.fillColor = undefined;
3048
+ particle.fillOpacity = defaultOpacity;
3049
+ return;
3050
+ }
3051
+ const fillColor = AnimatableColor.create(paintColor === undefined ? undefined : AnimatableColor.create(undefined, paintColor), fill.color);
3052
+ particle.fillEnabled = fill.enable;
3053
+ particle.fillOpacity = getRangeValue(fill.opacity);
3054
+ particle.fillAnimation = fillColor.animation;
3055
+ const fillHslColor = rangeColorToHsl(this.#pluginManager, fillColor);
3056
+ if (!fillHslColor) {
3057
+ return;
3058
+ }
3059
+ particle.fillColor = getHslAnimationFromHsl(fillHslColor, particle.fillAnimation, container.retina.reduceFactor);
3060
+ }
3061
+ #initStroke(paint, particle, container) {
3062
+ const stroke = paint?.stroke, color = paint?.color, paintColor = color ?? undefined;
3063
+ if (!stroke) {
3064
+ particle.strokeAnimation = undefined;
3065
+ particle.strokeColor = undefined;
3066
+ particle.strokeOpacity = defaultOpacity;
3067
+ particle.strokeWidth = 0;
3068
+ return;
3069
+ }
3070
+ const strokeColor = AnimatableColor.create(paintColor === undefined ? undefined : AnimatableColor.create(undefined, paintColor), stroke.color);
3071
+ particle.strokeWidth = getRangeValue(stroke.width) * container.retina.pixelRatio;
3072
+ particle.strokeOpacity = getRangeValue(stroke.opacity ?? defaultOpacity);
3073
+ particle.strokeAnimation = strokeColor.animation;
3074
+ const strokeHslColor = rangeColorToHsl(this.#pluginManager, strokeColor) ?? particle.getFillColor();
3075
+ if (!strokeHslColor) {
3076
+ return;
3077
+ }
3078
+ particle.strokeColor = getHslAnimationFromHsl(strokeHslColor, particle.strokeAnimation, container.retina.reduceFactor);
3007
3079
  }
3008
3080
  }
3009
3081
 
3010
3082
  async function loadPaintUpdater(engine) {
3011
- engine.checkVersion("4.4.0");
3083
+ engine.checkVersion("4.5.0");
3012
3084
  await engine.pluginManager.register(e => {
3013
3085
  e.pluginManager.addParticleUpdater("paint", container => {
3014
3086
  return Promise.resolve(new PaintUpdater(e.pluginManager, container));
@@ -3050,7 +3122,7 @@
3050
3122
  if (!this.accepts(input)) {
3051
3123
  return;
3052
3124
  }
3053
- const result = rgbRegex.exec(input), radix = 10, minLength = 4, defaultAlpha = 1;
3125
+ const result = rgbRegex.exec(input), radix = 10, minLength = 4;
3054
3126
  return result
3055
3127
  ? {
3056
3128
  a: result.length > minLength ? parseAlpha(result[RgbIndexes.a]) : defaultAlpha,
@@ -3063,7 +3135,7 @@
3063
3135
  }
3064
3136
 
3065
3137
  async function loadRgbColorPlugin(engine) {
3066
- engine.checkVersion("4.4.0");
3138
+ engine.checkVersion("4.5.0");
3067
3139
  await engine.pluginManager.register(e => {
3068
3140
  e.pluginManager.addColorManager("rgb", new RgbColorManager());
3069
3141
  });
@@ -3148,7 +3220,7 @@
3148
3220
  }
3149
3221
 
3150
3222
  async function loadSizeUpdater(engine) {
3151
- engine.checkVersion("4.4.0");
3223
+ engine.checkVersion("4.5.0");
3152
3224
  await engine.pluginManager.register(e => {
3153
3225
  e.pluginManager.addParticleUpdater("size", container => {
3154
3226
  return Promise.resolve(new SizeUpdater(container));
@@ -3157,7 +3229,7 @@
3157
3229
  }
3158
3230
 
3159
3231
  async function loadBasic(engine) {
3160
- engine.checkVersion("4.4.0");
3232
+ engine.checkVersion("4.5.0");
3161
3233
  await engine.pluginManager.register(async (e) => {
3162
3234
  await Promise.all([
3163
3235
  loadBlendPlugin(e),
@@ -3296,6 +3368,8 @@
3296
3368
  autoPlay = true;
3297
3369
  direction;
3298
3370
  domId;
3371
+ draggable = false;
3372
+ draw = true;
3299
3373
  fill = true;
3300
3374
  life = new EmitterLife();
3301
3375
  name;
@@ -3319,6 +3393,8 @@
3319
3393
  }
3320
3394
  loadProperty(this, "direction", data.direction);
3321
3395
  loadProperty(this, "domId", data.domId);
3396
+ loadProperty(this, "draggable", data.draggable);
3397
+ loadProperty(this, "draw", data.draw);
3322
3398
  loadProperty(this, "fill", data.fill);
3323
3399
  this.life.load(data.life);
3324
3400
  loadProperty(this, "name", data.name);
@@ -3380,6 +3456,14 @@
3380
3456
  }
3381
3457
  }
3382
3458
 
3459
+ const ErrorCodes = {
3460
+ emittersPluginNotLoaded: "TSP-3101",
3461
+ };
3462
+
3463
+ const ErrorMessages = {
3464
+ [ErrorCodes.emittersPluginNotLoaded]: "tsParticles Emitters Plugin is not loaded",
3465
+ };
3466
+
3383
3467
  async function addEmittersShapesManager(e) {
3384
3468
  const { ShapeManager } = await Promise.resolve().then(function () { return ShapeManager$1; }), pluginManager = e.pluginManager;
3385
3469
  pluginManager.emitterShapeManager ??= new ShapeManager();
@@ -3410,7 +3494,10 @@
3410
3494
  })(EmitterClickMode || (EmitterClickMode = {}));
3411
3495
 
3412
3496
  async function loadEmittersPluginSimple(engine) {
3413
- engine.checkVersion("4.4.0");
3497
+ engine.checkVersion("4.5.0");
3498
+ if (typeof process !== "undefined" && process.env.NODE_ENV !== "production") {
3499
+ addErrorMessages(ErrorMessages);
3500
+ }
3414
3501
  await engine.pluginManager.register(async (e) => {
3415
3502
  const instancesManager = await getEmittersInstancesManager(e);
3416
3503
  await addEmittersShapesManager(e);
@@ -3464,7 +3551,7 @@
3464
3551
  }
3465
3552
 
3466
3553
  async function loadMotionPlugin(engine) {
3467
- engine.checkVersion("4.4.0");
3554
+ engine.checkVersion("4.5.0");
3468
3555
  await engine.pluginManager.register(e => {
3469
3556
  e.pluginManager.addPlugin(new MotionPlugin());
3470
3557
  });
@@ -3597,7 +3684,7 @@
3597
3684
  }
3598
3685
 
3599
3686
  async function loadRollUpdater(engine) {
3600
- engine.checkVersion("4.4.0");
3687
+ engine.checkVersion("4.5.0");
3601
3688
  await engine.pluginManager.register(e => {
3602
3689
  e.pluginManager.addParticleUpdater("roll", () => {
3603
3690
  return Promise.resolve(new RollUpdater(e.pluginManager));
@@ -3656,7 +3743,7 @@
3656
3743
  particle.pathRotation = rotateOptions.path;
3657
3744
  let rotateDirection = rotateOptions.direction;
3658
3745
  if (rotateDirection === RotateDirection.random) {
3659
- const index = Math.floor(getRandom() * double), minIndex = 0;
3746
+ const index = Math.floor(getRandom() * double);
3660
3747
  rotateDirection = index > minIndex ? RotateDirection.counterClockwise : RotateDirection.clockwise;
3661
3748
  }
3662
3749
  switch (rotateDirection) {
@@ -3703,7 +3790,7 @@
3703
3790
  }
3704
3791
 
3705
3792
  async function loadRotateUpdater(engine) {
3706
- engine.checkVersion("4.4.0");
3793
+ engine.checkVersion("4.5.0");
3707
3794
  await engine.pluginManager.register(e => {
3708
3795
  e.pluginManager.addParticleUpdater("rotate", container => {
3709
3796
  return Promise.resolve(new RotateUpdater(container));
@@ -3727,7 +3814,7 @@
3727
3814
  }
3728
3815
 
3729
3816
  async function loadSquareShape(engine) {
3730
- engine.checkVersion("4.4.0");
3817
+ engine.checkVersion("4.5.0");
3731
3818
  await engine.pluginManager.register(e => {
3732
3819
  e.pluginManager.addShape(["edge", "square"], () => Promise.resolve(new SquareDrawer()));
3733
3820
  });
@@ -3799,7 +3886,7 @@
3799
3886
  };
3800
3887
  let tiltDirection = tiltOptions.direction;
3801
3888
  if (tiltDirection === TiltDirection.random) {
3802
- const index = Math.floor(getRandom() * double), minIndex = 0;
3889
+ const index = Math.floor(getRandom() * double);
3803
3890
  tiltDirection = index > minIndex ? TiltDirection.counterClockwise : TiltDirection.clockwise;
3804
3891
  }
3805
3892
  switch (tiltDirection) {
@@ -3836,7 +3923,7 @@
3836
3923
  }
3837
3924
 
3838
3925
  async function loadTiltUpdater(engine) {
3839
- engine.checkVersion("4.4.0");
3926
+ engine.checkVersion("4.5.0");
3840
3927
  await engine.pluginManager.register(e => {
3841
3928
  e.pluginManager.addParticleUpdater("tilt", container => {
3842
3929
  return Promise.resolve(new TiltUpdater(container));
@@ -3938,7 +4025,7 @@
3938
4025
  }
3939
4026
 
3940
4027
  async function loadWobbleUpdater(engine) {
3941
- engine.checkVersion("4.4.0");
4028
+ engine.checkVersion("4.5.0");
3942
4029
  await engine.pluginManager.register(e => {
3943
4030
  e.pluginManager.addParticleUpdater("wobble", container => {
3944
4031
  return Promise.resolve(new WobbleUpdater(container));
@@ -4163,21 +4250,28 @@
4163
4250
  });
4164
4251
  }
4165
4252
  clear() {
4253
+ const visited = new Set();
4166
4254
  for (const plugin of this.#canvasClearPlugins) {
4255
+ visited.add(plugin);
4167
4256
  if (plugin.canvasClear?.() ?? false) {
4168
- return;
4257
+ return plugin;
4169
4258
  }
4170
4259
  }
4171
4260
  for (const layer of Object.values(DrawLayer)) {
4172
4261
  if (typeof layer === "number") {
4173
4262
  for (const plugin of this.#getLayerPlugins(layer)) {
4263
+ if (visited.has(plugin)) {
4264
+ continue;
4265
+ }
4266
+ visited.add(plugin);
4174
4267
  if (plugin.canvasClear?.() ?? false) {
4175
- return;
4268
+ return plugin;
4176
4269
  }
4177
4270
  }
4178
4271
  }
4179
4272
  }
4180
4273
  this.canvasClear();
4274
+ return undefined;
4181
4275
  }
4182
4276
  destroy() {
4183
4277
  this.stop();
@@ -4255,8 +4349,7 @@
4255
4349
  });
4256
4350
  }
4257
4351
  drawParticles(delta) {
4258
- const { particles, actualOptions } = this.#container;
4259
- this.clear();
4352
+ const { particles, actualOptions } = this.#container, clearedPlugin = this.clear();
4260
4353
  particles.update(delta);
4261
4354
  this.draw(ctx => {
4262
4355
  const width = this.#canvasManager.size.width, height = this.#canvasManager.size.height;
@@ -4278,7 +4371,9 @@
4278
4371
  }
4279
4372
  }
4280
4373
  for (const plugin of this.#getLayerPlugins(DrawLayer.BackgroundMask)) {
4281
- plugin.canvasPaint?.();
4374
+ if (plugin !== clearedPlugin) {
4375
+ plugin.canvasPaint?.();
4376
+ }
4282
4377
  }
4283
4378
  for (const plugin of this.#getLayerPlugins(DrawLayer.CanvasSetup)) {
4284
4379
  plugin.drawSettingsSetup?.(ctx, delta);
@@ -4310,35 +4405,7 @@
4310
4405
  this.#layers[layer] = [];
4311
4406
  }
4312
4407
  }
4313
- for (const plugin of this.#container.plugins) {
4314
- if (plugin.particleFillColor ?? plugin.particleStrokeColor) {
4315
- this.#colorPlugins.push(plugin);
4316
- }
4317
- if (plugin.drawParticle) {
4318
- this.#drawParticlePlugins.push(plugin);
4319
- }
4320
- if (plugin.drawParticleSetup) {
4321
- this.#drawParticlesSetupPlugins.push(plugin);
4322
- }
4323
- if (plugin.drawParticleCleanup) {
4324
- this.#drawParticlesCleanupPlugins.push(plugin);
4325
- }
4326
- if (plugin.canvasClear) {
4327
- this.#canvasClearPlugins.push(plugin);
4328
- }
4329
- if (plugin.canvasPaint) {
4330
- this.#getLayerPlugins(DrawLayer.BackgroundMask).push(plugin);
4331
- }
4332
- if (plugin.drawSettingsSetup) {
4333
- this.#getLayerPlugins(DrawLayer.CanvasSetup).push(plugin);
4334
- }
4335
- if (plugin.draw) {
4336
- this.#getLayerPlugins(DrawLayer.PluginContent).push(plugin);
4337
- }
4338
- if (plugin.clearDraw ?? plugin.drawSettingsCleanup) {
4339
- this.#getLayerPlugins(DrawLayer.CanvasCleanup).push(plugin);
4340
- }
4341
- }
4408
+ this.#initPluginsArray();
4342
4409
  }
4343
4410
  initUpdaters() {
4344
4411
  this.#preDrawUpdaters = [];
@@ -4547,6 +4614,45 @@
4547
4614
  this.#reusablePluginColors[sColorIndex] = sColor;
4548
4615
  return this.#reusablePluginColors;
4549
4616
  }
4617
+ #initLayerPlugin(plugin) {
4618
+ const layerMap = [
4619
+ [DrawLayer.BackgroundMask, !!plugin.canvasPaint],
4620
+ [DrawLayer.CanvasSetup, !!plugin.drawSettingsSetup],
4621
+ [DrawLayer.PluginContent, !!plugin.draw],
4622
+ [DrawLayer.CanvasCleanup, !!(plugin.clearDraw ?? plugin.drawSettingsCleanup)],
4623
+ ];
4624
+ for (const [layer, active] of layerMap) {
4625
+ if (active) {
4626
+ this.#layers[layer].push(plugin);
4627
+ }
4628
+ }
4629
+ }
4630
+ #initPluginsArray() {
4631
+ for (const plugin of this.#container.plugins) {
4632
+ if (plugin.particleFillColor ?? plugin.particleStrokeColor) {
4633
+ this.#colorPlugins.push(plugin);
4634
+ }
4635
+ if (plugin.drawParticle) {
4636
+ this.#drawParticlePlugins.push(plugin);
4637
+ }
4638
+ if (plugin.drawParticleSetup) {
4639
+ this.#drawParticlesSetupPlugins.push(plugin);
4640
+ }
4641
+ if (plugin.drawParticleCleanup) {
4642
+ this.#drawParticlesCleanupPlugins.push(plugin);
4643
+ }
4644
+ if (plugin.canvasClear) {
4645
+ this.#canvasClearPlugins.push(plugin);
4646
+ }
4647
+ this.#initLayerPlugin(plugin);
4648
+ }
4649
+ }
4650
+ #isSupportedElement(element) {
4651
+ return ((typeof HTMLCanvasElement !== "undefined" && element instanceof HTMLCanvasElement) ||
4652
+ (typeof OffscreenCanvas !== "undefined" && element instanceof OffscreenCanvas) ||
4653
+ (typeof HTMLVideoElement !== "undefined" && element instanceof HTMLVideoElement) ||
4654
+ (typeof HTMLImageElement !== "undefined" && element instanceof HTMLImageElement));
4655
+ }
4550
4656
  #resolveBackgroundElement() {
4551
4657
  const background = this.#container.actualOptions.background;
4552
4658
  this.#backgroundElement = null;
@@ -4556,9 +4662,7 @@
4556
4662
  if (typeof background.element === "string") {
4557
4663
  if (typeof document !== "undefined") {
4558
4664
  const node = document.querySelector(background.element);
4559
- if ((typeof HTMLCanvasElement !== "undefined" && node instanceof HTMLCanvasElement) ||
4560
- (typeof HTMLVideoElement !== "undefined" && node instanceof HTMLVideoElement) ||
4561
- (typeof HTMLImageElement !== "undefined" && node instanceof HTMLImageElement)) {
4665
+ if (node && this.#isSupportedElement(node)) {
4562
4666
  this.#backgroundElement = node;
4563
4667
  }
4564
4668
  else if (node) {
@@ -4569,10 +4673,7 @@
4569
4673
  }
4570
4674
  }
4571
4675
  }
4572
- else if ((typeof HTMLCanvasElement !== "undefined" && background.element instanceof HTMLCanvasElement) ||
4573
- (typeof OffscreenCanvas !== "undefined" && background.element instanceof OffscreenCanvas) ||
4574
- (typeof HTMLVideoElement !== "undefined" && background.element instanceof HTMLVideoElement) ||
4575
- (typeof HTMLImageElement !== "undefined" && background.element instanceof HTMLImageElement)) {
4676
+ else if (this.#isSupportedElement(background.element)) {
4576
4677
  this.#backgroundElement = background.element;
4577
4678
  }
4578
4679
  }
@@ -4590,7 +4691,7 @@
4590
4691
  return transferredCanvas;
4591
4692
  }
4592
4693
  if (typeof canvas.transferControlToOffscreen !== "function") {
4593
- throw new TypeError("OffscreenCanvas is required but not supported by this browser");
4694
+ throw new TypeError(getErrorMessage(ErrorCodes$2.offscreenCanvasUnsupported));
4594
4695
  }
4595
4696
  try {
4596
4697
  const offscreenCanvas = canvas.transferControlToOffscreen();
@@ -4598,10 +4699,16 @@
4598
4699
  return offscreenCanvas;
4599
4700
  }
4600
4701
  catch {
4601
- throw new TypeError("OffscreenCanvas transfer failed");
4702
+ throw new TypeError(getErrorMessage(ErrorCodes$2.offscreenCanvasTransferFailed));
4602
4703
  }
4603
4704
  }, isHtmlCanvasElement = (canvas) => {
4604
4705
  return typeof HTMLCanvasElement !== "undefined" && canvas instanceof HTMLCanvasElement;
4706
+ }, getEffectiveColorSpace = (context) => {
4707
+ if (!context) {
4708
+ return undefined;
4709
+ }
4710
+ const colorInfo = context;
4711
+ return colorInfo.getContextAttributes?.().colorSpace ?? undefined;
4605
4712
  };
4606
4713
  function setStyle(canvas, style, important = false) {
4607
4714
  if (!style) {
@@ -4726,7 +4833,7 @@
4726
4833
  const elementStyle = element.style, color = rangeColorToRgb(this.#pluginManager, background.color);
4727
4834
  if (color) {
4728
4835
  const hdrOptions = container.actualOptions.hdr;
4729
- elementStyle.backgroundColor = getStyleFromRgb(color, container.hdr, background.opacity, hdrOptions.peakNits, hdrOptions.mode);
4836
+ elementStyle.backgroundColor = getStyleFromRgb(color, container.hdr, background.opacity, hdrOptions.peakNits, toEnumValue(HdrMode, hdrOptions.mode, HdrMode.standard));
4730
4837
  }
4731
4838
  else {
4732
4839
  elementStyle.backgroundColor = "";
@@ -4846,11 +4953,11 @@
4846
4953
  const container = this.#container, canSupportHdr = container.actualOptions.hdr.enable &&
4847
4954
  safeMatchMedia("(color-gamut: p3)")?.matches &&
4848
4955
  safeMatchMedia("(dynamic-range: high)")?.matches;
4849
- container.hdr = canSupportHdr ?? false;
4850
- container.hdrMode = container.actualOptions.hdr.mode;
4956
+ container.hdrMode = toEnumValue(HdrMode, container.actualOptions.hdr.mode, HdrMode.standard);
4851
4957
  container.peakNits = container.actualOptions.hdr.peakNits;
4852
4958
  const renderCanvas = this.renderCanvas;
4853
4959
  if (!renderCanvas) {
4960
+ container.hdr = canSupportHdr ?? false;
4854
4961
  return;
4855
4962
  }
4856
4963
  this.render.setContextSettings({
@@ -4869,7 +4976,6 @@
4869
4976
  context = null;
4870
4977
  }
4871
4978
  if (canSupportHdr && !context) {
4872
- container.hdr = false;
4873
4979
  const sdrSettings = {
4874
4980
  alpha: true,
4875
4981
  desynchronized: true,
@@ -4885,11 +4991,16 @@
4885
4991
  }
4886
4992
  }
4887
4993
  this.render.setContext(context);
4994
+ if (context) {
4995
+ const effectiveColorSpace = getEffectiveColorSpace(context);
4996
+ if (effectiveColorSpace !== undefined) {
4997
+ container.hdr = effectiveColorSpace === "display-p3";
4998
+ }
4999
+ }
4888
5000
  }
4889
5001
  #initHdrListeners() {
4890
5002
  this.#removeHdrListeners();
4891
5003
  const p3Query = safeMatchMedia("(color-gamut: p3)"), hdrQuery = safeMatchMedia("(dynamic-range: high)"), handleChange = () => {
4892
- this.#recreateRenderCanvas();
4893
5004
  this.#initContext();
4894
5005
  this.initBackground();
4895
5006
  }, listeners = [];
@@ -4925,16 +5036,6 @@
4925
5036
  element.style.setProperty(key, value, "important");
4926
5037
  }
4927
5038
  }
4928
- #recreateRenderCanvas() {
4929
- const renderCanvas = this.renderCanvas;
4930
- if (!renderCanvas) {
4931
- return;
4932
- }
4933
- if (this.domElement) {
4934
- return;
4935
- }
4936
- this.renderCanvas = new OffscreenCanvas(renderCanvas.width, renderCanvas.height);
4937
- }
4938
5039
  #removeHdrListeners() {
4939
5040
  if (!this.#hdrMediaListeners) {
4940
5041
  return;
@@ -5033,8 +5134,7 @@
5033
5134
  this.#resizeTimeout = undefined;
5034
5135
  }
5035
5136
  const handleResize = async () => {
5036
- const canvas = this.#container.canvas;
5037
- await canvas.windowResize();
5137
+ await this.#container.canvas.windowResize();
5038
5138
  };
5039
5139
  this.#resizeTimeout = setTimeout(() => void handleResize(), this.#container.actualOptions.resize.delay * millisecondsToSeconds);
5040
5140
  }
@@ -5062,8 +5162,8 @@
5062
5162
  }
5063
5163
  else if (!this.#resizeObserver && add && canvasEl) {
5064
5164
  this.#resizeObserver = new ResizeObserver((entries) => {
5065
- const entry = entries.find(e => e.target === canvasEl);
5066
- if (!entry) {
5165
+ const res = entries.some(e => e.target === canvasEl);
5166
+ if (!res) {
5067
5167
  return;
5068
5168
  }
5069
5169
  this.#handleWindowResize();
@@ -5327,10 +5427,10 @@
5327
5427
  return this.#modifiers.find(m => m.id === id);
5328
5428
  }
5329
5429
  getOpacity() {
5330
- 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;
5331
- this.#cachedOpacityData.fillOpacity = fillOpacity;
5430
+ 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;
5431
+ this.#cachedOpacityData.fillOpacity = this.fillOpacity ?? defaultOpacity$1;
5332
5432
  this.#cachedOpacityData.opacity = opacity * zOpacityFactor;
5333
- this.#cachedOpacityData.strokeOpacity = strokeOpacity;
5433
+ this.#cachedOpacityData.strokeOpacity = this.strokeOpacity ?? defaultOpacity$1;
5334
5434
  return this.#cachedOpacityData;
5335
5435
  }
5336
5436
  getPosition() {
@@ -5577,7 +5677,7 @@
5577
5677
  #initPosition(position) {
5578
5678
  const container = this.#container, zIndexValue = Math.floor(getRangeValue(this.options.zIndex.value)), initialPosition = this.#calcPosition(position, clamp(zIndexValue, minZ, container.zLayers));
5579
5679
  if (!initialPosition) {
5580
- throw new Error("a valid position cannot be found for particle");
5680
+ throw new Error(getErrorMessage(ErrorCodes$2.particlePositionNotFound));
5581
5681
  }
5582
5682
  this.position = initialPosition;
5583
5683
  this.initialPosition = this.position.copy();
@@ -5626,6 +5726,12 @@
5626
5726
  this.#circlePoolIdx = 0;
5627
5727
  this.#rectanglePoolIdx = 0;
5628
5728
  }
5729
+ get cellSize() {
5730
+ return this.#cellSize;
5731
+ }
5732
+ set cellSize(value) {
5733
+ this.#pendingCellSize = value;
5734
+ }
5629
5735
  clear() {
5630
5736
  this.#cells.clear();
5631
5737
  const pendingCellSize = this.#pendingCellSize;
@@ -5649,18 +5755,7 @@
5649
5755
  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);
5650
5756
  for (let cx = minCellX; cx <= maxCellX; cx++) {
5651
5757
  for (let cy = minCellY; cy <= maxCellY; cy++) {
5652
- const key = `${cx}_${cy}`, cellParticles = this.#cells.get(key);
5653
- if (!cellParticles) {
5654
- continue;
5655
- }
5656
- for (const p of cellParticles) {
5657
- if (check && !check(p)) {
5658
- continue;
5659
- }
5660
- if (range.contains(p.getPosition())) {
5661
- out.push(p);
5662
- }
5663
- }
5758
+ this.#queryCell(cx, cy, range, check, out);
5664
5759
  }
5665
5760
  }
5666
5761
  return out;
@@ -5675,14 +5770,23 @@
5675
5770
  this.#releaseShapes();
5676
5771
  return result;
5677
5772
  }
5678
- setCellSize(cellSize) {
5679
- this.#pendingCellSize = cellSize;
5680
- }
5681
5773
  #acquireCircle(x, y, r) {
5682
- return (this.#circlePool[this.#circlePoolIdx++] ??= new Circle(x, y, r)).reset(x, y, r);
5774
+ const idx = this.#circlePoolIdx++;
5775
+ let circle = this.#circlePool[idx];
5776
+ if (!circle) {
5777
+ circle = new Circle(x, y, r);
5778
+ this.#circlePool[idx] = circle;
5779
+ }
5780
+ return circle.reset(x, y, r);
5683
5781
  }
5684
5782
  #acquireRectangle(x, y, w, h) {
5685
- return (this.#rectanglePool[this.#rectanglePoolIdx++] ??= new Rectangle(x, y, w, h)).reset(x, y, w, h);
5783
+ const idx = this.#rectanglePoolIdx++;
5784
+ let rectangle = this.#rectanglePool[idx];
5785
+ if (!rectangle) {
5786
+ rectangle = new Rectangle(x, y, w, h);
5787
+ this.#rectanglePool[idx] = rectangle;
5788
+ }
5789
+ return rectangle.reset(x, y, w, h);
5686
5790
  }
5687
5791
  #cellKeyFromCoords(x, y) {
5688
5792
  const cellX = Math.floor(x / this.#cellSize), cellY = Math.floor(y / this.#cellSize);
@@ -5709,6 +5813,20 @@
5709
5813
  }
5710
5814
  return null;
5711
5815
  }
5816
+ #queryCell(cx, cy, range, check, out) {
5817
+ const cellParticles = this.#cells.get(`${cx}_${cy}`);
5818
+ if (!cellParticles) {
5819
+ return;
5820
+ }
5821
+ for (const p of cellParticles) {
5822
+ if (check && !check(p)) {
5823
+ continue;
5824
+ }
5825
+ if (range.contains(p.getPosition())) {
5826
+ out.push(p);
5827
+ }
5828
+ }
5829
+ }
5712
5830
  #releaseShapes() {
5713
5831
  this.#circlePoolIdx = 0;
5714
5832
  this.#rectanglePoolIdx = 0;
@@ -5717,9 +5835,9 @@
5717
5835
 
5718
5836
  class ParticlesManager {
5719
5837
  checkParticlePositionPlugins;
5720
- grid;
5721
5838
  #array;
5722
5839
  #container;
5840
+ #grid;
5723
5841
  #groupLimits;
5724
5842
  #limit;
5725
5843
  #nextId;
@@ -5743,7 +5861,7 @@
5743
5861
  this.#groupLimits = new Map();
5744
5862
  this.#particleBuckets = new Map();
5745
5863
  this.#zBuckets = this.#createBuckets(this.#container.zLayers);
5746
- this.grid = new SpatialHashGrid(spatialHashGridCellSize);
5864
+ this.#grid = new SpatialHashGrid(spatialHashGridCellSize);
5747
5865
  this.checkParticlePositionPlugins = [];
5748
5866
  this.#particleResetPlugins = [];
5749
5867
  this.#particleUpdatePlugins = [];
@@ -5754,23 +5872,12 @@
5754
5872
  get count() {
5755
5873
  return this.#array.length;
5756
5874
  }
5875
+ get grid() {
5876
+ return this.#grid;
5877
+ }
5757
5878
  addParticle(position, overrideOptions, group, initializer) {
5758
- const limitMode = this.#container.actualOptions.particles.number.limit.mode, limit = group === undefined ? this.#limit : (this.#groupLimits.get(group) ?? this.#limit), currentCount = this.count;
5759
- if (limit > minLimit) {
5760
- switch (limitMode) {
5761
- case LimitMode.delete: {
5762
- const countToRemove = currentCount + countOffset - limit;
5763
- if (countToRemove > minCount) {
5764
- this.removeQuantity(countToRemove);
5765
- }
5766
- break;
5767
- }
5768
- case LimitMode.wait:
5769
- if (currentCount >= limit) {
5770
- return;
5771
- }
5772
- break;
5773
- }
5879
+ if (this.#checkAndApplyLimits(group, this.count)) {
5880
+ return;
5774
5881
  }
5775
5882
  try {
5776
5883
  const particle = this.#pool.pop() ?? new Particle(this.#pluginManager, this.#container);
@@ -5834,7 +5941,7 @@
5834
5941
  return this.#array[index];
5835
5942
  }
5836
5943
  async init() {
5837
- const container = this.#container, options = container.actualOptions;
5944
+ const container = this.#container;
5838
5945
  this.checkParticlePositionPlugins = [];
5839
5946
  this.#updatePlugins = [];
5840
5947
  this.#particleUpdatePlugins = [];
@@ -5843,59 +5950,16 @@
5843
5950
  this.#postParticleUpdatePlugins = [];
5844
5951
  this.#particleBuckets.clear();
5845
5952
  this.#resetBuckets(container.zLayers);
5846
- this.grid = new SpatialHashGrid(spatialHashGridCellSize * container.retina.pixelRatio);
5847
- for (const plugin of container.plugins) {
5848
- if (plugin.redrawInit) {
5849
- await plugin.redrawInit();
5850
- }
5851
- if (plugin.checkParticlePosition) {
5852
- this.checkParticlePositionPlugins.push(plugin);
5853
- }
5854
- if (plugin.update) {
5855
- this.#updatePlugins.push(plugin);
5856
- }
5857
- if (plugin.particleUpdate) {
5858
- this.#particleUpdatePlugins.push(plugin);
5859
- }
5860
- if (plugin.postUpdate) {
5861
- this.#postUpdatePlugins.push(plugin);
5862
- }
5863
- if (plugin.particleReset) {
5864
- this.#particleResetPlugins.push(plugin);
5865
- }
5866
- if (plugin.postParticleUpdate) {
5867
- this.#postParticleUpdatePlugins.push(plugin);
5868
- }
5869
- }
5870
- await this.#container.initDrawersAndUpdaters();
5871
- for (const drawer of this.#container.effectDrawers.values()) {
5872
- await drawer.init?.(container);
5873
- }
5874
- for (const drawer of this.#container.shapeDrawers.values()) {
5875
- await drawer.init?.(container);
5876
- }
5877
- let handled = false;
5878
- for (const plugin of container.plugins) {
5879
- handled = plugin.particlesInitialization?.() ?? handled;
5880
- if (handled) {
5881
- break;
5882
- }
5883
- }
5884
- if (!handled) {
5885
- const particlesOptions = options.particles, groups = particlesOptions.groups;
5886
- for (const group in groups) {
5887
- const groupOptions = groups[group];
5888
- if (!groupOptions) {
5889
- continue;
5890
- }
5891
- for (let i = this.count, j = 0; j < groupOptions.number.value && i < particlesOptions.number.value; i++, j++) {
5892
- this.addParticle(undefined, groupOptions, group);
5893
- }
5894
- }
5895
- for (let i = this.count; i < particlesOptions.number.value; i++) {
5896
- this.addParticle();
5953
+ this.#grid = new SpatialHashGrid(spatialHashGridCellSize * container.retina.pixelRatio);
5954
+ this.#applyLimits(container.actualOptions.particles);
5955
+ const particlesOptions = container.actualOptions.particles, groups = particlesOptions.groups;
5956
+ for (const group in groups) {
5957
+ const groupData = groups[group];
5958
+ if (groupData) {
5959
+ this.#applyLimits(loadParticlesOptions(this.#pluginManager, this.#container, groupData), group, groupData);
5897
5960
  }
5898
5961
  }
5962
+ await this.#initPlugins();
5899
5963
  }
5900
5964
  push(nb, position, overrideOptions, group) {
5901
5965
  for (let i = 0; i < nb; i++) {
@@ -5910,13 +5974,13 @@
5910
5974
  remove(particle, group, override) {
5911
5975
  this.removeAt(this.#array.indexOf(particle), undefined, group, override);
5912
5976
  }
5913
- removeAt(index, quantity = defaultRemoveQuantity, group, override) {
5977
+ removeAt(index, quantity = defaultRemoveQuantity, group, override, matchGroup = true) {
5914
5978
  if (index < minIndex || index > this.count) {
5915
5979
  return;
5916
5980
  }
5917
5981
  let deleted = 0;
5918
5982
  for (let i = index; deleted < quantity && i < this.count; i++) {
5919
- if (this.#removeParticle(i, group, override)) {
5983
+ if (this.#removeParticle(i, group, override, matchGroup)) {
5920
5984
  i--;
5921
5985
  deleted++;
5922
5986
  }
@@ -5947,7 +6011,7 @@
5947
6011
  this.#resizeFactor = factor;
5948
6012
  }
5949
6013
  update(delta) {
5950
- this.grid.clear();
6014
+ this.#grid.clear();
5951
6015
  for (const plugin of this.#updatePlugins) {
5952
6016
  plugin.update?.(delta);
5953
6017
  }
@@ -5958,7 +6022,7 @@
5958
6022
  this.#updateParticlesPhase2(delta, particlesToDelete);
5959
6023
  if (particlesToDelete.size) {
5960
6024
  for (const particle of particlesToDelete) {
5961
- this.remove(particle);
6025
+ this.remove(particle, particle.group);
5962
6026
  }
5963
6027
  }
5964
6028
  this.#resizeFactor = undefined;
@@ -5969,12 +6033,7 @@
5969
6033
  #applyDensity(options, pluginsCount, group, groupOptions) {
5970
6034
  const numberOptions = options.number;
5971
6035
  if (!numberOptions.density.enable) {
5972
- if (group === undefined) {
5973
- this.#limit = numberOptions.limit.value;
5974
- }
5975
- else if (groupOptions?.number.limit.value ?? numberOptions.limit.value) {
5976
- this.#groupLimits.set(group, groupOptions?.number.limit.value ?? numberOptions.limit.value);
5977
- }
6036
+ this.#applyLimits(options, group, groupOptions);
5978
6037
  return;
5979
6038
  }
5980
6039
  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);
@@ -5982,7 +6041,10 @@
5982
6041
  this.#limit = numberOptions.limit.value * densityFactor;
5983
6042
  }
5984
6043
  else {
5985
- this.#groupLimits.set(group, numberOptions.limit.value * densityFactor);
6044
+ this.#groupLimits.set(group, {
6045
+ limit: numberOptions.limit.value * densityFactor,
6046
+ mode: toEnumValue(LimitMode, numberOptions.limit.mode, LimitMode.delete),
6047
+ });
5986
6048
  }
5987
6049
  if (particlesCount < particlesNumber) {
5988
6050
  this.push(Math.abs(particlesNumber - particlesCount), undefined, options, group);
@@ -5991,6 +6053,55 @@
5991
6053
  this.removeQuantity(particlesCount - particlesNumber, group);
5992
6054
  }
5993
6055
  }
6056
+ #applyLimits(options, group, groupOptions) {
6057
+ if (group === undefined) {
6058
+ this.#limit = options.number.limit.value;
6059
+ const groups = this.#container.actualOptions.particles.groups;
6060
+ for (const existingGroup of this.#groupLimits.keys()) {
6061
+ if (!(existingGroup in groups)) {
6062
+ this.#groupLimits.delete(existingGroup);
6063
+ }
6064
+ }
6065
+ }
6066
+ else {
6067
+ const limitValue = groupOptions?.number?.limit?.value ?? options.number.limit.value;
6068
+ if (limitValue > minLimit) {
6069
+ this.#groupLimits.set(group, {
6070
+ limit: limitValue,
6071
+ mode: toEnumValue(LimitMode, groupOptions?.number?.limit?.mode ?? options.number.limit.mode, LimitMode.delete),
6072
+ });
6073
+ }
6074
+ else {
6075
+ this.#groupLimits.delete(group);
6076
+ }
6077
+ }
6078
+ }
6079
+ #checkAndApplyLimits(group, currentCount) {
6080
+ const globalLimit = this.#limit, globalMode = this.#container.actualOptions.particles.number.limit.mode;
6081
+ if (globalLimit > minLimit && globalMode === LimitMode.wait && currentCount >= globalLimit) {
6082
+ return true;
6083
+ }
6084
+ const groupLimitEntry = group === undefined ? undefined : this.#groupLimits.get(group);
6085
+ if (groupLimitEntry && groupLimitEntry.limit > minLimit && groupLimitEntry.mode === LimitMode.wait) {
6086
+ const groupCount = this.filter(t => t.group === group).length;
6087
+ if (groupCount >= groupLimitEntry.limit) {
6088
+ return true;
6089
+ }
6090
+ }
6091
+ if (groupLimitEntry && groupLimitEntry.limit > minLimit && groupLimitEntry.mode === LimitMode.delete) {
6092
+ const groupCountToRemove = this.filter(t => t.group === group).length + countOffset - groupLimitEntry.limit;
6093
+ if (groupCountToRemove > minCount) {
6094
+ this.removeQuantity(groupCountToRemove, group);
6095
+ }
6096
+ }
6097
+ if (globalLimit > minLimit && globalMode === LimitMode.delete) {
6098
+ const globalCountToRemove = this.count + countOffset - globalLimit;
6099
+ if (globalCountToRemove > minCount) {
6100
+ this.#removeAny(globalCountToRemove);
6101
+ }
6102
+ }
6103
+ return false;
6104
+ }
5994
6105
  #createBuckets(zLayers) {
5995
6106
  const bucketCount = Math.max(Math.floor(zLayers), one);
5996
6107
  return Array.from({ length: bucketCount }, () => []);
@@ -6013,6 +6124,70 @@
6013
6124
  }
6014
6125
  return ((canvasSize.width * canvasSize.height) / (densityOptions.height * densityOptions.width * pxRatio ** squareExp));
6015
6126
  }
6127
+ async #initDrawersAndUpdaters() {
6128
+ const container = this.#container;
6129
+ await container.initDrawersAndUpdaters();
6130
+ for (const drawer of container.effectDrawers.values()) {
6131
+ await drawer.init?.(container);
6132
+ }
6133
+ for (const drawer of container.shapeDrawers.values()) {
6134
+ await drawer.init?.(container);
6135
+ }
6136
+ }
6137
+ async #initPlugins() {
6138
+ await this.#initPluginsArrays();
6139
+ await this.#initDrawersAndUpdaters();
6140
+ let handled = false;
6141
+ const container = this.#container;
6142
+ for (const plugin of container.plugins) {
6143
+ handled = plugin.particlesInitialization?.() ?? handled;
6144
+ if (handled) {
6145
+ break;
6146
+ }
6147
+ }
6148
+ if (handled) {
6149
+ return;
6150
+ }
6151
+ const particlesOptions = container.actualOptions.particles, groups = particlesOptions.groups;
6152
+ for (const group in groups) {
6153
+ const groupOptions = groups[group];
6154
+ if (!groupOptions) {
6155
+ continue;
6156
+ }
6157
+ for (let i = this.count, j = 0; j < groupOptions.number.value && i < particlesOptions.number.value; i++, j++) {
6158
+ this.addParticle(undefined, groupOptions, group);
6159
+ }
6160
+ }
6161
+ for (let i = this.count; i < particlesOptions.number.value; i++) {
6162
+ this.addParticle();
6163
+ }
6164
+ }
6165
+ async #initPluginsArrays() {
6166
+ const container = this.#container;
6167
+ for (const plugin of container.plugins) {
6168
+ if (plugin.redrawInit) {
6169
+ await plugin.redrawInit();
6170
+ }
6171
+ if (plugin.checkParticlePosition) {
6172
+ this.checkParticlePositionPlugins.push(plugin);
6173
+ }
6174
+ if (plugin.update) {
6175
+ this.#updatePlugins.push(plugin);
6176
+ }
6177
+ if (plugin.particleUpdate) {
6178
+ this.#particleUpdatePlugins.push(plugin);
6179
+ }
6180
+ if (plugin.postUpdate) {
6181
+ this.#postUpdatePlugins.push(plugin);
6182
+ }
6183
+ if (plugin.particleReset) {
6184
+ this.#particleResetPlugins.push(plugin);
6185
+ }
6186
+ if (plugin.postParticleUpdate) {
6187
+ this.#postParticleUpdatePlugins.push(plugin);
6188
+ }
6189
+ }
6190
+ }
6016
6191
  #insertParticleIntoBucket(particle) {
6017
6192
  const bucketIndex = this.#getBucketIndex(particle.position.z), bucket = this.#zBuckets[bucketIndex];
6018
6193
  if (!bucket) {
@@ -6021,12 +6196,15 @@
6021
6196
  bucket.push(particle);
6022
6197
  this.#particleBuckets.set(particle.id, bucketIndex);
6023
6198
  }
6024
- #removeParticle(index, group, override) {
6199
+ #removeAny(quantity) {
6200
+ this.removeAt(minIndex, quantity, undefined, undefined, false);
6201
+ }
6202
+ #removeParticle(index, group, override, matchGroup = true) {
6025
6203
  const particle = this.#array[index];
6026
6204
  if (!particle) {
6027
6205
  return false;
6028
6206
  }
6029
- if (particle.group !== group) {
6207
+ if (matchGroup && particle.group !== group) {
6030
6208
  return false;
6031
6209
  }
6032
6210
  this.#array.splice(index, deleteCount);
@@ -6113,7 +6291,7 @@
6113
6291
  particlesToDelete.add(particle);
6114
6292
  continue;
6115
6293
  }
6116
- this.grid.insert(particle);
6294
+ this.#grid.insert(particle);
6117
6295
  }
6118
6296
  return particlesToDelete;
6119
6297
  }
@@ -6289,7 +6467,6 @@
6289
6467
  this.shapeDrawers = new Map();
6290
6468
  this.particleUpdaters = [];
6291
6469
  this.plugins.length = 0;
6292
- this.#pluginManager.clearPlugins(this);
6293
6470
  this.destroyed = true;
6294
6471
  this.#onDestroy(remove);
6295
6472
  this.dispatchEvent(EventType.containerDestroyed);
@@ -6342,31 +6519,14 @@
6342
6519
  await this.initDrawersAndUpdaters();
6343
6520
  this.#options = loadContainerOptions(this.#pluginManager, this, this.#initialSourceOptions, this.sourceOptions);
6344
6521
  this.actualOptions = loadContainerOptions(this.#pluginManager, this, this.#options);
6345
- this.plugins.length = 0;
6346
- this.particleDestroyedPlugins.length = 0;
6347
- this.particleCreatedPlugins.length = 0;
6348
- this.particlePositionPlugins.length = 0;
6349
- for (const [plugin, containerPlugin] of allContainerPlugins) {
6350
- if (plugin.needsPlugin(this.actualOptions)) {
6351
- this.plugins.push(containerPlugin);
6352
- if (containerPlugin.particleCreated) {
6353
- this.particleCreatedPlugins.push(containerPlugin);
6354
- }
6355
- if (containerPlugin.particleDestroyed) {
6356
- this.particleDestroyedPlugins.push(containerPlugin);
6357
- }
6358
- if (containerPlugin.particlePosition) {
6359
- this.particlePositionPlugins.push(containerPlugin);
6360
- }
6361
- }
6362
- }
6522
+ this.#initPlugins(allContainerPlugins);
6363
6523
  this.retina.init();
6364
6524
  this.canvas.init();
6365
6525
  this.updateActualOptions();
6366
6526
  this.canvas.initBackground();
6367
6527
  this.canvas.resize();
6368
6528
  const { delay, duration, fpsLimit, smooth, zLayers } = this.actualOptions, hdrOptions = this.actualOptions.hdr;
6369
- this.hdrMode = hdrOptions.mode;
6529
+ this.hdrMode = toEnumValue(HdrMode, hdrOptions.mode, HdrMode.standard);
6370
6530
  this.peakNits = hdrOptions.peakNits;
6371
6531
  this.zLayers = zLayers;
6372
6532
  this.#duration = getRangeValue(duration) * millisecondsToSeconds;
@@ -6387,9 +6547,9 @@
6387
6547
  }
6388
6548
  async initDrawersAndUpdaters() {
6389
6549
  const pluginManager = this.#pluginManager;
6390
- this.effectDrawers = await pluginManager.getEffectDrawers(this, true);
6391
- this.shapeDrawers = await pluginManager.getShapeDrawers(this, true);
6392
- this.particleUpdaters = await pluginManager.getUpdaters(this, true);
6550
+ this.effectDrawers = await getItemMapFromInitializer(this, pluginManager.initializers.effects);
6551
+ this.shapeDrawers = await getItemMapFromInitializer(this, pluginManager.initializers.shapes);
6552
+ this.particleUpdaters = await getItemsFromInitializer(this, pluginManager.initializers.updaters);
6393
6553
  }
6394
6554
  pause() {
6395
6555
  if (!guardCheck(this)) {
@@ -6500,6 +6660,27 @@
6500
6660
  }
6501
6661
  return refresh;
6502
6662
  }
6663
+ #initPlugins(allContainerPlugins) {
6664
+ this.plugins.length = 0;
6665
+ this.particleDestroyedPlugins.length = 0;
6666
+ this.particleCreatedPlugins.length = 0;
6667
+ this.particlePositionPlugins.length = 0;
6668
+ for (const [plugin, containerPlugin] of allContainerPlugins) {
6669
+ if (!plugin.needsPlugin(this.actualOptions)) {
6670
+ continue;
6671
+ }
6672
+ this.plugins.push(containerPlugin);
6673
+ if (containerPlugin.particleCreated) {
6674
+ this.particleCreatedPlugins.push(containerPlugin);
6675
+ }
6676
+ if (containerPlugin.particleDestroyed) {
6677
+ this.particleDestroyedPlugins.push(containerPlugin);
6678
+ }
6679
+ if (containerPlugin.particlePosition) {
6680
+ this.particlePositionPlugins.push(containerPlugin);
6681
+ }
6682
+ }
6683
+ }
6503
6684
  #nextFrame(timestamp) {
6504
6685
  try {
6505
6686
  if (!this.#smooth &&
@@ -6776,11 +6957,11 @@
6776
6957
  }
6777
6958
  }
6778
6959
  async #init() {
6779
- const availablePathGenerators = await this.#pluginManager.getPathGenerators?.(this.#container, true);
6780
- if (!availablePathGenerators) {
6960
+ const pluginManager = this.#pluginManager;
6961
+ if (!pluginManager.initializers.pathGenerators) {
6781
6962
  return;
6782
6963
  }
6783
- this.availablePathGenerators = availablePathGenerators;
6964
+ this.availablePathGenerators = await getItemMapFromInitializer(this.#container, pluginManager.initializers.pathGenerators);
6784
6965
  this.pathGenerators = new Map();
6785
6966
  for (const pathGenerator of this.pathGenerators.values()) {
6786
6967
  pathGenerator.init();
@@ -6801,6 +6982,11 @@
6801
6982
  this.#container = container;
6802
6983
  this.#instancesManager.initContainer(container);
6803
6984
  }
6985
+ draw(context, _delta) {
6986
+ for (const emitter of this.#instancesManager.getArray(this.#container)) {
6987
+ emitter.draw(context);
6988
+ }
6989
+ }
6804
6990
  async init() {
6805
6991
  const emittersOptions = this.#container.actualOptions.emitters;
6806
6992
  if (isArray(emittersOptions)) {
@@ -6871,14 +7057,21 @@
6871
7057
  this.#pluginManager = pluginManager;
6872
7058
  }
6873
7059
  async addEmitter(container, options, position) {
6874
- const emitterOptions = new Emitter();
6875
- emitterOptions.load(options);
6876
- const { EmitterInstance } = await Promise.resolve().then(function () { return EmitterInstance$1; }), emitter = new EmitterInstance(this.#pluginManager, container, (emitter) => {
6877
- this.removeEmitter(container, emitter);
6878
- }, emitterOptions, position);
6879
- await emitter.init();
6880
- this.getArray(container).push(emitter);
6881
- return emitter;
7060
+ return this.addEmitters(container, [{ options, position }]).then(t => t[defaultIndex]);
7061
+ }
7062
+ async addEmitters(container, emitters) {
7063
+ const { EmitterInstance } = await Promise.resolve().then(function () { return EmitterInstance$1; }), res = [];
7064
+ for (const { options, position } of emitters) {
7065
+ const emitterOptions = new Emitter();
7066
+ emitterOptions.load(options);
7067
+ const emitter = new EmitterInstance(this.#pluginManager, container, (emitter) => {
7068
+ this.removeEmitter(container, emitter);
7069
+ }, emitterOptions, position);
7070
+ await emitter.init();
7071
+ this.getArray(container).push(emitter);
7072
+ res.push(emitter);
7073
+ }
7074
+ return res;
6882
7075
  }
6883
7076
  clear(container) {
6884
7077
  this.initContainer(container);
@@ -6905,6 +7098,7 @@
6905
7098
  : array.find(t => t.name === idxOrName);
6906
7099
  };
6907
7100
  container.addEmitter = async (options, position) => this.addEmitter(container, options, position);
7101
+ container.addEmitters = async (emitters) => this.addEmitters(container, emitters);
6908
7102
  container.removeEmitter = (idxOrName) => {
6909
7103
  const emitter = container.getEmitter?.(idxOrName);
6910
7104
  if (emitter) {
@@ -6925,7 +7119,7 @@
6925
7119
  };
6926
7120
  }
6927
7121
  removeEmitter(container, emitter) {
6928
- const index = this.getArray(container).indexOf(emitter), minIndex = 0, deleteCount = 1;
7122
+ const index = this.getArray(container).indexOf(emitter), deleteCount = 1;
6929
7123
  if (index >= minIndex) {
6930
7124
  this.getArray(container).splice(index, deleteCount);
6931
7125
  }
@@ -7035,6 +7229,7 @@
7035
7229
  #particlesOptions;
7036
7230
  #paused;
7037
7231
  #pluginManager;
7232
+ #positionOverride = false;
7038
7233
  #removeCallback;
7039
7234
  #resizeObserver;
7040
7235
  #shape;
@@ -7111,6 +7306,31 @@
7111
7306
  });
7112
7307
  this.play();
7113
7308
  }
7309
+ draw(context) {
7310
+ if (!this.options.draw || !this.#shape) {
7311
+ return;
7312
+ }
7313
+ const container = this.#container, fillEnabled = this.options.spawn.fill?.enable ?? true;
7314
+ context.save();
7315
+ context.beginPath();
7316
+ if (fillEnabled) {
7317
+ context.fillStyle = this.spawnFillColor
7318
+ ? getStyleFromHsl(this.spawnFillColor, container.hdr, this.spawnFillOpacity ?? defaultOpacity$1, container.peakNits, container.hdrMode)
7319
+ : getStyleFromRgb({ r: 0, g: 0, b: 0 }, container.hdr, defaultOpacity$1, container.peakNits, container.hdrMode);
7320
+ }
7321
+ if (this.spawnStrokeColor) {
7322
+ context.strokeStyle = getStyleFromHsl(this.spawnStrokeColor, container.hdr, this.spawnStrokeOpacity ?? defaultOpacity$1, container.peakNits, container.hdrMode);
7323
+ context.lineWidth = this.spawnStrokeWidth ?? defaultStrokeWidth;
7324
+ }
7325
+ this.#shape.draw?.(context);
7326
+ if (fillEnabled) {
7327
+ context.fill();
7328
+ }
7329
+ if (this.spawnStrokeColor) {
7330
+ context.stroke();
7331
+ }
7332
+ context.restore();
7333
+ }
7114
7334
  externalPause() {
7115
7335
  this.#paused = true;
7116
7336
  this.pause();
@@ -7148,11 +7368,14 @@
7148
7368
  }
7149
7369
  }
7150
7370
  resize() {
7151
- const initialPosition = this.#initialPosition, container = this.#container;
7152
- this.position =
7153
- initialPosition && isPointInside(initialPosition, container.canvas.size, Vector.origin)
7154
- ? initialPosition
7155
- : this.#calcPosition();
7371
+ const container = this.#container;
7372
+ if (!this.#positionOverride) {
7373
+ const initialPosition = this.#initialPosition;
7374
+ this.position =
7375
+ initialPosition && isPointInside(initialPosition, container.canvas.size, Vector.origin)
7376
+ ? initialPosition
7377
+ : this.#calcPosition();
7378
+ }
7156
7379
  this.#size = this.#calcSize();
7157
7380
  this.size =
7158
7381
  this.#size.mode === PixelMode.percent
@@ -7163,6 +7386,11 @@
7163
7386
  : { width: this.#size.width, height: this.#size.height };
7164
7387
  this.#shape?.resize(this.position, this.size);
7165
7388
  }
7389
+ setPosition(position) {
7390
+ this.#positionOverride = true;
7391
+ this.position = { ...position };
7392
+ this.#shape?.resize(this.position, this.size);
7393
+ }
7166
7394
  update(delta) {
7167
7395
  if (this.#paused) {
7168
7396
  return;
@@ -7358,6 +7586,7 @@
7358
7586
  exports.loadConfettiExplosionsPreset = loadConfettiExplosionsPreset;
7359
7587
  exports.tsParticles = tsParticles;
7360
7588
 
7361
- }));
7589
+ })(g.__tsParticlesInternals.presets.confettiExplosions = g.__tsParticlesInternals.presets.confettiExplosions || {});
7590
+ })(typeof globalThis !== "undefined" ? globalThis : typeof window !== "undefined" ? window : self);
7591
+
7362
7592
  Object.assign(globalThis.window || globalThis, { loadConfettiExplosionsPreset: (globalThis.__tsParticlesInternals.presets.confettiExplosions || {}).loadConfettiExplosionsPreset });
7363
- delete (globalThis.window || globalThis).tsparticlesInternalExports;