SuperAPI AI Directory

remotion-synced-video

Design & creation

View repository

Updated 10-16 09:56

About this skill

Remotion Synced Video with Real Web Images

Create professional-grade videos, integratingreal web images(Google Images scraping), perfect audio synchronization, rich content display, and beautiful visual design. Uses Remotion + TTS + multi-source image search to generate video content with a top-tier major-company style.

🆕 Multi-Source Image Search (v2.0)

This tool now integrates Google Images web scraping, allowing you to obtain a large number of high-quality real images without an Unsplash API Key:

🥇 Python/Google Images → 🥈 Bing Images → 🥉 Unsplash → 🎨 渐变占位图
Tier Source Description Requires configuration
1 Google Images Python + Playwright scrapes high-resolution original images No API Key required
2 Bing Images HTTP parsing, fast fallback No API Key required
3 Unsplash High-quality photographic images Requires UNSPLASH_ACCESS_KEY
4 Placeholder image Automatically generates gradient backgrounds No configuration required

Image search uses

# 一键搜索所有场景图片
node scripts/search_images.js scenes.json --output ./public/images

# 输出示例:
# ✅ 总计: 4 个场景
#    Google:    3 个  ← 真实网页图片
#    Bing:      1 个  ← 真实网页图片
#    Unsplash:  0 个
#    占位图:    0 个

Each scene will automatically obtain 1-2 high-resolution images, prioritizing real Google Images images.

✨ Features

  • 🖼️ Integrated image display - Images are part of the content, supporting various layouts such as side, floating, and card
  • 📝 Rich text content - Supports multiple content types such as multi-paragraph, bullet point lists, statistical data, and quotations
  • 💬 Intelligent subtitle system - Sentence-by-sentence subtitles are precisely synchronized with audio, supporting automatic timeline allocation
  • 🔤 Extra-large font design - Font sizes optimized specifically for video, ensuring clear readability on various screens
  • 🎬 Rich animation effects - Animations such as typewriter, line-by-line fade-in, keyword highlighting, and number scrolling
  • ✅ Perfect audio-video synchronization - Each scene waits for audio playback to complete
  • 🎙️ Multi-TTS support - Supports Doubao, Volcano, or any TTS service, using a natural male voice by default
  • 📐 Dynamic duration calculation - Automatically calculates the number of frames based on audio duration
  • 🔧 FFmpeg stitching - Seamlessly merges all scenes

Workflow

脚本 → TTS 音频 → 搜索图片 → 测量时长 → 渲染场景 → 拼接视频

Multi-source image search (new)

This tool now supports multi-source image search, automatically obtaining high-quality images by priority:

Google Images → Bing Images → Unsplash → 渐变占位图
  • Google Images: Preferred, scrapes high-resolution original images
  • Bing Images: Fallback, no API Key required
  • Unsplash: Last resort, high-quality photographic images (API Key required)
  • Placeholder image: Final fallback, automatically generates gradient colors based on the scene theme

How to use:

node scripts/search_images.js scenes.json --output ./public/images

After the search is complete, a summary report will be output, informing you of the image source used for each scene.

Prerequisites

1. System dependencies

# macOS
brew install ffmpeg

# Python 3.8+ 和 Playwright(用于 Google Images 爬取)
pip3 install playwright
npx playwright install chromium

2. Node.js dependencies

npm install @remotion/cli remotion react react-dom

Unsplash API configuration

1. Obtain an Unsplash Access Key

  1. Visit Unsplash Developers
  2. Register and create a new application
  3. Obtain Access Key

2. Set environment variables

# 添加到 ~/.zshrc 或 ~/.bashrc
export UNSPLASH_ACCESS_KEY="your_access_key_here"

# 立即生效
source ~/.zshrc

Project structure

my-video/
├── src/
│   ├── index.tsx              # 注册所有 compositions
│   ├── scenes/
│   │   └── SceneTemplate.tsx  # 专业风格模板
│   └── components/
│       ├── Typography.tsx     # 文字组件
│       ├── ImageCard.tsx      # 图片卡片组件
│       ├── Animations.tsx     # 动画组件
│       ├── GradientOverlay.tsx # 渐变遮罩
│       └── UnsplashImage.tsx  # 图片展示
├── scripts/
│   ├── search_images.js       # 🔥 多源图片搜索主脚本
│   ├── generate_placeholder.js # 渐变占位图生成
│   └── lib/                   # 爬取库
│       ├── crawl_google_images.py  # Python Google 图片爬取
│       └── download_images.py      # 图片下载器
├── public/
│   ├── audio/                 # TTS 音频文件
│   └── images/                # 下载的真实图片
├── scenes.json                # 场景配置
├── image-map.json             # 图片路径映射
└── package.json

