Canvas to HTML

approved

by Shao-En Ju

Export a Canvas to a single self-contained HTML file you can share. - This plugin has not been manually reviewed by Obsidian staff.

129 downloadsUpdated 1mo agoMIT

Canvas to HTML

CI Release License: MIT

Export an Obsidian Canvas to one self-contained HTML file you can email, drop in a folder, or open on any machine. The exported file zooms and pans the way the canvas does inside Obsidian.

No server. No build step for the reader. No network requests at all — every image is inlined, every font reference is stripped, and nothing phones home when the file is opened.

Install

From a release

  1. Download main.js, manifest.json, and styles.css from the latest release.
  2. Put all three in <your vault>/.obsidian/plugins/canvas-to-html/.
  3. Reload Obsidian, then enable Canvas to HTML in Settings → Community plugins.

If your vault syncs through iCloud, copy the files in. Do not symlink them — iCloud does not sync symlinks reliably.

With BRAT

Add sam080626-arch/obsidian-canvas-to-html as a beta plugin in BRAT.

Usage

Open a canvas and run Export canvas to HTML from the command palette, or right-click a .canvas file in the file explorer. The .html lands next to the canvas unless you set an output folder in settings.

In the exported file

InputAction
Two-finger scroll / wheelPan
Ctrl/⌘ + wheel, trackpad pinchZoom at the pointer
Drag empty spacePan
+ / -Zoom in / out
0, double-click empty spaceFit to screen
Click an edgeFrame both of its endpoints

Cards taller than their frame scroll internally. Corner buttons zoom, fit, and toggle light/dark; the theme choice persists.

What gets exported

Canvas nodeBecomes
Text cardRendered Markdown
Embedded .md noteThe note's rendered content, one level deep
ImageAn <img> with an inlined data URI, downscaled past a size limit
PDFA labelled placeholder card — the bytes are never inlined
Web linkA clickable link card, not a live iframe
GroupA tinted rect with its label, behind the cards
EdgeAn SVG Bézier with arrowheads, in canvas coordinates

Callouts, tables, task lists, code blocks with syntax colouring, math, and images embedded inside notes all survive. The stylesheet mirrors Obsidian's own default theme values — the type scale, spacing, and the canvas colour palette — so an export reads like the canvas it came from.

Settings

SettingDefault
Output folderNext to the source canvas
Maximum image dimension2000 px
Image re-encode quality0.85
Size warning threshold25 MB
Default theme in the exportFollow the reader's system
Open the file after exportingOff

Known limitations

  • Mermaid diagrams export as a source code block until you trust the vault in Obsidian, because Obsidian itself will not render them before that.
  • Math renders, but MathJax's web fonts are deliberately not embedded (they would add megabytes), so glyph metrics differ slightly from Obsidian. If a formula fails to render at all, its TeX source is exported instead of a blank.
  • Embeds are followed one level only. An ![[embed]] inside an embedded note is not expanded.
  • Community themes are not reproduced. The export matches Obsidian's default theme.
  • Wikilinks to notes that were not exported render as dotted, unclickable text with the target in the tooltip.

Development

npm install
npm run dev     # watch build
npm test        # vitest
npm run lint    # the same rules Obsidian's plugin validator applies
npm run build   # lint + typecheck + production bundle

Two bundles are produced: the plugin (main.js) and the viewer runtime, which is inlined into the plugin as a string at build time and written into every export.

Architecture

Logic lives in pure modules; the Obsidian-coupled modules are thin and take their dependencies through injected interfaces, so the whole pipeline is testable without the app.

ModuleResponsibilityObsidian API
canvas-model.tsParse .canvas JSON into a Scene, compute world boundsno
edges.tsBézier routing and arrowhead geometryno
assets.tsImage sizing, encoding, data URIs, cachingno
math.tsTeX source extraction, MathJax CSS sanitationno
clean-rendered.tsStrip app-only chrome, scrub links, carry math across sanitizationno
serialize.tsAssemble the exported documentno
viewer/transform.tsZoom/pan/fit mathsno
viewer/viewer.tsThe runtime shipped inside each exportno
resolve.tsCanvas nodes → renderable HTMLinjected
render-markdown.tsMarkdownRenderer + sanitization + mathyes
main.tsCommands, menus, settings, orchestrationyes

Testing

159 tests across unit, golden-file, and jsdom suites:

npm test

The jsdom suites drive the exported viewer with real wheel, pointer, and keyboard events and assert the resulting transform, because that layer cannot be covered by unit tests alone. MANUAL-VERIFICATION.md lists what still needs a human in real Obsidian — renderer fidelity, performance, and cross-browser checks.

Design notes and the implementation plan live in docs/superpowers/.

Releasing

npm version patch    # bumps package.json, manifest.json, versions.json together
git push --follow-tags

Pushing the tag runs the release workflow, which verifies the tag matches manifest.json, builds, and attaches main.js and manifest.json to a GitHub release — the layout Obsidian expects.

License

MIT © 朱劭恩

For plugin developers

Search results and similarity scores are powered by semantic analysis of your plugin's README. If your plugin isn't appearing for searches you'd expect, try updating your README to clearly describe your plugin's purpose, features, and use cases.