@tsparticles/preset-bubbles 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.bubbles = global.__tsParticlesInternals.presets.bubbles || {})));
7
- })(this, (function (exports) { 'use strict';
8
-
9
- const generatedAttribute = "generated", defaultCompositeValue = "source-over", resizeEvent = "resize", visibilityChangeEvent = "visibilitychange", percentDenominator = 100, half = 0.5, millisecondsToSeconds = 1000, originPoint = {
10
- x: 0,
11
- y: 0,
12
- z: 0,
13
- }, defaultTransform = {
14
- a: 1,
15
- b: 0,
16
- c: 0,
17
- d: 1,
18
- }, randomColorValue = "random", double = 2, doublePI = Math.PI * double, defaultFps = 60, generatedTrue = "true", generatedFalse = "false", canvasTag = "canvas", defaultRetryCount = 0, squareExp = 2, spatialHashGridCellSize = 100, defaultRemoveQuantity = 1, defaultRatio = 1, defaultReduceFactor = 1, inverseFactorNumerator = 1, rgbMax = 255, hMax = 360, sMax = 100, lMax = 100, hMin = 0, sMin = 0, hPhase = 60, empty = 0, quarter = 0.25, threeQuarter = half + quarter, minVelocity = 0, minDistance = 0, defaultTransformValue = 1, minimumSize = 0, zIndexFactorOffset = 1, defaultOpacity$1 = 1, removeDeleteCount = 1, removeMinIndex = 0, defaultFpsLimit = 120, minFpsLimit = 0, canvasFirstIndex = 0, loadRandomFactor = 10000, loadMinIndex = 0, one = 1, none = 0, decayOffset = 1, tryCountIncrement = 1, minZ = 0, minLimit = 0, countOffset = 1, minCount = 0, minIndex = 0, defaultDensityFactor = 1, deleteCount = 1, defaultAngle = 0, identity = 1, minStrokeWidth = 0, lFactor = 1, lMin = 0, maxNits = 400, triple = 3, sextuple = 6, sNormalizedOffset = 1, phaseNumerator = 1, defaultRgbMin = 0, defaultVelocity = 0, defaultLoops = 0, defaultTime = 0, defaultZoom = 1;
1
+ (function(g){g.__tsParticlesInternals=g.__tsParticlesInternals||{};g.__tsParticlesInternals.bundles=g.__tsParticlesInternals.bundles||{};g.__tsParticlesInternals.effects=g.__tsParticlesInternals.effects||{};g.__tsParticlesInternals.engine=g.__tsParticlesInternals.engine||{};g.__tsParticlesInternals.interactions=g.__tsParticlesInternals.interactions||{};g.__tsParticlesInternals.palettes=g.__tsParticlesInternals.palettes||{};g.__tsParticlesInternals.paths=g.__tsParticlesInternals.paths||{};g.__tsParticlesInternals.plugins=g.__tsParticlesInternals.plugins||{};g.__tsParticlesInternals.plugins=g.__tsParticlesInternals.plugins||{};g.__tsParticlesInternals.plugins.emittersShapes=g.__tsParticlesInternals.plugins.emittersShapes||{};g.__tsParticlesInternals.presets=g.__tsParticlesInternals.presets||{};g.__tsParticlesInternals.shapes=g.__tsParticlesInternals.shapes||{};g.__tsParticlesInternals.updaters=g.__tsParticlesInternals.updaters||{};g.__tsParticlesInternals.utils=g.__tsParticlesInternals.utils||{};g.__tsParticlesInternals.canvas=g.__tsParticlesInternals.canvas||{};g.__tsParticlesInternals.canvas=g.__tsParticlesInternals.canvas||{};g.__tsParticlesInternals.canvas.utils=g.__tsParticlesInternals.canvas.utils||{};g.__tsParticlesInternals.path=g.__tsParticlesInternals.path||{};g.__tsParticlesInternals.path=g.__tsParticlesInternals.path||{};g.__tsParticlesInternals.path.utils=g.__tsParticlesInternals.path.utils||{};var __tsProxyFactory=typeof Proxy!=="undefined"?function(obj){return new Proxy(obj,{get:function(target,key){if(!(key in target)){target[key]={};}return target[key];}});}:function(obj){return obj;};g.__tsParticlesInternals.bundles=__tsProxyFactory(g.__tsParticlesInternals.bundles);g.__tsParticlesInternals.effects=__tsProxyFactory(g.__tsParticlesInternals.effects);g.__tsParticlesInternals.interactions=__tsProxyFactory(g.__tsParticlesInternals.interactions);g.__tsParticlesInternals.palettes=__tsProxyFactory(g.__tsParticlesInternals.palettes);g.__tsParticlesInternals.paths=__tsProxyFactory(g.__tsParticlesInternals.paths);g.__tsParticlesInternals.plugins=__tsProxyFactory(g.__tsParticlesInternals.plugins);g.__tsParticlesInternals.plugins.emittersShapes=__tsProxyFactory(g.__tsParticlesInternals.plugins.emittersShapes);g.__tsParticlesInternals.presets=__tsProxyFactory(g.__tsParticlesInternals.presets);g.__tsParticlesInternals.shapes=__tsProxyFactory(g.__tsParticlesInternals.shapes);g.__tsParticlesInternals.updaters=__tsProxyFactory(g.__tsParticlesInternals.updaters);g.__tsParticlesInternals.utils=__tsProxyFactory(g.__tsParticlesInternals.utils);g.__tsParticlesInternals.canvas=__tsProxyFactory(g.__tsParticlesInternals.canvas);g.__tsParticlesInternals.path=__tsProxyFactory(g.__tsParticlesInternals.path);})(typeof globalThis!=="undefined"?globalThis:typeof window!=="undefined"?window:this);
2
+ (function (g) {
3
+ /* Preset v4.5.0 */
4
+ g.__tsParticlesInternals = g.__tsParticlesInternals || {};
5
+ g.__tsParticlesInternals.presets = g.__tsParticlesInternals.presets || {};
6
+ (function (exports) {
7
+ 'use strict';
8
+
9
+ const errorPrefix = "tsParticles - Error", codedErrorPattern = /^\[tsParticles Error (TSP-\d+)\]\s*/, fullMatchIndex = 0, codeIndex = 1;
10
+ const wrap = (fn) => (...args) => {
11
+ fn(...args);
12
+ }, _logger = {
13
+ debug: wrap(console.debug),
14
+ error: (message, ...optionalParams) => {
15
+ if (typeof message === "string") {
16
+ const match = codedErrorPattern.exec(message);
17
+ if (match?.[codeIndex]) {
18
+ console.error(`tsParticles - ${match[codeIndex]} - ${message.slice(match[fullMatchIndex].length)}`, ...optionalParams);
19
+ return;
20
+ }
21
+ }
22
+ console.error(`${errorPrefix} - ${message}`, ...optionalParams);
23
+ },
24
+ info: wrap(console.info),
25
+ log: wrap(console.log),
26
+ trace: wrap(console.trace),
27
+ verbose: wrap(console.log),
28
+ warning: wrap(console.warn),
29
+ };
30
+ function getLogger() {
31
+ return _logger;
32
+ }
19
33
 
20
34
  var MoveDirection;
21
35
  (function (MoveDirection) {
@@ -32,6 +46,17 @@
32
46
  MoveDirection["inside"] = "inside";
33
47
  })(MoveDirection || (MoveDirection = {}));
34
48
 
49
+ const generatedAttribute = "generated", fullPercent = "100%", defaultCompositeValue = "source-over", resizeEvent = "resize", visibilityChangeEvent = "visibilitychange", percentDenominator = 100, half = 0.5, millisecondsToSeconds = 1000, originPoint = {
50
+ x: 0,
51
+ y: 0,
52
+ z: 0,
53
+ }, defaultTransform = {
54
+ a: 1,
55
+ b: 0,
56
+ c: 0,
57
+ d: 1,
58
+ }, randomColorValue = "random", double = 2, doublePI = Math.PI * double, defaultFps = 60, defaultAlpha = 1, generatedTrue = "true", generatedFalse = "false", canvasTag = "canvas", defaultRetryCount = 0, squareExp = 2, spatialHashGridCellSize = 100, defaultRemoveQuantity = 1, defaultRatio = 1, defaultReduceFactor = 1, inverseFactorNumerator = 1, rgbMax = 255, hMax = 360, sMax = 100, lMax = 100, hMin = 0, sMin = 0, hPhase = 60, empty = 0, quarter = 0.25, threeQuarter = half + quarter, minVelocity = 0, minDistance = 0, minRadius = 0, defaultTransformValue = 1, minimumSize = 0, zIndexFactorOffset = 1, defaultOpacity$1 = 1, removeDeleteCount = 1, removeMinIndex = 0, defaultFpsLimit = 120, minFpsLimit = 0, canvasFirstIndex = 0, loadRandomFactor = 10000, loadMinIndex = 0, one = 1, none = 0, decayOffset = 1, tryCountIncrement = 1, minZ = 0, minLimit = 0, countOffset = 1, minCount = 0, minIndex = 0, defaultDensityFactor = 1, deleteCount = 1, defaultAngle = 0, identity = 1, minStrokeWidth = 0, lFactor = 1, lMin = 0, maxNits = 400, triple = 3, sextuple = 6, sNormalizedOffset = 1, phaseNumerator = 1, defaultRgbMin = 0, defaultVelocity = 0, defaultLoops = 0, defaultTime = 0, defaultZoom = 1;
59
+
35
60
  function getZ(source) {
36
61
  return "z" in source ? source.z : originPoint.z;
37
62
  }
@@ -147,6 +172,12 @@
147
172
  function isNumber(arg) {
148
173
  return typeof arg === "number";
149
174
  }
175
+ function isEnumValue(enumObject, arg) {
176
+ return Object.values(enumObject).some(enumValue => enumValue === arg);
177
+ }
178
+ function toEnumValue(enumObject, arg, defaultValue) {
179
+ return isEnumValue(enumObject, arg) ? arg : defaultValue;
180
+ }
150
181
  function isObject(arg) {
151
182
  return typeof arg === "object" && arg !== null;
152
183
  }
@@ -283,11 +314,61 @@
283
314
  };
284
315
  }
285
316
  function parseAlpha(input) {
286
- const defaultAlpha = 1;
287
317
  if (!input) {
288
318
  return defaultAlpha;
289
319
  }
290
- return input.endsWith("%") ? parseFloat(input) / percentDenominator : parseFloat(input);
320
+ return input.endsWith("%") ? Number.parseFloat(input) / percentDenominator : Number.parseFloat(input);
321
+ }
322
+
323
+ const ErrorCodes$2 = {
324
+ engineVersionMismatch: "TSP-1001",
325
+ particlePositionNotFound: "TSP-1002",
326
+ pluginRegisterAfterLoad: "TSP-1003",
327
+ offscreenCanvasUnsupported: "TSP-1101",
328
+ offscreenCanvasTransferFailed: "TSP-1102",
329
+ hdrEnableInvalid: "TSP-1201",
330
+ hdrModeInvalid: "TSP-1202",
331
+ hdrPeakNitsInvalid: "TSP-1203",
332
+ };
333
+
334
+ const messages = {
335
+ [ErrorCodes$2.engineVersionMismatch]: "The tsParticles version is different from the loaded plugins version. Engine version: {0}. Plugin version: {1}",
336
+ [ErrorCodes$2.particlePositionNotFound]: "a valid position cannot be found for particle",
337
+ [ErrorCodes$2.pluginRegisterAfterLoad]: "Register plugins can only be done before calling tsParticles.load()",
338
+ [ErrorCodes$2.offscreenCanvasUnsupported]: "OffscreenCanvas is required but not supported by this browser",
339
+ [ErrorCodes$2.offscreenCanvasTransferFailed]: "OffscreenCanvas transfer failed",
340
+ [ErrorCodes$2.hdrEnableInvalid]: 'Invalid HDR "enable" value: expected a boolean, got "{0}"',
341
+ [ErrorCodes$2.hdrModeInvalid]: 'Invalid HDR "mode" value: expected one of {0}, got "{1}"',
342
+ [ErrorCodes$2.hdrPeakNitsInvalid]: 'Invalid HDR "peakNits" value: expected a positive number, got "{0}"',
343
+ };
344
+
345
+ let registeredMessages;
346
+ const ensureRegisteredMessages = () => {
347
+ registeredMessages ??= new Map(Object.entries(messages));
348
+ return registeredMessages;
349
+ }, toStringValue$1 = (value) => String(value), format = (template, args) => {
350
+ return template.replace(/\{(\d+)\}/g, (match, index) => {
351
+ const arg = args[Number(index)];
352
+ return arg === undefined ? match : toStringValue$1(arg);
353
+ });
354
+ };
355
+ function addErrorMessages(extraMessages) {
356
+ if (typeof process !== "undefined" && process.env.NODE_ENV === "production") {
357
+ return;
358
+ }
359
+ const catalog = ensureRegisteredMessages();
360
+ for (const [code, message] of Object.entries(extraMessages)) {
361
+ if (message !== undefined) {
362
+ catalog.set(code, message);
363
+ }
364
+ }
365
+ }
366
+ function getErrorMessage(code, ...args) {
367
+ if (typeof process !== "undefined" && process.env.NODE_ENV === "production") {
368
+ return `[tsParticles Error ${code}] https://particles.js.org/errors/#${code}`;
369
+ }
370
+ const template = ensureRegisteredMessages().get(code) ?? `Unknown error code ${code}`;
371
+ return format(template, args);
291
372
  }
292
373
 
293
374
  var OutModeDirection;
@@ -304,7 +385,6 @@
304
385
  PixelMode["percent"] = "percent";
305
386
  })(PixelMode || (PixelMode = {}));
306
387
 
307
- const minRadius = 0;
308
388
  function isForbiddenKey(key) {
309
389
  return key === "__proto__" || key === "constructor" || key === "prototype";
310
390
  }
@@ -500,22 +580,84 @@
500
580
  element.removeEventListener(event, handler, removeOptions);
501
581
  }
502
582
  }
503
- async function getItemsFromInitializer(container, map, initializers, force = false) {
504
- let res = map.get(container);
505
- if (!res || force) {
506
- res = await Promise.all([...initializers.values()].map(t => t(container)));
507
- map.set(container, res);
583
+ async function getItemsFromInitializer(container, initializers) {
584
+ return await Promise.all([...initializers.values()].map(t => t(container)));
585
+ }
586
+ async function getItemMapFromInitializer(container, initializers) {
587
+ const entries = await Promise.all([...initializers.entries()].map(([key, initializer]) => initializer(container).then(item => [key, item])));
588
+ return new Map(entries);
589
+ }
590
+ async function getDataFromUrl(data) {
591
+ const url = itemFromSingleOrMultiple(data.url, data.index);
592
+ if (!url) {
593
+ return data.fallback;
508
594
  }
509
- return res;
595
+ try {
596
+ const response = await fetch(url);
597
+ if (response.ok) {
598
+ const current = (await response.json());
599
+ if (isSourceOptionsValue(current)) {
600
+ return current;
601
+ }
602
+ getLogger().error("invalid configuration data while retrieving config file");
603
+ }
604
+ else {
605
+ getLogger().error(`${response.status.toString()} while retrieving config file`);
606
+ }
607
+ }
608
+ catch (error) {
609
+ getLogger().error(`error while retrieving config file: ${error}`);
610
+ }
611
+ return data.fallback;
510
612
  }
511
- async function getItemMapFromInitializer(container, map, initializers, force = false) {
512
- let res = map.get(container);
513
- if (!res || force) {
514
- const entries = await Promise.all([...initializers.entries()].map(([key, initializer]) => initializer(container).then(item => [key, item])));
515
- res = new Map(entries);
516
- map.set(container, res);
613
+ function isSourceOptionsValue(value) {
614
+ if (isArray(value)) {
615
+ return value.every((entry) => isObject(entry) && !isArray(entry));
517
616
  }
518
- return res;
617
+ return isObject(value) && !isArray(value);
618
+ }
619
+ function getCanvasFromContainer(domContainer) {
620
+ let canvasEl;
621
+ const documentSafe = safeDocument(), isCanvas = domContainer instanceof HTMLCanvasElement || domContainer.tagName.toLowerCase() === canvasTag;
622
+ if (isCanvas) {
623
+ canvasEl = domContainer;
624
+ canvasEl.dataset[generatedAttribute] ??= generatedFalse;
625
+ if (canvasEl.dataset[generatedAttribute] === generatedTrue) {
626
+ canvasEl.style.width ||= fullPercent;
627
+ canvasEl.style.height ||= fullPercent;
628
+ canvasEl.style.pointerEvents = "none";
629
+ canvasEl.style.setProperty("pointer-events", "none");
630
+ }
631
+ }
632
+ else {
633
+ const existingCanvases = domContainer.getElementsByTagName(canvasTag), foundCanvas = existingCanvases.item(canvasFirstIndex);
634
+ if (foundCanvas) {
635
+ canvasEl = foundCanvas;
636
+ canvasEl.dataset[generatedAttribute] = generatedFalse;
637
+ }
638
+ else {
639
+ canvasEl = documentSafe.createElement(canvasTag);
640
+ canvasEl.dataset[generatedAttribute] = generatedTrue;
641
+ domContainer.appendChild(canvasEl);
642
+ }
643
+ canvasEl.style.width ||= fullPercent;
644
+ canvasEl.style.height ||= fullPercent;
645
+ canvasEl.style.pointerEvents = "none";
646
+ canvasEl.style.setProperty("pointer-events", "none");
647
+ }
648
+ return canvasEl;
649
+ }
650
+ function getDomContainer(id, source) {
651
+ const documentSafe = safeDocument();
652
+ let domContainer = source ?? documentSafe.getElementById(id);
653
+ if (domContainer) {
654
+ return domContainer;
655
+ }
656
+ domContainer = documentSafe.createElement("canvas");
657
+ domContainer.id = id;
658
+ domContainer.dataset[generatedAttribute] = generatedTrue;
659
+ documentSafe.body.append(domContainer);
660
+ return domContainer;
519
661
  }
520
662
 
521
663
  class EventDispatcher {
@@ -586,7 +728,6 @@
586
728
  class PluginManager {
587
729
  colorManagers = new Map();
588
730
  easingFunctions = new Map();
589
- effectDrawers = new Map();
590
731
  initializers = {
591
732
  effects: new Map(),
592
733
  shapes: new Map(),
@@ -595,8 +736,6 @@
595
736
  palettes = new Map();
596
737
  plugins = [];
597
738
  presets = new Map();
598
- shapeDrawers = new Map();
599
- updaters = new Map();
600
739
  #allLoadersSet = new Set();
601
740
  #configs = new Map();
602
741
  #engine;
@@ -614,57 +753,79 @@
614
753
  }
615
754
  return res;
616
755
  }
756
+ get initialized() {
757
+ return this.#initialized;
758
+ }
617
759
  addColorManager(name, manager) {
760
+ if (this.#initialized) {
761
+ return;
762
+ }
618
763
  this.colorManagers.set(name, manager);
619
764
  }
620
765
  addConfig(config) {
766
+ if (this.#initialized) {
767
+ return;
768
+ }
621
769
  const key = config.key ?? config.name ?? "default";
622
770
  this.#configs.set(key, config);
623
771
  this.#engine.dispatchEvent(EventType.configAdded, { data: { name: key, config } });
624
772
  }
625
773
  addEasing(name, easing) {
774
+ if (this.#initialized) {
775
+ return;
776
+ }
626
777
  if (this.easingFunctions.get(name)) {
627
778
  return;
628
779
  }
629
780
  this.easingFunctions.set(name, easing);
630
781
  }
631
782
  addEffect(effect, drawer) {
783
+ if (this.#initialized) {
784
+ return;
785
+ }
632
786
  this.initializers.effects.set(effect, drawer);
633
787
  }
634
788
  addPalette(name, palette) {
789
+ if (this.#initialized) {
790
+ return;
791
+ }
635
792
  this.palettes.set(name, palette);
636
793
  }
637
794
  addParticleUpdater(name, updaterInitializer) {
795
+ if (this.#initialized) {
796
+ return;
797
+ }
638
798
  this.initializers.updaters.set(name, updaterInitializer);
639
799
  }
640
800
  addPlugin(plugin) {
801
+ if (this.#initialized) {
802
+ return;
803
+ }
641
804
  if (this.getPlugin(plugin.id)) {
642
805
  return;
643
806
  }
644
807
  this.plugins.push(plugin);
645
808
  }
646
809
  addPreset(preset, options, override = false) {
810
+ if (this.#initialized) {
811
+ return;
812
+ }
647
813
  if (!(override || !this.getPreset(preset))) {
648
814
  return;
649
815
  }
650
816
  this.presets.set(preset, options);
651
817
  }
652
818
  addShape(shapes, drawer) {
819
+ if (this.#initialized) {
820
+ return;
821
+ }
653
822
  for (const shape of shapes) {
654
823
  this.initializers.shapes.set(shape, drawer);
655
824
  }
656
825
  }
657
- clearPlugins(container) {
658
- this.effectDrawers.delete(container);
659
- this.shapeDrawers.delete(container);
660
- this.updaters.delete(container);
661
- }
662
826
  getEasing(name) {
663
827
  return this.easingFunctions.get(name) ?? ((value) => value);
664
828
  }
665
- getEffectDrawers(container, force = false) {
666
- return getItemMapFromInitializer(container, this.effectDrawers, this.initializers.effects, force);
667
- }
668
829
  getPalette(name) {
669
830
  return this.palettes.get(name);
670
831
  }
@@ -674,12 +835,6 @@
674
835
  getPreset(preset) {
675
836
  return this.presets.get(preset);
676
837
  }
677
- async getShapeDrawers(container, force = false) {
678
- return getItemMapFromInitializer(container, this.shapeDrawers, this.initializers.shapes, force);
679
- }
680
- async getUpdaters(container, force = false) {
681
- return getItemsFromInitializer(container, this.updaters, this.initializers.updaters, force);
682
- }
683
838
  async init() {
684
839
  if (this.#initialized || this.#isRunningLoaders) {
685
840
  return;
@@ -698,16 +853,9 @@
698
853
  this.#initialized = true;
699
854
  }
700
855
  }
701
- loadParticlesOptions(container, options, ...sourceOptions) {
702
- const updaters = this.updaters.get(container);
703
- if (!updaters) {
704
- return;
705
- }
706
- updaters.forEach(updater => updater.loadOptions?.(options, ...sourceOptions));
707
- }
708
856
  async register(...loaders) {
709
857
  if (this.#initialized) {
710
- throw new Error("Register plugins can only be done before calling tsParticles.load()");
858
+ throw new Error(getErrorMessage(ErrorCodes$2.pluginRegisterAfterLoad));
711
859
  }
712
860
  for (const loader of loaders) {
713
861
  if (this.#isRunningLoaders) {
@@ -719,88 +867,15 @@
719
867
  }
720
868
  }
721
869
  async #runLoader(loader, executed, allLoaders) {
722
- if (executed.has(loader))
870
+ if (executed.has(loader)) {
723
871
  return;
872
+ }
724
873
  executed.add(loader);
725
874
  allLoaders.add(loader);
726
875
  await loader(this.#engine);
727
876
  }
728
877
  }
729
878
 
730
- const errorPrefix = "tsParticles - Error";
731
- const wrap = (fn) => (...args) => {
732
- fn(...args);
733
- }, _logger = {
734
- debug: wrap(console.debug),
735
- error: (message, ...optionalParams) => {
736
- console.error(`${errorPrefix} - ${message}`, ...optionalParams);
737
- },
738
- info: wrap(console.info),
739
- log: wrap(console.log),
740
- trace: wrap(console.trace),
741
- verbose: wrap(console.log),
742
- warning: wrap(console.warn),
743
- };
744
- function getLogger() {
745
- return _logger;
746
- }
747
-
748
- const fullPercent = "100%";
749
- async function getDataFromUrl(data) {
750
- const url = itemFromSingleOrMultiple(data.url, data.index);
751
- if (!url) {
752
- return data.fallback;
753
- }
754
- const response = await fetch(url);
755
- if (response.ok) {
756
- return (await response.json());
757
- }
758
- getLogger().error(`${response.status.toString()} while retrieving config file`);
759
- return data.fallback;
760
- }
761
- const getCanvasFromContainer = (domContainer) => {
762
- const documentSafe = safeDocument();
763
- let canvasEl;
764
- const isCanvas = domContainer instanceof HTMLCanvasElement || domContainer.tagName.toLowerCase() === canvasTag;
765
- if (isCanvas) {
766
- canvasEl = domContainer;
767
- canvasEl.dataset[generatedAttribute] ??= generatedFalse;
768
- if (canvasEl.dataset[generatedAttribute] === generatedTrue) {
769
- canvasEl.style.width ||= fullPercent;
770
- canvasEl.style.height ||= fullPercent;
771
- canvasEl.style.pointerEvents = "none";
772
- canvasEl.style.setProperty("pointer-events", "none");
773
- }
774
- }
775
- else {
776
- const existingCanvases = domContainer.getElementsByTagName(canvasTag), foundCanvas = existingCanvases.item(canvasFirstIndex);
777
- if (foundCanvas) {
778
- canvasEl = foundCanvas;
779
- canvasEl.dataset[generatedAttribute] = generatedFalse;
780
- }
781
- else {
782
- canvasEl = documentSafe.createElement(canvasTag);
783
- canvasEl.dataset[generatedAttribute] = generatedTrue;
784
- domContainer.appendChild(canvasEl);
785
- }
786
- canvasEl.style.width ||= fullPercent;
787
- canvasEl.style.height ||= fullPercent;
788
- canvasEl.style.pointerEvents = "none";
789
- canvasEl.style.setProperty("pointer-events", "none");
790
- }
791
- return canvasEl;
792
- }, getDomContainer = (id, source) => {
793
- const documentSafe = safeDocument();
794
- let domContainer = source ?? documentSafe.getElementById(id);
795
- if (domContainer) {
796
- return domContainer;
797
- }
798
- domContainer = documentSafe.createElement("canvas");
799
- domContainer.id = id;
800
- domContainer.dataset[generatedAttribute] = generatedTrue;
801
- documentSafe.body.append(domContainer);
802
- return domContainer;
803
- };
804
879
  class Engine {
805
880
  pluginManager = new PluginManager(this);
806
881
  #domArray = [];
@@ -810,7 +885,7 @@
810
885
  return this.#domArray;
811
886
  }
812
887
  get version() {
813
- return "4.3.2";
888
+ return "4.5.0";
814
889
  }
815
890
  addEventListener(type, listener) {
816
891
  this.#eventDispatcher.addEventListener(type, listener);
@@ -819,7 +894,7 @@
819
894
  if (this.version === pluginVersion) {
820
895
  return;
821
896
  }
822
- throw new Error(`The tsParticles version is different from the loaded plugins version. Engine version: ${this.version}. Plugin version: ${pluginVersion}`);
897
+ throw new Error(getErrorMessage(ErrorCodes$2.engineVersionMismatch, this.version, pluginVersion));
823
898
  }
824
899
  dispatchEvent(type, args) {
825
900
  this.#eventDispatcher.dispatchEvent(type, args);
@@ -891,6 +966,10 @@
891
966
  }
892
967
 
893
968
  function initEngine() {
969
+ const existing = globalThis.tsParticles;
970
+ if (existing?.pluginManager) {
971
+ return existing;
972
+ }
894
973
  return new Engine();
895
974
  }
896
975
 
@@ -988,6 +1067,15 @@
988
1067
  AnimationMode["random"] = "random";
989
1068
  })(AnimationMode || (AnimationMode = {}));
990
1069
 
1070
+ var HdrMode;
1071
+ (function (HdrMode) {
1072
+ HdrMode["standard"] = "standard";
1073
+ HdrMode["natural"] = "natural";
1074
+ HdrMode["vivid"] = "vivid";
1075
+ HdrMode["cinematic"] = "cinematic";
1076
+ HdrMode["dynamic"] = "dynamic";
1077
+ })(HdrMode || (HdrMode = {}));
1078
+
991
1079
  var LimitMode;
992
1080
  (function (LimitMode) {
993
1081
  LimitMode["delete"] = "delete";
@@ -1055,20 +1143,6 @@
1055
1143
  DrawLayer[DrawLayer["Foreground"] = 7] = "Foreground";
1056
1144
  })(DrawLayer || (DrawLayer = {}));
1057
1145
 
1058
- class OptionLoader {
1059
- load(data) {
1060
- if (isNull(data)) {
1061
- return;
1062
- }
1063
- this.doLoad(data);
1064
- }
1065
- }
1066
- function loadOptions(options, ...sourceOptionsArr) {
1067
- for (const sourceOptions of sourceOptionsArr) {
1068
- options.load(sourceOptions);
1069
- }
1070
- }
1071
-
1072
1146
  function loadProperty(obj, key, value) {
1073
1147
  if (value !== undefined) {
1074
1148
  obj[key] = value;
@@ -1100,6 +1174,20 @@
1100
1174
  }
1101
1175
  }
1102
1176
 
1177
+ class OptionLoader {
1178
+ load(data) {
1179
+ if (isNull(data)) {
1180
+ return;
1181
+ }
1182
+ this.doLoad(data);
1183
+ }
1184
+ }
1185
+ function loadOptions(options, ...sourceOptionsArr) {
1186
+ for (const sourceOptions of sourceOptionsArr) {
1187
+ options.load(sourceOptions);
1188
+ }
1189
+ }
1190
+
1103
1191
  class AnimationOptions extends OptionLoader {
1104
1192
  count = 0;
1105
1193
  decay = 0;
@@ -1243,6 +1331,28 @@
1243
1331
  }
1244
1332
  }
1245
1333
 
1334
+ const defaultPeakNits = 400, minPeakNits = 0, toStringValue = (value) => String(value);
1335
+ class HDROptions extends OptionLoader {
1336
+ enable = true;
1337
+ mode = HdrMode.standard;
1338
+ peakNits = defaultPeakNits;
1339
+ doLoad(data) {
1340
+ if (data.enable !== undefined && !isBoolean(data.enable)) {
1341
+ throw new Error(getErrorMessage(ErrorCodes$2.hdrEnableInvalid, String(data.enable)));
1342
+ }
1343
+ if (data.mode !== undefined && !isEnumValue(HdrMode, data.mode)) {
1344
+ throw new Error(getErrorMessage(ErrorCodes$2.hdrModeInvalid, Object.values(HdrMode).join(", "), toStringValue(data.mode)));
1345
+ }
1346
+ if (data.peakNits !== undefined &&
1347
+ (!isNumber(data.peakNits) || !Number.isFinite(data.peakNits) || data.peakNits <= minPeakNits)) {
1348
+ throw new Error(getErrorMessage(ErrorCodes$2.hdrPeakNitsInvalid, String(data.peakNits)));
1349
+ }
1350
+ loadProperty(this, "enable", data.enable);
1351
+ loadProperty(this, "mode", data.mode);
1352
+ loadProperty(this, "peakNits", data.peakNits);
1353
+ }
1354
+ }
1355
+
1246
1356
  class ResizeEvent extends OptionLoader {
1247
1357
  delay = 0.5;
1248
1358
  enable = true;
@@ -1613,12 +1723,10 @@
1613
1723
  plugin.loadParticlesOptions(this.#container, this, data);
1614
1724
  }
1615
1725
  }
1616
- const updaters = this.#pluginManager.updaters.get(this.#container);
1617
- if (updaters) {
1618
- for (const updater of updaters) {
1619
- if (updater.loadOptions) {
1620
- updater.loadOptions(this, data);
1621
- }
1726
+ const updaters = this.#container.particleUpdaters;
1727
+ for (const updater of updaters) {
1728
+ if (updater.loadOptions) {
1729
+ updater.loadOptions(this, data);
1622
1730
  }
1623
1731
  }
1624
1732
  }
@@ -1686,7 +1794,7 @@
1686
1794
  duration = 0;
1687
1795
  fpsLimit = 120;
1688
1796
  fullScreen;
1689
- hdr = true;
1797
+ hdr;
1690
1798
  key;
1691
1799
  name;
1692
1800
  palette;
@@ -1706,6 +1814,7 @@
1706
1814
  this.#container = container;
1707
1815
  this.background = new Background();
1708
1816
  this.fullScreen = new FullScreen();
1817
+ this.hdr = new HDROptions();
1709
1818
  this.particles = loadParticlesOptions(this.#pluginManager, this.#container);
1710
1819
  this.resize = new ResizeEvent();
1711
1820
  }
@@ -1728,7 +1837,15 @@
1728
1837
  loadProperty(this, "detectRetina", data.detectRetina);
1729
1838
  loadRangeProperty(this, "duration", data.duration);
1730
1839
  loadProperty(this, "fpsLimit", data.fpsLimit);
1731
- loadProperty(this, "hdr", data.hdr);
1840
+ const hdrData = data.hdr;
1841
+ if (isBoolean(hdrData)) {
1842
+ this.hdr.enable = hdrData;
1843
+ this.hdr.mode = HdrMode.standard;
1844
+ this.hdr.peakNits = 400;
1845
+ }
1846
+ else {
1847
+ this.hdr.load(hdrData);
1848
+ }
1732
1849
  loadProperty(this, "pauseOnBlur", data.pauseOnBlur);
1733
1850
  loadProperty(this, "pauseOnOutsideViewport", data.pauseOnOutsideViewport);
1734
1851
  loadProperty(this, "zLayers", data.zLayers);
@@ -1771,7 +1888,7 @@
1771
1888
  }
1772
1889
  }
1773
1890
 
1774
- const styleCache = new Map(), maxStyleCacheSize = 2000, rgbFixedPrecision = 2, hslFixedPrecision = 2, hdrRgbFixedPrecision = 4, hdrHslFixedPrecision = 4, sdrReferenceWhiteNits = 203, hdrAnimationScale = sdrReferenceWhiteNits / maxNits;
1891
+ 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;
1775
1892
  function getCachedStyle(key, generator) {
1776
1893
  let cached = styleCache.get(key);
1777
1894
  if (!cached) {
@@ -1783,6 +1900,42 @@
1783
1900
  }
1784
1901
  return cached;
1785
1902
  }
1903
+ function acesFilmic(x) {
1904
+ return clamp((x * (acesA * x + acesB)) / (x * (acesC * x + acesD) + acesE), none, one);
1905
+ }
1906
+ function applyHdrModeAdjustments(r, g, b, mode, maxChannel) {
1907
+ switch (mode) {
1908
+ case HdrMode.vivid: {
1909
+ const avg = (r + g + b) / channelCount;
1910
+ return {
1911
+ b: clamp(clamp(avg + (b - avg) * saturationBoost, none, maxChannel) * lightnessBoost, none, maxChannel),
1912
+ g: clamp(clamp(avg + (g - avg) * saturationBoost, none, maxChannel) * lightnessBoost, none, maxChannel),
1913
+ r: clamp(clamp(avg + (r - avg) * saturationBoost, none, maxChannel) * lightnessBoost, none, maxChannel),
1914
+ };
1915
+ }
1916
+ case HdrMode.cinematic: {
1917
+ const tempR = r * temperatureR, tempB = b * temperatureB, avg = (tempR + g + tempB) / channelCount;
1918
+ return {
1919
+ b: clamp(avg + (tempB - avg) * contrastFactor, none, maxChannel),
1920
+ g: clamp(avg + (g - avg) * contrastFactor, none, maxChannel),
1921
+ r: clamp(avg + (tempR - avg) * contrastFactor, none, maxChannel),
1922
+ };
1923
+ }
1924
+ case HdrMode.dynamic: {
1925
+ 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;
1926
+ return {
1927
+ b: clamp(b * naturalWeight + vividB * vividWeight, none, maxChannel),
1928
+ g: clamp(g * naturalWeight + vividG * vividWeight, none, maxChannel),
1929
+ r: clamp(r * naturalWeight + vividR * vividWeight, none, maxChannel),
1930
+ };
1931
+ }
1932
+ case HdrMode.standard:
1933
+ return { b, g, r };
1934
+ case HdrMode.natural:
1935
+ default:
1936
+ return { b, g, r };
1937
+ }
1938
+ }
1786
1939
  function stringToRgba(pluginManager, input) {
1787
1940
  if (!input) {
1788
1941
  return;
@@ -1906,9 +2059,9 @@
1906
2059
  const grayscaleValue = Math.round(lNormalized * rgbMax);
1907
2060
  return { r: grayscaleValue, g: grayscaleValue, b: grayscaleValue };
1908
2061
  }
1909
- const temp1 = lNormalized < half
2062
+ const temp2 = lNormalized < half
1910
2063
  ? lNormalized * (sNormalizedOffset + sNormalized)
1911
- : lNormalized + sNormalized - lNormalized * sNormalized, temp2 = double * lNormalized - temp1, phaseThird = phaseNumerator / triple, red = Math.min(rgbMax, rgbMax * hslChannel(temp2, temp1, hNormalized + phaseThird)), green = Math.min(rgbMax, rgbMax * hslChannel(temp2, temp1, hNormalized)), blue = Math.min(rgbMax, rgbMax * hslChannel(temp2, temp1, hNormalized - phaseThird));
2064
+ : lNormalized + sNormalized - lNormalized * sNormalized, temp1 = double * lNormalized - temp2, phaseThird = phaseNumerator / triple, red = Math.min(rgbMax, rgbMax * hslChannel(temp1, temp2, hNormalized + phaseThird)), green = Math.min(rgbMax, rgbMax * hslChannel(temp1, temp2, hNormalized)), blue = Math.min(rgbMax, rgbMax * hslChannel(temp1, temp2, hNormalized - phaseThird));
1912
2065
  return { r: Math.round(red), g: Math.round(green), b: Math.round(blue) };
1913
2066
  }
1914
2067
  function hslToRgbFloat(hsl) {
@@ -1917,9 +2070,9 @@
1917
2070
  const grayscaleValue = lNormalized * rgbMax;
1918
2071
  return { r: grayscaleValue, g: grayscaleValue, b: grayscaleValue };
1919
2072
  }
1920
- const temp1 = lNormalized < half
2073
+ const temp2 = lNormalized < half
1921
2074
  ? lNormalized * (sNormalizedOffset + sNormalized)
1922
- : lNormalized + sNormalized - lNormalized * sNormalized, temp2 = double * lNormalized - temp1, phaseThird = phaseNumerator / triple, red = Math.min(rgbMax, rgbMax * hslChannel(temp2, temp1, hNormalized + phaseThird)), green = Math.min(rgbMax, rgbMax * hslChannel(temp2, temp1, hNormalized)), blue = Math.min(rgbMax, rgbMax * hslChannel(temp2, temp1, hNormalized - phaseThird));
2075
+ : lNormalized + sNormalized - lNormalized * sNormalized, temp1 = double * lNormalized - temp2, phaseThird = phaseNumerator / triple, red = Math.min(rgbMax, rgbMax * hslChannel(temp1, temp2, hNormalized + phaseThird)), green = Math.min(rgbMax, rgbMax * hslChannel(temp1, temp2, hNormalized)), blue = Math.min(rgbMax, rgbMax * hslChannel(temp1, temp2, hNormalized - phaseThird));
1923
2076
  return { r: red, g: green, b: blue };
1924
2077
  }
1925
2078
  function hslaToRgba(hsla) {
@@ -1940,21 +2093,40 @@
1940
2093
  r: getRgbInRangeValue(),
1941
2094
  };
1942
2095
  }
