@tsparticles/preset-matrix 4.3.2 → 4.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,21 +1,35 @@
1
- (function(g){g.__tsParticlesInternals=g.__tsParticlesInternals||{};g.__tsParticlesInternals.bundles=g.__tsParticlesInternals.bundles||{};g.__tsParticlesInternals.effects=g.__tsParticlesInternals.effects||{};g.__tsParticlesInternals.engine=g.__tsParticlesInternals.engine||{};g.__tsParticlesInternals.interactions=g.__tsParticlesInternals.interactions||{};g.__tsParticlesInternals.palettes=g.__tsParticlesInternals.palettes||{};g.__tsParticlesInternals.paths=g.__tsParticlesInternals.paths||{};g.__tsParticlesInternals.plugins=g.__tsParticlesInternals.plugins||{};g.__tsParticlesInternals.plugins=g.__tsParticlesInternals.plugins||{};g.__tsParticlesInternals.plugins.emittersShapes=g.__tsParticlesInternals.plugins.emittersShapes||{};g.__tsParticlesInternals.presets=g.__tsParticlesInternals.presets||{};g.__tsParticlesInternals.shapes=g.__tsParticlesInternals.shapes||{};g.__tsParticlesInternals.updaters=g.__tsParticlesInternals.updaters||{};g.__tsParticlesInternals.utils=g.__tsParticlesInternals.utils||{};g.__tsParticlesInternals.canvas=g.__tsParticlesInternals.canvas||{};g.__tsParticlesInternals.canvas=g.__tsParticlesInternals.canvas||{};g.__tsParticlesInternals.canvas.utils=g.__tsParticlesInternals.canvas.utils||{};g.__tsParticlesInternals.path=g.__tsParticlesInternals.path||{};g.__tsParticlesInternals.path=g.__tsParticlesInternals.path||{};g.__tsParticlesInternals.path.utils=g.__tsParticlesInternals.path.utils||{};var __tsProxyFactory=typeof Proxy!=="undefined"?function(obj){return new Proxy(obj,{get:function(target,key){if(!(key in target)){target[key]={};}return target[key];}});}:function(obj){return obj;};g.__tsParticlesInternals.bundles=__tsProxyFactory(g.__tsParticlesInternals.bundles);g.__tsParticlesInternals.effects=__tsProxyFactory(g.__tsParticlesInternals.effects);g.__tsParticlesInternals.interactions=__tsProxyFactory(g.__tsParticlesInternals.interactions);g.__tsParticlesInternals.palettes=__tsProxyFactory(g.__tsParticlesInternals.palettes);g.__tsParticlesInternals.paths=__tsProxyFactory(g.__tsParticlesInternals.paths);g.__tsParticlesInternals.plugins=__tsProxyFactory(g.__tsParticlesInternals.plugins);g.__tsParticlesInternals.plugins.emittersShapes=__tsProxyFactory(g.__tsParticlesInternals.plugins.emittersShapes);g.__tsParticlesInternals.presets=__tsProxyFactory(g.__tsParticlesInternals.presets);g.__tsParticlesInternals.shapes=__tsProxyFactory(g.__tsParticlesInternals.shapes);g.__tsParticlesInternals.updaters=__tsProxyFactory(g.__tsParticlesInternals.updaters);g.__tsParticlesInternals.utils=__tsProxyFactory(g.__tsParticlesInternals.utils);g.__tsParticlesInternals.canvas=__tsProxyFactory(g.__tsParticlesInternals.canvas);g.__tsParticlesInternals.path=__tsProxyFactory(g.__tsParticlesInternals.path);g.tsparticlesInternalExports=g.tsparticlesInternalExports||{};})(typeof globalThis!=="undefined"?globalThis:typeof window!=="undefined"?window:this);
2
- /* Preset v4.3.2 */
3
- (function (global, factory) {
4
- typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
5
- typeof define === 'function' && define.amd ? define(['exports'], factory) :
6
- (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory((global.__tsParticlesInternals = global.__tsParticlesInternals || {}, global.__tsParticlesInternals.presets = global.__tsParticlesInternals.presets || {}, global.__tsParticlesInternals.presets.matrix = global.__tsParticlesInternals.presets.matrix || {})));
7
- })(this, (function (exports) { 'use strict';
8
-
9
- const generatedAttribute = "generated", defaultCompositeValue = "source-over", resizeEvent = "resize", visibilityChangeEvent = "visibilitychange", percentDenominator = 100, half = 0.5, millisecondsToSeconds = 1000, originPoint = {
10
- x: 0,
11
- y: 0,
12
- z: 0,
13
- }, defaultTransform = {
14
- a: 1,
15
- b: 0,
16
- c: 0,
17
- d: 1,
18
- }, randomColorValue = "random", double = 2, doublePI = Math.PI * double, defaultFps = 60, generatedTrue = "true", generatedFalse = "false", canvasTag = "canvas", defaultRetryCount = 0, squareExp = 2, spatialHashGridCellSize = 100, defaultRemoveQuantity = 1, defaultRatio = 1, defaultReduceFactor = 1, inverseFactorNumerator = 1, rgbMax = 255, hMax = 360, sMax = 100, lMax = 100, hMin = 0, sMin = 0, hPhase = 60, empty = 0, quarter = 0.25, threeQuarter = half + quarter, minVelocity = 0, minDistance = 0, defaultTransformValue = 1, minimumSize = 0, zIndexFactorOffset = 1, defaultOpacity$1 = 1, removeDeleteCount = 1, removeMinIndex = 0, defaultFpsLimit = 120, minFpsLimit = 0, canvasFirstIndex = 0, loadRandomFactor = 10000, loadMinIndex = 0, one = 1, none = 0, decayOffset = 1, tryCountIncrement = 1, minZ = 0, minLimit = 0, countOffset = 1, minCount = 0, minIndex = 0, defaultDensityFactor = 1, deleteCount = 1, defaultAngle = 0, identity = 1, minStrokeWidth = 0, lFactor = 1, lMin = 0, maxNits = 400, triple = 3, sextuple = 6, sNormalizedOffset = 1, phaseNumerator = 1, defaultRgbMin = 0, defaultVelocity = 0, defaultLoops = 0, defaultTime = 0, defaultZoom = 1;
1
+ (function(g){g.__tsParticlesInternals=g.__tsParticlesInternals||{};g.__tsParticlesInternals.bundles=g.__tsParticlesInternals.bundles||{};g.__tsParticlesInternals.effects=g.__tsParticlesInternals.effects||{};g.__tsParticlesInternals.engine=g.__tsParticlesInternals.engine||{};g.__tsParticlesInternals.interactions=g.__tsParticlesInternals.interactions||{};g.__tsParticlesInternals.palettes=g.__tsParticlesInternals.palettes||{};g.__tsParticlesInternals.paths=g.__tsParticlesInternals.paths||{};g.__tsParticlesInternals.plugins=g.__tsParticlesInternals.plugins||{};g.__tsParticlesInternals.plugins=g.__tsParticlesInternals.plugins||{};g.__tsParticlesInternals.plugins.emittersShapes=g.__tsParticlesInternals.plugins.emittersShapes||{};g.__tsParticlesInternals.presets=g.__tsParticlesInternals.presets||{};g.__tsParticlesInternals.shapes=g.__tsParticlesInternals.shapes||{};g.__tsParticlesInternals.updaters=g.__tsParticlesInternals.updaters||{};g.__tsParticlesInternals.utils=g.__tsParticlesInternals.utils||{};g.__tsParticlesInternals.canvas=g.__tsParticlesInternals.canvas||{};g.__tsParticlesInternals.canvas=g.__tsParticlesInternals.canvas||{};g.__tsParticlesInternals.canvas.utils=g.__tsParticlesInternals.canvas.utils||{};g.__tsParticlesInternals.path=g.__tsParticlesInternals.path||{};g.__tsParticlesInternals.path=g.__tsParticlesInternals.path||{};g.__tsParticlesInternals.path.utils=g.__tsParticlesInternals.path.utils||{};var __tsProxyFactory=typeof Proxy!=="undefined"?function(obj){return new Proxy(obj,{get:function(target,key){if(!(key in target)){target[key]={};}return target[key];}});}:function(obj){return obj;};g.__tsParticlesInternals.bundles=__tsProxyFactory(g.__tsParticlesInternals.bundles);g.__tsParticlesInternals.effects=__tsProxyFactory(g.__tsParticlesInternals.effects);g.__tsParticlesInternals.interactions=__tsProxyFactory(g.__tsParticlesInternals.interactions);g.__tsParticlesInternals.palettes=__tsProxyFactory(g.__tsParticlesInternals.palettes);g.__tsParticlesInternals.paths=__tsProxyFactory(g.__tsParticlesInternals.paths);g.__tsParticlesInternals.plugins=__tsProxyFactory(g.__tsParticlesInternals.plugins);g.__tsParticlesInternals.plugins.emittersShapes=__tsProxyFactory(g.__tsParticlesInternals.plugins.emittersShapes);g.__tsParticlesInternals.presets=__tsProxyFactory(g.__tsParticlesInternals.presets);g.__tsParticlesInternals.shapes=__tsProxyFactory(g.__tsParticlesInternals.shapes);g.__tsParticlesInternals.updaters=__tsProxyFactory(g.__tsParticlesInternals.updaters);g.__tsParticlesInternals.utils=__tsProxyFactory(g.__tsParticlesInternals.utils);g.__tsParticlesInternals.canvas=__tsProxyFactory(g.__tsParticlesInternals.canvas);g.__tsParticlesInternals.path=__tsProxyFactory(g.__tsParticlesInternals.path);})(typeof globalThis!=="undefined"?globalThis:typeof window!=="undefined"?window:this);
2
+ (function (g) {
3
+ /* Preset v4.5.0 */
4
+ g.__tsParticlesInternals = g.__tsParticlesInternals || {};
5
+ g.__tsParticlesInternals.presets = g.__tsParticlesInternals.presets || {};
6
+ (function (exports) {
7
+ 'use strict';
8
+
9
+ const errorPrefix = "tsParticles - Error", codedErrorPattern = /^\[tsParticles Error (TSP-\d+)\]\s*/, fullMatchIndex = 0, codeIndex = 1;
10
+ const wrap = (fn) => (...args) => {
11
+ fn(...args);
12
+ }, _logger = {
13
+ debug: wrap(console.debug),
14
+ error: (message, ...optionalParams) => {
15
+ if (typeof message === "string") {
16
+ const match = codedErrorPattern.exec(message);
17
+ if (match?.[codeIndex]) {
18
+ console.error(`tsParticles - ${match[codeIndex]} - ${message.slice(match[fullMatchIndex].length)}`, ...optionalParams);
19
+ return;
20
+ }
21
+ }
22
+ console.error(`${errorPrefix} - ${message}`, ...optionalParams);
23
+ },
24
+ info: wrap(console.info),
25
+ log: wrap(console.log),
26
+ trace: wrap(console.trace),
27
+ verbose: wrap(console.log),
28
+ warning: wrap(console.warn),
29
+ };
30
+ function getLogger() {
31
+ return _logger;
32
+ }
19
33
 
20
34
  var MoveDirection;
21
35
  (function (MoveDirection) {
@@ -32,6 +46,17 @@
32
46
  MoveDirection["inside"] = "inside";
33
47
  })(MoveDirection || (MoveDirection = {}));
34
48
 
49
+ const generatedAttribute = "generated", fullPercent = "100%", defaultCompositeValue = "source-over", resizeEvent = "resize", visibilityChangeEvent = "visibilitychange", percentDenominator = 100, half = 0.5, millisecondsToSeconds = 1000, originPoint = {
50
+ x: 0,
51
+ y: 0,
52
+ z: 0,
53
+ }, defaultTransform = {
54
+ a: 1,
55
+ b: 0,
56
+ c: 0,
57
+ d: 1,
58
+ }, randomColorValue = "random", double = 2, doublePI = Math.PI * double, defaultFps = 60, defaultAlpha = 1, generatedTrue = "true", generatedFalse = "false", canvasTag = "canvas", defaultRetryCount = 0, squareExp = 2, spatialHashGridCellSize = 100, defaultRemoveQuantity = 1, defaultRatio = 1, defaultReduceFactor = 1, inverseFactorNumerator = 1, rgbMax = 255, hMax = 360, sMax = 100, lMax = 100, hMin = 0, sMin = 0, hPhase = 60, empty = 0, quarter = 0.25, threeQuarter = half + quarter, minVelocity = 0, minDistance = 0, minRadius = 0, defaultTransformValue = 1, minimumSize = 0, zIndexFactorOffset = 1, defaultOpacity$1 = 1, removeDeleteCount = 1, removeMinIndex = 0, defaultFpsLimit = 120, minFpsLimit = 0, canvasFirstIndex = 0, loadRandomFactor = 10000, loadMinIndex = 0, one = 1, none = 0, decayOffset = 1, tryCountIncrement = 1, minZ = 0, minLimit = 0, countOffset = 1, minCount = 0, minIndex = 0, defaultDensityFactor = 1, deleteCount = 1, defaultAngle = 0, identity = 1, minStrokeWidth = 0, lFactor = 1, lMin = 0, maxNits = 400, triple = 3, sextuple = 6, sNormalizedOffset = 1, phaseNumerator = 1, defaultRgbMin = 0, defaultVelocity = 0, defaultLoops = 0, defaultTime = 0, defaultZoom = 1;
59
+
35
60
  function getZ(source) {
36
61
  return "z" in source ? source.z : originPoint.z;
37
62
  }
@@ -147,6 +172,12 @@
147
172
  function isNumber(arg) {
148
173
  return typeof arg === "number";
149
174
  }
175
+ function isEnumValue(enumObject, arg) {
176
+ return Object.values(enumObject).some(enumValue => enumValue === arg);
177
+ }
178
+ function toEnumValue(enumObject, arg, defaultValue) {
179
+ return isEnumValue(enumObject, arg) ? arg : defaultValue;
180
+ }
150
181
  function isObject(arg) {
151
182
  return typeof arg === "object" && arg !== null;
152
183
  }
@@ -270,11 +301,61 @@
270
301
  };
271
302
  }
272
303
  function parseAlpha(input) {
273
- const defaultAlpha = 1;
274
304
  if (!input) {
275
305
  return defaultAlpha;
276
306
  }
277
- return input.endsWith("%") ? parseFloat(input) / percentDenominator : parseFloat(input);
307
+ return input.endsWith("%") ? Number.parseFloat(input) / percentDenominator : Number.parseFloat(input);
308
+ }
309
+
310
+ const ErrorCodes$1 = {
311
+ engineVersionMismatch: "TSP-1001",
312
+ particlePositionNotFound: "TSP-1002",
313
+ pluginRegisterAfterLoad: "TSP-1003",
314
+ offscreenCanvasUnsupported: "TSP-1101",
315
+ offscreenCanvasTransferFailed: "TSP-1102",
316
+ hdrEnableInvalid: "TSP-1201",
317
+ hdrModeInvalid: "TSP-1202",
318
+ hdrPeakNitsInvalid: "TSP-1203",
319
+ };
320
+
321
+ const messages = {
322
+ [ErrorCodes$1.engineVersionMismatch]: "The tsParticles version is different from the loaded plugins version. Engine version: {0}. Plugin version: {1}",
323
+ [ErrorCodes$1.particlePositionNotFound]: "a valid position cannot be found for particle",
324
+ [ErrorCodes$1.pluginRegisterAfterLoad]: "Register plugins can only be done before calling tsParticles.load()",
325
+ [ErrorCodes$1.offscreenCanvasUnsupported]: "OffscreenCanvas is required but not supported by this browser",
326
+ [ErrorCodes$1.offscreenCanvasTransferFailed]: "OffscreenCanvas transfer failed",
327
+ [ErrorCodes$1.hdrEnableInvalid]: 'Invalid HDR "enable" value: expected a boolean, got "{0}"',
328
+ [ErrorCodes$1.hdrModeInvalid]: 'Invalid HDR "mode" value: expected one of {0}, got "{1}"',
329
+ [ErrorCodes$1.hdrPeakNitsInvalid]: 'Invalid HDR "peakNits" value: expected a positive number, got "{0}"',
330
+ };
331
+
332
+ let registeredMessages;
333
+ const ensureRegisteredMessages = () => {
334
+ registeredMessages ??= new Map(Object.entries(messages));
335
+ return registeredMessages;
336
+ }, toStringValue$1 = (value) => String(value), format = (template, args) => {
337
+ return template.replace(/\{(\d+)\}/g, (match, index) => {
338
+ const arg = args[Number(index)];
339
+ return arg === undefined ? match : toStringValue$1(arg);
340
+ });
341
+ };
342
+ function addErrorMessages(extraMessages) {
343
+ if (typeof process !== "undefined" && process.env.NODE_ENV === "production") {
344
+ return;
345
+ }
346
+ const catalog = ensureRegisteredMessages();
347
+ for (const [code, message] of Object.entries(extraMessages)) {
348
+ if (message !== undefined) {
349
+ catalog.set(code, message);
350
+ }
351
+ }
352
+ }
353
+ function getErrorMessage(code, ...args) {
354
+ if (typeof process !== "undefined" && process.env.NODE_ENV === "production") {
355
+ return `[tsParticles Error ${code}] https://particles.js.org/errors/#${code}`;
356
+ }
357
+ const template = ensureRegisteredMessages().get(code) ?? `Unknown error code ${code}`;
358
+ return format(template, args);
278
359
  }
279
360
 
280
361
  var OutModeDirection;
@@ -291,7 +372,6 @@
291
372
  PixelMode["percent"] = "percent";
292
373
  })(PixelMode || (PixelMode = {}));
293
374
 
294
- const minRadius = 0;
295
375
  function isForbiddenKey(key) {
296
376
  return key === "__proto__" || key === "constructor" || key === "prototype";
297
377
  }
@@ -487,22 +567,84 @@
487
567
  element.removeEventListener(event, handler, removeOptions);
488
568
  }
489
569
  }
490
- async function getItemsFromInitializer(container, map, initializers, force = false) {
491
- let res = map.get(container);
492
- if (!res || force) {
493
- res = await Promise.all([...initializers.values()].map(t => t(container)));
494
- map.set(container, res);
570
+ async function getItemsFromInitializer(container, initializers) {
571
+ return await Promise.all([...initializers.values()].map(t => t(container)));
572
+ }
573
+ async function getItemMapFromInitializer(container, initializers) {
574
+ const entries = await Promise.all([...initializers.entries()].map(([key, initializer]) => initializer(container).then(item => [key, item])));
575
+ return new Map(entries);
576
+ }
577
+ async function getDataFromUrl(data) {
578
+ const url = itemFromSingleOrMultiple(data.url, data.index);
579
+ if (!url) {
580
+ return data.fallback;
495
581
  }
496
- return res;
582
+ try {
583
+ const response = await fetch(url);
584
+ if (response.ok) {
585
+ const current = (await response.json());
586
+ if (isSourceOptionsValue(current)) {
587
+ return current;
588
+ }
589
+ getLogger().error("invalid configuration data while retrieving config file");
590
+ }
591
+ else {
592
+ getLogger().error(`${response.status.toString()} while retrieving config file`);
593
+ }
594
+ }
595
+ catch (error) {
596
+ getLogger().error(`error while retrieving config file: ${error}`);
597
+ }
598
+ return data.fallback;
497
599
  }
498
- async function getItemMapFromInitializer(container, map, initializers, force = false) {
499
- let res = map.get(container);
500
- if (!res || force) {
501
- const entries = await Promise.all([...initializers.entries()].map(([key, initializer]) => initializer(container).then(item => [key, item])));
502
- res = new Map(entries);
503
- map.set(container, res);
600
+ function isSourceOptionsValue(value) {
601
+ if (isArray(value)) {
602
+ return value.every((entry) => isObject(entry) && !isArray(entry));
504
603
  }
505
- return res;
604
+ return isObject(value) && !isArray(value);
605
+ }
606
+ function getCanvasFromContainer(domContainer) {
607
+ let canvasEl;
608
+ const documentSafe = safeDocument(), isCanvas = domContainer instanceof HTMLCanvasElement || domContainer.tagName.toLowerCase() === canvasTag;
609
+ if (isCanvas) {
610
+ canvasEl = domContainer;
611
+ canvasEl.dataset[generatedAttribute] ??= generatedFalse;
612
+ if (canvasEl.dataset[generatedAttribute] === generatedTrue) {
613
+ canvasEl.style.width ||= fullPercent;
614
+ canvasEl.style.height ||= fullPercent;
615
+ canvasEl.style.pointerEvents = "none";
616
+ canvasEl.style.setProperty("pointer-events", "none");
617
+ }
618
+ }
619
+ else {
620
+ const existingCanvases = domContainer.getElementsByTagName(canvasTag), foundCanvas = existingCanvases.item(canvasFirstIndex);
621
+ if (foundCanvas) {
622
+ canvasEl = foundCanvas;
623
+ canvasEl.dataset[generatedAttribute] = generatedFalse;
624
+ }
625
+ else {
626
+ canvasEl = documentSafe.createElement(canvasTag);
627
+ canvasEl.dataset[generatedAttribute] = generatedTrue;
628
+ domContainer.appendChild(canvasEl);
629
+ }
630
+ canvasEl.style.width ||= fullPercent;
631
+ canvasEl.style.height ||= fullPercent;
632
+ canvasEl.style.pointerEvents = "none";
633
+ canvasEl.style.setProperty("pointer-events", "none");
634
+ }
635
+ return canvasEl;
636
+ }
637
+ function getDomContainer(id, source) {
638
+ const documentSafe = safeDocument();
639
+ let domContainer = source ?? documentSafe.getElementById(id);
640
+ if (domContainer) {
641
+ return domContainer;
642
+ }
643
+ domContainer = documentSafe.createElement("canvas");
644
+ domContainer.id = id;
645
+ domContainer.dataset[generatedAttribute] = generatedTrue;
646
+ documentSafe.body.append(domContainer);
647
+ return domContainer;
506
648
  }
507
649
 
508
650
  class EventDispatcher {
@@ -573,7 +715,6 @@
573
715
  class PluginManager {
574
716
  colorManagers = new Map();
575
717
  easingFunctions = new Map();
576
- effectDrawers = new Map();
577
718
  initializers = {
578
719
  effects: new Map(),
579
720
  shapes: new Map(),
@@ -582,8 +723,6 @@
582
723
  palettes = new Map();
583
724
  plugins = [];
584
725
  presets = new Map();
585
- shapeDrawers = new Map();
586
- updaters = new Map();
587
726
  #allLoadersSet = new Set();
588
727
  #configs = new Map();
589
728
  #engine;
@@ -601,57 +740,79 @@
601
740
  }
602
741
  return res;
603
742
  }
743
+ get initialized() {
744
+ return this.#initialized;
745
+ }
604
746
  addColorManager(name, manager) {
747
+ if (this.#initialized) {
748
+ return;
749
+ }
605
750
  this.colorManagers.set(name, manager);
606
751
  }
607
752
  addConfig(config) {
753
+ if (this.#initialized) {
754
+ return;
755
+ }
608
756
  const key = config.key ?? config.name ?? "default";
609
757
  this.#configs.set(key, config);
610
758
  this.#engine.dispatchEvent(EventType.configAdded, { data: { name: key, config } });
611
759
  }
612
760
  addEasing(name, easing) {
761
+ if (this.#initialized) {
762
+ return;
763
+ }
613
764
  if (this.easingFunctions.get(name)) {
614
765
  return;
615
766
  }
616
767
  this.easingFunctions.set(name, easing);
617
768
  }
618
769
  addEffect(effect, drawer) {
770
+ if (this.#initialized) {
771
+ return;
772
+ }
619
773
  this.initializers.effects.set(effect, drawer);
620
774
  }
621
775
  addPalette(name, palette) {
776
+ if (this.#initialized) {
777
+ return;
778
+ }
622
779
  this.palettes.set(name, palette);
623
780
  }
624
781
  addParticleUpdater(name, updaterInitializer) {
782
+ if (this.#initialized) {
783
+ return;
784
+ }
625
785
  this.initializers.updaters.set(name, updaterInitializer);
626
786
  }
627
787
  addPlugin(plugin) {
788
+ if (this.#initialized) {
789
+ return;
790
+ }
628
791
  if (this.getPlugin(plugin.id)) {
629
792
  return;
630
793
  }
631
794
  this.plugins.push(plugin);
632
795
  }
633
796
  addPreset(preset, options, override = false) {
797
+ if (this.#initialized) {
798
+ return;
799
+ }
634
800
  if (!(override || !this.getPreset(preset))) {
635
801
  return;
636
802
  }
637
803
  this.presets.set(preset, options);
638
804
  }
639
805
  addShape(shapes, drawer) {
806
+ if (this.#initialized) {
807
+ return;
808
+ }
640
809
  for (const shape of shapes) {
641
810
  this.initializers.shapes.set(shape, drawer);
642
811
  }
643
812
  }
644
- clearPlugins(container) {
645
- this.effectDrawers.delete(container);
646
- this.shapeDrawers.delete(container);
647
- this.updaters.delete(container);
648
- }
649
813
  getEasing(name) {
650
814
  return this.easingFunctions.get(name) ?? ((value) => value);
651
815
  }
652
- getEffectDrawers(container, force = false) {
653
- return getItemMapFromInitializer(container, this.effectDrawers, this.initializers.effects, force);
654
- }
655
816
  getPalette(name) {
656
817
  return this.palettes.get(name);
657
818
  }
@@ -661,12 +822,6 @@
661
822
  getPreset(preset) {
662
823
  return this.presets.get(preset);
663
824
  }
664
- async getShapeDrawers(container, force = false) {
665
- return getItemMapFromInitializer(container, this.shapeDrawers, this.initializers.shapes, force);
666
- }
667
- async getUpdaters(container, force = false) {
668
- return getItemsFromInitializer(container, this.updaters, this.initializers.updaters, force);
669
- }
670
825
  async init() {
671
826
  if (this.#initialized || this.#isRunningLoaders) {
672
827
  return;
@@ -685,16 +840,9 @@
685
840
  this.#initialized = true;
686
841
  }
687
842
  }
688
- loadParticlesOptions(container, options, ...sourceOptions) {
689
- const updaters = this.updaters.get(container);
690
- if (!updaters) {
691
- return;
692
- }
693
- updaters.forEach(updater => updater.loadOptions?.(options, ...sourceOptions));
694
- }
695
843
  async register(...loaders) {
696
844
  if (this.#initialized) {
697
- throw new Error("Register plugins can only be done before calling tsParticles.load()");
845
+ throw new Error(getErrorMessage(ErrorCodes$1.pluginRegisterAfterLoad));
698
846
  }
699
847
  for (const loader of loaders) {
700
848
  if (this.#isRunningLoaders) {
@@ -706,88 +854,15 @@
706
854
  }
707
855
  }
708
856
  async #runLoader(loader, executed, allLoaders) {
709
- if (executed.has(loader))
857
+ if (executed.has(loader)) {
710
858
  return;
859
+ }
711
860
  executed.add(loader);
712
861
  allLoaders.add(loader);
713
862
  await loader(this.#engine);
714
863
  }
715
864
  }
716
865
 
717
- const errorPrefix = "tsParticles - Error";
718
- const wrap = (fn) => (...args) => {
719
- fn(...args);
720
- }, _logger = {
721
- debug: wrap(console.debug),
722
- error: (message, ...optionalParams) => {
723
- console.error(`${errorPrefix} - ${message}`, ...optionalParams);
724
- },
725
- info: wrap(console.info),
726
- log: wrap(console.log),
727
- trace: wrap(console.trace),
728
- verbose: wrap(console.log),
729
- warning: wrap(console.warn),
730
- };
731
- function getLogger() {
732
- return _logger;
733
- }
734
-
735
- const fullPercent = "100%";
736
- async function getDataFromUrl(data) {
737
- const url = itemFromSingleOrMultiple(data.url, data.index);
738
- if (!url) {
739
- return data.fallback;
740
- }
741
- const response = await fetch(url);
742
- if (response.ok) {
743
- return (await response.json());
744
- }
745
- getLogger().error(`${response.status.toString()} while retrieving config file`);
746
- return data.fallback;
747
- }
748
- const getCanvasFromContainer = (domContainer) => {
749
- const documentSafe = safeDocument();
750
- let canvasEl;
751
- const isCanvas = domContainer instanceof HTMLCanvasElement || domContainer.tagName.toLowerCase() === canvasTag;
752
- if (isCanvas) {
753
- canvasEl = domContainer;
754
- canvasEl.dataset[generatedAttribute] ??= generatedFalse;
755
- if (canvasEl.dataset[generatedAttribute] === generatedTrue) {
756
- canvasEl.style.width ||= fullPercent;
757
- canvasEl.style.height ||= fullPercent;
758
- canvasEl.style.pointerEvents = "none";
759
- canvasEl.style.setProperty("pointer-events", "none");
760
- }
761
- }
762
- else {
763
- const existingCanvases = domContainer.getElementsByTagName(canvasTag), foundCanvas = existingCanvases.item(canvasFirstIndex);
764
- if (foundCanvas) {
765
- canvasEl = foundCanvas;
766
- canvasEl.dataset[generatedAttribute] = generatedFalse;
767
- }
768
- else {
769
- canvasEl = documentSafe.createElement(canvasTag);
770
- canvasEl.dataset[generatedAttribute] = generatedTrue;
771
- domContainer.appendChild(canvasEl);
772
- }
773
- canvasEl.style.width ||= fullPercent;
774
- canvasEl.style.height ||= fullPercent;
775
- canvasEl.style.pointerEvents = "none";
776
- canvasEl.style.setProperty("pointer-events", "none");
777
- }
778
- return canvasEl;
779
- }, getDomContainer = (id, source) => {
780
- const documentSafe = safeDocument();
781
- let domContainer = source ?? documentSafe.getElementById(id);
782
- if (domContainer) {
783
- return domContainer;
784
- }
785
- domContainer = documentSafe.createElement("canvas");
786
- domContainer.id = id;
787
- domContainer.dataset[generatedAttribute] = generatedTrue;
788
- documentSafe.body.append(domContainer);
789
- return domContainer;
790
- };
791
866
  class Engine {
792
867
  pluginManager = new PluginManager(this);
793
868
  #domArray = [];
@@ -797,7 +872,7 @@
797
872
  return this.#domArray;
798
873
  }
799
874
  get version() {
800
- return "4.3.2";
875
+ return "4.5.0";
801
876
  }
802
877
  addEventListener(type, listener) {
803
878
  this.#eventDispatcher.addEventListener(type, listener);
@@ -806,7 +881,7 @@
806
881
  if (this.version === pluginVersion) {
807
882
  return;
808
883
  }
809
- throw new Error(`The tsParticles version is different from the loaded plugins version. Engine version: ${this.version}. Plugin version: ${pluginVersion}`);
884
+ throw new Error(getErrorMessage(ErrorCodes$1.engineVersionMismatch, this.version, pluginVersion));
810
885
  }
811
886
  dispatchEvent(type, args) {
812
887
  this.#eventDispatcher.dispatchEvent(type, args);
@@ -878,6 +953,10 @@
878
953
  }
879
954
 
880
955
  function initEngine() {
956
+ const existing = globalThis.tsParticles;
957
+ if (existing?.pluginManager) {
958
+ return existing;
959
+ }
881
960
  return new Engine();
882
961
  }
883
962
 
@@ -975,6 +1054,15 @@
975
1054
  AnimationMode["random"] = "random";
976
1055
  })(AnimationMode || (AnimationMode = {}));
977
1056
 
1057
+ var HdrMode;
1058
+ (function (HdrMode) {
1059
+ HdrMode["standard"] = "standard";
1060
+ HdrMode["natural"] = "natural";
1061
+ HdrMode["vivid"] = "vivid";
1062
+ HdrMode["cinematic"] = "cinematic";
1063
+ HdrMode["dynamic"] = "dynamic";
1064
+ })(HdrMode || (HdrMode = {}));
1065
+
978
1066
  var LimitMode;
979
1067
  (function (LimitMode) {
980
1068
  LimitMode["delete"] = "delete";
@@ -1042,20 +1130,6 @@
1042
1130
  DrawLayer[DrawLayer["Foreground"] = 7] = "Foreground";
1043
1131
  })(DrawLayer || (DrawLayer = {}));
1044
1132
 
1045
- class OptionLoader {
1046
- load(data) {
1047
- if (isNull(data)) {
1048
- return;
1049
- }
1050
- this.doLoad(data);
1051
- }
1052
- }
1053
- function loadOptions(options, ...sourceOptionsArr) {
1054
- for (const sourceOptions of sourceOptionsArr) {
1055
- options.load(sourceOptions);
1056
- }
1057
- }
1058
-
1059
1133
  function loadProperty(obj, key, value) {
1060
1134
  if (value !== undefined) {
1061
1135
  obj[key] = value;
@@ -1087,6 +1161,20 @@
1087
1161
  }
1088
1162
  }
1089
1163
 
1164
+ class OptionLoader {
1165
+ load(data) {
1166
+ if (isNull(data)) {
1167
+ return;
1168
+ }
1169
+ this.doLoad(data);
1170
+ }
1171
+ }
1172
+ function loadOptions(options, ...sourceOptionsArr) {
1173
+ for (const sourceOptions of sourceOptionsArr) {
1174
+ options.load(sourceOptions);
1175
+ }
1176
+ }
1177
+
1090
1178
  class AnimationOptions extends OptionLoader {
1091
1179
  count = 0;
1092
1180
  decay = 0;
@@ -1230,6 +1318,28 @@
1230
1318
  }
1231
1319
  }
1232
1320
 
1321
+ const defaultPeakNits = 400, minPeakNits = 0, toStringValue = (value) => String(value);
1322
+ class HDROptions extends OptionLoader {
1323
+ enable = true;
1324
+ mode = HdrMode.standard;
1325
+ peakNits = defaultPeakNits;
1326
+ doLoad(data) {
1327
+ if (data.enable !== undefined && !isBoolean(data.enable)) {
1328
+ throw new Error(getErrorMessage(ErrorCodes$1.hdrEnableInvalid, String(data.enable)));
1329
+ }
1330
+ if (data.mode !== undefined && !isEnumValue(HdrMode, data.mode)) {
1331
+ throw new Error(getErrorMessage(ErrorCodes$1.hdrModeInvalid, Object.values(HdrMode).join(", "), toStringValue(data.mode)));
1332
+ }
1333
+ if (data.peakNits !== undefined &&
1334
+ (!isNumber(data.peakNits) || !Number.isFinite(data.peakNits) || data.peakNits <= minPeakNits)) {
1335
+ throw new Error(getErrorMessage(ErrorCodes$1.hdrPeakNitsInvalid, String(data.peakNits)));
1336
+ }
1337
+ loadProperty(this, "enable", data.enable);
1338
+ loadProperty(this, "mode", data.mode);
1339
+ loadProperty(this, "peakNits", data.peakNits);
1340
+ }
1341
+ }
1342
+
1233
1343
  class ResizeEvent extends OptionLoader {
1234
1344
  delay = 0.5;
1235
1345
  enable = true;
@@ -1600,12 +1710,10 @@
1600
1710
  plugin.loadParticlesOptions(this.#container, this, data);
1601
1711
  }
1602
1712
  }
1603
- const updaters = this.#pluginManager.updaters.get(this.#container);
1604
- if (updaters) {
1605
- for (const updater of updaters) {
1606
- if (updater.loadOptions) {
1607
- updater.loadOptions(this, data);
1608
- }
1713
+ const updaters = this.#container.particleUpdaters;
1714
+ for (const updater of updaters) {
1715
+ if (updater.loadOptions) {
1716
+ updater.loadOptions(this, data);
1609
1717
  }
1610
1718
  }
1611
1719
  }
@@ -1673,7 +1781,7 @@
1673
1781
  duration = 0;
1674
1782
  fpsLimit = 120;
1675
1783
  fullScreen;
1676
- hdr = true;
1784
+ hdr;
1677
1785
  key;
1678
1786
  name;
1679
1787
  palette;
@@ -1693,6 +1801,7 @@
1693
1801
  this.#container = container;
1694
1802
  this.background = new Background();
1695
1803
  this.fullScreen = new FullScreen();
1804
+ this.hdr = new HDROptions();
1696
1805
  this.particles = loadParticlesOptions(this.#pluginManager, this.#container);
1697
1806
  this.resize = new ResizeEvent();
1698
1807
  }
@@ -1715,7 +1824,15 @@
1715
1824
  loadProperty(this, "detectRetina", data.detectRetina);
1716
1825
  loadRangeProperty(this, "duration", data.duration);
1717
1826
  loadProperty(this, "fpsLimit", data.fpsLimit);
1718
- loadProperty(this, "hdr", data.hdr);
1827
+ const hdrData = data.hdr;
1828
+ if (isBoolean(hdrData)) {
1829
+ this.hdr.enable = hdrData;
1830
+ this.hdr.mode = HdrMode.standard;
1831
+ this.hdr.peakNits = 400;
1832
+ }
1833
+ else {
1834
+ this.hdr.load(hdrData);
1835
+ }
1719
1836
  loadProperty(this, "pauseOnBlur", data.pauseOnBlur);
1720
1837
  loadProperty(this, "pauseOnOutsideViewport", data.pauseOnOutsideViewport);
1721
1838
  loadProperty(this, "zLayers", data.zLayers);
@@ -1758,7 +1875,7 @@
1758
1875
  }
1759
1876
  }
1760
1877
 
1761
- const styleCache = new Map(), maxStyleCacheSize = 2000, rgbFixedPrecision = 2, hslFixedPrecision = 2, hdrRgbFixedPrecision = 4, hdrHslFixedPrecision = 4, sdrReferenceWhiteNits = 203, hdrAnimationScale = sdrReferenceWhiteNits / maxNits;
1878
+ const styleCache = new Map(), maxStyleCacheSize = 2000, rgbFixedPrecision = 2, hslFixedPrecision = 2, hdrRgbFixedPrecision = 4, hdrHslFixedPrecision = 4, sdrReferenceWhiteNits = 203, acesA = 2.51, acesB = 0.03, acesC = 2.43, acesD = 0.59, acesE = 0.14, saturationBoost = 1.15, lightnessBoost = 1.05, temperatureR = 1.05, temperatureB = 0.95, contrastFactor = 1.1, luminanceR = 0.2126, luminanceG = 0.7152, luminanceB = 0.0722, dynamicLuminanceFactor = 2, channelCount = 3;
1762
1879
  function getCachedStyle(key, generator) {
1763
1880
  let cached = styleCache.get(key);
1764
1881
  if (!cached) {
@@ -1770,6 +1887,42 @@
1770
1887
  }
1771
1888
  return cached;
1772
1889
  }
1890
+ function acesFilmic(x) {
1891
+ return clamp((x * (acesA * x + acesB)) / (x * (acesC * x + acesD) + acesE), none, one);
1892
+ }
1893
+ function applyHdrModeAdjustments(r, g, b, mode, maxChannel) {
1894
+ switch (mode) {
1895
+ case HdrMode.vivid: {
1896
+ const avg = (r + g + b) / channelCount;
1897
+ return {
1898
+ b: clamp(clamp(avg + (b - avg) * saturationBoost, none, maxChannel) * lightnessBoost, none, maxChannel),
1899
+ g: clamp(clamp(avg + (g - avg) * saturationBoost, none, maxChannel) * lightnessBoost, none, maxChannel),
1900
+ r: clamp(clamp(avg + (r - avg) * saturationBoost, none, maxChannel) * lightnessBoost, none, maxChannel),
1901
+ };
1902
+ }
1903
+ case HdrMode.cinematic: {
1904
+ const tempR = r * temperatureR, tempB = b * temperatureB, avg = (tempR + g + tempB) / channelCount;
1905
+ return {
1906
+ b: clamp(avg + (tempB - avg) * contrastFactor, none, maxChannel),
1907
+ g: clamp(avg + (g - avg) * contrastFactor, none, maxChannel),
1908
+ r: clamp(avg + (tempR - avg) * contrastFactor, none, maxChannel),
1909
+ };
1910
+ }
1911
+ case HdrMode.dynamic: {
1912
+ const luminance = luminanceR * r + luminanceG * g + luminanceB * b, vividWeight = Math.min(one, luminance * dynamicLuminanceFactor), naturalWeight = one - vividWeight, avg = (r + g + b) / channelCount, vividR = clamp(avg + (r - avg) * saturationBoost, none, maxChannel) * lightnessBoost, vividG = clamp(avg + (g - avg) * saturationBoost, none, maxChannel) * lightnessBoost, vividB = clamp(avg + (b - avg) * saturationBoost, none, maxChannel) * lightnessBoost;
1913
+ return {
1914
+ b: clamp(b * naturalWeight + vividB * vividWeight, none, maxChannel),
1915
+ g: clamp(g * naturalWeight + vividG * vividWeight, none, maxChannel),
1916
+ r: clamp(r * naturalWeight + vividR * vividWeight, none, maxChannel),
1917
+ };
1918
+ }
1919
+ case HdrMode.standard:
1920
+ return { b, g, r };
1921
+ case HdrMode.natural:
1922
+ default:
1923
+ return { b, g, r };
1924
+ }
1925
+ }
1773
1926
  function stringToRgba(pluginManager, input) {
1774
1927
  if (!input) {
1775
1928
  return;
@@ -1893,9 +2046,9 @@
1893
2046
  const grayscaleValue = Math.round(lNormalized * rgbMax);
1894
2047
  return { r: grayscaleValue, g: grayscaleValue, b: grayscaleValue };
1895
2048
  }
1896
- const temp1 = lNormalized < half
2049
+ const temp2 = lNormalized < half
1897
2050
  ? lNormalized * (sNormalizedOffset + sNormalized)
1898
- : lNormalized + sNormalized - lNormalized * sNormalized, temp2 = double * lNormalized - temp1, phaseThird = phaseNumerator / triple, red = Math.min(rgbMax, rgbMax * hslChannel(temp2, temp1, hNormalized + phaseThird)), green = Math.min(rgbMax, rgbMax * hslChannel(temp2, temp1, hNormalized)), blue = Math.min(rgbMax, rgbMax * hslChannel(temp2, temp1, hNormalized - phaseThird));
2051
+ : lNormalized + sNormalized - lNormalized * sNormalized, temp1 = double * lNormalized - temp2, phaseThird = phaseNumerator / triple, red = Math.min(rgbMax, rgbMax * hslChannel(temp1, temp2, hNormalized + phaseThird)), green = Math.min(rgbMax, rgbMax * hslChannel(temp1, temp2, hNormalized)), blue = Math.min(rgbMax, rgbMax * hslChannel(temp1, temp2, hNormalized - phaseThird));
1899
2052
  return { r: Math.round(red), g: Math.round(green), b: Math.round(blue) };
1900
2053
  }
1901
2054
  function hslToRgbFloat(hsl) {
@@ -1904,9 +2057,9 @@
1904
2057
  const grayscaleValue = lNormalized * rgbMax;
1905
2058
  return { r: grayscaleValue, g: grayscaleValue, b: grayscaleValue };
1906
2059
  }
1907
- const temp1 = lNormalized < half
2060
+ const temp2 = lNormalized < half
1908
2061
  ? lNormalized * (sNormalizedOffset + sNormalized)
1909
- : 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));
2062
+ : 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));
1910
2063
  return { r: red, g: green, b: blue };
