@tsparticles/preset-squares 4.3.2 → 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.3.2 */
3
- (function (global, factory) {
4
- typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
5
- typeof define === 'function' && define.amd ? define(['exports'], factory) :
6
- (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory((global.__tsParticlesInternals = global.__tsParticlesInternals || {}, global.__tsParticlesInternals.presets = global.__tsParticlesInternals.presets || {}, global.__tsParticlesInternals.presets.squares = global.__tsParticlesInternals.presets.squares || {})));
7
- })(this, (function (exports) { 'use strict';
1
+ (function(g){g.__tsParticlesInternals=g.__tsParticlesInternals||{};g.__tsParticlesInternals.bundles=g.__tsParticlesInternals.bundles||{};g.__tsParticlesInternals.effects=g.__tsParticlesInternals.effects||{};g.__tsParticlesInternals.engine=g.__tsParticlesInternals.engine||{};g.__tsParticlesInternals.interactions=g.__tsParticlesInternals.interactions||{};g.__tsParticlesInternals.palettes=g.__tsParticlesInternals.palettes||{};g.__tsParticlesInternals.paths=g.__tsParticlesInternals.paths||{};g.__tsParticlesInternals.plugins=g.__tsParticlesInternals.plugins||{};g.__tsParticlesInternals.plugins=g.__tsParticlesInternals.plugins||{};g.__tsParticlesInternals.plugins.emittersShapes=g.__tsParticlesInternals.plugins.emittersShapes||{};g.__tsParticlesInternals.presets=g.__tsParticlesInternals.presets||{};g.__tsParticlesInternals.shapes=g.__tsParticlesInternals.shapes||{};g.__tsParticlesInternals.updaters=g.__tsParticlesInternals.updaters||{};g.__tsParticlesInternals.utils=g.__tsParticlesInternals.utils||{};g.__tsParticlesInternals.canvas=g.__tsParticlesInternals.canvas||{};g.__tsParticlesInternals.canvas=g.__tsParticlesInternals.canvas||{};g.__tsParticlesInternals.canvas.utils=g.__tsParticlesInternals.canvas.utils||{};g.__tsParticlesInternals.path=g.__tsParticlesInternals.path||{};g.__tsParticlesInternals.path=g.__tsParticlesInternals.path||{};g.__tsParticlesInternals.path.utils=g.__tsParticlesInternals.path.utils||{};var __tsProxyFactory=typeof Proxy!=="undefined"?function(obj){return new Proxy(obj,{get:function(target,key){if(!(key in target)){target[key]={};}return target[key];}});}:function(obj){return obj;};g.__tsParticlesInternals.bundles=__tsProxyFactory(g.__tsParticlesInternals.bundles);g.__tsParticlesInternals.effects=__tsProxyFactory(g.__tsParticlesInternals.effects);g.__tsParticlesInternals.interactions=__tsProxyFactory(g.__tsParticlesInternals.interactions);g.__tsParticlesInternals.palettes=__tsProxyFactory(g.__tsParticlesInternals.palettes);g.__tsParticlesInternals.paths=__tsProxyFactory(g.__tsParticlesInternals.paths);g.__tsParticlesInternals.plugins=__tsProxyFactory(g.__tsParticlesInternals.plugins);g.__tsParticlesInternals.plugins.emittersShapes=__tsProxyFactory(g.__tsParticlesInternals.plugins.emittersShapes);g.__tsParticlesInternals.presets=__tsProxyFactory(g.__tsParticlesInternals.presets);g.__tsParticlesInternals.shapes=__tsProxyFactory(g.__tsParticlesInternals.shapes);g.__tsParticlesInternals.updaters=__tsProxyFactory(g.__tsParticlesInternals.updaters);g.__tsParticlesInternals.utils=__tsProxyFactory(g.__tsParticlesInternals.utils);g.__tsParticlesInternals.canvas=__tsProxyFactory(g.__tsParticlesInternals.canvas);g.__tsParticlesInternals.path=__tsProxyFactory(g.__tsParticlesInternals.path);})(typeof globalThis!=="undefined"?globalThis:typeof window!=="undefined"?window:this);
2
+ (function (g) {
3
+ /* Preset v4.5.0 */
4
+ g.__tsParticlesInternals = g.__tsParticlesInternals || {};
5
+ g.__tsParticlesInternals.presets = g.__tsParticlesInternals.presets || {};
6
+ (function (exports) {
7
+ 'use strict';
8
8
 
9
- const generatedAttribute = "generated", defaultCompositeValue = "source-over", resizeEvent = "resize", visibilityChangeEvent = "visibilitychange", percentDenominator = 100, half = 0.5, millisecondsToSeconds = 1000, originPoint = {
10
- x: 0,
11
- y: 0,
12
- z: 0,
13
- }, defaultTransform = {
14
- a: 1,
15
- b: 0,
16
- c: 0,
17
- d: 1,
18
- }, randomColorValue = "random", double = 2, doublePI = Math.PI * double, defaultFps = 60, generatedTrue = "true", generatedFalse = "false", canvasTag = "canvas", defaultRetryCount = 0, squareExp = 2, spatialHashGridCellSize = 100, defaultRemoveQuantity = 1, defaultRatio = 1, defaultReduceFactor = 1, inverseFactorNumerator = 1, rgbMax = 255, hMax = 360, sMax = 100, lMax = 100, hMin = 0, sMin = 0, hPhase = 60, empty = 0, quarter = 0.25, threeQuarter = half + quarter, defaultTransformValue = 1, minimumSize = 0, zIndexFactorOffset = 1, defaultOpacity$1 = 1, removeDeleteCount = 1, removeMinIndex = 0, defaultFpsLimit = 120, minFpsLimit = 0, canvasFirstIndex = 0, loadRandomFactor = 10000, loadMinIndex = 0, one = 1, none = 0, decayOffset = 1, tryCountIncrement = 1, minZ = 0, minLimit = 0, countOffset = 1, minCount = 0, minIndex = 0, defaultDensityFactor = 1, deleteCount = 1, defaultAngle = 0, identity = 1, minStrokeWidth = 0, lFactor = 1, lMin = 0, maxNits = 400, triple = 3, sextuple = 6, sNormalizedOffset = 1, phaseNumerator = 1, defaultRgbMin = 0, defaultVelocity = 0, defaultLoops = 0, defaultTime = 0, defaultZoom = 1;
9
+ const errorPrefix = "tsParticles - Error", codedErrorPattern = /^\[tsParticles Error (TSP-\d+)\]\s*/, fullMatchIndex = 0, codeIndex = 1;
10
+ const wrap = (fn) => (...args) => {
11
+ fn(...args);
12
+ }, _logger = {
13
+ debug: wrap(console.debug),
14
+ error: (message, ...optionalParams) => {
15
+ if (typeof message === "string") {
16
+ const match = codedErrorPattern.exec(message);
17
+ if (match?.[codeIndex]) {
18
+ console.error(`tsParticles - ${match[codeIndex]} - ${message.slice(match[fullMatchIndex].length)}`, ...optionalParams);
19
+ return;
20
+ }
21
+ }
22
+ console.error(`${errorPrefix} - ${message}`, ...optionalParams);
23
+ },
24
+ info: wrap(console.info),
25
+ log: wrap(console.log),
26
+ trace: wrap(console.trace),
27
+ verbose: wrap(console.log),
28
+ warning: wrap(console.warn),
29
+ };
30
+ function getLogger() {
31
+ return _logger;
32
+ }
19
33
 
20
34
  var MoveDirection;
21
35
  (function (MoveDirection) {
@@ -32,6 +46,17 @@
32
46
  MoveDirection["inside"] = "inside";
33
47
  })(MoveDirection || (MoveDirection = {}));
34
48
 
49
+ const generatedAttribute = "generated", fullPercent = "100%", defaultCompositeValue = "source-over", resizeEvent = "resize", visibilityChangeEvent = "visibilitychange", percentDenominator = 100, half = 0.5, millisecondsToSeconds = 1000, originPoint = {
50
+ x: 0,
51
+ y: 0,
52
+ z: 0,
53
+ }, defaultTransform = {
54
+ a: 1,
55
+ b: 0,
56
+ c: 0,
57
+ d: 1,
58
+ }, randomColorValue = "random", double = 2, doublePI = Math.PI * double, defaultFps = 60, defaultAlpha = 1, generatedTrue = "true", generatedFalse = "false", canvasTag = "canvas", defaultRetryCount = 0, squareExp = 2, spatialHashGridCellSize = 100, defaultRemoveQuantity = 1, defaultRatio = 1, defaultReduceFactor = 1, inverseFactorNumerator = 1, rgbMax = 255, hMax = 360, sMax = 100, lMax = 100, hMin = 0, sMin = 0, hPhase = 60, empty = 0, quarter = 0.25, threeQuarter = half + quarter, minRadius = 0, defaultTransformValue = 1, minimumSize = 0, zIndexFactorOffset = 1, defaultOpacity$1 = 1, removeDeleteCount = 1, removeMinIndex = 0, defaultFpsLimit = 120, minFpsLimit = 0, canvasFirstIndex = 0, loadRandomFactor = 10000, loadMinIndex = 0, one = 1, none = 0, decayOffset = 1, tryCountIncrement = 1, minZ = 0, minLimit = 0, countOffset = 1, minCount = 0, minIndex = 0, defaultDensityFactor = 1, deleteCount = 1, defaultAngle = 0, identity = 1, minStrokeWidth = 0, lFactor = 1, lMin = 0, maxNits = 400, triple = 3, sextuple = 6, sNormalizedOffset = 1, phaseNumerator = 1, defaultRgbMin = 0, defaultVelocity = 0, defaultLoops = 0, defaultTime = 0, defaultZoom = 1;
59
+
35
60
  function getZ(source) {
36
61
  return "z" in source ? source.z : originPoint.z;
37
62
  }
@@ -147,6 +172,12 @@
147
172
  function isNumber(arg) {
148
173
  return typeof arg === "number";
149
174
  }
175
+ function isEnumValue(enumObject, arg) {
176
+ return Object.values(enumObject).some(enumValue => enumValue === arg);
177
+ }
178
+ function toEnumValue(enumObject, arg, defaultValue) {
179
+ return isEnumValue(enumObject, arg) ? arg : defaultValue;
180
+ }
150
181
  function isObject(arg) {
151
182
  return typeof arg === "object" && arg !== null;
152
183
  }
@@ -276,6 +307,57 @@
276
307
  };
277
308
  }
278
309
 
310
+ const ErrorCodes$1 = {
311
+ engineVersionMismatch: "TSP-1001",
312
+ particlePositionNotFound: "TSP-1002",
313
+ pluginRegisterAfterLoad: "TSP-1003",
314
+ offscreenCanvasUnsupported: "TSP-1101",
315
+ offscreenCanvasTransferFailed: "TSP-1102",
316
+ hdrEnableInvalid: "TSP-1201",
317
+ hdrModeInvalid: "TSP-1202",
318
+ hdrPeakNitsInvalid: "TSP-1203",
319
+ };
320
+
321
+ const messages = {
322
+ [ErrorCodes$1.engineVersionMismatch]: "The tsParticles version is different from the loaded plugins version. Engine version: {0}. Plugin version: {1}",
323
+ [ErrorCodes$1.particlePositionNotFound]: "a valid position cannot be found for particle",
324
+ [ErrorCodes$1.pluginRegisterAfterLoad]: "Register plugins can only be done before calling tsParticles.load()",
325
+ [ErrorCodes$1.offscreenCanvasUnsupported]: "OffscreenCanvas is required but not supported by this browser",
326
+ [ErrorCodes$1.offscreenCanvasTransferFailed]: "OffscreenCanvas transfer failed",
327
+ [ErrorCodes$1.hdrEnableInvalid]: 'Invalid HDR "enable" value: expected a boolean, got "{0}"',
328
+ [ErrorCodes$1.hdrModeInvalid]: 'Invalid HDR "mode" value: expected one of {0}, got "{1}"',
329
+ [ErrorCodes$1.hdrPeakNitsInvalid]: 'Invalid HDR "peakNits" value: expected a positive number, got "{0}"',
330
+ };
331
+
332
+ let registeredMessages;
333
+ const ensureRegisteredMessages = () => {
334
+ registeredMessages ??= new Map(Object.entries(messages));
335
+ return registeredMessages;
336
+ }, toStringValue$1 = (value) => String(value), format = (template, args) => {
337
+ return template.replace(/\{(\d+)\}/g, (match, index) => {
338
+ const arg = args[Number(index)];
339
+ return arg === undefined ? match : toStringValue$1(arg);
340
+ });
341
+ };
342
+ function addErrorMessages(extraMessages) {
343
+ if (typeof process !== "undefined" && process.env.NODE_ENV === "production") {
344
+ return;
345
+ }
346
+ const catalog = ensureRegisteredMessages();
347
+ for (const [code, message] of Object.entries(extraMessages)) {
348
+ if (message !== undefined) {
349
+ catalog.set(code, message);
350
+ }
351
+ }
352
+ }
353
+ function getErrorMessage(code, ...args) {
354
+ if (typeof process !== "undefined" && process.env.NODE_ENV === "production") {
355
+ return `[tsParticles Error ${code}] https://particles.js.org/errors/#${code}`;
356
+ }
357
+ const template = ensureRegisteredMessages().get(code) ?? `Unknown error code ${code}`;
358
+ return format(template, args);
359
+ }
360
+
279
361
  var OutModeDirection;
280
362
  (function (OutModeDirection) {
281
363
  OutModeDirection["bottom"] = "bottom";
@@ -290,7 +372,6 @@
290
372
  PixelMode["percent"] = "percent";
291
373
  })(PixelMode || (PixelMode = {}));
292
374
 
293
- const minRadius = 0;
294
375
  function isForbiddenKey(key) {
295
376
  return key === "__proto__" || key === "constructor" || key === "prototype";
296
377
  }
@@ -486,22 +567,84 @@
486
567
  element.removeEventListener(event, handler, removeOptions);
487
568
  }
488
569
  }
489
- async function getItemsFromInitializer(container, map, initializers, force = false) {
490
- let res = map.get(container);
491
- if (!res || force) {
492
- res = await Promise.all([...initializers.values()].map(t => t(container)));
493
- map.set(container, res);
570
+ async function getItemsFromInitializer(container, initializers) {
571
+ return await Promise.all([...initializers.values()].map(t => t(container)));
572
+ }
573
+ async function getItemMapFromInitializer(container, initializers) {
574
+ const entries = await Promise.all([...initializers.entries()].map(([key, initializer]) => initializer(container).then(item => [key, item])));
575
+ return new Map(entries);
576
+ }
577
+ async function getDataFromUrl(data) {
578
+ const url = itemFromSingleOrMultiple(data.url, data.index);
579
+ if (!url) {
580
+ return data.fallback;
494
581
  }
495
- return res;
582
+ try {
583
+ const response = await fetch(url);
584
+ if (response.ok) {
585
+ const current = (await response.json());
586
+ if (isSourceOptionsValue(current)) {
587
+ return current;
588
+ }
589
+ getLogger().error("invalid configuration data while retrieving config file");
590
+ }
591
+ else {
592
+ getLogger().error(`${response.status.toString()} while retrieving config file`);
593
+ }
594
+ }
595
+ catch (error) {
596
+ getLogger().error(`error while retrieving config file: ${error}`);
597
+ }
598
+ return data.fallback;
496
599
  }
497
- async function getItemMapFromInitializer(container, map, initializers, force = false) {
498
- let res = map.get(container);
499
- if (!res || force) {
500
- const entries = await Promise.all([...initializers.entries()].map(([key, initializer]) => initializer(container).then(item => [key, item])));
501
- res = new Map(entries);
502
- map.set(container, res);
600
+ function isSourceOptionsValue(value) {
601
+ if (isArray(value)) {
602
+ return value.every((entry) => isObject(entry) && !isArray(entry));
503
603
  }
504
- return res;
604
+ return isObject(value) && !isArray(value);
605
+ }
606
+ function getCanvasFromContainer(domContainer) {
607
+ let canvasEl;
608
+ const documentSafe = safeDocument(), isCanvas = domContainer instanceof HTMLCanvasElement || domContainer.tagName.toLowerCase() === canvasTag;
609
+ if (isCanvas) {
610
+ canvasEl = domContainer;
611
+ canvasEl.dataset[generatedAttribute] ??= generatedFalse;
612
+ if (canvasEl.dataset[generatedAttribute] === generatedTrue) {
613
+ canvasEl.style.width ||= fullPercent;
614
+ canvasEl.style.height ||= fullPercent;
615
+ canvasEl.style.pointerEvents = "none";
616
+ canvasEl.style.setProperty("pointer-events", "none");
617
+ }
618
+ }
619
+ else {
620
+ const existingCanvases = domContainer.getElementsByTagName(canvasTag), foundCanvas = existingCanvases.item(canvasFirstIndex);
621
+ if (foundCanvas) {
622
+ canvasEl = foundCanvas;
623
+ canvasEl.dataset[generatedAttribute] = generatedFalse;
624
+ }
625
+ else {
626
+ canvasEl = documentSafe.createElement(canvasTag);
627
+ canvasEl.dataset[generatedAttribute] = generatedTrue;
628
+ domContainer.appendChild(canvasEl);
629
+ }
630
+ canvasEl.style.width ||= fullPercent;
631
+ canvasEl.style.height ||= fullPercent;
632
+ canvasEl.style.pointerEvents = "none";
633
+ canvasEl.style.setProperty("pointer-events", "none");
634
+ }
635
+ return canvasEl;
636
+ }
637
+ function getDomContainer(id, source) {
638
+ const documentSafe = safeDocument();
639
+ let domContainer = source ?? documentSafe.getElementById(id);
640
+ if (domContainer) {
641
+ return domContainer;
642
+ }
643
+ domContainer = documentSafe.createElement("canvas");
644
+ domContainer.id = id;
645
+ domContainer.dataset[generatedAttribute] = generatedTrue;
646
+ documentSafe.body.append(domContainer);
647
+ return domContainer;
505
648
  }
506
649
 
507
650
  class EventDispatcher {
@@ -572,7 +715,6 @@
572
715
  class PluginManager {
573
716
  colorManagers = new Map();
574
717
  easingFunctions = new Map();
575
- effectDrawers = new Map();
576
718
  initializers = {
577
719
  effects: new Map(),
578
720
  shapes: new Map(),
@@ -581,8 +723,6 @@
581
723
  palettes = new Map();
582
724
  plugins = [];
583
725
  presets = new Map();
584
- shapeDrawers = new Map();
585
- updaters = new Map();
586
726
  #allLoadersSet = new Set();
587
727
  #configs = new Map();
588
728
  #engine;
@@ -600,57 +740,79 @@
600
740
  }
601
741
  return res;
602
742
  }
743
+ get initialized() {
744
+ return this.#initialized;
745
+ }
603
746
  addColorManager(name, manager) {
747
+ if (this.#initialized) {
748
+ return;
749
+ }
604
750
  this.colorManagers.set(name, manager);
605
751
  }
606
752
  addConfig(config) {
753
+ if (this.#initialized) {
754
+ return;
755
+ }
607
756
  const key = config.key ?? config.name ?? "default";
608
757
  this.#configs.set(key, config);
609
758
  this.#engine.dispatchEvent(EventType.configAdded, { data: { name: key, config } });
610
759
  }
611
760
  addEasing(name, easing) {
761
+ if (this.#initialized) {
762
+ return;
763
+ }
612
764
  if (this.easingFunctions.get(name)) {
613
765
  return;
614
766
  }
615
767
  this.easingFunctions.set(name, easing);
616
768
  }
617
769
  addEffect(effect, drawer) {
770
+ if (this.#initialized) {
771
+ return;
772
+ }
618
773
  this.initializers.effects.set(effect, drawer);
619
774
  }
620
775
  addPalette(name, palette) {
776
+ if (this.#initialized) {
777
+ return;
778
+ }
621
779
  this.palettes.set(name, palette);
622
780
  }
623
781
  addParticleUpdater(name, updaterInitializer) {
782
+ if (this.#initialized) {
783
+ return;
784
+ }
624
785
  this.initializers.updaters.set(name, updaterInitializer);
625
786
  }
626
787
  addPlugin(plugin) {
788
+ if (this.#initialized) {
789
+ return;
790
+ }
627
791
  if (this.getPlugin(plugin.id)) {
628
792
  return;
629
793
  }
630
794
  this.plugins.push(plugin);
631
795
  }
632
796
  addPreset(preset, options, override = false) {
797
+ if (this.#initialized) {
798
+ return;
799
+ }
633
800
  if (!(override || !this.getPreset(preset))) {
634
801
  return;
635
802
  }
636
803
  this.presets.set(preset, options);
637
804
  }
638
805
  addShape(shapes, drawer) {
806
+ if (this.#initialized) {
807
+ return;
808
+ }
639
809
  for (const shape of shapes) {
640
810
  this.initializers.shapes.set(shape, drawer);
641
811
  }
642
812
  }
643
- clearPlugins(container) {
644
- this.effectDrawers.delete(container);
645
- this.shapeDrawers.delete(container);
646
- this.updaters.delete(container);
647
- }
648
813
  getEasing(name) {
649
814
  return this.easingFunctions.get(name) ?? ((value) => value);
650
815
  }
651
- getEffectDrawers(container, force = false) {
652
- return getItemMapFromInitializer(container, this.effectDrawers, this.initializers.effects, force);
653
- }
654
816
  getPalette(name) {
655
817
  return this.palettes.get(name);
656
818
  }
@@ -660,12 +822,6 @@
660
822
  getPreset(preset) {
661
823
  return this.presets.get(preset);
662
824
  }
663
- async getShapeDrawers(container, force = false) {
664
- return getItemMapFromInitializer(container, this.shapeDrawers, this.initializers.shapes, force);
665
- }
666
- async getUpdaters(container, force = false) {
667
- return getItemsFromInitializer(container, this.updaters, this.initializers.updaters, force);
668
- }
669
825
  async init() {
670
826
  if (this.#initialized || this.#isRunningLoaders) {
671
827
  return;
@@ -684,16 +840,9 @@
684
840
  this.#initialized = true;
685
841
  }
686
842
  }
687
- loadParticlesOptions(container, options, ...sourceOptions) {
688
- const updaters = this.updaters.get(container);
689
- if (!updaters) {
690
- return;
691
- }
692
- updaters.forEach(updater => updater.loadOptions?.(options, ...sourceOptions));
693
- }
694
843
  async register(...loaders) {
695
844
  if (this.#initialized) {
696
- throw new Error("Register plugins can only be done before calling tsParticles.load()");
845
+ throw new Error(getErrorMessage(ErrorCodes$1.pluginRegisterAfterLoad));
697
846
  }
698
847
  for (const loader of loaders) {
699
848
  if (this.#isRunningLoaders) {
@@ -705,88 +854,15 @@
705
854
  }
706
855
  }
707
856
  async #runLoader(loader, executed, allLoaders) {
708
- if (executed.has(loader))
857
+ if (executed.has(loader)) {
709
858
  return;
859
+ }
710
860
  executed.add(loader);
711
861
  allLoaders.add(loader);
712
862
  await loader(this.#engine);
713
863
  }
714
864
  }
715
865
 
716
- const errorPrefix = "tsParticles - Error";
717
- const wrap = (fn) => (...args) => {
718
- fn(...args);
719
- }, _logger = {
720
- debug: wrap(console.debug),
721
- error: (message, ...optionalParams) => {
722
- console.error(`${errorPrefix} - ${message}`, ...optionalParams);
723
- },
724
- info: wrap(console.info),
725
- log: wrap(console.log),
726
- trace: wrap(console.trace),
727
- verbose: wrap(console.log),
728
- warning: wrap(console.warn),
729
- };
730
- function getLogger() {
731
- return _logger;
732
- }
733
-
734
- const fullPercent = "100%";
735
- async function getDataFromUrl(data) {
736
- const url = itemFromSingleOrMultiple(data.url, data.index);
737
- if (!url) {
738
- return data.fallback;
739
- }
740
- const response = await fetch(url);
741
- if (response.ok) {
742
- return (await response.json());
743
- }
744
- getLogger().error(`${response.status.toString()} while retrieving config file`);
745
- return data.fallback;
746
- }
747
- const getCanvasFromContainer = (domContainer) => {
748
- const documentSafe = safeDocument();
749
- let canvasEl;
750
- const isCanvas = domContainer instanceof HTMLCanvasElement || domContainer.tagName.toLowerCase() === canvasTag;
751
- if (isCanvas) {
752
- canvasEl = domContainer;
753
- canvasEl.dataset[generatedAttribute] ??= generatedFalse;
754
- if (canvasEl.dataset[generatedAttribute] === generatedTrue) {
755
- canvasEl.style.width ||= fullPercent;
756
- canvasEl.style.height ||= fullPercent;
757
- canvasEl.style.pointerEvents = "none";
758
- canvasEl.style.setProperty("pointer-events", "none");
759
- }
760
- }
761
- else {
762
- const existingCanvases = domContainer.getElementsByTagName(canvasTag), foundCanvas = existingCanvases.item(canvasFirstIndex);
763
- if (foundCanvas) {
764
- canvasEl = foundCanvas;
765
- canvasEl.dataset[generatedAttribute] = generatedFalse;
766
- }
767
- else {
768
- canvasEl = documentSafe.createElement(canvasTag);
769
- canvasEl.dataset[generatedAttribute] = generatedTrue;
770
- domContainer.appendChild(canvasEl);
771
- }
772
- canvasEl.style.width ||= fullPercent;
773
- canvasEl.style.height ||= fullPercent;
774
- canvasEl.style.pointerEvents = "none";
775
- canvasEl.style.setProperty("pointer-events", "none");
776
- }
777
- return canvasEl;
778
- }, getDomContainer = (id, source) => {
779
- const documentSafe = safeDocument();
780
- let domContainer = source ?? documentSafe.getElementById(id);
781
- if (domContainer) {
782
- return domContainer;
783
- }
784
- domContainer = documentSafe.createElement("canvas");
785
- domContainer.id = id;
786
- domContainer.dataset[generatedAttribute] = generatedTrue;
787
- documentSafe.body.append(domContainer);
788
- return domContainer;
789
- };
790
866
  class Engine {
791
867
  pluginManager = new PluginManager(this);
792
868
  #domArray = [];
@@ -796,7 +872,7 @@
796
872
  return this.#domArray;
797
873
  }
798
874
  get version() {
799
- return "4.3.2";
875
+ return "4.5.0";
800
876
  }
801
877
  addEventListener(type, listener) {
802
878
  this.#eventDispatcher.addEventListener(type, listener);
@@ -805,7 +881,7 @@
805
881
  if (this.version === pluginVersion) {
806
882
  return;
807
883
  }
808
- throw new Error(`The tsParticles version is different from the loaded plugins version. Engine version: ${this.version}. Plugin version: ${pluginVersion}`);
884
+ throw new Error(getErrorMessage(ErrorCodes$1.engineVersionMismatch, this.version, pluginVersion));
809
885
  }
810
886
  dispatchEvent(type, args) {
811
887
  this.#eventDispatcher.dispatchEvent(type, args);
@@ -877,6 +953,10 @@
877
953
  }
878
954
 
879
955
  function initEngine() {
956
+ const existing = globalThis.tsParticles;
957
+ if (existing?.pluginManager) {
958
+ return existing;
959
+ }
880
960
  return new Engine();
881
961
  }
882
962
 
@@ -974,6 +1054,15 @@
974
1054
  AnimationMode["random"] = "random";
975
1055
  })(AnimationMode || (AnimationMode = {}));
976
1056
 
1057
+ var HdrMode;
1058
+ (function (HdrMode) {
1059
+ HdrMode["standard"] = "standard";
1060
+ HdrMode["natural"] = "natural";
1061
+ HdrMode["vivid"] = "vivid";
1062
+ HdrMode["cinematic"] = "cinematic";
1063
+ HdrMode["dynamic"] = "dynamic";
1064
+ })(HdrMode || (HdrMode = {}));
1065
+
977
1066
  var LimitMode;
978
1067
  (function (LimitMode) {
979
1068
  LimitMode["delete"] = "delete";
@@ -1041,20 +1130,6 @@
1041
1130
  DrawLayer[DrawLayer["Foreground"] = 7] = "Foreground";
1042
1131
  })(DrawLayer || (DrawLayer = {}));
1043
1132
 
1044
- class OptionLoader {
1045
- load(data) {
1046
- if (isNull(data)) {
1047
- return;
1048
- }
1049
- this.doLoad(data);
1050
- }
1051
- }
1052
- function loadOptions(options, ...sourceOptionsArr) {
1053
- for (const sourceOptions of sourceOptionsArr) {
1054
- options.load(sourceOptions);
1055
- }
1056
- }
1057
-
1058
1133
  function loadProperty(obj, key, value) {
1059
1134
  if (value !== undefined) {
1060
1135
  obj[key] = value;
@@ -1086,6 +1161,20 @@
1086
1161
  }
1087
1162
  }
1088
1163
 
1164
+ class OptionLoader {
1165
+ load(data) {
1166
+ if (isNull(data)) {
1167
+ return;
1168
+ }
1169
+ this.doLoad(data);
1170
+ }
1171
+ }
1172
+ function loadOptions(options, ...sourceOptionsArr) {
1173
+ for (const sourceOptions of sourceOptionsArr) {
1174
+ options.load(sourceOptions);
1175
+ }
1176
+ }
1177
+
1089
1178
  class AnimationOptions extends OptionLoader {
1090
1179
  count = 0;
1091
1180
  decay = 0;
@@ -1229,6 +1318,28 @@
1229
1318
  }
1230
1319
  }
1231
1320
 
1321
+ const defaultPeakNits = 400, minPeakNits = 0, toStringValue = (value) => String(value);
1322
+ class HDROptions extends OptionLoader {
1323
+ enable = true;
1324
+ mode = HdrMode.standard;
1325
+ peakNits = defaultPeakNits;
1326
+ doLoad(data) {
1327
+ if (data.enable !== undefined && !isBoolean(data.enable)) {
1328
+ throw new Error(getErrorMessage(ErrorCodes$1.hdrEnableInvalid, String(data.enable)));
1329
+ }
1330
+ if (data.mode !== undefined && !isEnumValue(HdrMode, data.mode)) {
1331
+ throw new Error(getErrorMessage(ErrorCodes$1.hdrModeInvalid, Object.values(HdrMode).join(", "), toStringValue(data.mode)));
1332
+ }
1333
+ if (data.peakNits !== undefined &&
1334
+ (!isNumber(data.peakNits) || !Number.isFinite(data.peakNits) || data.peakNits <= minPeakNits)) {
1335
+ throw new Error(getErrorMessage(ErrorCodes$1.hdrPeakNitsInvalid, String(data.peakNits)));
1336
+ }
1337
+ loadProperty(this, "enable", data.enable);
1338
+ loadProperty(this, "mode", data.mode);
1339
+ loadProperty(this, "peakNits", data.peakNits);
1340
+ }
1341
+ }
1342
+
1232
1343
  class ResizeEvent extends OptionLoader {
1233
1344
  delay = 0.5;
1234
1345
  enable = true;
@@ -1599,12 +1710,10 @@
1599
1710
  plugin.loadParticlesOptions(this.#container, this, data);
1600
1711
  }
1601
1712
  }
1602
- const updaters = this.#pluginManager.updaters.get(this.#container);
1603
- if (updaters) {
1604
- for (const updater of updaters) {
1605
- if (updater.loadOptions) {
1606
- updater.loadOptions(this, data);
1607
- }
1713
+ const updaters = this.#container.particleUpdaters;
1714
+ for (const updater of updaters) {
1715
+ if (updater.loadOptions) {
1716
+ updater.loadOptions(this, data);
1608
1717
  }
1609
1718
  }
1610
1719
  }
@@ -1672,7 +1781,7 @@
1672
1781
  duration = 0;
1673
1782
  fpsLimit = 120;
1674
1783
  fullScreen;
1675
- hdr = true;
1784
+ hdr;
1676
1785
  key;
1677
1786
  name;
1678
1787
  palette;
@@ -1692,6 +1801,7 @@
1692
1801
  this.#container = container;
1693
1802
  this.background = new Background();
1694
1803
  this.fullScreen = new FullScreen();
1804
+ this.hdr = new HDROptions();
1695
1805
  this.particles = loadParticlesOptions(this.#pluginManager, this.#container);
1696
1806
  this.resize = new ResizeEvent();
1697
1807
  }
@@ -1714,7 +1824,15 @@
1714
1824
  loadProperty(this, "detectRetina", data.detectRetina);
1715
1825
  loadRangeProperty(this, "duration", data.duration);
1716
1826
  loadProperty(this, "fpsLimit", data.fpsLimit);
1717
- loadProperty(this, "hdr", data.hdr);
1827
+ const hdrData = data.hdr;
1828
+ if (isBoolean(hdrData)) {
1829
+ this.hdr.enable = hdrData;
1830
+ this.hdr.mode = HdrMode.standard;
1831
+ this.hdr.peakNits = 400;
1832
+ }
1833
+ else {
1834
+ this.hdr.load(hdrData);
1835
+ }
1718
1836
  loadProperty(this, "pauseOnBlur", data.pauseOnBlur);
1719
1837
  loadProperty(this, "pauseOnOutsideViewport", data.pauseOnOutsideViewport);
1720
1838
  loadProperty(this, "zLayers", data.zLayers);
@@ -1757,7 +1875,7 @@
1757
1875
  }
1758
1876
  }
1759
1877
 
1760
- const styleCache = new Map(), maxStyleCacheSize = 2000, rgbFixedPrecision = 2, hslFixedPrecision = 2, hdrRgbFixedPrecision = 4, hdrHslFixedPrecision = 4, sdrReferenceWhiteNits = 203, hdrAnimationScale = sdrReferenceWhiteNits / maxNits;
1878
+ const styleCache = new Map(), maxStyleCacheSize = 2000, rgbFixedPrecision = 2, hslFixedPrecision = 2, hdrRgbFixedPrecision = 4, hdrHslFixedPrecision = 4, sdrReferenceWhiteNits = 203, acesA = 2.51, acesB = 0.03, acesC = 2.43, acesD = 0.59, acesE = 0.14, saturationBoost = 1.15, lightnessBoost = 1.05, temperatureR = 1.05, temperatureB = 0.95, contrastFactor = 1.1, luminanceR = 0.2126, luminanceG = 0.7152, luminanceB = 0.0722, dynamicLuminanceFactor = 2, channelCount = 3;
1761
1879
  function getCachedStyle(key, generator) {
1762
1880
  let cached = styleCache.get(key);
1763
1881
  if (!cached) {
@@ -1769,6 +1887,42 @@
1769
1887
  }
1770
1888
  return cached;
1771
1889
  }
1890
+ function acesFilmic(x) {
1891
+ return clamp((x * (acesA * x + acesB)) / (x * (acesC * x + acesD) + acesE), none, one);
1892
+ }
1893
+ function applyHdrModeAdjustments(r, g, b, mode, maxChannel) {
1894
+ switch (mode) {
1895
+ case HdrMode.vivid: {
1896
+ const avg = (r + g + b) / channelCount;
1897
+ return {
1898
+ b: clamp(clamp(avg + (b - avg) * saturationBoost, none, maxChannel) * lightnessBoost, none, maxChannel),
1899
+ g: clamp(clamp(avg + (g - avg) * saturationBoost, none, maxChannel) * lightnessBoost, none, maxChannel),
1900
+ r: clamp(clamp(avg + (r - avg) * saturationBoost, none, maxChannel) * lightnessBoost, none, maxChannel),
1901
+ };
1902
+ }
1903
+ case HdrMode.cinematic: {
1904
+ const tempR = r * temperatureR, tempB = b * temperatureB, avg = (tempR + g + tempB) / channelCount;
1905
+ return {
1906
+ b: clamp(avg + (tempB - avg) * contrastFactor, none, maxChannel),
1907
+ g: clamp(avg + (g - avg) * contrastFactor, none, maxChannel),
1908
+ r: clamp(avg + (tempR - avg) * contrastFactor, none, maxChannel),
1909
+ };
1910
+ }
1911
+ case HdrMode.dynamic: {
1912
+ const luminance = luminanceR * r + luminanceG * g + luminanceB * b, vividWeight = Math.min(one, luminance * dynamicLuminanceFactor), naturalWeight = one - vividWeight, avg = (r + g + b) / channelCount, vividR = clamp(avg + (r - avg) * saturationBoost, none, maxChannel) * lightnessBoost, vividG = clamp(avg + (g - avg) * saturationBoost, none, maxChannel) * lightnessBoost, vividB = clamp(avg + (b - avg) * saturationBoost, none, maxChannel) * lightnessBoost;
1913
+ return {
1914
+ b: clamp(b * naturalWeight + vividB * vividWeight, none, maxChannel),
1915
+ g: clamp(g * naturalWeight + vividG * vividWeight, none, maxChannel),
1916
+ r: clamp(r * naturalWeight + vividR * vividWeight, none, maxChannel),
1917
+ };
1918
+ }
1919
+ case HdrMode.standard:
1920
+ return { b, g, r };
1921
+ case HdrMode.natural:
1922
+ default:
1923
+ return { b, g, r };
1924
+ }
1925
+ }
1772
1926
  function stringToRgba(pluginManager, input) {
1773
1927
  if (!input) {
1774
1928
  return;
@@ -1892,9 +2046,9 @@
1892
2046
  const grayscaleValue = lNormalized * rgbMax;
1893
2047
  return { r: grayscaleValue, g: grayscaleValue, b: grayscaleValue };
1894
2048
  }
1895
- const temp1 = lNormalized < half
2049
+ const temp2 = lNormalized < half
1896
2050
  ? lNormalized * (sNormalizedOffset + sNormalized)
1897
- : lNormalized + sNormalized - lNormalized * sNormalized, temp2 = double * lNormalized - temp1, phaseThird = phaseNumerator / triple, red = Math.min(rgbMax, rgbMax * hslChannel(temp2, temp1, hNormalized + phaseThird)), green = Math.min(rgbMax, rgbMax * hslChannel(temp2, temp1, hNormalized)), blue = Math.min(rgbMax, rgbMax * hslChannel(temp2, temp1, hNormalized - phaseThird));
2051
+ : lNormalized + sNormalized - lNormalized * sNormalized, temp1 = double * lNormalized - temp2, phaseThird = phaseNumerator / triple, red = Math.min(rgbMax, rgbMax * hslChannel(temp1, temp2, hNormalized + phaseThird)), green = Math.min(rgbMax, rgbMax * hslChannel(temp1, temp2, hNormalized)), blue = Math.min(rgbMax, rgbMax * hslChannel(temp1, temp2, hNormalized - phaseThird));
1898
2052
  return { r: red, g: green, b: blue };
1899
2053
  }
1900
2054
  function getRandomRgbColor(min, hdr) {
@@ -1906,21 +2060,40 @@
1906
2060
  r: getRgbInRangeValue(),
1907
2061
  };
1908
2062
  }
1909
- function getStyleFromRgb(color, hdr, opacity) {
1910
- const rgbPrecision = hdr ? hdrRgbFixedPrecision : rgbFixedPrecision, op = opacity ?? defaultOpacity$1, key = `rgb-${color.r.toFixed(rgbPrecision)}-${color.g.toFixed(rgbPrecision)}-${color.b.toFixed(rgbPrecision)}-${hdr ? "hdr" : "sdr"}-${op.toString()}`;
1911
- return getCachedStyle(key, () => (hdr ? getHdrStyleFromRgb(color, opacity) : getSdrStyleFromRgb(color, opacity)));
2063
+ function getStyleFromRgb(color, hdr, opacity, peakNits, mode) {
2064
+ const rgbPrecision = hdr ? hdrRgbFixedPrecision : rgbFixedPrecision, op = opacity ?? defaultOpacity$1, key = hdr
2065
+ ? `rgb-${color.r.toFixed(rgbPrecision)}-${color.g.toFixed(rgbPrecision)}-${color.b.toFixed(rgbPrecision)}-hdr-${op.toString()}-${(peakNits ?? maxNits).toString()}-${mode ?? HdrMode.standard}`
2066
+ : `rgb-${color.r.toFixed(rgbPrecision)}-${color.g.toFixed(rgbPrecision)}-${color.b.toFixed(rgbPrecision)}-sdr-${op.toString()}`;
2067
+ return getCachedStyle(key, () => hdr ? getHdrStyleFromRgb(color, opacity, peakNits, mode) : getSdrStyleFromRgb(color, opacity));
1912
2068
  }
1913
- function getHdrStyleFromRgb(color, opacity, peakNits = maxNits) {
1914
- const headroom = peakNits / sdrReferenceWhiteNits;
1915
- return `color(display-p3 ${((color.r / rgbMax) * headroom).toString()} ${((color.g / rgbMax) * headroom).toString()} ${((color.b / rgbMax) * headroom).toString()} / ${(opacity ?? defaultOpacity$1).toString()})`;
2069
+ function getHdrStyleFromRgb(color, opacity, peakNits = maxNits, mode = HdrMode.standard) {
2070
+ const headroom = peakNits / sdrReferenceWhiteNits, middleGray = 0.18, mapped = hdrToneMapColor(color, headroom, middleGray, mode);
2071
+ return `color(display-p3 ${mapped.r.toString()} ${mapped.g.toString()} ${mapped.b.toString()} / ${(opacity ?? defaultOpacity$1).toString()})`;
2072
+ }
2073
+ function hdrToneMapColor(color, headroom, middleGray, mode) {
2074
+ const rNorm = color.r / rgbMax, gNorm = color.g / rgbMax, bNorm = color.b / rgbMax;
2075
+ if (mode !== HdrMode.natural && mode !== HdrMode.vivid && mode !== HdrMode.cinematic && mode !== HdrMode.dynamic) {
2076
+ return { b: bNorm, g: gNorm, r: rNorm };
2077
+ }
2078
+ const maxChannel = Math.max(one, headroom), luminance = luminanceR * rNorm + luminanceG * gNorm + luminanceB * bNorm, mappedLuminance = hdrToneMap(luminance, headroom, middleGray), scale = luminance > none ? mappedLuminance / luminance : one;
2079
+ return applyHdrModeAdjustments(clamp(rNorm * scale, none, maxChannel), clamp(gNorm * scale, none, maxChannel), clamp(bNorm * scale, none, maxChannel), mode, maxChannel);
2080
+ }
2081
+ function hdrToneMap(normalized, headroom, middleGray) {
2082
+ if (normalized <= middleGray) {
2083
+ return acesFilmic(normalized);
2084
+ }
2085
+ const expanded = normalized + (normalized - middleGray) * (headroom - one);
2086
+ return acesFilmic(expanded);
1916
2087
  }
1917
2088
  function getSdrStyleFromRgb(color, opacity) {
1918
2089
  return `rgba(${color.r.toString()}, ${color.g.toString()}, ${color.b.toString()}, ${(opacity ?? defaultOpacity$1).toString()})`;
1919
2090
  }
1920
- function getStyleFromHsl(color, hdr, opacity) {
1921
- const hslPrecision = hdr ? hdrHslFixedPrecision : hslFixedPrecision, op = opacity ?? defaultOpacity$1, key = `hsl-${color.h.toFixed(hslPrecision)}-${color.s.toFixed(hslPrecision)}-${color.l.toFixed(hslPrecision)}-${hdr ? "hdr" : "sdr"}-${op.toString()}`;
2091
+ function getStyleFromHsl(color, hdr, opacity, peakNits, mode) {
2092
+ const hslPrecision = hdr ? hdrHslFixedPrecision : hslFixedPrecision, op = opacity ?? defaultOpacity$1, key = hdr
2093
+ ? `hsl-${color.h.toFixed(hslPrecision)}-${color.s.toFixed(hslPrecision)}-${color.l.toFixed(hslPrecision)}-hdr-${op.toString()}-${(peakNits ?? maxNits).toString()}-${mode ?? HdrMode.standard}`
2094
+ : `hsl-${color.h.toFixed(hslPrecision)}-${color.s.toFixed(hslPrecision)}-${color.l.toFixed(hslPrecision)}-sdr-${op.toString()}`;
1922
2095
  return getCachedStyle(key, () => hdr
1923
- ? getStyleFromRgb(hslToRgbFloat(color), true, opacity)
2096
+ ? getStyleFromRgb(hslToRgbFloat(color), true, opacity, peakNits, mode)
1924
2097
  : `hsla(${color.h.toString()}, ${color.s.toString()}%, ${color.l.toString()}%, ${op.toString()})`);
1925
2098
  }
1926
2099
  function getHslFromAnimation(animation) {
@@ -1983,7 +2156,7 @@
1983
2156
  colorValue.velocity = defaultVelocity;
1984
2157
  }
1985
2158
  }
1986
- function updateColorValue(data, decrease, delta, hdr) {
2159
+ function updateColorValue(data, decrease, delta, _hdr) {
1987
2160
  const minLoops = 0, minDelay = 0, identity = 1, minVelocity = 0, minOffset = 0, velocityFactor = 3.6;
1988
2161
  if (!data.enable ||
1989
2162
  ((data.maxLoops ?? minLoops) > minLoops && (data.loops ?? minLoops) > (data.maxLoops ?? minLoops))) {
@@ -1996,7 +2169,7 @@
1996
2169
  if ((data.delayTime ?? minDelay) > minDelay && data.time < (data.delayTime ?? minDelay)) {
1997
2170
  return;
1998
2171
  }
1999
- const offset = data.offset ? randomInRangeValue(data.offset) : minOffset, velocity = ((data.velocity ?? minVelocity) * delta.factor + offset * velocityFactor) * (hdr ? hdrAnimationScale : identity), decay = data.decay ?? identity, max = data.max, min = data.min;
2172
+ const offset = data.offset ? randomInRangeValue(data.offset) : minOffset, velocity = (data.velocity ?? minVelocity) * delta.factor + offset * velocityFactor, decay = data.decay ?? identity, max = data.max, min = data.min;
2000
2173
  if (!decrease || data.status === AnimationStatus.increasing) {
2001
2174
  data.value += velocity;
2002
2175
  if (data.value > max) {
@@ -2028,9 +2201,9 @@
2028
2201
  return;
2029
2202
  }
2030
2203
  const { h, s, l } = color;
2031
- updateColorValue(h, false, delta, hdr);
2032
- updateColorValue(s, true, delta, hdr);
2033
- updateColorValue(l, true, delta, hdr);
2204
+ updateColorValue(h, false, delta);
2205
+ updateColorValue(s, true, delta);
2206
+ updateColorValue(l, true, delta);
2034
2207
  }
2035
2208
  function alterHsl(color, type, value) {
2036
2209
  return {
@@ -2134,6 +2307,8 @@
2134
2307
  autoPlay = true;
2135
2308
  direction;
2136
2309
  domId;
2310
+ draggable = false;
2311
+ draw = true;
2137
2312
  fill = true;
2138
2313
  life = new EmitterLife();
2139
2314
  name;
@@ -2157,6 +2332,8 @@
2157
2332
  }
2158
2333
  loadProperty(this, "direction", data.direction);
2159
2334
  loadProperty(this, "domId", data.domId);
2335
+ loadProperty(this, "draggable", data.draggable);
2336
+ loadProperty(this, "draw", data.draw);
2160
2337
  loadProperty(this, "fill", data.fill);
2161
2338
  this.life.load(data.life);
2162
2339
  loadProperty(this, "name", data.name);
@@ -2218,6 +2395,14 @@
2218
2395
  }
2219
2396
  }
2220
2397
 
2398
+ const ErrorCodes = {
2399
+ emittersPluginNotLoaded: "TSP-3101",
2400
+ };
2401
+
2402
+ const ErrorMessages = {
2403
+ [ErrorCodes.emittersPluginNotLoaded]: "tsParticles Emitters Plugin is not loaded",
2404
+ };
2405
+
2221
2406
  async function addEmittersShapesManager(e) {
2222
2407
  const { ShapeManager } = await Promise.resolve().then(function () { return ShapeManager$1; }), pluginManager = e.pluginManager;
2223
2408
  pluginManager.emitterShapeManager ??= new ShapeManager();
@@ -2248,7 +2433,10 @@
2248
2433
  })(EmitterClickMode || (EmitterClickMode = {}));
2249
2434
 
2250
2435
  async function loadEmittersPluginSimple(engine) {
2251
- engine.checkVersion("4.3.2");
2436
+ engine.checkVersion("4.5.0");
2437
+ if (typeof process !== "undefined" && process.env.NODE_ENV !== "production") {
2438
+ addErrorMessages(ErrorMessages);
2439
+ }
2252
2440
  await engine.pluginManager.register(async (e) => {
2253
2441
  const instancesManager = await getEmittersInstancesManager(e);
2254
2442
  await addEmittersShapesManager(e);
@@ -2263,7 +2451,7 @@
2263
2451
  RgbIndexes[RgbIndexes["b"] = 3] = "b";
2264
2452
  RgbIndexes[RgbIndexes["a"] = 4] = "a";
2265
2453
  })(RgbIndexes || (RgbIndexes = {}));
2266
- const shorthandHexRegex = /^#?([a-f\d])([a-f\d])([a-f\d])([a-f\d])?$/i, hexRegex = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})?$/i, hexRadix = 16, defaultAlpha = 1, alphaFactor = 0xff;
2454
+ const shorthandHexRegex = /^#?([a-f\d])([a-f\d])([a-f\d])([a-f\d])?$/i, hexRegex = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})?$/i, hexRadix = 16, alphaFactor = 0xff;
2267
2455
  class HexColorManager {
2268
2456
  accepts(input) {
2269
2457
  return input.startsWith("#");
@@ -2296,7 +2484,7 @@
2296
2484
  }
2297
2485
 
2298
2486
  async function loadHexColorPlugin(engine) {
2299
- engine.checkVersion("4.3.2");
2487
+ engine.checkVersion("4.5.0");
2300
2488
  await engine.pluginManager.register(e => {
2301
2489
  e.pluginManager.addColorManager("hex", new HexColorManager());
2302
2490
  });
@@ -2311,39 +2499,9 @@
2311
2499
  this.#pluginManager = pluginManager;
2312
2500
  }
2313
2501
  init(particle) {
2314
- 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;
2315
- if (fill) {
2316
- const fillColor = AnimatableColor.create(paintColor === undefined ? undefined : AnimatableColor.create(undefined, paintColor), fill.color);
2317
- particle.fillEnabled = fill.enable;
2318
- particle.fillOpacity = getRangeValue(fill.opacity);
2319
- particle.fillAnimation = fillColor.animation;
2320
- const fillHslColor = rangeColorToHsl(this.#pluginManager, fillColor);
2321
- if (fillHslColor) {
2322
- particle.fillColor = getHslAnimationFromHsl(fillHslColor, particle.fillAnimation, container.retina.reduceFactor);
2323
- }
2324
- }
2325
- else {
2326
- particle.fillEnabled = false;
2327
- particle.fillAnimation = undefined;
2328
- particle.fillColor = undefined;
2329
- particle.fillOpacity = defaultOpacity;
2330
- }
2331
- if (stroke) {
2332
- const strokeColor = AnimatableColor.create(paintColor === undefined ? undefined : AnimatableColor.create(undefined, paintColor), stroke.color);
2333
- particle.strokeWidth = getRangeValue(stroke.width) * container.retina.pixelRatio;
2334
- particle.strokeOpacity = getRangeValue(stroke.opacity ?? defaultOpacity);
2335
- particle.strokeAnimation = strokeColor.animation;
2336
- const strokeHslColor = rangeColorToHsl(this.#pluginManager, strokeColor) ?? particle.getFillColor();
2337
- if (strokeHslColor) {
2338
- particle.strokeColor = getHslAnimationFromHsl(strokeHslColor, particle.strokeAnimation, container.retina.reduceFactor);
2339
- }
2340
- }
2341
- else {
2342
- particle.strokeAnimation = undefined;
2343
- particle.strokeColor = undefined;
2344
- particle.strokeOpacity = defaultOpacity;
2345
- particle.strokeWidth = 0;
2346
- }
2502
+ const container = this.#container, options = particle.options, paint = itemFromSingleOrMultiple(options.paint, particle.id, options.reduceDuplicates);
2503
+ this.#initFill(paint, particle, container);
2504
+ this.#initStroke(paint, particle, container);
2347
2505
  }
2348
2506
  isEnabled(particle) {
2349
2507
  const { fillAnimation, fillColor, strokeAnimation, strokeColor } = particle, fillEnabled = !!fillAnimation &&
@@ -2362,10 +2520,48 @@
2362
2520
  updateColor(particle.fillColor, delta, this.#container.hdr);
2363
2521
  updateColor(particle.strokeColor, delta, this.#container.hdr);
2364
2522
  }
2523
+ #initFill(paint, particle, container) {
2524
+ const fill = paint?.fill, color = paint?.color, paintColor = color ?? undefined;
2525
+ if (!fill) {
2526
+ particle.fillEnabled = false;
2527
+ particle.fillAnimation = undefined;
2528
+ particle.fillColor = undefined;
2529
+ particle.fillOpacity = defaultOpacity;
2530
+ return;
2531
+ }
2532
+ const fillColor = AnimatableColor.create(paintColor === undefined ? undefined : AnimatableColor.create(undefined, paintColor), fill.color);
2533
+ particle.fillEnabled = fill.enable;
2534
+ particle.fillOpacity = getRangeValue(fill.opacity);
2535
+ particle.fillAnimation = fillColor.animation;
2536
+ const fillHslColor = rangeColorToHsl(this.#pluginManager, fillColor);
2537
+ if (!fillHslColor) {
2538
+ return;
2539
+ }
2540
+ particle.fillColor = getHslAnimationFromHsl(fillHslColor, particle.fillAnimation, container.retina.reduceFactor);
2541
+ }
2542
+ #initStroke(paint, particle, container) {
2543
+ const stroke = paint?.stroke, color = paint?.color, paintColor = color ?? undefined;
2544
+ if (!stroke) {
2545
+ particle.strokeAnimation = undefined;
2546
+ particle.strokeColor = undefined;
2547
+ particle.strokeOpacity = defaultOpacity;
2548
+ particle.strokeWidth = 0;
2549
+ return;
2550
+ }
2551
+ const strokeColor = AnimatableColor.create(paintColor === undefined ? undefined : AnimatableColor.create(undefined, paintColor), stroke.color);
2552
+ particle.strokeWidth = getRangeValue(stroke.width) * container.retina.pixelRatio;
2553
+ particle.strokeOpacity = getRangeValue(stroke.opacity ?? defaultOpacity);
2554
+ particle.strokeAnimation = strokeColor.animation;
2555
+ const strokeHslColor = rangeColorToHsl(this.#pluginManager, strokeColor) ?? particle.getFillColor();
2556
+ if (!strokeHslColor) {
2557
+ return;
2558
+ }
2559
+ particle.strokeColor = getHslAnimationFromHsl(strokeHslColor, particle.strokeAnimation, container.retina.reduceFactor);
2560
+ }
2365
2561
  }
2366
2562
 
2367
2563
  async function loadPaintUpdater(engine) {
2368
- engine.checkVersion("4.3.2");
2564
+ engine.checkVersion("4.5.0");
2369
2565
  await engine.pluginManager.register(e => {
2370
2566
  e.pluginManager.addParticleUpdater("paint", container => {
2371
2567
  return Promise.resolve(new PaintUpdater(e.pluginManager, container));
@@ -2547,7 +2743,7 @@
2547
2743
  particle.pathRotation = rotateOptions.path;
2548
2744
  let rotateDirection = rotateOptions.direction;
2549
2745
  if (rotateDirection === RotateDirection.random) {
2550
- const index = Math.floor(getRandom() * double), minIndex = 0;
2746
+ const index = Math.floor(getRandom() * double);
2551
2747
  rotateDirection = index > minIndex ? RotateDirection.counterClockwise : RotateDirection.clockwise;
2552
2748
  }
2553
2749
  switch (rotateDirection) {
@@ -2594,7 +2790,7 @@
2594
2790
  }
2595
2791
 
2596
2792
  async function loadRotateUpdater(engine) {
2597
- engine.checkVersion("4.3.2");
2793
+ engine.checkVersion("4.5.0");
2598
2794
  await engine.pluginManager.register(e => {
2599
2795
  e.pluginManager.addParticleUpdater("rotate", container => {
2600
2796
  return Promise.resolve(new RotateUpdater(container));
@@ -2681,7 +2877,7 @@
2681
2877
  }
2682
2878
 
2683
2879
  async function loadSizeUpdater(engine) {
2684
- engine.checkVersion("4.3.2");
2880
+ engine.checkVersion("4.5.0");
2685
2881
  await engine.pluginManager.register(e => {
2686
2882
  e.pluginManager.addParticleUpdater("size", container => {
2687
2883
  return Promise.resolve(new SizeUpdater(container));
@@ -2705,7 +2901,7 @@
2705
2901
  }
2706
2902
 
2707
2903
  async function loadSquareShape(engine) {
2708
- engine.checkVersion("4.3.2");
2904
+ engine.checkVersion("4.5.0");
2709
2905
  await engine.pluginManager.register(e => {
2710
2906
  e.pluginManager.addShape(["edge", "square"], () => Promise.resolve(new SquareDrawer()));
2711
2907
  });
@@ -2844,21 +3040,28 @@
2844
3040
  });
2845
3041
  }
2846
3042
  clear() {
3043
+ const visited = new Set();
2847
3044
  for (const plugin of this.#canvasClearPlugins) {
3045
+ visited.add(plugin);
2848
3046
  if (plugin.canvasClear?.() ?? false) {
2849
- return;
3047
+ return plugin;
2850
3048
  }
2851
3049
  }
2852
3050
  for (const layer of Object.values(DrawLayer)) {
2853
3051
  if (typeof layer === "number") {
2854
3052
  for (const plugin of this.#getLayerPlugins(layer)) {
3053
+ if (visited.has(plugin)) {
3054
+ continue;
3055
+ }
3056
+ visited.add(plugin);
2855
3057
  if (plugin.canvasClear?.() ?? false) {
2856
- return;
3058
+ return plugin;
2857
3059
  }
2858
3060
  }
2859
3061
  }
2860
3062
  }
2861
3063
  this.canvasClear();
3064
+ return undefined;
2862
3065
  }
2863
3066
  destroy() {
2864
3067
  this.stop();
@@ -2899,7 +3102,11 @@
2899
3102
  if (!fColor && !sColor) {
2900
3103
  return;
2901
3104
  }
2902
- const container = this.#container, zIndexOptions = particle.options.zIndex, zIndexFactor = zIndexFactorOffset - particle.zIndexFactor, { fillOpacity, opacity, strokeOpacity } = particle.getOpacity(), transform = this.#reusableTransform, colorStyles = this.#reusableColorStyles, fill = fColor ? getStyleFromHsl(fColor, container.hdr, fillOpacity * opacity) : undefined, stroke = sColor ? getStyleFromHsl(sColor, container.hdr, strokeOpacity * opacity) : fill;
3105
+ const container = this.#container, zIndexOptions = particle.options.zIndex, zIndexFactor = zIndexFactorOffset - particle.zIndexFactor, { fillOpacity, opacity, strokeOpacity } = particle.getOpacity(), transform = this.#reusableTransform, colorStyles = this.#reusableColorStyles, fill = fColor
3106
+ ? getStyleFromHsl(fColor, container.hdr, fillOpacity * opacity, container.peakNits, container.hdrMode)
3107
+ : undefined, stroke = sColor
3108
+ ? getStyleFromHsl(sColor, container.hdr, strokeOpacity * opacity, container.peakNits, container.hdrMode)
3109
+ : fill;
2903
3110
  transform.a = transform.b = transform.c = transform.d = undefined;
2904
3111
  colorStyles.fill = fill;
2905
3112
  colorStyles.stroke = stroke;
@@ -2932,8 +3139,7 @@
2932
3139
  });
2933
3140
  }
2934
3141
  drawParticles(delta) {
2935
- const { particles, actualOptions } = this.#container;
2936
- this.clear();
3142
+ const { particles, actualOptions } = this.#container, clearedPlugin = this.clear();
2937
3143
  particles.update(delta);
2938
3144
  this.draw(ctx => {
2939
3145
  const width = this.#canvasManager.size.width, height = this.#canvasManager.size.height;
@@ -2955,7 +3161,9 @@
2955
3161
  }
2956
3162
  }
2957
3163
  for (const plugin of this.#getLayerPlugins(DrawLayer.BackgroundMask)) {
2958
- plugin.canvasPaint?.();
3164
+ if (plugin !== clearedPlugin) {
3165
+ plugin.canvasPaint?.();
3166
+ }
2959
3167
  }
2960
3168
  for (const plugin of this.#getLayerPlugins(DrawLayer.CanvasSetup)) {
2961
3169
  plugin.drawSettingsSetup?.(ctx, delta);
@@ -2987,35 +3195,7 @@
2987
3195
  this.#layers[layer] = [];
2988
3196
  }
2989
3197
  }
2990
- for (const plugin of this.#container.plugins) {
2991
- if (plugin.particleFillColor ?? plugin.particleStrokeColor) {
2992
- this.#colorPlugins.push(plugin);
2993
- }
2994
- if (plugin.drawParticle) {
2995
- this.#drawParticlePlugins.push(plugin);
2996
- }
2997
- if (plugin.drawParticleSetup) {
2998
- this.#drawParticlesSetupPlugins.push(plugin);
2999
- }
3000
- if (plugin.drawParticleCleanup) {
3001
- this.#drawParticlesCleanupPlugins.push(plugin);
3002
- }
3003
- if (plugin.canvasClear) {
3004
- this.#canvasClearPlugins.push(plugin);
3005
- }
3006
- if (plugin.canvasPaint) {
3007
- this.#getLayerPlugins(DrawLayer.BackgroundMask).push(plugin);
3008
- }
3009
- if (plugin.drawSettingsSetup) {
3010
- this.#getLayerPlugins(DrawLayer.CanvasSetup).push(plugin);
3011
- }
3012
- if (plugin.draw) {
3013
- this.#getLayerPlugins(DrawLayer.PluginContent).push(plugin);
3014
- }
3015
- if (plugin.clearDraw ?? plugin.drawSettingsCleanup) {
3016
- this.#getLayerPlugins(DrawLayer.CanvasCleanup).push(plugin);
3017
- }
3018
- }
3198
+ this.#initPluginsArray();
3019
3199
  }
3020
3200
  initUpdaters() {
3021
3201
  this.#preDrawUpdaters = [];
@@ -3224,6 +3404,45 @@
3224
3404
  this.#reusablePluginColors[sColorIndex] = sColor;
3225
3405
  return this.#reusablePluginColors;
3226
3406
  }
3407
+ #initLayerPlugin(plugin) {
3408
+ const layerMap = [
3409
+ [DrawLayer.BackgroundMask, !!plugin.canvasPaint],
3410
+ [DrawLayer.CanvasSetup, !!plugin.drawSettingsSetup],
3411
+ [DrawLayer.PluginContent, !!plugin.draw],
3412
+ [DrawLayer.CanvasCleanup, !!(plugin.clearDraw ?? plugin.drawSettingsCleanup)],
3413
+ ];
3414
+ for (const [layer, active] of layerMap) {
3415
+ if (active) {
3416
+ this.#layers[layer].push(plugin);
3417
+ }
3418
+ }
3419
+ }
3420
+ #initPluginsArray() {
3421
+ for (const plugin of this.#container.plugins) {
3422
+ if (plugin.particleFillColor ?? plugin.particleStrokeColor) {
3423
+ this.#colorPlugins.push(plugin);
3424
+ }
3425
+ if (plugin.drawParticle) {
3426
+ this.#drawParticlePlugins.push(plugin);
3427
+ }
3428
+ if (plugin.drawParticleSetup) {
3429
+ this.#drawParticlesSetupPlugins.push(plugin);
3430
+ }
3431
+ if (plugin.drawParticleCleanup) {
3432
+ this.#drawParticlesCleanupPlugins.push(plugin);
3433
+ }
3434
+ if (plugin.canvasClear) {
3435
+ this.#canvasClearPlugins.push(plugin);
3436
+ }
3437
+ this.#initLayerPlugin(plugin);
3438
+ }
3439
+ }
3440
+ #isSupportedElement(element) {
3441
+ return ((typeof HTMLCanvasElement !== "undefined" && element instanceof HTMLCanvasElement) ||
3442
+ (typeof OffscreenCanvas !== "undefined" && element instanceof OffscreenCanvas) ||
3443
+ (typeof HTMLVideoElement !== "undefined" && element instanceof HTMLVideoElement) ||
3444
+ (typeof HTMLImageElement !== "undefined" && element instanceof HTMLImageElement));
3445
+ }
3227
3446
  #resolveBackgroundElement() {
3228
3447
  const background = this.#container.actualOptions.background;
3229
3448
  this.#backgroundElement = null;
@@ -3233,7 +3452,7 @@
3233
3452
  if (typeof background.element === "string") {
3234
3453
  if (typeof document !== "undefined") {
3235
3454
  const node = document.querySelector(background.element);
3236
- if (node instanceof HTMLCanvasElement || node instanceof HTMLVideoElement || node instanceof HTMLImageElement) {
3455
+ if (node && this.#isSupportedElement(node)) {
3237
3456
  this.#backgroundElement = node;
3238
3457
  }
3239
3458
  else if (node) {
@@ -3244,10 +3463,7 @@
3244
3463
  }
3245
3464
  }
3246
3465
  }
3247
- else if (background.element instanceof HTMLCanvasElement ||
3248
- background.element instanceof OffscreenCanvas ||
3249
- background.element instanceof HTMLVideoElement ||
3250
- background.element instanceof HTMLImageElement) {
3466
+ else if (this.#isSupportedElement(background.element)) {
3251
3467
  this.#backgroundElement = background.element;
3252
3468
  }
3253
3469
  }
@@ -3265,7 +3481,7 @@
3265
3481
  return transferredCanvas;
3266
3482
  }
3267
3483
  if (typeof canvas.transferControlToOffscreen !== "function") {
3268
- throw new TypeError("OffscreenCanvas is required but not supported by this browser");
3484
+ throw new TypeError(getErrorMessage(ErrorCodes$1.offscreenCanvasUnsupported));
3269
3485
  }
3270
3486
  try {
3271
3487
  const offscreenCanvas = canvas.transferControlToOffscreen();
@@ -3273,10 +3489,16 @@
3273
3489
  return offscreenCanvas;
3274
3490
  }
3275
3491
  catch {
3276
- throw new TypeError("OffscreenCanvas transfer failed");
3492
+ throw new TypeError(getErrorMessage(ErrorCodes$1.offscreenCanvasTransferFailed));
3277
3493
  }
3278
3494
  }, isHtmlCanvasElement = (canvas) => {
3279
3495
  return typeof HTMLCanvasElement !== "undefined" && canvas instanceof HTMLCanvasElement;
3496
+ }, getEffectiveColorSpace = (context) => {
3497
+ if (!context) {
3498
+ return undefined;
3499
+ }
3500
+ const colorInfo = context;
3501
+ return colorInfo.getContextAttributes?.().colorSpace ?? undefined;
3280
3502
  };
3281
3503
  function setStyle(canvas, style, important = false) {
3282
3504
  if (!style) {
@@ -3315,6 +3537,7 @@
3315
3537
  zoom = defaultZoom;
3316
3538
  #container;
3317
3539
  #generated;
3540
+ #hdrMediaListeners;
3318
3541
  #mutationObserver;
3319
3542
  #originalStyle;
3320
3543
  #pluginManager;
@@ -3379,7 +3602,6 @@
3379
3602
  });
3380
3603
  this.resize();
3381
3604
  this.#initStyle();
3382
- this.initBackground();
3383
3605
  this.#safeMutationObserver(obs => {
3384
3606
  const element = this.domElement;
3385
3607
  if (!element || !(element instanceof Node)) {
@@ -3389,6 +3611,8 @@
3389
3611
  });
3390
3612
  this.initPlugins();
3391
3613
  this.#initContext();
3614
+ this.initBackground();
3615
+ this.#initHdrListeners();
3392
3616
  this.render.init();
3393
3617
  }
3394
3618
  initBackground() {
@@ -3398,7 +3622,8 @@
3398
3622
  }
3399
3623
  const elementStyle = element.style, color = rangeColorToRgb(this.#pluginManager, background.color);
3400
3624
  if (color) {
3401
- elementStyle.backgroundColor = getStyleFromRgb(color, container.actualOptions.hdr, background.opacity);
3625
+ const hdrOptions = container.actualOptions.hdr;
3626
+ elementStyle.backgroundColor = getStyleFromRgb(color, container.hdr, background.opacity, hdrOptions.peakNits, toEnumValue(HdrMode, hdrOptions.mode, HdrMode.standard));
3402
3627
  }
3403
3628
  else {
3404
3629
  elementStyle.backgroundColor = "";
@@ -3495,6 +3720,7 @@
3495
3720
  obs.disconnect();
3496
3721
  });
3497
3722
  this.#mutationObserver = undefined;
3723
+ this.#removeHdrListeners();
3498
3724
  this.render.stop();
3499
3725
  }
3500
3726
  async windowResize() {
@@ -3514,9 +3740,16 @@
3514
3740
  }
3515
3741
  }
3516
3742
  #initContext() {
3517
- const container = this.#container, canSupportHdr = container.actualOptions.hdr &&
3743
+ const container = this.#container, canSupportHdr = container.actualOptions.hdr.enable &&
3518
3744
  safeMatchMedia("(color-gamut: p3)")?.matches &&
3519
3745
  safeMatchMedia("(dynamic-range: high)")?.matches;
3746
+ container.hdrMode = toEnumValue(HdrMode, container.actualOptions.hdr.mode, HdrMode.standard);
3747
+ container.peakNits = container.actualOptions.hdr.peakNits;
3748
+ const renderCanvas = this.renderCanvas;
3749
+ if (!renderCanvas) {
3750
+ container.hdr = canSupportHdr ?? false;
3751
+ return;
3752
+ }
3520
3753
  this.render.setContextSettings({
3521
3754
  alpha: true,
3522
3755
  desynchronized: true,
@@ -3525,11 +3758,51 @@
3525
3758
  ? { colorSpace: "display-p3", colorType: "float16" }
3526
3759
  : { colorSpace: "srgb" }),
3527
3760
  });
3528
- const renderCanvas = this.renderCanvas;
3529
- if (!renderCanvas) {
3530
- return;
3761
+ let context;
3762
+ try {
3763
+ context = renderCanvas.getContext("2d", this.render.settings);
3764
+ }
3765
+ catch {
3766
+ context = null;
3767
+ }
3768
+ if (canSupportHdr && !context) {
3769
+ const sdrSettings = {
3770
+ alpha: true,
3771
+ desynchronized: true,
3772
+ willReadFrequently: false,
3773
+ colorSpace: "srgb",
3774
+ };
3775
+ this.render.setContextSettings(sdrSettings);
3776
+ try {
3777
+ context = renderCanvas.getContext("2d", sdrSettings);
3778
+ }
3779
+ catch {
3780
+ context = null;
3781
+ }
3782
+ }
3783
+ this.render.setContext(context);
3784
+ if (context) {
3785
+ const effectiveColorSpace = getEffectiveColorSpace(context);
3786
+ if (effectiveColorSpace !== undefined) {
3787
+ container.hdr = effectiveColorSpace === "display-p3";
3788
+ }
3789
+ }
3790
+ }
3791
+ #initHdrListeners() {
3792
+ this.#removeHdrListeners();
3793
+ const p3Query = safeMatchMedia("(color-gamut: p3)"), hdrQuery = safeMatchMedia("(dynamic-range: high)"), handleChange = () => {
3794
+ this.#initContext();
3795
+ this.initBackground();
3796
+ }, listeners = [];
3797
+ if (p3Query) {
3798
+ p3Query.addEventListener("change", handleChange);
3799
+ listeners.push({ handler: handleChange, mql: p3Query });
3800
+ }
3801
+ if (hdrQuery) {
3802
+ hdrQuery.addEventListener("change", handleChange);
3803
+ listeners.push({ handler: handleChange, mql: hdrQuery });
3531
3804
  }
3532
- this.render.setContext(renderCanvas.getContext("2d", this.render.settings));
3805
+ this.#hdrMediaListeners = listeners;
3533
3806
  }
3534
3807
  #initStyle() {
3535
3808
  const element = this.domElement, options = this.#container.actualOptions;
@@ -3553,6 +3826,15 @@
3553
3826
  element.style.setProperty(key, value, "important");
3554
3827
  }
3555
3828
  }
3829
+ #removeHdrListeners() {
3830
+ if (!this.#hdrMediaListeners) {
3831
+ return;
3832
+ }
3833
+ for (const { handler, mql } of this.#hdrMediaListeners) {
3834
+ mql.removeEventListener("change", handler);
3835
+ }
3836
+ this.#hdrMediaListeners = undefined;
3837
+ }
3556
3838
  #repairStyle() {
3557
3839
  const element = this.domElement;
3558
3840
  if (!element) {
@@ -3642,8 +3924,7 @@
3642
3924
  this.#resizeTimeout = undefined;
3643
3925
  }
3644
3926
  const handleResize = async () => {
3645
- const canvas = this.#container.canvas;
3646
- await canvas.windowResize();
3927
+ await this.#container.canvas.windowResize();
3647
3928
  };
3648
3929
  this.#resizeTimeout = setTimeout(() => void handleResize(), this.#container.actualOptions.resize.delay * millisecondsToSeconds);
3649
3930
  }
@@ -3671,8 +3952,8 @@
3671
3952
  }
3672
3953
  else if (!this.#resizeObserver && add && canvasEl) {
3673
3954
  this.#resizeObserver = new ResizeObserver((entries) => {
3674
- const entry = entries.find(e => e.target === canvasEl);
3675
- if (!entry) {
3955
+ const res = entries.some(e => e.target === canvasEl);
3956
+ if (!res) {
3676
3957
  return;
3677
3958
  }
3678
3959
  this.#handleWindowResize();
@@ -3936,10 +4217,10 @@
3936
4217
  return this.#modifiers.find(m => m.id === id);
3937
4218
  }
3938
4219
  getOpacity() {
3939
- 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;
3940
- this.#cachedOpacityData.fillOpacity = opacity * fillOpacity * zOpacityFactor;
4220
+ const zIndexOptions = this.options.zIndex, zIndexFactor = zIndexFactorOffset - this.zIndexFactor, zOpacityFactor = zIndexFactor ** zIndexOptions.opacityRate, baseOpacity = getRangeValue(this.opacity?.value ?? defaultOpacity$1), modifierOpacity = this.#applyModifiers(undefined, m => m.opacity), opacity = modifierOpacity ?? baseOpacity;
4221
+ this.#cachedOpacityData.fillOpacity = this.fillOpacity ?? defaultOpacity$1;
3941
4222
  this.#cachedOpacityData.opacity = opacity * zOpacityFactor;
3942
- this.#cachedOpacityData.strokeOpacity = opacity * strokeOpacity * zOpacityFactor;
4223
+ this.#cachedOpacityData.strokeOpacity = this.strokeOpacity ?? defaultOpacity$1;
3943
4224
  return this.#cachedOpacityData;
3944
4225
  }
3945
4226
  getPosition() {
@@ -4186,7 +4467,7 @@
4186
4467
  #initPosition(position) {
4187
4468
  const container = this.#container, zIndexValue = Math.floor(getRangeValue(this.options.zIndex.value)), initialPosition = this.#calcPosition(position, clamp(zIndexValue, minZ, container.zLayers));
4188
4469
  if (!initialPosition) {
4189
- throw new Error("a valid position cannot be found for particle");
4470
+ throw new Error(getErrorMessage(ErrorCodes$1.particlePositionNotFound));
4190
4471
  }
4191
4472
  this.position = initialPosition;
4192
4473
  this.initialPosition = this.position.copy();
@@ -4235,6 +4516,12 @@
4235
4516
  this.#circlePoolIdx = 0;
4236
4517
  this.#rectanglePoolIdx = 0;
4237
4518
  }
4519
+ get cellSize() {
4520
+ return this.#cellSize;
4521
+ }
4522
+ set cellSize(value) {
4523
+ this.#pendingCellSize = value;
4524
+ }
4238
4525
  clear() {
4239
4526
  this.#cells.clear();
4240
4527
  const pendingCellSize = this.#pendingCellSize;
@@ -4258,18 +4545,7 @@
4258
4545
  const minCellX = Math.floor(bounds.minX / this.#cellSize), maxCellX = Math.floor(bounds.maxX / this.#cellSize), minCellY = Math.floor(bounds.minY / this.#cellSize), maxCellY = Math.floor(bounds.maxY / this.#cellSize);
4259
4546
  for (let cx = minCellX; cx <= maxCellX; cx++) {
4260
4547
  for (let cy = minCellY; cy <= maxCellY; cy++) {
4261
- const key = `${cx}_${cy}`, cellParticles = this.#cells.get(key);
4262
- if (!cellParticles) {
4263
- continue;
4264
- }
4265
- for (const p of cellParticles) {
4266
- if (check && !check(p)) {
4267
- continue;
4268
- }
4269
- if (range.contains(p.getPosition())) {
4270
- out.push(p);
4271
- }
4272
- }
4548
+ this.#queryCell(cx, cy, range, check, out);
4273
4549
  }
4274
4550
  }
4275
4551
  return out;
@@ -4284,14 +4560,23 @@
4284
4560
  this.#releaseShapes();
4285
4561
  return result;
4286
4562
  }
4287
- setCellSize(cellSize) {
4288
- this.#pendingCellSize = cellSize;
4289
- }
4290
4563
  #acquireCircle(x, y, r) {
4291
- return (this.#circlePool[this.#circlePoolIdx++] ??= new Circle(x, y, r)).reset(x, y, r);
4564
+ const idx = this.#circlePoolIdx++;
4565
+ let circle = this.#circlePool[idx];
4566
+ if (!circle) {
4567
+ circle = new Circle(x, y, r);
4568
+ this.#circlePool[idx] = circle;
4569
+ }
4570
+ return circle.reset(x, y, r);
4292
4571
  }
4293
4572
  #acquireRectangle(x, y, w, h) {
4294
- return (this.#rectanglePool[this.#rectanglePoolIdx++] ??= new Rectangle(x, y, w, h)).reset(x, y, w, h);
4573
+ const idx = this.#rectanglePoolIdx++;
4574
+ let rectangle = this.#rectanglePool[idx];
4575
+ if (!rectangle) {
4576
+ rectangle = new Rectangle(x, y, w, h);
4577
+ this.#rectanglePool[idx] = rectangle;
4578
+ }
4579
+ return rectangle.reset(x, y, w, h);
4295
4580
  }
4296
4581
  #cellKeyFromCoords(x, y) {
4297
4582
  const cellX = Math.floor(x / this.#cellSize), cellY = Math.floor(y / this.#cellSize);
@@ -4318,6 +4603,20 @@
4318
4603
  }
4319
4604
  return null;
4320
4605
  }
4606
+ #queryCell(cx, cy, range, check, out) {
4607
+ const cellParticles = this.#cells.get(`${cx}_${cy}`);
4608
+ if (!cellParticles) {
4609
+ return;
4610
+ }
4611
+ for (const p of cellParticles) {
4612
+ if (check && !check(p)) {
4613
+ continue;
4614
+ }
4615
+ if (range.contains(p.getPosition())) {
4616
+ out.push(p);
4617
+ }
4618
+ }
4619
+ }
4321
4620
  #releaseShapes() {
4322
4621
  this.#circlePoolIdx = 0;
4323
4622
  this.#rectanglePoolIdx = 0;
@@ -4326,9 +4625,9 @@
4326
4625
 
4327
4626
  class ParticlesManager {
4328
4627
  checkParticlePositionPlugins;
4329
- grid;
4330
4628
  #array;
4331
4629
  #container;
4630
+ #grid;
4332
4631
  #groupLimits;
4333
4632
  #limit;
4334
4633
  #nextId;
@@ -4352,7 +4651,7 @@
4352
4651
  this.#groupLimits = new Map();
4353
4652
  this.#particleBuckets = new Map();
4354
4653
  this.#zBuckets = this.#createBuckets(this.#container.zLayers);
4355
- this.grid = new SpatialHashGrid(spatialHashGridCellSize);
4654
+ this.#grid = new SpatialHashGrid(spatialHashGridCellSize);
4356
4655
  this.checkParticlePositionPlugins = [];
4357
4656
  this.#particleResetPlugins = [];
4358
4657
  this.#particleUpdatePlugins = [];
@@ -4363,23 +4662,12 @@
4363
4662
  get count() {
4364
4663
  return this.#array.length;
4365
4664
  }
4665
+ get grid() {
4666
+ return this.#grid;
4667
+ }
4366
4668
  addParticle(position, overrideOptions, group, initializer) {
4367
- const limitMode = this.#container.actualOptions.particles.number.limit.mode, limit = group === undefined ? this.#limit : (this.#groupLimits.get(group) ?? this.#limit), currentCount = this.count;
4368
- if (limit > minLimit) {
4369
- switch (limitMode) {
4370
- case LimitMode.delete: {
4371
- const countToRemove = currentCount + countOffset - limit;
4372
- if (countToRemove > minCount) {
4373
- this.removeQuantity(countToRemove);
4374
- }
4375
- break;
4376
- }
4377
- case LimitMode.wait:
4378
- if (currentCount >= limit) {
4379
- return;
4380
- }
4381
- break;
4382
- }
4669
+ if (this.#checkAndApplyLimits(group, this.count)) {
4670
+ return;
4383
4671
  }
4384
4672
  try {
4385
4673
  const particle = this.#pool.pop() ?? new Particle(this.#pluginManager, this.#container);
@@ -4443,7 +4731,7 @@
4443
4731
  return this.#array[index];
4444
4732
  }
4445
4733
  async init() {
4446
- const container = this.#container, options = container.actualOptions;
4734
+ const container = this.#container;
4447
4735
  this.checkParticlePositionPlugins = [];
4448
4736
  this.#updatePlugins = [];
4449
4737
  this.#particleUpdatePlugins = [];
@@ -4452,59 +4740,16 @@
4452
4740
  this.#postParticleUpdatePlugins = [];
4453
4741
  this.#particleBuckets.clear();
4454
4742
  this.#resetBuckets(container.zLayers);
4455
- this.grid = new SpatialHashGrid(spatialHashGridCellSize * container.retina.pixelRatio);
4456
- for (const plugin of container.plugins) {
4457
- if (plugin.redrawInit) {
4458
- await plugin.redrawInit();
4459
- }
4460
- if (plugin.checkParticlePosition) {
4461
- this.checkParticlePositionPlugins.push(plugin);
4462
- }
4463
- if (plugin.update) {
4464
- this.#updatePlugins.push(plugin);
4465
- }
4466
- if (plugin.particleUpdate) {
4467
- this.#particleUpdatePlugins.push(plugin);
4468
- }
4469
- if (plugin.postUpdate) {
4470
- this.#postUpdatePlugins.push(plugin);
4471
- }
4472
- if (plugin.particleReset) {
4473
- this.#particleResetPlugins.push(plugin);
4474
- }
4475
- if (plugin.postParticleUpdate) {
4476
- this.#postParticleUpdatePlugins.push(plugin);
4477
- }
4478
- }
4479
- await this.#container.initDrawersAndUpdaters();
4480
- for (const drawer of this.#container.effectDrawers.values()) {
4481
- await drawer.init?.(container);
4482
- }
4483
- for (const drawer of this.#container.shapeDrawers.values()) {
4484
- await drawer.init?.(container);
4485
- }
4486
- let handled = false;
4487
- for (const plugin of container.plugins) {
4488
- handled = plugin.particlesInitialization?.() ?? handled;
4489
- if (handled) {
4490
- break;
4491
- }
4492
- }
4493
- if (!handled) {
4494
- const particlesOptions = options.particles, groups = particlesOptions.groups;
4495
- for (const group in groups) {
4496
- const groupOptions = groups[group];
4497
- if (!groupOptions) {
4498
- continue;
4499
- }
4500
- for (let i = this.count, j = 0; j < groupOptions.number.value && i < particlesOptions.number.value; i++, j++) {
4501
- this.addParticle(undefined, groupOptions, group);
4502
- }
4503
- }
4504
- for (let i = this.count; i < particlesOptions.number.value; i++) {
4505
- this.addParticle();
4743
+ this.#grid = new SpatialHashGrid(spatialHashGridCellSize * container.retina.pixelRatio);
4744
+ this.#applyLimits(container.actualOptions.particles);
4745
+ const particlesOptions = container.actualOptions.particles, groups = particlesOptions.groups;
4746
+ for (const group in groups) {
4747
+ const groupData = groups[group];
4748
+ if (groupData) {
4749
+ this.#applyLimits(loadParticlesOptions(this.#pluginManager, this.#container, groupData), group, groupData);
4506
4750
  }
4507
4751
  }
4752
+ await this.#initPlugins();
4508
4753
  }
4509
4754
  push(nb, position, overrideOptions, group) {
4510
4755
  for (let i = 0; i < nb; i++) {
@@ -4519,13 +4764,13 @@
4519
4764
  remove(particle, group, override) {
4520
4765
  this.removeAt(this.#array.indexOf(particle), undefined, group, override);
4521
4766
  }
4522
- removeAt(index, quantity = defaultRemoveQuantity, group, override) {
4767
+ removeAt(index, quantity = defaultRemoveQuantity, group, override, matchGroup = true) {
4523
4768
  if (index < minIndex || index > this.count) {
4524
4769
  return;
4525
4770
  }
4526
4771
  let deleted = 0;
4527
4772
  for (let i = index; deleted < quantity && i < this.count; i++) {
4528
- if (this.#removeParticle(i, group, override)) {
4773
+ if (this.#removeParticle(i, group, override, matchGroup)) {
4529
4774
  i--;
4530
4775
  deleted++;
4531
4776
  }
@@ -4556,7 +4801,7 @@
4556
4801
  this.#resizeFactor = factor;
4557
4802
  }
4558
4803
  update(delta) {
4559
- this.grid.clear();
4804
+ this.#grid.clear();
4560
4805
  for (const plugin of this.#updatePlugins) {
4561
4806
  plugin.update?.(delta);
4562
4807
  }
@@ -4567,7 +4812,7 @@
4567
4812
  this.#updateParticlesPhase2(delta, particlesToDelete);
4568
4813
  if (particlesToDelete.size) {
4569
4814
  for (const particle of particlesToDelete) {
4570
- this.remove(particle);
4815
+ this.remove(particle, particle.group);
4571
4816
  }
4572
4817
  }
4573
4818
  this.#resizeFactor = undefined;
@@ -4578,12 +4823,7 @@
4578
4823
  #applyDensity(options, pluginsCount, group, groupOptions) {
4579
4824
  const numberOptions = options.number;
4580
4825
  if (!numberOptions.density.enable) {
4581
- if (group === undefined) {
4582
- this.#limit = numberOptions.limit.value;
4583
- }
4584
- else if (groupOptions?.number.limit.value ?? numberOptions.limit.value) {
4585
- this.#groupLimits.set(group, groupOptions?.number.limit.value ?? numberOptions.limit.value);
4586
- }
4826
+ this.#applyLimits(options, group, groupOptions);
4587
4827
  return;
4588
4828
  }
4589
4829
  const densityFactor = this.#initDensityFactor(numberOptions.density), optParticlesNumber = numberOptions.value, optParticlesLimit = numberOptions.limit.value > minLimit ? numberOptions.limit.value : optParticlesNumber, particlesNumber = Math.min(optParticlesNumber, optParticlesLimit) * densityFactor + pluginsCount, particlesCount = Math.min(this.count, this.filter(t => t.group === group).length);
@@ -4591,7 +4831,10 @@
4591
4831
  this.#limit = numberOptions.limit.value * densityFactor;
4592
4832
  }
4593
4833
  else {
4594
- this.#groupLimits.set(group, numberOptions.limit.value * densityFactor);
4834
+ this.#groupLimits.set(group, {
4835
+ limit: numberOptions.limit.value * densityFactor,
4836
+ mode: toEnumValue(LimitMode, numberOptions.limit.mode, LimitMode.delete),
4837
+ });
4595
4838
  }
4596
4839
  if (particlesCount < particlesNumber) {
4597
4840
  this.push(Math.abs(particlesNumber - particlesCount), undefined, options, group);
@@ -4600,6 +4843,55 @@
4600
4843
  this.removeQuantity(particlesCount - particlesNumber, group);
4601
4844
  }
4602
4845
  }
4846
+ #applyLimits(options, group, groupOptions) {
4847
+ if (group === undefined) {
4848
+ this.#limit = options.number.limit.value;
4849
+ const groups = this.#container.actualOptions.particles.groups;
4850
+ for (const existingGroup of this.#groupLimits.keys()) {
4851
+ if (!(existingGroup in groups)) {
4852
+ this.#groupLimits.delete(existingGroup);
4853
+ }
4854
+ }
4855
+ }
4856
+ else {
4857
+ const limitValue = groupOptions?.number?.limit?.value ?? options.number.limit.value;
4858
+ if (limitValue > minLimit) {
4859
+ this.#groupLimits.set(group, {
4860
+ limit: limitValue,
4861
+ mode: toEnumValue(LimitMode, groupOptions?.number?.limit?.mode ?? options.number.limit.mode, LimitMode.delete),
4862
+ });
4863
+ }
4864
+ else {
4865
+ this.#groupLimits.delete(group);
4866
+ }
4867
+ }
4868
+ }
4869
+ #checkAndApplyLimits(group, currentCount) {
4870
+ const globalLimit = this.#limit, globalMode = this.#container.actualOptions.particles.number.limit.mode;
4871
+ if (globalLimit > minLimit && globalMode === LimitMode.wait && currentCount >= globalLimit) {
4872
+ return true;
4873
+ }
4874
+ const groupLimitEntry = group === undefined ? undefined : this.#groupLimits.get(group);
4875
+ if (groupLimitEntry && groupLimitEntry.limit > minLimit && groupLimitEntry.mode === LimitMode.wait) {
4876
+ const groupCount = this.filter(t => t.group === group).length;
4877
+ if (groupCount >= groupLimitEntry.limit) {
4878
+ return true;
4879
+ }
4880
+ }
4881
+ if (groupLimitEntry && groupLimitEntry.limit > minLimit && groupLimitEntry.mode === LimitMode.delete) {
4882
+ const groupCountToRemove = this.filter(t => t.group === group).length + countOffset - groupLimitEntry.limit;
4883
+ if (groupCountToRemove > minCount) {
4884
+ this.removeQuantity(groupCountToRemove, group);
4885
+ }
4886
+ }
4887
+ if (globalLimit > minLimit && globalMode === LimitMode.delete) {
4888
+ const globalCountToRemove = this.count + countOffset - globalLimit;
4889
+ if (globalCountToRemove > minCount) {
4890
+ this.#removeAny(globalCountToRemove);
4891
+ }
4892
+ }
4893
+ return false;
4894
+ }
4603
4895
  #createBuckets(zLayers) {
4604
4896
  const bucketCount = Math.max(Math.floor(zLayers), one);
4605
4897
  return Array.from({ length: bucketCount }, () => []);
@@ -4622,6 +4914,70 @@
4622
4914
  }
4623
4915
  return ((canvasSize.width * canvasSize.height) / (densityOptions.height * densityOptions.width * pxRatio ** squareExp));
4624
4916
  }
4917
+ async #initDrawersAndUpdaters() {
4918
+ const container = this.#container;
4919
+ await container.initDrawersAndUpdaters();
4920
+ for (const drawer of container.effectDrawers.values()) {
4921
+ await drawer.init?.(container);
4922
+ }
4923
+ for (const drawer of container.shapeDrawers.values()) {
4924
+ await drawer.init?.(container);
4925
+ }
4926
+ }
4927
+ async #initPlugins() {
4928
+ await this.#initPluginsArrays();
4929
+ await this.#initDrawersAndUpdaters();
4930
+ let handled = false;
4931
+ const container = this.#container;
4932
+ for (const plugin of container.plugins) {
4933
+ handled = plugin.particlesInitialization?.() ?? handled;
4934
+ if (handled) {
4935
+ break;
4936
+ }
4937
+ }
4938
+ if (handled) {
4939
+ return;
4940
+ }
4941
+ const particlesOptions = container.actualOptions.particles, groups = particlesOptions.groups;
4942
+ for (const group in groups) {
4943
+ const groupOptions = groups[group];
4944
+ if (!groupOptions) {
4945
+ continue;
4946
+ }
4947
+ for (let i = this.count, j = 0; j < groupOptions.number.value && i < particlesOptions.number.value; i++, j++) {
4948
+ this.addParticle(undefined, groupOptions, group);
4949
+ }
4950
+ }
4951
+ for (let i = this.count; i < particlesOptions.number.value; i++) {
4952
+ this.addParticle();
4953
+ }
4954
+ }
4955
+ async #initPluginsArrays() {
4956
+ const container = this.#container;
4957
+ for (const plugin of container.plugins) {
4958
+ if (plugin.redrawInit) {
4959
+ await plugin.redrawInit();
4960
+ }
4961
+ if (plugin.checkParticlePosition) {
4962
+ this.checkParticlePositionPlugins.push(plugin);
4963
+ }
4964
+ if (plugin.update) {
4965
+ this.#updatePlugins.push(plugin);
4966
+ }
4967
+ if (plugin.particleUpdate) {
4968
+ this.#particleUpdatePlugins.push(plugin);
4969
+ }
4970
+ if (plugin.postUpdate) {
4971
+ this.#postUpdatePlugins.push(plugin);
4972
+ }
4973
+ if (plugin.particleReset) {
4974
+ this.#particleResetPlugins.push(plugin);
4975
+ }
4976
+ if (plugin.postParticleUpdate) {
4977
+ this.#postParticleUpdatePlugins.push(plugin);
4978
+ }
4979
+ }
4980
+ }
4625
4981
  #insertParticleIntoBucket(particle) {
4626
4982
  const bucketIndex = this.#getBucketIndex(particle.position.z), bucket = this.#zBuckets[bucketIndex];
4627
4983
  if (!bucket) {
@@ -4630,12 +4986,15 @@
4630
4986
  bucket.push(particle);
4631
4987
  this.#particleBuckets.set(particle.id, bucketIndex);
4632
4988
  }
4633
- #removeParticle(index, group, override) {
4989
+ #removeAny(quantity) {
4990
+ this.removeAt(minIndex, quantity, undefined, undefined, false);
4991
+ }
4992
+ #removeParticle(index, group, override, matchGroup = true) {
4634
4993
  const particle = this.#array[index];
4635
4994
  if (!particle) {
4636
4995
  return false;
4637
4996
  }
4638
- if (particle.group !== group) {
4997
+ if (matchGroup && particle.group !== group) {
4639
4998
  return false;
4640
4999
  }
4641
5000
  this.#array.splice(index, deleteCount);
@@ -4722,7 +5081,7 @@
4722
5081
  particlesToDelete.add(particle);
4723
5082
  continue;
4724
5083
  }
4725
- this.grid.insert(particle);
5084
+ this.#grid.insert(particle);
4726
5085
  }
4727
5086
  return particlesToDelete;
4728
5087
  }
