TeXlyre BusyTeX

Run LaTeX compilation directly in your browser

Interactive Demo

Try out LaTeX compilation below. Select an engine, configure options, and compile your LaTeX code.

Fonts must be referenced by filename rather than by font name, e.g. \setmainfont{FiraSans-Regular.otf} instead of \setmainfont{Fira Sans}.

Shell escape in this demo runs entirely in the browser through registered JavaScript handlers. It does not execute arbitrary native system commands. The syntax highlighting example uses a browser-side handler powered by PrismJS to emulate a small external command safely inside the WebAssembly workflow.

Features requiring unavailable native external tools, such as SVG/EPS conversion or bibliography processing with biber, are not supported unless a compatible browser-side handler is provided.

TeX Live Collections
Preloads TeX Live files into /tmp/texlive_remote for offline compilation. The ZIP is produced by the "Download Remote Package ZIP" button after a previous compilation.
On-demand TeX Live server fetched at compile time for packages beyond the selected collections. Leave blank to disable. Ensure that "Use Web Worker" is checked to enable this feature.
Browser shell escape is limited to commands registered by loaded JavaScript handler scripts. The demo syntax-highlighting handler registers texlyre-highlight and writes generated LaTeX back into the virtual filesystem.

Input

PDF Preview

Compilation Log

Features

Installation

npm install texlyre-busytex
npx texlyre-busytex download-assets

Usage

import { BusyTexRunner, XeLatex, PdfLatex, LuaLatex } from 'texlyre-busytex';

// Combined mode (single WASM with all engines, default)
const runner = new BusyTexRunner({
  busytexBasePath: '/core/busytex'
});
await runner.initialize();

const xelatex = new XeLatex(runner);
const result = await xelatex.compile({
  input: '\\documentclass{article}\\begin{document}Hello\\end{document}',
  bibtex: true,
  makeindex: true,
  rerun: true,
});

if (result.success && result.pdf) {
  const blob = new Blob([result.pdf], { type: 'application/pdf' });
  window.open(URL.createObjectURL(blob));
}

// Browser shell escape with a registered JavaScript handler
const shellEscapeResult = await xelatex.compile({
  input: '\\documentclass{article}\\usepackage{xcolor}\\begin{document}\\input{highlighted-output.tex}\\end{document}',
  shellEscape: true,
  shellHandlerScripts: [
    '/shell-handlers/highlight-handler.js'
  ],
  additionalFiles: [
    {
      path: 'snippet-javascript.txt',
      content: 'const message = "Hello from BusyTeX";\\nconsole.log(message);'
    }
  ]
});

// Split mode (per-engine WASM, smaller downloads)
const pdftexRunner = new BusyTexRunner({
  busytexBasePath: '/core/busytex',
  engineMode: 'pdftex'
});
await pdftexRunner.initialize();

const pdflatex = new PdfLatex(pdftexRunner);
const pdfResult = await pdflatex.compile({
  input: '\\documentclass{article}\\begin{document}Hello\\end{document}'
});

// Switch engines with split builds
const xetexRunner = new BusyTexRunner({
  busytexBasePath: '/core/busytex',
  engineMode: 'xetex'
});
await xetexRunner.initialize();

const xelatexSplit = new XeLatex(xetexRunner);
const xeResult = await xelatexSplit.compile({
  input: '\\documentclass{article}\\begin{document}Hello\\end{document}'
});