Phase T 설계 보완: 수치 오류 수정 + 누락 항목 추가
수정: - sidebar 너비 420→380px (space_allocator 실측값 반영) - 글자폭 비율 출처 명확화 (space_allocator.py 실측) - body 배경 예시 계산 추가 추가: - 원인 3가지 명시 (폰트 위계 부재, 블록 디자인 선택 부재, 비율 고정) - 근본 원칙 3가지 (폰트 먼저, body 키우기, 사전 판단) - 다단 레이아웃 판단 기준 + 전환 조건 - 비율 변경 시 구체적 px 계산 + 효과 비교표 - 블록 디자인 선택 문제 섹션 (Phase T 범위 외, 별도 검토) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -1,8 +1,8 @@
|
|||||||
# Phase T: 폰트 위계 + 동적 컨테이너 계산
|
# Phase T: 폰트 위계 + 동적 컨테이너 계산 + 디자인 선택
|
||||||
|
|
||||||
> 작성일: 2026-03-31
|
> 작성일: 2026-03-31
|
||||||
> 상태: 설계
|
> 상태: 설계
|
||||||
> 근거: Phase S 결과물에서 폰트 크기가 중요도와 역전 — 첨부(14px) > 배경(9px). 컨테이너 비율이 폰트 위계를 따라가야 함.
|
> 근거: Phase S 결과물에서 (1) 폰트 크기가 중요도와 역전, (2) 블록 디자인 선택이 전혀 없음, (3) 컨테이너 비율이 고정. 이 3가지를 해결.
|
||||||
> 선행: Phase S (Claude HTML 직접 생성 + 독립 검증 시스템)
|
> 선행: Phase S (Claude HTML 직접 생성 + 독립 검증 시스템)
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -19,11 +19,15 @@
|
|||||||
|
|
||||||
**폰트 크기가 중요도와 완전히 역전되어 있다.**
|
**폰트 크기가 중요도와 완전히 역전되어 있다.**
|
||||||
|
|
||||||
### 원인
|
### 원인 3가지
|
||||||
각 프롬프트를 독립적으로 설계하면서 "이 영역 안에서 맞추기"만 했고, 슬라이드 전체에서의 시각적 위계를 고려하지 않음. 컨테이너 크기를 먼저 정하고 폰트를 끼워 맞추니 중요도가 뒤집힘.
|
1. **폰트 위계 부재**: 각 프롬프트를 독립적으로 설계하면서 "이 영역 안에서 맞추기"만 했고, 슬라이드 전체에서의 시각적 위계를 고려하지 않음. 컨테이너 크기를 먼저 정하고 폰트를 끼워 맞추니 중요도가 뒤집힘.
|
||||||
|
2. **블록 디자인 선택 부재**: Phase S는 blocks/ 디렉토리의 블록 템플릿을 전혀 참조하지 않음. 4개 프롬프트에 CSS가 직접 하드코딩되어 있어, 어떤 MDX가 와도 항상 동일한 디자인이 나옴. 콘텐츠 특성에 따른 디자인 다양성이 없음.
|
||||||
|
3. **컨테이너 비율 고정**: body:sidebar = 65:35 고정. 배경+본심이 좁고 첨부가 넓어서 폰트 역전의 원인.
|
||||||
|
|
||||||
### 근본 원칙
|
### 근본 원칙
|
||||||
**폰트(위계)가 먼저고, 컨테이너(공간)가 따라가야 한다.**
|
1. **폰트(위계)가 먼저고, 컨테이너(공간)가 따라가야 한다.**
|
||||||
|
2. **배경과 본심의 컨테이너를 키우고, 첨부의 컨테이너를 줄여야 한다.** (폰트 위계에 맞추기 위해)
|
||||||
|
3. **텍스트 양을 사전에 보고, 비율과 다단 여부를 판단한 후 프롬프트를 조립해야 한다.**
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -64,9 +68,10 @@
|
|||||||
|
|
||||||
## 4. 수학적 기초
|
## 4. 수학적 기초
|
||||||
|
|
||||||
### 기본 상수 (Pretendard 한글 실측)
|
### 기본 상수 (Pretendard 한글, space_allocator.py 실측)
|
||||||
```
|
```
|
||||||
글자폭 비율: font_size × 0.947 (fonttools 실측)
|
DEFAULT_AVG_CHAR_WIDTH_PX = 14.4 (at 15.2px font)
|
||||||
|
→ 글자폭 비율: font_size × 0.947
|
||||||
줄 높이 비율: font_size × 1.5 (본문 기준, 영역마다 조정 가능)
|
줄 높이 비율: font_size × 1.5 (본문 기준, 영역마다 조정 가능)
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -80,34 +85,57 @@
|
|||||||
### 가용 공간 계산
|
### 가용 공간 계산
|
||||||
```
|
```
|
||||||
슬라이드: 1280 × 720px
|
슬라이드: 1280 × 720px
|
||||||
padding: 40px × 2 = 80px (상하좌우)
|
padding: 40px × 2 = 80px (상하좌우) ← tokens.css --spacing-page
|
||||||
grid gap: 20px × 2 = 40px (행/열 간격)
|
grid gap: 20px × 2 = 40px (행/열 간격) ← tokens.css --spacing-block
|
||||||
header: ~66px (2rem × 1.7 + padding + border)
|
header: ~66px (2rem × 1.7 + padding 8px + border 3px)
|
||||||
|
|
||||||
내부 영역: (1280 - 80) × (720 - 80) = 1200 × 640px
|
내부 영역: (1280 - 80) × (720 - 80) = 1200 × 640px
|
||||||
body+sidebar 행 높이: 640 - 66(header) - 60(footer) - 40(gaps) = 474px
|
body+sidebar 행 높이: 640 - 66(header) - 60(footer) - 40(gaps) = 474px
|
||||||
|
|
||||||
body 열 너비: 1200 × body_ratio - 20(gap)
|
열 너비 계산 (space_allocator.py):
|
||||||
sidebar 열 너비: 1200 × sidebar_ratio
|
zone_width_px = int(slide_width × zone_width_pct / 100 × 0.85)
|
||||||
|
현재 body: 1280 × 65% × 0.85 = 707px
|
||||||
|
현재 sidebar: 1280 × 35% × 0.85 = 380px
|
||||||
```
|
```
|
||||||
|
|
||||||
### 예시 계산: sidebar (현재 35%, 420px)
|
### 예시 계산: sidebar (현재 35% = 380px)
|
||||||
|
|
||||||
```
|
```
|
||||||
텍스트: 용어 3개, 총 ~400자
|
텍스트: 용어 3개, 총 ~400자
|
||||||
폰트: 10px
|
폰트: 10px
|
||||||
줄 높이: 10 × 1.5 = 15px
|
줄 높이: 10 × 1.5 = 15px
|
||||||
카드 chrome: 3 × (title 20px + padding 28px + margin 10px) = 174px
|
카드 chrome: 3 × (title ~22px + padding 14×2=28px + margin 10px) = 3 × 60 = 180px
|
||||||
header: 30px, outer padding: 40px
|
header "용어 정의": ~30px, outer padding: 16×2 = 32px
|
||||||
가용 높이: 474 - 40 - 30 - 174 = 230px
|
가용 높이: 474 - 32 - 30 - 180 = 232px
|
||||||
가용 줄 수: 230 ÷ 15 = 15줄 (카드당 5줄)
|
가용 줄 수: 232 ÷ 15 ≈ 15줄 (카드당 5줄)
|
||||||
줄당 글자: (420 - 40 - 28 - 14) ÷ 9.47 ≈ 35자
|
줄당 글자: (380 - 32 - 28 - 14) ÷ (10 × 0.947) = 306 ÷ 9.47 ≈ 32자
|
||||||
총 수용: 15 × 35 = 525자 > 400자 → OK
|
총 수용: 15 × 32 = 480자 > 400자 → OK
|
||||||
|
|
||||||
만약 용어 6개, 총 ~800자라면?
|
만약 용어 6개, 총 ~800자라면?
|
||||||
카드 chrome: 6 × 58 = 348px → 가용 높이 = 474 - 40 - 30 - 348 = 56px
|
카드 chrome: 6 × 60 = 360px → 가용 높이 = 474 - 32 - 30 - 360 = 52px
|
||||||
줄 수 = 56 ÷ 15 = 3줄 → 3 × 35 = 105자 ≪ 800자 → FAIL
|
줄 수 = 52 ÷ 15 = 3줄 → 3 × 32 = 96자 ≪ 800자 → FAIL
|
||||||
→ 9px로 축소해도 불가 → 2단 레이아웃 또는 body:sidebar 비율 변경 필요
|
→ 9px로 축소: 줄 높이 13.5px, 줄 수 = 52/13.5 = 3줄 → 여전히 FAIL
|
||||||
|
→ 2단 레이아웃 또는 body:sidebar 비율 변경 필요
|
||||||
|
```
|
||||||
|
|
||||||
|
### 예시 계산: body 배경 (현재 65% = 707px, 높이 176px)
|
||||||
|
|
||||||
|
```
|
||||||
|
텍스트: 혼용 설명 3문장(~150자) + 정책 사례 2건(~180자) = 총 ~330자
|
||||||
|
폰트: 11px (위계 기준 10-12px)
|
||||||
|
줄 높이: 11 × 1.4 = 15.4px
|
||||||
|
outer padding: 10×2 + 14×2 = 48px (상하+좌우)
|
||||||
|
제목 2개: 2 × 20px = 40px
|
||||||
|
사례 카드 chrome: 2 × (제목 16px + padding 12px) = 56px
|
||||||
|
가용 높이: 176 - 20 - 40 = 116px (좌측 텍스트) / 176 - 20 - 56 = 100px (우측 사례)
|
||||||
|
좌측 줄 수: 116 ÷ 15.4 ≈ 7줄
|
||||||
|
줄당 글자: (707/2 - 48 - 14) ÷ (11 × 0.947) = 291 ÷ 10.4 ≈ 28자
|
||||||
|
좌측 수용: 7 × 28 = 196자 > 150자 → OK
|
||||||
|
|
||||||
|
만약 body:sidebar = 70:30이면?
|
||||||
|
body 너비: 1280 × 70% × 0.85 = 762px
|
||||||
|
좌측 줄당 글자: (762/2 - 48 - 14) ÷ 10.4 = 319 ÷ 10.4 ≈ 30자
|
||||||
|
→ 2자 더 여유, 12px 폰트도 가능할 수 있음
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
@@ -127,49 +155,105 @@ header: 30px, outer padding: 40px
|
|||||||
- 레이아웃을 바꾸면 너비가 줄어서 줄당 글자 수가 줄어듦
|
- 레이아웃을 바꾸면 너비가 줄어서 줄당 글자 수가 줄어듦
|
||||||
- 줄당 글자 수가 줄면 다시 줄 수가 늘어남...
|
- 줄당 글자 수가 줄면 다시 줄 수가 늘어남...
|
||||||
|
|
||||||
|
### 다단 레이아웃 판단 기준
|
||||||
|
|
||||||
|
사전에 텍스트 양을 보고, 비율과 다단 여부를 판단해야 한다.
|
||||||
|
하드코딩("22줄, 60자/줄")이 아니라 동적 판단 로직이 필요.
|
||||||
|
|
||||||
|
```
|
||||||
|
판단 흐름:
|
||||||
|
1. 위계 기준 폰트로 수용량 계산 (기본 폰트)
|
||||||
|
2. 텍스트 양 > 수용량 × 1.0 → 폰트 1px 축소 (위계 범위 내)
|
||||||
|
3. 최소 폰트로도 텍스트 양 > 수용량 → 레이아웃 변경 (1단→2단)
|
||||||
|
4. 2단으로도 불가 → 컨테이너 비율 조정 (sidebar 축소 → body 확대)
|
||||||
|
5. 비율 조정으로도 불가 → 텍스트 편집 필요 (경고)
|
||||||
|
```
|
||||||
|
|
||||||
|
다단 전환 기준:
|
||||||
|
- sidebar: 카드 3개 이하 = 1단, 4개 이상이면서 최소 폰트로 불가 = 2단 검토
|
||||||
|
- 배경: topic 2개 = 가로 flex (현재), topic 3개 이상 = 2행 flex 검토
|
||||||
|
- 본문: 항상 1단 (이미지 float으로 실질 2단 효과)
|
||||||
|
|
||||||
### 해결: 보수적 추정 + 검증 1회 (하이브리드)
|
### 해결: 보수적 추정 + 검증 1회 (하이브리드)
|
||||||
|
|
||||||
100% 정확한 사전 계산 대신:
|
100% 정확한 사전 계산 대신:
|
||||||
1. **보수적으로 계산** (실제보다 10-15% 작게 추정)
|
1. **보수적으로 계산** (실제보다 10-15% 작게 추정)
|
||||||
2. **위계 범위 내에서 폰트 결정** (간단한 단계적 판단)
|
2. **위계 범위 내에서 폰트 결정** (단계적 판단 로직)
|
||||||
3. **Claude에게 정확한 수치 전달**
|
3. **다단 필요 여부 사전 판단** (텍스트 양 ÷ 수용량)
|
||||||
4. **content_verifier + Selenium으로 1회 검증** (이미 구현됨)
|
4. **Claude에게 정확한 수치 전달**
|
||||||
5. **실패 시 1단계 축소 후 재생성** (이미 구현됨)
|
5. **content_verifier + Selenium으로 1회 검증** (이미 구현됨)
|
||||||
|
6. **실패 시 1단계 축소 후 재생성** (이미 구현됨)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 6. 컨테이너 비율 조정
|
## 6. 컨테이너 비율 조정
|
||||||
|
|
||||||
|
### 핵심 방향
|
||||||
|
배경과 본심의 컨테이너를 키우고 글씨 크기를 맞추고,
|
||||||
|
첨부의 컨테이너를 줄이고 글씨를 작게 한다.
|
||||||
|
|
||||||
### 현재
|
### 현재
|
||||||
```
|
```
|
||||||
grid-template-columns: 65fr 35fr (body 65% : sidebar 35%)
|
grid-template-columns: 65fr 35fr (body 65% : sidebar 35%)
|
||||||
|
body 너비: 1280 × 65% × 0.85 = 707px
|
||||||
|
sidebar 너비: 1280 × 35% × 0.85 = 380px
|
||||||
```
|
```
|
||||||
|
|
||||||
### 제안: 텍스트 양에 따라 동적 조정
|
### 제안: 텍스트 양에 따라 동적 조정
|
||||||
```
|
```
|
||||||
sidebar 텍스트가 적으면 → 70:30 또는 72:28
|
sidebar 텍스트가 적으면 → 70:30 또는 72:28
|
||||||
|
body: 1280 × 70% × 0.85 = 762px / sidebar: 1280 × 30% × 0.85 = 326px
|
||||||
|
body: 1280 × 72% × 0.85 = 783px / sidebar: 1280 × 28% × 0.85 = 305px
|
||||||
|
|
||||||
sidebar 텍스트가 보통이면 → 68:32
|
sidebar 텍스트가 보통이면 → 68:32
|
||||||
|
body: 1280 × 68% × 0.85 = 741px / sidebar: 1280 × 32% × 0.85 = 348px
|
||||||
|
|
||||||
sidebar 텍스트가 많으면 → 65:35 (현재 유지)
|
sidebar 텍스트가 많으면 → 65:35 (현재 유지)
|
||||||
|
body: 707px / sidebar: 380px
|
||||||
```
|
```
|
||||||
|
|
||||||
판단 기준:
|
판단 기준:
|
||||||
```
|
```
|
||||||
sidebar 글자 수 ÷ sidebar 수용량(최소 폰트 기준) = 충전율
|
sidebar 글자 수 ÷ sidebar 수용량(최소 폰트 9px 기준) = 충전율
|
||||||
충전율 < 50% → 비율 축소 가능 (28-30%)
|
|
||||||
충전율 50-80% → 현재 유지 (32-35%)
|
충전율 < 50% → 비율 축소 (28-30%) — body가 넓어짐, 배경 12px 가능
|
||||||
충전율 > 80% → 비율 확대 또는 레이아웃 변경
|
충전율 50-80% → 보통 (32-35%)
|
||||||
|
충전율 > 80% → 현재 유지 또는 확대, 다단 검토
|
||||||
|
```
|
||||||
|
|
||||||
|
### 비율 변경의 효과
|
||||||
|
```
|
||||||
|
현재 (65:35) 변경 후 (70:30)
|
||||||
|
배경 폰트: 9-11px (작음) 11-12px (적절)
|
||||||
|
본심 폰트: 12px 12px (유지)
|
||||||
|
sidebar 폰트: 14px (너무 큼) 9-11px (적절)
|
||||||
|
위계: ❌ 역전 ✅ 정상
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 7. 정렬 규칙
|
## 7. 블록 디자인 선택 문제 (미해결, 별도 Phase 검토)
|
||||||
|
|
||||||
|
### 현재 상태
|
||||||
|
Phase S의 4개 프롬프트(BG/CORE/SIDEBAR/FOOTER)에 CSS가 직접 하드코딩되어 있음.
|
||||||
|
blocks/ 디렉토리에 블록 템플릿이 있지만 전혀 참조되지 않음.
|
||||||
|
어떤 MDX가 와도 항상 동일한 디자인이 나옴.
|
||||||
|
|
||||||
|
### Phase T에서는
|
||||||
|
폰트 위계와 컨테이너 비율에 집중. 블록 디자인 다양성은 Phase T 범위 밖.
|
||||||
|
다만, 동적 계산 시스템이 완성되면 "이 콘텐츠에 어떤 레이아웃이 적합한가"를
|
||||||
|
판단하는 기반이 되므로, Phase T가 선행되어야 함.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 8. 정렬 규칙
|
||||||
|
|
||||||
- "용어 정의" 라벨: 카드 좌측 시작점에 맞춰 정렬 (중앙 정렬 아님)
|
- "용어 정의" 라벨: 카드 좌측 시작점에 맞춰 정렬 (중앙 정렬 아님)
|
||||||
- 각 영역의 텍스트 시작점이 수직으로 정렬되어야 함
|
- 각 영역의 텍스트 시작점이 수직으로 정렬되어야 함
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 8. 구현 대상
|
## 9. 구현 대상
|
||||||
|
|
||||||
### 신규 함수 (위치: src/space_allocator.py 또는 신규 모듈)
|
### 신규 함수 (위치: src/space_allocator.py 또는 신규 모듈)
|
||||||
```python
|
```python
|
||||||
@@ -193,7 +277,7 @@ def calculate_text_capacity(width_px: int, height_px: int, font_size: float, ...
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 9. 자기 검증 체크리스트
|
## 10. 자기 검증 체크리스트
|
||||||
|
|
||||||
- [ ] 핵심 메시지(key-msg)가 14px로 가장 큰가?
|
- [ ] 핵심 메시지(key-msg)가 14px로 가장 큰가?
|
||||||
- [ ] 본문(core)이 12px인가?
|
- [ ] 본문(core)이 12px인가?
|
||||||
|
|||||||
Reference in New Issue
Block a user