@@ -4794,6 +5153,7 @@
4794
5153
  effectDrawers;
4795
5154
  fpsLimit;
4796
5155
  hdr;
5156
+ hdrMode;
4797
5157
  id;
4798
5158
  pageHidden;
4799
5159
  particleCreatedPlugins;
@@ -4801,6 +5161,7 @@
4801
5161
  particlePositionPlugins;
4802
5162
  particleUpdaters;
4803
5163
  particles;
5164
+ peakNits;
4804
5165
  plugins;
4805
5166
  retina;
4806
5167
  shapeDrawers;
@@ -4831,6 +5192,8 @@
4831
5192
  this.id = Symbol(id);
4832
5193
  this.fpsLimit = 120;
4833
5194
  this.hdr = false;
5195
+ this.hdrMode = HdrMode.standard;
5196
+ this.peakNits = 400;
4834
5197
  this.#smooth = false;
4835
5198
  this.#delay = 0;
4836
5199
  this.#duration = 0;
@@ -4894,7 +5257,6 @@
4894
5257
  this.shapeDrawers = new Map();
4895
5258
  this.particleUpdaters = [];
4896
5259
  this.plugins.length = 0;
4897
- this.#pluginManager.clearPlugins(this);
4898
5260
  this.destroyed = true;
4899
5261
  this.#onDestroy(remove);
