Skip to content

feat: Excalidraw drawings inside notes - #99

Merged
FabioHAraujo merged 3 commits into
mainfrom
feat/excalidraw-drawings
Oct 29, 2026
Merged

FabioHAraujo merged 3 commits into
mainfrom
feat/excalidraw-drawings

Conversation

@FabioHAraujo

Copy link
Copy Markdown
Contributor

Closes #98

What

Excalidraw drawings inside notes, similar to Obsidian's Excalidraw plugin.

  • Drawing in the editor toolbar adds a drawing at the cursor and opens a full-screen canvas (DrawingEditor.svelte). With the cursor inside an existing drawing it opens that one. A new drawing closed without strokes takes its text back out of the note.
  • The drawing is an excalidraw fenced code block in the Markdown. Sync, history, trash and collaboration work unchanged; no Rust or protocol change.
  • The preview renders it as an image and opens it on click. The editor pane shows the block folded.
  • Word and PDF exports embed drawings as images (renderExportDiagram dispatches on the block language).
  • Excalidraw (React) loads on demand, the first time a drawing is shown. The canvas uses the app language.

Sync and merge

drawing-blocks.ts serializes one element per line and writes the smallest text change, so concurrent edits to different elements merge in the CRDT as valid JSON. While a drawing is open, remote changes to its block are merged into the canvas with Excalidraw's reconcileElements, so they are not overwritten by the next local save. Deleted elements are kept for 24 hours so open editors on other devices learn about the deletion. A block damaged by a merge keeps every element line that still parses.

CSP

The CSP is unchanged:

  • Excalidraw always adds the esm.sh CDN as a font fallback. A Vite plugin serves the fonts from the app (/excalidraw/fonts/) and rewrites that fallback to the same local path, in the build and in dev pre-bundling. The build fails if the fallback code changes in a future Excalidraw version.
  • The preview and exports render through exportToCanvas. Excalidraw's SVG export subsets fonts with code that needs unsafe-eval.
  • Xiaolai (13 MB of CJK glyphs) is not shipped; its faces are kept out of document.fonts, so CJK text uses system fonts.

Limitations

  • Pasting images into a drawing is blocked, so base64 does not end up in notes.
  • Excalidraw library items are not persisted.
  • About 5 MB of JavaScript, fonts and locales is added to the bundle, loaded only when a drawing is shown.

Dependencies

@excalidraw/excalidraw 0.18.1 (MIT), react and react-dom 19.2.9, and their type packages.

Tests

  • tests/drawing-blocks.test.ts: block discovery (lists, quotes, CRLF, unclosed fences), minimal changes, insertion, serialization, tombstones, concurrent appends, damaged content.
  • tests/e2e/drawing.pw.ts: draw and save, toolbar insert and empty-close cleanup, remote strokes merged into an open drawing.
  • tests/e2e/csp.pw.ts now renders a drawing and opens the canvas with zero CSP violations.
  • Markdown placeholder and export tests.

Run locally: bun run check, bun run check:e2e, bun test (108 pass), bun run build, bun run test:e2e (37 pass), bun run version:check, Python script tests. No Rust changes.

Not yet tried in the packaged Tauri app; the e2e suite runs in Chromium, the WebView2 engine.

@FabioHAraujo FabioHAraujo added enhancement New feature or request priority: P2 Important: performance, architecture or release quality size: L Large: a week or more, likely several PRs area: frontend Svelte/TypeScript side (src) dependencies Pull requests that update a dependency file labels Oct 29, 2026
@FabioHAraujo
FabioHAraujo force-pushed the feat/excalidraw-drawings branch from f73aae4 to 7fe444c Compare October 29, 2026 16:04
Drawings live in the note as `excalidraw` code blocks, so sync, history
and collaboration need no protocol change. The toolbar adds one and opens
a full-screen canvas; the preview renders it and opens it on click; exports
embed it as an image. Strokes from another device merge into an open
drawing. Excalidraw and React load on demand, and its fonts are served by
the app so the CSP stays unchanged.

Closes #98
The canvas also keeps Excalidraw's own right-click menu; an e2e check covers it.
@excalidraw/excalidraw pins nanoid 3.3.3 and mermaid-to-excalidraw pins 4.0.2; both only import nanoid(), and docx bundles its own copy.
@FabioHAraujo
FabioHAraujo force-pushed the feat/excalidraw-drawings branch from a4dd92a to 1a1dcbf Compare October 29, 2026 20:19
@FabioHAraujo
FabioHAraujo merged commit b879ce3 into main Oct 29, 2026
8 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: frontend Svelte/TypeScript side (src) dependencies Pull requests that update a dependency file enhancement New feature or request priority: P2 Important: performance, architecture or release quality size: L Large: a week or more, likely several PRs

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Excalidraw drawings inside notes

1 participant