Explain Diff (HTML 교육자료)
지정된 코드 변경에 대해 풍부하고 대화형인 해설서를 만든다.
절대 규칙: HTML을 직접 쓰지 마라
HTML/CSS/JS를 손으로 작성하면 안 된다. 실측 결과 손으로 쓴 55KB 문서 중 실제 내용은 18%뿐이고 나머지 82%(CSS 21% · 다이어그램 마크업 18% · JS 17% · 코드블록 14% …)는 매번 동일한 형식이었다.
대신 마크다운 문서 하나를 작성하고 렌더러를 돌린다:
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)처럼 명확하고 흐르는 클래식한 문체로, 섹션 전환을 매끄럽게.
작성 형식
---
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.
```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개 테마), 바뀐 경로 전체는 정렬해 빠짐없이 나열하라. 조용히 자르지 마라 — 다 담지 못하면 몇 개를 생략했는지 명시한다.
절차
- 위 소스 선택 표에 따라 diff 범위를 확정한다(
git log,git diff --stat, 주변 코드 탐색). 변경이 없으면 여기서 멈추고 "변경 없음"을 보고한다. - 마크다운 문서를 작성한다 — 스크래치패드나
/tmp에 둔다. - 렌더링:
python render.py doc.md --open(render.py는 이 SKILL.md와 같은 디렉터리)- 출력은
/tmp/YYYY-MM-DD-explanation-<slug>.html(날짜 접두사 → 시간순 정렬 + 저장소 밖). --repo로 저장소를 덮어쓸 수 있고,--seed로 퀴즈 셔플을 고정할 수 있다.- 출력 경로를 저장소 안으로 잡지 마라 — 하드 룰. 사용자가 이미 갖고 있는 파일을 조용히 덮어쓰지 말고, 경로가 겹치면 슬러그를 바꾸거나 확인을 구한다.
- 출력은
- 렌더가 실패하면 오류 메시지를 읽고 문서를 고친다(대개
rev/파일 경로/grep불일치). - 결과를 열어 목차 링크와 퀴즈 정답/오답 클릭이 실제로 동작하는지 최소 1문항 확인한다(브라우저 도구가 있으면 직접 열어서, 없으면 렌더된 HTML/JS를 읽어서 점검). 어느 쪽으로 확인했는지 결과 보고에 남긴다.
- Claude 환경이면 artifact로 업로드한다.