ansimax 1.0.0 → 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.mts CHANGED
@@ -1,146 +1,606 @@
1
- type ColorMode = 'basic' | '256' | 'truecolor';
2
- type AnimationSpeed = 'slow' | 'normal' | 'fast';
1
+ /** Color rendering capability. 'none' suppresses all color output. */
2
+ type ColorMode = 'none' | 'basic' | '256' | 'truecolor' | 'auto';
3
+ /** Animation pacing multiplier preset. */
4
+ type AnimationSpeed = 'slow' | 'normal' | 'fast' | 'instant';
3
5
  interface AnsimaxConfig {
6
+ /** Color rendering mode. 'auto' (default) defers to terminal detection. */
4
7
  colorMode?: ColorMode;
8
+ /** Animation speed preset. */
5
9
  animationSpeed?: AnimationSpeed;
6
- asciiFont?: 'big' | 'small';
10
+ /** Default ASCII font name. Accepts built-in ('big', 'small') or custom names. */
11
+ asciiFont?: string;
12
+ /** UI locale. Currently informational; reserved for future i18n. */
7
13
  locale?: string;
14
+ /** Active theme name. Setting this calls themes.tryUse(name). */
8
15
  theme?: string;
16
+ /** Disable all motion (overrides animationSpeed). Useful for accessibility. */
17
+ reducedMotion?: boolean;
18
+ }
19
+ type ConfigChangeListener = (config: Required<AnsimaxConfig>) => void;
20
+ type ConfigKey = keyof AnsimaxConfig;
21
+ type ConfigKeyListener<K extends ConfigKey> = (newValue: Required<AnsimaxConfig>[K], oldValue: Required<AnsimaxConfig>[K]) => void;
22
+ declare const DEFAULTS: Readonly<Required<AnsimaxConfig>>;
23
+ /**
24
+ * Subscribe to ANY configuration change.
25
+ *
26
+ * @param listener Called with the new config whenever it changes
27
+ * @returns Unsubscribe function
28
+ *
29
+ * @example
30
+ * const off = onConfigChange((c) => console.log('Theme:', c.theme));
31
+ * // Later: off();
32
+ */
33
+ declare const onConfigChange: (listener: ConfigChangeListener) => (() => void);
34
+ /**
35
+ * Subscribe to changes of a SPECIFIC key. Listener fires only when that
36
+ * key's value actually changes (not on every config update).
37
+ *
38
+ * @example
39
+ * const off = onConfigKeyChange('theme', (newT, oldT) => updateUI(newT));
40
+ */
41
+ declare const onConfigKeyChange: <K extends ConfigKey>(key: K, listener: ConfigKeyListener<K>) => (() => void);
42
+ /**
43
+ * Pause listener notifications until resume() is called. Useful for
44
+ * batch updates where you don't want intermediate states to fire
45
+ * subscribers.
46
+ *
47
+ * @example
48
+ * pauseListeners();
49
+ * configure({ theme: 'matrix' });
50
+ * configure({ colorMode: 'none' });
51
+ * resumeListeners(); // fires once with final config
52
+ */
53
+ declare const pauseListeners: () => void;
54
+ declare const resumeListeners: () => void;
55
+ interface ConfigureOptions {
56
+ /**
57
+ * Strict mode rejects unknown keys with RangeError instead of
58
+ * silently ignoring them. Useful for catching typos in config files.
59
+ * Default: false.
60
+ */
61
+ strict?: boolean;
9
62
  }
10
- declare const configure: (opts?: AnsimaxConfig) => void;
63
+ /**
64
+ * Update one or more configuration values. Validates inputs strictly —
65
+ * invalid colorMode or animationSpeed throws a RangeError, wrong types
66
+ * throw a TypeError. Partial updates merge with current state.
67
+ *
68
+ * Triggers subscribed listeners ONLY if values actually changed.
69
+ *
70
+ * @example
71
+ * configure({ colorMode: 'none', theme: 'matrix' });
72
+ * configure({ theme: 'nord' }, { strict: true });
73
+ */
74
+ declare const configure: (opts?: AnsimaxConfig, meta?: ConfigureOptions) => void;
75
+ /** Get a snapshot of the current configuration. */
11
76
  declare const getConfig: () => Required<AnsimaxConfig>;
77
+ /** Numeric multiplier for animation timings. Returns 0 in reducedMotion. */
12
78
  declare const getSpeedMultiplier: () => number;
79
+ /**
80
+ * Reset configuration to defaults. Triggers listeners if state differs
81
+ * from defaults. Side effects are applied (NO_COLOR cleared, theme
82
+ * reverts to 'dracula', etc.).
83
+ */
84
+ declare const resetConfig: () => void;
85
+ /** Read a single config field by name (typed). */
86
+ declare const getConfigValue: <K extends keyof AnsimaxConfig>(key: K) => Required<AnsimaxConfig>[K];
87
+ /**
88
+ * Temporarily override config for the duration of `fn`, then restore
89
+ * the previous state. Listeners fire for both the override and the
90
+ * restore.
91
+ *
92
+ * @example
93
+ * await withConfig({ reducedMotion: true }, async () => {
94
+ * await runAccessibilityChecks();
95
+ * });
96
+ */
97
+ declare const withConfig: <T>(overrides: AnsimaxConfig, fn: () => T | Promise<T>) => T | Promise<T>;
13
98
 
