Content
# Showreel
**Turn a URL + CSS selectors into a finished visual — annotated screenshots, flow GIFs, cinematic recordings and terminal captures. One command each. The agent never guesses pixels; every output is pixel-verified before it's saved.**
[](https://github.com/HeyRenan/showreel/actions/workflows/ci.yml)
[](showreel/.claude-plugin/plugin.json)
[](LICENSE)
[](https://claude.com/claude-code)
[English](README.md) · [Português](README.pt-BR.md)
## Showcase
[](assets/showcase.mp4)
*One take, every feature — drawer, camera, loupe, spotlight, live blur, typed form, region pick, live legend panel, one-click deploy. Generated entirely by the plugin against the bundled demo page. ([click to play the full MP4](assets/showcase.mp4))*
> Every image in this README was generated by Showreel itself, against the bundled "Lumen" demo page. Run the same commands, get the same files.
## What it is
A [Claude Code](https://claude.com/claude-code) plugin for **visual documentation**: explaining a change, a bug, a feature or a tutorial step with a picture instead of a paragraph.
You point it at a page and name elements by **CSS selector**. Showreel measures the DOM, draws the annotation exactly on target, and **validates the result before exit** — a bad capture is an error, never a shipped file. No screenshot → eyeball → retry loop, no pixel coordinates, no tokens burned guessing.
- **Self-contained** — bundles its own headless Chromium; no browser MCP, no credentials, nothing sent anywhere.
- **Deterministic** — same selectors in, same pixels out. Placement is computed, not guessed.
- **Cheap** — `--batch` renders many captures in one browser launch.
## Quick start
```bash
# install
claude plugin marketplace add HeyRenan/showreel
claude plugin install showreel@showreel
# one-time: check the machine + pre-warm the motor (~90MB Chromium, once)
bash ~/.claude/plugins/showreel/showreel/scripts/preflight.sh
node ~/.claude/plugins/showreel/showreel/scripts/ensure-deps.mjs
```
Restart Claude Code, then invoke **`/showreel`** and describe what to capture. Or run a script directly:
```bash
# annotate one element, self-validated
node scripts/prove.mjs https://example.com ".cards .card:first-child" out.png --label "Service card verified"
```
`/showreel:guide` opens a visual setup guide. Local-folder install and full paths in [INSTALL.md](INSTALL.md).
## What it can do
Every capability, one command each. All scripts live in `showreel/scripts/`. The agent always speaks in **selectors + text**, never pixels.
| Capability | Script | What you get |
|---|---|---|
| **Annotated proof** | `prove.mjs` | DOM-exact rectangle + callout + arrow, pixel-verified (`vcheck`) — exits 0 only on PASS. Flags: `--circle`, `--blur "<sel>"`, `--zoom`, `--batch jobs.json`. |
| **Annotation primitives** | `demo.mjs` | One concept per image: `rect`, `circle`, `arrow`, `badge`, `blur`, `zoom`, `callout`, `label`. `--batch` = 8 captures in one launch. |
| **Flow recording** | `rec.mjs` | Narrated GIF/MP4 from JSON steps — cursor motion, ripples, scrolling, narration modals, step stamps. The hero GIF above is one call. |
| **Cinematic camera** | `rec.mjs` | Real viewport move: page glides + scales under an animated transform. `camera` frames an element, `follow` chases the cursor, `inset` is a magnifier loupe. |
| **Spotlight / slow-mo / auto-annotate** | `rec.mjs` | `spotlight` dims all but the target; per-step `speed` slows an animation; `--auto-annotate` outlines a bare `click`/`fill` for free. |
| **Live elements** | `rec.mjs` | A `glossary`/`modal` with an `id` becomes **live** — later `live` steps append/update/recolor/replace/remove rows in place, no rebuild, no blink. Per-item colors, theme-matched text. |
| **Offline render** | `rec.mjs --offline` | Renders on the page's virtual clock — reading dwells collapse, text-heavy takes finish in a fraction of the time. Best for static/text takes; motion bursts (`confetti`, `sparkline`) require a realtime take. |
| **Terminal recording** | `tape.mjs` | CLI proof via [vhs](https://github.com/charmbracelet/vhs): JSON steps → `.tape` → GIF. The preflight GIF below is one call. |
| **Before/after compare** | `compose.mjs`, `lh-ba.sh` | Two PNGs or two GIFs side by side with labels. `lh-ba.sh` runs real Lighthouse on both branches. |
| **Size optimizer** | `shrink.mjs` | Re-encodes gif/png with no visible quality loss; `--target-kb` walks a quality ladder. Every image here went through it. |
| **Tight crop** | `shot.mjs` | Just the element, no annotation. |
### Recording: how steps work
`rec.mjs` takes JSON steps — each names an element and what to do. The script owns all the motion.
```bash
node scripts/rec.mjs <url> --steps-json '[
{"click":"#menu","note":"Drawer opens","badge":1,"screen":"Dashboard"},
{"scrollTo":".cards","rect":true,"glide":true,"note":"Active services","badge":2},
{"fill":"#email","text":"dana@example.com"},
{"camera":{"sel":".kpis","zoom":1.3},"note":"Framing the KPIs"},
{"click":"#deploy","follow":1.6,"note":"Camera chases the cursor"}
]' out.gif
```
**56 step keys** (unknown keys rejected up front):
- **actions** — `click, fill, text, select, option, scrollTo, scrollIn, to, hide`
- **annotation** — `note, arrow, badge, rect, circle, marks, glossary, inset, modal`
- **camera / motion** — `camera, zoom, follow, glide, speed`
- **emphasis** — `spotlight, blur, redact, highlight, pulse, ripple, shake, glow, flash`
- **state / data** — `checkmark, typeon, reveal, orbit, kenburns, progress, countdown, countup, sparkline, confetti, trail`
- **live** — `live` (mutate a `glossary`/`modal` in place across steps — append/update/recolor/replace/remove)
- **chrome / timing** — `screen, topbar, bottombar, wait, delay, fade, stagger, accent`
- **per-effect knobs** — `size, dur, count, intensity`
**Author fast:** `--dry` resolves every selector against the live page in <1s (`[ok]`/`[MISS]` per step, no recording) — fix misses, record once. `--pace fast` trims holds ~45% for drafts. `--contact-sheet` writes a tile of ~24 frames so the take reviews itself.
### See each one
Every feature, demonstrated — each image generated by the plugin against the demo page.
| | | |
|:---:|:---:|:---:|
|  |  |  |
| **prove** — annotated proof | **camera** — viewport move | **marks** — sub-badges |
|  |  |  |
| **modal** — narration | **bars** — top/bottom context | **spotlight** — dim all but target |
|  |  |  |
| **speed** — per-step slow-mo | **auto-annotate** — free outline | **stamp** — step counter |
|  |  |  |
| **fill** — typed input | **select** — dropdown pick | **inset** — magnifier loupe |
|  |  |  |
| **glossary** — badge legend panel | **hide** — drop an element | **glide** — animated scroll |
|  |  |  |
| **compose** — before/after (motion) | **tape** — terminal capture | **compose** — before/after (static) |
**Live elements & state** — a panel that grows in place, plus the full motion/state kit:
| | | |
|:---:|:---:|:---:|
|  |  |  |
| **live** — append rows in place | **confetti** — celebrate a success | **countup** — roll a number up |
|  |  |  |
| **sparkline** — draw a trend | **progress** — rollout bar | **countdown** — ticking pre-action |
|  |  |  |
| **pulse** — attention ring | **ripple** — tap feedback | **glow** — active emphasis |
|  |  |  |
| **checkmark** — stage done | **reveal** — new content enters | **flash** — status blink |
|  |  |  |
| **orbit** — working spinner | **trail** — A→B connector | **shake** — blocked/error |
|  |  |  |
| **typeon** — streaming text | **kenburns** — slow zoom | **redact** — hide sensitive data |
|  | | |
| **highlight** — marker swipe | | |
### Annotation primitives (`demo.mjs`)
Eight callout styles, one concept per image — all eight from a single `demo --batch` launch:
| | | | |
|:---:|:---:|:---:|:---:|
|  |  |  |  |
| **rect** | **circle** | **arrow** | **badge** |
|  |  |  |  |
| **blur** | **zoom** | **callout** | **label** |
## Why it's fast
Measured on this codebase (Apple Silicon, warm motor):
| | Naive | Showreel |
|---|---|---|
| 8 annotated captures | 8 browser launches ≈ 60 s | `demo --batch` ≈ **6 s**, one launch |
| Annotation placement | read PNG → guess pixels → retry | deterministic `autoplace`, **0 retries** |
| Contrast on dark/light pages | manual color picking | **adaptive** from page luminance |
| Overlapping annotations | manual nudging | **collision-aware**, never covers the target |
## How it works
The agent sends selectors + text. The motor (self-contained Chromium in `scripts/.deps/`) measures the DOM, places every annotation deterministically (`lib/autoplace.mjs`), and self-validates (`vcheck`) before saving — so there's no guess/retry loop. Web captures run through Chromium; terminal captures through `vhs`. `rec.mjs` is modular: single-responsibility modules (`rec-steps`, `cam-inject`, `rec-camera`, `rec-motion`, `rec-annotate`, `rec-input`, `rec-encode`, `rec-page`) over one `clock` that makes realtime and offline two implementations of the same time contract.
## Requirements
node 18+. Optional: `ffmpeg` (best GIF quality), `vhs` (terminal recordings). No git, no tokens, nothing to configure. `preflight.sh` prints exact setup commands for anything missing. Full matrix in [INSTALL.md](INSTALL.md), version history in [CHANGELOG.md](CHANGELOG.md).
## Tests
```bash
cd showreel && node --test 'scripts/__tests__/*.test.mjs' # no network or browser
```
## License
[MIT](LICENSE)
Connection Info
You Might Also Like
No recommendations available