핵심 14px > 본문 12px > 배경 10-12px > 첨부 9-11px 위계 확정. 폰트가 먼저, 컨테이너가 따라가는 계산 순서 정의. 보수적 추정 + 검증 1회 하이브리드 접근 설계. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
7.1 KiB
7.1 KiB
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% 정확한 사전 계산 대신:
- 보수적으로 계산 (실제보다 10-15% 작게 추정)
- 위계 범위 내에서 폰트 결정 (간단한 단계적 판단)
- Claude에게 정확한 수치 전달
- content_verifier + Selenium으로 1회 검증 (이미 구현됨)
- 실패 시 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 또는 신규 모듈)
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(텍스트 양이 다른)에서도 위계가 유지되는가?