Take any AI's output without it breaking.

MODU is a normalization and typesetting engine for LLM output — the tangle of Markdown, LaTeX, tables and code that every other renderer assumes away. It arbitrates the boundary first, then typesets.

raw paste
The laptop sold for $999. The span `price = $x * 2` is code. But $y = x^2$ is math.
MODU

The laptop sold for $999. The span price = $x * 2 is code. But y=x2\displaystyle y = x^2 is math.

Why

Every other renderer assumes a human wrote valid source. MODU assumes an LLM didn't.

TeX, KaTeX, browsers, PreTeXt — all of them were born to typeset source a person wrote on purpose. Model output is not that. It is half-closed, mixed-syntax, delimiter-optional slop, and it is the input MODU was designed for first, not patched for later.

Built to swallow output from

  • ChatGPT
  • Claude
  • Gemini
  • Copilot
  • Llama
  • HWP(X)

What the engine actually does

Tables that survive math

A | inside $-\ln|\cos x|$ is an absolute value, not a column break. Splitting cells on | first is why table math breaks everywhere else.

raw paste
| Function | Derivative | Integral |
|:--:|:--:|:--:|
| $\tan x$ | $\sec^2 x$ | $-\ln|\cos x|$ |
| $f(x)=|x|$ | $\mathrm{sgn}(x)$ | $\frac{1}{2}x|x|$ |
MODU
FunctionDerivativeIntegral
tanx\displaystyle \tan xsec2x\displaystyle \sec^2 xlncosx\displaystyle -\ln|\cos x|
f(x)=x\displaystyle f(x)=|x|sgn(x)\displaystyle \mathrm{sgn}(x)12xx\displaystyle \frac{1}{2}x|x|

Arbitration, not just rendering

Markdown and LaTeX fight over the same characters — | _ * $ \. Deciding who owns each one is the whole job, and it happens before anything renders. Headings, bold, lists and math all come out of the same tangled string.

raw paste
# Quadratic roots

**The formula**:

$$x = \frac{-b \pm \sqrt{b^2-4ac}}{2a}$$

1. Compute $D = b^2 - 4ac$
2. If $D > 0$, two distinct real roots

- first item
- second *item*
MODU

Quadratic roots

The formula:

x=b±b24ac2ax = \frac{-b \pm \sqrt{b^2-4ac}}{2a}
  1. Compute D=b24ac\displaystyle D = b^2 - 4ac
  2. If D>0\displaystyle D > 0, two distinct real roots
  • first item
  • second item

Math with no delimiters

Models drop raw LaTeX straight into prose with no $ at all. MODU detects it on language boundaries, wraps it, and renders it anyway.

raw paste
The line through them is \ell(x) = 3x + 3, and the discriminant is \frac{-b}{2a}.
MODU

The line through them is (x)=3x+3\displaystyle \ell(x) = 3x + 3, and the discriminant is b2a\displaystyle \frac{-b}{2a}.

Whatever delimiter the model felt like

$…$, \(…\), \[…\] — every model has its own habit, and some change habits mid-answer. All of it normalizes to one form.

raw paste
Inline \(a^2+b^2=c^2\) and the block form:

\[E = mc^2\]
MODU

Inline a2+b2=c2\displaystyle a^2+b^2=c^2 and the block form:

E=mc2E = mc^2

The $ that isn't math

$999 is a price. `price = $x` is code. $y = x^2$ is math. One character, three different answers, decided by context.

raw paste
The laptop sold for $999. The span `price = $x * 2` is code. But $y = x^2$ is math.
MODU

The laptop sold for $999. The span price = $x * 2 is code. But y=x2\displaystyle y = x^2 is math.

Unfinished input is fine

Streaming output arrives half-written — an open $$, an unclosed **. MODU typesets what already closed and leaves the rest as text, instead of throwing the document away.

raw paste
The probability is:

$$P(A) = \frac{1}{2}$$

and the next one is $$P(B) = \frac{1{
MODU

The probability is:

P(A)=12P(A) = \frac{1}{2}

and the next one is P(B) = \frac{1{

At scale

Fifty thousand characters. One pass. Zero errors.

No headings, no bold — just Korean and English prose with hundreds of formulas, block equations jammed against paragraphs on purpose. MODU typeset the whole document live in your browser just now. Scroll it.

Usage

String in, HTML out.

No framework, no store, no DOM required. The engine depends on katex and jszip and nothing else, so it runs at build time on the server or live in the browser — every example above was typeset by MODU when this page was built.

Not published to npm yet — the engine is being hardened first.

modu
import { renderContentToHtml } from "modu";

// Is the | inside that cell an absolute value, or a column break?
// The engine decides before anything renders.
const html = renderContentToHtml(
  "| $f(x)=|x|$ | $\\frac{1}{2}x|x|$ |\n|---|---|\n| a | b |"
);

Playground

Paste something that breaks.

Real output from ChatGPT, Claude, Gemini — or one of the adversarial cases below. It renders as you type, in your browser.