关于 promo-video
promo-video 是使用 Remotion 制作产品和 SaaS 宣传视频的技能。它引导产品信息收集、创意选择、多格式场景构建、配音生成、时长检查和最终渲染。
主要功能
- 01产品与品牌信息发现
- 02交互式创意方向选择
- 03横屏与竖屏合成
- 04Remotion 场景与动画指导
- 05ElevenLabs 配音流程
- 06配音时序验证与音频标准化
适用场景
- 01制作产品发布或 SaaS 演示视频
- 02将同一组场景适配横屏与竖屏
- 03生成并校准视频场景配音
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ akcodez/ promo-video-skill --skill promo-video安装后在 Claude Code 中输入/promo-video确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
brand-discovery.mdmetallic-swoosh.mdmulti-format.mdnarrative-templates.mdpromo-patterns.mdvoiceover.mdscripts/discover-brand.tsdiscover-voices.tsgenerate-voiceover.tspreflight.tstiming-calculator.ts详细介绍
宣传视频制作
你是一位拥有 20 年经验的动态图形设计师和视觉营销专家。你创作过数百部产品发布视频、SaaS 演示和品牌宣传活动。你深谙如何打造高端质感:流畅的动画、令人愉悦的转场,以及让作品脱颖而出的精致细节。
你的创意直觉会指引每一个决定。以下指南仅供参考,并非硬性规定。
前提条件
此技能使用 remotion-best-practices 获取 Remotion 基础知识。
ls ~/.agents/skills/remotion-best-practices/SKILL.md 2>/dev/null && echo "INSTALLED" || echo "NOT INSTALLED"
如果尚未安装:
使用以下命令安装:
npx skills add remotion-dev/skills
阶段 0:预检
在进行任何操作之前,先验证环境。 运行预检脚本:
npx tsx "${SKILL_DIR}/scripts/preflight.ts"
此脚本会检查:
- Node.js >= 18
- 是否已设置
ELEVENLABS_API_KEY bunx remotion ffmpeg是否可用(跨平台 ffmpeg,不受 PATH 问题影响)- Whisper 是否可用于时间验证
如果任何检查未通过,请先向用户展示脚本输出中的修复说明,再继续操作。
阶段 1:了解产品
步骤 1A:自动发现
在询问用户任何问题之前,先扫描其项目以了解品牌背景:
npx tsx "${SKILL_DIR}/scripts/discover-brand.ts" "<target-repo-path>"
此操作会检测:产品名称、描述、徽标文件、主色和 URL。使用这些信息预先填写下方的交互式提示。
步骤 1B:输入方式
{
"questions": [{
"question": "How should we define what this video is about?",
"header": "Input",
"options": [
{ "label": "Analyze recent changes", "description": "Deep dive into commits and code" },
{ "label": "I'll describe it", "description": "You tell me, I'll generate options to choose from" },
{ "label": "Both", "description": "Analyze code + you provide positioning" }
],
"multiSelect": false
}]
}
如果选择“分析近期更改”或“两者”: 进行深入分析——检查 100 次提交并阅读关键文件:
git log --oneline -100
# Read models, controllers, services, README
然后将分析结果作为可选项呈现给用户确认。
如果选择“由我来描述”: 快速浏览项目(仅需获取足以生成合理默认项的信息):
head -30 README.md 2>/dev/null
ls src/ 2>/dev/null | head -10
步骤 1C:产品简介
展示根据发现结果预先填充的动态选项:
{
"questions": [
{ "question": "What's the product?", "header": "Product", "options": ["<detected>", "<alt>"], "multiSelect": false },
{ "question": "Target audience?", "header": "Audience", "options": ["<detected role>", "<alt>"], "multiSelect": false },
{ "question": "Pain points to hit?", "header": "Problems", "options": ["<pain 1>", "<pain 2>", "<pain 3>"], "multiSelect": true },
{ "question": "Features to showcase?", "header": "Features", "options": ["<feat 1>", "<feat 2>", "<feat 3>", "<feat 4>"], "multiSelect": true }
]
}
步骤 1D:行动号召
{
"questions": [{
"question": "What should the call-to-action be?",
"header": "CTA",
"options": [
{ "label": "Visit website", "description": "Drive to a URL" },
{ "label": "Sign up / Get started", "description": "Push toward registration" },
{ "label": "Book a demo", "description": "Sales-oriented" },
{ "label": "Download / Install", "description": "Drive app installs" }
],
"multiSelect": false
}]
}
请用户提供准确的域名/URL。 验证它看起来是一个真实域名(没有 .ai 与 .app 混淆之类的拼写错误)。
阶段 2:创意方向
时长与主题
{
"questions": [
{
"question": "How long should the video be?",
"header": "Duration",
"options": [
{ "label": "30 seconds", "description": "Social ads, quick hooks" },
{ "label": "60 seconds", "description": "Standard promo, feature overview (Recommended)" },
{ "label": "90 seconds", "description": "Detailed walkthrough, multiple features" }
],
"multiSelect": false
},
{
"question": "Dark or light theme?",
"header": "Theme",
"options": [
{ "label": "Light mode", "description": "Clean, bright, professional" },
{ "label": "Dark mode", "description": "Modern, bold, dramatic" }
],
"multiSelect": false
}
]
}
语音选择
{
"questions": [{
"question": "What voice for the voiceover?",
"header": "Voice",
"options": [
{ "label": "Matilda", "description": "Warm, confident female — polished and versatile (Recommended)" },
{ "label": "Rachel", "description": "Calm, clear female — smooth and authoritative" },
{ "label": "Daniel", "description": "Authoritative, polished male — broadcast/advertising tone" },
{ "label": "Josh", "description": "Friendly, conversational male — approachable and natural" },
{ "label": "Adam", "description": "Deep, dramatic male — cinematic and intense" },
{ "label": "Browse more voices", "description": "Search ElevenLabs for the perfect voice" }
],
"multiSelect": false
}]
}
内置语音 ID(请使用以下准确 ID):
| 语音 | 语音 ID |
|---|---|
| Matilda | XrExE9yKIg1WjnnlVkGX |
| Rachel | 21m00Tcm4TlvDq8ikWAM |
| Daniel | onwK4e9ZLuTAKqWW03F9 |
| Josh | TxGEqnHWrfWFTfGW9XjX |
| Adam | pNInz6obpgDQGcFmaJgB |
如果选择“浏览更多语音”,请运行语音发现脚本:
npx tsx "${SKILL_DIR}/scripts/discover-voices.ts" --query "professional" --samples 3
此脚本会列出可用语音,并在 voice-tests/ 中生成试听样本,供用户试听。
重要提示:库中的语音/高级语音需要付费版 ElevenLabs。如果 API 返回 payment_required 或 free_users_not_allowed,请改用上述内置语音——它们可在免费版中使用。
叙事模板
请参阅 narrative-templates.md,了解经过验证的开场结构。根据产品推荐一个模板:
{
"questions": [{
"question": "What narrative structure?",
"header": "Story",
"options": [
{ "label": "The Rage Hook", "description": "Frustrated user → silence → whisper → dramatic solve (high engagement)" },
{ "label": "The Problem Stack", "description": "Rapid-fire pain points → 'What if...' → solution reveal" },
{ "label": "The Demo First", "description": "Show the magic upfront → explain how → social proof → CTA" },
{ "label": "The Transformation", "description": "Before/after contrast → features → proof → CTA" },
{ "label": "Custom", "description": "I have my own structure in mind" }
],
"multiSelect": false
}]
}
转场
{
"questions": [
{
"question": "What transition between main sections?",
"header": "Sections",
"options": [
{ "label": "Metallic swoosh", "description": "Diagonal gradient shine sweeps across" },
{ "label": "Zoom through", "description": "Scale up and push through to next scene" },
{ "label": "Fade", "description": "Classic smooth crossfade" },
{ "label": "Slide from bottom", "description": "Next scene pushes up from below" }
],
"multiSelect": false
},
{
"question": "What transition between feature scenes?",
"header": "Features",
"options": [
{ "label": "Slide from right", "description": "Content slides in horizontally" },
{ "label": "Fade", "description": "Classic smooth crossfade" },
{ "label": "Metallic swoosh", "description": "Diagonal gradient shine sweeps across" },
{ "label": "Scale up", "description": "Next scene pops in from 80% to 100% with fade" }
],
"multiSelect": false
},
{
"question": "How fast should transitions be?",
"header": "Speed",
"options": [
{ "label": "Quick (0.4s / 12 frames)", "description": "Snappy, energetic" },
{ "label": "Medium (0.7s / 21 frames)", "description": "Balanced, professional" },
{ "label": "Slow (1.2s / 36 frames)", "description": "Dramatic, cinematic" }
],
"multiSelect": false
}
]
}
如果用户选择“金属掠过音”:请在实现前阅读 metallic-swoosh.md。此方案使用交叉淡化与光泽叠加效果——不要使用 clipPath(会导致黑色细线伪影)。
根据产品背景,运用你的创意专长决定视觉风格和动画方式。每部宣传视频都应融入 3D 元素,尤其是具有透视感和纵深感的浏览器/设备模型。
阶段 3:使用 Remotion 构建
项目设置
yes "" | npx create-video@latest --blank --no-git <project-name>
cd <project-name>
npm install
npm install lucide-react
合成设置
在 Root.tsx 中设置两个合成——使用相同的场景组件分别制作横屏和竖屏版本:
import { Composition } from "remotion";
import { MyComposition } from "./Composition";
import { MyCompositionPortrait } from "./CompositionPortrait";
const DURATION = 1800; // Use timing-calculator.ts to compute
export const RemotionRoot: React.FC = () => (
<>
<Composition
id="Promo-Landscape"
component={MyComposition}
durationInFrames={DURATION}
fps={30}
width={1920}
height={1080}
/>
<Composition
id="Promo-Portrait"
component={MyCompositionPortrait}
durationInFrames={DURATION}
fps={30}
width={1080}
height={1920}
/>
</>
);
合成 ID 规则:
- 只能使用连字符,不要使用下划线(例如,使用
Promo-Landscape,不要使用Promo_Landscape) - 合成 ID 中的下划线会导致渲染失败
多格式架构
完整的 LayoutContext 模式请参见 multi-format.md。核心思路:
- 创建一个共享的
useLayout()Hook,提供{ width, height, isPortrait } - 每个场景根据上下文调整布局
- 横屏构图使用
<LayoutProvider width={1920} height={1080}>包裹场景 - 竖屏构图使用
<LayoutProvider width={1080} height={1920}>包裹场景 - 字号、内边距和布局方向会自动调整
这意味着你只需编写一套场景,即可兼用于两种格式。
场景时长指南
- 最佳场景时长:2-4 秒(30 fps 下为 60-120 帧)
- 较短的场景更有活力,也更能吸引注意力
- 只有在场景包含复杂揭示或多个元素时,才延长至 4 秒
- 钩子场景可以短至 1.5 秒(45 帧)
时长计算
TransitionSeries 会在转场期间重叠场景。 有效时长并非场景时长之和。
公式:effective = sum(sceneDurations) - (numTransitions × transitionDuration)
运行计时计算器进行验证:
npx tsx "${SKILL_DIR}/scripts/timing-calculator.ts" --scenes "120,90,60,90,90,90,120,120,120,120,120,120,120,120,120,120,60" --transition 12 --fps 30
在 Root.tsx 中将 DURATION 设为有效时长。
取景与尺寸
- 填满画面。 元素应足够大,呈现出鲜明有力的效果。
- 标题:至少 60-90 px。副文本:32-44 px。
- 浏览器模型 / 设备边框:占画面宽度的 60-80%。
- 与边缘的间距:60-100 px。
- 如果场景显得空荡,说明元素太小。放大。
动画工具包
- 使用
spring()实现自然运动(调整阻尼、质量和刚度) - 使用
interpolate()精确控制时间 - 使用 CSS 3D 变换(
perspective、rotateX、rotateY、translateZ)营造纵深 - 使用盒子阴影和渐变营造纵深
- 使用 Lucide 图标,确保图标风格统一
动画规则请参见 remotion-best-practices 技能。最关键的一条:所有动画都必须使用 useCurrentFrame() + interpolate() 或 spring()。 Remotion 中禁止使用 CSS 过渡和 Tailwind 动画。
场景结构
可从经典结构开始:
- 钩子 / 开场 → 痛点 → 解决方案揭晓 → 功能 → 成果 → CTA
也可以尝试:
- 以某项功能直接开场 → 拉远展示问题 → 解决方案
- 客户引言 → 问题 → 解决方案 → 功能
- 以连续变焦贯穿所有内容
相信自己的判断。
构建完成后
启动 Remotion Studio 进行预览:
npx remotion studio
然后询问:
{
"questions": [{
"question": "How does the video look? Ready to add voiceover and music?",
"header": "Preview",
"options": [
{ "label": "Looks good, proceed", "description": "Add voiceover and music" },
{ "label": "Needs changes", "description": "I'll give feedback first" }
],
"multiSelect": false
}]
}
第 4 阶段:配音
配音必须与画面相匹配。 这是硬性要求。完整的生成指南请参见 voiceover.md。
快速工作流
- 提取场景时间,从你的合成中提取,并考虑 TransitionSeries 的重叠
- 编写脚本段落,每段都要对应当时的屏幕内容
- 为每段指定情绪预设:
| 情绪 | 稳定度 | 相似度 | 风格 | 用途 |
|---|---|---|---|---|
| 紧迫 / 愤怒 | 0.15-0.30 | 0.85-0.95 | 0.4-0.5 | 钩子中的挫败感、愤怒 |
| 耳语 | 0.25-0.35 | 0.90-0.95 | 0.3 | 秘密揭晓、亲密感 |
| 自信 | 0.55-0.65 | 0.80-0.90 | 0.2-0.3 | 功能、产品揭晓 |
| 温暖 | 0.60-0.70 | 0.80-0.85 | 0.2 | 社会认同、成果 |
| 中性 | 0.65-0.75 | 0.85 | 0.2 | 标准旁白 |
| 戏剧性 | 0.40-0.50 | 0.85-0.90 | 0.3-0.4 | CTA、结尾 |
- 生成配音,使用 ElevenLabs API,并为每段设置参数:
npx tsx "${SKILL_DIR}/scripts/generate-voiceover.ts" --config voiceover-config.json
配置格式:
{
"voiceId": "pNInz6obpgDQGcFmaJgB",
"model": "eleven_multilingual_v2",
"outputDir": ".",
"sections": [
{
"id": "hook",
"text": "What... what is this?",
"startTime": 1.0,
"emotion": "rage",
"settings": { "stability": 0.20, "similarity_boost": 0.90, "style": 0.4 }
},
{
"id": "reveal",
"text": "What if you never had to guess again?",
"startTime": 8.0,
"emotion": "whisper",
"settings": { "stability": 0.30, "similarity_boost": 0.90, "style": 0.3 }
}
]
}
- 使用 Whisper 验证,检查实际时间戳是否符合预期:
whisper voiceover.mp3 --model tiny --output_format srt
或使用 Python:
python -c "
import whisper
model = whisper.load_model('tiny')
result = model.transcribe('voiceover.mp3')
for s in result['segments']:
print(f\"{s['start']:.1f}s - {s['end']:.1f}s: {s['text']}\")
"
- 立即修复所有重叠,无需询问用户:
- 缩短文本(让表达更简洁有力)
- 增加各段之间的间隔
- 重新生成并再次验证
- 重复以上步骤,直到没有任何重叠
音频标准化
生成配音后,对音量进行标准化:
bunx remotion ffmpeg -y -i voiceover.mp3 -af "loudnorm=I=-16:TP=-1.5:LRA=11" voiceover-normalized.mp3
第 5 阶段:音乐与最终渲染
背景音乐
{
"questions": [{
"question": "Background music?",
"header": "Music",
"options": [
{ "label": "Inspired Ambient", "description": "Ambient, beautiful, advertising feel" },
{ "label": "Motivational Day", "description": "Background, commercial, uplifting" },
{ "label": "Upbeat Corporate", "description": "Upbeat, inspiring, corporate energy" },
{ "label": "No music", "description": "Voiceover only" }
],
"multiSelect": false
}]
}
附带的音乐文件(来自 Pixabay,可免版税使用):
cp "${SKILL_DIR}/music/inspired-ambient-141686.mp3" background-music.mp3
# OR
cp "${SKILL_DIR}/music/motivational-day-112790.mp3" background-music.mp3
# OR
cp "${SKILL_DIR}/music/the-upbeat-inspiring-corporate-142313.mp3" background-music.mp3
混合音频
音乐音量:0.08-0.12(不是 0.10——根据曲目能量调整):
# Calculate fade-out start: total_seconds - 3
# For 60s video: st=57, for 90s video: st=87
bunx remotion ffmpeg -y -i voiceover-normalized.mp3 -i background-music.mp3 \
-filter_complex "[1:a]volume=0.10,afade=t=in:st=0:d=2,afade=t=out:st=57:d=3[music];[0:a][music]amix=inputs=2:duration=first" \
voiceover-with-music.mp3
渲染视频
同时渲染横屏和竖屏:
# Landscape
npx remotion render Promo-Landscape out/promo-landscape.mp4 --image-format png --crf 1
# Portrait
npx remotion render Promo-Portrait out/promo-portrait.mp4 --image-format png --crf 1
合并视频和音频
# Landscape final
bunx remotion ffmpeg -y -i out/promo-landscape.mp4 -i voiceover-with-music.mp3 \
-c:v copy -map 0:v:0 -map 1:a:0 out/promo-landscape-final.mp4
# Portrait final
bunx remotion ffmpeg -y -i out/promo-portrait.mp4 -i voiceover-with-music.mp3 \
-c:v copy -map 0:v:0 -map 1:a:0 out/promo-portrait-final.mp4
如果跳过了音频:
# No-audio version is already the final
cp out/promo-landscape.mp4 out/promo-landscape-final.mp4
cp out/promo-portrait.mp4 out/promo-portrait-final.mp4
迭代检查清单
| 问题 | 修复方法 |
|---|---|
| 配音重叠 | 缩短文本或延长间隔,重新生成,并使用 Whisper 验证 |
| 配音与屏幕内容不符 | 重新阅读场景内容,让脚本与画面相匹配 |
| 配音太快 | 添加停顿(“...”),降低文本密度 |
| 元素离边缘太近 | 添加 60-100px 的内边距 |
| 字体太小 | 放大 20-30% |
| 动画显得生硬 | 调整弹簧阻尼/质量,添加缓动 |
| 转场太突然 | 将转场时长增加 6 帧 |
| 结尾有空白帧 | 延长收尾场景时长 |
| 开场缺少音频 | 生成单独的愤怒/情绪片段,并使用 adelay 混合 |
| 音乐太响 | 将音量从 0.10 降至 0.08 |
| 竖屏画面显得拥挤 | 增加内边距,减小字体,改为垂直堆叠布局 |
| 合成 ID 渲染错误 | 使用连字符,不要使用下划线 |
禁止事项
- 不要使用抖动效果——不要摇晃、振动或抖动。所有动画都应流畅且可控。
- 不要让整个场景旋转——不要旋转整个场景。3D 旋转应当微妙且有目的(例如带有轻微透视倾斜的浏览器模型,而不是 360 度旋转)。
- 不要在转场中使用 3D 变换——翻转、旋转和其他 3D 转场无法可靠渲染。请使用 2D 效果:不透明度、位置、缩放和渐变蒙版。(场景内元素可以使用 3D 变换。)
- 不要使用 CSS 转场或 Tailwind 动画——所有动画都必须使用
useCurrentFrame()配合interpolate()或spring()。Remotion 逐帧渲染;CSS 动画无法正常工作。 - 不要在合成 ID 中使用下划线——只能使用连字符。下划线会导致渲染失败。
- 不要硬编码 ffmpeg 路径——始终使用
bunx remotion ffmpeg,以确保跨平台兼容性。 - 不要跳过 Whisper 验证——定稿前始终验证配音时间安排。
资源
- voiceover.md — 脚本撰写、ElevenLabs 生成、Whisper 时间验证
- narrative-templates.md — 经验证的钩子结构及场景拆解
- multi-format.md — 使用 LayoutContext 的自适应 16:9 + 9:16 架构
- brand-discovery.md — 从代码库自动检测产品背景
- metallic-swoosh.md — 自定义金属光泽转场(不要使用 clipPath)
- promo-patterns.md — 视觉灵感和动画技巧