Skip to main content

3 posts tagged with "LaTeX"

LaTeX language

View All Tags

Chelys Local Typesetting Engine Support

· 6 min read
Fares Abawi
TeXlyre author & maintainer
Part of the NGI0 Core roadmap

This post reports on Task 5 of TeXlyre's NGI0 Commons grant. For the full project roadmap, see TeXlyre joins NGI0 Commons.

TeXlyre can now compile projects with typesetting systems running on the user's machine. A typesetter is exposed as a compile service, in that TeXlyre sends the project files and compile options, the service runs the selected tool (typesetter or document authoring compiler), then returns the log and generated output. Chelys then installs and manages these services through its recipe system.

The same interface is used by SILE, TeX Live (LaTeX), PreTeXt, ConTeXt, and the other typesetter recipes. TeXlyre sees each one as a compiler provider alongside its built-in browser compilers.

Background

TeXlyre's support for WebAssembly-based Typst and LaTeX typesetting engines satisfies most common use cases. However, certain packages depend on libraries or environments that cannot practically be bundled in a browser environment. For example, LaTeX's SVG support relies on Inkscape, while some Typst packages and templates rely on system fonts unavailable to the WebAssembly engine. Similarly, many alternative typesetting systems depend on native binaries or language runtimes that are impractical to port and maintain in WebAssembly. Supporting them through external execution environments is therefore more feasible than running every typesetting backend directly in the browser.

TeXlyre represents each external backend through a provider, which describes how the editor can interact with it, including the supported project type, input files, output formats, compile controls, and transport address. The corresponding recipe defines how that backend is installed, configured, and executed in the external environment. This allows SILE, PreTeXt, TeX Live, and other backends to share the same editor-side compilation workflow, keeping the editor agnostic to backend-specific execution details.

The work spans three repositories. Each link below shows the full diff for that repository's contribution to this task.

  • chelys: the typesetter plugin type and its integration with the Chelys recipe lifecycle.
  • texlyre: compiler registration, external compile dispatch, file synchronization, controls, and output handling.
  • chelys-recipes: the shared compile bridge and the typesetter recipes.

Milestone 5a: Compile dispatch, file transfer, and PDF retrieval

Unlike in-browser typesetters, TeXlyre has no direct control over the execution pipeline of external backends. At the same time, from the editor's perspective, the behavior and procedures should remain identical regardless of whether compilation is performed locally or externally. To compile a project successfully, an external backend therefore needs access to the complete project file tree, including scripts, bibliographies, images, and other binary assets.

TeXlyre constructs a temporary working tree that mirrors the project's directory structure and transfers it to the external environment over WebSocket. Each project instance receives an independent working directory, preventing files and generated artifacts from leaking between project instances or connections. The recipe bridge can then invoke the configured backend for this reconstructed project and return the resulting output, logs, and auxiliary files to TeXlyre in a uniform structure. This allows the editor to treat external and local compilation in a similar fashion.

Once compilation is complete, the generated outputs, such as a PDF and other requested artifacts, are transmitted back to the originating TeXlyre instance together with the compiler log and auxiliary files generated during the run. TeXlyre can then pass the main output through the same rendering and preview pipeline used by its in-browser typesetters.

Compile dispatch and file synchronization between TeXlyre and an external backend

A connection-scoped working tree mirrors the project inside the recipe bridge; the first compile transfers the full tree and later compiles synchronize only the files that changed.

A provider can optionally enable incremental file synchronization. After an initial project transfer, further compile requests send only files that have changed or have been removed, while the bridge keeps the reconstructed working tree for the lifetime of the connection. Once the connection closes, the working directory is discarded, and a new connection begins with a fresh project state. For example, given a SILE project, the first compile transfers main.sil together with its project assets. If only one source file changes afterwards, the next request synchronizes that file before compiling with SILE again.

Incremental file synchronization

Currently, incremental synchronization operates on the complete file, meaning that changing a single character in the editor would retransmit the entire text document.

