@tsparticles/stencil 4.1.3 → 4.2.1

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 (29) hide show
  1. package/README.md +13 -0
  2. package/dist/cjs/{Container-0BqPfTsu.js → Container-BIhHE6mu.js} +659 -1010
  3. package/dist/cjs/{index-Bw7g3biq.js → index-BIoj1BEO.js} +57 -160
  4. package/dist/cjs/{index-B2lLThjb.js → index-BjS63OiI.js} +95 -5
  5. package/dist/cjs/index.cjs.js +1 -1
  6. package/dist/cjs/loader.cjs.js +2 -2
  7. package/dist/cjs/stencil-particles.cjs.entry.js +23 -6
  8. package/dist/cjs/tsparticlesstencil.cjs.js +2 -2
  9. package/dist/collection/components/stencil-particles/stencil-particles.js +83 -4
  10. package/dist/esm/{Container-BxLt611H.js → Container-DZZsfp6i.js} +659 -1010
  11. package/dist/esm/{index-BXzC9NH1.js → index-BH3sNkGS.js} +57 -160
  12. package/dist/esm/{index-DKFk70aj.js → index-PhwiK2_P.js} +95 -6
  13. package/dist/esm/index.js +1 -1
  14. package/dist/esm/loader.js +3 -3
  15. package/dist/esm/stencil-particles.entry.js +23 -6
  16. package/dist/esm/tsparticlesstencil.js +3 -3
  17. package/dist/tsparticlesstencil/index.esm.js +1 -1
  18. package/dist/tsparticlesstencil/p-CIUgBOXY.js +1 -0
  19. package/dist/tsparticlesstencil/p-PhwiK2_P.js +2 -0
  20. package/dist/tsparticlesstencil/p-QSzGOBhI.js +1 -0
  21. package/dist/tsparticlesstencil/p-bd76f15b.entry.js +1 -0
  22. package/dist/tsparticlesstencil/tsparticlesstencil.esm.js +1 -1
  23. package/dist/types/components/stencil-particles/stencil-particles.d.ts +6 -2
  24. package/dist/types/components.d.ts +24 -2
  25. package/package.json +8 -7
  26. package/dist/tsparticlesstencil/p-BhGs05ap.js +0 -1
  27. package/dist/tsparticlesstencil/p-DKFk70aj.js +0 -2
  28. package/dist/tsparticlesstencil/p-LyLjQmWv.js +0 -1
  29. package/dist/tsparticlesstencil/p-cf6e2424.entry.js +0 -1
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var index = require('./index-Bw7g3biq.js');
3
+ var index = require('./index-BIoj1BEO.js');
4
4
 
5
5
  class BaseRange {
6
6
  position;
@@ -75,93 +75,86 @@ class Rectangle extends BaseRange {
75
75
  }
76
76
  }
77
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
- }
78
+ class OptionLoader {
93
79
  load(data) {
94
80
  if (index.isNull(data)) {
95
81
  return;
96
82
  }
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
- }
83
+ this.doLoad(data);
84
+ }
85
+ }
86
+ function loadOptions(options, ...sourceOptionsArr) {
87
+ for (const sourceOptions of sourceOptionsArr) {
88
+ options.load(sourceOptions);
89
+ }
90
+ }
91
+
92
+ function loadProperty(obj, key, value) {
93
+ if (value !== undefined) {
94
+ obj[key] = value;
95
+ }
96
+ }
97
+ function loadRangeProperty(obj, key, value) {
98
+ if (value !== undefined) {
99
+ obj[key] = index.setRangeValue(value);
100
+ }
101
+ }
102
+ function loadLazyProperty(obj, key, value, factory) {
103
+ if (value !== undefined) {
104
+ const objRecord = obj;
105
+ objRecord[key] ??= factory();
106
+ objRecord[key].load(value);
107
+ }
108
+ }
109
+
110
+ class AnimationOptions extends OptionLoader {
111
+ count = 0;
112
+ decay = 0;
113
+ delay = 0;
114
+ enable = false;
115
+ speed = 1;
116
+ sync = false;
117
+ doLoad(data) {
118
+ loadRangeProperty(this, "count", data.count);
119
+ loadProperty(this, "enable", data.enable);
120
+ loadRangeProperty(this, "speed", data.speed);
121
+ loadRangeProperty(this, "decay", data.decay);
122
+ loadRangeProperty(this, "delay", data.delay);
123
+ loadProperty(this, "sync", data.sync);
115
124
  }
116
125
  }
117
126
 
118
127
  class ColorAnimation extends AnimationOptions {
119
128
  max;
120
129
  min;
121
- offset;
130
+ offset = 0;
131
+ sync = true;
122
132
  constructor(min, max) {
123
133
  super();
124
134
  this.min = min;
125
135
  this.max = max;
126
- this.offset = 0;
127
- this.sync = true;
128
136
  }
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
- }
137
+ doLoad(data) {
138
+ super.doLoad(data);
139
+ loadProperty(this, "max", data.max);
140
+ loadProperty(this, "min", data.min);
141
+ loadRangeProperty(this, "offset", data.offset);
143
142
  }
144
143
  }
145
144
 
