ChatGPT 안에서 Velt 댓글이 포함된 실시간 tldraw 화이트보드 만들기🤯🔥
Source: Dev.to
우리가 만들고 있는 것
우리는 ChatGPT로 제어할 수 있는 협업 화이트보드를 만들고 있습니다. ChatGPT에게 도형을 추가하거나, 스티키 노트를 붙이거나, 레이아웃을 변경하라고 말하면 보드가 즉시 업데이트됩니다. 팀원들은 보드에 참여해 실시간으로 변화를 확인하고 캔버스에 직접 댓글을 남길 수 있습니다.
우리는 TLDraw 를 캔버스로, Velt 를 실시간 협업을 위해, 그리고 Model Context Protocol (MCP) 을 사용해 모든 것을 ChatGPT와 연결합니다. 최종적으로 ChatGPT 안에서 동작하고 자연어에 반응하는 실용적인 화이트보드 앱을 얻게 됩니다.
기본 이해
GPT 앱은 두 부분으로 구성됩니다:
- Web 위젯 – ChatGPT 안에 렌더링되는 UI(우리의 화이트보드 캔버스).
- MCP 서버 – ChatGPT가 호출할 수 있는 도구들을 정의하는 Node.js 서비스(예: “사각형 추가”).
“사각형을 그려줘” 라고 말하면 ChatGPT가 도구 정의를 읽고 MCP 서버를 호출하며, 서버는 캔버스를 업데이트합니다.

TLDraw
- 캔버스, 그리기 도구, 도형, 텍스트를 담당합니다.
@tldraw/sync를 통해 실시간 보드 동기화를 제공 – 같은 방에 있는 모든 사용자가 즉시 업데이트를 봅니다.
Velt
- 협업 기능을 제공합니다: 댓글, 실시간 커서, 존재 표시기.
- 프론트엔드에서는 React 컴포넌트로, 백엔드에서는 REST API로 동작합니다.
이 두 라이브러리가 UI를 만들고, MCP 서버가 UI와 ChatGPT를 연결합니다.
MCP 서버
MCP 서버는 ChatGPT가 호출할 수 있는 도구들을 정의하는 Node.js 앱입니다. 각 도구는 이름, 설명, 그리고 필요한 매개변수를 기술한 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 는 어떤 데이터를 보내야 하는지 알려줍니다.
사전 준비 사항
| 서비스 | 필요 사항 |
|---|---|
| Velt | API 키와 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 플래그를 비활성화하세요.
chrome://flags/열기local-network-access-check검색- 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 에 연결된 동기화 스토어를 생성합니다. 해당 방에 있는 모든 참가자는 동일한 캔버스 상태를 공유합니다.
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);
// Initialize Velt client
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 (
<>
{/* Top bar with collaboration controls */}
{veltReady && <VeltSidebarButton />}
{veltReady && <VeltCommentTool />}
{/* Main canvas */}
<Tldraw store={store} />
{/* Velt overlays */}
{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 스토어에 사각형 도형을 삽입하도록 구현해야 합니다.
ngrok 으로 서버를 외부에 노출해 ChatGPT가 접근할 수 있게 합니다:
ngrok http 3000
생성된 HTTPS URL을 복사하고 ChatGPT 앱 설정에서 MCP 엔드포인트로 지정합니다.
앱 실행하기
- 프론트엔드(위젯) 시작 – 보통 Vite 혹은 선호하는 개발 서버를 사용합니다.
- MCP 서버 시작 (
node syncboard_server/src/server.ts). - ngrok 으로 서버를 노출합니다.
- ChatGPT에서 새 커스텀 앱을 추가하고 ngrok URL을 지정합니다.
- 상호작용해 보세요! 예시 프롬프트:
- “파란색 사각형을 가로 200 px, 세로 100 px 로 그려줘.”
- “‘Sprint goals’ 라는 스티키 노트를 추가해줘.”
ChatGPT가 해당 도구를 호출하면 MCP 서버가 Velt 문서를 업데이트하고, 변경 사항이 공유 화이트보드에 즉시 반영됩니다.