Skip to content

Render textbook LaTeX as static MathML - #17

Merged
erinepshovel-code merged 16 commits into
mainfrom
agent/repair-textbook-math
Jul 25, 2026
Merged

erinepshovel-code merged 16 commits into
mainfrom
agent/repair-textbook-math

Conversation

@erinepshovel-code

Copy link
Copy Markdown
Contributor

Purpose

Repairs the actual current textbook defect: source LaTeX is fetched and displayed, but the existing plain markdown-it path has no math renderer and can consume \(, \), \[, and \] as ordinary Markdown escapes. The result is visibly untypeset or malformed mathematics even though the owning chapter source is intact.

What changed

  • adds a repository-owned Markdown adapter that recognizes:
    • inline \(...\)
    • display \[...\]
    • display $$...$$
    • supported AMS equation, align, alignat, gather, and CD environments
  • intercepts math before Markdown escaping
  • renders at build time through exactly pinned temml@0.13.3
  • emits semantic, annotated MathML with the original TeX retained in <annotation encoding="application/x-tex">
  • keeps untrusted Temml commands disabled and bounds expansion and author-specified size
  • fails the site build when a recognized expression cannot be parsed instead of publishing broken notation
  • adds local MathML presentation and horizontal containment without bundling a font or loading a remote resource
  • states explicitly that the complete mathematics remains available with JavaScript disabled

Source and authority boundary

No textbook source file is modified. Chapter One remains owned by The-Interdependency/ucns:docs/chapter-1.md, and every displayed chapter remains bound to its exact source commit, blob, and SHA-256 identity.

The renderer proves only that the source notation was converted into MathML. It does not evaluate an equation, confer proof status, repair source mathematics, or transfer authority between repositories.

No runtime renderer

The generated chapter contains the MathML directly. There is no KaTeX, MathJax, Temml, jsDelivr, unpkg, or other runtime script dependency. The existing site JavaScript remains limited to the compact navigation enhancement.

Gates added

  • parser test for inline, display, cases, and AMS syntax
  • code-fence exclusion test
  • invalid-expression fail-closed test
  • generated Chapter One test requiring substantial MathML coverage and rejecting leaked delimiters
  • generated artifact test requiring the local math stylesheet and rejecting runtime renderer URLs
  • Chromium test with JavaScript disabled requiring visible inline and display MathML and overflow containment

Build dependency

  • temml is pinned exactly at 0.13.3
  • package-lock.json was regenerated by Node 24/npm and records the package tarball integrity
  • the one-time lock-generation workflow was removed before this pull request

hmmm

Native MathML gives the site static, semantic, no-JavaScript mathematics. Cross-browser font metrics can still differ because this repair deliberately uses locally available math fonts rather than shipping a font file; the release gate now catches absence and gross presentation failure, while pixel-identical typography remains outside the contract.

@erinepshovel-code
erinepshovel-code marked this pull request as ready for review July 25, 2026 02:45
@erinepshovel-code
erinepshovel-code merged commit 3a5c51a into main Jul 25, 2026
5 checks passed

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 4735149b5f

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread scripts/markdown-math.mjs
{ open: '$$', close: '$$', displayMode: true }
];

const AMS_ENVIRONMENT = /^\\begin\{(equation\*?|align\*?|alignat\*?|gather\*?|CD)\}\s*$/;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Accept alignat's required column argument

When a chapter uses a valid standalone AMS environment such as \begin{alignat}{2}, this anchored expression rejects the opener because alignat requires a column-count argument after the environment name. Consequently mathBlock declines the block and Markdown publishes the raw TeX instead of MathML, despite the renderer explicitly advertising alignat support; recognize and preserve the mandatory {n} argument for both alignat and alignat*.

Useful? React with 👍 / 👎.

Comment thread scripts/markdown-math.mjs
Comment on lines +127 to +129
const contentStart = state.pos + fence.open.length;
const contentEnd = state.src.indexOf(fence.close, contentStart);
if (contentEnd < 0) return false;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Fail on unclosed inline TeX fences

When inline source contains an unclosed recognized opener such as Let \(x, returning false hands it to Markdown's escape rule, which silently publishes Let (x instead of failing the build. This contradicts the adapter's fail-closed behavior and makes a delimiter typo corrupt the displayed notation; once an unambiguous \( or \[ opener is encountered, report the missing closing fence rather than treating it as ordinary Markdown.

Useful? React with 👍 / 👎.

Comment thread scripts/markdown-math.mjs
Comment on lines +131 to +134
if (!silent) {
const token = state.push('math_inline', 'math', 0);
token.content = state.src.slice(contentStart, contentEnd);
token.meta = { displayMode: fence.displayMode };

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Preserve formulas in image alternative text

When a chapter uses math in an image label, such as ![Graph of \(f(x)\)](/graph.svg), this custom token is parsed inside the label but MarkdownIt's image renderer omits unknown token types while constructing alt, producing only alt="Graph of ". The formula therefore disappears for screen-reader users even though it remains part of the source; provide a plain-text representation of math tokens when rendering image alternative text.

Useful? React with 👍 / 👎.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant