npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

ansimax

v1.7.1

Published

Zero-dependency CLI rendering library: colors, gradients, animations, ASCII art, pixel art, components, and themes — all in TypeScript.

Readme

The ultimate CLI rendering library for Node.js

Colors • Gradients • Animations • ASCII Art • Pixel Art • Trees • Components • Themes

License npm TypeScript Coverage Tests Zero deps Node ESM%20%2B%20CJS

English · Español


🎬 Preview


🌟 What is Ansimax?

Ansimax is a batteries-included rendering library for building beautiful terminal UIs in Node.js. One package replaces a stack of 8+ dependencies — colors, gradients, ASCII art, spinners, progress bars, tables, menus, trees, themes, pixel art — combined into a single coherent TypeScript API with zero runtime dependencies.

npm install ansimax
import { color, gradient, ascii, loader, sleep } from 'ansimax';

console.log(ascii.banner('hello', {
  colorFn: (t) => gradient(t, ['#ff79c6', '#bd93f9', '#8be9fd']),
}));

const stop = loader.spin('Building project', { color: '#bd93f9' });
await sleep(1500);
stop('Build complete', true);

💡 Why Ansimax?

| Without Ansimax | With Ansimax | |---|---| | Install 8+ packages: chalk, gradient-string, figlet, ora, cli-progress, cli-table3, boxen, inquirer | One install: ansimax | | Mix incompatible APIs, different paradigms, conflicting types | Consistent functional API, single source of truth | | No coherent theme system across packages | Built-in themes (Dracula, Nord, Matrix, Cyberpunk, +5) | | Manual cursor cleanup, no crash safety | Reference-counted cursor + crash handlers built in | | No AbortSignal support in most CLI libs | Every animation, loader, and prompt is abortable | | Each lib brings its own runtime fallback logic | Unified NO_COLOR / FORCE_COLOR / TTY detection | | No memory bounds on color caches | Bounded LRU caches everywhere (no leaks under load) |


🆚 Comparison with the Node.js ecosystem

Ansimax replaces a stack of popular Node.js libraries with one coherent, typed, zero-dependency package:

| Feature | chalk | gradient-string | ora | cli-progress | figlet | boxen | inquirer | cli-table3 | Ansimax | |---|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:|:-:| | Basic + 256 colors | ✅ | — | — | — | — | — | — | — | ✅ | | Truecolor with adaptive fallback | ✅ | ✅ | — | — | — | — | — | — | ✅ | | Multi-stop gradients | — | ✅ | — | — | — | — | — | — | ✅ | | Animated gradients | — | — | — | — | — | — | — | — | ✅ | | Easing curves (5 presets + custom) | — | — | — | — | — | — | — | — | ✅ | | Conic gradients (radial sweep) | — | — | — | — | — | — | — | — | ✅ | | ASCII banners | — | — | — | — | ✅ | — | — | — | ✅ | | Image → ASCII converter | — | — | — | — | — | — | — | — | ✅ | | Figlet .flf font parser | — | — | — | — | ✅ (own) | — | — | — | ✅ (250+ fonts) | | Custom font registry | — | — | — | — | partial | — | — | — | ✅ | | Boxes with multiple styles | — | — | — | — | — | ✅ | — | — | ✅ (6 styles) | | Spinners (multiple styles) | — | — | ✅ | — | — | — | — | — | ✅ (11 styles) | | Animated progress bars | — | — | — | ✅ | — | — | — | — | ✅ | | Hierarchical/parallel tasks | — | — | — | — | — | — | — | — | ✅ | | Tables (multi-line, ANSI-aware) | — | — | — | — | — | — | — | ✅ | ✅ | | Interactive menus + multi-select | — | — | — | — | — | — | ✅ | — | ✅ | | Trees with cycle detection | — | — | — | — | — | — | — | — | ✅ | | Split layouts (vsplit/hsplit) | — | — | — | — | — | — | — | — | ✅ (v1.3.0) | | JSON colored pretty-printer | — | — | — | — | — | — | — | — | ✅ (v1.3.0) | | CSS Grid (colSpan/rowSpan/areas) | — | — | — | — | — | — | — | — | ✅ (v1.4.1–v1.4.4) | | Markdown → terminal renderer | — | — | — | — | — | — | — | — | ✅ (v1.4.0–v1.4.4) | | Syntax highlighting (js/ts/json/bash) | — | — | — | — | — | — | — | — | ✅ (v1.4.5) | | Pixel art + canvas + sprites | — | — | — | — | — | — | — | — | ✅ | | Theme system + per-instance isolation | — | — | — | — | — | — | — | — | ✅ | | AbortSignal everywhere | — | — | partial | — | — | — | partial | — | ✅ | | NO_COLOR env support | ✅ | partial | partial | — | — | — | — | — | ✅ | | Stable error codes (ANSIMAX_*) | — | — | — | — | — | — | — | — | ✅ | | TypeScript-first (strict mode) | partial | partial | ✅ | partial | partial | ✅ | partial | partial | ✅ | | Zero runtime dependencies | ✅ | — | — | — | — | — | — | — | ✅ | | ESM + CJS dual export | partial | partial | ✅ | ✅ | partial | ✅ | partial | partial | ✅ | | Test coverage | ~95% | partial | partial | partial | partial | partial | partial | partial | ~98% (3000+ tests) |

Comparison reflects what each library officially supports at time of writing. Some libraries can be combined to approach ansimax's feature set, but at the cost of bundle size, version-skew bugs, and inconsistent APIs.


📦 Installation

npm install ansimax
# or
pnpm add ansimax
# or
yarn add ansimax

Requirements: Node.js ≥ 18. ESM and CJS both supported. Examples published with the package — see /examples.


⚡ 30-second example

import { color, gradient, loader, ascii, sleep } from 'ansimax';

console.log(ascii.banner('deploy', {
  colorFn: (t) => gradient(t, ['#ff6b6b', '#feca57', '#48dbfb']),
}));

const stop = loader.spin('Building project', { color: '#bd93f9' });
await sleep(1500);             // simulate async work
stop('Build complete', true);  // ✓ + success color

console.log(color.green('✓') + ' Ready in ' + color.bold('1.4s'));

🚀 Quick Start

import { configure, color, themes, gradient } from 'ansimax';

// Global configuration
configure({ theme: 'dracula', animationSpeed: 'normal' });

// Basic styling
console.log(color.red('error'));
console.log(color.bold(color.cyan('important')));

// Multi-stop gradient
console.log(gradient('rainbow text', [
  '#ff5555', '#ffaa00', '#ffff00',
  '#00ff00', '#0099ff', '#cc44ff',
]));

// Switch theme — fires subscribers
themes.use('cyberpunk');
console.log(themes.primary('cyberpunk primary'));

✨ Features

  • 🎨 Colors — Truecolor / 256 / basic with adaptive fallback. NO_COLOR / FORCE_COLOR / TTY detection
  • 🌈 Gradients — Multi-stop linear, radial, diagonal, arbitrary-angle. Custom presets via registerPreset
  • 🔠 ASCII Art — Banners (big/small fonts), boxes (6 styles), dividers, logos. Stream API + custom font registry
  • 🖼️ Pixel Art — Sprites, alpha blending, dithered gradients, canvas with dirty-rect rendering, braille mode (2×4 sub-pixel)
  • 🌳 Trees — Builder + plain-data API, 4 styles, per-node colors/icons, max-depth, cycle detection, walk/find/map/filter algorithms
  • 🎞️ Animations — Typewriter, fade, slide, pulse, wave, glitch, reveal. AbortSignal-aware, reducedMotion mode
  • ⏳ Loaders — 11 spinner styles, animated bars, hierarchical/parallel tasks, countdowns, multi-spinner manager
  • 🎬 Frames — Sequenced playback with pause/resume/seek, live push-based renderer, drift-corrected timing, morph
  • 🧱 Components — Tables (ANSI-aware, multi-line cells), badges, status lines, sections, columns, timelines, interactive menus
  • 🎨 Themes — 8 built-ins (Dracula, Nord, Monokai, Cyberpunk, Pastel, Matrix, Ocean, Sunset). Per-instance isolation, onChange listeners, bg* helpers
  • ⚙️ Configure — Centralized config with subscribers, batched updates, withConfig() temporary overrides, strict mode
  • 🛠️ Utils — ANSI primitives, cursor control, terminal hyperlinks (OSC 8), setTitle, safeJson, onResize, debounce/throttle/memoize