1943
- function getStyleFromRgb(color, hdr, opacity) {
1944
- 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()}`;
1945
- return getCachedStyle(key, () => (hdr ? getHdrStyleFromRgb(color, opacity) : getSdrStyleFromRgb(color, opacity)));
2096
+ function getStyleFromRgb(color, hdr, opacity, peakNits, mode) {
2097
+ const rgbPrecision = hdr ? hdrRgbFixedPrecision : rgbFixedPrecision, op = opacity ?? defaultOpacity$1, key = hdr
2098
+ ? `rgb-${color.r.toFixed(rgbPrecision)}-${color.g.toFixed(rgbPrecision)}-${color.b.toFixed(rgbPrecision)}-hdr-${op.toString()}-${(peakNits ?? maxNits).toString()}-${mode ?? HdrMode.standard}`
2099
+ : `rgb-${color.r.toFixed(rgbPrecision)}-${color.g.toFixed(rgbPrecision)}-${color.b.toFixed(rgbPrecision)}-sdr-${op.toString()}`;
2100
+ return getCachedStyle(key, () => hdr ? getHdrStyleFromRgb(color, opacity, peakNits, mode) : getSdrStyleFromRgb(color, opacity));
2101
+ }
2102
+ function getHdrStyleFromRgb(color, opacity, peakNits = maxNits, mode = HdrMode.standard) {
2103
+ const headroom = peakNits / sdrReferenceWhiteNits, middleGray = 0.18, mapped = hdrToneMapColor(color, headroom, middleGray, mode);
2104
+ return `color(display-p3 ${mapped.r.toString()} ${mapped.g.toString()} ${mapped.b.toString()} / ${(opacity ?? defaultOpacity$1).toString()})`;
2105
+ }
2106
+ function hdrToneMapColor(color, headroom, middleGray, mode) {
2107
+ const rNorm = color.r / rgbMax, gNorm = color.g / rgbMax, bNorm = color.b / rgbMax;
2108
+ if (mode !== HdrMode.natural && mode !== HdrMode.vivid && mode !== HdrMode.cinematic && mode !== HdrMode.dynamic) {
2109
+ return { b: bNorm, g: gNorm, r: rNorm };
2110
+ }
2111
+ const maxChannel = Math.max(one, headroom), luminance = luminanceR * rNorm + luminanceG * gNorm + luminanceB * bNorm, mappedLuminance = hdrToneMap(luminance, headroom, middleGray), scale = luminance > none ? mappedLuminance / luminance : one;
2112
+ return applyHdrModeAdjustments(clamp(rNorm * scale, none, maxChannel), clamp(gNorm * scale, none, maxChannel), clamp(bNorm * scale, none, maxChannel), mode, maxChannel);
1946
2113
  }
1947
- function getHdrStyleFromRgb(color, opacity, peakNits = maxNits) {
1948
- const headroom = peakNits / sdrReferenceWhiteNits;
1949
- return `color(display-p3 ${((color.r / rgbMax) * headroom).toString()} ${((color.g / rgbMax) * headroom).toString()} ${((color.b / rgbMax) * headroom).toString()} / ${(opacity ?? defaultOpacity$1).toString()})`;
2114
+ function hdrToneMap(normalized, headroom, middleGray) {
2115
+ if (normalized <= middleGray) {
2116
+ return acesFilmic(normalized);
2117
+ }
2118
+ const expanded = normalized + (normalized - middleGray) * (headroom - one);
2119
+ return acesFilmic(expanded);
1950
2120
  }
1951
2121
  function getSdrStyleFromRgb(color, opacity) {
1952
2122
  return `rgba(${color.r.toString()}, ${color.g.toString()}, ${color.b.toString()}, ${(opacity ?? defaultOpacity$1).toString()})`;
1953
2123
  }
1954
- function getStyleFromHsl(color, hdr, opacity) {
1955
- 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()}`;
2124
+ function getStyleFromHsl(color, hdr, opacity, peakNits, mode) {
2125
+ const hslPrecision = hdr ? hdrHslFixedPrecision : hslFixedPrecision, op = opacity ?? defaultOpacity$1, key = hdr
2126
+ ? `hsl-${color.h.toFixed(hslPrecision)}-${color.s.toFixed(hslPrecision)}-${color.l.toFixed(hslPrecision)}-hdr-${op.toString()}-${(peakNits ?? maxNits).toString()}-${mode ?? HdrMode.standard}`
2127
+ : `hsl-${color.h.toFixed(hslPrecision)}-${color.s.toFixed(hslPrecision)}-${color.l.toFixed(hslPrecision)}-sdr-${op.toString()}`;
1956
2128
  return getCachedStyle(key, () => hdr
1957
- ? getStyleFromRgb(hslToRgbFloat(color), true, opacity)
2129
+ ? getStyleFromRgb(hslToRgbFloat(color), true, opacity, peakNits, mode)
1958
2130
  : `hsla(${color.h.toString()}, ${color.s.toString()}%, ${color.l.toString()}%, ${op.toString()})`);
1959
2131
  }
