- align Phase Z hierarchy terms with Layer A and Frame Slot planning - reframe Type A/B/B'/B'' as legacy layout hints - record trace-only render path activation as the current anchor model
30 KiB
Design Agent — 콘텐츠 시각 구조화 슬라이드 생성기
프로젝트 목적
텍스트/MDX 콘텐츠를 **가로 슬라이드(1페이지 또는 다중 페이지)**로 시각 구조화하는 독립 에이전트. 콘텐츠의 의미를 분석하여 적합한 레이아웃 블록을 선택하고, 핵심만 추출하여 깔끔한 HTML/CSS로 렌더링한다.
핵심 원칙:
- 전체 페이지를 하나의 고정 템플릿으로 찍어내는 것이 아니라, 콘텐츠를 분석 → 각 덩어리별로 적합한 레이아웃 블록 선택 → 조합하여 배치
- 기획자(편집자)가 정리한 텍스트가 기준. 디자인이 텍스트에 맞춘다 (텍스트가 디자인에 맞추는 것이 아님)
- 모든 판단은 실장/팀장/편집자의 사고. 하드코딩 없음
위계 + 용어 (Phase Z 정리, 2026-04-28)
매칭 시스템 (V1~V4) 통합 설계 시 정리. 상세는
IMPROVEMENT-REDESIGN.md4 장 참조.Phase Z 사전 작업 — Frame Zone 적용 분류
docs/architecture/FRAME-INTEGRATION-MAP.md, Frame / Style / Token 인벤토리docs/architecture/PHASE-Z-FRAME-STYLE-INVENTORY.md.
슬라이드 위계
[ slide ] 1280×720 (전체 슬라이드)
│
├─ slide-title ← MDX 대목차 제목 (자동 매핑)
├─ slide-divider (고정)
│
├─ slide-body ≈ 1200×590 (콘텐츠 영역 — `templates/blocks/slide-base.html`)
│ │
│ └─ 레이아웃 (8-preset layout vocabulary; legacy hint = Type A/B/B'/B'')
│ │
│ └─ Zone (top / bottom_l / bottom_r 등)
│ │
│ └─ 프레임 (Figma 디자인 단위)
│
└─ slide-footer ← MDX 대목차 결론 (자동 매핑)
용어
| 용어 | 의미 |
|---|---|
| 슬라이드 | 1280×720 한 장 |
| slide-base | 모든 슬라이드 공통 그릇 (배경 + 제목 + 구분선 + 결론 pill) — templates/blocks/slide-base.html |
| slide-body | 본문 가용 영역 (≈ 1200×590) |
| 레이아웃 (Layout) | 8-preset layout vocabulary — slide-body 안 zone 분배 형태 (legacy hint = Type A/B/B'/B'') |
| Zone (영역) | 레이아웃이 결정한 콘텐츠 구역 |
| Internal Region | Zone 안의 placement / planning unit (Layer A) — content_object 를 배치하는 내부 영역 (SPEC v1 §2) |
| 컨테이너 (Container) | zone 의 px 명세 (코드 레벨) |
| 프레임 (Frame) | Figma 디자인 단위 (= 기존 "블록") — zone 안 |
| Frame Slot | Frame 안의 declared placement slot (Layer B) — frame contract 가 선언하는 콘텐츠 placement target (SPEC v1 §3) |
| Layer A | composition planning 의 zone-내 layer — content_object 를 Internal Region 으로 배치하는 단위 (SPEC v1 §1~§2) |
| Layer B | frame contract 기반 frame-내 layer — 콘텐츠 매핑 대상인 Frame Slot 구조를 선언하는 단위 (SPEC v1 §3) |
MDX → 슬라이드 매핑
| MDX 위치 | 슬라이드 위치 |
|---|---|
# 대목차 제목 |
slide-title |
본문 (## / ###) |
slide-body 안 (레이아웃 + zone + 프레임) |
# 대목차 결론 |
slide-footer |
<details> 팝업 |
슬라이드 위 별도 레이어 |
Layer A planning telemetry is active in trace-only mode; render path activation remains the next axis.
아키텍처 — Phase Z 흐름 (5 단계)
상세는
IMPROVEMENT-REDESIGN.md5 장 참조.
STAGE 1) MDX 분석 + 레이아웃 매칭 (8-preset layout vocabulary; legacy = Type A/B/B'/B'')
STAGE 2) Zone 별 텍스트 1차 배치
STAGE 3) Zone 별 프레임 매칭 (V1~V4; B4 frame_selection evidence integration pending)
├ 매칭 완벽 → 텍스트 업데이트
├ 매칭 어정쩡 → 디자인 참고 재구성
└ 매칭 안 됨 → 디자인 컨셉 바탕 재구성
STAGE 4) 프레임 검토 + 컨테이너 조정 (5 차 Fallback)
STAGE 5) HTML 조립 + 검증 + 출력
핵심 원칙 :
- MDX 1 파일 = 슬라이드 1 장 (절대 분할 X)
- 텍스트 원문 무손실 보존 (본문 미리보기 + 팝업 원문)
- 자유 디자인 금지 (항상 Figma 프레임 DB 참고)
- 불일치 시 레이아웃 회귀 (콘텐츠 줄이지 않고 그릇 변경)
아키텍처 (Phase Q 파이프라인 — 기존)
Phase P(다후보 렌더링 비교) 실행 결과 20/100점. 업계 조사(Beautiful.ai, Napkin.ai, VASCAR 등) 기반으로 Phase Q에서 재설계. 핵심 전환: "계산 먼저, AI 판단 나중에, 렌더링은 검증만"
⚠️ Phase Z (매칭 시스템 통합) 진행 후 이 섹션의 일부는 새 흐름으로 대체될 예정.
[1단계] Kei 실장 (Opus) — AI 사고
꼭지 추출 → 정보 구조 파악 → 비중(page_structure) → relation_type
↓
[1.5단계] Kei 실장 (Opus) — 컨셉 구체화
relation_type, expression_hint, source_data
↓
[컨테이너 계산] 코드 — 결정론적
Kei 비중 → 역할별 컨테이너 px 확정
↓
[2단계] 블록 선택 (Phase Q) — 코드(결정론적) + Kei 1회
① relation_type → 블록 카테고리 매핑 (코드, Napkin.ai 방식)
② 컨테이너 제약 필터링: min_height_px, height_cost, sidebar 제한 (코드)
③ catalog 존재 검증: 유령 블록 차단 (코드)
④ 글자수 예산 계산: 컨테이너 px → 최대 글자수/항목수 (코드)
⑤ Kei에게 필터된 2-3개 후보 제시 → 1개 선택 (AI 1회)
↓
[3단계] Kei 편집자 (Opus) — AI 사고
글자수 예산 = 하드 제약. 예산 안에서 의미 우선 편집. 원본 보존.
↓
[4단계] 디자인 실무자 (Sonnet + Jinja2) — CSS 조정 + HTML 조립
↓
[검증] Selenium 1회 렌더링 — overflow 확인 (코드)
overflow 시: ① 간격 축소(LaTeX 글루) ② 폰트 축소(이진탐색) ③ 텍스트 압축(AI 1회)
↓
[품질 게이트] Opus 멀티모달 (VASCAR식)
스크린샷 기반 시각 품질 평가 → 미달 시 교정 또는 출력 차단
레이아웃 프리셋 (2단계 Step A)
실장의 role 분석을 보고 규칙 기반으로 프리셋을 자동 선택한다. LLM 호출 불필요.
| 프리셋 | 조건 | CSS grid |
|---|---|---|
sidebar-right |
reference 꼭지가 1개 이상 있음 | "title title" "body sidebar" "footer footer" / 65fr 35fr |
two-column |
모든 flow 꼭지가 대등한 비교 | "title title" "left right" "footer footer" / 1fr 1fr |
hero-detail |
고강조 꼭지 1개 + 나머지 보조 | "title title" "hero hero" "detail detail" "footer footer" |
single-column |
모든 꼭지가 flow, 순차적 | "title" "body" "footer" / 1fr |
선택 규칙:
reference 꼭지 있음 → sidebar-right
모든 flow가 대등 비교 → two-column
고강조 1개 + 나머지 보조 → hero-detail
나머지 → single-column
역할 분리 (Phase Z)
⚠️ Phase R' 의 역할 분리 (AI 가 HTML 구조 직접 생성) 는 Phase Z 에서 폐기. 아래는 Phase Z 기준.
| 역할 | 담당 | 방식 | 하는 일 | 하지 않는 일 |
|---|---|---|---|---|
| Kei 실장 | Opus (Kei API) | AI | MDX 본문 분석 보조, 최종 검수 | HTML 생성, 레이아웃 계산 |
| 레이아웃 결정 | 코드 | 룰 매칭 | MDX 콘텐츠 → 8-preset layout vocabulary 기반 slide/zone topology 선택 (legacy hint = Type A/B/B'/B'') | — |
| 컨테이너 계산 | 코드 | 결정론적 | zone 별 px 확정 (space_allocator) |
— |
| 프레임 매칭 | 코드 (V1~V4; B4 frame_selection evidence integration pending) | 결정론적 | zone ↔ Figma 프레임 매칭 | — |
| 콘텐츠 매핑 | 코드 + AI | 하이브리드 | zone 안 콘텐츠 / 텍스트를 프레임 슬롯에 배치 / 다듬기 / 변형 | HTML 구조 생성 X |
| HTML 조립 | 코드 (Jinja2) | 결정론적 | slide-base + 프레임 + 슬롯 콘텐츠 합쳐서 final.html |
AI 호출 X |
| 검증 | 코드 + AI | Selenium + Vision | overflow 측정, 시각 품질 평가 | — |
HTML 생성 원칙 (Phase Z)
블록이 구조를 결정 (P=Q=R, 실패)
콘텐츠가 구조를 결정 (R', 폐기 — AI 가 HTML 직접 생성하면 회귀 가능성 큼)
→ slide-base + 프레임 DB 가 구조를 결정, AI 는 zone 안 콘텐츠만 (Phase Z)
Phase Z 의 핵심 원칙:
- HTML 구조 =
slide-base.html+ 코드 (Jinja2) 가 결정 (절대 AI 가 생성 X) - AI 의 역할 = zone 안 콘텐츠 매핑 / 텍스트 다듬기 / 디자인 변형 (콘텐츠 단위)
- 프레임 DB 참고 필수 — 자유 디자인 금지
- MDX 원문 무손실 보존 (본문 preview, 팝업에 원문)
⚠️ Phase R' 회귀 방지: AI 한테 "HTML 구조 만들어줘" 같은 호출 절대 X. AI 호출은 zone 안 콘텐츠 단위로만.
핵심 프로세스 (구 Phase Q 기준 — Phase Z 에서 대체됨)
⚠️ 아래 흐름은 구 Phase Q 기준의 5 단계 (Kei 실장 → 디자인 팀장 → 텍스트 편집자 → 디자인 실무자 → 재검토). Phase Z 에서 대체됨.
신규 흐름은 위 "아키텍처 — Phase Z 흐름 (5 단계)" 섹션 또는 IMPROVEMENT-REDESIGN.md 5 장 따름.
⚠️ 특히 Phase Z 와 충돌하므로 무시할 것:
- "페이지 분리" → Phase Z: MDX 1 파일 = 슬라이드 1 장 (절대 분할 X)
- "텍스트 압축 / 요약" → Phase Z: MDX 원문 무손실 보존 (본문 preview, 팝업 원문)
- "AI 5 단계" → Phase Z: AI 호출은 zone 안 콘텐츠 단위로만 (HTML 구조 / 레이아웃 / 프리셋 결정 X)
사용자 콘텐츠 입력 (텍스트/MDX 붙여넣기 또는 파일 업로드)
↓
[1단계] Kei 실장 — 꼭지 추출 + 분석
꼭지 추출:
- 본문에서 핵심 꼭지 추출 (2~5개)
- 1페이지 적정 꼭지 수: 5개
페이지 분리 판단:
- 중요도가 5개를 넘고 레이어도 동등하면 → 2페이지로 분리
- 내용과 의미 기반으로 자연스러운 분할 (2/3, 3/4, 4/3, 5/2 등)
- 5개인데 내용이 많으면 → 꼭지 레이어를 보고 세부 내용은 자세히보기로
각 꼭지 분석:
- 레이어 수준 (도입/핵심/보조/결론)
- 강조 판단 (어떤 꼭지를 눈에 띄게 할 것인가)
- 배치 방향 (세로로 긴 꼭지, 가로 나열 꼭지)
이미지 판단:
- 몇 개인지, 어떤 꼭지에 속하는지
- 핵심인지(도표/차트) 보조인지(참고 문서 표지)
- 텍스트가 포함된 이미지인지 (너무 축소하면 안 됨)
표 판단:
- 행/열 규모
- 전체 표시 가능한지, 요약 필요한지
상세 콘텐츠 판단:
- 너무 구체적/세부적인 내용은 "자세히보기" 대상
↓
[2단계] 블록 선택 (Phase Q — 코드 결정론적 + Kei 1회)
Step A: 프리셋 선택 (규칙 기반, LLM 불필요)
- 실장의 role 분석을 보고 자동 선택
Step B: 제약 기반 블록 선택 (코드 결정론적 + Kei AI 1회)
① relation_type → 블록 카테고리 매핑 (코드)
hierarchy → visuals, comparison → tables/emphasis, definition → cards 등
② 컨테이너 제약 필터링 (코드)
min_height_px, height_cost, sidebar 시각 블록 제한, 중복 블록 제한
③ catalog.yaml 존재 검증 (코드) — 유령 블록 차단
④ 글자수 예산 계산 (코드)
컨테이너 px → 최대 글자수/항목수 → AI 편집 시 하드 제약
⑤ Kei에게 필터된 2-3개 후보 제시 → 1개 선택 (AI 1회)
- AI에게 불가능한 선택지를 주지 않는다 (Beautiful.ai 원칙)
이미지 배치:
- 원본 이미지 크기 확인 (Pillow Image.open().size)
- 가로/세로 비율에 따라 영역 결정
- 이미지는 원본 그대로 사용, 크기만 조절
표 배치:
- 행×열 규모 보고 공간 안에 들어가는지 판단
- 안 들어가면 요약 요청 또는 popup
자세히보기:
- detail_target 꼭지는 <details>/<summary>로 popup 연결
↓
[3단계] Kei 텍스트 편집자 — 텍스트 정리 (글자수 예산 포함)
- 글자수 예산 = 하드 제약 (컨테이너 px에서 수학적으로 도출)
- 예산 안에서 내용 의미 우선 편집
- 전체 컨텍스트와 핵심 용어 유지
- 도메인 전문가로서 세련된 표현으로 편집
- 출처 보존, 개조식 작성, 날조 금지
- 표 내용도 편집 (핵심 행/열 선택, 요약 등)
- 자세히보기 대상은 요약 버전 + 상세 버전 둘 다 작성
↓
[4단계] 디자인 실무자 — 디자인 조정 + HTML 조립
텍스트 맞춤:
- 편집자가 정리한 텍스트 양에 맞게 디자인 조정
- 텍스트가 가이드보다 길면 → 폰트/여백/박스를 조정 (텍스트를 자르지 않음)
- 빈 공간 방치 안 함 (박스 줄이거나 공간 활용)
이미지 처리:
- object-fit: contain (비율 유지, 잘리지 않게)
- 팀장이 정한 영역 크기에 맞춤
표 처리:
- table-layout: fixed + container query 폰트 스케일링
- 행/열 수에 따라 셀 크기 자동 조정
자세히보기:
- <details>/<summary>로 접기/펼치기
- 인쇄 시 자동 펼침 (JavaScript)
HTML 조립:
- Jinja2 템플릿 렌더링
- 다중 페이지 시 page-break 처리
↓
[검증] Selenium 1회 렌더링 (코드)
- overflow 확인 (글자수 예산으로 대부분 사전 방지됨)
- overflow 시 수학적 조정:
① 간격 축소 (LaTeX 글루 모델, AI 없음)
② 폰트 크기 축소 (이진 탐색, AI 없음)
③ 텍스트 압축 (최후 수단, AI 1회)
↓
[품질 게이트] Opus 멀티모달 (VASCAR식)
- 스크린샷 기반 시각 품질 평가:
① 콘텐츠 겹침/잘림 없는가?
② 본심 영역이 시각적으로 가장 두드러지는가?
③ 폰트가 읽을 수 있는 크기인가?
④ 블록 유형에 다양성이 있는가?
⑤ 한국어 비즈니스 프레젠테이션으로서 적절한가?
- 미달 시: 구체적 문제 교정 → 재렌더링 (최대 2회)
- 미달 지속 시: 출력 차단 (깨진 슬라이드를 사용자에게 전달하지 않음)
↓
미리보기 → HTML 다운로드
핵심 원칙 (Phase Q):
- 계산 먼저, AI 판단 나중에, 렌더링은 검증만 — 업계 조사 기반 핵심 원칙
- 블록 = 시각 패턴(구조), 크기가 아님 — 같은 블록이 컨테이너에 따라 항목수/폰트/패딩 변동
- AI에게 불가능한 선택지를 주지 않는다 — 결정론적 필터링 후 Kei에게 제시
- 글자수 예산은 하드 제약 — 컨테이너 px에서 수학적으로 도출, 편집 전에 전달
- overflow 상태에서 출력 금지 — 비전 모델 품질 게이트 통과 필수
- 텍스트 편집자가 정리한 텍스트가 기준. 디자인이 텍스트에 맞춘다.
- 실무자는 텍스트를 자르지 않고, 디자인을 조정한다.
- 이미지는 원본 그대로 사용, 크기만 조절.
- 표는 표로 유지, 공간 안 되면 요약하거나 페이지 분리.
- 상세 내용은
<details>로 접기/펼치기. - 1차 조립 후 팀장이 전체 균형을 재검토하여 2차 조정.
- 모든 기준은 하드코딩 없이 실장/팀장/편집자의 사고로 판단.
콘텐츠 유형 분류 기준
실장이 콘텐츠를 분석하여 아래 유형으로 분류한다. 이 분류는 하드코딩이 아니라, 실장이 매번 사고하여 판단한다.
| 텍스트 패턴 | 유형 | 적합한 블록 |
|---|---|---|
| "A vs B", 장단점, 차이점 | 비교 | 2단 병렬 / 비교 테이블 |
| "1단계 → 2단계 → 3단계" | 프로세스 | 플로우차트 / 단계 카드 |
| "X는 Y를 포함한다", 상위-하위 | 구성/관계 | 벤 다이어그램 / 트리 |
| 수치, KPI, 통계 | 핵심 지표 | 큰 숫자 + 보조 텍스트 |
| 용어 정의, 개념 설명 | 정의 | 카드 3열 / 아이콘 카드 |
| 기능/특성 나열 | 목록 | 아이콘 리스트 / 카드 그리드 |
| 연도별 사건, 로드맵 | 시간 순서 | 타임라인 (가로/세로) |
| 핵심 메시지, 결론 | 강조 | 결론 바 / 인용 블록 |
| 문제 상황, 경고 | 문제 제기 | 경고 박스 / 강조 인용 |
| 이미지 + 텍스트 | 이미지 참조 | 전체너비 / 사이드 / 썸네일 |
| 다항목 데이터 | 표 | 비교 테이블 |
| 세부/구체적 내용 | 자세히보기 | <details>/<summary> |
블록 타입 정의
6개 카테고리, 18개 블록 변형. 상세는 templates/blocks/INDEX.md 참조.
| 카테고리 | 블록 수 | 구현 방식 | 주요 블록 |
|---|---|---|---|
| headers/ | 2 | HTML/CSS | section-title-with-bg, topic-left-right |
| cards/ | 3 | HTML/CSS | card-image-3col, card-text-grid, card-dark-overlay |
| tables/ | 1 | HTML/CSS | compare-3col-badge |
| visuals/ | 4 | SVG (수학적 좌표 계산) | venn-diagram, circle-gradient, compare-pill-pair, process-horizontal |
| emphasis/ | 5 | HTML/CSS | quote-left-border, conclusion-accent-bar, comparison-2col, banner-gradient, quote-question |
| media/ | 3 | HTML/CSS + 이미지 | image-row-2col, image-grid-2x2, image-side-text |
각 블록은 독립적인 컴포넌트로 슬롯(교체 가능한 위치)을 가지며, catalog.yaml에 when/not_for/slots가 정의되어 있다.
이미지 처리 원칙
- 원본 이미지를 그대로 사용 (crop/재구성은 극히 예외)
- 팀장이 슬라이드 구조에 맞게 크기만 조절 (가로/세로 비율 유지)
- 이미지 크기 읽기: Pillow
Image.open().size(헤더만 읽음, 전체 로드 안 함) - 가로형(ratio > 1.2) → 전체 너비 배치
- 세로형(ratio < 0.8) → 텍스트 옆 배치
- 텍스트 포함 도표 → 너무 작게 축소하면 안 됨
- CSS:
object-fit: contain(전체 보이게, 비율 유지)
표 처리 원칙
- 표는 표로 유지 (다른 형태로 전환하지 않음)
- 공간에 안 들어가면: 요약하거나 페이지 분리
- CSS:
table-layout: fixed+ container query 폰트 스케일링 - 표 내용 편집은 Kei 텍스트 편집자가 담당
자세히보기 (상세 콘텐츠) 원칙
- HTML 네이티브
<details>/<summary>사용 (JavaScript 불필요) - 슬라이드 표면: 요약/핵심만 표시
- 펼치면: 전체 상세 내용 표시
- 인쇄 시: JavaScript 6줄로 자동 펼침
- 정보 밀도는 실장/팀장이 사고로 판단 (하드코딩 기준 없음)
페이지 구성 원칙
레이아웃 배치 규칙
- CSS Grid 기반 (
grid-template-areas) - 가로 슬라이드 비율: 16:9 (1280×720)
- 1페이지 적정 꼭지 수: 5개
- 정보 계층: 위 → 아래 (문제 제기 → 분석 → 결론)
- 여백: 블록 간 최소 20px, 페이지 패딩 40px
페이지 분리 기준
- 꼭지 5개 이하 + 내용 적절 → 1페이지
- 꼭지 5개 + 내용 많음 → 1페이지 + 일부 자세히보기
- 꼭지 5개 초과 + 레이어 동등 → 2페이지 (의미 기반 분할)
- 분할 비율: 2/3, 3/4, 4/3, 5/2 등 내용에 따라
블록 조합 예시
┌─────────────────────────────────────────────┐
│ [강조 인용] 문제 제기 │
├──────────────────┬──────────────────────────┤
│ [사례 카드 2열] │ [카드 그리드 3열] │
│ 정책 사례 │ 용어 정의 │
├──────────────────┴──────────────────────────┤
│ [관계도] 벤 다이어그램 │
├─────────────────────────────────────────────┤
│ [결론 바] 핵심 한 줄 │
└─────────────────────────────────────────────┘
글자 수 추정 (타이포그래피 기반)
한글은 글자 너비가 거의 일정하므로, 블록 크기에서 글자 수를 계산할 수 있다. 이 계산은 팀장의 글자 수 가이드를 보조하는 참고 도구이지, 하드코딩 기준이 아니다.
계산식:
한 줄 글자 수 = 블록 너비(px) ÷ (폰트 크기(px) × 0.97)
줄 수 = 블록 높이(px) ÷ (폰트 크기(px) × 줄간격)
총 글자 수 = 한 줄 글자 수 × 줄 수 × 안전 계수(0.85)
Pretendard 폰트 크기별 참고값 (1회 측정, 상수 저장):
| 폰트 크기 | 한글 글자 너비 | 줄간격 1.6 기준 줄 높이 |
|---|---|---|
| 12px | ~11.6px | 19.2px |
| 16px | ~15.5px | 25.6px |
| 20px | ~19.4px | 32.0px |
| 24px | ~23.3px | 38.4px |
디자인 원칙 (절대 규칙)
DO (해야 하는 것)
- 여백을 충분히 확보한다 (여백 > 장식)
- 색상은 최대 3개 (메인 1개 + 포인트 1개 + 중성 1개)
- 폰트 크기 체계를 일관되게 유지 (제목/소제목/본문/캡션 4단계)
- 흑백 기조 + 포인트 컬러 최소 사용
- 정보 계층을 시각적으로 명확히 표현
DON'T (하지 않는 것)
- HTML/CSS 블록의 배경 그라데이션 금지 (SVG 시각화 블록, 디자인 의도가 명확한 블록(배너, 오버레이, 콜아웃 등)은 허용)
- CSS 애니메이션/트랜지션 금지
- 호버 효과 금지
- 그림자(box-shadow) 최소화 (1개 레벨만. SVG filter는 예외)
- 다크 테마 금지 (요청하지 않는 한)
- 둥근 모서리 과다 사용 금지 (border-radius 최대 8px)
- 텍스트를 자르지 않는다 (디자인이 텍스트에 맞춘다)
디자인 토큰
:root {
/* 색상 */
--color-primary: #1e293b;
--color-accent: #2563eb;
--color-neutral: #64748b;
--color-bg: #ffffff;
--color-bg-subtle: #f8fafc;
--color-border: #e2e8f0;
--color-danger: #dc2626;
/* 폰트 크기 */
--font-title: 2rem;
--font-subtitle: 1.25rem;
--font-body: 0.95rem;
--font-caption: 0.8rem;
/* 여백 */
--spacing-page: 40px;
--spacing-block: 20px;
--spacing-inner: 16px;
/* 기타 */
--radius: 6px;
--border-width: 1px;
--accent-border: 3px;
}
Kei API 연동
호출 포인트
| 단계 | API | 용도 |
|---|---|---|
| 1단계 꼭지 추출 | Anthropic API (Sonnet) | 꼭지 추출 + 레이어 + 강조 + 배치 + 이미지/표/상세 판단 |
| 2단계 레이아웃 설계 | Anthropic API (Sonnet) | 블록 매핑 + 공간 배분 + 글자 수 가이드 |
| 3단계 텍스트 정리 | Anthropic API (Sonnet) | 의미 보존 편집 + 표 편집 + 자세히보기 작성 |
| 4단계 디자인 조정 + 조립 | Anthropic API (Sonnet) + Jinja2/CSS | 텍스트에 맞게 디자인 조정 + HTML 생성 |
| 5단계 재검토 | Anthropic API (Sonnet) | 균형 점검 + 2차 조정 |
독립 실행 가능
- Kei API 없이 Anthropic API 직접 호출로 동작
- Kei API 연결 시 1단계에서 Kei RAG 지식 활용 가능
블록 라이브러리
핵심 원칙: 변형 기반 선택
하나의 블록 유형에 **여러 변형(variation)**이 존재하고, 디자인 팀장이 콘텐츠 성격에 맞는 변형을 검색하여 선택한다.
콘텐츠 분석 → "이 꼭지는 좌:질문 우:설명 구조다"
↓
블록 라이브러리 검색 → headers/ 카테고리에서 후보 3~4개 반환
↓
팀장이 선택 → topic-left-right.html
카테고리 구조 (6개, 18개 블록)
templates/blocks/
├── INDEX.md ← 전체 인덱스 + 추가 예정 목록
├── headers/ (2개) ← 타이틀, 꼭지 헤더
│ ├── section-title-with-bg.html 배경 이미지 + 영문/한글 타이틀
│ └── topic-left-right.html 좌:파란 제목 + 우:설명
├── cards/ (3개) ← 카드 계열 (정보 나열)
│ ├── card-image-3col.html 상단 이미지 + 하단 텍스트 3열
│ ├── card-text-grid.html 텍스트만 카드 2~4열
│ └── card-dark-overlay.html 다크 이미지 배경 + 흰 텍스트 오버레이
├── tables/ (1개) ← 표/비교 계열
│ └── compare-3col-badge.html A|VS배지|B 3단 비교
├── visuals/ (4개) ← 시각 요소 — **SVG로 제작**
│ ├── circle-gradient.html 파란 그라데이션 원 + 텍스트
│ ├── compare-pill-pair.html 둥근 테두리 박스 2개 + VS
│ ├── venn-diagram.html 벤 다이어그램 (**SVG premium, 수학적 계산**)
│ └── process-horizontal.html 가로 단계 흐름
├── emphasis/ (5개) ← 강조 (인용, 결론)
│ ├── quote-left-border.html 좌측 라인 + 인용
│ ├── conclusion-accent-bar.html 좌측 파란 라인 + 밝은 배경 결론
│ ├── comparison-2col.html 2단 병렬 비교
│ ├── banner-gradient.html 파란 그라데이션 전체 너비 배너
│ └── quote-question.html 질문형 강조 박스
└── media/ (3개) ← 이미지/미디어
├── image-row-2col.html 이미지 2장 나란히
├── image-grid-2x2.html 이미지 4장 2x2 격자
└── image-side-text.html 좌:이미지 우:텍스트+불릿
시각화 방식 (Phase 1 확정)
블록 유형별 구현 방식:
| 블록 유형 | 구현 방식 | 이유 |
|---|---|---|
| 텍스트 블록 (카드, 비교, 표, 인용, 결론) | HTML/CSS | Jinja2 템플릿으로 조립 |
| 시각화 다이어그램 (관계도, 프로세스, 순환도) | SVG | 좌표 정확 + 그라데이션/글로우 가능 + 개수 자동 대응 |
| 실사 이미지 (시공 사진, 3D 렌더링) | Figma export 또는 원본 이미지 | CSS/SVG로 재현 불가 |
| 배경 텍스처 (보케, 분위기) | Gemini API 이미지 생성 | 실사 배경 전용 |
SVG 시각화 원칙 (검증 완료):
- SVG 안에
<text>포함 → 원 좌표와 텍스트 좌표가 같은 공간 → 위치 100% 정확 radialGradient,linearGradient→ 고급 그라데이션filter: feGaussianBlur,feDropShadow→ 글로우/그림자- 하이라이트 오버레이 → 구체(3D) 느낌
- 수학적 계산 (
cos/sin) → N개 원소 자동 배치 (360/N간격) — Phase 2 구현 예정. 현재는 3개 고정 SVG
AI 이미지 생성은 시각화에 사용하지 않는다:
- AI 생성 이미지는 원 위치가 매번 달라 텍스트 위치를 맞출 수 없음 (검증 완료)
- AI 이미지는 실사 배경 텍스처 (보케, 헥사곤, 분위기)에만 사용
변형 검색 (향후)
변형이 수십~수백 개로 늘어나면:
- 각 블록 HTML의 구조/슬롯/용도를 임베딩
- FAISS 인덱스로 구축
- 콘텐츠 분석 결과를 쿼리 → 적절한 변형 3~4개 반환
- 팀장이 최종 선택
현재 규모(13개)에서는 catalog.yaml만으로 충분. 40개 이상부터 FAISS 도입 검토.
catalog.yaml
- 디자인 팀장의 "메뉴판"
- 각 블록의 id, 시각 설명, 언제 쓰는지(when), 슬롯 목록
- Figma에서 디자인 추출 → 템플릿 변환 → catalog에 등록
- 블록 추가 시 반드시 catalog에도 등록 (미등록 = 팀장이 모름)
Figma 에셋
Figma에서 추출한 이미지 에셋은 docs/figma-assets/에 저장:
- 배경 이미지 (bg_header.png 등)
- 3D 렌더링 이미지 (card_img_design.png 등)
- 시각화 에셋 (mountain_viz.png 등)
- 블록에서
src="{{ image_path }}"로 참조
기술 스택
| 역할 | 도구 | 비고 |
|---|---|---|
| 서버 | FastAPI + uvicorn | 포트 8001 |
| 템플릿 | Jinja2 | 카테고리별 블록 조합 |
| 렌더링 | CSS Grid + 디자인 토큰 | 슬라이드(16:9) + 웹(세로 스크롤) |
| 폰트 | Pretendard Variable | word-break: keep-all |
| AI | Anthropic API (Sonnet) | 5단계 모두 |
| 이미지 크기 | Pillow Image.open().size | 헤더만 읽음 |
| 시각화 | SVG (radialGradient, filter, 수학적 좌표 계산) | 다이어그램/관계도 |
| 실사 배경 | Gemini API | 배경 텍스처 전용 (시각화에는 사용 금지) |
| 자세히보기 | <details>/<summary> |
HTML 내장 |
| Figma 연동 | Figma REST API + Framelink MCP | 에셋 추출, 디자인 토큰 |
| 변형 검색 | FAISS (향후) | 블록 40개+ 시 도입 |
| 출력 | HTML 다운로드 / .astro (Starlight) |
향후 연결 가능성
현재: 독립 개발 + 테스트
↓
검증 후 선택지:
A) Kei 본체에 합치기 (대화 안에서 "슬라이드로 정리해줘")
B) 글벗에 붙이기 (문서 자동화 → 시각화 단계)
C) 둘 다
금지 사항
- Kei Persona Agent 코드를 수정하지 않는다
- 디자인 판단을 하드코딩하지 않는다 (AI가 사고한다)
- 전체 페이지를 하나의 고정 템플릿으로 만들지 않는다 (블록 조합 방식)
- 텍스트를 자르지 않는다 (디자인이 텍스트에 맞춘다)
- 이미지를 crop하지 않는다 (크기만 조절)
- 그라데이션, 애니메이션, 다크 테마를 기본으로 사용하지 않는다