📸 Showcase

Colors & Gradients

import { color, gradient, rainbow } from 'ansimax';

// Basic colors
console.log(color.red('red'), color.green('green'), color.blue('blue'));

// Style modifiers
console.log(color.bold('bold'), color.italic('italic'), color.underline('underlined'));

// Multi-stop gradient
console.log(gradient('fire to ocean', ['#ff6b6b', '#feca57', '#48dbfb']));

// Built-in rainbow preset
console.log(rainbow('built-in rainbow preset'));

Animated Gradients (v1.2.0)

import { animateGradient, sleep } from 'ansimax';

// Color flow animation — runs until you call stop()
const ctrl = animateGradient('Loading...', ['#ff79c6', '#bd93f9', '#8be9fd'], {
  duration: 2000,    // ms per cycle
  fps: 30,
  direction: 'forward',  // or 'reverse'
});

await sleep(3000);
ctrl.stop();

// v1.2.2: await directly (no .done needed)
await animateGradient('Done!', ['#50fa7b', '#bd93f9'], {
  infinite: false, cycles: 2, duration: 800,
});

Easing Curves (v1.2.0)

import { gradient } from 'ansimax';

const stops = ['#ff79c6', '#bd93f9', '#8be9fd'];

// Five built-in easings + custom function support
console.log(gradient('hello world', stops, { easing: 'linear' }));
console.log(gradient('hello world', stops, { easing: 'ease-in' }));
console.log(gradient('hello world', stops, { easing: 'ease-out' }));
console.log(gradient('hello world', stops, { easing: 'ease-in-out' }));
console.log(gradient('hello world', stops, { easing: 'cubic-bezier' }));

// Or pass your own easing function (t → eased t, both in [0,1])
console.log(gradient('hello world', stops, { easing: (t) => t * t * t }));

Conic Gradients (v1.2.0)

import { gradientRect } from 'ansimax';

// Radial sweep around center — rainbow wheel
console.log(gradientRect({
  width: 30, height: 15,
  colors: ['#ff0000', '#ffff00', '#00ff00', '#00ffff', '#0000ff', '#ff00ff', '#ff0000'],
  style: 'conic',
  startAngle: 0,   // rotation angle in degrees
  dither: 'bayer',
}));

Reusable Gradients (v1.2.3)

import { createGradient, reverseGradient, ascii } from 'ansimax';

// Pre-resolve hex stops once — significantly faster for repeated use
const fire = createGradient(['#ff5555', '#ffb86c', '#f1fa8c']);

console.log(fire('First line'));
console.log(fire('Second line'));
console.log(fire('Third line'));

// Use as a colorFn for banners — same ColorFn signature
console.log(ascii.banner('FIRE', { colorFn: fire }));

// v1.2.4: inspect metadata
console.log('Stops:', fire.stops);             // → ['#ff5555', '#ffb86c', '#f1fa8c']
console.log('Resolved:', fire.resolvedStops);  // → [{r:255,g:85,b:85}, ...]

// v1.2.4: reverse a gradient (preserves default options)
const ice = reverseGradient(fire);
console.log(ice('Cool side'));

// Per-call options still work — perfect for animation
for (let p = 0; p < 1; p += 0.05) {
  process.stdout.write('\r' + fire('flowing', { phase: p }));
  await new Promise((r) => setTimeout(r, 50));
}

ASCII Art

import { ascii, gradient } from 'ansimax';

console.log(ascii.banner('HELLO', {
  font: 'big',
  align: 'center',
  colorFn: (t) => gradient(t, ['#ff79c6', '#bd93f9']),
}));

console.log(ascii.box('Rainbow box!', { padding: 1, borderStyle: 'rounded' }));

Image → ASCII (v1.2.5)

import { ascii } from 'ansimax';
import sharp from 'sharp';

// Get raw RGB pixels from any image library — example using `sharp`.
// You can use jimp, pngjs, canvas, or any decoder. Ansimax stays zero-deps.
const { data, info } = await sharp('./photo.png')
  .raw()
  .toBuffer({ resolveWithObject: true });

// Convert raw RGB buffer → PixelGrid (a 2D array of { r, g, b } objects)
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);
}

// Now use ansimax — multiple ways:

// 1. Monochrome
console.log(ascii.fromImage(pixels, { width: 80 }));

// 2. Color + Floyd-Steinberg dithering + detailed ramp
console.log(ascii.fromImage(pixels, {
  width: 100,
  color: true,
  dither: 'floyd-steinberg',
  ramp: 'detailed',
}));

// 3. Edge-detection mode (line art)
console.log(ascii.fromImage(pixels, {
  width: 80,
  edgeDetect: 'sobel',
  edgeThreshold: 50,
  ramp: 'blocks',
}));

// 4. Face mode for portraits (boosts midtone contrast)
console.log(ascii.fromImage(pixels, {
  width: 60,
  ramp: 'detailed',
  faceMode: true,
}));

Figlet Fonts (v1.2.5)

import { readFileSync } from 'node:fs';
import { parseFiglet, ascii, gradient } from 'ansimax';

// Download fonts from http://www.figlet.org/fontdb.cgi
const font = parseFiglet(readFileSync('./standard.flf', 'utf8'));

console.log(ascii.figletText('Hello!', font));

// With color
console.log(ascii.figletText('STYLE', font, {
  colorFn: (t) => gradient(t, ['#ff79c6', '#bd93f9', '#8be9fd']),
}));

Trees

import { tree, color } from 'ansimax';

const project = tree({ label: 'my-app', icon: '📦', color: color.bold });
const src = project.add({ label: 'src', icon: '📁' });
src.addLeaf({ label: 'index.ts', icon: '📄' });
src.addLeaf({ label: 'app.ts',   icon: '📄' });

console.log(project.render({
  style: 'rounded',
  palette: [color.cyan, color.green, color.magenta],
  guideColor: color.dim,
}));

Pixel Art & Canvas

import { images, createCanvas, gradientRect, SPRITES } from 'ansimax';

// Built-in sprite
console.log(images.sprite('heart'));

// Smooth gradient with Bayer dither
console.log(gradientRect({
  width: 50, height: 4,
  colors: ['#ff6b6b', '#feca57', '#48dbfb'],
  dither: 'bayer',
}));

// Custom canvas
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();

Components

import { components, color } from 'ansimax';

console.log(components.table([
  ['Module',     'Status',                'Coverage'],
  ['colors',     color.green('● ready'),  '100%'],
  ['animations', color.green('● ready'),  '100%'],
  ['loaders',    color.green('● ready'),  '100%'],
], { borderStyle: 'rounded' }));

console.log(components.badge('VERSION', 'v1.7.0'));
console.log(components.badge('BUILD',   'passing'));

Timeline

import { components } from 'ansimax';

console.log(components.timeline([
  { label: 'Project init',   done: true,  time: '10:00' },
  { label: 'Build pipeline', done: true,  time: '10:15' },
  { label: 'Run tests',      done: false, time: '10:32' },
  { label: 'Deploy to npm',  done: false },
]));

Loaders & Progress

import { loader, sleep } from 'ansimax';

// Spinner with success/failure
const stop = loader.spin('Loading...', { color: '#bd93f9' });
await sleep(1500);
stop('Done!', true);   // ✓ green icon

// Animated progress bar
await loader.progressAnimate(100, 'Downloading', {
  color: '#50fa7b', delay: 25,
});

// Hierarchical tasks with parallel execution
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 });

Animations

import { animate, gradient, sleep } from 'ansimax';

await animate.typewriter('Welcome to the deployment wizard...', {
  speed: 30,
  colorFn: (t) => gradient(t, ['#bd93f9', '#ff79c6']),
});

await animate.fadeIn('Loading complete', { duration: 600 });

// Race steps against a timeout — never hang
await animate.parallel([
  async () => await sleep(500),   // simulated network check
  async () => await sleep(700),   // simulated database check
  async () => await sleep(400),   // simulated auth check
], { timeout: 5000 });

Themes

import { themes, createTheme } from 'ansimax';

