Untie is a pure-Go math renderer for TeX and Typst. It parses both input languages into one language-neutral representation, lays formulas out with a host-supplied OpenType MATH font, and returns a UI-independent display list of glyph paths, rules, source hits, and accessibility text.
- one renderer for TeX and Typst math;
- pure Go with
CGO_ENABLED=0; - no browser, DOM, GPU, platform text, or system-font dependency;
- deterministic layout and output;
- recoverable parsing with source diagnostics;
- core color policies for authored-color preservation, semantic mapping, and contrast correction;
- structured text-face and missing-fallback reporting;
- optional conservative pixel-grid snapping for thin rules and stems;
- source-mapped hit regions, caret stops, and explicit stable node IDs;
- OpenType MATH metrics, glyph outlines, variants, and assemblies;
- reusable rendering with bounded caches;
- inline and display layout, line breaking, equation tags, and overflow bounds;
- formula-scoped labels and host-resolved equation references;
- deterministic text, speech, and structured localization alternatives for accessibility;
- deterministic Presentation MathML export and a bounded strict importer;
- bounded
mhchem-style\ceand\pusupport without a chemistry database; - coalesced streaming layouts with stable display-list transitions;
- optional SVG and PNG output.
NewRenderer is the main API for applications. Load the font once, keep the
renderer, and call Render whenever the source or style changes.
import (
"context"
"os"
"github.com/caelyreth/untie"
"github.com/caelyreth/untie/render"
)
fontBytes, err := os.ReadFile("NewCMMath-Book.otf")
if err != nil {
return err
}
fonts, err := untie.LoadMathFont(fontBytes)
if err != nil {
return err
}
math, err := untie.NewRenderer(fonts, untie.RendererOptions{
DefaultStyle: untie.Style{Size: 24},
CacheEntries: 128,
})
if err != nil {
return err
}
result, err := math.Render(context.Background(), `x^2+\frac{1}{2}`, untie.RenderRequest{
Mode: untie.Display,
})
if err != nil {
// Recoverable parse diagnostics may still be present in result.
return err
}
err = render.Walk(result.Box, func(command render.Command) error {
switch command.Kind {
case render.CommandPath:
// Paint command.Path using command.At, command.Em, and command.Paint.
case render.CommandRule:
// Fill command.Rect with command.Paint.
}
return nil
})The renderer caches immutable parsed expressions when CacheEntries is
positive. It never reuses returned boxes, so each successful Render produces
an independent display list.
For ready-made output, use
encode/svg or encode/raster.
SVG supports deterministic vector export; the raster package provides
antialiased RGBA and PNG output without cgo.
Use mathml for Presentation MathML interchange. Export
covers every canonical IR node family. Import is intentionally limited to a
documented strict subset with structured diagnostics for unsupported input.
Use NewEngine when you need explicit engine ownership, direct canonical-IR
layout, or a custom parse/layout pipeline. It exposes the same layout core as
Renderer, without the convenience facade.
engine, err := untie.NewEngine(fonts, untie.Limits{})
if err != nil {
return err
}
expr := untie.ParseTeX(`\sum_{i=1}^{n} i^2`, untie.Display, untie.ParseOptions{})
box, err := engine.Layout(expr, untie.Style{Size: 24})See Getting Started for the complete integration pipeline and Rendering for the drawing contract.
The optional contrib/mygo adapter renders directly to MyGo
elements and plugs into Markdown math:
math, err := untiemygo.New(fonts, untiemygo.Options{
Dialect: untie.TeX,
CacheEntries: 128,
})
if err != nil {
return err
}
ui.Column(c).Children(func() {
math.Element(c, source, untie.Display).FillWidth()
})BindMarkdown adds $...$, $$...$$, \(...\), and \[...\] support to a
MyGo Markdown view. See the
MyGo integration guide for direct elements,
Markdown binding, and existing-box drawing.
- Runnable Examples
- Website and Documentation Project
- Getting Started
- Core Concepts
- Rendering
- Streaming
- MathML Interchange
- Editor Integration
- Fonts
- Parsing
- MyGo Integration
- Supported TeX
- TeX Chemistry
- Supported Typst
- API Stability
- Migrating to 0.3
- Migrating to 0.4
- Migrating to 0.5
- Release Process
- Security Policy
- Full Documentation Index
v0.5.0 is the latest published release.
Untie remains pre-1.0 while its API stability tiers are validated through real
integrations. Release notes are generated from Conventional Commits and
published in GitHub Releases;
see Release Process for the maintainer workflow.
Copyright 2026 Yu (Caelyreth).
Untie is dual-licensed under either:
- the MIT License;
- the Apache License, Version 2.0.
You may choose either license at your option.
The SPDX expression for original project material is MIT OR Apache-2.0.
Third-party material remains under its own license; see Third-Party Licenses.