@sarmal/core 0.23.0 → 0.24.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (75) hide show
  1. package/dist/auto-init.cjs +148 -137
  2. package/dist/auto-init.cjs.map +1 -1
  3. package/dist/auto-init.js +147 -136
  4. package/dist/auto-init.js.map +1 -1
  5. package/dist/curves/artemis2.cjs +7 -10
  6. package/dist/curves/artemis2.d.cts +1 -1
  7. package/dist/curves/artemis2.d.ts +1 -1
  8. package/dist/curves/artemis2.js +6 -9
  9. package/dist/curves/astroid.cjs +4 -4
  10. package/dist/curves/astroid.d.cts +1 -1
  11. package/dist/curves/astroid.d.ts +1 -1
  12. package/dist/curves/astroid.js +3 -3
  13. package/dist/curves/deltoid.cjs +4 -4
  14. package/dist/curves/deltoid.d.cts +1 -1
  15. package/dist/curves/deltoid.d.ts +1 -1
  16. package/dist/curves/deltoid.js +3 -3
  17. package/dist/curves/epicycloid3.cjs +4 -4
  18. package/dist/curves/epicycloid3.d.cts +1 -1
  19. package/dist/curves/epicycloid3.d.ts +1 -1
  20. package/dist/curves/epicycloid3.js +3 -3
  21. package/dist/curves/epitrochoid7.cjs +5 -5
  22. package/dist/curves/epitrochoid7.d.cts +1 -1
  23. package/dist/curves/epitrochoid7.d.ts +1 -1
  24. package/dist/curves/epitrochoid7.js +4 -4
  25. package/dist/curves/index.cjs +40 -53
  26. package/dist/curves/index.d.cts +29 -29
  27. package/dist/curves/index.d.ts +29 -29
  28. package/dist/curves/index.js +40 -69
  29. package/dist/curves/lame.cjs +5 -6
  30. package/dist/curves/lame.d.cts +1 -1
  31. package/dist/curves/lame.d.ts +1 -1
  32. package/dist/curves/lame.js +4 -5
  33. package/dist/curves/lissajous32.cjs +4 -4
  34. package/dist/curves/lissajous32.d.cts +1 -1
  35. package/dist/curves/lissajous32.d.ts +1 -1
  36. package/dist/curves/lissajous32.js +3 -3
  37. package/dist/curves/lissajous43.cjs +4 -4
  38. package/dist/curves/lissajous43.d.cts +1 -1
  39. package/dist/curves/lissajous43.d.ts +1 -1
  40. package/dist/curves/lissajous43.js +3 -3
  41. package/dist/curves/rose3.cjs +4 -4
  42. package/dist/curves/rose3.d.cts +1 -1
  43. package/dist/curves/rose3.d.ts +1 -1
  44. package/dist/curves/rose3.js +3 -3
  45. package/dist/curves/rose5.cjs +4 -4
  46. package/dist/curves/rose5.d.cts +1 -1
  47. package/dist/curves/rose5.d.ts +1 -1
  48. package/dist/curves/rose5.js +3 -3
  49. package/dist/curves/rose52.cjs +5 -5
  50. package/dist/curves/rose52.d.cts +1 -1
  51. package/dist/curves/rose52.d.ts +1 -1
  52. package/dist/curves/rose52.js +4 -4
  53. package/dist/curves/star.cjs +5 -8
  54. package/dist/curves/star.d.cts +1 -1
  55. package/dist/curves/star.d.ts +1 -1
  56. package/dist/curves/star.js +4 -7
  57. package/dist/curves/star4.cjs +5 -8
  58. package/dist/curves/star4.d.cts +1 -1
  59. package/dist/curves/star4.d.ts +1 -1
  60. package/dist/curves/star4.js +4 -7
  61. package/dist/curves/star7.cjs +5 -8
  62. package/dist/curves/star7.d.cts +1 -1
  63. package/dist/curves/star7.d.ts +1 -1
  64. package/dist/curves/star7.js +4 -7
  65. package/dist/index.cjs +140 -133
  66. package/dist/index.cjs.map +1 -1
  67. package/dist/index.d.cts +33 -74
  68. package/dist/index.d.ts +33 -74
  69. package/dist/index.js +140 -153
  70. package/dist/index.js.map +1 -1
  71. package/dist/types-CknrlCAf.d.cts +314 -0
  72. package/dist/types-CknrlCAf.d.ts +314 -0
  73. package/package.json +1 -1
  74. package/dist/types-C0b4MPtI.d.cts +0 -321
  75. package/dist/types-C0b4MPtI.d.ts +0 -321
@@ -1,4 +1,4 @@
1
- "use strict";
1
+ 'use strict';
2
2
 
3
3
  // src/engine.ts
4
4
  var TWO_PI = Math.PI * 2;
@@ -63,13 +63,13 @@ function resolveCurve(curveDef) {
63
63
  period,
64
64
  speed,
65
65
  skeleton: curveDef.skeleton,
66
- skeletonFn: curveDef.skeletonFn,
66
+ skeletonFn: curveDef.skeletonFn
67
67
  };
68
68
  }
