@sarmal/core 0.13.0 → 0.15.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 +172 -53
- package/dist/auto-init.cjs.map +1 -1
- package/dist/auto-init.js +172 -53
- package/dist/auto-init.js.map +1 -1
- package/dist/curves/artemis2.d.cts +1 -1
- package/dist/curves/artemis2.d.ts +1 -1
- package/dist/curves/astroid.d.cts +1 -1
- package/dist/curves/astroid.d.ts +1 -1
- package/dist/curves/deltoid.d.cts +1 -1
- package/dist/curves/deltoid.d.ts +1 -1
- package/dist/curves/epicycloid3.d.cts +1 -1
- package/dist/curves/epicycloid3.d.ts +1 -1
- package/dist/curves/epitrochoid7.d.cts +1 -1
- package/dist/curves/epitrochoid7.d.ts +1 -1
- package/dist/curves/index.d.cts +1 -1
- package/dist/curves/index.d.ts +1 -1
- package/dist/curves/lame.d.cts +1 -1
- package/dist/curves/lame.d.ts +1 -1
- package/dist/curves/lissajous32.d.cts +1 -1
- package/dist/curves/lissajous32.d.ts +1 -1
- package/dist/curves/lissajous43.d.cts +1 -1
- package/dist/curves/lissajous43.d.ts +1 -1
- package/dist/curves/rose3.d.cts +1 -1
- package/dist/curves/rose3.d.ts +1 -1
- package/dist/curves/rose5.d.cts +1 -1
- package/dist/curves/rose5.d.ts +1 -1
- package/dist/index.cjs +246 -58
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +20 -5
- package/dist/index.d.ts +20 -5
- package/dist/index.js +246 -58
- package/dist/index.js.map +1 -1
- package/dist/{types-BW0bpL1Z.d.cts → types-BL9HhEmk.d.cts} +43 -21
- package/dist/{types-BW0bpL1Z.d.ts → types-BL9HhEmk.d.ts} +43 -21
- package/package.json +1 -1
package/dist/auto-init.js
CHANGED
|
@@ -376,25 +376,6 @@ function enginePassthroughs(engine) {
|
|
|
376
376
|
setSpeedOver: engine.setSpeedOver,
|
|
377
377
|
};
|
|
378
378
|
}
|
|
379
|
-
|
|
380
|
-
// src/renderer.ts
|
|
381
|
-
var DEFAULT_SKELETON_COLOR = "#ffffff";
|
|
382
|
-
var GRADIENT = {
|
|
383
|
-
bard: ["#a855f7", "#3b82f6", "#14b8a6", "#ec4899"],
|
|
384
|
-
sunset: ["#f97316", "#dc2626", "#9333ea", "#f472b6"],
|
|
385
|
-
ocean: ["#1e3a8a", "#06b6d4", "#22d3ee", "#e0f2fe"],
|
|
386
|
-
ice: ["#1e3a8a", "#67e8f9"],
|
|
387
|
-
fire: ["#7f1d1d", "#fbbf24"],
|
|
388
|
-
forest: ["#14532d", "#86efac"],
|
|
389
|
-
};
|
|
390
|
-
var PRESETS = {
|
|
391
|
-
bard: GRADIENT.bard,
|
|
392
|
-
sunset: GRADIENT.sunset,
|
|
393
|
-
ocean: GRADIENT.ocean,
|
|
394
|
-
ice: GRADIENT.ice,
|
|
395
|
-
fire: GRADIENT.fire,
|
|
396
|
-
forest: GRADIENT.forest,
|
|
397
|
-
};
|
|
398
379
|
function hexToRgb(hex) {
|
|
399
380
|
const n = parseInt(hex.slice(1), 16);
|
|
400
381
|
return { r: n >> 16, g: (n >> 8) & 255, b: n & 255 };
|
|
@@ -405,8 +386,12 @@ var lerpRgb = (a, b, t) => ({
|
|
|
405
386
|
b: Math.round(a.b + (b.b - a.b) * t),
|
|
406
387
|
});
|
|
407
388
|
function getPaletteColor(palette, position, timeOffset = 0) {
|
|
408
|
-
if (palette.length === 0)
|
|
409
|
-
|
|
389
|
+
if (palette.length === 0) {
|
|
390
|
+
return { r: 255, g: 255, b: 255 };
|
|
391
|
+
}
|
|
392
|
+
if (palette.length === 1) {
|
|
393
|
+
return hexToRgb(palette[0]);
|
|
394
|
+
}
|
|
410
395
|
const cyclePos = (position + timeOffset) % 1;
|
|
411
396
|
const scaled = cyclePos * palette.length;
|
|
412
397
|
const idx = Math.floor(scaled);
|
|
@@ -415,11 +400,120 @@ function getPaletteColor(palette, position, timeOffset = 0) {
|
|
|
415
400
|
const c2 = hexToRgb(palette[(idx + 1) % palette.length]);
|
|
416
401
|
return lerpRgb(c1, c2, t);
|
|
417
402
|
}
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
403
|
+
var HEX_COLOR_RE = /^#[0-9a-fA-F]{6}$/;
|
|
404
|
+
var TRAIL_STYLES = ["default", "gradient-static", "gradient-animated"];
|
|
405
|
+
var RENDER_OPTION_KEYS = /* @__PURE__ */ new Set([
|
|
406
|
+
"trailColor",
|
|
407
|
+
"headColor",
|
|
408
|
+
"skeletonColor",
|
|
409
|
+
"trailStyle",
|
|
410
|
+
]);
|
|
411
|
+
function validateRenderOptions(partial) {
|
|
412
|
+
for (const key of Object.keys(partial)) {
|
|
413
|
+
if (!RENDER_OPTION_KEYS.has(key)) {
|
|
414
|
+
throw new TypeError(`[sarmal] setRenderOptions: unknown key "${key}"`);
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
if (partial.trailColor !== void 0) {
|
|
418
|
+
assertTrailColor(partial.trailColor);
|
|
419
|
+
}
|
|
420
|
+
if (partial.headColor !== void 0) {
|
|
421
|
+
assertHeadColor(partial.headColor);
|
|
422
|
+
}
|
|
423
|
+
if (partial.skeletonColor !== void 0) {
|
|
424
|
+
assertSkeletonColor(partial.skeletonColor);
|
|
425
|
+
}
|
|
426
|
+
if (partial.trailStyle !== void 0) {
|
|
427
|
+
assertTrailStyle(partial.trailStyle);
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
function assertTrailColor(value) {
|
|
431
|
+
if (typeof value === "string") {
|
|
432
|
+
if (!HEX_COLOR_RE.test(value)) {
|
|
433
|
+
throw new TypeError(
|
|
434
|
+
`[sarmal] setRenderOptions: trailColor must be a 6-digit hex string, got "${value}"`,
|
|
435
|
+
);
|
|
436
|
+
}
|
|
437
|
+
return;
|
|
438
|
+
}
|
|
439
|
+
if (Array.isArray(value)) {
|
|
440
|
+
if (value.length < 2) {
|
|
441
|
+
throw new RangeError(
|
|
442
|
+
`[sarmal] setRenderOptions: trailColor array must have at least 2 entries, got ${value.length}`,
|
|
443
|
+
);
|
|
444
|
+
}
|
|
445
|
+
for (let i = 0; i < value.length; i++) {
|
|
446
|
+
const entry = value[i];
|
|
447
|
+
if (typeof entry !== "string" || !HEX_COLOR_RE.test(entry)) {
|
|
448
|
+
throw new TypeError(
|
|
449
|
+
`[sarmal] setRenderOptions: trailColor[${i}] must be a 6-digit hex string, got ${JSON.stringify(entry)}`,
|
|
450
|
+
);
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
return;
|
|
454
|
+
}
|
|
455
|
+
throw new TypeError(
|
|
456
|
+
`[sarmal] setRenderOptions: trailColor must be a 6-digit hex string or an array of hex strings, got ${JSON.stringify(value)}`,
|
|
457
|
+
);
|
|
458
|
+
}
|
|
459
|
+
function assertHeadColor(value) {
|
|
460
|
+
if (value === null) {
|
|
461
|
+
return;
|
|
462
|
+
}
|
|
463
|
+
if (typeof value !== "string" || !HEX_COLOR_RE.test(value)) {
|
|
464
|
+
throw new TypeError(
|
|
465
|
+
`[sarmal] setRenderOptions: headColor must be a 6-digit hex string or null, got ${JSON.stringify(value)}`,
|
|
466
|
+
);
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
function assertSkeletonColor(value) {
|
|
470
|
+
if (value === "transparent") {
|
|
471
|
+
return;
|
|
472
|
+
}
|
|
473
|
+
if (typeof value !== "string" || !HEX_COLOR_RE.test(value)) {
|
|
474
|
+
throw new TypeError(
|
|
475
|
+
`[sarmal] setRenderOptions: skeletonColor must be a 6-digit hex string or "transparent", got ${JSON.stringify(value)}`,
|
|
476
|
+
);
|
|
477
|
+
}
|
|
422
478
|
}
|
|
479
|
+
function assertTrailStyle(value) {
|
|
480
|
+
if (!TRAIL_STYLES.includes(value)) {
|
|
481
|
+
throw new RangeError(
|
|
482
|
+
`[sarmal] setRenderOptions: trailStyle must be one of "default", "gradient-static", "gradient-animated", got ${JSON.stringify(value)}`,
|
|
483
|
+
);
|
|
484
|
+
}
|
|
485
|
+
}
|
|
486
|
+
function resolveTrailMainColor(trailColor) {
|
|
487
|
+
return typeof trailColor === "string" ? trailColor : trailColor[0];
|
|
488
|
+
}
|
|
489
|
+
function resolveTrailPalette(trailColor) {
|
|
490
|
+
return typeof trailColor === "string" ? [trailColor] : trailColor;
|
|
491
|
+
}
|
|
492
|
+
function resolveHeadColor(trailColor, trailStyle) {
|
|
493
|
+
if (trailStyle === "default") {
|
|
494
|
+
return resolveTrailMainColor(trailColor);
|
|
495
|
+
}
|
|
496
|
+
const palette = resolveTrailPalette(trailColor);
|
|
497
|
+
const last = palette[palette.length - 1];
|
|
498
|
+
const { r, g, b } = hexToRgb(last);
|
|
499
|
+
return `rgb(${r},${g},${b})`;
|
|
500
|
+
}
|
|
501
|
+
function warnIfTrailColorMismatch(trailColor, trailStyle) {
|
|
502
|
+
if (trailStyle === "default" && Array.isArray(trailColor)) {
|
|
503
|
+
console.warn(
|
|
504
|
+
'[sarmal] trailColor is an array but trailStyle is "default"; only the first color will be used. Pass a gradient trailStyle to use the whole palette.',
|
|
505
|
+
);
|
|
506
|
+
return;
|
|
507
|
+
}
|
|
508
|
+
if (trailStyle !== "default" && typeof trailColor === "string") {
|
|
509
|
+
console.warn(
|
|
510
|
+
`[sarmal] trailColor is a single color but trailStyle is "${trailStyle}"; the trail will render as a solid color. Pass an array of hex colors to use a real gradient.`,
|
|
511
|
+
);
|
|
512
|
+
}
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
// src/renderer.ts
|
|
516
|
+
var WHITE_HEX = "#ffffff";
|
|
423
517
|
function hexToRgbComponents(hex) {
|
|
424
518
|
const n = parseInt(hex.slice(1), 16);
|
|
425
519
|
return `${n >> 16},${(n >> 8) & 255},${n & 255}`;
|
|
@@ -437,22 +531,14 @@ function createRenderer(options) {
|
|
|
437
531
|
}
|
|
438
532
|
const ctx = canvas.getContext("2d");
|
|
439
533
|
const engine = options.engine;
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
return trailColor;
|
|
449
|
-
}
|
|
450
|
-
const opts = {
|
|
451
|
-
skeletonColor: options.skeletonColor ?? DEFAULT_SKELETON_COLOR,
|
|
452
|
-
trailColor,
|
|
453
|
-
headColor: options.headColor ?? defaultHeadColor(),
|
|
454
|
-
};
|
|
455
|
-
const trailRgb = hexToRgbComponents(opts.trailColor);
|
|
534
|
+
let trailStyle = options.trailStyle ?? "default";
|
|
535
|
+
let trailColor = options.trailColor ?? WHITE_HEX;
|
|
536
|
+
let skeletonColor = options.skeletonColor ?? WHITE_HEX;
|
|
537
|
+
let userHeadColor = options.headColor ?? null;
|
|
538
|
+
let headColor = userHeadColor ?? resolveHeadColor(trailColor, trailStyle);
|
|
539
|
+
let trailSolidRgb = hexToRgbComponents(resolveTrailMainColor(trailColor));
|
|
540
|
+
let trailPalette = resolveTrailPalette(trailColor);
|
|
541
|
+
warnIfTrailColorMismatch(trailColor, trailStyle);
|
|
456
542
|
const dpr = typeof window !== "undefined" ? window.devicePixelRatio || 1 : 1;
|
|
457
543
|
function setupCanvas() {
|
|
458
544
|
const rect = canvas.getBoundingClientRect();
|
|
@@ -487,11 +573,13 @@ function createRenderer(options) {
|
|
|
487
573
|
}
|
|
488
574
|
}
|
|
489
575
|
function buildSkeletonCanvas() {
|
|
490
|
-
if (skeleton.length < 2)
|
|
576
|
+
if (skeleton.length < 2) {
|
|
577
|
+
return;
|
|
578
|
+
}
|
|
491
579
|
skeletonCanvas = new OffscreenCanvas(canvas.width, canvas.height);
|
|
492
580
|
const skeletonCtx = skeletonCanvas.getContext("2d");
|
|
493
581
|
skeletonCtx.setTransform(dpr, 0, 0, dpr, 0, 0);
|
|
494
|
-
skeletonCtx.strokeStyle = `rgba(${hexToRgbComponents(
|
|
582
|
+
skeletonCtx.strokeStyle = `rgba(${hexToRgbComponents(skeletonColor)},${DEFAULT_SKELETON_OPACITY})`;
|
|
495
583
|
skeletonCtx.lineWidth = 1.5;
|
|
496
584
|
skeletonCtx.beginPath();
|
|
497
585
|
const first = skeleton[0];
|
|
@@ -503,8 +591,10 @@ function createRenderer(options) {
|
|
|
503
591
|
skeletonCtx.stroke();
|
|
504
592
|
}
|
|
505
593
|
function drawSkeletonPath(pts, opacity) {
|
|
506
|
-
if (pts.length < 2)
|
|
507
|
-
|
|
594
|
+
if (pts.length < 2) {
|
|
595
|
+
return;
|
|
596
|
+
}
|
|
597
|
+
ctx.strokeStyle = `rgba(${hexToRgbComponents(skeletonColor)},${opacity})`;
|
|
508
598
|
ctx.lineWidth = 1.5;
|
|
509
599
|
ctx.beginPath();
|
|
510
600
|
ctx.moveTo(pts[0].x * scale + offsetX, pts[0].y * scale + offsetY);
|
|
@@ -514,7 +604,7 @@ function createRenderer(options) {
|
|
|
514
604
|
ctx.stroke();
|
|
515
605
|
}
|
|
516
606
|
function drawSkeleton() {
|
|
517
|
-
if (
|
|
607
|
+
if (skeletonColor === "transparent") {
|
|
518
608
|
return;
|
|
519
609
|
}
|
|
520
610
|
if (engine.morphAlpha !== null) {
|
|
@@ -525,7 +615,7 @@ function createRenderer(options) {
|
|
|
525
615
|
if (skeleton.length < 2) {
|
|
526
616
|
return;
|
|
527
617
|
}
|
|
528
|
-
ctx.strokeStyle = `rgba(${hexToRgbComponents(
|
|
618
|
+
ctx.strokeStyle = `rgba(${hexToRgbComponents(skeletonColor)},${DEFAULT_SKELETON_OPACITY})`;
|
|
529
619
|
ctx.lineWidth = 1.5;
|
|
530
620
|
ctx.beginPath();
|
|
531
621
|
const first = skeleton[0];
|
|
@@ -554,10 +644,10 @@ function createRenderer(options) {
|
|
|
554
644
|
toY,
|
|
555
645
|
);
|
|
556
646
|
if (trailStyle === "default") {
|
|
557
|
-
ctx.fillStyle = `rgba(${
|
|
647
|
+
ctx.fillStyle = `rgba(${trailSolidRgb},${opacity})`;
|
|
558
648
|
} else {
|
|
559
649
|
const timeOffset = trailStyle === "gradient-animated" ? gradientAnimTime * 5e-4 : 0;
|
|
560
|
-
const color = getPaletteColor(
|
|
650
|
+
const color = getPaletteColor(trailPalette, progress, timeOffset);
|
|
561
651
|
ctx.fillStyle = `rgba(${color.r},${color.g},${color.b},${opacity})`;
|
|
562
652
|
}
|
|
563
653
|
ctx.beginPath();
|
|
@@ -577,7 +667,7 @@ function createRenderer(options) {
|
|
|
577
667
|
const y = head.y * scale + offsetY;
|
|
578
668
|
const r =
|
|
579
669
|
options.headRadius ?? Math.max(2, 3 * Math.sqrt(Math.min(logicalWidth, logicalHeight) / 160));
|
|
580
|
-
ctx.fillStyle =
|
|
670
|
+
ctx.fillStyle = headColor;
|
|
581
671
|
ctx.beginPath();
|
|
582
672
|
ctx.arc(x, y, r, 0, Math.PI * 2);
|
|
583
673
|
ctx.fill();
|
|
@@ -678,6 +768,34 @@ function createRenderer(options) {
|
|
|
678
768
|
morphResolve = resolve;
|
|
679
769
|
});
|
|
680
770
|
},
|
|
771
|
+
setRenderOptions(partial) {
|
|
772
|
+
validateRenderOptions(partial);
|
|
773
|
+
if (partial.trailColor !== void 0) {
|
|
774
|
+
trailColor = partial.trailColor;
|
|
775
|
+
trailSolidRgb = hexToRgbComponents(resolveTrailMainColor(trailColor));
|
|
776
|
+
trailPalette = resolveTrailPalette(trailColor);
|
|
777
|
+
}
|
|
778
|
+
if (partial.skeletonColor !== void 0) {
|
|
779
|
+
skeletonColor = partial.skeletonColor;
|
|
780
|
+
if (skeletonColor !== "transparent" && !engine.isLiveSkeleton) {
|
|
781
|
+
buildSkeletonCanvas();
|
|
782
|
+
}
|
|
783
|
+
}
|
|
784
|
+
if (partial.trailStyle !== void 0) {
|
|
785
|
+
trailStyle = partial.trailStyle;
|
|
786
|
+
}
|
|
787
|
+
if (partial.headColor !== void 0) {
|
|
788
|
+
userHeadColor = partial.headColor;
|
|
789
|
+
}
|
|
790
|
+
if (userHeadColor === null) {
|
|
791
|
+
headColor = resolveHeadColor(trailColor, trailStyle);
|
|
792
|
+
} else {
|
|
793
|
+
headColor = userHeadColor;
|
|
794
|
+
}
|
|
795
|
+
if (partial.trailColor !== void 0 || partial.trailStyle !== void 0) {
|
|
796
|
+
warnIfTrailColorMismatch(trailColor, trailStyle);
|
|
797
|
+
}
|
|
798
|
+
},
|
|
681
799
|
};
|
|
682
800
|
if (shouldAutoStart) {
|
|
683
801
|
instance.play();
|
|
@@ -884,7 +1002,7 @@ function createSarmal(canvas, curveDef, options) {
|
|
|
884
1002
|
}
|
|
885
1003
|
|
|
886
1004
|
// src/auto-init.ts
|
|
887
|
-
function
|
|
1005
|
+
function parseTrailColor(value) {
|
|
888
1006
|
try {
|
|
889
1007
|
const parsed = JSON.parse(value);
|
|
890
1008
|
if (Array.isArray(parsed)) {
|
|
@@ -905,7 +1023,9 @@ function init() {
|
|
|
905
1023
|
return console.error(`[sarmal] "${curveName}" is not a valid curve name`);
|
|
906
1024
|
}
|
|
907
1025
|
createSarmal(canvas, curveDef, {
|
|
908
|
-
...(canvas.dataset.trailColor && {
|
|
1026
|
+
...(canvas.dataset.trailColor && {
|
|
1027
|
+
trailColor: parseTrailColor(canvas.dataset.trailColor),
|
|
1028
|
+
}),
|
|
909
1029
|
...(canvas.dataset.skeletonColor && { skeletonColor: canvas.dataset.skeletonColor }),
|
|
910
1030
|
...(canvas.dataset.headColor && { headColor: canvas.dataset.headColor }),
|
|
911
1031
|
...(canvas.dataset.headRadius && { headRadius: parseFloat(canvas.dataset.headRadius) }),
|
|
@@ -913,7 +1033,6 @@ function init() {
|
|
|
913
1033
|
...(canvas.dataset.trailStyle && {
|
|
914
1034
|
trailStyle: canvas.dataset.trailStyle,
|
|
915
1035
|
}),
|
|
916
|
-
...(canvas.dataset.palette && { palette: parsePalette(canvas.dataset.palette) }),
|
|
917
1036
|
});
|
|
918
1037
|
});
|
|
919
1038
|
}
|