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