This project compiles LaTeX math formulas into browser-native MathML Core markup. Through compile-time conversion, it bypasses client-side layout engines to achieve zero-overhead formula rendering.
Key Features:
- High Performance: Compiles TeX formulas directly to native MathML. Processing speed exceeds 300,000 operations per second, 3 times faster than KaTeX and 40 times faster than MathJax.
- Lightweight: Core package size is 8.95 KB (4.62 KB gzipped) with zero external dependencies.
- Zero Runtime Overhead: Relies entirely on the browser's native engine for layout, eliminating client-side JavaScript formatting libraries.
- Robust Fault Tolerance: Catches syntax errors (such as unclosed braces) and reverts to raw TeX string output to prevent application crashes.
- High Compatibility: Generates standard MathML tags suitable for Server-Side Rendering (SSR), Static Site Generation (SSG), and Client-Side Rendering (CSR).
import mathml from "@webc.site/math";
// Second parameter set to true renders block style
const html = mathml("e^{i\\pi} + 1 = 0", true);import mdMath from "@webc.site/math/md.js";
import compile from "@webc.site/math";
const html = mdMath("Euler's identity: $$e^{i\\pi} + 1 = 0$$", compile);MathML layout relies on OpenType Math fonts containing dedicated mathematical metrics (the MATH table) to correctly handle radical scaling, delimiter stretching (e.g., parentheses, braces), fraction line thickness, and sub/superscript alignments.
The classic TeX math font Latin Modern Math (derived from Donald Knuth's Computer Modern family) is recommended.
Import the Latin Modern Math font stylesheet from the 18s font package (which registers the font family name as m):
In CSS:
@import url("https://registry.npmmirror.com/18s/0.2.24/files/m.css");Or in HTML <head>:
<link rel="stylesheet" href="https://registry.npmmirror.com/18s/0.2.24/files/m.css" />To include the body text font (t) and monospace code font (c) along with the math font, import the complete stylesheet:
<link rel="stylesheet" href="https://registry.npmmirror.com/18s/0.2.24/files/_.css" />Download the Latin Modern Math WOFF2 font file and declare @font-face:
@font-face {
font-family: "Latin Modern Math";
src: url("/fonts/latinmodern-math.woff2") format("woff2");
font-style: normal;
font-display: swap;
}Declare the font stack and inherit text color for <math> elements:
math {
font-family: m, "Latin Modern Math", "Cambria Math", math, sans-serif;
color: inherit;
}m: Latin Modern Math declared viam.css"Latin Modern Math": Self-hosted or system-installed Latin Modern Math"Cambria Math": Built-in Windows system math fontmath: W3C CSS Fonts generic math font family keyword (natively supported in modern browsers)sans-serif: Final sans-serif fallback
Compiled block formulas contain the display="block" attribute. To prevent wide formulas from overflowing containers on mobile or narrow screens, configure horizontal scrolling and centering:
math[display="block"] {
display: block;
max-width: 100%;
overflow-x: auto;
overflow-y: hidden;
margin: 1em auto;
padding: 0.5em 0;
text-align: center;
}This project provides extension plugins for mainstream Markdown parsers to render TeX formulas directly to MathML markup during compilation/building.
Installation:
npm install @webc.site/math-markdown-itUsage:
import markdownit from "markdown-it";
import mathMarkdownIt from "@webc.site/math-markdown-it";
const md = markdownit().use(mathMarkdownIt);
const html = md.render("Inline math: $E = mc^2$ and block math: \n$$\n\\frac{a}{b}\n$$");
console.log(html);Installation:
npm install @webc.site/math-markedUsage:
import { marked } from "marked";
import mathMarked from "@webc.site/math-marked";
marked.use(mathMarked());
const html = marked.parse("Inline math: $E = mc^2$ and block math: \n$$\n\\frac{a}{b}\n$$");
console.log(html);Installation:
npm install @webc.site/math-remarkUsage:
import { unified } from "unified";
import remarkParse from "remark-parse";
import remarkMath from "remark-math";
import mathRemark from "@webc.site/math-remark";
import remarkHtml from "remark-html";
const processor = unified()
.use(remarkParse)
.use(remarkMath)
.use(mathRemark)
.use(remarkHtml, { sanitize: false });
const html = await processor.process(
"Inline math: $E = mc^2$ and block math: \n$$\n\\frac{a}{b}\n$$",
);
console.log(String(html));The compiler extracts TeX formulas from input Markdown text, tokenizes and parses them, and translates the AST to semantic MathML markup.
graph TD
Input[Input Markdown] --> Scanner[Scanner: Locates Delimiters]
Scanner -->|Plain Text| Buffer[Output Buffer]
Scanner -->|TeX Formula| Lexer[Lexer: Tokenizes Input]
Lexer --> Parser[Parser: Builds AST]
Parser --> Codegen[Codegen: Translates to MathML Tags]
Codegen --> Wrapper[Semantic Wrapper]
Wrapper --> MathML[MathML Output]
Buffer --> Output[Final HTML]
MathML --> Output
- Build & Test Environment: Bun, Node.js
- Linter & Formatter: oxlint, oxfmt
- Build Tool: Vite, Rolldown, Lightning CSS
.
├── demo/ # Interactive demo page
├── extract/ # Test cases extraction scripts
├── lib/ # Compiled distribution files
│ ├── mathml.js # Core compiler (minified)
│ └── md.js # Markdown math formula parser (minified)
├── src/ # Source code
│ ├── const/ # Tokens, AST types, symbols, and functions constants
│ ├── lex.js # LaTeX lexer
│ ├── parse.js # LaTeX parser (AST builder)
│ ├── mathml.js # Core TeX-to-MathML compiler
│ └── md.js # Markdown parser entry
├── sh/ # Scripts
└── test.sh # Quality verification and test runner
The W3C published the MathML 1.0 specification in 1998 to standardize mathematical notation on the web. However, the complexity of the specification placed a maintenance burden on browser layout engines.
In 2013, the Chromium team removed the unfinished MathML rendering implementation from the Blink engine due to maintenance costs and security vulnerabilities. Web developers subsequently relied on client-side JavaScript libraries (such as MathJax and KaTeX) to simulate formula layout. These libraries increased bundle sizes and consumed client-side CPU resources, impacting page load times and rendering performance.
To resolve this issue, organizations like Igalia and Mozilla refactored the specification into the MathML Core standard, focusing on essential, implementable parts backed by Web Platform Tests.
In January 2023, Chrome 109 reintroduced support for the MathML Core specification. With Blink, Gecko, and WebKit all natively supporting this subset, web browsers achieved consistent native MathML rendering. This project compiles TeX directly to native MathML markup at compile time, eliminating client-side layout engines and avoiding client-side rendering overhead.
本项目将 LaTeX 数学公式编译为浏览器原生支持的 MathML Core 标记。通过编译期转换,无需客户端排版引擎,实现零运行时开销的公式渲染。
核心特性:
- 高性能:TeX 公式直接转换为原生 MathML 标签,处理速度达每秒 300,000 次以上
- 轻量化:核心包体积 8.95 KB(Gzip 压缩后 4.62 KB),无外部依赖
- 零运行开销:完全依赖浏览器原生引擎排版与渲染
- 高容错性:自动捕获语法错误,降级输出原始 TeX 字符串
- 强兼容性:生成标准 MathML 标签,适配 SSR、SSG 和 CSR
import mathml from "@webc.site/math";
// 第二参数为 true 表示渲染为块级公式
const html = mathml("e^{i\\pi} + 1 = 0", true);import mdMath from "@webc.site/math/md.js";
import compile from "@webc.site/math";
const html = mdMath("欧拉恒等式:$$e^{i\\pi} + 1 = 0$$", compile);浏览器排版 MathML 依赖包含数学排版度量(OpenType Math 表)的数学字体,用于呈现根号伸缩、大括号拉伸、分式厚度与上下标对齐。
推荐使用 TeX 经典数学字体 Latin Modern Math(源自 Computer Modern 字体家族)。
通过 18s 字体包在线引入 Latin Modern Math 样式(该样式将 Latin Modern Math 声明为字体族 m):
在 CSS 中引入:
@import url("https://registry.npmmirror.com/18s/0.2.24/files/m.css");或在 HTML <head> 中引入:
<link rel="stylesheet" href="https://registry.npmmirror.com/18s/0.2.24/files/m.css" />若同时需要页面正文字体(t)与代码等宽字体(c),可直接引用完整样式表:
<link rel="stylesheet" href="https://registry.npmmirror.com/18s/0.2.24/files/_.css" />下载 Latin Modern Math 字体文件(WOFF2 格式),通过 @font-face 声明:
@font-face {
font-family: "Latin Modern Math";
src: url("/fonts/latinmodern-math.woff2") format("woff2");
font-style: normal;
font-display: swap;
}为 <math> 标签配置字体族与继承颜色:
math {
font-family: m, "Latin Modern Math", "Cambria Math", math, sans-serif;
color: inherit;
}m:m.css声明的 Latin Modern Math 网页字体"Latin Modern Math":本地托管或系统安装的 Latin Modern Math 字体"Cambria Math":Windows 系统内置数学字体math:CSS Fonts 规范定义的数学通用字体族关键字(现代主流浏览器原生支持)sans-serif:无衬线回退字体
块级公式编译后带有 display="block" 属性。为防止长公式超出容器或在移动端撑破页面,推荐配置横向滚动与居中样式:
math[display="block"] {
display: block;
max-width: 100%;
overflow-x: auto;
overflow-y: hidden;
margin: 1em auto;
padding: 0.5em 0;
text-align: center;
}本项目为各大主流 Markdown 解析器提供了扩展插件,可在编译/构建时直接将 TeX 公式渲染为原生 MathML 标记。
安装:
npm install @webc.site/math-markdown-it使用方法:
import markdownit from "markdown-it";
import mathMarkdownIt from "@webc.site/math-markdown-it";
const md = markdownit().use(mathMarkdownIt);
const html = md.render("行内公式: $E = mc^2$ 和 块级公式: \n$$\n\\frac{a}{b}\n$$");
console.log(html);安装:
npm install @webc.site/math-marked使用方法:
import { marked } from "marked";
import mathMarked from "@webc.site/math-marked";
marked.use(mathMarked());
const html = marked.parse("行内公式: $E = mc^2$ 和 块级公式: \n$$\n\\frac{a}{b}\n$$");
console.log(html);安装:
npm install @webc.site/math-remark使用方法:
import { unified } from "unified";
import remarkParse from "remark-parse";
import remarkMath from "remark-math";
import mathRemark from "@webc.site/math-remark";
import remarkHtml from "remark-html";
const processor = unified()
.use(remarkParse)
.use(remarkMath)
.use(mathRemark)
.use(remarkHtml, { sanitize: false });
const html = await processor.process("行内公式: $E = mc^2$ 和 块级公式: \n$$\n\\frac{a}{b}\n$$");
console.log(String(html));编译器从输入文本中提取 TeX 公式,依次通过扫描、词法分析、语法分析,最终生成语义化 MathML 标记。
graph TD
Input[输入文本] --> Scanner[扫描器: 定界符定位]
Scanner -->|普通文本| Buffer[输出缓冲区]
Scanner -->|TeX 公式| Lexer[词法分析: 生成 Token]
Lexer --> Parser[语法分析: 生成 AST]
Parser --> Codegen[代码生成: 映射 MathML 标签]
Codegen --> Wrapper[语义包装]
Wrapper --> MathML[MathML 输出]
Buffer --> Output[最终 HTML]
MathML --> Output
- 运行环境:Node.js, Bun
- 构建工具:Rolldown, Vite
- 样式处理:Lightning CSS
- 代码质量:oxlint, oxfmt
.
├── lib/ # 编译产物目录
│ ├── mathml.js # 核心编译器
│ └── md.js # Markdown 公式解析器
├── src/ # 源代码
│ ├── const/ # Token、AST 节点、符号和函数常量定义
│ ├── lex.js # LaTeX 词法分析器
│ ├── parse.js # LaTeX 语法分析器
│ ├── mathml.js # TeX 至 MathML 核心编译器
│ └── md.js # Markdown 公式解析入口
├── demo/ # 演示页面
├── extract/ # 测试用例提取脚本
└── sh/ # 构建脚本
1998 年,W3C 发布 MathML 1.0 规范,旨在提供万维网数学公式的标准排版方案。由于早期规范复杂,给浏览器排版引擎带来维护负担。
2013 年,Chromium 团队因维护成本与安全漏洞考量,移除了 Blink 引擎中的 MathML 渲染代码。网页公式排版转为依赖第三方 JavaScript 库(如 MathJax、KaTeX)模拟公式布局。
2023 年 1 月,Chrome 109 重新支持 MathML Core 标准,Blink、Gecko 和 WebKit 三大主流浏览器引擎实现原生 MathML 渲染支持。本项目在此背景下开发,将 TeX 在构建期或服务端直接编译为原生 MathML 标记。