Video via ffmpeg
Render time-stepped raw RGBA frames into an MP4.

For real video — high frame rate, MP4, audio later — renderAnimation() doesn't fit. Instead, loop over time with render(..., { format: "raw", timeMs }) and pipe each frame's raw RGBA bytes straight to ffmpeg's stdin. Render and write one frame at a time so memory stays bounded no matter how long the clip is.
import { render } from "takumi-js";
import { spawn } from "bun";
const fps = 30;
const durationSeconds = 4;
const totalFrames = fps * durationSeconds;
const width = 1200;
const height = 630;
const ffmpeg = spawn(
[
"ffmpeg",
"-y",
"-f",
"rawvideo",
"-pixel_format",
"rgba",
"-video_size",
`${width}x${height}`,
"-framerate",
`${fps}`,
"-i",
"pipe:0",
"-vf",
"format=yuv420p",
"-c:v",
"libx264",
"-crf",
"18",
"output.mp4",
],
{ stdin: "pipe" },
);
const scene = <Scene />;
for (let i = 0; i < totalFrames; i++) {
const frame = await render(scene, {
width,
height,
format: "raw",
timeMs: (i / fps) * 1000,
});
ffmpeg.stdin.write(frame);
}
ffmpeg.stdin.end();
await ffmpeg.exited;Source:
example/ffmpeg-keyframe-animation
— full Scene with shiki tokens, keyframe definitions, and ffplay variant.
Edit on GitHub
Last updated on