UniNotepad Markdown Preview
Markdown preview with an interactive Mermaid layer — pan, zoom, and a
switchable transparent/solid diagram backdrop — ported from the
UniNotepad editor.
📄 Website: English ·
한국어 — what the desktop editor is, and
where to download it (Windows · macOS · Linux).
VS Code already ships a Markdown preview, so this extension is not trying to
replace it. What it adds is the diagram-handling that UniNotepad built up: a zoom
ladder that scales the document text and the diagrams together, click-and-drag
panning inside an overflowing chart, a per-diagram backdrop you can dial in with
RGBA sliders (useful when a light diagram is unreadable under a dark theme, or
when you want to paste the diagram somewhere with a specific background), and a
full-bleed layout for a standalone .mmd file that is one diagram.
Usage
| Action |
How |
| Open the preview |
Cmd/Ctrl+K Shift+M or the diagram icon in the editor title bar |
| Preview several files as tabs |
Right-click a file in the Explorer or its editor tab → Open Preview (UniNote) — each file gets its own locked tab; choosing a file that already has one brings that tab forward |
| Zoom text + diagrams |
Cmd/Ctrl+= / Cmd/Ctrl+- / Cmd/Ctrl+0 (preview focused) |
| Pan a zoomed diagram |
Click and drag inside it |
| Diagram backdrop |
Hover a diagram → Transparent / Backdrop in its toolbar |
| Export |
UniNotepad: Export Preview as HTML |
Works on .md and on standalone .mmd / .mermaid files.
Local images — , PNG, JPG, GIF, WebP and the like — are
resolved against the Markdown file's own folder and shown inline, SVG included
(rendered as an image, so any script inside it never runs). An exported HTML file
carries them along, so it stands on its own.
The preview follows the active editor, like the built-in one: switch to
another Markdown file and the preview switches with you, scrolled back to the top.
Editors it cannot render — a .ts file, an output channel, or the preview itself
taking focus — leave the last render in place rather than blanking the pane.
To keep several previews open side by side, lock one: the lock button in a
focused preview's title bar pins it to its document, and the next preview you
open is a new panel that follows the editor as usual. Lock that one too for a third, and so on. A locked preview
still updates as its document is edited, keeps its last render if the document is
closed, and comes back locked after a window reload. Unlocking makes it the
following preview again — any other following preview closes, since only one can
follow the editor.
This sits alongside VS Code's built-in Markdown preview rather than replacing it,
so a .md file's title bar carries both buttons. The built-in one keeps the
open-preview icon; this extension's is the app's own <> diamond — the only
coloured glyph in that toolbar — and its tooltip reads Open Mermaid Preview to
the Side.
Settings
| Setting |
Default |
Meaning |
uninotepadPreview.mermaidBackgroundEnabled |
false |
Paint a solid backdrop behind diagrams |
uninotepadPreview.mermaidBackground |
255,255,255,1 |
Backdrop as r,g,b,a — normally edited by the in-diagram popover |
uninotepadPreview.scrollEditorWithPreview |
true |
Sync preview scroll to the editor (one-way) |
uninotepadPreview.contentWidth |
680 |
Text column width cap in px at 100% zoom; 0 fills the panel. Mermaid diagrams ignore it and always use the full width |
Known gaps
These are real limitations of this version, not oversights:
- Fenced code blocks are not syntax-highlighted. UniNotepad highlights them by
reusing CodeMirror's own grammars, which means one dynamic import per language —
and a webview can only load resources through
asWebviewUri, so a split bundle's
chunk fetches are blocked by the Content-Security-Policy. Getting this back means
swapping in a highlighter that fits a single bundle.
- No printing. VS Code webviews cannot call
window.print() — the sandbox has
no allow-modals. Export to HTML and print from a browser; the export command
offers to open the file for you.
#anchor links mostly miss. marked does not generate heading slugs by
default, so there is usually no matching id to scroll to.
- Scroll sync is one-way (editor → preview), matching UniNotepad. Scrolling the
preview does not move the editor.
Development
npm install
npm run typecheck # both bundles: extension host and webview
npm run test # build, then 50 assertions across both runtimes
npm run build # dist/extension.js + dist/webview.js
npm run watch
Open vscode-ext/ as the workspace folder (not the repository root) and press
F5; the launch configuration builds, starts an Extension Development Host, and
opens sample/demo.md, which is a checklist for the things the tests cannot reach.
test/ runs both halves outside VS Code: extension-host.test.cjs drives
dist/extension.js against a stub vscode module, and webview.test.cjs runs
dist/webview.js in jsdom with a stubbed acquireVsCodeApi. The one thing neither
covers is Mermaid's SVG output — mermaid measures text with getBBox, which jsdom
does not implement, so a diagram deliberately lands in the error path there. Verify
diagrams by eye via F5.
npm run package builds a .vsix. The publisher in package.json is ilphs,
which must stay in sync with the Marketplace publisher the .vsix is uploaded
under — a mismatch is rejected at upload time.
Layout
src/ extension host — commands, panel lifecycle, document sync
webview/ the preview itself — render core + Mermaid interaction layer
shared/ the message contract both sides import
media/ preview.css, icon.png (gallery icon), toolbar-icon-{light,dark}.svg
media/icon.png is a copy of the app's own icon (src-tauri/icons/128x128@2x.png,
256×256) so the extension is recognisable as part of UniNotepad. It is a copy for
the same reason site/assets/app-icon.png is: each deliverable packages
independently. Re-copy it if the app icon changes.
The two toolbar-icon-*.svg files are that same icon redrawn for a 16×16
title-bar slot: the black rounded square is dropped (at 16px it swallowed the
whole glyph — invisible against a dark toolbar, a heavy black block against a
light one) and only the <> diamond survives, keeping the app's cyan #51D7FF
→ violet #AE59EF gradient and its mirrored direction on the two strokes. The
light variant is the same two hues at lower lightness, because the cyan end
washes out on white. Re-derive them if the app icon's palette changes.
webview/mermaid-view.ts and webview/preview.ts are ports of the same files in
UniNotepad's src/. They are copies, not a shared module: the app keys its
state off a tab store and localStorage, the extension off a panel and
workspace.getConfiguration. Fixes to the Mermaid layout and zoom rules generally
apply to both and should be made in both.
License
MIT