1911
2064
  }
1912
2065
  function hslaToRgba(hsla) {
@@ -1927,21 +2080,40 @@
1927
2080
  r: getRgbInRangeValue(),
1928
2081
  };
1929
2082
  }
1930
- function getStyleFromRgb(color, hdr, opacity) {
1931
- const rgbPrecision = hdr ? hdrRgbFixedPrecision : rgbFixedPrecision, op = opacity ?? defaultOpacity$1, key = `rgb-${color.r.toFixed(rgbPrecision)}-${color.g.toFixed(rgbPrecision)}-${color.b.toFixed(rgbPrecision)}-${hdr ? "hdr" : "sdr"}-${op.toString()}`;
1932
- return getCachedStyle(key, () => (hdr ? getHdrStyleFromRgb(color, opacity) : getSdrStyleFromRgb(color, opacity)));
2083
+ function getStyleFromRgb(color, hdr, opacity, peakNits, mode) {
2084
+ const rgbPrecision = hdr ? hdrRgbFixedPrecision : rgbFixedPrecision, op = opacity ?? defaultOpacity$1, key = hdr
2085
+ ? `rgb-${color.r.toFixed(rgbPrecision)}-${color.g.toFixed(rgbPrecision)}-${color.b.toFixed(rgbPrecision)}-hdr-${op.toString()}-${(peakNits ?? maxNits).toString()}-${mode ?? HdrMode.standard}`
2086
+ : `rgb-${color.r.toFixed(rgbPrecision)}-${color.g.toFixed(rgbPrecision)}-${color.b.toFixed(rgbPrecision)}-sdr-${op.toString()}`;
2087
+ return getCachedStyle(key, () => hdr ? getHdrStyleFromRgb(color, opacity, peakNits, mode) : getSdrStyleFromRgb(color, opacity));
2088
+ }
2089
+ function getHdrStyleFromRgb(color, opacity, peakNits = maxNits, mode = HdrMode.standard) {
2090
+ const headroom = peakNits / sdrReferenceWhiteNits, middleGray = 0.18, mapped = hdrToneMapColor(color, headroom, middleGray, mode);
2091
+ return `color(display-p3 ${mapped.r.toString()} ${mapped.g.toString()} ${mapped.b.toString()} / ${(opacity ?? defaultOpacity$1).toString()})`;
1933
2092
  }
1934
- function getHdrStyleFromRgb(color, opacity, peakNits = maxNits) {
1935
- const headroom = peakNits / sdrReferenceWhiteNits;
1936
- return `color(display-p3 ${((color.r / rgbMax) * headroom).toString()} ${((color.g / rgbMax) * headroom).toString()} ${((color.b / rgbMax) * headroom).toString()} / ${(opacity ?? defaultOpacity$1).toString()})`;
2093
+ function hdrToneMapColor(color, headroom, middleGray, mode) {
2094
+ const rNorm = color.r / rgbMax, gNorm = color.g / rgbMax, bNorm = color.b / rgbMax;
2095
+ if (mode !== HdrMode.natural && mode !== HdrMode.vivid && mode !== HdrMode.cinematic && mode !== HdrMode.dynamic) {
2096
+ return { b: bNorm, g: gNorm, r: rNorm };
2097
+ }
2098
+ const maxChannel = Math.max(one, headroom), luminance = luminanceR * rNorm + luminanceG * gNorm + luminanceB * bNorm, mappedLuminance = hdrToneMap(luminance, headroom, middleGray), scale = luminance > none ? mappedLuminance / luminance : one;
2099
+ return applyHdrModeAdjustments(clamp(rNorm * scale, none, maxChannel), clamp(gNorm * scale, none, maxChannel), clamp(bNorm * scale, none, maxChannel), mode, maxChannel);
2100
+ }
2101
+ function hdrToneMap(normalized, headroom, middleGray) {
2102
+ if (normalized <= middleGray) {
2103
+ return acesFilmic(normalized);
2104
+ }
2105
+ const expanded = normalized + (normalized - middleGray) * (headroom - one);
2106
+ return acesFilmic(expanded);
1937
2107
  }
1938
2108
  function getSdrStyleFromRgb(color, opacity) {
1939
2109
  return `rgba(${color.r.toString()}, ${color.g.toString()}, ${color.b.toString()}, ${(opacity ?? defaultOpacity$1).toString()})`;
1940
2110
  }
1941
- function getStyleFromHsl(color, hdr, opacity) {
1942
- const hslPrecision = hdr ? hdrHslFixedPrecision : hslFixedPrecision, op = opacity ?? defaultOpacity$1, key = `hsl-${color.h.toFixed(hslPrecision)}-${color.s.toFixed(hslPrecision)}-${color.l.toFixed(hslPrecision)}-${hdr ? "hdr" : "sdr"}-${op.toString()}`;
2111
+ function getStyleFromHsl(color, hdr, opacity, peakNits, mode) {
2112
+ const hslPrecision = hdr ? hdrHslFixedPrecision : hslFixedPrecision, op = opacity ?? defaultOpacity$1, key = hdr
2113
+ ? `hsl-${color.h.toFixed(hslPrecision)}-${color.s.toFixed(hslPrecision)}-${color.l.toFixed(hslPrecision)}-hdr-${op.toString()}-${(peakNits ?? maxNits).toString()}-${mode ?? HdrMode.standard}`
2114
+ : `hsl-${color.h.toFixed(hslPrecision)}-${color.s.toFixed(hslPrecision)}-${color.l.toFixed(hslPrecision)}-sdr-${op.toString()}`;
1943
2115
  return getCachedStyle(key, () => hdr
1944
- ? getStyleFromRgb(hslToRgbFloat(color), true, opacity)
2116
+ ? getStyleFromRgb(hslToRgbFloat(color), true, opacity, peakNits, mode)
1945
2117
  : `hsla(${color.h.toString()}, ${color.s.toString()}%, ${color.l.toString()}%, ${op.toString()})`);
1946
2118
  }
1947
2119
  function getHslFromAnimation(animation) {
@@ -2004,7 +2176,7 @@
2004
2176
  colorValue.velocity = defaultVelocity;
2005
2177
  }
2006
2178
  }
2007
- function updateColorValue(data, decrease, delta, hdr) {
2179
+ function updateColorValue(data, decrease, delta, _hdr) {
2008
2180
  const minLoops = 0, minDelay = 0, identity = 1, minVelocity = 0, minOffset = 0, velocityFactor = 3.6;
2009
2181
  if (!data.enable ||
2010
2182
  ((data.maxLoops ?? minLoops) > minLoops && (data.loops ?? minLoops) > (data.maxLoops ?? minLoops))) {
@@ -2017,7 +2189,7 @@
2017
2189
  if ((data.delayTime ?? minDelay) > minDelay && data.time < (data.delayTime ?? minDelay)) {
2018
2190
  return;
2019
2191
  }
2020
- 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;
2192
+ 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;
2021
2193
  if (!decrease || data.status === AnimationStatus.increasing) {
2022
2194
  data.value += velocity;
2023
2195
  if (data.value > max) {
@@ -2049,9 +2221,9 @@
2049
2221
  return;
2050
2222
  }
2051
2223
  const { h, s, l } = color;
2052
- updateColorValue(h, false, delta, hdr);
2053
- updateColorValue(s, true, delta, hdr);
2054
- updateColorValue(l, true, delta, hdr);
2224
+ updateColorValue(h, false, delta);
2225
+ updateColorValue(s, true, delta);
2226
+ updateColorValue(l, true, delta);
2055
2227
  }
2056
2228
  function alterHsl(color, type, value) {
2057
2229
  return {
@@ -2101,7 +2273,7 @@
2101
2273
  }
2102
2274
 
2103
2275
  async function loadBlendPlugin(engine) {
2104
- engine.checkVersion("4.3.2");
2276
+ engine.checkVersion("4.5.0");
2105
2277
  await engine.pluginManager.register(e => {
2106
2278
  e.pluginManager.addPlugin(new BlendPlugin());
2107
2279
  });
@@ -2138,7 +2310,7 @@
2138
2310
  }
2139
2311
 
2140
2312
  async function loadCircleShape(engine) {
2141
- engine.checkVersion("4.3.2");
2313
+ engine.checkVersion("4.5.0");
2142
2314
  await engine.pluginManager.register(e => {
2143
2315
  e.pluginManager.addShape(["circle"], () => {
2144
2316
  return Promise.resolve(new CircleDrawer());
@@ -2153,7 +2325,7 @@
2153
2325
  RgbIndexes[RgbIndexes["b"] = 3] = "b";
2154
2326
  RgbIndexes[RgbIndexes["a"] = 4] = "a";
2155
2327
  })(RgbIndexes$1 || (RgbIndexes$1 = {}));
2156
- 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;
2328
+ 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;
2157
2329
  class HexColorManager {
2158
2330
  accepts(input) {
2159
2331
  return input.startsWith("#");
@@ -2186,7 +2358,7 @@
2186
2358
  }
2187
2359
 
2188
2360
  async function loadHexColorPlugin(engine) {
2189
- engine.checkVersion("4.3.2");
2361
+ engine.checkVersion("4.5.0");
2190
2362
  await engine.pluginManager.register(e => {
2191
2363
  e.pluginManager.addColorManager("hex", new HexColorManager());
2192
2364
  });
@@ -2226,7 +2398,7 @@
2226
2398
  if (!this.accepts(input)) {
2227
2399
  return;
2228
2400
  }
2229
- const result = hslRegex.exec(input), minLength = 4, defaultAlpha = 1, radix = 10;
2401
+ const result = hslRegex.exec(input), minLength = 4, radix = 10;
2230
2402
  return result
2231
2403
  ? hslaToRgba({
2232
2404
  a: result.length > minLength ? parseAlpha(result[HslIndexes.a]) : defaultAlpha,
@@ -2239,12 +2411,20 @@
2239
2411
  }
2240
2412
 
2241
2413
  async function loadHslColorPlugin(engine) {
2242
- engine.checkVersion("4.3.2");
2414
+ engine.checkVersion("4.5.0");
2243
2415
  await engine.pluginManager.register(e => {
2244
2416
  e.pluginManager.addColorManager("hsl", new HslColorManager());
2245
2417
  });
2246
2418
  }
2247
2419
 
2420
+ const ErrorCodes = {
2421
+ baseMoverNotLoaded: "TSP-3203",
2422
+ };
2423
+
2424
+ const ErrorMessages = {
2425
+ [ErrorCodes.baseMoverNotLoaded]: "tsParticles Base Mover is not loaded",
2426
+ };
2427
+
2248
2428
  class MovePlugin {
2249
2429
  id = "move";
2250
2430
  #pluginManager;
@@ -2263,20 +2443,20 @@
2263
2443
  }
2264
2444
 
2265
2445
  async function loadMovePlugin(engine) {
2266
- engine.checkVersion("4.3.2");
2446
+ engine.checkVersion("4.5.0");
2447
+ if (typeof process !== "undefined" && process.env.NODE_ENV !== "production") {
2448
+ addErrorMessages(ErrorMessages);
2449
+ }
2267
2450
  await engine.pluginManager.register(e => {
2268
2451
  const moveEngine = e, movePluginManager = moveEngine.pluginManager;
2269
2452
  movePluginManager.initializers.pathGenerators ??= new Map();
2270
- movePluginManager.pathGenerators ??= new Map();
2271
2453
  movePluginManager.addPathGenerator = (name, generator) => {
2454
+ if (movePluginManager.initialized) {
2455
+ return;
2456
+ }
2272
2457
  movePluginManager.initializers.pathGenerators ??= new Map();
2273
2458
  movePluginManager.initializers.pathGenerators.set(name, generator);
2274
2459
  };
2275
- movePluginManager.getPathGenerators = async (container, force = false) => {
2276
- movePluginManager.initializers.pathGenerators ??= new Map();
2277
- movePluginManager.pathGenerators ??= new Map();
2278
- return getItemMapFromInitializer(container, movePluginManager.pathGenerators, movePluginManager.initializers.pathGenerators, force);
2279
- };
2280
2460
  e.pluginManager.addPlugin(new MovePlugin(e.pluginManager));
2281
2461
  });
2282
2462
  }
@@ -2473,7 +2653,7 @@
2473
2653
  }
2474
2654
 
2475
2655
  async function loadOpacityUpdater(engine) {
2476
- engine.checkVersion("4.3.2");
2656
+ engine.checkVersion("4.5.0");
2477
2657
  await engine.pluginManager.register(e => {
2478
2658
  e.pluginManager.addParticleUpdater("opacity", container => {
2479
2659
  return Promise.resolve(new OpacityUpdater(container));
@@ -2482,70 +2662,60 @@
2482
2662
  }
2483
2663
 
2484
2664
  const boundsMin = 0;
2485
- function bounceHorizontal(data) {
2486
- if ((data.outMode !== OutMode.bounce && data.outMode !== OutMode.split) ||
2487
- (data.direction !== OutModeDirection.left && data.direction !== OutModeDirection.right)) {
2488
- return;
2489
- }
2490
- if (data.bounds.right < boundsMin && data.direction === OutModeDirection.left) {
2491
- data.particle.position.x = data.size + data.offset.x;
2492
- }
2493
- else if (data.bounds.left > data.canvasSize.width && data.direction === OutModeDirection.right) {
2494
- data.particle.position.x = data.canvasSize.width - data.size - data.offset.x;
2495
- }
2496
- const velocity = data.particle.velocity.x;
2497
- let bounced = false;
2498
- if (data.outOfCanvas &&
2499
- ((data.direction === OutModeDirection.right && velocity > minVelocity) ||
2500
- (data.direction === OutModeDirection.left && velocity < minVelocity))) {
2501
- const newVelocity = getRangeValue(data.particle.options.bounce.horizontal.value);
2502
- data.particle.velocity.x *= -newVelocity;
2503
- bounced = true;
2504
- }
2505
- if (!bounced) {
2506
- return;
2507
- }
2508
- const minPos = data.offset.x + data.size;
2509
- if (data.outOfCanvas && data.direction === OutModeDirection.right) {
2510
- data.particle.position.x = data.canvasSize.width - minPos;
2511
- }
2512
- else if (data.outOfCanvas && data.direction === OutModeDirection.left) {
2513
- data.particle.position.x = minPos;
2514
- }
2515
- if (data.outMode === OutMode.split) {
2516
- data.particle.destroy();
2517
- }
2518
- }
2519
- function bounceVertical(data) {
2520
- if ((data.outMode !== OutMode.bounce && data.outMode !== OutMode.split) ||
2521
- (data.direction !== OutModeDirection.bottom && data.direction !== OutModeDirection.top)) {
2665
+ const bounceAxisConfigs = {
2666
+ [OutModeDirection.left]: {
2667
+ axis: "x",
2668
+ canvas: "width",
2669
+ bounce: "horizontal",
2670
+ negativeEdge: "right",
2671
+ positiveEdge: "left",
2672
+ negative: true,
2673
+ },
2674
+ [OutModeDirection.right]: {
2675
+ axis: "x",
2676
+ canvas: "width",
2677
+ bounce: "horizontal",
2678
+ negativeEdge: "right",
2679
+ positiveEdge: "left",
2680
+ negative: false,
2681
+ },
2682
+ [OutModeDirection.top]: {
2683
+ axis: "y",
2684
+ canvas: "height",
2685
+ bounce: "vertical",
2686
+ negativeEdge: "bottom",
2687
+ positiveEdge: "top",
2688
+ negative: true,
2689
+ },
2690
+ [OutModeDirection.bottom]: {
2691
+ axis: "y",
2692
+ canvas: "height",
2693
+ bounce: "vertical",
2694
+ negativeEdge: "bottom",
2695
+ positiveEdge: "top",
2696
+ negative: false,
2697
+ },
2698
+ };
2699
+ function bounce(data) {
2700
+ if ((data.outMode !== OutMode.bounce && data.outMode !== OutMode.split) || !(data.direction in bounceAxisConfigs)) {
2522
2701
  return;
2523
2702
  }
2524
- if (data.bounds.bottom < boundsMin && data.direction === OutModeDirection.top) {
2525
- data.particle.position.y = data.size + data.offset.y;
2703
+ const config = bounceAxisConfigs[data.direction], bounds = data.bounds, canvasDim = data.canvasSize[config.canvas], position = data.particle.position, velocity = data.particle.velocity[config.axis];
2704
+ if (config.negative && bounds[config.negativeEdge] < boundsMin) {
2705
+ position[config.axis] = data.size + data.offset[config.axis];
2526
2706
  }
2527
- else if (data.bounds.top > data.canvasSize.height && data.direction === OutModeDirection.bottom) {
2528
- data.particle.position.y = data.canvasSize.height - data.size - data.offset.y;
2707
+ else if (!config.negative && bounds[config.positiveEdge] > canvasDim) {
2708
+ position[config.axis] = canvasDim - data.size - data.offset[config.axis];
2529
2709
  }
2530
- const velocity = data.particle.velocity.y;
2531
- let bounced = false;
2532
2710
  if (data.outOfCanvas &&
2533
- ((data.direction === OutModeDirection.bottom && velocity > minVelocity) ||
2534
- (data.direction === OutModeDirection.top && velocity < minVelocity))) {
2535
- const newVelocity = getRangeValue(data.particle.options.bounce.vertical.value);
2536
- data.particle.velocity.y *= -newVelocity;
2537
- bounced = true;
2711
+ ((config.negative && velocity < minVelocity) || (!config.negative && velocity > minVelocity))) {
2712
+ data.particle.velocity[config.axis] *= -getRangeValue(data.particle.options.bounce[config.bounce].value);
2538
2713
  }
2539
- if (!bounced) {
2714
+ else {
2540
2715
  return;
2541
2716
  }
2542
- const minPos = data.offset.y + data.size;
2543
- if (data.outOfCanvas && data.direction === OutModeDirection.bottom) {
2544
- data.particle.position.y = data.canvasSize.height - minPos;
2545
- }
2546
- else if (data.outOfCanvas && data.direction === OutModeDirection.top) {
2547
- data.particle.position.y = minPos;
2548
- }
2717
+ const minPos = data.offset[config.axis] + data.size;
2718
+ position[config.axis] = config.negative ? minPos : canvasDim - minPos;
2549
2719
  if (data.outMode === OutMode.split) {
2550
2720
  data.particle.destroy();
2551
2721
  }
@@ -2561,26 +2731,19 @@
2561
2731
  OutMode.bounce,
2562
2732
  OutMode.split,
2563
2733
  ];
2564
- this.#particleBouncePlugins = container.plugins.filter(p => p.particleBounce !== undefined);
2734
+ this.#particleBouncePlugins = container.plugins.filter(p => !!p.particleBounce);
2565
2735
  }
2566
2736
  update(particle, direction, delta, outMode) {
2567
2737
  if (!this.modes.includes(outMode)) {
2568
2738
  return;
2569
2739
  }
2570
- const container = this.#container;
2571
- let handled = false;
2572
2740
  for (const plugin of this.#particleBouncePlugins) {
2573
- handled = plugin.particleBounce?.(particle, delta, direction) ?? false;
2574
- if (handled) {
2575
- break;
2741
+ if (plugin.particleBounce?.(particle, delta, direction)) {
2742
+ return;
2576
2743
  }
2577
2744
  }
2578
- if (handled) {
2579
- return;
2580
- }
2581
- const pos = particle.getPosition(), offset = particle.offset, size = particle.getRadius(), bounds = calculateBounds(pos, size), canvasSize = container.canvas.size, outOfCanvas = !particle.isInsideCanvasForOutMode(outMode, direction);
2582
- bounceHorizontal({ particle, outMode, direction, bounds, canvasSize, offset, outOfCanvas, size });
2583
- bounceVertical({ particle, outMode, direction, bounds, canvasSize, offset, outOfCanvas, size });
2745
+ const pos = particle.getPosition(), offset = particle.offset, size = particle.getRadius(), bounds = calculateBounds(pos, size), canvasSize = this.#container.canvas.size, outOfCanvas = !particle.isInsideCanvasForOutMode(outMode, direction);
2746
+ bounce({ particle, outMode, direction, bounds, canvasSize, offset, outOfCanvas, size });
2584
2747
  }
2585
2748
  }
2586
2749
 
@@ -2669,108 +2832,109 @@
2669
2832
  return;
2670
2833
  }
2671
2834
  const container = this.#container;
2672
- switch (particle.outType) {
2673
- case ParticleOutType.inside: {
2674
- const { x: vx, y: vy } = particle.velocity;
2675
- updateVector.setTo(originPoint);
2676
- updateVector.length = particle.moveCenter.radius;
2677
- updateVector.angle = particle.velocity.angle + Math.PI;
2678
- updateVector.addTo(particle.moveCenter);
2679
- const { dx, dy } = getDistances(particle.position, updateVector);
2680
- if ((vx <= minVelocity && dx >= minDistance) ||
2681
- (vy <= minVelocity && dy >= minDistance) ||
2682
- (vx >= minVelocity && dx <= minDistance) ||
2683
- (vy >= minVelocity && dy <= minDistance)) {
2684
- return;
2685
- }
2686
- particle.position.x = Math.floor(randomInRangeValue({
2687
- min: 0,
2688
- max: container.canvas.size.width,
2689
- }));
2690
- particle.position.y = Math.floor(randomInRangeValue({
2691
- min: 0,
2692
- max: container.canvas.size.height,
2693
- }));
2694
- const { dx: newDx, dy: newDy } = getDistances(particle.position, particle.moveCenter);
2695
- particle.direction = Math.atan2(-newDy, -newDx);
2696
- particle.velocity.angle = particle.direction;
2697
- particle.justWarped = true;
2698
- break;
2835
+ if (particle.outType === ParticleOutType.inside) {
2836
+ this.#applyOutModeInside(particle, container);
2837
+ }
2838
+ else {
2839
+ if (particle.isInsideCanvasForOutMode(outMode, direction)) {
2840
+ return;
2699
2841
  }
2700
- default: {
2701
- if (particle.isInsideCanvasForOutMode(outMode, direction)) {
2702
- return;
2703
- }
2704
- switch (particle.outType) {
2705
- case ParticleOutType.outside: {
2706
- particle.position.x =
2707
- Math.floor(randomInRangeValue({
2708
- min: -particle.moveCenter.radius,
2709
- max: particle.moveCenter.radius,
2710
- })) + particle.moveCenter.x;
2711
- particle.position.y =
2712
- Math.floor(randomInRangeValue({
2713
- min: -particle.moveCenter.radius,
2714
- max: particle.moveCenter.radius,
2715
- })) + particle.moveCenter.y;
2716
- const { dx, dy } = getDistances(particle.position, particle.moveCenter);
2717
- if (particle.moveCenter.radius) {
2718
- particle.direction = Math.atan2(dy, dx);
2719
- particle.velocity.angle = particle.direction;
2720
- }
2721
- particle.justWarped = true;
2722
- break;
2723
- }
2724
- case ParticleOutType.normal: {
2725
- const warp = particle.options.move.warp, canvasSize = container.canvas.size, newPos = {
2726
- bottom: canvasSize.height + particle.getRadius() + particle.offset.y,
2727
- left: -particle.getRadius() - particle.offset.x,
2728
- right: canvasSize.width + particle.getRadius() + particle.offset.x,
2729
- top: -particle.getRadius() - particle.offset.y,
2730
- }, sizeValue = particle.getRadius(), nextBounds = calculateBounds(particle.position, sizeValue);
2731
- if (direction === OutModeDirection.right && nextBounds.left > canvasSize.width + particle.offset.x) {
2732
- particle.position.x = newPos.left;
2733
- particle.initialPosition.x = particle.position.x;
2734
- if (!warp) {
2735
- particle.position.y = getRandom() * canvasSize.height;
2736
- particle.initialPosition.y = particle.position.y;
2737
- }
2738
- particle.justWarped = true;
2739
- }
2740
- else if (direction === OutModeDirection.left && nextBounds.right < -particle.offset.x) {
2741
- particle.position.x = newPos.right;
2742
- particle.initialPosition.x = particle.position.x;
2743
- if (!warp) {
2744
- particle.position.y = getRandom() * canvasSize.height;
2745
- particle.initialPosition.y = particle.position.y;
2746
- }
2747
- particle.justWarped = true;
2748
- }
2749
- if (direction === OutModeDirection.bottom && nextBounds.top > canvasSize.height + particle.offset.y) {
2750
- if (!warp) {
2751
- particle.position.x = getRandom() * canvasSize.width;
2752
- particle.initialPosition.x = particle.position.x;
2753
- }
2754
- particle.position.y = newPos.top;
2755
- particle.initialPosition.y = particle.position.y;
2756
- particle.justWarped = true;
2757
- }
2758
- else if (direction === OutModeDirection.top && nextBounds.bottom < -particle.offset.y) {
2759
- if (!warp) {
2760
- particle.position.x = getRandom() * canvasSize.width;
2761
- particle.initialPosition.x = particle.position.x;
2762
- }
2763
- particle.position.y = newPos.bottom;
2764
- particle.initialPosition.y = particle.position.y;
2765
- particle.justWarped = true;
2766
- }
2767
- break;
2768
- }
2769
- }
2770
- break;
2842
+ if (particle.outType === ParticleOutType.outside) {
2843
+ this.#applyParticleModeOutside(particle);
2844
+ }
2845
+ else {
2846
+ this.#applyOutModeNormal(particle, container, direction);
2771
2847
  }
2772
2848
  }
2773
2849
  }
2850
+ #applyOutModeInside(particle, container) {
2851
+ const { x: vx, y: vy } = particle.velocity;
2852
+ updateVector.setTo(originPoint);
2853
+ updateVector.length = particle.moveCenter.radius;
2854
+ updateVector.angle = particle.velocity.angle + Math.PI;
2855
+ updateVector.addTo(particle.moveCenter);
2856
+ const { dx, dy } = getDistances(particle.position, updateVector);
2857
+ if ((vx <= minVelocity && dx >= minDistance) ||
2858
+ (vy <= minVelocity && dy >= minDistance) ||
2859
+ (vx >= minVelocity && dx <= minDistance) ||
2860
+ (vy >= minVelocity && dy <= minDistance)) {
2861
+ return;
2862
+ }
2863
+ particle.position.x = Math.floor(randomInRangeValue({
2864
+ min: 0,
2865
+ max: container.canvas.size.width,
2866
+ }));
2867
+ particle.position.y = Math.floor(randomInRangeValue({
2868
+ min: 0,
2869
+ max: container.canvas.size.height,
2870
+ }));
2871
+ const { dx: newDx, dy: newDy } = getDistances(particle.position, particle.moveCenter);
2872
+ particle.direction = Math.atan2(-newDy, -newDx);
2873
+ particle.velocity.angle = particle.direction;
2874
+ particle.justWarped = true;
2875
+ }
2876
+ #applyOutModeNormal(particle, container, direction) {
2877
+ const warp = particle.options.move.warp, canvasSize = container.canvas.size, sizeValue = particle.getRadius(), newPos = {
2878
+ bottom: canvasSize.height + sizeValue + particle.offset.y,
2879
+ left: -sizeValue - particle.offset.x,
2880
+ right: canvasSize.width + sizeValue + particle.offset.x,
2881
+ top: -sizeValue - particle.offset.y,
2882
+ }, nextBounds = calculateBounds(particle.position, sizeValue);
2883
+ if (direction === OutModeDirection.right && nextBounds.left > canvasSize.width + particle.offset.x) {
2884
+ particle.position.x = newPos.left;
2885
+ particle.initialPosition.x = particle.position.x;
2886
+ if (!warp) {
2887
+ particle.position.y = getRandom() * canvasSize.height;
2888
+ particle.initialPosition.y = particle.position.y;
2889
+ }
2890
+ particle.justWarped = true;
2891
+ }
2892
+ else if (direction === OutModeDirection.left && nextBounds.right < -particle.offset.x) {
2893
+ particle.position.x = newPos.right;
2894
+ particle.initialPosition.x = particle.position.x;
2895
+ if (!warp) {
2896
+ particle.position.y = getRandom() * canvasSize.height;
2897
+ particle.initialPosition.y = particle.position.y;
2898
+ }
2899
+ particle.justWarped = true;
2900
+ }
2901
+ if (direction === OutModeDirection.bottom && nextBounds.top > canvasSize.height + particle.offset.y) {
2902
+ if (!warp) {
2903
+ particle.position.x = getRandom() * canvasSize.width;
2904
+ particle.initialPosition.x = particle.position.x;
2905
+ }
2906
+ particle.position.y = newPos.top;
2907
+ particle.initialPosition.y = particle.position.y;
2908
+ particle.justWarped = true;
2909
+ }
2910
+ else if (direction === OutModeDirection.top && nextBounds.bottom < -particle.offset.y) {
2911
+ if (!warp) {
2912
+ particle.position.x = getRandom() * canvasSize.width;
2913
+ particle.initialPosition.x = particle.position.x;
2914
+ }
2915
+ particle.position.y = newPos.bottom;
2916
+ particle.initialPosition.y = particle.position.y;
2917
+ particle.justWarped = true;
2918
+ }
2919
+ }
2920
+ #applyParticleModeOutside(particle) {
2921
+ particle.position.x =
2922
+ Math.floor(randomInRangeValue({
2923
+ min: -particle.moveCenter.radius,
2924
+ max: particle.moveCenter.radius,
2925
+ })) + particle.moveCenter.x;
2926
+ particle.position.y =
2927
+ Math.floor(randomInRangeValue({
2928
+ min: -particle.moveCenter.radius,
2929
+ max: particle.moveCenter.radius,
2930
+ })) + particle.moveCenter.y;
2931
+ const { dx, dy } = getDistances(particle.position, particle.moveCenter);
2932
+ if (particle.moveCenter.radius) {
2933
+ particle.direction = Math.atan2(dy, dx);
2934
+ particle.velocity.angle = particle.direction;
2935
+ }
2936
+ particle.justWarped = true;
2937
+ }
2774
2938
  }
2775
2939
 
2776
2940
  const checkOutMode = (outModes, outMode) => {
@@ -2818,7 +2982,7 @@
2818
2982
  }
2819
2983
 
2820
2984
  async function loadOutModesUpdater(engine) {
2821
- engine.checkVersion("4.3.2");
2985
+ engine.checkVersion("4.5.0");
2822
2986
  await engine.pluginManager.register(e => {
2823
2987
  e.pluginManager.addParticleUpdater("outModes", container => {
2824
2988
  return Promise.resolve(new OutOfCanvasUpdater(container));
@@ -2835,39 +2999,9 @@
2835
2999
  this.#pluginManager = pluginManager;
2836
3000
  }
2837
3001
  init(particle) {
2838
- 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;
2839
- if (fill) {
2840
- const fillColor = AnimatableColor.create(paintColor === undefined ? undefined : AnimatableColor.create(undefined, paintColor), fill.color);
2841
- particle.fillEnabled = fill.enable;
2842
- particle.fillOpacity = getRangeValue(fill.opacity);
2843
- particle.fillAnimation = fillColor.animation;
2844
- const fillHslColor = rangeColorToHsl(this.#pluginManager, fillColor);
2845
- if (fillHslColor) {
2846
- particle.fillColor = getHslAnimationFromHsl(fillHslColor, particle.fillAnimation, container.retina.reduceFactor);
2847
- }
2848
- }
2849
- else {
2850
- particle.fillEnabled = false;
2851
- particle.fillAnimation = undefined;
2852
- particle.fillColor = undefined;
2853
- particle.fillOpacity = defaultOpacity;
2854
- }
2855
- if (stroke) {
2856
- const strokeColor = AnimatableColor.create(paintColor === undefined ? undefined : AnimatableColor.create(undefined, paintColor), stroke.color);
2857
- particle.strokeWidth = getRangeValue(stroke.width) * container.retina.pixelRatio;
2858
- particle.strokeOpacity = getRangeValue(stroke.opacity ?? defaultOpacity);
2859
- particle.strokeAnimation = strokeColor.animation;
2860
- const strokeHslColor = rangeColorToHsl(this.#pluginManager, strokeColor) ?? particle.getFillColor();
2861
- if (strokeHslColor) {
2862
- particle.strokeColor = getHslAnimationFromHsl(strokeHslColor, particle.strokeAnimation, container.retina.reduceFactor);
2863
- }
2864
- }
2865
- else {
2866
- particle.strokeAnimation = undefined;
2867
- particle.strokeColor = undefined;
2868
- particle.strokeOpacity = defaultOpacity;
2869
- particle.strokeWidth = 0;
2870
- }
3002
+ const container = this.#container, options = particle.options, paint = itemFromSingleOrMultiple(options.paint, particle.id, options.reduceDuplicates);
3003
+ this.#initFill(paint, particle, container);
3004
+ this.#initStroke(paint, particle, container);
2871
3005
  }
2872
3006
  isEnabled(particle) {
2873
3007
  const { fillAnimation, fillColor, strokeAnimation, strokeColor } = particle, fillEnabled = !!fillAnimation &&
@@ -2879,17 +3013,55 @@
2879
3013
  (strokeColor?.l.value !== undefined && strokeColor.l.enable));
2880
3014
  return !particle.destroyed && !particle.spawning && (fillEnabled || strokeEnabled);
2881
3015
  }
2882
- update(particle, delta) {
2883
- if (!this.isEnabled(particle)) {
3016
+ update(particle, delta) {
3017
+ if (!this.isEnabled(particle)) {
3018
+ return;
3019
+ }
3020
+ updateColor(particle.fillColor, delta, this.#container.hdr);
3021
+ updateColor(particle.strokeColor, delta, this.#container.hdr);
3022
+ }
3023
+ #initFill(paint, particle, container) {
3024
+ const fill = paint?.fill, color = paint?.color, paintColor = color ?? undefined;
3025
+ if (!fill) {
3026
+ particle.fillEnabled = false;
3027
+ particle.fillAnimation = undefined;
3028
+ particle.fillColor = undefined;
3029
+ particle.fillOpacity = defaultOpacity;
3030
+ return;
3031
+ }
3032
+ const fillColor = AnimatableColor.create(paintColor === undefined ? undefined : AnimatableColor.create(undefined, paintColor), fill.color);
3033
+ particle.fillEnabled = fill.enable;
3034
+ particle.fillOpacity = getRangeValue(fill.opacity);
3035
+ particle.fillAnimation = fillColor.animation;
3036
+ const fillHslColor = rangeColorToHsl(this.#pluginManager, fillColor);
3037
+ if (!fillHslColor) {
3038
+ return;
3039
+ }
3040
+ particle.fillColor = getHslAnimationFromHsl(fillHslColor, particle.fillAnimation, container.retina.reduceFactor);
3041
+ }
3042
+ #initStroke(paint, particle, container) {
3043
+ const stroke = paint?.stroke, color = paint?.color, paintColor = color ?? undefined;
3044
+ if (!stroke) {
3045
+ particle.strokeAnimation = undefined;
3046
+ particle.strokeColor = undefined;
3047
+ particle.strokeOpacity = defaultOpacity;
3048
+ particle.strokeWidth = 0;
2884
3049
  return;
2885
3050
  }
2886
- updateColor(particle.fillColor, delta, this.#container.hdr);
2887
- updateColor(particle.strokeColor, delta, this.#container.hdr);
3051
+ const strokeColor = AnimatableColor.create(paintColor === undefined ? undefined : AnimatableColor.create(undefined, paintColor), stroke.color);
3052
+ particle.strokeWidth = getRangeValue(stroke.width) * container.retina.pixelRatio;
3053
+ particle.strokeOpacity = getRangeValue(stroke.opacity ?? defaultOpacity);
3054
+ particle.strokeAnimation = strokeColor.animation;
3055
+ const strokeHslColor = rangeColorToHsl(this.#pluginManager, strokeColor) ?? particle.getFillColor();
3056
+ if (!strokeHslColor) {
3057
+ return;
3058
+ }
3059
+ particle.strokeColor = getHslAnimationFromHsl(strokeHslColor, particle.strokeAnimation, container.retina.reduceFactor);
2888
3060
  }
2889
3061
  }
2890
3062
 
2891
3063
  async function loadPaintUpdater(engine) {
2892
- engine.checkVersion("4.3.2");
3064
+ engine.checkVersion("4.5.0");
2893
3065
  await engine.pluginManager.register(e => {
2894
3066
  e.pluginManager.addParticleUpdater("paint", container => {
2895
3067
  return Promise.resolve(new PaintUpdater(e.pluginManager, container));
@@ -2931,7 +3103,7 @@
2931
3103
  if (!this.accepts(input)) {
2932
3104
  return;
2933
3105
  }
2934
- const result = rgbRegex.exec(input), radix = 10, minLength = 4, defaultAlpha = 1;
3106
+ const result = rgbRegex.exec(input), radix = 10, minLength = 4;
2935
3107
  return result
2936
3108
  ? {
2937
3109
  a: result.length > minLength ? parseAlpha(result[RgbIndexes.a]) : defaultAlpha,
@@ -2944,7 +3116,7 @@
2944
3116
  }
2945
3117
 
2946
3118
  async function loadRgbColorPlugin(engine) {
2947
- engine.checkVersion("4.3.2");
3119
+ engine.checkVersion("4.5.0");
2948
3120
  await engine.pluginManager.register(e => {
2949
3121
  e.pluginManager.addColorManager("rgb", new RgbColorManager());
2950
3122
  });
@@ -3029,7 +3201,7 @@
3029
3201
  }
3030
3202
 
3031
3203
  async function loadSizeUpdater(engine) {
3032
- engine.checkVersion("4.3.2");
3204
+ engine.checkVersion("4.5.0");
3033
3205
  await engine.pluginManager.register(e => {
3034
3206
  e.pluginManager.addParticleUpdater("size", container => {
3035
3207
  return Promise.resolve(new SizeUpdater(container));
@@ -3038,7 +3210,7 @@
3038
3210
  }
3039
3211
 
3040
3212
  async function loadBasic(engine) {
3041
- engine.checkVersion("4.3.2");
3213
+ engine.checkVersion("4.5.0");
3042
3214
  await engine.pluginManager.register(async (e) => {
3043
3215
  await Promise.all([
3044
3216
  loadBlendPlugin(e),
@@ -3270,7 +3442,7 @@
3270
3442
  }
3271
3443
 
3272
3444
  async function loadMatrixShape(engine) {
3273
- engine.checkVersion("4.3.2");
3445
+ engine.checkVersion("4.5.0");
3274
3446
  await engine.pluginManager.register(e => {
3275
3447
  e.pluginManager.addShape(["matrix"], () => Promise.resolve(new MatrixDrawer()));
3276
3448
  });
@@ -3315,12 +3487,16 @@
3315
3487
  }
3316
3488
 
3317
3489
  async function loadPoissonDiscPlugin(engine) {
3318
- engine.checkVersion("4.3.2");
3490
+ engine.checkVersion("4.5.0");
3319
3491
  await engine.pluginManager.register(e => {
3320
3492
  e.pluginManager.addPlugin(new PoissonDiscPlugin());
3321
3493
  });
3322
3494
  }
3323
3495
 
3496
+ const globalObject$1 = globalThis;
3497
+ globalObject$1.__tsParticlesInternals = globalObject$1.__tsParticlesInternals ?? {};
3498
+ globalObject$1.loadPoissonDiscPlugin = loadPoissonDiscPlugin;
3499
+
3324
3500
  const defaultShadowBlur = 0, defaultShadowOffsetValue = 0;
3325
3501
  class ShadowDrawer {
3326
3502
  #container;
@@ -3340,7 +3516,7 @@
3340
3516
  }
3341
3517
  context.save();
3342
3518
  context.shadowBlur = shadowParticle.shadowBlur ?? defaultShadowBlur;
3343
- context.shadowColor = getStyleFromRgb(shadowColor, container.hdr);
3519
+ context.shadowColor = getStyleFromRgb(shadowColor, container.hdr, undefined, container.peakNits, container.hdrMode);
3344
3520
  context.shadowOffsetX = shadowOffset?.x ?? defaultShadowOffsetValue;
3345
3521
  context.shadowOffsetY = shadowOffset?.y ?? defaultShadowOffsetValue;
3346
3522
  }
@@ -3353,7 +3529,7 @@
3353
3529
  }
3354
3530
 
3355
3531
  async function loadShadowEffect(engine) {
3356
- engine.checkVersion("4.3.2");
3532
+ engine.checkVersion("4.5.0");
3357
3533
  await engine.pluginManager.register(e => {
3358
3534
  e.pluginManager.addEffect("shadow", container => {
3359
3535
  return Promise.resolve(new ShadowDrawer(e.pluginManager, container));
@@ -3417,7 +3593,7 @@
3417
3593
  }
3418
3594
 
3419
3595
  async function loadTrailPlugin(engine) {
3420
- engine.checkVersion("4.3.2");
3596
+ engine.checkVersion("4.5.0");
3421
3597
  await engine.pluginManager.register(e => {
3422
3598
  e.pluginManager.addPlugin(new TrailPlugin(e.pluginManager));
3423
3599
  });
@@ -3582,21 +3758,28 @@
3582
3758
  });
3583
3759
  }
3584
3760
  clear() {
3761
+ const visited = new Set();
3585
3762
  for (const plugin of this.#canvasClearPlugins) {
3763
+ visited.add(plugin);
3586
3764
  if (plugin.canvasClear?.() ?? false) {
3587
- return;
3765
+ return plugin;
3588
3766
  }
3589
3767
  }
3590
3768
  for (const layer of Object.values(DrawLayer)) {
3591
3769
  if (typeof layer === "number") {
3592
3770
  for (const plugin of this.#getLayerPlugins(layer)) {
3771
+ if (visited.has(plugin)) {
3772
+ continue;
3773
+ }
3774
+ visited.add(plugin);
3593
3775
  if (plugin.canvasClear?.() ?? false) {
3594
- return;
3776
+ return plugin;
3595
3777
  }
3596
3778
  }
3597
3779
  }
3598
3780
  }
3599
3781
  this.canvasClear();
3782
+ return undefined;
3600
3783
  }
3601
3784
  destroy() {
3602
3785
  this.stop();
@@ -3637,7 +3820,11 @@
3637
3820
  if (!fColor && !sColor) {
3638
3821
  return;
3639
3822
  }
3640
- 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;
3823
+ 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
3824
+ ? getStyleFromHsl(fColor, container.hdr, fillOpacity * opacity, container.peakNits, container.hdrMode)
3825
+ : undefined, stroke = sColor
3826
+ ? getStyleFromHsl(sColor, container.hdr, strokeOpacity * opacity, container.peakNits, container.hdrMode)
3827
+ : fill;
3641
3828
  transform.a = transform.b = transform.c = transform.d = undefined;
3642
3829
  colorStyles.fill = fill;
3643
3830
  colorStyles.stroke = stroke;
@@ -3670,8 +3857,7 @@
3670
3857
  });
3671
3858
  }
3672
3859
  drawParticles(delta) {
3673
- const { particles, actualOptions } = this.#container;
3674
- this.clear();
3860
+ const { particles, actualOptions } = this.#container, clearedPlugin = this.clear();
3675
3861
  particles.update(delta);
3676
3862
  this.draw(ctx => {
3677
3863
  const width = this.#canvasManager.size.width, height = this.#canvasManager.size.height;
@@ -3693,7 +3879,9 @@
3693
3879
  }
3694
3880
  }
3695
3881
  for (const plugin of this.#getLayerPlugins(DrawLayer.BackgroundMask)) {
3696
- plugin.canvasPaint?.();
3882
+ if (plugin !== clearedPlugin) {
3883
+ plugin.canvasPaint?.();
3884
+ }
3697
3885
  }
3698
3886
  for (const plugin of this.#getLayerPlugins(DrawLayer.CanvasSetup)) {
3699
3887
  plugin.drawSettingsSetup?.(ctx, delta);
@@ -3725,35 +3913,7 @@
3725
3913
  this.#layers[layer] = [];
3726
3914
  }
3727
3915
  }
3728
- for (const plugin of this.#container.plugins) {
3729
- if (plugin.particleFillColor ?? plugin.particleStrokeColor) {
3730
- this.#colorPlugins.push(plugin);
3731
- }
3732
- if (plugin.drawParticle) {
3733
- this.#drawParticlePlugins.push(plugin);
3734
- }
3735
- if (plugin.drawParticleSetup) {
3736
- this.#drawParticlesSetupPlugins.push(plugin);
3737
- }
3738
- if (plugin.drawParticleCleanup) {
3739
- this.#drawParticlesCleanupPlugins.push(plugin);
3740
- }
3741
- if (plugin.canvasClear) {
3742
- this.#canvasClearPlugins.push(plugin);
3743
- }
3744
- if (plugin.canvasPaint) {
3745
- this.#getLayerPlugins(DrawLayer.BackgroundMask).push(plugin);
3746
- }
3747
- if (plugin.drawSettingsSetup) {
3748
- this.#getLayerPlugins(DrawLayer.CanvasSetup).push(plugin);
3749
- }
3750
- if (plugin.draw) {
3751
- this.#getLayerPlugins(DrawLayer.PluginContent).push(plugin);
3752
- }
3753
- if (plugin.clearDraw ?? plugin.drawSettingsCleanup) {
3754
- this.#getLayerPlugins(DrawLayer.CanvasCleanup).push(plugin);
3755
- }
3756
- }
3916
+ this.#initPluginsArray();
3757
3917
  }
3758
3918
  initUpdaters() {
3759
3919
  this.#preDrawUpdaters = [];
@@ -3962,6 +4122,45 @@
3962
4122
  this.#reusablePluginColors[sColorIndex] = sColor;
3963
4123
  return this.#reusablePluginColors;
3964
4124
  }
4125
+ #initLayerPlugin(plugin) {
4126
+ const layerMap = [
4127
+ [DrawLayer.BackgroundMask, !!plugin.canvasPaint],
4128
+ [DrawLayer.CanvasSetup, !!plugin.drawSettingsSetup],
4129
+ [DrawLayer.PluginContent, !!plugin.draw],
4130
+ [DrawLayer.CanvasCleanup, !!(plugin.clearDraw ?? plugin.drawSettingsCleanup)],
4131
+ ];
4132
+ for (const [layer, active] of layerMap) {
4133
+ if (active) {
4134
+ this.#layers[layer].push(plugin);
4135
+ }
4136
+ }
4137
+ }
4138
+ #initPluginsArray() {
4139
+ for (const plugin of this.#container.plugins) {
4140
+ if (plugin.particleFillColor ?? plugin.particleStrokeColor) {
4141
+ this.#colorPlugins.push(plugin);
4142
+ }
4143
+ if (plugin.drawParticle) {
4144
+ this.#drawParticlePlugins.push(plugin);
4145
+ }
4146
+ if (plugin.drawParticleSetup) {
4147
+ this.#drawParticlesSetupPlugins.push(plugin);
4148
+ }
4149
+ if (plugin.drawParticleCleanup) {
4150
+ this.#drawParticlesCleanupPlugins.push(plugin);
4151
+ }
4152
+ if (plugin.canvasClear) {
4153
+ this.#canvasClearPlugins.push(plugin);
4154
+ }
4155
+ this.#initLayerPlugin(plugin);
4156
+ }
4157
+ }
4158
+ #isSupportedElement(element) {
4159
+ return ((typeof HTMLCanvasElement !== "undefined" && element instanceof HTMLCanvasElement) ||
4160
+ (typeof OffscreenCanvas !== "undefined" && element instanceof OffscreenCanvas) ||
4161
+ (typeof HTMLVideoElement !== "undefined" && element instanceof HTMLVideoElement) ||
4162
+ (typeof HTMLImageElement !== "undefined" && element instanceof HTMLImageElement));
4163
+ }
3965
4164
  #resolveBackgroundElement() {
3966
4165
  const background = this.#container.actualOptions.background;
3967
4166
  this.#backgroundElement = null;
@@ -3971,7 +4170,7 @@
3971
4170
  if (typeof background.element === "string") {
3972
4171
  if (typeof document !== "undefined") {
3973
4172
  const node = document.querySelector(background.element);
3974
- if (node instanceof HTMLCanvasElement || node instanceof HTMLVideoElement || node instanceof HTMLImageElement) {
4173
+ if (node && this.#isSupportedElement(node)) {
3975
4174
  this.#backgroundElement = node;
3976
4175
  }
3977
4176
  else if (node) {
@@ -3982,10 +4181,7 @@
3982
4181
  }
3983
4182
  }
3984
4183
  }
3985
- else if (background.element instanceof HTMLCanvasElement ||
3986
- background.element instanceof OffscreenCanvas ||
3987
- background.element instanceof HTMLVideoElement ||
3988
- background.element instanceof HTMLImageElement) {
4184
+ else if (this.#isSupportedElement(background.element)) {
3989
4185
  this.#backgroundElement = background.element;
3990
4186
  }
3991
4187
  }
@@ -4003,7 +4199,7 @@
4003
4199
  return transferredCanvas;
4004
4200
  }
4005
4201
  if (typeof canvas.transferControlToOffscreen !== "function") {
4006
- throw new TypeError("OffscreenCanvas is required but not supported by this browser");
4202
+ throw new TypeError(getErrorMessage(ErrorCodes$1.offscreenCanvasUnsupported));
4007
4203
  }
4008
4204
  try {
4009
4205
  const offscreenCanvas = canvas.transferControlToOffscreen();
@@ -4011,10 +4207,16 @@
4011
4207
  return offscreenCanvas;
4012
4208
  }
4013
4209
  catch {
4014
- throw new TypeError("OffscreenCanvas transfer failed");
4210
+ throw new TypeError(getErrorMessage(ErrorCodes$1.offscreenCanvasTransferFailed));
4015
4211
  }
4016
4212
  }, isHtmlCanvasElement = (canvas) => {
4017
4213
  return typeof HTMLCanvasElement !== "undefined" && canvas instanceof HTMLCanvasElement;
4214
+ }, getEffectiveColorSpace = (context) => {
4215
+ if (!context) {
4216
+ return undefined;
4217
+ }
4218
+ const colorInfo = context;
4219
+ return colorInfo.getContextAttributes?.().colorSpace ?? undefined;
4018
4220
  };
4019
4221
  function setStyle(canvas, style, important = false) {
4020
4222
  if (!style) {
@@ -4053,6 +4255,7 @@
4053
4255
  zoom = defaultZoom;
4054
4256
  #container;
4055
4257
  #generated;
4258
+ #hdrMediaListeners;
4056
4259
  #mutationObserver;
4057
4260
  #originalStyle;
4058
4261
  #pluginManager;
@@ -4117,7 +4320,6 @@
4117
4320
  });
4118
4321
  this.resize();
4119
4322
  this.#initStyle();
4120
- this.initBackground();
4121
4323
  this.#safeMutationObserver(obs => {
4122
4324
  const element = this.domElement;
4123
4325
  if (!element || !(element instanceof Node)) {
@@ -4127,6 +4329,8 @@
4127
4329
  });
4128
4330
  this.initPlugins();
4129
4331
  this.#initContext();
4332
+ this.initBackground();
4333
+ this.#initHdrListeners();
4130
4334
  this.render.init();
4131
4335
  }
4132
4336
  initBackground() {
@@ -4136,7 +4340,8 @@
4136
4340
  }
4137
4341
  const elementStyle = element.style, color = rangeColorToRgb(this.#pluginManager, background.color);
4138
4342
  if (color) {
4139
- elementStyle.backgroundColor = getStyleFromRgb(color, container.actualOptions.hdr, background.opacity);
4343
+ const hdrOptions = container.actualOptions.hdr;
4344
+ elementStyle.backgroundColor = getStyleFromRgb(color, container.hdr, background.opacity, hdrOptions.peakNits, toEnumValue(HdrMode, hdrOptions.mode, HdrMode.standard));
4140
4345
  }
4141
4346
  else {
4142
4347
  elementStyle.backgroundColor = "";
@@ -4233,6 +4438,7 @@
4233
4438
  obs.disconnect();
4234
4439
  });
4235
4440
  this.#mutationObserver = undefined;
4441
+ this.#removeHdrListeners();
4236
4442
  this.render.stop();
4237
4443
  }
4238
4444
  async windowResize() {
@@ -4252,9 +4458,16 @@
4252
4458
  }
4253
4459
  }
4254
4460
  #initContext() {
4255
- const container = this.#container, canSupportHdr = container.actualOptions.hdr &&
4461
+ const container = this.#container, canSupportHdr = container.actualOptions.hdr.enable &&
4256
4462
  safeMatchMedia("(color-gamut: p3)")?.matches &&
4257
4463
  safeMatchMedia("(dynamic-range: high)")?.matches;
4464
+ container.hdrMode = toEnumValue(HdrMode, container.actualOptions.hdr.mode, HdrMode.standard);
4465
+ container.peakNits = container.actualOptions.hdr.peakNits;
4466
+ const renderCanvas = this.renderCanvas;
4467
+ if (!renderCanvas) {
4468
+ container.hdr = canSupportHdr ?? false;
4469
+ return;
4470
+ }
4258
4471
  this.render.setContextSettings({
4259
4472
  alpha: true,
4260
4473
  desynchronized: true,
@@ -4263,11 +4476,51 @@
4263
4476
  ? { colorSpace: "display-p3", colorType: "float16" }
4264
4477
  : { colorSpace: "srgb" }),
4265
4478
  });
4266
- const renderCanvas = this.renderCanvas;
4267
- if (!renderCanvas) {
4268
- return;
4479
+ let context;
4480
+ try {
4481
+ context = renderCanvas.getContext("2d", this.render.settings);
4482
+ }
4483
+ catch {
4484
+ context = null;
4485
+ }
4486
+ if (canSupportHdr && !context) {
4487
+ const sdrSettings = {
4488
+ alpha: true,
4489
+ desynchronized: true,
4490
+ willReadFrequently: false,
4491
+ colorSpace: "srgb",
4492
+ };
4493
+ this.render.setContextSettings(sdrSettings);
4494
+ try {
4495
+ context = renderCanvas.getContext("2d", sdrSettings);
4496
+ }
4497
+ catch {
4498
+ context = null;
4499
+ }
4500
+ }
4501
+ this.render.setContext(context);
4502
+ if (context) {
4503
+ const effectiveColorSpace = getEffectiveColorSpace(context);
4504
+ if (effectiveColorSpace !== undefined) {
4505
+ container.hdr = effectiveColorSpace === "display-p3";
4506
+ }
4507
+ }
4508
+ }
4509
+ #initHdrListeners() {
4510
+ this.#removeHdrListeners();
4511
+ const p3Query = safeMatchMedia("(color-gamut: p3)"), hdrQuery = safeMatchMedia("(dynamic-range: high)"), handleChange = () => {
4512
+ this.#initContext();
4513
+ this.initBackground();
4514
+ }, listeners = [];
4515
+ if (p3Query) {
4516
+ p3Query.addEventListener("change", handleChange);
4517
+ listeners.push({ handler: handleChange, mql: p3Query });
4518
+ }
4519
+ if (hdrQuery) {
4520
+ hdrQuery.addEventListener("change", handleChange);
4521
+ listeners.push({ handler: handleChange, mql: hdrQuery });
4269
4522
  }
4270
- this.render.setContext(renderCanvas.getContext("2d", this.render.settings));
4523
+ this.#hdrMediaListeners = listeners;
4271
4524
  }
4272
4525
  #initStyle() {
4273
4526
  const element = this.domElement, options = this.#container.actualOptions;
@@ -4291,6 +4544,15 @@
4291
4544
  element.style.setProperty(key, value, "important");
4292
4545
  }
4293
4546
  }
4547
+ #removeHdrListeners() {
4548
+ if (!this.#hdrMediaListeners) {
4549
+ return;
4550
+ }
4551
+ for (const { handler, mql } of this.#hdrMediaListeners) {
4552
+ mql.removeEventListener("change", handler);
4553
+ }
4554
+ this.#hdrMediaListeners = undefined;
4555
+ }
4294
4556
  #repairStyle() {
4295
4557
  const element = this.domElement;
4296
4558
  if (!element) {
@@ -4380,8 +4642,7 @@
4380
4642
  this.#resizeTimeout = undefined;
4381
4643
  }
4382
4644
  const handleResize = async () => {
4383
- const canvas = this.#container.canvas;
4384
- await canvas.windowResize();
4645
+ await this.#container.canvas.windowResize();
4385
4646
  };
4386
4647
  this.#resizeTimeout = setTimeout(() => void handleResize(), this.#container.actualOptions.resize.delay * millisecondsToSeconds);
4387
4648
  }
@@ -4409,8 +4670,8 @@
4409
4670
  }
4410
4671
  else if (!this.#resizeObserver && add && canvasEl) {
4411
4672
  this.#resizeObserver = new ResizeObserver((entries) => {
4412
- const entry = entries.find(e => e.target === canvasEl);
4413
- if (!entry) {
4673
+ const res = entries.some(e => e.target === canvasEl);
4674
+ if (!res) {
4414
4675
  return;
4415
4676
  }
4416
4677
  this.#handleWindowResize();
@@ -4674,10 +4935,10 @@
4674
4935
  return this.#modifiers.find(m => m.id === id);
4675
4936
  }
4676
4937
  getOpacity() {
4677
- const zIndexOptions = this.options.zIndex, zIndexFactor = zIndexFactorOffset - this.zIndexFactor, zOpacityFactor = zIndexFactor ** zIndexOptions.opacityRate, baseOpacity = getRangeValue(this.opacity?.value ?? defaultOpacity$1), modifierOpacity = this.#applyModifiers(undefined, m => m.opacity), opacity = modifierOpacity ?? baseOpacity, fillOpacity = this.fillOpacity ?? defaultOpacity$1, strokeOpacity = this.strokeOpacity ?? defaultOpacity$1;
4678
- this.#cachedOpacityData.fillOpacity = opacity * fillOpacity * zOpacityFactor;
4938
+ const zIndexOptions = this.options.zIndex, zIndexFactor = zIndexFactorOffset - this.zIndexFactor, zOpacityFactor = zIndexFactor ** zIndexOptions.opacityRate, baseOpacity = getRangeValue(this.opacity?.value ?? defaultOpacity$1), modifierOpacity = this.#applyModifiers(undefined, m => m.opacity), opacity = modifierOpacity ?? baseOpacity;
4939
+ this.#cachedOpacityData.fillOpacity = this.fillOpacity ?? defaultOpacity$1;
4679
4940
  this.#cachedOpacityData.opacity = opacity * zOpacityFactor;
4680
- this.#cachedOpacityData.strokeOpacity = opacity * strokeOpacity * zOpacityFactor;
4941
+ this.#cachedOpacityData.strokeOpacity = this.strokeOpacity ?? defaultOpacity$1;
4681
4942
  return this.#cachedOpacityData;
4682
4943
  }
4683
4944
  getPosition() {
@@ -4924,7 +5185,7 @@
4924
5185
  #initPosition(position) {
4925
5186
  const container = this.#container, zIndexValue = Math.floor(getRangeValue(this.options.zIndex.value)), initialPosition = this.#calcPosition(position, clamp(zIndexValue, minZ, container.zLayers));
4926
5187
  if (!initialPosition) {
4927
- throw new Error("a valid position cannot be found for particle");
5188
+ throw new Error(getErrorMessage(ErrorCodes$1.particlePositionNotFound));
4928
5189
  }
4929
5190
  this.position = initialPosition;
4930
5191
  this.initialPosition = this.position.copy();
@@ -4973,6 +5234,12 @@
4973
5234
  this.#circlePoolIdx = 0;
4974
5235
  this.#rectanglePoolIdx = 0;
4975
5236
  }
5237
+ get cellSize() {
5238
+ return this.#cellSize;
5239
+ }
5240
+ set cellSize(value) {
5241
+ this.#pendingCellSize = value;
5242
+ }
4976
5243
  clear() {
4977
5244
  this.#cells.clear();
4978
5245
  const pendingCellSize = this.#pendingCellSize;
@@ -4996,18 +5263,7 @@
4996
5263
  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);
4997
5264
  for (let cx = minCellX; cx <= maxCellX; cx++) {
4998
5265
  for (let cy = minCellY; cy <= maxCellY; cy++) {
4999
- const key = `${cx}_${cy}`, cellParticles = this.#cells.get(key);
5000
- if (!cellParticles) {
5001
- continue;
5002
- }
5003
- for (const p of cellParticles) {
5004
- if (check && !check(p)) {
5005
- continue;
5006
- }
5007
- if (range.contains(p.getPosition())) {
5008
- out.push(p);
5009
- }
5010
- }
5266
+ this.#queryCell(cx, cy, range, check, out);
5011
5267
  }
5012
5268
  }
5013
5269
  return out;
@@ -5022,14 +5278,23 @@
5022
5278
  this.#releaseShapes();
5023
5279
  return result;
5024
5280
  }
5025
- setCellSize(cellSize) {
5026
- this.#pendingCellSize = cellSize;
5027
- }
5028
5281
  #acquireCircle(x, y, r) {
5029
- return (this.#circlePool[this.#circlePoolIdx++] ??= new Circle(x, y, r)).reset(x, y, r);
5282
+ const idx = this.#circlePoolIdx++;
5283
+ let circle = this.#circlePool[idx];
5284
+ if (!circle) {
5285
+ circle = new Circle(x, y, r);
5286
+ this.#circlePool[idx] = circle;
5287
+ }
5288
+ return circle.reset(x, y, r);
5030
5289
  }
5031
5290
  #acquireRectangle(x, y, w, h) {
5032
- return (this.#rectanglePool[this.#rectanglePoolIdx++] ??= new Rectangle(x, y, w, h)).reset(x, y, w, h);
5291
+ const idx = this.#rectanglePoolIdx++;
5292
+ let rectangle = this.#rectanglePool[idx];
5293
+ if (!rectangle) {
5294
+ rectangle = new Rectangle(x, y, w, h);
5295
+ this.#rectanglePool[idx] = rectangle;
5296
+ }
5297
+ return rectangle.reset(x, y, w, h);
5033
5298
  }
5034
5299
  #cellKeyFromCoords(x, y) {
5035
5300
  const cellX = Math.floor(x / this.#cellSize), cellY = Math.floor(y / this.#cellSize);
@@ -5056,6 +5321,20 @@
5056
5321
  }
5057
5322
  return null;
5058
5323
  }
5324
+ #queryCell(cx, cy, range, check, out) {
5325
+ const cellParticles = this.#cells.get(`${cx}_${cy}`);
5326
+ if (!cellParticles) {
5327
+ return;
5328
+ }
5329
+ for (const p of cellParticles) {
5330
+ if (check && !check(p)) {
5331
+ continue;
5332
+ }
5333
+ if (range.contains(p.getPosition())) {
5334
+ out.push(p);
5335
+ }
5336
+ }
5337
+ }
5059
5338
  #releaseShapes() {
5060
5339
  this.#circlePoolIdx = 0;
5061
5340
  this.#rectanglePoolIdx = 0;
@@ -5064,9 +5343,9 @@
5064
5343
 
5065
5344
  class ParticlesManager {
5066
5345
  checkParticlePositionPlugins;
5067
- grid;
5068
5346
  #array;
5069
5347
  #container;
5348
+ #grid;
5070
5349
  #groupLimits;
5071
5350
  #limit;
5072
5351
  #nextId;
@@ -5090,7 +5369,7 @@
5090
5369
  this.#groupLimits = new Map();
5091
5370
  this.#particleBuckets = new Map();
5092
5371
  this.#zBuckets = this.#createBuckets(this.#container.zLayers);
5093
- this.grid = new SpatialHashGrid(spatialHashGridCellSize);
5372
+ this.#grid = new SpatialHashGrid(spatialHashGridCellSize);
5094
5373
  this.checkParticlePositionPlugins = [];
5095
5374
  this.#particleResetPlugins = [];
5096
5375
  this.#particleUpdatePlugins = [];
@@ -5101,23 +5380,12 @@
5101
5380
  get count() {
5102
5381
  return this.#array.length;
5103
5382
  }
5383
+ get grid() {
5384
+ return this.#grid;
5385
+ }
5104
5386
  addParticle(position, overrideOptions, group, initializer) {
5105
- const limitMode = this.#container.actualOptions.particles.number.limit.mode, limit = group === undefined ? this.#limit : (this.#groupLimits.get(group) ?? this.#limit), currentCount = this.count;
5106
- if (limit > minLimit) {
5107
- switch (limitMode) {
5108
- case LimitMode.delete: {
5109
- const countToRemove = currentCount + countOffset - limit;
5110
- if (countToRemove > minCount) {
5111
- this.removeQuantity(countToRemove);
5112
- }
5113
- break;
5114
- }
5115
- case LimitMode.wait:
5116
- if (currentCount >= limit) {
5117
- return;
5118
- }
5119
- break;
5120
- }
5387
+ if (this.#checkAndApplyLimits(group, this.count)) {
5388
+ return;
5121
5389
  }
5122
5390
  try {
5123
5391
  const particle = this.#pool.pop() ?? new Particle(this.#pluginManager, this.#container);
@@ -5181,7 +5449,7 @@
5181
5449
  return this.#array[index];
5182
5450
  }
5183
5451
  async init() {
5184
- const container = this.#container, options = container.actualOptions;
5452
+ const container = this.#container;
5185
5453
  this.checkParticlePositionPlugins = [];
5186
5454
  this.#updatePlugins = [];
5187
5455
  this.#particleUpdatePlugins = [];
@@ -5190,59 +5458,16 @@
5190
5458
  this.#postParticleUpdatePlugins = [];
5191
5459
  this.#particleBuckets.clear();
5192
5460
  this.#resetBuckets(container.zLayers);
5193
- this.grid = new SpatialHashGrid(spatialHashGridCellSize * container.retina.pixelRatio);
5194
- for (const plugin of container.plugins) {
5195
- if (plugin.redrawInit) {
5196
- await plugin.redrawInit();
5197
- }
5198
- if (plugin.checkParticlePosition) {
5199
- this.checkParticlePositionPlugins.push(plugin);
5200
- }
5201
- if (plugin.update) {
5202
- this.#updatePlugins.push(plugin);
5203
- }
5204
- if (plugin.particleUpdate) {
5205
- this.#particleUpdatePlugins.push(plugin);
5206
- }
5207
- if (plugin.postUpdate) {
5208
- this.#postUpdatePlugins.push(plugin);
5209
- }
5210
- if (plugin.particleReset) {
5211
- this.#particleResetPlugins.push(plugin);
5212
- }
5213
- if (plugin.postParticleUpdate) {
5214
- this.#postParticleUpdatePlugins.push(plugin);
5215
- }
5216
- }
5217
- await this.#container.initDrawersAndUpdaters();
5218
- for (const drawer of this.#container.effectDrawers.values()) {
5219
- await drawer.init?.(container);
5220
- }
5221
- for (const drawer of this.#container.shapeDrawers.values()) {
5222
- await drawer.init?.(container);
5223
- }
5224
- let handled = false;
5225
- for (const plugin of container.plugins) {
5226
- handled = plugin.particlesInitialization?.() ?? handled;
5227
- if (handled) {
5228
- break;
5229
- }
5230
- }
5231
- if (!handled) {
5232
- const particlesOptions = options.particles, groups = particlesOptions.groups;
5233
- for (const group in groups) {
5234
- const groupOptions = groups[group];
5235
- if (!groupOptions) {
5236
- continue;
5237
- }
5238
- for (let i = this.count, j = 0; j < groupOptions.number.value && i < particlesOptions.number.value; i++, j++) {
5239
- this.addParticle(undefined, groupOptions, group);
5240
- }
5241
- }
5242
- for (let i = this.count; i < particlesOptions.number.value; i++) {
5243
- this.addParticle();
5461
+ this.#grid = new SpatialHashGrid(spatialHashGridCellSize * container.retina.pixelRatio);
5462
+ this.#applyLimits(container.actualOptions.particles);
5463
+ const particlesOptions = container.actualOptions.particles, groups = particlesOptions.groups;
5464
+ for (const group in groups) {
5465
+ const groupData = groups[group];
5466
+ if (groupData) {
5467
+ this.#applyLimits(loadParticlesOptions(this.#pluginManager, this.#container, groupData), group, groupData);
5244
5468
  }
5245
5469
  }
5470
+ await this.#initPlugins();
5246
5471
  }
5247
5472
  push(nb, position, overrideOptions, group) {
5248
5473
  for (let i = 0; i < nb; i++) {
@@ -5257,13 +5482,13 @@
5257
5482
  remove(particle, group, override) {
5258
5483
  this.removeAt(this.#array.indexOf(particle), undefined, group, override);
5259
5484
  }
5260
- removeAt(index, quantity = defaultRemoveQuantity, group, override) {
5485
+ removeAt(index, quantity = defaultRemoveQuantity, group, override, matchGroup = true) {
5261
5486
  if (index < minIndex || index > this.count) {
5262
5487
  return;
5263
5488
  }
5264
5489
  let deleted = 0;
5265
5490
  for (let i = index; deleted < quantity && i < this.count; i++) {
5266
- if (this.#removeParticle(i, group, override)) {
5491
+ if (this.#removeParticle(i, group, override, matchGroup)) {
5267
5492
  i--;
5268
5493
  deleted++;
5269
5494
  }
@@ -5294,7 +5519,7 @@
5294
5519
  this.#resizeFactor = factor;
5295
5520
  }
5296
5521
  update(delta) {
5297
- this.grid.clear();
5522
+ this.#grid.clear();
5298
5523
  for (const plugin of this.#updatePlugins) {
5299
5524
  plugin.update?.(delta);
5300
5525
  }
@@ -5305,7 +5530,7 @@
5305
5530
  this.#updateParticlesPhase2(delta, particlesToDelete);
5306
5531
  if (particlesToDelete.size) {
5307
5532
  for (const particle of particlesToDelete) {
5308
- this.remove(particle);
5533
+ this.remove(particle, particle.group);
5309
5534
  }
5310
5535
  }
5311
5536
  this.#resizeFactor = undefined;
@@ -5316,12 +5541,7 @@
5316
5541
  #applyDensity(options, pluginsCount, group, groupOptions) {
5317
5542
  const numberOptions = options.number;
5318
5543
  if (!numberOptions.density.enable) {
5319
- if (group === undefined) {
5320
- this.#limit = numberOptions.limit.value;
5321
- }
5322
- else if (groupOptions?.number.limit.value ?? numberOptions.limit.value) {
5323
- this.#groupLimits.set(group, groupOptions?.number.limit.value ?? numberOptions.limit.value);
5324
- }
5544
+ this.#applyLimits(options, group, groupOptions);
5325
5545
  return;
5326
5546
  }
5327
5547
  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);
@@ -5329,7 +5549,10 @@
5329
5549
  this.#limit = numberOptions.limit.value * densityFactor;
5330
5550
  }
5331
5551
  else {
5332
- this.#groupLimits.set(group, numberOptions.limit.value * densityFactor);
5552
+ this.#groupLimits.set(group, {
5553
+ limit: numberOptions.limit.value * densityFactor,
5554
+ mode: toEnumValue(LimitMode, numberOptions.limit.mode, LimitMode.delete),
5555
+ });
5333
5556
  }
5334
5557
  if (particlesCount < particlesNumber) {
5335
5558
  this.push(Math.abs(particlesNumber - particlesCount), undefined, options, group);
@@ -5338,6 +5561,55 @@
5338
5561
  this.removeQuantity(particlesCount - particlesNumber, group);
5339
5562
  }
5340
5563
  }
5564
+ #applyLimits(options, group, groupOptions) {
5565
+ if (group === undefined) {
5566
+ this.#limit = options.number.limit.value;
5567
+ const groups = this.#container.actualOptions.particles.groups;
5568
+ for (const existingGroup of this.#groupLimits.keys()) {
5569
+ if (!(existingGroup in groups)) {
5570
+ this.#groupLimits.delete(existingGroup);
5571
+ }
5572
+ }
5573
+ }
5574
+ else {
5575
+ const limitValue = groupOptions?.number?.limit?.value ?? options.number.limit.value;
5576
+ if (limitValue > minLimit) {
5577
+ this.#groupLimits.set(group, {
5578
+ limit: limitValue,
5579
+ mode: toEnumValue(LimitMode, groupOptions?.number?.limit?.mode ?? options.number.limit.mode, LimitMode.delete),
5580
+ });
5581
+ }
5582
+ else {
5583
+ this.#groupLimits.delete(group);
5584
+ }
5585
+ }
5586
+ }
5587
+ #checkAndApplyLimits(group, currentCount) {
5588
+ const globalLimit = this.#limit, globalMode = this.#container.actualOptions.particles.number.limit.mode;
5589
+ if (globalLimit > minLimit && globalMode === LimitMode.wait && currentCount >= globalLimit) {
5590
+ return true;
5591
+ }
5592
+ const groupLimitEntry = group === undefined ? undefined : this.#groupLimits.get(group);
5593
+ if (groupLimitEntry && groupLimitEntry.limit > minLimit && groupLimitEntry.mode === LimitMode.wait) {
5594
+ const groupCount = this.filter(t => t.group === group).length;
5595
+ if (groupCount >= groupLimitEntry.limit) {
5596
+ return true;
5597
+ }
5598
+ }
5599
+ if (groupLimitEntry && groupLimitEntry.limit > minLimit && groupLimitEntry.mode === LimitMode.delete) {
5600
+ const groupCountToRemove = this.filter(t => t.group === group).length + countOffset - groupLimitEntry.limit;
5601
+ if (groupCountToRemove > minCount) {
5602
+ this.removeQuantity(groupCountToRemove, group);
5603
+ }
5604
+ }
5605
+ if (globalLimit > minLimit && globalMode === LimitMode.delete) {
5606
+ const globalCountToRemove = this.count + countOffset - globalLimit;
5607
+ if (globalCountToRemove > minCount) {
5608
+ this.#removeAny(globalCountToRemove);
5609
+ }
5610
+ }
5611
+ return false;
5612
+ }
5341
5613
  #createBuckets(zLayers) {
5342
5614
  const bucketCount = Math.max(Math.floor(zLayers), one);
5343
5615
  return Array.from({ length: bucketCount }, () => []);
@@ -5360,6 +5632,70 @@
5360
5632
  }
5361
5633
  return ((canvasSize.width * canvasSize.height) / (densityOptions.height * densityOptions.width * pxRatio ** squareExp));
5362
5634
  }
5635
+ async #initDrawersAndUpdaters() {
5636
+ const container = this.#container;
5637
+ await container.initDrawersAndUpdaters();
5638
+ for (const drawer of container.effectDrawers.values()) {
5639
+ await drawer.init?.(container);
5640
+ }
5641
+ for (const drawer of container.shapeDrawers.values()) {
5642
+ await drawer.init?.(container);
5643
+ }
5644
+ }
5645
+ async #initPlugins() {
5646
+ await this.#initPluginsArrays();
5647
+ await this.#initDrawersAndUpdaters();
5648
+ let handled = false;
5649
+ const container = this.#container;
5650
+ for (const plugin of container.plugins) {
5651
+ handled = plugin.particlesInitialization?.() ?? handled;
5652
+ if (handled) {
5653
+ break;
5654
+ }
5655
+ }
5656
+ if (handled) {
5657
+ return;
5658
+ }
5659
+ const particlesOptions = container.actualOptions.particles, groups = particlesOptions.groups;
5660
+ for (const group in groups) {
5661
+ const groupOptions = groups[group];
5662
+ if (!groupOptions) {
5663
+ continue;
5664
+ }
5665
+ for (let i = this.count, j = 0; j < groupOptions.number.value && i < particlesOptions.number.value; i++, j++) {
5666
+ this.addParticle(undefined, groupOptions, group);
5667
+ }
5668
+ }
5669
+ for (let i = this.count; i < particlesOptions.number.value; i++) {
5670
+ this.addParticle();
5671
+ }
5672
+ }
5673
+ async #initPluginsArrays() {
5674
+ const container = this.#container;
5675
+ for (const plugin of container.plugins) {
5676
+ if (plugin.redrawInit) {
5677
+ await plugin.redrawInit();
5678
+ }
5679
+ if (plugin.checkParticlePosition) {
5680
+ this.checkParticlePositionPlugins.push(plugin);
5681
+ }
5682
+ if (plugin.update) {
5683
+ this.#updatePlugins.push(plugin);
5684
+ }
5685
+ if (plugin.particleUpdate) {
5686
+ this.#particleUpdatePlugins.push(plugin);
5687
+ }
5688
+ if (plugin.postUpdate) {
5689
+ this.#postUpdatePlugins.push(plugin);
5690
+ }
5691
+ if (plugin.particleReset) {
5692
+ this.#particleResetPlugins.push(plugin);
5693
+ }
5694
+ if (plugin.postParticleUpdate) {
5695
+ this.#postParticleUpdatePlugins.push(plugin);
5696
+ }
5697
+ }
5698
+ }
5363
5699
  #insertParticleIntoBucket(particle) {
5364
5700
  const bucketIndex = this.#getBucketIndex(particle.position.z), bucket = this.#zBuckets[bucketIndex];
5365
5701
  if (!bucket) {
@@ -5368,12 +5704,15 @@
5368
5704
  bucket.push(particle);
5369
5705
  this.#particleBuckets.set(particle.id, bucketIndex);
5370
5706
  }
5371
- #removeParticle(index, group, override) {
5707
+ #removeAny(quantity) {
5708
+ this.removeAt(minIndex, quantity, undefined, undefined, false);
5709
+ }
5710
+ #removeParticle(index, group, override, matchGroup = true) {
5372
5711
  const particle = this.#array[index];
5373
5712
  if (!particle) {
5374
5713
  return false;
5375
5714
  }
5376
- if (particle.group !== group) {
5715
+ if (matchGroup && particle.group !== group) {
5377
5716
  return false;
5378
5717
  }
5379
5718
  this.#array.splice(index, deleteCount);
@@ -5460,7 +5799,7 @@
5460
5799
  particlesToDelete.add(particle);
5461
5800
  continue;
5462
5801
  }
5463
- this.grid.insert(particle);
5802
+ this.#grid.insert(particle);
5464
5803
  }
5465
5804
  return particlesToDelete;
5466
5805
  }
@@ -5532,6 +5871,7 @@
5532
5871
  effectDrawers;
5533
5872
  fpsLimit;
5534
5873
  hdr;
5874
+ hdrMode;
5535
5875
  id;
5536
5876
  pageHidden;
5537
5877
  particleCreatedPlugins;
@@ -5539,6 +5879,7 @@
5539
5879
  particlePositionPlugins;
5540
5880
  particleUpdaters;
5541
5881
  particles;
5882
+ peakNits;
5542
5883
  plugins;
5543
5884
  retina;
5544
5885
  shapeDrawers;
@@ -5569,6 +5910,8 @@
5569
5910
  this.id = Symbol(id);
5570
5911
  this.fpsLimit = 120;
5571
5912
  this.hdr = false;
5913
+ this.hdrMode = HdrMode.standard;
5914
+ this.peakNits = 400;
5572
5915
  this.#smooth = false;
5573
5916
  this.#delay = 0;
5574
5917
  this.#duration = 0;
@@ -5632,7 +5975,6 @@
5632
5975
  this.shapeDrawers = new Map();
5633
5976
  this.particleUpdaters = [];
5634
5977
  this.plugins.length = 0;
5635
- this.#pluginManager.clearPlugins(this);
5636
5978
  this.destroyed = true;
5637
5979
  this.#onDestroy(remove);
5638
5980
  this.dispatchEvent(EventType.containerDestroyed);
@@ -5685,31 +6027,15 @@
5685
6027
  await this.initDrawersAndUpdaters();
5686
6028
  this.#options = loadContainerOptions(this.#pluginManager, this, this.#initialSourceOptions, this.sourceOptions);
5687
6029
  this.actualOptions = loadContainerOptions(this.#pluginManager, this, this.#options);
5688
- this.plugins.length = 0;
5689
- this.particleDestroyedPlugins.length = 0;
5690
- this.particleCreatedPlugins.length = 0;
5691
- this.particlePositionPlugins.length = 0;
5692
- for (const [plugin, containerPlugin] of allContainerPlugins) {
5693
- if (plugin.needsPlugin(this.actualOptions)) {
5694
- this.plugins.push(containerPlugin);
5695
- if (containerPlugin.particleCreated) {
5696
- this.particleCreatedPlugins.push(containerPlugin);
5697
- }
5698
- if (containerPlugin.particleDestroyed) {
5699
- this.particleDestroyedPlugins.push(containerPlugin);
5700
- }
5701
- if (containerPlugin.particlePosition) {
5702
- this.particlePositionPlugins.push(containerPlugin);
5703
- }
5704
- }
5705
- }
6030
+ this.#initPlugins(allContainerPlugins);
5706
6031
  this.retina.init();
5707
6032
  this.canvas.init();
5708
6033
  this.updateActualOptions();
5709
6034
  this.canvas.initBackground();
5710
6035
  this.canvas.resize();
5711
- const { delay, duration, fpsLimit, hdr, smooth, zLayers } = this.actualOptions;
5712
- this.hdr = hdr;
6036
+ const { delay, duration, fpsLimit, smooth, zLayers } = this.actualOptions, hdrOptions = this.actualOptions.hdr;
6037
+ this.hdrMode = toEnumValue(HdrMode, hdrOptions.mode, HdrMode.standard);
6038
+ this.peakNits = hdrOptions.peakNits;
5713
6039
  this.zLayers = zLayers;
5714
6040
  this.#duration = getRangeValue(duration) * millisecondsToSeconds;
5715
6041
  this.#delay = getRangeValue(delay) * millisecondsToSeconds;
@@ -5729,9 +6055,9 @@
5729
6055
  }
5730
6056
  async initDrawersAndUpdaters() {
5731
6057
  const pluginManager = this.#pluginManager;
5732
- this.effectDrawers = await pluginManager.getEffectDrawers(this, true);
5733
- this.shapeDrawers = await pluginManager.getShapeDrawers(this, true);
5734
- this.particleUpdaters = await pluginManager.getUpdaters(this, true);
6058
+ this.effectDrawers = await getItemMapFromInitializer(this, pluginManager.initializers.effects);
6059
+ this.shapeDrawers = await getItemMapFromInitializer(this, pluginManager.initializers.shapes);
6060
+ this.particleUpdaters = await getItemsFromInitializer(this, pluginManager.initializers.updaters);
5735
6061
  }
5736
6062
  pause() {
5737
6063
  if (!guardCheck(this)) {
@@ -5842,6 +6168,27 @@
5842
6168
  }
5843
6169
  return refresh;
5844
6170
  }
6171
+ #initPlugins(allContainerPlugins) {
6172
+ this.plugins.length = 0;
6173
+ this.particleDestroyedPlugins.length = 0;
6174
+ this.particleCreatedPlugins.length = 0;
6175
+ this.particlePositionPlugins.length = 0;
6176
+ for (const [plugin, containerPlugin] of allContainerPlugins) {
6177
+ if (!plugin.needsPlugin(this.actualOptions)) {
6178
+ continue;
6179
+ }
6180
+ this.plugins.push(containerPlugin);
6181
+ if (containerPlugin.particleCreated) {
6182
+ this.particleCreatedPlugins.push(containerPlugin);
6183
+ }
6184
+ if (containerPlugin.particleDestroyed) {
6185
+ this.particleDestroyedPlugins.push(containerPlugin);
6186
+ }
6187
+ if (containerPlugin.particlePosition) {
6188
+ this.particlePositionPlugins.push(containerPlugin);
6189
+ }
6190
+ }
6191
+ }
5845
6192
  #nextFrame(timestamp) {
5846
6193
  try {
5847
6194
  if (!this.#smooth &&
@@ -6118,11 +6465,11 @@
6118
6465
  }
6119
6466
  }
6120
6467
  async #init() {
6121
- const availablePathGenerators = await this.#pluginManager.getPathGenerators?.(this.#container, true);
6122
- if (!availablePathGenerators) {
6468
+ const pluginManager = this.#pluginManager;
6469
+ if (!pluginManager.initializers.pathGenerators) {
6123
6470
  return;
6124
6471
  }
6125
- this.availablePathGenerators = availablePathGenerators;
6472
+ this.availablePathGenerators = await getItemMapFromInitializer(this.#container, pluginManager.initializers.pathGenerators);
6126
6473
  this.pathGenerators = new Map();
6127
6474
  for (const pathGenerator of this.pathGenerators.values()) {
6128
6475
  pathGenerator.init();
@@ -6220,7 +6567,7 @@
6220
6567
  let handled = false;
6221
6568
  const canvas = container.canvas;
6222
6569
  if (trailFill.color) {
6223
- canvas.render.paintBase(getStyleFromRgb(trailFill.color, container.hdr, trailFill.opacity));
6570
+ canvas.render.paintBase(getStyleFromRgb(trailFill.color, container.hdr, trailFill.opacity, container.peakNits, container.hdrMode));
6224
6571
  handled = true;
6225
6572
  }
6226
6573
  else if (trailFill.image) {
@@ -6357,7 +6704,7 @@
6357
6704
  }
6358
6705
  async run() {
6359
6706
  this.reset();
6360
- const minCount = 0, step = 1, yieldEvery = 100, yieldStepModule = 0;
6707
+ const step = 1, yieldEvery = 100, yieldStepModule = 0;
6361
6708
  let iterations = 0;
6362
6709
  while (this.active.length > minCount) {
6363
6710
  this.steps(step);
@@ -6367,7 +6714,6 @@
6367
6714
  }
6368
6715
  }
6369
6716
  steps(steps) {
6370
- const minCount = 0;
6371
6717
  for (let i = 0; i < steps; i++) {
6372
6718
  if (this.active.length <= minCount) {
6373
6719
  continue;
@@ -6434,7 +6780,7 @@
6434
6780
  return newPoint;
6435
6781
  }
6436
6782
  #step() {
6437
- const minCount = 0, randomActive = this.getRandom(minCount, this.active.length);
6783
+ const randomActive = this.getRandom(minCount, this.active.length);
6438
6784
  let foundNewPoint = false;
6439
6785
  for (let tries = 0; tries < this.retries; tries++) {
6440
6786
  const randomActivePointIndex = this.active[randomActive];
@@ -6467,6 +6813,7 @@
6467
6813
  exports.loadMatrixPreset = loadMatrixPreset;
6468
6814
  exports.tsParticles = tsParticles;
6469
6815
 
6470
- }));
6816
+ })(g.__tsParticlesInternals.presets.matrix = g.__tsParticlesInternals.presets.matrix || {});
6817
+ })(typeof globalThis !== "undefined" ? globalThis : typeof window !== "undefined" ? window : self);
6818
+
6471
6819
  Object.assign(globalThis.window || globalThis, { loadMatrixPreset: (globalThis.__tsParticlesInternals.presets.matrix || {}).loadMatrixPreset });
6472
- delete (globalThis.window || globalThis).tsparticlesInternalExports;