ansimax 1.2.8 → 1.3.1

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,239 @@
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.1] — Polish for panels + json
7
+
8
+ Patch release improving the two modules introduced in v1.3.0 — adds layout
9
+ helpers, JSON readability options, and tests. No breaking changes.
10
+
11
+ ### Added — `panels.center(block, opts)`
12
+
13
+ Center a multi-line block horizontally (and optionally vertically) within
14
+ a fixed width/height. Useful for centering boxes, banners, or any pre-rendered
15
+ block in a known terminal width.
16
+
17
+ ```js
18
+ import { panels, ascii } from 'ansimax';
19
+
20
+ // Horizontal centering only
21
+ console.log(panels.center('Hello!', { width: 30 }));
22
+ // " Hello! "
23
+
24
+ // Vertical too — content fits in 5 rows
25
+ console.log(panels.center('X', { width: 5, height: 5, align: 'center' }));
26
+
27
+ // Combine with box for a centered card
28
+ console.log(panels.center(ascii.box('Hello'), { width: 80 }));
29
+ ```
30
+
31
+ Exported as `centerBlock` from the main barrel (to avoid colliding with the
32
+ existing `center` text helper). The namespaced form `panels.center` works
33
+ identically.
34
+
35
+ ### Added — `panels.frame(block, opts)`
36
+
37
+ Lighter alternative to `ascii.box`: draws only top/bottom decorative rules
38
+ (not full sides). Supports a centered title, padding, and custom characters.
39
+
40
+ ```js
41
+ import { panels } from 'ansimax';
42
+
43
+ // Simple rules
44
+ console.log(panels.frame('Hello world!'));
45
+ // ─────────────
46
+ // Hello world!
47
+ // ─────────────
48
+
49
+ // With title + padding
50
+ console.log(panels.frame('Body content\nMore content', {
51
+ title: 'Header',
52
+ padding: 1,
53
+ }));
54
+ // ───── Header ─────
55
+ //
56
+ // Body content
57
+ // More content
58
+ //
59
+ // ──────────────────
60
+
61
+ // Custom decoration chars
62
+ console.log(panels.frame('Important!', {
63
+ topChar: '═',
64
+ padding: 2,
65
+ }));
66
+ ```
67
+
68
+ ### Added — `json.pretty` option `sortKeys`
69
+
70
+ Sort object keys alphabetically for deterministic output. Useful for diffs,
71
+ snapshots, and visual scanning of large objects.
72
+
73
+ ```js
74
+ import { json } from 'ansimax';
75
+
76
+ console.log(json.pretty({ zebra: 1, apple: 2, mango: 3 }, { sortKeys: true }));
77
+ // {
78
+ // "apple": 2,
79
+ // "mango": 3,
80
+ // "zebra": 1
81
+ // }
82
+ ```
83
+
84
+ Recursive — applies to all nested objects. Default `false` (preserves
85
+ insertion order).
86
+
87
+ ### Added — `json.pretty` option `inlineArrayMaxLength`
88
+
89
+ Arrays of primitives now render on a single line when their rendered length
90
+ is short enough (default threshold: 60 visible characters). This improves
91
+ readability significantly for typical configs:
92
+
93
+ ```js
94
+ // Before v1.3.1:
95
+ {
96
+ "tags": [
97
+ "frontend",
98
+ "react",
99
+ "typescript"
100
+ ]
101
+ }
102
+
103
+ // In v1.3.1 (default behavior):
104
+ {
105
+ "tags": ["frontend", "react", "typescript"]
106
+ }
107
+ ```
108
+
109
+ Arrays containing objects/arrays never inline regardless of length. Set
110
+ `inlineArrayMaxLength: 0` to restore the v1.3.0 always-expand behavior.
111
+
112
+ ### Improved — Tests
113
+
114
+ - `+11` tests for `panels.center` + `panels.frame`
115
+ - `+15` tests for `json.pretty` `sortKeys` + `inlineArrayMaxLength`
116
+ - Total tests: 2,000+ → **~2,026** across 18 suites
117
+
118
+ ### Notes
119
+
120
+ - No runtime dependencies — still zero
121
+ - No breaking changes — drop-in replacement for `1.3.0`
122
+ - `panels.center` is exposed as `centerBlock` at the top level to avoid
123
+ conflict with the existing `center` text helper; both `panels.center` and
124
+ `centerBlock` reference the same function
125
+
126
+ ---
127
+
128
+ ## [1.3.0] — Phase 4 progress: Panels + JSON pretty-print
129
+
130
+ Minor release adding **split layout primitives** and **JSON pretty-printing**.
131
+ Two new top-level modules, zero breaking changes — every 1.2.x program runs
132
+ identically.
133
+
134
+ ### Added — `panels` module (split layouts)
135
+
136
+ Two composition primitives for combining already-rendered blocks:
137
+
138
+ - **`panels.vsplit(blocks, opts)`** — joins blocks side-by-side (columns).
139
+ ANSI-aware width measurement, variable height handling, alignment, gap,
140
+ fixed-width mode.
141
+
142
+ - **`panels.hsplit(blocks, opts)`** — stacks blocks vertically (rows).
143
+ Width alignment, vertical gap.
144
+
145
+ ```js
146
+ import { panels, ascii } from 'ansimax';
147
+
148
+ // Two columns side-by-side
149
+ console.log(panels.vsplit([
150
+ ascii.box('Left side', { borderStyle: 'rounded' }),
151
+ ascii.box('Right side', { borderStyle: 'rounded' }),
152
+ ], { gap: 2 }));
153
+
154
+ // Three rows stacked vertically
155
+ console.log(panels.hsplit([
156
+ '── Header ──',
157
+ ascii.box('Body content'),
158
+ '── Footer ──',
159
+ ], { align: 'center' }));
160
+
161
+ // Nested — sidebar + main in an app shell
162
+ const sidebar = ascii.box('Sidebar', { width: 20 });
163
+ const main = ascii.box('Main', { width: 40 });
164
+
165
+ console.log(panels.hsplit([
166
+ '── Application ──',
167
+ panels.vsplit([sidebar, main], { gap: 2 }),
168
+ ]));
169
+ ```
170
+
171
+ **Both functions:**
172
+ - Preserve ANSI escapes from input blocks
173
+ - Handle multi-line blocks of variable height
174
+ - Coerce invalid inputs (`gap: -5` → `0`, empty arrays → `''`)
175
+ - Compose freely with each other (panels-in-panels)
176
+
177
+ Three alignment modes (`'start'` / `'center'` / `'end'`) for both axes.
178
+
179
+ ### Added — `json` module (pretty-printer)
180
+
181
+ Color-coded JSON pretty-printer for terminal display:
182
+
183
+ ```js
184
+ import { json } from 'ansimax';
185
+
186
+ // Basic — colored output
187
+ console.log(json.pretty({
188
+ name: 'ansimax',
189
+ version: '1.3.0',
190
+ features: ['colors', 'gradients', 'panels'],
191
+ stats: { tests: 2000, coverage: 0.98 },
192
+ }));
193
+
194
+ // With depth limit — deep nesting collapses to {...}
195
+ console.log(json.pretty(deeplyNested, { maxDepth: 2 }));
196
+
197
+ // Limit array display — huge arrays show "... (N more)"
198
+ console.log(json.pretty(bigArray, { maxItems: 10 }));
199
+
200
+ // Monochrome for log files
201
+ console.log(json.pretty(data, { colors: false }));
202
+
203
+ // Handles circular refs gracefully
204
+ const obj = { name: 'foo' };
205
+ obj.self = obj;
206
+ console.log(json.pretty(obj)); // → { "name": "foo", "self": [Circular] }
207
+ ```
208
+
209
+ **Features:**
210
+ - Color-coded by type: cyan (keys), green (strings), yellow (numbers), magenta (booleans), gray (null/undefined)
211
+ - Circular reference detection
212
+ - Depth limit with `{...}` / `[...]` collapse markers
213
+ - Array length limit with `... (N more)` marker
214
+ - String length limit with `...` truncation
215
+ - BigInt, function, symbol rendering
216
+ - ANSI auto-disabled in `NO_COLOR` / non-TTY environments
217
+ - Configurable indent (default `2`)
218
+
219
+ ### Roadmap impact — Phase 4 progress
220
+
221
+ Phase 4 (Terminal UI primitives) advances from 8/15 → **10/15**:
222
+
223
+ - [x] Panels (split layouts: hsplit, vsplit) ← **v1.3.0**
224
+ - [x] JSON/YAML pretty-printing (with depth limit + collapse) ← **v1.3.0**
225
+
226
+ Still pending in Phase 4: Layouts (flexbox-style), Grid system, Markdown
227
+ rendering, Syntax highlighting, Logging integration. These come in later
228
+ 1.3.x / 1.4.x releases.
229
+
230
+ ### Notes
231
+
232
+ - 2 new test files: `panels.test.ts` (~25 tests), `json.test.ts` (~30 tests)
233
+ - No runtime dependencies — still zero
234
+ - No breaking API changes — pure additions
235
+ - Drop-in replacement for `1.2.8`
236
+
237
+ ---
238
+
6
239
  ## [1.2.8] — Documentation polish
