构建一个实时 tldraw 白板,带 Velt Comments,嵌入 ChatGPT 🤯🔥

发布: (2025年12月11日 GMT+8 02:58)
7 min read
原文: Dev.to

Source: Dev.to

我们要构建的内容

我们正在构建一个可以通过 ChatGPT 控制的协作白板。你可以让 ChatGPT 添加形状、放置便利贴或更改布局,白板会即时更新。你的团队成员可以加入白板,实时看到变化,并直接在画布上留下评论。

我们将使用 TLDraw 作为画布,Velt 负责实时协作,并使用 Model Context Protocol (MCP) 将所有内容连接到 ChatGPT。完成后,你将拥有一个可在 ChatGPT 内部运行、能够响应自然语言的功能性白板应用。

理解基础

一个 GPT 应用由两部分组成:

  1. Web 小部件 – 在 ChatGPT 内渲染的 UI(我们的白板画布)。
  2. MCP 服务器 – 一个 Node.js 服务,定义 ChatGPT 可以调用的工具(例如 “添加矩形”)。

当你说 “画一个矩形” 时,ChatGPT 读取工具定义,调用你的 MCP 服务器,服务器随后更新画布。

chatgpt UI

TLDraw

  • 负责画布、绘图工具、形状、文字。
  • 通过 @tldraw/sync 提供实时白板同步——同一房间的所有人都会即时看到更新。

Velt

  • 提供协作功能:评论、实时光标、在场指示器。
  • 通过前端的 React 组件和后端的 REST API 工作。

这两个库负责构建 UI;MCP 服务器则将 UI 与 ChatGPT 连接。

MCP 服务器

MCP 服务器是一个 Node.js 应用,定义 ChatGPT 可以调用的工具。每个工具包括名称、描述以及描述必需参数的 inputSchema

const tools = [
  {
    name: "add-item",
    description: "Add an item to the list",
    inputSchema: {
      type: "object",
      properties: {
        text: {
          type: "string",
          description: "The item text"
        },
        priority: {
          type: "string",
          enum: ["low", "medium", "high"],
          description: "Item priority"
        }
      },
      required: ["text"]
    }
  }
];

description 用来指导 ChatGPT 何时使用该工具,而 inputSchema 则告诉它需要发送哪些数据。

前置条件

服务需要的内容
VeltAPI 密钥和 Auth Token(用于处理评论与协作)
TLDraw许可证密钥(白板画布必需)
ngrok将本地服务器暴露给 ChatGPT
ChatGPT Plus必须使用自定义应用

设置

git clone https://github.com/Studio1HQ/velt-app-examples
cd velt-app-examples
pnpm install

cd syncboard_server
pnpm install
cd ..

Chrome 142+ 用户: 禁用 local‑network‑access‑check 标志。

  1. 打开 chrome://flags/
  2. 搜索 local-network-access-check
  3. 设置为 Disabled 并重启 Chrome。

构建白板

项目分为前端(小部件)和后端(MCP 服务器)两部分。

src/syncboard/          # 前端白板
├── syncboard.jsx       # 画布和 Velt 组件
├── mockUsers.js        # 测试用户(Bob & Alice)
└── index.jsx           # 入口文件

syncboard_server/       # 后端 MCP 服务器
└── src/
    ├── server.ts       # 工具定义
    └── velt/           # 评论处理器

设置 TLDraw

编辑 src/syncboard/syncboard.jsx,添加基础 TLDraw 画布:

import { Tldraw } from 'tldraw';
import { useSyncDemo } from '@tldraw/sync';
import 'tldraw/tldraw.css';

function SyncboardCanvas() {
  const store = useSyncDemo({
    roomId: import.meta.env.VITE_TLDRAW_ROOM_ID // e.g., "my-room-abc"
  });

  return <Tldraw store={store} />;
}

useSyncDemo 会创建一个与指定 roomId 关联的同步 store。该房间的所有参与者共享同一个画布状态。

添加 Velt

将 TLDraw 画布包裹在 Velt 的 provider 中,并加入协作组件。

// syncboard.jsx
import {
  VeltProvider,
  useVeltClient,
  VeltComments,
  VeltPresence,
  VeltCursor,
  VeltCommentTool,
  VeltSidebarButton
} from '@veltdev/react';
import { Tldraw } from 'tldraw';
import { useSyncDemo } from '@tldraw/sync';
import 'tldraw/tldraw.css';
import { useEffect, useState } from 'react';

function SyncboardCanvas() {
  const store = useSyncDemo({
    roomId: import.meta.env.VITE_TLDRAW_ROOM_ID
  });

  const { client } = useVeltClient();
  const [veltReady, setVeltReady] = useState(false);

  // 初始化 Velt 客户端
  useEffect(() => {
    const init = async () => {
      if (!client || veltReady) return;

      await client.identify(currentUser, { forceReset: true });
      await client.setDocument('syncboard-whiteboard', {
        documentName: 'Syncboard Collaborative Whiteboard'
      });

      setVeltReady(true);
    };
    init();
  }, [client, veltReady]);

  return (
    <>
      {/* 顶部栏,放置协作控制 */}
      {veltReady && <VeltSidebarButton />}
      {veltReady && <VeltCommentTool />}

      {/* 主画布 */}
      <Tldraw store={store} />

      {/* Velt 覆盖层 */}
      {veltReady && (
        <>
          <VeltComments />
          <VeltPresence />
          <VeltCursor />
        </>
      )}
    </>
  );
}

export default function Syncboard() {
  return (
    <VeltProvider>
      <SyncboardCanvas />
    </VeltProvider>
  );
}

Velt 组件在 TLDraw 画布之上添加评论线程、在场指示器和实时光标。

MCP 服务器(后端)

syncboard_server/src/server.ts 中创建 MCP 服务器。下面是一个最小示例,定义了向白板添加矩形的工具。

import { createMcpServer } from '@openai/mcp';
import { addRectangle } from './velt/rectangleHandler'; // your custom logic

const tools = [
  {
    name: "add-rectangle",
    description: "Add a rectangle shape to the whiteboard",
    inputSchema: {
      type: "object",
      properties: {
        width: { type: "number", description: "Width of the rectangle" },
        height: { type: "number", description: "Height of the rectangle" },
        color: { type: "string", description: "Fill color (hex)" }
      },
      required: ["width", "height"]
    }
  }
];

const server = createMcpServer({
  tools,
  handler: async (toolName, params) => {
    if (toolName === "add-rectangle") {
      await addRectangle(params);
    }
    // Add more tool handlers as needed
  }
});

server.listen(3000, () => console.log("MCP server listening on port 3000"));

addRectangle 应当通过 Velt 的 REST API 或 SDK 与文档交互,在 TLDraw store 中插入矩形形状。

使用 ngrok 将服务器暴露出来,以便 ChatGPT 能访问:

ngrok http 3000

复制生成的 HTTPS URL,并在 ChatGPT 应用设置中将其配置为 MCP 端点。

运行应用

  1. 启动前端(小部件)——通常使用 Vite 或你喜欢的开发服务器。
  2. 启动 MCP 服务器node syncboard_server/src/server.ts)。
  3. 使用 ngrok 暴露服务器
  4. 在 ChatGPT 中添加一个新的自定义应用,并指向 ngrok URL。
  5. 开始交互!尝试以下提示:
    • “画一个蓝色矩形,宽 200 px,高 100 px。”
    • “添加一个写着 ‘Sprint goals’ 的便利贴。”

ChatGPT 将调用相应的工具,MCP 服务器更新 Velt 文档,变化会即时出现在共享白板上。

Back to Blog

相关文章

阅读更多 »