TreeBlood: Beautiful Math on the Web

TreeBlood Is the fastest L A T E X \LaTeX to MathML compiler that exists. Written in pure Go, it outperforms MathJax by over 1000 times in terms of raw speed. To try it out, simply enter a L A T E X \LaTeX expression in the box below. To see TreeBlood in action in the wild, browse around my blog for a while. All math on my website is rendered by TreeBlood via a goldmark extension.

Live Demo

Why TreeBlood?

MathML is an Open Standard

Since Chromium’s implementation of MathML Core in 2023, all major browsers now support MathML, making it a viable option. Documents produced by TreeBlood will remain intelligible for as long as open standards are respected. Unlike JavaScript rendering done by MathJax or KaTeX, native MathML (ideally) does not require any post-processing; rather, it is a native part of the document and will immediately be recognized and rendered as such by the viewing software.

While all major browsers now support MathML, the chromium family has the worst support. Though I have implemented some shims and bodges with CSS (see _resources/chromium-shims.css), there are still many unsupported features. The best course of action for the present, then is to use a JavaScript typesetting library to post-process MathML. This will not only preserve the source of the file, but also make page reflows have less impact since the bulk of the formatting will already be computed by the browser, with MathJax only making minor tweaks.

With EPUB 3.0, MathML has been added to the specification. EPUB readers may have limited scripting functionality, so having precompiled MathML in the source document is a clear benefit.

TreeBlood is 1000 times faster than MathJax

TreeBlood is written in Go with a hand-rolled finite state automaton for lexing. In normal use, TreeBlood can process over 8000 characters of L A T E X \LaTeX input per millisecond. This speed includes the amount of time taken to write the corresponding MathML data to a string. Shorter input strings will have a smaller throughput due to constant-time overhead, but still have a smaller absolute run time. I have only encountered a handful of inputs that regularly take more than 100 microseconds (one tenth of a millisecond) on my machine.

TreeBlood has no external dependencies

Web development is plagued by pulling dozens (sometimes thousands) of third-party dependencies for even small projects. The security implications (and functional implications - remember leftpad?) of this practice should be immediately apparent. I have been using MathJax on my infrequently updated personal site for years, and it has been working for years without modification. I used the boilerplate recommended by the official MathJax website to get everything working and then promptly forgot about it. Until mid-2024 when I found out about the polyfill.io supply chain attack, but I was unfortunately a few months behind the times. It had been so long since I had done anything with the MathJax configuration that I had completely forgotten that it was using the compromised polyfill CDN, and I only noticed it by coincidence.

I do not have any deep love for JavaScript and use it only grudgingly. This latest vulnerability crystallized my motivation to finally tackle server-side L A T E X \LaTeX rendering.

Oh you mean the name?

The Maya were the first people to master both latex and mathematics. They developed sophisticated mathematics (including the concept of zero) to facilitate astronomy and timekeeping (and everything else a civilization may calculate). Latex was used in the production of rubber balls for the sacred Mesoamerican Ballgame (called pitz in Classic Maya).

Latex was significant enough in Mayan culture to share its name with that of blood, Ch’ich’. The original name was to be a rough translation of the phrase “latex writing,” but most English speakers would struggle to both pronounce and remember Ch’ich’ Tz’ihb, so TreeBlood it is!

Goals

Differences from L A T E X \LaTeX

While the aim is to be as close as possible to L A T E X \LaTeX , there are a few deviations made for the sake of easier parsing

Command arguments

L A T E X \LaTeX commands are typically given parameters in {curly braces}, but this is not a requirement. If no curly braces are present, the next non-reserved character will be used. For example, \frac12 renders the same as \frac{1}{2}. I hate this. ALL parameters must either be {enclosed in curly braces} or separated by whitespace.

Resources

Tags