4900
5262
  this.dispatchEvent(EventType.containerDestroyed);
@@ -4947,31 +5309,15 @@
4947
5309
  await this.initDrawersAndUpdaters();
4948
5310
  this.#options = loadContainerOptions(this.#pluginManager, this, this.#initialSourceOptions, this.sourceOptions);
4949
5311
  this.actualOptions = loadContainerOptions(this.#pluginManager, this, this.#options);
4950
- this.plugins.length = 0;
4951
- this.particleDestroyedPlugins.length = 0;
4952
- this.particleCreatedPlugins.length = 0;
4953
- this.particlePositionPlugins.length = 0;
4954
- for (const [plugin, containerPlugin] of allContainerPlugins) {
4955
- if (plugin.needsPlugin(this.actualOptions)) {
4956
- this.plugins.push(containerPlugin);
4957
- if (containerPlugin.particleCreated) {
4958
- this.particleCreatedPlugins.push(containerPlugin);
4959
- }
4960
- if (containerPlugin.particleDestroyed) {
4961
- this.particleDestroyedPlugins.push(containerPlugin);
4962
- }
4963
- if (containerPlugin.particlePosition) {
4964
- this.particlePositionPlugins.push(containerPlugin);
4965
- }
4966
- }
4967
- }
5312
+ this.#initPlugins(allContainerPlugins);
4968
5313
  this.retina.init();
4969
5314
  this.canvas.init();
4970
5315
  this.updateActualOptions();
4971
5316
  this.canvas.initBackground();
4972
5317
  this.canvas.resize();
4973
- const { delay, duration, fpsLimit, hdr, smooth, zLayers } = this.actualOptions;
4974
- this.hdr = hdr;
5318
+ const { delay, duration, fpsLimit, smooth, zLayers } = this.actualOptions, hdrOptions = this.actualOptions.hdr;
5319
+ this.hdrMode = toEnumValue(HdrMode, hdrOptions.mode, HdrMode.standard);
5320
+ this.peakNits = hdrOptions.peakNits;
4975
5321
  this.zLayers = zLayers;
4976
5322
  this.#duration = getRangeValue(duration) * millisecondsToSeconds;
4977
5323
  this.#delay = getRangeValue(delay) * millisecondsToSeconds;
@@ -4991,9 +5337,9 @@
4991
5337
  }
