Millisecond-accurate non-linear editing timeline (Timeline, TimelineClip) across 6 track types (Video, BRoll, Voiceover, Music, SoundEffects, Subtitles) with validate_primary_video_overlaps().
openmontage-rs is a pure Rust programmatic video production engine designed for both human editors and autonomous AI agents. It compiles declarative JSON/YAML storyboards, automated B-roll placement, and kinetic typography into frame-accurate multi-track video masters.
$ cargo install openmontage-rs
Timeline + PacingValidator + PipelineRegistry + CostTracker
Millisecond-accurate non-linear editing timeline (Timeline, TimelineClip) across 6 track types (Video, BRoll, Voiceover, Music, SoundEffects, Subtitles) with validate_primary_video_overlaps().
Analyzes sequences of Shot definitions across 8 ShotType framings and 9 CameraMotion trajectories, computing average cut length, short/long cut counts, consecutive static slideshow risk, and framing variety score.
Built-in and YAML-configurable production pipelines (cinematic, animated-explainer, avatar-spokesperson) with per-stage required inputs, artifacts, automated verification gates, and cost estimates.
Broadcast audio stem mixer (AudioMixer::mix_tracks) with a 100 ms sliding-window voiceover activity detector that attenuates music stems by ducking_db (-12.0 dB) and normalizes the master to -16.0 LUFS with soft-knee limiting.
Tracks LLM tokens, video diffusion seconds, and TTS character spend across providers (CostTracker, CostRecord, CostSummary) with real-time budget overrun gates.
Serializes and loads reproducible ProductionManifest playbooks and RenderedAsset inventories to pretty-printed JSON.
Strongly-typed ProductionConfig and AspectRatio (16:9 Landscape, 9:16 Portrait, 1:1 Square) resolution calculators.
The openmontage command-line interface supporting plan, render, pipelines, validate, cost, and bench.
| Subsystem / Kernel | Rust Module | Workload | openmontage-rs (Rust) | Reference Python Pipeline | Speedup & Engineering Advantage |
|---|---|---|---|---|---|
| NLE Timeline Validation | timeline::Timeline | 1,000 clips primary video overlap check | 48.0 µs | 1.82 ms (moviepy) |
37.9x faster + Zero-copy slice sort |
| Pipeline DAG Deserialization | pipeline::PipelineRegistry | 4-stage YAML pipeline & stage-gate parse | 62.0 µs | 2.15 ms (PyYAML) |
34.7x faster + Strongly-typed stage gates |
| Shotlist Pacing & Variety | shot::PacingValidator | 500 shots slideshow-risk & framing variety | 14.2 µs | 490.0 µs (Python validator) | 34.5x faster + O(N) single-pass scan |
| Manifest & Cost Ledger | manifest + cost | Playbook JSON + multi-provider cost summary | 19.0 µs | 610.0 µs (Python JSON) | 32.1x faster + Deterministic budget gate |
| 44.1 kHz Audio Ducking + LUFS | audio::AudioMixer | 60s @ 44.1kHz 100ms window ducking + -16 LUFS |
1.84 ms | 58.40 ms (pydub + numpy) |
31.7x faster + Soft-knee tanh limiter |
# Clone and run all workspace unit & integration tests git clone https://github.com/bhubbard/openmontage-rs.git cd openmontage-rs cargo test --workspace --release # 1. Inspect available production pipelines and stage gates cargo run --release -p openmontage-cli -- pipelines # 2. Generate a cinematic production playbook with a $10 budget cap cargo run --release -p openmontage-cli -- plan \ --script "Autonomous Rust Video Engine" \ --pipeline cinematic --budget 10.0 --output playbook.json # 3. Run the 500-clip NLE timeline & 44.1 kHz audio mixing benchmark cargo run --release -p openmontage-cli -- bench --clips 500 --sample-rate 44100
use openmontage_core::{
AudioMixConfig, AudioMixer, CameraMotion, PacingValidator, Shot, ShotType,
Timeline, TimelineClip, TrackType,
};
fn main() {
// 1. Assemble a non-overlapping primary video timeline
let mut tl = Timeline::new("Launch Reel", 30.0);
tl.add_clip(TimelineClip {
id: "shot_1".into(),
track_type: TrackType::Video,
source_path: "intro.mp4".into(),
in_point_ms: 0,
out_point_ms: 3500,
timeline_start_ms: 0,
volume: 1.0,
opacity: 1.0,
});
assert!(tl.validate_primary_video_overlaps());
// 2. Validate camera motion pacing & framing variety
let shots = vec![Shot {
id: "s1".into(),
shot_type: ShotType::AerialDrone,
motion: CameraMotion::Orbit,
description: "Establishing shot".into(),
duration_seconds: 3.5,
visual_prompt: "Aerial sunrise".into(),
}];
let report = PacingValidator::analyze(&shots);
assert!(!report.slideshow_risk);
}