@sarmal/core 0.6.0 → 0.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -49,7 +49,7 @@ function resolveCurve(curveDef) {
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
54
  }
55
55
  function createEngine(curveDef, trailLength = 120) {
@@ -75,7 +75,7 @@ function createEngine(curveDef, trailLength = 120) {
75
75
  actualTime += deltaTime;
76
76
  if (morphCurveB !== null && _morphAlpha !== null) {
77
77
  const a = curve.fn(t, actualTime, {});
78
- const tB = _morphStrategy === "normalized" ? (t / curve.period) * morphCurveB.period : t;
78
+ const tB = _morphStrategy === "normalized" ? t / curve.period * morphCurveB.period : t;
79
79
  const b = morphCurveB.fn(tB, actualTime, {});
80
80
  trail.push(a.x + (b.x - a.x) * _morphAlpha, a.y + (b.y - a.y) * _morphAlpha);
81
81
  } else {
@@ -99,14 +99,14 @@ function createEngine(curveDef, trailLength = 120) {
99
99
  trail.clear();
100
100
  },
101
101
  seek(newT, { clearTrail = false } = {}) {
102
- t = ((newT % curve.period) + curve.period) % curve.period;
102
+ t = (newT % curve.period + curve.period) % curve.period;
103
103
  if (clearTrail) {
104
104
  trail.clear();
105
105
  }
106
106
  },
107
107
  seekWithTrail(targetT, { wrap = false, step = curve.period / trailLength } = {}) {
108
108
  const advance = curve.speed * step;
109
- const target = ((targetT % curve.period) + curve.period) % curve.period;
109
+ const target = (targetT % curve.period + curve.period) % curve.period;
110
110
  const targetTime = target / curve.speed;
111
111
  t = target;
112
112
  actualTime = targetTime;
@@ -132,16 +132,13 @@ function createEngine(curveDef, trailLength = 120) {
132
132
  ...frozenB,
133
133
  fn: (sampleT, time, params) => {
134
134
  const a = frozenA.fn(sampleT, time, params);
135
- const tB =
136
- frozenStrategy === "normalized"
137
- ? (sampleT / frozenA.period) * frozenB.period
138
- : sampleT;
135
+ const tB = frozenStrategy === "normalized" ? sampleT / frozenA.period * frozenB.period : sampleT;
139
136
  const b = frozenB.fn(tB, time, params);
140
137
  return {
141
138
  x: a.x + (b.x - a.x) * frozenAlpha,
142
- y: a.y + (b.y - a.y) * frozenAlpha,
139
+ y: a.y + (b.y - a.y) * frozenAlpha
143
140
  };
144
- },
141
+ }
145
142
  };
146
143
  }
147
144
  _morphStrategy = strategy;
@@ -153,6 +150,9 @@ function createEngine(curveDef, trailLength = 120) {
153
150
  },
154
151
  completeMorph() {
155
152
  if (morphCurveB !== null) {
153
+ if (_morphStrategy === "normalized" && curve.period !== morphCurveB.period) {
154
+ t = t / curve.period * morphCurveB.period;
155
+ }
156
156
  curve = morphCurveB;
157
157
  }
158
158
  morphCurveB = null;
@@ -163,26 +163,23 @@ function createEngine(curveDef, trailLength = 120) {
163
163
  const points = new Array(steps);
164
164
  if (morphCurveB !== null && _morphAlpha !== null) {
165
165
  for (let i = 0; i < steps; i++) {
166
- const sampleT = (i / (steps - 1)) * curve.period;
166
+ const sampleT = i / (steps - 1) * curve.period;
167
167
  const a = sampleSkeleton(curve, sampleT);
168
- const tB =
169
- _morphStrategy === "normalized"
170
- ? (sampleT / curve.period) * morphCurveB.period
171
- : sampleT;
168
+ const tB = _morphStrategy === "normalized" ? sampleT / curve.period * morphCurveB.period : sampleT;
172
169
  const b = sampleSkeleton(morphCurveB, tB);
173
170
  points[i] = {
174
171
  x: a.x + (b.x - a.x) * _morphAlpha,
175
- y: a.y + (b.y - a.y) * _morphAlpha,
172
+ y: a.y + (b.y - a.y) * _morphAlpha
176
173
  };
177
174
  }
178
175
  return points;
179
176
  }
180
177
  for (let i = 0; i < steps; i++) {
181
- const sampleT = (i / (steps - 1)) * curve.period;
178
+ const sampleT = i / (steps - 1) * curve.period;
182
179
  points[i] = sampleSkeleton(curve, sampleT);
183
180
  }
184
181
  return points;
185
- },
182
+ }
186
183
  };
187
184
  }
