ansimax
v1.4.7
Published
Zero-dependency CLI rendering library: colors, gradients, animations, ASCII art, pixel art, components, and themes — all in TypeScript.
Maintainers
Keywords
Readme
La librería definitiva de renderizado CLI para Node.js
Colores • Gradientes • Animaciones • ASCII Art • Pixel Art • Árboles • Componentes • Temas
English · Español
🎬 Vista previa
🌟 ¿Qué es Ansimax?
Ansimax es una librería de renderizado todo-en-uno para construir interfaces de terminal hermosas en Node.js. Un solo paquete reemplaza un stack de más de 8 dependencias — colores, gradientes, ASCII art, spinners, barras de progreso, tablas, menús, árboles, temas, pixel art — combinadas en una única API coherente de TypeScript con cero dependencias en runtime.
npm install ansimaximport { color, gradient, ascii, loader, sleep } from 'ansimax';
console.log(ascii.banner('hola', {
colorFn: (t) => gradient(t, ['#ff79c6', '#bd93f9', '#8be9fd']),
}));
const stop = loader.spin('Construyendo proyecto', { color: '#bd93f9' });
await sleep(1500);
stop('Build completado', true);💡 ¿Por qué Ansimax?
| Sin Ansimax | Con Ansimax |
|---|---|
| Instalar 8+ paquetes: chalk, gradient-string, figlet, ora, cli-progress, cli-table3, boxen, inquirer | Una sola instalación: ansimax |
| Mezclar APIs incompatibles, paradigmas diferentes, tipos en conflicto | API funcional consistente, fuente única de verdad |
| Sin sistema de temas coherente entre paquetes | Temas integrados (Dracula, Nord, Matrix, Cyberpunk, +5) |
| Limpieza manual del cursor, sin protección ante crashes | Cursor con conteo de referencias + handlers de crash integrados |
| Sin soporte de AbortSignal en la mayoría de libs CLI | Toda animación, loader y prompt es abortable |
| Cada lib trae su propia lógica de fallback en runtime | NO_COLOR / FORCE_COLOR / detección de TTY unificada |
| Sin límites de memoria en cachés de color | Cachés LRU acotadas en todo el código (sin fugas bajo carga) |
🆚 Comparación con el ecosistema Node.js
Ansimax reemplaza un stack de librerías populares de Node.js con un solo paquete coherente, tipado y de cero dependencias:
| Característica | chalk | gradient-string | ora | cli-progress | figlet | boxen | inquirer | cli-table3 | Ansimax |
|---|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|
| Colores básicos + 256 | ✅ | — | — | — | — | — | — | — | ✅ |
| Truecolor con fallback adaptativo | ✅ | ✅ | — | — | — | — | — | — | ✅ |
| Gradientes multi-stop | — | ✅ | — | — | — | — | — | — | ✅ |
| Gradientes animados | — | — | — | — | — | — | — | — | ✅ |
| Curvas de easing (5 presets + custom) | — | — | — | — | — | — | — | — | ✅ |
| Gradientes cónicos (barrido radial) | — | — | — | — | — | — | — | — | ✅ |
| Banners ASCII | — | — | — | — | ✅ | — | — | — | ✅ |
| Conversor Imagen → ASCII | — | — | — | — | — | — | — | — | ✅ |
| Parser figlet .flf | — | — | — | — | ✅ (propio) | — | — | — | ✅ (250+ fuentes) |
| Registro de fuentes personalizadas | — | — | — | — | parcial | — | — | — | ✅ |
| Cajas con múltiples estilos | — | — | — | — | — | ✅ | — | — | ✅ (6 estilos) |
| Spinners (varios estilos) | — | — | ✅ | — | — | — | — | — | ✅ (11 estilos) |
| Barras de progreso animadas | — | — | — | ✅ | — | — | — | — | ✅ |
| Tareas jerárquicas/paralelas | — | — | — | — | — | — | — | — | ✅ |
| Tablas (multi-línea, conscientes de ANSI) | — | — | — | — | — | — | — | ✅ | ✅ |
| Menús interactivos + multi-select | — | — | — | — | — | — | ✅ | — | ✅ |
| Árboles con detección de ciclos | — | — | — | — | — | — | — | — | ✅ |
| Layouts divididos (vsplit/hsplit) | — | — | — | — | — | — | — | — | ✅ (v1.3.0) |
| Pretty-printer JSON coloreado | — | — | — | — | — | — | — | — | ✅ (v1.3.0) |
| CSS Grid (colSpan/rowSpan/areas) | — | — | — | — | — | — | — | — | ✅ (v1.4.1–v1.4.4) |
| Renderizador Markdown → terminal | — | — | — | — | — | — | — | — | ✅ (v1.4.0–v1.4.4) |
| Resaltado de sintaxis (js/ts/json/bash) | — | — | — | — | — | — | — | — | ✅ (v1.4.5) |
| Pixel art + canvas + sprites | — | — | — | — | — | — | — | — | ✅ |
| Sistema de temas + aislamiento por instancia | — | — | — | — | — | — | — | — | ✅ |
| AbortSignal en todas partes | — | — | parcial | — | — | — | parcial | — | ✅ |
| Soporte NO_COLOR | ✅ | parcial | parcial | — | — | — | — | — | ✅ |
| Códigos de error estables (ANSIMAX_*) | — | — | — | — | — | — | — | — | ✅ |
| TypeScript-first (strict mode) | parcial | parcial | ✅ | parcial | parcial | ✅ | parcial | parcial | ✅ |
| Cero dependencias en runtime | ✅ | — | — | — | — | — | — | — | ✅ |
| Export dual ESM + CJS | parcial | parcial | ✅ | ✅ | parcial | ✅ | parcial | parcial | ✅ |
| Cobertura de tests | ~95% | parcial | parcial | parcial | parcial | parcial | parcial | parcial | ~98% (2000+ tests) |
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.
📦 Instalación
npm install ansimax
# o
pnpm add ansimax
# o
yarn add ansimaxRequisitos: Node.js ≥ 18. Soporta ESM y CJS. Los ejemplos se publican junto con el paquete — ver /examples.
⚡ Ejemplo en 30 segundos
import { color, gradient, loader, ascii, sleep } from 'ansimax';
console.log(ascii.banner('deploy', {
colorFn: (t) => gradient(t, ['#ff6b6b', '#feca57', '#48dbfb']),
}));
const stop = loader.spin('Construyendo proyecto', { color: '#bd93f9' });
await sleep(1500); // simula trabajo asíncrono
stop('Build completado', true); // ✓ + color de éxito
console.log(color.green('✓') + ' Listo en ' + color.bold('1.4s'));🚀 Inicio rápido
import { configure, color, themes, gradient } from 'ansimax';
// Configuración global
configure({ theme: 'dracula', animationSpeed: 'normal' });
// Estilos básicos
console.log(color.red('error'));
console.log(color.bold(color.cyan('importante')));
// Gradiente multi-stop
console.log(gradient('texto arcoiris', [
'#ff5555', '#ffaa00', '#ffff00',
'#00ff00', '#0099ff', '#cc44ff',
]));
// Cambiar tema — dispara los subscribers
themes.use('cyberpunk');
console.log(themes.primary('primary de cyberpunk'));✨ Características
- 🎨 Colores — Truecolor / 256 / básico con fallback adaptativo. Detección de NO_COLOR / FORCE_COLOR / TTY
- 🌈 Gradientes — Lineales multi-stop, radiales, diagonales, ángulo arbitrario. Presets personalizados vía
registerPreset - 🔠 ASCII Art — Banners (fuentes
big/small), cajas (6 estilos), divisores, logos. API de stream + registro de fuentes - 🖼️ Pixel Art — Sprites, alpha blending, gradientes con dithering, canvas con renderizado dirty-rect, modo braille (sub-pixel 2×4)
- 🌳 Árboles — API builder + data plana, 4 estilos, colores/iconos por nodo, max-depth, detección de ciclos, algoritmos walk/find/map/filter
- 🎞️ Animaciones — Typewriter, fade, slide, pulse, wave, glitch, reveal. Conscientes de AbortSignal, modo reducedMotion
- ⏳ Loaders — 11 estilos de spinner, barras animadas, tareas jerárquicas/paralelas, cuentas regresivas, gestor multi-spinner
- 🎬 Frames — Reproducción secuenciada con pause/resume/seek, renderizador live push-based, timing con corrección de drift, morph
- 🧱 Componentes — Tablas (conscientes de ANSI, celdas multi-línea), badges, líneas de estado, secciones, columnas, timelines, menús interactivos
- 🎨 Temas — 8 built-in (Dracula, Nord, Monokai, Cyberpunk, Pastel, Matrix, Ocean, Sunset). Aislamiento por instancia, listeners
onChange, helpersbg* - ⚙️ Configure — Config centralizada con subscribers, updates batched, overrides temporales con
withConfig(), modo strict - 🛠️ Utils — Primitivas ANSI, control del cursor, hyperlinks de terminal (OSC 8),
setTitle,safeJson,onResize, debounce/throttle/memoize
📸 Showcase
Colores y Gradientes
import { color, gradient, rainbow } from 'ansimax';
// Colores básicos
console.log(color.red('rojo'), color.green('verde'), color.blue('azul'));
// Modificadores de estilo
console.log(color.bold('negrita'), color.italic('itálica'), color.underline('subrayado'));
// Gradiente multi-stop
console.log(gradient('fuego a océano', ['#ff6b6b', '#feca57', '#48dbfb']));
// Preset rainbow integrado
console.log(rainbow('preset rainbow integrado'));Gradientes animados (v1.2.0)
import { animateGradient, sleep } from 'ansimax';
// Animación de flujo de color — corre hasta llamar stop()
const ctrl = animateGradient('Cargando...', ['#ff79c6', '#bd93f9', '#8be9fd'], {
duration: 2000, // ms por ciclo
fps: 30,
direction: 'forward', // o 'reverse'
});
await sleep(3000);
ctrl.stop();
// v1.2.2: await directo (no se necesita .done)
await animateGradient('¡Listo!', ['#50fa7b', '#bd93f9'], {
infinite: false, cycles: 2, duration: 800,
});Curvas de interpolación (v1.2.0)
import { gradient } from 'ansimax';
const stops = ['#ff79c6', '#bd93f9', '#8be9fd'];
// Cinco easings built-in + soporte para funciones personalizadas
console.log(gradient('hola mundo', stops, { easing: 'linear' }));
console.log(gradient('hola mundo', stops, { easing: 'ease-in' }));
console.log(gradient('hola mundo', stops, { easing: 'ease-out' }));
console.log(gradient('hola mundo', stops, { easing: 'ease-in-out' }));
console.log(gradient('hola mundo', stops, { easing: 'cubic-bezier' }));
// O tu propia función de easing (t → t suavizado, ambos en [0,1])
console.log(gradient('hola mundo', stops, { easing: (t) => t * t * t }));Gradientes cónicos (v1.2.0)
import { gradientRect } from 'ansimax';
// Barrido radial alrededor del centro — rueda arcoíris
console.log(gradientRect({
width: 30, height: 15,
colors: ['#ff0000', '#ffff00', '#00ff00', '#00ffff', '#0000ff', '#ff00ff', '#ff0000'],
style: 'conic',
startAngle: 0, // ángulo de rotación en grados
dither: 'bayer',
}));Gradientes reusables (v1.2.3)
import { createGradient, reverseGradient, ascii } from 'ansimax';
// Pre-resuelve los stops de hex una vez — significativamente más rápido para uso repetido
const fire = createGradient(['#ff5555', '#ffb86c', '#f1fa8c']);
console.log(fire('Primera línea'));
console.log(fire('Segunda línea'));
console.log(fire('Tercera línea'));
// Úsalo como colorFn para banners — misma firma de ColorFn
console.log(ascii.banner('FIRE', { colorFn: fire }));
// v1.2.4: inspecciona metadata
console.log('Stops:', fire.stops); // → ['#ff5555', '#ffb86c', '#f1fa8c']
console.log('Resolved:', fire.resolvedStops); // → [{r:255,g:85,b:85}, ...]
// v1.2.4: invierte un gradiente (preserva las opciones por defecto)
const ice = reverseGradient(fire);
console.log(ice('Lado frío'));
// Las opciones por-llamada aún funcionan — perfecto para animación
for (let p = 0; p < 1; p += 0.05) {
process.stdout.write('\r' + fire('fluyendo', { phase: p }));
await new Promise((r) => setTimeout(r, 50));
}ASCII Art
import { ascii, gradient } from 'ansimax';
console.log(ascii.banner('HOLA', {
font: 'big',
align: 'center',
colorFn: (t) => gradient(t, ['#ff79c6', '#bd93f9']),
}));
console.log(ascii.box('¡Caja arcoiris!', { padding: 1, borderStyle: 'rounded' }));Imagen → ASCII (v1.2.5)
import { ascii } from 'ansimax';
import sharp from 'sharp';
// Obtén píxeles RGB raw de cualquier librería de imágenes — ejemplo con `sharp`.
// Puedes usar jimp, pngjs, canvas, o cualquier decoder. Ansimax sigue sin deps.
const { data, info } = await sharp('./foto.png')
.raw()
.toBuffer({ resolveWithObject: true });
// Convierte el buffer RGB raw → PixelGrid (un array 2D de objetos { r, g, b })
const pixels = [];
for (let y = 0; y < info.height; y++) {
const row = [];
for (let x = 0; x < info.width; x++) {
const i = (y * info.width + x) * info.channels;
row.push({ r: data[i], g: data[i + 1], b: data[i + 2] });
}
pixels.push(row);
}
// Ahora usa ansimax — varias formas:
// 1. Monocromo
console.log(ascii.fromImage(pixels, { width: 80 }));
// 2. Color + dithering Floyd-Steinberg + ramp detallado
console.log(ascii.fromImage(pixels, {
width: 100,
color: true,
dither: 'floyd-steinberg',
ramp: 'detailed',
}));
// 3. Modo detección de bordes (line art)
console.log(ascii.fromImage(pixels, {
width: 80,
edgeDetect: 'sobel',
edgeThreshold: 50,
ramp: 'blocks',
}));
// 4. Modo rostro para retratos (mejora contraste de tonos medios)
console.log(ascii.fromImage(pixels, {
width: 60,
ramp: 'detailed',
faceMode: true,
}));Fuentes Figlet (v1.2.5)
import { readFileSync } from 'node:fs';
import { parseFiglet, ascii, gradient } from 'ansimax';
// Descarga fuentes desde http://www.figlet.org/fontdb.cgi
const font = parseFiglet(readFileSync('./standard.flf', 'utf8'));
console.log(ascii.figletText('¡Hola!', font));
// Con color
console.log(ascii.figletText('STYLE', font, {
colorFn: (t) => gradient(t, ['#ff79c6', '#bd93f9', '#8be9fd']),
}));Árboles
import { tree, color } from 'ansimax';
const proyecto = tree({ label: 'mi-app', icon: '📦', color: color.bold });
const src = proyecto.add({ label: 'src', icon: '📁' });
src.addLeaf({ label: 'index.ts', icon: '📄' });
src.addLeaf({ label: 'app.ts', icon: '📄' });
console.log(proyecto.render({
style: 'rounded',
palette: [color.cyan, color.green, color.magenta],
guideColor: color.dim,
}));Pixel Art y Canvas
import { images, createCanvas, gradientRect, SPRITES } from 'ansimax';
// Sprite integrado
console.log(images.sprite('heart'));
// Gradiente suave con dither Bayer
console.log(gradientRect({
width: 50, height: 4,
colors: ['#ff6b6b', '#feca57', '#48dbfb'],
dither: 'bayer',
}));
// Canvas personalizado
const c = createCanvas(40, 10);
c.fill({ r: 18, g: 18, b: 38 });
c.drawCircle(20, 5, 4, { r: 255, g: 200, b: 0 }, true);
const starSprite = SPRITES.star;
if (starSprite) c.drawSprite(2, 2, starSprite.pixels);
c.print();Componentes
import { components, color } from 'ansimax';
console.log(components.table([
['Módulo', 'Estado', 'Cobertura'],
['colors', color.green('● listo'), '100%'],
['animations', color.green('● listo'), '100%'],
['loaders', color.green('● listo'), '100%'],
], { borderStyle: 'rounded' }));
console.log(components.badge('VERSION', 'v1.4.7'));
console.log(components.badge('BUILD', 'passing'));Timeline
import { components } from 'ansimax';
console.log(components.timeline([
{ label: 'Init del proyecto', done: true, time: '10:00' },
{ label: 'Pipeline de build', done: true, time: '10:15' },
{ label: 'Correr tests', done: false, time: '10:32' },
{ label: 'Deploy a npm', done: false },
]));Loaders y Progreso
import { loader, sleep } from 'ansimax';
// Spinner con éxito/fallo
const stop = loader.spin('Cargando...', { color: '#bd93f9' });
await sleep(1500);
stop('¡Listo!', true); // ✓ ícono verde
// Barra de progreso animada
await loader.progressAnimate(100, 'Descargando', {
color: '#50fa7b', delay: 25,
});
// Tareas jerárquicas con ejecución paralela
await loader.tasks([
{
text: 'Build',
fn: async () => await sleep(500),
subtasks: [
{ text: 'TypeScript', fn: async () => await sleep(800) },
{ text: 'Bundle', fn: async () => await sleep(600) },
],
},
{ text: 'Test', fn: async () => await sleep(700) },
], { parallel: true });Animaciones
import { animate, gradient, sleep } from 'ansimax';
await animate.typewriter('Bienvenido al wizard de deployment...', {
speed: 30,
colorFn: (t) => gradient(t, ['#bd93f9', '#ff79c6']),
});
await animate.fadeIn('Carga completa', { duration: 600 });
// Carrera de pasos contra timeout — nunca se cuelga
await animate.parallel([
async () => await sleep(500), // simulación de chequeo de red
async () => await sleep(700), // simulación de chequeo de base de datos
async () => await sleep(400), // simulación de chequeo de auth
], { timeout: 5000 });Temas
import { themes, createTheme } from 'ansimax';
// Temas built-in
themes.use('dracula');
console.log(themes.primary('hola'));
// Escuchar cambios
const off = themes.onChange((nuevo, anterior) => {
console.log(`Tema: ${anterior.name} → ${nuevo.name}`);
});
// Multi-tenant: cada instancia totalmente aislada
const tenantA = createTheme('nord');
const tenantB = createTheme('matrix');
// Definir un tema personalizado y registrarlo SÓLO en tenantA
tenantA.register('custom', {
name: 'Custom',
primary: '#ff5e5e',
secondary: '#5e5eff',
accent: '#5eff5e',
success: '#10b981',
warning: '#fbbf24',
error: '#ef4444',
info: '#06b6d4',
muted: '#6b7280',
bg: '#1e293b',
surface: '#334155',
text: '#f1f5f9',
gradient: ['#ff5e5e', '#5eff5e', '#5e5eff'],
});
console.log('tenantA incluye custom?', tenantA.list().includes('custom'));
console.log('tenantB incluye custom?', tenantB.list().includes('custom'));
// ↑ false — aislamiento totalPanels — Layouts divididos (v1.3.0)
import { panels, ascii } from 'ansimax';
// Columnas lado a lado
const left = ascii.box('Sidebar', { borderStyle: 'rounded' });
const right = ascii.box('Vista principal', { borderStyle: 'rounded' });
console.log(panels.vsplit([left, right], { gap: 2, align: 'center' }));
// Apilado vertical
console.log(panels.hsplit([
'── Aplicación ──',
ascii.box('Contenido'),
'── Pie ──',
], { gap: 1, align: 'center' }));
// Anidado — sidebar + main dentro de un shell de aplicación
console.log(panels.hsplit([
'── Mi App ──',
panels.vsplit([
ascii.box('Sidebar', { width: 20 }),
ascii.box('Main', { width: 40 }),
], { gap: 2 }),
'── Fin ──',
]));JSON Pretty-print (v1.3.0)
import { json } from 'ansimax';
// Pretty-print coloreado y consciente de profundidad
console.log(json.pretty({
name: 'ansimax',
version: '1.3.0',
features: ['colors', 'gradients', 'panels'],
stats: { tests: 2000, coverage: 0.98 },
active: true,
}));
// Límite de profundidad — colapsa objetos profundos a {...}
const deeplyNested = { a: { b: { c: { d: { e: 'muy profundo' } } } } };
console.log(json.pretty(deeplyNested, { maxDepth: 2 }));
// Límite de items — arrays grandes muestran "... (N more)"
const largeArray = Array.from({ length: 50 }, (_, i) => `item_${i}`);
console.log(json.pretty(largeArray, { maxItems: 5 }));
// Referencias circulares manejadas con gracia
const obj = { name: 'foo' };
obj.self = obj;
console.log(json.pretty(obj)); // → "self": [Circular]📖 Documentación
La carpeta docs/ contiene ejemplos completos para cada módulo:
| Documento | Descripción |
|---|---|
| docs/README.md | Índice de documentación — empieza aquí |
| docs/examples-ts.md | 33 ejemplos en TypeScript (3 por módulo × 11 módulos) |
| docs/examples-mjs.md | 33 ejemplos en JavaScript ESM |
| docs/examples-cjs.md | 33 ejemplos en JavaScript CommonJS |
| docs/showcase.md | App completa que combina todos los módulos |
Cada ejemplo es copy-paste ejecutable con escenarios realistas de complejidad media — no solo one-liners.
📚 Ejemplos
Once ejemplos de calidad de producción se publican en el paquete npm y son ejecutables directamente. Los encuentras en /examples después de instalar:
| Archivo | Qué demuestra |
|---|---|
| 01-quick-smoke.ts | Test rápido de humo — verifica que cada import principal funciona |
| 02-colors-gradients.ts | Toda función de color, tipos de gradiente, presets, compose, API chain |
| 03-ascii-banners.ts | Banners (big/small), 6 estilos de caja, divisores, compositor de logos |
| 04-trees.ts | Tree builder + API data-plana, 4 estilos, palettes, algoritmos (walk/find/map/filter) |
| 05-components.ts | Tablas, badges, status, secciones, columnas, timelines, barras de progreso |
| 06-pixel-art.ts | Sprites, canvas personalizado, gradient rects con dither, transforms (flip/rotate) |
| 07-animations.ts | typewriter, fadeIn/Out, slide, pulse, wave, glitch, reveal |
| 08-loaders.ts | Estilos de spinner, progreso animado, tareas jerárquicas, cuenta regresiva |
| 09-themes.ts | Los 8 temas integrados, listeners, registro de temas personalizados, aislamiento por instancia |
| 10-everything.ts | Showcase completo — cada módulo ejercitado en un demo cohesivo |
| all-in-one.mjs | Demo completo en ESM (JS puro con import) — sin necesidad de TypeScript |
| all-in-one.cjs | Demo completo en CommonJS (JS puro con require) — sin necesidad de TypeScript |
Ejecuta cualquier ejemplo con:
# Ejemplos en TypeScript
npx tsx examples/10-everything.ts
# JS puro — ESM
node examples/all-in-one.mjs
# JS puro — CommonJS
node examples/all-in-one.cjs🎯 Casos de uso
- Instaladores y scaffolders CLI — hermosa experiencia de primer arranque (estilo create-react-app, create-next-app)
- Herramientas DevOps — dashboards de deployment, pipelines de build, monitores de salud
- Dev experience — mejores test runners, output de lint, formateo de errores
- Prompts interactivos — menús, confirmaciones, wizards multi-select
- Exploración de datos — tablas, árboles, charts para workflows terminal-first
- Reportes de estado — progreso en tiempo real, orquestación multi-tarea
- Intros ASCII — launchers de juego, splash screens, banners de login
⚙️ Configuración
La config global afecta cada módulo que la respeta (colores, temas, velocidad de animación, etc.):
import { configure, getConfig, withConfig, onConfigKeyChange } from 'ansimax';
configure({
colorMode: 'auto', // 'none' | 'basic' | '256' | 'truecolor' | 'auto'
animationSpeed: 'normal', // 'slow' | 'normal' | 'fast' | 'instant'
theme: 'dracula', // cualquier tema registrado
reducedMotion: false,
});
// Escuchar cambios (por-key — evita disparos excesivos)
const off = onConfigKeyChange('theme', (nuevo, anterior) => {
console.log(`Tema: ${anterior} → ${nuevo}`);
});
// Override temporal + restauración automática al completar o lanzar
await withConfig({ animationSpeed: 'fast' }, async () => {
// ...tu código en modo fast aquí...
});
// Modo strict captura typos en config
// configure({ unknwnKey: 'x' }, { strict: true }); // lanza RangeError⚠️ Códigos de error
Varias funciones de ansimax lanzan Error / TypeError / RangeError para inputs inválidos.
Hacer catch por código de error es la forma estable y recomendada para manejarlos programáticamente — el texto del mensaje puede cambiar, pero los valores .code están garantizados como semver-estables.
import { themes, ascii, parseFiglet } from 'ansimax';
try {
themes.use('tema-inexistente');
} catch (e) {
if (e.code === 'ANSIMAX_UNKNOWN_THEME') {
themes.use('dracula'); // fallback
} else {
throw e; // re-lanzar errores inesperados
}
}Todos los códigos de error
| Código | Lanzado por | Tipo | Cuándo |
|---|---|---|---|
| ANSIMAX_INVALID_THEME | themes.register | TypeError | El valor del tema no es un objeto plano |
| ANSIMAX_INVALID_THEME_NAME | themes.register | TypeError | El tema tiene name vacío o ausente |
| ANSIMAX_UNKNOWN_THEME | themes.use | RangeError | El nombre del tema solicitado no está registrado |
| ANSIMAX_INVALID_FONT_NAME | ascii.registerFont | TypeError | Nombre de fuente vacío o no string |
| ANSIMAX_RESERVED_FONT_NAME | ascii.registerFont | Error | Sobrescribir fuente built-in sin { force: true } |
| ANSIMAX_INVALID_FIGLET_INPUT | parseFiglet | TypeError | Contenido .flf vacío o no string |
| ANSIMAX_INVALID_FIGLET_HEADER | parseFiglet | TypeError | La primera línea no es un header FIGfont válido |
| ANSIMAX_INVALID_FIGLET_HEIGHT | parseFiglet | TypeError | El header declara altura cero o negativa |
🧩 Paquetes del ecosistema
El ecosistema ansimax se estructura en dos niveles — paquetes companion que extienden el core, y evoluciones independientes que apuntan a diferentes plataformas.
@ansimax/* — Paquetes companion
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.
| Paquete | Estado | Descripción |
|---|:-:|---|
| ansimax | ✅ estable | Core de renderizado terminal. Cero dependencias. |
| @ansimax/image | 🟡 planeado | Cargador imagen-a-ASCII — PNG/JPEG/WebP desde archivo/buffer/URL |
| @ansimax/cli | 🟡 planeado | Binario standalone — npx @ansimax/cli demo, explorador de fuentes, conversor de imágenes |
| @ansimax/fonts | 🟡 planeado | 250+ fuentes figlet .flf pre-empacadas, listas para usar |
| @ansimax/sprites | 🔴 futuro | Librería curada de sprites (animales, iconos UI, diagramas técnicos) |
| @ansimax/video | 🔴 futuro | Extracción de frames de video → reproducción ASCII |
| @ansimax/themes-extra | 🔴 futuro | Pack de themes contribuidos por la comunidad |
Cómo se conectan:
┌─────────────────────────────┐
│ ansimax (cero deps) │ ← core, siempre lo instalas
│ • colors, ASCII, panels │
│ • types: PixelGrid, etc. │
└────────────┬────────────────┘
│ peer dependency
┌────────────────────┼────────────────────┐
▼ ▼ ▼
@ansimax/image @ansimax/cli @ansimax/fonts
(deps: jimp) (binario) (solo datos)Cada companion declara "ansimax": "^X.Y.Z" como peerDependency — coordinado por semver, nunca duplicado, nunca desincronizado.
ansimax-* — Evoluciones independientes
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.
| Paquete | Estado | Descripción |
|---|:-:|---|
| ansimax-native | 🔴 futuro | Reescritura Rust + TS del hot path de renderizado. Performance nativa via napi-rs. Misma superficie de API que ansimax. |
| ansimax-web | 🔴 futuro | Capa de renderizado para browser. Conversión ANSI → HTML/CSS + renderizado a canvas. Para demos, sitios de docs, terminales web. |
Sub-ecosistemas: cada uno de estos puede tener sus propios sub-paquetes con scope (@ansimax-native/image, @ansimax-web/canvas, etc.) con el tiempo.
¿Por qué dos convenciones de nombrado?
Convención de la industria usada por muchos ecosistemas maduros (Babel, Vue, Webpack, etc.):
@scope/*= "misma familia del proyecto, release coordinado, mismo equipo"name-*= "inspirado en / trabaja junto con, identidad independiente"
Al usar ambos, ansimax señala:
- El core (
ansimax) se mantiene pequeño, cero-deps, enfocado en renderizado terminal - El ecosistema (
@ansimax/*) crece a su alrededor como extensiones opt-in - Las evoluciones (
ansimax-native,ansimax-web) exploran diferentes plataformas sin comprometer el core
💡 Próximamente: cuando se publiquen
@ansimax/imageo paquetes similares, esta sección incluirá enlaces. ¿Quieres que uno de estos se construya antes? Abre un issue para votar.
🛣️ Roadmap
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.
El roadmap apunta intencionalmente — y busca superar — gaps que ni siquiera librerías TUI maduras de Python han resuelto completamente: renderers live-diff, gradientes animados, protocolos de imágenes en terminal, y una verdadera capa reactiva.
✅ Fase 1 — Fundamento core
- [x] Motor de estilos — ANSI 16 / 256 / truecolor con fallback adaptativo
- [x] Helpers Hex + RGB con clamping y validación
- [x] Soporte
NO_COLOR/FORCE_COLOR+ auto-detección no-TTY - [x] Integración de
AbortSignalen animaciones y loaders - [x] Stacking de estilos
compose()con emisión single-reset - [x] Caché LRU acotada de escapes (512 entradas, key packed-RGB)
- [x] Registro de presets personalizados (
registerPreset,listPresets)
✅ Fase 2 — Motor de gradientes
- [x] Gradientes lineales (multi-stop)
- [x] Rainbow + 6 presets built-in
- [x] Gradientes radiales (en
gradientRect) - [x] Gradientes diagonales
- [x] Gradientes a ángulo arbitrario
- [x] Dithering Bayer 4×4 para transiciones tonales suaves
- [x] UX single-stop (comportamiento estilo CSS)
- [x] Gradientes animados — flujo de color en el tiempo con
animateGradient()(v1.2.0) - [x] Curvas de interpolación —
linear/ease-in/ease-out/ease-in-out/cubic-bezier/ personalizado (v1.2.0) - [x] Gradientes cónicos — barrido radial con
style: 'conic'(v1.2.0)
✅ Fase 3 — Motor ASCII
- [x] Fuentes de bloque (
big,small) - [x] Banner con gradiente + alineación + coloreado por carácter
- [x] Dibujo de cajas (6 estilos de borde)
- [x] Divisores con variantes de estilo
- [x] Compositor de logos (gradiente + box wrapping)
- [x] Registro de fuentes personalizadas (
registerFont,hasFont,listFonts) - [x] API de stream (
ascii.stream()con AbortSignal) - [x] Conversor Imagen → ASCII —
ascii.fromImage()con mapeo de luminancia (v1.2.5) - [x] Renderizado ASCII en color — preserva colores de imagen con
color: true(v1.2.5) - [x] Dithering de imágenes — error diffusion Floyd-Steinberg (v1.2.5)
- [x] ASCII optimizado para rostros — histogram stretching para retratos (v1.2.5)
- [x] Soporte de fuentes figlet — parser + renderer
.flf(parseFiglet+ascii.figletText) (v1.2.5) - [x] Detección de bordes — operador Sobel integrado en
fromImage(v1.2.5, bonus)
✅ Fase 4 — Primitivas TUI
- [x] Tablas (filas irregulares, celdas multi-línea, conscientes de ANSI)
- [x] Cajas con múltiples estilos
- [x] Mensajes de estado + badges (con opción de borde)
- [x] Timelines con estados done/pending
- [x] Menús interactivos (single + multi-select)
- [x] Layout de columnas (overflow truncate/wrap)
- [x] Secciones (cabeceras con gradiente, ancho automático)
- [x] Árboles (colapsables, max-depth, cycle-safe)
- [x] Panels — split layouts:
hsplit,vsplitcon alineación + anidamiento (v1.3.0) - [x] Pretty-printing JSON/YAML — coloreado, depth-limit, cycle-safe (v1.3.0)
- [x] Sistema de grid — inspirado en CSS Grid:
colSpan,rowSpan(mark-and-pack),flow,cellWidth/cellHeight, y template areas congridAreas(v1.4.1–v1.4.4) - [x] Renderizado de Markdown — headings (ATX + setext), listas (anidadas + task lists), code blocks, tablas, blockquotes, estilos inline, escapes CommonMark, autolinks (v1.4.0–v1.4.6)
- [x] Syntax highlighting — gramáticas integradas para JS/TS/JSON/Bash con aliases (v1.4.5)
- [x] Layouts — CSS Grid (
grid/gridAreas) + flow estilo flexbox (flexcon justify + grow, v1.4.7) - [ ] Integración de logging (drop-in para
console/pino/winston)
✅ Fase 5 — Control de cursor y pantalla
- [x] Visibilidad de cursor, save/restore, posicionamiento, navegación por líneas
- [x] Limpieza de pantalla (línea, área, completa)
- [x] Cursor con conteo de referencias (calls superpuestas son seguras)
- [x] Restauración crash-safe (handlers de exit/SIGINT/SIGTERM)
- [x] Hyperlinks de terminal (OSC 8)
- [x] Título de ventana (OSC 2)
- [x] Bell (BEL)
✅ Fase 6 — Motor de animaciones
- [x] Typewriter, fadeIn, fadeOut, slide, pulse, wave, glitch, reveal
- [x] Conscientes de
AbortSignal - [x] Modo
reducedMotionpara accesibilidad - [x] Frame morph (interpolación texto → texto, descifrado cinematográfico)
- [x]
parallel()con timeout - [x] Propagación de signal a animaciones anidadas
- [ ] Librería de funciones easing (24 easings estándar: cubic, elastic, bounce, back)
- [ ] Composición de animaciones (DSL
parallel + sequence + delay) - [ ] Animaciones con física de spring (estilo
react-spring) - [ ] Motor de tween (interpolar cualquier tipo de valor)
🟡 Fase 7 — Ecosistema de progreso
- [x] Spinners (11 estilos) con color + AbortSignal
- [x] Barras de progreso animadas
- [x] Runners multi-tarea (secuencial + paralelo)
- [x] Cuentas regresivas
- [x] Manager multi-spinner (spinners concurrentes apilados)
- [x] Tareas jerárquicas (rollup padre + subtareas)
- [ ] Estimación live de ETA (rolling average + proyección con filtro de Kalman)
- [ ] Refresh live con diff renderer (sin flicker, solo redibujar líneas cambiadas)
- [ ] Grupos de progreso (grupos con nombre y tema compartido)
- [ ] Medidores de throughput (bytes/s, ops/s con unidades auto-escaladas)
🟡 Fase 8 — Detección de capacidades
- [x] Detección de TTY (auto-desactivar en pipes/CI)
- [x] Soporte de env
NO_COLOR/FORCE_COLOR - [x] Detección de profundidad de color (16 / 256 / truecolor)
- [x] Detección de proveedor CI (GitHub Actions, CircleCI, GitLab, Buildkite, Drone, Travis)
- [x] Detección de programa de terminal (iTerm, vscode, WezTerm, Hyper, Apple_Terminal)
- [x] Detección de Windows Terminal (
WT_SESSION) - [ ] Detección de ancho Unicode (CJK halfwidth/fullwidth, clusters de emoji, ZWJ)
- [ ] Detección de protocolos de imagen (Sixel, imágenes inline de iTerm, protocolo de Kitty)
- [ ] Base de datos de capacidades de terminal (flags xterm completos + probes de versión)
- [ ] Detección de métricas de fuente (ancho/alto de celda para layouts pixel-accurate)
🟡 Fase 9 — Renderizado avanzado
- [x] Canvas dirty-rectangle (solo redibujar píxeles cambiados)
- [x] Cachés LRU acotadas (escape sequences, render cache, ANSI cache)
- [x] Timing con corrección de drift (animaciones permanecen pegadas al reloj)
- [ ] Diff renderer (damage tracking a nivel de línea para UIs completas)
- [ ] Buffer virtual (componer UI sin escribir a stdout)
- [ ] Z-index / layering (overlapping de paneles con prioridad)
- [ ] Soporte de eventos de mouse (click, hover, drag, scroll)
- [ ] Abstracción de eventos de teclado (flechas, modificadores, secuencias, dead keys)
- [ ] Framework TUI completo (componentes reactivos — equivalente a Textual para Node)
🔴 Fase 10 — Charts de terminal
- [ ] Barras (horizontal + vertical, agrupadas, apiladas)
- [ ] Líneas (con braille para resolución sub-carácter)
- [ ] Sparklines (mini-charts inline para status bars)
- [ ] Áreas (rellenas con gradientes)
- [ ] Heatmaps (grids 2D color-mapped)
- [ ] Pie / donut (con etiquetas de porcentaje)
- [ ] Scatter plots
- [ ] Box plots / candlestick
- [ ] Charts en streaming en tiempo real (feed de datos con ventana móvil)
- [ ] Compositor de plots (dashboards multi-chart con ejes compartidos)
🔴 Fase 11 — Formularios e input
- [ ] Prompts de texto (con autocomplete + historial)
- [ ] Prompts de password (mascarados, medidor de fortaleza)
- [ ] Diálogos de confirmación (yes/no con highlight de default)
- [ ] Input numérico (con validación min/max)
- [ ] Pickers de fecha/hora (widget calendario)
- [ ] Picker de archivos (navegador de filesystem)
- [ ] Compositor de formularios (multi-campo con validación + display de errores)
- [ ] Flujos de wizard (formularios multi-paso con back/forward, indicador de progreso)
🔴 Fase 12 — Imagen y media
- [ ] Renderizado de imágenes Sixel (xterm, mlterm, WezTerm)
- [ ] Imágenes inline de iTerm2 (protocolo base64)
- [ ] Protocolo gráfico de Kitty
- [ ] PNG/JPEG → imagen de terminal (auto-detecta mejor protocolo)
- [ ] Preview de video (frame-por-frame a bajo FPS)
- [ ] Generación de códigos QR (con opciones de tamaño + nivel ECC)
- [ ] Generación de códigos de barras (Code 128, EAN-13)
🔴 Fase 13 — Sistema de plugins
- [ ] API de plugins para componentes personalizados
- [ ] Marketplace de temas
- [ ] Registro de fuentes personalizadas vía paquetes npm
- [ ] Registro de animaciones de la comunidad
- [ ] Interfaz de proveedor de capabilities (plug-in para detectores propios)
- [ ] Plugins de renderer (cambiar stdout por cualquier writable stream)
🔴 Fase 14 — Capa reactiva (framework TUI)
- [ ] Ciclo de vida de componentes (hooks mount/unmount/update)
- [ ] Estado reactivo (auto re-render al cambiar data, signals o hooks)
- [ ] Diffing de Virtual DOM (updates a nivel de línea)
- [ ] Event bus (comunicación entre componentes)
- [ ] Loop de aplicación (árbol de render único con ciclo de vida completo)
- [ ] Routing (apps multi-pantalla con historial)
- [ ] Integración DevTools (inspector de árbol de componentes, mark de nodos cambiados)
- [ ] CSS-in-TS styling (estilos con scope por componente)
Leyenda: ✅ Completo · 🟡 Parcial · 🔴 Planeado
🧪 Testing
npm test # Correr todos los 2000+ tests
npm run test:watch # Modo watch
npm run test:coverage # Reporte de coberturaCobertura (a v1.3.0):
| Métrica | Score | |---|:-:| | Statements | ~98% | | Branches | ~95% | | Functions | ~99% | | Lines | ~99% | | Tests totales | 2,000+ | | Test suites | 18 | | Matrix CI | Node 18, 20, 22, latest | | Plataformas probadas | Linux, macOS, Windows |
🛠️ Requisitos
- Node.js ≥ 18
- TypeScript ≥ 5.0 (para consumo tipado — opcional)
- Terminal con soporte truecolor recomendado (Windows Terminal, iTerm2, WezTerm, Kitty, xterm moderno). Degrada gracefully a 256 / 16 / sin-color.
🏗️ Estructura del proyecto
ansimax/
├── src/
│ ├── colors/ Renderizado de color + motor de gradientes
│ ├── themes/ Sistema de temas + 8 built-ins
│ ├── ascii/ Banners, cajas, fuentes
│ ├── animations/ Typewriter, fade, slide, pulse, wave, glitch, reveal
│ ├── loaders/ Spinners, progreso, tareas, multi-loader
│ ├── frames/ Reproducción secuenciada + renderer live + morph
│ ├── components/ Tablas, badges, status, timelines, menús
│ ├── images/ Sprites, canvas, gradientes con dither
│ ├── trees/ Builder de árboles + algoritmos
│ ├── utils/ Primitivas ANSI + helpers
│ └── configure.ts Config global + subscribers
├── examples/ 10 ejemplos (TS) + 2 (JS — ESM y CJS) — todas las funciones cubiertas
└── __tests__/ 16 test suites, 1700+ tests📝 Changelog
📝 Changelog
v1.4.7 — Reference links + layout flexbox
Dos items del roadmap, cero breaking changes:
- 🔗 Reference links en markdown —
[text][ref],[text][],[shortcut]+ definiciones[ref]: url "title" - 📐
panels.flex— layout estilo flexbox conjustify(start/end/center/between/around/evenly) + pesosgrow - 🧪 +30 tests
import { panels, markdown } from 'ansimax';
// Layout flexbox
panels.flex([boxA, boxB, boxC], { width: 60, justify: 'between' });
panels.flex([boxA, boxB], { width: 40, grow: [3, 1] }); // A crece 3× más
// Reference links
markdown.render(`
Ver [la docs][docs] y [shortcut].
[docs]: https://docs.example.com "Documentación"
[shortcut]: https://example.com
`);Ambos construyen sobre las bases de v1.4.6 (placeholders de links + distribute). Cada estrategia justify de flex conserva el ancho total exactamente.
Drop-in replacement para 1.4.6.
v1.4.6 — Consolidación v4 + toolkit matemático + autolinks
Release de mantenimiento + feature. Cero breaking changes:
- 🧹
HEX_REconsolidado — 5 copias duplicadas → 1 (isHexColor) - 🔢 Nuevo toolkit
utils/math—lerp,smoothstep,mod,gcd,distribute, y más (15 funciones puras) - 🔗 Autolinks en markdown —
<https://…>y URLs bare renderizan como hyperlinks de terminal - 🧪 +44 tests
import { smoothstep, distribute, mod } from 'ansimax';
smoothstep(0, 1, 0.25); // → 0.15625 (easing Hermite)
distribute(10, 3); // → [4, 3, 3] (suma exactamente 10)
mod(-1, 4); // → 3 (módulo verdadero)
import { markdown } from 'ansimax';
markdown.render('Docs en https://example.com'); // link clickeableDrop-in replacement para 1.4.5.
v1.4.5 — Refactor panels + resaltado de sintaxis
Dos grandes mejoras, cero breaking changes:
- 🎨 Resaltado de sintaxis para code blocks (js/ts/json/bash con aliases)
- 📁 Módulo panels refactorizado de monolito de 1116 líneas → 7 submódulos enfocados
- 🧩
griddescompuesto en 3 fases puras (resolve → pack → render) - ➕ 3 nuevos exports:
highlightCode,tokenizeCode,isHighlightSupported - 🧪 +50 tests
import { markdown } from 'ansimax';
console.log(markdown.render(`
\`\`\`js
const greet = (name) => \`Hola, \${name}!\`;
\`\`\`
`));
// Renderiza con highlighting de keywords (const), colores en strings, etc.Lenguajes soportados: js/javascript/jsx, ts/typescript/tsx, json, bash/sh/shell/zsh.
API directa:
import { highlightCode, tokenizeCode, isHighlightSupported } from 'ansimax';
highlightCode('const x = 42;', 'js'); // String con ANSI codes
tokenizeCode('const x = 42;', 'js'); // [{ kind, text }, ...]
isHighlightSupported('rust'); // falseDrop-in replacement para 1.4.4.
v1.4.4 — Grid areas + task lists + setext headings
Release patch finalizando el roadmap de Fase 4:
- 🎨
panels.gridAreas— template areas estilo CSS Grid con validación matemática de rectángulos - ✅ Task lists en markdown:
- [ ]y- [x](sintaxis GFM) - 📄 Setext headings en markdown:
text\n===(h1) ytext\n---(h2) - 🧪 +27 tests para todas las features nuevas
import { panels, markdown, ascii } from 'ansimax';
// CSS Grid template areas
panels.gridAreas(
{ header: 'HEAD', sidebar: 'SIDE', main: 'MAIN', footer: 'FOOT' },
{
areas: [
['header', 'header', 'header'],
['sidebar', 'main', 'main' ],
['footer', 'footer', 'footer'],
],
}
);
// Task lists renderizan como [ ] / [✓]
markdown.render(`
- [ ] pendiente
- [x] hecho
- item regular
`);
// Setext headings funcionan igual que # H1 / ## H2
markdown.render(`
Título
======
Subtítulo
---------
`);Validación de rectángulos detecta áreas no-contiguas al compilar:
Error: areas: "foo" is not a rectangle — cells at [0,0]..[1,1]
have 3 occurrences, expected 4Drop-in replacement para 1.4.3.
v1.4.3 — Grid rowSpan + escapes markdown + listas anidadas
Release patch con 3 features nuevas significativas:
- 🎯
panels.gridrowSpan — layouts multi-fila estilo CSS Grid usando algoritmo mark-and-pack - ⛓️ Escapes CommonMark en markdown:
\*,\_,\``,\,[,],~` - 🌳 Listas anidadas en markdown — sublistas recursivas por indentación con bullets por profundidad
- 🧪 +27 tests para todas las features nuevas
import { panels, markdown } from 'ansimax';
// Layout estilo CSS Grid
panels.grid([sidebar, top, bottom, side2], {
columns: 3,
colSpan: [1, 2, 2, 1],
rowSpan: [2, 1, 1, 1],
cellHeight: 4,
});
// Escapar caracteres literales de markdown
markdown.render('Mostrar \\*asteriscos literales\\*');
// Listas anidadas
markdown.render(`
- Exterior
- Anidado
- Profundo
`);Nota: items de Block.type === 'list' ahora son ListItem[] (antes string[]).
Solo afecta código externo que use parseBlocks directamente; usuarios de markdown.render no requieren cambios.
v1.4.2 — Consolidación interna v3
Release patch continuando el trabajo DRY de v1.3.7. Cero cambios de comportamiento:
- ➕
ensureString(value)— coerce a string (null/undefined → '') - ➕
clampNonNeg(n, fallback?)— entero no-negativo con fallback seguro - ➕
clampPositiveInt(n, fallback?)— entero positivo (≥ 1) con fallback seguro - 🧹 Removidas 10 implementaciones inline duplicadas entre components, frames, loaders, trees
- 🧪 +18 tests para los helpers consolidados
import { ensureString, clampNonNeg, clampPositiveInt } from 'ansimax';
ensureString(null) // → ''
clampNonNeg(-3) // → 0
clampPositiveInt(0) // → 1 (clamped up)
clampPositiveInt(NaN, 10) // → 10 (fallback)Drop-in replacement para 1.4.1.
v1.4.1 — Grid v2 + refactor markdown
Release patch. Cero breaking changes:
- 🎯
panels.grid— colSpan: span de columnas por bloque (auto-flow estilo CSS Grid) - 📏
panels.grid— cellHeight: alturas de fila uniformes (complementacellWidth) - 🔀
panels.grid— flow: dirección de auto-flow'row'(default) o'column' - 📁
markdownrefactorizado de monolito de 522 líneas → 5 submódulos enfocados (API sin cambios) - 🌳 Imports de submódulo habilitados:
import { parseBlocks } from 'ansimax/markdown/block-parser' - 🧪 +32 tests
import { panels, ascii } from 'ansimax';
// Header span ambas columnas, luego sidebar + content lado a lado
panels.grid([header, sidebar, content], {
columns: 2,
colSpan: [2, 1, 1],
cellHeight: 10, // altura de fila uniforme
});Drop-in replacement para 1.4.0.
v1.4.0 — Cierre de Fase 4: Renderizado Markdown 🎉
Release minor completando la Fase 4 con el nuevo módulo markdown:
- 📝
markdown.render(source, opts?)— pipeline completo markdown → terminal - 🧩
markdown.parseBlocks+markdown.parseInline— helpers de bajo nivel - 🎨 Temas:
'dark'(default) y'light' - 📐 Renderiza headings (h1–h6), bold/italic/strikethrough/code, listas, tablas, blockquotes, HRs, links
- 🔗 Links usan hyperlinks OSC 8 (clickables en terminales modernos)
- 📦 Bloques de código renderizados en
ascii.boxcon label de lenguaje - 🚀 Cero dependencias nuevas — reusa
color,gradient,ascii,components,hyperlink - 🧪 +54 tests para parser + renderer
import { markdown } from 'ansimax';
console.log(markdown.render(`
# Bienvenido
Esto es **bold** con \`code\` y [un link](https://example.com).
- Feature uno
- Feature dos
\`\`\`js
const x = 42;
\`\`\`
`));La Fase 4 está completa. Refinamientos posteriores en v1.4.x: listas anidadas + task lists (v1.4.3–v1.4.4) ✅, syntax highlighting (v1.4.5) ✅, autolinks (v1.4.6) ✅. Pendiente: CommonMark estricto (reference links, footnotes).
v1.3.7 — Consolidación interna + helpers clamp
Release de mantenimiento enfocado en limpieza de código. Cero cambios de comportamiento:
- ➕
clampPercent(value)— clamp + coerce a rango 0–100 (NaN/no-numérico → 0) - ➕
clampInt(value, min, max, fallback?)— clamp de enteros con fallback seguro - 🧹 Removidas 5 copias duplicadas de
isFiniteNumberentre módulos (ahora importadas desdeutils/helpers) - 🧹 Removidas 2 copias duplicadas de
clampPercent(components + loaders) - 🧹 Removida 1 copia duplicada de
clampInten images - 🧪 +13 tests para los helpers consolidados
import { clampPercent, clampInt } from 'ansimax';
clampPercent(150) // → 100 (clamped)
clampPercent(NaN) // → 0 (fallback seguro)
clampInt(50.7, 0, 100) // → 50 (floored + clamped)
clampInt(NaN, 0, 100, 25) // → 25 (fallback con inválidos)Drop-in replacement para 1.3.6.
v1.3.6 — Mejoras de branch coverage
Release de mantenimiento. Cero cambios de comportamiento:
- 🧪 +19 tests cubriendo branches defensivos en panels, frames, loaders
- 🧹 Mejorados comentarios
istanbul ignorepara branches genuinamente inalcanzables - ✅ Drop-in replacement para
1.3.5— mismodist/output
v1.3.5 — Color science matemático + limpieza
Release patch enfocado en profundidad matemática y limpieza de código. Cero breaking changes:
- 🎨 Espacio de color Oklab —
rgbToOklab/oklabToRgb. Gradientes perceptualmente uniformes - 🌈 Espacio de color HSL —
rgbToHsl/hslToRgb. Rotación de matiz, manipulación de color - 🎯
lerpColor/gradientColor/gradientStopsahora aceptanspace: 'rgb' | 'hsl' | 'oklab'(default'rgb', retro-compatible) - 🥄
mixColors(a, b, t, space)— alias semántico, acepta hex strings o RGB - 📐
quantizeColor(color, levels)— reducción de paleta (efecto posterize) - ⚡ Librería
easings— set completo de Robert Penner (quad/cubic/quart/quint/sine/expo/circ/back/elastic/bounce en in/out/inOut) - 🧮
isFiniteNumber+safeInt+clampByte— helpers numéricos exportados (consolida 25+ patrones defensivos duplicados) - 🧪 +82 tests incluyendo validación de correctitud matemática
import { lerpColor, easings, animate, mixColors } from 'ansimax';
// Midpoint de gradiente perceptualmente uniforme
mixColors('#ff0000', '#0000ff', 0.5, 'oklab');
// → { r: 140, g: 83, b: 162 } — magenta vibrante
// (vs RGB naive: { r: 128, g: 0, b: 128 } — púrpura turbio)
// Contador con animación bouncing
await animate.countUp(0, 1000, {
duration: 2000,
easing: easings.easeOutBounce,
});Drop-in replacement para 1.3.4.
v1.3.4 — Features para animations, configure, utils
Release patch con features opt-in en varios módulos. Cero breaking changes:
- 🎬
animate.shake(text, opts)— efecto tremor horizontal para errores - 🔢
animate.countUp(from, to, opts)— contadores numéricos animados con format/easing - ⚙️
setConfigValue(key, value)— atajo single-key + aliassubscribeConfig - 🔗
hyperlink(url, label)— links clickables vía OSC 8 (VS Code, iTerm2, WezTerm, Kitty...) - 🧹
clearLine()— helper conveniente para render loops - 🎨
gradientStops(start, end, count)— N stops procedurales entre dos colores - 🛡️
escapeForRegex(str)— escapa input de usuario para regex literals - 📏
measureBlock(block)— dimensiones ANSI-aware de texto multi-línea - 📐
node-globals.d.ts— añadidos tiposAsyncIterator/AsyncIterable/AsyncGenerator - 🧪 +45 tests entre animations, configure, utils
import { animate, hyperlink } from 'ansimax';
await animate.countUp(0, 1000, {
duration: 1500,
format: (n) => `$${n.toLocaleString()}`,
});
console.log(`Ver ${hyperlink('https://npmjs.com/ansimax', 'la página de npm')}`);Drop-in replacement para 1.3.3.
v1.3.3 — Features para panels, json, ascii
Release patch con nuevas features opt-in. Cero breaking changes:
- 📐
panels.grid(blocks, opts)— layout de grid en N columnas con auto-flow, gaps, alineación, y opción de ancho uniforme de celda - 🎯
panels.frame+ascii.box+ascii.dividertodos reciben opcióntitleAlign(oalign):'left','center'(default),'right' - 🏷️
ascii.boxnueva opcióntitle— muestra un label en el borde superior (expande el box si el title es más ancho que el contenido) - 📅
json.prettysoporta Map / Set / Date nativamente —Date(...),Map(N) [...],Set(N) [...]en modo display - 📤
json.prettynueva opciónmode: 'json'— produce JSON estricto y parseable (sin colores, descarta undefined/functions/symbols, lanza en circulares) - 🧪 +38 tests entre panels + json + ascii
import { panels, json, ascii } from 'ansimax';
// Grid de 2×2 con metric cards
console.log(panels.grid(cards, { columns: 2, gapX: 2 }));
// Title en el borde del box
console.log(ascii.box('content', { title: 'Section', titleAlign: 'left' }));
// Output JSON estricto (parseable)
const out = json.pretty(data, { mode: 'json' });
JSON.parse(out); // ✓ funcionaDrop-in replacement para 1.3.2.
v1.3.2 — Pulido de documentación para frames + images
Release patch con cobertura JSDoc + IntelliSense significativamente mejorada:
- 📝 Módulo
frames—play,generate,live,morph,presetsahora tienen JSDoc completo con 17 ejemplos ejecutables - 📝 Módulo
images—renderPixelArt,gradientRect,createCanvas,SPRITESahora tienen 18 ejemplos ejecutables - 🎯 Total: +35 nuevos bloques
@examplevisibles en tu editor
// Pasando el cursor sobre frames.play() en VS Code ahora muestra patrones de uso:
import { frames } from 'ansimax';
await frames.play(myFrames, {
interval: 80,
loop: true,
signal: ctrl.signal,
onFrame: (f, i) => color.cyan(`[${i}] ${f}`),
}).promise;Release puramente de documentación — cero cambios en código, API o tests.
Drop-in replacement para 1.3.1.
v1.3.1 — Pulido de panels + json
Release patch que mejora los módulos de v1.3.0 con quality-of-life:
- 🎯
panels.center(block, opts)— centra un block horizontalmente (y opcionalmente verticalmente) en un ancho conocido - 🖼️
panels.frame(block, opts)— alternativa más ligera aascii.box: solo top/bottom con title + padding opcionales - 📋
json.prettyopciónsortKeys— orden alfabético de keys para diffs deterministas - 📐
json.prettyopcióninlineArrayMaxLength— arrays cortos de primitivos ahora se renderizan como[1, 2, 3]en una línea (threshold default: 60 chars) - 🧪 +26 tests entre panels + json
import { panels, json } from 'ansimax';
// Centrar un box dentro de la terminal
console.log(panels.center(ascii.box('Hello'), { width: 80 }));
// Frame decorativo más ligero
console.log(panels.frame('Body', { title: 'Header', padding: 1 }));
// Sorted, con inline arrays
console.log(json.pretty({ zebra: [1, 2, 3], apple: 'A' }, { sortKeys: true }));
// {
// "apple": "A",
// "zebra": [1, 2, 3]
// }Drop-in replacement para 1.3.0.
v1.3.0 — Avance Fase 4: Panels + JSON pretty-print
Release minor que añade dos nuevos módulos top-level — split layouts y pretty-print de JSON:
- 🪟 Módulo
panels—vsplit(columnas) +hsplit(filas) con consciencia ANSI, alineación (start/center/end), gap, modo ancho fijo, anidamiento - 🎨 Módulo
json— pretty-printer coloreado con límite de profundidad, límite de items, truncamiento de strings, detección de referencias circulares - 🛣️ Fase 4 del roadmap: 8/15 → 10/15 completo
import { panels, json, ascii } from 'ansimax';
// Columnas lado a lado
console.log(panels.vsplit([
ascii.box('Sidebar', { width: 20 }),
ascii.box('Main', { width: 40 }),
], { gap: 2 }));
// Pretty-print JSON
console.log(json.pretty({ name: 'app', tests: 2000 }, { maxDepth: 3 }));Drop-in replacement para 1.2.8. Dos módulos nuevos, cero breaking changes.
v1.2.8 — Pulido de documentación
Release patch con cobertura JSDoc + IntelliSense masivamente mejorada:
- 📝 Módulo
components—table,badge,status,timelineahora tienen JSDoc completo con ejemplos ejecutables - 📝 Módulo
loaders—loader.spinyloader.tasksahora muestran patrones de uso en IntelliSense - 📝 Módulo
themes— JSDoc completo con ejemplos de cambio, registro y suscripción - 📝 Módulo
animations—animate.typewriteryanimate.fadeInmuestran cómo usar abort signals, reduced-motion, colores custom - 📝
ascii.box— 4 ejemplos (básico, multilínea, ancho fijo, con color) - 📖 Sección Códigos de error en README — los 8 códigos
ANSIMAX_*documentados
Total: ~30 nuevos bloques @example visibles en tu editor. Cero cambios en código —
tus programas existentes corren idéntico.
Drop-in replacement para 1.2.7.
v1.2.7 — Correcciones + robustez
Release patch enfocado en manejo de edge cases y mejor DX:
- 🐛
fromImagerechaza dimensiones inválidas explícitamente —width: 0,NaN,Infinityahora retornan''en vez de clampear silenciosamente - 🐛
figletText('')retorna''— antes retornaba filas vacías - 🛡️ Grids no-rectangulares manejados con gracia — filas de distinto largo ya no crashean
fromImage - 🎯 Códigos de error añadidos en todo el módulo ASCII —
ANSIMAX_INVALID_FIGLET_HEADER,ANSIMAX_INVALID_FONT_NAME, etc. paracatchprogramático - 📝 Mejores mensajes de error —
parseFigletahora incluye snippet del input problemático
try {
ascii.registerFont('big', myFont); // 'big' está reservado
} catch (e) {
if (e.code === 'ANSIMAX_RESERVED_FONT_NAME') {
ascii.registerFont('big', myFont, { force: true }); // override
}
}Drop-in replacement para 1.2.6.
v1.2.6 — Mejoras del módulo ASCII
Release patch con mejoras al motor ASCII:
- 🎨 4 ramps built-in nuevos —
binary,dots,shades,ascii64 - 🖼️ Opción
bgColorenfromImage— colores van al background (excelente conramp: 'binary'para efecto foto) - 🔆
brightnessycontrastpre-ajuste enfromImage— afina el rango tonal sin re-procesar - 📏 Opción
kerningenfigletText— controla el espacio entre glyphs - 📄
figletTextmulti-línea — input con\nrenderiza múltiples bloques FIGfont conlineSpacingopcional
import { ascii, ASCII_RAMPS } from 'ansimax';
// Renderizado tipo-foto con bloques coloreados en background
console.log(ascii.fromImage(pixels, {
width: 80,
bgColor: true,
ramp: 'binary',
brightness: 0.1,
contrast: 0.2,
}));
// Figlet multi-línea con espaciado
console.log(ascii.figletText('TITULO\nSUBTITULO', font, {
kerning: 1,
lineSpacing: 1,
}));Drop-in replacement para 1.2.5.
v1.2.5 — Fase 3 completa: motor de imagen-a-ASCII
Release minor que cierra el roadmap del motor ASCII con 5 features nuevas:
- 🖼️
ascii.fromImage(pixels, opts)— Conversor Imagen → ASCII (input:PixelGrid) - 🎨 Renderizado ASCII en color —
color: truepreserva los colores fuente - 📐 Dithering Floyd-Steinberg —
dither: 'floyd-steinberg'para gradientes tonales más suaves - 👤 Modo optimizado para rostros —
faceMode: truemejora contraste de tonos medios en retratos - 🔠 Soporte Figlet (.flf) —
parseFiglet()+ascii.figletText()para 250+ fuentes de comunidad - ⚡ Bonus: detección de bordes Sobel —
edgeDetect: 'sobel'para efectos line-art
import { readFileSync } from 'node:fs';
import { ascii, parseFiglet } from 'ansimax';
// Construye un PixelGrid pequeño a mano (usa sharp/jimp/etc para imágenes
// reales — ver sección Imagen → ASCII arriba)
const pixels = [
[{ r: 255, g: 0, b: 0 }, { r: 0, g: 255, b: 0 }],
[{ r: 0, g: 0, b: 255 }, { r: 255, g: 255, b: 0 }],
];
// Imagen a ASCII (input desde sharp/jimp/etc, sin dependencia de decoder)
console.log(ascii.fromImage(pixels, {
width: 80,
color: true,
dither: 'floyd-steinberg',
ramp: 'detailed',
}));
// Renderizado Figlet
const font = parseFiglet(readFileSync('./standard.flf', 'utf8'));
console.log(ascii.figletText('¡Hola!', font));Drop-in replacement para 1.2.4.
v1.2.4 — Utilidades de gradiente + inspectabilidad
Release patch añadiendo metadata de inspección y un helper reverseGradient():
- 🔍
ReusableGradientexpone.stops,.resolvedStops,.defaultOptions— todos congelados, todos de solo lectura - 🔄 Helper
reverseGradient()— invierte el orden de stops de un gradiente (funciona con arrays oReusableGradient) - 🎯
presetsexportado con su nombre canónico — junto al alias existentecolorPresets
import { createGradient, reverseGradient } from 'ansimax';
const fire = createGradient(['#ff5555', '#ffb86c', '#f1fa8c']);
const ice = reverseGradient(fire);
console.log(fire.stops); // ['#ff5555', '#ffb86c', '#f1fa8c'] — read-only
console.log(fire('cálido'));
console.log(ice('frío'));Drop-in replacement para 1.2.3.
v1.2.3 — Factory de gradientes + performance
Release patch añadiendo una API orientada a performance:
- ⚡ Factory
createGradient()— pre-resuelve los stops de hex una vez para reuso, ~40-60% más rápido en loops de animación y colorizado en bulk - 📖 Más JSDoc con ejemplos ejecutables
- 🎯 Coincide con la firma
ColorFn— funciona comocolorFnenascii.banner, themes, etc.
import { createGradient, ascii } from 'ansimax';
const fire = createGradient(['#ff5555', '#ffb86c', '#f1fa8c']);
console.log(fire('¡Colores reusados!'));
console.log(ascii.banner('FIRE', { colorFn: fire }));Drop-in replacement para 1.2.2.
v1.2.2 — Pulido de calidad
Release patch enfocado en ergonomía de API y refinamientos de robustez.
- ✨
animateGradientahora es thenable —await animateGradient(...)directo sin.done - 🎯 Códigos de error estables — los errores de tema llevan propiedad
.code(ANSIMAX_UNKNOWN_THEME, etc.) paracatchprogramático - 🛡️ Seguridad en sandboxes —
animateGradientya no crashea cuandoprocess.stdoutno está disponible (workers, edge runtimes) - 📖 Mejor JSDoc —
gradient()ahora muestra IntelliSense completo con ejemplos - 🐛 Fix de README — snippet de Easing Curves ahora es ejecutable copy-paste
Drop-in replacement para 1.2.0.
v1.2.0 — Fase 2 completa: gradientes animados, easing y cónicos
Release minor que cierra el roadmap del motor de gradientes con tres features potentes:
- 🌊
animateGradient()— flujo de color en el tiempo con ciclo de vida apropiado (Promise, signal, fps, direction) - 📐 Curvas de interpolación —
linear/ease-in/ease-out/ease-in-out/cubic-bezier/ funciones personalizadas - ⭕ Gradientes cónicos —
gradientRect({ style: 'conic', startAngle })para barridos radiales
import { animateGradient } from 'ansimax';
const ctrl = animateGradient('Cargando...', ['#ff79c6', '#bd93f9', '#8be9fd']);
await sleep(3000);
ctrl.stop();Totalmente retrocompatible — todo programa 1.1.x corre idénticamente.
v1.1.2 — Madurez y robustez
Release patch enfocado en refinamientos de calidad — sin cambios en la API.
- 🛡️ Bump defensivo de
process.setMaxListeners— previeneMaxListenersExceededWarningen setups con HMR / nodemon / ts-node-dev donde los módulos de ansimax re-registran handlers de restauración de cursor - 🧪
TypeErroruniforme para validación de themes —themes.register()ahora arroja consistentementeTypeErrorpara errores estructurales / de tipo (antes era mezcla deErroryTypeError) - 🎯
themes.use()arrojaRangeErrorpara nombres de tema desconocidos (antesError) — mejor match semántico con "valor fuera del set permitido" - 📝 Re-exports más limpios en el barrel —
