ansimax 1.3.1 ā 1.3.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +178 -0
- package/README.es.md +117 -8
- package/README.md +117 -8
- package/dist/index.d.mts +309 -2
- package/dist/index.d.ts +309 -2
- package/dist/index.js +209 -42
- package/dist/index.mjs +208 -42
- package/docs/README.md +110 -0
- package/docs/examples-cjs.md +706 -0
- package/docs/examples-mjs.md +676 -0
- package/docs/examples-ts.md +715 -0
- package/docs/showcase.md +398 -0
- package/examples/all-in-one.cjs +1 -1
- package/examples/all-in-one.mjs +1 -1
- package/package.json +2 -1
|
@@ -0,0 +1,715 @@
|
|
|
1
|
+
# š ansimax ā TypeScript examples
|
|
2
|
+
|
|
3
|
+
All examples are written in **TypeScript** with explicit types. Save any snippet as `example.ts` and run with:
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
npx tsx example.ts
|
|
7
|
+
# or: npx ts-node example.ts
|
|
8
|
+
# or: npx tsc example.ts && node example.js
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
For JavaScript versions, see [`examples-mjs.md`](./examples-mjs.md) (ESM) or [`examples-cjs.md`](./examples-cjs.md) (CommonJS).
|
|
12
|
+
|
|
13
|
+
---
|
|
14
|
+
|
|
15
|
+
## šØ 1. `color` ā Terminal colors & styles
|
|
16
|
+
|
|
17
|
+
### 1.1 ā Basic colored output
|
|
18
|
+
|
|
19
|
+
```ts
|
|
20
|
+
import { color } from 'ansimax';
|
|
21
|
+
|
|
22
|
+
console.log(color.green('ā Build successful'));
|
|
23
|
+
console.log(color.red('ā Build failed'));
|
|
24
|
+
console.log(color.yellow('ā 3 warnings'));
|
|
25
|
+
console.log(color.cyan('ā¹ Check the logs above'));
|
|
26
|
+
|
|
27
|
+
// Composable styles
|
|
28
|
+
const heading: string = color.bold(color.magenta('Application started'));
|
|
29
|
+
console.log(heading);
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### 1.2 ā Status report with mixed colors
|
|
33
|
+
|
|
34
|
+
```ts
|
|
35
|
+
import { color } from 'ansimax';
|
|
36
|
+
|
|
37
|
+
interface Service {
|
|
38
|
+
name: string;
|
|
39
|
+
status: 'up' | 'down' | 'degraded';
|
|
40
|
+
latency: number;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const services: Service[] = [
|
|
44
|
+
{ name: 'api', status: 'up', latency: 45 },
|
|
45
|
+
{ name: 'database', status: 'up', latency: 12 },
|
|
46
|
+
{ name: 'cache', status: 'degraded', latency: 240 },
|
|
47
|
+
{ name: 'auth', status: 'down', latency: 0 },
|
|
48
|
+
];
|
|
49
|
+
|
|
50
|
+
console.log(color.bold('Service Health Report\n'));
|
|
51
|
+
|
|
52
|
+
for (const svc of services) {
|
|
53
|
+
const icon = svc.status === 'up' ? color.green('ā')
|
|
54
|
+
: svc.status === 'degraded' ? color.yellow('ā')
|
|
55
|
+
: color.red('ā');
|
|
56
|
+
const lat = svc.latency > 100 ? color.red(`${svc.latency}ms`)
|
|
57
|
+
: svc.latency > 50 ? color.yellow(`${svc.latency}ms`)
|
|
58
|
+
: color.green(`${svc.latency}ms`);
|
|
59
|
+
|
|
60
|
+
console.log(`${icon} ${svc.name.padEnd(10)} ${lat}`);
|
|
61
|
+
}
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
### 1.3 ā Truecolor & hex colors
|
|
65
|
+
|
|
66
|
+
```ts
|
|
67
|
+
import { color } from 'ansimax';
|
|
68
|
+
|
|
69
|
+
// Hex colors via background helpers
|
|
70
|
+
console.log(color.bgHex('#bd93f9')(' Dracula purple '));
|
|
71
|
+
console.log(color.bgHex('#ff79c6')(' Pink '));
|
|
72
|
+
console.log(color.bgHex('#50fa7b')(' Green '));
|
|
73
|
+
|
|
74
|
+
// Foreground hex
|
|
75
|
+
console.log(color.hex('#ff6b6b')('Bright red text'));
|
|
76
|
+
console.log(color.hex('#4ecdc4')('Turquoise text'));
|
|
77
|
+
|
|
78
|
+
// ANSI escapes are stripped automatically when piped to a non-TTY:
|
|
79
|
+
// node example.ts ā colored
|
|
80
|
+
// node example.ts | cat ā plain text
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
---
|
|
84
|
+
|
|
85
|
+
## š 2. `gradient` ā Multi-stop gradients
|
|
86
|
+
|
|
87
|
+
### 2.1 ā Simple two-color gradient
|
|
88
|
+
|
|
89
|
+
```ts
|
|
90
|
+
import { gradient } from 'ansimax';
|
|
91
|
+
|
|
92
|
+
console.log(gradient('Hello, gradients!', ['#ff79c6', '#bd93f9']));
|
|
93
|
+
console.log(gradient('Pink to purple', ['#ff79c6', '#bd93f9']));
|
|
94
|
+
console.log(gradient('Sunset', ['#ff5e62', '#ff9966', '#ffd86f']));
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
### 2.2 ā Reusable gradient with easing
|
|
98
|
+
|
|
99
|
+
```ts
|
|
100
|
+
import { createGradient, type EasingName } from 'ansimax';
|
|
101
|
+
|
|
102
|
+
const easings: EasingName[] = ['linear', 'ease-in', 'ease-out', 'ease-in-out'];
|
|
103
|
+
|
|
104
|
+
for (const ease of easings) {
|
|
105
|
+
const grad = createGradient(['#8be9fd', '#bd93f9', '#ff79c6'], { easing: ease });
|
|
106
|
+
console.log(`${ease.padEnd(15)} ${grad('āāāāāāāāāāāāāāāāāāāāāāāāāāāā')}`);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
// Custom easing function (t ā [0, 1] ā eased t)
|
|
110
|
+
const cubic = createGradient(['#ff0000', '#0000ff'], {
|
|
111
|
+
easing: (t: number) => t * t * t,
|
|
112
|
+
});
|
|
113
|
+
console.log(cubic('Custom cubic easing across this whole line'));
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### 2.3 ā Animated gradient (color cycles over time)
|
|
117
|
+
|
|
118
|
+
```ts
|
|
119
|
+
import { animateGradient } from 'ansimax';
|
|
120
|
+
|
|
121
|
+
const ctrl = animateGradient(
|
|
122
|
+
'āāāā Loading data... āāāā',
|
|
123
|
+
['#ff79c6', '#bd93f9', '#8be9fd', '#50fa7b'],
|
|
124
|
+
{
|
|
125
|
+
interval: 80,
|
|
126
|
+
cycles: 3, // play 3 full color cycles
|
|
127
|
+
duration: 800, // ms per cycle
|
|
128
|
+
infinite: false,
|
|
129
|
+
},
|
|
130
|
+
);
|
|
131
|
+
|
|
132
|
+
await ctrl.promise;
|
|
133
|
+
console.log('\nā Done');
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
---
|
|
137
|
+
|
|
138
|
+
## š¤ 3. `ascii` ā Boxes, banners, image-to-ASCII
|
|
139
|
+
|
|
140
|
+
### 3.1 ā Boxes with multiple styles
|
|
141
|
+
|
|
142
|
+
```ts
|
|
143
|
+
import { ascii, gradient } from 'ansimax';
|
|
144
|
+
|
|
145
|
+
console.log(ascii.box('Hello world!', { borderStyle: 'rounded' }));
|
|
146
|
+
console.log(ascii.box('Important!', { borderStyle: 'double', padding: 2 }));
|
|
147
|
+
|
|
148
|
+
// Box around colored content ā border stays uncolored
|
|
149
|
+
const colored = gradient('Rainbow inside', ['#ff79c6', '#bd93f9', '#8be9fd']);
|
|
150
|
+
console.log(ascii.box(colored, { borderStyle: 'heavy', padding: 1 }));
|
|
151
|
+
|
|
152
|
+
// Multi-line box
|
|
153
|
+
const multi = 'Line 1\nLine 2\nLine 3 longer\n\nWith blank line';
|
|
154
|
+
console.log(ascii.box(multi, { borderStyle: 'rounded', padding: 1 }));
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
### 3.2 ā Banner with figlet font
|
|
158
|
+
|
|
159
|
+
```ts
|
|
160
|
+
import { ascii, gradient } from 'ansimax';
|
|
161
|
+
|
|
162
|
+
const banner: string = ascii.figletText('ANSIMAX', { font: 'standard' });
|
|
163
|
+
const colored: string = gradient(banner, ['#ff79c6', '#bd93f9', '#8be9fd']);
|
|
164
|
+
console.log(colored);
|
|
165
|
+
|
|
166
|
+
// Different font
|
|
167
|
+
const compact: string = ascii.figletText('v1.3.2', { font: 'small' });
|
|
168
|
+
console.log(ascii.box(compact, { borderStyle: 'rounded' }));
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
### 3.3 ā Image-to-ASCII from a PixelGrid
|
|
172
|
+
|
|
173
|
+
```ts
|
|
174
|
+
import { ascii, type PixelGrid } from 'ansimax';
|
|
175
|
+
|
|
176
|
+
// Build a small "image" ā a smiley face ā programmatically
|
|
177
|
+
const N = null;
|
|
178
|
+
const Y = { r: 255, g: 220, b: 0 };
|
|
179
|
+
const K = { r: 0, g: 0, b: 0 };
|
|
180
|
+
|
|
181
|
+
const smiley: PixelGrid = [
|
|
182
|
+
[N, N, Y, Y, Y, Y, N, N],
|
|
183
|
+
[N, Y, Y, Y, Y, Y, Y, N],
|
|
184
|
+
[Y, Y, K, Y, Y, K, Y, Y],
|
|
185
|
+
[Y, Y, Y, Y, Y, Y, Y, Y],
|
|
186
|
+
[Y, K, Y, Y, Y, Y, K, Y],
|
|
187
|
+
[Y, Y, K, K, K, K, Y, Y],
|
|
188
|
+
[N, Y, Y, Y, Y, Y, Y, N],
|
|
189
|
+
[N, N, Y, Y, Y, Y, N, N],
|
|
190
|
+
];
|
|
191
|
+
|
|
192
|
+
console.log(ascii.fromImage(smiley, { width: 30, ramp: 'block' }));
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
---
|
|
196
|
+
|
|
197
|
+
## ⨠4. `animations` ā Typewriter, fadeIn, fadeOut
|
|
198
|
+
|
|
199
|
+
### 4.1 ā Typewriter effect
|
|
200
|
+
|
|
201
|
+
```ts
|
|
202
|
+
import { animate } from 'ansimax';
|
|
203
|
+
|
|
204
|
+
await animate.typewriter('Loading project configuration...', { speed: 40 });
|
|
205
|
+
console.log();
|
|
206
|
+
|
|
207
|
+
// Abortable ā stops after 500ms even on a long string
|
|
208
|
+
const ctrl = new AbortController();
|
|
209
|
+
setTimeout(() => ctrl.abort(), 500);
|
|
210
|
+
|
|
211
|
+
try {
|
|
212
|
+
await animate.typewriter(
|
|
213
|
+
'This is a very long sentence that will get cut off mid-print.',
|
|
214
|
+
{ speed: 30, signal: ctrl.signal },
|
|
215
|
+
);
|
|
216
|
+
} catch {
|
|
217
|
+
console.log('\n(aborted)');
|
|
218
|
+
}
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
### 4.2 ā Fade in with custom color
|
|
222
|
+
|
|
223
|
+
```ts
|
|
224
|
+
import { animate } from 'ansimax';
|
|
225
|
+
|
|
226
|
+
await animate.fadeIn('ā
Welcome to the demo ā
', {
|
|
227
|
+
duration: 1200,
|
|
228
|
+
color: '#bd93f9',
|
|
229
|
+
steps: 25,
|
|
230
|
+
});
|
|
231
|
+
console.log();
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
### 4.3 ā Sequenced reveals for a fake intro
|
|
235
|
+
|
|
236
|
+
```ts
|
|
237
|
+
import { animate, color } from 'ansimax';
|
|
238
|
+
|
|
239
|
+
const lines: string[] = [
|
|
240
|
+
'> Initializing system...',
|
|
241
|
+
'> Loading modules: 12/12 ā',
|
|
242
|
+
'> Connecting to mainframe...',
|
|
243
|
+
'> Access granted',
|
|
244
|
+
'> Welcome, operator.',
|
|
245
|
+
];
|
|
246
|
+
|
|
247
|
+
for (const line of lines) {
|
|
248
|
+
await animate.typewriter(color.green(line), { speed: 25 });
|
|
249
|
+
console.log();
|
|
250
|
+
await new Promise<void>((resolve) => setTimeout(resolve, 200));
|
|
251
|
+
}
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
---
|
|
255
|
+
|
|
256
|
+
## ā³ 5. `loaders` ā Spinners, tasks, progress
|
|
257
|
+
|
|
258
|
+
### 5.1 ā Spinner with success/error states
|
|
259
|
+
|
|
260
|
+
```ts
|
|
261
|
+
import { loader } from 'ansimax';
|
|
262
|
+
|
|
263
|
+
const stop = loader.spin('Fetching data from API...', {
|
|
264
|
+
type: 'dots',
|
|
265
|
+
color: '#bd93f9',
|
|
266
|
+
});
|
|
267
|
+
|
|
268
|
+
try {
|
|
269
|
+
await new Promise<void>((resolve) => setTimeout(resolve, 1500));
|
|
270
|
+
stop('Data loaded successfully!', true);
|
|
271
|
+
} catch {
|
|
272
|
+
stop('Request failed', false);
|
|
273
|
+
}
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
### 5.2 ā Hierarchical task runner
|
|
277
|
+
|
|
278
|
+
```ts
|
|
279
|
+
import { loader } from 'ansimax';
|
|
280
|
+
|
|
281
|
+
const sleep = (ms: number) => new Promise<void>((r) => setTimeout(r, ms));
|
|
282
|
+
|
|
283
|
+
await loader.tasks([
|
|
284
|
+
{
|
|
285
|
+
text: 'Build pipeline',
|
|
286
|
+
fn: async () => sleep(200),
|
|
287
|
+
subtasks: [
|
|
288
|
+
{ text: 'Compile TypeScript', fn: async () => sleep(400) },
|
|
289
|
+
{ text: 'Bundle for production', fn: async () => sleep(300) },
|
|
290
|
+
{ text: 'Generate type defs', fn: async () => sleep(200) },
|
|
291
|
+
],
|
|
292
|
+
},
|
|
293
|
+
{
|
|
294
|
+
text: 'Quality checks',
|
|
295
|
+
fn: async () => sleep(150),
|
|
296
|
+
subtasks: [
|
|
297
|
+
{ text: 'Lint', fn: async () => sleep(250) },
|
|
298
|
+
{ text: 'Test', fn: async () => sleep(500) },
|
|
299
|
+
],
|
|
300
|
+
},
|
|
301
|
+
{ text: 'Publish to npm', fn: async () => sleep(300) },
|
|
302
|
+
]);
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
### 5.3 ā Parallel task execution with results
|
|
306
|
+
|
|
307
|
+
```ts
|
|
308
|
+
import { loader } from 'ansimax';
|
|
309
|
+
|
|
310
|
+
interface CheckResult {
|
|
311
|
+
ok: boolean;
|
|
312
|
+
duration: number;
|
|
313
|
+
}
|
|
314
|
+
|
|
315
|
+
const ping = async (name: string): Promise<CheckResult> => {
|
|
316
|
+
const start = Date.now();
|
|
317
|
+
await new Promise<void>((r) => setTimeout(r, 200 + Math.random() * 600));
|
|
318
|
+
return { ok: Math.random() > 0.2, duration: Date.now() - start };
|
|
319
|
+
};
|
|
320
|
+
|
|
321
|
+
const results = await loader.tasks([
|
|
322
|
+
{ text: 'Check api.example.com', fn: async () => { await ping('api'); } },
|
|
323
|
+
{ text: 'Check db.example.com', fn: async () => { await ping('db'); } },
|
|
324
|
+
{ text: 'Check auth.example.com', fn: async () => { await ping('auth'); } },
|
|
325
|
+
{ text: 'Check cdn.example.com', fn: async () => { await ping('cdn'); } },
|
|
326
|
+
], { parallel: true });
|
|
327
|
+
|
|
328
|
+
const failed = results.filter((r) => !r.success);
|
|
329
|
+
console.log(`\n${results.length - failed.length}/${results.length} services healthy`);
|
|
330
|
+
```
|
|
331
|
+
|
|
332
|
+
---
|
|
333
|
+
|
|
334
|
+
## š§± 6. `components` ā Table, badge, status, timeline
|
|
335
|
+
|
|
336
|
+
### 6.1 ā Status report with badges
|
|
337
|
+
|
|
338
|
+
```ts
|
|
339
|
+
import { components } from 'ansimax';
|
|
340
|
+
|
|
341
|
+
console.log(
|
|
342
|
+
components.badge('VERSION', 'v1.3.2'),
|
|
343
|
+
components.badge('BUILD', 'passing'),
|
|
344
|
+
components.badge('TESTS', '2000+ passing'),
|
|
345
|
+
components.badge('LICENSE', 'Apache 2.0'),
|
|
346
|
+
);
|
|
347
|
+
|
|
348
|
+
console.log();
|
|
349
|
+
console.log(components.status('success', 'Build completed in 4.2s'));
|
|
350
|
+
console.log(components.status('warn', '3 deprecation warnings'));
|
|
351
|
+
console.log(components.status('error', 'Type error in src/main.ts:42'));
|
|
352
|
+
console.log(components.status('info', 'Documentation generated at docs/'));
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
### 6.2 ā Table with ANSI-aware cells
|
|
356
|
+
|
|
357
|
+
```ts
|
|
358
|
+
import { components, color } from 'ansimax';
|
|
359
|
+
|
|
360
|
+
const rows: string[][] = [
|
|
361
|
+
['Service', 'Status', 'Latency', 'Uptime'],
|
|
362
|
+
['api', color.green('ā healthy'), '45ms', '99.99%'],
|
|
363
|
+
['db', color.green('ā healthy'), '12ms', '99.95%'],
|
|
364
|
+
['cache', color.yellow('ā degraded'), '240ms', '98.20%'],
|
|
365
|
+
['auth', color.red('ā down'), 'ā', '95.10%'],
|
|
366
|
+
];
|
|
367
|
+
|
|
368
|
+
console.log(components.table(rows, {
|
|
369
|
+
borderStyle: 'rounded',
|
|
370
|
+
padding: 1,
|
|
371
|
+
}));
|
|
372
|
+
```
|
|
373
|
+
|
|
374
|
+
### 6.3 ā Project timeline with done/pending
|
|
375
|
+
|
|
376
|
+
```ts
|
|
377
|
+
import { components } from 'ansimax';
|
|
378
|
+
|
|
379
|
+
interface ProjectEvent {
|
|
380
|
+
label: string;
|
|
381
|
+
time?: string;
|
|
382
|
+
done?: boolean;
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
const events: ProjectEvent[] = [
|
|
386
|
+
{ label: 'Project initialized', time: 'Mon', done: true },
|
|
387
|
+
{ label: 'Dependencies set up', time: 'Tue', done: true },
|
|
388
|
+
{ label: 'Core modules done', time: 'Wed', done: true },
|
|
389
|
+
{ label: 'Tests passing', time: 'Thu', done: true },
|
|
390
|
+
{ label: 'Documentation', time: 'Fri', done: false }, // current
|
|
391
|
+
{ label: 'Publish to npm', done: false },
|
|
392
|
+
];
|
|
393
|
+
|
|
394
|
+
console.log(components.timeline(events, { node: 'ā', connector: 'ā' }));
|
|
395
|
+
```
|
|
396
|
+
|
|
397
|
+
---
|
|
398
|
+
|
|
399
|
+
## šØ 7. `themes` ā Built-in and custom themes
|
|
400
|
+
|
|
401
|
+
### 7.1 ā Switching active theme
|
|
402
|
+
|
|
403
|
+
```ts
|
|
404
|
+
import { themes, type Theme } from 'ansimax';
|
|
405
|
+
|
|
406
|
+
themes.use('dracula');
|
|
407
|
+
const active: Theme = themes.current();
|
|
408
|
+
|
|
409
|
+
console.log(`Active theme: ${active.name}`);
|
|
410
|
+
console.log(`Primary color: ${active.primary}`);
|
|
411
|
+
console.log(`Available themes: ${themes.list().join(', ')}`);
|
|
412
|
+
```
|
|
413
|
+
|
|
414
|
+
### 7.2 ā Registering a custom theme
|
|
415
|
+
|
|
416
|
+
```ts
|
|
417
|
+
import { themes, type Theme } from 'ansimax';
|
|
418
|
+
|
|
419
|
+
const synthwave: Theme = {
|
|
420
|
+
name: 'synthwave',
|
|
421
|
+
primary: '#ff6ec7',
|
|
422
|
+
secondary: '#36d6e7',
|
|
423
|
+
accent: '#ffd93d',
|
|
424
|
+
success: '#06d6a0',
|
|
425
|
+
warning: '#ffd93d',
|
|
426
|
+
error: '#ff5e5b',
|
|
427
|
+
info: '#36d6e7',
|
|
428
|
+
muted: '#6c757d',
|
|
429
|
+
bg: '#241734',
|
|
430
|
+
surface: '#34174f',
|
|
431
|
+
text: '#ffffff',
|
|
432
|
+
gradient: ['#ff6ec7', '#36d6e7'],
|
|
433
|
+
};
|
|
434
|
+
|
|
435
|
+
themes.register('synthwave', synthwave);
|
|
436
|
+
themes.use('synthwave');
|
|
437
|
+
|
|
438
|
+
console.log(`Now using: ${themes.current().name}`);
|
|
439
|
+
```
|
|
440
|
+
|
|
441
|
+
### 7.3 ā Subscribing to theme changes (live UI updates)
|
|
442
|
+
|
|
443
|
+
```ts
|
|
444
|
+
import { themes, type Theme } from 'ansimax';
|
|
445
|
+
|
|
446
|
+
const unsubscribe = themes.onChange((newT: Theme, oldT: Theme) => {
|
|
447
|
+
console.log(`Theme changed: ${oldT.name} ā ${newT.name}`);
|
|
448
|
+
// In a real app: trigger UI re-render here
|
|
449
|
+
});
|
|
450
|
+
|
|
451
|
+
themes.use('dracula'); // logs "default ā dracula"
|
|
452
|
+
themes.use('nord'); // logs "dracula ā nord"
|
|
453
|
+
themes.use('monokai'); // logs "nord ā monokai"
|
|
454
|
+
|
|
455
|
+
unsubscribe(); // stop listening
|
|
456
|
+
themes.use('dracula'); // no log this time
|
|
457
|
+
```
|
|
458
|
+
|
|
459
|
+
---
|
|
460
|
+
|
|
461
|
+
## š³ 8. `trees` ā Hierarchical rendering
|
|
462
|
+
|
|
463
|
+
### 8.1 ā Simple file tree
|
|
464
|
+
|
|
465
|
+
```ts
|
|
466
|
+
import { trees, type TreeNode } from 'ansimax';
|
|
467
|
+
|
|
468
|
+
const projectTree: TreeNode = {
|
|
469
|
+
label: 'my-app/',
|
|
470
|
+
children: [
|
|
471
|
+
{
|
|
472
|
+
label: 'src/',
|
|
473
|
+
children: [
|
|
474
|
+
{ label: 'index.ts' },
|
|
475
|
+
{ label: 'utils.ts' },
|
|
476
|
+
{ label: 'config.ts' },
|
|
477
|
+
],
|
|
478
|
+
},
|
|
479
|
+
{
|
|
480
|
+
label: 'tests/',
|
|
481
|
+
children: [
|
|
482
|
+
{ label: 'unit/' },
|
|
483
|
+
{ label: 'e2e/' },
|
|
484
|
+
],
|
|
485
|
+
},
|
|
486
|
+
{ label: 'package.json' },
|
|
487
|
+
{ label: 'README.md' },
|
|
488
|
+
],
|
|
489
|
+
};
|
|
490
|
+
|
|
491
|
+
console.log(trees.tree(projectTree, { style: 'unicode' }));
|
|
492
|
+
```
|
|
493
|
+
|
|
494
|
+
### 8.2 ā Limit depth for large trees
|
|
495
|
+
|
|
496
|
+
```ts
|
|
497
|
+
import { trees, type TreeNode } from 'ansimax';
|
|
498
|
+
|
|
499
|
+
const deep: TreeNode = {
|
|
500
|
+
label: 'root',
|
|
501
|
+
children: [
|
|
502
|
+
{ label: 'level-1', children: [
|
|
503
|
+
{ label: 'level-2', children: [
|
|
504
|
+
{ label: 'level-3', children: [
|
|
505
|
+
{ label: 'level-4 (hidden)' },
|
|
506
|
+
]},
|
|
507
|
+
]},
|
|
508
|
+
]},
|
|
509
|
+
],
|
|
510
|
+
};
|
|
511
|
+
|
|
512
|
+
// Only show 2 levels deep, collapse rest with "..."
|
|
513
|
+
console.log(trees.tree(deep, { maxDepth: 2 }));
|
|
514
|
+
```
|
|
515
|
+
|
|
516
|
+
### 8.3 ā Cycle-safe rendering (no infinite recursion)
|
|
517
|
+
|
|
518
|
+
```ts
|
|
519
|
+
import { trees, type TreeNode } from 'ansimax';
|
|
520
|
+
|
|
521
|
+
// Two nodes referencing each other ā cycle
|
|
522
|
+
const a: TreeNode = { label: 'Node A', children: [] };
|
|
523
|
+
const b: TreeNode = { label: 'Node B', children: [] };
|
|
524
|
+
a.children = [b];
|
|
525
|
+
b.children = [a]; // ā cycle!
|
|
526
|
+
|
|
527
|
+
// trees.tree() detects the cycle and shows [Circular] instead of crashing
|
|
528
|
+
console.log(trees.tree(a, { maxDepth: 5 }));
|
|
529
|
+
```
|
|
530
|
+
|
|
531
|
+
---
|
|
532
|
+
|
|
533
|
+
## š¬ 9. `frames` ā Frame-by-frame animation
|
|
534
|
+
|
|
535
|
+
### 9.1 ā Loading spinner with custom frames
|
|
536
|
+
|
|
537
|
+
```ts
|
|
538
|
+
import { frames } from 'ansimax';
|
|
539
|
+
|
|
540
|
+
const spinner = ['ā ', 'ā ', 'ā ¹', 'ā ø', 'ā ¼', 'ā “', 'ā ¦', 'ā §', 'ā ', 'ā '];
|
|
541
|
+
|
|
542
|
+
const ctrl = frames.play(
|
|
543
|
+
spinner.map((f) => `${f} Loading...`),
|
|
544
|
+
{ interval: 80, loop: true },
|
|
545
|
+
);
|
|
546
|
+
|
|
547
|
+
setTimeout(() => ctrl.stop(), 3000);
|
|
548
|
+
await ctrl.promise;
|
|
549
|
+
console.log('Done!');
|
|
550
|
+
```
|
|
551
|
+
|
|
552
|
+
### 9.2 ā Procedural frame generation
|
|
553
|
+
|
|
554
|
+
```ts
|
|
555
|
+
import { frames } from 'ansimax';
|
|
556
|
+
|
|
557
|
+
// Generate a pulsing dot animation
|
|
558
|
+
const pulse: string[] = frames.generate(20, (i: number, total: number) => {
|
|
559
|
+
const intensity = Math.sin((i / total) * Math.PI * 2);
|
|
560
|
+
const size = Math.round(Math.abs(intensity) * 5) + 1;
|
|
561
|
+
return 'ā'.repeat(size).padEnd(7);
|
|
562
|
+
});
|
|
563
|
+
|
|
564
|
+
await frames.play(pulse, { interval: 80, loop: true, signal: AbortSignal.timeout(2000) }).promise;
|
|
565
|
+
```
|
|
566
|
+
|
|
567
|
+
### 9.3 ā Morph one text into another
|
|
568
|
+
|
|
569
|
+
```ts
|
|
570
|
+
import { frames } from 'ansimax';
|
|
571
|
+
|
|
572
|
+
// Decryption-style morph effect
|
|
573
|
+
const morphed: string[] = frames.morph('HELLO', 'WORLD', 15, 'āāāāāāā');
|
|
574
|
+
await frames.play(morphed, { interval: 80, loop: false }).promise;
|
|
575
|
+
|
|
576
|
+
console.log('\nā Morph complete');
|
|
577
|
+
```
|
|
578
|
+
|
|
579
|
+
---
|
|
580
|
+
|
|
581
|
+
## š¼ļø 10. `images` ā Pixel art, canvas, gradients
|
|
582
|
+
|
|
583
|
+
### 10.1 ā Render a sprite from the built-in library
|
|
584
|
+
|
|
585
|
+
```ts
|
|
586
|
+
import { renderPixelArt, SPRITES } from 'ansimax';
|
|
587
|
+
|
|
588
|
+
console.log('All sprites:', Object.keys(SPRITES).join(', '));
|
|
589
|
+
console.log();
|
|
590
|
+
console.log(renderPixelArt(SPRITES.heart.pixels, { scale: 2 }));
|
|
591
|
+
```
|
|
592
|
+
|
|
593
|
+
### 10.2 ā Gradient rectangle for visual demos
|
|
594
|
+
|
|
595
|
+
```ts
|
|
596
|
+
import { gradientRect } from 'ansimax';
|
|
597
|
+
|
|
598
|
+
// Sunset
|
|
599
|
+
console.log(gradientRect({
|
|
600
|
+
width: 50, height: 8,
|
|
601
|
+
colors: ['#ff5e62', '#ff9966', '#ffd86f'],
|
|
602
|
+
style: 'horizontal',
|
|
603
|
+
}));
|
|
604
|
+
|
|
605
|
+
console.log();
|
|
606
|
+
|
|
607
|
+
// Conic (rainbow wheel)
|
|
608
|
+
console.log(gradientRect({
|
|
609
|
+
width: 30, height: 15,
|
|
610
|
+
colors: ['#ff0000', '#ffff00', '#00ff00', '#00ffff', '#0000ff', '#ff00ff', '#ff0000'],
|
|
611
|
+
style: 'conic',
|
|
612
|
+
dither: 'bayer',
|
|
613
|
+
}));
|
|
614
|
+
```
|
|
615
|
+
|
|
616
|
+
### 10.3 ā Canvas with drawing primitives
|
|
617
|
+
|
|
618
|
+
```ts
|
|
619
|
+
import { createCanvas, type Canvas, type Pixel } from 'ansimax';
|
|
620
|
+
|
|
621
|
+
const canvas: Canvas = createCanvas(40, 20, { r: 30, g: 30, b: 40 });
|
|
622
|
+
|
|
623
|
+
const orange: Pixel = { r: 255, g: 165, b: 0 };
|
|
624
|
+
const cyan: Pixel = { r: 0, g: 200, b: 255 };
|
|
625
|
+
const pink: Pixel = { r: 255, g: 105, b: 180 };
|
|
626
|
+
|
|
627
|
+
canvas.drawRect(2, 2, 12, 6, cyan, true);
|
|
628
|
+
canvas.drawCircle(25, 8, 4, orange, true);
|
|
629
|
+
canvas.drawLine(0, 19, 39, 0, pink);
|
|
630
|
+
|
|
631
|
+
canvas.print();
|
|
632
|
+
```
|
|
633
|
+
|
|
634
|
+
---
|
|
635
|
+
|
|
636
|
+
## šŖ 11. `panels` + `json` ā Layouts and pretty-printing (v1.3.0+)
|
|
637
|
+
|
|
638
|
+
### 11.1 ā Side-by-side columns with nesting
|
|
639
|
+
|
|
640
|
+
```ts
|
|
641
|
+
import { panels, ascii } from 'ansimax';
|
|
642
|
+
|
|
643
|
+
const sidebar: string = ascii.box('Sidebar\n⢠Item 1\n⢠Item 2\n⢠Item 3', { borderStyle: 'rounded' });
|
|
644
|
+
const main: string = ascii.box('Main content\n\nLorem ipsum dolor sit amet, consectetur.', { borderStyle: 'rounded' });
|
|
645
|
+
|
|
646
|
+
console.log(panels.vsplit([sidebar, main], { gap: 2, align: 'start' }));
|
|
647
|
+
|
|
648
|
+
console.log();
|
|
649
|
+
|
|
650
|
+
// Vertical stacking
|
|
651
|
+
console.log(panels.hsplit([
|
|
652
|
+
'āā Header āā',
|
|
653
|
+
ascii.box('Body content'),
|
|
654
|
+
'āā Footer āā',
|
|
655
|
+
], { align: 'center', gap: 1 }));
|
|
656
|
+
```
|
|
657
|
+
|
|
658
|
+
### 11.2 ā Centering and decorative frames
|
|
659
|
+
|
|
660
|
+
```ts
|
|
661
|
+
import { panels, ascii } from 'ansimax';
|
|
662
|
+
|
|
663
|
+
// Center a box within an 80-column terminal
|
|
664
|
+
const card: string = ascii.box('Welcome!', { borderStyle: 'rounded', padding: 2 });
|
|
665
|
+
console.log(panels.center(card, { width: 80 }));
|
|
666
|
+
|
|
667
|
+
console.log();
|
|
668
|
+
|
|
669
|
+
// Lighter alternative to a full box ā only top/bottom rules
|
|
670
|
+
console.log(panels.frame('Important section content here', {
|
|
671
|
+
title: 'Section Header',
|
|
672
|
+
padding: 1,
|
|
673
|
+
topChar: 'ā',
|
|
674
|
+
}));
|
|
675
|
+
```
|
|
676
|
+
|
|
677
|
+
### 11.3 ā JSON pretty-print with all options
|
|
678
|
+
|
|
679
|
+
```ts
|
|
680
|
+
import { json } from 'ansimax';
|
|
681
|
+
|
|
682
|
+
interface AppData {
|
|
683
|
+
name: string;
|
|
684
|
+
version: string;
|
|
685
|
+
features: string[];
|
|
686
|
+
stats: { tests: number; coverage: number };
|
|
687
|
+
meta: { active: boolean };
|
|
688
|
+
}
|
|
689
|
+
|
|
690
|
+
const data: AppData = {
|
|
691
|
+
name: 'ansimax',
|
|
692
|
+
version: '1.3.2',
|
|
693
|
+
features: ['colors', 'gradients', 'panels', 'json'],
|
|
694
|
+
stats: { tests: 2104, coverage: 0.98 },
|
|
695
|
+
meta: { active: true },
|
|
696
|
+
};
|
|
697
|
+
|
|
698
|
+
// Default ā colored, inline short arrays
|
|
699
|
+
console.log(json.pretty(data));
|
|
700
|
+
|
|
701
|
+
console.log('\n--- With sortKeys (alphabetical) ---');
|
|
702
|
+
console.log(json.pretty(data, { sortKeys: true }));
|
|
703
|
+
|
|
704
|
+
console.log('\n--- With maxDepth: 1 (collapsed) ---');
|
|
705
|
+
console.log(json.pretty(data, { maxDepth: 1 }));
|
|
706
|
+
```
|
|
707
|
+
|
|
708
|
+
---
|
|
709
|
+
|
|
710
|
+
## šÆ Next steps
|
|
711
|
+
|
|
712
|
+
- **JavaScript ESM?** ā [`examples-mjs.md`](./examples-mjs.md)
|
|
713
|
+
- **JavaScript CommonJS?** ā [`examples-cjs.md`](./examples-cjs.md)
|
|
714
|
+
- **Complete demo app combining everything?** ā [`showcase.md`](./showcase.md)
|
|
715
|
+
- **Back to docs index?** ā [`README.md`](./README.md)
|