@tsparticles/particles 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,58 @@
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
- /* tsParticles 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.bundles = global.__tsParticlesInternals.bundles || {}, global.__tsParticlesInternals.bundles.particles = global.__tsParticlesInternals.bundles.particles || {})));
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", midColorValue = "mid", double = 2, doublePI = Math.PI * double, defaultFps = 60, defaultAlpha$1 = 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$2 = 0, minRadius$1 = 0, defaultTransformValue = 1, minimumSize = 0, zIndexFactorOffset = 1, defaultOpacity$2 = 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, lengthOffset = 1, 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
+ /* tsParticles v4.5.0 */
4
+ g.__tsParticlesInternals = g.__tsParticlesInternals || {};
5
+ g.__tsParticlesInternals.bundles = g.__tsParticlesInternals.bundles || {};
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 setLogger(logger) {
31
+ if (logger.debug) {
32
+ _logger.debug = wrap(logger.debug);
33
+ }
34
+ if (logger.error) {
35
+ _logger.error = wrap(logger.error);
36
+ }
37
+ if (logger.info) {
38
+ _logger.info = wrap(logger.info);
39
+ }
40
+ if (logger.log) {
41
+ _logger.log = wrap(logger.log);
42
+ }
43
+ if (logger.trace) {
44
+ _logger.trace = wrap(logger.trace);
45
+ }
46
+ if (logger.verbose) {
47
+ _logger.verbose = wrap(logger.verbose);
48
+ }
49
+ if (logger.warning) {
50
+ _logger.warning = wrap(logger.warning);
51
+ }
52
+ }
53
+ function getLogger() {
54
+ return _logger;
55
+ }
19
56
 
20
57
  exports.MoveDirection = void 0;
21
58
  (function (MoveDirection) {
@@ -32,6 +69,17 @@
32
69
  MoveDirection["inside"] = "inside";
33
70
  })(exports.MoveDirection || (exports.MoveDirection = {}));
34
71
 
72
+ const generatedAttribute = "generated", fullPercent = "100%", defaultCompositeValue = "source-over", resizeEvent = "resize", visibilityChangeEvent = "visibilitychange", percentDenominator = 100, half = 0.5, millisecondsToSeconds = 1000, originPoint = {
73
+ x: 0,
74
+ y: 0,
75
+ z: 0,
76
+ }, defaultTransform = {
77
+ a: 1,
78
+ b: 0,
79
+ c: 0,
80
+ d: 1,
81
+ }, randomColorValue = "random", midColorValue = "mid", 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$2 = 0, minRadius = 0, defaultTransformValue = 1, minimumSize = 0, zIndexFactorOffset = 1, defaultOpacity$2 = 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, lengthOffset = 1, 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;
82
+
35
83
  function getZ(source) {
36
84
  return "z" in source ? source.z : originPoint.z;
37
85
  }
@@ -150,6 +198,12 @@
150
198
  function isFunction(arg) {
151
199
  return typeof arg === "function";
152
200
  }
201
+ function isEnumValue(enumObject, arg) {
202
+ return Object.values(enumObject).some(enumValue => enumValue === arg);
203
+ }
204
+ function toEnumValue(enumObject, arg, defaultValue) {
205
+ return isEnumValue(enumObject, arg) ? arg : defaultValue;
206
+ }
153
207
  function isObject(arg) {
154
208
  return typeof arg === "object" && arg !== null;
155
209
  }
@@ -310,11 +364,61 @@
310
364
  };
311
365
  }
312
366
  function parseAlpha(input) {
313
- const defaultAlpha = 1;
314
367
  if (!input) {
315
368
  return defaultAlpha;
316
369
  }
317
- return input.endsWith("%") ? parseFloat(input) / percentDenominator : parseFloat(input);
370
+ return input.endsWith("%") ? Number.parseFloat(input) / percentDenominator : Number.parseFloat(input);
371
+ }
372
+
373
+ const ErrorCodes$3 = {
374
+ engineVersionMismatch: "TSP-1001",
375
+ particlePositionNotFound: "TSP-1002",
376
+ pluginRegisterAfterLoad: "TSP-1003",
377
+ offscreenCanvasUnsupported: "TSP-1101",
378
+ offscreenCanvasTransferFailed: "TSP-1102",
379
+ hdrEnableInvalid: "TSP-1201",
380
+ hdrModeInvalid: "TSP-1202",
381
+ hdrPeakNitsInvalid: "TSP-1203",
382
+ };
383
+
384
+ const messages = {
385
+ [ErrorCodes$3.engineVersionMismatch]: "The tsParticles version is different from the loaded plugins version. Engine version: {0}. Plugin version: {1}",
386
+ [ErrorCodes$3.particlePositionNotFound]: "a valid position cannot be found for particle",
387
+ [ErrorCodes$3.pluginRegisterAfterLoad]: "Register plugins can only be done before calling tsParticles.load()",
388
+ [ErrorCodes$3.offscreenCanvasUnsupported]: "OffscreenCanvas is required but not supported by this browser",
389
+ [ErrorCodes$3.offscreenCanvasTransferFailed]: "OffscreenCanvas transfer failed",
390
+ [ErrorCodes$3.hdrEnableInvalid]: 'Invalid HDR "enable" value: expected a boolean, got "{0}"',
391
+ [ErrorCodes$3.hdrModeInvalid]: 'Invalid HDR "mode" value: expected one of {0}, got "{1}"',
392
+ [ErrorCodes$3.hdrPeakNitsInvalid]: 'Invalid HDR "peakNits" value: expected a positive number, got "{0}"',
393
+ };
394
+
395
+ let registeredMessages;
396
+ const ensureRegisteredMessages = () => {
397
+ registeredMessages ??= new Map(Object.entries(messages));
398
+ return registeredMessages;
399
+ }, toStringValue$1 = (value) => String(value), format = (template, args) => {
400
+ return template.replace(/\{(\d+)\}/g, (match, index) => {
401
+ const arg = args[Number(index)];
402
+ return arg === undefined ? match : toStringValue$1(arg);
403
+ });
404
+ };
405
+ function addErrorMessages(extraMessages) {
406
+ if (typeof process !== "undefined" && process.env.NODE_ENV === "production") {
407
+ return;
408
+ }
409
+ const catalog = ensureRegisteredMessages();
410
+ for (const [code, message] of Object.entries(extraMessages)) {
411
+ if (message !== undefined) {
412
+ catalog.set(code, message);
413
+ }
414
+ }
415
+ }
416
+ function getErrorMessage(code, ...args) {
417
+ if (typeof process !== "undefined" && process.env.NODE_ENV === "production") {
418
+ return `[tsParticles Error ${code}] https://particles.js.org/errors/#${code}`;
419
+ }
420
+ const template = ensureRegisteredMessages().get(code) ?? `Unknown error code ${code}`;
421
+ return format(template, args);
318
422
  }
319
423
 
320
424
  exports.OutModeDirection = void 0;
@@ -331,7 +435,6 @@
331
435
  PixelMode["percent"] = "percent";
332
436
  })(exports.PixelMode || (exports.PixelMode = {}));
333
437
 
334
- const minRadius = 0;
335
438
  function isForbiddenKey(key) {
336
439
  return key === "__proto__" || key === "constructor" || key === "prototype";
337
440
  }
@@ -547,22 +650,84 @@
547
650
  element.removeEventListener(event, handler, removeOptions);
548
651
  }
549
652
  }
550
- async function getItemsFromInitializer(container, map, initializers, force = false) {
551
- let res = map.get(container);
552
- if (!res || force) {
553
- res = await Promise.all([...initializers.values()].map(t => t(container)));
554
- map.set(container, res);
653
+ async function getItemsFromInitializer(container, initializers) {
654
+ return await Promise.all([...initializers.values()].map(t => t(container)));
655
+ }
656
+ async function getItemMapFromInitializer(container, initializers) {
657
+ const entries = await Promise.all([...initializers.entries()].map(([key, initializer]) => initializer(container).then(item => [key, item])));
658
+ return new Map(entries);
659
+ }
660
+ async function getDataFromUrl(data) {
661
+ const url = itemFromSingleOrMultiple(data.url, data.index);
662
+ if (!url) {
663
+ return data.fallback;
555
664
  }
556
- return res;
665
+ try {
666
+ const response = await fetch(url);
667
+ if (response.ok) {
668
+ const current = (await response.json());
669
+ if (isSourceOptionsValue(current)) {
670
+ return current;
671
+ }
672
+ getLogger().error("invalid configuration data while retrieving config file");
673
+ }
674
+ else {
675
+ getLogger().error(`${response.status.toString()} while retrieving config file`);
676
+ }
677
+ }
678
+ catch (error) {
679
+ getLogger().error(`error while retrieving config file: ${error}`);
680
+ }
681
+ return data.fallback;
557
682
  }
558
- async function getItemMapFromInitializer(container, map, initializers, force = false) {
559
- let res = map.get(container);
560
- if (!res || force) {
561
- const entries = await Promise.all([...initializers.entries()].map(([key, initializer]) => initializer(container).then(item => [key, item])));
562
- res = new Map(entries);
563
- map.set(container, res);
683
+ function isSourceOptionsValue(value) {
684
+ if (isArray(value)) {
685
+ return value.every((entry) => isObject(entry) && !isArray(entry));
564
686
  }
565
- return res;
687
+ return isObject(value) && !isArray(value);
688
+ }
689
+ function getCanvasFromContainer(domContainer) {
690
+ let canvasEl;
691
+ const documentSafe = safeDocument(), isCanvas = domContainer instanceof HTMLCanvasElement || domContainer.tagName.toLowerCase() === canvasTag;
692
+ if (isCanvas) {
693
+ canvasEl = domContainer;
694
+ canvasEl.dataset[generatedAttribute] ??= generatedFalse;
695
+ if (canvasEl.dataset[generatedAttribute] === generatedTrue) {
696
+ canvasEl.style.width ||= fullPercent;
697
+ canvasEl.style.height ||= fullPercent;
698
+ canvasEl.style.pointerEvents = "none";
699
+ canvasEl.style.setProperty("pointer-events", "none");
700
+ }
701
+ }
702
+ else {
703
+ const existingCanvases = domContainer.getElementsByTagName(canvasTag), foundCanvas = existingCanvases.item(canvasFirstIndex);
704
+ if (foundCanvas) {
705
+ canvasEl = foundCanvas;
706
+ canvasEl.dataset[generatedAttribute] = generatedFalse;
707
+ }
708
+ else {
709
+ canvasEl = documentSafe.createElement(canvasTag);
710
+ canvasEl.dataset[generatedAttribute] = generatedTrue;
711
+ domContainer.appendChild(canvasEl);
712
+ }
713
+ canvasEl.style.width ||= fullPercent;
714
+ canvasEl.style.height ||= fullPercent;
715
+ canvasEl.style.pointerEvents = "none";
716
+ canvasEl.style.setProperty("pointer-events", "none");
717
+ }
718
+ return canvasEl;
719
+ }
720
+ function getDomContainer(id, source) {
721
+ const documentSafe = safeDocument();
722
+ let domContainer = source ?? documentSafe.getElementById(id);
723
+ if (domContainer) {
724
+ return domContainer;
725
+ }
726
+ domContainer = documentSafe.createElement("canvas");
727
+ domContainer.id = id;
728
+ domContainer.dataset[generatedAttribute] = generatedTrue;
729
+ documentSafe.body.append(domContainer);
730
+ return domContainer;
566
731
  }
567
732
 
568
733
  class EventDispatcher {
@@ -633,7 +798,6 @@
633
798
  class PluginManager {
634
799
  colorManagers = new Map();
635
800
  easingFunctions = new Map();
636
- effectDrawers = new Map();
637
801
  initializers = {
638
802
  effects: new Map(),
639
803
  shapes: new Map(),
@@ -642,8 +806,6 @@
642
806
  palettes = new Map();
643
807
  plugins = [];
644
808
  presets = new Map();
645
- shapeDrawers = new Map();
646
- updaters = new Map();
647
809
  #allLoadersSet = new Set();
648
810
  #configs = new Map();
649
811
  #engine;
@@ -661,57 +823,79 @@
661
823
  }
662
824
  return res;
663
825
  }
826
+ get initialized() {
827
+ return this.#initialized;
828
+ }
664
829
  addColorManager(name, manager) {
830
+ if (this.#initialized) {
831
+ return;
832
+ }
665
833
  this.colorManagers.set(name, manager);
666
834
  }
667
835
  addConfig(config) {
836
+ if (this.#initialized) {
837
+ return;
838
+ }
668
839
  const key = config.key ?? config.name ?? "default";
669
840
  this.#configs.set(key, config);
670
841
  this.#engine.dispatchEvent(exports.EventType.configAdded, { data: { name: key, config } });
671
842
  }
672
843
  addEasing(name, easing) {
844
+ if (this.#initialized) {
845
+ return;
846
+ }
673
847
  if (this.easingFunctions.get(name)) {
674
848
  return;
675
849
  }
676
850
  this.easingFunctions.set(name, easing);
677
851
  }
678
852
  addEffect(effect, drawer) {
853
+ if (this.#initialized) {
854
+ return;
855
+ }
679
856
  this.initializers.effects.set(effect, drawer);
680
857
  }
681
858
  addPalette(name, palette) {
859
+ if (this.#initialized) {
860
+ return;
861
+ }
682
862
  this.palettes.set(name, palette);
683
863
  }
684
864
  addParticleUpdater(name, updaterInitializer) {
865
+ if (this.#initialized) {
866
+ return;
867
+ }
685
868
  this.initializers.updaters.set(name, updaterInitializer);
686
869
  }
687
870
  addPlugin(plugin) {
871
+ if (this.#initialized) {
872
+ return;
873
+ }
688
874
  if (this.getPlugin(plugin.id)) {
689
875
  return;
690
876
  }
691
877
  this.plugins.push(plugin);
692
878
  }
693
879
  addPreset(preset, options, override = false) {
880
+ if (this.#initialized) {
881
+ return;
882
+ }
694
883
  if (!(override || !this.getPreset(preset))) {
695
884
  return;
696
885
  }
697
886
  this.presets.set(preset, options);
698
887
  }
699
888
  addShape(shapes, drawer) {
889
+ if (this.#initialized) {
890
+ return;
891
+ }
700
892
  for (const shape of shapes) {
701
893
  this.initializers.shapes.set(shape, drawer);
702
894
  }
703
895
  }
704
- clearPlugins(container) {
705
- this.effectDrawers.delete(container);
706
- this.shapeDrawers.delete(container);
707
- this.updaters.delete(container);
708
- }
709
896
  getEasing(name) {
710
897
  return this.easingFunctions.get(name) ?? ((value) => value);
711
898
  }
712
- getEffectDrawers(container, force = false) {
713
- return getItemMapFromInitializer(container, this.effectDrawers, this.initializers.effects, force);
714
- }
715
899
  getPalette(name) {
716
900
  return this.palettes.get(name);
717
901
  }
@@ -721,12 +905,6 @@
721
905
  getPreset(preset) {
722
906
  return this.presets.get(preset);
723
907
  }
724
- async getShapeDrawers(container, force = false) {
725
- return getItemMapFromInitializer(container, this.shapeDrawers, this.initializers.shapes, force);
726
- }
727
- async getUpdaters(container, force = false) {
728
- return getItemsFromInitializer(container, this.updaters, this.initializers.updaters, force);
729
- }
730
908
  async init() {
731
909
  if (this.#initialized || this.#isRunningLoaders) {
732
910
  return;
@@ -745,16 +923,9 @@
745
923
  this.#initialized = true;
746
924
  }
747
925
  }
748
- loadParticlesOptions(container, options, ...sourceOptions) {
749
- const updaters = this.updaters.get(container);
750
- if (!updaters) {
751
- return;
752
- }
753
- updaters.forEach(updater => updater.loadOptions?.(options, ...sourceOptions));
754
- }
755
926
  async register(...loaders) {
756
927
  if (this.#initialized) {
757
- throw new Error("Register plugins can only be done before calling tsParticles.load()");
928
+ throw new Error(getErrorMessage(ErrorCodes$3.pluginRegisterAfterLoad));
758
929
  }
759
930
  for (const loader of loaders) {
760
931
  if (this.#isRunningLoaders) {
@@ -766,111 +937,15 @@
766
937
  }
767
938
  }
768
939
  async #runLoader(loader, executed, allLoaders) {
769
- if (executed.has(loader))
940
+ if (executed.has(loader)) {
770
941
  return;
942
+ }
771
943
  executed.add(loader);
772
944
  allLoaders.add(loader);
773
945
  await loader(this.#engine);
774
946
  }
775
947
  }
776
948
 
777
- const errorPrefix = "tsParticles - Error";
778
- const wrap = (fn) => (...args) => {
779
- fn(...args);
780
- }, _logger = {
781
- debug: wrap(console.debug),
782
- error: (message, ...optionalParams) => {
783
- console.error(`${errorPrefix} - ${message}`, ...optionalParams);
784
- },
785
- info: wrap(console.info),
786
- log: wrap(console.log),
787
- trace: wrap(console.trace),
788
- verbose: wrap(console.log),
789
- warning: wrap(console.warn),
790
- };
791
- function setLogger(logger) {
792
- if (logger.debug) {
793
- _logger.debug = wrap(logger.debug);
794
- }
795
- if (logger.error) {
796
- _logger.error = wrap(logger.error);
797
- }
798
- if (logger.info) {
799
- _logger.info = wrap(logger.info);
800
- }
801
- if (logger.log) {
802
- _logger.log = wrap(logger.log);
803
- }
804
- if (logger.trace) {
805
- _logger.trace = wrap(logger.trace);
806
- }
807
- if (logger.verbose) {
808
- _logger.verbose = wrap(logger.verbose);
809
- }
810
- if (logger.warning) {
811
- _logger.warning = wrap(logger.warning);
812
- }
813
- }
814
- function getLogger() {
815
- return _logger;
816
- }
817
-
818
- const fullPercent = "100%";
819
- async function getDataFromUrl(data) {
820
- const url = itemFromSingleOrMultiple(data.url, data.index);
821
- if (!url) {
822
- return data.fallback;
823
- }
824
- const response = await fetch(url);
825
- if (response.ok) {
826
- return (await response.json());
827
- }
828
- getLogger().error(`${response.status.toString()} while retrieving config file`);
829
- return data.fallback;
830
- }
831
- const getCanvasFromContainer = (domContainer) => {
832
- const documentSafe = safeDocument();
833
- let canvasEl;
834
- const isCanvas = domContainer instanceof HTMLCanvasElement || domContainer.tagName.toLowerCase() === canvasTag;
835
- if (isCanvas) {
836
- canvasEl = domContainer;
837
- canvasEl.dataset[generatedAttribute] ??= generatedFalse;
838
- if (canvasEl.dataset[generatedAttribute] === generatedTrue) {
839
- canvasEl.style.width ||= fullPercent;
840
- canvasEl.style.height ||= fullPercent;
841
- canvasEl.style.pointerEvents = "none";
842
- canvasEl.style.setProperty("pointer-events", "none");
843
- }
844
- }
845
- else {
846
- const existingCanvases = domContainer.getElementsByTagName(canvasTag), foundCanvas = existingCanvases.item(canvasFirstIndex);
847
- if (foundCanvas) {
848
- canvasEl = foundCanvas;
849
- canvasEl.dataset[generatedAttribute] = generatedFalse;
850
- }
851
- else {
852
- canvasEl = documentSafe.createElement(canvasTag);
853
- canvasEl.dataset[generatedAttribute] = generatedTrue;
854
- domContainer.appendChild(canvasEl);
855
- }
856
- canvasEl.style.width ||= fullPercent;
857
- canvasEl.style.height ||= fullPercent;
858
- canvasEl.style.pointerEvents = "none";
859
- canvasEl.style.setProperty("pointer-events", "none");
860
- }
861
- return canvasEl;
862
- }, getDomContainer = (id, source) => {
863
- const documentSafe = safeDocument();
864
- let domContainer = source ?? documentSafe.getElementById(id);
865
- if (domContainer) {
866
- return domContainer;
867
- }
868
- domContainer = documentSafe.createElement("canvas");
869
- domContainer.id = id;
870
- domContainer.dataset[generatedAttribute] = generatedTrue;
871
- documentSafe.body.append(domContainer);
872
- return domContainer;
873
- };
874
949
  class Engine {
875
950
  pluginManager = new PluginManager(this);
876
951
  #domArray = [];
@@ -880,7 +955,7 @@
880
955
  return this.#domArray;
881
956
  }
882
957
  get version() {
883
- return "4.3.2";
958
+ return "4.5.0";
884
959
  }
885
960
  addEventListener(type, listener) {
886
961
  this.#eventDispatcher.addEventListener(type, listener);
@@ -889,7 +964,7 @@
889
964
  if (this.version === pluginVersion) {
890
965
  return;
891
966
  }
892
- throw new Error(`The tsParticles version is different from the loaded plugins version. Engine version: ${this.version}. Plugin version: ${pluginVersion}`);
967
+ throw new Error(getErrorMessage(ErrorCodes$3.engineVersionMismatch, this.version, pluginVersion));
893
968
  }
894
969
  dispatchEvent(type, args) {
895
970
  this.#eventDispatcher.dispatchEvent(type, args);
@@ -961,6 +1036,10 @@
961
1036
  }
962
1037
 
963
1038
  function initEngine() {
1039
+ const existing = globalThis.tsParticles;
1040
+ if (existing?.pluginManager) {
1041
+ return existing;
1042
+ }
964
1043
  return new Engine();
965
1044
  }
966
1045
 
@@ -1058,6 +1137,15 @@
1058
1137
  AnimationMode["random"] = "random";
1059
1138
  })(exports.AnimationMode || (exports.AnimationMode = {}));
1060
1139
 
1140
+ exports.HdrMode = void 0;
1141
+ (function (HdrMode) {
1142
+ HdrMode["standard"] = "standard";
1143
+ HdrMode["natural"] = "natural";
1144
+ HdrMode["vivid"] = "vivid";
1145
+ HdrMode["cinematic"] = "cinematic";
1146
+ HdrMode["dynamic"] = "dynamic";
1147
+ })(exports.HdrMode || (exports.HdrMode = {}));
1148
+
1061
1149
  exports.LimitMode = void 0;
1062
1150
  (function (LimitMode) {
1063
1151
  LimitMode["delete"] = "delete";
@@ -1125,20 +1213,6 @@
1125
1213
  DrawLayer[DrawLayer["Foreground"] = 7] = "Foreground";
1126
1214
  })(exports.DrawLayer || (exports.DrawLayer = {}));
1127
1215
 
1128
- class OptionLoader {
1129
- load(data) {
1130
- if (isNull(data)) {
1131
- return;
1132
- }
1133
- this.doLoad(data);
1134
- }
1135
- }
1136
- function loadOptions(options, ...sourceOptionsArr) {
1137
- for (const sourceOptions of sourceOptionsArr) {
1138
- options.load(sourceOptions);
1139
- }
1140
- }
1141
-
1142
1216
  function loadProperty(obj, key, value) {
1143
1217
  if (value !== undefined) {
1144
1218
  obj[key] = value;
@@ -1167,7 +1241,7 @@
1167
1241
  if (keyStr === "__proto__" || keyStr === "constructor" || keyStr === "prototype") {
1168
1242
  return;
1169
1243
  }
1170
- const objRecord = obj, currentValue = Object.prototype.hasOwnProperty.call(objRecord, keyStr) ? objRecord[keyStr] : {};
1244
+ const objRecord = obj, currentValue = Object.hasOwn(objRecord, keyStr) ? objRecord[keyStr] : {};
1171
1245
  objRecord[keyStr] = deepExtend(currentValue, value);
1172
1246
  }
1173
1247
  }
@@ -1180,6 +1254,20 @@
1180
1254
  }
1181
1255
  }
1182
1256
 
1257
+ class OptionLoader {
1258
+ load(data) {
1259
+ if (isNull(data)) {
1260
+ return;
1261
+ }
1262
+ this.doLoad(data);
1263
+ }
1264
+ }
1265
+ function loadOptions(options, ...sourceOptionsArr) {
1266
+ for (const sourceOptions of sourceOptionsArr) {
1267
+ options.load(sourceOptions);
1268
+ }
1269
+ }
1270
+
1183
1271
  class AnimationOptions extends OptionLoader {
1184
1272
  count = 0;
1185
1273
  decay = 0;
@@ -1319,7 +1407,29 @@
1319
1407
  zIndex = 0;
1320
1408
  doLoad(data) {
1321
1409
  loadProperty(this, "enable", data.enable);
1322
- loadProperty(this, "zIndex", data.zIndex);
1410
+ loadProperty(this, "zIndex", data.zIndex);
1411
+ }
1412
+ }
1413
+
1414
+ const defaultPeakNits = 400, minPeakNits = 0, toStringValue = (value) => String(value);
1415
+ class HDROptions extends OptionLoader {
1416
+ enable = true;
1417
+ mode = exports.HdrMode.standard;
1418
+ peakNits = defaultPeakNits;
1419
+ doLoad(data) {
1420
+ if (data.enable !== undefined && !isBoolean(data.enable)) {
1421
+ throw new Error(getErrorMessage(ErrorCodes$3.hdrEnableInvalid, String(data.enable)));
1422
+ }
1423
+ if (data.mode !== undefined && !isEnumValue(exports.HdrMode, data.mode)) {
1424
+ throw new Error(getErrorMessage(ErrorCodes$3.hdrModeInvalid, Object.values(exports.HdrMode).join(", "), toStringValue(data.mode)));
1425
+ }
1426
+ if (data.peakNits !== undefined &&
1427
+ (!isNumber(data.peakNits) || !Number.isFinite(data.peakNits) || data.peakNits <= minPeakNits)) {
1428
+ throw new Error(getErrorMessage(ErrorCodes$3.hdrPeakNitsInvalid, String(data.peakNits)));
1429
+ }
1430
+ loadProperty(this, "enable", data.enable);
1431
+ loadProperty(this, "mode", data.mode);
1432
+ loadProperty(this, "peakNits", data.peakNits);
1323
1433
  }
1324
1434
  }
1325
1435
 
@@ -1693,12 +1803,10 @@
1693
1803
  plugin.loadParticlesOptions(this.#container, this, data);
1694
1804
  }
1695
1805
  }
