The document language for people who love LaTeX's output
Write the paper. Not the preamble .
Wit gives you typeset-quality documents without the LaTeX tax — plain, readable source with real components, data, and cross-references. One file renders to HTML, Markdown, and print-ready PDF.
@div(class hero) @h1 Hello, @span(class grad) world span@ h1@ A paragraph that simply reads like a paragraph. div@
Made for manuscripts
What Markdown and raw HTML make painful, Wit makes native. Click a card for the source, the result, and the thing you no longer do by hand.
📚
Citations that resolve themselves
Name a source once and cite it by idea. The reference — and the bibliography — stay in sync.
🧩
Write a component once
Define a callout, a figure, a pull quote — then reuse it. Change the design in one place.
📊
Tables from data, not by hand
Keep the data as data; the table renders from it. Edit a value, not a wall of pipes.
🔀
Draft and final, one source
Gate content on data. The same file renders a working draft and a clean final.
🗂
Assemble across files
A thesis is chapters. Reference them and emit them in order — one document, many files.
📄
One source, every format
The same manuscript becomes semantic HTML, Markdown, or a paginated, print-ready PDF.
📚 Citations that resolve themselves
Close ✕
Wit source
#weil: Simone Weil, Gravity & Grace (1952) !! Attention, as @weil argued, is the rarest form of generosity.
Renders to
Attention, as Simone Weil, Gravity & Grace (1952) argued, is the rarest form of generosity.
Markdown: retype the full citation everywhere, and keep the reference list in sync by hand.
🧩 Write a component once
Close ✕
Wit source
#tip @aside(class note) 💡 ... aside@ tip# @tip Save early. Save often. tip@
Renders to
Markdown: no components — paste the same block of HTML every single time.
📊 Tables from data, not by hand
Close ✕
Wit source
#sites: [
{ name - Dunmore, lit - yes }
{ name - Carrick, lit - no }
] !!
@table |schema [name, lit]| |rows @sites|Renders to
| Name | Lit |
|---|---|
| Dunmore | yes |
| Carrick | no |
Markdown: hand-align pipes; change one value and re-type the row.
🔀 Draft and final, one source
Close ✕
Wit source
(if @doc.status is draft) @aside Draft — do not circulate. aside@ (end)
Renders to (draft build)
Markdown: keep a second copy and remember to strip the notes.
🗂 Assemble across files
Close ✕
Wit source
reference ./intro.wit reference ./methods.wit reference ./results.wit @intro intro@ @methods methods@ @results results@
Compiles to
intro.wit + methods.wit + results.wit → one thesis.pdf.
Markdown: no includes — you bolt on a separate build tool to stitch files.
📄 One source, every format
Close ✕
Wit source
wit build thesis.wit -o thesis.html wit build thesis.wit -o thesis.pdf wit build thesis.wit -o thesis.md
Produces
HTML PDF Markdown
Markdown: it is the source, and HTML is the ceiling — no route to a print-ready PDF.
Three documents, one language
A journal-style thesis, a novel that never indents, and a branching game script — same tool, same source rules. Click a panel to open it.
🎓 A thesis chapter
Academic
Collapse ↑
Wit source
reference ./sources.wit ~ the bibliography, written once @h2 3 · Method 3.method@ We pre-train on a masked-language objective, following @cite bert bert@, then fine-tune each task in turn. @figure @img |src corpus.png| |alt Corpus by domain| @figcaption Figure 3.1 — Corpus composition. figcaption@ figure@ @table |schema [split, docs, tokens]| |rows @corpus| table@ As @xref 3.method xref@ shows, scale beats architecture — a point @cite sutton sutton@ makes forcefully.
Renders to
3 · Method
We pre-train on a masked-language objective, following Devlin et al. (2019), then fine-tune each task in turn.
| Split | Documents | Tokens |
|---|---|---|
| Train | 40k | 12.4M |
| Dev | 5k | 1.5M |
| Test | 5k | 1.5M |
As §3 shows, scale beats architecture — a point Sutton (2019) makes forcefully.
References
- Devlin, J. et al. (2019). BERT. NAACL.
- Sutton, R. (2019). The Bitter Lesson.
Why not LaTeX? the citation, the table, and the cross-reference all resolve from one source — no preamble, no package hunt, no re-compile roulette.
✍ A novel that never indents
Prose
Expand ↓
Wit source — flat, no indentation
@h2 One · The Harbour h2@ The rain had not stopped for three days. Mara pressed her palm to the cold glass and counted the boats that were no longer there. @em One. Two. em@ The third had been her father's. @break ✦ ✦ ✦ break@ "You can't stay," the harbourmaster said. She said nothing. There was nothing, she had learned, that saying could fix.
Renders to
One · The Harbour
The rain had not stopped for three days.
Mara pressed her palm to the cold glass and counted the boats that were no longer there. One. Two. The third had been her father's.
✦ ✦ ✦
"You can't stay," the harbourmaster said.
She said nothing. There was nothing, she had learned, that saying could fix.
Why not Markdown? for pure prose Wit gets out of the way entirely — but a scene break, an epigraph, or a chapter component is one node away, not a drop into raw HTML.
🎲 A branching game script
Interactive
Expand ↓
Wit source — data, conditions, iteration
#hero: { name - Vera, hp - 8, gold - 12 } !!
@scene The Crossroads scene@
::hero.name::, the road forks beneath a broken
signpost. You are carrying ::hero.gold:: gold.
(if @hero.hp is low)
@warn You are wounded — the dark path may kill you. warn@
(end)
@choices
@choice |goto village| Take the lit path choice@
@choice |goto tower| Take the dark path choice@
choices@
Pack: (each @hero.pack) ::this:: (end)Renders to (one playthrough)
The Crossroads
Vera, the road forks beneath a broken signpost. You are carrying 12 gold.
Choose:- → Take the lit path toward the village
- → Take the dark path toward the tower
torch · rope · a letter you should have burned.
Why not HTML? the stats, the wounded-check, and the inventory are data and logic in the document — not a wall of tags you hand-edit for every state.
It's just a parser and an AST
Wit parses your document into a small, typed AST. HTML, Markdown, and PDF are renderers over that tree — so when you need a different target, you write a function, not a fork.
| Format | Renderer | Output |
|---|---|---|
| HTML | built in | clean semantic markup |
| Markdown | built in | portable plain text |
| headless Chrome | paginated pages | |
| Anything | a function you write | whatever you need |
import { parse } from "@witlang/parser";
const ast = parse(source); // the whole document, typed
const html = renderHtml(ast); // a renderer is just: AST in, string out
const mine = myRenderer(ast); // so bring your own targetEvery built-in renderer is written exactly this way.