Typst: render a Document as a PDF with citations
The add-on @skaile/forge-editor-typst adds one render target, typst-pdf. It turns a whole Document, or one Typed block of the Block type paper, into a PDF made by Typst. The Cite nodes of the content become citations, and the Bibliographic records inside the content become the bibliography.
The add-on is server-side only. It needs no editor feature: the block action „Erzeugen als …“ and the command „Dokument erzeugen als …“ list every target of the render capability, this one among them.
Install and wire
import { createRenderer, markdownTarget } from '@skaile/forge-editor/adapters/render'
import { typstTarget } from '@skaile/forge-editor-typst'
// installEditorServer({ ports: { render } })
export const render = createRenderer([markdownTarget(), typstTarget({ style: 'apa', locale: 'de' })])
Option of typstTarget | Meaning |
|---|---|
style | citation style when the render names none: one of CSL_STYLES, default apa |
locale | language of the PDF (hyphenation, the bibliography title) and of the error messages: de (default) or en |
label | the name in the export menu (default PDF (Typst)) |
accepts | Block types accepted besides 'document' (default ['paper']) |
compile | { engine?: 'auto' | 'node' | 'binary', binary?: string }, see below |
A render input picks the style per request: options: { style: 'ieee' }.
The compiler
compileTypst tries two engines in this order:
- The native compiler
@myriaddreamin/typst-ts-node-compiler, an optional dependency of the add-on. It runs inside the server process; notypstprogram is needed. The compile is synchronous and blocks the event loop while it runs. - The
typstprogram on thePATH(orcompile.binary). The add-on writesmain.typandrefs.bibto a temporary directory, runstypst compile, reads the PDF and removes the directory. A client that disconnects aborts the process.
When neither exists the render fails with the error code typst-missing. Markup that Typst rejects fails with typst-failed; the message holds Typst's own diagnostics. A style outside CSL_STYLES fails with bad-style before any compile starts. All three are TypstError with a stable code; the message is in the language of the render and reaches the client as the error event.
What the markup holds
typstOf(content, bib, style) is pure. It maps the content like the editor's Markdown export does:
| Content | Typst |
|---|---|
| heading (level n) | = repeated n times |
| Typed block (depth d) | heading of level d with its title (not when the title is hidden), the description in #emph, the tags in small grey text, then the body |
| paragraph, hard break | text; a break is \ and a newline |
| bold, italic, strike, underline, highlight, sub, super, code, link | #strong, #emph, #strike, #underline, #highlight, #sub, #super, #raw, #link (the function form works inside a word, which *…* does not) |
| bullet, ordered and task lists | - and 1. items, nested by indentation; a task item starts with ☐ or ☑ |
| table | #table with table.header for a header row, colspan and rowspan kept |
| code block, quote, rule | #raw(block: true), #quote(block: true), #line |
| mention, tag, reference chip | their text |
| image, audio, video, file, block embed | the kind and name in italics: the editor's asset URLs are not files Typst can read |
cite node | @key, or @key[locator] |
A cite whose key names an entry of the bibliography becomes a Typst citation. A cite whose key names none reads as the text (key), like the editor's gone chip. When at least one citation resolved, the markup ends with #bibliography("refs.bib", style: …, title: …); Typst prints only the works that are cited. A bare @key followed by unmarked text that continues the word gets an empty content block (@key#[]), so Typst does not read the text as part of the key.
The bibliography
bibEntriesOf(content) collects the CSL-JSON record of every Typed block with meta.bib, in Document order, with the block id and the title. bibFileOf(entries) writes one BibTeX entry for each through the library's bibtexOf; the citation key is the one the cite node holds (bibtexKey). Two records that derive one key keep the first. The file is refs.bib, next to the main file.
| Style | Typst style |
|---|---|
apa | APA |
ieee | IEEE |
chicago-author-date | Chicago author-date |
vancouver | Vancouver |
The styles are Typst's built-in CSL styles, so the add-on has no citation processor of its own.
Pieces for your own pipeline
| Export | Use |
|---|---|
typstTarget(options?) | the RenderTarget |
typstOf, typstSourceOf | markup, or markup with its .bib text |
bibEntriesOf, bibFileOf, BIB_FILE | the bibliography of a content tree |
compileTypst, typstEngineOf | the PDF; which engine would run, or null |
CSL_STYLES, isCslStyle | the citation styles |
TypstError | the error with its code |
Obsidian: import and export a vault
The add-on @skaile/forge-editor-obsidian: importVault plans one Document per note with frontmatter as properties, wikilinks as reference chips and ^id block ids kept; exportVault writes them back; a command uploads a vault to an editor server.
Audio: read aloud, mixdown and ElevenLabs
The add-on @skaile/forge-editor-audio: an ElevenLabs SpeechProvider, the derive methods audio-tts and audio-mixdown that make recording blocks with named Derivation inputs, and the render target audio-mixdown that mixes takes through ffmpeg.