Files
C.E.L_Slide_test2/IMPROVEMENT-PHASE-T.md
kyeongmin c31d72a877 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>
2026-03-31 08:49:23 +09:00

11 KiB
Raw Blame History

Phase T: 폰트 위계 + 동적 컨테이너 계산 + 디자인 선택

작성일: 2026-03-31 상태: 설계 근거: Phase S 결과물에서 (1) 폰트 크기가 중요도와 역전, (2) 블록 디자인 선택이 전혀 없음, (3) 컨테이너 비율이 고정. 이 3가지를 해결. 선행: Phase S (Claude HTML 직접 생성 + 독립 검증 시스템)


1. 문제

현재 상태

영역 중요도 있어야 할 크기 현재 실제 크기
핵심 (key-msg) 1위 가장 큼 11px (가장 작음)
본문 (core) 2위 12px
배경 (bg) 3위 보통 9-11px
첨부 (sidebar) 4위 가장 작음 14px (가장 큼)

폰트 크기가 중요도와 완전히 역전되어 있다.

원인 3가지

  1. 폰트 위계 부재: 각 프롬프트를 독립적으로 설계하면서 "이 영역 안에서 맞추기"만 했고, 슬라이드 전체에서의 시각적 위계를 고려하지 않음. 컨테이너 크기를 먼저 정하고 폰트를 끼워 맞추니 중요도가 뒤집힘.
  2. 블록 디자인 선택 부재: Phase S는 blocks/ 디렉토리의 블록 템플릿을 전혀 참조하지 않음. 4개 프롬프트에 CSS가 직접 하드코딩되어 있어, 어떤 MDX가 와도 항상 동일한 디자인이 나옴. 콘텐츠 특성에 따른 디자인 다양성이 없음.
  3. 컨테이너 비율 고정: body:sidebar = 65:35 고정. 배경+본심이 좁고 첨부가 넓어서 폰트 역전의 원인.

근본 원칙

  1. 폰트(위계)가 먼저고, 컨테이너(공간)가 따라가야 한다.
  2. 배경과 본심의 컨테이너를 키우고, 첨부의 컨테이너를 줄여야 한다. (폰트 위계에 맞추기 위해)
  3. 텍스트 양을 사전에 보고, 비율과 다단 여부를 판단한 후 프롬프트를 조립해야 한다.

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 한글, space_allocator.py 실측)

DEFAULT_AVG_CHAR_WIDTH_PX = 14.4   (at 15.2px font)
→ 글자폭 비율: font_size × 0.947
줄 높이 비율: font_size × 1.5 (본문 기준, 영역마다 조정 가능)

수용량 계산 공식

줄당 글자 수 = (가용 너비 - 들여쓰기) ÷ (font_size × 0.947)
줄 수 = (가용 높이 - padding - 헤더) ÷ (font_size × 줄높이비율)
총 수용량 = 줄당 글자 수 × 줄 수

가용 공간 계산

슬라이드: 1280 × 720px
padding: 40px × 2 = 80px (상하좌우)    ← tokens.css --spacing-page
grid gap: 20px × 2 = 40px (행/열 간격) ← tokens.css --spacing-block
header: ~66px (2rem × 1.7 + padding 8px + border 3px)

내부 영역: (1280 - 80) × (720 - 80) = 1200 × 640px
body+sidebar 행 높이: 640 - 66(header) - 60(footer) - 40(gaps) = 474px

열 너비 계산 (space_allocator.py):
  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% = 380px)

텍스트: 용어 3개, 총 ~400자
폰트: 10px
줄 높이: 10 × 1.5 = 15px
카드 chrome: 3 × (title ~22px + padding 14×2=28px + margin 10px) = 3 × 60 = 180px
header "용어 정의": ~30px, outer padding: 16×2 = 32px
가용 높이: 474 - 32 - 30 - 180 = 232px
가용 줄 수: 232 ÷ 15 ≈ 15줄 (카드당 5줄)
줄당 글자: (380 - 32 - 28 - 14) ÷ (10 × 0.947) = 306 ÷ 9.47 ≈ 32자
총 수용: 15 × 32 = 480자 > 400자 → OK

만약 용어 6개, 총 ~800자라면?
카드 chrome: 6 × 60 = 360px → 가용 높이 = 474 - 32 - 30 - 360 = 52px
줄 수 = 52 ÷ 15 = 3줄 → 3 × 32 = 96자 ≪ 800자 → FAIL
→ 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 폰트도 가능할 수 있음

