Intended Audience:

  • You want to share notes containing mathematical content in multiple formats (PDF, web).
  • You are using or are thinking of using Obsidian for note-taking.

Click here to go skip right to the instructions.

Survey of Existing Methods

The amount of effort that went into making my own solution is proportional to the amount of inconveniences found in existing solutions. But chances are that they might be good enough for you.

Mathjax and KaTeX

Almost all the time you see mathematical expressions rendered on the web, it was produced using either MathJax (used by Physics Stackexchange, Wikipedia, MathOverflow or some Discord Extensions) or KaTeX (used by Notion, GitLab, GradeScope, VSCode Preview).

What’s important to know about them is that they are not a compiler, but rather use a bunch of JavaScript to parse the text and render them to images. As a consequence, they only support a fraction of what offers. KaTeX’s subset of supported LaTeX is relatively small, but good enough for most efforts. MathJax’s list of available commands is much larger and offers more flexibility for custom macros and packages (like amsmath), but as somebody who has been using for a long time before trying to host content on the web, I have built up a large collection of macros, commands, package preferences and configuration options that improved my writing, editing and typesetting experience that I can’t do without but which will very likely not be supported without me writing my own MathJax extensions.

Ergonomic Issues

Now compatibility issues aside, there is another reason why something new was required. I have spent countless hours trying to find some way of writing content once, and obtaining html and pdf output “in 𝒪︀(1) time” (i.e. without needing to write and maintain multiple versions).

A big problem for me was with passing/generating the preambles for MathJax/KaTeX. Even writing in Obsidian itself and using plugins like LaTex Suite had the problem of not allowing for enough flexibility in dispatching which preambles or macros you want to use.

The closest to Nirvana I came with Org-Mode. You write content once, use their literate programming techniques (see also Org Babel) to weave together the necessary preambles to export to pdf and html. But this had some drawbacks

  • You need to use Emacs/Lisp (For some people, this would a huge plus but broader society isn’t ready for this yet)
  • It’s relatively hard to set everything up. It’s a skill issue to some degree for sure, but I take the small quantity of sites similar to mine as evidence that it is indeed difficult.

I also saw people have quite a bit of success using Pandoc. They would essentially write their content in Markdown and write custom processors that transform them to pdf and html - something that I spent a long time trying to get it to behave as I wanted it to, but never achieved anything that was comfortable to use.

Typst and Typst-Mate

A big improvement came with Typst Plugins for Obsidian. The (now no longer maintained) Typst Renderer Plugin made it possible to include arbitrary packages in your preamble by using an actual Typst compiler.

The processor dispatch mechanism however made it hard to customize which preamble was used. My preamble grew larger and larger which came with stability issues. If something broke in one end, all of my math rendering would break and I had to frequently debug my 600+ line preamble to get things right.

Earlier this year, I came across the Typst Mate plugin, which made it possible to conveniently include preambles by looking at the tags of the file. If a file has the physics tag, it will include the physics.typ file which means I can keep my preambles lean and only include what I need when I need it.

Typst mate also made exporting to PDF much nicer to deal with and this just left me with the problem of hosting the content on the web. I tried many options: Hugo, Jekyll, Obsidian Publish and even MediaWiki, but they felt very opaque and hard to reconcile with my setup (or cost $8/month to host).

Quartz, a self-hostable alternative to Obsidian Publish, looked very promising and I submitted some PRs to their latex plugin to add typst support (which eventually got added by the maintainer without crediting me :(). Despite the experimental typst support, I never got around to using it since it didn’t have all of the features I wanted.

Quartz Typst Mate

The feature set of Typst Mate gave me enough motivation to start this project by showing that it is possible to have nice things, which led to the development of the qtypst-mate plugin.

For a breakdown of how the plugin works, check out Quartz Typst Mate Plugin Internals.

Tutorial

The tutorial is written for a less tech-savvy audience. If you do not require this level of detail, just check the instructions from the plugin repo.

Prerequisites

To set everything up, you will need:

  • A computer that can run 24/7 (or a VPS)
  • A Domain Name If you know me personally and don’t have these things, feel free to reach out.

Project Structure

Relevant directories

  • /etc/nginx: configuration site for your web page
  • /var/www/example.org: where your server will serve files from
  • ~/vault/: location of your obsidian vault
  • ~/vault/pub/typstmate/tags/: place to put .typ preambles.
  • ~/quartz/

Setup your vault

# /etc/nginx/sites-available/example.org
server {
	listen 80;
	listen [::]:80;
    server_name example.org www.example.org;
    root /var/www/example.org/;
    index index.html;
    location / {
        try_files $uri $uri/ $uri.html =404;
    }
}
ln -sf /etc/nginx/sites-available/example.org /etc/nginx/sites-enabled/
sudo nginx -s reload

Install quartz and the plugin

git clone https://github.com/jackyzha0/quartz.git ~/quartz && cd ~/quartz

npm i
npx quartz plugin add github:kimhanm/qtypst-mate

npx quartz plugin install

Build the files

npx quartz build -d ~/vault/pub -o /var/www/example.org/

In order to rebuild the vault whenever you push new versions (from your local machine to the server), you can use git’s hooks:

mkdir ~/vault && cd ~/vault 

git init
nano ~/vault/.git/hooks/post-receive

Content of .git/hooks/post-receive

#!/bin/bash

echo "rebuilding Quartz ..."

cd ~/quartz
npx quartz build -d ~/vault/pub/ -o /var/www/example.org/

make it executable

sudo chmod a+x ~/vault/.git/hooks/post-receive