Can I configure my document (e.g. draft/release version, color theme) when creating a PDF without modifying the Typst file directly?

Basically, are there ways to to create multiple structurally similar PDFs from the same Typst document, by configuring it in some way? Use cases that come to mind:

  • draft version (with watermark, comments, …) vs. release version
  • different themes, e.g. light/dark, serif/sans
  • exam and solution sheets
  • slides, handout, and speaker notes
  • rendering different data, serial letter style

Is there a mechanism that lets one achieve that without having to modify the input Typst document itself?

2 Likes

You can use system.inputs (System Functions – Typst Documentation) to get the command-line inputs at compile time, and then check for the presence of specific inputs to define the document style in different ways.

There absolutely is: the sys.inputs dictionary contains values that have been set from the command line, via the --input key=value syntax. To my knowledge, the web app currently doesn’t have a way to put values into that dictionary, so be aware of that.

It’s often useful to have default values for these parameters, and check whether values are valid. Let’s say you want to assume --input theme=light and --input solutions=false, you could process the sys.inputs dictionary like this:

let theme = {
  let valid-values = ("light", "dark")
  let value = sys.inputs.at("theme", default: "light")
  assert(value in valid-values, message: "`--input theme` must be light or dark")
  value
}

let solutions = {
  let valid-values = ("true": true, "false": false)
  let value = sys.inputs.at("solutions", default: "false")
  assert(value in valid-values, message: "`--input solutions` must be true or false")
  valid-values.at(value)
}

Using this code, theme will be a string value (default "light") and solutions will be a boolean value (default false).

For more complex data input needs, using one of the data loading functions is probably the best idea:

  • directly in the command line: --input 'data={"some-num": 1, "some-bool": true}' (this syntax may need some tweaking for your shell, e.g. for Windows’ cmd)
    then read via json(bytes(sys.inputs.data))
  • in a separate file: --input 'file=data.json'
    then read via json(sys.inputs.file)
    For this to work, the file must be accessible to Typst, i.e. it must be in the Typst root directory. By default, that is the directory where the main Typst file you’re processing is located.

(JSON is of course just one option for a data format that can be read like this.)

7 Likes

For windows, there are two things that need to be different to take in JSON data from the command line (for those who were lost like me).

  1. cmd doesn’t have strong quotation using single quotes, so we have to escape double quotes like this: --input "data={\"some-num\": 1, \"some-bool\": true}"
  2. For typst 0.13.1, it says that json.decode() is deprecated, but not using it and passing the data directly to the json function json(sys.inputs.data) results in this error:
error: failed to load file (The filename, directory name, or volume label syntax is incorrect. (os error 123))
   ┌─ \\?\C:\Users\<redacted>\Desktop\typst\testing\test.typ:11:14
   │
11 │ #let d = json(sys.inputs.data)
   │

So, just using json.decode() works fine.

1 Like
  1. with cmd you can also use double double quotes, is IMO a bit more readable: --input "data={""some-num"": 1, ""some-bool"": true}"
  2. The correct syntax for 0.13.1 is json(bytes(...))
1 Like

thanks for pointing out the updates, I have incorporated both your comments into my answer!