# task-436.3 보고서: ThreadAuto Remotion Phase 3 — 영상 파이프라인 전환 (숏폼)

**팀**: dev1 (헤르메스 팀장, 이리스/불칸/아르고스)
**일시**: 2026-03-10
**레벨**: Lv.3

---

## 작업 내용

### 3-1. ShortForm Composition 등록

- `src/compositions/ShortForm/index.tsx` 생성
- 규격: 1080x1920, 30fps (Threads/Reels 세로 형식)
- Root.tsx에 `<Composition id="ShortForm">` Video 등록
- `ShortFormProps` 타입: scenes 배열, theme, audioSrc, transitionType, transitionDuration

### 3-2. Scene 컴포넌트 5종

마스터플랜 매핑표 기반 구현:

- **HookScene** (`src/scenes/HookScene.tsx`): useCurrentFrame() + interpolate() 타이틀 fade-in/translateY + spring() scale 바운스. 자동 fade-out.
- **ChecklistScene** (`src/scenes/ChecklistScene.tsx`): Sequence 컴포넌트로 20프레임 간격 항목별 순차 등장. spring() + interpolate()로 opacity/translateX 애니메이션. 체크마크(✓) 원형 배지.
- **DataScene** (`src/scenes/DataScene.tsx`): 숫자 카운트업 애니메이션 (duration의 80% 동안). LabelDisplay fade-in + CounterDisplay spring scale.
- **InfoScene** (`src/scenes/InfoScene.tsx`): title/body 쌍으로 InfoCard 생성, 18프레임 간격 순차 등장. glass-morphism 카드 (backdrop-filter, box-shadow).
- **CtaScene** (`src/scenes/CtaScene.tsx`): spring() 바운스 (stiffness:300) 큰 타이틀. 배경 글로우 원, 화살표 bounce, 브랜드 아웃트로.

### 3-3. 전환 효과

- `@remotion/transitions` 패키지 활용 (v4)
- `fade()`, `slide({direction: "from-right"})`, `wipe({direction: "from-right"})` 3종 구현
- `TransitionSeries` + `linearTiming`으로 Scene 간 전환 연결
- 기본 전환 시간: 15프레임 (0.5초 at 30fps)

### 3-4. Audio 컴포넌트

- `<Audio>` 컴포넌트로 BGM/TTS MP3 삽입
- `audioSrc` props로 파일 경로 전달
- 영상 전체 duration에 맞춰 재생

### 3-5. Python 영상 파이프라인 연결

`render_bridge.py`에 Phase 3 함수 추가:
- `RemotionBridge._build_render_command()`: `npx remotion render` CLI 명령어 생성
- `RemotionBridge.render_video()`: MP4 영상 렌더링 (타임아웃 기본 600초, 출력 디렉토리 자동 생성)
- `slides_to_scenes()`: 카드뉴스 슬라이드 → ShortForm scenes 변환 (cover→hook, card_list→checklist, detail→data, body→info, cta→cta)
- `render_shortform()`: 기존 `generate_slideshow()` 호환 래퍼. 슬라이드/테마를 받아 Remotion으로 영상 렌더링

### 3-6. 테스트 결과

- **TypeScript tsc --noEmit**: 에러 0건 (Audio deprecated 경고 1건 - 향후 OffthreadAudio 전환 예정)
- **Python pytest**: 34/34 PASSED (Phase 1+2: 13건, Phase 3: 21건)
- **영상 렌더링 테스트**: 성공
  - 출력: `output/samples/shortform_test.mp4`
  - 해상도: 1080x1920
  - FPS: 30
  - 코덱: h264, 픽셀포맷: yuv420p
  - 프레임수: 510 (17초)
  - 파일크기: 2.1MB
  - Threads/Reels 업로드 규격 호환 확인

---

## 생성/수정 파일 목록

### 신규 생성 (8개)
- `remotion/src/types/shortform.ts` — SceneType, SceneData, ShortFormProps 타입
- `remotion/src/scenes/HookScene.tsx` — 오프닝 장면
- `remotion/src/scenes/ChecklistScene.tsx` — 체크리스트 장면
- `remotion/src/scenes/DataScene.tsx` — 데이터/숫자 장면
- `remotion/src/scenes/InfoScene.tsx` — 정보 카드 장면
- `remotion/src/scenes/CtaScene.tsx` — CTA 아웃트로 장면
- `remotion/src/compositions/ShortForm/index.tsx` — ShortForm Video Composition
- `remotion/src/__tests__/ShortForm.test.tsx` — ShortForm 타입/props 테스트

### 수정 (4개)
- `remotion/src/Root.tsx` — ShortForm Composition 등록
- `remotion/render_bridge.py` — render_video(), slides_to_scenes(), render_shortform() 추가
- `remotion/tests/test_render_bridge.py` — Phase 3 테스트 21건 추가
- `remotion/package.json` — @remotion/transitions 의존성 추가

### 렌더링 샘플 (1개)
- `remotion/output/samples/shortform_test.mp4` — 전체 파이프라인 테스트 영상

---

## 머지 판단
- **머지 필요**: Yes
- **브랜치**: task/task-436.3-dev1
- **워크트리 경로**: /home/jay/projects/ThreadAuto/.worktrees/task-436.3-dev1
- **머지 의견**: remotion/ 디렉토리 내 신규 파일 추가 + 기존 4개 파일 수정. 기존 video/ 코드 변경 없음 (병행 운영). tsc 에러 0건, pytest 34/34 통과, 영상 렌더링 성공. 충돌 가능성 없음.

---

## 셀프 QC

- [x] 1. 이 변경이 다른 파일에 영향을 미치는가? → remotion/ 디렉토리 내부만 변경. 기존 video/ 코드 미수정.
- [x] 2. 이 로직의 엣지 케이스는 무엇인가? → scenes 빈 배열, elements 빈 배열, audioSrc 미설정, 알 수 없는 scene type — 모두 처리됨 (기본값/fallback)
- [x] 3. 이 구현이 작업 지시와 정확히 일치하는가? → ShortForm Composition 등록, Scene 5종, 전환 효과 3종, Audio, Python 래퍼 — 전부 완료
- [x] 4. 에러 처리와 보안은 확인했는가? → render_video() RuntimeError, 알 수 없는 SceneType → info fallback, 타임아웃 600초
- [x] 5. 테스트가 모든 경로를 커버하는가? → TS 타입 테스트 + Python 34건 단위 테스트 + 실 렌더링 검증

---

## 버그/이슈

- Audio 컴포넌트 deprecated 경고 (Remotion v4.0.434): 현재 `Audio` 사용 중, 향후 `OffthreadAudio`로 교체 필요 (v4.1+ 예상)
- 렌더링 속도: 17초 영상 기준 약 1분 30초 소요 (Phase 4에서 최적화 예정)

## 비고

- MoviePy 기반 video/ 파이프라인과 병행 운영 가능 (render_shortform이 기존 generate_slideshow 시그니처 호환)
- TransitionSeries는 React.Fragment를 자식으로 허용하지 않으므로 flatMap 패턴으로 children 배열 구성
- @remotion/transitions의 TransitionPresentation 제네릭이 서로 다른 전환 타입 간 호환되지 않아 any 반환 타입 사용
- 다음 Phase 지시서: `/home/jay/workspace/memory/tasks/task-436.4.md`
