Skip to content

feat: the HTML book output - #15

Merged
apiad merged 14 commits into
mainfrom
html-book
Oct 20, 2026
Merged

apiad merged 14 commits into
mainfrom
html-book

Conversation

@apiad

@apiad apiad commented Oct 20, 2026 •

Copy link
Copy Markdown
Owner

Part 2 of 3 for #13, stacked on #14. Plan tasks 4-7.

What changed

  • scriptorium/book.py:
    • browser_css() drops what only paged media runs (@page rules including @page:left, page and slide boxes, string-set, target-counter()/target-text()/counter(page) declarations) and turns page breaks into column breaks.
    • resolve_refs() writes cross-reference text into the empty a.ref-* anchors, counting chapters, sections and figures as the themes' CSS does. The strings live in each theme's theme.yml under html-refs:, merged through extends:.
    • collect_images() writes local images as WebP (capped at image-max-width, named by content) with intrinsic width/height. collect_css_assets() copies theme fonts.
    • relative_sizes() turns font-size: Npt into a share of the reader's size, so A−/A+ scales headings with the text.
    • render_book() / emit_book() write the directory. It holds a cover, a title page and one section.chapter.recto per chapter, and a full page right before a chapter heading opens that chapter.
  • themes/base/reader/: index.html, reader.css, reader.js. CSS multi-column layout makes the pages and the script never measures text. Each chapter is its own file (chapters/NNN.html) and its own column strip: the reader loads the chapter it needs, counts the other chapters' pages out of sight in idle time (cached per geometry, font size and edition) and estimates until then. Each section restarts the theme's CSS counters where the chapters before it left them. It provides swipe, tap zones, keys and wheel; rectos in a spread (a blank page goes in before a chapter heading that would land on the left); in-book links turn to their target; the place is stored by block, so it survives resizes and font changes. There are three reading modes, English and Spanish chrome, window.scriptoriumReader, and reader:ready / reader:page / reader:layout events. A project's js: files load after it.
  • prepare(for_screen=True) skips the inline TOC and ends page-floated notes with their chapter.
  • CLI: an html output builds the book; --format html builds one from a single file.
  • examples/html-book/: three short chapters (lang es) with outputs print, pocket (A5) and web.

Measured

  • Unit tests: test_book_css (7), test_book_refs (5), test_book_assets (6), test_book_html (10).

  • Browser tests (-m browser, Chromium found or skipped): 14 pass at 390×844 touch and 1440×900. They cover the TOC jump, turn and resume; arrow keys walking every page across all chapters in order and back; a swipe that starts on an image; rectos all on right pages; nothing spilling out of its page in any chapter (a 300-character word, a wide table, a long code line); a link to another chapter loading it; a reference in the same chapter; a font change keeping the first block; a #hash opening at its chapter; and no console errors.

  • Layout cost on a 129,000-word book (861 pages at 390×844), one strip for the whole book against one strip per chapter:

    whole book, CPU ×1 per chapter, CPU ×1 whole book, CPU ×4 per chapter, CPU ×4
    ready to read 3.7 s 0.44 s 11.6 s 0.70 s
    font size change 1.05 s 28 ms 4.1 s 66 ms
    crossing into a chapter n/a 8–21 ms n/a 35–110 ms
    every page counted (background) n/a 2.7 s n/a 7.7 s

    The per-chapter count gives the same 861 pages as the single strip. Before the split, parsing the 1 MB index alone took 1.2 s, and the theme's styles plus the columns took 2.8 s more.

🤖 Generated with Claude Code

apiad and others added 12 commits October 20, 2026 10:03
Refs #13

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Refs #13

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Refs #13

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Refs #13

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Refs #13

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Themes declare the strings under html-refs:, merged through extends like page:.

Refs #13

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Pillow becomes a direct dependency: the book needs it without the pdf extra.

Refs #13

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
No inline TOC, and page-floated notes end their chapter instead.

Refs #13

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
render_book writes a static directory: the theme CSS filtered for a browser,
font sizes as shares of the reader's size, images as WebP, and a reader that
pages with CSS columns, swipes, keeps rectos in a spread, follows in-book links
and remembers the place by block. examples/html-book builds it next to two PDFs.

Refs #13

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@apiad
apiad deleted the branch outputs October 20, 2026 14:32
@apiad apiad closed this Oct 20, 2026
@apiad apiad reopened this Oct 20, 2026
@apiad
apiad changed the base branch from outputs to main October 20, 2026 14:33
apiad and others added 2 commits October 20, 2026 10:33
# Conflicts:
#	docs/superpowers/plans/2026-10-20-html-book.html
#	scriptorium/cli.py
#	scriptorium/render.py
Each chapter is its own file and its own column strip. index.html carries the
TOC, which chapter holds each id and each chapter's length; the reader loads
the chapter it needs, counts the others' pages out of sight in idle time
(cached per geometry, font size and edition), and estimates until then. Each
section restarts the theme's CSS counters where the previous chapters left them.

On an 861-page book at a phone size: ready in 0.44 s (0.70 s at CPU x4), a font
change re-lays out in 28 ms (66 ms), crossing into a chapter takes 8-21 ms
(35-110 ms), and all pages are counted 2.7 s (7.7 s) after opening.

Refs #13

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@apiad
apiad merged commit 00c5d8f into main Oct 20, 2026
2 checks passed
@apiad
apiad deleted the html-book branch October 20, 2026 15:00
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant