asciify-engine 1.0.32 → 1.0.35

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.cts CHANGED
@@ -17,24 +17,99 @@ declare const PALETTE_THEMES: Record<PaletteTheme, {
17
17
  }>;
18
18
  type SourceType = 'image' | 'video' | 'gif' | null;
19
19
  interface AsciiOptions {
20
+ /** Character cell size in pixels. Smaller = more detail, more cells. Default: `10` */
20
21
  fontSize: number;
22
+ /** Extra horizontal spacing between characters (pixels). Default: `1` */
21
23
  charSpacing: number;
24
+ /**
25
+ * Brightness adjustment applied before luminance mapping.
26
+ * Range −1 (black) → 0 (unchanged) → 1 (white). Default: `0`
27
+ */
22
28
  brightness: number;
29
+ /**
30
+ * Contrast boost applied before luminance mapping.
31
+ * `0` = unchanged, positive values increase contrast, negative decrease it.
32
+ * Default: `0`
33
+ */
23
34
  contrast: number;
35
+ /**
36
+ * Character density ramp — ordered from lightest to darkest.
37
+ * Use `CHARSETS` for pre-built ramps or supply your own string.
38
+ * Default: `' .:-=+*#%@'`
39
+ */
24
40
  charset: string;
41
+ /**
42
+ * Colour output mode.
43
+ * - `'grayscale'` — white-on-black monochrome
44
+ * - `'fullcolor'` — samples pixel colours from the source
45
+ * - `'matrix'` — green phosphor terminal look
46
+ * - `'accent'` — single accent colour with intensity-driven brightness
47
+ * Default: `'grayscale'`
48
+ */
25
49
  colorMode: ColorMode;
50
+ /**
51
+ * The accent colour used when `colorMode` is `'accent'` or `'matrix'`.
52
+ * Any CSS colour string. Default: `'#d4ff00'`
53
+ */
26
54
  accentColor: string;
55
+ /** Invert luminance mapping (light pixels → dense chars). Default: `false` */
27
56
  invert: boolean;
57
+ /**
58
+ * Render mode.
59
+ * - `'ascii'` — characters drawn as text
60
+ * - `'dots'` — each cell rendered as a filled circle (particle look)
61
+ * Default: `'ascii'`
62
+ */
28
63
  renderMode: RenderMode;
64
+ /**
65
+ * Per-character animation driven over time.
66
+ * Applies wave, glitch, rain-drop, spiral, and other effects to the rendered text.
67
+ * Default: `'none'`
68
+ */
29
69
  animationStyle: AnimationStyle;
70
+ /** Speed multiplier for `animationStyle` effects. Default: `1` */
30
71
  animationSpeed: number;
72
+ /**
73
+ * Size of each dot relative to the cell when `renderMode === 'dots'`.
74
+ * `1` fills the whole cell, `0.5` draws half-size circles. Default: `0.8`
75
+ */
31
76
  dotSizeRatio: number;
77
+ /**
78
+ * Floyd-Steinberg dither strength applied to the luminance map.
79
+ * `0` = no dithering, `1` = full dithering. Default: `0`
80
+ */
32
81
  ditherStrength: number;
82
+ /**
83
+ * Overall intensity of the hover / cursor interaction effect.
84
+ * `0` disables the effect. Default: `0`
85
+ */
33
86
  hoverStrength: number;
87
+ /**
88
+ * Radius of the hover interaction zone as a fraction of the canvas size.
89
+ * `0.1` = 10% of canvas width. Default: `0.2`
90
+ */
34
91
  hoverRadius: number;
92
+ /**
93
+ * Which cursor interaction style to apply when `hoverStrength > 0`.
94
+ * See `HoverPreset` or `HOVER_PRESETS` for ready-made configurations.
95
+ * Default: `'spotlight'`
96
+ */
35
97
  hoverEffect: HoverEffect;
98
+ /**
99
+ * Tint colour used by hover effects such as spotlight, glow, and colorShift.
100
+ * Any CSS colour string. Default: `'#ffffff'`
101
+ */
36
102
  hoverColor: string;
103
+ /**
104
+ * Art style preset applied at render time.
105
+ * Shorthand for a specific combination of `charset`, `renderMode`, and `colorMode`.
106
+ * See `ART_STYLE_PRESETS` for the full list. Default: `'classic'`
107
+ */
37
108
  artStyle: ArtStyle;
109
+ /**
110
+ * Custom repeating text used when `artStyle` is `'letters'` or when you set
111
+ * a custom charset. Leave empty to use the selected `charset`. Default: `''`
112
+ */
38
113
  customText: string;
39
114
  }
