Zorto
Introduction to Zorto
← / → · space · F
Introduction to Zorto 1 / 22
Zorto

Zorto #

Content above config above code.

The AI-native static site generator (SSG) with executable code blocks & more.

Introduction to Zorto 2 / 22

What is Zorto? #

  • Static site generator written in Rust
  • Python bindings via PyO3: install with uv or pip
  • Markdown content with TOML frontmatter
  • Executable code blocks: run Python and Bash at build time
  • Built-in search, feeds, and llms.txt
  • Data apps: HTML/CSS/JS plus DuckDB data
  • MIT licensed, open source forever
Zorto
Introduction to Zorto 3 / 22

Content above config above code #

Content #

  • Markdown pages
  • Prose, docs, decks
  • SQL receipts and notes
  • Mostly human-owned

Config #

  • config.toml
  • Routes, templates, themes
  • Sources, queries, dashboards
  • Human or AI-owned

Code handles the machinery: Rust builds, Python orchestrates local data, JavaScript renders browser interfaces.

Introduction to Zorto 4 / 22

Small core, wide surface #

Rust core Site model, rendering, search, checks, and output safety.
Rust CLI Build, preview, clean, init, and developer workflow commands.
Python distribution PyO3 bindings and `uv tool install zorto` for broad installation.
Static runtime HTML, CSS, JavaScript, search tables, and public database files.

Code can grow behind stable boundaries. Content and config stay readable.

Introduction to Zorto 5 / 22

AI-native by design #

  • Markdown + TOML are easy to diff, review, and edit
  • One file per page or slide keeps agent edits scoped
  • content_dirs lets zorto.dev publish repo docs without duplication
  • zorto check validates links, headings, and structure
  • llms.txt gives agents a compact site map at build time
Introduction to Zorto 6 / 22

Core surface #

  • Content model: pages, sections, taxonomies, feeds, clean URLs
  • Search: built-in client-side index for static hosting
  • Code execution: Python and Bash outputs baked into pages
  • Data apps: DuckDB-backed HTML/CSS/JS interfaces
  • Presentations: one markdown file per slide, native HTML runtime
  • AI contracts: AGENTS.md, llms.txt, and zorto check
Introduction to Zorto 7 / 22
Zorto

Native presentations #

  • Markdown source, one file per slide
  • TOML frontmatter controls order, layout, theme, and backgrounds
  • Shortcodes handle columns, fragments, notes, and media
  • Output is static HTML/CSS/JS
  • No presentation server required
Introduction to Zorto 8 / 22

Executable code blocks #

Write Python in a fenced block: Zorto runs it at build time and embeds the output.

# Stdlib only: this demo runs without extra installs.
import statistics

revenue = [12, 15, 13, 17, 21, 24]
costs   = [10, 11, 12, 13, 14, 15]

print(f"Mean revenue: {statistics.mean(revenue):.2f}")
print(f"Mean costs:   {statistics.mean(costs):.2f}")
print(f"Margin:       {statistics.mean(revenue) - statistics.mean(costs):.2f}")
Mean revenue: 17.00
Mean costs:   12.50
Margin:       4.50

Add plotly, matplotlib, altair, or seaborn to your venv to embed figure output the same way.

Introduction to Zorto 9 / 22

Dependencies are explicit #

# website/pyproject.toml
[project]
dependencies = [
  "matplotlib",
  "plotly",
  "pandas",
  "numpy",
]

# build_meta.py
# /// script
# dependencies = [
#   "duckdb==1.5.2",
]
  • Executable blocks: Zorto activates the site .venv
  • Website builds: uv sync installs chart/data deps
  • Pipelines: uv run --locked --script owns script deps
  • Distribution: uv tool install zorto installs the Rust-backed CLI

No hidden global Python. No generated dependency soup.

Introduction to Zorto 10 / 22

Build-time visualizations #

# Stdlib only: a tiny ASCII sparkline of a damped oscillation.
import math

x = [i * 0.4 for i in range(40)]
y = [math.sin(v) * math.exp(-v * 0.12) for v in x]
ramp = " ▁▂▃▄▅▆▇█"
lo, hi = min(y), max(y)
spark = "".join(ramp[round((v - lo) / (hi - lo) * (len(ramp) - 1))] for v in y)

print(f"damped sin(x) * e^(-0.12x), 40 samples")
print(spark)
damped sin(x) * e^(-0.12x), 40 samples
▃▅▇██▇▆▅▃▂▁  ▁▁▂▄▅▅▅▅▅▄▄▃▂▂▂▂▂▃▃▄▄▄▄▄▄▄▃

