Project

typst

0.01
The project is in a healthy, maintained state
Ruby binding to typst, a new markup-based typesetting system that is powerful and easy to learn.
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
 Dependencies

Development

~> 1.5
~> 3.6

Runtime

~> 3.2
~> 0.9, >= 0.9.128
 Project Readme

typst-rb

Ruby binding to typst, a new markup-based typesetting system that is powerful and easy to learn.

Installation

gem install typst

Usage

require "typst"

Hello World

Typst(body: %{hello world}).compile(:pdf).write("hello_world.pdf")

Open a local typst file named example.typ

t = Typst("example.typ")

Use a typst string

t = Typst(body: %{hello world})

Use a zipped typst file

t = Typst(zip: "test/main.typ.zip")

Open a remote typst file

require "open-uri"
URI.open("https://github.com/actsasflinn/typst-rb/raw/refs/heads/main/README.typ") do |u|
  Typst(body: u.read).compile(:pdf).write("remote_readme.pdf")
end

Open a remote zipped typst file

require "open-uri"
URI.open("https://github.com/actsasflinn/typst-rb/raw/refs/heads/main/test/hello.typ.zip") do |u|
  Tempfile.create do |f|
    f.write(u.read)
    f.rewind
    Typst(zip: f).compile(:pdf).write("remote_zipped.pdf")
  end
end

Compile to PDF

doc = t.compile(:pdf)

Compile to PDF selecting the typst supported PdfStandard

doc = t.compile(:pdf, pdf_standards: ["2.0"])

Compile to SVG

doc = t.compile(:svg)

Compile to PNG

doc = t.compile(:png)

Compile to PNG and set PPI

doc = t.compile(:png, ppi: 72)

Compile to HTML (using Typst expirmental HTML)

doc = t.compile(:html_experimental)

Or return content as an array of bytes

pdf_bytes = Typst("readme.typ").compile(:pdf).bytes
# => [37, 80, 68, 70, 45, 49, 46, 55, 10, 37, 128 ...]

Write the output to a file

Note: for multi-page documents using formats other than PDF and HTML, pages write to multiple files, e.g. readme_0.png, readme_1.png

doc.write("filename.pdf")

Return PDF, SVG, PNG or HTML content as an array of pages

Typst("readme.typ").compile(:pdf).pages
# => ["%PDF-1.7\n%\x80\x80\x80\x80\n\n1 0 obj\n<<\n  /Type /Pages\n  /Count 3\n  /Kids [160 0 R 162 ...

Typst("readme.typ").compile(:svg).pages
# => ["<svg class=\"typst-doc\" viewBox=\"0 0 595.2764999999999 841.89105\" ...

Typst("readme.typ").compile(:png).pages
# => ["\x89PNG\r\n\x1A\n\x00\x00\x00\rIHDR\x00\x00\x04\xA7\x00\x00\x06\x94\b\ ...

Typst("readme.typ").compile(:html_experimental).pages
# => ["<!DOCTYPE html>\n<html>\n  <head>\n    <meta charset=\"utf-8\">\n    <meta name=\"viewport\" ...

Pass values into typst using sys_inputs

sys_inputs_example = %{
#let persons = json(bytes(sys.inputs.persons))

#for person in persons [
  #person.name is #person.age years old.\\
]
}
people = [{"name" => "John", "age" => 35}, {"name" => "Xoliswa", "age" => 45}]
data = { "persons" => people.to_json }
Typst(body: sys_inputs_example, sys_inputs: data).compile(:pdf).write("sys_inputs_example.pdf")

Apply inputs to typst to product multiple PDFs

t = Typst(body: sys_inputs_example)
people.each do |person|
  t.with_inputs({ "persons" => [person].to_json }).compile(:pdf).write("#{person['name']}.pdf")
end

A more complex example of compiling from string using other dependency typst template, svg and font resources all in memory

main = %{
#import "template.typ": *

#show: template.with()

#lorem(50)

#image("icon.svg")
}

template = %{
#let template(body) = {
  set text(12pt, font: "Example")
  body
}
}

icon = File.read("icon.svg")
font_bytes = File.read("Example.ttf")

Typst(body: main, dependencies: { "template.typ" => template, "icon.svg" => icon }, fonts: { "Example.ttf" => font_bytes }).compile(:pdf)

Use a zip file with an alternatively named main typst file

Typst(zip: "test/main.typ.zip", main_file: "hello.typ").compile(:pdf)

Use a package from the Typst Universe

Your package_example.typ file...

#import "@preview/wordometer:0.1.5": word-count, total-words
#show: word-count

In this document, there are #total-words words all up.

#word-count(total => [
  The number of words in this block is #total.words
  and there are #total.characters letters.
])

...compiles just like anything else

Typst("package_example.typ").compile(:pdf).write("package_example.pdf")

Query a typst document

Typst("readme.typ").query("heading").result
# => 
# [{"func" => "heading",
#   "level" => 1,
#   "depth" => 1,
# ...

Typst("readme.typ").query("heading", format: "json").result(raw: true)
# => "[\n  {\n    \"func\": \"heading\",\n    \"level\": 1,\n    \"depth\": ..."

Typst("readme.typ").query("heading", format: "yaml").result(raw: true)
# => "- func: heading\n  level: 1\n  depth: 1\n  offset: 0\n  numbering: ..."

# Query results as JSON string
Typst("test/test.typ").query("heading").to_s
# => "[\n  {\n    \"func\": \"heading\",\n    \"level\": 1,\n    \"depth\": 1,\n    \"offset\": 0,\n ...

# Query results as YAML string
Typst("test/test.typ").query("heading", format: "yaml").to_s
# => "- func: heading\n  level: 1\n  depth: 1\n  offset: 0\n  numbering: null\n  supplement:\n    ...

clear the compilation cache

# Evict all entries whose age is larger than or equal to `max_age`
max_age = 10
Typst::clear_cache(max_age)

Contributors & Acknowledgements

typst-rb is based on typst-py by messense
clear_cache was contributed by NRicciVestmark
CI improvements were contributed by am1006
Defect resolutions by adam12 and walterdavis
Design suggestions by alec-c4

License

This work is released under the Apache-2.0 license. A copy of the license is provided in the LICENSE file.