1960
2132
  function getHslFromAnimation(animation) {
@@ -2017,7 +2189,7 @@
2017
2189
  colorValue.velocity = defaultVelocity;
2018
2190
  }
2019
2191
  }
2020
- function updateColorValue(data, decrease, delta, hdr) {
2192
+ function updateColorValue(data, decrease, delta, _hdr) {
2021
2193
  const minLoops = 0, minDelay = 0, identity = 1, minVelocity = 0, minOffset = 0, velocityFactor = 3.6;
2022
2194
  if (!data.enable ||
2023
2195
  ((data.maxLoops ?? minLoops) > minLoops && (data.loops ?? minLoops) > (data.maxLoops ?? minLoops))) {
@@ -2030,7 +2202,7 @@
2030
2202
  if ((data.delayTime ?? minDelay) > minDelay && data.time < (data.delayTime ?? minDelay)) {
2031
2203
  return;
2032
2204
  }
2033
- 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;
2205
+ 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;
2034
2206
  if (!decrease || data.status === AnimationStatus.increasing) {
2035
2207
  data.value += velocity;
2036
2208
  if (data.value > max) {
@@ -2062,9 +2234,9 @@
2062
2234
  return;
2063
2235
  }
2064
2236
  const { h, s, l } = color;
2065
- updateColorValue(h, false, delta, hdr);
2066
- updateColorValue(s, true, delta, hdr);
2067
- updateColorValue(l, true, delta, hdr);
2237
+ updateColorValue(h, false, delta);
2238
+ updateColorValue(s, true, delta);
2239
+ updateColorValue(l, true, delta);
2068
2240
  }
2069
2241
  function alterHsl(color, type, value) {
2070
2242
  return {
@@ -2114,7 +2286,7 @@
2114
2286
  }
2115
2287
 
2116
2288
  async function loadBlendPlugin(engine) {
2117
- engine.checkVersion("4.3.2");
2289
+ engine.checkVersion("4.5.0");
2118
2290
  await engine.pluginManager.register(e => {
2119
2291
  e.pluginManager.addPlugin(new BlendPlugin());
2120
2292
  });
@@ -2151,7 +2323,7 @@
2151
2323
  }
2152
2324
 
2153
2325
  async function loadCircleShape(engine) {
2154
- engine.checkVersion("4.3.2");
2326
+ engine.checkVersion("4.5.0");
2155
2327
  await engine.pluginManager.register(e => {
2156
2328
  e.pluginManager.addShape(["circle"], () => {
2157
2329
  return Promise.resolve(new CircleDrawer());
@@ -2166,7 +2338,7 @@
2166
2338
  RgbIndexes[RgbIndexes["b"] = 3] = "b";
2167
2339
  RgbIndexes[RgbIndexes["a"] = 4] = "a";
2168
2340
  })(RgbIndexes$1 || (RgbIndexes$1 = {}));
2169
- const shorthandHexRegex = /^#?([a-f\d])([a-f\d])([a-f\d])([a-f\d])?$/i, hexRegex = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})?$/i, hexRadix = 16, defaultAlpha = 1, alphaFactor = 0xff;
2341
+ const shorthandHexRegex = /^#?([a-f\d])([a-f\d])([a-f\d])([a-f\d])?$/i, hexRegex = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})?$/i, hexRadix = 16, alphaFactor = 0xff;
2170
2342
  class HexColorManager {
2171
2343
  accepts(input) {
2172
2344
  return input.startsWith("#");
@@ -2199,7 +2371,7 @@
2199
2371
  }
2200
2372
 
2201
2373
  async function loadHexColorPlugin(engine) {
2202
- engine.checkVersion("4.3.2");
2374
+ engine.checkVersion("4.5.0");
2203
2375
  await engine.pluginManager.register(e => {
2204
2376
  e.pluginManager.addColorManager("hex", new HexColorManager());
2205
2377
  });
@@ -2239,7 +2411,7 @@
2239
2411
  if (!this.accepts(input)) {
2240
2412
  return;
2241
2413
  }
2242
- const result = hslRegex.exec(input), minLength = 4, defaultAlpha = 1, radix = 10;
2414
+ const result = hslRegex.exec(input), minLength = 4, radix = 10;
2243
2415
  return result
2244
2416
  ? hslaToRgba({
2245
2417
  a: result.length > minLength ? parseAlpha(result[HslIndexes.a]) : defaultAlpha,
@@ -2252,12 +2424,20 @@
2252
2424
  }
2253
2425
 
2254
2426
  async function loadHslColorPlugin(engine) {
2255
- engine.checkVersion("4.3.2");
2427
+ engine.checkVersion("4.5.0");
2256
2428
  await engine.pluginManager.register(e => {
2257
2429
  e.pluginManager.addColorManager("hsl", new HslColorManager());
2258
2430
  });
2259
2431
  }
2260
2432
 
2433
+ const ErrorCodes$1 = {
2434
+ baseMoverNotLoaded: "TSP-3203",
2435
+ };
2436
+
2437
+ const ErrorMessages$1 = {
2438
+ [ErrorCodes$1.baseMoverNotLoaded]: "tsParticles Base Mover is not loaded",
2439
+ };
2440
+
2261
2441
  class MovePlugin {
2262
2442
  id = "move";
2263
2443
  #pluginManager;
@@ -2276,20 +2456,20 @@
2276
2456
  }
2277
2457
 
2278
2458
  async function loadMovePlugin(engine) {
2279
- engine.checkVersion("4.3.2");
2459
+ engine.checkVersion("4.5.0");
2460
+ if (typeof process !== "undefined" && process.env.NODE_ENV !== "production") {
2461
+ addErrorMessages(ErrorMessages$1);
2462
+ }
2280
2463
  await engine.pluginManager.register(e => {
2281
2464
  const moveEngine = e, movePluginManager = moveEngine.pluginManager;
2282
2465
  movePluginManager.initializers.pathGenerators ??= new Map();
2283
- movePluginManager.pathGenerators ??= new Map();
2284
2466
  movePluginManager.addPathGenerator = (name, generator) => {
2467
+ if (movePluginManager.initialized) {
2468
+ return;
2469
+ }
2285
2470
  movePluginManager.initializers.pathGenerators ??= new Map();
2286
2471
  movePluginManager.initializers.pathGenerators.set(name, generator);
2287
2472
  };
2288
- movePluginManager.getPathGenerators = async (container, force = false) => {
2289
- movePluginManager.initializers.pathGenerators ??= new Map();
2290
- movePluginManager.pathGenerators ??= new Map();
2291
- return getItemMapFromInitializer(container, movePluginManager.pathGenerators, movePluginManager.initializers.pathGenerators, force);
2292
- };
2293
2473
  e.pluginManager.addPlugin(new MovePlugin(e.pluginManager));
2294
2474
  });
2295
2475
  }
@@ -2486,7 +2666,7 @@
2486
2666
  }
2487
2667
 
2488
2668
  async function loadOpacityUpdater(engine) {
2489
- engine.checkVersion("4.3.2");
2669
+ engine.checkVersion("4.5.0");
2490
2670
  await engine.pluginManager.register(e => {
2491
2671
  e.pluginManager.addParticleUpdater("opacity", container => {
2492
2672
  return Promise.resolve(new OpacityUpdater(container));
@@ -2495,70 +2675,60 @@
2495
2675
  }
2496
2676
 
2497
2677
  const boundsMin = 0;
2498
- function bounceHorizontal(data) {
2499
- if ((data.outMode !== OutMode.bounce && data.outMode !== OutMode.split) ||
2500
- (data.direction !== OutModeDirection.left && data.direction !== OutModeDirection.right)) {
2501
- return;
2502
- }
2503
- if (data.bounds.right < boundsMin && data.direction === OutModeDirection.left) {
2504
- data.particle.position.x = data.size + data.offset.x;
2505
- }
2506
- else if (data.bounds.left > data.canvasSize.width && data.direction === OutModeDirection.right) {
2507
- data.particle.position.x = data.canvasSize.width - data.size - data.offset.x;
2508
- }
2509
- const velocity = data.particle.velocity.x;
2510
- let bounced = false;
2511
- if (data.outOfCanvas &&
2512
- ((data.direction === OutModeDirection.right && velocity > minVelocity) ||
2513
- (data.direction === OutModeDirection.left && velocity < minVelocity))) {
2514
- const newVelocity = getRangeValue(data.particle.options.bounce.horizontal.value);
2515
- data.particle.velocity.x *= -newVelocity;
2516
- bounced = true;
2517
- }
2518
- if (!bounced) {
2519
- return;
2520
- }
2521
- const minPos = data.offset.x + data.size;
2522
- if (data.outOfCanvas && data.direction === OutModeDirection.right) {
2523
- data.particle.position.x = data.canvasSize.width - minPos;
2524
- }
2525
- else if (data.outOfCanvas && data.direction === OutModeDirection.left) {
2526
- data.particle.position.x = minPos;
2527
- }
2528
- if (data.outMode === OutMode.split) {
2529
- data.particle.destroy();
2530
- }
2531
- }
2532
- function bounceVertical(data) {
2533
- if ((data.outMode !== OutMode.bounce && data.outMode !== OutMode.split) ||
2534
- (data.direction !== OutModeDirection.bottom && data.direction !== OutModeDirection.top)) {
2678
+ const bounceAxisConfigs = {
2679
+ [OutModeDirection.left]: {
2680
+ axis: "x",
2681
+ canvas: "width",
2682
+ bounce: "horizontal",
2683
+ negativeEdge: "right",
2684
+ positiveEdge: "left",
2685
+ negative: true,
2686
+ },
2687
+ [OutModeDirection.right]: {
2688
+ axis: "x",
2689
+ canvas: "width",
2690
+ bounce: "horizontal",
2691
+ negativeEdge: "right",
2692
+ positiveEdge: "left",
2693
+ negative: false,
2694
+ },
2695
+ [OutModeDirection.top]: {
2696
+ axis: "y",
2697
+ canvas: "height",
2698
+ bounce: "vertical",
2699
+ negativeEdge: "bottom",
2700
+ positiveEdge: "top",
2701
+ negative: true,
2702
+ },
2703
+ [OutModeDirection.bottom]: {
2704
+ axis: "y",
2705
+ canvas: "height",
2706
+ bounce: "vertical",
2707
+ negativeEdge: "bottom",
2708
+ positiveEdge: "top",
2709
+ negative: false,
2710
+ },
2711
+ };
2712
+ function bounce(data) {
2713
+ if ((data.outMode !== OutMode.bounce && data.outMode !== OutMode.split) || !(data.direction in bounceAxisConfigs)) {
2535
2714
  return;
2536
2715
  }
2537
- if (data.bounds.bottom < boundsMin && data.direction === OutModeDirection.top) {
2538
- data.particle.position.y = data.size + data.offset.y;
2716
+ const config = bounceAxisConfigs[data.direction], bounds = data.bounds, canvasDim = data.canvasSize[config.canvas], position = data.particle.position, velocity = data.particle.velocity[config.axis];
2717
+ if (config.negative && bounds[config.negativeEdge] < boundsMin) {
2718
+ position[config.axis] = data.size + data.offset[config.axis];
2539
2719
  }
2540
- else if (data.bounds.top > data.canvasSize.height && data.direction === OutModeDirection.bottom) {
2541
- data.particle.position.y = data.canvasSize.height - data.size - data.offset.y;
2720
+ else if (!config.negative && bounds[config.positiveEdge] > canvasDim) {
2721
+ position[config.axis] = canvasDim - data.size - data.offset[config.axis];
2542
2722
  }
2543
- const velocity = data.particle.velocity.y;
2544
- let bounced = false;
2545
2723
  if (data.outOfCanvas &&
2546
- ((data.direction === OutModeDirection.bottom && velocity > minVelocity) ||
2547
- (data.direction === OutModeDirection.top && velocity < minVelocity))) {
2548
- const newVelocity = getRangeValue(data.particle.options.bounce.vertical.value);
2549
- data.particle.velocity.y *= -newVelocity;
2550
- bounced = true;
2724
+ ((config.negative && velocity < minVelocity) || (!config.negative && velocity > minVelocity))) {
2725
+ data.particle.velocity[config.axis] *= -getRangeValue(data.particle.options.bounce[config.bounce].value);
2551
2726
  }
2552
- if (!bounced) {
2727
+ else {
2553
2728
  return;
2554
2729
  }
2555
- const minPos = data.offset.y + data.size;
2556
- if (data.outOfCanvas && data.direction === OutModeDirection.bottom) {
2557
- data.particle.position.y = data.canvasSize.height - minPos;
2558
- }
2559
- else if (data.outOfCanvas && data.direction === OutModeDirection.top) {
2560
- data.particle.position.y = minPos;
2561
- }
2730
+ const minPos = data.offset[config.axis] + data.size;
2731
+ position[config.axis] = config.negative ? minPos : canvasDim - minPos;
2562
2732
  if (data.outMode === OutMode.split) {
2563
2733
  data.particle.destroy();
2564
2734
  }
@@ -2574,26 +2744,19 @@
2574
2744
  OutMode.bounce,
2575
2745
  OutMode.split,
2576
2746
  ];
2577
- this.#particleBouncePlugins = container.plugins.filter(p => p.particleBounce !== undefined);
2747
+ this.#particleBouncePlugins = container.plugins.filter(p => !!p.particleBounce);
2578
2748
  }
2579
2749
  update(particle, direction, delta, outMode) {
2580
2750
  if (!this.modes.includes(outMode)) {
2581
2751
  return;
2582
2752
  }
2583
- const container = this.#container;
2584
- let handled = false;
2585
2753
  for (const plugin of this.#particleBouncePlugins) {
2586
- handled = plugin.particleBounce?.(particle, delta, direction) ?? false;
2587
- if (handled) {
2588
- break;
2754
+ if (plugin.particleBounce?.(particle, delta, direction)) {
2755
+ return;
2589
2756
  }
2590
2757
  }
2591
- if (handled) {
2592
- return;
2593
- }
2594
- const pos = particle.getPosition(), offset = particle.offset, size = particle.getRadius(), bounds = calculateBounds(pos, size), canvasSize = container.canvas.size, outOfCanvas = !particle.isInsideCanvasForOutMode(outMode, direction);
2595
- bounceHorizontal({ particle, outMode, direction, bounds, canvasSize, offset, outOfCanvas, size });
2596
- bounceVertical({ particle, outMode, direction, bounds, canvasSize, offset, outOfCanvas, size });
2758
+ const pos = particle.getPosition(), offset = particle.offset, size = particle.getRadius(), bounds = calculateBounds(pos, size), canvasSize = this.#container.canvas.size, outOfCanvas = !particle.isInsideCanvasForOutMode(outMode, direction);
2759
+ bounce({ particle, outMode, direction, bounds, canvasSize, offset, outOfCanvas, size });
2597
2760
  }
2598
2761
  }
2599
2762
 
@@ -2682,107 +2845,108 @@
2682
2845
  return;
2683
2846
  }
2684
2847
  const container = this.#container;
2685
- switch (particle.outType) {
2686
- case ParticleOutType.inside: {
2687
- const { x: vx, y: vy } = particle.velocity;
2688
- updateVector.setTo(originPoint);
2689
- updateVector.length = particle.moveCenter.radius;
2690
- updateVector.angle = particle.velocity.angle + Math.PI;
2691
- updateVector.addTo(particle.moveCenter);
2692
- const { dx, dy } = getDistances(particle.position, updateVector);
2693
- if ((vx <= minVelocity && dx >= minDistance) ||
2694
- (vy <= minVelocity && dy >= minDistance) ||
2695
- (vx >= minVelocity && dx <= minDistance) ||
2696
- (vy >= minVelocity && dy <= minDistance)) {
2697
- return;
2698
- }
2699
- particle.position.x = Math.floor(randomInRangeValue({
2700
- min: 0,
2701
- max: container.canvas.size.width,
2702
- }));
2703
- particle.position.y = Math.floor(randomInRangeValue({
2704
- min: 0,
2705
- max: container.canvas.size.height,
2706
- }));
2707
- const { dx: newDx, dy: newDy } = getDistances(particle.position, particle.moveCenter);
2708
- particle.direction = Math.atan2(-newDy, -newDx);
2709
- particle.velocity.angle = particle.direction;
2710
- particle.justWarped = true;
2711
- break;
2848
+ if (particle.outType === ParticleOutType.inside) {
2849
+ this.#applyOutModeInside(particle, container);
2850
+ }
2851
+ else {
2852
+ if (particle.isInsideCanvasForOutMode(outMode, direction)) {
2853
+ return;
2712
2854
  }
2713
- default: {
2714
- if (particle.isInsideCanvasForOutMode(outMode, direction)) {
2715
- return;
2716
- }
2717
- switch (particle.outType) {
2718
- case ParticleOutType.outside: {
2719
- particle.position.x =
2720
- Math.floor(randomInRangeValue({
2721
- min: -particle.moveCenter.radius,
2722
- max: particle.moveCenter.radius,
2723
- })) + particle.moveCenter.x;
2724
- particle.position.y =
2725
- Math.floor(randomInRangeValue({
2726
- min: -particle.moveCenter.radius,
2727
- max: particle.moveCenter.radius,
2728
- })) + particle.moveCenter.y;
2729
- const { dx, dy } = getDistances(particle.position, particle.moveCenter);
2730
- if (particle.moveCenter.radius) {
2731
- particle.direction = Math.atan2(dy, dx);
2732
- particle.velocity.angle = particle.direction;
2733
- }
2734
- particle.justWarped = true;
2735
- break;
2736
- }
2737
- case ParticleOutType.normal: {
2738
- const warp = particle.options.move.warp, canvasSize = container.canvas.size, newPos = {
2739
- bottom: canvasSize.height + particle.getRadius() + particle.offset.y,
2740
- left: -particle.getRadius() - particle.offset.x,
2741
- right: canvasSize.width + particle.getRadius() + particle.offset.x,
2742
- top: -particle.getRadius() - particle.offset.y,
2743
- }, sizeValue = particle.getRadius(), nextBounds = calculateBounds(particle.position, sizeValue);
2744
- if (direction === OutModeDirection.right && nextBounds.left > canvasSize.width + particle.offset.x) {
2745
- particle.position.x = newPos.left;
2746
- particle.initialPosition.x = particle.position.x;
2747
- if (!warp) {
2748
- particle.position.y = getRandom() * canvasSize.height;
2749
- particle.initialPosition.y = particle.position.y;
2750
- }
2751
- particle.justWarped = true;
2752
- }
2753
- else if (direction === OutModeDirection.left && nextBounds.right < -particle.offset.x) {
2754
- particle.position.x = newPos.right;
2755
- particle.initialPosition.x = particle.position.x;
2756
- if (!warp) {
2757
- particle.position.y = getRandom() * canvasSize.height;
2758
- particle.initialPosition.y = particle.position.y;
2759
- }
2760
- particle.justWarped = true;
2761
- }
2762
- if (direction === OutModeDirection.bottom && nextBounds.top > canvasSize.height + particle.offset.y) {
2763
- if (!warp) {
2764
- particle.position.x = getRandom() * canvasSize.width;
2765
- particle.initialPosition.x = particle.position.x;
2766
- }
2767
- particle.position.y = newPos.top;
2768
- particle.initialPosition.y = particle.position.y;
2769
- particle.justWarped = true;
2770
- }
2771
- else if (direction === OutModeDirection.top && nextBounds.bottom < -particle.offset.y) {
2772
- if (!warp) {
2773
- particle.position.x = getRandom() * canvasSize.width;
2774
- particle.initialPosition.x = particle.position.x;
2775
- }
2776
- particle.position.y = newPos.bottom;
2777
- particle.initialPosition.y = particle.position.y;
2778
- particle.justWarped = true;
2779
- }
2780
- break;
2781
- }
2782
- }
2783
- break;
2855
+ if (particle.outType === ParticleOutType.outside) {
2856
+ this.#applyParticleModeOutside(particle);
2784
2857
  }
2858
+ else {
2859
+ this.#applyOutModeNormal(particle, container, direction);
2860
+ }
2861
+ }
2862
+ }
2863
+ #applyOutModeInside(particle, container) {
2864
+ const { x: vx, y: vy } = particle.velocity;
2865
+ updateVector.setTo(originPoint);
2866
+ updateVector.length = particle.moveCenter.radius;
2867
+ updateVector.angle = particle.velocity.angle + Math.PI;
2868
+ updateVector.addTo(particle.moveCenter);
2869
+ const { dx, dy } = getDistances(particle.position, updateVector);
2870
+ if ((vx <= minVelocity && dx >= minDistance) ||
2871
+ (vy <= minVelocity && dy >= minDistance) ||
2872
+ (vx >= minVelocity && dx <= minDistance) ||
2873
+ (vy >= minVelocity && dy <= minDistance)) {
2874
+ return;
2785
2875
  }
2876
+ particle.position.x = Math.floor(randomInRangeValue({
2877
+ min: 0,
2878
+ max: container.canvas.size.width,
2879
+ }));
2880
+ particle.position.y = Math.floor(randomInRangeValue({
2881
+ min: 0,
2882
+ max: container.canvas.size.height,
2883
+ }));
2884
+ const { dx: newDx, dy: newDy } = getDistances(particle.position, particle.moveCenter);
2885
+ particle.direction = Math.atan2(-newDy, -newDx);
2886
+ particle.velocity.angle = particle.direction;
2887
+ particle.justWarped = true;
2888
+ }
2889
+ #applyOutModeNormal(particle, container, direction) {
2890
+ const warp = particle.options.move.warp, canvasSize = container.canvas.size, sizeValue = particle.getRadius(), newPos = {
2891
+ bottom: canvasSize.height + sizeValue + particle.offset.y,
2892
+ left: -sizeValue - particle.offset.x,
2893
+ right: canvasSize.width + sizeValue + particle.offset.x,
2894
+ top: -sizeValue - particle.offset.y,
2895
+ }, nextBounds = calculateBounds(particle.position, sizeValue);
2896
+ if (direction === OutModeDirection.right && nextBounds.left > canvasSize.width + particle.offset.x) {
2897
+ particle.position.x = newPos.left;
2898
+ particle.initialPosition.x = particle.position.x;
2899
+ if (!warp) {
2900
+ particle.position.y = getRandom() * canvasSize.height;
2901
+ particle.initialPosition.y = particle.position.y;
2902
+ }
2903
+ particle.justWarped = true;
2904
+ }
2905
+ else if (direction === OutModeDirection.left && nextBounds.right < -particle.offset.x) {
2906
+ particle.position.x = newPos.right;
2907
+ particle.initialPosition.x = particle.position.x;
2908
+ if (!warp) {
2909
+ particle.position.y = getRandom() * canvasSize.height;
2910
+ particle.initialPosition.y = particle.position.y;
2911
+ }
2912
+ particle.justWarped = true;
2913
+ }
2914
+ if (direction === OutModeDirection.bottom && nextBounds.top > canvasSize.height + particle.offset.y) {
2915
+ if (!warp) {
2916
+ particle.position.x = getRandom() * canvasSize.width;
2917
+ particle.initialPosition.x = particle.position.x;
2918
+ }
2919
+ particle.position.y = newPos.top;
2920
+ particle.initialPosition.y = particle.position.y;
2921
+ particle.justWarped = true;
2922
+ }
2923
+ else if (direction === OutModeDirection.top && nextBounds.bottom < -particle.offset.y) {
2924
+ if (!warp) {
2925
+ particle.position.x = getRandom() * canvasSize.width;
2926
+ particle.initialPosition.x = particle.position.x;
2927
+ }
2928
+ particle.position.y = newPos.bottom;
2929
+ particle.initialPosition.y = particle.position.y;
2930
+ particle.justWarped = true;
2931
+ }
2932
+ }
2933
+ #applyParticleModeOutside(particle) {
2934
+ particle.position.x =
2935
+ Math.floor(randomInRangeValue({
2936
+ min: -particle.moveCenter.radius,
2937
+ max: particle.moveCenter.radius,
2938
+ })) + particle.moveCenter.x;
2939
+ particle.position.y =
2940
+ Math.floor(randomInRangeValue({
2941
+ min: -particle.moveCenter.radius,
2942
+ max: particle.moveCenter.radius,
2943
+ })) + particle.moveCenter.y;
2944
+ const { dx, dy } = getDistances(particle.position, particle.moveCenter);
2945
+ if (particle.moveCenter.radius) {
2946
+ particle.direction = Math.atan2(dy, dx);
2947
+ particle.velocity.angle = particle.direction;
2948
+ }
2949
+ particle.justWarped = true;
2786
2950
  }
2787
2951
  }
2788
2952
 
@@ -2831,7 +2995,7 @@
2831
2995
  }
2832
2996
 
2833
2997
  async function loadOutModesUpdater(engine) {
2834
- engine.checkVersion("4.3.2");
2998
+ engine.checkVersion("4.5.0");
2835
2999
  await engine.pluginManager.register(e => {
2836
3000
  e.pluginManager.addParticleUpdater("outModes", container => {
2837
3001
  return Promise.resolve(new OutOfCanvasUpdater(container));
@@ -2848,39 +3012,9 @@
2848
3012
  this.#pluginManager = pluginManager;
2849
3013
  }
2850
3014
  init(particle) {
2851
- 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;
2852
- if (fill) {
2853
- const fillColor = AnimatableColor.create(paintColor === undefined ? undefined : AnimatableColor.create(undefined, paintColor), fill.color);
2854
- particle.fillEnabled = fill.enable;
2855
- particle.fillOpacity = getRangeValue(fill.opacity);
2856
- particle.fillAnimation = fillColor.animation;
2857
- const fillHslColor = rangeColorToHsl(this.#pluginManager, fillColor);
2858
- if (fillHslColor) {
2859
- particle.fillColor = getHslAnimationFromHsl(fillHslColor, particle.fillAnimation, container.retina.reduceFactor);
2860
- }
2861
- }
2862
- else {
2863
- particle.fillEnabled = false;
2864
- particle.fillAnimation = undefined;
2865
- particle.fillColor = undefined;
2866
- particle.fillOpacity = defaultOpacity;
2867
- }
2868
- if (stroke) {
2869
- const strokeColor = AnimatableColor.create(paintColor === undefined ? undefined : AnimatableColor.create(undefined, paintColor), stroke.color);
2870
- particle.strokeWidth = getRangeValue(stroke.width) * container.retina.pixelRatio;
2871
- particle.strokeOpacity = getRangeValue(stroke.opacity ?? defaultOpacity);
2872
- particle.strokeAnimation = strokeColor.animation;
2873
- const strokeHslColor = rangeColorToHsl(this.#pluginManager, strokeColor) ?? particle.getFillColor();
2874
- if (strokeHslColor) {
2875
- particle.strokeColor = getHslAnimationFromHsl(strokeHslColor, particle.strokeAnimation, container.retina.reduceFactor);
2876
- }
2877
- }
2878
- else {
2879
- particle.strokeAnimation = undefined;
2880
- particle.strokeColor = undefined;
2881
- particle.strokeOpacity = defaultOpacity;
2882
- particle.strokeWidth = 0;
2883
- }
3015
+ const container = this.#container, options = particle.options, paint = itemFromSingleOrMultiple(options.paint, particle.id, options.reduceDuplicates);
3016
+ this.#initFill(paint, particle, container);
3017
+ this.#initStroke(paint, particle, container);
2884
3018
  }
2885
3019
  isEnabled(particle) {
2886
3020
  const { fillAnimation, fillColor, strokeAnimation, strokeColor } = particle, fillEnabled = !!fillAnimation &&
@@ -2899,10 +3033,48 @@
2899
3033
  updateColor(particle.fillColor, delta, this.#container.hdr);
2900
3034
  updateColor(particle.strokeColor, delta, this.#container.hdr);
2901
3035
  }
3036
+ #initFill(paint, particle, container) {
3037
+ const fill = paint?.fill, color = paint?.color, paintColor = color ?? undefined;
3038
+ if (!fill) {
3039
+ particle.fillEnabled = false;
3040
+ particle.fillAnimation = undefined;
3041
+ particle.fillColor = undefined;
3042
+ particle.fillOpacity = defaultOpacity;
3043
+ return;
3044
+ }
3045
+ const fillColor = AnimatableColor.create(paintColor === undefined ? undefined : AnimatableColor.create(undefined, paintColor), fill.color);
3046
+ particle.fillEnabled = fill.enable;
3047
+ particle.fillOpacity = getRangeValue(fill.opacity);
3048
+ particle.fillAnimation = fillColor.animation;
3049
+ const fillHslColor = rangeColorToHsl(this.#pluginManager, fillColor);
3050
+ if (!fillHslColor) {
3051
+ return;
3052
+ }
3053
+ particle.fillColor = getHslAnimationFromHsl(fillHslColor, particle.fillAnimation, container.retina.reduceFactor);
3054
+ }
3055
+ #initStroke(paint, particle, container) {
3056
+ const stroke = paint?.stroke, color = paint?.color, paintColor = color ?? undefined;
3057
+ if (!stroke) {
3058
+ particle.strokeAnimation = undefined;
3059
+ particle.strokeColor = undefined;
3060
+ particle.strokeOpacity = defaultOpacity;
3061
+ particle.strokeWidth = 0;
3062
+ return;
3063
+ }
3064
+ const strokeColor = AnimatableColor.create(paintColor === undefined ? undefined : AnimatableColor.create(undefined, paintColor), stroke.color);
3065
+ particle.strokeWidth = getRangeValue(stroke.width) * container.retina.pixelRatio;
3066
+ particle.strokeOpacity = getRangeValue(stroke.opacity ?? defaultOpacity);
3067
+ particle.strokeAnimation = strokeColor.animation;
3068
+ const strokeHslColor = rangeColorToHsl(this.#pluginManager, strokeColor) ?? particle.getFillColor();
3069
+ if (!strokeHslColor) {
3070
+ return;
3071
+ }
3072
+ particle.strokeColor = getHslAnimationFromHsl(strokeHslColor, particle.strokeAnimation, container.retina.reduceFactor);
3073
+ }
2902
3074
  }
2903
3075
 
2904
3076
  async function loadPaintUpdater(engine) {
2905
- engine.checkVersion("4.3.2");
3077
+ engine.checkVersion("4.5.0");
2906
3078
  await engine.pluginManager.register(e => {
2907
3079
  e.pluginManager.addParticleUpdater("paint", container => {
2908
3080
  return Promise.resolve(new PaintUpdater(e.pluginManager, container));
@@ -2944,7 +3116,7 @@
2944
3116
  if (!this.accepts(input)) {
2945
3117
  return;
2946
3118
  }
2947
- const result = rgbRegex.exec(input), radix = 10, minLength = 4, defaultAlpha = 1;
3119
+ const result = rgbRegex.exec(input), radix = 10, minLength = 4;
2948
3120
  return result
2949
3121
  ? {
2950
3122
  a: result.length > minLength ? parseAlpha(result[RgbIndexes.a]) : defaultAlpha,
@@ -2957,7 +3129,7 @@
2957
3129
  }
2958
3130
 
2959
3131
  async function loadRgbColorPlugin(engine) {
2960
- engine.checkVersion("4.3.2");
3132
+ engine.checkVersion("4.5.0");
2961
3133
  await engine.pluginManager.register(e => {
2962
3134
  e.pluginManager.addColorManager("rgb", new RgbColorManager());
2963
3135
  });
@@ -3042,7 +3214,7 @@
3042
3214
  }
3043
3215
 
3044
3216
  async function loadSizeUpdater(engine) {
3045
- engine.checkVersion("4.3.2");
3217
+ engine.checkVersion("4.5.0");
3046
3218
  await engine.pluginManager.register(e => {
3047
3219
  e.pluginManager.addParticleUpdater("size", container => {
3048
3220
  return Promise.resolve(new SizeUpdater(container));
@@ -3051,7 +3223,7 @@
3051
3223
  }
3052
3224
 
3053
3225
  async function loadBasic(engine) {
3054
- engine.checkVersion("4.3.2");
3226
+ engine.checkVersion("4.5.0");
3055
3227
  await engine.pluginManager.register(async (e) => {
3056
3228
  await Promise.all([
3057
3229
  loadBlendPlugin(e),
@@ -3160,6 +3332,8 @@
3160
3332
  autoPlay = true;
3161
3333
  direction;
3162
3334
  domId;
3335
+ draggable = false;
3336
+ draw = true;
3163
3337
  fill = true;
3164
3338
  life = new EmitterLife();
3165
3339
  name;
@@ -3183,6 +3357,8 @@
3183
3357
  }
3184
3358
  loadProperty(this, "direction", data.direction);
3185
3359
  loadProperty(this, "domId", data.domId);
3360
+ loadProperty(this, "draggable", data.draggable);
3361
+ loadProperty(this, "draw", data.draw);
3186
3362
  loadProperty(this, "fill", data.fill);
3187
3363
  this.life.load(data.life);
3188
3364
  loadProperty(this, "name", data.name);
@@ -3244,6 +3420,14 @@
3244
3420
  }
3245
3421
  }
3246
3422
 
3423
+ const ErrorCodes = {
3424
+ emittersPluginNotLoaded: "TSP-3101",
3425
+ };
3426
+
3427
+ const ErrorMessages = {
3428
+ [ErrorCodes.emittersPluginNotLoaded]: "tsParticles Emitters Plugin is not loaded",
3429
+ };
3430
+
3247
3431
  async function addEmittersShapesManager(e) {
3248
3432
  const { ShapeManager } = await Promise.resolve().then(function () { return ShapeManager$1; }), pluginManager = e.pluginManager;
3249
3433
  pluginManager.emitterShapeManager ??= new ShapeManager();
@@ -3274,7 +3458,10 @@
3274
3458
  })(EmitterClickMode || (EmitterClickMode = {}));
3275
3459
 
3276
3460
  async function loadEmittersPluginSimple(engine) {
3277
- engine.checkVersion("4.3.2");
3461
+ engine.checkVersion("4.5.0");
3462
+ if (typeof process !== "undefined" && process.env.NODE_ENV !== "production") {
3463
+ addErrorMessages(ErrorMessages);
3464
+ }
3278
3465
  await engine.pluginManager.register(async (e) => {
3279
3466
  const instancesManager = await getEmittersInstancesManager(e);
3280
3467
  await addEmittersShapesManager(e);
@@ -3414,21 +3601,28 @@
3414
3601
  });
3415
3602
  }
3416
3603
  clear() {
3604
+ const visited = new Set();
3417
3605
  for (const plugin of this.#canvasClearPlugins) {
3606
+ visited.add(plugin);
3418
3607
  if (plugin.canvasClear?.() ?? false) {
3419
- return;
3608
+ return plugin;
3420
3609
  }
3421
3610
  }
3422
3611
  for (const layer of Object.values(DrawLayer)) {
3423
3612
  if (typeof layer === "number") {
3424
3613
  for (const plugin of this.#getLayerPlugins(layer)) {
3614
+ if (visited.has(plugin)) {
3615
+ continue;
3616
+ }
3617
+ visited.add(plugin);
3425
3618
  if (plugin.canvasClear?.() ?? false) {
3426
- return;
3619
+ return plugin;
3427
3620
  }
3428
3621
  }
3429
3622
  }
3430
3623
  }
3431
3624
  this.canvasClear();
3625
+ return undefined;
3432
3626
  }
3433
3627
  destroy() {
3434
3628
  this.stop();
@@ -3469,7 +3663,11 @@
3469
3663
  if (!fColor && !sColor) {
3470
3664
  return;
3471
3665
  }
3472
- 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;
3666
+ 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
3667
+ ? getStyleFromHsl(fColor, container.hdr, fillOpacity * opacity, container.peakNits, container.hdrMode)
3668
+ : undefined, stroke = sColor
3669
+ ? getStyleFromHsl(sColor, container.hdr, strokeOpacity * opacity, container.peakNits, container.hdrMode)
3670
+ : fill;
3473
3671
  transform.a = transform.b = transform.c = transform.d = undefined;
3474
3672
  colorStyles.fill = fill;
3475
3673
  colorStyles.stroke = stroke;
@@ -3502,8 +3700,7 @@
3502
3700
  });
3503
3701
  }
3504
3702
  drawParticles(delta) {
3505
- const { particles, actualOptions } = this.#container;
3506
- this.clear();
3703
+ const { particles, actualOptions } = this.#container, clearedPlugin = this.clear();
3507
3704
  particles.update(delta);
3508
3705
  this.draw(ctx => {
3509
3706
  const width = this.#canvasManager.size.width, height = this.#canvasManager.size.height;
@@ -3525,7 +3722,9 @@
3525
3722
  }
3526
3723
  }
3527
3724
  for (const plugin of this.#getLayerPlugins(DrawLayer.BackgroundMask)) {
3528
- plugin.canvasPaint?.();
3725
+ if (plugin !== clearedPlugin) {
3726
+ plugin.canvasPaint?.();
3727
+ }
3529
3728
  }
3530
3729
  for (const plugin of this.#getLayerPlugins(DrawLayer.CanvasSetup)) {
3531
3730
  plugin.drawSettingsSetup?.(ctx, delta);
@@ -3557,35 +3756,7 @@
3557
3756
  this.#layers[layer] = [];
3558
3757
  }
3559
3758
  }
3560
- for (const plugin of this.#container.plugins) {
3561
- if (plugin.particleFillColor ?? plugin.particleStrokeColor) {
3562
- this.#colorPlugins.push(plugin);
3563
- }
3564
- if (plugin.drawParticle) {
3565
- this.#drawParticlePlugins.push(plugin);
3566
- }
3567
- if (plugin.drawParticleSetup) {
3568
- this.#drawParticlesSetupPlugins.push(plugin);
3569
- }
3570
- if (plugin.drawParticleCleanup) {
3571
- this.#drawParticlesCleanupPlugins.push(plugin);
3572
- }
3573
- if (plugin.canvasClear) {
3574
- this.#canvasClearPlugins.push(plugin);
3575
- }
3576
- if (plugin.canvasPaint) {
3577
- this.#getLayerPlugins(DrawLayer.BackgroundMask).push(plugin);
3578
- }
3579
- if (plugin.drawSettingsSetup) {
3580
- this.#getLayerPlugins(DrawLayer.CanvasSetup).push(plugin);
3581
- }
3582
- if (plugin.draw) {
3583
- this.#getLayerPlugins(DrawLayer.PluginContent).push(plugin);
3584
- }
3585
- if (plugin.clearDraw ?? plugin.drawSettingsCleanup) {
3586
- this.#getLayerPlugins(DrawLayer.CanvasCleanup).push(plugin);
3587
- }
3588
- }
3759
+ this.#initPluginsArray();
3589
3760
  }
3590
3761
  initUpdaters() {
3591
3762
  this.#preDrawUpdaters = [];
@@ -3794,6 +3965,45 @@
3794
3965
  this.#reusablePluginColors[sColorIndex] = sColor;
3795
3966
  return this.#reusablePluginColors;
3796
3967
  }
3968
+ #initLayerPlugin(plugin) {
3969
+ const layerMap = [
3970
+ [DrawLayer.BackgroundMask, !!plugin.canvasPaint],
3971
+ [DrawLayer.CanvasSetup, !!plugin.drawSettingsSetup],
3972
+ [DrawLayer.PluginContent, !!plugin.draw],
3973
+ [DrawLayer.CanvasCleanup, !!(plugin.clearDraw ?? plugin.drawSettingsCleanup)],
3974
+ ];
3975
+ for (const [layer, active] of layerMap) {
3976
+ if (active) {
3977
+ this.#layers[layer].push(plugin);
3978
+ }
3979
+ }
3980
+ }
3981
+ #initPluginsArray() {
3982
+ for (const plugin of this.#container.plugins) {
3983
+ if (plugin.particleFillColor ?? plugin.particleStrokeColor) {
3984
+ this.#colorPlugins.push(plugin);
3985
+ }
3986
+ if (plugin.drawParticle) {
3987
+ this.#drawParticlePlugins.push(plugin);
3988
+ }
3989
+ if (plugin.drawParticleSetup) {
3990
+ this.#drawParticlesSetupPlugins.push(plugin);
3991
+ }
3992
+ if (plugin.drawParticleCleanup) {
3993
+ this.#drawParticlesCleanupPlugins.push(plugin);
3994
+ }
3995
+ if (plugin.canvasClear) {
3996
+ this.#canvasClearPlugins.push(plugin);
3997
+ }
3998
+ this.#initLayerPlugin(plugin);
3999
+ }
4000
+ }
4001
+ #isSupportedElement(element) {
4002
+ return ((typeof HTMLCanvasElement !== "undefined" && element instanceof HTMLCanvasElement) ||
4003
+ (typeof OffscreenCanvas !== "undefined" && element instanceof OffscreenCanvas) ||
4004
+ (typeof HTMLVideoElement !== "undefined" && element instanceof HTMLVideoElement) ||
4005
+ (typeof HTMLImageElement !== "undefined" && element instanceof HTMLImageElement));
4006
+ }
3797
4007
  #resolveBackgroundElement() {
3798
4008
  const background = this.#container.actualOptions.background;
3799
4009
  this.#backgroundElement = null;
@@ -3803,7 +4013,7 @@
3803
4013
  if (typeof background.element === "string") {
3804
4014
  if (typeof document !== "undefined") {
3805
4015
  const node = document.querySelector(background.element);
3806
- if (node instanceof HTMLCanvasElement || node instanceof HTMLVideoElement || node instanceof HTMLImageElement) {
4016
+ if (node && this.#isSupportedElement(node)) {
3807
4017
  this.#backgroundElement = node;
3808
4018
  }
3809
4019
  else if (node) {
@@ -3814,10 +4024,7 @@
3814
4024
  }
3815
4025
  }
3816
4026
  }
3817
- else if (background.element instanceof HTMLCanvasElement ||
3818
- background.element instanceof OffscreenCanvas ||
3819
- background.element instanceof HTMLVideoElement ||
3820
- background.element instanceof HTMLImageElement) {
4027
+ else if (this.#isSupportedElement(background.element)) {
3821
4028
  this.#backgroundElement = background.element;
3822
4029
  }
3823
4030
  }
@@ -3835,7 +4042,7 @@
3835
4042
  return transferredCanvas;
3836
4043
  }
3837
4044
  if (typeof canvas.transferControlToOffscreen !== "function") {
3838
- throw new TypeError("OffscreenCanvas is required but not supported by this browser");
4045
+ throw new TypeError(getErrorMessage(ErrorCodes$2.offscreenCanvasUnsupported));
3839
4046
  }
3840
4047
  try {
3841
4048
  const offscreenCanvas = canvas.transferControlToOffscreen();
@@ -3843,10 +4050,16 @@
3843
4050
  return offscreenCanvas;
3844
4051
  }
3845
4052
  catch {
3846
- throw new TypeError("OffscreenCanvas transfer failed");
4053
+ throw new TypeError(getErrorMessage(ErrorCodes$2.offscreenCanvasTransferFailed));
3847
4054
  }
3848
4055
  }, isHtmlCanvasElement = (canvas) => {
3849
4056
  return typeof HTMLCanvasElement !== "undefined" && canvas instanceof HTMLCanvasElement;
4057
+ }, getEffectiveColorSpace = (context) => {
4058
+ if (!context) {
4059
+ return undefined;
4060
+ }
4061
+ const colorInfo = context;
4062
+ return colorInfo.getContextAttributes?.().colorSpace ?? undefined;
3850
4063
  };
3851
4064
  function setStyle(canvas, style, important = false) {
3852
4065
  if (!style) {
@@ -3885,6 +4098,7 @@
3885
4098
  zoom = defaultZoom;
3886
4099
  #container;
3887
4100
  #generated;
4101
+ #hdrMediaListeners;
3888
4102
  #mutationObserver;
3889
4103
  #originalStyle;
3890
4104
  #pluginManager;
@@ -3949,7 +4163,6 @@
3949
4163
  });
3950
4164
  this.resize();
3951
4165
  this.#initStyle();
3952
- this.initBackground();
3953
4166
  this.#safeMutationObserver(obs => {
3954
4167
  const element = this.domElement;
3955
4168
  if (!element || !(element instanceof Node)) {
@@ -3959,6 +4172,8 @@
3959
4172
  });
3960
4173
  this.initPlugins();
3961
4174
  this.#initContext();
4175
+ this.initBackground();
4176
+ this.#initHdrListeners();
3962
4177
  this.render.init();
3963
4178
  }
3964
4179
  initBackground() {
@@ -3968,7 +4183,8 @@
3968
4183
  }
3969
4184
  const elementStyle = element.style, color = rangeColorToRgb(this.#pluginManager, background.color);
3970
4185
  if (color) {
3971
- elementStyle.backgroundColor = getStyleFromRgb(color, container.actualOptions.hdr, background.opacity);
4186
+ const hdrOptions = container.actualOptions.hdr;
4187
+ elementStyle.backgroundColor = getStyleFromRgb(color, container.hdr, background.opacity, hdrOptions.peakNits, toEnumValue(HdrMode, hdrOptions.mode, HdrMode.standard));
3972
4188
  }
3973
4189
  else {
3974
4190
  elementStyle.backgroundColor = "";
@@ -4065,6 +4281,7 @@
4065
4281
  obs.disconnect();
4066
4282
  });
4067
4283
  this.#mutationObserver = undefined;
4284
+ this.#removeHdrListeners();
4068
4285
  this.render.stop();
4069
4286
  }
4070
4287
  async windowResize() {
@@ -4084,9 +4301,16 @@
4084
4301
  }
4085
4302
  }
4086
4303
  #initContext() {
4087
- const container = this.#container, canSupportHdr = container.actualOptions.hdr &&
4304
+ const container = this.#container, canSupportHdr = container.actualOptions.hdr.enable &&
4088
4305
  safeMatchMedia("(color-gamut: p3)")?.matches &&
4089
4306
  safeMatchMedia("(dynamic-range: high)")?.matches;
4307
+ container.hdrMode = toEnumValue(HdrMode, container.actualOptions.hdr.mode, HdrMode.standard);
4308
+ container.peakNits = container.actualOptions.hdr.peakNits;
4309
+ const renderCanvas = this.renderCanvas;
4310
+ if (!renderCanvas) {
4311
+ container.hdr = canSupportHdr ?? false;
4312
+ return;
4313
+ }
4090
4314
  this.render.setContextSettings({
4091
4315
  alpha: true,
4092
4316
  desynchronized: true,
@@ -4095,11 +4319,51 @@
4095
4319
  ? { colorSpace: "display-p3", colorType: "float16" }
4096
4320
  : { colorSpace: "srgb" }),
4097
4321
  });
4098
- const renderCanvas = this.renderCanvas;
4099
- if (!renderCanvas) {
4100
- return;
4322
+ let context;
4323
+ try {
4324
+ context = renderCanvas.getContext("2d", this.render.settings);
4325
+ }
4326
+ catch {
4327
+ context = null;
4328
+ }
4329
+ if (canSupportHdr && !context) {
4330
+ const sdrSettings = {
4331
+ alpha: true,
4332
+ desynchronized: true,
4333
+ willReadFrequently: false,
4334
+ colorSpace: "srgb",
4335
+ };
4336
+ this.render.setContextSettings(sdrSettings);
4337
+ try {
4338
+ context = renderCanvas.getContext("2d", sdrSettings);
4339
+ }
4340
+ catch {
4341
+ context = null;
4342
+ }
4343
+ }
4344
+ this.render.setContext(context);
4345
+ if (context) {
4346
+ const effectiveColorSpace = getEffectiveColorSpace(context);
4347
+ if (effectiveColorSpace !== undefined) {
4348
+ container.hdr = effectiveColorSpace === "display-p3";
4349
+ }
4101
4350
  }
4102
- this.render.setContext(renderCanvas.getContext("2d", this.render.settings));
4351
+ }
4352
+ #initHdrListeners() {
4353
+ this.#removeHdrListeners();
4354
+ const p3Query = safeMatchMedia("(color-gamut: p3)"), hdrQuery = safeMatchMedia("(dynamic-range: high)"), handleChange = () => {
4355
+ this.#initContext();
4356
+ this.initBackground();
4357
+ }, listeners = [];
4358
+ if (p3Query) {
4359
+ p3Query.addEventListener("change", handleChange);
4360
+ listeners.push({ handler: handleChange, mql: p3Query });
4361
+ }
4362
+ if (hdrQuery) {
4363
+ hdrQuery.addEventListener("change", handleChange);
4364
+ listeners.push({ handler: handleChange, mql: hdrQuery });
4365
+ }
4366
+ this.#hdrMediaListeners = listeners;
4103
4367
  }
4104
4368
  #initStyle() {
4105
4369
  const element = this.domElement, options = this.#container.actualOptions;
@@ -4123,6 +4387,15 @@
4123
4387
  element.style.setProperty(key, value, "important");
4124
4388
  }
4125
4389
  }
4390
+ #removeHdrListeners() {
4391
+ if (!this.#hdrMediaListeners) {
4392
+ return;
4393
+ }
4394
+ for (const { handler, mql } of this.#hdrMediaListeners) {
4395
+ mql.removeEventListener("change", handler);
4396
+ }
4397
+ this.#hdrMediaListeners = undefined;
4398
+ }
4126
4399
  #repairStyle() {
4127
4400
  const element = this.domElement;
4128
4401
  if (!element) {
@@ -4212,8 +4485,7 @@
4212
4485
  this.#resizeTimeout = undefined;
4213
4486
  }
4214
4487
  const handleResize = async () => {
4215
- const canvas = this.#container.canvas;
4216
- await canvas.windowResize();
4488
+ await this.#container.canvas.windowResize();
4217
4489
  };
4218
4490
  this.#resizeTimeout = setTimeout(() => void handleResize(), this.#container.actualOptions.resize.delay * millisecondsToSeconds);
4219
4491
  }
@@ -4241,8 +4513,8 @@
4241
4513
  }
4242
4514
  else if (!this.#resizeObserver && add && canvasEl) {
4243
4515
  this.#resizeObserver = new ResizeObserver((entries) => {
4244
- const entry = entries.find(e => e.target === canvasEl);
4245
- if (!entry) {
4516
+ const res = entries.some(e => e.target === canvasEl);
4517
+ if (!res) {
4246
4518
  return;
4247
4519
  }
4248
4520
  this.#handleWindowResize();
@@ -4506,10 +4778,10 @@
4506
4778
  return this.#modifiers.find(m => m.id === id);
4507
4779
  }
4508
4780
  getOpacity() {
4509
- 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;
4510
- this.#cachedOpacityData.fillOpacity = opacity * fillOpacity * zOpacityFactor;
4781
+ 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;
4782
+ this.#cachedOpacityData.fillOpacity = this.fillOpacity ?? defaultOpacity$1;
4511
4783
  this.#cachedOpacityData.opacity = opacity * zOpacityFactor;
4512
- this.#cachedOpacityData.strokeOpacity = opacity * strokeOpacity * zOpacityFactor;
4784
+ this.#cachedOpacityData.strokeOpacity = this.strokeOpacity ?? defaultOpacity$1;
4513
4785
  return this.#cachedOpacityData;
4514
4786
  }
4515
4787
  getPosition() {
@@ -4756,7 +5028,7 @@
4756
5028
  #initPosition(position) {
4757
5029
  const container = this.#container, zIndexValue = Math.floor(getRangeValue(this.options.zIndex.value)), initialPosition = this.#calcPosition(position, clamp(zIndexValue, minZ, container.zLayers));
4758
5030
  if (!initialPosition) {
4759
- throw new Error("a valid position cannot be found for particle");
5031
+ throw new Error(getErrorMessage(ErrorCodes$2.particlePositionNotFound));
4760
5032
  }
4761
5033
  this.position = initialPosition;
4762
5034
  this.initialPosition = this.position.copy();
@@ -4805,6 +5077,12 @@
4805
5077
  this.#circlePoolIdx = 0;
4806
5078
  this.#rectanglePoolIdx = 0;
4807
5079
  }
5080
+ get cellSize() {
5081
+ return this.#cellSize;
5082
+ }
5083
+ set cellSize(value) {
5084
+ this.#pendingCellSize = value;
5085
+ }
4808
5086
  clear() {
4809
5087
  this.#cells.clear();
4810
5088
  const pendingCellSize = this.#pendingCellSize;
@@ -4828,18 +5106,7 @@
4828
5106
  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);
4829
5107
  for (let cx = minCellX; cx <= maxCellX; cx++) {
4830
5108
  for (let cy = minCellY; cy <= maxCellY; cy++) {
4831
- const key = `${cx}_${cy}`, cellParticles = this.#cells.get(key);
4832
- if (!cellParticles) {
4833
- continue;
4834
- }
4835
- for (const p of cellParticles) {
4836
- if (check && !check(p)) {
4837
- continue;
4838
- }
4839
- if (range.contains(p.getPosition())) {
4840
- out.push(p);
4841
- }
4842
- }
5109
+ this.#queryCell(cx, cy, range, check, out);
4843
5110
  }
4844
5111
  }
4845
5112
  return out;
@@ -4854,14 +5121,23 @@
4854
5121
  this.#releaseShapes();
4855
5122
  return result;
4856
5123
  }
4857
- setCellSize(cellSize) {
4858
- this.#pendingCellSize = cellSize;
4859
- }
4860
5124
  #acquireCircle(x, y, r) {
4861
- return (this.#circlePool[this.#circlePoolIdx++] ??= new Circle(x, y, r)).reset(x, y, r);
5125
+ const idx = this.#circlePoolIdx++;
5126
+ let circle = this.#circlePool[idx];
5127
+ if (!circle) {
5128
+ circle = new Circle(x, y, r);
5129
+ this.#circlePool[idx] = circle;
5130
+ }
5131
+ return circle.reset(x, y, r);
4862
5132
  }
4863
5133
  #acquireRectangle(x, y, w, h) {
4864
- return (this.#rectanglePool[this.#rectanglePoolIdx++] ??= new Rectangle(x, y, w, h)).reset(x, y, w, h);
5134
+ const idx = this.#rectanglePoolIdx++;
5135
+ let rectangle = this.#rectanglePool[idx];
5136
+ if (!rectangle) {
5137
+ rectangle = new Rectangle(x, y, w, h);
5138
+ this.#rectanglePool[idx] = rectangle;
5139
+ }
5140
+ return rectangle.reset(x, y, w, h);
4865
5141
  }
4866
5142
  #cellKeyFromCoords(x, y) {
4867
5143
  const cellX = Math.floor(x / this.#cellSize), cellY = Math.floor(y / this.#cellSize);
@@ -4888,6 +5164,20 @@
4888
5164
  }
4889
5165
  return null;
4890
5166
  }
5167
+ #queryCell(cx, cy, range, check, out) {
5168
+ const cellParticles = this.#cells.get(`${cx}_${cy}`);
5169
+ if (!cellParticles) {
5170
+ return;
5171
+ }
5172
+ for (const p of cellParticles) {
5173
+ if (check && !check(p)) {
5174
+ continue;
5175
+ }
5176
+ if (range.contains(p.getPosition())) {
5177
+ out.push(p);
5178
+ }
5179
+ }
5180
+ }
4891
5181
  #releaseShapes() {
4892
5182
  this.#circlePoolIdx = 0;
4893
5183
  this.#rectanglePoolIdx = 0;
@@ -4896,9 +5186,9 @@
4896
5186
 
4897
5187
  class ParticlesManager {
4898
5188
  checkParticlePositionPlugins;
4899
- grid;
4900
5189
  #array;
4901
5190
  #container;
5191
+ #grid;
4902
5192
  #groupLimits;
4903
5193
  #limit;
4904
5194
  #nextId;
@@ -4922,7 +5212,7 @@
4922
5212
  this.#groupLimits = new Map();
4923
5213
  this.#particleBuckets = new Map();
4924
5214
  this.#zBuckets = this.#createBuckets(this.#container.zLayers);
4925
- this.grid = new SpatialHashGrid(spatialHashGridCellSize);
5215
+ this.#grid = new SpatialHashGrid(spatialHashGridCellSize);
4926
5216
  this.checkParticlePositionPlugins = [];
4927
5217
  this.#particleResetPlugins = [];
4928
5218
  this.#particleUpdatePlugins = [];
@@ -4933,23 +5223,12 @@
4933
5223
  get count() {
4934
5224
  return this.#array.length;
4935
5225
  }
5226
+ get grid() {
5227
+ return this.#grid;
5228
+ }
4936
5229
  addParticle(position, overrideOptions, group, initializer) {
4937
- const limitMode = this.#container.actualOptions.particles.number.limit.mode, limit = group === undefined ? this.#limit : (this.#groupLimits.get(group) ?? this.#limit), currentCount = this.count;
4938
- if (limit > minLimit) {
4939
- switch (limitMode) {
4940
- case LimitMode.delete: {
4941
- const countToRemove = currentCount + countOffset - limit;
4942
- if (countToRemove > minCount) {
4943
- this.removeQuantity(countToRemove);
4944
- }
4945
- break;
4946
- }
4947
- case LimitMode.wait:
4948
- if (currentCount >= limit) {
4949
- return;
4950
- }
4951
- break;
4952
- }
5230
+ if (this.#checkAndApplyLimits(group, this.count)) {
5231
+ return;
4953
5232
  }
4954
5233
  try {
4955
5234
  const particle = this.#pool.pop() ?? new Particle(this.#pluginManager, this.#container);
@@ -5013,7 +5292,7 @@
5013
5292
  return this.#array[index];
5014
5293
  }
5015
5294
  async init() {
5016
- const container = this.#container, options = container.actualOptions;
5295
+ const container = this.#container;
5017
5296
  this.checkParticlePositionPlugins = [];
5018
5297
  this.#updatePlugins = [];
5019
5298
  this.#particleUpdatePlugins = [];
@@ -5022,59 +5301,16 @@
5022
5301
  this.#postParticleUpdatePlugins = [];
5023
5302
  this.#particleBuckets.clear();
5024
5303
  this.#resetBuckets(container.zLayers);
5025
- this.grid = new SpatialHashGrid(spatialHashGridCellSize * container.retina.pixelRatio);
5026
- for (const plugin of container.plugins) {
5027
- if (plugin.redrawInit) {
5028
- await plugin.redrawInit();
5029
- }
5030
- if (plugin.checkParticlePosition) {
5031
- this.checkParticlePositionPlugins.push(plugin);
5032
- }
5033
- if (plugin.update) {
5034
- this.#updatePlugins.push(plugin);
5035
- }
5036
- if (plugin.particleUpdate) {
5037
- this.#particleUpdatePlugins.push(plugin);
5038
- }
5039
- if (plugin.postUpdate) {
5040
- this.#postUpdatePlugins.push(plugin);
5041
- }
5042
- if (plugin.particleReset) {
5043
- this.#particleResetPlugins.push(plugin);
5044
- }
5045
- if (plugin.postParticleUpdate) {
5046
- this.#postParticleUpdatePlugins.push(plugin);
5047
- }
5048
- }
5049
- await this.#container.initDrawersAndUpdaters();
5050
- for (const drawer of this.#container.effectDrawers.values()) {
5051
- await drawer.init?.(container);
5052
- }
5053
- for (const drawer of this.#container.shapeDrawers.values()) {
5054
- await drawer.init?.(container);
5055
- }
5056
- let handled = false;
5057
- for (const plugin of container.plugins) {
5058
- handled = plugin.particlesInitialization?.() ?? handled;
5059
- if (handled) {
5060
- break;
5061
- }
5062
- }
5063
- if (!handled) {
5064
- const particlesOptions = options.particles, groups = particlesOptions.groups;
5065
- for (const group in groups) {
5066
- const groupOptions = groups[group];
5067
- if (!groupOptions) {
5068
- continue;
5069
- }
5070
- for (let i = this.count, j = 0; j < groupOptions.number.value && i < particlesOptions.number.value; i++, j++) {
5071
- this.addParticle(undefined, groupOptions, group);
5072
- }
5073
- }
5074
- for (let i = this.count; i < particlesOptions.number.value; i++) {
5075
- this.addParticle();
5304
+ this.#grid = new SpatialHashGrid(spatialHashGridCellSize * container.retina.pixelRatio);
5305
+ this.#applyLimits(container.actualOptions.particles);
5306
+ const particlesOptions = container.actualOptions.particles, groups = particlesOptions.groups;
5307
+ for (const group in groups) {
5308
+ const groupData = groups[group];
5309
+ if (groupData) {
5310
+ this.#applyLimits(loadParticlesOptions(this.#pluginManager, this.#container, groupData), group, groupData);
5076
5311
  }
5077
5312
  }
5313
+ await this.#initPlugins();
5078
5314
  }
5079
5315
  push(nb, position, overrideOptions, group) {
5080
5316
  for (let i = 0; i < nb; i++) {
@@ -5089,13 +5325,13 @@
5089
5325
  remove(particle, group, override) {
5090
5326
  this.removeAt(this.#array.indexOf(particle), undefined, group, override);
5091
5327
  }
5092
- removeAt(index, quantity = defaultRemoveQuantity, group, override) {
5328
+ removeAt(index, quantity = defaultRemoveQuantity, group, override, matchGroup = true) {
5093
5329
  if (index < minIndex || index > this.count) {
5094
5330
  return;
5095
5331
  }
5096
5332
  let deleted = 0;
5097
5333
  for (let i = index; deleted < quantity && i < this.count; i++) {
5098
- if (this.#removeParticle(i, group, override)) {
5334
+ if (this.#removeParticle(i, group, override, matchGroup)) {
5099
5335
  i--;
5100
5336
  deleted++;
5101
5337
  }
@@ -5126,7 +5362,7 @@
5126
5362
  this.#resizeFactor = factor;
5127
5363
  }
5128
5364
  update(delta) {
5129
- this.grid.clear();
5365
+ this.#grid.clear();
5130
5366
  for (const plugin of this.#updatePlugins) {
5131
5367
  plugin.update?.(delta);
5132
5368
  }
@@ -5137,7 +5373,7 @@
5137
5373
  this.#updateParticlesPhase2(delta, particlesToDelete);
5138
5374
  if (particlesToDelete.size) {
5139
5375
  for (const particle of particlesToDelete) {
5140
- this.remove(particle);
5376
+ this.remove(particle, particle.group);
5141
5377
  }
5142
5378
  }
5143
5379
  this.#resizeFactor = undefined;
@@ -5148,12 +5384,7 @@
5148
5384
  #applyDensity(options, pluginsCount, group, groupOptions) {
5149
5385
  const numberOptions = options.number;
5150
5386
  if (!numberOptions.density.enable) {
5151
- if (group === undefined) {
5152
- this.#limit = numberOptions.limit.value;
5153
- }
5154
- else if (groupOptions?.number.limit.value ?? numberOptions.limit.value) {
5155
- this.#groupLimits.set(group, groupOptions?.number.limit.value ?? numberOptions.limit.value);
5156
- }
5387
+ this.#applyLimits(options, group, groupOptions);
5157
5388
  return;
5158
5389
  }
5159
5390
  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);
@@ -5161,7 +5392,10 @@
5161
5392
  this.#limit = numberOptions.limit.value * densityFactor;
5162
5393
  }
5163
5394
  else {
5164
- this.#groupLimits.set(group, numberOptions.limit.value * densityFactor);
5395
+ this.#groupLimits.set(group, {
5396
+ limit: numberOptions.limit.value * densityFactor,
5397
+ mode: toEnumValue(LimitMode, numberOptions.limit.mode, LimitMode.delete),
5398
+ });
5165
5399
  }
5166
5400
  if (particlesCount < particlesNumber) {
5167
5401
  this.push(Math.abs(particlesNumber - particlesCount), undefined, options, group);
@@ -5170,6 +5404,55 @@
5170
5404
  this.removeQuantity(particlesCount - particlesNumber, group);
5171
5405
  }
5172
5406
  }
5407
+ #applyLimits(options, group, groupOptions) {
5408
+ if (group === undefined) {
5409
+ this.#limit = options.number.limit.value;
5410
+ const groups = this.#container.actualOptions.particles.groups;
5411
+ for (const existingGroup of this.#groupLimits.keys()) {
5412
+ if (!(existingGroup in groups)) {
5413
+ this.#groupLimits.delete(existingGroup);
5414
+ }
5415
+ }
5416
+ }
5417
+ else {
5418
+ const limitValue = groupOptions?.number?.limit?.value ?? options.number.limit.value;
5419
+ if (limitValue > minLimit) {
5420
+ this.#groupLimits.set(group, {
5421
+ limit: limitValue,
5422
+ mode: toEnumValue(LimitMode, groupOptions?.number?.limit?.mode ?? options.number.limit.mode, LimitMode.delete),
5423
+ });
5424
+ }
5425
+ else {
5426
+ this.#groupLimits.delete(group);
5427
+ }
5428
+ }
5429
+ }
5430
+ #checkAndApplyLimits(group, currentCount) {
5431
+ const globalLimit = this.#limit, globalMode = this.#container.actualOptions.particles.number.limit.mode;
5432
+ if (globalLimit > minLimit && globalMode === LimitMode.wait && currentCount >= globalLimit) {
5433
+ return true;
5434
+ }
5435
+ const groupLimitEntry = group === undefined ? undefined : this.#groupLimits.get(group);
5436
+ if (groupLimitEntry && groupLimitEntry.limit > minLimit && groupLimitEntry.mode === LimitMode.wait) {
5437
+ const groupCount = this.filter(t => t.group === group).length;
5438
+ if (groupCount >= groupLimitEntry.limit) {
5439
+ return true;
5440
+ }
5441
+ }
5442
+ if (groupLimitEntry && groupLimitEntry.limit > minLimit && groupLimitEntry.mode === LimitMode.delete) {
5443
+ const groupCountToRemove = this.filter(t => t.group === group).length + countOffset - groupLimitEntry.limit;
5444
+ if (groupCountToRemove > minCount) {
5445
+ this.removeQuantity(groupCountToRemove, group);
5446
+ }
5447
+ }
5448
+ if (globalLimit > minLimit && globalMode === LimitMode.delete) {
5449
+ const globalCountToRemove = this.count + countOffset - globalLimit;
5450
+ if (globalCountToRemove > minCount) {
5451
+ this.#removeAny(globalCountToRemove);
5452
+ }
5453
+ }
5454
+ return false;
5455
+ }
5173
5456
  #createBuckets(zLayers) {
5174
5457
  const bucketCount = Math.max(Math.floor(zLayers), one);
5175
5458
  return Array.from({ length: bucketCount }, () => []);
@@ -5192,6 +5475,70 @@
5192
5475
  }
5193
5476
  return ((canvasSize.width * canvasSize.height) / (densityOptions.height * densityOptions.width * pxRatio ** squareExp));
5194
5477
  }
5478
+ async #initDrawersAndUpdaters() {
5479
+ const container = this.#container;
5480
+ await container.initDrawersAndUpdaters();
5481
+ for (const drawer of container.effectDrawers.values()) {
5482
+ await drawer.init?.(container);
5483
+ }
5484
+ for (const drawer of container.shapeDrawers.values()) {
5485
+ await drawer.init?.(container);
5486
+ }
5487
+ }
5488
+ async #initPlugins() {
5489
+ await this.#initPluginsArrays();
5490
+ await this.#initDrawersAndUpdaters();
5491
+ let handled = false;
5492
+ const container = this.#container;
5493
+ for (const plugin of container.plugins) {
5494
+ handled = plugin.particlesInitialization?.() ?? handled;
5495
+ if (handled) {
5496
+ break;
5497
+ }
5498
+ }
5499
+ if (handled) {
5500
+ return;
5501
+ }
5502
+ const particlesOptions = container.actualOptions.particles, groups = particlesOptions.groups;
5503
+ for (const group in groups) {
5504
+ const groupOptions = groups[group];
5505
+ if (!groupOptions) {
5506
+ continue;
5507
+ }
5508
+ for (let i = this.count, j = 0; j < groupOptions.number.value && i < particlesOptions.number.value; i++, j++) {
5509
+ this.addParticle(undefined, groupOptions, group);
5510
+ }
5511
+ }
5512
+ for (let i = this.count; i < particlesOptions.number.value; i++) {
5513
+ this.addParticle();
5514
+ }
5515
+ }
5516
+ async #initPluginsArrays() {
5517
+ const container = this.#container;
5518
+ for (const plugin of container.plugins) {
5519
+ if (plugin.redrawInit) {
5520
+ await plugin.redrawInit();
5521
+ }
5522
+ if (plugin.checkParticlePosition) {
5523
+ this.checkParticlePositionPlugins.push(plugin);
5524
+ }
5525
+ if (plugin.update) {
5526
+ this.#updatePlugins.push(plugin);
5527
+ }
5528
+ if (plugin.particleUpdate) {
5529
+ this.#particleUpdatePlugins.push(plugin);
5530
+ }
5531
+ if (plugin.postUpdate) {
5532
+ this.#postUpdatePlugins.push(plugin);
5533
+ }
5534
+ if (plugin.particleReset) {
5535
+ this.#particleResetPlugins.push(plugin);
5536
+ }
5537
+ if (plugin.postParticleUpdate) {
5538
+ this.#postParticleUpdatePlugins.push(plugin);
5539
+ }
5540
+ }
5541
+ }
5195
5542
  #insertParticleIntoBucket(particle) {
5196
5543
  const bucketIndex = this.#getBucketIndex(particle.position.z), bucket = this.#zBuckets[bucketIndex];
5197
5544
  if (!bucket) {
@@ -5200,12 +5547,15 @@
5200
5547
  bucket.push(particle);
5201
5548
  this.#particleBuckets.set(particle.id, bucketIndex);
5202
5549
  }
5203
- #removeParticle(index, group, override) {
5550
+ #removeAny(quantity) {
5551
+ this.removeAt(minIndex, quantity, undefined, undefined, false);
5552
+ }
5553
+ #removeParticle(index, group, override, matchGroup = true) {
5204
5554
  const particle = this.#array[index];
5205
5555
  if (!particle) {
5206
5556
  return false;
5207
5557
  }
5208
- if (particle.group !== group) {
5558
+ if (matchGroup && particle.group !== group) {
5209
5559
  return false;
5210
5560
  }
5211
5561
  this.#array.splice(index, deleteCount);
@@ -5292,7 +5642,7 @@
5292
5642
  particlesToDelete.add(particle);
5293
5643
  continue;
5294
5644
  }
5295
- this.grid.insert(particle);
5645
+ this.#grid.insert(particle);
5296
5646
  }
5297
5647
  return particlesToDelete;
5298
5648
  }
@@ -5364,6 +5714,7 @@
5364
5714
  effectDrawers;
5365
5715
  fpsLimit;
5366
5716
  hdr;
5717
+ hdrMode;
5367
5718
  id;
5368
5719
  pageHidden;
5369
5720
  particleCreatedPlugins;
@@ -5371,6 +5722,7 @@
5371
5722
  particlePositionPlugins;
5372
5723
  particleUpdaters;
5373
5724
  particles;
5725
+ peakNits;
5374
5726
  plugins;
5375
5727
  retina;
5376
5728
  shapeDrawers;
@@ -5401,6 +5753,8 @@
5401
5753
  this.id = Symbol(id);
5402
5754
  this.fpsLimit = 120;
5403
5755
  this.hdr = false;
5756
+ this.hdrMode = HdrMode.standard;
5757
+ this.peakNits = 400;
5404
5758
  this.#smooth = false;
5405
5759
  this.#delay = 0;
5406
5760
  this.#duration = 0;
@@ -5464,7 +5818,6 @@
5464
5818
  this.shapeDrawers = new Map();
5465
5819
  this.particleUpdaters = [];
5466
5820
  this.plugins.length = 0;
5467
- this.#pluginManager.clearPlugins(this);
5468
5821
  this.destroyed = true;
5469
5822
  this.#onDestroy(remove);
5470
5823
  this.dispatchEvent(EventType.containerDestroyed);
@@ -5517,31 +5870,15 @@
5517
5870
  await this.initDrawersAndUpdaters();
5518
5871
  this.#options = loadContainerOptions(this.#pluginManager, this, this.#initialSourceOptions, this.sourceOptions);
5519
5872
  this.actualOptions = loadContainerOptions(this.#pluginManager, this, this.#options);
5520
- this.plugins.length = 0;
5521
- this.particleDestroyedPlugins.length = 0;
5522
- this.particleCreatedPlugins.length = 0;
5523
- this.particlePositionPlugins.length = 0;
5524
- for (const [plugin, containerPlugin] of allContainerPlugins) {
5525
- if (plugin.needsPlugin(this.actualOptions)) {
5526
- this.plugins.push(containerPlugin);
5527
- if (containerPlugin.particleCreated) {
5528
- this.particleCreatedPlugins.push(containerPlugin);
5529
- }
5530
- if (containerPlugin.particleDestroyed) {
5531
- this.particleDestroyedPlugins.push(containerPlugin);
5532
- }
5533
- if (containerPlugin.particlePosition) {
5534
- this.particlePositionPlugins.push(containerPlugin);
5535
- }
5536
- }
5537
- }
5873
+ this.#initPlugins(allContainerPlugins);
5538
5874
  this.retina.init();
5539
5875
  this.canvas.init();
5540
5876
  this.updateActualOptions();
5541
5877
  this.canvas.initBackground();
5542
5878
  this.canvas.resize();
5543
- const { delay, duration, fpsLimit, hdr, smooth, zLayers } = this.actualOptions;
5544
- this.hdr = hdr;
5879
+ const { delay, duration, fpsLimit, smooth, zLayers } = this.actualOptions, hdrOptions = this.actualOptions.hdr;
5880
+ this.hdrMode = toEnumValue(HdrMode, hdrOptions.mode, HdrMode.standard);
5881
+ this.peakNits = hdrOptions.peakNits;
5545
5882
  this.zLayers = zLayers;
5546
5883
  this.#duration = getRangeValue(duration) * millisecondsToSeconds;
5547
5884
  this.#delay = getRangeValue(delay) * millisecondsToSeconds;
@@ -5561,9 +5898,9 @@
5561
5898
  }
5562
5899
  async initDrawersAndUpdaters() {
5563
5900
  const pluginManager = this.#pluginManager;
5564
- this.effectDrawers = await pluginManager.getEffectDrawers(this, true);
5565
- this.shapeDrawers = await pluginManager.getShapeDrawers(this, true);
5566
- this.particleUpdaters = await pluginManager.getUpdaters(this, true);
5901
+ this.effectDrawers = await getItemMapFromInitializer(this, pluginManager.initializers.effects);
5902
+ this.shapeDrawers = await getItemMapFromInitializer(this, pluginManager.initializers.shapes);
5903
+ this.particleUpdaters = await getItemsFromInitializer(this, pluginManager.initializers.updaters);
5567
5904
  }
5568
5905
  pause() {
5569
5906
  if (!guardCheck(this)) {
@@ -5674,6 +6011,27 @@
5674
6011
  }
5675
6012
  return refresh;
5676
6013
  }
6014
+ #initPlugins(allContainerPlugins) {
6015
+ this.plugins.length = 0;
6016
+ this.particleDestroyedPlugins.length = 0;
6017
+ this.particleCreatedPlugins.length = 0;
6018
+ this.particlePositionPlugins.length = 0;
6019
+ for (const [plugin, containerPlugin] of allContainerPlugins) {
6020
+ if (!plugin.needsPlugin(this.actualOptions)) {
6021
+ continue;
6022
+ }
6023
+ this.plugins.push(containerPlugin);
6024
+ if (containerPlugin.particleCreated) {
6025
+ this.particleCreatedPlugins.push(containerPlugin);
6026
+ }
6027
+ if (containerPlugin.particleDestroyed) {
6028
+ this.particleDestroyedPlugins.push(containerPlugin);
6029
+ }
6030
+ if (containerPlugin.particlePosition) {
6031
+ this.particlePositionPlugins.push(containerPlugin);
6032
+ }
6033
+ }
6034
+ }
5677
6035
  #nextFrame(timestamp) {
5678
6036
  try {
5679
6037
  if (!this.#smooth &&
@@ -5950,11 +6308,11 @@
5950
6308
  }
5951
6309
  }
5952
6310
  async #init() {
5953
- const availablePathGenerators = await this.#pluginManager.getPathGenerators?.(this.#container, true);
5954
- if (!availablePathGenerators) {
6311
+ const pluginManager = this.#pluginManager;
6312
+ if (!pluginManager.initializers.pathGenerators) {
5955
6313
  return;
5956
6314
  }
5957
- this.availablePathGenerators = availablePathGenerators;
6315
+ this.availablePathGenerators = await getItemMapFromInitializer(this.#container, pluginManager.initializers.pathGenerators);
5958
6316
  this.pathGenerators = new Map();
5959
6317
  for (const pathGenerator of this.pathGenerators.values()) {
5960
6318
  pathGenerator.init();
@@ -5975,6 +6333,11 @@
5975
6333
  this.#container = container;
5976
6334
  this.#instancesManager.initContainer(container);
5977
6335
  }
6336
+ draw(context, _delta) {
6337
+ for (const emitter of this.#instancesManager.getArray(this.#container)) {
6338
+ emitter.draw(context);
6339
+ }
6340
+ }
5978
6341
  async init() {
5979
6342
  const emittersOptions = this.#container.actualOptions.emitters;
5980
6343
  if (isArray(emittersOptions)) {
@@ -6045,14 +6408,21 @@
6045
6408
  this.#pluginManager = pluginManager;
6046
6409
  }
6047
6410
  async addEmitter(container, options, position) {
6048
- const emitterOptions = new Emitter();
6049
- emitterOptions.load(options);
6050
- const { EmitterInstance } = await Promise.resolve().then(function () { return EmitterInstance$1; }), emitter = new EmitterInstance(this.#pluginManager, container, (emitter) => {
6051
- this.removeEmitter(container, emitter);
6052
- }, emitterOptions, position);
6053
- await emitter.init();
6054
- this.getArray(container).push(emitter);
6055
- return emitter;
6411
+ return this.addEmitters(container, [{ options, position }]).then(t => t[defaultIndex]);
6412
+ }
6413
+ async addEmitters(container, emitters) {
6414
+ const { EmitterInstance } = await Promise.resolve().then(function () { return EmitterInstance$1; }), res = [];
6415
+ for (const { options, position } of emitters) {
6416
+ const emitterOptions = new Emitter();
6417
+ emitterOptions.load(options);
6418
+ const emitter = new EmitterInstance(this.#pluginManager, container, (emitter) => {
6419
+ this.removeEmitter(container, emitter);
6420
+ }, emitterOptions, position);
6421
+ await emitter.init();
6422
+ this.getArray(container).push(emitter);
6423
+ res.push(emitter);
6424
+ }
6425
+ return res;
6056
6426
  }
6057
6427
  clear(container) {
6058
6428
  this.initContainer(container);
@@ -6079,6 +6449,7 @@
6079
6449
  : array.find(t => t.name === idxOrName);
6080
6450
  };
6081
6451
  container.addEmitter = async (options, position) => this.addEmitter(container, options, position);
6452
+ container.addEmitters = async (emitters) => this.addEmitters(container, emitters);
6082
6453
  container.removeEmitter = (idxOrName) => {
6083
6454
  const emitter = container.getEmitter?.(idxOrName);
6084
6455
  if (emitter) {
@@ -6099,7 +6470,7 @@
6099
6470
  };
6100
6471
  }
6101
6472
  removeEmitter(container, emitter) {
6102
- const index = this.getArray(container).indexOf(emitter), minIndex = 0, deleteCount = 1;
6473
+ const index = this.getArray(container).indexOf(emitter), deleteCount = 1;
6103
6474
  if (index >= minIndex) {
6104
6475
  this.getArray(container).splice(index, deleteCount);
6105
6476
  }
@@ -6154,6 +6525,7 @@
6154
6525
  #particlesOptions;
6155
6526
  #paused;
6156
6527
  #pluginManager;
6528
+ #positionOverride = false;
6157
6529
  #removeCallback;
6158
6530
  #resizeObserver;
6159
6531
  #shape;
@@ -6230,6 +6602,31 @@
6230
6602
  });
6231
6603
  this.play();
6232
6604
  }
6605
+ draw(context) {
6606
+ if (!this.options.draw || !this.#shape) {
6607
+ return;
6608
+ }
6609
+ const container = this.#container, fillEnabled = this.options.spawn.fill?.enable ?? true;
6610
+ context.save();
6611
+ context.beginPath();
6612
+ if (fillEnabled) {
6613
+ context.fillStyle = this.spawnFillColor
6614
+ ? getStyleFromHsl(this.spawnFillColor, container.hdr, this.spawnFillOpacity ?? defaultOpacity$1, container.peakNits, container.hdrMode)
6615
+ : getStyleFromRgb({ r: 0, g: 0, b: 0 }, container.hdr, defaultOpacity$1, container.peakNits, container.hdrMode);
6616
+ }
6617
+ if (this.spawnStrokeColor) {
6618
+ context.strokeStyle = getStyleFromHsl(this.spawnStrokeColor, container.hdr, this.spawnStrokeOpacity ?? defaultOpacity$1, container.peakNits, container.hdrMode);
6619
+ context.lineWidth = this.spawnStrokeWidth ?? defaultStrokeWidth;
6620
+ }
6621
+ this.#shape.draw?.(context);
6622
+ if (fillEnabled) {
6623
+ context.fill();
6624
+ }
6625
+ if (this.spawnStrokeColor) {
6626
+ context.stroke();
6627
+ }
6628
+ context.restore();
6629
+ }
6233
6630
  externalPause() {
6234
6631
  this.#paused = true;
6235
6632
  this.pause();
@@ -6267,11 +6664,14 @@
6267
6664
  }
6268
6665
  }
6269
6666
  resize() {
6270
- const initialPosition = this.#initialPosition, container = this.#container;
6271
- this.position =
6272
- initialPosition && isPointInside(initialPosition, container.canvas.size, Vector.origin)
6273
- ? initialPosition
6274
- : this.#calcPosition();
6667
+ const container = this.#container;
6668
+ if (!this.#positionOverride) {
6669
+ const initialPosition = this.#initialPosition;
6670
+ this.position =
6671
+ initialPosition && isPointInside(initialPosition, container.canvas.size, Vector.origin)
6672
+ ? initialPosition
6673
+ : this.#calcPosition();
6674
+ }
6275
6675
  this.#size = this.#calcSize();
6276
6676
  this.size =
6277
6677
  this.#size.mode === PixelMode.percent
@@ -6282,6 +6682,11 @@
6282
6682
  : { width: this.#size.width, height: this.#size.height };
6283
6683
  this.#shape?.resize(this.position, this.size);
6284
6684
  }
6685
+ setPosition(position) {
6686
+ this.#positionOverride = true;
6687
+ this.position = { ...position };
6688
+ this.#shape?.resize(this.position, this.size);
6689
+ }
6285
6690
  update(delta) {
6286
6691
  if (this.#paused) {
6287
6692
  return;
@@ -6477,6 +6882,7 @@
6477
6882
  exports.loadBubblesPreset = loadBubblesPreset;
6478
6883
  exports.tsParticles = tsParticles;
6479
6884
 
6480
- }));
6885
+ })(g.__tsParticlesInternals.presets.bubbles = g.__tsParticlesInternals.presets.bubbles || {});
6886
+ })(typeof globalThis !== "undefined" ? globalThis : typeof window !== "undefined" ? window : self);
6887
+
6481
6888
  Object.assign(globalThis.window || globalThis, { loadBubblesPreset: (globalThis.__tsParticlesInternals.presets.bubbles || {}).loadBubblesPreset });
6482
- delete (globalThis.window || globalThis).tsparticlesInternalExports;