@sarmal/core 0.17.3 → 0.19.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 (76) hide show
  1. package/README.md +1 -12
  2. package/dist/auto-init.cjs +124 -92
  3. package/dist/auto-init.cjs.map +1 -1
  4. package/dist/auto-init.js +123 -91
  5. package/dist/auto-init.js.map +1 -1
  6. package/dist/curves/artemis2.cjs +10 -7
  7. package/dist/curves/artemis2.d.cts +1 -1
  8. package/dist/curves/artemis2.d.ts +1 -1
  9. package/dist/curves/artemis2.js +9 -6
  10. package/dist/curves/astroid.cjs +4 -4
  11. package/dist/curves/astroid.d.cts +1 -1
  12. package/dist/curves/astroid.d.ts +1 -1
  13. package/dist/curves/astroid.js +3 -3
  14. package/dist/curves/deltoid.cjs +4 -4
  15. package/dist/curves/deltoid.d.cts +1 -1
  16. package/dist/curves/deltoid.d.ts +1 -1
  17. package/dist/curves/deltoid.js +3 -3
  18. package/dist/curves/epicycloid3.cjs +4 -4
  19. package/dist/curves/epicycloid3.d.cts +1 -1
  20. package/dist/curves/epicycloid3.d.ts +1 -1
  21. package/dist/curves/epicycloid3.js +3 -3
  22. package/dist/curves/epitrochoid7.cjs +5 -5
  23. package/dist/curves/epitrochoid7.d.cts +1 -1
  24. package/dist/curves/epitrochoid7.d.ts +1 -1
  25. package/dist/curves/epitrochoid7.js +4 -4
  26. package/dist/curves/index.cjs +53 -40
  27. package/dist/curves/index.d.cts +29 -29
  28. package/dist/curves/index.d.ts +29 -29
  29. package/dist/curves/index.js +69 -40
  30. package/dist/curves/lame.cjs +6 -5
  31. package/dist/curves/lame.d.cts +1 -1
  32. package/dist/curves/lame.d.ts +1 -1
  33. package/dist/curves/lame.js +5 -4
  34. package/dist/curves/lissajous32.cjs +4 -4
  35. package/dist/curves/lissajous32.d.cts +1 -1
  36. package/dist/curves/lissajous32.d.ts +1 -1
  37. package/dist/curves/lissajous32.js +3 -3
  38. package/dist/curves/lissajous43.cjs +4 -4
  39. package/dist/curves/lissajous43.d.cts +1 -1
  40. package/dist/curves/lissajous43.d.ts +1 -1
  41. package/dist/curves/lissajous43.js +3 -3
  42. package/dist/curves/rose3.cjs +4 -4
  43. package/dist/curves/rose3.d.cts +1 -1
  44. package/dist/curves/rose3.d.ts +1 -1
  45. package/dist/curves/rose3.js +3 -3
  46. package/dist/curves/rose5.cjs +4 -4
  47. package/dist/curves/rose5.d.cts +1 -1
  48. package/dist/curves/rose5.d.ts +1 -1
  49. package/dist/curves/rose5.js +3 -3
  50. package/dist/curves/rose52.cjs +5 -5
  51. package/dist/curves/rose52.d.cts +1 -1
  52. package/dist/curves/rose52.d.ts +1 -1
  53. package/dist/curves/rose52.js +4 -4
  54. package/dist/curves/star.cjs +8 -5
  55. package/dist/curves/star.d.cts +1 -1
  56. package/dist/curves/star.d.ts +1 -1
  57. package/dist/curves/star.js +7 -4
  58. package/dist/curves/star4.cjs +8 -5
  59. package/dist/curves/star4.d.cts +1 -1
  60. package/dist/curves/star4.d.ts +1 -1
  61. package/dist/curves/star4.js +7 -4
  62. package/dist/curves/star7.cjs +8 -5
  63. package/dist/curves/star7.d.cts +1 -1
  64. package/dist/curves/star7.d.ts +1 -1
  65. package/dist/curves/star7.js +7 -4
  66. package/dist/index.cjs +159 -118
  67. package/dist/index.cjs.map +1 -1
  68. package/dist/index.d.cts +78 -37
  69. package/dist/index.d.ts +78 -37
  70. package/dist/index.js +177 -118
  71. package/dist/index.js.map +1 -1
  72. package/dist/types-frtEoAq6.d.cts +317 -0
  73. package/dist/types-frtEoAq6.d.ts +317 -0
  74. package/package.json +1 -1
  75. package/dist/types-BL9HhEmk.d.cts +0 -299
  76. package/dist/types-BL9HhEmk.d.ts +0 -299
