$npx -y skills add MatrixReligio/ProductVideoCreator --skill compositing使用 Remotion 合成最终视频。当需要将片头、录屏、配音、片尾组合成完整视频时使用。包含动画效果、时间线管理、多尺寸模板和故障处理。
| 1 | # 视频合成技能 |
| 2 | |
| 3 | ## 快速开始:使用模板 |
| 4 | |
| 5 | 项目提供了可复用的配置和组件模板,位于 `templates/` 目录: |
| 6 | |
| 7 | ```bash |
| 8 | templates/ |
| 9 | ├── config/ # 配置模板 |
| 10 | │ ├── scenes.ts # 场景时间配置 |
| 11 | │ ├── theme.ts # 主题颜色配置 |
| 12 | │ ├── types.ts # TypeScript 类型定义 |
| 13 | │ ├── videoPresets.ts # 多尺寸视频预设 |
| 14 | │ └── index.ts # 统一导出 |
| 15 | └── components/ # 组件模板 |
| 16 | ├── SubtitleDisplay.tsx # 字幕组件 |
| 17 | ├── AnimatedText.tsx # 动画文字组件 |
| 18 | ├── BackgroundEffects.tsx # 背景效果组件 |
| 19 | ├── BrandElements.tsx # 品牌元素组件 |
| 20 | ├── useResponsive.ts # 响应式 Hook |
| 21 | └── index.ts # 统一导出 |
| 22 | ``` |
| 23 | |
| 24 | ### 使用方法 |
| 25 | |
| 26 | 1. 复制模板到项目目录: |
| 27 | ```bash |
| 28 | cp -r templates/config src/config |
| 29 | cp -r templates/components src/components |
| 30 | ``` |
| 31 | |
| 32 | 2. 根据项目需要修改配置(颜色、场景时间等) |
| 33 | |
| 34 | 3. 在组件中导入使用: |
| 35 | ```tsx |
| 36 | import { SCENES, FPS, VIDEO_DURATION } from "./config"; |
| 37 | import { THEME, getGlowStyle } from "./config"; |
| 38 | import { SubtitleDisplay, FadeInText, ParticleField } from "./components"; |
| 39 | ``` |
| 40 | |
| 41 | --- |
| 42 | |
| 43 | ## 多尺寸视频模板 |
| 44 | |
| 45 | ### 预设尺寸 |
| 46 | |
| 47 | | 名称 | 分辨率 | 比例 | 适用平台 | |
| 48 | |------|--------|------|----------| |
| 49 | | 1080p (默认) | 1920×1080 | 16:9 | YouTube, 官网 | |
| 50 | | 720p | 1280×720 | 16:9 | 快速预览, 低带宽 | |
| 51 | | vertical | 1080×1920 | 9:16 | 抖音, 小红书, Reels | |
| 52 | | square | 1080×1080 | 1:1 | Instagram, 微信 | |
| 53 | | 4K | 3840×2160 | 16:9 | 高端展示 | |
| 54 | |
| 55 | ### Remotion 多尺寸配置 |
| 56 | |
| 57 | ```tsx |
| 58 | // videoPresets.ts |
| 59 | export const VIDEO_PRESETS = { |
| 60 | "1080p": { width: 1920, height: 1080, name: "Full HD" }, |
| 61 | "720p": { width: 1280, height: 720, name: "HD" }, |
| 62 | "vertical": { width: 1080, height: 1920, name: "Vertical" }, |
| 63 | "square": { width: 1080, height: 1080, name: "Square" }, |
| 64 | "4k": { width: 3840, height: 2160, name: "4K" }, |
| 65 | } as const; |
| 66 | |
| 67 | export type VideoPreset = keyof typeof VIDEO_PRESETS; |
| 68 | ``` |
| 69 | |
| 70 | ### Root.tsx 多尺寸定义 |
| 71 | |
| 72 | ```tsx |
| 73 | import { Composition } from "remotion"; |
| 74 | import { MainVideo } from "./MainVideo"; |
| 75 | import { VIDEO_PRESETS, VideoPreset } from "./videoPresets"; |
| 76 | |
| 77 | const FPS = 30; |
| 78 | const DURATION_SECONDS = 85; |
| 79 | |
| 80 | export const RemotionRoot: React.FC = () => { |
| 81 | return ( |
| 82 | <> |
| 83 | {/* 为每个尺寸创建 Composition */} |
| 84 | {Object.entries(VIDEO_PRESETS).map(([key, preset]) => ( |
| 85 | <Composition |
| 86 | key={key} |
| 87 | id={`Video-${key}`} |
| 88 | component={MainVideo} |
| 89 | durationInFrames={DURATION_SECONDS * FPS} |
| 90 | fps={FPS} |
| 91 | width={preset.width} |
| 92 | height={preset.height} |
| 93 | defaultProps={{ preset: key as VideoPreset }} |
| 94 | /> |
| 95 | ))} |
| 96 | </> |
| 97 | ); |
| 98 | }; |
| 99 | ``` |
| 100 | |
| 101 | ### 响应式组件适配 |
| 102 | |
| 103 | ```tsx |
| 104 | // 根据视频尺寸调整布局 |
| 105 | const ResponsiveLayout: React.FC<{ children: React.ReactNode }> = ({ children }) => { |
| 106 | const { width, height } = useVideoConfig(); |
| 107 | const aspectRatio = width / height; |
| 108 | |
| 109 | // 竖屏布局 (9:16) |
| 110 | if (aspectRatio < 1) { |
| 111 | return ( |
| 112 | <AbsoluteFill style={{ flexDirection: "column", padding: "60px 40px" }}> |
| 113 | {children} |
| 114 | </AbsoluteFill> |
| 115 | ); |
| 116 | } |
| 117 | |
| 118 | // 方形布局 (1:1) |
| 119 | if (aspectRatio === 1) { |
| 120 | return ( |
| 121 | <AbsoluteFill style={{ padding: "40px" }}> |
| 122 | {children} |
| 123 | </AbsoluteFill> |
| 124 | ); |
| 125 | } |
| 126 | |
| 127 | // 横屏布局 (16:9) |
| 128 | return ( |
| 129 | <AbsoluteFill style={{ padding: "60px 120px" }}> |
| 130 | {children} |
| 131 | </AbsoluteFill> |
| 132 | ); |
| 133 | }; |
| 134 | ``` |
| 135 | |
| 136 | ### 字体大小适配 |
| 137 | |
| 138 | ```tsx |
| 139 | // 根据分辨率计算字体大小 |
| 140 | const getResponsiveFontSize = (baseSize: number): number => { |
| 141 | const { width, height } = useVideoConfig(); |
| 142 | const scale = Math.min(width / 1920, height / 1080); |
| 143 | return Math.round(baseSize * scale); |
| 144 | }; |
| 145 | |
| 146 | // 使用示例 |
| 147 | const title = getResponsiveFontSize(72); // 1080p 下 72px |
| 148 | ``` |
| 149 | |
| 150 | ### 批量渲染脚本 |
| 151 | |
| 152 | ```bash |
| 153 | #!/bin/bash |
| 154 | # render_all_sizes.sh |
| 155 | |
| 156 | SIZES=("1080p" "720p" "vertical" "square") |
| 157 | OUTPUT_DIR="out" |
| 158 | |
| 159 | for size in "${SIZES[@]}"; do |
| 160 | echo "渲染 $size..." |
| 161 | npx remotion render src/index.ts "Video-$size" "$OUTPUT_DIR/video_$size.mp4" |
| 162 | done |
| 163 | |
| 164 | echo "所有尺寸渲染完成!" |
| 165 | ``` |
| 166 | |
| 167 | --- |
| 168 | |
| 169 | ## Remotion 基础 |
| 170 | |
| 171 | Remotion 是 React-based 的视频渲染框架,使用 React 组件定义视频内容。 |
| 172 | |
| 173 | ### 核心概念 |
| 174 | |
| 175 | | 概念 | 说明 | |
| 176 | |------|------| |
| 177 | | Composition | 视频组合定义(分辨率、帧率、时长) | |
| 178 | | Sequence | 时间序列,控制内容出现时机 | |
| 179 | | useCurrentFrame | 获取当前帧数 | |
| 180 | | interpolate | 数值插值,用于动画 | |
| 181 | | spring | 弹性动画 | |
| 182 | |
| 183 | ### 基本结构 |
| 184 | |
| 185 | ```tsx |
| 186 | import { Composition } from "remotion"; |
| 187 | |
| 188 | export const RemotionRoot = () => { |
| 189 | return ( |
| 190 | <Composition |
| 191 | id="FinalVideo" |
| 192 | component={FinalVideo} |
| 193 | durationInFrames={2550} // 85秒 * 30fps |
| 194 | fps={30} |
| 195 | width={1920} |
| 196 | height={1080} |
| 197 | /> |
| 198 | ); |
| 199 | }; |
| 200 | ``` |
| 201 | |
| 202 | ## 故障处理 (重要) |
| 203 | |
| 204 | ### 浏览器下载失败 |
| 205 | |
| 206 | **问题表现**: |
| 207 | ``` |
| 208 | Error: Tried to download file xxx, but the server sent no data for 20 seconds |
| 209 | ``` |
| 210 | |
| 211 | **解决方案 A: 手动下载 Chrome Headless Shell** |
| 212 | |
| 213 | ```bash |
| 214 | # 1. 手动下载 (更长超时) |
| 215 | curl -L --connect-timeout 30 --max-time 300 \ |
| 216 | "https://storage.googleapis.com/chrome-for-testing-public/134.0.6998.35/mac-arm64/chrome-headless-shell-mac-arm64.zip" \ |
| 217 | -o /tmp/chrome-headless-shell.zip |
| 218 | |
| 219 | # 2. 解压到 Remotion 缓存目录 |
| 220 | mkdir -p ~/.cache/remotion |
| 221 | unzip /tmp/chrome-headless-shell.zip -d ~/.cache/remotion/ |
| 222 | |
| 223 | # 3. 渲染时指定浏览器路径 |
| 224 | npx remotion render src/index.ts VideoId out/video.mp4 \ |
| 225 | --browser-executable="$HOME/.cache/remotion/chrome-headless-shell-mac-ar |