Typst

  1. Why not Latex?
  2. How
  3. Rewriting
  4. Multi-row table items
  5. Comparing with the original
  6. Size issues

Turns out Typst is a decent project as a Latex drop-in replacement, at least for small files.

§ Why not Latex?

A lot of dependencies: needed packages for an ordinary document span around 1GB in the distribution. Tinytex is slightly better but still wants 300MB. It’s okay when you think that Latex is a one-size-fits-all bells and whistles typographic system. But I don’t need all these. I want something small, because I don’t really depend on Latex and don’t want it to pollute my system backups.

Also, recompilation isn’t instant. I want things to work fast as computers are fast nowadays.

§ How

Download Typst compiler (36Mb). Add support for Vim if you use Vim:

au BufWritePost *.typ ++once sil! call jobstart(['typst', 'w', '--open', 'open', expand('<afile>')])

(on first file write this will start typst compiler in incremental mode and open compiled PDF in your favourite reader, zathura in my case)

If you want something fancy, use the plugin.

Draw the rest of the owl i.e. rewrite some document.

§ Rewriting

CV (source) looks like a good candidate for rewriting. Except for ordinary text and lists, I use a bit of styling which converts easily:

  • Page margins
\usepackage[bottom=0pt, top=5pt, left=5pt, right=5pt]{geometry}
#set page(margin: (top: 10pt, bottom: 0pt, x: 14pt))
  • Bullet list tweaks
\usepackage{enumitem}
\setlist[itemize]{leftmargin=1em, topsep=1pt, itemsep=1pt, parsep=1pt}
#set list(indent: 1em, body-indent: 1em)
  • Section underlining and font tweaks
\newcommand{\lineunder} { \vspace*{-8pt} \\ \hrulefill \\ }
\newcommand{\header} [1] { {\hspace*{-4pt}\vspace*{6pt} \textsc{#1}} \vspace*{-6pt} \lineunder }
\header{Experience}
#show heading: it => {
  set text(10pt, weight: "regular")
  pad(top: -5pt, bottom: -10pt, smallcaps(it.body))
  line(length: 100%, stroke: .5pt)
}
= Experience
  • URL embedding (press the URL and it opens in a web browser)
\usepackage{hyperref}
\url{https://foo.bar}, \href{mailto:foo@bar.baz}{email}
#show link: it => text(font: "New Computer Modern Mono", it)
https://foo.bar, link("mailto:foo@bar.baz")

Some differences spotted:

  • You can style each section heading in a neat way, so you can make all headings first level (useless in Latex as you need to type the macro in any case)
  • Bullet lists are same as Markdown
  • No manual line breaks are needed
  • Typst doesn’t have predefined font sizes like \Huge, so you need to specify manual size i.e. 24.88pt.
  • Typst doesn’t have monospace fonts, and the default font isn’t that appealing, so you can change it to Latex’s New Computer Modern.

§ Multi-row table items

When I started writing this article, Typst didn’t have inbuilt support for table items spanning multiple rows or columns (there was a workaround). In CV’s header there should be a three column table, first one occupied by my name. The trick is, name should span two rows. In order to ensure correct row handling, each one had to be set manually.

#align(center, grid(columns: 3, gutter: 20pt,
  text(24.88pt, smallcaps[Mike Kot]),
  align(left, stack(spacing: 4pt, link("mailto:to-job@myrrc.dev"), [https://myrrc.dev])),
  align(left, stack(spacing: 4pt, [https://github.com/myrrc], [https://sr.ht/~myrrc]))
))

Now you can do it with tables (not much of a difference visually)

#align(center, table(columns: 3, stroke: none, inset: 2pt, column-gutter: 15pt, align: (center, left, left),
  table.cell(rowspan: 2, text(24.88pt, smallcaps[Mike Kot])),
  link("mailto:to-job@myrrc.dev"), [https://github.com/myrrc],
  [https://myrrc.dev], [https://sr.ht/~myrrc])
)

§ Comparing with the original

The new file is rendered, and it looks the same … More or less. Now it’s time to ensure it looks and feels exactly like the origin.

Here’s how you can compare files visually using ImageMagick in case you need 1:1 correspondence:

convert -density 300 $1 -background white -alpha remove $1.png &> /dev/null &
convert -density 300 $2 -background white -alpha remove $2.png &> /dev/null &
wait
compare -metric AE -fuzz 10% $1.png $2.png diff.png
rm $1.png $2.png

./compare 1.pdf 2.pdf will create a red map of differences between files looking like this Difference map

Just in case, you can preview the file in terminal (if it supports sixel) with

compare -metric AE -fuzz 10% $1.png $2.png - 2>/dev/null | img2sixel

Now it’s time to dig deeper. CVs are usually parsed automatically by an ATS like Greenhouse or Workday. Such systems predominantly get parsed text from PDF. I’ve heard some awkward ones may first perform an OCR but let’s pretend they don’t.

So you just need to check output of gs -sDEVICE=txtwrite -o - cv.pdf.

Not a very fun fact: in early CV versions there was a link bug which caused my work email to be parsed as to-job@myrrc.devhttps. Guess I lost some invitations due to that.

§ Size issues

This is Typst’s downside – by default, generated files are way bigger (152Kb vs 76Kb for Latex). Hopefully, this also can be solved using Ghostscript and qpdf.

mv cv.pdf tmp
gs -sDEVICE=pdfwrite -dCompatibilityLevel=1.6 -dPDFSETTINGS=/default \
  -dNOPAUSE -dQUIET -dBATCH -dCompressFonts=true -r150 -sOutputFile=tmp2 tmp
qpdf --compress-streams=y --object-streams=generate tmp2 cv.pdf
rm tmp*

First one reduces size to 89Kb, second one gets it to 85Kb.