Replace the charCount * fontSize * 0.55 text sizing heuristic with canvas-based measurement (graceful fallback when native deps unavailable). Add validate.mjs for automated spatial checks (text overflow, arrow-text collisions, element overlap). Update element format reference with sizing rules, label guidelines, and arrow routing conventions. Add verification step to SKILL.md workflow. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
6.2 KiB
name, description
| name | description |
|---|---|
| excalidraw-png-export | This skill should be used when creating diagrams, architecture visuals, or flowcharts and exporting them as PNG files. It uses the Excalidraw MCP to render hand-drawn style diagrams locally and Playwright to export them to PNG without sending data to any remote server. Triggers on requests like 'create a diagram', 'make an architecture diagram', 'draw a flowchart and export as PNG', or any request that needs a visual diagram delivered as an image file. |
Excalidraw PNG Export
Create hand-drawn style diagrams with the Excalidraw MCP and export them locally to PNG files. All rendering happens on the local machine. Diagram data never leaves the user's computer.
Prerequisites
First-Time Setup
Run the setup script once per machine to install Playwright and Chromium headless:
bash <skill-path>/scripts/setup.sh
This creates a .export-runtime directory inside scripts/ with the Node.js dependencies. The setup is idempotent and skips installation if already present.
Required MCP
The Excalidraw MCP server must be configured. Verify availability by checking for mcp__excalidraw__create_view and mcp__excalidraw__read_checkpoint tools.
Workflow
Step 1: Design the Diagram Elements
Translate the user's request into Excalidraw element JSON. Load excalidraw-element-format.md for the full element specification, color palette, and sizing guidelines.
Key design decisions:
- Choose appropriate colors from the palette to distinguish different components
- Use
labelon shapes instead of separate text elements - Use
roundness: { type: 3 }for rounded corners on rectangles - Include
cameraUpdateas the first element to frame the view (MCP rendering only) - Use arrow bindings (
startBinding/endBinding) to connect shapes
Step 2: Render with Excalidraw MCP
Call mcp__excalidraw__create_view with the element JSON array. This renders an interactive preview in the Claude Code UI.
mcp__excalidraw__create_view({ elements: "<JSON array string>" })
The response includes a checkpointId for retrieving the rendered state.
Step 3: Extract the Checkpoint Data
Call mcp__excalidraw__read_checkpoint with the checkpoint ID to get the full element JSON back.
mcp__excalidraw__read_checkpoint({ id: "<checkpointId>" })
Step 4: Convert Checkpoint to .excalidraw File
Use the convert.mjs script to transform raw MCP checkpoint JSON into a valid .excalidraw file. This handles all the tedious parts automatically:
- Filters out pseudo-elements (
cameraUpdate,delete,restoreCheckpoint) - Adds required Excalidraw defaults (
seed,version,fontFamily, etc.) - Expands
labelproperties on shapes/arrows into proper bound text elements
# Save checkpoint JSON to a file first, then convert:
node <skill-path>/scripts/convert.mjs <input.json> <output.excalidraw>
The input JSON should be the raw checkpoint data from mcp__excalidraw__read_checkpoint (the {"elements": [...]} object).
For batch exports: Write each checkpoint to a separate raw JSON file, then convert each one:
node <skill-path>/scripts/convert.mjs raw1.json diagram1.excalidraw
node <skill-path>/scripts/convert.mjs raw2.json diagram2.excalidraw
Manual alternative: If you need to write the .excalidraw file by hand (e.g., without the convert script), each element needs these defaults:
angle: 0, roughness: 1, opacity: 100, groupIds: [], seed: <unique int>,
version: 1, versionNonce: <unique int>, isDeleted: false,
boundElements: null, link: null, locked: false
Text elements also need: fontFamily: 1, textAlign: "left", verticalAlign: "top", baseline: 14, containerId: null, originalText: "<same as text>"
Bound text (labels on shapes/arrows) needs: containerId: "<parent-id>", textAlign: "center", verticalAlign: "middle", and the parent needs boundElements: [{"id": "<text-id>", "type": "text"}].
Step 5: Export to PNG
Run the export script. Determine the runtime path relative to this skill's scripts directory:
cd <skill-path>/scripts/.export-runtime && node <skill-path>/scripts/export_png.mjs /tmp/excalidraw-export/diagram.excalidraw /tmp/excalidraw-export/output.png
The script:
- Starts a local HTTP server serving the
.excalidrawfile and an HTML page - Launches headless Chromium via Playwright
- The HTML page loads the Excalidraw library from esm.sh (library code only, not user data)
- Calls
exportToBlobon the local diagram data - Extracts the base64 PNG and writes it to disk
- Cleans up temp files and exits
The script prints the output path on success. Verify the result with file <output.png>.
Step 5.5: Validate and Iterate
Run the validation script on the .excalidraw file to catch spatial issues:
node <skill-path>/scripts/validate.mjs /tmp/excalidraw-export/diagram.excalidraw
Then read the exported PNG back using the Read tool to visually inspect:
- All label text fits within its container (no overflow/clipping)
- No arrows cross over text labels
- Spacing between elements is consistent
- Legend and titles are properly positioned
If the validation script or visual inspection reveals issues:
- Identify the specific elements that need adjustment
- Edit the
.excalidrawfile (adjust coordinates, box sizes, or arrow waypoints) - Re-run the export script (Step 5)
- Re-validate
Step 6: Deliver the Result
Read the PNG file to display it to the user. Provide the file path so the user can access it directly.
Troubleshooting
Setup fails: Verify Node.js v18+ is installed (node --version). Ensure npm has network access for the initial Playwright/Chromium download.
Export times out: The HTML page has a 30-second timeout. If it fails, check browser console output in the script's error messages. Common cause: esm.sh CDN is temporarily slow on first load.
Blank PNG: Ensure elements include all required properties (see Step 4 defaults). Missing seed, version, or fontFamily on text elements can cause silent render failures.
"READY" never fires: The exportToBlob call requires valid elements. Filter out cameraUpdate and other pseudo-elements before writing the .excalidraw file.