@tsparticles/preset-confetti-falling 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.confettiFalling = global.__tsParticlesInternals.presets.confettiFalling || {})));
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
  }
@@ -270,11 +301,61 @@
270
301
  };
271
302
  }
272
303
  function parseAlpha(input) {
273
- const defaultAlpha = 1;
274
304
  if (!input) {
275
305
  return defaultAlpha;
276
306
  }
277
- return input.endsWith("%") ? parseFloat(input) / percentDenominator : parseFloat(input);
307
+ return input.endsWith("%") ? Number.parseFloat(input) / percentDenominator : Number.parseFloat(input);
308
+ }
309
+
310
+ const ErrorCodes$1 = {
311
+ engineVersionMismatch: "TSP-1001",
312
+ particlePositionNotFound: "TSP-1002",
313
+ pluginRegisterAfterLoad: "TSP-1003",
314
+ offscreenCanvasUnsupported: "TSP-1101",
315
+ offscreenCanvasTransferFailed: "TSP-1102",
316
+ hdrEnableInvalid: "TSP-1201",
317
+ hdrModeInvalid: "TSP-1202",
318
+ hdrPeakNitsInvalid: "TSP-1203",
319
+ };
320
+
321
+ const messages = {
322
+ [ErrorCodes$1.engineVersionMismatch]: "The tsParticles version is different from the loaded plugins version. Engine version: {0}. Plugin version: {1}",
323
+ [ErrorCodes$1.particlePositionNotFound]: "a valid position cannot be found for particle",
324
+ [ErrorCodes$1.pluginRegisterAfterLoad]: "Register plugins can only be done before calling tsParticles.load()",
325
+ [ErrorCodes$1.offscreenCanvasUnsupported]: "OffscreenCanvas is required but not supported by this browser",
326
+ [ErrorCodes$1.offscreenCanvasTransferFailed]: "OffscreenCanvas transfer failed",
327
+ [ErrorCodes$1.hdrEnableInvalid]: 'Invalid HDR "enable" value: expected a boolean, got "{0}"',
328
+ [ErrorCodes$1.hdrModeInvalid]: 'Invalid HDR "mode" value: expected one of {0}, got "{1}"',
329
+ [ErrorCodes$1.hdrPeakNitsInvalid]: 'Invalid HDR "peakNits" value: expected a positive number, got "{0}"',
330
+ };
331
+
332
+ let registeredMessages;
333
+ const ensureRegisteredMessages = () => {
334
+ registeredMessages ??= new Map(Object.entries(messages));
335
+ return registeredMessages;
336
+ }, toStringValue$1 = (value) => String(value), format = (template, args) => {
337
+ return template.replace(/\{(\d+)\}/g, (match, index) => {
338
+ const arg = args[Number(index)];
339
+ return arg === undefined ? match : toStringValue$1(arg);
340
+ });
341
+ };
342
+ function addErrorMessages(extraMessages) {
343
+ if (typeof process !== "undefined" && process.env.NODE_ENV === "production") {
344
+ return;
345
+ }
346
+ const catalog = ensureRegisteredMessages();
347
+ for (const [code, message] of Object.entries(extraMessages)) {
348
+ if (message !== undefined) {
349
+ catalog.set(code, message);
350
+ }
351
+ }
352
+ }
353
+ function getErrorMessage(code, ...args) {
354
+ if (typeof process !== "undefined" && process.env.NODE_ENV === "production") {
355
+ return `[tsParticles Error ${code}] https://particles.js.org/errors/#${code}`;
356
+ }
357
+ const template = ensureRegisteredMessages().get(code) ?? `Unknown error code ${code}`;
358
+ return format(template, args);
278
359
  }
279
360
 
280
361
  var OutModeDirection;
@@ -291,7 +372,6 @@
291
372
  PixelMode["percent"] = "percent";
292
373
  })(PixelMode || (PixelMode = {}));
293
374
 
294
- const minRadius = 0;
295
375
  function isForbiddenKey(key) {
296
376
  return key === "__proto__" || key === "constructor" || key === "prototype";
297
377
  }
@@ -487,22 +567,84 @@
487
567
  element.removeEventListener(event, handler, removeOptions);
488
568
  }
489
569
  }
