remotion-claude-agent-demo 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +160 -0
- package/apps/web/README.md +36 -0
- package/apps/web/env.example +20 -0
- package/apps/web/eslint.config.mjs +18 -0
- package/apps/web/next.config.ts +7 -0
- package/apps/web/package-lock.json +10348 -0
- package/apps/web/package.json +35 -0
- package/apps/web/postcss.config.mjs +7 -0
- package/apps/web/public/file.svg +1 -0
- package/apps/web/public/globe.svg +1 -0
- package/apps/web/public/next.svg +1 -0
- package/apps/web/public/vercel.svg +1 -0
- package/apps/web/public/window.svg +1 -0
- package/apps/web/src/app/.well-known/agent-card.json/route.ts +50 -0
- package/apps/web/src/app/background-tasks/[jobId]/cancel/route.ts +29 -0
- package/apps/web/src/app/events/stream/route.ts +58 -0
- package/apps/web/src/app/favicon.ico +0 -0
- package/apps/web/src/app/globals.css +174 -0
- package/apps/web/src/app/layout.tsx +34 -0
- package/apps/web/src/app/messages/answer/route.ts +57 -0
- package/apps/web/src/app/messages/stream/route.ts +381 -0
- package/apps/web/src/app/page.tsx +358 -0
- package/apps/web/src/app/tasks/[taskId]/cancel/route.ts +24 -0
- package/apps/web/src/app/tasks/[taskId]/route.ts +24 -0
- package/apps/web/src/app/tasks/route.ts +13 -0
- package/apps/web/src/components/chat/agent-blocks.tsx +111 -0
- package/apps/web/src/components/chat/ask-user-question-panel.tsx +172 -0
- package/apps/web/src/components/chat/session-sidebar.tsx +222 -0
- package/apps/web/src/components/chat/subagent-activity-sidebar.tsx +248 -0
- package/apps/web/src/components/chat/tool-blocks.tsx +550 -0
- package/apps/web/src/lib/a2a/activity-store.ts +150 -0
- package/apps/web/src/lib/a2a/client.ts +357 -0
- package/apps/web/src/lib/a2a/sse.ts +19 -0
- package/apps/web/src/lib/a2a/task-store.ts +111 -0
- package/apps/web/src/lib/a2a/types.ts +216 -0
- package/apps/web/src/lib/agent/answer-store.ts +109 -0
- package/apps/web/src/lib/agent/background-delivery.ts +343 -0
- package/apps/web/src/lib/agent/background-tool.ts +78 -0
- package/apps/web/src/lib/agent/background.ts +452 -0
- package/apps/web/src/lib/agent/chat.ts +543 -0
- package/apps/web/src/lib/agent/session-store.ts +26 -0
- package/apps/web/src/lib/chat/types.ts +44 -0
- package/apps/web/src/lib/env.ts +31 -0
- package/apps/web/src/lib/hooks/useA2AChat.ts +863 -0
- package/apps/web/src/lib/state/chat-atoms.ts +52 -0
- package/apps/web/src/lib/workspace.ts +9 -0
- package/apps/web/tsconfig.json +35 -0
- package/bin/remotion-agent.js +451 -0
- package/package.json +34 -0
- package/templates/.claude/CLAUDE.md +95 -0
- package/templates/.claude/README.md +129 -0
- package/templates/.claude/agents/composer-agent.md +188 -0
- package/templates/.claude/agents/crafter.md +181 -0
- package/templates/.claude/agents/creator.md +134 -0
- package/templates/.claude/agents/perceiver.md +92 -0
- package/templates/.claude/settings.json +36 -0
- package/templates/.claude/settings.local.json +39 -0
- package/templates/.claude/skills/agent-browser/SKILL.md +349 -0
- package/templates/.claude/skills/agent-browser/references/authentication.md +188 -0
- package/templates/.claude/skills/agent-browser/references/proxy-support.md +175 -0
- package/templates/.claude/skills/agent-browser/references/session-management.md +181 -0
- package/templates/.claude/skills/agent-browser/references/snapshot-refs.md +186 -0
- package/templates/.claude/skills/agent-browser/references/video-recording.md +162 -0
- package/templates/.claude/skills/agent-browser/templates/authenticated-session.sh +91 -0
- package/templates/.claude/skills/agent-browser/templates/capture-workflow.sh +68 -0
- package/templates/.claude/skills/agent-browser/templates/form-automation.sh +64 -0
- package/templates/.claude/skills/algorithmic-art/LICENSE.txt +202 -0
- package/templates/.claude/skills/algorithmic-art/SKILL.md +405 -0
- package/templates/.claude/skills/algorithmic-art/templates/generator_template.js +223 -0
- package/templates/.claude/skills/algorithmic-art/templates/viewer.html +599 -0
- package/templates/.claude/skills/asset-validator/SKILL.md +376 -0
- package/templates/.claude/skills/audio-video-sync/SKILL.md +219 -0
- package/templates/.claude/skills/bgm-manager/SKILL.md +334 -0
- package/templates/.claude/skills/remotion-best-practices/SKILL.md +45 -0
- package/templates/.claude/skills/remotion-best-practices/rules/3d.md +86 -0
- package/templates/.claude/skills/remotion-best-practices/rules/animations.md +29 -0
- package/templates/.claude/skills/remotion-best-practices/rules/assets/charts-bar-chart.tsx +173 -0
- package/templates/.claude/skills/remotion-best-practices/rules/assets/text-animations-typewriter.tsx +100 -0
- package/templates/.claude/skills/remotion-best-practices/rules/assets/text-animations-word-highlight.tsx +108 -0
- package/templates/.claude/skills/remotion-best-practices/rules/assets.md +78 -0
- package/templates/.claude/skills/remotion-best-practices/rules/audio.md +172 -0
- package/templates/.claude/skills/remotion-best-practices/rules/calculate-metadata.md +104 -0
- package/templates/.claude/skills/remotion-best-practices/rules/can-decode.md +75 -0
- package/templates/.claude/skills/remotion-best-practices/rules/charts.md +58 -0
- package/templates/.claude/skills/remotion-best-practices/rules/compositions.md +141 -0
- package/templates/.claude/skills/remotion-best-practices/rules/display-captions.md +126 -0
- package/templates/.claude/skills/remotion-best-practices/rules/extract-frames.md +229 -0
- package/templates/.claude/skills/remotion-best-practices/rules/fonts.md +152 -0
- package/templates/.claude/skills/remotion-best-practices/rules/get-audio-duration.md +58 -0
- package/templates/.claude/skills/remotion-best-practices/rules/get-video-dimensions.md +68 -0
- package/templates/.claude/skills/remotion-best-practices/rules/get-video-duration.md +58 -0
- package/templates/.claude/skills/remotion-best-practices/rules/gifs.md +138 -0
- package/templates/.claude/skills/remotion-best-practices/rules/images.md +130 -0
- package/templates/.claude/skills/remotion-best-practices/rules/import-srt-captions.md +67 -0
- package/templates/.claude/skills/remotion-best-practices/rules/lottie.md +68 -0
- package/templates/.claude/skills/remotion-best-practices/rules/maps.md +403 -0
- package/templates/.claude/skills/remotion-best-practices/rules/measuring-dom-nodes.md +35 -0
- package/templates/.claude/skills/remotion-best-practices/rules/measuring-text.md +143 -0
- package/templates/.claude/skills/remotion-best-practices/rules/parameters.md +98 -0
- package/templates/.claude/skills/remotion-best-practices/rules/sequencing.md +118 -0
- package/templates/.claude/skills/remotion-best-practices/rules/tailwind.md +11 -0
- package/templates/.claude/skills/remotion-best-practices/rules/text-animations.md +20 -0
- package/templates/.claude/skills/remotion-best-practices/rules/timing.md +179 -0
- package/templates/.claude/skills/remotion-best-practices/rules/transcribe-captions.md +19 -0
- package/templates/.claude/skills/remotion-best-practices/rules/transitions.md +122 -0
- package/templates/.claude/skills/remotion-best-practices/rules/trimming.md +53 -0
- package/templates/.claude/skills/remotion-best-practices/rules/videos.md +171 -0
- package/templates/.claude/skills/remotion-components/SKILL.md +453 -0
- package/templates/.claude/skills/render-config/SKILL.md +290 -0
- package/templates/.claude/skills/script-writer/SKILL.md +59 -0
- package/templates/.claude/skills/style-director/script-writer/SKILL.md +82 -0
- package/templates/.claude/skills/style-director/style-director/SKILL.md +287 -0
- package/templates/.claude/skills/style-director/style-director/references/audience-and-scenarios.md +43 -0
- package/templates/.claude/skills/style-director/style-director/references/interaction-innovation.md +26 -0
- package/templates/.claude/skills/style-director/style-director/references/motion-grammar.md +66 -0
- package/templates/.claude/skills/style-director/style-director/references/quality-checklist.md +29 -0
- package/templates/.claude/skills/style-director/style-director/references/scene-recipes.md +38 -0
- package/templates/.claude/skills/style-director/style-director/references/visual-style-system.md +148 -0
- package/templates/.claude/skills/subtitle-composer/SKILL.md +304 -0
- package/templates/.claude/skills/subtitle-processor/SKILL.md +308 -0
- package/templates/.claude/skills/timeline-generator/SKILL.md +253 -0
- package/templates/.claude/skills/video-preflight-check/SKILL.md +353 -0
- package/templates/.claude/skills/voice-synthesizer/SKILL.md +296 -0
- package/templates/.claude/skills/voice-synthesizer/scripts/synthesize_voice.py +315 -0
- package/templates/.claude/skills/voice-synthesizer/scripts/tts_cli.py +142 -0
- package/templates/.claude/skills/web-design-guidelines/SKILL.md +36 -0
- package/templates/.claude/skills/youtube-downloader/SKILL.md +99 -0
- package/templates/.claude/skills/youtube-downloader/scripts/download_video.py +145 -0
|
@@ -0,0 +1,334 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: bgm-manager
|
|
3
|
+
version: 1.0.0
|
|
4
|
+
description: 背景音乐管理技能。搜索免费无版权音乐,推荐合适BGM,管理音量曲线,确保BGM不抢戏。
|
|
5
|
+
triggers:
|
|
6
|
+
- 背景音乐
|
|
7
|
+
- BGM
|
|
8
|
+
- background music
|
|
9
|
+
- 音乐搜索
|
|
10
|
+
tools:
|
|
11
|
+
- WebSearch
|
|
12
|
+
- Bash
|
|
13
|
+
- Read
|
|
14
|
+
- Write
|
|
15
|
+
---
|
|
16
|
+
|
|
17
|
+
# 背景音乐管理技能 (BGM Manager)
|
|
18
|
+
|
|
19
|
+
为视频选择和管理背景音乐,包括搜索免费音乐库、推荐合适的 BGM、设计音量曲线、提供下载和集成方案。
|
|
20
|
+
|
|
21
|
+
## 免费无版权音乐库
|
|
22
|
+
|
|
23
|
+
### 1. Pixabay Music
|
|
24
|
+
**网站**: https://pixabay.com/music/
|
|
25
|
+
**特点**:
|
|
26
|
+
- 完全免费,无需署名
|
|
27
|
+
- 高质量音乐
|
|
28
|
+
- 多种风格和情绪分类
|
|
29
|
+
- 支持按时长筛选
|
|
30
|
+
|
|
31
|
+
**搜索示例**:
|
|
32
|
+
- 科技感: "tech", "futuristic", "ambient"
|
|
33
|
+
- 企业风: "corporate", "motivational", "uplifting"
|
|
34
|
+
- 教程风: "calm", "focus", "background"
|
|
35
|
+
|
|
36
|
+
### 2. Mixkit
|
|
37
|
+
**网站**: https://mixkit.co/free-stock-music/
|
|
38
|
+
**特点**:
|
|
39
|
+
- 免费商用
|
|
40
|
+
- 按类别分类(Corporate, Tech, Ambient)
|
|
41
|
+
- 音质优秀
|
|
42
|
+
|
|
43
|
+
### 3. FreePD
|
|
44
|
+
**网站**: https://freepd.com/
|
|
45
|
+
**特点**:
|
|
46
|
+
- 公共领域音乐
|
|
47
|
+
- 完全免费
|
|
48
|
+
- 按情绪和风格分类
|
|
49
|
+
|
|
50
|
+
### 4. YouTube Audio Library
|
|
51
|
+
**网站**: https://www.youtube.com/audiolibrary
|
|
52
|
+
**特点**:
|
|
53
|
+
- Google 官方音乐库
|
|
54
|
+
- 部分需要署名
|
|
55
|
+
- 质量很高
|
|
56
|
+
|
|
57
|
+
## BGM 推荐策略
|
|
58
|
+
|
|
59
|
+
根据视频类型推荐合适的 BGM:
|
|
60
|
+
|
|
61
|
+
### 产品教程 (2-4分钟)
|
|
62
|
+
```yaml
|
|
63
|
+
mood: 平静、专注、不干扰
|
|
64
|
+
tempo: 60-90 BPM
|
|
65
|
+
keywords: ["ambient", "calm", "focus", "background", "subtle"]
|
|
66
|
+
volume_range: 0.10-0.15 (-30dB to -26dB)
|
|
67
|
+
characteristics:
|
|
68
|
+
- 无明显旋律
|
|
69
|
+
- 无人声
|
|
70
|
+
- 节奏平缓
|
|
71
|
+
- 不抢戏
|
|
72
|
+
recommended_tracks:
|
|
73
|
+
- "Calm Technology" (Pixabay)
|
|
74
|
+
- "Soft Background" (Mixkit)
|
|
75
|
+
- "Ambient Corporate" (FreePD)
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
### Demo 演示 (4-7分钟)
|
|
79
|
+
```yaml
|
|
80
|
+
mood: 现代、科技感、有节奏
|
|
81
|
+
tempo: 90-120 BPM
|
|
82
|
+
keywords: ["tech", "modern", "electronic", "upbeat", "inspiring"]
|
|
83
|
+
volume_range: 0.12-0.18 (-28dB to -24dB)
|
|
84
|
+
characteristics:
|
|
85
|
+
- 电子音色
|
|
86
|
+
- 节奏明确但不强烈
|
|
87
|
+
- 有层次感
|
|
88
|
+
- 适合展示动态内容
|
|
89
|
+
recommended_tracks:
|
|
90
|
+
- "Technology Innovation" (Pixabay)
|
|
91
|
+
- "Digital World" (Mixkit)
|
|
92
|
+
- "Future Tech" (FreePD)
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### SaaS 介绍 (3-5分钟)
|
|
96
|
+
```yaml
|
|
97
|
+
mood: 专业、可信、有动力
|
|
98
|
+
tempo: 80-110 BPM
|
|
99
|
+
keywords: ["corporate", "professional", "motivational", "uplifting", "business"]
|
|
100
|
+
volume_range: 0.12-0.16 (-28dB to -26dB)
|
|
101
|
+
characteristics:
|
|
102
|
+
- 企业风格
|
|
103
|
+
- 正面积极
|
|
104
|
+
- 不过于激进
|
|
105
|
+
- 衬托而非主导
|
|
106
|
+
recommended_tracks:
|
|
107
|
+
- "Corporate Success" (Pixabay)
|
|
108
|
+
- "Business Presentation" (Mixkit)
|
|
109
|
+
- "Motivational Corporate" (FreePD)
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
## 音量曲线设计
|
|
113
|
+
|
|
114
|
+
```typescript
|
|
115
|
+
interface VolumePoint {
|
|
116
|
+
time: number; // 时间(秒)
|
|
117
|
+
volume: number; // 音量 (0-1)
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
type VolumeCurve = VolumePoint[];
|
|
121
|
+
|
|
122
|
+
// 标准音量曲线:淡入 → 维持 → 淡出
|
|
123
|
+
function createStandardVolumeCurve(
|
|
124
|
+
totalDuration: number,
|
|
125
|
+
fadeInDuration: number = 3,
|
|
126
|
+
fadeOutDuration: number = 3,
|
|
127
|
+
mainVolume: number = 0.15
|
|
128
|
+
): VolumeCurve {
|
|
129
|
+
return [
|
|
130
|
+
{ time: 0, volume: 0 }, // 开始静音
|
|
131
|
+
{ time: fadeInDuration, volume: mainVolume }, // 淡入完成
|
|
132
|
+
{ time: totalDuration - fadeOutDuration, volume: mainVolume }, // 维持音量
|
|
133
|
+
{ time: totalDuration, volume: 0 }, // 结束静音
|
|
134
|
+
];
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
// Ducking 音量曲线:对白时降低 BGM
|
|
138
|
+
function createDuckingVolumeCurve(
|
|
139
|
+
totalDuration: number,
|
|
140
|
+
dialogueTimes: Array<{ start: number; end: number }>,
|
|
141
|
+
mainVolume: number = 0.15,
|
|
142
|
+
duckVolume: number = 0.08
|
|
143
|
+
): VolumeCurve {
|
|
144
|
+
const curve: VolumeCurve = [{ time: 0, volume: 0 }];
|
|
145
|
+
|
|
146
|
+
let currentTime = 3; // 淡入 3 秒
|
|
147
|
+
curve.push({ time: currentTime, volume: mainVolume });
|
|
148
|
+
|
|
149
|
+
for (const { start, end } of dialogueTimes) {
|
|
150
|
+
// 对白前 0.5s 开始降低音量
|
|
151
|
+
curve.push({ time: start - 0.5, volume: mainVolume });
|
|
152
|
+
curve.push({ time: start, volume: duckVolume });
|
|
153
|
+
|
|
154
|
+
// 对白结束后 0.5s 恢复音量
|
|
155
|
+
curve.push({ time: end, volume: duckVolume });
|
|
156
|
+
curve.push({ time: end + 0.5, volume: mainVolume });
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
// 淡出
|
|
160
|
+
curve.push({ time: totalDuration - 3, volume: mainVolume });
|
|
161
|
+
curve.push({ time: totalDuration, volume: 0 });
|
|
162
|
+
|
|
163
|
+
return curve;
|
|
164
|
+
}
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
## Remotion 音量控制实现
|
|
168
|
+
|
|
169
|
+
```typescript
|
|
170
|
+
// src/utils/bgm-volume.ts
|
|
171
|
+
export function getBGMVolume(frame: number, curve: VolumeCurve, fps: number = 30): number {
|
|
172
|
+
const timeInSeconds = frame / fps;
|
|
173
|
+
|
|
174
|
+
// 线性插值
|
|
175
|
+
for (let i = 0; i < curve.length - 1; i++) {
|
|
176
|
+
const current = curve[i];
|
|
177
|
+
const next = curve[i + 1];
|
|
178
|
+
|
|
179
|
+
if (timeInSeconds >= current.time && timeInSeconds <= next.time) {
|
|
180
|
+
const ratio = (timeInSeconds - current.time) / (next.time - current.time);
|
|
181
|
+
return current.volume + (next.volume - current.volume) * ratio;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// 超出范围返回 0
|
|
186
|
+
return 0;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
// 在 MainVideo.tsx 中使用
|
|
190
|
+
import { Audio, staticFile } from 'remotion';
|
|
191
|
+
import { getBGMVolume } from './utils/bgm-volume';
|
|
192
|
+
|
|
193
|
+
const bgmVolumeCurve = [
|
|
194
|
+
{ time: 0, volume: 0 },
|
|
195
|
+
{ time: 3, volume: 0.15 },
|
|
196
|
+
{ time: 117, volume: 0.15 },
|
|
197
|
+
{ time: 120, volume: 0 },
|
|
198
|
+
];
|
|
199
|
+
|
|
200
|
+
<Audio
|
|
201
|
+
src={staticFile('assets/bgm/tech-ambient.mp3')}
|
|
202
|
+
volume={(frame) => getBGMVolume(frame, bgmVolumeCurve)}
|
|
203
|
+
/>
|
|
204
|
+
```
|
|
205
|
+
|
|
206
|
+
## 搜索和下载流程
|
|
207
|
+
|
|
208
|
+
### 1. 搜索合适的 BGM
|
|
209
|
+
|
|
210
|
+
使用 WebSearch 搜索:
|
|
211
|
+
```bash
|
|
212
|
+
# 示例搜索
|
|
213
|
+
site:pixabay.com music tech ambient download
|
|
214
|
+
site:mixkit.co free stock music corporate
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
### 2. 下载 BGM
|
|
218
|
+
|
|
219
|
+
```bash
|
|
220
|
+
# 使用 curl 或 wget 下载
|
|
221
|
+
curl -o assets/bgm/tech-ambient.mp3 "https://example.com/music.mp3"
|
|
222
|
+
|
|
223
|
+
# 或使用 yt-dlp(如果从 YouTube Audio Library)
|
|
224
|
+
yt-dlp -x --audio-format mp3 -o "assets/bgm/%(title)s.mp3" "URL"
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
### 3. 检查音频信息
|
|
228
|
+
|
|
229
|
+
```bash
|
|
230
|
+
# 使用 ffprobe 检查时长和格式
|
|
231
|
+
ffprobe -v error -show_entries format=duration -of csv=p=0 assets/bgm/tech-ambient.mp3
|
|
232
|
+
|
|
233
|
+
# 检查音频属性
|
|
234
|
+
ffprobe -v error -show_entries stream=codec_name,sample_rate,channels -of csv=p=0 assets/bgm/tech-ambient.mp3
|
|
235
|
+
```
|
|
236
|
+
|
|
237
|
+
## BGM 配置输出格式
|
|
238
|
+
|
|
239
|
+
```yaml
|
|
240
|
+
bgm_config:
|
|
241
|
+
file_path: "./assets/bgm/tech-ambient.mp3"
|
|
242
|
+
duration: 120.5
|
|
243
|
+
source: "Pixabay Music"
|
|
244
|
+
license: "Free for commercial use, no attribution required"
|
|
245
|
+
url: "https://pixabay.com/music/..."
|
|
246
|
+
|
|
247
|
+
metadata:
|
|
248
|
+
title: "Technology Ambient"
|
|
249
|
+
artist: "AudioCreator"
|
|
250
|
+
mood: "calm, focused, technological"
|
|
251
|
+
tempo: 85
|
|
252
|
+
|
|
253
|
+
volume_curve:
|
|
254
|
+
- { time: 0, volume: 0 }
|
|
255
|
+
- { time: 3, volume: 0.15 }
|
|
256
|
+
- { time: 117, volume: 0.15 }
|
|
257
|
+
- { time: 120, volume: 0 }
|
|
258
|
+
|
|
259
|
+
recommendations:
|
|
260
|
+
- "音量设置为 0.12-0.15,确保不抢配音"
|
|
261
|
+
- "淡入淡出各 3 秒,避免突兀"
|
|
262
|
+
- "如有重要对白,考虑使用 ducking"
|
|
263
|
+
```
|
|
264
|
+
|
|
265
|
+
## 使用建议
|
|
266
|
+
|
|
267
|
+
### 音量标准
|
|
268
|
+
```
|
|
269
|
+
配音(主音频): -15dB to -12dB (音量约 0.8-1.0)
|
|
270
|
+
BGM(背景音乐): -30dB to -26dB (音量约 0.10-0.15)
|
|
271
|
+
音效(SFX): -20dB to -18dB (音量约 0.3-0.5)
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
### BGM 选择原则
|
|
275
|
+
1. **不抢戏**: BGM 应衬托而非主导,用户应专注于内容而非音乐
|
|
276
|
+
2. **风格匹配**: 科技产品配科技感音乐,企业视频配企业风
|
|
277
|
+
3. **无人声**: 避免带人声的 BGM,会干扰配音
|
|
278
|
+
4. **时长匹配**: BGM 时长应≥视频时长,或支持循环
|
|
279
|
+
5. **淡入淡出**: 始终使用淡入淡出,避免突然开始/结束
|
|
280
|
+
|
|
281
|
+
### 特殊场景处理
|
|
282
|
+
- **Hook 开场**: BGM 可稍强,吸引注意力
|
|
283
|
+
- **代码演示**: BGM 应极低或静音,让用户专注
|
|
284
|
+
- **CTA 结尾**: BGM 可稍强,增强号召力
|
|
285
|
+
- **转场时刻**: BGM 音量变化配合转场效果
|
|
286
|
+
|
|
287
|
+
## 集成示例
|
|
288
|
+
|
|
289
|
+
### 在 creative_plan.yaml 中定义
|
|
290
|
+
```yaml
|
|
291
|
+
asset_requirements:
|
|
292
|
+
bgm:
|
|
293
|
+
required: true
|
|
294
|
+
type: "tech_ambient"
|
|
295
|
+
duration: 120
|
|
296
|
+
mood: "calm, focused, technological"
|
|
297
|
+
volume_profile: "standard" # or "ducking"
|
|
298
|
+
```
|
|
299
|
+
|
|
300
|
+
### Crafter Agent 执行
|
|
301
|
+
```yaml
|
|
302
|
+
collected_assets:
|
|
303
|
+
bgm:
|
|
304
|
+
file_path: "./assets/bgm/tech-ambient.mp3"
|
|
305
|
+
duration: 120.5
|
|
306
|
+
config: { volume_curve: [...] }
|
|
307
|
+
```
|
|
308
|
+
|
|
309
|
+
### Composer Agent 使用
|
|
310
|
+
```tsx
|
|
311
|
+
// MainVideo.tsx
|
|
312
|
+
{bgmConfig && (
|
|
313
|
+
<Audio
|
|
314
|
+
src={staticFile(bgmConfig.file_path)}
|
|
315
|
+
volume={(frame) => getBGMVolume(frame, bgmConfig.volume_curve)}
|
|
316
|
+
/>
|
|
317
|
+
)}
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
## 优势
|
|
321
|
+
|
|
322
|
+
✅ **专业音质**: 使用高质量免费音乐库
|
|
323
|
+
✅ **合法合规**: 确保版权合规,避免侵权
|
|
324
|
+
✅ **智能推荐**: 根据视频类型自动推荐合适BGM
|
|
325
|
+
✅ **音量控制**: 动态音量曲线,确保不抢配音
|
|
326
|
+
✅ **自动化**: 集成到视频生成流程
|
|
327
|
+
|
|
328
|
+
## 注意事项
|
|
329
|
+
|
|
330
|
+
- 始终检查音乐的许可证条款
|
|
331
|
+
- 如需署名,在视频结尾添加音乐信息
|
|
332
|
+
- 下载的 BGM 文件应放在 `assets/bgm/` 目录
|
|
333
|
+
- BGM 是可选的,不是所有视频都需要
|
|
334
|
+
- 如果视频已有丰富的音效,可以不加 BGM
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: remotion-best-practices
|
|
3
|
+
description: Best practices for Remotion - Video creation in React
|
|
4
|
+
metadata:
|
|
5
|
+
tags: remotion, video, react, animation, composition
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
## When to use
|
|
9
|
+
|
|
10
|
+
Use this skills whenever you are dealing with Remotion code to obtain the domain-specific knowledge.
|
|
11
|
+
|
|
12
|
+
## How to use
|
|
13
|
+
|
|
14
|
+
Read individual rule files for detailed explanations and code examples:
|
|
15
|
+
|
|
16
|
+
- [rules/3d.md](rules/3d.md) - 3D content in Remotion using Three.js and React Three Fiber
|
|
17
|
+
- [rules/animations.md](rules/animations.md) - Fundamental animation skills for Remotion
|
|
18
|
+
- [rules/assets.md](rules/assets.md) - Importing images, videos, audio, and fonts into Remotion
|
|
19
|
+
- [rules/audio.md](rules/audio.md) - Using audio and sound in Remotion - importing, trimming, volume, speed, pitch
|
|
20
|
+
- [rules/calculate-metadata.md](rules/calculate-metadata.md) - Dynamically set composition duration, dimensions, and props
|
|
21
|
+
- [rules/can-decode.md](rules/can-decode.md) - Check if a video can be decoded by the browser using Mediabunny
|
|
22
|
+
- [rules/charts.md](rules/charts.md) - Chart and data visualization patterns for Remotion
|
|
23
|
+
- [rules/compositions.md](rules/compositions.md) - Defining compositions, stills, folders, default props and dynamic metadata
|
|
24
|
+
- [rules/display-captions.md](rules/display-captions.md) - Displaying captions in Remotion with TikTok-style pages and word highlighting
|
|
25
|
+
- [rules/extract-frames.md](rules/extract-frames.md) - Extract frames from videos at specific timestamps using Mediabunny
|
|
26
|
+
- [rules/fonts.md](rules/fonts.md) - Loading Google Fonts and local fonts in Remotion
|
|
27
|
+
- [rules/get-audio-duration.md](rules/get-audio-duration.md) - Getting the duration of an audio file in seconds with Mediabunny
|
|
28
|
+
- [rules/get-video-dimensions.md](rules/get-video-dimensions.md) - Getting the width and height of a video file with Mediabunny
|
|
29
|
+
- [rules/get-video-duration.md](rules/get-video-duration.md) - Getting the duration of a video file in seconds with Mediabunny
|
|
30
|
+
- [rules/gifs.md](rules/gifs.md) - Displaying GIFs synchronized with Remotion's timeline
|
|
31
|
+
- [rules/images.md](rules/images.md) - Embedding images in Remotion using the Img component
|
|
32
|
+
- [rules/import-srt-captions.md](rules/import-srt-captions.md) - Importing .srt subtitle files into Remotion using @remotion/captions
|
|
33
|
+
- [rules/lottie.md](rules/lottie.md) - Embedding Lottie animations in Remotion
|
|
34
|
+
- [rules/measuring-dom-nodes.md](rules/measuring-dom-nodes.md) - Measuring DOM element dimensions in Remotion
|
|
35
|
+
- [rules/measuring-text.md](rules/measuring-text.md) - Measuring text dimensions, fitting text to containers, and checking overflow
|
|
36
|
+
- [rules/sequencing.md](rules/sequencing.md) - Sequencing patterns for Remotion - delay, trim, limit duration of items
|
|
37
|
+
- [rules/tailwind.md](rules/tailwind.md) - Using TailwindCSS in Remotion
|
|
38
|
+
- [rules/text-animations.md](rules/text-animations.md) - Typography and text animation patterns for Remotion
|
|
39
|
+
- [rules/timing.md](rules/timing.md) - Interpolation curves in Remotion - linear, easing, spring animations
|
|
40
|
+
- [rules/transcribe-captions.md](rules/transcribe-captions.md) - Transcribing audio to generate captions in Remotion
|
|
41
|
+
- [rules/transitions.md](rules/transitions.md) - Scene transition patterns for Remotion
|
|
42
|
+
- [rules/trimming.md](rules/trimming.md) - Trimming patterns for Remotion - cut the beginning or end of animations
|
|
43
|
+
- [rules/videos.md](rules/videos.md) - Embedding videos in Remotion - trimming, volume, speed, looping, pitch
|
|
44
|
+
- [rules/parameters.md](rules/parameters.md) - Make a video parametrizable by adding a Zod schema
|
|
45
|
+
- [rules/maps.md](rules/maps.md) - Add a map using Mapbox and animate it
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: 3d
|
|
3
|
+
description: 3D content in Remotion using Three.js and React Three Fiber.
|
|
4
|
+
metadata:
|
|
5
|
+
tags: 3d, three, threejs
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
# Using Three.js and React Three Fiber in Remotion
|
|
9
|
+
|
|
10
|
+
Follow React Three Fiber and Three.js best practices.
|
|
11
|
+
Only the following Remotion-specific rules need to be followed:
|
|
12
|
+
|
|
13
|
+
## Prerequisites
|
|
14
|
+
|
|
15
|
+
First, the `@remotion/three` package needs to be installed.
|
|
16
|
+
If it is not, use the following command:
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npx remotion add @remotion/three # If project uses npm
|
|
20
|
+
bunx remotion add @remotion/three # If project uses bun
|
|
21
|
+
yarn remotion add @remotion/three # If project uses yarn
|
|
22
|
+
pnpm exec remotion add @remotion/three # If project uses pnpm
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Using ThreeCanvas
|
|
26
|
+
|
|
27
|
+
You MUST wrap 3D content in `<ThreeCanvas>` and include proper lighting.
|
|
28
|
+
`<ThreeCanvas>` MUST have a `width` and `height` prop.
|
|
29
|
+
|
|
30
|
+
```tsx
|
|
31
|
+
import { ThreeCanvas } from "@remotion/three";
|
|
32
|
+
import { useVideoConfig } from "remotion";
|
|
33
|
+
|
|
34
|
+
const { width, height } = useVideoConfig();
|
|
35
|
+
|
|
36
|
+
<ThreeCanvas width={width} height={height}>
|
|
37
|
+
<ambientLight intensity={0.4} />
|
|
38
|
+
<directionalLight position={[5, 5, 5]} intensity={0.8} />
|
|
39
|
+
<mesh>
|
|
40
|
+
<sphereGeometry args={[1, 32, 32]} />
|
|
41
|
+
<meshStandardMaterial color="red" />
|
|
42
|
+
</mesh>
|
|
43
|
+
</ThreeCanvas>
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
## No animations not driven by `useCurrentFrame()`
|
|
47
|
+
|
|
48
|
+
Shaders, models etc MUST NOT animate by themselves.
|
|
49
|
+
No animations are allowed unless they are driven by `useCurrentFrame()`.
|
|
50
|
+
Otherwise, it will cause flickering during rendering.
|
|
51
|
+
|
|
52
|
+
Using `useFrame()` from `@react-three/fiber` is forbidden.
|
|
53
|
+
|
|
54
|
+
## Animate using `useCurrentFrame()`
|
|
55
|
+
|
|
56
|
+
Use `useCurrentFrame()` to perform animations.
|
|
57
|
+
|
|
58
|
+
```tsx
|
|
59
|
+
const frame = useCurrentFrame();
|
|
60
|
+
const rotationY = frame * 0.02;
|
|
61
|
+
|
|
62
|
+
<mesh rotation={[0, rotationY, 0]}>
|
|
63
|
+
<boxGeometry args={[2, 2, 2]} />
|
|
64
|
+
<meshStandardMaterial color="#4a9eff" />
|
|
65
|
+
</mesh>
|
|
66
|
+
```
|
|
67
|
+
|
|
68
|
+
## Using `<Sequence>` inside `<ThreeCanvas>`
|
|
69
|
+
|
|
70
|
+
The `layout` prop of any `<Sequence>` inside a `<ThreeCanvas>` must be set to `none`.
|
|
71
|
+
|
|
72
|
+
```tsx
|
|
73
|
+
import { Sequence } from "remotion";
|
|
74
|
+
import { ThreeCanvas } from "@remotion/three";
|
|
75
|
+
|
|
76
|
+
const { width, height } = useVideoConfig();
|
|
77
|
+
|
|
78
|
+
<ThreeCanvas width={width} height={height}>
|
|
79
|
+
<Sequence layout="none">
|
|
80
|
+
<mesh>
|
|
81
|
+
<boxGeometry args={[2, 2, 2]} />
|
|
82
|
+
<meshStandardMaterial color="#4a9eff" />
|
|
83
|
+
</mesh>
|
|
84
|
+
</Sequence>
|
|
85
|
+
</ThreeCanvas>
|
|
86
|
+
```
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: animations
|
|
3
|
+
description: Fundamental animation skills for Remotion
|
|
4
|
+
metadata:
|
|
5
|
+
tags: animations, transitions, frames, useCurrentFrame
|
|
6
|
+
---
|
|
7
|
+
|
|
8
|
+
All animations MUST be driven by the `useCurrentFrame()` hook.
|
|
9
|
+
Write animations in seconds and multiply them by the `fps` value from `useVideoConfig()`.
|
|
10
|
+
|
|
11
|
+
```tsx
|
|
12
|
+
import { useCurrentFrame } from "remotion";
|
|
13
|
+
|
|
14
|
+
export const FadeIn = () => {
|
|
15
|
+
const frame = useCurrentFrame();
|
|
16
|
+
const { fps } = useVideoConfig();
|
|
17
|
+
|
|
18
|
+
const opacity = interpolate(frame, [0, 2 * fps], [0, 1], {
|
|
19
|
+
extrapolateRight: 'clamp',
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
return (
|
|
23
|
+
<div style={{ opacity }}>Hello World!</div>
|
|
24
|
+
);
|
|
25
|
+
};
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
CSS transitions or animations are FORBIDDEN - they will not render correctly.
|
|
29
|
+
Tailwind animation class names are FORBIDDEN - they will not render correctly.
|
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
import {loadFont} from '@remotion/google-fonts/Inter';
|
|
2
|
+
import {AbsoluteFill, spring, useCurrentFrame, useVideoConfig} from 'remotion';
|
|
3
|
+
|
|
4
|
+
const {fontFamily} = loadFont();
|
|
5
|
+
|
|
6
|
+
const COLOR_BAR = '#D4AF37';
|
|
7
|
+
const COLOR_TEXT = '#ffffff';
|
|
8
|
+
const COLOR_MUTED = '#888888';
|
|
9
|
+
const COLOR_BG = '#0a0a0a';
|
|
10
|
+
const COLOR_AXIS = '#333333';
|
|
11
|
+
|
|
12
|
+
// Ideal composition size: 1280x720
|
|
13
|
+
|
|
14
|
+
const Title: React.FC<{children: React.ReactNode}> = ({children}) => (
|
|
15
|
+
<div style={{textAlign: 'center', marginBottom: 40}}>
|
|
16
|
+
<div style={{color: COLOR_TEXT, fontSize: 48, fontWeight: 600}}>
|
|
17
|
+
{children}
|
|
18
|
+
</div>
|
|
19
|
+
</div>
|
|
20
|
+
);
|
|
21
|
+
|
|
22
|
+
const YAxis: React.FC<{steps: number[]; height: number}> = ({
|
|
23
|
+
steps,
|
|
24
|
+
height,
|
|
25
|
+
}) => (
|
|
26
|
+
<div
|
|
27
|
+
style={{
|
|
28
|
+
display: 'flex',
|
|
29
|
+
flexDirection: 'column',
|
|
30
|
+
justifyContent: 'space-between',
|
|
31
|
+
height,
|
|
32
|
+
paddingRight: 16,
|
|
33
|
+
}}
|
|
34
|
+
>
|
|
35
|
+
{steps
|
|
36
|
+
.slice()
|
|
37
|
+
.reverse()
|
|
38
|
+
.map((step) => (
|
|
39
|
+
<div
|
|
40
|
+
key={step}
|
|
41
|
+
style={{
|
|
42
|
+
color: COLOR_MUTED,
|
|
43
|
+
fontSize: 20,
|
|
44
|
+
textAlign: 'right',
|
|
45
|
+
}}
|
|
46
|
+
>
|
|
47
|
+
{step.toLocaleString()}
|
|
48
|
+
</div>
|
|
49
|
+
))}
|
|
50
|
+
</div>
|
|
51
|
+
);
|
|
52
|
+
|
|
53
|
+
const Bar: React.FC<{
|
|
54
|
+
height: number;
|
|
55
|
+
progress: number;
|
|
56
|
+
}> = ({height, progress}) => (
|
|
57
|
+
<div
|
|
58
|
+
style={{
|
|
59
|
+
flex: 1,
|
|
60
|
+
display: 'flex',
|
|
61
|
+
flexDirection: 'column',
|
|
62
|
+
justifyContent: 'flex-end',
|
|
63
|
+
}}
|
|
64
|
+
>
|
|
65
|
+
<div
|
|
66
|
+
style={{
|
|
67
|
+
width: '100%',
|
|
68
|
+
height,
|
|
69
|
+
backgroundColor: COLOR_BAR,
|
|
70
|
+
borderRadius: '8px 8px 0 0',
|
|
71
|
+
opacity: progress,
|
|
72
|
+
}}
|
|
73
|
+
/>
|
|
74
|
+
</div>
|
|
75
|
+
);
|
|
76
|
+
|
|
77
|
+
const XAxis: React.FC<{
|
|
78
|
+
children: React.ReactNode;
|
|
79
|
+
labels: string[];
|
|
80
|
+
height: number;
|
|
81
|
+
}> = ({children, labels, height}) => (
|
|
82
|
+
<div style={{flex: 1, display: 'flex', flexDirection: 'column'}}>
|
|
83
|
+
<div
|
|
84
|
+
style={{
|
|
85
|
+
display: 'flex',
|
|
86
|
+
alignItems: 'flex-end',
|
|
87
|
+
gap: 16,
|
|
88
|
+
height,
|
|
89
|
+
borderLeft: `2px solid ${COLOR_AXIS}`,
|
|
90
|
+
borderBottom: `2px solid ${COLOR_AXIS}`,
|
|
91
|
+
paddingLeft: 16,
|
|
92
|
+
}}
|
|
93
|
+
>
|
|
94
|
+
{children}
|
|
95
|
+
</div>
|
|
96
|
+
<div
|
|
97
|
+
style={{
|
|
98
|
+
display: 'flex',
|
|
99
|
+
gap: 16,
|
|
100
|
+
paddingLeft: 16,
|
|
101
|
+
marginTop: 12,
|
|
102
|
+
}}
|
|
103
|
+
>
|
|
104
|
+
{labels.map((label) => (
|
|
105
|
+
<div
|
|
106
|
+
key={label}
|
|
107
|
+
style={{
|
|
108
|
+
flex: 1,
|
|
109
|
+
textAlign: 'center',
|
|
110
|
+
color: COLOR_MUTED,
|
|
111
|
+
fontSize: 20,
|
|
112
|
+
}}
|
|
113
|
+
>
|
|
114
|
+
{label}
|
|
115
|
+
</div>
|
|
116
|
+
))}
|
|
117
|
+
</div>
|
|
118
|
+
</div>
|
|
119
|
+
);
|
|
120
|
+
|
|
121
|
+
export const MyAnimation = () => {
|
|
122
|
+
const frame = useCurrentFrame();
|
|
123
|
+
const {fps, height} = useVideoConfig();
|
|
124
|
+
|
|
125
|
+
const data = [
|
|
126
|
+
{month: 'Jan', price: 2039},
|
|
127
|
+
{month: 'Mar', price: 2160},
|
|
128
|
+
{month: 'May', price: 2327},
|
|
129
|
+
{month: 'Jul', price: 2426},
|
|
130
|
+
{month: 'Sep', price: 2634},
|
|
131
|
+
{month: 'Nov', price: 2672},
|
|
132
|
+
];
|
|
133
|
+
|
|
134
|
+
const minPrice = 2000;
|
|
135
|
+
const maxPrice = 2800;
|
|
136
|
+
const priceRange = maxPrice - minPrice;
|
|
137
|
+
const chartHeight = height - 280;
|
|
138
|
+
const yAxisSteps = [2000, 2400, 2800];
|
|
139
|
+
|
|
140
|
+
return (
|
|
141
|
+
<AbsoluteFill
|
|
142
|
+
style={{
|
|
143
|
+
backgroundColor: COLOR_BG,
|
|
144
|
+
padding: 60,
|
|
145
|
+
display: 'flex',
|
|
146
|
+
flexDirection: 'column',
|
|
147
|
+
fontFamily,
|
|
148
|
+
}}
|
|
149
|
+
>
|
|
150
|
+
<Title>Gold Price 2024</Title>
|
|
151
|
+
|
|
152
|
+
<div style={{display: 'flex', flex: 1}}>
|
|
153
|
+
<YAxis steps={yAxisSteps} height={chartHeight} />
|
|
154
|
+
<XAxis height={chartHeight} labels={data.map((d) => d.month)}>
|
|
155
|
+
{data.map((item, i) => {
|
|
156
|
+
const progress = spring({
|
|
157
|
+
frame: frame - i * 5 - 10,
|
|
158
|
+
fps,
|
|
159
|
+
config: {damping: 18, stiffness: 80},
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
const barHeight =
|
|
163
|
+
((item.price - minPrice) / priceRange) * chartHeight * progress;
|
|
164
|
+
|
|
165
|
+
return (
|
|
166
|
+
<Bar key={item.month} height={barHeight} progress={progress} />
|
|
167
|
+
);
|
|
168
|
+
})}
|
|
169
|
+
</XAxis>
|
|
170
|
+
</div>
|
|
171
|
+
</AbsoluteFill>
|
|
172
|
+
);
|
|
173
|
+
};
|