# Explain Diff HTML

> Generates interactive HTML explainers for code diffs, branches, and PRs from a single Markdown document, using a renderer to produce styled output with diagrams and quizzes.

- Skill: `moonklabs/explain-diff-html` (Agent Skill, multi-file: 2 files)
- Install (CLI): `npx skillmds@latest add moonklabs/explain-diff-html`
- Raw SKILL.md: https://api.skillmd.com/api/skills/moonklabs/explain-diff-html/raw
- Safety review: CAUTION (external: skill-scanner PASS, skillspector PASS)
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Docs & Writing, Web & Frontend, Diagrams & Charts, Technical Writing
- Tags: Diagrams, Diff, Git, Html, Markdown, Pull Request, Quiz, Renderer
- Author: moonklabs (https://skillmd.com/u/moonklabs)
- Updated: 2026-08-22
- Page: https://skillmd.com/skills/moonklabs/explain-diff-html

---


# Explain Diff (HTML 교육자료)

지정된 코드 변경에 대해 풍부하고 대화형인 해설서를 만든다.

## 절대 규칙: HTML을 직접 쓰지 마라

**HTML/CSS/JS를 손으로 작성하면 안 된다.** 실측 결과 손으로 쓴 55KB 문서 중 실제 내용은 18%뿐이고
나머지 82%(CSS 21% · 다이어그램 마크업 18% · JS 17% · 코드블록 14% …)는 매번 동일한 형식이었다.

대신 **마크다운 문서 하나**를 작성하고 렌더러를 돌린다:

```bash
python render.py doc.md --open   # render.py는 이 SKILL.md와 같은 디렉터리에 있다
```

실측 증폭비 **6.3배** — 작성량이 84% 줄고, 문서 간 디자인이 완전히 일관되며,
diff를 손으로 옮겨 적지 않으므로 **원본과 어긋날 수 없다**.

정확한 문법 레퍼런스가 필요하면 `python render.py --help`(docstring 전문)를 읽어라.

## 소스 선택

무엇을 설명할지부터 정한다 — 아래 넷은 서로 배타적이다:

| 요청 | 의미 | `gitdiff`의 `rev:` |
|---|---|---|
| "이 브랜치/변경 설명해줘" (기본값) | 베이스(기본 `main`) 대비 브랜치 | `rev: main..HEAD` |
| "PR #123 해설" | 해당 PR의 diff + 메타데이터 | `gh pr checkout 123` 후 `rev: <base>..HEAD`; 제목/설명은 `gh pr view 123`으로 확보 |
| "스테이징된 변경" | index vs HEAD | `rev: --staged` |
| "워킹트리 변경(아직 add 안 함)" | 워크트리 vs HEAD | `rev: HEAD` |

특별한 언급이 없으면 브랜치 비교로 간주한다. `git diff --stat`이 비어 있으면(변경 없음) 문서를 만들지 말고
그대로 "변경 없음"을 보고한다 — 빈 해설서를 만들지 마라. PR 메타데이터를 가져올 수 없으면 diff만으로
작성하고, 아래 근거 원칙에 따라 동기(motive) 관련 문장은 쓰지 않는다.

## 담아야 할 것

**언어:** 본문·다이어그램·퀴즈는 사용자 대화 언어(기본 한국어). 코드 식별자·기술 용어는 원형 유지.

- **Background(배경)** — 주변 코드를 넓게 탐색한 뒤 쓴다. 독자 수준을 알 수 없으므로
  초보자용 깊은 배경을 먼저 두되 **"익숙하면 건너뛰어도 좋다"고 명시**하고, 이어서 변경과
  직접 관련된 구체적 배경을 설명한다.
- **Intuition(직관)** — 세부보다 본질. 간단한 예시 데이터로 구체적 사례를 들고 다이어그램을 적극 쓴다.
- **Code(코드)** — 변경을 이해하기 쉬운 단위로 묶고 정렬해 고수준에서 설명한다.
- **Quiz(퀴즈)** — 5문제. 꼬아낸 문제가 아니라 **실질 내용을 이해해야 맞출 수 있는** 중간 난이도.

마틴 클렙만(Martin Kleppmann)처럼 명확하고 흐르는 클래식한 문체로, 섹션 전환을 매끄럽게.

## 작성 형식

````markdown
---
title: 문서 제목
kicker: 상단 라벨 · 프로젝트명
subtitle: 리드 문단 — 독자를 끌어들이는 질문이면 더 좋다
slug: url-slug
repo: /절대/경로/저장소        # gitdiff·snippet 이 사용
meta:
  - 2026-07-21
  - "브랜치 `feature/x`"
---

## 배경 {#bg}

!lede 이 줄은 리드 문단(큰 글씨)이 된다.

### 소제목 {#bg-what}

본문은 **마크다운**이다. `인라인 코드`, [링크](url), 목록, 파이프 표를 지원한다.
````

`##` = 섹션(자동으로 "Part N" 번호 + 목차 항목), `###` = 하위 목차 항목.
`{#id}`로 앵커를 명시하고, 생략하면 자동 부여된다.

## 지시자 (펜스 블록)

모든 지시자는 마지막에 `:: 캡션` 줄을 둘 수 있다. 스타일 토큰: `hi` `ok` `no` `wa`.

````markdown
```flow 그림 1 — 피드의 기본 구조
앱 (v0.2.0) | 4시간마다 체크 | hi
GET beta.yml | 피드에서 매니페스트
:: 캡션은 다이어그램이 말하려는 바를 한 문장으로.
```

```stack 그림 2 — 단계별 누적
창 열기 #1 > 리스너 6개 > 타이머 1개 [ok]
한 번 더 > 리스너 18개 [no]
```

```uiwin 앱 이름
win: ① 변경 전
banner: 새 버전 준비됐어요. | btn: 지금 재시작
stub
win: ② 변경 후
banner.mute: 수집이 끝나면 재시작할 수 있어요. | btn.gone: 지금 재시작
```

```gitdiff desktop/src/main.ts
rev: 25c7a47..HEAD
grep: updaterHandle      # 이 문자열을 포함한 hunk 만 (선택)
context: 3               # (선택)
cap: 캡션                 # (선택)
```

```snippet desktop/src/updater.ts:55-67
lang: ts
```

```code ts 제목
직접 쓴 코드 (git 에 없을 때만)
```

```callout warn 놓치기 쉬운 곳
본문은 **마크다운**. 종류: info · warn · bad · good
```

```quiz
Q: 질문? `인라인 코드` 사용 가능
- 오답
* 정답 (별표가 정답 표시)
- 오답
> 해설 — 왜 그런지 설명한다.
---
Q: 다음 문제
...
```

```html
<p>DSL로 표현 못 하는 경우의 탈출구 — 원시 HTML을 그대로 통과시킨다.</p>
```
````

## 지침

- **코드는 `gitdiff`/`snippet`으로 가져와라.** 손으로 옮겨 적지 마라 — 토큰 낭비이고 원본과 어긋난다.
  `code` 지시자는 git에 없는 내용에만 쓴다.
- **다이어그램 패밀리를 소수로 고정하라.** 문서 전체에서 `flow`·`stack`·`uiwin` 몇 종을 반복 재사용하는
  편이, 매번 새로운 그림을 만드는 것보다 독자가 읽기 쉽다. ASCII 다이어그램은 절대 쓰지 마라.
- 다이어그램에는 **예시 데이터를 반드시 넣어라**(버전 번호, 파일명, 상태값 등).
- 핵심 개념·정의·중요한 엣지 케이스는 `callout`으로 강조한다.
- 퀴즈 보기 순서는 렌더러가 섞으므로 자연스러운 순서로 쓰면 된다.
- **모든 사실 문장은 hunk나 실제로 읽은 파일에 근거해야 한다.** diff·PR 설명 어디에도 없는 의도·동기를
  추측해서 쓰지 마라 — "왜 이렇게 바꿨는지"는 커밋 메시지/PR 설명에 있을 때만 인용하고, 없으면 무엇이
  바뀌었는지만 설명한다.
- **바뀐 파일이 50개를 넘으면 대표 hunk로 테마를 설명하되(최대 12개 테마), 바뀐 경로 전체는 정렬해
  빠짐없이 나열하라.** 조용히 자르지 마라 — 다 담지 못하면 몇 개를 생략했는지 명시한다.

## 절차

1. 위 소스 선택 표에 따라 diff 범위를 확정한다(`git log`, `git diff --stat`, 주변 코드 탐색). 변경이
   없으면 여기서 멈추고 "변경 없음"을 보고한다.
2. 마크다운 문서를 작성한다 — 스크래치패드나 `/tmp`에 둔다.
3. 렌더링: `python render.py doc.md --open` (render.py는 이 SKILL.md와 같은 디렉터리)
   - 출력은 `/tmp/YYYY-MM-DD-explanation-<slug>.html` (날짜 접두사 → 시간순 정렬 + 저장소 밖).
   - `--repo`로 저장소를 덮어쓸 수 있고, `--seed`로 퀴즈 셔플을 고정할 수 있다.
   - **출력 경로를 저장소 안으로 잡지 마라** — 하드 룰. 사용자가 이미 갖고 있는 파일을 조용히
     덮어쓰지 말고, 경로가 겹치면 슬러그를 바꾸거나 확인을 구한다.
4. 렌더가 실패하면 오류 메시지를 읽고 문서를 고친다(대개 `rev`/파일 경로/`grep` 불일치).
5. 결과를 열어 목차 링크와 퀴즈 정답/오답 클릭이 실제로 동작하는지 최소 1문항 확인한다(브라우저 도구가
   있으면 직접 열어서, 없으면 렌더된 HTML/JS를 읽어서 점검). 어느 쪽으로 확인했는지 결과 보고에 남긴다.
6. Claude 환경이면 artifact로 업로드한다.

