@tsparticles/engine 4.0.0-beta.9 → 4.0.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 (84) hide show
  1. package/browser/Core/CanvasManager.js +74 -37
  2. package/browser/Core/Engine.js +23 -8
  3. package/browser/Core/Particle.js +3 -3
  4. package/browser/Core/ParticlesManager.js +157 -78
  5. package/browser/Core/Retina.js +2 -3
  6. package/browser/Core/Utils/EventListeners.js +1 -1
  7. package/browser/Options/Classes/Particles/Fill.js +0 -2
  8. package/browser/Options/Classes/Particles/Paint.js +25 -0
  9. package/browser/Options/Classes/Particles/ParticlesOptions.js +54 -48
  10. package/browser/Utils/CanvasUtils.js +3 -3
  11. package/browser/Utils/LogUtils.js +32 -15
  12. package/browser/Utils/Utils.js +1 -0
  13. package/browser/browser.js +5 -0
  14. package/browser/exports.js +1 -0
  15. package/browser/index.js +0 -1
  16. package/cjs/Core/CanvasManager.js +74 -37
  17. package/cjs/Core/Engine.js +23 -8
  18. package/cjs/Core/Particle.js +3 -3
  19. package/cjs/Core/ParticlesManager.js +157 -78
  20. package/cjs/Core/Retina.js +2 -3
  21. package/cjs/Core/Utils/EventListeners.js +1 -1
  22. package/cjs/Options/Classes/Particles/Fill.js +0 -2
  23. package/cjs/Options/Classes/Particles/Paint.js +25 -0
  24. package/cjs/Options/Classes/Particles/ParticlesOptions.js +54 -48
  25. package/cjs/Utils/CanvasUtils.js +3 -3
  26. package/cjs/Utils/LogUtils.js +32 -15
  27. package/cjs/Utils/Utils.js +1 -0
  28. package/cjs/browser.js +5 -0
  29. package/cjs/exports.js +1 -0
  30. package/cjs/index.js +0 -1
  31. package/esm/Core/CanvasManager.js +74 -37
  32. package/esm/Core/Engine.js +23 -8
  33. package/esm/Core/Particle.js +3 -3
  34. package/esm/Core/ParticlesManager.js +157 -78
  35. package/esm/Core/Retina.js +2 -3
  36. package/esm/Core/Utils/EventListeners.js +1 -1
  37. package/esm/Options/Classes/Particles/Fill.js +0 -2
  38. package/esm/Options/Classes/Particles/Paint.js +25 -0
  39. package/esm/Options/Classes/Particles/ParticlesOptions.js +54 -48
  40. package/esm/Utils/CanvasUtils.js +3 -3
  41. package/esm/Utils/LogUtils.js +32 -15
  42. package/esm/Utils/Utils.js +1 -0
  43. package/esm/browser.js +5 -0
  44. package/esm/exports.js +1 -0
  45. package/esm/index.js +0 -1
  46. package/package.json +8 -1
  47. package/report.html +4949 -94
  48. package/scripts/install.js +321 -220
  49. package/tsparticles.engine.js +5293 -939
  50. package/tsparticles.engine.min.js +1 -2
  51. package/types/Core/CanvasManager.d.ts +3 -2
  52. package/types/Core/Container.d.ts +1 -2
  53. package/types/Core/Interfaces/IContainerPlugin.d.ts +7 -8
  54. package/types/Core/Interfaces/IDrawParticleParams.d.ts +1 -2
  55. package/types/Core/Interfaces/ILoadParams.d.ts +1 -1
  56. package/types/Core/Interfaces/IPalette.d.ts +4 -2
  57. package/types/Core/Interfaces/IParticleUpdater.d.ts +1 -2
  58. package/types/Core/Interfaces/IShapeDrawData.d.ts +1 -2
  59. package/types/Core/Particle.d.ts +1 -0
  60. package/types/Core/ParticlesManager.d.ts +11 -5
  61. package/types/Core/RenderManager.d.ts +2 -3
  62. package/types/Core/Utils/PluginManager.d.ts +5 -6
  63. package/types/Options/Classes/Options.d.ts +1 -2
  64. package/types/Options/Classes/Particles/Fill.d.ts +1 -1
  65. package/types/Options/Classes/Particles/Paint.d.ts +12 -0
  66. package/types/Options/Classes/Particles/ParticlesOptions.d.ts +2 -4
  67. package/types/Options/Interfaces/Particles/IPaint.d.ts +10 -0
  68. package/types/Options/Interfaces/Particles/IParticlesOptions.d.ts +2 -4
  69. package/types/Utils/CanvasUtils.d.ts +4 -5
  70. package/types/Utils/LogUtils.d.ts +2 -3
  71. package/types/Utils/Utils.d.ts +1 -2
  72. package/types/browser.d.ts +1 -0
  73. package/types/export-types.d.ts +1 -1
  74. package/types/exports.d.ts +1 -0
  75. package/types/{bundle.d.ts → index.lazy.d.ts} +1 -0
  76. package/67.min.js +0 -1
  77. package/dist_browser_Core_Container_js.js +0 -102
  78. package/types/Types/CanvasContextType.d.ts +0 -1
  79. /package/browser/{Types/CanvasContextType.js → Options/Interfaces/Particles/IPaint.js} +0 -0
  80. /package/browser/{bundle.js → index.lazy.js} +0 -0
  81. /package/cjs/{Types/CanvasContextType.js → Options/Interfaces/Particles/IPaint.js} +0 -0
  82. /package/cjs/{bundle.js → index.lazy.js} +0 -0
  83. /package/esm/{Types/CanvasContextType.js → Options/Interfaces/Particles/IPaint.js} +0 -0
  84. /package/esm/{bundle.js → index.lazy.js} +0 -0
