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.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) {
@@ -3704,11 +3848,11 @@ var loader = {
3704
3848
  };
3705
3849
 
3706
3850
  // src/frames/index.ts
3707
- var isFiniteNumber3 = (n) => typeof n === "number" && Number.isFinite(n);
3851
+ var isFiniteNumber4 = (n) => typeof n === "number" && Number.isFinite(n);
3708
3852
  var ensureString4 = (v) => typeof v === "string" ? v : String(v ?? "");
3709
3853
  var MAX_FPS = 60;
3710
3854
  var clampFps = (fps, fallback) => {
3711
- if (!isFiniteNumber3(fps)) return fallback;
3855
+ if (!isFiniteNumber4(fps)) return fallback;
3712
3856
  return Math.max(1, Math.min(MAX_FPS, Math.floor(fps)));
3713
3857
  };
3714
3858
  var _cursorHiddenCount2 = 0;
@@ -3807,14 +3951,14 @@ var play = (frames2, opts = {}) => {
3807
3951
  if (fps !== void 0) {
3808
3952
  const safeFps = clampFps(fps, 60);
3809
3953
  tickMs = Math.max(FRAME_MS, Math.floor(1e3 / safeFps));
3810
- } else if (isFiniteNumber3(interval)) {
3954
+ } else if (isFiniteNumber4(interval)) {
3811
3955
  tickMs = Math.max(FRAME_MS, Math.floor(interval));
3812
3956
  } else {
3813
3957
  tickMs = 100;
3814
3958
  }
3815
3959
  let safeRepeat;
3816
3960
  let infinite;
3817
- if (!isFiniteNumber3(repeat)) {
3961
+ if (!isFiniteNumber4(repeat)) {
3818
3962
  safeRepeat = 1;
3819
3963
  infinite = false;
3820
3964
  } else if (repeat === 0) {
@@ -3939,7 +4083,7 @@ var play = (frames2, opts = {}) => {
3939
4083
  paused = false;
3940
4084
  },
3941
4085
  seek: (idx) => {
3942
- if (!isFiniteNumber3(idx)) return;
4086
+ if (!isFiniteNumber4(idx)) return;
3943
4087
  const safe = Math.max(0, Math.floor(idx));
3944
4088
  frameIdx = frames2.length > 0 ? safe % frames2.length : 0;
3945
4089
  },
@@ -3952,7 +4096,7 @@ var play = (frames2, opts = {}) => {
3952
4096
  };
3953
4097
  };
3954
4098
  var generate = (count, fn) => {
3955
- const safeCount = isFiniteNumber3(count) ? Math.max(0, Math.floor(count)) : 0;
4099
+ const safeCount = isFiniteNumber4(count) ? Math.max(0, Math.floor(count)) : 0;
3956
4100
  if (typeof fn !== "function") return Array(safeCount).fill("");
3957
4101
  return Array.from({ length: safeCount }, (_, i) => {
3958
4102
  try {
@@ -4024,7 +4168,7 @@ var morph = (frameA, frameB, steps = 8, charset = "\u2591\u2592\u2593\u2588\u259
4024
4168
  const a0 = ensureString4(frameA);
4025
4169
  const b0 = ensureString4(frameB);
4026
4170
  if (!a0 && !b0) return [""];
4027
- const n = Math.max(2, isFiniteNumber3(steps) ? Math.floor(steps) : 8);
4171
+ const n = Math.max(2, isFiniteNumber4(steps) ? Math.floor(steps) : 8);
4028
4172
  const len = Math.max(a0.length, b0.length);
4029
4173
  const a = a0.padEnd(len);
4030
4174
  const b = b0.padEnd(len);
@@ -4046,7 +4190,7 @@ var morph = (frameA, frameB, steps = 8, charset = "\u2591\u2592\u2593\u2588\u259
4046
4190
  var presets2 = {
4047
4191
  loadingBar: (opts = {}) => {
4048
4192
  const { width = 20, char = "\u2588", empty = "\u2591", label = "Loading" } = opts;
4049
- const safeWidth = Math.max(0, isFiniteNumber3(width) ? Math.floor(width) : 20);
4193
+ const safeWidth = Math.max(0, isFiniteNumber4(width) ? Math.floor(width) : 20);
4050
4194
  const safeChar = typeof char === "string" && char.length > 0 ? char : "\u2588";
4051
4195
  const safeEmpty = typeof empty === "string" && empty.length > 0 ? empty : "\u2591";
4052
4196
  const safeLabel = ensureString4(label);
@@ -4060,7 +4204,7 @@ var presets2 = {
4060
4204
  /* istanbul ignore next — default opts {} */
4061
4205
  ball: (opts = {}) => {
4062
4206
  const { width = 20, char = "\u25CF" } = opts;
4063
- const safeWidth = Math.max(1, isFiniteNumber3(width) ? Math.floor(width) : 20);
4207
+ const safeWidth = Math.max(1, isFiniteNumber4(width) ? Math.floor(width) : 20);
4064
4208
  const safeChar = typeof char === "string" && char.length > 0 ? char : "\u25CF";
4065
4209
  const forward = generate(safeWidth, (i) => " ".repeat(i) + safeChar);
4066
4210
  const backward = generate(safeWidth, (i) => " ".repeat(safeWidth - i - 1) + safeChar);
@@ -4070,7 +4214,7 @@ var presets2 = {
4070
4214
  breathe: (text, opts = {}) => {
4071
4215
  const { steps = 8 } = opts;
4072
4216
  const safeText = ensureString4(text);
4073
- const safeSteps2 = Math.max(1, isFiniteNumber3(steps) ? Math.floor(steps) : 8);
4217
+ const safeSteps2 = Math.max(1, isFiniteNumber4(steps) ? Math.floor(steps) : 8);
4074
4218
  const shades = ["\u2591", "\u2592", "\u2593", "\u2588"];
4075
4219
  return generate(safeSteps2 * 2, (i) => {
4076
4220
  const t = i < safeSteps2 ? i / safeSteps2 : 1 - (i - safeSteps2) / safeSteps2;
@@ -4091,22 +4235,22 @@ var presets2 = {
4091
4235
  var frames = { play, generate, live, morph, presets: presets2 };
4092
4236
 
4093
4237
  // src/components/index.ts
4094
- var isFiniteNumber4 = (n) => typeof n === "number" && Number.isFinite(n);
4238
+ var isFiniteNumber5 = (n) => typeof n === "number" && Number.isFinite(n);
4095
4239
  var ensureString5 = (v) => typeof v === "string" ? v : String(v ?? "");
4096
4240
  var clampPercent2 = (p) => {
4097
- if (!isFiniteNumber4(p)) return 0;
4241
+ if (!isFiniteNumber5(p)) return 0;
4098
4242
  return Math.max(0, Math.min(100, p));
4099
4243
  };
4100
4244
  var clampNonNeg = (n, fallback) => {
4101
- if (!isFiniteNumber4(n)) return fallback;
4245
+ if (!isFiniteNumber5(n)) return fallback;
4102
4246
  return Math.max(0, Math.floor(n));
4103
4247
  };
4104
4248
  var clampPositive2 = (n, fallback) => {
4105
- if (!isFiniteNumber4(n)) return fallback;
4249
+ if (!isFiniteNumber5(n)) return fallback;
4106
4250
  return Math.max(1, Math.floor(n));
4107
4251
  };
4108
4252
  var safeSgrCode = (code, fallback) => {
4109
- if (!isFiniteNumber4(code)) return fallback;
4253
+ if (!isFiniteNumber5(code)) return fallback;
4110
4254
  return Math.max(0, Math.min(255, Math.floor(code)));
4111
4255
  };
4112
4256
  var truncateVisible = (str, maxWidth, ellipsis = "\u2026") => {
@@ -4144,7 +4288,7 @@ var table = (rows, opts = {}) => {
4144
4288
  const b = TABLE_BORDERS[borderStyle] ?? TABLE_BORDERS.rounded;
4145
4289
  const safePadding = clampNonNeg(padding, 1);
4146
4290
  const pad = " ".repeat(safePadding);
4147
- const safeMaxCol = maxColWidth !== null && isFiniteNumber4(maxColWidth) ? Math.max(1, Math.floor(maxColWidth)) : null;
4291
+ const safeMaxCol = maxColWidth !== null && isFiniteNumber5(maxColWidth) ? Math.max(1, Math.floor(maxColWidth)) : null;
4148
4292
  const validRows = rows.filter((r) => Array.isArray(r));
4149
4293
  if (validRows.length === 0) return "";
4150
4294
  const cols = Math.max(...validRows.map((r) => r.length), 0);
@@ -4237,7 +4381,7 @@ var progressBar = (percent, opts = {}) => {
4237
4381
  let filledStr = safeChar.repeat(filled);
4238
4382
  if (Array.isArray(gradientStops2) && gradientStops2.length >= 1 && filled > 0) {
4239
4383
  filledStr = gradient(filledStr, gradientStops2);
4240
- } else if (color2 !== null && isFiniteNumber4(color2)) {
4384
+ } else if (color2 !== null && isFiniteNumber5(color2)) {
4241
4385
  filledStr = sgr(safeSgrCode(color2, FG.white)) + filledStr + reset();
4242
4386
  }
4243
4387
  const emptyStr = safeEmpty.repeat(empty);
@@ -4273,7 +4417,7 @@ var section = (title, opts = {}) => {
4273
4417
  const safeChar = typeof char === "string" && char.length > 0 ? char : "\u2500";
4274
4418
  const safeColor2 = safeSgrCode(colorCode, FG.cyan);
4275
4419
  const titleLen = visibleLen(safeTitle);
4276
- const requestedWidth = width !== null && isFiniteNumber4(width) ? Math.max(1, Math.floor(width)) : cols;
4420
+ const requestedWidth = width !== null && isFiniteNumber5(width) ? Math.max(1, Math.floor(width)) : cols;
4277
4421
  const w = Math.max(requestedWidth, titleLen + 2);
4278
4422
  const side = Math.floor((w - titleLen - 2) / 2);
4279
4423
  const dividerL = sgr(safeColor2) + safeChar.repeat(Math.max(0, side)) + reset();
@@ -4287,7 +4431,7 @@ var columns = (items, opts = {}) => {
4287
4431
  const safeCols = clampPositive2(numCols, 2);
4288
4432
  const safeGap = clampNonNeg(gap, 2);
4289
4433
  const { cols: termCols } = termSize();
4290
- const totalW = width !== null && isFiniteNumber4(width) ? Math.max(safeCols, Math.floor(width)) : termCols;
4434
+ const totalW = width !== null && isFiniteNumber5(width) ? Math.max(safeCols, Math.floor(width)) : termCols;
4291
4435
  const colW = Math.max(1, Math.floor((totalW - safeGap * (safeCols - 1)) / safeCols));
4292
4436
  const gapStr = " ".repeat(safeGap);
4293
4437
  const rows = [];
@@ -4327,7 +4471,7 @@ var timeline = (events, opts = {}) => {
4327
4471
  const safeColor2 = safeSgrCode(colorCode, FG.cyan);
4328
4472
  const safeDoneColor = safeSgrCode(doneColor, FG.green);
4329
4473
  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));
4474
+ 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
4475
  const lines = [];
4332
4476
  events.forEach((ev, i) => {
4333
4477
  const isLast = i === events.length - 1;
@@ -4519,10 +4663,10 @@ var STYLES = {
4519
4663
  heavy: { branch: "\u2523\u2501\u2501 ", last: "\u2517\u2501\u2501 ", vert: "\u2503 ", space: " " },
4520
4664
  ascii: { branch: "+-- ", last: "`-- ", vert: "| ", space: " " }
4521
4665
  };
4522
- var isFiniteNumber5 = (n) => typeof n === "number" && Number.isFinite(n);
4666
+ var isFiniteNumber6 = (n) => typeof n === "number" && Number.isFinite(n);
4523
4667
  var ensureString6 = (v) => typeof v === "string" ? v : String(v ?? "");
4524
4668
  var clampNonNeg2 = (n, fallback) => {
4525
- if (!isFiniteNumber5(n)) return fallback;
4669
+ if (!isFiniteNumber6(n)) return fallback;
4526
4670
  return Math.max(0, Math.floor(n));
4527
4671
  };
4528
4672
  var normalizeNewlines = (s) => s.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
@@ -4594,7 +4738,7 @@ var renderChildren = (children, parentContinuation, lines, indentStr, defaultSty
4594
4738
  if (!Array.isArray(children)) return;
4595
4739
  let visible = children;
4596
4740
  let collapsedCount = 0;
4597
- const safeCollapse = isFiniteNumber5(collapse) ? Math.floor(collapse) : 0;
4741
+ const safeCollapse = isFiniteNumber6(collapse) ? Math.floor(collapse) : 0;
4598
4742
  if (safeCollapse > 0 && safeCollapse < children.length) {
4599
4743
  visible = children.slice(safeCollapse);
4600
4744
  collapsedCount = safeCollapse;
@@ -4664,7 +4808,7 @@ var renderTree = (root, opts = {}) => {
4664
4808
  } = opts;
4665
4809
  const safeStyle = style && STYLES[style] ? style : "normal";
4666
4810
  const safeIndent = clampNonNeg2(indent, 0);
4667
- const safeMaxDepth = isFiniteNumber5(maxDepth) ? Math.max(0, Math.floor(maxDepth)) : Infinity;
4811
+ const safeMaxDepth = isFiniteNumber6(maxDepth) ? Math.max(0, Math.floor(maxDepth)) : Infinity;
4668
4812
  const indentStr = " ".repeat(safeIndent);
4669
4813
  const lines = [];
4670
4814
  const rootLabel = formatNode(root, 0, palette);
@@ -5283,13 +5427,13 @@ var themes = {
5283
5427
  var FULL_BLOCK = "\u2588";
5284
5428
  var UPPER_HALF = "\u2580";
5285
5429
  var LOWER_HALF = "\u2584";
5286
- var isFiniteNumber6 = (n) => typeof n === "number" && Number.isFinite(n);
5430
+ var isFiniteNumber7 = (n) => typeof n === "number" && Number.isFinite(n);
5287
5431
  var clampInt = (n, min, max, fallback) => {
5288
- if (!isFiniteNumber6(n)) return fallback;
5432
+ if (!isFiniteNumber7(n)) return fallback;
5289
5433
  return Math.max(min, Math.min(max, Math.floor(n)));
5290
5434
  };
5291
5435
  var clampByte3 = (n) => {
5292
- if (!isFiniteNumber6(n)) return 0;
5436
+ if (!isFiniteNumber7(n)) return 0;
5293
5437
  return Math.max(0, Math.min(255, Math.round(n)));
5294
5438
  };
5295
5439
  var MAX_DIMENSION = 1e4;
@@ -5594,7 +5738,7 @@ var gradientRect = (opts = {}) => {
5594
5738
  const safeW = clampInt(width, 2, MAX_DIMENSION, 40);
5595
5739
  const safeH = clampInt(height, 2, MAX_DIMENSION, 10);
5596
5740
  let cosA = 1, sinA = 0;
5597
- if (isFiniteNumber6(angle)) {
5741
+ if (isFiniteNumber7(angle)) {
5598
5742
  const rad = angle * Math.PI / 180;
5599
5743
  cosA = Math.cos(rad);
5600
5744
  sinA = Math.sin(rad);
@@ -5604,7 +5748,7 @@ var gradientRect = (opts = {}) => {
5604
5748
  const line = [];
5605
5749
  for (let col = 0; col < safeW; col++) {
5606
5750
  let t;
5607
- if (isFiniteNumber6(angle)) {
5751
+ if (isFiniteNumber7(angle)) {
5608
5752
  const projection = col / (safeW - 1) * cosA + row / (safeH - 1) * sinA;
5609
5753
  t = clamp((projection + 1) / 2, 0, 1);
5610
5754
  } else if (style === "horizontal") t = col / (safeW - 1);
@@ -5661,7 +5805,7 @@ var createCanvas = (width, height, fillColor = null) => {
5661
5805
  if (y > dirtyMaxY) dirtyMaxY = y;
5662
5806
  };
5663
5807
  const setInternal = (x, y, color2) => {
5664
- if (!isFiniteNumber6(x) || !isFiniteNumber6(y)) return;
5808
+ if (!isFiniteNumber7(x) || !isFiniteNumber7(y)) return;
5665
5809
  const ix = Math.floor(x);
5666
5810
  const iy = Math.floor(y);
5667
5811
  if (iy < 0 || iy >= h || ix < 0 || ix >= w) return;
@@ -5676,7 +5820,7 @@ var createCanvas = (width, height, fillColor = null) => {
5676
5820
  },
5677
5821
  set: setInternal,
5678
5822
  get(x, y) {
5679
- if (!isFiniteNumber6(x) || !isFiniteNumber6(y)) return null;
5823
+ if (!isFiniteNumber7(x) || !isFiniteNumber7(y)) return null;
5680
5824
  const ix = Math.floor(x), iy = Math.floor(y);
5681
5825
  return cloneColor(pixels[iy]?.[ix] ?? null);
5682
5826
  },
@@ -5692,7 +5836,7 @@ var createCanvas = (width, height, fillColor = null) => {
5692
5836
  dirtyMaxY = h - 1;
5693
5837
  },
5694
5838
  drawRect(x, y, rw, rh, color2, fill = false) {
5695
- if (!isFiniteNumber6(x) || !isFiniteNumber6(y) || !isFiniteNumber6(rw) || !isFiniteNumber6(rh)) return;
5839
+ if (!isFiniteNumber7(x) || !isFiniteNumber7(y) || !isFiniteNumber7(rw) || !isFiniteNumber7(rh)) return;
5696
5840
  if (rw <= 0 || rh <= 0) return;
5697
5841
  const ix = Math.floor(x);
5698
5842
  const iy = Math.floor(y);
@@ -5714,7 +5858,7 @@ var createCanvas = (width, height, fillColor = null) => {
5714
5858
  }
5715
5859
  },
5716
5860
  drawCircle(cx, cy, radius, color2, fill = false) {
5717
- if (!isFiniteNumber6(cx) || !isFiniteNumber6(cy) || !isFiniteNumber6(radius)) return;
5861
+ if (!isFiniteNumber7(cx) || !isFiniteNumber7(cy) || !isFiniteNumber7(radius)) return;
5718
5862
  if (radius <= 0) return;
5719
5863
  const x0 = Math.max(0, Math.floor(cx - radius - 1));
5720
5864
  const y0 = Math.max(0, Math.floor(cy - radius - 1));
@@ -5737,7 +5881,7 @@ var createCanvas = (width, height, fillColor = null) => {
5737
5881
  }
5738
5882
  },
5739
5883
  drawSprite(x, y, sprite) {
5740
- if (!isFiniteNumber6(x) || !isFiniteNumber6(y)) return;
5884
+ if (!isFiniteNumber7(x) || !isFiniteNumber7(y)) return;
5741
5885
  if (!Array.isArray(sprite)) return;
5742
5886
  const sx = Math.floor(x);
5743
5887
  const sy = Math.floor(y);
@@ -6499,6 +6643,95 @@ var setConfigValue = (key, value) => {
6499
6643
  };
6500
6644
  var subscribeConfig = onConfigChange;
6501
6645
 
6646
+ // src/utils/easing.ts
6647
+ var c1 = 1.70158;
6648
+ var c2 = c1 * 1.525;
6649
+ var c3 = c1 + 1;
6650
+ var c4 = 2 * Math.PI / 3;
6651
+ var c5 = 2 * Math.PI / 4.5;
6652
+ var _bounceOut = (t) => {
6653
+ const n1 = 7.5625;
6654
+ const d1 = 2.75;
6655
+ if (t < 1 / d1) return n1 * t * t;
6656
+ if (t < 2 / d1) {
6657
+ const x2 = t - 1.5 / d1;
6658
+ return n1 * x2 * x2 + 0.75;
6659
+ }
6660
+ if (t < 2.5 / d1) {
6661
+ const x2 = t - 2.25 / d1;
6662
+ return n1 * x2 * x2 + 0.9375;
6663
+ }
6664
+ const x = t - 2.625 / d1;
6665
+ return n1 * x * x + 0.984375;
6666
+ };
6667
+ var easings = {
6668
+ // ── Linear ──
6669
+ linear: (t) => t,
6670
+ // ── Quadratic (t²) ──
6671
+ easeInQuad: (t) => t * t,
6672
+ easeOutQuad: (t) => 1 - (1 - t) * (1 - t),
6673
+ easeInOutQuad: (t) => t < 0.5 ? 2 * t * t : 1 - Math.pow(-2 * t + 2, 2) / 2,
6674
+ // ── Cubic (t³) ──
6675
+ easeInCubic: (t) => t * t * t,
6676
+ easeOutCubic: (t) => 1 - Math.pow(1 - t, 3),
6677
+ easeInOutCubic: (t) => t < 0.5 ? 4 * t * t * t : 1 - Math.pow(-2 * t + 2, 3) / 2,
6678
+ // ── Quartic (t⁴) ──
6679
+ easeInQuart: (t) => t * t * t * t,
6680
+ easeOutQuart: (t) => 1 - Math.pow(1 - t, 4),
6681
+ easeInOutQuart: (t) => t < 0.5 ? 8 * t * t * t * t : 1 - Math.pow(-2 * t + 2, 4) / 2,
6682
+ // ── Quintic (t⁵) ──
6683
+ easeInQuint: (t) => t * t * t * t * t,
6684
+ easeOutQuint: (t) => 1 - Math.pow(1 - t, 5),
6685
+ easeInOutQuint: (t) => t < 0.5 ? 16 * t * t * t * t * t : 1 - Math.pow(-2 * t + 2, 5) / 2,
6686
+ // ── Sinusoidal ──
6687
+ easeInSine: (t) => 1 - Math.cos(t * Math.PI / 2),
6688
+ easeOutSine: (t) => Math.sin(t * Math.PI / 2),
6689
+ easeInOutSine: (t) => -(Math.cos(Math.PI * t) - 1) / 2,
6690
+ // ── Exponential ──
6691
+ easeInExpo: (t) => t === 0 ? 0 : Math.pow(2, 10 * t - 10),
6692
+ easeOutExpo: (t) => t === 1 ? 1 : 1 - Math.pow(2, -10 * t),
6693
+ easeInOutExpo: (t) => {
6694
+ if (t === 0) return 0;
6695
+ if (t === 1) return 1;
6696
+ return t < 0.5 ? Math.pow(2, 20 * t - 10) / 2 : (2 - Math.pow(2, -20 * t + 10)) / 2;
6697
+ },
6698
+ // ── Circular ──
6699
+ easeInCirc: (t) => 1 - Math.sqrt(1 - Math.pow(t, 2)),
6700
+ easeOutCirc: (t) => Math.sqrt(1 - Math.pow(t - 1, 2)),
6701
+ 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,
6702
+ // ── Back (overshoots) ──
6703
+ easeInBack: (t) => c3 * t * t * t - c1 * t * t,
6704
+ easeOutBack: (t) => 1 + c3 * Math.pow(t - 1, 3) + c1 * Math.pow(t - 1, 2),
6705
+ 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,
6706
+ // ── Elastic (oscillates) ──
6707
+ easeInElastic: (t) => {
6708
+ if (t === 0) return 0;
6709
+ if (t === 1) return 1;
6710
+ return -Math.pow(2, 10 * t - 10) * Math.sin((t * 10 - 10.75) * c4);
6711
+ },
6712
+ easeOutElastic: (t) => {
6713
+ if (t === 0) return 0;
6714
+ if (t === 1) return 1;
6715
+ return Math.pow(2, -10 * t) * Math.sin((t * 10 - 0.75) * c4) + 1;
6716
+ },
6717
+ easeInOutElastic: (t) => {
6718
+ if (t === 0) return 0;
6719
+ if (t === 1) return 1;
6720
+ 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;
6721
+ },
6722
+ // ── Bounce (bouncing ball) ──
6723
+ easeInBounce: (t) => 1 - _bounceOut(1 - t),
6724
+ easeOutBounce: _bounceOut,
6725
+ easeInOutBounce: (t) => t < 0.5 ? (1 - _bounceOut(1 - 2 * t)) / 2 : (1 + _bounceOut(2 * t - 1)) / 2
6726
+ };
6727
+ var resolveEasingByName = (e) => {
6728
+ if (typeof e === "function") return e;
6729
+ if (typeof e === "string" && easings[e]) {
6730
+ return easings[e];
6731
+ }
6732
+ return easings.linear;
6733
+ };
6734
+
6502
6735
  // src/index.ts
6503
6736
  var ansimax = { color, animate, ascii, loader, frames, components, trees, themes, images, configure };
6504
6737
  var index_default = ansimax;
@@ -6534,6 +6767,7 @@ var index_default = ansimax;
6534
6767
  chain,
6535
6768
  charWidth,
6536
6769
  clamp,
6770
+ clampByte,
6537
6771
  clearAnsiCache,
6538
6772
  clearColorCache,
6539
6773
  clearLine,
@@ -6553,6 +6787,7 @@ var index_default = ansimax;
6553
6787
  cursor,
6554
6788
  debounce,
6555
6789
  diffLines,
6790
+ easings,
6556
6791
  escapeForRegex,
6557
6792
  escapeRegex,
6558
6793
  fg256,
@@ -6580,9 +6815,11 @@ var index_default = ansimax;
6580
6815
  hasFont,
6581
6816
  hexToRgb,
6582
6817
  hideCursor,
6818
+ hslToRgb,
6583
6819
  hsplit,
6584
6820
  hyperlink,
6585
6821
  images,
6822
+ isFiniteNumber,
6586
6823
  isHexColor,
6587
6824
  isNoColor,
6588
6825
  json,
@@ -6597,7 +6834,9 @@ var index_default = ansimax;
6597
6834
  measureBlock,
6598
6835
  measureTree,
6599
6836
  memoize,
6837
+ mixColors,
6600
6838
  nextTick,
6839
+ oklabToRgb,
6601
6840
  onConfigChange,
6602
6841
  onConfigKeyChange,
6603
6842
  onResize,
@@ -6610,6 +6849,7 @@ var index_default = ansimax;
6610
6849
  pauseListeners,
6611
6850
  presetNames,
6612
6851
  presets,
6852
+ quantizeColor,
6613
6853
  rainbow,
6614
6854
  registerFont,
6615
6855
  registerPreset,
@@ -6625,11 +6865,15 @@ var index_default = ansimax;
6625
6865
  resetFramesCursorCount,
6626
6866
  resetLoaderCursorCount,
6627
6867
  resetNoColor,
6868
+ resolveEasingByName,
6628
6869
  resumeListeners,
6629
6870
  reverseGradient,
6630
6871
  rgbTo256,
6631
6872
  rgbToHex,
6873
+ rgbToHsl,
6874
+ rgbToOklab,
6632
6875
  rotate90,
6876
+ safeInt,
6633
6877
  safeJson,
6634
6878
  screen,
6635
6879
  setConfigValue,