@webc.site/math 0.1.16 → 0.1.19

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 +400 -421
  2. package/package.json +1 -1
package/README.md CHANGED
@@ -14,40 +14,81 @@
14
14
    
15
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>
16
16
 
17
- 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.
18
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)
19
25
  - [Usage](#usage)
20
- - [JavaScript Example](#javascript-example)
21
- - [Markdown Parser Plugins](#markdown-parser-plugins)
26
+ - [JavaScript Examples](#javascript-examples)
22
27
  - [CSS and Math Font Configuration](#css-and-math-font-configuration)
28
+ - [Markdown Parser Plugins](#markdown-parser-plugins)
23
29
  - [Features](#features)
24
30
  - [Supported Syntax List](#supported-syntax-list)
25
- - [Unsupported Syntax (Non-Goals)](#unsupported-syntax-non-goals)
31
+ - [Unsupported Syntax](#unsupported-syntax)
26
32
  - [Error Handling and Fault Tolerance](#error-handling-and-fault-tolerance)
27
33
  - [Internal Error Codes](#internal-error-codes)
28
- - [What is MathML?](#what-is-mathml)
29
- - [Why Compile TeX Formulas to MathML?](#why-compile-tex-formulas-to-mathml)
30
- - [Benchmark](#benchmark)
31
- - [1. Size Comparison (Gzipped)](#1-size-comparison-gzipped)
32
- - [2. Generation Speed (Ops/sec)](#2-generation-speed-opssec)
33
- - [Design and Calling Process](#design-and-calling-process)
34
- - [Module Flow](#module-flow)
35
- - [How to Add Syntax Support](#how-to-add-syntax-support)
36
- - [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)
37
38
  - [2. Lexer](#2-lexer)
38
39
  - [3. Parser](#3-parser)
39
- - [4. Renderer](#4-renderer)
40
+ - [4. Codegen](#4-codegen)
40
41
  - [Tech Stack](#tech-stack)
41
42
  - [Directory Structure](#directory-structure)
42
- - [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)
43
84
 
44
85
  ## Usage
45
86
 
46
- ### JavaScript Example
87
+ ### JavaScript Examples
47
88
 
48
89
  #### 1. Render TeX Formulas Directly
49
90
 
50
- 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):
51
92
 
52
93
  ```javascript
53
94
  import mathml from "@webc.site/math";
@@ -58,7 +99,7 @@ const html = mathml(tex, true); // true for block math, false/empty for inline m
58
99
 
59
100
  #### 2. Replace Formulas in Markdown
60
101
 
61
- 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):
62
103
 
63
104
  ```javascript
64
105
  import mdMath from "@webc.site/math/md.js";
@@ -71,83 +112,62 @@ console.log(html);
71
112
  // Output: Euler's identity: <math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><msup><mi>e</mi><mrow><mi>i</mi><mi>π</mi></mrow></msup><mo>+</mo><mn>1</mn><mo>=</mo><mn>0</mn></mrow><annotation encoding="application/x-tex">e^{i\pi} + 1 = 0</annotation></semantics></math>
72
113
  ```
73
114
 
74
- ### Markdown Parser Plugins
115
+ ### CSS and Math Font Configuration
75
116
 
76
- #### 1. Marked Extension
117
+ 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).
77
118
 
78
- 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
+ #### 1. Online Reference (Recommended)
79
120
 
80
- ```javascript
81
- import { marked } from "marked";
82
- import mathMarked from "@webc.site/math-marked";
121
+ Import the online font in CSS:
83
122
 
84
- marked.use(mathMarked());
85
-
86
- const html = marked.parse("Euler's identity: $$e^{i\\pi} + 1 = 0$$");
123
+ ```css
124
+ /* Import the bundle (includes Source Han Sans t, monospace c, and math font m) */
125
+ @import url("//registry.npmmirror.com/18s/0.2.24/files/_.css");
87
126
  ```
88
127
 
89
- #### 2. Remark Plugin
90
-
91
- 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.
92
-
93
- ```javascript
94
- import { unified } from "unified";
95
- import remarkParse from "remark-parse";
96
- import remarkMath from "remark-math";
97
- import mathRemark from "@webc.site/math-remark";
98
- import remarkHtml from "remark-html";
128
+ Or import the math font `m` only:
99
129
 
100
- const html = await unified()
101
- .use(remarkParse)
102
- .use(remarkMath)
103
- .use(mathRemark)
104
- .use(remarkHtml, { sanitize: false })
105
- .process("Euler's identity: $$e^{i\\pi} + 1 = 0$$");
130
+ ```css
131
+ @import url("//registry.npmmirror.com/18s/0.2.24/files/m.css");
106
132
  ```
107
133
 
108
- #### 3. Markdown-it Plugin
134
+ #### 2. Configure CSS Style
109
135
 
110
- 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.
136
+ Set the font family for the `math` tag in your global CSS stylesheet.
111
137
 
112
- ```javascript
113
- import markdownit from "markdown-it";
114
- import mathMarkdownIt from "@webc.site/math-markdown-it";
138
+ ##### Option A: Using Hosted/Local Fonts (Recommended for best visual quality)
115
139
 
116
- const md = markdownit().use(mathMarkdownIt);
140
+ For projects importing the `18s` font assets (which contains the optimized math font `m` and Source Han Sans `t`):
117
141
 
118
- const html = md.render("Euler's identity: $$e^{i\\pi} + 1 = 0$$");
142
+ ```css
143
+ math {
144
+ /* 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 */
145
+ font-family: m, t, math, sans-serif;
146
+ }
119
147
  ```
120
148
 
121
- ### CSS and Math Font Configuration
149
+ ##### Option B: Using System Math Fonts (Zero external font assets)
122
150
 
123
- 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).
124
-
125
- #### 1. Online Reference (Recommended)
126
-
127
- You can import the online font directly in your CSS:
151
+ Leverage system-default math fonts to minimize loading size:
128
152
 
129
153
  ```css
130
- /* Import the bundle (includes Source Han Sans t, monospace c, and math font m) */
131
- @import url("//registry.npmmirror.com/18s/0.2.24/files/_.css");
154
+ math {
155
+ /* Prioritize system-built-in math fonts, fallback to standard CSS 'math' generic font family, and use sans-serif as a final fallback */
156
+ font-family: "STIX Two Math", "Latin Modern Math", "Cambria Math", math, sans-serif;
157
+ }
132
158
  ```
133
159
 
134
- Or import the math font `m` only:
135
-
136
- ```css
137
- @import url("//registry.npmmirror.com/18s/0.2.24/files/m.css");
138
- ```
160
+ #### 3. Integration with Build Tools
139
161
 
140
- #### 2. Local Installation
162
+ Install the `18s` font package via npm, and import it at your project entry using build tools like Vite or Webpack:
141
163
 
142
164
  ```bash
143
165
  npm install 18s
144
166
  ```
145
167
 
146
- ##### Import Local Font
147
-
148
- 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):
168
+ Import font styles in your project entry file (do not mix JS and CSS imports):
149
169
 
150
- ###### Method 1: Import in JS/TS Entry File
170
+ ##### Method A: Import in JS/TS Entry File
151
171
 
152
172
  ```javascript
153
173
  // Import the bundle (includes Source Han Sans t, monospace c, and math font m)
@@ -160,7 +180,7 @@ Or import math font `m` only:
160
180
  import "18s/m.css";
161
181
  ```
162
182
 
163
- ###### Method 2: Import in CSS Stylesheet
183
+ ##### Method B: Import in CSS Stylesheet
164
184
 
165
185
  ```css
166
186
  /* Import the bundle (includes Source Han Sans t, monospace c, and math font m) */
@@ -173,34 +193,60 @@ Or import math font `m` only:
173
193
  @import "18s/m.css";
174
194
  ```
175
195
 
176
- #### 3. Configure CSS Style
196
+ ### Markdown Parser Plugins
197
+
198
+ #### 1. Marked Extension
177
199
 
178
- 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:
200
+ Use [`@webc.site/math-marked`](https://www.npmjs.com/package/@webc.site/math-marked) to automatically parse and compile inline (`$...$`) and block (`$$...$$`) formulas:
179
201
 
180
- ```css
181
- math {
182
- /* 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 */
183
- font-family: m, t, sans-serif;
184
- }
202
+ ```javascript
203
+ import { marked } from "marked";
204
+ import mathMarked from "@webc.site/math-marked";
205
+
206
+ marked.use(mathMarked());
207
+
208
+ const html = marked.parse("Euler's identity: $$e^{i\\pi} + 1 = 0$$");
185
209
  ```
186
210
 
187
- ## Features
211
+ #### 2. Remark Plugin
188
212
 
189
- - **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).
190
- - **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.
191
- - **Fast Compiler**: Compiles TeX formulas directly to semantic MathML without external parser dependencies.
192
- - **Markdown Integration**: Automatically parses inline math (`$formula$`) and block math (`$$formula$$`) in Markdown text.
193
- - **High Performance**: Only 7.78 KB raw size (3.58 KB gzipped), far smaller than KaTeX and MathJax (see size comparison chart below):
213
+ 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:
194
214
 
195
- | Library | Raw Size | Gzip Size | Size Ratio |
196
- | :---------------------------------------------------------- | :-------: | :-------: | :--------: |
197
- | [@webc.site/math](https://github.com/webc-site/math) (Ours) | 7.78 KB | 3.58 KB | 1.0 ⭐️ |
198
- | [KaTeX](https://github.com/KaTeX/KaTeX) | 264.79 KB | 75.15 KB | 21.0 |
199
- | [MathJax](https://github.com/mathjax/MathJax) | 971.04 KB | 278.39 KB | 77.7 |
215
+ ```javascript
216
+ import { unified } from "unified";
217
+ import remarkParse from "remark-parse";
218
+ import remarkMath from "remark-math";
219
+ import mathRemark from "@webc.site/math-remark";
220
+ import remarkHtml from "remark-html";
200
221
 
201
- ![](demo/size.svg)
222
+ const html = await unified()
223
+ .use(remarkParse)
224
+ .use(remarkMath)
225
+ .use(mathRemark)
226
+ .use(remarkHtml, { sanitize: false })
227
+ .process("Euler's identity: $$e^{i\\pi} + 1 = 0$$");
228
+ ```
202
229
 
203
- - **Standard Compatibility**: Outputs valid MathML elements supported by modern browser layout engines.
230
+ #### 3. Markdown-it Plugin
231
+
232
+ 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`:
233
+
234
+ ```javascript
235
+ import markdownit from "markdown-it";
236
+ import mathMarkdownIt from "@webc.site/math-markdown-it";
237
+
238
+ const md = markdownit().use(mathMarkdownIt);
239
+
240
+ const html = md.render("Euler's identity: $$e^{i\\pi} + 1 = 0$$");
241
+ ```
242
+
243
+ ## Features
244
+
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.
204
250
 
205
251
  ## Supported Syntax List
206
252
 
@@ -210,55 +256,55 @@ Designed to be extremely lightweight, this library supports the most commonly us
210
256
  - **Subscripts & Superscripts**:
211
257
  - Superscript `^` (e.g., `x^2`)
212
258
  - Subscript `_` (e.g., `x_i`)
213
- - Simultaneous subscripts/superscripts (e.g., `x_i^2` or `x^2_i`)
214
- - 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`)
215
261
  - **Fractions**: `\frac{numerator}{denominator}` (e.g., `\frac{a}{b}`)
216
- - **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}`
217
263
  - **Overlines & Bars**: `\overline{x}` and the shorthand `\bar{x}`
218
- - **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:
219
265
  - Parentheses: `(` and `)`
220
266
  - Square brackets: `[` and `]`
221
- - Curly braces: `\{` and `\}`
222
- - Angle brackets: `<` (⟨) and `>` (⟩)
267
+ - Braces: `\{` and `\}`
268
+ - Angle brackets: `<` and `>`
223
269
  - Vertical bars: `|` or `\|`
224
- - 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`)
225
271
  - **Text Mode**: `\text{...}` (e.g., `\text{if }`), extracts literal text inside braces and renders it as MathML `<mtext>` in normal upright font.
226
- - **Horizontal Spacing**: Supports `\quad` (1em space) and `\qquad` (2em space) horizontal spacing.
272
+ - **Horizontal Spacing**: Supports `\quad` (1em spacing) and `\qquad` (2em spacing).
227
273
  - **Styles, Strikethroughs & Phantom**:
228
- - Borders: `\boxed{...}` (adds a border around the formula, e.g., `\boxed{x+y}`)
229
- - Strikethroughs: `\cancel{...}` (crosses out with a diagonal line, e.g., `\cancel{x}`) and `\sout{...}` (crosses out with a horizontal line, e.g., `\sout{y}`)
230
- - Hiding & Spacing: `\phantom{...}` (renders an invisible placeholder with the same width and height as the argument, e.g., `\phantom{x}`)
231
- - **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.
232
- - **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)$)
233
279
  - **Greek Letters**:
234
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$)
235
- - 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$)
236
282
  - **Operators & Relations**:
237
283
  - `\le` / `\leq` ($\le$), `\ge` / `\geq` ($\ge$), `\ne` / `\neq` ($\ne$)
238
284
  - `\cdot` ($\cdot$), `\times` ($\times$), `\pm` ($\pm$), `\mp` ($\mp$), `\div` ($\div$), `\infty` ($\infty$)
239
285
  - `\approx` ($\approx$), `\sim` ($\sim$), `\cong` ($\cong$), `\propto` ($\propto$), `\equiv` ($\equiv$), `\perp` ($\perp$), `\parallel` ($\parallel$)
240
286
  - **Calculus, Sets & Logic**:
241
- - Gradient: `\nabla` ($\nabla$), Partial derivative: `\partial` ($\partial$)
242
- - 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$)
243
289
  - Set relations: `\in` ($\in$), `\notin` ($\notin$), `\ni` ($\ni$), `\subset` ($\subset$), `\supset` ($\supset$), `\subseteq` ($\subseteq$), `\supseteq` ($\supseteq$)
244
- - Set operations: `\cup` ($\cup$), `\cap` ($\cap$), Empty set: `\emptyset` ($\emptyset$)
290
+ - Set operations: `\cup` ($\cup$), `\cap` ($\cap$), empty set: `\emptyset` ($\emptyset$)
245
291
  - Special variables & constants: `\ell` ($\ell$), `\hbar` ($\hbar$)
246
- - Big operators: summation `\sum` ($\sum$), integral `\int` ($\int$)
292
+ - Large operators: summation `\sum` ($\sum$), integration `\int` ($\int$)
247
293
  - **Arrows**:
248
- - Unidirectional: `\to` / `\rightarrow` ($\rightarrow$), `\leftarrow` / `\gets` ($\leftarrow$), `\Leftarrow` ($\Leftarrow$), `\Rightarrow` ($\Rightarrow$)
249
- - Bidirectional: `\leftrightarrow` ($\leftrightarrow$), `\Leftrightarrow` ($\Leftrightarrow$)
250
- - **Ellipses (Dots)**:
294
+ - Single arrows: `\to` / `\rightarrow` ($\rightarrow$), `\leftarrow` / `\gets` ($\leftarrow$), `\Leftarrow` ($\Leftarrow$), `\Rightarrow` ($\Rightarrow$)
295
+ - Double arrows: `\leftrightarrow` ($\leftrightarrow$), `\Leftrightarrow` ($\Leftrightarrow$)
296
+ - **Dots**:
251
297
  - Baseline dots: `\dots` / `\ldots` ($\dots$)
252
- - Center dots: `\cdots` ($\cdots$)
298
+ - Centered dots: `\cdots` ($\cdots$)
253
299
  - **Matrices & Multi-line Layouts**:
254
300
  - Matrix environments: `matrix`, `pmatrix`, `bmatrix`, `vmatrix`, `Vmatrix` (e.g., `\begin{pmatrix} a & b \\ c & d \end{pmatrix}`)
255
- - Systems of equations & conditional branches: `cases` (e.g., `\begin{cases} x & x \ge 0 \\ -x & x < 0 \end{cases}`)
256
- - General-purpose array layouts: `array`
257
- - 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.
258
304
 
259
- ### Unsupported Syntax (Non-Goals)
305
+ ## Unsupported Syntax
260
306
 
261
- 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:
262
308
 
263
309
  1. **Macro Definitions**: `\newcommand`, `\renewcommand`, `\providecommand`, `\gdef`, `\let`, etc.
264
310
  2. **Background Colors & Advanced Borders**: `\colorbox`, `\fcolorbox`, `\cellcolor`, etc. (while `\boxed` is supported).
@@ -268,18 +314,16 @@ Currently, the following LaTeX extensions, macro definitions, or custom styling
268
314
  6. **Verbatim Text**: `\verb`, etc.
269
315
  7. **Advanced Positionings**: `\sideset`, `\prescript`, `\cramped`, `\flatfrac`, etc.
270
316
  8. **Equation Numbering & Custom Tags**: `\tag`, `\newtagform`, `\usetagform`, etc.
271
- 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.
272
318
 
273
319
  ## Error Handling and Fault Tolerance
274
320
 
275
- 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.
276
322
 
277
- 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.
278
324
 
279
325
  ### Internal Error Codes
280
326
 
281
- 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:
282
-
283
327
  | Error Code | Constant | Description | Trigger Example |
284
328
  | :--------: | :------------------ | :-------------------------------------------- | :------------------------------------ |
285
329
  | `0` | `ERR_EXTRA_END` | Extra or invalid `\end` command | `\end{matrix}` (no matching `\begin`) |
@@ -287,171 +331,116 @@ The following error codes are used internally during the compilation phase to si
287
331
  | `2` | `ERR_EXTRA_RIGHT` | Extra or invalid `\right` command | `x \right)` (no matching `\left`) |
288
332
  | `3` | `ERR_MISSING_BRACE` | Command missing required curly brace `{}` | `\text x` (missing braces) |
289
333
 
290
- ## What is MathML?
291
-
292
- MathML (Mathematical Markup Language) is an XML-based standard for describing mathematical notations and capturing both its structure and content on the web.
293
-
294
- **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.
295
-
296
- ### Why Compile TeX Formulas to MathML?
297
-
298
- 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).
299
-
300
- 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.
301
-
302
- 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:
303
-
304
- #### 1. Extremely Lightweight (~1.8 KB Gzip) & Zero Dependencies
305
-
306
- 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.
307
-
308
- #### 2. Native Browser Layout (No Heavy Client-Side Rendering Engine)
309
-
310
- 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.
311
- 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.
312
-
313
- #### 3. Seamless Real-Time Frontend Previews & Low CPU Overhead
314
-
315
- 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.
316
-
317
- #### 4. Unified Frontend and SSR Capabilities
318
-
319
- 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.
320
-
321
- ## Benchmark
322
-
323
- 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.
324
-
325
- ### 1. Size Comparison (Gzipped)
326
-
327
- | Library | Raw Size | Gzip Size | Size Ratio |
328
- | :-------------------------------------------- | :-------: | :-------: | :--------: |
329
- | @webc.site/math (Ours) | 7.78 KB | 3.58 KB | 1.0 ⭐️ |
330
- | [KaTeX](https://github.com/KaTeX/KaTeX) | 264.79 KB | 75.15 KB | 21.0 |
331
- | [MathJax](https://github.com/mathjax/MathJax) | 971.04 KB | 278.39 KB | 77.7 |
332
-
333
- ![](demo/size.svg)
334
-
335
- ### 2. Generation Speed (Ops/sec)
336
-
337
- Based on compiling standard test equations (measured using [sh/bench/pk.js](https://github.com/webc-site/math/blob/dev/sh/bench/pk.js)):
334
+ ## Design and Workflow
338
335
 
339
- - **@webc.site/math (Ours)**: ~329, 000 ops/s (1.0 ⭐️)
340
- - **[KaTeX](https://github.com/KaTeX/KaTeX)**: ~92, 000 ops/s (~3.6x slower)
341
- - **[MathJax](https://github.com/mathjax/MathJax)**: ~6, 700 ops/s (~48.8x slower)
342
-
343
- ![](demo/speed.svg)
344
-
345
- ## Design and Calling Process
346
-
347
- 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.
348
337
 
349
338
  ```mermaid
350
339
  graph TD
351
340
  A[Input Markdown] --> B{Scanner}
352
- B -- Markdown Text --> C[Output Buffer]
353
- B -- TeX Formula --> D[Lexer: Tokenization]
354
- D --> E[Parser: AST Generation]
355
- E --> F[Generator: MathML Tag Creation]
356
- 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]
357
346
  G --> H[MathML Output]
358
347
  C --> I[Final HTML]
359
348
  H --> I
360
349
  ```
361
350
 
362
- ### Module Flow
351
+ ### Module Stages
363
352
 
364
- 1. **Scanner**: Scans the input string to locate delimiters (`$` and `$$`).
365
- 2. **Lexer**: Tokenizes TeX string into numbers, variables, operations, and control characters.
366
- 3. **Parser**: Converts tokens into Abstract Syntax Tree (AST) nodes supporting fractions, subscripts, superscripts, and functions.
367
- 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>`).
368
357
 
369
- ## How to Add Syntax Support
358
+ ## Adding New Syntax
370
359
 
371
- 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:
372
361
 
373
- ### 1. Constants
362
+ ### 1. Constant Definitions
374
363
 
375
- 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:
376
365
 
377
- - **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).
378
- - **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).
379
- - **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`).
380
- - **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).
381
- - **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).
382
371
 
383
372
  ### 2. Lexer
384
373
 
385
- 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).
386
375
 
387
- - 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.
388
377
 
389
378
  ### 3. Parser
390
379
 
391
- 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).
392
381
 
393
- - **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]`.
394
383
 
395
- ### 4. Renderer
384
+ ### 4. Codegen
396
385
 
397
- 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).
398
387
 
399
- - 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.
400
389
 
401
390
  ## Tech Stack
402
391
 
403
392
  - **Runtime**: Bun, Node.js
404
- - **Compilation & Bundling**: SWC (minify), Vite (demo)
405
- - **Development Tools**: oxlint, oxfmt
393
+ - **Build & Bundle**: SWC (compression), Vite (demo site)
394
+ - **Quality Assurance**: oxlint, oxfmt
406
395
 
407
396
  ## Directory Structure
408
397
 
409
398
  ```
410
399
  .
411
- ├── demo/ # Interactive rendering demo site
412
- │ ├── const/ # Constants (formulas, languages)
413
- │ ├── i18n/ # Internationalization translation files
414
- │ ├── 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
415
404
  │ ├── index.pug # Pug HTML template
416
- │ └── style.styl # Premium layout styling
417
- ├── extract/ # Classical formula extraction scripts (KaTeX / MathJax test cases)
418
- ├── lib/ # Compiled production distribution
419
- │ ├── package.json # Minified package.json for NPM publication
420
- │ ├── README.md # Automatically synchronized README for publication
421
- │ ├── mathml.js # Minified distribution JS (TeX compiler)
422
- │ ├── mathml.js.map # Source map for TeX compiler
423
- │ ├── md.js # Minified distribution JS (Markdown parser)
424
- │ └── 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
425
414
  ├── src/ # Source code
426
- │ ├── const/ # Constant definitions (types, symbols, functions, etc.)
427
- │ ├── lex.js # LaTeX formula lexer
428
- │ ├── 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)
429
418
  │ ├── mathml.js # TeX-to-MathML compiler
430
- │ └── md.js # Markdown math formula parser entry point
431
- ├── sh/ # Shell scripts
432
- │ ├── bench/ # Benchmark scripts, shared utilities & history
433
- │ │ ├── pk.js # Size/speed comparison benchmark & SVG generator
434
- │ │ ├── self.js # Performance & size regression test runner
435
- │ │ ├── util.js # Shared benchmark utilities
436
- │ │ ├── chart.js # SVG chart renderer
437
- │ │ └── 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
438
427
  │ └── check.js # Language file validation script
439
- ├── dev.js # Programmatic Vite development server launcher
440
- ├── dist.js # Build & distribution helper script (bumps version, compiles templates)
441
- ├── minify.js # Build minification compiler script
442
- ├── package.json # Project configuration metadata
443
- ├── README.md # Synchronized root project documentation
444
- ├── README.mdt # Markdown template for compiling English, Chinese and About files
445
- └── 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
446
435
  ```
447
436
 
448
- ## History and Background
437
+ ## Historical Background
449
438
 
450
- 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.
451
440
 
452
- 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.
453
442
 
454
- 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.
455
444
 
456
445
  ---
457
446
 
@@ -467,40 +456,81 @@ The `18s` project provides a optimized math font `m` (Latin Modern Math, derived
467
456
  &nbsp;&nbsp;
468
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>
469
458
 
470
- 告别数百 KB 的 KaTeX/MathJax 与臃肿的 CSS 字体包!仅约 4KB (Gzip) 的极致体积,将 LaTeX 公式瞬间编译为现代浏览器原生支持的 MathML,带来零运行开销、零延迟的完美渲染体验。
459
+ 无需引入数百 KB 的 KaTeX/MathJax 及庞大的字体包。包体积仅约 4KB (Gzip),将 LaTeX 公式编译为浏览器原生支持的 MathML,实现零运行开销的公式渲染。
471
460
 
461
+ - [核心优势](#核心优势)
462
+ - [什么是 MathML?](#什么是-mathml)
463
+ - [为什么将 TeX 编译为 MathML?](#为什么将-tex-编译为-mathml)
464
+ - [性能对比](#性能对比)
465
+ - [1. 体积对比(Gzip 压缩)](#1-体积对比gzip-压缩)
466
+ - [2. 生成速度对比](#2-生成速度对比)
472
467
  - [使用方法](#使用方法)
473
468
  - [JavaScript 示例](#javascript-示例)
474
- - [Markdown 解析器插件](#markdown-解析器插件)
475
469
  - [CSS 与数学字体配置](#css-与数学字体配置)
470
+ - [Markdown 解析器插件](#markdown-解析器插件)
476
471
  - [功能特性](#功能特性)
477
472
  - [支持的语法清单](#支持的语法清单)
478
- - [不支持的语法 (非本库设计目标)](#不支持的语法-非本库设计目标)
473
+ - [不支持的语法](#不支持的语法)
479
474
  - [错误处理与容错机制](#错误处理与容错机制)
480
475
  - [内部错误码](#内部错误码)
481
- - [什么是 MathML?](#什么是-mathml)
482
- - [为什么需要 TeX 公式转 MathML?](#为什么需要-tex-公式转-mathml)
483
- - [性能对比](#性能对比)
484
- - [1. 体积对比(Gzip 压缩后)](#1-体积对比gzip-压缩后)
485
- - [2. 生成速度对比 (Ops/sec)](#2-生成速度对比-opssec)
486
476
  - [设计思路与调用流程](#设计思路与调用流程)
487
477
  - [模块运行流程](#模块运行流程)
488
- - [如何添加新的语法支持](#如何添加新的语法支持)
489
- - [1. 常量定义 (Constants)](#1-常量定义-constants)
490
- - [2. 词法分析 (Lexer)](#2-词法分析-lexer)
491
- - [3. 语法分析 (Parser)](#3-语法分析-parser)
492
- - [4. 代码渲染 (Renderer)](#4-代码渲染-renderer)
478
+ - [如何添加新语法](#如何添加新语法)
479
+ - [1. 常量定义](#1-常量定义)
480
+ - [2. 词法分析](#2-词法分析)
481
+ - [3. 语法分析](#3-语法分析)
482
+ - [4. 代码渲染](#4-代码渲染)
493
483
  - [技术堆栈](#技术堆栈)
494
484
  - [目录结构](#目录结构)
495
485
  - [历史背景](#历史背景)
496
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
+
497
527
  ## 使用方法
498
528
 
499
529
  ### JavaScript 示例
500
530
 
501
531
  #### 1. 直接渲染 TeX 公式
502
532
 
503
- 使用 `@webc.site/math`。直接将 TeX 公式编译为 MathML。适合配合 Markdown 解析器(如 markdown-it、marked)实现公式渲染插件。
533
+ 使用 `@webc.site/math` TeX 公式编译为 MathML(适用于 Markdown 渲染插件开发):
504
534
 
505
535
  ```javascript
506
536
  import mathml from "@webc.site/math";
@@ -511,7 +541,7 @@ const html = mathml(tex, true); // 第二个参数传 true 表示块级公式,
511
541
 
512
542
  #### 2. 替换 Markdown 中的公式
513
543
 
514
- 使用 `@webc.site/math/md.js`。输入 Markdown 文本,自动识别其中的行内/块级公式并替换为 MathML。需将公式编译器(如 `@webc.site/math`)作为第二个参数传入。
544
+ 使用 `@webc.site/math/md.js` 自动识别 Markdown 文本中的行内/块级公式并替换为 MathML(需传入公式编译器):
515
545
 
516
546
  ```javascript
517
547
  import mdMath from "@webc.site/math/md.js";
@@ -524,83 +554,62 @@ console.log(html);
524
554
  // 输出: 欧拉恒等式:<math xmlns="http://www.w3.org/1998/Math/MathML" display="block"><semantics><mrow><msup><mi>e</mi><mrow><mi>i</mi><mi>π</mi></mrow></msup><mo>+</mo><mn>1</mn><mo>=</mo><mn>0</mn></mrow><annotation encoding="application/x-tex">e^{i\pi} + 1 = 0</annotation></semantics></math>
525
555
  ```
526
556
 
527
- ### Markdown 解析器插件
557
+ ### CSS 与数学字体配置
528
558
 
529
- #### 1. Marked 插件
559
+ 为保证浏览器原生数学公式的排版,建议配置数学字体。推荐使用 `18s` 字体包的 **Latin Modern Math**(源自高德纳的 Computer Modern 字体,支持 OpenType 数学排版特性)。
530
560
 
531
- 使用 [`@webc.site/math-marked`](https://www.npmjs.com/package/@webc.site/math-marked)。自动解析并编译使用 `marked` 渲染时的行内公式(`$...$`)和块级公式(`$$...$$`)。
561
+ #### 1. 在线引用
532
562
 
533
- ```javascript
534
- import { marked } from "marked";
535
- import mathMarked from "@webc.site/math-marked";
536
-
537
- marked.use(mathMarked());
563
+ 在 CSS 中通过 `@import` 引入在线字体:
538
564
 
539
- const html = marked.parse("欧拉恒等式:$$e^{i\\pi} + 1 = 0$$");
565
+ ```css
566
+ /* 引入合并后的字体 CSS(包含思源黑体 t、代码字体 c 及数学字体 m) */
567
+ @import url("//registry.npmmirror.com/18s/0.2.24/files/_.css");
540
568
  ```
541
569
 
542
- #### 2. Remark 插件
543
-
544
- 使用 [`@webc.site/math-remark`](https://www.npmjs.com/package/@webc.site/math-remark)。用于 Unified / Remark 抽象语法树(AST)转换的插件,无缝将 AST 中的 `inlineMath` 与 `math` 节点替换为原生 MathML HTML。
545
-
546
- ```javascript
547
- import { unified } from "unified";
548
- import remarkParse from "remark-parse";
549
- import remarkMath from "remark-math";
550
- import mathRemark from "@webc.site/math-remark";
551
- import remarkHtml from "remark-html";
570
+ 或者仅按需引入数学字体 `m`:
552
571
 
553
- const html = await unified()
554
- .use(remarkParse)
555
- .use(remarkMath)
556
- .use(mathRemark)
557
- .use(remarkHtml, { sanitize: false })
558
- .process("欧拉恒等式:$$e^{i\\pi} + 1 = 0$$");
572
+ ```css
573
+ @import url("//registry.npmmirror.com/18s/0.2.24/files/m.css");
559
574
  ```
560
575
 
561
- #### 3. Markdown-it 插件
576
+ #### 2. 配置 CSS 样式
562
577
 
563
- 使用 [`@webc.site/math-markdown-it`](https://www.npmjs.com/package/@webc.site/math-markdown-it)。用于 `markdown-it` 的数学公式渲染插件,在解析时自动将行内公式(`$...$`)和块级公式(`$$...$$`)编译为原生 MathML HTML。
578
+ 在全局 CSS 样式表中,为 `math` 标签指定数学字体。
564
579
 
565
- ```javascript
566
- import markdownit from "markdown-it";
567
- import mathMarkdownIt from "@webc.site/math-markdown-it";
580
+ ##### 方案 A:使用托管/本地字体(推荐,效果最完美)
568
581
 
569
- const md = markdownit().use(mathMarkdownIt);
582
+ 引入 `18s` 提供的字体包(含切片优化思源黑体 `t` 与数学字体 `m`):
570
583
 
571
- const html = md.render("欧拉恒等式:$$e^{i\\pi} + 1 = 0$$");
584
+ ```css
585
+ math {
586
+ /* m 为数学字体,t 为思源黑体(对中文字符进行了切片优化以提升加载性能),math 为系统数学字体,sans-serif 为系统默认无衬线字体 */
587
+ font-family: m, t, math, sans-serif;
588
+ }
572
589
  ```
573
590
 
574
- ### CSS 与数学字体配置
575
-
576
- 为了使浏览器原生呈现出排版更精美的数学公式,强烈建议配合专门的数学字体使用。这里我们推荐使用 `18s` 包中提供的 **Latin Modern Math** 数学字体(源自高德纳的经典 Computer Modern 字体,包含完整的数学和技术符号集与 OpenType 排版特性映射)。
577
-
578
- #### 1. 在线引用(推荐)
591
+ ##### 方案 B:使用系统数学字体(免引入外部资源)
579
592
 
580
- 可以直接在 CSS 中通过 `@import` 引入在线字体:
593
+ 直接使用系统内置数学字体以最小化体积:
581
594
 
582
595
  ```css
583
- /* 引入合并后的字体 CSS(包含思源黑体 t、代码字体 c 及数学字体 m) */
584
- @import url("//registry.npmmirror.com/18s/0.2.24/files/_.css");
596
+ math {
597
+ /* 优先使用各平台内置的数学字体,其次降级到 CSS 标准 math 泛型,最后以系统默认无衬线字体作为后备 */
598
+ font-family: "STIX Two Math", "Latin Modern Math", "Cambria Math", math, sans-serif;
599
+ }
585
600
  ```
586
601
 
587
- 或者仅按需引入数学字体 `m`:
588
-
589
- ```css
590
- @import url("//registry.npmmirror.com/18s/0.2.24/files/m.css");
591
- ```
602
+ #### 3. 配合构建工具引用
592
603
 
593
- #### 2. 本地安装字体包
604
+ 通过 npm 安装 `18s` 字体包,配合 Vite、Webpack 等构建工具在项目入口中引入:
594
605
 
595
606
  ```bash
596
607
  npm install 18s
597
608
  ```
598
609
 
599
- ##### 引入本地字体
610
+ 在项目入口文件中引入字体样式(请勿混用 JS 与 CSS 引入):
600
611
 
601
- 根据你的项目,选择以下一种方式引入字体映射关系(注意:请不要把 JS CSS 的引入混在同一个文件中):
602
-
603
- ###### 方式 1:在项目入口 JS/TS 文件中引入
612
+ ##### 方式 A:在 JS/TS 入口中引入
604
613
 
605
614
  ```javascript
606
615
  // 引入合并后的字体 CSS(包含思源黑体 t、代码字体 c 及数学字体 m)
@@ -613,7 +622,7 @@ import "18s/_.css";
613
622
  import "18s/m.css";
614
623
  ```
615
624
 
616
- ###### 方式 2:在项目入口 CSS 文件中引入
625
+ ##### 方式 B:在 CSS 入口中引入
617
626
 
618
627
  ```css
619
628
  /* 引入合并后的字体 CSS(包含思源黑体 t、代码字体 c 及数学字体 m) */
@@ -626,92 +635,118 @@ import "18s/m.css";
626
635
  @import "18s/m.css";
627
636
  ```
628
637
 
629
- #### 3. 配置 CSS 样式
638
+ ### Markdown 解析器插件
630
639
 
631
- 在全局 CSS 样式表中,为 `math` 标签指定数学字体族别名 `m`(其中 `t` 是思源黑体,对中文进行了切片优化):
640
+ #### 1. Marked 插件
632
641
 
633
- ```css
634
- math {
635
- /* m 为数学字体,t 为思源黑体(对中文字符进行了切片优化以提升加载性能),sans-serif 为系统默认无衬线字体 */
636
- font-family: m, t, sans-serif;
637
- }
642
+ 使用 [`@webc.site/math-marked`](https://www.npmjs.com/package/@webc.site/math-marked) 自动解析并编译行内(`$...$`)与块级(`$$...$$`)公式:
643
+
644
+ ```javascript
645
+ import { marked } from "marked";
646
+ import mathMarked from "@webc.site/math-marked";
647
+
648
+ marked.use(mathMarked());
649
+
650
+ const html = marked.parse("欧拉恒等式:$$e^{i\\pi} + 1 = 0$$");
638
651
  ```
639
652
 
640
- ## 功能特性
653
+ #### 2. Remark 插件
641
654
 
642
- - **功能完备**:从 KaTeX 和 MathJax 官方测试用例库中抽取了数千个公式进行编译测试,全部通过(测试用例见 [extract](https://github.com/webc-site/math/tree/dev/extract))。
643
- - **健壮容错**:在解析 Markdown 文本时,公式中的语法错误(如未闭合的 `\left`/`\right` 或其他非法语法)会被自动捕获并优雅退化,直接返回原始的 TeX 代码而不抛出 JavaScript 异常,防止前端应用崩溃。
644
- - **快速编译**:直接编译 TeX 公式为语义化 MathML,无外部解析器依赖。
645
- - **Markdown 集成**:自动解析 Markdown 文本中的行内公式(`$ 公式 $`)和块级公式(`$$ 公式 $$`)。
646
- - **高性能**:原始体积仅 7.78 KB(Gzip 压缩后 3.58 KB),体积远小于 KaTeX 和 MathJax(见下图体积对比):
655
+ 使用 [`@webc.site/math-remark`](https://www.npmjs.com/package/@webc.site/math-remark) 将 Unified/Remark AST 中的 `inlineMath` 与 `math` 节点替换为原生 MathML HTML:
647
656
 
648
- | 库 | 原始体积 | Gzip 体积 | 尺寸比 |
649
- | :---------------------------------------------------------- | :-------: | :-------: | :----: |
650
- | [@webc.site/math](https://github.com/webc-site/math) (本库) | 7.78 KB | 3.58 KB | 1.0 ⭐️ |
651
- | [KaTeX](https://github.com/KaTeX/KaTeX) | 264.79 KB | 75.15 KB | 21.0 |
652
- | [MathJax](https://github.com/mathjax/MathJax) | 971.04 KB | 278.39 KB | 77.7 |
657
+ ```javascript
658
+ import { unified } from "unified";
659
+ import remarkParse from "remark-parse";
660
+ import remarkMath from "remark-math";
661
+ import mathRemark from "@webc.site/math-remark";
662
+ import remarkHtml from "remark-html";
653
663
 
654
- ![](demo/size.svg)
664
+ const html = await unified()
665
+ .use(remarkParse)
666
+ .use(remarkMath)
667
+ .use(mathRemark)
668
+ .use(remarkHtml, { sanitize: false })
669
+ .process("欧拉恒等式:$$e^{i\\pi} + 1 = 0$$");
670
+ ```
655
671
 
656
- - **标准兼容**:输出现代浏览器排版引擎支持的标准 MathML 元素。
672
+ #### 3. Markdown-it 插件
673
+
674
+ 使用 [`@webc.site/math-markdown-it`](https://www.npmjs.com/package/@webc.site/math-markdown-it) 自动解析并渲染 `markdown-it` 中的行内与块级公式:
675
+
676
+ ```javascript
677
+ import markdownit from "markdown-it";
678
+ import mathMarkdownIt from "@webc.site/math-markdown-it";
679
+
680
+ const md = markdownit().use(mathMarkdownIt);
681
+
682
+ const html = md.render("欧拉恒等式:$$e^{i\\pi} + 1 = 0$$");
683
+ ```
684
+
685
+ ## 功能特性
686
+
687
+ - **功能完备**:通过数千个 KaTeX/MathJax 官方测试用例(详见 [extract](https://github.com/webc-site/math/tree/dev/extract))。
688
+ - **健壮容错**:公式语法错误(如未闭合的 `\left`/`\right`)会自动捕获并降级显示原始公式,不抛出异常,防止应用崩溃。
689
+ - **快速编译**:无需外部依赖,直接将 TeX 公式编译为语义化 MathML。
690
+ - **Markdown 集成**:自动解析 Markdown 中的行内公式(`$ 公式 $`)和块级公式(`$$ 公式 $$`)。
691
+ - **标准兼容**:输出现代浏览器原生支持的标准 MathML 元素。
657
692
 
658
693
  ## 支持的语法清单
659
694
 
660
- 本库在极简的包体积下,支持了最常用的数学公式排版语法:
695
+ 本库在极简的包体积下,支持最常用的数学公式排版语法:
661
696
 
662
697
  - **基础算术与符号**:数字、英文字母、基础运算符(`+`, `-`, `*`, `/`, `=`, `<`, `>`, `(`, `)`, `[`, `]`, `.`)。其中 `-` 自动映射为减号 `\u2212`,`*` 映射为星号 `\u2217`,`/` 以直立体呈现。
663
- - **上下标 (Subscripts & Superscripts)**:
698
+ - **上下标**:
664
699
  - 上标 `^`(如 `x^2`)
665
700
  - 下标 `_`(如 `x_i`)
666
701
  - 同时存在上下标(如 `x_i^2` 或 `x^2_i`)
667
- - 对于求和与积分等大型运算符,上下标会自动以限位上下标(limits)形式呈现(如 `\sum_{i=1}^n`,`\int_a^b`)
668
- - **分式 (Fraction)**:`\frac{分子}{分母}`(如 `\frac{a}{b}`)
669
- - **开根号 (Square Root)**:平方根 `\sqrt{x}` 以及 $n$ 次方根 `\sqrt[n]{x}`
670
- - **上划线与横线 (Overlines & Bars)**:`\overline{x}` 及简写形式 `\bar{x}`
671
- - **自适应括号与定界符 (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)`)。支持的定界符包括:
672
707
  - 圆括号:`(` 和 `)`
673
708
  - 方括号:`[` 和 `]`
674
709
  - 花括号:`\{` 和 `\}`
675
- - 尖括号:`<` (⟨) 和 `>` (⟩)
710
+ - 尖括号:`<` 和 `>`
676
711
  - 竖线:`|` 或 `\|`
677
712
  - 空白定界符:`.`(表示不显示该侧定界符,例如 `\left. \frac{df}{dx} \right| _0`)
678
- - **文本模式 (Text Mode)**:`\text{...}`(如 `\text{if }`),提取大括号中的字面文本,渲染为 MathML `<mtext>`,以常规直立体呈现。
679
- - **水平间距 (Horizontal Spacing)**:支持 `\quad`(1em 间距)和 `\qquad`(2em 间距)的空格占位。
680
- - **样式、删除线与占位隐藏 (Styles, Strikethroughs & Phantom)**:
713
+ - **文本模式**:`\text{...}`(如 `\text{if }`),提取大括号中的字面文本,渲染为 MathML `<mtext>`,以常规直立体呈现。
714
+ - **水平间距**:支持 `\quad`(1em 间距)和 `\qquad`(2em 间距)的空格占位。
715
+ - **样式、删除线与占位隐藏**:
681
716
  - 边框:`\boxed{...}`(在公式周围加上边框,如 `\boxed{x+y}`)
682
717
  - 删除线与取消线:`\cancel{...}`(通过斜线划掉,如 `\cancel{x}`)和 `\sout{...}`(通过水平线划掉,如 `\sout{y}`)
683
718
  - 隐藏与占位:`\phantom{...}`(生成与输入内容相同宽高的不可见占位空间,如 `\phantom{x}`)
684
- - **常用数学函数 (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 形式显示在算子正下方。
685
- - **同余括号 (Modulo)**:`\pmod{...}`(生成带括号的同余占位,如 `\pmod{m}` 渲染为 $(mod\ m)$)
686
- - **希腊字母 (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
+ - **希腊字母**:
687
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$)
688
723
  - 大写希腊字母(以直立体呈现):`\Delta` ($\Delta$), `\Gamma` ($\Gamma$), `\Theta` ($\Theta$), `\Lambda` ($\Lambda$), `\Xi` ($\Xi$), `\Pi` ($\Pi$), `\Sigma` ($\Sigma$), `\Upsilon` ($\Upsilon$), `\Phi` ($\Phi$), `\Psi` ($\Psi$), `\Omega` ($\Omega$)
689
- - **算术运算符与关系符 (Operators & Relations)**:
724
+ - **算术运算符与关系符**:
690
725
  - `\le` / `\leq` ($\le$), `\ge` / `\geq` ($\ge$), `\ne` / `\neq` ($\ne$)
691
726
  - `\cdot` ($\cdot$), `\times` ($\times$), `\pm` ($\pm$), `\mp` ($\mp$), `\div` ($\div$), `\infty` ($\infty$)
692
727
  - `\approx` ($\approx$), `\sim` ($\sim$), `\cong` ($\cong$), `\propto` ($\propto$), `\equiv` ($\equiv$), `\perp` ($\perp$), `\parallel` ($\parallel$)
693
- - **微积分、集合与逻辑符号 (Calculus, Sets & Logic)**:
728
+ - **微积分、集合与逻辑符号**:
694
729
  - 梯度:`\nabla` ($\nabla$),偏微分:`\partial` ($\partial$)
695
730
  - 逻辑量词与运算:`\forall` ($\forall$),`\exists` ($\exists$),`\neg` ($\neg$),`\land` ($\land$),`\lor` ($\lor$)
696
731
  - 集合关系:`\in` ($\in$),`\notin` ($\notin$),`\ni` ($\ni$),`\subset` ($\subset$),`\supset` ($\supset$),`\subseteq` ($\subseteq$),`\supseteq` ($\supseteq$)
697
732
  - 集合运算:`\cup` ($\cup$),`\cap` ($\cap$),空集:`\emptyset` ($\emptyset$)
698
733
  - 特殊变量与常量:`\ell` ($\ell$), `\hbar` ($\hbar$)
699
734
  - 大型运算符:求和 `\sum` ($\sum$),积分 `\int` ($\int$)
700
- - **箭头符号 (Arrows)**:
735
+ - **箭头符号**:
701
736
  - 单向箭头:`\to` / `\rightarrow` ($\rightarrow$), `\leftarrow` / `\gets` ($\leftarrow$), `\Leftarrow` ($\Leftarrow$), `\Rightarrow` ($\Rightarrow$)
702
737
  - 双向箭头:`\leftrightarrow` ($\leftrightarrow$), `\Leftrightarrow` ($\Leftrightarrow$)
703
- - **省略号 (Dots)**:
738
+ - **省略号**:
704
739
  - 基线省略号:`\dots` / `\ldots` ($\dots$)
705
740
  - 居中省略号:`\cdots` ($\cdots$)
706
- - **矩阵与多行排版 (Matrices & Multi-line Layouts)**:
741
+ - **矩阵与多行排版**:
707
742
  - 矩阵环境:`matrix`, `pmatrix`, `bmatrix`, `vmatrix`, `Vmatrix`(如 `\begin{pmatrix} a & b \\ c & d \end{pmatrix}`)
708
743
  - 方程组与条件分支:`cases`(如 `\begin{cases} x & x \ge 0 \\ -x & x < 0 \end{cases}`)
709
744
  - 通用数组排版:`array`
710
- - 换行与对齐:使用 `\\`、`\\*` 或 `\\[width]`(如 `\\[10px]`)进行换行,以及使用 `&` 进行列对齐
745
+ - 换行与对齐:使用 `\\`、`\\*` 或 `\\[width]` 进行换行,以及使用 `&` 进行列对齐
711
746
 
712
- ### 不支持的语法 (非本库设计目标)
747
+ ## 不支持的语法
713
748
 
714
- 目前还不支持以下 LaTeX 扩展、宏定义或样式微调指令:
749
+ 目前不支持以下 LaTeX 扩展、宏定义或样式微调指令:
715
750
 
716
751
  1. **宏定义命令**:`\newcommand`, `\renewcommand`, `\providecommand`, `\gdef`, `\let` 等。
717
752
  2. **背景色与高级边框**:`\colorbox`, `\fcolorbox`, `\cellcolor` 等(支持 `\boxed`)。
@@ -721,18 +756,16 @@ math {
721
756
  6. **代码/文本抄录**:`\verb` 等。
722
757
  7. **高级上/下标定位**:`\sideset`, `\prescript`, `\cramped`, `\flatfrac` 等。
723
758
  8. **公式编号与自定义标签**:`\tag`, `\newtagform`, `\usetagform` 等。
724
- 9. **任意运算符的限位 (Limits) 强制调整**:除预设的 `\sum`, `\int` 等大型运算符和 `\lim` 等极限算子外,不支持对任意自定义命令或结构使用 `\limits` 强制限位(例如 `\operatorname{sn}\limits_{...}`)。
759
+ 9. **任意运算符的限位强制调整**:除预设的 `\sum`, `\int` 等大型运算符和 `\lim` 等极限算子外,不支持对任意自定义命令或结构使用 `\limits` 强制限位。
725
760
 
726
761
  ## 错误处理与容错机制
727
762
 
728
- 在使用 `@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`。
729
764
 
730
- 但需要注意的是,如果直接使用 `@webc.site/math` 的默认导出(TeX 编译器核心)来渲染非法的 LaTeX 语法,它会抛出包含错误码的数组(详见下文错误码表)。因此,直接调用 TeX 编译器时建议使用 `try...catch` 进行包裹。
765
+ 如直接调用 `@webc.site/math` 编译非法 LaTeX,则会抛出错误码数组(详见下表),建议使用 `try...catch` 包裹。
731
766
 
732
767
  ### 内部错误码
733
768
 
734
- 在解析器内部编译公式时,可能会产生以下错误码。这些错误码主要在开发或单元测试时用于指示语法错误的具体类型:
735
-
736
769
  | 错误码 | 常量名 | 含义 | 触发示例 |
737
770
  | :----: | :------------------ | :-------------------------------- | :--------------------------------- |
738
771
  | `0` | `ERR_EXTRA_END` | 多余或非法的 `\end` 指令 | `\end{matrix}` (无对应的 `\begin`) |
@@ -740,60 +773,6 @@ math {
740
773
  | `2` | `ERR_EXTRA_RIGHT` | 多余或非法的 `\right` 指令 | `x \right)` (无对应的 `\left`) |
741
774
  | `3` | `ERR_MISSING_BRACE` | 命令缺少必填的大括号参数 | `\text x` (缺少 `{}`) |
742
775
 
743
- ## 什么是 MathML?
744
-
745
- MathML(Mathematical Markup Language,数学标记语言)是一种基于 XML 的标准,用于在 Web 页面中描述数学公式的结构与语义。
746
-
747
- **自 2023 年 1 月起**(随着 Chrome 109 正式启用对 MathML Core 的原生支持),此特性已被所有主流浏览器渲染引擎(Chromium/Blink、Gecko/Firefox、WebKit/Safari)全面且原生支持,这标志着无需加载任何 JavaScript 排版库,即可在绝大多数桌面端、移动端设备及主流浏览器版本中正常、快速地呈现数学公式。
748
-
749
- ### 为什么需要 TeX 公式转 MathML?
750
-
751
- 虽然 MathML 是浏览器原生支持的数学排版标准,但它的 XML 语法极其繁琐,不适合人类直接书写。人类书写数学公式的事实标准是 **TeX/LaTeX** 语法(例如在 Markdown 中书写 `$e^{i\pi} + 1 = 0$`)。
752
-
753
- 传统的网页公式解决方案(如 MathJax 或 KaTeX)在前端运行,需要加载数以百 KB 甚至数 MB 的 JS/CSS 排版引擎,并消耗大量客户端 CPU 进行复杂的 DOM 重绘与排版计算,非常臃肿。
754
-
755
- 使用 `@webc.site/math` 将 TeX 编译为 MathML,可以完美解决这些痛点,尤其在**前端渲染(Client-side Rendering)**场景下具有压倒性优势:
756
-
757
- #### 1. 极致轻量(~1.8 KB Gzip)与零运行依赖
758
-
759
- 相比于 KaTeX (300 KB+) 和 MathJax (数 MB) 的庞大体积,`@webc.site/math` 极其微小。你可以轻松地将它打包进任何前端/单页应用(SPA)中,几乎不增加首屏加载时间。
760
-
761
- #### 2. 利用浏览器原生排版,省去前端渲染引擎
762
-
763
- 传统的公式库不仅是个“解析器”,还包含一整套“前端排版引擎”(用于计算字符宽高、间距,并使用绝对定位生成成百上千个 DOM 节点或 SVG 元素)。而本库只负责在前端将 TeX 代码“翻译”成标准的 MathML 语义标签,具体的排版布局完全交由浏览器底层的 C++ 原生引擎渲染。这极大地解放了浏览器的 JS 线程和主线程。
764
-
765
- #### 3. 流畅的前端实时预览与极低 CPU 消耗
766
-
767
- 因为只做简单的标签翻译,且将排版工作外包给了浏览器原生引擎,本库在前端执行速度极快、CPU 开销极低。这使得它非常适合用于**公式编辑器、Markdown 编辑器等实时预览场景**,输入公式时可以做到瞬时无缝渲染,即使在配置较低的移动端设备上也能保持极高的流畅度。
768
-
769
- #### 4. 前后端通用,统一的技术栈
770
-
771
- 由于编译输出的是纯 HTML 标准的 MathML 元素,无论是作为前端排版(在浏览器端动态转换并插入 DOM),还是在构建期(SSR/SSG)静态编译为 HTML,都能保持完全一致的高效表现。
772
-
773
- ## 性能对比
774
-
775
- 由于 KaTeX 和 MathJax 本身是 TeX 公式编译器(不包含 Markdown 解析功能),为了确保基准测试的公平性,我们使用本库的 TeX 编译器核心([@webc.site/math/mathml.js](https://github.com/webc-site/math/blob/dev/src/mathml.js))直接与它们进行对比。
776
-
777
- ### 1. 体积对比(Gzip 压缩后)
778
-
779
- | 库 | 原始体积 | Gzip 体积 | 尺寸比 |
780
- | :-------------------------------------------- | :-------: | :-------: | :----: |
781
- | @webc.site/math (本库) | 7.78 KB | 3.58 KB | 1.0 ⭐️ |
782
- | [KaTeX](https://github.com/KaTeX/KaTeX) | 264.79 KB | 75.15 KB | 21.0 |
783
- | [MathJax](https://github.com/mathjax/MathJax) | 971.04 KB | 278.39 KB | 77.7 |
784
-
785
- ![](demo/size.svg)
786
-
787
- ### 2. 生成速度对比 (Ops/sec)
788
-
789
- 基于经典公式循环编译测试(使用 [sh/bench/pk.js](https://github.com/webc-site/math/blob/dev/sh/bench/pk.js) 测得):
790
-
791
- - **@webc.site/math (本库)**: ~329, 000 ops/s (1.0 ⭐️)
792
- - **[KaTeX](https://github.com/KaTeX/KaTeX)**: ~92, 000 ops/s (约 3.6x 较慢)
793
- - **[MathJax](https://github.com/mathjax/MathJax)**: ~6, 700 ops/s (约 48.8x 较慢)
794
-
795
- ![](demo/speed.svg)
796
-
797
776
  ## 设计思路与调用流程
798
777
 
799
778
  解析器处理输入的 Markdown 字符串,隔离 TeX 表达式,并将其转换为 MathML 结构。
@@ -818,37 +797,37 @@ graph TD
818
797
  3. **语法分析**:将 Token 转换为抽象语法树(AST)节点,支持分式、上下标及预设数学函数。
819
798
  4. **代码生成**:将 AST 节点映射为标准 XML 节点(`<mi>`、`<mo>`、`<mn>`、`<mfrac>`、`<msup>`、`<msub>`、`<msubsup>`)。
820
799
 
821
- ## 如何添加新的语法支持
800
+ ## 如何添加新语法
822
801
 
823
802
  添加新的 LaTeX 语法支持需要按顺序修改以下四个核心部分:
824
803
 
825
- ### 1. 常量定义 (Constants)
804
+ ### 1. 常量定义
826
805
 
827
806
  定义相应的词法 Token、语法节点类型、函数名或符号映射表:
828
807
 
829
- - **Token 类型**:在 [const/TOK.js](https://github.com/webc-site/math/blob/dev/src/const/TOK.js) 中定义(如 `export const TOK_MY_CMD = ...`,若需要新的词法分类)。
830
- - **节点类型 (AST Node Type)**:在 [const/TYPE.js](https://github.com/webc-site/math/blob/dev/src/const/TYPE.js) 中定义(如 `export const TYPE_MY_NODE = ...`,指定新的语法树节点类型)。
831
- - **环境定界符**:若添加新的环境(如新矩阵或括号类型),需在 [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` 中配置其左右定界符。
832
811
  - **符号映射表**:如果是普通数学符号或简单命令,只需在 [const/SYM.js](https://github.com/webc-site/math/blob/dev/src/const/SYM.js) 的 `SYM_MAP` 中将命令名映射为对应的 Unicode 字符。
833
812
  - **数学函数名**:在 [const/FUNC.js](https://github.com/webc-site/math/blob/dev/src/const/FUNC.js) 的 `FUNC_NAMES` 集合中定义。
834
813
 
835
- ### 2. 词法分析 (Lexer)
814
+ ### 2. 词法分析
836
815
 
837
816
  `lex(str)` 函数负责将 LaTeX 输入字符串切割为 Token 数组。它位于 [lex.js](https://github.com/webc-site/math/blob/dev/src/lex.js)。
838
817
 
839
818
  - 如果引入了新的特殊字符或不同结构,需要更新 `lex` 函数中的字符匹配逻辑,让其识别并向 `tokens` 数组中推送相应的 `TOK_*` 类型和其字面值。
840
819
 
841
- ### 3. 语法分析 (Parser)
820
+ ### 3. 语法分析
842
821
 
843
822
  `parse(tokens, state)` 函数负责将 Token 转换为抽象语法树(AST)节点。它位于 [parse.js](https://github.com/webc-site/math/blob/dev/src/parse.js)。
844
823
 
845
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]`。
846
825
 
847
- ### 4. 代码渲染 (Renderer)
826
+ ### 4. 代码渲染
848
827
 
849
- `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)
850
829
 
851
- - 注册新的节点渲染函数:`[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 标记。
852
831
 
853
832
  ## 技术堆栈
854
833
 
@@ -899,8 +878,8 @@ graph TD
899
878
 
900
879
  ## 历史背景
901
880
 
902
- 传统的 Web 数学公式渲染多依赖 MathJax 或 KaTeX。这类库体积庞大,需要加载大量 JS 文件并执行复杂的排版计算,容易导致页面渲染出现明显的延迟与白屏。
881
+ 传统的 Web 数学公式渲染多依赖 MathJax 或 KaTeX。这类库体积较大,需要加载大量 JS 文件并执行复杂的排版计算,容易导致页面渲染出现延迟与白屏。
903
882
 
904
- MathML(数学标记语言)规范旨在通过浏览器原生支持渲染数学符号。2023 年,Blink 引擎正式支持 MathML Core 标准,标志着 Chrome、Safari 和 Firefox 等主流浏览器全面实现了原生的数学公式排版。
883
+ MathML(数学标记语言)规范旨在通过浏览器原生支持渲染数学符号。2023年,Blink 引擎正式支持 MathML Core 标准,标志着 Chrome、Safari 和 Firefox 等主流浏览器全面实现了原生的数学公式排版。
905
884
 
906
- 配合 `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.16","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.19","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":{}}