5. 동적 계산이 어려운 이유

텍스트 양 → 폰트 크기 → 줄 수 → 레이아웃 → 컨테이너 크기
    ↑                                              ↓
    └──────────── 서로 영향을 줌 ────────────────────┘
  • 텍스트가 많으면 폰트를 줄여야 함
  • 폰트를 줄이면 줄 수가 늘어남
  • 줄 수가 늘어나면 높이가 부족할 수 있음
  • 높이가 부족하면 레이아웃을 바꿔야 함 (1단 → 2단)
  • 레이아웃을 바꾸면 너비가 줄어서 줄당 글자 수가 줄어듦
  • 줄당 글자 수가 줄면 다시 줄 수가 늘어남...

다단 레이아웃 판단 기준

사전에 텍스트 양을 보고, 비율과 다단 여부를 판단해야 한다. 하드코딩("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회 (하이브리드)

100% 정확한 사전 계산 대신:

  1. 보수적으로 계산 (실제보다 10-15% 작게 추정)
  2. 위계 범위 내에서 폰트 결정 (단계적 판단 로직)
  3. 다단 필요 여부 사전 판단 (텍스트 양 ÷ 수용량)
  4. Claude에게 정확한 수치 전달
  5. content_verifier + Selenium으로 1회 검증 (이미 구현됨)
  6. 실패 시 1단계 축소 후 재생성 (이미 구현됨)

6. 컨테이너 비율 조정

핵심 방향

배경과 본심의 컨테이너를 키우고 글씨 크기를 맞추고, 첨부의 컨테이너를 줄이고 글씨를 작게 한다.

현재

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
  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
  body: 1280 × 68% × 0.85 = 741px  /  sidebar: 1280 × 32% × 0.85 = 348px

sidebar 텍스트가 많으면 → 65:35 (현재 유지)
  body: 707px  /  sidebar: 380px

판단 기준:

sidebar 글자 수 ÷ sidebar 수용량(최소 폰트 9px 기준) = 충전율

충전율 < 50% → 비율 축소 (28-30%) — body가 넓어짐, 배경 12px 가능
충전율 50-80% → 보통 (32-35%)
충전율 > 80% → 현재 유지 또는 확대, 다단 검토

비율 변경의 효과

                현재 (65:35)        변경 후 (70:30)
배경 폰트:      9-11px (작음)       11-12px (적절)
본심 폰트:      12px               12px (유지)
sidebar 폰트:   14px (너무 큼)      9-11px (적절)
위계:           ❌ 역전             ✅ 정상

7. 블록 디자인 선택 문제 (미해결, 별도 Phase 검토)

현재 상태

Phase S의 4개 프롬프트(BG/CORE/SIDEBAR/FOOTER)에 CSS가 직접 하드코딩되어 있음. blocks/ 디렉토리에 블록 템플릿이 있지만 전혀 참조되지 않음. 어떤 MDX가 와도 항상 동일한 디자인이 나옴.

Phase T에서는

폰트 위계와 컨테이너 비율에 집중. 블록 디자인 다양성은 Phase T 범위 밖. 다만, 동적 계산 시스템이 완성되면 "이 콘텐츠에 어떤 레이아웃이 적합한가"를 판단하는 기반이 되므로, Phase T가 선행되어야 함.


8. 정렬 규칙

  • "용어 정의" 라벨: 카드 좌측 시작점에 맞춰 정렬 (중앙 정렬 아님)
  • 각 영역의 텍스트 시작점이 수직으로 정렬되어야 함

9. 구현 대상

신규 함수 (위치: 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 확장)

10. 자기 검증 체크리스트

  • 핵심 메시지(key-msg)가 14px로 가장 큰가?
  • 본문(core)이 12px인가?
  • 배경(bg)이 10-12px 범위인가?
  • 첨부(sidebar)가 9-11px으로 가장 작은가?
  • 폰트 크기가 중요도 순서와 일치하는가? (핵심 > 본문 > 배경 > 첨부)
  • 컨테이너 비율이 텍스트 양에 맞게 조정되었는가?
  • "용어 정의" 라벨이 카드 좌측에 정렬되었는가?
  • 모든 영역에서 텍스트가 잘리지 않는가?
  • 다른 MDX(텍스트 양이 다른)에서도 위계가 유지되는가?