@sarmal/core 0.9.0 → 0.9.7

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 (81) hide show
  1. package/dist/auto-init.cjs +255 -154
  2. package/dist/auto-init.cjs.map +1 -1
  3. package/dist/auto-init.d.cts +1 -2
  4. package/dist/auto-init.d.ts +1 -2
  5. package/dist/auto-init.js +254 -153
  6. package/dist/auto-init.js.map +1 -1
  7. package/dist/curves/artemis2.cjs +26 -0
  8. package/dist/curves/artemis2.cjs.map +1 -0
  9. package/dist/curves/artemis2.d.cts +9 -0
  10. package/dist/curves/artemis2.d.ts +9 -0
  11. package/dist/curves/artemis2.js +24 -0
  12. package/dist/curves/artemis2.js.map +1 -0
  13. package/dist/curves/astroid.cjs +22 -0
  14. package/dist/curves/astroid.cjs.map +1 -0
  15. package/dist/curves/astroid.d.cts +9 -0
  16. package/dist/curves/astroid.d.ts +9 -0
  17. package/dist/curves/astroid.js +20 -0
  18. package/dist/curves/astroid.js.map +1 -0
  19. package/dist/curves/deltoid.cjs +20 -0
  20. package/dist/curves/deltoid.cjs.map +1 -0
  21. package/dist/curves/deltoid.d.cts +9 -0
  22. package/dist/curves/deltoid.d.ts +9 -0
  23. package/dist/curves/deltoid.js +18 -0
  24. package/dist/curves/deltoid.js.map +1 -0
  25. package/dist/curves/epicycloid3.cjs +20 -0
  26. package/dist/curves/epicycloid3.cjs.map +1 -0
  27. package/dist/curves/epicycloid3.d.cts +9 -0
  28. package/dist/curves/epicycloid3.d.ts +9 -0
  29. package/dist/curves/epicycloid3.js +18 -0
  30. package/dist/curves/epicycloid3.js.map +1 -0
  31. package/dist/curves/epitrochoid7.cjs +29 -0
  32. package/dist/curves/epitrochoid7.cjs.map +1 -0
  33. package/dist/curves/epitrochoid7.d.cts +9 -0
  34. package/dist/curves/epitrochoid7.d.ts +9 -0
  35. package/dist/curves/epitrochoid7.js +27 -0
  36. package/dist/curves/epitrochoid7.js.map +1 -0
  37. package/dist/curves/index.cjs +206 -0
  38. package/dist/curves/index.cjs.map +1 -0
  39. package/dist/curves/index.d.cts +19 -0
  40. package/dist/curves/index.d.ts +19 -0
  41. package/dist/curves/index.js +206 -0
  42. package/dist/curves/index.js.map +1 -0
  43. package/dist/curves/lame.cjs +24 -0
  44. package/dist/curves/lame.cjs.map +1 -0
  45. package/dist/curves/lame.d.cts +9 -0
  46. package/dist/curves/lame.d.ts +9 -0
  47. package/dist/curves/lame.js +22 -0
  48. package/dist/curves/lame.js.map +1 -0
  49. package/dist/curves/lissajous32.cjs +22 -0
  50. package/dist/curves/lissajous32.cjs.map +1 -0
  51. package/dist/curves/lissajous32.d.cts +9 -0
  52. package/dist/curves/lissajous32.d.ts +9 -0
  53. package/dist/curves/lissajous32.js +20 -0
  54. package/dist/curves/lissajous32.js.map +1 -0
  55. package/dist/curves/lissajous43.cjs +22 -0
  56. package/dist/curves/lissajous43.cjs.map +1 -0
  57. package/dist/curves/lissajous43.d.cts +9 -0
  58. package/dist/curves/lissajous43.d.ts +9 -0
  59. package/dist/curves/lissajous43.js +20 -0
  60. package/dist/curves/lissajous43.js.map +1 -0
  61. package/dist/curves/rose3.cjs +21 -0
  62. package/dist/curves/rose3.cjs.map +1 -0
  63. package/dist/curves/rose3.d.cts +9 -0
  64. package/dist/curves/rose3.d.ts +9 -0
  65. package/dist/curves/rose3.js +19 -0
  66. package/dist/curves/rose3.js.map +1 -0
  67. package/dist/curves/rose5.cjs +21 -0
  68. package/dist/curves/rose5.cjs.map +1 -0
  69. package/dist/curves/rose5.d.cts +9 -0
  70. package/dist/curves/rose5.d.ts +9 -0
  71. package/dist/curves/rose5.js +19 -0
  72. package/dist/curves/rose5.js.map +1 -0
  73. package/dist/index.cjs +263 -154
  74. package/dist/index.cjs.map +1 -1
  75. package/dist/index.d.cts +64 -233
  76. package/dist/index.d.ts +64 -233
  77. package/dist/index.js +270 -154
  78. package/dist/index.js.map +1 -1
  79. package/dist/types-cR2xOewv.d.cts +234 -0
  80. package/dist/types-cR2xOewv.d.ts +234 -0
  81. package/package.json +14 -3
