ansimax 1.3.4 → 1.3.6

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) {
@@ -3425,6 +3558,7 @@ var multi = (opts = {}) => {
3425
3558
  const item = {
3426
3559
  id,
3427
3560
  text,
3561
+ /* istanbul ignore next — conditional spread + default */
3428
3562
  ...addOpts.color !== void 0 && { color: addOpts.color },
3429
3563
  type: addOpts.type ?? "dots",
3430
3564
  state: "spinning"
@@ -3509,11 +3643,11 @@ var loader = {
3509
3643
  };
3510
3644
 
3511
3645
  // src/frames/index.ts
3512
- var isFiniteNumber3 = (n) => typeof n === "number" && Number.isFinite(n);
3646
+ var isFiniteNumber4 = (n) => typeof n === "number" && Number.isFinite(n);
3513
3647
  var ensureString4 = (v) => typeof v === "string" ? v : String(v ?? "");
3514
3648
  var MAX_FPS = 60;
3515
3649
  var clampFps = (fps, fallback) => {
3516
- if (!isFiniteNumber3(fps)) return fallback;
3650
+ if (!isFiniteNumber4(fps)) return fallback;
3517
3651
  return Math.max(1, Math.min(MAX_FPS, Math.floor(fps)));
3518
3652
  };
3519
3653
  var _cursorHiddenCount2 = 0;
@@ -3612,14 +3746,14 @@ var play = (frames2, opts = {}) => {
3612
3746
  if (fps !== void 0) {
3613
3747
  const safeFps = clampFps(fps, 60);
3614
3748
  tickMs = Math.max(FRAME_MS, Math.floor(1e3 / safeFps));
3615
- } else if (isFiniteNumber3(interval)) {
3749
+ } else if (isFiniteNumber4(interval)) {
3616
3750
  tickMs = Math.max(FRAME_MS, Math.floor(interval));
3617
3751
  } else {
3618
3752
  tickMs = 100;
3619
3753
  }
3620
3754
  let safeRepeat;
3621
3755
  let infinite;
3622
- if (!isFiniteNumber3(repeat)) {
3756
+ if (!isFiniteNumber4(repeat)) {
3623
3757
  safeRepeat = 1;
3624
3758
  infinite = false;
3625
3759
  } else if (repeat === 0) {
@@ -3744,7 +3878,7 @@ var play = (frames2, opts = {}) => {
3744
3878
  paused = false;
3745
3879
  },
3746
3880
  seek: (idx) => {
3747
- if (!isFiniteNumber3(idx)) return;
3881
+ if (!isFiniteNumber4(idx)) return;
3748
3882
  const safe = Math.max(0, Math.floor(idx));
3749
3883
  frameIdx = frames2.length > 0 ? safe % frames2.length : 0;
3750
3884
  },
@@ -3757,7 +3891,7 @@ var play = (frames2, opts = {}) => {
3757
3891
  };
3758
3892
  };
3759
3893
  var generate = (count, fn) => {
3760
- const safeCount = isFiniteNumber3(count) ? Math.max(0, Math.floor(count)) : 0;
3894
+ const safeCount = isFiniteNumber4(count) ? Math.max(0, Math.floor(count)) : 0;
3761
3895
  if (typeof fn !== "function") return Array(safeCount).fill("");
3762
3896
  return Array.from({ length: safeCount }, (_, i) => {
3763
3897
  try {
@@ -3829,7 +3963,7 @@ var morph = (frameA, frameB, steps = 8, charset = "\u2591\u2592\u2593\u2588\u259
3829
3963
  const a0 = ensureString4(frameA);
3830
3964
  const b0 = ensureString4(frameB);
3831
3965
  if (!a0 && !b0) return [""];
3832
- const n = Math.max(2, isFiniteNumber3(steps) ? Math.floor(steps) : 8);
3966
+ const n = Math.max(2, isFiniteNumber4(steps) ? Math.floor(steps) : 8);
3833
3967
  const len = Math.max(a0.length, b0.length);
3834
3968
  const a = a0.padEnd(len);
3835
3969
  const b = b0.padEnd(len);
@@ -3851,7 +3985,7 @@ var morph = (frameA, frameB, steps = 8, charset = "\u2591\u2592\u2593\u2588\u259
3851
3985
  var presets2 = {
3852
3986
  loadingBar: (opts = {}) => {
3853
3987
  const { width = 20, char = "\u2588", empty = "\u2591", label = "Loading" } = opts;
3854
- const safeWidth = Math.max(0, isFiniteNumber3(width) ? Math.floor(width) : 20);
3988
+ const safeWidth = Math.max(0, isFiniteNumber4(width) ? Math.floor(width) : 20);
3855
3989
  const safeChar = typeof char === "string" && char.length > 0 ? char : "\u2588";
3856
3990
  const safeEmpty = typeof empty === "string" && empty.length > 0 ? empty : "\u2591";
3857
3991
  const safeLabel = ensureString4(label);
@@ -3865,7 +3999,7 @@ var presets2 = {
3865
3999
  /* istanbul ignore next — default opts {} */
3866
4000
  ball: (opts = {}) => {
3867
4001
  const { width = 20, char = "\u25CF" } = opts;
3868
- const safeWidth = Math.max(1, isFiniteNumber3(width) ? Math.floor(width) : 20);
4002
+ const safeWidth = Math.max(1, isFiniteNumber4(width) ? Math.floor(width) : 20);
3869
4003
  const safeChar = typeof char === "string" && char.length > 0 ? char : "\u25CF";
3870
4004
  const forward = generate(safeWidth, (i) => " ".repeat(i) + safeChar);
3871
4005
  const backward = generate(safeWidth, (i) => " ".repeat(safeWidth - i - 1) + safeChar);
@@ -3875,7 +4009,7 @@ var presets2 = {
3875
4009
  breathe: (text, opts = {}) => {
3876
4010
  const { steps = 8 } = opts;
3877
4011
  const safeText = ensureString4(text);
3878
- const safeSteps2 = Math.max(1, isFiniteNumber3(steps) ? Math.floor(steps) : 8);
4012
+ const safeSteps2 = Math.max(1, isFiniteNumber4(steps) ? Math.floor(steps) : 8);
3879
4013
  const shades = ["\u2591", "\u2592", "\u2593", "\u2588"];
3880
4014
  return generate(safeSteps2 * 2, (i) => {
3881
4015
  const t = i < safeSteps2 ? i / safeSteps2 : 1 - (i - safeSteps2) / safeSteps2;
@@ -3896,22 +4030,22 @@ var presets2 = {
3896
4030
  var frames = { play, generate, live, morph, presets: presets2 };
3897
4031
 
3898
4032
  // src/components/index.ts
3899
- var isFiniteNumber4 = (n) => typeof n === "number" && Number.isFinite(n);
4033
+ var isFiniteNumber5 = (n) => typeof n === "number" && Number.isFinite(n);
3900
4034
  var ensureString5 = (v) => typeof v === "string" ? v : String(v ?? "");
3901
4035
  var clampPercent2 = (p) => {
3902
- if (!isFiniteNumber4(p)) return 0;
4036
+ if (!isFiniteNumber5(p)) return 0;
3903
4037
  return Math.max(0, Math.min(100, p));
3904
4038
  };
3905
4039
  var clampNonNeg = (n, fallback) => {
3906
- if (!isFiniteNumber4(n)) return fallback;
4040
+ if (!isFiniteNumber5(n)) return fallback;
3907
4041
  return Math.max(0, Math.floor(n));
3908
4042
  };
3909
4043
  var clampPositive2 = (n, fallback) => {
3910
- if (!isFiniteNumber4(n)) return fallback;
4044
+ if (!isFiniteNumber5(n)) return fallback;
3911
4045
  return Math.max(1, Math.floor(n));
3912
4046
  };
3913
4047
  var safeSgrCode = (code, fallback) => {
3914
- if (!isFiniteNumber4(code)) return fallback;
4048
+ if (!isFiniteNumber5(code)) return fallback;
3915
4049
  return Math.max(0, Math.min(255, Math.floor(code)));
3916
4050
  };
3917
4051
  var truncateVisible = (str, maxWidth, ellipsis = "\u2026") => {
@@ -3949,7 +4083,7 @@ var table = (rows, opts = {}) => {
3949
4083
  const b = TABLE_BORDERS[borderStyle] ?? TABLE_BORDERS.rounded;
3950
4084
  const safePadding = clampNonNeg(padding, 1);
3951
4085
  const pad = " ".repeat(safePadding);
3952
- const safeMaxCol = maxColWidth !== null && isFiniteNumber4(maxColWidth) ? Math.max(1, Math.floor(maxColWidth)) : null;
4086
+ const safeMaxCol = maxColWidth !== null && isFiniteNumber5(maxColWidth) ? Math.max(1, Math.floor(maxColWidth)) : null;
3953
4087
  const validRows = rows.filter((r) => Array.isArray(r));
3954
4088
  if (validRows.length === 0) return "";
3955
4089
  const cols = Math.max(...validRows.map((r) => r.length), 0);
@@ -4042,7 +4176,7 @@ var progressBar = (percent, opts = {}) => {
4042
4176
  let filledStr = safeChar.repeat(filled);
4043
4177
  if (Array.isArray(gradientStops2) && gradientStops2.length >= 1 && filled > 0) {
4044
4178
  filledStr = gradient(filledStr, gradientStops2);
4045
- } else if (color2 !== null && isFiniteNumber4(color2)) {
4179
+ } else if (color2 !== null && isFiniteNumber5(color2)) {
4046
4180
  filledStr = sgr(safeSgrCode(color2, FG.white)) + filledStr + reset();
4047
4181
  }
4048
4182
  const emptyStr = safeEmpty.repeat(empty);
@@ -4078,7 +4212,7 @@ var section = (title, opts = {}) => {
4078
4212
  const safeChar = typeof char === "string" && char.length > 0 ? char : "\u2500";
4079
4213
  const safeColor2 = safeSgrCode(colorCode, FG.cyan);
4080
4214
  const titleLen = visibleLen(safeTitle);
4081
- const requestedWidth = width !== null && isFiniteNumber4(width) ? Math.max(1, Math.floor(width)) : cols;
4215
+ const requestedWidth = width !== null && isFiniteNumber5(width) ? Math.max(1, Math.floor(width)) : cols;
4082
4216
  const w = Math.max(requestedWidth, titleLen + 2);
4083
4217
  const side = Math.floor((w - titleLen - 2) / 2);
4084
4218
  const dividerL = sgr(safeColor2) + safeChar.repeat(Math.max(0, side)) + reset();
@@ -4092,7 +4226,7 @@ var columns = (items, opts = {}) => {
4092
4226
  const safeCols = clampPositive2(numCols, 2);
4093
4227
  const safeGap = clampNonNeg(gap, 2);
4094
4228
  const { cols: termCols } = termSize();
4095
- const totalW = width !== null && isFiniteNumber4(width) ? Math.max(safeCols, Math.floor(width)) : termCols;
4229
+ const totalW = width !== null && isFiniteNumber5(width) ? Math.max(safeCols, Math.floor(width)) : termCols;
4096
4230
  const colW = Math.max(1, Math.floor((totalW - safeGap * (safeCols - 1)) / safeCols));
4097
4231
  const gapStr = " ".repeat(safeGap);
4098
4232
  const rows = [];
@@ -4132,7 +4266,7 @@ var timeline = (events, opts = {}) => {
4132
4266
  const safeColor2 = safeSgrCode(colorCode, FG.cyan);
4133
4267
  const safeDoneColor = safeSgrCode(doneColor, FG.green);
4134
4268
  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));
4269
+ 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
4270
  const lines = [];
4137
4271
  events.forEach((ev, i) => {
4138
4272
  const isLast = i === events.length - 1;
@@ -4324,10 +4458,10 @@ var STYLES = {
4324
4458
  heavy: { branch: "\u2523\u2501\u2501 ", last: "\u2517\u2501\u2501 ", vert: "\u2503 ", space: " " },
4325
4459
  ascii: { branch: "+-- ", last: "`-- ", vert: "| ", space: " " }
4326
4460
  };
4327
- var isFiniteNumber5 = (n) => typeof n === "number" && Number.isFinite(n);
4461
+ var isFiniteNumber6 = (n) => typeof n === "number" && Number.isFinite(n);
4328
4462
  var ensureString6 = (v) => typeof v === "string" ? v : String(v ?? "");
4329
4463
  var clampNonNeg2 = (n, fallback) => {
4330
- if (!isFiniteNumber5(n)) return fallback;
4464
+ if (!isFiniteNumber6(n)) return fallback;
4331
4465
  return Math.max(0, Math.floor(n));
4332
4466
  };
4333
4467
  var normalizeNewlines = (s) => s.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
@@ -4399,7 +4533,7 @@ var renderChildren = (children, parentContinuation, lines, indentStr, defaultSty
4399
4533
  if (!Array.isArray(children)) return;
4400
4534
  let visible = children;
4401
4535
  let collapsedCount = 0;
4402
- const safeCollapse = isFiniteNumber5(collapse) ? Math.floor(collapse) : 0;
4536
+ const safeCollapse = isFiniteNumber6(collapse) ? Math.floor(collapse) : 0;
4403
4537
  if (safeCollapse > 0 && safeCollapse < children.length) {
4404
4538
  visible = children.slice(safeCollapse);
4405
4539
  collapsedCount = safeCollapse;
@@ -4469,7 +4603,7 @@ var renderTree = (root, opts = {}) => {
4469
4603
  } = opts;
4470
4604
  const safeStyle = style && STYLES[style] ? style : "normal";
4471
4605
  const safeIndent = clampNonNeg2(indent, 0);
4472
- const safeMaxDepth = isFiniteNumber5(maxDepth) ? Math.max(0, Math.floor(maxDepth)) : Infinity;
4606
+ const safeMaxDepth = isFiniteNumber6(maxDepth) ? Math.max(0, Math.floor(maxDepth)) : Infinity;
4473
4607
  const indentStr = " ".repeat(safeIndent);
4474
4608
  const lines = [];
4475
4609
  const rootLabel = formatNode(root, 0, palette);
@@ -5088,13 +5222,13 @@ var themes = {
5088
5222
  var FULL_BLOCK = "\u2588";
5089
5223
  var UPPER_HALF = "\u2580";
5090
5224
  var LOWER_HALF = "\u2584";
5091
- var isFiniteNumber6 = (n) => typeof n === "number" && Number.isFinite(n);
5225
+ var isFiniteNumber7 = (n) => typeof n === "number" && Number.isFinite(n);
5092
5226
  var clampInt = (n, min, max, fallback) => {
5093
- if (!isFiniteNumber6(n)) return fallback;
5227
+ if (!isFiniteNumber7(n)) return fallback;
5094
5228
  return Math.max(min, Math.min(max, Math.floor(n)));
5095
5229
  };
5096
5230
  var clampByte3 = (n) => {
5097
- if (!isFiniteNumber6(n)) return 0;
5231
+ if (!isFiniteNumber7(n)) return 0;
5098
5232
  return Math.max(0, Math.min(255, Math.round(n)));
5099
5233
  };
5100
5234
  var MAX_DIMENSION = 1e4;
@@ -5399,7 +5533,7 @@ var gradientRect = (opts = {}) => {
5399
5533
  const safeW = clampInt(width, 2, MAX_DIMENSION, 40);
5400
5534
  const safeH = clampInt(height, 2, MAX_DIMENSION, 10);
5401
5535
  let cosA = 1, sinA = 0;
5402
- if (isFiniteNumber6(angle)) {
5536
+ if (isFiniteNumber7(angle)) {
5403
5537
  const rad = angle * Math.PI / 180;
5404
5538
  cosA = Math.cos(rad);
5405
5539
  sinA = Math.sin(rad);
@@ -5409,7 +5543,7 @@ var gradientRect = (opts = {}) => {
5409
5543
  const line = [];
5410
5544
  for (let col = 0; col < safeW; col++) {
5411
5545
  let t;
5412
- if (isFiniteNumber6(angle)) {
5546
+ if (isFiniteNumber7(angle)) {
5413
5547
  const projection = col / (safeW - 1) * cosA + row / (safeH - 1) * sinA;
5414
5548
  t = clamp((projection + 1) / 2, 0, 1);
5415
5549
  } else if (style === "horizontal") t = col / (safeW - 1);
@@ -5466,7 +5600,7 @@ var createCanvas = (width, height, fillColor = null) => {
5466
5600
  if (y > dirtyMaxY) dirtyMaxY = y;
5467
5601
  };
5468
5602
  const setInternal = (x, y, color2) => {
5469
- if (!isFiniteNumber6(x) || !isFiniteNumber6(y)) return;
5603
+ if (!isFiniteNumber7(x) || !isFiniteNumber7(y)) return;
5470
5604
  const ix = Math.floor(x);
5471
5605
  const iy = Math.floor(y);
5472
5606
  if (iy < 0 || iy >= h || ix < 0 || ix >= w) return;
@@ -5481,7 +5615,7 @@ var createCanvas = (width, height, fillColor = null) => {
5481
5615
  },
5482
5616
  set: setInternal,
5483
5617
  get(x, y) {
5484
- if (!isFiniteNumber6(x) || !isFiniteNumber6(y)) return null;
5618
+ if (!isFiniteNumber7(x) || !isFiniteNumber7(y)) return null;
5485
5619
  const ix = Math.floor(x), iy = Math.floor(y);
5486
5620
  return cloneColor(pixels[iy]?.[ix] ?? null);
5487
5621
  },
@@ -5497,7 +5631,7 @@ var createCanvas = (width, height, fillColor = null) => {
5497
5631
  dirtyMaxY = h - 1;
5498
5632
  },
5499
5633
  drawRect(x, y, rw, rh, color2, fill = false) {
5500
- if (!isFiniteNumber6(x) || !isFiniteNumber6(y) || !isFiniteNumber6(rw) || !isFiniteNumber6(rh)) return;
5634
+ if (!isFiniteNumber7(x) || !isFiniteNumber7(y) || !isFiniteNumber7(rw) || !isFiniteNumber7(rh)) return;
5501
5635
  if (rw <= 0 || rh <= 0) return;
5502
5636
  const ix = Math.floor(x);
5503
5637
  const iy = Math.floor(y);
@@ -5519,7 +5653,7 @@ var createCanvas = (width, height, fillColor = null) => {
5519
5653
  }
5520
5654
  },
5521
5655
  drawCircle(cx, cy, radius, color2, fill = false) {
5522
- if (!isFiniteNumber6(cx) || !isFiniteNumber6(cy) || !isFiniteNumber6(radius)) return;
5656
+ if (!isFiniteNumber7(cx) || !isFiniteNumber7(cy) || !isFiniteNumber7(radius)) return;
5523
5657
  if (radius <= 0) return;
5524
5658
  const x0 = Math.max(0, Math.floor(cx - radius - 1));
5525
5659
  const y0 = Math.max(0, Math.floor(cy - radius - 1));
@@ -5542,7 +5676,7 @@ var createCanvas = (width, height, fillColor = null) => {
5542
5676
  }
5543
5677
  },
5544
5678
  drawSprite(x, y, sprite) {
5545
- if (!isFiniteNumber6(x) || !isFiniteNumber6(y)) return;
5679
+ if (!isFiniteNumber7(x) || !isFiniteNumber7(y)) return;
5546
5680
  if (!Array.isArray(sprite)) return;
5547
5681
  const sx = Math.floor(x);
5548
5682
  const sy = Math.floor(y);
@@ -6304,6 +6438,95 @@ var setConfigValue = (key, value) => {
6304
6438
  };
6305
6439
  var subscribeConfig = onConfigChange;
6306
6440
 
6441
+ // src/utils/easing.ts
6442
+ var c1 = 1.70158;
6443
+ var c2 = c1 * 1.525;
6444
+ var c3 = c1 + 1;
6445
+ var c4 = 2 * Math.PI / 3;
6446
+ var c5 = 2 * Math.PI / 4.5;
6447
+ var _bounceOut = (t) => {
6448
+ const n1 = 7.5625;
6449
+ const d1 = 2.75;
6450
+ if (t < 1 / d1) return n1 * t * t;
6451
+ if (t < 2 / d1) {
6452
+ const x2 = t - 1.5 / d1;
6453
+ return n1 * x2 * x2 + 0.75;
6454
+ }
6455
+ if (t < 2.5 / d1) {
6456
+ const x2 = t - 2.25 / d1;
6457
+ return n1 * x2 * x2 + 0.9375;
6458
+ }
6459
+ const x = t - 2.625 / d1;
6460
+ return n1 * x * x + 0.984375;
6461
+ };
6462
+ var easings = {
6463
+ // ── Linear ──
6464
+ linear: (t) => t,
6465
+ // ── Quadratic (t²) ──
6466
+ easeInQuad: (t) => t * t,
6467
+ easeOutQuad: (t) => 1 - (1 - t) * (1 - t),
6468
+ easeInOutQuad: (t) => t < 0.5 ? 2 * t * t : 1 - Math.pow(-2 * t + 2, 2) / 2,
6469
+ // ── Cubic (t³) ──
6470
+ easeInCubic: (t) => t * t * t,
6471
+ easeOutCubic: (t) => 1 - Math.pow(1 - t, 3),
6472
+ easeInOutCubic: (t) => t < 0.5 ? 4 * t * t * t : 1 - Math.pow(-2 * t + 2, 3) / 2,
6473
+ // ── Quartic (t⁴) ──
6474
+ easeInQuart: (t) => t * t * t * t,
6475
+ easeOutQuart: (t) => 1 - Math.pow(1 - t, 4),
6476
+ easeInOutQuart: (t) => t < 0.5 ? 8 * t * t * t * t : 1 - Math.pow(-2 * t + 2, 4) / 2,
6477
+ // ── Quintic (t⁵) ──
6478
+ easeInQuint: (t) => t * t * t * t * t,
6479
+ easeOutQuint: (t) => 1 - Math.pow(1 - t, 5),
6480
+ easeInOutQuint: (t) => t < 0.5 ? 16 * t * t * t * t * t : 1 - Math.pow(-2 * t + 2, 5) / 2,
6481
+ // ── Sinusoidal ──
6482
+ easeInSine: (t) => 1 - Math.cos(t * Math.PI / 2),
6483
+ easeOutSine: (t) => Math.sin(t * Math.PI / 2),
6484
+ easeInOutSine: (t) => -(Math.cos(Math.PI * t) - 1) / 2,
6485
+ // ── Exponential ──
6486
+ easeInExpo: (t) => t === 0 ? 0 : Math.pow(2, 10 * t - 10),
6487
+ easeOutExpo: (t) => t === 1 ? 1 : 1 - Math.pow(2, -10 * t),
6488
+ easeInOutExpo: (t) => {
6489
+ if (t === 0) return 0;
6490
+ if (t === 1) return 1;
6491
+ return t < 0.5 ? Math.pow(2, 20 * t - 10) / 2 : (2 - Math.pow(2, -20 * t + 10)) / 2;
6492
+ },
6493
+ // ── Circular ──
6494
+ easeInCirc: (t) => 1 - Math.sqrt(1 - Math.pow(t, 2)),
6495
+ easeOutCirc: (t) => Math.sqrt(1 - Math.pow(t - 1, 2)),
6496
+ 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,
6497
+ // ── Back (overshoots) ──
6498
+ easeInBack: (t) => c3 * t * t * t - c1 * t * t,
6499
+ easeOutBack: (t) => 1 + c3 * Math.pow(t - 1, 3) + c1 * Math.pow(t - 1, 2),
6500
+ 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,
6501
+ // ── Elastic (oscillates) ──
6502
+ easeInElastic: (t) => {
6503
+ if (t === 0) return 0;
6504
+ if (t === 1) return 1;
6505
+ return -Math.pow(2, 10 * t - 10) * Math.sin((t * 10 - 10.75) * c4);
6506
+ },
6507
+ easeOutElastic: (t) => {
6508
+ if (t === 0) return 0;
6509
+ if (t === 1) return 1;
6510
+ return Math.pow(2, -10 * t) * Math.sin((t * 10 - 0.75) * c4) + 1;
6511
+ },
6512
+ easeInOutElastic: (t) => {
6513
+ if (t === 0) return 0;
6514
+ if (t === 1) return 1;
6515
+ 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;
6516
+ },
6517
+ // ── Bounce (bouncing ball) ──
6518
+ easeInBounce: (t) => 1 - _bounceOut(1 - t),
6519
+ easeOutBounce: _bounceOut,
6520
+ easeInOutBounce: (t) => t < 0.5 ? (1 - _bounceOut(1 - 2 * t)) / 2 : (1 + _bounceOut(2 * t - 1)) / 2
6521
+ };
6522
+ var resolveEasingByName = (e) => {
6523
+ if (typeof e === "function") return e;
6524
+ if (typeof e === "string" && easings[e]) {
6525
+ return easings[e];
6526
+ }
6527
+ return easings.linear;
6528
+ };
6529
+
6307
6530
  // src/index.ts
6308
6531
  var ansimax = { color, animate, ascii, loader, frames, components, trees, themes, images, configure };
6309
6532
  var index_default = ansimax;
@@ -6338,6 +6561,7 @@ export {
6338
6561
  chain,
6339
6562
  charWidth,
6340
6563
  clamp,
6564
+ clampByte2 as clampByte,
6341
6565
  clearAnsiCache,
6342
6566
  clearColorCache,
6343
6567
  clearLine,
@@ -6358,6 +6582,7 @@ export {
6358
6582
  debounce,
6359
6583
  index_default as default,
6360
6584
  diffLines,
6585
+ easings,
6361
6586
  escapeForRegex,
6362
6587
  escapeRegex,
6363
6588
  fg256,
@@ -6385,9 +6610,11 @@ export {
6385
6610
  hasFont,
6386
6611
  hexToRgb,
6387
6612
  hideCursor,
6613
+ hslToRgb,
6388
6614
  hsplit,
6389
6615
  hyperlink,
6390
6616
  images,
6617
+ isFiniteNumber2 as isFiniteNumber,
6391
6618
  isHexColor,
6392
6619
  isNoColor,
6393
6620
  json,
@@ -6402,7 +6629,9 @@ export {
6402
6629
  measureBlock,
6403
6630
  measureTree,
6404
6631
  memoize,
6632
+ mixColors,
6405
6633
  nextTick,
6634
+ oklabToRgb,
6406
6635
  onConfigChange,
6407
6636
  onConfigKeyChange,
6408
6637
  onResize,
@@ -6415,6 +6644,7 @@ export {
6415
6644
  pauseListeners,
6416
6645
  presetNames,
6417
6646
  presets,
6647
+ quantizeColor,
6418
6648
  rainbow,
6419
6649
  registerFont,
6420
6650
  registerPreset,
@@ -6430,11 +6660,15 @@ export {
6430
6660
  resetFramesCursorCount,
6431
6661
  resetLoaderCursorCount,
6432
6662
  resetNoColor,
6663
+ resolveEasingByName,
6433
6664
  resumeListeners,
6434
6665
  reverseGradient,
6435
6666
  rgbTo256,
6436
6667
  rgbToHex,
6668
+ rgbToHsl,
6669
+ rgbToOklab,
6437
6670
  rotate90,
6671
+ safeInt,
6438
6672
  safeJson,
6439
6673
  screen,
6440
6674
  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.6'),
122
122
  components.badge('BUILD', 'passing'),
123
123
  components.badge('LICENSE', 'Apache 2.0'));
124
124
  console.log();