Remotion 教程 04:把音频、转场和运动模糊放进时间轴
前面几篇讲的是 Remotion 的基础:入口、帧、时间轴和动画。现在开始接触更像真实视频的部分:素材、声音、场景切换和运动质感。
这一篇聚焦三个能力:
Audio:把音频素材放进视频TransitionSeries:让两个场景之间有转场Trail:给快速运动元素加尾迹
为什么这一章重要
只会让一个方块移动,还不能算视频生成。真实视频通常至少有三类内容:
- 画面素材:图片、视频、图形、产品卡片
- 声音素材:口播、音乐、音效
- 场景结构:从片头到正文,从一个镜头切到另一个镜头
Remotion 的优势是把这些内容都放进同一条 frame 时间轴。
把音频放进时间轴
音频文件应该放在 public/ 目录下,例如:
public/audio/talking-demo.wav在组件里用 staticFile() 引用:
<Audio src={staticFile("audio/talking-demo.wav")} volume={0.25} />volume={0.25} 表示把音量降到 25%。做课程示例或预览时,这样可以避免音频过响。
注意:音频进入时间轴后,并不会自动和字幕或画面同步。你仍然需要用 frame 或字幕时间戳来安排画面节奏。
用 Trail 做运动尾迹
快速运动的物体如果完全锐利,画面会显得很硬。@remotion/motion-blur 里的 Trail 可以复制多层延迟画面,形成尾迹。
<Trail layers={9} lagInFrames={2} trailOpacity={0.18}>
<div style={{ left: x }} />
</Trail>三个参数的意思是:
layers:尾迹层数,越多越明显lagInFrames:每层尾迹延迟多少帧trailOpacity:尾迹透明度
真正控制运动的仍然是 frame:
const x = interpolate(frame, [0, 60], [-140, 620], {
extrapolateLeft: "clamp",
extrapolateRight: "clamp",
});Trail 只是让这个运动更有视觉质感。
用 TransitionSeries 做场景切换
TransitionSeries 用来把多个场景接起来,并在中间插入转场:
<TransitionSeries>
<TransitionSeries.Sequence durationInFrames={82}>
<ProductScene />
</TransitionSeries.Sequence>
<TransitionSeries.Transition
presentation={slide({ direction: "from-right" })}
timing={linearTiming({ durationInFrames: 24 })}
/>
<TransitionSeries.Sequence durationInFrames={82}>
<ResultScene />
</TransitionSeries.Sequence>
</TransitionSeries>这段代码表达的是:
- 第一个场景播放 82 帧。
- 用 24 帧做 slide 转场。
- 第二个场景播放 82 帧。
presentation 决定转场长什么样。
timing 决定转场持续多久。
30fps 下,24 帧大约是 0.8 秒。
完整最小示例
下面是一个两场景视频:第一个场景播放音频并展示带尾迹的运动方块,第二个场景通过 slide 转场进入。
import React from "react";
import { Trail } from "@remotion/motion-blur";
import { linearTiming, TransitionSeries } from "@remotion/transitions";
import { slide } from "@remotion/transitions/slide";
import {
AbsoluteFill,
Audio,
interpolate,
staticFile,
useCurrentFrame,
} from "remotion";
const ProductScene: React.FC = () => {
const frame = useCurrentFrame();
const x = interpolate(frame, [0, 60], [-140, 620], {
extrapolateLeft: "clamp",
extrapolateRight: "clamp",
});
return (
<AbsoluteFill style={{ backgroundColor: "#f8fafc", padding: 96 }}>
<Audio src={staticFile("audio/talking-demo.wav")} volume={0.25} />
<h1 style={{ margin: 0, fontSize: 72 }}>真实素材进入时间轴</h1>
<div
style={{
marginTop: 120,
width: 620,
height: 340,
borderRadius: 8,
backgroundColor: "#dbeafe",
position: "relative",
overflow: "hidden",
}}
>
<Trail layers={9} lagInFrames={2} trailOpacity={0.18}>
<div
style={{
position: "absolute",
top: 110,
left: x,
width: 120,
height: 120,
borderRadius: 8,
backgroundColor: "#2563eb",
}}
/>
</Trail>
</div>
</AbsoluteFill>
);
};
const ResultScene: React.FC = () => {
return (
<AbsoluteFill
style={{
backgroundColor: "#312e81",
color: "white",
padding: 96,
}}
>
<h1 style={{ margin: 0, fontSize: 72 }}>场景切换也由帧控制</h1>
<p style={{ marginTop: 80, fontSize: 38 }}>
TransitionSeries 把两个场景接起来。
</p>
</AbsoluteFill>
);
};
export const MediaDemo: React.FC = () => {
return (
<TransitionSeries>
<TransitionSeries.Sequence durationInFrames={82}>
<ProductScene />
</TransitionSeries.Sequence>
<TransitionSeries.Transition
presentation={slide({ direction: "from-right" })}
timing={linearTiming({ durationInFrames: 24 })}
/>
<TransitionSeries.Sequence durationInFrames={82}>
<ResultScene />
</TransitionSeries.Sequence>
</TransitionSeries>
);
};三个能力的分工
不要把 media、transitions、motion-blur 混在一起理解:
media:素材怎么进视频
transitions:场景怎么切换
motion-blur:运动怎么更自然在真实项目里,常见组合是:
素材场景 + 转场 + 局部运动质感你不需要给所有东西都加运动模糊,也不需要每个场景都用很夸张的转场。它们应该服务内容节奏。
示例项目位置
这篇文章对应示例项目里的:
Composition: LessonMediaTransitions
文件: src/lessons/MediaTransitions.tsx
素材: public/audio/talking-demo.wav运行示例项目后,可以试三个改动:
- 把
volume={0.25}改成volume={0.1}。 - 把
linearTiming({ durationInFrames: 24 })改成 12 或 36。 - 把
Trail的layers从 9 改成 3,再改成 14。
下一篇继续沿着“声音和文字”往前走,讲口播字幕、词级高亮和 TTS/Whisper 数据。