From 572a05962c36ebb07a72d7bf89f3c8bd274b98b9 Mon Sep 17 00:00:00 2001 From: Julien Calixte Date: Fri, 15 May 2026 16:25:55 +0200 Subject: [PATCH] fix(markdown): load TikZ font stylesheet to keep text aligned The obsidian-tikzjax bundle emits SVG referencing Computer Modern font families like cmbx7 but ships the @font-face declarations in a separate styles.css. Without it the browser substitutes a default font whose glyph widths don't match TeX's, leaving visible gaps between each kerned text run. Lazy-load the stylesheet alongside the engine on first TikZ render so cache hits and misses both see correct fonts. --- src/hooks/useMarkdown.hook.ts | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/hooks/useMarkdown.hook.ts b/src/hooks/useMarkdown.hook.ts index 88a9f85..beb2088 100644 --- a/src/hooks/useMarkdown.hook.ts +++ b/src/hooks/useMarkdown.hook.ts @@ -28,6 +28,8 @@ import { markdownItTablerIcons } from "@/utils/markdown/markdown-it-tabler-icons const TIKZ_BUNDLE_URL = "https://cdn.jsdelivr.net/gh/artisticat1/obsidian-tikzjax@0.5.2/tikzjax.js" +const TIKZ_STYLES_URL = + "https://cdn.jsdelivr.net/gh/artisticat1/obsidian-tikzjax@0.5.2/styles.css" const TIKZ_RENDER_TIMEOUT_MS = 30000 const markdownItMermaidExtractor = (md: MarkdownIt) => { @@ -188,6 +190,7 @@ export const runMermaid = (querySelector: string) => { } let tikzBundlePromise: Promise | null = null +let tikzStylesPromise: Promise | null = null let domPurifyPromise: Promise | null = null const ensureTikzBundle = (): Promise => { @@ -215,6 +218,31 @@ const ensureTikzBundle = (): Promise => { return tikzBundlePromise } +const ensureTikzStyles = (): Promise => { + if (tikzStylesPromise) return tikzStylesPromise + + tikzStylesPromise = new Promise((resolve, reject) => { + const existing = document.getElementById("tikzjax-styles") + if (existing) { + resolve() + return + } + const link = document.createElement("link") + link.id = "tikzjax-styles" + link.rel = "stylesheet" + link.href = TIKZ_STYLES_URL + link.crossOrigin = "anonymous" + link.addEventListener("load", () => resolve()) + link.addEventListener("error", () => { + tikzStylesPromise = null + reject(new Error("Failed to load TikZ font styles")) + }) + document.head.appendChild(link) + }) + + return tikzStylesPromise +} + const ensureDomPurify = (): Promise => { if (!domPurifyPromise) domPurifyPromise = import("dompurify") return domPurifyPromise @@ -297,6 +325,8 @@ export const runTikz = async (querySelector: string): Promise => { ) if (elements.length === 0) return + void ensureTikzStyles().catch(() => undefined) + await Promise.all( elements.map(async (el) => { if (el.dataset.tikzRendered) return