Add Local Mac Voiceover to a Remotion Video
Add a local Murmur WAV to Remotion, calculate frames from audio duration, and render a vertical MP4. Download the tested React source and commands.
Choose this Remotion voiceover workflow when you want an editable React animation with narration generated on your Mac. Save the voice as a WAV, place it in the Remotion project, measure the audio duration, and let calculateMetadata set the video frame count before rendering an MP4. Murmur supplies the speech track; Remotion supplies the composition and movie export. The downloadable example gives you both the original source and the commands to check the result.
We executed the example on October 9, 2026 using Remotion 4.0.534. A 7.12-second Murmur narration became a 1080 by 1920 video with 214 frames at 30 fps. Full video and audio decoding succeeded, and representative frames were inspected. An independent run with a 2.25-second WAV produced 68 frames. Download the complete local Remotion workflow to reproduce the small composition before adding your own product footage.
Prepare the Mac and the project
Murmur requires an Apple Silicon Mac with macOS 15 or later. Finish app setup, enable local automation in Settings, and install the CLI from that pane. Read the automation documentation if Terminal cannot find murmur. For the movie portion, install Node.js with npm and have ffprobe and ffmpeg available in Terminal. These video-development tools are separate from Murmur's managed speech runtime.
The download pins remotion, @remotion/cli, and @remotion/media to 4.0.534, with React and React DOM 19.3.0. Keep the Remotion packages on the same version. Preserve the generated package-lock.json and use npm ci for later installs; direct pins do not freeze every transitive dependency. The render ran under Node 26.10.0; that is the measured environment, not a claim that every Node release works. Start in a new folder so old audio, metadata, or movies cannot be mistaken for the current take.
The first dependency installation and Remotion browser download use the network. The tested composition references one local audio file and original text, with no remote media assets. Remotion's public/ folder is its asset directory, not a privacy setting. Keep the project local and exclude private narration if you later publish source or web assets. A hosted coding assistant may also send the script to its provider even when speech generation and rendering happen on your Mac.
Generate or export the local narration
You can export a WAV from Murmur's interface or generate it from Terminal. Use the same narration file throughout the first render check. If you need help deciding the script and visual sequence, the promo-reel guide covers that production brief. This guide focuses on the Remotion integration once you have the words and an approved take.
murmur status --json
murmur models --json
murmur voices --model qwen3-base --json
murmur generate --input script.txt --model qwen3-base --voice Ryan \
--language EN-US --speed 1.0 --output narration.wav --jsonSelect a model that is installed on your own Mac and a voice returned for that model. The original fixture used Qwen3-TTS Base with the Ryan preset. That pair was available on the test machine; a voice ID from another model may not work. The audio came from a development helper reporting Murmur 1.0.18, and parity with the released binary was not verified. No coding-assistant model was invoked for this render.
The original spoken script is: “Start with one clear idea. Write a short script. Generate the voice on your Mac, then build the motion around it.” Save only spoken words in script.txt. Put scene directions and screen text in your composition. For another take, choose a new audio filename rather than replacing the earlier version. An agent can request speech through MCP too; the MCP setup guide explains discovery and completed-job checks.
Reference the WAV in the Remotion composition
The recipe copies the approved take into public/narration.wav. The composition imports Audio from @remotion/media and uses staticFile('narration.wav') for its source. This is the component currently recommended in the Remotion audio documentation. It avoids using a Mac filesystem path as a browser URL. The download contains the complete working JSX.
import {Audio} from '@remotion/media';
import {staticFile} from 'remotion';The narration starts at frame zero and plays at its normal rate. The audio component is outside the changing visual stages, so switching a title does not restart the voice track. The original visual uses three labels, WRITE, VOICE, and MOTION, with short frame-based entrances and a progress bar. You can replace those labels and colors while keeping the speech file and duration logic intact.
Those three stages occupy equal portions of the composition. That makes the sample easy to reproduce, but it does not match each spoken phrase to a scene boundary. For a product demo, use measured cue points from an approved take and align the demonstrated feature with the relevant words. Add checked captions if viewers need to understand the reel without sound. The small fixture does not generate or validate captions.
Calculate frames from the actual audio duration
Run node prepare.mjs after copying the WAV. The helper calls ffprobe, rejects a missing or invalid duration, and writes props.json with the audio filename and measured seconds. The composition uses those props in calculateMetadata. Remotion runs that callback before rendering, so the export receives the calculated frame count rather than the one-second placeholder in the source.
const fps = 30;
const durationInFrames = Math.ceil(durationSeconds * fps);For the measured 7.12-second take, 7.12 multiplied by 30 is 213.6. Rounding up gives 214 frames, so the video track lasts 214 divided by 30, or 7.133333 seconds. Rounding down could end the visuals before the narration ends. The independent 2.25-second input resolved to 68 frames and a 2.266667-second video track, confirming that the same code changes duration when the input changes.
AAC encoding can add a small amount of padding, so the MP4 container duration need not equal either the WAV duration or the video-track duration exactly. Our first export reported a 7.147-second container. Inspect frame count and both streams rather than treating that small difference as proof of a broken render. If you revise the narration or change frame rate, prepare new metadata and render a new version together.
Render the editable video and check the export
node prepare.mjs
npm run render
ffprobe -v error -count_frames -show_format -show_streams \
-of json local-voiceover.mp4
ffmpeg -hide_banner -loglevel error -i local-voiceover.mp4 -f null -The recipe renders H.264 picture with AAC audio and yuv420p pixels at 1080 by 1920. It uses --overwrite=false; Remotion otherwise enables overwriting by default. The tested command refused an existing output without changing the movie bytes. The preparation helper also refuses an existing props file. Use a fresh version folder for a complete rerun, or intentionally choose new filenames for revised outputs.
- Check that the video stream reports 1080 by 1920, 30/1 fps, and the calculated frame count. The original output had 214 video frames.
- Confirm an AAC audio stream exists. The tested renderer encoded stereo at 48,000 Hz from the mono 24,000 Hz WAV; preserve the original WAV as your source.
- Decode the whole MP4 with FFmpeg. Exit zero checks codec integrity; it does not prove that every spoken word or scene cue is correct.
- Watch and listen from beginning to end. Check pronunciation, the last word, title readability, cue timing, and any captions before sharing.
The original export was 395,762 bytes. File size can differ with the script, fonts, software, or render settings; match the intended streams and timing rather than requiring identical bytes on every machine. If the render fails, read the first error, confirm the WAV path and props file, and retry into a new output. A missing audio file should fail visibly rather than leave you accepting a silent movie.
Check licensing before using the workflow commercially
Remotion is not unconditionally free for every business. The license for the pinned version lists individuals, for-profit organizations with up to three employees, nonprofits, and noncommercial evaluators as eligible for its free tier. Other organizations need a Company License. The current pricing page also addresses collaborations. Check that page and the linked license terms for your organization and use case, especially before upgrading versions or building an automated video service.
Murmur's website edition costs $49 one-time, with no free trial and a 7-day refund policy. Local speech generation does not use per-character credits on a licensed installation. Mac memory, storage, and render time remain finite, and any hosted assistant plan, API bill, or renderer license is separate. Listen to Murmur's public speech samples before deciding whether its voices suit your project.
Sources
- Remotion: recommended Audio component and local file sourcesAccessed 2026-10-09
- Remotion: dynamic composition metadataAccessed 2026-10-09
- Remotion: render CLI and overwrite behaviorAccessed 2026-10-09
- Remotion: license eligibility and pricingAccessed 2026-10-09
- Remotion: published license termsAccessed 2026-10-09
- FFmpeg: ffprobe metadata and frame-count optionsAccessed 2026-10-09
- Murmur: CLI and MCP automation documentationAccessed 2026-10-09
- Murmur: Mac requirements, website-edition offer and purchase policyAccessed 2026-10-09
Can I use a Murmur WAV as a Remotion voiceover?
Yes. Export or generate the WAV, place it in the local Remotion public folder, and reference it with staticFile through Audio from @remotion/media. This guide executed that path with an original Murmur-generated narration and checked the resulting video and audio streams.
How do I set Remotion duration from the narration?
Measure the actual file, then use calculateMetadata to return Math.ceil(durationSeconds * fps). The downloadable helper writes those measured seconds into props.json. At 30 fps, our 7.12-second input required 214 frames; a separate 2.25-second input required 68 frames.
Does this example work entirely offline?
It uses local narration and no remote media assets, but installing npm packages and the Remotion browser requires network access initially. This test did not run with networking disabled. Any assistant or added remote asset can introduce its own network requests.
Does Murmur create the React animation or render the MP4?
Murmur creates the speech file. Remotion renders the original React composition and combines it with audio. A coding assistant can help edit source when its host has file and terminal access, but no assistant model was tested for this example.
Is Remotion free for commercial promo videos?
Eligible individuals and small organizations can use its free license commercially, subject to the current terms. Larger organizations and some collaborations need a Company License. Check Remotion's license and pricing pages for your circumstances; Murmur's purchase does not include a Remotion license.