Docs for v0.0.16.v0.0.17 is the current release.

Static site generator

Write Typst. Ship a website.

Pages are .typ files and layouts are Typst functions. One binary does the rest: clean URLs, feeds, taxonomies, search, an asset pipeline, and a build cache.

Get started

curl -fsSL https://baudelaire.cstef.dev/install.sh -o install.sh
less install.sh # read it
sh install.sh

A page is a program

content/sourdough.typ

== Sourdough

#let recipe = (Flour: 300, Water: 210, Salt: 6)
#let total = recipe.values().sum()

#total g of dough, #recipe.len() ingredients.

#table(
  columns: 3,
  table.header([Ingredient], [Grams], [Share]),
  ..recipe.pairs().map(((name, g)) => (
    [#name], [#g], [#calc.round(100 * g / total)%],
  )).flatten(),
)

what it renders

Sourdough

516 g of dough, 3 ingredients.

Ingredient Grams Share
Flour 300 58%
Water 210 41%
Salt 6 1%

The right pane is not a screenshot. It is the left pane, evaluated while this page compiled, by the same Typst that built every other page here. That is the whole argument: Markdown has no variables, no functions, no math, and no way to load a CSV and build a table from it, so the moment you want one you start stacking a template engine and plugins on top. What that trade costs, next to Hugo, Zola, Eleventy and Astro, is on compared.

One block, every artifact

config.kdl

generate {  sitemap #true  feed { formats "rss" "atom" }}

Turn one on and the config writes itself, along with what it puts in dist/. Each artifact is built from the pages you already wrote, none of it is on until the config says so, and each has its own page under Build.

Start here

Latest writing

These docs are a baudelaire site: 57 pages, one config file, no plugins, and the sidebar on every other page built from the same content tree the build uses for prev/next links. Its source is in the repository, under docs/.