Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# Build intermediates. The deliverables (.epub, .pdf, cover .png) are committed.
build/*/body.html
build/*/media/

node_modules
package-lock.json
113 changes: 113 additions & 0 deletions BUILDEBOOK.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
# Build brief — turn these HTML books into sellable ebooks

Hand this whole file to Claude Code, in the folder that contains the source files.

---

## Project

Two editions of the same novel, plus a cover generator.

| File | What it is |
|---|---|
| `faramushkhaneh.html` | Persian edition — «مردی که دخترش را فراموش کرد» |
| `the-man-who-forgot-his-daughter.html` | English edition — *The Man Who Forgot His Daughter* |
| `cover.html` | Cover generator (canvas, exports 1600×2560 PNG, FA/EN toggle) |

**Author (both editions):** محمدپرهام پلنگ سنگدوینی / Mohammadparham Palangsangdovini

**Deliverables:** for each language — a validated EPUB 3, a print-ready PDF, and a cover PNG.

---

## Task 1 — Covers

Open `cover.html` in a headless browser (Playwright is fine). Wait for
`document.fonts.ready` before capturing, or the Persian text will render as boxes.

Export four PNGs by clicking the language toggle and the full-size download:

- `cover-fa.png` — 1600×2560
- `cover-en.png` — 1600×2560
- plus 600×960 web versions of each for store listings

