Run LaTeX compilation directly in your browser using WebAssembly. Supports TeX Live 2026 XeLaTeX, pdfLaTeX, and LuaLaTeX with BibTeX and makeindex integration.
Live Demo | TeX Live-on-demand & Build
- XeLaTeX: Compile with XeTeX engine + bibtex8 + dvipdfmx
- PdfLaTeX: Compile with PdfTeX engine + bibtex8
- LuaLaTeX: Compile with LuaHBTeX engine + bibtex8
- Multi-file Support: Handle complex projects with multiple .tex and .bib files
- SyncTeX: Generate SyncTeX files for editor synchronization
- Browser-based: All compilation runs entirely in the browser with no server required
- Web Worker Support: Non-blocking compilation using Web Workers
npm install texlyre-busytexBusyTeX requires WASM files (~32 MB) + data (90-400 MB) that are hosted on GitHub Releases:
# Download to default location (./public/core)
npx texlyre-busytex download-assets
# Or specify custom location
npx texlyre-busytex download-assets ./static/wasm
npx texlyre-busytex download-assets ./public/assetsAssets will be downloaded to <destination>/busytex/ directory.
import { BusyTexRunner, XeLatex } from 'texlyre-busytex';
const runner = new BusyTexRunner({
busytexBasePath: '/core/busytex'
});
await runner.initialize();
const xelatex = new XeLatex(runner);
const result = await xelatex.compile({
input: `\\documentclass{article}
\\usepackage{amsmath}
\\begin{document}
\\section{Introduction}
Hello, LaTeX!
\\begin{equation}
E = mc^2
\\end{equation}
\\end{document}`
});
if (result.success && result.pdf) {
const blob = new Blob([result.pdf], { type: 'application/pdf' });
const url = URL.createObjectURL(blob);
window.open(url);
}const result = await xelatex.compile({
input: `\\documentclass{article}
\\begin{document}
\\cite{sample2023}
\\bibliographystyle{plain}
\\bibliography{references}
\\end{document}`,
bibtex: true,
makeindex: true,
rerun: true,
additionalFiles: [
{
path: 'references.bib',
content: `@article{sample2023,
title={Sample Article},
author={Author, John},
year={2023}
}`
}
]
});const result = await xelatex.compile({
input: `\\documentclass{article}
\\begin{document}
\\input{chapter1.tex}
\\input{chapter2.tex}
\\end{document}`,
additionalFiles: [
{
path: 'chapter1.tex',
content: '\\section{Chapter 1}\nContent...'
},
{
path: 'chapter2.tex',
content: '\\section{Chapter 2}\nContent...'
}
]
});import { PdfLatex, LuaLatex } from 'texlyre-busytex';
const pdflatex = new PdfLatex(runner);
const result = await pdflatex.compile({ input: '...' });
const lualatex = new LuaLatex(runner);
const result2 = await lualatex.compile({ input: '...' });const runner = new BusyTexRunner({
busytexBasePath: '/core/busytex',
verbose: true
});
await runner.initialize(true); // true = use Web Workerconst result = await xelatex.compile({ input: '...' });
if (result.synctex) {
const blob = new Blob([result.synctex], { type: 'application/gzip' });
const url = URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = url;
link.download = 'main.synctex.gz';
link.click();
}constructor(config?: BusyTexConfig)Config Options:
busytexBasePath: Path to BusyTeX assets (default:'/core/busytex')verbose: Enable verbose logging (default:false)
Methods:
initialize(useWorker?: boolean): Promise<void>- Initialize the runnerisInitialized(): boolean- Check if initializedterminate(): void- Clean up resources
constructor(runner: BusyTexRunner, verbose?: boolean)
compile(options: CompileOptions): Promise<CompileResult>CompileOptions:
input: Main LaTeX document contentbibtex?: Enable BibTeX compilation (default:false)makeindex?: Enable MakeIndex for index generation (default:false)rerun?: Enable multiple TeX passes to resolve references, TOC, and index entries (default:false)verbose?: Verbosity level -'silent','info', or'debug'(default:'silent')additionalFiles?: Array of{ path: string, content: string | Uint8Array }
CompileResult:
success: Compilation succeededpdf?: PDF output as Uint8Arraysynctex?: SyncTeX output as Uint8Arraylog: Compilation logexitCode: Process exit codelogs: Detailed log entries
git clone https://github.com/TeXlyre/texlyre-busytex.git
cd texlyre-busytex
npm install
npm run download-assets
npm run build# build (first-time use only)
npm run build:pages-example
# run example
npm run pages-exampleThen open http://localhost:3000
# Create archive and upload to GitHub Releases
npm run upload-assets- Fonts must be referenced by filename rather than by font name, e.g. \setmainfont{FiraSans-Regular.otf} instead of \setmainfont{Fira Sans}.
- Features requiring external tools such as SVG/EPS inclusion, bibliography processing with
biber, or shell escape (e.g.minted) are not supported in WebAssembly. - When TeX Live endpoint URL is set, pdfTeX and XeTeX can run all packages available in
texlive-recommendedandtexlive-extrausingtexlive-basiconly. However, LuaTeX requirestexlive-recommendedat least for a considerable number of packages to work. - The example page relies on Emscripten's built-in
EM_PRELOAD_CACHE(IndexedDB) to persist downloaded.datapackages across page refreshes, but does not implement any additional caching layer on top of it for caching packages and fonts downloaded from the remote endpoint. For a production-ready environment with richer caching and project management, use TeXlyre instead.
TeXlyre-BusyTeX is licensed under the GNU Affero General Public License v3.0 (AGPL-3.0). See LICENSE for the complete license text.
This project incorporates TeXlyre-BusyTeX WASM (AGPL-3.0), itself derived from BusyTeX WASM (MIT).
Built with BusyTeX - A WebAssembly port of TeX Live.