Rendering Equations with Typst
2025-06-05
I wanted to be able to have nice math formulas on my blog, and I wanted them to be written in typst.
With the power of computers, I have achieved it:
!
To do this, I have written a script which looks for instances of three [
s enclosing a formula,
optionally starting with a !
to indicate block-equations.
It then (more or less) runs it through the following commands:
$ typst compile template.typ - --format svg --input d=IS_BLOCK --input eq="FORMULA"
$ typst query template.typ "<down>" --input d=IS_BLOCK --input eq="FORMULA" --field value --one
The first command creates the svg, which gets added some styling to make the text-color match my blog and work in dark-mode:
<style>
:root { color-scheme: light dark; }
.typst-text use { fill: light-dark(oklch(0.35 0.035 215), oklch(0.98 0.015 215)) !important; }
.typst-shape { stroke: light-dark(oklch(0.35 0.035 215), oklch(0.98 0.015 215)) !important; }
</style>
The second command simply outputs the baseline height (in millimeters). This is used as
vertical-align: -___mm;
on the <img>
to properly align the equation with the surrounding text.
The typst template.typ
is as follows:
#{
let display = eval(mode: "code", sys.inputs.at("d", default: "true"))
let equation = eval(mode: "math", sys.inputs.at("eq", default: "quest.double"))
let eq = math.equation(block: display, equation)
set text(top-edge: "bounds", size: 13pt)
show math.equation: set text(font: "IBM Plex Math")
context {
let rendered-tight = measure(eq).height
set text(bottom-edge: "bounds")
context {
let rendered-loose = measure(eq).height
let diff = rendered-loose - rendered-tight
set page(
width: auto,
height: auto,
margin: 0pt,
fill: none,
)
[#metadata(diff.mm())<down>]
eq
}
}
}
Most of the complications here come from calculating the baseline height relative to the image boundary.