40
115
  interface AsciiCell {
@@ -130,8 +205,12 @@ declare function renderFrameToCanvas(ctx: CanvasRenderingContext2D, frame: Ascii
130
205
  interface AsciifySimpleOptions {
131
206
  /** Character size in pixels. Default: 10 */
132
207
  fontSize?: number;
133
- /** Art style preset. Default: 'classic' */
134
- style?: ArtStyle;
208
+ /**
209
+ * Art style preset — controls charset, render mode, and color mode together.
210
+ * Shorthand for spreading `ART_STYLE_PRESETS[artStyle]` into options.
211
+ * Default: `'classic'`
212
+ */
213
+ artStyle?: ArtStyle;
135
214
  /** Extra options to merge on top of the preset */
136
215
  options?: Partial<AsciiOptions>;
137
216
  }
@@ -140,9 +219,9 @@ interface AsciifySimpleOptions {
140
219
  *
141
220
  * @example
142
221
  * await asciify(document.querySelector('img'), canvas);
143
- * await asciify(img, canvas, { fontSize: 8, style: 'letters' });
222
+ * await asciify(img, canvas, { fontSize: 8, artStyle: 'letters' });
144
223
  */
145
- declare function asciify(source: HTMLImageElement | HTMLVideoElement | HTMLCanvasElement | string, canvas: HTMLCanvasElement, { fontSize, style, options }?: AsciifySimpleOptions): Promise<void>;
224
+ declare function asciify(source: HTMLImageElement | HTMLVideoElement | HTMLCanvasElement | string, canvas: HTMLCanvasElement, { fontSize, artStyle, options }?: AsciifySimpleOptions): Promise<void>;
146
225
  /**
147
226
  * Fetch a GIF, convert it to ASCII, and start an animation loop on a canvas.
148
227
  * Returns a `stop()` function that cancels the loop.
@@ -151,7 +230,7 @@ declare function asciify(source: HTMLImageElement | HTMLVideoElement | HTMLCanva
151
230
  * const stop = await asciifyGif('animation.gif', canvas);
152
231
  * // later: stop();
153
232
  */
154
- declare function asciifyGif(source: string | ArrayBuffer, canvas: HTMLCanvasElement, { fontSize, style, options }?: AsciifySimpleOptions): Promise<() => void>;
233
+ declare function asciifyGif(source: string | ArrayBuffer, canvas: HTMLCanvasElement, { fontSize, artStyle, options }?: AsciifySimpleOptions): Promise<() => void>;
155
234
  /**
156
235
  * Convert a video element to ASCII art and start an animation loop on a canvas.
157
236
  * Returns a `stop()` function that cancels the loop.
@@ -160,7 +239,7 @@ declare function asciifyGif(source: string | ArrayBuffer, canvas: HTMLCanvasElem
160
239
  * const stop = await asciifyVideo(video, canvas);
161
240
  * // later: stop();
162
241
  */
163
- declare function asciifyVideo(source: HTMLVideoElement | string, canvas: HTMLCanvasElement, { fontSize, style, options }?: AsciifySimpleOptions): Promise<() => void>;
242
+ declare function asciifyVideo(source: HTMLVideoElement | string, canvas: HTMLCanvasElement, { fontSize, artStyle, options }?: AsciifySimpleOptions): Promise<() => void>;
164
243
 
165
244
  interface WaveBackgroundOptions {
166
245
  /** Font size in CSS pixels (default: 13) */
@@ -711,66 +790,108 @@ declare function renderTextBackground(ctx: CanvasRenderingContext2D, width: numb
711
790
  intensity?: number;
712
791
  } | null): void;
713
792
 
714
- /**
715
- * record() — capture a rolling frame buffer from a running ASCII canvas
716
- * and export it as a downloadable animated GIF or WebP data URL.
717
- *
718
- * Usage:
719
- * ```ts
720
- * const recorder = createRecorder(canvasEl, { fps: 15, maxFrames: 120 });
721
- * recorder.start();
722
- * // ... after a few seconds ...
723
- * const dataUrl = await recorder.stop(); // 'data:image/gif;base64,...'
724
- * ```
725
- */
726
- interface RecorderOptions {
727
- /** Target capture frame rate (default: 15) */
728
- fps?: number;
729
- /** Maximum number of frames to buffer (default: 120 → 8 s at 15 fps) */
730
- maxFrames?: number;
731
- /**
732
- * Output format.
733
- * - 'gif' — animated GIF via gif.js worker (requires gif.worker.js in public/)
734
- * - 'webp' — animated WebP via MediaRecorder API (Chrome/Edge only)
735
- * - 'png-sequence' — returns a JSON array of PNG data URLs (universal)
736
- * Default: 'gif'
737
- */
738
- format?: 'gif' | 'webp' | 'png-sequence';
739
- /** GIF quality 1 (best) – 30 (smallest) — only used for format:'gif' (default: 10) */
793
+ interface SnapshotOptions {
794
+ /**
795
+ * Image format.
796
+ * - 'png' — lossless (default)
797
+ * - 'jpeg' — smaller, no transparency
798
+ * - 'webp' — best compression with transparency
799
+ */
800
+ format?: 'png' | 'jpeg' | 'webp';
801
+ /** 0–1 quality for jpeg/webp. Default: 0.92 */
740
802
  quality?: number;
741
803
  /**
742
- * Scale factor applied to the canvas before capture (default: 1).
743
- * Use 0.5 to halve dimensions and reduce file size.
804
+ * Scale factor applied before capture. Default: 1.
805
+ * Use 2 for a high-resolution export at the canvas size.
744
806
  */
745
807
  scale?: number;
746
808
  }
747
- interface Recorder {
748
- /** Start capturing frames from the canvas. */
749
- start(): void;
750
- /**
751
- * Stop capturing and encode.
752
- * Resolves with a data URL (gif/webp) or JSON string (png-sequence).
753
- */
754
- stop(): Promise<string>;
755
- /** True while recording. */
756
- readonly isRecording: boolean;
757
- /** Number of frames captured so far. */
758
- readonly frameCount: number;
759
- }
760
809
  /**
761
- * Create a Recorder bound to a canvas element.
810
+ * Capture a single frame from a canvas as a Blob.
811
+ *
812
+ * @example
813
+ * ```ts
814
+ * const blob = await captureSnapshot(canvas);
815
+ * const url = URL.createObjectURL(blob);
816
+ * ```
762
817
  */
763
- declare function createRecorder(canvas: HTMLCanvasElement, options?: RecorderOptions): Recorder;
818
+ declare function captureSnapshot(canvas: HTMLCanvasElement, { format, quality, scale }?: SnapshotOptions): Promise<Blob>;
764
819
  /**
765
- * Convenience: record for a fixed duration and auto-download.
820
+ * Capture a single frame and immediately trigger a browser download.
766
821
  *
767
822
  * @example
768
823
  * ```ts
769
- * await recordAndDownload(canvasEl, 3000, { fps: 15, format: 'gif' });
824
+ * await snapshotAndDownload(canvas);
825
+ * await snapshotAndDownload(canvas, { format: 'jpeg', filename: 'my-art' });
770
826
  * ```
771
827
  */
772
- declare function recordAndDownload(canvas: HTMLCanvasElement, durationMs: number, options?: RecorderOptions & {
828
+ declare function snapshotAndDownload(canvas: HTMLCanvasElement, options?: SnapshotOptions & {
773
829
  filename?: string;
774
830
  }): Promise<void>;
775
831
 
776
- export { ART_STYLE_PRESETS, type AnimationStyle, type ArtStyle, type AsciiBackgroundOptions, type AsciiCell, type AsciiFrame, type AsciiOptions, type AsciiResult, type AsciifySimpleOptions, type AuroraBackgroundOptions, CHARSETS, type CharsetKey, type CircuitBackgroundOptions, type ColorMode, DEFAULT_OPTIONS, type DnaBackgroundOptions, type FireBackgroundOptions, type GridBackgroundOptions, HOVER_PRESETS, type HoverEffect, type HoverPreset, type MorphBackgroundOptions, type MountWaveOptions, type NoiseBackgroundOptions, PALETTE_THEMES, type PaletteTheme, type PulseBackgroundOptions, type RainBackgroundOptions, type Recorder, type RecorderOptions, type RenderMode, type SilkBackgroundOptions, type SourceType, type StarsBackgroundOptions, type TerrainBackgroundOptions, type TextBackgroundOptions, type VoidBackgroundOptions, type WaveBackgroundOptions, asciiBackground, asciiText, asciiTextAnsi, asciify, asciifyGif, asciifyVideo, buildTextFrame, createRecorder, gifToAsciiFrames, imageToAsciiFrame, mountWaveBackground, recordAndDownload, renderAuroraBackground, renderCircuitBackground, renderDnaBackground, renderFireBackground, renderFrameToCanvas, renderGridBackground, renderMorphBackground, renderNoiseBackground, renderPulseBackground, renderRainBackground, renderSilkBackground, renderStarsBackground, renderTerrainBackground, renderTextBackground, renderVoidBackground, renderWaveBackground, videoToAsciiFrames };
832
+ /**
833
+ * asciifyWebcam — live webcam → ASCII art on canvas.
834
+ *
835
+ * Requests camera access, attaches the stream to a hidden video element, and
836
+ * runs a rAF loop that converts each frame to ASCII and renders it onto a
837
+ * supplied canvas.
838
+ *
839
+ * @example
840
+ * const stop = await asciifyWebcam(canvas);
841
+ * // later: stop();
842
+ *
843
+ * @example
844
+ * const stop = await asciifyWebcam(canvas, {
845
+ * fontSize: 8,
846
+ * style: 'terminal',
847
+ * mirror: true, // horizontal flip (selfie mode)
848
+ * constraints: { facingMode: 'user' },
849
+ * });
850
+ */
851
+
852
+ interface WebcamOptions {
853
+ /** Character size in pixels. Default: 10 */
854
+ fontSize?: number;
855
+ /** Art style preset. Default: 'classic' */
856
+ style?: ArtStyle;
857
+ /** Extra AsciiOptions merged on top of the preset */
858
+ options?: Partial<AsciiOptions>;
859
+ /**
860
+ * Called every frame to get the latest options. Takes priority over `options`.
861
+ * Use this to keep the rendering in sync with live UI controls without
862
+ * restarting the camera.
863
+ *
864
+ * @example
865
+ * const optionsRef = useRef(currentOptions);
866
+ * optionsRef.current = currentOptions;
867
+ * asciifyWebcam(canvas, { liveOptions: () => optionsRef.current });
868
+ */
869
+ liveOptions?: () => Partial<AsciiOptions>;
870
+ /**
871
+ * Flip the output horizontally so it reads like a mirror / selfie camera.
872
+ * Default: true
873
+ */
874
+ mirror?: boolean;
875
+ /**
876
+ * Passed directly to `getUserMedia({ video: constraints })`.
877
+ * Defaults to `{ facingMode: 'user' }`.
878
+ */
879
+ constraints?: MediaTrackConstraints;
880
+ /**
881
+ * Device pixel ratio used to compute logical render dimensions from the
882
+ * canvas's physical pixel size. Defaults to `window.devicePixelRatio ?? 1`.
883
+ * Set this when you size the canvas at physical resolution (e.g. width × dpr)
884
+ * so that ASCII column/row counts are based on CSS pixels, not physical ones.
885
+ */
886
+ dpr?: number;
887
+ }
888
+ /**
889
+ * Start a live webcam ASCII-art loop and render it onto `canvas`.
890
+ * Returns a `stop()` function that cancels the loop and releases the camera.
891
+ *
892
+ * Throws if the browser doesn't support `getUserMedia` or the user denies
893
+ * camera permission.
894
+ */
895
+ declare function asciifyWebcam(canvas: HTMLCanvasElement, { fontSize, style, options, liveOptions, mirror, constraints, dpr: dprOverride, }?: WebcamOptions): Promise<() => void>;
896
+
897
+ export { ART_STYLE_PRESETS, type AnimationStyle, type ArtStyle, type AsciiBackgroundOptions, type AsciiCell, type AsciiFrame, type AsciiOptions, type AsciiResult, type AsciifySimpleOptions, type AuroraBackgroundOptions, CHARSETS, type CharsetKey, type CircuitBackgroundOptions, type ColorMode, DEFAULT_OPTIONS, type DnaBackgroundOptions, type FireBackgroundOptions, type GridBackgroundOptions, HOVER_PRESETS, type HoverEffect, type HoverPreset, type MorphBackgroundOptions, type MountWaveOptions, type NoiseBackgroundOptions, PALETTE_THEMES, type PaletteTheme, type PulseBackgroundOptions, type RainBackgroundOptions, type RenderMode, type SilkBackgroundOptions, type SnapshotOptions, type SourceType, type StarsBackgroundOptions, type TerrainBackgroundOptions, type TextBackgroundOptions, type VoidBackgroundOptions, type WaveBackgroundOptions, type WebcamOptions, asciiBackground, asciiText, asciiTextAnsi, asciify, asciifyGif, asciifyVideo, asciifyWebcam, buildTextFrame, captureSnapshot, gifToAsciiFrames, imageToAsciiFrame, mountWaveBackground, renderAuroraBackground, renderCircuitBackground, renderDnaBackground, renderFireBackground, renderFrameToCanvas, renderGridBackground, renderMorphBackground, renderNoiseBackground, renderPulseBackground, renderRainBackground, renderSilkBackground, renderStarsBackground, renderTerrainBackground, renderTextBackground, renderVoidBackground, renderWaveBackground, snapshotAndDownload, videoToAsciiFrames };
package/dist/index.d.ts CHANGED
@@ -17,24 +17,99 @@ declare const PALETTE_THEMES: Record<PaletteTheme, {
17
17
  }>;
18
18
  type SourceType = 'image' | 'video' | 'gif' | null;
19
19
  interface AsciiOptions {
20
+ /** Character cell size in pixels. Smaller = more detail, more cells. Default: `10` */
20
21
  fontSize: number;
22
+ /** Extra horizontal spacing between characters (pixels). Default: `1` */
21
23
  charSpacing: number;
24
+ /**
25
+ * Brightness adjustment applied before luminance mapping.
26
+ * Range −1 (black) → 0 (unchanged) → 1 (white). Default: `0`
27
+ */
22
28
  brightness: number;
29
+ /**
30
+ * Contrast boost applied before luminance mapping.
31
+ * `0` = unchanged, positive values increase contrast, negative decrease it.
32
+ * Default: `0`
33
+ */
23
34
  contrast: number;
35
+ /**
36
+ * Character density ramp — ordered from lightest to darkest.
37
+ * Use `CHARSETS` for pre-built ramps or supply your own string.
38
+ * Default: `' .:-=+*#%@'`
39
+ */
24
40
  charset: string;
41
+ /**
42
+ * Colour output mode.
43
+ * - `'grayscale'` — white-on-black monochrome
44
+ * - `'fullcolor'` — samples pixel colours from the source
45
+ * - `'matrix'` — green phosphor terminal look
46
+ * - `'accent'` — single accent colour with intensity-driven brightness
47
+ * Default: `'grayscale'`
48
+ */
25
49
  colorMode: ColorMode;
50
+ /**
51
+ * The accent colour used when `colorMode` is `'accent'` or `'matrix'`.
52
+ * Any CSS colour string. Default: `'#d4ff00'`
53
+ */
26
54
  accentColor: string;
55
+ /** Invert luminance mapping (light pixels → dense chars). Default: `false` */
27
56
  invert: boolean;
57
+ /**
58
+ * Render mode.
59
+ * - `'ascii'` — characters drawn as text
60
+ * - `'dots'` — each cell rendered as a filled circle (particle look)
61
+ * Default: `'ascii'`
62
+ */
28
63
  renderMode: RenderMode;
64
+ /**
65
+ * Per-character animation driven over time.
66
+ * Applies wave, glitch, rain-drop, spiral, and other effects to the rendered text.
67
+ * Default: `'none'`
68
+ */
29
69
  animationStyle: AnimationStyle;
70
+ /** Speed multiplier for `animationStyle` effects. Default: `1` */
30
71
  animationSpeed: number;
72
+ /**
73
+ * Size of each dot relative to the cell when `renderMode === 'dots'`.
74
+ * `1` fills the whole cell, `0.5` draws half-size circles. Default: `0.8`
75
+ */
31
76
  dotSizeRatio: number;
77
+ /**
78
+ * Floyd-Steinberg dither strength applied to the luminance map.
79
+ * `0` = no dithering, `1` = full dithering. Default: `0`
80
+ */
32
81
  ditherStrength: number;
82
+ /**
83
+ * Overall intensity of the hover / cursor interaction effect.
84
+ * `0` disables the effect. Default: `0`
85
+ */
33
86
  hoverStrength: number;
87
+ /**
88
+ * Radius of the hover interaction zone as a fraction of the canvas size.
89
+ * `0.1` = 10% of canvas width. Default: `0.2`
90
+ */
34
91
  hoverRadius: number;
92
+ /**
93
+ * Which cursor interaction style to apply when `hoverStrength > 0`.
94
+ * See `HoverPreset` or `HOVER_PRESETS` for ready-made configurations.
95
+ * Default: `'spotlight'`
96
+ */
35
97
  hoverEffect: HoverEffect;
98
+ /**
99
+ * Tint colour used by hover effects such as spotlight, glow, and colorShift.
100
+ * Any CSS colour string. Default: `'#ffffff'`
101
+ */
36
102
  hoverColor: string;
103
+ /**
104
+ * Art style preset applied at render time.
105
+ * Shorthand for a specific combination of `charset`, `renderMode`, and `colorMode`.
106
+ * See `ART_STYLE_PRESETS` for the full list. Default: `'classic'`
107
+ */
37
108
  artStyle: ArtStyle;
109
+ /**
110
+ * Custom repeating text used when `artStyle` is `'letters'` or when you set
111
+ * a custom charset. Leave empty to use the selected `charset`. Default: `''`
112
+ */
38
113
  customText: string;
39
114
  }
40
115
  interface AsciiCell {
@@ -130,8 +205,12 @@ declare function renderFrameToCanvas(ctx: CanvasRenderingContext2D, frame: Ascii
130
205
  interface AsciifySimpleOptions {
131
206
  /** Character size in pixels. Default: 10 */
132
207
  fontSize?: number;
133
- /** Art style preset. Default: 'classic' */
134
- style?: ArtStyle;
208
+ /**
209
+ * Art style preset — controls charset, render mode, and color mode together.
210
+ * Shorthand for spreading `ART_STYLE_PRESETS[artStyle]` into options.
211
+ * Default: `'classic'`
212
+ */
213
+ artStyle?: ArtStyle;
135
214
  /** Extra options to merge on top of the preset */
136
215
  options?: Partial<AsciiOptions>;
137
216
  }
@@ -140,9 +219,9 @@ interface AsciifySimpleOptions {
140
219
  *
141
220
  * @example
142
221
  * await asciify(document.querySelector('img'), canvas);
143
- * await asciify(img, canvas, { fontSize: 8, style: 'letters' });
222
+ * await asciify(img, canvas, { fontSize: 8, artStyle: 'letters' });
144
223
  */
145
- declare function asciify(source: HTMLImageElement | HTMLVideoElement | HTMLCanvasElement | string, canvas: HTMLCanvasElement, { fontSize, style, options }?: AsciifySimpleOptions): Promise<void>;
224
+ declare function asciify(source: HTMLImageElement | HTMLVideoElement | HTMLCanvasElement | string, canvas: HTMLCanvasElement, { fontSize, artStyle, options }?: AsciifySimpleOptions): Promise<void>;
146
225
  /**
147
226
  * Fetch a GIF, convert it to ASCII, and start an animation loop on a canvas.
148
227
  * Returns a `stop()` function that cancels the loop.
@@ -151,7 +230,7 @@ declare function asciify(source: HTMLImageElement | HTMLVideoElement | HTMLCanva
151
230
  * const stop = await asciifyGif('animation.gif', canvas);
152
231
  * // later: stop();
153
232
  */
154
- declare function asciifyGif(source: string | ArrayBuffer, canvas: HTMLCanvasElement, { fontSize, style, options }?: AsciifySimpleOptions): Promise<() => void>;
233
+ declare function asciifyGif(source: string | ArrayBuffer, canvas: HTMLCanvasElement, { fontSize, artStyle, options }?: AsciifySimpleOptions): Promise<() => void>;
155
234
  /**
156
235
  * Convert a video element to ASCII art and start an animation loop on a canvas.
157
236
  * Returns a `stop()` function that cancels the loop.
@@ -160,7 +239,7 @@ declare function asciifyGif(source: string | ArrayBuffer, canvas: HTMLCanvasElem
160
239
  * const stop = await asciifyVideo(video, canvas);
161
240
  * // later: stop();
162
241
  */
163
- declare function asciifyVideo(source: HTMLVideoElement | string, canvas: HTMLCanvasElement, { fontSize, style, options }?: AsciifySimpleOptions): Promise<() => void>;
242
+ declare function asciifyVideo(source: HTMLVideoElement | string, canvas: HTMLCanvasElement, { fontSize, artStyle, options }?: AsciifySimpleOptions): Promise<() => void>;
164
243
 
165
244
  interface WaveBackgroundOptions {
166
245
  /** Font size in CSS pixels (default: 13) */
@@ -711,66 +790,108 @@ declare function renderTextBackground(ctx: CanvasRenderingContext2D, width: numb
711
790
  intensity?: number;
712
791
  } | null): void;
713
792
 
714
- /**
715
- * record() — capture a rolling frame buffer from a running ASCII canvas
716
- * and export it as a downloadable animated GIF or WebP data URL.
717
- *
718
- * Usage:
719
- * ```ts
720
- * const recorder = createRecorder(canvasEl, { fps: 15, maxFrames: 120 });
721
- * recorder.start();
722
- * // ... after a few seconds ...
723
- * const dataUrl = await recorder.stop(); // 'data:image/gif;base64,...'
724
- * ```
725
- */
726
- interface RecorderOptions {
727
- /** Target capture frame rate (default: 15) */
728
- fps?: number;
729
- /** Maximum number of frames to buffer (default: 120 → 8 s at 15 fps) */
730
- maxFrames?: number;
731
- /**
732
- * Output format.
733
- * - 'gif' — animated GIF via gif.js worker (requires gif.worker.js in public/)
734
- * - 'webp' — animated WebP via MediaRecorder API (Chrome/Edge only)
735
- * - 'png-sequence' — returns a JSON array of PNG data URLs (universal)
736
- * Default: 'gif'
737
- */
738
- format?: 'gif' | 'webp' | 'png-sequence';
739
- /** GIF quality 1 (best) – 30 (smallest) — only used for format:'gif' (default: 10) */
793
+ interface SnapshotOptions {
794
+ /**
795
+ * Image format.
796
+ * - 'png' — lossless (default)
797
+ * - 'jpeg' — smaller, no transparency
798
+ * - 'webp' — best compression with transparency
799
+ */
800
+ format?: 'png' | 'jpeg' | 'webp';
801
+ /** 0–1 quality for jpeg/webp. Default: 0.92 */
740
802
  quality?: number;
741
803
  /**
742
- * Scale factor applied to the canvas before capture (default: 1).
743
- * Use 0.5 to halve dimensions and reduce file size.
804
+ * Scale factor applied before capture. Default: 1.
805
+ * Use 2 for a high-resolution export at the canvas size.
744
806
  */
745
807
  scale?: number;
746
808
  }
747
- interface Recorder {
748
- /** Start capturing frames from the canvas. */
749
- start(): void;
750
- /**
751
- * Stop capturing and encode.
752
- * Resolves with a data URL (gif/webp) or JSON string (png-sequence).
753
- */
754
- stop(): Promise<string>;
755
- /** True while recording. */
756
- readonly isRecording: boolean;
757
- /** Number of frames captured so far. */
758
- readonly frameCount: number;
759
- }
760
809
  /**
761
- * Create a Recorder bound to a canvas element.
810
+ * Capture a single frame from a canvas as a Blob.
811
+ *
812
+ * @example
813
+ * ```ts
814
+ * const blob = await captureSnapshot(canvas);
815
+ * const url = URL.createObjectURL(blob);
816
+ * ```
762
817
  */
763
- declare function createRecorder(canvas: HTMLCanvasElement, options?: RecorderOptions): Recorder;
818
+ declare function captureSnapshot(canvas: HTMLCanvasElement, { format, quality, scale }?: SnapshotOptions): Promise<Blob>;
764
819
  /**
765
- * Convenience: record for a fixed duration and auto-download.
820
+ * Capture a single frame and immediately trigger a browser download.
766
821
  *
767
822
  * @example
768
823
  * ```ts
769
- * await recordAndDownload(canvasEl, 3000, { fps: 15, format: 'gif' });
824
+ * await snapshotAndDownload(canvas);
825
+ * await snapshotAndDownload(canvas, { format: 'jpeg', filename: 'my-art' });
770
826
  * ```
771
827
  */
772
- declare function recordAndDownload(canvas: HTMLCanvasElement, durationMs: number, options?: RecorderOptions & {
828
+ declare function snapshotAndDownload(canvas: HTMLCanvasElement, options?: SnapshotOptions & {
773
829
  filename?: string;
774
830
  }): Promise<void>;
775
831
 
776
- export { ART_STYLE_PRESETS, type AnimationStyle, type ArtStyle, type AsciiBackgroundOptions, type AsciiCell, type AsciiFrame, type AsciiOptions, type AsciiResult, type AsciifySimpleOptions, type AuroraBackgroundOptions, CHARSETS, type CharsetKey, type CircuitBackgroundOptions, type ColorMode, DEFAULT_OPTIONS, type DnaBackgroundOptions, type FireBackgroundOptions, type GridBackgroundOptions, HOVER_PRESETS, type HoverEffect, type HoverPreset, type MorphBackgroundOptions, type MountWaveOptions, type NoiseBackgroundOptions, PALETTE_THEMES, type PaletteTheme, type PulseBackgroundOptions, type RainBackgroundOptions, type Recorder, type RecorderOptions, type RenderMode, type SilkBackgroundOptions, type SourceType, type StarsBackgroundOptions, type TerrainBackgroundOptions, type TextBackgroundOptions, type VoidBackgroundOptions, type WaveBackgroundOptions, asciiBackground, asciiText, asciiTextAnsi, asciify, asciifyGif, asciifyVideo, buildTextFrame, createRecorder, gifToAsciiFrames, imageToAsciiFrame, mountWaveBackground, recordAndDownload, renderAuroraBackground, renderCircuitBackground, renderDnaBackground, renderFireBackground, renderFrameToCanvas, renderGridBackground, renderMorphBackground, renderNoiseBackground, renderPulseBackground, renderRainBackground, renderSilkBackground, renderStarsBackground, renderTerrainBackground, renderTextBackground, renderVoidBackground, renderWaveBackground, videoToAsciiFrames };
832
+ /**
833
+ * asciifyWebcam — live webcam → ASCII art on canvas.
834
+ *
835
+ * Requests camera access, attaches the stream to a hidden video element, and
836
+ * runs a rAF loop that converts each frame to ASCII and renders it onto a
837
+ * supplied canvas.
838
+ *
839
+ * @example
840
+ * const stop = await asciifyWebcam(canvas);
841
+ * // later: stop();
842
+ *
843
+ * @example
844
+ * const stop = await asciifyWebcam(canvas, {
845
+ * fontSize: 8,
846
+ * style: 'terminal',
847
+ * mirror: true, // horizontal flip (selfie mode)
848
+ * constraints: { facingMode: 'user' },
849
+ * });
850
+ */
851
+
852
+ interface WebcamOptions {
853
+ /** Character size in pixels. Default: 10 */
854
+ fontSize?: number;
855
+ /** Art style preset. Default: 'classic' */
856
+ style?: ArtStyle;
857
+ /** Extra AsciiOptions merged on top of the preset */
858
+ options?: Partial<AsciiOptions>;
859
+ /**
860
+ * Called every frame to get the latest options. Takes priority over `options`.
861
+ * Use this to keep the rendering in sync with live UI controls without
862
+ * restarting the camera.
863
+ *
864
+ * @example
865
+ * const optionsRef = useRef(currentOptions);
866
+ * optionsRef.current = currentOptions;
867
+ * asciifyWebcam(canvas, { liveOptions: () => optionsRef.current });
868
+ */
869
+ liveOptions?: () => Partial<AsciiOptions>;
870
+ /**
871
+ * Flip the output horizontally so it reads like a mirror / selfie camera.
872
+ * Default: true
873
+ */
874
+ mirror?: boolean;
875
+ /**
876
+ * Passed directly to `getUserMedia({ video: constraints })`.
877
+ * Defaults to `{ facingMode: 'user' }`.
878
+ */
879
+ constraints?: MediaTrackConstraints;
880
+ /**
881
+ * Device pixel ratio used to compute logical render dimensions from the
882
+ * canvas's physical pixel size. Defaults to `window.devicePixelRatio ?? 1`.
883
+ * Set this when you size the canvas at physical resolution (e.g. width × dpr)
884
+ * so that ASCII column/row counts are based on CSS pixels, not physical ones.
885
+ */
886
+ dpr?: number;
887
+ }
888
+ /**
889
+ * Start a live webcam ASCII-art loop and render it onto `canvas`.
890
+ * Returns a `stop()` function that cancels the loop and releases the camera.
891
+ *
892
+ * Throws if the browser doesn't support `getUserMedia` or the user denies
893
+ * camera permission.
894
+ */
895
+ declare function asciifyWebcam(canvas: HTMLCanvasElement, { fontSize, style, options, liveOptions, mirror, constraints, dpr: dprOverride, }?: WebcamOptions): Promise<() => void>;
896
+
897
+ export { ART_STYLE_PRESETS, type AnimationStyle, type ArtStyle, type AsciiBackgroundOptions, type AsciiCell, type AsciiFrame, type AsciiOptions, type AsciiResult, type AsciifySimpleOptions, type AuroraBackgroundOptions, CHARSETS, type CharsetKey, type CircuitBackgroundOptions, type ColorMode, DEFAULT_OPTIONS, type DnaBackgroundOptions, type FireBackgroundOptions, type GridBackgroundOptions, HOVER_PRESETS, type HoverEffect, type HoverPreset, type MorphBackgroundOptions, type MountWaveOptions, type NoiseBackgroundOptions, PALETTE_THEMES, type PaletteTheme, type PulseBackgroundOptions, type RainBackgroundOptions, type RenderMode, type SilkBackgroundOptions, type SnapshotOptions, type SourceType, type StarsBackgroundOptions, type TerrainBackgroundOptions, type TextBackgroundOptions, type VoidBackgroundOptions, type WaveBackgroundOptions, type WebcamOptions, asciiBackground, asciiText, asciiTextAnsi, asciify, asciifyGif, asciifyVideo, asciifyWebcam, buildTextFrame, captureSnapshot, gifToAsciiFrames, imageToAsciiFrame, mountWaveBackground, renderAuroraBackground, renderCircuitBackground, renderDnaBackground, renderFireBackground, renderFrameToCanvas, renderGridBackground, renderMorphBackground, renderNoiseBackground, renderPulseBackground, renderRainBackground, renderSilkBackground, renderStarsBackground, renderTerrainBackground, renderTextBackground, renderVoidBackground, renderWaveBackground, snapshotAndDownload, videoToAsciiFrames };