# Komadori: a 10 second 1080p clip of a million boids in 11-14 seconds

**Komadori** (コマ撮り, "stop-motion") makes a 10 s 1080p clip of a million boids in 11-14 s, on a laptop GPU. You can't watch a canvas run from a terminal, and neither can your agent. Komadori runs the page in Chrome one frame at a time and hands back what it drew: a clip, a contact sheet (one image of sampled frames) and a report.

A flock of a million boids drawn by spryte, as a clip made by Komadori.

*The clip is spryte's million-boid demo, made by Komadori with `--capture canvas`. This copy is 720p.*

| Machine | A screenshot per frame | `--capture canvas` | Faster by |
| --- | --- | --- | --- |
| Radeon 780M (integrated) | 35.0 s | 13.5 s | 2.6x |
| RTX 5060 laptop | 37.6 s | 11.2 s | 3.4x |

600 frames at 1920x1080, in Chrome on Windows 11. Earlier runs gave 3.0x and 3.6x, so "about 3x" is what holds. [The measurements](https://github.com/debuffjp/komadori/blob/master/bench/capture/README.md) include the runs that didn't agree.

```bash
npx komadori dist --query "capture=1" --frames 600 --size 1920x1080 --mp4 clip.mp4 --capture canvas
```

`dist` is a built page or a URL. Komadori needs Node 20, Chrome or Chromium, and ffmpeg for `--mp4`. The page defines one function, `window.__frame()`, that advances the scene by exactly one frame and draws it. [The guide](/komadori/) shows how.

## Why it's fast

Every way of taking a screenshot of a page per frame ran at about 18 frames a second on both machines, so a faster screenshot call doesn't help. `--capture canvas` encodes the canvas to H.264 inside the page with WebCodecs and pipes it to ffmpeg. That runs close to the speed of the simulation itself: a million boids stepped on the CPU, 58 to 80 frames a second with no capture at all. That is why a 10 s clip takes about 10 s to make.

## What else it does

- **Checks every frame.** A run fails when the page throws, a request fails, a shader doesn't compile or every sampled frame is one flat colour. A shader error names the line of your source, the compiler's message and the line itself.
- **Golden frames.** `approve` saves frames only if two renders agree. Later runs fail on a mismatch, and Komadori writes the saved frame, the new frame and the difference side by side. The limits for comparing across GPUs come from measurements on a Radeon 780M, an RTX 5060 laptop and Vulkan SwiftShader. spryte's CI uses them.
- **An MCP server.** `komadori mcp` has three tools: `render`, `look` (one frame, full size or zoomed) and `diff`.

## What this doesn't show

- It isn't shown to help agents. On four small tasks, Sonnet did as well without rendering anything ([the runs and costs](https://github.com/debuffjp/komadori/blob/master/bench/eval/README.md)).
- It runs in Chrome. It has been tested on Windows, and the golden frames check also runs on a Linux runner.
- A clip holds only the canvas, so a title drawn in HTML over it is missing.
- It checks what was drawn, not whether it looks good. It can't see stripes or unreadable text. Open the contact sheet and look.

Komadori was built for [spryte](/spryte/) scenes and works with any page that draws on a canvas. The source is on [GitHub](https://github.com/debuffjp/komadori) and the package is on [npm](https://www.npmjs.com/package/komadori).

```bash
npx komadori dist --frames 600 --size 1920x1080 --out render --mp4 render/clip.mp4
```