excalidraw-render
Clean, deterministic, browser-free renderer for .excalidraw files. Pure Python + cairosvg. No Node, no headless browser, no node-canvas.
pip install excalidraw-render
excalidraw-render diagram.excalidraw # → diagram.png
excalidraw-render diagram.excalidraw -f svg # → diagram.svg
excalidraw-render diagram.excalidraw -f pdf # → diagram.pdf (vector)
excalidraw-render diagram.excalidraw --width 1200 # PNG at 1200px wide
excalidraw-render ./docs/ # batch: every .excalidraw → .png
excalidraw-render ./docs/ --watch # re-render on every save
Why this exists
The Excalidraw ecosystem's existing exporters either need Node + node-canvas (excalidraw_export) or a headless browser running React (@excalidraw/excalidraw). Both are heavy, fragile in CI, and slow to start.
excalidraw-render is Python + cairosvg. Single-digit-megabyte install, instant startup, no native canvas libs, no Chromium. Useful for:
- Static-site generators (Hugo, MkDocs, Sphinx) baking
.excalidrawto PNG at build time - CI/screenshot pipelines where pulling Chromium is overkill
- Doc + slide generators that want predictable, deterministic vector output
- Terminal viewers (Kitty, iTerm2, Sixel) — on the roadmap
Trade-off: no hand-drawn style
Excalidraw's signature squiggly look comes from roughjs, a JavaScript library with no native Python port. excalidraw-render produces clean vector output instead. This is a deliberate trade-off — clean output is what most doc / slide / report pipelines actually want, and skipping roughjs removes the heaviest dependency.
A pure-Python roughjs port (pyroughjs) is on the roadmap. Until then, if you need the hand-drawn look, use Excalidraw's official export.
Comparison
excalidraw-render |
excalidraw_export |
@excalidraw/excalidraw |
|
|---|---|---|---|
| Language | Python | Node | React + Node |
| Hand-drawn (roughjs) | No (planned) | Yes | Yes |
| PNG output | Yes | via rsvg-convert |
Yes |
| SVG output | Yes | Yes | Yes |
| PDF output | Yes | via rsvg-convert |
No |
| Headless browser needed | No | No | Yes |
| Native canvas / image libs | No | Yes (node-canvas) |
No |
| Install size | ~10 MB | ~150 MB | Depends |
| Batch / watch mode | Yes | No | No |
| Terminal protocols | Planned (iTerm / Kitty / Sixel) | No | No |
Install
pip install excalidraw-render
On Linux you may need libcairo2:
sudo apt-get install libcairo2 # Debian / Ubuntu
sudo dnf install cairo # Fedora
sudo pacman -S cairo # Arch
On macOS, Cairo is typically already present via Homebrew. If not:
brew install cairo
Usage
CLI
# Single file → PNG next to source
excalidraw-render diagram.excalidraw
# Specify output + format
excalidraw-render diagram.excalidraw -o /tmp/out.svg -f svg
# Higher resolution PNG
excalidraw-render diagram.excalidraw --width 1600
# Or scale instead of fixed width
excalidraw-render diagram.excalidraw --scale 2.0
# Transparent background
excalidraw-render diagram.excalidraw --no-background
# Vector PDF / compressed JPEG
excalidraw-render diagram.excalidraw -f pdf
excalidraw-render diagram.excalidraw -f jpg --quality 85
# Batch mode: every .excalidraw in a directory
excalidraw-render ./docs/diagrams/ -o ./public/diagrams/
# Watch mode: re-render on every save (single file or directory)
excalidraw-render ./docs/diagrams/ --watch
Python API
from excalidraw_render.render import load_scene, render_svg, render_png, render_pdf, render_jpg
scene = load_scene("diagram.excalidraw")
# SVG as a string
svg = render_svg(scene)
# PNG to a file
render_png(scene, "diagram.png", width=1200)
# Vector PDF / JPEG
render_pdf(scene, "diagram.pdf")
render_jpg(scene, "diagram.jpg", quality=85)
# PNG to a binary stream
import io
buf = io.BytesIO()
render_png(scene, buf, scale=2.0)
What's supported
Formats: PNG, SVG, vector PDF, JPEG.
Elements: rectangle, ellipse, diamond, arrow, line, text, freedraw, image, frame.
Arrowheads: arrow, triangle, triangle_outline, bar, dot, diamond, diamond_outline, crowfoot_one, crowfoot_many, crowfoot_one_or_many.
Styling: stroke color/width, fill color, fill patterns (hachure, cross-hatch, zigzag, dots, dashed — clean SVG-pattern approximations of the roughjs originals), stroke style (solid/dashed/dotted), opacity, per-element rotation.
Text: multi-line, text-align (left/center/right), vertical-align (top/middle/bottom), Excalidraw font families mapped to web-safe fonts. Container-bound text (labels inside rectangles, ellipses, diamonds) is positioned with Excalidraw's own padding-aware layout algorithm and rotates with its container.
Freedraw: smooth path via Catmull-Rom → cubic Bezier conversion.
Image: embedded raster data from the scene's files dict.
Frame: dashed boundary box with optional label.
Coverage matrix: docs/elements.md.
What's not supported yet
See ROADMAP.md for the full release ladder to 1.0. Highlights:
- Roughness / hand-drawn look (needs roughjs port — planned for 0.7.0)
- Markdown preprocessor subcommand (0.5.0)
- Terminal output (iTerm / Kitty / Sixel) (0.6.0)
Contributing
This is pre-alpha and breaking changes between minor versions are likely until v1.0. Issues, ideas, and PRs welcome — please file at https://github.com/shivama205/excalidraw-render/issues.
Local dev:
git clone https://github.com/shivama205/excalidraw-render
cd excalidraw-render
python -m venv .venv && .venv/bin/pip install -e ".[dev]"
.venv/bin/pytest
.venv/bin/ruff check src tests
.venv/bin/mypy src
License
MIT — see LICENSE.
Metadata
Release files for excalidraw-render 0.3.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| excalidraw_render-0.3.0.tar.gz | 56.5 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| excalidraw_render-0.3.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 81.6 kB
Release files / excalidraw_render-0.3.0.tar.gz
| Download URL | excalidraw_render-0.3.0.tar.gz |
|---|---|
| Size | 56.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
907057b671e5ccac6970e333a5d00debd75859ec4a963f828ffc046c0957ee6a
|
|
BLAKE2b-256 checksum How to use checksums |
502fd0184f2fd0eab1f4c3789b5982fb923a95e702022162f1ae481011a67e2e
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.14.3
|
Release files / excalidraw_render-0.3.0-py3-none-any.whl
| Download URL | excalidraw_render-0.3.0-py3-none-any.whl |
|---|---|
| Size | 25.1 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
725aa78771381c553016977e5f683594dd948d1b1eda210ab64f04d848448dd9
|
|
BLAKE2b-256 checksum How to use checksums |
f85c2c39bebaf0ddcd4bddab17a62a962d64a948b75f6322cba59a8b493b7486
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.14.3
|