490
- async function getItemsFromInitializer(container, map, initializers, force = false) {
491
- let res = map.get(container);
492
- if (!res || force) {
493
- res = await Promise.all([...initializers.values()].map(t => t(container)));
494
- map.set(container, res);
570
+ async function getItemsFromInitializer(container, initializers) {
571
+ return await Promise.all([...initializers.values()].map(t => t(container)));
572
+ }
573
+ async function getItemMapFromInitializer(container, initializers) {
574
+ const entries = await Promise.all([...initializers.entries()].map(([key, initializer]) => initializer(container).then(item => [key, item])));
575
+ return new Map(entries);
576
+ }
577
+ async function getDataFromUrl(data) {
578
+ const url = itemFromSingleOrMultiple(data.url, data.index);
579
+ if (!url) {
580
+ return data.fallback;
495
581
  }
496
- return res;
582
+ try {
583
+ const response = await fetch(url);
584
+ if (response.ok) {
585
+ const current = (await response.json());
586
+ if (isSourceOptionsValue(current)) {
587
+ return current;
588
+ }
589
+ getLogger().error("invalid configuration data while retrieving config file");
590
+ }
591
+ else {
592
+ getLogger().error(`${response.status.toString()} while retrieving config file`);
593
+ }
594
+ }
595
+ catch (error) {
596
+ getLogger().error(`error while retrieving config file: ${error}`);
597
+ }
598
+ return data.fallback;
497
599
  }
498
- async function getItemMapFromInitializer(container, map, initializers, force = false) {
499
- let res = map.get(container);
500
- if (!res || force) {
501
- const entries = await Promise.all([...initializers.entries()].map(([key, initializer]) => initializer(container).then(item => [key, item])));
502
- res = new Map(entries);
503
- map.set(container, res);
600
+ function isSourceOptionsValue(value) {
601
+ if (isArray(value)) {
602
+ return value.every((entry) => isObject(entry) && !isArray(entry));
504
603
  }
505
- return res;
604
+ return isObject(value) && !isArray(value);
605
+ }
606
+ function getCanvasFromContainer(domContainer) {
607
+ let canvasEl;
608
+ const documentSafe = safeDocument(), isCanvas = domContainer instanceof HTMLCanvasElement || domContainer.tagName.toLowerCase() === canvasTag;
609
+ if (isCanvas) {
610
+ canvasEl = domContainer;
611
+ canvasEl.dataset[generatedAttribute] ??= generatedFalse;
612
+ if (canvasEl.dataset[generatedAttribute] === generatedTrue) {
613
+ canvasEl.style.width ||= fullPercent;
614
+ canvasEl.style.height ||= fullPercent;
615
+ canvasEl.style.pointerEvents = "none";
616
+ canvasEl.style.setProperty("pointer-events", "none");
617
+ }
618
+ }
619
+ else {
620
+ const existingCanvases = domContainer.getElementsByTagName(canvasTag), foundCanvas = existingCanvases.item(canvasFirstIndex);
621
+ if (foundCanvas) {
622
+ canvasEl = foundCanvas;
623
+ canvasEl.dataset[generatedAttribute] = generatedFalse;
624
+ }
625
+ else {
626
+ canvasEl = documentSafe.createElement(canvasTag);
627
+ canvasEl.dataset[generatedAttribute] = generatedTrue;
628
+ domContainer.appendChild(canvasEl);
629
+ }
630
+ canvasEl.style.width ||= fullPercent;
631
+ canvasEl.style.height ||= fullPercent;
632
+ canvasEl.style.pointerEvents = "none";
633
+ canvasEl.style.setProperty("pointer-events", "none");
634
+ }
635
+ return canvasEl;
636
+ }
637
+ function getDomContainer(id, source) {
638
+ const documentSafe = safeDocument();
639
+ let domContainer = source ?? documentSafe.getElementById(id);
640
+ if (domContainer) {
641
+ return domContainer;
642
+ }
643
+ domContainer = documentSafe.createElement("canvas");
644
+ domContainer.id = id;
645
+ domContainer.dataset[generatedAttribute] = generatedTrue;
646
+ documentSafe.body.append(domContainer);
647
+ return domContainer;
506
648
  }
507
649
 
508
650
  class EventDispatcher {
@@ -573,7 +715,6 @@
573
715
  class PluginManager {
574
716
  colorManagers = new Map();
575
717
  easingFunctions = new Map();
576
- effectDrawers = new Map();
577
718
  initializers = {
578
719
  effects: new Map(),
579
720
  shapes: new Map(),
@@ -582,8 +723,6 @@
582
723
  palettes = new Map();
583
724
  plugins = [];
584
725
  presets = new Map();
585
- shapeDrawers = new Map();
586
- updaters = new Map();
587
726
  #allLoadersSet = new Set();
588
727
  #configs = new Map();
589
728
  #engine;
@@ -601,57 +740,79 @@
601
740
  }
602
741
  return res;
603
742
  }
743
+ get initialized() {
744
+ return this.#initialized;
745
+ }
604
746
  addColorManager(name, manager) {
747
+ if (this.#initialized) {
748
+ return;
749
+ }
605
750
  this.colorManagers.set(name, manager);
606
751
  }
607
752
  addConfig(config) {
753
+ if (this.#initialized) {
754
+ return;
755
+ }
608
756
  const key = config.key ?? config.name ?? "default";
609
757
  this.#configs.set(key, config);
610
758
  this.#engine.dispatchEvent(EventType.configAdded, { data: { name: key, config } });
611
759
  }
612
760
  addEasing(name, easing) {
761
+ if (this.#initialized) {
762
+ return;
763
+ }
613
764
  if (this.easingFunctions.get(name)) {
614
765
  return;
615
766
  }
616
767
  this.easingFunctions.set(name, easing);
617
768
  }
618
769
  addEffect(effect, drawer) {
770
+ if (this.#initialized) {
771
+ return;
772
+ }
619
773
  this.initializers.effects.set(effect, drawer);
620
774
  }
621
775
  addPalette(name, palette) {
776
+ if (this.#initialized) {
777
+ return;
778
+ }
622
779
  this.palettes.set(name, palette);
623
780
  }
624
781
  addParticleUpdater(name, updaterInitializer) {
782
+ if (this.#initialized) {
783
+ return;
784
+ }
625
785
  this.initializers.updaters.set(name, updaterInitializer);
626
786
  }
627
787
  addPlugin(plugin) {
788
+ if (this.#initialized) {
789
+ return;
790
+ }
628
791
  if (this.getPlugin(plugin.id)) {
629
792
  return;
630
793
  }
631
794
  this.plugins.push(plugin);
632
795
  }
633
796
  addPreset(preset, options, override = false) {
797
+ if (this.#initialized) {
798
+ return;
799
+ }
634
800
  if (!(override || !this.getPreset(preset))) {
635
801
  return;
636
802
  }
637
803
  this.presets.set(preset, options);
638
804
  }
639
805
  addShape(shapes, drawer) {
806
+ if (this.#initialized) {
807
+ return;
808
+ }
640
809
  for (const shape of shapes) {
641
810
  this.initializers.shapes.set(shape, drawer);
642
811
  }
643
812
  }
644
- clearPlugins(container) {
645
- this.effectDrawers.delete(container);
646
- this.shapeDrawers.delete(container);
647
- this.updaters.delete(container);
648
- }
649
813
  getEasing(name) {
650
814
  return this.easingFunctions.get(name) ?? ((value) => value);
651
815
  }
652
- getEffectDrawers(container, force = false) {
653
- return getItemMapFromInitializer(container, this.effectDrawers, this.initializers.effects, force);
654
- }
655
816
  getPalette(name) {
656
817
  return this.palettes.get(name);
657
818
  }
@@ -661,12 +822,6 @@
661
822
  getPreset(preset) {
662
823
  return this.presets.get(preset);
663
824
  }
664
- async getShapeDrawers(container, force = false) {
665
- return getItemMapFromInitializer(container, this.shapeDrawers, this.initializers.shapes, force);
666
- }
667
- async getUpdaters(container, force = false) {
668
- return getItemsFromInitializer(container, this.updaters, this.initializers.updaters, force);
669
- }
670
825
  async init() {
671
826
  if (this.#initialized || this.#isRunningLoaders) {
672
827
  return;
@@ -685,16 +840,9 @@
685
840
  this.#initialized = true;
686
841
  }
687
842
  }
688
- loadParticlesOptions(container, options, ...sourceOptions) {
689
- const updaters = this.updaters.get(container);
690
- if (!updaters) {
691
- return;
692
- }
693
- updaters.forEach(updater => updater.loadOptions?.(options, ...sourceOptions));
694
- }
695
843
  async register(...loaders) {
696
844
  if (this.#initialized) {
697
- throw new Error("Register plugins can only be done before calling tsParticles.load()");
845
+ throw new Error(getErrorMessage(ErrorCodes$1.pluginRegisterAfterLoad));
698
846
  }
699
847
  for (const loader of loaders) {
700
848
  if (this.#isRunningLoaders) {
@@ -706,88 +854,15 @@
706
854
  }
707
855
  }
708
856
  async #runLoader(loader, executed, allLoaders) {
709
- if (executed.has(loader))
857
+ if (executed.has(loader)) {
710
858
  return;
859
+ }
711
860
  executed.add(loader);
712
861
  allLoaders.add(loader);
713
862
  await loader(this.#engine);
714
863
  }
715
864
  }
716
865
 
717
- const errorPrefix = "tsParticles - Error";
718
- const wrap = (fn) => (...args) => {
719
- fn(...args);
720
- }, _logger = {
721
- debug: wrap(console.debug),
722
- error: (message, ...optionalParams) => {
723
- console.error(`${errorPrefix} - ${message}`, ...optionalParams);
724
- },
725
- info: wrap(console.info),
726
- log: wrap(console.log),
727
- trace: wrap(console.trace),
728
- verbose: wrap(console.log),
729
- warning: wrap(console.warn),
730
- };
731
- function getLogger() {
732
- return _logger;
733
- }
734
-
735
- const fullPercent = "100%";
736
- async function getDataFromUrl(data) {
737
- const url = itemFromSingleOrMultiple(data.url, data.index);
738
- if (!url) {
739
- return data.fallback;
740
- }
741
- const response = await fetch(url);
742
- if (response.ok) {
743
- return (await response.json());
744
- }
745
- getLogger().error(`${response.status.toString()} while retrieving config file`);
746
- return data.fallback;
747
- }
748
- const getCanvasFromContainer = (domContainer) => {
749
- const documentSafe = safeDocument();
750
- let canvasEl;
751
- const isCanvas = domContainer instanceof HTMLCanvasElement || domContainer.tagName.toLowerCase() === canvasTag;
752
- if (isCanvas) {
753
- canvasEl = domContainer;
754
- canvasEl.dataset[generatedAttribute] ??= generatedFalse;
755
- if (canvasEl.dataset[generatedAttribute] === generatedTrue) {
756
- canvasEl.style.width ||= fullPercent;
757
- canvasEl.style.height ||= fullPercent;
758
- canvasEl.style.pointerEvents = "none";
759
- canvasEl.style.setProperty("pointer-events", "none");
760
- }
761
- }
762
- else {
763
- const existingCanvases = domContainer.getElementsByTagName(canvasTag), foundCanvas = existingCanvases.item(canvasFirstIndex);
764
- if (foundCanvas) {
765
- canvasEl = foundCanvas;
766
- canvasEl.dataset[generatedAttribute] = generatedFalse;
767
- }
768
- else {
769
- canvasEl = documentSafe.createElement(canvasTag);
770
- canvasEl.dataset[generatedAttribute] = generatedTrue;
771
- domContainer.appendChild(canvasEl);
772
- }
773
- canvasEl.style.width ||= fullPercent;
774
- canvasEl.style.height ||= fullPercent;
775
- canvasEl.style.pointerEvents = "none";
776
- canvasEl.style.setProperty("pointer-events", "none");
777
- }
778
- return canvasEl;
779
- }, getDomContainer = (id, source) => {
780
- const documentSafe = safeDocument();
781
- let domContainer = source ?? documentSafe.getElementById(id);
782
- if (domContainer) {
783
- return domContainer;
784
- }
785
- domContainer = documentSafe.createElement("canvas");
786
- domContainer.id = id;
787
- domContainer.dataset[generatedAttribute] = generatedTrue;
788
- documentSafe.body.append(domContainer);
789
- return domContainer;
790
- };
791
866
  class Engine {
792
867
  pluginManager = new PluginManager(this);
793
868
  #domArray = [];
@@ -797,7 +872,7 @@
797
872
  return this.#domArray;
798
873
  }
799
874
  get version() {
800
- return "4.3.2";
875
+ return "4.5.0";
801
876
  }
802
877
  addEventListener(type, listener) {
803
878
  this.#eventDispatcher.addEventListener(type, listener);
@@ -806,7 +881,7 @@
806
881
  if (this.version === pluginVersion) {
807
882
  return;
808
883
  }
809
- throw new Error(`The tsParticles version is different from the loaded plugins version. Engine version: ${this.version}. Plugin version: ${pluginVersion}`);
884
+ throw new Error(getErrorMessage(ErrorCodes$1.engineVersionMismatch, this.version, pluginVersion));
810
885
  }
811
886
  dispatchEvent(type, args) {
812
887
  this.#eventDispatcher.dispatchEvent(type, args);
@@ -878,6 +953,10 @@
878
953
  }
879
954
 
880
955
  function initEngine() {
956
+ const existing = globalThis.tsParticles;
957
+ if (existing?.pluginManager) {
958
+ return existing;
959
+ }
881
960
  return new Engine();
882
961
  }
883
962
 
@@ -975,6 +1054,15 @@
975
1054
  AnimationMode["random"] = "random";
976
1055
  })(AnimationMode || (AnimationMode = {}));
977
1056
 
1057
+ var HdrMode;
1058
+ (function (HdrMode) {
1059
+ HdrMode["standard"] = "standard";
1060
+ HdrMode["natural"] = "natural";
1061
+ HdrMode["vivid"] = "vivid";
1062
+ HdrMode["cinematic"] = "cinematic";
1063
+ HdrMode["dynamic"] = "dynamic";
1064
+ })(HdrMode || (HdrMode = {}));
1065
+
978
1066
  var LimitMode;
979
1067
  (function (LimitMode) {
980
1068
  LimitMode["delete"] = "delete";
@@ -1042,20 +1130,6 @@
1042
1130
  DrawLayer[DrawLayer["Foreground"] = 7] = "Foreground";
1043
1131
  })(DrawLayer || (DrawLayer = {}));
1044
1132
 
1045
- class OptionLoader {
1046
- load(data) {
1047
- if (isNull(data)) {
1048
- return;
1049
- }
1050
- this.doLoad(data);
1051
- }
1052
- }
1053
- function loadOptions(options, ...sourceOptionsArr) {
1054
- for (const sourceOptions of sourceOptionsArr) {
1055
- options.load(sourceOptions);
1056
- }
1057
- }
1058
-
1059
1133
  function loadProperty(obj, key, value) {
1060
1134
  if (value !== undefined) {
1061
1135
  obj[key] = value;
@@ -1087,6 +1161,20 @@
1087
1161
  }
1088
1162
  }
1089
1163
 
1164
+ class OptionLoader {
1165
+ load(data) {
1166
+ if (isNull(data)) {
1167
+ return;
1168
+ }
1169
+ this.doLoad(data);
1170
+ }
1171
+ }
1172
+ function loadOptions(options, ...sourceOptionsArr) {
1173
+ for (const sourceOptions of sourceOptionsArr) {
1174
+ options.load(sourceOptions);
1175
+ }
1176
+ }
1177
+
1090
1178
  class AnimationOptions extends OptionLoader {
1091
1179
  count = 0;
1092
1180
  decay = 0;
@@ -1230,6 +1318,28 @@
1230
1318
  }
1231
1319
  }
1232
1320
 
1321
+ const defaultPeakNits = 400, minPeakNits = 0, toStringValue = (value) => String(value);
1322
+ class HDROptions extends OptionLoader {
1323
+ enable = true;
1324
+ mode = HdrMode.standard;
1325
+ peakNits = defaultPeakNits;
1326
+ doLoad(data) {
1327
+ if (data.enable !== undefined && !isBoolean(data.enable)) {
1328
+ throw new Error(getErrorMessage(ErrorCodes$1.hdrEnableInvalid, String(data.enable)));
1329
+ }
1330
+ if (data.mode !== undefined && !isEnumValue(HdrMode, data.mode)) {
1331
+ throw new Error(getErrorMessage(ErrorCodes$1.hdrModeInvalid, Object.values(HdrMode).join(", "), toStringValue(data.mode)));
1332
+ }
1333
+ if (data.peakNits !== undefined &&
1334
+ (!isNumber(data.peakNits) || !Number.isFinite(data.peakNits) || data.peakNits <= minPeakNits)) {
1335
+ throw new Error(getErrorMessage(ErrorCodes$1.hdrPeakNitsInvalid, String(data.peakNits)));
1336
+ }
1337
+ loadProperty(this, "enable", data.enable);
1338
+ loadProperty(this, "mode", data.mode);
1339
+ loadProperty(this, "peakNits", data.peakNits);
1340
+ }
1341
+ }
1342
+
1233
1343
  class ResizeEvent extends OptionLoader {
1234
1344
  delay = 0.5;
1235
1345
  enable = true;
@@ -1600,12 +1710,10 @@
1600
1710
  plugin.loadParticlesOptions(this.#container, this, data);
1601
1711
  }
1602
1712
  }
1603
- const updaters = this.#pluginManager.updaters.get(this.#container);
1604
- if (updaters) {
1605
- for (const updater of updaters) {
1606
- if (updater.loadOptions) {
1607
- updater.loadOptions(this, data);
1608
- }
1713
+ const updaters = this.#container.particleUpdaters;
1714
+ for (const updater of updaters) {
1715
+ if (updater.loadOptions) {
1716
+ updater.loadOptions(this, data);
1609
1717
  }
1610
1718
  }
1611
1719
  }
@@ -1673,7 +1781,7 @@
1673
1781
  duration = 0;
1674
1782
  fpsLimit = 120;
1675
1783
  fullScreen;
1676
- hdr = true;
1784
+ hdr;
1677
1785
  key;
1678
1786
  name;
1679
1787
  palette;
@@ -1693,6 +1801,7 @@
1693
1801
  this.#container = container;
1694
1802
  this.background = new Background();
1695
1803
  this.fullScreen = new FullScreen();
1804
+ this.hdr = new HDROptions();
1696
1805
  this.particles = loadParticlesOptions(this.#pluginManager, this.#container);
1697
1806
  this.resize = new ResizeEvent();
1698
1807
  }
@@ -1715,7 +1824,15 @@
1715
1824
  loadProperty(this, "detectRetina", data.detectRetina);
1716
1825
  loadRangeProperty(this, "duration", data.duration);
1717
1826
  loadProperty(this, "fpsLimit", data.fpsLimit);
1718
- loadProperty(this, "hdr", data.hdr);
1827
+ const hdrData = data.hdr;
1828
+ if (isBoolean(hdrData)) {
1829
+ this.hdr.enable = hdrData;
1830
+ this.hdr.mode = HdrMode.standard;
1831
+ this.hdr.peakNits = 400;
1832
+ }
1833
+ else {
1834
+ this.hdr.load(hdrData);
1835
+ }
1719
1836
  loadProperty(this, "pauseOnBlur", data.pauseOnBlur);
1720
1837
  loadProperty(this, "pauseOnOutsideViewport", data.pauseOnOutsideViewport);
1721
1838
  loadProperty(this, "zLayers", data.zLayers);
@@ -1758,7 +1875,7 @@
1758
1875
  }
1759
1876
  }
1760
1877
 
1761
- const styleCache = new Map(), maxStyleCacheSize = 2000, rgbFixedPrecision = 2, hslFixedPrecision = 2, hdrRgbFixedPrecision = 4, hdrHslFixedPrecision = 4, sdrReferenceWhiteNits = 203, hdrAnimationScale = sdrReferenceWhiteNits / maxNits;
1878
+ const styleCache = new Map(), maxStyleCacheSize = 2000, rgbFixedPrecision = 2, hslFixedPrecision = 2, hdrRgbFixedPrecision = 4, hdrHslFixedPrecision = 4, sdrReferenceWhiteNits = 203, acesA = 2.51, acesB = 0.03, acesC = 2.43, acesD = 0.59, acesE = 0.14, saturationBoost = 1.15, lightnessBoost = 1.05, temperatureR = 1.05, temperatureB = 0.95, contrastFactor = 1.1, luminanceR = 0.2126, luminanceG = 0.7152, luminanceB = 0.0722, dynamicLuminanceFactor = 2, channelCount = 3;
1762
1879
  function getCachedStyle(key, generator) {
1763
1880
  let cached = styleCache.get(key);
1764
1881
  if (!cached) {
@@ -1770,6 +1887,42 @@
1770
1887
  }
1771
1888
  return cached;
1772
1889
  }
1890
+ function acesFilmic(x) {
1891
+ return clamp((x * (acesA * x + acesB)) / (x * (acesC * x + acesD) + acesE), none, one);
1892
+ }
1893
+ function applyHdrModeAdjustments(r, g, b, mode, maxChannel) {
1894
+ switch (mode) {
1895
+ case HdrMode.vivid: {
1896
+ const avg = (r + g + b) / channelCount;
1897
+ return {
1898
+ b: clamp(clamp(avg + (b - avg) * saturationBoost, none, maxChannel) * lightnessBoost, none, maxChannel),
1899
+ g: clamp(clamp(avg + (g - avg) * saturationBoost, none, maxChannel) * lightnessBoost, none, maxChannel),
1900
+ r: clamp(clamp(avg + (r - avg) * saturationBoost, none, maxChannel) * lightnessBoost, none, maxChannel),
1901
+ };
1902
+ }
1903
+ case HdrMode.cinematic: {
1904
+ const tempR = r * temperatureR, tempB = b * temperatureB, avg = (tempR + g + tempB) / channelCount;
1905
+ return {
1906
+ b: clamp(avg + (tempB - avg) * contrastFactor, none, maxChannel),
1907
+ g: clamp(avg + (g - avg) * contrastFactor, none, maxChannel),
1908
+ r: clamp(avg + (tempR - avg) * contrastFactor, none, maxChannel),
1909
+ };
1910
+ }
1911
+ case HdrMode.dynamic: {
1912
+ const luminance = luminanceR * r + luminanceG * g + luminanceB * b, vividWeight = Math.min(one, luminance * dynamicLuminanceFactor), naturalWeight = one - vividWeight, avg = (r + g + b) / channelCount, vividR = clamp(avg + (r - avg) * saturationBoost, none, maxChannel) * lightnessBoost, vividG = clamp(avg + (g - avg) * saturationBoost, none, maxChannel) * lightnessBoost, vividB = clamp(avg + (b - avg) * saturationBoost, none, maxChannel) * lightnessBoost;
1913
+ return {
1914
+ b: clamp(b * naturalWeight + vividB * vividWeight, none, maxChannel),
1915
+ g: clamp(g * naturalWeight + vividG * vividWeight, none, maxChannel),
1916
+ r: clamp(r * naturalWeight + vividR * vividWeight, none, maxChannel),
1917
+ };
1918
+ }
1919
+ case HdrMode.standard:
1920
+ return { b, g, r };
1921
+ case HdrMode.natural:
1922
+ default:
1923
+ return { b, g, r };
1924
+ }
1925
+ }
1773
1926
  function stringToRgba(pluginManager, input) {
1774
1927
  if (!input) {
1775
1928
  return;
@@ -1893,9 +2046,9 @@
1893
2046
  const grayscaleValue = Math.round(lNormalized * rgbMax);
1894
2047
  return { r: grayscaleValue, g: grayscaleValue, b: grayscaleValue };
1895
2048
  }
1896
- const temp1 = lNormalized < half
2049
+ const temp2 = lNormalized < half
1897
2050
  ? lNormalized * (sNormalizedOffset + sNormalized)
1898
- : lNormalized + sNormalized - lNormalized * sNormalized, temp2 = double * lNormalized - temp1, phaseThird = phaseNumerator / triple, red = Math.min(rgbMax, rgbMax * hslChannel(temp2, temp1, hNormalized + phaseThird)), green = Math.min(rgbMax, rgbMax * hslChannel(temp2, temp1, hNormalized)), blue = Math.min(rgbMax, rgbMax * hslChannel(temp2, temp1, hNormalized - phaseThird));
2051
+ : lNormalized + sNormalized - lNormalized * sNormalized, temp1 = double * lNormalized - temp2, phaseThird = phaseNumerator / triple, red = Math.min(rgbMax, rgbMax * hslChannel(temp1, temp2, hNormalized + phaseThird)), green = Math.min(rgbMax, rgbMax * hslChannel(temp1, temp2, hNormalized)), blue = Math.min(rgbMax, rgbMax * hslChannel(temp1, temp2, hNormalized - phaseThird));
1899
2052
  return { r: Math.round(red), g: Math.round(green), b: Math.round(blue) };
1900
2053
  }
1901
2054
  function hslToRgbFloat(hsl) {
@@ -1904,9 +2057,9 @@
1904
2057
  const grayscaleValue = lNormalized * rgbMax;
1905
2058
  return { r: grayscaleValue, g: grayscaleValue, b: grayscaleValue };
1906
2059
  }
1907
- const temp1 = lNormalized < half
2060
+ const temp2 = lNormalized < half
1908
2061
  ? lNormalized * (sNormalizedOffset + sNormalized)
1909
- : lNormalized + sNormalized - lNormalized * sNormalized, temp2 = double * lNormalized - temp1, phaseThird = phaseNumerator / triple, red = Math.min(rgbMax, rgbMax * hslChannel(temp2, temp1, hNormalized + phaseThird)), green = Math.min(rgbMax, rgbMax * hslChannel(temp2, temp1, hNormalized)), blue = Math.min(rgbMax, rgbMax * hslChannel(temp2, temp1, hNormalized - phaseThird));
2062
+ : lNormalized + sNormalized - lNormalized * sNormalized, temp1 = double * lNormalized - temp2, phaseThird = phaseNumerator / triple, red = Math.min(rgbMax, rgbMax * hslChannel(temp1, temp2, hNormalized + phaseThird)), green = Math.min(rgbMax, rgbMax * hslChannel(temp1, temp2, hNormalized)), blue = Math.min(rgbMax, rgbMax * hslChannel(temp1, temp2, hNormalized - phaseThird));
1910
2063
  return { r: red, g: green, b: blue };
1911
2064
  }
