Heine

Heine is a small, synchronous Rust static-site generator. It compiles a configured content tree and Tera2 templates into a checked, managed output tree.

Pronounced Hei·ne, [ˈhaɪ̯nə], “Heineken” without “ken.” Named after Heinrich Heine, the German poet and prose writer known for his wit and irony. Heine is not affiliated with Heineken.

Heine owns the relationships it can check from a site's resolved model: rendered pages, copied assets, locale-aware content, generated routes, and generated resources. A missing internal page or copied asset therefore fails where it is authored instead of becoming a browser 404.

Status

Heine is pre-release and is not published to crates.io yet. Install a current stable Rust toolchain, clone this repository, and run it with cargo run.

It currently provides Markdown rendering with page-owned tables of contents and margin footnotes, Tera2 templates, locale-aware content and Fluent localization, checked page and asset links, collections, pagination, taxonomies, Series, Atom feeds, sitemaps, search-document indexes, and a development server with live reload, media range requests, and draft previews. Copied assets may carry checked REUSE-compatible declarations, including optional complete coverage and exact shared declarations for coherent asset sets.

Heine does not bundle a frontend toolchain or deployment integration. Use ordinary tools for general CSS and JavaScript processing, general media transformation, deployment, audits, and external services. Kits, plugins, and RSS are not implemented yet.

First site

A minimal site has a configuration file, one locale tree, and one template:

my-site/
├── heine.toml
├── content/
│   └── en/
│       └── index.page
└── templates/
    └── page.tera
# heine.toml
[i18n]
default_locale = "en"

[i18n.locales.en]
direction = "ltr"
# content/en/index.page
template = "page.tera"
title = "Hello, Heine"
{# templates/page.tera #}
<!doctype html>
<html lang="{{ locale.code }}" dir="{{ locale.direction }}">
  <head><title>{{ page.title }}</title></head>
  <body><h1>{{ page.title }}</h1></body>
</html>

Build it from this repository:

cargo run -- --root /path/to/my-site

This generates public/index.html. The configured default locale is unprefixed; later locale trees receive their locale code in generated URLs.

Preview locally

Run the development server while writing:

cargo run -- serve --root /path/to/my-site

It first performs a complete build, serves the generated output, watches the site inputs, and reloads open HTML pages after a successful rebuild. It starts with port 1111, then tries the next available unprivileged port.

The development-server guide covers base paths, live reload, range requests for media, failed rebuilds, and local-network use.

For a site being served below a subdirectory, set the base path and choose an output directory appropriate for the host. The reference gives the exact configuration rules.

Where to go next

The documentation map explains the available reading paths.

Starter site

starter-site/ is a complete, working multilingual example. Use it after the tutorial when you want to see several features composed in one site rather than introduced one at a time:

cargo run -- --root starter-site

Its public/ directory is generated output. If it already contains unrelated files, explicitly adopt and replace it with:

cargo run -- --root starter-site --clean-output

External asset tools

Heine copies final assets; it does not compile Sass, process images, bundle JavaScript, or generate content-hashed filenames. Run such tools separately and have them write their final files below content/assets/ (or a locale's asset tree). Heine then copies those files and asset() can link to them.

Run an asset transformation before Heine when a template references the asset through asset(). Modifying managed output afterward can invalidate a Heine-generated versioned URL or integrity value.

heine serve watches copied assets but does not start or supervise another tool's watcher. Filename-based versioned assets and optional integrity values are available when a site needs them; neither is automatic content-hash generation.

Build behavior

A normal build checks a complete site and publishes it only after rendering and copying succeed. It replaces stale generated files left by renamed or deleted inputs. If an existing output directory was not created by Heine, use --clean-output only after confirming that it is safe to replace.

--quick updates changed present inputs in place. It intentionally does not notice template, configuration, relationship, rename, or deletion changes, so use a normal build after those changes. The glossary and reference describe the exact contract.

Development

Run the full local quality check before contributing changes:

cargo fmt --check
cargo clippy --all-targets --all-features -- -D warnings
cargo test --all-targets --all-features