Scene configuration (scenes.json)

Basic scene

{
  "id": "intro",
  "searchQuery": "artificial intelligence technology abstract blue",
  "title": "人工智能革命",
  "subtitle": "探索改变世界的技术力量",
  "caption": "Introduction",
  "variant": "hero"
}

Rich content scene

{
  "id": "solution",
  "searchQuery": "neural network ai brain technology",
  "title": "智能解决方案",
  "caption": "Our Solution",
  "variant": "content-rich",
  "layout": {
    "imageLayout": "side-right",
    "imageStyle": "card",
    "imageAnimation": "float",
    "textAlign": "left",
    "accentColor": "#10b981"
  },
  "paragraphs": [
    "我们的 AI 平台能够自动处理海量数据,从中提取有价值的洞察。",
    "通过深度学习算法,系统可以识别复杂的模式和趋势。"
  ],
  "bulletPoints": [
    "实时数据处理,毫秒级响应",
    "准确率高达 99.7%",
    "自动生成可视化报告"
  ],
  "stat": {
    "value": "300",
    "label": "效率提升",
    "suffix": "%"
  },
  "highlightKeywords": ["AI", "深度学习"]
}

Configuration options explained in detail

Variant

Variant Description Image layout
hero Full-screen background, centered title background
centered Centered layout, vignette mask background
split Left-right split layout side-right
minimal Minimal bottom alignment background
content-rich Rich content display side-right or side-left

Layout configuration

{
  "layout": {
    "imageLayout": "side-right",    // 图片位置
    "imageStyle": "card",            // 图片样式
    "imageAnimation": "float",       // 图片动画
    "textAlign": "left",             // 文字对齐
    "accentColor": "#3b82f6"         // 强调色
  }
}

imageLayout options

  • background - Full-screen background (traditional method)
  • side-left - Image on the left, occupying 42% width
  • side-right - Image on the right, occupying 42% width
  • floating - Image floating at the upper right
  • inline - Image embedded within the text content

imageStyle options

  • none - No border, no shadow
  • rounded - Rounded corners (24px)
  • card - Card style (rounded corners + shadow + border)
  • polaroid - Polaroid style (white border)
  • circle - Circle

imageAnimation options

  • none - No animation
  • zoom - Slow zoom (Ken Burns effect)
  • fade - Fade in
  • slide - Slide in
  • float - Hover float

Content fields

Field Type Description
title string Main title (required)
subtitle string Subtitle
caption string Section label (uppercase letters, e.g. "INTRODUCTION")
paragraphs string[] Paragraph text array
bulletPoints string[] Bullet point list
quote {text, author?} Quote text and author
stat {value, label, suffix?} Statistics display
highlightKeywords string[] Keywords to highlight
subtitles object Sentence-by-sentence subtitle configuration (see below)

Sentence-by-sentence subtitle configuration

Configure subtitles synchronized with audio via the subtitles field:

{
  "id": "intro",
  "title": "AGI 早已实现",
  "subtitles": {
    "sentences": [
      "Nature 重磅评论:",
      "AGI 早已实现,人类却不敢承认。",
      "就在五年前,我们还没有 AGI;",
      "而今天,我们已经拥有它。"
    ],
    "mode": "word-count",
    "style": {
      "position": "bottom",
      "bgOpacity": 0.8,
      "fontSize": 52,
      "maxWidth": "90%",
      "bottomOffset": 100
    }
  }
}

Subtitle configuration options:

Field Type Description
sentences string[] Subtitle sentence array; each sentence is displayed according to time
mode string Time allocation mode:word-count(by word count) / equal(even)
style.position string Position:bottom(bottom) / middle(middle)
style.bgOpacity number Background opacity, 0-1
style.fontSize number Font size (px)
style.maxWidth string Maximum width, e.g. "90%"
style.bottomOffset number Distance from bottom (px)

Time allocation mode:

  • word-count (default): allocate audio duration proportionally by each sentence's word count; longer sentences display longer
  • equal: evenly distribute the audio duration across each sentence

💡 Tip: allocating by word count is usually more natural, because longer sentences need more time to read.

Font size specifications

Optimized specifically for 1920x1080 video:

