walkthrough-video
Compare original and translation side by side
🇺🇸
Original
English🇨🇳
Translation
ChineseWalkthrough Video Generator
演示视频生成器
Create professional walkthrough videos from app screenshots or live sites using Remotion. Produces smooth, polished MP4 videos with transitions, zoom effects, and text overlays.
使用Remotion从应用截图或线上站点创建专业的流程演示视频,可输出带有转场、缩放效果和文字叠加的流畅精致MP4视频。
Overview
概述
This skill takes a set of screenshots (or captures them from a running app) and orchestrates them into a Remotion video composition with:
- Smooth transitions between screens (fade, slide, wipe)
- Zoom effects to highlight specific UI areas
- Text overlays with titles, descriptions, and callouts
- Progress indicators showing position in the walkthrough
- Optional voiceover narration track
本技能接收一组截图(或从运行中的应用捕获截图),并将其编排为Remotion视频合成文件,具备以下特性:
- 页面间流畅转场(淡入淡出、滑动、擦除)
- 缩放效果,用于高亮特定UI区域
- 文字叠加层,支持标题、描述和标注提示
- 进度指示器,显示当前演示所处位置
- 可选旁白配音轨道
Prerequisites
前置要求
- Node.js 18+ installed
- Screenshots of the app (or a running app to screenshot)
- No Remotion experience needed — the skill generates all code
- 已安装 Node.js 18+版本
- 准备好应用截图(或可运行的用于截图的应用)
- 无需Remotion使用经验——本技能会自动生成所有代码
Workflow
工作流程
Step 1: Gather Screenshots
步骤1:收集截图
Choose one approach:
选择以下任意一种方案:
Option A: From Existing Screenshots
方案A:使用现有截图
If the user already has screenshots (e.g. from or ):
design-loopproduct-showcaseRead screenshots from:
- .design/screenshots/
- .jez/screenshots/
- User-specified directorySort them in walkthrough order (alphabetically by filename, or as user specifies).
如果用户已经准备好了截图(例如来自或的产出):
design-loopproduct-showcase从以下位置读取截图:
- .design/screenshots/
- .jez/screenshots/
- 用户指定的目录按照演示顺序排序(按文件名自动排序,或按照用户指定的顺序排序)。
Option B: Capture from Running App
方案B:从运行中的本地应用捕获
If the app is running locally:
- Start Playwright CLI session
- Navigate through each screen in sequence
- Screenshot at consistent dimensions (1280x720 recommended for video)
- Save to
video/public/screens/
bash
playwright-cli -s=walkthrough open http://localhost:3000
playwright-cli -s=walkthrough resize 1280 720
playwright-cli -s=walkthrough screenshot --filename=video/public/screens/01-home.png如果应用正在本地运行:
- 启动Playwright CLI会话
- 按顺序访问每个页面
- 以统一尺寸截图(视频推荐使用1280x720分辨率)
- 保存到目录
video/public/screens/
bash
playwright-cli -s=walkthrough open http://localhost:3000
playwright-cli -s=walkthrough resize 1280 720
playwright-cli -s=walkthrough screenshot --filename=video/public/screens/01-home.pngNavigate to next page...
导航到下一页...
playwright-cli -s=walkthrough screenshot --filename=video/public/screens/02-dashboard.png
undefinedplaywright-cli -s=walkthrough screenshot --filename=video/public/screens/02-dashboard.png
undefinedOption C: From Live URL
方案C:从线上URL捕获
Same as Option B but with a public URL. Screenshot each key page.
和方案B逻辑一致,仅将地址替换为公开URL,对每个核心页面截图即可。
Step 2: Create Screen Manifest
步骤2:创建页面清单文件
Build a describing the walkthrough:
screens.jsonjson
{
"projectName": "My App Walkthrough",
"fps": 30,
"width": 1280,
"height": 720,
"screens": [
{
"id": "home",
"title": "Welcome to MyApp",
"description": "The landing page introduces the core value proposition",
"imagePath": "screens/01-home.png",
"durationSeconds": 4,
"transition": "fade",
"zoomTarget": null
},
{
"id": "dashboard",
"title": "Your Dashboard",
"description": "See all your projects at a glance",
"imagePath": "screens/02-dashboard.png",
"durationSeconds": 5,
"transition": "slide-left",
"zoomTarget": { "x": 100, "y": 200, "width": 400, "height": 300, "delay": 2 }
}
]
}| Field | Type | Description |
|---|---|---|
| string | Unique screen identifier |
| string | Text overlay title |
| string | Subtitle or narration text |
| string | Path relative to |
| number | How long to show this screen |
| string | |
| object/null | If set, zoom into this region after |
编写文件描述演示流程:
screens.jsonjson
{
"projectName": "My App Walkthrough",
"fps": 30,
"width": 1280,
"height": 720,
"screens": [
{
"id": "home",
"title": "Welcome to MyApp",
"description": "The landing page introduces the core value proposition",
"imagePath": "screens/01-home.png",
"durationSeconds": 4,
"transition": "fade",
"zoomTarget": null
},
{
"id": "dashboard",
"title": "Your Dashboard",
"description": "See all your projects at a glance",
"imagePath": "screens/02-dashboard.png",
"durationSeconds": 5,
"transition": "slide-left",
"zoomTarget": { "x": 100, "y": 200, "width": 400, "height": 300, "delay": 2 }
}
]
}| 字段 | 类型 | 说明 |
|---|---|---|
| string | 页面唯一标识 |
| string | 文字叠加层标题 |
| string | 副标题或旁白文本 |
| string | 相对于 |
| number | 该页面展示时长(秒) |
| string | |
| object/null | 如配置该项,会在 |
Step 3: Scaffold Remotion Project
步骤3:初始化Remotion项目
If no Remotion project exists:
bash
mkdir -p video
cd video
npm init -y
npm install remotion @remotion/cli @remotion/transitions react react-dom
npm install -D typescript @types/reactCreate the project structure:
video/
├── src/
│ ├── Root.tsx # Remotion entry point
│ ├── WalkthroughComposition.tsx # Main composition
│ ├── components/
│ │ ├── ScreenSlide.tsx # Individual screen display
│ │ ├── TextOverlay.tsx # Title/description overlay
│ │ ├── ProgressBar.tsx # Walkthrough progress indicator
│ │ └── ZoomEffect.tsx # Zoom into regions
│ └── config.ts # Load screens.json, calculate durations
├── public/
│ └── screens/ # Screenshot assets
│ ├── 01-home.png
│ └── 02-dashboard.png
├── screens.json # Screen manifest
├── remotion.config.ts
├── tsconfig.json
└── package.json如果不存在Remotion项目:
bash
mkdir -p video
cd video
npm init -y
npm install remotion @remotion/cli @remotion/transitions react react-dom
npm install -D typescript @types/react创建项目结构:
video/
├── src/
│ ├── Root.tsx # Remotion入口文件
│ ├── WalkthroughComposition.tsx # 主合成文件
│ ├── components/
│ │ ├── ScreenSlide.tsx # 单页面展示组件
│ │ ├── TextOverlay.tsx # 标题/描述叠加层
│ │ ├── ProgressBar.tsx # 演示进度指示器
│ │ └── ZoomEffect.tsx # 区域缩放效果
│ └── config.ts # 加载screens.json,计算时长
├── public/
│ └── screens/ # 截图资源
│ ├── 01-home.png
│ └── 02-dashboard.png
├── screens.json # 页面清单文件
├── remotion.config.ts
├── tsconfig.json
└── package.jsonStep 4: Generate Remotion Components
步骤4:生成Remotion组件
Generate each component file. Key patterns:
生成每个组件文件,核心代码模式如下:
Root.tsx
Root.tsx
tsx
import { Composition } from "remotion";
import { WalkthroughComposition } from "./WalkthroughComposition";
import { screens, totalDurationInFrames, FPS, WIDTH, HEIGHT } from "./config";
export const RemotionRoot = () => (
<Composition
id="Walkthrough"
component={WalkthroughComposition}
durationInFrames={totalDurationInFrames}
fps={FPS}
width={WIDTH}
height={HEIGHT}
defaultProps={{ screens }}
/>
);tsx
import { Composition } from "remotion";
import { WalkthroughComposition } from "./WalkthroughComposition";
import { screens, totalDurationInFrames, FPS, WIDTH, HEIGHT } from "./config";
export const RemotionRoot = () => (
<Composition
id="Walkthrough"
component={WalkthroughComposition}
durationInFrames={totalDurationInFrames}
fps={FPS}
width={WIDTH}
height={HEIGHT}
defaultProps={{ screens }}
/>
);ScreenSlide.tsx Pattern
ScreenSlide.tsx 代码模式
tsx
import { AbsoluteFill, Img, spring, useCurrentFrame, useVideoConfig } from "remotion";
interface ScreenSlideProps {
imageSrc: string;
title: string;
description: string;
}
export const ScreenSlide: React.FC<ScreenSlideProps> = ({ imageSrc, title, description }) => {
const frame = useCurrentFrame();
const { fps } = useVideoConfig();
// Fade in
const opacity = spring({ frame, fps, config: { damping: 20 } });
// Subtle zoom (Ken Burns effect)
const scale = 1 + frame * 0.0002;
return (
<AbsoluteFill style={{ backgroundColor: "#000" }}>
<Img
src={imageSrc}
style={{
width: "100%",
height: "100%",
objectFit: "contain",
opacity,
transform: `scale(${scale})`,
}}
/>
{/* Text overlay at bottom */}
<div style={{
position: "absolute",
bottom: 40,
left: 40,
right: 40,
opacity: spring({ frame: frame - 15, fps, config: { damping: 20 } }),
}}>
<h2 style={{ color: "#fff", fontSize: 32, fontWeight: 700, textShadow: "0 2px 8px rgba(0,0,0,0.8)" }}>
{title}
</h2>
<p style={{ color: "#ccc", fontSize: 18, textShadow: "0 1px 4px rgba(0,0,0,0.8)" }}>
{description}
</p>
</div>
</AbsoluteFill>
);
};tsx
import { AbsoluteFill, Img, spring, useCurrentFrame, useVideoConfig } from "remotion";
interface ScreenSlideProps {
imageSrc: string;
title: string;
description: string;
}
export const ScreenSlide: React.FC<ScreenSlideProps> = ({ imageSrc, title, description }) => {
const frame = useCurrentFrame();
const { fps } = useVideoConfig();
// 淡入效果
const opacity = spring({ frame, fps, config: { damping: 20 } });
// 轻微缩放(肯·伯恩斯效应)
const scale = 1 + frame * 0.0002;
return (
<AbsoluteFill style={{ backgroundColor: "#000" }}>
<Img
src={imageSrc}
style={{
width: "100%",
height: "100%",
objectFit: "contain",
opacity,
transform: `scale(${scale})`,
}}
/>
{/* 底部文字叠加层 */}
<div style={{
position: "absolute",
bottom: 40,
left: 40,
right: 40,
opacity: spring({ frame: frame - 15, fps, config: { damping: 20 } }),
}}>
<h2 style={{ color: "#fff", fontSize: 32, fontWeight: 700, textShadow: "0 2px 8px rgba(0,0,0,0.8)" }}>
{title}
</h2>
<p style={{ color: "#ccc", fontSize: 18, textShadow: "0 1px 4px rgba(0,0,0,0.8)" }}>
{description}
</p>
</div>
</AbsoluteFill>
);
};Transitions Between Screens
页面间转场效果
Use for transitions:
@remotion/transitionstsx
import { TransitionSeries } from "@remotion/transitions";
import { fade } from "@remotion/transitions/fade";
import { slide } from "@remotion/transitions/slide";
// In WalkthroughComposition:
<TransitionSeries>
{screens.map((screen, i) => (
<TransitionSeries.Sequence
key={screen.id}
durationInFrames={screen.durationSeconds * FPS}
>
<ScreenSlide {...screen} />
</TransitionSeries.Sequence>
// Add transition between screens (not after last)
{i < screens.length - 1 && (
<TransitionSeries.Transition
presentation={getTransition(screens[i + 1].transition)}
timing={springTiming({ config: { damping: 20 }, durationInFrames: 15 })}
/>
)}
))}
</TransitionSeries>使用实现转场:
@remotion/transitionstsx
import { TransitionSeries } from "@remotion/transitions";
import { fade } from "@remotion/transitions/fade";
import { slide } from "@remotion/transitions/slide";
// 在WalkthroughComposition组件中:
<TransitionSeries>
{screens.map((screen, i) => (
<TransitionSeries.Sequence
key={screen.id}
durationInFrames={screen.durationSeconds * FPS}
>
<ScreenSlide {...screen} />
</TransitionSeries.Sequence>
// 在页面间添加转场(最后一页后不需要)
{i < screens.length - 1 && (
<TransitionSeries.Transition
presentation={getTransition(screens[i + 1].transition)}
timing={springTiming({ config: { damping: 20 }, durationInFrames: 15 })}
/>
)}
))}
</TransitionSeries>Step 5: Preview and Refine
步骤5:预览与调整
bash
cd video
npx remotion studioThis opens a browser-based preview. Check:
- Timing feels right for each screen
- Transitions are smooth
- Text overlays are readable
- Zoom targets hit the right area
- Progress bar (if included) is accurate
bash
cd video
npx remotion studio该命令会打开浏览器端预览页面,检查以下内容:
- 每个页面的展示时长合理
- 转场效果流畅
- 文字叠加层清晰可读
- 缩放目标区域准确
- 进度条(如启用)显示正确
Step 6: Render the Video
步骤6:渲染视频
bash
cd video
npx remotion render Walkthrough output.mp4 --codec h264For higher quality:
bash
npx remotion render Walkthrough output.mp4 --codec h264 --quality 90For web-optimised (smaller file):
bash
npx remotion render Walkthrough output.webm --codec vp8bash
cd video
npx remotion render Walkthrough output.mp4 --codec h264如需更高画质:
bash
npx remotion render Walkthrough output.mp4 --codec h264 --quality 90如需网页优化版本(更小文件体积):
bash
npx remotion render Walkthrough output.webm --codec vp8Advanced Features
高级功能
Zoom to Region
区域缩放
Zoom into a specific area of the screen to highlight a feature:
tsx
// In ZoomEffect.tsx — interpolate scale and translate
const zoomScale = interpolate(frame, [delayFrames, delayFrames + 30], [1, 2.5], {
extrapolateRight: "clamp",
});
const translateX = interpolate(frame, [delayFrames, delayFrames + 30], [0, -targetX], {
extrapolateRight: "clamp",
});缩放至屏幕的特定区域以高亮功能点:
tsx
// 在ZoomEffect.tsx中 — 插值计算缩放比例和位移
const zoomScale = interpolate(frame, [delayFrames, delayFrames + 30], [1, 2.5], {
extrapolateRight: "clamp",
});
const translateX = interpolate(frame, [delayFrames, delayFrames + 30], [0, -targetX], {
extrapolateRight: "clamp",
});Animated Callout Circles
动态标注圆圈
Draw attention to UI elements:
tsx
// Pulsing circle that appears at a specific point
const scale = spring({ frame: frame - delay, fps, config: { damping: 8, stiffness: 80 } });
<div style={{
position: "absolute",
left: x - 20, top: y - 20,
width: 40, height: 40,
borderRadius: "50%",
border: "3px solid #3B82F6",
transform: `scale(${scale})`,
opacity: Math.min(1, scale),
}} />吸引用户注意UI元素:
tsx
// 在指定位置显示脉动圆圈
const scale = spring({ frame: frame - delay, fps, config: { damping: 8, stiffness: 80 } });
<div style={{
position: "absolute",
left: x - 20, top: y - 20,
width: 40, height: 40,
borderRadius: "50%",
border: "3px solid #3B82F6",
transform: `scale(${scale})`,
opacity: Math.min(1, scale),
}} />Background Music
背景音乐
Add a subtle background track:
tsx
import { Audio } from "remotion";
<Audio src={staticFile("music/background.mp3")} volume={0.15} />添加轻柔的背景音轨:
tsx
import { Audio } from "remotion";
<Audio src={staticFile("music/background.mp3")} volume={0.15} />Intro and Outro Slides
开场和结束页
Add title card at start and CTA at end:
tsx
// First sequence: Title card (3 seconds)
<TransitionSeries.Sequence durationInFrames={90}>
<TitleCard projectName="MyApp" tagline="The future of project management" />
</TransitionSeries.Sequence>
// ... screen sequences ...
// Last sequence: CTA card (4 seconds)
<TransitionSeries.Sequence durationInFrames={120}>
<CtaCard url="myapp.com" text="Try it free" />
</TransitionSeries.Sequence>在开头添加标题卡片,结尾添加行动引导卡片:
tsx
// 第一个序列:标题卡片(3秒)
<TransitionSeries.Sequence durationInFrames={90}>
<TitleCard projectName="MyApp" tagline="The future of project management" />
</TransitionSeries.Sequence>
// ... 页面序列 ...
// 最后一个序列:行动引导卡片(4秒)
<TransitionSeries.Sequence durationInFrames={120}>
<CtaCard url="myapp.com" text="Try it free" />
</TransitionSeries.Sequence>Transition Reference
转场效果参考
| Name | Effect | Best for |
|---|---|---|
| Cross-fade dissolve | Default, works everywhere |
| New screen slides in from right | Sequential flow (next page) |
| New screen slides in from left | Going back |
| New screen slides in from bottom | Drill-down into detail |
| Wipe transition | Dramatic reveal |
| Hard cut | Quick comparison |
| 名称 | 效果 | 适用场景 |
|---|---|---|
| 交叉淡入淡出 | 默认效果,通用所有场景 |
| 新页面从右侧滑入 | 顺序流程(下一页) |
| 新页面从左侧滑入 | 返回上一页场景 |
| 新页面从底部滑入 | 进入详情页场景 |
| 擦除转场 | 戏剧化展示场景 |
| 硬切 | 快速对比场景 |
Output Options
输出选项
| Format | Command | Use case |
|---|---|---|
| MP4 (H.264) | | Universal compatibility |
| WebM (VP8) | | Web embedding, smaller files |
| GIF | | Short loops, social media |
| PNG sequence | | Post-production editing |
| 格式 | 命令 | 适用场景 |
|---|---|---|
| MP4 (H.264) | | 通用兼容场景 |
| WebM (VP8) | | 网页嵌入场景,文件体积更小 |
| GIF | | 短循环内容,社交媒体场景 |
| PNG序列 | | 后期编辑场景 |
Tips
使用提示
- 1280x720 is ideal for web walkthrough videos (good quality, reasonable file size)
- 3-5 seconds per screen feels natural — longer for complex screens
- Fade is the safest transition — use others sparingly for emphasis
- Text overlays need contrast — use text-shadow or semi-transparent background
- Ken Burns effect (subtle zoom) prevents static screenshots from feeling dead
- Preview before rendering — saves time vs full renders
npx remotion studio - Keep it under 90 seconds — attention drops sharply after that
- 1280x720是网页演示视频的理想分辨率(画质优秀,文件体积合理)
- 每个页面展示3-5秒体验最自然,复杂页面可适当延长
- 淡入淡出是最稳妥的转场效果——其他效果按需少量使用用于强调
- 文字叠加层需要足够对比度——使用文字阴影或半透明背景提升可读性
- **肯·伯恩斯效应(轻微缩放)**可避免静态截图显得呆板
- 渲染前先预览——比全量渲染节省大量时间
npx remotion studio - 视频时长控制在90秒以内——超过该时长用户注意力会大幅下降
Common Pitfalls
常见问题
- ❌ Using screenshots at different dimensions (causes scaling issues)
- ❌ Too many transition types (pick 1-2 and stay consistent)
- ❌ Text overlays that are too small or lack contrast
- ❌ No intro/outro — video feels abrupt
- ❌ Rendering before previewing (wastes time on fixable issues)
- ❌ Forgetting for assets in
staticFile()directorypublic/
- ❌ 使用不同尺寸的截图(会导致缩放异常)
- ❌ 使用过多转场类型(选择1-2种保持风格一致即可)
- ❌ 文字叠加层太小或对比度不足
- ❌ 缺少开场/结束页——视频会显得很突兀
- ❌ 预览前就渲染(会在可修复的问题上浪费大量时间)
- ❌ 忘记使用引用
staticFile()目录下的资源public/