146
- class HslAnimation {
145
+ class HslAnimation extends OptionLoader {
147
146
  h = new ColorAnimation(index.hMin, index.hMax);
148
147
  l = new ColorAnimation(index.lMin, index.lMax);
149
148
  s = new ColorAnimation(index.sMin, index.sMax);
150
- load(data) {
151
- if (index.isNull(data)) {
152
- return;
153
- }
149
+ doLoad(data) {
154
150
  this.h.load(data.h);
155
151
  this.s.load(data.s);
156
152
  this.l.load(data.l);
157
153
  }
158
154
  }
159
155
 
160
- class OptionsColor {
161
- value;
162
- constructor() {
163
- this.value = "";
164
- }
156
+ class OptionsColor extends OptionLoader {
157
+ value = "";
165
158
  static create(source, data) {
166
159
  const color = new OptionsColor();
167
160
  color.load(source);
@@ -175,10 +168,7 @@ class OptionsColor {
175
168
  }
176
169
  return color;
177
170
  }
178
- load(data) {
179
- if (index.isNull(data)) {
180
- return;
181
- }
171
+ doLoad(data) {
182
172
  if (!index.isNull(data.value)) {
183
173
  this.value = data.value;
184
174
  }
@@ -186,11 +176,7 @@ class OptionsColor {
186
176
  }
187
177
 
188
178
  class AnimatableColor extends OptionsColor {
189
- animation;
190
- constructor() {
191
- super();
192
- this.animation = new HslAnimation();
193
- }
179
+ animation = new HslAnimation();
194
180
  static create(source, data) {
195
181
  const color = new AnimatableColor();
196
182
  color.load(source);
@@ -204,11 +190,8 @@ class AnimatableColor extends OptionsColor {
204
190
  }
205
191
  return color;
206
192
  }
207
- load(data) {
208
- super.load(data);
209
- if (index.isNull(data)) {
210
- return;
211
- }
193
+ doLoad(data) {
194
+ super.doLoad(data);
212
195
  const colorAnimation = data.animation;
213
196
  if (colorAnimation !== undefined) {
214
197
  if (colorAnimation.enable === undefined) {
@@ -221,100 +204,53 @@ class AnimatableColor extends OptionsColor {
221
204
  }
222
205
  }
223
206
 
224
- class Background {
207
+ class Background extends OptionLoader {
225
208
  color;
226
- image;
227
- opacity;
228
- position;
229
- repeat;
230
- size;
209
+ image = "";
210
+ opacity = 1;
211
+ position = "";
212
+ repeat = "";
213
+ size = "";
231
214
  constructor() {
215
+ super();
232
216
  this.color = new OptionsColor();
233
217
  this.color.value = "";
234
- this.image = "";
235
- this.position = "";
236
- this.repeat = "";
237
- this.size = "";
238
- this.opacity = 1;
239
218
  }
240
- load(data) {
241
- if (index.isNull(data)) {
242
- return;
243
- }
219
+ doLoad(data) {
244
220
  if (data.color !== undefined) {
245
221
  this.color = OptionsColor.create(this.color, data.color);
246
222
  }
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
- }
223
+ loadProperty(this, "image", data.image);
224
+ loadProperty(this, "position", data.position);
225
+ loadProperty(this, "repeat", data.repeat);
226
+ loadProperty(this, "size", data.size);
227
+ loadProperty(this, "opacity", data.opacity);
262
228
  }
263
229
  }
264
230
 
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
- }
231
+ class FullScreen extends OptionLoader {
232
+ enable = true;
233
+ zIndex = 0;
234
+ doLoad(data) {
235
+ loadProperty(this, "enable", data.enable);
236
+ loadProperty(this, "zIndex", data.zIndex);
282
237
  }
283
238
  }
284
239
 
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
- }
240
+ class ResizeEvent extends OptionLoader {
241
+ delay = 0.5;
242
+ enable = true;
243
+ doLoad(data) {
244
+ loadProperty(this, "delay", data.delay);
245
+ loadProperty(this, "enable", data.enable);
302
246
  }
303
247
  }
304
248
 
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
- }
249
+ class Effect extends OptionLoader {
250
+ close = true;
251
+ options = {};
252
+ type = [];
253
+ doLoad(data) {
318
254
  const options = data.options;
319
255
  if (options !== undefined) {
320
256
  for (const effect in options) {
@@ -324,157 +260,78 @@ class Effect {
324
260
  }
325
261
  }
326
262
  }
327
- if (data.close !== undefined) {
328
- this.close = data.close;
329
- }
330
- if (data.type !== undefined) {
331
- this.type = data.type;
332
- }
263
+ loadProperty(this, "close", data.close);
264
+ loadProperty(this, "type", data.type);
333
265
  }
334
266
  }
335
267
 
336
- class Fill {
268
+ class Fill extends OptionLoader {
337
269
  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
- }
270
+ enable = true;
271
+ opacity = 1;
272
+ doLoad(data) {
348
273
  if (data.color !== undefined) {
349
274
  this.color = AnimatableColor.create(this.color, data.color);
350
275
  }
351
- if (data.enable !== undefined) {
352
- this.enable = data.enable;
353
- }
354
- if (data.opacity !== undefined) {
355
- this.opacity = index.setRangeValue(data.opacity);
356
- }
276
+ loadProperty(this, "enable", data.enable);
277
+ loadRangeProperty(this, "opacity", data.opacity);
357
278
  }
358
279
  }
359
280
 
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
- }
281
+ class MoveAngle extends OptionLoader {
282
+ offset = 0;
283
+ value = 90;
284
+ doLoad(data) {
285
+ loadRangeProperty(this, "offset", data.offset);
286
+ loadRangeProperty(this, "value", data.value);
377
287
  }
378
288
  }
379
289
 
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
- }
290
+ class MoveCenter extends OptionLoader {
291
+ mode = index.PixelMode.percent;
292
+ radius = 0;
293
+ x = 50;
294
+ y = 50;
295
+ doLoad(data) {
296
+ loadProperty(this, "x", data.x);
297
+ loadProperty(this, "y", data.y);
298
+ loadProperty(this, "mode", data.mode);
299
+ loadProperty(this, "radius", data.radius);
407
300
  }
408
301
  }
409
302
 
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
- }
303
+ class MoveGravity extends OptionLoader {
304
+ acceleration = 9.81;
305
+ enable = false;
306
+ inverse = false;
307
+ maxSpeed = 50;
308
+ doLoad(data) {
309
+ loadRangeProperty(this, "acceleration", data.acceleration);
310
+ loadProperty(this, "enable", data.enable);
311
+ loadProperty(this, "inverse", data.inverse);
312
+ loadRangeProperty(this, "maxSpeed", data.maxSpeed);
437
313
  }
438
314
  }
439
315
 
440
- class ValueWithRandom {
441
- value;
442
- constructor() {
443
- this.value = 0;
444
- }
445
- load(data) {
446
- if (index.isNull(data)) {
447
- return;
448
- }
316
+ class ValueWithRandom extends OptionLoader {
317
+ value = 0;
318
+ doLoad(data) {
449
319
  if (!index.isNull(data.value)) {
450
320
  this.value = index.setRangeValue(data.value);
451
321
  }
452
322
  }
453
323
  }
454
324
 
455
- class MovePath {
456
- clamp;
457
- delay;
458
- enable;
325
+ class MovePath extends OptionLoader {
326
+ clamp = true;
327
+ delay = new ValueWithRandom();
328
+ enable = false;
459
329
  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
- }
330
+ options = {};
331
+ doLoad(data) {
332
+ loadProperty(this, "clamp", data.clamp);
474
333
  this.delay.load(data.delay);
475
- if (data.enable !== undefined) {
476
- this.enable = data.enable;
477
- }
334
+ loadProperty(this, "enable", data.enable);
478
335
  this.generator = data.generator;
479
336
  if (data.options) {
480
337
  this.options = index.deepExtend(this.options, data.options);
@@ -482,19 +339,13 @@ class MovePath {
482
339
  }
483
340
  }
484
341
 
485
- class OutModes {
342
+ class OutModes extends OptionLoader {
486
343
  bottom;
487
- default;
344
+ default = index.OutMode.out;
488
345
  left;
489
346
  right;
490
347
  top;
491
- constructor() {
492
- this.default = index.OutMode.out;
493
- }
494
- load(data) {
495
- if (index.isNull(data)) {
496
- return;
497
- }
348
+ doLoad(data) {
498
349
  if (data.default !== undefined) {
499
350
  this.default = data.default;
500
351
  }
@@ -505,79 +356,42 @@ class OutModes {
505
356
  }
506
357
  }
507
358
 
508
- class Spin {
509
- acceleration;
510
- enable;
359
+ class Spin extends OptionLoader {
360
+ acceleration = 0;
361
+ enable = false;
511
362
  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
- }
363
+ doLoad(data) {
364
+ loadRangeProperty(this, "acceleration", data.acceleration);
365
+ loadProperty(this, "enable", data.enable);
526
366
  if (data.position) {
527
367
  this.position = index.deepExtend({}, data.position);
528
368
  }
529
369
  }
530
370
  }
531
371
 
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
- }
372
+ class Move extends OptionLoader {
373
+ angle = new MoveAngle();
374
+ center = new MoveCenter();
375
+ decay = 0;
376
+ direction = index.MoveDirection.none;
377
+ distance = {};
378
+ drift = 0;
379
+ enable = false;
380
+ gravity = new MoveGravity();
381
+ outModes = new OutModes();
382
+ path = new MovePath();
383
+ random = false;
384
+ size = false;
385
+ speed = 2;
386
+ spin = new Spin();
387
+ straight = false;
388
+ vibrate = false;
389
+ warp = false;
390
+ doLoad(data) {
573
391
  this.angle.load(index.isNumber(data.angle) ? { value: data.angle } : data.angle);
574
392
  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
- }
393
+ loadRangeProperty(this, "decay", data.decay);
394
+ loadProperty(this, "direction", data.direction);
581
395
  if (data.distance !== undefined) {
582
396
  this.distance = index.isNumber(data.distance)
583
397
  ? {
@@ -586,12 +400,8 @@ class Move {
586
400
  }
587
401
  : { ...data.distance };
588
402
  }
589
- if (data.drift !== undefined) {
590
- this.drift = index.setRangeValue(data.drift);
591
- }
592
- if (data.enable !== undefined) {
593
- this.enable = data.enable;
594
- }
403
+ loadRangeProperty(this, "drift", data.drift);
404
+ loadProperty(this, "enable", data.enable);
595
405
  this.gravity.load(data.gravity);
596
406
  const outModes = data.outModes;
597
407
  if (outModes !== undefined) {
@@ -605,177 +415,91 @@ class Move {
605
415
  }
606
416
  }
607
417
  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
- }
418
+ loadProperty(this, "random", data.random);
419
+ loadProperty(this, "size", data.size);
420
+ loadRangeProperty(this, "speed", data.speed);
617
421
  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
- }
422
+ loadProperty(this, "straight", data.straight);
423
+ loadProperty(this, "vibrate", data.vibrate);
424
+ loadProperty(this, "warp", data.warp);
627
425
  }
628
426
  }
629
427
 
630
- class Stroke {
428
+ class Stroke extends OptionLoader {
631
429
  color;
632
430
  opacity;
633
- width;
634
- constructor() {
635
- this.width = 0;
636
- }
637
- load(data) {
638
- if (index.isNull(data)) {
639
- return;
640
- }
431
+ width = 0;
432
+ doLoad(data) {
641
433
  if (data.color !== undefined) {
642
434
  this.color = AnimatableColor.create(this.color, data.color);
643
435
  }
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
- }
436
+ loadRangeProperty(this, "width", data.width);
437
+ loadRangeProperty(this, "opacity", data.opacity);
650
438
  }
651
439
  }
652
440
 
653
- class Paint {
441
+ class Paint extends OptionLoader {
654
442
  color;
655
443
  fill;
656
444
  stroke;
657
- load(data) {
658
- if (index.isNull(data)) {
659
- return;
660
- }
445
+ doLoad(data) {
661
446
  if (data.color !== undefined) {
662
447
  this.color = AnimatableColor.create(this.color, data.color);
663
448
  }
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
- }
449
+ loadLazyProperty(this, "fill", data.fill, () => new Fill());
450
+ loadLazyProperty(this, "stroke", data.stroke, () => new Stroke());
672
451
  }
673
452
  }
674
453
 
675
454
  class ParticlesBounceFactor extends ValueWithRandom {
676
- constructor() {
677
- super();
678
- this.value = 1;
679
- }
455
+ value = 1;
680
456
  }
681
457
 
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
- }
458
+ class ParticlesBounce extends OptionLoader {
459
+ horizontal = new ParticlesBounceFactor();
460
+ vertical = new ParticlesBounceFactor();
461
+ doLoad(data) {
693
462
  this.horizontal.load(data.horizontal);
694
463
  this.vertical.load(data.vertical);
695
464
  }
696
465
  }
697
466
 
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
- }
467
+ class ParticlesDensity extends OptionLoader {
468
+ enable = false;
469
+ height = 1080;
470
+ width = 1920;
471
+ doLoad(data) {
472
+ loadProperty(this, "enable", data.enable);
473
+ loadProperty(this, "width", data.width);
474
+ loadProperty(this, "height", data.height);
722
475
  }
723
476
  }
724
477
 
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
- }
478
+ class ParticlesNumberLimit extends OptionLoader {
479
+ mode = index.LimitMode.delete;
480
+ value = 0;
481
+ doLoad(data) {
482
+ loadProperty(this, "mode", data.mode);
483
+ loadProperty(this, "value", data.value);
742
484
  }
743
485
  }
744
486
 
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
- }
487
+ class ParticlesNumber extends OptionLoader {
488
+ density = new ParticlesDensity();
489
+ limit = new ParticlesNumberLimit();
490
+ value = 0;
491
+ doLoad(data) {
758
492
  this.density.load(data.density);
759
493
  this.limit.load(data.limit);
760
- if (data.value !== undefined) {
761
- this.value = data.value;
762
- }
494
+ loadProperty(this, "value", data.value);
763
495
  }
764
496
  }
765
497
 
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
- }
498
+ class Shape extends OptionLoader {
499
+ close = true;
500
+ options = {};
501
+ type = "circle";
502
+ doLoad(data) {
779
503
  const options = data.options;
780
504
  if (options !== undefined) {
781
505
  for (const shape in options) {
@@ -785,76 +509,47 @@ class Shape {
785
509
  }
786
510
  }
787
511
  }
788
- if (data.close !== undefined) {
789
- this.close = data.close;
790
- }
791
- if (data.type !== undefined) {
792
- this.type = data.type;
793
- }
512
+ loadProperty(this, "close", data.close);
513
+ loadProperty(this, "type", data.type);
794
514
  }
795
515
  }
796
516
 
797
517
  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
- }
518
+ opacityRate = 1;
519
+ sizeRate = 1;
520
+ velocityRate = 1;
521
+ doLoad(data) {
522
+ super.doLoad(data);
523
+ loadProperty(this, "opacityRate", data.opacityRate);
524
+ loadProperty(this, "sizeRate", data.sizeRate);
525
+ loadProperty(this, "velocityRate", data.velocityRate);
821
526
  }
822
527
  }
823
528
 
824
- class ParticlesOptions {
825
- bounce;
826
- effect;
827
- groups;
828
- move;
829
- number;
529
+ class ParticlesOptions extends OptionLoader {
530
+ bounce = new ParticlesBounce();
531
+ effect = new Effect();
532
+ groups = {};
533
+ move = new Move();
534
+ number = new ParticlesNumber();
830
535
  paint;
831
536
  palette;
832
- reduceDuplicates;
833
- shape;
834
- zIndex;
537
+ reduceDuplicates = false;
538
+ shape = new Shape();
539
+ zIndex = new ZIndex();
835
540
  #container;
836
541
  #pluginManager;
837
542
  constructor(pluginManager, container) {
543
+ super();
838
544
  this.#pluginManager = pluginManager;
839
545
  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
546
  this.paint = new Paint();
846
547
  this.paint.color = new AnimatableColor();
847
548
  this.paint.color.value = "#fff";
848
549
  this.paint.fill = new Fill();
849
550
  this.paint.fill.enable = true;
850
- this.reduceDuplicates = false;
851
- this.shape = new Shape();
852
- this.zIndex = new ZIndex();
853
551
  }
854
- load(data) {
855
- if (index.isNull(data)) {
856
- return;
857
- }
552
+ doLoad(data) {
858
553
  if (data.palette) {
859
554
  this.palette = data.palette;
860
555
  this.#importPalette(this.palette);
@@ -912,7 +607,7 @@ class ParticlesOptions {
912
607
  }
913
608
  }
914
609
  }
915
- #importPalette = (palette) => {
610
+ #importPalette(palette) {
916
611
  const paletteData = this.#pluginManager.getPalette(palette);
917
612
  if (!paletteData) {
918
613
  return;
@@ -956,69 +651,49 @@ class ParticlesOptions {
956
651
  mode: paletteData.blendMode,
957
652
  },
958
653
  });
959
- };
960
- }
961
-
962
- function loadOptions(options, ...sourceOptionsArr) {
963
- for (const sourceOptions of sourceOptionsArr) {
964
- options.load(sourceOptions);
965
654
  }
966
655
  }
656
+
967
657
  function loadParticlesOptions(pluginManager, container, ...sourceOptionsArr) {
968
658
  const options = new ParticlesOptions(pluginManager, container);
969
659
  loadOptions(options, ...sourceOptionsArr);
970
660
  return options;
971
661
  }
972
662
 
973
- class Options {
974
- autoPlay;
663
+ class Options extends OptionLoader {
664
+ autoPlay = true;
975
665
  background;
976
- clear;
977
- defaultThemes;
978
- delay;
979
- detectRetina;
980
- duration;
981
- fpsLimit;
666
+ clear = true;
667
+ defaultThemes = {};
668
+ delay = 0;
669
+ detectRetina = true;
670
+ duration = 0;
671
+ fpsLimit = 120;
982
672
  fullScreen;
983
- hdr;
673
+ hdr = true;
984
674
  key;
985
675
  name;
986
676
  palette;
987
677
  particles;
988
- pauseOnBlur;
989
- pauseOnOutsideViewport;
678
+ pauseOnBlur = true;
679
+ pauseOnOutsideViewport = true;
990
680
  preset;
991
681
  resize;
992
- smooth;
993
- style;
994
- zLayers;
682
+ smooth = false;
683
+ style = {};
684
+ zLayers = 100;
995
685
  #container;
996
686
  #pluginManager;
997
687
  constructor(pluginManager, container) {
688
+ super();
998
689
  this.#pluginManager = pluginManager;
999
690
  this.#container = container;
1000
- this.autoPlay = true;
1001
691
  this.background = new Background();
1002
- this.clear = true;
1003
- this.defaultThemes = {};
1004
- this.delay = 0;
1005
692
  this.fullScreen = new FullScreen();
1006
- this.detectRetina = true;
1007
- this.duration = 0;
1008
- this.fpsLimit = 120;
1009
- this.hdr = true;
1010
693
  this.particles = loadParticlesOptions(this.#pluginManager, this.#container);
1011
- this.pauseOnBlur = true;
1012
- this.pauseOnOutsideViewport = true;
1013
694
  this.resize = new ResizeEvent();
1014
- this.smooth = false;
1015
- this.style = {};
1016
- this.zLayers = 100;
1017
695
  }
1018
- load(data) {
1019
- if (index.isNull(data)) {
1020
- return;
1021
- }
696
+ doLoad(data) {
1022
697
  if (data.preset !== undefined) {
1023
698
  this.preset = data.preset;
1024
699
  index.executeOnSingleOrMultiple(this.preset, preset => {
@@ -1029,44 +704,18 @@ class Options {
1029
704
  this.palette = data.palette;
1030
705
  this.#importPalette(this.palette);
1031
706
  }
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
- }
707
+ loadProperty(this, "autoPlay", data.autoPlay);
708
+ loadProperty(this, "clear", data.clear);
709
+ loadProperty(this, "key", data.key);
710
+ loadProperty(this, "name", data.name);
711
+ loadRangeProperty(this, "delay", data.delay);
712
+ loadProperty(this, "detectRetina", data.detectRetina);
713
+ loadRangeProperty(this, "duration", data.duration);
714
+ loadProperty(this, "fpsLimit", data.fpsLimit);
715
+ loadProperty(this, "hdr", data.hdr);
716
+ loadProperty(this, "pauseOnBlur", data.pauseOnBlur);
717
+ loadProperty(this, "pauseOnOutsideViewport", data.pauseOnOutsideViewport);
718
+ loadProperty(this, "zLayers", data.zLayers);
1070
719
  this.background.load(data.background);
1071
720
  const fullScreen = data.fullScreen;
1072
721
  if (index.isBoolean(fullScreen)) {
@@ -1078,14 +727,12 @@ class Options {
1078
727
  this.particles.load(data.particles);
1079
728
  this.resize.load(data.resize);
1080
729
  this.style = index.deepExtend(this.style, data.style);
1081
- if (data.smooth !== undefined) {
1082
- this.smooth = data.smooth;
1083
- }
730
+ loadProperty(this, "smooth", data.smooth);
1084
731
  this.#pluginManager.plugins.forEach(plugin => {
1085
732
  plugin.loadOptions(this.#container, this, data);
1086
733
  });
1087
734
  }
1088
- #importPalette = palette => {
735
+ #importPalette(palette) {
1089
736
  const paletteData = this.#pluginManager.getPalette(palette);
1090
737
  if (!paletteData) {
1091
738
  return;
@@ -1102,143 +749,19 @@ class Options {
1102
749
  palette,
1103
750
  },
1104
751
  });
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
752
  }
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;
753
+ #importPreset(preset) {
754
+ this.load(this.#pluginManager.getPreset(preset));
1230
755
  }
1231
- plugin.drawParticle(context, particle, delta);
1232
756
  }
1233
757
 
1234
- const styleCache = new Map(), maxCacheSize = 1000, firstIndex = 0, rgbFixedPrecision = 2, hslFixedPrecision = 2;
758
+ const styleCache = new Map(), maxStyleCacheSize = 2000, rgbFixedPrecision = 2, hslFixedPrecision = 2, sdrReferenceWhiteNits = 203;
1235
759
  function getCachedStyle(key, generator) {
1236
760
  let cached = styleCache.get(key);
1237
761
  if (!cached) {
1238
762
  cached = generator();
1239
- if (styleCache.size >= maxCacheSize) {
1240
- const keysToDelete = [...styleCache.keys()].slice(firstIndex, maxCacheSize * index.half);
1241
- keysToDelete.forEach(k => styleCache.delete(k));
763
+ if (styleCache.size > maxStyleCacheSize) {
764
+ styleCache.clear();
1242
765
  }
1243
766
  styleCache.set(key, cached);
1244
767
  }
@@ -1341,34 +864,35 @@ function rgbToHsl(color) {
1341
864
  function stringToRgb(pluginManager, input) {
1342
865
  return stringToRgba(pluginManager, input);
1343
866
  }
867
+ function hslChannel(temp1, temp2, temp3) {
868
+ const temp3Min = 0, temp3Max = 1;
869
+ if (temp3 < temp3Min) {
870
+ temp3++;
871
+ }
872
+ if (temp3 > temp3Max) {
873
+ temp3--;
874
+ }
875
+ if (temp3 * index.sextuple < temp3Max) {
876
+ return temp1 + (temp2 - temp1) * index.sextuple * temp3;
877
+ }
878
+ if (temp3 * index.double < temp3Max) {
879
+ return temp2;
880
+ }
881
+ if (temp3 * index.triple < temp3Max * index.double) {
882
+ const temp3Offset = index.double / index.triple;
883
+ return temp1 + (temp2 - temp1) * (temp3Offset - temp3) * index.sextuple;
884
+ }
885
+ return temp1;
886
+ }
1344
887
  function hslToRgb(hsl) {
1345
888
  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
889
  if (s === index.sMin) {
1347
890
  const grayscaleValue = Math.round(lNormalized * index.rgbMax);
1348
891
  return { r: grayscaleValue, g: grayscaleValue, b: grayscaleValue };
1349
892
  }
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
893
+ const temp1 = lNormalized < index.half
1370
894
  ? 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));
895
+ : lNormalized + sNormalized - lNormalized * sNormalized, temp2 = index.double * lNormalized - temp1, phaseThird = index.phaseNumerator / index.triple, red = Math.min(index.rgbMax, index.rgbMax * hslChannel(temp2, temp1, hNormalized + phaseThird)), green = Math.min(index.rgbMax, index.rgbMax * hslChannel(temp2, temp1, hNormalized)), blue = Math.min(index.rgbMax, index.rgbMax * hslChannel(temp2, temp1, hNormalized - phaseThird));
1372
896
  return { r: Math.round(red), g: Math.round(green), b: Math.round(blue) };
1373
897
  }
1374
898
  function getRandomRgbColor(min) {
@@ -1383,21 +907,18 @@ function getStyleFromRgb(color, hdr, opacity) {
1383
907
  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
908
  return getCachedStyle(key, () => (hdr ? getHdrStyleFromRgb(color, opacity) : getSdrStyleFromRgb(color, opacity)));
1385
909
  }
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()})`;
910
+ function getHdrStyleFromRgb(color, opacity, peakNits = index.maxNits) {
911
+ const headroom = peakNits / sdrReferenceWhiteNits;
912
+ return `color(display-p3 ${((color.r / index.rgbMax) * headroom).toString()} ${((color.g / index.rgbMax) * headroom).toString()} ${((color.b / index.rgbMax) * headroom).toString()} / ${(opacity ?? index.defaultOpacity).toString()})`;
1388
913
  }
1389
914
  function getSdrStyleFromRgb(color, opacity) {
1390
915
  return `rgba(${color.r.toString()}, ${color.g.toString()}, ${color.b.toString()}, ${(opacity ?? index.defaultOpacity).toString()})`;
1391
916
  }
1392
917
  function getStyleFromHsl(color, hdr, opacity) {
1393
918
  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()})`;
919
+ return getCachedStyle(key, () => hdr
920
+ ? getStyleFromRgb(hslToRgb(color), true, opacity)
921
+ : `hsla(${color.h.toString()}, ${color.s.toString()}%, ${color.l.toString()}%, ${op.toString()})`);
1401
922
  }
1402
923
  function getHslFromAnimation(animation) {
1403
924
  return animation === undefined
@@ -1470,7 +991,7 @@ class RenderManager {
1470
991
  return;
1471
992
  }
1472
993
  this.draw(ctx => {
1473
- clear(ctx, this.#canvasManager.size);
994
+ ctx.clearRect(index.originPoint.x, index.originPoint.y, this.#canvasManager.size.width, this.#canvasManager.size.height);
1474
995
  });
1475
996
  }
1476
997
  clear() {
@@ -1532,7 +1053,7 @@ class RenderManager {
1532
1053
  plugin.drawParticleSetup?.(context, particle, delta);
1533
1054
  }
1534
1055
  this.#applyPreDrawUpdaters(context, particle, radius, opacity, colorStyles, transform);
1535
- drawParticle({
1056
+ this.#drawParticle({
1536
1057
  container,
1537
1058
  context,
1538
1059
  particle,
@@ -1551,7 +1072,7 @@ class RenderManager {
1551
1072
  drawParticlePlugins(particle, delta) {
1552
1073
  this.draw(ctx => {
1553
1074
  for (const plugin of this.#drawParticlePlugins) {
1554
- drawParticlePlugin(ctx, plugin, particle, delta);
1075
+ this.#drawParticlePlugin(ctx, plugin, particle, delta);
1555
1076
  }
1556
1077
  });
1557
1078
  }
@@ -1651,12 +1172,19 @@ class RenderManager {
1651
1172
  }
1652
1173
  paintBase(baseColor) {
1653
1174
  this.draw(ctx => {
1654
- paintBase(ctx, this.#canvasManager.size, baseColor);
1175
+ ctx.fillStyle = baseColor ?? "rgba(0,0,0,0)";
1176
+ ctx.fillRect(index.originPoint.x, index.originPoint.y, this.#canvasManager.size.width, this.#canvasManager.size.height);
1655
1177
  });
1656
1178
  }
1657
1179
  paintImage(image, opacity) {
1658
1180
  this.draw(ctx => {
1659
- paintImage(ctx, this.#canvasManager.size, image, opacity);
1181
+ if (!image) {
1182
+ return;
1183
+ }
1184
+ const prevAlpha = ctx.globalAlpha;
1185
+ ctx.globalAlpha = opacity;
1186
+ ctx.drawImage(image, index.originPoint.x, index.originPoint.y, this.#canvasManager.size.width, this.#canvasManager.size.height);
1187
+ ctx.globalAlpha = prevAlpha;
1660
1188
  });
1661
1189
  }
1662
1190
  setContext(context) {
@@ -1670,15 +1198,15 @@ class RenderManager {
1670
1198
  }
1671
1199
  stop() {
1672
1200
  this.draw(ctx => {
1673
- clear(ctx, this.#canvasManager.size);
1201
+ ctx.clearRect(index.originPoint.x, index.originPoint.y, this.#canvasManager.size.width, this.#canvasManager.size.height);
1674
1202
  });
1675
1203
  }
1676
- #applyPostDrawUpdaters = particle => {
1204
+ #applyPostDrawUpdaters(particle) {
1677
1205
  for (const updater of this.#postDrawUpdaters) {
1678
1206
  updater.afterDraw?.(particle);
1679
1207
  }
1680
- };
1681
- #applyPreDrawUpdaters = (ctx, particle, radius, zOpacity, colorStyles, transform) => {
1208
+ }
1209
+ #applyPreDrawUpdaters(ctx, particle, radius, zOpacity, colorStyles, transform) {
1682
1210
  for (const updater of this.#preDrawUpdaters) {
1683
1211
  if (updater.getColorStyles) {
1684
1212
  const { fill, stroke } = updater.getColorStyles(particle, ctx, radius, zOpacity);
@@ -1697,8 +1225,114 @@ class RenderManager {
1697
1225
  }
1698
1226
  updater.beforeDraw?.(particle);
1699
1227
  }
1700
- };
1701
- #getPluginParticleColors = particle => {
1228
+ }
1229
+ #drawAfterEffect(drawer, data) {
1230
+ if (!drawer?.drawAfter) {
1231
+ return;
1232
+ }
1233
+ const { particle } = data;
1234
+ if (!particle.effect) {
1235
+ return;
1236
+ }
1237
+ drawer.drawAfter(data);
1238
+ }
1239
+ #drawBeforeEffect(drawer, data) {
1240
+ if (!drawer?.drawBefore) {
1241
+ return;
1242
+ }
1243
+ const { particle } = data;
1244
+ if (!particle.effect) {
1245
+ return;
1246
+ }
1247
+ drawer.drawBefore(data);
1248
+ }
1249
+ #drawParticle(data) {
1250
+ const { container, context, particle, delta, colorStyles, radius, opacity, transform } = data, { effectDrawers, shapeDrawers } = container, pos = particle.getPosition(), transformData = particle.getTransformData(transform), drawScale = index.defaultZoom, drawPosition = {
1251
+ x: pos.x,
1252
+ y: pos.y,
1253
+ };
1254
+ context.setTransform(transformData.a, transformData.b, transformData.c, transformData.d, pos.x, pos.y);
1255
+ if (colorStyles.fill) {
1256
+ context.fillStyle = colorStyles.fill;
1257
+ }
1258
+ const fillEnabled = !!particle.fillEnabled, strokeWidth = particle.strokeWidth ?? index.minStrokeWidth;
1259
+ context.lineWidth = strokeWidth;
1260
+ if (colorStyles.stroke) {
1261
+ context.strokeStyle = colorStyles.stroke;
1262
+ }
1263
+ const drawData = {
1264
+ context,
1265
+ particle,
1266
+ radius,
1267
+ drawRadius: radius * drawScale,
1268
+ opacity,
1269
+ delta,
1270
+ pixelRatio: container.retina.pixelRatio,
1271
+ fill: fillEnabled,
1272
+ stroke: strokeWidth > index.minStrokeWidth,
1273
+ transformData,
1274
+ position: { ...pos },
1275
+ drawPosition,
1276
+ drawScale,
1277
+ };
1278
+ for (const plugin of container.plugins) {
1279
+ plugin.drawParticleTransform?.(drawData);
1280
+ }
1281
+ const effect = particle.effect ? effectDrawers.get(particle.effect) : undefined, shape = particle.shape ? shapeDrawers.get(particle.shape) : undefined;
1282
+ this.#drawBeforeEffect(effect, drawData);
1283
+ this.#drawShapeBeforeDraw(shape, drawData);
1284
+ this.#drawShape(shape, drawData);
1285
+ this.#drawShapeAfterDraw(shape, drawData);
1286
+ this.#drawAfterEffect(effect, drawData);
1287
+ context.resetTransform();
1288
+ }
1289
+ #drawParticlePlugin(context, plugin, particle, delta) {
1290
+ if (!plugin.drawParticle) {
1291
+ return;
1292
+ }
1293
+ plugin.drawParticle(context, particle, delta);
1294
+ }
1295
+ #drawShape(drawer, data) {
1296
+ if (!drawer) {
1297
+ return;
1298
+ }
1299
+ const { context, fill, particle, stroke } = data;
1300
+ if (!particle.shape) {
1301
+ return;
1302
+ }
1303
+ context.beginPath();
1304
+ drawer.draw(data);
1305
+ if (particle.shapeClose) {
1306
+ context.closePath();
1307
+ }
1308
+ if (fill) {
1309
+ context.fill();
1310
+ }
1311
+ if (stroke) {
1312
+ context.stroke();
1313
+ }
1314
+ }
1315
+ #drawShapeAfterDraw(drawer, data) {
1316
+ if (!drawer?.afterDraw) {
1317
+ return;
1318
+ }
1319
+ const { particle } = data;
1320
+ if (!particle.shape) {
1321
+ return;
1322
+ }
1323
+ drawer.afterDraw(data);
1324
+ }
1325
+ #drawShapeBeforeDraw(drawer, data) {
1326
+ if (!drawer?.beforeDraw) {
1327
+ return;
1328
+ }
1329
+ const { particle } = data;
1330
+ if (!particle.shape) {
1331
+ return;
1332
+ }
1333
+ drawer.beforeDraw(data);
1334
+ }
1335
+ #getPluginParticleColors(particle) {
1702
1336
  let fColor, sColor;
1703
1337
  for (const plugin of this.#colorPlugins) {
1704
1338
  if (!fColor && plugin.particleFillColor) {
@@ -1714,7 +1348,7 @@ class RenderManager {
1714
1348
  this.#reusablePluginColors[fColorIndex] = fColor;
1715
1349
  this.#reusablePluginColors[sColorIndex] = sColor;
1716
1350
  return this.#reusablePluginColors;
1717
- };
1351
+ }
1718
1352
  }
1719
1353
 
1720
1354
  const transferredCanvases = new WeakMap(), getTransferredCanvas = (canvas) => {
@@ -1846,6 +1480,7 @@ class CanvasManager {
1846
1480
  obs.observe(element, { attributes: true });
1847
1481
  });
1848
1482
  this.initPlugins();
1483
+ this.#initContext();
1849
1484
  this.render.init();
1850
1485
  }
1851
1486
  initBackground() {
@@ -1855,7 +1490,7 @@ class CanvasManager {
1855
1490
  }
1856
1491
  const elementStyle = element.style, color = rangeColorToRgb(this.#pluginManager, background.color);
1857
1492
  if (color) {
1858
- elementStyle.backgroundColor = getStyleFromRgb(color, container.hdr, background.opacity);
1493
+ elementStyle.backgroundColor = getStyleFromRgb(color, container.actualOptions.hdr, background.opacity);
1859
1494
  }
1860
1495
  else {
1861
1496
  elementStyle.backgroundColor = "";
@@ -1877,7 +1512,7 @@ class CanvasManager {
1877
1512
  if (this.#generated && this.domElement) {
1878
1513
  this.domElement.remove();
1879
1514
  }
1880
- const container = this.#container, domCanvas = isHtmlCanvasElement(canvas) ? canvas : undefined;
1515
+ const domCanvas = isHtmlCanvasElement(canvas) ? canvas : undefined;
1881
1516
  this.domElement = domCanvas;
1882
1517
  this.#generated = domCanvas ? domCanvas.dataset[index.generatedAttribute] === "true" : false;
1883
1518
  this.renderCanvas = domCanvas ? getTransferredCanvas(domCanvas) : canvas;
@@ -1898,26 +1533,6 @@ class CanvasManager {
1898
1533
  const pxRatio = this.#container.retina.pixelRatio, retinaSize = this.size;
1899
1534
  renderCanvas.height = retinaSize.height = standardSize.height * pxRatio;
1900
1535
  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
1536
  }
1922
1537
  resize() {
1923
1538
  const element = this.domElement;
@@ -1985,12 +1600,30 @@ class CanvasManager {
1985
1600
  await container.refresh();
1986
1601
  }
1987
1602
  }
1988
- #applyResizePlugins = () => {
1603
+ #applyResizePlugins() {
1989
1604
  for (const plugin of this.#resizePlugins) {
1990
1605
  plugin.resize?.();
1991
1606
  }
1992
- };
1993
- #initStyle = () => {
1607
+ }
1608
+ #initContext() {
1609
+ const container = this.#container, canSupportHdr = container.actualOptions.hdr &&
1610
+ index.safeMatchMedia("(color-gamut: p3)")?.matches &&
1611
+ index.safeMatchMedia("(dynamic-range: high)")?.matches;
1612
+ this.render.setContextSettings({
1613
+ alpha: true,
1614
+ desynchronized: true,
1615
+ willReadFrequently: false,
1616
+ ...(canSupportHdr
1617
+ ? { colorSpace: "display-p3", colorType: "float16" }
1618
+ : { colorSpace: "srgb" }),
1619
+ });
1620
+ const renderCanvas = this.renderCanvas;
1621
+ if (!renderCanvas) {
1622
+ return;
1623
+ }
1624
+ this.render.setContext(renderCanvas.getContext("2d", this.render.settings));
1625
+ }
1626
+ #initStyle() {
1994
1627
  const element = this.domElement, options = this.#container.actualOptions;
1995
1628
  if (!element) {
1996
1629
  return;
@@ -2011,8 +1644,8 @@ class CanvasManager {
2011
1644
  }
2012
1645
  element.style.setProperty(key, value, "important");
2013
1646
  }
2014
- };
2015
- #repairStyle = () => {
1647
+ }
1648
+ #repairStyle() {
2016
1649
  const element = this.domElement;
2017
1650
  if (!element) {
2018
1651
  return;
@@ -2031,27 +1664,27 @@ class CanvasManager {
2031
1664
  }
2032
1665
  observer.observe(element, { attributes: true });
2033
1666
  });
2034
- };
2035
- #resetOriginalStyle = () => {
1667
+ }
1668
+ #resetOriginalStyle() {
2036
1669
  const element = this.domElement, originalStyle = this.#originalStyle;
2037
1670
  if (!element || !originalStyle) {
2038
1671
  return;
2039
1672
  }
2040
1673
  setStyle(element, originalStyle, true);
2041
- };
2042
- #safeMutationObserver = callback => {
1674
+ }
1675
+ #safeMutationObserver(callback) {
2043
1676
  if (!this.#mutationObserver) {
2044
1677
  return;
2045
1678
  }
2046
1679
  callback(this.#mutationObserver);
2047
- };
2048
- #setFullScreenStyle = () => {
1680
+ }
1681
+ #setFullScreenStyle() {
2049
1682
  const element = this.domElement;
2050
1683
  if (!element) {
2051
1684
  return;
2052
1685
  }
2053
1686
  setStyle(element, index.getFullScreenStyle(this.#container.actualOptions.fullScreen.zIndex), true);
2054
- };
1687
+ }
2055
1688
  }
2056
1689
 
2057
1690
  class EventListeners {
@@ -2076,7 +1709,7 @@ class EventListeners {
2076
1709
  removeListeners() {
2077
1710
  this.#manageListeners(false);
2078
1711
  }
2079
- #handleVisibilityChange = () => {
1712
+ #handleVisibilityChange() {
2080
1713
  const container = this.#container, options = container.actualOptions;
2081
1714
  if (!options.pauseOnBlur) {
2082
1715
  return;
@@ -2094,8 +1727,8 @@ class EventListeners {
2094
1727
  container.draw(true);
2095
1728
  }
2096
1729
  }
2097
- };
2098
- #handleWindowResize = () => {
1730
+ }
1731
+ #handleWindowResize() {
2099
1732
  if (this.#resizeTimeout) {
2100
1733
  clearTimeout(this.#resizeTimeout);
2101
1734
  this.#resizeTimeout = undefined;
@@ -2105,13 +1738,13 @@ class EventListeners {
2105
1738
  await canvas.windowResize();
2106
1739
  };
2107
1740
  this.#resizeTimeout = setTimeout(() => void handleResize(), this.#container.actualOptions.resize.delay * index.millisecondsToSeconds);
2108
- };
2109
- #manageListeners = add => {
1741
+ }
1742
+ #manageListeners(add) {
2110
1743
  const handlers = this.#handlers;
2111
1744
  this.#manageResize(add);
2112
1745
  index.manageListener(document, index.visibilityChangeEvent, handlers.visibilityChange, add, false);
2113
- };
2114
- #manageResize = add => {
1746
+ }
1747
+ #manageResize(add) {
2115
1748
  const handlers = this.#handlers, container = this.#container, options = container.actualOptions;
