Generate PDF Documentation

Build the complete documentation PDF with Hugo and Prince.

Overview and tools needed

The full-document PDF is generated by rendering the Hugo site and converting the resulting HTML with Prince. Prince supports print-specific CSS, bookmarks, cross-reference page numbers, links, and the JavaScript needed for equation rendering. Its non-commercial license is sufficient for local and project use, but it adds a watermark to generated documents. A license suitable for public distribution is required before publishing an unwatermarked PDF.

Install Hugo Extended, Go, Python 3, curl, and Prince before running the generator. The minimum Prince version for the MathJax compatibility script is 20210624; the latest Prince release is recommended.

Build process

The repository-root pdf-docs.sh script performs the complete build directly with Hugo. It performs four steps:

  1. Hugo renders the PDF outputs and selected documentation pages into a temporary directory.
  2. Hugo generates a Prince input list from the documentation, tutorials, and appendix sidebars.
  3. A temporary local HTTP server serves the rendered HTML and static assets.
  4. Prince reads the input list and writes the final PDF.

Render the PDF target with Hugo

Run the script from the repository root:

./pdf-docs.sh

Internally, the Hugo step is equivalent to:

hugo --gc --minify --cleanDestinationDir \
  --environment pdf \
  --renderSegments pdf \
  --destination public-pdf \
  --baseURL http://127.0.0.1:4173/

The pdf environment is defined in config/pdf/hugo.toml. It adds the title page, table of contents, part-title pages, and Prince input-list output. The pdf segment limits normal HTML output to the documentation and tutorial sections included in the PDF.

Generate the Prince input list

The list is generated at public-pdf/pdf/prince-list.txt; it must not be edited manually. layouts/partials/pdf/prince-list.txt traverses the Hugo sidebar data and includes only entries whose sidebar output contains pdf. The current order is:

  1. title page;
  2. table of contents;
  3. documentation part page and documentation pages;
  4. tutorials part page and tutorial pages; and
  5. appendix part page and appendix pages.

The generated list contains local absolute URLs, for example:

http://127.0.0.1:4173/pdf/title.html
http://127.0.0.1:4173/pdf/toc.html
http://127.0.0.1:4173/docs/fundamentals/overview/

layouts/partials/pdf/page-for-url.html resolves sidebar URLs and aliases to the corresponding Hugo page, so renamed pages can still be included.

Convert the rendered pages to PDF

After the temporary server is ready, the script invokes Prince with the generated list:

prince --javascript \
  --input-list=public-pdf/pdf/prince-list.txt \
  -o pdf/docs.pdf

The final document is written to pdf/docs.pdf. The server is stopped and its temporary log is removed automatically when the script exits.

The output directory, output file, and local server port can be changed using environment variables:

PDF_BUILD_DIR=/tmp/precice-pdf \
PDF_OUTPUT=/tmp/precice-docs.pdf \
PDF_PORT=4174 \
./pdf-docs.sh

Styling

When params.output is pdf, the base and content layouts use the print markup instead of the normal navigation and sidebar wrappers. The print templates and PDF-specific partials are in layouts/partials/pdf/, while layouts/partials/head_print.html loads the local print resources.

PDF-only styles are in static/css/printstyles.css. They define page headers and footers, page counters, table-of-contents leaders, page breaks, image limits, and print-friendly alert boxes. Do not edit minified vendor CSS for a PDF-only adjustment; add a scoped rule to printstyles.css instead.

Prince compatibility scripts and print assets are served locally from static/js/, static/fonts/, and static/webfonts/. Keeping these resources in the generated site prevents the PDF build from depending on a browser or on CDN availability.

Contents, title page, and table of contents

The Hugo sidebars in data/sidebars/ define the PDF contents. Add pdf to a sidebar entry’s output value when a page belongs in the document, for example output: web, pdf. Entries without pdf remain available on the website but are excluded from the PDF. The appendix uses data/sidebars/pdf_appendix_sidebar.yaml.

The title page, table of contents, and part-title pages are separate Hugo outputs. The table of contents is built recursively from the sidebar folders, preserving nested sections and the order defined in the data files.

Troubleshooting

Prince warnings

Prince validates CSS more strictly than a browser. Warnings about unsupported Bootstrap properties, modern pseudo-classes, or browser-only media features are expected when they do not affect the printed output. A missing resource, failed URL, or non-zero Prince exit status requires investigation.

Missing resources

Prince reads one URL at a time from the local server. Run the script rather than opening generated HTML with a file:// URL, and check that referenced stylesheets, images, scripts, and fonts exist below public-pdf/.

Missing glyphs or fonts

If Prince reports missing glyphs, verify that the required Fira Sans, Fira Mono, Font Awesome, and KaTeX resources are present in static/fonts/, static/webfonts/, and static/css/fonts/. See the Prince troubleshooting documentation for details.

Debugging one page

To debug a specific page, copy its local URL into a temporary input list and run Prince against that list. This avoids rebuilding the entire document while investigating CSS, images, or equations.