4992
5338
  async initDrawersAndUpdaters() {
4993
5339
  const pluginManager = this.#pluginManager;
4994
- this.effectDrawers = await pluginManager.getEffectDrawers(this, true);
4995
- this.shapeDrawers = await pluginManager.getShapeDrawers(this, true);
4996
- this.particleUpdaters = await pluginManager.getUpdaters(this, true);
5340
+ this.effectDrawers = await getItemMapFromInitializer(this, pluginManager.initializers.effects);
5341
+ this.shapeDrawers = await getItemMapFromInitializer(this, pluginManager.initializers.shapes);
5342
+ this.particleUpdaters = await getItemsFromInitializer(this, pluginManager.initializers.updaters);
4997
5343
  }
4998
5344
  pause() {
4999
5345
  if (!guardCheck(this)) {
@@ -5104,6 +5450,27 @@
5104
5450
  }
5105
5451
  return refresh;
5106
5452
  }
5453
+ #initPlugins(allContainerPlugins) {
5454
+ this.plugins.length = 0;
5455
+ this.particleDestroyedPlugins.length = 0;
5456
+ this.particleCreatedPlugins.length = 0;
5457
+ this.particlePositionPlugins.length = 0;
5458
+ for (const [plugin, containerPlugin] of allContainerPlugins) {
5459
+ if (!plugin.needsPlugin(this.actualOptions)) {
5460
+ continue;
5461
+ }
5462
+ this.plugins.push(containerPlugin);
5463
+ if (containerPlugin.particleCreated) {
5464
+ this.particleCreatedPlugins.push(containerPlugin);
5465
+ }
5466
+ if (containerPlugin.particleDestroyed) {
5467
+ this.particleDestroyedPlugins.push(containerPlugin);
5468
+ }
5469
+ if (containerPlugin.particlePosition) {
5470
+ this.particlePositionPlugins.push(containerPlugin);
5471
+ }
5472
+ }
5473
+ }
5107
5474
  #nextFrame(timestamp) {