2116
1749
  if (!options.resize.enable) {
2117
1750
  return;
@@ -2138,7 +1771,7 @@ class EventListeners {
2138
1771
  });
2139
1772
  this.#resizeObserver.observe(canvasEl);
2140
1773
  }
2141
- };
1774
+ }
2142
1775
  }
2143
1776
 
2144
1777
  function loadEffectData(effect, effectOptions, id, reduceDuplicates) {
@@ -2165,6 +1798,131 @@ function fixOutMode(data) {
2165
1798
  data.setCb(data.radius);
2166
1799
  }
2167
1800
  }
1801
+ function normalizeAngle(angle, modulus) {
1802
+ const normalized = angle % modulus;
1803
+ return normalized < index.defaultAngle ? normalized + modulus : normalized;
1804
+ }
1805
+ function initParticleState(particle, id, group) {
1806
+ particle.id = id;
1807
+ particle.group = group;
1808
+ particle.justWarped = false;
1809
+ particle.effectClose = true;
1810
+ particle.shapeClose = true;
1811
+ particle.pathRotation = false;
1812
+ particle.lastPathTime = 0;
1813
+ particle.destroyed = false;
1814
+ particle.unbreakable = false;
1815
+ particle.isRotating = false;
1816
+ particle.rotation = 0;
1817
+ particle.misplaced = false;
1818
+ particle.retina = {
1819
+ maxDistance: {},
1820
+ maxSpeed: 0,
1821
+ moveDrift: 0,
1822
+ moveSpeed: 0,
1823
+ sizeAnimationSpeed: 0,
1824
+ };
1825
+ particle.size = {
1826
+ value: 1,
1827
+ max: 1,
1828
+ min: 1,
1829
+ enable: false,
1830
+ };
1831
+ particle.outType = index.ParticleOutType.normal;
1832
+ particle.ignoresResizeRatio = true;
1833
+ }
1834
+ function resolveParticleOptions(particle, container, pluginManager, overrideOptions) {
1835
+ const mainOptions = container.actualOptions, particlesOptions = loadParticlesOptions(pluginManager, container, mainOptions.particles), reduceDuplicates = particlesOptions.reduceDuplicates;
1836
+ particle.effect = index.itemFromSingleOrMultiple(particlesOptions.effect.type, particle.id, reduceDuplicates);
1837
+ particle.shape = index.itemFromSingleOrMultiple(particlesOptions.shape.type, particle.id, reduceDuplicates);
1838
+ const effectOptions = particlesOptions.effect, shapeOptions = particlesOptions.shape;
1839
+ if (overrideOptions) {
1840
+ if (overrideOptions.effect) {
1841
+ const overrideEffectType = overrideOptions.effect.type;
1842
+ if (overrideEffectType && overrideEffectType !== particle.effect) {
1843
+ const effect = index.itemFromSingleOrMultiple(overrideEffectType, particle.id, reduceDuplicates);
1844
+ if (effect) {
1845
+ particle.effect = effect;
1846
+ }
1847
+ }
1848
+ effectOptions.load(overrideOptions.effect);
1849
+ }
1850
+ if (overrideOptions.shape) {
1851
+ const overrideShapeType = overrideOptions.shape.type;
1852
+ if (overrideShapeType && overrideShapeType !== particle.shape) {
1853
+ const shape = index.itemFromSingleOrMultiple(overrideShapeType, particle.id, reduceDuplicates);
1854
+ if (shape) {
1855
+ particle.shape = shape;
1856
+ }
1857
+ }
1858
+ shapeOptions.load(overrideOptions.shape);
1859
+ }
1860
+ }
1861
+ if (particle.effect === index.randomColorValue) {
1862
+ const availableEffects = [...container.effectDrawers.keys()];
1863
+ particle.effect = availableEffects[Math.floor(index.getRandom() * availableEffects.length)];
1864
+ }
1865
+ if (particle.shape === index.randomColorValue) {
1866
+ const availableShapes = [...container.shapeDrawers.keys()];
1867
+ particle.shape = availableShapes[Math.floor(index.getRandom() * availableShapes.length)];
1868
+ }
1869
+ particle.effectData = particle.effect
1870
+ ? loadEffectData(particle.effect, effectOptions, particle.id, reduceDuplicates)
1871
+ : undefined;
1872
+ particle.shapeData = particle.shape
1873
+ ? loadShapeData(particle.shape, shapeOptions, particle.id, reduceDuplicates)
1874
+ : undefined;
1875
+ particlesOptions.load(overrideOptions);
1876
+ const effectData = particle.effectData, shapeData = particle.shapeData;
1877
+ if (effectData) {
1878
+ particlesOptions.load(effectData.particles);
1879
+ }
1880
+ if (shapeData) {
1881
+ particlesOptions.load(shapeData.particles);
1882
+ }
1883
+ particle.effectClose = effectData?.close ?? particlesOptions.effect.close;
1884
+ particle.shapeClose = shapeData?.close ?? particlesOptions.shape.close;
1885
+ return particlesOptions;
1886
+ }
1887
+ function initParticleDrawers(particle, container) {
1888
+ let effectDrawer, shapeDrawer;
1889
+ if (particle.effect) {
1890
+ effectDrawer = container.effectDrawers.get(particle.effect);
1891
+ }
1892
+ if (effectDrawer?.loadEffect) {
1893
+ effectDrawer.loadEffect(particle);
1894
+ }
1895
+ if (particle.shape) {
1896
+ shapeDrawer = container.shapeDrawers.get(particle.shape);
1897
+ }
1898
+ if (shapeDrawer?.loadShape) {
1899
+ shapeDrawer.loadShape(particle);
1900
+ }
1901
+ const sideCountFunc = shapeDrawer?.getSidesCount;
1902
+ if (sideCountFunc) {
1903
+ particle.sides = sideCountFunc(particle);
1904
+ }
1905
+ }
1906
+ function runUpdaterPreInit(updaters, particle) {
1907
+ for (const updater of updaters) {
1908
+ updater.preInit?.(particle);
1909
+ }
1910
+ }
1911
+ function runUpdaterInit(updaters, particle) {
1912
+ for (const updater of updaters) {
1913
+ updater.init(particle);
1914
+ }
1915
+ }
1916
+ function runDrawerInit(container, particle) {
1917
+ const shapeDrawer = particle.shape ? container.shapeDrawers.get(particle.shape) : undefined, effectDrawer = particle.effect ? container.effectDrawers.get(particle.effect) : undefined;
1918
+ effectDrawer?.particleInit?.(container, particle);
1919
+ shapeDrawer?.particleInit?.(container, particle);
1920
+ }
1921
+ function runParticleCreatedPlugins(container, particle) {
1922
+ for (const plugin of container.particleCreatedPlugins) {
1923
+ plugin.particleCreated?.(particle);
1924
+ }
1925
+ }
2168
1926
  class Particle {
2169
1927
  backColor;
2170
1928
  bubble;
@@ -2300,84 +2058,10 @@ class Particle {
2300
2058
  }
2301
2059
  init(id, position, overrideOptions, group) {
2302
2060
  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) {
2336
- const overrideEffectType = overrideOptions.effect.type;
2337
- if (overrideEffectType && overrideEffectType !== this.effect) {
2338
- const effect = index.itemFromSingleOrMultiple(overrideEffectType, this.id, reduceDuplicates);
2339
- if (effect) {
2340
- this.effect = effect;
2341
- }
2342
- }
2343
- effectOptions.load(overrideOptions.effect);
2344
- }
2345
- if (overrideOptions.shape) {
2346
- const overrideShapeType = overrideOptions.shape.type;
2347
- if (overrideShapeType && overrideShapeType !== this.shape) {
2348
- const shape = index.itemFromSingleOrMultiple(overrideShapeType, this.id, reduceDuplicates);
2349
- if (shape) {
2350
- this.shape = shape;
2351
- }
2352
- }
2353
- shapeOptions.load(overrideOptions.shape);
2354
- }
2355
- }
2356
- if (this.effect === index.randomColorValue) {
2357
- const availableEffects = [...this.#container.effectDrawers.keys()];
2358
- this.effect = availableEffects[Math.floor(index.getRandom() * availableEffects.length)];
2359
- }
2360
- if (this.shape === index.randomColorValue) {
2361
- const availableShapes = [...this.#container.shapeDrawers.keys()];
2362
- this.shape = availableShapes[Math.floor(index.getRandom() * availableShapes.length)];
2363
- }
2364
- this.effectData = this.effect ? loadEffectData(this.effect, effectOptions, this.id, reduceDuplicates) : undefined;
2365
- this.shapeData = this.shape ? loadShapeData(this.shape, shapeOptions, this.id, reduceDuplicates) : undefined;
2366
- particlesOptions.load(overrideOptions);
2367
- const effectData = this.effectData, shapeData = this.shapeData;
2368
- if (effectData) {
2369
- particlesOptions.load(effectData.particles);
2370
- }
2371
- if (shapeData) {
2372
- particlesOptions.load(shapeData.particles);
2373
- }
2374
- this.effectClose = effectData?.close ?? particlesOptions.effect.close;
2375
- this.shapeClose = shapeData?.close ?? particlesOptions.shape.close;
2376
- this.options = particlesOptions;
2061
+ initParticleState(this, id, group);
2062
+ this.options = resolveParticleOptions(this, container, this.#pluginManager, overrideOptions);
2377
2063
  container.retina.initParticle(this);
2378
- for (const updater of container.particleUpdaters) {
2379
- updater.preInit?.(this);
2380
- }
2064
+ runUpdaterPreInit(container.particleUpdaters, this);
2381
2065
  this.bubble = {
2382
2066
  inRange: false,
2383
2067
  };
@@ -2390,32 +2074,11 @@ class Particle {
2390
2074
  this.velocity = this.initialVelocity.copy();
2391
2075
  this.zIndexFactor = this.position.z / container.zLayers;
2392
2076
  this.sides = 24;
2393
- let effectDrawer, shapeDrawer;
2394
- if (this.effect) {
2395
- effectDrawer = container.effectDrawers.get(this.effect);
2396
- }
2397
- if (effectDrawer?.loadEffect) {
2398
- effectDrawer.loadEffect(this);
2399
- }
2400
- if (this.shape) {
2401
- shapeDrawer = container.shapeDrawers.get(this.shape);
2402
- }
2403
- if (shapeDrawer?.loadShape) {
2404
- shapeDrawer.loadShape(this);
2405
- }
2406
- const sideCountFunc = shapeDrawer?.getSidesCount;
2407
- if (sideCountFunc) {
2408
- this.sides = sideCountFunc(this);
2409
- }
2077
+ initParticleDrawers(this, container);
2410
2078
  this.spawning = false;
2411
- for (const updater of container.particleUpdaters) {
2412
- updater.init(this);
2413
- }
2414
- effectDrawer?.particleInit?.(container, this);
2415
- shapeDrawer?.particleInit?.(container, this);
2416
- for (const plugin of container.particleCreatedPlugins) {
2417
- plugin.particleCreated?.(this);
2418
- }
2079
+ runUpdaterInit(container.particleUpdaters, this);
2080
+ runDrawerInit(container, this);
2081
+ runParticleCreatedPlugins(container, this);
2419
2082
  }
2420
2083
  isInsideCanvas(direction) {
2421
2084
  return this.#getInsideCanvasResult({ direction }).inside;
@@ -2429,15 +2092,15 @@ class Particle {
2429
2092
  }
2430
2093
  const angle = this.roll.angle;
2431
2094
  if (this.roll.horizontal && this.roll.vertical) {
2432
- const normalizedAngle = angle % index.doublePI, adjustedAngle = normalizedAngle < index.defaultAngle ? normalizedAngle + index.doublePI : normalizedAngle;
2095
+ const adjustedAngle = normalizeAngle(angle, index.doublePI);
2433
2096
  return adjustedAngle >= Math.PI * index.half && adjustedAngle < Math.PI * index.triple * index.half;
2434
2097
  }
2435
2098
  if (this.roll.horizontal) {
2436
- const normalizedAngle = (angle + Math.PI * index.half) % (Math.PI * index.double), adjustedAngle = normalizedAngle < index.defaultAngle ? normalizedAngle + Math.PI * index.double : normalizedAngle;
2099
+ const adjustedAngle = normalizeAngle(angle + Math.PI * index.half, index.doublePI);
2437
2100
  return adjustedAngle >= Math.PI && adjustedAngle < Math.PI * index.double;
2438
2101
  }
2439
2102
  if (this.roll.vertical) {
2440
- const normalizedAngle = angle % (Math.PI * index.double), adjustedAngle = normalizedAngle < index.defaultAngle ? normalizedAngle + Math.PI * index.double : normalizedAngle;
2103
+ const adjustedAngle = normalizeAngle(angle, index.doublePI);
2441
2104
  return adjustedAngle >= Math.PI && adjustedAngle < Math.PI * index.double;
2442
2105
  }
2443
2106
  return false;
@@ -2450,10 +2113,10 @@ class Particle {
2450
2113
  updater.reset?.(this);
2451
2114
  }
2452
2115
  }
2453
- #calcPosition = (position, zIndex) => {
2116
+ #calcPosition(position, zIndex) {
2454
2117
  let tryCount = index.defaultRetryCount, posVec = position ? index.Vector3d.create(position.x, position.y, zIndex) : undefined;
2455
- const container = this.#container, plugins = container.particlePositionPlugins, outModes = this.options.move.outModes, radius = this.getRadius(), canvasSize = container.canvas.size, abortController = new AbortController(), { signal } = abortController;
2456
- while (!signal.aborted) {
2118
+ const container = this.#container, plugins = container.particlePositionPlugins, outModes = this.options.move.outModes, radius = this.getRadius(), canvasSize = container.canvas.size;
2119
+ for (;;) {
2457
2120
  for (const plugin of plugins) {
2458
2121
  const pluginPos = plugin.particlePosition?.(posVec, this);
2459
2122
  if (pluginPos) {
@@ -2481,9 +2144,8 @@ class Particle {
2481
2144
  tryCount += index.tryCountIncrement;
2482
2145
  posVec = undefined;
2483
2146
  }
2484
- return posVec;
2485
- };
2486
- #calculateVelocity = () => {
2147
+ }
2148
+ #calculateVelocity() {
2487
2149
  const moveOptions = this.options.move, baseVelocity = index.getParticleBaseVelocity(this.direction), res = baseVelocity.copy();
2488
2150
  if (moveOptions.direction === index.MoveDirection.inside || moveOptions.direction === index.MoveDirection.outside) {
2489
2151
  return res;
@@ -2499,8 +2161,8 @@ class Particle {
2499
2161
  res.length *= index.getRandom();
2500
2162
  }
2501
2163
  return res;
2502
- };
2503
- #fixHorizontal = (pos, radius, outMode) => {
2164
+ }
2165
+ #fixHorizontal(pos, radius, outMode) {
2504
2166
  fixOutMode({
2505
2167
  outMode,
2506
2168
  checkModes: [index.OutMode.bounce],
@@ -2509,8 +2171,8 @@ class Particle {
2509
2171
  setCb: (value) => (pos.x += value),
2510
2172
  radius,
2511
2173
  });
2512
- };
2513
- #fixVertical = (pos, radius, outMode) => {
2174
+ }
2175
+ #fixVertical(pos, radius, outMode) {
2514
2176
  fixOutMode({
2515
2177
  outMode,
2516
2178
  checkModes: [index.OutMode.bounce],
@@ -2519,8 +2181,8 @@ class Particle {
2519
2181
  setCb: (value) => (pos.y += value),
2520
2182
  radius,
2521
2183
  });
2522
- };
2523
- #getDefaultInsideCanvasResult = (direction, outMode) => {
2184
+ }
2185
+ #getDefaultInsideCanvasResult(direction, outMode) {
2524
2186
  const radius = this.getRadius(), canvasSize = this.#container.canvas.size, position = this.position, isBounce = outMode === index.OutMode.bounce;
2525
2187
  if (direction === index.OutModeDirection.bottom) {
2526
2188
  return {
@@ -2553,8 +2215,8 @@ class Particle {
2553
2215
  position.x <= canvasSize.width + radius,
2554
2216
  reason: "default",
2555
2217
  };
2556
- };
2557
- #getInsideCanvasCallbackData = (direction, outMode) => {
2218
+ }
2219
+ #getInsideCanvasCallbackData(direction, outMode) {
2558
2220
  return {
2559
2221
  canvasSize: this.#container.canvas.size,
2560
2222
  direction,
@@ -2562,8 +2224,8 @@ class Particle {
2562
2224
  particle: this,
2563
2225
  radius: this.getRadius(),
2564
2226
  };
2565
- };
2566
- #getInsideCanvasResult = (data) => {
2227
+ }
2228
+ #getInsideCanvasResult(data) {
2567
2229
  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;
2568
2230
  if (!shapeCheck && !effectCheck) {
2569
2231
  return defaultResult;
@@ -2578,8 +2240,8 @@ class Particle {
2578
2240
  };
2579
2241
  }
2580
2242
  return shapeResult ?? effectResult ?? defaultResult;
2581
- };
2582
- #getRollColor = color => {
2243
+ }
2244
+ #getRollColor(color) {
2583
2245
  if (!color || !this.roll || (!this.backColor && !this.roll.alter)) {
2584
2246
  return color;
2585
2247
  }
