@tsparticles/preset-hyperspace 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.hyperspace = global.__tsParticlesInternals.presets.hyperspace || {})));
7
- })(this, (function (exports) { 'use strict';
8
-
9
- const generatedAttribute = "generated", defaultCompositeValue = "source-over", resizeEvent = "resize", visibilityChangeEvent = "visibilitychange", percentDenominator = 100, half = 0.5, millisecondsToSeconds = 1000, originPoint = {
10
- x: 0,
11
- y: 0,
12
- z: 0,
13
- }, defaultTransform = {
14
- a: 1,
15
- b: 0,
16
- c: 0,
17
- d: 1,
18
- }, randomColorValue = "random", double = 2, doublePI = Math.PI * double, defaultFps = 60, generatedTrue = "true", generatedFalse = "false", canvasTag = "canvas", defaultRetryCount = 0, squareExp = 2, spatialHashGridCellSize = 100, defaultRemoveQuantity = 1, defaultRatio = 1, defaultReduceFactor = 1, inverseFactorNumerator = 1, rgbMax = 255, hMax = 360, sMax = 100, lMax = 100, hMin = 0, sMin = 0, hPhase = 60, empty = 0, quarter = 0.25, threeQuarter = half + quarter, minVelocity = 0, minDistance = 0, defaultTransformValue = 1, minimumSize = 0, zIndexFactorOffset = 1, defaultOpacity$1 = 1, removeDeleteCount = 1, removeMinIndex = 0, defaultFpsLimit = 120, minFpsLimit = 0, canvasFirstIndex = 0, loadRandomFactor = 10000, loadMinIndex = 0, one = 1, none = 0, decayOffset = 1, tryCountIncrement = 1, minZ = 0, minLimit = 0, countOffset = 1, minCount = 0, minIndex = 0, defaultDensityFactor = 1, deleteCount = 1, defaultAngle = 0, identity$1 = 1, minStrokeWidth = 0, lFactor = 1, lMin = 0, maxNits = 400, triple = 3, sextuple = 6, sNormalizedOffset = 1, phaseNumerator = 1, defaultRgbMin = 0, defaultVelocity = 0, defaultLoops = 0, defaultTime = 0, defaultZoom = 1;
1
+ (function(g){g.__tsParticlesInternals=g.__tsParticlesInternals||{};g.__tsParticlesInternals.bundles=g.__tsParticlesInternals.bundles||{};g.__tsParticlesInternals.effects=g.__tsParticlesInternals.effects||{};g.__tsParticlesInternals.engine=g.__tsParticlesInternals.engine||{};g.__tsParticlesInternals.interactions=g.__tsParticlesInternals.interactions||{};g.__tsParticlesInternals.palettes=g.__tsParticlesInternals.palettes||{};g.__tsParticlesInternals.paths=g.__tsParticlesInternals.paths||{};g.__tsParticlesInternals.plugins=g.__tsParticlesInternals.plugins||{};g.__tsParticlesInternals.plugins=g.__tsParticlesInternals.plugins||{};g.__tsParticlesInternals.plugins.emittersShapes=g.__tsParticlesInternals.plugins.emittersShapes||{};g.__tsParticlesInternals.presets=g.__tsParticlesInternals.presets||{};g.__tsParticlesInternals.shapes=g.__tsParticlesInternals.shapes||{};g.__tsParticlesInternals.updaters=g.__tsParticlesInternals.updaters||{};g.__tsParticlesInternals.utils=g.__tsParticlesInternals.utils||{};g.__tsParticlesInternals.canvas=g.__tsParticlesInternals.canvas||{};g.__tsParticlesInternals.canvas=g.__tsParticlesInternals.canvas||{};g.__tsParticlesInternals.canvas.utils=g.__tsParticlesInternals.canvas.utils||{};g.__tsParticlesInternals.path=g.__tsParticlesInternals.path||{};g.__tsParticlesInternals.path=g.__tsParticlesInternals.path||{};g.__tsParticlesInternals.path.utils=g.__tsParticlesInternals.path.utils||{};var __tsProxyFactory=typeof Proxy!=="undefined"?function(obj){return new Proxy(obj,{get:function(target,key){if(!(key in target)){target[key]={};}return target[key];}});}:function(obj){return obj;};g.__tsParticlesInternals.bundles=__tsProxyFactory(g.__tsParticlesInternals.bundles);g.__tsParticlesInternals.effects=__tsProxyFactory(g.__tsParticlesInternals.effects);g.__tsParticlesInternals.interactions=__tsProxyFactory(g.__tsParticlesInternals.interactions);g.__tsParticlesInternals.palettes=__tsProxyFactory(g.__tsParticlesInternals.palettes);g.__tsParticlesInternals.paths=__tsProxyFactory(g.__tsParticlesInternals.paths);g.__tsParticlesInternals.plugins=__tsProxyFactory(g.__tsParticlesInternals.plugins);g.__tsParticlesInternals.plugins.emittersShapes=__tsProxyFactory(g.__tsParticlesInternals.plugins.emittersShapes);g.__tsParticlesInternals.presets=__tsProxyFactory(g.__tsParticlesInternals.presets);g.__tsParticlesInternals.shapes=__tsProxyFactory(g.__tsParticlesInternals.shapes);g.__tsParticlesInternals.updaters=__tsProxyFactory(g.__tsParticlesInternals.updaters);g.__tsParticlesInternals.utils=__tsProxyFactory(g.__tsParticlesInternals.utils);g.__tsParticlesInternals.canvas=__tsProxyFactory(g.__tsParticlesInternals.canvas);g.__tsParticlesInternals.path=__tsProxyFactory(g.__tsParticlesInternals.path);})(typeof globalThis!=="undefined"?globalThis:typeof window!=="undefined"?window:this);
2
+ (function (g) {
3
+ /* Preset v4.5.0 */
4
+ g.__tsParticlesInternals = g.__tsParticlesInternals || {};
5
+ g.__tsParticlesInternals.presets = g.__tsParticlesInternals.presets || {};
6
+ (function (exports) {
7
+ 'use strict';
8
+
9
+ const errorPrefix = "tsParticles - Error", codedErrorPattern = /^\[tsParticles Error (TSP-\d+)\]\s*/, fullMatchIndex = 0, codeIndex = 1;
10
+ const wrap = (fn) => (...args) => {
11
+ fn(...args);
12
+ }, _logger = {
13
+ debug: wrap(console.debug),
14
+ error: (message, ...optionalParams) => {
15
+ if (typeof message === "string") {
16
+ const match = codedErrorPattern.exec(message);
17
+ if (match?.[codeIndex]) {
18
+ console.error(`tsParticles - ${match[codeIndex]} - ${message.slice(match[fullMatchIndex].length)}`, ...optionalParams);
19
+ return;
20
+ }
21
+ }
22
+ console.error(`${errorPrefix} - ${message}`, ...optionalParams);
23
+ },
24
+ info: wrap(console.info),
25
+ log: wrap(console.log),
26
+ trace: wrap(console.trace),
27
+ verbose: wrap(console.log),
28
+ warning: wrap(console.warn),
29
+ };
30
+ function getLogger() {
31
+ return _logger;
32
+ }
19
33
 
20
34
  var MoveDirection;
21
35
  (function (MoveDirection) {
@@ -32,6 +46,17 @@
32
46
  MoveDirection["inside"] = "inside";
33
47
  })(MoveDirection || (MoveDirection = {}));
34
48
 
49
+ const generatedAttribute = "generated", fullPercent = "100%", defaultCompositeValue = "source-over", resizeEvent = "resize", visibilityChangeEvent = "visibilitychange", percentDenominator = 100, half = 0.5, millisecondsToSeconds = 1000, originPoint = {
50
+ x: 0,
51
+ y: 0,
52
+ z: 0,
53
+ }, defaultTransform = {
54
+ a: 1,
55
+ b: 0,
56
+ c: 0,
57
+ d: 1,
58
+ }, randomColorValue = "random", double = 2, doublePI = Math.PI * double, defaultFps = 60, defaultAlpha = 1, generatedTrue = "true", generatedFalse = "false", canvasTag = "canvas", defaultRetryCount = 0, squareExp = 2, spatialHashGridCellSize = 100, defaultRemoveQuantity = 1, defaultRatio = 1, defaultReduceFactor = 1, inverseFactorNumerator = 1, rgbMax = 255, hMax = 360, sMax = 100, lMax = 100, hMin = 0, sMin = 0, hPhase = 60, empty = 0, quarter = 0.25, threeQuarter = half + quarter, minVelocity = 0, minDistance = 0, minRadius = 0, defaultTransformValue = 1, minimumSize = 0, zIndexFactorOffset = 1, defaultOpacity$1 = 1, removeDeleteCount = 1, removeMinIndex = 0, defaultFpsLimit = 120, minFpsLimit = 0, canvasFirstIndex = 0, loadRandomFactor = 10000, loadMinIndex = 0, one = 1, none = 0, decayOffset = 1, tryCountIncrement = 1, minZ = 0, minLimit = 0, countOffset = 1, minCount = 0, minIndex = 0, defaultDensityFactor = 1, deleteCount = 1, defaultAngle = 0, identity$1 = 1, minStrokeWidth = 0, lFactor = 1, lMin = 0, maxNits = 400, triple = 3, sextuple = 6, sNormalizedOffset = 1, phaseNumerator = 1, defaultRgbMin = 0, defaultVelocity = 0, defaultLoops = 0, defaultTime = 0, defaultZoom = 1;
59
+
35
60
  function getZ(source) {
36
61
  return "z" in source ? source.z : originPoint.z;
37
62
  }
@@ -147,6 +172,12 @@
147
172
  function isNumber(arg) {
148
173
  return typeof arg === "number";
149
174
  }
175
+ function isEnumValue(enumObject, arg) {
176
+ return Object.values(enumObject).some(enumValue => enumValue === arg);
177
+ }
178
+ function toEnumValue(enumObject, arg, defaultValue) {
179
+ return isEnumValue(enumObject, arg) ? arg : defaultValue;
180
+ }
150
181
  function isObject(arg) {
151
182
  return typeof arg === "object" && arg !== null;
152
183
  }
@@ -283,11 +314,61 @@
283
314
  };
284
315
  }
285
316
  function parseAlpha(input) {
286
- const defaultAlpha = 1;
287
317
  if (!input) {
288
318
  return defaultAlpha;
289
319
  }
290
- return input.endsWith("%") ? parseFloat(input) / percentDenominator : parseFloat(input);
320
+ return input.endsWith("%") ? Number.parseFloat(input) / percentDenominator : Number.parseFloat(input);
321
+ }
322
+
323
+ const ErrorCodes$2 = {
324
+ engineVersionMismatch: "TSP-1001",
325
+ particlePositionNotFound: "TSP-1002",
326
+ pluginRegisterAfterLoad: "TSP-1003",
327
+ offscreenCanvasUnsupported: "TSP-1101",
328
+ offscreenCanvasTransferFailed: "TSP-1102",
329
+ hdrEnableInvalid: "TSP-1201",
330
+ hdrModeInvalid: "TSP-1202",
331
+ hdrPeakNitsInvalid: "TSP-1203",
332
+ };
333
+
334
+ const messages = {
335
+ [ErrorCodes$2.engineVersionMismatch]: "The tsParticles version is different from the loaded plugins version. Engine version: {0}. Plugin version: {1}",
336
+ [ErrorCodes$2.particlePositionNotFound]: "a valid position cannot be found for particle",
337
+ [ErrorCodes$2.pluginRegisterAfterLoad]: "Register plugins can only be done before calling tsParticles.load()",
338
+ [ErrorCodes$2.offscreenCanvasUnsupported]: "OffscreenCanvas is required but not supported by this browser",
339
+ [ErrorCodes$2.offscreenCanvasTransferFailed]: "OffscreenCanvas transfer failed",
340
+ [ErrorCodes$2.hdrEnableInvalid]: 'Invalid HDR "enable" value: expected a boolean, got "{0}"',
341
+ [ErrorCodes$2.hdrModeInvalid]: 'Invalid HDR "mode" value: expected one of {0}, got "{1}"',
342
+ [ErrorCodes$2.hdrPeakNitsInvalid]: 'Invalid HDR "peakNits" value: expected a positive number, got "{0}"',
343
+ };
344
+
345
+ let registeredMessages;
346
+ const ensureRegisteredMessages = () => {
347
+ registeredMessages ??= new Map(Object.entries(messages));
348
+ return registeredMessages;
349
+ }, toStringValue$1 = (value) => String(value), format = (template, args) => {
350
+ return template.replace(/\{(\d+)\}/g, (match, index) => {
351
+ const arg = args[Number(index)];
352
+ return arg === undefined ? match : toStringValue$1(arg);
353
+ });
354
+ };
355
+ function addErrorMessages(extraMessages) {
356
+ if (typeof process !== "undefined" && process.env.NODE_ENV === "production") {
357
+ return;
358
+ }
359
+ const catalog = ensureRegisteredMessages();
360
+ for (const [code, message] of Object.entries(extraMessages)) {
361
+ if (message !== undefined) {
362
+ catalog.set(code, message);
363
+ }
364
+ }
365
+ }
366
+ function getErrorMessage(code, ...args) {
367
+ if (typeof process !== "undefined" && process.env.NODE_ENV === "production") {
368
+ return `[tsParticles Error ${code}] https://particles.js.org/errors/#${code}`;
369
+ }
370
+ const template = ensureRegisteredMessages().get(code) ?? `Unknown error code ${code}`;
371
+ return format(template, args);
291
372
  }
292
373
 
293
374
  var OutModeDirection;
@@ -304,7 +385,6 @@
304
385
  PixelMode["percent"] = "percent";
305
386
  })(PixelMode || (PixelMode = {}));
306
387
 
307
- const minRadius = 0;
308
388
  function isForbiddenKey(key) {
309
389
  return key === "__proto__" || key === "constructor" || key === "prototype";
310
390
  }
@@ -500,22 +580,84 @@
500
580
  element.removeEventListener(event, handler, removeOptions);
501
581
  }
502
582
  }
503
- async function getItemsFromInitializer(container, map, initializers, force = false) {
504
- let res = map.get(container);
505
- if (!res || force) {
506
- res = await Promise.all([...initializers.values()].map(t => t(container)));
507
- map.set(container, res);
583
+ async function getItemsFromInitializer(container, initializers) {
584
+ return await Promise.all([...initializers.values()].map(t => t(container)));
585
+ }
586
+ async function getItemMapFromInitializer(container, initializers) {
587
+ const entries = await Promise.all([...initializers.entries()].map(([key, initializer]) => initializer(container).then(item => [key, item])));
588
+ return new Map(entries);
589
+ }
590
+ async function getDataFromUrl(data) {
591
+ const url = itemFromSingleOrMultiple(data.url, data.index);
592
+ if (!url) {
593
+ return data.fallback;
508
594
  }
509
- return res;
595
+ try {
596
+ const response = await fetch(url);
597
+ if (response.ok) {
598
+ const current = (await response.json());
599
+ if (isSourceOptionsValue(current)) {
600
+ return current;
601
+ }
602
+ getLogger().error("invalid configuration data while retrieving config file");
603
+ }
604
+ else {
605
+ getLogger().error(`${response.status.toString()} while retrieving config file`);
606
+ }
607
+ }
608
+ catch (error) {
609
+ getLogger().error(`error while retrieving config file: ${error}`);
610
+ }
611
+ return data.fallback;
510
612
  }
511
- async function getItemMapFromInitializer(container, map, initializers, force = false) {
512
- let res = map.get(container);
513
- if (!res || force) {
514
- const entries = await Promise.all([...initializers.entries()].map(([key, initializer]) => initializer(container).then(item => [key, item])));
515
- res = new Map(entries);
516
- map.set(container, res);
613
+ function isSourceOptionsValue(value) {
614
+ if (isArray(value)) {
615
+ return value.every((entry) => isObject(entry) && !isArray(entry));
517
616
  }
518
- return res;
617
+ return isObject(value) && !isArray(value);
618
+ }
619
+ function getCanvasFromContainer(domContainer) {
620
+ let canvasEl;
621
+ const documentSafe = safeDocument(), isCanvas = domContainer instanceof HTMLCanvasElement || domContainer.tagName.toLowerCase() === canvasTag;
622
+ if (isCanvas) {
623
+ canvasEl = domContainer;
624
+ canvasEl.dataset[generatedAttribute] ??= generatedFalse;
625
+ if (canvasEl.dataset[generatedAttribute] === generatedTrue) {
626
+ canvasEl.style.width ||= fullPercent;
627
+ canvasEl.style.height ||= fullPercent;
628
+ canvasEl.style.pointerEvents = "none";
629
+ canvasEl.style.setProperty("pointer-events", "none");
630
+ }
631
+ }
632
+ else {
633
+ const existingCanvases = domContainer.getElementsByTagName(canvasTag), foundCanvas = existingCanvases.item(canvasFirstIndex);
634
+ if (foundCanvas) {
635
+ canvasEl = foundCanvas;
636
+ canvasEl.dataset[generatedAttribute] = generatedFalse;
637
+ }
638
+ else {
639
+ canvasEl = documentSafe.createElement(canvasTag);
640
+ canvasEl.dataset[generatedAttribute] = generatedTrue;
641
+ domContainer.appendChild(canvasEl);
642
+ }
643
+ canvasEl.style.width ||= fullPercent;
644
+ canvasEl.style.height ||= fullPercent;
645
+ canvasEl.style.pointerEvents = "none";
646
+ canvasEl.style.setProperty("pointer-events", "none");
647
+ }
648
+ return canvasEl;
649
+ }
650
+ function getDomContainer(id, source) {
651
+ const documentSafe = safeDocument();
652
+ let domContainer = source ?? documentSafe.getElementById(id);
653
+ if (domContainer) {
654
+ return domContainer;
655
+ }
656
+ domContainer = documentSafe.createElement("canvas");
657
+ domContainer.id = id;
658
+ domContainer.dataset[generatedAttribute] = generatedTrue;
659
+ documentSafe.body.append(domContainer);
660
+ return domContainer;
519
661
  }
520
662
 
521
663
  class EventDispatcher {
@@ -586,7 +728,6 @@
586
728
  class PluginManager {
587
729
  colorManagers = new Map();
588
730
  easingFunctions = new Map();
589
- effectDrawers = new Map();
590
731
  initializers = {
591
732
  effects: new Map(),
592
733
  shapes: new Map(),
@@ -595,8 +736,6 @@
595
736
  palettes = new Map();
596
737
  plugins = [];
597
738
  presets = new Map();
598
- shapeDrawers = new Map();
599
- updaters = new Map();
600
739
  #allLoadersSet = new Set();
601
740
  #configs = new Map();
602
741
  #engine;
@@ -614,57 +753,79 @@
614
753
  }
615
754
  return res;
616
755
  }
756
+ get initialized() {
757
+ return this.#initialized;
758
+ }
617
759
  addColorManager(name, manager) {
760
+ if (this.#initialized) {
761
+ return;
762
+ }
618
763
  this.colorManagers.set(name, manager);
619
764
  }
620
765
  addConfig(config) {
766
+ if (this.#initialized) {
767
+ return;
768
+ }
621
769
  const key = config.key ?? config.name ?? "default";
622
770
  this.#configs.set(key, config);
623
771
  this.#engine.dispatchEvent(EventType.configAdded, { data: { name: key, config } });
624
772
  }
625
773
  addEasing(name, easing) {
774
+ if (this.#initialized) {
775
+ return;
776
+ }
626
777
  if (this.easingFunctions.get(name)) {
627
778
  return;
628
779
  }
629
780
  this.easingFunctions.set(name, easing);
630
781
  }
631
782
  addEffect(effect, drawer) {
783
+ if (this.#initialized) {
784
+ return;
785
+ }
632
786
  this.initializers.effects.set(effect, drawer);
633
787
  }
634
788
  addPalette(name, palette) {
789
+ if (this.#initialized) {
790
+ return;
791
+ }
635
792
  this.palettes.set(name, palette);
636
793
  }
637
794
  addParticleUpdater(name, updaterInitializer) {
795
+ if (this.#initialized) {
796
+ return;
797
+ }
638
798
  this.initializers.updaters.set(name, updaterInitializer);
639
799
  }
640
800
  addPlugin(plugin) {
801
+ if (this.#initialized) {
802
+ return;
803
+ }
641
804
  if (this.getPlugin(plugin.id)) {
642
805
  return;
643
806
  }
644
807
  this.plugins.push(plugin);
645
808
  }
646
809
  addPreset(preset, options, override = false) {
810
+ if (this.#initialized) {
811
+ return;
812
+ }
647
813
  if (!(override || !this.getPreset(preset))) {
648
814
  return;
649
815
  }
650
816
  this.presets.set(preset, options);
651
817
  }
652
818
  addShape(shapes, drawer) {
819
+ if (this.#initialized) {
820
+ return;
821
+ }
653
822
  for (const shape of shapes) {
654
823
  this.initializers.shapes.set(shape, drawer);
655
824
  }
656
825
  }
657
- clearPlugins(container) {
658
- this.effectDrawers.delete(container);
659
- this.shapeDrawers.delete(container);
660
- this.updaters.delete(container);
661
- }
662
826
  getEasing(name) {
663
827
  return this.easingFunctions.get(name) ?? ((value) => value);
664
828
  }
665
- getEffectDrawers(container, force = false) {
666
- return getItemMapFromInitializer(container, this.effectDrawers, this.initializers.effects, force);
667
- }
668
829
  getPalette(name) {
669
830
  return this.palettes.get(name);
670
831
  }
@@ -674,12 +835,6 @@
674
835
  getPreset(preset) {
675
836
  return this.presets.get(preset);
676
837
  }
677
- async getShapeDrawers(container, force = false) {
678
- return getItemMapFromInitializer(container, this.shapeDrawers, this.initializers.shapes, force);
679
- }
680
- async getUpdaters(container, force = false) {
681
- return getItemsFromInitializer(container, this.updaters, this.initializers.updaters, force);
682
- }
683
838
  async init() {
684
839
  if (this.#initialized || this.#isRunningLoaders) {
685
840
  return;
@@ -698,16 +853,9 @@
698
853
  this.#initialized = true;
699
854
  }
700
855
  }
701
- loadParticlesOptions(container, options, ...sourceOptions) {
702
- const updaters = this.updaters.get(container);
703
- if (!updaters) {
704
- return;
705
- }
706
- updaters.forEach(updater => updater.loadOptions?.(options, ...sourceOptions));
707
- }
708
856
  async register(...loaders) {
709
857
  if (this.#initialized) {
710
- throw new Error("Register plugins can only be done before calling tsParticles.load()");
858
+ throw new Error(getErrorMessage(ErrorCodes$2.pluginRegisterAfterLoad));
711
859
  }
712
860
  for (const loader of loaders) {
713
861
  if (this.#isRunningLoaders) {
@@ -719,88 +867,15 @@
719
867
  }
720
868
  }
721
869
  async #runLoader(loader, executed, allLoaders) {
722
- if (executed.has(loader))
870
+ if (executed.has(loader)) {
723
871
  return;
872
+ }
724
873
  executed.add(loader);
725
874
  allLoaders.add(loader);
726
875
  await loader(this.#engine);
727
876
  }
728
877
  }
729
878
 
730
- const errorPrefix = "tsParticles - Error";
731
- const wrap = (fn) => (...args) => {
732
- fn(...args);
733
- }, _logger = {
734
- debug: wrap(console.debug),
735
- error: (message, ...optionalParams) => {
736
- console.error(`${errorPrefix} - ${message}`, ...optionalParams);
737
- },
738
- info: wrap(console.info),
739
- log: wrap(console.log),
740
- trace: wrap(console.trace),
741
- verbose: wrap(console.log),
742
- warning: wrap(console.warn),
743
- };
744
- function getLogger() {
745
- return _logger;
746
- }
747
-
748
- const fullPercent = "100%";
749
- async function getDataFromUrl(data) {
750
- const url = itemFromSingleOrMultiple(data.url, data.index);
751
- if (!url) {
752
- return data.fallback;
753
- }
754
- const response = await fetch(url);
755
- if (response.ok) {
756
- return (await response.json());
757
- }
758
- getLogger().error(`${response.status.toString()} while retrieving config file`);
759
- return data.fallback;
760
- }
761
- const getCanvasFromContainer = (domContainer) => {
762
- const documentSafe = safeDocument();
763
- let canvasEl;
764
- const isCanvas = domContainer instanceof HTMLCanvasElement || domContainer.tagName.toLowerCase() === canvasTag;
765
- if (isCanvas) {
766
- canvasEl = domContainer;
767
- canvasEl.dataset[generatedAttribute] ??= generatedFalse;
768
- if (canvasEl.dataset[generatedAttribute] === generatedTrue) {
769
- canvasEl.style.width ||= fullPercent;
770
- canvasEl.style.height ||= fullPercent;
771
- canvasEl.style.pointerEvents = "none";
772
- canvasEl.style.setProperty("pointer-events", "none");
773
- }
774
- }
775
- else {
776
- const existingCanvases = domContainer.getElementsByTagName(canvasTag), foundCanvas = existingCanvases.item(canvasFirstIndex);
777
- if (foundCanvas) {
778
- canvasEl = foundCanvas;
779
- canvasEl.dataset[generatedAttribute] = generatedFalse;
780
- }
781
- else {
782
- canvasEl = documentSafe.createElement(canvasTag);
783
- canvasEl.dataset[generatedAttribute] = generatedTrue;
784
- domContainer.appendChild(canvasEl);
785
- }
786
- canvasEl.style.width ||= fullPercent;
787
- canvasEl.style.height ||= fullPercent;
788
- canvasEl.style.pointerEvents = "none";
789
- canvasEl.style.setProperty("pointer-events", "none");
790
- }
791
- return canvasEl;
792
- }, getDomContainer = (id, source) => {
793
- const documentSafe = safeDocument();
794
- let domContainer = source ?? documentSafe.getElementById(id);
795
- if (domContainer) {
796
- return domContainer;
797
- }
798
- domContainer = documentSafe.createElement("canvas");
799
- domContainer.id = id;
800
- domContainer.dataset[generatedAttribute] = generatedTrue;
801
- documentSafe.body.append(domContainer);
802
- return domContainer;
803
- };
804
879
  class Engine {
805
880
  pluginManager = new PluginManager(this);
806
881
  #domArray = [];
@@ -810,7 +885,7 @@
810
885
  return this.#domArray;
811
886
  }
812
887
  get version() {
813
- return "4.3.2";
888
+ return "4.5.0";
814
889
  }
815
890
  addEventListener(type, listener) {
816
891
  this.#eventDispatcher.addEventListener(type, listener);
@@ -819,7 +894,7 @@
819
894
  if (this.version === pluginVersion) {
820
895
  return;
821
896
  }
822
- throw new Error(`The tsParticles version is different from the loaded plugins version. Engine version: ${this.version}. Plugin version: ${pluginVersion}`);
897
+ throw new Error(getErrorMessage(ErrorCodes$2.engineVersionMismatch, this.version, pluginVersion));
823
898
  }
824
899
  dispatchEvent(type, args) {
825
900
  this.#eventDispatcher.dispatchEvent(type, args);
@@ -891,6 +966,10 @@
891
966
  }
892
967
 
893
968
  function initEngine() {
969
+ const existing = globalThis.tsParticles;
970
+ if (existing?.pluginManager) {
971
+ return existing;
972
+ }
894
973
  return new Engine();
895
974
  }
896
975
 
@@ -988,6 +1067,15 @@
988
1067
  AnimationMode["random"] = "random";
989
1068
  })(AnimationMode || (AnimationMode = {}));
990
1069
 
1070
+ var HdrMode;
1071
+ (function (HdrMode) {
1072
+ HdrMode["standard"] = "standard";
1073
+ HdrMode["natural"] = "natural";
1074
+ HdrMode["vivid"] = "vivid";
1075
+ HdrMode["cinematic"] = "cinematic";
1076
+ HdrMode["dynamic"] = "dynamic";
1077
+ })(HdrMode || (HdrMode = {}));
1078
+
991
1079
  var LimitMode;
992
1080
  (function (LimitMode) {
993
1081
  LimitMode["delete"] = "delete";
@@ -1055,20 +1143,6 @@
1055
1143
  DrawLayer[DrawLayer["Foreground"] = 7] = "Foreground";
1056
1144
  })(DrawLayer || (DrawLayer = {}));
1057
1145
 
1058
- class OptionLoader {
1059
- load(data) {
1060
- if (isNull(data)) {
1061
- return;
1062
- }
1063
- this.doLoad(data);
1064
- }
1065
- }
1066
- function loadOptions(options, ...sourceOptionsArr) {
1067
- for (const sourceOptions of sourceOptionsArr) {
1068
- options.load(sourceOptions);
1069
- }
1070
- }
1071
-
1072
1146
  function loadProperty(obj, key, value) {
1073
1147
  if (value !== undefined) {
1074
1148
  obj[key] = value;
@@ -1100,6 +1174,20 @@
1100
1174
  }
1101
1175
  }
1102
1176
 
1177
+ class OptionLoader {
1178
+ load(data) {
1179
+ if (isNull(data)) {
1180
+ return;
1181
+ }
1182
+ this.doLoad(data);
1183
+ }
1184
+ }
1185
+ function loadOptions(options, ...sourceOptionsArr) {
1186
+ for (const sourceOptions of sourceOptionsArr) {
1187
+ options.load(sourceOptions);
1188
+ }
1189
+ }
1190
+
1103
1191
  class AnimationOptions extends OptionLoader {
1104
1192
  count = 0;
1105
1193
  decay = 0;
@@ -1243,6 +1331,28 @@
1243
1331
  }
1244
1332
  }
1245
1333
 
1334
+ const defaultPeakNits = 400, minPeakNits = 0, toStringValue = (value) => String(value);
1335
+ class HDROptions extends OptionLoader {
1336
+ enable = true;
1337
+ mode = HdrMode.standard;
1338
+ peakNits = defaultPeakNits;
1339
+ doLoad(data) {
1340
+ if (data.enable !== undefined && !isBoolean(data.enable)) {
1341
+ throw new Error(getErrorMessage(ErrorCodes$2.hdrEnableInvalid, String(data.enable)));
1342
+ }
1343
+ if (data.mode !== undefined && !isEnumValue(HdrMode, data.mode)) {
1344
+ throw new Error(getErrorMessage(ErrorCodes$2.hdrModeInvalid, Object.values(HdrMode).join(", "), toStringValue(data.mode)));
1345
+ }
1346
+ if (data.peakNits !== undefined &&
1347
+ (!isNumber(data.peakNits) || !Number.isFinite(data.peakNits) || data.peakNits <= minPeakNits)) {
1348
+ throw new Error(getErrorMessage(ErrorCodes$2.hdrPeakNitsInvalid, String(data.peakNits)));
1349
+ }
1350
+ loadProperty(this, "enable", data.enable);
1351
+ loadProperty(this, "mode", data.mode);
1352
+ loadProperty(this, "peakNits", data.peakNits);
1353
+ }
1354
+ }
1355
+
1246
1356
  class ResizeEvent extends OptionLoader {
1247
1357
  delay = 0.5;
1248
1358
  enable = true;
@@ -1613,12 +1723,10 @@
1613
1723
  plugin.loadParticlesOptions(this.#container, this, data);
1614
1724
  }
1615
1725
  }
1616
- const updaters = this.#pluginManager.updaters.get(this.#container);
1617
- if (updaters) {
1618
- for (const updater of updaters) {
1619
- if (updater.loadOptions) {
1620
- updater.loadOptions(this, data);
1621
- }
1726
+ const updaters = this.#container.particleUpdaters;
1727
+ for (const updater of updaters) {
1728
+ if (updater.loadOptions) {
1729
+ updater.loadOptions(this, data);
1622
1730
  }
1623
1731
  }
1624
1732
  }
@@ -1686,7 +1794,7 @@
1686
1794
  duration = 0;
1687
1795
  fpsLimit = 120;
1688
1796
  fullScreen;
1689
- hdr = true;
1797
+ hdr;
1690
1798
  key;
1691
1799
  name;
1692
1800
  palette;
@@ -1706,6 +1814,7 @@
1706
1814
  this.#container = container;
1707
1815
  this.background = new Background();
1708
1816
  this.fullScreen = new FullScreen();
1817
+ this.hdr = new HDROptions();
1709
1818
  this.particles = loadParticlesOptions(this.#pluginManager, this.#container);
1710
1819
  this.resize = new ResizeEvent();
1711
1820
  }
@@ -1728,7 +1837,15 @@
1728
1837
  loadProperty(this, "detectRetina", data.detectRetina);
1729
1838
  loadRangeProperty(this, "duration", data.duration);
1730
1839
  loadProperty(this, "fpsLimit", data.fpsLimit);
1731
- loadProperty(this, "hdr", data.hdr);
1840
+ const hdrData = data.hdr;
1841
+ if (isBoolean(hdrData)) {
1842
+ this.hdr.enable = hdrData;
1843
+ this.hdr.mode = HdrMode.standard;
1844
+ this.hdr.peakNits = 400;
1845
+ }
1846
+ else {
1847
+ this.hdr.load(hdrData);
1848
+ }
1732
1849
  loadProperty(this, "pauseOnBlur", data.pauseOnBlur);
1733
1850
  loadProperty(this, "pauseOnOutsideViewport", data.pauseOnOutsideViewport);
1734
1851
  loadProperty(this, "zLayers", data.zLayers);
@@ -1771,7 +1888,7 @@
1771
1888
  }
1772
1889
  }
1773
1890
 
1774
- const styleCache = new Map(), maxStyleCacheSize = 2000, rgbFixedPrecision = 2, hslFixedPrecision = 2, hdrRgbFixedPrecision = 4, hdrHslFixedPrecision = 4, sdrReferenceWhiteNits = 203, hdrAnimationScale = sdrReferenceWhiteNits / maxNits;
1891
+ const styleCache = new Map(), maxStyleCacheSize = 2000, rgbFixedPrecision = 2, hslFixedPrecision = 2, hdrRgbFixedPrecision = 4, hdrHslFixedPrecision = 4, sdrReferenceWhiteNits = 203, acesA = 2.51, acesB = 0.03, acesC = 2.43, acesD = 0.59, acesE = 0.14, saturationBoost = 1.15, lightnessBoost = 1.05, temperatureR = 1.05, temperatureB = 0.95, contrastFactor = 1.1, luminanceR = 0.2126, luminanceG = 0.7152, luminanceB = 0.0722, dynamicLuminanceFactor = 2, channelCount = 3;
1775
1892
  function getCachedStyle(key, generator) {
1776
1893
  let cached = styleCache.get(key);
1777
1894
  if (!cached) {
@@ -1783,6 +1900,42 @@
1783
1900
  }
1784
1901
  return cached;
1785
1902
  }
1903
+ function acesFilmic(x) {
1904
+ return clamp((x * (acesA * x + acesB)) / (x * (acesC * x + acesD) + acesE), none, one);
1905
+ }
1906
+ function applyHdrModeAdjustments(r, g, b, mode, maxChannel) {
1907
+ switch (mode) {
1908
+ case HdrMode.vivid: {
1909
+ const avg = (r + g + b) / channelCount;
1910
+ return {
1911
+ b: clamp(clamp(avg + (b - avg) * saturationBoost, none, maxChannel) * lightnessBoost, none, maxChannel),
1912
+ g: clamp(clamp(avg + (g - avg) * saturationBoost, none, maxChannel) * lightnessBoost, none, maxChannel),
1913
+ r: clamp(clamp(avg + (r - avg) * saturationBoost, none, maxChannel) * lightnessBoost, none, maxChannel),
1914
+ };
1915
+ }
1916
+ case HdrMode.cinematic: {
1917
+ const tempR = r * temperatureR, tempB = b * temperatureB, avg = (tempR + g + tempB) / channelCount;
1918
+ return {
1919
+ b: clamp(avg + (tempB - avg) * contrastFactor, none, maxChannel),
1920
+ g: clamp(avg + (g - avg) * contrastFactor, none, maxChannel),
1921
+ r: clamp(avg + (tempR - avg) * contrastFactor, none, maxChannel),
1922
+ };
1923
+ }
1924
+ case HdrMode.dynamic: {
1925
+ const luminance = luminanceR * r + luminanceG * g + luminanceB * b, vividWeight = Math.min(one, luminance * dynamicLuminanceFactor), naturalWeight = one - vividWeight, avg = (r + g + b) / channelCount, vividR = clamp(avg + (r - avg) * saturationBoost, none, maxChannel) * lightnessBoost, vividG = clamp(avg + (g - avg) * saturationBoost, none, maxChannel) * lightnessBoost, vividB = clamp(avg + (b - avg) * saturationBoost, none, maxChannel) * lightnessBoost;
1926
+ return {
1927
+ b: clamp(b * naturalWeight + vividB * vividWeight, none, maxChannel),
1928
+ g: clamp(g * naturalWeight + vividG * vividWeight, none, maxChannel),
1929
+ r: clamp(r * naturalWeight + vividR * vividWeight, none, maxChannel),
1930
+ };
1931
+ }
1932
+ case HdrMode.standard:
1933
+ return { b, g, r };
1934
+ case HdrMode.natural:
1935
+ default:
1936
+ return { b, g, r };
1937
+ }
1938
+ }
1786
1939
  function stringToRgba(pluginManager, input) {
1787
1940
  if (!input) {
1788
1941
  return;
@@ -1906,9 +2059,9 @@
1906
2059
  const grayscaleValue = Math.round(lNormalized * rgbMax);
1907
2060
  return { r: grayscaleValue, g: grayscaleValue, b: grayscaleValue };
1908
2061
  }
1909
- const temp1 = lNormalized < half
2062
+ const temp2 = lNormalized < half
1910
2063
  ? lNormalized * (sNormalizedOffset + sNormalized)
1911
- : lNormalized + sNormalized - lNormalized * sNormalized, temp2 = double * lNormalized - temp1, phaseThird = phaseNumerator / triple, red = Math.min(rgbMax, rgbMax * hslChannel(temp2, temp1, hNormalized + phaseThird)), green = Math.min(rgbMax, rgbMax * hslChannel(temp2, temp1, hNormalized)), blue = Math.min(rgbMax, rgbMax * hslChannel(temp2, temp1, hNormalized - phaseThird));
2064
+ : lNormalized + sNormalized - lNormalized * sNormalized, temp1 = double * lNormalized - temp2, phaseThird = phaseNumerator / triple, red = Math.min(rgbMax, rgbMax * hslChannel(temp1, temp2, hNormalized + phaseThird)), green = Math.min(rgbMax, rgbMax * hslChannel(temp1, temp2, hNormalized)), blue = Math.min(rgbMax, rgbMax * hslChannel(temp1, temp2, hNormalized - phaseThird));
1912
2065
  return { r: Math.round(red), g: Math.round(green), b: Math.round(blue) };
1913
2066
  }
1914
2067
  function hslToRgbFloat(hsl) {
@@ -1917,9 +2070,9 @@
1917
2070
  const grayscaleValue = lNormalized * rgbMax;
1918
2071
  return { r: grayscaleValue, g: grayscaleValue, b: grayscaleValue };
1919
2072
  }
1920
- const temp1 = lNormalized < half
2073
+ const temp2 = lNormalized < half
1921
2074
  ? lNormalized * (sNormalizedOffset + sNormalized)
1922
- : lNormalized + sNormalized - lNormalized * sNormalized, temp2 = double * lNormalized - temp1, phaseThird = phaseNumerator / triple, red = Math.min(rgbMax, rgbMax * hslChannel(temp2, temp1, hNormalized + phaseThird)), green = Math.min(rgbMax, rgbMax * hslChannel(temp2, temp1, hNormalized)), blue = Math.min(rgbMax, rgbMax * hslChannel(temp2, temp1, hNormalized - phaseThird));
2075
+ : lNormalized + sNormalized - lNormalized * sNormalized, temp1 = double * lNormalized - temp2, phaseThird = phaseNumerator / triple, red = Math.min(rgbMax, rgbMax * hslChannel(temp1, temp2, hNormalized + phaseThird)), green = Math.min(rgbMax, rgbMax * hslChannel(temp1, temp2, hNormalized)), blue = Math.min(rgbMax, rgbMax * hslChannel(temp1, temp2, hNormalized - phaseThird));
1923
2076
  return { r: red, g: green, b: blue };
1924
2077
  }
1925
2078
  function hslaToRgba(hsla) {
@@ -1940,21 +2093,40 @@
1940
2093
  r: getRgbInRangeValue(),
1941
2094
  };
1942
2095
  }