5108
5475
  try {
5109
5476
  if (!this.#smooth &&
@@ -5148,6 +5515,11 @@
5148
5515
  this.#container = container;
5149
5516
  this.#instancesManager.initContainer(container);
5150
5517
  }
5518
+ draw(context, _delta) {
5519
+ for (const emitter of this.#instancesManager.getArray(this.#container)) {
5520
+ emitter.draw(context);
5521
+ }
5522
+ }
5151
5523
  async init() {
5152
5524
  const emittersOptions = this.#container.actualOptions.emitters;
5153
5525
  if (isArray(emittersOptions)) {
@@ -5218,14 +5590,21 @@
5218
5590
  this.#pluginManager = pluginManager;
5219
5591
  }
5220
5592
  async addEmitter(container, options, position) {
5221
- const emitterOptions = new Emitter();
5222
- emitterOptions.load(options);
5223
- const { EmitterInstance } = await Promise.resolve().then(function () { return EmitterInstance$1; }), emitter = new EmitterInstance(this.#pluginManager, container, (emitter) => {
5224
- this.removeEmitter(container, emitter);
5225
- }, emitterOptions, position);
5226
- await emitter.init();
5227
- this.getArray(container).push(emitter);
5228
- return emitter;
5593
+ return this.addEmitters(container, [{ options, position }]).then(t => t[defaultIndex]);
5594
+ }
5595
+ async addEmitters(container, emitters) {
5596
+ const { EmitterInstance } = await Promise.resolve().then(function () { return EmitterInstance$1; }), res = [];
5597
+ for (const { options, position } of emitters) {
5598
+ const emitterOptions = new Emitter();
5599
+ emitterOptions.load(options);
5600
+ const emitter = new EmitterInstance(this.#pluginManager, container, (emitter) => {
5601
+ this.removeEmitter(container, emitter);
5602
+ }, emitterOptions, position);
5603
+ await emitter.init();
5604
+ this.getArray(container).push(emitter);
5605
+ res.push(emitter);
5606
+ }
5607
+ return res;
5229
5608
  }
