@tsparticles/preset-squares 4.1.2 → 4.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,5 +1,5 @@
1
1
  (function(g){g.__tsParticlesInternals=g.__tsParticlesInternals||{};g.__tsParticlesInternals.bundles=g.__tsParticlesInternals.bundles||{};g.__tsParticlesInternals.effects=g.__tsParticlesInternals.effects||{};g.__tsParticlesInternals.engine=g.__tsParticlesInternals.engine||{};g.__tsParticlesInternals.interactions=g.__tsParticlesInternals.interactions||{};g.__tsParticlesInternals.palettes=g.__tsParticlesInternals.palettes||{};g.__tsParticlesInternals.paths=g.__tsParticlesInternals.paths||{};g.__tsParticlesInternals.plugins=g.__tsParticlesInternals.plugins||{};g.__tsParticlesInternals.plugins=g.__tsParticlesInternals.plugins||{};g.__tsParticlesInternals.plugins.emittersShapes=g.__tsParticlesInternals.plugins.emittersShapes||{};g.__tsParticlesInternals.presets=g.__tsParticlesInternals.presets||{};g.__tsParticlesInternals.shapes=g.__tsParticlesInternals.shapes||{};g.__tsParticlesInternals.updaters=g.__tsParticlesInternals.updaters||{};g.__tsParticlesInternals.utils=g.__tsParticlesInternals.utils||{};g.__tsParticlesInternals.canvas=g.__tsParticlesInternals.canvas||{};g.__tsParticlesInternals.canvas=g.__tsParticlesInternals.canvas||{};g.__tsParticlesInternals.canvas.utils=g.__tsParticlesInternals.canvas.utils||{};g.__tsParticlesInternals.path=g.__tsParticlesInternals.path||{};g.__tsParticlesInternals.path=g.__tsParticlesInternals.path||{};g.__tsParticlesInternals.path.utils=g.__tsParticlesInternals.path.utils||{};var __tsProxyFactory=typeof Proxy!=="undefined"?function(obj){return new Proxy(obj,{get:function(target,key){if(!(key in target)){target[key]={};}return target[key];}});}:function(obj){return obj;};g.__tsParticlesInternals.bundles=__tsProxyFactory(g.__tsParticlesInternals.bundles);g.__tsParticlesInternals.effects=__tsProxyFactory(g.__tsParticlesInternals.effects);g.__tsParticlesInternals.interactions=__tsProxyFactory(g.__tsParticlesInternals.interactions);g.__tsParticlesInternals.palettes=__tsProxyFactory(g.__tsParticlesInternals.palettes);g.__tsParticlesInternals.paths=__tsProxyFactory(g.__tsParticlesInternals.paths);g.__tsParticlesInternals.plugins=__tsProxyFactory(g.__tsParticlesInternals.plugins);g.__tsParticlesInternals.plugins.emittersShapes=__tsProxyFactory(g.__tsParticlesInternals.plugins.emittersShapes);g.__tsParticlesInternals.presets=__tsProxyFactory(g.__tsParticlesInternals.presets);g.__tsParticlesInternals.shapes=__tsProxyFactory(g.__tsParticlesInternals.shapes);g.__tsParticlesInternals.updaters=__tsProxyFactory(g.__tsParticlesInternals.updaters);g.__tsParticlesInternals.utils=__tsProxyFactory(g.__tsParticlesInternals.utils);g.__tsParticlesInternals.canvas=__tsProxyFactory(g.__tsParticlesInternals.canvas);g.__tsParticlesInternals.path=__tsProxyFactory(g.__tsParticlesInternals.path);g.tsparticlesInternalExports=g.tsparticlesInternalExports||{};})(typeof globalThis!=="undefined"?globalThis:typeof window!=="undefined"?window:this);
2
- /* Preset v4.1.2 */
2
+ /* Preset v4.2.0 */
3
3
  (function (global, factory) {
4
4
  typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
5
5
  typeof define === 'function' && define.amd ? define(['exports'], factory) :
@@ -15,7 +15,7 @@
15
15
  b: 0,
16
16
  c: 0,
17
17
  d: 1,
18
- }, randomColorValue = "random", double = 2, doublePI = Math.PI * double, defaultFps = 60, generatedTrue = "true", generatedFalse = "false", canvasTag = "canvas", defaultRetryCount = 0, squareExp = 2, spatialHashGridCellSize = 100, defaultRemoveQuantity = 1, defaultRatio = 1, defaultReduceFactor = 1, inverseFactorNumerator = 1, rgbMax = 255, hMax = 360, sMax = 100, lMax = 100, hMin = 0, sMin = 0, hPhase = 60, empty = 0, quarter = 0.25, threeQuarter = half + quarter, defaultTransformValue = 1, minimumSize = 0, zIndexFactorOffset = 1, defaultOpacity$1 = 1, removeDeleteCount = 1, removeMinIndex = 0, defaultFpsLimit = 120, minFpsLimit = 0, canvasFirstIndex = 0, loadRandomFactor = 10000, loadMinIndex = 0, one = 1, none = 0, decayOffset = 1, tryCountIncrement = 1, minZ = 0, minLimit = 0, countOffset = 1, minCount = 0, minIndex = 0, defaultDensityFactor = 1, deleteCount = 1, defaultAngle = 0, identity = 1, minStrokeWidth = 0, lFactor = 1, lMin = 0, triple = 3, sextuple = 6, sNormalizedOffset = 1, phaseNumerator = 1, defaultRgbMin = 0, defaultVelocity = 0, defaultLoops = 0, defaultTime = 0, defaultZoom = 1;
18
+ }, randomColorValue = "random", double = 2, doublePI = Math.PI * double, defaultFps = 60, generatedTrue = "true", generatedFalse = "false", canvasTag = "canvas", defaultRetryCount = 0, squareExp = 2, spatialHashGridCellSize = 100, defaultRemoveQuantity = 1, defaultRatio = 1, defaultReduceFactor = 1, inverseFactorNumerator = 1, rgbMax = 255, hMax = 360, sMax = 100, lMax = 100, hMin = 0, sMin = 0, hPhase = 60, empty = 0, quarter = 0.25, threeQuarter = half + quarter, defaultTransformValue = 1, minimumSize = 0, zIndexFactorOffset = 1, defaultOpacity$1 = 1, removeDeleteCount = 1, removeMinIndex = 0, defaultFpsLimit = 120, minFpsLimit = 0, canvasFirstIndex = 0, loadRandomFactor = 10000, loadMinIndex = 0, one = 1, none = 0, decayOffset = 1, tryCountIncrement = 1, minZ = 0, minLimit = 0, countOffset = 1, minCount = 0, minIndex = 0, defaultDensityFactor = 1, deleteCount = 1, defaultAngle = 0, identity = 1, minStrokeWidth = 0, lFactor = 1, lMin = 0, maxNits = 400, triple = 3, sextuple = 6, sNormalizedOffset = 1, phaseNumerator = 1, defaultRgbMin = 0, defaultVelocity = 0, defaultLoops = 0, defaultTime = 0, defaultZoom = 1;
19
19
 
20
20
  var MoveDirection;
21
21
  (function (MoveDirection) {
@@ -82,11 +82,6 @@
82
82
  div(n) {
83
83
  return Vector3d.create(this.x / n, this.y / n, this.z / n);
84
84
  }
85
- divTo(n) {
86
- this.x /= n;
87
- this.y /= n;
88
- this.z /= n;
89
- }
90
85
  getLengthSq() {
91
86
  return this.x ** squareExp + this.y ** squareExp;
92
87
  }
@@ -281,27 +276,6 @@
281
276
  };
282
277
  }
283
278
 
284
- var AnimationMode;
285
- (function (AnimationMode) {
286
- AnimationMode["auto"] = "auto";
287
- AnimationMode["increase"] = "increase";
288
- AnimationMode["decrease"] = "decrease";
289
- AnimationMode["random"] = "random";
290
- })(AnimationMode || (AnimationMode = {}));
291
-
292
- var AnimationStatus;
293
- (function (AnimationStatus) {
294
- AnimationStatus["increasing"] = "increasing";
295
- AnimationStatus["decreasing"] = "decreasing";
296
- })(AnimationStatus || (AnimationStatus = {}));
297
-
298
- var DestroyType;
299
- (function (DestroyType) {
300
- DestroyType["none"] = "none";
301
- DestroyType["max"] = "max";
302
- DestroyType["min"] = "min";
303
- })(DestroyType || (DestroyType = {}));
304
-
305
279
  var OutModeDirection;
306
280
  (function (OutModeDirection) {
307
281
  OutModeDirection["bottom"] = "bottom";
@@ -316,67 +290,7 @@
316
290
  PixelMode["percent"] = "percent";
317
291
  })(PixelMode || (PixelMode = {}));
318
292
 
319
- var StartValueType;
320
- (function (StartValueType) {
321
- StartValueType["max"] = "max";
322
- StartValueType["min"] = "min";
323
- StartValueType["random"] = "random";
324
- })(StartValueType || (StartValueType = {}));
325
-
326
293
  const minRadius = 0;
327
- function memoize(fn, options) {
328
- const cache = new Map(), stableStringify = (obj, seen = new WeakSet()) => {
329
- if (obj === null) {
330
- return "null";
331
- }
332
- const t = typeof obj;
333
- if (t === "undefined") {
334
- return "undefined";
335
- }
336
- if (t === "number" || t === "boolean" || t === "string") {
337
- return JSON.stringify(obj);
338
- }
339
- if (t === "function") {
340
- try {
341
- const fn = obj;
342
- return fn.toString();
343
- }
344
- catch {
345
- return '"[Function]"';
346
- }
347
- }
348
- if (t === "symbol") {
349
- try {
350
- return obj.toString();
351
- }
352
- catch {
353
- return '"[Symbol]"';
354
- }
355
- }
356
- if (Array.isArray(obj)) {
357
- return `[${obj.map(i => stableStringify(i, seen)).join(",")}]`;
358
- }
359
- if (seen.has(obj)) {
360
- return '"[Circular]"';
361
- }
362
- seen.add(obj);
363
- const keys = Object.keys(obj).sort();
364
- return `{${keys.map(k => `${JSON.stringify(k)}:${stableStringify(obj[k], seen)}`).join(",")}}`;
365
- }, defaultKeyer = (args) => stableStringify(args), makeKey = (args) => (defaultKeyer(args));
366
- return (...args) => {
367
- const key = makeKey(args), now = Date.now(), entry = cache.get(key);
368
- if (entry !== undefined) {
369
- {
370
- cache.delete(key);
371
- cache.set(key, { value: entry.value, ts: entry.ts });
372
- return entry.value;
373
- }
374
- }
375
- const result = fn(...args);
376
- cache.set(key, { value: result, ts: now });
377
- return result;
378
- };
379
- }
380
294
  function hasMatchMedia() {
381
295
  return typeof matchMedia !== "undefined";
382
296
  }
@@ -398,11 +312,8 @@
398
312
  function isInArray(value, array) {
399
313
  return value === array || (isArray(array) && array.includes(value));
400
314
  }
401
- function arrayRandomIndex(array) {
402
- return Math.floor(getRandom() * array.length);
403
- }
404
315
  function itemFromArray(array, index, useIndex = true) {
405
- return array[index !== undefined && useIndex ? index % array.length : arrayRandomIndex(array)];
316
+ return array[index !== undefined && useIndex ? index % array.length : Math.floor(getRandom() * array.length)];
406
317
  }