1912
2065
  function hslaToRgba(hsla) {
@@ -1927,21 +2080,40 @@
1927
2080
  r: getRgbInRangeValue(),
1928
2081
  };
1929
2082
  }
1930
- function getStyleFromRgb(color, hdr, opacity) {
1931
- const rgbPrecision = hdr ? hdrRgbFixedPrecision : rgbFixedPrecision, op = opacity ?? defaultOpacity$1, key = `rgb-${color.r.toFixed(rgbPrecision)}-${color.g.toFixed(rgbPrecision)}-${color.b.toFixed(rgbPrecision)}-${hdr ? "hdr" : "sdr"}-${op.toString()}`;
1932
- return getCachedStyle(key, () => (hdr ? getHdrStyleFromRgb(color, opacity) : getSdrStyleFromRgb(color, opacity)));
2083
+ function getStyleFromRgb(color, hdr, opacity, peakNits, mode) {
2084
+ const rgbPrecision = hdr ? hdrRgbFixedPrecision : rgbFixedPrecision, op = opacity ?? defaultOpacity$1, key = hdr
2085
+ ? `rgb-${color.r.toFixed(rgbPrecision)}-${color.g.toFixed(rgbPrecision)}-${color.b.toFixed(rgbPrecision)}-hdr-${op.toString()}-${(peakNits ?? maxNits).toString()}-${mode ?? HdrMode.standard}`
2086
+ : `rgb-${color.r.toFixed(rgbPrecision)}-${color.g.toFixed(rgbPrecision)}-${color.b.toFixed(rgbPrecision)}-sdr-${op.toString()}`;
2087
+ return getCachedStyle(key, () => hdr ? getHdrStyleFromRgb(color, opacity, peakNits, mode) : getSdrStyleFromRgb(color, opacity));
2088
+ }
2089
+ function getHdrStyleFromRgb(color, opacity, peakNits = maxNits, mode = HdrMode.standard) {
2090
+ const headroom = peakNits / sdrReferenceWhiteNits, middleGray = 0.18, mapped = hdrToneMapColor(color, headroom, middleGray, mode);
2091
+ return `color(display-p3 ${mapped.r.toString()} ${mapped.g.toString()} ${mapped.b.toString()} / ${(opacity ?? defaultOpacity$1).toString()})`;
1933
2092
  }
1934
- function getHdrStyleFromRgb(color, opacity, peakNits = maxNits) {
1935
- const headroom = peakNits / sdrReferenceWhiteNits;
1936
- return `color(display-p3 ${((color.r / rgbMax) * headroom).toString()} ${((color.g / rgbMax) * headroom).toString()} ${((color.b / rgbMax) * headroom).toString()} / ${(opacity ?? defaultOpacity$1).toString()})`;
2093
+ function hdrToneMapColor(color, headroom, middleGray, mode) {
2094
+ const rNorm = color.r / rgbMax, gNorm = color.g / rgbMax, bNorm = color.b / rgbMax;
2095
+ if (mode !== HdrMode.natural && mode !== HdrMode.vivid && mode !== HdrMode.cinematic && mode !== HdrMode.dynamic) {
2096
+ return { b: bNorm, g: gNorm, r: rNorm };
2097
+ }
2098
+ const maxChannel = Math.max(one, headroom), luminance = luminanceR * rNorm + luminanceG * gNorm + luminanceB * bNorm, mappedLuminance = hdrToneMap(luminance, headroom, middleGray), scale = luminance > none ? mappedLuminance / luminance : one;
2099
+ return applyHdrModeAdjustments(clamp(rNorm * scale, none, maxChannel), clamp(gNorm * scale, none, maxChannel), clamp(bNorm * scale, none, maxChannel), mode, maxChannel);
2100
+ }
2101
+ function hdrToneMap(normalized, headroom, middleGray) {
2102
+ if (normalized <= middleGray) {
2103
+ return acesFilmic(normalized);
2104
+ }
2105
+ const expanded = normalized + (normalized - middleGray) * (headroom - one);
2106
+ return acesFilmic(expanded);
1937
2107
  }
1938
2108
  function getSdrStyleFromRgb(color, opacity) {
1939
2109
  return `rgba(${color.r.toString()}, ${color.g.toString()}, ${color.b.toString()}, ${(opacity ?? defaultOpacity$1).toString()})`;
1940
2110
  }
1941
- function getStyleFromHsl(color, hdr, opacity) {
1942
- const hslPrecision = hdr ? hdrHslFixedPrecision : hslFixedPrecision, op = opacity ?? defaultOpacity$1, key = `hsl-${color.h.toFixed(hslPrecision)}-${color.s.toFixed(hslPrecision)}-${color.l.toFixed(hslPrecision)}-${hdr ? "hdr" : "sdr"}-${op.toString()}`;
2111
+ function getStyleFromHsl(color, hdr, opacity, peakNits, mode) {
2112
+ const hslPrecision = hdr ? hdrHslFixedPrecision : hslFixedPrecision, op = opacity ?? defaultOpacity$1, key = hdr
2113
+ ? `hsl-${color.h.toFixed(hslPrecision)}-${color.s.toFixed(hslPrecision)}-${color.l.toFixed(hslPrecision)}-hdr-${op.toString()}-${(peakNits ?? maxNits).toString()}-${mode ?? HdrMode.standard}`
2114
+ : `hsl-${color.h.toFixed(hslPrecision)}-${color.s.toFixed(hslPrecision)}-${color.l.toFixed(hslPrecision)}-sdr-${op.toString()}`;
1943
2115
  return getCachedStyle(key, () => hdr
1944
- ? getStyleFromRgb(hslToRgbFloat(color), true, opacity)
2116
+ ? getStyleFromRgb(hslToRgbFloat(color), true, opacity, peakNits, mode)
1945
2117
  : `hsla(${color.h.toString()}, ${color.s.toString()}%, ${color.l.toString()}%, ${op.toString()})`);
1946
2118
  }
1947
2119
  function getHslFromAnimation(animation) {
@@ -2004,7 +2176,7 @@
2004
2176
  colorValue.velocity = defaultVelocity;
2005
2177
  }
2006
2178
  }
2007
- function updateColorValue(data, decrease, delta, hdr) {
2179
+ function updateColorValue(data, decrease, delta, _hdr) {
2008
2180
  const minLoops = 0, minDelay = 0, identity = 1, minVelocity = 0, minOffset = 0, velocityFactor = 3.6;
2009
2181
  if (!data.enable ||
2010
2182
  ((data.maxLoops ?? minLoops) > minLoops && (data.loops ?? minLoops) > (data.maxLoops ?? minLoops))) {
@@ -2017,7 +2189,7 @@
2017
2189
  if ((data.delayTime ?? minDelay) > minDelay && data.time < (data.delayTime ?? minDelay)) {
2018
2190
  return;
2019
2191
  }
2020
- const offset = data.offset ? randomInRangeValue(data.offset) : minOffset, velocity = ((data.velocity ?? minVelocity) * delta.factor + offset * velocityFactor) * (hdr ? hdrAnimationScale : identity), decay = data.decay ?? identity, max = data.max, min = data.min;
2192
+ const offset = data.offset ? randomInRangeValue(data.offset) : minOffset, velocity = (data.velocity ?? minVelocity) * delta.factor + offset * velocityFactor, decay = data.decay ?? identity, max = data.max, min = data.min;
2021
2193
  if (!decrease || data.status === AnimationStatus.increasing) {
2022
2194
  data.value += velocity;
2023
2195
  if (data.value > max) {
@@ -2049,9 +2221,9 @@
2049
2221
  return;
2050
2222
  }
2051
2223
  const { h, s, l } = color;
2052
- updateColorValue(h, false, delta, hdr);
2053
- updateColorValue(s, true, delta, hdr);
2054
- updateColorValue(l, true, delta, hdr);
2224
+ updateColorValue(h, false, delta);
2225
+ updateColorValue(s, true, delta);
2226
+ updateColorValue(l, true, delta);
2055
2227
  }
2056
2228
  function alterHsl(color, type, value) {
2057
2229
  return {
@@ -2101,7 +2273,7 @@
2101
2273
  }
2102
2274
 
2103
2275
  async function loadBlendPlugin(engine) {
2104
- engine.checkVersion("4.3.2");
2276
+ engine.checkVersion("4.5.0");
2105
2277
  await engine.pluginManager.register(e => {
2106
2278
  e.pluginManager.addPlugin(new BlendPlugin());
2107
2279
  });
@@ -2138,7 +2310,7 @@
2138
2310
  }
2139
2311
 
2140
2312
  async function loadCircleShape(engine) {
2141
- engine.checkVersion("4.3.2");
2313
+ engine.checkVersion("4.5.0");
2142
2314
  await engine.pluginManager.register(e => {
2143
2315
  e.pluginManager.addShape(["circle"], () => {
2144
2316
  return Promise.resolve(new CircleDrawer());
@@ -2153,7 +2325,7 @@
2153
2325
  RgbIndexes[RgbIndexes["b"] = 3] = "b";
2154
2326
  RgbIndexes[RgbIndexes["a"] = 4] = "a";
2155
2327
  })(RgbIndexes$1 || (RgbIndexes$1 = {}));
2156
- const shorthandHexRegex = /^#?([a-f\d])([a-f\d])([a-f\d])([a-f\d])?$/i, hexRegex = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})?$/i, hexRadix = 16, defaultAlpha = 1, alphaFactor = 0xff;
2328
+ const shorthandHexRegex = /^#?([a-f\d])([a-f\d])([a-f\d])([a-f\d])?$/i, hexRegex = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})?$/i, hexRadix = 16, alphaFactor = 0xff;
2157
2329
  class HexColorManager {
2158
2330
  accepts(input) {
2159
2331
  return input.startsWith("#");
@@ -2186,7 +2358,7 @@
2186
2358
  }
2187
2359
 
2188
2360
  async function loadHexColorPlugin(engine) {
2189
- engine.checkVersion("4.3.2");
2361
+ engine.checkVersion("4.5.0");
2190
2362
  await engine.pluginManager.register(e => {
2191
2363
  e.pluginManager.addColorManager("hex", new HexColorManager());
2192
2364
  });
@@ -2226,7 +2398,7 @@
2226
2398
  if (!this.accepts(input)) {
2227
2399
  return;
2228
2400
  }
2229
- const result = hslRegex.exec(input), minLength = 4, defaultAlpha = 1, radix = 10;
2401
+ const result = hslRegex.exec(input), minLength = 4, radix = 10;
2230
2402
  return result
2231
2403
  ? hslaToRgba({
2232
2404
  a: result.length > minLength ? parseAlpha(result[HslIndexes.a]) : defaultAlpha,
@@ -2239,12 +2411,20 @@
2239
2411
  }
2240
2412
 
2241
2413
  async function loadHslColorPlugin(engine) {
2242
- engine.checkVersion("4.3.2");
2414
+ engine.checkVersion("4.5.0");
2243
2415
  await engine.pluginManager.register(e => {
2244
2416
  e.pluginManager.addColorManager("hsl", new HslColorManager());
2245
2417
  });
2246
2418
  }
2247
2419
 
2420
+ const ErrorCodes = {
2421
+ baseMoverNotLoaded: "TSP-3203",
2422
+ };
2423
+
2424
+ const ErrorMessages = {
2425
+ [ErrorCodes.baseMoverNotLoaded]: "tsParticles Base Mover is not loaded",
2426
+ };
2427
+
2248
2428
  class MovePlugin {
2249
2429
  id = "move";
2250
2430
  #pluginManager;
@@ -2263,20 +2443,20 @@
2263
2443
  }
2264
2444
 
2265
2445
  async function loadMovePlugin(engine) {
2266
- engine.checkVersion("4.3.2");
2446
+ engine.checkVersion("4.5.0");
2447
+ if (typeof process !== "undefined" && process.env.NODE_ENV !== "production") {
2448
+ addErrorMessages(ErrorMessages);
2449
+ }
2267
2450
  await engine.pluginManager.register(e => {
2268
2451
  const moveEngine = e, movePluginManager = moveEngine.pluginManager;
2269
2452
  movePluginManager.initializers.pathGenerators ??= new Map();
2270
- movePluginManager.pathGenerators ??= new Map();
2271
2453
  movePluginManager.addPathGenerator = (name, generator) => {
2454
+ if (movePluginManager.initialized) {
2455
+ return;
2456
+ }
2272
2457
  movePluginManager.initializers.pathGenerators ??= new Map();
2273
2458
  movePluginManager.initializers.pathGenerators.set(name, generator);
2274
2459
  };
2275
- movePluginManager.getPathGenerators = async (container, force = false) => {
2276
- movePluginManager.initializers.pathGenerators ??= new Map();
2277
- movePluginManager.pathGenerators ??= new Map();
2278
- return getItemMapFromInitializer(container, movePluginManager.pathGenerators, movePluginManager.initializers.pathGenerators, force);
2279
- };
2280
2460
  e.pluginManager.addPlugin(new MovePlugin(e.pluginManager));
2281
2461
  });
2282
2462
  }
@@ -2479,7 +2659,7 @@
2479
2659
  }
2480
2660
 
2481
2661
  async function loadOpacityUpdater(engine) {
2482
- engine.checkVersion("4.3.2");
2662
+ engine.checkVersion("4.5.0");
2483
2663
  await engine.pluginManager.register(e => {
2484
2664
  e.pluginManager.addParticleUpdater("opacity", container => {
2485
2665
  return Promise.resolve(new OpacityUpdater(container));
@@ -2488,70 +2668,60 @@
2488
2668
  }
2489
2669
 
2490
2670
  const boundsMin = 0;
2491
- function bounceHorizontal(data) {
2492
- if ((data.outMode !== OutMode.bounce && data.outMode !== OutMode.split) ||
2493
- (data.direction !== OutModeDirection.left && data.direction !== OutModeDirection.right)) {
2494
- return;
2495
- }
2496
- if (data.bounds.right < boundsMin && data.direction === OutModeDirection.left) {
2497
- data.particle.position.x = data.size + data.offset.x;
2498
- }
2499
- else if (data.bounds.left > data.canvasSize.width && data.direction === OutModeDirection.right) {
2500
- data.particle.position.x = data.canvasSize.width - data.size - data.offset.x;
2501
- }
2502
- const velocity = data.particle.velocity.x;
2503
- let bounced = false;
2504
- if (data.outOfCanvas &&
2505
- ((data.direction === OutModeDirection.right && velocity > minVelocity) ||
2506
- (data.direction === OutModeDirection.left && velocity < minVelocity))) {
2507
- const newVelocity = getRangeValue(data.particle.options.bounce.horizontal.value);
2508
- data.particle.velocity.x *= -newVelocity;
2509
- bounced = true;
2510
- }
2511
- if (!bounced) {
2512
- return;
2513
- }
2514
- const minPos = data.offset.x + data.size;
2515
- if (data.outOfCanvas && data.direction === OutModeDirection.right) {
2516
- data.particle.position.x = data.canvasSize.width - minPos;
2517
- }
2518
- else if (data.outOfCanvas && data.direction === OutModeDirection.left) {
2519
- data.particle.position.x = minPos;
2520
- }
2521
- if (data.outMode === OutMode.split) {
2522
- data.particle.destroy();
2523
- }
2524
- }
2525
- function bounceVertical(data) {
2526
- if ((data.outMode !== OutMode.bounce && data.outMode !== OutMode.split) ||
2527
- (data.direction !== OutModeDirection.bottom && data.direction !== OutModeDirection.top)) {
2671
+ const bounceAxisConfigs = {
2672
+ [OutModeDirection.left]: {
2673
+ axis: "x",
2674
+ canvas: "width",
2675
+ bounce: "horizontal",
2676
+ negativeEdge: "right",
2677
+ positiveEdge: "left",
2678
+ negative: true,
2679
+ },
2680
+ [OutModeDirection.right]: {
2681
+ axis: "x",
2682
+ canvas: "width",
2683
+ bounce: "horizontal",
2684
+ negativeEdge: "right",
2685
+ positiveEdge: "left",
2686
+ negative: false,
2687
+ },
2688
+ [OutModeDirection.top]: {
2689
+ axis: "y",
2690
+ canvas: "height",
2691
+ bounce: "vertical",
2692
+ negativeEdge: "bottom",
2693
+ positiveEdge: "top",
2694
+ negative: true,
2695
+ },
2696
+ [OutModeDirection.bottom]: {
2697
+ axis: "y",
2698
+ canvas: "height",
2699
+ bounce: "vertical",
2700
+ negativeEdge: "bottom",
2701
+ positiveEdge: "top",
2702
+ negative: false,
2703
+ },
2704
+ };
2705
+ function bounce(data) {
2706
+ if ((data.outMode !== OutMode.bounce && data.outMode !== OutMode.split) || !(data.direction in bounceAxisConfigs)) {
2528
2707
  return;
2529
2708
  }
2530
- if (data.bounds.bottom < boundsMin && data.direction === OutModeDirection.top) {
2531
- data.particle.position.y = data.size + data.offset.y;
2709
+ const config = bounceAxisConfigs[data.direction], bounds = data.bounds, canvasDim = data.canvasSize[config.canvas], position = data.particle.position, velocity = data.particle.velocity[config.axis];
2710
+ if (config.negative && bounds[config.negativeEdge] < boundsMin) {
2711
+ position[config.axis] = data.size + data.offset[config.axis];
2532
2712
  }
2533
- else if (data.bounds.top > data.canvasSize.height && data.direction === OutModeDirection.bottom) {
2534
- data.particle.position.y = data.canvasSize.height - data.size - data.offset.y;
2713
+ else if (!config.negative && bounds[config.positiveEdge] > canvasDim) {
2714
+ position[config.axis] = canvasDim - data.size - data.offset[config.axis];
2535
2715
  }
2536
- const velocity = data.particle.velocity.y;
2537
- let bounced = false;
2538
2716
  if (data.outOfCanvas &&
2539
- ((data.direction === OutModeDirection.bottom && velocity > minVelocity) ||
2540
- (data.direction === OutModeDirection.top && velocity < minVelocity))) {
2541
- const newVelocity = getRangeValue(data.particle.options.bounce.vertical.value);
2542
- data.particle.velocity.y *= -newVelocity;
2543
- bounced = true;
2717
+ ((config.negative && velocity < minVelocity) || (!config.negative && velocity > minVelocity))) {
2718
+ data.particle.velocity[config.axis] *= -getRangeValue(data.particle.options.bounce[config.bounce].value);
2544
2719
  }
2545
- if (!bounced) {
2720
+ else {
2546
2721
  return;
2547
2722
  }
2548
- const minPos = data.offset.y + data.size;
2549
- if (data.outOfCanvas && data.direction === OutModeDirection.bottom) {
2550
- data.particle.position.y = data.canvasSize.height - minPos;
2551
- }
2552
- else if (data.outOfCanvas && data.direction === OutModeDirection.top) {
2553
- data.particle.position.y = minPos;
2554
- }
2723
+ const minPos = data.offset[config.axis] + data.size;
2724
+ position[config.axis] = config.negative ? minPos : canvasDim - minPos;
2555
2725
  if (data.outMode === OutMode.split) {
2556
2726
  data.particle.destroy();
2557
2727
  }
@@ -2567,26 +2737,19 @@
2567
2737
  OutMode.bounce,
2568
2738
  OutMode.split,
2569
2739
  ];
2570
- this.#particleBouncePlugins = container.plugins.filter(p => p.particleBounce !== undefined);
2740
+ this.#particleBouncePlugins = container.plugins.filter(p => !!p.particleBounce);
2571
2741
  }
2572
2742
  update(particle, direction, delta, outMode) {
2573
2743
  if (!this.modes.includes(outMode)) {
2574
2744
  return;
2575
2745
  }
2576
- const container = this.#container;
2577
- let handled = false;
2578
2746
  for (const plugin of this.#particleBouncePlugins) {
2579
- handled = plugin.particleBounce?.(particle, delta, direction) ?? false;
2580
- if (handled) {
2581
- break;
2747
+ if (plugin.particleBounce?.(particle, delta, direction)) {
2748
+ return;
2582
2749
  }
2583
2750
  }
2584
- if (handled) {
2585
- return;
2586
- }
2587
- const pos = particle.getPosition(), offset = particle.offset, size = particle.getRadius(), bounds = calculateBounds(pos, size), canvasSize = container.canvas.size, outOfCanvas = !particle.isInsideCanvasForOutMode(outMode, direction);
2588
- bounceHorizontal({ particle, outMode, direction, bounds, canvasSize, offset, outOfCanvas, size });
2589
- bounceVertical({ particle, outMode, direction, bounds, canvasSize, offset, outOfCanvas, size });
2751
+ const pos = particle.getPosition(), offset = particle.offset, size = particle.getRadius(), bounds = calculateBounds(pos, size), canvasSize = this.#container.canvas.size, outOfCanvas = !particle.isInsideCanvasForOutMode(outMode, direction);
2752
+ bounce({ particle, outMode, direction, bounds, canvasSize, offset, outOfCanvas, size });
2590
2753
  }
2591
2754
  }
2592
2755
 
@@ -2675,108 +2838,109 @@
2675
2838
  return;
2676
2839
  }
2677
2840
  const container = this.#container;
2678
- switch (particle.outType) {
2679
- case ParticleOutType.inside: {
2680
- const { x: vx, y: vy } = particle.velocity;
2681
- updateVector.setTo(originPoint);
2682
- updateVector.length = particle.moveCenter.radius;
2683
- updateVector.angle = particle.velocity.angle + Math.PI;
2684
- updateVector.addTo(particle.moveCenter);
2685
- const { dx, dy } = getDistances(particle.position, updateVector);
2686
- if ((vx <= minVelocity && dx >= minDistance) ||
2687
- (vy <= minVelocity && dy >= minDistance) ||
2688
- (vx >= minVelocity && dx <= minDistance) ||
2689
- (vy >= minVelocity && dy <= minDistance)) {
2690
- return;
2691
- }
2692
- particle.position.x = Math.floor(randomInRangeValue({
2693
- min: 0,
2694
- max: container.canvas.size.width,
2695
- }));
2696
- particle.position.y = Math.floor(randomInRangeValue({
2697
- min: 0,
2698
- max: container.canvas.size.height,
2699
- }));
2700
- const { dx: newDx, dy: newDy } = getDistances(particle.position, particle.moveCenter);
2701
- particle.direction = Math.atan2(-newDy, -newDx);
2702
- particle.velocity.angle = particle.direction;
2703
- particle.justWarped = true;
2704
- break;
2841
+ if (particle.outType === ParticleOutType.inside) {
2842
+ this.#applyOutModeInside(particle, container);
2843
+ }
2844
+ else {
2845
+ if (particle.isInsideCanvasForOutMode(outMode, direction)) {
2846
+ return;
2705
2847
  }
2706
- default: {
2707
- if (particle.isInsideCanvasForOutMode(outMode, direction)) {
2708
- return;
2709
- }
2710
- switch (particle.outType) {
2711
- case ParticleOutType.outside: {
2712
- particle.position.x =
2713
- Math.floor(randomInRangeValue({
2714
- min: -particle.moveCenter.radius,
2715
- max: particle.moveCenter.radius,
2716
- })) + particle.moveCenter.x;
2717
- particle.position.y =
2718
- Math.floor(randomInRangeValue({
2719
- min: -particle.moveCenter.radius,
2720
- max: particle.moveCenter.radius,
2721
- })) + particle.moveCenter.y;
2722
- const { dx, dy } = getDistances(particle.position, particle.moveCenter);
2723
- if (particle.moveCenter.radius) {
2724
- particle.direction = Math.atan2(dy, dx);
2725
- particle.velocity.angle = particle.direction;
2726
- }
2727
- particle.justWarped = true;
2728
- break;
2729
- }
2730
- case ParticleOutType.normal: {
2731
- const warp = particle.options.move.warp, canvasSize = container.canvas.size, newPos = {
2732
- bottom: canvasSize.height + particle.getRadius() + particle.offset.y,
2733
- left: -particle.getRadius() - particle.offset.x,
2734
- right: canvasSize.width + particle.getRadius() + particle.offset.x,
2735
- top: -particle.getRadius() - particle.offset.y,
2736
- }, sizeValue = particle.getRadius(), nextBounds = calculateBounds(particle.position, sizeValue);
2737
- if (direction === OutModeDirection.right && nextBounds.left > canvasSize.width + particle.offset.x) {
2738
- particle.position.x = newPos.left;
2739
- particle.initialPosition.x = particle.position.x;
2740
- if (!warp) {
2741
- particle.position.y = getRandom() * canvasSize.height;
2742
- particle.initialPosition.y = particle.position.y;
2743
- }
2744
- particle.justWarped = true;
2745
- }
2746
- else if (direction === OutModeDirection.left && nextBounds.right < -particle.offset.x) {
2747
- particle.position.x = newPos.right;
2748
- particle.initialPosition.x = particle.position.x;
2749
- if (!warp) {
2750
- particle.position.y = getRandom() * canvasSize.height;
2751
- particle.initialPosition.y = particle.position.y;
2752
- }
2753
- particle.justWarped = true;
2754
- }
2755
- if (direction === OutModeDirection.bottom && nextBounds.top > canvasSize.height + particle.offset.y) {
2756
- if (!warp) {
2757
- particle.position.x = getRandom() * canvasSize.width;
2758
- particle.initialPosition.x = particle.position.x;
2759
- }
2760
- particle.position.y = newPos.top;
2761
- particle.initialPosition.y = particle.position.y;
2762
- particle.justWarped = true;
2763
- }
2764
- else if (direction === OutModeDirection.top && nextBounds.bottom < -particle.offset.y) {
2765
- if (!warp) {
2766
- particle.position.x = getRandom() * canvasSize.width;
2767
- particle.initialPosition.x = particle.position.x;
2768
- }
2769
- particle.position.y = newPos.bottom;
2770
- particle.initialPosition.y = particle.position.y;
2771
- particle.justWarped = true;
2772
- }
2773
- break;
2774
- }
2775
- }
2776
- break;
2848
+ if (particle.outType === ParticleOutType.outside) {
2849
+ this.#applyParticleModeOutside(particle);
2850
+ }
2851
+ else {
2852
+ this.#applyOutModeNormal(particle, container, direction);
2777
2853
  }
2778
2854
  }
2779
2855
  }
2856
+ #applyOutModeInside(particle, container) {
2857
+ const { x: vx, y: vy } = particle.velocity;
2858
+ updateVector.setTo(originPoint);
2859
+ updateVector.length = particle.moveCenter.radius;
2860
+ updateVector.angle = particle.velocity.angle + Math.PI;
2861
+ updateVector.addTo(particle.moveCenter);
2862
+ const { dx, dy } = getDistances(particle.position, updateVector);
2863
+ if ((vx <= minVelocity && dx >= minDistance) ||
2864
+ (vy <= minVelocity && dy >= minDistance) ||
2865
+ (vx >= minVelocity && dx <= minDistance) ||
2866
+ (vy >= minVelocity && dy <= minDistance)) {
2867
+ return;
2868
+ }
2869
+ particle.position.x = Math.floor(randomInRangeValue({
2870
+ min: 0,
2871
+ max: container.canvas.size.width,
2872
+ }));
2873
+ particle.position.y = Math.floor(randomInRangeValue({
2874
+ min: 0,
2875
+ max: container.canvas.size.height,
2876
+ }));
2877
+ const { dx: newDx, dy: newDy } = getDistances(particle.position, particle.moveCenter);
2878
+ particle.direction = Math.atan2(-newDy, -newDx);
2879
+ particle.velocity.angle = particle.direction;
2880
+ particle.justWarped = true;
2881
+ }
2882
+ #applyOutModeNormal(particle, container, direction) {
2883
+ const warp = particle.options.move.warp, canvasSize = container.canvas.size, sizeValue = particle.getRadius(), newPos = {
2884
+ bottom: canvasSize.height + sizeValue + particle.offset.y,
2885
+ left: -sizeValue - particle.offset.x,
2886
+ right: canvasSize.width + sizeValue + particle.offset.x,
2887
+ top: -sizeValue - particle.offset.y,
2888
+ }, nextBounds = calculateBounds(particle.position, sizeValue);
2889
+ if (direction === OutModeDirection.right && nextBounds.left > canvasSize.width + particle.offset.x) {
2890
+ particle.position.x = newPos.left;
2891
+ particle.initialPosition.x = particle.position.x;
2892
+ if (!warp) {
2893
+ particle.position.y = getRandom() * canvasSize.height;
2894
+ particle.initialPosition.y = particle.position.y;
2895
+ }
2896
+ particle.justWarped = true;
2897
+ }
2898
+ else if (direction === OutModeDirection.left && nextBounds.right < -particle.offset.x) {
2899
+ particle.position.x = newPos.right;
2900
+ particle.initialPosition.x = particle.position.x;
2901
+ if (!warp) {
2902
+ particle.position.y = getRandom() * canvasSize.height;
2903
+ particle.initialPosition.y = particle.position.y;
2904
+ }
2905
+ particle.justWarped = true;
2906
+ }
2907
+ if (direction === OutModeDirection.bottom && nextBounds.top > canvasSize.height + particle.offset.y) {
2908
+ if (!warp) {
2909
+ particle.position.x = getRandom() * canvasSize.width;
2910
+ particle.initialPosition.x = particle.position.x;
2911
+ }
2912
+ particle.position.y = newPos.top;
2913
+ particle.initialPosition.y = particle.position.y;
2914
+ particle.justWarped = true;
2915
+ }
2916
+ else if (direction === OutModeDirection.top && nextBounds.bottom < -particle.offset.y) {
2917
+ if (!warp) {
2918
+ particle.position.x = getRandom() * canvasSize.width;
2919
+ particle.initialPosition.x = particle.position.x;
2920
+ }
2921
+ particle.position.y = newPos.bottom;
2922
+ particle.initialPosition.y = particle.position.y;
2923
+ particle.justWarped = true;
2924
+ }
2925
+ }
2926
+ #applyParticleModeOutside(particle) {
2927
+ particle.position.x =
2928
+ Math.floor(randomInRangeValue({
2929
+ min: -particle.moveCenter.radius,
2930
+ max: particle.moveCenter.radius,
2931
+ })) + particle.moveCenter.x;
2932
+ particle.position.y =
2933
+ Math.floor(randomInRangeValue({
2934
+ min: -particle.moveCenter.radius,
2935
+ max: particle.moveCenter.radius,
2936
+ })) + particle.moveCenter.y;
2937
+ const { dx, dy } = getDistances(particle.position, particle.moveCenter);
2938
+ if (particle.moveCenter.radius) {
2939
+ particle.direction = Math.atan2(dy, dx);
2940
+ particle.velocity.angle = particle.direction;
2941
+ }
2942
+ particle.justWarped = true;
2943
+ }
2780
2944
  }
2781
2945
 
2782
2946
  const checkOutMode = (outModes, outMode) => {
@@ -2824,7 +2988,7 @@
2824
2988
  }
2825
2989
 
2826
2990
  async function loadOutModesUpdater(engine) {
2827
- engine.checkVersion("4.3.2");
2991
+ engine.checkVersion("4.5.0");
2828
2992
  await engine.pluginManager.register(e => {
2829
2993
  e.pluginManager.addParticleUpdater("outModes", container => {
2830
2994
  return Promise.resolve(new OutOfCanvasUpdater(container));
@@ -2841,39 +3005,9 @@
2841
3005
  this.#pluginManager = pluginManager;
2842
3006
  }
2843
3007
  init(particle) {
2844
- 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;
2845
- if (fill) {
2846
- const fillColor = AnimatableColor.create(paintColor === undefined ? undefined : AnimatableColor.create(undefined, paintColor), fill.color);
2847
- particle.fillEnabled = fill.enable;
2848
- particle.fillOpacity = getRangeValue(fill.opacity);
2849
- particle.fillAnimation = fillColor.animation;
2850
- const fillHslColor = rangeColorToHsl(this.#pluginManager, fillColor);
2851
- if (fillHslColor) {
2852
- particle.fillColor = getHslAnimationFromHsl(fillHslColor, particle.fillAnimation, container.retina.reduceFactor);
2853
- }
2854
- }
2855
- else {
2856
- particle.fillEnabled = false;
2857
- particle.fillAnimation = undefined;
2858
- particle.fillColor = undefined;
2859
- particle.fillOpacity = defaultOpacity;
2860
- }
2861
- if (stroke) {
2862
- const strokeColor = AnimatableColor.create(paintColor === undefined ? undefined : AnimatableColor.create(undefined, paintColor), stroke.color);
2863
- particle.strokeWidth = getRangeValue(stroke.width) * container.retina.pixelRatio;
2864
- particle.strokeOpacity = getRangeValue(stroke.opacity ?? defaultOpacity);
2865
- particle.strokeAnimation = strokeColor.animation;
2866
- const strokeHslColor = rangeColorToHsl(this.#pluginManager, strokeColor) ?? particle.getFillColor();
2867
- if (strokeHslColor) {
2868
- particle.strokeColor = getHslAnimationFromHsl(strokeHslColor, particle.strokeAnimation, container.retina.reduceFactor);
2869
- }
2870
- }
2871
- else {
2872
- particle.strokeAnimation = undefined;
2873
- particle.strokeColor = undefined;
2874
- particle.strokeOpacity = defaultOpacity;
2875
- particle.strokeWidth = 0;
2876
- }
3008
+ const container = this.#container, options = particle.options, paint = itemFromSingleOrMultiple(options.paint, particle.id, options.reduceDuplicates);
3009
+ this.#initFill(paint, particle, container);
3010
+ this.#initStroke(paint, particle, container);
2877
3011
  }
2878
3012
  isEnabled(particle) {
2879
3013
  const { fillAnimation, fillColor, strokeAnimation, strokeColor } = particle, fillEnabled = !!fillAnimation &&
@@ -2885,17 +3019,55 @@
2885
3019
  (strokeColor?.l.value !== undefined && strokeColor.l.enable));
2886
3020
  return !particle.destroyed && !particle.spawning && (fillEnabled || strokeEnabled);
2887
3021
  }
2888
- update(particle, delta) {
2889
- if (!this.isEnabled(particle)) {
3022
+ update(particle, delta) {
3023
+ if (!this.isEnabled(particle)) {
3024
+ return;
3025
+ }
3026
+ updateColor(particle.fillColor, delta, this.#container.hdr);
3027
+ updateColor(particle.strokeColor, delta, this.#container.hdr);
3028
+ }
3029
+ #initFill(paint, particle, container) {
3030
+ const fill = paint?.fill, color = paint?.color, paintColor = color ?? undefined;
3031
+ if (!fill) {
3032
+ particle.fillEnabled = false;
3033
+ particle.fillAnimation = undefined;
3034
+ particle.fillColor = undefined;
3035
+ particle.fillOpacity = defaultOpacity;
3036
+ return;
3037
+ }
3038
+ const fillColor = AnimatableColor.create(paintColor === undefined ? undefined : AnimatableColor.create(undefined, paintColor), fill.color);
3039
+ particle.fillEnabled = fill.enable;
3040
+ particle.fillOpacity = getRangeValue(fill.opacity);
3041
+ particle.fillAnimation = fillColor.animation;
3042
+ const fillHslColor = rangeColorToHsl(this.#pluginManager, fillColor);
3043
+ if (!fillHslColor) {
3044
+ return;
3045
+ }
3046
+ particle.fillColor = getHslAnimationFromHsl(fillHslColor, particle.fillAnimation, container.retina.reduceFactor);
3047
+ }
3048
+ #initStroke(paint, particle, container) {
3049
+ const stroke = paint?.stroke, color = paint?.color, paintColor = color ?? undefined;
3050
+ if (!stroke) {
3051
+ particle.strokeAnimation = undefined;
3052
+ particle.strokeColor = undefined;
3053
+ particle.strokeOpacity = defaultOpacity;
3054
+ particle.strokeWidth = 0;
2890
3055
  return;
2891
3056
  }
2892
- updateColor(particle.fillColor, delta, this.#container.hdr);
2893
- updateColor(particle.strokeColor, delta, this.#container.hdr);
3057
+ const strokeColor = AnimatableColor.create(paintColor === undefined ? undefined : AnimatableColor.create(undefined, paintColor), stroke.color);
3058
+ particle.strokeWidth = getRangeValue(stroke.width) * container.retina.pixelRatio;
3059
+ particle.strokeOpacity = getRangeValue(stroke.opacity ?? defaultOpacity);
3060
+ particle.strokeAnimation = strokeColor.animation;
3061
+ const strokeHslColor = rangeColorToHsl(this.#pluginManager, strokeColor) ?? particle.getFillColor();
3062
+ if (!strokeHslColor) {
3063
+ return;
3064
+ }
3065
+ particle.strokeColor = getHslAnimationFromHsl(strokeHslColor, particle.strokeAnimation, container.retina.reduceFactor);
2894
3066
  }
2895
3067
  }
2896
3068
 
2897
3069
  async function loadPaintUpdater(engine) {
2898
- engine.checkVersion("4.3.2");
3070
+ engine.checkVersion("4.5.0");
2899
3071
  await engine.pluginManager.register(e => {
2900
3072
  e.pluginManager.addParticleUpdater("paint", container => {
2901
3073
  return Promise.resolve(new PaintUpdater(e.pluginManager, container));
@@ -2937,7 +3109,7 @@
2937
3109
  if (!this.accepts(input)) {
2938
3110
  return;
2939
3111
  }
2940
- const result = rgbRegex.exec(input), radix = 10, minLength = 4, defaultAlpha = 1;
3112
+ const result = rgbRegex.exec(input), radix = 10, minLength = 4;
2941
3113
  return result
2942
3114
  ? {
2943
3115
  a: result.length > minLength ? parseAlpha(result[RgbIndexes.a]) : defaultAlpha,
@@ -2950,7 +3122,7 @@
2950
3122
  }
2951
3123
 
2952
3124
  async function loadRgbColorPlugin(engine) {
2953
- engine.checkVersion("4.3.2");
3125
+ engine.checkVersion("4.5.0");
2954
3126
  await engine.pluginManager.register(e => {
2955
3127
  e.pluginManager.addColorManager("rgb", new RgbColorManager());
2956
3128
  });
@@ -3035,7 +3207,7 @@
3035
3207
  }
3036
3208
 
3037
3209
  async function loadSizeUpdater(engine) {
3038
- engine.checkVersion("4.3.2");
3210
+ engine.checkVersion("4.5.0");
3039
3211
  await engine.pluginManager.register(e => {
3040
3212
  e.pluginManager.addParticleUpdater("size", container => {
3041
3213
  return Promise.resolve(new SizeUpdater(container));
@@ -3044,7 +3216,7 @@
3044
3216
  }
3045
3217
 
3046
3218
  async function loadBasic(engine) {
3047
- engine.checkVersion("4.3.2");
3219
+ engine.checkVersion("4.5.0");
3048
3220
  await engine.pluginManager.register(async (e) => {
3049
3221
  await Promise.all([
3050
3222
  loadBlendPlugin(e),
@@ -3137,7 +3309,7 @@
3137
3309
  }
3138
3310
 
3139
3311
  async function loadMotionPlugin(engine) {
3140
- engine.checkVersion("4.3.2");
3312
+ engine.checkVersion("4.5.0");
3141
3313
  await engine.pluginManager.register(e => {
3142
3314
  e.pluginManager.addPlugin(new MotionPlugin());
3143
3315
  });
@@ -3270,7 +3442,7 @@
3270
3442
  }
3271
3443
 
3272
3444
  async function loadRollUpdater(engine) {
3273
- engine.checkVersion("4.3.2");
3445
+ engine.checkVersion("4.5.0");
3274
3446
  await engine.pluginManager.register(e => {
3275
3447
  e.pluginManager.addParticleUpdater("roll", () => {
3276
3448
  return Promise.resolve(new RollUpdater(e.pluginManager));
@@ -3329,7 +3501,7 @@
3329
3501
  particle.pathRotation = rotateOptions.path;
3330
3502
  let rotateDirection = rotateOptions.direction;
3331
3503
  if (rotateDirection === RotateDirection.random) {
3332
- const index = Math.floor(getRandom() * double), minIndex = 0;
3504
+ const index = Math.floor(getRandom() * double);
3333
3505
  rotateDirection = index > minIndex ? RotateDirection.counterClockwise : RotateDirection.clockwise;
3334
3506
  }
3335
3507
  switch (rotateDirection) {
@@ -3376,7 +3548,7 @@
3376
3548
  }
3377
3549
 
3378
3550
  async function loadRotateUpdater(engine) {
3379
- engine.checkVersion("4.3.2");
3551
+ engine.checkVersion("4.5.0");
3380
3552
  await engine.pluginManager.register(e => {
3381
3553
  e.pluginManager.addParticleUpdater("rotate", container => {
3382
3554
  return Promise.resolve(new RotateUpdater(container));
@@ -3400,7 +3572,7 @@
3400
3572
  }
3401
3573
 
3402
3574
  async function loadSquareShape(engine) {
3403
- engine.checkVersion("4.3.2");
3575
+ engine.checkVersion("4.5.0");
3404
3576
  await engine.pluginManager.register(e => {
3405
3577
  e.pluginManager.addShape(["edge", "square"], () => Promise.resolve(new SquareDrawer()));
3406
3578
  });
@@ -3472,7 +3644,7 @@
3472
3644
  };
3473
3645
  let tiltDirection = tiltOptions.direction;
3474
3646
  if (tiltDirection === TiltDirection.random) {
3475
- const index = Math.floor(getRandom() * double), minIndex = 0;
3647
+ const index = Math.floor(getRandom() * double);
3476
3648
  tiltDirection = index > minIndex ? TiltDirection.counterClockwise : TiltDirection.clockwise;
3477
3649
  }
3478
3650
  switch (tiltDirection) {
@@ -3509,7 +3681,7 @@
3509
3681
  }
3510
3682
 
3511
3683
  async function loadTiltUpdater(engine) {
3512
- engine.checkVersion("4.3.2");
3684
+ engine.checkVersion("4.5.0");
3513
3685
  await engine.pluginManager.register(e => {
3514
3686
  e.pluginManager.addParticleUpdater("tilt", container => {
3515
3687
  return Promise.resolve(new TiltUpdater(container));
@@ -3611,7 +3783,7 @@
3611
3783
  }
3612
3784
 
3613
3785
  async function loadWobbleUpdater(engine) {
3614
- engine.checkVersion("4.3.2");
3786
+ engine.checkVersion("4.5.0");
3615
3787
  await engine.pluginManager.register(e => {
3616
3788
  e.pluginManager.addParticleUpdater("wobble", container => {
3617
3789
  return Promise.resolve(new WobbleUpdater(container));
@@ -3793,21 +3965,28 @@
3793
3965
  });
3794
3966
  }
3795
3967
  clear() {
3968
+ const visited = new Set();
3796
3969
  for (const plugin of this.#canvasClearPlugins) {
3970
+ visited.add(plugin);
3797
3971
  if (plugin.canvasClear?.() ?? false) {
3798
- return;
3972
+ return plugin;
3799
3973
  }
3800
3974
  }
3801
3975
  for (const layer of Object.values(DrawLayer)) {
3802
3976
  if (typeof layer === "number") {
3803
3977
  for (const plugin of this.#getLayerPlugins(layer)) {
3978
+ if (visited.has(plugin)) {
3979
+ continue;
3980
+ }
3981
+ visited.add(plugin);
3804
3982
  if (plugin.canvasClear?.() ?? false) {
3805
- return;
3983
+ return plugin;
3806
3984
  }
3807
3985
  }
3808
3986
  }
3809
3987
  }
3810
3988
  this.canvasClear();
3989
+ return undefined;
3811
3990
  }
3812
3991
  destroy() {
3813
3992
  this.stop();
@@ -3848,7 +4027,11 @@
3848
4027
  if (!fColor && !sColor) {
3849
4028
  return;
3850
4029
  }
3851
- 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;
4030
+ 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
4031
+ ? getStyleFromHsl(fColor, container.hdr, fillOpacity * opacity, container.peakNits, container.hdrMode)
4032
+ : undefined, stroke = sColor
4033
+ ? getStyleFromHsl(sColor, container.hdr, strokeOpacity * opacity, container.peakNits, container.hdrMode)
4034
+ : fill;
3852
4035
  transform.a = transform.b = transform.c = transform.d = undefined;
3853
4036
  colorStyles.fill = fill;
3854
4037
  colorStyles.stroke = stroke;
@@ -3881,8 +4064,7 @@
3881
4064
  });
3882
4065
  }
3883
4066
  drawParticles(delta) {
3884
- const { particles, actualOptions } = this.#container;
3885
- this.clear();
4067
+ const { particles, actualOptions } = this.#container, clearedPlugin = this.clear();
3886
4068
  particles.update(delta);
3887
4069
  this.draw(ctx => {
3888
4070
  const width = this.#canvasManager.size.width, height = this.#canvasManager.size.height;
@@ -3904,7 +4086,9 @@
3904
4086
  }
3905
4087
  }
3906
4088
  for (const plugin of this.#getLayerPlugins(DrawLayer.BackgroundMask)) {
3907
- plugin.canvasPaint?.();
4089
+ if (plugin !== clearedPlugin) {
4090
+ plugin.canvasPaint?.();
4091
+ }
3908
4092
  }
3909
4093
  for (const plugin of this.#getLayerPlugins(DrawLayer.CanvasSetup)) {
3910
4094
  plugin.drawSettingsSetup?.(ctx, delta);
@@ -3936,35 +4120,7 @@
3936
4120
  this.#layers[layer] = [];
3937
4121
  }
3938
4122
  }
3939
- for (const plugin of this.#container.plugins) {
3940
- if (plugin.particleFillColor ?? plugin.particleStrokeColor) {
3941
- this.#colorPlugins.push(plugin);
3942
- }
3943
- if (plugin.drawParticle) {
3944
- this.#drawParticlePlugins.push(plugin);
3945
- }
3946
- if (plugin.drawParticleSetup) {
3947
- this.#drawParticlesSetupPlugins.push(plugin);
3948
- }
3949
- if (plugin.drawParticleCleanup) {
3950
- this.#drawParticlesCleanupPlugins.push(plugin);
3951
- }
3952
- if (plugin.canvasClear) {
3953
- this.#canvasClearPlugins.push(plugin);
3954
- }
3955
- if (plugin.canvasPaint) {
3956
- this.#getLayerPlugins(DrawLayer.BackgroundMask).push(plugin);
3957
- }
3958
- if (plugin.drawSettingsSetup) {
3959
- this.#getLayerPlugins(DrawLayer.CanvasSetup).push(plugin);
3960
- }
3961
- if (plugin.draw) {
3962
- this.#getLayerPlugins(DrawLayer.PluginContent).push(plugin);
3963
- }
3964
- if (plugin.clearDraw ?? plugin.drawSettingsCleanup) {
3965
- this.#getLayerPlugins(DrawLayer.CanvasCleanup).push(plugin);
3966
- }
3967
- }
4123
+ this.#initPluginsArray();
3968
4124
  }
3969
4125
  initUpdaters() {
3970
4126
  this.#preDrawUpdaters = [];
@@ -4173,6 +4329,45 @@
4173
4329
  this.#reusablePluginColors[sColorIndex] = sColor;
4174
4330
  return this.#reusablePluginColors;
4175
4331
  }
4332
+ #initLayerPlugin(plugin) {
4333
+ const layerMap = [
4334
+ [DrawLayer.BackgroundMask, !!plugin.canvasPaint],
4335
+ [DrawLayer.CanvasSetup, !!plugin.drawSettingsSetup],
4336
+ [DrawLayer.PluginContent, !!plugin.draw],
4337
+ [DrawLayer.CanvasCleanup, !!(plugin.clearDraw ?? plugin.drawSettingsCleanup)],
4338
+ ];
4339
+ for (const [layer, active] of layerMap) {
4340
+ if (active) {
4341
+ this.#layers[layer].push(plugin);
4342
+ }
4343
+ }
4344
+ }
4345
+ #initPluginsArray() {
4346
+ for (const plugin of this.#container.plugins) {
4347
+ if (plugin.particleFillColor ?? plugin.particleStrokeColor) {
4348
+ this.#colorPlugins.push(plugin);
4349
+ }
4350
+ if (plugin.drawParticle) {
4351
+ this.#drawParticlePlugins.push(plugin);
4352
+ }
4353
+ if (plugin.drawParticleSetup) {
4354
+ this.#drawParticlesSetupPlugins.push(plugin);
4355
+ }
4356
+ if (plugin.drawParticleCleanup) {
4357
+ this.#drawParticlesCleanupPlugins.push(plugin);
4358
+ }
4359
+ if (plugin.canvasClear) {
4360
+ this.#canvasClearPlugins.push(plugin);
4361
+ }
4362
+ this.#initLayerPlugin(plugin);
4363
+ }
4364
+ }
4365
+ #isSupportedElement(element) {
4366
+ return ((typeof HTMLCanvasElement !== "undefined" && element instanceof HTMLCanvasElement) ||
4367
+ (typeof OffscreenCanvas !== "undefined" && element instanceof OffscreenCanvas) ||
4368
+ (typeof HTMLVideoElement !== "undefined" && element instanceof HTMLVideoElement) ||
4369
+ (typeof HTMLImageElement !== "undefined" && element instanceof HTMLImageElement));
4370
+ }
4176
4371
  #resolveBackgroundElement() {
4177
4372
  const background = this.#container.actualOptions.background;
4178
4373
  this.#backgroundElement = null;
@@ -4182,7 +4377,7 @@
4182
4377
  if (typeof background.element === "string") {
4183
4378
  if (typeof document !== "undefined") {
4184
4379
  const node = document.querySelector(background.element);
4185
- if (node instanceof HTMLCanvasElement || node instanceof HTMLVideoElement || node instanceof HTMLImageElement) {
4380
+ if (node && this.#isSupportedElement(node)) {
4186
4381
  this.#backgroundElement = node;
4187
4382
  }
4188
4383
  else if (node) {
@@ -4193,10 +4388,7 @@
4193
4388
  }
4194
4389
  }
4195
4390
  }
4196
- else if (background.element instanceof HTMLCanvasElement ||
4197
- background.element instanceof OffscreenCanvas ||
4198
- background.element instanceof HTMLVideoElement ||
4199
- background.element instanceof HTMLImageElement) {
4391
+ else if (this.#isSupportedElement(background.element)) {
4200
4392
  this.#backgroundElement = background.element;
4201
4393
  }
4202
4394
  }
@@ -4214,7 +4406,7 @@
4214
4406
  return transferredCanvas;
4215
4407
  }
4216
4408
  if (typeof canvas.transferControlToOffscreen !== "function") {
4217
- throw new TypeError("OffscreenCanvas is required but not supported by this browser");
4409
+ throw new TypeError(getErrorMessage(ErrorCodes$1.offscreenCanvasUnsupported));
4218
4410
  }
4219
4411
  try {
4220
4412
  const offscreenCanvas = canvas.transferControlToOffscreen();
@@ -4222,10 +4414,16 @@
4222
4414
  return offscreenCanvas;
4223
4415
  }
4224
4416
  catch {
4225
- throw new TypeError("OffscreenCanvas transfer failed");
4417
+ throw new TypeError(getErrorMessage(ErrorCodes$1.offscreenCanvasTransferFailed));
4226
4418
  }
4227
4419
  }, isHtmlCanvasElement = (canvas) => {
4228
4420
  return typeof HTMLCanvasElement !== "undefined" && canvas instanceof HTMLCanvasElement;
4421
+ }, getEffectiveColorSpace = (context) => {
4422
+ if (!context) {
4423
+ return undefined;
4424
+ }
4425
+ const colorInfo = context;
4426
+ return colorInfo.getContextAttributes?.().colorSpace ?? undefined;
4229
4427
  };
4230
4428
  function setStyle(canvas, style, important = false) {
4231
4429
  if (!style) {
@@ -4264,6 +4462,7 @@
4264
4462
  zoom = defaultZoom;
4265
4463
  #container;
4266
4464
  #generated;
4465
+ #hdrMediaListeners;
4267
4466
  #mutationObserver;
4268
4467
  #originalStyle;
4269
4468
  #pluginManager;
@@ -4328,7 +4527,6 @@
4328
4527
  });
4329
4528
  this.resize();
4330
4529
  this.#initStyle();
4331
- this.initBackground();
4332
4530
  this.#safeMutationObserver(obs => {
4333
4531
  const element = this.domElement;
4334
4532
  if (!element || !(element instanceof Node)) {
@@ -4338,6 +4536,8 @@
4338
4536
  });
4339
4537
  this.initPlugins();
4340
4538
  this.#initContext();
4539
+ this.initBackground();
4540
+ this.#initHdrListeners();
4341
4541
  this.render.init();
4342
4542
  }
4343
4543
  initBackground() {
@@ -4347,7 +4547,8 @@
4347
4547
  }
4348
4548
  const elementStyle = element.style, color = rangeColorToRgb(this.#pluginManager, background.color);
4349
4549
  if (color) {
4350
- elementStyle.backgroundColor = getStyleFromRgb(color, container.actualOptions.hdr, background.opacity);
4550
+ const hdrOptions = container.actualOptions.hdr;
4551
+ elementStyle.backgroundColor = getStyleFromRgb(color, container.hdr, background.opacity, hdrOptions.peakNits, toEnumValue(HdrMode, hdrOptions.mode, HdrMode.standard));
4351
4552
  }
4352
4553
  else {
4353
4554
  elementStyle.backgroundColor = "";
@@ -4444,6 +4645,7 @@
4444
4645
  obs.disconnect();
4445
4646
  });
4446
4647
  this.#mutationObserver = undefined;
4648
+ this.#removeHdrListeners();
4447
4649
  this.render.stop();
4448
4650
  }
4449
4651
  async windowResize() {
@@ -4463,9 +4665,16 @@
4463
4665
  }
4464
4666
  }
4465
4667
  #initContext() {
4466
- const container = this.#container, canSupportHdr = container.actualOptions.hdr &&
4668
+ const container = this.#container, canSupportHdr = container.actualOptions.hdr.enable &&
4467
4669
  safeMatchMedia("(color-gamut: p3)")?.matches &&
4468
4670
  safeMatchMedia("(dynamic-range: high)")?.matches;
4671
+ container.hdrMode = toEnumValue(HdrMode, container.actualOptions.hdr.mode, HdrMode.standard);
4672
+ container.peakNits = container.actualOptions.hdr.peakNits;
4673
+ const renderCanvas = this.renderCanvas;
4674
+ if (!renderCanvas) {
4675
+ container.hdr = canSupportHdr ?? false;
4676
+ return;
4677
+ }
4469
4678
  this.render.setContextSettings({
4470
4679
  alpha: true,
4471
4680
  desynchronized: true,
@@ -4474,11 +4683,51 @@
4474
4683
  ? { colorSpace: "display-p3", colorType: "float16" }
4475
4684
  : { colorSpace: "srgb" }),
4476
4685
  });
4477
- const renderCanvas = this.renderCanvas;
4478
- if (!renderCanvas) {
4479
- return;
4686
+ let context;
4687
+ try {
4688
+ context = renderCanvas.getContext("2d", this.render.settings);
4689
+ }
4690
+ catch {
4691
+ context = null;
4692
+ }
4693
+ if (canSupportHdr && !context) {
4694
+ const sdrSettings = {
4695
+ alpha: true,
4696
+ desynchronized: true,
4697
+ willReadFrequently: false,
4698
+ colorSpace: "srgb",
4699
+ };
4700
+ this.render.setContextSettings(sdrSettings);
4701
+ try {
4702
+ context = renderCanvas.getContext("2d", sdrSettings);
4703
+ }
4704
+ catch {
4705
+ context = null;
4706
+ }
4707
+ }
4708
+ this.render.setContext(context);
4709
+ if (context) {
4710
+ const effectiveColorSpace = getEffectiveColorSpace(context);
4711
+ if (effectiveColorSpace !== undefined) {
4712
+ container.hdr = effectiveColorSpace === "display-p3";
4713
+ }
4480
4714
  }
4481
- this.render.setContext(renderCanvas.getContext("2d", this.render.settings));
4715
+ }
4716
+ #initHdrListeners() {
4717
+ this.#removeHdrListeners();
4718
+ const p3Query = safeMatchMedia("(color-gamut: p3)"), hdrQuery = safeMatchMedia("(dynamic-range: high)"), handleChange = () => {
4719
+ this.#initContext();
4720
+ this.initBackground();
4721
+ }, listeners = [];
4722
+ if (p3Query) {
4723
+ p3Query.addEventListener("change", handleChange);
4724
+ listeners.push({ handler: handleChange, mql: p3Query });
4725
+ }
4726
+ if (hdrQuery) {
4727
+ hdrQuery.addEventListener("change", handleChange);
4728
+ listeners.push({ handler: handleChange, mql: hdrQuery });
4729
+ }
4730
+ this.#hdrMediaListeners = listeners;
4482
4731
  }
4483
4732
  #initStyle() {
4484
4733
  const element = this.domElement, options = this.#container.actualOptions;
@@ -4502,6 +4751,15 @@
4502
4751
  element.style.setProperty(key, value, "important");
4503
4752
  }
4504
4753
  }
4754
+ #removeHdrListeners() {
4755
+ if (!this.#hdrMediaListeners) {
4756
+ return;
4757
+ }
4758
+ for (const { handler, mql } of this.#hdrMediaListeners) {
4759
+ mql.removeEventListener("change", handler);
4760
+ }
4761
+ this.#hdrMediaListeners = undefined;
4762
+ }
4505
4763
  #repairStyle() {
4506
4764
  const element = this.domElement;
4507
4765
  if (!element) {
@@ -4591,8 +4849,7 @@
4591
4849
  this.#resizeTimeout = undefined;
4592
4850
  }
4593
4851
  const handleResize = async () => {
4594
- const canvas = this.#container.canvas;
4595
- await canvas.windowResize();
4852
+ await this.#container.canvas.windowResize();
4596
4853
  };
4597
4854
  this.#resizeTimeout = setTimeout(() => void handleResize(), this.#container.actualOptions.resize.delay * millisecondsToSeconds);
4598
4855
  }
@@ -4620,8 +4877,8 @@
4620
4877
  }
4621
4878
  else if (!this.#resizeObserver && add && canvasEl) {
4622
4879
  this.#resizeObserver = new ResizeObserver((entries) => {
4623
- const entry = entries.find(e => e.target === canvasEl);
4624
- if (!entry) {
4880
+ const res = entries.some(e => e.target === canvasEl);
4881
+ if (!res) {
4625
4882
  return;
4626
4883
  }
4627
4884
  this.#handleWindowResize();
@@ -4885,10 +5142,10 @@
4885
5142
  return this.#modifiers.find(m => m.id === id);
4886
5143
  }
4887
5144
  getOpacity() {
4888
- 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;
4889
- this.#cachedOpacityData.fillOpacity = opacity * fillOpacity * zOpacityFactor;
5145
+ 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;
5146
+ this.#cachedOpacityData.fillOpacity = this.fillOpacity ?? defaultOpacity$1;
4890
5147
  this.#cachedOpacityData.opacity = opacity * zOpacityFactor;
4891
- this.#cachedOpacityData.strokeOpacity = opacity * strokeOpacity * zOpacityFactor;
5148
+ this.#cachedOpacityData.strokeOpacity = this.strokeOpacity ?? defaultOpacity$1;
4892
5149
  return this.#cachedOpacityData;
4893
5150
  }
4894
5151
  getPosition() {
@@ -5135,7 +5392,7 @@
5135
5392
  #initPosition(position) {
5136
5393
  const container = this.#container, zIndexValue = Math.floor(getRangeValue(this.options.zIndex.value)), initialPosition = this.#calcPosition(position, clamp(zIndexValue, minZ, container.zLayers));
5137
5394
  if (!initialPosition) {
5138
- throw new Error("a valid position cannot be found for particle");
5395
+ throw new Error(getErrorMessage(ErrorCodes$1.particlePositionNotFound));
5139
5396
  }
5140
5397
  this.position = initialPosition;
5141
5398
  this.initialPosition = this.position.copy();
@@ -5184,6 +5441,12 @@
5184
5441
  this.#circlePoolIdx = 0;
5185
5442
  this.#rectanglePoolIdx = 0;
5186
5443
  }
5444
+ get cellSize() {
5445
+ return this.#cellSize;
5446
+ }
5447
+ set cellSize(value) {
5448
+ this.#pendingCellSize = value;
5449
+ }
5187
5450
  clear() {
5188
5451
  this.#cells.clear();
5189
5452
  const pendingCellSize = this.#pendingCellSize;
@@ -5207,18 +5470,7 @@
5207
5470
  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);
5208
5471
  for (let cx = minCellX; cx <= maxCellX; cx++) {
5209
5472
  for (let cy = minCellY; cy <= maxCellY; cy++) {
5210
- const key = `${cx}_${cy}`, cellParticles = this.#cells.get(key);
5211
- if (!cellParticles) {
5212
- continue;
5213
- }
5214
- for (const p of cellParticles) {
5215
- if (check && !check(p)) {
5216
- continue;
5217
- }
5218
- if (range.contains(p.getPosition())) {
5219
- out.push(p);
5220
- }
5221
- }
5473
+ this.#queryCell(cx, cy, range, check, out);
5222
5474
  }
5223
5475
  }
5224
5476
  return out;
@@ -5233,14 +5485,23 @@
5233
5485
  this.#releaseShapes();
5234
5486
  return result;
5235
5487
  }
5236
- setCellSize(cellSize) {
5237
- this.#pendingCellSize = cellSize;
5238
- }
5239
5488
  #acquireCircle(x, y, r) {
5240
- return (this.#circlePool[this.#circlePoolIdx++] ??= new Circle(x, y, r)).reset(x, y, r);
5489
+ const idx = this.#circlePoolIdx++;
5490
+ let circle = this.#circlePool[idx];
5491
+ if (!circle) {
5492
+ circle = new Circle(x, y, r);
5493
+ this.#circlePool[idx] = circle;
5494
+ }
5495
+ return circle.reset(x, y, r);
5241
5496
  }
5242
5497
  #acquireRectangle(x, y, w, h) {
5243
- return (this.#rectanglePool[this.#rectanglePoolIdx++] ??= new Rectangle(x, y, w, h)).reset(x, y, w, h);
5498
+ const idx = this.#rectanglePoolIdx++;
5499
+ let rectangle = this.#rectanglePool[idx];
5500
+ if (!rectangle) {
5501
+ rectangle = new Rectangle(x, y, w, h);
5502
+ this.#rectanglePool[idx] = rectangle;
5503
+ }
5504
+ return rectangle.reset(x, y, w, h);
5244
5505
  }
5245
5506
  #cellKeyFromCoords(x, y) {
5246
5507
  const cellX = Math.floor(x / this.#cellSize), cellY = Math.floor(y / this.#cellSize);
@@ -5267,6 +5528,20 @@
5267
5528
  }
5268
5529
  return null;
5269
5530
  }
5531
+ #queryCell(cx, cy, range, check, out) {
5532
+ const cellParticles = this.#cells.get(`${cx}_${cy}`);
5533
+ if (!cellParticles) {
5534
+ return;
5535
+ }
5536
+ for (const p of cellParticles) {
5537
+ if (check && !check(p)) {
5538
+ continue;
5539
+ }
5540
+ if (range.contains(p.getPosition())) {
5541
+ out.push(p);
5542
+ }
5543
+ }
5544
+ }
5270
5545
  #releaseShapes() {
5271
5546
  this.#circlePoolIdx = 0;
5272
5547
  this.#rectanglePoolIdx = 0;
@@ -5275,9 +5550,9 @@
5275
5550
 
5276
5551
  class ParticlesManager {
5277
5552
  checkParticlePositionPlugins;
5278
- grid;
5279
5553
  #array;
5280
5554
  #container;
5555
+ #grid;
5281
5556
  #groupLimits;
5282
5557
  #limit;
5283
5558
  #nextId;
@@ -5301,7 +5576,7 @@
5301
5576
  this.#groupLimits = new Map();
5302
5577
  this.#particleBuckets = new Map();
5303
5578
  this.#zBuckets = this.#createBuckets(this.#container.zLayers);
5304
- this.grid = new SpatialHashGrid(spatialHashGridCellSize);
5579
+ this.#grid = new SpatialHashGrid(spatialHashGridCellSize);
5305
5580
  this.checkParticlePositionPlugins = [];
5306
5581
  this.#particleResetPlugins = [];
5307
5582
  this.#particleUpdatePlugins = [];
@@ -5312,23 +5587,12 @@
5312
5587
  get count() {
5313
5588
  return this.#array.length;
5314
5589
  }
5590
+ get grid() {
5591
+ return this.#grid;
5592
+ }
5315
5593
  addParticle(position, overrideOptions, group, initializer) {
5316
- const limitMode = this.#container.actualOptions.particles.number.limit.mode, limit = group === undefined ? this.#limit : (this.#groupLimits.get(group) ?? this.#limit), currentCount = this.count;
5317
- if (limit > minLimit) {
5318
- switch (limitMode) {
5319
- case LimitMode.delete: {
5320
- const countToRemove = currentCount + countOffset - limit;
5321
- if (countToRemove > minCount) {
5322
- this.removeQuantity(countToRemove);
5323
- }
5324
- break;
5325
- }
5326
- case LimitMode.wait:
5327
- if (currentCount >= limit) {
5328
- return;
5329
- }
5330
- break;
5331
- }
5594
+ if (this.#checkAndApplyLimits(group, this.count)) {
5595
+ return;
5332
5596
  }
5333
5597
  try {
5334
5598
  const particle = this.#pool.pop() ?? new Particle(this.#pluginManager, this.#container);
@@ -5392,7 +5656,7 @@
5392
5656
  return this.#array[index];
5393
5657
  }
5394
5658
  async init() {
5395
- const container = this.#container, options = container.actualOptions;
5659
+ const container = this.#container;
5396
5660
  this.checkParticlePositionPlugins = [];
5397
5661
  this.#updatePlugins = [];
5398
5662
  this.#particleUpdatePlugins = [];
@@ -5401,59 +5665,16 @@
5401
5665
  this.#postParticleUpdatePlugins = [];
5402
5666
  this.#particleBuckets.clear();
5403
5667
  this.#resetBuckets(container.zLayers);
5404
- this.grid = new SpatialHashGrid(spatialHashGridCellSize * container.retina.pixelRatio);
5405
- for (const plugin of container.plugins) {
5406
- if (plugin.redrawInit) {
5407
- await plugin.redrawInit();
5408
- }
5409
- if (plugin.checkParticlePosition) {
5410
- this.checkParticlePositionPlugins.push(plugin);
5411
- }
5412
- if (plugin.update) {
5413
- this.#updatePlugins.push(plugin);
5414
- }
5415
- if (plugin.particleUpdate) {
5416
- this.#particleUpdatePlugins.push(plugin);
5417
- }
5418
- if (plugin.postUpdate) {
5419
- this.#postUpdatePlugins.push(plugin);
5420
- }
5421
- if (plugin.particleReset) {
5422
- this.#particleResetPlugins.push(plugin);
5423
- }
5424
- if (plugin.postParticleUpdate) {
5425
- this.#postParticleUpdatePlugins.push(plugin);
5426
- }
5427
- }
5428
- await this.#container.initDrawersAndUpdaters();
5429
- for (const drawer of this.#container.effectDrawers.values()) {
5430
- await drawer.init?.(container);
5431
- }
5432
- for (const drawer of this.#container.shapeDrawers.values()) {
5433
- await drawer.init?.(container);
5434
- }
5435
- let handled = false;
5436
- for (const plugin of container.plugins) {
5437
- handled = plugin.particlesInitialization?.() ?? handled;
5438
- if (handled) {
5439
- break;
5440
- }
5441
- }
5442
- if (!handled) {
5443
- const particlesOptions = options.particles, groups = particlesOptions.groups;
5444
- for (const group in groups) {
5445
- const groupOptions = groups[group];
5446
- if (!groupOptions) {
5447
- continue;
5448
- }
5449
- for (let i = this.count, j = 0; j < groupOptions.number.value && i < particlesOptions.number.value; i++, j++) {
5450
- this.addParticle(undefined, groupOptions, group);
5451
- }
5452
- }
5453
- for (let i = this.count; i < particlesOptions.number.value; i++) {
5454
- this.addParticle();
5668
+ this.#grid = new SpatialHashGrid(spatialHashGridCellSize * container.retina.pixelRatio);
5669
+ this.#applyLimits(container.actualOptions.particles);
5670
+ const particlesOptions = container.actualOptions.particles, groups = particlesOptions.groups;
5671
+ for (const group in groups) {
5672
+ const groupData = groups[group];
5673
+ if (groupData) {
5674
+ this.#applyLimits(loadParticlesOptions(this.#pluginManager, this.#container, groupData), group, groupData);
5455
5675
  }
5456
5676
  }
5677
+ await this.#initPlugins();
5457
5678
  }
5458
5679
  push(nb, position, overrideOptions, group) {
5459
5680
  for (let i = 0; i < nb; i++) {
@@ -5468,13 +5689,13 @@
5468
5689
  remove(particle, group, override) {
5469
5690
  this.removeAt(this.#array.indexOf(particle), undefined, group, override);
5470
5691
  }
5471
- removeAt(index, quantity = defaultRemoveQuantity, group, override) {
5692
+ removeAt(index, quantity = defaultRemoveQuantity, group, override, matchGroup = true) {
5472
5693
  if (index < minIndex || index > this.count) {
5473
5694
  return;
5474
5695
  }
5475
5696
  let deleted = 0;
5476
5697
  for (let i = index; deleted < quantity && i < this.count; i++) {
5477
- if (this.#removeParticle(i, group, override)) {
5698
+ if (this.#removeParticle(i, group, override, matchGroup)) {
5478
5699
  i--;
5479
5700
  deleted++;
5480
5701
  }
@@ -5505,7 +5726,7 @@
5505
5726
  this.#resizeFactor = factor;
5506
5727
  }
5507
5728
  update(delta) {
5508
- this.grid.clear();
5729
+ this.#grid.clear();
5509
5730
  for (const plugin of this.#updatePlugins) {
5510
5731
  plugin.update?.(delta);
5511
5732
  }
@@ -5516,7 +5737,7 @@
5516
5737
  this.#updateParticlesPhase2(delta, particlesToDelete);
5517
5738
  if (particlesToDelete.size) {
5518
5739
  for (const particle of particlesToDelete) {
5519
- this.remove(particle);
5740
+ this.remove(particle, particle.group);
5520
5741
  }
5521
5742
  }
5522
5743
  this.#resizeFactor = undefined;
@@ -5527,12 +5748,7 @@
5527
5748
  #applyDensity(options, pluginsCount, group, groupOptions) {
5528
5749
  const numberOptions = options.number;
5529
5750
  if (!numberOptions.density.enable) {
5530
- if (group === undefined) {
5531
- this.#limit = numberOptions.limit.value;
5532
- }
5533
- else if (groupOptions?.number.limit.value ?? numberOptions.limit.value) {
5534
- this.#groupLimits.set(group, groupOptions?.number.limit.value ?? numberOptions.limit.value);
5535
- }
5751
+ this.#applyLimits(options, group, groupOptions);
5536
5752
  return;
5537
5753
  }
5538
5754
  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);
@@ -5540,7 +5756,10 @@
5540
5756
  this.#limit = numberOptions.limit.value * densityFactor;
5541
5757
  }
5542
5758
  else {
5543
- this.#groupLimits.set(group, numberOptions.limit.value * densityFactor);
5759
+ this.#groupLimits.set(group, {
5760
+ limit: numberOptions.limit.value * densityFactor,
5761
+ mode: toEnumValue(LimitMode, numberOptions.limit.mode, LimitMode.delete),
5762
+ });
5544
5763
  }
5545
5764
  if (particlesCount < particlesNumber) {
5546
5765
  this.push(Math.abs(particlesNumber - particlesCount), undefined, options, group);
@@ -5549,6 +5768,55 @@
5549
5768
  this.removeQuantity(particlesCount - particlesNumber, group);
5550
5769
  }
5551
5770
  }
5771
+ #applyLimits(options, group, groupOptions) {
5772
+ if (group === undefined) {
5773
+ this.#limit = options.number.limit.value;
5774
+ const groups = this.#container.actualOptions.particles.groups;
5775
+ for (const existingGroup of this.#groupLimits.keys()) {
5776
+ if (!(existingGroup in groups)) {
5777
+ this.#groupLimits.delete(existingGroup);
5778
+ }
5779
+ }
5780
+ }
5781
+ else {
5782
+ const limitValue = groupOptions?.number?.limit?.value ?? options.number.limit.value;
5783
+ if (limitValue > minLimit) {
5784
+ this.#groupLimits.set(group, {
5785
+ limit: limitValue,
5786
+ mode: toEnumValue(LimitMode, groupOptions?.number?.limit?.mode ?? options.number.limit.mode, LimitMode.delete),
5787
+ });
5788
+ }
5789
+ else {
5790
+ this.#groupLimits.delete(group);
5791
+ }
5792
+ }
5793
+ }
5794
+ #checkAndApplyLimits(group, currentCount) {
5795
+ const globalLimit = this.#limit, globalMode = this.#container.actualOptions.particles.number.limit.mode;
5796
+ if (globalLimit > minLimit && globalMode === LimitMode.wait && currentCount >= globalLimit) {
5797
+ return true;
5798
+ }
5799
+ const groupLimitEntry = group === undefined ? undefined : this.#groupLimits.get(group);
5800
+ if (groupLimitEntry && groupLimitEntry.limit > minLimit && groupLimitEntry.mode === LimitMode.wait) {
5801
+ const groupCount = this.filter(t => t.group === group).length;
5802
+ if (groupCount >= groupLimitEntry.limit) {
5803
+ return true;
5804
+ }
5805
+ }
5806
+ if (groupLimitEntry && groupLimitEntry.limit > minLimit && groupLimitEntry.mode === LimitMode.delete) {
5807
+ const groupCountToRemove = this.filter(t => t.group === group).length + countOffset - groupLimitEntry.limit;
5808
+ if (groupCountToRemove > minCount) {
5809
+ this.removeQuantity(groupCountToRemove, group);
5810
+ }
5811
+ }
5812
+ if (globalLimit > minLimit && globalMode === LimitMode.delete) {
5813
+ const globalCountToRemove = this.count + countOffset - globalLimit;
5814
+ if (globalCountToRemove > minCount) {
5815
+ this.#removeAny(globalCountToRemove);
5816
+ }
5817
+ }
5818
+ return false;
5819
+ }
5552
5820
  #createBuckets(zLayers) {
5553
5821
  const bucketCount = Math.max(Math.floor(zLayers), one);
5554
5822
  return Array.from({ length: bucketCount }, () => []);
@@ -5571,6 +5839,70 @@
5571
5839
  }
5572
5840
  return ((canvasSize.width * canvasSize.height) / (densityOptions.height * densityOptions.width * pxRatio ** squareExp));
5573
5841
  }
5842
+ async #initDrawersAndUpdaters() {
5843
+ const container = this.#container;
5844
+ await container.initDrawersAndUpdaters();
5845
+ for (const drawer of container.effectDrawers.values()) {
5846
+ await drawer.init?.(container);
5847
+ }
5848
+ for (const drawer of container.shapeDrawers.values()) {
5849
+ await drawer.init?.(container);
5850
+ }
5851
+ }
5852
+ async #initPlugins() {
5853
+ await this.#initPluginsArrays();
5854
+ await this.#initDrawersAndUpdaters();
5855
+ let handled = false;
5856
+ const container = this.#container;
5857
+ for (const plugin of container.plugins) {
5858
+ handled = plugin.particlesInitialization?.() ?? handled;
5859
+ if (handled) {
5860
+ break;
5861
+ }
5862
+ }
5863
+ if (handled) {
5864
+ return;
5865
+ }
5866
+ const particlesOptions = container.actualOptions.particles, groups = particlesOptions.groups;
5867
+ for (const group in groups) {
5868
+ const groupOptions = groups[group];
5869
+ if (!groupOptions) {
5870
+ continue;
5871
+ }
5872
+ for (let i = this.count, j = 0; j < groupOptions.number.value && i < particlesOptions.number.value; i++, j++) {
5873
+ this.addParticle(undefined, groupOptions, group);
5874
+ }
5875
+ }
5876
+ for (let i = this.count; i < particlesOptions.number.value; i++) {
5877
+ this.addParticle();
5878
+ }
5879
+ }
5880
+ async #initPluginsArrays() {
5881
+ const container = this.#container;
5882
+ for (const plugin of container.plugins) {
5883
+ if (plugin.redrawInit) {
5884
+ await plugin.redrawInit();
5885
+ }
5886
+ if (plugin.checkParticlePosition) {
5887
+ this.checkParticlePositionPlugins.push(plugin);
5888
+ }
5889
+ if (plugin.update) {
5890
+ this.#updatePlugins.push(plugin);
5891
+ }
5892
+ if (plugin.particleUpdate) {
5893
+ this.#particleUpdatePlugins.push(plugin);
5894
+ }
5895
+ if (plugin.postUpdate) {
5896
+ this.#postUpdatePlugins.push(plugin);
5897
+ }
5898
+ if (plugin.particleReset) {
5899
+ this.#particleResetPlugins.push(plugin);
5900
+ }
5901
+ if (plugin.postParticleUpdate) {
5902
+ this.#postParticleUpdatePlugins.push(plugin);
5903
+ }
5904
+ }
5905
+ }
5574
5906
  #insertParticleIntoBucket(particle) {
5575
5907
  const bucketIndex = this.#getBucketIndex(particle.position.z), bucket = this.#zBuckets[bucketIndex];
5576
5908
  if (!bucket) {
@@ -5579,12 +5911,15 @@
5579
5911
  bucket.push(particle);
5580
5912
  this.#particleBuckets.set(particle.id, bucketIndex);
5581
5913
  }
5582
- #removeParticle(index, group, override) {
5914
+ #removeAny(quantity) {
5915
+ this.removeAt(minIndex, quantity, undefined, undefined, false);
5916
+ }
5917
+ #removeParticle(index, group, override, matchGroup = true) {
5583
5918
  const particle = this.#array[index];
5584
5919
  if (!particle) {
5585
5920
  return false;
5586
5921
  }
5587
- if (particle.group !== group) {
5922
+ if (matchGroup && particle.group !== group) {
5588
5923
  return false;
5589
5924
  }
5590
5925
  this.#array.splice(index, deleteCount);
@@ -5671,7 +6006,7 @@
5671
6006
  particlesToDelete.add(particle);
5672
6007
  continue;
5673
6008
  }
5674
- this.grid.insert(particle);
6009
+ this.#grid.insert(particle);
5675
6010
  }
5676
6011
  return particlesToDelete;
5677
6012
  }
@@ -5743,6 +6078,7 @@
5743
6078
  effectDrawers;
5744
6079
  fpsLimit;
5745
6080
  hdr;
6081
+ hdrMode;
5746
6082
  id;
5747
6083
  pageHidden;
5748
6084
  particleCreatedPlugins;
@@ -5750,6 +6086,7 @@
5750
6086
  particlePositionPlugins;
5751
6087
  particleUpdaters;
5752
6088
  particles;
6089
+ peakNits;
5753
6090
  plugins;
5754
6091
  retina;
5755
6092
  shapeDrawers;
@@ -5780,6 +6117,8 @@
5780
6117
  this.id = Symbol(id);
5781
6118
  this.fpsLimit = 120;
5782
6119
  this.hdr = false;
6120
+ this.hdrMode = HdrMode.standard;
6121
+ this.peakNits = 400;
5783
6122
  this.#smooth = false;
5784
6123
  this.#delay = 0;
5785
6124
  this.#duration = 0;
@@ -5843,7 +6182,6 @@
5843
6182
  this.shapeDrawers = new Map();
5844
6183
  this.particleUpdaters = [];
5845
6184
  this.plugins.length = 0;
5846
- this.#pluginManager.clearPlugins(this);
5847
6185
  this.destroyed = true;
5848
6186
  this.#onDestroy(remove);
5849
6187
  this.dispatchEvent(EventType.containerDestroyed);
@@ -5896,31 +6234,15 @@
5896
6234
  await this.initDrawersAndUpdaters();
5897
6235
  this.#options = loadContainerOptions(this.#pluginManager, this, this.#initialSourceOptions, this.sourceOptions);
5898
6236
  this.actualOptions = loadContainerOptions(this.#pluginManager, this, this.#options);
5899
- this.plugins.length = 0;
5900
- this.particleDestroyedPlugins.length = 0;
5901
- this.particleCreatedPlugins.length = 0;
5902
- this.particlePositionPlugins.length = 0;
5903
- for (const [plugin, containerPlugin] of allContainerPlugins) {
5904
- if (plugin.needsPlugin(this.actualOptions)) {
5905
- this.plugins.push(containerPlugin);
5906
- if (containerPlugin.particleCreated) {
5907
- this.particleCreatedPlugins.push(containerPlugin);
5908
- }
5909
- if (containerPlugin.particleDestroyed) {
5910
- this.particleDestroyedPlugins.push(containerPlugin);
5911
- }
5912
- if (containerPlugin.particlePosition) {
5913
- this.particlePositionPlugins.push(containerPlugin);
5914
- }
5915
- }
5916
- }
6237
+ this.#initPlugins(allContainerPlugins);
5917
6238
  this.retina.init();
5918
6239
  this.canvas.init();
5919
6240
  this.updateActualOptions();
5920
6241
  this.canvas.initBackground();
5921
6242
  this.canvas.resize();
5922
- const { delay, duration, fpsLimit, hdr, smooth, zLayers } = this.actualOptions;
5923
- this.hdr = hdr;
6243
+ const { delay, duration, fpsLimit, smooth, zLayers } = this.actualOptions, hdrOptions = this.actualOptions.hdr;
6244
+ this.hdrMode = toEnumValue(HdrMode, hdrOptions.mode, HdrMode.standard);
6245
+ this.peakNits = hdrOptions.peakNits;
5924
6246
  this.zLayers = zLayers;
5925
6247
  this.#duration = getRangeValue(duration) * millisecondsToSeconds;
5926
6248
  this.#delay = getRangeValue(delay) * millisecondsToSeconds;
@@ -5940,9 +6262,9 @@
5940
6262
  }
5941
6263
  async initDrawersAndUpdaters() {
5942
6264
  const pluginManager = this.#pluginManager;
5943
- this.effectDrawers = await pluginManager.getEffectDrawers(this, true);
5944
- this.shapeDrawers = await pluginManager.getShapeDrawers(this, true);
5945
- this.particleUpdaters = await pluginManager.getUpdaters(this, true);
6265
+ this.effectDrawers = await getItemMapFromInitializer(this, pluginManager.initializers.effects);
6266
+ this.shapeDrawers = await getItemMapFromInitializer(this, pluginManager.initializers.shapes);
6267
+ this.particleUpdaters = await getItemsFromInitializer(this, pluginManager.initializers.updaters);
5946
6268
  }
5947
6269
  pause() {
5948
6270
  if (!guardCheck(this)) {
@@ -6053,6 +6375,27 @@
6053
6375
  }
6054
6376
  return refresh;
6055
6377
  }
6378
+ #initPlugins(allContainerPlugins) {
6379
+ this.plugins.length = 0;
6380
+ this.particleDestroyedPlugins.length = 0;
6381
+ this.particleCreatedPlugins.length = 0;
6382
+ this.particlePositionPlugins.length = 0;
6383
+ for (const [plugin, containerPlugin] of allContainerPlugins) {
6384
+ if (!plugin.needsPlugin(this.actualOptions)) {
6385
+ continue;
6386
+ }
6387
+ this.plugins.push(containerPlugin);
6388
+ if (containerPlugin.particleCreated) {
6389
+ this.particleCreatedPlugins.push(containerPlugin);
6390
+ }
6391
+ if (containerPlugin.particleDestroyed) {
6392
+ this.particleDestroyedPlugins.push(containerPlugin);
6393
+ }
6394
+ if (containerPlugin.particlePosition) {
6395
+ this.particlePositionPlugins.push(containerPlugin);
6396
+ }
6397
+ }
6398
+ }
6056
6399
  #nextFrame(timestamp) {
6057
6400
  try {
6058
6401
  if (!this.#smooth &&
@@ -6329,11 +6672,11 @@
6329
6672
  }
6330
6673
  }
6331
6674
  async #init() {
6332
- const availablePathGenerators = await this.#pluginManager.getPathGenerators?.(this.#container, true);
6333
- if (!availablePathGenerators) {
6675
+ const pluginManager = this.#pluginManager;
6676
+ if (!pluginManager.initializers.pathGenerators) {
6334
6677
  return;
6335
6678
  }
6336
- this.availablePathGenerators = availablePathGenerators;
6679
+ this.availablePathGenerators = await getItemMapFromInitializer(this.#container, pluginManager.initializers.pathGenerators);
6337
6680
  this.pathGenerators = new Map();
6338
6681
  for (const pathGenerator of this.pathGenerators.values()) {
6339
6682
  pathGenerator.init();
@@ -6404,6 +6747,7 @@
6404
6747
  exports.loadConfettiFallingPreset = loadConfettiFallingPreset;
6405
6748
  exports.tsParticles = tsParticles;
6406
6749
 
6407
- }));
6750
+ })(g.__tsParticlesInternals.presets.confettiFalling = g.__tsParticlesInternals.presets.confettiFalling || {});
6751
+ })(typeof globalThis !== "undefined" ? globalThis : typeof window !== "undefined" ? window : self);
6752
+
6408
6753
  Object.assign(globalThis.window || globalThis, { loadConfettiFallingPreset: (globalThis.__tsParticlesInternals.presets.confettiFalling || {}).loadConfettiFallingPreset });
6409
- delete (globalThis.window || globalThis).tsparticlesInternalExports;