@sarmal/core 0.4.2 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/auto-init.cjs +92 -50
- package/dist/auto-init.cjs.map +1 -1
- package/dist/auto-init.d.cts +2 -1
- package/dist/auto-init.d.ts +2 -1
- package/dist/auto-init.js +91 -49
- package/dist/auto-init.js.map +1 -1
- package/dist/index.cjs +108 -58
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +151 -160
- package/dist/index.d.ts +151 -160
- package/dist/index.js +107 -57
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -48,6 +48,8 @@ function createEngine(curveDef, trailLength = 120) {
|
|
|
48
48
|
fn: curveDef.fn,
|
|
49
49
|
period: curveDef.period ?? TWO_PI,
|
|
50
50
|
speed: curveDef.speed ?? 1,
|
|
51
|
+
skeleton: curveDef.skeleton,
|
|
52
|
+
skeletonFn: curveDef.skeletonFn
|
|
51
53
|
};
|
|
52
54
|
const trail = new CircularBuffer(trailLength);
|
|
53
55
|
let t = 0;
|
|
@@ -63,20 +65,23 @@ function createEngine(curveDef, trailLength = 120) {
|
|
|
63
65
|
get trailCount() {
|
|
64
66
|
return trail.length;
|
|
65
67
|
},
|
|
68
|
+
get isLiveSkeleton() {
|
|
69
|
+
return curve.skeleton === "live";
|
|
70
|
+
},
|
|
66
71
|
reset() {
|
|
67
72
|
t = 0;
|
|
68
73
|
actualTime = 0;
|
|
69
74
|
trail.clear();
|
|
70
75
|
},
|
|
71
76
|
seek(newT, { clearTrail = false } = {}) {
|
|
72
|
-
t = (
|
|
77
|
+
t = (newT % curve.period + curve.period) % curve.period;
|
|
73
78
|
if (clearTrail) {
|
|
74
79
|
trail.clear();
|
|
75
80
|
}
|
|
76
81
|
},
|
|
77
82
|
seekWithTrail(targetT, { wrap = false, step = curve.period / trailLength } = {}) {
|
|
78
83
|
const advance = curve.speed * step;
|
|
79
|
-
const target = (
|
|
84
|
+
const target = (targetT % curve.period + curve.period) % curve.period;
|
|
80
85
|
const targetTime = target / curve.speed;
|
|
81
86
|
t = target;
|
|
82
87
|
actualTime = targetTime;
|
|
@@ -94,13 +99,24 @@ function createEngine(curveDef, trailLength = 120) {
|
|
|
94
99
|
getSarmalSkeleton() {
|
|
95
100
|
const steps = Math.ceil(curve.period * POINTS_PER_PERIOD_UNIT);
|
|
96
101
|
const points = new Array(steps);
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
102
|
+
if (curve.skeletonFn) {
|
|
103
|
+
for (let i = 0; i < steps; i++) {
|
|
104
|
+
const sampleT = i / (steps - 1) * curve.period;
|
|
105
|
+
points[i] = curve.skeletonFn(sampleT);
|
|
106
|
+
}
|
|
107
|
+
} else if (curve.skeleton === "live") {
|
|
108
|
+
for (let i = 0; i < steps; i++) {
|
|
109
|
+
const sampleT = i / (steps - 1) * curve.period;
|
|
110
|
+
points[i] = curve.fn(sampleT, actualTime, {});
|
|
111
|
+
}
|
|
112
|
+
} else {
|
|
113
|
+
for (let i = 0; i < steps; i++) {
|
|
114
|
+
const sampleT = i / (steps - 1) * curve.period;
|
|
115
|
+
points[i] = curve.fn(sampleT, 0, {});
|
|
116
|
+
}
|
|
101
117
|
}
|
|
102
118
|
return points;
|
|
103
|
-
}
|
|
119
|
+
}
|
|
104
120
|
};
|
|
105
121
|
}
|
|
106
122
|
|
|
@@ -119,7 +135,7 @@ var GLOW_INNER_EDGE = 0.4;
|
|
|
119
135
|
var GLOW_FALLOFF_OPACITY = 0.53;
|
|
120
136
|
function hexToRgbComponents(hex) {
|
|
121
137
|
const n = parseInt(hex.slice(1), 16);
|
|
122
|
-
return `${n >> 16},${
|
|
138
|
+
return `${n >> 16},${n >> 8 & 255},${n & 255}`;
|
|
123
139
|
}
|
|
124
140
|
function createRenderer(options) {
|
|
125
141
|
const canvas = options.canvas;
|
|
@@ -133,7 +149,7 @@ function createRenderer(options) {
|
|
|
133
149
|
trailColor: options.trailColor ?? "#ffffff",
|
|
134
150
|
headColor: options.headColor ?? "#ffffff",
|
|
135
151
|
headRadius: options.headRadius ?? DEFAULT_HEAD_RADIUS,
|
|
136
|
-
glowSize: options.glowSize ?? DEFAULT_GLOW_SIZE
|
|
152
|
+
glowSize: options.glowSize ?? DEFAULT_GLOW_SIZE
|
|
137
153
|
};
|
|
138
154
|
const trailRgb = hexToRgbComponents(opts.trailColor);
|
|
139
155
|
const headRgbFalloff = `rgba(${hexToRgbComponents(opts.headColor)},${GLOW_FALLOFF_OPACITY})`;
|
|
@@ -152,10 +168,7 @@ function createRenderer(options) {
|
|
|
152
168
|
return;
|
|
153
169
|
}
|
|
154
170
|
const first = skeleton[0];
|
|
155
|
-
let minX = first.x,
|
|
156
|
-
maxX = first.x,
|
|
157
|
-
minY = first.y,
|
|
158
|
-
maxY = first.y;
|
|
171
|
+
let minX = first.x, maxX = first.x, minY = first.y, maxY = first.y;
|
|
159
172
|
for (const p of skeleton) {
|
|
160
173
|
if (p.x < minX) {
|
|
161
174
|
minX = p.x;
|
|
@@ -198,10 +211,26 @@ function createRenderer(options) {
|
|
|
198
211
|
skeletonCtx.stroke();
|
|
199
212
|
}
|
|
200
213
|
function drawSkeleton() {
|
|
201
|
-
if (
|
|
214
|
+
if (opts.skeletonColor === "transparent") {
|
|
202
215
|
return;
|
|
203
216
|
}
|
|
204
|
-
|
|
217
|
+
if (engine.isLiveSkeleton) {
|
|
218
|
+
if (skeleton.length < 2) {
|
|
219
|
+
return;
|
|
220
|
+
}
|
|
221
|
+
ctx.strokeStyle = `rgba(${hexToRgbComponents(opts.skeletonColor)},${DEFAULT_SKELETON_OPACITY})`;
|
|
222
|
+
ctx.lineWidth = 1.5;
|
|
223
|
+
ctx.beginPath();
|
|
224
|
+
const first = skeleton[0];
|
|
225
|
+
ctx.moveTo(first.x * scale + offsetX, first.y * scale + offsetY);
|
|
226
|
+
for (let i = 1; i < skeleton.length; i++) {
|
|
227
|
+
const p = skeleton[i];
|
|
228
|
+
ctx.lineTo(p.x * scale + offsetX, p.y * scale + offsetY);
|
|
229
|
+
}
|
|
230
|
+
ctx.stroke();
|
|
231
|
+
} else if (skeletonCanvas) {
|
|
232
|
+
ctx.drawImage(skeletonCanvas, 0, 0);
|
|
233
|
+
}
|
|
205
234
|
}
|
|
206
235
|
function drawTrail() {
|
|
207
236
|
if (trailCount < 2) {
|
|
@@ -255,6 +284,10 @@ function createRenderer(options) {
|
|
|
255
284
|
trailCount = engine.trailCount;
|
|
256
285
|
head = trailCount > 0 ? trail[trailCount - 1] : null;
|
|
257
286
|
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
|
287
|
+
if (engine.isLiveSkeleton) {
|
|
288
|
+
skeleton = engine.getSarmalSkeleton();
|
|
289
|
+
calculateBoundaries();
|
|
290
|
+
}
|
|
258
291
|
drawSkeleton();
|
|
259
292
|
drawTrail();
|
|
260
293
|
drawHead();
|
|
@@ -262,7 +295,9 @@ function createRenderer(options) {
|
|
|
262
295
|
}
|
|
263
296
|
skeleton = engine.getSarmalSkeleton();
|
|
264
297
|
calculateBoundaries();
|
|
265
|
-
|
|
298
|
+
if (!engine.isLiveSkeleton) {
|
|
299
|
+
buildSkeletonCanvas();
|
|
300
|
+
}
|
|
266
301
|
return {
|
|
267
302
|
start() {
|
|
268
303
|
if (animationId !== null) {
|
|
@@ -294,7 +329,7 @@ function createRenderer(options) {
|
|
|
294
329
|
},
|
|
295
330
|
seekWithTrail(t) {
|
|
296
331
|
engine.seekWithTrail(t);
|
|
297
|
-
}
|
|
332
|
+
}
|
|
298
333
|
};
|
|
299
334
|
}
|
|
300
335
|
|
|
@@ -320,7 +355,7 @@ function createSVGRenderer(options) {
|
|
|
320
355
|
headColor: options.headColor ?? "#ffffff",
|
|
321
356
|
headRadius: options.headRadius ?? 4,
|
|
322
357
|
glowSize: options.glowSize ?? 20,
|
|
323
|
-
ariaLabel: options.ariaLabel ?? "Loading"
|
|
358
|
+
ariaLabel: options.ariaLabel ?? "Loading"
|
|
324
359
|
};
|
|
325
360
|
const uid = ++instanceCount;
|
|
326
361
|
const gradientId = `sarmal-glow-${uid}`;
|
|
@@ -390,10 +425,7 @@ function createSVGRenderer(options) {
|
|
|
390
425
|
return;
|
|
391
426
|
}
|
|
392
427
|
const first = skeleton2[0];
|
|
393
|
-
let minX = first.x,
|
|
394
|
-
maxX = first.x,
|
|
395
|
-
minY = first.y,
|
|
396
|
-
maxY = first.y;
|
|
428
|
+
let minX = first.x, maxX = first.x, minY = first.y, maxY = first.y;
|
|
397
429
|
for (const p of skeleton2) {
|
|
398
430
|
if (p.x < minX) {
|
|
399
431
|
minX = p.x;
|
|
@@ -422,16 +454,23 @@ function createSVGRenderer(options) {
|
|
|
422
454
|
function py(p) {
|
|
423
455
|
return (p.y * scale + offsetY).toFixed(2);
|
|
424
456
|
}
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
457
|
+
function updateSkeleton(skeleton2) {
|
|
458
|
+
if (skeleton2.length < 2) {
|
|
459
|
+
skeletonPath.setAttribute("d", "");
|
|
460
|
+
return;
|
|
461
|
+
}
|
|
462
|
+
let d = `M${px(skeleton2[0])} ${py(skeleton2[0])}`;
|
|
463
|
+
for (let i = 1; i < skeleton2.length; i++) {
|
|
464
|
+
d += ` L${px(skeleton2[i])} ${py(skeleton2[i])}`;
|
|
431
465
|
}
|
|
432
466
|
d += " Z";
|
|
433
467
|
skeletonPath.setAttribute("d", d);
|
|
434
468
|
}
|
|
469
|
+
const skeleton = engine.getSarmalSkeleton();
|
|
470
|
+
calculateBoundaries(skeleton);
|
|
471
|
+
if (!engine.isLiveSkeleton) {
|
|
472
|
+
updateSkeleton(skeleton);
|
|
473
|
+
}
|
|
435
474
|
function updateTrail(trail, trailCount) {
|
|
436
475
|
if (trailCount < 2) {
|
|
437
476
|
for (const p of trailPaths) {
|
|
@@ -473,14 +512,18 @@ function createSVGRenderer(options) {
|
|
|
473
512
|
}
|
|
474
513
|
let animationId = null;
|
|
475
514
|
let lastTime = 0;
|
|
476
|
-
const prefersReducedMotion =
|
|
477
|
-
typeof window !== "undefined" && window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
515
|
+
const prefersReducedMotion = typeof window !== "undefined" && window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
478
516
|
function renderFrame() {
|
|
479
517
|
const now = performance.now();
|
|
480
518
|
const dt = Math.min((now - lastTime) / 1e3, 1 / 30);
|
|
481
519
|
lastTime = now;
|
|
482
520
|
const trail = engine.tick(dt);
|
|
483
521
|
const trailCount = engine.trailCount;
|
|
522
|
+
if (engine.isLiveSkeleton) {
|
|
523
|
+
const liveSkeleton = engine.getSarmalSkeleton();
|
|
524
|
+
calculateBoundaries(liveSkeleton);
|
|
525
|
+
updateSkeleton(liveSkeleton);
|
|
526
|
+
}
|
|
484
527
|
updateTrail(trail, trailCount);
|
|
485
528
|
updateHead(trail, trailCount);
|
|
486
529
|
if (!prefersReducedMotion) {
|
|
@@ -517,7 +560,7 @@ function createSVGRenderer(options) {
|
|
|
517
560
|
},
|
|
518
561
|
seekWithTrail(t) {
|
|
519
562
|
engine.seekWithTrail(t);
|
|
520
|
-
}
|
|
563
|
+
}
|
|
521
564
|
};
|
|
522
565
|
}
|
|
523
566
|
function createSarmalSVG(container, curveDef, options) {
|
|
@@ -529,22 +572,26 @@ function createSarmalSVG(container, curveDef, options) {
|
|
|
529
572
|
// src/curves.ts
|
|
530
573
|
var TWO_PI2 = Math.PI * 2;
|
|
531
574
|
function artemis2(t, _time, _params) {
|
|
532
|
-
const a = 0.35,
|
|
533
|
-
|
|
534
|
-
ox = 0.175;
|
|
535
|
-
const s = Math.sin(t),
|
|
536
|
-
c = Math.cos(t);
|
|
575
|
+
const a = 0.35, b = 0.15, ox = 0.175;
|
|
576
|
+
const s = Math.sin(t), c = Math.cos(t);
|
|
537
577
|
const denom = 1 + s * s;
|
|
538
578
|
return {
|
|
539
|
-
x:
|
|
540
|
-
y:
|
|
579
|
+
x: c * (1 + a * c) / denom - ox,
|
|
580
|
+
y: s * c * (1 + b * c) / denom
|
|
541
581
|
};
|
|
542
582
|
}
|
|
543
583
|
function epitrochoid7(t, _time, _params) {
|
|
544
584
|
const d = 1 + 0.55 * Math.sin(t * 0.5);
|
|
545
585
|
return {
|
|
546
586
|
x: 7 * Math.cos(t) - d * Math.cos(7 * t),
|
|
547
|
-
y: 7 * Math.sin(t) - d * Math.sin(7 * t)
|
|
587
|
+
y: 7 * Math.sin(t) - d * Math.sin(7 * t)
|
|
588
|
+
};
|
|
589
|
+
}
|
|
590
|
+
function epitrochoid7Skeleton(t) {
|
|
591
|
+
const d = 1.275;
|
|
592
|
+
return {
|
|
593
|
+
x: 7 * Math.cos(t) - d * Math.cos(7 * t),
|
|
594
|
+
y: 7 * Math.sin(t) - d * Math.sin(7 * t)
|
|
548
595
|
};
|
|
549
596
|
}
|
|
550
597
|
function astroid(t, _time, _params) {
|
|
@@ -552,56 +599,55 @@ function astroid(t, _time, _params) {
|
|
|
552
599
|
const s = Math.sin(t);
|
|
553
600
|
return {
|
|
554
601
|
x: c * c * c,
|
|
555
|
-
y: s * s * s
|
|
602
|
+
y: s * s * s
|
|
556
603
|
};
|
|
557
604
|
}
|
|
558
605
|
function deltoid(t, _time, _params) {
|
|
559
606
|
return {
|
|
560
607
|
x: 2 * Math.cos(t) + Math.cos(2 * t),
|
|
561
|
-
y: 2 * Math.sin(t) - Math.sin(2 * t)
|
|
608
|
+
y: 2 * Math.sin(t) - Math.sin(2 * t)
|
|
562
609
|
};
|
|
563
610
|
}
|
|
564
611
|
function rose5(t, _time, _params) {
|
|
565
612
|
const r = Math.cos(5 * t);
|
|
566
613
|
return {
|
|
567
614
|
x: r * Math.cos(t),
|
|
568
|
-
y: r * Math.sin(t)
|
|
615
|
+
y: r * Math.sin(t)
|
|
569
616
|
};
|
|
570
617
|
}
|
|
571
618
|
function rose3(t, _time, _params) {
|
|
572
619
|
const r = Math.cos(3 * t);
|
|
573
620
|
return {
|
|
574
621
|
x: r * Math.cos(t),
|
|
575
|
-
y: r * Math.sin(t)
|
|
622
|
+
y: r * Math.sin(t)
|
|
576
623
|
};
|
|
577
624
|
}
|
|
578
625
|
function lissajous32(t, time, _params) {
|
|
579
626
|
const phi = time * 0.45;
|
|
580
627
|
return {
|
|
581
628
|
x: Math.sin(3 * t + phi),
|
|
582
|
-
y: Math.sin(2 * t)
|
|
629
|
+
y: Math.sin(2 * t)
|
|
583
630
|
};
|
|
584
631
|
}
|
|
585
632
|
function lissajous43(t, time, _params) {
|
|
586
633
|
const phi = time * 0.38;
|
|
587
634
|
return {
|
|
588
635
|
x: Math.sin(4 * t + phi),
|
|
589
|
-
y: Math.sin(3 * t)
|
|
636
|
+
y: Math.sin(3 * t)
|
|
590
637
|
};
|
|
591
638
|
}
|
|
592
639
|
function epicycloid3(t, _time, _params) {
|
|
593
640
|
return {
|
|
594
641
|
x: 4 * Math.cos(t) - Math.cos(4 * t),
|
|
595
|
-
y: 4 * Math.sin(t) - Math.sin(4 * t)
|
|
642
|
+
y: 4 * Math.sin(t) - Math.sin(4 * t)
|
|
596
643
|
};
|
|
597
644
|
}
|
|
598
645
|
function lame(t, time, _params) {
|
|
599
646
|
const p = 1.75 + 1.25 * Math.sin(time * 0.48);
|
|
600
|
-
const c = Math.cos(t),
|
|
601
|
-
s = Math.sin(t);
|
|
647
|
+
const c = Math.cos(t), s = Math.sin(t);
|
|
602
648
|
return {
|
|
603
649
|
x: Math.sign(c) * Math.pow(Math.abs(c), p),
|
|
604
|
-
y: Math.sign(s) * Math.pow(Math.abs(s), p)
|
|
650
|
+
y: Math.sign(s) * Math.pow(Math.abs(s), p)
|
|
605
651
|
};
|
|
606
652
|
}
|
|
607
653
|
var curves = {
|
|
@@ -609,62 +655,66 @@ var curves = {
|
|
|
609
655
|
name: "Artemis II",
|
|
610
656
|
fn: artemis2,
|
|
611
657
|
period: TWO_PI2,
|
|
612
|
-
speed: 0.7
|
|
658
|
+
speed: 0.7
|
|
613
659
|
},
|
|
614
660
|
epitrochoid7: {
|
|
615
661
|
name: "Epitrochoid",
|
|
616
662
|
fn: epitrochoid7,
|
|
617
663
|
period: TWO_PI2,
|
|
618
664
|
speed: 1.4,
|
|
665
|
+
skeletonFn: epitrochoid7Skeleton
|
|
619
666
|
},
|
|
620
667
|
astroid: {
|
|
621
668
|
name: "Astroid",
|
|
622
669
|
fn: astroid,
|
|
623
670
|
period: TWO_PI2,
|
|
624
|
-
speed: 1.1
|
|
671
|
+
speed: 1.1
|
|
625
672
|
},
|
|
626
673
|
deltoid: {
|
|
627
674
|
name: "Deltoid",
|
|
628
675
|
fn: deltoid,
|
|
629
676
|
period: TWO_PI2,
|
|
630
|
-
speed: 0.9
|
|
677
|
+
speed: 0.9
|
|
631
678
|
},
|
|
632
679
|
rose5: {
|
|
633
680
|
name: "Rose (n=5)",
|
|
634
681
|
fn: rose5,
|
|
635
682
|
period: TWO_PI2,
|
|
636
|
-
speed: 1
|
|
683
|
+
speed: 1
|
|
637
684
|
},
|
|
638
685
|
rose3: {
|
|
639
686
|
name: "Rose (n=3)",
|
|
640
687
|
fn: rose3,
|
|
641
688
|
period: TWO_PI2,
|
|
642
|
-
speed: 1.15
|
|
689
|
+
speed: 1.15
|
|
643
690
|
},
|
|
644
691
|
lissajous32: {
|
|
645
692
|
name: "Lissajous 3:2",
|
|
646
693
|
fn: lissajous32,
|
|
647
694
|
period: TWO_PI2,
|
|
648
695
|
speed: 2,
|
|
696
|
+
skeleton: "live"
|
|
649
697
|
},
|
|
650
698
|
lissajous43: {
|
|
651
699
|
name: "Lissajous 4:3",
|
|
652
700
|
fn: lissajous43,
|
|
653
701
|
period: TWO_PI2,
|
|
654
702
|
speed: 1.8,
|
|
703
|
+
skeleton: "live"
|
|
655
704
|
},
|
|
656
705
|
epicycloid3: {
|
|
657
706
|
name: "Epicycloid (n=3)",
|
|
658
707
|
fn: epicycloid3,
|
|
659
708
|
period: TWO_PI2,
|
|
660
|
-
speed: 0.75
|
|
709
|
+
speed: 0.75
|
|
661
710
|
},
|
|
662
711
|
lame: {
|
|
663
712
|
name: "Lam\xE9 Curve",
|
|
664
713
|
fn: lame,
|
|
665
714
|
period: TWO_PI2,
|
|
666
715
|
speed: 1,
|
|
667
|
-
|
|
716
|
+
skeleton: "live"
|
|
717
|
+
}
|
|
668
718
|
};
|
|
669
719
|
|
|
670
720
|
// src/index.ts
|
|
@@ -676,4 +726,4 @@ function createSarmal(canvas, curveDef, options) {
|
|
|
676
726
|
|
|
677
727
|
export { createEngine, createRenderer, createSVGRenderer, createSarmal, createSarmalSVG, curves };
|
|
678
728
|
//# sourceMappingURL=index.js.map
|
|
679
|
-
//# sourceMappingURL=index.js.map
|
|
729
|
+
//# sourceMappingURL=index.js.map
|