// Built-in themes
themes.use('dracula');
console.log(themes.primary('hello'));

// Listen for changes
const off = themes.onChange((newTheme, oldTheme) => {
  console.log(`Theme: ${oldTheme.name} → ${newTheme.name}`);
});

// Multi-tenant: each instance fully isolated
const tenantA = createTheme('nord');
const tenantB = createTheme('matrix');

// Define a custom theme and register it ONLY in 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 themes include custom?', tenantA.list().includes('custom'));
console.log('tenantB themes include custom?', tenantB.list().includes('custom'));
//                                            ↑ false — full isolation

Panels — Split Layouts (v1.3.0)

import { panels, ascii } from 'ansimax';

// Side-by-side columns
const left  = ascii.box('Sidebar',   { borderStyle: 'rounded' });
const right = ascii.box('Main view', { borderStyle: 'rounded' });

console.log(panels.vsplit([left, right], { gap: 2, align: 'center' }));

// Vertical stacking
console.log(panels.hsplit([
  '── Application ──',
  ascii.box('Body content'),
  '── Footer ──',
], { gap: 1, align: 'center' }));

// Nested — sidebar + main inside an app shell
console.log(panels.hsplit([
  '── My App ──',
  panels.vsplit([
    ascii.box('Sidebar', { width: 20 }),
    ascii.box('Main',    { width: 40 }),
  ], { gap: 2 }),
  '── End ──',
]));

JSON Pretty-print (v1.3.0)

import { json } from 'ansimax';

// Colored, depth-aware pretty-printing
console.log(json.pretty({
  name: 'ansimax',
  version: '1.3.0',
  features: ['colors', 'gradients', 'panels'],
  stats: { tests: 2000, coverage: 0.98 },
  active: true,
}));

// Depth limit — collapses deep objects to {...}
const deeplyNested = { a: { b: { c: { d: { e: 'too deep' } } } } };
console.log(json.pretty(deeplyNested, { maxDepth: 2 }));

// Item limit — huge arrays show "... (N more)"
const largeArray = Array.from({ length: 50 }, (_, i) => `item_${i}`);
console.log(json.pretty(largeArray, { maxItems: 5 }));

// Circular references handled gracefully
const obj = { name: 'foo' };
obj.self = obj;
console.log(json.pretty(obj));   // → "self": [Circular]

📖 Documentation

The docs/ folder contains comprehensive examples for every module:

| Document | Description | |---|---| | docs/README.md | Documentation index — start here | | docs/examples-ts.md | 33 TypeScript examples (3 per module × 11 modules) | | docs/examples-mjs.md | 33 JavaScript ESM examples | | docs/examples-cjs.md | 33 JavaScript CommonJS examples | | docs/showcase.md | Complete demo app combining every module |

Every example is copy-paste runnable with realistic, mid-complexity scenarios — not just one-liners.


📚 Examples

Eleven production-grade examples ship in the npm package and are runnable directly. Find them in /examples once you install:

| File | What it demonstrates | |---|---| | 01-quick-smoke.ts | Quick smoke test — verifies every major import works | | 02-colors-gradients.ts | Every color fn, gradient types, presets, compose, chain API | | 03-ascii-banners.ts | Banners (big/small), 6 box styles, dividers, logo composer | | 04-trees.ts | Tree builder + plain-data API, 4 styles, palettes, algorithms (walk/find/map/filter) | | 05-components.ts | Tables, badges, status, sections, columns, timelines, progress bars | | 06-pixel-art.ts | Sprites, custom canvas, gradient rects with dither, transforms (flip/rotate) | | 07-animations.ts | typewriter, fadeIn/Out, slide, pulse, wave, glitch, reveal | | 08-loaders.ts | spinner styles, animated progress, hierarchical tasks, countdown | | 09-themes.ts | All 8 built-in themes, listeners, custom theme registration, per-instance isolation | | 10-everything.ts | Comprehensive showcase — every module exercised in one cohesive demo | | all-in-one.mjs | Full demo in ESM (plain JS with import) — no TypeScript needed | | all-in-one.cjs | Full demo in CommonJS (plain JS with require) — no TypeScript needed |

Run any example with:

# TypeScript examples
npx tsx examples/10-everything.ts

# Plain JS — ESM
node examples/all-in-one.mjs

# Plain JS — CommonJS
node examples/all-in-one.cjs

🎯 Use Cases

  • CLI installers & scaffolders — beautiful first-run experience (create-react-app, create-next-app style)
  • DevOps tools — deployment dashboards, build pipelines, health monitors
  • Dev experience — better test runners, lint output, error formatting
  • Interactive prompts — menus, confirmations, multi-select wizards
  • Data exploration — tables, trees, charts for terminal-first workflows
  • Status reporters — real-time progress, multi-task orchestration
  • ASCII intros — game launchers, demo splash screens, login banners

⚙️ Configuration

Global config affects every module that respects it (colors, themes, animation speed, etc.):

import { configure, getConfig, withConfig, onConfigKeyChange } from 'ansimax';

configure({
  colorMode:      'auto',     // 'none' | 'basic' | '256' | 'truecolor' | 'auto'
  animationSpeed: 'normal',   // 'slow' | 'normal' | 'fast' | 'instant'
  theme:          'dracula',  // any registered theme
  reducedMotion:  false,
});

// Listen for changes (per-key — avoids over-firing)
const off = onConfigKeyChange('theme', (newTheme, oldTheme) => {
  console.log(`Theme: ${oldTheme} → ${newTheme}`);
});

// Temporary override + auto-restore on completion or throw
await withConfig({ animationSpeed: 'fast' }, async () => {
  // ...your fast-mode code here...
});

// Strict mode catches config typos
// configure({ unknwnKey: 'x' }, { strict: true });  // throws RangeError

⚠️ Error codes

Several ansimax functions throw Error / TypeError / RangeError for invalid input. Catching by error code is the stable, recommended way to handle them programmatically — message text may evolve, but .code values are guaranteed semver-stable.

import { themes, ascii, parseFiglet } from 'ansimax';

try {
  themes.use('inexistent-theme');
} catch (e) {
  if (e.code === 'ANSIMAX_UNKNOWN_THEME') {
    themes.use('dracula');  // fallback
  } else {
    throw e;  // re-throw unexpected errors
  }
}

All error codes

| Code | Thrown by | Type | When | |---|---|---|---| | ANSIMAX_INVALID_THEME | themes.register | TypeError | Theme value is not a plain object | | ANSIMAX_INVALID_THEME_NAME | themes.register | TypeError | Theme has missing/empty name | | ANSIMAX_UNKNOWN_THEME | themes.use | RangeError | Requested theme name not registered | | ANSIMAX_INVALID_FONT_NAME | ascii.registerFont | TypeError | Empty or non-string font name | | ANSIMAX_RESERVED_FONT_NAME | ascii.registerFont | Error | Overwriting built-in font without { force: true } | | ANSIMAX_INVALID_FIGLET_INPUT | parseFiglet | TypeError | Non-string or empty .flf content | | ANSIMAX_INVALID_FIGLET_HEADER | parseFiglet | TypeError | First line is not a valid FIGfont header | | ANSIMAX_INVALID_FIGLET_HEIGHT | parseFiglet | TypeError | Header declared zero/negative height |


🧩 Ecosystem packages

The ansimax ecosystem is structured in two tiers — companion packages that extend the core, and independent evolutions that target different platforms.

@ansimax/* — Companion packages

Scoped packages that extend ansimax without breaking its zero-dependency promise. Each is published independently but shares ansimax's philosophy and naming.

| Package | Status | Description | |---|:-:|---| | ansimax | ✅ stable | Terminal-rendering core. Zero dependencies. | | @ansimax/image | 🟡 planned | Image-to-ASCII loader — PNG/JPEG/WebP from file/buffer/URL | | @ansimax/cli | 🟡 planned | Standalone binary — npx @ansimax/cli demo, font browser, image converter | | @ansimax/fonts | 🟡 planned | 250+ figlet .flf fonts pre-bundled, ready to use | | @ansimax/sprites | 🔴 future | Curated sprite library (animals, UI icons, technical diagrams) | | @ansimax/video | 🔴 future | Video frame extraction → ASCII playback | | @ansimax/themes-extra | 🔴 future | Community-contributed themes pack |

How they connect:

                ┌─────────────────────────────┐
                │   ansimax  (zero deps)      │  ← core, you always install
                │   • colors, ASCII, panels   │
                │   • types: PixelGrid, etc.  │
                └────────────┬────────────────┘
                             │ peer dependency
        ┌────────────────────┼────────────────────┐
        ▼                    ▼                    ▼
  @ansimax/image      @ansimax/cli         @ansimax/fonts
  (deps: jimp)        (binary)             (data only)

Each companion declares "ansimax": "^X.Y.Z" as peerDependency — semver-coordinated, never duplicated, never out of sync.

ansimax-* — Independent evolutions

Standalone projects that build alongside ansimax for different platforms. Not companions — these are separate identities with their own scope and release cycle.

| Package | Status | Description | |---|:-:|---| | ansimax-native | 🔴 future | Rust + TS rewrite of the rendering hot path. Native performance via napi-rs. Same API surface as ansimax. | | ansimax-web | 🔴 future | Browser rendering layer. ANSI → HTML/CSS conversion + canvas rendering. For demos, docs sites, web terminals. |

Sub-ecosystems: each of these can have their own scoped sub-packages (@ansimax-native/image, @ansimax-web/canvas, etc.) over time.

Why two naming conventions?

Industry convention used by many mature ecosystems (Babel, Vue, Webpack, etc.):

  • @scope/* = "same project family, coordinated release, same team"
  • name-* = "inspired by / works alongside, independent identity"

By using both, ansimax signals:

  • The core (ansimax) stays small, zero-dep, focused on terminal rendering
  • The ecosystem (@ansimax/*) grows around it as opt-in extensions
  • Evolutions (ansimax-native, ansimax-web) explore different platforms without compromising the core

💡 Coming soon: When @ansimax/image or similar packages are released, this section will link to them. Want one of these built sooner? Open an issue to vote.


🛣️ Roadmap

Ansimax is being built toward a full terminal rendering platform — a Node-native answer to what Python developers get from rich + textual combined, with Node-specific improvements where it matters.

The roadmap intentionally targets — and aims to surpass — gaps that even mature Python TUI libraries haven't fully solved: live-diff renderers, animated gradients, terminal image protocols, and a true reactive layer.

✅ Phase 1 — Core foundation

  • [x] Styling engine — ANSI 16 / 256 / truecolor with adaptive fallback
  • [x] Hex + RGB helpers with clamping and validation
  • [x] NO_COLOR / FORCE_COLOR env support + non-TTY auto-detection
  • [x] AbortSignal integration across animations and loaders
  • [x] compose() style stacking with single-reset emission
  • [x] Bounded LRU escape cache (512 entries, packed-RGB keyed)
  • [x] Custom preset registry (registerPreset, listPresets)

✅ Phase 2 — Gradient engine

  • [x] Linear gradients (multi-stop)
  • [x] Rainbow + 6 built-in presets
  • [x] Radial gradients (in gradientRect)
  • [x] Diagonal gradients
  • [x] Arbitrary-angle gradients
  • [x] Bayer 4×4 dithering for smooth tonal transitions
  • [x] Single-stop UX (CSS-style behavior)
  • [x] Animated gradients — color flow over time with animateGradient() (v1.2.0)
  • [x] Gradient interpolation curves — linear / ease-in / ease-out / ease-in-out / cubic-bezier / custom (v1.2.0)
  • [x] Conic gradients — radial sweep with style: 'conic' (v1.2.0)
  • [x] Mirror gradients — symmetric A→B→C→B→A fill via mirror (v1.4.13)
  • [x] Interpolation space — rgb / hsl / oklab color-space blending (v1.4.13)
  • [x] 16 named gradient presets — viridis, plasma, pastel, cyberpunk, and more (v1.6.0)
  • [x] presetStops() + gradientRect({ preset }) — reuse named preset colors anywhere (v1.6.1)
  • [x] gradientScale() — sample a gradient into N discrete palette colors (v1.6.3)

✅ Phase 3 — ASCII engine

  • [x] Block fonts (big, small)
  • [x] Banner with gradient + alignment + per-char coloring
  • [x] Box drawing (6 border styles)
  • [x] Divider with style variants
  • [x] Logo composer (gradient + box wrapping)
  • [x] Custom font registry (registerFont, hasFont, listFonts)
  • [x] Stream API (ascii.stream() with AbortSignal)
  • [x] Image → ASCII converter — ascii.fromImage() with luminance mapping (v1.2.5)
  • [x] Color ASCII rendering — preserve image colors via color: true (v1.2.5)
  • [x] Image dithering — Floyd-Steinberg error diffusion (v1.2.5)
  • [x] 4 dithering algorithms — Floyd-Steinberg, Atkinson, JJN, Sierra (v1.6.2)
  • [x] Face-optimized ASCII — histogram stretching for portraits (v1.2.5)
  • [x] Figlet font support — .flf parser + renderer (parseFiglet + ascii.figletText) (v1.2.5)
  • [x] Edge detection — Sobel operator integrated in fromImage (v1.2.5, bonus)
  • [x] ASCII ramp registry — registerAsciiRamp + named presets (v1.4.13)

✅ Phase 4 — Terminal UI primitives

  • [x] Tables (irregular rows, multi-line cells, ANSI-aware)
  • [x] Boxes with multiple styles
  • [x] Status messages + badges (with border option)
  • [x] Timelines with done/pending states
  • [x] Interactive menus (single + multi-select)
  • [x] Columns layout (truncate/wrap overflow)
  • [x] Sections (gradient headers with auto-width)
  • [x] Trees (collapsible, max-depth, cycle-safe)
  • [x] Panels — split layouts: hsplit, vsplit with alignment + nesting (v1.3.0)
  • [x] Balanced table wrap — minimum-raggedness word wrap for even cell lines (v1.6.2)
  • [x] JSON/YAML pretty-printing — colored, depth-limit, circular-safe (v1.3.0)
  • [x] Grid system — CSS Grid-inspired: colSpan, rowSpan (mark-and-pack), flow, cellWidth/cellHeight, and gridAreas template areas (v1.4.1–v1.4.4)
  • [x] Markdown rendering — headings (ATX + setext), lists (nested + task lists), code blocks, tables, blockquotes, inline styles, CommonMark escapes, autolinks, reference links, footnotes, HTML blocks (v1.4.0–v1.4.11)
  • [x] Markdown theme registry — custom palettes via registerMarkdownTheme (v1.4.11)
  • [x] Syntax highlighting — built-in grammars for JS/TS/JSON/Bash with aliases (v1.4.5)
  • [x] Layouts — CSS Grid (grid/gridAreas) + flexbox-style flow (flex with justify + grow, v1.4.7)
  • [x] Logging integration — createLogger with levels, fields, child loggers, transports + console/pino/winston shims (v1.4.12)

✅ Phase 5 — Cursor & screen control

  • [x] Cursor visibility, save/restore, positioning, line navigation
  • [x] Screen clearing (line, area, full)
  • [x] Reference-counted cursor (overlapping calls safe)
  • [x] Crash-safe restore (exit/SIGINT/SIGTERM handlers)
  • [x] Terminal hyperlinks (OSC 8)
  • [x] Window title (OSC 2)
  • [x] Bell (BEL)
  • [x] Managed alternate screen — createScreen (alt buffer, guaranteed restore on crash) — TUI foundation (v1.7.0)

✅ Phase 6 — Animation engine

  • [x] Typewriter, fadeIn, fadeOut, slide, pulse, wave, glitch, reveal
  • [x] All AbortSignal-aware
  • [x] reducedMotion mode for accessibility
  • [x] Frame morph (text → text interpolation, cinematic decryption)
  • [x] parallel() with timeout
  • [x] Signal propagation to nested animations
  • [x] Easing functions library (31 standard easings: cubic, elastic, bounce, back) (v1.3.5)
  • [x] Animation composition (parallel + sequence + delay DSL) (v1.5.0)
  • [x] Spring physics animations (react-spring style) (v1.5.0)
  • [x] Tween engine (interpolate any value type) (v1.5.0)

✅ Phase 7 — Progress ecosystem

  • [x] Spinners (11 styles) with color + AbortSignal
  • [x] Animated progress bars
  • [x] Multi-task runners (sequential + parallel)
  • [x] Countdown timers
  • [x] Multi-spinner manager (stacked concurrent spinners)
  • [x] Hierarchical tasks (parent + subtasks rollup)
  • [x] Live ETA estimation (rolling average) (v1.6.0)
  • [x] Live refresh diff renderer (no flicker, only redraw changed lines) (v1.6.0)
  • [x] Progress groups (named groups with shared theme) (v1.6.1)
  • [x] Throughput meters (bytes/sec, ops/sec with auto-scaling units) (v1.6.0)

🟡 Phase 8 — Capability detection

  • [x] TTY detection (auto-disable in pipes/CI)
  • [x] NO_COLOR / FORCE_COLOR env support
  • [x] Color depth detection (16 / 256 / truecolor)
  • [x] CI provider detection (GitHub Actions, CircleCI, GitLab, Buildkite, Drone, Travis)
  • [x] Terminal program detection (iTerm, vscode, WezTerm, Hyper, Apple_Terminal)
  • [x] Windows Terminal detection (WT_SESSION)
  • [x] Unicode width detection (CJK halfwidth/fullwidth, emoji clusters, ZWJ sequences) (v1.6.5)
  • [x] Image protocol detection — detection only, not an encoder: reports which protocol the terminal advertises so callers can plug in their own; ansimax itself renders via the universal path (v1.6.4)
  • [ ] Terminal capability database (full xterm capability flags + version probes)
  • [x] Font metrics detection — cell aspect ratio (cellAspectRatio, aspectScale) for pixel-accurate sub-cell layouts; overridable, defaults to the near-universal 0.5 (v1.7.1)

🟡 Phase 9 — Advanced rendering

  • [x] Dirty-rectangle canvas (only redraw changed pixels)
  • [x] Bounded LRU caches (escape sequences, render cache, ANSI cache)
  • [x] Drift-corrected timing (animations stay locked to wall-clock)
  • [ ] Diff renderer (line-level damage tracking for full UIs)
  • [ ] Virtual buffer (compose UI without writing to stdout)
  • [ ] Z-index / layering (overlap panels with priority)
  • [ ] Mouse event support (click, hover, drag, scroll wheel)
  • [ ] Keyboard event abstraction (arrow keys, modifiers, key sequences, dead keys)
  • [ ] Full TUI framework (reactive components — Textual-equivalent for Node)

🔴 Phase 10 — Terminal charts

  • [~] Bar charts (horizontal + vertical, grouped, stacked) — horizontal bar + histogram (v1.6.6)
  • [x] Line charts (with braille for sub-character resolution) — lineChart, 8× sub-pixel, multi-series, Wu-style per-cell coverage color (v1.7.1)
  • [x] Sparklines (inline mini-charts for status bars) (v1.6.6)
  • [ ] Area charts (filled with gradients)
  • [ ] Heatmaps (color-mapped 2D grids)
  • [ ] Pie / donut charts (with percentage labels)
  • [ ] Scatter plots
  • [ ] Box plots / candlestick charts
  • [ ] Real-time streaming charts (live data feed with rolling window)
  • [ ] Plot composer (multi-chart dashboards with shared axes)

🔴 Phase 11 — Forms & Input

  • [ ] Text input prompts (with autocomplete + history)
  • [ ] Password prompts (masked, strength meter)
  • [ ] Confirm dialogs (yes/no with default highlight)
  • [ ] Numeric input (with min/max validation)
  • [ ] Date/time pickers (calendar widget)
  • [ ] File picker (filesystem navigator)
  • [ ] Form composer (multi-field with validation + error display)
  • [ ] Wizard flows (multi-step forms with back/forward, progress indicator)

🔴 Phase 12 — Image & media

Philosophy: ansimax renders images through universal, self-generated methods that work in any terminal — never by depending on a proprietary protocol. Kitty/iTerm/Sixel are treated as detection (Phase 8); emitting them is optional and left to the caller. renderImageAuto already picks the best portable method automatically.

  • [x] Universal auto-render — renderImageAuto picks half-blocks (color) or ASCII (no color) by capability (v1.6.7)
  • [x] Half-block rendering — ▀/▄ with fg/bg color, double vertical resolution, any truecolor terminal
  • [ ] Sixel encoder (open DEC format — pure algorithm, portable to any Sixel terminal)
  • [x] Perceptual quantization — rgbTo256Perceptual / nearestPerceptual via Oklab ΔE (kills banding vs RGB L2) (v1.7.0)
  • [ ] PNG/JPEG decode → pixel grid (feed into the universal renderers)
  • [ ] QR code generation (with size + ECC level options)
  • [ ] Bar code generation (Code 128, EAN-13)
  • [ ] (detection-only, opt-in) iTerm2 / Kitty encoders — caller-supplied, never the default

🔴 Phase 13 — Plugin system

  • [ ] Plugin API for custom components
  • [ ] Theme marketplace
  • [ ] Custom font registration via npm packages
  • [ ] Community animations registry
  • [ ] Capability provider interface (plug in custom detectors)
  • [ ] Renderer plugins (swap stdout for any writable stream)

🔴 Phase 14 — Reactivity layer (TUI framework)

  • [ ] Component lifecycle (mount/unmount/update hooks)
  • [ ] Reactive state (auto re-render on data change, signals or hooks)
  • [ ] Virtual DOM diffing (line-level updates)
  • [ ] Event bus (component communication)
  • [ ] Application loop (single render tree with full lifecycle)
  • [ ] Routing (multi-screen apps with history)
  • [ ] DevTools integration (inspect component tree, mark changed nodes)
  • [ ] CSS-in-TS styling (scoped styles per component)

🔵 Phase 15 — AXSS / AXB styling pipeline (ecosystem)

A dedicated stylesheet language for terminal UIs (AXSS — Ansi eXtended Style Sheets) that compiles to a portable binary format (AXB — Ansi Binary) consumed by ansimax-native. The design is frozen; implementation waits on ansimax-native (there is no engine to consume AXB yet, so this is deliberately not rushed).

  • [ ] AXSS language — high-level terminal stylesheets (Button { color: yellow; padding: 1 2; }) with type / id / multi-class / state selectors
  • [ ] AXB binary format — portable, versioned, little-endian bytecode; magic + format version + minimum engine version + CRC; extensible sections
  • [ ] Declarative model — AXB describes state per selector, not imperative instructions; the engine decides when each state applies
  • [ ] Compile-time cascade & specificity — resolved by the compiler (id > class > type, ties → last rule wins); the runtime receives flattened StyleStates
  • [ ] Stable ID tables — PropertyId / StateId / ColorKind are part of the spec with explicit values, never reordered or recycled
  • [ ] Color encoding — named / ANSI-256 / RGB tri-form with a discriminant byte
  • [ ] ansimax axb inspect — a disassembler/debugger born alongside the compiler (with optional debug metadata: background: BLUE ← inherited from Button)
  • [ ] Multiple frontends (later) — CSS / TOML / YAML / JSON / XML all producing the same AST → the same AXB, making AXB the engine's universal format

Note: AXSS is the human-readable frontend; AXB is the compact binary the engine consumes. .axb is bytecode — low-level relative to AXSS, but high-level relative to the hardware (closer to WASM/SPIR-V than to machine code). It is designed to be shipped with your app, like a compiled shader.

Legend: ✅ Complete · 🟡 Partial · 🔴 Planned · 🔵 Designed (awaiting ansimax-native)


🧪 Testing

npm test              # Run all 3000+ tests
npm run test:watch    # Watch mode
npm run test:coverage # Coverage report

Coverage (as of v1.3.0):

| Metric | Score | |---|:-:| | Statements | ~98% | | Branches | ~95% | | Functions | ~99% | | Lines | ~99% | | Total tests | 2,000+ | | Test suites | 27 | | CI matrix | Node 18, 20, 22, latest | | Platforms tested | Linux, macOS, Windows |


🛠️ Requirements

  • Node.js ≥ 18
  • TypeScript ≥ 5.0 (for typed consumption — optional)
  • Terminal with truecolor support recommended (Windows Terminal, iTerm2, WezTerm, Kitty, modern xterm). Gracefully degrades to 256 / 16 / no-color.

🏗️ Project Structure

ansimax/
├── src/
│   ├── colors/         Color rendering + gradient engine
│   ├── themes/         Theme system + 8 built-ins
│   ├── ascii/          Banners, boxes, fonts
│   ├── animations/     Typewriter, fade, slide, pulse, wave, glitch, reveal
│   ├── loaders/        Spinners, progress, tasks, multi-loader
│   ├── frames/         Sequenced playback + live renderer + morph
│   ├── components/     Tables, badges, status, timelines, menus
│   ├── images/         Sprites, canvas, dithered gradients
│   ├── trees/          Tree builder + algorithms
│   ├── utils/          ANSI primitives + helpers
│   └── configure.ts    Global config + subscribers
├── examples/           10 examples (TS) + 2 (JS — ESM & CJS) — all features covered
└── __tests__/          27 test suites, 3000+ tests

📝 Changelog

v1.7.0 — Perceptual color, managed screen, spline gradients, lap timing

A larger minor. Highlights:

  • 🎨 Perceptual quantization — rgbTo256Perceptual, nearestPerceptual, oklabDistance (Oklab ΔE — kills banding vs RGB L2)
  • 🖥️ Managed alternate screen — createScreen (vim/htop-style full-screen with guaranteed restore) — TUI foundation
  • 🌈 Spline gradients — gradientColorSpline (Catmull-Rom C¹, smooth through multi-stops)
  • ⏱️ Lap stopwatch — createStopwatch (labelled splits, report(), slowest())
  • 🧪 +60 tests
import { createScreen, rgbTo256Perceptual, gradientColorSpline, createStopwatch } from 'ansimax';

await createScreen().run((s) => { s.moveTo(1,1); s.write('Full-screen app'); });
rgbTo256Perceptual(128, 64, 32);              // nearest xterm-256 by perceptual ΔE
gradientColorSpline(stops, 0.25);             // smooth multi-stop sampling
const sw = createStopwatch(); sw.lap('load'); // profile stages

Drop-in replacement for 1.6.7.

v1.6.7 — Universal image auto-render + cubic-bezier easing + event counter

  • 🖼️ renderImageAuto — picks half-blocks (color) or ASCII (no color) by capability; portable, no proprietary encoders
  • 📐 cubicBezier(x1,y1,x2,y2) — CSS-style easing factory (Newton–Raphson solve; supports overshoot)
  • 🔢 createCounter — event counter with EMA rate, total, and lifetime average
  • 🧪 +50 tests
import { renderImageAuto, cubicBezier, createCounter } from 'ansimax';

const { output, method } = renderImageAuto(pixels);  // 'halfblock' | 'ascii'
const ease = cubicBezier(0.25, 0.1, 0.25, 1);        // CSS "ease"
const c = createCounter(); c.tick(); c.formatRate();  // "1.2K/s"

On image protocols: ansimax renders via universal, self-generated methods (half-blocks / ASCII) that work in any terminal. Sixel/Kitty/iTerm are detection only — surfaced so callers can plug in their own encoder, never emitted by default.

Drop-in replacement for 1.6.6.

v1.6.6 — Inline charts (Phase 10 begins) + stepped easings

  • 📊 Inline charts — sparkline, bar, histogram (also the chart namespace)
  • 🪜 Stepped easings — steps(n, position), stepStart, stepEnd (CSS steps() style)
  • 〰️ Smoothstep easings — smoothStep, smootherStep (shader S-curves)
  • 🧪 +45 tests
import { sparkline, bar, histogram, steps } from 'ansimax';

sparkline([1, 5, 2, 8, 3, 7, 9, 4]);   // '▁▅▂▇▃▆█▄'
bar(0.66, { width: 12 });               // eighth-cell precision
histogram([{ label: 'GET', value: 1240 }, { label: 'POST', value: 430 }]);
steps(4);                               // staircase easing

Drop-in replacement for 1.6.5.

v1.6.5 — Unicode width detection + ETA smoothing + numeric table alignment

  • 📏 Unicode width detection — stringWidth, isFullWidth, isEmoji, isCombining
  • 📊 Rate formatters — formatPercent, formatRate ("1.5 MB/s", "1.2K req/s")
  • 📈 ETA EMA smoothing — createETA({ smoothing: 'ema' }) reacts faster to speed changes
  • 🔢 Auto-aligned numeric columns — ascii.table({ autoAlignNumbers: true })
  • 🧪 +40 tests
import { stringWidth, formatRate, createETA, ascii } from 'ansimax';

stringWidth('中文');                                  // 4
formatRate(1572864);                                 // "1.5 MB/s"
createETA({ total: 1000, smoothing: 'ema' });        // faster reaction
ascii.table(rows, { autoAlignNumbers: true });       // numbers right-aligned

Drop-in replacement for 1.6.4.

v1.6.4 — Image protocol detection + elapsed timer + colors refactor

  • 🖼️ Image protocol detection — detectImageProtocol() → 'kitty' / 'iterm' / 'sixel' / 'none'
  • ⏱️ createTimer — elapsed-time stopwatch (start/stop/reset, pause-aware)
  • 🧹 Colors refactor — shared core moved to colors/internal.ts; public API byte-for-byte identical
  • 🧪 +40 tests
import { detectImageProtocol, supportsInlineImages, createTimer } from 'ansimax';

detectImageProtocol();     // 'kitty' | 'iterm' | 'sixel' | 'none'
supportsInlineImages();    // boolean

const t = createTimer();
t.start(); /* ...work... */ t.stop();
t.formatted();             // "1.5s"

