# ASCII Video

> Video files, streams or the webcam, converted every frame.

Category: Images. Docs: https://asciicn.sumak.dev/docs/ascii-video

## Installation

```bash
npx shadcn@latest add @asciicn/ascii-video
```

Needs the `@asciicn` registry in components.json: `"registries": { "@asciicn": "https://asciicn.sumak.dev/r/{name}.json" }`.

## Usage

```tsx
import { AsciiVideo } from "@/components/ascii/ascii-video"

<AsciiVideo src="/clips/surf.mp4" dither="bayer" />
<AsciiVideo src="webcam" aria-label="Your camera" />
```

## Props

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `src` | `string | MediaStream | "webcam"` |  | A URL, a stream, or the user's camera. |
| `mirror` | `boolean` | `webcam only` | Flip horizontally. |
| `onError` | `(error) => void` |  | Called when playback or camera access fails. |

Also accepts every `AsciiCanvas` prop:

| Prop | Type | Default | Description |
| --- | --- | --- | --- |
| `charset` | `CharsetName | string` | `"standard"` | Named ramp or your own string, empty to dense. "braille" packs 2×4 dots per cell, "quadrants" 2×2 blocks. |
| `fontSize` | `number` | `12` | Cell size in CSS pixels. Smaller means more detail. |
| `dither` | `"none" | "bayer" | "floyd"` | `"none"` | Quantisation. Floyd–Steinberg for photos, Bayer for a retro look. |
| `color` | `"ink" | "source" | string[]` | `"ink"` | Ink uses the CSS colour (theme with text-*). Source keeps pixel colours. An array maps tone onto gradient stops, e.g. palettes.thermal. |
| `edges` | `number` | `0` | Outline contours with | / - \ where the tone gradient beats this strength. Try 0.3. Ramps only. |
| `opacity` | `boolean` | `false` | Fade each glyph by its tone. |
| `brightness` | `number` | `0` | Added after contrast, -1 to 1. |
| `contrast` | `number` | `1` | Multiplier around mid grey. |
| `gamma` | `number` | `1` | Tone curve exponent. |
| `invert` | `boolean` | `false` | Swap ink and blank. |
| `animate` | `boolean` | `auto` | On for fields, frames and video. Off under reduced motion, except video. |
| `fps` | `number` | `30` | Frame cap. |
| `ref` | `Ref<AsciiHandle>` |  | Exposes text(), svg(), png() and the canvas. |

## Notes

- **Privacy.** Camera frames are drawn locally and never leave the browser. The stream stops when the component unmounts or `src` changes.
- **Accessibility.** Pass `aria-label` to say what the video shows. The underlying `<video>` is muted and never rendered.
- **Motion.** Video keeps playing under `prefers-reduced-motion`, since the user chose to start it. Drawing pauses offscreen.
- **Performance.** Each frame is sampled once onto the grid, so cost tracks the number of cells, not the video resolution.
