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 접두사 찾기[prefix]:list_projects호출 → 프로젝트 선택[prefix]:list_screens호출projects/[projectId]→ 모든 스크린 나열- 비디오에 포함할 각 스크린에 대해 숫자 ID로
[prefix]:get_screen호출
스크린샷 다운로드
각 스크린에 대해:
# assets 디렉토리로 스크린샷 다운로드
curl -L "[screenshot.downloadUrl]" -o "video/public/assets/[screen-name].png"
또는 fetch 스크립트 사용:
bash scripts/fetch-stitch.sh "[htmlCode.downloadUrl]" "temp/[screen-name].html"
# 스크린샷은 별도 — 스크린샷 URL로 curl을 통해 다운로드
스크린 매니페스트 생성
비디오를 설명하는 screens.json 생성:
{
"projectName": "내 앱",
"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
문제 해결
| 문제 | 해결책 |
|---|---|
| 흐릿한 스크린샷 | 전체 해상도 다운로드: 썸네일이 아닌 스크린샷 URL 직접 사용 |
| 레이아웃 불일치 | 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— 스크린샷 다운로드 URL 가져오기