Drop-in replacement for 1.6.3.

v1.6.3 — Refactor: split animations + contrast/a11y + gradient scale

  • 🧹 Animations split — the ~1,100-line module is now 5 focused files; public API byte-for-byte identical
  • ♿ WCAG contrast helpers — relativeLuminance, contrastRatio, readableTextColor, meetsContrast
  • 🎨 gradientScale() — sample a gradient into N discrete palette colors
  • 🧪 +30 tests
import { contrastRatio, readableTextColor, gradientScale } from 'ansimax';

contrastRatio({ r: 0, g: 0, b: 0 }, { r: 255, g: 255, b: 255 }); // 21 (max)
readableTextColor({ r: 255, g: 235, b: 59 });                    // black on yellow
gradientScale(['#ff0000', '#0000ff'], 3);      // ['#ff0000','#800080','#0000ff']

Drop-in replacement for 1.6.2.

v1.6.2 — Advanced algorithms: dithering, balanced wrap, statistics

  • 🖼️ 4 dithering algorithms — floyd-steinberg, atkinson, jjn, sierra (error-diffusion kernels)
  • 📐 Balanced table wrap — minimum-raggedness word wrap (balancedWrap: true) for even cell lines
  • 🧮 7 math helpers — median, variance, stddev, percentile, quantize, catmullRom, gaussian
  • 🧪 +45 tests
