| name | diagram-excalidraw |
| description | Generate professional system architecture diagrams using Excalidraw. Expert-level system design visuals. |
| triggers | ["์์คํ
์ํคํ
์ฒ","system architecture","์ํคํ
์ฒ ๋ค์ด์ด๊ทธ๋จ","architecture diagram","๋ค์ด์ด๊ทธ๋จ ๊ทธ๋ ค","๋ธ๋ก๊ทธ ๋ค์ด์ด๊ทธ๋จ","excalidraw","sequence diagram ๊ทธ๋ ค","์ํ์ค ๋ค์ด์ด๊ทธ๋จ ๊ทธ๋ ค","flow diagram","ํ๋ก์ฐ ๋ค์ด์ด๊ทธ๋จ","system design","์์คํ
์ค๊ณ","MSA","๋ง์ดํฌ๋ก์๋น์ค"] |
Excalidraw Professional Architecture Diagram Skill
MANDATORY: Use Excalidraw MCP tools exclusively. Never fall back to Mermaid, PlantUML, or ASCII art.
Style Selection
This skill supports two visual styles. Ask the user which style to use, or infer from context:
| Style | When to use | Visual character |
|---|
| Style 1: Minimal (default) | System design interviews, whiteboard-style, blog posts | Transparent boxes, hand-drawn feel, minimal color |
| Style 2: Icon | Presentations, formal documentation, detailed infra diagrams | Library icons (DB cylinders, browsers, phones), richer visuals |
If the user says "์์ด์ฝ", "icon", "์์ด์ฝ ์คํ์ผ", "์คํ์ผ 2" โ use Style 2.
Otherwise โ default to Style 1.
Both styles share: Design Philosophy (Section 2), Layout System (Section 3), Arrow Rules (Section 6), Templates (Section 7), Generation Workflow (Section 8), Quality Checklist (Section 9). They differ in visual style (Section 4 vs 4B) and component rendering.
1. MCP Setup
Canvas: http://localhost:3111 โ ์ฌ์ฉ์๊ฐ ๋ธ๋ผ์ฐ์ ์์ ์ด์ด๋๋ฉด ์ค์๊ฐ ๋ฐ์.
Canvas ์๋ฒ๊ฐ ๊บผ์ ธ์์ผ๋ฉด:
docker start excalidraw-canvas
docker run -d --name excalidraw-canvas -p 3111:3000 --restart unless-stopped ghcr.io/yctimlin/mcp_excalidraw-canvas:latest
์ค์๊ฐ ๋ฏธ๋ฆฌ๋ณด๊ธฐ ์๋ด (MANDATORY): ๋ค์ด์ด๊ทธ๋จ ์์ ์ ๋ฐ๋์ ์๋ด:
๋ธ๋ผ์ฐ์ ์์ http://localhost:3111 ์ ์ด์ด๋๋ฉด ์ค์๊ฐ์ผ๋ก ๋ณ๊ฒฝ์ฌํญ์ ํ์ธํ ์ ์์ต๋๋ค.
MCP ๋๊ตฌ (26๊ฐ):
| ์นดํ
๊ณ ๋ฆฌ | ๋๊ตฌ |
|---|
| ์์ CRUD | create_element, get_element, update_element, delete_element, query_elements, batch_create_elements, duplicate_elements |
| ๋ ์ด์์ | align_elements, distribute_elements, group_elements, ungroup_elements |
| Canvas ์ํ | describe_scene, get_canvas_screenshot, clear_canvas, set_viewport |
| ์ ์ฅ/๋ด๋ณด๋ด๊ธฐ | export_scene, import_scene, export_to_image, snapshot_scene, restore_snapshot |
| ๋ณํ | create_from_mermaid |
| ๊ฐ์ด๋ | read_diagram_guide, read_me |
2. Design Philosophy
These principles are grounded in cognitive science and information design research. They are not stylistic preferences โ they are how humans actually process visual information.
Gutenberg Diagram (Edmund Arnold): The eye scans from top-left (Primary Optical Area) to bottom-right (Terminal Area). Place entry points (clients, users) top-left, terminal states (databases, external APIs) bottom-right. Causality and reading direction must align.
Tufte's Data-Ink Ratio: Every visual element must carry structural meaning. No decorative fills, no gradient backgrounds, no drop shadows. If a color doesn't encode architecture role, remove it. Transparent backgrounds by default.
Miller's 7ยฑ2 Limit: Working memory holds ~7 chunks. A single diagram view should contain no more than 7-9 primary nodes. For larger systems, split into multiple diagrams at different abstraction levels (C4 model).
Gestalt Proximity: Physical distance is the strongest grouping signal. Components that are close together are perceived as a group โ more powerfully than any bounding box or color. Use whitespace intentionally to separate concerns.
Arrow Crossing Minimization: Edge crossings at shallow angles (<30ยฐ) cause measurable reading delays (Ware et al., 2008). Eliminate crossings by reordering components. If unavoidable, ensure crossings are near 90ยฐ.
3-Color Rule: The visual system reliably distinguishes ~6-8 hues. Limit to: neutral base (near-black #1e1e1e) + structural accent (system boundary color) + one semantic color (e.g., purple for async). More colors = more noise.
Fowler's Principle: "Comprehensiveness is the enemy of comprehensibility." A diagram showing the right things simply outperforms a diagram showing everything beautifully.
3. Layout System
Primary flow: Left-to-Right (following Gutenberg Diagram for LTR readers).
All coordinates and dimensions MUST be multiples of 20 (grid-snap).
Column Structure (LโR):
Col 1 x=80 External actors (Client, Users) โ outside system boundary
Col 2 x=380 Entry point (API Gateway, Load Balancer)
Col 3 x=700 Services (stacked vertically, 180px row gap)
Col 4 x=1060 Data stores (same row as their service โ horizontal alignment)
Col 5 x=1380 External dependencies (Stripe, third-party APIs) โ outside boundary
Vertical row spacing: 180px between rows.
Horizontal centering for vertical stacks: When stacking N components of width W with gap G:
- Total height = N ร H + (Nโ1) ร G
- Start Y = center_y โ (Total height / 2)
Critical layout rule โ Same-Row Alignment:
Service and its dedicated DB MUST be on the same horizontal row. This ensures ServiceโDB arrows are perfectly horizontal, eliminating all vertical crossing issues.
Row 1: Product Service โโโ Products DB
Row 2: User Service โโโ Users DB
Row 3: Order Service โโโ Orders DB
Row 4: Payment Service โโโ Payments DB โโโ Stripe API
Row ordering strategy: Order rows by user journey flow (top=first interaction, bottom=last). This naturally places event publishers (Order, Payment) near the bottom, close to the Event Bus below.
Skip empty layers. Never leave empty vertical space.
System boundary: A large rectangle with strokeWidth: 4 and accent color (e.g., #f08c00 orange) enclosing all internal components. External actors (Client, third-party APIs) stay OUTSIDE the boundary.
Logical grouping: Use strokeStyle: "dashed" rectangles with strokeWidth: 2 inside the system boundary to cluster related services (e.g., "Microservices" cluster).
4. Visual Style
Global defaults for ALL components:
{
"roughness": 1,
"strokeWidth": 2,
"strokeColor": "#1e1e1e",
"backgroundColor": "transparent",
"fontFamily": 5,
"fontSize": 20
}
Why these values:
roughness: 1 โ Slight hand-drawn feel. Signals "this is a design sketch, not a blueprint" (Fowler's sketching mode). Invites discussion and revision.
backgroundColor: transparent โ Tufte's data-ink ratio. No decorative fills. Structure is communicated through borders, position, and grouping.
fontFamily: 5 (Excalifont) โ Clean, consistent, slightly informal.
fontSize: 20 โ Uniform size for all component labels. Hierarchy is through position and nesting, not font size.
strokeColor: "#1e1e1e" (near-black) โ One neutral color for all components. Color is reserved for structural boundaries only.
Stroke width hierarchy (communicates architectural importance):
| strokeWidth | Purpose |
|---|
| 4 | System boundary (outermost container) |
| 2 | Components, arrows, logical groupings |
| 1 | Icon internals (if using custom shapes) |
Color usage (3-color rule):
| Color | Hex | Purpose |
|---|
| Near-black | #1e1e1e | ALL components, ALL arrows (default) |
| Orange | #f08c00 | System boundary rectangle (strokeColor) |
| Purple | #6741d9 | Async/event arrows and labels ONLY |
The system boundary gets white fill (#ffffff) to visually separate the system interior from the canvas background.
External systems: strokeStyle: "dashed" (signals "outside our control").
Logical clusters: strokeStyle: "dashed", strokeColor: "#1e1e1e".
5. Component Naming
Text pattern: Short, descriptive name only.
- Services:
"Order Service", "User Service" (NOT "Order Service\n[Spring Boot]")
- Databases:
"Orders DB", "Users DB"
- Infrastructure:
"Event Bus (Kafka)", "API Gateway"
- External:
"Stripe API"
Technology annotations: Place as a SEPARATE small text element at the top-left corner of the component box, NOT inside the box or on arrows.
{ "type": "text", "x": box_x + 2, "y": box_y - 16, "text": "PostgreSQL", "fontSize": 12, "fontFamily": 5, "strokeColor": "#868e96" }
This keeps the component box clean while still showing the technology stack. Only annotate where the technology choice is architecturally significant (e.g., MongoDB vs PostgreSQL matters; "Spring Boot" on every service does not).
4B. Visual Style โ Style 2: Icon Mode
Use this style when the user requests icons, richer visuals, or presentation-quality output.
Library location: ~/.claude/skills/diagram-excalidraw/libraries/
| File | Items | ์ฉ๋ | ์ฌ์ฉ ์์ |
|---|
general-icons.excalidrawlib | 36 | drwnio + technology-logos ํตํฉ. ๋ฒ์ฉ ์ํคํ
์ฒ ์์ด์ฝ + ๊ธฐ์ ๋ก๊ณ | ๊ธฐ๋ณธ (Style 2 default) |
aws-icons.excalidrawlib | 249 | AWS ์๋น์ค ๊ณต์ ์์ด์ฝ | "AWS ์ํคํ
์ฒ" ์์ฒญ ์ |
gcp-icons.excalidrawlib | 83 | GCP ์๋น์ค ์์ด์ฝ | "GCP ์ํคํ
์ฒ" ์์ฒญ ์ |
์์ด์ฝ ์ ํ ์ฐ์ ์์:
- ๊ธฐ๋ณธ:
general-icons.excalidrawlib
- "AWS๋ก ๊ทธ๋ ค์ค":
aws-icons.excalidrawlib
- "GCP๋ก ๊ทธ๋ ค์ค":
gcp-icons.excalidrawlib
general-icons.excalidrawlib (๊ธฐ๋ณธ ์์ด์ฝ):
๊ตฌ์กฐ: it-logos (index 0-30, ์ฐ์ ์์ 1, ์ด๋ฆ ์์) + drwnio filtered (index 31-45, fallback, ์ค๋ณต ์ ๊ฑฐ๋จ)
it-logos (index 0-30) โ ์ฐ์ ์ฌ์ฉ (์ด๋ฆ ๊ธฐ๋ฐ ๊ฒ์):
| Index | Name | ์ฉ๋ |
|---|
| 4 | Docker | ์ปจํ
์ด๋ |
| 7 | Firebase | ์๋ฆผ/ํธ์ |
| 9 | GitLab | Git |
| 10 | Kafka | Event Bus / Message Queue |
| 12 | Kubernetes | ์ค์ผ์คํธ๋ ์ด์
|
| 16 | Next | Next.js ํ๋ก ํธ์๋ |
| 18 | Python | Python ์๋น์ค |
| 19 | React | Web Client |
| 24 | Svelte | Svelte ํ๋ก ํธ์๋ |
| 28 | Vercel | ๋ฐฐํฌ |
| 29 | Vue | Vue ํ๋ก ํธ์๋ |
drwnio (index 31-45) โ fallback (๋ฒ์ฉ ์ํคํ
์ฒ ์์ด์ฝ):
| Index | Name | ์ฉ๋ |
|---|
| 31 | Server | ์๋ฒ |
| 32 | DB Cylinder | ๋ฐ์ดํฐ๋ฒ ์ด์ค |
| 33 | JSON File | ์ค์ /ํ์ผ |
| 34 | Redis | ์บ์ |
| 35 | Node.js | Node ์๋น์ค |
| 36 | Service Icon | ๋ฒ์ฉ ์๋น์ค |
| 37 | Network | ๋คํธ์ํฌ |
| 38 | Server Alt | ์๋ฒ ๋์ฒด |
| 39 | Globe/Internet | Web Client / ์ธํฐ๋ท |
| 40 | Storage | ์คํ ๋ฆฌ์ง |
| 41 | Container | ์ปจํ
์ด๋ |
| 42 | User | ์ฌ์ฉ์/๋ชจ๋ฐ์ผ |
| 43 | API | API ์๋ํฌ์ธํธ |
| 44 | Large Service | ํฐ ์๋น์ค |
| 45 | DNS | DNS |
How to place library icons:
๊ฐ ์์ด์ฝ์ ๊ฐ๋ณ .excalidraw ํ์ผ๋ก ์ ์ฅ ํ import_scene์ผ๋ก ํ๋์ฉ import.
import json, uuid, copy
LIB_DIR = '~/.claude/skills/diagram-excalidraw/libraries'
def save_icon(lib_path, index, target_x, target_y, prefix, out_path):
"""Extract one library item, assign unique IDs, save as .excalidraw"""
with open(lib_path) as f:
lib = json.load(f)
item = copy.deepcopy(lib['library'][index])
min_x = min(e['x'] for e in item)
min_y = min(e['y'] for e in item)
grp = f"{prefix}-grp"
for e in item:
e['x'] = e['x'] - min_x + target_x
e['y'] = e['y'] - min_y + target_y
e['id'] = f"{prefix}-{uuid.uuid4().hex[:8]}"
if e.get('groupIds'):
e['groupIds'] = [grp]
scene = json.dumps({'type': 'excalidraw', 'version': 2, 'elements': item})
with open(out_path, 'w') as f:
f.write(scene)
Then import each file individually:
import_scene(filePath="icon-db1.excalidraw", mode="merge")
CRITICAL constraints (์๋ฌ ๋ฐฉ์ง):
- One icon per file: ์ฌ๋ฌ ์์ด์ฝ์ ํ .excalidraw ํ์ผ์ ํฉ์น๋ฉด import ์ ๋๋ฝ๋จ. ๋ฐ๋์ ์์ด์ฝ 1๊ฐ = ํ์ผ 1๊ฐ.
- Unique IDs: ๊ฐ์ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์์ดํ
์ ์ฌ๋ฌ ๋ฒ ๋ณต์ ํ ๋ ๋ฐ๋์
uuid.uuid4()๋ก ๊ฐ ์์ ID + groupId ์ ๋ํฌํ. ์ค๋ณต ID๋ ๋ง์ง๋ง ํ๋๋ง ๋ ๋๋ง๋จ.
- System boundary: Style 2์์๋
backgroundColor: "transparent" ํ์. white fill์ ์์ด์ฝ์ z-order๋ก ๊ฐ๋ฆผ.
- filePath ์ ํ:
import_scene์ filePath๋ ํ๋ก์ ํธ ๋๋ ํ ๋ฆฌ ๋ด๋ถ๋ง ๊ฐ๋ฅ. /tmp/ ๋ฑ ์ธ๋ถ ๊ฒฝ๋ก ์ฐจ๋จ๋จ. ๋ฐ๋์ ํ๋ก์ ํธ ๋ฃจํธ์ temp ํ์ผ ์์ฑ.
- temp ํ์ผ ์ ๋ฆฌ: import ์ฑ๊ณต ํ ์ฆ์
.excalidraw temp ํ์ผ ์ญ์ (rm).
- scale ์ฒ๋ฆฌ: ์์ด์ฝ ์๋ณธ์ด 300-600px๋ก ํฌ๋ฏ๋ก scale ํฉํฐ(0.15~0.4)๋ฅผ ์ ์ฉ. width, height, points ๋ฐฐ์ด ๋ชจ๋ scale ์ ์ฉ ํ์.
- import ์์: ๋จผ์
batch_create_elements๋ก ๋ชจ๋ rectangle/arrow/text ์์ฑ โ ๊ทธ ๋ค์ import_scene์ผ๋ก ์์ด์ฝ ์ถ๊ฐ (z-order: ์์ด์ฝ์ด ์์ ๋ ๋๋ง๋จ)
Style 2 component rendering (๊ธฐ๋ณธ: general-icons):
- ์์ด์ฝ์ด ์ปดํฌ๋ํธ ์๋ฏธ์ ์ ํํ ๋ง์ ๋๋ง ์ฌ์ฉ. ์ต์ง๋ก ๋ฃ์ง ์๋๋ค.
- ๋ง์ง ์์ผ๋ฉด Style 1๊ณผ ๋์ผํ rectangle + ํ
์คํธ๋ก ๋์ฒด.
- DB โ index 32 (DB Cylinder, drwnio) + ์๋ ํ
์คํธ ๋ ์ด๋ธ
- Kafka/Queue โ index 10 (Kafka, it-logos) + ์๋ ํ
์คํธ
- Kubernetes โ index 12 (Kubernetes, it-logos)
- Docker โ index 4 (Docker, it-logos)
- Redis/Cache โ index 34 (Redis, drwnio)
- Python Service โ index 18 (Python, it-logos)
- React Client โ index 19 (React, it-logos) โ ๋จ, ์ด์ธ๋ฆฌ์ง ์์ผ๋ฉด rectangle
- Client (Web/Mobile), API Gateway, ์ผ๋ฐ Service โ rectangle ์ ์ง (์์ด์ฝ ๋ถํ์)
- ์์น: ์์ด์ฝ์ ๊ธฐ์ ์คํ์ ์๊ฐ์ ์ผ๋ก ์ฆ์ ์ธ์ ๊ฐ๋ฅํ ๋๋ง ์ฌ์ฉ. ๋ชจํธํ๋ฉด ๋ฐ์ค๊ฐ ๋ซ๋ค.
Arrow binding for icons: ์์ด์ฝ์ line/ellipse/draw ์์๋ก ๊ตฌ์ฑ โ arrow binding ๋ถ๊ฐ. ๊ฐ์ ์์น์ opacity: 0 ํฌ๋ช
rectangle์ ์์ฑํ๊ณ ํ์ดํ๋ฅผ ๊ทธ rectangle์ ๋ฐ์ธ๋ฉ.
Style 2 inherits from Style 1: Layout system, arrow rules, design philosophy, templates, quality checklist ๋ชจ๋ ๋์ผ. ์ปดํฌ๋ํธ ๋ ๋๋ง๋ง ์์ด์ฝ์ผ๋ก ๊ต์ฒด.
AWS Icons ์ฃผ์ ์ธ๋ฑ์ค (aws-icons.excalidrawlib, "AWS๋ก ๊ทธ๋ ค์ค" ์์ฒญ ์):
| Index | Name | Use for |
|---|
| 52 | Aurora | Aurora DB |
| 54 | DynamoDB | NoSQL |
| 62 | RDS | SQL DB |
| 65 | ElastiCache | Cache |
| 74 | S3 | Storage |
| 78 | EC2 | Compute |
| 87 | Lambda | Serverless |
| 94 | EKS | K8s |
| 98 | ECS | Container |
| 104 | Fargate | Serverless Container |
| 105 | SNS | Pub/Sub |
| 106 | SQS | Queue |
| 110 | EventBridge | Event Bus |
| 209 | CloudFront | CDN |
| 228 | ELB | Load Balancer |
| 233 | API Gateway | API GW |
6. Arrow & Connection Rules
Global arrow defaults:
{
"strokeWidth": 2,
"strokeColor": "#1e1e1e",
"roughness": 1,
"endArrowhead": "arrow"
}
CRITICAL: Always use startElementId and endElementId for arrow binding. Never use manual coordinates.
Arrow text: Use floating text labels, NOT built-in arrow text property.
Built-in arrow labels auto-place at the midpoint and CANNOT be repositioned, causing overlap when arrows cross other elements. Instead, create a separate type: "text" element positioned near the arrow's source or along the arrow path.
{ "type": "arrow", ..., "text": "REST" }
{ "type": "text", "x": 610, "y": 266, "text": "REST", "fontSize": 16, "fontFamily": 5, "strokeColor": "#868e96" }
Label placement strategy:
- Protocol labels (HTTPS, REST, gRPC): Place as floating text between source and target, slightly above the arrow path
- One label per arrow group is sufficient (e.g., one "REST" label for 4 GatewayโService arrows, not 4 separate labels)
- Async labels: Place near the Event Bus with the async accent color
Connection types:
| Type | strokeStyle | strokeColor | Label example |
|---|
| Sync call | solid | #1e1e1e | "HTTPS", "REST", "gRPC" |
| Async event | dashed | #6741d9 | "Pub/Sub", "Event" |
| Data access | solid | #1e1e1e | (usually unlabeled โ the DB box name is sufficient) |
| External API | solid | #1e1e1e | "REST API" |
When NOT to label arrows:
- Service โ its own DB: The horizontal arrow's meaning is obvious from context. No label needed.
- Multiple identical connections: Use one shared label (e.g., one "REST" for all GatewayโService arrows).
7. Diagram Templates
Template selection logic:
- "์์คํ
์ค๊ณ", "system design" โ System Design Template
- "MSA", "๋ง์ดํฌ๋ก์๋น์ค", "microservice" โ MSA Template
- "ํ์ดํ๋ผ์ธ", "data flow", "ETL" โ Data Pipeline Template
- Default โ System Design Template
System Design Template
Left-to-right flow:
Client โ LB/CDN โ API Gateway โ Services โ Cache/DB
- Entry point (Client) at top-left, outside system boundary
- Services stacked vertically in center column
- Data stores to the right, same row as their service
MSA Template
Left-to-right flow with per-service databases:
Client โ API Gateway โ [Services column] โ [DB column]
โ
Event Bus โ Notification
- System boundary (orange, strokeWidth 4) encloses Gateway through DBs
- Dashed cluster around Microservices column
- Each Service โ DB on same horizontal row (zero crossing)
- Row order follows user journey (browse โ auth โ order โ pay)
- Event Bus below services; publishers (Order, Payment) at bottom rows, closest to Event Bus
- Async arrows in purple dashed (#6741d9)
- External systems (Stripe) outside boundary, connected via dashed-border box
Data Pipeline Template
Left-to-right horizontal flow:
Sources โ Ingestion โ Processing โ Storage โ Serving โ Consumers
- Stages as columns, components stacked vertically within each stage
- Stage gap: 240px horizontal
8. Generation Workflow
Execute in this exact order:
Step 1: clear_canvas
Step 2: Plan layout โ calculate all positions using Column Structure + Same-Row Alignment
Step 3: batch_create_elements โ System boundary + logical grouping zones
Step 4: batch_create_elements โ All components (assign custom `id` to each)
Step 5: batch_create_elements โ All arrows (using startElementId/endElementId) + floating text labels + title
Step 6: get_canvas_screenshot โ Visual verification
Step 7: Quality Checklist review โ fix issues with update_element / delete_element
ID convention: Use descriptive, kebab-case IDs:
"client", "gw", "svc-order", "svc-user", "db-orders", "event-bus", "stripe"
Title placement: Top-left corner (Gutenberg primary optical area), fontSize: 28, fontFamily: 5.
9. Quality Checklist
After get_canvas_screenshot, verify:
If any item fails, fix with update_element or delete_element. Do NOT regenerate the entire diagram.
10. Saving & Export
- File save:
export_scene โ .excalidraw JSON file
- Image export:
export_to_image โ PNG/SVG
- Snapshot:
snapshot_scene / restore_snapshot โ backup/restore during work
11. Fallback
If MCP server is unavailable:
- Generate
.excalidraw JSON file directly for opening in excalidraw.com
- Guide user to start the MCP server
12. Exception
If the user explicitly asks for a README or markdown-embedded diagram, Mermaid is acceptable.
For any blog, presentation, or standalone diagram, Excalidraw is mandatory.