npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

texlyre-busytex

v1.4.0

Published

Run LaTeX compilation (pdflatex, xelatex, lualatex) in the browser using WebAssembly (TeX Live 2026)

Readme

TeXlyre BusyTeX

Run LaTeX compilation directly in your browser using WebAssembly. Supports TeX Live 2026 XeLaTeX, pdfLaTeX, and LuaLaTeX with BibTeX, makeindex, and browser-side shell escape handler integration.

npm version License: AGPL v3

Live Demo | TeX Live-on-demand & Build

Features

  • 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
  • Browser Shell Escape: Register JavaScript shell handlers for controlled in-browser command emulation

Installation

npm install texlyre-busytex

Download Assets

BusyTeX 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/assets

Assets will be downloaded to <destination>/busytex/ directory.

Usage

Basic Example

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);
}

With BibTeX, MakeIndex, and Multiple Runs

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}
}`
    }
  ]
});

Multi-file Projects

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...'
    }
  ]
});

Using PdfLaTeX or LuaLaTeX

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: '...' });

With Web Worker

const runner = new BusyTexRunner({
  busytexBasePath: '/core/busytex',
  verbose: true
});

await runner.initialize(true); // true = use Web Worker

Browser Shell Escape Handlers

BusyTeX can enable controlled shell escape in the browser by loading JavaScript handler scripts. This does not run arbitrary native commands. Instead, handler scripts register supported commands with BusyTeX and emulate those commands inside the browser or worker context.

const result = await pdflatex.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);'
    }
  ]
});

A shell handler script can register a browser-side command:

register_shell_handler('texlyre-highlight', (argv, cwd, FS, PATH, Module) => {
  const [, language, inputPath, outputPath] = argv;

  const source = FS.readFile(inputPath, { encoding: 'utf8' });
  const contents = `{\\ttfamily\n${source}\n\\par}\n`;

  return {
    exit_code: 0,
    files: [
      {
        path: outputPath,
        contents
      }
    ]
  };
});

The registered handler receives:

  • argv: command-line arguments passed by TeX
  • cwd: current working directory
  • FS: Emscripten filesystem API
  • PATH: path helper object from the runtime
  • Module: active Emscripten module

The handler may return:

{
  exit_code: number;
  files?: {
    path: string;
    contents: string | Uint8Array;
  }[];
}

This is useful for examples such as browser-side syntax highlighting, small code generators, diagram preprocessors, or other deterministic transformations that can safely run as JavaScript in the browser.

SyncTeX Support

const 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();
}

API Reference

BusyTexRunner

constructor(config?: BusyTexConfig)

Config Options:

  • busytexBasePath: Path to BusyTeX assets (default: '/core/busytex')
  • verbose: Enable verbose logging (default: false)
  • engineMode: Engine bundle mode: 'combined', 'pdftex', 'xetex', or 'luahbtex' (default: 'combined')
  • preloadDataPackages: Data packages to preload during initialization
  • catalogDataPackages: Data packages available for later loading

Methods:

  • initialize(useWorker?: boolean): Promise<void> - Initialize the runner
  • isInitialized(): boolean - Check if initialized
  • terminate(): void - Clean up resources

XeLatex, PdfLatex, LuaLatex

constructor(runner: BusyTexRunner, verbose?: boolean)
compile(options: CompileOptions): Promise<CompileResult>

CompileOptions:

  • input: Main LaTeX document content
  • bibtex?: Enable BibTeX compilation (default: false)
  • biber?: Enable Biber for BibLaTeX bibliographies, replacing the bibtex8 pass (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 }
  • dataPackagesJs?: Additional TeX Live data package scripts to load
  • remoteEndpoint?: Optional TeX Live remote endpoint for on-demand package fetching
  • shellEscape?: Enable browser-side shell escape command handling (default: false)
  • shellHandlerScripts?: Array of JavaScript handler script URLs loaded before compilation when shell escape is enabled

CompileResult:

  • success: Compilation succeeded
  • pdf?: PDF output as Uint8Array
  • synctex?: SyncTeX output as Uint8Array
  • log: Compilation log
  • exitCode: Process exit code
  • logs: Detailed log entries

Development

Clone and Setup

git clone https://github.com/TeXlyre/texlyre-busytex.git
cd texlyre-busytex
npm install
npm run download-assets
npm run build

Run Example

# build (first-time use only)
npm run build:pages-example

# run example
npm run pages-example

Then open http://localhost:3000

Upload Assets (Maintainers)

# Create archive and upload to GitHub Releases
npm run upload-assets

Limitations

  • Browser shell escape does not run arbitrary native programs. It only supports commands explicitly registered by JavaScript shell handler scripts.
  • Features requiring unavailable native external tools, such as SVG/EPS conversion, are not supported unless a compatible browser-side handler is provided. Bibliography processing with biber runs as a separate wasm module, loaded on demand the first time a .bcf control file is produced.
  • When TeX Live endpoint URL is set, pdfTeX and XeTeX can run all packages available in texlive-recommended and texlive-extra using texlive-basic only. However, LuaTeX requires texlive-recommended at 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 .data packages 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 full caching and project management, use TeXlyre instead.

License

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).

Acknowledgments

Built with BusyTeX - A WebAssembly port of TeX Live.