Element Size Purpose
Main title (xl) 160px Important section title
Main title (lg) 120px Standard section title
Main title (md) 90px Secondary title
Subtitle 64px Subtitle description
Paragraph text 44px Body content
Bullet point list 40px List item
Statistics value 220px Large number display
Statistics label 44px Number description
Quote text 56px Quote content
Description Label 28px Chapter Marker

Animation Effects

Text Animation

import { TypewriterText, StaggerContainer, HighlightText } from './components';

// 打字机效果
<TypewriterText text="逐字出现的文字" speed={2} />

// 逐行淡入
<StaggerContainer delay={20} staggerDelay={15}>
  <Paragraph>第一行</Paragraph>
  <Paragraph>第二行</Paragraph>
</StaggerContainer>

// 关键词高亮
<HighlightText 
  text="这是AI驱动的深度学习解决方案"
  keywords={["AI", "深度学习"]}
  highlightColor="#3b82f6"
/>

Number Rolling

import { AnimatedCounter } from './components';

<AnimatedCounter 
  value={300} 
  suffix="%"
  duration={60}
/>

TTS Voice Configuration

Option 1: Doubao TTS (Recommended ⭐)

Create voice.json:

{
  "provider": "doubao",
  "voice": "zh_male_jieshuoxiaoming_moon_bigtts",
  "speed": 1.0,
  "volume": 1.0,
  "pitch": 0
}

Environment Variable Settings:

export VOLCANO_TTS_APPID="your_app_id"
export VOLCANO_TTS_ACCESS_TOKEN="your_access_token"
export VOLCANO_TTS_SECRET_KEY="your_secret_key"

Option 2: System TTS (macOS)

If Doubao is temporarily unavailable, you can use the built-in system TTS:

say -v "Ting-Ting" "你的文案" -o output.aiff
# 转换为 mp3
ffmpeg -i output.aiff output.mp3

⚠️ System TTS audio quality is poor; it is recommended to prioritize Doubao TTS

Recommended Male Voices

Recommended for News/Science Videos:

  • zh_male_jieshuoxiaoming_moon_bigtts - Narrator Xiaoming ⭐ Most recommended, no permissions required
  • zh_male_xinwenxiaozhi_mars_bigtts - News Xiaozhi (permissions required)
  • zh_male_jingdianxiaoming_mars_bigtts - Classic Xiaoming (permissions required)

Emotional/Story Videos:

  • zh_male_xiaomo_mars_bigtts - Xiao Mo, warm and friendly
  • zh_male_xudong_conversation_wvae_bigtts - Happy Xiaodong, sunny and cheerful

Complete Example Scenario

[
  {
    "id": "intro",
    "searchQuery": "artificial intelligence technology",
    "title": "AI 革命",
    "subtitle": "正在改变我们的世界",
    "variant": "hero",
    "layout": {
      "imageLayout": "background",
      "imageAnimation": "zoom",
      "accentColor": "#3b82f6"
    }
  },
  {
    "id": "challenge",
    "searchQuery": "complex data visualization",
    "title": "数据挑战",
    "caption": "THE CHALLENGE",
    "variant": "content-rich",
    "layout": {
      "imageLayout": "side-right",
      "imageStyle": "card",
      "accentColor": "#ef4444"
    },
    "paragraphs": [
      "数据爆炸时代已经来临,企业面临着前所未有的挑战。",
      "传统方法已无法满足现代数据处理需求。"
    ],
    "bulletPoints": [
      "数据量年增长 300%",
      "人工处理效率低下",
      "决策成本急剧上升"
    ],
    "highlightKeywords": ["数据爆炸", "挑战"]
  },
  {
    "id": "result",
    "searchQuery": "success business growth",
    "title": "显著成效",
    "caption": "RESULTS",
    "variant": "content-rich",
    "layout": {
      "imageLayout": "side-left",
      "imageStyle": "rounded",
      "accentColor": "#10b981"
    },
    "stat": {
      "value": "500",
      "label": "客户增长率",
      "suffix": "%"
    },
    "quote": {
      "text": "这是我们做过的最明智的投资",
      "author": "某知名企业 CEO"
    }
  }
]

Quick Start

# 1. 创建项目
mkdir my-video && cd my-video
npm init -y
npm install @remotion/cli remotion react react-dom axios

# 2. 复制 skill 文件
cp -r ~/clawd/skills/remotion-synced-video/src .
cp ~/clawd/skills/remotion-synced-video/scripts .
cp ~/clawd/skills/remotion-synced-video/scenes.json .

# 3. 可选:设置 Unsplash API Key(用于兜底)
export UNSPLASH_ACCESS_KEY="your_key_here"