@@ -2593,8 +2255,8 @@ class Particle {
2593
2255
  return alterHsl(color, this.roll.alter.type, this.roll.alter.value);
2594
2256
  }
2595
2257
  return color;
2596
- };
2597
- #initPosition = position => {
2258
+ }
2259
+ #initPosition(position) {
2598
2260
  const container = this.#container, zIndexValue = Math.floor(index.getRangeValue(this.options.zIndex.value)), initialPosition = this.#calcPosition(position, index.clamp(zIndexValue, index.minZ, container.zLayers));
2599
2261
  if (!initialPosition) {
2600
2262
  throw new Error("a valid position cannot be found for particle");
@@ -2617,8 +2279,8 @@ class Particle {
2617
2279
  break;
2618
2280
  }
2619
2281
  this.offset = index.Vector.origin;
2620
- };
2621
- #normalizeInsideCanvasResult = (result, reason) => {
2282
+ }
2283
+ #normalizeInsideCanvasResult(result, reason) {
2622
2284
  if (typeof result === "boolean") {
2623
2285
  return {
2624
2286
  inside: result,
@@ -2630,7 +2292,7 @@ class Particle {
2630
2292
  margin: result.margin,
2631
2293
  reason: result.reason ?? reason,
2632
2294
  };
2633
- };
2295
+ }
2634
2296
  }
