The modern ANSI and terminal toolkit for Node.js and browser.
Replace multiple CLI dependencies with one fast, unified library.
npm install @munesoft/ansix
Most CLI tools depend on a chain of small packages:
ansi-regex— detect/match ANSI sequencesstrip-ansi— remove ANSI codessupports-color— detect terminal color supportstring-width— measure display widthcli-truncate— truncate to widthwrap-ansi— word-wrap to columns
ansix replaces all of them with a single, modern, zero-dependency package.
| Feature | ansix |
|---|---|
| ANSI detection & stripping | ✅ |
| Terminal capability detection | ✅ |
| Named, 256-palette, RGB, and HEX colors | ✅ |
| Text styles (bold, italic, underline, …) | ✅ |
| ANSI-safe width calculation | ✅ |
| Wide character & emoji support | ✅ |
| Text truncation (ANSI-aware) | ✅ |
| Text wrapping (ANSI-aware) | ✅ |
| Cursor control sequences | ✅ |
| Safe output (auto-strip when unsupported) | ✅ |
| OSC 8 terminal hyperlinks | ✅ |
| Token-based parser | ✅ |
| Transform pipelines | ✅ |
| TypeScript types | ✅ |
| ESM + CommonJS dual package | ✅ |
| Browser compatible | ✅ |
| Zero dependencies | ✅ |
// ESM
import ansix from '@munesoft/ansix';
// CommonJS
const ansix = require('@munesoft/ansix');
ansix.strip('\x1b[31mHello\x1b[0m');
// => 'Hello'Named imports also work:
import { strip, color, width, truncate } from '@munesoft/ansix';ansix.has('\x1b[31mHello\x1b[0m') // => true
ansix.has('plain text') // => false
ansix.strip('\x1b[1m\x1b[32mBold Green\x1b[0m') // => 'Bold Green'const cap = ansix.supports();
// {
// level: 'truecolor' | '256' | 'basic' | 'none',
// hasBasic: true,
// has256: true,
// hasTruecolor: true,
// isBrowser: false
// }
ansix.supportsColor() // => true / falseRespects NO_COLOR, FORCE_COLOR, COLORTERM, TERM_PROGRAM, and CI environment variables.
Named colors:
ansix.color('red', 'Error!')
ansix.color('green', 'Success')
ansix.color('cyan', 'Info')
ansix.bgColor('blue', 'highlighted')Available names: black, red, green, yellow, blue, magenta, cyan, white, gray,
brightRed, brightGreen, brightYellow, brightBlue, brightMagenta, brightCyan, brightWhite
Text styles:
ansix.style('bold', 'Title')
ansix.style('italic', 'note')
ansix.style('underline', 'link')
ansix.style('strikethrough', 'deleted')256-palette:
ansix.color256(200, 'pink text')
ansix.bgColor256(100, 'colored background')Truecolor RGB:
ansix.rgb(255, 100, 0, 'orange text')
ansix.bgRgb(0, 0, 128, 'navy background')HEX:
ansix.hex('#ff6600', 'link text')
ansix.bgHex('#1a1a2e', 'dark background')ANSI-safe, handles CJK wide characters and emoji:
ansix.width('Hello') // => 5
ansix.width('\x1b[31mHello\x1b[0m') // => 5 (ignores ANSI)
ansix.width('你好') // => 4 (wide chars = 2 each)
ansix.width('🚀') // => 2ansix.truncate('Hello World', 8)
// => 'Hello W…'
ansix.truncate('\x1b[31mHello World\x1b[0m', 8)
// => '\x1b[31mHello W\x1b[0m…' (ANSI codes preserved)
ansix.truncate('Hello World', 8, { ellipsis: '...' })
// => 'Hello...'ansix.wrap('Hello World Foo Bar Baz', 10)
// => 'Hello\nWorld Foo\nBar Baz'
ansix.wrap(text, 40, { hard: true }) // break mid-word if needed
ansix.wrap(text, 40, { trim: false }) // keep leading whitespaceAll cursor functions return escape strings — write them to process.stdout:
process.stdout.write(ansix.cursor.hide())
process.stdout.write(ansix.cursor.show())
process.stdout.write(ansix.cursor.up(2))
process.stdout.write(ansix.cursor.moveTo(5, 1))
process.stdout.write(ansix.cursor.clearLine())
process.stdout.write(ansix.cursor.enterAltScreen())
process.stdout.write(ansix.cursor.exitAltScreen())
// Or use the convenience writer (Node.js only):
ansix.cursor.write(ansix.cursor.hide())Full list: hide, show, up, down, forward, backward, nextLine, prevLine,
column, moveTo, save, restore, clearScreen, clearScreenDown, clearScreenUp,
clearLine, clearLineRight, clearLineLeft, scrollUp, scrollDown,
enterAltScreen, exitAltScreen
Automatically strips ANSI codes when the terminal or environment doesn't support them:
process.stdout.write(ansix.safe(ansix.color('green', 'text')))
// In color terminals: outputs colored text
// In dumb terminals / NO_COLOR / browser: outputs plain 'text'OSC 8 terminal hyperlinks (iTerm2, Kitty, WezTerm, VTE, etc.):
ansix.link('Click here', 'https://example.com')
// In supporting terminals: clickable hyperlink
// In others: falls back to plain text
ansix.link('Click here', 'https://example.com', { force: true })
// Always emit the OSC 8 sequenceParse a string into text and ANSI tokens:
const tokens = ansix.parse('\x1b[31mHello\x1b[0m World');
// [
// { type: 'ansi', value: '\x1b[31m', kind: 'sgr' },
// { type: 'text', value: 'Hello' },
// { type: 'ansi', value: '\x1b[0m', kind: 'sgr' },
// { type: 'text', value: ' World' }
// ]
ansix.stringify(tokens) // reconstruct original stringBuild transform pipelines:
// Strip all ANSI
const stripAll = ansix.pipeline(ansix.stripTransform);
stripAll('\x1b[31mHello\x1b[0m') // => 'Hello'
// Strip colors only, keep cursor sequences
const stripColors = ansix.pipeline(ansix.stripColorsTransform);
// Uppercase text content, preserve ANSI codes
const upper = ansix.pipeline(ansix.mapText(t => t.toUpperCase()));
upper('\x1b[31mhello\x1b[0m') // => '\x1b[31mHELLO\x1b[0m'
// Chain transforms
const process = ansix.pipeline(
ansix.mapText(t => t.toUpperCase()),
ansix.stripColorsTransform
);ansix.ansiRegex() // /[all ANSI sequences]/g
ansix.sgrRegex() // /\x1b\[[\d;]*m/g (colors/styles only)
ansix.hyperlinkRegex() // OSC 8 hyperlink sequencesansix is fully browser compatible. supports() detects browser environments and returns { level: 'basic', isBrowser: true }. safe() and strip() work as expected for stripping ANSI from strings in non-terminal contexts.
MIT