Reference for the five output formats the rendering pipeline emits, the
render.formatsconfig block, the per-format env-var toggles, and the on-disk artefact layout.Companion to
../operational/logging/output-design.md(visual contract for terminal vs file output) andmarkdown-template-guide.md(source-format conventions).
| Format | Default | Output path | MIME | Renderer |
|---|---|---|---|---|
| on | output/<qualified-project>/pdf/<name>_combined.pdf |
application/pdf |
xelatex via pandoc | |
| HTML | on | output/<qualified-project>/web/index.html |
text/html |
pandoc |
| Slides | on | output/<qualified-project>/slides/<section>_slides.{pdf,html} |
Beamer PDF; Reveal HTML in the accessible pair | xelatex and pandoc |
| DOCX | opt-in | output/<qualified-project>/docx/<name>_combined.docx |
application/vnd.openxmlformats-officedocument.wordprocessingml.document |
pandoc |
| EPUB | opt-in | output/<qualified-project>/epub/<name>_combined.epub |
application/epub+zip |
pandoc |
Per-format toggles default to PDF/HTML/Slides on and DOCX/EPUB off —
opt in via render.formats in manuscript/config.yaml.
render:
formats:
pdf: true
html: true
slides: true
docx: true # opt-in
epub: false # opt-inThe block is validated by the project-config schema in
infrastructure/core/config/schema.py (negative control:
test_validate_config_keys_strict_raises_for_unknown_key asserts an unknown key
is rejected) — unknown keys under
render.formats are rejected at validation time.
ENABLE_DOCX=1 ENABLE_EPUB=1 \
./run.sh pipeline --project templates/template_code_project --mode core| Env var | Type | Default | Effect |
|---|---|---|---|
ENABLE_PDF |
0/1, true/false, yes/no (case-insensitive) |
1 |
Combined PDF + per-section LaTeX/PDF |
ENABLE_HTML |
same | 1 |
Combined HTML index + per-section HTML |
ENABLE_SLIDES |
same | 1 |
Archive: required per-section Beamer PDF. Accessible: transactional Beamer-PDF/Reveal-HTML pair. |
ENABLE_DOCX |
same | 0 |
Combined Microsoft Word document |
ENABLE_EPUB |
same | 0 |
Combined EPUB e-reader bundle |
The public precedence contract is an explicitly set
ENABLE_<FORMAT> environment variable over render.formats.<format> in YAML,
then the dataclass default. Direct users of the Python API may instead pass a
fully constructed RenderingConfig.
Precedence is resolved independently for each format, so mixed-source configuration is supported: an explicit false value remains an override rather than being treated as absent.
<project>_combined.pdf— the single canonical deliverable. Driven by the pandoc + xelatex pipeline; includes title page, TOC, bibliography, and all manuscript sections in order.- Auxiliary LaTeX artefacts (
.aux,.bbl,.tex,.log) support debugging and provenance inspection. Let the cleanup stage manage them; do not assume every tracked or release-bound artifact is disposable.
index.html— the combined HTML manuscript.- One
<section>.htmlper manuscript section, useful when previewing a single section in isolation. - Figures and cross-references are processed with
pandoc-crossrefwhen it is installed; the renderer logs a warning when the filter is unavailable.
- In the default
archiveprofile, one Beamer PDF per eligible manuscript section (<section>_slides.pdf) is required. Reveal.js HTML is an optional, explicitly requested derivative throughRenderManager.render_slides(..., output_format="revealjs")or the rendering CLI's--format revealjsoption. - In the
accessibleprofile, each eligible section produces both<section>_slides.pdfand<section>_slides.htmlfrom one composed Pandoc AST. The pair is transactional: failure of either writer removes both derivatives. - Beamer and Reveal.js decks resolve in-text citations against the shared top-level bibliography union. They suppress a repeated bibliography block; use the combined manuscript or dedicated references deck for the full list.
- Use the
render:skip-beamerHTML comment in a section to suppress its slide deck.
archive is the backwards-compatible default. Opt in to semantic accessible
composition in manuscript/config.yaml:
render:
slides:
profile: accessible
max_prose_words: 80
max_table_rows: 8
min_figure_area_percent: 70
title_font_pt: 28
body_font_pt: 20
figure_label_font_pt: 16
reader_href: ../web/index.htmlAccessible Beamer additionally requires the rendered-geometry inspection
capability supplied by pdfplumber. Install the rendering dependency group in
a source checkout with uv sync --group rendering, or install the package extra
with python -m pip install 'research-project-template[rendering]'. If that
capability is absent, the accessible profile fails with
slides.capability.pdf-geometry-required and removes the unverified derivative;
the default archive profile remains available. See
Optional Dependencies & Capability Matrix
for the complete boundary.
Configuration accepts these exact inclusive integer intervals:
| Field | Accepted interval | Default contract |
|---|---|---|
max_prose_words |
[1, 80] |
Ceiling 80 |
max_table_rows |
[1, 8] |
Ceiling 8 |
min_figure_area_percent |
[70, 100] |
Floor 70% |
title_font_pt |
[28, 96] |
Floor 28 pt |
body_font_pt |
[20, 72] |
Floor 20 pt |
figure_label_font_pt |
[16, 48] |
Floor 16 pt |
Within-range values remain policy settings rather than fit guarantees. The detailed renderer reference also lists the bounded AST, raw-TeX, image-path, and raster-resource diagnostics.
The numeric settings are guardrails: word and table-row maxima may only become
stricter, while figure-area and font floors may only increase. They are policy
ceilings and floors, not guarantees that every 80-word paragraph or eight-row
table fits. With a one-line title, the fixed 25-point Beamer footer leaves
seven regular 24-point-leading body lines at the 20-point floor. Compact table
rows and rules have a separately calibrated eight-unit geometry budget, and
figure percentages use a separate title-adjusted envelope; neither enlarges
the regular prose region. The renderer
uses one Pandoc semantic tree for both presentation formats. It may split
between paragraphs or other complete blocks, but never inside a list, equation,
code block, table, or figure. Oversized indivisible content produces a precise
slides.density.* failure instead of a smaller font. Tables display at most
eight body rows and link to the complete manuscript table; figure frames
allocate at least 70% of the usable slide area. An overfull accessible Beamer
frame is removed and reported as slides.density.beamer-overflow rather than
retained as a visually clipped PDF.
Reveal.js is the accessibility-enhanced presentation surface: named slide regions, keyboard navigation, visible focus, high contrast, responsive tables, reduced-motion behavior, source-owned figure alternatives and long descriptions, and a persistent manuscript-reader link. Beamer uses the same frame plan and visible 28/20/16-point floors but remains an explicitly labelled untagged PDF derivative. These controls do not establish WCAG or PDF/UA conformance. Reveal core, theme, and plugin assets use one version-pinned CDN release, so the browser deck remains network-dependent and is not an offline or byte-pinned bundle. Its MathJax loader is a narrower exception: the renderer normalizes it to one exact URL and reviewed SRI digest. The linked manuscript HTML retains complete captions, tables, long descriptions, and exact-value fallbacks and remains the canonical reader.
Every slide-policy field also has an environment override: SLIDES_PROFILE,
SLIDES_MAX_PROSE_WORDS, SLIDES_MAX_TABLE_ROWS,
SLIDES_MIN_FIGURE_AREA_PERCENT, SLIDES_TITLE_FONT_PT,
SLIDES_BODY_FONT_PT, SLIDES_FIGURE_LABEL_FONT_PT, and
SLIDES_READER_HREF. Explicit environment values take precedence over YAML.
<project>_combined.docx— the full manuscript as a Microsoft Word document, suitable for journal submission, collaborative editing, or reviewer markup.- Citations are processed with Pandoc
--citeprocusing the shared cross-format bibliography contract below. - An optional reference-doc template can be supplied to the renderer call —
see
infrastructure/rendering/docx_renderer.py.
<project>_combined.epub— the manuscript as an e-reader bundle (zip of XHTML + manifest + optional cover image).- Use the
cover_imagekwarg on the renderer call to bundle a cover.
Single- and multi-bibliography projects use one resolver. Combined PDF and
HTML, Beamer and Reveal.js slides, DOCX, EPUB, and the opt-in ebook stage
discover every top-level manuscript/*.bib file, sort by filename, deduplicate
repeated or symlinked paths, and pass the full set to their citation backend
without rewriting manuscript sources. Duplicate citation keys, including
case-only variants within one database or across databases, are an error:
fail-closed handling prevents BibTeX and citeproc from silently selecting
different definitions. The multi-bibliography
templates/template_search_project exemplar exercises this contract.
Per-section HTML previews remain intentionally separate: they render a single section and do not produce a combined bibliography. Slide decks resolve inline citations from the shared union but intentionally suppress the full references block in each section deck.
DOCX and EPUB consume a fresh shared preprocessed combined Markdown built
from the current ordered manuscript inputs. PDF-only and slides-only runs also
emit this file when HTML is disabled so every normal render lane has current
composition evidence. The composition is recorded in
output/reports/manuscript_composition.json; it does not depend on a PDF
artifact or a prior PDF run. PDF, DOCX, EPUB, and slides toggles can therefore
be selected independently. The receipt-bound combined Markdown remains in the
copied evidence tree even when HTML is disabled; renderer-owned HTML pages and
the favicon do not. Disabled deliverables cannot satisfy current-run
verification.
# All combined artifacts in the project working output
find projects/templates/template_code_project/output -type f \
-name '*_combined*' -newer pyproject.toml
# Check DOCX MIME
file -b --mime-type projects/templates/template_code_project/output/docx/*.docx
# Verify EPUB structure
unzip -l projects/templates/template_code_project/output/epub/*.epub | head -20render:
formats:
pdf: false # skip PDF; other enabled formats remain independent
html: true
slides: false
docx: false
epub: falsePipeline log shows the skip explicitly:
Render formats: pdf=False html=True slides=False docx=False epub=False
[skip] PDF rendering disabled in config (render.formats.pdf=false)
[skip] Slides rendering disabled in config (render.formats.slides=false)
Stages 3–5 use the same effective YAML-plus-environment configuration. Stage 3 removes renderer-owned prior deliverables before producing the enabled formats; Stage 4 rejects a source output tree that still contains a canonical artifact for a disabled format; and Stage 5 defensively removes disabled-format artifacts from the freshly cleaned copied tree before validating each enabled deliverable. A prior PDF therefore cannot satisfy an HTML-only run or be republished by the copy stage.
When slides: true, at least one current Markdown section must produce a deck;
configuring every section with <!-- render:skip-beamer --> is a validation
error rather than a successful zero-deliverable slides run. A project-local
scripts/_render_pdf_override.py is the legacy exception to the ordinary
format toggles: all three stages consistently treat that hook as PDF-only.
../operational/logging/output-design.md— terminal vs file visual contract../operational/config/configuration.md— full env-var + config referencemarkdown-template-guide.md— source-format conventions../guides/publishing-guide.md— uploading these formats to Zenodo / arXiv / GitHub Releases../architecture/adrs/003-multi-format-rendering-and-toggles.md— design rationale