2635
2297
 
2636
2298
  class SpatialHashGrid {
@@ -2983,10 +2645,10 @@ class ParticlesManager {
2983
2645
  }
2984
2646
  this.#resizeFactor = undefined;
2985
2647
  }
2986
- #addToPool = (...particles) => {
2648
+ #addToPool(...particles) {
2987
2649
  this.#pool.push(...particles);
2988
- };
2989
- #applyDensity = (options, pluginsCount, group, groupOptions) => {
2650
+ }
2651
+ #applyDensity(options, pluginsCount, group, groupOptions) {
2990
2652
  const numberOptions = options.number;
2991
2653
  if (!numberOptions.density.enable) {
2992
2654
  if (group === undefined) {
@@ -3010,36 +2672,19 @@ class ParticlesManager {
3010
2672
  else if (particlesCount > particlesNumber) {
3011
2673
  this.removeQuantity(particlesCount - particlesNumber, group);
3012
2674
  }
3013
- };
3014
- #createBuckets = (zLayers) => {
2675
+ }
2676
+ #createBuckets(zLayers) {
3015
2677
  const bucketCount = Math.max(Math.floor(zLayers), index.one);
3016
2678
  return Array.from({ length: bucketCount }, () => []);
3017
- };
3018
- #getBucketIndex = (zIndex) => {
2679
+ }
2680
+ #getBucketIndex(zIndex) {
3019
2681
  const maxBucketIndex = this.#zBuckets.length - index.one;
