Skip to content

Support mathjax (v3) math rendering#98

Closed
pelson wants to merge 8 commits into
ipython:masterfrom
pelson:feature/mathjax3
Closed

Support mathjax (v3) math rendering#98
pelson wants to merge 8 commits into
ipython:masterfrom
pelson:feature/mathjax3

Conversation

@pelson
Copy link
Copy Markdown
Member

@pelson pelson commented Jun 4, 2026

Closes #90 and #96.

Follows-up from lessons learned in #96 to introduce an xkcd-script-mathjax3.js file that you can include to have XKCD rendering of mathjax (v3). I believe that mathjax v4 gives us more flexibility in terms of custom fonts etc., but for now I targeted v3 as it is still particularly prevalent in the wild. I designed this setup to easily add v4 support independently of the v3 one (and it shouldn't be as much work as was done here).

pelson added 8 commits June 4, 2026 07:04
Introduces xkcd-mathjax3.js, a self-contained drop-in script that
renders MathJax 3 CHTML through xkcd-script:

- Hand-drawn sqrt surd and fraction-vinculum overlays built at runtime
  from font-extracted glyph outlines via a cut-and-extend algorithm
  (no manually maintained SVG paths in the script).
- pt8a_mathjax3.py orchestrator extracts the extensible glyph data
  from pt7's SFD and splices it into the script between markers.
- ss01 stylistic-alternate wiring for display-sized sigma / pi /
  integral: the base font carries inline-sized summation / product /
  integral at U+2211 / U+220F / U+222B with unencoded .disp variants
  reached via the ss01 feature, so a single xkcd-script.woff serves
  both body text and MathJax math (no separate math font).
- Initial samples directory with playwright-driven PNG generator.
  Each YAML group may carry a `mathjax: { packages: [...], tags: ... }`
  block so each sample loads only the MathJax TeX-input packages it
  needs; the default is no extras.
- ss01 GSUB lookup registered under DFLT script so browsers shape the
  common-script U+2211 / U+220F / U+222B operators through the feature
  (without DFLT binding, font-feature-settings has no effect on those
  codepoints and operators render at letter size).
- Consolidate inline-sum / inline-int / inline-prod into a single
  inline-ops multi-formula grid so the three inline operators diff
  together against the same render context.
MathJax CHTML wraps each char of \text{...} in a width-0 mjx-c with
padding-right baked from MJXTEX metrics, which produced fake-ligature
overlaps and big gaps when xkcd-script's different advances were
applied.  Collapse mjx-c / mjx-c::before inside mjx-mtext to
display: inline; padding: 0; width: auto so the text run flows
naturally through HarfBuzz instead.
Three DOM-overlay passes in xkcd-mathjax3.js — replaceStretchyBraces,
replaceStretchyParens, replaceStretchyBrackets — replace the MathJax
CHTML stacked-piece assemblies (mjx-stretchy-v) and TEX-Sn sized
variants with hand-drawn glyphs extended via the cut-and-extend
runtime.

- braceleft.tall + tall paren imports (pt5), bracket reuses the
  regular bracketleft glyph for straight strokes.
- Paren strokes thin uniformly with thicknessScale (X+Y shrink, then
  Y restored), compact mode for \binom via mjx-texatom detection.
- TEX-S1 filtered out so \bigl[ etc. stay at MathJax's intended size.
replaceCombiningAccents rewrites single-letter \hat / \bar / \tilde
/ \dot / \ddot / \check / \breve / \acute / \grave mover boxes
as a mjx-c-accent text node containing baseChar + combiningChar, so
HarfBuzz shapes the pair through xkcd-script's mark anchors instead
of falling back to MathJax's CSS-positioned overlay.

The injected base character comes from the math-italic codepoint
directly — pt6 cmap-aliases math-italic / bold / Greek codepoints
to their plain Latin / Greek glyphs, so the browser shapes the
text node through the alias automatically (no JS-side codepoint
remapping needed).

replaceWideMovers handles \vec (font's U+2192 overlay), \overline
(emdash extender), \widehat / \widetilde (CSS-centred non-stretchy
caret/wave).
- replaceVerticalRules + grouped rule collection draw one continuous
  hand-drawn bar per shared edge in array / matrix tables, instead of
  per-cell border segments.  Vertical bars are mirrorBarHTML rotated
  90° around their top-left corner.
- replaceVinculums groups bars by row to avoid stitched-together
  segments at row boundaries, and honours dataset.xkcdHidden so the
  sqrt's combined surd+bar overlay does not get a second bar painted
  on top.
- Digit-1 padding: collapse mjx-mn mjx-c padding to 0 / width auto,
  mirroring the mjx-mtext fix — xkcd-script's narrow `1` no longer
  leaves a visible gap right of every digit.
arrowright is added as an extensible glyph (EXTENSIBLE_CONFIG entry)
and replaceStretchyArrows overlays stretched copies for:

- \xrightarrow{f} / \xleftarrow{g} with labelled arrows.
- \overrightarrow{ABC} / \overleftarrow{ABC} wide-mover cases (the
  single non-stretchy fallback in replaceWideMovers is replaced for
  multi-letter bases).
- \vec{multi-letter} where the natural -> would look undersized.
- All four AMScd directions (CD horizontal + vertical arrows).
  The amscd-commutative-diagram sample opts into the [tex]/amscd
  package via its `mathjax:` block — no other sample loads amscd.
- \circ (U+2218): reuses the ring contours extracted from Å (same
  hand-drawn shape used as a diacritic above å/ů), recentred on the
  math axis.
- \ast (U+2217): asterisk outlines translated down to the math axis.
- \otimes (U+2297): hand-drawn from the 2034 equations comic via
  extras/2034_equations_2x__circled_times.png.
- Use createChar(cp, name) instead of createMappedChar(cp) when adding
  Unicode-mapped glyphs in pt6 — createMappedChar leaves unicode=-1 in
  the SFD and the OTF cmap omits the codepoint (which is why \cdot
  had been silently falling back to MJXTEX since it was introduced).
- Samples: align-eqref (AMS align + tag + eqref, opts into the
  [tex]/ams package via its `mathjax:` block) and math-symbols-zoo
  (binops / relations / arrows / delimiters / logic / misc reference).
@pelson pelson closed this Jun 4, 2026
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.

Mathjax rendering

1 participant