For real charts, install matplotlib, plotly, altair, or seaborn: Zorto captures Figure objects and embeds them as static HTML automatically.

Introduction to Zorto 11 / 22

Python deps render artifacts #

import matplotlib.pyplot as plt
import pandas as pd

df = pd.DataFrame({
    "week": range(1, 9),
    "content": [18, 21, 25, 32, 40, 48, 57, 69],
    "data apps": [2, 3, 3, 5, 8, 13, 21, 34],
})

ax = df.plot(x="week", y=["content", "data apps"], marker="o", linewidth=3, figsize=(7.2, 3.4))
ax.set_title("Generated during the Zorto build")
ax.grid(alpha=0.25)
ax.legend(frameon=False)

print(f"rows: {len(df)}")
print("deps: pandas + matplotlib")
rows: 8
deps: pandas + matplotlib
Plot output

The build runs inside the uv-managed site environment. The resulting figure is baked into static HTML.

Introduction to Zorto 12 / 22

Data app shape #

Sources Git, content, manifests, generated output, local files.
Pipeline Self-contained `uv` script plus DuckDB transforms.
Artifact Checked-in `site.ddb` today. Remote DuckDB and DuckLake-backed data next.
Config Site-local TOML declares views, SQL, tables, and chart bindings.
Browser DuckDB-Wasm queries data. Plotly renders charts.

Static-first does not mean static-only. The interface is HTML, CSS, and JavaScript.

Introduction to Zorto 13 / 22

The slide can query site.ddb #

Zorto can ship a public DuckDB database beside the site, then let a page query it in the browser.

  • site.ddb: generated locally
  • DuckDB-Wasm attaches it read-only
  • Plotly renders the result inside this deck

waiting for slide

content files pending build output pending latest build pending
Introduction to Zorto 14 / 22

Query the deck data #

ready

This deployment is static: the browser is doing the database work.

Introduction to Zorto 15 / 22

Dynamic when needed #

Static-first #

  • Public data: ship site.ddb
  • Local query: DuckDB-Wasm in the browser
  • Deploy: any static host
  • Cost: no server process

Live data #

  • Quack: DuckDB instances talk over HTTP
  • Attach: remote catalogs through a quack: URI
  • Auth: scoped secret or explicit TOKEN option
  • Interface: HTMX or JS updates browser views
  • Security: localhost default, reverse proxy/TLS for non-local

Zorto should not hide this. It should make the boundary obvious.

Introduction to Zorto 16 / 22

16 built-in themes #

  • zorto
  • dkdc
  • default
  • ember
  • forest
  • ocean
  • rose
  • slate
  • midnight
  • sunset
  • mint
  • plum
  • sand
  • arctic
  • lime
  • charcoal

Every theme supports light and dark mode with a single toggle.

Introduction to Zorto 17 / 22

Progressive reveal #

Press → or space to reveal one at a time:

  • fade-in: the default, gentle entrance
  • fade-up: slides in from below
  • grow: scales up to emphasize
  • highlight-blue: flashes a color highlight
  • fade-right: slides in from the left
Introduction to Zorto 18 / 22

Config drives the deck #

+++
title = "Data apps"
weight = 58

[extra]
slide_theme = "ink"
layout = "wide"
+++

Slide source stays readable. The template owns the runtime and visual system.

Introduction to Zorto 19 / 22

Presentations: one file per slide #

  • Each slide is a markdown file with its own frontmatter
  • weight field controls slide order
  • [extra] controls background, theme, and layout
  • Shortcodes for columns, fragments, speaker notes, and positioned images
  • Native HTML/CSS/JS: keyboard navigation, fullscreen, print
Introduction to Zorto 20 / 22

Shortcodes: rich content without HTML #

Built-in #

  • slide_image: positioned or inline images
  • fragment: progressive reveal
  • columns: side-by-side layout
  • speaker_notes: source-level presenter notes

Custom #

  • Drop a .tera template in shortcodes/
  • Call it from any markdown page
  • Keep repeated HTML out of prose
  • Validate author-facing inputs at shortcode boundaries
  • Test the rendered result with zorto check

The whole presentation you’re watching is rendered from these shortcodes.

Introduction to Zorto 21 / 22

Get started #

# Install
uv tool install zorto

# Create a new site
zorto init mysite
cd mysite

# Preview with live reload
zorto preview --open

Or use as a Python library:

import zorto
zorto.build(root=".")
Introduction to Zorto 22 / 22
Zorto

Thank you #

zorto.dev | github.com/dkdc-io/zorto

Install: uv tool install zorto

1 / 22