Files
claude-engineering-plugin/plugins/compound-engineering/skills/excalidraw-png-export/references/excalidraw-element-format.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

5.5 KiB

Excalidraw Element Format Reference

This reference documents the element JSON format accepted by the Excalidraw MCP create_view tool and the export_png.mjs script.

Color Palette

Primary Colors

Name Hex Use
Blue #4a9eed Primary actions, links
Amber #f59e0b Warnings, highlights
Green #22c55e Success, positive
Red #ef4444 Errors, negative
Purple #8b5cf6 Accents, special
Pink #ec4899 Decorative
Cyan #06b6d4 Info, secondary

Fill Colors (pastel, for shape backgrounds)

Color Hex Good For
Light Blue #a5d8ff Input, sources, primary
Light Green #b2f2bb Success, output
Light Orange #ffd8a8 Warning, pending
Light Purple #d0bfff Processing, middleware
Light Red #ffc9c9 Error, critical
Light Yellow #fff3bf Notes, decisions
Light Teal #c3fae8 Storage, data

Element Types

Required Fields (all elements)

type, id (unique string), x, y, width, height

Defaults (skip these)

strokeColor="#1e1e1e", backgroundColor="transparent", fillStyle="solid", strokeWidth=2, roughness=1, opacity=100

Shapes

Rectangle: { "type": "rectangle", "id": "r1", "x": 100, "y": 100, "width": 200, "height": 100 }

  • roundness: { type: 3 } for rounded corners
  • backgroundColor: "#a5d8ff", fillStyle: "solid" for filled

Ellipse: { "type": "ellipse", "id": "e1", "x": 100, "y": 100, "width": 150, "height": 150 }

Diamond: { "type": "diamond", "id": "d1", "x": 100, "y": 100, "width": 150, "height": 150 }

Labels

Labeled shape (preferred): Add label to any shape for auto-centered text.

{ "type": "rectangle", "id": "r1", "x": 100, "y": 100, "width": 200, "height": 80, "label": { "text": "Hello", "fontSize": 20 } }

Standalone text (titles, annotations only):

{ "type": "text", "id": "t1", "x": 150, "y": 138, "text": "Hello", "fontSize": 20 }

Arrows

{ "type": "arrow", "id": "a1", "x": 300, "y": 150, "width": 200, "height": 0, "points": [[0,0],[200,0]], "endArrowhead": "arrow" }

Bindings connect arrows to shapes:

"startBinding": { "elementId": "r1", "fixedPoint": [1, 0.5] }

fixedPoint: top=[0.5,0], bottom=[0.5,1], left=[0,0.5], right=[1,0.5]

Labeled arrow: "label": { "text": "connects" }

Camera (MCP only, not exported to PNG)

{ "type": "cameraUpdate", "width": 800, "height": 600, "x": 0, "y": 0 }

Camera sizes must be 4:3 ratio. The export script filters these out automatically.

Sizing Rules

Container-to-text ratios

  • Box width >= estimated_text_width * 1.4 (40% horizontal margin)
  • Box height >= estimated_text_height * 1.5 (50% vertical margin)
  • Minimum box size: 150x60 for single-line labels, 200x80 for multi-line

Font size constraints

  • Labels inside containers: max fontSize 14
  • Service/zone titles: fontSize 18-22
  • Standalone annotations: fontSize 12-14
  • Never exceed fontSize 16 inside a box smaller than 300px wide

Padding

  • Minimum 15px padding on each side between text and container edge
  • For multi-line text, add 8px vertical padding per line beyond the first

General

  • Leave 20-30px gaps between elements

Label Content Guidelines

Keep labels short

  • Maximum 2 lines per label inside shapes
  • Maximum 25 characters per line
  • If label needs 3+ lines, split: short name in box, details as annotation below

Label patterns

  • Service box: "Service Name" (1 line) or "Service Name\nBrief role" (2 lines)
  • Component box: "Component Name" (1 line)
  • Detail text: Use standalone text elements positioned below/beside the box

Bad vs Good

BAD: label "Auth-MS\nOAuth tokens, credentials\n800-1K req/s, <100ms" (3 lines, 30+ chars) GOOD: label "Auth-MS\nOAuth token management" (2 lines, 22 chars max) + standalone text below: "800-1K req/s, <100ms p99"

Arrow Routing Rules

Gutter-based routing

  • Define horizontal and vertical gutters (20-30px gaps between service zones)
  • Route arrows through gutters, never over content areas
  • Use right-angle waypoints along zone edges

Waypoint placement

  • Start/end points: attach to box edges using fixedPoint bindings
  • Mid-waypoints: offset 20px from nearest box edge
  • For crossing traffic: stagger parallel arrows by 10px

Vertical vs horizontal preference

  • Prefer horizontal arrows for same-tier connections
  • Prefer vertical arrows for cross-tier flows (consumer -> service -> external)
  • Diagonal arrows only when routing around would add 3+ waypoints

Label placement on arrows

  • Arrow labels should sit in empty space, not over boxes
  • For vertical arrows: place label to the left or right, offset 15px
  • For horizontal arrows: place label above, offset 10px

Example: Two Connected Boxes

[
  { "type": "cameraUpdate", "width": 800, "height": 600, "x": 50, "y": 50 },
  { "type": "rectangle", "id": "b1", "x": 100, "y": 100, "width": 200, "height": 100, "roundness": { "type": 3 }, "backgroundColor": "#a5d8ff", "fillStyle": "solid", "label": { "text": "Start", "fontSize": 20 } },
  { "type": "rectangle", "id": "b2", "x": 450, "y": 100, "width": 200, "height": 100, "roundness": { "type": 3 }, "backgroundColor": "#b2f2bb", "fillStyle": "solid", "label": { "text": "End", "fontSize": 20 } },
  { "type": "arrow", "id": "a1", "x": 300, "y": 150, "width": 150, "height": 0, "points": [[0,0],[150,0]], "endArrowhead": "arrow", "startBinding": { "elementId": "b1", "fixedPoint": [1, 0.5] }, "endBinding": { "elementId": "b2", "fixedPoint": [0, 0.5] } }
]