5. Math and Code Highlighting
pfpdf bundles everything needed for math and syntax highlighting. After the initial browser download, these features work without network access.
5.1 Inline math
Text enclosed in $...$ becomes inline math. Do not put whitespace immediately after the opening $ or immediately before the closing $, and do not let the expression span a line break.
The solutions of a quadratic equation are $x = \frac{-b \pm \sqrt{b^2 - 4ac}}{2a}$.
The solutions of a quadratic equation are $x = \frac{-b \pm \sqrt{b^2 - 4ac}}{2a}$.
5.2 Display math
Text between $$ delimiters on separate lines becomes display math. A delimiter on the same line as the expression does not start a display-math block.
$$
\int_{-\infty}^{\infty} e^{-x^2} \, dx = \sqrt{\pi}
$$
If the closing $$ is missing, no math block is started and the content is treated as regular text. If MathJax reports a TeX syntax error, pfpdf fails with exit code 2 rather than leaving behind a PDF containing the broken math.
$$ \int_{-\infty}^{\infty} e^{-x^2} , dx = \sqrt{\pi} $$
5.3 A $ that should not become math
To keep a $ in ordinary prose from becoming math, escape it as \$.
The price is \$100.
5.4 Code highlighting
Add a language name to a fenced code block to enable syntax highlighting.
```python
def greet(name: str) -> str:
return f"Hello, {name}!"
```
def greet(name: str) -> str:
return f"Hello, {name}!"
Other languages work the same way.
export function add(a: number, b: number): number {
return a + b;
}
If you omit the language name, you get a plain code block without highlighting. If you specify an unknown language name, the code itself is kept and displayed as plain text, and a warning is emitted.
a plain text block
5.5 Mermaid diagrams
A fenced code block with the language name mermaid is rendered as a diagram. The Mermaid runtime itself is bundled with pfpdf, so no CDN connection is required.
```mermaid
flowchart LR
A[Markdown] --> B[Mermaid]
B --> C[PDF]
```
flowchart LR
A[Markdown] --> B[Mermaid]
B --> C[PDF]
pfpdf renders Mermaid diagrams to SVG during Markdown conversion. It stores each SVG as a standalone image in the build workspace, and Vivliostyle lays the vector image out on the page. If a diagram contains a syntax error, pfpdf reports the source file and line and exits with code 2 instead of placing unrendered source in the PDF. A failure to load the bundled Mermaid runtime produces exit code 1.
Diagrams are laid out with ELK by default. To use another layout such as dagre for a diagram, specify it in the Mermaid front matter. Only that diagram uses the specified layout.
```mermaid
---
config:
layout: dagre
---
flowchart LR
A[Markdown] -->|convert| B[PDF]
```
Flowchart edge labels such as A -->|label| B and Japanese labels broken with <br/> are also laid out with sizes measured using the bundled font.
A diagram is never split across pages, so it is scaled down to fit both the body width and the height of one page. If a tall diagram makes its text too small, change its direction, for example to flowchart LR, or split it into several diagrams.
Gantt diagrams can also be rendered directly. The default width is 1200px. Set config.gantt.useWidth in the diagram’s front matter to choose a drawing width. The PDF scales the image to fit the body width, so reduce the drawing width if the text is too small.
---
config:
gantt:
useWidth: 800
---
gantt
dateFormat YYYY-MM-DD
axisFormat %m/%d
tickInterval 1day
todayMarker off
section Tasks
Prepare :a1, 2026-01-01, 3d
Build :a2, after a1, 2d
5.6 No conversion inside code blocks
Inside code blocks and inline code, notation such as **strong**, $math$, raw HTML, and ___ is never interpreted. This is handy when writing about the notation itself.