Using KaTeX with Hakyll

Posted on August 6, 2015

When Khan Academy initially released KaTeX 0.1.0 last year I was overjoyed. The performance comparison against MathJax was impressive and realistically the only reason MathJax has ever needed competition. For those interested in seeing the difference first hand, IntMath has a decent test suite.

After looking under the hood though I could see my work was going to be cut out for me if I wanted to incorporate it into this blog. Unlike MathJax, which scanned the document.body and rendered math elements (indicated via \[ ... \] tags) on the fly, KaTeX required the following syntax:

katex.render("c = \\pm\\sqrt{a^2 + b^2}", element);

Not really a problem in general, although it was obvious for my case I’d have to write some form of math parser for the markdown portion of Hakyll. Still being quite the Haskell neophyte, this became something for the too hard basket. Maybe I also rationalised the decision not to work on a solution due to the very restricted subset of LaTeX features implemented at the time. I mean, not that I ever do much with relational algebra, but the natural join operator (aka the bowtie: \(\bowtie\)) wasn’t introducted until v0.2.0. How am I supposed to make a fancy outfit for my mathematical symbol cat illustrations without a bowtie?

Fast forward a year and KaTeX has matured immensely, and is currently at v0.5.0. The feature list is much more expansive, and the only gripes I really have are the missing environments like \align and the font modifers \mathrm, \mathbf, \mathcal etc. However, it looks like these will all be part of the next release according to the status of this pull request.

My personal saviour was introduced in v0.3.0 by the way of the auto-render extension which acts in a similar fashion to the MathJax implementation and scans for $$ ... $$, \[ ... \] and \( ... \) tags. The first two tags indicate the display size environment whereas the last tag is for inline maths.

Luckily, you can configure Pandoc such that Hakyll parses the single $ ... $ tag in markdown and renders it as \( ... \) for use with MathJax. Travis Athougies has a good writeup on how to do this on his blog here, although I overload my pandoc options a little different so that Pygments can be used to do the syntax highlighting on my blog (see my Pandoc.hs):

readerOpts :: ReaderOptions
readerOpts =
    let extensions =
        S.fromList [ Ext_tex_math_dollars
                              , Ext_inline_code_attributes
                              , Ext_abbreviations
    in def { readerSmart = True
                , readerExtensions = S.union extensions (writerExtensions def)

writerOpts :: WriterOptions
writerOpts = def { writerHTMLMathMethod = MathJax ""
                                  , writerHighlight = False
                                  , writerHtml5 = True

So to get KaTex working from this starting point, we just need to build a maths context

import qualified Data.Map as M

mathCtx :: Context a
mathCtx = field "katex" $ \item -> do
    metadata <- getMetadata $ itemIdentifier item
    return $ if "katex" `M.member` metadata
                            then "<link rel=\"stylesheet\" href=\"/css/katex.min.css\">\n\
                                      \<script type=\"text/javascript\" src=\"/js/katex.min.js\"></script>\n\
                                      \<script src=\"/js/auto-render.min.js\"></script>"
                            else ""

and apply it to any template where the context is needed. For me, that’s:

loadAndApplyTemplate "templates/default.html" (mathCtx `mappend` postCtx) full
--- ... ---
>>= loadAndApplyTemplate "templates/default.html" (mathCtx `mappend` indexCtx)

which you can checkout properly in my site.hs. The reason I do it this way rather than just calling the stylesheet and .js files in default.html is to keep the site as lean as possible. Sure, I have some fancy things going on in the header etc. but I’m not pulling in jQuery or some other large library for no good reason, and there’s no good reason to load KaTeX on every page when only a few places will ever need it.

So I have a katex field which, if activated in the preamble of a post (for instance, see the markdown of this entry here), pumps in the return result of the katex field above into default.html (full source here) and calls the auto-renderer.

$if(katex)$ $katex$ $endif$
<!-- ... -->

With all that in place, embedding maths into posts is essentially trivial, cross platform and most importantly seemless. As an example, heres a short discussion about some of my recent work using just the $ ... $ inline and $$ ... $$ display tags in markdown.

Wick rotations are primarily used to find solutions to Minkowski space problems by an Euclidean space mapping. We can also use the rotation to evolve a time-dependent Schrödinger equation and solve for time-independent solutions in three dimensions. To do so we transfer our TDSE into an imaginary time basis \(t=i\tau\):

\[i \hbar \frac{\partial}{\partial t}\Psi(\vec{r},t) = H\Psi(\vec{r},t) \Rightarrow - \hbar \frac{\partial}{\partial \tau}\Psi(\vec{r},\tau) = H\Psi(\vec{r},\tau)\]

which yields a general solution to the wavefunctions

\[\Psi(\vec{r},\tau) = \sum_{k=0}^\infty a_k\psi_k(\vec{r})e^{-E_k \tau}.\]

Using the Gram-Schmidt orthoganilsation procedure, higher order orthogonal eigenfunctions can be found by projecting a guess along the lower states. For example

\[\lvert\tilde{\psi^\prime_1}\rangle = \lvert\psi^\prime_1\rangle-\lvert\psi_0\rangle\langle\psi_0\vert\psi^\prime_1\rangle,\]

which can even identify eigenfunctions within a degenerate subspace, as each state is chosen to be orthogonal to the systems’ basis.


Generating a Publication List From Mulitple ORCiDs

A website for my research group outside of the bounds of our abysmal university web restrictions has been discussed for quite some time. It’s genesis has only really started recently though, because I’ve had too many other things on my plate and no-one else has any decent web capability. Whilst I’d much prefer to use a simple static site tool or code something completely from scratch, the other members of my team really need something a bit more point and click. Plus, I’ll be leaving the group soon so it’s in their best interest ...

Continue Reading »

Makefiles Revisited

Writing a thesis. Writing at home, writing at uni, at work, on planes, on machines half way across the planet with Swedish keyboards attached to them. The amount of computers that have my git repository cloned on it is either impressive or terrifying depending on how you look at it. One positive thing about my tree is that a good 90-95% of my ridiculous figure count has been built in Tikz / PGFPlots. Totally source control friendly, small and portable.

What hasn’t been that nice about it ...

Continue Reading »