Integrating Tools and Assets

Otter Docs doesn’t have macros since Typst doesn’t have macros. It is hard to achieve mdBook style preprocessors. However, there are a few ways you can integrate foreign tools and assets in your documentation.

There are a couple of scenarios where you might want to integrate other tools and assets, for example, showing a copy of a file in the docs, displaying an interactive editor, or demonstrating the result of a program. Most of them are doable with Typst’s capabilities, and some require specific workarounds.

Reading and Processing Files

Typst provides native syntax for reading files. Specifically, there are these functions and keywords:

#read(<path>, encoding: <encoding>) Read a file’s content using the encoding specified. The <encoding> defaults to UTF-8, and the read function would return a string when the encoding is specified. Use encoding: none for reading and returning raw bytes.
#include "<filename>" Include and evaluate the content of a Typst .typ file. Unlike C/C++‘s #include, this is scoped.
#raw(block: <boolean>, lang: <code-language>, <content>) Display a string as code block. Use block: true for block-level code, and specify in the lang field. (e.g. "C++" for C++, and "rust" for Rust.)
#eval(mode: <evaluation-mode>, <content>) Evaluate the <content> as Typst code using the <evaluation-mode> specified.
#cbor(..) Functions for reading and processing data files. Those functions would return structured data. You can use the structured data and spread them into a table, evaluate them, or plot them. See https://typst.app/docs/reference/data-loading/ for details.
#csv(..)
#json(..)
#toml(..)
#xml(..)
#yaml(..)

A few examples include #table(columns: 3, ..csv("my_file.csv").flatten()) for reading records and displaying them and #raw(block: true, lang: "rust", read("my_file.rs")) for reading content from a Rust file in your project’s source code.

Embedding JavaScript

JavaScript is used for interactivity. Although Otter Docs ships no client-side JS by default, you can still embed JS yourself. The following is an example of how to embed an editor in the document:

// This uses tailwind
#html.div(id: "editor", class: "w-full h-40 border border-neutral-300")
#html.script(
  type: "module",
  {
    // This is the script used to setup the editor.
    // The editor is the Ace editor. See `https://ace.c9.io/` for detailsa
    let script-text = ```js
    import ace from "https://cdn.jsdelivr.net/npm/ace-builds@1/+esm";

    var editor = ace.edit("editor");
    editor.setTheme("ace/theme/monokai");
    editor.session.setMode("ace/mode/javascript");
    ```.text
    script-text + "\n" + "editor.setValue(`" + script-text + "`)"
  },
)

For the editor example specifically, you can even combine it with one of the many Typst packages that contains WebAssembly. For example, reading the content inside the editor then compiling it. In this case, you would have to write the glue yourself.