import { ascii, balancedWrap, catmullRom, percentile } from 'ansimax';

ascii.fromImage(pixels, { dither: 'atkinson' });          // crisp, high contrast
ascii.table(rows, { wrap: true, balancedWrap: true });    // even wrapped lines

balancedWrap('I am a very long sentence here', 11);       // minimum raggedness
catmullRom(0, 10, 20, 30, 0.5);                            // → 15 (smooth spline)
percentile([1, 2, 3, 4, 5], 50);                          // → 3

Drop-in replacement for 1.6.1.

v1.6.1 — Phase 7 complete (progress groups) + gradient preset reuse

  • 📊 createProgressGroup — several named bars under one title/theme, flicker-free (completes Phase 7)
  • 🎨 presetStops(name) + hasPreset(name) — reuse a preset's colors anywhere
  • 🖼️ gradientRect({ preset }) — fill a rectangle from a named preset
  • 🧪 +45 tests
import { createProgressGroup, presetStops, gradientRect } from 'ansimax';

const group = createProgressGroup({ title: 'Deploying' });
group.add('api', 'API').add('web', 'Web');
group.update('api', 0.4, '12 MB/s');
group.complete('web');
group.render();

gradient('text', presetStops('viridis'), { mirror: true });
gradientRect({ width: 40, height: 10, preset: 'plasma' });

Drop-in replacement for 1.6.0.