@@ -13,9 +13,8 @@ export class Retina {
13
13
  const container = this.container, options = container.actualOptions;
14
14
  this.pixelRatio = options.detectRetina ? devicePixelRatio : defaultRatio;
15
15
  this.reduceFactor = defaultReduceFactor;
16
- const ratio = this.pixelRatio, canvas = container.canvas;
17
- if (canvas.element) {
18
- const element = canvas.element;
16
+ const ratio = this.pixelRatio, canvas = container.canvas, element = canvas.domElement;
17
+ if (element) {
19
18
  canvas.size.width = element.offsetWidth * ratio;
20
19
  canvas.size.height = element.offsetHeight * ratio;
21
20
  }
@@ -66,7 +66,7 @@ export class EventListeners {
66
66
  manageListener(globalThis, resizeEvent, handlers.resize, add);
67
67
  return;
68
68
  }
69
- const canvasEl = container.canvas.element;
69
+ const canvasEl = container.canvas.domElement;
70
70
  if (this._resizeObserver && !add) {
71
71
  if (canvasEl) {
72
72
  this._resizeObserver.unobserve(canvasEl);
@@ -7,8 +7,6 @@ export class Fill {
7
7
  opacity;
8
8
  constructor() {
9
9
  this.enable = true;
10
- this.color = new AnimatableColor();
11
- this.color.value = "#fff";
12
10
  this.opacity = 1;
13
11
  }
14
12
  load(data) {
@@ -0,0 +1,25 @@
1
+ import { AnimatableColor } from "../AnimatableColor.js";
2
+ import { Fill } from "./Fill.js";
3
+ import { Stroke } from "./Stroke.js";
4
+ import { isNull } from "../../../Utils/TypeUtils.js";
5
+ export class Paint {
6
+ color;
7
+ fill;
8
+ stroke;
9
+ load(data) {
10
+ if (isNull(data)) {
11
+ return;
12
+ }
13
+ if (data.color !== undefined) {
14
+ this.color = AnimatableColor.create(this.color, data.color);
15
+ }
16
+ if (data.fill !== undefined) {
17
+ this.fill ??= new Fill();
18
+ this.fill.load(data.fill);
19
+ }
20
+ if (data.stroke !== undefined) {
21
+ this.stroke ??= new Stroke();
22
+ this.stroke.load(data.stroke);
23
+ }
24
+ }
25
+ }
@@ -1,28 +1,28 @@
1
1
  import { deepExtend, executeOnSingleOrMultiple } from "../../../Utils/Utils.js";
2
2
  import { isArray, isNull } from "../../../Utils/TypeUtils.js";
3
+ import { AnimatableColor } from "../AnimatableColor.js";
3
4
  import { Effect } from "./Effect/Effect.js";
4
5
  import { Fill } from "./Fill.js";
5
6
  import { Move } from "./Move/Move.js";
6
7
  import { Opacity } from "./Opacity/Opacity.js";
8
+ import { Paint } from "./Paint.js";
7
9
  import { ParticlesBounce } from "./Bounce/ParticlesBounce.js";
8
10
  import { ParticlesNumber } from "./Number/ParticlesNumber.js";
9
11
  import { Shape } from "./Shape/Shape.js";
10
12
  import { Size } from "./Size/Size.js";
11
- import { Stroke } from "./Stroke.js";
12
13
  import { ZIndex } from "./ZIndex/ZIndex.js";
13
14
  export class ParticlesOptions {
14
15
  bounce;
15
16
  effect;
16
- fill;
17
17
  groups;
18
18
  move;
19
19
  number;
20
20
  opacity;
21
+ paint;
21
22
  palette;
22
23
  reduceDuplicates;
23
24
  shape;
24
25
  size;
25
- stroke;
26
26
  zIndex;
27
27
  _container;
28
28
  _pluginManager;
@@ -31,15 +31,18 @@ export class ParticlesOptions {
31
31
  this._container = container;
32
32
  this.bounce = new ParticlesBounce();
33
33
  this.effect = new Effect();
34
- this.fill = new Fill();
35
34
  this.groups = {};
36
35
  this.move = new Move();
37
36
  this.number = new ParticlesNumber();
38
37
  this.opacity = new Opacity();
38
+ this.paint = new Paint();
39
+ this.paint.color = new AnimatableColor();
40
+ this.paint.color.value = "#fff";
41
+ this.paint.fill = new Fill();
42
+ this.paint.fill.enable = true;
39
43
  this.reduceDuplicates = false;
40
44
  this.shape = new Shape();
41
45
  this.size = new Size();
42
- this.stroke = new Stroke();
43
46
  this.zIndex = new ZIndex();
44
47
  }
45
48
  load(data) {
@@ -69,25 +72,26 @@ export class ParticlesOptions {
69
72
  this.move.load(data.move);
70
73
  this.number.load(data.number);
71
74
  this.opacity.load(data.opacity);
75
+ const paintToLoad = data.paint;
76
+ if (paintToLoad) {
77
+ if (isArray(paintToLoad)) {
78
+ this.paint = executeOnSingleOrMultiple(paintToLoad, t => {
79
+ const tmp = new Paint();
80
+ tmp.load(t);
81
+ return tmp;
82
+ });
83
+ }
84
+ else if (isArray(this.paint)) {
85
+ this.paint = new Paint();
86
+ this.paint.load(paintToLoad);
87
+ }
88
+ else {
89
+ this.paint.load(paintToLoad);
90
+ }
91
+ }
72
92
  this.shape.load(data.shape);
73
93
  this.size.load(data.size);
74
94
  this.zIndex.load(data.zIndex);
75
- const fillToLoad = data.fill;
76
- if (fillToLoad) {
77
- this.fill = executeOnSingleOrMultiple(fillToLoad, t => {
78
- const tmp = new Fill();
79
- tmp.load(t);
80
- return tmp;
81
- });
82
- }
83
- const strokeToLoad = data.stroke;
84
- if (strokeToLoad) {
85
- this.stroke = executeOnSingleOrMultiple(strokeToLoad, t => {
86
- const tmp = new Stroke();
87
- tmp.load(t);
88
- return tmp;
89
- });
90
- }
91
95
  if (this._container) {
92
96
  for (const plugin of this._pluginManager.plugins) {
93
97
  if (plugin.loadParticlesOptions) {
@@ -109,38 +113,40 @@ export class ParticlesOptions {
109
113
  if (!paletteData) {
110
114
  return;
111
115
  }
112
- const paletteColors = paletteData.colors, paletteFill = paletteColors.fill, paletteStroke = paletteColors.stroke;
113
- let paletteFillObj = undefined;
114
- if (paletteFill) {
115
- paletteFillObj = {
116
- color: {
117
- value: paletteFill.value,
118
- },
119
- enable: paletteFill.enable,
120
- };
121
- }
122
- let paletteStrokeObj = undefined;
123
- if (paletteStroke) {
124
- if (isArray(paletteStroke)) {
125
- paletteStrokeObj = paletteStroke.map(s => ({
116
+ const paletteColors = paletteData.colors, defaultPaintStrokeWidth = 0, defaultPaintVariantsLength = 1, firstPaintVariantIndex = 0, defaultPalettePaintVariant = {}, colorVariants = isArray(paletteColors) ? paletteColors : [paletteColors], palettePaintVariants = colorVariants.flatMap(variant => {
117
+ const paletteFill = variant.fill, paletteStroke = variant.stroke, fillPart = paletteFill
118
+ ? {
126
119
  color: {
127
- value: s.value,
120
+ value: paletteFill.value,
128
121
  },
129
- width: s.width,
130
- }));
131
- }
132
- else {
133
- paletteStrokeObj = {
134
- color: {
135
- value: paletteStroke.value,
122
+ enable: paletteFill.enable,
123
+ opacity: paletteFill.opacity,
124
+ }
125
+ : undefined;
126
+ if (!paletteStroke) {
127
+ return [
128
+ {
129
+ fill: fillPart,
136
130
  },
137
- width: paletteStroke.width,
138
- };
131
+ ];
139
132
  }
140
- }
133
+ return [
134
+ {
135
+ fill: fillPart,
136
+ stroke: {
137
+ color: {
138
+ value: paletteStroke.value,
139
+ },
140
+ opacity: paletteStroke.opacity,
141
+ width: paletteStroke.width || defaultPaintStrokeWidth,
142
+ },
143
+ },
144
+ ];
145
+ }), palettePaint = palettePaintVariants.length > defaultPaintVariantsLength
146
+ ? palettePaintVariants
147
+ : (palettePaintVariants[firstPaintVariantIndex] ?? defaultPalettePaintVariant);
141
148
  this.load({
142
- fill: paletteFillObj,
143
- stroke: paletteStrokeObj,
149
+ paint: palettePaint,
144
150
  blend: {
145
151
  enable: true,
146
152
  mode: paletteData.blendMode,
@@ -88,12 +88,12 @@ export function drawShape(drawer, data) {
88
88
  if (particle.shapeClose) {
89
89
  context.closePath();
90
90
  }
91
- if (stroke) {
92
- context.stroke();
93
- }
94
91
  if (fill) {
95
92
  context.fill();
96
93
  }
94
+ if (stroke) {
95
+ context.stroke();
96
+ }
97
97
  }
98
98
  export function drawShapeAfterDraw(drawer, data) {
99
99
  if (!drawer?.afterDraw) {
@@ -1,22 +1,39 @@
1
1
  const errorPrefix = "tsParticles - Error";
2
- const _logger = {
3
- debug: console.debug,
4
- error: (message, optionalParams) => {
5
- console.error(`${errorPrefix} - ${message}`, optionalParams);
2
+ const wrap = (fn) => (...args) => {
3
+ fn(...args);
4
+ }, _logger = {
5
+ debug: wrap(console.debug),
6
+ error: (message, ...optionalParams) => {
7
+ console.error(`${errorPrefix} - ${message}`, ...optionalParams);
6
8
  },
7
- info: console.info,
8
- log: console.log,
9
- trace: console.trace,
10
- verbose: console.log,
11
- warning: console.warn,
9
+ info: wrap(console.info),
10
+ log: wrap(console.log),
11
+ trace: wrap(console.trace),
12
+ verbose: wrap(console.log),
13
+ warning: wrap(console.warn),
12
14
  };
13
15
  export function setLogger(logger) {
14
- _logger.debug = logger.debug;
15
- _logger.error = logger.error;
16
- _logger.info = logger.info;
17
- _logger.log = logger.log;
18
- _logger.verbose = logger.verbose;
19
- _logger.warning = logger.warning;
16
+ if (logger.debug) {
17
+ _logger.debug = wrap(logger.debug);
18
+ }
19
+ if (logger.error) {
20
+ _logger.error = wrap(logger.error);
21
+ }
22
+ if (logger.info) {
23
+ _logger.info = wrap(logger.info);
24
+ }
25
+ if (logger.log) {
26
+ _logger.log = wrap(logger.log);
27
+ }
28
+ if (logger.trace) {
29
+ _logger.trace = wrap(logger.trace);
30
+ }
31
+ if (logger.verbose) {
32
+ _logger.verbose = wrap(logger.verbose);
33
+ }
34
+ if (logger.warning) {
35
+ _logger.warning = wrap(logger.warning);
36
+ }
20
37
  }
21
38
  export function getLogger() {
22
39
  return _logger;
@@ -405,6 +405,7 @@ function computeFullScreenStyle(zIndex) {
405
405
  "z-index": zIndex.toString(radix),
406
406
  top: "0",
407
407
  left: "0",
408
+ "pointer-events": "none",
408
409
  };
409
410
  for (const key in style) {
410
411
  const value = style[key];
@@ -0,0 +1,5 @@
1
+ import { tsParticles } from "./index.js";
2
+ const globalObject = globalThis;
3
+ globalObject.__tsParticlesInternals = globalObject.__tsParticlesInternals ?? {};
4
+ globalObject.tsParticles = tsParticles;
5
+ export * from "./index.js";
@@ -28,6 +28,7 @@ export * from "./Options/Classes/Particles/Bounce/ParticlesBounce.js";
28
28
  export * from "./Options/Classes/Particles/Bounce/ParticlesBounceFactor.js";
29
29
  export * from "./Options/Classes/Particles/ParticlesOptions.js";
30
30
  export * from "./Options/Classes/Particles/Fill.js";
31
+ export * from "./Options/Classes/Particles/Paint.js";
31
32
  export * from "./Options/Classes/Particles/Stroke.js";
32
33
  export * from "./Options/Classes/Particles/Move/Move.js";
33
34
  export * from "./Options/Classes/Particles/Move/MoveAngle.js";
package/browser/index.js CHANGED
@@ -1,5 +1,4 @@
1
1
  import { initEngine } from "./initEngine.js";
2
2
  const tsParticles = initEngine();
3
- globalThis.tsParticles = tsParticles;
4
3
  export * from "./exports.js";
5
4
  export { tsParticles };
@@ -2,6 +2,25 @@ import { cloneStyle, getFullScreenStyle, safeMatchMedia, safeMutationObserver }
2
2
  import { defaultZoom, generatedAttribute, half } from "./Utils/Constants.js";
3
3
  import { getStyleFromRgb, rangeColorToRgb } from "../Utils/ColorUtils.js";
4
4
  import { RenderManager } from "./RenderManager.js";
5
+ const transferredCanvases = new WeakMap(), getTransferredCanvas = (canvas) => {
6
+ const transferredCanvas = transferredCanvases.get(canvas);
7
+ if (transferredCanvas) {
8
+ return transferredCanvas;
9
+ }
10
+ if (typeof canvas.transferControlToOffscreen !== "function") {
11
+ throw new TypeError("OffscreenCanvas is required but not supported by this browser");
12
+ }
13
+ try {
14
+ const offscreenCanvas = canvas.transferControlToOffscreen();
15
+ transferredCanvases.set(canvas, offscreenCanvas);
16
+ return offscreenCanvas;
17
+ }
18
+ catch {
19
+ throw new TypeError("OffscreenCanvas transfer failed");
20
+ }
21
+ }, isHtmlCanvasElement = (canvas) => {
22
+ return typeof HTMLCanvasElement !== "undefined" && canvas instanceof HTMLCanvasElement;
23
+ };
5
24
  function setStyle(canvas, style, important = false) {
6
25
  if (!style) {
7
26
  return;
@@ -32,8 +51,9 @@ function setStyle(canvas, style, important = false) {
32
51
  }
33
52
  }
34
53
  export class CanvasManager {
35
- element;
54
+ domElement;
36
55
  render;
56
+ renderCanvas;
37
57
  size;
38
58
  zoom = defaultZoom;
39
59
  _container;
@@ -68,9 +88,10 @@ export class CanvasManager {
68
88
  destroy() {
69
89
  this.stop();
70
90
  if (this._generated) {
71
- const element = this.element;
91
+ const element = this.domElement;
72
92
  element?.remove();
73
- this.element = undefined;
93
+ this.domElement = undefined;
94
+ this.renderCanvas = undefined;
74
95
  }
75
96
  else {
76
97
  this._resetOriginalStyle();
@@ -103,16 +124,17 @@ export class CanvasManager {
103
124
  this._initStyle();
104
125
  this.initBackground();
105
126
  this._safeMutationObserver(obs => {
106
- if (!this.element || !(this.element instanceof Node)) {
127
+ const element = this.domElement;
128
+ if (!element || !(element instanceof Node)) {
107
129
  return;
108
130
  }
109
- obs.observe(this.element, { attributes: true });
131
+ obs.observe(element, { attributes: true });
110
132
  });
111
133
  this.initPlugins();
112
134
  this.render.init();
113
135
  }
114
136
  initBackground() {
115
- const { _container } = this, options = _container.actualOptions, background = options.background, element = this.element;
137
+ const { _container } = this, options = _container.actualOptions, background = options.background, element = this.domElement;
116
138
  if (!element) {
117
139
  return;
118
140
  }
@@ -137,21 +159,30 @@ export class CanvasManager {
137
159
  }
138
160
  }
139
161
  loadCanvas(canvas) {
140
- if (this._generated && this.element) {
141
- this.element.remove();
162
+ if (this._generated && this.domElement) {
163
+ this.domElement.remove();
164
+ }
165
+ const container = this._container, domCanvas = isHtmlCanvasElement(canvas) ? canvas : undefined;
166
+ this.domElement = domCanvas;
167
+ this._generated = domCanvas ? domCanvas.dataset[generatedAttribute] === "true" : false;
168
+ this.renderCanvas = domCanvas ? getTransferredCanvas(domCanvas) : canvas;
169
+ const domElement = this.domElement;
170
+ if (domElement) {
171
+ domElement.ariaHidden = "true";
172
+ this._originalStyle = cloneStyle(domElement.style);
173
+ }
174
+ const standardSize = this._standardSize, renderCanvas = this.renderCanvas;
175
+ if (domElement) {
176
+ standardSize.height = domElement.offsetHeight;
177
+ standardSize.width = domElement.offsetWidth;
178
+ }
179
+ else {
180
+ standardSize.height = renderCanvas.height;
181
+ standardSize.width = renderCanvas.width;
142
182
  }
143
- const container = this._container;
144
- this._generated =
145
- generatedAttribute in canvas.dataset ? canvas.dataset[generatedAttribute] === "true" : this._generated;
146
- this.element = canvas;
147
- this.element.ariaHidden = "true";
148
- this._originalStyle = cloneStyle(this.element.style);
149
- const standardSize = this._standardSize;
150
- standardSize.height = canvas.offsetHeight;
151
- standardSize.width = canvas.offsetWidth;
152
183
  const pxRatio = this._container.retina.pixelRatio, retinaSize = this.size;
153
- canvas.height = retinaSize.height = standardSize.height * pxRatio;
154
- canvas.width = retinaSize.width = standardSize.width * pxRatio;
184
+ renderCanvas.height = retinaSize.height = standardSize.height * pxRatio;
185
+ renderCanvas.width = retinaSize.width = standardSize.width * pxRatio;
155
186
  const canSupportHdrQuery = safeMatchMedia("(color-gamut: p3)");
156
187
  this.render.setContextSettings({
157
188
  alpha: true,
@@ -159,42 +190,48 @@ export class CanvasManager {
159
190
  desynchronized: true,
160
191
  willReadFrequently: false,
161
192
  });
162
- this.render.setContext(this.element.getContext("2d", this.render.settings));
193
+ this.render.setContext(renderCanvas.getContext("2d", this.render.settings));
163
194
  this._safeMutationObserver(obs => {
164
195
  obs.disconnect();
165
196
  });
166
197
  container.retina.init();
167
198
  this.initBackground();
168
199
  this._safeMutationObserver(obs => {
169
- if (!this.element || !(this.element instanceof Node)) {
200
+ const element = this.domElement;
201
+ if (!element || !(element instanceof Node)) {
170
202
  return;
171
203
  }
172
- obs.observe(this.element, { attributes: true });
204
+ obs.observe(element, { attributes: true });
173
205
  });
174
206
  }
175
207
  resize() {
176
- if (!this.element) {
208
+ const element = this.domElement;
209
+ if (!element) {
210
+ return false;
211
+ }
212
+ const container = this._container, renderCanvas = this.renderCanvas;
213
+ if (renderCanvas === undefined) {
177
214
  return false;
178
215
  }
179
- const container = this._container, currentSize = container.canvas._standardSize, newSize = {
180
- width: this.element.offsetWidth,
181
- height: this.element.offsetHeight,
216
+ const currentSize = container.canvas._standardSize, newSize = {
217
+ width: element.offsetWidth,
218
+ height: element.offsetHeight,
182
219
  }, pxRatio = container.retina.pixelRatio, retinaSize = {
183
220
  width: newSize.width * pxRatio,
184
221
  height: newSize.height * pxRatio,
185
222
  };
186
223
  if (newSize.height === currentSize.height &&
187
224
  newSize.width === currentSize.width &&
188
- retinaSize.height === this.element.height &&
189
- retinaSize.width === this.element.width) {
225
+ retinaSize.height === renderCanvas.height &&
226
+ retinaSize.width === renderCanvas.width) {
190
227
  return false;
191
228
  }
192
229
  const oldSize = { ...currentSize };
193
230
  currentSize.height = newSize.height;
194
231
  currentSize.width = newSize.width;
195
232
  const canvasSize = this.size;
196
- this.element.width = canvasSize.width = retinaSize.width;
197
- this.element.height = canvasSize.height = retinaSize.height;
233
+ renderCanvas.width = canvasSize.width = retinaSize.width;
234
+ renderCanvas.height = canvasSize.height = retinaSize.height;
198
235
  if (this._container.started) {
199
236
  container.particles.setResizeFactor({
200
237
  width: currentSize.width / oldSize.width,
@@ -204,7 +241,7 @@ export class CanvasManager {
204
241
  return true;
205
242
  }
206
243
  setPointerEvents(type) {
207
- const element = this.element;
244
+ const element = this.domElement;
208
245
  if (!element) {
209
246
  return;
210
247
  }
@@ -223,7 +260,7 @@ export class CanvasManager {
223
260
  this.render.stop();
224
261
  }
225
262
  async windowResize() {
226
- if (!this.element || !this.resize()) {
263
+ if (!this.domElement || !this.resize()) {
227
264
  return;
228
265
  }
229
266
  const container = this._container, needsRefresh = container.updateActualOptions();
@@ -239,7 +276,7 @@ export class CanvasManager {
239
276
  }
240
277
  };
241
278
  _initStyle = () => {
242
- const element = this.element, options = this._container.actualOptions;
279
+ const element = this.domElement, options = this._container.actualOptions;
243
280
  if (!element) {
244
281
  return;
245
282
  }
@@ -261,7 +298,7 @@ export class CanvasManager {
261
298
  }
262
299
  };
263
300
  _repairStyle = () => {
264
- const element = this.element;
301
+ const element = this.domElement;
265
302
  if (!element) {
266
303
  return;
267
304
  }
@@ -272,7 +309,7 @@ export class CanvasManager {
272
309
  this.initBackground();
273
310
  const pointerEvents = this._pointerEvents;
274
311
  element.style.pointerEvents = pointerEvents;
275
- element.setAttribute("pointer-events", pointerEvents);
312
+ element.style.setProperty("pointer-events", pointerEvents);
276
313
  this._safeMutationObserver(observer => {
277
314
  if (!(element instanceof Node)) {
278
315
  return;
@@ -281,7 +318,7 @@ export class CanvasManager {
281
318
  });
282
319
  };
283
320
  _resetOriginalStyle = () => {
284
- const element = this.element, originalStyle = this._originalStyle;
321
+ const element = this.domElement, originalStyle = this._originalStyle;
285
322
  if (!element || !originalStyle) {
286
323
  return;
287
324
  }
@@ -294,7 +331,7 @@ export class CanvasManager {
294
331
  callback(this._mutationObserver);
295
332
  };
296
333
  _setFullScreenStyle = () => {
297
- const element = this.element;
334
+ const element = this.domElement;
298
335
  if (!element) {
299
336
  return;
300
337
  }
@@ -20,12 +20,19 @@ async function getDataFromUrl(data) {
20
20
  const getCanvasFromContainer = (domContainer) => {
21
21
  const documentSafe = safeDocument();
22
22
  let canvasEl;
23
- if (domContainer instanceof HTMLCanvasElement || domContainer.tagName.toLowerCase() === canvasTag) {
23
+ const isCanvas = domContainer instanceof HTMLCanvasElement || domContainer.tagName.toLowerCase() === canvasTag;
24
+ if (isCanvas) {
24
25
  canvasEl = domContainer;
25
26
  canvasEl.dataset[generatedAttribute] ??= generatedFalse;
27
+ if (canvasEl.dataset[generatedAttribute] === generatedTrue) {
28
+ canvasEl.style.width ||= fullPercent;
29
+ canvasEl.style.height ||= fullPercent;
30
+ canvasEl.style.pointerEvents = "none";
31
+ canvasEl.style.setProperty("pointer-events", "none");
32
+ }
26
33
  }
27
34
  else {
28
- const existingCanvases = domContainer.getElementsByTagName(canvasTag), foundCanvas = existingCanvases[canvasFirstIndex];
35
+ const existingCanvases = domContainer.getElementsByTagName(canvasTag), foundCanvas = existingCanvases.item(canvasFirstIndex);
29
36
  if (foundCanvas) {
30
37
  canvasEl = foundCanvas;
31
38
  canvasEl.dataset[generatedAttribute] = generatedFalse;
@@ -35,9 +42,11 @@ const getCanvasFromContainer = (domContainer) => {
35
42
  canvasEl.dataset[generatedAttribute] = generatedTrue;
36
43
  domContainer.appendChild(canvasEl);
37
44
  }
45
+ canvasEl.style.width ||= fullPercent;
46
+ canvasEl.style.height ||= fullPercent;
47
+ canvasEl.style.pointerEvents = "none";
48
+ canvasEl.style.setProperty("pointer-events", "none");
38
49
  }
39
- canvasEl.style.width ||= fullPercent;
40
- canvasEl.style.height ||= fullPercent;
41
50
  return canvasEl;
42
51
  }, getDomContainer = (id, source) => {
43
52
  const documentSafe = safeDocument();
@@ -60,7 +69,7 @@ export class Engine {
60
69
  return this._domArray;
61
70
  }
62
71
  get version() {
63
- return "4.0.0-beta.9";
72
+ return "4.0.0";
64
73
  }
65
74
  addEventListener(type, listener) {
66
75
  this._eventDispatcher.addEventListener(type, listener);
@@ -91,7 +100,11 @@ export class Engine {
91
100
  }
92
101
  async load(params) {
93
102
  await this.init();
94
- const { Container } = await import("./Container.js"), id = params.id ?? params.element?.id ?? `tsparticles${Math.floor(getRandom() * loadRandomFactor).toString()}`, { index, url } = params, options = url ? await getDataFromUrl({ fallback: params.options, url, index }) : params.options, currentOptions = itemFromSingleOrMultiple(options, index), { items } = this, oldIndex = items.findIndex(v => v.id.description === id), newItem = new Container({
103
+ let domSourceElement;
104
+ if (typeof HTMLElement !== "undefined" && params.element instanceof HTMLElement) {
105
+ domSourceElement = params.element;
106
+ }
107
+ const { Container } = await import("./Container.js"), id = params.id ?? domSourceElement?.id ?? `tsparticles${Math.floor(getRandom() * loadRandomFactor).toString()}`, { index, url } = params, options = url ? await getDataFromUrl({ fallback: params.options, url, index }) : params.options, currentOptions = itemFromSingleOrMultiple(options, index), { items } = this, oldIndex = items.findIndex(v => v.id.description === id), newItem = new Container({
95
108
  dispatchCallback: (eventType, args) => {
96
109
  this.dispatchEvent(eventType, args);
97
110
  },
@@ -118,8 +131,10 @@ export class Engine {
118
131
  else {
119
132
  items.push(newItem);
120
133
  }
121
- const domContainer = getDomContainer(id, params.element), canvasEl = getCanvasFromContainer(domContainer);
122
- newItem.canvas.loadCanvas(canvasEl);
134
+ const sourceCanvas = typeof OffscreenCanvas !== "undefined" && params.element instanceof OffscreenCanvas
135
+ ? params.element
136
+ : getCanvasFromContainer(getDomContainer(id, domSourceElement));
137
+ newItem.canvas.loadCanvas(sourceCanvas);
123
138
  await newItem.start();
124
139
  return newItem;
125
140
  }
@@ -49,6 +49,7 @@ export class Particle {
49
49
  initialPosition;
50
50
  initialVelocity;
51
51
  isRotating;
52
+ justWarped;
52
53
  lastPathTime;
53
54
  misplaced;
54
55
  moveCenter;
@@ -168,6 +169,7 @@ export class Particle {
168
169
  const container = this._container;
169
170
  this.id = id;
170
171
  this.group = group;
172
+ this.justWarped = false;
171
173
  this.effectClose = true;
172
174
  this.shapeClose = true;
173
175
  this.pathRotation = false;
@@ -240,8 +242,6 @@ export class Particle {
240
242
  this._initPosition(position);
241
243
  this.initialVelocity = this._calculateVelocity();
242
244
  this.velocity = this.initialVelocity.copy();
243
- const particles = container.particles;
244
- particles.setLastZIndex(this.position.z);
245
245
  this.zIndexFactor = this.position.z / container.zLayers;
246
246
  this.sides = 24;
247
247
  let effectDrawer, shapeDrawer;
@@ -391,7 +391,7 @@ export class Particle {
391
391
  return color;
392
392
  };
393
393
  _initPosition = position => {
394
- const container = this._container, zIndexValue = getRangeValue(this.options.zIndex.value), initialPosition = this._calcPosition(position, clamp(zIndexValue, minZ, container.zLayers));
394
+ const container = this._container, zIndexValue = Math.floor(getRangeValue(this.options.zIndex.value)), initialPosition = this._calcPosition(position, clamp(zIndexValue, minZ, container.zLayers));
395
395
  if (!initialPosition) {
396
396
  throw new Error("a valid position cannot be found for particle");
397
397
  }