asciify-engine 1.0.92 → 1.0.94
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.
|
@@ -0,0 +1,730 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: asciify-engine
|
|
3
|
+
description: Convert images, videos, GIFs, webcam streams, text, and animated backgrounds into high-performance ASCII art with the asciify-engine npm package. Use when creating ASCII media, integrating asciifyVideo/asciify/asciifyGif, building scroll-synced ASCII video, tuning FPS/detail/performance, using compact text-frame APIs, hover effects, chroma key, recording/export, or updating an app that depends on asciify-engine.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# asciify-engine
|
|
7
|
+
|
|
8
|
+
Use this skill for the `asciify-engine` npm package.
|
|
9
|
+
|
|
10
|
+
**Package:** `asciify-engine`
|
|
11
|
+
**Current version:** `1.0.93`
|
|
12
|
+
**Playground:** https://asciify.org
|
|
13
|
+
**GitHub:** https://github.com/ayangabryl/asciify-engine
|
|
14
|
+
|
|
15
|
+
The engine is zero-dependency except GIF decoding. It renders ASCII art on canvas from images, videos, GIFs, webcam streams, generated backgrounds, and text.
|
|
16
|
+
|
|
17
|
+
## When To Use
|
|
18
|
+
|
|
19
|
+
Use this skill when the user wants to:
|
|
20
|
+
|
|
21
|
+
- Convert images, videos, GIFs, webcam, or text into ASCII art.
|
|
22
|
+
- Add ASCII video/backgrounds to React, Next.js, Vue, Svelte, or vanilla JS.
|
|
23
|
+
- Build scroll-synced ASCII video with GSAP ScrollTrigger or native scroll.
|
|
24
|
+
- Improve ASCII media performance, FPS, detail, resolution, or hover behavior.
|
|
25
|
+
- Use chroma key, fullcolor, accent, matrix, grayscale, dense/braille charsets, or hover effects.
|
|
26
|
+
- Use low-level prepared/compact frame APIs.
|
|
27
|
+
- Record/export ASCII canvas output.
|
|
28
|
+
- Update docs, package usage, or skill instructions for `asciify-engine`.
|
|
29
|
+
|
|
30
|
+
## Installation
|
|
31
|
+
|
|
32
|
+
```bash
|
|
33
|
+
npm install asciify-engine
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
For existing apps, install the latest tested version:
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
npm install asciify-engine@1.0.93
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Mental Model
|
|
43
|
+
|
|
44
|
+
Prefer the simple APIs first:
|
|
45
|
+
|
|
46
|
+
- `asciify()` for static images/canvas/video elements.
|
|
47
|
+
- `asciifyVideo()` for live or scroll-synced video.
|
|
48
|
+
- `asciifyGif()` for animated GIF files.
|
|
49
|
+
- `asciiBackground()` for procedural ASCII backgrounds.
|
|
50
|
+
|
|
51
|
+
For high-performance media, the engine uses compact text-frame paths when possible:
|
|
52
|
+
|
|
53
|
+
- `imageToAsciiTextFrame()`
|
|
54
|
+
- `videoToAsciiTextFrames()`
|
|
55
|
+
- `gifToAsciiTextFrames()`
|
|
56
|
+
- `renderTextFrameToCanvas()`
|
|
57
|
+
|
|
58
|
+
These avoid object-per-cell frames and are the preferred low-level APIs for dense media, including fullcolor in `1.0.91+`.
|
|
59
|
+
|
|
60
|
+
Use legacy object frames only when you need per-cell mutation, dots mode, heavy hover/animation transforms, or compatibility with existing `AsciiFrame` consumers:
|
|
61
|
+
|
|
62
|
+
- `imageToAsciiFrame()`
|
|
63
|
+
- `videoToAsciiFrames()`
|
|
64
|
+
- `gifToAsciiFrames()`
|
|
65
|
+
- `renderFrameToCanvas()`
|
|
66
|
+
|
|
67
|
+
Use `options.sourceCrop` when the source media has empty edges or needs tighter framing without changing the destination canvas size. Percent values are normalized `0–1` by default:
|
|
68
|
+
|
|
69
|
+
```ts
|
|
70
|
+
options: {
|
|
71
|
+
sourceCrop: { y: 0.16, height: 0.62 },
|
|
72
|
+
}
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
`sourceCrop` is opt-in. When omitted, the engine samples the full source exactly as older versions did.
|
|
76
|
+
|
|
77
|
+
## Visual Target
|
|
78
|
+
|
|
79
|
+
Good ASCII media should feel intentional, not like a broken video filter.
|
|
80
|
+
|
|
81
|
+
- The subject silhouette is readable at first glance.
|
|
82
|
+
- Character density reveals form, light, and motion without turning into noise.
|
|
83
|
+
- The canvas respects the media aspect ratio and fills the intended container.
|
|
84
|
+
- Accent/fullcolor choices support the page design instead of shouting over it.
|
|
85
|
+
- Text is crisp, not browser-blurred, stretched, or visibly low resolution.
|
|
86
|
+
- Motion updates feel continuous; if FPS drops, reduce work before adding effects.
|
|
87
|
+
|
|
88
|
+
## Decision Playbooks
|
|
89
|
+
|
|
90
|
+
### User Wants More Detail
|
|
91
|
+
|
|
92
|
+
Do not only reduce `fontSize`. Use this ladder:
|
|
93
|
+
|
|
94
|
+
1. Confirm the canvas/container is actually large enough and not CSS-stretched from a tiny backing buffer.
|
|
95
|
+
2. Use `fitTo` for videos so the engine owns canvas sizing.
|
|
96
|
+
3. Use `CHARSETS.dense` for normal ASCII detail.
|
|
97
|
+
4. Enable `normalize: true` for muted or low-contrast sources.
|
|
98
|
+
5. Raise `maxRenderDimension` one step: `960 -> 1280 -> 1600 -> 2048`.
|
|
99
|
+
6. Then lower `fontSize`: `8 -> 6 -> 5 -> 4`.
|
|
100
|
+
7. Try `colorMode: 'accent'` before `fullcolor` if the design can be monochrome.
|
|
101
|
+
8. Use `CHARSETS.braille` only when ultra-detail matters and the style can handle the texture.
|
|
102
|
+
|
|
103
|
+
Stop when the subject reads clearly. More cells after that often make the image noisier, not better.
|
|
104
|
+
|
|
105
|
+
### User Wants Smoother FPS
|
|
106
|
+
|
|
107
|
+
Reduce hot-path work in this order:
|
|
108
|
+
|
|
109
|
+
1. Keep `animationStyle: 'none'` and `hoverStrength: 0`.
|
|
110
|
+
2. Use compact text-frame-compatible settings: `renderMode: 'ascii'`, no `charsetFrames`.
|
|
111
|
+
3. Prefer `accent`, `matrix`, or `grayscale`; keep `fullcolor` only when color matters.
|
|
112
|
+
4. Lower `maxRenderDimension`: `2048 -> 1600 -> 1280 -> 960`.
|
|
113
|
+
5. Raise `fontSize`: `4 -> 5 -> 6 -> 8`.
|
|
114
|
+
6. Lower `fps`: `60 -> 30 -> 24`.
|
|
115
|
+
7. Avoid `dots`, per-cell hover, and animated charsets on dense video.
|
|
116
|
+
|
|
117
|
+
If FPS is still poor, inspect whether the app is resizing the canvas every frame or remounting the component.
|
|
118
|
+
|
|
119
|
+
### User Wants A Premium Hero
|
|
120
|
+
|
|
121
|
+
Recommended starting point:
|
|
122
|
+
|
|
123
|
+
```ts
|
|
124
|
+
{
|
|
125
|
+
fitTo: hero,
|
|
126
|
+
fontSize: 5,
|
|
127
|
+
fps: 60,
|
|
128
|
+
maxRenderDimension: 1280,
|
|
129
|
+
artStyle: 'classic',
|
|
130
|
+
options: {
|
|
131
|
+
charset: CHARSETS.dense,
|
|
132
|
+
colorMode: 'accent',
|
|
133
|
+
accentColor: '#e8d7b7',
|
|
134
|
+
normalize: true,
|
|
135
|
+
animationStyle: 'none',
|
|
136
|
+
hoverStrength: 0,
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
Design rules:
|
|
142
|
+
|
|
143
|
+
- Use one restrained accent color pulled from the brand/page palette.
|
|
144
|
+
- Put ASCII behind or below the core CTA, not directly under tiny text.
|
|
145
|
+
- Use masks or fades at edges when the ASCII meets page content.
|
|
146
|
+
- Keep the hero background quiet enough that the headline wins.
|
|
147
|
+
- Use scroll scrub only when it tells a story; do not scrub decorative noise.
|
|
148
|
+
|
|
149
|
+
### User Wants Fullcolor
|
|
150
|
+
|
|
151
|
+
Use fullcolor when color carries product meaning, artwork, identity, or footage mood.
|
|
152
|
+
|
|
153
|
+
Start with:
|
|
154
|
+
|
|
155
|
+
```ts
|
|
156
|
+
{
|
|
157
|
+
fontSize: 6,
|
|
158
|
+
fps: 30,
|
|
159
|
+
maxRenderDimension: 1280,
|
|
160
|
+
artStyle: 'art',
|
|
161
|
+
options: {
|
|
162
|
+
charset: CHARSETS.dense,
|
|
163
|
+
colorMode: 'fullcolor',
|
|
164
|
+
normalize: true,
|
|
165
|
+
animationStyle: 'none',
|
|
166
|
+
hoverStrength: 0,
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
If it is slow, first lower `maxRenderDimension` or raise `fontSize`. Do not jump straight to `fontSize: 3`.
|
|
172
|
+
|
|
173
|
+
### User Wants Hover Interaction
|
|
174
|
+
|
|
175
|
+
Hover is per-cell work. Keep it deliberate:
|
|
176
|
+
|
|
177
|
+
- Use `fontSize >= 8` for large canvases.
|
|
178
|
+
- Use smaller framed demos rather than full-screen 4px ASCII.
|
|
179
|
+
- Start with `HOVER_PRESETS.subtle` or `hoverStrength: 0.2`.
|
|
180
|
+
- Avoid hover on scroll-synced video unless the canvas is small.
|
|
181
|
+
- Prefer hover for static images, generated text backgrounds, or product demos.
|
|
182
|
+
|
|
183
|
+
### User Says It Is Blurry
|
|
184
|
+
|
|
185
|
+
Check in this order:
|
|
186
|
+
|
|
187
|
+
1. Is the canvas CSS size different from its backing `width`/`height`?
|
|
188
|
+
2. For video, is `fitTo` provided?
|
|
189
|
+
3. Is the source itself low resolution?
|
|
190
|
+
4. Is `maxRenderDimension` too low for the displayed size?
|
|
191
|
+
5. Is CSS applying `filter`, `transform: scale`, or opacity compositing that softens text?
|
|
192
|
+
6. For tiny font ASCII, verify the design accepts raster-like pixel detail.
|
|
193
|
+
|
|
194
|
+
### User Says It Is Blank
|
|
195
|
+
|
|
196
|
+
Check:
|
|
197
|
+
|
|
198
|
+
1. Source loaded and video has metadata.
|
|
199
|
+
2. Canvas has nonzero width/height.
|
|
200
|
+
3. Video is not `display: none`.
|
|
201
|
+
4. `chromaKey` is not removing the subject.
|
|
202
|
+
5. `invert` and page background are not making characters invisible.
|
|
203
|
+
6. For async React use, cleanup did not run before `asciifyVideo()` resolved.
|
|
204
|
+
|
|
205
|
+
### User Says It Is Too Large Or Overflows
|
|
206
|
+
|
|
207
|
+
Use layout fixes before quality fixes:
|
|
208
|
+
|
|
209
|
+
- Wrap canvas in a positioned container.
|
|
210
|
+
- Set canvas CSS to `position:absolute; inset:0; width:100%; height:100%`.
|
|
211
|
+
- Use `fitTo: container`.
|
|
212
|
+
- Keep the parent aspect ratio or explicit height stable.
|
|
213
|
+
- Avoid manually setting `canvas.width = window.innerWidth` in React render.
|
|
214
|
+
|
|
215
|
+
### User Wants To Remove Empty Space In The Media
|
|
216
|
+
|
|
217
|
+
Prefer source cropping over layout hacks when the video/image itself has dead space:
|
|
218
|
+
|
|
219
|
+
```ts
|
|
220
|
+
await asciifyVideo(video, canvas, {
|
|
221
|
+
fitTo: hero,
|
|
222
|
+
options: {
|
|
223
|
+
chromaKey: true,
|
|
224
|
+
sourceCrop: { y: 0.16, height: 0.62 },
|
|
225
|
+
},
|
|
226
|
+
});
|
|
227
|
+
```
|
|
228
|
+
|
|
229
|
+
- `sourceCrop` happens before ASCII sampling, so the subject is reframed without changing the canvas box.
|
|
230
|
+
- Default unit is `'percent'`; use values from `0` to `1`.
|
|
231
|
+
- Use `{ unit: 'pixel', x, y, width, height }` for exact media-pixel crops.
|
|
232
|
+
- Keep the crop aspect ratio close to the output aspect ratio when you want zero perceived stretching.
|
|
233
|
+
- For hero videos, crop the source first, then use small layout overlap only if the next section needs to tuck closer.
|
|
234
|
+
|
|
235
|
+
### Scroll-Scrub Performance Model
|
|
236
|
+
|
|
237
|
+
In `1.0.93+`, the fast text-frame scrub path uses a Pretext-inspired split:
|
|
238
|
+
|
|
239
|
+
- Prepare/cache frames lazily around the current scroll target.
|
|
240
|
+
- Render compact row strings instead of object-per-cell frames.
|
|
241
|
+
- Diff transparent rows and only redraw rows whose text changed.
|
|
242
|
+
- Prefer `fastSeek()` when the browser supports it.
|
|
243
|
+
- Prefetch nearby frames around the current target so scrolling back and forth has fewer misses.
|
|
244
|
+
|
|
245
|
+
For smooth scrub, keep options compatible with this fast path:
|
|
246
|
+
|
|
247
|
+
```ts
|
|
248
|
+
{
|
|
249
|
+
renderMode: 'ascii',
|
|
250
|
+
animationStyle: 'none',
|
|
251
|
+
hoverStrength: 0,
|
|
252
|
+
colorMode: 'accent', // or grayscale/matrix
|
|
253
|
+
}
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
## Design Playbooks
|
|
257
|
+
|
|
258
|
+
### Dark Premium Landing Page
|
|
259
|
+
|
|
260
|
+
- Use `#121212` or near-black page background.
|
|
261
|
+
- Prefer `accent` over `fullcolor` unless the footage itself is beautiful.
|
|
262
|
+
- Use warm off-white or brand accent, not neon by default.
|
|
263
|
+
- Pair ASCII with framed layout, thin borders, or quiet masks.
|
|
264
|
+
- Keep copy short; ASCII should carry some of the storytelling.
|
|
265
|
+
|
|
266
|
+
### Technical / Infrastructure Aesthetic
|
|
267
|
+
|
|
268
|
+
- Use `matrix`, `grayscale`, or a cool `accentColor`.
|
|
269
|
+
- Use `CHARSETS.dense`, `lines`, `box`, or `geometric`.
|
|
270
|
+
- Compose with visible grid lines, clipped containers, and measured spacing.
|
|
271
|
+
- Avoid playful emoji/katakana unless the brand asks for it.
|
|
272
|
+
|
|
273
|
+
### Editorial / Portfolio Aesthetic
|
|
274
|
+
|
|
275
|
+
- Use `accent` with a soft paper/warm ink palette.
|
|
276
|
+
- Use slower video, stills, or subtle scroll reveal.
|
|
277
|
+
- Keep `fontSize: 5-8`; avoid over-dense unreadable texture.
|
|
278
|
+
- Use ASCII as proof/atmosphere around work, not as a gimmick.
|
|
279
|
+
|
|
280
|
+
### Playground / Demo Aesthetic
|
|
281
|
+
|
|
282
|
+
- Show controls that map to real engine tradeoffs: detail, FPS, color, charset, hover.
|
|
283
|
+
- Surface live `cols x rows`, FPS, and current source dimensions.
|
|
284
|
+
- Include presets: `Smooth`, `Detailed`, `Fullcolor`, `Interactive`.
|
|
285
|
+
- When changing presets, explain the performance tradeoff in the UI.
|
|
286
|
+
|
|
287
|
+
## Quality Checks
|
|
288
|
+
|
|
289
|
+
- Subject is recognizable in a screenshot.
|
|
290
|
+
- FPS is stable for 5-10 seconds, not just on first load.
|
|
291
|
+
- The canvas does not resize every frame.
|
|
292
|
+
- Text/CTA remains readable over or near the ASCII.
|
|
293
|
+
- Mobile uses a less expensive preset than desktop when needed.
|
|
294
|
+
- Reduced-motion users still get a static or slower frame.
|
|
295
|
+
- Cleanup runs on unmount and cancels video/background loops.
|
|
296
|
+
|
|
297
|
+
## Simple APIs
|
|
298
|
+
|
|
299
|
+
### Static Image
|
|
300
|
+
|
|
301
|
+
```ts
|
|
302
|
+
import { asciify, CHARSETS } from 'asciify-engine';
|
|
303
|
+
|
|
304
|
+
await asciify('/photo.jpg', canvas, {
|
|
305
|
+
fontSize: 6,
|
|
306
|
+
artStyle: 'art',
|
|
307
|
+
options: {
|
|
308
|
+
charset: CHARSETS.dense,
|
|
309
|
+
colorMode: 'fullcolor',
|
|
310
|
+
normalize: true,
|
|
311
|
+
},
|
|
312
|
+
});
|
|
313
|
+
```
|
|
314
|
+
|
|
315
|
+
### Live Video
|
|
316
|
+
|
|
317
|
+
```ts
|
|
318
|
+
import { asciifyVideo, CHARSETS } from 'asciify-engine';
|
|
319
|
+
|
|
320
|
+
const stop = await asciifyVideo('/clip.mp4', canvas, {
|
|
321
|
+
fitTo: container,
|
|
322
|
+
fontSize: 6,
|
|
323
|
+
fps: 60,
|
|
324
|
+
maxRenderDimension: 1280,
|
|
325
|
+
artStyle: 'classic',
|
|
326
|
+
options: {
|
|
327
|
+
charset: CHARSETS.dense,
|
|
328
|
+
colorMode: 'accent',
|
|
329
|
+
accentColor: '#e8d7b7',
|
|
330
|
+
normalize: true,
|
|
331
|
+
},
|
|
332
|
+
});
|
|
333
|
+
|
|
334
|
+
// cleanup
|
|
335
|
+
stop();
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
### GIF
|
|
339
|
+
|
|
340
|
+
```ts
|
|
341
|
+
import { asciifyGif } from 'asciify-engine';
|
|
342
|
+
|
|
343
|
+
const stop = await asciifyGif('/loop.gif', canvas, {
|
|
344
|
+
fontSize: 8,
|
|
345
|
+
artStyle: 'letters',
|
|
346
|
+
options: { colorMode: 'fullcolor' },
|
|
347
|
+
});
|
|
348
|
+
|
|
349
|
+
stop();
|
|
350
|
+
```
|
|
351
|
+
|
|
352
|
+
## Scroll-Synced Video
|
|
353
|
+
|
|
354
|
+
`asciifyVideo()` supports scroll scrubbing. Use this for landing-page hero reveals, editorial sections, and pinned/scrollytelling moments.
|
|
355
|
+
|
|
356
|
+
### GSAP ScrollTrigger
|
|
357
|
+
|
|
358
|
+
```ts
|
|
359
|
+
import gsap from 'gsap';
|
|
360
|
+
import { ScrollTrigger } from 'gsap/ScrollTrigger';
|
|
361
|
+
import { asciifyVideo, CHARSETS } from 'asciify-engine';
|
|
362
|
+
|
|
363
|
+
const stop = await asciifyVideo('/hero.mp4', canvas, {
|
|
364
|
+
fitTo: wrapper,
|
|
365
|
+
fontSize: 4,
|
|
366
|
+
fps: 60,
|
|
367
|
+
maxRenderDimension: 1280,
|
|
368
|
+
trim: { start: 2.2, end: 6.65 },
|
|
369
|
+
scroll: {
|
|
370
|
+
gsap,
|
|
371
|
+
ScrollTrigger,
|
|
372
|
+
trigger: wrapper,
|
|
373
|
+
start: 'top 88%',
|
|
374
|
+
end: 'bottom 18%',
|
|
375
|
+
scrub: 0.45,
|
|
376
|
+
from: 2.2,
|
|
377
|
+
to: 6.65,
|
|
378
|
+
},
|
|
379
|
+
options: {
|
|
380
|
+
charset: CHARSETS.dense,
|
|
381
|
+
colorMode: 'accent',
|
|
382
|
+
accentColor: '#e8d7b7',
|
|
383
|
+
normalize: true,
|
|
384
|
+
chromaKey: true,
|
|
385
|
+
chromaKeyTolerance: 84,
|
|
386
|
+
},
|
|
387
|
+
});
|
|
388
|
+
```
|
|
389
|
+
|
|
390
|
+
### Native Scroll Scrub
|
|
391
|
+
|
|
392
|
+
```ts
|
|
393
|
+
const stop = await asciifyVideo('/hero.mp4', canvas, {
|
|
394
|
+
fitTo: wrapper,
|
|
395
|
+
fontSize: 6,
|
|
396
|
+
scroll: {
|
|
397
|
+
trigger: wrapper,
|
|
398
|
+
from: 0,
|
|
399
|
+
to: 5,
|
|
400
|
+
},
|
|
401
|
+
});
|
|
402
|
+
```
|
|
403
|
+
|
|
404
|
+
### Scroll Best Practices
|
|
405
|
+
|
|
406
|
+
- Use `scroll` for time-to-scroll mapping, not custom `video.currentTime` loops.
|
|
407
|
+
- Pass the same `from`/`to` as `trim.start`/`trim.end` when scrubbing a clipped range.
|
|
408
|
+
- Use `fps: 30-60`; choose `60` for smooth short hero clips, `24-30` for heavy fullcolor.
|
|
409
|
+
- Use `maxRenderDimension: 960-1280` for large full-width hero videos. Use `2048` only when truly needed.
|
|
410
|
+
- Use `fontSize: 4-6` for detailed hero ASCII; below `4px` is expensive and should use compact text-frame paths only.
|
|
411
|
+
- Avoid hover effects on dense scroll video. Hover is per-cell work.
|
|
412
|
+
- Never set the backing video to `display: none`; the API keeps URL-created videos decode-safe automatically.
|
|
413
|
+
|
|
414
|
+
## Performance Guide
|
|
415
|
+
|
|
416
|
+
### Fastest Media Settings
|
|
417
|
+
|
|
418
|
+
For smooth high-density video:
|
|
419
|
+
|
|
420
|
+
```ts
|
|
421
|
+
{
|
|
422
|
+
fontSize: 5,
|
|
423
|
+
fps: 60,
|
|
424
|
+
maxRenderDimension: 1280,
|
|
425
|
+
artStyle: 'classic',
|
|
426
|
+
options: {
|
|
427
|
+
charset: CHARSETS.dense,
|
|
428
|
+
colorMode: 'accent',
|
|
429
|
+
animationStyle: 'none',
|
|
430
|
+
hoverStrength: 0,
|
|
431
|
+
normalize: true,
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
```
|
|
435
|
+
|
|
436
|
+
### Fullcolor Settings
|
|
437
|
+
|
|
438
|
+
Fullcolor is supported by the compact text-frame path in `1.0.91+`.
|
|
439
|
+
|
|
440
|
+
```ts
|
|
441
|
+
{
|
|
442
|
+
fontSize: 6,
|
|
443
|
+
fps: 30,
|
|
444
|
+
maxRenderDimension: 1280,
|
|
445
|
+
artStyle: 'art',
|
|
446
|
+
options: {
|
|
447
|
+
charset: CHARSETS.dense,
|
|
448
|
+
colorMode: 'fullcolor',
|
|
449
|
+
animationStyle: 'none',
|
|
450
|
+
hoverStrength: 0,
|
|
451
|
+
normalize: true,
|
|
452
|
+
}
|
|
453
|
+
}
|
|
454
|
+
```
|
|
455
|
+
|
|
456
|
+
Use fullcolor when the source color is important. Use `accent` when you want the highest FPS and a more designed monochrome look.
|
|
457
|
+
|
|
458
|
+
### Detail Tuning
|
|
459
|
+
|
|
460
|
+
- `fontSize`: main detail/performance knob. Smaller means more cells.
|
|
461
|
+
- `maxRenderDimension`: caps media processing resolution before ASCII conversion.
|
|
462
|
+
- `CHARSETS.dense`: best general image/video ramp.
|
|
463
|
+
- `CHARSETS.braille`: very high visual resolution but can be visually noisy and heavier.
|
|
464
|
+
- `normalize: true`: improves contrast/detail for muted media.
|
|
465
|
+
- `ditherStrength: 0-0.25`: adds texture but costs more and can shimmer in video.
|
|
466
|
+
- `chromaKey`: useful for green/blue-screen subjects over page backgrounds.
|
|
467
|
+
|
|
468
|
+
### Expensive Features
|
|
469
|
+
|
|
470
|
+
These are intentionally richer and can reduce FPS on dense canvases:
|
|
471
|
+
|
|
472
|
+
- `renderMode: 'dots'`
|
|
473
|
+
- `hoverStrength > 0`
|
|
474
|
+
- `animationStyle !== 'none'`
|
|
475
|
+
- `charsetFrames`
|
|
476
|
+
- tiny `fontSize` with `fullcolor`
|
|
477
|
+
- very high `maxRenderDimension`
|
|
478
|
+
|
|
479
|
+
For interactive hover demos, use `fontSize >= 8` or smaller canvases.
|
|
480
|
+
|
|
481
|
+
## Low-Level APIs
|
|
482
|
+
|
|
483
|
+
### Compact Text Frames
|
|
484
|
+
|
|
485
|
+
Use for dense static images, GIFs, videos, and fullcolor media where you do not need per-cell mutation.
|
|
486
|
+
|
|
487
|
+
```ts
|
|
488
|
+
import {
|
|
489
|
+
imageToAsciiTextFrame,
|
|
490
|
+
renderTextFrameToCanvas,
|
|
491
|
+
DEFAULT_OPTIONS,
|
|
492
|
+
} from 'asciify-engine';
|
|
493
|
+
|
|
494
|
+
const frame = imageToAsciiTextFrame(img, {
|
|
495
|
+
...DEFAULT_OPTIONS,
|
|
496
|
+
fontSize: 6,
|
|
497
|
+
colorMode: 'fullcolor',
|
|
498
|
+
}, 1280, 720);
|
|
499
|
+
|
|
500
|
+
renderTextFrameToCanvas(ctx, frame, DEFAULT_OPTIONS, 1280, 720);
|
|
501
|
+
```
|
|
502
|
+
|
|
503
|
+
Available compact APIs:
|
|
504
|
+
|
|
505
|
+
```ts
|
|
506
|
+
imageToAsciiTextFrame(source, options, width?, height?) -> AsciiTextFrame
|
|
507
|
+
videoToAsciiTextFrames(video, options, width, height, fps?, maxSec?, onProgress?, startTime?)
|
|
508
|
+
gifToAsciiTextFrames(buffer, options, width, height, onProgress?)
|
|
509
|
+
renderTextFrameToCanvas(ctx, textFrame, options, width, height)
|
|
510
|
+
```
|
|
511
|
+
|
|
512
|
+
`AsciiTextFrame` contains:
|
|
513
|
+
|
|
514
|
+
```ts
|
|
515
|
+
type AsciiTextFrame = {
|
|
516
|
+
rows: string[];
|
|
517
|
+
cols: number;
|
|
518
|
+
rowCount: number;
|
|
519
|
+
colors?: Uint8ClampedArray; // present for fullcolor compact frames
|
|
520
|
+
}
|
|
521
|
+
```
|
|
522
|
+
|
|
523
|
+
### Legacy Object Frames
|
|
524
|
+
|
|
525
|
+
Use when you need cell objects, hover transforms, dots rendering, or compatibility:
|
|
526
|
+
|
|
527
|
+
```ts
|
|
528
|
+
imageToAsciiFrame(source, options, width?, height?) -> { frame, cols, rows }
|
|
529
|
+
videoToAsciiFrames(video, options, width, height, fps?, maxSec?, onProgress?, startTime?)
|
|
530
|
+
gifToAsciiFrames(buffer, options, width, height, onProgress?)
|
|
531
|
+
renderFrameToCanvas(ctx, frame, options, width, height, time?, mousePos?)
|
|
532
|
+
```
|
|
533
|
+
|
|
534
|
+
### Cache Management
|
|
535
|
+
|
|
536
|
+
Long-lived editors/playgrounds that cycle many charsets or fonts can clear shared lookup caches:
|
|
537
|
+
|
|
538
|
+
```ts
|
|
539
|
+
import { clearAsciifyCaches } from 'asciify-engine';
|
|
540
|
+
|
|
541
|
+
clearAsciifyCaches();
|
|
542
|
+
```
|
|
543
|
+
|
|
544
|
+
## React / Next.js Pattern
|
|
545
|
+
|
|
546
|
+
```tsx
|
|
547
|
+
'use client';
|
|
548
|
+
|
|
549
|
+
import { useEffect, useRef } from 'react';
|
|
550
|
+
import { asciifyVideo, CHARSETS } from 'asciify-engine';
|
|
551
|
+
|
|
552
|
+
export function AsciiHero() {
|
|
553
|
+
const wrapperRef = useRef<HTMLDivElement>(null);
|
|
554
|
+
const canvasRef = useRef<HTMLCanvasElement>(null);
|
|
555
|
+
|
|
556
|
+
useEffect(() => {
|
|
557
|
+
const wrapper = wrapperRef.current;
|
|
558
|
+
const canvas = canvasRef.current;
|
|
559
|
+
if (!wrapper || !canvas) return;
|
|
560
|
+
|
|
561
|
+
let cleanup: (() => void) | undefined;
|
|
562
|
+
let alive = true;
|
|
563
|
+
|
|
564
|
+
asciifyVideo('/hero.mp4', canvas, {
|
|
565
|
+
fitTo: wrapper,
|
|
566
|
+
fontSize: 5,
|
|
567
|
+
fps: 60,
|
|
568
|
+
maxRenderDimension: 1280,
|
|
569
|
+
artStyle: 'classic',
|
|
570
|
+
options: {
|
|
571
|
+
charset: CHARSETS.dense,
|
|
572
|
+
colorMode: 'accent',
|
|
573
|
+
accentColor: '#e8d7b7',
|
|
574
|
+
normalize: true,
|
|
575
|
+
},
|
|
576
|
+
}).then(stop => {
|
|
577
|
+
if (alive) cleanup = stop;
|
|
578
|
+
else stop();
|
|
579
|
+
});
|
|
580
|
+
|
|
581
|
+
return () => {
|
|
582
|
+
alive = false;
|
|
583
|
+
cleanup?.();
|
|
584
|
+
};
|
|
585
|
+
}, []);
|
|
586
|
+
|
|
587
|
+
return (
|
|
588
|
+
<div ref={wrapperRef} style={{ position: 'relative', width: '100%', height: '100vh' }}>
|
|
589
|
+
<canvas ref={canvasRef} style={{ position: 'absolute', inset: 0, width: '100%', height: '100%' }} />
|
|
590
|
+
</div>
|
|
591
|
+
);
|
|
592
|
+
}
|
|
593
|
+
```
|
|
594
|
+
|
|
595
|
+
## Animated Backgrounds
|
|
596
|
+
|
|
597
|
+
```ts
|
|
598
|
+
import { asciiBackground } from 'asciify-engine';
|
|
599
|
+
|
|
600
|
+
const stop = asciiBackground('#hero-bg', {
|
|
601
|
+
type: 'aurora',
|
|
602
|
+
colorScheme: 'auto',
|
|
603
|
+
fontSize: 14,
|
|
604
|
+
speed: 0.8,
|
|
605
|
+
density: 0.55,
|
|
606
|
+
accentColor: '#d4ff00',
|
|
607
|
+
});
|
|
608
|
+
|
|
609
|
+
stop();
|
|
610
|
+
```
|
|
611
|
+
|
|
612
|
+
Available background types:
|
|
613
|
+
|
|
614
|
+
`wave`, `rain`, `stars`, `pulse`, `noise`, `grid`, `aurora`, `silk`, `void`, `morph`, `fire`, `dna`, `terrain`, `circuit`
|
|
615
|
+
|
|
616
|
+
Individual `render*Background` functions are also exported for custom canvas loops.
|
|
617
|
+
|
|
618
|
+
## Options Reference
|
|
619
|
+
|
|
620
|
+
Common `AsciiOptions`:
|
|
621
|
+
|
|
622
|
+
| Property | Type | Notes |
|
|
623
|
+
|---|---|---|
|
|
624
|
+
| `fontSize` | `number` | Main detail/performance knob. |
|
|
625
|
+
| `charSpacing` | `number` | Cell spacing multiplier. |
|
|
626
|
+
| `brightness` | `number` | `-1` to `1`. |
|
|
627
|
+
| `contrast` | `number` | Positive increases contrast. |
|
|
628
|
+
| `charset` | `string` | Use `CHARSETS`. |
|
|
629
|
+
| `colorMode` | `'grayscale' | 'fullcolor' | 'matrix' | 'accent'` | Fullcolor is fast-path capable in `1.0.91+`. |
|
|
630
|
+
| `accentColor` | `string` | Used for accent/matrix-style rendering. |
|
|
631
|
+
| `invert` | `boolean | 'auto'` | Use `'auto'` for light/dark themes. |
|
|
632
|
+
| `renderMode` | `'ascii' | 'dots'` | Dots is richer/heavier. |
|
|
633
|
+
| `animationStyle` | `AnimationStyle` | Keep `'none'` for max FPS. |
|
|
634
|
+
| `animationSpeed` | `number` | Animation speed multiplier. |
|
|
635
|
+
| `dotSizeRatio` | `number` | Dot size for dots mode. |
|
|
636
|
+
| `ditherStrength` | `number` | Use lightly for video. |
|
|
637
|
+
| `hoverStrength` | `number` | Set `0` for fast media. |
|
|
638
|
+
| `hoverRadius` | `number` | Hover influence radius. |
|
|
639
|
+
| `hoverEffect` | `HoverEffect` | Spotlight/magnify/etc. |
|
|
640
|
+
| `hoverColor` | `string` | Hover tint. |
|
|
641
|
+
| `artStyle` | `ArtStyle` | Preset name. |
|
|
642
|
+
| `customText` | `string` | Repeating custom text. |
|
|
643
|
+
| `chromaKey` | `boolean | string | {r,g,b} | null` | Green/blue/custom keying. |
|
|
644
|
+
| `chromaKeyTolerance` | `number` | Default around `60`; raise for noisy footage. |
|
|
645
|
+
| `normalize` | `boolean` | Stretch source luminance. |
|
|
646
|
+
| `charsetFrames` | `string[]` | Animated charset sequence; heavier. |
|
|
647
|
+
| `charsetFps` | `number` | Charset sequence rate. |
|
|
648
|
+
|
|
649
|
+
## Charsets And Styles
|
|
650
|
+
|
|
651
|
+
Use:
|
|
652
|
+
|
|
653
|
+
```ts
|
|
654
|
+
import { CHARSETS, ART_STYLE_PRESETS } from 'asciify-engine';
|
|
655
|
+
```
|
|
656
|
+
|
|
657
|
+
Common charsets:
|
|
658
|
+
|
|
659
|
+
- `CHARSETS.standard`
|
|
660
|
+
- `CHARSETS.dense`
|
|
661
|
+
- `CHARSETS.blocks`
|
|
662
|
+
- `CHARSETS.braille`
|
|
663
|
+
- `CHARSETS.lines`
|
|
664
|
+
- `CHARSETS.dots`
|
|
665
|
+
- `CHARSETS.letters`
|
|
666
|
+
- `CHARSETS.katakana`
|
|
667
|
+
- `CHARSETS.circles`
|
|
668
|
+
- `CHARSETS.geometric`
|
|
669
|
+
- `CHARSETS.shadows`
|
|
670
|
+
- `CHARSETS.starfield`
|
|
671
|
+
|
|
672
|
+
Common art styles:
|
|
673
|
+
|
|
674
|
+
- `classic`: standard ASCII.
|
|
675
|
+
- `art`: dense fullcolor detail.
|
|
676
|
+
- `particles`: dots/fullcolor.
|
|
677
|
+
- `letters`: alphabet characters.
|
|
678
|
+
- `terminal`: matrix green.
|
|
679
|
+
- `braille`: high detail.
|
|
680
|
+
- `box`, `lines`, `katakana`, `emoji`, `circles`, `shadows`, `geometric`, `waves`, `shards`, `smoke`.
|
|
681
|
+
|
|
682
|
+
## Hover And Animation
|
|
683
|
+
|
|
684
|
+
Hover effects:
|
|
685
|
+
|
|
686
|
+
`spotlight`, `magnify`, `repel`, `glow`, `colorShift`, `attract`, `shatter`, `trail`, `glitchText`
|
|
687
|
+
|
|
688
|
+
Hover presets:
|
|
689
|
+
|
|
690
|
+
`none`, `subtle`, `flashlight`, `magnifier`, `forceField`, `neon`, `fire`, `ice`, `gravity`, `shatter`, `ghost`, `glitchReveal`
|
|
691
|
+
|
|
692
|
+
Animation styles:
|
|
693
|
+
|
|
694
|
+
`none`, `wave`, `pulse`, `rain`, `breathe`, `sparkle`, `glitch`, `spiral`, `typewriter`, `scatter`, `waveField`, `ripple`, `melt`, `orbit`, `cellular`
|
|
695
|
+
|
|
696
|
+
Best practice:
|
|
697
|
+
|
|
698
|
+
- For video backgrounds and scroll heroes, use `animationStyle: 'none'` and `hoverStrength: 0`.
|
|
699
|
+
- For interactive hover demos, keep the canvas smaller or use `fontSize >= 8`.
|
|
700
|
+
- Avoid combining tiny fonts, fullcolor, hover, and animation unless the visual really needs it.
|
|
701
|
+
|
|
702
|
+
## Recording And Export
|
|
703
|
+
|
|
704
|
+
```ts
|
|
705
|
+
import { createRecorder, recordAndDownload } from 'asciify-engine';
|
|
706
|
+
|
|
707
|
+
await recordAndDownload(canvas, { duration: 3000, filename: 'ascii-art' });
|
|
708
|
+
|
|
709
|
+
const recorder = createRecorder(canvas, { fps: 30 });
|
|
710
|
+
recorder.start();
|
|
711
|
+
const blob = await recorder.stop();
|
|
712
|
+
```
|
|
713
|
+
|
|
714
|
+
## Type Imports
|
|
715
|
+
|
|
716
|
+
```ts
|
|
717
|
+
import type {
|
|
718
|
+
AsciiOptions,
|
|
719
|
+
AsciiCell,
|
|
720
|
+
AsciiFrame,
|
|
721
|
+
AsciiTextFrame,
|
|
722
|
+
AsciifySimpleOptions,
|
|
723
|
+
AsciifyVideoOptions,
|
|
724
|
+
VideoScrollScrubOptions,
|
|
725
|
+
ColorMode,
|
|
726
|
+
AnimationStyle,
|
|
727
|
+
ArtStyle,
|
|
728
|
+
HoverEffect,
|
|
729
|
+
} from 'asciify-engine';
|
|
730
|
+
```
|