188
185
 
@@ -202,7 +199,7 @@ var GLOW_INNER_EDGE = 0.4;
202
199
  var GLOW_FALLOFF_OPACITY = 0.53;
203
200
  function hexToRgbComponents(hex) {
204
201
  const n = parseInt(hex.slice(1), 16);
205
- return `${n >> 16},${(n >> 8) & 255},${n & 255}`;
202
+ return `${n >> 16},${n >> 8 & 255},${n & 255}`;
206
203
  }
207
204
  function createRenderer(options) {
208
205
  const canvas = options.canvas;
@@ -216,7 +213,7 @@ function createRenderer(options) {
216
213
  trailColor: options.trailColor ?? "#ffffff",
217
214
  headColor: options.headColor ?? "#ffffff",
218
215
  headRadius: options.headRadius ?? DEFAULT_HEAD_RADIUS,
219
- glowSize: options.glowSize ?? DEFAULT_GLOW_SIZE,
216
+ glowSize: options.glowSize ?? DEFAULT_GLOW_SIZE
220
217
  };
221
218
  const trailRgb = hexToRgbComponents(opts.trailColor);
222
219
  const headRgbFalloff = `rgba(${hexToRgbComponents(opts.headColor)},${GLOW_FALLOFF_OPACITY})`;
@@ -232,32 +229,16 @@ function createRenderer(options) {
232
229
  let lastTime = 0;
233
230
  let morphResolve = null;
234
231
  let morphDurationMs = DEFAULT_MORPH_DURATION_MS;
235
- let morphTarget = null;
236
232
  let morphAlpha = 0;
237
- let skeletonCanvasA = null;
238
- let skeletonCanvasB = null;
239
- function calculateBoundaries() {
240
- if (skeleton.length === 0) {
241
- return;
242
- }
243
- const first = skeleton[0];
244
- let minX = first.x,
245
- maxX = first.x,
246
- minY = first.y,
247
- maxY = first.y;
248
- for (const p of skeleton) {
249
- if (p.x < minX) {
250
- minX = p.x;
251
- }
252
- if (p.x > maxX) {
253
- maxX = p.x;
254
- }
255
- if (p.y < minY) {
256
- minY = p.y;
257
- }
258
- if (p.y > maxY) {
259
- maxY = p.y;
260
- }
233
+ function computeBoundaries(pts) {
234
+ if (pts.length === 0) return null;
235
+ const first = pts[0];
236
+ let minX = first.x, maxX = first.x, minY = first.y, maxY = first.y;
237
+ for (const p of pts) {
238
+ if (p.x < minX) minX = p.x;
239
+ if (p.x > maxX) maxX = p.x;
240
+ if (p.y < minY) minY = p.y;
241
+ if (p.y > maxY) maxY = p.y;
261
242
  }
262
243
  const width = maxX - minX;
263
244
  const height = maxY - minY;
@@ -265,11 +246,22 @@ function createRenderer(options) {
265
246
  const canvasHeight = canvas.height;
266
247
  const scaleX = canvasWidth / (width * (1 + FIT_PADDING * 2));
267
248
  const scaleY = canvasHeight / (height * (1 + FIT_PADDING * 2));
268
- scale = Math.min(scaleX, scaleY);
269
- const boundsWidth = width * scale;
270
- const boundsHeight = height * scale;
271
- offsetX = (canvasWidth - boundsWidth) / 2 - minX * scale;
272
- offsetY = (canvasHeight - boundsHeight) / 2 - minY * scale;
249
+ const s = Math.min(scaleX, scaleY);
250
+ const boundsWidth = width * s;
251
+ const boundsHeight = height * s;
252
+ return {
253
+ scale: s,
254
+ offsetX: (canvasWidth - boundsWidth) / 2 - minX * s,
255
+ offsetY: (canvasHeight - boundsHeight) / 2 - minY * s
256
+ };
257
+ }
258
+ function calculateBoundaries() {
259
+ const b = computeBoundaries(skeleton);
260
+ if (b) {
261
+ scale = b.scale;
262
+ offsetX = b.offsetX;
263
+ offsetY = b.offsetY;
264
+ }
273
265
  }
274
266
  function buildSkeletonCanvas() {
275
267
  if (skeleton.length < 2) return;
@@ -286,20 +278,23 @@ function createRenderer(options) {
286
278
  }
287
279
  skeletonCtx.stroke();
288
280
  }
281
+ function drawSkeletonPath(pts, opacity) {
282
+ if (pts.length < 2) return;
283
+ ctx.strokeStyle = `rgba(${hexToRgbComponents(opts.skeletonColor)},${opacity})`;
284
+ ctx.lineWidth = 1.5;
285
+ ctx.beginPath();
286
+ ctx.moveTo(pts[0].x * scale + offsetX, pts[0].y * scale + offsetY);
287
+ for (let i = 1; i < pts.length; i++) {
288
+ ctx.lineTo(pts[i].x * scale + offsetX, pts[i].y * scale + offsetY);
289
+ }
290
+ ctx.stroke();
291
+ }
289
292
  function drawSkeleton() {
290
293
  if (opts.skeletonColor === "transparent") {
291
294
  return;
292
295
  }
293
296
  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;
297
+ drawSkeletonPath(engine.getSarmalSkeleton(), DEFAULT_SKELETON_OPACITY);
303
298
  return;
304
299
  }
305
300
  if (engine.isLiveSkeleton) {
@@ -371,23 +366,29 @@ function createRenderer(options) {
371
366
  if (engine.morphAlpha !== null) {
372
367
  morphAlpha = Math.min(1, morphAlpha + deltaTime / (morphDurationMs / 1e3));
373
368
  engine.setMorphAlpha(morphAlpha);
374
- skeleton = engine.getSarmalSkeleton();
375
- calculateBoundaries();
369
+ const interpolatedSkeleton = engine.getSarmalSkeleton();
370
+ const bounds = computeBoundaries(interpolatedSkeleton);
371
+ if (bounds) {
372
+ scale = bounds.scale;
373
+ offsetX = bounds.offsetX;
374
+ offsetY = bounds.offsetY;
375
+ }
376
376
  if (morphAlpha >= 1) {
377
377
  engine.completeMorph();
378
378
  morphResolve?.();
379
379
  morphResolve = null;
380
- morphTarget = null;
381
380
  morphAlpha = 0;
382
- skeletonCanvasA = null;
383
- skeletonCanvasB = null;
381
+ skeleton = engine.getSarmalSkeleton();
382
+ if (!engine.isLiveSkeleton) {
383
+ buildSkeletonCanvas();
384
+ }
384
385
  }
385
386
  }
386
387
  trail = engine.tick(deltaTime);
387
388
  trailCount = engine.trailCount;
388
389
  head = trailCount > 0 ? trail[trailCount - 1] : null;
389
390
  ctx.clearRect(0, 0, canvas.width, canvas.height);
390
- if (engine.isLiveSkeleton || engine.morphAlpha !== null) {
391
+ if (engine.isLiveSkeleton && engine.morphAlpha === null) {
391
392
  skeleton = engine.getSarmalSkeleton();
392
393
  calculateBoundaries();
393
394
  }
@@ -439,49 +440,14 @@ function createRenderer(options) {
439
440
  morphResolve();
440
441
  morphResolve = null;
441
442
  morphAlpha = 0;
442
- skeletonCanvasA = null;
443
- skeletonCanvasB = null;
444
443
  }
445
444
  morphDurationMs = options2?.duration ?? DEFAULT_MORPH_DURATION_MS;
446
- morphTarget = target;
447
445
  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
446
  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
447
  return new Promise((resolve) => {
482
448
  morphResolve = resolve;
483
449
  });
484
- },
450
+ }
485
451
  };
486
452
  }
487
453
 
@@ -508,7 +474,7 @@ function createSVGRenderer(options) {
508
474
  headColor: options.headColor ?? "#ffffff",
509
475
  headRadius: options.headRadius ?? 4,
510
476
  glowSize: options.glowSize ?? 20,
511
- ariaLabel: options.ariaLabel ?? "Loading",
477
+ ariaLabel: options.ariaLabel ?? "Loading"
512
478
  };
513
479
  const uid = ++instanceCount;
514
480
  const gradientId = `sarmal-glow-${uid}`;
@@ -592,10 +558,7 @@ function createSVGRenderer(options) {
592
558
  return;
593
559
  }
594
560
  const first = skeleton2[0];
595
- let minX = first.x,
596
- maxX = first.x,
597
- minY = first.y,
598
- maxY = first.y;
561
+ let minX = first.x, maxX = first.x, minY = first.y, maxY = first.y;
599
562
  for (const p of skeleton2) {
600
563
  if (p.x < minX) {
601
564
  minX = p.x;
@@ -682,8 +645,7 @@ function createSVGRenderer(options) {
682
645
  }
683
646
  let animationId = null;
684
647
  let lastTime = 0;
685
- const prefersReducedMotion =
686
- typeof window !== "undefined" && window.matchMedia("(prefers-reduced-motion: reduce)").matches;
648
+ const prefersReducedMotion = typeof window !== "undefined" && window.matchMedia("(prefers-reduced-motion: reduce)").matches;
687
649
  let morphResolve = null;
688
650
  let morphDurationMs = DEFAULT_MORPH_DURATION_MS2;
689
651
  let morphTarget = null;
@@ -693,7 +655,7 @@ function createSVGRenderer(options) {
693
655
  const samples = Math.max(50, Math.round(period * 20));
694
656
  const points = [];
695
657
  for (let i = 0; i <= samples; i++) {
696
- const t = (i / samples) * period;
658
+ const t = i / samples * period;
697
659
  const p = target.fn(t, 0, {});
698
660
  points.push(p);
699
661
  }
@@ -716,26 +678,18 @@ function createSVGRenderer(options) {
716
678
  if (engine.morphAlpha !== null) {
717
679
  morphAlpha = Math.min(1, morphAlpha + dt / (morphDurationMs / 1e3));
718
680
  engine.setMorphAlpha(morphAlpha);
719
- const morphSkeleton = engine.getSarmalSkeleton();
720
- calculateBoundaries(morphSkeleton);
721
- if (!engine.isLiveSkeleton) {
722
- updateSkeleton(morphSkeleton);
723
- }
724
681
  if (morphPathABuilt) {
725
682
  skeletonPathA.setAttribute("d", morphPathABuilt);
726
683
  skeletonPathA.setAttribute("visibility", "visible");
727
684
  skeletonPathA.setAttribute(
728
685
  "stroke-opacity",
729
- String((1 - morphAlpha) * DEFAULT_SKELETON_OPACITY2),
686
+ String((1 - morphAlpha) * DEFAULT_SKELETON_OPACITY2)
730
687
  );
731
688
  }
732
689
  if (morphPathBBuilt) {
733
690
  skeletonPathB.setAttribute("d", morphPathBBuilt);
734
691
  skeletonPathB.setAttribute("visibility", "visible");
735
- skeletonPathB.setAttribute(
736
- "stroke-opacity",
737
- String(morphAlpha * DEFAULT_SKELETON_OPACITY2),
738
- );
692
+ skeletonPathB.setAttribute("stroke-opacity", String(morphAlpha * DEFAULT_SKELETON_OPACITY2));
739
693
  }
740
694
  if (morphAlpha >= 1) {
741
695
  engine.completeMorph();
@@ -747,11 +701,14 @@ function createSVGRenderer(options) {
747
701
  morphPathBBuilt = "";
748
702
  skeletonPathA.setAttribute("visibility", "hidden");
749
703
  skeletonPathB.setAttribute("visibility", "hidden");
704
+ const newSkeleton = engine.getSarmalSkeleton();
705
+ calculateBoundaries(newSkeleton);
706
+ updateSkeleton(newSkeleton);
750
707
  }
751
708
  }
752
709
  const trail = engine.tick(dt);
753
710
  const trailCount = engine.trailCount;
754
- if (engine.isLiveSkeleton) {
711
+ if (engine.isLiveSkeleton && engine.morphAlpha === null) {
755
712
  const liveSkeleton = engine.getSarmalSkeleton();
756
713
  calculateBoundaries(liveSkeleton);
757
714
  updateSkeleton(liveSkeleton);
@@ -824,7 +781,7 @@ function createSVGRenderer(options) {
824
781
  return new Promise((resolve) => {
825
782
  morphResolve = resolve;
826
783
  });
827
- },
784
+ }
828
785
  };
829
786
  }
830
787
  function createSarmalSVG(container, curveDef, options) {
@@ -836,29 +793,26 @@ function createSarmalSVG(container, curveDef, options) {
836
793
  // src/curves.ts
837
794
  var TWO_PI2 = Math.PI * 2;
838
795
  function artemis2(t, _time, _params) {
839
- const a = 0.35,
840
- b = 0.15,
841
- ox = 0.175;
842
- const s = Math.sin(t),
843
- c = Math.cos(t);
796
+ const a = 0.35, b = 0.15, ox = 0.175;
797
+ const s = Math.sin(t), c = Math.cos(t);
844
798
  const denom = 1 + s * s;
845
799
  return {
846
- x: (c * (1 + a * c)) / denom - ox,
847
- y: (s * c * (1 + b * c)) / denom,
800
+ x: c * (1 + a * c) / denom - ox,
801
+ y: s * c * (1 + b * c) / denom
848
802
  };
849
803
  }
850
804
  function epitrochoid7(t, _time, _params) {
851
805
  const d = 1 + 0.55 * Math.sin(t * 0.5);
852
806
  return {
853
807
  x: 7 * Math.cos(t) - d * Math.cos(7 * t),
854
- y: 7 * Math.sin(t) - d * Math.sin(7 * t),
808
+ y: 7 * Math.sin(t) - d * Math.sin(7 * t)
855
809
  };
856
810
  }
857
811
  function epitrochoid7Skeleton(t) {
858
812
  const d = 1.275;
859
813
  return {
860
814
  x: 7 * Math.cos(t) - d * Math.cos(7 * t),
861
- y: 7 * Math.sin(t) - d * Math.sin(7 * t),
815
+ y: 7 * Math.sin(t) - d * Math.sin(7 * t)
862
816
  };
863
817
  }
864
818
  function astroid(t, _time, _params) {
@@ -866,56 +820,55 @@ function astroid(t, _time, _params) {
866
820
  const s = Math.sin(t);
867
821
  return {
868
822
  x: c * c * c,
869
- y: s * s * s,
823
+ y: s * s * s
870
824
  };
871
825
  }
872
826
  function deltoid(t, _time, _params) {
873
827
  return {
874
828
  x: 2 * Math.cos(t) + Math.cos(2 * t),
875
- y: 2 * Math.sin(t) - Math.sin(2 * t),
829
+ y: 2 * Math.sin(t) - Math.sin(2 * t)
876
830
  };
877
831
  }
878
832
  function rose5(t, _time, _params) {
879
833
  const r = Math.cos(5 * t);
880
834
  return {
881
835
  x: r * Math.cos(t),
882
- y: r * Math.sin(t),
836
+ y: r * Math.sin(t)
883
837
  };
884
838
  }
885
839
  function rose3(t, _time, _params) {
886
840
  const r = Math.cos(3 * t);
887
841
  return {
888
842
  x: r * Math.cos(t),
889
- y: r * Math.sin(t),
843
+ y: r * Math.sin(t)
890
844
  };
891
845
  }
892
846
  function lissajous32(t, time, _params) {
893
847
  const phi = time * 0.45;
894
848
  return {
895
849
  x: Math.sin(3 * t + phi),
896
- y: Math.sin(2 * t),
850
+ y: Math.sin(2 * t)
897
851
  };
898
852
  }
899
853
  function lissajous43(t, time, _params) {
900
854
  const phi = time * 0.38;
901
855
  return {
902
856
  x: Math.sin(4 * t + phi),
903
- y: Math.sin(3 * t),
857
+ y: Math.sin(3 * t)
904
858
  };
905
859
  }
906
860
  function epicycloid3(t, _time, _params) {
907
861
  return {
908
862
  x: 4 * Math.cos(t) - Math.cos(4 * t),
909
- y: 4 * Math.sin(t) - Math.sin(4 * t),
863
+ y: 4 * Math.sin(t) - Math.sin(4 * t)
910
864
  };
911
865
  }
912
866
  function lame(t, time, _params) {
913
867
  const p = 1.75 + 1.25 * Math.sin(time * 0.48);
914
- const c = Math.cos(t),
915
- s = Math.sin(t);
868
+ const c = Math.cos(t), s = Math.sin(t);
916
869
  return {
917
870
  x: Math.sign(c) * Math.pow(Math.abs(c), p),
918
- y: Math.sign(s) * Math.pow(Math.abs(s), p),
871
+ y: Math.sign(s) * Math.pow(Math.abs(s), p)
919
872
  };
920
873
  }
921
874
  var curves = {
@@ -923,66 +876,66 @@ var curves = {
923
876
  name: "Artemis II",
924
877
  fn: artemis2,
925
878
  period: TWO_PI2,
926
- speed: 0.7,
879
+ speed: 0.7
927
880
  },
928
881
  epitrochoid7: {
929
882
  name: "Epitrochoid",
930
883
  fn: epitrochoid7,
931
884
  period: TWO_PI2,
932
885
  speed: 1.4,
933
- skeletonFn: epitrochoid7Skeleton,
886
+ skeletonFn: epitrochoid7Skeleton
934
887
  },
935
888
  astroid: {
936
889
  name: "Astroid",
937
890
  fn: astroid,
938
891
  period: TWO_PI2,
939
- speed: 1.1,
892
+ speed: 1.1
940
893
  },
941
894
  deltoid: {
942
895
  name: "Deltoid",
943
896
  fn: deltoid,
944
897
  period: TWO_PI2,
945
- speed: 0.9,
898
+ speed: 0.9
946
899
  },
947
900
  rose5: {
948
901
  name: "Rose (n=5)",
949
902
  fn: rose5,
950
903
  period: TWO_PI2,
951
- speed: 1,
904
+ speed: 1
952
905
  },
953
906
  rose3: {
954
907
  name: "Rose (n=3)",
955
908
  fn: rose3,
956
909
  period: TWO_PI2,
957
- speed: 1.15,
910
+ speed: 1.15
958
911
  },
959
912
  lissajous32: {
960
913
  name: "Lissajous 3:2",
961
914
  fn: lissajous32,
962
915
  period: TWO_PI2,
963
916
  speed: 2,
964
- skeleton: "live",
917
+ skeleton: "live"
965
918
  },
966
919
  lissajous43: {
967
920
  name: "Lissajous 4:3",
968
921
  fn: lissajous43,
969
922
  period: TWO_PI2,
970
923
  speed: 1.8,
971
- skeleton: "live",
924
+ skeleton: "live"
972
925
  },
973
926
  epicycloid3: {
974
927
  name: "Epicycloid (n=3)",
975
928
  fn: epicycloid3,
976
929
  period: TWO_PI2,
977
- speed: 0.75,
930
+ speed: 0.75
978
931
  },
979
932
  lame: {
980
933
  name: "Lam\xE9 Curve",
981
934
  fn: lame,
982
935
  period: TWO_PI2,
983
936
  speed: 1,
984
- skeleton: "live",
985
- },
937
+ skeleton: "live"
938
+ }
986
939
  };
987
940
 
988
941
  // src/index.ts
@@ -994,4 +947,4 @@ function createSarmal(canvas, curveDef, options) {
994
947
 
995
948
  export { createEngine, createRenderer, createSVGRenderer, createSarmal, createSarmalSVG, curves };
996
949
  //# sourceMappingURL=index.js.map
997
- //# sourceMappingURL=index.js.map
950
+ //# sourceMappingURL=index.js.map