@sarmal/core 0.2.1 → 0.3.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/README.md +7 -0
- package/dist/auto-init.cjs +98 -28
- package/dist/auto-init.cjs.map +1 -1
- package/dist/auto-init.js +98 -28
- package/dist/auto-init.js.map +1 -1
- package/dist/index.cjs +318 -28
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +46 -7
- package/dist/index.d.ts +46 -7
- package/dist/index.js +317 -29
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -9,7 +9,7 @@ var CircularBuffer = class {
|
|
|
9
9
|
this.data = Array.from({ length: capacity }, () => ({ x: 0, y: 0 }));
|
|
10
10
|
this.result = Array.from({ length: capacity }, () => ({ x: 0, y: 0 }));
|
|
11
11
|
}
|
|
12
|
-
/** Mutates
|
|
12
|
+
/** Mutates in-place */
|
|
13
13
|
push(x, y) {
|
|
14
14
|
const slot = this.data[this.head];
|
|
15
15
|
slot.x = x;
|
|
@@ -20,9 +20,9 @@ var CircularBuffer = class {
|
|
|
20
20
|
}
|
|
21
21
|
}
|
|
22
22
|
/**
|
|
23
|
-
* Copies ordered points into the pre-allocated result buffer and returns it
|
|
24
|
-
* The same array reference is returned every call
|
|
25
|
-
*
|
|
23
|
+
* Copies ordered points into the pre-allocated result buffer and returns it
|
|
24
|
+
* Note: The *same* array reference is returned every call,
|
|
25
|
+
* so `result.length` is also always `capacity`
|
|
26
26
|
*/
|
|
27
27
|
toArray() {
|
|
28
28
|
const start = this.count < this.capacity ? 0 : this.head;
|
|
@@ -131,10 +131,18 @@ function createRenderer(options) {
|
|
|
131
131
|
const first = skeleton[0];
|
|
132
132
|
let minX = first.x, maxX = first.x, minY = first.y, maxY = first.y;
|
|
133
133
|
for (const p of skeleton) {
|
|
134
|
-
if (p.x < minX)
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
if (p.
|
|
134
|
+
if (p.x < minX) {
|
|
135
|
+
minX = p.x;
|
|
136
|
+
}
|
|
137
|
+
if (p.x > maxX) {
|
|
138
|
+
maxX = p.x;
|
|
139
|
+
}
|
|
140
|
+
if (p.y < minY) {
|
|
141
|
+
minY = p.y;
|
|
142
|
+
}
|
|
143
|
+
if (p.y > maxY) {
|
|
144
|
+
maxY = p.y;
|
|
145
|
+
}
|
|
138
146
|
}
|
|
139
147
|
const width = maxX - minX;
|
|
140
148
|
const height = maxY - minY;
|
|
@@ -151,38 +159,42 @@ function createRenderer(options) {
|
|
|
151
159
|
function buildSkeletonCanvas() {
|
|
152
160
|
if (skeleton.length < 2) return;
|
|
153
161
|
skeletonCanvas = new OffscreenCanvas(canvas.width, canvas.height);
|
|
154
|
-
const
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
162
|
+
const skeletonCtx = skeletonCanvas.getContext("2d");
|
|
163
|
+
skeletonCtx.strokeStyle = `rgba(${hexToRgbComponents(opts.skeletonColor)},${DEFAULT_SKELETON_OPACITY})`;
|
|
164
|
+
skeletonCtx.lineWidth = 1.5;
|
|
165
|
+
skeletonCtx.beginPath();
|
|
158
166
|
const first = skeleton[0];
|
|
159
|
-
|
|
167
|
+
skeletonCtx.moveTo(first.x * scale + offsetX, first.y * scale + offsetY);
|
|
160
168
|
for (let i = 1; i < skeleton.length; i++) {
|
|
161
169
|
const p = skeleton[i];
|
|
162
|
-
|
|
170
|
+
skeletonCtx.lineTo(p.x * scale + offsetX, p.y * scale + offsetY);
|
|
163
171
|
}
|
|
164
|
-
|
|
172
|
+
skeletonCtx.stroke();
|
|
165
173
|
}
|
|
166
174
|
function drawSkeleton() {
|
|
167
|
-
if (!skeletonCanvas)
|
|
175
|
+
if (!skeletonCanvas) {
|
|
176
|
+
return;
|
|
177
|
+
}
|
|
168
178
|
ctx.drawImage(skeletonCanvas, 0, 0);
|
|
169
179
|
}
|
|
170
180
|
function drawTrail() {
|
|
171
|
-
if (trailCount < 2)
|
|
181
|
+
if (trailCount < 2) {
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
172
184
|
ctx.lineJoin = "round";
|
|
173
185
|
ctx.lineCap = "round";
|
|
174
|
-
for (let
|
|
175
|
-
const bEnd = Math.min(
|
|
176
|
-
const progress = (
|
|
186
|
+
for (let batchIndex = 0; batchIndex < trailCount - 1; batchIndex += TRAIL_BATCH_SIZE) {
|
|
187
|
+
const bEnd = Math.min(batchIndex + TRAIL_BATCH_SIZE, trailCount - 1);
|
|
188
|
+
const progress = (batchIndex + bEnd) / 2 / (trailCount - 1);
|
|
177
189
|
const alpha = Math.pow(progress, TRAIL_FADE_CURVE) * TRAIL_MAX_OPACITY;
|
|
178
190
|
const lineWidth = TRAIL_MIN_WIDTH + progress * (TRAIL_MAX_WIDTH - TRAIL_MIN_WIDTH);
|
|
179
191
|
ctx.beginPath();
|
|
180
|
-
for (let i =
|
|
181
|
-
const
|
|
182
|
-
if (i ===
|
|
183
|
-
ctx.moveTo(
|
|
192
|
+
for (let i = batchIndex; i <= bEnd; i++) {
|
|
193
|
+
const point = trail[i];
|
|
194
|
+
if (i === batchIndex) {
|
|
195
|
+
ctx.moveTo(point.x * scale + offsetX, point.y * scale + offsetY);
|
|
184
196
|
} else {
|
|
185
|
-
ctx.lineTo(
|
|
197
|
+
ctx.lineTo(point.x * scale + offsetX, point.y * scale + offsetY);
|
|
186
198
|
}
|
|
187
199
|
}
|
|
188
200
|
ctx.strokeStyle = `rgba(${trailRgb},${alpha})`;
|
|
@@ -191,7 +203,9 @@ function createRenderer(options) {
|
|
|
191
203
|
}
|
|
192
204
|
}
|
|
193
205
|
function drawHead() {
|
|
194
|
-
if (!head)
|
|
206
|
+
if (!head) {
|
|
207
|
+
return;
|
|
208
|
+
}
|
|
195
209
|
const x = head.x * scale + offsetX;
|
|
196
210
|
const y = head.y * scale + offsetY;
|
|
197
211
|
const gradient = ctx.createRadialGradient(x, y, 0, x, y, opts.glowSize);
|
|
@@ -225,12 +239,16 @@ function createRenderer(options) {
|
|
|
225
239
|
buildSkeletonCanvas();
|
|
226
240
|
return {
|
|
227
241
|
start() {
|
|
228
|
-
if (animationId !== null)
|
|
242
|
+
if (animationId !== null) {
|
|
243
|
+
return;
|
|
244
|
+
}
|
|
229
245
|
lastTime = performance.now();
|
|
230
246
|
render();
|
|
231
247
|
},
|
|
232
248
|
stop() {
|
|
233
|
-
if (animationId === null)
|
|
249
|
+
if (animationId === null) {
|
|
250
|
+
return;
|
|
251
|
+
}
|
|
234
252
|
cancelAnimationFrame(animationId);
|
|
235
253
|
animationId = null;
|
|
236
254
|
},
|
|
@@ -248,6 +266,224 @@ function createRenderer(options) {
|
|
|
248
266
|
};
|
|
249
267
|
}
|
|
250
268
|
|
|
269
|
+
// src/renderer-svg.ts
|
|
270
|
+
var TRAIL_BATCH_COUNT = 12;
|
|
271
|
+
var TRAIL_FADE_CURVE2 = 1.5;
|
|
272
|
+
var TRAIL_MAX_OPACITY2 = 0.88;
|
|
273
|
+
var TRAIL_MIN_WIDTH2 = 0.5;
|
|
274
|
+
var TRAIL_MAX_WIDTH2 = 2.5;
|
|
275
|
+
var DEFAULT_SKELETON_OPACITY2 = 0.15;
|
|
276
|
+
var DEFAULT_GLOW_INNER_STOP = 0.4;
|
|
277
|
+
var DEFAULT_GLOW_FALLOFF_OPACITY = 0.53;
|
|
278
|
+
var FIT_PADDING2 = 0.1;
|
|
279
|
+
var instanceCount = 0;
|
|
280
|
+
function el(tag) {
|
|
281
|
+
return document.createElementNS("http://www.w3.org/2000/svg", tag);
|
|
282
|
+
}
|
|
283
|
+
function createSVGRenderer(options) {
|
|
284
|
+
const { container, engine } = options;
|
|
285
|
+
const opts = {
|
|
286
|
+
skeletonColor: options.skeletonColor ?? "#ffffff",
|
|
287
|
+
trailColor: options.trailColor ?? "#ffffff",
|
|
288
|
+
headColor: options.headColor ?? "#ffffff",
|
|
289
|
+
headRadius: options.headRadius ?? 4,
|
|
290
|
+
glowSize: options.glowSize ?? 20,
|
|
291
|
+
ariaLabel: options.ariaLabel ?? "Loading"
|
|
292
|
+
};
|
|
293
|
+
const uid = ++instanceCount;
|
|
294
|
+
const gradientId = `sarmal-glow-${uid}`;
|
|
295
|
+
const rect = container.getBoundingClientRect();
|
|
296
|
+
const width = rect.width || 200;
|
|
297
|
+
const height = rect.height || 200;
|
|
298
|
+
const svg = el("svg");
|
|
299
|
+
svg.setAttribute("width", String(width));
|
|
300
|
+
svg.setAttribute("height", String(height));
|
|
301
|
+
svg.setAttribute("viewBox", `0 0 ${width} ${height}`);
|
|
302
|
+
svg.setAttribute("role", "img");
|
|
303
|
+
svg.setAttribute("aria-label", opts.ariaLabel);
|
|
304
|
+
const titleEl = el("title");
|
|
305
|
+
titleEl.textContent = opts.ariaLabel;
|
|
306
|
+
svg.appendChild(titleEl);
|
|
307
|
+
const defs = el("defs");
|
|
308
|
+
const gradient = el("radialGradient");
|
|
309
|
+
gradient.id = gradientId;
|
|
310
|
+
gradient.setAttribute("cx", "50%");
|
|
311
|
+
gradient.setAttribute("cy", "50%");
|
|
312
|
+
gradient.setAttribute("r", "50%");
|
|
313
|
+
const stop0 = el("stop");
|
|
314
|
+
stop0.setAttribute("offset", "0%");
|
|
315
|
+
stop0.setAttribute("stop-color", opts.headColor);
|
|
316
|
+
stop0.setAttribute("stop-opacity", "1");
|
|
317
|
+
const stopMid = el("stop");
|
|
318
|
+
stopMid.setAttribute("offset", `${DEFAULT_GLOW_INNER_STOP * 100}%`);
|
|
319
|
+
stopMid.setAttribute("stop-color", opts.headColor);
|
|
320
|
+
stopMid.setAttribute("stop-opacity", String(DEFAULT_GLOW_FALLOFF_OPACITY));
|
|
321
|
+
const stop1 = el("stop");
|
|
322
|
+
stop1.setAttribute("offset", "100%");
|
|
323
|
+
stop1.setAttribute("stop-color", opts.headColor);
|
|
324
|
+
stop1.setAttribute("stop-opacity", "0");
|
|
325
|
+
gradient.append(stop0, stopMid, stop1);
|
|
326
|
+
defs.appendChild(gradient);
|
|
327
|
+
svg.appendChild(defs);
|
|
328
|
+
const skeletonPath = el("path");
|
|
329
|
+
skeletonPath.setAttribute("fill", "none");
|
|
330
|
+
skeletonPath.setAttribute("stroke", opts.skeletonColor);
|
|
331
|
+
skeletonPath.setAttribute("stroke-opacity", String(DEFAULT_SKELETON_OPACITY2));
|
|
332
|
+
skeletonPath.setAttribute("stroke-width", "1.5");
|
|
333
|
+
svg.appendChild(skeletonPath);
|
|
334
|
+
const trailPaths = [];
|
|
335
|
+
for (let i = 0; i < TRAIL_BATCH_COUNT; i++) {
|
|
336
|
+
const path = el("path");
|
|
337
|
+
path.setAttribute("fill", "none");
|
|
338
|
+
path.setAttribute("stroke", opts.trailColor);
|
|
339
|
+
path.setAttribute("stroke-linecap", "round");
|
|
340
|
+
path.setAttribute("stroke-linejoin", "round");
|
|
341
|
+
svg.appendChild(path);
|
|
342
|
+
trailPaths.push(path);
|
|
343
|
+
}
|
|
344
|
+
const glowCircle = el("circle");
|
|
345
|
+
glowCircle.setAttribute("fill", `url(#${gradientId})`);
|
|
346
|
+
glowCircle.setAttribute("r", String(opts.glowSize));
|
|
347
|
+
svg.appendChild(glowCircle);
|
|
348
|
+
const headCircle = el("circle");
|
|
349
|
+
headCircle.setAttribute("fill", opts.headColor);
|
|
350
|
+
headCircle.setAttribute("r", String(opts.headRadius));
|
|
351
|
+
svg.appendChild(headCircle);
|
|
352
|
+
container.appendChild(svg);
|
|
353
|
+
let scale = 1;
|
|
354
|
+
let offsetX = 0;
|
|
355
|
+
let offsetY = 0;
|
|
356
|
+
function calculateBoundaries(skeleton2) {
|
|
357
|
+
if (skeleton2.length === 0) {
|
|
358
|
+
return;
|
|
359
|
+
}
|
|
360
|
+
const first = skeleton2[0];
|
|
361
|
+
let minX = first.x, maxX = first.x, minY = first.y, maxY = first.y;
|
|
362
|
+
for (const p of skeleton2) {
|
|
363
|
+
if (p.x < minX) {
|
|
364
|
+
minX = p.x;
|
|
365
|
+
}
|
|
366
|
+
if (p.x > maxX) {
|
|
367
|
+
maxX = p.x;
|
|
368
|
+
}
|
|
369
|
+
if (p.y < minY) {
|
|
370
|
+
minY = p.y;
|
|
371
|
+
}
|
|
372
|
+
if (p.y > maxY) {
|
|
373
|
+
maxY = p.y;
|
|
374
|
+
}
|
|
375
|
+
}
|
|
376
|
+
const w = maxX - minX;
|
|
377
|
+
const h = maxY - minY;
|
|
378
|
+
const scaleX = width / (w * (1 + FIT_PADDING2 * 2));
|
|
379
|
+
const scaleY = height / (h * (1 + FIT_PADDING2 * 2));
|
|
380
|
+
scale = Math.min(scaleX, scaleY);
|
|
381
|
+
offsetX = (width - w * scale) / 2 - minX * scale;
|
|
382
|
+
offsetY = (height - h * scale) / 2 - minY * scale;
|
|
383
|
+
}
|
|
384
|
+
function px(p) {
|
|
385
|
+
return (p.x * scale + offsetX).toFixed(2);
|
|
386
|
+
}
|
|
387
|
+
function py(p) {
|
|
388
|
+
return (p.y * scale + offsetY).toFixed(2);
|
|
389
|
+
}
|
|
390
|
+
const skeleton = engine.getSarmalSkeleton();
|
|
391
|
+
calculateBoundaries(skeleton);
|
|
392
|
+
if (skeleton.length >= 2) {
|
|
393
|
+
let d = `M${px(skeleton[0])} ${py(skeleton[0])}`;
|
|
394
|
+
for (let i = 1; i < skeleton.length; i++) {
|
|
395
|
+
d += ` L${px(skeleton[i])} ${py(skeleton[i])}`;
|
|
396
|
+
}
|
|
397
|
+
d += " Z";
|
|
398
|
+
skeletonPath.setAttribute("d", d);
|
|
399
|
+
}
|
|
400
|
+
function updateTrail(trail, trailCount) {
|
|
401
|
+
if (trailCount < 2) {
|
|
402
|
+
for (const p of trailPaths) {
|
|
403
|
+
p.setAttribute("d", "");
|
|
404
|
+
}
|
|
405
|
+
return;
|
|
406
|
+
}
|
|
407
|
+
const batchSize = Math.ceil(trailCount / TRAIL_BATCH_COUNT);
|
|
408
|
+
for (let b = 0; b < TRAIL_BATCH_COUNT; b++) {
|
|
409
|
+
const start = b * batchSize;
|
|
410
|
+
const end = Math.min(start + batchSize, trailCount - 1);
|
|
411
|
+
if (start >= trailCount - 1) {
|
|
412
|
+
trailPaths[b].setAttribute("d", "");
|
|
413
|
+
continue;
|
|
414
|
+
}
|
|
415
|
+
const progress = (start + end) / 2 / (trailCount - 1);
|
|
416
|
+
const opacity = Math.pow(progress, TRAIL_FADE_CURVE2) * TRAIL_MAX_OPACITY2;
|
|
417
|
+
const strokeWidth = TRAIL_MIN_WIDTH2 + progress * (TRAIL_MAX_WIDTH2 - TRAIL_MIN_WIDTH2);
|
|
418
|
+
let d = `M${px(trail[start])} ${py(trail[start])}`;
|
|
419
|
+
for (let i = start + 1; i <= end; i++) {
|
|
420
|
+
d += ` L${px(trail[i])} ${py(trail[i])}`;
|
|
421
|
+
}
|
|
422
|
+
trailPaths[b].setAttribute("d", d);
|
|
423
|
+
trailPaths[b].setAttribute("stroke-opacity", opacity.toFixed(3));
|
|
424
|
+
trailPaths[b].setAttribute("stroke-width", strokeWidth.toFixed(2));
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
function updateHead(trail, trailCount) {
|
|
428
|
+
if (trailCount === 0) {
|
|
429
|
+
return;
|
|
430
|
+
}
|
|
431
|
+
const head = trail[trailCount - 1];
|
|
432
|
+
const x = px(head);
|
|
433
|
+
const y = py(head);
|
|
434
|
+
glowCircle.setAttribute("cx", x);
|
|
435
|
+
glowCircle.setAttribute("cy", y);
|
|
436
|
+
headCircle.setAttribute("cx", x);
|
|
437
|
+
headCircle.setAttribute("cy", y);
|
|
438
|
+
}
|
|
439
|
+
let animationId = null;
|
|
440
|
+
let lastTime = 0;
|
|
441
|
+
const prefersReducedMotion = typeof window !== "undefined" && window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
442
|
+
function renderFrame() {
|
|
443
|
+
const now = performance.now();
|
|
444
|
+
const dt = (now - lastTime) / 1e3;
|
|
445
|
+
lastTime = now;
|
|
446
|
+
const trail = engine.tick(dt);
|
|
447
|
+
const trailCount = engine.trailCount;
|
|
448
|
+
updateTrail(trail, trailCount);
|
|
449
|
+
updateHead(trail, trailCount);
|
|
450
|
+
if (!prefersReducedMotion) {
|
|
451
|
+
animationId = requestAnimationFrame(renderFrame);
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
return {
|
|
455
|
+
start() {
|
|
456
|
+
if (animationId !== null) {
|
|
457
|
+
return;
|
|
458
|
+
}
|
|
459
|
+
lastTime = performance.now();
|
|
460
|
+
renderFrame();
|
|
461
|
+
},
|
|
462
|
+
stop() {
|
|
463
|
+
if (animationId === null) {
|
|
464
|
+
return;
|
|
465
|
+
}
|
|
466
|
+
cancelAnimationFrame(animationId);
|
|
467
|
+
animationId = null;
|
|
468
|
+
},
|
|
469
|
+
reset() {
|
|
470
|
+
engine.reset();
|
|
471
|
+
},
|
|
472
|
+
destroy() {
|
|
473
|
+
if (animationId !== null) {
|
|
474
|
+
cancelAnimationFrame(animationId);
|
|
475
|
+
animationId = null;
|
|
476
|
+
}
|
|
477
|
+
svg.remove();
|
|
478
|
+
}
|
|
479
|
+
};
|
|
480
|
+
}
|
|
481
|
+
function createSarmalSVG(container, curveDef, options) {
|
|
482
|
+
const { trailLength, ...rendererOpts } = options ?? {};
|
|
483
|
+
const engine = createEngine(curveDef, trailLength);
|
|
484
|
+
return createSVGRenderer({ container, engine, ...rendererOpts });
|
|
485
|
+
}
|
|
486
|
+
|
|
251
487
|
// src/curves.ts
|
|
252
488
|
var TWO_PI2 = Math.PI * 2;
|
|
253
489
|
function artemis2(t, _time, _params) {
|
|
@@ -294,6 +530,34 @@ function rose3(t, _time, _params) {
|
|
|
294
530
|
y: r * Math.sin(t)
|
|
295
531
|
};
|
|
296
532
|
}
|
|
533
|
+
function lissajous32(t, time, _params) {
|
|
534
|
+
const phi = time * 0.45;
|
|
535
|
+
return {
|
|
536
|
+
x: Math.sin(3 * t + phi),
|
|
537
|
+
y: Math.sin(2 * t)
|
|
538
|
+
};
|
|
539
|
+
}
|
|
540
|
+
function lissajous43(t, time, _params) {
|
|
541
|
+
const phi = time * 0.38;
|
|
542
|
+
return {
|
|
543
|
+
x: Math.sin(4 * t + phi),
|
|
544
|
+
y: Math.sin(3 * t)
|
|
545
|
+
};
|
|
546
|
+
}
|
|
547
|
+
function epicycloid3(t, _time, _params) {
|
|
548
|
+
return {
|
|
549
|
+
x: 4 * Math.cos(t) - Math.cos(4 * t),
|
|
550
|
+
y: 4 * Math.sin(t) - Math.sin(4 * t)
|
|
551
|
+
};
|
|
552
|
+
}
|
|
553
|
+
function lame(t, time, _params) {
|
|
554
|
+
const p = 1.75 + 1.25 * Math.sin(time * 0.48);
|
|
555
|
+
const c = Math.cos(t), s = Math.sin(t);
|
|
556
|
+
return {
|
|
557
|
+
x: Math.sign(c) * Math.pow(Math.abs(c), p),
|
|
558
|
+
y: Math.sign(s) * Math.pow(Math.abs(s), p)
|
|
559
|
+
};
|
|
560
|
+
}
|
|
297
561
|
var curves = {
|
|
298
562
|
artemis2: {
|
|
299
563
|
name: "Artemis II",
|
|
@@ -330,6 +594,30 @@ var curves = {
|
|
|
330
594
|
fn: rose3,
|
|
331
595
|
period: TWO_PI2,
|
|
332
596
|
speed: 1.15
|
|
597
|
+
},
|
|
598
|
+
lissajous32: {
|
|
599
|
+
name: "Lissajous 3:2",
|
|
600
|
+
fn: lissajous32,
|
|
601
|
+
period: TWO_PI2,
|
|
602
|
+
speed: 2
|
|
603
|
+
},
|
|
604
|
+
lissajous43: {
|
|
605
|
+
name: "Lissajous 4:3",
|
|
606
|
+
fn: lissajous43,
|
|
607
|
+
period: TWO_PI2,
|
|
608
|
+
speed: 1.8
|
|
609
|
+
},
|
|
610
|
+
epicycloid3: {
|
|
611
|
+
name: "Epicycloid (n=3)",
|
|
612
|
+
fn: epicycloid3,
|
|
613
|
+
period: TWO_PI2,
|
|
614
|
+
speed: 0.75
|
|
615
|
+
},
|
|
616
|
+
lame: {
|
|
617
|
+
name: "Lam\xE9 Curve",
|
|
618
|
+
fn: lame,
|
|
619
|
+
period: TWO_PI2,
|
|
620
|
+
speed: 1
|
|
333
621
|
}
|
|
334
622
|
};
|
|
335
623
|
|
|
@@ -340,6 +628,6 @@ function createSarmal(canvas, curveDef, options) {
|
|
|
340
628
|
return createRenderer({ canvas, engine, ...rendererOpts });
|
|
341
629
|
}
|
|
342
630
|
|
|
343
|
-
export { createEngine, createRenderer, createSarmal, curves };
|
|
631
|
+
export { createEngine, createRenderer, createSVGRenderer, createSarmal, createSarmalSVG, curves };
|
|
344
632
|
//# sourceMappingURL=index.js.map
|
|
345
633
|
//# sourceMappingURL=index.js.map
|
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/engine.ts","../src/renderer.ts","../src/curves.ts","../src/index.ts"],"names":["TWO_PI"],"mappings":"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","file":"index.js","sourcesContent":["import type { CurveDef, Engine, Point } 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 * Zero heap allocations per frame:\n * - push() mutates the pre-allocated data slot in-place\n * - toArray() copies into a pre-allocated result buffer and returns the same reference every call\n * - result.length is NEVER changed — 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 the pre-allocated slot in-place — no allocation */\n push(x: number, y: number): void {\n const slot = this.data[this.head]!;\n slot.x = x;\n slot.y = y;\n this.head = (this.head + 1) % this.capacity;\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 * The same array reference is returned every call — result.length is always `capacity`.\n * Read only indices 0..count-1; the rest are stale pre-allocated slots.\n */\n toArray(): Array<Point> {\n const start = this.count < this.capacity ? 0 : this.head;\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 return this.result;\n }\n\n clear(): void {\n this.head = 0;\n this.count = 0;\n }\n\n get length(): number {\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(): number {\n return trail.length;\n },\n\n reset(): void {\n t = 0;\n actualTime = 0;\n trail.clear();\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;\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 * 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 (via offscreen canvas), 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 // Pre-parse hex colors once — avoids parseInt on every draw call\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: 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 that fits 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) minX = p.x;\n if (p.x > maxX) maxX = p.x;\n if (p.y < minY) minY = p.y;\n if (p.y > maxY) maxY = p.y;\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 sCtx = skeletonCanvas.getContext(\"2d\")!;\n\n sCtx.strokeStyle = `rgba(${hexToRgbComponents(opts.skeletonColor)},${DEFAULT_SKELETON_OPACITY})`;\n sCtx.lineWidth = 1.5;\n sCtx.beginPath();\n\n const first = skeleton[0]!;\n sCtx.moveTo(first.x * scale + offsetX, first.y * scale + offsetY);\n for (let i = 1; i < skeleton.length; i++) {\n const p = skeleton[i]!;\n sCtx.lineTo(p.x * scale + offsetX, p.y * scale + offsetY);\n }\n sCtx.stroke();\n }\n\n function drawSkeleton() {\n if (!skeletonCanvas) return;\n ctx.drawImage(skeletonCanvas, 0, 0);\n }\n\n function drawTrail() {\n if (trailCount < 2) return;\n\n // Set constant state once outside the batch loop\n ctx.lineJoin = \"round\";\n ctx.lineCap = \"round\";\n\n for (let b = 0; b < trailCount - 1; b += TRAIL_BATCH_SIZE) {\n const bEnd = Math.min(b + TRAIL_BATCH_SIZE, trailCount - 1);\n /** Normalized position of this batch along the trail (0 = tail, 1 = head) */\n const progress = (b + 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 = b; i <= bEnd; i++) {\n const p = trail[i]!;\n if (i === b) {\n ctx.moveTo(p.x * scale + offsetX, p.y * scale + offsetY);\n } else {\n ctx.lineTo(p.x * scale + offsetX, p.y * scale + offsetY);\n }\n }\n\n ctx.strokeStyle = `rgba(${trailRgb},${alpha})`;\n ctx.lineWidth = lineWidth;\n ctx.stroke();\n }\n }\n\n function drawHead() {\n if (!head) return;\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 = (now - lastTime) / 1000;\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) return;\n lastTime = performance.now();\n render();\n },\n\n stop() {\n if (animationId === null) return;\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}\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\n/** 7-lobed epitrochoid with a breathing distance parameter — d oscillates with t, making the loops pulse in and out */\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\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};\n","export type {\n Point,\n CurveDef,\n Engine,\n SarmalInstance,\n RendererOptions,\n SarmalOptions,\n} from \"./types\";\n\nexport { createEngine } from \"./engine\";\nexport { createRenderer } from \"./renderer\";\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":["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.js","sourcesContent":["import type { CurveDef, Engine, Point } 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 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;\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 = (now - lastTime) / 1000;\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}\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 = (now - lastTime) / 1000;\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}\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 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"]}
|