Composition Runtimes
OpenMontage dispatches video composition through the video_compose tool using one of three engines. The chosen runtime is locked at the proposal stage in proposal_packet.production_plan.render_runtime, carried verbatim into edit_decisions.render_runtime, and enforced at render time. Silent swaps are blocked by the tool and flagged during review.
See the Tool System for the video_compose contract and the Pipeline System for how proposal and edit stages produce these artifacts.
The Three Runtimes
| Runtime | Engine | Primary Use Cases | Requirements |
|---|---|---|---|
remotion |
React + Remotion 4 | Data-driven explainers, text/stat cards, charts, spring-animated scenes, TalkingHead, CinematicRenderer, word-level captions | Node.js 18+, remotion-composer/ installed |
hyperframes |
HTML/CSS/GSAP (via npx) | Kinetic typography, product promos, launch reels, SVG/GSAP character rigs, website-to-video | Node.js ≥ 22, FFmpeg, npx |
ffmpeg |
FFmpeg CLI | Pure concat/trim, subtitle burn-in | FFmpeg binary (always present) |
Remotion
Remotion lives in the standalone remotion-composer/ subproject (React 18 + Remotion 4.0 + TypeScript). It renders component-based scenes such as text_card, stat_card, bar/line/pie charts, and animated image sequences with spring physics. video_compose routes to _remotion_render when edit_decisions.render_runtime is set to remotion.
HyperFrames
HyperFrames is invoked via npx hyperframes (no monorepo checkout). The driver tools/video/hyperframes_compose.py materializes a workspace under projects/<name>/hyperframes/, runs lint → validate → render, and outputs renders/final.mp4. It is the default for motion-graphics-heavy briefs and the character-animation pipeline's rigged SVG characters. video_compose routes to _render_via_hyperframes for this runtime.
FFmpeg
FFmpeg handles simple cuts and post-hoc operations such as subtitle burn-in. It is the fallback when no composition engine is required. video_compose routes to _render_via_ffmpeg when edit_decisions.render_runtime is ffmpeg.
video_compose.get_info() reports live availability:
"render_engines": {
"ffmpeg": true,
"remotion": <bool>,
"hyperframes": <bool>
}
Routing Logic
video_compose.execute({"operation": "render", ...}) (or the legacy compose operation) reads the locked render_runtime value from edit_decisions and dispatches accordingly. The tool returns a structured blocker if the locked runtime is unavailable. Runtime swaps are never performed silently; the agent must obtain explicit approval and log the decision before changing the value.
Locking at Proposal
The runtime is selected and locked during the proposal stage. It is recorded in proposal_packet.production_plan.render_runtime together with renderer_family and delivery_promise. The value is copied unchanged into edit_decisions.render_runtime and must match at compose time. schemas/artifacts/edit_decisions.schema.json and proposal_packet.schema.json enforce the enum ["remotion", "hyperframes", "ffmpeg"].
When both Remotion and HyperFrames are available, the agent must present both options before locking: a one-sentence description of what each is best at for the brief, an honest tradeoff, and a recommendation tied to the delivery_promise. The full shortlist is recorded as options_considered in a render_runtime_selection entry in decision_log.json.
Governance Rules
render_runtimeis locked at proposal and must not change without a logged decision.- Motion-required deliveries (
delivery_promise.motion_required: true) forbid still-image or FFmpeg-only fallbacks that alter the approved character of the deliverable. composition_validatorand final review compareproposal_packetandedit_decisions; mismatches are reported asruntime_swap_detected.- If only one runtime is present, the agent must state it explicitly and record the unavailable option as
rejected_because: "runtime not available on this machine".
See Architecture for the high-level flow and Running Pipelines for how checkpoints carry the locked runtime forward.