@tsparticles/stencil 4.0.5

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 (42) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +73 -0
  3. package/dist/cjs/Container-DFed5jPA.js +3556 -0
  4. package/dist/cjs/app-globals-V2Kpy_OQ.js +5 -0
  5. package/dist/cjs/index-BY5-j3YK.js +1143 -0
  6. package/dist/cjs/index-Dwz1YgEM.js +1229 -0
  7. package/dist/cjs/index.cjs.js +9 -0
  8. package/dist/cjs/loader.cjs.js +13 -0
  9. package/dist/cjs/stencil-particles.cjs.entry.js +76 -0
  10. package/dist/cjs/tsparticlesstencil.cjs.js +25 -0
  11. package/dist/collection/collection-manifest.json +13 -0
  12. package/dist/collection/components/stencil-particles/stencil-particles.js +144 -0
  13. package/dist/collection/index.js +1 -0
  14. package/dist/collection/initParticlesEngine.js +38 -0
  15. package/dist/esm/Container-Di-pVL5B.js +3554 -0
  16. package/dist/esm/app-globals-DQuL1Twl.js +3 -0
  17. package/dist/esm/index-BzK79uqU.js +1223 -0
  18. package/dist/esm/index-CPcFDf6d.js +1052 -0
  19. package/dist/esm/index.js +1 -0
  20. package/dist/esm/loader.js +11 -0
  21. package/dist/esm/stencil-particles.entry.js +74 -0
  22. package/dist/esm/tsparticlesstencil.js +21 -0
  23. package/dist/index.cjs.js +1 -0
  24. package/dist/index.js +1 -0
  25. package/dist/tsparticlesstencil/index.esm.js +1 -0
  26. package/dist/tsparticlesstencil/p-2a10755a.entry.js +1 -0
  27. package/dist/tsparticlesstencil/p-BzK79uqU.js +2 -0
  28. package/dist/tsparticlesstencil/p-C6McIuSD.js +1 -0
  29. package/dist/tsparticlesstencil/p-DQuL1Twl.js +1 -0
  30. package/dist/tsparticlesstencil/p-x9G6hxBi.js +1 -0
  31. package/dist/tsparticlesstencil/tsparticlesstencil.esm.js +1 -0
  32. package/dist/types/components/stencil-particles/stencil-particles.d.ts +16 -0
  33. package/dist/types/components.d.ts +52 -0
  34. package/dist/types/index.d.ts +2 -0
  35. package/dist/types/initParticlesEngine.d.ts +5 -0
  36. package/dist/types/stencil-public-runtime.d.ts +1860 -0
  37. package/loader/cdn.js +1 -0
  38. package/loader/index.cjs.js +1 -0
  39. package/loader/index.d.ts +24 -0
  40. package/loader/index.es2017.js +1 -0
  41. package/loader/index.js +2 -0
  42. package/package.json +64 -0