Verify each PNG is exactly 1600×2560 and under 50 MB (Amazon's ceiling).

---

## Task 2 — EPUB

Use pandoc. Two things matter more than anything else here:

### Persian EPUB — the part that usually breaks

Persian will not render on Kindle, Kobo, or Apple Books unless the font is
**embedded inside the EPUB**. Do this:

1. Download a Persian-capable font with an open licence (Vazirmatn or Noto Naskh Arabic).
2. Embed it via `--epub-embed-font`.
3. Set RTL in the CSS: `body { direction: rtl; text-align: justify; }`
4. Set `page-progression-direction="rtl"` in the OPF spine. Pandoc will not do this
itself — unzip the EPUB, patch `content.opf`, rezip with `mimetype` stored
uncompressed and first in the archive, or the file will be rejected.

### Metadata

Read the author from `<meta name="author">` in each HTML file. Build an
`epub-metadata.yaml` per language with: title, author, language (`fa` / `en`),
publisher, rights, and a UUID identifier. Give each language its **own** UUID —
they are two different books in every store.

### Structure

The HTML uses `<h3>` for chapter titles and `<h2>` for the three book dividers.
Set `--toc --toc-depth=2` and make sure the generated navigation lists all 23
chapters plus the interlude, in order. Check the interlude sits between chapter 17
and chapter 18 — that placement is deliberate, not a mistake.

Keep the styled elements intact: `.letter` (Dalaram's letter), `.journal`
(the interlude's diary entries), `.ledger`, `.names`, `.brk` scene breaks, and the
drop caps on `.lead`. If a reader strips the drop cap, that's acceptable; if it
strips the letter and journal styling, fix the CSS — those blocks need to read as
documents, not as body text.

---

## Task 3 — PDF

Use Chromium print-to-PDF (weasyprint mishandles RTL). Page size 6×9 inches,
0.75in margins, and add `@media print` rules so:

- each `<section class="chapter">` starts on a new page
- the cover, part dividers, and colophon each get their own page
- `.brk`, `.letter`, and `.journal` blocks never split across a page break
- no orphans or widows on paragraph breaks

---

## Task 4 — Validate

Run `epubcheck` on both EPUBs. Zero errors — Amazon rejects on any error, and
warnings about unusual CSS are fine to ignore. Then open both EPUBs in Calibre's
viewer and confirm by eye:

- Persian reads right-to-left and the letters are joined (if letters appear
separated, some CSS `letter-spacing` survived — remove it, it breaks Persian script)
- the cover image is the first page
- the table of contents jumps correctly
- chapter numbering runs 1–23 with no gaps and no repeats

---

## Output

```
build/
fa/ faramushkhaneh.epub faramushkhaneh.pdf cover-fa.png
en/ the-man-who-forgot-his-daughter.epub ...pdf cover-en.png
```

Write a `Makefile` or `build.sh` so the whole thing can be re-run after any text
edit. I will be revising the manuscript, so the build has to be repeatable.

Report back with the epubcheck output and the final file sizes.
67 changes: 67 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# Thin wrapper over build.sh with per-target dependencies, so an edit to one
# edition's HTML does not rebuild the other.
#
# make both editions, then validate
# make fa en one edition
# make covers
# make check epubcheck + structural verification
# make clean

SHELL := /usr/bin/env bash

PANDOC ?= pandoc
NODE ?= node
EPUBCHECK ?=

FA_SRC := src/faramushkhaneh.html
EN_SRC := src/the-man-who-forgot-his-daughter.html

FA_EPUB := build/fa/faramushkhaneh.epub
FA_PDF := build/fa/faramushkhaneh.pdf
EN_EPUB := build/en/the-man-who-forgot-his-daughter.epub
EN_PDF := build/en/the-man-who-forgot-his-daughter.pdf

COVERS := build/fa/cover-fa.png build/en/cover-en.png

FONTS := assets/fonts/Vazirmatn-Regular.ttf

export PANDOC NODE EPUBCHECK

.PHONY: all fa en covers fonts check clean
.DEFAULT_GOAL := all

all: fa en check

fonts: $(FONTS)

$(FONTS): tools/fetch-fonts.py
./build.sh fonts

covers: $(COVERS)

$(COVERS): src/cover.html tools/render-cover.mjs tools/browser.mjs | fonts
./build.sh covers

fa: $(FA_EPUB) $(FA_PDF)

en: $(EN_EPUB) $(EN_PDF)

$(FA_EPUB) $(FA_PDF): $(FA_SRC) $(COVERS) \
metadata/epub-fa.yaml assets/css/epub-fa.css \
assets/css/print-common.css assets/css/print-fa.css \
tools/prepare.py tools/patch-epub.py tools/render-pdf.mjs
./build.sh fa

$(EN_EPUB) $(EN_PDF): $(EN_SRC) $(COVERS) \
metadata/epub-en.yaml assets/css/epub-en.css \
assets/css/print-common.css assets/css/print-en.css \
tools/prepare.py tools/patch-epub.py tools/render-pdf.mjs
./build.sh en

check: $(FA_EPUB) $(EN_EPUB)
./build.sh check
python3 tools/verify-epub.py $(FA_EPUB) --lang fa
python3 tools/verify-epub.py $(EN_EPUB) --lang en

clean:
rm -rf build
85 changes: 85 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
# مردی که دخترش را فراموش کرد / The Man Who Forgot His Daughter

Two editions of one novel by محمدپرهام پلنگ سنگدوینی / Mohammadparham
Palangsangdovini, built from HTML into sellable ebooks.

Each edition ships as a validated EPUB 3, a 6×9in print-ready PDF, and a cover
PNG at Amazon KDP's dimensions.

## Build

```sh
./build.sh # everything, then validate
./build.sh fa # Persian only
./build.sh en # English only
./build.sh covers # redraw the covers
./build.sh check # epubcheck + structural verification
```

`make` does the same with dependency tracking, so editing one edition's HTML
rebuilds only that edition:

```sh
make # both editions, then validate
make fa # Persian only
make clean
```

### Requirements

| Tool | Why | Notes |
|---|---|---|
| `pandoc` 3.x | EPUB generation | `PANDOC=/path/to/pandoc` to override |
| `node` 18+ with `playwright` | covers and PDFs | `npm install playwright` |
| Chromium | canvas rendering, print-to-PDF | auto-detected; `CHROMIUM_PATH` to override |
| `python3` with `beautifulsoup4` | HTML restructuring | `pip install beautifulsoup4` |
| `java` + `epubcheck.jar` | validation | `EPUBCHECK=/path/to/epubcheck.jar` |

Validation is skipped with a notice when `EPUBCHECK` is unset, so the build
still runs without it.

Fonts download themselves into `assets/fonts/` on first build and are cached
after that. All are Open Font Licence; the licence texts sit beside them.

## Editing the manuscript

Edit `src/faramushkhaneh.html` or `src/the-man-who-forgot-his-daughter.html`
and re-run the build. The pipeline reads the structure out of the markup rather
than from a hard-coded list, so adding or reordering a chapter needs no change
here — as long as the existing shape holds:

- `<section class="chapter">` per chapter, with a `<div class="chapter-num">`
and an `<h3>` inside `<div class="chapter-head">`
- `<section class="part">` for the three book dividers
- the interlude carries `class="chapter midbreak"`

`tools/verify-epub.py` re-checks chapter numbering, the interlude's position,
and the navigation after every build, so a mistake in the markup surfaces as a
failed check rather than as a broken store upload.

## Layout

```
src/ the two editions and the cover generator (the manuscript)
assets/css/ EPUB and print stylesheets
assets/fonts/ downloaded OFL fonts + their licences
metadata/ per-edition EPUB metadata, each with its own fixed UUID
tools/ build steps, each runnable on its own
build/ output: fa/ and en/
```

## Notes on the two formats

**EPUB.** Persian is embedded with Vazirmatn, Noto Naskh Arabic and Noto
Nastaliq Urdu, because no major reader ships a Persian face. Right-to-left is
declared through `dir` attributes and the OPF spine's
`page-progression-direction`, not through CSS — EPUB 3.3 forbids the CSS
`direction` property, and epubcheck rejects it.

**PDF.** Rendered by Chromium rather than weasyprint, which mishandles
Arabic-script shaping and bidi.

**No drop cap in the Persian edition.** A floated `::first-letter` lifts the
initial letter out of its word; in Arabic script that destroys the joined form,
so «هر» would set as «ه» plus a stranded «ر». The English edition keeps its
drop cap.
Loading