@sarmal/core 0.30.0 → 0.33.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.
Files changed (53) hide show
  1. package/dist/auto-init.cjs +115 -31
  2. package/dist/auto-init.cjs.map +1 -1
  3. package/dist/auto-init.js +115 -31
  4. package/dist/auto-init.js.map +1 -1
  5. package/dist/cli.js +8 -7
  6. package/dist/cli.js.map +1 -1
  7. package/dist/curves/artemis2.d.cts +1 -1
  8. package/dist/curves/artemis2.d.ts +1 -1
  9. package/dist/curves/astroid.d.cts +1 -1
  10. package/dist/curves/astroid.d.ts +1 -1
  11. package/dist/curves/deltoid.d.cts +1 -1
  12. package/dist/curves/deltoid.d.ts +1 -1
  13. package/dist/curves/epicycloid3.d.cts +1 -1
  14. package/dist/curves/epicycloid3.d.ts +1 -1
  15. package/dist/curves/epitrochoid7.d.cts +1 -1
  16. package/dist/curves/epitrochoid7.d.ts +1 -1
  17. package/dist/curves/index.d.cts +1 -1
  18. package/dist/curves/index.d.ts +1 -1
  19. package/dist/curves/lame.d.cts +1 -1
  20. package/dist/curves/lame.d.ts +1 -1
  21. package/dist/curves/lissajous32.d.cts +1 -1
  22. package/dist/curves/lissajous32.d.ts +1 -1
  23. package/dist/curves/lissajous43.d.cts +1 -1
  24. package/dist/curves/lissajous43.d.ts +1 -1
  25. package/dist/curves/rose3.d.cts +1 -1
  26. package/dist/curves/rose3.d.ts +1 -1
  27. package/dist/curves/rose5.d.cts +1 -1
  28. package/dist/curves/rose5.d.ts +1 -1
  29. package/dist/curves/rose52.d.cts +1 -1
  30. package/dist/curves/rose52.d.ts +1 -1
  31. package/dist/curves/star.d.cts +1 -1
  32. package/dist/curves/star.d.ts +1 -1
  33. package/dist/curves/star4.d.cts +1 -1
  34. package/dist/curves/star4.d.ts +1 -1
  35. package/dist/curves/star7.d.cts +1 -1
  36. package/dist/curves/star7.d.ts +1 -1
  37. package/dist/index.cjs +122 -34
  38. package/dist/index.cjs.map +1 -1
  39. package/dist/index.d.cts +3 -3
  40. package/dist/index.d.ts +3 -3
  41. package/dist/index.js +122 -34
  42. package/dist/index.js.map +1 -1
  43. package/dist/{renderer-shared-OR--cv-t.d.ts → renderer-shared-Bdca4O4G.d.ts} +8 -4
  44. package/dist/{renderer-shared-jqw_Q1WO.d.cts → renderer-shared-Ke9BeK1P.d.cts} +8 -4
  45. package/dist/terminal.cjs +8 -7
  46. package/dist/terminal.cjs.map +1 -1
  47. package/dist/terminal.d.cts +2 -2
  48. package/dist/terminal.d.ts +2 -2
  49. package/dist/terminal.js +8 -7
  50. package/dist/terminal.js.map +1 -1
  51. package/dist/{types-zbxUgcmZ.d.cts → types-BBuUk6nn.d.cts} +9 -0
  52. package/dist/{types-zbxUgcmZ.d.ts → types-BBuUk6nn.d.ts} +9 -0
  53. package/package.json +1 -1
package/dist/auto-init.js CHANGED
@@ -404,6 +404,49 @@ function parseColorToRgb(s) {
404
404
  }
405
405
  return null;
406
406
  }
