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.js CHANGED
@@ -60,6 +60,7 @@ __export(index_exports, {
60
60
  chain: () => chain,
61
61
  charWidth: () => charWidth,
62
62
  clamp: () => clamp,
63
+ clampByte: () => clampByte2,
63
64
  clearAnsiCache: () => clearAnsiCache,
64
65
  clearColorCache: () => clearColorCache,
65
66
  clearLine: () => clearLine,
@@ -80,6 +81,7 @@ __export(index_exports, {
80
81
  debounce: () => debounce,
81
82
  default: () => index_default,
82
83
  diffLines: () => diffLines,
84
+ easings: () => easings,
83
85
  escapeForRegex: () => escapeForRegex,
84
86
  escapeRegex: () => escapeRegex,
85
87
  fg256: () => fg256,
@@ -107,9 +109,11 @@ __export(index_exports, {
107
109
  hasFont: () => hasFont,
108
110
  hexToRgb: () => hexToRgb,
109
111
  hideCursor: () => hideCursor,
112
+ hslToRgb: () => hslToRgb,
110
113
  hsplit: () => hsplit,
111
114
  hyperlink: () => hyperlink,
112
115
  images: () => images,
116
+ isFiniteNumber: () => isFiniteNumber2,
113
117
  isHexColor: () => isHexColor,
114
118
  isNoColor: () => isNoColor,
115
119
  json: () => json,
@@ -124,7 +128,9 @@ __export(index_exports, {
124
128
  measureBlock: () => measureBlock,
125
129
  measureTree: () => measureTree,
126
130
  memoize: () => memoize,
131
+ mixColors: () => mixColors,
127
132
  nextTick: () => nextTick,
133
+ oklabToRgb: () => oklabToRgb,
128
134
  onConfigChange: () => onConfigChange,
129
135
  onConfigKeyChange: () => onConfigKeyChange,
130
136
  onResize: () => onResize,
@@ -137,6 +143,7 @@ __export(index_exports, {
137
143
  pauseListeners: () => pauseListeners,
138
144
  presetNames: () => presetNames,
139
145
  presets: () => presets,
146
+ quantizeColor: () => quantizeColor,
140
147
  rainbow: () => rainbow,
141
148
  registerFont: () => registerFont,
142
149
  registerPreset: () => registerPreset,
@@ -152,11 +159,15 @@ __export(index_exports, {
152
159
  resetFramesCursorCount: () => resetFramesCursorCount,
153
160
  resetLoaderCursorCount: () => resetLoaderCursorCount,
154
161
  resetNoColor: () => resetNoColor,
162
+ resolveEasingByName: () => resolveEasingByName,
155
163
  resumeListeners: () => resumeListeners,
156
164
  reverseGradient: () => reverseGradient,
157
165
  rgbTo256: () => rgbTo256,
158
166
  rgbToHex: () => rgbToHex,
167
+ rgbToHsl: () => rgbToHsl,
168
+ rgbToOklab: () => rgbToOklab,
159
169
  rotate90: () => rotate90,
170
+ safeInt: () => safeInt,
160
171
  safeJson: () => safeJson,
161
172
  screen: () => screen,
162
173
  setConfigValue: () => setConfigValue,
@@ -584,6 +595,16 @@ var hyperlink = (url, label) => {
584
595
  var clearLine = () => `${CSI}2K\r`;
585
596
 
586
597
  // src/utils/helpers.ts
598
+ var isFiniteNumber2 = (n) => typeof n === "number" && Number.isFinite(n);
599
+ var safeInt = (value, fallback = 0, min = -Infinity, max = Infinity) => {
600
+ const isRealNumeric = typeof value === "number" || typeof value === "string" && value.trim().length > 0 && Number.isFinite(Number(value));
601
+ if (!isRealNumeric) {
602
+ return Math.max(min, Math.min(max, Math.floor(fallback)));
603
+ }
604
+ const n = Number(value);
605
+ if (!Number.isFinite(n)) return Math.max(min, Math.min(max, Math.floor(fallback)));
606
+ return Math.max(min, Math.min(max, Math.floor(n)));
607
+ };
587
608
  var clamp = (n, min, max) => Math.min(Math.max(n, min), max);
588
609
  var lerp = (a, b, t) => a + (b - a) * t;
589
610
  var clampByte2 = (v) => clamp(Math.round(v), 0, 255);
@@ -599,25 +620,148 @@ var hexToRgb = (hex) => {
599
620
  return { r: int >> 16 & 255, g: int >> 8 & 255, b: int & 255 };
600
621
  };
601
622
  var rgbToHex = (r, g, b) => "#" + [clampByte2(r), clampByte2(g), clampByte2(b)].map((v) => v.toString(16).padStart(2, "0")).join("");
602
- var lerpColor = (a, b, t) => {
623
+ var rgbToHsl = (rgb) => {
624
+ const r = clamp(rgb.r, 0, 255) / 255;
625
+ const g = clamp(rgb.g, 0, 255) / 255;
626
+ const b = clamp(rgb.b, 0, 255) / 255;
627
+ const max = Math.max(r, g, b);
628
+ const min = Math.min(r, g, b);
629
+ const l = (max + min) / 2;
630
+ if (max === min) {
631
+ return { h: 0, s: 0, l };
632
+ }
633
+ const d = max - min;
634
+ const s = l > 0.5 ? d / (2 - max - min) : d / (max + min);
635
+ let h;
636
+ if (max === r) {
637
+ h = ((g - b) / d + (g < b ? 6 : 0)) * 60;
638
+ } else if (max === g) {
639
+ h = ((b - r) / d + 2) * 60;
640
+ } else {
641
+ h = ((r - g) / d + 4) * 60;
642
+ }
643
+ return { h, s, l };
644
+ };
645
+ var hslToRgb = (hsl) => {
646
+ const h = (hsl.h % 360 + 360) % 360 / 360;
647
+ const s = clamp(hsl.s, 0, 1);
648
+ const l = clamp(hsl.l, 0, 1);
649
+ if (s === 0) {
650
+ const v = Math.round(l * 255);
651
+ return { r: v, g: v, b: v };
652
+ }
653
+ const hue2rgb = (p2, q2, t) => {
654
+ let tt = t;
655
+ if (tt < 0) tt += 1;
656
+ if (tt > 1) tt -= 1;
657
+ if (tt < 1 / 6) return p2 + (q2 - p2) * 6 * tt;
658
+ if (tt < 1 / 2) return q2;
659
+ if (tt < 2 / 3) return p2 + (q2 - p2) * (2 / 3 - tt) * 6;
660
+ return p2;
661
+ };
662
+ const q = l < 0.5 ? l * (1 + s) : l + s - l * s;
663
+ const p = 2 * l - q;
664
+ return {
665
+ r: Math.round(hue2rgb(p, q, h + 1 / 3) * 255),
666
+ g: Math.round(hue2rgb(p, q, h) * 255),
667
+ b: Math.round(hue2rgb(p, q, h - 1 / 3) * 255)
668
+ };
669
+ };
670
+ var _srgbToLinear = (c) => {
671
+ const x = c / 255;
672
+ return x <= 0.04045 ? x / 12.92 : Math.pow((x + 0.055) / 1.055, 2.4);
673
+ };
674
+ var _linearToSrgb = (c) => {
675
+ const x = c <= 31308e-7 ? 12.92 * c : 1.055 * Math.pow(c, 1 / 2.4) - 0.055;
676
+ return clampByte2(x * 255);
677
+ };
678
+ var rgbToOklab = (rgb) => {
679
+ const r = _srgbToLinear(rgb.r);
680
+ const g = _srgbToLinear(rgb.g);
681
+ const b = _srgbToLinear(rgb.b);
682
+ const l = 0.4122214708 * r + 0.5363325363 * g + 0.0514459929 * b;
683
+ const m = 0.2119034982 * r + 0.6806995451 * g + 0.1073969566 * b;
684
+ const s = 0.0883024619 * r + 0.2817188376 * g + 0.6299787005 * b;
685
+ const l_ = Math.cbrt(l);
686
+ const m_ = Math.cbrt(m);
687
+ const s_ = Math.cbrt(s);
688
+ return {
689
+ L: 0.2104542553 * l_ + 0.793617785 * m_ - 0.0040720468 * s_,
690
+ a: 1.9779984951 * l_ - 2.428592205 * m_ + 0.4505937099 * s_,
691
+ b: 0.0259040371 * l_ + 0.7827717662 * m_ - 0.808675766 * s_
692
+ };
693
+ };
694
+ var oklabToRgb = (oklab) => {
695
+ const l_ = oklab.L + 0.3963377774 * oklab.a + 0.2158037573 * oklab.b;
696
+ const m_ = oklab.L - 0.1055613458 * oklab.a - 0.0638541728 * oklab.b;
697
+ const s_ = oklab.L - 0.0894841775 * oklab.a - 1.291485548 * oklab.b;
698
+ const l = l_ * l_ * l_;
699
+ const m = m_ * m_ * m_;
700
+ const s = s_ * s_ * s_;
701
+ const r = 4.0767416621 * l - 3.3077115913 * m + 0.2309699292 * s;
702
+ const g = -1.2684380046 * l + 2.6097574011 * m - 0.3413193965 * s;
703
+ const b = -0.0041960863 * l - 0.7034186147 * m + 1.707614701 * s;
704
+ return {
705
+ r: _linearToSrgb(r),
706
+ g: _linearToSrgb(g),
707
+ b: _linearToSrgb(b)
708
+ };
709
+ };
710
+ var lerpColor = (a, b, t, space = "rgb") => {
603
711
  const ct = clamp(t, 0, 1);
712
+ if (space === "oklab") {
713
+ const la = rgbToOklab(a);
714
+ const lb = rgbToOklab(b);
715
+ return oklabToRgb({
716
+ L: lerp(la.L, lb.L, ct),
717
+ a: lerp(la.a, lb.a, ct),
718
+ b: lerp(la.b, lb.b, ct)
719
+ });
720
+ }
721
+ if (space === "hsl") {
722
+ const ha = rgbToHsl(a);
723
+ const hb = rgbToHsl(b);
724
+ let dh = hb.h - ha.h;
725
+ if (dh > 180) dh -= 360;
726
+ else if (dh < -180) dh += 360;
727
+ const h = ha.h + dh * ct;
728
+ return hslToRgb({
729
+ h,
730
+ s: lerp(ha.s, hb.s, ct),
731
+ l: lerp(ha.l, hb.l, ct)
732
+ });
733
+ }
604
734
  return {
605
735
  r: Math.round(lerp(a.r, b.r, ct)),
606
736
  g: Math.round(lerp(a.g, b.g, ct)),
607
737
  b: Math.round(lerp(a.b, b.b, ct))
608
738
  };
609
739
  };
610
- var gradientColor = (colors, t) => {
740
+ var mixColors = (a, b, t, space = "rgb") => {
741
+ const ra = typeof a === "string" ? hexToRgb(a) : a;
742
+ const rb = typeof b === "string" ? hexToRgb(b) : b;
743
+ return lerpColor(ra, rb, t, space);
744
+ };
745
+ var quantizeColor = (color2, levels = 4) => {
746
+ const safeLevels = Math.max(2, Math.floor(levels));
747
+ const step = 255 / (safeLevels - 1);
748
+ return {
749
+ r: Math.round(clampByte2(color2.r) / step) * step | 0,
750
+ g: Math.round(clampByte2(color2.g) / step) * step | 0,
751
+ b: Math.round(clampByte2(color2.b) / step) * step | 0
752
+ };
753
+ };
754
+ var gradientColor = (colors, t, space = "rgb") => {
611
755
  if (!Array.isArray(colors) || colors.length === 0) {
612
756
  throw new Error("gradientColor requires at least one color stop");
613
757
  }
614
758
  if (colors.length === 1) return colors[0];
615
- const safeT = typeof t === "number" && Number.isFinite(t) ? t : 0;
759
+ const safeT = isFiniteNumber2(t) ? t : 0;
616
760
  const ct = clamp(safeT, 0, 1);
617
761
  const scaled = ct * (colors.length - 1);
618
762
  const lo = Math.floor(scaled);
619
763
  const hi = Math.min(lo + 1, colors.length - 1);
620
- return lerpColor(colors[lo], colors[hi], scaled - lo);
764
+ return lerpColor(colors[lo], colors[hi], scaled - lo, space);
621
765
  };
622
766
  var rgbTo256 = (r, g, b) => {
623
767
  const cr = clampByte2(r), cg = clampByte2(g), cb = clampByte2(b);
@@ -1004,7 +1148,7 @@ var padBoth = (str, width, ch = " ") => {
1004
1148
  const r = pad - l;
1005
1149
  return ch.repeat(l) + str + ch.repeat(r);
1006
1150
  };
1007
- var gradientStops = (start, end, count) => {
1151
+ var gradientStops = (start, end, count, space = "rgb") => {
1008
1152
  const safeCount = Math.max(2, Math.floor(Number.isFinite(count) ? count : 2));
1009
1153
  if (!isHexColor(start) || !isHexColor(end)) return [];
1010
1154
  const a = hexToRgb(start);
@@ -1012,7 +1156,7 @@ var gradientStops = (start, end, count) => {
1012
1156
  const result = [];
1013
1157
  for (let i = 0; i < safeCount; i++) {
1014
1158
  const t = i / (safeCount - 1);
1015
- const c = lerpColor(a, b, t);
1159
+ const c = lerpColor(a, b, t, space);
1016
1160
  result.push(rgbToHex(c.r, c.g, c.b));
1017
1161
  }
1018
1162
  return result;
@@ -1896,8 +2040,8 @@ var pulse = async (text, opts = {}) => {
1896
2040
  fireDone(hooks, isAborted(signal));
1897
2041
  return;
1898
2042
  }
1899
- const c1 = resolveRgb(color1);
1900
- const c2 = resolveRgb(color2);
2043
+ const c12 = resolveRgb(color1);
2044
+ const c22 = resolveRgb(color2);
1901
2045
  const cycles = Math.max(1, Math.round(times));
1902
2046
  const halfInterval = Math.max(FRAME_MS, interval);
1903
2047
  registerCrashHandlers();
@@ -1911,7 +2055,7 @@ var pulse = async (text, opts = {}) => {
1911
2055
  break;
1912
2056
  }
1913
2057
  await safeWriteAsync(
1914
- cursor.save() + fgRgb(c1.r, c1.g, c1.b) + text + reset() + cursor.restore()
2058
+ cursor.save() + fgRgb(c12.r, c12.g, c12.b) + text + reset() + cursor.restore()
1915
2059
  );
1916
2060
  fireFrame(hooks, frame2++);
1917
2061
  await sleep(halfInterval, { signal });
@@ -1920,14 +2064,14 @@ var pulse = async (text, opts = {}) => {
1920
2064
  break;
1921
2065
  }
1922
2066
  await safeWriteAsync(
1923
- cursor.save() + fgRgb(c2.r, c2.g, c2.b) + text + reset() + cursor.restore()
2067
+ cursor.save() + fgRgb(c22.r, c22.g, c22.b) + text + reset() + cursor.restore()
1924
2068
  );
1925
2069
  fireFrame(hooks, frame2++);
1926
2070
  await sleep(halfInterval, { signal });
1927
2071
  }
1928
2072
  if (!aborted) {
1929
2073
  await safeWriteAsync(
1930
- cursor.save() + fgRgb(c1.r, c1.g, c1.b) + text + reset() + cursor.restore()
2074
+ cursor.save() + fgRgb(c12.r, c12.g, c12.b) + text + reset() + cursor.restore()
1931
2075
  );
1932
2076
  }
1933
2077
  } finally {
@@ -3098,14 +3242,14 @@ var ascii = {
3098
3242
 
3099
3243
  // src/loaders/index.ts
3100
3244
  var canAnimate2 = () => Boolean(process.stdout?.isTTY) && supportsColor() !== "none";
3101
- var isFiniteNumber2 = (n) => typeof n === "number" && Number.isFinite(n);
3245
+ var isFiniteNumber3 = (n) => typeof n === "number" && Number.isFinite(n);
3102
3246
  var ensureString3 = (v) => typeof v === "string" ? v : String(v ?? "");
3103
3247
  var clampPositiveInt = (n, fallback) => {
3104
- if (!isFiniteNumber2(n)) return fallback;
3248
+ if (!isFiniteNumber3(n)) return fallback;
3105
3249
  return Math.max(1, Math.floor(n));
3106
3250
  };
3107
3251
  var clampPercent = (p) => {
3108
- if (!isFiniteNumber2(p)) return 0;
3252
+ if (!isFiniteNumber3(p)) return 0;
3109
3253
  return Math.max(0, Math.min(100, p));
3110
3254
  };
3111
3255
  var isUnicodeCapable = () => {
@@ -3497,7 +3641,7 @@ var custom = (frames2, text = "", opts = {}) => {
3497
3641
  };
3498
3642
  var countdown = async (seconds, opts = {}) => {
3499
3643
  const { label = "Starting in", color: hex, signal } = opts;
3500
- const safeSeconds = isFiniteNumber2(seconds) ? Math.max(0, Math.floor(seconds)) : 0;
3644
+ const safeSeconds = isFiniteNumber3(seconds) ? Math.max(0, Math.floor(seconds)) : 0;
3501
3645
  const safeLabel = ensureString3(label);
3502
3646
  const colorToUse = safeColor(hex) ? hex : "#ffd700";
3503
3647
  if (!canAnimate2() || signal?.aborted) {
@@ -3620,6 +3764,7 @@ var multi = (opts = {}) => {
3620
3764
  const item = {
3621
3765
  id,
3622
3766
  text,
3767
+ /* istanbul ignore next — conditional spread + default */
3623
3768
  ...addOpts.color !== void 0 && { color: addOpts.color },
3624
3769
  type: addOpts.type ?? "dots",
3625
3770
  state: "spinning"
@@ -3704,11 +3849,11 @@ var loader = {
3704
3849
  };
3705
3850
 
3706
3851
  // src/frames/index.ts
3707
- var isFiniteNumber3 = (n) => typeof n === "number" && Number.isFinite(n);
3852
+ var isFiniteNumber4 = (n) => typeof n === "number" && Number.isFinite(n);
3708
3853
  var ensureString4 = (v) => typeof v === "string" ? v : String(v ?? "");
3709
3854
  var MAX_FPS = 60;
3710
3855
  var clampFps = (fps, fallback) => {
3711
- if (!isFiniteNumber3(fps)) return fallback;
3856
+ if (!isFiniteNumber4(fps)) return fallback;
3712
3857
  return Math.max(1, Math.min(MAX_FPS, Math.floor(fps)));
3713
3858
  };
3714
3859
  var _cursorHiddenCount2 = 0;
@@ -3807,14 +3952,14 @@ var play = (frames2, opts = {}) => {
3807
3952
  if (fps !== void 0) {
3808
3953
  const safeFps = clampFps(fps, 60);
3809
3954
  tickMs = Math.max(FRAME_MS, Math.floor(1e3 / safeFps));
3810
- } else if (isFiniteNumber3(interval)) {
3955
+ } else if (isFiniteNumber4(interval)) {
3811
3956
  tickMs = Math.max(FRAME_MS, Math.floor(interval));
3812
3957
  } else {
3813
3958
  tickMs = 100;
3814
3959
  }
3815
3960
  let safeRepeat;
3816
3961
  let infinite;
3817
- if (!isFiniteNumber3(repeat)) {
3962
+ if (!isFiniteNumber4(repeat)) {
3818
3963
  safeRepeat = 1;
3819
3964
  infinite = false;
3820
3965
  } else if (repeat === 0) {
@@ -3939,7 +4084,7 @@ var play = (frames2, opts = {}) => {
3939
4084
  paused = false;
3940
4085
  },
3941
4086
  seek: (idx) => {
3942
- if (!isFiniteNumber3(idx)) return;
4087
+ if (!isFiniteNumber4(idx)) return;
3943
4088
  const safe = Math.max(0, Math.floor(idx));
3944
4089
  frameIdx = frames2.length > 0 ? safe % frames2.length : 0;
3945
4090
  },
@@ -3952,7 +4097,7 @@ var play = (frames2, opts = {}) => {
3952
4097
  };
3953
4098
  };
3954
4099
  var generate = (count, fn) => {
3955
- const safeCount = isFiniteNumber3(count) ? Math.max(0, Math.floor(count)) : 0;
4100
+ const safeCount = isFiniteNumber4(count) ? Math.max(0, Math.floor(count)) : 0;
3956
4101
  if (typeof fn !== "function") return Array(safeCount).fill("");
3957
4102
  return Array.from({ length: safeCount }, (_, i) => {
3958
4103
  try {
@@ -4024,7 +4169,7 @@ var morph = (frameA, frameB, steps = 8, charset = "\u2591\u2592\u2593\u2588\u259
4024
4169
  const a0 = ensureString4(frameA);
4025
4170
  const b0 = ensureString4(frameB);
4026
4171
  if (!a0 && !b0) return [""];
4027
- const n = Math.max(2, isFiniteNumber3(steps) ? Math.floor(steps) : 8);
4172
+ const n = Math.max(2, isFiniteNumber4(steps) ? Math.floor(steps) : 8);
4028
4173
  const len = Math.max(a0.length, b0.length);
4029
4174
  const a = a0.padEnd(len);
4030
4175
  const b = b0.padEnd(len);
@@ -4046,7 +4191,7 @@ var morph = (frameA, frameB, steps = 8, charset = "\u2591\u2592\u2593\u2588\u259
4046
4191
  var presets2 = {
4047
4192
  loadingBar: (opts = {}) => {
4048
4193
  const { width = 20, char = "\u2588", empty = "\u2591", label = "Loading" } = opts;
4049
- const safeWidth = Math.max(0, isFiniteNumber3(width) ? Math.floor(width) : 20);
4194
+ const safeWidth = Math.max(0, isFiniteNumber4(width) ? Math.floor(width) : 20);
4050
4195
  const safeChar = typeof char === "string" && char.length > 0 ? char : "\u2588";
4051
4196
  const safeEmpty = typeof empty === "string" && empty.length > 0 ? empty : "\u2591";
4052
4197
  const safeLabel = ensureString4(label);
@@ -4060,7 +4205,7 @@ var presets2 = {
4060
4205
  /* istanbul ignore next — default opts {} */
4061
4206
  ball: (opts = {}) => {
4062
4207
  const { width = 20, char = "\u25CF" } = opts;
4063
- const safeWidth = Math.max(1, isFiniteNumber3(width) ? Math.floor(width) : 20);
4208
+ const safeWidth = Math.max(1, isFiniteNumber4(width) ? Math.floor(width) : 20);
4064
4209
  const safeChar = typeof char === "string" && char.length > 0 ? char : "\u25CF";
4065
4210
  const forward = generate(safeWidth, (i) => " ".repeat(i) + safeChar);
4066
4211
  const backward = generate(safeWidth, (i) => " ".repeat(safeWidth - i - 1) + safeChar);
@@ -4070,7 +4215,7 @@ var presets2 = {
4070
4215
  breathe: (text, opts = {}) => {
4071
4216
  const { steps = 8 } = opts;
4072
4217
  const safeText = ensureString4(text);
4073
- const safeSteps2 = Math.max(1, isFiniteNumber3(steps) ? Math.floor(steps) : 8);
4218
+ const safeSteps2 = Math.max(1, isFiniteNumber4(steps) ? Math.floor(steps) : 8);
4074
4219
  const shades = ["\u2591", "\u2592", "\u2593", "\u2588"];
4075
4220
  return generate(safeSteps2 * 2, (i) => {
4076
4221
  const t = i < safeSteps2 ? i / safeSteps2 : 1 - (i - safeSteps2) / safeSteps2;
@@ -4091,22 +4236,22 @@ var presets2 = {
4091
4236
  var frames = { play, generate, live, morph, presets: presets2 };
4092
4237
 
4093
4238
  // src/components/index.ts
4094
- var isFiniteNumber4 = (n) => typeof n === "number" && Number.isFinite(n);
4239
+ var isFiniteNumber5 = (n) => typeof n === "number" && Number.isFinite(n);
4095
4240
  var ensureString5 = (v) => typeof v === "string" ? v : String(v ?? "");
4096
4241
  var clampPercent2 = (p) => {
4097
- if (!isFiniteNumber4(p)) return 0;
4242
+ if (!isFiniteNumber5(p)) return 0;
4098
4243
  return Math.max(0, Math.min(100, p));
4099
4244
  };
4100
4245
  var clampNonNeg = (n, fallback) => {
4101
- if (!isFiniteNumber4(n)) return fallback;
4246
+ if (!isFiniteNumber5(n)) return fallback;
4102
4247
  return Math.max(0, Math.floor(n));
4103
4248
  };
4104
4249
  var clampPositive2 = (n, fallback) => {
4105
- if (!isFiniteNumber4(n)) return fallback;
4250
+ if (!isFiniteNumber5(n)) return fallback;
4106
4251
  return Math.max(1, Math.floor(n));
4107
4252
  };
4108
4253
  var safeSgrCode = (code, fallback) => {
4109
- if (!isFiniteNumber4(code)) return fallback;
4254
+ if (!isFiniteNumber5(code)) return fallback;
4110
4255
  return Math.max(0, Math.min(255, Math.floor(code)));
4111
4256
  };
4112
4257
  var truncateVisible = (str, maxWidth, ellipsis = "\u2026") => {
@@ -4144,7 +4289,7 @@ var table = (rows, opts = {}) => {
4144
4289
  const b = TABLE_BORDERS[borderStyle] ?? TABLE_BORDERS.rounded;
4145
4290
  const safePadding = clampNonNeg(padding, 1);
4146
4291
  const pad = " ".repeat(safePadding);
4147
- const safeMaxCol = maxColWidth !== null && isFiniteNumber4(maxColWidth) ? Math.max(1, Math.floor(maxColWidth)) : null;
4292
+ const safeMaxCol = maxColWidth !== null && isFiniteNumber5(maxColWidth) ? Math.max(1, Math.floor(maxColWidth)) : null;
4148
4293
  const validRows = rows.filter((r) => Array.isArray(r));
4149
4294
  if (validRows.length === 0) return "";
4150
4295
  const cols = Math.max(...validRows.map((r) => r.length), 0);
@@ -4237,7 +4382,7 @@ var progressBar = (percent, opts = {}) => {
4237
4382
  let filledStr = safeChar.repeat(filled);
4238
4383
  if (Array.isArray(gradientStops2) && gradientStops2.length >= 1 && filled > 0) {
4239
4384
  filledStr = gradient(filledStr, gradientStops2);
4240
- } else if (color2 !== null && isFiniteNumber4(color2)) {
4385
+ } else if (color2 !== null && isFiniteNumber5(color2)) {
4241
4386
  filledStr = sgr(safeSgrCode(color2, FG.white)) + filledStr + reset();
4242
4387
  }
4243
4388
  const emptyStr = safeEmpty.repeat(empty);
@@ -4273,7 +4418,7 @@ var section = (title, opts = {}) => {
4273
4418
  const safeChar = typeof char === "string" && char.length > 0 ? char : "\u2500";
4274
4419
  const safeColor2 = safeSgrCode(colorCode, FG.cyan);
4275
4420
  const titleLen = visibleLen(safeTitle);
4276
- const requestedWidth = width !== null && isFiniteNumber4(width) ? Math.max(1, Math.floor(width)) : cols;
4421
+ const requestedWidth = width !== null && isFiniteNumber5(width) ? Math.max(1, Math.floor(width)) : cols;
4277
4422
  const w = Math.max(requestedWidth, titleLen + 2);
4278
4423
  const side = Math.floor((w - titleLen - 2) / 2);
4279
4424
  const dividerL = sgr(safeColor2) + safeChar.repeat(Math.max(0, side)) + reset();
@@ -4287,7 +4432,7 @@ var columns = (items, opts = {}) => {
4287
4432
  const safeCols = clampPositive2(numCols, 2);
4288
4433
  const safeGap = clampNonNeg(gap, 2);
4289
4434
  const { cols: termCols } = termSize();
4290
- const totalW = width !== null && isFiniteNumber4(width) ? Math.max(safeCols, Math.floor(width)) : termCols;
4435
+ const totalW = width !== null && isFiniteNumber5(width) ? Math.max(safeCols, Math.floor(width)) : termCols;
4291
4436
  const colW = Math.max(1, Math.floor((totalW - safeGap * (safeCols - 1)) / safeCols));
4292
4437
  const gapStr = " ".repeat(safeGap);
4293
4438
  const rows = [];
@@ -4327,7 +4472,7 @@ var timeline = (events, opts = {}) => {
4327
4472
  const safeColor2 = safeSgrCode(colorCode, FG.cyan);
4328
4473
  const safeDoneColor = safeSgrCode(doneColor, FG.green);
4329
4474
  const safePendingColor = safeSgrCode(pendingColor, FG.brightBlack);
4330
- 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));
4475
+ 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));
4331
4476
  const lines = [];
4332
4477
  events.forEach((ev, i) => {
4333
4478
  const isLast = i === events.length - 1;
@@ -4519,10 +4664,10 @@ var STYLES = {
4519
4664
  heavy: { branch: "\u2523\u2501\u2501 ", last: "\u2517\u2501\u2501 ", vert: "\u2503 ", space: " " },
4520
4665
  ascii: { branch: "+-- ", last: "`-- ", vert: "| ", space: " " }
4521
4666
  };
4522
- var isFiniteNumber5 = (n) => typeof n === "number" && Number.isFinite(n);
4667
+ var isFiniteNumber6 = (n) => typeof n === "number" && Number.isFinite(n);
4523
4668
  var ensureString6 = (v) => typeof v === "string" ? v : String(v ?? "");
4524
4669
  var clampNonNeg2 = (n, fallback) => {
4525
- if (!isFiniteNumber5(n)) return fallback;
4670
+ if (!isFiniteNumber6(n)) return fallback;
4526
4671
  return Math.max(0, Math.floor(n));
4527
4672
  };
4528
4673
  var normalizeNewlines = (s) => s.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
@@ -4594,7 +4739,7 @@ var renderChildren = (children, parentContinuation, lines, indentStr, defaultSty
4594
4739
  if (!Array.isArray(children)) return;
4595
4740
  let visible = children;
4596
4741
  let collapsedCount = 0;
4597
- const safeCollapse = isFiniteNumber5(collapse) ? Math.floor(collapse) : 0;
4742
+ const safeCollapse = isFiniteNumber6(collapse) ? Math.floor(collapse) : 0;
4598
4743
  if (safeCollapse > 0 && safeCollapse < children.length) {
4599
4744
  visible = children.slice(safeCollapse);
4600
4745
  collapsedCount = safeCollapse;
@@ -4664,7 +4809,7 @@ var renderTree = (root, opts = {}) => {
4664
4809
  } = opts;
4665
4810
  const safeStyle = style && STYLES[style] ? style : "normal";
4666
4811
  const safeIndent = clampNonNeg2(indent, 0);
4667
- const safeMaxDepth = isFiniteNumber5(maxDepth) ? Math.max(0, Math.floor(maxDepth)) : Infinity;
4812
+ const safeMaxDepth = isFiniteNumber6(maxDepth) ? Math.max(0, Math.floor(maxDepth)) : Infinity;
4668
4813
  const indentStr = " ".repeat(safeIndent);
4669
4814
  const lines = [];
4670
4815
  const rootLabel = formatNode(root, 0, palette);
@@ -5283,13 +5428,13 @@ var themes = {
5283
5428
  var FULL_BLOCK = "\u2588";
5284
5429
  var UPPER_HALF = "\u2580";
5285
5430
  var LOWER_HALF = "\u2584";
5286
- var isFiniteNumber6 = (n) => typeof n === "number" && Number.isFinite(n);
5431
+ var isFiniteNumber7 = (n) => typeof n === "number" && Number.isFinite(n);
5287
5432
  var clampInt = (n, min, max, fallback) => {
5288
- if (!isFiniteNumber6(n)) return fallback;
5433
+ if (!isFiniteNumber7(n)) return fallback;
5289
5434
  return Math.max(min, Math.min(max, Math.floor(n)));
5290
5435
  };
5291
5436
  var clampByte3 = (n) => {
5292
- if (!isFiniteNumber6(n)) return 0;
5437
+ if (!isFiniteNumber7(n)) return 0;
5293
5438
  return Math.max(0, Math.min(255, Math.round(n)));
5294
5439
  };
5295
5440
  var MAX_DIMENSION = 1e4;
@@ -5594,7 +5739,7 @@ var gradientRect = (opts = {}) => {
5594
5739
  const safeW = clampInt(width, 2, MAX_DIMENSION, 40);
5595
5740
  const safeH = clampInt(height, 2, MAX_DIMENSION, 10);
5596
5741
  let cosA = 1, sinA = 0;
5597
- if (isFiniteNumber6(angle)) {
5742
+ if (isFiniteNumber7(angle)) {
5598
5743
  const rad = angle * Math.PI / 180;
5599
5744
  cosA = Math.cos(rad);
5600
5745
  sinA = Math.sin(rad);
@@ -5604,7 +5749,7 @@ var gradientRect = (opts = {}) => {
5604
5749
  const line = [];
5605
5750
  for (let col = 0; col < safeW; col++) {
5606
5751
  let t;
5607
- if (isFiniteNumber6(angle)) {
5752
+ if (isFiniteNumber7(angle)) {
5608
5753
  const projection = col / (safeW - 1) * cosA + row / (safeH - 1) * sinA;
5609
5754
  t = clamp((projection + 1) / 2, 0, 1);
5610
5755
  } else if (style === "horizontal") t = col / (safeW - 1);
@@ -5661,7 +5806,7 @@ var createCanvas = (width, height, fillColor = null) => {
5661
5806
  if (y > dirtyMaxY) dirtyMaxY = y;
5662
5807
  };
5663
5808
  const setInternal = (x, y, color2) => {
5664
- if (!isFiniteNumber6(x) || !isFiniteNumber6(y)) return;
5809
+ if (!isFiniteNumber7(x) || !isFiniteNumber7(y)) return;
5665
5810
  const ix = Math.floor(x);
5666
5811
  const iy = Math.floor(y);
5667
5812
  if (iy < 0 || iy >= h || ix < 0 || ix >= w) return;
@@ -5676,7 +5821,7 @@ var createCanvas = (width, height, fillColor = null) => {
5676
5821
  },
5677
5822
  set: setInternal,
5678
5823
  get(x, y) {
5679
- if (!isFiniteNumber6(x) || !isFiniteNumber6(y)) return null;
5824
+ if (!isFiniteNumber7(x) || !isFiniteNumber7(y)) return null;
5680
5825
  const ix = Math.floor(x), iy = Math.floor(y);
5681
5826
  return cloneColor(pixels[iy]?.[ix] ?? null);
5682
5827
  },
@@ -5692,7 +5837,7 @@ var createCanvas = (width, height, fillColor = null) => {
5692
5837
  dirtyMaxY = h - 1;
5693
5838
  },
5694
5839
  drawRect(x, y, rw, rh, color2, fill = false) {
5695
- if (!isFiniteNumber6(x) || !isFiniteNumber6(y) || !isFiniteNumber6(rw) || !isFiniteNumber6(rh)) return;
5840
+ if (!isFiniteNumber7(x) || !isFiniteNumber7(y) || !isFiniteNumber7(rw) || !isFiniteNumber7(rh)) return;
5696
5841
  if (rw <= 0 || rh <= 0) return;
5697
5842
  const ix = Math.floor(x);
5698
5843
  const iy = Math.floor(y);
@@ -5714,7 +5859,7 @@ var createCanvas = (width, height, fillColor = null) => {
5714
5859
  }
5715
5860
  },
5716
5861
  drawCircle(cx, cy, radius, color2, fill = false) {
5717
- if (!isFiniteNumber6(cx) || !isFiniteNumber6(cy) || !isFiniteNumber6(radius)) return;
5862
+ if (!isFiniteNumber7(cx) || !isFiniteNumber7(cy) || !isFiniteNumber7(radius)) return;
5718
5863
  if (radius <= 0) return;
5719
5864
  const x0 = Math.max(0, Math.floor(cx - radius - 1));
5720
5865
  const y0 = Math.max(0, Math.floor(cy - radius - 1));
@@ -5737,7 +5882,7 @@ var createCanvas = (width, height, fillColor = null) => {
5737
5882
  }
5738
5883
  },
5739
5884
  drawSprite(x, y, sprite) {
5740
- if (!isFiniteNumber6(x) || !isFiniteNumber6(y)) return;
5885
+ if (!isFiniteNumber7(x) || !isFiniteNumber7(y)) return;
5741
5886
  if (!Array.isArray(sprite)) return;
5742
5887
  const sx = Math.floor(x);
5743
5888
  const sy = Math.floor(y);
@@ -6499,6 +6644,95 @@ var setConfigValue = (key, value) => {
6499
6644
  };
6500
6645
  var subscribeConfig = onConfigChange;
6501
6646
 
6647
+ // src/utils/easing.ts
6648
+ var c1 = 1.70158;
6649
+ var c2 = c1 * 1.525;
6650
+ var c3 = c1 + 1;
6651
+ var c4 = 2 * Math.PI / 3;
6652
+ var c5 = 2 * Math.PI / 4.5;
6653
+ var _bounceOut = (t) => {
6654
+ const n1 = 7.5625;
6655
+ const d1 = 2.75;
6656
+ if (t < 1 / d1) return n1 * t * t;
6657
+ if (t < 2 / d1) {
6658
+ const x2 = t - 1.5 / d1;
6659
+ return n1 * x2 * x2 + 0.75;
6660
+ }
6661
+ if (t < 2.5 / d1) {
6662
+ const x2 = t - 2.25 / d1;
6663
+ return n1 * x2 * x2 + 0.9375;
6664
+ }
6665
+ const x = t - 2.625 / d1;
6666
+ return n1 * x * x + 0.984375;
6667
+ };
6668
+ var easings = {
6669
+ // ── Linear ──
6670
+ linear: (t) => t,
6671
+ // ── Quadratic (t²) ──
6672
+ easeInQuad: (t) => t * t,
6673
+ easeOutQuad: (t) => 1 - (1 - t) * (1 - t),
6674
+ easeInOutQuad: (t) => t < 0.5 ? 2 * t * t : 1 - Math.pow(-2 * t + 2, 2) / 2,
6675
+ // ── Cubic (t³) ──
6676
+ easeInCubic: (t) => t * t * t,
6677
+ easeOutCubic: (t) => 1 - Math.pow(1 - t, 3),
6678
+ easeInOutCubic: (t) => t < 0.5 ? 4 * t * t * t : 1 - Math.pow(-2 * t + 2, 3) / 2,
6679
+ // ── Quartic (t⁴) ──
6680
+ easeInQuart: (t) => t * t * t * t,
6681
+ easeOutQuart: (t) => 1 - Math.pow(1 - t, 4),
6682
+ easeInOutQuart: (t) => t < 0.5 ? 8 * t * t * t * t : 1 - Math.pow(-2 * t + 2, 4) / 2,
6683
+ // ── Quintic (t⁵) ──
6684
+ easeInQuint: (t) => t * t * t * t * t,
6685
+ easeOutQuint: (t) => 1 - Math.pow(1 - t, 5),
6686
+ easeInOutQuint: (t) => t < 0.5 ? 16 * t * t * t * t * t : 1 - Math.pow(-2 * t + 2, 5) / 2,
6687
+ // ── Sinusoidal ──
6688
+ easeInSine: (t) => 1 - Math.cos(t * Math.PI / 2),
6689
+ easeOutSine: (t) => Math.sin(t * Math.PI / 2),
6690
+ easeInOutSine: (t) => -(Math.cos(Math.PI * t) - 1) / 2,
6691
+ // ── Exponential ──
6692
+ easeInExpo: (t) => t === 0 ? 0 : Math.pow(2, 10 * t - 10),
6693
+ easeOutExpo: (t) => t === 1 ? 1 : 1 - Math.pow(2, -10 * t),
6694
+ easeInOutExpo: (t) => {
6695
+ if (t === 0) return 0;
6696
+ if (t === 1) return 1;
6697
+ return t < 0.5 ? Math.pow(2, 20 * t - 10) / 2 : (2 - Math.pow(2, -20 * t + 10)) / 2;
6698
+ },
6699
+ // ── Circular ──
6700
+ easeInCirc: (t) => 1 - Math.sqrt(1 - Math.pow(t, 2)),
6701
+ easeOutCirc: (t) => Math.sqrt(1 - Math.pow(t - 1, 2)),
6702
+ 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,
6703
+ // ── Back (overshoots) ──
6704
+ easeInBack: (t) => c3 * t * t * t - c1 * t * t,
6705
+ easeOutBack: (t) => 1 + c3 * Math.pow(t - 1, 3) + c1 * Math.pow(t - 1, 2),
6706
+ 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,
6707
+ // ── Elastic (oscillates) ──
6708
+ easeInElastic: (t) => {
6709
+ if (t === 0) return 0;
6710
+ if (t === 1) return 1;
6711
+ return -Math.pow(2, 10 * t - 10) * Math.sin((t * 10 - 10.75) * c4);
6712
+ },
6713
+ easeOutElastic: (t) => {
6714
+ if (t === 0) return 0;
6715
+ if (t === 1) return 1;
6716
+ return Math.pow(2, -10 * t) * Math.sin((t * 10 - 0.75) * c4) + 1;
6717
+ },
6718
+ easeInOutElastic: (t) => {
6719
+ if (t === 0) return 0;
6720
+ if (t === 1) return 1;
6721
+ 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;
6722
+ },
6723
+ // ── Bounce (bouncing ball) ──
6724
+ easeInBounce: (t) => 1 - _bounceOut(1 - t),
6725
+ easeOutBounce: _bounceOut,
6726
+ easeInOutBounce: (t) => t < 0.5 ? (1 - _bounceOut(1 - 2 * t)) / 2 : (1 + _bounceOut(2 * t - 1)) / 2
6727
+ };
6728
+ var resolveEasingByName = (e) => {
6729
+ if (typeof e === "function") return e;
6730
+ if (typeof e === "string" && easings[e]) {
6731
+ return easings[e];
6732
+ }
6733
+ return easings.linear;
6734
+ };
6735
+
6502
6736
  // src/index.ts
6503
6737
  var ansimax = { color, animate, ascii, loader, frames, components, trees, themes, images, configure };
6504
6738
  var index_default = ansimax;
@@ -6534,6 +6768,7 @@ var index_default = ansimax;
6534
6768
  chain,
6535
6769
  charWidth,
6536
6770
  clamp,
6771
+ clampByte,
6537
6772
  clearAnsiCache,
6538
6773
  clearColorCache,
6539
6774
  clearLine,
@@ -6553,6 +6788,7 @@ var index_default = ansimax;
6553
6788
  cursor,
6554
6789
  debounce,
6555
6790
  diffLines,
6791
+ easings,
6556
6792
  escapeForRegex,
6557
6793
  escapeRegex,
6558
6794
  fg256,
@@ -6580,9 +6816,11 @@ var index_default = ansimax;
6580
6816
  hasFont,
6581
6817
  hexToRgb,
6582
6818
  hideCursor,
6819
+ hslToRgb,
6583
6820
  hsplit,
6584
6821
  hyperlink,
6585
6822
  images,
6823
+ isFiniteNumber,
6586
6824
  isHexColor,
6587
6825
  isNoColor,
6588
6826
  json,
@@ -6597,7 +6835,9 @@ var index_default = ansimax;
6597
6835
  measureBlock,
6598
6836
  measureTree,
6599
6837
  memoize,
6838
+ mixColors,
6600
6839
  nextTick,
6840
+ oklabToRgb,
6601
6841
  onConfigChange,
6602
6842
  onConfigKeyChange,
6603
6843
  onResize,
@@ -6610,6 +6850,7 @@ var index_default = ansimax;
6610
6850
  pauseListeners,
6611
6851
  presetNames,
6612
6852
  presets,
6853
+ quantizeColor,
6613
6854
  rainbow,
6614
6855
  registerFont,
6615
6856
  registerPreset,
@@ -6625,11 +6866,15 @@ var index_default = ansimax;
6625
6866
  resetFramesCursorCount,
6626
6867
  resetLoaderCursorCount,
6627
6868
  resetNoColor,
6869
+ resolveEasingByName,
6628
6870
  resumeListeners,
6629
6871
  reverseGradient,
6630
6872
  rgbTo256,
6631
6873
  rgbToHex,
6874
+ rgbToHsl,
6875
+ rgbToOklab,
6632
6876
  rotate90,
6877
+ safeInt,
6633
6878
  safeJson,
6634
6879
  screen,
6635
6880
  setConfigValue,