ansimax 1.3.3 → 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/CHANGELOG.md CHANGED
@@ -3,6 +3,285 @@
3
3
  All notable changes to **ansimax** are documented in this file.
4
4
  This project follows [Semantic Versioning](https://semver.org/).
5
5
 
6
+ ## [1.3.5] — Mathematical color science + cleanup
7
+
8
+ Patch release focused on mathematical depth: perceptually-uniform color
9
+ spaces (Oklab/HSL), comprehensive easing library, and removing duplicate
10
+ defensive patterns. **Zero breaking changes** — `lerpColor` and
11
+ `gradientColor` accept a new optional `space` parameter that defaults to
12
+ `'rgb'` (the previous behavior).
13
+
14
+ ### Added — Perceptually-uniform color spaces
15
+
16
+ **Oklab** — modern perceptual color space. Interpolating in Oklab produces
17
+ smoother, more natural-looking gradients than naive RGB:
18
+
19
+ ```js
20
+ import { lerpColor, mixColors, gradientStops } from 'ansimax';
21
+
22
+ const red = { r: 255, g: 0, b: 0 };
23
+ const blue = { r: 0, g: 0, b: 255 };
24
+
25
+ lerpColor(red, blue, 0.5); // → { r: 128, g: 0, b: 128 } (RGB midpoint — muddy)
26
+ lerpColor(red, blue, 0.5, 'oklab'); // → { r: 140, g: 83, b: 162 } (perceptual midpoint — vibrant)
27
+
28
+ // Or with hex inputs:
29
+ mixColors('#ff0000', '#0000ff', 0.5, 'oklab');
30
+
31
+ // Multi-stop gradients:
32
+ gradientStops('#ff0000', '#0000ff', 5, 'oklab');
33
+ ```
34
+
35
+ **HSL** — useful for hue rotation and color manipulation:
36
+
37
+ ```js
38
+ import { rgbToHsl, hslToRgb, lerpColor } from 'ansimax';
39
+
40
+ const hsl = rgbToHsl({ r: 255, g: 100, b: 50 }); // → { h: 12, s: 1, l: 0.598 }
41
+
42
+ // hslToRgb wraps hue automatically:
43
+ hslToRgb({ h: -120, s: 1, l: 0.5 }); // → { r: 0, g: 0, b: 255 }
44
+ hslToRgb({ h: 720, s: 1, l: 0.5 }); // → { r: 255, g: 0, b: 0 }
45
+
46
+ // Interpolation through HSL takes the shorter arc on the color wheel:
47
+ lerpColor(red, blue, 0.5, 'hsl');
48
+ ```
49
+
50
+ ### Added — `easings` library (Robert Penner library)
51
+
52
+ Comprehensive easing curve library:
53
+
54
+ ```js
55
+ import { easings, resolveEasingByName, animate } from 'ansimax';
56
+
57
+ // All curves: in/out/inOut variants of:
58
+ // quad, cubic, quart, quint, sine, expo, circ, back, elastic, bounce
59
+ // Plus linear.
60
+
61
+ await animate.countUp(0, 1000, {
62
+ duration: 2000,
63
+ easing: easings.easeOutBounce, // bouncing ball deceleration
64
+ });
65
+
66
+ // Resolve by name:
67
+ const fn = resolveEasingByName('easeInElastic');
68
+ ```
69
+
70
+ ### Added — Color utilities
71
+
72
+ **`mixColors(a, b, t, space?)`** — semantic alias accepting hex or RGB:
73
+
74
+ ```js
75
+ mixColors('#ff0000', { r: 0, g: 0, b: 255 }, 0.5, 'oklab');
76
+ ```
77
+
78
+ **`quantizeColor(color, levels)`** — palette reduction (posterize effect):
79
+
80
+ ```js
81
+ quantizeColor({ r: 100, g: 150, b: 200 }, 4);
82
+ // Snaps each channel to nearest of [0, 85, 170, 255] → 64-color palette
83
+ ```
84
+
85
+ ### Added — Numeric helpers
86
+
87
+ **`isFiniteNumber(n)`** — type guard, previously internal:
88
+
89
+ ```js
90
+ isFiniteNumber(42); // → true
91
+ isFiniteNumber(NaN); // → false
92
+ isFiniteNumber('5'); // → false
93
+ ```
94
+
95
+ **`safeInt(value, fallback?, min?, max?)`** — consolidates the
96
+ `Math.max(0, Math.floor(Number(x) || 0))` pattern that appeared 25+
97
+ times across the codebase:
98
+
99
+ ```js
100
+ safeInt('abc') // → 0
101
+ safeInt(3.7) // → 3
102
+ safeInt(NaN, 50) // → 50 (fallback)
103
+ safeInt(500, 0, 0, 100) // → 100 (clamped to max)
104
+ ```
105
+
106
+ **`clampByte(v)`** — previously private, now exported.
107
+
108
+ ### Improved — `gradientStops` accepts `space` parameter
109
+
110
+ ```js
111
+ gradientStops('#ff0000', '#0000ff', 5); // RGB (default, fast)
112
+ gradientStops('#ff0000', '#0000ff', 5, 'oklab'); // perceptually uniform
113
+ ```
114
+
115
+ ### Improved — Code cleanliness
116
+
117
+ - Replaced internal duplicate `typeof n === 'number' && Number.isFinite(n)`
118
+ checks with `isFiniteNumber()` calls
119
+ - `gradientColor` now uses `isFiniteNumber` instead of inline check
120
+
121
+ ### Improved — Tests
122
+
123
+ - `+18` tests for color spaces (rgbToHsl, hslToRgb, rgbToOklab, oklabToRgb)
124
+ - `+9` tests for `lerpColor` with spaces + `mixColors`
125
+ - `+6` tests for `quantizeColor`
126
+ - `+10` tests for numeric helpers (`isFiniteNumber`, `safeInt`, `clampByte`)
127
+ - `+30` tests for `easings` library (every curve + endpoint preservation)
128
+ - `+5` tests for `resolveEasingByName`
129
+ - `+4` tests for v1.3.5 barrel re-exports
130
+
131
+ Total: **+82 tests** added.
132
+
133
+ ### Notes
134
+
135
+ - No runtime dependencies — still zero
136
+ - **No breaking changes** — `lerpColor(a, b, t)` defaults to `'rgb'` and
137
+ produces identical output to v1.3.4
138
+ - Oklab math validated via roundtrip identity tests (±1 byte tolerance
139
+ for floating-point through linear sRGB intermediate)
140
+ - All easing curves verified to map `f(0) ≈ 0` and `f(1) ≈ 1`
141
+
142
+ ---
143
+
144
+ ## [1.3.4] — Feature additions across animations, configure, utils
145
+
146
+ Patch release adding small but useful features to several modules. No
147
+ breaking changes — every addition is opt-in.
148
+
149
+ ### Added — `animations` module
150
+
151
+ **`animate.shake(text, opts)`** — horizontal tremble effect for errors or alerts:
152
+
153
+ ```js
154
+ import { animate } from 'ansimax';
155
+
156
+ await animate.shake('Connection failed', {
157
+ times: 5,
158
+ intensity: 2,
159
+ interval: 50,
160
+ });
161
+ ```
162
+
163
+ **`animate.countUp(from, to, opts)`** — numeric animation for counters:
164
+
165
+ ```js
166
+ await animate.countUp(0, 100, {
167
+ duration: 1500,
168
+ decimals: 0,
169
+ format: (n) => `$${n.toLocaleString()}`,
170
+ easing: (t) => 1 - (1 - t) ** 3, // ease-out cubic
171
+ });
172
+ // Animates from "$0" → "$100" over 1.5 seconds
173
+ ```
174
+
175
+ Both functions support the standard animation pattern: `signal`, `reducedMotion`,
176
+ `onFrame`, `onDone`, `onAbort`.
177
+
178
+ ### Added — `configure` module
179
+
180
+ **`setConfigValue(key, value)`** — single-key shortcut:
181
+
182
+ ```js
183
+ import { setConfigValue } from 'ansimax';
184
+
185
+ setConfigValue('theme', 'dracula');
186
+ setConfigValue('animationSpeed', 'fast');
187
+ // equivalent to: configure({ theme: 'dracula' })
188
+ ```
189
+
190
+ **`subscribeConfig(listener)`** — alias for `onConfigChange` matching the
191
+ naming convention used by `themes.onChange`:
192
+
193
+ ```js
194
+ import { subscribeConfig } from 'ansimax';
195
+
196
+ const unsubscribe = subscribeConfig((newCfg, oldCfg) => {
197
+ console.log('Config changed:', newCfg);
198
+ });
199
+ ```
200
+
201
+ ### Added — `utils/ansi` module
202
+
203
+ **`hyperlink(url, label?)`** — OSC 8 escape sequence for clickable terminal links:
204
+
205
+ ```js
206
+ import { hyperlink } from 'ansimax';
207
+
208
+ console.log(`Visit ${hyperlink('https://github.com/Brashkie/ansimax', 'the repo')}`);
209
+ console.log(`Email: ${hyperlink('mailto:hi@example.com')}`);
210
+ ```
211
+
212
+ Supported terminals: VS Code, iTerm2, WezTerm, Kitty, Hyper, Alacritty, modern
213
+ Windows Terminal. Terminals without support just show the label text.
214
+
215
+ **`clearLine()`** — convenience for clearing current line + carriage return:
216
+
217
+ ```js
218
+ import { clearLine } from 'ansimax';
219
+
220
+ for (let i = 0; i <= 100; i++) {
221
+ process.stdout.write(clearLine() + `Progress: ${i}%`);
222
+ await sleep(30);
223
+ }
224
+ ```
225
+
226
+ ### Added — `utils/helpers` module
227
+
228
+ **`gradientStops(start, end, count)`** — interpolate N hex stops between two colors:
229
+
230
+ ```js
231
+ import { gradientStops } from 'ansimax';
232
+
233
+ const stops = gradientStops('#ff0000', '#0000ff', 5);
234
+ // → ['#ff0000', '#bf003f', '#7f007f', '#3f00bf', '#0000ff']
235
+ ```
236
+
237
+ **`escapeForRegex(str)`** — escape regex meta-characters in user input:
238
+
239
+ ```js
240
+ import { escapeForRegex } from 'ansimax';
241
+
242
+ const userInput = 'hello.world+code';
243
+ const re = new RegExp(escapeForRegex(userInput));
244
+ // Matches the literal string, not as a regex pattern
245
+ ```
246
+
247
+ **`measureBlock(block)`** — get dimensions of a multi-line string (ANSI-aware):
248
+
249
+ ```js
250
+ import { measureBlock, ascii } from 'ansimax';
251
+
252
+ const box = ascii.box('Hello world!');
253
+ const { width, height } = measureBlock(box);
254
+ // → { width: 15, height: 3 }
255
+ ```
256
+
257
+ ### Improved — `node-globals.d.ts`
258
+
259
+ Added ambient declarations for `AsyncIterator`, `AsyncIterable`, `AsyncGenerator`,
260
+ and `Symbol.asyncIterator`. Lets code using `for await...of` type-check without
261
+ needing `@types/node` installed at consumer projects.
262
+
263
+ ### Improved — Tests
264
+
265
+ - `+6` tests for `gradientStops`
266
+ - `+5` tests for `escapeForRegex`
267
+ - `+7` tests for `measureBlock`
268
+ - `+5` tests for `hyperlink`
269
+ - `+2` tests for `clearLine`
270
+ - `+4` tests for `setConfigValue`
271
+ - `+3` tests for `subscribeConfig`
272
+ - `+5` tests for `animate.shake`
273
+ - `+8` tests for `animate.countUp`
274
+
275
+ Total: **+45 tests** across utils, ansi, configure, animations.
276
+
277
+ ### Notes
278
+
279
+ - No runtime dependencies — still zero
280
+ - No breaking changes — drop-in replacement for `1.3.3`
281
+ - All new exports backward-compatible by default
282
+
283
+ ---
284
+
6
285
  ## [1.3.3] — Feature additions to panels, json, ascii
7
286
 
8
287
  Patch release adding new functionality to three modules. No breaking changes —
package/README.es.md CHANGED
@@ -7,7 +7,7 @@
7
7
  _Colores • Gradientes • Animaciones • ASCII Art • Pixel Art • Árboles • Componentes • Temas_
8
8
 
9
9
  [![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg?style=flat-square)](LICENSE)
10
- [![npm](https://img.shields.io/badge/npm-v1.3.3-cb3837.svg?style=flat-square)](https://www.npmjs.com/package/ansimax)
10
+ [![npm](https://img.shields.io/badge/npm-v1.3.5-cb3837.svg?style=flat-square)](https://www.npmjs.com/package/ansimax)
11
11
  [![TypeScript](https://img.shields.io/badge/TypeScript-strict-3178c6.svg?style=flat-square)](tsconfig.json)
12
12
  [![Coverage](https://img.shields.io/badge/coverage-98%25-brightgreen.svg?style=flat-square)](#testing)
13
13
  [![Tests](https://img.shields.io/badge/tests-2000%2B%20passing-brightgreen.svg?style=flat-square)](#testing)
@@ -478,7 +478,7 @@ console.log(components.table([
478
478
  ['loaders', color.green('● listo'), '100%'],
479
479
  ], { borderStyle: 'rounded' }));
480
480
 
481
- console.log(components.badge('VERSION', 'v1.3.3'));
481
+ console.log(components.badge('VERSION', 'v1.3.5'));
482
482
  console.log(components.badge('BUILD', 'passing'));
483
483
  ```
484
484
 
@@ -1065,6 +1065,64 @@ ansimax/
1065
1065
 
1066
1066
  ## 📝 Changelog
1067
1067
 
1068
+ ### v1.3.5 — Color science matemático + limpieza
1069
+
1070
+ Release patch enfocado en profundidad matemática y limpieza de código. Cero breaking changes:
1071
+
1072
+ - 🎨 **Espacio de color Oklab** — `rgbToOklab` / `oklabToRgb`. Gradientes perceptualmente uniformes
1073
+ - 🌈 **Espacio de color HSL** — `rgbToHsl` / `hslToRgb`. Rotación de matiz, manipulación de color
1074
+ - 🎯 **`lerpColor` / `gradientColor` / `gradientStops`** ahora aceptan `space: 'rgb' | 'hsl' | 'oklab'` (default `'rgb'`, retro-compatible)
1075
+ - 🥄 **`mixColors(a, b, t, space)`** — alias semántico, acepta hex strings o RGB
1076
+ - 📐 **`quantizeColor(color, levels)`** — reducción de paleta (efecto posterize)
1077
+ - ⚡ **Librería `easings`** — set completo de Robert Penner (quad/cubic/quart/quint/sine/expo/circ/back/elastic/bounce en in/out/inOut)
1078
+ - 🧮 **`isFiniteNumber` + `safeInt` + `clampByte`** — helpers numéricos exportados (consolida 25+ patrones defensivos duplicados)
1079
+ - 🧪 **+82 tests** incluyendo validación de correctitud matemática
1080
+
1081
+ ```js
1082
+ import { lerpColor, easings, animate, mixColors } from 'ansimax';
1083
+
1084
+ // Midpoint de gradiente perceptualmente uniforme
1085
+ mixColors('#ff0000', '#0000ff', 0.5, 'oklab');
1086
+ // → { r: 140, g: 83, b: 162 } — magenta vibrante
1087
+ // (vs RGB naive: { r: 128, g: 0, b: 128 } — púrpura turbio)
1088
+
1089
+ // Contador con animación bouncing
1090
+ await animate.countUp(0, 1000, {
1091
+ duration: 2000,
1092
+ easing: easings.easeOutBounce,
1093
+ });
1094
+ ```
1095
+
1096
+ Drop-in replacement para `1.3.4`.
1097
+
1098
+ ### v1.3.4 — Features para animations, configure, utils
1099
+
1100
+ Release patch con features opt-in en varios módulos. Cero breaking changes:
1101
+
1102
+ - 🎬 **`animate.shake(text, opts)`** — efecto tremor horizontal para errores
1103
+ - 🔢 **`animate.countUp(from, to, opts)`** — contadores numéricos animados con format/easing
1104
+ - ⚙️ **`setConfigValue(key, value)`** — atajo single-key + alias `subscribeConfig`
1105
+ - 🔗 **`hyperlink(url, label)`** — links clickables vía OSC 8 (VS Code, iTerm2, WezTerm, Kitty...)
1106
+ - 🧹 **`clearLine()`** — helper conveniente para render loops
1107
+ - 🎨 **`gradientStops(start, end, count)`** — N stops procedurales entre dos colores
1108
+ - 🛡️ **`escapeForRegex(str)`** — escapa input de usuario para regex literals
1109
+ - 📏 **`measureBlock(block)`** — dimensiones ANSI-aware de texto multi-línea
1110
+ - 📐 **`node-globals.d.ts`** — añadidos tipos `AsyncIterator`/`AsyncIterable`/`AsyncGenerator`
1111
+ - 🧪 **+45 tests** entre animations, configure, utils
1112
+
1113
+ ```js
1114
+ import { animate, hyperlink } from 'ansimax';
1115
+
1116
+ await animate.countUp(0, 1000, {
1117
+ duration: 1500,
1118
+ format: (n) => `$${n.toLocaleString()}`,
1119
+ });
1120
+
1121
+ console.log(`Ver ${hyperlink('https://npmjs.com/ansimax', 'la página de npm')}`);
1122
+ ```
1123
+
1124
+ Drop-in replacement para `1.3.3`.
1125
+
1068
1126
  ### v1.3.3 — Features para panels, json, ascii
1069
1127
 
1070
1128
  Release patch con nuevas features opt-in. Cero breaking changes:
@@ -1458,4 +1516,4 @@ Ansimax está licenciada bajo **Apache License, Version 2.0** — una licencia p
1458
1516
 
1459
1517
  Si Ansimax te ayuda a hacer mejores CLIs, ¡dale ⭐ en [GitHub](https://github.com/Brashkie/ansimax)!
1460
1518
 
1461
- </div>
1519
+ </div>
package/README.md CHANGED
@@ -7,7 +7,7 @@
7
7
  _Colors • Gradients • Animations • ASCII Art • Pixel Art • Trees • Components • Themes_
8
8
 
9
9
  [![License](https://img.shields.io/badge/license-Apache%202.0-blue.svg?style=flat-square)](LICENSE)
10
- [![npm](https://img.shields.io/badge/npm-v1.3.3-cb3837.svg?style=flat-square)](https://www.npmjs.com/package/ansimax)
10
+ [![npm](https://img.shields.io/badge/npm-v1.3.5-cb3837.svg?style=flat-square)](https://www.npmjs.com/package/ansimax)
11
11
  [![TypeScript](https://img.shields.io/badge/TypeScript-strict-3178c6.svg?style=flat-square)](tsconfig.json)
12
12
  [![Coverage](https://img.shields.io/badge/coverage-98%25-brightgreen.svg?style=flat-square)](#testing)
13
13
  [![Tests](https://img.shields.io/badge/tests-2000%2B%20passing-brightgreen.svg?style=flat-square)](#testing)
@@ -478,7 +478,7 @@ console.log(components.table([
478
478
  ['loaders', color.green('● ready'), '100%'],
479
479
  ], { borderStyle: 'rounded' }));
480
480
 
481
- console.log(components.badge('VERSION', 'v1.3.3'));
481
+ console.log(components.badge('VERSION', 'v1.3.5'));
482
482
  console.log(components.badge('BUILD', 'passing'));
483
483
  ```
484
484
 
@@ -1065,6 +1065,64 @@ ansimax/
1065
1065
 
1066
1066
  ## 📝 Changelog
1067
1067
 
1068
+ ### v1.3.5 — Mathematical color science + cleanup
1069
+
1070
+ Patch release focused on math depth and code cleanliness. Zero breaking changes:
1071
+
1072
+ - 🎨 **Oklab color space** — `rgbToOklab` / `oklabToRgb`. Perceptually uniform gradients
1073
+ - 🌈 **HSL color space** — `rgbToHsl` / `hslToRgb`. Hue rotation, color manipulation
1074
+ - 🎯 **`lerpColor` / `gradientColor` / `gradientStops`** all accept `space: 'rgb' | 'hsl' | 'oklab'` (default `'rgb'`, retro-compatible)
1075
+ - 🥄 **`mixColors(a, b, t, space)`** — semantic alias, accepts hex strings or RGB
1076
+ - 📐 **`quantizeColor(color, levels)`** — palette reduction (posterize effect)
1077
+ - ⚡ **`easings` library** — full Robert Penner set (quad/cubic/quart/quint/sine/expo/circ/back/elastic/bounce in/out/inOut)
1078
+ - 🧮 **`isFiniteNumber` + `safeInt` + `clampByte`** — exported numeric helpers (consolidates 25+ duplicate defensive patterns)
1079
+ - 🧪 **+82 tests** including math correctness validation
1080
+
1081
+ ```js
1082
+ import { lerpColor, easings, animate, mixColors } from 'ansimax';
1083
+
1084
+ // Perceptually-uniform gradient midpoint
1085
+ mixColors('#ff0000', '#0000ff', 0.5, 'oklab');
1086
+ // → { r: 140, g: 83, b: 162 } — vibrant magenta
1087
+ // (vs naive RGB: { r: 128, g: 0, b: 128 } — muddy purple)
1088
+
1089
+ // Bouncing counter animation
1090
+ await animate.countUp(0, 1000, {
1091
+ duration: 2000,
1092
+ easing: easings.easeOutBounce,
1093
+ });
1094
+ ```
1095
+
1096
+ Drop-in replacement for `1.3.4`.
1097
+
1098
+ ### v1.3.4 — Feature additions across animations, configure, utils
1099
+
1100
+ Patch release with opt-in additions to several modules. Zero breaking changes:
1101
+
1102
+ - 🎬 **`animate.shake(text, opts)`** — horizontal tremble effect for error feedback
1103
+ - 🔢 **`animate.countUp(from, to, opts)`** — animated numeric counters with format/easing
1104
+ - ⚙️ **`setConfigValue(key, value)`** — single-key config shortcut + `subscribeConfig` alias
1105
+ - 🔗 **`hyperlink(url, label)`** — OSC 8 clickable terminal links (VS Code, iTerm2, WezTerm, Kitty...)
1106
+ - 🧹 **`clearLine()`** — convenience helper for render loops
1107
+ - 🎨 **`gradientStops(start, end, count)`** — procedural N-color stops
1108
+ - 🛡️ **`escapeForRegex(str)`** — escape user input for regex literals
1109
+ - 📏 **`measureBlock(block)`** — get ANSI-aware dimensions of multi-line text
1110
+ - 📐 **`node-globals.d.ts`** — added `AsyncIterator`/`AsyncIterable`/`AsyncGenerator` ambient types
1111
+ - 🧪 **+45 tests** across animations, configure, utils
1112
+
1113
+ ```js
1114
+ import { animate, hyperlink } from 'ansimax';
1115
+
1116
+ await animate.countUp(0, 1000, {
1117
+ duration: 1500,
1118
+ format: (n) => `$${n.toLocaleString()}`,
1119
+ });
1120
+
1121
+ console.log(`See ${hyperlink('https://npmjs.com/ansimax', 'the npm page')}`);
1122
+ ```
1123
+
1124
+ Drop-in replacement for `1.3.3`.
1125
+
1068
1126
  ### v1.3.3 — Features for panels, json, ascii
1069
1127
 
1070
1128
  Patch release with new opt-in features. Zero breaking changes:
@@ -1458,4 +1516,4 @@ Ansimax is licensed under the **Apache License, Version 2.0** — a permissive l
1458
1516
 
1459
1517
  If Ansimax helps you ship better CLIs, give it a ⭐ on [GitHub](https://github.com/Brashkie/ansimax)!
1460
1518
 
1461
- </div>
1519
+ </div>