The render pipeline converts .excalidraw JSON files into high-quality PNG images using a Python script that orchestrates Playwright, headless Chromium, and the Excalidraw library.Location:references/render_excalidraw.py
The script validates the Excalidraw JSON structure before attempting to render:
references/render_excalidraw.py
def validate_excalidraw(data: dict) -> list[str]: """Validate Excalidraw JSON structure. Returns list of errors (empty = valid).""" errors: list[str] = [] if data.get("type") != "excalidraw": errors.append(f"Expected type 'excalidraw', got '{data.get('type')}'") if "elements" not in data: errors.append("Missing 'elements' array") elif not isinstance(data["elements"], list): errors.append("'elements' must be an array") elif len(data["elements"]) == 0: errors.append("'elements' array is empty — nothing to render") return errors
What it checks:
type field must be "excalidraw"
elements array must exist and be a valid array
At least one element must be present (no empty diagrams)
The script uses Playwright to control a headless Chromium browser:
references/render_excalidraw.py
with sync_playwright() as p: browser = p.chromium.launch(headless=True) page = browser.new_page( viewport={"width": vp_width, "height": vp_height}, device_scale_factor=scale, ) # Load the template page.goto(template_url) # Wait for the ES module to load (imports from esm.sh) page.wait_for_function("window.__moduleReady === true", timeout=30000) # Inject the diagram data and render json_str = json.dumps(data) result = page.evaluate(f"window.renderDiagram({json_str})") # Wait for render completion signal page.wait_for_function("window.__renderComplete === true", timeout=15000) # Screenshot the SVG element svg_el = page.query_selector("#root svg") svg_el.screenshot(path=str(output_path)) browser.close()
Render sequence:
Launch headless Chromium with specified viewport and scale
Load render_template.html from the same directory
Wait for Excalidraw library to load from esm.sh CDN
The template can’t load the Excalidraw library from esm.sh. Check your internet connection or firewall settings.
Rendered image is clipped or cut off
The bounding box calculation may not account for all elements. Try increasing the --width parameter or checking for elements with unusual coordinate values.
Text looks blurry
Increase the --scale parameter. Default is 2 (retina quality). Try --scale 3 for even sharper text.
Colors look different than in Excalidraw editor
The render uses Excalidraw’s exportToSvg function, which may render colors slightly differently than the interactive editor. This is expected behavior.