1943
- function getStyleFromRgb(color, hdr, opacity) {
1944
- const rgbPrecision = hdr ? hdrRgbFixedPrecision : rgbFixedPrecision, op = opacity ?? defaultOpacity$1, key = `rgb-${color.r.toFixed(rgbPrecision)}-${color.g.toFixed(rgbPrecision)}-${color.b.toFixed(rgbPrecision)}-${hdr ? "hdr" : "sdr"}-${op.toString()}`;
1945
- return getCachedStyle(key, () => (hdr ? getHdrStyleFromRgb(color, opacity) : getSdrStyleFromRgb(color, opacity)));
2096
+ function getStyleFromRgb(color, hdr, opacity, peakNits, mode) {
2097
+ const rgbPrecision = hdr ? hdrRgbFixedPrecision : rgbFixedPrecision, op = opacity ?? defaultOpacity$1, key = hdr
2098
+ ? `rgb-${color.r.toFixed(rgbPrecision)}-${color.g.toFixed(rgbPrecision)}-${color.b.toFixed(rgbPrecision)}-hdr-${op.toString()}-${(peakNits ?? maxNits).toString()}-${mode ?? HdrMode.standard}`
2099
+ : `rgb-${color.r.toFixed(rgbPrecision)}-${color.g.toFixed(rgbPrecision)}-${color.b.toFixed(rgbPrecision)}-sdr-${op.toString()}`;
2100
+ return getCachedStyle(key, () => hdr ? getHdrStyleFromRgb(color, opacity, peakNits, mode) : getSdrStyleFromRgb(color, opacity));
2101
+ }
2102
+ function getHdrStyleFromRgb(color, opacity, peakNits = maxNits, mode = HdrMode.standard) {
2103
+ const headroom = peakNits / sdrReferenceWhiteNits, middleGray = 0.18, mapped = hdrToneMapColor(color, headroom, middleGray, mode);
2104
+ return `color(display-p3 ${mapped.r.toString()} ${mapped.g.toString()} ${mapped.b.toString()} / ${(opacity ?? defaultOpacity$1).toString()})`;
2105
+ }
2106
+ function hdrToneMapColor(color, headroom, middleGray, mode) {
2107
+ const rNorm = color.r / rgbMax, gNorm = color.g / rgbMax, bNorm = color.b / rgbMax;
2108
+ if (mode !== HdrMode.natural && mode !== HdrMode.vivid && mode !== HdrMode.cinematic && mode !== HdrMode.dynamic) {
2109
+ return { b: bNorm, g: gNorm, r: rNorm };
2110
+ }
2111
+ const maxChannel = Math.max(one, headroom), luminance = luminanceR * rNorm + luminanceG * gNorm + luminanceB * bNorm, mappedLuminance = hdrToneMap(luminance, headroom, middleGray), scale = luminance > none ? mappedLuminance / luminance : one;
2112
+ return applyHdrModeAdjustments(clamp(rNorm * scale, none, maxChannel), clamp(gNorm * scale, none, maxChannel), clamp(bNorm * scale, none, maxChannel), mode, maxChannel);
1946
2113
  }
1947
- function getHdrStyleFromRgb(color, opacity, peakNits = maxNits) {
1948
- const headroom = peakNits / sdrReferenceWhiteNits;
1949
- return `color(display-p3 ${((color.r / rgbMax) * headroom).toString()} ${((color.g / rgbMax) * headroom).toString()} ${((color.b / rgbMax) * headroom).toString()} / ${(opacity ?? defaultOpacity$1).toString()})`;
2114
+ function hdrToneMap(normalized, headroom, middleGray) {
2115
+ if (normalized <= middleGray) {
2116
+ return acesFilmic(normalized);
2117
+ }
2118
+ const expanded = normalized + (normalized - middleGray) * (headroom - one);
2119
+ return acesFilmic(expanded);
1950
2120
  }
1951
2121
  function getSdrStyleFromRgb(color, opacity) {
1952
2122
  return `rgba(${color.r.toString()}, ${color.g.toString()}, ${color.b.toString()}, ${(opacity ?? defaultOpacity$1).toString()})`;
1953
2123
  }
1954
- function getStyleFromHsl(color, hdr, opacity) {
1955
- const hslPrecision = hdr ? hdrHslFixedPrecision : hslFixedPrecision, op = opacity ?? defaultOpacity$1, key = `hsl-${color.h.toFixed(hslPrecision)}-${color.s.toFixed(hslPrecision)}-${color.l.toFixed(hslPrecision)}-${hdr ? "hdr" : "sdr"}-${op.toString()}`;
2124
+ function getStyleFromHsl(color, hdr, opacity, peakNits, mode) {
2125
+ const hslPrecision = hdr ? hdrHslFixedPrecision : hslFixedPrecision, op = opacity ?? defaultOpacity$1, key = hdr
2126
+ ? `hsl-${color.h.toFixed(hslPrecision)}-${color.s.toFixed(hslPrecision)}-${color.l.toFixed(hslPrecision)}-hdr-${op.toString()}-${(peakNits ?? maxNits).toString()}-${mode ?? HdrMode.standard}`
2127
+ : `hsl-${color.h.toFixed(hslPrecision)}-${color.s.toFixed(hslPrecision)}-${color.l.toFixed(hslPrecision)}-sdr-${op.toString()}`;
1956
2128
  return getCachedStyle(key, () => hdr
1957
- ? getStyleFromRgb(hslToRgbFloat(color), true, opacity)
2129
+ ? getStyleFromRgb(hslToRgbFloat(color), true, opacity, peakNits, mode)
1958
2130
  : `hsla(${color.h.toString()}, ${color.s.toString()}%, ${color.l.toString()}%, ${op.toString()})`);
1959
2131
  }
1960
2132
  function getHslFromAnimation(animation) {
@@ -2017,7 +2189,7 @@
2017
2189
  colorValue.velocity = defaultVelocity;
2018
2190
  }
2019
2191
  }
2020
- function updateColorValue(data, decrease, delta, hdr) {
2192
+ function updateColorValue(data, decrease, delta, _hdr) {
2021
2193
  const minLoops = 0, minDelay = 0, identity = 1, minVelocity = 0, minOffset = 0, velocityFactor = 3.6;
2022
2194
  if (!data.enable ||
2023
2195
  ((data.maxLoops ?? minLoops) > minLoops && (data.loops ?? minLoops) > (data.maxLoops ?? minLoops))) {
@@ -2030,7 +2202,7 @@
2030
2202
  if ((data.delayTime ?? minDelay) > minDelay && data.time < (data.delayTime ?? minDelay)) {
2031
2203
  return;
2032
2204
  }
2033
- const offset = data.offset ? randomInRangeValue(data.offset) : minOffset, velocity = ((data.velocity ?? minVelocity) * delta.factor + offset * velocityFactor) * (hdr ? hdrAnimationScale : identity), decay = data.decay ?? identity, max = data.max, min = data.min;
2205
+ const offset = data.offset ? randomInRangeValue(data.offset) : minOffset, velocity = (data.velocity ?? minVelocity) * delta.factor + offset * velocityFactor, decay = data.decay ?? identity, max = data.max, min = data.min;
2034
2206
  if (!decrease || data.status === AnimationStatus.increasing) {
2035
2207
  data.value += velocity;
2036
2208
  if (data.value > max) {
@@ -2062,9 +2234,9 @@
2062
2234
  return;
2063
2235
  }
2064
2236
  const { h, s, l } = color;
2065
- updateColorValue(h, false, delta, hdr);
2066
- updateColorValue(s, true, delta, hdr);
2067
- updateColorValue(l, true, delta, hdr);
2237
+ updateColorValue(h, false, delta);
2238
+ updateColorValue(s, true, delta);
2239
+ updateColorValue(l, true, delta);
2068
2240
  }
2069
2241
  function alterHsl(color, type, value) {
2070
2242
  return {
@@ -2114,7 +2286,7 @@
2114
2286
  }
2115
2287
 
2116
2288
  async function loadBlendPlugin(engine) {
2117
- engine.checkVersion("4.3.2");
2289
+ engine.checkVersion("4.5.0");
2118
2290
  await engine.pluginManager.register(e => {
2119
2291
  e.pluginManager.addPlugin(new BlendPlugin());
2120
2292
  });
@@ -2151,7 +2323,7 @@
2151
2323
  }
2152
2324
 
2153
2325
  async function loadCircleShape(engine) {
2154
- engine.checkVersion("4.3.2");
2326
+ engine.checkVersion("4.5.0");
2155
2327
  await engine.pluginManager.register(e => {
2156
2328
  e.pluginManager.addShape(["circle"], () => {
2157
2329
  return Promise.resolve(new CircleDrawer());
@@ -2166,7 +2338,7 @@
2166
2338
  RgbIndexes[RgbIndexes["b"] = 3] = "b";
2167
2339
  RgbIndexes[RgbIndexes["a"] = 4] = "a";
2168
2340
  })(RgbIndexes$1 || (RgbIndexes$1 = {}));
2169
- const shorthandHexRegex = /^#?([a-f\d])([a-f\d])([a-f\d])([a-f\d])?$/i, hexRegex = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})?$/i, hexRadix = 16, defaultAlpha = 1, alphaFactor = 0xff;
2341
+ const shorthandHexRegex = /^#?([a-f\d])([a-f\d])([a-f\d])([a-f\d])?$/i, hexRegex = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})?$/i, hexRadix = 16, alphaFactor = 0xff;
2170
2342
  class HexColorManager {
2171
2343
  accepts(input) {
2172
2344
  return input.startsWith("#");
@@ -2199,7 +2371,7 @@
2199
2371
  }
2200
2372
 
2201
2373
  async function loadHexColorPlugin(engine) {
2202
- engine.checkVersion("4.3.2");
2374
+ engine.checkVersion("4.5.0");
2203
2375
  await engine.pluginManager.register(e => {
2204
2376
  e.pluginManager.addColorManager("hex", new HexColorManager());
2205
2377
  });
@@ -2239,7 +2411,7 @@
2239
2411
  if (!this.accepts(input)) {
2240
2412
  return;
2241
2413
  }
2242
- const result = hslRegex.exec(input), minLength = 4, defaultAlpha = 1, radix = 10;
2414
+ const result = hslRegex.exec(input), minLength = 4, radix = 10;
2243
2415
  return result
2244
2416
  ? hslaToRgba({
2245
2417
  a: result.length > minLength ? parseAlpha(result[HslIndexes.a]) : defaultAlpha,
@@ -2252,12 +2424,20 @@
2252
2424
  }
2253
2425
 
2254
2426
  async function loadHslColorPlugin(engine) {
2255
- engine.checkVersion("4.3.2");
2427
+ engine.checkVersion("4.5.0");
2256
2428
  await engine.pluginManager.register(e => {
2257
2429
  e.pluginManager.addColorManager("hsl", new HslColorManager());
2258
2430
  });
2259
2431
  }
2260
2432
 
2433
+ const ErrorCodes$1 = {
2434
+ baseMoverNotLoaded: "TSP-3203",
2435
+ };
2436
+
2437
+ const ErrorMessages$1 = {
2438
+ [ErrorCodes$1.baseMoverNotLoaded]: "tsParticles Base Mover is not loaded",
2439
+ };
2440
+
2261
2441
  class MovePlugin {
2262
2442
  id = "move";
2263
2443
  #pluginManager;
@@ -2276,20 +2456,20 @@
2276
2456
  }
2277
2457
 
2278
2458
  async function loadMovePlugin(engine) {
2279
- engine.checkVersion("4.3.2");
2459
+ engine.checkVersion("4.5.0");
2460
+ if (typeof process !== "undefined" && process.env.NODE_ENV !== "production") {
2461
+ addErrorMessages(ErrorMessages$1);
2462
+ }
2280
2463
  await engine.pluginManager.register(e => {
2281
2464
  const moveEngine = e, movePluginManager = moveEngine.pluginManager;
2282
2465
  movePluginManager.initializers.pathGenerators ??= new Map();
2283
- movePluginManager.pathGenerators ??= new Map();
2284
2466
  movePluginManager.addPathGenerator = (name, generator) => {
2467
+ if (movePluginManager.initialized) {
2468
+ return;
2469
+ }
2285
2470
  movePluginManager.initializers.pathGenerators ??= new Map();
2286
2471
  movePluginManager.initializers.pathGenerators.set(name, generator);
2287
2472
  };
2288
- movePluginManager.getPathGenerators = async (container, force = false) => {
2289
- movePluginManager.initializers.pathGenerators ??= new Map();
2290
- movePluginManager.pathGenerators ??= new Map();
2291
- return getItemMapFromInitializer(container, movePluginManager.pathGenerators, movePluginManager.initializers.pathGenerators, force);
2292
- };
2293
2473
  e.pluginManager.addPlugin(new MovePlugin(e.pluginManager));
2294
2474
  });
2295
2475
  }
@@ -2486,7 +2666,7 @@
2486
2666
  }
2487
2667
 
2488
2668
  async function loadOpacityUpdater(engine) {
2489
- engine.checkVersion("4.3.2");
2669
+ engine.checkVersion("4.5.0");
2490
2670
  await engine.pluginManager.register(e => {
2491
2671
  e.pluginManager.addParticleUpdater("opacity", container => {
2492
2672
  return Promise.resolve(new OpacityUpdater(container));
@@ -2495,70 +2675,60 @@
2495
2675
  }
2496
2676
 
2497
2677
  const boundsMin = 0;
2498
- function bounceHorizontal(data) {
2499
- if ((data.outMode !== OutMode.bounce && data.outMode !== OutMode.split) ||
2500
- (data.direction !== OutModeDirection.left && data.direction !== OutModeDirection.right)) {
2501
- return;
2502
- }
2503
- if (data.bounds.right < boundsMin && data.direction === OutModeDirection.left) {
2504
- data.particle.position.x = data.size + data.offset.x;
2505
- }
2506
- else if (data.bounds.left > data.canvasSize.width && data.direction === OutModeDirection.right) {
2507
- data.particle.position.x = data.canvasSize.width - data.size - data.offset.x;
2508
- }
2509
- const velocity = data.particle.velocity.x;
2510
- let bounced = false;
2511
- if (data.outOfCanvas &&
2512
- ((data.direction === OutModeDirection.right && velocity > minVelocity) ||
2513
- (data.direction === OutModeDirection.left && velocity < minVelocity))) {
2514
- const newVelocity = getRangeValue(data.particle.options.bounce.horizontal.value);
2515
- data.particle.velocity.x *= -newVelocity;
2516
- bounced = true;
2517
- }
2518
- if (!bounced) {
2519
- return;
2520
- }
2521
- const minPos = data.offset.x + data.size;
2522
- if (data.outOfCanvas && data.direction === OutModeDirection.right) {
2523
- data.particle.position.x = data.canvasSize.width - minPos;
2524
- }
2525
- else if (data.outOfCanvas && data.direction === OutModeDirection.left) {
2526
- data.particle.position.x = minPos;
2527
- }
2528
- if (data.outMode === OutMode.split) {
2529
- data.particle.destroy();
2530
- }
2531
- }
2532
- function bounceVertical(data) {
2533
- if ((data.outMode !== OutMode.bounce && data.outMode !== OutMode.split) ||
2534
- (data.direction !== OutModeDirection.bottom && data.direction !== OutModeDirection.top)) {
2678
+ const bounceAxisConfigs = {
2679
+ [OutModeDirection.left]: {
2680
+ axis: "x",
2681
+ canvas: "width",
2682
+ bounce: "horizontal",
2683
+ negativeEdge: "right",
2684
+ positiveEdge: "left",
2685
+ negative: true,
2686
+ },
2687
+ [OutModeDirection.right]: {
2688
+ axis: "x",
2689
+ canvas: "width",
2690
+ bounce: "horizontal",
2691
+ negativeEdge: "right",
2692
+ positiveEdge: "left",
2693
+ negative: false,
2694
+ },
2695
+ [OutModeDirection.top]: {
2696
+ axis: "y",
2697
+ canvas: "height",
2698
+ bounce: "vertical",
2699
+ negativeEdge: "bottom",
2700
+ positiveEdge: "top",
2701
+ negative: true,
2702
+ },
2703
+ [OutModeDirection.bottom]: {
2704
+ axis: "y",
2705
+ canvas: "height",
2706
+ bounce: "vertical",
2707
+ negativeEdge: "bottom",
2708
+ positiveEdge: "top",
2709
+ negative: false,
2710
+ },
2711
+ };
2712
+ function bounce(data) {
2713
+ if ((data.outMode !== OutMode.bounce && data.outMode !== OutMode.split) || !(data.direction in bounceAxisConfigs)) {
2535
2714
  return;
2536
2715
  }
2537
- if (data.bounds.bottom < boundsMin && data.direction === OutModeDirection.top) {
2538
- data.particle.position.y = data.size + data.offset.y;
2716
+ const config = bounceAxisConfigs[data.direction], bounds = data.bounds, canvasDim = data.canvasSize[config.canvas], position = data.particle.position, velocity = data.particle.velocity[config.axis];
2717
+ if (config.negative && bounds[config.negativeEdge] < boundsMin) {
2718
+ position[config.axis] = data.size + data.offset[config.axis];
2539
2719
  }
2540
- else if (data.bounds.top > data.canvasSize.height && data.direction === OutModeDirection.bottom) {
2541
- data.particle.position.y = data.canvasSize.height - data.size - data.offset.y;
2720
+ else if (!config.negative && bounds[config.positiveEdge] > canvasDim) {
2721
+ position[config.axis] = canvasDim - data.size - data.offset[config.axis];
2542
2722
  }
2543
- const velocity = data.particle.velocity.y;
2544
- let bounced = false;
2545
2723
  if (data.outOfCanvas &&
2546
- ((data.direction === OutModeDirection.bottom && velocity > minVelocity) ||
2547
- (data.direction === OutModeDirection.top && velocity < minVelocity))) {
2548
- const newVelocity = getRangeValue(data.particle.options.bounce.vertical.value);
2549
- data.particle.velocity.y *= -newVelocity;
2550
- bounced = true;
2724
+ ((config.negative && velocity < minVelocity) || (!config.negative && velocity > minVelocity))) {
2725
+ data.particle.velocity[config.axis] *= -getRangeValue(data.particle.options.bounce[config.bounce].value);
2551
2726
  }
2552
- if (!bounced) {
2727
+ else {
2553
2728
  return;
2554
2729
  }
2555
- const minPos = data.offset.y + data.size;
2556
- if (data.outOfCanvas && data.direction === OutModeDirection.bottom) {
2557
- data.particle.position.y = data.canvasSize.height - minPos;
2558
- }
2559
- else if (data.outOfCanvas && data.direction === OutModeDirection.top) {
2560
- data.particle.position.y = minPos;
2561
- }
2730
+ const minPos = data.offset[config.axis] + data.size;
2731
+ position[config.axis] = config.negative ? minPos : canvasDim - minPos;
2562
2732
  if (data.outMode === OutMode.split) {
2563
2733
  data.particle.destroy();
2564
2734
  }
@@ -2574,26 +2744,19 @@
2574
2744
  OutMode.bounce,
2575
2745
  OutMode.split,
2576
2746
  ];
2577
- this.#particleBouncePlugins = container.plugins.filter(p => p.particleBounce !== undefined);
2747
+ this.#particleBouncePlugins = container.plugins.filter(p => !!p.particleBounce);
2578
2748
  }
2579
2749
  update(particle, direction, delta, outMode) {
2580
2750
  if (!this.modes.includes(outMode)) {
2581
2751
  return;
2582
2752
  }
2583
- const container = this.#container;
2584
- let handled = false;
2585
2753
  for (const plugin of this.#particleBouncePlugins) {
2586
- handled = plugin.particleBounce?.(particle, delta, direction) ?? false;
2587
- if (handled) {
2588
- break;
2754
+ if (plugin.particleBounce?.(particle, delta, direction)) {
2755
+ return;
2589
2756
  }
2590
2757
  }
2591
- if (handled) {
2592
- return;
2593
- }
2594
- const pos = particle.getPosition(), offset = particle.offset, size = particle.getRadius(), bounds = calculateBounds(pos, size), canvasSize = container.canvas.size, outOfCanvas = !particle.isInsideCanvasForOutMode(outMode, direction);
2595
- bounceHorizontal({ particle, outMode, direction, bounds, canvasSize, offset, outOfCanvas, size });
2596
- bounceVertical({ particle, outMode, direction, bounds, canvasSize, offset, outOfCanvas, size });
2758
+ const pos = particle.getPosition(), offset = particle.offset, size = particle.getRadius(), bounds = calculateBounds(pos, size), canvasSize = this.#container.canvas.size, outOfCanvas = !particle.isInsideCanvasForOutMode(outMode, direction);
2759
+ bounce({ particle, outMode, direction, bounds, canvasSize, offset, outOfCanvas, size });
2597
2760
  }
2598
2761
  }
2599
2762
 
@@ -2682,108 +2845,109 @@
2682
2845
  return;
2683
2846
  }
2684
2847
  const container = this.#container;
2685
- switch (particle.outType) {
2686
- case ParticleOutType.inside: {
2687
- const { x: vx, y: vy } = particle.velocity;
2688
- updateVector.setTo(originPoint);
2689
- updateVector.length = particle.moveCenter.radius;
2690
- updateVector.angle = particle.velocity.angle + Math.PI;
2691
- updateVector.addTo(particle.moveCenter);
2692
- const { dx, dy } = getDistances(particle.position, updateVector);
2693
- if ((vx <= minVelocity && dx >= minDistance) ||
2694
- (vy <= minVelocity && dy >= minDistance) ||
2695
- (vx >= minVelocity && dx <= minDistance) ||
2696
- (vy >= minVelocity && dy <= minDistance)) {
2697
- return;
2698
- }
2699
- particle.position.x = Math.floor(randomInRangeValue({
2700
- min: 0,
2701
- max: container.canvas.size.width,
2702
- }));
2703
- particle.position.y = Math.floor(randomInRangeValue({
2704
- min: 0,
2705
- max: container.canvas.size.height,
2706
- }));
2707
- const { dx: newDx, dy: newDy } = getDistances(particle.position, particle.moveCenter);
2708
- particle.direction = Math.atan2(-newDy, -newDx);
2709
- particle.velocity.angle = particle.direction;
2710
- particle.justWarped = true;
2711
- break;
2848
+ if (particle.outType === ParticleOutType.inside) {
2849
+ this.#applyOutModeInside(particle, container);
2850
+ }
2851
+ else {
2852
+ if (particle.isInsideCanvasForOutMode(outMode, direction)) {
2853
+ return;
2712
2854
  }
2713
- default: {
2714
- if (particle.isInsideCanvasForOutMode(outMode, direction)) {
2715
- return;
2716
- }
2717
- switch (particle.outType) {
2718
- case ParticleOutType.outside: {
2719
- particle.position.x =
2720
- Math.floor(randomInRangeValue({
2721
- min: -particle.moveCenter.radius,
2722
- max: particle.moveCenter.radius,
2723
- })) + particle.moveCenter.x;
2724
- particle.position.y =
2725
- Math.floor(randomInRangeValue({
2726
- min: -particle.moveCenter.radius,
2727
- max: particle.moveCenter.radius,
2728
- })) + particle.moveCenter.y;
2729
- const { dx, dy } = getDistances(particle.position, particle.moveCenter);
2730
- if (particle.moveCenter.radius) {
2731
- particle.direction = Math.atan2(dy, dx);
2732
- particle.velocity.angle = particle.direction;
2733
- }
2734
- particle.justWarped = true;
2735
- break;
2736
- }
2737
- case ParticleOutType.normal: {
2738
- const warp = particle.options.move.warp, canvasSize = container.canvas.size, newPos = {
2739
- bottom: canvasSize.height + particle.getRadius() + particle.offset.y,
2740
- left: -particle.getRadius() - particle.offset.x,
2741
- right: canvasSize.width + particle.getRadius() + particle.offset.x,
2742
- top: -particle.getRadius() - particle.offset.y,
2743
- }, sizeValue = particle.getRadius(), nextBounds = calculateBounds(particle.position, sizeValue);
2744
- if (direction === OutModeDirection.right && nextBounds.left > canvasSize.width + particle.offset.x) {
2745
- particle.position.x = newPos.left;
2746
- particle.initialPosition.x = particle.position.x;
2747
- if (!warp) {
2748
- particle.position.y = getRandom() * canvasSize.height;
2749
- particle.initialPosition.y = particle.position.y;
2750
- }
2751
- particle.justWarped = true;
2752
- }
2753
- else if (direction === OutModeDirection.left && nextBounds.right < -particle.offset.x) {
2754
- particle.position.x = newPos.right;
2755
- particle.initialPosition.x = particle.position.x;
2756
- if (!warp) {
2757
- particle.position.y = getRandom() * canvasSize.height;
2758
- particle.initialPosition.y = particle.position.y;
2759
- }
2760
- particle.justWarped = true;
2761
- }
2762
- if (direction === OutModeDirection.bottom && nextBounds.top > canvasSize.height + particle.offset.y) {
2763
- if (!warp) {
2764
- particle.position.x = getRandom() * canvasSize.width;
2765
- particle.initialPosition.x = particle.position.x;
2766
- }
2767
- particle.position.y = newPos.top;
2768
- particle.initialPosition.y = particle.position.y;
2769
- particle.justWarped = true;
2770
- }
2771
- else if (direction === OutModeDirection.top && nextBounds.bottom < -particle.offset.y) {
2772
- if (!warp) {
2773
- particle.position.x = getRandom() * canvasSize.width;
2774
- particle.initialPosition.x = particle.position.x;
2775
- }
2776
- particle.position.y = newPos.bottom;
2777
- particle.initialPosition.y = particle.position.y;
2778
- particle.justWarped = true;
2779
- }
2780
- break;
2781
- }
2782
- }
2783
- break;
2855
+ if (particle.outType === ParticleOutType.outside) {
2856
+ this.#applyParticleModeOutside(particle);
2857
+ }
2858
+ else {
2859
+ this.#applyOutModeNormal(particle, container, direction);
2784
2860
  }
2785
2861
  }
2786
2862
  }
2863
+ #applyOutModeInside(particle, container) {
2864
+ const { x: vx, y: vy } = particle.velocity;
2865
+ updateVector.setTo(originPoint);
2866
+ updateVector.length = particle.moveCenter.radius;
2867
+ updateVector.angle = particle.velocity.angle + Math.PI;
2868
+ updateVector.addTo(particle.moveCenter);
2869
+ const { dx, dy } = getDistances(particle.position, updateVector);
2870
+ if ((vx <= minVelocity && dx >= minDistance) ||
2871
+ (vy <= minVelocity && dy >= minDistance) ||
2872
+ (vx >= minVelocity && dx <= minDistance) ||
2873
+ (vy >= minVelocity && dy <= minDistance)) {
2874
+ return;
2875
+ }
2876
+ particle.position.x = Math.floor(randomInRangeValue({
2877
+ min: 0,
2878
+ max: container.canvas.size.width,
2879
+ }));
2880
+ particle.position.y = Math.floor(randomInRangeValue({
2881
+ min: 0,
2882
+ max: container.canvas.size.height,
2883
+ }));
2884
+ const { dx: newDx, dy: newDy } = getDistances(particle.position, particle.moveCenter);
2885
+ particle.direction = Math.atan2(-newDy, -newDx);
2886
+ particle.velocity.angle = particle.direction;
2887
+ particle.justWarped = true;
2888
+ }
2889
+ #applyOutModeNormal(particle, container, direction) {
2890
+ const warp = particle.options.move.warp, canvasSize = container.canvas.size, sizeValue = particle.getRadius(), newPos = {
2891
+ bottom: canvasSize.height + sizeValue + particle.offset.y,
2892
+ left: -sizeValue - particle.offset.x,
2893
+ right: canvasSize.width + sizeValue + particle.offset.x,
2894
+ top: -sizeValue - particle.offset.y,
2895
+ }, nextBounds = calculateBounds(particle.position, sizeValue);
2896
+ if (direction === OutModeDirection.right && nextBounds.left > canvasSize.width + particle.offset.x) {
2897
+ particle.position.x = newPos.left;
2898
+ particle.initialPosition.x = particle.position.x;
2899
+ if (!warp) {
2900
+ particle.position.y = getRandom() * canvasSize.height;
2901
+ particle.initialPosition.y = particle.position.y;
2902
+ }
2903
+ particle.justWarped = true;
2904
+ }
2905
+ else if (direction === OutModeDirection.left && nextBounds.right < -particle.offset.x) {
2906
+ particle.position.x = newPos.right;
2907
+ particle.initialPosition.x = particle.position.x;
2908
+ if (!warp) {
2909
+ particle.position.y = getRandom() * canvasSize.height;
2910
+ particle.initialPosition.y = particle.position.y;
2911
+ }
2912
+ particle.justWarped = true;
2913
+ }
2914
+ if (direction === OutModeDirection.bottom && nextBounds.top > canvasSize.height + particle.offset.y) {
2915
+ if (!warp) {
2916
+ particle.position.x = getRandom() * canvasSize.width;
2917
+ particle.initialPosition.x = particle.position.x;
2918
+ }
2919
+ particle.position.y = newPos.top;
2920
+ particle.initialPosition.y = particle.position.y;
2921
+ particle.justWarped = true;
2922
+ }
2923
+ else if (direction === OutModeDirection.top && nextBounds.bottom < -particle.offset.y) {
2924
+ if (!warp) {
2925
+ particle.position.x = getRandom() * canvasSize.width;
2926
+ particle.initialPosition.x = particle.position.x;
2927
+ }
2928
+ particle.position.y = newPos.bottom;
2929
+ particle.initialPosition.y = particle.position.y;
2930
+ particle.justWarped = true;
2931
+ }
2932
+ }
2933
+ #applyParticleModeOutside(particle) {
2934
+ particle.position.x =
2935
+ Math.floor(randomInRangeValue({
2936
+ min: -particle.moveCenter.radius,
2937
+ max: particle.moveCenter.radius,
2938
+ })) + particle.moveCenter.x;
2939
+ particle.position.y =
2940
+ Math.floor(randomInRangeValue({
2941
+ min: -particle.moveCenter.radius,
2942
+ max: particle.moveCenter.radius,
2943
+ })) + particle.moveCenter.y;
2944
+ const { dx, dy } = getDistances(particle.position, particle.moveCenter);
2945
+ if (particle.moveCenter.radius) {
2946
+ particle.direction = Math.atan2(dy, dx);
2947
+ particle.velocity.angle = particle.direction;
2948
+ }
2949
+ particle.justWarped = true;
2950
+ }
2787
2951
  }
2788
2952
 
2789
2953
  const checkOutMode = (outModes, outMode) => {
@@ -2831,7 +2995,7 @@
2831
2995
  }
2832
2996
 
2833
2997
  async function loadOutModesUpdater(engine) {
2834
- engine.checkVersion("4.3.2");
2998
+ engine.checkVersion("4.5.0");
2835
2999
  await engine.pluginManager.register(e => {
2836
3000
  e.pluginManager.addParticleUpdater("outModes", container => {
2837
3001
  return Promise.resolve(new OutOfCanvasUpdater(container));
@@ -2848,39 +3012,9 @@
2848
3012
  this.#pluginManager = pluginManager;
2849
3013
  }
2850
3014
  init(particle) {
2851
- const container = this.#container, options = particle.options, paint = itemFromSingleOrMultiple(options.paint, particle.id, options.reduceDuplicates), color = paint?.color, paintColor = color ?? undefined, fill = paint?.fill, stroke = paint?.stroke;
2852
- if (fill) {
2853
- const fillColor = AnimatableColor.create(paintColor === undefined ? undefined : AnimatableColor.create(undefined, paintColor), fill.color);
2854
- particle.fillEnabled = fill.enable;
2855
- particle.fillOpacity = getRangeValue(fill.opacity);
2856
- particle.fillAnimation = fillColor.animation;
2857
- const fillHslColor = rangeColorToHsl(this.#pluginManager, fillColor);
2858
- if (fillHslColor) {
2859
- particle.fillColor = getHslAnimationFromHsl(fillHslColor, particle.fillAnimation, container.retina.reduceFactor);
2860
- }
2861
- }
2862
- else {
2863
- particle.fillEnabled = false;
2864
- particle.fillAnimation = undefined;
2865
- particle.fillColor = undefined;
2866
- particle.fillOpacity = defaultOpacity;
2867
- }
2868
- if (stroke) {
2869
- const strokeColor = AnimatableColor.create(paintColor === undefined ? undefined : AnimatableColor.create(undefined, paintColor), stroke.color);
2870
- particle.strokeWidth = getRangeValue(stroke.width) * container.retina.pixelRatio;
2871
- particle.strokeOpacity = getRangeValue(stroke.opacity ?? defaultOpacity);
2872
- particle.strokeAnimation = strokeColor.animation;
2873
- const strokeHslColor = rangeColorToHsl(this.#pluginManager, strokeColor) ?? particle.getFillColor();
2874
- if (strokeHslColor) {
2875
- particle.strokeColor = getHslAnimationFromHsl(strokeHslColor, particle.strokeAnimation, container.retina.reduceFactor);
2876
- }
2877
- }
2878
- else {
2879
- particle.strokeAnimation = undefined;
2880
- particle.strokeColor = undefined;
2881
- particle.strokeOpacity = defaultOpacity;
2882
- particle.strokeWidth = 0;
2883
- }
3015
+ const container = this.#container, options = particle.options, paint = itemFromSingleOrMultiple(options.paint, particle.id, options.reduceDuplicates);
3016
+ this.#initFill(paint, particle, container);
3017
+ this.#initStroke(paint, particle, container);
2884
3018
  }
2885
3019
  isEnabled(particle) {
2886
3020
  const { fillAnimation, fillColor, strokeAnimation, strokeColor } = particle, fillEnabled = !!fillAnimation &&
@@ -2899,10 +3033,48 @@
2899
3033
  updateColor(particle.fillColor, delta, this.#container.hdr);
2900
3034
  updateColor(particle.strokeColor, delta, this.#container.hdr);
2901
3035
  }
3036
+ #initFill(paint, particle, container) {
3037
+ const fill = paint?.fill, color = paint?.color, paintColor = color ?? undefined;
3038
+ if (!fill) {
3039
+ particle.fillEnabled = false;
3040
+ particle.fillAnimation = undefined;
3041
+ particle.fillColor = undefined;
3042
+ particle.fillOpacity = defaultOpacity;
3043
+ return;
3044
+ }
3045
+ const fillColor = AnimatableColor.create(paintColor === undefined ? undefined : AnimatableColor.create(undefined, paintColor), fill.color);
3046
+ particle.fillEnabled = fill.enable;
3047
+ particle.fillOpacity = getRangeValue(fill.opacity);
3048
+ particle.fillAnimation = fillColor.animation;
3049
+ const fillHslColor = rangeColorToHsl(this.#pluginManager, fillColor);
3050
+ if (!fillHslColor) {
3051
+ return;
3052
+ }
3053
+ particle.fillColor = getHslAnimationFromHsl(fillHslColor, particle.fillAnimation, container.retina.reduceFactor);
3054
+ }
3055
+ #initStroke(paint, particle, container) {
3056
+ const stroke = paint?.stroke, color = paint?.color, paintColor = color ?? undefined;
3057
+ if (!stroke) {
3058
+ particle.strokeAnimation = undefined;
3059
+ particle.strokeColor = undefined;
3060
+ particle.strokeOpacity = defaultOpacity;
3061
+ particle.strokeWidth = 0;
3062
+ return;
3063
+ }
3064
+ const strokeColor = AnimatableColor.create(paintColor === undefined ? undefined : AnimatableColor.create(undefined, paintColor), stroke.color);
3065
+ particle.strokeWidth = getRangeValue(stroke.width) * container.retina.pixelRatio;
3066
+ particle.strokeOpacity = getRangeValue(stroke.opacity ?? defaultOpacity);
3067
+ particle.strokeAnimation = strokeColor.animation;
3068
+ const strokeHslColor = rangeColorToHsl(this.#pluginManager, strokeColor) ?? particle.getFillColor();
3069
+ if (!strokeHslColor) {
3070
+ return;
3071
+ }
3072
+ particle.strokeColor = getHslAnimationFromHsl(strokeHslColor, particle.strokeAnimation, container.retina.reduceFactor);
3073
+ }
2902
3074
  }
2903
3075
 
2904
3076
  async function loadPaintUpdater(engine) {
2905
- engine.checkVersion("4.3.2");
3077
+ engine.checkVersion("4.5.0");
2906
3078
  await engine.pluginManager.register(e => {
2907
3079
  e.pluginManager.addParticleUpdater("paint", container => {
2908
3080
  return Promise.resolve(new PaintUpdater(e.pluginManager, container));
@@ -2944,7 +3116,7 @@
2944
3116
  if (!this.accepts(input)) {
2945
3117
  return;
2946
3118
  }
2947
- const result = rgbRegex.exec(input), radix = 10, minLength = 4, defaultAlpha = 1;
3119
+ const result = rgbRegex.exec(input), radix = 10, minLength = 4;
2948
3120
  return result
2949
3121
  ? {
2950
3122
  a: result.length > minLength ? parseAlpha(result[RgbIndexes.a]) : defaultAlpha,
@@ -2957,7 +3129,7 @@
2957
3129
  }
2958
3130
 
2959
3131
  async function loadRgbColorPlugin(engine) {
2960
- engine.checkVersion("4.3.2");
3132
+ engine.checkVersion("4.5.0");
2961
3133
  await engine.pluginManager.register(e => {
2962
3134
  e.pluginManager.addColorManager("rgb", new RgbColorManager());
2963
3135
  });
@@ -3042,7 +3214,7 @@
3042
3214
  }
3043
3215
 
3044
3216
  async function loadSizeUpdater(engine) {
3045
- engine.checkVersion("4.3.2");
3217
+ engine.checkVersion("4.5.0");
3046
3218
  await engine.pluginManager.register(e => {
3047
3219
  e.pluginManager.addParticleUpdater("size", container => {
3048
3220
  return Promise.resolve(new SizeUpdater(container));
@@ -3051,7 +3223,7 @@
3051
3223
  }
3052
3224
 
3053
3225
  async function loadBasic(engine) {
3054
- engine.checkVersion("4.3.2");
3226
+ engine.checkVersion("4.5.0");
3055
3227
  await engine.pluginManager.register(async (e) => {
3056
3228
  await Promise.all([
3057
3229
  loadBlendPlugin(e),
@@ -3160,6 +3332,8 @@
3160
3332
  autoPlay = true;
3161
3333
  direction;
3162
3334
  domId;
3335
+ draggable = false;
3336
+ draw = true;
3163
3337
  fill = true;
3164
3338
  life = new EmitterLife();
3165
3339
  name;
@@ -3183,6 +3357,8 @@
3183
3357
  }
3184
3358
  loadProperty(this, "direction", data.direction);
3185
3359
  loadProperty(this, "domId", data.domId);
3360
+ loadProperty(this, "draggable", data.draggable);
3361
+ loadProperty(this, "draw", data.draw);
3186
3362
  loadProperty(this, "fill", data.fill);
3187
3363
  this.life.load(data.life);
3188
3364
  loadProperty(this, "name", data.name);
@@ -3244,6 +3420,14 @@
3244
3420
  }
3245
3421
  }
3246
3422
 
3423
+ const ErrorCodes = {
3424
+ emittersPluginNotLoaded: "TSP-3101",
3425
+ };
3426
+
3427
+ const ErrorMessages = {
3428
+ [ErrorCodes.emittersPluginNotLoaded]: "tsParticles Emitters Plugin is not loaded",
3429
+ };
3430
+
3247
3431
  async function addEmittersShapesManager(e) {
3248
3432
  const { ShapeManager } = await Promise.resolve().then(function () { return ShapeManager$1; }), pluginManager = e.pluginManager;
3249
3433
  pluginManager.emitterShapeManager ??= new ShapeManager();
@@ -3279,6 +3463,8 @@
3279
3463
  this.fill = fill;
3280
3464
  this.options = options;
3281
3465
  }
3466
+ draw(_context) {
3467
+ }
3282
3468
  resize(position, size) {
3283
3469
  this.position = position;
3284
3470
  this.size = size;
@@ -3291,7 +3477,10 @@
3291
3477
  })(EmitterClickMode || (EmitterClickMode = {}));
3292
3478
 
3293
3479
  async function loadEmittersPluginSimple(engine) {
3294
- engine.checkVersion("4.3.2");
3480
+ engine.checkVersion("4.5.0");
3481
+ if (typeof process !== "undefined" && process.env.NODE_ENV !== "production") {
3482
+ addErrorMessages(ErrorMessages);
3483
+ }
3295
3484
  await engine.pluginManager.register(async (e) => {
3296
3485
  const instancesManager = await getEmittersInstancesManager(e);
3297
3486
  await addEmittersShapesManager(e);
@@ -3299,9 +3488,63 @@
3299
3488
  });
3300
3489
  }
3301
3490
 
3491
+ class EmittersPluginInstance {
3492
+ #container;
3493
+ #instancesManager;
3494
+ constructor(instancesManager, container) {
3495
+ this.#instancesManager = instancesManager;
3496
+ this.#container = container;
3497
+ this.#instancesManager.initContainer(container);
3498
+ }
3499
+ draw(context, _delta) {
3500
+ for (const emitter of this.#instancesManager.getArray(this.#container)) {
3501
+ emitter.draw(context);
3502
+ }
3503
+ }
3504
+ async init() {
3505
+ const emittersOptions = this.#container.actualOptions.emitters;
3506
+ if (isArray(emittersOptions)) {
3507
+ for (const emitterOptions of emittersOptions) {
3508
+ await this.#instancesManager.addEmitter(this.#container, emitterOptions);
3509
+ }
3510
+ }
3511
+ else {
3512
+ await this.#instancesManager.addEmitter(this.#container, emittersOptions);
3513
+ }
3514
+ }
3515
+ pause() {
3516
+ for (const emitter of this.#instancesManager.getArray(this.#container)) {
3517
+ emitter.pause();
3518
+ }
3519
+ }
3520
+ play() {
3521
+ for (const emitter of this.#instancesManager.getArray(this.#container)) {
3522
+ emitter.play();
3523
+ }
3524
+ }
3525
+ resize() {
3526
+ for (const emitter of this.#instancesManager.getArray(this.#container)) {
3527
+ emitter.resize();
3528
+ }
3529
+ }
3530
+ stop() {
3531
+ this.#instancesManager.clear(this.#container);
3532
+ }
3533
+ update(delta) {
3534
+ this.#instancesManager.getArray(this.#container).forEach(emitter => {
3535
+ emitter.update(delta);
3536
+ });
3537
+ }
3538
+ }
3539
+
3540
+ var EmittersPluginInstance$1 = /*#__PURE__*/Object.freeze({
3541
+ __proto__: null,
3542
+ EmittersPluginInstance: EmittersPluginInstance
3543
+ });
3544
+
3302
3545
  function ensureEmittersPluginLoaded(e) {
3303
3546
  if (!e.pluginManager.addEmitterShapeGenerator) {
3304
- throw new Error("tsParticles Emitters Plugin is not loaded");
3547
+ throw new Error(getErrorMessage(ErrorCodes.emittersPluginNotLoaded));
3305
3548
  }
3306
3549
  }
3307
3550
 
@@ -3317,12 +3560,16 @@
3317
3560
  return position + offset * (getRandom() - half);
3318
3561
  }
3319
3562
  function getRandomSize(sides) {
3320
- return Math.floor(getRandom() * sides);
3563
+ return toEnumValue(Sides, Math.floor(getRandom() * sides), Sides.BottomLeft);
3321
3564
  }
3322
3565
  class EmittersSquareShape extends EmitterShapeBase {
3323
3566
  constructor(position, size, fill, options) {
3324
3567
  super(position, size, fill, options);
3325
3568
  }
3569
+ draw(context) {
3570
+ const position = this.position, size = this.size, halfW = size.width * half, halfH = size.height * half;
3571
+ context.rect(position.x - halfW, position.y - halfH, size.width, size.height);
3572
+ }
3326
3573
  async init() {
3327
3574
  }
3328
3575
  randomPosition() {
@@ -3379,7 +3626,7 @@
3379
3626
  }
3380
3627
 
3381
3628
  async function loadEmittersShapeSquare(engine) {
3382
- engine.checkVersion("4.3.2");
3629
+ engine.checkVersion("4.5.0");
3383
3630
  await engine.pluginManager.register((e) => {
3384
3631
  ensureEmittersPluginLoaded(e);
3385
3632
  e.pluginManager.addEmitterShapeGenerator?.("square", new EmittersSquareShapeGenerator());
@@ -3523,7 +3770,7 @@
3523
3770
  }
3524
3771
 
3525
3772
  async function loadLifeUpdater(engine) {
3526
- engine.checkVersion("4.3.2");
3773
+ engine.checkVersion("4.5.0");
3527
3774
  await engine.pluginManager.register(e => {
3528
3775
  e.pluginManager.addParticleUpdater("life", container => {
3529
3776
  return Promise.resolve(new LifeUpdater(container));
@@ -3587,7 +3834,7 @@
3587
3834
  }
3588
3835
 
3589
3836
  async function loadTrailPlugin(engine) {
3590
- engine.checkVersion("4.3.2");
3837
+ engine.checkVersion("4.5.0");
3591
3838
  await engine.pluginManager.register(e => {
3592
3839
  e.pluginManager.addPlugin(new TrailPlugin(e.pluginManager));
3593
3840
  });
@@ -3739,21 +3986,28 @@
3739
3986
  });
3740
3987
  }
3741
3988
  clear() {
3989
+ const visited = new Set();
3742
3990
  for (const plugin of this.#canvasClearPlugins) {
3991
+ visited.add(plugin);
3743
3992
  if (plugin.canvasClear?.() ?? false) {
3744
- return;
3993
+ return plugin;
3745
3994
  }
3746
3995
  }
3747
3996
  for (const layer of Object.values(DrawLayer)) {
3748
3997
  if (typeof layer === "number") {
3749
3998
  for (const plugin of this.#getLayerPlugins(layer)) {
3999
+ if (visited.has(plugin)) {
4000
+ continue;
4001
+ }
4002
+ visited.add(plugin);
3750
4003
  if (plugin.canvasClear?.() ?? false) {
3751
- return;
4004
+ return plugin;
3752
4005
  }
3753
4006
  }
3754
4007
  }
3755
4008
  }
3756
4009
  this.canvasClear();
4010
+ return undefined;
3757
4011
  }
3758
4012
  destroy() {
3759
4013
  this.stop();
@@ -3794,7 +4048,11 @@
3794
4048
  if (!fColor && !sColor) {
3795
4049
  return;
3796
4050
  }
3797
- 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;
4051
+ 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
4052
+ ? getStyleFromHsl(fColor, container.hdr, fillOpacity * opacity, container.peakNits, container.hdrMode)
4053
+ : undefined, stroke = sColor
4054
+ ? getStyleFromHsl(sColor, container.hdr, strokeOpacity * opacity, container.peakNits, container.hdrMode)
4055
+ : fill;
3798
4056
  transform.a = transform.b = transform.c = transform.d = undefined;
3799
4057
  colorStyles.fill = fill;
3800
4058
  colorStyles.stroke = stroke;
@@ -3827,8 +4085,7 @@
3827
4085
  });
3828
4086
  }
3829
4087
  drawParticles(delta) {
3830
- const { particles, actualOptions } = this.#container;
3831
- this.clear();
4088
+ const { particles, actualOptions } = this.#container, clearedPlugin = this.clear();
3832
4089
  particles.update(delta);
3833
4090
  this.draw(ctx => {
3834
4091
  const width = this.#canvasManager.size.width, height = this.#canvasManager.size.height;
@@ -3850,7 +4107,9 @@
3850
4107
  }
3851
4108
  }
3852
4109
  for (const plugin of this.#getLayerPlugins(DrawLayer.BackgroundMask)) {
3853
- plugin.canvasPaint?.();
4110
+ if (plugin !== clearedPlugin) {
4111
+ plugin.canvasPaint?.();
4112
+ }
3854
4113
  }
3855
4114
  for (const plugin of this.#getLayerPlugins(DrawLayer.CanvasSetup)) {
3856
4115
  plugin.drawSettingsSetup?.(ctx, delta);
@@ -3882,35 +4141,7 @@
3882
4141
  this.#layers[layer] = [];
3883
4142
  }
3884
4143
  }
3885
- for (const plugin of this.#container.plugins) {
3886
- if (plugin.particleFillColor ?? plugin.particleStrokeColor) {
3887
- this.#colorPlugins.push(plugin);
3888
- }
3889
- if (plugin.drawParticle) {
3890
- this.#drawParticlePlugins.push(plugin);
3891
- }
3892
- if (plugin.drawParticleSetup) {
3893
- this.#drawParticlesSetupPlugins.push(plugin);
3894
- }
3895
- if (plugin.drawParticleCleanup) {
3896
- this.#drawParticlesCleanupPlugins.push(plugin);
3897
- }
3898
- if (plugin.canvasClear) {
3899
- this.#canvasClearPlugins.push(plugin);
3900
- }
3901
- if (plugin.canvasPaint) {
3902
- this.#getLayerPlugins(DrawLayer.BackgroundMask).push(plugin);
3903
- }
3904
- if (plugin.drawSettingsSetup) {
3905
- this.#getLayerPlugins(DrawLayer.CanvasSetup).push(plugin);
3906
- }
3907
- if (plugin.draw) {
3908
- this.#getLayerPlugins(DrawLayer.PluginContent).push(plugin);
3909
- }
3910
- if (plugin.clearDraw ?? plugin.drawSettingsCleanup) {
3911
- this.#getLayerPlugins(DrawLayer.CanvasCleanup).push(plugin);
3912
- }
3913
- }
4144
+ this.#initPluginsArray();
3914
4145
  }
3915
4146
  initUpdaters() {
3916
4147
  this.#preDrawUpdaters = [];
@@ -4119,6 +4350,45 @@
4119
4350
  this.#reusablePluginColors[sColorIndex] = sColor;
4120
4351
  return this.#reusablePluginColors;
4121
4352
  }
4353
+ #initLayerPlugin(plugin) {
4354
+ const layerMap = [
4355
+ [DrawLayer.BackgroundMask, !!plugin.canvasPaint],
4356
+ [DrawLayer.CanvasSetup, !!plugin.drawSettingsSetup],
4357
+ [DrawLayer.PluginContent, !!plugin.draw],
4358
+ [DrawLayer.CanvasCleanup, !!(plugin.clearDraw ?? plugin.drawSettingsCleanup)],
4359
+ ];
4360
+ for (const [layer, active] of layerMap) {
4361
+ if (active) {
4362
+ this.#layers[layer].push(plugin);
4363
+ }
4364
+ }
4365
+ }
4366
+ #initPluginsArray() {
4367
+ for (const plugin of this.#container.plugins) {
4368
+ if (plugin.particleFillColor ?? plugin.particleStrokeColor) {
4369
+ this.#colorPlugins.push(plugin);
4370
+ }
4371
+ if (plugin.drawParticle) {
4372
+ this.#drawParticlePlugins.push(plugin);
4373
+ }
4374
+ if (plugin.drawParticleSetup) {
4375
+ this.#drawParticlesSetupPlugins.push(plugin);
4376
+ }
4377
+ if (plugin.drawParticleCleanup) {
4378
+ this.#drawParticlesCleanupPlugins.push(plugin);
4379
+ }
4380
+ if (plugin.canvasClear) {
4381
+ this.#canvasClearPlugins.push(plugin);
4382
+ }
4383
+ this.#initLayerPlugin(plugin);
4384
+ }
4385
+ }
4386
+ #isSupportedElement(element) {
4387
+ return ((typeof HTMLCanvasElement !== "undefined" && element instanceof HTMLCanvasElement) ||
4388
+ (typeof OffscreenCanvas !== "undefined" && element instanceof OffscreenCanvas) ||
4389
+ (typeof HTMLVideoElement !== "undefined" && element instanceof HTMLVideoElement) ||
4390
+ (typeof HTMLImageElement !== "undefined" && element instanceof HTMLImageElement));
4391
+ }
4122
4392
  #resolveBackgroundElement() {
4123
4393
  const background = this.#container.actualOptions.background;
4124
4394
  this.#backgroundElement = null;
@@ -4128,7 +4398,7 @@
4128
4398
  if (typeof background.element === "string") {
4129
4399
  if (typeof document !== "undefined") {
4130
4400
  const node = document.querySelector(background.element);
4131
- if (node instanceof HTMLCanvasElement || node instanceof HTMLVideoElement || node instanceof HTMLImageElement) {
4401
+ if (node && this.#isSupportedElement(node)) {
4132
4402
  this.#backgroundElement = node;
4133
4403
  }
4134
4404
  else if (node) {
@@ -4139,10 +4409,7 @@
4139
4409
  }
4140
4410
  }
4141
4411
  }
4142
- else if (background.element instanceof HTMLCanvasElement ||
4143
- background.element instanceof OffscreenCanvas ||
4144
- background.element instanceof HTMLVideoElement ||
4145
- background.element instanceof HTMLImageElement) {
4412
+ else if (this.#isSupportedElement(background.element)) {
4146
4413
  this.#backgroundElement = background.element;
4147
4414
  }
4148
4415
  }
@@ -4160,7 +4427,7 @@
4160
4427
  return transferredCanvas;
4161
4428
  }
4162
4429
  if (typeof canvas.transferControlToOffscreen !== "function") {
4163
- throw new TypeError("OffscreenCanvas is required but not supported by this browser");
4430
+ throw new TypeError(getErrorMessage(ErrorCodes$2.offscreenCanvasUnsupported));
4164
4431
  }
4165
4432
  try {
4166
4433
  const offscreenCanvas = canvas.transferControlToOffscreen();
@@ -4168,10 +4435,16 @@
4168
4435
  return offscreenCanvas;
4169
4436
  }
4170
4437
  catch {
4171
- throw new TypeError("OffscreenCanvas transfer failed");
4438
+ throw new TypeError(getErrorMessage(ErrorCodes$2.offscreenCanvasTransferFailed));
4172
4439
  }
4173
4440
  }, isHtmlCanvasElement = (canvas) => {
4174
4441
  return typeof HTMLCanvasElement !== "undefined" && canvas instanceof HTMLCanvasElement;
4442
+ }, getEffectiveColorSpace = (context) => {
4443
+ if (!context) {
4444
+ return undefined;
4445
+ }
4446
+ const colorInfo = context;
4447
+ return colorInfo.getContextAttributes?.().colorSpace ?? undefined;
4175
4448
  };
4176
4449
  function setStyle(canvas, style, important = false) {
4177
4450
  if (!style) {
@@ -4210,6 +4483,7 @@
4210
4483
  zoom = defaultZoom;
4211
4484
  #container;
4212
4485
  #generated;
4486
+ #hdrMediaListeners;
4213
4487
  #mutationObserver;
4214
4488
  #originalStyle;
4215
4489
  #pluginManager;
@@ -4274,7 +4548,6 @@
4274
4548
  });
4275
4549
  this.resize();
4276
4550
  this.#initStyle();
4277
- this.initBackground();
4278
4551
  this.#safeMutationObserver(obs => {
4279
4552
  const element = this.domElement;
4280
4553
  if (!element || !(element instanceof Node)) {
@@ -4284,6 +4557,8 @@
4284
4557
  });
4285
4558
  this.initPlugins();
4286
4559
  this.#initContext();
4560
+ this.initBackground();
4561
+ this.#initHdrListeners();
4287
4562
  this.render.init();
4288
4563
  }
4289
4564
  initBackground() {
@@ -4293,7 +4568,8 @@
4293
4568
  }
4294
4569
  const elementStyle = element.style, color = rangeColorToRgb(this.#pluginManager, background.color);
4295
4570
  if (color) {
4296
- elementStyle.backgroundColor = getStyleFromRgb(color, container.actualOptions.hdr, background.opacity);
4571
+ const hdrOptions = container.actualOptions.hdr;
4572
+ elementStyle.backgroundColor = getStyleFromRgb(color, container.hdr, background.opacity, hdrOptions.peakNits, toEnumValue(HdrMode, hdrOptions.mode, HdrMode.standard));
4297
4573
  }
4298
4574
  else {
4299
4575
  elementStyle.backgroundColor = "";
@@ -4390,6 +4666,7 @@
4390
4666
  obs.disconnect();
4391
4667
  });
4392
4668
  this.#mutationObserver = undefined;
4669
+ this.#removeHdrListeners();
4393
4670
  this.render.stop();
4394
4671
  }
4395
4672
  async windowResize() {
@@ -4409,9 +4686,16 @@
4409
4686
  }
4410
4687
  }
4411
4688
  #initContext() {
4412
- const container = this.#container, canSupportHdr = container.actualOptions.hdr &&
4689
+ const container = this.#container, canSupportHdr = container.actualOptions.hdr.enable &&
4413
4690
  safeMatchMedia("(color-gamut: p3)")?.matches &&
4414
4691
  safeMatchMedia("(dynamic-range: high)")?.matches;
4692
+ container.hdrMode = toEnumValue(HdrMode, container.actualOptions.hdr.mode, HdrMode.standard);
4693
+ container.peakNits = container.actualOptions.hdr.peakNits;
4694
+ const renderCanvas = this.renderCanvas;
4695
+ if (!renderCanvas) {
4696
+ container.hdr = canSupportHdr ?? false;
4697
+ return;
4698
+ }
4415
4699
  this.render.setContextSettings({
4416
4700
  alpha: true,
4417
4701
  desynchronized: true,
@@ -4420,11 +4704,51 @@
4420
4704
  ? { colorSpace: "display-p3", colorType: "float16" }
4421
4705
  : { colorSpace: "srgb" }),
4422
4706
  });
4423
- const renderCanvas = this.renderCanvas;
4424
- if (!renderCanvas) {
4425
- return;
4707
+ let context;
4708
+ try {
4709
+ context = renderCanvas.getContext("2d", this.render.settings);
4710
+ }
4711
+ catch {
4712
+ context = null;
4713
+ }
4714
+ if (canSupportHdr && !context) {
4715
+ const sdrSettings = {
4716
+ alpha: true,
4717
+ desynchronized: true,
4718
+ willReadFrequently: false,
4719
+ colorSpace: "srgb",
4720
+ };
4721
+ this.render.setContextSettings(sdrSettings);
4722
+ try {
4723
+ context = renderCanvas.getContext("2d", sdrSettings);
4724
+ }
4725
+ catch {
4726
+ context = null;
4727
+ }
4426
4728
  }
4427
- this.render.setContext(renderCanvas.getContext("2d", this.render.settings));
4729
+ this.render.setContext(context);
4730
+ if (context) {
4731
+ const effectiveColorSpace = getEffectiveColorSpace(context);
4732
+ if (effectiveColorSpace !== undefined) {
4733
+ container.hdr = effectiveColorSpace === "display-p3";
4734
+ }
4735
+ }
4736
+ }
4737
+ #initHdrListeners() {
4738
+ this.#removeHdrListeners();
4739
+ const p3Query = safeMatchMedia("(color-gamut: p3)"), hdrQuery = safeMatchMedia("(dynamic-range: high)"), handleChange = () => {
4740
+ this.#initContext();
4741
+ this.initBackground();
4742
+ }, listeners = [];
4743
+ if (p3Query) {
4744
+ p3Query.addEventListener("change", handleChange);
4745
+ listeners.push({ handler: handleChange, mql: p3Query });
4746
+ }
4747
+ if (hdrQuery) {
4748
+ hdrQuery.addEventListener("change", handleChange);
4749
+ listeners.push({ handler: handleChange, mql: hdrQuery });
4750
+ }
4751
+ this.#hdrMediaListeners = listeners;
4428
4752
  }
4429
4753
  #initStyle() {
4430
4754
  const element = this.domElement, options = this.#container.actualOptions;
@@ -4448,6 +4772,15 @@
4448
4772
  element.style.setProperty(key, value, "important");
4449
4773
  }
4450
4774
  }
4775
+ #removeHdrListeners() {
4776
+ if (!this.#hdrMediaListeners) {
4777
+ return;
4778
+ }
4779
+ for (const { handler, mql } of this.#hdrMediaListeners) {
4780
+ mql.removeEventListener("change", handler);
4781
+ }
4782
+ this.#hdrMediaListeners = undefined;
4783
+ }
4451
4784
  #repairStyle() {
4452
4785
  const element = this.domElement;
4453
4786
  if (!element) {
@@ -4537,8 +4870,7 @@
4537
4870
  this.#resizeTimeout = undefined;
4538
4871
  }
4539
4872
  const handleResize = async () => {
4540
- const canvas = this.#container.canvas;
4541
- await canvas.windowResize();
4873
+ await this.#container.canvas.windowResize();
4542
4874
  };
4543
4875
  this.#resizeTimeout = setTimeout(() => void handleResize(), this.#container.actualOptions.resize.delay * millisecondsToSeconds);
4544
4876
  }
@@ -4566,8 +4898,8 @@
4566
4898
  }
4567
4899
  else if (!this.#resizeObserver && add && canvasEl) {
4568
4900
  this.#resizeObserver = new ResizeObserver((entries) => {
4569
- const entry = entries.find(e => e.target === canvasEl);
4570
- if (!entry) {
4901
+ const res = entries.some(e => e.target === canvasEl);
4902
+ if (!res) {
4571
4903
  return;
4572
4904
  }
4573
4905
  this.#handleWindowResize();
@@ -4831,10 +5163,10 @@
4831
5163
  return this.#modifiers.find(m => m.id === id);
4832
5164
  }
4833
5165
  getOpacity() {
4834
- 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;
4835
- this.#cachedOpacityData.fillOpacity = opacity * fillOpacity * zOpacityFactor;
5166
+ 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;
5167
+ this.#cachedOpacityData.fillOpacity = this.fillOpacity ?? defaultOpacity$1;
4836
5168
  this.#cachedOpacityData.opacity = opacity * zOpacityFactor;
4837
- this.#cachedOpacityData.strokeOpacity = opacity * strokeOpacity * zOpacityFactor;
5169
+ this.#cachedOpacityData.strokeOpacity = this.strokeOpacity ?? defaultOpacity$1;
4838
5170
  return this.#cachedOpacityData;
4839
5171
  }
4840
5172
  getPosition() {
@@ -5081,7 +5413,7 @@
5081
5413
  #initPosition(position) {
5082
5414
  const container = this.#container, zIndexValue = Math.floor(getRangeValue(this.options.zIndex.value)), initialPosition = this.#calcPosition(position, clamp(zIndexValue, minZ, container.zLayers));
5083
5415
  if (!initialPosition) {
5084
- throw new Error("a valid position cannot be found for particle");
5416
+ throw new Error(getErrorMessage(ErrorCodes$2.particlePositionNotFound));
5085
5417
  }
5086
5418
  this.position = initialPosition;
5087
5419
  this.initialPosition = this.position.copy();
@@ -5130,6 +5462,12 @@
5130
5462
  this.#circlePoolIdx = 0;
5131
5463
  this.#rectanglePoolIdx = 0;
5132
5464
  }
5465
+ get cellSize() {
5466
+ return this.#cellSize;
5467
+ }
5468
+ set cellSize(value) {
5469
+ this.#pendingCellSize = value;
5470
+ }
5133
5471
  clear() {
5134
5472
  this.#cells.clear();
5135
5473
  const pendingCellSize = this.#pendingCellSize;
@@ -5153,18 +5491,7 @@
5153
5491
  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);
5154
5492
  for (let cx = minCellX; cx <= maxCellX; cx++) {
5155
5493
  for (let cy = minCellY; cy <= maxCellY; cy++) {
5156
- const key = `${cx}_${cy}`, cellParticles = this.#cells.get(key);
5157
- if (!cellParticles) {
5158
- continue;
5159
- }
5160
- for (const p of cellParticles) {
5161
- if (check && !check(p)) {
5162
- continue;
5163
- }
5164
- if (range.contains(p.getPosition())) {
5165
- out.push(p);
5166
- }
5167
- }
5494
+ this.#queryCell(cx, cy, range, check, out);
5168
5495
  }
5169
5496
  }
5170
5497
  return out;
@@ -5179,14 +5506,23 @@
5179
5506
  this.#releaseShapes();
5180
5507
  return result;
5181
5508
  }
5182
- setCellSize(cellSize) {
5183
- this.#pendingCellSize = cellSize;
5184
- }
5185
5509
  #acquireCircle(x, y, r) {
5186
- return (this.#circlePool[this.#circlePoolIdx++] ??= new Circle(x, y, r)).reset(x, y, r);
5510
+ const idx = this.#circlePoolIdx++;
5511
+ let circle = this.#circlePool[idx];
5512
+ if (!circle) {
5513
+ circle = new Circle(x, y, r);
5514
+ this.#circlePool[idx] = circle;
5515
+ }
5516
+ return circle.reset(x, y, r);
5187
5517
  }
5188
5518
  #acquireRectangle(x, y, w, h) {
5189
- return (this.#rectanglePool[this.#rectanglePoolIdx++] ??= new Rectangle(x, y, w, h)).reset(x, y, w, h);
5519
+ const idx = this.#rectanglePoolIdx++;
5520
+ let rectangle = this.#rectanglePool[idx];
5521
+ if (!rectangle) {
5522
+ rectangle = new Rectangle(x, y, w, h);
5523
+ this.#rectanglePool[idx] = rectangle;
5524
+ }
5525
+ return rectangle.reset(x, y, w, h);
5190
5526
  }
5191
5527
  #cellKeyFromCoords(x, y) {
5192
5528
  const cellX = Math.floor(x / this.#cellSize), cellY = Math.floor(y / this.#cellSize);
@@ -5213,6 +5549,20 @@
5213
5549
  }
5214
5550
  return null;
5215
5551
  }
5552
+ #queryCell(cx, cy, range, check, out) {
5553
+ const cellParticles = this.#cells.get(`${cx}_${cy}`);
5554
+ if (!cellParticles) {
5555
+ return;
5556
+ }
5557
+ for (const p of cellParticles) {
5558
+ if (check && !check(p)) {
5559
+ continue;
5560
+ }
5561
+ if (range.contains(p.getPosition())) {
5562
+ out.push(p);
5563
+ }
5564
+ }
5565
+ }
5216
5566
  #releaseShapes() {
5217
5567
  this.#circlePoolIdx = 0;
5218
5568
  this.#rectanglePoolIdx = 0;
@@ -5221,9 +5571,9 @@
5221
5571
 
5222
5572
  class ParticlesManager {
5223
5573
  checkParticlePositionPlugins;
5224
- grid;
5225
5574
  #array;
5226
5575
  #container;
5576
+ #grid;
5227
5577
  #groupLimits;
5228
5578
  #limit;
5229
5579
  #nextId;
@@ -5247,7 +5597,7 @@
5247
5597
  this.#groupLimits = new Map();
5248
5598
  this.#particleBuckets = new Map();
5249
5599
  this.#zBuckets = this.#createBuckets(this.#container.zLayers);
5250
- this.grid = new SpatialHashGrid(spatialHashGridCellSize);
5600
+ this.#grid = new SpatialHashGrid(spatialHashGridCellSize);
5251
5601
  this.checkParticlePositionPlugins = [];
5252
5602
  this.#particleResetPlugins = [];
5253
5603
  this.#particleUpdatePlugins = [];
@@ -5258,23 +5608,12 @@
5258
5608
  get count() {
5259
5609
  return this.#array.length;
5260
5610
  }
5611
+ get grid() {
5612
+ return this.#grid;
5613
+ }
5261
5614
  addParticle(position, overrideOptions, group, initializer) {
5262
- const limitMode = this.#container.actualOptions.particles.number.limit.mode, limit = group === undefined ? this.#limit : (this.#groupLimits.get(group) ?? this.#limit), currentCount = this.count;
5263
- if (limit > minLimit) {
5264
- switch (limitMode) {
5265
- case LimitMode.delete: {
5266
- const countToRemove = currentCount + countOffset - limit;
5267
- if (countToRemove > minCount) {
5268
- this.removeQuantity(countToRemove);
5269
- }
5270
- break;
5271
- }
5272
- case LimitMode.wait:
5273
- if (currentCount >= limit) {
5274
- return;
5275
- }
5276
- break;
5277
- }
5615
+ if (this.#checkAndApplyLimits(group, this.count)) {
5616
+ return;
5278
5617
  }
5279
5618
  try {
5280
5619
  const particle = this.#pool.pop() ?? new Particle(this.#pluginManager, this.#container);
@@ -5338,7 +5677,7 @@
5338
5677
  return this.#array[index];
5339
5678
  }
5340
5679
  async init() {
5341
- const container = this.#container, options = container.actualOptions;
5680
+ const container = this.#container;
5342
5681
  this.checkParticlePositionPlugins = [];
5343
5682
  this.#updatePlugins = [];
5344
5683
  this.#particleUpdatePlugins = [];
@@ -5347,59 +5686,16 @@
5347
5686
  this.#postParticleUpdatePlugins = [];
5348
5687
  this.#particleBuckets.clear();
5349
5688
  this.#resetBuckets(container.zLayers);
5350
- this.grid = new SpatialHashGrid(spatialHashGridCellSize * container.retina.pixelRatio);
5351
- for (const plugin of container.plugins) {
5352
- if (plugin.redrawInit) {
5353
- await plugin.redrawInit();
5354
- }
5355
- if (plugin.checkParticlePosition) {
5356
- this.checkParticlePositionPlugins.push(plugin);
5357
- }
5358
- if (plugin.update) {
5359
- this.#updatePlugins.push(plugin);
5360
- }
5361
- if (plugin.particleUpdate) {
5362
- this.#particleUpdatePlugins.push(plugin);
5363
- }
5364
- if (plugin.postUpdate) {
5365
- this.#postUpdatePlugins.push(plugin);
5366
- }
5367
- if (plugin.particleReset) {
5368
- this.#particleResetPlugins.push(plugin);
5369
- }
5370
- if (plugin.postParticleUpdate) {
5371
- this.#postParticleUpdatePlugins.push(plugin);
5372
- }
5373
- }
5374
- await this.#container.initDrawersAndUpdaters();
5375
- for (const drawer of this.#container.effectDrawers.values()) {
5376
- await drawer.init?.(container);
5377
- }
5378
- for (const drawer of this.#container.shapeDrawers.values()) {
5379
- await drawer.init?.(container);
5380
- }
5381
- let handled = false;
5382
- for (const plugin of container.plugins) {
5383
- handled = plugin.particlesInitialization?.() ?? handled;
5384
- if (handled) {
5385
- break;
5386
- }
5387
- }
5388
- if (!handled) {
5389
- const particlesOptions = options.particles, groups = particlesOptions.groups;
5390
- for (const group in groups) {
5391
- const groupOptions = groups[group];
5392
- if (!groupOptions) {
5393
- continue;
5394
- }
5395
- for (let i = this.count, j = 0; j < groupOptions.number.value && i < particlesOptions.number.value; i++, j++) {
5396
- this.addParticle(undefined, groupOptions, group);
5397
- }
5398
- }
5399
- for (let i = this.count; i < particlesOptions.number.value; i++) {
5400
- this.addParticle();
5689
+ this.#grid = new SpatialHashGrid(spatialHashGridCellSize * container.retina.pixelRatio);
5690
+ this.#applyLimits(container.actualOptions.particles);
5691
+ const particlesOptions = container.actualOptions.particles, groups = particlesOptions.groups;
5692
+ for (const group in groups) {
5693
+ const groupData = groups[group];
5694
+ if (groupData) {
5695
+ this.#applyLimits(loadParticlesOptions(this.#pluginManager, this.#container, groupData), group, groupData);
5401
5696
  }
5402
5697
  }
5698
+ await this.#initPlugins();
5403
5699
  }
5404
5700
  push(nb, position, overrideOptions, group) {
5405
5701
  for (let i = 0; i < nb; i++) {
@@ -5414,13 +5710,13 @@
5414
5710
  remove(particle, group, override) {
5415
5711
  this.removeAt(this.#array.indexOf(particle), undefined, group, override);
5416
5712
  }
5417
- removeAt(index, quantity = defaultRemoveQuantity, group, override) {
5713
+ removeAt(index, quantity = defaultRemoveQuantity, group, override, matchGroup = true) {
5418
5714
  if (index < minIndex || index > this.count) {
5419
5715
  return;
5420
5716
  }
5421
5717
  let deleted = 0;
5422
5718
  for (let i = index; deleted < quantity && i < this.count; i++) {
5423
- if (this.#removeParticle(i, group, override)) {
5719
+ if (this.#removeParticle(i, group, override, matchGroup)) {
5424
5720
  i--;
5425
5721
  deleted++;
5426
5722
  }
@@ -5451,7 +5747,7 @@
5451
5747
  this.#resizeFactor = factor;
5452
5748
  }
5453
5749
  update(delta) {
5454
- this.grid.clear();
5750
+ this.#grid.clear();
5455
5751
  for (const plugin of this.#updatePlugins) {
5456
5752
  plugin.update?.(delta);
5457
5753
  }
@@ -5462,7 +5758,7 @@
5462
5758
  this.#updateParticlesPhase2(delta, particlesToDelete);
5463
5759
  if (particlesToDelete.size) {
5464
5760
  for (const particle of particlesToDelete) {
5465
- this.remove(particle);
5761
+ this.remove(particle, particle.group);
5466
5762
  }
5467
5763
  }
5468
5764
  this.#resizeFactor = undefined;
@@ -5473,12 +5769,7 @@
5473
5769
  #applyDensity(options, pluginsCount, group, groupOptions) {
5474
5770
  const numberOptions = options.number;
5475
5771
  if (!numberOptions.density.enable) {
5476
- if (group === undefined) {
5477
- this.#limit = numberOptions.limit.value;
5478
- }
5479
- else if (groupOptions?.number.limit.value ?? numberOptions.limit.value) {
5480
- this.#groupLimits.set(group, groupOptions?.number.limit.value ?? numberOptions.limit.value);
5481
- }
5772
+ this.#applyLimits(options, group, groupOptions);
5482
5773
  return;
5483
5774
  }
5484
5775
  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);
@@ -5486,7 +5777,10 @@
5486
5777
  this.#limit = numberOptions.limit.value * densityFactor;
5487
5778
  }
5488
5779
  else {
5489
- this.#groupLimits.set(group, numberOptions.limit.value * densityFactor);
5780
+ this.#groupLimits.set(group, {
5781
+ limit: numberOptions.limit.value * densityFactor,
5782
+ mode: toEnumValue(LimitMode, numberOptions.limit.mode, LimitMode.delete),
5783
+ });
5490
5784
  }
5491
5785
  if (particlesCount < particlesNumber) {
5492
5786
  this.push(Math.abs(particlesNumber - particlesCount), undefined, options, group);
@@ -5495,6 +5789,55 @@
5495
5789
  this.removeQuantity(particlesCount - particlesNumber, group);
5496
5790
  }
5497
5791
  }
5792
+ #applyLimits(options, group, groupOptions) {
5793
+ if (group === undefined) {
5794
+ this.#limit = options.number.limit.value;
5795
+ const groups = this.#container.actualOptions.particles.groups;
5796
+ for (const existingGroup of this.#groupLimits.keys()) {
5797
+ if (!(existingGroup in groups)) {
5798
+ this.#groupLimits.delete(existingGroup);
5799
+ }
5800
+ }
5801
+ }
5802
+ else {
5803
+ const limitValue = groupOptions?.number?.limit?.value ?? options.number.limit.value;
5804
+ if (limitValue > minLimit) {
5805
+ this.#groupLimits.set(group, {
5806
+ limit: limitValue,
5807
+ mode: toEnumValue(LimitMode, groupOptions?.number?.limit?.mode ?? options.number.limit.mode, LimitMode.delete),
5808
+ });
5809
+ }
5810
+ else {
5811
+ this.#groupLimits.delete(group);
5812
+ }
5813
+ }
5814
+ }
5815
+ #checkAndApplyLimits(group, currentCount) {
5816
+ const globalLimit = this.#limit, globalMode = this.#container.actualOptions.particles.number.limit.mode;
5817
+ if (globalLimit > minLimit && globalMode === LimitMode.wait && currentCount >= globalLimit) {
5818
+ return true;
5819
+ }
5820
+ const groupLimitEntry = group === undefined ? undefined : this.#groupLimits.get(group);
5821
+ if (groupLimitEntry && groupLimitEntry.limit > minLimit && groupLimitEntry.mode === LimitMode.wait) {
5822
+ const groupCount = this.filter(t => t.group === group).length;
5823
+ if (groupCount >= groupLimitEntry.limit) {
5824
+ return true;
5825
+ }
5826
+ }
5827
+ if (groupLimitEntry && groupLimitEntry.limit > minLimit && groupLimitEntry.mode === LimitMode.delete) {
5828
+ const groupCountToRemove = this.filter(t => t.group === group).length + countOffset - groupLimitEntry.limit;
5829
+ if (groupCountToRemove > minCount) {
5830
+ this.removeQuantity(groupCountToRemove, group);
5831
+ }
5832
+ }
5833
+ if (globalLimit > minLimit && globalMode === LimitMode.delete) {
5834
+ const globalCountToRemove = this.count + countOffset - globalLimit;
5835
+ if (globalCountToRemove > minCount) {
5836
+ this.#removeAny(globalCountToRemove);
5837
+ }
5838
+ }
5839
+ return false;
5840
+ }
5498
5841
  #createBuckets(zLayers) {
5499
5842
  const bucketCount = Math.max(Math.floor(zLayers), one);
5500
5843
  return Array.from({ length: bucketCount }, () => []);
@@ -5517,6 +5860,70 @@
5517
5860
  }
5518
5861
  return ((canvasSize.width * canvasSize.height) / (densityOptions.height * densityOptions.width * pxRatio ** squareExp));
5519
5862
  }
5863
+ async #initDrawersAndUpdaters() {
5864
+ const container = this.#container;
5865
+ await container.initDrawersAndUpdaters();
5866
+ for (const drawer of container.effectDrawers.values()) {
5867
+ await drawer.init?.(container);
5868
+ }
5869
+ for (const drawer of container.shapeDrawers.values()) {
5870
+ await drawer.init?.(container);
5871
+ }
5872
+ }
5873
+ async #initPlugins() {
5874
+ await this.#initPluginsArrays();
5875
+ await this.#initDrawersAndUpdaters();
5876
+ let handled = false;
5877
+ const container = this.#container;
5878
+ for (const plugin of container.plugins) {
5879
+ handled = plugin.particlesInitialization?.() ?? handled;
5880
+ if (handled) {
5881
+ break;
5882
+ }
5883
+ }
5884
+ if (handled) {
5885
+ return;
5886
+ }
5887
+ const particlesOptions = container.actualOptions.particles, groups = particlesOptions.groups;
5888
+ for (const group in groups) {
5889
+ const groupOptions = groups[group];
5890
+ if (!groupOptions) {
5891
+ continue;
5892
+ }
5893
+ for (let i = this.count, j = 0; j < groupOptions.number.value && i < particlesOptions.number.value; i++, j++) {
5894
+ this.addParticle(undefined, groupOptions, group);
5895
+ }
5896
+ }
5897
+ for (let i = this.count; i < particlesOptions.number.value; i++) {
5898
+ this.addParticle();
5899
+ }
5900
+ }
5901
+ async #initPluginsArrays() {
5902
+ const container = this.#container;
5903
+ for (const plugin of container.plugins) {
5904
+ if (plugin.redrawInit) {
5905
+ await plugin.redrawInit();
5906
+ }
5907
+ if (plugin.checkParticlePosition) {
5908
+ this.checkParticlePositionPlugins.push(plugin);
5909
+ }
5910
+ if (plugin.update) {
5911
+ this.#updatePlugins.push(plugin);
5912
+ }
5913
+ if (plugin.particleUpdate) {
5914
+ this.#particleUpdatePlugins.push(plugin);
5915
+ }
5916
+ if (plugin.postUpdate) {
5917
+ this.#postUpdatePlugins.push(plugin);
5918
+ }
5919
+ if (plugin.particleReset) {
5920
+ this.#particleResetPlugins.push(plugin);
5921
+ }
5922
+ if (plugin.postParticleUpdate) {
5923
+ this.#postParticleUpdatePlugins.push(plugin);
5924
+ }
5925
+ }
5926
+ }
5520
5927
  #insertParticleIntoBucket(particle) {
5521
5928
  const bucketIndex = this.#getBucketIndex(particle.position.z), bucket = this.#zBuckets[bucketIndex];
5522
5929
  if (!bucket) {
@@ -5525,12 +5932,15 @@
5525
5932
  bucket.push(particle);
5526
5933
  this.#particleBuckets.set(particle.id, bucketIndex);
5527
5934
  }
5528
- #removeParticle(index, group, override) {
5935
+ #removeAny(quantity) {
5936
+ this.removeAt(minIndex, quantity, undefined, undefined, false);
5937
+ }
5938
+ #removeParticle(index, group, override, matchGroup = true) {
5529
5939
  const particle = this.#array[index];
5530
5940
  if (!particle) {
5531
5941
  return false;
5532
5942
  }
5533
- if (particle.group !== group) {
5943
+ if (matchGroup && particle.group !== group) {
5534
5944
  return false;
5535
5945
  }
5536
5946
  this.#array.splice(index, deleteCount);
@@ -5617,7 +6027,7 @@
5617
6027
  particlesToDelete.add(particle);
5618
6028
  continue;
5619
6029
  }
5620
- this.grid.insert(particle);
6030
+ this.#grid.insert(particle);
5621
6031
  }
5622
6032
  return particlesToDelete;
5623
6033
  }
@@ -5689,6 +6099,7 @@
5689
6099
  effectDrawers;
5690
6100
  fpsLimit;
5691
6101
  hdr;
6102
+ hdrMode;
5692
6103
  id;
5693
6104
  pageHidden;
5694
6105
  particleCreatedPlugins;
@@ -5696,6 +6107,7 @@
5696
6107
  particlePositionPlugins;
5697
6108
  particleUpdaters;
5698
6109
  particles;
6110
+ peakNits;
5699
6111
  plugins;
5700
6112
  retina;
5701
6113
  shapeDrawers;
@@ -5726,6 +6138,8 @@
5726
6138
  this.id = Symbol(id);
5727
6139
  this.fpsLimit = 120;
5728
6140
  this.hdr = false;
6141
+ this.hdrMode = HdrMode.standard;
6142
+ this.peakNits = 400;
5729
6143
  this.#smooth = false;
5730
6144
  this.#delay = 0;
5731
6145
  this.#duration = 0;
@@ -5789,7 +6203,6 @@
5789
6203
  this.shapeDrawers = new Map();
5790
6204
  this.particleUpdaters = [];
5791
6205
  this.plugins.length = 0;
5792
- this.#pluginManager.clearPlugins(this);
5793
6206
  this.destroyed = true;
5794
6207
  this.#onDestroy(remove);
5795
6208
  this.dispatchEvent(EventType.containerDestroyed);
@@ -5842,31 +6255,15 @@
5842
6255
  await this.initDrawersAndUpdaters();
5843
6256
  this.#options = loadContainerOptions(this.#pluginManager, this, this.#initialSourceOptions, this.sourceOptions);
5844
6257
  this.actualOptions = loadContainerOptions(this.#pluginManager, this, this.#options);
5845
- this.plugins.length = 0;
5846
- this.particleDestroyedPlugins.length = 0;
5847
- this.particleCreatedPlugins.length = 0;
5848
- this.particlePositionPlugins.length = 0;
5849
- for (const [plugin, containerPlugin] of allContainerPlugins) {
5850
- if (plugin.needsPlugin(this.actualOptions)) {
5851
- this.plugins.push(containerPlugin);
5852
- if (containerPlugin.particleCreated) {
5853
- this.particleCreatedPlugins.push(containerPlugin);
5854
- }
5855
- if (containerPlugin.particleDestroyed) {
5856
- this.particleDestroyedPlugins.push(containerPlugin);
5857
- }
5858
- if (containerPlugin.particlePosition) {
5859
- this.particlePositionPlugins.push(containerPlugin);
5860
- }
5861
- }
5862
- }
6258
+ this.#initPlugins(allContainerPlugins);
5863
6259
  this.retina.init();
5864
6260
  this.canvas.init();
5865
6261
  this.updateActualOptions();
5866
6262
  this.canvas.initBackground();
5867
6263
  this.canvas.resize();
5868
- const { delay, duration, fpsLimit, hdr, smooth, zLayers } = this.actualOptions;
5869
- this.hdr = hdr;
6264
+ const { delay, duration, fpsLimit, smooth, zLayers } = this.actualOptions, hdrOptions = this.actualOptions.hdr;
6265
+ this.hdrMode = toEnumValue(HdrMode, hdrOptions.mode, HdrMode.standard);
6266
+ this.peakNits = hdrOptions.peakNits;
5870
6267
  this.zLayers = zLayers;
5871
6268
  this.#duration = getRangeValue(duration) * millisecondsToSeconds;
5872
6269
  this.#delay = getRangeValue(delay) * millisecondsToSeconds;
@@ -5886,9 +6283,9 @@
5886
6283
  }
5887
6284
  async initDrawersAndUpdaters() {
5888
6285
  const pluginManager = this.#pluginManager;
5889
- this.effectDrawers = await pluginManager.getEffectDrawers(this, true);
5890
- this.shapeDrawers = await pluginManager.getShapeDrawers(this, true);
5891
- this.particleUpdaters = await pluginManager.getUpdaters(this, true);
6286
+ this.effectDrawers = await getItemMapFromInitializer(this, pluginManager.initializers.effects);
6287
+ this.shapeDrawers = await getItemMapFromInitializer(this, pluginManager.initializers.shapes);
6288
+ this.particleUpdaters = await getItemsFromInitializer(this, pluginManager.initializers.updaters);
5892
6289
  }
5893
6290
  pause() {
5894
6291
  if (!guardCheck(this)) {
@@ -5999,6 +6396,27 @@
5999
6396
  }
6000
6397
  return refresh;
6001
6398
  }
6399
+ #initPlugins(allContainerPlugins) {
6400
+ this.plugins.length = 0;
6401
+ this.particleDestroyedPlugins.length = 0;
6402
+ this.particleCreatedPlugins.length = 0;
6403
+ this.particlePositionPlugins.length = 0;
6404
+ for (const [plugin, containerPlugin] of allContainerPlugins) {
6405
+ if (!plugin.needsPlugin(this.actualOptions)) {
6406
+ continue;
6407
+ }
6408
+ this.plugins.push(containerPlugin);
6409
+ if (containerPlugin.particleCreated) {
6410
+ this.particleCreatedPlugins.push(containerPlugin);
6411
+ }
6412
+ if (containerPlugin.particleDestroyed) {
6413
+ this.particleDestroyedPlugins.push(containerPlugin);
6414
+ }
6415
+ if (containerPlugin.particlePosition) {
6416
+ this.particlePositionPlugins.push(containerPlugin);
6417
+ }
6418
+ }
6419
+ }
6002
6420
  #nextFrame(timestamp) {
6003
6421
  try {
6004
6422
  if (!this.#smooth &&
@@ -6275,11 +6693,11 @@
6275
6693
  }
6276
6694
  }
6277
6695
  async #init() {
6278
- const availablePathGenerators = await this.#pluginManager.getPathGenerators?.(this.#container, true);
6279
- if (!availablePathGenerators) {
6696
+ const pluginManager = this.#pluginManager;
6697
+ if (!pluginManager.initializers.pathGenerators) {
6280
6698
  return;
6281
6699
  }
6282
- this.availablePathGenerators = availablePathGenerators;
6700
+ this.availablePathGenerators = await getItemMapFromInitializer(this.#container, pluginManager.initializers.pathGenerators);
6283
6701
  this.pathGenerators = new Map();
6284
6702
  for (const pathGenerator of this.pathGenerators.values()) {
6285
6703
  pathGenerator.init();
@@ -6292,55 +6710,6 @@
6292
6710
  MovePluginInstance: MovePluginInstance
6293
6711
  });
6294
6712
 
6295
- class EmittersPluginInstance {
6296
- #container;
6297
- #instancesManager;
6298
- constructor(instancesManager, container) {
6299
- this.#instancesManager = instancesManager;
6300
- this.#container = container;
6301
- this.#instancesManager.initContainer(container);
6302
- }
6303
- async init() {
6304
- const emittersOptions = this.#container.actualOptions.emitters;
6305
- if (isArray(emittersOptions)) {
6306
- for (const emitterOptions of emittersOptions) {
6307
- await this.#instancesManager.addEmitter(this.#container, emitterOptions);
6308
- }
6309
- }
6310
- else {
6311
- await this.#instancesManager.addEmitter(this.#container, emittersOptions);
6312
- }
6313
- }
6314
- pause() {
6315
- for (const emitter of this.#instancesManager.getArray(this.#container)) {
6316
- emitter.pause();
6317
- }
6318
- }
6319
- play() {
6320
- for (const emitter of this.#instancesManager.getArray(this.#container)) {
6321
- emitter.play();
6322
- }
6323
- }
6324
- resize() {
6325
- for (const emitter of this.#instancesManager.getArray(this.#container)) {
6326
- emitter.resize();
6327
- }
6328
- }
6329
- stop() {
6330
- this.#instancesManager.clear(this.#container);
6331
- }
6332
- update(delta) {
6333
- this.#instancesManager.getArray(this.#container).forEach(emitter => {
6334
- emitter.update(delta);
6335
- });
6336
- }
6337
- }
6338
-
6339
- var EmittersPluginInstance$1 = /*#__PURE__*/Object.freeze({
6340
- __proto__: null,
6341
- EmittersPluginInstance: EmittersPluginInstance
6342
- });
6343
-
6344
6713
  const shapeGenerators = new Map();
6345
6714
  class ShapeManager {
6346
6715
  addShapeGenerator(name, generator) {
@@ -6370,14 +6739,21 @@
6370
6739
  this.#pluginManager = pluginManager;
6371
6740
  }
6372
6741
  async addEmitter(container, options, position) {
6373
- const emitterOptions = new Emitter();
6374
- emitterOptions.load(options);
6375
- const { EmitterInstance } = await Promise.resolve().then(function () { return EmitterInstance$1; }), emitter = new EmitterInstance(this.#pluginManager, container, (emitter) => {
6376
- this.removeEmitter(container, emitter);
6377
- }, emitterOptions, position);
6378
- await emitter.init();
6379
- this.getArray(container).push(emitter);
6380
- return emitter;
6742
+ return this.addEmitters(container, [{ options, position }]).then(t => t[defaultIndex]);
6743
+ }
6744
+ async addEmitters(container, emitters) {
6745
+ const { EmitterInstance } = await Promise.resolve().then(function () { return EmitterInstance$1; }), res = [];
6746
+ for (const { options, position } of emitters) {
6747
+ const emitterOptions = new Emitter();
6748
+ emitterOptions.load(options);
6749
+ const emitter = new EmitterInstance(this.#pluginManager, container, (emitter) => {
6750
+ this.removeEmitter(container, emitter);
6751
+ }, emitterOptions, position);
6752
+ await emitter.init();
6753
+ this.getArray(container).push(emitter);
6754
+ res.push(emitter);
6755
+ }
6756
+ return res;
6381
6757
  }
6382
6758
  clear(container) {
6383
6759
  this.initContainer(container);
@@ -6404,6 +6780,7 @@
6404
6780
  : array.find(t => t.name === idxOrName);
6405
6781
  };
6406
6782
  container.addEmitter = async (options, position) => this.addEmitter(container, options, position);
6783
+ container.addEmitters = async (emitters) => this.addEmitters(container, emitters);
6407
6784
  container.removeEmitter = (idxOrName) => {
6408
6785
  const emitter = container.getEmitter?.(idxOrName);
6409
6786
  if (emitter) {
@@ -6424,7 +6801,7 @@
6424
6801
  };
6425
6802
  }
6426
6803
  removeEmitter(container, emitter) {
6427
- const index = this.getArray(container).indexOf(emitter), minIndex = 0, deleteCount = 1;
6804
+ const index = this.getArray(container).indexOf(emitter), deleteCount = 1;
6428
6805
  if (index >= minIndex) {
6429
6806
  this.getArray(container).splice(index, deleteCount);
6430
6807
  }
@@ -6454,7 +6831,7 @@
6454
6831
  let handled = false;
6455
6832
  const canvas = container.canvas;
6456
6833
  if (trailFill.color) {
6457
- canvas.render.paintBase(getStyleFromRgb(trailFill.color, container.hdr, trailFill.opacity));
6834
+ canvas.render.paintBase(getStyleFromRgb(trailFill.color, container.hdr, trailFill.opacity, container.peakNits, container.hdrMode));
6458
6835
  handled = true;
6459
6836
  }
6460
6837
  else if (trailFill.image) {
@@ -6560,6 +6937,7 @@
6560
6937
  #particlesOptions;
6561
6938
  #paused;
6562
6939
  #pluginManager;
6940
+ #positionOverride = false;
6563
6941
  #removeCallback;
6564
6942
  #resizeObserver;
6565
6943
  #shape;
@@ -6636,6 +7014,31 @@
6636
7014
  });
6637
7015
  this.play();
6638
7016
  }
7017
+ draw(context) {
7018
+ if (!this.options.draw || !this.#shape) {
7019
+ return;
7020
+ }
7021
+ const container = this.#container, fillEnabled = this.options.spawn.fill?.enable ?? true;
7022
+ context.save();
7023
+ context.beginPath();
7024
+ if (fillEnabled) {
7025
+ context.fillStyle = this.spawnFillColor
7026
+ ? getStyleFromHsl(this.spawnFillColor, container.hdr, this.spawnFillOpacity ?? defaultOpacity$1, container.peakNits, container.hdrMode)
7027
+ : getStyleFromRgb({ r: 0, g: 0, b: 0 }, container.hdr, defaultOpacity$1, container.peakNits, container.hdrMode);
7028
+ }
7029
+ if (this.spawnStrokeColor) {
7030
+ context.strokeStyle = getStyleFromHsl(this.spawnStrokeColor, container.hdr, this.spawnStrokeOpacity ?? defaultOpacity$1, container.peakNits, container.hdrMode);
7031
+ context.lineWidth = this.spawnStrokeWidth ?? defaultStrokeWidth;
7032
+ }
7033
+ this.#shape.draw?.(context);
7034
+ if (fillEnabled) {
7035
+ context.fill();
7036
+ }
7037
+ if (this.spawnStrokeColor) {
7038
+ context.stroke();
7039
+ }
7040
+ context.restore();
7041
+ }
6639
7042
  externalPause() {
6640
7043
  this.#paused = true;
6641
7044
  this.pause();
@@ -6673,11 +7076,14 @@
6673
7076
  }
6674
7077
  }
6675
7078
  resize() {
6676
- const initialPosition = this.#initialPosition, container = this.#container;
6677
- this.position =
6678
- initialPosition && isPointInside(initialPosition, container.canvas.size, Vector.origin)
6679
- ? initialPosition
6680
- : this.#calcPosition();
7079
+ const container = this.#container;
7080
+ if (!this.#positionOverride) {
7081
+ const initialPosition = this.#initialPosition;
7082
+ this.position =
7083
+ initialPosition && isPointInside(initialPosition, container.canvas.size, Vector.origin)
7084
+ ? initialPosition
7085
+ : this.#calcPosition();
7086
+ }
6681
7087
  this.#size = this.#calcSize();
6682
7088
  this.size =
6683
7089
  this.#size.mode === PixelMode.percent
@@ -6688,6 +7094,11 @@
6688
7094
  : { width: this.#size.width, height: this.#size.height };
6689
7095
  this.#shape?.resize(this.position, this.size);
6690
7096
  }
7097
+ setPosition(position) {
7098
+ this.#positionOverride = true;
7099
+ this.position = { ...position };
7100
+ this.#shape?.resize(this.position, this.size);
7101
+ }
6691
7102
  update(delta) {
6692
7103
  if (this.#paused) {
6693
7104
  return;
@@ -6883,6 +7294,7 @@
6883
7294
  exports.loadHyperspacePreset = loadHyperspacePreset;
6884
7295
  exports.tsParticles = tsParticles;
6885
7296
 
6886
- }));
7297
+ })(g.__tsParticlesInternals.presets.hyperspace = g.__tsParticlesInternals.presets.hyperspace || {});
7298
+ })(typeof globalThis !== "undefined" ? globalThis : typeof window !== "undefined" ? window : self);
7299
+
6887
7300
  Object.assign(globalThis.window || globalThis, { loadHyperspacePreset: (globalThis.__tsParticlesInternals.presets.hyperspace || {}).loadHyperspacePreset });
6888
- delete (globalThis.window || globalThis).tsparticlesInternalExports;