Remotion 混剪/讲解视频生成
基于 Remotion 4(React + TypeScript 写视频)的代码驱动视频生成工作流。 核心信条:视频不是堆特效,是信息传达的效率——数据驱动、改数据即改片。
何时使用
- 用户要「把零碎视频片段混剪成一条视频,带转场」
- 用户要「讲解视频 / 30 秒科普 / 产品介绍短视频」
- 用户要「渐变转场 / 关键词聚焦标记 / 双语字幕」
- 用户要「VLM 自动识别视频内容并标记重点」
- 用户要「嗅探下载 YouTube/B站 素材做科普混剪」(skillhub/clawhub universal-video-downloader 方案的落地替代)
- 平台:B站/YouTube 16:9 横屏(1920×1080)或 抖音 9:16 竖屏(1080×1920)
环境准备(Windows 注意)
# 工程依赖(关键:--legacy-peer-deps 绕过 React19 ERESOLVE)
cd remotion-videos
export npm_config_cache="$PWD/.npm-cache" # 绕过系统 AppData EACCES 权限坑
npm install --legacy-peer-deps --no-audit --no-fund
npm install lucide-react --legacy-peer-deps --no-audit --no-fund # 讲解视频图标库
# 渲染(无需系统 ffmpeg,用 ffmpeg-static;用项目内 cache 规避权限)
export npm_config_cache="$PWD/.npm-cache"
./node_modules/.bin/remotion render <composition-id> out/xxx.mp4 --concurrency=2
渲染环境修坑(必做一次)
Remotion 首次渲染要下载 Chrome Headless Shell。若因 safe-delete 钩子/版本校验失败,
在 remotion.config.ts 钉死已下载二进制,跳过下载:
import { Config } from "@remotion/cli/config";
Config.setVideoImageFormat("jpeg");
Config.setOverwriteOutput(true);
Config.setBrowserExecutable(
"C:/.../remotion-videos/node_modules/.remotion/chrome-headless-shell/win64/chrome-headless-shell-win64/chrome-headless-shell.exe"
);
fade必须是子路径导入:import { fade } from "@remotion/transitions/fade";(主入口没有!)- 验证:
./node_modules/.bin/tsc --noEmit -p tsconfig.json
核心组件结构(可复用模板)
src/compositions/mashup/ # 混剪(零碎视频 → 渐变转场 + 聚焦)
types.ts # Clip {id,src,placeholderColor,durationInFrames,captions[],fit} / Caption {text,translation?,start,end} / FocusConfig {keywords[],label?}
data.ts # 编辑区:clips[] / focusConfig / TRANSITION_FRAMES;横屏用 landscapeClips
ClipScene.tsx # 单片段:视频/占位 + 双语字幕(原文白+翻译金)+ 聚焦逻辑(s=height/1080 自适应)
FocusMarker.tsx# 暗角 radial-gradient + 右上角「重点:关键词」标签(中央光圈已按用户要求移除)
MashupVideo.tsx# TransitionSeries 串联 + fade() 渐变转场(props 传 clips/focusConfig)
src/compositions/explain/ # 30 秒讲解(场景制)
data.ts # scenes[](kicker/title/subtitle/accent/icon/focusKeyword)+ 画布/帧率/场景时长
ExplainScene.tsx # 渐变背景 + lucide 图标 + 大字标题 + 副标题 + 右上角重点标签
ExplainVideo.tsx # 场景间 fade 转场
IconMap.tsx # icon 类型 → lucide-react 组件映射
src/Root.tsx # 注册 composition(竖屏/横屏/横屏VLM/30s讲解)
关键实现细节:
- 渐变转场:
TransitionSeries+<TransitionSeries.Transition presentation={fade()} timing={linearTiming({durationInFrames})} /> - 关键词聚焦:字幕文本(含 translation)命中
focusConfig.keywords→focusProgress平滑进出 → 暗角 + 画面放大 1.06x + 右上角「重点:关键词」标签 - 尺寸自适应:组件内
const s = height/1080,所有字号/尺寸乘s,竖屏横屏共用一套组件
数据驱动(改数据即改片)
- 混剪:编辑
data.ts的clips[](src填staticFile("assets/xxx.mp4")或远程 URL)与focusConfig.keywords - 讲解:编辑
scenes[]的文案/配色/图标 - 关键词命中即触发聚焦标记,无需改组件
YouTube 嗅探下载(yt-dlp,含 403 破解)
素材准备:先搜索主题最新/综合评分最好的视频 → 嗅探下载 1080p 片段 → 截取/合并 → VLM 理解。
# 依赖
$VENV/Scripts/python.exe -m pip install yt-dlp
# ① 下载(关键:--extractor-args "youtube:player_client=tv_android" 破解 HTTP 403)
# -4 强制 IPv4;限 1080p 视频流 + 音频流并合并为 mp4
python -m yt_dlp --extractor-args "youtube:player_client=tv_android" -4 \
-f "bv*[height<=1080]+ba/b[height<=1080]" --merge-output-format mp4 \
-o "work/yt_downloads/%(id)s.%(ext)s" "URL"
# ② 截取 10-20s 片段(科普混剪通常取主题核心段落)
ffmpeg -y -ss 12 -t 20 -i work/yt_downloads/XXXX.mp4 \
-c:v libx264 -c:a aac -movflags +faststart work/clips/clip1.mp4
403 破解排障顺序(本机验证):直连 403 → --cookies-from-browser chrome(无 Chrome)→
edge(cookie 库被占用)→ web_safari(无格式)→ tv_android 成功。不同机器
cookie 情况不同,按此顺序逐个尝试。
合规守卫(脚本内置):仅允许 CC/授权/自有内容,--cc-licensed / --i-own-this 二选一,
未声明直接拒绝。科普二次创作/引用必须附完整出处(B站发布文案带来源链接)。
VLM 自动标重点(aiping Qwen3-VL)
pipeline/(Python)实现「视频理解 → 自动生成聚焦数据」闭环:
# 依赖:装到托管 venv(Windows 用 Scripts\python.exe)
python -m venv C:/Users/<user>/.workbuddy/binaries/python/envs/default
$VENV/Scripts/python.exe -m pip install openai yt-dlp faster-whisper bilibili-api
# ① 视频理解(key 走环境变量,不写文件)
AIPING_API_KEY=xxx python pipeline.py understand video.mp4 --json
# ② keypoints → Remotion data.ts 片段
python pipeline.py gen-data video.mp4.keypoints.json
# ③ 追加进 data.ts → remotion render
- 抽帧:
ffmpeg -i in.mp4 -vf fps=N/dur out_%03d.jpg(无需 ffprobe) - VLM 调用:OpenAI 兼容接口,帧 base64 内联 image_url,流式聚合
reasoning_content+content - 已知坑:VLM 常把 JSON 包在
json 围栏里 → gen-data 解析失败。模板脚本的 `_load` 已加正则剥离 `^(json)?\s*/\s*```$`,若自写脚本必须处理 - VLM keypoints 偏「画面描述」→ 生成字幕时融合视频真实主题人工精修(例:大模型科普 → 预测下一个词/Token/注意力/应用)
- 合规守卫:YouTube 下载仅限 CC/授权/自有内容(
--cc-licensed/--i-own-this),未声明直接拒绝
30 秒真实视频混剪模板(llmClips)
把 3 个真实科普视频各截 10s 片段 + 手写双语字幕 + 关键词聚焦,拼成 30s 科普混剪:
// data.ts —— 结构示例(src 指向 public/llm/ 下的本地片段)
export const llmClips: Clip[] = [
{ id: "clip-1", src: staticFile("llm/LPZh9BOjkQs.mp4"),
durationInFrames: 300, // 10s @30fps
captions: [
{ text: "LLMs predict the next token", translation: "大模型预测下一个词",
start: 0, end: 300 },
] },
// ...共 3 个片段,每个 10s,总长 30s
];
export const focusConfigLLM: FocusConfig = {
keywords: ["LLM", "token", "attention", "大模型", "Token", "注意力", "预测", "推理"],
label: "重点",
};
- 片段时长 10s × 3 = 30s,
TransitionSeries转场帧重叠约 0.5s,总时长 31s 左右 - 渲染:
remotion render mashup-llm-30s out/llm-30s.mp4(composition 在 Root.tsx 注册,defaultProps={{ clips: llmClips, focusConfig: focusConfigLLM }}) - 发布 B站文案必须带出处:标题 + 简介列 3 个来源视频链接 + 授权/引用声明
交付
- 渲染产物:
remotion-videos/out/*.mp4,复制到工作区根产物/便于用户查看 - 用
present_files展示 mp4 + 概览文档
边界
- 复杂转场/特效/混音建议专业软件(剪映/PR/达芬奇);Remotion 擅长数据驱动+程序化生成
- 音乐/素材版权必须合规;B站自动上传有平台风控,先人工核对
- 渲染耗时:视频越长越慢,交付前告知用户预估时间