@webc.site/math 0.1.13 → 0.1.18

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/README.md +303 -322
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -3,6 +3,7 @@
3
3
  ---
4
4
 
5
5
  <a id="en"></a>
6
+
6
7
  # @webc.site/math
7
8
 
8
9
  ### The world's smallest and fastest web Markdown formula renderer
@@ -13,40 +14,81 @@
13
14
  &nbsp;&nbsp;
14
15
  <a href="https://math.webc.site" target="_blank"><img src="https://raw.githubusercontent.com/webc-site/math/dev/readme/en/svg/badge.demo.svg" alt="demo" /></a>
15
16
 
16
- Say goodbye to hundreds of KB of KaTeX/MathJax and bloated CSS/fonts! With an ultra-lightweight size of just ~4KB (Gzipped), it instantly compiles LaTeX equations into native MathML supported by all modern browsers, delivering zero-overhead, lightning-fast rendering.
17
+ No need to load hundreds of KB of KaTeX/MathJax and large font packages. At just ~4KB (Gzipped), it compiles LaTeX equations into native MathML supported by modern browsers, achieving zero-overhead rendering.
17
18
 
19
+ - [Core Advantages](#core-advantages)
20
+ - [What is MathML?](#what-is-mathml)
21
+ - [Why Compile TeX Formulas to MathML?](#why-compile-tex-formulas-to-mathml)
22
+ - [Benchmark](#benchmark)
23
+ - [1. Size Comparison (Gzipped)](#1-size-comparison-gzipped)
24
+ - [2. Generation Speed (Ops/sec)](#2-generation-speed-opssec)
18
25
  - [Usage](#usage)
19
- - [JavaScript Example](#javascript-example)
26
+ - [JavaScript Examples](#javascript-examples)
20
27
  - [Markdown Parser Plugins](#markdown-parser-plugins)
21
28
  - [CSS and Math Font Configuration](#css-and-math-font-configuration)
22
29
  - [Features](#features)
23
30
  - [Supported Syntax List](#supported-syntax-list)
24
- - [Unsupported Syntax (Non-Goals)](#unsupported-syntax-non-goals)
31
+ - [Unsupported Syntax](#unsupported-syntax)
25
32
  - [Error Handling and Fault Tolerance](#error-handling-and-fault-tolerance)
26
33
  - [Internal Error Codes](#internal-error-codes)
27
- - [What is MathML?](#what-is-mathml)
28
- - [Why Compile TeX Formulas to MathML?](#why-compile-tex-formulas-to-mathml)
29
- - [Benchmark](#benchmark)
30
- - [1. Size Comparison (Gzipped)](#1-size-comparison-gzipped)
31
- - [2. Generation Speed (Ops/sec)](#2-generation-speed-opssec)
32
- - [Design and Calling Process](#design-and-calling-process)
33
- - [Module Flow](#module-flow)
34
- - [How to Add Syntax Support](#how-to-add-syntax-support)
35
- - [1. Constants](#1-constants)
34
+ - [Design and Workflow](#design-and-workflow)
35
+ - [Module Stages](#module-stages)
36
+ - [Adding New Syntax](#adding-new-syntax)
37
+ - [1. Constant Definitions](#1-constant-definitions)
36
38
  - [2. Lexer](#2-lexer)
37
39
  - [3. Parser](#3-parser)
38
- - [4. Renderer](#4-renderer)
40
+ - [4. Codegen](#4-codegen)
39
41
  - [Tech Stack](#tech-stack)
40
42
  - [Directory Structure](#directory-structure)
41
- - [History and Background](#history-and-background)
43
+ - [Historical Background](#historical-background)
44
+
45
+ ## Core Advantages
46
+
47
+ ### What is MathML?
48
+
49
+ MathML (Mathematical Markup Language) is an XML-based standard for describing math formulas on the Web.
50
+ Since January 2023 (following Chrome 109's native support for MathML Core), all major browser engines (Blink, Gecko, WebKit) natively support MathML. Pages can render formulas without loading third-party JavaScript layout libraries.
51
+
52
+ ### Why Compile TeX Formulas to MathML?
53
+
54
+ While MathML renders natively, its XML-based syntax is too verbose for direct writing. TeX remains the standard for authoring formulas (e.g., `$e^{i\pi} + 1 = 0$`).
55
+ Traditional solutions (like MathJax or KaTeX) require loading hundreds of KB of JS/CSS layout engines and consume CPU for DOM calculations.
56
+ `@webc.site/math` compiles TeX to MathML, offering several advantages for Client-Side Rendering (CSR):
57
+
58
+ - **Lightweight**: Only 7.78 KB raw size (3.58 KB gzipped), with zero footprint on initial page load times.
59
+ - **Zero Runtime Dependencies**: Performs translation at compile time, delegating all rendering, positioning, and layout to the browser's native C++ engine. No JS layout engine runs on the client.
60
+ - **Low CPU Overhead**: Designed for high-frequency rendering scenarios like WYSIWYG editors, running smoothly even on low-end mobile devices.
61
+ - **SSR-Friendly**: Outputs standard HTML MathML tags, working identically for client-side dynamic rendering or static server-side building (SSR/SSG).
62
+
63
+ ## Benchmark
64
+
65
+ ### 1. Size Comparison (Gzipped)
66
+
67
+ | Library | Raw Size | Gzip Size | Size Ratio |
68
+ | :---------------------------------------------------------- | :-------: | :-------: | :--------: |
69
+ | [@webc.site/math](https://github.com/webc-site/math) (Ours) | 7.78 KB | 3.58 KB | 1.0 ⭐️ |
70
+ | [KaTeX](https://github.com/KaTeX/KaTeX) | 264.79 KB | 75.15 KB | 21.0 |
71
+ | [MathJax](https://github.com/mathjax/MathJax) | 971.04 KB | 278.39 KB | 77.7 |
72
+
73
+ ![](demo/size.svg)
74
+
75
+ ### 2. Generation Speed (Ops/sec)
76
+
77
+ Based on compiling standard test equations (measured using [sh/bench/pk.js](https://github.com/webc-site/math/blob/dev/sh/bench/pk.js)):
78
+
79
+ - **@webc.site/math (Ours)**: ~329,000 ops/s (1.0 ⭐️)
80
+ - **[KaTeX](https://github.com/KaTeX/KaTeX)**: ~92,000 ops/s (~3.6x slower)
81
+ - **[MathJax](https://github.com/mathjax/MathJax)**: ~6,700 ops/s (~48.8x slower)
82
+
83
+ ![](demo/speed.svg)
42
84
 
43
85
  ## Usage
44
86
 
45
- ### JavaScript Example
87
+ ### JavaScript Examples
46
88
 
47
89
  #### 1. Render TeX Formulas Directly
48
90
 
49
- Using `@webc.site/math`. Compiles TeX formulas directly to MathML. Useful for implementing math rendering plugins for Markdown parsers (e.g., markdown-it, marked).
91
+ Use `@webc.site/math` to compile TeX formulas directly into MathML (ideal for Markdown parser plugins):
50
92
 
51
93
  ```javascript
52
94
  import mathml from "@webc.site/math";
@@ -57,7 +99,7 @@ const html = mathml(tex, true); // true for block math, false/empty for inline m
57
99
 
58
100
  #### 2. Replace Formulas in Markdown
59
101
 
60
- Using `@webc.site/math/md.js`. Parses Markdown text, automatically identifying and replacing inline/block equations with MathML. Pass the formula compiler (e.g. `@webc.site/math`) as the second argument.
102
+ Use `@webc.site/math/md.js` to automatically detect and replace inline/block formulas in Markdown text with MathML (requires passing the math compiler):
61
103
 
62
104
  ```javascript
63
105
  import mdMath from "@webc.site/math/md.js";
@@ -74,7 +116,7 @@ console.log(html);
74
116
 
75
117
  #### 1. Marked Extension
76
118
 
77
- Using [`@webc.site/math-marked`](https://www.npmjs.com/package/@webc.site/math-marked). Automatically parses and compiles inline math (`$...$`) and block math (`$$...$$`) inside markdown parsed with `marked`.
119
+ Use [`@webc.site/math-marked`](https://www.npmjs.com/package/@webc.site/math-marked) to automatically parse and compile inline (`$...$`) and block (`$$...$$`) formulas:
78
120
 
79
121
  ```javascript
80
122
  import { marked } from "marked";
@@ -87,7 +129,7 @@ const html = marked.parse("Euler's identity: $$e^{i\\pi} + 1 = 0$$");
87
129
 
88
130
  #### 2. Remark Plugin
89
131
 
90
- Using [`@webc.site/math-remark`](https://www.npmjs.com/package/@webc.site/math-remark). A `unified` / `remark` plugin to transform math nodes (`inlineMath` and `math`) in the AST into native MathML HTML.
132
+ Use [`@webc.site/math-remark`](https://www.npmjs.com/package/@webc.site/math-remark) to replace `inlineMath` and `math` nodes in Unified/Remark AST with native MathML HTML:
91
133
 
92
134
  ```javascript
93
135
  import { unified } from "unified";
@@ -106,7 +148,7 @@ const html = await unified()
106
148
 
107
149
  #### 3. Markdown-it Plugin
108
150
 
109
- Using [`@webc.site/math-markdown-it`](https://www.npmjs.com/package/@webc.site/math-markdown-it). A `markdown-it` plugin to automatically parse and compile inline math (`$...$`) and block math (`$$...$$`) into native MathML HTML.
151
+ Use [`@webc.site/math-markdown-it`](https://www.npmjs.com/package/@webc.site/math-markdown-it) to automatically parse and render inline/block formulas in `markdown-it`:
110
152
 
111
153
  ```javascript
112
154
  import markdownit from "markdown-it";
@@ -119,11 +161,11 @@ const html = md.render("Euler's identity: $$e^{i\\pi} + 1 = 0$$");
119
161
 
120
162
  ### CSS and Math Font Configuration
121
163
 
122
- For browser mathematical layout engines to present beautifully typeset math equations, we highly recommend using a math font. The **Latin Modern Math** font provided in the `18s` package is recommended (derived from Knuth's classical Computer Modern typeface, with a complete mathematical symbol set and OpenType MATH table support).
164
+ To ensure beautifully typeset browser-native math equations, using a math font is recommended. We recommend the **Latin Modern Math** font from the `18s` package (derived from Donald Knuth's classical Computer Modern, supporting OpenType MATH table features).
123
165
 
124
166
  #### 1. Online Reference (Recommended)
125
167
 
126
- You can import the online font directly in your CSS:
168
+ Import the online font in CSS:
127
169
 
128
170
  ```css
129
171
  /* Import the bundle (includes Source Han Sans t, monospace c, and math font m) */
@@ -144,7 +186,7 @@ npm install 18s
144
186
 
145
187
  ##### Import Local Font
146
188
 
147
- Depending on your project setup, choose one of the following methods to import the font mappings (Note: do not mix JS and CSS imports in the same file):
189
+ Choose one of the following methods (Note: do not mix JS and CSS imports):
148
190
 
149
191
  ###### Method 1: Import in JS/TS Entry File
150
192
 
@@ -174,32 +216,37 @@ Or import math font `m` only:
174
216
 
175
217
  #### 3. Configure CSS Style
176
218
 
177
- Set the `math` tag to use font family alias `m` (where `t` is Source Han Sans, optimized with font slicing for Chinese characters) in your global CSS styles:
219
+ Set the font family for the `math` tag in your global CSS stylesheet.
220
+
221
+ ##### Option A: Using Hosted/Local Fonts (Recommended for best visual quality)
222
+
223
+ For projects importing the `18s` font assets (which contains the optimized math font `m` and Source Han Sans `t`):
178
224
 
179
225
  ```css
180
226
  math {
181
- /* m is the math font, t is Source Han Sans (optimized with font slicing for Chinese characters to boost loading performance), sans-serif is default fallback */
182
- font-family: m, t, sans-serif;
227
+ /* m is the math font, t is Source Han Sans (optimized with font slicing for Chinese characters to boost loading performance), math is system math font, sans-serif is default fallback */
228
+ font-family: m, t, math, sans-serif;
183
229
  }
184
230
  ```
185
231
 
186
- ## Features
232
+ ##### Option B: Using System Math Fonts (Zero external font assets)
187
233
 
188
- - **Highly Complete Features**: Extracted and compiled thousands of mathematical formulas from KaTeX and MathJax official test suites, passing all test cases successfully (see [extract](https://github.com/webc-site/math/tree/dev/extract) for details).
189
- - **Robust & Fault-Tolerant**: When parsing Markdown text, syntax errors (such as unclosed `\left`/`\right` or invalid syntax) are caught automatically and gracefully degraded, returning the raw TeX code to prevent application crashes.
190
- - **Fast Compiler**: Compiles TeX formulas directly to semantic MathML without external parser dependencies.
191
- - **Markdown Integration**: Automatically parses inline math (`$formula$`) and block math (`$$formula$$`) in Markdown text.
192
- - **High Performance**: Only 7.78 KB raw size (3.58 KB gzipped), far smaller than KaTeX and MathJax (see size comparison chart below):
234
+ Leverage system-default math fonts to minimize loading size:
193
235
 
194
- | Library | Raw Size | Gzip Size | Size Ratio |
195
- | :---------------------------------------------------------- | :-------: | :-------: | :--------: |
196
- | [@webc.site/math](https://github.com/webc-site/math) (Ours) | 7.78 KB | 3.58 KB | 1.0 ⭐️ |
197
- | [KaTeX](https://github.com/KaTeX/KaTeX) | 264.79 KB | 75.15 KB | 21.0 |
198
- | [MathJax](https://github.com/mathjax/MathJax) | 971.04 KB | 278.39 KB | 77.7 |
236
+ ```css
237
+ math {
238
+ /* Prioritize system-built-in math fonts, fallback to standard CSS 'math' generic font family */
239
+ font-family: "STIX Two Math", "Latin Modern Math", "Cambria Math", math;
240
+ }
241
+ ```
199
242
 
200
- ![](demo/size.svg)
243
+ ## Features
201
244
 
202
- - **Standard Compatibility**: Outputs valid MathML elements supported by modern browser layout engines.
245
+ - **Highly Complete**: Successfully compiles thousands of math formulas from KaTeX/MathJax official test suites (see [extract](https://github.com/webc-site/math/tree/dev/extract)).
246
+ - **Fault-Tolerant**: Syntax errors (such as unclosed `\left`/`\right`) are automatically caught and degraded to display raw TeX code, preventing application crashes.
247
+ - **Fast Compiler**: Compiles TeX formulas directly to semantic MathML without external parser dependencies.
248
+ - **Markdown Integration**: Automatically parses inline math (`$formula$`) and block math (`$$formula$$`) in Markdown text.
249
+ - **Standard Compatibility**: Outputs valid MathML elements supported natively by modern browsers.
203
250
 
204
251
  ## Supported Syntax List
205
252
 
@@ -209,55 +256,55 @@ Designed to be extremely lightweight, this library supports the most commonly us
209
256
  - **Subscripts & Superscripts**:
210
257
  - Superscript `^` (e.g., `x^2`)
211
258
  - Subscript `_` (e.g., `x_i`)
212
- - Simultaneous subscripts/superscripts (e.g., `x_i^2` or `x^2_i`)
213
- - Big operators automatically render limits layout for subscripts and superscripts (e.g., `\sum_{i=1}^n`, `\int_a^b`)
259
+ - Both subscripts and superscripts (e.g., `x_i^2` or `x^2_i`)
260
+ - Subscripts/superscripts of sum, integration, and other big operators will automatically appear in limits form (e.g., `\sum_{i=1}^n`, `\int_a^b`)
214
261
  - **Fractions**: `\frac{numerator}{denominator}` (e.g., `\frac{a}{b}`)
215
- - **Square Roots**: Square root `\sqrt{x}` and $n$-th root `\sqrt[n]{x}`
262
+ - **Roots**: Square root `\sqrt{x}` and $n$-th root `\sqrt[n]{x}`
216
263
  - **Overlines & Bars**: `\overline{x}` and the shorthand `\bar{x}`
217
- - **Adaptive Delimiters**: `\left` and `\right` structures for autosizing delimiters (e.g., `\left( ... \right)`). Supported delimiters include:
264
+ - **Delimiters & Brackets**: `\left` and `\right` structures (e.g., `\left( ... \right)`). Supported delimiters include:
218
265
  - Parentheses: `(` and `)`
219
266
  - Square brackets: `[` and `]`
220
- - Curly braces: `\{` and `\}`
221
- - Angle brackets: `<` (⟨) and `>` (⟩)
267
+ - Braces: `\{` and `\}`
268
+ - Angle brackets: `<` and `>`
222
269
  - Vertical bars: `|` or `\|`
223
- - Null/Empty delimiter: `.` (shows no delimiter on that side, e.g., `\left. \frac{df}{dx} \right| _0`)
270
+ - Empty delimiter: `.` (hides the delimiter on that side, e.g., `\left. \frac{df}{dx} \right| _0`)
224
271
  - **Text Mode**: `\text{...}` (e.g., `\text{if }`), extracts literal text inside braces and renders it as MathML `<mtext>` in normal upright font.
225
- - **Horizontal Spacing**: Supports `\quad` (1em space) and `\qquad` (2em space) horizontal spacing.
272
+ - **Horizontal Spacing**: Supports `\quad` (1em spacing) and `\qquad` (2em spacing).
226
273
  - **Styles, Strikethroughs & Phantom**:
227
- - Borders: `\boxed{...}` (adds a border around the formula, e.g., `\boxed{x+y}`)
228
- - Strikethroughs: `\cancel{...}` (crosses out with a diagonal line, e.g., `\cancel{x}`) and `\sout{...}` (crosses out with a horizontal line, e.g., `\sout{y}`)
229
- - Hiding & Spacing: `\phantom{...}` (renders an invisible placeholder with the same width and height as the argument, e.g., `\phantom{x}`)
230
- - **Common Functions**: `\sin`, `\cos`, `\tan`, `\cot`, `\sec`, `\csc`, `\log`, `\lg`, `\ln`, `\lim`, `\exp`, `\max`, `\min`, `\sup`, `\inf`, `\det`, `\gcd`, `\arcsin`, `\arccos`, `\arctan`, `\sinh`, `\cosh`, `\tanh`, `\coth`, `\deg`, `\arg`. Note that limit-like operators (`\lim`, `\max`, `\min`, `\sup`, `\inf`) render with limits layout (above/under) for subscripts and superscripts in display/block math mode.
231
- - **Modulo parentheses**: `\pmod{...}` (generates parenthesized modulo, e.g., `\pmod{m}` renders as $(mod\ m)$)
274
+ - Border: `\boxed{...}` (adds a border around the formula, e.g., `\boxed{x+y}`)
275
+ - Strikethroughs: `\cancel{...}` (strikes through with a slash, e.g., `\cancel{x}`) and `\sout{...}` (strikes through with a horizontal line, e.g., `\sout{y}`)
276
+ - Hiding & Spacing: `\phantom{...}` (creates an invisible space with the same width and height, e.g., `\phantom{x}`)
277
+ - **Common Functions**: `\sin`, `\cos`, `\tan`, `\cot`, `\sec`, `\csc`, `\log`, `\lg`, `\ln`, `\lim`, `\exp`, `\max`, `\min`, `\sup`, `\inf`, `\det`, `\gcd`, `\arcsin`, `\arccos`, `\arctan`, `\sinh`, `\cosh`, `\tanh`, `\coth`, `\deg`, `\arg`. Subscripts/superscripts of limit-like operators (`\lim`, `\max`, `\min`, `\sup`, `\inf`) appear as limits (directly below/above) in display mode.
278
+ - **Modulo**: `\pmod{...}` (adds a modulo parenthesis, e.g., `\pmod{m}` renders as $(mod\ m)$)
232
279
  - **Greek Letters**:
233
280
  - Lowercase: `\alpha` ($\alpha$), `\beta` ($\beta$), `\gamma` ($\gamma$), `\delta` ($\delta$), `\epsilon` ($\epsilon$), `\zeta` ($\zeta$), `\eta` ($\eta$), `\theta` ($\theta$), `\iota` ($\iota$), `\kappa` ($\kappa$), `\lambda` ($\lambda$), `\mu` ($\mu$), `\nu` ($\nu$), `\xi` ($\xi$), `\pi` ($\pi$), `\rho` ($\rho$), `\sigma` ($\sigma$), `\tau` ($\tau$), `\upsilon` ($\upsilon$), `\phi` ($\phi$), `\chi` ($\chi$), `\psi` ($\psi$), `\omega` ($\omega$)
234
- - Uppercase (rendered upright): `\Delta` ($\Delta$), `\Gamma` ($\Gamma$), `\Theta` ($\Theta$), `\Lambda` ($\Lambda$), `\Xi` ($\Xi$), `\Pi` ($\Pi$), `\Sigma` ($\Sigma$), `\Upsilon` ($\Upsilon$), `\Phi` ($\Phi$), `\Psi` ($\Psi$), `\Omega` ($\Omega$)
281
+ - Uppercase (rendered in normal upright font): `\Delta` ($\Delta$), `\Gamma` ($\Gamma$), `\Theta` ($\Theta$), `\Lambda` ($\Lambda$), `\Xi` ($\Xi$), `\Pi` ($\Pi$), `\Sigma` ($\Sigma$), `\Upsilon` ($\Upsilon$), `\Phi` ($\Phi$), `\Psi` ($\Psi$), `\Omega` ($\Omega$)
235
282
  - **Operators & Relations**:
236
283
  - `\le` / `\leq` ($\le$), `\ge` / `\geq` ($\ge$), `\ne` / `\neq` ($\ne$)
237
284
  - `\cdot` ($\cdot$), `\times` ($\times$), `\pm` ($\pm$), `\mp` ($\mp$), `\div` ($\div$), `\infty` ($\infty$)
238
285
  - `\approx` ($\approx$), `\sim` ($\sim$), `\cong` ($\cong$), `\propto` ($\propto$), `\equiv` ($\equiv$), `\perp` ($\perp$), `\parallel` ($\parallel$)
239
286
  - **Calculus, Sets & Logic**:
240
- - Gradient: `\nabla` ($\nabla$), Partial derivative: `\partial` ($\partial$)
241
- - Logic quantifiers & operations: `\forall` ($\forall$), `\exists` ($\exists$), `\neg` ($\neg$), `\land` ($\land$), `\lor` ($\lor$)
287
+ - Gradient: `\nabla` ($\nabla$), partial differential: `\partial` ($\partial$)
288
+ - Quantifiers & operations: `\forall` ($\forall$), `\exists` ($\exists$), `\neg` ($\neg$), `\land` ($\land$), `\lor` ($\lor$)
242
289
  - Set relations: `\in` ($\in$), `\notin` ($\notin$), `\ni` ($\ni$), `\subset` ($\subset$), `\supset` ($\supset$), `\subseteq` ($\subseteq$), `\supseteq` ($\supseteq$)
243
- - Set operations: `\cup` ($\cup$), `\cap` ($\cap$), Empty set: `\emptyset` ($\emptyset$)
290
+ - Set operations: `\cup` ($\cup$), `\cap` ($\cap$), empty set: `\emptyset` ($\emptyset$)
244
291
  - Special variables & constants: `\ell` ($\ell$), `\hbar` ($\hbar$)
245
- - Big operators: summation `\sum` ($\sum$), integral `\int` ($\int$)
292
+ - Large operators: summation `\sum` ($\sum$), integration `\int` ($\int$)
246
293
  - **Arrows**:
247
- - Unidirectional: `\to` / `\rightarrow` ($\rightarrow$), `\leftarrow` / `\gets` ($\leftarrow$), `\Leftarrow` ($\Leftarrow$), `\Rightarrow` ($\Rightarrow$)
248
- - Bidirectional: `\leftrightarrow` ($\leftrightarrow$), `\Leftrightarrow` ($\Leftrightarrow$)
249
- - **Ellipses (Dots)**:
294
+ - Single arrows: `\to` / `\rightarrow` ($\rightarrow$), `\leftarrow` / `\gets` ($\leftarrow$), `\Leftarrow` ($\Leftarrow$), `\Rightarrow` ($\Rightarrow$)
295
+ - Double arrows: `\leftrightarrow` ($\leftrightarrow$), `\Leftrightarrow` ($\Leftrightarrow$)
296
+ - **Dots**:
250
297
  - Baseline dots: `\dots` / `\ldots` ($\dots$)
251
- - Center dots: `\cdots` ($\cdots$)
298
+ - Centered dots: `\cdots` ($\cdots$)
252
299
  - **Matrices & Multi-line Layouts**:
253
300
  - Matrix environments: `matrix`, `pmatrix`, `bmatrix`, `vmatrix`, `Vmatrix` (e.g., `\begin{pmatrix} a & b \\ c & d \end{pmatrix}`)
254
- - Systems of equations & conditional branches: `cases` (e.g., `\begin{cases} x & x \ge 0 \\ -x & x < 0 \end{cases}`)
255
- - General-purpose array layouts: `array`
256
- - Line breaks & alignments: use `\\`, `\\*`, or `\\[width]` (for custom row spacing, e.g. `\\[10px]`) for line breaks, and `&` for column alignments
301
+ - Cases: `cases` (e.g., `\begin{cases} x & x \ge 0 \\ -x & x < 0 \end{cases}`)
302
+ - General arrays: `array`
303
+ - Line breaks & alignment: Use `\\`, `\\*` or `\\[width]` (e.g., `\\[10px]`) for line breaks, and `&` for column alignment.
257
304
 
258
- ### Unsupported Syntax (Non-Goals)
305
+ ## Unsupported Syntax
259
306
 
260
- Currently, the following LaTeX extensions, macro definitions, or custom styling commands are not supported:
307
+ Currently, the following LaTeX extensions, macros, or fine-tuning style directives are not supported:
261
308
 
262
309
  1. **Macro Definitions**: `\newcommand`, `\renewcommand`, `\providecommand`, `\gdef`, `\let`, etc.
263
310
  2. **Background Colors & Advanced Borders**: `\colorbox`, `\fcolorbox`, `\cellcolor`, etc. (while `\boxed` is supported).
@@ -267,18 +314,16 @@ Currently, the following LaTeX extensions, macro definitions, or custom styling
267
314
  6. **Verbatim Text**: `\verb`, etc.
268
315
  7. **Advanced Positionings**: `\sideset`, `\prescript`, `\cramped`, `\flatfrac`, etc.
269
316
  8. **Equation Numbering & Custom Tags**: `\tag`, `\newtagform`, `\usetagform`, etc.
270
- 9. **Arbitrary Operator Limits**: Except for predefined big operators (`\sum`, `\int`) and limit-like operators (`\lim`), using `\limits` on arbitrary commands or structures (e.g., `\operatorname{sn}\limits_{...}`) is not supported.
317
+ 9. **Arbitrary Operator Limits**: Except for predefined big operators (`\sum`, `\int`) and limit-like operators (`\lim`), using `\limits` on arbitrary commands or structures is not supported.
271
318
 
272
319
  ## Error Handling and Fault Tolerance
273
320
 
274
- When parsing Markdown text using `@webc.site/math/md.js`, if a mathematical formula contains invalid LaTeX syntax (such as an unclosed `\left`), the parser automatically catches the compilation error internally and gracefully falls back to displaying the raw formula text (e.g., `$$x + \left( y$$`). This ensures that a single syntax error in a formula won't throw JavaScript exceptions or crash your application. Therefore, you **do not** need to wrap it in a `try...catch` block when calling this function.
321
+ When parsing Markdown text using `@webc.site/math/md.js`, syntax errors (such as an unclosed `\left`) are automatically caught and degraded to display raw TeX code (e.g., `$$x + \left( y$$`), without throwing JS exceptions. Therefore, you **do not** need to wrap it in a `try...catch` block.
275
322
 
276
- Note that calling `@webc.site/math` (the TeX compiler core) directly with invalid LaTeX syntax will throw an array containing an error code (see the internal error codes table below). If you are using the core TeX compiler directly, it is recommended to wrap the call in a `try...catch` block.
323
+ If you call the compiler core `@webc.site/math` directly with invalid LaTeX, it will throw an array containing an error code (see table below). Wrap direct core compiler calls in a `try...catch` block.
277
324
 
278
325
  ### Internal Error Codes
279
326
 
280
- The following error codes are used internally during the compilation phase to signal specific syntax issues. These are primarily useful for development, debugging, and testing:
281
-
282
327
  | Error Code | Constant | Description | Trigger Example |
283
328
  | :--------: | :------------------ | :-------------------------------------------- | :------------------------------------ |
284
329
  | `0` | `ERR_EXTRA_END` | Extra or invalid `\end` command | `\end{matrix}` (no matching `\begin`) |
@@ -286,175 +331,121 @@ The following error codes are used internally during the compilation phase to si
286
331
  | `2` | `ERR_EXTRA_RIGHT` | Extra or invalid `\right` command | `x \right)` (no matching `\left`) |
287
332
  | `3` | `ERR_MISSING_BRACE` | Command missing required curly brace `{}` | `\text x` (missing braces) |
288
333
 
289
- ## What is MathML?
290
-
291
- MathML (Mathematical Markup Language) is an XML-based standard for describing mathematical notations and capturing both its structure and content on the web.
292
-
293
- **Since January 2023** (with the release of Chrome 109 and native Blink engine support), MathML Core has been fully supported natively across all three major web rendering engines (Chromium/Blink, Gecko/Firefox, and WebKit/Safari). This ensures highly efficient and native rendering of mathematical equations across most desktop/mobile devices and modern browser versions without needing heavy client-side JavaScript rendering engines.
294
-
295
- ### Why Compile TeX Formulas to MathML?
296
-
297
- While MathML is the native web standard for mathematical typesetting, its XML-based syntax is too verbose for direct human authoring. TeX/LaTeX syntax remains the de facto standard for writing mathematical formulas (e.g., writing `$e^{i\pi} + 1 = 0$` in Markdown).
298
-
299
- Traditional web math solutions (such as MathJax or KaTeX) require loading hundreds of kilobytes to several megabytes of JS/CSS typesetting engines in the frontend, consuming substantial client-side CPU cycles for DOM mutations and layout calculations.
300
-
301
- By compiling TeX directly to native MathML using `@webc.site/math`, you get the best of both worlds—especially in **client-side (frontend) rendering** scenarios:
302
-
303
- #### 1. Extremely Lightweight (~1.8 KB Gzip) & Zero Dependencies
304
-
305
- Compared to KaTeX (300 KB+) and MathJax (several MBs), `@webc.site/math` has a virtually negligible footprint. It can be bundled directly into any frontend/SPA app without hurting initial page load times.
306
-
307
- #### 2. Native Browser Layout (No Heavy Client-Side Rendering Engine)
308
-
309
- Traditional math libraries pack not only a TeX parser but also a heavy client-side layout engine to calculate font metrics, alignment, and spacing, producing massive DOM trees or SVG elements.
310
- Our compiler acts as a translator that turns TeX into standard MathML tags on the client, leaving all the heavy rendering, typography, and positioning tasks to the browser's native C++ layout engine. This drastically reduces JavaScript execution time.
311
-
312
- #### 3. Seamless Real-Time Frontend Previews & Low CPU Overhead
313
-
314
- Because the compilation is purely a fast tag-mapping step and layout is handled natively, CPU usage is minimal. This makes it ideal for **WYSIWYG editors, live markdown previewers, and interactive apps** where formulas need to be rendered dynamically on every keystroke without lag—even on low-end mobile devices.
315
-
316
- #### 4. Unified Frontend and SSR Capabilities
317
-
318
- Since the output is standard HTML with MathML elements, the same compiler works seamlessly for dynamic client-side rendering (CSR), server-side rendering (SSR), and static site generation (SSG) alike.
319
-
320
- ## Benchmark
321
-
322
- Since KaTeX and MathJax are pure TeX compilers (without Markdown parsing features), to ensure a fair comparison, our benchmark directly compares the TeX compiler core ([@webc.site/math/mathml.js](https://github.com/webc-site/math/blob/dev/src/mathml.js)) against them.
323
-
324
- ### 1. Size Comparison (Gzipped)
325
-
326
- | Library | Raw Size | Gzip Size | Size Ratio |
327
- | :-------------------------------------------- | :-------: | :-------: | :--------: |
328
- | @webc.site/math (Ours) | 7.78 KB | 3.58 KB | 1.0 ⭐️ |
329
- | [KaTeX](https://github.com/KaTeX/KaTeX) | 264.79 KB | 75.15 KB | 21.0 |
330
- | [MathJax](https://github.com/mathjax/MathJax) | 971.04 KB | 278.39 KB | 77.7 |
331
-
332
- ![](demo/size.svg)
333
-
334
- ### 2. Generation Speed (Ops/sec)
334
+ ## Design and Workflow
335
335
 
336
- Based on compiling standard test equations (measured using [sh/bench/pk.js](https://github.com/webc-site/math/blob/dev/sh/bench/pk.js)):
337
-
338
- - **@webc.site/math (Ours)**: ~329, 000 ops/s (1.0 ⭐️)
339
- - **[KaTeX](https://github.com/KaTeX/KaTeX)**: ~92, 000 ops/s (~3.6x slower)
340
- - **[MathJax](https://github.com/mathjax/MathJax)**: ~6, 700 ops/s (~48.8x slower)
341
-
342
- ![](demo/speed.svg)
343
-
344
- ## Design and Calling Process
345
-
346
- The parser processes input Markdown string, isolates TeX expressions, and translates them to MathML structures.
336
+ The parser processes the input Markdown string, isolates TeX expressions, and translates them into MathML structures.
347
337
 
348
338
  ```mermaid
349
339
  graph TD
350
340
  A[Input Markdown] --> B{Scanner}
351
- B -- Markdown Text --> C[Output Buffer]
352
- B -- TeX Formula --> D[Lexer: Tokenization]
353
- D --> E[Parser: AST Generation]
354
- E --> F[Generator: MathML Tag Creation]
355
- F --> G[Semantic Wrapping]
341
+ B -- Plain Text --> C[Output Buffer]
342
+ B -- TeX Formula --> D[Lexer: Generate Tokens]
343
+ D --> E[Parser: Generate AST]
344
+ E --> F[Codegen: Generate MathML Tags]
345
+ F --> G[Semantic Wrapper]
356
346
  G --> H[MathML Output]
357
347
  C --> I[Final HTML]
358
348
  H --> I
359
349
  ```
360
350
 
361
- ### Module Flow
351
+ ### Module Stages
362
352
 
363
- 1. **Scanner**: Scans the input string to locate delimiters (`$` and `$$`).
364
- 2. **Lexer**: Tokenizes TeX string into numbers, variables, operations, and control characters.
365
- 3. **Parser**: Converts tokens into Abstract Syntax Tree (AST) nodes supporting fractions, subscripts, superscripts, and functions.
366
- 4. **Generator**: Converts AST nodes to standardized XML nodes (`<mi>`, `<mo>`, `<mn>`, `<mfrac>`, `<msup>`, `<msub>`, `<msubsup>`).
353
+ 1. **Scanner**: Scans the input string to locate formula delimiters (`$` and `$$`).
354
+ 2. **Lexer**: Breaks the TeX string into tokens like numbers, variables, operators, and control commands.
355
+ 3. **Parser**: Translates tokens into an Abstract Syntax Tree (AST), supporting operations like subscripts, superscripts, fractions, and built-in functions.
356
+ 4. **Codegen**: Maps AST nodes to standard MathML Core elements (`<mi>`, `<mo>`, `<mn>`, `<mfrac>`, `<msup>`, `<msub>`, `<msubsup>`).
367
357
 
368
- ## How to Add Syntax Support
358
+ ## Adding New Syntax
369
359
 
370
- To add support for a new LaTeX syntax, you need to modify the following four core parts in order:
360
+ To add support for a new LaTeX command, modify the following four core parts in order:
371
361
 
372
- ### 1. Constants
362
+ ### 1. Constant Definitions
373
363
 
374
- Define the corresponding lexical tokens, syntax node types, function names, or symbol mappings:
364
+ Define the corresponding lexical token, AST node type, function name, or symbol mapping:
375
365
 
376
- - **Token Type**: Defined in [const/TOK.js](https://github.com/webc-site/math/blob/dev/src/const/TOK.js) (e.g., `export const TOK_MY_CMD = ...` if a new lexical category is required).
377
- - **AST Node Type**: Defined in [const/TYPE.js](https://github.com/webc-site/math/blob/dev/src/const/TYPE.js) (e.g., `export const TYPE_MY_NODE = ...` specifies the new abstract syntax tree node type).
378
- - **Environment Delimiters**: If adding a new environment (such as a matrix variant), configure its left and right delimiters in `ENV_DELIMS` inside [mathml.js](https://github.com/webc-site/math/blob/dev/src/mathml.js) (previously `compile.js`).
379
- - **Symbol Map**: For simple math symbols or commands, map the command name to its corresponding Unicode character in `SYM_MAP` inside [const/SYM.js](https://github.com/webc-site/math/blob/dev/src/const/SYM.js).
380
- - **Function Names**: Defined in [const/FUNC.js](https://github.com/webc-site/math/blob/dev/src/const/FUNC.js) (under `FUNC_NAMES`).
366
+ - **Token Type**: Defined in [const/TOK.js](https://github.com/webc-site/math/blob/dev/src/const/TOK.js) (e.g., `export const TOK_MY_CMD = ...`).
367
+ - **AST Node Type**: Defined in [const/TYPE.js](https://github.com/webc-site/math/blob/dev/src/const/TYPE.js) (e.g., `export const TYPE_MY_NODE = ...`).
368
+ - **Environment Delimiters**: If adding a new environment (like a matrix or bracket type), configure its left and right delimiters in `ENV_DELIMS` inside [mathml.js](https://github.com/webc-site/math/blob/dev/src/mathml.js).
369
+ - **Symbol Mapping**: For simple operators or symbols, map the command name to its Unicode character in `SYM_MAP` inside [const/SYM.js](https://github.com/webc-site/math/blob/dev/src/const/SYM.js).
370
+ - **Math Function Name**: Define in `FUNC_NAMES` inside [const/FUNC.js](https://github.com/webc-site/math/blob/dev/src/const/FUNC.js).
381
371
 
382
372
  ### 2. Lexer
383
373
 
384
- The `lex(str)` function tokenizes the LaTeX input string into a flat token array. It is located in [lex.js](https://github.com/webc-site/math/blob/dev/src/lex.js).
374
+ The `lex(str)` function cuts the input LaTeX string into a token array. It is located in [lex.js](https://github.com/webc-site/math/blob/dev/src/lex.js).
385
375
 
386
- - If you introduce new special characters or structures, update the character matching logic in `lex` to recognize and push the corresponding `TOK_*` type and its literal value to the `tokens` array.
376
+ - If introducing a new special character or structure, update character matching logic in `lex` to push the correct `TOK_*` type and its literal value to the `tokens` array.
387
377
 
388
378
  ### 3. Parser
389
379
 
390
- The `parse(tokens, state)` function parses tokens into AST nodes. It is located in [parse.js](https://github.com/webc-site/math/blob/dev/src/parse.js).
380
+ The `parse(tokens, state)` function translates tokens into AST nodes. It is located in [parse.js](https://github.com/webc-site/math/blob/dev/src/parse.js).
391
381
 
392
- - **Command Parsing**: Handled in the `TOK_MAP[TOK_CMD]` function inside [parse.js](https://github.com/webc-site/math/blob/dev/src/parse.js). When a command (e.g., `\mycmd`) is matched, consume its arguments (using `read(tokens, state_ref)` or `grab(tokens, state_ref)`) and return an AST node array: `[TYPE_MY_NODE, arg1, arg2]`.
382
+ - **Command Parsing**: Handled primarily inside the `TOK_MAP[TOK_CMD]` function. When matching your command (e.g., `\mycmd`), read its arguments (using `read(tokens, state_ref)` or `grab(tokens, state_ref)`) and return the node array: `[TYPE_MY_NODE, arg1, arg2]`.
393
383
 
394
- ### 4. Renderer
384
+ ### 4. Codegen
395
385
 
396
- The `SHOW_MAP` dictionary converts AST nodes into standard MathML markup strings. It is located in [mathml.js](https://github.com/webc-site/math/blob/dev/src/mathml.js) (previously `compile.js`).
386
+ The `SHOW_MAP` dictionary maps AST nodes to standard MathML markup strings. It is located in [mathml.js](https://github.com/webc-site/math/blob/dev/src/mathml.js).
397
387
 
398
- - Register a new renderer function: `[TYPE_MY_NODE]: ([_, arg1, arg2]) => nest("mylabel", arg1, arg2)` or `tag("mi", ...)` to format node data into standard MathML tags (e.g., `<mfrac>`, `<msup>`, etc.).
388
+ - Register a renderer function: `[TYPE_MY_NODE]: ([_, arg1, arg2]) => nest("mylabel", arg1, arg2)`, formatting node data into native MathML tags.
399
389
 
400
390
  ## Tech Stack
401
391
 
402
392
  - **Runtime**: Bun, Node.js
403
- - **Compilation & Bundling**: SWC (minify), Vite (demo)
404
- - **Development Tools**: oxlint, oxfmt
393
+ - **Build & Bundle**: SWC (compression), Vite (demo site)
394
+ - **Quality Assurance**: oxlint, oxfmt
405
395
 
406
396
  ## Directory Structure
407
397
 
408
398
  ```
409
399
  .
410
- ├── demo/ # Interactive rendering demo site
411
- │ ├── const/ # Constants (formulas, languages)
412
- │ ├── i18n/ # Internationalization translation files
413
- │ ├── index.js # Demo interaction script
400
+ ├── demo/ # Interactive demo site
401
+ │ ├── const/ # Constants (preset formulas, language list)
402
+ │ ├── i18n/ # Language translation configurations
403
+ │ ├── index.js # Interactive demo logic
414
404
  │ ├── index.pug # Pug HTML template
415
- │ └── style.styl # Premium layout styling
416
- ├── extract/ # Classical formula extraction scripts (KaTeX / MathJax test cases)
417
- ├── lib/ # Compiled production distribution
418
- │ ├── package.json # Minified package.json for NPM publication
419
- │ ├── README.md # Automatically synchronized README for publication
420
- │ ├── mathml.js # Minified distribution JS (TeX compiler)
421
- │ ├── mathml.js.map # Source map for TeX compiler
422
- │ ├── md.js # Minified distribution JS (Markdown parser)
423
- │ └── md.js.map # Source map for Markdown parser
405
+ │ └── style.styl # Styling and themes
406
+ ├── extract/ # Test case extraction scripts (from KaTeX / MathJax)
407
+ ├── lib/ # Compilation output directory
408
+ │ ├── package.json # Lightweight package.json for npm publication
409
+ │ ├── README.md # Automatically generated distribution README
410
+ │ ├── mathml.js # Minified core TeX compiler
411
+ │ ├── mathml.js.map # Source map for mathml.js
412
+ │ ├── md.js # Minified Markdown parser
413
+ │ └── md.js.map # Source map for md.js
424
414
  ├── src/ # Source code
425
- │ ├── const/ # Constant definitions (types, symbols, functions, etc.)
426
- │ ├── lex.js # LaTeX formula lexer
427
- │ ├── parse.js # LaTeX formula parser (AST generator)
415
+ │ ├── const/ # Tokens, AST types, symbol maps, and function names
416
+ │ ├── lex.js # LaTeX lexer
417
+ │ ├── parse.js # LaTeX parser (AST generation)
428
418
  │ ├── mathml.js # TeX-to-MathML compiler
429
- │ └── md.js # Markdown math formula parser entry point
430
- ├── sh/ # Shell scripts
431
- │ ├── bench/ # Benchmark scripts, shared utilities & history
432
- │ │ ├── pk.js # Size/speed comparison benchmark & SVG generator
433
- │ │ ├── self.js # Performance & size regression test runner
434
- │ │ ├── util.js # Shared benchmark utilities
435
- │ │ ├── chart.js # SVG chart renderer
436
- │ │ └── history.yml # YAML baseline history data
419
+ │ └── md.js # Markdown mathematical formula parser
420
+ ├── sh/ # Scripts
421
+ │ ├── bench/ # Benchmark scripts, charts, and historical baseline data
422
+ │ │ ├── pk.js # Size and speed comparison & chart generation
423
+ │ │ ├── self.js # Regression tests
424
+ │ │ ├── util.js # Shared helpers
425
+ │ │ ├── chart.js # SVG chart component
426
+ │ │ └── history.yml # YAML historical benchmark records
437
427
  │ └── check.js # Language file validation script
438
- ├── dev.js # Programmatic Vite development server launcher
439
- ├── dist.js # Build & distribution helper script (bumps version, compiles templates)
440
- ├── minify.js # Build minification compiler script
441
- ├── package.json # Project configuration metadata
442
- ├── README.md # Synchronized root project documentation
443
- ├── README.mdt # Markdown template for compiling English, Chinese and About files
444
- └── test.sh # Formatter, linter, and compiler test runner
428
+ ├── dev.js # Dev server script (Vite)
429
+ ├── dist.js # Publish helper script (versioning and template rendering)
430
+ ├── minify.js # Bundle compression script
431
+ ├── package.json # Project package config
432
+ ├── README.md # Automatically generated root README
433
+ ├── README.mdt # Compilation template for README
434
+ └── test.sh # Formatting, linting, and unit test execution script
445
435
  ```
446
436
 
447
- ## History and Background
437
+ ## Historical Background
448
438
 
449
- Mathematical typesetting on the web has historically relied on heavy libraries like MathJax or KaTeX. These libraries fetch large bundles and execute extensive CSS and layout calculations, causing page loading latencies.
439
+ Web-based math formula rendering traditionally relied on MathJax or KaTeX. These libraries load large JS/CSS packages and perform complex client-side calculations, causing noticeable loading delay or page layout shifting.
450
440
 
451
- MathML (Mathematical Markup Language) was proposed to solve this by providing native browser rendering of mathematical notations. In 2023, the integration of MathML Core into the Blink layout engine completed native MathML support across major web browsers (Chrome, Safari, Firefox).
441
+ MathML Core specifies native mathematical typesetting in the browser. In 2023, the Blink engine introduced native support, enabling Chrome, Safari, and Firefox to natively lay out equations.
452
442
 
453
- The `18s` project provides a optimized math font `m` (Latin Modern Math, derived from Donald Knuth's Computer Modern typeface). The `@webc.site/math` compiler compiles TeX equations directly to native MathML Core elements, leveraging browser rendering capabilities to eliminate heavyweight runtime rendering dependencies.
443
+ In combination with the **Latin Modern Math** font (`m` from `18s` package), `@webc.site/math` acts as a translator, compiling TeX equations directly to native MathML Core tags to eliminate client-side rendering engines.
454
444
 
455
445
  ---
456
446
 
457
447
  <a id="zh"></a>
448
+
458
449
  # @webc.site/math
459
450
 
460
451
  ### 全球最小最快的网页 Markdown 公式渲染器
@@ -465,40 +456,81 @@ The `18s` project provides a optimized math font `m` (Latin Modern Math, derived
465
456
  &nbsp;&nbsp;
466
457
  <a href="https://math.webc.site" target="_blank"><img src="https://raw.githubusercontent.com/webc-site/math/dev/readme/zh/svg/badge.demo.svg" alt="demo" /></a>
467
458
 
468
- 告别数百 KB 的 KaTeX/MathJax 与臃肿的 CSS 字体包!仅约 4KB (Gzip) 的极致体积,将 LaTeX 公式瞬间编译为现代浏览器原生支持的 MathML,带来零运行开销、零延迟的完美渲染体验。
459
+ 无需引入数百 KB 的 KaTeX/MathJax 及庞大的字体包。包体积仅约 4KB (Gzip),将 LaTeX 公式编译为浏览器原生支持的 MathML,实现零运行开销的公式渲染。
469
460
 
461
+ - [核心优势](#核心优势)
462
+ - [什么是 MathML?](#什么是-mathml)
463
+ - [为什么将 TeX 编译为 MathML?](#为什么将-tex-编译为-mathml)
464
+ - [性能对比](#性能对比)
465
+ - [1. 体积对比(Gzip 压缩)](#1-体积对比gzip-压缩)
466
+ - [2. 生成速度对比](#2-生成速度对比)
470
467
  - [使用方法](#使用方法)
471
468
  - [JavaScript 示例](#javascript-示例)
472
469
  - [Markdown 解析器插件](#markdown-解析器插件)
473
470
  - [CSS 与数学字体配置](#css-与数学字体配置)
474
471
  - [功能特性](#功能特性)
475
472
  - [支持的语法清单](#支持的语法清单)
476
- - [不支持的语法 (非本库设计目标)](#不支持的语法-非本库设计目标)
473
+ - [不支持的语法](#不支持的语法)
477
474
  - [错误处理与容错机制](#错误处理与容错机制)
478
475
  - [内部错误码](#内部错误码)
479
- - [什么是 MathML?](#什么是-mathml)
480
- - [为什么需要 TeX 公式转 MathML?](#为什么需要-tex-公式转-mathml)
481
- - [性能对比](#性能对比)
482
- - [1. 体积对比(Gzip 压缩后)](#1-体积对比gzip-压缩后)
483
- - [2. 生成速度对比 (Ops/sec)](#2-生成速度对比-opssec)
484
476
  - [设计思路与调用流程](#设计思路与调用流程)
485
477
  - [模块运行流程](#模块运行流程)
486
- - [如何添加新的语法支持](#如何添加新的语法支持)
487
- - [1. 常量定义 (Constants)](#1-常量定义-constants)
488
- - [2. 词法分析 (Lexer)](#2-词法分析-lexer)
489
- - [3. 语法分析 (Parser)](#3-语法分析-parser)
490
- - [4. 代码渲染 (Renderer)](#4-代码渲染-renderer)
478
+ - [如何添加新语法](#如何添加新语法)
479
+ - [1. 常量定义](#1-常量定义)
480
+ - [2. 词法分析](#2-词法分析)
481
+ - [3. 语法分析](#3-语法分析)
482
+ - [4. 代码渲染](#4-代码渲染)
491
483
  - [技术堆栈](#技术堆栈)
492
484
  - [目录结构](#目录结构)
493
485
  - [历史背景](#历史背景)
494
486
 
487
+ ## 核心优势
488
+
489
+ ### 什么是 MathML?
490
+
491
+ MathML(数学标记语言)是描述数学公式结构与语义的 XML 标准。
492
+ 自 Chrome 109(2023年1月)起,所有主流浏览器引擎(Blink、Gecko、WebKit)均已原生支持 MathML Core 标准。页面无需加载 JS 排版库即可渲染公式。
493
+
494
+ ### 为什么将 TeX 编译为 MathML?
495
+
496
+ MathML 语法基于 XML,不便于直接书写。日常书写的公式标准是 TeX 语法(如 `$e^{i\pi} + 1 = 0$`)。
497
+ 传统库(如 MathJax、KaTeX)在前端运行时,需加载数百 KB 的排版引擎,并消耗 CPU 进行布局计算。
498
+ 本库将 TeX 直接编译为 MathML,具有以下优势:
499
+
500
+ - **体积小**:包体积仅 7.78 KB(Gzip 3.58 KB),不影响首屏加载。
501
+ - **零运行依赖**:仅在编译期进行标签翻译,排版布局完全由浏览器底层的 C++ 原生引擎渲染,无需前端 JS 引擎介入,释放主线程。
502
+ - **低 CPU 开销**:适用于编辑器实时预览等高频渲染场景,低配移动设备运行流畅。
503
+ - **前后端通用**:输出标准 MathML 元素,适用于前端动态转换与服务端静态编译(SSR/SSG)。
504
+
505
+ ## 性能对比
506
+
507
+ ### 1. 体积对比(Gzip 压缩)
508
+
509
+ | 库 | 原始体积 | Gzip 体积 | 尺寸比 |
510
+ | :---------------------------------------------------------- | :-------: | :-------: | :----: |
511
+ | [@webc.site/math](https://github.com/webc-site/math) (本库) | 7.78 KB | 3.58 KB | 1.0 ⭐️ |
512
+ | [KaTeX](https://github.com/KaTeX/KaTeX) | 264.79 KB | 75.15 KB | 21.0 |
513
+ | [MathJax](https://github.com/mathjax/MathJax) | 971.04 KB | 278.39 KB | 77.7 |
514
+
515
+ ![](demo/size.svg)
516
+
517
+ ### 2. 生成速度对比
518
+
519
+ 基于经典公式循环编译测试(使用 [sh/bench/pk.js](https://github.com/webc-site/math/blob/dev/sh/bench/pk.js) 测得):
520
+
521
+ - **@webc.site/math (本库)**: ~329,000 ops/s (1.0 ⭐️)
522
+ - **[KaTeX](https://github.com/KaTeX/KaTeX)**: ~92,000 ops/s (约 3.6x 较慢)
523
+ - **[MathJax](https://github.com/mathjax/MathJax)**: ~6,700 ops/s (约 48.8x 较慢)
524
+
525
+ ![](demo/speed.svg)
526
+
495
527
  ## 使用方法
496
528
 
497
529
  ### JavaScript 示例
498
530
 
499
531
  #### 1. 直接渲染 TeX 公式
500
532
 
501
- 使用 `@webc.site/math`。直接将 TeX 公式编译为 MathML。适合配合 Markdown 解析器(如 markdown-it、marked)实现公式渲染插件。
533
+ 使用 `@webc.site/math` TeX 公式编译为 MathML(适用于 Markdown 渲染插件开发):
502
534
 
503
535
  ```javascript
504
536
  import mathml from "@webc.site/math";
@@ -509,7 +541,7 @@ const html = mathml(tex, true); // 第二个参数传 true 表示块级公式,
509
541
 
510
542
  #### 2. 替换 Markdown 中的公式
511
543
 
512
- 使用 `@webc.site/math/md.js`。输入 Markdown 文本,自动识别其中的行内/块级公式并替换为 MathML。需将公式编译器(如 `@webc.site/math`)作为第二个参数传入。
544
+ 使用 `@webc.site/math/md.js` 自动识别 Markdown 文本中的行内/块级公式并替换为 MathML(需传入公式编译器):
513
545
 
514
546
  ```javascript
515
547
  import mdMath from "@webc.site/math/md.js";
@@ -526,7 +558,7 @@ console.log(html);
526
558
 
527
559
  #### 1. Marked 插件
528
560
 
529
- 使用 [`@webc.site/math-marked`](https://www.npmjs.com/package/@webc.site/math-marked)。自动解析并编译使用 `marked` 渲染时的行内公式(`$...$`)和块级公式(`$$...$$`)。
561
+ 使用 [`@webc.site/math-marked`](https://www.npmjs.com/package/@webc.site/math-marked) 自动解析并编译行内(`$...$`)与块级(`$$...$$`)公式:
530
562
 
531
563
  ```javascript
532
564
  import { marked } from "marked";
@@ -539,7 +571,7 @@ const html = marked.parse("欧拉恒等式:$$e^{i\\pi} + 1 = 0$$");
539
571
 
540
572
  #### 2. Remark 插件
541
573
 
542
- 使用 [`@webc.site/math-remark`](https://www.npmjs.com/package/@webc.site/math-remark)。用于 Unified / Remark 抽象语法树(AST)转换的插件,无缝将 AST 中的 `inlineMath` 与 `math` 节点替换为原生 MathML HTML
574
+ 使用 [`@webc.site/math-remark`](https://www.npmjs.com/package/@webc.site/math-remark) Unified/Remark AST 中的 `inlineMath` 与 `math` 节点替换为原生 MathML HTML
543
575
 
544
576
  ```javascript
545
577
  import { unified } from "unified";
@@ -558,7 +590,7 @@ const html = await unified()
558
590
 
559
591
  #### 3. Markdown-it 插件
560
592
 
561
- 使用 [`@webc.site/math-markdown-it`](https://www.npmjs.com/package/@webc.site/math-markdown-it)。用于 `markdown-it` 的数学公式渲染插件,在解析时自动将行内公式(`$...$`)和块级公式(`$$...$$`)编译为原生 MathML HTML。
593
+ 使用 [`@webc.site/math-markdown-it`](https://www.npmjs.com/package/@webc.site/math-markdown-it) 自动解析并渲染 `markdown-it` 中的行内与块级公式:
562
594
 
563
595
  ```javascript
564
596
  import markdownit from "markdown-it";
@@ -571,11 +603,11 @@ const html = md.render("欧拉恒等式:$$e^{i\\pi} + 1 = 0$$");
571
603
 
572
604
  ### CSS 与数学字体配置
573
605
 
574
- 为了使浏览器原生呈现出排版更精美的数学公式,强烈建议配合专门的数学字体使用。这里我们推荐使用 `18s` 包中提供的 **Latin Modern Math** 数学字体(源自高德纳的经典 Computer Modern 字体,包含完整的数学和技术符号集与 OpenType 排版特性映射)。
606
+ 为保证浏览器原生数学公式的排版,建议配置数学字体。推荐使用 `18s` 字体包的 **Latin Modern Math**(源自高德纳的 Computer Modern 字体,支持 OpenType 数学排版特性)。
575
607
 
576
- #### 1. 在线引用(推荐)
608
+ #### 1. 在线引用
577
609
 
578
- 可以直接在 CSS 中通过 `@import` 引入在线字体:
610
+ CSS 中通过 `@import` 引入在线字体:
579
611
 
580
612
  ```css
581
613
  /* 引入合并后的字体 CSS(包含思源黑体 t、代码字体 c 及数学字体 m) */
@@ -596,7 +628,7 @@ npm install 18s
596
628
 
597
629
  ##### 引入本地字体
598
630
 
599
- 根据你的项目,选择以下一种方式引入字体映射关系(注意:请不要把 JS CSS 的引入混在同一个文件中):
631
+ 选择以下一种方式引入字体映射(注意:请勿混用 JS CSS 引入):
600
632
 
601
633
  ###### 方式 1:在项目入口 JS/TS 文件中引入
602
634
 
@@ -626,90 +658,95 @@ import "18s/m.css";
626
658
 
627
659
  #### 3. 配置 CSS 样式
628
660
 
629
- 在全局 CSS 样式表中,为 `math` 标签指定数学字体族别名 `m`(其中 `t` 是思源黑体,对中文进行了切片优化):
661
+ 在全局 CSS 样式表中,为 `math` 标签指定数学字体。
662
+
663
+ ##### 方案 A:使用托管/本地字体(推荐,效果最完美)
664
+
665
+ 引入 `18s` 提供的字体包(含切片优化思源黑体 `t` 与数学字体 `m`):
630
666
 
631
667
  ```css
632
668
  math {
633
- /* m 为数学字体,t 为思源黑体(对中文字符进行了切片优化以提升加载性能),sans-serif 为系统默认无衬线字体 */
634
- font-family: m, t, sans-serif;
669
+ /* m 为数学字体,t 为思源黑体(对中文字符进行了切片优化以提升加载性能),math 为系统数学字体,sans-serif 为系统默认无衬线字体 */
670
+ font-family: m, t, math, sans-serif;
635
671
  }
636
672
  ```
637
673
 
638
- ## 功能特性
674
+ ##### 方案 B:使用系统数学字体(免引入外部资源)
639
675
 
640
- - **功能完备**:从 KaTeX 和 MathJax 官方测试用例库中抽取了数千个公式进行编译测试,全部通过(测试用例见 [extract](https://github.com/webc-site/math/tree/dev/extract))。
641
- - **健壮容错**:在解析 Markdown 文本时,公式中的语法错误(如未闭合的 `\left`/`\right` 或其他非法语法)会被自动捕获并优雅退化,直接返回原始的 TeX 代码而不抛出 JavaScript 异常,防止前端应用崩溃。
642
- - **快速编译**:直接编译 TeX 公式为语义化 MathML,无外部解析器依赖。
643
- - **Markdown 集成**:自动解析 Markdown 文本中的行内公式(`$ 公式 $`)和块级公式(`$$ 公式 $$`)。
644
- - **高性能**:原始体积仅 7.78 KB(Gzip 压缩后 3.58 KB),体积远小于 KaTeX 和 MathJax(见下图体积对比):
676
+ 直接使用系统内置数学字体以最小化体积:
645
677
 
646
- | 库 | 原始体积 | Gzip 体积 | 尺寸比 |
647
- | :---------------------------------------------------------- | :-------: | :-------: | :----: |
648
- | [@webc.site/math](https://github.com/webc-site/math) (本库) | 7.78 KB | 3.58 KB | 1.0 ⭐️ |
649
- | [KaTeX](https://github.com/KaTeX/KaTeX) | 264.79 KB | 75.15 KB | 21.0 |
650
- | [MathJax](https://github.com/mathjax/MathJax) | 971.04 KB | 278.39 KB | 77.7 |
678
+ ```css
679
+ math {
680
+ /* 优先使用各平台内置的数学字体,最后降级到 CSS 标准 math 泛型字体 */
681
+ font-family: "STIX Two Math", "Latin Modern Math", "Cambria Math", math;
682
+ }
683
+ ```
651
684
 
652
- ![](demo/size.svg)
685
+ ## 功能特性
653
686
 
654
- - **标准兼容**:输出现代浏览器排版引擎支持的标准 MathML 元素。
687
+ - **功能完备**:通过数千个 KaTeX/MathJax 官方测试用例(详见 [extract](https://github.com/webc-site/math/tree/dev/extract))。
688
+ - **健壮容错**:公式语法错误(如未闭合的 `\left`/`\right`)会自动捕获并降级显示原始公式,不抛出异常,防止应用崩溃。
689
+ - **快速编译**:无需外部依赖,直接将 TeX 公式编译为语义化 MathML。
690
+ - **Markdown 集成**:自动解析 Markdown 中的行内公式(`$ 公式 $`)和块级公式(`$$ 公式 $$`)。
691
+ - **标准兼容**:输出现代浏览器原生支持的标准 MathML 元素。
655
692
 
656
693
  ## 支持的语法清单
657
694
 
658
- 本库在极简的包体积下,支持了最常用的数学公式排版语法:
695
+ 本库在极简的包体积下,支持最常用的数学公式排版语法:
659
696
 
660
697
  - **基础算术与符号**:数字、英文字母、基础运算符(`+`, `-`, `*`, `/`, `=`, `<`, `>`, `(`, `)`, `[`, `]`, `.`)。其中 `-` 自动映射为减号 `\u2212`,`*` 映射为星号 `\u2217`,`/` 以直立体呈现。
661
- - **上下标 (Subscripts & Superscripts)**:
698
+ - **上下标**:
662
699
  - 上标 `^`(如 `x^2`)
663
700
  - 下标 `_`(如 `x_i`)
664
701
  - 同时存在上下标(如 `x_i^2` 或 `x^2_i`)
665
- - 对于求和与积分等大型运算符,上下标会自动以限位上下标(limits)形式呈现(如 `\sum_{i=1}^n`,`\int_a^b`)
666
- - **分式 (Fraction)**:`\frac{分子}{分母}`(如 `\frac{a}{b}`)
667
- - **开根号 (Square Root)**:平方根 `\sqrt{x}` 以及 $n$ 次方根 `\sqrt[n]{x}`
668
- - **上划线与横线 (Overlines & Bars)**:`\overline{x}` 及简写形式 `\bar{x}`
669
- - **自适应括号与定界符 (Delimiters)**:`\left` 和 `\right` 结构(如 `\left( ... \right)`)。支持的定界符包括:
702
+ - 对于求和与积分等大型运算符,上下标会自动以限位上下标形式呈现(如 `\sum_{i=1}^n`,`\int_a^b`)
703
+ - **分式**:`\frac{分子}{分母}`(如 `\frac{a}{b}`)
704
+ - **开根号**:平方根 `\sqrt{x}` 以及 $n$ 次方根 `\sqrt[n]{x}`
705
+ - **上划线与横线**:`\overline{x}` 及简写形式 `\bar{x}`
706
+ - **自适应括号与定界符**:`\left` 和 `\right` 结构(如 `\left( ... \right)`)。支持的定界符包括:
670
707
  - 圆括号:`(` 和 `)`
671
708
  - 方括号:`[` 和 `]`
672
709
  - 花括号:`\{` 和 `\}`
673
- - 尖括号:`<` (⟨) 和 `>` (⟩)
710
+ - 尖括号:`<` 和 `>`
674
711
  - 竖线:`|` 或 `\|`
675
712
  - 空白定界符:`.`(表示不显示该侧定界符,例如 `\left. \frac{df}{dx} \right| _0`)
676
- - **文本模式 (Text Mode)**:`\text{...}`(如 `\text{if }`),提取大括号中的字面文本,渲染为 MathML `<mtext>`,以常规直立体呈现。
677
- - **水平间距 (Horizontal Spacing)**:支持 `\quad`(1em 间距)和 `\qquad`(2em 间距)的空格占位。
678
- - **样式、删除线与占位隐藏 (Styles, Strikethroughs & Phantom)**:
713
+ - **文本模式**:`\text{...}`(如 `\text{if }`),提取大括号中的字面文本,渲染为 MathML `<mtext>`,以常规直立体呈现。
714
+ - **水平间距**:支持 `\quad`(1em 间距)和 `\qquad`(2em 间距)的空格占位。
715
+ - **样式、删除线与占位隐藏**:
679
716
  - 边框:`\boxed{...}`(在公式周围加上边框,如 `\boxed{x+y}`)
680
717
  - 删除线与取消线:`\cancel{...}`(通过斜线划掉,如 `\cancel{x}`)和 `\sout{...}`(通过水平线划掉,如 `\sout{y}`)
681
718
  - 隐藏与占位:`\phantom{...}`(生成与输入内容相同宽高的不可见占位空间,如 `\phantom{x}`)
682
- - **常用数学函数 (Common Functions)**:`\sin`, `\cos`, `\tan`, `\cot`, `\sec`, `\csc`, `\log`, `\lg`, `\ln`, `\lim`, `\exp`, `\max`, `\min`, `\sup`, `\inf`, `\det`, `\gcd`, `\arcsin`, `\arccos`, `\arctan`, `\sinh`, `\cosh`, `\tanh`, `\coth`, `\deg`, `\arg`。其中 `\lim`, `\max`, `\min`, `\sup`, `\inf` 作为极限算子,其上下标定位在行间/块级公式中会自动以 limits 形式显示在算子正下方。
683
- - **同余括号 (Modulo)**:`\pmod{...}`(生成带括号的同余占位,如 `\pmod{m}` 渲染为 $(mod\ m)$)
684
- - **希腊字母 (Greek Letters)**:
719
+ - **常用数学函数**:`\sin`, `\cos`, `\tan`, `\cot`, `\sec`, `\csc`, `\log`, `\lg`, `\ln`, `\lim`, `\exp`, `\max`, `\min`, `\sup`, `\inf`, `\det`, `\gcd`, `\arcsin`, `\arccos`, `\arctan`, `\sinh`, `\cosh`, `\tanh`, `\coth`, `\deg`, `\arg`。其中 `\lim`, `\max`, `\min`, `\sup`, `\inf` 作为极限算子,其上下标定位在行间/块级公式中会自动以 limits 形式显示在算子正下方。
720
+ - **同余括号**:`\pmod{...}`(生成带括号的同余占位,如 `\pmod{m}` 渲染为 $(mod\ m)$)
721
+ - **希腊字母**:
685
722
  - 小写希腊字母:`\alpha` ($\alpha$), `\beta` ($\beta$), `\gamma` ($\gamma$), `\delta` ($\delta$), `\epsilon` ($\epsilon$), `\zeta` ($\zeta$), `\eta` ($\eta$), `\theta` ($\theta$), `\iota` ($\iota$), `\kappa` ($\kappa$), `\lambda` ($\lambda$), `\mu` ($\mu$), `\nu` ($\nu$), `\xi` ($\xi$), `\pi` ($\pi$), `\rho` ($\rho$), `\sigma` ($\sigma$), `\tau` ($\tau$), `\upsilon` ($\upsilon$), `\phi` ($\phi$), `\chi` ($\chi$), `\psi` ($\psi$), `\omega` ($\omega$)
686
723
  - 大写希腊字母(以直立体呈现):`\Delta` ($\Delta$), `\Gamma` ($\Gamma$), `\Theta` ($\Theta$), `\Lambda` ($\Lambda$), `\Xi` ($\Xi$), `\Pi` ($\Pi$), `\Sigma` ($\Sigma$), `\Upsilon` ($\Upsilon$), `\Phi` ($\Phi$), `\Psi` ($\Psi$), `\Omega` ($\Omega$)
687
- - **算术运算符与关系符 (Operators & Relations)**:
724
+ - **算术运算符与关系符**:
688
725
  - `\le` / `\leq` ($\le$), `\ge` / `\geq` ($\ge$), `\ne` / `\neq` ($\ne$)
689
726
  - `\cdot` ($\cdot$), `\times` ($\times$), `\pm` ($\pm$), `\mp` ($\mp$), `\div` ($\div$), `\infty` ($\infty$)
690
727
  - `\approx` ($\approx$), `\sim` ($\sim$), `\cong` ($\cong$), `\propto` ($\propto$), `\equiv` ($\equiv$), `\perp` ($\perp$), `\parallel` ($\parallel$)
691
- - **微积分、集合与逻辑符号 (Calculus, Sets & Logic)**:
728
+ - **微积分、集合与逻辑符号**:
692
729
  - 梯度:`\nabla` ($\nabla$),偏微分:`\partial` ($\partial$)
693
730
  - 逻辑量词与运算:`\forall` ($\forall$),`\exists` ($\exists$),`\neg` ($\neg$),`\land` ($\land$),`\lor` ($\lor$)
694
731
  - 集合关系:`\in` ($\in$),`\notin` ($\notin$),`\ni` ($\ni$),`\subset` ($\subset$),`\supset` ($\supset$),`\subseteq` ($\subseteq$),`\supseteq` ($\supseteq$)
695
732
  - 集合运算:`\cup` ($\cup$),`\cap` ($\cap$),空集:`\emptyset` ($\emptyset$)
696
733
  - 特殊变量与常量:`\ell` ($\ell$), `\hbar` ($\hbar$)
697
734
  - 大型运算符:求和 `\sum` ($\sum$),积分 `\int` ($\int$)
698
- - **箭头符号 (Arrows)**:
735
+ - **箭头符号**:
699
736
  - 单向箭头:`\to` / `\rightarrow` ($\rightarrow$), `\leftarrow` / `\gets` ($\leftarrow$), `\Leftarrow` ($\Leftarrow$), `\Rightarrow` ($\Rightarrow$)
700
737
  - 双向箭头:`\leftrightarrow` ($\leftrightarrow$), `\Leftrightarrow` ($\Leftrightarrow$)
701
- - **省略号 (Dots)**:
738
+ - **省略号**:
702
739
  - 基线省略号:`\dots` / `\ldots` ($\dots$)
703
740
  - 居中省略号:`\cdots` ($\cdots$)
704
- - **矩阵与多行排版 (Matrices & Multi-line Layouts)**:
741
+ - **矩阵与多行排版**:
705
742
  - 矩阵环境:`matrix`, `pmatrix`, `bmatrix`, `vmatrix`, `Vmatrix`(如 `\begin{pmatrix} a & b \\ c & d \end{pmatrix}`)
706
743
  - 方程组与条件分支:`cases`(如 `\begin{cases} x & x \ge 0 \\ -x & x < 0 \end{cases}`)
707
744
  - 通用数组排版:`array`
708
- - 换行与对齐:使用 `\\`、`\\*` 或 `\\[width]`(如 `\\[10px]`)进行换行,以及使用 `&` 进行列对齐
745
+ - 换行与对齐:使用 `\\`、`\\*` 或 `\\[width]` 进行换行,以及使用 `&` 进行列对齐
709
746
 
710
- ### 不支持的语法 (非本库设计目标)
747
+ ## 不支持的语法
711
748
 
712
- 目前还不支持以下 LaTeX 扩展、宏定义或样式微调指令:
749
+ 目前不支持以下 LaTeX 扩展、宏定义或样式微调指令:
713
750
 
714
751
  1. **宏定义命令**:`\newcommand`, `\renewcommand`, `\providecommand`, `\gdef`, `\let` 等。
715
752
  2. **背景色与高级边框**:`\colorbox`, `\fcolorbox`, `\cellcolor` 等(支持 `\boxed`)。
@@ -719,18 +756,16 @@ math {
719
756
  6. **代码/文本抄录**:`\verb` 等。
720
757
  7. **高级上/下标定位**:`\sideset`, `\prescript`, `\cramped`, `\flatfrac` 等。
721
758
  8. **公式编号与自定义标签**:`\tag`, `\newtagform`, `\usetagform` 等。
722
- 9. **任意运算符的限位 (Limits) 强制调整**:除预设的 `\sum`, `\int` 等大型运算符和 `\lim` 等极限算子外,不支持对任意自定义命令或结构使用 `\limits` 强制限位(例如 `\operatorname{sn}\limits_{...}`)。
759
+ 9. **任意运算符的限位强制调整**:除预设的 `\sum`, `\int` 等大型运算符和 `\lim` 等极限算子外,不支持对任意自定义命令或结构使用 `\limits` 强制限位。
723
760
 
724
761
  ## 错误处理与容错机制
725
762
 
726
- 在使用 `@webc.site/math/md.js` 解析 Markdown 文本时,如果数学公式中包含非法的 LaTeX 语法(例如未闭合的 `\left`),内部会自动捕获该语法错误,并优雅地退化为显示原始的公式文本(如 `$$x + \left( y$$`),而不会抛出 JavaScript 异常或导致网页/应用渲染崩溃。因此,调用该函数时**无需**使用 `try...catch` 块包裹。
763
+ 使用 `@webc.site/math/md.js` 解析 Markdown 文本时,若包含非法 LaTeX 语法,内部会自动捕获错误并退化为原始公式文本(如 `$$x + \left( y$$`),不抛出 JS 异常。因此,调用时**无需**包裹 `try...catch`。
727
764
 
728
- 但需要注意的是,如果直接使用 `@webc.site/math` 的默认导出(TeX 编译器核心)来渲染非法的 LaTeX 语法,它会抛出包含错误码的数组(详见下文错误码表)。因此,直接调用 TeX 编译器时建议使用 `try...catch` 进行包裹。
765
+ 如直接调用 `@webc.site/math` 编译非法 LaTeX,则会抛出错误码数组(详见下表),建议使用 `try...catch` 包裹。
729
766
 
730
767
  ### 内部错误码
731
768
 
732
- 在解析器内部编译公式时,可能会产生以下错误码。这些错误码主要在开发或单元测试时用于指示语法错误的具体类型:
733
-
734
769
  | 错误码 | 常量名 | 含义 | 触发示例 |
735
770
  | :----: | :------------------ | :-------------------------------- | :--------------------------------- |
736
771
  | `0` | `ERR_EXTRA_END` | 多余或非法的 `\end` 指令 | `\end{matrix}` (无对应的 `\begin`) |
@@ -738,60 +773,6 @@ math {
738
773
  | `2` | `ERR_EXTRA_RIGHT` | 多余或非法的 `\right` 指令 | `x \right)` (无对应的 `\left`) |
739
774
  | `3` | `ERR_MISSING_BRACE` | 命令缺少必填的大括号参数 | `\text x` (缺少 `{}`) |
740
775
 
741
- ## 什么是 MathML?
742
-
743
- MathML(Mathematical Markup Language,数学标记语言)是一种基于 XML 的标准,用于在 Web 页面中描述数学公式的结构与语义。
744
-
745
- **自 2023 年 1 月起**(随着 Chrome 109 正式启用对 MathML Core 的原生支持),此特性已被所有主流浏览器渲染引擎(Chromium/Blink、Gecko/Firefox、WebKit/Safari)全面且原生支持,这标志着无需加载任何 JavaScript 排版库,即可在绝大多数桌面端、移动端设备及主流浏览器版本中正常、快速地呈现数学公式。
746
-
747
- ### 为什么需要 TeX 公式转 MathML?
748
-
749
- 虽然 MathML 是浏览器原生支持的数学排版标准,但它的 XML 语法极其繁琐,不适合人类直接书写。人类书写数学公式的事实标准是 **TeX/LaTeX** 语法(例如在 Markdown 中书写 `$e^{i\pi} + 1 = 0$`)。
750
-
751
- 传统的网页公式解决方案(如 MathJax 或 KaTeX)在前端运行,需要加载数以百 KB 甚至数 MB 的 JS/CSS 排版引擎,并消耗大量客户端 CPU 进行复杂的 DOM 重绘与排版计算,非常臃肿。
752
-
753
- 使用 `@webc.site/math` 将 TeX 编译为 MathML,可以完美解决这些痛点,尤其在**前端渲染(Client-side Rendering)**场景下具有压倒性优势:
754
-
755
- #### 1. 极致轻量(~1.8 KB Gzip)与零运行依赖
756
-
757
- 相比于 KaTeX (300 KB+) 和 MathJax (数 MB) 的庞大体积,`@webc.site/math` 极其微小。你可以轻松地将它打包进任何前端/单页应用(SPA)中,几乎不增加首屏加载时间。
758
-
759
- #### 2. 利用浏览器原生排版,省去前端渲染引擎
760
-
761
- 传统的公式库不仅是个“解析器”,还包含一整套“前端排版引擎”(用于计算字符宽高、间距,并使用绝对定位生成成百上千个 DOM 节点或 SVG 元素)。而本库只负责在前端将 TeX 代码“翻译”成标准的 MathML 语义标签,具体的排版布局完全交由浏览器底层的 C++ 原生引擎渲染。这极大地解放了浏览器的 JS 线程和主线程。
762
-
763
- #### 3. 流畅的前端实时预览与极低 CPU 消耗
764
-
765
- 因为只做简单的标签翻译,且将排版工作外包给了浏览器原生引擎,本库在前端执行速度极快、CPU 开销极低。这使得它非常适合用于**公式编辑器、Markdown 编辑器等实时预览场景**,输入公式时可以做到瞬时无缝渲染,即使在配置较低的移动端设备上也能保持极高的流畅度。
766
-
767
- #### 4. 前后端通用,统一的技术栈
768
-
769
- 由于编译输出的是纯 HTML 标准的 MathML 元素,无论是作为前端排版(在浏览器端动态转换并插入 DOM),还是在构建期(SSR/SSG)静态编译为 HTML,都能保持完全一致的高效表现。
770
-
771
- ## 性能对比
772
-
773
- 由于 KaTeX 和 MathJax 本身是 TeX 公式编译器(不包含 Markdown 解析功能),为了确保基准测试的公平性,我们使用本库的 TeX 编译器核心([@webc.site/math/mathml.js](https://github.com/webc-site/math/blob/dev/src/mathml.js))直接与它们进行对比。
774
-
775
- ### 1. 体积对比(Gzip 压缩后)
776
-
777
- | 库 | 原始体积 | Gzip 体积 | 尺寸比 |
778
- | :-------------------------------------------- | :-------: | :-------: | :----: |
779
- | @webc.site/math (本库) | 7.78 KB | 3.58 KB | 1.0 ⭐️ |
780
- | [KaTeX](https://github.com/KaTeX/KaTeX) | 264.79 KB | 75.15 KB | 21.0 |
781
- | [MathJax](https://github.com/mathjax/MathJax) | 971.04 KB | 278.39 KB | 77.7 |
782
-
783
- ![](demo/size.svg)
784
-
785
- ### 2. 生成速度对比 (Ops/sec)
786
-
787
- 基于经典公式循环编译测试(使用 [sh/bench/pk.js](https://github.com/webc-site/math/blob/dev/sh/bench/pk.js) 测得):
788
-
789
- - **@webc.site/math (本库)**: ~329, 000 ops/s (1.0 ⭐️)
790
- - **[KaTeX](https://github.com/KaTeX/KaTeX)**: ~92, 000 ops/s (约 3.6x 较慢)
791
- - **[MathJax](https://github.com/mathjax/MathJax)**: ~6, 700 ops/s (约 48.8x 较慢)
792
-
793
- ![](demo/speed.svg)
794
-
795
776
  ## 设计思路与调用流程
796
777
 
797
778
  解析器处理输入的 Markdown 字符串,隔离 TeX 表达式,并将其转换为 MathML 结构。
@@ -816,37 +797,37 @@ graph TD
816
797
  3. **语法分析**:将 Token 转换为抽象语法树(AST)节点,支持分式、上下标及预设数学函数。
817
798
  4. **代码生成**:将 AST 节点映射为标准 XML 节点(`<mi>`、`<mo>`、`<mn>`、`<mfrac>`、`<msup>`、`<msub>`、`<msubsup>`)。
818
799
 
819
- ## 如何添加新的语法支持
800
+ ## 如何添加新语法
820
801
 
821
802
  添加新的 LaTeX 语法支持需要按顺序修改以下四个核心部分:
822
803
 
823
- ### 1. 常量定义 (Constants)
804
+ ### 1. 常量定义
824
805
 
825
806
  定义相应的词法 Token、语法节点类型、函数名或符号映射表:
826
807
 
827
- - **Token 类型**:在 [const/TOK.js](https://github.com/webc-site/math/blob/dev/src/const/TOK.js) 中定义(如 `export const TOK_MY_CMD = ...`,若需要新的词法分类)。
828
- - **节点类型 (AST Node Type)**:在 [const/TYPE.js](https://github.com/webc-site/math/blob/dev/src/const/TYPE.js) 中定义(如 `export const TYPE_MY_NODE = ...`,指定新的语法树节点类型)。
829
- - **环境定界符**:若添加新的环境(如新矩阵或括号类型),需在 [mathml.js](https://github.com/webc-site/math/blob/dev/src/mathml.js)(原 `compile.js`)的 `ENV_DELIMS` 中配置其左右定界符。
808
+ - **Token 类型**:在 [const/TOK.js](https://github.com/webc-site/math/blob/dev/src/const/TOK.js) 中定义(如 `export const TOK_MY_CMD = ...`)。
809
+ - **节点类型**:在 [const/TYPE.js](https://github.com/webc-site/math/blob/dev/src/const/TYPE.js) 中定义(如 `export const TYPE_MY_NODE = ...`)。
810
+ - **环境定界符**:若添加新的环境(如新矩阵或括号类型),需在 [mathml.js](https://github.com/webc-site/math/blob/dev/src/mathml.js) `ENV_DELIMS` 中配置其左右定界符。
830
811
  - **符号映射表**:如果是普通数学符号或简单命令,只需在 [const/SYM.js](https://github.com/webc-site/math/blob/dev/src/const/SYM.js) 的 `SYM_MAP` 中将命令名映射为对应的 Unicode 字符。
831
812
  - **数学函数名**:在 [const/FUNC.js](https://github.com/webc-site/math/blob/dev/src/const/FUNC.js) 的 `FUNC_NAMES` 集合中定义。
832
813
 
833
- ### 2. 词法分析 (Lexer)
814
+ ### 2. 词法分析
834
815
 
835
816
  `lex(str)` 函数负责将 LaTeX 输入字符串切割为 Token 数组。它位于 [lex.js](https://github.com/webc-site/math/blob/dev/src/lex.js)。
836
817
 
837
818
  - 如果引入了新的特殊字符或不同结构,需要更新 `lex` 函数中的字符匹配逻辑,让其识别并向 `tokens` 数组中推送相应的 `TOK_*` 类型和其字面值。
838
819
 
839
- ### 3. 语法分析 (Parser)
820
+ ### 3. 语法分析
840
821
 
841
822
  `parse(tokens, state)` 函数负责将 Token 转换为抽象语法树(AST)节点。它位于 [parse.js](https://github.com/webc-site/math/blob/dev/src/parse.js)。
842
823
 
843
824
  - **命令解析**:主要在 [parse.js](https://github.com/webc-site/math/blob/dev/src/parse.js) 的 `TOK_MAP[TOK_CMD]` 函数中处理。当解析到对应的 LaTeX 命令(如 `\mycmd`)时,读取其参数(可使用 `read(tokens, state_ref)` 或 `grab(tokens, state_ref)`),并返回一个表示该节点的数组:`[TYPE_MY_NODE, arg1, arg2]`。
844
825
 
845
- ### 4. 代码渲染 (Renderer)
826
+ ### 4. 代码渲染
846
827
 
847
- `SHOW_MAP` 字典负责将 AST 节点转换为标准的 MathML 标签字符串。它位于 [mathml.js](https://github.com/webc-site/math/blob/dev/src/mathml.js)(原 `compile.js`)。
828
+ `SHOW_MAP` 字典负责将 AST 节点转换为标准的 MathML 标签字符串。它位于 [mathml.js](https://github.com/webc-site/math/blob/dev/src/mathml.js)
848
829
 
849
- - 注册新的节点渲染函数:`[TYPE_MY_NODE]: ([_, arg1, arg2]) => nest("mylabel", arg1, arg2)` 或 `tag("mi", ...)`,将节点数据格式化为对应的标准 MathML 标记(如 `<mfrac>`、`<msup>` 等)。
830
+ - 注册新的节点渲染函数:`[TYPE_MY_NODE]: ([_, arg1, arg2]) => nest("mylabel", arg1, arg2)`,将节点数据格式化为对应的标准 MathML 标记。
850
831
 
851
832
  ## 技术堆栈
852
833
 
@@ -897,8 +878,8 @@ graph TD
897
878
 
898
879
  ## 历史背景
899
880
 
900
- 传统的 Web 数学公式渲染多依赖 MathJax 或 KaTeX。这类库体积庞大,需要加载大量 JS 文件并执行复杂的排版计算,容易导致页面渲染出现明显的延迟与白屏。
881
+ 传统的 Web 数学公式渲染多依赖 MathJax 或 KaTeX。这类库体积较大,需要加载大量 JS 文件并执行复杂的排版计算,容易导致页面渲染出现延迟与白屏。
901
882
 
902
- MathML(数学标记语言)规范旨在通过浏览器原生支持渲染数学符号。2023 年,Blink 引擎正式支持 MathML Core 标准,标志着 Chrome、Safari 和 Firefox 等主流浏览器全面实现了原生的数学公式排版。
883
+ MathML(数学标记语言)规范旨在通过浏览器原生支持渲染数学符号。2023年,Blink 引擎正式支持 MathML Core 标准,标志着 Chrome、Safari 和 Firefox 等主流浏览器全面实现了原生的数学公式排版。
903
884
 
904
- 配合 `18s` 项目提供的数学字体 `m`(Latin Modern Math,源自高德纳的 Computer Modern 经典字体),`@webc.site/math` 编译器能够将 TeX 公式直接转换为原生的 MathML 元素,完全利用浏览器底层的排版能力,消除了对庞大运行时排版库的依赖。
885
+ 配合 `18s` 项目提供的数学字体 `m`(Latin Modern Math,源自高德纳的 Computer Modern 经典字体),`@webc.site/math` 编译器能够将 TeX 公式直接转换为原生的 MathML 元素,完全利用浏览器底层的排版能力,消除了对运行时排版库的依赖。
package/package.json CHANGED
@@ -1 +1 @@
1
- {"name":"@webc.site/math","version":"0.1.13","description":"The world's smallest and fastest web Markdown formula renderer / 全球最小最快的网页Markdown公式渲染器","keywords":["markdown","math","mathml","render","tex"],"homepage":"https://math.webc.site","license":"MulanPSL-2.0","author":"i18n.site@gmail.com","repository":{"type":"git","url":"git+https://github.com/webc-site/math.git"},"type":"module","exports":{".":{"types":"./mathml.d.ts","default":"./mathml.js"},"./md.js":{"types":"./md.d.ts","default":"./md.js"},"./*":"./*"},"dependencies":{}}
1
+ {"name":"@webc.site/math","version":"0.1.18","description":"The world's smallest and fastest web Markdown formula renderer / 全球最小最快的网页Markdown公式渲染器","keywords":["markdown","math","mathml","render","tex"],"homepage":"https://math.webc.site","license":"MulanPSL-2.0","author":"i18n.site@gmail.com","repository":{"type":"git","url":"git+https://github.com/webc-site/math.git"},"type":"module","exports":{".":{"types":"./mathml.d.ts","default":"./mathml.js"},"./md.js":{"types":"./md.d.ts","default":"./md.js"},"./*":"./*"},"dependencies":{}}