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