MDBook-binder
임의의 마크다운 코퍼스를 검색 가능한 단일 HTML 도서와 PDF(단권/병합)로 변환하고, 결과 HTML을 편집하는 범용 애플리케이션.
목차
1. 프로젝트 개요
무엇인가
MDBook-binder는 임의의 마크다운 파일 모음(코퍼스)을 입력으로 받아, 코드 수정 없이 다음 세 가지를 만들어내는 독립 실행형 CLI 애플리케이션이다.
- 검색 가능한 단일 HTML 도서 — 사이드바 목차, 인페이지 전문 검색을 갖추고, 이미지는 base64로 인라인 임베드되어 파일 하나만으로 열린다. Mermaid 다이어그램도 가능하면 빌드 시점에 정적 SVG로 사전 렌더링해 같이 임베드한다(오프라인 제약은 알려진 한계 참고).
- PDF 도서 — 챕터별 개별 PDF 또는 한 권으로 병합(merge)한 PDF.
- HTML 도서 편집기 — 생성된 HTML 도서를 브라우저에서 섹션 단위로 다시 열어 마크다운·이미지를 편집할 수 있는 웹 편집기.
코퍼스가 book.yaml로 순서·제목·콜아웃 마커 등을 명시하면 그대로 따르고,
없으면 파일/디렉토리 명명 규칙이나 디렉토리 트리 자연정렬로 순서를 자동
추론한다 — 그래서 새 마크다운 파일이 추가되어도 코드나 설정을 건드릴 필요가
없다.
아키텍처
flowchart TD
A["마크다운 코퍼스\n(임의의 디렉토리)"] --> B["manifest.py\nBookConfig(book.yaml) + resolve()\n3단계 순서 해석"]
B --> C["render.py\nmd_to_html / demote_headings\n(콜아웃·로케일 config 주입)"]
C --> D["html_book.py\n사이드바 · 검색 · base64 이미지\n섹션 id 충돌 자동 회피"]
C --> E["pdf_book.py\nPlaywright 청크 캡처\n개별 PDF / --merge 단권"]
D --> F["editor/\nLectureHTMLEditor·ImageEditor 포크\n(lecture-forge 비의존)"]
G["check.py\n빌드 전 사전 점검"] -.-> B
style D fill:#4527a0,color:#fff
style E fill:#00897b,color:#fff
style F fill:#5e35b1,color:#fff
html_book.py가 출력하는 <section class="chapter-section" id="{slug}">
구조는 editor/가 의존하는 유일한 불변 계약이다 — 다른 무엇을 바꾸더라도
이 마크업 계약은 유지해야 편집기가 섹션을 인식한다.
설계 원칙
- 순서 해석은 3단계 우선순위로 자동 결정된다 — 코드 수정 없이 새
마크다운 파일이 반영되도록 하는 것이 핵심 목표다.
- 명시적
book.yaml(order.manifest또는order.files) book.yaml이 없어도 루트에```toc펜스 매니페스트가 있으면 자동 채택Part_<로마숫자>_.../Chapter_<NN>_...명명 규칙 감지- 위 전부 실패 시 디렉토리 트리 전체를 자연정렬(natural sort)해 전부 포함 — "새 파일이 조용히 누락되는 일"을 구조적으로 없애는 최종 폴백
- 명시적
- 책마다 다른 값(제목/저자/언어/제외 패턴/콜아웃 마커/커스텀 CSS)은 전부
book.yaml로 외부화 — 렌더링 엔진(render.py) 코드는 어떤 코퍼스에도 수정 없이 동작해야 한다. - 섹션 ID는 기본적으로 H1/파일명 slug 자동 생성, 충돌 시 자동으로
-2/-3접미사를 붙인다 — 수작업 매핑 테이블은 "예쁜 URL을 원할 때만 쓰는 선택적 오버라이드"로 격하한다. - 편집기는 lecture-forge에 비의존 —
Lecture_forge의LectureHTMLEditor/ImageEditor를 포크하되 벡터스토어 기반 이미지 추천 등 강의 특화 기능은 제외했다.
파일 구조
MDBook-binder/
├── pyproject.toml
├── LICENSE
├── README.md
├── src/mdbook_binder/
│ ├── manifest.py # BookConfig(book.yaml) + resolve()/resolve_verbose()
│ ├── render.py # md_to_html / demote_headings / 콜아웃·로케일
│ ├── html_book.py # HTML 도서 빌더 (사이드바/검색/base64 이미지)
│ ├── imgembed.py # 이미지 → base64 data URI 인코딩 공용 유틸
│ ├── mermaid_prerender.py # Mermaid 빌드 타임 정적 SVG 사전 렌더링 (Playwright)
│ ├── mermaid_wrap.py # Mermaid 노드/엣지 라벨 자동 줄바꿈
│ ├── theme.py # --color 색상 테마 프리셋 (사이드바/제목 강조색)
│ ├── pdf_book.py # PDF 빌더 (청크 캡처 + 개별/병합)
│ ├── check.py # 빌드 전 사전 점검
│ ├── cli.py # mdbook-binder CLI (check/build html/build pdf/edit)
│ ├── editor/ # Lecture_forge 포크 — lecture-forge 비의존
│ │ ├── html_editor.py # BookHTMLEditor — 섹션 CRUD, 이미지 추가(base64 임베드)
│ │ ├── image_editor.py # 이미지/다이어그램 편집, 이미지 교체(base64 임베드)
│ │ └── server.py # Flask 편집 API 서버
│ └── templates/
│ ├── html_book.css/js # HTML 도서 사이드바·검색·mermaid
│ ├── pdf_override.css # PDF 전용 레이아웃 오버라이드(CSS)
│ ├── pdf_book.js # PDF 렌더링 보정(Mermaid 크기 측정·청크 분할)
│ ├── vendor/ # 번들된 mermaid.min.js + Noto Sans KR 폰트(오프라인 렌더링용)
│ └── editor/ # 편집 SPA (index.html/editor.css/editor.js)
└── tests/
├── test_manifest.py # 3단계 순서 해석 (5건)
├── test_html_book.py # 섹션 id 충돌 회피·이미지 임베드 (3건)
├── test_check.py # 사전 점검 (4건)
├── test_editor.py # 이미지 추가/교체 후 base64 임베드 (2건)
├── test_mermaid_prerender.py # Mermaid 사전 렌더링 성공/폴백 (3건)
├── test_mermaid_wrap.py # 라벨 자동 줄바꿈 (12건)
└── test_theme.py # 색상 테마 프리셋 + book.yaml/--color 연동 (8건)
2. 핵심 기능 및 사용법
순서 해석 — 3단계 우선순위
명령은 코퍼스가 무엇이든 동일하다(mdbook-binder build html <root>) — 코퍼스가
이미 가진 정보(매니페스트/명명 규칙)에 따라 내부적으로 다른 우선순위가 자동
선택된다.
# book.yaml도, 매니페스트도, Part/Chapter 명명 규칙도 없는 새 폴더
mdbook-binder build html ~/Docs/my-notes
# → 3순위(자연정렬)가 자동 적용, 최소한 파일이 빠지는 일은 없다
book.yaml 설정
코퍼스 루트에 선택적으로 둔다 — 없어도 전부 기본값/자동 감지로 동작한다.
title: "실전 AI 에이전트 하네스 엔지니어링"
author: "Sungwoo Kim"
language: ko # ko/en — 검색 UI 문자열 로케일
order: # 1순위 — 있으면 이걸로 순서 확정
files: [00_서문.md, Part_I_.../Chapter_01_*.md, ...]
# 또는: manifest: 01_목차.md ( ```toc 펜스 매니페스트 파일 지정 )
exclude: # 챕터가 아닌 문서 제외 (glob 패턴)
- "README.md"
- "IMAGES.md"
callouts:
tip_markers: ["👨💻", "📋", "📊", "🔧", "🚨", "💡"] # 없으면 전부 blockquote로 렌더
section_id_overrides: # 파일 stem → 원하는 URL slug (선택)
"Chapter_01_서론": "intro"
custom_css: custom.css # 코퍼스 루트 기준 상대 경로 (선택)
# 코퍼스별 raw-HTML 다이어그램(@@HTML_START@@ 블록)이
# 쓰는 커스텀 클래스는 범용 템플릿에 넣을 수 없으므로,
# 여기 지정한 CSS 파일 내용을 HTML/PDF 빌드 모두에 그대로 얹는다.
color: green # 사이드바/제목 강조색 테마 (선택, 기본 purple)
# purple/blue/green/teal/red/orange/gray 중 하나.
# CLI --color를 주면 이 값보다 우선한다.
마크다운 저작 규칙
빌드 엔진이 코퍼스를 올바르게 해석하려면 챕터 마크다운이 아래 규칙을 지켜야 한다.
- 각 챕터 파일은 H1(
# 제목) 하나로 시작해야 한다. 첫 H1이 섹션 제목· URL slug(#section-id)·PDF 표지 제목으로 추출된다. H1이 없으면 파일명 stem이 대신 쓰여 slug가 지저분해진다. 문서 안에 H1은 하나만 두고, 하위 제목은 H2 이하로 쓴다 — 전체 도서로 합쳐질 때 모든 헤딩이 자동으로 한 단계씩 강등되므로(H1→H2, H2→H3…) 챕터 내부 구조는 그대로 유지된다. - 이미지 경로는 해당 마크다운 파일 기준 상대 경로로 쓴다
(
등).http(s)://,data:,file://,#로 시작하는 경로는 그대로 통과된다. 참조된 파일이 실제로 없으면 빌드는 멈추지 않고 빌드 끝에 누락 목록만 모아 출력한다 — 오타를 늦게 발견하지 않으려면check명령으로 미리 확인한다. - Mermaid 다이어그램은
```mermaid펜스 블록으로 작성한다. - 코퍼스 전용 raw HTML(커스텀 다이어그램 등)은
@@HTML_START@@/@@HTML_END@@블록으로 감싼다. 그 안에서 쓰는 커스텀 CSS 클래스는 범용 템플릿에 없으므로book.yaml의custom_css로 별도 선언해야 한다. - 콜아웃(TIP박스)은 blockquote 맨 앞을
book.yaml의callouts.tip_markers에 등록한 이모지로 시작해야 인식된다. 등록하지 않으면 모든 blockquote는 그냥 일반 인용문으로 렌더된다. - blockquote 안에 코드블록을 넣으려면 각 줄 앞에
>를 붙인> ```~> ```형태로 쓴다. - 관리용 문서(집필 가이드 등 챕터가 아닌
.md)는 기본적으로 빌드에 포함된다 — 기본 제외 대상은book.yaml/README.md뿐이다. 그 외 파일은book.yaml의exclude패턴으로 직접 제외해야 한다. - 순서 자동 인식을 받으려면 파일/디렉토리 명명 규칙을 따른다:
Part_<로마숫자>_.../Chapter_<NN>_...구조를 쓰면 2순위 규칙이 파트· 챕터 순서를 자동으로 잡는다. 최상위 파일 중 앞자리 번호가00_류(서문)는 파트 챕터들 앞에,50이상(맺음말류)은 뒤에 자동 배치되고,Appendix/디렉토리는 항상 맨 마지막에 붙는다. 이 규칙을 따르지 않는 코퍼스는book.yaml의order.files로 순서를 직접 명시하거나, 그마저 없으면 3순위(자연정렬 전체 포함)로 폴백된다 — 파일이 조용히 빠지는 일은 없지만 순서가 기대와 다를 수 있다. - URL이 보기 좋은 slug를 원하면
book.yaml의section_id_overrides로 파일 stem → slug를 직접 지정한다. 지정하지 않으면 H1 제목에서 자동 생성되며, 서로 다른 챕터의 제목이 같아도-2/-3접미사로 충돌을 자동 회피한다.
AI로 챕터 저작하기 — Skill/프롬프트 활용
챕터 초안을 AI에게 맡기면 위 마크다운 저작 규칙을 모르는
채로 써서 check/빌드 시점에야 문제가 드러나기 쉽다 — 규칙 자체는 이 README를
정본(single source of truth)으로 유지하고, 사용하는 AI 도구에 맞는 방식으로
그 정본을 참조하게 만드는 두 가지 방법을 쓸 수 있다.
Claude Code — 얇은 래퍼 Skill. 규칙을 다시 옮겨 적지 않고 이 절을 가리키기만 하는 스킬을 저장소에 두면, 규칙이 바뀔 때 README 한 곳만 고치면 된다.
<!-- .claude/skills/mdbook-authoring/SKILL.md -->
---
name: mdbook-authoring
description: mdbook-binder 코퍼스에 마크다운 챕터를 추가/수정할 때 저작
규칙(H1 제목, 이미지 상대 경로, Mermaid 펜스, 콜아웃 마커, Part/Chapter
명명 규칙 등)을 적용한다. "챕터 써줘", "이 코퍼스에 새 문서 추가해줘" 등의
요청에 사용.
---
이 저장소는 mdbook-binder로 빌드되는 마크다운 코퍼스다. 챕터를 새로 쓰거나
수정하기 전에 README.md의 "마크다운 저작 규칙" 절
(#마크다운-저작-규칙)을 읽고 그대로 따른다 — 규칙 원문은 그 절에만 있으므로
여기서 다시 옮겨 적지 않는다. 작성 후에는 `mdbook-binder check <root>`로
검증한다.
다른 AI 도구(ChatGPT/Cursor 등) — 범용 프롬프트 블록. Claude Code의 스킬 자동 트리거 없이도 붙여넣기만 하면 되도록, 규칙을 요약한 프롬프트를 그대로 시스템/커스텀 프롬프트에 넣는다.
당신은 mdbook-binder로 빌드될 마크다운 챕터를 작성합니다. 다음 규칙을 반드시
지키세요.
1. 파일은 H1(`# 제목`) 하나로 시작한다. 하위 제목은 H2 이하로 쓴다.
2. 이미지 경로는 해당 마크다운 파일 기준 상대 경로로 쓴다.
3. Mermaid 다이어그램은 `mermaid` 코드 펜스 블록으로 작성한다.
4. 콜아웃(TIP박스)은 book.yaml의 callouts.tip_markers에 등록된 이모지로
blockquote를 시작한다. 등록되지 않은 이모지는 일반 인용문으로 렌더된다.
5. 커스텀 raw HTML은 @@HTML_START@@ / @@HTML_END@@ 블록으로 감싼다.
6. 순서 자동 인식을 받으려면 Part_<로마숫자>_.../Chapter_<NN>_... 명명
규칙을 따르거나, book.yaml의 order.files로 순서를 직접 명시한다.
자세한 근거는 프로젝트 README의 "마크다운 저작 규칙" 절을 참고하세요.
두 방식 모두 규칙 본문을 복제하지 않는다 — 복제하면 README를 고칠 때마다 스킬/프롬프트도 같이 고쳐야 해서 금방 어긋난다. 스킬은 짧은 안내문(위 예시) 정도만 유지하고, 프롬프트 블록은 배포 시점의 스냅샷이라는 점을 감안해 이 README가 바뀌면 함께 갱신한다.
빌드 전 사전 점검 — check
실제로 HTML을 렌더링하지 않고 원본 마크다운만 훑어 빠르게 확인한다 — 챕터가
아닌 문서(예: 집필 가이드 .md)가 잘못 포함되는 것을 빌드 후에야 발견하는
일을 줄인다.
mdbook-binder check ~/Docs/my-book
순서 해석: 2순위: Part/Chapter 명명 규칙 감지
챕터 수: 44개
[Part I]
- Part_I_기초/Chapter_01_...md
...
⚠️ 같은 제목을 쓰는 챕터 1건 (빌드 시 id에 -2, -3... 자동 부여됨):
- "개요": Part_I_.../Chapter_01_x.md, Part_II_.../Chapter_01_y.md
HTML 도서 빌드
mdbook-binder build html <코퍼스_루트> [--out out.html] [--title ...] [--language ko|en] [--color NAME]
- 이미지를 base64 data URI로 인라인 임베드 — 이미지 폴더 없이도 단일 파일로 완전히 독립적으로 열린다(다른 PC로 옮기거나 이메일 첨부해도 그대로 열림).
- Mermaid 다이어그램은 Playwright/Chromium이 설치돼 있으면(
[pdf]extra) 빌드 시점에 정적 SVG로 미리 렌더링해 그대로 삽입한다 — 열람 시 CDN mermaid.js가 필요 없어져 완전한 오프라인 단일 파일이 된다. Playwright가 없으면 조용히 원본 마크업으로 폴백해 기존처럼 열람 시 CDN에서 렌더링한다. - 인페이지 전문 검색(하이라이트·이전/다음 이동), 사이드바 목차 자동 생성.
- 서로 다른 Part의 챕터 제목이 우연히 같아도(예: "개요") 섹션 id 충돌을 자동으로 회피한다.
- 빌드 끝에 누락된 이미지 참조를 한 번에 모아 요약 출력한다.
--color로 사이드바/제목 강조색 테마를 고른다(purple(기본)/blue/green/teal/red/orange/gray) — book.yaml의color:보다 우선한다.
PDF 빌드 — 개별/병합
mdbook-binder build pdf <코퍼스_루트> # 챕터별 개별 A4 PDF
mdbook-binder build pdf <코퍼스_루트> --merge [이름] # 단권으로 병합
mdbook-binder build pdf <코퍼스_루트> --out-dir <디렉토리> # 출력 위치 지정
mdbook-binder build pdf <코퍼스_루트> --color green # 색상 테마 지정(HTML과 동일한 프리셋)
각 챕터를 Playwright/Chromium으로 독립 렌더링한다. 긴 Mermaid 다이어그램은
청크 단위로 스크린샷 캡처해 삽입해 페이지 경계에서 잘리는 문제를 피한다.
다이어그램은 viewBox에서 읽은 자연 크기를 기준으로 페이지 폭을 넘을 때만
축소하며, CSS가 강제로 확대해 여러 페이지에 걸쳐 표시되거나 그 앞뒤로 빈
페이지가 삽입되는 문제를 방지한다. 병합도 각 챕터를 동일한 코드 경로로
개별 렌더링한 뒤 pypdf로 PDF 객체 레벨에서 합쳐, 개별 생성과 병합 생성의
폰트 크기·다이어그램 해상도가 항상 동일하다.
HTML 편집
mdbook-binder edit <html_경로> [--port 5757] [--out edited.html] [--no-browser]
브라우저에서 섹션 단위로 마크다운 편집(EasyMDE), 이미지/다이어그램 목록·삭제·
교체, 이미지 업로드/갤러리를 제공한다. <section id="{slug}"> 구조에만
의존하므로 어떤 코퍼스로 만든 HTML이든 동일하게 동작한다.
3. 설치 가이드
PyPI에 배포돼 있어 pip install로
바로 설치할 수 있다. 개발에 참여하거나 아직 릴리스에 포함되지 않은
Unreleased 상태의 최신 수정 사항을 먼저 쓰려면 저장소를 직접 클론해
설치한다.
사전 준비
-
Python 3.11 이상
-
PDF 빌드(
[pdf]extra)를 쓸 경우: Playwright Chromium의 런타임 공유 라이브러리가 필요하다.python -m playwright install --with-deps chromium하나로 브라우저와 OS 의존성을 한 번에 설치하는 것을 권장한다. 리눅스에서--with-deps를 못 쓰는 제한된 환경이라면 Ubuntu 22.04/24.04 기준 아래 패키지가 대략 필요하다(버전에 따라 패키지명이 다를 수 있어 참고용):sudo apt install -y \ libnss3 libnspr4 libatk1.0-0 libatk-bridge2.0-0 libcups2 \ libdrm2 libdbus-1-3 libxcb1 libxkbcommon0 libx11-6 \ libxcomposite1 libxdamage1 libxext6 libxfixes3 libxrandr2 \ libgbm1 libpango-1.0-0 libcairo2 libasound2
macOS는 별도 시스템 패키지 없이
playwright install chromium만으로 충분하다.
설치 — PyPI (권장)
pip install mdbook-binder # 코어만 — HTML 빌드/check/편집(수동 조합)
pip install "mdbook-binder[pdf]" # + Playwright/pypdf (PDF 빌드용)
pip install "mdbook-binder[editor]" # + Flask/Pillow (웹 편집기용)
pip install "mdbook-binder[pdf,editor]" # 전체 기능
python -m playwright install --with-deps chromium # [pdf] 설치 시 1회
설치 — 저장소 클론 (개발/최신 미배포 수정 사항)
git clone https://github.com/bullpeng72/MDBook-binder.git
cd MDBook-binder
python3 -m venv .venv && source .venv/bin/activate
pip install -e . # 코어만 — HTML 빌드/check/편집(수동 조합)
pip install -e ".[pdf]" # + Playwright/pypdf (PDF 빌드용)
pip install -e ".[editor]" # + Flask/Pillow (웹 편집기용)
pip install -e ".[dev]" # + pytest/ruff (개발용)
pip install -e ".[pdf,editor,dev]" # 전체 기능
python -m playwright install --with-deps chromium # [pdf] 설치 시 1회
빠른 시작
mdbook-binder check ~/Docs/my-book # 1. 빌드 전 사전 점검
mdbook-binder build html ~/Docs/my-book --out out.html # 2. HTML 도서 빌드
mdbook-binder edit out.html # 3. 브라우저에서 편집
mdbook-binder build pdf ~/Docs/my-book --merge # 4. (선택) 단권 PDF
개발
pip install -e ".[dev,pdf,editor]"
pytest tests/ -q # 37개 테스트 (manifest 5 + html_book 3 + check 4 + editor 2 + mermaid_prerender 3 + mermaid_wrap 12 + theme 8)
ruff check src tests
알려진 한계
- HTML 도서는 이미지·Mermaid 다이어그램만 오프라인이고, 코드 하이라이트·
폰트는 여전히 CDN 의존적이다: 이미지는 항상 base64로 인라인 임베드되고,
Mermaid는 빌드 시점에 Playwright/Chromium(
[pdf]extra)이 있으면 정적 SVG로 사전 렌더링돼 같이 임베드된다 — 없으면 열람 시 CDNmermaid.js로 폴백한다(빌드 로그에 안내 출력). 반면 코드 하이라이트(highlight.js)와 본문 웹폰트(Google Fonts)는 아직<script>/<link>태그로 매번 CDN에서 불러온다 — 완전히 오프라인인 환경(인터넷 차단 사내망 등)에서 열면 코드 하이라이트·폰트가 브라우저 기본값으로 대체된다(내용 자체는 읽을 수 있음). CDN 스크립트가 로드에 실패해도 검색·목차 활성화 등 나머지 기능은 죽지 않도록 방어적으로 처리돼 있다. - Mermaid 오프라인 사전 렌더링 대가로 패키지 용량이 커졌다: 빌드 자체도
네트워크 없이 동작하도록
templates/vendor/mermaid.min.js(약 3.3MB)와, 다이어그램 안 한글 라벨이 어떤 환경에서 빌드/열람되든 동일하게 렌더링되게 하는NotoSansKR-Regular.woff2(약 2.1MB)를 패키지에 번들했다(합계 약 5.4MB) — 생성되는 각 HTML 도서 파일 크기와는 무관하고,pip install mdbook-binder1회 설치 용량에만 영향을 준다. - 병합 PDF(
--merge)에는 챕터별 북마크(아웃라인)가 없다:pypdf로 개별 챕터 PDF를 순서대로 이어붙이기만 하고(PdfWriter.append()에outline_item을 넘기지 않음) 원본 챕터 PDF 자체에도 아웃라인이 없으므로, 병합본을 PDF 뷰어로 열어도 사이드바 목차(챕터 점프)가 생성되지 않는다 — 목차는 도서 본문에 렌더된 페이지로만 확인 가능하다. - PDF/HTML 부분 빌드 미지원: 원본
build_pdf_chapters.py가 갖고 있던 "파일/패턴 지정 부분 변환"은 아직 이식하지 않았다 — 항상 코퍼스 전체를 대상으로 빌드한다. - 마크다운 스캐폴딩(정형 스텁 생성) 미포함: 의도적으로 범위에서 제외했다 — 마크다운 저작 자체는 각자의 저작 파이프라인에 맡기고, 이 도구는 빌드/편집에만 집중한다. 새 챕터 파일은 손으로 작성해야 한다.
Part_<로마숫자>_...명명 규칙 감지(2순위)는Appendix/만 특별 취급: 그 외 비-Part 디렉토리는 3순위 자연정렬로만 잡힌다 — 필요하면book.yaml의order.files로 명시하는 게 안전하다.pdf_book.py/editor/는 회귀 테스트가 일부만 있다: 이미지 추가/교체 후 base64 임베드가 유지되는지는test_editor.py로 고정돼 있지만, Flask API 엔드포인트·섹션 CRUD·다이어그램 편집·PDF 렌더링 자체는 실제 코퍼스로 수동 검증만 마쳤을 뿐manifest.py/html_book.py/check.py만큼 pytest로 고정돼 있지는 않다.- PyPI 배포와
Unreleased변경이력 사이에 시차가 있다: PyPI의mdbook-binder는 최신 태그 버전(pyproject.toml기준)까지만 반영되므로, 이 문서의 변경이력Unreleased항목은 아직 PyPI에 올라가지 않았다 — 그 수정 사항이 필요하면 저장소를 직접 클론해 설치한다.
변경이력
0.3.1 (2026-07-28)
- feat:
build html/build pdf에--color옵션 추가(신규theme.py). 사이드바 배경·제목·표 헤더·링크 강조색(--primary/--primary-light/--accent) 3개만 바꾸는 "메뉴 색 고르기" 수준의 프리셋 7종(purple(기본)/blue/green/teal/red/orange/gray)을 제공한다. 전부 사이드바의 흰 글자와 대비가 충분한 톤으로만 골라, 임의 hex를 받았을 때 밝은 색을 고르면 글자가 안 보이는 사고를 원천 차단했다.book.yaml의color:로 코퍼스 기본값을 정해두고 CLI--color로 그때그때 오버라이드할 수 있다 (--title/--language와 동일한 오버라이드 우선순위). PDF는 기존custom_css파이프라인에 얹는 방식이라 별도 배관 없이 HTML과 동일한 프리셋을 공유한다. - fix: 서브그래프(subgraph) 제목이 길어 자동 줄바꿈되면 둘째 줄이 그
서브그래프의 첫 자식 노드 박스와 겹쳐 보이던 문제 수정. 노드 라벨은
foreignObject가 실측 높이만큼 스스로 커지지만, Mermaid는 서브그래프 제목 위에 예약하는 세로 여백을 "제목은 한 줄"이라는 전제로 고정 계산해 실제 렌더 높이를 못 따라가는 게 원인이었다(실측: 2줄 제목의foreignObject가 38px인데 첫 자식 노드 상단은 25px 지점에서 시작).subgraph X["..."]줄의 제목 라벨은 자동 줄바꿈 대상에서 제외해, 길면 클러스터 박스가 가로로만 넓어지도록 함(mermaid_wrap.py). - fix: 긴 노드/엣지 라벨을 자동 줄바꿈할 때 폭 제한에 걸리면 무조건
문자 단위로 잘라
ChapterDrafterAgen/t,knowledge/store.js/on,query_with_scores(/)처럼 단어나 괄호 쌍 중간이 갈라져 보기 흉했던 문제 수정./,_,.,-뒤나 camelCase 전환 지점(소문자→대문자) 같은 자연 경계에서 우선 접도록 해ChapterDrafter/Agent,knowledge/store./json,query_with_/scores()처럼 의미 단위가 보존되게 함. 그런 경계가 아예 없는 텍스트(긴 한글 연속 등)만 기존처럼 문자 단위로 분할한다(mermaid_wrap.py). - fix: 웹 편집기(
edit) 미리보기에서 Mermaid 다이어그램을 렌더링할 때 HTML/PDF 빌드에는 이미 적용된 "Noto Sans KR 강제 지정 + line-height 고정" 설정이 빠져 있어, 서브그래프 라벨이 자기 배경 박스 폭을 넘어서고 좁은 미리보기 창에서 그 넘친 부분이 잘려 보이던 문제 수정. 빌드에 쓰는 것과 동일한 폰트 CSS(mermaid_font_face_css()/mermaid_label_css())를 에디터 페이지에도 주입하고,mermaid.initialize()에 같은themeVariables.fontFamily를 지정해 빌드 시점 라벨 크기 계산과 에디터 미리보기 렌더링이 어긋나지 않게 함(editor/server.py,templates/editor/index.html,templates/editor/editor.js). - 회귀 테스트 13건 추가(mermaid_wrap 5건 + theme 8건, 총 37개).
0.3.0 (2026-07-27)
- feat: Mermaid 다이어그램을 HTML 빌드 시점에 Playwright/Chromium으로
정적 SVG로 사전 렌더링해 인라인 삽입(
mermaid_prerender.py, 신규 모듈). 성공하면 열람 시 CDNmermaid.js(3.3MB)가 전혀 필요 없어 완전한 오프라인 단일 파일이 되고, 다이어그램이 없거나 Playwright가 없으면 자동으로 CDN 태그 자체를 생략(전자)하거나 기존 CDN 클라이언트 렌더링으로 폴백(후자)한다. 빌드 시점 렌더링도templates/vendor/mermaid.min.js를 번들해 네트워크 없이 동작한다. - feat: Mermaid 노드/엣지 라벨 중 긴 텍스트를 자동 줄바꿈(
mermaid_wrap.py, 신규 모듈). 다이아몬드(결정) 노드는 라벨 폭만큼 도형이 커지는데, 긴 한글 라벨 한 줄이 다이아몬드의 뾰족한 모서리 밖으로 삐져나오던 문제를 막는다.md_to_html()이 mermaid 코드 블록을 추출하는 시점에 한 번만 적용해, HTML 사전 렌더링과 PDF 변환(클라이언트 mermaid.js) 두 경로 모두 동일하게 줄바꿈된 결과를 쓴다. - fix: HTML 도서 열람 시 다이어그램 안 한글 라벨이 두 번째 줄부터 잘려
보이던 문제 수정. 원인은 두 겹이었다 — ①
body { line-height: 1.8 }가 Mermaid SVG의<foreignObject>라벨 텍스트까지 상속돼 실제 렌더링 높이가 Mermaid가 계산해 둔 도형 크기보다 커졌고, ② Noto Sans KR처럼 세로 메트릭이 큰 폰트에서는line-height: normal이어도 Mermaid의 자체 높이 측정치와 실제 브라우저 렌더링 높이가 20~30% 어긋났다. 라벨 텍스트의line-height를 고정 숫자값(1.2)으로 못박아 빌드 시점 측정과 표시 시점 렌더링을 일치시키고,foreignObject에overflow: visible을 둬 그래도 남는 서브픽셀 오차가 텍스트를 자르지 않고 살짝 넘치는 선에서 그치게 함(mermaid_prerender.py의 신규mermaid_label_css()를 빌드용 렌더 페이지·최종 HTML·PDF 렌더 페이지 세 곳에 동일하게 주입). Noto Sans KR 폰트를 base64로 번들해 오프라인 환경에서도 항상 같은 폰트로 렌더링되게 함(templates/vendor/). - fix:
html_book.js최상단의mermaid.initialize(...)가 톱레벨에서 무방비로 실행돼, CDN이 막혀mermaid가undefined면 그 예외가 같은<script>블록의 나머지(코드 하이라이트·TOC 활성화·전문 검색)까지 통째로 실행되지 못하게 막던 문제 수정 —mermaid/hljs전역 참조를 존재 확인 +try/catch로 감싸 CDN 실패가 다른 기능에 전파되지 않게 함. - fix: 편집기(
edit)에서 이미지를 추가·교체한 뒤 저장하면src에 파일 경로가 그대로 남아, 최초 빌드본과 달리 편집본이 이미지 폴더 없이는 열리지 않던 문제 수정.imgembed.py에 base64 인코딩 로직을 공용 유틸로 뽑아html_book.py(최초 빌드)·image_editor.py(이미지 교체)·html_editor.py(이미지 추가)가 모두 공유하도록 해, 편집 후 저장한 HTML도 항상 완전한 단일 파일로 유지되도록 함. - fix: PDF 변환 시 Mermaid 다이어그램이 실제보다 과도하게 확대되어 여러
페이지에 걸쳐 표시되던 문제, 그 앞뒤로 빈 페이지가 삽입되던 문제 수정.
pdf_override.css의.mermaid svg { max-width:100% !important }가 Mermaid 자신의 자연 크기 힌트(인라인style="max-width: Npx")를 덮어써width="100%"속성이 그대로 적용되는 게 근본 원인이었다 — 다이어그램을viewBox에서 읽은 자연 크기 기준으로 측정해, 페이지 폭을 넘을 때만 축소하도록 수정. - fix: PDF 1차 렌더링 컨텍스트에 뷰포트 폭을 지정하지 않아 기본값 (1280px)으로 레이아웃된 뒤 뒤늦게 좁히면서 텍스트가 재줄바꿈되어 문서 높이가 측정값을 벗어나던 문제 수정 — 렌더링 시작 시점부터 PDF 목표 폭을 고정.
- fix: PDF 변환 시 페이지 넘김 지점이 다이어그램 도형(다이아몬드/박스)
한가운데를 가로질러 잘려 보이던 문제 수정. 청크 분할 시 "안전한(도형이
없는) 절단 지점"을 찾을 때 화살표/연결선(
<path>)까지 "점유된 구간"에 포함시킨 게 원인이었다 — 연결선은 정의상 노드 사이 여백 전체를 잇는 선이라, 촘촘히 연결된 플로우차트에서는 이를 포함하는 순간 진짜 빈 공간이 거의 사라져 탐색이 실패하고 도형 내부의 좌표를 그대로 절단 지점으로 반환하게 됐다. 절단 지점 탐색 대상에서path를 제외해 연결선 중간에서만 끊기도록 수정(pdf_book.py) — 화살표가 페이지 경계에서 끊기는 건 시각적으로 자연스럽다. - fix: PDF 인쇄 스타일 개선 — 화면용 폰트 크기(16px 루트 등)를 인쇄
비율에 맞춰 축소, 제목/문단/표가 페이지 경계 중간에서 잘리지 않도록
break-inside 보호 추가(
pdf_override.css). - 회귀 테스트 7건 추가(mermaid_wrap, 총 24개).
0.2.0 (2026-07-27)
- feat:
mdbook-binder --version옵션 추가. - fix:
__init__.py의 버전/패키지명이pyproject.toml과 어긋난 것 수정. - chore:
pyproject.toml버전을 0.2.0으로 갱신, ruffper-file-ignores에S112추가.
0.1.0 (2026-07-26)
- rename: CLI/패키지명을
book-binder에서mdbook-binder로 변경. - fix: wheel/sdist 빌드 시
templates/디렉토리가 누락되는 문제 수정. - feat:
book.yaml의custom_css지원 추가, Mermaid 렌더링 안정성 개선. - fix: PDF 변환 시 다이어그램·이미지 해상도가 저하되는 문제 개선.
- docs: README 전면 재작성, LICENSE 추가.
- feat: 초기 구현 — 마크다운 코퍼스를 HTML/PDF 도서로 변환·편집하는 애플리케이션.
라이선스
MIT — LICENSE 참고.
Release files for mdbook-binder 0.3.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| mdbook_binder-0.3.1.tar.gz | 3.2 MB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| mdbook_binder-0.3.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 6.3 MB
Release files / mdbook_binder-0.3.1.tar.gz
| Download URL | mdbook_binder-0.3.1.tar.gz |
|---|---|
| Size | 3.2 MB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
f286c56027eb3814cb1583497f050d8f4943c2a9fa63654a9659eeb7481c9635
|
|
BLAKE2b-256 checksum How to use checksums |
98188eee640e7ea0cb637c23d62eedd6d63f3b608575e7ae94bc8e82a6ce348d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.11.15
|
Release files / mdbook_binder-0.3.1-py3-none-any.whl
| Download URL | mdbook_binder-0.3.1-py3-none-any.whl |
|---|---|
| Size | 3.2 MB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
35b55068866fb9afb13682afa543f6b039d81a43d2529ec52fa497097656dda2
|
|
BLAKE2b-256 checksum How to use checksums |
aeb980a1b2ab3f76b2e401febe118a6ef9a265d3b31a3ae55cd0b25d11363766
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.11.15
|