5230
5609
  clear(container) {
5231
5610
  this.initContainer(container);
@@ -5252,6 +5631,7 @@
5252
5631
  : array.find(t => t.name === idxOrName);
5253
5632
  };
5254
5633
  container.addEmitter = async (options, position) => this.addEmitter(container, options, position);
5634
+ container.addEmitters = async (emitters) => this.addEmitters(container, emitters);
5255
5635
  container.removeEmitter = (idxOrName) => {
5256
5636
  const emitter = container.getEmitter?.(idxOrName);
5257
5637
  if (emitter) {
@@ -5272,7 +5652,7 @@
5272
5652
  };
5273
5653
  }
5274
5654
  removeEmitter(container, emitter) {
5275
- const index = this.getArray(container).indexOf(emitter), minIndex = 0, deleteCount = 1;
5655
+ const index = this.getArray(container).indexOf(emitter), deleteCount = 1;
5276
5656
  if (index >= minIndex) {
5277
5657
  this.getArray(container).splice(index, deleteCount);
5278
5658
  }
@@ -5327,6 +5707,7 @@
5327
5707
  #particlesOptions;
5328
5708
  #paused;
5329
5709
  #pluginManager;
5710
+ #positionOverride = false;
5330
5711
  #removeCallback;
5331
5712
  #resizeObserver;
5332
5713
  #shape;
@@ -5403,6 +5784,31 @@
5403
5784
  });
