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