@sarmal/core 0.15.0 → 0.16.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/index.js CHANGED
@@ -519,6 +519,7 @@ function warnIfTrailColorMismatch(trailColor, trailStyle) {
519
519
  );
520
520
  }
521
521
  }
522
+ var getHeadDotRadius = (w, h) => Math.max(1, 3 * Math.sqrt(Math.min(w, h) / 160));
522
523
 
523
524
  // src/renderer.ts
524
525
  var WHITE_HEX = "#ffffff";
@@ -549,9 +550,8 @@ function createRenderer(options) {
549
550
  warnIfTrailColorMismatch(trailColor, trailStyle);
550
551
  const dpr = typeof window !== "undefined" ? window.devicePixelRatio || 1 : 1;
551
552
  function setupCanvas() {
552
- const rect = canvas.getBoundingClientRect();
553
- const lw = rect.width || 200;
554
- const lh = rect.height || 200;
553
+ const lw = canvas.offsetWidth || 200;
554
+ const lh = canvas.offsetHeight || 200;
555
555
  applyDprSizing(canvas, lw, lh, dpr);
556
556
  ctx.setTransform(dpr, 0, 0, dpr, 0, 0);
557
557
  }
@@ -569,6 +569,7 @@ function createRenderer(options) {
569
569
  let animationId = null;
570
570
  let lastTime = 0;
571
571
  let morphResolve = null;
572
+ let morphReject = null;
572
573
  let morphDurationMs = DEFAULT_MORPH_DURATION_MS;
573
574
  let morphAlpha = 0;
574
575
  let gradientAnimTime = 0;
@@ -673,8 +674,7 @@ function createRenderer(options) {
673
674
  }
674
675
  const x = head.x * scale + offsetX;
675
676
  const y = head.y * scale + offsetY;
676
- const r =
677
- options.headRadius ?? Math.max(2, 3 * Math.sqrt(Math.min(logicalWidth, logicalHeight) / 160));
677
+ const r = options.headRadius ?? getHeadDotRadius(logicalWidth, logicalHeight);
678
678
  ctx.fillStyle = headColor;
679
679
  ctx.beginPath();
680
680
  ctx.arc(x, y, r, 0, Math.PI * 2);
@@ -698,6 +698,7 @@ function createRenderer(options) {
698
698
  engine.completeMorph();
699
699
  morphResolve?.();
700
700
  morphResolve = null;
701
+ morphReject = null;
701
702
  morphAlpha = 0;
702
703
  skeleton = engine.getSarmalSkeleton();
703
704
  if (!engine.isLiveSkeleton) {
@@ -760,6 +761,11 @@ function createRenderer(options) {
760
761
  cancelAnimationFrame(animationId);
761
762
  animationId = null;
762
763
  }
764
+ if (morphReject !== null) {
765
+ morphReject(new Error("Instance destroyed during morph"));
766
+ morphResolve = null;
767
+ morphReject = null;
768
+ }
763
769
  },
764
770
  ...enginePassthroughs(engine),
765
771
  morphTo(target, options2) {
@@ -767,13 +773,15 @@ function createRenderer(options) {
767
773
  engine.completeMorph();
768
774
  morphResolve();
769
775
  morphResolve = null;
776
+ morphReject = null;
770
777
  morphAlpha = 0;
771
778
  }
772
779
  morphDurationMs = options2?.duration ?? DEFAULT_MORPH_DURATION_MS;
773
780
  morphAlpha = 0;
774
781
  engine.startMorph(target, options2?.morphStrategy);
775
- return new Promise((resolve) => {
782
+ return new Promise((resolve, reject) => {
776
783
  morphResolve = resolve;
784
+ morphReject = reject;
777
785
  });
778
786
  },
779
787
  setRenderOptions(partial) {
@@ -848,11 +856,10 @@ function createSVGRenderer(options) {
848
856
  let trailPalette = resolveTrailPalette(trailColor);
849
857
  const ariaLabel = options.ariaLabel ?? "Loading";
850
858
  warnIfTrailColorMismatch(trailColor, trailStyle);
851
- const rect = container.getBoundingClientRect();
852
- const width = rect.width || 200;
853
- const height = rect.height || 200;
854
- const headRadius =
855
- options.headRadius ?? Math.max(2, 3 * Math.sqrt(Math.min(width, height) / 160));
859
+ const htmlContainer = container;
860
+ const width = htmlContainer.offsetWidth || 200;
861
+ const height = htmlContainer.offsetHeight || 200;
862
+ const headRadius = options.headRadius ?? getHeadDotRadius(width, height);
856
863
  const svg = el("svg");
857
864
  svg.setAttribute("width", String(width));
858
865
  svg.setAttribute("height", String(height));
@@ -932,7 +939,10 @@ function createSVGRenderer(options) {
932
939
  }
933
940
  return;
934
941
  }
935
- for (let i = 0; i < trailCount - 1; i++) {
942
+ const startIdx = Math.max(0, trailCount - 1 - MAX_TRAIL_SEGMENTS);
943
+ const drawnCount = trailCount - 1 - startIdx;
944
+ for (let i = startIdx; i < trailCount - 1; i++) {
945
+ const j = i - startIdx;
936
946
  const { l0x, l0y, r0x, r0y, l1x, l1y, r1x, r1y, opacity, progress } = computeTrailQuad(
937
947
  trail,
938
948
  i,
@@ -941,15 +951,15 @@ function createSVGRenderer(options) {
941
951
  py,
942
952
  );
943
953
  const d = `M${l0x.toFixed(2)} ${l0y.toFixed(2)} L${l1x.toFixed(2)} ${l1y.toFixed(2)} L${r1x.toFixed(2)} ${r1y.toFixed(2)} L${r0x.toFixed(2)} ${r0y.toFixed(2)} Z`;
944
- trailPaths[i].setAttribute("d", d);
945
- trailPaths[i].setAttribute("fill-opacity", opacity.toFixed(3));
954
+ trailPaths[j].setAttribute("d", d);
955
+ trailPaths[j].setAttribute("fill-opacity", opacity.toFixed(3));
946
956
  if (trailStyle !== "default") {
947
957
  const timeOffset = trailStyle === "gradient-animated" ? gradientAnimTime * 5e-4 : 0;
948
958
  const { r, g, b } = getPaletteColor(trailPalette, progress, timeOffset);
949
- trailPaths[i].setAttribute("fill", `rgb(${r},${g},${b})`);
959
+ trailPaths[j].setAttribute("fill", `rgb(${r},${g},${b})`);
950
960
  }
951
961
  }
952
- for (let i = trailCount - 1; i < trailPaths.length; i++) {
962
+ for (let i = drawnCount; i < trailPaths.length; i++) {
953
963
  trailPaths[i].setAttribute("d", "");
954
964
  }
955
965
  }
@@ -968,6 +978,7 @@ function createSVGRenderer(options) {
968
978
  const prefersReducedMotion =
969
979
  typeof window !== "undefined" && window.matchMedia("(prefers-reduced-motion: reduce)").matches;
970
980
  let morphResolve = null;
981
+ let morphReject = null;
971
982
  let morphDurationMs = DEFAULT_MORPH_DURATION_MS;
972
983
  let morphTarget = null;
973
984
  let morphAlpha = 0;
@@ -995,6 +1006,7 @@ function createSVGRenderer(options) {
995
1006
  engine.completeMorph();
996
1007
  morphResolve?.();
997
1008
  morphResolve = null;
1009
+ morphReject = null;
998
1010
  morphTarget = null;
999
1011
  morphAlpha = 0;
1000
1012
  morphPathABuilt = "";
@@ -1054,6 +1066,11 @@ function createSVGRenderer(options) {
1054
1066
  cancelAnimationFrame(animationId);
1055
1067
  animationId = null;
1056
1068
  }
1069
+ if (morphReject !== null) {
1070
+ morphReject(new Error("Instance destroyed during morph"));
1071
+ morphResolve = null;
1072
+ morphReject = null;
1073
+ }
1057
1074
  svg.remove();
1058
1075
  },
1059
1076
  ...enginePassthroughs(engine),
@@ -1062,6 +1079,7 @@ function createSVGRenderer(options) {
1062
1079
  engine.completeMorph();
1063
1080
  morphResolve();
1064
1081
  morphResolve = null;
1082
+ morphReject = null;
1065
1083
  morphAlpha = 0;
1066
1084
  skeletonPathA.setAttribute("visibility", "hidden");
1067
1085
  skeletonPathB.setAttribute("visibility", "hidden");
@@ -1076,8 +1094,9 @@ function createSVGRenderer(options) {
1076
1094
  const targetSkeleton = sampleCurveSkeleton(target);
1077
1095
  morphPathBBuilt = pointsToPathString(targetSkeleton, scale, offsetX, offsetY);
1078
1096
  }
1079
- return new Promise((resolve) => {
1097
+ return new Promise((resolve, reject) => {
1080
1098
  morphResolve = resolve;
1099
+ morphReject = reject;
1081
1100
  });
1082
1101
  },
1083
1102
  setRenderOptions(partial) {