Clean, deterministic, browser-free renderer for .excalidraw files (PNG/SVG/PDF/JPEG).
Project description
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.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file excalidraw_render-0.3.0.tar.gz.
File metadata
- Download URL: excalidraw_render-0.3.0.tar.gz
- Upload date:
- Size: 56.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
907057b671e5ccac6970e333a5d00debd75859ec4a963f828ffc046c0957ee6a
|
|
| MD5 |
2d586bf325348906e679063e105b0692
|
|
| BLAKE2b-256 |
502fd0184f2fd0eab1f4c3789b5982fb923a95e702022162f1ae481011a67e2e
|
File details
Details for the file excalidraw_render-0.3.0-py3-none-any.whl.
File metadata
- Download URL: excalidraw_render-0.3.0-py3-none-any.whl
- Upload date:
- Size: 25.1 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
725aa78771381c553016977e5f683594dd948d1b1eda210ab64f04d848448dd9
|
|
| MD5 |
ecb51badbc255708414d91cacbd5a593
|
|
| BLAKE2b-256 |
f85c2c39bebaf0ddcd4bddab17a62a962d64a948b75f6322cba59a8b493b7486
|