1696
- const updaters = this.#pluginManager.updaters.get(this.#container);
1697
- if (updaters) {
1698
- for (const updater of updaters) {
1699
- if (updater.loadOptions) {
1700
- updater.loadOptions(this, data);
1701
- }
1806
+ const updaters = this.#container.particleUpdaters;
1807
+ for (const updater of updaters) {
1808
+ if (updater.loadOptions) {
1809
+ updater.loadOptions(this, data);
1702
1810
  }
1703
1811
  }
1704
1812
  }
@@ -1766,7 +1874,7 @@
1766
1874
  duration = 0;
1767
1875
  fpsLimit = 120;
1768
1876
  fullScreen;
1769
- hdr = true;
1877
+ hdr;
1770
1878
  key;
1771
1879
  name;
1772
1880
  palette;
@@ -1786,6 +1894,7 @@
1786
1894
  this.#container = container;
1787
1895
  this.background = new Background();
1788
1896
  this.fullScreen = new FullScreen();
1897
+ this.hdr = new HDROptions();
1789
1898
  this.particles = loadParticlesOptions(this.#pluginManager, this.#container);
1790
1899
  this.resize = new ResizeEvent();
1791
1900
  }
@@ -1808,7 +1917,15 @@
1808
1917
  loadProperty(this, "detectRetina", data.detectRetina);
1809
1918
  loadRangeProperty(this, "duration", data.duration);
1810
1919
  loadProperty(this, "fpsLimit", data.fpsLimit);
1811
- loadProperty(this, "hdr", data.hdr);
1920
+ const hdrData = data.hdr;
1921
+ if (isBoolean(hdrData)) {
1922
+ this.hdr.enable = hdrData;
1923
+ this.hdr.mode = exports.HdrMode.standard;
1924
+ this.hdr.peakNits = 400;
1925
+ }
1926
+ else {
1927
+ this.hdr.load(hdrData);
1928
+ }
1812
1929
  loadProperty(this, "pauseOnBlur", data.pauseOnBlur);
1813
1930
  loadProperty(this, "pauseOnOutsideViewport", data.pauseOnOutsideViewport);
1814
1931
  loadProperty(this, "zLayers", data.zLayers);
@@ -1851,7 +1968,7 @@
1851
1968
  }
1852
1969
  }
1853
1970
 
1854
- const styleCache = new Map(), maxStyleCacheSize = 2000, rgbFixedPrecision = 2, hslFixedPrecision = 2, hdrRgbFixedPrecision = 4, hdrHslFixedPrecision = 4, sdrReferenceWhiteNits = 203, hdrAnimationScale = sdrReferenceWhiteNits / maxNits;
1971
+ 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, srgbThreshold = 0.04045, srgbDivisor = 12.92, srgbOffset = 0.055, srgbScale = 1.055, srgbExponent = 2.4, linearThreshold = 0.0031308, linearScale = 12.92;
1855
1972
  function getCachedStyle(key, generator) {
1856
1973
  let cached = styleCache.get(key);
1857
1974
  if (!cached) {
@@ -1863,6 +1980,48 @@
1863
1980
  }
1864
1981
  return cached;
1865
1982
  }
1983
+ function acesFilmic(x) {
1984
+ return clamp((x * (acesA * x + acesB)) / (x * (acesC * x + acesD) + acesE), none, one);
1985
+ }
1986
+ function srgbToLinear(c) {
1987
+ return c <= srgbThreshold ? c / srgbDivisor : Math.pow((c + srgbOffset) / srgbScale, srgbExponent);
1988
+ }
1989
+ function linearToSrgb(c) {
1990
+ return c <= linearThreshold ? c * linearScale : srgbScale * Math.pow(c, one / srgbExponent) - srgbOffset;
1991
+ }
1992
+ function applyHdrModeAdjustments(r, g, b, mode, maxChannel) {
1993
+ switch (mode) {
1994
+ case exports.HdrMode.vivid: {
1995
+ const avg = (r + g + b) / channelCount;
1996
+ return {
1997
+ b: clamp(clamp(avg + (b - avg) * saturationBoost, none, maxChannel) * lightnessBoost, none, maxChannel),
1998
+ g: clamp(clamp(avg + (g - avg) * saturationBoost, none, maxChannel) * lightnessBoost, none, maxChannel),
1999
+ r: clamp(clamp(avg + (r - avg) * saturationBoost, none, maxChannel) * lightnessBoost, none, maxChannel),
2000
+ };
2001
+ }
2002
+ case exports.HdrMode.cinematic: {
2003
+ const tempR = r * temperatureR, tempB = b * temperatureB, avg = (tempR + g + tempB) / channelCount;
2004
+ return {
2005
+ b: clamp(avg + (tempB - avg) * contrastFactor, none, maxChannel),
2006
+ g: clamp(avg + (g - avg) * contrastFactor, none, maxChannel),
2007
+ r: clamp(avg + (tempR - avg) * contrastFactor, none, maxChannel),
2008
+ };
2009
+ }
2010
+ case exports.HdrMode.dynamic: {
2011
+ 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;
2012
+ return {
2013
+ b: clamp(b * naturalWeight + vividB * vividWeight, none, maxChannel),
2014
+ g: clamp(g * naturalWeight + vividG * vividWeight, none, maxChannel),
2015
+ r: clamp(r * naturalWeight + vividR * vividWeight, none, maxChannel),
2016
+ };
2017
+ }
2018
+ case exports.HdrMode.standard:
2019
+ return { b, g, r };
2020
+ case exports.HdrMode.natural:
2021
+ default:
2022
+ return { b, g, r };
2023
+ }
2024
+ }
1866
2025
  function stringToRgba(pluginManager, input) {
1867
2026
  if (!input) {
1868
2027
  return;
@@ -1989,9 +2148,9 @@
1989
2148
  const grayscaleValue = Math.round(lNormalized * rgbMax);
1990
2149
  return { r: grayscaleValue, g: grayscaleValue, b: grayscaleValue };
1991
2150
  }
1992
- const temp1 = lNormalized < half
2151
+ const temp2 = lNormalized < half
1993
2152
  ? lNormalized * (sNormalizedOffset + sNormalized)
1994
- : 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));
2153
+ : 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));
1995
2154
  return { r: Math.round(red), g: Math.round(green), b: Math.round(blue) };
1996
2155
  }
1997
2156
  function hslToRgbFloat(hsl) {
@@ -2000,9 +2159,9 @@
2000
2159
  const grayscaleValue = lNormalized * rgbMax;
2001
2160
  return { r: grayscaleValue, g: grayscaleValue, b: grayscaleValue };
2002
2161
  }
2003
- const temp1 = lNormalized < half
2162
+ const temp2 = lNormalized < half
2004
2163
  ? lNormalized * (sNormalizedOffset + sNormalized)
2005
- : 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));
2164
+ : 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));
2006
2165
  return { r: red, g: green, b: blue };
2007
2166
  }
2008
2167
  function hslaToRgba(hsla) {
@@ -2030,30 +2189,65 @@
2030
2189
  r: getRgbInRangeValue(),
2031
2190
  };
2032
2191
  }
2033
- function getStyleFromRgb(color, hdr, opacity) {
2034
- const rgbPrecision = hdr ? hdrRgbFixedPrecision : rgbFixedPrecision, op = opacity ?? defaultOpacity$2, key = `rgb-${color.r.toFixed(rgbPrecision)}-${color.g.toFixed(rgbPrecision)}-${color.b.toFixed(rgbPrecision)}-${hdr ? "hdr" : "sdr"}-${op.toString()}`;
2035
- return getCachedStyle(key, () => (hdr ? getHdrStyleFromRgb(color, opacity) : getSdrStyleFromRgb(color, opacity)));
2192
+ function getStyleFromRgb(color, hdr, opacity, peakNits, mode) {
2193
+ const rgbPrecision = hdr ? hdrRgbFixedPrecision : rgbFixedPrecision, op = opacity ?? defaultOpacity$2, key = hdr
2194
+ ? `rgb-${color.r.toFixed(rgbPrecision)}-${color.g.toFixed(rgbPrecision)}-${color.b.toFixed(rgbPrecision)}-hdr-${op.toString()}-${(peakNits ?? maxNits).toString()}-${mode ?? exports.HdrMode.standard}`
2195
+ : `rgb-${color.r.toFixed(rgbPrecision)}-${color.g.toFixed(rgbPrecision)}-${color.b.toFixed(rgbPrecision)}-sdr-${op.toString()}`;
2196
+ return getCachedStyle(key, () => hdr ? getHdrStyleFromRgb(color, opacity, peakNits, mode) : getSdrStyleFromRgb(color, opacity));
2197
+ }
2198
+ function getHdrStyleFromRgb(color, opacity, peakNits = maxNits, mode = exports.HdrMode.standard) {
2199
+ const headroom = peakNits / sdrReferenceWhiteNits, middleGray = 0.18, mapped = hdrToneMapColor(color, headroom, middleGray, mode);
2200
+ return `color(display-p3 ${mapped.r.toString()} ${mapped.g.toString()} ${mapped.b.toString()} / ${(opacity ?? defaultOpacity$2).toString()})`;
2201
+ }
2202
+ function hdrToneMapColor(color, headroom, middleGray, mode) {
2203
+ const rNorm = color.r / rgbMax, gNorm = color.g / rgbMax, bNorm = color.b / rgbMax;
2204
+ if (mode !== exports.HdrMode.natural && mode !== exports.HdrMode.vivid && mode !== exports.HdrMode.cinematic && mode !== exports.HdrMode.dynamic) {
2205
+ return { b: bNorm, g: gNorm, r: rNorm };
2206
+ }
2207
+ const maxChannel = Math.max(one, headroom), luminance = luminanceR * rNorm + luminanceG * gNorm + luminanceB * bNorm, mappedLuminance = hdrToneMap(luminance, headroom, middleGray), scale = luminance > none ? mappedLuminance / luminance : one;
2208
+ return applyHdrModeAdjustments(clamp(rNorm * scale, none, maxChannel), clamp(gNorm * scale, none, maxChannel), clamp(bNorm * scale, none, maxChannel), mode, maxChannel);
2036
2209
  }
2037
- function getHdrStyleFromRgb(color, opacity, peakNits = maxNits) {
2038
- const headroom = peakNits / sdrReferenceWhiteNits;
2039
- return `color(display-p3 ${((color.r / rgbMax) * headroom).toString()} ${((color.g / rgbMax) * headroom).toString()} ${((color.b / rgbMax) * headroom).toString()} / ${(opacity ?? defaultOpacity$2).toString()})`;
2210
+ function hdrToneMap(normalized, headroom, middleGray) {
2211
+ if (normalized <= middleGray) {
2212
+ return acesFilmic(normalized);
2213
+ }
2214
+ const expanded = normalized + (normalized - middleGray) * (headroom - one);
2215
+ return acesFilmic(expanded);
2040
2216
  }
2041
2217
  function getSdrStyleFromRgb(color, opacity) {
2042
2218
  return `rgba(${color.r.toString()}, ${color.g.toString()}, ${color.b.toString()}, ${(opacity ?? defaultOpacity$2).toString()})`;
2043
2219
  }
2044
- function getStyleFromHsl(color, hdr, opacity) {
2045
- const hslPrecision = hdr ? hdrHslFixedPrecision : hslFixedPrecision, op = opacity ?? defaultOpacity$2, key = `hsl-${color.h.toFixed(hslPrecision)}-${color.s.toFixed(hslPrecision)}-${color.l.toFixed(hslPrecision)}-${hdr ? "hdr" : "sdr"}-${op.toString()}`;
2220
+ function getStyleFromHsl(color, hdr, opacity, peakNits, mode) {
2221
+ const hslPrecision = hdr ? hdrHslFixedPrecision : hslFixedPrecision, op = opacity ?? defaultOpacity$2, key = hdr
2222
+ ? `hsl-${color.h.toFixed(hslPrecision)}-${color.s.toFixed(hslPrecision)}-${color.l.toFixed(hslPrecision)}-hdr-${op.toString()}-${(peakNits ?? maxNits).toString()}-${mode ?? exports.HdrMode.standard}`
2223
+ : `hsl-${color.h.toFixed(hslPrecision)}-${color.s.toFixed(hslPrecision)}-${color.l.toFixed(hslPrecision)}-sdr-${op.toString()}`;
2046
2224
  return getCachedStyle(key, () => hdr
2047
- ? getStyleFromRgb(hslToRgbFloat(color), true, opacity)
2225
+ ? getStyleFromRgb(hslToRgbFloat(color), true, opacity, peakNits, mode)
2048
2226
  : `hsla(${color.h.toString()}, ${color.s.toString()}%, ${color.l.toString()}%, ${op.toString()})`);
2049
2227
  }
2050
- function colorMix(color1, color2, size1, size2) {
2228
+ function colorMix(color1, color2, size1, size2, hdr) {
2051
2229
  let rgb1 = color1, rgb2 = color2;
2052
2230
  if (!("r" in rgb1)) {
2053
- rgb1 = hslToRgb(color1);
2231
+ rgb1 = hdr ? hslToRgbFloat(color1) : hslToRgb(color1);
2054
2232
  }
2055
2233
  if (!("r" in rgb2)) {
2056
- rgb2 = hslToRgb(color2);
2234
+ rgb2 = hdr ? hslToRgbFloat(color2) : hslToRgb(color2);
2235
+ }
2236
+ if (hdr) {
2237
+ const lin1 = {
2238
+ b: srgbToLinear(rgb1.b / rgbMax),
2239
+ g: srgbToLinear(rgb1.g / rgbMax),
2240
+ r: srgbToLinear(rgb1.r / rgbMax),
2241
+ }, lin2 = {
2242
+ b: srgbToLinear(rgb2.b / rgbMax),
2243
+ g: srgbToLinear(rgb2.g / rgbMax),
2244
+ r: srgbToLinear(rgb2.r / rgbMax),
2245
+ }, totalWeight = size1 + size2;
2246
+ return {
2247
+ b: linearToSrgb((lin1.b * size1 + lin2.b * size2) / totalWeight) * rgbMax,
2248
+ g: linearToSrgb((lin1.g * size1 + lin2.g * size2) / totalWeight) * rgbMax,
2249
+ r: linearToSrgb((lin1.r * size1 + lin2.r * size2) / totalWeight) * rgbMax,
2250
+ };
2057
2251
  }
2058
2252
  return {
2059
2253
  b: mix(rgb1.b, rgb2.b, size1, size2),
@@ -2061,14 +2255,14 @@
2061
2255
  r: mix(rgb1.r, rgb2.r, size1, size2),
2062
2256
  };
2063
2257
  }
2064
- function getLinkColor(p1, p2, linkColor) {
2258
+ function getLinkColor(p1, p2, linkColor, hdr) {
2065
2259
  if (linkColor === randomColorValue) {
2066
2260
  return getRandomRgbColor();
2067
2261
  }
2068
2262
  else if (linkColor === midColorValue) {
2069
2263
  const sourceColor = p1.getFillColor() ?? p1.getStrokeColor(), destColor = p2?.getFillColor() ?? p2?.getStrokeColor();
2070
2264
  if (sourceColor && destColor && p2) {
2071
- return colorMix(sourceColor, destColor, p1.getRadius(), p2.getRadius());
2265
+ return colorMix(sourceColor, destColor, p1.getRadius(), p2.getRadius(), hdr);
2072
2266
  }
2073
2267
  else {
2074
2268
  const hslColor = sourceColor ?? destColor;
@@ -2164,7 +2358,7 @@
2164
2358
  colorValue.velocity = defaultVelocity;
2165
2359
  }
2166
2360
  }
2167
- function updateColorValue(data, decrease, delta, hdr) {
2361
+ function updateColorValue(data, decrease, delta, _hdr) {
2168
2362
  const minLoops = 0, minDelay = 0, identity = 1, minVelocity = 0, minOffset = 0, velocityFactor = 3.6;
2169
2363
  if (!data.enable ||
2170
2364
  ((data.maxLoops ?? minLoops) > minLoops && (data.loops ?? minLoops) > (data.maxLoops ?? minLoops))) {
@@ -2177,7 +2371,7 @@
2177
2371
  if ((data.delayTime ?? minDelay) > minDelay && data.time < (data.delayTime ?? minDelay)) {
2178
2372
  return;
2179
2373
  }
2180
- 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;
2374
+ 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;
2181
2375
  if (!decrease || data.status === exports.AnimationStatus.increasing) {
2182
2376
  data.value += velocity;
2183
2377
  if (data.value > max) {
@@ -2209,9 +2403,9 @@
2209
2403
  return;
2210
2404
  }
2211
2405
  const { h, s, l } = color;
2212
- updateColorValue(h, false, delta, hdr);
2213
- updateColorValue(s, true, delta, hdr);
2214
- updateColorValue(l, true, delta, hdr);
2406
+ updateColorValue(h, false, delta);
2407
+ updateColorValue(s, true, delta);
2408
+ updateColorValue(l, true, delta);
2215
2409
  }
2216
2410
  function alterHsl(color, type, value) {
2217
2411
  return {
@@ -2327,7 +2521,7 @@
2327
2521
  }
2328
2522
 
2329
2523
  async function loadBlendPlugin(engine) {
2330
- engine.checkVersion("4.3.2");
2524
+ engine.checkVersion("4.5.0");
2331
2525
  await engine.pluginManager.register(e => {
2332
2526
  e.pluginManager.addPlugin(new BlendPlugin());
2333
2527
  });
@@ -2364,7 +2558,7 @@
2364
2558
  }
2365
2559
 
2366
2560
  async function loadCircleShape(engine) {
2367
- engine.checkVersion("4.3.2");
2561
+ engine.checkVersion("4.5.0");
2368
2562
  await engine.pluginManager.register(e => {
2369
2563
  e.pluginManager.addShape(["circle"], () => {
2370
2564
  return Promise.resolve(new CircleDrawer());
@@ -2379,7 +2573,7 @@
2379
2573
  RgbIndexes[RgbIndexes["b"] = 3] = "b";
2380
2574
  RgbIndexes[RgbIndexes["a"] = 4] = "a";
2381
2575
  })(RgbIndexes$1 || (RgbIndexes$1 = {}));
2382
- 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;
2576
+ 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;
2383
2577
  class HexColorManager {
2384
2578
  accepts(input) {
2385
2579
  return input.startsWith("#");
@@ -2412,7 +2606,7 @@
2412
2606
  }
2413
2607
 
2414
2608
  async function loadHexColorPlugin(engine) {
2415
- engine.checkVersion("4.3.2");
2609
+ engine.checkVersion("4.5.0");
2416
2610
  await engine.pluginManager.register(e => {
2417
2611
  e.pluginManager.addColorManager("hex", new HexColorManager());
2418
2612
  });
@@ -2452,7 +2646,7 @@
2452
2646
  if (!this.accepts(input)) {
2453
2647
  return;
2454
2648
  }
2455
- const result = hslRegex.exec(input), minLength = 4, defaultAlpha = 1, radix = 10;
2649
+ const result = hslRegex.exec(input), minLength = 4, radix = 10;
2456
2650
  return result
2457
2651
  ? hslaToRgba({
2458
2652
  a: result.length > minLength ? parseAlpha(result[HslIndexes.a]) : defaultAlpha,
@@ -2465,12 +2659,20 @@
2465
2659
  }
2466
2660
 
2467
2661
  async function loadHslColorPlugin(engine) {
2468
- engine.checkVersion("4.3.2");
2662
+ engine.checkVersion("4.5.0");
2469
2663
  await engine.pluginManager.register(e => {
2470
2664
  e.pluginManager.addColorManager("hsl", new HslColorManager());
2471
2665
  });
2472
2666
  }
2473
2667
 
2668
+ const ErrorCodes$2 = {
2669
+ baseMoverNotLoaded: "TSP-3203",
2670
+ };
2671
+
2672
+ const ErrorMessages$2 = {
2673
+ [ErrorCodes$2.baseMoverNotLoaded]: "tsParticles Base Mover is not loaded",
2674
+ };
2675
+
2474
2676
  class MovePlugin {
2475
2677
  id = "move";
2476
2678
  #pluginManager;
@@ -2489,20 +2691,20 @@
2489
2691
  }
2490
2692
 
2491
2693
  async function loadMovePlugin(engine) {
2492
- engine.checkVersion("4.3.2");
2694
+ engine.checkVersion("4.5.0");
2695
+ if (typeof process !== "undefined" && process.env.NODE_ENV !== "production") {
2696
+ addErrorMessages(ErrorMessages$2);
2697
+ }
2493
2698
  await engine.pluginManager.register(e => {
2494
2699
  const moveEngine = e, movePluginManager = moveEngine.pluginManager;
2495
2700
  movePluginManager.initializers.pathGenerators ??= new Map();
2496
- movePluginManager.pathGenerators ??= new Map();
2497
2701
  movePluginManager.addPathGenerator = (name, generator) => {
2702
+ if (movePluginManager.initialized) {
2703
+ return;
2704
+ }
2498
2705
  movePluginManager.initializers.pathGenerators ??= new Map();
2499
2706
  movePluginManager.initializers.pathGenerators.set(name, generator);
2500
2707
  };
2501
- movePluginManager.getPathGenerators = async (container, force = false) => {
2502
- movePluginManager.initializers.pathGenerators ??= new Map();
2503
- movePluginManager.pathGenerators ??= new Map();
2504
- return getItemMapFromInitializer(container, movePluginManager.pathGenerators, movePluginManager.initializers.pathGenerators, force);
2505
- };
2506
2708
  e.pluginManager.addPlugin(new MovePlugin(e.pluginManager));
2507
2709
  });
2508
2710
  }
@@ -2699,7 +2901,7 @@
2699
2901
  }
2700
2902
 
2701
2903
  async function loadOpacityUpdater(engine) {
2702
- engine.checkVersion("4.3.2");
2904
+ engine.checkVersion("4.5.0");
2703
2905
  await engine.pluginManager.register(e => {
2704
2906
  e.pluginManager.addParticleUpdater("opacity", container => {
2705
2907
  return Promise.resolve(new OpacityUpdater(container));
@@ -2708,70 +2910,60 @@
2708
2910
  }
2709
2911
 
2710
2912
  const boundsMin = 0;
2711
- function bounceHorizontal(data) {
2712
- if ((data.outMode !== exports.OutMode.bounce && data.outMode !== exports.OutMode.split) ||
2713
- (data.direction !== exports.OutModeDirection.left && data.direction !== exports.OutModeDirection.right)) {
2714
- return;
2715
- }
2716
- if (data.bounds.right < boundsMin && data.direction === exports.OutModeDirection.left) {
2717
- data.particle.position.x = data.size + data.offset.x;
2718
- }
2719
- else if (data.bounds.left > data.canvasSize.width && data.direction === exports.OutModeDirection.right) {
2720
- data.particle.position.x = data.canvasSize.width - data.size - data.offset.x;
2721
- }
2722
- const velocity = data.particle.velocity.x;
2723
- let bounced = false;
2724
- if (data.outOfCanvas &&
2725
- ((data.direction === exports.OutModeDirection.right && velocity > minVelocity) ||
2726
- (data.direction === exports.OutModeDirection.left && velocity < minVelocity))) {
2727
- const newVelocity = getRangeValue(data.particle.options.bounce.horizontal.value);
2728
- data.particle.velocity.x *= -newVelocity;
2729
- bounced = true;
2730
- }
2731
- if (!bounced) {
2732
- return;
2733
- }
2734
- const minPos = data.offset.x + data.size;
2735
- if (data.outOfCanvas && data.direction === exports.OutModeDirection.right) {
2736
- data.particle.position.x = data.canvasSize.width - minPos;
2737
- }
2738
- else if (data.outOfCanvas && data.direction === exports.OutModeDirection.left) {
2739
- data.particle.position.x = minPos;
2740
- }
2741
- if (data.outMode === exports.OutMode.split) {
2742
- data.particle.destroy();
2743
- }
2744
- }
2745
- function bounceVertical(data) {
2746
- if ((data.outMode !== exports.OutMode.bounce && data.outMode !== exports.OutMode.split) ||
2747
- (data.direction !== exports.OutModeDirection.bottom && data.direction !== exports.OutModeDirection.top)) {
2913
+ const bounceAxisConfigs = {
2914
+ [exports.OutModeDirection.left]: {
2915
+ axis: "x",
2916
+ canvas: "width",
2917
+ bounce: "horizontal",
2918
+ negativeEdge: "right",
2919
+ positiveEdge: "left",
2920
+ negative: true,
2921
+ },
2922
+ [exports.OutModeDirection.right]: {
2923
+ axis: "x",
2924
+ canvas: "width",
2925
+ bounce: "horizontal",
2926
+ negativeEdge: "right",
2927
+ positiveEdge: "left",
2928
+ negative: false,
2929
+ },
2930
+ [exports.OutModeDirection.top]: {
2931
+ axis: "y",
2932
+ canvas: "height",
2933
+ bounce: "vertical",
2934
+ negativeEdge: "bottom",
2935
+ positiveEdge: "top",
2936
+ negative: true,
2937
+ },
2938
+ [exports.OutModeDirection.bottom]: {
2939
+ axis: "y",
2940
+ canvas: "height",
2941
+ bounce: "vertical",
2942
+ negativeEdge: "bottom",
2943
+ positiveEdge: "top",
2944
+ negative: false,
2945
+ },
2946
+ };
2947
+ function bounce$1(data) {
2948
+ if ((data.outMode !== exports.OutMode.bounce && data.outMode !== exports.OutMode.split) || !(data.direction in bounceAxisConfigs)) {
2748
2949
  return;
2749
2950
  }
2750
- if (data.bounds.bottom < boundsMin && data.direction === exports.OutModeDirection.top) {
2751
- data.particle.position.y = data.size + data.offset.y;
2951
+ const config = bounceAxisConfigs[data.direction], bounds = data.bounds, canvasDim = data.canvasSize[config.canvas], position = data.particle.position, velocity = data.particle.velocity[config.axis];
2952
+ if (config.negative && bounds[config.negativeEdge] < boundsMin) {
2953
+ position[config.axis] = data.size + data.offset[config.axis];
2752
2954
  }
2753
- else if (data.bounds.top > data.canvasSize.height && data.direction === exports.OutModeDirection.bottom) {
2754
- data.particle.position.y = data.canvasSize.height - data.size - data.offset.y;
2955
+ else if (!config.negative && bounds[config.positiveEdge] > canvasDim) {
2956
+ position[config.axis] = canvasDim - data.size - data.offset[config.axis];
2755
2957
  }
2756
- const velocity = data.particle.velocity.y;
2757
- let bounced = false;
2758
2958
  if (data.outOfCanvas &&
2759
- ((data.direction === exports.OutModeDirection.bottom && velocity > minVelocity) ||
2760
- (data.direction === exports.OutModeDirection.top && velocity < minVelocity))) {
2761
- const newVelocity = getRangeValue(data.particle.options.bounce.vertical.value);
2762
- data.particle.velocity.y *= -newVelocity;
2763
- bounced = true;
2959
+ ((config.negative && velocity < minVelocity) || (!config.negative && velocity > minVelocity))) {
2960
+ data.particle.velocity[config.axis] *= -getRangeValue(data.particle.options.bounce[config.bounce].value);
2764
2961
  }
2765
- if (!bounced) {
2962
+ else {
2766
2963
  return;
2767
2964
  }
2768
- const minPos = data.offset.y + data.size;
2769
- if (data.outOfCanvas && data.direction === exports.OutModeDirection.bottom) {
2770
- data.particle.position.y = data.canvasSize.height - minPos;
2771
- }
2772
- else if (data.outOfCanvas && data.direction === exports.OutModeDirection.top) {
2773
- data.particle.position.y = minPos;
2774
- }
2965
+ const minPos = data.offset[config.axis] + data.size;
2966
+ position[config.axis] = config.negative ? minPos : canvasDim - minPos;
2775
2967
  if (data.outMode === exports.OutMode.split) {
2776
2968
  data.particle.destroy();
2777
2969
  }
@@ -2787,26 +2979,19 @@
2787
2979
  exports.OutMode.bounce,
2788
2980
  exports.OutMode.split,
2789
2981
  ];
2790
- this.#particleBouncePlugins = container.plugins.filter(p => p.particleBounce !== undefined);
2982
+ this.#particleBouncePlugins = container.plugins.filter(p => !!p.particleBounce);
2791
2983
  }
2792
2984
  update(particle, direction, delta, outMode) {
2793
2985
  if (!this.modes.includes(outMode)) {
2794
2986
  return;
2795
2987
  }
2796
- const container = this.#container;
2797
- let handled = false;
2798
2988
  for (const plugin of this.#particleBouncePlugins) {
2799
- handled = plugin.particleBounce?.(particle, delta, direction) ?? false;
2800
- if (handled) {
2801
- break;
2989
+ if (plugin.particleBounce?.(particle, delta, direction)) {
2990
+ return;
2802
2991
  }
2803
2992
  }
2804
- if (handled) {
2805
- return;
2806
- }
2807
- const pos = particle.getPosition(), offset = particle.offset, size = particle.getRadius(), bounds = calculateBounds(pos, size), canvasSize = container.canvas.size, outOfCanvas = !particle.isInsideCanvasForOutMode(outMode, direction);
2808
- bounceHorizontal({ particle, outMode, direction, bounds, canvasSize, offset, outOfCanvas, size });
2809
- bounceVertical({ particle, outMode, direction, bounds, canvasSize, offset, outOfCanvas, size });
2993
+ const pos = particle.getPosition(), offset = particle.offset, size = particle.getRadius(), bounds = calculateBounds(pos, size), canvasSize = this.#container.canvas.size, outOfCanvas = !particle.isInsideCanvasForOutMode(outMode, direction);
2994
+ bounce$1({ particle, outMode, direction, bounds, canvasSize, offset, outOfCanvas, size });
2810
2995
  }
2811
2996
  }
2812
2997
 
@@ -2895,107 +3080,108 @@
2895
3080
  return;
2896
3081
  }
2897
3082
  const container = this.#container;
2898
- switch (particle.outType) {
2899
- case exports.ParticleOutType.inside: {
2900
- const { x: vx, y: vy } = particle.velocity;
2901
- updateVector.setTo(originPoint);
2902
- updateVector.length = particle.moveCenter.radius;
2903
- updateVector.angle = particle.velocity.angle + Math.PI;
2904
- updateVector.addTo(particle.moveCenter);
2905
- const { dx, dy } = getDistances(particle.position, updateVector);
2906
- if ((vx <= minVelocity && dx >= minDistance$2) ||
2907
- (vy <= minVelocity && dy >= minDistance$2) ||
2908
- (vx >= minVelocity && dx <= minDistance$2) ||
2909
- (vy >= minVelocity && dy <= minDistance$2)) {
2910
- return;
2911
- }
2912
- particle.position.x = Math.floor(randomInRangeValue({
2913
- min: 0,
2914
- max: container.canvas.size.width,
2915
- }));
2916
- particle.position.y = Math.floor(randomInRangeValue({
2917
- min: 0,
2918
- max: container.canvas.size.height,
2919
- }));
2920
- const { dx: newDx, dy: newDy } = getDistances(particle.position, particle.moveCenter);
2921
- particle.direction = Math.atan2(-newDy, -newDx);
2922
- particle.velocity.angle = particle.direction;
2923
- particle.justWarped = true;
2924
- break;
3083
+ if (particle.outType === exports.ParticleOutType.inside) {
3084
+ this.#applyOutModeInside(particle, container);
3085
+ }
3086
+ else {
3087
+ if (particle.isInsideCanvasForOutMode(outMode, direction)) {
3088
+ return;
2925
3089
  }
2926
- default: {
2927
- if (particle.isInsideCanvasForOutMode(outMode, direction)) {
2928
- return;
2929
- }
2930
- switch (particle.outType) {
2931
- case exports.ParticleOutType.outside: {
2932
- particle.position.x =
2933
- Math.floor(randomInRangeValue({
2934
- min: -particle.moveCenter.radius,
2935
- max: particle.moveCenter.radius,
2936
- })) + particle.moveCenter.x;
2937
- particle.position.y =
2938
- Math.floor(randomInRangeValue({
2939
- min: -particle.moveCenter.radius,
2940
- max: particle.moveCenter.radius,
2941
- })) + particle.moveCenter.y;
2942
- const { dx, dy } = getDistances(particle.position, particle.moveCenter);
2943
- if (particle.moveCenter.radius) {
2944
- particle.direction = Math.atan2(dy, dx);
2945
- particle.velocity.angle = particle.direction;
2946
- }
2947
- particle.justWarped = true;
2948
- break;
2949
- }
2950
- case exports.ParticleOutType.normal: {
2951
- const warp = particle.options.move.warp, canvasSize = container.canvas.size, newPos = {
2952
- bottom: canvasSize.height + particle.getRadius() + particle.offset.y,
2953
- left: -particle.getRadius() - particle.offset.x,
2954
- right: canvasSize.width + particle.getRadius() + particle.offset.x,
2955
- top: -particle.getRadius() - particle.offset.y,
2956
- }, sizeValue = particle.getRadius(), nextBounds = calculateBounds(particle.position, sizeValue);
2957
- if (direction === exports.OutModeDirection.right && nextBounds.left > canvasSize.width + particle.offset.x) {
2958
- particle.position.x = newPos.left;
2959
- particle.initialPosition.x = particle.position.x;
2960
- if (!warp) {
2961
- particle.position.y = getRandom() * canvasSize.height;
2962
- particle.initialPosition.y = particle.position.y;
2963
- }
2964
- particle.justWarped = true;
2965
- }
2966
- else if (direction === exports.OutModeDirection.left && nextBounds.right < -particle.offset.x) {
2967
- particle.position.x = newPos.right;
2968
- particle.initialPosition.x = particle.position.x;
2969
- if (!warp) {
2970
- particle.position.y = getRandom() * canvasSize.height;
2971
- particle.initialPosition.y = particle.position.y;
2972
- }
2973
- particle.justWarped = true;
2974
- }
2975
- if (direction === exports.OutModeDirection.bottom && nextBounds.top > canvasSize.height + particle.offset.y) {
2976
- if (!warp) {
2977
- particle.position.x = getRandom() * canvasSize.width;
2978
- particle.initialPosition.x = particle.position.x;
2979
- }
2980
- particle.position.y = newPos.top;
2981
- particle.initialPosition.y = particle.position.y;
2982
- particle.justWarped = true;
2983
- }
2984
- else if (direction === exports.OutModeDirection.top && nextBounds.bottom < -particle.offset.y) {
2985
- if (!warp) {
2986
- particle.position.x = getRandom() * canvasSize.width;
2987
- particle.initialPosition.x = particle.position.x;
2988
- }
2989
- particle.position.y = newPos.bottom;
2990
- particle.initialPosition.y = particle.position.y;
2991
- particle.justWarped = true;
2992
- }
2993
- break;
2994
- }
2995
- }
2996
- break;
3090
+ if (particle.outType === exports.ParticleOutType.outside) {
3091
+ this.#applyParticleModeOutside(particle);
2997
3092
  }
2998
- }
3093
+ else {
3094
+ this.#applyOutModeNormal(particle, container, direction);
3095
+ }
3096
+ }
3097
+ }
3098
+ #applyOutModeInside(particle, container) {
3099
+ const { x: vx, y: vy } = particle.velocity;
3100
+ updateVector.setTo(originPoint);
3101
+ updateVector.length = particle.moveCenter.radius;
3102
+ updateVector.angle = particle.velocity.angle + Math.PI;
3103
+ updateVector.addTo(particle.moveCenter);
3104
+ const { dx, dy } = getDistances(particle.position, updateVector);
3105
+ if ((vx <= minVelocity && dx >= minDistance$2) ||
3106
+ (vy <= minVelocity && dy >= minDistance$2) ||
3107
+ (vx >= minVelocity && dx <= minDistance$2) ||
3108
+ (vy >= minVelocity && dy <= minDistance$2)) {
3109
+ return;
3110
+ }
3111
+ particle.position.x = Math.floor(randomInRangeValue({
3112
+ min: 0,
3113
+ max: container.canvas.size.width,
3114
+ }));
3115
+ particle.position.y = Math.floor(randomInRangeValue({
3116
+ min: 0,
3117
+ max: container.canvas.size.height,
3118
+ }));
3119
+ const { dx: newDx, dy: newDy } = getDistances(particle.position, particle.moveCenter);
3120
+ particle.direction = Math.atan2(-newDy, -newDx);
3121
+ particle.velocity.angle = particle.direction;
3122
+ particle.justWarped = true;
3123
+ }
3124
+ #applyOutModeNormal(particle, container, direction) {
3125
+ const warp = particle.options.move.warp, canvasSize = container.canvas.size, sizeValue = particle.getRadius(), newPos = {
3126
+ bottom: canvasSize.height + sizeValue + particle.offset.y,
3127
+ left: -sizeValue - particle.offset.x,
3128
+ right: canvasSize.width + sizeValue + particle.offset.x,
3129
+ top: -sizeValue - particle.offset.y,
3130
+ }, nextBounds = calculateBounds(particle.position, sizeValue);
3131
+ if (direction === exports.OutModeDirection.right && nextBounds.left > canvasSize.width + particle.offset.x) {
3132
+ particle.position.x = newPos.left;
3133
+ particle.initialPosition.x = particle.position.x;
3134
+ if (!warp) {
3135
+ particle.position.y = getRandom() * canvasSize.height;
3136
+ particle.initialPosition.y = particle.position.y;
3137
+ }
3138
+ particle.justWarped = true;
3139
+ }
3140
+ else if (direction === exports.OutModeDirection.left && nextBounds.right < -particle.offset.x) {
3141
+ particle.position.x = newPos.right;
3142
+ particle.initialPosition.x = particle.position.x;
3143
+ if (!warp) {
3144
+ particle.position.y = getRandom() * canvasSize.height;
3145
+ particle.initialPosition.y = particle.position.y;
3146
+ }
3147
+ particle.justWarped = true;
3148
+ }
3149
+ if (direction === exports.OutModeDirection.bottom && nextBounds.top > canvasSize.height + particle.offset.y) {
3150
+ if (!warp) {
3151
+ particle.position.x = getRandom() * canvasSize.width;
3152
+ particle.initialPosition.x = particle.position.x;
3153
+ }
3154
+ particle.position.y = newPos.top;
3155
+ particle.initialPosition.y = particle.position.y;
3156
+ particle.justWarped = true;
3157
+ }
3158
+ else if (direction === exports.OutModeDirection.top && nextBounds.bottom < -particle.offset.y) {
3159
+ if (!warp) {
3160
+ particle.position.x = getRandom() * canvasSize.width;
3161
+ particle.initialPosition.x = particle.position.x;
3162
+ }
3163
+ particle.position.y = newPos.bottom;
3164
+ particle.initialPosition.y = particle.position.y;
3165
+ particle.justWarped = true;
3166
+ }
3167
+ }
3168
+ #applyParticleModeOutside(particle) {
3169
+ particle.position.x =
3170
+ Math.floor(randomInRangeValue({
3171
+ min: -particle.moveCenter.radius,
3172
+ max: particle.moveCenter.radius,
3173
+ })) + particle.moveCenter.x;
3174
+ particle.position.y =
3175
+ Math.floor(randomInRangeValue({
3176
+ min: -particle.moveCenter.radius,
3177
+ max: particle.moveCenter.radius,
3178
+ })) + particle.moveCenter.y;
3179
+ const { dx, dy } = getDistances(particle.position, particle.moveCenter);
3180
+ if (particle.moveCenter.radius) {
3181
+ particle.direction = Math.atan2(dy, dx);
3182
+ particle.velocity.angle = particle.direction;
3183
+ }
3184
+ particle.justWarped = true;
2999
3185
  }
3000
3186
  }
3001
3187
 
@@ -3044,7 +3230,7 @@
3044
3230
  }
3045
3231
 
3046
3232
  async function loadOutModesUpdater(engine) {
3047
- engine.checkVersion("4.3.2");
3233
+ engine.checkVersion("4.5.0");
3048
3234
  await engine.pluginManager.register(e => {
3049
3235
  e.pluginManager.addParticleUpdater("outModes", container => {
3050
3236
  return Promise.resolve(new OutOfCanvasUpdater(container));
@@ -3061,39 +3247,9 @@
3061
3247
  this.#pluginManager = pluginManager;
3062
3248
  }
3063
3249
  init(particle) {
3064
- 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;
3065
- if (fill) {
3066
- const fillColor = AnimatableColor.create(paintColor === undefined ? undefined : AnimatableColor.create(undefined, paintColor), fill.color);
3067
- particle.fillEnabled = fill.enable;
3068
- particle.fillOpacity = getRangeValue(fill.opacity);
3069
- particle.fillAnimation = fillColor.animation;
3070
- const fillHslColor = rangeColorToHsl(this.#pluginManager, fillColor);
3071
- if (fillHslColor) {
3072
- particle.fillColor = getHslAnimationFromHsl(fillHslColor, particle.fillAnimation, container.retina.reduceFactor);
3073
- }
3074
- }
3075
- else {
3076
- particle.fillEnabled = false;
3077
- particle.fillAnimation = undefined;
3078
- particle.fillColor = undefined;
3079
- particle.fillOpacity = defaultOpacity;
3080
- }
3081
- if (stroke) {
3082
- const strokeColor = AnimatableColor.create(paintColor === undefined ? undefined : AnimatableColor.create(undefined, paintColor), stroke.color);
3083
- particle.strokeWidth = getRangeValue(stroke.width) * container.retina.pixelRatio;
3084
- particle.strokeOpacity = getRangeValue(stroke.opacity ?? defaultOpacity);
3085
- particle.strokeAnimation = strokeColor.animation;
3086
- const strokeHslColor = rangeColorToHsl(this.#pluginManager, strokeColor) ?? particle.getFillColor();
3087
- if (strokeHslColor) {
3088
- particle.strokeColor = getHslAnimationFromHsl(strokeHslColor, particle.strokeAnimation, container.retina.reduceFactor);
3089
- }
3090
- }
3091
- else {
3092
- particle.strokeAnimation = undefined;
3093
- particle.strokeColor = undefined;
3094
- particle.strokeOpacity = defaultOpacity;
3095
- particle.strokeWidth = 0;
3096
- }
3250
+ const container = this.#container, options = particle.options, paint = itemFromSingleOrMultiple(options.paint, particle.id, options.reduceDuplicates);
3251
+ this.#initFill(paint, particle, container);
3252
+ this.#initStroke(paint, particle, container);
3097
3253
  }
3098
3254
  isEnabled(particle) {
3099
3255
  const { fillAnimation, fillColor, strokeAnimation, strokeColor } = particle, fillEnabled = !!fillAnimation &&
@@ -3112,10 +3268,48 @@
3112
3268
  updateColor(particle.fillColor, delta, this.#container.hdr);
3113
3269
  updateColor(particle.strokeColor, delta, this.#container.hdr);
3114
3270
  }
3271
+ #initFill(paint, particle, container) {
3272
+ const fill = paint?.fill, color = paint?.color, paintColor = color ?? undefined;
3273
+ if (!fill) {
3274
+ particle.fillEnabled = false;
3275
+ particle.fillAnimation = undefined;
3276
+ particle.fillColor = undefined;
3277
+ particle.fillOpacity = defaultOpacity;
3278
+ return;
3279
+ }
3280
+ const fillColor = AnimatableColor.create(paintColor === undefined ? undefined : AnimatableColor.create(undefined, paintColor), fill.color);
3281
+ particle.fillEnabled = fill.enable;
3282
+ particle.fillOpacity = getRangeValue(fill.opacity);
3283
+ particle.fillAnimation = fillColor.animation;
3284
+ const fillHslColor = rangeColorToHsl(this.#pluginManager, fillColor);
3285
+ if (!fillHslColor) {
3286
+ return;
3287
+ }
3288
+ particle.fillColor = getHslAnimationFromHsl(fillHslColor, particle.fillAnimation, container.retina.reduceFactor);
3289
+ }
3290
+ #initStroke(paint, particle, container) {
3291
+ const stroke = paint?.stroke, color = paint?.color, paintColor = color ?? undefined;
3292
+ if (!stroke) {
3293
+ particle.strokeAnimation = undefined;
3294
+ particle.strokeColor = undefined;
3295
+ particle.strokeOpacity = defaultOpacity;
3296
+ particle.strokeWidth = 0;
3297
+ return;
3298
+ }
3299
+ const strokeColor = AnimatableColor.create(paintColor === undefined ? undefined : AnimatableColor.create(undefined, paintColor), stroke.color);
3300
+ particle.strokeWidth = getRangeValue(stroke.width) * container.retina.pixelRatio;
3301
+ particle.strokeOpacity = getRangeValue(stroke.opacity ?? defaultOpacity);
3302
+ particle.strokeAnimation = strokeColor.animation;
3303
+ const strokeHslColor = rangeColorToHsl(this.#pluginManager, strokeColor) ?? particle.getFillColor();
3304
+ if (!strokeHslColor) {
3305
+ return;
3306
+ }
3307
+ particle.strokeColor = getHslAnimationFromHsl(strokeHslColor, particle.strokeAnimation, container.retina.reduceFactor);
3308
+ }
3115
3309
  }
3116
3310
 
3117
3311
  async function loadPaintUpdater(engine) {
3118
- engine.checkVersion("4.3.2");
3312
+ engine.checkVersion("4.5.0");
3119
3313
  await engine.pluginManager.register(e => {
3120
3314
  e.pluginManager.addParticleUpdater("paint", container => {
3121
3315
  return Promise.resolve(new PaintUpdater(e.pluginManager, container));
@@ -3157,7 +3351,7 @@
3157
3351
  if (!this.accepts(input)) {
3158
3352
  return;
3159
3353
  }
3160
- const result = rgbRegex.exec(input), radix = 10, minLength = 4, defaultAlpha = 1;
3354
+ const result = rgbRegex.exec(input), radix = 10, minLength = 4;
3161
3355
  return result
3162
3356
  ? {
3163
3357
  a: result.length > minLength ? parseAlpha(result[RgbIndexes.a]) : defaultAlpha,
@@ -3170,7 +3364,7 @@
3170
3364
  }
3171
3365
 
3172
3366
  async function loadRgbColorPlugin(engine) {
3173
- engine.checkVersion("4.3.2");
3367
+ engine.checkVersion("4.5.0");
3174
3368
  await engine.pluginManager.register(e => {
3175
3369
  e.pluginManager.addColorManager("rgb", new RgbColorManager());
3176
3370
  });
@@ -3255,7 +3449,7 @@
3255
3449
  }
3256
3450
 
3257
3451
  async function loadSizeUpdater(engine) {
3258
- engine.checkVersion("4.3.2");
3452
+ engine.checkVersion("4.5.0");
3259
3453
  await engine.pluginManager.register(e => {
3260
3454
  e.pluginManager.addParticleUpdater("size", container => {
3261
3455
  return Promise.resolve(new SizeUpdater(container));
@@ -3264,7 +3458,7 @@
3264
3458
  }
3265
3459
 
3266
3460
  async function loadBasic(engine) {
3267
- engine.checkVersion("4.3.2");
3461
+ engine.checkVersion("4.5.0");
3268
3462
  await engine.pluginManager.register(async (e) => {
3269
3463
  await Promise.all([
3270
3464
  loadBlendPlugin(e),
@@ -3281,6 +3475,16 @@
3281
3475
  });
3282
3476
  }
3283
3477
 
3478
+ const ErrorCodes$1 = {
3479
+ interactivityPluginNotLoaded: "TSP-3201",
3480
+ interactivityClickHandlerNotSet: "TSP-3202",
3481
+ };
3482
+
3483
+ const ErrorMessages$1 = {
3484
+ [ErrorCodes$1.interactivityPluginNotLoaded]: "tsParticles Interactivity Plugin is not loaded",
3485
+ [ErrorCodes$1.interactivityClickHandlerNotSet]: "Click handlers can only be set after calling tsParticles.load()",
3486
+ };
3487
+
3284
3488
  class ClickEvent {
3285
3489
  enable = false;
3286
3490
  mode = [];
@@ -3357,9 +3561,7 @@
3357
3561
 
3358
3562
  class Modes {
3359
3563
  #container;
3360
- #pluginManager;
3361
- constructor(pluginManager, container) {
3362
- this.#pluginManager = pluginManager;
3564
+ constructor(container) {
3363
3565
  this.#container = container;
3364
3566
  }
3365
3567
  load(data) {
@@ -3369,10 +3571,7 @@
3369
3571
  if (!this.#container) {
3370
3572
  return;
3371
3573
  }
3372
- const interactors = this.#pluginManager.interactors?.get(this.#container);
3373
- if (!interactors) {
3374
- return;
3375
- }
3574
+ const interactors = this.#container.interactionManager?.interactors ?? [];
3376
3575
  for (const interactor of interactors) {
3377
3576
  if (!interactor.loadModeOptions) {
3378
3577
  continue;
@@ -3386,8 +3585,8 @@
3386
3585
  detectsOn = InteractivityDetect.window;
3387
3586
  events = new Events();
3388
3587
  modes;
3389
- constructor(pluginManager, container) {
3390
- this.modes = new Modes(pluginManager, container);
3588
+ constructor(container) {
3589
+ this.modes = new Modes(container);
3391
3590
  }
3392
3591
  load(data) {
3393
3592
  if (isNull(data)) {
@@ -3418,10 +3617,10 @@
3418
3617
  }
3419
3618
  let interactivityOptions = options.interactivity;
3420
3619
  if (!interactivityOptions?.load) {
3421
- options.interactivity = interactivityOptions = new Interactivity(this.#pluginManager, container);
3620
+ options.interactivity = interactivityOptions = new Interactivity(container);
3422
3621
  }
3423
3622
  interactivityOptions.load(source?.interactivity);
3424
- const interactors = this.#pluginManager.interactors?.get(container);
3623
+ const interactors = container.interactionManager?.interactors;
3425
3624
  if (!interactors) {
3426
3625
  return;
3427
3626
  }
@@ -3435,7 +3634,7 @@
3435
3634
  if (source?.interactivity) {
3436
3635
  options.interactivity = deepExtend({}, source.interactivity);
3437
3636
  }
3438
- const interactors = this.#pluginManager.interactors?.get(container);
3637
+ const interactors = container.interactionManager?.interactors;
3439
3638
  if (!interactors) {
3440
3639
  return;
3441
3640
  }
@@ -3465,25 +3664,25 @@
3465
3664
  const clickEvent = "click", mouseDownEvent = "pointerdown", mouseUpEvent = "pointerup", mouseLeaveEvent = "pointerleave", mouseMoveEvent = "pointermove", touchStartEvent = "touchstart", touchEndEvent = "touchend", touchMoveEvent = "touchmove", touchCancelEvent = "touchcancel";
3466
3665
 
3467
3666
  async function loadInteractivityPlugin(engine) {
3468
- engine.checkVersion("4.3.2");
3667
+ engine.checkVersion("4.5.0");
3668
+ if (typeof process !== "undefined" && process.env.NODE_ENV !== "production") {
3669
+ addErrorMessages(ErrorMessages$1);
3670
+ }
3469
3671
  await engine.pluginManager.register(e => {
3470
3672
  const interactivityEngine = e, interactivityPluginManager = interactivityEngine.pluginManager;
3471
3673
  interactivityPluginManager.addPlugin(new InteractivityPlugin(interactivityPluginManager));
3472
3674
  interactivityPluginManager.initializers.interactors ??= new Map();
3473
- interactivityPluginManager.interactors ??= new Map();
3474
3675
  interactivityPluginManager.addInteractor = (name, interactorInitializer) => {
3676
+ if (interactivityPluginManager.initialized) {
3677
+ return;
3678
+ }
3475
3679
  interactivityPluginManager.initializers.interactors ??= new Map();
3476
3680
  interactivityPluginManager.initializers.interactors.set(name, interactorInitializer);
3477
3681
  };
3478
- interactivityPluginManager.getInteractors = async (container, force = false) => {
3479
- interactivityPluginManager.interactors ??= new Map();
3480
- interactivityPluginManager.initializers.interactors ??= new Map();
3481
- return getItemsFromInitializer(container, interactivityPluginManager.interactors, interactivityPluginManager.initializers.interactors, force);
3482
- };
3483
3682
  interactivityPluginManager.setOnClickHandler = (callback) => {
3484
3683
  const { items } = interactivityEngine;
3485
3684
  if (!items.length) {
3486
- throw new Error("Click handlers can only be set after calling tsParticles.load()");
3685
+ throw new Error(getErrorMessage(ErrorCodes$1.interactivityClickHandlerNotSet));
3487
3686
  }
3488
3687
  items.forEach(item => {
3489
3688
  const interactivityContainer = item;
@@ -3494,7 +3693,7 @@
3494
3693
  }
3495
3694
  function ensureInteractivityPluginLoaded(e) {
3496
3695
  if (!e.pluginManager.addInteractor) {
3497
- throw new Error("tsParticles Interactivity Plugin is not loaded");
3696
+ throw new Error(getErrorMessage(ErrorCodes$1.interactivityPluginNotLoaded));
3498
3697
  }
3499
3698
  }
3500
3699
 
@@ -3503,6 +3702,7 @@
3503
3702
  CollisionMode["absorb"] = "absorb";
3504
3703
  CollisionMode["bounce"] = "bounce";
3505
3704
  CollisionMode["destroy"] = "destroy";
3705
+ CollisionMode["fluid"] = "fluid";
3506
3706
  })(CollisionMode || (CollisionMode = {}));
3507
3707
 
3508
3708
  class CollisionsAbsorb {
@@ -3515,6 +3715,26 @@
3515
3715
  }
3516
3716
  }
3517
3717
 
3718
+ class CollisionsFluid {
3719
+ maxForce = 2.5;
3720
+ maxNeighbors = 64;
3721
+ nearStiffness = 0.5;
3722
+ radius = 30;
3723
+ restDensity = 3;
3724
+ stiffness = 0.5;
3725
+ load(data) {
3726
+ if (isNull(data)) {
3727
+ return;
3728
+ }
3729
+ loadRangeProperty(this, "maxForce", data.maxForce);
3730
+ loadProperty(this, "maxNeighbors", data.maxNeighbors);
3731
+ loadRangeProperty(this, "nearStiffness", data.nearStiffness);
3732
+ loadRangeProperty(this, "radius", data.radius);
3733
+ loadRangeProperty(this, "restDensity", data.restDensity);
3734
+ loadRangeProperty(this, "stiffness", data.stiffness);
3735
+ }
3736
+ }
3737
+
3518
3738
  class CollisionsOverlap {
3519
3739
  enable = true;
3520
3740
  retries = 0;
@@ -3531,6 +3751,7 @@
3531
3751
  absorb = new CollisionsAbsorb();
3532
3752
  bounce = new ParticlesBounce();
3533
3753
  enable = false;
3754
+ fluid = new CollisionsFluid();
3534
3755
  maxSpeed = 50;
3535
3756
  mode = CollisionMode.bounce;
3536
3757
  overlap = new CollisionsOverlap();
@@ -3541,12 +3762,181 @@
3541
3762
  this.absorb.load(data.absorb);
3542
3763
  this.bounce.load(data.bounce);
3543
3764
  loadProperty(this, "enable", data.enable);
3765
+ this.fluid.load(data.fluid);
3544
3766
  loadRangeProperty(this, "maxSpeed", data.maxSpeed);
3545
3767
  loadProperty(this, "mode", data.mode);
3546
3768
  this.overlap.load(data.overlap);
3547
3769
  }
3548
3770
  }
3549
3771
 
3772
+ const wallMarginFactor = 0.15, restRetention = 0.1, supportContacts = 5, wallSpringFactor = half, minNeighborDistance = 0.0001, solverIterations = 3, separationIterations = 3;
3773
+ function applyWallSpring(position, margin, maxX, maxY) {
3774
+ if (position.x < margin) {
3775
+ position.x += (margin - position.x) * wallSpringFactor;
3776
+ }
3777
+ else if (position.x > maxX) {
3778
+ position.x -= (position.x - maxX) * wallSpringFactor;
3779
+ }
3780
+ if (position.y < margin) {
3781
+ position.y += (margin - position.y) * wallSpringFactor;
3782
+ }
3783
+ else if (position.y > maxY) {
3784
+ position.y -= (position.y - maxY) * wallSpringFactor;
3785
+ }
3786
+ }
3787
+ function clampToWalls(position, margin, maxX, maxY) {
3788
+ if (position.x < margin) {
3789
+ position.x = margin;
3790
+ }
3791
+ else if (position.x > maxX) {
3792
+ position.x = maxX;
3793
+ }
3794
+ if (position.y < margin) {
3795
+ position.y = margin;
3796
+ }
3797
+ else if (position.y > maxY) {
3798
+ position.y = maxY;
3799
+ }
3800
+ }
3801
+ class FluidSolver {
3802
+ #dir = Vector.origin;
3803
+ #isNeighbor;
3804
+ #maxNeighbors = minCount;
3805
+ #neighbors = [];
3806
+ #owner;
3807
+ #ownerZ = defaultAngle;
3808
+ constructor() {
3809
+ this.#isNeighbor = (particle) => {
3810
+ const owner = this.#owner, neighbor = particle;
3811
+ if (!owner ||
3812
+ this.#neighbors.length >= this.#maxNeighbors ||
3813
+ neighbor === owner ||
3814
+ neighbor.destroyed ||
3815
+ neighbor.spawning ||
3816
+ !neighbor.options.collisions?.enable ||
3817
+ neighbor.options.collisions.mode !== CollisionMode.fluid) {
3818
+ return false;
3819
+ }
3820
+ const ownerRadius = owner.getRadius();
3821
+ return (Math.abs(Math.round(this.#ownerZ) - Math.round(neighbor.getPosition().z)) <= ownerRadius + neighbor.getRadius());
3822
+ };
3823
+ }
3824
+ separateOverlaps(particle, position) {
3825
+ const neighbors = this.#neighbors, particlePosition = particle.position;
3826
+ particlePosition.setTo(position);
3827
+ for (let iteration = 0; iteration < separationIterations; iteration++) {
3828
+ for (const neighbor of neighbors) {
3829
+ this.#projectPair(particle, neighbor);
3830
+ }
3831
+ }
3832
+ }
3833
+ solve(container, particle) {
3834
+ const collisionsOptions = particle.options.collisions;
3835
+ if (!collisionsOptions) {
3836
+ return;
3837
+ }
3838
+ const fluidOptions = collisionsOptions.fluid, pixelRatio = container.retina.pixelRatio, radius = getRangeValue(fluidOptions.radius) * pixelRatio, stiffness = getRangeValue(fluidOptions.stiffness), nearStiffness = getRangeValue(fluidOptions.nearStiffness), restDensity = getRangeValue(fluidOptions.restDensity), maxForce = getRangeValue(fluidOptions.maxForce), maxNeighbors = fluidOptions.maxNeighbors, particleRadius = particle.getRadius(), position = particle.position, canvasSize = container.canvas.size, hasBounds = canvasSize.width > minRadius && canvasSize.height > minRadius, margin = hasBounds ? particleRadius * wallMarginFactor : minRadius, maxX = canvasSize.width - margin, maxY = canvasSize.height - margin, neighbors = this.#neighbors;
3839
+ this.#owner = particle;
3840
+ this.#maxNeighbors = maxNeighbors;
3841
+ this.#ownerZ = particle.getPosition().z;
3842
+ this.#queryNeighbors(container, particle, radius, maxNeighbors);
3843
+ for (let iteration = 0; iteration < solverIterations; iteration++) {
3844
+ const focalPosition = particle.getPosition();
3845
+ let density = 0, densityNear = 0;
3846
+ for (const neighbor of neighbors) {
3847
+ const dist = getDistance(focalPosition, neighbor.getPosition()), q = identity - dist / radius, q2 = q * q;
3848
+ density += q2;
3849
+ densityNear += q2 * q;
3850
+ }
3851
+ const pressure = (density - restDensity) * stiffness * half, pressureNear = densityNear * nearStiffness * half;
3852
+ if (hasBounds) {
3853
+ applyWallSpring(position, margin, maxX, maxY);
3854
+ }
3855
+ for (const neighbor of neighbors) {
3856
+ const neighborPosition = neighbor.getPosition(), dx = neighborPosition.x - focalPosition.x, dy = neighborPosition.y - focalPosition.y, dist = Math.sqrt(dx * dx + dy * dy);
3857
+ if (dist > radius) {
3858
+ continue;
3859
+ }
3860
+ const q = identity - dist / radius, force = clamp(pressure + pressureNear * q, -maxForce, maxForce), contactDistance = particleRadius + neighbor.getRadius(), push = Math.max(q * force * half, contactDistance - dist);
3861
+ if (dist > minNeighborDistance) {
3862
+ const inverseDist = inverseFactorNumerator / dist;
3863
+ this.#dir.x = dx * inverseDist * push;
3864
+ this.#dir.y = dy * inverseDist * push;
3865
+ }
3866
+ else {
3867
+ this.#dir.x = (particle.id + neighbor.id) % double === minCount ? identity : -identity;
3868
+ this.#dir.y = defaultAngle;
3869
+ this.#dir.multTo(push);
3870
+ }
3871
+ position.x -= this.#dir.x;
3872
+ position.y -= this.#dir.y;
3873
+ }
3874
+ }
3875
+ this.#queryNeighbors(container, particle, radius, maxNeighbors);
3876
+ if (hasBounds) {
3877
+ clampToWalls(position, margin, maxX, maxY);
3878
+ }
3879
+ this.separateOverlaps(particle, position);
3880
+ this.#dampContacts(particle);
3881
+ if (hasBounds) {
3882
+ this.#cancelWallVelocity(particle, margin, maxX, maxY);
3883
+ }
3884
+ }
3885
+ #cancelWallVelocity(particle, margin, maxX, maxY) {
3886
+ const position = particle.position, velocity = particle.velocity;
3887
+ if (position.x <= margin) {
3888
+ velocity.x = defaultAngle;
3889
+ }
3890
+ else if (position.x >= maxX) {
3891
+ velocity.x = defaultAngle;
3892
+ }
3893
+ if (position.y <= margin) {
3894
+ velocity.y = defaultAngle;
3895
+ }
3896
+ else if (position.y >= maxY) {
3897
+ velocity.y = defaultAngle;
3898
+ }
3899
+ }
3900
+ #dampContacts(particle) {
3901
+ const neighbors = this.#neighbors, position = particle.position, velocity = particle.velocity;
3902
+ let touching = minCount;
3903
+ for (const neighbor of neighbors) {
3904
+ const neighborPosition = neighbor.getPosition(), dx = position.x - neighborPosition.x, dy = position.y - neighborPosition.y, distanceSq = dx * dx + dy * dy, contactDistance = particle.getRadius() + neighbor.getRadius();
3905
+ if (distanceSq >= contactDistance * contactDistance || distanceSq <= minNeighborDistance) {
3906
+ continue;
3907
+ }
3908
+ if (++touching < supportContacts) {
3909
+ continue;
3910
+ }
3911
+ velocity.x *= restRetention;
3912
+ velocity.y *= restRetention;
3913
+ return;
3914
+ }
3915
+ }
3916
+ #projectPair(p1, p2) {
3917
+ const pos1 = p1.position, pos2 = p2.position, dx = pos1.x - pos2.x, dy = pos1.y - pos2.y, distanceSq = dx * dx + dy * dy, minDistance = p1.getRadius() + p2.getRadius();
3918
+ if (distanceSq >= minDistance * minDistance) {
3919
+ return;
3920
+ }
3921
+ if (distanceSq > minNeighborDistance) {
3922
+ const distance = Math.sqrt(distanceSq), inverseDistance = inverseFactorNumerator / distance, correction = minDistance - distance;
3923
+ pos1.x += dx * inverseDistance * correction;
3924
+ pos1.y += dy * inverseDistance * correction;
3925
+ }
3926
+ else {
3927
+ const direction = (p1.id + p2.id) % double === minCount ? identity : -identity;
3928
+ pos1.x += direction * minDistance;
3929
+ }
3930
+ }
3931
+ #queryNeighbors(container, particle, radius, maxNeighbors) {
3932
+ if (radius <= minRadius || maxNeighbors <= minCount) {
3933
+ return;
3934
+ }
3935
+ this.#neighbors.length = 0;
3936
+ container.particles.grid.queryCircle(particle.getPosition(), radius, this.#isNeighbor, this.#neighbors);
3937
+ }
3938
+ }
3939
+
3550
3940
  const minAbsorbAmount = 0;
3551
3941
  function updateAbsorb(p1, r1, p2, r2, delta, pixelRatio) {
3552
3942
  if (!p1.options.collisions || !p2.options.collisions) {
@@ -3636,14 +4026,22 @@
3636
4026
  destroy(p1, p2);
3637
4027
  break;
3638
4028
  }
4029
+ case CollisionMode.fluid: {
4030
+ break;
4031
+ }
3639
4032
  }
3640
4033
  }
3641
4034
 
3642
4035
  class Collider extends ParticlesInteractorBase {
3643
- maxDistance;
4036
+ #fluidSolver;
4037
+ #maxDistance;
3644
4038
  constructor(container) {
3645
4039
  super(container);
3646
- this.maxDistance = 0;
4040
+ this.#fluidSolver = new FluidSolver();
4041
+ this.#maxDistance = 0;
4042
+ }
4043
+ get maxDistance() {
4044
+ return this.#maxDistance;
3647
4045
  }
3648
4046
  clear() {
3649
4047
  }
@@ -3653,13 +4051,24 @@
3653
4051
  if (p1.destroyed || p1.spawning) {
3654
4052
  return;
3655
4053
  }
4054
+ const collisions = p1.options.collisions;
4055
+ if (!collisions?.enable) {
4056
+ return;
4057
+ }
4058
+ if (collisions.mode === CollisionMode.fluid) {
4059
+ const fluidRadius = getRangeValue(collisions.fluid.radius);
4060
+ if (fluidRadius > this.#maxDistance) {
4061
+ this.#maxDistance = fluidRadius;
4062
+ }
4063
+ this.#fluidSolver.solve(this.container, p1);
4064
+ return;
4065
+ }
3656
4066
  const container = this.container, pos1 = p1.getPosition(), radius1 = p1.getRadius(), query = container.particles.grid.queryCircle(pos1, radius1 * double);
3657
4067
  for (const p2 of query) {
3658
4068
  if (p1 === p2 ||
3659
4069
  p1.id >= p2.id ||
3660
- !p1.options.collisions?.enable ||
3661
4070
  !p2.options.collisions?.enable ||
3662
- p1.options.collisions.mode !== p2.options.collisions.mode ||
4071
+ collisions.mode !== p2.options.collisions.mode ||
3663
4072
  p2.destroyed ||
3664
4073
  p2.spawning) {
3665
4074
  continue;
@@ -3681,10 +4090,18 @@
3681
4090
  loadParticlesOptions(options, ...sources) {
3682
4091
  loadOptionProperty(options, "collisions", Collisions, ...sources);
3683
4092
  }
3684
- reset() {
4093
+ reset(_interactivityData, _particle) {
3685
4094
  }
3686
4095
  }
3687
4096
 
4097
+ const ErrorCodes = {
4098
+ overlapNotPlaced: "TSP-4001",
4099
+ };
4100
+
4101
+ const ErrorMessages = {
4102
+ [ErrorCodes.overlapNotPlaced]: "Particle is overlapping and can't be placed",
4103
+ };
4104
+
3688
4105
  class OverlapPlugin {
3689
4106
  id = "overlap";
3690
4107
  async getPlugin(container) {
@@ -3699,7 +4116,10 @@
3699
4116
  }
3700
4117
 
3701
4118
  async function loadParticlesCollisionsInteraction(engine) {
3702
- engine.checkVersion("4.3.2");
4119
+ engine.checkVersion("4.5.0");
4120
+ if (typeof process !== "undefined" && process.env.NODE_ENV !== "production") {
4121
+ addErrorMessages(ErrorMessages);
4122
+ }
3703
4123
  await engine.pluginManager.register((e) => {
3704
4124
  ensureInteractivityPluginLoaded(e);
3705
4125
  e.pluginManager.addPlugin(new OverlapPlugin());
@@ -3912,7 +4332,7 @@
3912
4332
  const linkColor = linksOptions.id !== undefined
3913
4333
  ? container.particles.linksColors.get(linksOptions.id)
3914
4334
  : container.particles.linksColor;
3915
- return getLinkColor(p1, p2, linkColor);
4335
+ return getLinkColor(p1, p2, linkColor, container.hdr);
3916
4336
  }
3917
4337
  #setColor(p1) {
3918
4338
  if (!p1.options.links) {
@@ -3953,7 +4373,7 @@
3953
4373
  }
3954
4374
 
3955
4375
  async function loadParticlesLinksInteraction(engine) {
3956
- engine.checkVersion("4.3.2");
4376
+ engine.checkVersion("4.5.0");
3957
4377
  await engine.pluginManager.register((e) => {
3958
4378
  const pluginManager = e.pluginManager;
3959
4379
  ensureInteractivityPluginLoaded(e);
@@ -3966,7 +4386,7 @@
3966
4386
 
3967
4387
  let initPromise = null;
3968
4388
  async function doInitPlugins(engine) {
3969
- engine.checkVersion("4.3.2");
4389
+ engine.checkVersion("4.5.0");
3970
4390
  await engine.pluginManager.register(async (e) => {
3971
4391
  const loadParticlesInteractivity = async (e) => {
3972
4392
  await loadInteractivityPlugin(e);
@@ -4009,7 +4429,7 @@
4009
4429
  particles.init = async () => {
4010
4430
  await initPlugins(tsParticles);
4011
4431
  };
4012
- particles.version = "4.3.2";
4432
+ particles.version = "4.5.0";
4013
4433
  globalThis.particles = particles;
4014
4434
 
4015
4435
  const globalObject = globalThis;
@@ -4079,21 +4499,28 @@
4079
4499
  });
4080
4500
  }
4081
4501
  clear() {
4502
+ const visited = new Set();
4082
4503
  for (const plugin of this.#canvasClearPlugins) {
4504
+ visited.add(plugin);
4083
4505
  if (plugin.canvasClear?.() ?? false) {
4084
- return;
4506
+ return plugin;
4085
4507
  }
4086
4508
  }
4087
4509
  for (const layer of Object.values(exports.DrawLayer)) {
4088
4510
  if (typeof layer === "number") {
4089
4511
  for (const plugin of this.#getLayerPlugins(layer)) {
4512
+ if (visited.has(plugin)) {
4513
+ continue;
4514
+ }
4515
+ visited.add(plugin);
4090
4516
  if (plugin.canvasClear?.() ?? false) {
4091
- return;
4517
+ return plugin;
4092
4518
  }
4093
4519
  }
4094
4520
  }
4095
4521
  }
4096
4522
  this.canvasClear();
4523
+ return undefined;
4097
4524
  }
4098
4525
  destroy() {
4099
4526
  this.stop();
@@ -4134,7 +4561,11 @@
4134
4561
  if (!fColor && !sColor) {
4135
4562
  return;
4136
4563
  }
4137
- 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;
4564
+ 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
4565
+ ? getStyleFromHsl(fColor, container.hdr, fillOpacity * opacity, container.peakNits, container.hdrMode)
4566
+ : undefined, stroke = sColor
4567
+ ? getStyleFromHsl(sColor, container.hdr, strokeOpacity * opacity, container.peakNits, container.hdrMode)
4568
+ : fill;
4138
4569
  transform.a = transform.b = transform.c = transform.d = undefined;
4139
4570
  colorStyles.fill = fill;
4140
4571
  colorStyles.stroke = stroke;
@@ -4167,8 +4598,7 @@
4167
4598
  });
4168
4599
  }
4169
4600
  drawParticles(delta) {
4170
- const { particles, actualOptions } = this.#container;
4171
- this.clear();
4601
+ const { particles, actualOptions } = this.#container, clearedPlugin = this.clear();
4172
4602
  particles.update(delta);
4173
4603
  this.draw(ctx => {
4174
4604
  const width = this.#canvasManager.size.width, height = this.#canvasManager.size.height;
@@ -4190,7 +4620,9 @@
4190
4620
  }
4191
4621
  }
4192
4622
  for (const plugin of this.#getLayerPlugins(exports.DrawLayer.BackgroundMask)) {
4193
- plugin.canvasPaint?.();
4623
+ if (plugin !== clearedPlugin) {
4624
+ plugin.canvasPaint?.();
4625
+ }
4194
4626
  }
4195
4627
  for (const plugin of this.#getLayerPlugins(exports.DrawLayer.CanvasSetup)) {
4196
4628
  plugin.drawSettingsSetup?.(ctx, delta);
@@ -4209,48 +4641,20 @@
4209
4641
  this.initUpdaters();
4210
4642
  this.initPlugins();
4211
4643
  this.#resolveBackgroundElement();
4212
- this.paint();
4213
- }
4214
- initPlugins() {
4215
- this.#canvasClearPlugins = [];
4216
- this.#colorPlugins = [];
4217
- this.#drawParticlePlugins = [];
4218
- this.#drawParticlesSetupPlugins = [];
4219
- this.#drawParticlesCleanupPlugins = [];
4220
- for (const layer of Object.values(exports.DrawLayer)) {
4221
- if (typeof layer === "number") {
4222
- this.#layers[layer] = [];
4223
- }
4224
- }
4225
- for (const plugin of this.#container.plugins) {
4226
- if (plugin.particleFillColor ?? plugin.particleStrokeColor) {
4227
- this.#colorPlugins.push(plugin);
4228
- }
4229
- if (plugin.drawParticle) {
4230
- this.#drawParticlePlugins.push(plugin);
4231
- }
4232
- if (plugin.drawParticleSetup) {
4233
- this.#drawParticlesSetupPlugins.push(plugin);
4234
- }
4235
- if (plugin.drawParticleCleanup) {
4236
- this.#drawParticlesCleanupPlugins.push(plugin);
4237
- }
4238
- if (plugin.canvasClear) {
4239
- this.#canvasClearPlugins.push(plugin);
4240
- }
4241
- if (plugin.canvasPaint) {
4242
- this.#getLayerPlugins(exports.DrawLayer.BackgroundMask).push(plugin);
4243
- }
4244
- if (plugin.drawSettingsSetup) {
4245
- this.#getLayerPlugins(exports.DrawLayer.CanvasSetup).push(plugin);
4246
- }
4247
- if (plugin.draw) {
4248
- this.#getLayerPlugins(exports.DrawLayer.PluginContent).push(plugin);
4249
- }
4250
- if (plugin.clearDraw ?? plugin.drawSettingsCleanup) {
4251
- this.#getLayerPlugins(exports.DrawLayer.CanvasCleanup).push(plugin);
4644
+ this.paint();
4645
+ }
4646
+ initPlugins() {
4647
+ this.#canvasClearPlugins = [];
4648
+ this.#colorPlugins = [];
4649
+ this.#drawParticlePlugins = [];
4650
+ this.#drawParticlesSetupPlugins = [];
4651
+ this.#drawParticlesCleanupPlugins = [];
4652
+ for (const layer of Object.values(exports.DrawLayer)) {
4653
+ if (typeof layer === "number") {
4654
+ this.#layers[layer] = [];
4252
4655
  }
4253
4656
  }
4657
+ this.#initPluginsArray();
4254
4658
  }
4255
4659
  initUpdaters() {
4256
4660
  this.#preDrawUpdaters = [];
@@ -4459,6 +4863,45 @@
4459
4863
  this.#reusablePluginColors[sColorIndex] = sColor;
4460
4864
  return this.#reusablePluginColors;
4461
4865
  }
4866
+ #initLayerPlugin(plugin) {
4867
+ const layerMap = [
4868
+ [exports.DrawLayer.BackgroundMask, !!plugin.canvasPaint],
4869
+ [exports.DrawLayer.CanvasSetup, !!plugin.drawSettingsSetup],
4870
+ [exports.DrawLayer.PluginContent, !!plugin.draw],
4871
+ [exports.DrawLayer.CanvasCleanup, !!(plugin.clearDraw ?? plugin.drawSettingsCleanup)],
4872
+ ];
4873
+ for (const [layer, active] of layerMap) {
4874
+ if (active) {
4875
+ this.#layers[layer].push(plugin);
4876
+ }
4877
+ }
4878
+ }
4879
+ #initPluginsArray() {
4880
+ for (const plugin of this.#container.plugins) {
4881
+ if (plugin.particleFillColor ?? plugin.particleStrokeColor) {
4882
+ this.#colorPlugins.push(plugin);
4883
+ }
4884
+ if (plugin.drawParticle) {
4885
+ this.#drawParticlePlugins.push(plugin);
4886
+ }
4887
+ if (plugin.drawParticleSetup) {
4888
+ this.#drawParticlesSetupPlugins.push(plugin);
4889
+ }
4890
+ if (plugin.drawParticleCleanup) {
4891
+ this.#drawParticlesCleanupPlugins.push(plugin);
4892
+ }
4893
+ if (plugin.canvasClear) {
4894
+ this.#canvasClearPlugins.push(plugin);
4895
+ }
4896
+ this.#initLayerPlugin(plugin);
4897
+ }
4898
+ }
4899
+ #isSupportedElement(element) {
4900
+ return ((typeof HTMLCanvasElement !== "undefined" && element instanceof HTMLCanvasElement) ||
4901
+ (typeof OffscreenCanvas !== "undefined" && element instanceof OffscreenCanvas) ||
4902
+ (typeof HTMLVideoElement !== "undefined" && element instanceof HTMLVideoElement) ||
4903
+ (typeof HTMLImageElement !== "undefined" && element instanceof HTMLImageElement));
4904
+ }
4462
4905
  #resolveBackgroundElement() {
4463
4906
  const background = this.#container.actualOptions.background;
4464
4907
  this.#backgroundElement = null;
@@ -4468,7 +4911,7 @@
4468
4911
  if (typeof background.element === "string") {
4469
4912
  if (typeof document !== "undefined") {
4470
4913
  const node = document.querySelector(background.element);
4471
- if (node instanceof HTMLCanvasElement || node instanceof HTMLVideoElement || node instanceof HTMLImageElement) {
4914
+ if (node && this.#isSupportedElement(node)) {
4472
4915
  this.#backgroundElement = node;
4473
4916
  }
4474
4917
  else if (node) {
@@ -4479,10 +4922,7 @@
4479
4922
  }
4480
4923
  }
4481
4924
  }
4482
- else if (background.element instanceof HTMLCanvasElement ||
4483
- background.element instanceof OffscreenCanvas ||
4484
- background.element instanceof HTMLVideoElement ||
4485
- background.element instanceof HTMLImageElement) {
4925
+ else if (this.#isSupportedElement(background.element)) {
4486
4926
  this.#backgroundElement = background.element;
4487
4927
  }
4488
4928
  }
@@ -4500,7 +4940,7 @@
4500
4940
  return transferredCanvas;
4501
4941
  }
4502
4942
  if (typeof canvas.transferControlToOffscreen !== "function") {
4503
- throw new TypeError("OffscreenCanvas is required but not supported by this browser");
4943
+ throw new TypeError(getErrorMessage(ErrorCodes$3.offscreenCanvasUnsupported));
4504
4944
  }
4505
4945
  try {
4506
4946
  const offscreenCanvas = canvas.transferControlToOffscreen();
@@ -4508,10 +4948,16 @@
4508
4948
  return offscreenCanvas;
4509
4949
  }
4510
4950
  catch {
4511
- throw new TypeError("OffscreenCanvas transfer failed");
4951
+ throw new TypeError(getErrorMessage(ErrorCodes$3.offscreenCanvasTransferFailed));
4512
4952
  }
4513
4953
  }, isHtmlCanvasElement = (canvas) => {
4514
4954
  return typeof HTMLCanvasElement !== "undefined" && canvas instanceof HTMLCanvasElement;
4955
+ }, getEffectiveColorSpace = (context) => {
4956
+ if (!context) {
4957
+ return undefined;
4958
+ }
4959
+ const colorInfo = context;
4960
+ return colorInfo.getContextAttributes?.().colorSpace ?? undefined;
4515
4961
  };
4516
4962
  function setStyle(canvas, style, important = false) {
4517
4963
  if (!style) {
@@ -4550,6 +4996,7 @@
4550
4996
  zoom = defaultZoom;
4551
4997
  #container;
4552
4998
  #generated;
4999
+ #hdrMediaListeners;
4553
5000
  #mutationObserver;
4554
5001
  #originalStyle;
4555
5002
  #pluginManager;
@@ -4614,7 +5061,6 @@
4614
5061
  });
4615
5062
  this.resize();
4616
5063
  this.#initStyle();
4617
- this.initBackground();
4618
5064
  this.#safeMutationObserver(obs => {
4619
5065
  const element = this.domElement;
4620
5066
  if (!element || !(element instanceof Node)) {
@@ -4624,6 +5070,8 @@
4624
5070
  });
4625
5071
  this.initPlugins();
4626
5072
  this.#initContext();
5073
+ this.initBackground();
5074
+ this.#initHdrListeners();
4627
5075
  this.render.init();
4628
5076
  }
4629
5077
  initBackground() {
@@ -4633,7 +5081,8 @@
4633
5081
  }
4634
5082
  const elementStyle = element.style, color = rangeColorToRgb(this.#pluginManager, background.color);
4635
5083
  if (color) {
4636
- elementStyle.backgroundColor = getStyleFromRgb(color, container.actualOptions.hdr, background.opacity);
5084
+ const hdrOptions = container.actualOptions.hdr;
5085
+ elementStyle.backgroundColor = getStyleFromRgb(color, container.hdr, background.opacity, hdrOptions.peakNits, toEnumValue(exports.HdrMode, hdrOptions.mode, exports.HdrMode.standard));
4637
5086
  }
4638
5087
  else {
4639
5088
  elementStyle.backgroundColor = "";
@@ -4730,6 +5179,7 @@
4730
5179
  obs.disconnect();
4731
5180
  });
4732
5181
  this.#mutationObserver = undefined;
5182
+ this.#removeHdrListeners();
4733
5183
  this.render.stop();
4734
5184
  }
4735
5185
  async windowResize() {
@@ -4749,9 +5199,16 @@
4749
5199
  }
4750
5200
  }
4751
5201
  #initContext() {
4752
- const container = this.#container, canSupportHdr = container.actualOptions.hdr &&
5202
+ const container = this.#container, canSupportHdr = container.actualOptions.hdr.enable &&
4753
5203
  safeMatchMedia("(color-gamut: p3)")?.matches &&
4754
5204
  safeMatchMedia("(dynamic-range: high)")?.matches;
5205
+ container.hdrMode = toEnumValue(exports.HdrMode, container.actualOptions.hdr.mode, exports.HdrMode.standard);
5206
+ container.peakNits = container.actualOptions.hdr.peakNits;
5207
+ const renderCanvas = this.renderCanvas;
5208
+ if (!renderCanvas) {
5209
+ container.hdr = canSupportHdr ?? false;
5210
+ return;
5211
+ }
4755
5212
  this.render.setContextSettings({
4756
5213
  alpha: true,
4757
5214
  desynchronized: true,
@@ -4760,11 +5217,51 @@
4760
5217
  ? { colorSpace: "display-p3", colorType: "float16" }
4761
5218
  : { colorSpace: "srgb" }),
4762
5219
  });
4763
- const renderCanvas = this.renderCanvas;
4764
- if (!renderCanvas) {
4765
- return;
5220
+ let context;
5221
+ try {
5222
+ context = renderCanvas.getContext("2d", this.render.settings);
5223
+ }
5224
+ catch {
5225
+ context = null;
5226
+ }
5227
+ if (canSupportHdr && !context) {
5228
+ const sdrSettings = {
5229
+ alpha: true,
5230
+ desynchronized: true,
5231
+ willReadFrequently: false,
5232
+ colorSpace: "srgb",
5233
+ };
5234
+ this.render.setContextSettings(sdrSettings);
5235
+ try {
5236
+ context = renderCanvas.getContext("2d", sdrSettings);
5237
+ }
5238
+ catch {
5239
+ context = null;
5240
+ }
5241
+ }
5242
+ this.render.setContext(context);
5243
+ if (context) {
5244
+ const effectiveColorSpace = getEffectiveColorSpace(context);
5245
+ if (effectiveColorSpace !== undefined) {
5246
+ container.hdr = effectiveColorSpace === "display-p3";
5247
+ }
5248
+ }
5249
+ }
5250
+ #initHdrListeners() {
5251
+ this.#removeHdrListeners();
5252
+ const p3Query = safeMatchMedia("(color-gamut: p3)"), hdrQuery = safeMatchMedia("(dynamic-range: high)"), handleChange = () => {
5253
+ this.#initContext();
5254
+ this.initBackground();
5255
+ }, listeners = [];
5256
+ if (p3Query) {
5257
+ p3Query.addEventListener("change", handleChange);
5258
+ listeners.push({ handler: handleChange, mql: p3Query });
5259
+ }
5260
+ if (hdrQuery) {
5261
+ hdrQuery.addEventListener("change", handleChange);
5262
+ listeners.push({ handler: handleChange, mql: hdrQuery });
4766
5263
  }
4767
- this.render.setContext(renderCanvas.getContext("2d", this.render.settings));
5264
+ this.#hdrMediaListeners = listeners;
4768
5265
  }
4769
5266
  #initStyle() {
4770
5267
  const element = this.domElement, options = this.#container.actualOptions;
@@ -4788,6 +5285,15 @@
4788
5285
  element.style.setProperty(key, value, "important");
4789
5286
  }
4790
5287
  }
5288
+ #removeHdrListeners() {
5289
+ if (!this.#hdrMediaListeners) {
5290
+ return;
5291
+ }
5292
+ for (const { handler, mql } of this.#hdrMediaListeners) {
5293
+ mql.removeEventListener("change", handler);
5294
+ }
5295
+ this.#hdrMediaListeners = undefined;
5296
+ }
4791
5297
  #repairStyle() {
4792
5298
  const element = this.domElement;
4793
5299
  if (!element) {
@@ -4877,8 +5383,7 @@
4877
5383
  this.#resizeTimeout = undefined;
4878
5384
  }
4879
5385
  const handleResize = async () => {
4880
- const canvas = this.#container.canvas;
4881
- await canvas.windowResize();
5386
+ await this.#container.canvas.windowResize();
4882
5387
  };
4883
5388
  this.#resizeTimeout = setTimeout(() => void handleResize(), this.#container.actualOptions.resize.delay * millisecondsToSeconds);
4884
5389
  }
@@ -4906,8 +5411,8 @@
4906
5411
  }
4907
5412
  else if (!this.#resizeObserver && add && canvasEl) {
4908
5413
  this.#resizeObserver = new ResizeObserver((entries) => {
4909
- const entry = entries.find(e => e.target === canvasEl);
4910
- if (!entry) {
5414
+ const res = entries.some(e => e.target === canvasEl);
5415
+ if (!res) {
4911
5416
  return;
4912
5417
  }
4913
5418
  this.#handleWindowResize();
@@ -5171,10 +5676,10 @@
5171
5676
  return this.#modifiers.find(m => m.id === id);
5172
5677
  }
5173
5678
  getOpacity() {
5174
- const zIndexOptions = this.options.zIndex, zIndexFactor = zIndexFactorOffset - this.zIndexFactor, zOpacityFactor = zIndexFactor ** zIndexOptions.opacityRate, baseOpacity = getRangeValue(this.opacity?.value ?? defaultOpacity$2), modifierOpacity = this.#applyModifiers(undefined, m => m.opacity), opacity = modifierOpacity ?? baseOpacity, fillOpacity = this.fillOpacity ?? defaultOpacity$2, strokeOpacity = this.strokeOpacity ?? defaultOpacity$2;
5175
- this.#cachedOpacityData.fillOpacity = opacity * fillOpacity * zOpacityFactor;
5679
+ const zIndexOptions = this.options.zIndex, zIndexFactor = zIndexFactorOffset - this.zIndexFactor, zOpacityFactor = zIndexFactor ** zIndexOptions.opacityRate, baseOpacity = getRangeValue(this.opacity?.value ?? defaultOpacity$2), modifierOpacity = this.#applyModifiers(undefined, m => m.opacity), opacity = modifierOpacity ?? baseOpacity;
5680
+ this.#cachedOpacityData.fillOpacity = this.fillOpacity ?? defaultOpacity$2;
5176
5681
  this.#cachedOpacityData.opacity = opacity * zOpacityFactor;
5177
- this.#cachedOpacityData.strokeOpacity = opacity * strokeOpacity * zOpacityFactor;
5682
+ this.#cachedOpacityData.strokeOpacity = this.strokeOpacity ?? defaultOpacity$2;
5178
5683
  return this.#cachedOpacityData;
5179
5684
  }
5180
5685
  getPosition() {
@@ -5421,7 +5926,7 @@
5421
5926
  #initPosition(position) {
5422
5927
  const container = this.#container, zIndexValue = Math.floor(getRangeValue(this.options.zIndex.value)), initialPosition = this.#calcPosition(position, clamp(zIndexValue, minZ, container.zLayers));
5423
5928
  if (!initialPosition) {
5424
- throw new Error("a valid position cannot be found for particle");
5929
+ throw new Error(getErrorMessage(ErrorCodes$3.particlePositionNotFound));
5425
5930
  }
5426
5931
  this.position = initialPosition;
5427
5932
  this.initialPosition = this.position.copy();
@@ -5470,6 +5975,12 @@
5470
5975
  this.#circlePoolIdx = 0;
5471
5976
  this.#rectanglePoolIdx = 0;
5472
5977
  }
5978
+ get cellSize() {
5979
+ return this.#cellSize;
5980
+ }
5981
+ set cellSize(value) {
5982
+ this.#pendingCellSize = value;
5983
+ }
5473
5984
  clear() {
5474
5985
  this.#cells.clear();
5475
5986
  const pendingCellSize = this.#pendingCellSize;
@@ -5493,18 +6004,7 @@
5493
6004
  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);
5494
6005
  for (let cx = minCellX; cx <= maxCellX; cx++) {
5495
6006
  for (let cy = minCellY; cy <= maxCellY; cy++) {
5496
- const key = `${cx}_${cy}`, cellParticles = this.#cells.get(key);
5497
- if (!cellParticles) {
5498
- continue;
5499
- }
5500
- for (const p of cellParticles) {
5501
- if (check && !check(p)) {
5502
- continue;
5503
- }
5504
- if (range.contains(p.getPosition())) {
5505
- out.push(p);
5506
- }
5507
- }
6007
+ this.#queryCell(cx, cy, range, check, out);
5508
6008
  }
5509
6009
  }
5510
6010
  return out;
@@ -5519,14 +6019,23 @@
5519
6019
  this.#releaseShapes();
5520
6020
  return result;
5521
6021
  }
5522
- setCellSize(cellSize) {
5523
- this.#pendingCellSize = cellSize;
5524
- }
5525
6022
  #acquireCircle(x, y, r) {
5526
- return (this.#circlePool[this.#circlePoolIdx++] ??= new Circle(x, y, r)).reset(x, y, r);
6023
+ const idx = this.#circlePoolIdx++;
6024
+ let circle = this.#circlePool[idx];
6025
+ if (!circle) {
6026
+ circle = new Circle(x, y, r);
6027
+ this.#circlePool[idx] = circle;
6028
+ }
6029
+ return circle.reset(x, y, r);
5527
6030
  }
5528
6031
  #acquireRectangle(x, y, w, h) {
5529
- return (this.#rectanglePool[this.#rectanglePoolIdx++] ??= new Rectangle(x, y, w, h)).reset(x, y, w, h);
6032
+ const idx = this.#rectanglePoolIdx++;
6033
+ let rectangle = this.#rectanglePool[idx];
6034
+ if (!rectangle) {
6035
+ rectangle = new Rectangle(x, y, w, h);
6036
+ this.#rectanglePool[idx] = rectangle;
6037
+ }
6038
+ return rectangle.reset(x, y, w, h);
5530
6039
  }
5531
6040
  #cellKeyFromCoords(x, y) {
5532
6041
  const cellX = Math.floor(x / this.#cellSize), cellY = Math.floor(y / this.#cellSize);
@@ -5553,6 +6062,20 @@
5553
6062
  }
5554
6063
  return null;
5555
6064
  }
6065
+ #queryCell(cx, cy, range, check, out) {
6066
+ const cellParticles = this.#cells.get(`${cx}_${cy}`);
6067
+ if (!cellParticles) {
6068
+ return;
6069
+ }
6070
+ for (const p of cellParticles) {
6071
+ if (check && !check(p)) {
6072
+ continue;
6073
+ }
6074
+ if (range.contains(p.getPosition())) {
6075
+ out.push(p);
6076
+ }
6077
+ }
6078
+ }
5556
6079
  #releaseShapes() {
5557
6080
  this.#circlePoolIdx = 0;
5558
6081
  this.#rectanglePoolIdx = 0;
@@ -5561,9 +6084,9 @@
5561
6084
 
5562
6085
  class ParticlesManager {
5563
6086
  checkParticlePositionPlugins;
5564
- grid;
5565
6087
  #array;
5566
6088
  #container;
6089
+ #grid;
5567
6090
  #groupLimits;
5568
6091
  #limit;
5569
6092
  #nextId;
@@ -5587,7 +6110,7 @@
5587
6110
  this.#groupLimits = new Map();
5588
6111
  this.#particleBuckets = new Map();
5589
6112
  this.#zBuckets = this.#createBuckets(this.#container.zLayers);
5590
- this.grid = new SpatialHashGrid(spatialHashGridCellSize);
6113
+ this.#grid = new SpatialHashGrid(spatialHashGridCellSize);
5591
6114
  this.checkParticlePositionPlugins = [];
5592
6115
  this.#particleResetPlugins = [];
5593
6116
  this.#particleUpdatePlugins = [];
@@ -5598,23 +6121,12 @@
5598
6121
  get count() {
5599
6122
  return this.#array.length;
5600
6123
  }
6124
+ get grid() {
6125
+ return this.#grid;
6126
+ }
5601
6127
  addParticle(position, overrideOptions, group, initializer) {
5602
- const limitMode = this.#container.actualOptions.particles.number.limit.mode, limit = group === undefined ? this.#limit : (this.#groupLimits.get(group) ?? this.#limit), currentCount = this.count;
5603
- if (limit > minLimit) {
5604
- switch (limitMode) {
5605
- case exports.LimitMode.delete: {
5606
- const countToRemove = currentCount + countOffset - limit;
5607
- if (countToRemove > minCount) {
5608
- this.removeQuantity(countToRemove);
5609
- }
5610
- break;
5611
- }
5612
- case exports.LimitMode.wait:
5613
- if (currentCount >= limit) {
5614
- return;
5615
- }
5616
- break;
5617
- }
6128
+ if (this.#checkAndApplyLimits(group, this.count)) {
6129
+ return;
5618
6130
  }
5619
6131
  try {
5620
6132
  const particle = this.#pool.pop() ?? new Particle(this.#pluginManager, this.#container);
@@ -5678,7 +6190,7 @@
5678
6190
  return this.#array[index];
5679
6191
  }
5680
6192
  async init() {
5681
- const container = this.#container, options = container.actualOptions;
6193
+ const container = this.#container;
5682
6194
  this.checkParticlePositionPlugins = [];
5683
6195
  this.#updatePlugins = [];
5684
6196
  this.#particleUpdatePlugins = [];
@@ -5687,59 +6199,16 @@
5687
6199
  this.#postParticleUpdatePlugins = [];
5688
6200
  this.#particleBuckets.clear();
5689
6201
  this.#resetBuckets(container.zLayers);
5690
- this.grid = new SpatialHashGrid(spatialHashGridCellSize * container.retina.pixelRatio);
5691
- for (const plugin of container.plugins) {
5692
- if (plugin.redrawInit) {
5693
- await plugin.redrawInit();
5694
- }
5695
- if (plugin.checkParticlePosition) {
5696
- this.checkParticlePositionPlugins.push(plugin);
5697
- }
5698
- if (plugin.update) {
5699
- this.#updatePlugins.push(plugin);
5700
- }
5701
- if (plugin.particleUpdate) {
5702
- this.#particleUpdatePlugins.push(plugin);
5703
- }
5704
- if (plugin.postUpdate) {
5705
- this.#postUpdatePlugins.push(plugin);
5706
- }
5707
- if (plugin.particleReset) {
5708
- this.#particleResetPlugins.push(plugin);
5709
- }
5710
- if (plugin.postParticleUpdate) {
5711
- this.#postParticleUpdatePlugins.push(plugin);
5712
- }
5713
- }
5714
- await this.#container.initDrawersAndUpdaters();
5715
- for (const drawer of this.#container.effectDrawers.values()) {
5716
- await drawer.init?.(container);
5717
- }
5718
- for (const drawer of this.#container.shapeDrawers.values()) {
5719
- await drawer.init?.(container);
5720
- }
5721
- let handled = false;
5722
- for (const plugin of container.plugins) {
5723
- handled = plugin.particlesInitialization?.() ?? handled;
5724
- if (handled) {
5725
- break;
5726
- }
5727
- }
5728
- if (!handled) {
5729
- const particlesOptions = options.particles, groups = particlesOptions.groups;
5730
- for (const group in groups) {
5731
- const groupOptions = groups[group];
5732
- if (!groupOptions) {
5733
- continue;
5734
- }
5735
- for (let i = this.count, j = 0; j < groupOptions.number.value && i < particlesOptions.number.value; i++, j++) {
5736
- this.addParticle(undefined, groupOptions, group);
5737
- }
5738
- }
5739
- for (let i = this.count; i < particlesOptions.number.value; i++) {
5740
- this.addParticle();
6202
+ this.#grid = new SpatialHashGrid(spatialHashGridCellSize * container.retina.pixelRatio);
6203
+ this.#applyLimits(container.actualOptions.particles);
6204
+ const particlesOptions = container.actualOptions.particles, groups = particlesOptions.groups;
6205
+ for (const group in groups) {
6206
+ const groupData = groups[group];
6207
+ if (groupData) {
6208
+ this.#applyLimits(loadParticlesOptions(this.#pluginManager, this.#container, groupData), group, groupData);
5741
6209
  }
5742
6210
  }
6211
+ await this.#initPlugins();
5743
6212
  }
5744
6213
  push(nb, position, overrideOptions, group) {
5745
6214
  for (let i = 0; i < nb; i++) {
@@ -5754,13 +6223,13 @@
5754
6223
  remove(particle, group, override) {
5755
6224
  this.removeAt(this.#array.indexOf(particle), undefined, group, override);
5756
6225
  }
5757
- removeAt(index, quantity = defaultRemoveQuantity, group, override) {
6226
+ removeAt(index, quantity = defaultRemoveQuantity, group, override, matchGroup = true) {
5758
6227
  if (index < minIndex || index > this.count) {
5759
6228
  return;
5760
6229
  }
5761
6230
  let deleted = 0;
5762
6231
  for (let i = index; deleted < quantity && i < this.count; i++) {
5763
- if (this.#removeParticle(i, group, override)) {
6232
+ if (this.#removeParticle(i, group, override, matchGroup)) {
5764
6233
  i--;
5765
6234
  deleted++;
5766
6235
  }
@@ -5791,7 +6260,7 @@
5791
6260
  this.#resizeFactor = factor;
5792
6261
  }
5793
6262
  update(delta) {
5794
- this.grid.clear();
6263
+ this.#grid.clear();
5795
6264
  for (const plugin of this.#updatePlugins) {
5796
6265
  plugin.update?.(delta);
5797
6266
  }
@@ -5802,7 +6271,7 @@
5802
6271
  this.#updateParticlesPhase2(delta, particlesToDelete);
5803
6272
  if (particlesToDelete.size) {
5804
6273
  for (const particle of particlesToDelete) {
5805
- this.remove(particle);
6274
+ this.remove(particle, particle.group);
5806
6275
  }
5807
6276
  }
5808
6277
  this.#resizeFactor = undefined;
@@ -5813,12 +6282,7 @@
5813
6282
  #applyDensity(options, pluginsCount, group, groupOptions) {
5814
6283
  const numberOptions = options.number;
5815
6284
  if (!numberOptions.density.enable) {
5816
- if (group === undefined) {
5817
- this.#limit = numberOptions.limit.value;
5818
- }
5819
- else if (groupOptions?.number.limit.value ?? numberOptions.limit.value) {
5820
- this.#groupLimits.set(group, groupOptions?.number.limit.value ?? numberOptions.limit.value);
5821
- }
6285
+ this.#applyLimits(options, group, groupOptions);
5822
6286
  return;
5823
6287
  }
5824
6288
  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);
@@ -5826,7 +6290,10 @@
5826
6290
  this.#limit = numberOptions.limit.value * densityFactor;
5827
6291
  }
5828
6292
  else {
5829
- this.#groupLimits.set(group, numberOptions.limit.value * densityFactor);
6293
+ this.#groupLimits.set(group, {
6294
+ limit: numberOptions.limit.value * densityFactor,
6295
+ mode: toEnumValue(exports.LimitMode, numberOptions.limit.mode, exports.LimitMode.delete),
6296
+ });
5830
6297
  }
5831
6298
  if (particlesCount < particlesNumber) {
5832
6299
  this.push(Math.abs(particlesNumber - particlesCount), undefined, options, group);
@@ -5835,6 +6302,55 @@
5835
6302
  this.removeQuantity(particlesCount - particlesNumber, group);
5836
6303
  }
5837
6304
  }
6305
+ #applyLimits(options, group, groupOptions) {
6306
+ if (group === undefined) {
6307
+ this.#limit = options.number.limit.value;
6308
+ const groups = this.#container.actualOptions.particles.groups;
6309
+ for (const existingGroup of this.#groupLimits.keys()) {
6310
+ if (!(existingGroup in groups)) {
6311
+ this.#groupLimits.delete(existingGroup);
6312
+ }
6313
+ }
6314
+ }
6315
+ else {
6316
+ const limitValue = groupOptions?.number?.limit?.value ?? options.number.limit.value;
6317
+ if (limitValue > minLimit) {
6318
+ this.#groupLimits.set(group, {
6319
+ limit: limitValue,
6320
+ mode: toEnumValue(exports.LimitMode, groupOptions?.number?.limit?.mode ?? options.number.limit.mode, exports.LimitMode.delete),
6321
+ });
6322
+ }
6323
+ else {
6324
+ this.#groupLimits.delete(group);
6325
+ }
6326
+ }
6327
+ }
6328
+ #checkAndApplyLimits(group, currentCount) {
6329
+ const globalLimit = this.#limit, globalMode = this.#container.actualOptions.particles.number.limit.mode;
6330
+ if (globalLimit > minLimit && globalMode === exports.LimitMode.wait && currentCount >= globalLimit) {
6331
+ return true;
6332
+ }
6333
+ const groupLimitEntry = group === undefined ? undefined : this.#groupLimits.get(group);
6334
+ if (groupLimitEntry && groupLimitEntry.limit > minLimit && groupLimitEntry.mode === exports.LimitMode.wait) {
6335
+ const groupCount = this.filter(t => t.group === group).length;
6336
+ if (groupCount >= groupLimitEntry.limit) {
6337
+ return true;
6338
+ }
6339
+ }
6340
+ if (groupLimitEntry && groupLimitEntry.limit > minLimit && groupLimitEntry.mode === exports.LimitMode.delete) {
6341
+ const groupCountToRemove = this.filter(t => t.group === group).length + countOffset - groupLimitEntry.limit;
6342
+ if (groupCountToRemove > minCount) {
6343
+ this.removeQuantity(groupCountToRemove, group);
6344
+ }
6345
+ }
6346
+ if (globalLimit > minLimit && globalMode === exports.LimitMode.delete) {
6347
+ const globalCountToRemove = this.count + countOffset - globalLimit;
6348
+ if (globalCountToRemove > minCount) {
6349
+ this.#removeAny(globalCountToRemove);
6350
+ }
6351
+ }
6352
+ return false;
6353
+ }
5838
6354
  #createBuckets(zLayers) {
5839
6355
  const bucketCount = Math.max(Math.floor(zLayers), one);
5840
6356
  return Array.from({ length: bucketCount }, () => []);
@@ -5857,6 +6373,70 @@
5857
6373
  }
5858
6374
  return ((canvasSize.width * canvasSize.height) / (densityOptions.height * densityOptions.width * pxRatio ** squareExp));
5859
6375
  }
6376
+ async #initDrawersAndUpdaters() {
6377
+ const container = this.#container;
6378
+ await container.initDrawersAndUpdaters();
6379
+ for (const drawer of container.effectDrawers.values()) {
6380
+ await drawer.init?.(container);
6381
+ }
6382
+ for (const drawer of container.shapeDrawers.values()) {
6383
+ await drawer.init?.(container);
6384
+ }
6385
+ }
6386
+ async #initPlugins() {
6387
+ await this.#initPluginsArrays();
6388
+ await this.#initDrawersAndUpdaters();
6389
+ let handled = false;
6390
+ const container = this.#container;
6391
+ for (const plugin of container.plugins) {
6392
+ handled = plugin.particlesInitialization?.() ?? handled;
6393
+ if (handled) {
6394
+ break;
6395
+ }
6396
+ }
6397
+ if (handled) {
6398
+ return;
6399
+ }
6400
+ const particlesOptions = container.actualOptions.particles, groups = particlesOptions.groups;
6401
+ for (const group in groups) {
6402
+ const groupOptions = groups[group];
6403
+ if (!groupOptions) {
6404
+ continue;
6405
+ }
6406
+ for (let i = this.count, j = 0; j < groupOptions.number.value && i < particlesOptions.number.value; i++, j++) {
6407
+ this.addParticle(undefined, groupOptions, group);
6408
+ }
6409
+ }
6410
+ for (let i = this.count; i < particlesOptions.number.value; i++) {
6411
+ this.addParticle();
6412
+ }
6413
+ }
6414
+ async #initPluginsArrays() {
6415
+ const container = this.#container;
6416
+ for (const plugin of container.plugins) {
6417
+ if (plugin.redrawInit) {
6418
+ await plugin.redrawInit();
6419
+ }
6420
+ if (plugin.checkParticlePosition) {
6421
+ this.checkParticlePositionPlugins.push(plugin);
6422
+ }
6423
+ if (plugin.update) {
6424
+ this.#updatePlugins.push(plugin);
6425
+ }
6426
+ if (plugin.particleUpdate) {
6427
+ this.#particleUpdatePlugins.push(plugin);
6428
+ }
6429
+ if (plugin.postUpdate) {
6430
+ this.#postUpdatePlugins.push(plugin);
6431
+ }
6432
+ if (plugin.particleReset) {
6433
+ this.#particleResetPlugins.push(plugin);
6434
+ }
6435
+ if (plugin.postParticleUpdate) {
6436
+ this.#postParticleUpdatePlugins.push(plugin);
6437
+ }
6438
+ }
6439
+ }
5860
6440
  #insertParticleIntoBucket(particle) {
5861
6441
  const bucketIndex = this.#getBucketIndex(particle.position.z), bucket = this.#zBuckets[bucketIndex];
5862
6442
  if (!bucket) {
@@ -5865,12 +6445,15 @@
5865
6445
  bucket.push(particle);
5866
6446
  this.#particleBuckets.set(particle.id, bucketIndex);
5867
6447
  }
5868
- #removeParticle(index, group, override) {
6448
+ #removeAny(quantity) {
6449
+ this.removeAt(minIndex, quantity, undefined, undefined, false);
6450
+ }
6451
+ #removeParticle(index, group, override, matchGroup = true) {
5869
6452
  const particle = this.#array[index];
5870
6453
  if (!particle) {
5871
6454
  return false;
5872
6455
  }
5873
- if (particle.group !== group) {
6456
+ if (matchGroup && particle.group !== group) {
5874
6457
  return false;
5875
6458
  }
5876
6459
  this.#array.splice(index, deleteCount);
@@ -5957,7 +6540,7 @@
5957
6540
  particlesToDelete.add(particle);
5958
6541
  continue;
5959
6542
  }
5960
- this.grid.insert(particle);
6543
+ this.#grid.insert(particle);
5961
6544
  }
5962
6545
  return particlesToDelete;
5963
6546
  }
@@ -6029,6 +6612,7 @@
6029
6612
  effectDrawers;
6030
6613
  fpsLimit;
6031
6614
  hdr;
6615
+ hdrMode;
6032
6616
  id;
6033
6617
  pageHidden;
6034
6618
  particleCreatedPlugins;
@@ -6036,6 +6620,7 @@
6036
6620
  particlePositionPlugins;
6037
6621
  particleUpdaters;
6038
6622
  particles;
6623
+ peakNits;
6039
6624
  plugins;
6040
6625
  retina;
6041
6626
  shapeDrawers;
@@ -6066,6 +6651,8 @@
6066
6651
  this.id = Symbol(id);
6067
6652
  this.fpsLimit = 120;
6068
6653
  this.hdr = false;
6654
+ this.hdrMode = exports.HdrMode.standard;
6655
+ this.peakNits = 400;
6069
6656
  this.#smooth = false;
6070
6657
  this.#delay = 0;
6071
6658
  this.#duration = 0;
@@ -6129,7 +6716,6 @@
6129
6716
  this.shapeDrawers = new Map();
6130
6717
  this.particleUpdaters = [];
6131
6718
  this.plugins.length = 0;
6132
- this.#pluginManager.clearPlugins(this);
6133
6719
  this.destroyed = true;
6134
6720
  this.#onDestroy(remove);
6135
6721
  this.dispatchEvent(exports.EventType.containerDestroyed);
@@ -6182,31 +6768,15 @@
6182
6768
  await this.initDrawersAndUpdaters();
6183
6769
  this.#options = loadContainerOptions(this.#pluginManager, this, this.#initialSourceOptions, this.sourceOptions);
6184
6770
  this.actualOptions = loadContainerOptions(this.#pluginManager, this, this.#options);
6185
- this.plugins.length = 0;
6186
- this.particleDestroyedPlugins.length = 0;
6187
- this.particleCreatedPlugins.length = 0;
6188
- this.particlePositionPlugins.length = 0;
6189
- for (const [plugin, containerPlugin] of allContainerPlugins) {
6190
- if (plugin.needsPlugin(this.actualOptions)) {
6191
- this.plugins.push(containerPlugin);
6192
- if (containerPlugin.particleCreated) {
6193
- this.particleCreatedPlugins.push(containerPlugin);
6194
- }
6195
- if (containerPlugin.particleDestroyed) {
6196
- this.particleDestroyedPlugins.push(containerPlugin);
6197
- }
6198
- if (containerPlugin.particlePosition) {
6199
- this.particlePositionPlugins.push(containerPlugin);
6200
- }
6201
- }
6202
- }
6771
+ this.#initPlugins(allContainerPlugins);
6203
6772
  this.retina.init();
6204
6773
  this.canvas.init();
6205
6774
  this.updateActualOptions();
6206
6775
  this.canvas.initBackground();
6207
6776
  this.canvas.resize();
6208
- const { delay, duration, fpsLimit, hdr, smooth, zLayers } = this.actualOptions;
6209
- this.hdr = hdr;
6777
+ const { delay, duration, fpsLimit, smooth, zLayers } = this.actualOptions, hdrOptions = this.actualOptions.hdr;
6778
+ this.hdrMode = toEnumValue(exports.HdrMode, hdrOptions.mode, exports.HdrMode.standard);
6779
+ this.peakNits = hdrOptions.peakNits;
6210
6780
  this.zLayers = zLayers;
6211
6781
  this.#duration = getRangeValue(duration) * millisecondsToSeconds;
6212
6782
  this.#delay = getRangeValue(delay) * millisecondsToSeconds;
@@ -6226,9 +6796,9 @@
6226
6796
  }
6227
6797
  async initDrawersAndUpdaters() {
6228
6798
  const pluginManager = this.#pluginManager;
6229
- this.effectDrawers = await pluginManager.getEffectDrawers(this, true);
6230
- this.shapeDrawers = await pluginManager.getShapeDrawers(this, true);
6231
- this.particleUpdaters = await pluginManager.getUpdaters(this, true);
6799
+ this.effectDrawers = await getItemMapFromInitializer(this, pluginManager.initializers.effects);
6800
+ this.shapeDrawers = await getItemMapFromInitializer(this, pluginManager.initializers.shapes);
6801
+ this.particleUpdaters = await getItemsFromInitializer(this, pluginManager.initializers.updaters);
6232
6802
  }
6233
6803
  pause() {
6234
6804
  if (!guardCheck(this)) {
@@ -6339,6 +6909,27 @@
6339
6909
  }
6340
6910
  return refresh;
6341
6911
  }
6912
+ #initPlugins(allContainerPlugins) {
6913
+ this.plugins.length = 0;
6914
+ this.particleDestroyedPlugins.length = 0;
6915
+ this.particleCreatedPlugins.length = 0;
6916
+ this.particlePositionPlugins.length = 0;
6917
+ for (const [plugin, containerPlugin] of allContainerPlugins) {
6918
+ if (!plugin.needsPlugin(this.actualOptions)) {
6919
+ continue;
6920
+ }
6921
+ this.plugins.push(containerPlugin);
6922
+ if (containerPlugin.particleCreated) {
6923
+ this.particleCreatedPlugins.push(containerPlugin);
6924
+ }
6925
+ if (containerPlugin.particleDestroyed) {
6926
+ this.particleDestroyedPlugins.push(containerPlugin);
6927
+ }
6928
+ if (containerPlugin.particlePosition) {
6929
+ this.particlePositionPlugins.push(containerPlugin);
6930
+ }
6931
+ }
6932
+ }
6342
6933
  #nextFrame(timestamp) {
6343
6934
  try {
6344
6935
  if (!this.#smooth &&
@@ -6645,11 +7236,11 @@
6645
7236
  }
6646
7237
  }
6647
7238
  async #init() {
6648
- const availablePathGenerators = await this.#pluginManager.getPathGenerators?.(this.#container, true);
6649
- if (!availablePathGenerators) {
7239
+ const pluginManager = this.#pluginManager;
7240
+ if (!pluginManager.initializers.pathGenerators) {
6650
7241
  return;
6651
7242
  }
6652
- this.availablePathGenerators = availablePathGenerators;
7243
+ this.availablePathGenerators = await getItemMapFromInitializer(this.#container, pluginManager.initializers.pathGenerators);
6653
7244
  this.pathGenerators = new Map();
6654
7245
  for (const pathGenerator of this.pathGenerators.values()) {
6655
7246
  pathGenerator.init();
@@ -6753,28 +7344,12 @@
6753
7344
  }
6754
7345
  const html = interactivityEl, canvas = container.canvas;
6755
7346
  canvas.setPointerEvents(html === canvas.domElement ? "initial" : "none");
6756
- if (add && !(options.interactivity?.events.onHover.enable || options.interactivity?.events.onClick.enable)) {
6757
- return;
6758
- }
6759
7347
  manageListener(interactivityEl, mouseMoveEvent, handlers.mouseMove, add);
6760
7348
  manageListener(interactivityEl, touchStartEvent, handlers.touchStart, add);
6761
7349
  manageListener(interactivityEl, touchMoveEvent, handlers.touchMove, add);
6762
- if (add) {
6763
- if (options.interactivity?.events.onClick.enable) {
6764
- manageListener(interactivityEl, touchEndEvent, handlers.touchEndClick, add);
6765
- manageListener(interactivityEl, mouseUpEvent, handlers.mouseUp, add);
6766
- manageListener(interactivityEl, mouseDownEvent, handlers.mouseDown, add);
6767
- }
6768
- else {
6769
- manageListener(interactivityEl, touchEndEvent, handlers.touchEnd, add);
6770
- }
6771
- }
6772
- else {
6773
- manageListener(interactivityEl, touchEndEvent, handlers.touchEndClick, add);
6774
- manageListener(interactivityEl, mouseUpEvent, handlers.mouseUp, add);
6775
- manageListener(interactivityEl, mouseDownEvent, handlers.mouseDown, add);
6776
- manageListener(interactivityEl, touchEndEvent, handlers.touchEnd, add);
6777
- }
7350
+ manageListener(interactivityEl, touchEndEvent, options.interactivity?.events.onClick.enable ? handlers.touchEndClick : handlers.touchEnd, add);
7351
+ manageListener(interactivityEl, mouseUpEvent, handlers.mouseUp, add);
7352
+ manageListener(interactivityEl, mouseDownEvent, handlers.mouseDown, add);
6778
7353
  manageListener(interactivityEl, mouseLeaveEvent, handlers.mouseLeave, add);
6779
7354
  manageListener(interactivityEl, touchCancelEvent, handlers.touchCancel, add);
6780
7355
  }
@@ -6800,19 +7375,18 @@
6800
7375
  #mouseTouchClick(e) {
6801
7376
  const container = this.#container, interactionManager = this.#interactionManager, options = container.actualOptions, { mouse } = interactionManager.interactivityData;
6802
7377
  mouse.inside = true;
6803
- let handled = false;
6804
7378
  const mousePosition = mouse.position;
6805
- if (!mousePosition || !options.interactivity?.events.onClick.enable) {
6806
- return;
6807
- }
6808
- for (const plugin of this.#clickPositionPlugins) {
6809
- handled = plugin.clickPositionValid?.(mousePosition) ?? false;
6810
- if (handled) {
6811
- break;
7379
+ if (mousePosition && options.interactivity?.events.onClick.enable) {
7380
+ let handled = false;
7381
+ for (const plugin of this.#clickPositionPlugins) {
7382
+ handled = plugin.clickPositionValid?.(mousePosition) ?? false;
7383
+ if (handled) {
7384
+ break;
7385
+ }
7386
+ }
7387
+ if (!handled) {
7388
+ this.#doMouseTouchClick(e);
6812
7389
  }
6813
- }
6814
- if (!handled) {
6815
- this.#doMouseTouchClick(e);
6816
7390
  }
6817
7391
  mouse.clicking = false;
6818
7392
  }
@@ -6908,6 +7482,9 @@
6908
7482
  this.#touches.set(touch.identifier, performance.now());
6909
7483
  }
6910
7484
  this.#mouseTouchMove(e);
7485
+ const { mouse } = this.#interactionManager.interactivityData;
7486
+ mouse.clicking = true;
7487
+ mouse.downPosition = mouse.position;
6911
7488
  }
6912
7489
  }
6913
7490
 
@@ -6920,18 +7497,18 @@
6920
7497
  }
6921
7498
  class InteractionManager {
6922
7499
  interactivityData;
7500
+ interactors;
6923
7501
  #clickHandlers;
6924
7502
  #container;
6925
7503
  #eventListeners;
6926
7504
  #externalInteractors;
6927
- #interactors;
6928
7505
  #intersectionObserver;
6929
7506
  #particleInteractors;
6930
7507
  #pluginManager;
6931
7508
  constructor(pluginManager, container) {
6932
7509
  this.#container = container;
6933
7510
  this.#pluginManager = pluginManager;
6934
- this.#interactors = [];
7511
+ this.interactors = [];
6935
7512
  this.#externalInteractors = [];
6936
7513
  this.#particleInteractors = [];
6937
7514
  this.#clickHandlers = new Map();
@@ -7050,7 +7627,7 @@
7050
7627
  }
7051
7628
  init() {
7052
7629
  this.#eventListeners.init();
7053
- for (const interactor of this.#interactors) {
7630
+ for (const interactor of this.interactors) {
7054
7631
  switch (interactor.type) {
7055
7632
  case InteractorType.external:
7056
7633
  this.#externalInteractors.push(interactor);
@@ -7063,11 +7640,11 @@
7063
7640
  }
7064
7641
  }
7065
7642
  async initInteractors() {
7066
- const interactors = await this.#pluginManager.getInteractors?.(this.#container, true);
7067
- if (!interactors) {
7643
+ const pluginManager = this.#pluginManager;
7644
+ if (!pluginManager.initializers.interactors) {
7068
7645
  return;
7069
7646
  }
7070
- this.#interactors = interactors;
7647
+ this.interactors = await getItemsFromInitializer(this.#container, pluginManager.initializers.interactors);
7071
7648
  this.#externalInteractors = [];
7072
7649
  this.#particleInteractors = [];
7073
7650
  }
@@ -7112,13 +7689,13 @@
7112
7689
  }
7113
7690
  updateMaxDistance() {
7114
7691
  let maxTotalDistance = 0;
7115
- for (const interactor of this.#interactors) {
7692
+ for (const interactor of this.interactors) {
7116
7693
  if (interactor.maxDistance > maxTotalDistance) {
7117
7694
  maxTotalDistance = interactor.maxDistance;
7118
7695
  }
7119
7696
  }
7120
7697
  const container = this.#container;
7121
- container.particles.grid.setCellSize(maxTotalDistance * container.retina.pixelRatio);
7698
+ container.particles.grid.cellSize = maxTotalDistance * container.retina.pixelRatio;
7122
7699
  }
7123
7700
  #intersectionManager(entries) {
7124
7701
  const container = this.#container;
@@ -7140,59 +7717,59 @@
7140
7717
  }
7141
7718
 
7142
7719
  class InteractivityPluginInstance {
7143
- interactionManager;
7144
7720
  #container;
7145
- #pluginManager;
7146
7721
  constructor(pluginManager, container) {
7147
- this.#container = container;
7148
- this.#pluginManager = pluginManager;
7149
- this.interactionManager = new InteractionManager(pluginManager, container);
7150
- this.#container.addClickHandler = (callback) => {
7151
- this.interactionManager.addClickHandler(callback);
7722
+ container.addClickHandler = (callback) => {
7723
+ container.interactionManager?.addClickHandler(callback);
7152
7724
  };
7725
+ container.interactionManager = new InteractionManager(pluginManager, container);
7726
+ this.#container = container;
7153
7727
  }
7154
7728
  addClickHandler(callback) {
7155
- this.interactionManager.addClickHandler(callback);
7729
+ this.#container.interactionManager?.addClickHandler(callback);
7156
7730
  }
7157
7731
  clearClickHandlers() {
7158
- this.interactionManager.clearClickHandlers();
7732
+ this.#container.interactionManager?.clearClickHandlers();
7159
7733
  }
7160
7734
  destroy() {
7161
7735
  this.clearClickHandlers();
7162
- this.#pluginManager.interactors?.delete(this.#container);
7163
7736
  }
7164
7737
  particleCreated(particle) {
7165
- const interactivityParticle = particle, interactivity = new Interactivity(this.#pluginManager, this.#container);
7166
- interactivity.load(this.#container.actualOptions.interactivity);
7738
+ const interactivityParticle = particle, container = this.#container, interactivity = new Interactivity(container);
7739
+ interactivity.load(container.actualOptions.interactivity);
7167
7740
  interactivity.load(interactivityParticle.options.interactivity);
7168
7741
  interactivityParticle.interactivity = interactivity;
7169
7742
  }
7170
7743
  particleReset(particle) {
7171
- this.interactionManager.reset(particle);
7744
+ this.#container.interactionManager?.reset(particle);
7172
7745
  }
7173
7746
  postParticleUpdate(particle, delta) {
7174
- this.interactionManager.particlesInteract(particle, delta);
7747
+ this.#container.interactionManager?.particlesInteract(particle, delta);
7175
7748
  }
7176
7749
  postUpdate(delta) {
7177
- this.interactionManager.externalInteract(delta);
7178
- this.interactionManager.updateMaxDistance();
7750
+ const container = this.#container;
7751
+ container.interactionManager?.externalInteract(delta);
7752
+ container.interactionManager?.updateMaxDistance();
7179
7753
  }
7180
7754
  async preInit() {
7181
- await this.interactionManager.initInteractors();
7182
- this.interactionManager.init();
7755
+ const container = this.#container;
7756
+ await container.interactionManager?.initInteractors();
7757
+ container.interactionManager?.init();
7183
7758
  }
7184
7759
  async redrawInit() {
7185
- await this.interactionManager.initInteractors();
7186
- this.interactionManager.init();
7760
+ const container = this.#container;
7761
+ await container.interactionManager?.initInteractors();
7762
+ container.interactionManager?.init();
7187
7763
  }
7188
7764
  start() {
7189
- this.interactionManager.addListeners();
7190
- this.interactionManager.startObserving();
7765
+ const container = this.#container;
7766
+ container.interactionManager?.addListeners();
7767
+ container.interactionManager?.startObserving();
7191
7768
  return Promise.resolve();
7192
7769
  }
7193
7770
  stop() {
7194
- this.interactionManager.removeListeners();
7195
- this.interactionManager.stopObserving();
7771
+ this.#container.interactionManager?.removeListeners();
7772
+ this.#container.interactionManager?.stopObserving();
7196
7773
  }
7197
7774
  }
7198
7775
 
@@ -7221,7 +7798,7 @@
7221
7798
  }
7222
7799
  const retries = overlapOptions.retries;
7223
7800
  if (retries >= minRetries && tryCount > retries) {
7224
- throw new Error(`Particle is overlapping and can't be placed`);
7801
+ throw new Error(getErrorMessage(ErrorCodes.overlapNotPlaced));
7225
7802
  }
7226
7803
  return !!this.#container.particles.find(p => getDistance(pos, p.position) < particle.getRadius() + p.getRadius());
7227
7804
  }
@@ -7393,10 +7970,10 @@
7393
7970
  }
7394
7971
  }
7395
7972
  #getCachedStyle(rgb) {
7396
- const key = `${rgb.r},${rgb.g},${rgb.b}`;
7973
+ const key = `${rgb.r},${rgb.g},${rgb.b}-${this.#container.hdr}-${this.#container.peakNits}-${this.#container.hdrMode}`;
7397
7974
  let style = this.#colorCache.get(key);
7398
7975
  if (!style) {
7399
- style = getStyleFromRgb(rgb, this.#container.hdr);
7976
+ style = getStyleFromRgb(rgb, this.#container.hdr, undefined, this.#container.peakNits, this.#container.hdrMode);
7400
7977
  this.#colorCache.set(key, style);
7401
7978
  }
7402
7979
  return style;
@@ -7421,8 +7998,10 @@
7421
7998
  exports.BaseRange = BaseRange;
7422
7999
  exports.Circle = Circle;
7423
8000
  exports.ColorAnimation = ColorAnimation;
8001
+ exports.ErrorCodes = ErrorCodes$3;
7424
8002
  exports.Fill = Fill;
7425
8003
  exports.FullScreen = FullScreen;
8004
+ exports.HDROptions = HDROptions;
7426
8005
  exports.HslAnimation = HslAnimation;
7427
8006
  exports.Move = Move;
7428
8007
  exports.MoveAngle = MoveAngle;
@@ -7451,6 +8030,7 @@
7451
8030
  exports.Vector = Vector;
7452
8031
  exports.Vector3d = Vector3d;
7453
8032
  exports.ZIndex = ZIndex;
8033
+ exports.addErrorMessages = addErrorMessages;
7454
8034
  exports.alterHsl = alterHsl;
7455
8035
  exports.animate = animate;
7456
8036
  exports.areBoundsInside = areBoundsInside;
@@ -7473,7 +8053,7 @@
7473
8053
  exports.countOffset = countOffset;
7474
8054
  exports.decayOffset = decayOffset;
7475
8055
  exports.deepExtend = deepExtend;
7476
- exports.defaultAlpha = defaultAlpha$1;
8056
+ exports.defaultAlpha = defaultAlpha;
7477
8057
  exports.defaultAngle = defaultAngle;
7478
8058
  exports.defaultCompositeValue = defaultCompositeValue;
7479
8059
  exports.defaultDensityFactor = defaultDensityFactor;
@@ -7497,12 +8077,17 @@
7497
8077
  exports.doublePI = doublePI;
7498
8078
  exports.empty = empty;
7499
8079
  exports.executeOnSingleOrMultiple = executeOnSingleOrMultiple;
8080
+ exports.fullPercent = fullPercent;
7500
8081
  exports.generatedAttribute = generatedAttribute;
7501
8082
  exports.generatedFalse = generatedFalse;
7502
8083
  exports.generatedTrue = generatedTrue;
8084
+ exports.getCanvasFromContainer = getCanvasFromContainer;
8085
+ exports.getDataFromUrl = getDataFromUrl;
7503
8086
  exports.getDistance = getDistance;
7504
8087
  exports.getDistanceSq = getDistanceSq;
7505
8088
  exports.getDistances = getDistances;
8089
+ exports.getDomContainer = getDomContainer;
8090
+ exports.getErrorMessage = getErrorMessage;
7506
8091
  exports.getFullScreenStyle = getFullScreenStyle;
7507
8092
  exports.getHslAnimationFromHsl = getHslAnimationFromHsl;
7508
8093
  exports.getHslFromAnimation = getHslFromAnimation;
@@ -7534,6 +8119,7 @@
7534
8119
  exports.inverseFactorNumerator = inverseFactorNumerator;
7535
8120
  exports.isArray = isArray;
7536
8121
  exports.isBoolean = isBoolean;
8122
+ exports.isEnumValue = isEnumValue;
7537
8123
  exports.isFunction = isFunction;
7538
8124
  exports.isInArray = isInArray;
7539
8125
  exports.isNull = isNull;
@@ -7566,7 +8152,7 @@
7566
8152
  exports.minFpsLimit = minFpsLimit;
7567
8153
  exports.minIndex = minIndex;
7568
8154
  exports.minLimit = minLimit;
7569
- exports.minRadius = minRadius$1;
8155
+ exports.minRadius = minRadius;
7570
8156
  exports.minStrokeWidth = minStrokeWidth;
7571
8157
  exports.minVelocity = minVelocity;
7572
8158
  exports.minZ = minZ;
@@ -7605,6 +8191,7 @@
7605
8191
  exports.stringToAlpha = stringToAlpha;
7606
8192
  exports.stringToRgb = stringToRgb;
7607
8193
  exports.threeQuarter = threeQuarter;
8194
+ exports.toEnumValue = toEnumValue;
7608
8195
  exports.triple = triple;
7609
8196
  exports.tryCountIncrement = tryCountIncrement;
7610
8197
  exports.tsParticles = tsParticles;
@@ -7613,10 +8200,11 @@
7613
8200
  exports.visibilityChangeEvent = visibilityChangeEvent;
7614
8201
  exports.zIndexFactorOffset = zIndexFactorOffset;
7615
8202
 
7616
- }));
8203
+ })(g.__tsParticlesInternals.bundles.particles = g.__tsParticlesInternals.bundles.particles || {});
8204
+ })(typeof globalThis !== "undefined" ? globalThis : typeof window !== "undefined" ? window : self);
8205
+
7617
8206
  Object.assign(globalThis.window || globalThis, { loadExtendProperty: (globalThis.__tsParticlesInternals.bundles.particles || {}).loadExtendProperty, loadLazyProperty: (globalThis.__tsParticlesInternals.bundles.particles || {}).loadLazyProperty, loadMinIndex: (globalThis.__tsParticlesInternals.bundles.particles || {}).loadMinIndex, loadNestedProperty: (globalThis.__tsParticlesInternals.bundles.particles || {}).loadNestedProperty, loadOptionProperty: (globalThis.__tsParticlesInternals.bundles.particles || {}).loadOptionProperty, loadOptions: (globalThis.__tsParticlesInternals.bundles.particles || {}).loadOptions, loadParticlesOptions: (globalThis.__tsParticlesInternals.bundles.particles || {}).loadParticlesOptions, loadProperty: (globalThis.__tsParticlesInternals.bundles.particles || {}).loadProperty, loadRandomFactor: (globalThis.__tsParticlesInternals.bundles.particles || {}).loadRandomFactor, loadRangeProperty: (globalThis.__tsParticlesInternals.bundles.particles || {}).loadRangeProperty, tsParticles: (globalThis.__tsParticlesInternals.bundles.particles || {}).tsParticles });
7618
8207
  globalThis.__tsParticlesInternals = globalThis.__tsParticlesInternals || {};
7619
8208
  if (!globalThis.__tsParticlesInternals.engine || !globalThis.__tsParticlesInternals.engine.tsParticles) {
7620
8209
  globalThis.__tsParticlesInternals.engine = globalThis.__tsParticlesInternals.bundles.particles || {};
7621
8210
  }
7622
- delete (globalThis.window || globalThis).tsparticlesInternalExports;