ansimax 1.3.4 → 1.3.5

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.mjs CHANGED
@@ -389,6 +389,16 @@ var hyperlink = (url, label) => {
389
389
  var clearLine = () => `${CSI}2K\r`;
390
390
 
391
391
  // src/utils/helpers.ts
392
+ var isFiniteNumber2 = (n) => typeof n === "number" && Number.isFinite(n);
393
+ var safeInt = (value, fallback = 0, min = -Infinity, max = Infinity) => {
394
+ const isRealNumeric = typeof value === "number" || typeof value === "string" && value.trim().length > 0 && Number.isFinite(Number(value));
395
+ if (!isRealNumeric) {
396
+ return Math.max(min, Math.min(max, Math.floor(fallback)));
397
+ }
398
+ const n = Number(value);
399
+ if (!Number.isFinite(n)) return Math.max(min, Math.min(max, Math.floor(fallback)));
400
+ return Math.max(min, Math.min(max, Math.floor(n)));
401
+ };
392
402
  var clamp = (n, min, max) => Math.min(Math.max(n, min), max);
393
403
  var lerp = (a, b, t) => a + (b - a) * t;
394
404
  var clampByte2 = (v) => clamp(Math.round(v), 0, 255);
@@ -404,25 +414,148 @@ var hexToRgb = (hex) => {
404
414
  return { r: int >> 16 & 255, g: int >> 8 & 255, b: int & 255 };
405
415
  };
406
416
  var rgbToHex = (r, g, b) => "#" + [clampByte2(r), clampByte2(g), clampByte2(b)].map((v) => v.toString(16).padStart(2, "0")).join("");
407
- var lerpColor = (a, b, t) => {
417
+ var rgbToHsl = (rgb) => {
418
+ const r = clamp(rgb.r, 0, 255) / 255;
419
+ const g = clamp(rgb.g, 0, 255) / 255;
420
+ const b = clamp(rgb.b, 0, 255) / 255;
421
+ const max = Math.max(r, g, b);
422
+ const min = Math.min(r, g, b);
423
+ const l = (max + min) / 2;
424
+ if (max === min) {
425
+ return { h: 0, s: 0, l };
426
+ }
427
+ const d = max - min;
428
+ const s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
429
+ let h;
430
+ if (max === r) {
431
+ h = ((g - b) / d + (g < b ? 6 : 0)) * 60;
432
+ } else if (max === g) {
433
+ h = ((b - r) / d + 2) * 60;
434
+ } else {
435
+ h = ((r - g) / d + 4) * 60;
436
+ }
437
+ return { h, s, l };
438
+ };
439
+ var hslToRgb = (hsl) => {
440
+ const h = (hsl.h % 360 + 360) % 360 / 360;
441
+ const s = clamp(hsl.s, 0, 1);
442
+ const l = clamp(hsl.l, 0, 1);
443
+ if (s === 0) {
444
+ const v = Math.round(l * 255);
445
+ return { r: v, g: v, b: v };
446
+ }
447
+ const hue2rgb = (p2, q2, t) => {
448
+ let tt = t;
449
+ if (tt < 0) tt += 1;
450
+ if (tt > 1) tt -= 1;
451
+ if (tt < 1 / 6) return p2 + (q2 - p2) * 6 * tt;
452
+ if (tt < 1 / 2) return q2;
453
+ if (tt < 2 / 3) return p2 + (q2 - p2) * (2 / 3 - tt) * 6;
454
+ return p2;
455
+ };
456
+ const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
457
+ const p = 2 * l - q;
458
+ return {
459
+ r: Math.round(hue2rgb(p, q, h + 1 / 3) * 255),
460
+ g: Math.round(hue2rgb(p, q, h) * 255),
461
+ b: Math.round(hue2rgb(p, q, h - 1 / 3) * 255)
462
+ };
463
+ };
464
+ var _srgbToLinear = (c) => {
465
+ const x = c / 255;
466
+ return x <= 0.04045 ? x / 12.92 : Math.pow((x + 0.055) / 1.055, 2.4);
467
+ };
468
+ var _linearToSrgb = (c) => {
469
+ const x = c <= 31308e-7 ? 12.92 * c : 1.055 * Math.pow(c, 1 / 2.4) - 0.055;
470
+ return clampByte2(x * 255);
471
+ };
472
+ var rgbToOklab = (rgb) => {
473
+ const r = _srgbToLinear(rgb.r);
474
+ const g = _srgbToLinear(rgb.g);
475
+ const b = _srgbToLinear(rgb.b);
476
+ const l = 0.4122214708 * r + 0.5363325363 * g + 0.0514459929 * b;
477
+ const m = 0.2119034982 * r + 0.6806995451 * g + 0.1073969566 * b;
478
+ const s = 0.0883024619 * r + 0.2817188376 * g + 0.6299787005 * b;
479
+ const l_ = Math.cbrt(l);
480
+ const m_ = Math.cbrt(m);
481
+ const s_ = Math.cbrt(s);
482
+ return {
483
+ L: 0.2104542553 * l_ + 0.793617785 * m_ - 0.0040720468 * s_,
484
+ a: 1.9779984951 * l_ - 2.428592205 * m_ + 0.4505937099 * s_,
485
+ b: 0.0259040371 * l_ + 0.7827717662 * m_ - 0.808675766 * s_
486
+ };
487
+ };
488
+ var oklabToRgb = (oklab) => {
489
+ const l_ = oklab.L + 0.3963377774 * oklab.a + 0.2158037573 * oklab.b;
490
+ const m_ = oklab.L - 0.1055613458 * oklab.a - 0.0638541728 * oklab.b;
491
+ const s_ = oklab.L - 0.0894841775 * oklab.a - 1.291485548 * oklab.b;
492
+ const l = l_ * l_ * l_;
493
+ const m = m_ * m_ * m_;
494
+ const s = s_ * s_ * s_;
495
+ const r = 4.0767416621 * l - 3.3077115913 * m + 0.2309699292 * s;
496
+ const g = -1.2684380046 * l + 2.6097574011 * m - 0.3413193965 * s;
497
+ const b = -0.0041960863 * l - 0.7034186147 * m + 1.707614701 * s;
498
+ return {
499
+ r: _linearToSrgb(r),
500
+ g: _linearToSrgb(g),
501
+ b: _linearToSrgb(b)
502
+ };
503
+ };
504
+ var lerpColor = (a, b, t, space = "rgb") => {
408
505
  const ct = clamp(t, 0, 1);
506
+ if (space === "oklab") {
507
+ const la = rgbToOklab(a);
508
+ const lb = rgbToOklab(b);
509
+ return oklabToRgb({
510
+ L: lerp(la.L, lb.L, ct),
511
+ a: lerp(la.a, lb.a, ct),
512
+ b: lerp(la.b, lb.b, ct)
513
+ });
514
+ }
515
+ if (space === "hsl") {
516
+ const ha = rgbToHsl(a);
517
+ const hb = rgbToHsl(b);
518
+ let dh = hb.h - ha.h;
519
+ if (dh > 180) dh -= 360;
520
+ else if (dh < -180) dh += 360;
521
+ const h = ha.h + dh * ct;
522
+ return hslToRgb({
523
+ h,
524
+ s: lerp(ha.s, hb.s, ct),
525
+ l: lerp(ha.l, hb.l, ct)
526
+ });
527
+ }
409
528
  return {
410
529
  r: Math.round(lerp(a.r, b.r, ct)),
411
530
  g: Math.round(lerp(a.g, b.g, ct)),
412
531
  b: Math.round(lerp(a.b, b.b, ct))
413
532
  };
414
533
  };
415
- var gradientColor = (colors, t) => {
534
+ var mixColors = (a, b, t, space = "rgb") => {
535
+ const ra = typeof a === "string" ? hexToRgb(a) : a;
536
+ const rb = typeof b === "string" ? hexToRgb(b) : b;
537
+ return lerpColor(ra, rb, t, space);
538
+ };
539
+ var quantizeColor = (color2, levels = 4) => {
540
+ const safeLevels = Math.max(2, Math.floor(levels));
541
+ const step = 255 / (safeLevels - 1);
542
+ return {
543
+ r: Math.round(clampByte2(color2.r) / step) * step | 0,
544
+ g: Math.round(clampByte2(color2.g) / step) * step | 0,
545
+ b: Math.round(clampByte2(color2.b) / step) * step | 0
546
+ };
547
+ };
548
+ var gradientColor = (colors, t, space = "rgb") => {
416
549
  if (!Array.isArray(colors) || colors.length === 0) {
417
550
  throw new Error("gradientColor requires at least one color stop");
418
551
  }
419
552
  if (colors.length === 1) return colors[0];
420
- const safeT = typeof t === "number" && Number.isFinite(t) ? t : 0;
553
+ const safeT = isFiniteNumber2(t) ? t : 0;
421
554
  const ct = clamp(safeT, 0, 1);
422
555
  const scaled = ct * (colors.length - 1);
423
556
  const lo = Math.floor(scaled);
424
557
  const hi = Math.min(lo + 1, colors.length - 1);
425
- return lerpColor(colors[lo], colors[hi], scaled - lo);
558
+ return lerpColor(colors[lo], colors[hi], scaled - lo, space);
426
559
  };
427
560
  var rgbTo256 = (r, g, b) => {
428
561
  const cr = clampByte2(r), cg = clampByte2(g), cb = clampByte2(b);
@@ -809,7 +942,7 @@ var padBoth = (str, width, ch = " ") => {
809
942
  const r = pad - l;
810
943
  return ch.repeat(l) + str + ch.repeat(r);
811
944
  };
812
- var gradientStops = (start, end, count) => {
945
+ var gradientStops = (start, end, count, space = "rgb") => {
813
946
  const safeCount = Math.max(2, Math.floor(Number.isFinite(count) ? count : 2));
814
947
  if (!isHexColor(start) || !isHexColor(end)) return [];
815
948
  const a = hexToRgb(start);
@@ -817,7 +950,7 @@ var gradientStops = (start, end, count) => {
817
950
  const result = [];
818
951
  for (let i = 0; i < safeCount; i++) {
819
952
  const t = i / (safeCount - 1);
820
- const c = lerpColor(a, b, t);
953
+ const c = lerpColor(a, b, t, space);
821
954
  result.push(rgbToHex(c.r, c.g, c.b));
822
955
  }
823
956
  return result;
@@ -1701,8 +1834,8 @@ var pulse = async (text, opts = {}) => {
1701
1834
  fireDone(hooks, isAborted(signal));
1702
1835
  return;
1703
1836
  }
1704
- const c1 = resolveRgb(color1);
1705
- const c2 = resolveRgb(color2);
1837
+ const c12 = resolveRgb(color1);
1838
+ const c22 = resolveRgb(color2);
1706
1839
  const cycles = Math.max(1, Math.round(times));
1707
1840
  const halfInterval = Math.max(FRAME_MS, interval);
1708
1841
  registerCrashHandlers();
@@ -1716,7 +1849,7 @@ var pulse = async (text, opts = {}) => {
1716
1849
  break;
1717
1850
  }
1718
1851
  await safeWriteAsync(
1719
- cursor.save() + fgRgb(c1.r, c1.g, c1.b) + text + reset() + cursor.restore()
1852
+ cursor.save() + fgRgb(c12.r, c12.g, c12.b) + text + reset() + cursor.restore()
1720
1853
  );
1721
1854
  fireFrame(hooks, frame2++);
1722
1855
  await sleep(halfInterval, { signal });
@@ -1725,14 +1858,14 @@ var pulse = async (text, opts = {}) => {
1725
1858
  break;
1726
1859
  }
1727
1860
  await safeWriteAsync(
1728
- cursor.save() + fgRgb(c2.r, c2.g, c2.b) + text + reset() + cursor.restore()
1861
+ cursor.save() + fgRgb(c22.r, c22.g, c22.b) + text + reset() + cursor.restore()
1729
1862
  );
1730
1863
  fireFrame(hooks, frame2++);
1731
1864
  await sleep(halfInterval, { signal });
1732
1865
  }
1733
1866
  if (!aborted) {
1734
1867
  await safeWriteAsync(
1735
- cursor.save() + fgRgb(c1.r, c1.g, c1.b) + text + reset() + cursor.restore()
1868
+ cursor.save() + fgRgb(c12.r, c12.g, c12.b) + text + reset() + cursor.restore()
1736
1869
  );
1737
1870
  }
1738
1871
  } finally {
@@ -2903,14 +3036,14 @@ var ascii = {
2903
3036
 
2904
3037
  // src/loaders/index.ts
2905
3038
  var canAnimate2 = () => Boolean(process.stdout?.isTTY) && supportsColor() !== "none";
2906
- var isFiniteNumber2 = (n) => typeof n === "number" && Number.isFinite(n);
3039
+ var isFiniteNumber3 = (n) => typeof n === "number" && Number.isFinite(n);
2907
3040
  var ensureString3 = (v) => typeof v === "string" ? v : String(v ?? "");
2908
3041
  var clampPositiveInt = (n, fallback) => {
2909
- if (!isFiniteNumber2(n)) return fallback;
3042
+ if (!isFiniteNumber3(n)) return fallback;
2910
3043
  return Math.max(1, Math.floor(n));
2911
3044
  };
2912
3045
  var clampPercent = (p) => {
2913
- if (!isFiniteNumber2(p)) return 0;
3046
+ if (!isFiniteNumber3(p)) return 0;
2914
3047
  return Math.max(0, Math.min(100, p));
2915
3048
  };
2916
3049
  var isUnicodeCapable = () => {
@@ -3302,7 +3435,7 @@ var custom = (frames2, text = "", opts = {}) => {
3302
3435
  };
3303
3436
  var countdown = async (seconds, opts = {}) => {
3304
3437
  const { label = "Starting in", color: hex, signal } = opts;
3305
- const safeSeconds = isFiniteNumber2(seconds) ? Math.max(0, Math.floor(seconds)) : 0;
3438
+ const safeSeconds = isFiniteNumber3(seconds) ? Math.max(0, Math.floor(seconds)) : 0;
3306
3439
  const safeLabel = ensureString3(label);
3307
3440
  const colorToUse = safeColor(hex) ? hex : "#ffd700";
3308
3441
  if (!canAnimate2() || signal?.aborted) {
@@ -3509,11 +3642,11 @@ var loader = {
3509
3642
  };
3510
3643
 
3511
3644
  // src/frames/index.ts
3512
- var isFiniteNumber3 = (n) => typeof n === "number" && Number.isFinite(n);
3645
+ var isFiniteNumber4 = (n) => typeof n === "number" && Number.isFinite(n);
3513
3646
  var ensureString4 = (v) => typeof v === "string" ? v : String(v ?? "");
3514
3647
  var MAX_FPS = 60;
3515
3648
  var clampFps = (fps, fallback) => {
3516
- if (!isFiniteNumber3(fps)) return fallback;
3649
+ if (!isFiniteNumber4(fps)) return fallback;
3517
3650
  return Math.max(1, Math.min(MAX_FPS, Math.floor(fps)));
3518
3651
  };
3519
3652
  var _cursorHiddenCount2 = 0;
@@ -3612,14 +3745,14 @@ var play = (frames2, opts = {}) => {
3612
3745
  if (fps !== void 0) {
3613
3746
  const safeFps = clampFps(fps, 60);
3614
3747
  tickMs = Math.max(FRAME_MS, Math.floor(1e3 / safeFps));
3615
- } else if (isFiniteNumber3(interval)) {
3748
+ } else if (isFiniteNumber4(interval)) {
3616
3749
  tickMs = Math.max(FRAME_MS, Math.floor(interval));
3617
3750
  } else {
3618
3751
  tickMs = 100;
3619
3752
  }
3620
3753
  let safeRepeat;
3621
3754
  let infinite;
3622
- if (!isFiniteNumber3(repeat)) {
3755
+ if (!isFiniteNumber4(repeat)) {
3623
3756
  safeRepeat = 1;
3624
3757
  infinite = false;
3625
3758
  } else if (repeat === 0) {
@@ -3744,7 +3877,7 @@ var play = (frames2, opts = {}) => {
3744
3877
  paused = false;
3745
3878
  },
3746
3879
  seek: (idx) => {
3747
- if (!isFiniteNumber3(idx)) return;
3880
+ if (!isFiniteNumber4(idx)) return;
3748
3881
  const safe = Math.max(0, Math.floor(idx));
3749
3882
  frameIdx = frames2.length > 0 ? safe % frames2.length : 0;
3750
3883
  },
@@ -3757,7 +3890,7 @@ var play = (frames2, opts = {}) => {
3757
3890
  };
3758
3891
  };
3759
3892
  var generate = (count, fn) => {
3760
- const safeCount = isFiniteNumber3(count) ? Math.max(0, Math.floor(count)) : 0;
3893
+ const safeCount = isFiniteNumber4(count) ? Math.max(0, Math.floor(count)) : 0;
3761
3894
  if (typeof fn !== "function") return Array(safeCount).fill("");
3762
3895
  return Array.from({ length: safeCount }, (_, i) => {
3763
3896
  try {
@@ -3829,7 +3962,7 @@ var morph = (frameA, frameB, steps = 8, charset = "\u2591\u2592\u2593\u2588\u259
3829
3962
  const a0 = ensureString4(frameA);
3830
3963
  const b0 = ensureString4(frameB);
3831
3964
  if (!a0 && !b0) return [""];
3832
- const n = Math.max(2, isFiniteNumber3(steps) ? Math.floor(steps) : 8);
3965
+ const n = Math.max(2, isFiniteNumber4(steps) ? Math.floor(steps) : 8);
3833
3966
  const len = Math.max(a0.length, b0.length);
3834
3967
  const a = a0.padEnd(len);
3835
3968
  const b = b0.padEnd(len);
@@ -3851,7 +3984,7 @@ var morph = (frameA, frameB, steps = 8, charset = "\u2591\u2592\u2593\u2588\u259
3851
3984
  var presets2 = {
3852
3985
  loadingBar: (opts = {}) => {
3853
3986
  const { width = 20, char = "\u2588", empty = "\u2591", label = "Loading" } = opts;
3854
- const safeWidth = Math.max(0, isFiniteNumber3(width) ? Math.floor(width) : 20);
3987
+ const safeWidth = Math.max(0, isFiniteNumber4(width) ? Math.floor(width) : 20);
3855
3988
  const safeChar = typeof char === "string" && char.length > 0 ? char : "\u2588";
3856
3989
  const safeEmpty = typeof empty === "string" && empty.length > 0 ? empty : "\u2591";
3857
3990
  const safeLabel = ensureString4(label);
@@ -3865,7 +3998,7 @@ var presets2 = {
3865
3998
  /* istanbul ignore next — default opts {} */
3866
3999
  ball: (opts = {}) => {
3867
4000
  const { width = 20, char = "\u25CF" } = opts;
3868
- const safeWidth = Math.max(1, isFiniteNumber3(width) ? Math.floor(width) : 20);
4001
+ const safeWidth = Math.max(1, isFiniteNumber4(width) ? Math.floor(width) : 20);
3869
4002
  const safeChar = typeof char === "string" && char.length > 0 ? char : "\u25CF";
3870
4003
  const forward = generate(safeWidth, (i) => " ".repeat(i) + safeChar);
3871
4004
  const backward = generate(safeWidth, (i) => " ".repeat(safeWidth - i - 1) + safeChar);
@@ -3875,7 +4008,7 @@ var presets2 = {
3875
4008
  breathe: (text, opts = {}) => {
3876
4009
  const { steps = 8 } = opts;
3877
4010
  const safeText = ensureString4(text);
3878
- const safeSteps2 = Math.max(1, isFiniteNumber3(steps) ? Math.floor(steps) : 8);
4011
+ const safeSteps2 = Math.max(1, isFiniteNumber4(steps) ? Math.floor(steps) : 8);
3879
4012
  const shades = ["\u2591", "\u2592", "\u2593", "\u2588"];
3880
4013
  return generate(safeSteps2 * 2, (i) => {
3881
4014
  const t = i < safeSteps2 ? i / safeSteps2 : 1 - (i - safeSteps2) / safeSteps2;
@@ -3896,22 +4029,22 @@ var presets2 = {
3896
4029
  var frames = { play, generate, live, morph, presets: presets2 };
3897
4030
 
3898
4031
  // src/components/index.ts
3899
- var isFiniteNumber4 = (n) => typeof n === "number" && Number.isFinite(n);
4032
+ var isFiniteNumber5 = (n) => typeof n === "number" && Number.isFinite(n);
3900
4033
  var ensureString5 = (v) => typeof v === "string" ? v : String(v ?? "");
3901
4034
  var clampPercent2 = (p) => {
3902
- if (!isFiniteNumber4(p)) return 0;
4035
+ if (!isFiniteNumber5(p)) return 0;
3903
4036
  return Math.max(0, Math.min(100, p));
3904
4037
  };
3905
4038
  var clampNonNeg = (n, fallback) => {
3906
- if (!isFiniteNumber4(n)) return fallback;
4039
+ if (!isFiniteNumber5(n)) return fallback;
3907
4040
  return Math.max(0, Math.floor(n));
3908
4041
  };
3909
4042
  var clampPositive2 = (n, fallback) => {
3910
- if (!isFiniteNumber4(n)) return fallback;
4043
+ if (!isFiniteNumber5(n)) return fallback;
3911
4044
  return Math.max(1, Math.floor(n));
3912
4045
  };
3913
4046
  var safeSgrCode = (code, fallback) => {
3914
- if (!isFiniteNumber4(code)) return fallback;
4047
+ if (!isFiniteNumber5(code)) return fallback;
3915
4048
  return Math.max(0, Math.min(255, Math.floor(code)));
3916
4049
  };
3917
4050
  var truncateVisible = (str, maxWidth, ellipsis = "\u2026") => {
@@ -3949,7 +4082,7 @@ var table = (rows, opts = {}) => {
3949
4082
  const b = TABLE_BORDERS[borderStyle] ?? TABLE_BORDERS.rounded;
3950
4083
  const safePadding = clampNonNeg(padding, 1);
3951
4084
  const pad = " ".repeat(safePadding);
3952
- const safeMaxCol = maxColWidth !== null && isFiniteNumber4(maxColWidth) ? Math.max(1, Math.floor(maxColWidth)) : null;
4085
+ const safeMaxCol = maxColWidth !== null && isFiniteNumber5(maxColWidth) ? Math.max(1, Math.floor(maxColWidth)) : null;
3953
4086
  const validRows = rows.filter((r) => Array.isArray(r));
3954
4087
  if (validRows.length === 0) return "";
3955
4088
  const cols = Math.max(...validRows.map((r) => r.length), 0);
@@ -4042,7 +4175,7 @@ var progressBar = (percent, opts = {}) => {
4042
4175
  let filledStr = safeChar.repeat(filled);
4043
4176
  if (Array.isArray(gradientStops2) && gradientStops2.length >= 1 && filled > 0) {
4044
4177
  filledStr = gradient(filledStr, gradientStops2);
4045
- } else if (color2 !== null && isFiniteNumber4(color2)) {
4178
+ } else if (color2 !== null && isFiniteNumber5(color2)) {
4046
4179
  filledStr = sgr(safeSgrCode(color2, FG.white)) + filledStr + reset();
4047
4180
  }
4048
4181
  const emptyStr = safeEmpty.repeat(empty);
@@ -4078,7 +4211,7 @@ var section = (title, opts = {}) => {
4078
4211
  const safeChar = typeof char === "string" && char.length > 0 ? char : "\u2500";
4079
4212
  const safeColor2 = safeSgrCode(colorCode, FG.cyan);
4080
4213
  const titleLen = visibleLen(safeTitle);
4081
- const requestedWidth = width !== null && isFiniteNumber4(width) ? Math.max(1, Math.floor(width)) : cols;
4214
+ const requestedWidth = width !== null && isFiniteNumber5(width) ? Math.max(1, Math.floor(width)) : cols;
4082
4215
  const w = Math.max(requestedWidth, titleLen + 2);
4083
4216
  const side = Math.floor((w - titleLen - 2) / 2);
4084
4217
  const dividerL = sgr(safeColor2) + safeChar.repeat(Math.max(0, side)) + reset();
@@ -4092,7 +4225,7 @@ var columns = (items, opts = {}) => {
4092
4225
  const safeCols = clampPositive2(numCols, 2);
4093
4226
  const safeGap = clampNonNeg(gap, 2);
4094
4227
  const { cols: termCols } = termSize();
4095
- const totalW = width !== null && isFiniteNumber4(width) ? Math.max(safeCols, Math.floor(width)) : termCols;
4228
+ const totalW = width !== null && isFiniteNumber5(width) ? Math.max(safeCols, Math.floor(width)) : termCols;
4096
4229
  const colW = Math.max(1, Math.floor((totalW - safeGap * (safeCols - 1)) / safeCols));
4097
4230
  const gapStr = " ".repeat(safeGap);
4098
4231
  const rows = [];
@@ -4132,7 +4265,7 @@ var timeline = (events, opts = {}) => {
4132
4265
  const safeColor2 = safeSgrCode(colorCode, FG.cyan);
4133
4266
  const safeDoneColor = safeSgrCode(doneColor, FG.green);
4134
4267
  const safePendingColor = safeSgrCode(pendingColor, FG.brightBlack);
4135
- const computedTimeWidth = timeColumnWidth !== null && isFiniteNumber4(timeColumnWidth) ? Math.max(0, Math.floor(timeColumnWidth)) : Math.max(0, ...events.map((e) => e.time ? visibleLen(ensureString5(e.time)) : 0));
4268
+ const computedTimeWidth = timeColumnWidth !== null && isFiniteNumber5(timeColumnWidth) ? Math.max(0, Math.floor(timeColumnWidth)) : Math.max(0, ...events.map((e) => e.time ? visibleLen(ensureString5(e.time)) : 0));
4136
4269
  const lines = [];
4137
4270
  events.forEach((ev, i) => {
4138
4271
  const isLast = i === events.length - 1;
@@ -4324,10 +4457,10 @@ var STYLES = {
4324
4457
  heavy: { branch: "\u2523\u2501\u2501 ", last: "\u2517\u2501\u2501 ", vert: "\u2503 ", space: " " },
4325
4458
  ascii: { branch: "+-- ", last: "`-- ", vert: "| ", space: " " }
4326
4459
  };
4327
- var isFiniteNumber5 = (n) => typeof n === "number" && Number.isFinite(n);
4460
+ var isFiniteNumber6 = (n) => typeof n === "number" && Number.isFinite(n);
4328
4461
  var ensureString6 = (v) => typeof v === "string" ? v : String(v ?? "");
4329
4462
  var clampNonNeg2 = (n, fallback) => {
4330
- if (!isFiniteNumber5(n)) return fallback;
4463
+ if (!isFiniteNumber6(n)) return fallback;
4331
4464
  return Math.max(0, Math.floor(n));
4332
4465
  };
4333
4466
  var normalizeNewlines = (s) => s.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
@@ -4399,7 +4532,7 @@ var renderChildren = (children, parentContinuation, lines, indentStr, defaultSty
4399
4532
  if (!Array.isArray(children)) return;
4400
4533
  let visible = children;
4401
4534
  let collapsedCount = 0;
4402
- const safeCollapse = isFiniteNumber5(collapse) ? Math.floor(collapse) : 0;
4535
+ const safeCollapse = isFiniteNumber6(collapse) ? Math.floor(collapse) : 0;
4403
4536
  if (safeCollapse > 0 && safeCollapse < children.length) {
4404
4537
  visible = children.slice(safeCollapse);
4405
4538
  collapsedCount = safeCollapse;
@@ -4469,7 +4602,7 @@ var renderTree = (root, opts = {}) => {
4469
4602
  } = opts;
4470
4603
  const safeStyle = style && STYLES[style] ? style : "normal";
4471
4604
  const safeIndent = clampNonNeg2(indent, 0);
4472
- const safeMaxDepth = isFiniteNumber5(maxDepth) ? Math.max(0, Math.floor(maxDepth)) : Infinity;
4605
+ const safeMaxDepth = isFiniteNumber6(maxDepth) ? Math.max(0, Math.floor(maxDepth)) : Infinity;
4473
4606
  const indentStr = " ".repeat(safeIndent);
4474
4607
  const lines = [];
4475
4608
  const rootLabel = formatNode(root, 0, palette);
@@ -5088,13 +5221,13 @@ var themes = {
5088
5221
  var FULL_BLOCK = "\u2588";
5089
5222
  var UPPER_HALF = "\u2580";
5090
5223
  var LOWER_HALF = "\u2584";
5091
- var isFiniteNumber6 = (n) => typeof n === "number" && Number.isFinite(n);
5224
+ var isFiniteNumber7 = (n) => typeof n === "number" && Number.isFinite(n);
5092
5225
  var clampInt = (n, min, max, fallback) => {
5093
- if (!isFiniteNumber6(n)) return fallback;
5226
+ if (!isFiniteNumber7(n)) return fallback;
5094
5227
  return Math.max(min, Math.min(max, Math.floor(n)));
5095
5228
  };
5096
5229
  var clampByte3 = (n) => {
5097
- if (!isFiniteNumber6(n)) return 0;
5230
+ if (!isFiniteNumber7(n)) return 0;
5098
5231
  return Math.max(0, Math.min(255, Math.round(n)));
5099
5232
  };
5100
5233
  var MAX_DIMENSION = 1e4;
@@ -5399,7 +5532,7 @@ var gradientRect = (opts = {}) => {
5399
5532
  const safeW = clampInt(width, 2, MAX_DIMENSION, 40);
5400
5533
  const safeH = clampInt(height, 2, MAX_DIMENSION, 10);
5401
5534
  let cosA = 1, sinA = 0;
5402
- if (isFiniteNumber6(angle)) {
5535
+ if (isFiniteNumber7(angle)) {
5403
5536
  const rad = angle * Math.PI / 180;
5404
5537
  cosA = Math.cos(rad);
5405
5538
  sinA = Math.sin(rad);
@@ -5409,7 +5542,7 @@ var gradientRect = (opts = {}) => {
5409
5542
  const line = [];
5410
5543
  for (let col = 0; col < safeW; col++) {
5411
5544
  let t;
5412
- if (isFiniteNumber6(angle)) {
5545
+ if (isFiniteNumber7(angle)) {
5413
5546
  const projection = col / (safeW - 1) * cosA + row / (safeH - 1) * sinA;
5414
5547
  t = clamp((projection + 1) / 2, 0, 1);
5415
5548
  } else if (style === "horizontal") t = col / (safeW - 1);
@@ -5466,7 +5599,7 @@ var createCanvas = (width, height, fillColor = null) => {
5466
5599
  if (y > dirtyMaxY) dirtyMaxY = y;
5467
5600
  };
5468
5601
  const setInternal = (x, y, color2) => {
5469
- if (!isFiniteNumber6(x) || !isFiniteNumber6(y)) return;
5602
+ if (!isFiniteNumber7(x) || !isFiniteNumber7(y)) return;
5470
5603
  const ix = Math.floor(x);
5471
5604
  const iy = Math.floor(y);
5472
5605
  if (iy < 0 || iy >= h || ix < 0 || ix >= w) return;
@@ -5481,7 +5614,7 @@ var createCanvas = (width, height, fillColor = null) => {
5481
5614
  },
5482
5615
  set: setInternal,
5483
5616
  get(x, y) {
5484
- if (!isFiniteNumber6(x) || !isFiniteNumber6(y)) return null;
5617
+ if (!isFiniteNumber7(x) || !isFiniteNumber7(y)) return null;
5485
5618
  const ix = Math.floor(x), iy = Math.floor(y);
5486
5619
  return cloneColor(pixels[iy]?.[ix] ?? null);
5487
5620
  },
@@ -5497,7 +5630,7 @@ var createCanvas = (width, height, fillColor = null) => {
5497
5630
  dirtyMaxY = h - 1;
5498
5631
  },
5499
5632
  drawRect(x, y, rw, rh, color2, fill = false) {
5500
- if (!isFiniteNumber6(x) || !isFiniteNumber6(y) || !isFiniteNumber6(rw) || !isFiniteNumber6(rh)) return;
5633
+ if (!isFiniteNumber7(x) || !isFiniteNumber7(y) || !isFiniteNumber7(rw) || !isFiniteNumber7(rh)) return;
5501
5634
  if (rw <= 0 || rh <= 0) return;
5502
5635
  const ix = Math.floor(x);
5503
5636
  const iy = Math.floor(y);
@@ -5519,7 +5652,7 @@ var createCanvas = (width, height, fillColor = null) => {
5519
5652
  }
5520
5653
  },
5521
5654
  drawCircle(cx, cy, radius, color2, fill = false) {
5522
- if (!isFiniteNumber6(cx) || !isFiniteNumber6(cy) || !isFiniteNumber6(radius)) return;
5655
+ if (!isFiniteNumber7(cx) || !isFiniteNumber7(cy) || !isFiniteNumber7(radius)) return;
5523
5656
  if (radius <= 0) return;
5524
5657
  const x0 = Math.max(0, Math.floor(cx - radius - 1));
5525
5658
  const y0 = Math.max(0, Math.floor(cy - radius - 1));
@@ -5542,7 +5675,7 @@ var createCanvas = (width, height, fillColor = null) => {
5542
5675
  }
5543
5676
  },
5544
5677
  drawSprite(x, y, sprite) {
5545
- if (!isFiniteNumber6(x) || !isFiniteNumber6(y)) return;
5678
+ if (!isFiniteNumber7(x) || !isFiniteNumber7(y)) return;
5546
5679
  if (!Array.isArray(sprite)) return;
5547
5680
  const sx = Math.floor(x);
5548
5681
  const sy = Math.floor(y);
@@ -6304,6 +6437,95 @@ var setConfigValue = (key, value) => {
6304
6437
  };
6305
6438
  var subscribeConfig = onConfigChange;
6306
6439
 
6440
+ // src/utils/easing.ts
6441
+ var c1 = 1.70158;
6442
+ var c2 = c1 * 1.525;
6443
+ var c3 = c1 + 1;
6444
+ var c4 = 2 * Math.PI / 3;
6445
+ var c5 = 2 * Math.PI / 4.5;
6446
+ var _bounceOut = (t) => {
6447
+ const n1 = 7.5625;
6448
+ const d1 = 2.75;
6449
+ if (t < 1 / d1) return n1 * t * t;
6450
+ if (t < 2 / d1) {
6451
+ const x2 = t - 1.5 / d1;
6452
+ return n1 * x2 * x2 + 0.75;
6453
+ }
6454
+ if (t < 2.5 / d1) {
6455
+ const x2 = t - 2.25 / d1;
6456
+ return n1 * x2 * x2 + 0.9375;
6457
+ }
6458
+ const x = t - 2.625 / d1;
6459
+ return n1 * x * x + 0.984375;
6460
+ };
6461
+ var easings = {
6462
+ // ── Linear ──
6463
+ linear: (t) => t,
6464
+ // ── Quadratic (t²) ──
6465
+ easeInQuad: (t) => t * t,
6466
+ easeOutQuad: (t) => 1 - (1 - t) * (1 - t),
6467
+ easeInOutQuad: (t) => t < 0.5 ? 2 * t * t : 1 - Math.pow(-2 * t + 2, 2) / 2,
6468
+ // ── Cubic (t³) ──
6469
+ easeInCubic: (t) => t * t * t,
6470
+ easeOutCubic: (t) => 1 - Math.pow(1 - t, 3),
6471
+ easeInOutCubic: (t) => t < 0.5 ? 4 * t * t * t : 1 - Math.pow(-2 * t + 2, 3) / 2,
6472
+ // ── Quartic (t⁴) ──
6473
+ easeInQuart: (t) => t * t * t * t,
6474
+ easeOutQuart: (t) => 1 - Math.pow(1 - t, 4),
6475
+ easeInOutQuart: (t) => t < 0.5 ? 8 * t * t * t * t : 1 - Math.pow(-2 * t + 2, 4) / 2,
6476
+ // ── Quintic (t⁵) ──
6477
+ easeInQuint: (t) => t * t * t * t * t,
6478
+ easeOutQuint: (t) => 1 - Math.pow(1 - t, 5),
6479
+ easeInOutQuint: (t) => t < 0.5 ? 16 * t * t * t * t * t : 1 - Math.pow(-2 * t + 2, 5) / 2,
6480
+ // ── Sinusoidal ──
6481
+ easeInSine: (t) => 1 - Math.cos(t * Math.PI / 2),
6482
+ easeOutSine: (t) => Math.sin(t * Math.PI / 2),
6483
+ easeInOutSine: (t) => -(Math.cos(Math.PI * t) - 1) / 2,
6484
+ // ── Exponential ──
6485
+ easeInExpo: (t) => t === 0 ? 0 : Math.pow(2, 10 * t - 10),
6486
+ easeOutExpo: (t) => t === 1 ? 1 : 1 - Math.pow(2, -10 * t),
6487
+ easeInOutExpo: (t) => {
6488
+ if (t === 0) return 0;
6489
+ if (t === 1) return 1;
6490
+ return t < 0.5 ? Math.pow(2, 20 * t - 10) / 2 : (2 - Math.pow(2, -20 * t + 10)) / 2;
6491
+ },
6492
+ // ── Circular ──
6493
+ easeInCirc: (t) => 1 - Math.sqrt(1 - Math.pow(t, 2)),
6494
+ easeOutCirc: (t) => Math.sqrt(1 - Math.pow(t - 1, 2)),
6495
+ easeInOutCirc: (t) => t < 0.5 ? (1 - Math.sqrt(1 - Math.pow(2 * t, 2))) / 2 : (Math.sqrt(1 - Math.pow(-2 * t + 2, 2)) + 1) / 2,
6496
+ // ── Back (overshoots) ──
6497
+ easeInBack: (t) => c3 * t * t * t - c1 * t * t,
6498
+ easeOutBack: (t) => 1 + c3 * Math.pow(t - 1, 3) + c1 * Math.pow(t - 1, 2),
6499
+ easeInOutBack: (t) => t < 0.5 ? Math.pow(2 * t, 2) * ((c2 + 1) * 2 * t - c2) / 2 : (Math.pow(2 * t - 2, 2) * ((c2 + 1) * (t * 2 - 2) + c2) + 2) / 2,
6500
+ // ── Elastic (oscillates) ──
6501
+ easeInElastic: (t) => {
6502
+ if (t === 0) return 0;
6503
+ if (t === 1) return 1;
6504
+ return -Math.pow(2, 10 * t - 10) * Math.sin((t * 10 - 10.75) * c4);
6505
+ },
6506
+ easeOutElastic: (t) => {
6507
+ if (t === 0) return 0;
6508
+ if (t === 1) return 1;
6509
+ return Math.pow(2, -10 * t) * Math.sin((t * 10 - 0.75) * c4) + 1;
6510
+ },
6511
+ easeInOutElastic: (t) => {
6512
+ if (t === 0) return 0;
6513
+ if (t === 1) return 1;
6514
+ return t < 0.5 ? -(Math.pow(2, 20 * t - 10) * Math.sin((20 * t - 11.125) * c5)) / 2 : Math.pow(2, -20 * t + 10) * Math.sin((20 * t - 11.125) * c5) / 2 + 1;
6515
+ },
6516
+ // ── Bounce (bouncing ball) ──
6517
+ easeInBounce: (t) => 1 - _bounceOut(1 - t),
6518
+ easeOutBounce: _bounceOut,
6519
+ easeInOutBounce: (t) => t < 0.5 ? (1 - _bounceOut(1 - 2 * t)) / 2 : (1 + _bounceOut(2 * t - 1)) / 2
6520
+ };
6521
+ var resolveEasingByName = (e) => {
6522
+ if (typeof e === "function") return e;
6523
+ if (typeof e === "string" && easings[e]) {
6524
+ return easings[e];
6525
+ }
6526
+ return easings.linear;
6527
+ };
6528
+
6307
6529
  // src/index.ts
6308
6530
  var ansimax = { color, animate, ascii, loader, frames, components, trees, themes, images, configure };
6309
6531
  var index_default = ansimax;
@@ -6338,6 +6560,7 @@ export {
6338
6560
  chain,
6339
6561
  charWidth,
6340
6562
  clamp,
6563
+ clampByte2 as clampByte,
6341
6564
  clearAnsiCache,
6342
6565
  clearColorCache,
6343
6566
  clearLine,
@@ -6358,6 +6581,7 @@ export {
6358
6581
  debounce,
6359
6582
  index_default as default,
6360
6583
  diffLines,
6584
+ easings,
6361
6585
  escapeForRegex,
6362
6586
  escapeRegex,
6363
6587
  fg256,
@@ -6385,9 +6609,11 @@ export {
6385
6609
  hasFont,
6386
6610
  hexToRgb,
6387
6611
  hideCursor,
6612
+ hslToRgb,
6388
6613
  hsplit,
6389
6614
  hyperlink,
6390
6615
  images,
6616
+ isFiniteNumber2 as isFiniteNumber,
6391
6617
  isHexColor,
6392
6618
  isNoColor,
6393
6619
  json,
@@ -6402,7 +6628,9 @@ export {
6402
6628
  measureBlock,
6403
6629
  measureTree,
6404
6630
  memoize,
6631
+ mixColors,
6405
6632
  nextTick,
6633
+ oklabToRgb,
6406
6634
  onConfigChange,
6407
6635
  onConfigKeyChange,
6408
6636
  onResize,
@@ -6415,6 +6643,7 @@ export {
6415
6643
  pauseListeners,
6416
6644
  presetNames,
6417
6645
  presets,
6646
+ quantizeColor,
6418
6647
  rainbow,
6419
6648
  registerFont,
6420
6649
  registerPreset,
@@ -6430,11 +6659,15 @@ export {
6430
6659
  resetFramesCursorCount,
6431
6660
  resetLoaderCursorCount,
6432
6661
  resetNoColor,
6662
+ resolveEasingByName,
6433
6663
  resumeListeners,
6434
6664
  reverseGradient,
6435
6665
  rgbTo256,
6436
6666
  rgbToHex,
6667
+ rgbToHsl,
6668
+ rgbToOklab,
6437
6669
  rotate90,
6670
+ safeInt,
6438
6671
  safeJson,
6439
6672
  screen,
6440
6673
  setConfigValue,
@@ -118,7 +118,7 @@ async function main() {
118
118
  console.log(components.section('🏷️ Badges & Status', { width: 60 }));
119
119
  console.log();
120
120
  console.log(' ',
121
- components.badge('VERSION', 'v1.3.4'),
121
+ components.badge('VERSION', 'v1.3.5'),
122
122
  components.badge('BUILD', 'passing'),
123
123
  components.badge('LICENSE', 'Apache 2.0'));
124
124
  console.log();
@@ -117,7 +117,7 @@ console.log();
117
117
  console.log(components.section('🏷️ Badges & Status', { width: 60 }));
118
118
  console.log();
119
119
  console.log(' ',
120
- components.badge('VERSION', 'v1.3.4'),
120
+ components.badge('VERSION', 'v1.3.5'),
121
121
  components.badge('BUILD', 'passing'),
122
122
  components.badge('LICENSE', 'Apache 2.0'));
123
123
  console.log();