@@ -0,0 +1,3556 @@
1
+ 'use strict';
2
+
3
+ var index = require('./index-BY5-j3YK.js');
4
+
5
+ class BaseRange {
6
+ position;
7
+ type;
8
+ constructor(x, y, type) {
9
+ this.position = {
10
+ x: x,
11
+ y: y,
12
+ };
13
+ this.type = type;
14
+ }
15
+ _resetPosition(x, y) {
16
+ this.position.x = x;
17
+ this.position.y = y;
18
+ }
19
+ }
20
+ class Circle extends BaseRange {
21
+ radius;
22
+ constructor(x, y, radius) {
23
+ super(x, y, index.RangeType.circle);
24
+ this.radius = radius;
25
+ }
26
+ contains(point) {
27
+ return index.checkDistance(point, this.position, this.radius);
28
+ }
29
+ intersects(range) {
30
+ const pos1 = this.position, pos2 = range.position, r = this.radius, dx = Math.abs(pos2.x - pos1.x), dy = Math.abs(pos2.y - pos1.y);
31
+ if (range instanceof Circle || range.type === index.RangeType.circle) {
32
+ const circleRange = range, rSum = r + circleRange.radius, dist = Math.hypot(dx, dy);
33
+ return rSum > dist;
34
+ }
35
+ else if (range instanceof Rectangle || range.type === index.RangeType.rectangle) {
36
+ const rectRange = range, { width, height } = rectRange.size, edges = Math.pow(dx - width, index.squareExp) + Math.pow(dy - height, index.squareExp);
37
+ return edges <= r ** index.squareExp || (dx <= r + width && dy <= r + height) || dx <= width || dy <= height;
38
+ }
39
+ return false;
40
+ }
41
+ reset(x, y, radius) {
42
+ this._resetPosition(x, y);
43
+ this.radius = radius;
44
+ return this;
45
+ }
46
+ }
47
+ class Rectangle extends BaseRange {
48
+ size;
49
+ constructor(x, y, width, height) {
50
+ super(x, y, index.RangeType.rectangle);
51
+ this.size = {
52
+ height: height,
53
+ width: width,
54
+ };
55
+ }
56
+ contains(point) {
57
+ const w = this.size.width, h = this.size.height, pos = this.position;
58
+ return point.x >= pos.x && point.x <= pos.x + w && point.y >= pos.y && point.y <= pos.y + h;
59
+ }
60
+ intersects(range) {
61
+ if (range instanceof Circle) {
62
+ return range.intersects(this);
63
+ }
64
+ if (!(range instanceof Rectangle)) {
65
+ return false;
66
+ }
67
+ const w = this.size.width, h = this.size.height, pos1 = this.position, pos2 = range.position, size2 = range.size, w2 = size2.width, h2 = size2.height;
68
+ return pos2.x < pos1.x + w && pos2.x + w2 > pos1.x && pos2.y < pos1.y + h && pos2.y + h2 > pos1.y;
69
+ }
70
+ reset(x, y, width, height) {
71
+ this._resetPosition(x, y);
72
+ this.size.width = width;
73
+ this.size.height = height;
74
+ return this;
75
+ }
76
+ }
77
+
78
+ class AnimationOptions {
79
+ count;
80
+ decay;
81
+ delay;
82
+ enable;
83
+ speed;
84
+ sync;
85
+ constructor() {
86
+ this.count = 0;
87
+ this.enable = false;
88
+ this.speed = 1;
89
+ this.decay = 0;
90
+ this.delay = 0;
91
+ this.sync = false;
92
+ }
93
+ load(data) {
94
+ if (index.isNull(data)) {
95
+ return;
96
+ }
97
+ if (data.count !== undefined) {
98
+ this.count = index.setRangeValue(data.count);
99
+ }
100
+ if (data.enable !== undefined) {
101
+ this.enable = data.enable;
102
+ }
103
+ if (data.speed !== undefined) {
104
+ this.speed = index.setRangeValue(data.speed);
105
+ }
106
+ if (data.decay !== undefined) {
107
+ this.decay = index.setRangeValue(data.decay);
108
+ }
109
+ if (data.delay !== undefined) {
110
+ this.delay = index.setRangeValue(data.delay);
111
+ }
112
+ if (data.sync !== undefined) {
113
+ this.sync = data.sync;
114
+ }
115
+ }
116
+ }
117
+
118
+ class ColorAnimation extends AnimationOptions {
119
+ max;
120
+ min;
121
+ offset;
122
+ constructor(min, max) {
123
+ super();
124
+ this.min = min;
125
+ this.max = max;
126
+ this.offset = 0;
127
+ this.sync = true;
128
+ }
129
+ load(data) {
130
+ super.load(data);
131
+ if (index.isNull(data)) {
132
+ return;
133
+ }
134
+ if (data.max !== undefined) {
135
+ this.max = data.max;
136
+ }
137
+ if (data.min !== undefined) {
138
+ this.min = data.min;
139
+ }
140
+ if (data.offset !== undefined) {
141
+ this.offset = index.setRangeValue(data.offset);
142
+ }
143
+ }
144
+ }
145
+
146
+ class HslAnimation {
147
+ h = new ColorAnimation(index.hMin, index.hMax);
148
+ l = new ColorAnimation(index.lMin, index.lMax);
149
+ s = new ColorAnimation(index.sMin, index.sMax);
150
+ load(data) {
151
+ if (index.isNull(data)) {
152
+ return;
153
+ }
154
+ this.h.load(data.h);
155
+ this.s.load(data.s);
156
+ this.l.load(data.l);
157
+ }
158
+ }
159
+
160
+ class OptionsColor {
161
+ value;
162
+ constructor() {
163
+ this.value = "";
164
+ }
165
+ static create(source, data) {
166
+ const color = new OptionsColor();
167
+ color.load(source);
168
+ if (data !== undefined) {
169
+ if (index.isString(data) || index.isArray(data)) {
170
+ color.load({ value: data });
171
+ }
172
+ else {
173
+ color.load(data);
174
+ }
175
+ }
176
+ return color;
177
+ }
178
+ load(data) {
179
+ if (index.isNull(data)) {
180
+ return;
181
+ }
182
+ if (!index.isNull(data.value)) {
183
+ this.value = data.value;
184
+ }
185
+ }
186
+ }
187
+
188
+ class AnimatableColor extends OptionsColor {
189
+ animation;
190
+ constructor() {
191
+ super();
192
+ this.animation = new HslAnimation();
193
+ }
194
+ static create(source, data) {
195
+ const color = new AnimatableColor();
196
+ color.load(source);
197
+ if (data !== undefined) {
198
+ if (index.isString(data) || index.isArray(data)) {
199
+ color.load({ value: data });
200
+ }
201
+ else {
202
+ color.load(data);
203
+ }
204
+ }
205
+ return color;
206
+ }
207
+ load(data) {
208
+ super.load(data);
209
+ if (index.isNull(data)) {
210
+ return;
211
+ }
212
+ const colorAnimation = data.animation;
213
+ if (colorAnimation !== undefined) {
214
+ if (colorAnimation.enable === undefined) {
215
+ this.animation.load(data.animation);
216
+ }
217
+ else {
218
+ this.animation.h.load(colorAnimation);
219
+ }
220
+ }
221
+ }
222
+ }
223
+
224
+ class Background {
225
+ color;
226
+ image;
227
+ opacity;
228
+ position;
229
+ repeat;
230
+ size;
231
+ constructor() {
232
+ this.color = new OptionsColor();
233
+ this.color.value = "";
234
+ this.image = "";
235
+ this.position = "";
236
+ this.repeat = "";
237
+ this.size = "";
238
+ this.opacity = 1;
239
+ }
240
+ load(data) {
241
+ if (index.isNull(data)) {
242
+ return;
243
+ }
244
+ if (data.color !== undefined) {
245
+ this.color = OptionsColor.create(this.color, data.color);
246
+ }
247
+ if (data.image !== undefined) {
248
+ this.image = data.image;
249
+ }
250
+ if (data.position !== undefined) {
251
+ this.position = data.position;
252
+ }
253
+ if (data.repeat !== undefined) {
254
+ this.repeat = data.repeat;
255
+ }
256
+ if (data.size !== undefined) {
257
+ this.size = data.size;
258
+ }
259
+ if (data.opacity !== undefined) {
260
+ this.opacity = data.opacity;
261
+ }
262
+ }
263
+ }
264
+
265
+ class FullScreen {
266
+ enable;
267
+ zIndex;
268
+ constructor() {
269
+ this.enable = true;
270
+ this.zIndex = 0;
271
+ }
272
+ load(data) {
273
+ if (index.isNull(data)) {
274
+ return;
275
+ }
276
+ if (data.enable !== undefined) {
277
+ this.enable = data.enable;
278
+ }
279
+ if (data.zIndex !== undefined) {
280
+ this.zIndex = data.zIndex;
281
+ }
282
+ }
283
+ }
284
+
285
+ class ResizeEvent {
286
+ delay;
287
+ enable;
288
+ constructor() {
289
+ this.delay = 0.5;
290
+ this.enable = true;
291
+ }
292
+ load(data) {
293
+ if (index.isNull(data)) {
294
+ return;
295
+ }
296
+ if (data.delay !== undefined) {
297
+ this.delay = data.delay;
298
+ }
299
+ if (data.enable !== undefined) {
300
+ this.enable = data.enable;
301
+ }
302
+ }
303
+ }
304
+
305
+ class Effect {
306
+ close;
307
+ options;
308
+ type;
309
+ constructor() {
310
+ this.close = true;
311
+ this.options = {};
312
+ this.type = [];
313
+ }
314
+ load(data) {
315
+ if (index.isNull(data)) {
316
+ return;
317
+ }
318
+ const options = data.options;
319
+ if (options !== undefined) {
320
+ for (const effect in options) {
321
+ const item = options[effect];
322
+ if (item) {
323
+ this.options[effect] = index.deepExtend(this.options[effect] ?? {}, item);
324
+ }
325
+ }
326
+ }
327
+ if (data.close !== undefined) {
328
+ this.close = data.close;
329
+ }
330
+ if (data.type !== undefined) {
331
+ this.type = data.type;
332
+ }
333
+ }
334
+ }
335
+
336
+ class Fill {
337
+ color;
338
+ enable;
339
+ opacity;
340
+ constructor() {
341
+ this.enable = true;
342
+ this.opacity = 1;
343
+ }
344
+ load(data) {
345
+ if (index.isNull(data)) {
346
+ return;
347
+ }
348
+ if (data.color !== undefined) {
349
+ this.color = AnimatableColor.create(this.color, data.color);
350
+ }
351
+ if (data.enable !== undefined) {
352
+ this.enable = data.enable;
353
+ }
354
+ if (data.opacity !== undefined) {
355
+ this.opacity = index.setRangeValue(data.opacity);
356
+ }
357
+ }
358
+ }
359
+
360
+ class MoveAngle {
361
+ offset;
362
+ value;
363
+ constructor() {
364
+ this.offset = 0;
365
+ this.value = 90;
366
+ }
367
+ load(data) {
368
+ if (index.isNull(data)) {
369
+ return;
370
+ }
371
+ if (data.offset !== undefined) {
372
+ this.offset = index.setRangeValue(data.offset);
373
+ }
374
+ if (data.value !== undefined) {
375
+ this.value = index.setRangeValue(data.value);
376
+ }
377
+ }
378
+ }
379
+
380
+ class MoveCenter {
381
+ mode;
382
+ radius;
383
+ x;
384
+ y;
385
+ constructor() {
386
+ this.x = 50;
387
+ this.y = 50;
388
+ this.mode = index.PixelMode.percent;
389
+ this.radius = 0;
390
+ }
391
+ load(data) {
392
+ if (index.isNull(data)) {
393
+ return;
394
+ }
395
+ if (data.x !== undefined) {
396
+ this.x = data.x;
397
+ }
398
+ if (data.y !== undefined) {
399
+ this.y = data.y;
400
+ }
401
+ if (data.mode !== undefined) {
402
+ this.mode = data.mode;
403
+ }
404
+ if (data.radius !== undefined) {
405
+ this.radius = data.radius;
406
+ }
407
+ }
408
+ }
409
+
410
+ class MoveGravity {
411
+ acceleration;
412
+ enable;
413
+ inverse;
414
+ maxSpeed;
415
+ constructor() {
416
+ this.acceleration = 9.81;
417
+ this.enable = false;
418
+ this.inverse = false;
419
+ this.maxSpeed = 50;
420
+ }
421
+ load(data) {
422
+ if (index.isNull(data)) {
423
+ return;
424
+ }
425
+ if (data.acceleration !== undefined) {
426
+ this.acceleration = index.setRangeValue(data.acceleration);
427
+ }
428
+ if (data.enable !== undefined) {
429
+ this.enable = data.enable;
430
+ }
431
+ if (data.inverse !== undefined) {
432
+ this.inverse = data.inverse;
433
+ }
434
+ if (data.maxSpeed !== undefined) {
435
+ this.maxSpeed = index.setRangeValue(data.maxSpeed);
436
+ }
437
+ }
438
+ }
439
+
440
+ class ValueWithRandom {
441
+ value;
442
+ constructor() {
443
+ this.value = 0;
444
+ }
445
+ load(data) {
446
+ if (index.isNull(data)) {
447
+ return;
448
+ }
449
+ if (!index.isNull(data.value)) {
450
+ this.value = index.setRangeValue(data.value);
451
+ }
452
+ }
453
+ }
454
+
455
+ class MovePath {
456
+ clamp;
457
+ delay;
458
+ enable;
459
+ generator;
460
+ options;
461
+ constructor() {
462
+ this.clamp = true;
463
+ this.delay = new ValueWithRandom();
464
+ this.enable = false;
465
+ this.options = {};
466
+ }
467
+ load(data) {
468
+ if (index.isNull(data)) {
469
+ return;
470
+ }
471
+ if (data.clamp !== undefined) {
472
+ this.clamp = data.clamp;
473
+ }
474
+ this.delay.load(data.delay);
475
+ if (data.enable !== undefined) {
476
+ this.enable = data.enable;
477
+ }
478
+ this.generator = data.generator;
479
+ if (data.options) {
480
+ this.options = index.deepExtend(this.options, data.options);
481
+ }
482
+ }
483
+ }
484
+
485
+ class OutModes {
486
+ bottom;
487
+ default;
488
+ left;
489
+ right;
490
+ top;
491
+ constructor() {
492
+ this.default = index.OutMode.out;
493
+ }
494
+ load(data) {
495
+ if (index.isNull(data)) {
496
+ return;
497
+ }
498
+ if (data.default !== undefined) {
499
+ this.default = data.default;
500
+ }
501
+ this.bottom = data.bottom ?? data.default;
502
+ this.left = data.left ?? data.default;
503
+ this.right = data.right ?? data.default;
504
+ this.top = data.top ?? data.default;
505
+ }
506
+ }
507
+
508
+ class Spin {
509
+ acceleration;
510
+ enable;
511
+ position;
512
+ constructor() {
513
+ this.acceleration = 0;
514
+ this.enable = false;
515
+ }
516
+ load(data) {
517
+ if (index.isNull(data)) {
518
+ return;
519
+ }
520
+ if (data.acceleration !== undefined) {
521
+ this.acceleration = index.setRangeValue(data.acceleration);
522
+ }
523
+ if (data.enable !== undefined) {
524
+ this.enable = data.enable;
525
+ }
526
+ if (data.position) {
527
+ this.position = index.deepExtend({}, data.position);
528
+ }
529
+ }
530
+ }
531
+
532
+ class Move {
533
+ angle;
534
+ center;
535
+ decay;
536
+ direction;
537
+ distance;
538
+ drift;
539
+ enable;
540
+ gravity;
541
+ outModes;
542
+ path;
543
+ random;
544
+ size;
545
+ speed;
546
+ spin;
547
+ straight;
548
+ vibrate;
549
+ warp;
550
+ constructor() {
551
+ this.angle = new MoveAngle();
552
+ this.center = new MoveCenter();
553
+ this.decay = 0;
554
+ this.distance = {};
555
+ this.direction = index.MoveDirection.none;
556
+ this.drift = 0;
557
+ this.enable = false;
558
+ this.gravity = new MoveGravity();
559
+ this.path = new MovePath();
560
+ this.outModes = new OutModes();
561
+ this.random = false;
562
+ this.size = false;
563
+ this.speed = 2;
564
+ this.spin = new Spin();
565
+ this.straight = false;
566
+ this.vibrate = false;
567
+ this.warp = false;
568
+ }
569
+ load(data) {
570
+ if (index.isNull(data)) {
571
+ return;
572
+ }
573
+ this.angle.load(index.isNumber(data.angle) ? { value: data.angle } : data.angle);
574
+ this.center.load(data.center);
575
+ if (data.decay !== undefined) {
576
+ this.decay = index.setRangeValue(data.decay);
577
+ }
578
+ if (data.direction !== undefined) {
579
+ this.direction = data.direction;
580
+ }
581
+ if (data.distance !== undefined) {
582
+ this.distance = index.isNumber(data.distance)
583
+ ? {
584
+ horizontal: data.distance,
585
+ vertical: data.distance,
586
+ }
587
+ : { ...data.distance };
588
+ }
589
+ if (data.drift !== undefined) {
590
+ this.drift = index.setRangeValue(data.drift);
591
+ }
592
+ if (data.enable !== undefined) {
593
+ this.enable = data.enable;
594
+ }
595
+ this.gravity.load(data.gravity);
596
+ const outModes = data.outModes;
597
+ if (outModes !== undefined) {
598
+ if (index.isObject(outModes)) {
599
+ this.outModes.load(outModes);
600
+ }
601
+ else {
602
+ this.outModes.load({
603
+ default: outModes,
604
+ });
605
+ }
606
+ }
607
+ this.path.load(data.path);
608
+ if (data.random !== undefined) {
609
+ this.random = data.random;
610
+ }
611
+ if (data.size !== undefined) {
612
+ this.size = data.size;
613
+ }
614
+ if (data.speed !== undefined) {
615
+ this.speed = index.setRangeValue(data.speed);
616
+ }
617
+ this.spin.load(data.spin);
618
+ if (data.straight !== undefined) {
619
+ this.straight = data.straight;
620
+ }
621
+ if (data.vibrate !== undefined) {
622
+ this.vibrate = data.vibrate;
623
+ }
624
+ if (data.warp !== undefined) {
625
+ this.warp = data.warp;
626
+ }
627
+ }
628
+ }
629
+
630
+ class Stroke {
631
+ color;
632
+ opacity;
633
+ width;
634
+ constructor() {
635
+ this.width = 0;
636
+ }
637
+ load(data) {
638
+ if (index.isNull(data)) {
639
+ return;
640
+ }
641
+ if (data.color !== undefined) {
642
+ this.color = AnimatableColor.create(this.color, data.color);
643
+ }
644
+ if (data.width !== undefined) {
645
+ this.width = index.setRangeValue(data.width);
646
+ }
647
+ if (data.opacity !== undefined) {
648
+ this.opacity = index.setRangeValue(data.opacity);
649
+ }
650
+ }
651
+ }
652
+
653
+ class Paint {
654
+ color;
655
+ fill;
656
+ stroke;
657
+ load(data) {
658
+ if (index.isNull(data)) {
659
+ return;
660
+ }
661
+ if (data.color !== undefined) {
662
+ this.color = AnimatableColor.create(this.color, data.color);
663
+ }
664
+ if (data.fill !== undefined) {
665
+ this.fill ??= new Fill();
666
+ this.fill.load(data.fill);
667
+ }
668
+ if (data.stroke !== undefined) {
669
+ this.stroke ??= new Stroke();
670
+ this.stroke.load(data.stroke);
671
+ }
672
+ }
673
+ }
674
+
675
+ class ParticlesBounceFactor extends ValueWithRandom {
676
+ constructor() {
677
+ super();
678
+ this.value = 1;
679
+ }
680
+ }
681
+
682
+ class ParticlesBounce {
683
+ horizontal;
684
+ vertical;
685
+ constructor() {
686
+ this.horizontal = new ParticlesBounceFactor();
687
+ this.vertical = new ParticlesBounceFactor();
688
+ }
689
+ load(data) {
690
+ if (index.isNull(data)) {
691
+ return;
692
+ }
693
+ this.horizontal.load(data.horizontal);
694
+ this.vertical.load(data.vertical);
695
+ }
696
+ }
697
+
698
+ class ParticlesDensity {
699
+ enable;
700
+ height;
701
+ width;
702
+ constructor() {
703
+ this.enable = false;
704
+ this.width = 1920;
705
+ this.height = 1080;
706
+ }
707
+ load(data) {
708
+ if (index.isNull(data)) {
709
+ return;
710
+ }
711
+ if (data.enable !== undefined) {
712
+ this.enable = data.enable;
713
+ }
714
+ const width = data.width;
715
+ if (width !== undefined) {
716
+ this.width = width;
717
+ }
718
+ const height = data.height;
719
+ if (height !== undefined) {
720
+ this.height = height;
721
+ }
722
+ }
723
+ }
724
+
725
+ class ParticlesNumberLimit {
726
+ mode;
727
+ value;
728
+ constructor() {
729
+ this.mode = index.LimitMode.delete;
730
+ this.value = 0;
731
+ }
732
+ load(data) {
733
+ if (index.isNull(data)) {
734
+ return;
735
+ }
736
+ if (data.mode !== undefined) {
737
+ this.mode = data.mode;
738
+ }
739
+ if (data.value !== undefined) {
740
+ this.value = data.value;
741
+ }
742
+ }
743
+ }
744
+
745
+ class ParticlesNumber {
746
+ density;
747
+ limit;
748
+ value;
749
+ constructor() {
750
+ this.density = new ParticlesDensity();
751
+ this.limit = new ParticlesNumberLimit();
752
+ this.value = 0;
753
+ }
754
+ load(data) {
755
+ if (index.isNull(data)) {
756
+ return;
757
+ }
758
+ this.density.load(data.density);
759
+ this.limit.load(data.limit);
760
+ if (data.value !== undefined) {
761
+ this.value = data.value;
762
+ }
763
+ }
764
+ }
765
+
766
+ class Shape {
767
+ close;
768
+ options;
769
+ type;
770
+ constructor() {
771
+ this.close = true;
772
+ this.options = {};
773
+ this.type = "circle";
774
+ }
775
+ load(data) {
776
+ if (index.isNull(data)) {
777
+ return;
778
+ }
779
+ const options = data.options;
780
+ if (options !== undefined) {
781
+ for (const shape in options) {
782
+ const item = options[shape];
783
+ if (item) {
784
+ this.options[shape] = index.deepExtend(this.options[shape] ?? {}, item);
785
+ }
786
+ }
787
+ }
788
+ if (data.close !== undefined) {
789
+ this.close = data.close;
790
+ }
791
+ if (data.type !== undefined) {
792
+ this.type = data.type;
793
+ }
794
+ }
795
+ }
796
+
797
+ class ZIndex extends ValueWithRandom {
798
+ opacityRate;
799
+ sizeRate;
800
+ velocityRate;
801
+ constructor() {
802
+ super();
803
+ this.opacityRate = 1;
804
+ this.sizeRate = 1;
805
+ this.velocityRate = 1;
806
+ }
807
+ load(data) {
808
+ super.load(data);
809
+ if (index.isNull(data)) {
810
+ return;
811
+ }
812
+ if (data.opacityRate !== undefined) {
813
+ this.opacityRate = data.opacityRate;
814
+ }
815
+ if (data.sizeRate !== undefined) {
816
+ this.sizeRate = data.sizeRate;
817
+ }
818
+ if (data.velocityRate !== undefined) {
819
+ this.velocityRate = data.velocityRate;
820
+ }
821
+ }
822
+ }
823
+
824
+ class ParticlesOptions {
825
+ bounce;
826
+ effect;
827
+ groups;
828
+ move;
829
+ number;
830
+ paint;
831
+ palette;
832
+ reduceDuplicates;
833
+ shape;
834
+ zIndex;
835
+ #container;
836
+ #pluginManager;
837
+ constructor(pluginManager, container) {
838
+ this.#pluginManager = pluginManager;
839
+ this.#container = container;
840
+ this.bounce = new ParticlesBounce();
841
+ this.effect = new Effect();
842
+ this.groups = {};
843
+ this.move = new Move();
844
+ this.number = new ParticlesNumber();
845
+ this.paint = new Paint();
846
+ this.paint.color = new AnimatableColor();
847
+ this.paint.color.value = "#fff";
848
+ this.paint.fill = new Fill();
849
+ this.paint.fill.enable = true;
850
+ this.reduceDuplicates = false;
851
+ this.shape = new Shape();
852
+ this.zIndex = new ZIndex();
853
+ }
854
+ load(data) {
855
+ if (index.isNull(data)) {
856
+ return;
857
+ }
858
+ if (data.palette) {
859
+ this.palette = data.palette;
860
+ this.#importPalette(this.palette);
861
+ }
862
+ if (data.groups !== undefined) {
863
+ for (const group of Object.keys(data.groups)) {
864
+ if (!(group in data.groups)) {
865
+ continue;
866
+ }
867
+ const item = data.groups[group];
868
+ if (item !== undefined) {
869
+ this.groups[group] = index.deepExtend(this.groups[group] ?? {}, item);
870
+ }
871
+ }
872
+ }
873
+ if (data.reduceDuplicates !== undefined) {
874
+ this.reduceDuplicates = data.reduceDuplicates;
875
+ }
876
+ this.bounce.load(data.bounce);
877
+ this.effect.load(data.effect);
878
+ this.move.load(data.move);
879
+ this.number.load(data.number);
880
+ const paintToLoad = data.paint;
881
+ if (paintToLoad) {
882
+ if (index.isArray(paintToLoad)) {
883
+ this.paint = index.executeOnSingleOrMultiple(paintToLoad, t => {
884
+ const tmp = new Paint();
885
+ tmp.load(t);
886
+ return tmp;
887
+ });
888
+ }
889
+ else if (index.isArray(this.paint)) {
890
+ this.paint = new Paint();
891
+ this.paint.load(paintToLoad);
892
+ }
893
+ else {
894
+ this.paint.load(paintToLoad);
895
+ }
896
+ }
897
+ this.shape.load(data.shape);
898
+ this.zIndex.load(data.zIndex);
899
+ if (this.#container) {
900
+ for (const plugin of this.#pluginManager.plugins) {
901
+ if (plugin.loadParticlesOptions) {
902
+ plugin.loadParticlesOptions(this.#container, this, data);
903
+ }
904
+ }
905
+ const updaters = this.#pluginManager.updaters.get(this.#container);
906
+ if (updaters) {
907
+ for (const updater of updaters) {
908
+ if (updater.loadOptions) {
909
+ updater.loadOptions(this, data);
910
+ }
911
+ }
912
+ }
913
+ }
914
+ }
915
+ #importPalette = (palette) => {
916
+ const paletteData = this.#pluginManager.getPalette(palette);
917
+ if (!paletteData) {
918
+ return;
919
+ }
920
+ const paletteColors = paletteData.colors, defaultPaintStrokeWidth = 0, defaultPaintVariantsLength = 1, firstPaintVariantIndex = 0, defaultPalettePaintVariant = {}, colorVariants = index.isArray(paletteColors) ? paletteColors : [paletteColors], palettePaintVariants = colorVariants.flatMap(variant => {
921
+ const paletteFill = variant.fill, paletteStroke = variant.stroke, fillPart = paletteFill
922
+ ? {
923
+ color: {
924
+ value: paletteFill.value,
925
+ },
926
+ enable: paletteFill.enable,
927
+ opacity: paletteFill.opacity,
928
+ }
929
+ : undefined;
930
+ if (!paletteStroke) {
931
+ return [
932
+ {
933
+ fill: fillPart,
934
+ },
935
+ ];
936
+ }
937
+ return [
938
+ {
939
+ fill: fillPart,
940
+ stroke: {
941
+ color: {
942
+ value: paletteStroke.value,
943
+ },
944
+ opacity: paletteStroke.opacity,
945
+ width: paletteStroke.width || defaultPaintStrokeWidth,
946
+ },
947
+ },
948
+ ];
949
+ }), palettePaint = palettePaintVariants.length > defaultPaintVariantsLength
950
+ ? palettePaintVariants
951
+ : (palettePaintVariants[firstPaintVariantIndex] ?? defaultPalettePaintVariant);
952
+ this.load({
953
+ paint: palettePaint,
954
+ blend: {
955
+ enable: true,
956
+ mode: paletteData.blendMode,
957
+ },
958
+ });
959
+ };
960
+ }
961
+
962
+ function loadOptions(options, ...sourceOptionsArr) {
963
+ for (const sourceOptions of sourceOptionsArr) {
964
+ options.load(sourceOptions);
965
+ }
966
+ }
967
+ function loadParticlesOptions(pluginManager, container, ...sourceOptionsArr) {
968
+ const options = new ParticlesOptions(pluginManager, container);
969
+ loadOptions(options, ...sourceOptionsArr);
970
+ return options;
971
+ }
972
+
973
+ class Options {
974
+ autoPlay;
975
+ background;
976
+ clear;
977
+ defaultThemes;
978
+ delay;
979
+ detectRetina;
980
+ duration;
981
+ fpsLimit;
982
+ fullScreen;
983
+ hdr;
984
+ key;
985
+ name;
986
+ palette;
987
+ particles;
988
+ pauseOnBlur;
989
+ pauseOnOutsideViewport;
990
+ preset;
991
+ resize;
992
+ smooth;
993
+ style;
994
+ zLayers;
995
+ #container;
996
+ #pluginManager;
997
+ constructor(pluginManager, container) {
998
+ this.#pluginManager = pluginManager;
999
+ this.#container = container;
1000
+ this.autoPlay = true;
1001
+ this.background = new Background();
1002
+ this.clear = true;
1003
+ this.defaultThemes = {};
1004
+ this.delay = 0;
1005
+ this.fullScreen = new FullScreen();
1006
+ this.detectRetina = true;
1007
+ this.duration = 0;
1008
+ this.fpsLimit = 120;
1009
+ this.hdr = true;
1010
+ this.particles = loadParticlesOptions(this.#pluginManager, this.#container);
1011
+ this.pauseOnBlur = true;
1012
+ this.pauseOnOutsideViewport = true;
1013
+ this.resize = new ResizeEvent();
1014
+ this.smooth = false;
1015
+ this.style = {};
1016
+ this.zLayers = 100;
1017
+ }
1018
+ load(data) {
1019
+ if (index.isNull(data)) {
1020
+ return;
1021
+ }
1022
+ if (data.preset !== undefined) {
1023
+ this.preset = data.preset;
1024
+ index.executeOnSingleOrMultiple(this.preset, preset => {
1025
+ this.#importPreset(preset);
1026
+ });
1027
+ }
1028
+ if (data.palette !== undefined) {
1029
+ this.palette = data.palette;
1030
+ this.#importPalette(this.palette);
1031
+ }
1032
+ if (data.autoPlay !== undefined) {
1033
+ this.autoPlay = data.autoPlay;
1034
+ }
1035
+ if (data.clear !== undefined) {
1036
+ this.clear = data.clear;
1037
+ }
1038
+ if (data.key !== undefined) {
1039
+ this.key = data.key;
1040
+ }
1041
+ if (data.name !== undefined) {
1042
+ this.name = data.name;
1043
+ }
1044
+ if (data.delay !== undefined) {
1045
+ this.delay = index.setRangeValue(data.delay);
1046
+ }
1047
+ const detectRetina = data.detectRetina;
1048
+ if (detectRetina !== undefined) {
1049
+ this.detectRetina = detectRetina;
1050
+ }
1051
+ if (data.duration !== undefined) {
1052
+ this.duration = index.setRangeValue(data.duration);
1053
+ }
1054
+ const fpsLimit = data.fpsLimit;
1055
+ if (fpsLimit !== undefined) {
1056
+ this.fpsLimit = fpsLimit;
1057
+ }
1058
+ if (data.hdr !== undefined) {
1059
+ this.hdr = data.hdr;
1060
+ }
1061
+ if (data.pauseOnBlur !== undefined) {
1062
+ this.pauseOnBlur = data.pauseOnBlur;
1063
+ }
1064
+ if (data.pauseOnOutsideViewport !== undefined) {
1065
+ this.pauseOnOutsideViewport = data.pauseOnOutsideViewport;
1066
+ }
1067
+ if (data.zLayers !== undefined) {
1068
+ this.zLayers = data.zLayers;
1069
+ }
1070
+ this.background.load(data.background);
1071
+ const fullScreen = data.fullScreen;
1072
+ if (index.isBoolean(fullScreen)) {
1073
+ this.fullScreen.enable = fullScreen;
1074
+ }
1075
+ else {
1076
+ this.fullScreen.load(fullScreen);
1077
+ }
1078
+ this.particles.load(data.particles);
1079
+ this.resize.load(data.resize);
1080
+ this.style = index.deepExtend(this.style, data.style);
1081
+ if (data.smooth !== undefined) {
1082
+ this.smooth = data.smooth;
1083
+ }
1084
+ this.#pluginManager.plugins.forEach(plugin => {
1085
+ plugin.loadOptions(this.#container, this, data);
1086
+ });
1087
+ }
1088
+ #importPalette = palette => {
1089
+ const paletteData = this.#pluginManager.getPalette(palette);
1090
+ if (!paletteData) {
1091
+ return;
1092
+ }
1093
+ this.load({
1094
+ background: {
1095
+ color: paletteData.background,
1096
+ },
1097
+ blend: {
1098
+ enable: true,
1099
+ mode: paletteData.blendMode,
1100
+ },
1101
+ particles: {
1102
+ palette,
1103
+ },
1104
+ });
1105
+ };
1106
+ #importPreset = preset => {
1107
+ this.load(this.#pluginManager.getPreset(preset));
1108
+ };
1109
+ }
1110
+
1111
+ function paintBase(context, dimension, baseColor) {
1112
+ context.fillStyle = baseColor ?? "rgba(0,0,0,0)";
1113
+ context.fillRect(index.originPoint.x, index.originPoint.y, dimension.width, dimension.height);
1114
+ }
1115
+ function paintImage(context, dimension, image, opacity) {
1116
+ if (!image) {
1117
+ return;
1118
+ }
1119
+ const prevAlpha = context.globalAlpha;
1120
+ context.globalAlpha = opacity;
1121
+ context.drawImage(image, index.originPoint.x, index.originPoint.y, dimension.width, dimension.height);
1122
+ context.globalAlpha = prevAlpha;
1123
+ }
1124
+ function clear(context, dimension) {
1125
+ context.clearRect(index.originPoint.x, index.originPoint.y, dimension.width, dimension.height);
1126
+ }
1127
+ function drawParticle(data) {
1128
+ const { container, context, particle, delta, colorStyles, radius, opacity, transform } = data, { effectDrawers, shapeDrawers } = container, pos = particle.getPosition(), transformData = particle.getTransformData(transform), drawScale = index.defaultZoom, drawPosition = {
1129
+ x: pos.x,
1130
+ y: pos.y,
1131
+ };
1132
+ context.setTransform(transformData.a, transformData.b, transformData.c, transformData.d, pos.x, pos.y);
1133
+ if (colorStyles.fill) {
1134
+ context.fillStyle = colorStyles.fill;
1135
+ }
1136
+ const fillEnabled = !!particle.fillEnabled, strokeWidth = particle.strokeWidth ?? index.minStrokeWidth;
1137
+ context.lineWidth = strokeWidth;
1138
+ if (colorStyles.stroke) {
1139
+ context.strokeStyle = colorStyles.stroke;
1140
+ }
1141
+ const drawData = {
1142
+ context,
1143
+ particle,
1144
+ radius,
1145
+ drawRadius: radius * drawScale,
1146
+ opacity,
1147
+ delta,
1148
+ pixelRatio: container.retina.pixelRatio,
1149
+ fill: fillEnabled,
1150
+ stroke: strokeWidth > index.minStrokeWidth,
1151
+ transformData,
1152
+ position: { ...pos },
1153
+ drawPosition,
1154
+ drawScale,
1155
+ };
1156
+ for (const plugin of container.plugins) {
1157
+ plugin.drawParticleTransform?.(drawData);
1158
+ }
1159
+ const effect = particle.effect ? effectDrawers.get(particle.effect) : undefined, shape = particle.shape ? shapeDrawers.get(particle.shape) : undefined;
1160
+ drawBeforeEffect(effect, drawData);
1161
+ drawShapeBeforeDraw(shape, drawData);
1162
+ drawShape(shape, drawData);
1163
+ drawShapeAfterDraw(shape, drawData);
1164
+ drawAfterEffect(effect, drawData);
1165
+ context.resetTransform();
1166
+ }
1167
+ function drawAfterEffect(drawer, data) {
1168
+ if (!drawer?.drawAfter) {
1169
+ return;
1170
+ }
1171
+ const { particle } = data;
1172
+ if (!particle.effect) {
1173
+ return;
1174
+ }
1175
+ drawer.drawAfter(data);
1176
+ }
1177
+ function drawBeforeEffect(drawer, data) {
1178
+ if (!drawer?.drawBefore) {
1179
+ return;
1180
+ }
1181
+ const { particle } = data;
1182
+ if (!particle.effect) {
1183
+ return;
1184
+ }
1185
+ drawer.drawBefore(data);
1186
+ }
1187
+ function drawShape(drawer, data) {
1188
+ if (!drawer) {
1189
+ return;
1190
+ }
1191
+ const { context, fill, particle, stroke } = data;
1192
+ if (!particle.shape) {
1193
+ return;
1194
+ }
1195
+ context.beginPath();
1196
+ drawer.draw(data);
1197
+ if (particle.shapeClose) {
1198
+ context.closePath();
1199
+ }
1200
+ if (fill) {
1201
+ context.fill();
1202
+ }
1203
+ if (stroke) {
1204
+ context.stroke();
1205
+ }
1206
+ }
1207
+ function drawShapeAfterDraw(drawer, data) {
1208
+ if (!drawer?.afterDraw) {
1209
+ return;
1210
+ }
1211
+ const { particle } = data;
1212
+ if (!particle.shape) {
1213
+ return;
1214
+ }
1215
+ drawer.afterDraw(data);
1216
+ }
1217
+ function drawShapeBeforeDraw(drawer, data) {
1218
+ if (!drawer?.beforeDraw) {
1219
+ return;
1220
+ }
1221
+ const { particle } = data;
1222
+ if (!particle.shape) {
1223
+ return;
1224
+ }
1225
+ drawer.beforeDraw(data);
1226
+ }
1227
+ function drawParticlePlugin(context, plugin, particle, delta) {
1228
+ if (!plugin.drawParticle) {
1229
+ return;
1230
+ }
1231
+ plugin.drawParticle(context, particle, delta);
1232
+ }
1233
+
1234
+ const styleCache = new Map(), maxCacheSize = 1000, firstIndex = 0, rgbFixedPrecision = 2, hslFixedPrecision = 2;
1235
+ function getCachedStyle(key, generator) {
1236
+ let cached = styleCache.get(key);
1237
+ if (!cached) {
1238
+ cached = generator();
1239
+ if (styleCache.size >= maxCacheSize) {
1240
+ const keysToDelete = [...styleCache.keys()].slice(firstIndex, maxCacheSize * index.half);
1241
+ keysToDelete.forEach(k => styleCache.delete(k));
1242
+ }
1243
+ styleCache.set(key, cached);
1244
+ }
1245
+ return cached;
1246
+ }
1247
+ function stringToRgba(pluginManager, input) {
1248
+ if (!input) {
1249
+ return;
1250
+ }
1251
+ for (const manager of pluginManager.colorManagers.values()) {
1252
+ if (manager.accepts(input)) {
1253
+ return manager.parseString(input);
1254
+ }
1255
+ }
1256
+ return undefined;
1257
+ }
1258
+ function rangeColorToRgb(pluginManager, input, index$1, useIndex = true) {
1259
+ if (!input) {
1260
+ return;
1261
+ }
1262
+ const color = index.isString(input) ? { value: input } : input;
1263
+ if (index.isString(color.value)) {
1264
+ return colorToRgb(pluginManager, color.value, index$1, useIndex);
1265
+ }
1266
+ if (index.isArray(color.value)) {
1267
+ const value = index.itemFromArray(color.value, index$1, useIndex);
1268
+ if (!value) {
1269
+ return;
1270
+ }
1271
+ return rangeColorToRgb(pluginManager, {
1272
+ value,
1273
+ });
1274
+ }
1275
+ for (const manager of pluginManager.colorManagers.values()) {
1276
+ const res = manager.handleRangeColor(color);
1277
+ if (res) {
1278
+ return res;
1279
+ }
1280
+ }
1281
+ return undefined;
1282
+ }
1283
+ function colorToRgb(pluginManager, input, index$1, useIndex = true) {
1284
+ if (!input) {
1285
+ return;
1286
+ }
1287
+ const color = index.isString(input) ? { value: input } : input;
1288
+ if (index.isString(color.value)) {
1289
+ return color.value === index.randomColorValue ? getRandomRgbColor() : stringToRgb(pluginManager, color.value);
1290
+ }
1291
+ if (index.isArray(color.value)) {
1292
+ const value = index.itemFromArray(color.value, index$1, useIndex);
1293
+ if (!value) {
1294
+ return;
1295
+ }
1296
+ return colorToRgb(pluginManager, {
1297
+ value,
1298
+ });
1299
+ }
1300
+ for (const manager of pluginManager.colorManagers.values()) {
1301
+ const res = manager.handleColor(color);
1302
+ if (res) {
1303
+ return res;
1304
+ }
1305
+ }
1306
+ return undefined;
1307
+ }
1308
+ function rangeColorToHsl(pluginManager, color, index, useIndex = true) {
1309
+ const rgb = rangeColorToRgb(pluginManager, color, index, useIndex);
1310
+ return rgb ? rgbToHsl(rgb) : undefined;
1311
+ }
1312
+ function rgbToHsl(color) {
1313
+ const r1 = color.r / index.rgbMax, g1 = color.g / index.rgbMax, b1 = color.b / index.rgbMax, max = Math.max(r1, g1, b1), min = Math.min(r1, g1, b1), res = {
1314
+ h: index.hMin,
1315
+ l: (max + min) * index.half,
1316
+ s: index.sMin,
1317
+ };
1318
+ if (max !== min) {
1319
+ res.s = res.l < index.half ? (max - min) / (max + min) : (max - min) / (index.double - max - min);
1320
+ if (r1 === max) {
1321
+ res.h = (g1 - b1) / (max - min);
1322
+ }
1323
+ else if (g1 === max) {
1324
+ res.h = index.double + (b1 - r1) / (max - min);
1325
+ }
1326
+ else {
1327
+ res.h = index.double * index.double + (r1 - g1) / (max - min);
1328
+ }
1329
+ }
1330
+ res.l *= index.lMax;
1331
+ res.s *= index.sMax;
1332
+ res.h *= index.hPhase;
1333
+ if (res.h < index.hMin) {
1334
+ res.h += index.hMax;
1335
+ }
1336
+ if (res.h >= index.hMax) {
1337
+ res.h -= index.hMax;
1338
+ }
1339
+ return res;
1340
+ }
1341
+ function stringToRgb(pluginManager, input) {
1342
+ return stringToRgba(pluginManager, input);
1343
+ }
1344
+ function hslToRgb(hsl) {
1345
+ const h = ((hsl.h % index.hMax) + index.hMax) % index.hMax, s = Math.max(index.sMin, Math.min(index.sMax, hsl.s)), l = Math.max(index.lMin, Math.min(index.lMax, hsl.l)), hNormalized = h / index.hMax, sNormalized = s / index.sMax, lNormalized = l / index.lMax;
1346
+ if (s === index.sMin) {
1347
+ const grayscaleValue = Math.round(lNormalized * index.rgbMax);
1348
+ return { r: grayscaleValue, g: grayscaleValue, b: grayscaleValue };
1349
+ }
1350
+ const channel = (temp1, temp2, temp3) => {
1351
+ const temp3Min = 0, temp3Max = 1;
1352
+ if (temp3 < temp3Min) {
1353
+ temp3++;
1354
+ }
1355
+ if (temp3 > temp3Max) {
1356
+ temp3--;
1357
+ }
1358
+ if (temp3 * index.sextuple < temp3Max) {
1359
+ return temp1 + (temp2 - temp1) * index.sextuple * temp3;
1360
+ }
1361
+ if (temp3 * index.double < temp3Max) {
1362
+ return temp2;
1363
+ }
1364
+ if (temp3 * index.triple < temp3Max * index.double) {
1365
+ const temp3Offset = index.double / index.triple;
1366
+ return temp1 + (temp2 - temp1) * (temp3Offset - temp3) * index.sextuple;
1367
+ }
1368
+ return temp1;
1369
+ }, temp1 = lNormalized < index.half
1370
+ ? lNormalized * (index.sNormalizedOffset + sNormalized)
1371
+ : lNormalized + sNormalized - lNormalized * sNormalized, temp2 = index.double * lNormalized - temp1, phaseThird = index.phaseNumerator / index.triple, red = Math.min(index.rgbMax, index.rgbMax * channel(temp2, temp1, hNormalized + phaseThird)), green = Math.min(index.rgbMax, index.rgbMax * channel(temp2, temp1, hNormalized)), blue = Math.min(index.rgbMax, index.rgbMax * channel(temp2, temp1, hNormalized - phaseThird));
1372
+ return { r: Math.round(red), g: Math.round(green), b: Math.round(blue) };
1373
+ }
1374
+ function getRandomRgbColor(min) {
1375
+ const fixedMin = index.defaultRgbMin, fixedMax = index.rgbMax + index.identity, getRgbInRangeValue = () => Math.floor(index.getRandomInRange(fixedMin, fixedMax));
1376
+ return {
1377
+ b: getRgbInRangeValue(),
1378
+ g: getRgbInRangeValue(),
1379
+ r: getRgbInRangeValue(),
1380
+ };
1381
+ }
1382
+ function getStyleFromRgb(color, hdr, opacity) {
1383
+ const op = opacity ?? index.defaultOpacity, key = `rgb-${color.r.toFixed(rgbFixedPrecision)}-${color.g.toFixed(rgbFixedPrecision)}-${color.b.toFixed(rgbFixedPrecision)}-${hdr ? "hdr" : "sdr"}-${op.toString()}`;
1384
+ return getCachedStyle(key, () => (hdr ? getHdrStyleFromRgb(color, opacity) : getSdrStyleFromRgb(color, opacity)));
1385
+ }
1386
+ function getHdrStyleFromRgb(color, opacity) {
1387
+ return `color(display-p3 ${(color.r / index.rgbMax).toString()} ${(color.g / index.rgbMax).toString()} ${(color.b / index.rgbMax).toString()} / ${(opacity ?? index.defaultOpacity).toString()})`;
1388
+ }
1389
+ function getSdrStyleFromRgb(color, opacity) {
1390
+ return `rgba(${color.r.toString()}, ${color.g.toString()}, ${color.b.toString()}, ${(opacity ?? index.defaultOpacity).toString()})`;
1391
+ }
1392
+ function getStyleFromHsl(color, hdr, opacity) {
1393
+ const op = opacity ?? index.defaultOpacity, key = `hsl-${color.h.toFixed(hslFixedPrecision)}-${color.s.toFixed(hslFixedPrecision)}-${color.l.toFixed(hslFixedPrecision)}-${hdr ? "hdr" : "sdr"}-${op.toString()}`;
1394
+ return getCachedStyle(key, () => (hdr ? getHdrStyleFromHsl(color, opacity) : getSdrStyleFromHsl(color, opacity)));
1395
+ }
1396
+ function getHdrStyleFromHsl(color, opacity) {
1397
+ return getHdrStyleFromRgb(hslToRgb(color), opacity);
1398
+ }
1399
+ function getSdrStyleFromHsl(color, opacity) {
1400
+ return `hsla(${color.h.toString()}, ${color.s.toString()}%, ${color.l.toString()}%, ${(opacity ?? index.defaultOpacity).toString()})`;
1401
+ }
1402
+ function getHslFromAnimation(animation) {
1403
+ return animation === undefined
1404
+ ? undefined
1405
+ : {
1406
+ h: animation.h.value,
1407
+ s: animation.s.value,
1408
+ l: animation.l.value,
1409
+ };
1410
+ }
1411
+ function alterHsl(color, type, value) {
1412
+ return {
1413
+ h: color.h,
1414
+ s: color.s,
1415
+ l: color.l + (type === index.AlterType.darken ? -index.lFactor : index.lFactor) * value,
1416
+ };
1417
+ }
1418
+
1419
+ const fColorIndex = 0, sColorIndex = 1;
1420
+ function setTransformValue(factor, newFactor, key) {
1421
+ const newValue = newFactor[key];
1422
+ if (newValue !== undefined) {
1423
+ factor[key] = (factor[key] ?? index.defaultTransformValue) * newValue;
1424
+ }
1425
+ }
1426
+ class RenderManager {
1427
+ #canvasClearPlugins;
1428
+ #canvasManager;
1429
+ #canvasPaintPlugins;
1430
+ #clearDrawPlugins;
1431
+ #colorPlugins;
1432
+ #container;
1433
+ #context;
1434
+ #contextSettings;
1435
+ #drawParticlePlugins;
1436
+ #drawParticlesCleanupPlugins;
1437
+ #drawParticlesSetupPlugins;
1438
+ #drawPlugins;
1439
+ #drawSettingsCleanupPlugins;
1440
+ #drawSettingsSetupPlugins;
1441
+ #pluginManager;
1442
+ #postDrawUpdaters;
1443
+ #preDrawUpdaters;
1444
+ #reusableColorStyles = {};
1445
+ #reusablePluginColors = [undefined, undefined];
1446
+ #reusableTransform = {};
1447
+ constructor(pluginManager, container, canvasManager) {
1448
+ this.#pluginManager = pluginManager;
1449
+ this.#container = container;
1450
+ this.#canvasManager = canvasManager;
1451
+ this.#context = null;
1452
+ this.#preDrawUpdaters = [];
1453
+ this.#postDrawUpdaters = [];
1454
+ this.#colorPlugins = [];
1455
+ this.#canvasClearPlugins = [];
1456
+ this.#canvasPaintPlugins = [];
1457
+ this.#clearDrawPlugins = [];
1458
+ this.#drawParticlePlugins = [];
1459
+ this.#drawParticlesCleanupPlugins = [];
1460
+ this.#drawParticlesSetupPlugins = [];
1461
+ this.#drawPlugins = [];
1462
+ this.#drawSettingsSetupPlugins = [];
1463
+ this.#drawSettingsCleanupPlugins = [];
1464
+ }
1465
+ get settings() {
1466
+ return this.#contextSettings;
1467
+ }
1468
+ canvasClear() {
1469
+ if (!this.#container.actualOptions.clear) {
1470
+ return;
1471
+ }
1472
+ this.draw(ctx => {
1473
+ clear(ctx, this.#canvasManager.size);
1474
+ });
1475
+ }
1476
+ clear() {
1477
+ let pluginHandled = false;
1478
+ for (const plugin of this.#canvasClearPlugins) {
1479
+ pluginHandled = plugin.canvasClear?.() ?? false;
1480
+ if (pluginHandled) {
1481
+ break;
1482
+ }
1483
+ }
1484
+ if (pluginHandled) {
1485
+ return;
1486
+ }
1487
+ this.canvasClear();
1488
+ }
1489
+ destroy() {
1490
+ this.stop();
1491
+ this.#preDrawUpdaters = [];
1492
+ this.#postDrawUpdaters = [];
1493
+ this.#colorPlugins = [];
1494
+ this.#canvasClearPlugins = [];
1495
+ this.#canvasPaintPlugins = [];
1496
+ this.#clearDrawPlugins = [];
1497
+ this.#drawParticlePlugins = [];
1498
+ this.#drawParticlesCleanupPlugins = [];
1499
+ this.#drawParticlesSetupPlugins = [];
1500
+ this.#drawPlugins = [];
1501
+ this.#drawSettingsSetupPlugins = [];
1502
+ this.#drawSettingsCleanupPlugins = [];
1503
+ }
1504
+ draw(cb) {
1505
+ const ctx = this.#context;
1506
+ if (!ctx) {
1507
+ return;
1508
+ }
1509
+ return cb(ctx);
1510
+ }
1511
+ drawParticle(particle, delta) {
1512
+ if (particle.spawning || particle.destroyed) {
1513
+ return;
1514
+ }
1515
+ const radius = particle.getRadius();
1516
+ if (radius <= index.minimumSize) {
1517
+ return;
1518
+ }
1519
+ const pfColor = particle.getFillColor(), psColor = particle.getStrokeColor();
1520
+ let [fColor, sColor] = this.#getPluginParticleColors(particle);
1521
+ fColor ??= pfColor;
1522
+ sColor ??= psColor;
1523
+ if (!fColor && !sColor) {
1524
+ return;
1525
+ }
1526
+ const container = this.#container, zIndexOptions = particle.options.zIndex, zIndexFactor = index.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;
1527
+ transform.a = transform.b = transform.c = transform.d = undefined;
1528
+ colorStyles.fill = fill;
1529
+ colorStyles.stroke = stroke;
1530
+ this.draw((context) => {
1531
+ for (const plugin of this.#drawParticlesSetupPlugins) {
1532
+ plugin.drawParticleSetup?.(context, particle, delta);
1533
+ }
1534
+ this.#applyPreDrawUpdaters(context, particle, radius, opacity, colorStyles, transform);
1535
+ drawParticle({
1536
+ container,
1537
+ context,
1538
+ particle,
1539
+ delta,
1540
+ colorStyles,
1541
+ radius: radius * zIndexFactor ** zIndexOptions.sizeRate,
1542
+ opacity: opacity,
1543
+ transform,
1544
+ });
1545
+ this.#applyPostDrawUpdaters(particle);
1546
+ for (const plugin of this.#drawParticlesCleanupPlugins) {
1547
+ plugin.drawParticleCleanup?.(context, particle, delta);
1548
+ }
1549
+ });
1550
+ }
1551
+ drawParticlePlugins(particle, delta) {
1552
+ this.draw(ctx => {
1553
+ for (const plugin of this.#drawParticlePlugins) {
1554
+ drawParticlePlugin(ctx, plugin, particle, delta);
1555
+ }
1556
+ });
1557
+ }
1558
+ drawParticles(delta) {
1559
+ const { particles } = this.#container;
1560
+ this.clear();
1561
+ particles.update(delta);
1562
+ this.draw(ctx => {
1563
+ for (const plugin of this.#drawSettingsSetupPlugins) {
1564
+ plugin.drawSettingsSetup?.(ctx, delta);
1565
+ }
1566
+ for (const plugin of this.#drawPlugins) {
1567
+ plugin.draw?.(ctx, delta);
1568
+ }
1569
+ particles.drawParticles(delta);
1570
+ for (const plugin of this.#clearDrawPlugins) {
1571
+ plugin.clearDraw?.(ctx, delta);
1572
+ }
1573
+ for (const plugin of this.#drawSettingsCleanupPlugins) {
1574
+ plugin.drawSettingsCleanup?.(ctx, delta);
1575
+ }
1576
+ });
1577
+ }
1578
+ init() {
1579
+ this.initUpdaters();
1580
+ this.initPlugins();
1581
+ this.paint();
1582
+ }
1583
+ initPlugins() {
1584
+ this.#colorPlugins = [];
1585
+ this.#canvasClearPlugins = [];
1586
+ this.#canvasPaintPlugins = [];
1587
+ this.#clearDrawPlugins = [];
1588
+ this.#drawParticlePlugins = [];
1589
+ this.#drawParticlesSetupPlugins = [];
1590
+ this.#drawParticlesCleanupPlugins = [];
1591
+ this.#drawPlugins = [];
1592
+ this.#drawSettingsSetupPlugins = [];
1593
+ this.#drawSettingsCleanupPlugins = [];
1594
+ for (const plugin of this.#container.plugins) {
1595
+ if (plugin.particleFillColor ?? plugin.particleStrokeColor) {
1596
+ this.#colorPlugins.push(plugin);
1597
+ }
1598
+ if (plugin.canvasClear) {
1599
+ this.#canvasClearPlugins.push(plugin);
1600
+ }
1601
+ if (plugin.canvasPaint) {
1602
+ this.#canvasPaintPlugins.push(plugin);
1603
+ }
1604
+ if (plugin.drawParticle) {
1605
+ this.#drawParticlePlugins.push(plugin);
1606
+ }
1607
+ if (plugin.drawParticleSetup) {
1608
+ this.#drawParticlesSetupPlugins.push(plugin);
1609
+ }
1610
+ if (plugin.drawParticleCleanup) {
1611
+ this.#drawParticlesCleanupPlugins.push(plugin);
1612
+ }
1613
+ if (plugin.draw) {
1614
+ this.#drawPlugins.push(plugin);
1615
+ }
1616
+ if (plugin.drawSettingsSetup) {
1617
+ this.#drawSettingsSetupPlugins.push(plugin);
1618
+ }
1619
+ if (plugin.drawSettingsCleanup) {
1620
+ this.#drawSettingsCleanupPlugins.push(plugin);
1621
+ }
1622
+ if (plugin.clearDraw) {
1623
+ this.#clearDrawPlugins.push(plugin);
1624
+ }
1625
+ }
1626
+ }
1627
+ initUpdaters() {
1628
+ this.#preDrawUpdaters = [];
1629
+ this.#postDrawUpdaters = [];
1630
+ for (const updater of this.#container.particleUpdaters) {
1631
+ if (updater.afterDraw) {
1632
+ this.#postDrawUpdaters.push(updater);
1633
+ }
1634
+ if (updater.getColorStyles ?? updater.getTransformValues ?? updater.beforeDraw) {
1635
+ this.#preDrawUpdaters.push(updater);
1636
+ }
1637
+ }
1638
+ }
1639
+ paint() {
1640
+ let handled = false;
1641
+ for (const plugin of this.#canvasPaintPlugins) {
1642
+ handled = plugin.canvasPaint?.() ?? false;
1643
+ if (handled) {
1644
+ break;
1645
+ }
1646
+ }
1647
+ if (handled) {
1648
+ return;
1649
+ }
1650
+ this.paintBase();
1651
+ }
1652
+ paintBase(baseColor) {
1653
+ this.draw(ctx => {
1654
+ paintBase(ctx, this.#canvasManager.size, baseColor);
1655
+ });
1656
+ }
1657
+ paintImage(image, opacity) {
1658
+ this.draw(ctx => {
1659
+ paintImage(ctx, this.#canvasManager.size, image, opacity);
1660
+ });
1661
+ }
1662
+ setContext(context) {
1663
+ this.#context = context;
1664
+ if (this.#context) {
1665
+ this.#context.globalCompositeOperation = index.defaultCompositeValue;
1666
+ }
1667
+ }
1668
+ setContextSettings(settings) {
1669
+ this.#contextSettings = settings;
1670
+ }
1671
+ stop() {
1672
+ this.draw(ctx => {
1673
+ clear(ctx, this.#canvasManager.size);
1674
+ });
1675
+ }
1676
+ #applyPostDrawUpdaters = particle => {
1677
+ for (const updater of this.#postDrawUpdaters) {
1678
+ updater.afterDraw?.(particle);
1679
+ }
1680
+ };
1681
+ #applyPreDrawUpdaters = (ctx, particle, radius, zOpacity, colorStyles, transform) => {
1682
+ for (const updater of this.#preDrawUpdaters) {
1683
+ if (updater.getColorStyles) {
1684
+ const { fill, stroke } = updater.getColorStyles(particle, ctx, radius, zOpacity);
1685
+ if (fill) {
1686
+ colorStyles.fill = fill;
1687
+ }
1688
+ if (stroke) {
1689
+ colorStyles.stroke = stroke;
1690
+ }
1691
+ }
1692
+ if (updater.getTransformValues) {
1693
+ const updaterTransform = updater.getTransformValues(particle);
1694
+ for (const key in updaterTransform) {
1695
+ setTransformValue(transform, updaterTransform, key);
1696
+ }
1697
+ }
1698
+ updater.beforeDraw?.(particle);
1699
+ }
1700
+ };
1701
+ #getPluginParticleColors = particle => {
1702
+ let fColor, sColor;
1703
+ for (const plugin of this.#colorPlugins) {
1704
+ if (!fColor && plugin.particleFillColor) {
1705
+ fColor = rangeColorToHsl(this.#pluginManager, plugin.particleFillColor(particle));
1706
+ }
1707
+ if (!sColor && plugin.particleStrokeColor) {
1708
+ sColor = rangeColorToHsl(this.#pluginManager, plugin.particleStrokeColor(particle));
1709
+ }
1710
+ if (fColor && sColor) {
1711
+ break;
1712
+ }
1713
+ }
1714
+ this.#reusablePluginColors[fColorIndex] = fColor;
1715
+ this.#reusablePluginColors[sColorIndex] = sColor;
1716
+ return this.#reusablePluginColors;
1717
+ };
1718
+ }
1719
+
1720
+ const transferredCanvases = new WeakMap(), getTransferredCanvas = (canvas) => {
1721
+ const transferredCanvas = transferredCanvases.get(canvas);
1722
+ if (transferredCanvas) {
1723
+ return transferredCanvas;
1724
+ }
1725
+ if (typeof canvas.transferControlToOffscreen !== "function") {
1726
+ throw new TypeError("OffscreenCanvas is required but not supported by this browser");
1727
+ }
1728
+ try {
1729
+ const offscreenCanvas = canvas.transferControlToOffscreen();
1730
+ transferredCanvases.set(canvas, offscreenCanvas);
1731
+ return offscreenCanvas;
1732
+ }
1733
+ catch {
1734
+ throw new TypeError("OffscreenCanvas transfer failed");
1735
+ }
1736
+ }, isHtmlCanvasElement = (canvas) => {
1737
+ return typeof HTMLCanvasElement !== "undefined" && canvas instanceof HTMLCanvasElement;
1738
+ };
1739
+ function setStyle(canvas, style, important = false) {
1740
+ if (!style) {
1741
+ return;
1742
+ }
1743
+ const element = canvas, elementStyle = element.style, keys = new Set();
1744
+ for (let i = 0; i < elementStyle.length; i++) {
1745
+ const key = elementStyle.item(i);
1746
+ if (!key) {
1747
+ continue;
1748
+ }
1749
+ keys.add(key);
1750
+ }
1751
+ for (let i = 0; i < style.length; i++) {
1752
+ const key = style.item(i);
1753
+ if (!key) {
1754
+ continue;
1755
+ }
1756
+ keys.add(key);
1757
+ }
1758
+ for (const key of keys) {
1759
+ const value = style.getPropertyValue(key);
1760
+ if (value) {
1761
+ elementStyle.setProperty(key, value, important ? "important" : "");
1762
+ }
1763
+ else {
1764
+ elementStyle.removeProperty(key);
1765
+ }
1766
+ }
1767
+ }
1768
+ class CanvasManager {
1769
+ domElement;
1770
+ render;
1771
+ renderCanvas;
1772
+ size;
1773
+ zoom = index.defaultZoom;
1774
+ #container;
1775
+ #generated;
1776
+ #mutationObserver;
1777
+ #originalStyle;
1778
+ #pluginManager;
1779
+ #pointerEvents;
1780
+ #resizePlugins;
1781
+ #standardSize;
1782
+ #zoomCenter;
1783
+ constructor(pluginManager, container) {
1784
+ this.#pluginManager = pluginManager;
1785
+ this.#container = container;
1786
+ this.render = new RenderManager(pluginManager, container, this);
1787
+ this.#standardSize = {
1788
+ height: 0,
1789
+ width: 0,
1790
+ };
1791
+ const pxRatio = container.retina.pixelRatio, stdSize = this.#standardSize;
1792
+ this.size = {
1793
+ height: stdSize.height * pxRatio,
1794
+ width: stdSize.width * pxRatio,
1795
+ };
1796
+ this.#generated = false;
1797
+ this.#resizePlugins = [];
1798
+ this.#pointerEvents = "none";
1799
+ }
1800
+ get #fullScreen() {
1801
+ return this.#container.actualOptions.fullScreen.enable;
1802
+ }
1803
+ destroy() {
1804
+ this.stop();
1805
+ if (this.#generated) {
1806
+ const element = this.domElement;
1807
+ element?.remove();
1808
+ this.domElement = undefined;
1809
+ this.renderCanvas = undefined;
1810
+ }
1811
+ else {
1812
+ this.#resetOriginalStyle();
1813
+ }
1814
+ this.render.destroy();
1815
+ this.#resizePlugins = [];
1816
+ }
1817
+ getZoomCenter() {
1818
+ const pxRatio = this.#container.retina.pixelRatio, { width, height } = this.size;
1819
+ if (this.#zoomCenter) {
1820
+ return this.#zoomCenter;
1821
+ }
1822
+ return {
1823
+ x: (width * index.half) / pxRatio,
1824
+ y: (height * index.half) / pxRatio,
1825
+ };
1826
+ }
1827
+ init() {
1828
+ this.#safeMutationObserver(obs => {
1829
+ obs.disconnect();
1830
+ });
1831
+ this.#mutationObserver = index.safeMutationObserver(records => {
1832
+ for (const record of records) {
1833
+ if (record.type === "attributes" && record.attributeName === "style") {
1834
+ this.#repairStyle();
1835
+ }
1836
+ }
1837
+ });
1838
+ this.resize();
1839
+ this.#initStyle();
1840
+ this.initBackground();
1841
+ this.#safeMutationObserver(obs => {
1842
+ const element = this.domElement;
1843
+ if (!element || !(element instanceof Node)) {
1844
+ return;
1845
+ }
1846
+ obs.observe(element, { attributes: true });
1847
+ });
1848
+ this.initPlugins();
1849
+ this.render.init();
1850
+ }
1851
+ initBackground() {
1852
+ const container = this.#container, options = container.actualOptions, background = options.background, element = this.domElement;
1853
+ if (!element) {
1854
+ return;
1855
+ }
1856
+ const elementStyle = element.style, color = rangeColorToRgb(this.#pluginManager, background.color);
1857
+ if (color) {
1858
+ elementStyle.backgroundColor = getStyleFromRgb(color, container.hdr, background.opacity);
1859
+ }
1860
+ else {
1861
+ elementStyle.backgroundColor = "";
1862
+ }
1863
+ elementStyle.backgroundImage = background.image || "";
1864
+ elementStyle.backgroundPosition = background.position || "";
1865
+ elementStyle.backgroundRepeat = background.repeat || "";
1866
+ elementStyle.backgroundSize = background.size || "";
1867
+ }
1868
+ initPlugins() {
1869
+ this.#resizePlugins = [];
1870
+ for (const plugin of this.#container.plugins) {
1871
+ if (plugin.resize) {
1872
+ this.#resizePlugins.push(plugin);
1873
+ }
1874
+ }
1875
+ }
1876
+ loadCanvas(canvas) {
1877
+ if (this.#generated && this.domElement) {
1878
+ this.domElement.remove();
1879
+ }
1880
+ const container = this.#container, domCanvas = isHtmlCanvasElement(canvas) ? canvas : undefined;
1881
+ this.domElement = domCanvas;
1882
+ this.#generated = domCanvas ? domCanvas.dataset[index.generatedAttribute] === "true" : false;
1883
+ this.renderCanvas = domCanvas ? getTransferredCanvas(domCanvas) : canvas;
1884
+ const domElement = this.domElement;
1885
+ if (domElement) {
1886
+ domElement.ariaHidden = "true";
1887
+ this.#originalStyle = index.cloneStyle(domElement.style);
1888
+ }
1889
+ const standardSize = this.#standardSize, renderCanvas = this.renderCanvas;
1890
+ if (domElement) {
1891
+ standardSize.height = domElement.offsetHeight;
1892
+ standardSize.width = domElement.offsetWidth;
1893
+ }
1894
+ else {
1895
+ standardSize.height = renderCanvas.height;
1896
+ standardSize.width = renderCanvas.width;
1897
+ }
1898
+ const pxRatio = this.#container.retina.pixelRatio, retinaSize = this.size;
1899
+ renderCanvas.height = retinaSize.height = standardSize.height * pxRatio;
1900
+ renderCanvas.width = retinaSize.width = standardSize.width * pxRatio;
1901
+ const canSupportHdrQuery = index.safeMatchMedia("(color-gamut: p3)");
1902
+ this.render.setContextSettings({
1903
+ alpha: true,
1904
+ colorSpace: canSupportHdrQuery?.matches && container.hdr ? "display-p3" : "srgb",
1905
+ desynchronized: true,
1906
+ willReadFrequently: false,
1907
+ });
1908
+ this.render.setContext(renderCanvas.getContext("2d", this.render.settings));
1909
+ this.#safeMutationObserver(obs => {
1910
+ obs.disconnect();
1911
+ });
1912
+ container.retina.init();
1913
+ this.initBackground();
1914
+ this.#safeMutationObserver(obs => {
1915
+ const element = this.domElement;
1916
+ if (!element || !(element instanceof Node)) {
1917
+ return;
1918
+ }
1919
+ obs.observe(element, { attributes: true });
1920
+ });
1921
+ }
1922
+ resize() {
1923
+ const element = this.domElement;
1924
+ if (!element) {
1925
+ return false;
1926
+ }
1927
+ const container = this.#container, renderCanvas = this.renderCanvas;
1928
+ if (renderCanvas === undefined) {
1929
+ return false;
1930
+ }
1931
+ const currentSize = container.canvas.#standardSize, newSize = {
1932
+ width: element.offsetWidth,
1933
+ height: element.offsetHeight,
1934
+ }, pxRatio = container.retina.pixelRatio, retinaSize = {
1935
+ width: newSize.width * pxRatio,
1936
+ height: newSize.height * pxRatio,
1937
+ };
1938
+ if (newSize.height === currentSize.height &&
1939
+ newSize.width === currentSize.width &&
1940
+ retinaSize.height === renderCanvas.height &&
1941
+ retinaSize.width === renderCanvas.width) {
1942
+ return false;
1943
+ }
1944
+ const oldSize = { ...currentSize };
1945
+ currentSize.height = newSize.height;
1946
+ currentSize.width = newSize.width;
1947
+ const canvasSize = this.size;
1948
+ renderCanvas.width = canvasSize.width = retinaSize.width;
1949
+ renderCanvas.height = canvasSize.height = retinaSize.height;
1950
+ if (this.#container.started) {
1951
+ container.particles.setResizeFactor({
1952
+ width: currentSize.width / oldSize.width,
1953
+ height: currentSize.height / oldSize.height,
1954
+ });
1955
+ }
1956
+ return true;
1957
+ }
1958
+ setPointerEvents(type) {
1959
+ const element = this.domElement;
1960
+ if (!element) {
1961
+ return;
1962
+ }
1963
+ this.#pointerEvents = type;
1964
+ this.#repairStyle();
1965
+ }
1966
+ setZoom(zoomLevel, center) {
1967
+ this.zoom = zoomLevel;
1968
+ this.#zoomCenter = center;
1969
+ }
1970
+ stop() {
1971
+ this.#safeMutationObserver(obs => {
1972
+ obs.disconnect();
1973
+ });
1974
+ this.#mutationObserver = undefined;
1975
+ this.render.stop();
1976
+ }
1977
+ async windowResize() {
1978
+ if (!this.domElement || !this.resize()) {
1979
+ return;
1980
+ }
1981
+ const container = this.#container, needsRefresh = container.updateActualOptions();
1982
+ container.particles.setDensity();
1983
+ this.#applyResizePlugins();
1984
+ if (needsRefresh) {
1985
+ await container.refresh();
1986
+ }
1987
+ }
1988
+ #applyResizePlugins = () => {
1989
+ for (const plugin of this.#resizePlugins) {
1990
+ plugin.resize?.();
1991
+ }
1992
+ };
1993
+ #initStyle = () => {
1994
+ const element = this.domElement, options = this.#container.actualOptions;
1995
+ if (!element) {
1996
+ return;
1997
+ }
1998
+ if (this.#fullScreen) {
1999
+ this.#setFullScreenStyle();
2000
+ }
2001
+ else {
2002
+ this.#resetOriginalStyle();
2003
+ }
2004
+ for (const key in options.style) {
2005
+ if (!key || !(key in options.style)) {
2006
+ continue;
2007
+ }
2008
+ const value = options.style[key];
2009
+ if (!value) {
2010
+ continue;
2011
+ }
2012
+ element.style.setProperty(key, value, "important");
2013
+ }
2014
+ };
2015
+ #repairStyle = () => {
2016
+ const element = this.domElement;
2017
+ if (!element) {
2018
+ return;
2019
+ }
2020
+ this.#safeMutationObserver(observer => {
2021
+ observer.disconnect();
2022
+ });
2023
+ this.#initStyle();
2024
+ this.initBackground();
2025
+ const pointerEvents = this.#pointerEvents;
2026
+ element.style.pointerEvents = pointerEvents;
2027
+ element.style.setProperty("pointer-events", pointerEvents);
2028
+ this.#safeMutationObserver(observer => {
2029
+ if (!(element instanceof Node)) {
2030
+ return;
2031
+ }
2032
+ observer.observe(element, { attributes: true });
2033
+ });
2034
+ };
2035
+ #resetOriginalStyle = () => {
2036
+ const element = this.domElement, originalStyle = this.#originalStyle;
2037
+ if (!element || !originalStyle) {
2038
+ return;
2039
+ }
2040
+ setStyle(element, originalStyle, true);
2041
+ };
2042
+ #safeMutationObserver = callback => {
2043
+ if (!this.#mutationObserver) {
2044
+ return;
2045
+ }
2046
+ callback(this.#mutationObserver);
2047
+ };
2048
+ #setFullScreenStyle = () => {
2049
+ const element = this.domElement;
2050
+ if (!element) {
2051
+ return;
2052
+ }
2053
+ setStyle(element, index.getFullScreenStyle(this.#container.actualOptions.fullScreen.zIndex), true);
2054
+ };
2055
+ }
2056
+
2057
+ class EventListeners {
2058
+ #container;
2059
+ #handlers;
2060
+ #resizeObserver;
2061
+ #resizeTimeout;
2062
+ constructor(container) {
2063
+ this.#container = container;
2064
+ this.#handlers = {
2065
+ visibilityChange: () => {
2066
+ this.#handleVisibilityChange();
2067
+ },
2068
+ resize: () => {
2069
+ this.#handleWindowResize();
2070
+ },
2071
+ };
2072
+ }
2073
+ addListeners() {
2074
+ this.#manageListeners(true);
2075
+ }
2076
+ removeListeners() {
2077
+ this.#manageListeners(false);
2078
+ }
2079
+ #handleVisibilityChange = () => {
2080
+ const container = this.#container, options = container.actualOptions;
2081
+ if (!options.pauseOnBlur) {
2082
+ return;
2083
+ }
2084
+ if (index.safeDocument().hidden) {
2085
+ container.pageHidden = true;
2086
+ container.pause();
2087
+ }
2088
+ else {
2089
+ container.pageHidden = false;
2090
+ if (container.animationStatus) {
2091
+ container.play(true);
2092
+ }
2093
+ else {
2094
+ container.draw(true);
2095
+ }
2096
+ }
2097
+ };
2098
+ #handleWindowResize = () => {
2099
+ if (this.#resizeTimeout) {
2100
+ clearTimeout(this.#resizeTimeout);
2101
+ this.#resizeTimeout = undefined;
2102
+ }
2103
+ const handleResize = async () => {
2104
+ const canvas = this.#container.canvas;
2105
+ await canvas.windowResize();
2106
+ };
2107
+ this.#resizeTimeout = setTimeout(() => void handleResize(), this.#container.actualOptions.resize.delay * index.millisecondsToSeconds);
2108
+ };
2109
+ #manageListeners = add => {
2110
+ const handlers = this.#handlers;
2111
+ this.#manageResize(add);
2112
+ index.manageListener(document, index.visibilityChangeEvent, handlers.visibilityChange, add, false);
2113
+ };
2114
+ #manageResize = add => {
2115
+ const handlers = this.#handlers, container = this.#container, options = container.actualOptions;
2116
+ if (!options.resize.enable) {
2117
+ return;
2118
+ }
2119
+ if (typeof ResizeObserver === "undefined") {
2120
+ index.manageListener(globalThis, index.resizeEvent, handlers.resize, add);
2121
+ return;
2122
+ }
2123
+ const canvasEl = container.canvas.domElement;
2124
+ if (this.#resizeObserver && !add) {
2125
+ if (canvasEl) {
2126
+ this.#resizeObserver.unobserve(canvasEl);
2127
+ }
2128
+ this.#resizeObserver.disconnect();
2129
+ this.#resizeObserver = undefined;
2130
+ }
2131
+ else if (!this.#resizeObserver && add && canvasEl) {
2132
+ this.#resizeObserver = new ResizeObserver((entries) => {
2133
+ const entry = entries.find(e => e.target === canvasEl);
2134
+ if (!entry) {
2135
+ return;
2136
+ }
2137
+ this.#handleWindowResize();
2138
+ });
2139
+ this.#resizeObserver.observe(canvasEl);
2140
+ }
2141
+ };
2142
+ }
2143
+
2144
+ function loadEffectData(effect, effectOptions, id, reduceDuplicates) {
2145
+ const effectData = effectOptions.options[effect];
2146
+ return index.deepExtend({
2147
+ close: effectOptions.close,
2148
+ }, index.itemFromSingleOrMultiple(effectData, id, reduceDuplicates));
2149
+ }
2150
+ function loadShapeData(shape, shapeOptions, id, reduceDuplicates) {
2151
+ const shapeData = shapeOptions.options[shape];
2152
+ return index.deepExtend({
2153
+ close: shapeOptions.close,
2154
+ }, index.itemFromSingleOrMultiple(shapeData, id, reduceDuplicates));
2155
+ }
2156
+ function fixOutMode(data) {
2157
+ if (!index.isInArray(data.outMode, data.checkModes)) {
2158
+ return;
2159
+ }
2160
+ const diameter = data.radius * index.double;
2161
+ if (data.coord > data.maxCoord - diameter) {
2162
+ data.setCb(-data.radius);
2163
+ }
2164
+ else if (data.coord < diameter) {
2165
+ data.setCb(data.radius);
2166
+ }
2167
+ }
2168
+ class Particle {
2169
+ backColor;
2170
+ bubble;
2171
+ destroyed;
2172
+ direction;
2173
+ effect;
2174
+ effectClose;
2175
+ effectData;
2176
+ fillColor;
2177
+ fillEnabled;
2178
+ fillOpacity;
2179
+ group;
2180
+ id;
2181
+ ignoresResizeRatio;
2182
+ initialPosition;
2183
+ initialVelocity;
2184
+ isRotating;
2185
+ justWarped;
2186
+ lastPathTime;
2187
+ misplaced;
2188
+ moveCenter;
2189
+ offset;
2190
+ opacity;
2191
+ options;
2192
+ outType;
2193
+ pathRotation;
2194
+ position;
2195
+ randomIndexData;
2196
+ retina;
2197
+ roll;
2198
+ rotation;
2199
+ shape;
2200
+ shapeClose;
2201
+ shapeData;
2202
+ sides;
2203
+ size;
2204
+ slow;
2205
+ spawning;
2206
+ strokeColor;
2207
+ strokeOpacity;
2208
+ strokeWidth;
2209
+ unbreakable;
2210
+ velocity;
2211
+ zIndexFactor;
2212
+ #cachedOpacityData = {
2213
+ fillOpacity: index.defaultOpacity,
2214
+ opacity: index.defaultOpacity,
2215
+ strokeOpacity: index.defaultOpacity,
2216
+ };
2217
+ #cachedPosition = index.Vector3d.origin;
2218
+ #cachedRotateData = { sin: 0, cos: 0 };
2219
+ #cachedTransform = {
2220
+ a: 1,
2221
+ b: 0,
2222
+ c: 0,
2223
+ d: 1,
2224
+ };
2225
+ #container;
2226
+ #pluginManager;
2227
+ constructor(pluginManager, container) {
2228
+ this.#pluginManager = pluginManager;
2229
+ this.#container = container;
2230
+ }
2231
+ destroy(override) {
2232
+ if (this.unbreakable || this.destroyed) {
2233
+ return;
2234
+ }
2235
+ this.destroyed = true;
2236
+ this.bubble.inRange = false;
2237
+ this.slow.inRange = false;
2238
+ const container = this.#container, shapeDrawer = this.shape ? container.shapeDrawers.get(this.shape) : undefined;
2239
+ shapeDrawer?.particleDestroy?.(this);
2240
+ for (const plugin of container.particleDestroyedPlugins) {
2241
+ plugin.particleDestroyed?.(this, override);
2242
+ }
2243
+ for (const updater of container.particleUpdaters) {
2244
+ updater.particleDestroyed?.(this, override);
2245
+ }
2246
+ this.#container.dispatchEvent(index.EventType.particleDestroyed, {
2247
+ particle: this,
2248
+ });
2249
+ }
2250
+ draw(delta) {
2251
+ const container = this.#container, render = container.canvas.render;
2252
+ render.drawParticlePlugins(this, delta);
2253
+ render.drawParticle(this, delta);
2254
+ }
2255
+ getAngle() {
2256
+ return this.rotation + (this.pathRotation ? this.velocity.angle : index.defaultAngle);
2257
+ }
2258
+ getFillColor() {
2259
+ return this.#getRollColor(this.bubble.color ?? getHslFromAnimation(this.fillColor));
2260
+ }
2261
+ getMass() {
2262
+ return this.getRadius() ** index.squareExp * Math.PI * index.half;
2263
+ }
2264
+ getOpacity() {
2265
+ const zIndexOptions = this.options.zIndex, zIndexFactor = index.zIndexFactorOffset - this.zIndexFactor, zOpacityFactor = zIndexFactor ** zIndexOptions.opacityRate, opacity = this.bubble.opacity ?? index.getRangeValue(this.opacity?.value ?? index.defaultOpacity), fillOpacity = this.fillOpacity ?? index.defaultOpacity, strokeOpacity = this.strokeOpacity ?? index.defaultOpacity;
2266
+ this.#cachedOpacityData.fillOpacity = opacity * fillOpacity * zOpacityFactor;
2267
+ this.#cachedOpacityData.opacity = opacity * zOpacityFactor;
2268
+ this.#cachedOpacityData.strokeOpacity = opacity * strokeOpacity * zOpacityFactor;
2269
+ return this.#cachedOpacityData;
2270
+ }
2271
+ getPosition() {
2272
+ this.#cachedPosition.x = this.position.x + this.offset.x;
2273
+ this.#cachedPosition.y = this.position.y + this.offset.y;
2274
+ this.#cachedPosition.z = this.position.z;
2275
+ return this.#cachedPosition;
2276
+ }
2277
+ getRadius() {
2278
+ return this.bubble.radius ?? this.size.value;
2279
+ }
2280
+ getRotateData() {
2281
+ const angle = this.getAngle();
2282
+ this.#cachedRotateData.sin = Math.sin(angle);
2283
+ this.#cachedRotateData.cos = Math.cos(angle);
2284
+ return this.#cachedRotateData;
2285
+ }
2286
+ getStrokeColor() {
2287
+ return this.#getRollColor(this.bubble.color ?? getHslFromAnimation(this.strokeColor));
2288
+ }
2289
+ getTransformData(externalTransform) {
2290
+ const rotateData = this.getRotateData(), rotating = this.isRotating;
2291
+ this.#cachedTransform.a = rotateData.cos * (externalTransform.a ?? index.defaultTransform.a);
2292
+ this.#cachedTransform.b = rotating
2293
+ ? rotateData.sin * (externalTransform.b ?? index.identity)
2294
+ : (externalTransform.b ?? index.defaultTransform.b);
2295
+ this.#cachedTransform.c = rotating
2296
+ ? -rotateData.sin * (externalTransform.c ?? index.identity)
2297
+ : (externalTransform.c ?? index.defaultTransform.c);
2298
+ this.#cachedTransform.d = rotateData.cos * (externalTransform.d ?? index.defaultTransform.d);
2299
+ return this.#cachedTransform;
2300
+ }
2301
+ init(id, position, overrideOptions, group) {
2302
+ const container = this.#container;
2303
+ this.id = id;
2304
+ this.group = group;
2305
+ this.justWarped = false;
2306
+ this.effectClose = true;
2307
+ this.shapeClose = true;
2308
+ this.pathRotation = false;
2309
+ this.lastPathTime = 0;
2310
+ this.destroyed = false;
2311
+ this.unbreakable = false;
2312
+ this.isRotating = false;
2313
+ this.rotation = 0;
2314
+ this.misplaced = false;
2315
+ this.retina = {
2316
+ maxDistance: {},
2317
+ maxSpeed: 0,
2318
+ moveDrift: 0,
2319
+ moveSpeed: 0,
2320
+ sizeAnimationSpeed: 0,
2321
+ };
2322
+ this.size = {
2323
+ value: 1,
2324
+ max: 1,
2325
+ min: 1,
2326
+ enable: false,
2327
+ };
2328
+ this.outType = index.ParticleOutType.normal;
2329
+ this.ignoresResizeRatio = true;
2330
+ const mainOptions = container.actualOptions, particlesOptions = loadParticlesOptions(this.#pluginManager, container, mainOptions.particles), reduceDuplicates = particlesOptions.reduceDuplicates, effectType = particlesOptions.effect.type, shapeType = particlesOptions.shape.type;
2331
+ this.effect = index.itemFromSingleOrMultiple(effectType, this.id, reduceDuplicates);
2332
+ this.shape = index.itemFromSingleOrMultiple(shapeType, this.id, reduceDuplicates);
2333
+ const effectOptions = particlesOptions.effect, shapeOptions = particlesOptions.shape;
2334
+ if (overrideOptions) {
2335
+ if (overrideOptions.effect?.type && overrideOptions.effect.type !== this.effect) {
2336
+ const overrideEffectType = overrideOptions.effect.type, effect = index.itemFromSingleOrMultiple(overrideEffectType, this.id, reduceDuplicates);
2337
+ if (effect) {
2338
+ this.effect = effect;
2339
+ effectOptions.load(overrideOptions.effect);
2340
+ }
2341
+ }
2342
+ if (overrideOptions.shape?.type && overrideOptions.shape.type !== this.shape) {
2343
+ const overrideShapeType = overrideOptions.shape.type, shape = index.itemFromSingleOrMultiple(overrideShapeType, this.id, reduceDuplicates);
2344
+ if (shape) {
2345
+ this.shape = shape;
2346
+ shapeOptions.load(overrideOptions.shape);
2347
+ }
2348
+ }
2349
+ }
2350
+ if (this.effect === index.randomColorValue) {
2351
+ const availableEffects = [...this.#container.effectDrawers.keys()];
2352
+ this.effect = availableEffects[Math.floor(index.getRandom() * availableEffects.length)];
2353
+ }
2354
+ if (this.shape === index.randomColorValue) {
2355
+ const availableShapes = [...this.#container.shapeDrawers.keys()];
2356
+ this.shape = availableShapes[Math.floor(index.getRandom() * availableShapes.length)];
2357
+ }
2358
+ this.effectData = this.effect ? loadEffectData(this.effect, effectOptions, this.id, reduceDuplicates) : undefined;
2359
+ this.shapeData = this.shape ? loadShapeData(this.shape, shapeOptions, this.id, reduceDuplicates) : undefined;
2360
+ particlesOptions.load(overrideOptions);
2361
+ const effectData = this.effectData, shapeData = this.shapeData;
2362
+ if (effectData) {
2363
+ particlesOptions.load(effectData.particles);
2364
+ }
2365
+ if (shapeData) {
2366
+ particlesOptions.load(shapeData.particles);
2367
+ }
2368
+ this.effectClose = effectData?.close ?? particlesOptions.effect.close;
2369
+ this.shapeClose = shapeData?.close ?? particlesOptions.shape.close;
2370
+ this.options = particlesOptions;
2371
+ container.retina.initParticle(this);
2372
+ for (const updater of container.particleUpdaters) {
2373
+ updater.preInit?.(this);
2374
+ }
2375
+ this.bubble = {
2376
+ inRange: false,
2377
+ };
2378
+ this.slow = {
2379
+ inRange: false,
2380
+ factor: 1,
2381
+ };
2382
+ this.#initPosition(position);
2383
+ this.initialVelocity = this.#calculateVelocity();
2384
+ this.velocity = this.initialVelocity.copy();
2385
+ this.zIndexFactor = this.position.z / container.zLayers;
2386
+ this.sides = 24;
2387
+ let effectDrawer, shapeDrawer;
2388
+ if (this.effect) {
2389
+ effectDrawer = container.effectDrawers.get(this.effect);
2390
+ }
2391
+ if (effectDrawer?.loadEffect) {
2392
+ effectDrawer.loadEffect(this);
2393
+ }
2394
+ if (this.shape) {
2395
+ shapeDrawer = container.shapeDrawers.get(this.shape);
2396
+ }
2397
+ if (shapeDrawer?.loadShape) {
2398
+ shapeDrawer.loadShape(this);
2399
+ }
2400
+ const sideCountFunc = shapeDrawer?.getSidesCount;
2401
+ if (sideCountFunc) {
2402
+ this.sides = sideCountFunc(this);
2403
+ }
2404
+ this.spawning = false;
2405
+ for (const updater of container.particleUpdaters) {
2406
+ updater.init(this);
2407
+ }
2408
+ effectDrawer?.particleInit?.(container, this);
2409
+ shapeDrawer?.particleInit?.(container, this);
2410
+ for (const plugin of container.particleCreatedPlugins) {
2411
+ plugin.particleCreated?.(this);
2412
+ }
2413
+ }
2414
+ isInsideCanvas(direction) {
2415
+ return this.#getInsideCanvasResult({ direction }).inside;
2416
+ }
2417
+ isInsideCanvasForOutMode(outMode, direction) {
2418
+ return this.#getInsideCanvasResult({ direction, outMode }).inside;
2419
+ }
2420
+ isShowingBack() {
2421
+ if (!this.roll) {
2422
+ return false;
2423
+ }
2424
+ const angle = this.roll.angle;
2425
+ if (this.roll.horizontal && this.roll.vertical) {
2426
+ const normalizedAngle = angle % index.doublePI, adjustedAngle = normalizedAngle < index.defaultAngle ? normalizedAngle + index.doublePI : normalizedAngle;
2427
+ return adjustedAngle >= Math.PI * index.half && adjustedAngle < Math.PI * index.triple * index.half;
2428
+ }
2429
+ if (this.roll.horizontal) {
2430
+ const normalizedAngle = (angle + Math.PI * index.half) % (Math.PI * index.double), adjustedAngle = normalizedAngle < index.defaultAngle ? normalizedAngle + Math.PI * index.double : normalizedAngle;
2431
+ return adjustedAngle >= Math.PI && adjustedAngle < Math.PI * index.double;
2432
+ }
2433
+ if (this.roll.vertical) {
2434
+ const normalizedAngle = angle % (Math.PI * index.double), adjustedAngle = normalizedAngle < index.defaultAngle ? normalizedAngle + Math.PI * index.double : normalizedAngle;
2435
+ return adjustedAngle >= Math.PI && adjustedAngle < Math.PI * index.double;
2436
+ }
2437
+ return false;
2438
+ }
2439
+ isVisible() {
2440
+ return !this.destroyed && !this.spawning && this.isInsideCanvas();
2441
+ }
2442
+ reset() {
2443
+ for (const updater of this.#container.particleUpdaters) {
2444
+ updater.reset?.(this);
2445
+ }
2446
+ }
2447
+ #calcPosition = (position, zIndex) => {
2448
+ let tryCount = index.defaultRetryCount, posVec = position ? index.Vector3d.create(position.x, position.y, zIndex) : undefined;
2449
+ const container = this.#container, plugins = container.particlePositionPlugins, outModes = this.options.move.outModes, radius = this.getRadius(), canvasSize = container.canvas.size, abortController = new AbortController(), { signal } = abortController;
2450
+ while (!signal.aborted) {
2451
+ for (const plugin of plugins) {
2452
+ const pluginPos = plugin.particlePosition?.(posVec, this);
2453
+ if (pluginPos) {
2454
+ return index.Vector3d.create(pluginPos.x, pluginPos.y, zIndex);
2455
+ }
2456
+ }
2457
+ const exactPosition = index.calcExactPositionOrRandomFromSize({
2458
+ size: canvasSize,
2459
+ position: posVec,
2460
+ }), pos = index.Vector3d.create(exactPosition.x, exactPosition.y, zIndex);
2461
+ this.#fixHorizontal(pos, radius, outModes.left ?? outModes.default);
2462
+ this.#fixHorizontal(pos, radius, outModes.right ?? outModes.default);
2463
+ this.#fixVertical(pos, radius, outModes.top ?? outModes.default);
2464
+ this.#fixVertical(pos, radius, outModes.bottom ?? outModes.default);
2465
+ let isValidPosition = true;
2466
+ for (const plugin of container.particles.checkParticlePositionPlugins) {
2467
+ isValidPosition = plugin.checkParticlePosition?.(this, pos, tryCount) ?? true;
2468
+ if (!isValidPosition) {
2469
+ break;
2470
+ }
2471
+ }
2472
+ if (isValidPosition) {
2473
+ return pos;
2474
+ }
2475
+ tryCount += index.tryCountIncrement;
2476
+ posVec = undefined;
2477
+ }
2478
+ return posVec;
2479
+ };
2480
+ #calculateVelocity = () => {
2481
+ const moveOptions = this.options.move, baseVelocity = index.getParticleBaseVelocity(this.direction), res = baseVelocity.copy();
2482
+ if (moveOptions.direction === index.MoveDirection.inside || moveOptions.direction === index.MoveDirection.outside) {
2483
+ return res;
2484
+ }
2485
+ const rad = index.degToRad(index.getRangeValue(moveOptions.angle.value)), radOffset = index.degToRad(index.getRangeValue(moveOptions.angle.offset)), range = {
2486
+ left: radOffset - rad * index.half,
2487
+ right: radOffset + rad * index.half,
2488
+ };
2489
+ if (!moveOptions.straight) {
2490
+ res.angle += index.randomInRangeValue(index.setRangeValue(range.left, range.right));
2491
+ }
2492
+ if (moveOptions.random && typeof moveOptions.speed === "number") {
2493
+ res.length *= index.getRandom();
2494
+ }
2495
+ return res;
2496
+ };
2497
+ #fixHorizontal = (pos, radius, outMode) => {
2498
+ fixOutMode({
2499
+ outMode,
2500
+ checkModes: [index.OutMode.bounce],
2501
+ coord: pos.x,
2502
+ maxCoord: this.#container.canvas.size.width,
2503
+ setCb: (value) => (pos.x += value),
2504
+ radius,
2505
+ });
2506
+ };
2507
+ #fixVertical = (pos, radius, outMode) => {
2508
+ fixOutMode({
2509
+ outMode,
2510
+ checkModes: [index.OutMode.bounce],
2511
+ coord: pos.y,
2512
+ maxCoord: this.#container.canvas.size.height,
2513
+ setCb: (value) => (pos.y += value),
2514
+ radius,
2515
+ });
2516
+ };
2517
+ #getDefaultInsideCanvasResult = (direction, outMode) => {
2518
+ const radius = this.getRadius(), canvasSize = this.#container.canvas.size, position = this.position, isBounce = outMode === index.OutMode.bounce;
2519
+ if (direction === index.OutModeDirection.bottom) {
2520
+ return {
2521
+ inside: isBounce ? position.y + radius < canvasSize.height : position.y - radius < canvasSize.height,
2522
+ reason: "default",
2523
+ };
2524
+ }
2525
+ if (direction === index.OutModeDirection.left) {
2526
+ return {
2527
+ inside: isBounce ? position.x - radius > index.defaultAngle : position.x + radius > index.defaultAngle,
2528
+ reason: "default",
2529
+ };
2530
+ }
2531
+ if (direction === index.OutModeDirection.right) {
2532
+ return {
2533
+ inside: isBounce ? position.x + radius < canvasSize.width : position.x - radius < canvasSize.width,
2534
+ reason: "default",
2535
+ };
2536
+ }
2537
+ if (direction === index.OutModeDirection.top) {
2538
+ return {
2539
+ inside: isBounce ? position.y - radius > index.defaultAngle : position.y + radius > index.defaultAngle,
2540
+ reason: "default",
2541
+ };
2542
+ }
2543
+ return {
2544
+ inside: position.x >= -radius &&
2545
+ position.y >= -radius &&
2546
+ position.y <= canvasSize.height + radius &&
2547
+ position.x <= canvasSize.width + radius,
2548
+ reason: "default",
2549
+ };
2550
+ };
2551
+ #getInsideCanvasCallbackData = (direction, outMode) => {
2552
+ return {
2553
+ canvasSize: this.#container.canvas.size,
2554
+ direction,
2555
+ outMode,
2556
+ particle: this,
2557
+ radius: this.getRadius(),
2558
+ };
2559
+ };
2560
+ #getInsideCanvasResult = (data) => {
2561
+ const defaultResult = this.#getDefaultInsideCanvasResult(data.direction, data.outMode), container = this.#container, shapeDrawer = this.shape ? container.shapeDrawers.get(this.shape) : undefined, effectDrawer = this.effect ? container.effectDrawers.get(this.effect) : undefined, shapeCheck = shapeDrawer?.isInsideCanvas, effectCheck = effectDrawer?.isInsideCanvas;
2562
+ if (!shapeCheck && !effectCheck) {
2563
+ return defaultResult;
2564
+ }
2565
+ const callbackData = this.#getInsideCanvasCallbackData(data.direction, data.outMode), shapeResult = shapeCheck ? this.#normalizeInsideCanvasResult(shapeCheck(callbackData), "shape") : undefined, effectResult = effectCheck ? this.#normalizeInsideCanvasResult(effectCheck(callbackData), "effect") : undefined;
2566
+ if (shapeResult && effectResult) {
2567
+ const margin = Math.max(shapeResult.margin ?? index.defaultAngle, effectResult.margin ?? index.defaultAngle);
2568
+ return {
2569
+ inside: shapeResult.inside && effectResult.inside,
2570
+ margin: margin > index.defaultAngle ? margin : undefined,
2571
+ reason: "combined",
2572
+ };
2573
+ }
2574
+ return shapeResult ?? effectResult ?? defaultResult;
2575
+ };
2576
+ #getRollColor = color => {
2577
+ if (!color || !this.roll || (!this.backColor && !this.roll.alter)) {
2578
+ return color;
2579
+ }
2580
+ if (!this.isShowingBack()) {
2581
+ return color;
2582
+ }
2583
+ if (this.backColor) {
2584
+ return this.backColor;
2585
+ }
2586
+ if (this.roll.alter) {
2587
+ return alterHsl(color, this.roll.alter.type, this.roll.alter.value);
2588
+ }
2589
+ return color;
2590
+ };
2591
+ #initPosition = position => {
2592
+ const container = this.#container, zIndexValue = Math.floor(index.getRangeValue(this.options.zIndex.value)), initialPosition = this.#calcPosition(position, index.clamp(zIndexValue, index.minZ, container.zLayers));
2593
+ if (!initialPosition) {
2594
+ throw new Error("a valid position cannot be found for particle");
2595
+ }
2596
+ this.position = initialPosition;
2597
+ this.initialPosition = this.position.copy();
2598
+ const canvasSize = container.canvas.size;
2599
+ this.moveCenter = {
2600
+ ...index.getPosition(this.options.move.center, canvasSize),
2601
+ radius: this.options.move.center.radius,
2602
+ mode: this.options.move.center.mode,
2603
+ };
2604
+ this.direction = index.getParticleDirectionAngle(this.options.move.direction, this.position, this.moveCenter);
2605
+ switch (this.options.move.direction) {
2606
+ case index.MoveDirection.inside:
2607
+ this.outType = index.ParticleOutType.inside;
2608
+ break;
2609
+ case index.MoveDirection.outside:
2610
+ this.outType = index.ParticleOutType.outside;
2611
+ break;
2612
+ }
2613
+ this.offset = index.Vector.origin;
2614
+ };
2615
+ #normalizeInsideCanvasResult = (result, reason) => {
2616
+ if (typeof result === "boolean") {
2617
+ return {
2618
+ inside: result,
2619
+ reason,
2620
+ };
2621
+ }
2622
+ return {
2623
+ inside: result.inside,
2624
+ margin: result.margin,
2625
+ reason: result.reason ?? reason,
2626
+ };
2627
+ };
2628
+ }
2629
+
2630
+ class SpatialHashGrid {
2631
+ #cellSize;
2632
+ #cells = new Map();
2633
+ #circlePool = [];
2634
+ #circlePoolIdx;
2635
+ #pendingCellSize;
2636
+ #rectanglePool = [];
2637
+ #rectanglePoolIdx;
2638
+ constructor(cellSize) {
2639
+ this.#cellSize = cellSize;
2640
+ this.#circlePoolIdx = 0;
2641
+ this.#rectanglePoolIdx = 0;
2642
+ }
2643
+ clear() {
2644
+ this.#cells.clear();
2645
+ const pendingCellSize = this.#pendingCellSize;
2646
+ if (pendingCellSize) {
2647
+ this.#cellSize = pendingCellSize;
2648
+ }
2649
+ this.#pendingCellSize = undefined;
2650
+ }
2651
+ insert(particle) {
2652
+ const { x, y } = particle.getPosition(), key = this.#cellKeyFromCoords(x, y);
2653
+ if (!this.#cells.has(key)) {
2654
+ this.#cells.set(key, []);
2655
+ }
2656
+ this.#cells.get(key)?.push(particle);
2657
+ }
2658
+ query(range, check, out = []) {
2659
+ const bounds = this.#getRangeBounds(range);
2660
+ if (!bounds) {
2661
+ return out;
2662
+ }
2663
+ 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);
2664
+ for (let cx = minCellX; cx <= maxCellX; cx++) {
2665
+ for (let cy = minCellY; cy <= maxCellY; cy++) {
2666
+ const key = `${cx}_${cy}`, cellParticles = this.#cells.get(key);
2667
+ if (!cellParticles) {
2668
+ continue;
2669
+ }
2670
+ for (const p of cellParticles) {
2671
+ if (check && !check(p)) {
2672
+ continue;
2673
+ }
2674
+ if (range.contains(p.getPosition())) {
2675
+ out.push(p);
2676
+ }
2677
+ }
2678
+ }
2679
+ }
2680
+ return out;
2681
+ }
2682
+ queryCircle(position, radius, check, out = []) {
2683
+ const circle = this.#acquireCircle(position.x, position.y, radius), result = this.query(circle, check, out);
2684
+ this.#releaseShapes();
2685
+ return result;
2686
+ }
2687
+ queryRectangle(position, size, check, out = []) {
2688
+ const rect = this.#acquireRectangle(position.x, position.y, size.width, size.height), result = this.query(rect, check, out);
2689
+ this.#releaseShapes();
2690
+ return result;
2691
+ }
2692
+ setCellSize(cellSize) {
2693
+ this.#pendingCellSize = cellSize;
2694
+ }
2695
+ #acquireCircle(x, y, r) {
2696
+ return (this.#circlePool[this.#circlePoolIdx++] ??= new Circle(x, y, r)).reset(x, y, r);
2697
+ }
2698
+ #acquireRectangle(x, y, w, h) {
2699
+ return (this.#rectanglePool[this.#rectanglePoolIdx++] ??= new Rectangle(x, y, w, h)).reset(x, y, w, h);
2700
+ }
2701
+ #cellKeyFromCoords(x, y) {
2702
+ const cellX = Math.floor(x / this.#cellSize), cellY = Math.floor(y / this.#cellSize);
2703
+ return `${cellX}_${cellY}`;
2704
+ }
2705
+ #getRangeBounds(range) {
2706
+ if (range instanceof Circle) {
2707
+ const r = range.radius, { x, y } = range.position;
2708
+ return {
2709
+ minX: x - r,
2710
+ maxX: x + r,
2711
+ minY: y - r,
2712
+ maxY: y + r,
2713
+ };
2714
+ }
2715
+ if (range instanceof Rectangle) {
2716
+ const { x, y } = range.position, { width, height } = range.size;
2717
+ return {
2718
+ minX: x,
2719
+ maxX: x + width,
2720
+ minY: y,
2721
+ maxY: y + height,
2722
+ };
2723
+ }
2724
+ return null;
2725
+ }
2726
+ #releaseShapes() {
2727
+ this.#circlePoolIdx = 0;
2728
+ this.#rectanglePoolIdx = 0;
2729
+ }
2730
+ }
2731
+
2732
+ class ParticlesManager {
2733
+ checkParticlePositionPlugins;
2734
+ grid;
2735
+ #array;
2736
+ #container;
2737
+ #groupLimits;
2738
+ #limit;
2739
+ #nextId;
2740
+ #particleBuckets;
2741
+ #particleResetPlugins;
2742
+ #particleUpdatePlugins;
2743
+ #pluginManager;
2744
+ #pool;
2745
+ #postParticleUpdatePlugins;
2746
+ #postUpdatePlugins;
2747
+ #resizeFactor;
2748
+ #updatePlugins;
2749
+ #zBuckets;
2750
+ constructor(pluginManager, container) {
2751
+ this.#pluginManager = pluginManager;
2752
+ this.#container = container;
2753
+ this.#nextId = 0;
2754
+ this.#array = [];
2755
+ this.#pool = [];
2756
+ this.#limit = 0;
2757
+ this.#groupLimits = new Map();
2758
+ this.#particleBuckets = new Map();
2759
+ this.#zBuckets = this.#createBuckets(this.#container.zLayers);
2760
+ this.grid = new SpatialHashGrid(index.spatialHashGridCellSize);
2761
+ this.checkParticlePositionPlugins = [];
2762
+ this.#particleResetPlugins = [];
2763
+ this.#particleUpdatePlugins = [];
2764
+ this.#postUpdatePlugins = [];
2765
+ this.#postParticleUpdatePlugins = [];
2766
+ this.#updatePlugins = [];
2767
+ }
2768
+ get count() {
2769
+ return this.#array.length;
2770
+ }
2771
+ addParticle(position, overrideOptions, group, initializer) {
2772
+ const limitMode = this.#container.actualOptions.particles.number.limit.mode, limit = group === undefined ? this.#limit : (this.#groupLimits.get(group) ?? this.#limit), currentCount = this.count;
2773
+ if (limit > index.minLimit) {
2774
+ switch (limitMode) {
2775
+ case index.LimitMode.delete: {
2776
+ const countToRemove = currentCount + index.countOffset - limit;
2777
+ if (countToRemove > index.minCount) {
2778
+ this.removeQuantity(countToRemove);
2779
+ }
2780
+ break;
2781
+ }
2782
+ case index.LimitMode.wait:
2783
+ if (currentCount >= limit) {
2784
+ return;
2785
+ }
2786
+ break;
2787
+ }
2788
+ }
2789
+ try {
2790
+ const particle = this.#pool.pop() ?? new Particle(this.#pluginManager, this.#container);
2791
+ particle.init(this.#nextId, position, overrideOptions, group);
2792
+ let canAdd = true;
2793
+ if (initializer) {
2794
+ canAdd = initializer(particle);
2795
+ }
2796
+ if (!canAdd) {
2797
+ this.#pool.push(particle);
2798
+ return;
2799
+ }
2800
+ this.#array.push(particle);
2801
+ this.#insertParticleIntoBucket(particle);
2802
+ this.#nextId++;
2803
+ this.#container.dispatchEvent(index.EventType.particleAdded, {
2804
+ particle,
2805
+ });
2806
+ return particle;
2807
+ }
2808
+ catch (e) {
2809
+ index.getLogger().warning(`error adding particle: ${e}`);
2810
+ }
2811
+ return undefined;
2812
+ }
2813
+ clear() {
2814
+ this.#array = [];
2815
+ this.#particleBuckets.clear();
2816
+ this.#resetBuckets(this.#container.zLayers);
2817
+ }
2818
+ destroy() {
2819
+ this.#array = [];
2820
+ this.#pool.length = 0;
2821
+ this.#particleBuckets.clear();
2822
+ this.#zBuckets = [];
2823
+ this.checkParticlePositionPlugins = [];
2824
+ this.#particleResetPlugins = [];
2825
+ this.#particleUpdatePlugins = [];
2826
+ this.#postUpdatePlugins = [];
2827
+ this.#postParticleUpdatePlugins = [];
2828
+ this.#updatePlugins = [];
2829
+ }
2830
+ drawParticles(delta) {
2831
+ for (let i = this.#zBuckets.length - index.one; i >= index.minIndex; i--) {
2832
+ const bucket = this.#zBuckets[i];
2833
+ if (!bucket) {
2834
+ continue;
2835
+ }
2836
+ for (const particle of bucket) {
2837
+ particle.draw(delta);
2838
+ }
2839
+ }
2840
+ }
2841
+ filter(condition) {
2842
+ return this.#array.filter(condition);
2843
+ }
2844
+ find(condition) {
2845
+ return this.#array.find(condition);
2846
+ }
2847
+ get(index) {
2848
+ return this.#array[index];
2849
+ }
2850
+ async init() {
2851
+ const container = this.#container, options = container.actualOptions;
2852
+ this.checkParticlePositionPlugins = [];
2853
+ this.#updatePlugins = [];
2854
+ this.#particleUpdatePlugins = [];
2855
+ this.#postUpdatePlugins = [];
2856
+ this.#particleResetPlugins = [];
2857
+ this.#postParticleUpdatePlugins = [];
2858
+ this.#particleBuckets.clear();
2859
+ this.#resetBuckets(container.zLayers);
2860
+ this.grid = new SpatialHashGrid(index.spatialHashGridCellSize * container.retina.pixelRatio);
2861
+ for (const plugin of container.plugins) {
2862
+ if (plugin.redrawInit) {
2863
+ await plugin.redrawInit();
2864
+ }
2865
+ if (plugin.checkParticlePosition) {
2866
+ this.checkParticlePositionPlugins.push(plugin);
2867
+ }
2868
+ if (plugin.update) {
2869
+ this.#updatePlugins.push(plugin);
2870
+ }
2871
+ if (plugin.particleUpdate) {
2872
+ this.#particleUpdatePlugins.push(plugin);
2873
+ }
2874
+ if (plugin.postUpdate) {
2875
+ this.#postUpdatePlugins.push(plugin);
2876
+ }
2877
+ if (plugin.particleReset) {
2878
+ this.#particleResetPlugins.push(plugin);
2879
+ }
2880
+ if (plugin.postParticleUpdate) {
2881
+ this.#postParticleUpdatePlugins.push(plugin);
2882
+ }
2883
+ }
2884
+ await this.#container.initDrawersAndUpdaters();
2885
+ for (const drawer of this.#container.effectDrawers.values()) {
2886
+ await drawer.init?.(container);
2887
+ }
2888
+ for (const drawer of this.#container.shapeDrawers.values()) {
2889
+ await drawer.init?.(container);
2890
+ }
2891
+ let handled = false;
2892
+ for (const plugin of container.plugins) {
2893
+ handled = plugin.particlesInitialization?.() ?? handled;
2894
+ if (handled) {
2895
+ break;
2896
+ }
2897
+ }
2898
+ if (!handled) {
2899
+ const particlesOptions = options.particles, groups = particlesOptions.groups;
2900
+ for (const group in groups) {
2901
+ const groupOptions = groups[group];
2902
+ if (!groupOptions) {
2903
+ continue;
2904
+ }
2905
+ for (let i = this.count, j = 0; j < groupOptions.number.value && i < particlesOptions.number.value; i++, j++) {
2906
+ this.addParticle(undefined, groupOptions, group);
2907
+ }
2908
+ }
2909
+ for (let i = this.count; i < particlesOptions.number.value; i++) {
2910
+ this.addParticle();
2911
+ }
2912
+ }
2913
+ }
2914
+ push(nb, position, overrideOptions, group) {
2915
+ for (let i = 0; i < nb; i++) {
2916
+ this.addParticle(position, overrideOptions, group);
2917
+ }
2918
+ }
2919
+ async redraw() {
2920
+ this.clear();
2921
+ await this.init();
2922
+ this.#container.canvas.render.drawParticles({ value: 0, factor: 0 });
2923
+ }
2924
+ remove(particle, group, override) {
2925
+ this.removeAt(this.#array.indexOf(particle), undefined, group, override);
2926
+ }
2927
+ removeAt(index$1, quantity = index.defaultRemoveQuantity, group, override) {
2928
+ if (index$1 < index.minIndex || index$1 > this.count) {
2929
+ return;
2930
+ }
2931
+ let deleted = 0;
2932
+ for (let i = index$1; deleted < quantity && i < this.count; i++) {
2933
+ if (this.#removeParticle(i, group, override)) {
2934
+ i--;
2935
+ deleted++;
2936
+ }
2937
+ }
2938
+ }
2939
+ removeQuantity(quantity, group) {
2940
+ this.removeAt(index.minIndex, quantity, group);
2941
+ }
2942
+ setDensity() {
2943
+ const options = this.#container.actualOptions, groups = options.particles.groups;
2944
+ let pluginsCount = 0;
2945
+ for (const plugin of this.#container.plugins) {
2946
+ if (plugin.particlesDensityCount) {
2947
+ pluginsCount += plugin.particlesDensityCount();
2948
+ }
2949
+ }
2950
+ for (const group in groups) {
2951
+ const groupData = groups[group];
2952
+ if (!groupData) {
2953
+ continue;
2954
+ }
2955
+ const groupDataOptions = loadParticlesOptions(this.#pluginManager, this.#container, groupData);
2956
+ this.#applyDensity(groupDataOptions, pluginsCount, group);
2957
+ }
2958
+ this.#applyDensity(options.particles, pluginsCount);
2959
+ }
2960
+ setResizeFactor(factor) {
2961
+ this.#resizeFactor = factor;
2962
+ }
2963
+ update(delta) {
2964
+ this.grid.clear();
2965
+ for (const plugin of this.#updatePlugins) {
2966
+ plugin.update?.(delta);
2967
+ }
2968
+ const particlesToDelete = this.#updateParticlesPhase1(delta);
2969
+ for (const plugin of this.#postUpdatePlugins) {
2970
+ plugin.postUpdate?.(delta);
2971
+ }
2972
+ this.#updateParticlesPhase2(delta, particlesToDelete);
2973
+ if (particlesToDelete.size) {
2974
+ for (const particle of particlesToDelete) {
2975
+ this.remove(particle);
2976
+ }
2977
+ }
2978
+ this.#resizeFactor = undefined;
2979
+ }
2980
+ #addToPool = (...particles) => {
2981
+ this.#pool.push(...particles);
2982
+ };
2983
+ #applyDensity = (options, pluginsCount, group, groupOptions) => {
2984
+ const numberOptions = options.number;
2985
+ if (!numberOptions.density.enable) {
2986
+ if (group === undefined) {
2987
+ this.#limit = numberOptions.limit.value;
2988
+ }
2989
+ else if (groupOptions?.number.limit.value ?? numberOptions.limit.value) {
2990
+ this.#groupLimits.set(group, groupOptions?.number.limit.value ?? numberOptions.limit.value);
2991
+ }
2992
+ return;
2993
+ }
2994
+ const densityFactor = this.#initDensityFactor(numberOptions.density), optParticlesNumber = numberOptions.value, optParticlesLimit = numberOptions.limit.value > index.minLimit ? numberOptions.limit.value : optParticlesNumber, particlesNumber = Math.min(optParticlesNumber, optParticlesLimit) * densityFactor + pluginsCount, particlesCount = Math.min(this.count, this.filter(t => t.group === group).length);
2995
+ if (group === undefined) {
2996
+ this.#limit = numberOptions.limit.value * densityFactor;
2997
+ }
2998
+ else {
2999
+ this.#groupLimits.set(group, numberOptions.limit.value * densityFactor);
3000
+ }
3001
+ if (particlesCount < particlesNumber) {
3002
+ this.push(Math.abs(particlesNumber - particlesCount), undefined, options, group);
3003
+ }
3004
+ else if (particlesCount > particlesNumber) {
3005
+ this.removeQuantity(particlesCount - particlesNumber, group);
3006
+ }
3007
+ };
3008
+ #createBuckets = (zLayers) => {
3009
+ const bucketCount = Math.max(Math.floor(zLayers), index.one);
3010
+ return Array.from({ length: bucketCount }, () => []);
3011
+ };
3012
+ #getBucketIndex = (zIndex) => {
3013
+ const maxBucketIndex = this.#zBuckets.length - index.one;
3014
+ if (maxBucketIndex <= index.minIndex) {
3015
+ return index.minIndex;
3016
+ }
3017
+ return Math.min(Math.max(Math.floor(zIndex), index.minIndex), maxBucketIndex);
3018
+ };
3019
+ #getParticleInsertIndex = (bucket, particleId) => {
3020
+ let start = index.minIndex, end = bucket.length;
3021
+ while (start < end) {
3022
+ const middle = Math.floor((start + end) / index.double), middleParticle = bucket[middle];
3023
+ if (!middleParticle) {
3024
+ end = middle;
3025
+ continue;
3026
+ }
3027
+ if (middleParticle.id < particleId) {
3028
+ start = middle + index.one;
3029
+ }
3030
+ else {
3031
+ end = middle;
3032
+ }
3033
+ }
3034
+ return start;
3035
+ };
3036
+ #initDensityFactor = densityOptions => {
3037
+ const container = this.#container;
3038
+ if (!densityOptions.enable) {
3039
+ return index.defaultDensityFactor;
3040
+ }
3041
+ const canvasSize = container.canvas.size, pxRatio = container.retina.pixelRatio;
3042
+ if (!canvasSize.width || !canvasSize.height) {
3043
+ return index.defaultDensityFactor;
3044
+ }
3045
+ return ((canvasSize.width * canvasSize.height) / (densityOptions.height * densityOptions.width * pxRatio ** index.squareExp));
3046
+ };
3047
+ #insertParticleIntoBucket = (particle) => {
3048
+ const bucketIndex = this.#getBucketIndex(particle.position.z), bucket = this.#zBuckets[bucketIndex];
3049
+ if (!bucket) {
3050
+ return;
3051
+ }
3052
+ bucket.splice(this.#getParticleInsertIndex(bucket, particle.id), index.empty, particle);
3053
+ this.#particleBuckets.set(particle.id, bucketIndex);
3054
+ };
3055
+ #removeParticle = (index$1, group, override) => {
3056
+ const particle = this.#array[index$1];
3057
+ if (!particle) {
3058
+ return false;
3059
+ }
3060
+ if (particle.group !== group) {
3061
+ return false;
3062
+ }
3063
+ this.#array.splice(index$1, index.deleteCount);
3064
+ this.#removeParticleFromBucket(particle);
3065
+ particle.destroy(override);
3066
+ this.#container.dispatchEvent(index.EventType.particleRemoved, {
3067
+ particle,
3068
+ });
3069
+ this.#addToPool(particle);
3070
+ return true;
3071
+ };
3072
+ #removeParticleFromBucket = (particle) => {
3073
+ const bucketIndex = this.#particleBuckets.get(particle.id) ?? this.#getBucketIndex(particle.position.z), bucket = this.#zBuckets[bucketIndex];
3074
+ if (!bucket) {
3075
+ this.#particleBuckets.delete(particle.id);
3076
+ return;
3077
+ }
3078
+ const particleIndex = this.#getParticleInsertIndex(bucket, particle.id);
3079
+ if (bucket[particleIndex]?.id !== particle.id) {
3080
+ this.#particleBuckets.delete(particle.id);
3081
+ return;
3082
+ }
3083
+ bucket.splice(particleIndex, index.deleteCount);
3084
+ this.#particleBuckets.delete(particle.id);
3085
+ };
3086
+ #resetBuckets = (zLayers) => {
3087
+ const bucketCount = Math.max(Math.floor(zLayers), index.one);
3088
+ if (this.#zBuckets.length !== bucketCount) {
3089
+ this.#zBuckets = this.#createBuckets(bucketCount);
3090
+ return;
3091
+ }
3092
+ for (const bucket of this.#zBuckets) {
3093
+ bucket.length = index.minIndex;
3094
+ }
3095
+ };
3096
+ #updateParticleBucket = (particle) => {
3097
+ const newBucketIndex = this.#getBucketIndex(particle.position.z), currentBucketIndex = this.#particleBuckets.get(particle.id);
3098
+ if (currentBucketIndex === undefined) {
3099
+ this.#insertParticleIntoBucket(particle);
3100
+ return;
3101
+ }
3102
+ if (currentBucketIndex === newBucketIndex) {
3103
+ return;
3104
+ }
3105
+ const currentBucket = this.#zBuckets[currentBucketIndex];
3106
+ if (currentBucket) {
3107
+ const particleIndex = this.#getParticleInsertIndex(currentBucket, particle.id);
3108
+ if (currentBucket[particleIndex]?.id === particle.id) {
3109
+ currentBucket.splice(particleIndex, index.deleteCount);
3110
+ }
3111
+ }
3112
+ const newBucket = this.#zBuckets[newBucketIndex];
3113
+ if (!newBucket) {
3114
+ this.#particleBuckets.set(particle.id, newBucketIndex);
3115
+ return;
3116
+ }
3117
+ newBucket.splice(this.#getParticleInsertIndex(newBucket, particle.id), index.empty, particle);
3118
+ this.#particleBuckets.set(particle.id, newBucketIndex);
3119
+ };
3120
+ #updateParticlesPhase1 = (delta) => {
3121
+ const particlesToDelete = new Set(), resizeFactor = this.#resizeFactor;
3122
+ for (const particle of this.#array) {
3123
+ if (resizeFactor && !particle.ignoresResizeRatio) {
3124
+ particle.position.x *= resizeFactor.width;
3125
+ particle.position.y *= resizeFactor.height;
3126
+ particle.initialPosition.x *= resizeFactor.width;
3127
+ particle.initialPosition.y *= resizeFactor.height;
3128
+ }
3129
+ particle.ignoresResizeRatio = false;
3130
+ for (const plugin of this.#particleResetPlugins) {
3131
+ plugin.particleReset?.(particle);
3132
+ }
3133
+ for (const plugin of this.#particleUpdatePlugins) {
3134
+ if (particle.destroyed) {
3135
+ break;
3136
+ }
3137
+ plugin.particleUpdate?.(particle, delta);
3138
+ }
3139
+ if (particle.destroyed) {
3140
+ particlesToDelete.add(particle);
3141
+ continue;
3142
+ }
3143
+ this.grid.insert(particle);
3144
+ }
3145
+ return particlesToDelete;
3146
+ };
3147
+ #updateParticlesPhase2 = (delta, particlesToDelete) => {
3148
+ for (const particle of this.#array) {
3149
+ if (particle.destroyed) {
3150
+ particlesToDelete.add(particle);
3151
+ continue;
3152
+ }
3153
+ for (const updater of this.#container.particleUpdaters) {
3154
+ updater.update(particle, delta);
3155
+ }
3156
+ if (!particle.spawning) {
3157
+ for (const plugin of this.#postParticleUpdatePlugins) {
3158
+ plugin.postParticleUpdate?.(particle, delta);
3159
+ }
3160
+ }
3161
+ this.#updateParticleBucket(particle);
3162
+ }
3163
+ };
3164
+ }
3165
+
3166
+ class Retina {
3167
+ pixelRatio;
3168
+ reduceFactor;
3169
+ #container;
3170
+ constructor(container) {
3171
+ this.#container = container;
3172
+ this.pixelRatio = index.defaultRatio;
3173
+ this.reduceFactor = index.defaultReduceFactor;
3174
+ }
3175
+ init() {
3176
+ const container = this.#container, options = container.actualOptions;
3177
+ this.pixelRatio = options.detectRetina ? devicePixelRatio : index.defaultRatio;
3178
+ this.reduceFactor = index.defaultReduceFactor;
3179
+ const ratio = this.pixelRatio, canvas = container.canvas, element = canvas.domElement;
3180
+ if (element) {
3181
+ canvas.size.width = element.offsetWidth * ratio;
3182
+ canvas.size.height = element.offsetHeight * ratio;
3183
+ }
3184
+ }
3185
+ initParticle(particle) {
3186
+ const options = particle.options, ratio = this.pixelRatio, moveOptions = options.move, moveDistance = moveOptions.distance, props = particle.retina;
3187
+ props.maxSpeed = index.getRangeValue(moveOptions.gravity.maxSpeed) * ratio;
3188
+ props.moveDrift = index.getRangeValue(moveOptions.drift) * ratio;
3189
+ props.moveSpeed = index.getRangeValue(moveOptions.speed) * ratio;
3190
+ const maxDistance = props.maxDistance;
3191
+ maxDistance.horizontal = moveDistance.horizontal === undefined ? undefined : moveDistance.horizontal * ratio;
3192
+ maxDistance.vertical = moveDistance.vertical === undefined ? undefined : moveDistance.vertical * ratio;
3193
+ }
3194
+ }
3195
+
3196
+ function guardCheck(container) {
3197
+ return !container.destroyed;
3198
+ }
3199
+ function updateDelta(delta, value, fpsLimit = index.defaultFps, smooth = false) {
3200
+ delta.value = value;
3201
+ delta.factor = smooth ? index.defaultFps / fpsLimit : (index.defaultFps * value) / index.millisecondsToSeconds;
3202
+ }
3203
+ function loadContainerOptions(pluginManager, container, ...sourceOptionsArr) {
3204
+ const options = new Options(pluginManager, container);
3205
+ loadOptions(options, ...sourceOptionsArr);
3206
+ return options;
3207
+ }
3208
+ class Container {
3209
+ actualOptions;
3210
+ canvas;
3211
+ destroyed;
3212
+ effectDrawers;
3213
+ fpsLimit;
3214
+ hdr;
3215
+ id;
3216
+ pageHidden;
3217
+ particleCreatedPlugins;
3218
+ particleDestroyedPlugins;
3219
+ particlePositionPlugins;
3220
+ particleUpdaters;
3221
+ particles;
3222
+ plugins;
3223
+ retina;
3224
+ shapeDrawers;
3225
+ started;
3226
+ zLayers;
3227
+ #delay;
3228
+ #delayTimeout;
3229
+ #delta = { value: 0, factor: 0 };
3230
+ #dispatchCallback;
3231
+ #drawAnimationFrame;
3232
+ #duration;
3233
+ #eventListeners;
3234
+ #firstStart;
3235
+ #initialSourceOptions;
3236
+ #lastFrameTime;
3237
+ #lifeTime;
3238
+ #onDestroy;
3239
+ #options;
3240
+ #paused;
3241
+ #pluginManager;
3242
+ #smooth;
3243
+ #sourceOptions;
3244
+ constructor(params) {
3245
+ const { dispatchCallback, pluginManager, id, onDestroy, sourceOptions } = params;
3246
+ this.#pluginManager = pluginManager;
3247
+ this.#dispatchCallback = dispatchCallback;
3248
+ this.#onDestroy = onDestroy;
3249
+ this.id = Symbol(id);
3250
+ this.fpsLimit = 120;
3251
+ this.hdr = false;
3252
+ this.#smooth = false;
3253
+ this.#delay = 0;
3254
+ this.#duration = 0;
3255
+ this.#lifeTime = 0;
3256
+ this.#firstStart = true;
3257
+ this.started = false;
3258
+ this.destroyed = false;
3259
+ this.#paused = true;
3260
+ this.#lastFrameTime = 0;
3261
+ this.zLayers = 100;
3262
+ this.pageHidden = false;
3263
+ this.#sourceOptions = sourceOptions;
3264
+ this.#initialSourceOptions = sourceOptions;
3265
+ this.effectDrawers = new Map();
3266
+ this.shapeDrawers = new Map();
3267
+ this.particleUpdaters = [];
3268
+ this.retina = new Retina(this);
3269
+ this.canvas = new CanvasManager(this.#pluginManager, this);
3270
+ this.particles = new ParticlesManager(this.#pluginManager, this);
3271
+ this.plugins = [];
3272
+ this.particleDestroyedPlugins = [];
3273
+ this.particleCreatedPlugins = [];
3274
+ this.particlePositionPlugins = [];
3275
+ this.#options = loadContainerOptions(this.#pluginManager, this);
3276
+ this.actualOptions = loadContainerOptions(this.#pluginManager, this);
3277
+ this.#eventListeners = new EventListeners(this);
3278
+ this.dispatchEvent(index.EventType.containerBuilt);
3279
+ }
3280
+ get animationStatus() {
3281
+ return !this.#paused && !this.pageHidden && guardCheck(this);
3282
+ }
3283
+ get options() {
3284
+ return this.#options;
3285
+ }
3286
+ get sourceOptions() {
3287
+ return this.#sourceOptions;
3288
+ }
3289
+ addLifeTime(value) {
3290
+ this.#lifeTime += value;
3291
+ }
3292
+ alive() {
3293
+ return !this.#duration || this.#lifeTime <= this.#duration;
3294
+ }
3295
+ destroy(remove = true) {
3296
+ if (!guardCheck(this)) {
3297
+ return;
3298
+ }
3299
+ this.stop();
3300
+ this.particles.destroy();
3301
+ this.canvas.destroy();
3302
+ for (const [, effectDrawer] of this.effectDrawers) {
3303
+ effectDrawer.destroy?.(this);
3304
+ }
3305
+ for (const [, shapeDrawer] of this.shapeDrawers) {
3306
+ shapeDrawer.destroy?.(this);
3307
+ }
3308
+ for (const plugin of this.plugins) {
3309
+ plugin.destroy?.();
3310
+ }
3311
+ this.effectDrawers = new Map();
3312
+ this.shapeDrawers = new Map();
3313
+ this.particleUpdaters = [];
3314
+ this.plugins.length = 0;
3315
+ this.#pluginManager.clearPlugins(this);
3316
+ this.destroyed = true;
3317
+ this.#onDestroy(remove);
3318
+ this.dispatchEvent(index.EventType.containerDestroyed);
3319
+ }
3320
+ dispatchEvent(type, data) {
3321
+ this.#dispatchCallback(type, {
3322
+ container: this,
3323
+ data,
3324
+ });
3325
+ }
3326
+ draw(force) {
3327
+ if (!guardCheck(this)) {
3328
+ return;
3329
+ }
3330
+ let refreshTime = force;
3331
+ this.#drawAnimationFrame = index.animate((timestamp) => {
3332
+ if (refreshTime) {
3333
+ this.#lastFrameTime = undefined;
3334
+ refreshTime = false;
3335
+ }
3336
+ this.#nextFrame(timestamp);
3337
+ });
3338
+ }
3339
+ async export(type, options = {}) {
3340
+ for (const plugin of this.plugins) {
3341
+ if (!plugin.export) {
3342
+ continue;
3343
+ }
3344
+ const res = await plugin.export(type, options);
3345
+ if (!res.supported) {
3346
+ continue;
3347
+ }
3348
+ return res.blob;
3349
+ }
3350
+ index.getLogger().error(`Export plugin with type ${type} not found`);
3351
+ return undefined;
3352
+ }
3353
+ async init() {
3354
+ if (!guardCheck(this)) {
3355
+ return;
3356
+ }
3357
+ const allContainerPlugins = new Map();
3358
+ for (const plugin of this.#pluginManager.plugins) {
3359
+ const containerPlugin = await plugin.getPlugin(this);
3360
+ if (containerPlugin.preInit) {
3361
+ await containerPlugin.preInit();
3362
+ }
3363
+ allContainerPlugins.set(plugin, containerPlugin);
3364
+ }
3365
+ await this.initDrawersAndUpdaters();
3366
+ this.#options = loadContainerOptions(this.#pluginManager, this, this.#initialSourceOptions, this.sourceOptions);
3367
+ this.actualOptions = loadContainerOptions(this.#pluginManager, this, this.#options);
3368
+ this.plugins.length = 0;
3369
+ this.particleDestroyedPlugins.length = 0;
3370
+ this.particleCreatedPlugins.length = 0;
3371
+ this.particlePositionPlugins.length = 0;
3372
+ for (const [plugin, containerPlugin] of allContainerPlugins) {
3373
+ if (plugin.needsPlugin(this.actualOptions)) {
3374
+ this.plugins.push(containerPlugin);
3375
+ if (containerPlugin.particleCreated) {
3376
+ this.particleCreatedPlugins.push(containerPlugin);
3377
+ }
3378
+ if (containerPlugin.particleDestroyed) {
3379
+ this.particleDestroyedPlugins.push(containerPlugin);
3380
+ }
3381
+ if (containerPlugin.particlePosition) {
3382
+ this.particlePositionPlugins.push(containerPlugin);
3383
+ }
3384
+ }
3385
+ }
3386
+ this.retina.init();
3387
+ this.canvas.init();
3388
+ this.updateActualOptions();
3389
+ this.canvas.initBackground();
3390
+ this.canvas.resize();
3391
+ const { delay, duration, fpsLimit, hdr, smooth, zLayers } = this.actualOptions;
3392
+ this.hdr = hdr;
3393
+ this.zLayers = zLayers;
3394
+ this.#duration = index.getRangeValue(duration) * index.millisecondsToSeconds;
3395
+ this.#delay = index.getRangeValue(delay) * index.millisecondsToSeconds;
3396
+ this.#lifeTime = 0;
3397
+ this.fpsLimit = fpsLimit > index.minFpsLimit ? fpsLimit : index.defaultFpsLimit;
3398
+ this.#smooth = smooth;
3399
+ for (const plugin of this.plugins) {
3400
+ await plugin.init?.();
3401
+ }
3402
+ await this.particles.init();
3403
+ this.dispatchEvent(index.EventType.containerInit);
3404
+ this.particles.setDensity();
3405
+ for (const plugin of this.plugins) {
3406
+ plugin.particlesSetup?.();
3407
+ }
3408
+ this.dispatchEvent(index.EventType.particlesSetup);
3409
+ }
3410
+ async initDrawersAndUpdaters() {
3411
+ const pluginManager = this.#pluginManager;
3412
+ this.effectDrawers = await pluginManager.getEffectDrawers(this, true);
3413
+ this.shapeDrawers = await pluginManager.getShapeDrawers(this, true);
3414
+ this.particleUpdaters = await pluginManager.getUpdaters(this, true);
3415
+ }
3416
+ pause() {
3417
+ if (!guardCheck(this)) {
3418
+ return;
3419
+ }
3420
+ if (this.#drawAnimationFrame !== undefined) {
3421
+ index.cancelAnimation(this.#drawAnimationFrame);
3422
+ this.#drawAnimationFrame = undefined;
3423
+ }
3424
+ if (this.#paused) {
3425
+ return;
3426
+ }
3427
+ for (const plugin of this.plugins) {
3428
+ plugin.pause?.();
3429
+ }
3430
+ if (!this.pageHidden) {
3431
+ this.#paused = true;
3432
+ }
3433
+ this.dispatchEvent(index.EventType.containerPaused);
3434
+ }
3435
+ play(force) {
3436
+ if (!guardCheck(this)) {
3437
+ return;
3438
+ }
3439
+ const needsUpdate = this.#paused || force;
3440
+ if (this.#firstStart && !this.actualOptions.autoPlay) {
3441
+ this.#firstStart = false;
3442
+ return;
3443
+ }
3444
+ if (this.#paused) {
3445
+ this.#paused = false;
3446
+ }
3447
+ if (needsUpdate) {
3448
+ for (const plugin of this.plugins) {
3449
+ if (plugin.play) {
3450
+ plugin.play();
3451
+ }
3452
+ }
3453
+ }
3454
+ this.dispatchEvent(index.EventType.containerPlay);
3455
+ this.draw(needsUpdate ?? false);
3456
+ }
3457
+ async refresh() {
3458
+ if (!guardCheck(this)) {
3459
+ return;
3460
+ }
3461
+ this.stop();
3462
+ return this.start();
3463
+ }
3464
+ async reset(sourceOptions) {
3465
+ if (!guardCheck(this)) {
3466
+ return;
3467
+ }
3468
+ this.#initialSourceOptions = sourceOptions;
3469
+ this.#sourceOptions = sourceOptions;
3470
+ this.#options = loadContainerOptions(this.#pluginManager, this, this.#initialSourceOptions, this.sourceOptions);
3471
+ this.actualOptions = loadContainerOptions(this.#pluginManager, this, this.#options);
3472
+ return this.refresh();
3473
+ }
3474
+ async start() {
3475
+ if (!guardCheck(this) || this.started) {
3476
+ return;
3477
+ }
3478
+ await this.init();
3479
+ this.started = true;
3480
+ await new Promise(resolve => {
3481
+ const start = async () => {
3482
+ this.#eventListeners.addListeners();
3483
+ for (const plugin of this.plugins) {
3484
+ await plugin.start?.();
3485
+ }
3486
+ this.dispatchEvent(index.EventType.containerStarted);
3487
+ this.play();
3488
+ resolve();
3489
+ };
3490
+ this.#delayTimeout = setTimeout(() => void start(), this.#delay);
3491
+ });
3492
+ }
3493
+ stop() {
3494
+ if (!guardCheck(this) || !this.started) {
3495
+ return;
3496
+ }
3497
+ if (this.#delayTimeout) {
3498
+ clearTimeout(this.#delayTimeout);
3499
+ this.#delayTimeout = undefined;
3500
+ }
3501
+ this.#firstStart = true;
3502
+ this.started = false;
3503
+ this.#eventListeners.removeListeners();
3504
+ this.pause();
3505
+ this.particles.clear();
3506
+ this.canvas.stop();
3507
+ for (const plugin of this.plugins) {
3508
+ plugin.stop?.();
3509
+ }
3510
+ this.particleCreatedPlugins.length = 0;
3511
+ this.particleDestroyedPlugins.length = 0;
3512
+ this.particlePositionPlugins.length = 0;
3513
+ this.#sourceOptions = this.#options;
3514
+ this.dispatchEvent(index.EventType.containerStopped);
3515
+ }
3516
+ updateActualOptions() {
3517
+ let refresh = false;
3518
+ for (const plugin of this.plugins) {
3519
+ if (plugin.updateActualOptions) {
3520
+ refresh = plugin.updateActualOptions() || refresh;
3521
+ }
3522
+ }
3523
+ return refresh;
3524
+ }
3525
+ #nextFrame = (timestamp) => {
3526
+ try {
3527
+ if (!this.#smooth &&
3528
+ this.#lastFrameTime !== undefined &&
3529
+ timestamp < this.#lastFrameTime + index.millisecondsToSeconds / this.fpsLimit) {
3530
+ this.draw(false);
3531
+ return;
3532
+ }
3533
+ this.#lastFrameTime ??= timestamp;
3534
+ updateDelta(this.#delta, timestamp - this.#lastFrameTime, this.fpsLimit, this.#smooth);
3535
+ this.addLifeTime(this.#delta.value);
3536
+ this.#lastFrameTime = timestamp;
3537
+ if (this.#delta.value > index.millisecondsToSeconds) {
3538
+ this.draw(false);
3539
+ return;
3540
+ }
3541
+ this.canvas.render.drawParticles(this.#delta);
3542
+ if (!this.alive()) {
3543
+ this.destroy();
3544
+ return;
3545
+ }
3546
+ if (this.animationStatus) {
3547
+ this.draw(false);
3548
+ }
3549
+ }
3550
+ catch (e) {
3551
+ index.getLogger().error("error in animation loop", e);
3552
+ }
3553
+ };
3554
+ }
3555
+
3556
+ exports.Container = Container;