@creately/rdm-video
v0.2.0
Published
Turn RDM diagrams into beat-synced, audio-reactive explainer videos — pixel-perfect browser capture with ffmpeg encoding
Readme
@creately/rdm-video
Turn RDM diagrams into beat-synced, audio-reactive explainer videos. Pixel-perfect browser capture — the video pipeline is a camera operator, not a renderer. Whatever the real canvas draws is what ends up in your MP4.
Install
bun add @creately/rdm-video
bunx playwright install chromiumYou also need ffmpeg on your PATH (or ffmpeg-static, which is an optional dep), and a compiled rdm-editor.iife.js bundle.
Quick start (library)
import { renderVideo, RenderVideoEmitter } from '@creately/rdm-video';
const events = new RenderVideoEmitter();
events.on('progress', ({ aspect, frame, totalFrames }) => {
process.stderr.write(`\r${aspect}: ${frame}/${totalFrames}`);
});
const result = await renderVideo({
rdmText: `---
type: orgchart
title: "My Team"
---
org T {
position ceo "Alice" { title: "CEO" }
position eng "Bob" { title: "Eng Lead" }
ceo -> eng
}`,
editorBundle: '/abs/path/to/rdm-editor.iife.js',
aspects: ['16x9', '9x16'],
preset: 'explainer',
outputDir: '/tmp/out',
events,
});
console.log(result.outputs['16x9']?.mp4Path);
// → /tmp/out/rdm-video-16x9.mp4Quick start (CLI)
# The editor bundle can be passed explicitly, via RDM_VIDEO_EDITOR_BUNDLE,
# or auto-discovered from cwd/sibling repos.
export RDM_VIDEO_EDITOR_BUNDLE=/abs/path/to/rdm-editor.iife.js
rdm-video my-diagram.rdm --preset explainer --aspect 16x9,9x16API
renderVideo(options)
interface RenderVideoOptions {
rdmText?: string; // RDM source (one of rdmText/rdmPath required)
rdmPath?: string; // File path sugar
editorBundle: string; // Absolute path to rdm-editor.iife.js (required)
preset?: string; // banger | explainer | doc | keynote | editorial | cinematic
template?: string;
aspects?: Aspect[]; // ['16x9'] | ['9x16'] | ['16x9','9x16','1x1']
fps?: number;
outputDir?: string;
outputName?: string;
config?: Partial<RenderConfig>; // music, bpm, splash, outro, brand, …
preview?: boolean; // Render 1-second preview instead of full video
dryRun?: boolean; // Compute timeline, skip render
events?: RenderVideoEmitter;
}Returns:
interface RenderVideoResult {
jobId: string;
outputs: Partial<Record<Aspect, {
mp4Path: string;
durationMs: number;
sizeBytes: number;
framesWritten: number;
}>>;
metadata: {
preset?: string;
template: string;
stepCount: number;
totalDurationMs: number;
renderedAt: string;
renderMs: number;
hasAudio: boolean;
};
warnings: string[];
}Events
Subscribe via a RenderVideoEmitter:
| Event | Payload |
|---|---|
| log | { level, prefix, message } |
| aspect-start | { aspect, width, height, totalFrames } |
| progress | { aspect, frame, totalFrames, phase } |
| aspect-complete | { aspect, outputPath, durationMs, sizeBytes } |
Errors
All API failures throw RdmVideoError with a structured code:
try {
await renderVideo({ ... });
} catch (err) {
if (err instanceof RdmVideoError) {
console.error(err.code, err.message, err.hint);
if (err.retryable) { /* retry */ }
}
}Error codes: INVALID_INPUT, RDM_PARSE_ERROR, PRESET_UNKNOWN, PRESET_VALIDATION_FAILED, EDITOR_BUNDLE_MISSING, BROWSER_LAUNCH_FAILED, ENCODER_FAILED, MUSIC_NOT_FOUND, TIMELINE_EMPTY.
Multi-aspect rendering
Passing aspects: ['16x9', '9x16', '1x1'] renders all three from a single renderVideo() call. The browser launches once and each aspect is captured in a fresh Playwright context. Wall time is dominated by the first launch (~3s) plus per-aspect context mount (~1s), not full browser restarts.
Presets
import { listPresets, loadPreset } from '@creately/rdm-video';
console.log(listPresets());
// [{ name: 'banger', description: '...', ... }, ...]Merge order (lower overrides higher):
- Library defaults (
DEFAULT_CONFIG) - Preset config (
--preset) - Sidecar file (
<name>.video.jsonnext to<name>.rdm) - Explicit
configin options / CLI flags
Editor bundle
The pipeline runs the real Creately canvas inside headless Chromium. To do that it needs the compiled rdm-editor.iife.js. Build it from creately-ai (bun run build:rdm-editor) and pass its path via editorBundle (or RDM_VIDEO_EDITOR_BUNDLE env var for the CLI).
License
MIT
