---
name: beautiful-pptx
description: .pptx/슬라이드/덱/발표자료를 만들거나 편집·읽을 때 발동. "deck", "slides", "presentation", ".pptx", "발표자료", "PPT 만들어줘", "슬라이드로 정리", "피치덱", "디펜스 슬라이드" 등이 언급되면 사용. 신규 생성(스펙·마크다운→pptxgenjs 빌드), 회사 템플릿 편집(Anthropic office 스크립트), 기존 .pptx 읽기(markitdown) 세 갈래를 모두 처리한다.
---

# beautiful-pptx

발표 덱을 코드로 생성·편집·검수하는 스킬. 엔진은 **pptxgenjs**. 디자인은 WCAG·Tufte·assertion-evidence 같은 정량 규칙을 코드 린트로 박제해서, "AI 티 나는 못생긴 슬라이드"를 생성 단계에서 막는다.

상세 규율은 곁의 두 문서로 분리:
- **DESIGN.md** — 색·타이포·그리드·아키타입·차트·린트 규칙 전부.
- **PRESETS.md** — 장르 프리셋 4종(연구·디펜스·임원·피치)의 슬라이드 시퀀스와 톤.

---

## 1. 3-갈래 라우팅 (먼저 어느 길인지 정한다)

| 길 | 언제 | 무엇으로 |
|---|---|---|
| **(A) 신규 생성** | "처음부터 만들어줘", 내용·주제만 있을 때 | 개요 → deckSpec JSON 또는 마크다운 → `deck.js build` (pptxgenjs) |
| **(B) 템플릿 편집** | 회사·기존 .pptx 양식을 채우거나 고칠 때 | Anthropic `office/` 스크립트(unpack→편집→clean→pack). 있으면 호출, 없으면 (A)로 폴백 |
| **(C) 읽기** | 기존 .pptx 내용을 텍스트로 뽑을 때 | `markitdown deck.pptx` (있으면). 없으면 unpack 후 XML 텍스트 추출 |

대부분 요청은 **(A)**. 사용자가 "이 템플릿에 맞춰" / 특정 .pptx를 주면 (B). "이 발표 내용 요약해줘"면 (C).

---

## 2. 워크플로 — 묻고, 가이드라인 주고, 깊이 합의 후 빌드 (절대 한 방에 찍지 마라)

**핵심 원칙: 발표 덱은 사용자와 함께 설계하는 것이지, 주제만 받고 얕게 찍어내는 게 아니다.** 특히 논문·기술 내용은 8~12장으로 절대 다 못 담는다 — **깊이를 먼저 합의한다.**

### 2-1. 인테이크 (생성 전 필수 — 모르면 가이드라인과 함께 묻는다)

사용자가 안 알려준 항목은 **AskUserQuestion으로 묻되, 각 선택지에 가이드라인을 붙여 준다**(karpathy식 — 그냥 묻지 말고 권고를 함께). 파악할 것:

- **목적·청중** → 프리셋 결정: 학회(research-talk) / 디펜스·심사(defense) / 임원 보고(exec) / 투자 피치(pitch) / 강의·교육(lecture).
- **발표 시간(분)** → 분량: 말 많은 슬라이드 분당 약 1장. 15분≈15장, 30분≈25~30장.
- **깊이(가장 중요)**:
  - **요약** (8~12장) — 핵심만. 소개·라이트닝 토크.
  - **표준** (15~20장) — 일반 발표.
  - **정밀·교육** (25~40장) — 논문 완독 수준. 동기·배경·방법·결과·분석·한계를 **각각 여러 장으로 쪼개** 깊이 설명. **논문·기술 주제의 기본 권고값.**
- **강조점**: 꼭 들어갈 핵심·그림·수치.
- **테마·소스**: 색 테마(slate/navy/forest/plum/mono/warm), 원본 자료(논문 PDF·데이터).

가이드라인 예시(이렇게 권고하며 묻는다): *"논문 발표면 정밀(25~35장)을 권합니다 — 8장으론 방법·결과를 제대로 못 보여줍니다. 핵심 결과 그림은 한 장에 하나씩(assertion-evidence), 짧으면 백업으로 빼고요. 어느 깊이로 갈까요?"*