v1.6.0 — Phase 7 progress meters + more gradient presets

  • ⏱️ createETA — rolling-average time-remaining estimator (eta(), rate(), progress())
  • 📊 createThroughput — bytes/sec or ops/sec with auto-scaling units ("1.5 MB/s")
  • 🖥️ createLiveRegion — flicker-free multi-line region: redraws only changed lines
  • 🎨 8 new gradient presets — viridis, plasma, pastel, cyberpunk, mono, mint, dusk, cotton (16 total)
  • 🧪 +35 tests
import { createETA, createThroughput, createLiveRegion } from 'ansimax';

const eta = createETA({ total: 1000 });
eta.update(downloaded);
console.log(eta.eta());              // "3.2s"

const tp = createThroughput({ unit: 'bytes' });
tp.update(bytesSoFar);
console.log(tp.format());            // "1.5 MB/s"

const region = createLiveRegion();
region.render(['A: 10%', 'B: 0%']);
region.render(['A: 100%', 'B: 0%']); // only line A rewritten

Drop-in replacement for 1.5.2.

v1.5.2 — Documentation audit: every example verified copy-paste-runnable

  • ✅ All 52 README examples executed against the real package and fixed (missing imports, self-contained snippets)
  • ✅ docs/examples-{mjs,cjs,ts}.md — 33/33 blocks each pass (ran ESM/CJS, type-checked TS); fixed 8 real TS API/type bugs
  • 🎬 showcase.md rewritten as one cohesive enterprise app ("Stardust Deploy") combining every module — not isolated snippets
  • 📝 No library code changed — documentation-only quality release

Drop-in replacement for 1.5.1.

v1.5.1 — Tween/spring quality-of-life: repeat, yoyo, callbacks, stagger

  • 🔁 repeat + yoyo — loop a tween N times (or Infinity), alternating direction
  • 📣 onStart / onComplete — lifecycle callbacks on tween and spring (not fired on abort)
  • 🎞️ stagger() — cascade a list of animations, each offset by gap × index
  • 🧪 +22 tests
  • 🔵 Roadmap: declared the frozen AXSS → AXB styling pipeline (Phase 15, awaiting ansimax-native)
import { tween, stagger } from 'ansimax';

const draw = (v) => process.stdout.write(`\r${v.toFixed(2)}`);
const ctrl = new AbortController();
setTimeout(() => ctrl.abort(), 1500);
await tween({ from: 0, to: 1, duration: 200, repeat: Infinity, yoyo: true, onUpdate: draw, signal: ctrl.signal });

// stagger a list — each row's animation starts 80ms after the previous
const rows = [{ setOpacity(v) {} }, { setOpacity(v) {} }, { setOpacity(v) {} }];
await stagger(rows.map((row) => (s) =>
  tween({ from: 0, to: 1, duration: 200, onUpdate: (v) => row.setOpacity(v), signal: s })
), 80);

Drop-in replacement for 1.5.0.

v1.5.0 — Phase 6 closure: tween engine, spring physics, composition DSL

  • 🎬 Tween engine — tween() interpolates numbers, arrays, and objects over time with easing
  • 🌱 Spring physics — spring() react-spring-style (stiffness/damping/mass)
  • 🔗 Composition DSL — sequence, parallel, delay, tweenStep, springStep
  • 🧪 +40 tests · Phase 6 complete
import { tween, spring, sequence, delay } from 'ansimax';

// `draw` is your render callback — here it just prints the current value
const draw = (v) => process.stdout.write(`\r${Math.round(v)}   `);

await tween({ from: 0, to: 100, duration: 1000, easing: 'easeOutCubic', onUpdate: draw });
await spring({ from: 0, to: 100, config: { stiffness: 210, damping: 20 }, onUpdate: draw });

await sequence([
  (s) => tween({ from: 0, to: 100, duration: 300, onUpdate: draw, signal: s }),
  delay(200),
  (s) => tween({ from: 100, to: 0, duration: 300, onUpdate: draw, signal: s }),
]);

All AbortSignal- and reducedMotion-aware. Drop-in replacement for 1.4.13.

v1.4.13 — Phase 2 & 3 improvements: mirror gradients, HSL interpolation, ramp registry

  • 🔁 Mirror gradients — mirror: true reflects the palette (A→B→C→B→A) on gradient, createGradient, gradientRect
  • 🎨 Interpolation space — interpolation: 'rgb' | 'hsl' | 'oklab' for vivid or perceptually-smooth blends
  • 🖼️ ASCII ramp registry — registerAsciiRamp + 3 new presets (minimal, thermal, hearts)
  • 🧪 +27 tests
import { gradient, registerAsciiRamp, ascii } from 'ansimax';

gradient('symmetric', ['#ff0000', '#00ff00', '#0000ff'], { mirror: true });
gradient('vivid', ['#ff0000', '#0000ff'], { interpolation: 'hsl' });

registerAsciiRamp('retro', ' .oO0');
// `pixels` is a 2D array of { r, g, b } — here a tiny 2×2 sample
const pixels = [
  [{ r: 0, g: 0, b: 0 }, { r: 255, g: 255, b: 255 }],
  [{ r: 128, g: 128, b: 128 }, { r: 0, g: 0, b: 0 }],
];
console.log(ascii.fromImage(pixels, { ramp: 'retro' }));

Drop-in replacement for 1.4.12.

v1.4.12 — Logging integration + Phase 4/2 improvements

  • 🪵 Logging — createLogger() with 7 levels, structured fields, child loggers, pluggable transports
  • 🔌 Drop-in shims — asConsole, pinoShim, winstonTransport
  • 🖊️ Markdown ==highlight== — GFM/Obsidian mark support
  • 📋 ascii.table caption — dimmed, centered note below the table
  • 🧪 +40 tests
import { createLogger } from 'ansimax';

const log = createLogger({ level: 'debug', name: 'api' });
log.info('server started', { port: 3000 });
log.child({ reqId: 'abc' }).debug('handling request');

Phase 4 is now complete (logging was the final item). Drop-in replacement for 1.4.11.

v1.4.11 — Phase 4 closure: theme registry, footnotes, HTML blocks

  • 🎨 Custom markdown themes — registerMarkdownTheme(name, palette), validated at registration
  • 📌 Footnotes — [^label] + [^label]: text, numbered by first reference (GFM behavior)
  • 🏷️ HTML blocks — htmlMode: 'strip' | 'raw' | 'hide' (CommonMark §4.6)
  • 🧪 +38 tests
import { registerMarkdownTheme, markdown } from 'ansimax';

registerMarkdownTheme('solarized', {
  h1: ['#b58900', '#cb4b16'], h2: '#cb4b16', h3: '#d33682',
  h4: '#6c71c4', h5: '#268bd2', h6: '#2aa198',
  code: '#b58900', codeBlockBorder: '#586e75', link: '#268bd2',
  blockquote: '#586e75', hr: '#586e75', tableHeader: '#cb4b16',
});

markdown.render('# Title\n\nCited[^a].\n\n[^a]: The note.', { theme: 'solarized' });

Phase 4 is now complete. Drop-in replacement for 1.4.10.

v1.4.10 — ascii module split + table minColWidth

  • 🧩 ascii/ module split — 1575-line index.ts → 9 focused modules (types/fonts/render/shapes/image/figlet/stream/table/index)
  • 📏 ascii.table minColWidth — floor on column shrinking so narrow columns stay legible
import { ascii } from 'ansimax';

const rows = [
  ['Name', 'Role', 'Location'],
  ['Ada Lovelace', 'Engineer', 'London'],
  ['Alan Turing', 'Researcher', 'Manchester'],
];
console.log(ascii.table(rows, { maxWidth: 30, minColWidth: 4 }));
// No column shrinks below 4 visible chars

The module split is pure rearrangement — the ascii namespace and all exports are 100% backward-compatible. The dependency graph is strictly layered and acyclic. Drop-in replacement for 1.4.9.

v1.4.9 — Table cell wrapping + coverage hardening

  • 📝 ascii.table cell wrapping — wrap: true word-wraps long cells to multiple lines instead of truncating
  • 🧪 Coverage hardening — closed remaining v1.4.8 branch gaps (reachable → tests, unreachable → documented istanbul ignore)
import { ascii } from 'ansimax';

