skill
kamishibai
Turn a web page into a video — every frame a pure function of its time, so capture is reproducible and parallel.
Set up
Skills are installed by placing their folder where your agent loads skills.
The download comes from github.com/reearth/kamishibai itself, not from our server, so what you get is exactly what its author published.
Install instructions come from the README
README
synced Oct 25, 2026kamishibai
Turn any web page into a video. kamishibai only seeks the page to each moment and captures it. A mechanism, not a framework. How you draw — React, plain DOM, canvas, WebGL — is up to you.
Rendered by kamishibai from site/demo/reel.ts: plain DOM, the one contract, and the Lexicon's drawings. (full mp4)
- 🧩 Minimal. One contract: the page exposes
window.kamishibai = { meta, seek }. No framework to adopt, no editor. - 🎨 Draw it any way. React, plain DOM, canvas, three.js: anything a browser can show. The React helpers are optional.
- ⚡ Edit, then render only what changed.
--incrementalcaptures again only the frames an edit touched. After one heading edit in an 86-second reel, it rendered again in 25 s, where Remotion took 48 s and HyperFrames 51 s (benchmarks). - 🔁 Reproducible and parallel. In a pinned environment, any order of frames gives the same video, so the frames are captured on several pages at once.
- 🔊 Sound included. Audio clips, background music with ducking, TTS narration and frame-accurate video clips.
- 🤖 Made for agents. The usage guide ships in the package (
npx kamishibai skill), with agent skills to point to it. - 🆓 MIT. Free for any use, by anyone, companies of any size included.
kamishibai turns any web page (DOM, canvas, anything) into a video by seeking to each moment and capturing a still, then assembling the stills with ffmpeg. Because every frame is a pure function of its time, capture is reproducible — in a pinned environment, any order of frames gives the same video — and trivially parallelisable across several pages of a headless Chrome.
It deliberately does not try to be a frame-accurate compositing engine or ship an editor. It gives you the renderer and one tiny contract; the rest is yours.
Website: reearth.github.io/kamishibai · Lexicon of motion, from camera moves and cuts to type, texture and generative art, each with a loop and words to hand an agent.
Quick start
npm i kamishibai react react-dom # react / react-dom are peer deps
npx playwright install chromium # the headless browser that captures frames
# plus ffmpeg on your PATH (not bundled) — e.g. `brew install ffmpeg`
Write a reel.tsx — a page that draws "the state at time ms". With the optional React sugar that's just a component plus mount:
import { mount, useClock, ramp, eases } from "kamishibai/react";
const Reel = () => {
const { ms } = useClock(); // current time, in milliseconds
const x = ramp(ms, 0, 1000, 0, 400, eases.smooth); // map a time window onto a value
return (
<div style={{ font: "700 96px system-ui", transform: `translateX(${x}px)` }}>
hello
</div>
);
};
// mount() renders the tree AND exposes window.kamishibai for the renderer.
mount(<Reel />, { fps: 30, durationMs: 3000, width: 1280, height: 720 });
Watch it while you edit, then render it:
npx kamishibai dev reel.tsx # a player that reloads on save
npx kamishibai render reel.tsx -o reel.mp4
There's no GUI editor; you're the editor. The loop is edit → look → render: the dev player shows the reel as you save, and a render writes the frames you can inspect one by one.
Requirements: Node.js ≥ 20 · ffmpeg on PATH (not bundled) · a Chromium for Playwright (npx playwright install chromium).
Kinds of reel
A reel is the thing kamishibai turns into a video. It comes in three kinds:
| What you write | Drawn by | Write one when | |
|---|---|---|---|
| Page | a web page that sets window.kamishibai: React, plain DOM, canvas, WebGL | headless Chrome | you want anything a browser can show. The default |
| Canvas | a module that paints each frame on a 2D canvas | Skia on the CPU, no browser | it must render with no browser. One reel lays itself out as 16:9 and as 9:16 |
| Kit | scenes as data, in YAML, JSON or code: titles, cards, flows, numbers | the kit, as a canvas reel | you want many videos fast. Parts move from scene to scene, and each scene is timed to its narration |
kamishibai export makes a reel of any kind one HTML file that plays with no server (more).
Agent skills
Building videos with an AI coding agent? Install the skill (as of October 2026 we recommend Claude Opus 5.5):
npx skills add reearth/kamishibai --skill kamishibai
# or
gh skills install reearth/kamishibai kamishibai
It points the agent at kamishibai skill, which prints the guide for the installed version. A program can take the same text from kamishibai/skill.
How it works
The one and only contract
A capturable page exposes exactly one global:
window.kamishibai = {
meta: { fps: 30, durationMs: 6000, width: 1920, height: 1080 },
// Build the still state for `ms` and resolve once the DOM has settled.
// Return false to mean "identical to the previous frame", or a fingerprint
// string for the frame's content (see below).
seek(ms: number): Promise<boolean | string | void> | boolean | string | void;
};
Whatever happens inside seek — a React re-render, ctx.clearRect + hand-drawing, a Konva layer.draw() — is entirely up to you. The renderer just calls seek(ms), screenshots, advances, and repeats. It never plays back in real time, so a slow frame takes longer but never drops, and in a pinned environment the output is reproducible (see Determinism & guarantees).
Parallel capture
A reel of N frames is cut into contiguous chunks of frame indices, and each chunk is captured by its own page in one headless Chrome. Since frame i depends only on its time, it doesn't matter which page renders which chunk:
frames 0–684 → page #1 ┐
frames 685–1369 → page #2 ├ run at once → PNG sequence → ffmpeg → mp4
frames 1370–… → page #3 ┘
seek can also say a frame is the same as the one before, by returning false or a fingerprint of its content. The renderer then copies the previous still instead of capturing it, and with --incremental it reuses frames from the last run whose fingerprint didn't change, so after an edit only the changed frames are captured again. kamishibai/react returns the fingerprint for you. See Skipping frames & incremental builds.
What's in the box
| React sugar | kamishibai/react: a clock, scenes back-to-back with crossfades, a camera over a world layer, positions along a path, easing and springs. Optional: any page that sets window.kamishibai works |
| Audio | declare files and start times; they're muxed after capture, with fades, loops and auto-ducking |
| Video | video clips decoded frame by frame with WebCodecs, so a clip is a pure function of time too |
| Subtitles | a soft track and a sidecar .srt by default, or burned into the pixels |
| Narration | text to speech once, before capture, content-hashed and cached, with scenes sized to each line. Kokoro (free, local), OpenAI, Google, Gemini, Polly, ElevenLabs, or macOS say |
| Live preview | kamishibai dev: play, scrub, a range to loop, sound or a storyboard, and which frames a render will capture |
| CLI | render, or its halves capture and encode, plus tts to bake narration |
| Library | the same from code: render, capture, encode and the building blocks under them |
All docs: docs/
Examples
examples/basics— a 6s reel showcasing thekamishibai/reactsugar: fade in/out, an eased progress meter + count-up, staggered reveals, and eased motion.examples/video— frame-accurate video via WebCodecs, both raw (index.ts) and React (react.tsx). The clip is an AV1-in-MP4 test pattern generated by ffmpeg (testsrc, synthetic — no copyright).examples/narration— TTS as a build pre-pass: synthesize the voice-over up front withsay, size each scene to its line withnarrationLayout, and add the text as captions.
pnpm build
node dist/cli.js render examples/basics/index.tsx -o basics.mp4 -w 4
node dist/cli.js render examples/video/react.tsx --public examples/video/public -o video.mp4 -w 4
node dist/cli.js render examples/narration/index.tsx -o narration.mp4 -w 4 # macOS `say`
Determinism & guarantees
kamishibai does not guarantee pixel-identical output across environments. It gives you the levers to make output stable, and the philosophy is to verify in CI rather than promise:
- Fonts are awaited (
document.fonts.ready) before the first capture, so text doesn't reflow mid-reel. - Pin Chromium via your Playwright version — emoji and sub-pixel rendering depend on the Chrome build.
- Keep
seek(ms)a pure function ofms(noDate.now(), no un-seeded randomness) so any Chrome renders any frame identically. - The worker count doesn't change the pixels. Each worker starts partway through the reel, so a frame must not depend on what its Chrome drew before. Before each screenshot the renderer drops the paint state Chrome keeps between frames, and
kamishibai/reactmakes the page paint exactly the values its fingerprint describes, so a run of copied frames starts from the same still however the reel is split.
The intended workflow: pin the environment, render in CI, and let a frame/checksum check fail loudly when something drifts.
License
MIT.
Name
紙芝居 (kamishibai) is a Japanese form of storytelling that advances a tale one picture at a time — precisely this tool's "show one still per moment" approach.