Gatongone47 downloadsFlip LaTeX formulas in your notes horizontally, vertically, or both, while keeping them real typeset math that stays selectable and searchable.
Mirror LaTeX formulas in Obsidian: $\mirrorh{...}$ flips a formula left/right,
$\mirrorv{...}$ flips it upside down.
$\mirrorh{\frac{a}{b}}$ whole formula, horizontal reflection
$\mirrorv{\vec{v}}$ whole formula, vertical reflection
$$\mirrorh{\begin{cases}a&b\\c&d\end{cases}}$$
$\mirrorhv{\int_0^1 f(x)\,dx}$ both axes (180° rotation)
$\mirrorh{\mirrorv{x}}$ nesting composes, same as \mirrorhv
$x + \mirrorv{\frac{a}{b}} = y$ only the fraction is flipped
The reflection is a CSS transform (scaleX(-1) / scaleY(-1)) applied to the
real MathJax output, not an image and not reordered characters, so mirrored
formulas stay selectable, searchable, theme-aware and vector-sharp when printed.
Requires Obsidian 1.13.7 or later (that is the version the MathJax internals it relies on were verified against). Works on desktop and mobile.
Install Math Mirror from the community plugin directory: Settings → Community plugins → Browse, search for "Math Mirror", then Install and Enable.
Before the directory listing is live, either use BRAT
with the repository Gatongone/MathMirror, or build it yourself:
npm install
npm run build
npm run deploy # copies into C:\Projects\Obsidian\Notes\.obsidian\plugins\math-mirror
Use $env:OBSIDIAN_VAULT = "D:\MyVault"; npm run deploy for another vault, or copy
manifest.json, main.js and styles.css into
<vault>/.obsidian/plugins/math-mirror/ yourself, then enable Math Mirror in
Settings → Community plugins. The folder name has to match the plugin id,
math-mirror.
Math that is already on screen when the plugin is enabled is not re-rendered by Obsidian (post processors only run while rendering). Reopen the note or toggle between editing and reading mode.
Math Mirror does not use the network, does not collect telemetry, does not show ads, and does not require an account. It only reads the notes you have open, works with the MathJax build Obsidian already ships, and writes nothing outside the rendered math in the DOM.
Two cases, decided per formula:
math-mirror + axis classes
on the .math element). Nested wrappers compose as reflections do - the same
axis twice cancels - so \mirrorh{\mirrorv{x}} is 180° and \mirrorh{\mirrorh{x}}
is the identity.$x + \mirrorv{\frac{a}{b}} = y$) is
rewritten to MathJax's own \class{mjx-mirror-v}{...}: MathJax then puts that
class on the rendered element of exactly that part (mjx-mfrac, mjx-mrow, …,
which its stylesheet already makes display: inline-block) and CSS reflects it.
The class name must start with mjx-, because MathJax's Safe extension filters
out every other class.Those two cases are implemented differently per view, because Obsidian renders math in two very different ways:
<span class="math math-inline">TeX</span> (delimiters already stripped)
and typesets it later. The plugin's markdown post processor registers with
sortOrder = -1, i.e. before Obsidian's math processor (sortOrder = 0), so it
always sees the raw TeX, whatever the MathJax loading state: it rewrites the TeX
and marks the element when the whole formula is wrapped. MathJax then typesets
into that same element, so the CSS transform applies to the real output.view.posAtDOM, reads the $...$ source from the document,
re-renders the rewritten TeX with renderMath, swaps the MathJax node and marks
the widget. Obsidian's widget stays in charge of layout, click-to-edit and the
block edit button.$\mirrorh{\mathcal{f}}_x$ mirrors the f and
leaves the subscript alone). Genuinely undefined macros, and a macro written
without braces, keep their red error.Everything is verified against Obsidian 1.13.7 (MathJax 3.2.2); the evidence is
collected in docs/obsidian-math-internals.md.
Mirror in Live Preview · Debug logging.
\mirrorh, \mirrorv, \mirrorhv (and \mirrorvh) are recognised, case
sensitively.$\mirrorh{x$ cannot be parsed, so the formula keeps
MathJax's red error rendering (with a console message when debug logging is on).mjx-mirror-h, mjx-mirror-v and
mjx-mirror-hv; a \class{mjx-mirror-...} written by hand is treated as a mirror
request as well.npm run dev (watch) · npm run build (type check + production bundle) ·
npm test (62 unit and integration tests, including a real CodeMirror 6 editor in
jsdom) · npm run deploy (copy the built plugin into a vault).
main.js and styles.css are build artifacts and are not committed; they are
attached to each release.
.github/workflows/release.yml builds and tests the plugin on every tag, then
opens a draft release with the three files Obsidian downloads. Push a tag that
matches manifest.json:
git tag -a 1.0.0 -m "1.0.0"
git push origin 1.0.0
Review the draft release, add the notes from CHANGELOG.md and
publish it. See docs/submission.md for the community
directory checklist.
Math Mirror is released under the MIT Copyright (c) 2026, Gatongone.