@sarmal/core 0.35.0 → 0.36.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 +5 -3
- package/dist/auto-init.cjs +3 -1
- package/dist/auto-init.cjs.map +1 -1
- package/dist/auto-init.js +3 -1
- package/dist/auto-init.js.map +1 -1
- package/dist/cli.js +9 -3
- package/dist/cli.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/curves/rose52.d.cts +1 -1
- package/dist/curves/rose52.d.ts +1 -1
- package/dist/curves/star.d.cts +1 -1
- package/dist/curves/star.d.ts +1 -1
- package/dist/curves/star4.d.cts +1 -1
- package/dist/curves/star4.d.ts +1 -1
- package/dist/curves/star7.d.cts +1 -1
- package/dist/curves/star7.d.ts +1 -1
- package/dist/index.cjs +109 -50
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +4 -4
- package/dist/index.d.ts +4 -4
- package/dist/index.js +109 -50
- package/dist/index.js.map +1 -1
- package/dist/{renderer-shared-DyOI68gd.d.ts → renderer-shared-BZV9ELOa.d.ts} +1 -1
- package/dist/{renderer-shared-C3KCEABq.d.cts → renderer-shared-CFimm7VD.d.cts} +1 -1
- package/dist/terminal.cjs +9 -3
- package/dist/terminal.cjs.map +1 -1
- package/dist/terminal.d.cts +2 -2
- package/dist/terminal.d.ts +2 -2
- package/dist/terminal.js +9 -3
- package/dist/terminal.js.map +1 -1
- package/dist/{types-_f27GDkU.d.cts → types-CCgSK31t.d.cts} +8 -4
- package/dist/{types-_f27GDkU.d.ts → types-CCgSK31t.d.ts} +8 -4
- package/package.json +2 -2
package/dist/curves/index.d.ts
CHANGED
package/dist/curves/lame.d.cts
CHANGED
package/dist/curves/lame.d.ts
CHANGED
package/dist/curves/rose3.d.cts
CHANGED
package/dist/curves/rose3.d.ts
CHANGED
package/dist/curves/rose5.d.cts
CHANGED
package/dist/curves/rose5.d.ts
CHANGED
package/dist/curves/rose52.d.cts
CHANGED
package/dist/curves/rose52.d.ts
CHANGED
package/dist/curves/star.d.cts
CHANGED
package/dist/curves/star.d.ts
CHANGED
package/dist/curves/star4.d.cts
CHANGED
package/dist/curves/star4.d.ts
CHANGED
package/dist/curves/star7.d.cts
CHANGED
package/dist/curves/star7.d.ts
CHANGED
package/dist/index.cjs
CHANGED
|
@@ -322,7 +322,9 @@ function computeTrailQuad(trail, i, trailCount, toX, toY, minWidth = TRAIL_MIN_W
|
|
|
322
322
|
};
|
|
323
323
|
}
|
|
324
324
|
function computeBoundaries(pts, logicalWidth, logicalHeight, minPaddingPx = FIT_PADDING_MIN) {
|
|
325
|
-
if (pts.length === 0)
|
|
325
|
+
if (pts.length === 0) {
|
|
326
|
+
return null;
|
|
327
|
+
}
|
|
326
328
|
const first = pts[0];
|
|
327
329
|
let minX = first.x, maxX = first.x, minY = first.y, maxY = first.y;
|
|
328
330
|
for (const p of pts) {
|
|
@@ -520,7 +522,11 @@ function getPaletteColor(palette, position, timeOffset = 0) {
|
|
|
520
522
|
return lerpOklab(c1, c2, t);
|
|
521
523
|
}
|
|
522
524
|
var TRAIL_STYLES = ["default", "gradient-static", "gradient-animated"];
|
|
523
|
-
var BASE_RENDER_OPTION_KEYS = /* @__PURE__ */ new Set([
|
|
525
|
+
var BASE_RENDER_OPTION_KEYS = /* @__PURE__ */ new Set([
|
|
526
|
+
"trailColor",
|
|
527
|
+
"trailStyle",
|
|
528
|
+
"skeletonColor"
|
|
529
|
+
]);
|
|
524
530
|
var RENDER_OPTION_KEYS = /* @__PURE__ */ new Set([
|
|
525
531
|
"trailColor",
|
|
526
532
|
"headColor",
|
|
@@ -541,6 +547,9 @@ function validateBaseRenderOptions(partial) {
|
|
|
541
547
|
if (partial.trailStyle !== void 0) {
|
|
542
548
|
assertTrailStyle(partial.trailStyle);
|
|
543
549
|
}
|
|
550
|
+
if (partial.skeletonColor !== void 0) {
|
|
551
|
+
assertSkeletonColor(partial.skeletonColor);
|
|
552
|
+
}
|
|
544
553
|
}
|
|
545
554
|
function validateRenderOptions(partial) {
|
|
546
555
|
for (const key of Object.keys(partial)) {
|
|
@@ -1426,6 +1435,7 @@ function createSarmalDotMatrix(canvas, curveDef, options) {
|
|
|
1426
1435
|
trailLength: trailLengthOpt,
|
|
1427
1436
|
trailColor: initialColor = "#ffffff",
|
|
1428
1437
|
trailStyle: initialTrailStyle = "default",
|
|
1438
|
+
skeletonColor: skeletonColorOpt = "#ffffff",
|
|
1429
1439
|
autoStart = true,
|
|
1430
1440
|
pauseOnHidden: pauseOnHiddenOpt = true,
|
|
1431
1441
|
initialPhase
|
|
@@ -1441,14 +1451,8 @@ function createSarmalDotMatrix(canvas, curveDef, options) {
|
|
|
1441
1451
|
const cellW = W / cols;
|
|
1442
1452
|
const cellH = H / rows;
|
|
1443
1453
|
const dotR = Math.min(cellW, cellH) * 0.36;
|
|
1444
|
-
let
|
|
1445
|
-
|
|
1446
|
-
validateBaseRenderOptions({ trailColor: initialColor });
|
|
1447
|
-
gradientRgb = initialColor.map(colorToRgb);
|
|
1448
|
-
} else {
|
|
1449
|
-
gradientRgb = null;
|
|
1450
|
-
}
|
|
1451
|
-
let colorRgb = gradientRgb ? gradientRgb[0] : colorToRgb(initialColor);
|
|
1454
|
+
let gradientOklab = null;
|
|
1455
|
+
let colorRgb = { r: 255, g: 255, b: 255 };
|
|
1452
1456
|
let currentTrailStyle = initialTrailStyle;
|
|
1453
1457
|
let animTime = 0;
|
|
1454
1458
|
const ANIM_PERIOD = 6;
|
|
@@ -1462,6 +1466,8 @@ function createSarmalDotMatrix(canvas, curveDef, options) {
|
|
|
1462
1466
|
let pixelMaskCoverages = new Float32Array(0);
|
|
1463
1467
|
let bgImageData = null;
|
|
1464
1468
|
let frameImageData = null;
|
|
1469
|
+
let skeletonColorOklab = null;
|
|
1470
|
+
const skeletonDotGrid = new Uint8Array(cols * rows);
|
|
1465
1471
|
let animationId = null;
|
|
1466
1472
|
let lastTime = 0;
|
|
1467
1473
|
let pausedByVisibility = false;
|
|
@@ -1520,7 +1526,7 @@ function createSarmalDotMatrix(canvas, curveDef, options) {
|
|
|
1520
1526
|
}
|
|
1521
1527
|
function buildBgImageData() {
|
|
1522
1528
|
bgImageData = new ImageData(W, H);
|
|
1523
|
-
const bg =
|
|
1529
|
+
const bg = colorRgb;
|
|
1524
1530
|
const baseAlpha = 0.05 * 255;
|
|
1525
1531
|
const { data } = bgImageData;
|
|
1526
1532
|
const n = cols * rows;
|
|
@@ -1537,18 +1543,61 @@ function createSarmalDotMatrix(canvas, curveDef, options) {
|
|
|
1537
1543
|
}
|
|
1538
1544
|
}
|
|
1539
1545
|
}
|
|
1540
|
-
function
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1546
|
+
function applyColor(color) {
|
|
1547
|
+
if (Array.isArray(color)) {
|
|
1548
|
+
gradientOklab = color.map((c) => parseColorToOklab(c));
|
|
1549
|
+
colorRgb = oklabToRgb(gradientOklab[0]);
|
|
1550
|
+
} else {
|
|
1551
|
+
gradientOklab = null;
|
|
1552
|
+
colorRgb = colorToRgb(color);
|
|
1553
|
+
}
|
|
1554
|
+
}
|
|
1555
|
+
function applySkeletonColor(color) {
|
|
1556
|
+
skeletonColorOklab = color === "transparent" ? null : parseColorToOklab(color);
|
|
1557
|
+
}
|
|
1558
|
+
function computeSkeletonGrid(skel) {
|
|
1559
|
+
skeletonDotGrid.fill(0);
|
|
1560
|
+
const count = skel.length;
|
|
1561
|
+
for (let i = 0; i < count; i++) {
|
|
1562
|
+
const pt = skel[i];
|
|
1563
|
+
const [c, r] = mapPt(pt.x, pt.y);
|
|
1564
|
+
skeletonDotGrid[r * cols + c] = 1;
|
|
1565
|
+
if (i < count - 1) {
|
|
1566
|
+
const next = skel[i + 1];
|
|
1567
|
+
const [nc, nr] = mapPt(next.x, next.y);
|
|
1568
|
+
const steps = Math.ceil(Math.max(Math.abs(nc - c), Math.abs(nr - r))) * 2;
|
|
1569
|
+
for (let s = 1; s < steps; s++) {
|
|
1570
|
+
const t = s / steps;
|
|
1571
|
+
const ix = pt.x + (next.x - pt.x) * t;
|
|
1572
|
+
const iy = pt.y + (next.y - pt.y) * t;
|
|
1573
|
+
const [ic, ir] = mapPt(ix, iy);
|
|
1574
|
+
skeletonDotGrid[ir * cols + ic] = 1;
|
|
1575
|
+
}
|
|
1576
|
+
}
|
|
1577
|
+
}
|
|
1578
|
+
}
|
|
1579
|
+
function writeSkeletonPixels(data) {
|
|
1580
|
+
if (skeletonColorOklab === null) {
|
|
1581
|
+
return;
|
|
1582
|
+
}
|
|
1583
|
+
const { r, g, b } = oklabToRgb(skeletonColorOklab);
|
|
1584
|
+
const skelBaseAlpha = DEFAULT_SKELETON_OPACITY * 255;
|
|
1585
|
+
const n = cols * rows;
|
|
1586
|
+
for (let dotIdx = 0; dotIdx < n; dotIdx++) {
|
|
1587
|
+
if (!skeletonDotGrid[dotIdx]) {
|
|
1588
|
+
continue;
|
|
1589
|
+
}
|
|
1590
|
+
const start = pixelMaskStarts[dotIdx];
|
|
1591
|
+
const len = pixelMaskLengths[dotIdx];
|
|
1592
|
+
for (let k = 0; k < len; k++) {
|
|
1593
|
+
const px = pixelMaskIndices[start + k];
|
|
1594
|
+
const coverage = pixelMaskCoverages[start + k];
|
|
1595
|
+
data[px] = r;
|
|
1596
|
+
data[px + 1] = g;
|
|
1597
|
+
data[px + 2] = b;
|
|
1598
|
+
data[px + 3] = Math.round(skelBaseAlpha * coverage);
|
|
1599
|
+
}
|
|
1600
|
+
}
|
|
1552
1601
|
}
|
|
1553
1602
|
function calculateBoundaries(skel) {
|
|
1554
1603
|
const b = computeBoundaries(skel, W, H);
|
|
@@ -1602,7 +1651,8 @@ function createSarmalDotMatrix(canvas, curveDef, options) {
|
|
|
1602
1651
|
}
|
|
1603
1652
|
frameImageData.data.set(bgImageData.data);
|
|
1604
1653
|
const { data } = frameImageData;
|
|
1605
|
-
|
|
1654
|
+
writeSkeletonPixels(data);
|
|
1655
|
+
const timeOffset = currentTrailStyle === "gradient-animated" ? animTime / ANIM_PERIOD : 0;
|
|
1606
1656
|
const n = cols * rows;
|
|
1607
1657
|
for (let dotIdx = 0; dotIdx < n; dotIdx++) {
|
|
1608
1658
|
const intensity = grid[dotIdx];
|
|
@@ -1610,9 +1660,8 @@ function createSarmalDotMatrix(canvas, curveDef, options) {
|
|
|
1610
1660
|
continue;
|
|
1611
1661
|
}
|
|
1612
1662
|
let r, g, b;
|
|
1613
|
-
if (
|
|
1614
|
-
|
|
1615
|
-
({ r, g, b } = sampleGradientRgb(gradientRgb, t));
|
|
1663
|
+
if (gradientOklab !== null) {
|
|
1664
|
+
({ r, g, b } = oklabToRgb(getPaletteColor(gradientOklab, intensity, timeOffset)));
|
|
1616
1665
|
} else {
|
|
1617
1666
|
({ r, g, b } = colorRgb);
|
|
1618
1667
|
}
|
|
@@ -1630,21 +1679,26 @@ function createSarmalDotMatrix(canvas, curveDef, options) {
|
|
|
1630
1679
|
}
|
|
1631
1680
|
ctx.putImageData(frameImageData, 0, 0);
|
|
1632
1681
|
}
|
|
1682
|
+
function completeMorphNow() {
|
|
1683
|
+
engine.completeMorph();
|
|
1684
|
+
morphResolve?.();
|
|
1685
|
+
morphResolve = null;
|
|
1686
|
+
morphReject = null;
|
|
1687
|
+
morphProgress = 0;
|
|
1688
|
+
}
|
|
1633
1689
|
function renderFrame(deltaTime) {
|
|
1634
1690
|
if (engine.morphAlpha !== null) {
|
|
1635
1691
|
morphProgress = Math.min(1, morphProgress + deltaTime / (morphDurationMs / 1e3));
|
|
1636
1692
|
engine.setMorphAlpha(morphProgress);
|
|
1637
1693
|
calculateBoundaries(engine.getSarmalSkeleton());
|
|
1638
1694
|
if (morphProgress >= 1) {
|
|
1639
|
-
|
|
1640
|
-
morphResolve?.();
|
|
1641
|
-
morphResolve = null;
|
|
1642
|
-
morphReject = null;
|
|
1643
|
-
morphProgress = 0;
|
|
1695
|
+
completeMorphNow();
|
|
1644
1696
|
calculateBoundaries(engine.getSarmalSkeleton());
|
|
1645
1697
|
}
|
|
1698
|
+
computeSkeletonGrid(engine.getSarmalSkeleton());
|
|
1646
1699
|
} else if (engine.isLiveSkeleton) {
|
|
1647
1700
|
calculateBoundaries(engine.getSarmalSkeleton());
|
|
1701
|
+
computeSkeletonGrid(engine.getSarmalSkeleton());
|
|
1648
1702
|
}
|
|
1649
1703
|
if (currentTrailStyle === "gradient-animated") {
|
|
1650
1704
|
animTime += deltaTime;
|
|
@@ -1658,8 +1712,12 @@ function createSarmalDotMatrix(canvas, curveDef, options) {
|
|
|
1658
1712
|
renderFrame(deltaTime);
|
|
1659
1713
|
animationId = requestAnimationFrame(loop);
|
|
1660
1714
|
}
|
|
1715
|
+
validateBaseRenderOptions({ trailColor: initialColor, skeletonColor: skeletonColorOpt });
|
|
1716
|
+
applyColor(initialColor);
|
|
1717
|
+
applySkeletonColor(skeletonColorOpt);
|
|
1661
1718
|
calculateBoundaries(engine.getSarmalSkeleton());
|
|
1662
1719
|
computePixelMask();
|
|
1720
|
+
computeSkeletonGrid(engine.getSarmalSkeleton());
|
|
1663
1721
|
frameImageData = new ImageData(W, H);
|
|
1664
1722
|
buildBgImageData();
|
|
1665
1723
|
if (initialPhase !== void 0) {
|
|
@@ -1669,13 +1727,17 @@ function createSarmalDotMatrix(canvas, curveDef, options) {
|
|
|
1669
1727
|
const instance = {
|
|
1670
1728
|
/** Starts the animation loop. Does nothing if already running. */
|
|
1671
1729
|
play() {
|
|
1672
|
-
if (animationId !== null)
|
|
1730
|
+
if (animationId !== null) {
|
|
1731
|
+
return;
|
|
1732
|
+
}
|
|
1673
1733
|
lastTime = performance.now();
|
|
1674
1734
|
loop();
|
|
1675
1735
|
},
|
|
1676
1736
|
/** Pauses the animation loop. Preserves current trail state. */
|
|
1677
1737
|
pause() {
|
|
1678
|
-
if (animationId === null)
|
|
1738
|
+
if (animationId === null) {
|
|
1739
|
+
return;
|
|
1740
|
+
}
|
|
1679
1741
|
cancelAnimationFrame(animationId);
|
|
1680
1742
|
animationId = null;
|
|
1681
1743
|
engine.cancelSpeedTransition();
|
|
@@ -1706,11 +1768,7 @@ function createSarmalDotMatrix(canvas, curveDef, options) {
|
|
|
1706
1768
|
*/
|
|
1707
1769
|
morphTo(target, opts) {
|
|
1708
1770
|
if (morphResolve !== null) {
|
|
1709
|
-
|
|
1710
|
-
morphResolve();
|
|
1711
|
-
morphResolve = null;
|
|
1712
|
-
morphReject = null;
|
|
1713
|
-
morphProgress = 0;
|
|
1771
|
+
completeMorphNow();
|
|
1714
1772
|
}
|
|
1715
1773
|
morphDurationMs = opts?.duration ?? DEFAULT_MORPH_DURATION_MS;
|
|
1716
1774
|
morphProgress = 0;
|
|
@@ -1723,23 +1781,20 @@ function createSarmalDotMatrix(canvas, curveDef, options) {
|
|
|
1723
1781
|
/**
|
|
1724
1782
|
* Updates render options on a live instance without stopping the animation.
|
|
1725
1783
|
*
|
|
1726
|
-
* Supported: `trailColor` and `
|
|
1727
|
-
* ! Unsupported fields (`headColor`, `
|
|
1784
|
+
* Supported: `trailColor`, `trailStyle`, and `skeletonColor`.
|
|
1785
|
+
* ! Unsupported fields (`headColor`, `headRadius`, `trailWidth`) throw.
|
|
1728
1786
|
* ! Validation fails the entire call if any field is invalid, leaving options unchanged.
|
|
1729
1787
|
*/
|
|
1730
1788
|
setRenderOptions(partial) {
|
|
1731
1789
|
validateBaseRenderOptions(partial);
|
|
1732
1790
|
let needsRebuildBg = false;
|
|
1733
1791
|
if (partial.trailColor !== void 0) {
|
|
1734
|
-
|
|
1735
|
-
gradientRgb = partial.trailColor.map(colorToRgb);
|
|
1736
|
-
colorRgb = gradientRgb[0];
|
|
1737
|
-
} else {
|
|
1738
|
-
gradientRgb = null;
|
|
1739
|
-
colorRgb = colorToRgb(partial.trailColor);
|
|
1740
|
-
}
|
|
1792
|
+
applyColor(partial.trailColor);
|
|
1741
1793
|
needsRebuildBg = true;
|
|
1742
1794
|
}
|
|
1795
|
+
if (partial.skeletonColor !== void 0) {
|
|
1796
|
+
applySkeletonColor(partial.skeletonColor);
|
|
1797
|
+
}
|
|
1743
1798
|
if (partial.trailStyle !== void 0) {
|
|
1744
1799
|
currentTrailStyle = partial.trailStyle;
|
|
1745
1800
|
if (currentTrailStyle === "default") {
|
|
@@ -1749,9 +1804,13 @@ function createSarmalDotMatrix(canvas, curveDef, options) {
|
|
|
1749
1804
|
if (needsRebuildBg) {
|
|
1750
1805
|
buildBgImageData();
|
|
1751
1806
|
}
|
|
1752
|
-
if (currentTrailStyle !== "default" &&
|
|
1807
|
+
if (currentTrailStyle !== "default" && gradientOklab === null) {
|
|
1808
|
+
console.warn(
|
|
1809
|
+
`[sarmal] dot matrix: trailColor is a single color but trailStyle is "${currentTrailStyle}"; the trail will render as a solid color. Pass an array of hex colors to use a real gradient.`
|
|
1810
|
+
);
|
|
1811
|
+
} else if (currentTrailStyle === "default" && gradientOklab !== null) {
|
|
1753
1812
|
console.warn(
|
|
1754
|
-
|
|
1813
|
+
'[sarmal] dot matrix: trailColor is an array but trailStyle is "default"; only the first color will be used. Pass a gradient trailStyle to use the whole palette.'
|
|
1755
1814
|
);
|
|
1756
1815
|
}
|
|
1757
1816
|
}
|