3020
2682
  if (maxBucketIndex <= index.minIndex) {
3021
2683
  return index.minIndex;
3022
2684
  }
3023
2685
  return Math.min(Math.max(Math.floor(zIndex), index.minIndex), maxBucketIndex);
3024
- };
3025
- #getParticleInsertIndex = (bucket, particleId) => {
3026
- let start = index.minIndex, end = bucket.length;
3027
- while (start < end) {
3028
- const middle = Math.floor((start + end) / index.double), middleParticle = bucket[middle];
3029
- if (!middleParticle) {
3030
- end = middle;
3031
- continue;
3032
- }
3033
- if (middleParticle.id < particleId) {
3034
- start = middle + index.one;
3035
- }
3036
- else {
3037
- end = middle;
3038
- }
3039
- }
3040
- return start;
3041
- };
3042
- #initDensityFactor = densityOptions => {
2686
+ }
2687
+ #initDensityFactor(densityOptions) {
3043
2688
  const container = this.#container;
3044
2689
  if (!densityOptions.enable) {
3045
2690
  return index.defaultDensityFactor;
@@ -3049,16 +2694,16 @@ class ParticlesManager {
3049
2694
  return index.defaultDensityFactor;
3050
2695
  }
3051
2696
  return ((canvasSize.width * canvasSize.height) / (densityOptions.height * densityOptions.width * pxRatio ** index.squareExp));
3052
- };
3053
- #insertParticleIntoBucket = (particle) => {
2697
+ }
2698
+ #insertParticleIntoBucket(particle) {
3054
2699
  const bucketIndex = this.#getBucketIndex(particle.position.z), bucket = this.#zBuckets[bucketIndex];
