asciify-engine 1.0.20 → 1.0.22
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/README.md +110 -36
- package/dist/index.cjs +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# asciify-engine
|
|
2
2
|
|
|
3
|
-
Framework-agnostic ASCII art engine. Convert images, videos, and GIFs into ASCII art rendered on HTML canvas.
|
|
3
|
+
Framework-agnostic ASCII art engine. Convert images, videos, and GIFs into ASCII art rendered on HTML canvas — plus 10 animated ASCII background effects.
|
|
4
4
|
|
|
5
5
|
## Features
|
|
6
6
|
|
|
@@ -11,6 +11,8 @@ Framework-agnostic ASCII art engine. Convert images, videos, and GIFs into ASCII
|
|
|
11
11
|
- **6 art styles** — Classic, Particles, Letters, Box Drawing, Dense Art, Terminal
|
|
12
12
|
- **Color modes** — Grayscale, Full Color, Matrix, Accent
|
|
13
13
|
- **Hover effects** — Spotlight, Magnify, Repel, Glow, Color Shift
|
|
14
|
+
- **10 animated backgrounds** — Wave, Rain, Stars, Pulse, Noise, Grid, Aurora, Silk, Void, Morph
|
|
15
|
+
- **Light & dark mode** — all backgrounds adapt via `lightMode` option or `colorScheme: 'auto'`
|
|
14
16
|
- **Embed code generation** — self-contained HTML output
|
|
15
17
|
- **Zero framework dependencies** — works with React, Angular, Vue, Svelte, vanilla JS
|
|
16
18
|
|
|
@@ -20,6 +22,92 @@ Framework-agnostic ASCII art engine. Convert images, videos, and GIFs into ASCII
|
|
|
20
22
|
npm install asciify-engine
|
|
21
23
|
```
|
|
22
24
|
|
|
25
|
+
## Animated Backgrounds
|
|
26
|
+
|
|
27
|
+
Drop a live ASCII animation into any element with one call.
|
|
28
|
+
|
|
29
|
+
```ts
|
|
30
|
+
import { asciiBackground } from 'asciify-engine';
|
|
31
|
+
|
|
32
|
+
// Attach to any selector — animates the element's background
|
|
33
|
+
asciiBackground('#hero', { type: 'rain' });
|
|
34
|
+
|
|
35
|
+
// Follows OS dark/light mode automatically
|
|
36
|
+
asciiBackground('#hero', { type: 'aurora', colorScheme: 'auto' });
|
|
37
|
+
|
|
38
|
+
// Force light mode (dark characters on light background)
|
|
39
|
+
asciiBackground('#hero', { type: 'wave', colorScheme: 'light' });
|
|
40
|
+
|
|
41
|
+
// Stop / clean up
|
|
42
|
+
const stop = asciiBackground('#hero', { type: 'stars' });
|
|
43
|
+
stop();
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
### Background Types
|
|
47
|
+
|
|
48
|
+
| Type | Description |
|
|
49
|
+
|---|---|
|
|
50
|
+
| `wave` | Flowing sine-wave field with noise turbulence |
|
|
51
|
+
| `rain` | Matrix-style vertical column rain with glowing head and fading tail |
|
|
52
|
+
| `stars` | Parallax star field that reacts to cursor position |
|
|
53
|
+
| `pulse` | Concentric ripple bursts that emanate from the cursor |
|
|
54
|
+
| `noise` | Smooth value-noise field with organic flow |
|
|
55
|
+
| `grid` | Geometric grid that warps and glows at cursor proximity |
|
|
56
|
+
| `aurora` | Sweeping borealis-style colour bands |
|
|
57
|
+
| `silk` | Silky fluid swirls following the cursor |
|
|
58
|
+
| `void` | Gravitational singularity — characters spiral inward toward cursor |
|
|
59
|
+
| `morph` | Characters morph between shapes driven by noise |
|
|
60
|
+
|
|
61
|
+
### `asciiBackground` Options
|
|
62
|
+
|
|
63
|
+
| Option | Type | Default | Description |
|
|
64
|
+
|---|---|---|---|
|
|
65
|
+
| `type` | `string` | `'wave'` | Which background renderer to use |
|
|
66
|
+
| `colorScheme` | `'auto' \| 'light' \| 'dark'` | `'dark'` | `'auto'` follows OS theme live; `'light'` = dark chars on light bg |
|
|
67
|
+
| `fontSize` | `number` | `13` | Character size in px |
|
|
68
|
+
| `accentColor` | `string` | varies | Head/highlight colour (CSS colour string) |
|
|
69
|
+
| `color` | `string` | — | Override body character colour |
|
|
70
|
+
| `speed` | `number` | `1` | Global animation speed multiplier |
|
|
71
|
+
| `density` | `number` | `0.55` | Fraction of cells active (0–1) |
|
|
72
|
+
| `lightMode` | `boolean` | `false` | Dark characters on light background |
|
|
73
|
+
|
|
74
|
+
Each background type also accepts its own specific options — see the individual type exports (e.g. `RainBackgroundOptions`, `WaveBackgroundOptions`, etc.) for the full list.
|
|
75
|
+
|
|
76
|
+
### Low-level background renderers
|
|
77
|
+
|
|
78
|
+
All renderers are also exported individually for direct canvas use:
|
|
79
|
+
|
|
80
|
+
```ts
|
|
81
|
+
import {
|
|
82
|
+
renderRainBackground,
|
|
83
|
+
renderWaveBackground,
|
|
84
|
+
renderStarsBackground,
|
|
85
|
+
renderPulseBackground,
|
|
86
|
+
renderNoiseBackground,
|
|
87
|
+
renderGridBackground,
|
|
88
|
+
renderAuroraBackground,
|
|
89
|
+
renderSilkBackground,
|
|
90
|
+
renderVoidBackground,
|
|
91
|
+
renderMorphBackground,
|
|
92
|
+
} from 'asciify-engine';
|
|
93
|
+
|
|
94
|
+
// Example: drive the rain renderer yourself
|
|
95
|
+
const canvas = document.getElementById('canvas') as HTMLCanvasElement;
|
|
96
|
+
const ctx = canvas.getContext('2d')!;
|
|
97
|
+
let t = 0;
|
|
98
|
+
function tick() {
|
|
99
|
+
renderRainBackground(ctx, canvas.width, canvas.height, t, {
|
|
100
|
+
speed: 1.2,
|
|
101
|
+
density: 0.6,
|
|
102
|
+
accentColor: '#00ffcc',
|
|
103
|
+
lightMode: false,
|
|
104
|
+
});
|
|
105
|
+
t += 0.016;
|
|
106
|
+
requestAnimationFrame(tick);
|
|
107
|
+
}
|
|
108
|
+
tick();
|
|
109
|
+
```
|
|
110
|
+
|
|
23
111
|
## Quick Start
|
|
24
112
|
|
|
25
113
|
### Vanilla JS
|
|
@@ -31,7 +119,6 @@ npm install asciify-engine
|
|
|
31
119
|
imageToAsciiFrame,
|
|
32
120
|
renderFrameToCanvas,
|
|
33
121
|
DEFAULT_OPTIONS,
|
|
34
|
-
ART_STYLE_PRESETS,
|
|
35
122
|
} from 'asciify-engine';
|
|
36
123
|
|
|
37
124
|
const img = new Image();
|
|
@@ -39,10 +126,8 @@ npm install asciify-engine
|
|
|
39
126
|
img.src = 'https://picsum.photos/600/400';
|
|
40
127
|
img.onload = () => {
|
|
41
128
|
const canvas = document.getElementById('ascii');
|
|
42
|
-
const options = { ...DEFAULT_OPTIONS,
|
|
43
|
-
const
|
|
44
|
-
const rows = Math.floor(canvas.height / (options.fontSize * 1.8));
|
|
45
|
-
const frame = imageToAsciiFrame(img, options, cols, rows);
|
|
129
|
+
const options = { ...DEFAULT_OPTIONS, fontSize: 10 };
|
|
130
|
+
const { frame } = imageToAsciiFrame(img, options, canvas.width, canvas.height);
|
|
46
131
|
renderFrameToCanvas(canvas.getContext('2d'), frame, options, canvas.width, canvas.height);
|
|
47
132
|
};
|
|
48
133
|
</script>
|
|
@@ -56,11 +141,9 @@ import {
|
|
|
56
141
|
imageToAsciiFrame,
|
|
57
142
|
renderFrameToCanvas,
|
|
58
143
|
DEFAULT_OPTIONS,
|
|
59
|
-
ART_STYLE_PRESETS,
|
|
60
|
-
type ArtStyle,
|
|
61
144
|
} from 'asciify-engine';
|
|
62
145
|
|
|
63
|
-
export function AsciiImage({ src
|
|
146
|
+
export function AsciiImage({ src }: { src: string }) {
|
|
64
147
|
const ref = useRef<HTMLCanvasElement>(null);
|
|
65
148
|
|
|
66
149
|
useEffect(() => {
|
|
@@ -69,13 +152,11 @@ export function AsciiImage({ src, style = 'classic' }: { src: string; style?: Ar
|
|
|
69
152
|
img.src = src;
|
|
70
153
|
img.onload = () => {
|
|
71
154
|
const canvas = ref.current!;
|
|
72
|
-
const opts = { ...DEFAULT_OPTIONS,
|
|
73
|
-
const
|
|
74
|
-
const rows = Math.floor(canvas.height / (opts.fontSize * 1.8));
|
|
75
|
-
const frame = imageToAsciiFrame(img, opts, cols, rows);
|
|
155
|
+
const opts = { ...DEFAULT_OPTIONS, fontSize: 10 };
|
|
156
|
+
const { frame } = imageToAsciiFrame(img, opts, canvas.width, canvas.height);
|
|
76
157
|
renderFrameToCanvas(canvas.getContext('2d')!, frame, opts, canvas.width, canvas.height);
|
|
77
158
|
};
|
|
78
|
-
}, [src
|
|
159
|
+
}, [src]);
|
|
79
160
|
|
|
80
161
|
return <canvas ref={ref} width={800} height={600} />;
|
|
81
162
|
}
|
|
@@ -84,12 +165,11 @@ export function AsciiImage({ src, style = 'classic' }: { src: string; style?: Ar
|
|
|
84
165
|
### Angular
|
|
85
166
|
|
|
86
167
|
```typescript
|
|
87
|
-
import { Component, ElementRef,
|
|
168
|
+
import { Component, ElementRef, ViewChild, AfterViewInit } from '@angular/core';
|
|
88
169
|
import {
|
|
89
170
|
imageToAsciiFrame,
|
|
90
171
|
renderFrameToCanvas,
|
|
91
172
|
DEFAULT_OPTIONS,
|
|
92
|
-
ART_STYLE_PRESETS,
|
|
93
173
|
} from 'asciify-engine';
|
|
94
174
|
|
|
95
175
|
@Component({
|
|
@@ -98,19 +178,15 @@ import {
|
|
|
98
178
|
})
|
|
99
179
|
export class AsciiComponent implements AfterViewInit {
|
|
100
180
|
@ViewChild('canvas') canvasRef!: ElementRef<HTMLCanvasElement>;
|
|
101
|
-
@Input() src!: string;
|
|
102
|
-
@Input() artStyle = 'classic';
|
|
103
181
|
|
|
104
182
|
ngAfterViewInit() {
|
|
105
183
|
const img = new Image();
|
|
106
184
|
img.crossOrigin = 'anonymous';
|
|
107
|
-
img.src =
|
|
185
|
+
img.src = 'https://picsum.photos/600/400';
|
|
108
186
|
img.onload = () => {
|
|
109
187
|
const canvas = this.canvasRef.nativeElement;
|
|
110
|
-
const opts = { ...DEFAULT_OPTIONS,
|
|
111
|
-
const
|
|
112
|
-
const rows = Math.floor(canvas.height / (opts.fontSize * 1.8));
|
|
113
|
-
const frame = imageToAsciiFrame(img, opts, cols, rows);
|
|
188
|
+
const opts = { ...DEFAULT_OPTIONS, fontSize: 10 };
|
|
189
|
+
const { frame } = imageToAsciiFrame(img, opts, canvas.width, canvas.height);
|
|
114
190
|
renderFrameToCanvas(canvas.getContext('2d')!, frame, opts, canvas.width, canvas.height);
|
|
115
191
|
};
|
|
116
192
|
}
|
|
@@ -128,10 +204,8 @@ const buffer = await response.arrayBuffer();
|
|
|
128
204
|
const canvas = document.getElementById('ascii') as HTMLCanvasElement;
|
|
129
205
|
const ctx = canvas.getContext('2d')!;
|
|
130
206
|
const options = { ...DEFAULT_OPTIONS, fontSize: 8 };
|
|
131
|
-
const cols = Math.floor(canvas.width / options.fontSize);
|
|
132
|
-
const rows = Math.floor(canvas.height / (options.fontSize * 1.8));
|
|
133
207
|
|
|
134
|
-
const { frames, fps } = await gifToAsciiFrames(buffer, options,
|
|
208
|
+
const { frames, fps } = await gifToAsciiFrames(buffer, options, canvas.width, canvas.height);
|
|
135
209
|
|
|
136
210
|
let i = 0;
|
|
137
211
|
setInterval(() => {
|
|
@@ -150,31 +224,31 @@ video.crossOrigin = 'anonymous';
|
|
|
150
224
|
video.src = '/my-video.mp4';
|
|
151
225
|
await new Promise((r) => (video.onloadeddata = r));
|
|
152
226
|
|
|
227
|
+
const canvas = document.getElementById('ascii') as HTMLCanvasElement;
|
|
153
228
|
const options = { ...DEFAULT_OPTIONS, fontSize: 8 };
|
|
154
|
-
|
|
155
|
-
const
|
|
156
|
-
const { frames, fps } = await videoToAsciiFrames(video, options, cols, rows, 10, 6);
|
|
229
|
+
|
|
230
|
+
const { frames, fps } = await videoToAsciiFrames(video, options, canvas.width, canvas.height, 12, 10);
|
|
157
231
|
|
|
158
232
|
let i = 0;
|
|
159
233
|
setInterval(() => {
|
|
160
|
-
|
|
161
|
-
renderFrameToCanvas(ctx, frames[i], options, 800, 600);
|
|
234
|
+
renderFrameToCanvas(canvas.getContext('2d')!, frames[i], options, canvas.width, canvas.height);
|
|
162
235
|
i = (i + 1) % frames.length;
|
|
163
236
|
}, 1000 / fps);
|
|
164
237
|
```
|
|
165
238
|
|
|
166
239
|
## API
|
|
167
240
|
|
|
168
|
-
### Functions
|
|
241
|
+
### Core Functions
|
|
169
242
|
|
|
170
243
|
| Function | Description |
|
|
171
244
|
|---|---|
|
|
172
|
-
| `imageToAsciiFrame(
|
|
173
|
-
| `renderFrameToCanvas(ctx, frame, options, width, height)` | Render an ASCII frame onto a canvas context |
|
|
174
|
-
| `gifToAsciiFrames(buffer, options,
|
|
175
|
-
| `videoToAsciiFrames(video, options,
|
|
245
|
+
| `imageToAsciiFrame(source, options, targetWidth?, targetHeight?)` | Convert an image/video/canvas to a single ASCII frame; returns `{ frame, cols, rows }` |
|
|
246
|
+
| `renderFrameToCanvas(ctx, frame, options, width, height, time?, hoverPos?)` | Render an ASCII frame onto a canvas context |
|
|
247
|
+
| `gifToAsciiFrames(buffer, options, targetWidth, targetHeight, onProgress?)` | Convert a GIF `ArrayBuffer` to animated frames; returns `{ frames, cols, rows, fps }` |
|
|
248
|
+
| `videoToAsciiFrames(video, options, targetWidth, targetHeight, fps?, maxDuration?, onProgress?)` | Convert a `<video>` to animated frames; returns `{ frames, cols, rows, fps }` |
|
|
176
249
|
| `generateEmbedCode(frame, options)` | Generate self-contained HTML embed string |
|
|
177
250
|
| `generateAnimatedEmbedCode(frames, options, fps)` | Generate animated HTML embed string |
|
|
251
|
+
| `asciiBackground(selector, options)` | Mount an animated ASCII background on an element; returns a cleanup function |
|
|
178
252
|
|
|
179
253
|
### Art Styles
|
|
180
254
|
|
package/dist/index.cjs
CHANGED
|
@@ -374,7 +374,7 @@ function lerp(a, b, t) {
|
|
|
374
374
|
function hash2(ix, iy) {
|
|
375
375
|
let n = ix * 127 + iy * 311;
|
|
376
376
|
n = n >> 13 ^ n;
|
|
377
|
-
return (n * (n * n * 15731 + 789221) + 1376312589 & 2147483647) /
|
|
377
|
+
return (n * (n * n * 15731 + 789221) + 1376312589 & 2147483647) / 2147483647;
|
|
378
378
|
}
|
|
379
379
|
function vnoise(x, y) {
|
|
380
380
|
const ix = Math.floor(x), iy = Math.floor(y);
|