# 4. 搜索图片(自动多源搜索)
node scripts/search_images.js scenes.json --output ./public/images

# 5. 预览
npx remotion preview src/index.tsx

# 6. 渲染
npx remotion render src/index.tsx Scene-intro out/intro.mp4

Best Practices

🎙️ TTS Voice Selection

Strongly recommended to use Doubao TTS, it is much more natural than system TTS:

# 安装豆包 TTS skill
cd ~/clawd/skills/doubao-open-tts
pip install -r requirements.txt

# 设置环境变量
export VOLCANO_TTS_APPID="your_app_id"
export VOLCANO_TTS_ACCESS_TOKEN="your_access_token"
export VOLCANO_TTS_SECRET_KEY="your_secret_key"

Recommended Chinese Male Voices(for News/Science Videos):

Voice Voice Type Features Notes
Narrator Xiaoming zh_male_jieshuoxiaoming_moon_bigtts News broadcast style, clear and professional ⭐ Recommended, no additional permissions required
News Xiaozhi zh_male_xinwenxiaozhi_mars_bigtts Standard news broadcast male voice Permissions required
Classic Xiaoming zh_male_jingdianxiaoming_mars_bigtts Classic documentary male voice Permissions required
Happy Xiaodong zh_male_xudong_conversation_wvae_bigtts Sunny and cheerful, natural and friendly Emotional Voice

⚠️ Note: Some voices require applying for permissions in the Volcano Engine console; it is recommended to test with Narrator Xiaoming first.

📦 Video File Size Management

Telegram limits to 16MB, compression is needed:

# 压缩至 16MB 以内(1080p 保持可接受画质)
ffmpeg -i input.mp4 \
  -vcodec h264 -acodec aac \
  -b:v 1.5M -b:a 128k \
  -movflags +faststart \
  output_compressed.mp4

# 如需更小文件,降低视频码率
ffmpeg -i input.mp4 -b:v 800k -b:a 96k output.mp4

Bitrate Reference:

  • High quality:-b:v 3M (~25MB/minute)
  • Standard quality:-b:v 1.5M (~12MB/minute) ⭐ Recommended
  • Low quality:-b:v 800k (~6MB/minute)

🔧 Complete Generation Workflow

# 1. 创建项目
mkdir my-video && cd my-video
npm init -y
npm install @remotion/cli remotion react react-dom axios

# 2. 复制 skill 文件
cp -r ~/clawd/skills/remotion-synced-video/src .
cp ~/clawd/skills/remotion-synced-video/scenes.json .

# 3. 设置环境变量
export UNSPLASH_ACCESS_KEY="your_key_here"
export VOLCANO_TTS_APPID="your_app_id"
export VOLCANO_TTS_ACCESS_TOKEN="your_token"
export VOLCANO_TTS_SECRET_KEY="your_secret"

# 4. 生成 TTS 音频(使用豆包)
python ~/clawd/skills/doubao-open-tts/scripts/tts.py "你的文案" \
  -v zh_male_jieshuoxiaoming_moon_bigtts \
  -o public/audio/scene1.mp3

# 5. 搜索图片
node src/../scripts/search_images.js scenes.json public/images

# 6. 测量音频时长并生成配置文件(关键步骤!)
# 这确保每个场景的时长与音频完全同步
echo "{"> audio-durations.json
for file in public/audio/*.mp3; do
  filename=$(basename "$file" .mp3)
  # 获取音频时长并加2秒缓冲
  duration=$(ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 "$file" | cut -d. -f1)
  duration=$((duration + 2))
  echo "  \"$filename\": $duration," >> audio-durations.json
done
# 删除最后一个逗号并关闭 JSON
truncate -s-2 audio-durations.json
echo "" >> audio-durations.json
echo "}" >> audio-durations.json

# 7. 预览
npx remotion preview src/index.tsx

# 8. 渲染所有场景
npx remotion render src/index.tsx Scene-intro out/intro.mp4
npx remotion render src/index.tsx Scene-history out/history.mp4
# ... 渲染其他场景

# 9. 拼接视频
ffmpeg -f concat -i filelist.txt -c copy output/final.mp4

# 10. 压缩(如需)
ffmpeg -i output/final.mp4 -b:v 1.5M -b:a 128k output/final_compressed.mp4

💡 Content Creation Tips

  1. Script length: Keep each scene within 50-80 characters, corresponding to 5-10 seconds of audio
  2. Total duration: Short videos are recommended to be 30-60 seconds, with 4-6 scenes
  3. Image search terms: Use English keywords, such as "artificial intelligence technology"、"neural network"
  4. highlightKeywords: Use highlights on key concepts to enhance memory retention

🐛 Common Troubleshooting

Issue: TTS generation failed

Solution: 检查 VOLCANO_TTS_* 环境变量是否设置正确

Issue: Voice reports permission error

Solution: 更换为解说小明 (zh_male_jieshuoxiaoming_moon_bigtts) 或其他无需权限的音色

Issue: Video file is too large

Solution: 使用 FFmpeg 压缩,降低 -b:v 码率参数

Issue: The scene switches before the voiceover finishes

原因:场景时长固定,没有根据实际音频长度调整
Solution: 
1. 使用 ffprobe 测量每个音频的实际时长
2. 生成 audio-durations.json 配置文件
3. 在 index.tsx 中读取配置并动态计算帧数

示例代码:
// index.tsx
import audioDurations from '../audio-durations.json';

function getAudioDuration(sceneId: string): number {
  return (audioDurations as Record<string, number>)[sceneId] || 5;
}

// 在 Composition 中使用
<Composition
  durationInFrames={getAudioDuration(scene.id) * 30} // 30fps
  ...
/>

🎯 Best Practices for Audio Duration Synchronization

Why is synchronization needed?

When a video is assembled from multiple scenes, each scene'svisual duration must exactly match the audio duration, otherwise the following will occur:

  • ❌ The voice hasn't finished yet, but the visuals cut to the next scene
  • ❌ The voice has ended, but the visuals are still on the current scene

Solution: Audio duration configuration

Step 1: Create an audio duration measurement script

Create scripts/measure-audio.sh:

#!/bin/bash
AUDIO_DIR="public/audio"
OUTPUT_FILE="audio-durations.json"

echo "{"
first=true
for file in "$AUDIO_DIR"/*.mp3; do
  filename=$(basename "$file" .mp3)
  duration=$(ffprobe -v error -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 "$file" | cut -d. -f1)
  if [ -z "$duration" ]; then duration=5; fi
  duration=$((duration + 2))  # 加2秒缓冲
  
  if [ "$first" = true ]; then first=false; else echo ","; fi
  echo "  \"$filename\": $duration"
done
echo ""
echo "}"

Step 2: Update index.tsx to read the durations

import {Composition, registerRoot} from 'remotion';
import {SceneTemplate} from './scenes/SceneTemplate';
import audioDurations from '../audio-durations.json'; // 导入配置

const FPS = 30;

// 从配置文件获取音频时长
function getAudioDuration(sceneId: string): number {
  return (audioDurations as Record<string, number>)[sceneId] || 5;
}

// 计算帧数
function calculateFrames(durationInSeconds: number): number {
  return Math.ceil(durationInSeconds * FPS);
}

export const RemotionRoot: React.FC = () => {
  return (
    <>
      {scenes.map((scene) => (
        <Composition
          key={scene.id}
          id={`Scene-${scene.id}`}
          component={SceneTemplate}
          durationInFrames={calculateFrames(getAudioDuration(scene.id))}
          fps={FPS}
          width={1920}
          height={1080}
          defaultProps={{...}}
        />
      ))}
    </>
  );
};

registerRoot(RemotionRoot);

Step 3: Perform the measurement in the rendering flow

# 生成 TTS 音频后,必须执行时长测量
./scripts/measure-audio.sh > audio-durations.json

# 然后再渲染
./scripts/render.sh

Duration configuration example

Generated audio-durations.json format:

{
  "intro": 7,
  "gpt4o": 16,
  "xai": 15,
  "google": 15,
  "moltbot": 11,
  "datacenter": 16,
  "outro": 8
}

💡 Tip: The values are in seconds and already include a +2 second buffer to ensure the voice plays completely.


FAQ

Q: How do fonts adapt to different resolutions?

A: Font sizes are designed based on 1920x1080 and will automatically scale when played at 4K. To adjust, use the textScale property.

Q: How do I choose an image layout?

A: For short, punchy titles use background, and when you need to show a lot of content use side-right or side-left。

Q: How do I customize the animation speed?

A: Most components support the delay and duration parameters, in frames (30fps = 1 second).

Q: Do statistics support decimals?

A: Yes, use the string format value: "99.7" or combine it with formatNumber: false to display decimals.


Pro Tip: Using highlightKeywords can make core concepts more eye-catching in the video and strengthen audience memory!