Skip to content
cccskills
FreePublished on GitHub

excalidraw

Expert guidance for Excalidraw, the open-source virtual whiteboard library for creating hand-drawn style diagrams and sketches. Helps developers embed Excalidraw in React applications, build custom integrations, and leverage the API for programmatic diagram creation.

The English summary is being prepared. Showing the original description.

See how to install

Files included (2)

  • SKILL.md10.4 KB
  • _scores.json1.6 KB

SKILL.md (original)

Review the instructions the agent will receive before you install.

Excalidraw — Hand-Drawn Whiteboard SDK

Overview

Excalidraw, the open-source virtual whiteboard library for creating hand-drawn style diagrams and sketches. Helps developers embed Excalidraw in React applications, build custom integrations, and leverage the API for programmatic diagram creation.

Instructions

Basic Embedding

Add an Excalidraw whiteboard to any React application:

// src/components/Whiteboard.tsx — Embed Excalidraw in a React app
import { Excalidraw } from "@excalidraw/excalidraw";
import { ExcalidrawElement } from "@excalidraw/excalidraw/types/element/types";
import { AppState } from "@excalidraw/excalidraw/types/types";
import { useState, useCallback } from "react";

export function Whiteboard() {
  const [excalidrawAPI, setExcalidrawAPI] = useState<any>(null);

  const handleChange = useCallback(
    (elements: readonly ExcalidrawElement[], state: AppState) => {
      // Called on every change — debounce before persisting
      console.log(`${elements.length} elements on canvas`);
    },
    []
  );

  return (
    <div style={{ height: "100vh", width: "100%" }}>
      <Excalidraw
        ref={(api) => setExcalidrawAPI(api)}
        onChange={handleChange}
        initialData={{
          appState: {
            viewBackgroundColor: "#fafafa",
            currentItemFontFamily: 1,    // 1 = Virgil (hand-drawn), 2 = Helvetica, 3 = Cascadia
          },
        }}
        UIOptions={{
          canvasActions: {
            loadScene: true,
            export: { saveFileToDisk: true },
            toggleTheme: true,
          },
        }}
      />
    </div>
  );
}

Programmatic Scene Creation

Generate diagrams from code or data:

// src/diagrams/architecture.ts — Generate architecture diagrams programmatically
import { ExcalidrawElement } from "@excalidraw/excalidraw/types/element/types";

interface ServiceNode {
  name: string;
  type: "api" | "database" | "queue" | "cache" | "frontend";
  x: number;
  y: number;
}

function createServiceBox(service: ServiceNode): ExcalidrawElement {
  const colors: Record<string, string> = {
    api: "#a5d8ff",        // Blue for APIs
    database: "#b2f2bb",   // Green for databases
    queue: "#ffec99",      // Yellow for queues
    cache: "#ffc9c9",      // Red for caches
    frontend: "#d0bfff",   // Purple for frontends
  };

  return {
    type: "rectangle",
    id: `service-${service.name}`,
    x: service.x,
    y: service.y,
    width: 200,
    height: 80,
    strokeColor: "#1e1e1e",
    backgroundColor: colors[service.type] || "#e9ecef",
    fillStyle: "solid",
    strokeWidth: 2,
    roughness: 1,            // 0 = smooth, 1 = hand-drawn, 2 = very rough
    roundness: { type: 3, value: 8 },
    isDeleted: false,
    boundElements: null,
    locked: false,
    opacity: 100,
    angle: 0,
    seed: Math.floor(Math.random() * 100000),  // Random seed for hand-drawn variation
    version: 1,
    versionNonce: Math.floor(Math.random() * 100000),
    groupIds: [],
    frameId: null,
    link: null,
    updated: Date.now(),
  } as any;
}

function createArrow(
  fromId: string, toId: string,
  startX: number, startY: number,
  endX: number, endY: number,
  label?: string
): ExcalidrawElement {
  return {
    type: "arrow",
    id: `arrow-${fromId}-${toId}`,
    x: startX,
    y: startY,
    width: endX - startX,
    height: endY - startY,
    strokeColor: "#1e1e1e",
    strokeWidth: 2,
    roughness: 1,
    points: [[0, 0], [endX - startX, endY - startY]],
    startBinding: { elementId: fromId, focus: 0, gap: 4 },
    endBinding: { elementId: toId, focus: 0, gap: 4 },
    startArrowhead: null,
    endArrowhead: "arrow",
    isDeleted: false,
    opacity: 100,
    angle: 0,
    seed: Math.floor(Math.random() * 100000),
    version: 1,
    versionNonce: Math.floor(Math.random() * 100000),
    groupIds: [],
    boundElements: null,
    locked: false,
    frameId: null,
    link: null,
    updated: Date.now(),
  } as any;
}

// Generate a full architecture diagram
export function generateArchitectureDiagram(services: ServiceNode[], connections: [string, string][]) {
  const elements: ExcalidrawElement[] = [];

  // Create service boxes
  for (const service of services) {
    elements.push(createServiceBox(service));

    // Add label text
    elements.push({
      type: "text",
      id: `label-${service.name}`,
      x: service.x + 20,
      y: service.y + 25,
      width: 160,
      height: 30,
      text: `${service.name}\n(${service.type})`,
      fontSize: 16,
      fontFamily: 1,           // Virgil hand-drawn font
      textAlign: "center",
      verticalAlign: "middle",
      strokeColor: "#1e1e1e",
      isDeleted: false,
      opacity: 100,
      angle: 0,
      seed: Math.floor(Math.random() * 100000),
      version: 1,
      versionNonce: Math.floor(Math.random() * 100000),
      groupIds: [],
      boundElements: null,
      locked: false,
      frameId: null,
      link: null,
      updated: Date.now(),
      containerId: `service-${service.name}`,
    } as any);
  }

  // Create arrows for connections
  for (const [from, to] of connections) {
    const fromService = services.find(s => s.name === from)!;
    const toService = services.find(s => s.name === to)!;
    elements.push(createArrow(
      `service-${from}`, `service-${to}`,
      fromService.x + 200, fromService.y + 40,
      toService.x, toService.y + 40,
    ));
  }

  return elements;
}

Export and Import

Save diagrams as files, images, or shareable links:

// src/utils/export.ts — Export Excalidraw scenes in various formats
import { exportToBlob, exportToSvg, serializeAsJSON } from "@excalidraw/excalidraw";

async function exportAsPNG(excalidrawAPI: any) {
  const elements = excalidrawAPI.getSceneElements();
  const appState = excalidrawAPI.getAppState();

  const blob = await exportToBlob({
    elements,
    appState: { ...appState, exportWithDarkMode: false },
    files: excalidrawAPI.getFiles(),
    getDimensions: () => ({ width: 1920, height: 1080, scale: 2 }),  // 2x for retina
  });

  // Download the image
  const url = URL.createObjectURL(blob);
  const link = document.createElement("a");
  link.href = url;
  link.download = "diagram.png";
  link.click();
  URL.revokeObjectURL(url);
}

async function exportAsSVG(excalidrawAPI: any) {
  const elements = excalidrawAPI.getSceneElements();
  const svg = await exportToSvg({
    elements,
    appState: { exportWithDarkMode: false },
    files: excalidrawAPI.getFiles(),
  });
  return svg.outerHTML;   // Returns SVG as string
}

function saveAsExcalidrawFile(excalidrawAPI: any) {
  const elements = excalidrawAPI.getSceneElements();
  const appState = excalidrawAPI.getAppState();
  const json = serializeAsJSON(elements, appState, excalidrawAPI.getFiles(), "local");

  const blob = new Blob([json], { type: "application/json" });
  const url = URL.createObjectURL(blob);
  const link = document.createElement("a");
  link.href = url;
  link.download = "diagram.excalidraw";
  link.click();
}

// Load from .excalidraw file
async function loadFromFile(excalidrawAPI: any, file: File) {
  const text = await file.text();
  const data = JSON.parse(text);
  excalidrawAPI.updateScene({
    elements: data.elements,
    appState: data.appState,
  });
}

Collaboration with Excalidraw+

Set up real-time collaboration:

// src/components/CollaborativeBoard.tsx — Real-time whiteboard with collaboration
import { Excalidraw, LiveCollaborationTrigger } from "@excalidraw/excalidraw";

export function CollaborativeBoard({ roomId }: { roomId: string }) {
  return (
    <div style={{ height: "100vh" }}>
      <Excalidraw
        isCollaborating={true}
        // Custom collaboration backend using WebSocket
        onCollabButtonClick={() => {
          // Open share dialog or copy room link
          const link = `${window.location.origin}/board/${roomId}`;
          navigator.clipboard.writeText(link);
        }}
        renderTopRightUI={() => (
          <LiveCollaborationTrigger
            isCollaborating={true}
            onSelect={() => {}}
          />
        )}
      />
    </div>
  );
}

Installation

npm install @excalidraw/excalidraw

# Peer dependencies
npm install react react-dom

Examples

Example 1: Setting up Excalidraw with a custom configuration

User request:

I just installed Excalidraw. Help me configure it for my TypeScript + React workflow with my preferred keybindings.

The agent creates the configuration file with TypeScript-aware settings, configures relevant plugins/extensions for React development, sets up keyboard shortcuts matching the user's preferences, and verifies the setup works correctly.

Example 2: Extending Excalidraw with custom functionality

User request:

I want to add a custom programmatic scene creation to Excalidraw. How do I build one?

The agent scaffolds the extension/plugin project, implements the core functionality following Excalidraw's API patterns, adds configuration options, and provides testing instructions to verify it works end-to-end.

Guidelines

  1. Container must have dimensions — Excalidraw expands to fill its container; ensure explicit height/width
  2. Debounce onChange — Canvas fires updates on every mouse move during drawing; debounce to 500ms for persistence
  3. Use roughness for style — roughness: 0 for clean diagrams, 1 for hand-drawn feel, 2 for sketch style
  4. Seed for consistency — Same seed = same hand-drawn variation; use deterministic seeds for reproducible diagrams
  5. Export SVG for docs — SVG exports are resolution-independent and embed well in documentation
  6. Lazy load the component — Excalidraw bundle is ~1MB; use React.lazy() to avoid blocking initial page load
  7. Use frames for grouping — Frames in Excalidraw act as containers; export individual frames as separate images
  8. Store .excalidraw files in git — The JSON format is text-based and diffs well in version control

Reviews

No reviews yet. Tell others what you thought.

Comments

No login needed. Share how it worked for you, ask a question, or note where it did not run.

No comments yet. Be the first to write one.

Comments are published right away. Do not include personal information such as email addresses or phone numbers. Up to 2 URLs.

0 / 1,000 characters

This form is protected by reCAPTCHA, and the Google Privacy Policy and Terms of Service apply.

More skills from this repository

Scripts and configures production rendering in Autodesk 3ds Max with the V-Ray and Corona renderers: output size and files, render elements, denoising, light mix, batch and command-line rendering, and network rendering. Use when a user asks to set up a production render, render several cameras in one batch, render from the command line or on a render farm, add render passes for compositing, or cut render time for archviz and product shots.

The English summary is being prepared. Showing the original description.

TerminalSkills/skills174Updated Oct 22, 2026

Covers scripting Autodesk 3ds Max, the 3D modeling and rendering application, with MAXScript and Python (pymxs): scene manipulation, object creation, material assignment, camera and light setup, batch operations, and file I/O. Use when tasks involve automating repetitive 3ds Max workflows, batch processing scenes, running scripts headless with 3dsmaxbatch, creating custom tools, or scripting scene setup for archviz, product visualization, or VFX.

The English summary is being prepared. Showing the original description.

TerminalSkills/skills174Updated Oct 22, 2026

3proxy

Free

3proxy is a small open-source proxy server that runs HTTP/HTTPS, SOCKS4/5, SNI and TCP/UDP port-mapping proxies from one config file. Use when a user asks to set up an HTTP or SOCKS5 proxy, add proxy users and passwords, write 3proxy access rules, chain or rotate upstream (parent) proxies, limit bandwidth, connections or monthly traffic per user, run 3proxy in Docker, or fix a 3proxy.cfg that will not start.

The English summary is being prepared. Showing the original description.

TerminalSkills/skills174Updated Oct 22, 2026

Builds Agent2Agent (A2A) servers and clients, the open protocol (originally from Google, now under the Linux Foundation) that lets AI agents from different frameworks call each other. Use when the user wants to create an A2A-compliant agent, build an Agent Card, implement task management, connect agents across frameworks, set up agent discovery, handle streaming responses, implement push notifications, or orchestrate multi-agent workflows. Trigger words: a2a, agent to agent, agent2agent, a2a protocol, a2a server, a2a client, agent card, agent interoperability, agent collaboration, multi-agent, agent discovery, a2a sdk, a2a task.

The English summary is being prepared. Showing the original description.

TerminalSkills/skills174Updated Oct 22, 2026

Plans a controlled experiment (A/B test) so its result can be trusted: writes the hypothesis, picks one primary metric and the guardrails, computes sample size and run time, specifies how visitors are assigned and when exposure is logged, and reads out the result with a confidence interval. Use when someone says "set up an A/B test", "split test this page", "how many visitors do I need", "how long should the experiment run", "is this result significant", "can I stop the test early", or wants to test a headline, price, layout or onboarding change against the current version.

The English summary is being prepared. Showing the original description.

TerminalSkills/skills174Updated Oct 22, 2026

ably

Free

Ably is a hosted realtime messaging service: clients publish and subscribe to named channels over WebSockets, see who is present, replay message history, and resume after a dropped connection. Use when a user asks to "add realtime updates", "push live notifications to the browser", "show who is online", "add a chat room with typing indicators", "publish from a serverless function", or "authenticate Ably clients without exposing the API key". Covers the ably 2.x JavaScript SDK (Realtime and REST), JWT token authentication, presence, history and rewind, batch publishing, and the @ably/chat 1.x SDK.

The English summary is being prepared. Showing the original description.

TerminalSkills/skills174Updated Oct 22, 2026

See all skills by TerminalSkills

Report a problem with this skill