Markdown to KDP-ready paperback, hardcover, and Kindle EPUB. XeLaTeX-driven interior typography with a ReportLab fallback, plus a calibrated cover-wrap PDF that gets the spine math right.
Project description
scbe-bookforge
Markdown to KDP-ready paperback, hardcover, and Kindle EPUB. XeLaTeX-driven interior typography with a ReportLab fallback, plus a calibrated cover-wrap PDF that gets the spine math right.
Built because we got tired of Word templates and Vellum subscriptions for self-publishing on Amazon KDP.
What it does
manuscript.md ─► bookforge build ─► interior.pdf + cover-wrap.pdf + book.epub + book.docx
- Interior PDF: real book typography via XeLaTeX (hyphenation, microtype, widow/orphan control). Falls back to ReportLab if XeLaTeX isn't installed.
- Cover wrap PDF: full back + spine + front with bleed. Spine width is computed from page count and paper type using the actual KDP formula (
pages × 0.0025 infor cream B&W). - EPUB: pandoc-native, with title/subtitle/author/identifier metadata.
- DOCX: pandoc-native, with TOC.
Install
pip install scbe-bookforge
For the better-typography path, also install:
- pandoc — https://pandoc.org/installing.html
- MiKTeX (Windows) or TeX Live (macOS/Linux) — provides
xelatex
If xelatex is missing, bookforge automatically uses its ReportLab fallback.
Quick start
Drop a bookforge.json next to your manuscript:
{
"title": "Your Book Title",
"subtitle": "An Optional Subtitle",
"author": "Your Name",
"copyright_year": 2026,
"publisher": "Your Name",
"isbn": "Print ISBN: printed on back cover (free KDP ISBN)",
"edition_statement": "First edition",
"source": "manuscript.md",
"output_dir": "build",
"trim": "5.5x8.5",
"page_count": 320,
"print": {
"paper": "cream",
"ink": "bw",
"cover_finish": "matte"
},
"epigraph": {
"enabled": true,
"text": "Your epigraph text.",
"attribution": "Source"
},
"dedication": "To whoever this is for."
}
Build everything:
bookforge build
Or one at a time:
bookforge interior
bookforge cover
bookforge epub
bookforge docx
bookforge info # show resolved profile + spine width
Outputs land in output_dir.
Profile reference
| Field | Default | Notes |
|---|---|---|
title |
required | Book title |
subtitle |
"" |
Optional |
author |
"" |
|
copyright_year |
2026 |
|
publisher |
author | Imprint name shown on copyright page |
isbn |
"" |
Use literal "Print ISBN: printed on back cover (free KDP ISBN)" for KDP free ISBNs |
edition_statement |
"First edition" |
|
creative_nonfiction_notice |
"" |
Shown on copyright page if set |
dedication |
"" |
Renders a dedication page if set |
epigraph.enabled |
false |
|
epigraph.text |
"" |
|
epigraph.attribution |
"" |
|
source |
required | Path to manuscript Markdown, relative to the profile |
output_dir |
"build" |
Relative to the profile |
binding |
"paperback" |
paperback or hardcover (hardcover adds 0.125" to inner margin) |
trim |
"5.5x8.5" |
Or "5x8", "5.25x8", "6x9", or {"width_in": W, "height_in": H} |
page_count |
null |
Required for cover wrap. Build the interior first; KDP's previewer will report the page count, paste it back here, rebuild the cover. |
print.paper |
"cream" |
cream or white (affects spine math) |
print.ink |
"bw" |
bw, color_standard, color_premium |
print.cover_finish |
"matte" |
Informational |
typography.body_font |
"Georgia" |
Any installed font; bookforge looks for it via fontspec (XeLaTeX) or C:\Windows\Fonts (ReportLab) |
typography.body_size_pt |
10.75 |
|
typography.leading_pt |
14.0 |
|
typography.first_line_indent_in |
0.22 |
|
typography.chapter_title_size_pt |
17.0 |
|
typography.part_title_size_pt |
18.0 |
|
margins.top_in |
0.62 |
|
margins.bottom_in |
0.68 |
|
margins.inside_in |
0.75 |
Inner margin (gutter side) |
margins.outside_in |
0.5 |
|
margins.hardcover_inside_bonus_in |
0.125 |
Extra inner margin when binding="hardcover" |
interior_engine |
"auto" |
auto, xelatex, or reportlab |
Back-cover blurb
The cover wrap defaults are intentionally bland. Pass --blurb path/to/blurb.json to populate them, or put the fields directly into your profile:
{
"hook": "Single line at the top of the back.",
"blurb_paragraphs": [
"First paragraph.",
"Second paragraph.",
"Third paragraph."
],
"author_bio": "Optional bio.",
"bottom_left_caption": "A WORK OF CREATIVE NONFICTION"
}
Manuscript conventions
- One
# H1line at the top of the file is treated as the book title and skipped (the title page comes from the profile). ## Chapter N. Title→ typeset chapter; gets its own page break + recto opening.## Part N. Title→ typeset part heading.---on its own line → typeset scene break (* * *).*italic*and**bold**work as expected.- Smart quotes are produced automatically (pandoc's
markdown+smart).
Spine math
Bookforge uses the KDP formulas:
| Paper type | Inches per page |
|---|---|
| Cream, B&W | 0.0025 |
| White, B&W | 0.002252 |
| Color, standard | 0.002347 |
| Color, premium | 0.002347 |
spine_width = page_count × per_page. Cover wrap dimensions = (0.125 + trim_w + spine + trim_w + 0.125) × (0.125 + trim_h + 0.125).
If KDP's previewer flags your cover by more than ~0.05", regenerate using the page count KDP reports for the interior you uploaded.
Programmatic use
from scbe_bookforge import load_profile, build_all
profile = load_profile("my-book/bookforge.json")
artifacts = build_all(profile)
print(artifacts)
# {"interior_pdf": ..., "cover_pdf": ..., "epub": ..., "docx": ...}
License
MIT or Apache 2.0, at your option.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file scbe_bookforge-0.1.0.tar.gz.
File metadata
- Download URL: scbe_bookforge-0.1.0.tar.gz
- Upload date:
- Size: 22.8 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
520bcd5d9012b986a7c93d2816c4f0266ff826c1aa3a31c43861e041ad99a24a
|
|
| MD5 |
241c5a0c9ad8e76df97893002113edd0
|
|
| BLAKE2b-256 |
8a891115e9f8222433378e5a5c4fe89f4a3ee2d3b069766d1b8365b4fa46b87a
|
File details
Details for the file scbe_bookforge-0.1.0-py3-none-any.whl.
File metadata
- Download URL: scbe_bookforge-0.1.0-py3-none-any.whl
- Upload date:
- Size: 23.6 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
c805e6e54cc0849e6ed3d63180d84fd0329f132eda7a1276076f76204fd9cc07
|
|
| MD5 |
b9b41c4239c8128dcf19696e185c3b32
|
|
| BLAKE2b-256 |
8968e13cfe7fc7632a203f311092f222f425676e6aacfdb5871d091b091945ae
|