Providers may also define compile-time controls that are exposed in TeXlyre's interface. The TeX Live provider, for instance, provides an engine selector for pdfLaTeX, LuaLaTeX, XeLaTeX, pLaTeX, and upLaTeX. The selected value is passed with the compile request, enabling a single external backend to support multiple compilation modes without requiring backend-specific handling in the editor.

Milestone 5b: Typesetting engine lifecycle in Chelys

In Milestone 4a, we introduced the recipe manager used to install and supervise local service providers. In this task, we extend the same lifecycle to typesetter recipes, allowing external typesetting backends to be installed, started, stopped, updated, and removed through Chelys.

When a typesetter service starts, Chelys publishes its provider configuration through the state shared with TeXlyre. TeXlyre observes this state and registers the corresponding typesetting compiler. When the service is stopped or removed, the provider is withdrawn and the compiler becomes unavailable again. Compiler availability in the editor therefore follows the actual state of the service without requiring a separate lifecycle in TeXlyre.

Typesetter service lifecycle across Chelys and TeXlyre

Starting a typesetter recipe publishes its provider configuration to the shared state, which TeXlyre observes to register or withdraw the corresponding compiler.

The backend runtime remains encapsulated by the recipe. A Docker recipe provides the full typesetting environment, whereas connect mode can attach to a compatible backend service that is already running. Both expose the same provider interface to TeXlyre, letting the editor-side compilation path remain agnostic of the service and how it is run or deployed.

In Task 3, we further extend this service model by enabling compatible Chelys services (tools) to be offered to collaborators over WebRTC.

Acknowledgements

This work was funded by NLnet Foundation as part of the TeXlyre project.

LaTeX WebAssembly Engine Modernization

· 6 min read
Fares Abawi
TeXlyre author & maintainer
Part of the NGI0 Core roadmap

This post reports on Task 1 of TeXlyre's NGI0 Commons grant. For the full project roadmap, see TeXlyre joins NGI0 Commons.

TeXlyre's in-browser LaTeX compilation has been upgraded from TeX Live 2020 to TeX Live 2026. LuaLaTeX now works alongside pdfLaTeX and XeLaTeX, and SyncTeX provides bidirectional navigation between source and PDF.

Background

TeXlyre originally used SwiftLaTeX, whose WebAssembly build was frozen at TeX Live 2020. This meant any LaTeX package released after 2020 would fail to compile in the browser, and LuaLaTeX was unavailable at all. Bundling a full TeX Live installation into the browser wasn't practical due to size, so we took inspiration from SwiftLaTeX's approach: a dedicated package server that serves individual packages on demand, paired with a modernized BusyTeX WebAssembly engine.

The work spans three repositories that together form the engine stack. Each link below goes to the full diff for that repository's contribution to this task.

Milestone 1a: Dynamic package downloading

Rather than bundling all required TeX Live collections into the WASM image as was previously done in BusyTeX, packages are now fetched from a dedicated TeX Live package server (see the texlyre-busytex-build diff for the server and kpse resolver implementation). A remote kpse resolver bridges the WebAssembly filesystem to the server, so when the engine requests a package during compilation, it's fetched, cached client-side, and served locally on subsequent runs. Cache misses are tracked explicitly to avoid redundant downloads, and ZIP-packaged collections are supported for environments where bulk loading is needed.

Integration with the application layer (engine selection, lazy loading, and cache handling) is in the texlyre and texlyre-busytex diffs.

Packages outside the bundled core are now fetched on demand, making any CTAN package available without rebuilding the engine or the bundle data.

Milestone 1b: LuaLaTeX and modern package compatibility

BusyTeX now builds against TeX Live 2026, with LuaTeX (LuaHBTeX) supported alongside pdfTeX and XeTeX. Multi-engine hyphenation generation and WASM format file rebuilding were both needed to make the new engines work properly across different languages. The build system changes are in the texlyre-busytex-build diff; the engine and multi-tool selection interface is in the texlyre-busytex diff.

Each of the three examples below targets a different capability or package introduced after TeX Live 2020: modern cross-referencing, accessibility tagging, and key-value table syntax

