@sarmal/core 0.24.0 → 0.25.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (79) hide show
  1. package/dist/auto-init.cjs +245 -141
  2. package/dist/auto-init.cjs.map +1 -1
  3. package/dist/auto-init.js +244 -140
  4. package/dist/auto-init.js.map +1 -1
  5. package/dist/curves/artemis2.cjs +87 -14
  6. package/dist/curves/artemis2.cjs.map +1 -1
  7. package/dist/curves/artemis2.d.cts +1 -5
  8. package/dist/curves/artemis2.d.ts +1 -5
  9. package/dist/curves/artemis2.js +86 -13
  10. package/dist/curves/artemis2.js.map +1 -1
  11. package/dist/curves/astroid.cjs +4 -4
  12. package/dist/curves/astroid.d.cts +1 -1
  13. package/dist/curves/astroid.d.ts +1 -1
  14. package/dist/curves/astroid.js +3 -3
  15. package/dist/curves/deltoid.cjs +4 -4
  16. package/dist/curves/deltoid.d.cts +1 -1
  17. package/dist/curves/deltoid.d.ts +1 -1
  18. package/dist/curves/deltoid.js +3 -3
  19. package/dist/curves/epicycloid3.cjs +4 -4
  20. package/dist/curves/epicycloid3.d.cts +1 -1
  21. package/dist/curves/epicycloid3.d.ts +1 -1
  22. package/dist/curves/epicycloid3.js +3 -3
  23. package/dist/curves/epitrochoid7.cjs +5 -5
  24. package/dist/curves/epitrochoid7.d.cts +1 -1
  25. package/dist/curves/epitrochoid7.d.ts +1 -1
  26. package/dist/curves/epitrochoid7.js +4 -4
  27. package/dist/curves/index.cjs +154 -71
  28. package/dist/curves/index.cjs.map +1 -1
  29. package/dist/curves/index.d.cts +29 -29
  30. package/dist/curves/index.d.ts +29 -29
  31. package/dist/curves/index.js +170 -71
  32. package/dist/curves/index.js.map +1 -1
  33. package/dist/curves/lame.cjs +6 -5
  34. package/dist/curves/lame.d.cts +1 -1
  35. package/dist/curves/lame.d.ts +1 -1
  36. package/dist/curves/lame.js +5 -4
  37. package/dist/curves/lissajous32.cjs +4 -4
  38. package/dist/curves/lissajous32.d.cts +1 -1
  39. package/dist/curves/lissajous32.d.ts +1 -1
  40. package/dist/curves/lissajous32.js +3 -3
  41. package/dist/curves/lissajous43.cjs +4 -4
  42. package/dist/curves/lissajous43.d.cts +1 -1
  43. package/dist/curves/lissajous43.d.ts +1 -1
  44. package/dist/curves/lissajous43.js +3 -3
  45. package/dist/curves/rose3.cjs +4 -4
  46. package/dist/curves/rose3.d.cts +1 -1
  47. package/dist/curves/rose3.d.ts +1 -1
  48. package/dist/curves/rose3.js +3 -3
  49. package/dist/curves/rose5.cjs +4 -4
  50. package/dist/curves/rose5.d.cts +1 -1
  51. package/dist/curves/rose5.d.ts +1 -1
  52. package/dist/curves/rose5.js +3 -3
  53. package/dist/curves/rose52.cjs +5 -5
  54. package/dist/curves/rose52.d.cts +1 -1
  55. package/dist/curves/rose52.d.ts +1 -1
  56. package/dist/curves/rose52.js +4 -4
  57. package/dist/curves/star.cjs +8 -5
  58. package/dist/curves/star.d.cts +1 -1
  59. package/dist/curves/star.d.ts +1 -1
  60. package/dist/curves/star.js +7 -4
  61. package/dist/curves/star4.cjs +8 -5
  62. package/dist/curves/star4.d.cts +1 -1
  63. package/dist/curves/star4.d.ts +1 -1
  64. package/dist/curves/star4.js +7 -4
  65. package/dist/curves/star7.cjs +8 -5
  66. package/dist/curves/star7.d.cts +1 -1
  67. package/dist/curves/star7.d.ts +1 -1
  68. package/dist/curves/star7.js +7 -4
  69. package/dist/index.cjs +232 -172
  70. package/dist/index.cjs.map +1 -1
  71. package/dist/index.d.cts +106 -36
  72. package/dist/index.d.ts +106 -36
  73. package/dist/index.js +252 -172
  74. package/dist/index.js.map +1 -1
  75. package/dist/types-Z9i1_AQZ.d.cts +339 -0
  76. package/dist/types-Z9i1_AQZ.d.ts +339 -0
  77. package/package.json +1 -1
  78. package/dist/types-CknrlCAf.d.cts +0 -314
  79. package/dist/types-CknrlCAf.d.ts +0 -314
package/dist/index.js CHANGED
@@ -61,13 +61,13 @@ function resolveCurve(curveDef) {
61
61
  period,
62
62
  speed,
63
63
  skeleton: curveDef.skeleton,
64
- skeletonFn: curveDef.skeletonFn
64
+ skeletonFn: curveDef.skeletonFn,
65
65
  };
66
66
  }
