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:  L(x,lambda) = f(x) + sum_(i in [n]) lambda_i g_i (x) !

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.