3055
2700
  if (!bucket) {
3056
2701
  return;
3057
2702
  }
3058
- bucket.splice(this.#getParticleInsertIndex(bucket, particle.id), index.empty, particle);
2703
+ bucket.push(particle);
3059
2704
  this.#particleBuckets.set(particle.id, bucketIndex);
3060
- };
3061
- #removeParticle = (index$1, group, override) => {
2705
+ }
2706
+ #removeParticle(index$1, group, override) {
3062
2707
  const particle = this.#array[index$1];
3063
2708
  if (!particle) {
3064
2709
  return false;
@@ -3074,22 +2719,20 @@ class ParticlesManager {
3074
2719
  });
3075
2720
  this.#addToPool(particle);
3076
2721
  return true;
3077
- };
3078
- #removeParticleFromBucket = (particle) => {
2722
+ }
2723
+ #removeParticleFromBucket(particle) {
3079
2724
  const bucketIndex = this.#particleBuckets.get(particle.id) ?? this.#getBucketIndex(particle.position.z), bucket = this.#zBuckets[bucketIndex];
3080
2725
  if (!bucket) {
3081
2726
  this.#particleBuckets.delete(particle.id);
3082
2727
  return;
3083
2728
  }
3084
- const particleIndex = this.#getParticleInsertIndex(bucket, particle.id);
3085
- if (bucket[particleIndex]?.id !== particle.id) {
3086
- this.#particleBuckets.delete(particle.id);
3087
- return;
2729
+ const idx = bucket.findIndex(p => p.id === particle.id);
2730
+ if (idx >= index.minIndex) {
2731
+ bucket.splice(idx, index.deleteCount);
3088
2732
  }
3089
- bucket.splice(particleIndex, index.deleteCount);
3090
2733
  this.#particleBuckets.delete(particle.id);
3091
- };
3092
- #resetBuckets = (zLayers) => {
2734
+ }
2735
+ #resetBuckets(zLayers) {
3093
2736
  const bucketCount = Math.max(Math.floor(zLayers), index.one);
