跳到正文
cccskills
免费在 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.

中文简介正在准备中。当前显示原文说明。

查看安装方法

包含的文件(2)

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

SKILL.md(原文)

安装前可以查看交给 AI 代理的指令内容。

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

评价

还没有评价。欢迎分享你的使用感受。

评论

无需登录即可发表。欢迎分享使用感受、提问,或说明在哪些环境下无法运行。

还没有评论。来写第一条吧。

提交后会立即公开。请勿填写邮箱、电话等个人信息。URL 最多 2 个。

0 / 1000 字

此表单受 reCAPTCHA 保护,适用 Google 的隐私权政策和服务条款。

同一仓库的技能

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.

中文简介正在准备中。当前显示原文说明。

TerminalSkills/skills1742026年10月21日 更新

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.

中文简介正在准备中。当前显示原文说明。

TerminalSkills/skills1742026年10月21日 更新

3proxy

免费

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.

中文简介正在准备中。当前显示原文说明。

TerminalSkills/skills1742026年10月21日 更新

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.

中文简介正在准备中。当前显示原文说明。

TerminalSkills/skills1742026年10月21日 更新

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.

中文简介正在准备中。当前显示原文说明。

TerminalSkills/skills1742026年10月21日 更新

ably

免费

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.

中文简介正在准备中。当前显示原文说明。

TerminalSkills/skills1742026年10月21日 更新

查看 TerminalSkills 的全部技能

报告此技能的问题