# Capture

Records a component out of the page: a snapshotter that bakes the cascade into a clone, a GIF89a encoder, and an animated-WebP muxer built on the browser's own encoder. No dependencies, no server, nothing uploaded.

> For the complete index, see [llms.txt](https://robocn.dev/llms.txt). A Markdown version of any page is available by appending `.md` to its URL or by sending an `Accept: text/markdown` header.

## Install

```bash
bunx --bun shadcn@latest add https://robocn.dev/r/robot-capture.json
```

Registry item: `robot-capture` · [`https://robocn.dev/r/robot-capture.json`](https://robocn.dev/r/robot-capture.json)

## Notes

- The snapshot resolves `var()` and `currentColor` off the live element, because a detached clone has no cascade: without it every export comes out in the fallback palette. Elements mid-keyframe have their computed transform and opacity copied too, so CSS animation lands in the recording.
- Recording is real time — the machines run on requestAnimationFrame, so a four-second capture takes four seconds and the tab has to stay in front.
- A `<canvas>` is read back with toDataURL and swapped into the clone as an image. WebGL needs `preserveDrawingBuffer`, which `robot-stage` sets.
- Cross-origin images and stylesheets cannot be inlined and are dropped rather than tainting the canvas. Notes: `docs/export.md`.
- The way out of the page is a callback, not a hard-coded download: pass `save` to `exportNode` and the blob goes wherever you send it. `docs/checkout.md` is the workbench writing one into a folder it is holding.

## Usage

```tsx
import { exportNode, record, encodeFrames, download } from "@/lib/robocn/capture"

// The whole path: record two seconds and save the file.
await exportNode(node, { format: "gif", name: "robot-arm", duration: 2, fps: 15 })

// Or keep the frames: they are canvases, so anything can have them.
const frames = await record(node, { duration: 2, fps: 20, scale: 2 })
download(await encodeFrames(frames, "webp"), "robot-arm.webp")
```

## API

| name | type | default | description |
| --- | --- | --- | --- |
| `exportNode` | `(target, options?) => Promise<ExportResult>` | — | Record a DOM node and save it. `format` is `webp`, `gif` or `png`; `duration` of 0 takes a still. Reports the file, the frame count and the pixel size. `save` replaces the browser download with anything that takes a blob and a name — a directory handle, an upload, a clipboard write. |
| `record` | `(target, options?) => Promise<Frame[]>` | — | Sample a node in real time into canvases, one a frame, each carrying the delay that was actually measured between it and the next. |
| `snapshot / rasterize` | `(target, options?) => Promise<Snapshot> / (snapshot, options?) => Promise<HTMLCanvasElement>` | — | The two halves of a frame: a standalone SVG document with the computed cascade baked in, and that document painted onto a canvas. |
| `encodeFrames` | `(frames, format, options?) => Promise<Blob>` | — | Frames to a file. One frame is a still; more than one is an animation. |
| `encodeGif` | `(frames, { width, height, loop }) => Uint8Array` | — | From `gif.ts`: GIF89a with median-cut quantization, a local colour table per frame and LZW. Transparency is a palette slot with disposal 2. |
| `muxAnimatedWebp` | `(frames, { width, height, loop }) => Uint8Array` | — | From `webp.ts`: re-houses single-image WebP files as `ANMF` frames under `VP8X`/`ANIM`. It never touches a pixel — the browser did the encoding. |
| `frameDelays / backgroundBehind / supportsWebp` | `helpers` | — | The measured deltas of a recording, the first opaque colour above a node, and whether this browser's canvas can write WebP at all. |

## Source

- `src/lib/robocn/capture.ts`
- `src/lib/robocn/gif.ts`
- `src/lib/robocn/webp.ts`
