Templates and build scripts for writing good-looking teaching documents for the ISC curricula. Exams and exercise series are authored in LaTeX on top of Philip Hirschorn's exam class, heavily tailored for ISC; labs are authored in GitHub-flavoured Markdown and rendered through pandoc to PDF — with LaTeX or, since 1.3.0, with Typst — and to standalone HTML.
Have fun teaching 💻 Pierre-André
| Lab as PDF | Lab as HTML |
|---|---|
![]() |
![]() |
Ready-made samples live in ./samples: a written exam and its solution, a series of exercises and its solution, a lab rendered with LaTeX and with Typst, and a lab as HTML.
- Exams that count themselves — the point total, the scale and the solution document are all derived from the same
.texsource - Labs in Markdown — GFM in, PDF out, with YAML front-matter variables forwarded to the template for titles, authors and course metadata
- Two renderers, one source — the very same
.mdfeedsxelatexand Typst, so you can switch engine with a single flag - Typst preview renderer — 0.8 s per lab against 4.9 s with
xelatex, and error messages you can actually read - Standalone HTML output — a single self-contained file, KaTeX included, several themes available
- Batch builds —
build_all.shwalks every lab directory and uses GNUparallelwhen it is installed
# Exams and series: run the build script next to the .tex source.
# It produces both the student hand-in and the solution.
cd samples/sample_written_exam && ./build.sh
# Labs: run the toolchain from the directory holding your Markdown file
~/build_tool/build_pandoc.sh -n lab-expressions.md
# With no file given, the first .md of the directory is compiled
~/build_tool/build_pandoc.sh
# Same lab, rendered with Typst instead of LaTeX
~/build_tool/build_pandoc.sh --typst
# Every lab directory at once, in parallel
~/build_tool/build_all.shClone the repository anywhere in your filesystem; the examples above assume the toolchain ended up in ~/build_tool/.
Not really a toolchain, rather a set of LaTeX files and scripts building on the exam class. The general look-and-feel has been tailored for the ISC programme, and a number of things have been adapted to the context of computer science. The shared template files live in ./texcommon.
The only prerequisite is a reasonably recent LaTeX installation and a Linux box for the build script. Compiling the samples elsewhere works, but you are on your own.
Two samples are provided: one exam and one series of exercises, each a xxx-sample.tex compiled by the build.sh sitting next to it. The script produces both the solution and the hand-in document.
The logo files are duplicated across the two toolchains. Yes, it is ugly. It is intended.
Because exams and exercises are built out of categorised questions (MCQs, true/false, long questions), they need a granularity that only LaTeX gives. Labs have no such need — no solution to hand in, no points to count — so they are described in Markdown and converted by pandoc. Previewing and editing stay straightforward, and the result is still a proper ISC document.
pandoc ≥ 3.9 |
required. The Typst template targets the writer of pandoc 3.6 and later, which dropped the definitions.typst data template that older templates included; 3.9 is the version the templates are tested against. build_pandoc.sh and build_typst.sh refuse to run on an older pandoc rather than failing later with a puzzling Could not find data file (build_html.sh is not guarded) |
xelatex |
for the LaTeX renderer (lualatex / pdflatex are used as fallbacks) |
typst |
for the Typst renderer, tested with 0.15.1 |
ghostscript |
optional, repacks the Typst PDF; skipped when absent |
| Fonts | Source Sans 3 and Fira Mono must be visible to typst — typst fonts lists what it sees, and ~/.local/share/fonts is enough. New Computer Modern Math ships with typst and needs no install |
Watch the fonts. Typst does not fail on a missing font: it prints
warning: unknown font family: ...and silently falls back to a serif, which is easy to miss in the build output and ends up in a PDF you commit. If a rebuild suddenly looks different, checktypst fontsfirst.
The md → pdf conversion uses a LaTeX template derived from Wandmalfarbe's; HTML goes through github.html5, itself picked over easy-pandoc-templates after some experimenting with its side TOC.
pandoc— parses the GFM source and applies the Lua filters in./build_tool/lua_filters(callouts, metadata variables, colours, TODO replacement)- Template —
isc_lab.texorisc_lab.typreceives the YAML front-matter variables and lays the document out - Engine —
xelatex(default),typst, or neither for the HTML path ghostscript— repacks the Typst PDF when available, and is skipped when it is not
flowchart TD
A["📄 lab.md"] -->|pandoc + lua filters| B["📝 isc_lab.tex"]
A -->|pandoc + typst-compat.lua| C["📝 lab.typ"]
A -->|pandoc + github.html5| G["🌐 lab.html"]
B -->|xelatex| D["📑 lab.pdf"]
C -->|typst compile| E["📑 lab-typst.pdf"]
E -->|ghostscript| F["📦 lab-typst.pdf, repacked"]
The script options are -i FILE (input), -n DIR (working directory), -o DEST (copy the PDF somewhere), -t (oral exam template), -e ENGINE (LaTeX engine), --typst / -y (hand over to Typst). Anything else is forwarded to pandoc untouched. Without -e, xelatex is used when available, otherwise the first of lualatex / pdflatex found on the system.
Since version 1.3.0, labs can also be rendered with Typst instead of LaTeX. This is a preview feature: the LaTeX template remains the reference and is not going anywhere.
~/build_tool/build_pandoc.sh --typst # -y works too
~/build_tool/build_typst.sh # same thing, called directly
~/build_tool/build_all.sh --typst # the whole batchTypst does not produce smaller files: it embeds a full subset per font, so its PDF comes out about three times heavier than the LaTeX one. If ghostscript is installed, the build repacks the file and brings it back in line (290 kB down to 100 kB on the sample); if it is not, the step is skipped and the PDF is simply bigger. --no-compress turns it off.
An intermediate .typ file is written next to the Markdown and kept on purpose: it is what you need to debug a layout problem, and typst compile --watch lab.typ gives a sub-second edit loop. Add *.typ to your .gitignore, or pass -c to build_typst.sh to have it removed.
The whole point being visual parity, there is a tool for it:
~/build_tool/compareEngines.sh lab-expressions.mdIt renders the same source with both engines and writes one PNG per page, LaTeX on the left and Typst on the right, along with the two page counts. Spacing differences are invisible in the sources: you have to look at the pages.
Ported, in ./build_tool/typst/isc_lab.typ: page geometry, fonts, headers and footers, headings with their rules, framed listings with line numbers, booktabs tables, captions, block quotes and the callout boxes (::: info, ::: warning, ::: checkout, closed by a bare :::, with the default title replaceable through ::: {.warning title="..."}). The sample lab uses all three. The spacing is calibrated against the LaTeX output, measured rather than eyeballed.
Not ported: the oral exam template, and toolchain 1 for exams and series, which does not go through pandoc at all.
Known differences:
- A
\newpageat the end of a list item is dropped, Typst forbidding a page break inside a container. One at the end of a paragraph works fine. - Syntax highlighting uses Typst's own engine, so token colours are close to, but not identical to, the
lstlistingpalette. - A level-2 heading placed directly under a level-1 one gets slightly more air than in LaTeX, which collapses the spacing of consecutive titles.
Raw LaTeX in the Markdown is translated where an equivalent exists (\newpage, \vspace, \label, \ref); anything else is dropped, so do check the result if your source leans on LaTeX commands.
HTML goes through pandoc as well, and the output is a single self-contained file. Several themes are embedded in ./build_tool/html_templates; the results are not perfect yet, but they work. Go to ./samples/sample_lab_html and run the .sh files to see for yourself.
For continuous rebuilds while writing, build_html_continuous.sh relies on filewatcher:
gem install filewatcher filewatcher-cli
./build_html.shScreenshots are what make a lab heavy, and they are worth quantizing before anything else. From the figs directory of your lab:
pngquant --quality 50-80 *.png --ext .png --forceCareful, this rewrites the files in place, so commit them first or work on a copy. On a set of 16 real lab screenshots the gain was 68% (7.9 MB down to 2.5 MB), for a loss invisible at the size a figure is printed. This is why the build scripts do not do it for you: it touches your sources, not the output.
The toolchain is tested on Debian-based distributions (Ubuntu on WSL2, native Debian) and on macOS. The table below lists every binary the build scripts call. MacPorts works just as well as Homebrew — port install <pkg> for the same package names.
| Tool | Required for | Linux (Debian/Ubuntu) | macOS (Homebrew) |
|---|---|---|---|
| pandoc | Markdown → PDF and HTML | GitHub release .deb (do not use apt, its packages are outdated) |
brew install pandoc |
| TeX Live | every LaTeX document, exams included | apt install texlive-full |
port install texlive-latex texlive-latex-extra |
| librsvg | SVG figures and logos | apt install librsvg2-bin |
brew install librsvg |
| GNU parallel | batch builds with build_all.sh |
apt install parallel |
brew install parallel |
| rename | batch builds | apt install rename |
brew install rename |
| typst | the Typst preview renderer | GitHub release, or cargo install --locked typst-cli |
brew install typst |
| ghostscript | optional — repacking the Typst PDF | apt install ghostscript |
brew install ghostscript |
| pngquant | optional — quantizing figures | apt install pngquant |
brew install pngquant |
| poppler-utils | compareEngines.sh (pdftoppm) |
apt install poppler-utils |
brew install poppler |
| filewatcher | optional — continuous HTML rebuilds | gem install filewatcher filewatcher-cli |
gem install filewatcher filewatcher-cli |
Unifying the two toolchains behind a Markdown extension able to categorise questions and answers is the plan, so that exams and series stop needing hand-written LaTeX. This remains work-in-progress — contributions welcome. Oral exams have a template but no sample yet.
If you need help installing or running the tools, get in touch with the maintainer, open an issue, or send a PR.
Copyright © 2023–2026 P.-A. Mudry / ISC — HES-SO Valais. This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.
You are free to share and adapt the material for non-commercial purposes, as long as you give appropriate credit and distribute your contributions under the same licence.
Made with ♥ by mui, 2026