### 2-2. 개요 제시 → 확인

합의한 깊이·프리셋으로 **슬라이드별 제목 + 유형**을 표로 제시(아직 빌드 X). **정밀 깊이면 한 섹션을 한 장에 욱여넣지 말고 여러 장으로 펼친다** — 예: 방법을 `방법 개요 → 세부 단계1 → 세부 단계2 → 직관 그림` 4장으로, 결과는 그림 하나당 슬라이드 하나. "제목 스택 테스트"(제목만 읽어도 논리 성립)로 점검하고 사용자가 수정·승인.

### 2-3. 빌드 → 시각 QA → 수정 루프

3. **빌드.** deckSpec JSON → `deck.js build`. 반환에 린트 경고 배열이 온다.
4. **시각 QA(필수).** soffice/pdftoppm로 .pptx→PDF→슬라이드 PNG 렌더 후 **버그헌트 12항목**(§7)으로 **눈으로** 검수 — 렌더를 안 보고 "잘 됐다"고 하지 마라(겹침·오버플로는 린트로 안 잡힌다). 없으면 설치하거나 사용자에게 받아 확인 요청.
5. **수정 반복.** 겹침·오버플로·대비·정렬을 고치고 다시 렌더·검수. 깨끗할 때까지.

개요·인테이크 단계를 건너뛰지 마라. "그냥 빨리"라고 해도 **깊이 한 번, 슬라이드 제목 목록 한 번**은 확인받고 간다.

---

## 3. 사용법 (실행)

엔진이 전역 설치라 `NODE_PATH`를 잡아준다. 또는 스킬 폴더에서 `npm install` 한 번 하면 로컬 resolve.

```bash
# 전역 설치 resolve
NODE_PATH=$(npm root -g) node deck.js build spec.json out.pptx

# 또는 스킬 폴더에서 로컬 설치 후
cd ~/.claude/skills/beautiful-pptx && npm install
node deck.js build spec.json out.pptx

# 엔진 점검(예제 스펙으로 빌드)
node deck.js smoke
```

`build`는 `{path, lint}`를 반환. `lint`는 `[{rule, level, msg}]` 배열 — `level:'fail'`이 하나라도 있으면 고치고 다시 빌드한다.

### deckSpec JSON 형태

공개 입력은 이 JSON 하나(CONTRACT §5):

```json
{
  "theme": "slate", "mode": "light",
  "preset": "research-talk", "layout": "16x9",
  "slides": [
    { "type": "cover", "title": "...", "subtitle": "...", "meta": "발표자·날짜", "notes": "..." },
    { "type": "keymsg", "title": "X는 Y 조건에서 Z만큼 개선된다", "chart": {...}, "source": "..." },
    { "type": "kpi", "title": "...", "items": [{ "value": "37%", "label": "...", "interp": "...", "color": "ok" }] },
    { "type": "chart", "title": "...", "chartType": "bar", "data": [...], "takeaway": "so-what 한 줄", "source": "..." },
    { "type": "closing", "title": "감사합니다 / Q&A", "contact": "..." }
  ]
}
```

마크다운 입력도 받는다: `parseDeck(md)` 가 H1=섹션, H2=슬라이드, 표=chart/kpi 후보, frontmatter=theme/preset/layout으로 변환. 유형이 비면 `chooseLayout`이 휴리스틱으로 채운다(숫자 1~2개→kpi, A vs B→compare, 연도 나열→timeline, 인용부호→quote, 그 외→keymsg).

### 슬라이드 유형 (DISPATCH 토큰)

`cover` 표지 · `section` 섹션 구분 · `keymsg` 핵심 메시지(assertion-evidence) · `kpi` 수치 카드 · `chart` 차트+so-what · `compare` 2단 비교 · `timeline` 타임라인 · `process` 프로세스 박스 · `quote` 인용 · `closing` 마무리 · `backup` 백업.

각 유형의 좌표·구조는 DESIGN.md 아키타입 9종 참고.

---

## 4. 디자인 규율 (요약 — 상세는 DESIGN.md)

지킬 것만 추리면:

- **색 60/30/10.** 중립 베이스 60%, 보조(짙은 회색/네이비) 30%, 액센트 1색 10%. 액센트를 10% 안에 가둬야 프로처럼 보인다.
- **초록·주황은 텍스트 색 금지.** 흰 배경에서 WCAG AA(4.5:1)를 못 넘는다(3.2~3.6:1). 채움·아이콘·큰 굵은 글자만. 텍스트로 꼭 쓰면 700번대로 어둡게.
- **다크 배경엔 의미색 400번대**로 자동 스왑(라이트=600/700, 다크=400). 표지·섹션·마무리는 다크, 본문은 라이트(샌드위치).
- **본문 18pt 바닥**, 제목 24~28pt, 폰트 2종 이내, 안전폰트만(Calibri/Arial/Georgia, 한글 Malgun Gothic).
- **그리드·세이프존.** 좌우 0.5인치, 상하 0.3인치 여백. 좌표는 직접 박지 말고 `grid`/`col()`에서 산출.
- **제목 밑 액센트 라인 금지**(AI 티). **차트는 막대·라인만**, 파이·3D·격자·범례 제거가 기본.
- **1슬라이드 1메시지.** 시각 요소 6개 넘으면 분할.

---

## 5. 프리셋 (요약 — 상세는 PRESETS.md)

| 프리셋 | 언제 | 논리 | 제목 스타일 | 분량 |
|---|---|---|---|---|
| `research-talk` | 학회 구두발표(12~15분) | 귀납(결론 끝) | assertion(문장) | 12~15장 |
| `defense` | 박사·석사 디펜스/심사 | 귀납·Swath&Dive | assertion | 25~35장 |
| `exec` | 임원 보고 | 연역(답 먼저) | action title(동사) | 8~15장 |
| `pitch` | 투자 피치덱 | 연역·내러티브 | 메시지·임팩트 | 10~12장 |

핵심 갈림: **연구/학술은 근거를 쌓아 마지막에 결론(귀납·assertion)**, **비즈니스는 답을 먼저 놓고 근거로 내려간다(연역·action title)**. 프리셋이 슬라이드 시퀀스를 골격으로 깔아준다.

---

## 6. 린트·QA 게이트

빌드 직후 `lint`가 자동으로 슬라이드를 스캔한다. 규칙 ID(level):

- `L_ELEMENTS`(fail) 시각요소 >6 · `L_FONT`(fail) 본문 <18pt / 제목 <24pt
- `L_TITLELINE`(fail) 제목 밑 액센트 라인 · `L_CONTRAST`(fail) 대비 <4.5:1(대형 bold는 <3)
- `L_TEXTONLY`(warn) 시각요소 0 텍스트만 · `L_CENTERBODY`(warn) 본문 장문 가운데정렬
- `L_ACTIONTITLE`(warn) exec/pitch인데 제목이 동사 없는 명사구 · `L_DENSITY`(warn) 본문 한글 >150자
- `L_SOURCE`(warn) chart/kpi인데 source 비어있음

`fail`은 반드시 고친다. `warn`은 사용자에게 알리고 판단을 맡긴다.

**산출 게이트(있으면):** pack 검증으로 OOXML 스키마 "새 에러 0"일 때만 방출. 깨진 XML 차단.

---

## 7. 시각 QA — 버그헌트 12항목

렌더한 슬라이드 JPG를 신선한 눈으로 볼 때 체크:

1. 텍스트 박스 오버플로(글자가 박스 밖으로) 2. 요소 겹침 3. 정렬 어긋남(그리드 미스냅) 4. 대비 부족(흐린 글자) 5. 폰트 깨짐/폴백 6. 플레이스홀더 잔존(lorem/xxxx/TODO) 7. 빈 슬라이드·잘린 차트 8. 액센트색 과다(무지개) 9. 제목 밑 라인·그림자·베벨 10. 파이/3D 차트 11. 본문 과밀(150자 초과) 12. 페이지번호·출처 누락.

`markitdown`이나 unpack 텍스트에서 `lorem|xxxx|TODO|placeholder` grep으로 6번을 자동 탐지.

---

## 8. AI 티 슬라이드 안티패턴 (생성기에서 차단·경고)

