# task-675.1 완료 보고서

## SCQA

**S**: ThreadAuto 영상 렌더러(evan_dynamic.py)가 task-673.1에서 font_size를 1.3배 확대 적용했으나, y좌표/여백/간격 조정 없이 적용되어 Cover/Card_list/Detail/CTA 4개 장면에서 레이아웃 깨짐이 발생했다. 또한 나레이션-화면 텍스트 동기화가 슬라이드 단위로만 되어 있어 문장별 동기화가 부재했다.

**C**: 캡처 증거 4건 확인 — Cover 텍스트 좌측 잘림(font_size 122, 1080px 초과), Card_list 항목 우측 잘림(font_size 64 + 긴 텍스트), Detail label/value 겹침(간격 120px < label+value 높이), CTA 과대 폰트(135px). 현 상태로는 Threads 업로드 불가.

**Q**: 하드코딩 font_size를 제거하고 동적 레이아웃 시스템을 도입하여 레이아웃 깨짐 0건을 달성할 수 있는가? 나레이션-화면 문장별 Sync를 구현할 수 있는가?

**A**: 동적 레이아웃 시스템(`_calc_font_size` + `_wrap_text` + 멀티라인 렌더링) 도입으로 4건의 레이아웃 깨짐 모두 해결. 나레이션 Sync는 글자 수 비율 방식(옵션 A)으로 문장별 시작 시간을 추정하여 element delay에 반영. pytest 61건 전체 통과, pyright 0 에러.

## 작업 내용

### 문제 1 해결: 동적 레이아웃 시스템 (evan_dynamic.py)

1. **`_calc_font_size(text, max_width, desired_size, font_path, min_size=36)`**: PIL getbbox()로 텍스트 너비 측정, max_width 초과 시 2px씩 축소. 최소 36px 보장.

2. **`_wrap_text(text, max_width, font_size, font_path)`**: 공백 기준 단어 분리 → 줄별 max_width 체크 → 단어 초과 시 글자 단위 분리.

3. **`_render_text_element()` 멀티라인**: max_width 기반 동적 font_size + wrap 후 각 줄을 `line_height = font_size * 1.3` 간격으로 렌더링. typing 애니메이션도 멀티라인 지원.

4. **장면별 수정 사항**:
   - Cover: `max_width=960` 추가 (좌우 60px 여백)
   - Card_list: 타이틀 `max_width=920`, 아이템 텍스트 `max_width=840` (카드 내부)
   - Detail: 아이템 간격 120px → 166px (label 55 + gap 10 + value 81 + gap 20)
   - CTA/Body: 모든 텍스트에 `max_width` 추가

### 문제 2 해결: 나레이션-화면 문장별 Sync

1. **`_calc_sentence_timing(narration_text, total_duration)`** (pipeline_orchestrator.py): 문장 분리(`re.split`) → 글자 수 비율로 각 문장 `start_time` 추정.

2. **`generate_shortform_video()`**: TTS duration 측정 후 `_calc_sentence_timing()` 호출 → `narration_timing` 리스트 생성 → `generate_scenes_from_slides()`에 전달.

3. **`generate_scenes_from_slides()`**: `narration_timing` 파라미터 추가. timing 제공 시 text element의 delay를 문장 시작 시간에 동기화.

### 기존 테스트 호환성
- `test_render_single_scene_returns_rgb_frames`: generator → `list()` 변환 (task-673.1의 generator 전환 이후 깨진 테스트 복구)

## 생성/수정 파일 목록

| 파일 | 변경 유형 | 내용 |
|------|-----------|------|
| `video/evan_dynamic.py` | 수정 | `_calc_font_size`, `_wrap_text`, `_render_text_element` 멀티라인, 동적 레이아웃, `narration_timing` 파라미터 |
| `video/pipeline_orchestrator.py` | 수정 | `_calc_sentence_timing()` 추가, `generate_shortform_video()` timing 통합 |
| `video/tests/test_evan_dynamic.py` | 수정 | generator 호환 수정, `TestCalcFontSize`(4건), `TestWrapText`(4건), `TestGenerateScenesWithTiming`(3건) 추가 |
| `video/tests/test_pipeline_orchestrator.py` | 수정 | `TestCalcSentenceTiming`(4건), `TestGenerateScenesWithTiming`(1건) 추가 |
| `video/tests/test_layout_validation.py` | 신규 | 화면경계(2건), 겹침(1건), 폰트범위(2건), max_width(4건) 총 9건 |

## 테스트 결과

- **pytest**: 61 passed, 0 failed (기존 37건 + 신규 24건)
- **pyright**: 0 errors, 0 warnings, 0 informations
- **black + isort**: 포맷팅 완료

### 테스트 상세

| 카테고리 | 테스트 수 | 상태 |
|----------|-----------|------|
| 기존 evan_dynamic | 9 | PASS |
| 기존 pipeline_orchestrator | 19 | PASS |
| 기존 tts_sync | 5 | PASS |
| 신규 _calc_font_size | 4 | PASS |
| 신규 _wrap_text | 4 | PASS |
| 신규 _calc_sentence_timing | 4 | PASS |
| 신규 narration timing 통합 | 4 | PASS |
| 신규 레이아웃 검증 | 9 | PASS |
| **합계** | **61** | **ALL PASS** |

## 발견 이슈 및 해결

### 자체 해결 (3건)

1. **generator 호환 테스트 깨짐** — `test_render_single_scene_returns_rgb_frames`에서 `len(frames)` 호출이 generator에서 실패. `list()` 변환으로 수정.
   - `video/tests/test_evan_dynamic.py:38`: `frames = self.renderer.render_scene(scene)` → `frames = list(self.renderer.render_scene(scene))`

2. **Detail 간격 부족으로 텍스트 겹침** — 기존 간격 120px에서 label(55px) + value(81px) = 136px으로 이미 초과. 간격을 166px(55+10+81+20)으로 변경.
   - `video/evan_dynamic.py:549`: `y_offset = 700 + i * 166`

3. **untracked 파일 worktree 미포함** — `pipeline_orchestrator.py`와 `test_pipeline_orchestrator.py`가 main에서 untracked 상태여서 worktree에 포함되지 않음. 수동 복사 후 작업.

### 범위 외 미해결 (1건)

1. **Threads 실제 업로드 테스트** — 검증 기준 7번(Threads 업로드 1건)은 실제 TTS + 영상 렌더링 + 업로드 파이프라인 전체 실행이 필요. 현재 작업은 레이아웃/Sync 로직 구현에 집중했으며, 실제 업로드는 별도 통합 테스트에서 수행 필요. 범위 외 사유: 외부 서비스(Threads API) 의존성.

## 머지 판단
- **머지 필요**: Yes
- **브랜치**: task/task-675.1-dev1
- **워크트리 경로**: /home/jay/projects/ThreadAuto/.worktrees/task-675.1-dev1
- **머지 의견**: pytest 61건 전체 통과, pyright 0 에러, 레이아웃 검증 테스트 9건 전체 통과. 4건의 레이아웃 깨짐 모두 해결, 나레이션 Sync 구현 완료. 기존 테스트 회귀 0건. 머지 권장.
