@sarmal/core 0.4.0 → 0.4.2
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/README.md +1 -1
- package/dist/auto-init.cjs +55 -49
- package/dist/auto-init.cjs.map +1 -1
- package/dist/auto-init.d.cts +1 -2
- package/dist/auto-init.d.ts +1 -2
- package/dist/auto-init.js +54 -48
- package/dist/auto-init.js.map +1 -1
- package/dist/index.cjs +57 -47
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +160 -129
- package/dist/index.d.ts +160 -129
- package/dist/index.js +56 -46
- package/dist/index.js.map +1 -1
- package/package.json +6 -3
package/dist/index.cjs
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
"use strict";
|
|
2
2
|
|
|
3
3
|
// src/engine.ts
|
|
4
4
|
var TWO_PI = Math.PI * 2;
|
|
@@ -49,7 +49,7 @@ function createEngine(curveDef, trailLength = 120) {
|
|
|
49
49
|
name: curveDef.name,
|
|
50
50
|
fn: curveDef.fn,
|
|
51
51
|
period: curveDef.period ?? TWO_PI,
|
|
52
|
-
speed: curveDef.speed ?? 1
|
|
52
|
+
speed: curveDef.speed ?? 1,
|
|
53
53
|
};
|
|
54
54
|
const trail = new CircularBuffer(trailLength);
|
|
55
55
|
let t = 0;
|
|
@@ -71,25 +71,24 @@ function createEngine(curveDef, trailLength = 120) {
|
|
|
71
71
|
trail.clear();
|
|
72
72
|
},
|
|
73
73
|
seek(newT, { clearTrail = false } = {}) {
|
|
74
|
-
t = (newT % curve.period + curve.period) % curve.period;
|
|
74
|
+
t = ((newT % curve.period) + curve.period) % curve.period;
|
|
75
75
|
if (clearTrail) {
|
|
76
76
|
trail.clear();
|
|
77
77
|
}
|
|
78
78
|
},
|
|
79
|
-
seekWithTrail(targetT, { wrap = false } = {}) {
|
|
80
|
-
const
|
|
81
|
-
const
|
|
82
|
-
const target = (targetT % curve.period + curve.period) % curve.period;
|
|
79
|
+
seekWithTrail(targetT, { wrap = false, step = curve.period / trailLength } = {}) {
|
|
80
|
+
const advance = curve.speed * step;
|
|
81
|
+
const target = ((targetT % curve.period) + curve.period) % curve.period;
|
|
83
82
|
const targetTime = target / curve.speed;
|
|
84
83
|
t = target;
|
|
85
84
|
actualTime = targetTime;
|
|
86
85
|
trail.clear();
|
|
87
86
|
const pointsFromStart = Math.floor(target / advance) + 1;
|
|
88
87
|
const count = wrap ? trailLength : Math.min(trailLength, pointsFromStart);
|
|
89
|
-
for (let
|
|
90
|
-
const sampleT = target -
|
|
88
|
+
for (let i = count - 1; i >= 0; i--) {
|
|
89
|
+
const sampleT = target - i * advance;
|
|
91
90
|
const wrappedT = sampleT < 0 ? sampleT + curve.period : sampleT;
|
|
92
|
-
const time = targetTime -
|
|
91
|
+
const time = targetTime - i * step;
|
|
93
92
|
const point = curve.fn(wrappedT, time, {});
|
|
94
93
|
trail.push(point.x, point.y);
|
|
95
94
|
}
|
|
@@ -98,12 +97,12 @@ function createEngine(curveDef, trailLength = 120) {
|
|
|
98
97
|
const steps = Math.ceil(curve.period * POINTS_PER_PERIOD_UNIT);
|
|
99
98
|
const points = new Array(steps);
|
|
100
99
|
for (let i = 0; i < steps; i++) {
|
|
101
|
-
const sampleT = i / (steps - 1) * curve.period;
|
|
100
|
+
const sampleT = (i / (steps - 1)) * curve.period;
|
|
102
101
|
const point = curve.fn(sampleT, 0, {});
|
|
103
102
|
points[i] = point;
|
|
104
103
|
}
|
|
105
104
|
return points;
|
|
106
|
-
}
|
|
105
|
+
},
|
|
107
106
|
};
|
|
108
107
|
}
|
|
109
108
|
|
|
@@ -122,7 +121,7 @@ var GLOW_INNER_EDGE = 0.4;
|
|
|
122
121
|
var GLOW_FALLOFF_OPACITY = 0.53;
|
|
123
122
|
function hexToRgbComponents(hex) {
|
|
124
123
|
const n = parseInt(hex.slice(1), 16);
|
|
125
|
-
return `${n >> 16},${n >> 8 & 255},${n & 255}`;
|
|
124
|
+
return `${n >> 16},${(n >> 8) & 255},${n & 255}`;
|
|
126
125
|
}
|
|
127
126
|
function createRenderer(options) {
|
|
128
127
|
const canvas = options.canvas;
|
|
@@ -136,7 +135,7 @@ function createRenderer(options) {
|
|
|
136
135
|
trailColor: options.trailColor ?? "#ffffff",
|
|
137
136
|
headColor: options.headColor ?? "#ffffff",
|
|
138
137
|
headRadius: options.headRadius ?? DEFAULT_HEAD_RADIUS,
|
|
139
|
-
glowSize: options.glowSize ?? DEFAULT_GLOW_SIZE
|
|
138
|
+
glowSize: options.glowSize ?? DEFAULT_GLOW_SIZE,
|
|
140
139
|
};
|
|
141
140
|
const trailRgb = hexToRgbComponents(opts.trailColor);
|
|
142
141
|
const headRgbFalloff = `rgba(${hexToRgbComponents(opts.headColor)},${GLOW_FALLOFF_OPACITY})`;
|
|
@@ -155,7 +154,10 @@ function createRenderer(options) {
|
|
|
155
154
|
return;
|
|
156
155
|
}
|
|
157
156
|
const first = skeleton[0];
|
|
158
|
-
let minX = first.x,
|
|
157
|
+
let minX = first.x,
|
|
158
|
+
maxX = first.x,
|
|
159
|
+
minY = first.y,
|
|
160
|
+
maxY = first.y;
|
|
159
161
|
for (const p of skeleton) {
|
|
160
162
|
if (p.x < minX) {
|
|
161
163
|
minX = p.x;
|
|
@@ -198,7 +200,7 @@ function createRenderer(options) {
|
|
|
198
200
|
skeletonCtx.stroke();
|
|
199
201
|
}
|
|
200
202
|
function drawSkeleton() {
|
|
201
|
-
if (!skeletonCanvas) {
|
|
203
|
+
if (!skeletonCanvas || opts.skeletonColor === "transparent") {
|
|
202
204
|
return;
|
|
203
205
|
}
|
|
204
206
|
ctx.drawImage(skeletonCanvas, 0, 0);
|
|
@@ -294,7 +296,7 @@ function createRenderer(options) {
|
|
|
294
296
|
},
|
|
295
297
|
seekWithTrail(t) {
|
|
296
298
|
engine.seekWithTrail(t);
|
|
297
|
-
}
|
|
299
|
+
},
|
|
298
300
|
};
|
|
299
301
|
}
|
|
300
302
|
|
|
@@ -320,7 +322,7 @@ function createSVGRenderer(options) {
|
|
|
320
322
|
headColor: options.headColor ?? "#ffffff",
|
|
321
323
|
headRadius: options.headRadius ?? 4,
|
|
322
324
|
glowSize: options.glowSize ?? 20,
|
|
323
|
-
ariaLabel: options.ariaLabel ?? "Loading"
|
|
325
|
+
ariaLabel: options.ariaLabel ?? "Loading",
|
|
324
326
|
};
|
|
325
327
|
const uid = ++instanceCount;
|
|
326
328
|
const gradientId = `sarmal-glow-${uid}`;
|
|
@@ -390,7 +392,10 @@ function createSVGRenderer(options) {
|
|
|
390
392
|
return;
|
|
391
393
|
}
|
|
392
394
|
const first = skeleton2[0];
|
|
393
|
-
let minX = first.x,
|
|
395
|
+
let minX = first.x,
|
|
396
|
+
maxX = first.x,
|
|
397
|
+
minY = first.y,
|
|
398
|
+
maxY = first.y;
|
|
394
399
|
for (const p of skeleton2) {
|
|
395
400
|
if (p.x < minX) {
|
|
396
401
|
minX = p.x;
|
|
@@ -470,7 +475,8 @@ function createSVGRenderer(options) {
|
|
|
470
475
|
}
|
|
471
476
|
let animationId = null;
|
|
472
477
|
let lastTime = 0;
|
|
473
|
-
const prefersReducedMotion =
|
|
478
|
+
const prefersReducedMotion =
|
|
479
|
+
typeof window !== "undefined" && window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
474
480
|
function renderFrame() {
|
|
475
481
|
const now = performance.now();
|
|
476
482
|
const dt = Math.min((now - lastTime) / 1e3, 1 / 30);
|
|
@@ -513,7 +519,7 @@ function createSVGRenderer(options) {
|
|
|
513
519
|
},
|
|
514
520
|
seekWithTrail(t) {
|
|
515
521
|
engine.seekWithTrail(t);
|
|
516
|
-
}
|
|
522
|
+
},
|
|
517
523
|
};
|
|
518
524
|
}
|
|
519
525
|
function createSarmalSVG(container, curveDef, options) {
|
|
@@ -525,19 +531,22 @@ function createSarmalSVG(container, curveDef, options) {
|
|
|
525
531
|
// src/curves.ts
|
|
526
532
|
var TWO_PI2 = Math.PI * 2;
|
|
527
533
|
function artemis2(t, _time, _params) {
|
|
528
|
-
const a = 0.35,
|
|
529
|
-
|
|
534
|
+
const a = 0.35,
|
|
535
|
+
b = 0.15,
|
|
536
|
+
ox = 0.175;
|
|
537
|
+
const s = Math.sin(t),
|
|
538
|
+
c = Math.cos(t);
|
|
530
539
|
const denom = 1 + s * s;
|
|
531
540
|
return {
|
|
532
|
-
x: c * (1 + a * c) / denom - ox,
|
|
533
|
-
y: s * c * (1 + b * c) / denom
|
|
541
|
+
x: (c * (1 + a * c)) / denom - ox,
|
|
542
|
+
y: (s * c * (1 + b * c)) / denom,
|
|
534
543
|
};
|
|
535
544
|
}
|
|
536
545
|
function epitrochoid7(t, _time, _params) {
|
|
537
546
|
const d = 1 + 0.55 * Math.sin(t * 0.5);
|
|
538
547
|
return {
|
|
539
548
|
x: 7 * Math.cos(t) - d * Math.cos(7 * t),
|
|
540
|
-
y: 7 * Math.sin(t) - d * Math.sin(7 * t)
|
|
549
|
+
y: 7 * Math.sin(t) - d * Math.sin(7 * t),
|
|
541
550
|
};
|
|
542
551
|
}
|
|
543
552
|
function astroid(t, _time, _params) {
|
|
@@ -545,55 +554,56 @@ function astroid(t, _time, _params) {
|
|
|
545
554
|
const s = Math.sin(t);
|
|
546
555
|
return {
|
|
547
556
|
x: c * c * c,
|
|
548
|
-
y: s * s * s
|
|
557
|
+
y: s * s * s,
|
|
549
558
|
};
|
|
550
559
|
}
|
|
551
560
|
function deltoid(t, _time, _params) {
|
|
552
561
|
return {
|
|
553
562
|
x: 2 * Math.cos(t) + Math.cos(2 * t),
|
|
554
|
-
y: 2 * Math.sin(t) - Math.sin(2 * t)
|
|
563
|
+
y: 2 * Math.sin(t) - Math.sin(2 * t),
|
|
555
564
|
};
|
|
556
565
|
}
|
|
557
566
|
function rose5(t, _time, _params) {
|
|
558
567
|
const r = Math.cos(5 * t);
|
|
559
568
|
return {
|
|
560
569
|
x: r * Math.cos(t),
|
|
561
|
-
y: r * Math.sin(t)
|
|
570
|
+
y: r * Math.sin(t),
|
|
562
571
|
};
|
|
563
572
|
}
|
|
564
573
|
function rose3(t, _time, _params) {
|
|
565
574
|
const r = Math.cos(3 * t);
|
|
566
575
|
return {
|
|
567
576
|
x: r * Math.cos(t),
|
|
568
|
-
y: r * Math.sin(t)
|
|
577
|
+
y: r * Math.sin(t),
|
|
569
578
|
};
|
|
570
579
|
}
|
|
571
580
|
function lissajous32(t, time, _params) {
|
|
572
581
|
const phi = time * 0.45;
|
|
573
582
|
return {
|
|
574
583
|
x: Math.sin(3 * t + phi),
|
|
575
|
-
y: Math.sin(2 * t)
|
|
584
|
+
y: Math.sin(2 * t),
|
|
576
585
|
};
|
|
577
586
|
}
|
|
578
587
|
function lissajous43(t, time, _params) {
|
|
579
588
|
const phi = time * 0.38;
|
|
580
589
|
return {
|
|
581
590
|
x: Math.sin(4 * t + phi),
|
|
582
|
-
y: Math.sin(3 * t)
|
|
591
|
+
y: Math.sin(3 * t),
|
|
583
592
|
};
|
|
584
593
|
}
|
|
585
594
|
function epicycloid3(t, _time, _params) {
|
|
586
595
|
return {
|
|
587
596
|
x: 4 * Math.cos(t) - Math.cos(4 * t),
|
|
588
|
-
y: 4 * Math.sin(t) - Math.sin(4 * t)
|
|
597
|
+
y: 4 * Math.sin(t) - Math.sin(4 * t),
|
|
589
598
|
};
|
|
590
599
|
}
|
|
591
600
|
function lame(t, time, _params) {
|
|
592
601
|
const p = 1.75 + 1.25 * Math.sin(time * 0.48);
|
|
593
|
-
const c = Math.cos(t),
|
|
602
|
+
const c = Math.cos(t),
|
|
603
|
+
s = Math.sin(t);
|
|
594
604
|
return {
|
|
595
605
|
x: Math.sign(c) * Math.pow(Math.abs(c), p),
|
|
596
|
-
y: Math.sign(s) * Math.pow(Math.abs(s), p)
|
|
606
|
+
y: Math.sign(s) * Math.pow(Math.abs(s), p),
|
|
597
607
|
};
|
|
598
608
|
}
|
|
599
609
|
var curves = {
|
|
@@ -601,62 +611,62 @@ var curves = {
|
|
|
601
611
|
name: "Artemis II",
|
|
602
612
|
fn: artemis2,
|
|
603
613
|
period: TWO_PI2,
|
|
604
|
-
speed: 0.7
|
|
614
|
+
speed: 0.7,
|
|
605
615
|
},
|
|
606
616
|
epitrochoid7: {
|
|
607
617
|
name: "Epitrochoid",
|
|
608
618
|
fn: epitrochoid7,
|
|
609
619
|
period: TWO_PI2,
|
|
610
|
-
speed: 1.4
|
|
620
|
+
speed: 1.4,
|
|
611
621
|
},
|
|
612
622
|
astroid: {
|
|
613
623
|
name: "Astroid",
|
|
614
624
|
fn: astroid,
|
|
615
625
|
period: TWO_PI2,
|
|
616
|
-
speed: 1.1
|
|
626
|
+
speed: 1.1,
|
|
617
627
|
},
|
|
618
628
|
deltoid: {
|
|
619
629
|
name: "Deltoid",
|
|
620
630
|
fn: deltoid,
|
|
621
631
|
period: TWO_PI2,
|
|
622
|
-
speed: 0.9
|
|
632
|
+
speed: 0.9,
|
|
623
633
|
},
|
|
624
634
|
rose5: {
|
|
625
635
|
name: "Rose (n=5)",
|
|
626
636
|
fn: rose5,
|
|
627
637
|
period: TWO_PI2,
|
|
628
|
-
speed: 1
|
|
638
|
+
speed: 1,
|
|
629
639
|
},
|
|
630
640
|
rose3: {
|
|
631
641
|
name: "Rose (n=3)",
|
|
632
642
|
fn: rose3,
|
|
633
643
|
period: TWO_PI2,
|
|
634
|
-
speed: 1.15
|
|
644
|
+
speed: 1.15,
|
|
635
645
|
},
|
|
636
646
|
lissajous32: {
|
|
637
647
|
name: "Lissajous 3:2",
|
|
638
648
|
fn: lissajous32,
|
|
639
649
|
period: TWO_PI2,
|
|
640
|
-
speed: 2
|
|
650
|
+
speed: 2,
|
|
641
651
|
},
|
|
642
652
|
lissajous43: {
|
|
643
653
|
name: "Lissajous 4:3",
|
|
644
654
|
fn: lissajous43,
|
|
645
655
|
period: TWO_PI2,
|
|
646
|
-
speed: 1.8
|
|
656
|
+
speed: 1.8,
|
|
647
657
|
},
|
|
648
658
|
epicycloid3: {
|
|
649
659
|
name: "Epicycloid (n=3)",
|
|
650
660
|
fn: epicycloid3,
|
|
651
661
|
period: TWO_PI2,
|
|
652
|
-
speed: 0.75
|
|
662
|
+
speed: 0.75,
|
|
653
663
|
},
|
|
654
664
|
lame: {
|
|
655
665
|
name: "Lam\xE9 Curve",
|
|
656
666
|
fn: lame,
|
|
657
667
|
period: TWO_PI2,
|
|
658
|
-
speed: 1
|
|
659
|
-
}
|
|
668
|
+
speed: 1,
|
|
669
|
+
},
|
|
660
670
|
};
|
|
661
671
|
|
|
662
672
|
// src/index.ts
|
|
@@ -673,4 +683,4 @@ exports.createSarmal = createSarmal;
|
|
|
673
683
|
exports.createSarmalSVG = createSarmalSVG;
|
|
674
684
|
exports.curves = curves;
|
|
675
685
|
//# sourceMappingURL=index.cjs.map
|
|
676
|
-
//# sourceMappingURL=index.cjs.map
|
|
686
|
+
//# sourceMappingURL=index.cjs.map
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/engine.ts","../src/renderer.ts","../src/renderer-svg.ts","../src/curves.ts","../src/index.ts"],"names":["options","TRAIL_FADE_CURVE","TRAIL_MAX_OPACITY","TRAIL_MIN_WIDTH","TRAIL_MAX_WIDTH","DEFAULT_SKELETON_OPACITY","FIT_PADDING","skeleton","TWO_PI"],"mappings":"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","file":"index.cjs","sourcesContent":["import type { CurveDef, Engine, Point, SeekOptions, SeekWithTrailOptions } from \"./types\";\n\nconst TWO_PI = Math.PI * 2;\nconst POINTS_PER_PERIOD_UNIT = 50;\n\n/**\n * A fixed-size list of points with first in, last out method\n * The oldest entry is automatically discarded when the list is at capacity\n *\n * Note: `result.length` is *never* changed,\n * so callers use the separate `count` getter to know valid size\n */\nclass CircularBuffer {\n private data: Array<Point>;\n private result: Array<Point>;\n private capacity: number;\n private head: number = 0;\n private count: number = 0;\n\n constructor(capacity: number) {\n this.capacity = capacity;\n this.data = Array.from({ length: capacity }, () => ({ x: 0, y: 0 }));\n this.result = Array.from({ length: capacity }, () => ({ x: 0, y: 0 }));\n }\n\n /** Mutates in-place */\n push(x: number, y: number): void {\n const slot = this.data[this.head]!;\n\n slot.x = x;\n slot.y = y;\n this.head = (this.head + 1) % this.capacity;\n\n if (this.count < this.capacity) {\n this.count++;\n }\n }\n\n /**\n * Copies ordered points into the pre-allocated result buffer and returns it\n * Note: The *same* array reference is returned every call,\n * so `result.length` is also always `capacity`\n */\n toArray(): Array<Point> {\n const start = this.count < this.capacity ? 0 : this.head;\n\n for (let i = 0; i < this.count; i++) {\n const src = this.data[(start + i) % this.capacity]!;\n const dst = this.result[i]!;\n dst.x = src.x;\n dst.y = src.y;\n }\n\n return this.result;\n }\n\n clear(): void {\n this.head = 0;\n this.count = 0;\n }\n\n get length() {\n return this.count;\n }\n}\n\n/**\n * Creates the core simulation engine for a sarmal\n *\n * it runs a clock (time `t`), asks the curve for the current Point position at that time,\n * and remembers the last N positions so the renderer can draw the trail\n *\n * The engine is only responsible for math coordinates,\n * so it is not responsible for drawing or colors\n *\n * @param curveDef A curve definition\n * @param trailLength default: `120`\n */\nexport function createEngine(curveDef: CurveDef, trailLength: number = 120): Engine {\n const curve = {\n name: curveDef.name,\n fn: curveDef.fn,\n period: curveDef.period ?? TWO_PI,\n speed: curveDef.speed ?? 1,\n };\n const trail = new CircularBuffer(trailLength);\n let t = 0;\n let actualTime = 0;\n\n return {\n tick(deltaTime: number): Array<Point> {\n t = (t + curve.speed * deltaTime) % curve.period;\n actualTime += deltaTime;\n const point = curve.fn(t, actualTime, {});\n trail.push(point.x, point.y);\n return trail.toArray();\n },\n\n get trailCount() {\n return trail.length;\n },\n\n reset() {\n t = 0;\n actualTime = 0;\n trail.clear();\n },\n\n seek(newT: number, { clearTrail = false }: SeekOptions = {}) {\n t = ((newT % curve.period) + curve.period) % curve.period;\n if (clearTrail) {\n trail.clear();\n }\n },\n\n seekWithTrail(targetT: number, { wrap = false }: SeekWithTrailOptions = {}) {\n // TODO: assumes 60fps, will need to further evaluate approach\n const STEP = 1 / 60;\n const advance = curve.speed * STEP;\n const target = ((targetT % curve.period) + curve.period) % curve.period;\n const targetTime = target / curve.speed;\n\n t = target;\n actualTime = targetTime;\n trail.clear();\n\n const pointsFromStart = Math.floor(target / advance) + 1;\n const count = wrap ? trailLength : Math.min(trailLength, pointsFromStart);\n\n for (let step = count - 1; step >= 0; step--) {\n const sampleT = target - step * advance;\n const wrappedT = sampleT < 0 ? sampleT + curve.period : sampleT;\n const time = targetTime - step * STEP;\n const point = curve.fn(wrappedT, time, {});\n trail.push(point.x, point.y);\n }\n },\n\n getSarmalSkeleton(): Array<Point> {\n const steps = Math.ceil(curve.period * POINTS_PER_PERIOD_UNIT);\n // oxlint-disable-next-line unicorn/no-new-array -- array is pre-allocated, filled immediately below\n const points: Array<Point> = new Array(steps);\n for (let i = 0; i < steps; i++) {\n const sampleT = (i / (steps - 1)) * curve.period;\n const point = curve.fn(sampleT, 0, {});\n points[i] = point;\n }\n return points;\n },\n };\n}\n","import type { Point, RendererOptions, SarmalInstance } from \"./types\";\n\nconst DEFAULT_HEAD_RADIUS = 4;\n// TODO: Re-evaluate glow implementation. Current approach looks TERRIBLE!\n// Consider: remove glow entirely, replace with a sharper bloom, or make it opt-in only (default 0).\nconst DEFAULT_GLOW_SIZE = 20;\nconst DEFAULT_SKELETON_COLOR = \"#ffffff\";\nconst DEFAULT_SKELETON_OPACITY = 0.15;\n\n/** Fraction of the bounding box added as padding when fitting the curve to the canvas */\nconst FIT_PADDING = 0.1;\n\n/**\n * The trail is drawn in batches of points\n * Each batch has lower opacity than the one that comes before it\n * (0 = oldest/tail, 1 = newest/head)\n *\n * ! Performance note: Larger batch size = fewer GPU stroke calls per frame\n */\nconst TRAIL_BATCH_SIZE = 20;\n/** Higher values = sharper fade near the tail, more of the trail appears faint */\nconst TRAIL_FADE_CURVE = 1.5;\nconst TRAIL_MAX_OPACITY = 0.88;\n/** Line width of tail */\nconst TRAIL_MIN_WIDTH = 0.5;\n/** Line width of head */\nconst TRAIL_MAX_WIDTH = 2.5;\n\nconst GLOW_INNER_EDGE = 0.4;\n/** Opacity at the inner edge of the glow falloff */\nconst GLOW_FALLOFF_OPACITY = 0.53;\n\n/** Parses a hex color into its \"r,g,b\" string for use in rgba() — called once at init */\nfunction hexToRgbComponents(hex: string): string {\n const n = parseInt(hex.slice(1), 16);\n return `${n >> 16},${(n >> 8) & 255},${n & 255}`;\n}\n\n/**\n * Creates a Canvas 2D renderer for sarmal animations\n * Renders the skeleton, the trail, and the glowing dot\n */\nexport function createRenderer(options: RendererOptions): SarmalInstance {\n const canvas = options.canvas;\n if (!canvas.getContext(\"2d\")) {\n throw new Error(\"Could not get 2d context from canvas\");\n }\n const ctx = canvas.getContext(\"2d\")!;\n\n const engine = options.engine;\n const opts = {\n skeletonColor: options.skeletonColor ?? DEFAULT_SKELETON_COLOR,\n trailColor: options.trailColor ?? \"#ffffff\",\n headColor: options.headColor ?? \"#ffffff\",\n headRadius: options.headRadius ?? DEFAULT_HEAD_RADIUS,\n glowSize: options.glowSize ?? DEFAULT_GLOW_SIZE,\n };\n\n const trailRgb = hexToRgbComponents(opts.trailColor);\n const headRgbFalloff = `rgba(${hexToRgbComponents(opts.headColor)},${GLOW_FALLOFF_OPACITY})`;\n\n let skeleton: Array<Point> = [];\n let skeletonCanvas: OffscreenCanvas | null = null;\n let trail: Array<Point> = [];\n let trailCount = 0;\n let head: Point | null = null;\n let scale = 1;\n let offsetX = 0;\n let offsetY = 0;\n let animationId: number | null = null;\n let lastTime = 0;\n\n /**\n * Computes how to map engine coordinates to canvas pixels\n *\n * Steps are roughly: curve fn -> coordinate point -> (scale + offset) -> pixel\n *\n * 1. Find the bounding box of the skeleton (min/max x/y in coordinates)\n * 2. Compute a scale factor within the bounds into the canvas with padding\n * 3. Compute offsets to center the curve in the canvas\n */\n function calculateBoundaries() {\n if (skeleton.length === 0) {\n return;\n }\n\n const first = skeleton[0]!;\n let minX = first.x,\n maxX = first.x,\n minY = first.y,\n maxY = first.y;\n for (const p of skeleton) {\n if (p.x < minX) {\n minX = p.x;\n }\n\n if (p.x > maxX) {\n maxX = p.x;\n }\n\n if (p.y < minY) {\n minY = p.y;\n }\n\n if (p.y > maxY) {\n maxY = p.y;\n }\n }\n\n const width = maxX - minX;\n const height = maxY - minY;\n const canvasWidth = canvas.width;\n const canvasHeight = canvas.height;\n\n const scaleX = canvasWidth / (width * (1 + FIT_PADDING * 2));\n const scaleY = canvasHeight / (height * (1 + FIT_PADDING * 2));\n scale = Math.min(scaleX, scaleY);\n\n const boundsWidth = width * scale;\n const boundsHeight = height * scale;\n offsetX = (canvasWidth - boundsWidth) / 2 - minX * scale;\n offsetY = (canvasHeight - boundsHeight) / 2 - minY * scale;\n }\n\n /**\n * Draws the skeleton once into an OffscreenCanvas so that every frame\n * only needs a single ctx.drawImage() instead of rebuilding the full path.\n */\n function buildSkeletonCanvas() {\n if (skeleton.length < 2) return;\n\n skeletonCanvas = new OffscreenCanvas(canvas.width, canvas.height);\n const skeletonCtx = skeletonCanvas.getContext(\"2d\")!;\n\n skeletonCtx.strokeStyle = `rgba(${hexToRgbComponents(opts.skeletonColor)},${DEFAULT_SKELETON_OPACITY})`;\n skeletonCtx.lineWidth = 1.5;\n skeletonCtx.beginPath();\n\n const first = skeleton[0]!;\n skeletonCtx.moveTo(first.x * scale + offsetX, first.y * scale + offsetY);\n\n for (let i = 1; i < skeleton.length; i++) {\n const p = skeleton[i]!;\n skeletonCtx.lineTo(p.x * scale + offsetX, p.y * scale + offsetY);\n }\n\n skeletonCtx.stroke();\n }\n\n function drawSkeleton() {\n if (!skeletonCanvas) {\n return;\n }\n\n ctx.drawImage(skeletonCanvas, 0, 0);\n }\n\n function drawTrail() {\n if (trailCount < 2) {\n return;\n }\n\n // Set constant state once outside the batch loop\n ctx.lineJoin = \"round\";\n ctx.lineCap = \"round\";\n\n for (let batchIndex = 0; batchIndex < trailCount - 1; batchIndex += TRAIL_BATCH_SIZE) {\n const bEnd = Math.min(batchIndex + TRAIL_BATCH_SIZE, trailCount - 1);\n /** Normalized position of this batch along the trail (0 = tail, 1 = head) */\n const progress = (batchIndex + bEnd) / 2 / (trailCount - 1);\n const alpha = Math.pow(progress, TRAIL_FADE_CURVE) * TRAIL_MAX_OPACITY;\n const lineWidth = TRAIL_MIN_WIDTH + progress * (TRAIL_MAX_WIDTH - TRAIL_MIN_WIDTH);\n\n ctx.beginPath();\n for (let i = batchIndex; i <= bEnd; i++) {\n const point = trail[i]!;\n\n if (i === batchIndex) {\n ctx.moveTo(point.x * scale + offsetX, point.y * scale + offsetY);\n } else {\n ctx.lineTo(point.x * scale + offsetX, point.y * scale + offsetY);\n }\n }\n\n // ! AI Note\n // FIXME: still allocates a new string every batch every frame (~20x/frame).\n // `trailRgb` avoids re-parsing the hex, but alpha is a continuous float so the full\n // rgba string can't be pre-computed. Fix: discretize alpha into N buckets at init\n // and do a lookup (e.g. trailColors[Math.round(progress * N)]) instead of a template literal.\n ctx.strokeStyle = `rgba(${trailRgb},${alpha})`;\n ctx.lineWidth = lineWidth;\n ctx.stroke();\n }\n }\n\n function drawHead() {\n if (!head) {\n return;\n }\n\n const x = head.x * scale + offsetX;\n const y = head.y * scale + offsetY;\n\n const gradient = ctx.createRadialGradient(x, y, 0, x, y, opts.glowSize);\n gradient.addColorStop(0, opts.headColor);\n gradient.addColorStop(GLOW_INNER_EDGE, headRgbFalloff);\n gradient.addColorStop(1, \"transparent\");\n\n ctx.fillStyle = gradient;\n ctx.beginPath();\n ctx.arc(x, y, opts.glowSize, 0, Math.PI * 2);\n ctx.fill();\n\n ctx.fillStyle = opts.headColor;\n ctx.beginPath();\n ctx.arc(x, y, opts.headRadius, 0, Math.PI * 2);\n ctx.fill();\n }\n\n function render() {\n const now = performance.now();\n const deltaTime = Math.min((now - lastTime) / 1000, 1 / 30);\n lastTime = now;\n\n trail = engine.tick(deltaTime);\n trailCount = engine.trailCount;\n head = trailCount > 0 ? trail[trailCount - 1]! : null;\n\n ctx.clearRect(0, 0, canvas.width, canvas.height);\n\n drawSkeleton();\n drawTrail();\n drawHead();\n\n animationId = requestAnimationFrame(render);\n }\n\n // Initialize skeleton and offscreen canvas on creation\n skeleton = engine.getSarmalSkeleton();\n calculateBoundaries();\n buildSkeletonCanvas();\n\n return {\n start() {\n if (animationId !== null) {\n return;\n }\n\n lastTime = performance.now();\n render();\n },\n\n stop() {\n if (animationId === null) {\n return;\n }\n\n cancelAnimationFrame(animationId);\n animationId = null;\n },\n\n reset() {\n engine.reset();\n trail = [];\n head = null;\n },\n\n destroy() {\n if (animationId !== null) {\n cancelAnimationFrame(animationId);\n animationId = null;\n }\n },\n\n seek(t, options) {\n engine.seek(t, options);\n },\n\n seekWithTrail(t) {\n engine.seekWithTrail(t);\n },\n };\n}\n","import type { CurveDef, Engine, Point, SarmalInstance } from \"./types\";\nimport { createEngine } from \"./engine\";\n\nconst TRAIL_BATCH_COUNT = 12;\n/** Higher values = sharper fade near the tail */\nconst TRAIL_FADE_CURVE = 1.5;\nconst TRAIL_MAX_OPACITY = 0.88;\n/** Stroke width at the tail */\nconst TRAIL_MIN_WIDTH = 0.5;\n/** Stroke width at the head */\nconst TRAIL_MAX_WIDTH = 2.5;\nconst DEFAULT_SKELETON_OPACITY = 0.15;\nconst DEFAULT_GLOW_INNER_STOP = 0.4;\nconst DEFAULT_GLOW_FALLOFF_OPACITY = 0.53;\n/** Fraction of the bounding box added as padding when auto-fitting the curve */\nconst FIT_PADDING = 0.1;\n\nlet instanceCount = 0;\n\nexport interface SVGRendererOptions {\n /** Container element that will contain the SVG */\n container: Element;\n engine: Engine;\n /** @default '#ffffff' */\n skeletonColor?: string;\n /** @default '#ffffff' */\n trailColor?: string;\n /** @default '#ffffff' */\n headColor?: string;\n /** @default 4 */\n headRadius?: number;\n /** @default 20 */\n glowSize?: number;\n /** @default 'Loading' */\n ariaLabel?: string;\n}\n\nexport interface SVGSarmalOptions extends Omit<SVGRendererOptions, \"container\" | \"engine\"> {\n /** @default 120 */\n trailLength?: number;\n}\n\nfunction el(tag: string): SVGElement {\n return document.createElementNS(\"http://www.w3.org/2000/svg\", tag);\n}\n\n/**\n * Creates a live SVG renderer for sarmal animations\n * The SVG is appended into `container` and updated each frame via **requestAnimationFrame**\n */\nexport function createSVGRenderer(options: SVGRendererOptions): SarmalInstance {\n const { container, engine } = options;\n const opts = {\n skeletonColor: options.skeletonColor ?? \"#ffffff\",\n trailColor: options.trailColor ?? \"#ffffff\",\n headColor: options.headColor ?? \"#ffffff\",\n headRadius: options.headRadius ?? 4,\n glowSize: options.glowSize ?? 20,\n ariaLabel: options.ariaLabel ?? \"Loading\",\n };\n\n // Unique per-instance ID prevents ID collisions of multiple instances\n const uid = ++instanceCount;\n const gradientId = `sarmal-glow-${uid}`;\n\n const rect = container.getBoundingClientRect();\n const width = rect.width || 200;\n const height = rect.height || 200;\n\n const svg = el(\"svg\") as SVGSVGElement;\n svg.setAttribute(\"width\", String(width));\n svg.setAttribute(\"height\", String(height));\n svg.setAttribute(\"viewBox\", `0 0 ${width} ${height}`);\n svg.setAttribute(\"role\", \"img\");\n svg.setAttribute(\"aria-label\", opts.ariaLabel);\n\n const titleEl = el(\"title\");\n titleEl.textContent = opts.ariaLabel;\n svg.appendChild(titleEl);\n\n const defs = el(\"defs\");\n const gradient = el(\"radialGradient\") as SVGRadialGradientElement;\n gradient.id = gradientId;\n gradient.setAttribute(\"cx\", \"50%\");\n gradient.setAttribute(\"cy\", \"50%\");\n gradient.setAttribute(\"r\", \"50%\");\n const stop0 = el(\"stop\");\n stop0.setAttribute(\"offset\", \"0%\");\n stop0.setAttribute(\"stop-color\", opts.headColor);\n stop0.setAttribute(\"stop-opacity\", \"1\");\n const stopMid = el(\"stop\");\n stopMid.setAttribute(\"offset\", `${DEFAULT_GLOW_INNER_STOP * 100}%`);\n stopMid.setAttribute(\"stop-color\", opts.headColor);\n stopMid.setAttribute(\"stop-opacity\", String(DEFAULT_GLOW_FALLOFF_OPACITY));\n const stop1 = el(\"stop\");\n stop1.setAttribute(\"offset\", \"100%\");\n stop1.setAttribute(\"stop-color\", opts.headColor);\n stop1.setAttribute(\"stop-opacity\", \"0\");\n gradient.append(stop0, stopMid, stop1);\n defs.appendChild(gradient);\n svg.appendChild(defs);\n\n const skeletonPath = el(\"path\") as SVGPathElement;\n skeletonPath.setAttribute(\"fill\", \"none\");\n skeletonPath.setAttribute(\"stroke\", opts.skeletonColor);\n skeletonPath.setAttribute(\"stroke-opacity\", String(DEFAULT_SKELETON_OPACITY));\n skeletonPath.setAttribute(\"stroke-width\", \"1.5\");\n svg.appendChild(skeletonPath);\n\n const trailPaths: SVGPathElement[] = [];\n for (let i = 0; i < TRAIL_BATCH_COUNT; i++) {\n const path = el(\"path\") as SVGPathElement;\n path.setAttribute(\"fill\", \"none\");\n path.setAttribute(\"stroke\", opts.trailColor);\n path.setAttribute(\"stroke-linecap\", \"round\");\n path.setAttribute(\"stroke-linejoin\", \"round\");\n svg.appendChild(path);\n trailPaths.push(path);\n }\n\n const glowCircle = el(\"circle\") as SVGCircleElement;\n glowCircle.setAttribute(\"fill\", `url(#${gradientId})`);\n glowCircle.setAttribute(\"r\", String(opts.glowSize));\n svg.appendChild(glowCircle);\n\n const headCircle = el(\"circle\") as SVGCircleElement;\n headCircle.setAttribute(\"fill\", opts.headColor);\n headCircle.setAttribute(\"r\", String(opts.headRadius));\n svg.appendChild(headCircle);\n\n container.appendChild(svg);\n\n let scale = 1;\n let offsetX = 0;\n let offsetY = 0;\n\n function calculateBoundaries(skeleton: Point[]) {\n if (skeleton.length === 0) {\n return;\n }\n\n const first = skeleton[0]!;\n let minX = first.x,\n maxX = first.x,\n minY = first.y,\n maxY = first.y;\n\n for (const p of skeleton) {\n if (p.x < minX) {\n minX = p.x;\n }\n\n if (p.x > maxX) {\n maxX = p.x;\n }\n\n if (p.y < minY) {\n minY = p.y;\n }\n\n if (p.y > maxY) {\n maxY = p.y;\n }\n }\n\n const w = maxX - minX;\n const h = maxY - minY;\n const scaleX = width / (w * (1 + FIT_PADDING * 2));\n const scaleY = height / (h * (1 + FIT_PADDING * 2));\n\n scale = Math.min(scaleX, scaleY);\n offsetX = (width - w * scale) / 2 - minX * scale;\n offsetY = (height - h * scale) / 2 - minY * scale;\n }\n\n // TODO: might avoid code repetition\n function px(p: Point) {\n return (p.x * scale + offsetX).toFixed(2);\n }\n function py(p: Point) {\n return (p.y * scale + offsetY).toFixed(2);\n }\n\n const skeleton = engine.getSarmalSkeleton();\n calculateBoundaries(skeleton);\n\n if (skeleton.length >= 2) {\n let d = `M${px(skeleton[0]!)} ${py(skeleton[0]!)}`;\n\n for (let i = 1; i < skeleton.length; i++) {\n d += ` L${px(skeleton[i]!)} ${py(skeleton[i]!)}`;\n }\n d += \" Z\";\n\n skeletonPath.setAttribute(\"d\", d);\n }\n\n function updateTrail(trail: Point[], trailCount: number) {\n if (trailCount < 2) {\n for (const p of trailPaths) {\n p.setAttribute(\"d\", \"\");\n }\n\n return;\n }\n const batchSize = Math.ceil(trailCount / TRAIL_BATCH_COUNT);\n\n for (let b = 0; b < TRAIL_BATCH_COUNT; b++) {\n const start = b * batchSize;\n const end = Math.min(start + batchSize, trailCount - 1);\n if (start >= trailCount - 1) {\n trailPaths[b]!.setAttribute(\"d\", \"\");\n continue;\n }\n const progress = (start + end) / 2 / (trailCount - 1);\n const opacity = Math.pow(progress, TRAIL_FADE_CURVE) * TRAIL_MAX_OPACITY;\n const strokeWidth = TRAIL_MIN_WIDTH + progress * (TRAIL_MAX_WIDTH - TRAIL_MIN_WIDTH);\n\n let d = `M${px(trail[start]!)} ${py(trail[start]!)}`;\n for (let i = start + 1; i <= end; i++) {\n d += ` L${px(trail[i]!)} ${py(trail[i]!)}`;\n }\n\n trailPaths[b]!.setAttribute(\"d\", d);\n trailPaths[b]!.setAttribute(\"stroke-opacity\", opacity.toFixed(3));\n trailPaths[b]!.setAttribute(\"stroke-width\", strokeWidth.toFixed(2));\n }\n }\n\n function updateHead(trail: Point[], trailCount: number) {\n if (trailCount === 0) {\n return;\n }\n\n const head = trail[trailCount - 1]!;\n const x = px(head);\n const y = py(head);\n\n glowCircle.setAttribute(\"cx\", x);\n glowCircle.setAttribute(\"cy\", y);\n headCircle.setAttribute(\"cx\", x);\n headCircle.setAttribute(\"cy\", y);\n }\n\n let animationId: number | null = null;\n let lastTime = 0;\n const prefersReducedMotion =\n typeof window !== \"undefined\" && window.matchMedia(\"(prefers-reduced-motion: reduce)\").matches;\n\n function renderFrame() {\n const now = performance.now();\n const dt = Math.min((now - lastTime) / 1000, 1 / 30);\n lastTime = now;\n\n const trail = engine.tick(dt);\n const trailCount = engine.trailCount;\n\n updateTrail(trail, trailCount);\n updateHead(trail, trailCount);\n\n if (!prefersReducedMotion) {\n animationId = requestAnimationFrame(renderFrame);\n }\n }\n\n return {\n start() {\n if (animationId !== null) {\n return;\n }\n lastTime = performance.now();\n renderFrame();\n },\n\n stop() {\n if (animationId === null) {\n return;\n }\n cancelAnimationFrame(animationId);\n animationId = null;\n },\n\n reset() {\n engine.reset();\n },\n\n destroy() {\n if (animationId !== null) {\n cancelAnimationFrame(animationId);\n animationId = null;\n }\n svg.remove();\n },\n\n seek(t, options) {\n engine.seek(t, options);\n },\n\n seekWithTrail(t) {\n engine.seekWithTrail(t);\n },\n };\n}\n\n/**\n * Creates a sarmal animation inside a container element using an SVG renderer\n * The SVG is appended to the container and animated via requestAnimationFrame\n *\n * @example\n * ```ts\n * import { createSarmalSVG, curves } from '@sarmal/core'\n * const sarmal = createSarmalSVG(document.getElementById('spinner'), curves.epitrochoid7)\n * sarmal.start()\n * ```\n */\nexport function createSarmalSVG(\n container: Element,\n curveDef: CurveDef,\n options?: SVGSarmalOptions,\n): SarmalInstance {\n const { trailLength, ...rendererOpts } = options ?? {};\n const engine = createEngine(curveDef, trailLength);\n return createSVGRenderer({ container, engine, ...rendererOpts });\n}\n","import type { CurveDef, Point } from \"./types\";\n\nconst TWO_PI = Math.PI * 2;\n\n/**\n * Artemis II free-return lunar trajectory\n * @see https://www.nasa.gov/wp-content/uploads/2025/09/artemis-ii-map-508.pdf\n * a = x-axis asymmetry (widens one lobe),\n * b = y-axis asymmetry,\n * ox = horizontal offset to visually center the shape\n */\nfunction artemis2(t: number, _time: number, _params: Record<string, number>): Point {\n const a = 0.35,\n b = 0.15,\n ox = 0.175;\n const s = Math.sin(t),\n c = Math.cos(t);\n const denom = 1 + s * s;\n return {\n x: (c * (1 + a * c)) / denom - ox,\n y: (s * c * (1 + b * c)) / denom,\n };\n}\n\nfunction epitrochoid7(t: number, _time: number, _params: Record<string, number>): Point {\n const d = 1.0 + 0.55 * Math.sin(t * 0.5);\n return {\n x: 7 * Math.cos(t) - d * Math.cos(7 * t),\n y: 7 * Math.sin(t) - d * Math.sin(7 * t),\n };\n}\n\nfunction astroid(t: number, _time: number, _params: Record<string, number>): Point {\n const c = Math.cos(t);\n const s = Math.sin(t);\n return {\n x: c * c * c,\n y: s * s * s,\n };\n}\n\nfunction deltoid(t: number, _time: number, _params: Record<string, number>): Point {\n return {\n x: 2 * Math.cos(t) + Math.cos(2 * t),\n y: 2 * Math.sin(t) - Math.sin(2 * t),\n };\n}\n\nfunction rose5(t: number, _time: number, _params: Record<string, number>): Point {\n const r = Math.cos(5 * t);\n return {\n x: r * Math.cos(t),\n y: r * Math.sin(t),\n };\n}\n\nfunction rose3(t: number, _time: number, _params: Record<string, number>): Point {\n const r = Math.cos(3 * t);\n return {\n x: r * Math.cos(t),\n y: r * Math.sin(t),\n };\n}\n\nfunction lissajous32(t: number, time: number, _params: Record<string, number>): Point {\n const phi = time * 0.45;\n return {\n x: Math.sin(3 * t + phi),\n y: Math.sin(2 * t),\n };\n}\n\nfunction lissajous43(t: number, time: number, _params: Record<string, number>): Point {\n const phi = time * 0.38;\n return {\n x: Math.sin(4 * t + phi),\n y: Math.sin(3 * t),\n };\n}\n\nfunction epicycloid3(t: number, _time: number, _params: Record<string, number>): Point {\n return {\n x: 4 * Math.cos(t) - Math.cos(4 * t),\n y: 4 * Math.sin(t) - Math.sin(4 * t),\n };\n}\n\nfunction lame(t: number, time: number, _params: Record<string, number>): Point {\n const p = 1.75 + 1.25 * Math.sin(time * 0.48);\n const c = Math.cos(t),\n s = Math.sin(t);\n return {\n x: Math.sign(c) * Math.pow(Math.abs(c), p),\n y: Math.sign(s) * Math.pow(Math.abs(s), p),\n };\n}\nexport const curves: Record<string, CurveDef> = {\n artemis2: {\n name: \"Artemis II\",\n fn: artemis2,\n period: TWO_PI,\n speed: 0.7,\n },\n epitrochoid7: {\n name: \"Epitrochoid\",\n fn: epitrochoid7,\n period: TWO_PI,\n speed: 1.4,\n },\n astroid: {\n name: \"Astroid\",\n fn: astroid,\n period: TWO_PI,\n speed: 1.1,\n },\n deltoid: {\n name: \"Deltoid\",\n fn: deltoid,\n period: TWO_PI,\n speed: 0.9,\n },\n rose5: {\n name: \"Rose (n=5)\",\n fn: rose5,\n period: TWO_PI,\n speed: 1.0,\n },\n rose3: {\n name: \"Rose (n=3)\",\n fn: rose3,\n period: TWO_PI,\n speed: 1.15,\n },\n lissajous32: {\n name: \"Lissajous 3:2\",\n fn: lissajous32,\n period: TWO_PI,\n speed: 2.0,\n },\n lissajous43: {\n name: \"Lissajous 4:3\",\n fn: lissajous43,\n period: TWO_PI,\n speed: 1.8,\n },\n epicycloid3: {\n name: \"Epicycloid (n=3)\",\n fn: epicycloid3,\n period: TWO_PI,\n speed: 0.75,\n },\n lame: {\n name: \"Lamé Curve\",\n fn: lame,\n period: TWO_PI,\n speed: 1.0,\n },\n};\n","export type { SVGRendererOptions, SVGSarmalOptions } from \"./renderer-svg\";\nexport type {\n Point,\n CurveDef,\n Engine,\n SarmalInstance,\n SeekOptions,\n SeekWithTrailOptions,\n RendererOptions,\n SarmalOptions,\n} from \"./types\";\n\nexport { createEngine } from \"./engine\";\nexport { createRenderer } from \"./renderer\";\nexport { createSVGRenderer, createSarmalSVG } from \"./renderer-svg\";\nexport { curves } from \"./curves\";\n\nimport type { CurveDef, SarmalInstance, SarmalOptions } from \"./types\";\nimport { createEngine } from \"./engine\";\nimport { createRenderer } from \"./renderer\";\n\n/**\n * Creates a sarmal animation on a canvas element\n *\n * @example\n * ```ts\n * import { createSarmal, curves } from '@sarmal/core'\n * const sarmal = createSarmal(canvas, curves.artemis2)\n * sarmal.start()\n * ```\n */\nexport function createSarmal(\n canvas: HTMLCanvasElement,\n curveDef: CurveDef,\n options?: SarmalOptions,\n): SarmalInstance {\n const { trailLength, ...rendererOpts } = options ?? {};\n const engine = createEngine(curveDef, trailLength);\n\n return createRenderer({ canvas, engine, ...rendererOpts });\n}\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/engine.ts","../src/renderer.ts","../src/renderer-svg.ts","../src/curves.ts","../src/index.ts"],"names":["options","TRAIL_FADE_CURVE","TRAIL_MAX_OPACITY","TRAIL_MIN_WIDTH","TRAIL_MAX_WIDTH","DEFAULT_SKELETON_OPACITY","FIT_PADDING","skeleton","TWO_PI"],"mappings":"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","file":"index.cjs","sourcesContent":["import type { CurveDef, Engine, Point, SeekOptions, SeekWithTrailOptions } from \"./types\";\n\nconst TWO_PI = Math.PI * 2;\nconst POINTS_PER_PERIOD_UNIT = 50;\n\n/**\n * A fixed-size list of points with first in, last out method\n * The oldest entry is automatically discarded when the list is at capacity\n *\n * Note: `result.length` is *never* changed,\n * so callers use the separate `count` getter to know valid size\n */\nclass CircularBuffer {\n private data: Array<Point>;\n private result: Array<Point>;\n private capacity: number;\n private head: number = 0;\n private count: number = 0;\n\n constructor(capacity: number) {\n this.capacity = capacity;\n this.data = Array.from({ length: capacity }, () => ({ x: 0, y: 0 }));\n this.result = Array.from({ length: capacity }, () => ({ x: 0, y: 0 }));\n }\n\n /** Mutates in-place */\n push(x: number, y: number): void {\n const slot = this.data[this.head]!;\n\n slot.x = x;\n slot.y = y;\n this.head = (this.head + 1) % this.capacity;\n\n if (this.count < this.capacity) {\n this.count++;\n }\n }\n\n /**\n * Copies ordered points into the pre-allocated result buffer and returns it\n * Note: The *same* array reference is returned every call,\n * so `result.length` is also always `capacity`\n */\n toArray(): Array<Point> {\n const start = this.count < this.capacity ? 0 : this.head;\n\n for (let i = 0; i < this.count; i++) {\n const src = this.data[(start + i) % this.capacity]!;\n const dst = this.result[i]!;\n dst.x = src.x;\n dst.y = src.y;\n }\n\n return this.result;\n }\n\n clear(): void {\n this.head = 0;\n this.count = 0;\n }\n\n get length() {\n return this.count;\n }\n}\n\n/**\n * Creates the core simulation engine for a sarmal\n *\n * it runs a clock (time `t`), asks the curve for the current Point position at that time,\n * and remembers the last N positions so the renderer can draw the trail\n *\n * The engine is only responsible for math coordinates,\n * so it is not responsible for drawing or colors\n *\n * @param curveDef A curve definition\n * @param trailLength default: `120`\n */\nexport function createEngine(curveDef: CurveDef, trailLength: number = 120): Engine {\n const curve = {\n name: curveDef.name,\n fn: curveDef.fn,\n period: curveDef.period ?? TWO_PI,\n speed: curveDef.speed ?? 1,\n };\n const trail = new CircularBuffer(trailLength);\n let t = 0;\n let actualTime = 0;\n\n return {\n tick(deltaTime: number): Array<Point> {\n t = (t + curve.speed * deltaTime) % curve.period;\n actualTime += deltaTime;\n const point = curve.fn(t, actualTime, {});\n trail.push(point.x, point.y);\n return trail.toArray();\n },\n\n get trailCount() {\n return trail.length;\n },\n\n reset() {\n t = 0;\n actualTime = 0;\n trail.clear();\n },\n\n seek(newT: number, { clearTrail = false }: SeekOptions = {}) {\n t = ((newT % curve.period) + curve.period) % curve.period;\n if (clearTrail) {\n trail.clear();\n }\n },\n\n seekWithTrail(\n targetT: number,\n { wrap = false, step = curve.period / trailLength }: SeekWithTrailOptions = {},\n ) {\n const advance = curve.speed * step;\n const target = ((targetT % curve.period) + curve.period) % curve.period;\n const targetTime = target / curve.speed;\n\n t = target;\n actualTime = targetTime;\n trail.clear();\n\n const pointsFromStart = Math.floor(target / advance) + 1;\n const count = wrap ? trailLength : Math.min(trailLength, pointsFromStart);\n\n for (let i = count - 1; i >= 0; i--) {\n const sampleT = target - i * advance;\n const wrappedT = sampleT < 0 ? sampleT + curve.period : sampleT;\n const time = targetTime - i * step;\n const point = curve.fn(wrappedT, time, {});\n\n trail.push(point.x, point.y);\n }\n },\n\n getSarmalSkeleton(): Array<Point> {\n const steps = Math.ceil(curve.period * POINTS_PER_PERIOD_UNIT);\n // oxlint-disable-next-line unicorn/no-new-array -- array is pre-allocated, filled immediately below\n const points: Array<Point> = new Array(steps);\n for (let i = 0; i < steps; i++) {\n const sampleT = (i / (steps - 1)) * curve.period;\n const point = curve.fn(sampleT, 0, {});\n points[i] = point;\n }\n return points;\n },\n };\n}\n","import type { Point, RendererOptions, SarmalInstance } from \"./types\";\n\nconst DEFAULT_HEAD_RADIUS = 4;\n// TODO: Re-evaluate glow implementation. Current approach looks TERRIBLE!\n// Consider: remove glow entirely, replace with a sharper bloom, or make it opt-in only (default 0).\nconst DEFAULT_GLOW_SIZE = 20;\nconst DEFAULT_SKELETON_COLOR = \"#ffffff\";\nconst DEFAULT_SKELETON_OPACITY = 0.15;\n\n/** Fraction of the bounding box added as padding when fitting the curve to the canvas */\nconst FIT_PADDING = 0.1;\n\n/**\n * The trail is drawn in batches of points\n * Each batch has lower opacity than the one that comes before it\n * (0 = oldest/tail, 1 = newest/head)\n *\n * ! Performance note: Larger batch size = fewer GPU stroke calls per frame\n */\nconst TRAIL_BATCH_SIZE = 20;\n/** Higher values = sharper fade near the tail, more of the trail appears faint */\nconst TRAIL_FADE_CURVE = 1.5;\nconst TRAIL_MAX_OPACITY = 0.88;\n/** Line width of tail */\nconst TRAIL_MIN_WIDTH = 0.5;\n/** Line width of head */\nconst TRAIL_MAX_WIDTH = 2.5;\n\nconst GLOW_INNER_EDGE = 0.4;\n/** Opacity at the inner edge of the glow falloff */\nconst GLOW_FALLOFF_OPACITY = 0.53;\n\n/** Parses a hex color into its \"r,g,b\" string for use in rgba() — called once at init */\nexport function hexToRgbComponents(hex: string): string {\n const n = parseInt(hex.slice(1), 16);\n return `${n >> 16},${(n >> 8) & 255},${n & 255}`;\n}\n\n/**\n * Creates a Canvas 2D renderer for sarmal animations\n * Renders the skeleton, the trail, and the glowing dot\n */\nexport function createRenderer(options: RendererOptions): SarmalInstance {\n const canvas = options.canvas;\n if (!canvas.getContext(\"2d\")) {\n throw new Error(\"Could not get 2d context from canvas\");\n }\n const ctx = canvas.getContext(\"2d\")!;\n\n const engine = options.engine;\n const opts = {\n skeletonColor: options.skeletonColor ?? DEFAULT_SKELETON_COLOR,\n trailColor: options.trailColor ?? \"#ffffff\",\n headColor: options.headColor ?? \"#ffffff\",\n headRadius: options.headRadius ?? DEFAULT_HEAD_RADIUS,\n glowSize: options.glowSize ?? DEFAULT_GLOW_SIZE,\n };\n\n const trailRgb = hexToRgbComponents(opts.trailColor);\n const headRgbFalloff = `rgba(${hexToRgbComponents(opts.headColor)},${GLOW_FALLOFF_OPACITY})`;\n\n let skeleton: Array<Point> = [];\n let skeletonCanvas: OffscreenCanvas | null = null;\n let trail: Array<Point> = [];\n let trailCount = 0;\n let head: Point | null = null;\n let scale = 1;\n let offsetX = 0;\n let offsetY = 0;\n let animationId: number | null = null;\n let lastTime = 0;\n\n /**\n * Computes how to map engine coordinates to canvas pixels\n *\n * Steps are roughly: curve fn -> coordinate point -> (scale + offset) -> pixel\n *\n * 1. Find the bounding box of the skeleton (min/max x/y in coordinates)\n * 2. Compute a scale factor within the bounds into the canvas with padding\n * 3. Compute offsets to center the curve in the canvas\n */\n function calculateBoundaries() {\n if (skeleton.length === 0) {\n return;\n }\n\n const first = skeleton[0]!;\n let minX = first.x,\n maxX = first.x,\n minY = first.y,\n maxY = first.y;\n for (const p of skeleton) {\n if (p.x < minX) {\n minX = p.x;\n }\n\n if (p.x > maxX) {\n maxX = p.x;\n }\n\n if (p.y < minY) {\n minY = p.y;\n }\n\n if (p.y > maxY) {\n maxY = p.y;\n }\n }\n\n const width = maxX - minX;\n const height = maxY - minY;\n const canvasWidth = canvas.width;\n const canvasHeight = canvas.height;\n\n const scaleX = canvasWidth / (width * (1 + FIT_PADDING * 2));\n const scaleY = canvasHeight / (height * (1 + FIT_PADDING * 2));\n scale = Math.min(scaleX, scaleY);\n\n const boundsWidth = width * scale;\n const boundsHeight = height * scale;\n offsetX = (canvasWidth - boundsWidth) / 2 - minX * scale;\n offsetY = (canvasHeight - boundsHeight) / 2 - minY * scale;\n }\n\n /**\n * Draws the skeleton once into an OffscreenCanvas so that every frame\n * only needs a single ctx.drawImage() instead of rebuilding the full path.\n */\n function buildSkeletonCanvas() {\n if (skeleton.length < 2) return;\n\n skeletonCanvas = new OffscreenCanvas(canvas.width, canvas.height);\n const skeletonCtx = skeletonCanvas.getContext(\"2d\")!;\n\n skeletonCtx.strokeStyle = `rgba(${hexToRgbComponents(opts.skeletonColor)},${DEFAULT_SKELETON_OPACITY})`;\n skeletonCtx.lineWidth = 1.5;\n skeletonCtx.beginPath();\n\n const first = skeleton[0]!;\n skeletonCtx.moveTo(first.x * scale + offsetX, first.y * scale + offsetY);\n\n for (let i = 1; i < skeleton.length; i++) {\n const p = skeleton[i]!;\n skeletonCtx.lineTo(p.x * scale + offsetX, p.y * scale + offsetY);\n }\n\n skeletonCtx.stroke();\n }\n\n function drawSkeleton() {\n if (!skeletonCanvas || opts.skeletonColor === \"transparent\") {\n return;\n }\n\n ctx.drawImage(skeletonCanvas, 0, 0);\n }\n\n function drawTrail() {\n if (trailCount < 2) {\n return;\n }\n\n // Set constant state once outside the batch loop\n ctx.lineJoin = \"round\";\n ctx.lineCap = \"round\";\n\n for (let batchIndex = 0; batchIndex < trailCount - 1; batchIndex += TRAIL_BATCH_SIZE) {\n const bEnd = Math.min(batchIndex + TRAIL_BATCH_SIZE, trailCount - 1);\n /** Normalized position of this batch along the trail (0 = tail, 1 = head) */\n const progress = (batchIndex + bEnd) / 2 / (trailCount - 1);\n const alpha = Math.pow(progress, TRAIL_FADE_CURVE) * TRAIL_MAX_OPACITY;\n const lineWidth = TRAIL_MIN_WIDTH + progress * (TRAIL_MAX_WIDTH - TRAIL_MIN_WIDTH);\n\n ctx.beginPath();\n for (let i = batchIndex; i <= bEnd; i++) {\n const point = trail[i]!;\n\n if (i === batchIndex) {\n ctx.moveTo(point.x * scale + offsetX, point.y * scale + offsetY);\n } else {\n ctx.lineTo(point.x * scale + offsetX, point.y * scale + offsetY);\n }\n }\n\n // ! AI Note\n // FIXME: still allocates a new string every batch every frame (~20x/frame).\n // `trailRgb` avoids re-parsing the hex, but alpha is a continuous float so the full\n // rgba string can't be pre-computed. Fix: discretize alpha into N buckets at init\n // and do a lookup (e.g. trailColors[Math.round(progress * N)]) instead of a template literal.\n ctx.strokeStyle = `rgba(${trailRgb},${alpha})`;\n ctx.lineWidth = lineWidth;\n ctx.stroke();\n }\n }\n\n function drawHead() {\n if (!head) {\n return;\n }\n\n const x = head.x * scale + offsetX;\n const y = head.y * scale + offsetY;\n\n const gradient = ctx.createRadialGradient(x, y, 0, x, y, opts.glowSize);\n gradient.addColorStop(0, opts.headColor);\n gradient.addColorStop(GLOW_INNER_EDGE, headRgbFalloff);\n gradient.addColorStop(1, \"transparent\");\n\n ctx.fillStyle = gradient;\n ctx.beginPath();\n ctx.arc(x, y, opts.glowSize, 0, Math.PI * 2);\n ctx.fill();\n\n ctx.fillStyle = opts.headColor;\n ctx.beginPath();\n ctx.arc(x, y, opts.headRadius, 0, Math.PI * 2);\n ctx.fill();\n }\n\n function render() {\n const now = performance.now();\n const deltaTime = Math.min((now - lastTime) / 1000, 1 / 30);\n lastTime = now;\n\n trail = engine.tick(deltaTime);\n trailCount = engine.trailCount;\n head = trailCount > 0 ? trail[trailCount - 1]! : null;\n\n ctx.clearRect(0, 0, canvas.width, canvas.height);\n\n drawSkeleton();\n drawTrail();\n drawHead();\n\n animationId = requestAnimationFrame(render);\n }\n\n // Initialize skeleton and offscreen canvas on creation\n skeleton = engine.getSarmalSkeleton();\n calculateBoundaries();\n buildSkeletonCanvas();\n\n return {\n start() {\n if (animationId !== null) {\n return;\n }\n\n lastTime = performance.now();\n render();\n },\n\n stop() {\n if (animationId === null) {\n return;\n }\n\n cancelAnimationFrame(animationId);\n animationId = null;\n },\n\n reset() {\n engine.reset();\n trail = [];\n head = null;\n },\n\n destroy() {\n if (animationId !== null) {\n cancelAnimationFrame(animationId);\n animationId = null;\n }\n },\n\n seek(t, options) {\n engine.seek(t, options);\n },\n\n seekWithTrail(t) {\n engine.seekWithTrail(t);\n },\n };\n}\n","import type { CurveDef, Engine, Point, SarmalInstance } from \"./types\";\nimport { createEngine } from \"./engine\";\n\nconst TRAIL_BATCH_COUNT = 12;\n/** Higher values = sharper fade near the tail */\nconst TRAIL_FADE_CURVE = 1.5;\nconst TRAIL_MAX_OPACITY = 0.88;\n/** Stroke width at the tail */\nconst TRAIL_MIN_WIDTH = 0.5;\n/** Stroke width at the head */\nconst TRAIL_MAX_WIDTH = 2.5;\nconst DEFAULT_SKELETON_OPACITY = 0.15;\nconst DEFAULT_GLOW_INNER_STOP = 0.4;\nconst DEFAULT_GLOW_FALLOFF_OPACITY = 0.53;\n/** Fraction of the bounding box added as padding when auto-fitting the curve */\nconst FIT_PADDING = 0.1;\n\nlet instanceCount = 0;\n\nexport interface SVGRendererOptions {\n /** Container element that will contain the SVG */\n container: Element;\n engine: Engine;\n /** @default '#ffffff' */\n skeletonColor?: string;\n /** @default '#ffffff' */\n trailColor?: string;\n /** @default '#ffffff' */\n headColor?: string;\n /** @default 4 */\n headRadius?: number;\n /** @default 20 */\n glowSize?: number;\n /** @default 'Loading' */\n ariaLabel?: string;\n}\n\nexport interface SVGSarmalOptions extends Omit<SVGRendererOptions, \"container\" | \"engine\"> {\n /** @default 120 */\n trailLength?: number;\n}\n\nfunction el(tag: string): SVGElement {\n return document.createElementNS(\"http://www.w3.org/2000/svg\", tag);\n}\n\n/**\n * Creates a live SVG renderer for sarmal animations\n * The SVG is appended into `container` and updated each frame via **requestAnimationFrame**\n */\nexport function createSVGRenderer(options: SVGRendererOptions): SarmalInstance {\n const { container, engine } = options;\n const opts = {\n skeletonColor: options.skeletonColor ?? \"#ffffff\",\n trailColor: options.trailColor ?? \"#ffffff\",\n headColor: options.headColor ?? \"#ffffff\",\n headRadius: options.headRadius ?? 4,\n glowSize: options.glowSize ?? 20,\n ariaLabel: options.ariaLabel ?? \"Loading\",\n };\n\n // Unique per-instance ID prevents ID collisions of multiple instances\n const uid = ++instanceCount;\n const gradientId = `sarmal-glow-${uid}`;\n\n const rect = container.getBoundingClientRect();\n const width = rect.width || 200;\n const height = rect.height || 200;\n\n const svg = el(\"svg\") as SVGSVGElement;\n svg.setAttribute(\"width\", String(width));\n svg.setAttribute(\"height\", String(height));\n svg.setAttribute(\"viewBox\", `0 0 ${width} ${height}`);\n svg.setAttribute(\"role\", \"img\");\n svg.setAttribute(\"aria-label\", opts.ariaLabel);\n\n const titleEl = el(\"title\");\n titleEl.textContent = opts.ariaLabel;\n svg.appendChild(titleEl);\n\n const defs = el(\"defs\");\n const gradient = el(\"radialGradient\") as SVGRadialGradientElement;\n gradient.id = gradientId;\n gradient.setAttribute(\"cx\", \"50%\");\n gradient.setAttribute(\"cy\", \"50%\");\n gradient.setAttribute(\"r\", \"50%\");\n const stop0 = el(\"stop\");\n stop0.setAttribute(\"offset\", \"0%\");\n stop0.setAttribute(\"stop-color\", opts.headColor);\n stop0.setAttribute(\"stop-opacity\", \"1\");\n const stopMid = el(\"stop\");\n stopMid.setAttribute(\"offset\", `${DEFAULT_GLOW_INNER_STOP * 100}%`);\n stopMid.setAttribute(\"stop-color\", opts.headColor);\n stopMid.setAttribute(\"stop-opacity\", String(DEFAULT_GLOW_FALLOFF_OPACITY));\n const stop1 = el(\"stop\");\n stop1.setAttribute(\"offset\", \"100%\");\n stop1.setAttribute(\"stop-color\", opts.headColor);\n stop1.setAttribute(\"stop-opacity\", \"0\");\n gradient.append(stop0, stopMid, stop1);\n defs.appendChild(gradient);\n svg.appendChild(defs);\n\n const skeletonPath = el(\"path\") as SVGPathElement;\n skeletonPath.setAttribute(\"fill\", \"none\");\n skeletonPath.setAttribute(\"stroke\", opts.skeletonColor);\n skeletonPath.setAttribute(\"stroke-opacity\", String(DEFAULT_SKELETON_OPACITY));\n skeletonPath.setAttribute(\"stroke-width\", \"1.5\");\n svg.appendChild(skeletonPath);\n\n const trailPaths: SVGPathElement[] = [];\n for (let i = 0; i < TRAIL_BATCH_COUNT; i++) {\n const path = el(\"path\") as SVGPathElement;\n path.setAttribute(\"fill\", \"none\");\n path.setAttribute(\"stroke\", opts.trailColor);\n path.setAttribute(\"stroke-linecap\", \"round\");\n path.setAttribute(\"stroke-linejoin\", \"round\");\n svg.appendChild(path);\n trailPaths.push(path);\n }\n\n const glowCircle = el(\"circle\") as SVGCircleElement;\n glowCircle.setAttribute(\"fill\", `url(#${gradientId})`);\n glowCircle.setAttribute(\"r\", String(opts.glowSize));\n svg.appendChild(glowCircle);\n\n const headCircle = el(\"circle\") as SVGCircleElement;\n headCircle.setAttribute(\"fill\", opts.headColor);\n headCircle.setAttribute(\"r\", String(opts.headRadius));\n svg.appendChild(headCircle);\n\n container.appendChild(svg);\n\n let scale = 1;\n let offsetX = 0;\n let offsetY = 0;\n\n function calculateBoundaries(skeleton: Point[]) {\n if (skeleton.length === 0) {\n return;\n }\n\n const first = skeleton[0]!;\n let minX = first.x,\n maxX = first.x,\n minY = first.y,\n maxY = first.y;\n\n for (const p of skeleton) {\n if (p.x < minX) {\n minX = p.x;\n }\n\n if (p.x > maxX) {\n maxX = p.x;\n }\n\n if (p.y < minY) {\n minY = p.y;\n }\n\n if (p.y > maxY) {\n maxY = p.y;\n }\n }\n\n const w = maxX - minX;\n const h = maxY - minY;\n const scaleX = width / (w * (1 + FIT_PADDING * 2));\n const scaleY = height / (h * (1 + FIT_PADDING * 2));\n\n scale = Math.min(scaleX, scaleY);\n offsetX = (width - w * scale) / 2 - minX * scale;\n offsetY = (height - h * scale) / 2 - minY * scale;\n }\n\n // TODO: might avoid code repetition\n function px(p: Point) {\n return (p.x * scale + offsetX).toFixed(2);\n }\n function py(p: Point) {\n return (p.y * scale + offsetY).toFixed(2);\n }\n\n const skeleton = engine.getSarmalSkeleton();\n calculateBoundaries(skeleton);\n\n if (skeleton.length >= 2) {\n let d = `M${px(skeleton[0]!)} ${py(skeleton[0]!)}`;\n\n for (let i = 1; i < skeleton.length; i++) {\n d += ` L${px(skeleton[i]!)} ${py(skeleton[i]!)}`;\n }\n d += \" Z\";\n\n skeletonPath.setAttribute(\"d\", d);\n }\n\n function updateTrail(trail: Point[], trailCount: number) {\n if (trailCount < 2) {\n for (const p of trailPaths) {\n p.setAttribute(\"d\", \"\");\n }\n\n return;\n }\n const batchSize = Math.ceil(trailCount / TRAIL_BATCH_COUNT);\n\n for (let b = 0; b < TRAIL_BATCH_COUNT; b++) {\n const start = b * batchSize;\n const end = Math.min(start + batchSize, trailCount - 1);\n if (start >= trailCount - 1) {\n trailPaths[b]!.setAttribute(\"d\", \"\");\n continue;\n }\n const progress = (start + end) / 2 / (trailCount - 1);\n const opacity = Math.pow(progress, TRAIL_FADE_CURVE) * TRAIL_MAX_OPACITY;\n const strokeWidth = TRAIL_MIN_WIDTH + progress * (TRAIL_MAX_WIDTH - TRAIL_MIN_WIDTH);\n\n let d = `M${px(trail[start]!)} ${py(trail[start]!)}`;\n for (let i = start + 1; i <= end; i++) {\n d += ` L${px(trail[i]!)} ${py(trail[i]!)}`;\n }\n\n trailPaths[b]!.setAttribute(\"d\", d);\n trailPaths[b]!.setAttribute(\"stroke-opacity\", opacity.toFixed(3));\n trailPaths[b]!.setAttribute(\"stroke-width\", strokeWidth.toFixed(2));\n }\n }\n\n function updateHead(trail: Point[], trailCount: number) {\n if (trailCount === 0) {\n return;\n }\n\n const head = trail[trailCount - 1]!;\n const x = px(head);\n const y = py(head);\n\n glowCircle.setAttribute(\"cx\", x);\n glowCircle.setAttribute(\"cy\", y);\n headCircle.setAttribute(\"cx\", x);\n headCircle.setAttribute(\"cy\", y);\n }\n\n let animationId: number | null = null;\n let lastTime = 0;\n const prefersReducedMotion =\n typeof window !== \"undefined\" && window.matchMedia(\"(prefers-reduced-motion: reduce)\").matches;\n\n function renderFrame() {\n const now = performance.now();\n const dt = Math.min((now - lastTime) / 1000, 1 / 30);\n lastTime = now;\n\n const trail = engine.tick(dt);\n const trailCount = engine.trailCount;\n\n updateTrail(trail, trailCount);\n updateHead(trail, trailCount);\n\n if (!prefersReducedMotion) {\n animationId = requestAnimationFrame(renderFrame);\n }\n }\n\n return {\n start() {\n if (animationId !== null) {\n return;\n }\n lastTime = performance.now();\n renderFrame();\n },\n\n stop() {\n if (animationId === null) {\n return;\n }\n cancelAnimationFrame(animationId);\n animationId = null;\n },\n\n reset() {\n engine.reset();\n },\n\n destroy() {\n if (animationId !== null) {\n cancelAnimationFrame(animationId);\n animationId = null;\n }\n svg.remove();\n },\n\n seek(t, options) {\n engine.seek(t, options);\n },\n\n seekWithTrail(t) {\n engine.seekWithTrail(t);\n },\n };\n}\n\n/**\n * Creates a sarmal animation inside a container element using an SVG renderer\n * The SVG is appended to the container and animated via requestAnimationFrame\n *\n * @example\n * ```ts\n * import { createSarmalSVG, curves } from '@sarmal/core'\n * const sarmal = createSarmalSVG(document.getElementById('spinner'), curves.epitrochoid7)\n * sarmal.start()\n * ```\n */\nexport function createSarmalSVG(\n container: Element,\n curveDef: CurveDef,\n options?: SVGSarmalOptions,\n): SarmalInstance {\n const { trailLength, ...rendererOpts } = options ?? {};\n const engine = createEngine(curveDef, trailLength);\n return createSVGRenderer({ container, engine, ...rendererOpts });\n}\n","import type { CurveDef, Point } from \"./types\";\n\nconst TWO_PI = Math.PI * 2;\n\n/**\n * Artemis II free-return lunar trajectory\n * @see https://www.nasa.gov/wp-content/uploads/2025/09/artemis-ii-map-508.pdf\n * a = x-axis asymmetry (widens one lobe),\n * b = y-axis asymmetry,\n * ox = horizontal offset to visually center the shape\n */\nfunction artemis2(t: number, _time: number, _params: Record<string, number>): Point {\n const a = 0.35,\n b = 0.15,\n ox = 0.175;\n const s = Math.sin(t),\n c = Math.cos(t);\n const denom = 1 + s * s;\n return {\n x: (c * (1 + a * c)) / denom - ox,\n y: (s * c * (1 + b * c)) / denom,\n };\n}\n\nfunction epitrochoid7(t: number, _time: number, _params: Record<string, number>): Point {\n const d = 1.0 + 0.55 * Math.sin(t * 0.5);\n return {\n x: 7 * Math.cos(t) - d * Math.cos(7 * t),\n y: 7 * Math.sin(t) - d * Math.sin(7 * t),\n };\n}\n\nfunction astroid(t: number, _time: number, _params: Record<string, number>): Point {\n const c = Math.cos(t);\n const s = Math.sin(t);\n return {\n x: c * c * c,\n y: s * s * s,\n };\n}\n\nfunction deltoid(t: number, _time: number, _params: Record<string, number>): Point {\n return {\n x: 2 * Math.cos(t) + Math.cos(2 * t),\n y: 2 * Math.sin(t) - Math.sin(2 * t),\n };\n}\n\nfunction rose5(t: number, _time: number, _params: Record<string, number>): Point {\n const r = Math.cos(5 * t);\n return {\n x: r * Math.cos(t),\n y: r * Math.sin(t),\n };\n}\n\nfunction rose3(t: number, _time: number, _params: Record<string, number>): Point {\n const r = Math.cos(3 * t);\n return {\n x: r * Math.cos(t),\n y: r * Math.sin(t),\n };\n}\n\nfunction lissajous32(t: number, time: number, _params: Record<string, number>): Point {\n const phi = time * 0.45;\n return {\n x: Math.sin(3 * t + phi),\n y: Math.sin(2 * t),\n };\n}\n\nfunction lissajous43(t: number, time: number, _params: Record<string, number>): Point {\n const phi = time * 0.38;\n return {\n x: Math.sin(4 * t + phi),\n y: Math.sin(3 * t),\n };\n}\n\nfunction epicycloid3(t: number, _time: number, _params: Record<string, number>): Point {\n return {\n x: 4 * Math.cos(t) - Math.cos(4 * t),\n y: 4 * Math.sin(t) - Math.sin(4 * t),\n };\n}\n\nfunction lame(t: number, time: number, _params: Record<string, number>): Point {\n const p = 1.75 + 1.25 * Math.sin(time * 0.48);\n const c = Math.cos(t),\n s = Math.sin(t);\n return {\n x: Math.sign(c) * Math.pow(Math.abs(c), p),\n y: Math.sign(s) * Math.pow(Math.abs(s), p),\n };\n}\nexport const curves: Record<string, CurveDef> = {\n artemis2: {\n name: \"Artemis II\",\n fn: artemis2,\n period: TWO_PI,\n speed: 0.7,\n },\n epitrochoid7: {\n name: \"Epitrochoid\",\n fn: epitrochoid7,\n period: TWO_PI,\n speed: 1.4,\n },\n astroid: {\n name: \"Astroid\",\n fn: astroid,\n period: TWO_PI,\n speed: 1.1,\n },\n deltoid: {\n name: \"Deltoid\",\n fn: deltoid,\n period: TWO_PI,\n speed: 0.9,\n },\n rose5: {\n name: \"Rose (n=5)\",\n fn: rose5,\n period: TWO_PI,\n speed: 1.0,\n },\n rose3: {\n name: \"Rose (n=3)\",\n fn: rose3,\n period: TWO_PI,\n speed: 1.15,\n },\n lissajous32: {\n name: \"Lissajous 3:2\",\n fn: lissajous32,\n period: TWO_PI,\n speed: 2.0,\n },\n lissajous43: {\n name: \"Lissajous 4:3\",\n fn: lissajous43,\n period: TWO_PI,\n speed: 1.8,\n },\n epicycloid3: {\n name: \"Epicycloid (n=3)\",\n fn: epicycloid3,\n period: TWO_PI,\n speed: 0.75,\n },\n lame: {\n name: \"Lamé Curve\",\n fn: lame,\n period: TWO_PI,\n speed: 1.0,\n },\n};\n","export type { SVGRendererOptions, SVGSarmalOptions } from \"./renderer-svg\";\nexport type {\n Point,\n CurveDef,\n Engine,\n SarmalInstance,\n SeekOptions,\n SeekWithTrailOptions,\n RendererOptions,\n SarmalOptions,\n} from \"./types\";\n\nexport { createEngine } from \"./engine\";\nexport { createRenderer } from \"./renderer\";\nexport { createSVGRenderer, createSarmalSVG } from \"./renderer-svg\";\nexport { curves } from \"./curves\";\n\nimport type { CurveDef, SarmalInstance, SarmalOptions } from \"./types\";\nimport { createEngine } from \"./engine\";\nimport { createRenderer } from \"./renderer\";\n\n/**\n * Creates a sarmal animation on a canvas element\n *\n * @example\n * ```ts\n * import { createSarmal, curves } from '@sarmal/core'\n * const sarmal = createSarmal(canvas, curves.artemis2)\n * sarmal.start()\n * ```\n */\nexport function createSarmal(\n canvas: HTMLCanvasElement,\n curveDef: CurveDef,\n options?: SarmalOptions,\n): SarmalInstance {\n const { trailLength, ...rendererOpts } = options ?? {};\n const engine = createEngine(curveDef, trailLength);\n\n return createRenderer({ canvas, engine, ...rendererOpts });\n}\n"]}
|