This is the documented process to transform a nicely written Markdown report into a nice Crítica-looking PDF.
The pipeline is Pandoc → LaTeX → Tectonic. All the styling lives in
assets/, so the Markdown stays clean prose. The output mimics iA Writer's
Modern (Sans) print template, with a custom Crítica cover page.
./build.sh # auto-detect the report .md in this folder
./build.sh report.md # build a specific file
./build.sh report.md out.pdfWith no argument, build.sh finds the one report Markdown in the repo root —
any *.md that isn't a doc (README/CLAUDE/…) and that opens with a YAML ---
metadata block — and writes a PDF named after it (e.g. report.md → report.pdf).
If there's no such file, or more than one, it tells you to name the file
explicitly. It also runs a preflight check first and stops with install hints
if a dependency is missing.
First run needs the network. Tectonic downloads its LaTeX support bundle once on first use, then caches it. Every build after that is offline.
Everything needed to build is either a small CLI install or already vendored in the repo. On a fresh machine you need exactly two tools:
| Tool | Version | Install |
|---|---|---|
| Pandoc | ≥ 3.9 | brew install pandoc · apt-get install pandoc |
| Tectonic | ≥ 0.16 | brew install tectonic · cargo install tectonic |
brew install pandoc tectonic # macOS, both at onceThen just ./build.sh. You do not need a LaTeX distribution (Tectonic is
self-contained) and you do not need to install any fonts — the IBM Plex
fonts are bundled in assets/fonts/ and loaded from there (see Fonts below).
The first build needs network access so Tectonic can fetch its support bundle.
The IBM Plex Sans and IBM Plex Mono fonts the design uses are vendored
in assets/fonts/ (the 8 .otf weights the template references), so the build
is self-contained — no system font install required. assets/cover.latex
loads them by relative path (Path = assets/fonts/).
IBM Plex is licensed under the SIL Open Font License (assets/fonts/OFL.txt),
which permits this redistribution. The fonts come from the official sources:
the IBM/plex repo or the
@ibm/plex npm package. To update
or add a weight, drop the .otf in assets/fonts/ and reference it in
cover.latex.
-
The document must carry its own metadata in a YAML frontmatter block. It drives the cover page and TOC:
--- title: TITLE subtitle: SUBTITLE eyebrow: Phase 1 Report # small-caps tracked label above the title author: AUTHORS date: May, 2026 cover: true # render the cover page toc: true # render the table of contents # Optional: header-text: TITLE # running header text (defaults to title) no-section-breaks: false # true = sections flow, don't break pages ---
build.sh is just one pandoc call that wires the assets together:
pandoc fase1v2.md \
--to=pdf --pdf-engine=tectonic \
--template=assets/cover.latex \
--include-in-header=assets/pdf-preamble.tex \
--lua-filter=assets/date-code.lua \
--lua-filter=assets/source-caption.lua \
--lua-filter=assets/keep-tables.lua \
--toc --toc-depth=3 \
-V colorlinks=true -V documentclass=article -V papersize=letter \
-o fase1.pdf| File | Role |
|---|---|
cover.latex |
Pandoc template: cover page (eyebrow → rule → title → subtitle → authors/date → wordmark), then TOC, then body. Loads the IBM Plex fonts from assets/fonts/. |
fonts/ |
Vendored IBM Plex Sans/Mono .otf weights + their OFL license. Makes the build self-contained — no system font install. |
pdf-preamble.tex |
All the print typography: page geometry, font sizes, heading scale, table styling, quotes, footnotes, page numbers. |
date-code.lua |
Filter: monospaces dates, renders --- as a full-width rule, makes tables span the full text width. |
source-caption.lua |
Filter: paragraphs starting with Source: render smaller and lighter, as captions. |
keep-tables.lua |
Filter: sizes table columns to their content (so headers aren't cut), keeps short tables on one page (boxed + auto-shrunk), and lets tables too tall for a page flow across pages with a repeating header. |
critica-wordmark.png |
Crítica logo on the cover. |
Plain Markdown, plus a few conventions:
| You want… | Write… |
|---|---|
| A top-level section (starts a new page) | ## Heading |
| A sub-section | ### Heading |
| A page break anywhere | \newpage on its own line (blank line above & below) |
| A horizontal divider rule | --- on its own line |
| A table/figure attribution | a paragraph starting with Source: |
| An image | {width=100%} |
Good to know:
- Every
##(H2) starts on a new page automatically — no manual breaks needed. The first H2 stays put, right after the TOC. - Tables are sized to their content (columns fit their headers and values). A table that fits on a page is kept whole and auto-shrunk if needed; one too tall to fit flows across pages with its header row repeated on each.
- Don't use
---for a page break — it renders as a divider rule. Use\newpage(or\clearpageto also flush any pending floats first). - Internal links and the TOC are black; external URLs are blue.
Most adjustments are one-liners in assets/pdf-preamble.tex:
| To change… | Edit |
|---|---|
| Body font size | \renewcommand{\normalsize}{...} near the top |
| Text column width / margins | the geometry block (365pt column) |
| Table font size | the \tbltabfont definition in the Tables section (wide page-breaking tables drop a notch automatically via keep-tables.lua) |
| Table row height | \arraystretch in the Tables section |
| Heading sizes / spacing | the \titleformat / \titlespacing blocks |
Cover layout (sizes, spacing, wordmark) lives in assets/cover.latex.
The font "IBMPlexSans-…" cannot be found— the vendored.otffiles are missing fromassets/fonts/. Restore them from the IBM/plex repo (build.shchecks for them and names any that are missing).- Build hangs or panics on the first run — Tectonic is fetching its bundle and needs network access. Run once online, then it works offline.
- Overfull
\hboxwarnings — harmless. The iA style disables hyphenation, so the odd long URL/token runs slightly past the right margin.
