Stitch → Remotion 逐步解說影片
限制: 僅當使用者明確提及「Stitch」與逐步解說影片、示範或 Remotion 時,才使用此技能。
您是一位影片製作專家,負責從 Stitch 應用程式設計稿建立逐步解說影片。您將擷取 Stitch 螢幕截圖,並建構 Remotion 組合 — 包含滑入轉場、縮放動畫與文字疊加。
先決條件
- Stitch MCP 伺服器(或已知的畫面 ID)
- Node.js 18+ 和 npm
- Remotion CLI(
npm install -g remotion或透過npx使用)
步驟 1:收集 Stitch 素材
探索畫面
- 執行
list_tools→ 找到 Stitch MCP 前綴 - 呼叫
[前綴]:list_projects→ 選擇專案 - 使用
projects/[專案ID]呼叫[前綴]:list_screens→ 列出所有畫面 - 對每個要放入影片的畫面,使用數位 ID 呼叫
[前綴]:get_screen
下載螢幕截圖
對每個畫面:
# 將螢幕截圖下載到 assets 目錄
curl -L "[screenshot.downloadUrl]" -o "video/public/assets/[畫面名稱].png"
或使用 fetch 腳本:
bash scripts/fetch-stitch.sh "[htmlCode.downloadUrl]" "temp/[畫面名稱].html"
# 螢幕截圖是分開的 — 透過 curl 下載截圖網址
建立畫面清單
建立 screens.json 來描述影片:
{
"projectName": "My App",
"fps": 30,
"screens": [
{
"id": "home",
"title": "首頁畫面",
"description": "主要儀表板,顯示關鍵指標",
"imagePath": "./public/assets/home.png",
"width": 390,
"height": 844,
"durationSeconds": 4
},
{
"id": "profile",
"title": "使用者個人資料",
"description": "設定與帳號管理",
"imagePath": "./public/assets/profile.png",
"width": 390,
"height": 844,
"durationSeconds": 3
}
]
}
步驟 2:設定 Remotion 專案
# 在工作目錄內建立新的 Remotion 專案
cd video
npm create video@latest -- --blank
cd walkthrough-video
npm install @remotion/transitions
步驟 3:建構組合
ScreenSlide 元件
// video/src/ScreenSlide.tsx
import { AbsoluteFill, Img, interpolate, spring, useCurrentFrame, useVideoConfig } from 'remotion'
interface ScreenSlideProps {
/** 螢幕截圖路徑 */
imagePath: string
/** 作為疊加層顯示的畫面標題 */
title: string
/** 輔助說明文字 */
description: string
/** 是否在顯示時稍微縮放 */
withZoom?: boolean
}
/**
* 單一畫面投影片,可選縮放效果與文字疊加。
* 淡入、停留、再淡出。
*/
export function ScreenSlide({ imagePath, title, description, withZoom = true }: ScreenSlideProps) {
const frame = useCurrentFrame()
const { fps, durationInFrames } = useVideoConfig()
// 前 15 禎淡入
const fadeIn = spring({ fps, frame, config: { damping: 200 } })
// 細微縮放:100% → 105% 持續整個時長
const scale = withZoom
? interpolate(frame, [0, durationInFrames], [1, 1.05], { extrapolateRight: 'clamp' })
: 1
return (
<AbsoluteFill style={{ backgroundColor: '#000' }}>
{/* 螢幕截圖 */}
<AbsoluteFill style={{ opacity: fadeIn, transform: `scale(${scale})`, transformOrigin: 'center' }}>
<Img src={imagePath} style={{ width: '100%', height: '100%', objectFit: 'contain' }} />
</AbsoluteFill>
{/* 底部文字疊加 */}
<AbsoluteFill
style={{
justifyContent: 'flex-end',
padding: '40px 60px',
background: 'linear-gradient(transparent, rgba(0,0,0,0.7))',
opacity: fadeIn,
}}
>
<h2 style={{ color: '#fff', fontSize: 36, fontWeight: 700, margin: 0 }}>{title}</h2>
{description ? (
<p style={{ color: 'rgba(255,255,255,0.8)', fontSize: 20, margin: '8px 0 0' }}>
{description}
</p>
) : null}
</AbsoluteFill>
</AbsoluteFill>
)
}
逐步解說組合
// video/src/WalkthroughComposition.tsx
import { Series, TransitionSeries } from '@remotion/transitions'
import { fade } from '@remotion/transitions/fade'
import { slide } from '@remotion/transitions/slide'
import screensData from '../../screens.json'
import { ScreenSlide } from './ScreenSlide'
const TRANSITION_FRAMES = 15 // 30fps 下約 0.5 秒
/**
* 主要逐步解說組合 — 每個畫面一個投影片,使用淡入/滑入轉場。
*/
export function WalkthroughComposition() {
return (
<TransitionSeries>
{screensData.screens.map((screen, i) => (
<>
<TransitionSeries.Sequence
key={screen.id}
durationInFrames={screen.durationSeconds * screensData.fps}
>
<ScreenSlide
imagePath={screen.imagePath}
title={screen.title}
description={screen.description}
/>
</TransitionSeries.Sequence>
{/* 在畫面之間加入轉場(除了最後一個畫面之後) */}
{i < screensData.screens.length - 1 && (
<TransitionSeries.Transition
key={`t-${screen.id}`}
timing={fade({ durationInFrames: TRANSITION_FRAMES })}
/>
)}
</>
))}
</TransitionSeries>
)
}
在 Root.tsx 中註冊
// video/src/Root.tsx
import { Composition } from 'remotion'
import { WalkthroughComposition } from './WalkthroughComposition'
import screensData from '../../screens.json'
const TOTAL_FRAMES = screensData.screens.reduce(
(acc, s) => acc + s.durationSeconds * screensData.fps,
0
)
export const RemotionRoot = () => (
<>
<Composition
id="Walkthrough"
component={WalkthroughComposition}
durationInFrames={TOTAL_FRAMES}
fps={screensData.fps}
width={screensData.screens[0]?.width ?? 390}
height={screensData.screens[0]?.height ?? 844}
/>
</>
)
步驟 4:預覽與渲染
# 在瀏覽器中預覽
cd video/walkthrough-video
npm run dev
# 渲染為 MP4
npx remotion render Walkthrough output.mp4
# 較高品質渲染
npx remotion render Walkthrough output.mp4 --jpeg-quality 95 --concurrency 4
常見影片風格
| 風格 | 設定 |
|---|---|
| 快速示範(1–2 分鐘) | 每畫面 2–3 秒,淡入轉場,僅標題 |
| 功能逐步解說 | 每畫面 4–5 秒,縮放 + 滑入,標題 + 說明 |
| 簡報投影片 | 每畫面 5–8 秒,僅淡入,完整說明疊加 |
| 社交媒體短片 | 每畫面 1–2 秒,快速切換,音樂背景 |
檔案結構
project/
├── screens.json ← 畫面清單
├── scripts/fetch-stitch.sh ← GCS 下載器
└── video/
├── public/
│ └── assets/ ← 已下載的螢幕截圖
└── walkthrough-video/
├── src/
│ ├── WalkthroughComposition.tsx
│ ├── ScreenSlide.tsx
│ └── Root.tsx
├── remotion.config.ts
└── package.json
疑難排解
| 問題 | 解決方案 |
|---|---|
| 螢幕截圖模糊 | 下載全解析度:直接使用螢幕截圖網址,而非縮圖 |
| 版面不符 | 將 Remotion 組合尺寸設定為與 get_screen 回傳的畫面 width 與 height 相同 |
| 轉場過於突兀 | 增加 TRANSITION_FRAMES 或從 slide 改為 fade |
| 建置失敗(ESM 問題) | 在 package.json 中加入 "type": "module",並檢查 Remotion 版本相容性 |
| MP4 無法播放 | 檢查 FFmpeg 是否已安裝:ffmpeg -version |
參考資料
- Remotion 文件:https://www.remotion.dev/docs/
- Remotion 轉場:https://www.remotion.dev/docs/transitions
scripts/fetch-stitch.sh— 可靠的 GCS 下載器stitch-mcp-list-screens— 探索 Stitch 專案中的畫面stitch-mcp-get-screen— 取得螢幕截圖下載網址