14
- type FrameCallback = (frame: string, index: number) => string;
15
- interface PlayOptions {
16
- interval?: number;
17
- repeat?: number;
18
- clearOnFinish?: boolean;
19
- onFrame?: FrameCallback | null;
20
- signal?: AbortSignal;
21
- }
22
- interface LiveOptions {
23
- fps?: number;
24
- autoStart?: boolean;
99
+ declare const ESC = "\u001B";
100
+ declare const CSI = "\u001B[";
101
+ /** OSC sequence introducer (Operating System Command). */
102
+ declare const OSC = "\u001B]";
103
+ /** String terminator used to close OSC sequences. */
104
+ declare const ST = "\u001B\\";
105
+ /** BEL — alternative OSC terminator (older terminals). */
106
+ declare const BEL = "\u0007";
107
+ type AnsiCode = number;
108
+ /** Default fallback dimensions when stdout is not a TTY. */
109
+ declare const DEFAULT_TERM_COLS = 80;
110
+ declare const DEFAULT_TERM_ROWS = 24;
111
+ declare const cursor: {
112
+ readonly up: (n?: number) => string;
113
+ readonly down: (n?: number) => string;
114
+ readonly right: (n?: number) => string;
115
+ readonly left: (n?: number) => string;
116
+ readonly to: (x: number, y: number) => string;
117
+ /** Move cursor to absolute column n (1-based). */
118
+ readonly column: (n: number) => string;
119
+ /** Save cursor (CSI s — DEC private). */
120
+ readonly save: () => string;
121
+ /** Restore cursor (CSI u). */
122
+ readonly restore: () => string;
123
+ /** Save cursor (ESC 7 — VT100 standard). */
124
+ readonly saveCompat: () => string;
125
+ /** Restore cursor (ESC 8). */
126
+ readonly restoreCompat: () => string;
127
+ readonly hide: () => string;
128
+ readonly show: () => string;
129
+ /** Query cursor position. Terminal responds with CSI <row>;<col>R. */
130
+ readonly position: () => string;
131
+ /** Move cursor to next line (CR + line down). */
132
+ readonly nextLine: (n?: number) => string;
133
+ /** Move cursor to previous line. */
134
+ readonly prevLine: (n?: number) => string;
135
+ };
136
+ /**
137
+ * Hide cursor and register an exit handler that restores it on crash/SIGINT.
138
+ * Use this instead of writing `cursor.hide()` directly when you care about
139
+ * leaving the user's shell in a clean state.
140
+ */
141
+ declare const hideCursor: () => boolean;
142
+ declare const showCursor: () => boolean;
143
+ type EraseMode = 'down' | 'up' | 'all';
144
+ declare const screen: {
145
+ readonly clear: () => string;
146
+ /** Alias for clear() — covers `screen.clearAll()` callers. */
147
+ readonly clearAll: () => string;
148
+ readonly clearLine: () => string;
149
+ readonly clearRight: () => string;
150
+ readonly clearLeft: () => string;
151
+ readonly clearDown: () => string;
152
+ readonly clearUp: () => string;
153
+ readonly eraseDisplay: (mode?: EraseMode) => string;
154
+ readonly scrollUp: (n?: number) => string;
155
+ readonly scrollDown: (n?: number) => string;
156
+ };
157
+ declare const FG: {
158
+ readonly black: 30;
159
+ readonly red: 31;
160
+ readonly green: 32;
161
+ readonly yellow: 33;
162
+ readonly blue: 34;
163
+ readonly magenta: 35;
164
+ readonly cyan: 36;
165
+ readonly white: 37;
166
+ readonly brightBlack: 90;
167
+ readonly brightRed: 91;
168
+ readonly brightGreen: 92;
169
+ readonly brightYellow: 93;
170
+ readonly brightBlue: 94;
171
+ readonly brightMagenta: 95;
172
+ readonly brightCyan: 96;
173
+ readonly brightWhite: 97;
174
+ };
175
+ declare const BG: {
176
+ readonly black: 40;
177
+ readonly red: 41;
178
+ readonly green: 42;
179
+ readonly yellow: 43;
180
+ readonly blue: 44;
181
+ readonly magenta: 45;
182
+ readonly cyan: 46;
183
+ readonly white: 47;
184
+ readonly brightBlack: 100;
185
+ readonly brightRed: 101;
186
+ readonly brightGreen: 102;
187
+ readonly brightYellow: 103;
188
+ readonly brightBlue: 104;
189
+ readonly brightMagenta: 105;
190
+ readonly brightCyan: 106;
191
+ readonly brightWhite: 107;
192
+ };
193
+ declare const STYLE: {
194
+ readonly reset: 0;
195
+ readonly bold: 1;
196
+ readonly dim: 2;
197
+ readonly italic: 3;
198
+ readonly underline: 4;
199
+ readonly blink: 5;
200
+ readonly inverse: 7;
201
+ readonly hidden: 8;
202
+ readonly strikethrough: 9;
203
+ };
204
+ declare const sgr: (...codes: AnsiCode[]) => string;
205
+ declare const reset: () => string;
206
+ declare const fgRgb: (r: number, g: number, b: number) => string;
207
+ declare const bgRgb: (r: number, g: number, b: number) => string;
208
+ declare const fg256: (n: number) => string;
209
+ declare const bg256: (n: number) => string;
210
+ /**
211
+ * Set the terminal window title (OSC 2). Most terminals support this.
212
+ * Returns the escape sequence; caller is responsible for writing it.
213
+ */
214
+ declare const setTitle: (text: string) => string;
215
+ /**
216
+ * Make `text` a clickable hyperlink to `url` (OSC 8).
217
+ * Supported by iTerm2, Terminal.app (macOS 13+), WezTerm, Kitty, modern xterm.
218
+ * Falls back gracefully (just prints text) on terminals that don't support it.
219
+ */
220
+ declare const link: (text: string, url: string) => string;
221
+ /** Ring the terminal bell. Most modern terminals visualize, not audio. */
222
+ declare const bell: () => string;
223
+ type ColorSupport = 'none' | 'basic' | '256' | 'truecolor';
224
+ type ColorLevel = 0 | 1 | 2 | 3;
225
+ declare const supportsColor: () => ColorSupport;
226
+ declare const supportsColorLevel: () => ColorLevel;
227
+ /**
228
+ * Reset the cached capability — call after changing FORCE_COLOR /
229
+ * NO_COLOR env vars at runtime, or before a test that needs to
230
+ * exercise different code paths.
231
+ */
232
+ declare const resetColorSupportCache: () => void;
233
+ /** Returns terminal width in columns. Falls back to DEFAULT_TERM_COLS. */
234
+ declare const getTerminalWidth: () => number;
235
+ /** Returns terminal height in rows. Falls back to DEFAULT_TERM_ROWS. */
236
+ declare const getTerminalHeight: () => number;
237
+ declare const stripAnsi$2: (str: string) => string;
238
+ /** Sync write to stdout. Returns false if stdout is missing or full. */
239
+ declare const write: (str: string) => boolean;
240
+ /** Sync write to stderr. Useful for CLI errors and logs. */
241
+ declare const writeErr: (str: string) => boolean;
242
+ declare const writeln: (str?: string) => boolean;
243
+ declare const writelnErr: (str?: string) => boolean;
244
+ /**
245
+ * Async write with backpressure handling.
246
+ * - Resolves immediately when the buffer accepted the data
247
+ * - Waits for `'drain'` when full
248
+ * - Resolves on `'error'` instead of hanging forever
249
+ * - No-ops gracefully if stdout is missing
250
+ * - Optional timeout (ms) — resolves anyway after timeout to prevent
251
+ * infinite hangs on broken streams
252
+ */
253
+ interface WriteAsyncOptions {
254
+ /** Max time (ms) to wait for drain. Default: 5000. 0 disables. */
255
+ timeout?: number;
25
256
  }
26
- interface LiveController {
27
- start: () => void;
28
- stop: () => void;
29
- update: (frame: string) => void;
257
+ declare const writeAsync: (str: string, opts?: WriteAsyncOptions) => Promise<void>;
258
+ interface OutputBuffer {
259
+ /** Append a string to the buffer. */
260
+ push(str: string): OutputBuffer;
261
+ /** Append a string with a trailing newline. */
262
+ pushln(str?: string): OutputBuffer;
263
+ /** Append `str` only when `cond` is truthy. Useful for conditional escapes. */
264
+ pushIf(cond: unknown, str: string): OutputBuffer;
265
+ /** Get the buffered content without flushing. */
266
+ toString(): string;
267
+ /** Number of characters currently buffered. */
268
+ length(): number;
269
+ /** Clear the buffer without writing. */
270
+ reset(): OutputBuffer;
271
+ /** Flush to stdout synchronously. Returns false on backpressure. */
272
+ flush(): boolean;
273
+ /** Flush to stdout asynchronously. Awaits drain on backpressure. */
274
+ flushAsync(opts?: WriteAsyncOptions): Promise<void>;
30
275
  }
31
- declare const frames: {
32
- play: (frames: string[], opts?: PlayOptions) => Promise<void>;
33
- generate: (count: number, fn: (i: number, total: number) => string) => string[];
34
- live: (opts?: LiveOptions) => LiveController;
35
- morph: (frameA: string, frameB: string, steps?: number, charset?: string) => string[];
36
- presets: {
37
- loadingBar: (opts?: {
38
- width?: number;
39
- char?: string;
40
- empty?: string;
41
- label?: string;
42
- }) => string[];
43
- ball: (opts?: {
44
- width?: number;
45
- char?: string;
46
- }) => string[];
47
- breathe: (text: string, opts?: {
48
- steps?: number;
49
- }) => string[];
50
- typeDelete: (text: string, opts?: {
51
- cursor?: string;
52
- }) => string[];
53
- };
54
- };
55
-
56
- type SpinnerType = 'dots' | 'dots2' | 'line' | 'arrow' | 'bounce' | 'star' | 'pong' | 'aesthetic' | 'blocks' | 'moon' | 'clock';
57
- declare const SPINNERS: Record<SpinnerType, string[]>;
58
- interface SpinOptions {
59
- type?: SpinnerType;
60
- interval?: number;
61
- color?: string | null;
62
- prefix?: string;
63
- suffix?: string;
64
- persist?: boolean;
276
+ declare const createOutputBuffer: () => OutputBuffer;
277
+ /** Recommended frame interval (ms) for animations. ~60 fps. */
278
+ declare const FRAME_MS = 16;
279
+ interface SleepOptions {
280
+ /** Optional AbortSignal sleep resolves immediately when aborted. */
65
281
  signal?: AbortSignal;
66
- reducedMotion?: boolean;
67
282
  }
68
- interface ProgressOptions {
69
- width?: number;
70
- char?: string;
71
- emptyChar?: string;
72
- showPercentage?: boolean;
73
- color?: string | null;
74
- label?: string;
283
+ /**
284
+ * Pause for `ms` milliseconds. Cancellable via AbortSignal.
285
+ * - Negative or NaN ms is clamped to 0
286
+ * - Resolves silently on abort (no rejection)
287
+ * - Cleans up timer + listener on every path
288
+ */
289
+ declare const sleep: (ms: number, opts?: SleepOptions) => Promise<void>;
290
+ /**
291
+ * Like sleep, but rounds the wait time up to the next frame boundary.
292
+ * Useful inside animation loops to throttle output to a reasonable framerate.
293
+ */
294
+ declare const sleepFrame: (ms?: number, opts?: SleepOptions) => Promise<void>;
295
+
296
+ interface RGB {
297
+ r: number;
298
+ g: number;
299
+ b: number;
75
300
  }
76
- interface Task {
77
- text: string;
78
- fn: () => Promise<unknown>;
301
+ declare const clamp: (n: number, min: number, max: number) => number;
302
+ declare const lerp: (a: number, b: number, t: number) => number;
303
+ /** Returns true when a string is a valid 3- or 6-digit hex color. */
304
+ declare const isHexColor: (hex: string) => boolean;
305
+ /**
306
+ * Parses a hex color string to RGB. Throws on invalid input.
307
+ * Use isHexColor() first if you need fail-soft behaviour.
308
+ */
309
+ declare const hexToRgb: (hex: string) => RGB;
310
+ /** Converts R, G, B values to a hex string. Values are clamped to 0–255. */
311
+ declare const rgbToHex: (r: number, g: number, b: number) => string;
312
+ /** Linearly interpolates between two RGB colors. t is clamped to [0, 1]. */
313
+ declare const lerpColor: (a: RGB, b: RGB, t: number) => RGB;
314
+ /**
315
+ * Multi-stop gradient interpolation. Given a list of color stops and t in [0, 1],
316
+ * returns the interpolated RGB. Equivalent to a CSS `linear-gradient` sampler.
317
+ *
318
+ * Defensive: empty colors throws (no sensible default), single color returns
319
+ * that color regardless of t, t outside [0,1] is clamped automatically.
320
+ *
321
+ * @example
322
+ * gradientColor([red, yellow, green], 0.5) → yellow
323
+ * gradientColor([red, blue], 0.0) → red
324
+ * gradientColor([red, blue], -1) → red (t clamped to 0)
325
+ * gradientColor([red, blue], 99) → blue (t clamped to 1)
326
+ */
327
+ declare const gradientColor: (colors: RGB[], t: number) => RGB;
328
+ declare const rgbTo256: (r: number, g: number, b: number) => number;
329
+ declare const stripAnsi$1: (str: string) => string;
330
+ /**
331
+ * Width of a single character (or grapheme) in terminal cells.
332
+ * - 0 for combining marks, ZWJ, VS, BOM
333
+ * - 2 for wide CJK / emoji presentation
334
+ * - 1 for everything else
335
+ */
336
+ declare const charWidth: (char: string) => number;
337
+ /**
338
+ * Iterate grapheme clusters in a string. A grapheme is a user-perceived
339
+ * character — e.g. '👨‍👩‍👧‍👦' is one grapheme even though it's 7 codepoints.
340
+ *
341
+ * Uses Intl.Segmenter when available, otherwise falls back to Unicode
342
+ * codepoint iteration via [...str].
343
+ */
344
+ declare const graphemes: (str: string) => Generator<string, void, unknown>;
345
+ /**
346
+ * Visible terminal width of a string.
347
+ *
348
+ * Strips ANSI escapes first, then sums grapheme cluster widths using
349
+ * the Unicode-aware `charWidth()`. This is the function every layout
350
+ * helper (padding, centering, table columns) should use.
351
+ */
352
+ declare const visibleLen: (str: string) => number;
353
+ declare const sliceAnsi: (str: string, start: number, end?: number) => string;
354
+ /**
355
+ * Truncates a string with ANSI escapes to a max visible width.
356
+ * Preserves color codes that started before the cut and emits a final reset.
357
+ * Now Unicode-aware (handles CJK, emoji, graphemes correctly).
358
+ */
359
+ declare const truncateAnsi: (str: string, width: number, ellipsis?: string) => string;
360
+ declare const padEnd: (str: string, width: number, ch?: string) => string;
361
+ declare const padStart: (str: string, width: number, ch?: string) => string;
362
+ declare const center: (str: string, width: number, ch?: string) => string;
363
+ /** Repeats a string until its visible length reaches the target width. */
364
+ declare const repeatVisible: (str: string, width: number) => string;
365
+ /**
366
+ * Current terminal size. Reads from process.stdout each call so callers
367
+ * always get up-to-date dimensions after a resize.
368
+ *
369
+ * Falls back to 80×24 (classic VT100 default) if stdout doesn't expose
370
+ * dimensions. Negative or non-number values are also handled.
371
+ */
372
+ declare const termSize: () => {
373
+ cols: number;
374
+ rows: number;
375
+ };
376
+ type ResizeListener = (size: {
377
+ cols: number;
378
+ rows: number;
379
+ }) => void;
380
+ interface OnResizeOptions {
381
+ /**
382
+ * Throttle interval in ms. Coalesces rapid resize events (which can
383
+ * fire dozens per second during active drag-resize). Default: 50ms.
384
+ * Pass 0 to disable throttling.
385
+ */
386
+ throttle?: number;
79
387
  }
80
- interface TaskResult {
81
- success: boolean;
82
- result?: unknown;
83
- error?: Error;
388
+ /**
389
+ * Subscribe to terminal resize events. Returns a function that unsubscribes.
390
+ * Useful for dashboards and live UIs that need responsive re-layout.
391
+ *
392
+ * By default coalesces rapid resize events at ~20fps (50ms throttle) to
393
+ * avoid flooding the redraw path.
394
+ *
395
+ * @example
396
+ * const off = onResize(({ cols, rows }) => redraw(cols, rows));
397
+ * // Later: off();
398
+ */
399
+ declare const onResize: (listener: ResizeListener, opts?: OnResizeOptions) => (() => void);
400
+ /**
401
+ * ANSI-aware word wrap. Tokens are split by whitespace, but ANSI escape
402
+ * sequences within tokens are preserved verbatim. Visible width is
403
+ * computed Unicode-correctly. Tokens longer than `width` are soft-broken
404
+ * into chunks that respect ANSI boundaries.
405
+ */
406
+ declare const wrapAnsi: (text: string, width: number) => string[];
407
+ /**
408
+ * Backwards-compat alias. Newer code should use `wrapAnsi`.
409
+ * Identical behavior — wrapAnsi is the same algorithm but ANSI-aware.
410
+ */
411
+ declare const wordWrap: (text: string, width: number) => string[];
412
+ interface DebounceOptions {
413
+ /**
414
+ * Maximum time (ms) to wait before forcing invocation, even if calls
415
+ * keep arriving. Useful for resize handlers — without maxWait, an
416
+ * actively-resized window never fires its handler.
417
+ */
418
+ maxWait?: number;
84
419
  }
85
- interface TaskOptions {
86
- type?: SpinnerType;
87
- spinColor?: string;
88
- parallel?: boolean;
420
+ /**
421
+ * Debounce a function: delay invocation until `ms` have passed since the
422
+ * last call. Optional `maxWait` guarantees invocation within that window
423
+ * even if calls keep coming.
424
+ */
425
+ declare const debounce: <T extends (...args: never[]) => unknown>(fn: T, ms: number, opts?: DebounceOptions) => T & {
426
+ cancel(): void;
427
+ flush(): void;
428
+ };
429
+ /**
430
+ * Throttle a function: invoke at most once per `ms` window. The first
431
+ * call fires immediately; subsequent calls inside the window are
432
+ * coalesced and the last one fires when the window expires.
433
+ */
434
+ declare const throttle: <T extends (...args: never[]) => unknown>(fn: T, ms: number) => T & {
435
+ cancel(): void;
436
+ };
437
+ /**
438
+ * Schedules a callback for the next animation frame (~16ms).
439
+ * Inspired by browser `requestAnimationFrame` — useful for coalescing
440
+ * multiple render requests into a single paint.
441
+ *
442
+ * Returns a handle that can be passed to `cancelTerminalFrame()`.
443
+ */
444
+ type FrameHandle = ReturnType<typeof setTimeout>;
445
+ declare const requestTerminalFrame: (cb: () => void) => FrameHandle;
446
+ declare const cancelTerminalFrame: (handle: FrameHandle) => void;
447
+ /**
448
+ * Coalesce sync work to the next event loop turn (microtask + I/O).
449
+ * Falls back to setTimeout(0) in environments without setImmediate.
450
+ */
451
+ declare const nextTick: (cb: () => void) => void;
452
+ interface MemoizeOptions<A extends unknown[]> {
453
+ /** Max cached entries before FIFO eviction. Default: 100. */
454
+ max?: number;
455
+ /**
456
+ * Key extractor — given the args, returns the cache key.
457
+ * Use to memoize multi-arg fns: `keyFn: (a, b) => a + ':' + b`.
458
+ * Default: first arg.
459
+ */
460
+ keyFn?: (...args: A) => unknown;
89
461
  }
90
- declare const loader: {
91
- spin: (text?: string, opts?: SpinOptions) => ((message?: string, success?: boolean) => void);
92
- dots: (text?: string, opts?: {
93
- interval?: number;
94
- max?: number;
95
- signal?: AbortSignal;
96
- }) => (() => void);
97
- progress: (percent: number, label?: string, opts?: ProgressOptions) => void;
98
- progressAnimate: (steps: number, label?: string, opts?: ProgressOptions & {
99
- delay?: number;
100
- signal?: AbortSignal;
101
- }) => Promise<void>;
102
- tasks: (taskList: Task[], opts?: TaskOptions) => Promise<TaskResult[]>;
103
- custom: (frames: string[], text?: string, opts?: {
104
- interval?: number;
105
- signal?: AbortSignal;
106
- }) => (() => void);
107
- countdown: (seconds: number, opts?: {
108
- label?: string;
109
- color?: string;
110
- signal?: AbortSignal;
111
- }) => Promise<void>;
112
- spinners: Record<SpinnerType, string[]>;
462
+ /**
463
+ * Memoize a function with bounded FIFO cache.
464
+ *
465
+ * Single-arg simple form (passes the arg as cache key):
466
+ * memoize((n: number) => expensive(n))
467
+ *
468
+ * Multi-arg with key extractor:
469
+ * memoize((a, b, c) => f(a,b,c), { keyFn: (a, b, c) => `${a}:${b}:${c}` })
470
+ *
471
+ * Returns the memoized fn with `clear()` and `size()` methods.
472
+ */
473
+ declare const memoize: <A extends unknown[], V>(fn: (...args: A) => V, optsOrMax?: number | MemoizeOptions<A>) => ((...args: A) => V) & {
474
+ clear(): void;
475
+ size(): number;
113
476
  };
477
+ type DiffType = 'added' | 'removed' | 'changed';
478
+ interface LineDiff {
479
+ /** Index of the line that changed. */
480
+ index: number;
481
+ /** New content of that line (empty string for 'removed'). */
482
+ line: string;
483
+ /** What kind of change this line represents. */
484
+ type: DiffType;
485
+ }
486
+ /**
487
+ * Compute line-level differences between two multi-line frames.
488
+ * Returns only the lines that changed, with their indices and type.
489
+ *
490
+ * Useful for damage-tracked redraws: instead of clearing and re-rendering
491
+ * the full frame, redraw only the changed lines.
492
+ */
493
+ declare const diffLines: (oldFrame: string, newFrame: string) => LineDiff[];
494
+ /**
495
+ * Wraps a function so it only invokes the underlying fn ONCE.
496
+ * Subsequent calls return the cached first result. Useful for one-time
497
+ * setup / lazy initialization that must not run twice.
498
+ */
499
+ declare const once: <T extends (...args: never[]) => unknown>(fn: T) => T;
500
+ /**
501
+ * Escape a string for safe use inside a regex literal. Escapes
502
+ * `.`, `*`, `+`, `?`, `^`, `$`, `(`, `)`, `[`, `]`, `{`, `}`, `|`,
503
+ * `\`, `/`.
504
+ *
505
+ * @example
506
+ * new RegExp(escapeRegex('a.b+c')); // matches "a.b+c" literally
507
+ */
508
+ declare const escapeRegex: (str: string) => string;
509
+ /**
510
+ * JSON.stringify replacement that handles BigInt and circular refs.
511
+ * BigInt is serialized as its string form. Circular references emit
512
+ * `"[Circular]"` placeholder instead of throwing.
513
+ *
514
+ * @example
515
+ * safeJson({ n: 1n, ref: obj }); // never throws
516
+ */
517
+ declare const safeJson: (value: unknown, indent?: number) => string;
518
+ /**
519
+ * Pad a string equally on both sides until it reaches `width`.
520
+ * If the padding can't be split evenly, the right side gets the extra char.
521
+ *
522
+ * @example
523
+ * padBoth('hi', 6) → ' hi '
524
+ * padBoth('hi', 5) → ' hi '
525
+ */
526
+ declare const padBoth: (str: string, width: number, ch?: string) => string;
114
527
 
115
528
  type ColorFn = (text: string) => string;
529
+
116
530
  /** Override color suppression at runtime. Pass true to suppress, false to force on. */
117
531
  declare const setNoColor: (v: boolean) => void;
118
- /** Reset to auto-detect mode (reads NO_COLOR + isTTY at call time). */
532
+ /** Reset to auto-detect mode. */
119
533
  declare const resetNoColor: () => void;
120
534
  /** Returns true when colors should be suppressed. */
121
535
  declare const isNoColor: () => boolean;
536
+ /** Numeric color support level (0-3). */
537
+ declare const colorLevel: () => ColorLevel;
538
+ /** Clear adaptive escape caches. Call after a color level change. */
539
+ declare const clearColorCache: () => void;
122
540
  declare const compose: (...fns: ColorFn[]) => ColorFn;
123
- declare const gradient: (text: string, stops: string[]) => string;
541
+ declare const stripAnsi: (str: string) => string;
542
+ interface GradientOptions {
543
+ /** Skip ANSI escapes in the input instead of overwriting them. */
544
+ preserveAnsi?: boolean;
545
+ }
546
+ declare const gradient: (text: unknown, stops: string[] | null | undefined, opts?: GradientOptions) => string;
124
547
  declare const rainbow: ColorFn;
125
- declare const presets: {
126
- sunset: (t: string) => string;
127
- ocean: (t: string) => string;
128
- fire: (t: string) => string;
129
- neon: (t: string) => string;
130
- forest: (t: string) => string;
131
- aurora: (t: string) => string;
132
- candy: (t: string) => string;
133
- gold: (t: string) => string;
548
+ declare const PRESET_DEFS: {
549
+ readonly sunset: readonly ["#ff6b6b", "#feca57", "#48dbfb"];
550
+ readonly ocean: readonly ["#0575e6", "#021b79"];
551
+ readonly fire: readonly ["#f7971e", "#ffd200", "#ff0000"];
552
+ readonly neon: readonly ["#f953c6", "#b91d73"];
553
+ readonly forest: readonly ["#134e5e", "#71b280"];
554
+ readonly aurora: readonly ["#00c6ff", "#0072ff", "#7e57c2"];
555
+ readonly candy: readonly ["#fd79a8", "#a29bfe", "#74b9ff"];
556
+ readonly gold: readonly ["#f7971e", "#ffd200"];
134
557
  };
558
+ type PresetName = keyof typeof PRESET_DEFS;
559
+ /** All available built-in gradient preset names. */
560
+ declare const presetNames: readonly PresetName[];
561
+ /**
562
+ * Register a custom gradient preset accessible via `color.<name>(text)`.
563
+ * Throws if `name` collides with an existing color method.
564
+ *
565
+ * @example
566
+ * registerPreset('mango', ['#ff5e3a', '#ff9500']);
567
+ * color.mango('hello');
568
+ */
569
+ declare const registerPreset: (name: string, stops: string[]) => void;
570
+ /** List all registered presets (built-in + custom). */
571
+ declare const listPresets: () => string[];
572
+ declare const presets: Record<string, ColorFn>;
573
+ interface ColorChain {
574
+ black: () => ColorChain;
575
+ red: () => ColorChain;
576
+ green: () => ColorChain;
577
+ yellow: () => ColorChain;
578
+ blue: () => ColorChain;
579
+ magenta: () => ColorChain;
580
+ cyan: () => ColorChain;
581
+ white: () => ColorChain;
582
+ gray: () => ColorChain;
583
+ brightRed: () => ColorChain;
584
+ brightGreen: () => ColorChain;
585
+ brightYellow: () => ColorChain;
586
+ brightBlue: () => ColorChain;
587
+ bold: () => ColorChain;
588
+ dim: () => ColorChain;
589
+ italic: () => ColorChain;
590
+ underline: () => ColorChain;
591
+ inverse: () => ColorChain;
592
+ strikethrough: () => ColorChain;
593
+ rgb: (r: number, g: number, b: number) => ColorChain;
594
+ hex: (h: string) => ColorChain;
595
+ bgRgb: (r: number, g: number, b: number) => ColorChain;
596
+ bgHex: (h: string) => ColorChain;
597
+ apply: (text: unknown) => string;
598
+ /** Returns the composed function for reuse. */
599
+ fn: () => ColorFn;
600
+ }
601
+ /** Start a new color chain. */
602
+ declare const chain: () => ColorChain;
135
603
  declare const color: {
136
- sunset: (t: string) => string;
137
- ocean: (t: string) => string;
138
- fire: (t: string) => string;
139
- neon: (t: string) => string;
140
- forest: (t: string) => string;
141
- aurora: (t: string) => string;
142
- candy: (t: string) => string;
143
- gold: (t: string) => string;
144
604
  black: ColorFn;
145
605
  red: ColorFn;
146
606
  green: ColorFn;
@@ -159,7 +619,7 @@ declare const color: {
159
619
  brightWhite: ColorFn;
160
620
  gray: ColorFn;
161
621
  grey: ColorFn;
162
- orange: (t: string) => string;
622
+ orange: (t: unknown) => string;
163
623
  purple: ColorFn;
164
624
  bgBlack: ColorFn;
165
625
  bgRed: ColorFn;
@@ -169,69 +629,48 @@ declare const color: {
169
629
  bgMagenta: ColorFn;
170
630
  bgCyan: ColorFn;
171
631
  bgWhite: ColorFn;
172
- bold: (t: string) => string;
173
- dim: (t: string) => string;
174
- italic: (t: string) => string;
175
- underline: (t: string) => string;
176
- blink: (t: string) => string;
177
- inverse: (t: string) => string;
178
- strikethrough: (t: string) => string;
179
- hidden: (t: string) => string;
632
+ bold: (t: unknown) => string;
633
+ dim: (t: unknown) => string;
634
+ italic: (t: unknown) => string;
635
+ underline: (t: unknown) => string;
636
+ blink: (t: unknown) => string;
637
+ inverse: (t: unknown) => string;
638
+ strikethrough: (t: unknown) => string;
639
+ hidden: (t: unknown) => string;
180
640
  rgb: (r: number, g: number, b: number) => ColorFn;
181
641
  bgRgb: (r: number, g: number, b: number) => ColorFn;
182
642
  hex: (h: string) => ColorFn;
183
643
  bgHex: (h: string) => ColorFn;
184
644
  color256: (n: number) => ColorFn;
185
645
  bgColor256: (n: number) => ColorFn;
186
- gradient: (text: string, stops: string[]) => string;
646
+ gradient: (text: unknown, stops: string[] | null | undefined, opts?: GradientOptions) => string;
187
647
  rainbow: ColorFn;
648
+ chain: () => ColorChain;
188
649
  };
189
650
 
190
- interface RGB {
191
- r: number;
192
- g: number;
193
- b: number;
194
- }
195
- declare const clamp: (n: number, min: number, max: number) => number;
196
- declare const lerp: (a: number, b: number, t: number) => number;
197
- /** Returns true when a string is a valid 3- or 6-digit hex color. */
198
- declare const isHexColor: (hex: string) => boolean;
199
651
  /**
200
- * Parses a hex color string to RGB. Throws on invalid input.
201
- * Use isHexColor() first if you need fail-soft behaviour.
202
- */
203
- declare const hexToRgb: (hex: string) => RGB;
204
- /** Converts R, G, B values to a hex string. Values are clamped to 0–255. */
205
- declare const rgbToHex: (r: number, g: number, b: number) => string;
206
- /** Linearly interpolates between two RGB colors. t is clamped to [0, 1]. */
207
- declare const lerpColor: (a: RGB, b: RGB, t: number) => RGB;
208
- declare const rgbTo256: (r: number, g: number, b: number) => number;
209
- declare const stripAnsi: (str: string) => string;
210
- declare const visibleLen: (str: string) => number;
211
- /**
212
- * Truncates a string with ANSI escapes to a max visible width.
213
- * Preserves color codes that started before the cut and emits a final reset.
652
+ * True when colors AND TTY are both available.
653
+ * Public predicate useful for callers that want to gate features.
214
654
  */
215
- declare const truncateAnsi: (str: string, width: number, ellipsis?: string) => string;
216
- declare const padEnd: (str: string, width: number, ch?: string) => string;
217
- declare const padStart: (str: string, width: number, ch?: string) => string;
218
- declare const center: (str: string, width: number, ch?: string) => string;
219
- /** Repeats a string until its visible length reaches the target width. */
220
- declare const repeatVisible: (str: string, width: number) => string;
221
- declare const termSize: () => {
222
- cols: number;
223
- rows: number;
224
- };
225
- declare const wordWrap: (text: string, width: number) => string[];
226
-
227
- interface TypewriterOptions {
655
+ declare const canAnimate: () => boolean;
656
+ /** For tests reset the cursor counter back to zero. */
657
+ declare const resetCursorRefCount: () => void;
658
+ interface AnimationHooks {
659
+ /** Called after each frame is written. Receives 0-based frame index. */
660
+ onFrame?: (frame: number) => void;
661
+ /** Called when the animation completes naturally. */
662
+ onDone?: () => void;
663
+ /** Called when the signal aborts the animation. */
664
+ onAbort?: () => void;
665
+ }
666
+ interface TypewriterOptions extends AnimationHooks {
228
667
  speed?: number;
229
668
  newline?: boolean;
230
669
  colorFn?: ColorFn | null;
231
670
  signal?: AbortSignal;
232
671
  reducedMotion?: boolean;
233
672
  }
234
- interface FadeOptions {
673
+ interface FadeOptions extends AnimationHooks {
235
674
  duration?: number;
236
675
  steps?: number;
237
676
  newline?: boolean;
@@ -239,14 +678,14 @@ interface FadeOptions {
239
678
  signal?: AbortSignal;
240
679
  reducedMotion?: boolean;
241
680
  }
242
- interface SlideOptions {
681
+ interface SlideOptions extends AnimationHooks {
243
682
  direction?: 'left' | 'right';
244
683
  duration?: number;
245
684
  newline?: boolean;
246
685
  signal?: AbortSignal;
247
686
  reducedMotion?: boolean;
248
687
  }
249
- interface PulseOptions {
688
+ interface PulseOptions extends AnimationHooks {
250
689
  times?: number;
251
690
  interval?: number;
252
691
  color1?: string | RGB;
@@ -255,7 +694,7 @@ interface PulseOptions {
255
694
  signal?: AbortSignal;
256
695
  reducedMotion?: boolean;
257
696
  }
258
- interface WaveOptions {
697
+ interface WaveOptions extends AnimationHooks {
259
698
  duration?: number;
260
699
  steps?: number;
261
700
  colors?: string[];
@@ -263,20 +702,48 @@ interface WaveOptions {
263
702
  signal?: AbortSignal;
264
703
  reducedMotion?: boolean;
265
704
  }
266
- interface GlitchOptions {
705
+ interface GlitchOptions extends AnimationHooks {
267
706
  duration?: number;
268
707
  intensity?: number;
269
708
  newline?: boolean;
270
709
  signal?: AbortSignal;
271
710
  reducedMotion?: boolean;
272
711
  }
273
- interface RevealOptions {
712
+ interface RevealOptions extends AnimationHooks {
274
713
  duration?: number;
275
714
  charset?: string;
276
715
  newline?: boolean;
277
716
  signal?: AbortSignal;
278
717
  reducedMotion?: boolean;
718
+ /**
719
+ * Number of "scramble" frames before the text resolves. Default scales
720
+ * with text length (longer text → more frames for visible reveal).
721
+ */
722
+ steps?: number;
279
723
  }
724
+ /**
725
+ * A parallel step receives the parent signal. Steps that ignore it
726
+ * (zero-arg thunks) still work via the optional parameter.
727
+ */
728
+ type ParallelStep = (opts?: {
729
+ signal?: AbortSignal;
730
+ }) => Promise<void>;
731
+ interface ParallelOptions {
732
+ signal?: AbortSignal;
733
+ /**
734
+ * Maximum time (ms) to wait for all steps to settle. After timeout,
735
+ * remaining steps are abandoned and parallel() resolves. Useful for
736
+ * preventing animations from blocking indefinitely on stuck steps.
737
+ */
738
+ timeout?: number;
739
+ }
740
+ /**
741
+ * Apply multiple animations to the SAME text in order.
742
+ * Each entry is `[fn, options]` or just `fn`.
743
+ * Errors in any step propagate after cursor cleanup.
744
+ */
745
+ type AnimFn = (text: string, opts?: Record<string, unknown>) => Promise<void>;
746
+ type ChainStep = AnimFn | [AnimFn] | [AnimFn, Record<string, unknown>];
280
747
  declare const animate: {
281
748
  typewriter: (text: string, opts?: TypewriterOptions) => Promise<void>;
282
749
  fadeIn: (text: string, opts?: FadeOptions) => Promise<void>;
@@ -286,8 +753,49 @@ declare const animate: {
286
753
  wave: (text: string, opts?: WaveOptions) => Promise<void>;
287
754
  glitch: (text: string, opts?: GlitchOptions) => Promise<void>;
288
755
  reveal: (text: string, opts?: RevealOptions) => Promise<void>;
756
+ sequence: (steps: Array<() => Promise<void>>, opts?: {
757
+ signal?: AbortSignal;
758
+ }) => Promise<void>;
759
+ chain: (text: string, steps: ChainStep[], opts?: {
760
+ signal?: AbortSignal;
761
+ }) => Promise<void>;
762
+ parallel: (steps: ParallelStep[], opts?: ParallelOptions) => Promise<void>;
763
+ delay: (ms: number) => (opts?: {
764
+ signal?: AbortSignal;
765
+ }) => Promise<void>;
289
766
  };
290
767
 
768
+ /** A glyph is an array of equal-length strings (one per row). */
769
+ type Glyph = string[];
770
+ /** Maps a character to its glyph. Every font must define ' ' or '?'. */
771
+ type FontMap = Record<string, Glyph>;
772
+ /** Built-in font name. */
773
+ type FontName = 'big' | 'small';
774
+ /** For tests — clear the render cache. */
775
+ declare const clearRenderCache: () => void;
776
+ /** For tests/debugging — current cache size. */
777
+ declare const getRenderCacheSize: () => number;
778
+ interface RegisterFontOptions {
779
+ /** Allow overwriting reserved built-in fonts (big, small). Default: false. */
780
+ force?: boolean;
781
+ }
782
+ /**
783
+ * Register a custom font at runtime.
784
+ * Validates that the font is internally consistent before accepting it.
785
+ * Throws TypeError for invalid types, Error for structural issues.
786
+ *
787
+ * @example
788
+ * ascii.registerFont('mini', {
789
+ * ' ': [' ', ' '],
790
+ * A: ['▄▀', '▀▀'],
791
+ * '?': ['?·', ' ·'],
792
+ * });
793
+ */
794
+ declare const registerFont: (name: string, fontMap: FontMap, opts?: RegisterFontOptions) => void;
795
+ /** List all registered font names. */
796
+ declare const listFonts: () => string[];
797
+ /** Check if a font is registered (built-in or custom). */
798
+ declare const hasFont: (name: string) => boolean;
291
799
  type BoxStyle = 'single' | 'double' | 'rounded' | 'heavy' | 'dashed' | 'ascii';
292
800
  interface BoxChars {
293
801
  tl: string;
@@ -301,12 +809,17 @@ declare const BOX_STYLES: Record<BoxStyle, BoxChars>;
301
809
  interface BoxOptions {
302
810
  padding?: number;
303
811
  borderStyle?: BoxStyle;
812
+ /** Fix inner content width. Lines are padded/truncated to fit. */
304
813
  width?: number | null;
305
814
  }
306
815
  interface BannerOptions {
307
- font?: 'big' | 'small';
816
+ font?: FontName | string;
308
817
  colorFn?: ColorFn | null;
818
+ /** Apply colorFn per-character instead of per-line (true gradients). */
819
+ perCharColor?: boolean;
309
820
  align?: 'left' | 'center';
821
+ /** Spaces between glyphs (default: 1). */
822
+ letterSpacing?: number;
310
823
  }
311
824
  interface DividerOptions {
312
825
  char?: string;
@@ -317,31 +830,254 @@ interface DividerOptions {
317
830
  interface LogoOptions {
318
831
  gradient?: ColorFn | null;
319
832
  boxStyle?: BoxStyle;
833
+ /** Center the rendered ASCII inside the box (default: true). */
834
+ centered?: boolean;
835
+ }
836
+ interface Dimensions {
837
+ width: number;
838
+ height: number;
839
+ }
840
+ interface StreamOptions {
841
+ /** Font name to use. Default: 'big'. */
842
+ font?: FontName | string;
843
+ /** Spaces between glyphs. Default: 1. */
844
+ letterSpacing?: number;
845
+ /** Stream granularity: 'row' yields one line at a time, 'char' yields one char. */
846
+ granularity?: 'row' | 'char';
847
+ /** Abort signal — stops yielding when triggered. */
848
+ signal?: AbortSignal;
320
849
  }
321
850
  declare const ascii: {
322
851
  big: (text: string) => string;
323
852
  small: (text: string) => string;
324
853
  figlet: (text: string, opts?: {
325
- font?: "big" | "small";
854
+ font?: FontName | string;
855
+ letterSpacing?: number;
326
856
  }) => string;
327
857
  banner: (text: string, opts?: BannerOptions) => string;
328
858
  box: (text: string, opts?: BoxOptions) => string;
329
859
  divider: (opts?: DividerOptions) => string;
330
860
  logo: (text: string, opts?: LogoOptions) => string;
861
+ stream: (text: string, opts?: StreamOptions) => AsyncGenerator<string, void, unknown>;
862
+ measure: (text: string, font?: FontName | string, letterSpacing?: number) => Dimensions;
863
+ stageRender: (text: string, font: FontName | string, letterSpacing?: number) => string;
864
+ stageAlign: (rendered: string, align: "left" | "center") => string;
865
+ stageColorize: (rendered: string, colorFn: ColorFn | null, perCharColor: boolean) => string;
866
+ registerFont: (name: string, fontMap: FontMap, opts?: RegisterFontOptions) => void;
867
+ listFonts: () => string[];
868
+ hasFont: (name: string) => boolean;
869
+ clearRenderCache: () => void;
870
+ getRenderCacheSize: () => number;
331
871
  boxStyles: Array<keyof typeof BOX_STYLES>;
332
872
  };
333
873
 
874
+ /** For tests — reset the cursor counter. */
875
+ declare const resetLoaderCursorCount: () => void;
876
+ type SpinnerType = 'dots' | 'dots2' | 'line' | 'arrow' | 'bounce' | 'star' | 'pong' | 'aesthetic' | 'blocks' | 'moon' | 'clock';
877
+ declare const SPINNERS: Record<SpinnerType, string[]>;
878
+ interface SpinOptions {
879
+ type?: SpinnerType;
880
+ interval?: number;
881
+ color?: string | null;
882
+ prefix?: string;
883
+ suffix?: string;
884
+ persist?: boolean;
885
+ signal?: AbortSignal;
886
+ reducedMotion?: boolean;
887
+ }
888
+ interface ProgressOptions {
889
+ width?: number;
890
+ char?: string;
891
+ emptyChar?: string;
892
+ showPercentage?: boolean;
893
+ color?: string | null;
894
+ label?: string;
895
+ }
896
+ interface Task {
897
+ text: string;
898
+ fn: () => Promise<unknown>;
899
+ /** Optional sub-tasks executed inside this task's lifecycle. */
900
+ subtasks?: Task[];
901
+ }
902
+ interface TaskResult {
903
+ success: boolean;
904
+ result?: unknown;
905
+ error?: Error;
906
+ /** Results for subtasks, in order of execution. */
907
+ subtasks?: TaskResult[];
908
+ }
909
+ type StopFn = (finalText?: string, success?: boolean) => void;
910
+ interface ProgressAnimateOptions extends ProgressOptions {
911
+ delay?: number;
912
+ signal?: AbortSignal;
913
+ }
914
+ interface TasksOptions {
915
+ type?: SpinnerType;
916
+ spinColor?: string;
917
+ successColor?: string;
918
+ errorColor?: string;
919
+ interval?: number;
920
+ signal?: AbortSignal;
921
+ /** Indent prefix for nested subtasks. Default 2 spaces per level. */
922
+ indent?: string;
923
+ /**
924
+ * Run top-level tasks in parallel instead of sequentially.
925
+ * Subtasks within each parent still run sequentially. Default: false.
926
+ */
927
+ parallel?: boolean;
928
+ }
929
+ interface DotsOptions {
930
+ interval?: number;
931
+ max?: number;
932
+ color?: string;
933
+ signal?: AbortSignal;
934
+ }
935
+ interface CustomOptions {
936
+ interval?: number;
937
+ color?: string;
938
+ signal?: AbortSignal;
939
+ }
940
+ interface CountdownOptions {
941
+ label?: string;
942
+ color?: string;
943
+ signal?: AbortSignal;
944
+ }
945
+ interface MultiLoaderItem {
946
+ /** Update the displayed text. */
947
+ update(text: string): void;
948
+ /** Mark as success and remove. */
949
+ succeed(text?: string): void;
950
+ /** Mark as failed and remove. */
951
+ fail(text?: string): void;
952
+ /** Just remove without success/fail. */
953
+ stop(): void;
954
+ /** Current displayed text. */
955
+ text: string;
956
+ }
957
+ interface MultiLoader {
958
+ /** Add a spinner; returns a controller for that line. */
959
+ add(text: string, opts?: {
960
+ color?: string;
961
+ type?: SpinnerType;
962
+ }): MultiLoaderItem;
963
+ /** Stop all and remove. */
964
+ clear(): void;
965
+ /** Number of active items. */
966
+ count(): number;
967
+ }
968
+ declare const loader: {
969
+ spin: (text?: string, opts?: SpinOptions) => StopFn;
970
+ progress: (percent: number, label?: string, opts?: ProgressOptions) => void;
971
+ progressAnimate: (steps: number, label?: string, opts?: ProgressAnimateOptions) => Promise<void>;
972
+ tasks: (taskList: Task[], opts?: TasksOptions) => Promise<TaskResult[]>;
973
+ dots: (text?: string, opts?: DotsOptions) => (() => void);
974
+ custom: (frames: string[], text?: string, opts?: CustomOptions) => (() => void);
975
+ countdown: (seconds: number, opts?: CountdownOptions) => Promise<void>;
976
+ multi: (opts?: {
977
+ interval?: number;
978
+ }) => MultiLoader;
979
+ /** Alias for SPINNERS — the built-in spinner frame definitions. */
980
+ spinners: Record<SpinnerType, string[]>;
981
+ };
982
+
983
+ type FrameCallback = (frame: string, index: number) => string;
984
+ interface PlayOptions {
985
+ /** Milliseconds between frames. Ignored if `fps` is provided. */
986
+ interval?: number;
987
+ /** Frames per second. Takes precedence over `interval`. Capped at 60 fps. */
988
+ fps?: number;
989
+ /** Number of full loops. 0 means infinite. Default: 1. */
990
+ repeat?: number;
991
+ /** Clear all rendered lines when playback finishes. */
992
+ clearOnFinish?: boolean;
993
+ /** Transform each frame before writing. Errors are swallowed. */
994
+ onFrame?: FrameCallback | null;
995
+ /** Called when playback completes naturally (not aborted). */
996
+ onFinish?: () => void;
997
+ /** Cancel playback mid-run. */
998
+ signal?: AbortSignal;
999
+ }
1000
+ /** Returned by `play()` — controls a running animation. */
1001
+ interface PlayController {
1002
+ /** Pause playback. Idempotent. */
1003
+ pause: () => void;
1004
+ /** Resume playback after pause. Idempotent. */
1005
+ resume: () => void;
1006
+ /** Jump to a specific frame index (modulo frame count). */
1007
+ seek: (frameIndex: number) => void;
1008
+ /** Cancel playback immediately. */
1009
+ stop: () => void;
1010
+ /** True while the animation is actively running. */
1011
+ isPlaying: () => boolean;
1012
+ /** Promise that resolves when playback finishes (or is stopped). */
1013
+ done: Promise<void>;
1014
+ }
1015
+ interface LiveOptions {
1016
+ /** Frames per second for the render tick. Default: 12. Capped at 60. */
1017
+ fps?: number;
1018
+ /** Start the render loop immediately. Default: true. */
1019
+ autoStart?: boolean;
1020
+ /** Auto-stop the render loop when this signal aborts. */
1021
+ signal?: AbortSignal;
1022
+ }
1023
+ interface LiveController {
1024
+ start: () => void;
1025
+ /** Stop the loop. Pass `{ clear: true }` to wipe the last rendered frame. */
1026
+ stop: (opts?: {
1027
+ clear?: boolean;
1028
+ }) => void;
1029
+ update: (frame: string) => void;
1030
+ /** True while the render tick is active. */
1031
+ isRunning: () => boolean;
1032
+ }
1033
+ /** For tests — reset cursor ref count. */
1034
+ declare const resetFramesCursorCount: () => void;
1035
+ interface LoadingBarOptions {
1036
+ width?: number;
1037
+ char?: string;
1038
+ empty?: string;
1039
+ label?: string;
1040
+ }
1041
+ interface BallOptions {
1042
+ width?: number;
1043
+ char?: string;
1044
+ }
1045
+ interface BreatheOptions {
1046
+ steps?: number;
1047
+ }
1048
+ interface TypeDeleteOptions {
1049
+ cursor?: string;
1050
+ }
1051
+ declare const frames: {
1052
+ play: (frames: string[], opts?: PlayOptions) => PlayController;
1053
+ generate: (count: number, fn: (i: number, total: number) => string) => string[];
1054
+ live: (opts?: LiveOptions) => LiveController;
1055
+ morph: (frameA: string, frameB: string, steps?: number, charset?: string) => string[];
1056
+ presets: {
1057
+ loadingBar: (opts?: LoadingBarOptions) => string[];
1058
+ ball: (opts?: BallOptions) => string[];
1059
+ breathe: (text: string, opts?: BreatheOptions) => string[];
1060
+ typeDelete: (text: string, opts?: TypeDeleteOptions) => string[];
1061
+ };
1062
+ };
1063
+
334
1064
  type TableBorderStyle = 'single' | 'double' | 'rounded' | 'heavy';
335
1065
  interface TableOptions {
336
1066
  header?: boolean;
337
1067
  borderStyle?: TableBorderStyle;
338
1068
  padding?: number;
1069
+ /** Truncate cell content if it exceeds the column max. Default: null (auto-size). */
1070
+ maxColWidth?: number | null;
339
1071
  }
340
1072
  interface BadgeOptions {
341
1073
  labelBg?: number;
342
1074
  valueBg?: number;
343
1075
  labelFg?: number;
344
1076
  valueFg?: number;
1077
+ /** Inner padding (spaces) around the text. Default: 1. */
1078
+ padding?: number;
1079
+ /** Wrap the badge in a box-drawing border. Default: false. */
1080
+ border?: boolean;
345
1081
  }
346
1082
  interface ProgressBarOptions {
347
1083
  width?: number;
@@ -350,8 +1086,17 @@ interface ProgressBarOptions {
350
1086
  showPercentage?: boolean;
351
1087
  label?: string;
352
1088
  color?: number | null;
1089
+ /** Optional gradient stops applied to the filled portion. Overrides `color`. */
1090
+ gradient?: string[] | null;
353
1091
  }
1092
+ declare const box: (text: string, opts?: BoxOptions) => string;
354
1093
  type StatusType = 'success' | 'error' | 'warn' | 'info' | 'wait';
1094
+ interface StatusOptions {
1095
+ /** Override the default icon (or pass `null`/empty string for no icon). */
1096
+ icon?: string | null;
1097
+ /** Override the default color. */
1098
+ color?: number;
1099
+ }
355
1100
  interface SectionOptions {
356
1101
  char?: string;
357
1102
  width?: number | null;
@@ -361,6 +1106,8 @@ interface ColumnsOptions {
361
1106
  cols?: number;
362
1107
  gap?: number;
363
1108
  width?: number | null;
1109
+ /** Truncate items wider than the column. Default: 'truncate'. Use 'wrap' to flow into multiple lines. */
1110
+ overflow?: 'truncate' | 'wrap';
364
1111
  }
365
1112
  interface TimelineEvent {
366
1113
  label: string;
@@ -373,6 +1120,8 @@ interface TimelineOptions {
373
1120
  color?: number;
374
1121
  doneColor?: number;
375
1122
  pendingColor?: number;
1123
+ /** Pad time column to this visible width for alignment. Default: max time width across events. */
1124
+ timeColumnWidth?: number | null;
376
1125
  }
377
1126
  interface MenuInput {
378
1127
  isTTY?: boolean;
@@ -399,11 +1148,147 @@ declare const components: {
399
1148
  table: (rows: string[][], opts?: TableOptions) => string;
400
1149
  badge: (label: string, value: string, opts?: BadgeOptions) => string;
401
1150
  progressBar: (percent: number, opts?: ProgressBarOptions) => string;
402
- status: (type: StatusType, message: string) => string;
1151
+ status: (type: StatusType, message: string, opts?: StatusOptions) => string;
403
1152
  section: (title: string, opts?: SectionOptions) => string;
404
1153
  columns: (items: string[], opts?: ColumnsOptions) => string;
405
1154
  timeline: (events: TimelineEvent[], opts?: TimelineOptions) => string;
406
1155
  menu: (items: string[], opts?: MenuOptions) => Promise<MenuResult>;
1156
+ box: (text: string, opts?: BoxOptions) => string;
1157
+ };
1158
+
1159
+ type TreeStyle = 'normal' | 'rounded' | 'heavy' | 'ascii';
1160
+ /**
1161
+ * Plain-data representation of a tree node.
1162
+ * Use when you have data and want to render it (e.g. JSON, filesystem walk).
1163
+ */
1164
+ interface TreeData {
1165
+ /** Display label. Multi-line strings render with aligned continuation. */
1166
+ label: string;
1167
+ /** Optional colorizer applied to this node's label. */
1168
+ color?: ColorFn;
1169
+ /** Optional icon prefix (e.g. '📁', '📄'). Rendered before label. */
1170
+ icon?: string;
1171
+ /** Override visual style for the subtree starting at this node. */
1172
+ style?: TreeStyle;
1173
+ /** Hide first N children, show "[+N hidden]" instead. */
1174
+ collapse?: number;
1175
+ /** Child nodes. */
1176
+ children?: TreeData[];
1177
+ }
1178
+ /**
1179
+ * Builder-style node returned by `tree(label)`.
1180
+ * Mirrors Rich's API: `tree('root').add('child').add('grandchild')`.
1181
+ */
1182
+ interface TreeNode extends TreeData {
1183
+ /**
1184
+ * Add a child node. Accepts a label string OR a partial TreeData object
1185
+ * for icons/colors. Returns the *child* (so `.add().add()` walks deeper).
1186
+ */
1187
+ add(child: string | Partial<TreeData>): TreeNode;
1188
+ /** Add a child and return the parent (for fluent sibling adds). */
1189
+ addLeaf(child: string | Partial<TreeData>): TreeNode;
1190
+ /** Render to string using the tree's own root style. */
1191
+ render(opts?: RenderOptions$1): string;
1192
+ }
1193
+ interface RenderOptions$1 {
1194
+ /** Visual style. Default: 'normal'. */
1195
+ style?: TreeStyle;
1196
+ /**
1197
+ * Per-depth color palette. Node at depth N uses palette[N % palette.length].
1198
+ * Per-node `color` overrides this. Empty palette is treated as "no palette".
1199
+ */
1200
+ palette?: ColorFn[];
1201
+ /**
1202
+ * Apply guide-line color (the ├──, │, └── chars).
1203
+ * Default: undefined (no color).
1204
+ */
1205
+ guideColor?: ColorFn;
1206
+ /** Maximum depth to render. Deeper nodes show "[+N more]". Default: Infinity. */
1207
+ maxDepth?: number;
1208
+ /** Indent the entire tree by N spaces. Default: 0. */
1209
+ indent?: number;
1210
+ }
1211
+ /**
1212
+ * Start a new tree with a root label. Returns a builder.
1213
+ *
1214
+ * @example
1215
+ * const t = tree('Project');
1216
+ * t.add('src').add('index.ts');
1217
+ * t.add('package.json');
1218
+ * console.log(t.render());
1219
+ */
1220
+ declare const tree: (root: string | Partial<TreeData>) => TreeNode;
1221
+ /**
1222
+ * Render a tree from plain data. Pure — no side effects.
1223
+ *
1224
+ * @example
1225
+ * renderTree({
1226
+ * label: 'src',
1227
+ * children: [
1228
+ * { label: 'index.ts' },
1229
+ * { label: 'utils', children: [{ label: 'helpers.ts' }] },
1230
+ * ],
1231
+ * });
1232
+ */
1233
+ declare const renderTree: (root: TreeData, opts?: RenderOptions$1) => string;
1234
+ declare const renderTreeStream: (root: TreeData, opts?: RenderOptions$1) => Generator<string, void, unknown>;
1235
+ interface TreeDimensions {
1236
+ width: number;
1237
+ height: number;
1238
+ }
1239
+ declare const measureTree: (root: TreeData, opts?: RenderOptions$1) => TreeDimensions;
1240
+ interface WalkVisitor {
1241
+ (node: TreeData, depth: number, isLast: boolean): void;
1242
+ }
1243
+ /**
1244
+ * Depth-first walk over the tree, calling `visitor` for each node.
1245
+ * Detects cycles to prevent infinite recursion.
1246
+ */
1247
+ declare const walkTree: (root: TreeData, visitor: WalkVisitor) => void;
1248
+ /**
1249
+ * Find the first node matching a predicate (depth-first). Returns null if none.
1250
+ *
1251
+ * @example
1252
+ * const found = findInTree(tree, (n) => n.label === 'package.json');
1253
+ */
1254
+ declare const findInTree: (root: TreeData, predicate: (node: TreeData, depth: number) => boolean) => TreeData | null;
1255
+ /**
1256
+ * Count nodes in the tree (including root).
1257
+ * @example countNodes(tree) → number of nodes total
1258
+ */
1259
+ declare const countNodes: (root: TreeData) => number;
1260
+ /**
1261
+ * Transform every node's label via `fn`. Returns a NEW tree (input untouched).
1262
+ *
1263
+ * @example
1264
+ * const uppered = mapTree(tree, (n) => ({ ...n, label: n.label.toUpperCase() }));
1265
+ */
1266
+ declare const mapTree: (root: TreeData, fn: (node: TreeData, depth: number) => TreeData) => TreeData;
1267
+ /**
1268
+ * Filter tree to keep only nodes matching `predicate`. Returns NEW tree
1269
+ * (or `null` if root itself fails the predicate).
1270
+ *
1271
+ * Note: a parent that fails the predicate but has matching descendants
1272
+ * is kept (otherwise descendants would be orphaned). Set `prune: true`
1273
+ * to drop those parents entirely (losing their descendants too).
1274
+ */
1275
+ declare const filterTree: (root: TreeData, predicate: (node: TreeData, depth: number) => boolean, opts?: {
1276
+ prune?: boolean;
1277
+ }) => TreeData | null;
1278
+ declare const trees: {
1279
+ tree: (root: string | Partial<TreeData>) => TreeNode;
1280
+ render: (root: TreeData, opts?: RenderOptions$1) => string;
1281
+ renderStream: (root: TreeData, opts?: RenderOptions$1) => Generator<string, void, unknown>;
1282
+ measure: (root: TreeData, opts?: RenderOptions$1) => TreeDimensions;
1283
+ walk: (root: TreeData, visitor: WalkVisitor) => void;
1284
+ find: (root: TreeData, predicate: (node: TreeData, depth: number) => boolean) => TreeData | null;
1285
+ count: (root: TreeData) => number;
1286
+ map: (root: TreeData, fn: (node: TreeData, depth: number) => TreeData) => TreeData;
1287
+ filter: (root: TreeData, predicate: (node: TreeData, depth: number) => boolean, opts?: {
1288
+ prune?: boolean;
1289
+ }) => TreeData | null;
1290
+ /** Map of available styles (read-only). */
1291
+ styles: TreeStyle[];
407
1292
  };
408
1293
 
409
1294
  interface Theme {
@@ -411,6 +1296,8 @@ interface Theme {
411
1296
  primary: string;
412
1297
  secondary: string;
413
1298
  accent: string;
1299
+ /** Alias-friendly success color (defaults to accent if missing). */
1300
+ success?: string;
414
1301
  warning: string;
415
1302
  error: string;
416
1303
  info: string;
@@ -420,122 +1307,163 @@ interface Theme {
420
1307
  text: string;
421
1308
  gradient: string[];
422
1309
  }
423
- declare const themes: {
1310
+ /** Names of style methods on a ThemeInstance — used by `style()`. */
1311
+ type ThemeStyleName = 'primary' | 'secondary' | 'accent' | 'success' | 'warning' | 'error' | 'info' | 'muted' | 'text';
1312
+ type ThemeChangeListener = (newTheme: Theme, oldTheme: Theme) => void;
1313
+ interface ThemeInstance {
1314
+ /** List all registered theme names (built-in + custom). */
424
1315
  list: () => string[];
1316
+ /** Look up a theme definition. Returns null if missing. */
425
1317
  get: (name: string) => Theme | null;
426
- use(name: string): /*elided*/ any;
1318
+ /** Switch active theme. Throws if name doesn't exist. */
1319
+ use: (name: string) => ThemeInstance;
1320
+ /**
1321
+ * Try to switch active theme. Returns true on success, false if missing.
1322
+ * Useful when names come from runtime config that may have typos.
1323
+ */
1324
+ tryUse: (name: string) => boolean;
1325
+ /** Get the currently active theme definition. */
427
1326
  current: () => Theme;
428
- primary: (text: string) => string;
429
- secondary: (text: string) => string;
430
- accent: (text: string) => string;
431
- warning: (text: string) => string;
432
- error: (text: string) => string;
433
- info: (text: string) => string;
434
- muted: (text: string) => string;
435
- text: (text: string) => string;
436
- bold: (text: string) => string;
437
- gradient: (text: string) => string;
1327
+ /** Register a custom theme. Validates input strictly. */
438
1328
  register: (name: string, def: Theme) => void;
439
- preview: () => void;
440
- };
1329
+ /** Remove a registered theme. Throws if removing the active one. */
1330
+ unregister: (name: string) => void;
1331
+ /**
1332
+ * Subscribe to theme changes. Returns an unsubscribe function.
1333
+ * Listener errors are caught — they don't break others.
1334
+ */
1335
+ onChange: (listener: ThemeChangeListener) => () => void;
1336
+ primary: ColorFn;
1337
+ secondary: ColorFn;
1338
+ accent: ColorFn;
1339
+ /** Semantic success color (falls back to `accent` if not defined). */
1340
+ success: ColorFn;
1341
+ warning: ColorFn;
1342
+ error: ColorFn;
1343
+ info: ColorFn;
1344
+ muted: ColorFn;
1345
+ text: ColorFn;
1346
+ bgPrimary: ColorFn;
1347
+ bgSecondary: ColorFn;
1348
+ bgAccent: ColorFn;
1349
+ bgSuccess: ColorFn;
1350
+ bgWarning: ColorFn;
1351
+ bgError: ColorFn;
1352
+ bgInfo: ColorFn;
1353
+ bgMuted: ColorFn;
1354
+ bgSurface: ColorFn;
1355
+ bold: ColorFn;
1356
+ /**
1357
+ * Dynamic accessor — get a color fn by name. Useful when the field
1358
+ * comes from config: `theme.style(level)(message)`.
1359
+ * Returns identity fn (passthrough) for unknown names.
1360
+ */
1361
+ style: (name: ThemeStyleName) => ColorFn;
1362
+ gradient: (text: string, custom?: string[]) => string;
1363
+ banner: (text: string, opts?: BannerOpts) => string;
1364
+ preview: () => string;
1365
+ }
1366
+ /**
1367
+ * Banner options — same as `ascii.banner` minus `colorFn` (we provide it).
1368
+ * Defined explicitly to avoid fragile `Omit<Parameters<...>>` derivation.
1369
+ */
1370
+ interface BannerOpts {
1371
+ font?: 'big' | 'small' | string;
1372
+ align?: 'left' | 'center';
1373
+ perCharColor?: boolean;
1374
+ letterSpacing?: number;
1375
+ }
1376
+ declare const createTheme: (initial?: string) => ThemeInstance;
1377
+ /** Clear the global singleton's color cache. */
1378
+ declare const clearThemeColorCache: () => void;
1379
+ declare const themes: ThemeInstance;
441
1380
 
442
- type Pixel = RGB | null;
1381
+ interface RGBA {
1382
+ r: number;
1383
+ g: number;
1384
+ b: number;
1385
+ /** 0..1 alpha. 1 = opaque, 0 = transparent. */
1386
+ a: number;
1387
+ }
1388
+ /** A pixel can be opaque RGB, semi-transparent RGBA, or null (fully transparent). */
1389
+ type Pixel = RGB | RGBA | null;
443
1390
  type PixelGrid = Pixel[][];
444
- declare const renderPixelArt: (pixels: PixelGrid, opts?: {
1391
+ /** Clear the ANSI escape caches. Useful for tests or after large palette changes. */
1392
+ declare const clearAnsiCache: () => void;
1393
+ interface RenderOptions {
445
1394
  scale?: number;
446
1395
  halfBlock?: boolean;
447
- }) => string;
1396
+ /** Use braille (2×4 sub-char resolution). Overrides halfBlock. */
1397
+ braille?: boolean;
1398
+ }
1399
+ declare const renderPixelArt: (pixels: PixelGrid, opts?: RenderOptions) => string;
448
1400
  declare const SPRITES: Record<string, {
449
1401
  pixels: PixelGrid;
450
1402
  }>;
451
- declare const gradientRect: (opts?: {
1403
+ declare const flipHorizontal: (pixels: PixelGrid) => PixelGrid;
1404
+ declare const flipVertical: (pixels: PixelGrid) => PixelGrid;
1405
+ declare const rotate90: (pixels: PixelGrid) => PixelGrid;
1406
+ interface GradientRectOptions {
452
1407
  width?: number;
453
1408
  height?: number;
454
1409
  colors?: string[];
455
- style?: "horizontal" | "vertical" | "diagonal" | "radial";
456
- }) => string;
1410
+ /** Built-in style. Use `angle` for arbitrary directions. */
1411
+ style?: 'horizontal' | 'vertical' | 'diagonal' | 'radial';
1412
+ /** Custom angle in degrees (0=right, 90=down). Overrides `style`. */
1413
+ angle?: number;
1414
+ /** Dithering algorithm. 'bayer' improves perceived smoothness. */
1415
+ dither?: 'none' | 'bayer';
1416
+ /** Render in braille mode for 2× horizontal × 4× vertical resolution. */
1417
+ braille?: boolean;
1418
+ }
1419
+ declare const gradientRect: (opts?: GradientRectOptions) => string;
1420
+ interface CanvasRenderOptions extends RenderOptions {
1421
+ /** Render only the dirty region instead of the whole canvas. Default: false. */
1422
+ dirtyOnly?: boolean;
1423
+ }
457
1424
  interface Canvas {
458
1425
  set: (x: number, y: number, color: Pixel) => void;
459
1426
  get: (x: number, y: number) => Pixel;
460
1427
  fill: (color: Pixel) => void;
461
- drawRect: (x: number, y: number, w: number, h: number, color: RGB, fill?: boolean) => void;
462
- drawCircle: (cx: number, cy: number, radius: number, color: RGB, fill?: boolean) => void;
463
- render: (opts?: {
464
- scale?: number;
465
- halfBlock?: boolean;
466
- }) => string;
467
- print: (opts?: {
468
- scale?: number;
469
- halfBlock?: boolean;
470
- }) => void;
1428
+ drawRect: (x: number, y: number, w: number, h: number, color: Pixel, fill?: boolean) => void;
1429
+ drawCircle: (cx: number, cy: number, radius: number, color: Pixel, fill?: boolean) => void;
1430
+ /** Composite a sprite at (x, y) with optional alpha blending. */
1431
+ drawSprite: (x: number, y: number, sprite: PixelGrid) => void;
1432
+ render: (opts?: CanvasRenderOptions) => string;
1433
+ print: (opts?: CanvasRenderOptions) => void;
1434
+ /** Resize the canvas, preserving content within the new bounds. */
1435
+ resize: (newWidth: number, newHeight: number, fillColor?: Pixel) => void;
1436
+ /** Mark all pixels as dirty (forces full redraw on next dirtyOnly render). */
1437
+ markDirty: () => void;
1438
+ /** Clear the dirty region tracker (after a full render). */
1439
+ clearDirty: () => void;
471
1440
  width: number;
472
1441
  height: number;
1442
+ /** Deep copy of the current pixel grid. Mutations don't affect the canvas. */
473
1443
  pixels: PixelGrid;
474
1444
  }
475
1445
  declare const createCanvas: (width: number, height: number, fillColor?: Pixel) => Canvas;
476
1446
  declare const images: {
477
- render: (pixels: PixelGrid, opts?: {
478
- scale?: number;
479
- halfBlock?: boolean;
480
- }) => string;
1447
+ render: (pixels: PixelGrid, opts?: RenderOptions) => string;
481
1448
  sprites: Record<string, {
482
1449
  pixels: PixelGrid;
483
1450
  }>;
484
1451
  flipHorizontal: (pixels: PixelGrid) => PixelGrid;
485
1452
  flipVertical: (pixels: PixelGrid) => PixelGrid;
486
1453
  rotate90: (pixels: PixelGrid) => PixelGrid;
487
- sprite(name: string, opts?: {
488
- scale?: number;
489
- halfBlock?: boolean;
490
- }): string;
491
- gradientRect: (opts?: {
492
- width?: number;
493
- height?: number;
494
- colors?: string[];
495
- style?: "horizontal" | "vertical" | "diagonal" | "radial";
496
- }) => string;
1454
+ sprite(name: string, opts?: RenderOptions): string;
1455
+ gradientRect: (opts?: GradientRectOptions) => string;
497
1456
  createCanvas: (width: number, height: number, fillColor?: Pixel) => Canvas;
1457
+ colors: {
1458
+ hex: (h: unknown) => RGB | null;
1459
+ lerp: (a: RGB, b: RGB, t: number) => RGB;
1460
+ blend: (fg: Pixel, bg: RGB) => RGB;
1461
+ };
1462
+ clearAnsiCache: () => void;
498
1463
  };
499
1464
 
500
- declare const cursor: {
501
- readonly up: (n?: number) => string;
502
- readonly down: (n?: number) => string;
503
- readonly right: (n?: number) => string;
504
- readonly left: (n?: number) => string;
505
- readonly to: (x: number, y: number) => string;
506
- readonly save: () => string;
507
- readonly restore: () => string;
508
- readonly hide: () => string;
509
- readonly show: () => string;
510
- };
511
- declare const screen: {
512
- readonly clear: () => string;
513
- readonly clearLine: () => string;
514
- readonly clearRight: () => string;
515
- readonly clearDown: () => string;
516
- readonly scrollUp: (n?: number) => string;
517
- readonly scrollDown: (n?: number) => string;
518
- };
519
- declare const sgr: (...codes: number[]) => string;
520
- declare const reset: () => string;
521
- declare const fgRgb: (r: number, g: number, b: number) => string;
522
- declare const bgRgb: (r: number, g: number, b: number) => string;
523
- type ColorSupport = 'none' | 'basic' | '256' | 'truecolor';
524
- declare const supportsColor: () => ColorSupport;
525
- declare const sleep: (ms: number) => Promise<void>;
526
- declare const write: (str: string) => boolean;
527
- declare const writeln: (str?: string) => boolean;
528
-
529
1465
  declare const ansimax: {
530
1466
  color: {
531
- sunset: (t: string) => string;
532
- ocean: (t: string) => string;
533
- fire: (t: string) => string;
534
- neon: (t: string) => string;
535
- forest: (t: string) => string;
536
- aurora: (t: string) => string;
537
- candy: (t: string) => string;
538
- gold: (t: string) => string;
539
1467
  black: ColorFn;
540
1468
  red: ColorFn;
541
1469
  green: ColorFn;
@@ -554,7 +1482,7 @@ declare const ansimax: {
554
1482
  brightWhite: ColorFn;
555
1483
  gray: ColorFn;
556
1484
  grey: ColorFn;
557
- orange: (t: string) => string;
1485
+ orange: (t: unknown) => string;
558
1486
  purple: ColorFn;
559
1487
  bgBlack: ColorFn;
560
1488
  bgRed: ColorFn;
@@ -564,22 +1492,23 @@ declare const ansimax: {
564
1492
  bgMagenta: ColorFn;
565
1493
  bgCyan: ColorFn;
566
1494
  bgWhite: ColorFn;
567
- bold: (t: string) => string;
568
- dim: (t: string) => string;
569
- italic: (t: string) => string;
570
- underline: (t: string) => string;
571
- blink: (t: string) => string;
572
- inverse: (t: string) => string;
573
- strikethrough: (t: string) => string;
574
- hidden: (t: string) => string;
1495
+ bold: (t: unknown) => string;
1496
+ dim: (t: unknown) => string;
1497
+ italic: (t: unknown) => string;
1498
+ underline: (t: unknown) => string;
1499
+ blink: (t: unknown) => string;
1500
+ inverse: (t: unknown) => string;
1501
+ strikethrough: (t: unknown) => string;
1502
+ hidden: (t: unknown) => string;
575
1503
  rgb: (r: number, g: number, b: number) => ColorFn;
576
1504
  bgRgb: (r: number, g: number, b: number) => ColorFn;
577
1505
  hex: (h: string) => ColorFn;
578
1506
  bgHex: (h: string) => ColorFn;
579
1507
  color256: (n: number) => ColorFn;
580
1508
  bgColor256: (n: number) => ColorFn;
581
- gradient: (text: string, stops: string[]) => string;
1509
+ gradient: (text: unknown, stops: string[] | null | undefined, opts?: GradientOptions) => string;
582
1510
  rainbow: ColorFn;
1511
+ chain: () => ColorChain;
583
1512
  };
584
1513
  animate: {
585
1514
  typewriter: (text: string, opts?: TypewriterOptions) => Promise<void>;
@@ -590,119 +1519,110 @@ declare const ansimax: {
590
1519
  wave: (text: string, opts?: WaveOptions) => Promise<void>;
591
1520
  glitch: (text: string, opts?: GlitchOptions) => Promise<void>;
592
1521
  reveal: (text: string, opts?: RevealOptions) => Promise<void>;
1522
+ sequence: (steps: Array<() => Promise<void>>, opts?: {
1523
+ signal?: AbortSignal;
1524
+ }) => Promise<void>;
1525
+ chain: (text: string, steps: (((text: string, opts?: Record<string, unknown>) => Promise<void>) | [(text: string, opts?: Record<string, unknown>) => Promise<void>] | [(text: string, opts?: Record<string, unknown>) => Promise<void>, Record<string, unknown>])[], opts?: {
1526
+ signal?: AbortSignal;
1527
+ }) => Promise<void>;
1528
+ parallel: (steps: ParallelStep[], opts?: ParallelOptions) => Promise<void>;
1529
+ delay: (ms: number) => (opts?: {
1530
+ signal?: AbortSignal;
1531
+ }) => Promise<void>;
593
1532
  };
594
1533
  ascii: {
595
1534
  big: (text: string) => string;
596
1535
  small: (text: string) => string;
597
1536
  figlet: (text: string, opts?: {
598
- font?: "big" | "small";
1537
+ font?: FontName | string;
1538
+ letterSpacing?: number;
599
1539
  }) => string;
600
1540
  banner: (text: string, opts?: BannerOptions) => string;
601
1541
  box: (text: string, opts?: BoxOptions) => string;
602
1542
  divider: (opts?: DividerOptions) => string;
603
1543
  logo: (text: string, opts?: LogoOptions) => string;
1544
+ stream: (text: string, opts?: StreamOptions) => AsyncGenerator<string, void, unknown>;
1545
+ measure: (text: string, font?: FontName | string, letterSpacing?: number) => Dimensions;
1546
+ stageRender: (text: string, font: FontName | string, letterSpacing?: number) => string;
1547
+ stageAlign: (rendered: string, align: "left" | "center") => string;
1548
+ stageColorize: (rendered: string, colorFn: ColorFn | null, perCharColor: boolean) => string;
1549
+ registerFont: (name: string, fontMap: FontMap, opts?: RegisterFontOptions) => void;
1550
+ listFonts: () => string[];
1551
+ hasFont: (name: string) => boolean;
1552
+ clearRenderCache: () => void;
1553
+ getRenderCacheSize: () => number;
604
1554
  boxStyles: Array<BoxStyle>;
605
1555
  };
606
1556
  loader: {
607
- spin: (text?: string, opts?: SpinOptions) => ((message?: string, success?: boolean) => void);
608
- dots: (text?: string, opts?: {
609
- interval?: number;
610
- max?: number;
611
- signal?: AbortSignal;
612
- }) => (() => void);
1557
+ spin: (text?: string, opts?: SpinOptions) => StopFn;
613
1558
  progress: (percent: number, label?: string, opts?: ProgressOptions) => void;
614
- progressAnimate: (steps: number, label?: string, opts?: ProgressOptions & {
615
- delay?: number;
616
- signal?: AbortSignal;
617
- }) => Promise<void>;
618
- tasks: (taskList: Task[], opts?: TaskOptions) => Promise<TaskResult[]>;
619
- custom: (frames: string[], text?: string, opts?: {
1559
+ progressAnimate: (steps: number, label?: string, opts?: ProgressAnimateOptions) => Promise<void>;
1560
+ tasks: (taskList: Task[], opts?: TasksOptions) => Promise<TaskResult[]>;
1561
+ dots: (text?: string, opts?: DotsOptions) => (() => void);
1562
+ custom: (frames: string[], text?: string, opts?: CustomOptions) => (() => void);
1563
+ countdown: (seconds: number, opts?: CountdownOptions) => Promise<void>;
1564
+ multi: (opts?: {
620
1565
  interval?: number;
621
- signal?: AbortSignal;
622
- }) => (() => void);
623
- countdown: (seconds: number, opts?: {
624
- label?: string;
625
- color?: string;
626
- signal?: AbortSignal;
627
- }) => Promise<void>;
1566
+ }) => MultiLoader;
628
1567
  spinners: Record<SpinnerType, string[]>;
629
1568
  };
630
1569
  frames: {
631
- play: (frames: string[], opts?: PlayOptions) => Promise<void>;
1570
+ play: (frames: string[], opts?: PlayOptions) => PlayController;
632
1571
  generate: (count: number, fn: (i: number, total: number) => string) => string[];
633
1572
  live: (opts?: LiveOptions) => LiveController;
634
1573
  morph: (frameA: string, frameB: string, steps?: number, charset?: string) => string[];
635
1574
  presets: {
636
- loadingBar: (opts?: {
637
- width?: number;
638
- char?: string;
639
- empty?: string;
640
- label?: string;
641
- }) => string[];
642
- ball: (opts?: {
643
- width?: number;
644
- char?: string;
645
- }) => string[];
646
- breathe: (text: string, opts?: {
647
- steps?: number;
648
- }) => string[];
649
- typeDelete: (text: string, opts?: {
650
- cursor?: string;
651
- }) => string[];
1575
+ loadingBar: (opts?: LoadingBarOptions) => string[];
1576
+ ball: (opts?: BallOptions) => string[];
1577
+ breathe: (text: string, opts?: BreatheOptions) => string[];
1578
+ typeDelete: (text: string, opts?: TypeDeleteOptions) => string[];
652
1579
  };
653
1580
  };
654
1581
  components: {
655
1582
  table: (rows: string[][], opts?: TableOptions) => string;
656
1583
  badge: (label: string, value: string, opts?: BadgeOptions) => string;
657
1584
  progressBar: (percent: number, opts?: ProgressBarOptions) => string;
658
- status: (type: StatusType, message: string) => string;
1585
+ status: (type: StatusType, message: string, opts?: StatusOptions) => string;
659
1586
  section: (title: string, opts?: SectionOptions) => string;
660
1587
  columns: (items: string[], opts?: ColumnsOptions) => string;
661
1588
  timeline: (events: TimelineEvent[], opts?: TimelineOptions) => string;
662
1589
  menu: (items: string[], opts?: MenuOptions) => Promise<MenuResult>;
1590
+ box: (text: string, opts?: BoxOptions) => string;
663
1591
  };
664
- themes: {
665
- list: () => string[];
666
- get: (name: string) => Theme | null;
667
- use(name: string): /*elided*/ any;
668
- current: () => Theme;
669
- primary: (text: string) => string;
670
- secondary: (text: string) => string;
671
- accent: (text: string) => string;
672
- warning: (text: string) => string;
673
- error: (text: string) => string;
674
- info: (text: string) => string;
675
- muted: (text: string) => string;
676
- text: (text: string) => string;
677
- bold: (text: string) => string;
678
- gradient: (text: string) => string;
679
- register: (name: string, def: Theme) => void;
680
- preview: () => void;
1592
+ trees: {
1593
+ tree: (root: string | Partial<TreeData>) => TreeNode;
1594
+ render: (root: TreeData, opts?: RenderOptions$1) => string;
1595
+ renderStream: (root: TreeData, opts?: RenderOptions$1) => Generator<string, void, unknown>;
1596
+ measure: (root: TreeData, opts?: RenderOptions$1) => TreeDimensions;
1597
+ walk: (root: TreeData, visitor: WalkVisitor) => void;
1598
+ find: (root: TreeData, predicate: (node: TreeData, depth: number) => boolean) => TreeData | null;
1599
+ count: (root: TreeData) => number;
1600
+ map: (root: TreeData, fn: (node: TreeData, depth: number) => TreeData) => TreeData;
1601
+ filter: (root: TreeData, predicate: (node: TreeData, depth: number) => boolean, opts?: {
1602
+ prune?: boolean;
1603
+ }) => TreeData | null;
1604
+ styles: TreeStyle[];
681
1605
  };
1606
+ themes: ThemeInstance;
682
1607
  images: {
683
- render: (pixels: (RGB | null)[][], opts?: {
684
- scale?: number;
685
- halfBlock?: boolean;
686
- }) => string;
1608
+ render: (pixels: PixelGrid, opts?: RenderOptions) => string;
687
1609
  sprites: Record<string, {
688
- pixels: (RGB | null)[][];
1610
+ pixels: PixelGrid;
689
1611
  }>;
690
- flipHorizontal: (pixels: (RGB | null)[][]) => (RGB | null)[][];
691
- flipVertical: (pixels: (RGB | null)[][]) => (RGB | null)[][];
692
- rotate90: (pixels: (RGB | null)[][]) => (RGB | null)[][];
693
- sprite(name: string, opts?: {
694
- scale?: number;
695
- halfBlock?: boolean;
696
- }): string;
697
- gradientRect: (opts?: {
698
- width?: number;
699
- height?: number;
700
- colors?: string[];
701
- style?: "horizontal" | "vertical" | "diagonal" | "radial";
702
- }) => string;
703
- createCanvas: (width: number, height: number, fillColor?: RGB | null) => Canvas;
1612
+ flipHorizontal: (pixels: PixelGrid) => PixelGrid;
1613
+ flipVertical: (pixels: PixelGrid) => PixelGrid;
1614
+ rotate90: (pixels: PixelGrid) => PixelGrid;
1615
+ sprite(name: string, opts?: RenderOptions): string;
1616
+ gradientRect: (opts?: GradientRectOptions) => string;
1617
+ createCanvas: (width: number, height: number, fillColor?: Pixel) => Canvas;
1618
+ colors: {
1619
+ hex: (h: unknown) => RGB | null;
1620
+ lerp: (a: RGB, b: RGB, t: number) => RGB;
1621
+ blend: (fg: Pixel, bg: RGB) => RGB;
1622
+ };
1623
+ clearAnsiCache: () => void;
704
1624
  };
705
- configure: (opts?: AnsimaxConfig) => void;
1625
+ configure: (opts?: AnsimaxConfig, meta?: ConfigureOptions) => void;
706
1626
  };
707
1627
 
708
- export { type AnimationSpeed, type AnsimaxConfig, type BadgeOptions, type BannerOptions, type BoxOptions, type BoxStyle, type Canvas, type ColorFn, type ColorMode, type ColumnsOptions, type DividerOptions, type FadeOptions, type GlitchOptions, type LiveController, type LogoOptions, type MenuInput, type MenuOptions, type MenuOutput, type MenuResult, type PlayOptions, type ProgressBarOptions, type ProgressOptions, type PulseOptions, type RGB, type RevealOptions, SPINNERS, SPRITES, type SectionOptions, type SlideOptions, type SpinOptions, type SpinnerType, type StatusType, type TableOptions, type Task, type TaskResult, type Theme, type TimelineEvent, type TimelineOptions, type TypewriterOptions, type WaveOptions, animate, ascii, bgRgb, center, clamp, color, presets as colorPresets, components, compose, configure, createCanvas, cursor, ansimax as default, fgRgb, frames, getConfig, getSpeedMultiplier, gradient, gradientRect, hexToRgb, images, isHexColor, isNoColor, lerp, lerpColor, loader, padEnd, padStart, rainbow, renderPixelArt, repeatVisible, reset, resetNoColor, rgbTo256, rgbToHex, screen, setNoColor, sgr, sleep, stripAnsi, supportsColor, termSize, themes, truncateAnsi, visibleLen, wordWrap, write, writeln };
1628
+ export { type AnimationHooks, type AnimationSpeed, type AnsiCode, type AnsimaxConfig, BEL, BG, type BadgeOptions, type BallOptions, type BannerOptions, type BoxOptions, type BoxStyle, type BreatheOptions, DEFAULTS as CONFIG_DEFAULTS, CSI, type Canvas, type CanvasRenderOptions, type ColorChain, type ColorFn, type ColorLevel, type ColorMode, type ColorSupport, type ColumnsOptions, type ConfigChangeListener, type ConfigKey, type ConfigKeyListener, type ConfigureOptions, type CountdownOptions, type CustomOptions, DEFAULT_TERM_COLS, DEFAULT_TERM_ROWS, type DebounceOptions, type DiffType, type Dimensions, type DividerOptions, type DotsOptions, ESC, type EraseMode, FG, FRAME_MS, type FadeOptions, type FontMap, type FontName, type FrameCallback, type FrameHandle, type GlitchOptions, type Glyph, type GradientOptions, type GradientRectOptions, type LineDiff, type LiveController, type LiveOptions, type LoadingBarOptions, type LogoOptions, MENU_CANCELLED, type MemoizeOptions, type MenuInput, type MenuOptions, type MenuOutput, type MenuResult, type MultiLoader, type MultiLoaderItem, OSC, type OnResizeOptions, type OutputBuffer, type ParallelOptions, type ParallelStep, type Pixel, type PixelGrid, type PlayController, type PlayOptions, type PresetName, type ProgressAnimateOptions, type ProgressBarOptions, type ProgressOptions, type PulseOptions, type RGB, type RGBA, type RegisterFontOptions, type RenderOptions, type ResizeListener, type RevealOptions, SPINNERS, SPRITES, ST, STYLE, type SectionOptions, type SleepOptions, type SlideOptions, type SpinOptions, type SpinnerType, type StatusOptions, type StatusType, type StopFn, type StreamOptions, type TableBorderStyle, type TableOptions, type Task, type TaskResult, type TasksOptions, type Theme, type BannerOpts as ThemeBannerOpts, type ThemeChangeListener, type ThemeInstance, type ThemeStyleName, type TimelineEvent, type TimelineOptions, type TreeData, type TreeDimensions, type TreeNode, type RenderOptions$1 as TreeRenderOptions, type TreeStyle, type TypeDeleteOptions, type TypewriterOptions, type WalkVisitor, type WaveOptions, type WriteAsyncOptions, animate, ascii, bell, bg256, bgRgb, box, canAnimate, cancelTerminalFrame, center, chain, charWidth, clamp, clearAnsiCache, clearColorCache, clearRenderCache, clearThemeColorCache, color, colorLevel, presets as colorPresets, components, compose, configure, countNodes, createCanvas, createOutputBuffer, createTheme, cursor, debounce, ansimax as default, diffLines, escapeRegex, fg256, fgRgb, filterTree, findInTree, flipHorizontal, flipVertical, frames, getConfig, getConfigValue, getRenderCacheSize, getSpeedMultiplier, getTerminalHeight, getTerminalWidth, gradient, gradientColor, gradientRect, graphemes, hasFont, hexToRgb, hideCursor, images, isHexColor, isNoColor, lerp, lerpColor, link, listFonts, listPresets, loader, mapTree, measureTree, memoize, nextTick, onConfigChange, onConfigKeyChange, onResize, once, padBoth, padEnd, padStart, pauseListeners, presetNames, rainbow, registerFont, registerPreset, renderPixelArt, renderTree, renderTreeStream, repeatVisible, requestTerminalFrame, reset, resetColorSupportCache, resetConfig, resetCursorRefCount, resetFramesCursorCount, resetLoaderCursorCount, resetNoColor, resumeListeners, rgbTo256, rgbToHex, rotate90, safeJson, screen, setNoColor, setTitle, sgr, showCursor, sleep, sleepFrame, sliceAnsi, stripAnsi$1 as stripAnsi, stripAnsi$2 as stripAnsiCodes, stripAnsi as stripAnsiColors, supportsColor, supportsColorLevel, termSize, themes, throttle, tree, trees, truncateAnsi, visibleLen, walkTree, withConfig, wordWrap, wrapAnsi, write, writeAsync, writeErr, writeln, writelnErr };