Files
claude-engineering-plugin/plugins/compound-engineering/skills/excalidraw-png-export/SKILL.md
John Lamb fe3b1eee16 Merge upstream v2.67.0 with fork customizations preserved
Synced 79 commits from EveryInc/compound-engineering-plugin upstream while
preserving fork-specific customizations (Python/FastAPI pivot, Zoominfo-internal
review agents, deploy-wiring operational lessons, custom personas).

## Triage decisions (15 conflicts resolved)

Keep deleted (7) -- fork already removed these in prior cleanups:
- agents/design/{design-implementation-reviewer,design-iterator,figma-design-sync}
  (no fork successor; backend-Python focus doesn't need UI/Figma agents)
- agents/docs/ankane-readme-writer (replaced by python-package-readme-writer)
- agents/review/{data-migration-expert,performance-oracle,security-sentinel}
  (replaced by *-reviewer naming convention: data-migrations-reviewer,
  performance-reviewer, security-reviewer)

Keep local (1):
- agents/workflow/lint.md (Python tooling: ruff/mypy/djlint/bandit; upstream
  deleted the file). Fixed pre-existing duplicate "2." numbering bug.

Restore from upstream (1):
- agents/review/data-integrity-guardian.md (kept for GDPR/CCPA privacy
  compliance angle not covered by data-migrations-reviewer)

Merge both (6) -- upstream structural wins layered with fork intent:
- agents/research/best-practices-researcher.md (upstream <examples> removal +
  fork's Rails/Ruby -> Python/FastAPI translations)
- skills/ce-brainstorm/SKILL.md (universal-brainstorming routing + Slack
  context + non-obvious angles + fork's Deploy wiring flag)
- skills/ce-plan/SKILL.md (universal-planning routing + planning-bootstrap +
  fork's two Deploy wiring check bullets)
- skills/ce-review/SKILL.md (Run ID, model tiering haiku->sonnet, compact-JSON
  artifact contract, file-type awareness, cli-readiness-reviewer + fork's
  zip-agent-validator, design-conformance-reviewer, Stage 6 Zip Agent
  Validation)
- skills/ce-review/references/persona-catalog.md (cli-readiness row + adversarial
  refinement + fork's Language & Framework Conditional layer; 22 personas total)
- skills/ce-work/SKILL.md (Parallel Safety Check, parallel-subagent constraints,
  Phase 3-4 compression + fork's deploy-values self-review row, with duplicate
  checklist bullet collapsed to single occurrence)

## Auto-applied (no triage needed)

- 225 remote-only files: accepted as-is (new docs, brainstorms, plans,
  upstream skills, tests, scripts)
- 70 local-only files: 46 preserved as-is (kieran-python, tiangolo-fastapi,
  zip-agent-validator, design-conformance-reviewer, essay/proof commands,
  excalidraw-png-export, etc.); 24 stayed deleted (dhh-rails-style,
  andrew-kane-gem-writer, dspy-ruby Ruby skills no longer needed)

## README updated

- Removed Design section (3 deleted agents)
- Removed deleted Review entries (data-migration-expert, dhh-rails-reviewer,
  kieran-rails-reviewer, performance-oracle, security-sentinel)
- Added new Review entries: design-conformance-reviewer, previous-comments-reviewer,
  tiangolo-fastapi-reviewer, zip-agent-validator
- Workflow: added lint
- Docs: replaced ankane-readme-writer with python-package-readme-writer

## Known issues (not introduced by merge decisions)

- 9 detect-project-type.sh tests fail on macOS bash 3.2 (script uses
  `declare -A` which requires bash 4+). Upstream regression in commit 070092d
  (#568). Resolution: install bash 4+ via `brew install bash` locally;
  upstream fix tracked separately.
- 2 review-skill-contract tests reference deleted agents (dhh-rails-reviewer,
  data-migration-expert). Pre-existing fork inconsistency, not new.

bun run release:validate: passes (46 agents, 51 skills, 0 MCP servers)
2026-04-17 17:24:41 -05:00

6.9 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.

File Location Convention

Save diagram source files alongside their PNG exports in the project's image directory. This enables re-exporting diagrams when content or styling changes.

Standard pattern:

docs/images/my-diagram.excalidraw    # source (commit this)
docs/images/my-diagram.png           # rendered output (commit this)

When updating an existing diagram, look for a .excalidraw file next to the PNG. If one exists, edit it and re-export rather than rebuilding from scratch.

Temporary files (raw checkpoint JSON) go in /tmp/excalidraw-export/ and are discarded after conversion.

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 label on shapes instead of separate text elements
  • Use roundness: { type: 3 } for rounded corners on rectangles
  • Include cameraUpdate as 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 label properties on shapes/arrows into proper bound text elements
# Save checkpoint JSON to a temp file, then convert to the project's image directory:
node <skill-path>/scripts/convert.mjs /tmp/excalidraw-export/raw.json docs/images/my-diagram.excalidraw

The input JSON should be the raw checkpoint data from mcp__excalidraw__read_checkpoint (the {"elements": [...]} object). The output .excalidraw file goes in the project's image directory (see File Location Convention above).

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 docs/images/my-diagram.excalidraw docs/images/my-diagram.png

The script:

  1. Starts a local HTTP server serving the .excalidraw file and an HTML page
  2. Launches headless Chromium via Playwright
  3. The HTML page loads the Excalidraw library from esm.sh (library code only, not user data)
  4. Calls exportToBlob on the local diagram data
  5. Extracts the base64 PNG and writes it to disk
  6. 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 docs/images/my-diagram.excalidraw

Then read the exported PNG back using the Read tool to visually inspect:

  1. All label text fits within its container (no overflow/clipping)
  2. No arrows cross over text labels
  3. Spacing between elements is consistent
  4. Legend and titles are properly positioned

If the validation script or visual inspection reveals issues:

  1. Identify the specific elements that need adjustment
  2. Edit the .excalidraw file (adjust coordinates, box sizes, or arrow waypoints)
  3. Re-run the export script (Step 5)
  4. 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.