package/dist/index.cjs CHANGED
@@ -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 {
@@ -122,6 +122,9 @@ function createEngine(curveDef, trailLength = 120) {
122
122
  get trailCount() {
123
123
  return trail.length;
124
124
  },
125
+ get trailLength() {
126
+ return trailLength;
127
+ },
125
128
  get isLiveSkeleton() {
126
129
  return curve.skeleton === "live";
127
130
  },
@@ -134,14 +137,14 @@ function createEngine(curveDef, trailLength = 120) {
134
137
  trail.clear();
135
138
  },
136
139
  jump(newT, { clearTrail = false } = {}) {
137
- t = (newT % curve.period + curve.period) % curve.period;
140
+ t = ((newT % curve.period) + curve.period) % curve.period;
138
141
  if (clearTrail) {
139
142
  trail.clear();
140
143
  }
141
144
  },
142
145
  seek(targetT, { wrap = false, step = curve.period / trailLength } = {}) {
143
146
  const advance = curve.speed * step;
144
- const target = (targetT % curve.period + curve.period) % curve.period;
147
+ const target = ((targetT % curve.period) + curve.period) % curve.period;
145
148
  const targetTime = target / curve.speed;
146
149
  t = target;
147
150
  actualTime = targetTime;
@@ -150,7 +153,7 @@ function createEngine(curveDef, trailLength = 120) {
150
153
  const count = wrap ? trailLength : Math.min(trailLength, pointsFromStart);
151
154
  for (let i = count - 1; i >= 0; i--) {
152
155
  const sampleT = target - i * advance;
153
- const wrappedT = (sampleT % curve.period + curve.period) % curve.period;
156
+ const wrappedT = ((sampleT % curve.period) + curve.period) % curve.period;
154
157
  const time = targetTime - i * step;
155
158
  const point = curve.fn(wrappedT, time, EMPTY_PARAMS);
156
159
  trail.push(point.x, point.y);
@@ -167,13 +170,16 @@ function createEngine(curveDef, trailLength = 120) {
167
170
  ...frozenB,
168
171
  fn: (sampleT, time, params) => {
169
172
  const a = frozenA.fn(sampleT, time, params);
170
- const tB = frozenStrategy === "normalized" ? sampleT / frozenA.period * frozenB.period : sampleT;
173
+ const tB =
174
+ frozenStrategy === "normalized"
175
+ ? (sampleT / frozenA.period) * frozenB.period
176
+ : sampleT;
171
177
  const b = frozenB.fn(tB, time, params);
172
178
  return {
173
179
  x: a.x + (b.x - a.x) * frozenAlpha,
174
- y: a.y + (b.y - a.y) * frozenAlpha
180
+ y: a.y + (b.y - a.y) * frozenAlpha,
175
181
  };
176
- }
182
+ },
177
183
  };
178
184
  }
179
185
  _morphStrategy = strategy;
@@ -186,7 +192,7 @@ function createEngine(curveDef, trailLength = 120) {
186
192
  completeMorph() {
187
193
  if (morphCurveB !== null) {
188
194
  if (_morphStrategy === "normalized" && curve.period !== morphCurveB.period) {
189
- t = t / curve.period * morphCurveB.period;
195
+ t = (t / curve.period) * morphCurveB.period;
190
196
  }
191
197
  curve = morphCurveB;
192
198
  }
@@ -198,19 +204,22 @@ function createEngine(curveDef, trailLength = 120) {
198
204
  const points = new Array(steps);
199
205
  if (morphCurveB !== null && _morphAlpha !== null) {
200
206
  for (let i = 0; i < steps; i++) {
201
- const sampleT = i / (steps - 1) * curve.period;
207
+ const sampleT = (i / (steps - 1)) * curve.period;
202
208
  const a = sampleSkeleton(curve, sampleT);
203
- const tB = _morphStrategy === "normalized" ? sampleT / curve.period * morphCurveB.period : sampleT;
209
+ const tB =
210
+ _morphStrategy === "normalized"
211
+ ? (sampleT / curve.period) * morphCurveB.period
212
+ : sampleT;
204
213
  const b = sampleSkeleton(morphCurveB, tB);
205
214
  points[i] = {
206
215
  x: a.x + (b.x - a.x) * _morphAlpha,
207
- y: a.y + (b.y - a.y) * _morphAlpha
216
+ y: a.y + (b.y - a.y) * _morphAlpha,
208
217
  };
209
218
  }
210
219
  return points;
211
220
  }
212
221
  for (let i = 0; i < steps; i++) {
213
- const sampleT = i / (steps - 1) * curve.period;
222
+ const sampleT = (i / (steps - 1)) * curve.period;
214
223
  points[i] = sampleSkeleton(curve, sampleT);
215
224
  }
216
225
  return points;
@@ -252,7 +261,7 @@ function createEngine(curveDef, trailLength = 120) {
252
261
  _speedTransition.reject(new Error("Speed transition cancelled"));
253
262
  _speedTransition = null;
254
263
  }
255
- }
264
+ },
256
265
  };
257
266
  }
258
267
 
@@ -291,12 +300,20 @@ function computeNormal(trail, i) {
291
300
  const tangent = computeTangent(trail, i);
292
301
  return { x: -tangent.y, y: tangent.x };
293
302
  }
294
- function computeTrailQuad(trail, i, trailCount, toX, toY) {
303
+ function computeTrailQuad(
304
+ trail,
305
+ i,
306
+ trailCount,
307
+ toX,
308
+ toY,
309
+ minWidth = TRAIL_MIN_WIDTH,
310
+ maxWidth = TRAIL_MAX_WIDTH,
311
+ ) {
295
312
  const progress = i / (trailCount - 1);
296
313
  const nextProgress = (i + 1) / (trailCount - 1);
297
314
  const opacity = Math.pow(progress, TRAIL_FADE_CURVE) * TRAIL_MAX_OPACITY;
298
- const w0 = (TRAIL_MIN_WIDTH + progress * (TRAIL_MAX_WIDTH - TRAIL_MIN_WIDTH)) / 2;
299
- const w1 = (TRAIL_MIN_WIDTH + nextProgress * (TRAIL_MAX_WIDTH - TRAIL_MIN_WIDTH)) / 2;
315
+ const w0 = (minWidth + progress * (maxWidth - minWidth)) / 2;
316
+ const w1 = (minWidth + nextProgress * (maxWidth - minWidth)) / 2;
300
317
  const curr = trail[i];
301
318
  const next = trail[i + 1];
302
319
  const n0 = computeNormal(trail, i);
@@ -315,13 +332,16 @@ function computeTrailQuad(trail, i, trailCount, toX, toY) {
315
332
  r1x: nx - n1.x * w1,
316
333
  r1y: ny - n1.y * w1,
317
334
  opacity,
318
- progress
335
+ progress,
319
336
  };
320
337
  }
321
338
  function computeBoundaries(pts, logicalWidth, logicalHeight) {
322
339
  if (pts.length === 0) return null;
323
340
  const first = pts[0];
324
- let minX = first.x, maxX = first.x, minY = first.y, maxY = first.y;
341
+ let minX = first.x,
342
+ maxX = first.x,
343
+ minY = first.y,
344
+ maxY = first.y;
325
345
  for (const p of pts) {
326
346
  if (p.x < minX) {
327
347
  minX = p.x;
@@ -340,7 +360,7 @@ function computeBoundaries(pts, logicalWidth, logicalHeight) {
340
360
  const h = maxY - minY;
341
361
  if (w === 0 && h === 0) {
342
362
  throw new Error(
343
- "[sarmal] Degenerate curve: all skeleton points are identical. Check that your curve fn returns distinct points for different values of t."
363
+ "[sarmal] Degenerate curve: all skeleton points are identical. Check that your curve fn returns distinct points for different values of t.",
344
364
  );
345
365
  }
346
366
  const scaleXProportional = logicalWidth / (w * (1 + FIT_PADDING * 2));
@@ -351,12 +371,12 @@ function computeBoundaries(pts, logicalWidth, logicalHeight) {
351
371
  scaleXProportional,
352
372
  scaleYProportional,
353
373
  scaleXMinPadding,
354
- scaleYMinPadding
374
+ scaleYMinPadding,
355
375
  );
356
376
  return {
357
377
  scale,
358
378
  offsetX: (logicalWidth - w * scale) / 2 - minX * scale,
359
- offsetY: (logicalHeight - h * scale) / 2 - minY * scale
379
+ offsetY: (logicalHeight - h * scale) / 2 - minY * scale,
360
380
  };
361
381
  }
362
382
  function enginePassthroughs(engine) {
@@ -366,7 +386,7 @@ function enginePassthroughs(engine) {
366
386
  setSpeed: engine.setSpeed,
367
387
  getSpeed: engine.getSpeed,
368
388
  resetSpeed: engine.resetSpeed,
369
- setSpeedOver: engine.setSpeedOver
389
+ setSpeedOver: engine.setSpeedOver,
370
390
  };
371
391
  }
372
392
  var palettes = {
@@ -375,16 +395,16 @@ var palettes = {
375
395
  ocean: ["#1e3a8a", "#06b6d4", "#22d3ee", "#e0f2fe"],
376
396
  ice: ["#1e3a8a", "#67e8f9"],
377
397
  fire: ["#7f1d1d", "#fbbf24"],
378
- forest: ["#14532d", "#86efac"]
398
+ forest: ["#14532d", "#86efac"],
379
399
  };
380
400
  function hexToRgb(hex) {
381
401
  const n = parseInt(hex.slice(1), 16);
382
- return { r: n >> 16, g: n >> 8 & 255, b: n & 255 };
402
+ return { r: n >> 16, g: (n >> 8) & 255, b: n & 255 };
383
403
  }
384
404
  var lerpRgb = (a, b, t) => ({
385
405
  r: Math.round(a.r + (b.r - a.r) * t),
386
406
  g: Math.round(a.g + (b.g - a.g) * t),
387
- b: Math.round(a.b + (b.b - a.b) * t)
407
+ b: Math.round(a.b + (b.b - a.b) * t),
388
408
  });
389
409
  function getPaletteColor(palette, position, timeOffset = 0) {
390
410
  if (palette.length === 0) {
@@ -393,7 +413,7 @@ function getPaletteColor(palette, position, timeOffset = 0) {
393
413
  if (palette.length === 1) {
394
414
  return hexToRgb(palette[0]);
395
415
  }
396
- const cyclePos = ((position + timeOffset) % 1 + 1) % 1;
416
+ const cyclePos = (((position + timeOffset) % 1) + 1) % 1;
397
417
  const scaled = cyclePos * palette.length;
398
418
  const idx = Math.floor(scaled);
399
419
  const t = scaled - idx;
@@ -407,7 +427,7 @@ var RENDER_OPTION_KEYS = /* @__PURE__ */ new Set([
407
427
  "trailColor",
408
428
  "headColor",
409
429
  "skeletonColor",
410
- "trailStyle"
430
+ "trailStyle",
411
431
  ]);
412
432
  function validateRenderOptions(partial) {
413
433
  for (const key of Object.keys(partial)) {
@@ -432,7 +452,7 @@ function assertTrailColor(value) {
432
452
  if (typeof value === "string") {
433
453
  if (!HEX_COLOR_RE.test(value)) {
434
454
  throw new TypeError(
435
- `[sarmal] setRenderOptions: trailColor must be a 6-digit hex string, got "${value}"`
455
+ `[sarmal] setRenderOptions: trailColor must be a 6-digit hex string, got "${value}"`,
436
456
  );
437
457
  }
438
458
  return;
@@ -440,21 +460,21 @@ function assertTrailColor(value) {
440
460
  if (Array.isArray(value)) {
441
461
  if (value.length < 2) {
442
462
  throw new RangeError(
443
- `[sarmal] setRenderOptions: trailColor array must have at least 2 entries, got ${value.length}`
463
+ `[sarmal] setRenderOptions: trailColor array must have at least 2 entries, got ${value.length}`,
444
464
  );
445
465
  }
446
466
  for (let i = 0; i < value.length; i++) {
447
467
  const entry = value[i];
448
468
  if (typeof entry !== "string" || !HEX_COLOR_RE.test(entry)) {
449
469
  throw new TypeError(
450
- `[sarmal] setRenderOptions: trailColor[${i}] must be a 6-digit hex string, got ${JSON.stringify(entry)}`
470
+ `[sarmal] setRenderOptions: trailColor[${i}] must be a 6-digit hex string, got ${JSON.stringify(entry)}`,
451
471
  );
452
472
  }
453
473
  }
454
474
  return;
455
475
  }
456
476
  throw new TypeError(
457
- `[sarmal] setRenderOptions: trailColor must be a 6-digit hex string or an array of hex strings, got ${JSON.stringify(value)}`
477
+ `[sarmal] setRenderOptions: trailColor must be a 6-digit hex string or an array of hex strings, got ${JSON.stringify(value)}`,
458
478
  );
459
479
  }
460
480
  function assertHeadColor(value) {
@@ -463,7 +483,7 @@ function assertHeadColor(value) {
463
483
  }
464
484
  if (typeof value !== "string" || !HEX_COLOR_RE.test(value)) {
465
485
  throw new TypeError(
466
- `[sarmal] setRenderOptions: headColor must be a 6-digit hex string or null, got ${JSON.stringify(value)}`
486
+ `[sarmal] setRenderOptions: headColor must be a 6-digit hex string or null, got ${JSON.stringify(value)}`,
467
487
  );
468
488
  }
469
489
  }
@@ -473,14 +493,14 @@ function assertSkeletonColor(value) {
473
493
  }
474
494
  if (typeof value !== "string" || !HEX_COLOR_RE.test(value)) {
475
495
  throw new TypeError(
476
- `[sarmal] setRenderOptions: skeletonColor must be a 6-digit hex string or "transparent", got ${JSON.stringify(value)}`
496
+ `[sarmal] setRenderOptions: skeletonColor must be a 6-digit hex string or "transparent", got ${JSON.stringify(value)}`,
477
497
  );
478
498
  }
479
499
  }
480
500
  function assertTrailStyle(value) {
481
501
  if (!TRAIL_STYLES.includes(value)) {
482
502
  throw new RangeError(
483
- `[sarmal] setRenderOptions: trailStyle must be one of "default", "gradient-static", "gradient-animated", got ${JSON.stringify(value)}`
503
+ `[sarmal] setRenderOptions: trailStyle must be one of "default", "gradient-static", "gradient-animated", got ${JSON.stringify(value)}`,
484
504
  );
485
505
  }
486
506
  }
@@ -502,13 +522,13 @@ function resolveHeadColor(trailColor, trailStyle) {
502
522
  function warnIfTrailColorMismatch(trailColor, trailStyle) {
503
523
  if (trailStyle === "default" && Array.isArray(trailColor)) {
504
524
  console.warn(
505
- '[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.'
525
+ '[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.',
506
526
  );
507
527
  return;
508
528
  }
509
529
  if (trailStyle !== "default" && typeof trailColor === "string") {
510
530
  console.warn(
511
- `[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.`
531
+ `[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.`,
512
532
  );
513
533
  }
514
534
  }
@@ -518,7 +538,7 @@ var getHeadDotRadius = (w, h) => Math.max(1, 3 * Math.sqrt(Math.min(w, h) / 160)
518
538
  var WHITE_HEX = "#ffffff";
519
539
  function hexToRgbComponents(hex) {
520
540
  const n = parseInt(hex.slice(1), 16);
521
- return `${n >> 16},${n >> 8 & 255},${n & 255}`;
541
+ return `${n >> 16},${(n >> 8) & 255},${n & 255}`;
522
542
  }
523
543
  function applyDprSizing(target, logicalWidth, logicalHeight, dpr) {
524
544
  target.style.width = `${logicalWidth}px`;
@@ -643,7 +663,7 @@ function createRenderer(options) {
643
663
  i,
644
664
  trailCount,
645
665
  toX,
646
- toY
666
+ toY,
647
667
  );
648
668
  if (trailStyle === "default") {
649
669
  ctx.fillStyle = `rgba(${trailSolidRgb},${opacity})`;
@@ -804,7 +824,7 @@ function createRenderer(options) {
804
824
  if (partial.trailColor !== void 0 || partial.trailStyle !== void 0) {
805
825
  warnIfTrailColorMismatch(trailColor, trailStyle);
806
826
  }
807
- }
827
+ },
808
828
  };
809
829
  if (shouldAutoStart) {
810
830
  instance.play();
@@ -813,10 +833,12 @@ function createRenderer(options) {
813
833
  }
814
834
 
815
835
  // src/renderer-svg.ts
816
- var MAX_TRAIL_SEGMENTS = 200;
817
836
  var EMPTY_PARAMS2 = {};
837
+ var HIGH_TRAIL_LENGTH_THRESHOLD = 5e3;
818
838
  function pointsToPathString(pts, scale, offsetX, offsetY) {
819
- if (pts.length < 2) return "";
839
+ if (pts.length < 2) {
840
+ return "";
841
+ }
820
842
  const px = (p) => (p.x * scale + offsetX).toFixed(2);
821
843
  const py = (p) => (p.y * scale + offsetY).toFixed(2);
822
844
  let d = `M${px(pts[0])} ${py(pts[0])}`;
@@ -830,7 +852,7 @@ function sampleCurveSkeleton(curveDef) {
830
852
  const samples = Math.ceil(period * 50);
831
853
  const pts = Array.from({ length: samples });
832
854
  for (let i = 0; i < samples; i++) {
833
- const t = i / (samples - 1) * period;
855
+ const t = (i / (samples - 1)) * period;
834
856
  pts[i] = curveDef.skeletonFn ? curveDef.skeletonFn(t) : curveDef.fn(t, 0, EMPTY_PARAMS2);
835
857
  }
836
858
  return pts;
@@ -840,6 +862,12 @@ function el(tag) {
840
862
  }
841
863
  function createSVGRenderer(options) {
842
864
  const { container, engine } = options;
865
+ const poolSize = engine.trailLength;
866
+ if (poolSize > HIGH_TRAIL_LENGTH_THRESHOLD) {
867
+ console.warn(
868
+ `[sarmal] High trailLength in SVG renderer (${poolSize}). Consider using the canvas renderer for long trails.`,
869
+ );
870
+ }
843
871
  let trailStyle = options.trailStyle ?? "default";
844
872
  let trailColor = options.trailColor ?? "#ffffff";
845
873
  let skeletonColor = options.skeletonColor ?? "#ffffff";
@@ -849,62 +877,61 @@ function createSVGRenderer(options) {
849
877
  let trailPalette = resolveTrailPalette(trailColor);
850
878
  const ariaLabel = options.ariaLabel ?? "Loading";
851
879
  warnIfTrailColorMismatch(trailColor, trailStyle);
852
- const htmlContainer = container;
853
- const width = htmlContainer.offsetWidth || 200;
854
- const height = htmlContainer.offsetHeight || 200;
855
- const headRadius = options.headRadius ?? getHeadDotRadius(width, height);
856
- const svg = el("svg");
857
- svg.setAttribute("width", String(width));
858
- svg.setAttribute("height", String(height));
859
- svg.setAttribute("viewBox", `0 0 ${width} ${height}`);
860
- svg.setAttribute("role", "img");
861
- svg.setAttribute("aria-label", ariaLabel);
880
+ const viewSize = 100;
881
+ const headRadius = options.headRadius ?? 1.5;
882
+ const svgTrailMinWidth = 0.25;
883
+ const svgTrailMaxWidth = 1.25;
884
+ const svgSkeletonStrokeWidth = "0.75";
885
+ container.setAttribute("viewBox", `0 0 ${viewSize} ${viewSize}`);
886
+ container.setAttribute("role", "img");
887
+ container.setAttribute("aria-label", ariaLabel);
888
+ const group = el("g");
862
889
  const titleEl = el("title");
863
890
  titleEl.textContent = ariaLabel;
864
- svg.appendChild(titleEl);
891
+ group.appendChild(titleEl);
865
892
  const skeletonPath = el("path");
866
893
  skeletonPath.setAttribute("data-sarmal-role", "skeleton");
867
894
  skeletonPath.setAttribute("fill", "none");
868
895
  skeletonPath.setAttribute("stroke", skeletonColor);
869
896
  skeletonPath.setAttribute("stroke-opacity", String(DEFAULT_SKELETON_OPACITY));
870
- skeletonPath.setAttribute("stroke-width", "1.5");
897
+ skeletonPath.setAttribute("stroke-width", svgSkeletonStrokeWidth);
871
898
  if (skeletonColor === "transparent") {
872
899
  skeletonPath.setAttribute("visibility", "hidden");
873
900
  }
874
- svg.appendChild(skeletonPath);
901
+ group.appendChild(skeletonPath);
875
902
  const skeletonPathA = el("path");
876
903
  skeletonPathA.setAttribute("fill", "none");
877
904
  skeletonPathA.setAttribute("stroke", skeletonColor);
878
- skeletonPathA.setAttribute("stroke-width", "1.5");
905
+ skeletonPathA.setAttribute("stroke-width", svgSkeletonStrokeWidth);
879
906
  skeletonPathA.setAttribute("visibility", "hidden");
880
- svg.appendChild(skeletonPathA);
907
+ group.appendChild(skeletonPathA);
881
908
  const skeletonPathB = el("path");
882
909
  skeletonPathB.setAttribute("fill", "none");
883
910
  skeletonPathB.setAttribute("stroke", skeletonColor);
884
- skeletonPathB.setAttribute("stroke-width", "1.5");
911
+ skeletonPathB.setAttribute("stroke-width", svgSkeletonStrokeWidth);
885
912
  skeletonPathB.setAttribute("visibility", "hidden");
886
- svg.appendChild(skeletonPathB);
913
+ group.appendChild(skeletonPathB);
887
914
  let morphPathABuilt = "";
888
915
  let morphPathBBuilt = "";
889
916
  const trailPaths = [];
890
- for (let i = 0; i < MAX_TRAIL_SEGMENTS; i++) {
917
+ for (let i = 0; i < poolSize; i++) {
891
918
  const path = el("path");
892
919
  path.setAttribute("fill", trailSolid);
893
- svg.appendChild(path);
920
+ group.appendChild(path);
894
921
  trailPaths.push(path);
895
922
  }
896
923
  const headCircle = el("circle");
897
924
  headCircle.setAttribute("data-sarmal-role", "head");
898
925
  headCircle.setAttribute("fill", headColor);
899
926
  headCircle.setAttribute("r", String(headRadius));
900
- svg.appendChild(headCircle);
901
- container.appendChild(svg);
927
+ group.appendChild(headCircle);
928
+ container.appendChild(group);
902
929
  let gradientAnimTime = 0;
903
930
  let scale = 1;
904
931
  let offsetX = 0;
905
932
  let offsetY = 0;
906
933
  function applyBoundaries(skeleton2) {
907
- const b = computeBoundaries(skeleton2, width, height);
934
+ const b = computeBoundaries(skeleton2, viewSize, viewSize);
908
935
  if (b) {
909
936
  scale = b.scale;
910
937
  offsetX = b.offsetX;
@@ -932,24 +959,24 @@ function createSVGRenderer(options) {
932
959
  }
933
960
  return;
934
961
  }
935
- const startIdx = Math.max(0, trailCount - 1 - MAX_TRAIL_SEGMENTS);
936
- const drawnCount = trailCount - 1 - startIdx;
937
- for (let i = startIdx; i < trailCount - 1; i++) {
938
- const j = i - startIdx;
962
+ const drawnCount = trailCount - 1;
963
+ for (let i = 0; i < drawnCount; i++) {
939
964
  const { l0x, l0y, r0x, r0y, l1x, l1y, r1x, r1y, opacity, progress } = computeTrailQuad(
940
965
  trail,
941
966
  i,
942
967
  trailCount,
943
968
  px,
944
- py
969
+ py,
970
+ svgTrailMinWidth,
971
+ svgTrailMaxWidth,
945
972
  );
946
973
  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`;
947
- trailPaths[j].setAttribute("d", d);
948
- trailPaths[j].setAttribute("fill-opacity", opacity.toFixed(3));
974
+ trailPaths[i].setAttribute("d", d);
975
+ trailPaths[i].setAttribute("fill-opacity", opacity.toFixed(3));
949
976
  if (trailStyle !== "default") {
950
977
  const timeOffset = trailStyle === "gradient-animated" ? gradientAnimTime * 5e-4 : 0;
951
978
  const { r, g, b } = getPaletteColor(trailPalette, progress, timeOffset);
952
- trailPaths[j].setAttribute("fill", `rgb(${r},${g},${b})`);
979
+ trailPaths[i].setAttribute("fill", `rgb(${r},${g},${b})`);
953
980
  }
954
981
  }
955
982
  for (let i = drawnCount; i < trailPaths.length; i++) {
@@ -968,7 +995,8 @@ function createSVGRenderer(options) {
968
995
  }
969
996
  let animationId = null;
970
997
  let lastTime = 0;
971
- const prefersReducedMotion = typeof window !== "undefined" && window.matchMedia("(prefers-reduced-motion: reduce)").matches;
998
+ const prefersReducedMotion =
999
+ typeof window !== "undefined" && window.matchMedia("(prefers-reduced-motion: reduce)").matches;
972
1000
  let morphResolve = null;
973
1001
  let morphReject = null;
974
1002
  let morphDurationMs = DEFAULT_MORPH_DURATION_MS;
@@ -986,7 +1014,7 @@ function createSVGRenderer(options) {
986
1014
  skeletonPathA.setAttribute("visibility", "visible");
987
1015
  skeletonPathA.setAttribute(
988
1016
  "stroke-opacity",
989
- String((1 - morphAlpha) * DEFAULT_SKELETON_OPACITY)
1017
+ String((1 - morphAlpha) * DEFAULT_SKELETON_OPACITY),
990
1018
  );
991
1019
  }
992
1020
  if (morphPathBBuilt) {
@@ -1063,7 +1091,7 @@ function createSVGRenderer(options) {
1063
1091
  morphResolve = null;
1064
1092
  morphReject = null;
1065
1093
  }
1066
- svg.remove();
1094
+ group.remove();
1067
1095
  },
1068
1096
  ...enginePassthroughs(engine),
1069
1097
  morphTo(target, options2) {
@@ -1135,7 +1163,7 @@ function createSVGRenderer(options) {
1135
1163
  if (partial.trailColor !== void 0 || partial.trailStyle !== void 0) {
1136
1164
  warnIfTrailColorMismatch(trailColor, trailStyle);
1137
1165
  }
1138
- }
1166
+ },
1139
1167
  };
1140
1168
  if (shouldAutoStart) {
1141
1169
  instance.play();
@@ -1151,19 +1179,22 @@ function createSarmalSVG(container, curveDef, options) {
1151
1179
  // src/curves/artemis2.ts
1152
1180
  var TWO_PI2 = Math.PI * 2;
1153
1181
  function artemis2Fn(t, _time, _params) {
1154
- const a = 0.35, b = 0.15, ox = 0.175;
1155
- const s = Math.sin(t), c = Math.cos(t);
1182
+ const a = 0.35,
1183
+ b = 0.15,
1184
+ ox = 0.175;
1185
+ const s = Math.sin(t),
1186
+ c = Math.cos(t);
1156
1187
  const denom = 1 + s * s;
1157
1188
  return {
1158
- x: c * (1 + a * c) / denom - ox,
1159
- y: s * c * (1 + b * c) / denom
1189
+ x: (c * (1 + a * c)) / denom - ox,
1190
+ y: (s * c * (1 + b * c)) / denom,
1160
1191
  };
1161
1192
  }
1162
1193
  var artemis2 = {
1163
1194
  name: "Artemis II",
1164
1195
  fn: artemis2Fn,
1165
1196
  period: TWO_PI2,
1166
- speed: 0.7
1197
+ speed: 0.7,
1167
1198
  };
1168
1199
 
1169
1200
  // src/curves/astroid.ts
@@ -1173,14 +1204,14 @@ function astroidFn(t, _time, _params) {
1173
1204
  const s = Math.sin(t);
1174
1205
  return {
1175
1206
  x: c * c * c,
1176
- y: s * s * s
1207
+ y: s * s * s,
1177
1208
  };
1178
1209
  }
1179
1210
  var astroid = {
1180
1211
  name: "Astroid",
1181
1212
  fn: astroidFn,
1182
1213
  period: TWO_PI3,
1183
- speed: 1.1
1214
+ speed: 1.1,
1184
1215
  };
1185
1216
 
1186
1217
  // src/curves/deltoid.ts
@@ -1188,14 +1219,14 @@ var TWO_PI4 = Math.PI * 2;
1188
1219
  function deltoidFn(t, _time, _params) {
1189
1220
  return {
1190
1221
  x: 2 * Math.cos(t) + Math.cos(2 * t),
1191
- y: 2 * Math.sin(t) - Math.sin(2 * t)
1222
+ y: 2 * Math.sin(t) - Math.sin(2 * t),
1192
1223
  };
1193
1224
  }
1194
1225
  var deltoid = {
1195
1226
  name: "Deltoid",
1196
1227
  fn: deltoidFn,
1197
1228
  period: TWO_PI4,
1198
- speed: 0.9
1229
+ speed: 0.9,
1199
1230
  };
1200
1231
 
1201
1232
  // src/curves/epicycloid3.ts
@@ -1203,14 +1234,14 @@ var TWO_PI5 = Math.PI * 2;
1203
1234
  function epicycloid3Fn(t, _time, _params) {
1204
1235
  return {
1205
1236
  x: 4 * Math.cos(t) - Math.cos(4 * t),
1206
- y: 4 * Math.sin(t) - Math.sin(4 * t)
1237
+ y: 4 * Math.sin(t) - Math.sin(4 * t),
1207
1238
  };
1208
1239
  }
1209
1240
  var epicycloid3 = {
1210
1241
  name: "Epicycloid (n=3)",
1211
1242
  fn: epicycloid3Fn,
1212
1243
  period: TWO_PI5,
1213
- speed: 0.75
1244
+ speed: 0.75,
1214
1245
  };
1215
1246
 
1216
1247
  // src/curves/epitrochoid7.ts
@@ -1219,14 +1250,14 @@ function epitrochoid7Fn(t, _time, _params) {
1219
1250
  const d = 1 + 0.55 * Math.sin(t * 0.5);
1220
1251
  return {
1221
1252
  x: 7 * Math.cos(t) - d * Math.cos(7 * t),
1222
- y: 7 * Math.sin(t) - d * Math.sin(7 * t)
1253
+ y: 7 * Math.sin(t) - d * Math.sin(7 * t),
1223
1254
  };
1224
1255
  }
1225
1256
  function epitrochoid7SkeletonFn(t) {
1226
1257
  const d = 1.275;
1227
1258
  return {
1228
1259
  x: 7 * Math.cos(t) - d * Math.cos(7 * t),
1229
- y: 7 * Math.sin(t) - d * Math.sin(7 * t)
1260
+ y: 7 * Math.sin(t) - d * Math.sin(7 * t),
1230
1261
  };
1231
1262
  }
1232
1263
  var epitrochoid7 = {
@@ -1234,7 +1265,7 @@ var epitrochoid7 = {
1234
1265
  fn: epitrochoid7Fn,
1235
1266
  period: TWO_PI6,
1236
1267
  speed: 1.4,
1237
- skeletonFn: epitrochoid7SkeletonFn
1268
+ skeletonFn: epitrochoid7SkeletonFn,
1238
1269
  };
1239
1270
 
1240
1271
  // src/curves/lissajous32.ts
@@ -1243,7 +1274,7 @@ function lissajous32Fn(t, time, _params) {
1243
1274
  const phi = time * 0.45;
1244
1275
  return {
1245
1276
  x: Math.sin(3 * t + phi),
1246
- y: Math.sin(2 * t)
1277
+ y: Math.sin(2 * t),
1247
1278
  };
1248
1279
  }
1249
1280
  var lissajous32 = {
@@ -1251,7 +1282,7 @@ var lissajous32 = {
1251
1282
  fn: lissajous32Fn,
1252
1283
  period: TWO_PI7,
1253
1284
  speed: 2,
1254
- skeleton: "live"
1285
+ skeleton: "live",
1255
1286
  };
1256
1287
 
1257
1288
  // src/curves/lissajous43.ts
@@ -1260,7 +1291,7 @@ function lissajous43Fn(t, time, _params) {
1260
1291
  const phi = time * 0.38;
1261
1292
  return {
1262
1293
  x: Math.sin(4 * t + phi),
1263
- y: Math.sin(3 * t)
1294
+ y: Math.sin(3 * t),
1264
1295
  };
1265
1296
  }
1266
1297
  var lissajous43 = {
@@ -1268,17 +1299,18 @@ var lissajous43 = {
1268
1299
  fn: lissajous43Fn,
1269
1300
  period: TWO_PI8,
1270
1301
  speed: 1.8,
1271
- skeleton: "live"
1302
+ skeleton: "live",
1272
1303
  };
1273
1304
 
1274
1305
  // src/curves/lame.ts
1275
1306
  var TWO_PI9 = Math.PI * 2;
1276
1307
  function lameFn(t, time, _params) {
1277
1308
  const p = 1.75 + 1.25 * Math.sin(time * 0.48);
1278
- const c = Math.cos(t), s = Math.sin(t);
1309
+ const c = Math.cos(t),
1310
+ s = Math.sin(t);
1279
1311
  return {
1280
1312
  x: Math.sign(c) * Math.pow(Math.abs(c), p),
1281
- y: Math.sign(s) * Math.pow(Math.abs(s), p)
1313
+ y: Math.sign(s) * Math.pow(Math.abs(s), p),
1282
1314
  };
1283
1315
  }
1284
1316
  var lame = {
@@ -1286,7 +1318,7 @@ var lame = {
1286
1318
  fn: lameFn,
1287
1319
  period: TWO_PI9,
1288
1320
  speed: 1,
1289
- skeleton: "live"
1321
+ skeleton: "live",
1290
1322
  };
1291
1323
 
1292
1324
  // src/curves/rose3.ts
@@ -1295,14 +1327,14 @@ function rose3Fn(t, _time, _params) {
1295
1327
  const r = Math.cos(3 * t);
1296
1328
  return {
1297
1329
  x: r * Math.cos(t),
1298
- y: r * Math.sin(t)
1330
+ y: r * Math.sin(t),
1299
1331
  };
1300
1332
  }
1301
1333
  var rose3 = {
1302
1334
  name: "Rose (n=3)",
1303
1335
  fn: rose3Fn,
1304
1336
  period: TWO_PI10,
1305
- speed: 1.15
1337
+ speed: 1.15,
1306
1338
  };
1307
1339
 
1308
1340
  // src/curves/rose5.ts
@@ -1311,78 +1343,87 @@ function rose5Fn(t, _time, _params) {
1311
1343
  const r = Math.cos(5 * t);
1312
1344
  return {
1313
1345
  x: r * Math.cos(t),
1314
- y: r * Math.sin(t)
1346
+ y: r * Math.sin(t),
1315
1347
  };
1316
1348
  }
1317
1349
  var rose5 = {
1318
1350
  name: "Rose (n=5)",
1319
1351
  fn: rose5Fn,
1320
1352
  period: TWO_PI11,
1321
- speed: 1
1353
+ speed: 1,
1322
1354
  };
1323
1355
 
1324
1356
  // src/curves/rose52.ts
1325
1357
  var FOUR_PI = Math.PI * 4;
1326
1358
  function rose52Fn(t, _time, _params) {
1327
- const r = Math.cos(5 / 2 * t);
1359
+ const r = Math.cos((5 / 2) * t);
1328
1360
  return {
1329
1361
  x: r * Math.cos(t),
1330
- y: r * Math.sin(t)
1362
+ y: r * Math.sin(t),
1331
1363
  };
1332
1364
  }
1333
1365
  var rose52 = {
1334
1366
  name: "Rose (n=5/2)",
1335
1367
  fn: rose52Fn,
1336
1368
  period: FOUR_PI,
1337
- speed: 0.8
1369
+ speed: 0.8,
1338
1370
  };
1339
1371
 
1340
1372
  // src/curves/star.ts
1341
1373
  var TWO_PI12 = Math.PI * 2;
1342
1374
  function starFn(t, _time, _params) {
1343
- 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));
1375
+ const r =
1376
+ Math.abs(Math.cos((5 / 2) * t)) +
1377
+ 0.35 * Math.abs(Math.cos((15 / 2) * t)) +
1378
+ 0.15 * Math.abs(Math.cos((25 / 2) * t));
1344
1379
  return {
1345
1380
  x: r * Math.cos(t),
1346
- y: r * Math.sin(t)
1381
+ y: r * Math.sin(t),
1347
1382
  };
1348
1383
  }
1349
1384
  var star = {
1350
1385
  name: "Star",
1351
1386
  fn: starFn,
1352
1387
  period: TWO_PI12,
1353
- speed: 1
1388
+ speed: 1,
1354
1389
  };
1355
1390
 
1356
1391
  // src/curves/star4.ts
1357
1392
  var TWO_PI13 = Math.PI * 2;
1358
1393
  function star4Fn(t, _time, _params) {
1359
- const r = Math.abs(Math.cos(2 * t)) + 0.35 * Math.abs(Math.cos(6 * t)) + 0.15 * Math.abs(Math.cos(10 * t));
1394
+ const r =
1395
+ Math.abs(Math.cos(2 * t)) +
1396
+ 0.35 * Math.abs(Math.cos(6 * t)) +
1397
+ 0.15 * Math.abs(Math.cos(10 * t));
1360
1398
  return {
1361
1399
  x: r * Math.cos(t),
1362
- y: r * Math.sin(t)
1400
+ y: r * Math.sin(t),
1363
1401
  };
1364
1402
  }
1365
1403
  var star4 = {
1366
1404
  name: "Star (4-arm)",
1367
1405
  fn: star4Fn,
1368
1406
  period: TWO_PI13,
1369
- speed: 1
1407
+ speed: 1,
1370
1408
  };
1371
1409
 
1372
1410
  // src/curves/star7.ts
1373
1411
  var TWO_PI14 = Math.PI * 2;
1374
1412
  function star7Fn(t, _time, _params) {
1375
- 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));
1413
+ const r =
1414
+ Math.abs(Math.cos((7 / 2) * t)) +
1415
+ 0.35 * Math.abs(Math.cos((21 / 2) * t)) +
1416
+ 0.15 * Math.abs(Math.cos((35 / 2) * t));
1376
1417
  return {
1377
1418
  x: r * Math.cos(t),
1378
- y: r * Math.sin(t)
1419
+ y: r * Math.sin(t),
1379
1420
  };
1380
1421
  }
1381
1422
  var star7 = {
1382
1423
  name: "Star (7-arm)",
1383
1424
  fn: star7Fn,
1384
1425
  period: TWO_PI14,
1385
- speed: 1
1426
+ speed: 1,
1386
1427
  };
1387
1428
 
1388
1429
  // src/curves/index.ts
@@ -1400,7 +1441,7 @@ var curves = {
1400
1441
  lissajous32,
1401
1442
  lissajous43,
1402
1443
  epicycloid3,
1403
- lame
1444
+ lame,
1404
1445
  };
1405
1446
 
1406
1447
  // src/index.ts
@@ -1428,4 +1469,4 @@ exports.palettes = palettes;
1428
1469
  exports.rose3 = rose3;
1429
1470
  exports.rose5 = rose5;
1430
1471
  //# sourceMappingURL=index.cjs.map
1431
- //# sourceMappingURL=index.cjs.map
1472
+ //# sourceMappingURL=index.cjs.map