Instant.
Only what you touched is rebuilt. A word edit in a 64-page thesis lands in about 10 ms. You forget a compile step was ever there.
PhiTeX
Incremental, parallel, and byte-identical to pdfTeX and XeTeX.
Edit, and only what changed is rebuilt: a word in a 400-page thesis in milliseconds. One process to the fixed point, BibTeX and makeindex included, no second pass. It runs on your machine from a single phitex binary, and phitex watch serves a live preview in your browser that redraws only the pages you changed.
The compiler itself. A phitex watch session: a cold build, then each edit rebuilt on its own. The status line, progress bar and sparkline are the real TUI; per-edit times are illustrative, within the measured native range.
Only what you touched is rebuilt. A word edit in a 64-page thesis lands in about 10 ms. You forget a compile step was ever there.
PhiTeX compiles on your computer. Your thesis, your grant, your unpublished paper: none of it leaves your machine.
Byte for byte the PDF pdfTeX and XeTeX would make. And the instant result always equals a full rebuild.
§1 A better way to write
A compiler you never wait for, never fight, and never have to think about.
\ref, \cite, the table of contents, the index: no more “run it twice”. PhiTeX repeats what it must until nothing changes, and only that.
A 400-page thesis edits as fast as a one-page letter. PhiTeX rebuilds the paragraph you touched and the pages it moved, never the whole book.
Click any word in the PDF and your cursor jumps to it. Select text in the editor and it lights up on the page. Both ways, always in sync.
On a plane, in a library basement, behind a firewall: PhiTeX needs no server and no connection. Your document compiles where you are.
Dark mode for the page as well as the editor, crisp at any zoom, and text you can select, copy and search, because the preview is vector, not an image.
LaTeX with the packages you already use, BibTeX and biber, Unicode and OpenType fonts, SyncTeX: click the page to jump to the source.
§1.1 Friendly errors
No wall of log. The preview says why the page looks the way it does, at the line to look at, and it never breaks. Incomplete input doesn't trap: an open { just runs to the end, and the last good page stays up, dimmed, with a banner saying why.
Every message comes from the compiler itself, with the exact place in your source. There's a --json mode for tools too.
§2 One engine, everywhere
The same compiler, the same instant page, in the editor you already use.
One switch in the PDF toolbar, and the page follows your typing. Collaborators' edits too.
A live page beside your editor, errors in the Problems panel, click-to-source both ways.
phitex watch rebuilds on every save and serves a live preview in your browser, the same viewer the extensions use. Scriptable and CI-friendly.
§3 Try it
The same engine, compiled to WebAssembly and running on this page. No server, nothing uploaded. Type, and it repaints on every keystroke, or pick another file on the left.
Type in it. A design preview of PhiTeX's own editor, running in your browser. It repaints on every keystroke, no Recompile. Pick another file on the left.
§5 For VS Code
The same instant preview beside your editor: a live page that follows your typing, errors in the Problems panel, and click-to-source both ways.
It's the same engine and the same session as the Overleaf extension, in a webview.
Install for VS Code§5.1 In the CLI
One binary, for any OS. phitex build main.tex writes your PDF, and phitex watch keeps it up to date as you save, serving a live page in your browser that repaints only the pages that changed. No editor plugin needed. There's also a Rust library to embed it in your own tools, plus --ssa to see your document the way the compiler does.
$ phitex --ssa examples/phi.tex ; l.1 \count1=0 %0 = prim count %1 = %0(1, 0) ; \count1 = 0 … %21 = φ(%7, %20, %1) ; \count1 (then)
§6 Numbers
Native figures from the compiler's benches, and keystroke→page figures from the same engine in Chromium.
a word edit in a 64-page thesis, rebuilt natively with phitex
keystroke → page on real Overleaf, 46 keys through CDP key input
the core's edit, even on a 185 KB, 38-page document
fast keystrokes, coalesced into 2 builds. One build is in flight at a time, and the rest merge.
| document | pages | open | first paint | fixed point | fresh-build check |
|---|---|---|---|---|---|
| 3 paragraphs | 1 | 16 ms | 0.06–0.09 ms | same | 0.8 ms |
| 200 paragraphs, 18 KB | 4 | 10 ms | 0.10–0.26 ms | same | 5.2 ms |
| 2000 paragraphs, 185 KB | 38 | 62 ms | 0.23–0.26 ms | 0.26–0.28 ms | 47 ms |
book.tex + main (refs, .aux loop) | 6 | 15 ms | 0.14–0.21 ms | same | 8.8 ms |
Browser figures: phitex-overleaf REPORT.md, “Measured latencies”, from bench/latency.mjs. Native figures: the PhiTeX repository's bench/.
§7 For engineers: how it works
PhiTeX compiles TeX the way compilers like LLVM compile code: into SSA (static single assignment), where every value is defined exactly once. Then, through a second IR for the pages, it knows precisely what each edit changed, and rebuilds only that.
Every file comes through PhiTeX's virtual file layer. Each has its own tree and can be edited. The build's own files are values too, read like any file: the .aux (what was written to it), and the .bbl and .ind that BibTeX and makeindex make.
The CST's children are paragraphs, up to their blank lines, each with an id. An edit reparses only the paragraphs it touched, until the old boundaries come back, and hands back a splice.
Every value (a primitive, a macro, a catcode table, a register, a paragraph) is defined once, and every use points at the one value it means. The SSA is cut into chunks, one per paragraph, or per run of paragraphs that a group, a conditional or a macro call spans. Each chunk records its imports (what the names it read meant) and its exports.
Each chunk's material flows into the page state. Where a page is full, the output routine runs as an output chunk: kept if its page is the same, built again if not. The page you are looking at is painted first. The rest catch up after.
The .aux, .bbl and .ind are the only back edges (μ). Only the chunks that read a μ that changed are built again, and the loop runs until nothing changes. That is the document's fixed point, the same whether it was reached from nothing or from the last build. Then each page's PDF stream is written, and a page that didn't change reuses its stream.
§7.1 One keystroke
An edit rebuilds the chunks it touched. Then it walks the rest: a chunk whose imports all mean what they meant is kept, untouched. A node whose value comes out equal wakes nothing (early cutoff). Change a macro's body, and exactly its readers light up.
Illustration of the rule. The demo's own counts appear under the demo above.
§7.2 One graph, one engine
The document is one graph of typed nodes, run by one agenda. Deltas flow down the tiers, and stop where a value comes out equal.
Read names by position. Equal imports: kept.
Each adds its chunk's material to the page state. Equal state after: stop.
The output routine, one per page. Same page: kept.
.aux, .bbl, .ind: the only back edges, iterated to the fixed point.
Typesetting is TeX's own algorithms, ported from tex.web as pure functions: line breaking, hyphenation, math, the page builder. Each is memoized and runs in parallel, on every core you have.
§8 FAQ
No. On this page and in the browser extension, everything runs locally as WebAssembly; the phitex CLI runs on your own machine. The extension's only requests go to overleaf.com, as you, for your own project's files, the same way the editor gets them. No analytics, no server, no remote code. This site makes no third-party requests either: its fonts and libraries are bundled.
Yes. It handles LaTeX with your packages, BibTeX and biber, Unicode and OpenType fonts, and the PDF matches pdfTeX and XeTeX byte for byte. LuaTeX is planned.
It's PhiTeX's core invariant: after any sequence of edits, the incremental program equals a fresh build of the same text. The tests check it after random edits, and the extension can check it live against a fresh build.
In SSA, every value is defined once, and every use points at the one value it means. Names exist only while the program is built. That makes “what did this edit change?” a question about values, so a chunk whose imports mean the same is simply kept.
Nothing. PhiTeX is free and open source.
Yes. The PhiTeX engine is free software under the GNU Affero General Public License v3.0 (AGPL-3.0-only).