Repository navigation
Roadmap
This is the order I plan to work in. There are no dates. Every version goes through the community store's review again, so I would rather put out fewer, bigger releases than many small ones, and each comes out when it is done. The order can change if something turns out to matter more, and you can help decide that: see the end of the page.
0.2.0 made TeX faster; 0.2.1 takes on everything else a new diagram waited for, and stops the engine doing the same work twice. It went out first as six betas, through BRAT.
- No wait before the engine. In 0.2.0 a diagram that was not cached waited 300 ms on a computer and 500 ms on a phone before it went to the engine, so that typing in a diagram would not compile it at every keystroke. It waited also when you had just opened the note. 0.2.1 keeps that wait only for a note you are typing in, and starts the engine as soon as a diagram turns out not to be cached.
- TeX takes about a third less time. The engine is compiled so that TeX keeps the values it works on where the processor reaches them directly, rather than in its memory, and is optimised with a newer binaryen; TeX's calls into the plugin no longer make new arrays for every line and character.
- A faster engine start. The engine is handed its files when it starts, instead of carrying them inside its own code, and unpacks them with the system's own decompression where there is one, from iOS 16.4 on.
-
Saved preambles. A diagram whose text up to
\begin{document}is the same as an earlier diagram's starts where that one stood at that point, and TeX compiles only its body. The saved preambles are also kept in the device's own storage, so they outlast the engine's stop and a restart of Obsidian. - A second engine on a computer, while several new diagrams wait. A note of 37 new diagrams handed over at once took 46 to 47% less time with two engines than with one, on my desktop. Phones and tablets keep one.
- Labels in other scripts. Chinese, Japanese, Korean, Greek, Cyrillic, Arabic, Hebrew, Thai, Devanagari, IPA and emoji are drawn in your system's sans-serif over boxes TeX sets for them. RepentStar contributed this, in pull request #2.
Grey is 0.2.0, blue is 0.2.1 compiling the diagram from the start, and green is 0.2.1 drawing the same diagram a second time in a row, from the preamble it saved the first time. In Chromium, over the 37 test diagrams 0.2.0 was released with, TeX's time went from 2,827 ms to 1,850 ms from the start, 35% less, and to 752 ms from a saved preamble. I measured it on my Windows desktop in headless Chromium 153, which is what Obsidian's desktop app is built on, through Playwright rather than inside Obsidian, with 0.2.0's main.js as released beside 0.2.1's; each figure is the fastest of seven runs, each in a fresh browser. In WebKit 26.6, the browser engine of the iPhone and iPad, run on the same desktop, the same sums went from 4,210 ms to 2,772 ms, and to 1,192 ms from a saved preamble. The README has the table for all 37.
The same runs, medians in Chromium, and the wait, which is the plugin's setting rather than a measurement; 0.2.1 keeps it only for a note you are typing in. The first diagram after the engine starts takes a few milliseconds longer than in 0.2.0, because it saves its preamble for the diagrams after it. Added up, the first new diagram of a session spent about 500 ms on these three in 0.2.0 and about 100 ms in 0.2.1, before the plugin's SVG pipeline and drawing it in the note, which this harness does not include. After it, a small diagram with the same preamble takes 7 ms instead of 24, because it starts from the saved preamble, and 14 with saved preambles off; the harness timed the same diagram drawn a second time.
On my iPhone 16 Pro, on iOS 27.0.1 with Obsidian 1.14.5, 0.2.0's engine started in 134 ms, and small diagrams took 15 to 40 ms of TeX after the 500 ms wait; circuitikz took 268 to 276 ms of TeX, pgfplots 244 to 275 and pgfplotstable 233, read off the diagnostics view on 14 October 2026. I will add 0.2.1's figures from the same phone here once I have read them off it the same way.
In a diagram that loads packages, much of TeX's time goes into loading them before the picture starts, and a note often has several diagrams with the same preamble. Before 0.2.0 shipped I measured how much, which is what made saved preambles worth building.
I ran each of these diagrams twice on the first build of the 0.2.0 engine, the one with only asyncify taken out: as written, and with the same preamble but a one-line picture. The blue part is the second run less the same one-line picture with no packages at all (16 ms), so it is the preamble alone; the grey part is everything else. For the two pgfplots test diagrams the preamble was about 55% of TeX's time, for circuitikz 64%, for siunitx 78%. That is roughly what a saved preamble now spares the diagrams after the first: in the chart above, siunitx drawn a second time took 10 ms of TeX where it took 89 from the start.
The numbers, on both engines
| Diagram | 0.1.5 total (ms) | preamble (ms) | share | first 0.2.0 build total (ms) | preamble (ms) | share |
|---|---|---|---|---|---|---|
| feynhand | 771 | 202 | 26% | 400 | 110 | 27% |
| circuitikz | 655 | 418 | 64% | 353 | 225 | 64% |
| pgfplots-axis | 616 | 336 | 55% | 338 | 182 | 54% |
| pgfplots-fillbetween | 605 | 351 | 58% | 340 | 186 | 55% |
| forest | 557 | 275 | 49% | 322 | 156 | 49% |
| siunitx | 249 | 198 | 79% | 144 | 113 | 78% |
| tikz-cd | 204 | 84 | 41% | 115 | 44 | 38% |
| chemfig | 124 | 51 | 41% | 71 | 29 | 42% |
| mathtools | 90 | 59 | 65% | 53 | 33 | 63% |
| patterns | 80 | 49 | 61% | 46 | 26 | 56% |
| arrows-meta | 80 | 40 | 51% | 46 | 22 | 48% |
| xparse | 37 | 8 | 20% | 23 | 3 | 15% |
| mathfrak | 34 | 3 | 8% | 21 | 2 | 10% |
| mathscr | 35 | 3 | 8% | 21 | 1 | 6% |
| expl3 | 33 | 3 | 10% | 21 | 2 | 8% |
The one-line picture with no packages took 25.6 ms on 0.1.5 and 15.9 ms on the first 0.2.0 build. Best of 3 runs. Shares are computed from the unrounded times.
A saved preamble is the part of TeX's memory that loading the preamble changed, with the files TeX had open. It goes in only because it changes nothing a diagram renders to: every release checks every test diagram, and 33 cases written to break it, against the same diagram drawn from the start, byte for byte, with the preamble kept in memory and read back from storage. A diagram that reads its own file in its preamble never saves one. An engine keeps up to 32 MB of saved preambles on a computer and 12 MB on a phone, or on a computer that reports less than 8 GB of memory, and the device's storage keeps up to 64 MB for each vault on a computer and 16 MB on a phone or on such a computer, never in the vault itself. Settings → Saved preambles turns them off.
0.2.0 is about the time a new diagram takes. Cached diagrams cost nothing, so this is the wait you see whenever a diagram is new, and on a phone it is the wait that matters. On 0.1.5, nearly all of the engine's work on a diagram that loads packages was TeX itself, running in WebAssembly: about 97% in a CPU profile of four test diagrams on my desktop. The first diagram that was not cached also waited about half a second, once, for the engine to start.
0.2.0 rebuilt the engine:
- Without asyncify. Asyncify is a transform that lets WebAssembly pause while JavaScript fetches something. The engine used it to load TeX files one at a time; by 0.1.5 every file was already in memory and only TeX's jump out on a fatal error still used it, but the 11,333 checks it added ran all the time. Taking them out is most of the gain, and it also made
tex.wasmabout a third smaller (526 KB to 356 KB). - Pinned to WebAssembly 1.0, the original feature set, so it runs in the same WebViews as before, iOS 14.5's among them. I tried the newer features as well: for this engine they produced the same code and no measurable difference.
- With a larger hash table inside TeX, so that finding a macro name takes shorter searches. That saves a few percent.
- With a lighter memory reset. TeX's starting memory image is 156 MiB, mostly zeros. 0.2.0 ships, unpacks and copies only the parts that hold anything, about 22 MiB, so setting up TeX's memory before each diagram takes about 5 ms, where it took about 29. For a small diagram, those 29 ms were close to what TeX itself took.
- With a cheaper start, for the same reason: on my desktop the engine starts about three times as fast.
A rebuilt engine also fixed three things that could not be fixed without one. ~ no longer raises errors and prints a stray ˜, because the engine has \ifincsname; with it, LaTeX also loads its current UTF-8 support, so accented letters work in node, coordinate and style names. LaTeX's check for whether a file exists no longer answers yes for files that are not there (\filesize), so a diagram that loads a package the engine does not have is drawn without it, with LaTeX's File `x.sty' not found on it. And a fatal TeX error ends the run straight away with TeX's own message, instead of waiting for the time limit.
The diagnostics view now shows where each diagram's time goes: waiting, engine start, memory reset, TeX, DVI to SVG and the SVG pipeline. That is how I will measure the speed on a phone rather than guess it from my desktop.
I ran 0.2.0 and 0.1.5 side by side in Node 22 on my Windows desktop, not inside Obsidian, over the 26 test diagrams 0.1.5 was released with, best of 5 runs each. TeX's time went from 4,612 ms to 2,539 ms, 45% less, and each diagram took between 37% and 48% less. A second run of the whole benchmark gave 45% again. The 11 test diagrams added since are left out, because 0.1.5 cannot finish some of them. 24 of the 26 came out byte for byte the same as on 0.1.5; the other two, mathfrak and mathscr, cannot be drawn as SVG by either engine (see Status). Desktop Obsidian runs V8 as well, so I expect about the same there. Before the release this page showed the first build of the engine, with only asyncify taken out and plain WebAssembly, at 42% less; these are the figures for 0.2.0 as released.
| On the same desktop | 0.1.5 | 0.2.0 |
|---|---|---|
| Engine start | 528 ms | 161 ms |
| A small diagram, compiled in the engine worker once it is running | 61 ms | 27 ms |
| Setting up TeX's memory before each diagram, timed on its own | about 29 ms | about 5 ms |
| Memory buffers held once started | 157.5 MiB | 23.5 MiB |
| Peak memory of the whole test process over five diagrams | 703 MiB | 168 MiB |
The memory setup was timed on its own, in three processes per version. The other rows are medians of seven fresh processes, each starting the plugin's engine worker and compiling five diagrams. The small diagram's time is the worker's own (memory reset, TeX, DVI to SVG); waiting in the queue and the SVG pipeline come on top.
These figures do not carry over to an iPhone, where Obsidian runs JavaScriptCore, not V8. On my iPhone 16 Pro, on iOS 27.0.1, read off the diagnostics view on 14 October 2026, 0.2.0's engine started in 134 ms and circuitikz took 268 to 276 ms of TeX; 0.1.5 was not timed there.
The numbers in the chart
| Diagram | 0.1.5 (ms) | 0.2.0 (ms) | Change |
|---|---|---|---|
| feynhand | 768 | 399 | −48% |
| circuitikz | 652 | 349 | −46% |
| pgfplots-axis | 622 | 335 | −46% |
| pgfplots-fillbetween | 613 | 332 | −46% |
| forest | 566 | 312 | −45% |
| siunitx | 251 | 143 | −43% |
| tikz-cd | 208 | 118 | −44% |
| chemfig | 128 | 71 | −45% |
| mathtools | 89 | 53 | −40% |
| arrows-meta | 81 | 46 | −43% |
| patterns | 79 | 47 | −41% |
| ts1-currency | 48 | 30 | −39% |
| ts1-symbols | 44 | 26 | −41% |
| dieresis | 43 | 24 | −43% |
| ts1-small-caps | 42 | 25 | −39% |
| shading | 41 | 24 | −41% |
| xparse | 38 | 23 | −38% |
| l-stroke | 37 | 22 | −40% |
| rule-frac | 36 | 22 | −39% |
| mathfrak | 35 | 21 | −40% |
| mathscr | 35 | 21 | −39% |
| expl3 | 34 | 21 | −38% |
| basic | 33 | 20 | −41% |
| white-fill | 32 | 19 | −40% |
| omega-otimes | 30 | 19 | −38% |
| broken | 26 | 16 | −37% |
| All 26 | 4,612 | 2,539 | −45% |
TeX's time only. The changes were computed from the unrounded times, so they can differ by a point from what the rounded milliseconds give.
After updating to 0.2.0, each diagram compiles once more the first time it is shown, as after every engine change. Diagrams that rendered before come out the same, byte for byte, apart from the fixes above.
The packages inside the engine are TeX Live 2023's. TeX Live 2026 brings pgf 3.1.12, pgfplots 1.18.3, circuitikz 1.8.7, chemfig 1.82 and siunitx 3.6.4. In a diagram that means new circuitikz components, chemfig's \hreac, and three years of fixes.
main.js should also shrink, from about 12.2 MB to about 8.3 MB, because the newer LaTeX's memory image compresses to half the size. That is an estimate from a test build, not a release. TeX itself will not get faster. In my tests, on the engine before 0.2.0, the total was a few percent slower, and small diagrams were 10 to 20 ms slower each. The larger hash table from 0.2.0 wins back most of the total, but not the cost on small diagrams.
It had to wait for 0.2.0. pgf 3.1.12 checks whether files exist through LaTeX's \IfFileExists, which needs the \filesize fix that 0.2.0 made; without it, arrows.meta silently fails to load. In the test build, with that fix simulated, 20 of the 21 test diagrams that existed then came out identical, and one, a circuitikz resistor, moved slightly. I will look at every difference before it ships, and the TeX Live snapshot will be pinned to a date so that the build stays reproducible. The newer LaTeX also has to keep the point where 0.2.1 saves a preamble, and every test diagram drawn from a saved preamble has to come out byte for byte as one drawn from the start, as it does now.
| Feature | State | What it would do |
|---|---|---|
![[file.tex]] embeds |
planned | Keep a diagram in its own .tex file and embed it in any note, rendered in place, in Reading view and Live Preview. Asked for in issue #1, where one question is still open: whether the files are whole LaTeX documents or bare tikzpictures. |
.sty and data files from the vault |
idea |
\usepackage{mystyle} would find mystyle.sty in the vault, and pgfplots could plot a .csv file from it. Support for your own packages is the oldest open request on the original plugin, and the simplest way to use a package that is not bundled. |
| Copy as PNG | idea | A command next to Copy as SVG, for the places where an SVG cannot be pasted. |
| Syntax highlighting | idea | TeX highlighting for tikz blocks in Source mode, and in Live Preview while the cursor is inside the block. Today the code shows without any. |
Also up for votes, though not on this list: more bundled packages, \mathfrak and \mathscr, and rendering every diagram in the vault at once. Labels in Chinese, Greek, Cyrillic and other scripts, which were on this list, came in 0.2.1, from RepentStar's pull request #2.
If something here matters to you, or something you need is missing, say so in Discussions → Ideas. If the idea is already there, give it a thumbs-up: that is what I look at when I pick the next thing.
Something wrong or missing on these pages? Say so in Discussions.