Cross-referencing with zref-clever

zref-clever is a cross-referencing package released on CTAN in 2022 and was not yet available in TeX Live 2020.

\documentclass{article}
\usepackage{zref-clever}
\usepackage{amsmath}

\begin{document}
\section{Introduction}\label{sec:intro}
\section{Equations}\label{sec:eq}
\begin{equation}\label{eq:pythagoras} a^2 + b^2 = c^2 \end{equation}
\begin{equation}\label{eq:euler} e^{i\pi} + 1 = 0 \end{equation}

\section{References}
See \zcref{sec:intro}.
See \zcref{eq:pythagoras,eq:euler}.
See \zcref{sec:intro,eq:pythagoras,sec:eq}.
\end{document}

Output, identical across pdflatex, lualatex, and xelatex:

See section 1. See equations (1) and (2). See sections 1 and 2 and equation (1).

zref-clever correctly groups the two section references together, separates the equation, and joins them with "and".

Accessibility and math tagging with ltx-talk

ltx-talk is a presentation class that uses LaTeX's \DocumentMetadata interface and the tagging pipeline to produce a structurally tagged PDF, including math content. This only compiles with full tagging capability under LuaLaTeX, which is itself the reason Milestone 1b was necessary, since prior to this upgrade, TeXlyre had no LuaLaTeX engine support.

\DocumentMetadata{tagging = on}
\documentclass{ltx-talk}

\IfFontExistsTF{Pennstander-Regular.otf}{
\setmainfont{Pennstander-Regular.otf}
\setmathfont{PennstanderMath-Regular.otf}
}{}

\begin{document}
\begin{frame}
\frametitle{Tagged math in the browser}
\[
\int_0^1 x^2 \, dx = \frac{1}{3}
\]
\end{frame}
\end{document}

The resulting PDF carries structural tags for both text and math, readable by screen readers and other assistive tools. Authoring accessible documents is now possible directly from the browser instead of requiring a local TeX installation.

Modern tables with tabularray

tabularray (first CTAN release in 2021) replaces tabular's positional column specifiers with a key-value syntax. It compiles under all three engines.

\documentclass{article}
\usepackage{xcolor}
\usepackage{tabularray}

\begin{document}
\begin{tblr}{
colspec = {Q[c] Q[c] Q[r]},
row{1} = {bg=gray!20, font=\bfseries},
hlines
}
Engine & Year & Status \\
pdfTeX & 2026 & Supported \\
LuaTeX & 2026 & Supported \\
XeTeX & 2026 & Supported \\
\end{tblr}
\end{document}

All dependencies (tabularray, xcolor, ninecolors, and their transitive requirements) are resolved at compile time via the on-demand package server.

Milestone 1c: SyncTeX bidirectional navigation

SyncTeX is implemented across three layers, with one diff per layer:

  • Engine layer (texlyre-busytex-build diff): SyncTeX generation enabled in the BusyTeX build, producing .synctex.gz output alongside the PDF.
  • API layer (texlyre-busytex diff): an interface for extracting the SyncTeX file within a compilation session.
  • UI layer (texlyre diff): a SyncTeX parser and source map service that decode the SyncTeX data into coordinates usable by the editor.It supports forward navigation (click in source, highlight in PDF) and reverse navigation (click in PDF, cursor jumps to source), integrated with both the PDF.js renderer and the canvas renderer.

SyncTeX source-to-PDF highlighting

SyncTeX forward navigation (only supported with BusyTeX engines): clicking the target button or double clicking in the source editor highlights the corresponding region in the rendered PDF.

Acknowledgements

This work was funded by NLnet Foundation as part of the TeXlyre project.

Introducing TeXlyre - Local-First Real-Time LaTeX Collaboration

· 7 min read
Fares Abawi
TeXlyre author & maintainer

TeXlyre is a local-first real-time LaTeX collaboration platform that enables researchers, academics, and teams to work together on scientific documents. Built with cutting-edge technologies including React, TypeScript, and Yjs, TeXlyre enables collaborative document editing with complete offline capabilities.