Skip to content

Video export — in-browser render to MP4/WebM/MP3 - #41

Merged
cbaucom merged 5 commits into
mainfrom
feat/video-export
Jun 12, 2026
Merged

cbaucom merged 5 commits into
mainfrom
feat/video-export

Conversation

@cbaucom

@cbaucom cbaucom commented Jun 12, 2026

Copy link
Copy Markdown
Owner

Closes #40

What

Export the slideshow (picture + soundtrack, ducking applied) as a single file, rendered fully in the browser by @remotion/web-renderer — no backend. The Export dialog offers a format (MP4 H.264/AAC, WebM VP9/Opus, audio-only MP3) and a destination: the project's exports/ subfolder or anywhere via showSaveFilePicker (picked before the render starts). Progress bar with cancel; a failed save after a successful render can still be rescued via "Save elsewhere…".

How

  • Composition: soundtrack swapped from Html5Audio to @remotion/media's Audio (required by the web renderer, supported by the Player), with the ducking envelope applied through the pure volumeAtFrame as a volume callback. New thin render entry point composition/exportVideo.ts wraps renderMediaOnWeb with the same component + RenderPlan the preview uses — WYSIWYG by construction.
  • Project Store: export-store.ts writes blobs into exports/; top-level enumeration skips directories, so exports never re-enter the media bin. Timestamped filenames from the folder name.
  • Bundle: the renderer is dynamically imported; the static format table (exportFormats.ts) uses type-only renderer imports. Main chunk shrank vs. before the feature.
  • All Remotion deps exact-pinned to 4.0.475 (the renderer enforces version match).

Testing

  • export-store tested against in-memory FS fakes (TDD); 222 tests, lint, build all green.
  • scripts/playwright-export-smoke.mjs (run against a preview build, exit 0): exports MP4 to exports/, decodes it in-page asserting 1920×1080, expected duration, and a decodable audio track; then exports WebM through a mocked showSaveFilePicker. ffprobe on a real artifact: h264 1920×1080 + aac, duration matching the RenderPlan.
  • Code-reviewer agent: APPROVE, 5/5, zero blocking findings (the two substantive non-blocking notes — version pinning, non-null assertion — are fixed in the last commit).

configure

🤖 Generated with Claude Code

cbaucom and others added 5 commits June 12, 2026 14:28
Html5Audio is unsupported by @remotion/web-renderer; @remotion/media's
Audio works in both the Player preview and in-browser rendering. The
ducking envelope now feeds the volume prop as a pure frame callback.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
exportVideo renders the existing composition to MP4 (H.264/AAC), WebM
(VP9/Opus), or audio-only MP3 via renderMediaOnWeb — fully client-side,
no backend. The Project Store writes results into an exports/ subfolder;
top-level enumeration skips directories, so exports never re-enter the
media bin. Format specs live in their own module so the editor shell can
import them without pulling the renderer into the main bundle.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Export Video button in the header opens a dialog where the user picks
the format (MP4/WebM/MP3) and where to save — the project's exports/
folder or anywhere via showSaveFilePicker. Rendering shows a progress
bar with cancel; if saving fails after a successful render, the blob
can still be saved elsewhere.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Drives both export paths against a preview build: MP4 into exports/
(decoded in-page to verify dimensions, duration, and audio track) and
WebM to a mocked showSaveFilePicker target.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…null assertion

Caret ranges on the core Remotion packages could float past the pinned
web-renderer on a future install and trip Remotion's version-mismatch
check; exact-pin all five together. Narrow the error blob to a const
instead of asserting non-null in the JSX handler.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@cbaucom
cbaucom merged commit 91fb7ba into main Jun 12, 2026
1 check passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Video export — in-browser render to MP4/WebM/MP3

1 participant