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