@sarmal/core 0.5.0 → 0.6.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.
package/dist/index.js CHANGED
@@ -42,24 +42,46 @@ var CircularBuffer = class {
42
42
  return this.count;
43
43
  }
44
44
  };
45
- function createEngine(curveDef, trailLength = 120) {
46
- const curve = {
45
+ function resolveCurve(curveDef) {
46
+ return {
47
47
  name: curveDef.name,
48
48
  fn: curveDef.fn,
49
49
  period: curveDef.period ?? TWO_PI,
50
50
  speed: curveDef.speed ?? 1,
51
51
  skeleton: curveDef.skeleton,
52
- skeletonFn: curveDef.skeletonFn
52
+ skeletonFn: curveDef.skeletonFn,
53
53
  };
54
+ }
55
+ function createEngine(curveDef, trailLength = 120) {
56
+ let curve = resolveCurve(curveDef);
54
57
  const trail = new CircularBuffer(trailLength);
55
58
  let t = 0;
56
59
  let actualTime = 0;
60
+ let morphCurveB = null;
61
+ let _morphAlpha = null;
62
+ let _morphStrategy = "normalized";
63
+ function sampleSkeleton(c, sampleT) {
64
+ if (c.skeletonFn) {
65
+ return c.skeletonFn(sampleT);
66
+ }
67
+ if (c.skeleton === "live") {
68
+ return c.fn(sampleT, actualTime, {});
69
+ }
70
+ return c.fn(sampleT, 0, {});
71
+ }
57
72
  return {
58
73
  tick(deltaTime) {
59
74
  t = (t + curve.speed * deltaTime) % curve.period;
60
75
  actualTime += deltaTime;
61
- const point = curve.fn(t, actualTime, {});
62
- trail.push(point.x, point.y);
76
+ 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, {});
80
+ trail.push(a.x + (b.x - a.x) * _morphAlpha, a.y + (b.y - a.y) * _morphAlpha);
81
+ } else {
82
+ const point = curve.fn(t, actualTime, {});
83
+ trail.push(point.x, point.y);
84
+ }
63
85
  return trail.toArray();
64
86
  },
65
87
  get trailCount() {
@@ -68,20 +90,23 @@ function createEngine(curveDef, trailLength = 120) {
68
90
  get isLiveSkeleton() {
69
91
  return curve.skeleton === "live";
70
92
  },
93
+ get morphAlpha() {
94
+ return _morphAlpha;
95
+ },
71
96
  reset() {
72
97
  t = 0;
73
98
  actualTime = 0;
74
99
  trail.clear();
75
100
  },
76
101
  seek(newT, { clearTrail = false } = {}) {
77
- t = (newT % curve.period + curve.period) % curve.period;
102
+ t = ((newT % curve.period) + curve.period) % curve.period;
78
103
  if (clearTrail) {
79
104
  trail.clear();
80
105
  }
81
106
  },
82
107
  seekWithTrail(targetT, { wrap = false, step = curve.period / trailLength } = {}) {
83
108
  const advance = curve.speed * step;
84
- const target = (targetT % curve.period + curve.period) % curve.period;
109
+ const target = ((targetT % curve.period) + curve.period) % curve.period;
85
110
  const targetTime = target / curve.speed;
86
111
  t = target;
87
112
  actualTime = targetTime;
@@ -96,31 +121,73 @@ function createEngine(curveDef, trailLength = 120) {
96
121
  trail.push(point.x, point.y);
97
122
  }
98
123
  },
124
+ startMorph(target, strategy = "normalized") {
125
+ const resolvedTarget = resolveCurve(target);
126
+ if (morphCurveB !== null && _morphAlpha !== null) {
127
+ const frozenAlpha = _morphAlpha;
128
+ const frozenA = curve;
129
+ const frozenB = morphCurveB;
130
+ const frozenStrategy = _morphStrategy;
131
+ curve = {
132
+ ...frozenB,
133
+ fn: (sampleT, time, params) => {
134
+ const a = frozenA.fn(sampleT, time, params);
135
+ const tB =
136
+ frozenStrategy === "normalized"
137
+ ? (sampleT / frozenA.period) * frozenB.period
138
+ : sampleT;
139
+ const b = frozenB.fn(tB, time, params);
140
+ return {
141
+ x: a.x + (b.x - a.x) * frozenAlpha,
142
+ y: a.y + (b.y - a.y) * frozenAlpha,
143
+ };
144
+ },
145
+ };
146
+ }
147
+ _morphStrategy = strategy;
148
+ morphCurveB = resolvedTarget;
149
+ _morphAlpha = 0;
150
+ },
151
+ setMorphAlpha(alpha) {
152
+ _morphAlpha = alpha;
153
+ },
154
+ completeMorph() {
155
+ if (morphCurveB !== null) {
156
+ curve = morphCurveB;
157
+ }
158
+ morphCurveB = null;
159
+ _morphAlpha = null;
160
+ },
99
161
  getSarmalSkeleton() {
100
162
  const steps = Math.ceil(curve.period * POINTS_PER_PERIOD_UNIT);
101
163
  const points = new Array(steps);
102
- if (curve.skeletonFn) {
164
+ if (morphCurveB !== null && _morphAlpha !== null) {
103
165
  for (let i = 0; i < steps; i++) {
104
- const sampleT = i / (steps - 1) * curve.period;
105
- points[i] = curve.skeletonFn(sampleT);
106
- }
107
- } else if (curve.skeleton === "live") {
108
- for (let i = 0; i < steps; i++) {
109
- const sampleT = i / (steps - 1) * curve.period;
110
- points[i] = curve.fn(sampleT, actualTime, {});
111
- }
112
- } else {
113
- for (let i = 0; i < steps; i++) {
114
- const sampleT = i / (steps - 1) * curve.period;
115
- points[i] = curve.fn(sampleT, 0, {});
166
+ const sampleT = (i / (steps - 1)) * curve.period;
167
+ const a = sampleSkeleton(curve, sampleT);
168
+ const tB =
169
+ _morphStrategy === "normalized"
170
+ ? (sampleT / curve.period) * morphCurveB.period
171
+ : sampleT;
172
+ const b = sampleSkeleton(morphCurveB, tB);
173
+ points[i] = {
174
+ x: a.x + (b.x - a.x) * _morphAlpha,
175
+ y: a.y + (b.y - a.y) * _morphAlpha,
176
+ };
116
177
  }
178
+ return points;
179
+ }
180
+ for (let i = 0; i < steps; i++) {
181
+ const sampleT = (i / (steps - 1)) * curve.period;
182
+ points[i] = sampleSkeleton(curve, sampleT);
117
183
  }
118
184
  return points;
119
- }
185
+ },
120
186
  };
121
187
  }
122
188
 
123
189
  // src/renderer.ts
190
+ var DEFAULT_MORPH_DURATION_MS = 300;
124
191
  var DEFAULT_HEAD_RADIUS = 4;
125
192
  var DEFAULT_GLOW_SIZE = 20;
126
193
  var DEFAULT_SKELETON_COLOR = "#ffffff";
@@ -135,7 +202,7 @@ var GLOW_INNER_EDGE = 0.4;
135
202
  var GLOW_FALLOFF_OPACITY = 0.53;
136
203
  function hexToRgbComponents(hex) {
137
204
  const n = parseInt(hex.slice(1), 16);
138
- return `${n >> 16},${n >> 8 & 255},${n & 255}`;
205
+ return `${n >> 16},${(n >> 8) & 255},${n & 255}`;
139
206
  }
140
207
  function createRenderer(options) {
141
208
  const canvas = options.canvas;
@@ -149,7 +216,7 @@ function createRenderer(options) {
149
216
  trailColor: options.trailColor ?? "#ffffff",
150
217
  headColor: options.headColor ?? "#ffffff",
151
218
  headRadius: options.headRadius ?? DEFAULT_HEAD_RADIUS,
152
- glowSize: options.glowSize ?? DEFAULT_GLOW_SIZE
219
+ glowSize: options.glowSize ?? DEFAULT_GLOW_SIZE,
153
220
  };
154
221
  const trailRgb = hexToRgbComponents(opts.trailColor);
155
222
  const headRgbFalloff = `rgba(${hexToRgbComponents(opts.headColor)},${GLOW_FALLOFF_OPACITY})`;
@@ -163,12 +230,21 @@ function createRenderer(options) {
163
230
  let offsetY = 0;
164
231
  let animationId = null;
165
232
  let lastTime = 0;
233
+ let morphResolve = null;
234
+ let morphDurationMs = DEFAULT_MORPH_DURATION_MS;
235
+ let morphTarget = null;
236
+ let morphAlpha = 0;
237
+ let skeletonCanvasA = null;
238
+ let skeletonCanvasB = null;
166
239
  function calculateBoundaries() {
167
240
  if (skeleton.length === 0) {
168
241
  return;
169
242
  }
170
243
  const first = skeleton[0];
171
- let minX = first.x, maxX = first.x, minY = first.y, maxY = first.y;
244
+ let minX = first.x,
245
+ maxX = first.x,
246
+ minY = first.y,
247
+ maxY = first.y;
172
248
  for (const p of skeleton) {
173
249
  if (p.x < minX) {
174
250
  minX = p.x;
@@ -214,6 +290,18 @@ function createRenderer(options) {
214
290
  if (opts.skeletonColor === "transparent") {
215
291
  return;
216
292
  }
293
+ if (engine.morphAlpha !== null) {
294
+ if (skeletonCanvasA) {
295
+ ctx.globalAlpha = (1 - morphAlpha) * DEFAULT_SKELETON_OPACITY;
296
+ ctx.drawImage(skeletonCanvasA, 0, 0);
297
+ }
298
+ if (skeletonCanvasB) {
299
+ ctx.globalAlpha = morphAlpha * DEFAULT_SKELETON_OPACITY;
300
+ ctx.drawImage(skeletonCanvasB, 0, 0);
301
+ }
302
+ ctx.globalAlpha = 1;
303
+ return;
304
+ }
217
305
  if (engine.isLiveSkeleton) {
218
306
  if (skeleton.length < 2) {
219
307
  return;
@@ -280,11 +368,26 @@ function createRenderer(options) {
280
368
  const now = performance.now();
281
369
  const deltaTime = Math.min((now - lastTime) / 1e3, 1 / 30);
282
370
  lastTime = now;
371
+ if (engine.morphAlpha !== null) {
372
+ morphAlpha = Math.min(1, morphAlpha + deltaTime / (morphDurationMs / 1e3));
373
+ engine.setMorphAlpha(morphAlpha);
374
+ skeleton = engine.getSarmalSkeleton();
375
+ calculateBoundaries();
376
+ if (morphAlpha >= 1) {
377
+ engine.completeMorph();
378
+ morphResolve?.();
379
+ morphResolve = null;
380
+ morphTarget = null;
381
+ morphAlpha = 0;
382
+ skeletonCanvasA = null;
383
+ skeletonCanvasB = null;
384
+ }
385
+ }
283
386
  trail = engine.tick(deltaTime);
284
387
  trailCount = engine.trailCount;
285
388
  head = trailCount > 0 ? trail[trailCount - 1] : null;
286
389
  ctx.clearRect(0, 0, canvas.width, canvas.height);
287
- if (engine.isLiveSkeleton) {
390
+ if (engine.isLiveSkeleton || engine.morphAlpha !== null) {
288
391
  skeleton = engine.getSarmalSkeleton();
289
392
  calculateBoundaries();
290
393
  }
@@ -329,11 +432,61 @@ function createRenderer(options) {
329
432
  },
330
433
  seekWithTrail(t) {
331
434
  engine.seekWithTrail(t);
332
- }
435
+ },
436
+ morphTo(target, options2) {
437
+ if (morphResolve !== null) {
438
+ engine.completeMorph();
439
+ morphResolve();
440
+ morphResolve = null;
441
+ morphAlpha = 0;
442
+ skeletonCanvasA = null;
443
+ skeletonCanvasB = null;
444
+ }
445
+ morphDurationMs = options2?.duration ?? DEFAULT_MORPH_DURATION_MS;
446
+ morphTarget = target;
447
+ morphAlpha = 0;
448
+ const currentSkeleton = engine.getSarmalSkeleton();
449
+ if (currentSkeleton.length >= 2) {
450
+ skeletonCanvasA = new OffscreenCanvas(canvas.width, canvas.height);
451
+ const ctxA = skeletonCanvasA.getContext("2d");
452
+ ctxA.strokeStyle = `rgba(${hexToRgbComponents(opts.skeletonColor)},${DEFAULT_SKELETON_OPACITY})`;
453
+ ctxA.lineWidth = 1.5;
454
+ ctxA.beginPath();
455
+ const first = currentSkeleton[0];
456
+ ctxA.moveTo(first.x * scale + offsetX, first.y * scale + offsetY);
457
+ for (let i = 1; i < currentSkeleton.length; i++) {
458
+ const p = currentSkeleton[i];
459
+ ctxA.lineTo(p.x * scale + offsetX, p.y * scale + offsetY);
460
+ }
461
+ ctxA.stroke();
462
+ }
463
+ engine.startMorph(target, options2?.morphStrategy);
464
+ if (morphTarget && !engine.isLiveSkeleton) {
465
+ skeletonCanvasB = new OffscreenCanvas(canvas.width, canvas.height);
466
+ const skeletonCtx = skeletonCanvasB.getContext("2d");
467
+ skeletonCtx.strokeStyle = `rgba(${hexToRgbComponents(opts.skeletonColor)},${DEFAULT_SKELETON_OPACITY})`;
468
+ skeletonCtx.lineWidth = 1.5;
469
+ skeletonCtx.beginPath();
470
+ const period = morphTarget.period ?? Math.PI * 2;
471
+ const samples = Math.max(50, Math.round(period * 20));
472
+ const firstB = morphTarget.fn(0, 0, {});
473
+ skeletonCtx.moveTo(firstB.x * scale + offsetX, firstB.y * scale + offsetY);
474
+ for (let i = 1; i <= samples; i++) {
475
+ const t = (i / samples) * period;
476
+ const p = morphTarget.fn(t, 0, {});
477
+ skeletonCtx.lineTo(p.x * scale + offsetX, p.y * scale + offsetY);
478
+ }
479
+ skeletonCtx.stroke();
480
+ }
481
+ return new Promise((resolve) => {
482
+ morphResolve = resolve;
483
+ });
484
+ },
333
485
  };
334
486
  }
335
487
 
336
488
  // src/renderer-svg.ts
489
+ var DEFAULT_MORPH_DURATION_MS2 = 300;
337
490
  var TRAIL_BATCH_COUNT = 12;
338
491
  var TRAIL_FADE_CURVE2 = 1.5;
339
492
  var TRAIL_MAX_OPACITY2 = 0.88;
@@ -355,7 +508,7 @@ function createSVGRenderer(options) {
355
508
  headColor: options.headColor ?? "#ffffff",
356
509
  headRadius: options.headRadius ?? 4,
357
510
  glowSize: options.glowSize ?? 20,
358
- ariaLabel: options.ariaLabel ?? "Loading"
511
+ ariaLabel: options.ariaLabel ?? "Loading",
359
512
  };
360
513
  const uid = ++instanceCount;
361
514
  const gradientId = `sarmal-glow-${uid}`;
@@ -398,6 +551,20 @@ function createSVGRenderer(options) {
398
551
  skeletonPath.setAttribute("stroke-opacity", String(DEFAULT_SKELETON_OPACITY2));
399
552
  skeletonPath.setAttribute("stroke-width", "1.5");
400
553
  svg.appendChild(skeletonPath);
554
+ const skeletonPathA = el("path");
555
+ skeletonPathA.setAttribute("fill", "none");
556
+ skeletonPathA.setAttribute("stroke", opts.skeletonColor);
557
+ skeletonPathA.setAttribute("stroke-width", "1.5");
558
+ skeletonPathA.setAttribute("visibility", "hidden");
559
+ svg.appendChild(skeletonPathA);
560
+ const skeletonPathB = el("path");
561
+ skeletonPathB.setAttribute("fill", "none");
562
+ skeletonPathB.setAttribute("stroke", opts.skeletonColor);
563
+ skeletonPathB.setAttribute("stroke-width", "1.5");
564
+ skeletonPathB.setAttribute("visibility", "hidden");
565
+ svg.appendChild(skeletonPathB);
566
+ let morphPathABuilt = "";
567
+ let morphPathBBuilt = "";
401
568
  const trailPaths = [];
402
569
  for (let i = 0; i < TRAIL_BATCH_COUNT; i++) {
403
570
  const path = el("path");
@@ -425,7 +592,10 @@ function createSVGRenderer(options) {
425
592
  return;
426
593
  }
427
594
  const first = skeleton2[0];
428
- let minX = first.x, maxX = first.x, minY = first.y, maxY = first.y;
595
+ let minX = first.x,
596
+ maxX = first.x,
597
+ minY = first.y,
598
+ maxY = first.y;
429
599
  for (const p of skeleton2) {
430
600
  if (p.x < minX) {
431
601
  minX = p.x;
@@ -512,11 +682,73 @@ function createSVGRenderer(options) {
512
682
  }
513
683
  let animationId = null;
514
684
  let lastTime = 0;
515
- const prefersReducedMotion = typeof window !== "undefined" && window.matchMedia("(prefers-reduced-motion: reduce)").matches;
685
+ const prefersReducedMotion =
686
+ typeof window !== "undefined" && window.matchMedia("(prefers-reduced-motion: reduce)").matches;
687
+ let morphResolve = null;
688
+ let morphDurationMs = DEFAULT_MORPH_DURATION_MS2;
689
+ let morphTarget = null;
690
+ let morphAlpha = 0;
691
+ function buildSkeletonPath(target, scale2, offsetX2, offsetY2) {
692
+ const period = target.period ?? Math.PI * 2;
693
+ const samples = Math.max(50, Math.round(period * 20));
694
+ const points = [];
695
+ for (let i = 0; i <= samples; i++) {
696
+ const t = (i / samples) * period;
697
+ const p = target.fn(t, 0, {});
698
+ points.push(p);
699
+ }
700
+ if (points.length < 2) {
701
+ return "";
702
+ }
703
+ const px2 = (p) => (p.x * scale2 + offsetX2).toFixed(2);
704
+ const py2 = (p) => (p.y * scale2 + offsetY2).toFixed(2);
705
+ let d = `M${px2(points[0])} ${py2(points[0])}`;
706
+ for (let i = 1; i < points.length; i++) {
707
+ d += ` L${px2(points[i])} ${py2(points[i])}`;
708
+ }
709
+ d += " Z";
710
+ return d;
711
+ }
516
712
  function renderFrame() {
517
713
  const now = performance.now();
518
714
  const dt = Math.min((now - lastTime) / 1e3, 1 / 30);
519
715
  lastTime = now;
716
+ if (engine.morphAlpha !== null) {
717
+ morphAlpha = Math.min(1, morphAlpha + dt / (morphDurationMs / 1e3));
718
+ engine.setMorphAlpha(morphAlpha);
719
+ const morphSkeleton = engine.getSarmalSkeleton();
720
+ calculateBoundaries(morphSkeleton);
721
+ if (!engine.isLiveSkeleton) {
722
+ updateSkeleton(morphSkeleton);
723
+ }
724
+ if (morphPathABuilt) {
725
+ skeletonPathA.setAttribute("d", morphPathABuilt);
726
+ skeletonPathA.setAttribute("visibility", "visible");
727
+ skeletonPathA.setAttribute(
728
+ "stroke-opacity",
729
+ String((1 - morphAlpha) * DEFAULT_SKELETON_OPACITY2),
730
+ );
731
+ }
732
+ if (morphPathBBuilt) {
733
+ skeletonPathB.setAttribute("d", morphPathBBuilt);
734
+ skeletonPathB.setAttribute("visibility", "visible");
735
+ skeletonPathB.setAttribute(
736
+ "stroke-opacity",
737
+ String(morphAlpha * DEFAULT_SKELETON_OPACITY2),
738
+ );
739
+ }
740
+ if (morphAlpha >= 1) {
741
+ engine.completeMorph();
742
+ morphResolve?.();
743
+ morphResolve = null;
744
+ morphTarget = null;
745
+ morphAlpha = 0;
746
+ morphPathABuilt = "";
747
+ morphPathBBuilt = "";
748
+ skeletonPathA.setAttribute("visibility", "hidden");
749
+ skeletonPathB.setAttribute("visibility", "hidden");
750
+ }
751
+ }
520
752
  const trail = engine.tick(dt);
521
753
  const trailCount = engine.trailCount;
522
754
  if (engine.isLiveSkeleton) {
@@ -560,7 +792,39 @@ function createSVGRenderer(options) {
560
792
  },
561
793
  seekWithTrail(t) {
562
794
  engine.seekWithTrail(t);
563
- }
795
+ },
796
+ morphTo(target, options2) {
797
+ if (morphResolve !== null) {
798
+ engine.completeMorph();
799
+ morphResolve();
800
+ morphResolve = null;
801
+ morphAlpha = 0;
802
+ skeletonPathA.setAttribute("visibility", "hidden");
803
+ skeletonPathB.setAttribute("visibility", "hidden");
804
+ }
805
+ morphDurationMs = options2?.duration ?? DEFAULT_MORPH_DURATION_MS2;
806
+ morphTarget = target;
807
+ morphAlpha = 0;
808
+ const currentSkeleton = engine.getSarmalSkeleton();
809
+ if (currentSkeleton.length >= 2) {
810
+ const px2 = (p) => (p.x * scale + offsetX).toFixed(2);
811
+ const py2 = (p) => (p.y * scale + offsetY).toFixed(2);
812
+ morphPathABuilt = `M${px2(currentSkeleton[0])} ${py2(currentSkeleton[0])}`;
813
+ for (let i = 1; i < currentSkeleton.length; i++) {
814
+ morphPathABuilt += ` L${px2(currentSkeleton[i])} ${py2(currentSkeleton[i])}`;
815
+ }
816
+ morphPathABuilt += " Z";
817
+ } else {
818
+ morphPathABuilt = "";
819
+ }
820
+ engine.startMorph(target, options2?.morphStrategy);
821
+ if (morphTarget) {
822
+ morphPathBBuilt = buildSkeletonPath(morphTarget, scale, offsetX, offsetY);
823
+ }
824
+ return new Promise((resolve) => {
825
+ morphResolve = resolve;
826
+ });
827
+ },
564
828
  };
565
829
  }
566
830
  function createSarmalSVG(container, curveDef, options) {
@@ -572,26 +836,29 @@ function createSarmalSVG(container, curveDef, options) {
572
836
  // src/curves.ts
573
837
  var TWO_PI2 = Math.PI * 2;
574
838
  function artemis2(t, _time, _params) {
575
- const a = 0.35, b = 0.15, ox = 0.175;
576
- const s = Math.sin(t), c = Math.cos(t);
839
+ const a = 0.35,
840
+ b = 0.15,
841
+ ox = 0.175;
842
+ const s = Math.sin(t),
843
+ c = Math.cos(t);
577
844
  const denom = 1 + s * s;
578
845
  return {
579
- x: c * (1 + a * c) / denom - ox,
580
- y: s * c * (1 + b * c) / denom
846
+ x: (c * (1 + a * c)) / denom - ox,
847
+ y: (s * c * (1 + b * c)) / denom,
581
848
  };
582
849
  }
583
850
  function epitrochoid7(t, _time, _params) {
584
851
  const d = 1 + 0.55 * Math.sin(t * 0.5);
585
852
  return {
586
853
  x: 7 * Math.cos(t) - d * Math.cos(7 * t),
587
- y: 7 * Math.sin(t) - d * Math.sin(7 * t)
854
+ y: 7 * Math.sin(t) - d * Math.sin(7 * t),
588
855
  };
589
856
  }
590
857
  function epitrochoid7Skeleton(t) {
591
858
  const d = 1.275;
592
859
  return {
593
860
  x: 7 * Math.cos(t) - d * Math.cos(7 * t),
594
- y: 7 * Math.sin(t) - d * Math.sin(7 * t)
861
+ y: 7 * Math.sin(t) - d * Math.sin(7 * t),
595
862
  };
596
863
  }
597
864
  function astroid(t, _time, _params) {
@@ -599,55 +866,56 @@ function astroid(t, _time, _params) {
599
866
  const s = Math.sin(t);
600
867
  return {
601
868
  x: c * c * c,
602
- y: s * s * s
869
+ y: s * s * s,
603
870
  };
604
871
  }
605
872
  function deltoid(t, _time, _params) {
606
873
  return {
607
874
  x: 2 * Math.cos(t) + Math.cos(2 * t),
608
- y: 2 * Math.sin(t) - Math.sin(2 * t)
875
+ y: 2 * Math.sin(t) - Math.sin(2 * t),
609
876
  };
610
877
  }
611
878
  function rose5(t, _time, _params) {
612
879
  const r = Math.cos(5 * t);
613
880
  return {
614
881
  x: r * Math.cos(t),
615
- y: r * Math.sin(t)
882
+ y: r * Math.sin(t),
616
883
  };
617
884
  }
618
885
  function rose3(t, _time, _params) {
619
886
  const r = Math.cos(3 * t);
620
887
  return {
621
888
  x: r * Math.cos(t),
622
- y: r * Math.sin(t)
889
+ y: r * Math.sin(t),
623
890
  };
624
891
  }
625
892
  function lissajous32(t, time, _params) {
626
893
  const phi = time * 0.45;
627
894
  return {
628
895
  x: Math.sin(3 * t + phi),
629
- y: Math.sin(2 * t)
896
+ y: Math.sin(2 * t),
630
897
  };
631
898
  }
632
899
  function lissajous43(t, time, _params) {
633
900
  const phi = time * 0.38;
634
901
  return {
635
902
  x: Math.sin(4 * t + phi),
636
- y: Math.sin(3 * t)
903
+ y: Math.sin(3 * t),
637
904
  };
638
905
  }
639
906
  function epicycloid3(t, _time, _params) {
640
907
  return {
641
908
  x: 4 * Math.cos(t) - Math.cos(4 * t),
642
- y: 4 * Math.sin(t) - Math.sin(4 * t)
909
+ y: 4 * Math.sin(t) - Math.sin(4 * t),
643
910
  };
644
911
  }
645
912
  function lame(t, time, _params) {
646
913
  const p = 1.75 + 1.25 * Math.sin(time * 0.48);
647
- const c = Math.cos(t), s = Math.sin(t);
914
+ const c = Math.cos(t),
915
+ s = Math.sin(t);
648
916
  return {
649
917
  x: Math.sign(c) * Math.pow(Math.abs(c), p),
650
- y: Math.sign(s) * Math.pow(Math.abs(s), p)
918
+ y: Math.sign(s) * Math.pow(Math.abs(s), p),
651
919
  };
652
920
  }
653
921
  var curves = {
@@ -655,66 +923,66 @@ var curves = {
655
923
  name: "Artemis II",
656
924
  fn: artemis2,
657
925
  period: TWO_PI2,
658
- speed: 0.7
926
+ speed: 0.7,
659
927
  },
660
928
  epitrochoid7: {
661
929
  name: "Epitrochoid",
662
930
  fn: epitrochoid7,
663
931
  period: TWO_PI2,
664
932
  speed: 1.4,
665
- skeletonFn: epitrochoid7Skeleton
933
+ skeletonFn: epitrochoid7Skeleton,
666
934
  },
667
935
  astroid: {
668
936
  name: "Astroid",
669
937
  fn: astroid,
670
938
  period: TWO_PI2,
671
- speed: 1.1
939
+ speed: 1.1,
672
940
  },
673
941
  deltoid: {
674
942
  name: "Deltoid",
675
943
  fn: deltoid,
676
944
  period: TWO_PI2,
677
- speed: 0.9
945
+ speed: 0.9,
678
946
  },
679
947
  rose5: {
680
948
  name: "Rose (n=5)",
681
949
  fn: rose5,
682
950
  period: TWO_PI2,
683
- speed: 1
951
+ speed: 1,
684
952
  },
685
953
  rose3: {
686
954
  name: "Rose (n=3)",
687
955
  fn: rose3,
688
956
  period: TWO_PI2,
689
- speed: 1.15
957
+ speed: 1.15,
690
958
  },
691
959
  lissajous32: {
692
960
  name: "Lissajous 3:2",
693
961
  fn: lissajous32,
694
962
  period: TWO_PI2,
695
963
  speed: 2,
696
- skeleton: "live"
964
+ skeleton: "live",
697
965
  },
698
966
  lissajous43: {
699
967
  name: "Lissajous 4:3",
700
968
  fn: lissajous43,
701
969
  period: TWO_PI2,
702
970
  speed: 1.8,
703
- skeleton: "live"
971
+ skeleton: "live",
704
972
  },
705
973
  epicycloid3: {
706
974
  name: "Epicycloid (n=3)",
707
975
  fn: epicycloid3,
708
976
  period: TWO_PI2,
709
- speed: 0.75
977
+ speed: 0.75,
710
978
  },
711
979
  lame: {
712
980
  name: "Lam\xE9 Curve",
713
981
  fn: lame,
714
982
  period: TWO_PI2,
715
983
  speed: 1,
716
- skeleton: "live"
717
- }
984
+ skeleton: "live",
985
+ },
718
986
  };
719
987
 
720
988
  // src/index.ts
@@ -726,4 +994,4 @@ function createSarmal(canvas, curveDef, options) {
726
994
 
727
995
  export { createEngine, createRenderer, createSVGRenderer, createSarmal, createSarmalSVG, curves };
728
996
  //# sourceMappingURL=index.js.map
729
- //# sourceMappingURL=index.js.map
997
+ //# sourceMappingURL=index.js.map