Remotion 主题解说视频技能(50-60秒)
本技能指导您为任意给定主题创建高质量、50-60秒的短视频解说(TikTok / YouTube Shorts / Reels 格式:1080x1920 @ 30fps)。
它结合了:
- 视觉最佳实践来自
remotion-dev/skills(帧精确的弹簧动画、裁剪插值、序列组成、排版层次)。 - AI 语音合成通过
.env中的TTS_PROVIDER:edge(edge-tts-universal,在线,免费)或cit(CIT Voice Studio,离线越南语录音室语音 - 下载地址:github.com/quyen2867/cit-voice-studio,API 文档:docs/cit-voice-studio.md)。 - 精确时间同步将音频旁白长度直接映射到 Remotion 的帧序列中。
1. 视频结构与时间线(50-60秒 / 1500-1800帧 @ 30fps)
一个引人入胜的短视频遵循 钩子-问题-解决方案-价值-结尾 框架:
| 场景 | 名称 | 时间 | 帧范围(@ 30fps) | 目的与视觉效果 |
|---|---|---|---|---|
| 1 | 钩子 | 0秒 – 5秒 | ~150帧 | 立即吸引注意:大标题、激发好奇的问题、浮动徽章。 |
| 2 | 背景 / 痛点 | 5秒 – 15秒 | ~300帧 | 提出问题或阐述该主题的重要性。警告图标/对比。 |
| 3 | 核心概念第1部分 | 15秒 – 28秒 | ~390帧 | 解释第一个核心原理:玻璃卡片、插图图标、突出关键词。 |
| 4 | 核心概念第2部分 | 28秒 – 42秒 | ~420帧 | 扩展细节或运作机制:3步流程、流畅的流程图。 |
| 5 | 现实世界影响 | 42秒 – 52秒 | ~300帧 | 实际应用、实战建议或令人印象深刻的数据。 |
| 6 | 结尾与行动号召 | 52秒 – 60秒 | ~240帧 | 一句精辟的总结、呼吁点赞/分享/关注及个人品牌展示。 |
总时长: 1500 – 1800帧(大约 50 – 60 秒)。
2. TTS 语音旁白生成(edge | cit)
2.1 通过 .env 配置语音
确保 .env 文件已配置(完整配置见 .env.example):
TTS_PROVIDER=edge # edge | cit
TTS_OUTPUT_DIR=public/audio
# Edge TTS (TTS_PROVIDER=edge)
EDGE_TTS_VOICE=vi-VN-HoaiMyNeural # 或 vi-VN-NamMinhNeural, en-US-ChristopherNeural
EDGE_TTS_RATE=+10% # +10% 到 +15% 有助于短视频节奏明快,更具吸引力
# CIT Voice Studio (TTS_PROVIDER=cit)
CIT_TTS_BASE_URL=http://127.0.0.1:8001
CIT_TTS_VOICE=Hải Đăng # 声音列表:docs/cit-voice-studio.md 或 GET /voices
CIT_TTS_SPEED=1.1 # 0.5 - 2.0
当 TTS_PROVIDER=cit 时:
- 必须打开 CIT Voice Studio 应用程序。脚本在生成音频前会自动调用
GET /health;如果报告无法连接,则会提示用户打开该应用程序(或从 github.com/quyen2867/cit-voice-studio 下载)。 - 对白中可以插入情感标签
[cười]、[thở dài]、[hắng giọng]和停顿标签[nghỉ 0.5s](不会被朗读出来)。请勿滥用:每个场景最多使用1个标签。 - 错误
400 Voice not found= 声音名称错误(区分音调)。请检查CIT_TTS_VOICE。
2.2 生成音频文件的流程
收到主题后,创建旁白脚本文件并运行 scripts/generate-tts.ts 脚本以生成音频:
import { generateTopicVoices } from "../../scripts/generate-tts";
const scenes = [
{
id: "scene1_hook",
text: "您是否知道 Docker 到底是什么,以及为什么每个程序员都需要它?",
},
{
id: "scene2_problem",
text: "过去,'在我机器上能运行'这句话在交付产品时总是噩梦。",
},
{
id: "scene3_concept1",
text: "Docker 通过 Container 解决了这个问题——将整个代码和环境打包成一个独立的单元。",
},
{
id: "scene4_concept2",
text: "与笨重的虚拟机不同,Docker 共享操作系统内核,使其能在瞬间启动。",
},
{
id: "scene5_impact",
text: "因此,您可以在任何服务器上无缝部署应用程序,从 AWS、GCP 到廉价 VPS。",
},
{
id: "scene6_outro",
text: "关注频道,每天掌握精炼的技术知识!",
},
];
await generateTopicVoices("DockerShort", scenes);
音频文件将自动保存到 public/audio/<TopicName>/<sceneId>.<ext>(edge 为 .mp3,cit 为 .wav),并附带一个 manifest.json 文件,其中精确记录了每个场景的帧数(durationInFrames)和 audioPath。
- 每个场景可选:
voice(所选提供者的声音)、rate/pitch/volume(仅 edge)、speed0.5-2.0(仅 cit)。 - 已存在的文件将被重用(缓存)。如果要在修改对白或更换声音后重新生成,请先删除相应的音频文件。
3. Remotion 编码规则(来自 remotion-dev/skills)
在编写 Remotion 源代码时,必须遵守以下原则:
3.1 使用弹簧动画
不要使用无生气的 CSS keyframes/transitions 或线性缓动。请使用 spring():
import { spring, useCurrentFrame, useVideoConfig } from "remotion";
const frame = useCurrentFrame();
const { fps } = useVideoConfig();
// 为卡片/图标提供流畅的弹性缩放效果
const scale = spring({
frame,
fps,
config: {
damping: 12, // 低于15可产生自然的弹性回弹
stiffness: 100, // 张力
mass: 0.8,
},
});
const entrance = spring({
frame: frame - 10, // 延迟10帧
fps,
from: 50,
to: 0,
});
3.2 安全的插值(始终裁剪)
始终提供 extrapolateLeft: "clamp" 和 extrapolateRight: "clamp" 以防止时间线超出范围时值溢出:
import { interpolate } from "remotion";
const opacity = interpolate(frame, [0, 15], [0, 1], {
extrapolateLeft: "clamp",
extrapolateRight: "clamp",
});
3.3 嵌入音频与同步序列
组合中的每个场景使用 <Sequence> 或 <Series> 来精确管理时间:
import { Audio, staticFile, Sequence } from "remotion";
// 在场景组件中 - 从清单中获取路径,请勿硬编码 .mp3 后缀(cit 供应商输出 .wav):
<Sequence from={0} durationInFrames={sceneDuration}>
<Audio src={staticFile(audioManifest.scenes[0].audioPath)} />
<SceneContent />
</Sequence>
- 紧凑的场景切换缓冲(快速过渡缓冲):
- 场景之间的缓冲仅应为 +3 到 +4 帧(约 0.1 秒),紧跟在配音结束之后。
- 避免使用过长的缓冲(+15 到 +20 帧),这会导致场景之间出现静音/节奏中断。下一个场景应在上一句刚结束时立即出现,以保持短视频快节奏、引人入胜的节奏。
// 计算系列中各场景时长的示例
const d1 = audioManifest.scenes[0].durationInFrames + 3;
const d2 = audioManifest.scenes[1].durationInFrames + 3;
// ...
3.4 视觉设计规范(竖屏 1080x1920)
- 背景:高级深色模式(
bg-slate-950或渐变from-slate-950 via-zinc-900 to-black)结合微弱的径向发光/网格效果。 - 玻璃拟态卡片:
backdrop-blur-xl bg-white/10 border border-white/20 rounded-3xl p-8 shadow-2xl
- 频道品牌标头:
- 始终在顶部居中显示品牌组件
⚡ [CHANNEL_NAME](top: 150px,left: 50%translate-x),其值从环境变量CHANNEL_NAME读取(默认值:“mquyen”),以防止被平台的搜索栏和“正在关注”/“为你推荐”选项卡(TikTok、Shorts、Reels)遮挡。
- 始终在顶部居中显示品牌组件
- 针对移动端优化的排印(1080x1920):
- 主标题:72px - 96px,粗体 font-black,清晰渐变。
- 卡片内容/引用:40px - 50px,font-extrabold。
- 次要/解释文本:28px - 36px,font-semibold。
- 类别徽章:28px - 32px,font-black 大写。
- 居中布局与单行分段字幕:
- 主要布局:所有重要内容块必须位于屏幕正中央(纵向
justify-center)。 - 字幕位置:位于中心块下方,留有充足间距(
mt-64),不会被 TikTok/Reels 的底部工具栏遮挡。 - 单行格式:字幕仅显示一行(约 5-7 个词),大字
text-4xl font-black,根据短语自动剪切,并按照配音进度(durationInFrames)平滑过渡。使用药丸卡片rounded-full bg-slate-950/95 border-2 border-sky-400/50 px-10 py-5,并对关键词进行高亮。
- 主要布局:所有重要内容块必须位于屏幕正中央(纵向
4. 为 Antigravity / Codex 创建视频的分步流程
当收到请求:“创建关于 [主题 X] 的解释视频”:
步骤 1:编写脚本
- 确定 6 个场景(钩子、问题、概念1、概念2、影响、结尾)。
- 编写自然、简洁的越南语对白,句子简短(每个场景 15-30 个词)。
步骤 2:生成立体声音
- 读取
.env中的TTS_PROVIDER以确定使用的是 edge 还是 cit。 - 创建脚本
scripts/generate-<topic>-audio.ts并调用generateTopicVoices,然后运行npx tsx scripts/generate-<topic>-audio.ts。 - 从
manifest.json/src/<TopicName>/audioData.ts获取实际的帧时长列表。
步骤 3:创建代码目录 src/<TopicName>/
标准目录结构:
src/<TopicName>/
├── <TopicName>.tsx # 主组合,包含系列/序列
├── types.ts # 架构与属性
├── audioData.ts # 音频时长元数据
└── scenes/
├── Scene1Hook.tsx
├── Scene2Problem.tsx
├── Scene3Concept1.tsx
├── Scene4Concept2.tsx
├── Scene5Impact.tsx
└── Scene6Outro.tsx
步骤 4:在 src/Root.tsx 中注册组合
将新的组合添加到 src/Root.tsx:
<Composition
id="<TopicName>"
component={<TopicName>}
durationInFrames={totalFrames}
fps={30}
width={1080}
height={1920}
defaultProps={{}}
/>
步骤 5:检查与报告
- 运行
npm run lint以检查 TypeScript/ESLint 错误。 - 向用户报告可在 Remotion Studio(
http://localhost:3000)上打开组合的链接,或提供渲染 MP4 的命令:npx remotion render <TopicName> out/<TopicName>.mp4