5404
5785
  this.play();
5405
5786
  }
5787
+ draw(context) {
5788
+ if (!this.options.draw || !this.#shape) {
5789
+ return;
5790
+ }
5791
+ const container = this.#container, fillEnabled = this.options.spawn.fill?.enable ?? true;
5792
+ context.save();
5793
+ context.beginPath();
5794
+ if (fillEnabled) {
5795
+ context.fillStyle = this.spawnFillColor
5796
+ ? getStyleFromHsl(this.spawnFillColor, container.hdr, this.spawnFillOpacity ?? defaultOpacity$1, container.peakNits, container.hdrMode)
5797
+ : getStyleFromRgb({ r: 0, g: 0, b: 0 }, container.hdr, defaultOpacity$1, container.peakNits, container.hdrMode);
5798
+ }
5799
+ if (this.spawnStrokeColor) {
5800
+ context.strokeStyle = getStyleFromHsl(this.spawnStrokeColor, container.hdr, this.spawnStrokeOpacity ?? defaultOpacity$1, container.peakNits, container.hdrMode);
5801
+ context.lineWidth = this.spawnStrokeWidth ?? defaultStrokeWidth;
5802
+ }
5803
+ this.#shape.draw?.(context);
5804
+ if (fillEnabled) {
5805
+ context.fill();
5806
+ }
5807
+ if (this.spawnStrokeColor) {
5808
+ context.stroke();
5809
+ }
5810
+ context.restore();
5811
+ }
5406
5812
  externalPause() {
5407
5813
  this.#paused = true;
5408
5814
  this.pause();
@@ -5440,11 +5846,14 @@
5440
5846
  }
