@tsparticles/engine 3.0.3 → 3.2.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.
Files changed (156) hide show
  1. package/373.min.js +2 -0
  2. package/373.min.js.LICENSE.txt +1 -0
  3. package/438.min.js +2 -0
  4. package/438.min.js.LICENSE.txt +1 -0
  5. package/README.md +337 -216
  6. package/browser/Core/Canvas.js +102 -49
  7. package/browser/Core/Container.js +53 -41
  8. package/browser/Core/Engine.js +47 -32
  9. package/browser/Core/Particle.js +46 -48
  10. package/browser/Core/Particles.js +70 -57
  11. package/browser/Core/Retina.js +5 -4
  12. package/browser/Core/Utils/Circle.js +4 -3
  13. package/browser/Core/Utils/Constants.js +3 -0
  14. package/browser/Core/Utils/EventListeners.js +19 -16
  15. package/browser/Core/Utils/ExternalInteractorBase.js +1 -1
  16. package/browser/Core/Utils/InteractionManager.js +17 -8
  17. package/browser/Core/Utils/ParticlesInteractorBase.js +1 -1
  18. package/browser/Core/Utils/QuadTree.js +5 -3
  19. package/browser/Core/Utils/Vector.js +7 -2
  20. package/browser/Core/Utils/Vector3d.js +14 -9
  21. package/browser/Options/Classes/BackgroundMask/BackgroundMask.js +1 -1
  22. package/browser/Options/Classes/BackgroundMask/BackgroundMaskCover.js +3 -2
  23. package/browser/Options/Classes/ManualParticle.js +3 -2
  24. package/browser/Options/Classes/Options.js +3 -0
  25. package/browser/Utils/CanvasUtils.js +50 -40
  26. package/browser/Utils/ColorUtils.js +124 -45
  27. package/browser/Utils/EventDispatcher.js +6 -5
  28. package/browser/Utils/HslColorManager.js +5 -5
  29. package/browser/Utils/NumberUtils.js +35 -23
  30. package/browser/Utils/RgbColorManager.js +5 -5
  31. package/browser/Utils/Utils.js +102 -19
  32. package/cjs/Core/Canvas.js +102 -49
  33. package/cjs/Core/Container.js +53 -41
  34. package/cjs/Core/Engine.js +70 -32
  35. package/cjs/Core/Particle.js +45 -47
  36. package/cjs/Core/Particles.js +93 -57
  37. package/cjs/Core/Retina.js +5 -4
  38. package/cjs/Core/Utils/Circle.js +4 -3
  39. package/cjs/Core/Utils/Constants.js +4 -1
  40. package/cjs/Core/Utils/EventListeners.js +18 -15
  41. package/cjs/Core/Utils/ExternalInteractorBase.js +1 -1
  42. package/cjs/Core/Utils/InteractionManager.js +17 -8
  43. package/cjs/Core/Utils/ParticlesInteractorBase.js +1 -1
  44. package/cjs/Core/Utils/QuadTree.js +5 -3
  45. package/cjs/Core/Utils/Vector.js +7 -2
  46. package/cjs/Core/Utils/Vector3d.js +14 -9
  47. package/cjs/Options/Classes/BackgroundMask/BackgroundMask.js +1 -1
  48. package/cjs/Options/Classes/BackgroundMask/BackgroundMaskCover.js +3 -2
  49. package/cjs/Options/Classes/ManualParticle.js +3 -2
  50. package/cjs/Options/Classes/Options.js +3 -0
  51. package/cjs/Utils/CanvasUtils.js +50 -40
  52. package/cjs/Utils/ColorUtils.js +126 -45
  53. package/cjs/Utils/EventDispatcher.js +6 -5
  54. package/cjs/Utils/HslColorManager.js +5 -5
  55. package/cjs/Utils/NumberUtils.js +37 -24
  56. package/cjs/Utils/RgbColorManager.js +5 -5
  57. package/cjs/Utils/Utils.js +103 -19
  58. package/dist_browser_Core_Container_js.js +92 -0
  59. package/dist_browser_Core_Particle_js.js +32 -0
  60. package/esm/Core/Canvas.js +102 -49
  61. package/esm/Core/Container.js +53 -41
  62. package/esm/Core/Engine.js +47 -32
  63. package/esm/Core/Particle.js +46 -48
  64. package/esm/Core/Particles.js +70 -57
  65. package/esm/Core/Retina.js +5 -4
  66. package/esm/Core/Utils/Circle.js +4 -3
  67. package/esm/Core/Utils/Constants.js +3 -0
  68. package/esm/Core/Utils/EventListeners.js +19 -16
  69. package/esm/Core/Utils/ExternalInteractorBase.js +1 -1
  70. package/esm/Core/Utils/InteractionManager.js +17 -8
  71. package/esm/Core/Utils/ParticlesInteractorBase.js +1 -1
  72. package/esm/Core/Utils/QuadTree.js +5 -3
  73. package/esm/Core/Utils/Vector.js +7 -2
  74. package/esm/Core/Utils/Vector3d.js +14 -9
  75. package/esm/Options/Classes/BackgroundMask/BackgroundMask.js +1 -1
  76. package/esm/Options/Classes/BackgroundMask/BackgroundMaskCover.js +3 -2
  77. package/esm/Options/Classes/ManualParticle.js +3 -2
  78. package/esm/Options/Classes/Options.js +3 -0
  79. package/esm/Utils/CanvasUtils.js +50 -40
  80. package/esm/Utils/ColorUtils.js +124 -45
  81. package/esm/Utils/EventDispatcher.js +6 -5
  82. package/esm/Utils/HslColorManager.js +5 -5
  83. package/esm/Utils/NumberUtils.js +35 -23
  84. package/esm/Utils/RgbColorManager.js +5 -5
  85. package/esm/Utils/Utils.js +102 -19
  86. package/package.json +1 -1
  87. package/report.html +3 -3
  88. package/tsparticles.engine.js +894 -5461
  89. package/tsparticles.engine.min.js +1 -1
  90. package/tsparticles.engine.min.js.LICENSE.txt +1 -1
  91. package/types/Core/Canvas.d.ts +5 -3
  92. package/types/Core/Container.d.ts +1 -1
  93. package/types/Core/Engine.d.ts +13 -8
  94. package/types/Core/Interfaces/IContainerPlugin.d.ts +3 -3
  95. package/types/Core/Interfaces/IEffectDrawer.d.ts +3 -3
  96. package/types/Core/Interfaces/IMovePathGenerator.d.ts +2 -2
  97. package/types/Core/Interfaces/IParticleHslAnimation.d.ts +4 -4
  98. package/types/Core/Interfaces/IParticleMover.d.ts +2 -2
  99. package/types/Core/Interfaces/IParticleUpdater.d.ts +2 -2
  100. package/types/Core/Interfaces/IParticleValueAnimation.d.ts +4 -0
  101. package/types/Core/Interfaces/IPlugin.d.ts +1 -1
  102. package/types/Core/Interfaces/IShapeDrawData.d.ts +2 -2
  103. package/types/Core/Interfaces/IShapeDrawer.d.ts +4 -4
  104. package/types/Core/Particle.d.ts +3 -3
  105. package/types/Core/Particles.d.ts +12 -8
  106. package/types/Core/Utils/Constants.d.ts +3 -0
  107. package/types/Core/Utils/ExternalInteractorBase.d.ts +1 -1
  108. package/types/Core/Utils/InteractionManager.d.ts +3 -3
  109. package/types/Core/Utils/ParticlesInteractorBase.d.ts +1 -1
  110. package/types/Core/Utils/Point.d.ts +1 -1
  111. package/types/Enums/Modes/OutMode.d.ts +0 -3
  112. package/types/Options/Classes/BackgroundMask/BackgroundMaskCover.d.ts +2 -1
  113. package/types/Options/Classes/Options.d.ts +1 -0
  114. package/types/Options/Classes/Particles/Move/Move.d.ts +1 -2
  115. package/types/Options/Classes/Particles/Move/OutModes.d.ts +5 -6
  116. package/types/Options/Interfaces/BackgroundMask/IBackgroundMask.d.ts +2 -1
  117. package/types/Options/Interfaces/BackgroundMask/IBackgroundMaskCover.d.ts +2 -1
  118. package/types/Options/Interfaces/IOptions.d.ts +1 -0
  119. package/types/Options/Interfaces/Interactivity/Modes/IModes.d.ts +1 -3
  120. package/types/Options/Interfaces/Particles/Move/IMove.d.ts +2 -2
  121. package/types/Options/Interfaces/Particles/Move/IOutModes.d.ts +6 -6
  122. package/types/Types/CustomEventArgs.d.ts +2 -2
  123. package/types/Types/ExportResult.d.ts +2 -2
  124. package/types/Types/ParticlesGroups.d.ts +1 -3
  125. package/types/Types/PathOptions.d.ts +1 -3
  126. package/types/Types/ShapeData.d.ts +1 -3
  127. package/types/Utils/CanvasUtils.d.ts +9 -8
  128. package/types/Utils/ColorUtils.d.ts +5 -0
  129. package/types/Utils/NumberUtils.d.ts +2 -2
  130. package/types/Utils/Utils.d.ts +9 -6
  131. package/umd/Core/Canvas.js +102 -49
  132. package/umd/Core/Container.js +54 -42
  133. package/umd/Core/Engine.js +72 -33
  134. package/umd/Core/Particle.js +46 -48
  135. package/umd/Core/Particles.js +95 -58
  136. package/umd/Core/Retina.js +5 -4
  137. package/umd/Core/Utils/Circle.js +4 -3
  138. package/umd/Core/Utils/Constants.js +4 -1
  139. package/umd/Core/Utils/EventListeners.js +18 -15
  140. package/umd/Core/Utils/ExternalInteractorBase.js +1 -1
  141. package/umd/Core/Utils/InteractionManager.js +17 -8
  142. package/umd/Core/Utils/ParticlesInteractorBase.js +1 -1
  143. package/umd/Core/Utils/QuadTree.js +5 -3
  144. package/umd/Core/Utils/Vector.js +7 -2
  145. package/umd/Core/Utils/Vector3d.js +14 -9
  146. package/umd/Options/Classes/BackgroundMask/BackgroundMask.js +1 -1
  147. package/umd/Options/Classes/BackgroundMask/BackgroundMaskCover.js +3 -2
  148. package/umd/Options/Classes/ManualParticle.js +3 -2
  149. package/umd/Options/Classes/Options.js +3 -0
  150. package/umd/Utils/CanvasUtils.js +50 -40
  151. package/umd/Utils/ColorUtils.js +127 -46
  152. package/umd/Utils/EventDispatcher.js +6 -5
  153. package/umd/Utils/HslColorManager.js +5 -5
  154. package/umd/Utils/NumberUtils.js +38 -25
  155. package/umd/Utils/RgbColorManager.js +5 -5
  156. package/umd/Utils/Utils.js +104 -20
