Repository navigation
Expose render_html and make the PDF stack an optional extra #2
Description
Problem
Scriptorium can only produce a PDF. For documents the pipeline is already pure HTML + CSS: the preprocessors (footnotes, citations, glossary, timeline) → parse() → emit() build one HTML document, and WeasyPrint only prints it. But that HTML exists only as a local inside render_pdf (scriptorium/galley.py:668), and galley.py imports weasyprint at module level (galley.py:19). So:
- No HTML output. Nothing returns the HTML a document renders to, so a screen consumer has to re-implement the preprocessor chain to get it. The chain's order is deliberate (citations after footnotes, glossary last), so a copy drifts.
- WeasyPrint is mandatory. It pulls in pango and friends. A consumer that only needs Markdown → HTML still has to install the whole PDF stack.
- The entry point lives in
galley.py, which is being retired: only the deck path still usesmeasure()/pack().
First consumer
marginalia (apiad/marginalia#5) is being rebuilt on scriptorium so its reader inherits all of scriptorium's Markdown features (components, math, footnotes, citations, glossary, cross-refs). It needs the HTML of a document and never a PDF. It will run on a server where installing WeasyPrint is pure cost.
Checked on 2026-10-04: a raw <span class="marg-s" data-o="42"></span> block survives process_footnotes → parse → emit as its own <div class="unit">, in order, between a footnoted paragraph, a loose list and the endnotes. HTML comments are already stripped by _split_md, so marginalia's annotations (HTML comments in the chapter source) never reach the PDF.
Wanted
render_html(src, *, theme_name=None, cwd=None, execute=True, vars=None, code_root=None, project_meta=None) -> (html, warnings)in a module outsidegalley.py, holding everythingrender_pdfdoes up to and includingemit().render_pdfbecomesrender_html+ WeasyPrint, with unchanged behaviour and report.- WeasyPrint moves to an optional extra (
scriptorium[pdf]) and is imported lazily inside the PDF path.import scriptoriumandrender_htmlwork without it;render_pdfwithout it fails with a message naming the extra. scriptorium render --html(or-o x.html) writes the HTML document. A deck theme still needs measuring and thepdfextra, so--htmlon a deck errors out clearly.- Tests:
render_htmlround trip on the existing fixtures,render_pdfoutput unchanged, and an import test in an environment without WeasyPrint.
Note: parse.py and tests/test_parse.py carry uncommitted changes in the shared checkout on zion; this work should not need to touch either.
Activity
apiad commentedon Oct 5, 2026
Also needed for any install that is not an editable checkout: the wheel ships no themes.
uv build --wheelon d87d5d9 produces 24 files and none underthemes/, because[tool.hatch.build.targets.wheel] packages = ["scriptorium"]andTHEMES_DIR = Path(__file__).resolve().parent.parent / "themes"(scriptorium/theme.py:26) points outside the package. marginalia installs scriptorium as a git dependency, soload_themewould fail there. Fix: force-includethemesinto the package and resolveTHEMES_DIRinside it, falling back to the repo layout.apiad commentedon Oct 5, 2026
taken by httyc-dictation-pilot