Skip to content
caelyrethPublic

About

Pure-Go TeX and Typst math renderer for native UIs and MyGo

Topics

Resources

Contributing

Security policy

Accessibility

Stars

59 stars

Watchers

0 watching

Forks

Latest commit

 

History

555 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Untie

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.

Properties

  • 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 \ce and \pu support without a chemistry database;
  • coalesced streaming layouts with stable display-list transitions;
  • optional SVG and PNG output.

Use

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.

Lower-Level API

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.

MyGo

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.

Documentation

Release

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.

License

Copyright 2026 Yu (Caelyreth).

Untie is dual-licensed under either:

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.

About

Pure-Go TeX and Typst math renderer for native UIs and MyGo

Topics

Resources

Contributing

Security policy

Accessibility

Stars

59 stars

Watchers

0 watching

Forks

Releases

Contributors

Languages