7
240
 
8
241
  Patch release improving JSDoc and IntelliSense coverage across previously
package/README.es.md CHANGED
@@ -7,12 +7,13 @@
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.2.8-cb3837.svg?style=flat-square)](https://www.npmjs.com/package/ansimax)
10
+ [![npm](https://img.shields.io/badge/npm-v1.3.1-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
- [![Tests](https://img.shields.io/badge/tests-1900%2B%20passing-brightgreen.svg?style=flat-square)](#testing)
13
+ [![Tests](https://img.shields.io/badge/tests-2000%2B%20passing-brightgreen.svg?style=flat-square)](#testing)
14
14
  [![Zero deps](https://img.shields.io/badge/dependencies-0-brightgreen.svg?style=flat-square)](#)
15
- [![Bundle](https://img.shields.io/badge/bundle-%3C100kb-brightgreen.svg?style=flat-square)](#)
15
+ [![Node](https://img.shields.io/badge/Node-%3E%3D18-43853d.svg?style=flat-square)](#requirements)
16
+ [![ESM%20%2B%20CJS](https://img.shields.io/badge/ESM%20%2B%20CJS-dual-blueviolet.svg?style=flat-square)](#)
16
17
 
17
18
  [English](README.md) · **Español**
18
19
 
@@ -79,30 +80,40 @@ stop('Build completado', true);
79
80
 
80
81
  ## 🆚 Comparación con el ecosistema Node.js
81
82
 
82
- Ansimax reemplaza un stack de dependencias de librerías populares de Node.js con un solo paquete coherente y tipado:
83
+ Ansimax reemplaza un stack de librerías populares de Node.js con **un solo paquete coherente, tipado y de cero dependencias**:
83
84
 
84
85
  | Característica | chalk | gradient-string | ora | cli-progress | figlet | boxen | inquirer | cli-table3 | **Ansimax** |
85
86
  |---|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
86
87
  | Colores básicos + 256 | ✅ | — | — | — | — | — | — | — | ✅ |
87
88
  | Truecolor con fallback adaptativo | ✅ | ✅ | — | — | — | — | — | — | ✅ |
88
89
  | Gradientes multi-stop | — | ✅ | — | — | — | — | — | — | ✅ |
89
- | **Gradientes animados** | — | — | — | — | — | — | — | — | 🔜 |
90
+ | **Gradientes animados** | — | — | — | — | — | — | — | — | |
91
+ | **Curvas de easing (5 presets + custom)** | — | — | — | — | — | — | — | — | ✅ |
92
+ | **Gradientes cónicos (barrido radial)** | — | — | — | — | — | — | — | — | ✅ |
90
93
  | Banners ASCII | — | — | — | — | ✅ | — | — | — | ✅ |
94
+ | **Conversor Imagen → ASCII** | — | — | — | — | — | — | — | — | ✅ |
95
+ | **Parser figlet `.flf`** | — | — | — | — | ✅ (propio) | — | — | — | ✅ (250+ fuentes) |
91
96
  | Registro de fuentes personalizadas | — | — | — | — | parcial | — | — | — | ✅ |
92
- | Cajas con múltiples estilos | — | — | — | — | — | ✅ | — | — | ✅ |
97
+ | Cajas con múltiples estilos | — | — | — | — | — | ✅ | — | — | ✅ (6 estilos) |
93
98
  | Spinners (varios estilos) | — | — | ✅ | — | — | — | — | — | ✅ (11 estilos) |
94
99
  | Barras de progreso animadas | — | — | — | ✅ | — | — | — | — | ✅ |
95
100
  | **Tareas jerárquicas/paralelas** | — | — | — | — | — | — | — | — | ✅ |
96
101
  | Tablas (multi-línea, conscientes de ANSI) | — | — | — | — | — | — | — | ✅ | ✅ |
97
102
  | Menús interactivos + multi-select | — | — | — | — | — | — | ✅ | — | ✅ |
98
103
  | **Árboles con detección de ciclos** | — | — | — | — | — | — | — | — | ✅ |
104
+ | **Layouts divididos (vsplit/hsplit)** | — | — | — | — | — | — | — | — | ✅ (v1.3.0) |
105
+ | **Pretty-printer JSON coloreado** | — | — | — | — | — | — | — | — | ✅ (v1.3.0) |
99
106
  | **Pixel art + canvas + sprites** | — | — | — | — | — | — | — | — | ✅ |
100
107
  | **Sistema de temas + aislamiento por instancia** | — | — | — | — | — | — | — | — | ✅ |
101
108
  | `AbortSignal` en todas partes | — | — | parcial | — | — | — | parcial | — | ✅ |
102
- | Soporte de `NO_COLOR` | ✅ | parcial | parcial | — | — | — | — | — | ✅ |
103
- | TypeScript-first | parcial | parcial | | parcial | parcial | | parcial | parcial | ✅ |
104
- | Cero dependencias en runtime | | | | | | | | | ✅ |
105
- | **Tamaño total de instalación** | pequeño | pequeño | medio | medio | medio | pequeño | grande | medio | **< 100 KB** |
109
+ | Soporte `NO_COLOR` | ✅ | parcial | parcial | — | — | — | — | — | ✅ |
110
+ | Códigos de error estables (`ANSIMAX_*`) | | | | | | | | | ✅ |
111
+ | TypeScript-first (strict mode) | parcial | parcial | | parcial | parcial | | parcial | parcial | ✅ |
112
+ | **Cero dependencias en runtime** | | | | | | | | | |
113
+ | Export dual ESM + CJS | parcial | parcial | ✅ | ✅ | parcial | ✅ | parcial | parcial | ✅ |
114
+ | **Cobertura de tests** | ~95% | parcial | parcial | parcial | parcial | parcial | parcial | parcial | **~98% (2000+ tests)** |
115
+
116
+ > La comparación refleja lo que cada librería soporta oficialmente al momento de escribir esto. Algunas librerías pueden combinarse para acercarse al conjunto de features de ansimax, pero al costo de tamaño de bundle, bugs de version-skew, y APIs inconsistentes.
106
117
 
107
118
  ---
108
119
 
@@ -225,7 +236,7 @@ await animateGradient('¡Listo!', ['#50fa7b', '#bd93f9'], {
225
236
 
226
237
  ### Curvas de interpolación (v1.2.0)
227
238
 
228
- <img src="media/easing_curves.png" alt="Colors and gradients" />
239
+ <img src="media/easing_curves.png" alt="Vista previa de curvas de easing" />
229
240
 
230
241
  ```js
231
242
  import { gradient } from 'ansimax';
@@ -245,7 +256,7 @@ console.log(gradient('hola mundo', stops, { easing: (t) => t * t * t }));
245
256
 
246
257
  ### Gradientes cónicos (v1.2.0)
247
258
 
248
- <img src="media/conic_gradients.png" alt="Colors and gradients" />
259
+ <img src="media/conic_gradients.png" alt="Vista previa de gradientes cónicos" />
249
260
 
250
261
  ```js
251
262
  import { gradientRect } from 'ansimax';
@@ -434,7 +445,7 @@ console.log(components.table([
434
445
  ['loaders', color.green('● listo'), '100%'],
435
446
  ], { borderStyle: 'rounded' }));
436
447
 
437
- console.log(components.badge('VERSION', 'v1.2.8'));
448
+ console.log(components.badge('VERSION', 'v1.3.1'));
438
449
  console.log(components.badge('BUILD', 'passing'));
439
450
  ```
440
451
 
@@ -544,6 +555,61 @@ console.log('tenantB incluye custom?', tenantB.list().includes('custom'));
544
555
  // ↑ false — aislamiento total
545
556
  ```
546
557
 
558
+ ### Panels — Layouts divididos (v1.3.0)
559
+
560
+ ```js
561
+ import { panels, ascii } from 'ansimax';
562
+
563
+ // Columnas lado a lado
564
+ const left = ascii.box('Sidebar', { borderStyle: 'rounded' });
565
+ const right = ascii.box('Vista principal', { borderStyle: 'rounded' });
566
+
567
+ console.log(panels.vsplit([left, right], { gap: 2, align: 'center' }));
568
+
569
+ // Apilado vertical
570
+ console.log(panels.hsplit([
571
+ '── Aplicación ──',
572
+ ascii.box('Contenido'),
573
+ '── Pie ──',
574
+ ], { gap: 1, align: 'center' }));
575
+
576
+ // Anidado — sidebar + main dentro de un shell de aplicación
577
+ console.log(panels.hsplit([
578
+ '── Mi App ──',
579
+ panels.vsplit([
580
+ ascii.box('Sidebar', { width: 20 }),
581
+ ascii.box('Main', { width: 40 }),
582
+ ], { gap: 2 }),
583
+ '── Fin ──',
584
+ ]));
585
+ ```
586
+
587
+ ### JSON Pretty-print (v1.3.0)
588
+
589
+ ```js
590
+ import { json } from 'ansimax';
591
+
592
+ // Pretty-print coloreado y consciente de profundidad
593
+ console.log(json.pretty({
594
+ name: 'ansimax',
595
+ version: '1.3.0',
596
+ features: ['colors', 'gradients', 'panels'],
597
+ stats: { tests: 2000, coverage: 0.98 },
598
+ active: true,
599
+ }));
600
+
601
+ // Límite de profundidad — colapsa objetos profundos a {...}
602
+ console.log(json.pretty(deeplyNested, { maxDepth: 2 }));
603
+
604
+ // Límite de items — arrays grandes muestran "... (N more)"
605
+ console.log(json.pretty(largeArray, { maxItems: 10 }));
606
+
607
+ // Referencias circulares manejadas con gracia
608
+ const obj = { name: 'foo' };
609
+ obj.self = obj;
610
+ console.log(json.pretty(obj)); // → "self": [Circular]
611
+ ```
612
+
547
613
  ---
548
614
 
549
615
  ## 📚 Ejemplos
@@ -655,6 +721,68 @@ try {
655
721
 
656
722
  ---
657
723
 
724
+ ## 🧩 Paquetes del ecosistema
725
+
726
+ El **ecosistema ansimax** se estructura en dos niveles — paquetes companion que extienden el core, y evoluciones independientes que apuntan a diferentes plataformas.
727
+
728
+ ### `@ansimax/*` — Paquetes companion
729
+
730
+ Paquetes con scope que extienden `ansimax` sin romper su promesa de cero dependencias. Cada uno se publica de forma independiente pero comparte la filosofía y nombrado de ansimax.
731
+
732
+ | Paquete | Estado | Descripción |
733
+ |---|:-:|---|
734
+ | `ansimax` | ✅ estable | Core de renderizado terminal. Cero dependencias. |
735
+ | `@ansimax/image` | 🟡 planeado | Cargador imagen-a-ASCII — PNG/JPEG/WebP desde archivo/buffer/URL |
736
+ | `@ansimax/cli` | 🟡 planeado | Binario standalone — `npx @ansimax/cli demo`, explorador de fuentes, conversor de imágenes |
737
+ | `@ansimax/fonts` | 🟡 planeado | 250+ fuentes figlet `.flf` pre-empacadas, listas para usar |
738
+ | `@ansimax/sprites` | 🔴 futuro | Librería curada de sprites (animales, iconos UI, diagramas técnicos) |
739
+ | `@ansimax/video` | 🔴 futuro | Extracción de frames de video → reproducción ASCII |
740
+ | `@ansimax/themes-extra` | 🔴 futuro | Pack de themes contribuidos por la comunidad |
741
+
742
+ **Cómo se conectan:**
743
+
744
+ ```
745
+ ┌─────────────────────────────┐
746
+ │ ansimax (cero deps) │ ← core, siempre lo instalas
747
+ │ • colors, ASCII, panels │
748
+ │ • types: PixelGrid, etc. │
749
+ └────────────┬────────────────┘
750
+ │ peer dependency
751
+ ┌────────────────────┼────────────────────┐
752
+ ▼ ▼ ▼
753
+ @ansimax/image @ansimax/cli @ansimax/fonts
754
+ (deps: jimp) (binario) (solo datos)
755
+ ```
756
+
757
+ Cada companion declara `"ansimax": "^X.Y.Z"` como `peerDependency` — coordinado por semver, nunca duplicado, nunca desincronizado.
758
+
759
+ ### `ansimax-*` — Evoluciones independientes
760
+
761
+ Proyectos standalone que se construyen **al lado de** ansimax para diferentes plataformas. No son companions — son identidades separadas con su propio scope y ciclo de release.
762
+
763
+ | Paquete | Estado | Descripción |
764
+ |---|:-:|---|
765
+ | `ansimax-native` | 🔴 futuro | **Reescritura Rust + TS** del hot path de renderizado. Performance nativa via napi-rs. Misma superficie de API que `ansimax`. |
766
+ | `ansimax-web` | 🔴 futuro | **Capa de renderizado para browser**. Conversión ANSI → HTML/CSS + renderizado a canvas. Para demos, sitios de docs, terminales web. |
767
+
768
+ **Sub-ecosistemas**: cada uno de estos puede tener sus propios sub-paquetes con scope (`@ansimax-native/image`, `@ansimax-web/canvas`, etc.) con el tiempo.
769
+
770
+ ### ¿Por qué dos convenciones de nombrado?
771
+
772
+ Convención de la industria usada por muchos ecosistemas maduros (Babel, Vue, Webpack, etc.):
773
+
774
+ - **`@scope/*`** = "misma familia del proyecto, release coordinado, mismo equipo"
775
+ - **`name-*`** = "inspirado en / trabaja junto con, identidad independiente"
776
+
777
+ Al usar ambos, ansimax señala:
778
+ - El **core** (`ansimax`) se mantiene pequeño, cero-deps, enfocado en renderizado terminal
779
+ - El **ecosistema** (`@ansimax/*`) crece a su alrededor como extensiones opt-in
780
+ - Las **evoluciones** (`ansimax-native`, `ansimax-web`) exploran diferentes plataformas sin comprometer el core
781
+
782
+ > 💡 **Próximamente**: cuando se publiquen `@ansimax/image` o paquetes similares, esta sección incluirá enlaces. ¿Quieres que uno de estos se construya antes? [Abre un issue](https://github.com/Brashkie/ansimax/issues) para votar.
783
+
784
+ ---
785
+
658
786
  ## 🛣️ Roadmap
659
787
 
660
788
  Ansimax se está construyendo hacia una **plataforma completa de renderizado de terminal** — una respuesta nativa de Node a lo que los desarrolladores de Python obtienen de `rich` + `textual` combinados, con mejoras específicas de Node donde importa.
@@ -706,12 +834,12 @@ El roadmap apunta intencionalmente — y busca superar — gaps que ni siquiera
706
834
  - [x] Layout de columnas (overflow truncate/wrap)
707
835
  - [x] Secciones (cabeceras con gradiente, ancho automático)
708
836
  - [x] Árboles (colapsables, max-depth, cycle-safe)
709
- - [ ] **Panels** (split layouts: hsplit, vsplit)
837
+ - [x] **Panels** split layouts: `hsplit`, `vsplit` con alineación + anidamiento (v1.3.0)
838
+ - [x] **Pretty-printing JSON/YAML** — coloreado, depth-limit, cycle-safe (v1.3.0)
710
839
  - [ ] **Layouts** (posicionamiento estilo flexbox)
711
840
  - [ ] **Sistema de grid** (spans column/row inspirados en CSS Grid)
712
841
  - [ ] **Renderizado de Markdown** (headings, listas, code blocks, tablas)
713
842
  - [ ] **Syntax highlighting** (gramáticas integradas)
714
- - [ ] **Pretty-printing JSON/YAML** (con límite de profundidad + collapse)
715
843
  - [ ] **Integración de logging** (drop-in para `console`/`pino`/`winston`)
716
844
 
717
845
  ### ✅ Fase 5 — Control de cursor y pantalla
@@ -826,16 +954,23 @@ El roadmap apunta intencionalmente — y busca superar — gaps que ni siquiera
826
954
  ## 🧪 Testing
827
955
 
828
956
  ```bash
829
- npm test # Correr todos los 1700+ tests
957
+ npm test # Correr todos los 2000+ tests
830
958
  npm run test:watch # Modo watch
831
959
  npm run test:coverage # Reporte de cobertura
832
960
  ```
833
961
 
834
- Targets de cobertura:
835
- - Statements: **98%**
836
- - Branches: **95%**
837
- - Functions: **99%**
838
- - Lines: **99%**
962
+ Cobertura (a v1.3.0):
963
+
964
+ | Métrica | Score |
965
+ |---|:-:|
966
+ | **Statements** | ~98% |
967
+ | **Branches** | ~95% |
968
+ | **Functions** | ~99% |
969
+ | **Lines** | ~99% |
970
+ | **Tests totales** | **2,000+** |
971
+ | **Test suites** | 18 |
972
+ | **Matrix CI** | Node 18, 20, 22, latest |
973
+ | **Plataformas probadas** | Linux, macOS, Windows |
839
974
 
840
975
  ---
841
976
 
@@ -871,6 +1006,58 @@ ansimax/
871
1006
 
872
1007
  ## 📝 Changelog
873
1008
 
1009
+ ### v1.3.1 — Pulido de panels + json
1010
+
1011
+ Release patch que mejora los módulos de v1.3.0 con quality-of-life:
1012
+
1013
+ - 🎯 **`panels.center(block, opts)`** — centra un block horizontalmente (y opcionalmente verticalmente) en un ancho conocido
1014
+ - 🖼️ **`panels.frame(block, opts)`** — alternativa más ligera a `ascii.box`: solo top/bottom con title + padding opcionales
1015
+ - 📋 **`json.pretty` opción `sortKeys`** — orden alfabético de keys para diffs deterministas
1016
+ - 📐 **`json.pretty` opción `inlineArrayMaxLength`** — arrays cortos de primitivos ahora se renderizan como `[1, 2, 3]` en una línea (threshold default: 60 chars)
1017
+ - 🧪 **+26 tests** entre panels + json
1018
+
1019
+ ```js
1020
+ import { panels, json } from 'ansimax';
1021
+
1022
+ // Centrar un box dentro de la terminal
1023
+ console.log(panels.center(ascii.box('Hello'), { width: 80 }));
1024
+
1025
+ // Frame decorativo más ligero
1026
+ console.log(panels.frame('Body', { title: 'Header', padding: 1 }));
1027
+
1028
+ // Sorted, con inline arrays
1029
+ console.log(json.pretty({ zebra: [1, 2, 3], apple: 'A' }, { sortKeys: true }));
1030
+ // {
1031
+ // "apple": "A",
1032
+ // "zebra": [1, 2, 3]
1033
+ // }
1034
+ ```
1035
+
1036
+ Drop-in replacement para `1.3.0`.
1037
+
1038
+ ### v1.3.0 — Avance Fase 4: Panels + JSON pretty-print
1039
+
1040
+ Release minor que añade dos nuevos módulos top-level — split layouts y pretty-print de JSON:
1041
+
1042
+ - 🪟 **Módulo `panels`** — `vsplit` (columnas) + `hsplit` (filas) con consciencia ANSI, alineación (`start`/`center`/`end`), gap, modo ancho fijo, anidamiento
1043
+ - 🎨 **Módulo `json`** — pretty-printer coloreado con límite de profundidad, límite de items, truncamiento de strings, detección de referencias circulares
1044
+ - 🛣️ **Fase 4 del roadmap**: 8/15 → **10/15** completo
1045
+
1046
+ ```js
1047
+ import { panels, json, ascii } from 'ansimax';
1048
+
1049
+ // Columnas lado a lado
1050
+ console.log(panels.vsplit([
1051
+ ascii.box('Sidebar', { width: 20 }),
1052
+ ascii.box('Main', { width: 40 }),
1053
+ ], { gap: 2 }));
1054
+
1055
+ // Pretty-print JSON
1056
+ console.log(json.pretty({ name: 'app', tests: 2000 }, { maxDepth: 3 }));
1057
+ ```
1058
+
1059
+ Drop-in replacement para `1.2.8`. Dos módulos nuevos, cero breaking changes.
1060
+
874
1061
  ### v1.2.8 — Pulido de documentación
875
1062
 
876
1063
  Release patch con cobertura JSDoc + IntelliSense masivamente mejorada: