excalidraw-generation

from rhuss/cc-slidev

Claude Code plugin for creating developer-focused technical presentations using Slidev with evidence-based design guardrails

5 stars2 forksUpdated Dec 4, 2025
npx skills add https://github.com/rhuss/cc-slidev --skill excalidraw-generation

SKILL.md

Excalidraw Generation Expert

Core Philosophy: Semantic redesign, not mechanical conversion. Think like both a presentation designer (clarity, accessibility, simplicity) and an artist (creative visual expression, spatial design, aesthetic beauty).

CRITICAL - Rendering Rule

ALWAYS use render-excalidraw.sh for SVG conversion - NO EXCEPTIONS

After creating Excalidraw JSON:

  1. Save JSON to diagrams/<slug>.excalidraw
  2. MUST render using: ${CLAUDE_PLUGIN_ROOT}/scripts/render-excalidraw.sh
  3. NEVER attempt manual SVG conversion
  4. NEVER embed JSON in markdown - only reference the rendered SVG

The script handles all rendering automatically with excalidraw-brute-export-cli.

When to Use This Skill

Auto-trigger when:

  • User explicitly requests: "create excalidraw diagram", "hand-drawn diagram", "sketch", "whiteboard"
  • Slide content suggests conceptual/spatial relationships
  • Architecture with nested components
  • Brainstorming/ideation context
  • Informal, approachable style needed
  • Annotations and callouts would add value

Diagram type suitability:

  • ✅✅✅ BEST: Conceptual relationships, architecture diagrams, mind maps, timelines, comparisons
  • ✅✅ EXCELLENT: Flowcharts (with annotations), spatial layouts, nested structures
  • ⚠️ OKAY: Sequence diagrams (prefer Mermaid instead)
  • ❌ NOT RECOMMENDED: Formal UML (use PlantUML), state machines (use Mermaid)

Evidence-Based Design Constraints (HARD LIMITS)

These constraints are NON-NEGOTIABLE. Enforce strictly:

  • Cognitive load: Maximum 9 elements (7±2 rule from cognitive psychology)
  • Accessibility:
    • Colorblind-safe palette ONLY: Blue #3b82f6 + Orange #f97316
    • Minimum 4.5:1 contrast ratio for all text (WCAG AA)
    • Never rely on color alone to convey information
  • Minimal text: Under 50 words total per diagram
  • One idea per diagram: If concept is complex, split into multiple diagrams
  • Hand-drawn aesthetic: Roughness 1 for informal feel

Core Capabilities

1. Semantic Concept Extraction

Process (ALWAYS follow this order):

  1. Analyze user's description or slide content

  2. Extract core concepts (entities, relationships, flows)

  3. Identify semantic type:

    • Containment: X contains Y → Use nested boxes/frames
    • Flow: A→B→C → Use arrows with spatial progression
    • Comparison: X vs Y → Use side-by-side separation
    • Hierarchy: Parent-child → Use vertical/spatial positioning
    • Grouping: Related items → Use frames or color-coded regions
    • Annotation: Context/explanation → Use callouts and bound text
  4. Design layout (choose from layout algorithms below)

  5. Generate JSON (use element factories below)

Example:

Input: "Kubernetes device plugin architecture"

Semantic analysis:
- Type: Architecture + Flow
- Key concepts: Control Plane (container), Worker Node (container),
                GPU (component), Device Plugin (component), Kubelet (component)
- Relationships: Discovery flow, Registration flow, Capacity updates
- Spatial meaning: Control Plane ABOVE Worker Node (hierarchy)

Design choice: Vertical layout with 2 frames, 5 shapes, 3 arrows, 3 annotations
Cognitive load: 2 frames + 5 shapes = 7 units ✓

2. Element Factories

These functions generate valid Excalidraw JSON elements. Use them to build diagrams.

ID Generation

function generateId() {
  // Excalidraw uses random alphanumeric IDs (12+ chars)
  return Math.random().toString(36).substring(2, 15) +
         Math.random().toString(36).substring(2, 15);
}

Rectangle Factory

function createRectangle(x, y, width, height, text = null, options = {}) {
  const id = generateId();

  const element = {
    type: "rectangle",
    version: 1,
    versionNonce: Math.floor(Math.random() * 1000000),
    isDeleted: false,
    id: id,
    fillStyle: options.fillStyle || "hachure",
    strokeWidth: options.strokeWidth || 2,
    strokeStyle: "solid",
    roughness: options.roughness !== undefined ? options.roughness : 1,
    opacity: 100,
    angle: options.angle || 0,
    x: x,
    y: y,
    strokeColor: options.strokeColor || THEME_COLORS.primary,
    backgroundColor: options.backgroundColor || "transparent",
    width: width,
    height: height,
    seed: Math.floor(Math.random() * 1000000),
    groupIds: options.groupIds || [],
    frameId: options.frameId || null,
    roundness: { type: 3 },
    boundElements: [],
    updated: Date.now(),
    link: null,
    locked: false
  };

  // If text provided, create bound text element
  if (text) {
    const textElement = createBoundText(text, id, x, y, width, height);
    element.boundElements.push({ type: "text", id: textElement.id });
    return [element, textElement];  // Return array
  }

  return element;  // Return single element
}

Text Factory (Standalone and Bound)

function createText(text, x, y, options = {}) {
  return {
    type: "text",
    version: 1,
    v

...
Read full content

Repository Stats

Stars5
Forks2
LicenseMIT License