Phase T 설계: 폰트 위계 + 동적 컨테이너 계산
핵심 14px > 본문 12px > 배경 10-12px > 첨부 9-11px 위계 확정. 폰트가 먼저, 컨테이너가 따라가는 계산 순서 정의. 보수적 추정 + 검증 1회 하이브리드 접근 설계. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
206
IMPROVEMENT-PHASE-T.md
Normal file
206
IMPROVEMENT-PHASE-T.md
Normal file
@@ -0,0 +1,206 @@
|
|||||||
|
# Phase T: 폰트 위계 + 동적 컨테이너 계산
|
||||||
|
|
||||||
|
> 작성일: 2026-03-31
|
||||||
|
> 상태: 설계
|
||||||
|
> 근거: Phase S 결과물에서 폰트 크기가 중요도와 역전 — 첨부(14px) > 배경(9px). 컨테이너 비율이 폰트 위계를 따라가야 함.
|
||||||
|
> 선행: Phase S (Claude HTML 직접 생성 + 독립 검증 시스템)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. 문제
|
||||||
|
|
||||||
|
### 현재 상태
|
||||||
|
| 영역 | 중요도 | 있어야 할 크기 | 현재 실제 크기 |
|
||||||
|
|------|--------|-------------|-------------|
|
||||||
|
| 핵심 (key-msg) | 1위 | 가장 큼 | 11px (가장 작음) |
|
||||||
|
| 본문 (core) | 2위 | 큼 | 12px |
|
||||||
|
| 배경 (bg) | 3위 | 보통 | 9-11px |
|
||||||
|
| 첨부 (sidebar) | 4위 | 가장 작음 | 14px (가장 큼) |
|
||||||
|
|
||||||
|
**폰트 크기가 중요도와 완전히 역전되어 있다.**
|
||||||
|
|
||||||
|
### 원인
|
||||||
|
각 프롬프트를 독립적으로 설계하면서 "이 영역 안에서 맞추기"만 했고, 슬라이드 전체에서의 시각적 위계를 고려하지 않음. 컨테이너 크기를 먼저 정하고 폰트를 끼워 맞추니 중요도가 뒤집힘.
|
||||||
|
|
||||||
|
### 근본 원칙
|
||||||
|
**폰트(위계)가 먼저고, 컨테이너(공간)가 따라가야 한다.**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. 폰트 위계 (확정)
|
||||||
|
|
||||||
|
| 영역 | 중요도 | 폰트 크기 | 비고 |
|
||||||
|
|------|--------|----------|------|
|
||||||
|
| 핵심 (key-msg) | 1위 | **14px** bold | 무조건 한 줄, 하나의 메시지 |
|
||||||
|
| 본문 (core) | 2위 | **12px** | 본문 텍스트 기본 |
|
||||||
|
| 배경 (bg) | 3위 | **10-12px** | 텍스트 양에 따라 조정 |
|
||||||
|
| 첨부 (sidebar) | 4위 | **9-11px** | 참고 자료, 가장 작아도 됨 |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. 계산 순서
|
||||||
|
|
||||||
|
```
|
||||||
|
[Phase 1] 텍스트 분석
|
||||||
|
각 영역별 글자 수 측정
|
||||||
|
↓
|
||||||
|
[Phase 2] 폰트 위계로 필요 공간 계산
|
||||||
|
"이 폰트 크기로 이 텍스트를 넣으려면 몇 px 필요한가?"
|
||||||
|
↓
|
||||||
|
[Phase 3] 컨테이너 비율 역산
|
||||||
|
필요 공간에 맞춰 body:sidebar 비율 조정
|
||||||
|
↓
|
||||||
|
[Phase 4] 폰트 미세 조정
|
||||||
|
컨테이너 확정 후, 위계 범위 내에서 최적 폰트 결정
|
||||||
|
↓
|
||||||
|
[Phase 5] 레이아웃 결정
|
||||||
|
폰트 최소값으로도 안 되면 구조 변경 (2단 등)
|
||||||
|
↓
|
||||||
|
[Phase 6] 프롬프트에 확정된 수치 전달
|
||||||
|
"10px, 22줄, overflow:hidden" — Claude에게 정확한 제약 조건
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. 수학적 기초
|
||||||
|
|
||||||
|
### 기본 상수 (Pretendard 한글 실측)
|
||||||
|
```
|
||||||
|
글자폭 비율: font_size × 0.947 (fonttools 실측)
|
||||||
|
줄 높이 비율: font_size × 1.5 (본문 기준, 영역마다 조정 가능)
|
||||||
|
```
|
||||||
|
|
||||||
|
### 수용량 계산 공식
|
||||||
|
```
|
||||||
|
줄당 글자 수 = (가용 너비 - 들여쓰기) ÷ (font_size × 0.947)
|
||||||
|
줄 수 = (가용 높이 - padding - 헤더) ÷ (font_size × 줄높이비율)
|
||||||
|
총 수용량 = 줄당 글자 수 × 줄 수
|
||||||
|
```
|
||||||
|
|
||||||
|
### 가용 공간 계산
|
||||||
|
```
|
||||||
|
슬라이드: 1280 × 720px
|
||||||
|
padding: 40px × 2 = 80px (상하좌우)
|
||||||
|
grid gap: 20px × 2 = 40px (행/열 간격)
|
||||||
|
header: ~66px (2rem × 1.7 + padding + border)
|
||||||
|
|
||||||
|
내부 영역: (1280 - 80) × (720 - 80) = 1200 × 640px
|
||||||
|
body+sidebar 행 높이: 640 - 66(header) - 60(footer) - 40(gaps) = 474px
|
||||||
|
|
||||||
|
body 열 너비: 1200 × body_ratio - 20(gap)
|
||||||
|
sidebar 열 너비: 1200 × sidebar_ratio
|
||||||
|
```
|
||||||
|
|
||||||
|
### 예시 계산: sidebar (현재 35%, 420px)
|
||||||
|
|
||||||
|
```
|
||||||
|
텍스트: 용어 3개, 총 ~400자
|
||||||
|
폰트: 10px
|
||||||
|
줄 높이: 10 × 1.5 = 15px
|
||||||
|
카드 chrome: 3 × (title 20px + padding 28px + margin 10px) = 174px
|
||||||
|
header: 30px, outer padding: 40px
|
||||||
|
가용 높이: 474 - 40 - 30 - 174 = 230px
|
||||||
|
가용 줄 수: 230 ÷ 15 = 15줄 (카드당 5줄)
|
||||||
|
줄당 글자: (420 - 40 - 28 - 14) ÷ 9.47 ≈ 35자
|
||||||
|
총 수용: 15 × 35 = 525자 > 400자 → OK
|
||||||
|
|
||||||
|
만약 용어 6개, 총 ~800자라면?
|
||||||
|
카드 chrome: 6 × 58 = 348px → 가용 높이 = 474 - 40 - 30 - 348 = 56px
|
||||||
|
줄 수 = 56 ÷ 15 = 3줄 → 3 × 35 = 105자 ≪ 800자 → FAIL
|
||||||
|
→ 9px로 축소해도 불가 → 2단 레이아웃 또는 body:sidebar 비율 변경 필요
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. 동적 계산이 어려운 이유
|
||||||
|
|
||||||
|
```
|
||||||
|
텍스트 양 → 폰트 크기 → 줄 수 → 레이아웃 → 컨테이너 크기
|
||||||
|
↑ ↓
|
||||||
|
└──────────── 서로 영향을 줌 ────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
- 텍스트가 많으면 폰트를 줄여야 함
|
||||||
|
- 폰트를 줄이면 줄 수가 늘어남
|
||||||
|
- 줄 수가 늘어나면 높이가 부족할 수 있음
|
||||||
|
- 높이가 부족하면 레이아웃을 바꿔야 함 (1단 → 2단)
|
||||||
|
- 레이아웃을 바꾸면 너비가 줄어서 줄당 글자 수가 줄어듦
|
||||||
|
- 줄당 글자 수가 줄면 다시 줄 수가 늘어남...
|
||||||
|
|
||||||
|
### 해결: 보수적 추정 + 검증 1회 (하이브리드)
|
||||||
|
|
||||||
|
100% 정확한 사전 계산 대신:
|
||||||
|
1. **보수적으로 계산** (실제보다 10-15% 작게 추정)
|
||||||
|
2. **위계 범위 내에서 폰트 결정** (간단한 단계적 판단)
|
||||||
|
3. **Claude에게 정확한 수치 전달**
|
||||||
|
4. **content_verifier + Selenium으로 1회 검증** (이미 구현됨)
|
||||||
|
5. **실패 시 1단계 축소 후 재생성** (이미 구현됨)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. 컨테이너 비율 조정
|
||||||
|
|
||||||
|
### 현재
|
||||||
|
```
|
||||||
|
grid-template-columns: 65fr 35fr (body 65% : sidebar 35%)
|
||||||
|
```
|
||||||
|
|
||||||
|
### 제안: 텍스트 양에 따라 동적 조정
|
||||||
|
```
|
||||||
|
sidebar 텍스트가 적으면 → 70:30 또는 72:28
|
||||||
|
sidebar 텍스트가 보통이면 → 68:32
|
||||||
|
sidebar 텍스트가 많으면 → 65:35 (현재 유지)
|
||||||
|
```
|
||||||
|
|
||||||
|
판단 기준:
|
||||||
|
```
|
||||||
|
sidebar 글자 수 ÷ sidebar 수용량(최소 폰트 기준) = 충전율
|
||||||
|
충전율 < 50% → 비율 축소 가능 (28-30%)
|
||||||
|
충전율 50-80% → 현재 유지 (32-35%)
|
||||||
|
충전율 > 80% → 비율 확대 또는 레이아웃 변경
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7. 정렬 규칙
|
||||||
|
|
||||||
|
- "용어 정의" 라벨: 카드 좌측 시작점에 맞춰 정렬 (중앙 정렬 아님)
|
||||||
|
- 각 영역의 텍스트 시작점이 수직으로 정렬되어야 함
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 8. 구현 대상
|
||||||
|
|
||||||
|
### 신규 함수 (위치: src/space_allocator.py 또는 신규 모듈)
|
||||||
|
```python
|
||||||
|
def analyze_text_volume(content: str, analysis: dict) -> dict[str, int]:
|
||||||
|
"""각 영역별 글자 수 측정"""
|
||||||
|
|
||||||
|
def calculate_font_sizes(text_volumes: dict, container_specs: dict) -> dict[str, float]:
|
||||||
|
"""위계 범위 내에서 최적 폰트 크기 결정"""
|
||||||
|
|
||||||
|
def calculate_container_ratios(text_volumes: dict, font_sizes: dict) -> dict:
|
||||||
|
"""필요 공간에 맞춰 body:sidebar 비율 역산"""
|
||||||
|
|
||||||
|
def calculate_text_capacity(width_px: int, height_px: int, font_size: float, ...) -> int:
|
||||||
|
"""주어진 컨테이너에서 수용 가능한 글자 수"""
|
||||||
|
```
|
||||||
|
|
||||||
|
### 수정 대상
|
||||||
|
- **html_generator.py**: 프롬프트에 동적 폰트 크기 전달 ({font_size} 변수 추가)
|
||||||
|
- **space_allocator.py**: 컨테이너 비율 동적 조정
|
||||||
|
- **content_verifier.py**: 폰트 크기 균형 검증 추가 (L3 확장)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 9. 자기 검증 체크리스트
|
||||||
|
|
||||||
|
- [ ] 핵심 메시지(key-msg)가 14px로 가장 큰가?
|
||||||
|
- [ ] 본문(core)이 12px인가?
|
||||||
|
- [ ] 배경(bg)이 10-12px 범위인가?
|
||||||
|
- [ ] 첨부(sidebar)가 9-11px으로 가장 작은가?
|
||||||
|
- [ ] 폰트 크기가 중요도 순서와 일치하는가? (핵심 > 본문 > 배경 > 첨부)
|
||||||
|
- [ ] 컨테이너 비율이 텍스트 양에 맞게 조정되었는가?
|
||||||
|
- [ ] "용어 정의" 라벨이 카드 좌측에 정렬되었는가?
|
||||||
|
- [ ] 모든 영역에서 텍스트가 잘리지 않는가?
|
||||||
|
- [ ] 다른 MDX(텍스트 양이 다른)에서도 위계가 유지되는가?
|
||||||
Reference in New Issue
Block a user