407
+ var OKLCH_RE = /^oklch\(\s*([\d.]+)\s+([\d.]+)\s+([\d.]+)(?:\s*\/\s*[\d.]+)?\s*\)$/i;
408
+ function parseOklchToOklab(s) {
409
+ const m = OKLCH_RE.exec(s.trim());
410
+ if (!m) {
411
+ return null;
412
+ }
413
+ const L = parseFloat(m[1]);
414
+ const C = parseFloat(m[2]);
415
+ const H = parseFloat(m[3]);
416
+ if (Number.isNaN(L) || Number.isNaN(C) || Number.isNaN(H)) {
417
+ return null;
418
+ }
419
+ const clampedL = Math.max(0, Math.min(1, L));
420
+ const clampedC = Math.max(0, Math.min(0.4, C));
421
+ const H_rad = H * (Math.PI / 180);
422
+ return {
423
+ L: clampedL,
424
+ a: clampedC * Math.cos(H_rad),
425
+ b: clampedC * Math.sin(H_rad)
426
+ };
427
+ }
428
+ function parseColorToOklab(s) {
429
+ const oklab = parseOklchToOklab(s);
430
+ if (oklab !== null) {
431
+ return oklab;
432
+ }
433
+ const rgb = parseColorToRgb(s);
434
+ if (rgb === null) {
435
+ return null;
436
+ }
437
+ return rgbToOklab(rgb);
438
+ }
439
+ function colorToRgb(color) {
440
+ const rgb = parseColorToRgb(color);
441
+ if (rgb !== null) {
442
+ return rgb;
443
+ }
444
+ const lab = parseOklchToOklab(color);
445
+ if (lab !== null) {
446
+ return oklabToRgb(lab);
447
+ }
448
+ throw new Error(`[sarmal] unrecognized color "${color}"`);
449
+ }
407
450
  function srgbByteToLinear(c) {
408
451
  const n = c / 255;
409
452
  return n <= 0.04045 ? n / 12.92 : Math.pow((n + 0.055) / 1.055, 2.4);
@@ -441,26 +484,25 @@ var lerpOklab = (a, b, t) => {
441
484
  if (t >= 1) {
442
485
  return b;
443
486
  }
444
- const la = rgbToOklab(a), lb = rgbToOklab(b);
445
- return oklabToRgb({
446
- L: la.L + (lb.L - la.L) * t,
447
- a: la.a + (lb.a - la.a) * t,
448
- b: la.b + (lb.b - la.b) * t
449
- });
487
+ return {
488
+ L: a.L + (b.L - a.L) * t,
489
+ a: a.a + (b.a - a.a) * t,
490
+ b: a.b + (b.b - a.b) * t
491
+ };
450
492
  };
451
493
  function getPaletteColor(palette, position, timeOffset = 0) {
452
494
  if (palette.length === 0) {
453
- return { r: 255, g: 255, b: 255 };
495
+ return { L: 1, a: 0, b: 0 };
454
496
  }
455
497
  if (palette.length === 1) {
456
- return hexToRgb(palette[0]);
498
+ return palette[0];
457
499
  }
458
500
  const cyclePos = ((position + timeOffset) % 1 + 1) % 1;
459
501
  const scaled = cyclePos * palette.length;
460
502
  const idx = Math.floor(scaled);
461
503
  const t = scaled - idx;
462
- const c1 = hexToRgb(palette[idx % palette.length]);
463
- const c2 = hexToRgb(palette[(idx + 1) % palette.length]);
504
+ const c1 = palette[idx % palette.length];
505
+ const c2 = palette[(idx + 1) % palette.length];
464
506
  return lerpOklab(c1, c2, t);
465
507
  }
466
508
  var TRAIL_STYLES = ["default", "gradient-static", "gradient-animated"];
@@ -469,7 +511,8 @@ var RENDER_OPTION_KEYS = /* @__PURE__ */ new Set([
469
511
  "headColor",
470
512
  "skeletonColor",
471
513
  "trailStyle",
472
- "headRadius"
514
+ "headRadius",
515
+ "trailWidth"
473
516
  ]);
474
517
  function validateRenderOptions(partial) {
475
518
  for (const key of Object.keys(partial)) {
@@ -492,12 +535,15 @@ function validateRenderOptions(partial) {
492
535
  if (partial.headRadius !== void 0) {
493
536
  assertHeadRadius(partial.headRadius);
494
537
  }
538
+ if (partial.trailWidth !== void 0) {
539
+ assertTrailWidth(partial.trailWidth);
540
+ }
495
541
  }
496
542
  function assertTrailColor(value) {
497
543
  if (typeof value === "string") {
498
- if (parseColorToRgb(value) === null) {
544
+ if (parseColorToOklab(value) === null) {
499
545
  throw new TypeError(
500
- `[sarmal] setRenderOptions: trailColor must be a valid color string (#rrggbb, #rgb, rgb(), rgba()), got "${value}"`
546
+ `[sarmal] setRenderOptions: trailColor must be a valid color string (#rrggbb, #rgb, rgb(), rgba(), oklch()), got "${value}"`
501
547
  );
502
548
  }
503
549
  return;
@@ -510,25 +556,25 @@ function assertTrailColor(value) {
510
556
  }
511
557
  for (let i = 0; i < value.length; i++) {
512
558
  const entry = value[i];
513
- if (typeof entry !== "string" || parseColorToRgb(entry) === null) {
559
+ if (typeof entry !== "string" || parseColorToOklab(entry) === null) {
514
560
  throw new TypeError(
515
- `[sarmal] setRenderOptions: trailColor[${i}] must be a valid color string (#rrggbb, #rgb, rgb(), rgba()), got ${JSON.stringify(entry)}`
561
+ `[sarmal] setRenderOptions: trailColor[${i}] must be a valid color string (#rrggbb, #rgb, rgb(), rgba(), oklch()), got ${JSON.stringify(entry)}`
516
562
  );
517
563
  }
518
564
  }
519
565
  return;
520
566
  }
521
567
  throw new TypeError(
522
- `[sarmal] setRenderOptions: trailColor must be a valid color string (#rrggbb, #rgb, rgb(), rgba()) or an array of color strings, got ${JSON.stringify(value)}`
568
+ `[sarmal] setRenderOptions: trailColor must be a valid color string (#rrggbb, #rgb, rgb(), rgba(), oklch()) or an array of color strings, got ${JSON.stringify(value)}`
523
569
  );
524
570
  }
525
571
  function assertHeadColor(value) {
526
572
  if (value === null) {
527
573
  return;
528
574
  }
529
- if (typeof value !== "string" || parseColorToRgb(value) === null) {
575
+ if (typeof value !== "string" || parseColorToOklab(value) === null) {
530
576
  throw new TypeError(
531
- `[sarmal] setRenderOptions: headColor must be a valid color string (#rrggbb, #rgb, rgb(), rgba()) or null, got ${JSON.stringify(value)}`
577
+ `[sarmal] setRenderOptions: headColor must be a valid color string (#rrggbb, #rgb, rgb(), rgba(), oklch()) or null, got ${JSON.stringify(value)}`
532
578
  );
533
579
  }
534
580
  }
@@ -536,9 +582,9 @@ function assertSkeletonColor(value) {
536
582
  if (value === "transparent") {
537
583
  return;
538
584
  }
539
- if (typeof value !== "string" || parseColorToRgb(value) === null) {
585
+ if (typeof value !== "string" || parseColorToOklab(value) === null) {
540
586
  throw new TypeError(
541
- `[sarmal] setRenderOptions: skeletonColor must be a valid color string (#rrggbb, #rgb, rgb(), rgba()) or "transparent", got ${JSON.stringify(value)}`
587
+ `[sarmal] setRenderOptions: skeletonColor must be a valid color string (#rrggbb, #rgb, rgb(), rgba(), oklch()) or "transparent", got ${JSON.stringify(value)}`
542
588
  );
543
589
  }
544
590
  }
@@ -561,6 +607,18 @@ function assertHeadRadius(value) {
561
607
  );
562
608
  }
563
609
  }
610
+ function assertTrailWidth(value) {
611
+ if (typeof value !== "number") {
612
+ throw new TypeError(
613
+ `[sarmal] setRenderOptions: trailWidth must be a number, got ${JSON.stringify(value)}`
614
+ );
615
+ }
616
+ if (!Number.isFinite(value) || value <= 0) {
617
+ throw new TypeError(
618
+ `[sarmal] setRenderOptions: trailWidth must be a finite positive number, got ${value}`
619
+ );
620
+ }
621
+ }
564
622
  function resolveTrailMainColor(trailColor) {
565
623
  return typeof trailColor === "string" ? trailColor : trailColor[0];
566
624
  }
@@ -573,7 +631,7 @@ function resolveHeadColor(trailColor, trailStyle) {
573
631
  }
574
632
  const palette = resolveTrailPalette(trailColor);
575
633
  const last = palette[palette.length - 1];
576
- const { r, g, b } = parseColorToRgb(last);
634
+ const { r, g, b } = colorToRgb(last);
577
635
  return `rgb(${r},${g},${b})`;
578
636
  }
579
637
  function warnIfTrailColorMismatch(trailColor, trailStyle) {
@@ -594,8 +652,8 @@ function warnIfTrailColorMismatch(trailColor, trailStyle) {
594
652
  var getHeadDotRadius = (w, h) => Math.max(1, 3 * Math.sqrt(Math.min(w, h) / 160));
595
653
  var WHITE_HEX = "#ffffff";
596
654
  function colorToRgbComponents(color) {
597
- const c = parseColorToRgb(color);
598
- return `${c.r},${c.g},${c.b}`;
655
+ const { r, g, b } = colorToRgb(color);
656
+ return `${r},${g},${b}`;
599
657
  }
600
658
  function applyDprSizing(target, logicalWidth, logicalHeight, dpr) {
601
659
  target.style.width = `${logicalWidth}px`;
@@ -617,6 +675,7 @@ function createRenderer(options) {
617
675
  let headColor = userHeadColor ?? resolveHeadColor(trailColor, trailStyle);
618
676
  let trailSolidRgb = colorToRgbComponents(resolveTrailMainColor(trailColor));
619
677
  let trailPalette = resolveTrailPalette(trailColor);
678
+ let trailPaletteOklab = trailPalette.map((c) => parseColorToOklab(c));
620
679
  warnIfTrailColorMismatch(trailColor, trailStyle);
621
680
  const dpr = typeof window !== "undefined" ? window.devicePixelRatio || 1 : 1;
622
681
  function setupCanvas() {
@@ -628,7 +687,14 @@ function createRenderer(options) {
628
687
  setupCanvas();
629
688
  let logicalWidth = canvas.width / dpr;
630
689
  let logicalHeight = canvas.height / dpr;
690
+ if (options.headRadius !== void 0) {
691
+ validateRenderOptions({ headRadius: options.headRadius });
692
+ }
693
+ if (options.trailWidth !== void 0) {
694
+ validateRenderOptions({ trailWidth: options.trailWidth });
695
+ }
631
696
  let headRadius = options.headRadius ?? getHeadDotRadius(logicalWidth, logicalHeight);
697
+ let trailWidth = options.trailWidth ?? 1;
632
698
  let skeleton = [];
633
699
  let skeletonCanvas = null;
634
700
  let trail = [];
@@ -722,14 +788,16 @@ function createRenderer(options) {
722
788
  i,
723
789
  trailCount,
724
790
  toX,
725
- toY
791
+ toY,
792
+ TRAIL_MIN_WIDTH * trailWidth,
793
+ TRAIL_MAX_WIDTH * trailWidth
726
794
  );
727
795
  if (trailStyle === "default") {
728
796
  ctx.fillStyle = `rgba(${trailSolidRgb},${opacity})`;
729
797
  } else {
730
798
  const timeOffset = trailStyle === "gradient-animated" ? gradientAnimTime * 5e-4 : 0;
731
- const color = getPaletteColor(trailPalette, progress, timeOffset);
732
- ctx.fillStyle = `rgba(${color.r},${color.g},${color.b},${opacity})`;
799
+ const { r, g, b } = oklabToRgb(getPaletteColor(trailPaletteOklab, progress, timeOffset));
800
+ ctx.fillStyle = `rgba(${r},${g},${b},${opacity})`;
733
801
  }
734
802
  ctx.beginPath();
735
803
  ctx.moveTo(l0x, l0y);
@@ -863,6 +931,7 @@ function createRenderer(options) {
863
931
  trailColor = partial.trailColor;
864
932
  trailSolidRgb = colorToRgbComponents(resolveTrailMainColor(trailColor));
865
933
  trailPalette = resolveTrailPalette(trailColor);
934
+ trailPaletteOklab = trailPalette.map((c) => parseColorToOklab(c));
866
935
  }
867
936
  if (partial.skeletonColor !== void 0) {
868
937
  skeletonColor = partial.skeletonColor;
@@ -879,6 +948,9 @@ function createRenderer(options) {
879
948
  if (partial.headRadius !== void 0) {
880
949
  headRadius = partial.headRadius;
881
950
  }
951
+ if (partial.trailWidth !== void 0) {
952
+ trailWidth = partial.trailWidth;
953
+ }
882
954
  if (userHeadColor === null) {
883
955
  headColor = resolveHeadColor(trailColor, trailStyle);
884
956
  } else {
@@ -946,8 +1018,8 @@ function el(tag) {
946
1018
  return document.createElementNS("http://www.w3.org/2000/svg", tag);
947
1019
  }
948
1020
  function colorToRgbAttr(color) {
949
- const c = parseColorToRgb(color);
950
- return `rgb(${c.r},${c.g},${c.b})`;
1021
+ const { r, g, b } = colorToRgb(color);
1022
+ return `rgb(${r},${g},${b})`;
951
1023
  }
952
1024
  function createSVGRenderer(options) {
953
1025
  const { container, engine } = options;
@@ -965,6 +1037,7 @@ function createSVGRenderer(options) {
965
1037
  let headRadius;
966
1038
  let trailSolid = colorToRgbAttr(resolveTrailMainColor(trailColor));
967
1039
  let trailPalette = resolveTrailPalette(trailColor);
1040
+ let trailPaletteOklab = trailPalette.map((c) => parseColorToOklab(c));
968
1041
  const ariaLabel = options.ariaLabel ?? "Loading";
969
1042
  warnIfTrailColorMismatch(trailColor, trailStyle);
970
1043
  const viewSize = 100;
@@ -976,7 +1049,14 @@ function createSVGRenderer(options) {
976
1049
  const svgTrailMinWidth = TRAIL_MIN_WIDTH * viewSize / containerPx;
977
1050
  const svgTrailMaxWidth = TRAIL_MAX_WIDTH * viewSize / containerPx;
978
1051
  const svgSkeletonStrokeWidth = String(SKELETON_STROKE_WIDTH_PX * viewSize / containerPx);
1052
+ if (options.headRadius !== void 0) {
1053
+ validateRenderOptions({ headRadius: options.headRadius });
1054
+ }
1055
+ if (options.trailWidth !== void 0) {
1056
+ validateRenderOptions({ trailWidth: options.trailWidth });
1057
+ }
979
1058
  headRadius = options.headRadius ?? SVG_DEFAULT_HEAD_RADIUS;
1059
+ let trailWidth = options.trailWidth ?? 1;
980
1060
  container.setAttribute("viewBox", `0 0 ${viewSize} ${viewSize}`);
981
1061
  container.setAttribute("role", "img");
982
1062
  container.setAttribute("aria-label", ariaLabel);
@@ -1071,15 +1151,15 @@ function createSVGRenderer(options) {
1071
1151
  trailCount,
1072
1152
  px,
1073
1153
  py,
1074
- svgTrailMinWidth,
1075
- svgTrailMaxWidth
1154
+ svgTrailMinWidth * trailWidth,
1155
+ svgTrailMaxWidth * trailWidth
1076
1156
  );
1077
1157
  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`;
1078
1158
  trailPaths[i].setAttribute("d", d);
1079
1159
  trailPaths[i].setAttribute("fill-opacity", opacity.toFixed(3));
1080
1160
  if (trailStyle !== "default") {
1081
1161
  const timeOffset = trailStyle === "gradient-animated" ? gradientAnimTime * 5e-4 : 0;
1082
- const { r, g, b } = getPaletteColor(trailPalette, progress, timeOffset);
1162
+ const { r, g, b } = oklabToRgb(getPaletteColor(trailPaletteOklab, progress, timeOffset));
1083
1163
  trailPaths[i].setAttribute("fill", `rgb(${r},${g},${b})`);
1084
1164
  }
1085
1165
  }
@@ -1231,6 +1311,7 @@ function createSVGRenderer(options) {
1231
1311
  trailColor = partial.trailColor;
1232
1312
  trailSolid = colorToRgbAttr(resolveTrailMainColor(trailColor));
1233
1313
  trailPalette = resolveTrailPalette(trailColor);
1314
+ trailPaletteOklab = trailPalette.map((c) => parseColorToOklab(c));
1234
1315
  if (trailStyle === "default") {
1235
1316
  for (const p of trailPaths) {
1236
1317
  p.setAttribute("fill", trailSolid);
@@ -1263,6 +1344,9 @@ function createSVGRenderer(options) {
1263
1344
  headRadius = partial.headRadius;
1264
1345
  headCircle.setAttribute("r", String(headRadius));
1265
1346
  }
1347
+ if (partial.trailWidth !== void 0) {
1348
+ trailWidth = partial.trailWidth;
1349
+ }
1266
1350
  if (userHeadColor === null) {
1267
1351
  headColor = resolveHeadColor(trailColor, trailStyle);
1268
1352
  } else {