# ThreadAuto 영상 제작 규칙

**최종 수정**: 2026-03-18
**지시자**: 제이회장님

---

## ★ 렌더링 엔진 결정 (확정, 2026-03-18)

### MoviePy + PIL 유지 (확정)
- **사용 엔진**: MoviePy + PIL (`evan_dynamic.py`)
- **Remotion 폐기 결정**: 아래 사유로 MoviePy 단일 엔진 확정
- Remotion 코드는 참고용으로 보존 (삭제 금지), 단 실행 경로에서 제외

### Remotion 폐기 사유
MoviePy(PIL)로 80% 수준의 결과가 나오는데, Remotion으로 변환하면 10%도 충족 못하는 이유:
1. **렌더링 패러다임 차이**: PIL = 픽셀 직접 제어 / Remotion = 브라우저(Chromium) 해석 위임
2. **한글 폰트**: PIL은 .otf 직접 로드, Remotion은 브라우저 폰트 매칭 → 서버 headless 환경에서 fallback
3. **좌표계**: PIL `draw.text((x,y))` = 정확한 픽셀 / CSS = box model + line-height + auto-wrap 해석
4. **색상 블렌딩**: PIL `_blend_color()` = RGB 수학 계산 / CSS opacity = 브라우저 compositing (감마 보정 차이)
5. **핵심**: 에반 6원칙의 모든 파라미터가 PIL 출력 기준으로 튜닝됨 → CSS로 1:1 번역 불가능

### ★ RAM 관리 — FFmpeg 파이프 스트리밍 (필수, 2026-03-18)
서버 RAM 7.7GB에서 영상 렌더링 시 프레임 메모리 폭발 방지.

**문제**: `render_all_scenes()`가 모든 프레임을 list에 누적 → 1080×1920×3 × ~1200프레임 = 7.1GB → 서버 다운

**해결 (task-673.1에서 구현)**:
- `render_scene()`, `render_all_scenes()` → **generator** (yield)
- `ImageSequenceClip` 제거 → **FFmpeg subprocess pipe**로 프레임 직접 쓰기
- 메모리: 7.1GB → 프레임 1장(5.9MB) + FFmpeg 버퍼 = 수십MB

**코드 패턴 (표준)**:
```python
# evan_dynamic.py — generator
def render_scene(self, scene) -> Iterator[np.ndarray]:
    for frame_idx in range(total_frames):
        img = Image.new("RGB", (self.width, self.height), self.bg_color)
        # ... 렌더링 ...
        yield np.array(img, dtype=np.uint8)

def render_all_scenes(self, scenes) -> Iterator[np.ndarray]:
    for scene in scenes:
        yield from self.render_scene(scene)

# pipeline_orchestrator.py — FFmpeg pipe
cmd = [
    "ffmpeg", "-y", "-f", "rawvideo", "-pix_fmt", "rgb24",
    "-s", f"{width}x{height}", "-r", str(fps), "-i", "-",
    "-c:v", "libx264", "-preset", "ultrafast",
    "-pix_fmt", "yuv420p", "-an", output_path,
]
proc = subprocess.Popen(cmd, stdin=subprocess.PIPE, stderr=subprocess.PIPE)
for frame in renderer.render_all_scenes(scenes):
    proc.stdin.write(frame.tobytes())
proc.stdin.close()
proc.wait()
```

**⚠️ 금지 사항**:
- `list(renderer.render_all_scenes(scenes))` — 프레임 전체 메모리 적재 금지
- `ImageSequenceClip(all_frames)` — MoviePy 메모리 적재 방식 사용 금지
- 썸네일 등 소수 프레임만 필요할 때만 `list(renderer.render_scene(scenes[0]))` 허용

## 에반 6원칙 (확정)
1. 검정 배경
2. 테마 색상 (주제별 포인트 컬러)
3. 레이아웃 변주 (같은 구조 반복 금지)
4. 타이핑 효과 (글자 등장)
5. 시간차 등장 (요소가 순차 등장)
6. 다이나믹 (정적이지 않은 화면)

## ★ 영상 퀄리티 필수 규칙 (제이회장님 지시, 2026-03-14)

### 1. TTS-영상 싱크 필수
- 음성(TTS)과 화면에 표시되는 텍스트/내용이 **정확히 일치**해야 함
- 음성이 말하는 내용과 다른 텍스트가 화면에 있으면 안 됨
- 타이밍도 맞춰야 함: 음성이 해당 내용을 말할 때 해당 화면이 표시

### 2. 폰트 크기 — 가독성 최우선
- 벤치마킹 영상(에반) 확인 필수
- 작은 폰트 금지. 모바일(세로 영상)에서도 바로 읽힐 수 있는 크기
- 제목/핵심 키워드는 더 크게, 보조 텍스트는 적절히

### 3. 문구 좌우 여백 — 절대 뚫고 나가지 않기
- 텍스트가 영상 좌우 경계를 넘어가면 **절대 안 됨**
- 디자인상 최소 여백 확보 (좌우 각 5~10% 이상)
- **줄바꿈을 적극적으로 사용** — 한 줄에 너무 긴 문장 금지
- 글자 수 제한: 한 줄에 최대 15~18자 (한국어 기준, 세로 영상)

### 4. 아이콘/형상화 — 텍스트만 쓰지 않기
- 줄글, 카드뉴스식 텍스트 나열 금지
- **아이콘, 이모지, 도형, 일러스트**로 내용을 시각화
- 핵심 키워드는 텍스트 + 아이콘 조합으로 기억에 남게
- 예: "보험료 절약" → 💰 아이콘 + 텍스트, "체크리스트" → ✅ 리스트 형태

## 레퍼런스
- 에반 영상 분석: `memory/meetings/2026-03-07-dialogue-video-quality.md`
- Threads 전략: `memory/meetings/2026-03-11-threads-marketing-strategy.md`
- 영상 방향 확정: MEMORY.md "ThreadAuto 영상 방향" 섹션