package/dist/auto-init.js CHANGED
@@ -1,6 +1,10 @@
1
1
  // src/engine.ts
2
2
  var TWO_PI = Math.PI * 2;
3
3
  var POINTS_PER_PERIOD_UNIT = 50;
4
+ function lerp(start, end, t) {
5
+ return start + (end - start) * t;
6
+ }
7
+ var EMPTY_PARAMS = {};
4
8
  var CircularBuffer = class {
5
9
  constructor(capacity) {
6
10
  this.head = 0;
@@ -43,16 +47,29 @@ var CircularBuffer = class {
43
47
  }
44
48
  };
45
49
  function resolveCurve(curveDef) {
50
+ const period = curveDef.period ?? TWO_PI;
51
+ if (!Number.isFinite(period) || period <= 0) {
52
+ throw new RangeError(`[sarmal] period must be a positive finite number, got ${period}`);
53
+ }
54
+ const speed = curveDef.speed ?? 1;
55
+ if (!Number.isFinite(speed)) {
56
+ throw new RangeError(`[sarmal] speed must be a finite number, got ${speed}`);
57
+ }
46
58
  return {
47
59
  name: curveDef.name,
48
60
  fn: curveDef.fn,
49
- period: curveDef.period ?? TWO_PI,
50
- speed: curveDef.speed ?? 1,
61
+ period,
62
+ speed,
51
63
  skeleton: curveDef.skeleton,
52
- skeletonFn: curveDef.skeletonFn
64
+ skeletonFn: curveDef.skeletonFn,
53
65
  };
54
66
  }
55
67
  function createEngine(curveDef, trailLength = 120) {
68
+ if (!Number.isFinite(trailLength) || trailLength <= 0) {
69
+ throw new RangeError(
70
+ `[sarmal] trailLength must be a positive finite number, got ${trailLength}`,
71
+ );
72
+ }
56
73
  let curve = resolveCurve(curveDef);
57
74
  const trail = new CircularBuffer(trailLength);
58
75
  let t = 0;
@@ -65,21 +82,25 @@ function createEngine(curveDef, trailLength = 120) {
65
82
  return c.skeletonFn(sampleT);
66
83
  }
67
84
  if (c.skeleton === "live") {
68
- return c.fn(sampleT, actualTime, {});
85
+ return c.fn(sampleT, actualTime, EMPTY_PARAMS);
69
86
  }
70
- return c.fn(sampleT, 0, {});
87
+ return c.fn(sampleT, 0, EMPTY_PARAMS);
71
88
  }
72
89
  return {
73
90
  tick(deltaTime) {
74
- t = (t + curve.speed * deltaTime) % curve.period;
91
+ let effectiveSpeed = curve.speed;
92
+ if (morphCurveB !== null && _morphAlpha !== null) {
93
+ effectiveSpeed = lerp(curve.speed, morphCurveB.speed, _morphAlpha);
94
+ }
95
+ t = (t + effectiveSpeed * deltaTime) % curve.period;
75
96
  actualTime += deltaTime;
76
97
  if (morphCurveB !== null && _morphAlpha !== null) {
77
- const a = curve.fn(t, actualTime, {});
78
- const tB = _morphStrategy === "normalized" ? t / curve.period * morphCurveB.period : t;
79
- const b = morphCurveB.fn(tB, actualTime, {});
98
+ const a = curve.fn(t, actualTime, EMPTY_PARAMS);
99
+ const tB = _morphStrategy === "normalized" ? (t / curve.period) * morphCurveB.period : t;
100
+ const b = morphCurveB.fn(tB, actualTime, EMPTY_PARAMS);
80
101
  trail.push(a.x + (b.x - a.x) * _morphAlpha, a.y + (b.y - a.y) * _morphAlpha);
81
102
  } else {
82
- const point = curve.fn(t, actualTime, {});
103
+ const point = curve.fn(t, actualTime, EMPTY_PARAMS);
83
104
  trail.push(point.x, point.y);
84
105
  }
85
106
  return trail.toArray();
@@ -99,14 +120,14 @@ function createEngine(curveDef, trailLength = 120) {
99
120
  trail.clear();
100
121
  },
101
122
  seek(newT, { clearTrail = false } = {}) {
102
- t = (newT % curve.period + curve.period) % curve.period;
123
+ t = ((newT % curve.period) + curve.period) % curve.period;
103
124
  if (clearTrail) {
104
125
  trail.clear();
105
126
  }
106
127
  },
107
128
  seekWithTrail(targetT, { wrap = false, step = curve.period / trailLength } = {}) {
108
129
  const advance = curve.speed * step;
109
- const target = (targetT % curve.period + curve.period) % curve.period;
130
+ const target = ((targetT % curve.period) + curve.period) % curve.period;
110
131
  const targetTime = target / curve.speed;
111
132
  t = target;
112
133
  actualTime = targetTime;
@@ -115,9 +136,9 @@ function createEngine(curveDef, trailLength = 120) {
115
136
  const count = wrap ? trailLength : Math.min(trailLength, pointsFromStart);
116
137
  for (let i = count - 1; i >= 0; i--) {
117
138
  const sampleT = target - i * advance;
118
- const wrappedT = sampleT < 0 ? sampleT + curve.period : sampleT;
139
+ const wrappedT = ((sampleT % curve.period) + curve.period) % curve.period;
119
140
  const time = targetTime - i * step;
120
- const point = curve.fn(wrappedT, time, {});
141
+ const point = curve.fn(wrappedT, time, EMPTY_PARAMS);
121
142
  trail.push(point.x, point.y);
122
143
  }
123
144
  },
@@ -132,13 +153,16 @@ function createEngine(curveDef, trailLength = 120) {
132
153
  ...frozenB,
133
154
  fn: (sampleT, time, params) => {
134
155
  const a = frozenA.fn(sampleT, time, params);
135
- const tB = frozenStrategy === "normalized" ? sampleT / frozenA.period * frozenB.period : sampleT;
156
+ const tB =
157
+ frozenStrategy === "normalized"
158
+ ? (sampleT / frozenA.period) * frozenB.period
159
+ : sampleT;
136
160
  const b = frozenB.fn(tB, time, params);
137
161
  return {
138
162
  x: a.x + (b.x - a.x) * frozenAlpha,
139
- y: a.y + (b.y - a.y) * frozenAlpha
163
+ y: a.y + (b.y - a.y) * frozenAlpha,
140
164
  };
141
- }
165
+ },
142
166
  };
143
167
  }
144
168
  _morphStrategy = strategy;
@@ -151,7 +175,7 @@ function createEngine(curveDef, trailLength = 120) {
151
175
  completeMorph() {
152
176
  if (morphCurveB !== null) {
153
177
  if (_morphStrategy === "normalized" && curve.period !== morphCurveB.period) {
154
- t = t / curve.period * morphCurveB.period;
178
+ t = (t / curve.period) * morphCurveB.period;
155
179
  }
156
180
  curve = morphCurveB;
157
181
  }
@@ -163,23 +187,26 @@ function createEngine(curveDef, trailLength = 120) {
163
187
  const points = new Array(steps);
164
188
  if (morphCurveB !== null && _morphAlpha !== null) {
165
189
  for (let i = 0; i < steps; i++) {
166
- const sampleT = i / (steps - 1) * curve.period;
190
+ const sampleT = (i / (steps - 1)) * curve.period;
167
191
  const a = sampleSkeleton(curve, sampleT);
168
- const tB = _morphStrategy === "normalized" ? sampleT / curve.period * morphCurveB.period : sampleT;
192
+ const tB =
193
+ _morphStrategy === "normalized"
194
+ ? (sampleT / curve.period) * morphCurveB.period
195
+ : sampleT;
169
196
  const b = sampleSkeleton(morphCurveB, tB);
170
197
  points[i] = {
171
198
  x: a.x + (b.x - a.x) * _morphAlpha,
172
- y: a.y + (b.y - a.y) * _morphAlpha
199
+ y: a.y + (b.y - a.y) * _morphAlpha,
173
200
  };
174
201
  }
175
202
  return points;
176
203
  }
177
204
  for (let i = 0; i < steps; i++) {
178
- const sampleT = i / (steps - 1) * curve.period;
205
+ const sampleT = (i / (steps - 1)) * curve.period;
179
206
  points[i] = sampleSkeleton(curve, sampleT);
180
207
  }
181
208
  return points;
182
- }
209
+ },
183
210
  };
184
211
  }
185
212
 
@@ -199,7 +226,7 @@ var GRADIENT = {
199
226
  ocean: ["#1e3a8a", "#06b6d4", "#22d3ee", "#e0f2fe"],
200
227
  ice: ["#1e3a8a", "#67e8f9"],
201
228
  fire: ["#7f1d1d", "#fbbf24"],
202
- forest: ["#14532d", "#86efac"]
229
+ forest: ["#14532d", "#86efac"],
203
230
  };
204
231
  var PRESETS = {
205
232
  bard: GRADIENT.bard,
@@ -207,16 +234,16 @@ var PRESETS = {
207
234
  ocean: GRADIENT.ocean,
208
235
  ice: GRADIENT.ice,
209
236
  fire: GRADIENT.fire,
210
- forest: GRADIENT.forest
237
+ forest: GRADIENT.forest,
211
238
  };
212
239
  function hexToRgb(hex) {
213
240
  const n = parseInt(hex.slice(1), 16);
214
- return { r: n >> 16, g: n >> 8 & 255, b: n & 255 };
241
+ return { r: n >> 16, g: (n >> 8) & 255, b: n & 255 };
215
242
  }
216
243
  var lerpRgb = (a, b, t) => ({
217
244
  r: Math.round(a.r + (b.r - a.r) * t),
218
245
  g: Math.round(a.g + (b.g - a.g) * t),
219
- b: Math.round(a.b + (b.b - a.b) * t)
246
+ b: Math.round(a.b + (b.b - a.b) * t),
220
247
  });
221
248
  function getPaletteColor(palette, position, timeOffset = 0) {
222
249
  if (palette.length === 0) return { r: 255, g: 255, b: 255 };
@@ -236,7 +263,7 @@ function resolvePalette(palette, trailStyle) {
236
263
  }
237
264
  function hexToRgbComponents(hex) {
238
265
  const n = parseInt(hex.slice(1), 16);
239
- return `${n >> 16},${n >> 8 & 255},${n & 255}`;
266
+ return `${n >> 16},${(n >> 8) & 255},${n & 255}`;
240
267
  }
241
268
  function computeTangent(trail, i) {
242
269
  const count = trail.length;
@@ -281,7 +308,7 @@ function createRenderer(options) {
281
308
  skeletonColor: options.skeletonColor ?? DEFAULT_SKELETON_COLOR,
282
309
  trailColor: options.trailColor ?? "#ffffff",
283
310
  headColor: options.headColor ?? "#ffffff",
284
- headRadius: options.headRadius ?? DEFAULT_HEAD_RADIUS
311
+ headRadius: options.headRadius ?? DEFAULT_HEAD_RADIUS,
285
312
  };
286
313
  const trailStyle = options.trailStyle ?? "default";
287
314
  const palette = resolvePalette(options.palette, trailStyle);
@@ -314,15 +341,31 @@ function createRenderer(options) {
314
341
  function computeBoundaries(pts) {
315
342
  if (pts.length === 0) return null;
316
343
  const first = pts[0];
317
- let minX = first.x, maxX = first.x, minY = first.y, maxY = first.y;
344
+ let minX = first.x,
345
+ maxX = first.x,
346
+ minY = first.y,
347
+ maxY = first.y;
318
348
  for (const p of pts) {
319
- if (p.x < minX) minX = p.x;
320
- if (p.x > maxX) maxX = p.x;
321
- if (p.y < minY) minY = p.y;
322
- if (p.y > maxY) maxY = p.y;
349
+ if (p.x < minX) {
350
+ minX = p.x;
351
+ }
352
+ if (p.x > maxX) {
353
+ maxX = p.x;
354
+ }
355
+ if (p.y < minY) {
356
+ minY = p.y;
357
+ }
358
+ if (p.y > maxY) {
359
+ maxY = p.y;
360
+ }
323
361
  }
324
362
  const width = maxX - minX;
325
363
  const height = maxY - minY;
364
+ if (width === 0 && height === 0) {
365
+ throw new Error(
366
+ "[sarmal] Degenerate curve: all skeleton points are identical. Check that your curve fn returns distinct points for different values of t.",
367
+ );
368
+ }
326
369
  const scaleX = logicalWidth / (width * (1 + FIT_PADDING * 2));
327
370
  const scaleY = logicalHeight / (height * (1 + FIT_PADDING * 2));
328
371
  const s = Math.min(scaleX, scaleY);
@@ -331,7 +374,7 @@ function createRenderer(options) {
331
374
  return {
332
375
  scale: s,
333
376
  offsetX: (logicalWidth - boundsWidth) / 2 - minX * s,
334
- offsetY: (logicalHeight - boundsHeight) / 2 - minY * s
377
+ offsetY: (logicalHeight - boundsHeight) / 2 - minY * s,
335
378
  };
336
379
  }
337
380
  function calculateBoundaries() {
@@ -537,156 +580,199 @@ function createRenderer(options) {
537
580
  return new Promise((resolve) => {
538
581
  morphResolve = resolve;
539
582
  });
540
- }
583
+ },
541
584
  };
542
585
  }
543
586
 
544
- // src/curves.ts
587
+ // src/curves/artemis2.ts
545
588
  var TWO_PI2 = Math.PI * 2;
546
- function artemis2(t, _time, _params) {
547
- const a = 0.35, b = 0.15, ox = 0.175;
548
- const s = Math.sin(t), c = Math.cos(t);
589
+ function artemis2Fn(t, _time, _params) {
590
+ const a = 0.35,
591
+ b = 0.15,
592
+ ox = 0.175;
593
+ const s = Math.sin(t),
594
+ c = Math.cos(t);
549
595
  const denom = 1 + s * s;
550
596
  return {
551
- x: c * (1 + a * c) / denom - ox,
552
- y: s * c * (1 + b * c) / denom
597
+ x: (c * (1 + a * c)) / denom - ox,
598
+ y: (s * c * (1 + b * c)) / denom,
553
599
  };
554
600
  }
555
- function epitrochoid7(t, _time, _params) {
556
- const d = 1 + 0.55 * Math.sin(t * 0.5);
557
- return {
558
- x: 7 * Math.cos(t) - d * Math.cos(7 * t),
559
- y: 7 * Math.sin(t) - d * Math.sin(7 * t)
560
- };
561
- }
562
- function epitrochoid7Skeleton(t) {
563
- const d = 1.275;
564
- return {
565
- x: 7 * Math.cos(t) - d * Math.cos(7 * t),
566
- y: 7 * Math.sin(t) - d * Math.sin(7 * t)
567
- };
568
- }
569
- function astroid(t, _time, _params) {
601
+ var artemis2 = {
602
+ name: "Artemis II",
603
+ fn: artemis2Fn,
604
+ period: TWO_PI2,
605
+ speed: 0.7,
606
+ };
607
+
608
+ // src/curves/astroid.ts
609
+ var TWO_PI3 = Math.PI * 2;
610
+ function astroidFn(t, _time, _params) {
570
611
  const c = Math.cos(t);
571
612
  const s = Math.sin(t);
572
613
  return {
573
614
  x: c * c * c,
574
- y: s * s * s
615
+ y: s * s * s,
575
616
  };
576
617
  }
577
- function deltoid(t, _time, _params) {
618
+ var astroid = {
619
+ name: "Astroid",
620
+ fn: astroidFn,
621
+ period: TWO_PI3,
622
+ speed: 1.1,
623
+ };
624
+
625
+ // src/curves/deltoid.ts
626
+ var TWO_PI4 = Math.PI * 2;
627
+ function deltoidFn(t, _time, _params) {
578
628
  return {
579
629
  x: 2 * Math.cos(t) + Math.cos(2 * t),
580
- y: 2 * Math.sin(t) - Math.sin(2 * t)
630
+ y: 2 * Math.sin(t) - Math.sin(2 * t),
581
631
  };
582
632
  }
583
- function rose5(t, _time, _params) {
584
- const r = Math.cos(5 * t);
633
+ var deltoid = {
634
+ name: "Deltoid",
635
+ fn: deltoidFn,
636
+ period: TWO_PI4,
637
+ speed: 0.9,
638
+ };
639
+
640
+ // src/curves/epicycloid3.ts
641
+ var TWO_PI5 = Math.PI * 2;
642
+ function epicycloid3Fn(t, _time, _params) {
585
643
  return {
586
- x: r * Math.cos(t),
587
- y: r * Math.sin(t)
644
+ x: 4 * Math.cos(t) - Math.cos(4 * t),
645
+ y: 4 * Math.sin(t) - Math.sin(4 * t),
588
646
  };
589
647
  }
590
- function rose3(t, _time, _params) {
591
- const r = Math.cos(3 * t);
648
+ var epicycloid3 = {
649
+ name: "Epicycloid (n=3)",
650
+ fn: epicycloid3Fn,
651
+ period: TWO_PI5,
652
+ speed: 0.75,
653
+ };
654
+
655
+ // src/curves/epitrochoid7.ts
656
+ var TWO_PI6 = Math.PI * 2;
657
+ function epitrochoid7Fn(t, _time, _params) {
658
+ const d = 1 + 0.55 * Math.sin(t * 0.5);
592
659
  return {
593
- x: r * Math.cos(t),
594
- y: r * Math.sin(t)
660
+ x: 7 * Math.cos(t) - d * Math.cos(7 * t),
661
+ y: 7 * Math.sin(t) - d * Math.sin(7 * t),
662
+ };
663
+ }
664
+ function epitrochoid7SkeletonFn(t) {
665
+ const d = 1.275;
666
+ return {
667
+ x: 7 * Math.cos(t) - d * Math.cos(7 * t),
668
+ y: 7 * Math.sin(t) - d * Math.sin(7 * t),
595
669
  };
596
670
  }
597
- function lissajous32(t, time, _params) {
671
+ var epitrochoid7 = {
672
+ name: "Epitrochoid",
673
+ fn: epitrochoid7Fn,
674
+ period: TWO_PI6,
675
+ speed: 1.4,
676
+ skeletonFn: epitrochoid7SkeletonFn,
677
+ };
678
+
679
+ // src/curves/lissajous32.ts
680
+ var TWO_PI7 = Math.PI * 2;
681
+ function lissajous32Fn(t, time, _params) {
598
682
  const phi = time * 0.45;
599
683
  return {
600
684
  x: Math.sin(3 * t + phi),
601
- y: Math.sin(2 * t)
685
+ y: Math.sin(2 * t),
602
686
  };
603
687
  }
604
- function lissajous43(t, time, _params) {
688
+ var lissajous32 = {
689
+ name: "Lissajous 3:2",
690
+ fn: lissajous32Fn,
691
+ period: TWO_PI7,
692
+ speed: 2,
693
+ skeleton: "live",
694
+ };
695
+
696
+ // src/curves/lissajous43.ts
697
+ var TWO_PI8 = Math.PI * 2;
698
+ function lissajous43Fn(t, time, _params) {
605
699
  const phi = time * 0.38;
606
700
  return {
607
701
  x: Math.sin(4 * t + phi),
608
- y: Math.sin(3 * t)
702
+ y: Math.sin(3 * t),
609
703
  };
610
704
  }
611
- function epicycloid3(t, _time, _params) {
705
+ var lissajous43 = {
706
+ name: "Lissajous 4:3",
707
+ fn: lissajous43Fn,
708
+ period: TWO_PI8,
709
+ speed: 1.8,
710
+ skeleton: "live",
711
+ };
712
+
713
+ // src/curves/lame.ts
714
+ var TWO_PI9 = Math.PI * 2;
715
+ function lameFn(t, time, _params) {
716
+ const p = 1.75 + 1.25 * Math.sin(time * 0.48);
717
+ const c = Math.cos(t),
718
+ s = Math.sin(t);
612
719
  return {
613
- x: 4 * Math.cos(t) - Math.cos(4 * t),
614
- y: 4 * Math.sin(t) - Math.sin(4 * t)
720
+ x: Math.sign(c) * Math.pow(Math.abs(c), p),
721
+ y: Math.sign(s) * Math.pow(Math.abs(s), p),
615
722
  };
616
723
  }
617
- function lame(t, time, _params) {
618
- const p = 1.75 + 1.25 * Math.sin(time * 0.48);
619
- const c = Math.cos(t), s = Math.sin(t);
724
+ var lame = {
725
+ name: "Lam\xE9 Curve",
726
+ fn: lameFn,
727
+ period: TWO_PI9,
728
+ speed: 1,
729
+ skeleton: "live",
730
+ };
731
+
732
+ // src/curves/rose3.ts
733
+ var TWO_PI10 = Math.PI * 2;
734
+ function rose3Fn(t, _time, _params) {
735
+ const r = Math.cos(3 * t);
620
736
  return {
621
- x: Math.sign(c) * Math.pow(Math.abs(c), p),
622
- y: Math.sign(s) * Math.pow(Math.abs(s), p)
737
+ x: r * Math.cos(t),
738
+ y: r * Math.sin(t),
739
+ };
740
+ }
741
+ var rose3 = {
742
+ name: "Rose (n=3)",
743
+ fn: rose3Fn,
744
+ period: TWO_PI10,
745
+ speed: 1.15,
746
+ };
747
+
748
+ // src/curves/rose5.ts
749
+ var TWO_PI11 = Math.PI * 2;
750
+ function rose5Fn(t, _time, _params) {
751
+ const r = Math.cos(5 * t);
752
+ return {
753
+ x: r * Math.cos(t),
754
+ y: r * Math.sin(t),
623
755
  };
624
756
  }
757
+ var rose5 = {
758
+ name: "Rose (n=5)",
759
+ fn: rose5Fn,
760
+ period: TWO_PI11,
761
+ speed: 1,
762
+ };
763
+
764
+ // src/curves/index.ts
625
765
  var curves = {
626
- artemis2: {
627
- name: "Artemis II",
628
- fn: artemis2,
629
- period: TWO_PI2,
630
- speed: 0.7
631
- },
632
- epitrochoid7: {
633
- name: "Epitrochoid",
634
- fn: epitrochoid7,
635
- period: TWO_PI2,
636
- speed: 1.4,
637
- skeletonFn: epitrochoid7Skeleton
638
- },
639
- astroid: {
640
- name: "Astroid",
641
- fn: astroid,
642
- period: TWO_PI2,
643
- speed: 1.1
644
- },
645
- deltoid: {
646
- name: "Deltoid",
647
- fn: deltoid,
648
- period: TWO_PI2,
649
- speed: 0.9
650
- },
651
- rose5: {
652
- name: "Rose (n=5)",
653
- fn: rose5,
654
- period: TWO_PI2,
655
- speed: 1
656
- },
657
- rose3: {
658
- name: "Rose (n=3)",
659
- fn: rose3,
660
- period: TWO_PI2,
661
- speed: 1.15
662
- },
663
- lissajous32: {
664
- name: "Lissajous 3:2",
665
- fn: lissajous32,
666
- period: TWO_PI2,
667
- speed: 2,
668
- skeleton: "live"
669
- },
670
- lissajous43: {
671
- name: "Lissajous 4:3",
672
- fn: lissajous43,
673
- period: TWO_PI2,
674
- speed: 1.8,
675
- skeleton: "live"
676
- },
677
- epicycloid3: {
678
- name: "Epicycloid (n=3)",
679
- fn: epicycloid3,
680
- period: TWO_PI2,
681
- speed: 0.75
682
- },
683
- lame: {
684
- name: "Lam\xE9 Curve",
685
- fn: lame,
686
- period: TWO_PI2,
687
- speed: 1,
688
- skeleton: "live"
689
- }
766
+ artemis2,
767
+ epitrochoid7,
768
+ astroid,
769
+ deltoid,
770
+ rose5,
771
+ rose3,
772
+ lissajous32,
773
+ lissajous43,
774
+ epicycloid3,
775
+ lame,
690
776
  };
691
777
 
692
778
  // src/index.ts
@@ -697,31 +783,46 @@ function createSarmal(canvas, curveDef, options) {
697
783
  }
698
784
 
699
785
  // src/auto-init.ts
786
+ function parsePalette(value) {
787
+ try {
788
+ const parsed = JSON.parse(value);
789
+ if (Array.isArray(parsed)) {
790
+ return parsed;
791
+ }
792
+ } catch {}
793
+ return value;
794
+ }
700
795
  function init() {
701
796
  const canvases = document.querySelectorAll("canvas[data-sarmal]");
702
797
  canvases.forEach((canvas) => {
703
798
  const curveName = canvas.getAttribute("data-sarmal");
704
799
  if (curveName == null) {
705
- return console.warn("[sarmal] curveName isrequried");
800
+ return console.warn("[sarmal] curveName is required");
706
801
  }
707
802
  const curveDef = curves[curveName];
708
803
  if (!curveDef) {
709
804
  return console.error(`[sarmal] "${curveName}" is not a valid curve name`);
710
805
  }
711
806
  const sarmal = createSarmal(canvas, curveDef, {
712
- ...canvas.dataset.trailColor && { trailColor: canvas.dataset.trailColor },
713
- ...canvas.dataset.skeletonColor && { skeletonColor: canvas.dataset.skeletonColor },
714
- ...canvas.dataset.headColor && { headColor: canvas.dataset.headColor },
715
- ...canvas.dataset.headRadius && { headRadius: parseFloat(canvas.dataset.headRadius) },
716
- ...canvas.dataset.trailLength && { trailLength: parseInt(canvas.dataset.trailLength, 10) }
807
+ ...(canvas.dataset.trailColor && { trailColor: canvas.dataset.trailColor }),
808
+ ...(canvas.dataset.skeletonColor && { skeletonColor: canvas.dataset.skeletonColor }),
809
+ ...(canvas.dataset.headColor && { headColor: canvas.dataset.headColor }),
810
+ ...(canvas.dataset.headRadius && { headRadius: parseFloat(canvas.dataset.headRadius) }),
811
+ ...(canvas.dataset.trailLength && { trailLength: parseInt(canvas.dataset.trailLength, 10) }),
812
+ ...(canvas.dataset.trailStyle && {
813
+ trailStyle: canvas.dataset.trailStyle,
814
+ }),
815
+ ...(canvas.dataset.palette && { palette: parsePalette(canvas.dataset.palette) }),
717
816
  });
718
817
  sarmal.start();
719
818
  });
720
819
  }
721
820
  if (document.readyState === "loading") {
722
- document.addEventListener("DOMContentLoaded", init);
821
+ document.addEventListener("DOMContentLoaded", () => {
822
+ requestAnimationFrame(init);
823
+ });
723
824
  } else {
724
- init();
825
+ requestAnimationFrame(init);
725
826
  }
726
827
  //# sourceMappingURL=auto-init.js.map
727
- //# sourceMappingURL=auto-init.js.map
828
+ //# sourceMappingURL=auto-init.js.map