67
67
  function createEngine(curveDef, trailLength = 120) {
68
68
  if (!Number.isFinite(trailLength) || trailLength <= 0) {
69
69
  throw new RangeError(
70
- `[sarmal] trailLength must be a positive finite number, got ${trailLength}`
70
+ `[sarmal] trailLength must be a positive finite number, got ${trailLength}`,
71
71
  );
72
72
  }
73
73
  let curve = resolveCurve(curveDef);
@@ -108,7 +108,7 @@ function createEngine(curveDef, trailLength = 120) {
108
108
  actualTime += deltaTime;
109
109
  if (morphCurveB !== null && _morphAlpha !== null) {
110
110
  const a = curve.fn(t, actualTime, EMPTY_PARAMS);
111
- const tB = _morphStrategy === "normalized" ? t / curve.period * morphCurveB.period : t;
111
+ const tB = _morphStrategy === "normalized" ? (t / curve.period) * morphCurveB.period : t;
112
112
  const b = morphCurveB.fn(tB, actualTime, EMPTY_PARAMS);
113
113
  trail.push(a.x + (b.x - a.x) * _morphAlpha, a.y + (b.y - a.y) * _morphAlpha);
114
114
  } else {
@@ -135,14 +135,14 @@ function createEngine(curveDef, trailLength = 120) {
135
135
  trail.clear();
136
136
  },
137
137
  jump(newT, { clearTrail = false } = {}) {
138
- t = (newT % curve.period + curve.period) % curve.period;
138
+ t = ((newT % curve.period) + curve.period) % curve.period;
139
139
  if (clearTrail) {
140
140
  trail.clear();
141
141
  }
142
142
  },
143
143
  seek(targetT, { wrap = false, step = curve.period / trailLength } = {}) {
144
144
  const advance = curve.speed * step;
145
- const target = (targetT % curve.period + curve.period) % curve.period;
145
+ const target = ((targetT % curve.period) + curve.period) % curve.period;
146
146
  const targetTime = target / curve.speed;
147
147
  t = target;
148
148
  actualTime = targetTime;
@@ -151,7 +151,7 @@ function createEngine(curveDef, trailLength = 120) {
151
151
  const count = wrap ? trailLength : Math.min(trailLength, pointsFromStart);
152
152
  for (let i = count - 1; i >= 0; i--) {
153
153
  const sampleT = target - i * advance;
154
- const wrappedT = (sampleT % curve.period + curve.period) % curve.period;
154
+ const wrappedT = ((sampleT % curve.period) + curve.period) % curve.period;
155
155
  const time = targetTime - i * step;
156
156
  const point = curve.fn(wrappedT, time, EMPTY_PARAMS);
157
157
  trail.push(point.x, point.y);
@@ -168,13 +168,16 @@ function createEngine(curveDef, trailLength = 120) {
168
168
  ...frozenB,
169
169
  fn: (sampleT, time, params) => {
170
170
  const a = frozenA.fn(sampleT, time, params);
171
- const tB = frozenStrategy === "normalized" ? sampleT / frozenA.period * frozenB.period : sampleT;
171
+ const tB =
172
+ frozenStrategy === "normalized"
173
+ ? (sampleT / frozenA.period) * frozenB.period
174
+ : sampleT;
172
175
  const b = frozenB.fn(tB, time, params);
173
176
  return {
174
177
  x: a.x + (b.x - a.x) * frozenAlpha,
175
- y: a.y + (b.y - a.y) * frozenAlpha
178
+ y: a.y + (b.y - a.y) * frozenAlpha,
176
179
  };
177
- }
180
+ },
178
181
  };
179
182
  }
180
183
  _morphStrategy = strategy;
@@ -187,7 +190,7 @@ function createEngine(curveDef, trailLength = 120) {
187
190
  completeMorph() {
188
191
  if (morphCurveB !== null) {
189
192
  if (_morphStrategy === "normalized" && curve.period !== morphCurveB.period) {
190
- t = t / curve.period * morphCurveB.period;
193
+ t = (t / curve.period) * morphCurveB.period;
191
194
  }
192
195
  curve = morphCurveB;
193
196
  }
@@ -196,25 +199,28 @@ function createEngine(curveDef, trailLength = 120) {
196
199
  },
197
200
  getSarmalSkeleton() {
198
201
  const steps = Math.ceil(curve.period * POINTS_PER_PERIOD_UNIT);
199
- const points = new Array(steps);
202
+ const points2 = new Array(steps);
200
203
  if (morphCurveB !== null && _morphAlpha !== null) {
201
204
  for (let i = 0; i < steps; i++) {
202
- const sampleT = i / (steps - 1) * curve.period;
205
+ const sampleT = (i / (steps - 1)) * curve.period;
203
206
  const a = sampleSkeleton(curve, sampleT);
204
- const tB = _morphStrategy === "normalized" ? sampleT / curve.period * morphCurveB.period : sampleT;
207
+ const tB =
208
+ _morphStrategy === "normalized"
209
+ ? (sampleT / curve.period) * morphCurveB.period
210
+ : sampleT;
205
211
  const b = sampleSkeleton(morphCurveB, tB);
206
- points[i] = {
212
+ points2[i] = {
207
213
  x: a.x + (b.x - a.x) * _morphAlpha,
208
- y: a.y + (b.y - a.y) * _morphAlpha
214
+ y: a.y + (b.y - a.y) * _morphAlpha,
209
215
  };
210
216
  }
211
- return points;
217
+ return points2;
212
218
  }
213
219
  for (let i = 0; i < steps; i++) {
214
- const sampleT = i / (steps - 1) * curve.period;
215
- points[i] = sampleSkeleton(curve, sampleT);
220
+ const sampleT = (i / (steps - 1)) * curve.period;
221
+ points2[i] = sampleSkeleton(curve, sampleT);
216
222
  }
217
- return points;
223
+ return points2;
218
224
  },
219
225
  setSpeed(speed) {
220
226
  if (!Number.isFinite(speed)) {
@@ -253,7 +259,7 @@ function createEngine(curveDef, trailLength = 120) {
253
259
  _speedTransition.reject(new Error("Speed transition cancelled"));
254
260
  _speedTransition = null;
255
261
  }
256
- }
262
+ },
257
263
  };
258
264
  }
259
265
 
@@ -292,7 +298,15 @@ function computeNormal(trail, i) {
292
298
  const tangent = computeTangent(trail, i);
293
299
  return { x: -tangent.y, y: tangent.x };
294
300
  }
295
- function computeTrailQuad(trail, i, trailCount, toX, toY, minWidth = TRAIL_MIN_WIDTH, maxWidth = TRAIL_MAX_WIDTH) {
301
+ function computeTrailQuad(
302
+ trail,
303
+ i,
304
+ trailCount,
305
+ toX,
306
+ toY,
307
+ minWidth = TRAIL_MIN_WIDTH,
308
+ maxWidth = TRAIL_MAX_WIDTH,
309
+ ) {
296
310
  const progress = i / (trailCount - 1);
297
311
  const nextProgress = (i + 1) / (trailCount - 1);
298
312
  const opacity = Math.pow(progress, TRAIL_FADE_CURVE) * TRAIL_MAX_OPACITY;
@@ -316,13 +330,16 @@ function computeTrailQuad(trail, i, trailCount, toX, toY, minWidth = TRAIL_MIN_W
316
330
  r1x: nx - n1.x * w1,
317
331
  r1y: ny - n1.y * w1,
318
332
  opacity,
319
- progress
333
+ progress,
320
334
  };
321
335
  }
322
- function computeBoundaries(pts, logicalWidth, logicalHeight) {
336
+ function computeBoundaries(pts, logicalWidth, logicalHeight, minPaddingPx = FIT_PADDING_MIN) {
323
337
  if (pts.length === 0) return null;
324
338
  const first = pts[0];
325
- let minX = first.x, maxX = first.x, minY = first.y, maxY = first.y;
339
+ let minX = first.x,
340
+ maxX = first.x,
341
+ minY = first.y,
342
+ maxY = first.y;
326
343
  for (const p of pts) {
327
344
  if (p.x < minX) {
328
345
  minX = p.x;
@@ -341,23 +358,23 @@ function computeBoundaries(pts, logicalWidth, logicalHeight) {
341
358
  const h = maxY - minY;
342
359
  if (w === 0 && h === 0) {
343
360
  throw new Error(
344
- "[sarmal] Degenerate curve: all skeleton points are identical. Check that your curve fn returns distinct points for different values of t."
361
+ "[sarmal] Degenerate curve: all skeleton points are identical. Check that your curve fn returns distinct points for different values of t.",
345
362
  );
346
363
  }
347
364
  const scaleXProportional = logicalWidth / (w * (1 + FIT_PADDING * 2));
348
365
  const scaleYProportional = logicalHeight / (h * (1 + FIT_PADDING * 2));
349
- const scaleXMinPadding = (logicalWidth - FIT_PADDING_MIN * 2) / w;
350
- const scaleYMinPadding = (logicalHeight - FIT_PADDING_MIN * 2) / h;
366
+ const scaleXMinPadding = (logicalWidth - minPaddingPx * 2) / w;
367
+ const scaleYMinPadding = (logicalHeight - minPaddingPx * 2) / h;
351
368
  const scale = Math.min(
352
369
  scaleXProportional,
353
370
  scaleYProportional,
354
371
  scaleXMinPadding,
355
- scaleYMinPadding
372
+ scaleYMinPadding,
356
373
  );
357
374
  return {
358
375
  scale,
359
376
  offsetX: (logicalWidth - w * scale) / 2 - minX * scale,
360
- offsetY: (logicalHeight - h * scale) / 2 - minY * scale
377
+ offsetY: (logicalHeight - h * scale) / 2 - minY * scale,
361
378
  };
362
379
  }
363
380
  function enginePassthroughs(engine) {
@@ -367,7 +384,8 @@ function enginePassthroughs(engine) {
367
384
  setSpeed: engine.setSpeed,
368
385
  getSpeed: engine.getSpeed,
369
386
  resetSpeed: engine.resetSpeed,
370
- setSpeedOver: engine.setSpeedOver
387
+ setSpeedOver: engine.setSpeedOver,
388
+ getSarmalSkeleton: engine.getSarmalSkeleton,
371
389
  };
372
390
  }
373
391
  var palettes = {
@@ -376,16 +394,16 @@ var palettes = {
376
394
  ocean: ["#1e3a8a", "#06b6d4", "#22d3ee", "#e0f2fe"],
377
395
  ice: ["#1e3a8a", "#67e8f9"],
378
396
  fire: ["#7f1d1d", "#fbbf24"],
379
- forest: ["#14532d", "#86efac"]
397
+ forest: ["#14532d", "#86efac"],
380
398
  };
381
399
  function hexToRgb(hex) {
382
400
  const n = parseInt(hex.slice(1), 16);
383
- return { r: n >> 16, g: n >> 8 & 255, b: n & 255 };
401
+ return { r: n >> 16, g: (n >> 8) & 255, b: n & 255 };
384
402
  }
385
403
  var lerpRgb = (a, b, t) => ({
386
404
  r: Math.round(a.r + (b.r - a.r) * t),
387
405
  g: Math.round(a.g + (b.g - a.g) * t),
388
- b: Math.round(a.b + (b.b - a.b) * t)
406
+ b: Math.round(a.b + (b.b - a.b) * t),
389
407
  });
390
408
  function getPaletteColor(palette, position, timeOffset = 0) {
391
409
  if (palette.length === 0) {
@@ -394,7 +412,7 @@ function getPaletteColor(palette, position, timeOffset = 0) {
394
412
  if (palette.length === 1) {
395
413
  return hexToRgb(palette[0]);
396
414
  }
397
- const cyclePos = ((position + timeOffset) % 1 + 1) % 1;
415
+ const cyclePos = (((position + timeOffset) % 1) + 1) % 1;
398
416
  const scaled = cyclePos * palette.length;
399
417
  const idx = Math.floor(scaled);
400
418
  const t = scaled - idx;
@@ -409,7 +427,7 @@ var RENDER_OPTION_KEYS = /* @__PURE__ */ new Set([
409
427
  "headColor",
410
428
  "skeletonColor",
411
429
  "trailStyle",
412
- "headRadius"
430
+ "headRadius",
413
431
  ]);
414
432
  function validateRenderOptions(partial) {
415
433
  for (const key of Object.keys(partial)) {
@@ -437,7 +455,7 @@ function assertTrailColor(value) {
437
455
  if (typeof value === "string") {
438
456
  if (!HEX_COLOR_RE.test(value)) {
439
457
  throw new TypeError(
440
- `[sarmal] setRenderOptions: trailColor must be a 6-digit hex string, got "${value}"`
458
+ `[sarmal] setRenderOptions: trailColor must be a 6-digit hex string, got "${value}"`,
441
459
  );
442
460
  }
443
461
  return;
@@ -445,21 +463,21 @@ function assertTrailColor(value) {
445
463
  if (Array.isArray(value)) {
446
464
  if (value.length < 2) {
447
465
  throw new RangeError(
448
- `[sarmal] setRenderOptions: trailColor array must have at least 2 entries, got ${value.length}`
466
+ `[sarmal] setRenderOptions: trailColor array must have at least 2 entries, got ${value.length}`,
449
467
  );
450
468
  }
451
469
  for (let i = 0; i < value.length; i++) {
452
470
  const entry = value[i];
453
471
  if (typeof entry !== "string" || !HEX_COLOR_RE.test(entry)) {
454
472
  throw new TypeError(
455
- `[sarmal] setRenderOptions: trailColor[${i}] must be a 6-digit hex string, got ${JSON.stringify(entry)}`
473
+ `[sarmal] setRenderOptions: trailColor[${i}] must be a 6-digit hex string, got ${JSON.stringify(entry)}`,
456
474
  );
457
475
  }
458
476
  }
459
477
  return;
460
478
  }
461
479
  throw new TypeError(
462
- `[sarmal] setRenderOptions: trailColor must be a 6-digit hex string or an array of hex strings, got ${JSON.stringify(value)}`
480
+ `[sarmal] setRenderOptions: trailColor must be a 6-digit hex string or an array of hex strings, got ${JSON.stringify(value)}`,
463
481
  );
464
482
  }
465
483
  function assertHeadColor(value) {
@@ -468,7 +486,7 @@ function assertHeadColor(value) {
468
486
  }
469
487
  if (typeof value !== "string" || !HEX_COLOR_RE.test(value)) {
470
488
  throw new TypeError(
471
- `[sarmal] setRenderOptions: headColor must be a 6-digit hex string or null, got ${JSON.stringify(value)}`
489
+ `[sarmal] setRenderOptions: headColor must be a 6-digit hex string or null, got ${JSON.stringify(value)}`,
472
490
  );
473
491
  }
474
492
  }
@@ -478,26 +496,26 @@ function assertSkeletonColor(value) {
478
496
  }
479
497
  if (typeof value !== "string" || !HEX_COLOR_RE.test(value)) {
480
498
  throw new TypeError(
481
- `[sarmal] setRenderOptions: skeletonColor must be a 6-digit hex string or "transparent", got ${JSON.stringify(value)}`
499
+ `[sarmal] setRenderOptions: skeletonColor must be a 6-digit hex string or "transparent", got ${JSON.stringify(value)}`,
482
500
  );
483
501
  }
484
502
  }
485
503
  function assertTrailStyle(value) {
486
504
  if (!TRAIL_STYLES.includes(value)) {
487
505
  throw new RangeError(
488
- `[sarmal] setRenderOptions: trailStyle must be one of "default", "gradient-static", "gradient-animated", got ${JSON.stringify(value)}`
506
+ `[sarmal] setRenderOptions: trailStyle must be one of "default", "gradient-static", "gradient-animated", got ${JSON.stringify(value)}`,
489
507
  );
490
508
  }
491
509
  }
492
510
  function assertHeadRadius(value) {
493
511
  if (typeof value !== "number") {
494
512
  throw new TypeError(
495
- `[sarmal] setRenderOptions: headRadius must be a number, got ${JSON.stringify(value)}`
513
+ `[sarmal] setRenderOptions: headRadius must be a number, got ${JSON.stringify(value)}`,
496
514
  );
497
515
  }
498
516
  if (!Number.isFinite(value) || value <= 0) {
499
517
  throw new TypeError(
500
- `[sarmal] setRenderOptions: headRadius must be a finite positive number, got ${value}`
518
+ `[sarmal] setRenderOptions: headRadius must be a finite positive number, got ${value}`,
501
519
  );
502
520
  }
503
521
  }
@@ -519,13 +537,13 @@ function resolveHeadColor(trailColor, trailStyle) {
519
537
  function warnIfTrailColorMismatch(trailColor, trailStyle) {
520
538
  if (trailStyle === "default" && Array.isArray(trailColor)) {
521
539
  console.warn(
522
- '[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.'
540
+ '[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.',
523
541
  );
524
542
  return;
525
543
  }
526
544
  if (trailStyle !== "default" && typeof trailColor === "string") {
527
545
  console.warn(
528
- `[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.`
546
+ `[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.`,
529
547
  );
530
548
  }
531
549
  }
@@ -535,7 +553,7 @@ var getHeadDotRadius = (w, h) => Math.max(1, 3 * Math.sqrt(Math.min(w, h) / 160)
535
553
  var WHITE_HEX = "#ffffff";
536
554
  function hexToRgbComponents(hex) {
537
555
  const n = parseInt(hex.slice(1), 16);
538
- return `${n >> 16},${n >> 8 & 255},${n & 255}`;
556
+ return `${n >> 16},${(n >> 8) & 255},${n & 255}`;
539
557
  }
540
558
  function applyDprSizing(target, logicalWidth, logicalHeight, dpr) {
541
559
  target.style.width = `${logicalWidth}px`;
@@ -662,7 +680,7 @@ function createRenderer(options) {
662
680
  i,
663
681
  trailCount,
664
682
  toX,
665
- toY
683
+ toY,
666
684
  );
667
685
  if (trailStyle === "default") {
668
686
  ctx.fillStyle = `rgba(${trailSolidRgb},${opacity})`;
@@ -827,7 +845,7 @@ function createRenderer(options) {
827
845
  if (partial.trailColor !== void 0 || partial.trailStyle !== void 0) {
828
846
  warnIfTrailColorMismatch(trailColor, trailStyle);
829
847
  }
830
- }
848
+ },
831
849
  };
832
850
  const pauseOnHidden = options.pauseOnHidden !== false;
833
851
  function handleVisibilityChange() {
@@ -877,7 +895,7 @@ function sampleCurveSkeleton(curveDef) {
877
895
  const samples = Math.ceil(period * 50);
878
896
  const pts = Array.from({ length: samples });
879
897
  for (let i = 0; i < samples; i++) {
880
- const t = i / (samples - 1) * period;
898
+ const t = (i / (samples - 1)) * period;
881
899
  pts[i] = curveDef.skeletonFn ? curveDef.skeletonFn(t) : curveDef.fn(t, 0, EMPTY_PARAMS2);
882
900
  }
883
901
  return pts;
@@ -890,7 +908,7 @@ function createSVGRenderer(options) {
890
908
  const poolSize = engine.trailLength;
891
909
  if (poolSize > HIGH_TRAIL_LENGTH_THRESHOLD) {
892
910
  console.warn(
893
- `[sarmal] High trailLength in SVG renderer (${poolSize}). Consider using the canvas renderer for long trails.`
911
+ `[sarmal] High trailLength in SVG renderer (${poolSize}). Consider using the canvas renderer for long trails.`,
894
912
  );
895
913
  }
896
914
  let trailStyle = options.trailStyle ?? "default";
@@ -909,9 +927,9 @@ function createSVGRenderer(options) {
909
927
  return rect.width && rect.height ? Math.min(rect.width, rect.height) : 200;
910
928
  }
911
929
  const containerPx = getContainerPixelSize();
912
- const svgTrailMinWidth = TRAIL_MIN_WIDTH * viewSize / containerPx;
913
- const svgTrailMaxWidth = TRAIL_MAX_WIDTH * viewSize / containerPx;
914
- const svgSkeletonStrokeWidth = String(SKELETON_STROKE_WIDTH_PX * viewSize / containerPx);
930
+ const svgTrailMinWidth = (TRAIL_MIN_WIDTH * viewSize) / containerPx;
931
+ const svgTrailMaxWidth = (TRAIL_MAX_WIDTH * viewSize) / containerPx;
932
+ const svgSkeletonStrokeWidth = String((SKELETON_STROKE_WIDTH_PX * viewSize) / containerPx);
915
933
  headRadius = options.headRadius ?? SVG_DEFAULT_HEAD_RADIUS;
916
934
  container.setAttribute("viewBox", `0 0 ${viewSize} ${viewSize}`);
917
935
  container.setAttribute("role", "img");
@@ -999,7 +1017,7 @@ function createSVGRenderer(options) {
999
1017
  px,
1000
1018
  py,
1001
1019
  svgTrailMinWidth,
1002
- svgTrailMaxWidth
1020
+ svgTrailMaxWidth,
1003
1021
  );
1004
1022
  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`;
1005
1023
  trailPaths[i].setAttribute("d", d);
@@ -1027,7 +1045,8 @@ function createSVGRenderer(options) {
1027
1045
  let animationId = null;
1028
1046
  let lastTime = 0;
1029
1047
  let pausedByVisibility = false;
1030
- const prefersReducedMotion = typeof window !== "undefined" && window.matchMedia("(prefers-reduced-motion: reduce)").matches;
1048
+ const prefersReducedMotion =
1049
+ typeof window !== "undefined" && window.matchMedia("(prefers-reduced-motion: reduce)").matches;
1031
1050
  let morphResolve = null;
1032
1051
  let morphReject = null;
1033
1052
  let morphDurationMs = DEFAULT_MORPH_DURATION_MS;
@@ -1045,7 +1064,7 @@ function createSVGRenderer(options) {
1045
1064
  skeletonPathA.setAttribute("visibility", "visible");
1046
1065
  skeletonPathA.setAttribute(
1047
1066
  "stroke-opacity",
1048
- String((1 - morphAlpha) * DEFAULT_SKELETON_OPACITY)
1067
+ String((1 - morphAlpha) * DEFAULT_SKELETON_OPACITY),
1049
1068
  );
1050
1069
  }
1051
1070
  if (morphPathBBuilt) {
@@ -1199,7 +1218,7 @@ function createSVGRenderer(options) {
1199
1218
  if (partial.trailColor !== void 0 || partial.trailStyle !== void 0) {
1200
1219
  warnIfTrailColorMismatch(trailColor, trailStyle);
1201
1220
  }
1202
- }
1221
+ },
1203
1222
  };
1204
1223
  const pauseOnHidden = options.pauseOnHidden !== false;
1205
1224
  function handleVisibilityChange() {
@@ -1232,241 +1251,324 @@ function createSarmalSVG(container, curveDef, options) {
1232
1251
  return createSVGRenderer({ container, engine, ...rendererOpts });
1233
1252
  }
1234
1253
 
1235
- // src/curves/artemis2.ts
1236
- var TWO_PI2 = Math.PI * 2;
1237
- function artemis2Fn(t, _time, _params) {
1238
- const a = 0.35, b = 0.15, ox = 0.175;
1239
- const s = Math.sin(t), c = Math.cos(t);
1240
- const denom = 1 + s * s;
1254
+ // src/catmull-rom.ts
1255
+ var PERIOD = 2 * Math.PI;
1256
+ function catmullRom1D(p0, p1, p2, p3, u) {
1257
+ const u2 = u * u;
1258
+ const u3 = u2 * u;
1259
+ return (
1260
+ 0.5 *
1261
+ (2 * p1 +
1262
+ (-p0 + p2) * u +
1263
+ (2 * p0 - 5 * p1 + 4 * p2 - p3) * u2 +
1264
+ (-p0 + 3 * p1 - 3 * p2 + p3) * u3)
1265
+ );
1266
+ }
1267
+ function evaluateCatmullRom(points2, t) {
1268
+ const N = points2.length;
1269
+ if (N === 0) {
1270
+ return { x: 0, y: 0 };
1271
+ }
1272
+ if (N === 1) {
1273
+ return { x: points2[0][0], y: points2[0][1] };
1274
+ }
1275
+ t = ((t % PERIOD) + PERIOD) % PERIOD;
1276
+ const segmentSize = PERIOD / N;
1277
+ let i = Math.floor(t / segmentSize);
1278
+ if (i >= N) {
1279
+ i = N - 1;
1280
+ }
1281
+ let u = (t - i * segmentSize) / segmentSize;
1282
+ u = Math.max(0, Math.min(1, u));
1283
+ const p0 = points2[(i - 1 + N) % N];
1284
+ const p1 = points2[i];
1285
+ const p2 = points2[(i + 1) % N];
1286
+ const p3 = points2[(i + 2) % N];
1241
1287
  return {
1242
- x: c * (1 + a * c) / denom - ox,
1243
- y: s * c * (1 + b * c) / denom
1288
+ x: catmullRom1D(p0[0], p1[0], p2[0], p3[0], u),
1289
+ y: catmullRom1D(p0[1], p1[1], p2[1], p3[1], u),
1244
1290
  };
1245
1291
  }
1292
+ function drawCurve(points2, opts) {
1293
+ if (points2.length < 3) {
1294
+ throw new Error(`drawCurve requires at least 3 points, received ${points2.length}.`);
1295
+ }
1296
+ const first = points2[0];
1297
+ if (points2.every((p) => p[0] === first[0] && p[1] === first[1])) {
1298
+ console.warn(
1299
+ "[sarmal].drawCurve: all control points are identical. The curve will be a single point.",
1300
+ );
1301
+ }
1302
+ const maxAbs = points2.reduce((m, p) => Math.max(m, Math.abs(p[0]), Math.abs(p[1])), 0);
1303
+ if (maxAbs > 2) {
1304
+ console.warn(
1305
+ `[sarmal].drawCurve: control points extend to \xB1${maxAbs.toFixed(1)}, which may render off-screen. Coordinates should be in [-1, 1].`,
1306
+ );
1307
+ }
1308
+ const pts = points2.map(([x, y]) => [x, y]);
1309
+ return {
1310
+ name: opts?.name ?? "drawn",
1311
+ fn: (t) => evaluateCatmullRom(pts, t),
1312
+ period: PERIOD,
1313
+ };
1314
+ }
1315
+
1316
+ // src/curves/artemis2.ts
1317
+ var points = [
1318
+ [-0.44, -0.45],
1319
+ [-0.53, -0.77],
1320
+ [-0.82, -0.66],
1321
+ [-0.82, -0.18],
1322
+ [-0.25, -0.04],
1323
+ [0.16, -0.49],
1324
+ [-0.03, -0.87],
1325
+ [-0.68, -0.94],
1326
+ [-0.95, -0.61],
1327
+ [-0.87, -0],
1328
+ [-0.34, 0.21],
1329
+ [0.27, -0.04],
1330
+ [0.87, 0.06],
1331
+ [0.87, 0.57],
1332
+ [0.32, 0.66],
1333
+ [-0.21, -0.43],
1334
+ [-0.43, -0.81],
1335
+ [-0.69, -0.84],
1336
+ [-0.87, -0.66],
1337
+ [-0.9, -0.47],
1338
+ [-0.76, -0.35],
1339
+ ];
1246
1340
  var artemis2 = {
1247
- name: "Artemis II",
1248
- fn: artemis2Fn,
1249
- period: TWO_PI2,
1250
- speed: 0.7
1341
+ ...drawCurve(points, { name: "Artemis II" }),
1342
+ speed: 0.7,
1251
1343
  };
1252
1344
 
1253
1345
  // src/curves/astroid.ts
1254
- var TWO_PI3 = Math.PI * 2;
1346
+ var TWO_PI2 = Math.PI * 2;
1255
1347
  function astroidFn(t, _time, _params) {
1256
1348
  const c = Math.cos(t);
1257
1349
  const s = Math.sin(t);
1258
1350
  return {
1259
1351
  x: c * c * c,
1260
- y: s * s * s
1352
+ y: s * s * s,
1261
1353
  };
1262
1354
  }
1263
1355
  var astroid = {
1264
1356
  name: "Astroid",
1265
1357
  fn: astroidFn,
1266
- period: TWO_PI3,
1267
- speed: 1.1
1358
+ period: TWO_PI2,
1359
+ speed: 1.1,
1268
1360
  };
1269
1361
 
1270
1362
  // src/curves/deltoid.ts
1271
- var TWO_PI4 = Math.PI * 2;
1363
+ var TWO_PI3 = Math.PI * 2;
1272
1364
  function deltoidFn(t, _time, _params) {
1273
1365
  return {
1274
1366
  x: 2 * Math.cos(t) + Math.cos(2 * t),
1275
- y: 2 * Math.sin(t) - Math.sin(2 * t)
1367
+ y: 2 * Math.sin(t) - Math.sin(2 * t),
1276
1368
  };
1277
1369
  }
1278
1370
  var deltoid = {
1279
1371
  name: "Deltoid",
1280
1372
  fn: deltoidFn,
1281
- period: TWO_PI4,
1282
- speed: 0.9
1373
+ period: TWO_PI3,
1374
+ speed: 0.9,
1283
1375
  };
1284
1376
 
1285
1377
  // src/curves/epicycloid3.ts
1286
- var TWO_PI5 = Math.PI * 2;
1378
+ var TWO_PI4 = Math.PI * 2;
1287
1379
  function epicycloid3Fn(t, _time, _params) {
1288
1380
  return {
1289
1381
  x: 4 * Math.cos(t) - Math.cos(4 * t),
1290
- y: 4 * Math.sin(t) - Math.sin(4 * t)
1382
+ y: 4 * Math.sin(t) - Math.sin(4 * t),
1291
1383
  };
1292
1384
  }
1293
1385
  var epicycloid3 = {
1294
1386
  name: "Epicycloid (n=3)",
1295
1387
  fn: epicycloid3Fn,
1296
- period: TWO_PI5,
1297
- speed: 0.75
1388
+ period: TWO_PI4,
1389
+ speed: 0.75,
1298
1390
  };
1299
1391
 
1300
1392
  // src/curves/epitrochoid7.ts
1301
- var TWO_PI6 = Math.PI * 2;
1393
+ var TWO_PI5 = Math.PI * 2;
1302
1394
  function epitrochoid7Fn(t, _time, _params) {
1303
1395
  const d = 1 + 0.55 * Math.sin(t * 0.5);
1304
1396
  return {
1305
1397
  x: 7 * Math.cos(t) - d * Math.cos(7 * t),
1306
- y: 7 * Math.sin(t) - d * Math.sin(7 * t)
1398
+ y: 7 * Math.sin(t) - d * Math.sin(7 * t),
1307
1399
  };
1308
1400
  }
1309
1401
  function epitrochoid7SkeletonFn(t) {
1310
1402
  const d = 1.275;
1311
1403
  return {
1312
1404
  x: 7 * Math.cos(t) - d * Math.cos(7 * t),
1313
- y: 7 * Math.sin(t) - d * Math.sin(7 * t)
1405
+ y: 7 * Math.sin(t) - d * Math.sin(7 * t),
1314
1406
  };
1315
1407
  }
1316
1408
  var epitrochoid7 = {
1317
1409
  name: "Epitrochoid",
1318
1410
  fn: epitrochoid7Fn,
1319
- period: TWO_PI6,
1411
+ period: TWO_PI5,
1320
1412
  speed: 1.4,
1321
- skeletonFn: epitrochoid7SkeletonFn
1413
+ skeletonFn: epitrochoid7SkeletonFn,
1322
1414
  };
1323
1415
 
1324
1416
  // src/curves/lissajous32.ts
1325
- var TWO_PI7 = Math.PI * 2;
1417
+ var TWO_PI6 = Math.PI * 2;
1326
1418
  function lissajous32Fn(t, time, _params) {
1327
1419
  const phi = time * 0.45;
1328
1420
  return {
1329
1421
  x: Math.sin(3 * t + phi),
1330
- y: Math.sin(2 * t)
1422
+ y: Math.sin(2 * t),
1331
1423
  };
1332
1424
  }
1333
1425
  var lissajous32 = {
1334
1426
  name: "Lissajous 3:2",
1335
1427
  fn: lissajous32Fn,
1336
- period: TWO_PI7,
1428
+ period: TWO_PI6,
1337
1429
  speed: 2,
1338
- skeleton: "live"
1430
+ skeleton: "live",
1339
1431
  };
1340
1432
 
1341
1433
  // src/curves/lissajous43.ts
1342
- var TWO_PI8 = Math.PI * 2;
1434
+ var TWO_PI7 = Math.PI * 2;
1343
1435
  function lissajous43Fn(t, time, _params) {
1344
1436
  const phi = time * 0.38;
1345
1437
  return {
1346
1438
  x: Math.sin(4 * t + phi),
1347
- y: Math.sin(3 * t)
1439
+ y: Math.sin(3 * t),
1348
1440
  };
1349
1441
  }
1350
1442
  var lissajous43 = {
1351
1443
  name: "Lissajous 4:3",
1352
1444
  fn: lissajous43Fn,
1353
- period: TWO_PI8,
1445
+ period: TWO_PI7,
1354
1446
  speed: 1.8,
1355
- skeleton: "live"
1447
+ skeleton: "live",
1356
1448
  };
1357
1449
 
1358
1450
  // src/curves/lame.ts
1359
- var TWO_PI9 = Math.PI * 2;
1451
+ var TWO_PI8 = Math.PI * 2;
1360
1452
  function lameFn(t, time, _params) {
1361
1453
  const p = 1.75 + 1.25 * Math.sin(time * 0.48);
1362
- const c = Math.cos(t), s = Math.sin(t);
1454
+ const c = Math.cos(t),
1455
+ s = Math.sin(t);
1363
1456
  return {
1364
1457
  x: Math.sign(c) * Math.pow(Math.abs(c), p),
1365
- y: Math.sign(s) * Math.pow(Math.abs(s), p)
1458
+ y: Math.sign(s) * Math.pow(Math.abs(s), p),
1366
1459
  };
1367
1460
  }
1368
1461
  var lame = {
1369
1462
  name: "Lam\xE9 Curve",
1370
1463
  fn: lameFn,
1371
- period: TWO_PI9,
1464
+ period: TWO_PI8,
1372
1465
  speed: 1,
1373
- skeleton: "live"
1466
+ skeleton: "live",
1374
1467
  };
1375
1468
 
1376
1469
  // src/curves/rose3.ts
1377
- var TWO_PI10 = Math.PI * 2;
1470
+ var TWO_PI9 = Math.PI * 2;
1378
1471
  function rose3Fn(t, _time, _params) {
1379
1472
  const r = Math.cos(3 * t);
1380
1473
  return {
1381
1474
  x: r * Math.cos(t),
1382
- y: r * Math.sin(t)
1475
+ y: r * Math.sin(t),
1383
1476
  };
1384
1477
  }
1385
1478
  var rose3 = {
1386
1479
  name: "Rose (n=3)",
1387
1480
  fn: rose3Fn,
1388
- period: TWO_PI10,
1389
- speed: 1.15
1481
+ period: TWO_PI9,
1482
+ speed: 1.15,
1390
1483
  };
1391
1484
 
1392
1485
  // src/curves/rose5.ts
1393
- var TWO_PI11 = Math.PI * 2;
1486
+ var TWO_PI10 = Math.PI * 2;
1394
1487
  function rose5Fn(t, _time, _params) {
1395
1488
  const r = Math.cos(5 * t);
1396
1489
  return {
1397
1490
  x: r * Math.cos(t),
1398
- y: r * Math.sin(t)
1491
+ y: r * Math.sin(t),
1399
1492
  };
1400
1493
  }
1401
1494
  var rose5 = {
1402
1495
  name: "Rose (n=5)",
1403
1496
  fn: rose5Fn,
1404
- period: TWO_PI11,
1405
- speed: 1
1497
+ period: TWO_PI10,
1498
+ speed: 1,
1406
1499
  };
1407
1500
 
1408
1501
  // src/curves/rose52.ts
1409
1502
  var FOUR_PI = Math.PI * 4;
1410
1503
  function rose52Fn(t, _time, _params) {
1411
- const r = Math.cos(5 / 2 * t);
1504
+ const r = Math.cos((5 / 2) * t);
1412
1505
  return {
1413
1506
  x: r * Math.cos(t),
1414
- y: r * Math.sin(t)
1507
+ y: r * Math.sin(t),
1415
1508
  };
1416
1509
  }
1417
1510
  var rose52 = {
1418
1511
  name: "Rose (n=5/2)",
1419
1512
  fn: rose52Fn,
1420
1513
  period: FOUR_PI,
1421
- speed: 0.8
1514
+ speed: 0.8,
1422
1515
  };
1423
1516
 
1424
1517
  // src/curves/star.ts
1425
- var TWO_PI12 = Math.PI * 2;
1518
+ var TWO_PI11 = Math.PI * 2;
1426
1519
  function starFn(t, _time, _params) {
1427
- 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));
1520
+ const r =
1521
+ Math.abs(Math.cos((5 / 2) * t)) +
1522
+ 0.35 * Math.abs(Math.cos((15 / 2) * t)) +
1523
+ 0.15 * Math.abs(Math.cos((25 / 2) * t));
1428
1524
  return {
1429
1525
  x: r * Math.cos(t),
1430
- y: r * Math.sin(t)
1526
+ y: r * Math.sin(t),
1431
1527
  };
1432
1528
  }
1433
1529
  var star = {
1434
1530
  name: "Star",
1435
1531
  fn: starFn,
1436
- period: TWO_PI12,
1437
- speed: 1
1532
+ period: TWO_PI11,
1533
+ speed: 1,
1438
1534
  };
1439
1535
 
1440
1536
  // src/curves/star4.ts
1441
- var TWO_PI13 = Math.PI * 2;
1537
+ var TWO_PI12 = Math.PI * 2;
1442
1538
  function star4Fn(t, _time, _params) {
1443
- const r = Math.abs(Math.cos(2 * t)) + 0.35 * Math.abs(Math.cos(6 * t)) + 0.15 * Math.abs(Math.cos(10 * t));
1539
+ const r =
1540
+ Math.abs(Math.cos(2 * t)) +
1541
+ 0.35 * Math.abs(Math.cos(6 * t)) +
1542
+ 0.15 * Math.abs(Math.cos(10 * t));
1444
1543
  return {
1445
1544
  x: r * Math.cos(t),
1446
- y: r * Math.sin(t)
1545
+ y: r * Math.sin(t),
1447
1546
  };
1448
1547
  }
1449
1548
  var star4 = {
1450
1549
  name: "Star (4-arm)",
1451
1550
  fn: star4Fn,
1452
- period: TWO_PI13,
1453
- speed: 1
1551
+ period: TWO_PI12,
1552
+ speed: 1,
1454
1553
  };
1455
1554
 
1456
1555
  // src/curves/star7.ts
1457
- var TWO_PI14 = Math.PI * 2;
1556
+ var TWO_PI13 = Math.PI * 2;
1458
1557
  function star7Fn(t, _time, _params) {
1459
- 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));
1558
+ const r =
1559
+ Math.abs(Math.cos((7 / 2) * t)) +
1560
+ 0.35 * Math.abs(Math.cos((21 / 2) * t)) +
1561
+ 0.15 * Math.abs(Math.cos((35 / 2) * t));
1460
1562
  return {
1461
1563
  x: r * Math.cos(t),
1462
- y: r * Math.sin(t)
1564
+ y: r * Math.sin(t),
1463
1565
  };
1464
1566
  }
1465
1567
  var star7 = {
1466
1568
  name: "Star (7-arm)",
1467
1569
  fn: star7Fn,
1468
- period: TWO_PI14,
1469
- speed: 1
1570
+ period: TWO_PI13,
1571
+ speed: 1,
1470
1572
  };
1471
1573
 
1472
1574
  // src/curves/index.ts
@@ -1484,52 +1586,9 @@ var curves = {
1484
1586
  lissajous32,
1485
1587
  lissajous43,
1486
1588
  epicycloid3,
1487
- lame
1589
+ lame,
1488
1590
  };
1489
1591
 
1490
- // src/catmull-rom.ts
1491
- var PERIOD = 2 * Math.PI;
1492
- function catmullRom1D(p0, p1, p2, p3, u) {
1493
- const u2 = u * u;
1494
- const u3 = u2 * u;
1495
- return 0.5 * (2 * p1 + (-p0 + p2) * u + (2 * p0 - 5 * p1 + 4 * p2 - p3) * u2 + (-p0 + 3 * p1 - 3 * p2 + p3) * u3);
1496
- }
1497
- function evaluateCatmullRom(points, t) {
1498
- const N = points.length;
1499
- if (N === 0) {
1500
- return { x: 0, y: 0 };
1501
- }
1502
- if (N === 1) {
1503
- return { x: points[0][0], y: points[0][1] };
1504
- }
1505
- t = (t % PERIOD + PERIOD) % PERIOD;
1506
- const segmentSize = PERIOD / N;
1507
- let i = Math.floor(t / segmentSize);
1508
- if (i >= N) {
1509
- i = N - 1;
1510
- }
1511
- let u = (t - i * segmentSize) / segmentSize;
1512
- u = Math.max(0, Math.min(1, u));
1513
- const p0 = points[(i - 1 + N) % N];
1514
- const p1 = points[i];
1515
- const p2 = points[(i + 1) % N];
1516
- const p3 = points[(i + 2) % N];
1517
- return {
1518
- x: catmullRom1D(p0[0], p1[0], p2[0], p3[0], u),
1519
- y: catmullRom1D(p0[1], p1[1], p2[1], p3[1], u)
1520
- };
1521
- }
1522
- function drawCurve(points) {
1523
- if (points.length < 3) {
1524
- throw new Error(`drawCurve requires at least 3 points, received ${points.length}.`);
1525
- }
1526
- return {
1527
- name: "custom",
1528
- fn: (t) => evaluateCatmullRom(points, t),
1529
- period: PERIOD
1530
- };
1531
- }
1532
-
1533
1592
  // src/index.ts
1534
1593
  function createSarmal(canvas, curveDef, options) {
1535
1594
  const { trailLength, ...rendererOpts } = options ?? {};
@@ -1537,6 +1596,27 @@ function createSarmal(canvas, curveDef, options) {
1537
1596
  return createRenderer({ canvas, engine, ...rendererOpts });
1538
1597
  }
1539
1598
 
1540
- export { artemis2, astroid, createEngine, createRenderer, createSVGRenderer, createSarmal, createSarmalSVG, curves, deltoid, drawCurve, epicycloid3, epitrochoid7, evaluateCatmullRom, lame, lissajous32, lissajous43, palettes, rose3, rose5 };
1599
+ export {
1600
+ artemis2,
1601
+ astroid,
1602
+ computeBoundaries,
1603
+ createEngine,
1604
+ createRenderer,
1605
+ createSVGRenderer,
1606
+ createSarmal,
1607
+ createSarmalSVG,
1608
+ curves,
1609
+ deltoid,
1610
+ drawCurve,
1611
+ epicycloid3,
1612
+ epitrochoid7,
1613
+ evaluateCatmullRom,
1614
+ lame,
1615
+ lissajous32,
1616
+ lissajous43,
1617
+ palettes,
1618
+ rose3,
1619
+ rose5,
1620
+ };
1621
+ //# sourceMappingURL=index.js.map
1541
1622
  //# sourceMappingURL=index.js.map
1542
- //# sourceMappingURL=index.js.map