69
69
  function createEngine(curveDef, trailLength = 120) {
70
70
  if (!Number.isFinite(trailLength) || trailLength <= 0) {
71
71
  throw new RangeError(
72
- `[sarmal] trailLength must be a positive finite number, got ${trailLength}`,
72
+ `[sarmal] trailLength must be a positive finite number, got ${trailLength}`
73
73
  );
74
74
  }
75
75
  let curve = resolveCurve(curveDef);
@@ -110,7 +110,7 @@ function createEngine(curveDef, trailLength = 120) {
110
110
  actualTime += deltaTime;
111
111
  if (morphCurveB !== null && _morphAlpha !== null) {
112
112
  const a = curve.fn(t, actualTime, EMPTY_PARAMS);
113
- const tB = _morphStrategy === "normalized" ? (t / curve.period) * morphCurveB.period : t;
113
+ const tB = _morphStrategy === "normalized" ? t / curve.period * morphCurveB.period : t;
114
114
  const b = morphCurveB.fn(tB, actualTime, EMPTY_PARAMS);
115
115
  trail.push(a.x + (b.x - a.x) * _morphAlpha, a.y + (b.y - a.y) * _morphAlpha);
116
116
  } else {
@@ -137,14 +137,14 @@ function createEngine(curveDef, trailLength = 120) {
137
137
  trail.clear();
138
138
  },
139
139
  jump(newT, { clearTrail = false } = {}) {
140
- t = ((newT % curve.period) + curve.period) % curve.period;
140
+ t = (newT % curve.period + curve.period) % curve.period;
141
141
  if (clearTrail) {
142
142
  trail.clear();
143
143
  }
144
144
  },
145
145
  seek(targetT, { wrap = false, step = curve.period / trailLength } = {}) {
146
146
  const advance = curve.speed * step;
147
- const target = ((targetT % curve.period) + curve.period) % curve.period;
147
+ const target = (targetT % curve.period + curve.period) % curve.period;
148
148
  const targetTime = target / curve.speed;
149
149
  t = target;
150
150
  actualTime = targetTime;
@@ -153,7 +153,7 @@ function createEngine(curveDef, trailLength = 120) {
153
153
  const count = wrap ? trailLength : Math.min(trailLength, pointsFromStart);
154
154
  for (let i = count - 1; i >= 0; i--) {
155
155
  const sampleT = target - i * advance;
156
- const wrappedT = ((sampleT % curve.period) + curve.period) % curve.period;
156
+ const wrappedT = (sampleT % curve.period + curve.period) % curve.period;
157
157
  const time = targetTime - i * step;
158
158
  const point = curve.fn(wrappedT, time, EMPTY_PARAMS);
159
159
  trail.push(point.x, point.y);
@@ -170,16 +170,13 @@ function createEngine(curveDef, trailLength = 120) {
170
170
  ...frozenB,
171
171
  fn: (sampleT, time, params) => {
172
172
  const a = frozenA.fn(sampleT, time, params);
173
- const tB =
174
- frozenStrategy === "normalized"
175
- ? (sampleT / frozenA.period) * frozenB.period
176
- : sampleT;
173
+ const tB = frozenStrategy === "normalized" ? sampleT / frozenA.period * frozenB.period : sampleT;
177
174
  const b = frozenB.fn(tB, time, params);
178
175
  return {
179
176
  x: a.x + (b.x - a.x) * frozenAlpha,
180
- y: a.y + (b.y - a.y) * frozenAlpha,
177
+ y: a.y + (b.y - a.y) * frozenAlpha
181
178
  };
182
- },
179
+ }
183
180
  };
184
181
  }
185
182
  _morphStrategy = strategy;
@@ -192,7 +189,7 @@ function createEngine(curveDef, trailLength = 120) {
192
189
  completeMorph() {
193
190
  if (morphCurveB !== null) {
194
191
  if (_morphStrategy === "normalized" && curve.period !== morphCurveB.period) {
195
- t = (t / curve.period) * morphCurveB.period;
192
+ t = t / curve.period * morphCurveB.period;
196
193
  }
197
194
  curve = morphCurveB;
198
195
  }
@@ -204,22 +201,19 @@ function createEngine(curveDef, trailLength = 120) {
204
201
  const points = new Array(steps);
205
202
  if (morphCurveB !== null && _morphAlpha !== null) {
206
203
  for (let i = 0; i < steps; i++) {
207
- const sampleT = (i / (steps - 1)) * curve.period;
204
+ const sampleT = i / (steps - 1) * curve.period;
208
205
  const a = sampleSkeleton(curve, sampleT);
209
- const tB =
210
- _morphStrategy === "normalized"
211
- ? (sampleT / curve.period) * morphCurveB.period
212
- : sampleT;
206
+ const tB = _morphStrategy === "normalized" ? sampleT / curve.period * morphCurveB.period : sampleT;
213
207
  const b = sampleSkeleton(morphCurveB, tB);
214
208
  points[i] = {
215
209
  x: a.x + (b.x - a.x) * _morphAlpha,
216
- y: a.y + (b.y - a.y) * _morphAlpha,
210
+ y: a.y + (b.y - a.y) * _morphAlpha
217
211
  };
218
212
  }
219
213
  return points;
220
214
  }
221
215
  for (let i = 0; i < steps; i++) {
222
- const sampleT = (i / (steps - 1)) * curve.period;
216
+ const sampleT = i / (steps - 1) * curve.period;
223
217
  points[i] = sampleSkeleton(curve, sampleT);
224
218
  }
225
219
  return points;
@@ -261,7 +255,7 @@ function createEngine(curveDef, trailLength = 120) {
261
255
  _speedTransition.reject(new Error("Speed transition cancelled"));
262
256
  _speedTransition = null;
263
257
  }
264
- },
258
+ }
265
259
  };
266
260
  }
267
261
 
@@ -300,15 +294,7 @@ function computeNormal(trail, i) {
300
294
  const tangent = computeTangent(trail, i);
301
295
  return { x: -tangent.y, y: tangent.x };
302
296
  }
303
- function computeTrailQuad(
304
- trail,
305
- i,
306
- trailCount,
307
- toX,
308
- toY,
309
- minWidth = TRAIL_MIN_WIDTH,
310
- maxWidth = TRAIL_MAX_WIDTH,
311
- ) {
297
+ function computeTrailQuad(trail, i, trailCount, toX, toY, minWidth = TRAIL_MIN_WIDTH, maxWidth = TRAIL_MAX_WIDTH) {
312
298
  const progress = i / (trailCount - 1);
313
299
  const nextProgress = (i + 1) / (trailCount - 1);
314
300
  const opacity = Math.pow(progress, TRAIL_FADE_CURVE) * TRAIL_MAX_OPACITY;
@@ -332,16 +318,13 @@ function computeTrailQuad(
332
318
  r1x: nx - n1.x * w1,
333
319
  r1y: ny - n1.y * w1,
334
320
  opacity,
335
- progress,
321
+ progress
336
322
  };
337
323
  }
338
324
  function computeBoundaries(pts, logicalWidth, logicalHeight) {
339
325
  if (pts.length === 0) return null;
340
326
  const first = pts[0];
341
- let minX = first.x,
342
- maxX = first.x,
343
- minY = first.y,
344
- maxY = first.y;
327
+ let minX = first.x, maxX = first.x, minY = first.y, maxY = first.y;
345
328
  for (const p of pts) {
346
329
  if (p.x < minX) {
347
330
  minX = p.x;
@@ -360,7 +343,7 @@ function computeBoundaries(pts, logicalWidth, logicalHeight) {
360
343
  const h = maxY - minY;
361
344
  if (w === 0 && h === 0) {
362
345
  throw new Error(
363
- "[sarmal] Degenerate curve: all skeleton points are identical. Check that your curve fn returns distinct points for different values of t.",
346
+ "[sarmal] Degenerate curve: all skeleton points are identical. Check that your curve fn returns distinct points for different values of t."
364
347
  );
365
348
  }
366
349
  const scaleXProportional = logicalWidth / (w * (1 + FIT_PADDING * 2));
@@ -371,12 +354,12 @@ function computeBoundaries(pts, logicalWidth, logicalHeight) {
371
354
  scaleXProportional,
372
355
  scaleYProportional,
373
356
  scaleXMinPadding,
374
- scaleYMinPadding,
357
+ scaleYMinPadding
375
358
  );
376
359
  return {
377
360
  scale,
378
361
  offsetX: (logicalWidth - w * scale) / 2 - minX * scale,
379
- offsetY: (logicalHeight - h * scale) / 2 - minY * scale,
362
+ offsetY: (logicalHeight - h * scale) / 2 - minY * scale
380
363
  };
381
364
  }
382
365
  function enginePassthroughs(engine) {
@@ -386,17 +369,17 @@ function enginePassthroughs(engine) {
386
369
  setSpeed: engine.setSpeed,
387
370
  getSpeed: engine.getSpeed,
388
371
  resetSpeed: engine.resetSpeed,
389
- setSpeedOver: engine.setSpeedOver,
372
+ setSpeedOver: engine.setSpeedOver
390
373
  };
391
374
  }
392
375
  function hexToRgb(hex) {
393
376
  const n = parseInt(hex.slice(1), 16);
394
- return { r: n >> 16, g: (n >> 8) & 255, b: n & 255 };
377
+ return { r: n >> 16, g: n >> 8 & 255, b: n & 255 };
395
378
  }
396
379
  var lerpRgb = (a, b, t) => ({
397
380
  r: Math.round(a.r + (b.r - a.r) * t),
398
381
  g: Math.round(a.g + (b.g - a.g) * t),
399
- b: Math.round(a.b + (b.b - a.b) * t),
382
+ b: Math.round(a.b + (b.b - a.b) * t)
400
383
  });
401
384
  function getPaletteColor(palette, position, timeOffset = 0) {
402
385
  if (palette.length === 0) {
@@ -405,7 +388,7 @@ function getPaletteColor(palette, position, timeOffset = 0) {
405
388
  if (palette.length === 1) {
406
389
  return hexToRgb(palette[0]);
407
390
  }
408
- const cyclePos = (((position + timeOffset) % 1) + 1) % 1;
391
+ const cyclePos = ((position + timeOffset) % 1 + 1) % 1;
409
392
  const scaled = cyclePos * palette.length;
410
393
  const idx = Math.floor(scaled);
411
394
  const t = scaled - idx;
@@ -420,7 +403,7 @@ var RENDER_OPTION_KEYS = /* @__PURE__ */ new Set([
420
403
  "headColor",
421
404
  "skeletonColor",
422
405
  "trailStyle",
423
- "headRadius",
406
+ "headRadius"
424
407
  ]);
425
408
  function validateRenderOptions(partial) {
426
409
  for (const key of Object.keys(partial)) {
@@ -448,7 +431,7 @@ function assertTrailColor(value) {
448
431
  if (typeof value === "string") {
449
432
  if (!HEX_COLOR_RE.test(value)) {
450
433
  throw new TypeError(
451
- `[sarmal] setRenderOptions: trailColor must be a 6-digit hex string, got "${value}"`,
434
+ `[sarmal] setRenderOptions: trailColor must be a 6-digit hex string, got "${value}"`
452
435
  );
453
436
  }
454
437
  return;
@@ -456,21 +439,21 @@ function assertTrailColor(value) {
456
439
  if (Array.isArray(value)) {
457
440
  if (value.length < 2) {
458
441
  throw new RangeError(
459
- `[sarmal] setRenderOptions: trailColor array must have at least 2 entries, got ${value.length}`,
442
+ `[sarmal] setRenderOptions: trailColor array must have at least 2 entries, got ${value.length}`
460
443
  );
461
444
  }
462
445
  for (let i = 0; i < value.length; i++) {
463
446
  const entry = value[i];
464
447
  if (typeof entry !== "string" || !HEX_COLOR_RE.test(entry)) {
465
448
  throw new TypeError(
466
- `[sarmal] setRenderOptions: trailColor[${i}] must be a 6-digit hex string, got ${JSON.stringify(entry)}`,
449
+ `[sarmal] setRenderOptions: trailColor[${i}] must be a 6-digit hex string, got ${JSON.stringify(entry)}`
467
450
  );
468
451
  }
469
452
  }
470
453
  return;
471
454
  }
472
455
  throw new TypeError(
473
- `[sarmal] setRenderOptions: trailColor must be a 6-digit hex string or an array of hex strings, got ${JSON.stringify(value)}`,
456
+ `[sarmal] setRenderOptions: trailColor must be a 6-digit hex string or an array of hex strings, got ${JSON.stringify(value)}`
474
457
  );
475
458
  }
476
459
  function assertHeadColor(value) {
@@ -479,7 +462,7 @@ function assertHeadColor(value) {
479
462
  }
480
463
  if (typeof value !== "string" || !HEX_COLOR_RE.test(value)) {
481
464
  throw new TypeError(
482
- `[sarmal] setRenderOptions: headColor must be a 6-digit hex string or null, got ${JSON.stringify(value)}`,
465
+ `[sarmal] setRenderOptions: headColor must be a 6-digit hex string or null, got ${JSON.stringify(value)}`
483
466
  );
484
467
  }
485
468
  }
@@ -489,26 +472,26 @@ function assertSkeletonColor(value) {
489
472
  }
490
473
  if (typeof value !== "string" || !HEX_COLOR_RE.test(value)) {
491
474
  throw new TypeError(
492
- `[sarmal] setRenderOptions: skeletonColor must be a 6-digit hex string or "transparent", got ${JSON.stringify(value)}`,
475
+ `[sarmal] setRenderOptions: skeletonColor must be a 6-digit hex string or "transparent", got ${JSON.stringify(value)}`
493
476
  );
494
477
  }
495
478
  }
496
479
  function assertTrailStyle(value) {
497
480
  if (!TRAIL_STYLES.includes(value)) {
498
481
  throw new RangeError(
499
- `[sarmal] setRenderOptions: trailStyle must be one of "default", "gradient-static", "gradient-animated", got ${JSON.stringify(value)}`,
482
+ `[sarmal] setRenderOptions: trailStyle must be one of "default", "gradient-static", "gradient-animated", got ${JSON.stringify(value)}`
500
483
  );
501
484
  }
502
485
  }
503
486
  function assertHeadRadius(value) {
504
487
  if (typeof value !== "number") {
505
488
  throw new TypeError(
506
- `[sarmal] setRenderOptions: headRadius must be a number, got ${JSON.stringify(value)}`,
489
+ `[sarmal] setRenderOptions: headRadius must be a number, got ${JSON.stringify(value)}`
507
490
  );
508
491
  }
509
492
  if (!Number.isFinite(value) || value <= 0) {
510
493
  throw new TypeError(
511
- `[sarmal] setRenderOptions: headRadius must be a finite positive number, got ${value}`,
494
+ `[sarmal] setRenderOptions: headRadius must be a finite positive number, got ${value}`
512
495
  );
513
496
  }
514
497
  }
@@ -530,13 +513,13 @@ function resolveHeadColor(trailColor, trailStyle) {
530
513
  function warnIfTrailColorMismatch(trailColor, trailStyle) {
531
514
  if (trailStyle === "default" && Array.isArray(trailColor)) {
532
515
  console.warn(
533
- '[sarmal] trailColor is an array but trailStyle is "default"; only the first color will be used. Pass a gradient trailStyle to use the whole palette.',
516
+ '[sarmal] trailColor is an array but trailStyle is "default"; only the first color will be used. Pass a gradient trailStyle to use the whole palette.'
534
517
  );
535
518
  return;
536
519
  }
537
520
  if (trailStyle !== "default" && typeof trailColor === "string") {
538
521
  console.warn(
539
- `[sarmal] trailColor is a single color but trailStyle is "${trailStyle}"; the trail will render as a solid color. Pass an array of hex colors to use a real gradient.`,
522
+ `[sarmal] trailColor is a single color but trailStyle is "${trailStyle}"; the trail will render as a solid color. Pass an array of hex colors to use a real gradient.`
540
523
  );
541
524
  }
542
525
  }
@@ -546,7 +529,7 @@ var getHeadDotRadius = (w, h) => Math.max(1, 3 * Math.sqrt(Math.min(w, h) / 160)
546
529
  var WHITE_HEX = "#ffffff";
547
530
  function hexToRgbComponents(hex) {
548
531
  const n = parseInt(hex.slice(1), 16);
549
- return `${n >> 16},${(n >> 8) & 255},${n & 255}`;
532
+ return `${n >> 16},${n >> 8 & 255},${n & 255}`;
550
533
  }
551
534
  function applyDprSizing(target, logicalWidth, logicalHeight, dpr) {
552
535
  target.style.width = `${logicalWidth}px`;
@@ -590,6 +573,7 @@ function createRenderer(options) {
590
573
  let offsetY = 0;
591
574
  let animationId = null;
592
575
  let lastTime = 0;
576
+ let pausedByVisibility = false;
593
577
  let morphResolve = null;
594
578
  let morphReject = null;
595
579
  let morphDurationMs = DEFAULT_MORPH_DURATION_MS;
@@ -672,7 +656,7 @@ function createRenderer(options) {
672
656
  i,
673
657
  trailCount,
674
658
  toX,
675
- toY,
659
+ toY
676
660
  );
677
661
  if (trailStyle === "default") {
678
662
  ctx.fillStyle = `rgba(${trailSolidRgb},${opacity})`;
@@ -783,6 +767,7 @@ function createRenderer(options) {
783
767
  cancelAnimationFrame(animationId);
784
768
  animationId = null;
785
769
  }
770
+ document.removeEventListener("visibilitychange", handleVisibilityChange);
786
771
  if (morphReject !== null) {
787
772
  morphReject(new Error("Instance destroyed during morph"));
788
773
  morphResolve = null;
@@ -836,10 +821,30 @@ function createRenderer(options) {
836
821
  if (partial.trailColor !== void 0 || partial.trailStyle !== void 0) {
837
822
  warnIfTrailColorMismatch(trailColor, trailStyle);
838
823
  }
839
- },
824
+ }
840
825
  };
841
- if (shouldAutoStart) {
826
+ const pauseOnHidden = options.pauseOnHidden !== false;
827
+ function handleVisibilityChange() {
828
+ if (document.hidden) {
829
+ if (animationId !== null) {
830
+ instance.pause();
831
+ pausedByVisibility = true;
832
+ }
833
+ } else {
834
+ if (pausedByVisibility) {
835
+ pausedByVisibility = false;
836
+ instance.play();
837
+ }
838
+ }
839
+ }
840
+ if (pauseOnHidden) {
841
+ document.addEventListener("visibilitychange", handleVisibilityChange);
842
+ }
843
+ const actuallyAutoStart = shouldAutoStart && !(pauseOnHidden && document.hidden);
844
+ if (actuallyAutoStart) {
842
845
  instance.play();
846
+ } else if (shouldAutoStart) {
847
+ pausedByVisibility = true;
843
848
  }
844
849
  return instance;
845
850
  }
@@ -866,7 +871,7 @@ function sampleCurveSkeleton(curveDef) {
866
871
  const samples = Math.ceil(period * 50);
867
872
  const pts = Array.from({ length: samples });
868
873
  for (let i = 0; i < samples; i++) {
869
- const t = (i / (samples - 1)) * period;
874
+ const t = i / (samples - 1) * period;
870
875
  pts[i] = curveDef.skeletonFn ? curveDef.skeletonFn(t) : curveDef.fn(t, 0, EMPTY_PARAMS2);
871
876
  }
872
877
  return pts;
@@ -879,7 +884,7 @@ function createSVGRenderer(options) {
879
884
  const poolSize = engine.trailLength;
880
885
  if (poolSize > HIGH_TRAIL_LENGTH_THRESHOLD) {
881
886
  console.warn(
882
- `[sarmal] High trailLength in SVG renderer (${poolSize}). Consider using the canvas renderer for long trails.`,
887
+ `[sarmal] High trailLength in SVG renderer (${poolSize}). Consider using the canvas renderer for long trails.`
883
888
  );
884
889
  }
885
890
  let trailStyle = options.trailStyle ?? "default";
@@ -898,9 +903,9 @@ function createSVGRenderer(options) {
898
903
  return rect.width && rect.height ? Math.min(rect.width, rect.height) : 200;
899
904
  }
900
905
  const containerPx = getContainerPixelSize();
901
- const svgTrailMinWidth = (TRAIL_MIN_WIDTH * viewSize) / containerPx;
902
- const svgTrailMaxWidth = (TRAIL_MAX_WIDTH * viewSize) / containerPx;
903
- const svgSkeletonStrokeWidth = String((SKELETON_STROKE_WIDTH_PX * viewSize) / containerPx);
906
+ const svgTrailMinWidth = TRAIL_MIN_WIDTH * viewSize / containerPx;
907
+ const svgTrailMaxWidth = TRAIL_MAX_WIDTH * viewSize / containerPx;
908
+ const svgSkeletonStrokeWidth = String(SKELETON_STROKE_WIDTH_PX * viewSize / containerPx);
904
909
  headRadius = options.headRadius ?? SVG_DEFAULT_HEAD_RADIUS;
905
910
  container.setAttribute("viewBox", `0 0 ${viewSize} ${viewSize}`);
906
911
  container.setAttribute("role", "img");
@@ -988,7 +993,7 @@ function createSVGRenderer(options) {
988
993
  px,
989
994
  py,
990
995
  svgTrailMinWidth,
991
- svgTrailMaxWidth,
996
+ svgTrailMaxWidth
992
997
  );
993
998
  const d = `M${l0x.toFixed(2)} ${l0y.toFixed(2)} L${l1x.toFixed(2)} ${l1y.toFixed(2)} L${r1x.toFixed(2)} ${r1y.toFixed(2)} L${r0x.toFixed(2)} ${r0y.toFixed(2)} Z`;
994
999
  trailPaths[i].setAttribute("d", d);
@@ -1015,8 +1020,8 @@ function createSVGRenderer(options) {
1015
1020
  }
1016
1021
  let animationId = null;
1017
1022
  let lastTime = 0;
1018
- const prefersReducedMotion =
1019
- typeof window !== "undefined" && window.matchMedia("(prefers-reduced-motion: reduce)").matches;
1023
+ let pausedByVisibility = false;
1024
+ const prefersReducedMotion = typeof window !== "undefined" && window.matchMedia("(prefers-reduced-motion: reduce)").matches;
1020
1025
  let morphResolve = null;
1021
1026
  let morphReject = null;
1022
1027
  let morphDurationMs = DEFAULT_MORPH_DURATION_MS;
@@ -1034,7 +1039,7 @@ function createSVGRenderer(options) {
1034
1039
  skeletonPathA.setAttribute("visibility", "visible");
1035
1040
  skeletonPathA.setAttribute(
1036
1041
  "stroke-opacity",
1037
- String((1 - morphAlpha) * DEFAULT_SKELETON_OPACITY),
1042
+ String((1 - morphAlpha) * DEFAULT_SKELETON_OPACITY)
1038
1043
  );
1039
1044
  }
1040
1045
  if (morphPathBBuilt) {
@@ -1106,6 +1111,7 @@ function createSVGRenderer(options) {
1106
1111
  cancelAnimationFrame(animationId);
1107
1112
  animationId = null;
1108
1113
  }
1114
+ document.removeEventListener("visibilitychange", handleVisibilityChange);
1109
1115
  if (morphReject !== null) {
1110
1116
  morphReject(new Error("Instance destroyed during morph"));
1111
1117
  morphResolve = null;
@@ -1187,10 +1193,30 @@ function createSVGRenderer(options) {
1187
1193
  if (partial.trailColor !== void 0 || partial.trailStyle !== void 0) {
1188
1194
  warnIfTrailColorMismatch(trailColor, trailStyle);
1189
1195
  }
1190
- },
1196
+ }
1191
1197
  };
1192
- if (shouldAutoStart) {
1198
+ const pauseOnHidden = options.pauseOnHidden !== false;
1199
+ function handleVisibilityChange() {
1200
+ if (document.hidden) {
1201
+ if (animationId !== null) {
1202
+ instance.pause();
1203
+ pausedByVisibility = true;
1204
+ }
1205
+ } else {
1206
+ if (pausedByVisibility) {
1207
+ pausedByVisibility = false;
1208
+ instance.play();
1209
+ }
1210
+ }
1211
+ }
1212
+ if (pauseOnHidden) {
1213
+ document.addEventListener("visibilitychange", handleVisibilityChange);
1214
+ }
1215
+ const actuallyAutoStart = shouldAutoStart && !(pauseOnHidden && document.hidden);
1216
+ if (actuallyAutoStart) {
1193
1217
  instance.play();
1218
+ } else if (shouldAutoStart) {
1219
+ pausedByVisibility = true;
1194
1220
  }
1195
1221
  return instance;
1196
1222
  }
@@ -1203,22 +1229,19 @@ function createSarmalSVG(container, curveDef, options) {
1203
1229
  // src/curves/artemis2.ts
1204
1230
  var TWO_PI2 = Math.PI * 2;
1205
1231
  function artemis2Fn(t, _time, _params) {
1206
- const a = 0.35,
1207
- b = 0.15,
1208
- ox = 0.175;
1209
- const s = Math.sin(t),
1210
- c = Math.cos(t);
1232
+ const a = 0.35, b = 0.15, ox = 0.175;
1233
+ const s = Math.sin(t), c = Math.cos(t);
1211
1234
  const denom = 1 + s * s;
1212
1235
  return {
1213
- x: (c * (1 + a * c)) / denom - ox,
1214
- y: (s * c * (1 + b * c)) / denom,
1236
+ x: c * (1 + a * c) / denom - ox,
1237
+ y: s * c * (1 + b * c) / denom
1215
1238
  };
1216
1239
  }
1217
1240
  var artemis2 = {
1218
1241
  name: "Artemis II",
1219
1242
  fn: artemis2Fn,
1220
1243
  period: TWO_PI2,
1221
- speed: 0.7,
1244
+ speed: 0.7
1222
1245
  };
1223
1246
 
1224
1247
  // src/curves/astroid.ts
@@ -1228,14 +1251,14 @@ function astroidFn(t, _time, _params) {
1228
1251
  const s = Math.sin(t);
1229
1252
  return {
1230
1253
  x: c * c * c,
1231
- y: s * s * s,
1254
+ y: s * s * s
1232
1255
  };
1233
1256
  }
1234
1257
  var astroid = {
1235
1258
  name: "Astroid",
1236
1259
  fn: astroidFn,
1237
1260
  period: TWO_PI3,
1238
- speed: 1.1,
1261
+ speed: 1.1
1239
1262
  };
1240
1263
 
1241
1264
  // src/curves/deltoid.ts
@@ -1243,14 +1266,14 @@ var TWO_PI4 = Math.PI * 2;
1243
1266
  function deltoidFn(t, _time, _params) {
1244
1267
  return {
1245
1268
  x: 2 * Math.cos(t) + Math.cos(2 * t),
1246
- y: 2 * Math.sin(t) - Math.sin(2 * t),
1269
+ y: 2 * Math.sin(t) - Math.sin(2 * t)
1247
1270
  };
1248
1271
  }
1249
1272
  var deltoid = {
1250
1273
  name: "Deltoid",
1251
1274
  fn: deltoidFn,
1252
1275
  period: TWO_PI4,
1253
- speed: 0.9,
1276
+ speed: 0.9
1254
1277
  };
1255
1278
 
1256
1279
  // src/curves/epicycloid3.ts
@@ -1258,14 +1281,14 @@ var TWO_PI5 = Math.PI * 2;
1258
1281
  function epicycloid3Fn(t, _time, _params) {
1259
1282
  return {
1260
1283
  x: 4 * Math.cos(t) - Math.cos(4 * t),
1261
- y: 4 * Math.sin(t) - Math.sin(4 * t),
1284
+ y: 4 * Math.sin(t) - Math.sin(4 * t)
1262
1285
  };
1263
1286
  }
1264
1287
  var epicycloid3 = {
1265
1288
  name: "Epicycloid (n=3)",
1266
1289
  fn: epicycloid3Fn,
1267
1290
  period: TWO_PI5,
1268
- speed: 0.75,
1291
+ speed: 0.75
1269
1292
  };
1270
1293
 
1271
1294
  // src/curves/epitrochoid7.ts
@@ -1274,14 +1297,14 @@ function epitrochoid7Fn(t, _time, _params) {
1274
1297
  const d = 1 + 0.55 * Math.sin(t * 0.5);
1275
1298
  return {
1276
1299
  x: 7 * Math.cos(t) - d * Math.cos(7 * t),
1277
- y: 7 * Math.sin(t) - d * Math.sin(7 * t),
1300
+ y: 7 * Math.sin(t) - d * Math.sin(7 * t)
1278
1301
  };
1279
1302
  }
1280
1303
  function epitrochoid7SkeletonFn(t) {
1281
1304
  const d = 1.275;
1282
1305
  return {
1283
1306
  x: 7 * Math.cos(t) - d * Math.cos(7 * t),
1284
- y: 7 * Math.sin(t) - d * Math.sin(7 * t),
1307
+ y: 7 * Math.sin(t) - d * Math.sin(7 * t)
1285
1308
  };
1286
1309
  }
1287
1310
  var epitrochoid7 = {
@@ -1289,7 +1312,7 @@ var epitrochoid7 = {
1289
1312
  fn: epitrochoid7Fn,
1290
1313
  period: TWO_PI6,
1291
1314
  speed: 1.4,
1292
- skeletonFn: epitrochoid7SkeletonFn,
1315
+ skeletonFn: epitrochoid7SkeletonFn
1293
1316
  };
1294
1317
 
1295
1318
  // src/curves/lissajous32.ts
@@ -1298,7 +1321,7 @@ function lissajous32Fn(t, time, _params) {
1298
1321
  const phi = time * 0.45;
1299
1322
  return {
1300
1323
  x: Math.sin(3 * t + phi),
1301
- y: Math.sin(2 * t),
1324
+ y: Math.sin(2 * t)
1302
1325
  };
1303
1326
  }
1304
1327
  var lissajous32 = {
@@ -1306,7 +1329,7 @@ var lissajous32 = {
1306
1329
  fn: lissajous32Fn,
1307
1330
  period: TWO_PI7,
1308
1331
  speed: 2,
1309
- skeleton: "live",
1332
+ skeleton: "live"
1310
1333
  };
1311
1334
 
1312
1335
  // src/curves/lissajous43.ts
@@ -1315,7 +1338,7 @@ function lissajous43Fn(t, time, _params) {
1315
1338
  const phi = time * 0.38;
1316
1339
  return {
1317
1340
  x: Math.sin(4 * t + phi),
1318
- y: Math.sin(3 * t),
1341
+ y: Math.sin(3 * t)
1319
1342
  };
1320
1343
  }
1321
1344
  var lissajous43 = {
@@ -1323,18 +1346,17 @@ var lissajous43 = {
1323
1346
  fn: lissajous43Fn,
1324
1347
  period: TWO_PI8,
1325
1348
  speed: 1.8,
1326
- skeleton: "live",
1349
+ skeleton: "live"
1327
1350
  };
1328
1351
 
1329
1352
  // src/curves/lame.ts
1330
1353
  var TWO_PI9 = Math.PI * 2;
1331
1354
  function lameFn(t, time, _params) {
1332
1355
  const p = 1.75 + 1.25 * Math.sin(time * 0.48);
1333
- const c = Math.cos(t),
1334
- s = Math.sin(t);
1356
+ const c = Math.cos(t), s = Math.sin(t);
1335
1357
  return {
1336
1358
  x: Math.sign(c) * Math.pow(Math.abs(c), p),
1337
- y: Math.sign(s) * Math.pow(Math.abs(s), p),
1359
+ y: Math.sign(s) * Math.pow(Math.abs(s), p)
1338
1360
  };
1339
1361
  }
1340
1362
  var lame = {
@@ -1342,7 +1364,7 @@ var lame = {
1342
1364
  fn: lameFn,
1343
1365
  period: TWO_PI9,
1344
1366
  speed: 1,
1345
- skeleton: "live",
1367
+ skeleton: "live"
1346
1368
  };
1347
1369
 
1348
1370
  // src/curves/rose3.ts
@@ -1351,14 +1373,14 @@ function rose3Fn(t, _time, _params) {
1351
1373
  const r = Math.cos(3 * t);
1352
1374
  return {
1353
1375
  x: r * Math.cos(t),
1354
- y: r * Math.sin(t),
1376
+ y: r * Math.sin(t)
1355
1377
  };
1356
1378
  }
1357
1379
  var rose3 = {
1358
1380
  name: "Rose (n=3)",
1359
1381
  fn: rose3Fn,
1360
1382
  period: TWO_PI10,
1361
- speed: 1.15,
1383
+ speed: 1.15
1362
1384
  };
1363
1385
 
1364
1386
  // src/curves/rose5.ts
@@ -1367,87 +1389,78 @@ function rose5Fn(t, _time, _params) {
1367
1389
  const r = Math.cos(5 * t);
1368
1390
  return {
1369
1391
  x: r * Math.cos(t),
1370
- y: r * Math.sin(t),
1392
+ y: r * Math.sin(t)
1371
1393
  };
1372
1394
  }
1373
1395
  var rose5 = {
1374
1396
  name: "Rose (n=5)",
1375
1397
  fn: rose5Fn,
1376
1398
  period: TWO_PI11,
1377
- speed: 1,
1399
+ speed: 1
1378
1400
  };
1379
1401
 
1380
1402
  // src/curves/rose52.ts
1381
1403
  var FOUR_PI = Math.PI * 4;
1382
1404
  function rose52Fn(t, _time, _params) {
1383
- const r = Math.cos((5 / 2) * t);
1405
+ const r = Math.cos(5 / 2 * t);
1384
1406
  return {
1385
1407
  x: r * Math.cos(t),
1386
- y: r * Math.sin(t),
1408
+ y: r * Math.sin(t)
1387
1409
  };
1388
1410
  }
1389
1411
  var rose52 = {
1390
1412
  name: "Rose (n=5/2)",
1391
1413
  fn: rose52Fn,
1392
1414
  period: FOUR_PI,
1393
- speed: 0.8,
1415
+ speed: 0.8
1394
1416
  };
1395
1417
 
1396
1418
  // src/curves/star.ts
1397
1419
  var TWO_PI12 = Math.PI * 2;
1398
1420
  function starFn(t, _time, _params) {
1399
- const r =
1400
- Math.abs(Math.cos((5 / 2) * t)) +
1401
- 0.35 * Math.abs(Math.cos((15 / 2) * t)) +
1402
- 0.15 * Math.abs(Math.cos((25 / 2) * t));
1421
+ const r = Math.abs(Math.cos(5 / 2 * t)) + 0.35 * Math.abs(Math.cos(15 / 2 * t)) + 0.15 * Math.abs(Math.cos(25 / 2 * t));
1403
1422
  return {
1404
1423
  x: r * Math.cos(t),
1405
- y: r * Math.sin(t),
1424
+ y: r * Math.sin(t)
1406
1425
  };
1407
1426
  }
1408
1427
  var star = {
1409
1428
  name: "Star",
1410
1429
  fn: starFn,
1411
1430
  period: TWO_PI12,
1412
- speed: 1,
1431
+ speed: 1
1413
1432
  };
1414
1433
 
1415
1434
  // src/curves/star4.ts
1416
1435
  var TWO_PI13 = Math.PI * 2;
1417
1436
  function star4Fn(t, _time, _params) {
1418
- const r =
1419
- Math.abs(Math.cos(2 * t)) +
1420
- 0.35 * Math.abs(Math.cos(6 * t)) +
1421
- 0.15 * Math.abs(Math.cos(10 * t));
1437
+ const r = Math.abs(Math.cos(2 * t)) + 0.35 * Math.abs(Math.cos(6 * t)) + 0.15 * Math.abs(Math.cos(10 * t));
1422
1438
  return {
1423
1439
  x: r * Math.cos(t),
1424
- y: r * Math.sin(t),
1440
+ y: r * Math.sin(t)
1425
1441
  };
1426
1442
  }
1427
1443
  var star4 = {
1428
1444
  name: "Star (4-arm)",
1429
1445
  fn: star4Fn,
1430
1446
  period: TWO_PI13,
1431
- speed: 1,
1447
+ speed: 1
1432
1448
  };
1433
1449
 
1434
1450
  // src/curves/star7.ts
1435
1451
  var TWO_PI14 = Math.PI * 2;
1436
1452
  function star7Fn(t, _time, _params) {
1437
- const r =
1438
- Math.abs(Math.cos((7 / 2) * t)) +
1439
- 0.35 * Math.abs(Math.cos((21 / 2) * t)) +
1440
- 0.15 * Math.abs(Math.cos((35 / 2) * t));
1453
+ const r = Math.abs(Math.cos(7 / 2 * t)) + 0.35 * Math.abs(Math.cos(21 / 2 * t)) + 0.15 * Math.abs(Math.cos(35 / 2 * t));
1441
1454
  return {
1442
1455
  x: r * Math.cos(t),
1443
- y: r * Math.sin(t),
1456
+ y: r * Math.sin(t)
1444
1457
  };
1445
1458
  }
1446
1459
  var star7 = {
1447
1460
  name: "Star (7-arm)",
1448
1461
  fn: star7Fn,
1449
1462
  period: TWO_PI14,
1450
- speed: 1,
1463
+ speed: 1
1451
1464
  };
1452
1465
 
1453
1466
  // src/curves/index.ts
@@ -1465,7 +1478,7 @@ var curves = {
1465
1478
  lissajous32,
1466
1479
  lissajous43,
1467
1480
  epicycloid3,
1468
- lame,
1481
+ lame
1469
1482
  };
1470
1483
 
1471
1484
  // src/index.ts
@@ -1482,21 +1495,22 @@ function parseTrailColor(value) {
1482
1495
  if (Array.isArray(parsed)) {
1483
1496
  return parsed;
1484
1497
  }
1485
- } catch {}
1498
+ } catch {
1499
+ }
1486
1500
  return value;
1487
1501
  }
1488
1502
  function buildOptions(el2) {
1489
1503
  return {
1490
- ...(el2.dataset.trailColor && {
1491
- trailColor: parseTrailColor(el2.dataset.trailColor),
1492
- }),
1493
- ...(el2.dataset.skeletonColor && { skeletonColor: el2.dataset.skeletonColor }),
1494
- ...(el2.dataset.headColor && { headColor: el2.dataset.headColor }),
1495
- ...(el2.dataset.headRadius && { headRadius: parseFloat(el2.dataset.headRadius) }),
1496
- ...(el2.dataset.trailLength && { trailLength: parseInt(el2.dataset.trailLength, 10) }),
1497
- ...(el2.dataset.trailStyle && {
1498
- trailStyle: el2.dataset.trailStyle,
1499
- }),
1504
+ ...el2.dataset.trailColor && {
1505
+ trailColor: parseTrailColor(el2.dataset.trailColor)
1506
+ },
1507
+ ...el2.dataset.skeletonColor && { skeletonColor: el2.dataset.skeletonColor },
1508
+ ...el2.dataset.headColor && { headColor: el2.dataset.headColor },
1509
+ ...el2.dataset.headRadius && { headRadius: parseFloat(el2.dataset.headRadius) },
1510
+ ...el2.dataset.trailLength && { trailLength: parseInt(el2.dataset.trailLength, 10) },
1511
+ ...el2.dataset.trailStyle && {
1512
+ trailStyle: el2.dataset.trailStyle
1513
+ }
1500
1514
  };
1501
1515
  }
1502
1516
  function init() {
@@ -1511,10 +1525,7 @@ function init() {
1511
1525
  return console.error(`[sarmal] "${curveName}" is not a valid curve name`);
1512
1526
  }
1513
1527
  const options = buildOptions(el2);
1514
- const instance =
1515
- el2 instanceof HTMLCanvasElement
1516
- ? createSarmal(el2, curveDef, options)
1517
- : createSarmalSVG(el2, curveDef, options);
1528
+ const instance = el2 instanceof HTMLCanvasElement ? createSarmal(el2, curveDef, options) : createSarmalSVG(el2, curveDef, options);
1518
1529
  if (el2.dataset.speed) {
1519
1530
  instance.setSpeed(parseFloat(el2.dataset.speed));
1520
1531
  }
@@ -1530,4 +1541,4 @@ if (document.readyState === "loading") {
1530
1541
 
1531
1542
  exports.init = init;
1532
1543
  //# sourceMappingURL=auto-init.cjs.map
1533
- //# sourceMappingURL=auto-init.cjs.map
1544
+ //# sourceMappingURL=auto-init.cjs.map