@@ -1,12 +1,11 @@
1
1
  import { errorPrefix, generatedAttribute } from "./Utils/Constants.js";
2
2
  import { executeOnSingleOrMultiple, getLogger, itemFromSingleOrMultiple } from "../Utils/Utils.js";
3
- import { Container } from "./Container.js";
4
3
  import { EventDispatcher } from "../Utils/EventDispatcher.js";
5
4
  import { getRandom } from "../Utils/NumberUtils.js";
6
- function getItemsFromInitializer(container, map, initializers, force = false) {
5
+ async function getItemsFromInitializer(container, map, initializers, force = false) {
7
6
  let res = map.get(container);
8
7
  if (!res || force) {
9
- res = [...initializers.values()].map((t) => t(container));
8
+ res = await Promise.all([...initializers.values()].map((t) => t(container)));
10
9
  map.set(container, res);
11
10
  }
12
11
  return res;
@@ -18,7 +17,7 @@ async function getDataFromUrl(data) {
18
17
  }
19
18
  const response = await fetch(url);
20
19
  if (response.ok) {
21
- return response.json();
20
+ return (await response.json());
22
21
  }
23
22
  getLogger().error(`${errorPrefix} ${response.status} while retrieving config file`);
24
23
  return data.fallback;
@@ -51,16 +50,18 @@ export class Engine {
51
50
  return res;
52
51
  }
53
52
  get version() {
54
- return "3.0.3";
53
+ return "3.2.0";
55
54
  }
56
55
  addConfig(config) {
57
- const name = config.name ?? "default";
58
- this._configs.set(name, config);
59
- this._eventDispatcher.dispatchEvent("configAdded", { data: { name, config } });
56
+ const key = config.key ?? config.name ?? "default";
57
+ this._configs.set(key, config);
58
+ this._eventDispatcher.dispatchEvent("configAdded", { data: { name: key, config } });
60
59
  }
61
60
  async addEffect(effect, drawer, refresh = true) {
62
61
  executeOnSingleOrMultiple(effect, (type) => {
63
- !this.getEffectDrawer(type) && this.effectDrawers.set(type, drawer);
62
+ if (!this.getEffectDrawer(type)) {
63
+ this.effectDrawers.set(type, drawer);
64
+ }
64
65
  });
65
66
  await this.refresh(refresh);
66
67
  }
@@ -80,20 +81,28 @@ export class Engine {
80
81
  await this.refresh(refresh);
81
82
  }
82
83
  async addPathGenerator(name, generator, refresh = true) {
83
- !this.getPathGenerator(name) && this.pathGenerators.set(name, generator);
84
+ if (!this.getPathGenerator(name)) {
85
+ this.pathGenerators.set(name, generator);
86
+ }
84
87
  await this.refresh(refresh);
85
88
  }
86
89
  async addPlugin(plugin, refresh = true) {
87
- !this.getPlugin(plugin.id) && this.plugins.push(plugin);
90
+ if (!this.getPlugin(plugin.id)) {
91
+ this.plugins.push(plugin);
92
+ }
88
93
  await this.refresh(refresh);
89
94
  }
90
95
  async addPreset(preset, options, override = false, refresh = true) {
91
- (override || !this.getPreset(preset)) && this.presets.set(preset, options);
96
+ if (override || !this.getPreset(preset)) {
97
+ this.presets.set(preset, options);
98
+ }
92
99
  await this.refresh(refresh);
93
100
  }
94
101
  async addShape(shape, drawer, refresh = true) {
95
102
  executeOnSingleOrMultiple(shape, (type) => {
96
- !this.getShapeDrawer(type) && this.shapeDrawers.set(type, drawer);
103
+ if (!this.getShapeDrawer(type)) {
104
+ this.shapeDrawers.set(type, drawer);
105
+ }
97
106
  });
98
107
  await this.refresh(refresh);
99
108
  }
@@ -111,26 +120,29 @@ export class Engine {
111
120
  domItem(index) {
112
121
  const dom = this.dom(), item = dom[index];
113
122
  if (!item || item.destroyed) {
114
- dom.splice(index, 1);
123
+ const deleteCount = 1;
124
+ dom.splice(index, deleteCount);
115
125
  return;
116
126
  }
117
127
  return item;
118
128
  }
119
- getAvailablePlugins(container) {
129
+ async getAvailablePlugins(container) {
120
130
  const res = new Map();
121
131
  for (const plugin of this.plugins) {
122
- plugin.needsPlugin(container.actualOptions) && res.set(plugin.id, plugin.getPlugin(container));
132
+ if (plugin.needsPlugin(container.actualOptions)) {
133
+ res.set(plugin.id, await plugin.getPlugin(container));
134
+ }
123
135
  }
124
136
  return res;
125
137
  }
126
138
  getEffectDrawer(type) {
127
139
  return this.effectDrawers.get(type);
128
140
  }
129
- getInteractors(container, force = false) {
130
- return getItemsFromInitializer(container, this.interactors, this._initializers.interactors, force);
141
+ async getInteractors(container, force = false) {
142
+ return await getItemsFromInitializer(container, this.interactors, this._initializers.interactors, force);
131
143
  }
132
- getMovers(container, force = false) {
133
- return getItemsFromInitializer(container, this.movers, this._initializers.movers, force);
144
+ async getMovers(container, force = false) {
145
+ return await getItemsFromInitializer(container, this.movers, this._initializers.movers, force);
134
146
  }
135
147
  getPathGenerator(type) {
136
148
  return this.pathGenerators.get(type);
@@ -150,8 +162,8 @@ export class Engine {
150
162
  getSupportedShapes() {
151
163
  return this.shapeDrawers.keys();
152
164
  }
153
- getUpdaters(container, force = false) {
154
- return getItemsFromInitializer(container, this.updaters, this._initializers.updaters, force);
165
+ async getUpdaters(container, force = false) {
166
+ return await getItemsFromInitializer(container, this.updaters, this._initializers.updaters, force);
155
167
  }
156
168
  init() {
157
169
  if (this._initialized) {
@@ -160,19 +172,20 @@ export class Engine {
160
172
  this._initialized = true;
161
173
  }
162
174
  async load(params) {
163
- const id = params.id ?? params.element?.id ?? `tsparticles${Math.floor(getRandom() * 10000)}`, { index, url } = params, options = url ? await getDataFromUrl({ fallback: params.options, url, index }) : params.options;
175
+ const randomFactor = 10000, id = params.id ?? params.element?.id ?? `tsparticles${Math.floor(getRandom() * randomFactor)}`, { index, url } = params, options = url ? await getDataFromUrl({ fallback: params.options, url, index }) : params.options;
164
176
  let domContainer = params.element ?? document.getElementById(id);
165
177
  if (!domContainer) {
166
178
  domContainer = document.createElement("div");
167
179
  domContainer.id = id;
168
180
  document.body.append(domContainer);
169
181
  }
170
- const currentOptions = itemFromSingleOrMultiple(options, index), dom = this.dom(), oldIndex = dom.findIndex((v) => v.id.description === id);
171
- if (oldIndex >= 0) {
182
+ const currentOptions = itemFromSingleOrMultiple(options, index), dom = this.dom(), oldIndex = dom.findIndex((v) => v.id.description === id), minIndex = 0;
183
+ if (oldIndex >= minIndex) {
172
184
  const old = this.domItem(oldIndex);
173
185
  if (old && !old.destroyed) {
174
186
  old.destroy();
175
- dom.splice(oldIndex, 1);
187
+ const deleteCount = 1;
188
+ dom.splice(oldIndex, deleteCount);
176
189
  }
177
190
  }
178
191
  let canvasEl;
@@ -183,7 +196,8 @@ export class Engine {
183
196
  else {
184
197
  const existingCanvases = domContainer.getElementsByTagName("canvas");
185
198
  if (existingCanvases.length) {
186
- canvasEl = existingCanvases[0];
199
+ const firstIndex = 0;
200
+ canvasEl = existingCanvases[firstIndex];
187
201
  canvasEl.dataset[generatedAttribute] = "false";
188
202
  }
189
203
  else {
@@ -198,9 +212,10 @@ export class Engine {
198
212
  if (!canvasEl.style.height) {
199
213
  canvasEl.style.height = "100%";
200
214
  }
201
- const newItem = new Container(this, id, currentOptions);
202
- if (oldIndex >= 0) {
203
- dom.splice(oldIndex, 0, newItem);
215
+ const { Container } = await import("./Container.js"), newItem = new Container(this, id, currentOptions);
216
+ if (oldIndex >= minIndex) {
217
+ const deleteCount = 0;
218
+ dom.splice(oldIndex, deleteCount, newItem);
204
219
  }
205
220
  else {
206
221
  dom.push(newItem);
@@ -220,14 +235,14 @@ export class Engine {
220
235
  return;
221
236
  }
222
237
  for (const updater of updaters) {
223
- updater.loadOptions && updater.loadOptions(options, ...sourceOptions);
238
+ updater.loadOptions?.(options, ...sourceOptions);
224
239
  }
225
240
  }
226
241
  async refresh(refresh = true) {
227
242
  if (!refresh) {
228
243
  return;
229
244
  }
230
- this.dom().forEach((t) => t.refresh());
245
+ await Promise.all(this.dom().map((t) => t.refresh()));
231
246
  }
232
247
  removeEventListener(type, listener) {
233
248
  this._eventDispatcher.removeEventListener(type, listener);
@@ -1,12 +1,13 @@
1
- import { calcExactPositionOrRandomFromSize, clamp, getDistance, getParticleBaseVelocity, getParticleDirectionAngle, getRandom, getRangeValue, randomInRange, setRangeValue, } from "../Utils/NumberUtils.js";
1
+ import { calcExactPositionOrRandomFromSize, clamp, degToRad, getDistance, getParticleBaseVelocity, getParticleDirectionAngle, getRandom, getRangeValue, randomInRange, setRangeValue, } from "../Utils/NumberUtils.js";
2
2
  import { deepExtend, getPosition, initParticleNumericAnimationValue, isInArray, itemFromSingleOrMultiple, } from "../Utils/Utils.js";
3
+ import { errorPrefix, millisecondsToSeconds } from "./Utils/Constants.js";
3
4
  import { getHslFromAnimation, rangeColorToRgb } from "../Utils/ColorUtils.js";
4
5
  import { Interactivity } from "../Options/Classes/Interactivity/Interactivity.js";
5
6
  import { Vector } from "./Utils/Vector.js";
6
7
  import { Vector3d } from "./Utils/Vector3d.js";
7
8
  import { alterHsl } from "../Utils/CanvasUtils.js";
8
- import { errorPrefix } from "./Utils/Constants.js";
9
9
  import { loadParticlesOptions } from "../Utils/OptionsUtils.js";
10
+ const defaultRetryCount = 0, double = 2, half = 0.5, squareExp = 2;
10
11
  function loadEffectData(effect, effectOptions, id, reduceDuplicates) {
11
12
  const effectData = effectOptions.options[effect];
12
13
  if (!effectData) {
@@ -31,7 +32,7 @@ function fixOutMode(data) {
31
32
  if (!isInArray(data.outMode, data.checkModes)) {
32
33
  return;
33
34
  }
34
- const diameter = data.radius * 2;
35
+ const diameter = data.radius * double;
35
36
  if (data.coord > data.maxCoord - diameter) {
36
37
  data.setCb(-data.radius);
37
38
  }
@@ -40,9 +41,9 @@ function fixOutMode(data) {
40
41
  }
41
42
  }
42
43
  export class Particle {
43
- constructor(engine, id, container, position, overrideOptions, group) {
44
+ constructor(engine, container) {
44
45
  this.container = container;
45
- this._calcPosition = (container, position, zIndex, tryCount = 0) => {
46
+ this._calcPosition = (container, position, zIndex, tryCount = defaultRetryCount) => {
46
47
  for (const [, plugin] of container.plugins) {
47
48
  const pluginPos = plugin.particlePosition !== undefined ? plugin.particlePosition(position, this) : undefined;
48
49
  if (pluginPos) {
@@ -55,7 +56,7 @@ export class Particle {
55
56
  }), pos = Vector3d.create(exactPosition.x, exactPosition.y, zIndex), radius = this.getRadius(), outModes = this.options.move.outModes, fixHorizontal = (outMode) => {
56
57
  fixOutMode({
57
58
  outMode,
58
- checkModes: ["bounce", "bounce-horizontal"],
59
+ checkModes: ["bounce"],
59
60
  coord: pos.x,
60
61
  maxCoord: container.canvas.size.width,
61
62
  setCb: (value) => (pos.x += value),
@@ -64,7 +65,7 @@ export class Particle {
64
65
  }, fixVertical = (outMode) => {
65
66
  fixOutMode({
66
67
  outMode,
67
- checkModes: ["bounce", "bounce-vertical"],
68
+ checkModes: ["bounce"],
68
69
  coord: pos.y,
69
70
  maxCoord: container.canvas.size.height,
70
71
  setCb: (value) => (pos.y += value),
@@ -76,7 +77,8 @@ export class Particle {
76
77
  fixVertical(outModes.top ?? outModes.default);
77
78
  fixVertical(outModes.bottom ?? outModes.default);
78
79
  if (this._checkOverlap(pos, tryCount)) {
79
- return this._calcPosition(container, undefined, zIndex, tryCount + 1);
80
+ const increment = 1;
81
+ return this._calcPosition(container, undefined, zIndex, tryCount + increment);
80
82
  }
81
83
  return pos;
82
84
  };
@@ -85,9 +87,9 @@ export class Particle {
85
87
  if (moveOptions.direction === "inside" || moveOptions.direction === "outside") {
86
88
  return res;
87
89
  }
88
- const rad = (Math.PI / 180) * getRangeValue(moveOptions.angle.value), radOffset = (Math.PI / 180) * getRangeValue(moveOptions.angle.offset), range = {
89
- left: radOffset - rad * 0.5,
90
- right: radOffset + rad * 0.5,
90
+ const rad = degToRad(getRangeValue(moveOptions.angle.value)), radOffset = degToRad(getRangeValue(moveOptions.angle.offset)), range = {
91
+ left: radOffset - rad * half,
92
+ right: radOffset + rad * half,
91
93
  };
92
94
  if (!moveOptions.straight) {
93
95
  res.angle += randomInRange(setRangeValue(range.left, range.right));
@@ -97,7 +99,7 @@ export class Particle {
97
99
  }
98
100
  return res;
99
101
  };
100
- this._checkOverlap = (pos, tryCount = 0) => {
102
+ this._checkOverlap = (pos, tryCount = defaultRetryCount) => {
101
103
  const collisionsOptions = this.options.collisions, radius = this.getRadius();
102
104
  if (!collisionsOptions.enable) {
103
105
  return false;
@@ -106,8 +108,8 @@ export class Particle {
106
108
  if (overlapOptions.enable) {
107
109
  return false;
108
110
  }
109
- const retries = overlapOptions.retries;
110
- if (retries >= 0 && tryCount > retries) {
111
+ const retries = overlapOptions.retries, minRetries = 0;
112
+ if (retries >= minRetries && tryCount > retries) {
111
113
  throw new Error(`${errorPrefix} particle is overlapping and can't be placed`);
112
114
  }
113
115
  return !!this.container.particles.find((particle) => getDistance(pos, particle.position) < radius + particle.getRadius());
@@ -116,7 +118,7 @@ export class Particle {
116
118
  if (!color || !this.roll || (!this.backColor && !this.roll.alter)) {
117
119
  return color;
118
120
  }
119
- const backFactor = this.roll.horizontal && this.roll.vertical ? 2 : 1, backSum = this.roll.horizontal ? Math.PI * 0.5 : 0, rolled = Math.floor(((this.roll.angle ?? 0) + backSum) / (Math.PI / backFactor)) % 2;
121
+ const rollFactor = 1, none = 0, backFactor = this.roll.horizontal && this.roll.vertical ? double * rollFactor : rollFactor, backSum = this.roll.horizontal ? Math.PI * half : none, rolled = Math.floor(((this.roll.angle ?? none) + backSum) / (Math.PI / backFactor)) % double;
120
122
  if (!rolled) {
121
123
  return color;
122
124
  }
@@ -129,13 +131,13 @@ export class Particle {
129
131
  return color;
130
132
  };
131
133
  this._initPosition = (position) => {
132
- const container = this.container, zIndexValue = getRangeValue(this.options.zIndex.value);
133
- this.position = this._calcPosition(container, position, clamp(zIndexValue, 0, container.zLayers));
134
+ const container = this.container, zIndexValue = getRangeValue(this.options.zIndex.value), minZ = 0;
135
+ this.position = this._calcPosition(container, position, clamp(zIndexValue, minZ, container.zLayers));
134
136
  this.initialPosition = this.position.copy();
135
- const canvasSize = container.canvas.size;
137
+ const canvasSize = container.canvas.size, defaultRadius = 0;
136
138
  this.moveCenter = {
137
139
  ...getPosition(this.options.move.center, canvasSize),
138
- radius: this.options.move.center.radius ?? 0,
140
+ radius: this.options.move.center.radius ?? defaultRadius,
139
141
  mode: this.options.move.center.mode ?? "percent",
140
142
  };
141
143
  this.direction = getParticleDirectionAngle(this.options.move.direction, this.position, this.moveCenter);
@@ -150,7 +152,6 @@ export class Particle {
150
152
  this.offset = Vector.origin;
151
153
  };
152
154
  this._engine = engine;
153
- this.init(id, position, overrideOptions, group);
154
155
  }
155
156
  destroy(override) {
156
157
  if (this.unbreakable || this.destroyed) {
@@ -160,14 +161,14 @@ export class Particle {
160
161
  this.bubble.inRange = false;
161
162
  this.slow.inRange = false;
162
163
  const container = this.container, pathGenerator = this.pathGenerator, shapeDrawer = container.shapeDrawers.get(this.shape);
163
- shapeDrawer && shapeDrawer.particleDestroy && shapeDrawer.particleDestroy(this);
164
+ shapeDrawer?.particleDestroy?.(this);
164
165
  for (const [, plugin] of container.plugins) {
165
- plugin.particleDestroyed && plugin.particleDestroyed(this, override);
166
+ plugin.particleDestroyed?.(this, override);
166
167
  }
167
168
  for (const updater of container.particles.updaters) {
168
- updater.particleDestroyed && updater.particleDestroyed(this, override);
169
+ updater.particleDestroyed?.(this, override);
169
170
  }
170
- pathGenerator && pathGenerator.reset(this);
171
+ pathGenerator?.reset(this);
171
172
  this._engine.dispatchEvent("particleDestroyed", {
172
173
  container: this.container,
173
174
  data: {
@@ -175,18 +176,18 @@ export class Particle {
175
176
  },
176
177
  });
177
178
  }
178
- draw(delta) {
179
+ async draw(delta) {
179
180
  const container = this.container, canvas = container.canvas;
180
181
  for (const [, plugin] of container.plugins) {
181
- canvas.drawParticlePlugin(plugin, this, delta);
182
+ await canvas.drawParticlePlugin(plugin, this, delta);
182
183
  }
183
- canvas.drawParticle(this, delta);
184
+ await canvas.drawParticle(this, delta);
184
185
  }
185
186
  getFillColor() {
186
187
  return this._getRollColor(this.bubble.color ?? getHslFromAnimation(this.color));
187
188
  }
188
189
  getMass() {
189
- return this.getRadius() ** 2 * Math.PI * 0.5;
190
+ return this.getRadius() ** squareExp * Math.PI * half;
190
191
  }
191
192
  getPosition() {
192
193
  return {
@@ -201,7 +202,7 @@ export class Particle {
201
202
  getStrokeColor() {
202
203
  return this._getRollColor(this.bubble.color ?? getHslFromAnimation(this.strokeColor));
203
204
  }
204
- init(id, position, overrideOptions, group) {
205
+ async init(id, position, overrideOptions, group) {
205
206
  const container = this.container, engine = this._engine;
206
207
  this.id = id;
207
208
  this.group = group;
@@ -225,14 +226,14 @@ export class Particle {
225
226
  this.shape = itemFromSingleOrMultiple(shapeType, this.id, reduceDuplicates);
226
227
  const effectOptions = particlesOptions.effect, shapeOptions = particlesOptions.shape;
227
228
  if (overrideOptions) {
228
- if (overrideOptions.effect && overrideOptions.effect.type) {
229
+ if (overrideOptions.effect?.type) {
229
230
  const overrideEffectType = overrideOptions.effect.type, effect = itemFromSingleOrMultiple(overrideEffectType, this.id, reduceDuplicates);
230
231
  if (effect) {
231
232
  this.effect = effect;
232
233
  effectOptions.load(overrideOptions.effect);
233
234
  }
234
235
  }
235
- if (overrideOptions.shape && overrideOptions.shape.type) {
236
+ if (overrideOptions.shape?.type) {
236
237
  const overrideShapeType = overrideOptions.shape.type, shape = itemFromSingleOrMultiple(overrideShapeType, this.id, reduceDuplicates);
237
238
  if (shape) {
238
239
  this.shape = shape;
@@ -261,11 +262,11 @@ export class Particle {
261
262
  this.shapeClose = shapeData?.close ?? particlesOptions.shape.close;
262
263
  this.options = particlesOptions;
263
264
  const pathOptions = this.options.move.path;
264
- this.pathDelay = getRangeValue(pathOptions.delay.value) * 1000;
265
+ this.pathDelay = getRangeValue(pathOptions.delay.value) * millisecondsToSeconds;
265
266
  if (pathOptions.generator) {
266
267
  this.pathGenerator = this._engine.getPathGenerator(pathOptions.generator);
267
268
  if (this.pathGenerator && container.addPath(pathOptions.generator, this.pathGenerator)) {
268
- this.pathGenerator.init(container);
269
+ await this.pathGenerator.init(container);
269
270
  }
270
271
  }
271
272
  container.retina.initParticle(this);
@@ -280,7 +281,8 @@ export class Particle {
280
281
  this._initPosition(position);
281
282
  this.initialVelocity = this._calculateVelocity();
282
283
  this.velocity = this.initialVelocity.copy();
283
- this.moveDecay = 1 - getRangeValue(this.options.move.decay);
284
+ const decayOffset = 1;
285
+ this.moveDecay = decayOffset - getRangeValue(this.options.move.decay);
284
286
  const particles = container.particles;
285
287
  particles.setLastZIndex(this.position.z);
286
288
  this.zIndexFactor = this.position.z / container.zLayers;
@@ -292,8 +294,8 @@ export class Particle {
292
294
  container.effectDrawers.set(this.effect, effectDrawer);
293
295
  }
294
296
  }
295
- if (effectDrawer && effectDrawer.loadEffect) {
296
- effectDrawer.loadEffect(this);
297
+ if (effectDrawer?.loadEffect) {
298
+ await effectDrawer.loadEffect(this);
297
299
  }
298
300
  let shapeDrawer = container.shapeDrawers.get(this.shape);
299
301
  if (!shapeDrawer) {
@@ -302,8 +304,8 @@ export class Particle {
302
304
  container.shapeDrawers.set(this.shape, shapeDrawer);
303
305
  }
304
306
  }
305
- if (shapeDrawer && shapeDrawer.loadShape) {
306
- shapeDrawer.loadShape(this);
307
+ if (shapeDrawer?.loadShape) {
308
+ await shapeDrawer.loadShape(this);
307
309
  }
308
310
  const sideCountFunc = shapeDrawer?.getSidesCount;
309
311
  if (sideCountFunc) {
@@ -312,19 +314,15 @@ export class Particle {
312
314
  this.spawning = false;
313
315
  this.shadowColor = rangeColorToRgb(this.options.shadow.color);
314
316
  for (const updater of particles.updaters) {
315
- updater.init(this);
317
+ await updater.init(this);
316
318
  }
317
319
  for (const mover of particles.movers) {
318
- mover.init && mover.init(this);
319
- }
320
- if (effectDrawer && effectDrawer.particleInit) {
321
- effectDrawer.particleInit(container, this);
322
- }
323
- if (shapeDrawer && shapeDrawer.particleInit) {
324
- shapeDrawer.particleInit(container, this);
320
+ await mover.init?.(this);
325
321
  }
322
+ await effectDrawer?.particleInit?.(container, this);
323
+ await shapeDrawer?.particleInit?.(container, this);
326
324
  for (const [, plugin] of container.plugins) {
327
- plugin.particleCreated && plugin.particleCreated(this);
325
+ plugin.particleCreated?.(this);
328
326
  }
329
327
  }
330
328
  isInsideCanvas() {
@@ -339,7 +337,7 @@ export class Particle {
339
337
  }
340
338
  reset() {
341
339
  for (const updater of this.container.particles.updaters) {
342
- updater.reset && updater.reset(this);
340
+ updater.reset?.(this);
343
341
  }
344
342
  }
345
343
  }