(This is a guest post kindly contributed by the team at NETWAYS.)

Learn how NETWAYS streamlined their training documentation workflow by migrating from Markdown and HTML to Typst, enabling them to generate slides, handouts, and exercise solutions from a single source while maintaining professional styling and cross-platform consistency.

At NETWAYS, we offer a variety of training courses for open-source software. For every course, attendees receive several documents with additional information on the topic, as well as exercises and their respective solutions. Furthermore, the trainers conduct the courses over several days with slides. In this article, we want to show how we modernized all of these documents using Typst.

First, let's have a brief overview of our requirements. We want slides, handouts, exercises and solutions to be rendered from the same source. Having the same source helps us prevent the different documents from diverging when new content is created, as synchronizing multiple sources or tools is prone to errors. This also means we have different requirements for the shape and appearance of the documents that need to be handled. For example, the slides are mainly composed of bullet points to guide the course; in contrast, the handouts need to be more detailed and self-contained documents. Additionally, a range of people teach these courses, so we require tools that are easy to use and consistent across multiple machines. And finally, styling these documents should be flexible and provide a sharp look.

Why Typst

Our previous solution was obviously functional; however, there were limitations that we could no longer work with. That solution was Markdown and HTML-based, which works well for slides, albeit rendering handouts and exercise documents always being a struggle. Typesetting was never optimal for us: design options were limited, and the generated table of contents was often counterproductive, as it was based solely on the slide titles. So, we set out to find a new solution. Most of the tools out there are designed to either render slides or handouts, not both. Obviously, LaTeX was one of the contenders, but we decided against it due to its poor usability. In the end, we decided to use Typst!

Typst offered us a great balance between a simple-to-learn markup language and very flexible typesetting. Together with the possibility of creating custom modules, we were ready to address our requirements. In the following section, we will take a closer look at how we did that.

Our Typst Module

As described, each course contains three artefacts: slides, handouts, and solutions for the exercises. These artefacts share some of their content and parts of their structure; for example, the exercises require the same identifier in the handout and the solution. Other parts differ significantly across these documents.

What we wanted was to have a single Typst code base that can compile into different artefacts. We solved this by using the compiler's --input flag to pass the desired artefact type during compilation. This parameter is then used inside a custom Typst module, in which we bundle our logic. For example, typst compile --input mode=slide training.typ renders the slides in "presentation-16-9" aspect ratio, --input mode=handout the handout in "a4". Now, we are able to control what shows up in which artefact and how it is formatted. Additionally, for formatting the slides and handouts, we use the very good Polylux package from the public Typst Universe.

Inside our module, we categorize content via functions: a key function being the slide(title: [], slide-only: [], handout-only: [], common: [], notes: []) function. So, we still use a slide as a unit but are now able to differentiate content categories, which helps us during compilation.

#slide(
  title: "Example",
  common: [
    I am a common element.
  ],
  slide-only: [
    Just on the slides please.
  ],
  handout-only: [
    Only for the handout.
  ],
)

Since Typst is just good old plain text, we can manage all of these with Git, where every course has its own repository. Our module can then simply be included via a submodule or subtree—which which incurs a bit of overhead—yet we're happy with having each course as a self-contained unit. Finally, thanks to the statically compiled Typst executable, incorporating them into our automated pipelines was quite simple.

The Typst team's decision to use plain text is a boon that, in a world of proprietary formats and vendor lock-in, needs to be appreciated. Nonetheless, IT people still have their grievances about how plain text should be formatted, but let's not delve into that topic now. We like that everyone can use the editor of their choice to write Typst and that there's already an existing ecosystem (e.g. LSP servers).

Summary

In summary, the migration to Typst was very pleasant, and we're currently optimistic that it is a future-proof solution. We now have greater flexibility for our training course material with a justifiable increase in complexity. A big thanks to the Typst team for all the hard work, the great documentation and all the little details that result in an enjoyable product.