407
318
  function isPointInside(point, size, offset, radius, direction) {
408
319
  return areBoundsInside(calculateBounds(point, minRadius), size, offset);
@@ -486,56 +397,6 @@
486
397
  function itemFromSingleOrMultiple(obj, index, useIndex) {
487
398
  return isArray(obj) ? itemFromArray(obj, index, useIndex) : obj;
488
399
  }
489
- function initParticleNumericAnimationValue(options, pxRatio) {
490
- const valueRange = options.value, animationOptions = options.animation, res = {
491
- delayTime: getRangeValue(animationOptions.delay) * millisecondsToSeconds,
492
- enable: animationOptions.enable,
493
- value: getRangeValue(options.value) * pxRatio,
494
- max: getRangeMax(valueRange) * pxRatio,
495
- min: getRangeMin(valueRange) * pxRatio,
496
- loops: 0,
497
- maxLoops: getRangeValue(animationOptions.count),
498
- time: 0,
499
- }, decayOffset = 1;
500
- if (animationOptions.enable) {
501
- res.decay = decayOffset - getRangeValue(animationOptions.decay);
502
- switch (animationOptions.mode) {
503
- case AnimationMode.increase:
504
- res.status = AnimationStatus.increasing;
505
- break;
506
- case AnimationMode.decrease:
507
- res.status = AnimationStatus.decreasing;
508
- break;
509
- case AnimationMode.random:
510
- res.status = getRandom() >= half ? AnimationStatus.increasing : AnimationStatus.decreasing;
511
- break;
512
- }
513
- const autoStatus = animationOptions.mode === AnimationMode.auto;
514
- switch (animationOptions.startValue) {
515
- case StartValueType.min:
516
- res.value = res.min;
517
- if (autoStatus) {
518
- res.status = AnimationStatus.increasing;
519
- }
520
- break;
521
- case StartValueType.max:
522
- res.value = res.max;
523
- if (autoStatus) {
524
- res.status = AnimationStatus.decreasing;
525
- }
526
- break;
527
- case StartValueType.random:
528
- default:
529
- res.value = randomInRangeValue(res);
530
- if (autoStatus) {
531
- res.status = getRandom() >= half ? AnimationStatus.increasing : AnimationStatus.decreasing;
532
- }
533
- break;
534
- }
535
- }
536
- res.initialValue = res.value;
537
- return res;
538
- }
539
400
  function getPositionOrSize(positionOrSize, canvasSize) {
540
401
  const isPercent = positionOrSize.mode === PixelMode.percent;
541
402
  if (!isPercent) {
@@ -559,80 +420,6 @@
559
420
  function getPosition(position, canvasSize) {
560
421
  return getPositionOrSize(position, canvasSize);
561
422
  }
562
- function getSize(size, canvasSize) {
563
- return getPositionOrSize(size, canvasSize);
564
- }
565
- function checkDestroy(particle, destroyType, value, minValue, maxValue) {
566
- switch (destroyType) {
567
- case DestroyType.max:
568
- if (value >= maxValue) {
569
- particle.destroy();
570
- }
571
- break;
572
- case DestroyType.min:
573
- if (value <= minValue) {
574
- particle.destroy();
575
- }
576
- break;
577
- }
578
- }
579
- function updateAnimation(particle, data, changeDirection, destroyType, delta) {
580
- const minLoops = 0, minDelay = 0, identity = 1, minVelocity = 0, minDecay = 1;
581
- if (particle.destroyed ||
582
- !data.enable ||
583
- ((data.maxLoops ?? minLoops) > minLoops && (data.loops ?? minLoops) > (data.maxLoops ?? minLoops))) {
584
- return;
585
- }
586
- const velocity = (data.velocity ?? minVelocity) * delta.factor, minValue = data.min, maxValue = data.max, decay = data.decay ?? minDecay;
587
- data.time ??= 0;
588
- if ((data.delayTime ?? minDelay) > minDelay && data.time < (data.delayTime ?? minDelay)) {
589
- data.time += delta.value;
590
- }
591
- if ((data.delayTime ?? minDelay) > minDelay && data.time < (data.delayTime ?? minDelay)) {
592
- return;
593
- }
594
- switch (data.status) {
595
- case AnimationStatus.increasing:
596
- data.value += velocity;
597
- break;
598
- case AnimationStatus.decreasing:
599
- data.value -= velocity;
600
- break;
601
- }
602
- if (data.velocity && decay !== identity) {
603
- data.velocity *= decay;
604
- }
605
- switch (data.status) {
606
- case AnimationStatus.increasing:
607
- if (data.value >= maxValue) {
608
- if (changeDirection) {
609
- data.status = AnimationStatus.decreasing;
610
- }
611
- else {
612
- data.value -= maxValue;
613
- }
614
- data.loops ??= minLoops;
615
- data.loops++;
616
- }
617
- break;
618
- case AnimationStatus.decreasing:
619
- if (data.value <= minValue) {
620
- if (changeDirection) {
621
- data.status = AnimationStatus.increasing;
622
- }
623
- else {
624
- data.value += maxValue;
625
- }
626
- data.loops ??= minLoops;
627
- data.loops++;
628
- }
629
- break;
630
- }
631
- checkDestroy(particle, destroyType, data.value, minValue, maxValue);
632
- if (!particle.destroyed) {
633
- data.value = clamp(data.value, minValue, maxValue);
634
- }
635
- }
636
423
  function cloneStyle(style) {
637
424
  const clonedStyle = safeDocument().createElement("div").style;
638
425
  for (const key in style) {
@@ -654,30 +441,34 @@
654
441
  }
655
442
  return clonedStyle;
656
443
  }
657
- function computeFullScreenStyle(zIndex) {
658
- const fullScreenStyle = safeDocument().createElement("div").style, radix = 10, style = {
659
- width: "100%",
660
- height: "100%",
661
- margin: "0",
662
- padding: "0",
663
- borderWidth: "0",
664
- position: "fixed",
665
- zIndex: zIndex.toString(radix),
666
- "z-index": zIndex.toString(radix),
667
- top: "0",
668
- left: "0",
669
- "pointer-events": "none",
670
- };
671
- for (const key in style) {
672
- const value = style[key];
673
- if (value === undefined) {
674
- continue;
444
+ let _cachedZIndex, _cachedStyle;
445
+ function getFullScreenStyle(zIndex) {
446
+ if (_cachedZIndex !== zIndex || !_cachedStyle) {
447
+ _cachedZIndex = zIndex;
448
+ const fullScreenStyle = safeDocument().createElement("div").style, radix = 10, style = {
449
+ width: "100%",
450
+ height: "100%",
451
+ margin: "0",
452
+ padding: "0",
453
+ borderWidth: "0",
454
+ position: "fixed",
455
+ zIndex: zIndex.toString(radix),
456
+ "z-index": zIndex.toString(radix),
457
+ top: "0",
458
+ left: "0",
459
+ "pointer-events": "none",
460
+ };
461
+ for (const key in style) {
462
+ const value = style[key];
463
+ if (value === undefined) {
464
+ continue;
465
+ }
466
+ fullScreenStyle.setProperty(key, value);
675
467
  }
676
- fullScreenStyle.setProperty(key, value);
468
+ _cachedStyle = fullScreenStyle;
677
469
  }
678
- return fullScreenStyle;
470
+ return _cachedStyle;
679
471
  }
680
- const getFullScreenStyle = memoize(computeFullScreenStyle);
681
472
  function manageListener(element, event, handler, add, options) {
682
473
  if (add) {
683
474
  let addOptions = { passive: true };
@@ -1004,7 +795,7 @@
1004
795
  return this.#domArray;
1005
796
  }
1006
797
  get version() {
1007
- return "4.1.2";
798
+ return "4.2.0";
1008
799
  }
1009
800
  addEventListener(type, listener) {
1010
801
  this.#eventDispatcher.addEventListener(type, listener);
@@ -1174,6 +965,14 @@
1174
965
  RotateDirection["random"] = "random";
1175
966
  })(RotateDirection || (RotateDirection = {}));
1176
967
 
968
+ var AnimationMode;
969
+ (function (AnimationMode) {
970
+ AnimationMode["auto"] = "auto";
971
+ AnimationMode["increase"] = "increase";
972
+ AnimationMode["decrease"] = "decrease";
973
+ AnimationMode["random"] = "random";
974
+ })(AnimationMode || (AnimationMode = {}));
975
+
1177
976
  var LimitMode;
1178
977
  (function (LimitMode) {
1179
978
  LimitMode["delete"] = "delete";
@@ -1195,6 +994,13 @@
1195
994
  AlterType["enlighten"] = "enlighten";
1196
995
  })(AlterType || (AlterType = {}));
1197
996
 
997
+ var DestroyType;
998
+ (function (DestroyType) {
999
+ DestroyType["none"] = "none";
1000
+ DestroyType["max"] = "max";
1001
+ DestroyType["min"] = "min";
1002
+ })(DestroyType || (DestroyType = {}));
1003
+
1198
1004
  var GradientType;
1199
1005
  (function (GradientType) {
1200
1006
  GradientType["linear"] = "linear";
@@ -1209,160 +1015,121 @@
1209
1015
  ParticleOutType["outside"] = "outside";
1210
1016
  })(ParticleOutType || (ParticleOutType = {}));
1211
1017
 
1212
- var EasingType;
1213
- (function (EasingType) {
1214
- EasingType["easeInBack"] = "ease-in-back";
1215
- EasingType["easeInBounce"] = "ease-in-bounce";
1216
- EasingType["easeInCirc"] = "ease-in-circ";
1217
- EasingType["easeInCubic"] = "ease-in-cubic";
1218
- EasingType["easeInElastic"] = "ease-in-elastic";
1219
- EasingType["easeInExpo"] = "ease-in-expo";
1220
- EasingType["easeInGaussian"] = "ease-in-gaussian";
1221
- EasingType["easeInLinear"] = "ease-in-linear";
1222
- EasingType["easeInQuad"] = "ease-in-quad";
1223
- EasingType["easeInQuart"] = "ease-in-quart";
1224
- EasingType["easeInQuint"] = "ease-in-quint";
1225
- EasingType["easeInSigmoid"] = "ease-in-sigmoid";
1226
- EasingType["easeInSine"] = "ease-in-sine";
1227
- EasingType["easeInSmoothstep"] = "ease-in-smoothstep";
1228
- EasingType["easeOutBack"] = "ease-out-back";
1229
- EasingType["easeOutBounce"] = "ease-out-bounce";
1230
- EasingType["easeOutCirc"] = "ease-out-circ";
1231
- EasingType["easeOutCubic"] = "ease-out-cubic";
1232
- EasingType["easeOutElastic"] = "ease-out-elastic";
1233
- EasingType["easeOutExpo"] = "ease-out-expo";
1234
- EasingType["easeOutGaussian"] = "ease-out-gaussian";
1235
- EasingType["easeOutLinear"] = "ease-out-linear";
1236
- EasingType["easeOutQuad"] = "ease-out-quad";
1237
- EasingType["easeOutQuart"] = "ease-out-quart";
1238
- EasingType["easeOutQuint"] = "ease-out-quint";
1239
- EasingType["easeOutSigmoid"] = "ease-out-sigmoid";
1240
- EasingType["easeOutSine"] = "ease-out-sine";
1241
- EasingType["easeOutSmoothstep"] = "ease-out-smoothstep";
1242
- EasingType["easeInOutBack"] = "ease-in-out-back";
1243
- EasingType["easeInOutBounce"] = "ease-in-out-bounce";
1244
- EasingType["easeInOutCirc"] = "ease-in-out-circ";
1245
- EasingType["easeInOutCubic"] = "ease-in-out-cubic";
1246
- EasingType["easeInOutElastic"] = "ease-in-out-elastic";
1247
- EasingType["easeInOutExpo"] = "ease-in-out-expo";
1248
- EasingType["easeInOutGaussian"] = "ease-in-out-gaussian";
1249
- EasingType["easeInOutLinear"] = "ease-in-out-linear";
1250
- EasingType["easeInOutQuad"] = "ease-in-out-quad";
1251
- EasingType["easeInOutQuart"] = "ease-in-out-quart";
1252
- EasingType["easeInOutQuint"] = "ease-in-out-quint";
1253
- EasingType["easeInOutSigmoid"] = "ease-in-out-sigmoid";
1254
- EasingType["easeInOutSine"] = "ease-in-out-sine";
1255
- EasingType["easeInOutSmoothstep"] = "ease-in-out-smoothstep";
1256
- })(EasingType || (EasingType = {}));
1018
+ var StartValueType;
1019
+ (function (StartValueType) {
1020
+ StartValueType["max"] = "max";
1021
+ StartValueType["min"] = "min";
1022
+ StartValueType["random"] = "random";
1023
+ })(StartValueType || (StartValueType = {}));
1024
+
1025
+ var AnimationStatus;
1026
+ (function (AnimationStatus) {
1027
+ AnimationStatus["increasing"] = "increasing";
1028
+ AnimationStatus["decreasing"] = "decreasing";
1029
+ })(AnimationStatus || (AnimationStatus = {}));
1257
1030
 
1258
- class AnimationOptions {
1259
- count;
1260
- decay;
1261
- delay;
1262
- enable;
1263
- speed;
1264
- sync;
1265
- constructor() {
1266
- this.count = 0;
1267
- this.enable = false;
1268
- this.speed = 1;
1269
- this.decay = 0;
1270
- this.delay = 0;
1271
- this.sync = false;
1272
- }
1031
+ class OptionLoader {
1273
1032
  load(data) {
1274
1033
  if (isNull(data)) {
1275
1034
  return;
1276
1035
  }
1277
- if (data.count !== undefined) {
1278
- this.count = setRangeValue(data.count);
1279
- }
1280
- if (data.enable !== undefined) {
1281
- this.enable = data.enable;
1282
- }
1283
- if (data.speed !== undefined) {
1284
- this.speed = setRangeValue(data.speed);
1285
- }
1286
- if (data.decay !== undefined) {
1287
- this.decay = setRangeValue(data.decay);
1288
- }
1289
- if (data.delay !== undefined) {
1290
- this.delay = setRangeValue(data.delay);
1291
- }
1292
- if (data.sync !== undefined) {
1293
- this.sync = data.sync;
1294
- }
1036
+ this.doLoad(data);
1295
1037
  }
1296
1038
  }
1297
- class RangedAnimationOptions extends AnimationOptions {
1298
- mode;
1299
- startValue;
1300
- constructor() {
1301
- super();
1302
- this.mode = AnimationMode.auto;
1303
- this.startValue = StartValueType.random;
1039
+ function loadOptions(options, ...sourceOptionsArr) {
1040
+ for (const sourceOptions of sourceOptionsArr) {
1041
+ options.load(sourceOptions);
1304
1042
  }
1305
- load(data) {
1306
- super.load(data);
1307
- if (isNull(data)) {
1308
- return;
1309
- }
1310
- if (data.mode !== undefined) {
1311
- this.mode = data.mode;
1312
- }
1313
- if (data.startValue !== undefined) {
1314
- this.startValue = data.startValue;
1315
- }
1043
+ }
1044
+
1045
+ function loadProperty(obj, key, value) {
1046
+ if (value !== undefined) {
1047
+ obj[key] = value;
1048
+ }
1049
+ }
1050
+ function loadRangeProperty(obj, key, value) {
1051
+ if (value !== undefined) {
1052
+ obj[key] = setRangeValue(value);
1053
+ }
1054
+ }
1055
+ function loadNestedProperty(obj, key, value) {
1056
+ if (value !== undefined) {
1057
+ obj[key].load(value);
1058
+ }
1059
+ }
1060
+ function loadLazyProperty(obj, key, value, factory) {
1061
+ if (value !== undefined) {
1062
+ const objRecord = obj;
1063
+ objRecord[key] ??= factory();
1064
+ objRecord[key].load(value);
1065
+ }
1066
+ }
1067
+ function loadOptionProperty(obj, key, optionClass, ...sources) {
1068
+ const objRecord = obj;
1069
+ objRecord[key] ??= new optionClass();
1070
+ const target = objRecord[key];
1071
+ for (const source of sources) {
1072
+ target.load(source?.[key]);
1073
+ }
1074
+ }
1075
+
1076
+ class AnimationOptions extends OptionLoader {
1077
+ count = 0;
1078
+ decay = 0;
1079
+ delay = 0;
1080
+ enable = false;
1081
+ speed = 1;
1082
+ sync = false;
1083
+ doLoad(data) {
1084
+ loadRangeProperty(this, "count", data.count);
1085
+ loadProperty(this, "enable", data.enable);
1086
+ loadRangeProperty(this, "speed", data.speed);
1087
+ loadRangeProperty(this, "decay", data.decay);
1088
+ loadRangeProperty(this, "delay", data.delay);
1089
+ loadProperty(this, "sync", data.sync);
1090
+ }
1091
+ }
1092
+ class RangedAnimationOptions extends AnimationOptions {
1093
+ mode = AnimationMode.auto;
1094
+ startValue = StartValueType.random;
1095
+ doLoad(data) {
1096
+ super.doLoad(data);
1097
+ loadProperty(this, "mode", data.mode);
1098
+ loadProperty(this, "startValue", data.startValue);
1316
1099
  }
1317
1100
  }
1318
1101
 
1319
1102
  class ColorAnimation extends AnimationOptions {
1320
1103
  max;
1321
1104
  min;
1322
- offset;
1105
+ offset = 0;
1106
+ sync = true;
1323
1107
  constructor(min, max) {
1324
1108
  super();
1325
1109
  this.min = min;
1326
1110
  this.max = max;
1327
- this.offset = 0;
1328
- this.sync = true;
1329
1111
  }
1330
- load(data) {
1331
- super.load(data);
1332
- if (isNull(data)) {
1333
- return;
1334
- }
1335
- if (data.max !== undefined) {
1336
- this.max = data.max;
1337
- }
1338
- if (data.min !== undefined) {
1339
- this.min = data.min;
1340
- }
1341
- if (data.offset !== undefined) {
1342
- this.offset = setRangeValue(data.offset);
1343
- }
1112
+ doLoad(data) {
1113
+ super.doLoad(data);
1114
+ loadProperty(this, "max", data.max);
1115
+ loadProperty(this, "min", data.min);
1116
+ loadRangeProperty(this, "offset", data.offset);
1344
1117
  }
1345
1118
  }
1346
1119
 
1347
- class HslAnimation {
1120
+ class HslAnimation extends OptionLoader {
1348
1121
  h = new ColorAnimation(hMin, hMax);
1349
1122
  l = new ColorAnimation(lMin, lMax);
1350
1123
  s = new ColorAnimation(sMin, sMax);
1351
- load(data) {
1352
- if (isNull(data)) {
1353
- return;
1354
- }
1124
+ doLoad(data) {
1355
1125
  this.h.load(data.h);
1356
1126
  this.s.load(data.s);
1357
1127
  this.l.load(data.l);
1358
1128
  }
1359
1129
  }
1360
1130
 
1361
- class OptionsColor {
1362
- value;
1363
- constructor() {
1364
- this.value = "";
1365
- }
1131
+ class OptionsColor extends OptionLoader {
1132
+ value = "";
1366
1133
  static create(source, data) {
1367
1134
  const color = new OptionsColor();
1368
1135
  color.load(source);
@@ -1376,10 +1143,7 @@
1376
1143
  }
1377
1144
  return color;
1378
1145
  }
1379
- load(data) {
1380
- if (isNull(data)) {
1381
- return;
1382
- }
1146
+ doLoad(data) {
1383
1147
  if (!isNull(data.value)) {
1384
1148
  this.value = data.value;
1385
1149
  }
@@ -1387,11 +1151,7 @@
1387
1151
  }
1388
1152
 
1389
1153
  class AnimatableColor extends OptionsColor {
1390
- animation;
1391
- constructor() {
1392
- super();
1393
- this.animation = new HslAnimation();
1394
- }
1154
+ animation = new HslAnimation();
1395
1155
  static create(source, data) {
1396
1156
  const color = new AnimatableColor();
1397
1157
  color.load(source);
@@ -1405,11 +1165,8 @@
1405
1165
  }
1406
1166
  return color;
1407
1167
  }
1408
- load(data) {
1409
- super.load(data);
1410
- if (isNull(data)) {
1411
- return;
1412
- }
1168
+ doLoad(data) {
1169
+ super.doLoad(data);
1413
1170
  const colorAnimation = data.animation;
1414
1171
  if (colorAnimation !== undefined) {
1415
1172
  if (colorAnimation.enable === undefined) {
@@ -1422,100 +1179,53 @@
1422
1179
  }
1423
1180
  }
1424
1181
 
1425
- class Background {
1182
+ class Background extends OptionLoader {
1426
1183
  color;
1427
- image;
1428
- opacity;
1429
- position;
1430
- repeat;
1431
- size;
1184
+ image = "";
1185
+ opacity = 1;
1186
+ position = "";
1187
+ repeat = "";
1188
+ size = "";
1432
1189
  constructor() {
1190
+ super();
1433
1191
  this.color = new OptionsColor();
1434
1192
  this.color.value = "";
1435
- this.image = "";
1436
- this.position = "";
1437
- this.repeat = "";
1438
- this.size = "";
1439
- this.opacity = 1;
1440
1193
  }
1441
- load(data) {
1442
- if (isNull(data)) {
1443
- return;
1444
- }
1194
+ doLoad(data) {
1445
1195
  if (data.color !== undefined) {
1446
1196
  this.color = OptionsColor.create(this.color, data.color);
1447
1197
  }
1448
- if (data.image !== undefined) {
1449
- this.image = data.image;
1450
- }
1451
- if (data.position !== undefined) {
1452
- this.position = data.position;
1453
- }
1454
- if (data.repeat !== undefined) {
1455
- this.repeat = data.repeat;
1456
- }
1457
- if (data.size !== undefined) {
1458
- this.size = data.size;
1459
- }
1460
- if (data.opacity !== undefined) {
1461
- this.opacity = data.opacity;
1462
- }
1198
+ loadProperty(this, "image", data.image);
1199
+ loadProperty(this, "position", data.position);
1200
+ loadProperty(this, "repeat", data.repeat);
1201
+ loadProperty(this, "size", data.size);
1202
+ loadProperty(this, "opacity", data.opacity);
1463
1203
  }
1464
1204
  }
1465
1205
 
1466
- class FullScreen {
1467
- enable;
1468
- zIndex;
1469
- constructor() {
1470
- this.enable = true;
1471
- this.zIndex = 0;
1472
- }
1473
- load(data) {
1474
- if (isNull(data)) {
1475
- return;
1476
- }
1477
- if (data.enable !== undefined) {
1478
- this.enable = data.enable;
1479
- }
1480
- if (data.zIndex !== undefined) {
1481
- this.zIndex = data.zIndex;
1482
- }
1206
+ class FullScreen extends OptionLoader {
1207
+ enable = true;
1208
+ zIndex = 0;
1209
+ doLoad(data) {
1210
+ loadProperty(this, "enable", data.enable);
1211
+ loadProperty(this, "zIndex", data.zIndex);
1483
1212
  }
1484
1213
  }
1485
1214
 
1486
- class ResizeEvent {
1487
- delay;
1488
- enable;
1489
- constructor() {
1490
- this.delay = 0.5;
1491
- this.enable = true;
1492
- }
1493
- load(data) {
1494
- if (isNull(data)) {
1495
- return;
1496
- }
1497
- if (data.delay !== undefined) {
1498
- this.delay = data.delay;
1499
- }
1500
- if (data.enable !== undefined) {
1501
- this.enable = data.enable;
1502
- }
1215
+ class ResizeEvent extends OptionLoader {
1216
+ delay = 0.5;
1217
+ enable = true;
1218
+ doLoad(data) {
1219
+ loadProperty(this, "delay", data.delay);
1220
+ loadProperty(this, "enable", data.enable);
1503
1221
  }
1504
1222
  }
1505
1223
 
1506
- class Effect {
1507
- close;
1508
- options;
1509
- type;
1510
- constructor() {
1511
- this.close = true;
1512
- this.options = {};
1513
- this.type = [];
1514
- }
1515
- load(data) {
1516
- if (isNull(data)) {
1517
- return;
1518
- }
1224
+ class Effect extends OptionLoader {
1225
+ close = true;
1226
+ options = {};
1227
+ type = [];
1228
+ doLoad(data) {
1519
1229
  const options = data.options;
1520
1230
  if (options !== undefined) {
1521
1231
  for (const effect in options) {
@@ -1525,128 +1235,62 @@
1525
1235
  }
1526
1236
  }
1527
1237
  }
1528
- if (data.close !== undefined) {
1529
- this.close = data.close;
1530
- }
1531
- if (data.type !== undefined) {
1532
- this.type = data.type;
1533
- }
1238
+ loadProperty(this, "close", data.close);
1239
+ loadProperty(this, "type", data.type);
1534
1240
  }
1535
1241
  }
1536
1242
 
1537
- class Fill {
1243
+ class Fill extends OptionLoader {
1538
1244
  color;
1539
- enable;
1540
- opacity;
1541
- constructor() {
1542
- this.enable = true;
1543
- this.opacity = 1;
1544
- }
1545
- load(data) {
1546
- if (isNull(data)) {
1547
- return;
1548
- }
1245
+ enable = true;
1246
+ opacity = 1;
1247
+ doLoad(data) {
1549
1248
  if (data.color !== undefined) {
1550
1249
  this.color = AnimatableColor.create(this.color, data.color);
1551
1250
  }
1552
- if (data.enable !== undefined) {
1553
- this.enable = data.enable;
1554
- }
1555
- if (data.opacity !== undefined) {
1556
- this.opacity = setRangeValue(data.opacity);
1557
- }
1251
+ loadProperty(this, "enable", data.enable);
1252
+ loadRangeProperty(this, "opacity", data.opacity);
1558
1253
  }
1559
1254
  }
1560
1255
 
1561
- class MoveAngle {
1562
- offset;
1563
- value;
1564
- constructor() {
1565
- this.offset = 0;
1566
- this.value = 90;
1567
- }
1568
- load(data) {
1569
- if (isNull(data)) {
1570
- return;
1571
- }
1572
- if (data.offset !== undefined) {
1573
- this.offset = setRangeValue(data.offset);
1574
- }
1575
- if (data.value !== undefined) {
1576
- this.value = setRangeValue(data.value);
1577
- }
1256
+ class MoveAngle extends OptionLoader {
1257
+ offset = 0;
1258
+ value = 90;
1259
+ doLoad(data) {
1260
+ loadRangeProperty(this, "offset", data.offset);
1261
+ loadRangeProperty(this, "value", data.value);
1578
1262
  }
1579
1263
  }
1580
1264
 
1581
- class MoveCenter {
1582
- mode;
1583
- radius;
1584
- x;
1585
- y;
1586
- constructor() {
1587
- this.x = 50;
1588
- this.y = 50;
1589
- this.mode = PixelMode.percent;
1590
- this.radius = 0;
1591
- }
1592
- load(data) {
1593
- if (isNull(data)) {
1594
- return;
1595
- }
1596
- if (data.x !== undefined) {
1597
- this.x = data.x;
1598
- }
1599
- if (data.y !== undefined) {
1600
- this.y = data.y;
1601
- }
1602
- if (data.mode !== undefined) {
1603
- this.mode = data.mode;
1604
- }
1605
- if (data.radius !== undefined) {
1606
- this.radius = data.radius;
1607
- }
1265
+ class MoveCenter extends OptionLoader {
1266
+ mode = PixelMode.percent;
1267
+ radius = 0;
1268
+ x = 50;
1269
+ y = 50;
1270
+ doLoad(data) {
1271
+ loadProperty(this, "x", data.x);
1272
+ loadProperty(this, "y", data.y);
1273
+ loadProperty(this, "mode", data.mode);
1274
+ loadProperty(this, "radius", data.radius);
1608
1275
  }
1609
1276
  }
1610
1277
 
1611
- class MoveGravity {
1612
- acceleration;
1613
- enable;
1614
- inverse;
1615
- maxSpeed;
1616
- constructor() {
1617
- this.acceleration = 9.81;
1618
- this.enable = false;
1619
- this.inverse = false;
1620
- this.maxSpeed = 50;
1621
- }
1622
- load(data) {
1623
- if (isNull(data)) {
1624
- return;
1625
- }
1626
- if (data.acceleration !== undefined) {
1627
- this.acceleration = setRangeValue(data.acceleration);
1628
- }
1629
- if (data.enable !== undefined) {
1630
- this.enable = data.enable;
1631
- }
1632
- if (data.inverse !== undefined) {
1633
- this.inverse = data.inverse;
1634
- }
1635
- if (data.maxSpeed !== undefined) {
1636
- this.maxSpeed = setRangeValue(data.maxSpeed);
1637
- }
1278
+ class MoveGravity extends OptionLoader {
1279
+ acceleration = 9.81;
1280
+ enable = false;
1281
+ inverse = false;
1282
+ maxSpeed = 50;
1283
+ doLoad(data) {
1284
+ loadRangeProperty(this, "acceleration", data.acceleration);
1285
+ loadProperty(this, "enable", data.enable);
1286
+ loadProperty(this, "inverse", data.inverse);
1287
+ loadRangeProperty(this, "maxSpeed", data.maxSpeed);
1638
1288
  }
1639
1289
  }
1640
1290
 
1641
- class ValueWithRandom {
1642
- value;
1643
- constructor() {
1644
- this.value = 0;
1645
- }
1646
- load(data) {
1647
- if (isNull(data)) {
1648
- return;
1649
- }
1291
+ class ValueWithRandom extends OptionLoader {
1292
+ value = 0;
1293
+ doLoad(data) {
1650
1294
  if (!isNull(data.value)) {
1651
1295
  this.value = setRangeValue(data.value);
1652
1296
  }
@@ -1654,51 +1298,25 @@
1654
1298
  }
1655
1299
  class AnimationValueWithRandom extends ValueWithRandom {
1656
1300
  animation = new AnimationOptions();
1657
- load(data) {
1658
- super.load(data);
1659
- if (isNull(data)) {
1660
- return;
1661
- }
1662
- const animation = data.animation;
1663
- if (animation !== undefined) {
1664
- this.animation.load(animation);
1665
- }
1301
+ doLoad(data) {
1302
+ super.doLoad(data);
1303
+ loadNestedProperty(this, "animation", data.animation);
1666
1304
  }
1667
1305
  }
1668
1306
  class RangedAnimationValueWithRandom extends AnimationValueWithRandom {
1669
- animation;
1670
- constructor() {
1671
- super();
1672
- this.animation = new RangedAnimationOptions();
1673
- }
1674
- load(data) {
1675
- super.load(data);
1676
- }
1307
+ animation = new RangedAnimationOptions();
1677
1308
  }
1678
1309
 
1679
- class MovePath {
1680
- clamp;
1681
- delay;
1682
- enable;
1310
+ class MovePath extends OptionLoader {
1311
+ clamp = true;
1312
+ delay = new ValueWithRandom();
1313
+ enable = false;
1683
1314
  generator;
1684
- options;
1685
- constructor() {
1686
- this.clamp = true;
1687
- this.delay = new ValueWithRandom();
1688
- this.enable = false;
1689
- this.options = {};
1690
- }
1691
- load(data) {
1692
- if (isNull(data)) {
1693
- return;
1694
- }
1695
- if (data.clamp !== undefined) {
1696
- this.clamp = data.clamp;
1697
- }
1315
+ options = {};
1316
+ doLoad(data) {
1317
+ loadProperty(this, "clamp", data.clamp);
1698
1318
  this.delay.load(data.delay);
1699
- if (data.enable !== undefined) {
1700
- this.enable = data.enable;
1701
- }
1319
+ loadProperty(this, "enable", data.enable);
1702
1320
  this.generator = data.generator;
1703
1321
  if (data.options) {
1704
1322
  this.options = deepExtend(this.options, data.options);
@@ -1706,19 +1324,13 @@
1706
1324
  }
1707
1325
  }
1708
1326
 
1709
- class OutModes {
1327
+ class OutModes extends OptionLoader {
1710
1328
  bottom;
1711
- default;
1329
+ default = OutMode.out;
1712
1330
  left;
1713
1331
  right;
1714
1332
  top;
1715
- constructor() {
1716
- this.default = OutMode.out;
1717
- }
1718
- load(data) {
1719
- if (isNull(data)) {
1720
- return;
1721
- }
1333
+ doLoad(data) {
1722
1334
  if (data.default !== undefined) {
1723
1335
  this.default = data.default;
1724
1336
  }
@@ -1729,79 +1341,42 @@
1729
1341
  }
1730
1342
  }
1731
1343
 
1732
- class Spin {
1733
- acceleration;
1734
- enable;
1344
+ class Spin extends OptionLoader {
1345
+ acceleration = 0;
1346
+ enable = false;
1735
1347
  position;
1736
- constructor() {
1737
- this.acceleration = 0;
1738
- this.enable = false;
1739
- }
1740
- load(data) {
1741
- if (isNull(data)) {
1742
- return;
1743
- }
1744
- if (data.acceleration !== undefined) {
1745
- this.acceleration = setRangeValue(data.acceleration);
1746
- }
1747
- if (data.enable !== undefined) {
1748
- this.enable = data.enable;
1749
- }
1348
+ doLoad(data) {
1349
+ loadRangeProperty(this, "acceleration", data.acceleration);
1350
+ loadProperty(this, "enable", data.enable);
1750
1351
  if (data.position) {
1751
1352
  this.position = deepExtend({}, data.position);
1752
1353
  }
1753
1354
  }
1754
1355
  }
1755
1356
 
1756
- class Move {
1757
- angle;
1758
- center;
1759
- decay;
1760
- direction;
1761
- distance;
1762
- drift;
1763
- enable;
1764
- gravity;
1765
- outModes;
1766
- path;
1767
- random;
1768
- size;
1769
- speed;
1770
- spin;
1771
- straight;
1772
- vibrate;
1773
- warp;
1774
- constructor() {
1775
- this.angle = new MoveAngle();
1776
- this.center = new MoveCenter();
1777
- this.decay = 0;
1778
- this.distance = {};
1779
- this.direction = MoveDirection.none;
1780
- this.drift = 0;
1781
- this.enable = false;
1782
- this.gravity = new MoveGravity();
1783
- this.path = new MovePath();
1784
- this.outModes = new OutModes();
1785
- this.random = false;
1786
- this.size = false;
1787
- this.speed = 2;
1788
- this.spin = new Spin();
1789
- this.straight = false;
1790
- this.vibrate = false;
1791
- this.warp = false;
1792
- }
1793
- load(data) {
1794
- if (isNull(data)) {
1795
- return;
1796
- }
1357
+ class Move extends OptionLoader {
1358
+ angle = new MoveAngle();
1359
+ center = new MoveCenter();
1360
+ decay = 0;
1361
+ direction = MoveDirection.none;
1362
+ distance = {};
1363
+ drift = 0;
1364
+ enable = false;
1365
+ gravity = new MoveGravity();
1366
+ outModes = new OutModes();
1367
+ path = new MovePath();
1368
+ random = false;
1369
+ size = false;
1370
+ speed = 2;
1371
+ spin = new Spin();
1372
+ straight = false;
1373
+ vibrate = false;
1374
+ warp = false;
1375
+ doLoad(data) {
1797
1376
  this.angle.load(isNumber(data.angle) ? { value: data.angle } : data.angle);
1798
1377
  this.center.load(data.center);
1799
- if (data.decay !== undefined) {
1800
- this.decay = setRangeValue(data.decay);
1801
- }
1802
- if (data.direction !== undefined) {
1803
- this.direction = data.direction;
1804
- }
1378
+ loadRangeProperty(this, "decay", data.decay);
1379
+ loadProperty(this, "direction", data.direction);
1805
1380
  if (data.distance !== undefined) {
1806
1381
  this.distance = isNumber(data.distance)
1807
1382
  ? {
@@ -1810,12 +1385,8 @@
1810
1385
  }
1811
1386
  : { ...data.distance };
1812
1387
  }
1813
- if (data.drift !== undefined) {
1814
- this.drift = setRangeValue(data.drift);
1815
- }
1816
- if (data.enable !== undefined) {
1817
- this.enable = data.enable;
1818
- }
1388
+ loadRangeProperty(this, "drift", data.drift);
1389
+ loadProperty(this, "enable", data.enable);
1819
1390
  this.gravity.load(data.gravity);
1820
1391
  const outModes = data.outModes;
1821
1392
  if (outModes !== undefined) {
@@ -1829,177 +1400,91 @@
1829
1400
  }
1830
1401
  }
1831
1402
  this.path.load(data.path);
1832
- if (data.random !== undefined) {
1833
- this.random = data.random;
1834
- }
1835
- if (data.size !== undefined) {
1836
- this.size = data.size;
1837
- }
1838
- if (data.speed !== undefined) {
1839
- this.speed = setRangeValue(data.speed);
1840
- }
1403
+ loadProperty(this, "random", data.random);
1404
+ loadProperty(this, "size", data.size);
1405
+ loadRangeProperty(this, "speed", data.speed);
1841
1406
  this.spin.load(data.spin);
1842
- if (data.straight !== undefined) {
1843
- this.straight = data.straight;
1844
- }
1845
- if (data.vibrate !== undefined) {
1846
- this.vibrate = data.vibrate;
1847
- }
1848
- if (data.warp !== undefined) {
1849
- this.warp = data.warp;
1850
- }
1407
+ loadProperty(this, "straight", data.straight);
1408
+ loadProperty(this, "vibrate", data.vibrate);
1409
+ loadProperty(this, "warp", data.warp);
1851
1410
  }
1852
1411
  }
1853
1412
 
1854
- class Stroke {
1413
+ class Stroke extends OptionLoader {
1855
1414
  color;
1856
1415
  opacity;
1857
- width;
1858
- constructor() {
1859
- this.width = 0;
1860
- }
1861
- load(data) {
1862
- if (isNull(data)) {
1863
- return;
1864
- }
1416
+ width = 0;
1417
+ doLoad(data) {
1865
1418
  if (data.color !== undefined) {
1866
1419
  this.color = AnimatableColor.create(this.color, data.color);
1867
1420
  }
1868
- if (data.width !== undefined) {
1869
- this.width = setRangeValue(data.width);
1870
- }
1871
- if (data.opacity !== undefined) {
1872
- this.opacity = setRangeValue(data.opacity);
1873
- }
1421
+ loadRangeProperty(this, "width", data.width);
1422
+ loadRangeProperty(this, "opacity", data.opacity);
1874
1423
  }
1875
1424
  }
1876
1425
 
1877
- class Paint {
1426
+ class Paint extends OptionLoader {
1878
1427
  color;
1879
1428
  fill;
1880
1429
  stroke;
1881
- load(data) {
1882
- if (isNull(data)) {
1883
- return;
1884
- }
1430
+ doLoad(data) {
1885
1431
  if (data.color !== undefined) {
1886
1432
  this.color = AnimatableColor.create(this.color, data.color);
1887
1433
  }
1888
- if (data.fill !== undefined) {
1889
- this.fill ??= new Fill();
1890
- this.fill.load(data.fill);
1891
- }
1892
- if (data.stroke !== undefined) {
1893
- this.stroke ??= new Stroke();
1894
- this.stroke.load(data.stroke);
1895
- }
1434
+ loadLazyProperty(this, "fill", data.fill, () => new Fill());
1435
+ loadLazyProperty(this, "stroke", data.stroke, () => new Stroke());
1896
1436
  }
1897
1437
  }
1898
1438
 
1899
1439
  class ParticlesBounceFactor extends ValueWithRandom {
1900
- constructor() {
1901
- super();
1902
- this.value = 1;
1903
- }
1440
+ value = 1;
1904
1441
  }
1905
1442
 
1906
- class ParticlesBounce {
1907
- horizontal;
1908
- vertical;
1909
- constructor() {
1910
- this.horizontal = new ParticlesBounceFactor();
1911
- this.vertical = new ParticlesBounceFactor();
1912
- }
1913
- load(data) {
1914
- if (isNull(data)) {
1915
- return;
1916
- }
1443
+ class ParticlesBounce extends OptionLoader {
1444
+ horizontal = new ParticlesBounceFactor();
1445
+ vertical = new ParticlesBounceFactor();
1446
+ doLoad(data) {
1917
1447
  this.horizontal.load(data.horizontal);
1918
1448
  this.vertical.load(data.vertical);
1919
1449
  }
1920
1450
  }
1921
1451
 
1922
- class ParticlesDensity {
1923
- enable;
1924
- height;
1925
- width;
1926
- constructor() {
1927
- this.enable = false;
1928
- this.width = 1920;
1929
- this.height = 1080;
1930
- }
1931
- load(data) {
1932
- if (isNull(data)) {
1933
- return;
1934
- }
1935
- if (data.enable !== undefined) {
1936
- this.enable = data.enable;
1937
- }
1938
- const width = data.width;
1939
- if (width !== undefined) {
1940
- this.width = width;
1941
- }
1942
- const height = data.height;
1943
- if (height !== undefined) {
1944
- this.height = height;
1945
- }
1452
+ class ParticlesDensity extends OptionLoader {
1453
+ enable = false;
1454
+ height = 1080;
1455
+ width = 1920;
1456
+ doLoad(data) {
1457
+ loadProperty(this, "enable", data.enable);
1458
+ loadProperty(this, "width", data.width);
1459
+ loadProperty(this, "height", data.height);
1946
1460
  }
1947
1461
  }
1948
1462
 
1949
- class ParticlesNumberLimit {
1950
- mode;
1951
- value;
1952
- constructor() {
1953
- this.mode = LimitMode.delete;
1954
- this.value = 0;
1955
- }
1956
- load(data) {
1957
- if (isNull(data)) {
1958
- return;
1959
- }
1960
- if (data.mode !== undefined) {
1961
- this.mode = data.mode;
1962
- }
1963
- if (data.value !== undefined) {
1964
- this.value = data.value;
1965
- }
1463
+ class ParticlesNumberLimit extends OptionLoader {
1464
+ mode = LimitMode.delete;
1465
+ value = 0;
1466
+ doLoad(data) {
1467
+ loadProperty(this, "mode", data.mode);
1468
+ loadProperty(this, "value", data.value);
1966
1469
  }
1967
1470
  }
1968
1471
 
1969
- class ParticlesNumber {
1970
- density;
1971
- limit;
1972
- value;
1973
- constructor() {
1974
- this.density = new ParticlesDensity();
1975
- this.limit = new ParticlesNumberLimit();
1976
- this.value = 0;
1977
- }
1978
- load(data) {
1979
- if (isNull(data)) {
1980
- return;
1981
- }
1472
+ class ParticlesNumber extends OptionLoader {
1473
+ density = new ParticlesDensity();
1474
+ limit = new ParticlesNumberLimit();
1475
+ value = 0;
1476
+ doLoad(data) {
1982
1477
  this.density.load(data.density);
1983
1478
  this.limit.load(data.limit);
1984
- if (data.value !== undefined) {
1985
- this.value = data.value;
1986
- }
1479
+ loadProperty(this, "value", data.value);
1987
1480
  }
1988
1481
  }
1989
1482
 
1990
- class Shape {
1991
- close;
1992
- options;
1993
- type;
1994
- constructor() {
1995
- this.close = true;
1996
- this.options = {};
1997
- this.type = "circle";
1998
- }
1999
- load(data) {
2000
- if (isNull(data)) {
2001
- return;
2002
- }
1483
+ class Shape extends OptionLoader {
1484
+ close = true;
1485
+ options = {};
1486
+ type = "circle";
1487
+ doLoad(data) {
2003
1488
  const options = data.options;
2004
1489
  if (options !== undefined) {
2005
1490
  for (const shape in options) {
@@ -2009,76 +1494,47 @@
2009
1494
  }
2010
1495
  }
2011
1496
  }
2012
- if (data.close !== undefined) {
2013
- this.close = data.close;
2014
- }
2015
- if (data.type !== undefined) {
2016
- this.type = data.type;
2017
- }
1497
+ loadProperty(this, "close", data.close);
1498
+ loadProperty(this, "type", data.type);
2018
1499
  }
2019
1500
  }
2020
1501
 
2021
1502
  class ZIndex extends ValueWithRandom {
2022
- opacityRate;
2023
- sizeRate;
2024
- velocityRate;
2025
- constructor() {
2026
- super();
2027
- this.opacityRate = 1;
2028
- this.sizeRate = 1;
2029
- this.velocityRate = 1;
2030
- }
2031
- load(data) {
2032
- super.load(data);
2033
- if (isNull(data)) {
2034
- return;
2035
- }
2036
- if (data.opacityRate !== undefined) {
2037
- this.opacityRate = data.opacityRate;
2038
- }
2039
- if (data.sizeRate !== undefined) {
2040
- this.sizeRate = data.sizeRate;
2041
- }
2042
- if (data.velocityRate !== undefined) {
2043
- this.velocityRate = data.velocityRate;
2044
- }
1503
+ opacityRate = 1;
1504
+ sizeRate = 1;
1505
+ velocityRate = 1;
1506
+ doLoad(data) {
1507
+ super.doLoad(data);
1508
+ loadProperty(this, "opacityRate", data.opacityRate);
1509
+ loadProperty(this, "sizeRate", data.sizeRate);
1510
+ loadProperty(this, "velocityRate", data.velocityRate);
2045
1511
  }
2046
1512
  }
2047
1513
 
2048
- class ParticlesOptions {
2049
- bounce;
2050
- effect;
2051
- groups;
2052
- move;
2053
- number;
1514
+ class ParticlesOptions extends OptionLoader {
1515
+ bounce = new ParticlesBounce();
1516
+ effect = new Effect();
1517
+ groups = {};
1518
+ move = new Move();
1519
+ number = new ParticlesNumber();
2054
1520
  paint;
2055
1521
  palette;
2056
- reduceDuplicates;
2057
- shape;
2058
- zIndex;
1522
+ reduceDuplicates = false;
1523
+ shape = new Shape();
1524
+ zIndex = new ZIndex();
2059
1525
  #container;
2060
1526
  #pluginManager;
2061
1527
  constructor(pluginManager, container) {
1528
+ super();
2062
1529
  this.#pluginManager = pluginManager;
2063
1530
  this.#container = container;
2064
- this.bounce = new ParticlesBounce();
2065
- this.effect = new Effect();
2066
- this.groups = {};
2067
- this.move = new Move();
2068
- this.number = new ParticlesNumber();
2069
1531
  this.paint = new Paint();
2070
1532
  this.paint.color = new AnimatableColor();
2071
1533
  this.paint.color.value = "#fff";
2072
1534
  this.paint.fill = new Fill();
2073
1535
  this.paint.fill.enable = true;
2074
- this.reduceDuplicates = false;
2075
- this.shape = new Shape();
2076
- this.zIndex = new ZIndex();
2077
1536
  }
2078
- load(data) {
2079
- if (isNull(data)) {
2080
- return;
2081
- }
1537
+ doLoad(data) {
2082
1538
  if (data.palette) {
2083
1539
  this.palette = data.palette;
2084
1540
  this.#importPalette(this.palette);
@@ -2136,7 +1592,7 @@
2136
1592
  }
2137
1593
  }
2138
1594
  }
2139
- #importPalette = (palette) => {
1595
+ #importPalette(palette) {
2140
1596
  const paletteData = this.#pluginManager.getPalette(palette);
2141
1597
  if (!paletteData) {
2142
1598
  return;
@@ -2180,69 +1636,49 @@
2180
1636
  mode: paletteData.blendMode,
2181
1637
  },
2182
1638
  });
2183
- };
2184
- }
2185
-
2186
- function loadOptions(options, ...sourceOptionsArr) {
2187
- for (const sourceOptions of sourceOptionsArr) {
2188
- options.load(sourceOptions);
2189
1639
  }
2190
1640
  }
1641
+
2191
1642
  function loadParticlesOptions(pluginManager, container, ...sourceOptionsArr) {
2192
1643
  const options = new ParticlesOptions(pluginManager, container);
2193
1644
  loadOptions(options, ...sourceOptionsArr);
2194
1645
  return options;
2195
1646
  }
2196
1647
 
2197
- class Options {
2198
- autoPlay;
1648
+ class Options extends OptionLoader {
1649
+ autoPlay = true;
2199
1650
  background;
2200
- clear;
2201
- defaultThemes;
2202
- delay;
2203
- detectRetina;
2204
- duration;
2205
- fpsLimit;
1651
+ clear = true;
1652
+ defaultThemes = {};
1653
+ delay = 0;
1654
+ detectRetina = true;
1655
+ duration = 0;
1656
+ fpsLimit = 120;
2206
1657
  fullScreen;
2207
- hdr;
1658
+ hdr = true;
2208
1659
  key;
2209
1660
  name;
2210
1661
  palette;
2211
1662
  particles;
2212
- pauseOnBlur;
2213
- pauseOnOutsideViewport;
1663
+ pauseOnBlur = true;
1664
+ pauseOnOutsideViewport = true;
2214
1665
  preset;
2215
1666
  resize;
2216
- smooth;
2217
- style;
2218
- zLayers;
1667
+ smooth = false;
1668
+ style = {};
1669
+ zLayers = 100;
2219
1670
  #container;
2220
1671
  #pluginManager;
2221
1672
  constructor(pluginManager, container) {
1673
+ super();
2222
1674
  this.#pluginManager = pluginManager;
2223
1675
  this.#container = container;
2224
- this.autoPlay = true;
2225
1676
  this.background = new Background();
2226
- this.clear = true;
2227
- this.defaultThemes = {};
2228
- this.delay = 0;
2229
1677
  this.fullScreen = new FullScreen();
2230
- this.detectRetina = true;
2231
- this.duration = 0;
2232
- this.fpsLimit = 120;
2233
- this.hdr = true;
2234
1678
  this.particles = loadParticlesOptions(this.#pluginManager, this.#container);
2235
- this.pauseOnBlur = true;
2236
- this.pauseOnOutsideViewport = true;
2237
1679
  this.resize = new ResizeEvent();
2238
- this.smooth = false;
2239
- this.style = {};
2240
- this.zLayers = 100;
2241
1680
  }
2242
- load(data) {
2243
- if (isNull(data)) {
2244
- return;
2245
- }
1681
+ doLoad(data) {
2246
1682
  if (data.preset !== undefined) {
2247
1683
  this.preset = data.preset;
2248
1684
  executeOnSingleOrMultiple(this.preset, preset => {
@@ -2253,44 +1689,18 @@
2253
1689
  this.palette = data.palette;
2254
1690
  this.#importPalette(this.palette);
2255
1691
  }
2256
- if (data.autoPlay !== undefined) {
2257
- this.autoPlay = data.autoPlay;
2258
- }
2259
- if (data.clear !== undefined) {
2260
- this.clear = data.clear;
2261
- }
2262
- if (data.key !== undefined) {
2263
- this.key = data.key;
2264
- }
2265
- if (data.name !== undefined) {
2266
- this.name = data.name;
2267
- }
2268
- if (data.delay !== undefined) {
2269
- this.delay = setRangeValue(data.delay);
2270
- }
2271
- const detectRetina = data.detectRetina;
2272
- if (detectRetina !== undefined) {
2273
- this.detectRetina = detectRetina;
2274
- }
2275
- if (data.duration !== undefined) {
2276
- this.duration = setRangeValue(data.duration);
2277
- }
2278
- const fpsLimit = data.fpsLimit;
2279
- if (fpsLimit !== undefined) {
2280
- this.fpsLimit = fpsLimit;
2281
- }
2282
- if (data.hdr !== undefined) {
2283
- this.hdr = data.hdr;
2284
- }
2285
- if (data.pauseOnBlur !== undefined) {
2286
- this.pauseOnBlur = data.pauseOnBlur;
2287
- }
2288
- if (data.pauseOnOutsideViewport !== undefined) {
2289
- this.pauseOnOutsideViewport = data.pauseOnOutsideViewport;
2290
- }
2291
- if (data.zLayers !== undefined) {
2292
- this.zLayers = data.zLayers;
2293
- }
1692
+ loadProperty(this, "autoPlay", data.autoPlay);
1693
+ loadProperty(this, "clear", data.clear);
1694
+ loadProperty(this, "key", data.key);
1695
+ loadProperty(this, "name", data.name);
1696
+ loadRangeProperty(this, "delay", data.delay);
1697
+ loadProperty(this, "detectRetina", data.detectRetina);
1698
+ loadRangeProperty(this, "duration", data.duration);
1699
+ loadProperty(this, "fpsLimit", data.fpsLimit);
1700
+ loadProperty(this, "hdr", data.hdr);
1701
+ loadProperty(this, "pauseOnBlur", data.pauseOnBlur);
1702
+ loadProperty(this, "pauseOnOutsideViewport", data.pauseOnOutsideViewport);
1703
+ loadProperty(this, "zLayers", data.zLayers);
2294
1704
  this.background.load(data.background);
2295
1705
  const fullScreen = data.fullScreen;
2296
1706
  if (isBoolean(fullScreen)) {
@@ -2302,14 +1712,12 @@
2302
1712
  this.particles.load(data.particles);
2303
1713
  this.resize.load(data.resize);
2304
1714
  this.style = deepExtend(this.style, data.style);
2305
- if (data.smooth !== undefined) {
2306
- this.smooth = data.smooth;
2307
- }
1715
+ loadProperty(this, "smooth", data.smooth);
2308
1716
  this.#pluginManager.plugins.forEach(plugin => {
2309
1717
  plugin.loadOptions(this.#container, this, data);
2310
1718
  });
2311
1719
  }
2312
- #importPalette = palette => {
1720
+ #importPalette(palette) {
2313
1721
  const paletteData = this.#pluginManager.getPalette(palette);
2314
1722
  if (!paletteData) {
2315
1723
  return;
@@ -2326,143 +1734,19 @@
2326
1734
  palette,
2327
1735
  },
2328
1736
  });
2329
- };
2330
- #importPreset = preset => {
2331
- this.load(this.#pluginManager.getPreset(preset));
2332
- };
2333
- }
2334
-
2335
- function paintBase(context, dimension, baseColor) {
2336
- context.fillStyle = baseColor ?? "rgba(0,0,0,0)";
2337
- context.fillRect(originPoint.x, originPoint.y, dimension.width, dimension.height);
2338
- }
2339
- function paintImage(context, dimension, image, opacity) {
2340
- if (!image) {
2341
- return;
2342
- }
2343
- const prevAlpha = context.globalAlpha;
2344
- context.globalAlpha = opacity;
2345
- context.drawImage(image, originPoint.x, originPoint.y, dimension.width, dimension.height);
2346
- context.globalAlpha = prevAlpha;
2347
- }
2348
- function clear(context, dimension) {
2349
- context.clearRect(originPoint.x, originPoint.y, dimension.width, dimension.height);
2350
- }
2351
- function drawParticle(data) {
2352
- const { container, context, particle, delta, colorStyles, radius, opacity, transform } = data, { effectDrawers, shapeDrawers } = container, pos = particle.getPosition(), transformData = particle.getTransformData(transform), drawScale = defaultZoom, drawPosition = {
2353
- x: pos.x,
2354
- y: pos.y,
2355
- };
2356
- context.setTransform(transformData.a, transformData.b, transformData.c, transformData.d, pos.x, pos.y);
2357
- if (colorStyles.fill) {
2358
- context.fillStyle = colorStyles.fill;
2359
- }
2360
- const fillEnabled = !!particle.fillEnabled, strokeWidth = particle.strokeWidth ?? minStrokeWidth;
2361
- context.lineWidth = strokeWidth;
2362
- if (colorStyles.stroke) {
2363
- context.strokeStyle = colorStyles.stroke;
2364
- }
2365
- const drawData = {
2366
- context,
2367
- particle,
2368
- radius,
2369
- drawRadius: radius * drawScale,
2370
- opacity,
2371
- delta,
2372
- pixelRatio: container.retina.pixelRatio,
2373
- fill: fillEnabled,
2374
- stroke: strokeWidth > minStrokeWidth,
2375
- transformData,
2376
- position: { ...pos },
2377
- drawPosition,
2378
- drawScale,
2379
- };
2380
- for (const plugin of container.plugins) {
2381
- plugin.drawParticleTransform?.(drawData);
2382
- }
2383
- const effect = particle.effect ? effectDrawers.get(particle.effect) : undefined, shape = particle.shape ? shapeDrawers.get(particle.shape) : undefined;
2384
- drawBeforeEffect(effect, drawData);
2385
- drawShapeBeforeDraw(shape, drawData);
2386
- drawShape(shape, drawData);
2387
- drawShapeAfterDraw(shape, drawData);
2388
- drawAfterEffect(effect, drawData);
2389
- context.resetTransform();
2390
- }
2391
- function drawAfterEffect(drawer, data) {
2392
- if (!drawer?.drawAfter) {
2393
- return;
2394
- }
2395
- const { particle } = data;
2396
- if (!particle.effect) {
2397
- return;
2398
- }
2399
- drawer.drawAfter(data);
2400
- }
2401
- function drawBeforeEffect(drawer, data) {
2402
- if (!drawer?.drawBefore) {
2403
- return;
2404
- }
2405
- const { particle } = data;
2406
- if (!particle.effect) {
2407
- return;
2408
- }
2409
- drawer.drawBefore(data);
2410
- }
2411
- function drawShape(drawer, data) {
2412
- if (!drawer) {
2413
- return;
2414
- }
2415
- const { context, fill, particle, stroke } = data;
2416
- if (!particle.shape) {
2417
- return;
2418
- }
2419
- context.beginPath();
2420
- drawer.draw(data);
2421
- if (particle.shapeClose) {
2422
- context.closePath();
2423
- }
2424
- if (fill) {
2425
- context.fill();
2426
- }
2427
- if (stroke) {
2428
- context.stroke();
2429
- }
2430
- }
2431
- function drawShapeAfterDraw(drawer, data) {
2432
- if (!drawer?.afterDraw) {
2433
- return;
2434
- }
2435
- const { particle } = data;
2436
- if (!particle.shape) {
2437
- return;
2438
- }
2439
- drawer.afterDraw(data);
2440
- }
2441
- function drawShapeBeforeDraw(drawer, data) {
2442
- if (!drawer?.beforeDraw) {
2443
- return;
2444
- }
2445
- const { particle } = data;
2446
- if (!particle.shape) {
2447
- return;
2448
1737
  }
2449
- drawer.beforeDraw(data);
2450
- }
2451
- function drawParticlePlugin(context, plugin, particle, delta) {
2452
- if (!plugin.drawParticle) {
2453
- return;
1738
+ #importPreset(preset) {
1739
+ this.load(this.#pluginManager.getPreset(preset));
2454
1740
  }
2455
- plugin.drawParticle(context, particle, delta);
2456
1741
  }
2457
1742
 
2458
- const styleCache = new Map(), maxCacheSize = 1000, firstIndex = 0, rgbFixedPrecision = 2, hslFixedPrecision = 2;
1743
+ const styleCache = new Map(), maxStyleCacheSize = 2000, rgbFixedPrecision = 2, hslFixedPrecision = 2, sdrReferenceWhiteNits = 203;
2459
1744
  function getCachedStyle(key, generator) {
2460
1745
  let cached = styleCache.get(key);
2461
1746
  if (!cached) {
2462
1747
  cached = generator();
2463
- if (styleCache.size >= maxCacheSize) {
2464
- const keysToDelete = [...styleCache.keys()].slice(firstIndex, maxCacheSize * half);
2465
- keysToDelete.forEach(k => styleCache.delete(k));
1748
+ if (styleCache.size > maxStyleCacheSize) {
1749
+ styleCache.clear();
2466
1750
  }
2467
1751
  styleCache.set(key, cached);
2468
1752
  }
@@ -2565,34 +1849,35 @@
2565
1849
  function stringToRgb(pluginManager, input) {
2566
1850
  return stringToRgba(pluginManager, input);
2567
1851
  }
1852
+ function hslChannel(temp1, temp2, temp3) {
1853
+ const temp3Min = 0, temp3Max = 1;
1854
+ if (temp3 < temp3Min) {
1855
+ temp3++;
1856
+ }
1857
+ if (temp3 > temp3Max) {
1858
+ temp3--;
1859
+ }
1860
+ if (temp3 * sextuple < temp3Max) {
1861
+ return temp1 + (temp2 - temp1) * sextuple * temp3;
1862
+ }
1863
+ if (temp3 * double < temp3Max) {
1864
+ return temp2;
1865
+ }
1866
+ if (temp3 * triple < temp3Max * double) {
1867
+ const temp3Offset = double / triple;
1868
+ return temp1 + (temp2 - temp1) * (temp3Offset - temp3) * sextuple;
1869
+ }
1870
+ return temp1;
1871
+ }
2568
1872
  function hslToRgb(hsl) {
2569
1873
  const h = ((hsl.h % hMax) + hMax) % hMax, s = Math.max(sMin, Math.min(sMax, hsl.s)), l = Math.max(lMin, Math.min(lMax, hsl.l)), hNormalized = h / hMax, sNormalized = s / sMax, lNormalized = l / lMax;
2570
1874
  if (s === sMin) {
2571
1875
  const grayscaleValue = Math.round(lNormalized * rgbMax);
2572
1876
  return { r: grayscaleValue, g: grayscaleValue, b: grayscaleValue };
2573
1877
  }
2574
- const channel = (temp1, temp2, temp3) => {
2575
- const temp3Min = 0, temp3Max = 1;
2576
- if (temp3 < temp3Min) {
2577
- temp3++;
2578
- }
2579
- if (temp3 > temp3Max) {
2580
- temp3--;
2581
- }
2582
- if (temp3 * sextuple < temp3Max) {
2583
- return temp1 + (temp2 - temp1) * sextuple * temp3;
2584
- }
2585
- if (temp3 * double < temp3Max) {
2586
- return temp2;
2587
- }
2588
- if (temp3 * triple < temp3Max * double) {
2589
- const temp3Offset = double / triple;
2590
- return temp1 + (temp2 - temp1) * (temp3Offset - temp3) * sextuple;
2591
- }
2592
- return temp1;
2593
- }, temp1 = lNormalized < half
1878
+ const temp1 = lNormalized < half
2594
1879
  ? lNormalized * (sNormalizedOffset + sNormalized)
2595
- : lNormalized + sNormalized - lNormalized * sNormalized, temp2 = double * lNormalized - temp1, phaseThird = phaseNumerator / triple, red = Math.min(rgbMax, rgbMax * channel(temp2, temp1, hNormalized + phaseThird)), green = Math.min(rgbMax, rgbMax * channel(temp2, temp1, hNormalized)), blue = Math.min(rgbMax, rgbMax * channel(temp2, temp1, hNormalized - phaseThird));
1880
+ : lNormalized + sNormalized - lNormalized * sNormalized, temp2 = double * lNormalized - temp1, phaseThird = phaseNumerator / triple, red = Math.min(rgbMax, rgbMax * hslChannel(temp2, temp1, hNormalized + phaseThird)), green = Math.min(rgbMax, rgbMax * hslChannel(temp2, temp1, hNormalized)), blue = Math.min(rgbMax, rgbMax * hslChannel(temp2, temp1, hNormalized - phaseThird));
2596
1881
  return { r: Math.round(red), g: Math.round(green), b: Math.round(blue) };
2597
1882
  }
2598
1883
  function getRandomRgbColor(min) {
@@ -2607,21 +1892,18 @@
2607
1892
  const op = opacity ?? defaultOpacity$1, key = `rgb-${color.r.toFixed(rgbFixedPrecision)}-${color.g.toFixed(rgbFixedPrecision)}-${color.b.toFixed(rgbFixedPrecision)}-${hdr ? "hdr" : "sdr"}-${op.toString()}`;
2608
1893
  return getCachedStyle(key, () => (hdr ? getHdrStyleFromRgb(color, opacity) : getSdrStyleFromRgb(color, opacity)));
2609
1894
  }
2610
- function getHdrStyleFromRgb(color, opacity) {
2611
- return `color(display-p3 ${(color.r / rgbMax).toString()} ${(color.g / rgbMax).toString()} ${(color.b / rgbMax).toString()} / ${(opacity ?? defaultOpacity$1).toString()})`;
1895
+ function getHdrStyleFromRgb(color, opacity, peakNits = maxNits) {
1896
+ const headroom = peakNits / sdrReferenceWhiteNits;
1897
+ return `color(display-p3 ${((color.r / rgbMax) * headroom).toString()} ${((color.g / rgbMax) * headroom).toString()} ${((color.b / rgbMax) * headroom).toString()} / ${(opacity ?? defaultOpacity$1).toString()})`;
2612
1898
  }
2613
1899
  function getSdrStyleFromRgb(color, opacity) {
2614
1900
  return `rgba(${color.r.toString()}, ${color.g.toString()}, ${color.b.toString()}, ${(opacity ?? defaultOpacity$1).toString()})`;
2615
1901
  }
2616
1902
  function getStyleFromHsl(color, hdr, opacity) {
2617
1903
  const op = opacity ?? defaultOpacity$1, key = `hsl-${color.h.toFixed(hslFixedPrecision)}-${color.s.toFixed(hslFixedPrecision)}-${color.l.toFixed(hslFixedPrecision)}-${hdr ? "hdr" : "sdr"}-${op.toString()}`;
2618
- return getCachedStyle(key, () => (hdr ? getHdrStyleFromHsl(color, opacity) : getSdrStyleFromHsl(color, opacity)));
2619
- }
2620
- function getHdrStyleFromHsl(color, opacity) {
2621
- return getHdrStyleFromRgb(hslToRgb(color), opacity);
2622
- }
2623
- function getSdrStyleFromHsl(color, opacity) {
2624
- return `hsla(${color.h.toString()}, ${color.s.toString()}%, ${color.l.toString()}%, ${(opacity ?? defaultOpacity$1).toString()})`;
1904
+ return getCachedStyle(key, () => hdr
1905
+ ? getStyleFromRgb(hslToRgb(color), true, opacity)
1906
+ : `hsla(${color.h.toString()}, ${color.s.toString()}%, ${color.l.toString()}%, ${op.toString()})`);
2625
1907
  }
2626
1908
  function getHslFromAnimation(animation) {
2627
1909
  return animation === undefined
@@ -2746,78 +2028,46 @@
2746
2028
  count;
2747
2029
  delay;
2748
2030
  duration;
2749
- wait;
2750
- constructor() {
2751
- this.wait = false;
2752
- }
2031
+ wait = false;
2753
2032
  load(data) {
2754
2033
  if (isNull(data)) {
2755
2034
  return;
2756
2035
  }
2757
- if (data.count !== undefined) {
2758
- this.count = data.count;
2759
- }
2760
- if (data.delay !== undefined) {
2761
- this.delay = setRangeValue(data.delay);
2762
- }
2763
- if (data.duration !== undefined) {
2764
- this.duration = setRangeValue(data.duration);
2765
- }
2766
- if (data.wait !== undefined) {
2767
- this.wait = data.wait;
2768
- }
2036
+ loadProperty(this, "count", data.count);
2037
+ loadRangeProperty(this, "delay", data.delay);
2038
+ loadRangeProperty(this, "duration", data.duration);
2039
+ loadProperty(this, "wait", data.wait);
2769
2040
  }
2770
2041
  }
2771
2042
 
2772
2043
  class EmitterRate {
2773
- delay;
2774
- quantity;
2775
- constructor() {
2776
- this.quantity = 1;
2777
- this.delay = 0.1;
2778
- }
2044
+ delay = 0.1;
2045
+ quantity = 1;
2779
2046
  load(data) {
2780
2047
  if (isNull(data)) {
2781
2048
  return;
2782
2049
  }
2783
- if (data.quantity !== undefined) {
2784
- this.quantity = setRangeValue(data.quantity);
2785
- }
2786
- if (data.delay !== undefined) {
2787
- this.delay = setRangeValue(data.delay);
2788
- }
2050
+ loadRangeProperty(this, "quantity", data.quantity);
2051
+ loadRangeProperty(this, "delay", data.delay);
2789
2052
  }
2790
2053
  }
2791
2054
 
2792
2055
  class EmitterShapeReplace {
2793
- color;
2794
- opacity;
2795
- constructor() {
2796
- this.color = false;
2797
- this.opacity = false;
2798
- }
2056
+ color = false;
2057
+ opacity = false;
2799
2058
  load(data) {
2800
2059
  if (isNull(data)) {
2801
2060
  return;
2802
2061
  }
2803
- if (data.color !== undefined) {
2804
- this.color = data.color;
2805
- }
2806
- if (data.opacity !== undefined) {
2807
- this.opacity = data.opacity;
2808
- }
2062
+ loadProperty(this, "color", data.color);
2063
+ loadProperty(this, "opacity", data.opacity);
2809
2064
  }
2810
2065
  }
2811
2066
 
2812
2067
  class EmitterShape {
2813
- options;
2814
- replace;
2815
- type;
2816
- constructor() {
2817
- this.options = {};
2818
- this.replace = new EmitterShapeReplace();
2819
- this.type = "square";
2820
- }
2068
+ options = {};
2069
+ replace = new EmitterShapeReplace();
2070
+ type = "square";
2821
2071
  load(data) {
2822
2072
  if (isNull(data)) {
2823
2073
  return;
@@ -2826,34 +2076,21 @@
2826
2076
  this.options = deepExtend({}, data.options ?? {});
2827
2077
  }
2828
2078
  this.replace.load(data.replace);
2829
- if (data.type !== undefined) {
2830
- this.type = data.type;
2831
- }
2079
+ loadProperty(this, "type", data.type);
2832
2080
  }
2833
2081
  }
2834
2082
 
2835
2083
  class EmitterSize {
2836
- height;
2837
- mode;
2838
- width;
2839
- constructor() {
2840
- this.mode = PixelMode.percent;
2841
- this.height = 0;
2842
- this.width = 0;
2843
- }
2084
+ height = 0;
2085
+ mode = PixelMode.percent;
2086
+ width = 0;
2844
2087
  load(data) {
2845
2088
  if (isNull(data)) {
2846
2089
  return;
2847
2090
  }
2848
- if (data.mode !== undefined) {
2849
- this.mode = data.mode;
2850
- }
2851
- if (data.height !== undefined) {
2852
- this.height = data.height;
2853
- }
2854
- if (data.width !== undefined) {
2855
- this.width = data.width;
2856
- }
2091
+ loadProperty(this, "mode", data.mode);
2092
+ loadProperty(this, "height", data.height);
2093
+ loadProperty(this, "width", data.width);
2857
2094
  }
2858
2095
  }
2859
2096
 
@@ -2876,50 +2113,35 @@
2876
2113
  }
2877
2114
 
2878
2115
  class Emitter {
2879
- autoPlay;
2116
+ autoPlay = true;
2880
2117
  direction;
2881
2118
  domId;
2882
- fill;
2883
- life;
2119
+ fill = true;
2120
+ life = new EmitterLife();
2884
2121
  name;
2885
2122
  particles;
2886
2123
  position;
2887
- rate;
2888
- shape;
2124
+ rate = new EmitterRate();
2125
+ shape = new EmitterShape();
2889
2126
  size;
2890
- spawn;
2127
+ spawn = new EmitterSpawn();
2891
2128
  spawnFillColor;
2892
2129
  spawnStrokeColor;
2893
- startCount;
2894
- constructor() {
2895
- this.autoPlay = true;
2896
- this.fill = true;
2897
- this.life = new EmitterLife();
2898
- this.rate = new EmitterRate();
2899
- this.shape = new EmitterShape();
2900
- this.spawn = new EmitterSpawn();
2901
- this.startCount = 0;
2902
- }
2130
+ startCount = 0;
2903
2131
  load(data) {
2904
2132
  if (isNull(data)) {
2905
2133
  return;
2906
2134
  }
2907
- if (data.autoPlay !== undefined) {
2908
- this.autoPlay = data.autoPlay;
2909
- }
2135
+ loadProperty(this, "autoPlay", data.autoPlay);
2910
2136
  if (data.size !== undefined) {
2911
2137
  this.size ??= new EmitterSize();
2912
2138
  this.size.load(data.size);
2913
2139
  }
2914
- if (data.direction !== undefined) {
2915
- this.direction = data.direction;
2916
- }
2917
- this.domId = data.domId;
2918
- if (data.fill !== undefined) {
2919
- this.fill = data.fill;
2920
- }
2140
+ loadProperty(this, "direction", data.direction);
2141
+ loadProperty(this, "domId", data.domId);
2142
+ loadProperty(this, "fill", data.fill);
2921
2143
  this.life.load(data.life);
2922
- this.name = data.name;
2144
+ loadProperty(this, "name", data.name);
2923
2145
  this.particles = executeOnSingleOrMultiple(data.particles, particles => {
2924
2146
  return deepExtend({}, particles);
2925
2147
  });
@@ -2943,9 +2165,7 @@
2943
2165
  this.spawnStrokeColor ??= new AnimatableColor();
2944
2166
  this.spawnStrokeColor.load(data.spawnStrokeColor);
2945
2167
  }
2946
- if (data.startCount !== undefined) {
2947
- this.startCount = data.startCount;
2948
- }
2168
+ loadProperty(this, "startCount", data.startCount);
2949
2169
  }
2950
2170
  }
2951
2171
 
@@ -3010,7 +2230,7 @@
3010
2230
  })(EmitterClickMode || (EmitterClickMode = {}));
3011
2231
 
3012
2232
  async function loadEmittersPluginSimple(engine) {
3013
- engine.checkVersion("4.1.2");
2233
+ engine.checkVersion("4.2.0");
3014
2234
  await engine.pluginManager.register(async (e) => {
3015
2235
  const instancesManager = await getEmittersInstancesManager(e);
3016
2236
  await addEmittersShapesManager(e);
@@ -3058,7 +2278,7 @@
3058
2278
  }
3059
2279
 
3060
2280
  async function loadHexColorPlugin(engine) {
3061
- engine.checkVersion("4.1.2");
2281
+ engine.checkVersion("4.2.0");
3062
2282
  await engine.pluginManager.register(e => {
3063
2283
  e.pluginManager.addColorManager("hex", new HexColorManager());
3064
2284
  });
@@ -3127,7 +2347,7 @@
3127
2347
  }
3128
2348
 
3129
2349
  async function loadPaintUpdater(engine) {
3130
- engine.checkVersion("4.1.2");
2350
+ engine.checkVersion("4.2.0");
3131
2351
  await engine.pluginManager.register(e => {
3132
2352
  e.pluginManager.addParticleUpdater("paint", container => {
3133
2353
  return Promise.resolve(new PaintUpdater(e.pluginManager, container));
@@ -3136,58 +2356,156 @@
3136
2356
  }
3137
2357
 
3138
2358
  class RotateAnimation {
3139
- decay;
3140
- enable;
3141
- speed;
3142
- sync;
3143
- constructor() {
3144
- this.enable = false;
3145
- this.speed = 0;
3146
- this.decay = 0;
3147
- this.sync = false;
3148
- }
2359
+ decay = 0;
2360
+ enable = false;
2361
+ speed = 0;
2362
+ sync = false;
3149
2363
  load(data) {
3150
2364
  if (isNull(data)) {
3151
2365
  return;
3152
2366
  }
3153
- if (data.enable !== undefined) {
3154
- this.enable = data.enable;
3155
- }
3156
- if (data.speed !== undefined) {
3157
- this.speed = setRangeValue(data.speed);
2367
+ loadProperty(this, "enable", data.enable);
2368
+ loadRangeProperty(this, "speed", data.speed);
2369
+ loadRangeProperty(this, "decay", data.decay);
2370
+ loadProperty(this, "sync", data.sync);
2371
+ }
2372
+ }
2373
+
2374
+ class Rotate extends ValueWithRandom {
2375
+ animation = new RotateAnimation();
2376
+ direction = RotateDirection.clockwise;
2377
+ path = false;
2378
+ load(data) {
2379
+ if (isNull(data)) {
2380
+ return;
3158
2381
  }
3159
- if (data.decay !== undefined) {
3160
- this.decay = setRangeValue(data.decay);
2382
+ super.load(data);
2383
+ loadProperty(this, "direction", data.direction);
2384
+ this.animation.load(data.animation);
2385
+ loadProperty(this, "path", data.path);
2386
+ }
2387
+ }
2388
+
2389
+ function checkDestroy(particle, destroyType, value, minValue, maxValue) {
2390
+ switch (destroyType) {
2391
+ case DestroyType.max:
2392
+ if (value >= maxValue) {
2393
+ particle.destroy();
2394
+ }
2395
+ break;
2396
+ case DestroyType.min:
2397
+ if (value <= minValue) {
2398
+ particle.destroy();
2399
+ }
2400
+ break;
2401
+ }
2402
+ }
2403
+ function initParticleNumericAnimationValue(options, pxRatio) {
2404
+ const valueRange = options.value, animationOptions = options.animation, res = {
2405
+ delayTime: getRangeValue(animationOptions.delay) * millisecondsToSeconds,
2406
+ enable: animationOptions.enable,
2407
+ value: getRangeValue(options.value) * pxRatio,
2408
+ max: getRangeMax(valueRange) * pxRatio,
2409
+ min: getRangeMin(valueRange) * pxRatio,
2410
+ loops: 0,
2411
+ maxLoops: getRangeValue(animationOptions.count),
2412
+ time: 0,
2413
+ }, decayOffset = 1;
2414
+ if (animationOptions.enable) {
2415
+ res.decay = decayOffset - getRangeValue(animationOptions.decay);
2416
+ switch (animationOptions.mode) {
2417
+ case AnimationMode.increase:
2418
+ res.status = AnimationStatus.increasing;
2419
+ break;
2420
+ case AnimationMode.decrease:
2421
+ res.status = AnimationStatus.decreasing;
2422
+ break;
2423
+ case AnimationMode.random:
2424
+ res.status = getRandom() >= half ? AnimationStatus.increasing : AnimationStatus.decreasing;
2425
+ break;
3161
2426
  }
3162
- if (data.sync !== undefined) {
3163
- this.sync = data.sync;
2427
+ const autoStatus = animationOptions.mode === AnimationMode.auto;
2428
+ switch (animationOptions.startValue) {
2429
+ case StartValueType.min:
2430
+ res.value = res.min;
2431
+ if (autoStatus) {
2432
+ res.status = AnimationStatus.increasing;
2433
+ }
2434
+ break;
2435
+ case StartValueType.max:
2436
+ res.value = res.max;
2437
+ if (autoStatus) {
2438
+ res.status = AnimationStatus.decreasing;
2439
+ }
2440
+ break;
2441
+ case StartValueType.random:
2442
+ default:
2443
+ res.value = randomInRangeValue(res);
2444
+ if (autoStatus) {
2445
+ res.status = getRandom() >= half ? AnimationStatus.increasing : AnimationStatus.decreasing;
2446
+ }
2447
+ break;
3164
2448
  }
3165
2449
  }
2450
+ res.initialValue = res.value;
2451
+ return res;
3166
2452
  }
3167
-
3168
- class Rotate extends ValueWithRandom {
3169
- animation;
3170
- direction;
3171
- path;
3172
- constructor() {
3173
- super();
3174
- this.animation = new RotateAnimation();
3175
- this.direction = RotateDirection.clockwise;
3176
- this.path = false;
3177
- this.value = 0;
2453
+ function updateAnimation(particle, data, changeDirection, destroyType, delta) {
2454
+ const minLoops = 0, minDelay = 0, identity = 1, minVelocity = 0, minDecay = 1;
2455
+ if (particle.destroyed ||
2456
+ !data.enable ||
2457
+ ((data.maxLoops ?? minLoops) > minLoops && (data.loops ?? minLoops) > (data.maxLoops ?? minLoops))) {
2458
+ return;
2459
+ }
2460
+ const velocity = (data.velocity ?? minVelocity) * delta.factor, minValue = data.min, maxValue = data.max, decay = data.decay ?? minDecay;
2461
+ data.time ??= 0;
2462
+ const delayTime = data.delayTime ?? minDelay;
2463
+ if (delayTime > minDelay && data.time < delayTime) {
2464
+ data.time += delta.value;
2465
+ if (data.time < delayTime) {
2466
+ return;
2467
+ }
2468
+ }
2469
+ switch (data.status) {
2470
+ case AnimationStatus.increasing:
2471
+ data.value += velocity;
2472
+ break;
2473
+ case AnimationStatus.decreasing:
2474
+ data.value -= velocity;
2475
+ break;
2476
+ }
2477
+ if (data.velocity && decay !== identity) {
2478
+ data.velocity *= decay;
2479
+ }
2480
+ switch (data.status) {
2481
+ case AnimationStatus.increasing:
2482
+ if (data.value >= maxValue) {
2483
+ if (changeDirection) {
2484
+ data.status = AnimationStatus.decreasing;
2485
+ }
2486
+ else {
2487
+ data.value -= maxValue;
2488
+ }
2489
+ data.loops ??= minLoops;
2490
+ data.loops++;
2491
+ }
2492
+ break;
2493
+ case AnimationStatus.decreasing:
2494
+ if (data.value <= minValue) {
2495
+ if (changeDirection) {
2496
+ data.status = AnimationStatus.increasing;
2497
+ }
2498
+ else {
2499
+ data.value += maxValue;
2500
+ }
2501
+ data.loops ??= minLoops;
2502
+ data.loops++;
2503
+ }
2504
+ break;
3178
2505
  }
3179
- load(data) {
3180
- if (isNull(data)) {
3181
- return;
3182
- }
3183
- super.load(data);
3184
- if (data.direction !== undefined) {
3185
- this.direction = data.direction;
3186
- }
3187
- this.animation.load(data.animation);
3188
- if (data.path !== undefined) {
3189
- this.path = data.path;
3190
- }
2506
+ checkDestroy(particle, destroyType, data.value, minValue, maxValue);
2507
+ if (!particle.destroyed) {
2508
+ data.value = clamp(data.value, minValue, maxValue);
3191
2509
  }
3192
2510
  }
3193
2511
 
@@ -3242,10 +2560,7 @@
3242
2560
  return !particle.destroyed && !particle.spawning && (!!rotate.value || rotate.animation.enable || rotate.path);
3243
2561
  }
3244
2562
  loadOptions(options, ...sources) {
3245
- options.rotate ??= new Rotate();
3246
- for (const source of sources) {
3247
- options.rotate.load(source?.rotate);
3248
- }
2563
+ loadOptionProperty(options, "rotate", Rotate, ...sources);
3249
2564
  }
3250
2565
  update(particle, delta) {
3251
2566
  if (!this.isEnabled(particle)) {
@@ -3261,7 +2576,7 @@
3261
2576
  }
3262
2577
 
3263
2578
  async function loadRotateUpdater(engine) {
3264
- engine.checkVersion("4.1.2");
2579
+ engine.checkVersion("4.2.0");
3265
2580
  await engine.pluginManager.register(e => {
3266
2581
  e.pluginManager.addParticleUpdater("rotate", container => {
3267
2582
  return Promise.resolve(new RotateUpdater(container));
@@ -3270,30 +2585,19 @@
3270
2585
  }
3271
2586
 
3272
2587
  class SizeAnimation extends RangedAnimationOptions {
3273
- destroy;
3274
- constructor() {
3275
- super();
3276
- this.destroy = DestroyType.none;
3277
- this.speed = 5;
3278
- }
2588
+ destroy = DestroyType.none;
3279
2589
  load(data) {
3280
2590
  super.load(data);
3281
2591
  if (isNull(data)) {
3282
2592
  return;
3283
2593
  }
3284
- if (data.destroy !== undefined) {
3285
- this.destroy = data.destroy;
3286
- }
2594
+ loadProperty(this, "destroy", data.destroy);
3287
2595
  }
3288
2596
  }
3289
2597
 
3290
2598
  class Size extends RangedAnimationValueWithRandom {
3291
- animation;
3292
- constructor() {
3293
- super();
3294
- this.animation = new SizeAnimation();
3295
- this.value = 3;
3296
- }
2599
+ animation = new SizeAnimation();
2600
+ value = 3;
3297
2601
  load(data) {
3298
2602
  super.load(data);
3299
2603
  if (isNull(data)) {
@@ -3336,10 +2640,7 @@
3336
2640
  (particle.size.loops ?? minLoops) < (particle.size.maxLoops ?? minLoops))));
3337
2641
  }
3338
2642
  loadOptions(options, ...sources) {
3339
- options.size ??= new Size();
3340
- for (const source of sources) {
3341
- options.size.load(source?.size);
3342
- }
2643
+ loadOptionProperty(options, "size", Size, ...sources);
3343
2644
  }
3344
2645
  preInit(particle) {
3345
2646
  const pxRatio = this.#container.retina.pixelRatio, options = particle.options, sizeOptions = options.size;
@@ -3362,7 +2663,7 @@
3362
2663
  }
3363
2664
 
3364
2665
  async function loadSizeUpdater(engine) {
3365
- engine.checkVersion("4.1.2");
2666
+ engine.checkVersion("4.2.0");
3366
2667
  await engine.pluginManager.register(e => {
3367
2668
  e.pluginManager.addParticleUpdater("size", container => {
3368
2669
  return Promise.resolve(new SizeUpdater(container));
@@ -3386,7 +2687,7 @@
3386
2687
  }
3387
2688
 
3388
2689
  async function loadSquareShape(engine) {
3389
- engine.checkVersion("4.1.2");
2690
+ engine.checkVersion("4.2.0");
3390
2691
  await engine.pluginManager.register(e => {
3391
2692
  e.pluginManager.addShape(["edge", "square"], () => Promise.resolve(new SquareDrawer()));
3392
2693
  });
@@ -3516,7 +2817,7 @@
3516
2817
  return;
3517
2818
  }
3518
2819
  this.draw(ctx => {
3519
- clear(ctx, this.#canvasManager.size);
2820
+ ctx.clearRect(originPoint.x, originPoint.y, this.#canvasManager.size.width, this.#canvasManager.size.height);
3520
2821
  });
3521
2822
  }
3522
2823
  clear() {
@@ -3578,7 +2879,7 @@
3578
2879
  plugin.drawParticleSetup?.(context, particle, delta);
3579
2880
  }
3580
2881
  this.#applyPreDrawUpdaters(context, particle, radius, opacity, colorStyles, transform);
3581
- drawParticle({
2882
+ this.#drawParticle({
3582
2883
  container,
3583
2884
  context,
3584
2885
  particle,
@@ -3597,7 +2898,7 @@
3597
2898
  drawParticlePlugins(particle, delta) {
3598
2899
  this.draw(ctx => {
3599
2900
  for (const plugin of this.#drawParticlePlugins) {
3600
- drawParticlePlugin(ctx, plugin, particle, delta);
2901
+ this.#drawParticlePlugin(ctx, plugin, particle, delta);
3601
2902
  }
3602
2903
  });
3603
2904
  }
@@ -3697,12 +2998,19 @@
3697
2998
  }
3698
2999
  paintBase(baseColor) {
3699
3000
  this.draw(ctx => {
3700
- paintBase(ctx, this.#canvasManager.size, baseColor);
3001
+ ctx.fillStyle = baseColor ?? "rgba(0,0,0,0)";
3002
+ ctx.fillRect(originPoint.x, originPoint.y, this.#canvasManager.size.width, this.#canvasManager.size.height);
3701
3003
  });
3702
3004
  }
3703
3005
  paintImage(image, opacity) {
3704
3006
  this.draw(ctx => {
3705
- paintImage(ctx, this.#canvasManager.size, image, opacity);
3007
+ if (!image) {
3008
+ return;
3009
+ }
3010
+ const prevAlpha = ctx.globalAlpha;
3011
+ ctx.globalAlpha = opacity;
3012
+ ctx.drawImage(image, originPoint.x, originPoint.y, this.#canvasManager.size.width, this.#canvasManager.size.height);
3013
+ ctx.globalAlpha = prevAlpha;
3706
3014
  });
3707
3015
  }
3708
3016
  setContext(context) {
@@ -3716,15 +3024,15 @@
3716
3024
  }
3717
3025
  stop() {
3718
3026
  this.draw(ctx => {
3719
- clear(ctx, this.#canvasManager.size);
3027
+ ctx.clearRect(originPoint.x, originPoint.y, this.#canvasManager.size.width, this.#canvasManager.size.height);
3720
3028
  });
3721
3029
  }
3722
- #applyPostDrawUpdaters = particle => {
3030
+ #applyPostDrawUpdaters(particle) {
3723
3031
  for (const updater of this.#postDrawUpdaters) {
3724
3032
  updater.afterDraw?.(particle);
3725
3033
  }
3726
- };
3727
- #applyPreDrawUpdaters = (ctx, particle, radius, zOpacity, colorStyles, transform) => {
3034
+ }
3035
+ #applyPreDrawUpdaters(ctx, particle, radius, zOpacity, colorStyles, transform) {
3728
3036
  for (const updater of this.#preDrawUpdaters) {
3729
3037
  if (updater.getColorStyles) {
3730
3038
  const { fill, stroke } = updater.getColorStyles(particle, ctx, radius, zOpacity);
@@ -3743,8 +3051,114 @@
3743
3051
  }
3744
3052
  updater.beforeDraw?.(particle);
3745
3053
  }
3746
- };
3747
- #getPluginParticleColors = particle => {
3054
+ }
3055
+ #drawAfterEffect(drawer, data) {
3056
+ if (!drawer?.drawAfter) {
3057
+ return;
3058
+ }
3059
+ const { particle } = data;
3060
+ if (!particle.effect) {
3061
+ return;
3062
+ }
3063
+ drawer.drawAfter(data);
3064
+ }
3065
+ #drawBeforeEffect(drawer, data) {
3066
+ if (!drawer?.drawBefore) {
3067
+ return;
3068
+ }
3069
+ const { particle } = data;
3070
+ if (!particle.effect) {
3071
+ return;
3072
+ }
3073
+ drawer.drawBefore(data);
3074
+ }
3075
+ #drawParticle(data) {
3076
+ const { container, context, particle, delta, colorStyles, radius, opacity, transform } = data, { effectDrawers, shapeDrawers } = container, pos = particle.getPosition(), transformData = particle.getTransformData(transform), drawScale = defaultZoom, drawPosition = {
3077
+ x: pos.x,
3078
+ y: pos.y,
3079
+ };
3080
+ context.setTransform(transformData.a, transformData.b, transformData.c, transformData.d, pos.x, pos.y);
3081
+ if (colorStyles.fill) {
3082
+ context.fillStyle = colorStyles.fill;
3083
+ }
3084
+ const fillEnabled = !!particle.fillEnabled, strokeWidth = particle.strokeWidth ?? minStrokeWidth;
3085
+ context.lineWidth = strokeWidth;
3086
+ if (colorStyles.stroke) {
3087
+ context.strokeStyle = colorStyles.stroke;
3088
+ }
3089
+ const drawData = {
3090
+ context,
3091
+ particle,
3092
+ radius,
3093
+ drawRadius: radius * drawScale,
3094
+ opacity,
3095
+ delta,
3096
+ pixelRatio: container.retina.pixelRatio,
3097
+ fill: fillEnabled,
3098
+ stroke: strokeWidth > minStrokeWidth,
3099
+ transformData,
3100
+ position: { ...pos },
3101
+ drawPosition,
3102
+ drawScale,
3103
+ };
3104
+ for (const plugin of container.plugins) {
3105
+ plugin.drawParticleTransform?.(drawData);
3106
+ }
3107
+ const effect = particle.effect ? effectDrawers.get(particle.effect) : undefined, shape = particle.shape ? shapeDrawers.get(particle.shape) : undefined;
3108
+ this.#drawBeforeEffect(effect, drawData);
3109
+ this.#drawShapeBeforeDraw(shape, drawData);
3110
+ this.#drawShape(shape, drawData);
3111
+ this.#drawShapeAfterDraw(shape, drawData);
3112
+ this.#drawAfterEffect(effect, drawData);
3113
+ context.resetTransform();
3114
+ }
3115
+ #drawParticlePlugin(context, plugin, particle, delta) {
3116
+ if (!plugin.drawParticle) {
3117
+ return;
3118
+ }
3119
+ plugin.drawParticle(context, particle, delta);
3120
+ }
3121
+ #drawShape(drawer, data) {
3122
+ if (!drawer) {
3123
+ return;
3124
+ }
3125
+ const { context, fill, particle, stroke } = data;
3126
+ if (!particle.shape) {
3127
+ return;
3128
+ }
3129
+ context.beginPath();
3130
+ drawer.draw(data);
3131
+ if (particle.shapeClose) {
3132
+ context.closePath();
3133
+ }
3134
+ if (fill) {
3135
+ context.fill();
3136
+ }
3137
+ if (stroke) {
3138
+ context.stroke();
3139
+ }
3140
+ }
3141
+ #drawShapeAfterDraw(drawer, data) {
3142
+ if (!drawer?.afterDraw) {
3143
+ return;
3144
+ }
3145
+ const { particle } = data;
3146
+ if (!particle.shape) {
3147
+ return;
3148
+ }
3149
+ drawer.afterDraw(data);
3150
+ }
3151
+ #drawShapeBeforeDraw(drawer, data) {
3152
+ if (!drawer?.beforeDraw) {
3153
+ return;
3154
+ }
3155
+ const { particle } = data;
3156
+ if (!particle.shape) {
3157
+ return;
3158
+ }
3159
+ drawer.beforeDraw(data);
3160
+ }
3161
+ #getPluginParticleColors(particle) {
3748
3162
  let fColor, sColor;
3749
3163
  for (const plugin of this.#colorPlugins) {
3750
3164
  if (!fColor && plugin.particleFillColor) {
@@ -3760,7 +3174,7 @@
3760
3174
  this.#reusablePluginColors[fColorIndex] = fColor;
3761
3175
  this.#reusablePluginColors[sColorIndex] = sColor;
3762
3176
  return this.#reusablePluginColors;
3763
- };
3177
+ }
3764
3178
  }
3765
3179
 
3766
3180
  const transferredCanvases = new WeakMap(), getTransferredCanvas = (canvas) => {
@@ -3892,6 +3306,7 @@
3892
3306
  obs.observe(element, { attributes: true });
3893
3307
  });
3894
3308
  this.initPlugins();
3309
+ this.#initContext();
3895
3310
  this.render.init();
3896
3311
  }
3897
3312
  initBackground() {
@@ -3901,7 +3316,7 @@
3901
3316
  }
3902
3317
  const elementStyle = element.style, color = rangeColorToRgb(this.#pluginManager, background.color);
3903
3318
  if (color) {
3904
- elementStyle.backgroundColor = getStyleFromRgb(color, container.hdr, background.opacity);
3319
+ elementStyle.backgroundColor = getStyleFromRgb(color, container.actualOptions.hdr, background.opacity);
3905
3320
  }
3906
3321
  else {
3907
3322
  elementStyle.backgroundColor = "";
@@ -3923,7 +3338,7 @@
3923
3338
  if (this.#generated && this.domElement) {
3924
3339
  this.domElement.remove();
3925
3340
  }
3926
- const container = this.#container, domCanvas = isHtmlCanvasElement(canvas) ? canvas : undefined;
3341
+ const domCanvas = isHtmlCanvasElement(canvas) ? canvas : undefined;
3927
3342
  this.domElement = domCanvas;
3928
3343
  this.#generated = domCanvas ? domCanvas.dataset[generatedAttribute] === "true" : false;
3929
3344
  this.renderCanvas = domCanvas ? getTransferredCanvas(domCanvas) : canvas;
@@ -3944,26 +3359,6 @@
3944
3359
  const pxRatio = this.#container.retina.pixelRatio, retinaSize = this.size;
3945
3360
  renderCanvas.height = retinaSize.height = standardSize.height * pxRatio;
3946
3361
  renderCanvas.width = retinaSize.width = standardSize.width * pxRatio;
3947
- const canSupportHdrQuery = safeMatchMedia("(color-gamut: p3)");
3948
- this.render.setContextSettings({
3949
- alpha: true,
3950
- colorSpace: canSupportHdrQuery?.matches && container.hdr ? "display-p3" : "srgb",
3951
- desynchronized: true,
3952
- willReadFrequently: false,
3953
- });
3954
- this.render.setContext(renderCanvas.getContext("2d", this.render.settings));
3955
- this.#safeMutationObserver(obs => {
3956
- obs.disconnect();
3957
- });
3958
- container.retina.init();
3959
- this.initBackground();
3960
- this.#safeMutationObserver(obs => {
3961
- const element = this.domElement;
3962
- if (!element || !(element instanceof Node)) {
3963
- return;
3964
- }
3965
- obs.observe(element, { attributes: true });
3966
- });
3967
3362
  }
3968
3363
  resize() {
3969
3364
  const element = this.domElement;
@@ -4031,12 +3426,30 @@
4031
3426
  await container.refresh();
4032
3427
  }
4033
3428
  }
4034
- #applyResizePlugins = () => {
3429
+ #applyResizePlugins() {
4035
3430
  for (const plugin of this.#resizePlugins) {
4036
3431
  plugin.resize?.();
4037
3432
  }
4038
- };
4039
- #initStyle = () => {
3433
+ }
3434
+ #initContext() {
3435
+ const container = this.#container, canSupportHdr = container.actualOptions.hdr &&
3436
+ safeMatchMedia("(color-gamut: p3)")?.matches &&
3437
+ safeMatchMedia("(dynamic-range: high)")?.matches;
3438
+ this.render.setContextSettings({
3439
+ alpha: true,
3440
+ desynchronized: true,
3441
+ willReadFrequently: false,
3442
+ ...(canSupportHdr
3443
+ ? { colorSpace: "display-p3", colorType: "float16" }
3444
+ : { colorSpace: "srgb" }),
3445
+ });
3446
+ const renderCanvas = this.renderCanvas;
3447
+ if (!renderCanvas) {
3448
+ return;
3449
+ }
3450
+ this.render.setContext(renderCanvas.getContext("2d", this.render.settings));
3451
+ }
3452
+ #initStyle() {
4040
3453
  const element = this.domElement, options = this.#container.actualOptions;
4041
3454
  if (!element) {
4042
3455
  return;
@@ -4057,8 +3470,8 @@
4057
3470
  }
4058
3471
  element.style.setProperty(key, value, "important");
4059
3472
  }
4060
- };
4061
- #repairStyle = () => {
3473
+ }
3474
+ #repairStyle() {
4062
3475
  const element = this.domElement;
4063
3476
  if (!element) {
4064
3477
  return;
@@ -4077,27 +3490,27 @@
4077
3490
  }
4078
3491
  observer.observe(element, { attributes: true });
4079
3492
  });
4080
- };
4081
- #resetOriginalStyle = () => {
3493
+ }
3494
+ #resetOriginalStyle() {
4082
3495
  const element = this.domElement, originalStyle = this.#originalStyle;
4083
3496
  if (!element || !originalStyle) {
4084
3497
  return;
4085
3498
  }
4086
3499
  setStyle(element, originalStyle, true);
4087
- };
4088
- #safeMutationObserver = callback => {
3500
+ }
3501
+ #safeMutationObserver(callback) {
4089
3502
  if (!this.#mutationObserver) {
4090
3503
  return;
4091
3504
  }
4092
3505
  callback(this.#mutationObserver);
4093
- };
4094
- #setFullScreenStyle = () => {
3506
+ }
3507
+ #setFullScreenStyle() {
4095
3508
  const element = this.domElement;
4096
3509
  if (!element) {
4097
3510
  return;
4098
3511
  }
4099
3512
  setStyle(element, getFullScreenStyle(this.#container.actualOptions.fullScreen.zIndex), true);
4100
- };
3513
+ }
4101
3514
  }
4102
3515
 
4103
3516
  class EventListeners {
@@ -4122,7 +3535,7 @@
4122
3535
  removeListeners() {
4123
3536
  this.#manageListeners(false);
4124
3537
  }
4125
- #handleVisibilityChange = () => {
3538
+ #handleVisibilityChange() {
4126
3539
  const container = this.#container, options = container.actualOptions;
4127
3540
  if (!options.pauseOnBlur) {
4128
3541
  return;
@@ -4140,8 +3553,8 @@
4140
3553
  container.draw(true);
4141
3554
  }
4142
3555
  }
4143
- };
4144
- #handleWindowResize = () => {
3556
+ }
3557
+ #handleWindowResize() {
4145
3558
  if (this.#resizeTimeout) {
4146
3559
  clearTimeout(this.#resizeTimeout);
4147
3560
  this.#resizeTimeout = undefined;
@@ -4151,13 +3564,13 @@
4151
3564
  await canvas.windowResize();
4152
3565
  };
4153
3566
  this.#resizeTimeout = setTimeout(() => void handleResize(), this.#container.actualOptions.resize.delay * millisecondsToSeconds);
4154
- };
4155
- #manageListeners = add => {
3567
+ }
3568
+ #manageListeners(add) {
4156
3569
  const handlers = this.#handlers;
4157
3570
  this.#manageResize(add);
4158
3571
  manageListener(document, visibilityChangeEvent, handlers.visibilityChange, add, false);
4159
- };
4160
- #manageResize = add => {
3572
+ }
3573
+ #manageResize(add) {
4161
3574
  const handlers = this.#handlers, container = this.#container, options = container.actualOptions;
4162
3575
  if (!options.resize.enable) {
4163
3576
  return;
@@ -4184,7 +3597,7 @@
4184
3597
  });
4185
3598
  this.#resizeObserver.observe(canvasEl);
4186
3599
  }
4187
- };
3600
+ }
4188
3601
  }
4189
3602
 
4190
3603
  function loadEffectData(effect, effectOptions, id, reduceDuplicates) {
@@ -4211,6 +3624,131 @@
4211
3624
  data.setCb(data.radius);
4212
3625
  }
4213
3626
  }
3627
+ function normalizeAngle(angle, modulus) {
3628
+ const normalized = angle % modulus;
3629
+ return normalized < defaultAngle ? normalized + modulus : normalized;
3630
+ }
3631
+ function initParticleState(particle, id, group) {
3632
+ particle.id = id;
3633
+ particle.group = group;
3634
+ particle.justWarped = false;
3635
+ particle.effectClose = true;
3636
+ particle.shapeClose = true;
3637
+ particle.pathRotation = false;
3638
+ particle.lastPathTime = 0;
3639
+ particle.destroyed = false;
3640
+ particle.unbreakable = false;
3641
+ particle.isRotating = false;
3642
+ particle.rotation = 0;
3643
+ particle.misplaced = false;
3644
+ particle.retina = {
3645
+ maxDistance: {},
3646
+ maxSpeed: 0,
3647
+ moveDrift: 0,
3648
+ moveSpeed: 0,
3649
+ sizeAnimationSpeed: 0,
3650
+ };
3651
+ particle.size = {
3652
+ value: 1,
3653
+ max: 1,
3654
+ min: 1,
3655
+ enable: false,
3656
+ };
3657
+ particle.outType = ParticleOutType.normal;
3658
+ particle.ignoresResizeRatio = true;
3659
+ }
3660
+ function resolveParticleOptions(particle, container, pluginManager, overrideOptions) {
3661
+ const mainOptions = container.actualOptions, particlesOptions = loadParticlesOptions(pluginManager, container, mainOptions.particles), reduceDuplicates = particlesOptions.reduceDuplicates;
3662
+ particle.effect = itemFromSingleOrMultiple(particlesOptions.effect.type, particle.id, reduceDuplicates);
3663
+ particle.shape = itemFromSingleOrMultiple(particlesOptions.shape.type, particle.id, reduceDuplicates);
3664
+ const effectOptions = particlesOptions.effect, shapeOptions = particlesOptions.shape;
3665
+ if (overrideOptions) {
3666
+ if (overrideOptions.effect) {
3667
+ const overrideEffectType = overrideOptions.effect.type;
3668
+ if (overrideEffectType && overrideEffectType !== particle.effect) {
3669
+ const effect = itemFromSingleOrMultiple(overrideEffectType, particle.id, reduceDuplicates);
3670
+ if (effect) {
3671
+ particle.effect = effect;
3672
+ }
3673
+ }
3674
+ effectOptions.load(overrideOptions.effect);
3675
+ }
3676
+ if (overrideOptions.shape) {
3677
+ const overrideShapeType = overrideOptions.shape.type;
3678
+ if (overrideShapeType && overrideShapeType !== particle.shape) {
3679
+ const shape = itemFromSingleOrMultiple(overrideShapeType, particle.id, reduceDuplicates);
3680
+ if (shape) {
3681
+ particle.shape = shape;
3682
+ }
3683
+ }
3684
+ shapeOptions.load(overrideOptions.shape);
3685
+ }
3686
+ }
3687
+ if (particle.effect === randomColorValue) {
3688
+ const availableEffects = [...container.effectDrawers.keys()];
3689
+ particle.effect = availableEffects[Math.floor(getRandom() * availableEffects.length)];
3690
+ }
3691
+ if (particle.shape === randomColorValue) {
3692
+ const availableShapes = [...container.shapeDrawers.keys()];
3693
+ particle.shape = availableShapes[Math.floor(getRandom() * availableShapes.length)];
3694
+ }
3695
+ particle.effectData = particle.effect
3696
+ ? loadEffectData(particle.effect, effectOptions, particle.id, reduceDuplicates)
3697
+ : undefined;
3698
+ particle.shapeData = particle.shape
3699
+ ? loadShapeData(particle.shape, shapeOptions, particle.id, reduceDuplicates)
3700
+ : undefined;
3701
+ particlesOptions.load(overrideOptions);
3702
+ const effectData = particle.effectData, shapeData = particle.shapeData;
3703
+ if (effectData) {
3704
+ particlesOptions.load(effectData.particles);
3705
+ }
3706
+ if (shapeData) {
3707
+ particlesOptions.load(shapeData.particles);
3708
+ }
3709
+ particle.effectClose = effectData?.close ?? particlesOptions.effect.close;
3710
+ particle.shapeClose = shapeData?.close ?? particlesOptions.shape.close;
3711
+ return particlesOptions;
3712
+ }
3713
+ function initParticleDrawers(particle, container) {
3714
+ let effectDrawer, shapeDrawer;
3715
+ if (particle.effect) {
3716
+ effectDrawer = container.effectDrawers.get(particle.effect);
3717
+ }
3718
+ if (effectDrawer?.loadEffect) {
3719
+ effectDrawer.loadEffect(particle);
3720
+ }
3721
+ if (particle.shape) {
3722
+ shapeDrawer = container.shapeDrawers.get(particle.shape);
3723
+ }
3724
+ if (shapeDrawer?.loadShape) {
3725
+ shapeDrawer.loadShape(particle);
3726
+ }
3727
+ const sideCountFunc = shapeDrawer?.getSidesCount;
3728
+ if (sideCountFunc) {
3729
+ particle.sides = sideCountFunc(particle);
3730
+ }
3731
+ }
3732
+ function runUpdaterPreInit(updaters, particle) {
3733
+ for (const updater of updaters) {
3734
+ updater.preInit?.(particle);
3735
+ }
3736
+ }
3737
+ function runUpdaterInit(updaters, particle) {
3738
+ for (const updater of updaters) {
3739
+ updater.init(particle);
3740
+ }
3741
+ }
3742
+ function runDrawerInit(container, particle) {
3743
+ const shapeDrawer = particle.shape ? container.shapeDrawers.get(particle.shape) : undefined, effectDrawer = particle.effect ? container.effectDrawers.get(particle.effect) : undefined;
3744
+ effectDrawer?.particleInit?.(container, particle);
3745
+ shapeDrawer?.particleInit?.(container, particle);
3746
+ }
3747
+ function runParticleCreatedPlugins(container, particle) {
3748
+ for (const plugin of container.particleCreatedPlugins) {
3749
+ plugin.particleCreated?.(particle);
3750
+ }
3751
+ }
4214
3752
  class Particle {
4215
3753
  backColor;
4216
3754
  bubble;
@@ -4346,78 +3884,10 @@
4346
3884
  }
4347
3885
  init(id, position, overrideOptions, group) {
4348
3886
  const container = this.#container;
4349
- this.id = id;
4350
- this.group = group;
4351
- this.justWarped = false;
4352
- this.effectClose = true;
4353
- this.shapeClose = true;
4354
- this.pathRotation = false;
4355
- this.lastPathTime = 0;
4356
- this.destroyed = false;
4357
- this.unbreakable = false;
4358
- this.isRotating = false;
4359
- this.rotation = 0;
4360
- this.misplaced = false;
4361
- this.retina = {
4362
- maxDistance: {},
4363
- maxSpeed: 0,
4364
- moveDrift: 0,
4365
- moveSpeed: 0,
4366
- sizeAnimationSpeed: 0,
4367
- };
4368
- this.size = {
4369
- value: 1,
4370
- max: 1,
4371
- min: 1,
4372
- enable: false,
4373
- };
4374
- this.outType = ParticleOutType.normal;
4375
- this.ignoresResizeRatio = true;
4376
- const mainOptions = container.actualOptions, particlesOptions = loadParticlesOptions(this.#pluginManager, container, mainOptions.particles), reduceDuplicates = particlesOptions.reduceDuplicates, effectType = particlesOptions.effect.type, shapeType = particlesOptions.shape.type;
4377
- this.effect = itemFromSingleOrMultiple(effectType, this.id, reduceDuplicates);
4378
- this.shape = itemFromSingleOrMultiple(shapeType, this.id, reduceDuplicates);
4379
- const effectOptions = particlesOptions.effect, shapeOptions = particlesOptions.shape;
4380
- if (overrideOptions) {
4381
- if (overrideOptions.effect?.type && overrideOptions.effect.type !== this.effect) {
4382
- const overrideEffectType = overrideOptions.effect.type, effect = itemFromSingleOrMultiple(overrideEffectType, this.id, reduceDuplicates);
4383
- if (effect) {
4384
- this.effect = effect;
4385
- effectOptions.load(overrideOptions.effect);
4386
- }
4387
- }
4388
- if (overrideOptions.shape?.type && overrideOptions.shape.type !== this.shape) {
4389
- const overrideShapeType = overrideOptions.shape.type, shape = itemFromSingleOrMultiple(overrideShapeType, this.id, reduceDuplicates);
4390
- if (shape) {
4391
- this.shape = shape;
4392
- shapeOptions.load(overrideOptions.shape);
4393
- }
4394
- }
4395
- }
4396
- if (this.effect === randomColorValue) {
4397
- const availableEffects = [...this.#container.effectDrawers.keys()];
4398
- this.effect = availableEffects[Math.floor(getRandom() * availableEffects.length)];
4399
- }
4400
- if (this.shape === randomColorValue) {
4401
- const availableShapes = [...this.#container.shapeDrawers.keys()];
4402
- this.shape = availableShapes[Math.floor(getRandom() * availableShapes.length)];
4403
- }
4404
- this.effectData = this.effect ? loadEffectData(this.effect, effectOptions, this.id, reduceDuplicates) : undefined;
4405
- this.shapeData = this.shape ? loadShapeData(this.shape, shapeOptions, this.id, reduceDuplicates) : undefined;
4406
- particlesOptions.load(overrideOptions);
4407
- const effectData = this.effectData, shapeData = this.shapeData;
4408
- if (effectData) {
4409
- particlesOptions.load(effectData.particles);
4410
- }
4411
- if (shapeData) {
4412
- particlesOptions.load(shapeData.particles);
4413
- }
4414
- this.effectClose = effectData?.close ?? particlesOptions.effect.close;
4415
- this.shapeClose = shapeData?.close ?? particlesOptions.shape.close;
4416
- this.options = particlesOptions;
3887
+ initParticleState(this, id, group);
3888
+ this.options = resolveParticleOptions(this, container, this.#pluginManager, overrideOptions);
4417
3889
  container.retina.initParticle(this);
4418
- for (const updater of container.particleUpdaters) {
4419
- updater.preInit?.(this);
4420
- }
3890
+ runUpdaterPreInit(container.particleUpdaters, this);
4421
3891
  this.bubble = {
4422
3892
  inRange: false,
4423
3893
  };
@@ -4430,32 +3900,11 @@
4430
3900
  this.velocity = this.initialVelocity.copy();
4431
3901
  this.zIndexFactor = this.position.z / container.zLayers;
4432
3902
  this.sides = 24;
4433
- let effectDrawer, shapeDrawer;
4434
- if (this.effect) {
4435
- effectDrawer = container.effectDrawers.get(this.effect);
4436
- }
4437
- if (effectDrawer?.loadEffect) {
4438
- effectDrawer.loadEffect(this);
4439
- }
4440
- if (this.shape) {
4441
- shapeDrawer = container.shapeDrawers.get(this.shape);
4442
- }
4443
- if (shapeDrawer?.loadShape) {
4444
- shapeDrawer.loadShape(this);
4445
- }
4446
- const sideCountFunc = shapeDrawer?.getSidesCount;
4447
- if (sideCountFunc) {
4448
- this.sides = sideCountFunc(this);
4449
- }
3903
+ initParticleDrawers(this, container);
4450
3904
  this.spawning = false;
4451
- for (const updater of container.particleUpdaters) {
4452
- updater.init(this);
4453
- }
4454
- effectDrawer?.particleInit?.(container, this);
4455
- shapeDrawer?.particleInit?.(container, this);
4456
- for (const plugin of container.particleCreatedPlugins) {
4457
- plugin.particleCreated?.(this);
4458
- }
3905
+ runUpdaterInit(container.particleUpdaters, this);
3906
+ runDrawerInit(container, this);
3907
+ runParticleCreatedPlugins(container, this);
4459
3908
  }
4460
3909
  isInsideCanvas(direction) {
4461
3910
  return this.#getInsideCanvasResult({ direction }).inside;
@@ -4469,15 +3918,15 @@
4469
3918
  }
4470
3919
  const angle = this.roll.angle;
4471
3920
  if (this.roll.horizontal && this.roll.vertical) {
4472
- const normalizedAngle = angle % doublePI, adjustedAngle = normalizedAngle < defaultAngle ? normalizedAngle + doublePI : normalizedAngle;
3921
+ const adjustedAngle = normalizeAngle(angle, doublePI);
4473
3922
  return adjustedAngle >= Math.PI * half && adjustedAngle < Math.PI * triple * half;
4474
3923
  }
4475
3924
  if (this.roll.horizontal) {
4476
- const normalizedAngle = (angle + Math.PI * half) % (Math.PI * double), adjustedAngle = normalizedAngle < defaultAngle ? normalizedAngle + Math.PI * double : normalizedAngle;
3925
+ const adjustedAngle = normalizeAngle(angle + Math.PI * half, doublePI);
4477
3926
  return adjustedAngle >= Math.PI && adjustedAngle < Math.PI * double;
4478
3927
  }
4479
3928
  if (this.roll.vertical) {
4480
- const normalizedAngle = angle % (Math.PI * double), adjustedAngle = normalizedAngle < defaultAngle ? normalizedAngle + Math.PI * double : normalizedAngle;
3929
+ const adjustedAngle = normalizeAngle(angle, doublePI);
4481
3930
  return adjustedAngle >= Math.PI && adjustedAngle < Math.PI * double;
4482
3931
  }
4483
3932
  return false;
@@ -4490,10 +3939,10 @@
4490
3939
  updater.reset?.(this);
4491
3940
  }
4492
3941
  }
4493
- #calcPosition = (position, zIndex) => {
3942
+ #calcPosition(position, zIndex) {
4494
3943
  let tryCount = defaultRetryCount, posVec = position ? Vector3d.create(position.x, position.y, zIndex) : undefined;
4495
- const container = this.#container, plugins = container.particlePositionPlugins, outModes = this.options.move.outModes, radius = this.getRadius(), canvasSize = container.canvas.size, abortController = new AbortController(), { signal } = abortController;
4496
- while (!signal.aborted) {
3944
+ const container = this.#container, plugins = container.particlePositionPlugins, outModes = this.options.move.outModes, radius = this.getRadius(), canvasSize = container.canvas.size;
3945
+ for (;;) {
4497
3946
  for (const plugin of plugins) {
4498
3947
  const pluginPos = plugin.particlePosition?.(posVec, this);
4499
3948
  if (pluginPos) {
@@ -4521,9 +3970,8 @@
4521
3970
  tryCount += tryCountIncrement;
4522
3971
  posVec = undefined;
4523
3972
  }
4524
- return posVec;
4525
- };
4526
- #calculateVelocity = () => {
3973
+ }
3974
+ #calculateVelocity() {
4527
3975
  const moveOptions = this.options.move, baseVelocity = getParticleBaseVelocity(this.direction), res = baseVelocity.copy();
4528
3976
  if (moveOptions.direction === MoveDirection.inside || moveOptions.direction === MoveDirection.outside) {
4529
3977
  return res;
@@ -4539,8 +3987,8 @@
4539
3987
  res.length *= getRandom();
4540
3988
  }
4541
3989
  return res;
4542
- };
4543
- #fixHorizontal = (pos, radius, outMode) => {
3990
+ }
3991
+ #fixHorizontal(pos, radius, outMode) {
4544
3992
  fixOutMode({
4545
3993
  outMode,
4546
3994
  checkModes: [OutMode.bounce],
@@ -4549,8 +3997,8 @@
4549
3997
  setCb: (value) => (pos.x += value),
4550
3998
  radius,
4551
3999
  });
4552
- };
4553
- #fixVertical = (pos, radius, outMode) => {
4000
+ }
4001
+ #fixVertical(pos, radius, outMode) {
4554
4002
  fixOutMode({
4555
4003
  outMode,
4556
4004
  checkModes: [OutMode.bounce],
@@ -4559,8 +4007,8 @@
4559
4007
  setCb: (value) => (pos.y += value),
4560
4008
  radius,
4561
4009
  });
4562
- };
4563
- #getDefaultInsideCanvasResult = (direction, outMode) => {
4010
+ }
4011
+ #getDefaultInsideCanvasResult(direction, outMode) {
4564
4012
  const radius = this.getRadius(), canvasSize = this.#container.canvas.size, position = this.position, isBounce = outMode === OutMode.bounce;
4565
4013
  if (direction === OutModeDirection.bottom) {
4566
4014
  return {
@@ -4593,8 +4041,8 @@
4593
4041
  position.x <= canvasSize.width + radius,
4594
4042
  reason: "default",
4595
4043
  };
4596
- };
4597
- #getInsideCanvasCallbackData = (direction, outMode) => {
4044
+ }
4045
+ #getInsideCanvasCallbackData(direction, outMode) {
4598
4046
  return {
4599
4047
  canvasSize: this.#container.canvas.size,
4600
4048
  direction,
@@ -4602,8 +4050,8 @@
4602
4050
  particle: this,
4603
4051
  radius: this.getRadius(),
4604
4052
  };
4605
- };
4606
- #getInsideCanvasResult = (data) => {
4053
+ }
4054
+ #getInsideCanvasResult(data) {
4607
4055
  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;
4608
4056
  if (!shapeCheck && !effectCheck) {
4609
4057
  return defaultResult;
@@ -4618,8 +4066,8 @@
4618
4066
  };
4619
4067
  }
4620
4068
  return shapeResult ?? effectResult ?? defaultResult;
4621
- };
4622
- #getRollColor = color => {
4069
+ }
4070
+ #getRollColor(color) {
4623
4071
  if (!color || !this.roll || (!this.backColor && !this.roll.alter)) {
4624
4072
  return color;
4625
4073
  }
@@ -4633,8 +4081,8 @@
4633
4081
  return alterHsl(color, this.roll.alter.type, this.roll.alter.value);
4634
4082
  }
4635
4083
  return color;
4636
- };
4637
- #initPosition = position => {
4084
+ }
4085
+ #initPosition(position) {
4638
4086
  const container = this.#container, zIndexValue = Math.floor(getRangeValue(this.options.zIndex.value)), initialPosition = this.#calcPosition(position, clamp(zIndexValue, minZ, container.zLayers));
4639
4087
  if (!initialPosition) {
4640
4088
  throw new Error("a valid position cannot be found for particle");
@@ -4657,8 +4105,8 @@
4657
4105
  break;
4658
4106
  }
4659
4107
  this.offset = Vector.origin;
4660
- };
4661
- #normalizeInsideCanvasResult = (result, reason) => {
4108
+ }
4109
+ #normalizeInsideCanvasResult(result, reason) {
4662
4110
  if (typeof result === "boolean") {
4663
4111
  return {
4664
4112
  inside: result,
@@ -4670,7 +4118,7 @@
4670
4118
  margin: result.margin,
4671
4119
  reason: result.reason ?? reason,
4672
4120
  };
4673
- };
4121
+ }
4674
4122
  }
4675
4123
 
4676
4124
  class SpatialHashGrid {
@@ -5023,10 +4471,10 @@
5023
4471
  }
5024
4472
  this.#resizeFactor = undefined;
5025
4473
  }
5026
- #addToPool = (...particles) => {
4474
+ #addToPool(...particles) {
5027
4475
  this.#pool.push(...particles);
5028
- };
5029
- #applyDensity = (options, pluginsCount, group, groupOptions) => {
4476
+ }
4477
+ #applyDensity(options, pluginsCount, group, groupOptions) {
5030
4478
  const numberOptions = options.number;
5031
4479
  if (!numberOptions.density.enable) {
5032
4480
  if (group === undefined) {
@@ -5050,36 +4498,19 @@
5050
4498
  else if (particlesCount > particlesNumber) {
5051
4499
  this.removeQuantity(particlesCount - particlesNumber, group);
5052
4500
  }
5053
- };
5054
- #createBuckets = (zLayers) => {
4501
+ }
4502
+ #createBuckets(zLayers) {
5055
4503
  const bucketCount = Math.max(Math.floor(zLayers), one);
5056
4504
  return Array.from({ length: bucketCount }, () => []);
5057
- };
5058
- #getBucketIndex = (zIndex) => {
4505
+ }
4506
+ #getBucketIndex(zIndex) {
5059
4507
  const maxBucketIndex = this.#zBuckets.length - one;
5060
4508
  if (maxBucketIndex <= minIndex) {
5061
4509
  return minIndex;
5062
4510
  }
5063
4511
  return Math.min(Math.max(Math.floor(zIndex), minIndex), maxBucketIndex);
5064
- };
5065
- #getParticleInsertIndex = (bucket, particleId) => {
5066
- let start = minIndex, end = bucket.length;
5067
- while (start < end) {
5068
- const middle = Math.floor((start + end) / double), middleParticle = bucket[middle];
5069
- if (!middleParticle) {
5070
- end = middle;
5071
- continue;
5072
- }
5073
- if (middleParticle.id < particleId) {
5074
- start = middle + one;
5075
- }
5076
- else {
5077
- end = middle;
5078
- }
5079
- }
5080
- return start;
5081
- };
5082
- #initDensityFactor = densityOptions => {
4512
+ }
4513
+ #initDensityFactor(densityOptions) {
5083
4514
  const container = this.#container;
5084
4515
  if (!densityOptions.enable) {
5085
4516
  return defaultDensityFactor;
@@ -5089,16 +4520,16 @@
5089
4520
  return defaultDensityFactor;
5090
4521
  }
5091
4522
  return ((canvasSize.width * canvasSize.height) / (densityOptions.height * densityOptions.width * pxRatio ** squareExp));
5092
- };
5093
- #insertParticleIntoBucket = (particle) => {
4523
+ }
4524
+ #insertParticleIntoBucket(particle) {
5094
4525
  const bucketIndex = this.#getBucketIndex(particle.position.z), bucket = this.#zBuckets[bucketIndex];
5095
4526
  if (!bucket) {
5096
4527
  return;
5097
4528
  }
5098
- bucket.splice(this.#getParticleInsertIndex(bucket, particle.id), empty, particle);
4529
+ bucket.push(particle);
5099
4530
  this.#particleBuckets.set(particle.id, bucketIndex);
5100
- };
5101
- #removeParticle = (index, group, override) => {
4531
+ }
4532
+ #removeParticle(index, group, override) {
5102
4533
  const particle = this.#array[index];
5103
4534
  if (!particle) {
5104
4535
  return false;
@@ -5114,22 +4545,20 @@
5114
4545
  });
5115
4546
  this.#addToPool(particle);
5116
4547
  return true;
5117
- };
5118
- #removeParticleFromBucket = (particle) => {
4548
+ }
4549
+ #removeParticleFromBucket(particle) {
5119
4550
  const bucketIndex = this.#particleBuckets.get(particle.id) ?? this.#getBucketIndex(particle.position.z), bucket = this.#zBuckets[bucketIndex];
5120
4551
  if (!bucket) {
5121
4552
  this.#particleBuckets.delete(particle.id);
5122
4553
  return;
5123
4554
  }
5124
- const particleIndex = this.#getParticleInsertIndex(bucket, particle.id);
5125
- if (bucket[particleIndex]?.id !== particle.id) {
5126
- this.#particleBuckets.delete(particle.id);
5127
- return;
4555
+ const idx = bucket.findIndex(p => p.id === particle.id);
4556
+ if (idx >= minIndex) {
4557
+ bucket.splice(idx, deleteCount);
5128
4558
  }
5129
- bucket.splice(particleIndex, deleteCount);
5130
4559
  this.#particleBuckets.delete(particle.id);
5131
- };
5132
- #resetBuckets = (zLayers) => {
4560
+ }
4561
+ #resetBuckets(zLayers) {
5133
4562
  const bucketCount = Math.max(Math.floor(zLayers), one);
5134
4563
  if (this.#zBuckets.length !== bucketCount) {
5135
4564
  this.#zBuckets = this.#createBuckets(bucketCount);
@@ -5138,8 +4567,8 @@
5138
4567
  for (const bucket of this.#zBuckets) {
5139
4568
  bucket.length = minIndex;
5140
4569
  }
5141
- };
5142
- #updateParticleBucket = (particle) => {
4570
+ }
4571
+ #updateParticleBucket(particle) {
5143
4572
  const newBucketIndex = this.#getBucketIndex(particle.position.z), currentBucketIndex = this.#particleBuckets.get(particle.id);
5144
4573
  if (currentBucketIndex === undefined) {
5145
4574
  this.#insertParticleIntoBucket(particle);
@@ -5150,9 +4579,9 @@
5150
4579
  }
5151
4580
  const currentBucket = this.#zBuckets[currentBucketIndex];
5152
4581
  if (currentBucket) {
5153
- const particleIndex = this.#getParticleInsertIndex(currentBucket, particle.id);
5154
- if (currentBucket[particleIndex]?.id === particle.id) {
5155
- currentBucket.splice(particleIndex, deleteCount);
4582
+ const idx = currentBucket.findIndex(p => p.id === particle.id);
4583
+ if (idx >= minIndex) {
4584
+ currentBucket.splice(idx, deleteCount);
5156
4585
  }
5157
4586
  }
5158
4587
  const newBucket = this.#zBuckets[newBucketIndex];
@@ -5160,10 +4589,16 @@
5160
4589
  this.#particleBuckets.set(particle.id, newBucketIndex);
5161
4590
  return;
5162
4591
  }
5163
- newBucket.splice(this.#getParticleInsertIndex(newBucket, particle.id), empty, particle);
4592
+ newBucket.push(particle);
4593
+ if (newBucket.length >= double) {
4594
+ const prev = newBucket[newBucket.length - double];
4595
+ if (prev && particle.id < prev.id) {
4596
+ newBucket.sort((a, b) => a.id - b.id);
4597
+ }
4598
+ }
5164
4599
  this.#particleBuckets.set(particle.id, newBucketIndex);
5165
- };
5166
- #updateParticlesPhase1 = (delta) => {
4600
+ }
4601
+ #updateParticlesPhase1(delta) {
5167
4602
  const particlesToDelete = new Set(), resizeFactor = this.#resizeFactor;
5168
4603
  for (const particle of this.#array) {
5169
4604
  if (resizeFactor && !particle.ignoresResizeRatio) {
@@ -5189,8 +4624,8 @@
5189
4624
  this.grid.insert(particle);
5190
4625
  }
5191
4626
  return particlesToDelete;
5192
- };
5193
- #updateParticlesPhase2 = (delta, particlesToDelete) => {
4627
+ }
4628
+ #updateParticlesPhase2(delta, particlesToDelete) {
5194
4629
  for (const particle of this.#array) {
5195
4630
  if (particle.destroyed) {
5196
4631
  particlesToDelete.add(particle);
@@ -5206,7 +4641,7 @@
5206
4641
  }
5207
4642
  this.#updateParticleBucket(particle);
5208
4643
  }
5209
- };
4644
+ }
5210
4645
  }
5211
4646
 
5212
4647
  class Retina {
@@ -5568,7 +5003,7 @@
5568
5003
  }
5569
5004
  return refresh;
5570
5005
  }
5571
- #nextFrame = (timestamp) => {
5006
+ #nextFrame(timestamp) {
5572
5007
  try {
5573
5008
  if (!this.#smooth &&
5574
5009
  this.#lastFrameTime !== undefined &&
@@ -5596,7 +5031,7 @@
5596
5031
  catch (e) {
5597
5032
  getLogger().error("error in animation loop", e);
5598
5033
  }
5599
- };
5034
+ }
5600
5035
  }
5601
5036
 
5602
5037
  var Container$1 = /*#__PURE__*/Object.freeze({
@@ -5833,7 +5268,13 @@
5833
5268
  this.#paused = !this.options.autoPlay;
5834
5269
  this.#particlesOptions = particlesOptions;
5835
5270
  this.#size = this.#calcSize();
5836
- this.size = getSize(this.#size, this.#container.canvas.size);
5271
+ this.size =
5272
+ this.#size.mode === PixelMode.percent
5273
+ ? {
5274
+ width: (this.#size.width / percentDenominator) * this.#container.canvas.size.width,
5275
+ height: (this.#size.height / percentDenominator) * this.#container.canvas.size.height,
5276
+ }
5277
+ : { width: this.#size.width, height: this.#size.height };
5837
5278
  this.#lifeCount = this.options.life.count ?? defaultLifeCount;
5838
5279
  this.#immortal = this.#lifeCount <= minLifeCount;
5839
5280
  if (this.options.domId) {
@@ -5904,7 +5345,13 @@
5904
5345
  ? initialPosition
5905
5346
  : this.#calcPosition();
5906
5347
  this.#size = this.#calcSize();
5907
- this.size = getSize(this.#size, container.canvas.size);
5348
+ this.size =
5349
+ this.#size.mode === PixelMode.percent
5350
+ ? {
5351
+ width: (this.#size.width / percentDenominator) * container.canvas.size.width,
5352
+ height: (this.#size.height / percentDenominator) * container.canvas.size.height,
5353
+ }
5354
+ : { width: this.#size.width, height: this.#size.height };
5908
5355
  this.#shape?.resize(this.position, this.size);
5909
5356
  }
5910
5357
  update(delta) {
@@ -6004,7 +5451,7 @@
6004
5451
  return size;
6005
5452
  })());
6006
5453
  }
6007
- #destroy = () => {
5454
+ #destroy() {
6008
5455
  this.#mutationObserver?.disconnect();
6009
5456
  this.#mutationObserver = undefined;
6010
5457
  this.#resizeObserver?.disconnect();
@@ -6013,7 +5460,7 @@
6013
5460
  this.#container.dispatchEvent("emitterDestroyed", {
6014
5461
  emitter: this,
6015
5462
  });
6016
- };
5463
+ }
6017
5464
  #emit() {
6018
5465
  if (this.#paused) {
6019
5466
  return;
@@ -6073,7 +5520,7 @@
6073
5520
  }
6074
5521
  }
6075
5522
  }
6076
- #prepareToDie = () => {
5523
+ #prepareToDie() {
6077
5524
  if (this.#paused) {
6078
5525
  return;
6079
5526
  }
@@ -6081,8 +5528,8 @@
6081
5528
  if ((this.#lifeCount > minLifeCount || this.#immortal) && duration !== undefined && duration > minDuration) {
6082
5529
  this.#duration = duration * millisecondsToSeconds;
6083
5530
  }
6084
- };
6085
- #setColorAnimation = (animation, initValue, maxValue, factor = defaultColorAnimationFactor) => {
5531
+ }
5532
+ #setColorAnimation(animation, initValue, maxValue, factor = defaultColorAnimationFactor) {
6086
5533
  const container = this.#container;
6087
5534
  if (!animation.enable) {
6088
5535
  return initValue;
@@ -6091,7 +5538,7 @@
6091
5538
  ? (delay * millisecondsToSeconds) / container.retina.reduceFactor
6092
5539
  : Infinity, colorSpeed = getRangeValue(animation.speed);
6093
5540
  return (initValue + (colorSpeed * container.fpsLimit) / emitFactor + colorOffset * factor) % maxValue;
6094
- };
5541
+ }
6095
5542
  }
6096
5543
 
6097
5544
  var EmitterInstance$1 = /*#__PURE__*/Object.freeze({