이런 슬라이드가 나오면 "AI가 만든 티"가 난다. 린트가 잡지만 사람이 한 번 더 본다:

1. 텍스트로 꽉 찬 슬라이드(150자/40단어 초과) 2. 그라데이션·그림자·베벨 남발 3. 3D·파이 차트 4. 5색 이상 무지개 팔레트 5. 가운데정렬 장문 본문 6. 폰트 3종 이상 7. 빨강·초록만으로 상태 구분(색맹 무시) 8. 클립아트·저화질 이미지·이모지 장식 9. 제목 밑 장식 라인 10. 모든 슬라이드 똑같은 불릿 레이아웃 11. 완결 문장을 슬라이드 본문에 다 적기(노트로 빼야 함) 12. 출처 없는 차트·수치.

---

## 9. chat-understanding 연동 (선택)

`~/.claude/skills/chat-understanding/`가 깔려 있으면, 슬라이드 **텍스트·스피커노트**에 그 스킬의 문체·레벨·AI티 점검을 적용한다. 슬라이드 제목과 노트가 "살펴보겠습니다", "다양한/전반적으로" 같은 AI투를 안 쓰도록, 결론 먼저·숫자 해석 병기 원칙을 따르도록 다듬는다. 없으면 그냥 건너뛴다.

---

## 10. 이미지 생성 API 연동 (선택 — 로컬/원격 모델)

슬라이드에 AI 생성 이미지를 넣으려면 **이미지 생성 API 주소만 지정**하면 된다. **MCP 불필요** — 빌드 엔진이 HTTP로 직접 호출한다.

**설정**(둘 중 하나):
- 환경변수: `BP_IMAGE_API_URL`(필수) · `BP_IMAGE_API_KIND`(`openai`|`a1111`|`comfy`|`generic`, 기본 openai) · `BP_IMAGE_API_MODEL` · `BP_IMAGE_API_KEY`.
- deckSpec: `"imageApi": { "url":"http://<로컬머신>:<포트>", "kind":"openai", "model":"...", "key":"..." }`.

**사용**: 슬라이드 스펙에 `"imagePrompt": "..."` 를 넣으면 그 프롬프트로 이미지를 생성해 채운다.
- `cover`: 풀블리드 히어로 이미지 + 어두운 오버레이(텍스트 가독성 보장).
- `keymsg` 등: 본문 시각 자리에 인라인.
- 미설정·실패·타임아웃이면 그라데이션 배경으로 **graceful 폴백**(이미지 없이도 빌드 성공).

```bash
# 예: 로컬 머신의 OpenAI 호환 이미지 서버
BP_IMAGE_API_URL=http://192.168.0.10:8000 BP_IMAGE_API_KIND=openai \
  node deck.js build spec.json out.pptx
```

**규율(중요)**: **정확한 숫자·라벨은 `imagePrompt`에 넣지 마라.** 최강 모델(Nano Banana Pro 포함)도 이미지 속 긴·정밀 텍스트는 100% 신뢰 못 한다. 이미지는 히어로·추상 배경·일러스트·개념도에만 쓰고, **수치·차트·제목은 우리 엔진이 진짜 텍스트로** 얹는다(정확·편집 가능). 이게 "이쁨 + 정확"의 최적해다.

**로컬 모델 권고(2026 기준)**: 라이선스 자유 = Qwen-Image-2512 + Qwen-Image-Edit-2511(Apache). 텍스트·디자인 최강 = Ideogram 4.0(가중치 비상업). 히어로·멀티참조 = FLUX.2 dev(비상업). ComfyUI/SD-WebUI를 OpenAI 호환 또는 a1111 형식으로 노출하면 위 kind로 바로 붙는다.

---

## 11. 산출물 받기

이 환경은 **헤드리스 서버**다. 빌드한 .pptx는 화면에 안 뜬다. 사용자에게 **경로를 알려주고 scp/다운로드로 받으라**고 안내한다:

```bash
# 예: 로컬로 내려받기
scp user@server:~/.claude/skills/beautiful-pptx/out.pptx ./
```

QA용 PDF/JPG를 만들었으면 그 경로도 같이 알려준다.