5441
5847
  }
5442
5848
  resize() {
5443
- const initialPosition = this.#initialPosition, container = this.#container;
5444
- this.position =
5445
- initialPosition && isPointInside(initialPosition, container.canvas.size, Vector.origin)
5446
- ? initialPosition
5447
- : this.#calcPosition();
5849
+ const container = this.#container;
5850
+ if (!this.#positionOverride) {
5851
+ const initialPosition = this.#initialPosition;
5852
+ this.position =
5853
+ initialPosition && isPointInside(initialPosition, container.canvas.size, Vector.origin)
5854
+ ? initialPosition
5855
+ : this.#calcPosition();
5856
+ }
5448
5857
  this.#size = this.#calcSize();
5449
5858
  this.size =
5450
5859
  this.#size.mode === PixelMode.percent
@@ -5455,6 +5864,11 @@
5455
5864
  : { width: this.#size.width, height: this.#size.height };
5456
5865
  this.#shape?.resize(this.position, this.size);
5457
5866
  }
5867
+ setPosition(position) {
5868
+ this.#positionOverride = true;
5869
+ this.position = { ...position };
5870
+ this.#shape?.resize(this.position, this.size);
5871
+ }
5458
5872
  update(delta) {
5459
5873
  if (this.#paused) {
5460
5874
  return;
@@ -5650,6 +6064,7 @@
5650
6064
  exports.loadSquaresPreset = loadSquaresPreset;
5651
6065
  exports.tsParticles = tsParticles;
5652
6066
 
5653
- }));
6067
+ })(g.__tsParticlesInternals.presets.squares = g.__tsParticlesInternals.presets.squares || {});
6068
+ })(typeof globalThis !== "undefined" ? globalThis : typeof window !== "undefined" ? window : self);
6069
+
5654
6070
  Object.assign(globalThis.window || globalThis, { loadSquaresPreset: (globalThis.__tsParticlesInternals.presets.squares || {}).loadSquaresPreset });
5655
- delete (globalThis.window || globalThis).tsparticlesInternalExports;