3094
2737
  if (this.#zBuckets.length !== bucketCount) {
3095
2738
  this.#zBuckets = this.#createBuckets(bucketCount);
@@ -3098,8 +2741,8 @@ class ParticlesManager {
3098
2741
  for (const bucket of this.#zBuckets) {
3099
2742
  bucket.length = index.minIndex;
3100
2743
  }
3101
- };
3102
- #updateParticleBucket = (particle) => {
2744
+ }
2745
+ #updateParticleBucket(particle) {
3103
2746
  const newBucketIndex = this.#getBucketIndex(particle.position.z), currentBucketIndex = this.#particleBuckets.get(particle.id);
3104
2747
  if (currentBucketIndex === undefined) {
3105
2748
  this.#insertParticleIntoBucket(particle);
@@ -3110,9 +2753,9 @@ class ParticlesManager {
3110
2753
  }
3111
2754
  const currentBucket = this.#zBuckets[currentBucketIndex];
3112
2755
  if (currentBucket) {
3113
- const particleIndex = this.#getParticleInsertIndex(currentBucket, particle.id);
3114
- if (currentBucket[particleIndex]?.id === particle.id) {
3115
- currentBucket.splice(particleIndex, index.deleteCount);
2756
+ const idx = currentBucket.findIndex(p => p.id === particle.id);
2757
+ if (idx >= index.minIndex) {
2758
+ currentBucket.splice(idx, index.deleteCount);
3116
2759
  }
3117
2760
  }
3118
2761
  const newBucket = this.#zBuckets[newBucketIndex];
@@ -3120,10 +2763,16 @@ class ParticlesManager {
3120
2763
  this.#particleBuckets.set(particle.id, newBucketIndex);
3121
2764
  return;
3122
2765
  }
3123
- newBucket.splice(this.#getParticleInsertIndex(newBucket, particle.id), index.empty, particle);
2766
+ newBucket.push(particle);
2767
+ if (newBucket.length >= index.double) {
2768
+ const prev = newBucket[newBucket.length - index.double];
2769
+ if (prev && particle.id < prev.id) {
2770
+ newBucket.sort((a, b) => a.id - b.id);
2771
+ }
2772
+ }
3124
2773
  this.#particleBuckets.set(particle.id, newBucketIndex);
3125
- };
3126
- #updateParticlesPhase1 = (delta) => {
2774
+ }
2775
+ #updateParticlesPhase1(delta) {
3127
2776
  const particlesToDelete = new Set(), resizeFactor = this.#resizeFactor;
3128
2777
  for (const particle of this.#array) {
3129
2778
  if (resizeFactor && !particle.ignoresResizeRatio) {
@@ -3149,8 +2798,8 @@ class ParticlesManager {
3149
2798
  this.grid.insert(particle);
3150
2799
  }
3151
2800
  return particlesToDelete;
3152
- };
3153
- #updateParticlesPhase2 = (delta, particlesToDelete) => {
2801
+ }
2802
+ #updateParticlesPhase2(delta, particlesToDelete) {
3154
2803
  for (const particle of this.#array) {
3155
2804
  if (particle.destroyed) {
3156
2805
  particlesToDelete.add(particle);
@@ -3166,7 +2815,7 @@ class ParticlesManager {
3166
2815
  }
3167
2816
  this.#updateParticleBucket(particle);
3168
2817
  }
3169
- };
2818
+ }
3170
2819
  }
3171
2820
 
3172
2821
  class Retina {
@@ -3528,7 +3177,7 @@ class Container {
3528
3177
  }
3529
3178
  return refresh;
3530
3179
  }
3531
- #nextFrame = (timestamp) => {
3180
+ #nextFrame(timestamp) {
3532
3181
  try {
3533
3182
  if (!this.#smooth &&
3534
3183
  this.#lastFrameTime !== undefined &&
@@ -3556,7 +3205,7 @@ class Container {
3556
3205
  catch (e) {
3557
3206
  index.getLogger().error("error in animation loop", e);
3558
3207
  }
3559
- };
3208
+ }
3560
3209
  }
3561
3210
 
3562
3211
  exports.Container = Container;