ascii.table([
  ['id', 'description'],
  ['1', 'a fairly long description that wraps neatly across several lines'],
], { maxWidth: 40, wrap: true });

Column sizing runs first (water-filling), then cells wrap within the resulting widths. Rows grow to fit their tallest cell. wrap: false (default) keeps v1.4.8 ellipsis behavior.

Drop-in replacement for 1.4.8.

v1.4.8 — Grids, tables, wrapping + scroll regions

Four additive features, zero breaking changes:

  • 📊 ascii.table — auto-layout tables with 6 border styles + water-filling column sizing
  • 🔲 panels.wrap — flex-wrap-style block flow (greedy bin-packing)
  • 📐 grid per-cell align — cellAlign: ['start', 'center', 'end']
  • 🖥️ cursor.scrollRegion + cursor.batch — DECSTBM scroll regions + atomic writes (Phase 5)
  • 🧪 +36 tests
import { ascii, panels, cursor } from 'ansimax';

// Auto-sized table (widest column shrinks first when over budget)
console.log(ascii.table([
  ['Name', 'Role', 'Commits'],
  ['Ada', 'Author', '1200'],
], { align: ['left', 'left', 'right'], maxWidth: 40 }));

// Wrap cards to fit the terminal width
const cards = ['A', 'B', 'C', 'D'].map((c) => ascii.box(c, { padding: 1 }));
console.log(panels.wrap(cards, { maxWidth: 60, gapX: 2, gapY: 1 }));

// Pinned header/footer with a scrolling body
process.stdout.write(cursor.scrollRegion(2, 23));

Drop-in replacement for 1.4.7.

v1.4.7 — Reference links + flexbox layout

Two roadmap items, zero breaking changes:

  • 🔗 Markdown reference links — [text][ref], [text][], [shortcut] + [ref]: url "title" definitions
  • 📐 panels.flex — flexbox-style layout with justify (start/end/center/between/around/evenly) + grow weights
  • 🧪 +30 tests
import { panels, ascii, markdown } from 'ansimax';

const [boxA, boxB, boxC] = ['A', 'B', 'C'].map((c) => ascii.box(c, { padding: 1 }));

// Flexbox layout
console.log(panels.flex([boxA, boxB, boxC], { width: 60, justify: 'between' }));
console.log(panels.flex([boxA, boxB], { width: 40, grow: [3, 1] }));  // A grows 3× as much

// Reference links
markdown.render(`
See [the docs][docs] and [shortcut].

[docs]: https://docs.example.com "Documentation"
[shortcut]: https://example.com
`);

Both build on v1.4.6 foundations (link placeholders + distribute). Every flex justify strategy conserves total width exactly.

Drop-in replacement for 1.4.6.

v1.4.6 — Consolidation v4 + math toolkit + autolinks

Maintenance + feature release. Zero breaking changes:

  • 🧹 HEX_RE consolidated — 5 duplicate copies → 1 (isHexColor)
  • 🔢 New utils/math toolkit — lerp, smoothstep, mod, gcd, distribute, and more (15 pure functions)
  • 🔗 Markdown autolinks — <https://…> and bare URLs render as terminal hyperlinks
  • 🧪 +44 tests
import { smoothstep, distribute, mod } from 'ansimax';

smoothstep(0, 1, 0.25);      // → 0.15625 (Hermite easing)
distribute(10, 3);           // → [4, 3, 3] (sums exactly to 10)
mod(-1, 4);                  // → 3 (true modulo)

import { markdown } from 'ansimax';
markdown.render('Docs at https://example.com');  // clickable link

Drop-in replacement for 1.4.5.

v1.4.5 — Panels refactor + syntax highlighting

Two big improvements, zero breaking changes:

  • 🎨 Syntax highlighting for code blocks (js/ts/json/bash with aliases)
  • 📁 Panels module refactored from 1116-line monolith → 7 focused submodules
  • 🧩 grid decomposed into 3 pure phases (resolve → pack → render)
  • ➕ 3 new exports: highlightCode, tokenizeCode, isHighlightSupported
  • 🧪 +50 tests
import { markdown } from 'ansimax';

console.log(markdown.render(`
\`\`\`js
const greet = (name) => \`Hello, \${name}!\`;
\`\`\`
`));
// Renders with keyword highlighting (const), string coloring, etc.

Supported languages: js/javascript/jsx, ts/typescript/tsx, json, bash/sh/shell/zsh.

Direct API:

import { highlightCode, tokenizeCode, isHighlightSupported } from 'ansimax';

highlightCode('const x = 42;', 'js');    // ANSI-colored string
tokenizeCode('const x = 42;', 'js');     // [{ kind, text }, ...]
isHighlightSupported('rust');            // false

Drop-in replacement for 1.4.4.

v1.4.4 — Grid areas + task lists + setext headings

Patch release finishing the Phase 4 roadmap:

  • 🎨 panels.gridAreas — CSS Grid-style template areas with rectangle validation
  • ✅ Task lists in markdown: - [ ] and - [x] (GFM syntax)
  • 📄 Setext headings in markdown: text\n=== (h1) and text\n--- (h2)
  • 🧪 +27 tests for all new features
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 render as [ ] / [✓]
markdown.render(`
- [ ] pending
- [x] done
- regular item
`);

// Setext headings work identically to # H1 / ## H2
markdown.render(`
Title
=====

Subtitle
--------
`);

Rectangle validation catches non-contiguous areas at compile time:

Error: areas: "foo" is not a rectangle — cells at [0,0]..[1,1]
       have 3 occurrences, expected 4

Drop-in replacement for 1.4.3.

v1.4.3 — Grid rowSpan + markdown escapes + nested lists

Patch release with 3 substantial new features:

  • 🎯 panels.grid rowSpan — CSS Grid-style multi-row layouts using mark-and-pack algorithm
  • ⛓️ CommonMark escapes in markdown: \*, \_, \, \\, \[, \], \~
  • 🌳 Nested lists in markdown — recursive indentation-based sublists with depth-aware bullets
  • 🧪 +27 tests for all new features
import { panels, ascii, markdown } from 'ansimax';

const [sidebar, top, bottom, side2] = ['nav', 'top', 'bottom', 'aside']
  .map((c) => ascii.box(c, { padding: 1 }));

// CSS Grid-style layout
console.log(panels.grid([sidebar, top, bottom, side2], {
  columns: 3,
  colSpan: [1, 2, 2, 1],
  rowSpan: [2, 1, 1, 1],
  cellHeight: 4,
}));

// Escape literal markdown characters
markdown.render('Show \\*literal asterisks\\*');

// Nested lists
markdown.render(`
- Outer
  - Nested
    - Deep
`);

Note: Block.type === 'list' items are now ListItem[] (was string[]). Only affects external code using parseBlocks directly; markdown.render users are unaffected.

v1.4.2 — Internal consolidation v3

Patch release continuing v1.3.7's DRY work. Zero behavior changes:

  • ➕ ensureString(value) — coerce to string (null/undefined → '')
  • ➕ clampNonNeg(n, fallback?) — non-negative integer with safe fallback
  • ➕ clampPositiveInt(n, fallback?) — positive integer (≥ 1) with safe fallback
  • 🧹 Removed 10 duplicate inline implementations across components, frames, loaders, trees
  • 🧪 +18 tests for the consolidated helpers
import { ensureString, clampNonNeg, clampPositiveInt } from 'ansimax';

ensureString(null)              // → ''
clampNonNeg(-3)                 // → 0
clampPositiveInt(0)             // → 1  (clamped up)
clampPositiveInt(NaN, 10)       // → 10 (fallback)

Drop-in replacement for 1.4.1.

v1.4.1 — Grid v2 + markdown refactor

Patch release. Zero breaking changes:

  • 🎯 panels.grid — colSpan: per-block column span (CSS Grid-style auto-flow)
  • 📏 panels.grid — cellHeight: uniform row heights (complements cellWidth)
  • 🔀 panels.grid — flow: 'row' (default) or 'column' auto-flow direction
  • 📁 markdown refactored from 522-line monolith → 5 focused submodules (API unchanged)
  • 🌳 Submodule imports enabled: import { parseBlocks } from 'ansimax/markdown/block-parser'
  • 🧪 +32 tests
import { panels, ascii } from 'ansimax';

const [header, sidebar, con