{"slug": "build-a-real-time-excalidraw-like-collaborative-canvas-using-velt-mcp-and", "title": "Build a Real-Time Excalidraw-like Collaborative Canvas using Velt MCP and Antigravity🎉", "summary": "Explaining how to build a real-time collaborative whiteboard, similar to Excalidraw, using Next.js, HTML5 Canvas, and the Velt collaboration SDK. It details using Velt's MCP (Model Context Protocol) and AI agents to automate the integration of features like live cursors, comments, and CRDT-based synchronization, allowing developers to add multi-user functionality without building backend infrastructure. The guide walks through setting up the project, configuring Velt with an API key, and using an AI agent within an editor to analyze the codebase and implement the collaboration features.", "body_md": "In this tutorial, we’ll build an Excalidraw-style collaborative whiteboard using Next.js, HTML5 Canvas, and Velt. You’ll add real-time features like live cursors, comments, presence, and huddles directly into your app. Instead of wiring everything manually, we’ll use Velt MCP and AI agents to handle the integration. We’ll also look at how CRDT-based sync keeps everything in real time.\n\nBy the end, you’ll have a fully working multi-user canvas app with production-ready collaboration built in.\n\n## What we are building\n\n- Excalidraw-style infinite whiteboard\n- Real-time collaboration with cursors, comments, huddle, notifications, and presence\n- Multi-user canvas with shared state\n\n## Why add collaboration to Canvas apps\n\n-\n**Single-user by default:** Most canvas apps work locally and don’t support multiple users out of the box -**Real-time sync is complex:** Handling state sync, conflicts, and updates across users is not trivial -**Lack of shared context:** Without comments, cursors, and presence, collaboration feels disconnected\n\n## Why use Velt\n\n[Velt is a collaboration SDK](https://velt.dev/) that lets you add real-time, multi-user features directly into your app without building the backend infrastructure yourself. It handles presence, syncing, communication, and UI components out of the box, so you can focus on your product.\n\n-**Drop-in collaboration layer:** Add features like comments, cursors, and presence without building from scratch -**Real-time features built in:** Cursors, comments, presence, notifications, and huddles -**CRDT-based sync support:** Enables conflict-free real-time state updates for multi-user apps -**AI-powered setup with MCP:** Use Velt MCP and agent skills to automatically install and configure features -**No infra needed:** No need to manage WebSockets, sync engines, or backend services -**Customizable UI components:** Easily integrate collaboration UI into your existing design system\n\n## Prerequisites\n\n- Node.js 18+\n- Velt API key (from Velt dashboard)\n- AI coding editor (Anitgravity is used in this demo)\n- Basic React and TypeScript knowledge**Setting up the project**- Clone the repository -\n[https://github.com/Studio1HQ/Velt-Demos/tree/main/excalidraw-velt-demo](https://github.com/Studio1HQ/Velt-Demos/tree/main/excalidraw-velt-demo) - Run\n`npm install`\n\n- And then run\n`npm run dev`\n\n- Now, open\n[http://localhost:3000](http://localhost:3000/)\n\n## Tutorial: Building Velt-powered Excalidraw-like App\n\n### Step 1: Set up Velt MCP\n\nVelt MCP lets your editor (Antigravity) run the Velt installer and guide the integration.\n\nNow, add the Velt MCP installer to Antigravity using the command below:\n\n```\nnpx -y @velt-js/mcp-installer\n```\n\nAdd it to the Antigravity MCP server configuration with** command: \"npx\"**and**.**`args: [\"-y\", \"@velt-js/mcp-installer\"]`\n\nAlso, [Velt Agent Skills](https://docs.velt.dev/get-started/skills) guides the AI on what to implement using best practices, while MCP gives it access to the tools needed to actually execute those changes. Together, they make the integration accurate, structured, and reliable. We have both installed and will be used accordingly.**Get your Velt API key**:\n\n- Go to the Velt Dashboard\n- Create a project\n- Copy your API key\n\nAdd it to your `.env`\n\n:\n\n```\nNEXT_PUBLIC_VELT_API_KEY=your_api_key_here\n```\n\n### Step 2: Start Velt installation using AI\n\nNow that MCP is set up, we can let the AI agent handle the Velt integration for us.\n\nOpen your editor (Antigravity) and type:\n\n```\ninstall velt\n```\n\nThis triggers the Velt MCP installer, which runs as a guided setup inside your editor.\n\nInstead of manually adding SDKs and wiring things, the agent walks you through the setup step by step.\n\nIt will ask you for a few inputs:\n\n- Your**project directory**- Your** Velt API key and auth token**- The** features you want to enable**(comments, presence, cursors, CRDT, etc.) - Where to place the** VeltProvider**(recommended:`app/page.tsx`\n\n) - UI placement preferences (like corner position)\n\nYou can answer each step directly in chat. The flow is simple and guided.\n\n### Step 3: Provide the prompt for MCP\n\nAt this point, we already have a working whiteboard built manually. Now, instead of integrating Velt step by step ourselves, we use Velt Agent Skills to analyze this existing app and plan how collaboration should be added.\n\nIn your editor, after running `install velt`\n\n, provide the following prompt:\n\nI want to start the Velt integration. Review my project structure and use your Velt Agent Skills to plan the CRDT store implementation.\n\nOnce you provide this, the agent starts analyzing your codebase. It looks at how your canvas is structured, how state is managed, and where real-time sync can be introduced. Based on this, it generates an integration plan tailored to your whiteboard.\n\nInstead of manually deciding how to structure CRDT or where to wire Velt, the agent uses its skills to plan it correctly for your app.\n\nAfter reviewing the plan, you can approve it, and the agent will apply the changes step by step.\n\n### Step 4: Understand the existing project structure\n\nBefore we look at what MCP added, let us understand how this project is structured. Since the agent analyzes your codebase before integrating Velt, this gives context for what it is working with.\n\nThe [project is organized into three main folders](https://github.com/Studio1HQ/Velt-Demos/tree/main/excalidraw-velt-demo): `app`\n\n, `components`\n\n, and `lib`\n\n.\n\n- The\n`app/`\n\nfolder contains the core application logic. This is where the whiteboard is rendered and all canvas interactions like drawing, selecting, and updating elements are handled. - The\n`components/`\n\nfolder contains UI elements and collaboration integrations. This is where Velt features are connected to your app, including user identity, comments, and UI-level controls. - The\n`lib/`\n\nfolder handles state management and shared logic. It manages canvas data, document context, and sync-ready state, making it easier to extend the app with real-time collaboration.\n\n### Step 5: Add real-time collaboration features (Using MCP)\n\nNow that the whiteboard is working, we layer Velt on top to make it collaborative. This is where users start seeing each other, interacting in real time, and sharing context.\n\nAfter you provide the prompt and approve the plan, the MCP installer integrates Velt into your project. It sets up the foundation required for collaboration to work correctly with your existing whiteboard.\n\n### Presence and cursors\n\nIn [ app/layout.tsx](https://github.com/Studio1HQ/Velt-Demos/blob/main/excalidraw-velt-demo/app/layout.tsx), the\n\n`VeltProvider`\n\nenables real-time awareness across your app. Then in `VeltSetup.tsx`\n\n, each user is identified using. This is what allows Velt to track who is online.Learn more [here](https://docs.velt.dev/realtime-collaboration/presence/overview)\n\n``` python\n'use client'\nimport React, { useEffect, useState, Suspense } from \"react\";\nimport {\n  VeltProvider,\n  useSetDocument,\n  VeltCursor,\n  useVeltClient,\n} from \"@veltdev/react\";\nimport { useCurrentDocument } from \"@/lib/useCurrentDocument\";\nimport { TEST_USERS } from \"@/lib/users\";\nimport { useSearchParams } from \"next/navigation\";\n\nfunction VeltIdentity({ children }: { children: React.ReactNode }) {\n  const { documentId } = useCurrentDocument();\n  useSetDocument(documentId ?? \"default-whiteboard\");\n  return <>{children}</>;\n}\n\nfunction VeltProviderInner({ children }: { children: React.ReactNode }) {\n  const searchParams = useSearchParams();\n  const [user, setUser] = useState(TEST_USERS[0]);\n\n  useEffect(() => {\n    const userIndex = searchParams.get(\"user\");\n    if (userIndex) {\n      const index = parseInt(userIndex);\n      if (!isNaN(index) && TEST_USERS[index]) {\n        setUser(TEST_USERS[index]);\n      }\n    } else {\n      // Fallback or default behavior\n    }\n  }, [searchParams]);\n\n  return (\n    <VeltProvider\n      apiKey={process.env.NEXT_PUBLIC_VELT_API_KEY!}\n      authProvider={{\n        user: user,\n      }}\n    >\n      <VeltIdentity>\n        {/* <VeltCursor /> */}\n        {children}\n      </VeltIdentity>\n    </VeltProvider>\n  );\n}\n\nexport function VeltSetup({ children }: { children: React.ReactNode }) {\n  return (\n    <Suspense fallback={null}>\n      <VeltProviderInner>{children}</VeltProviderInner>\n    </Suspense>\n  );\n}\n```\n\nOnce identity is set, Velt automatically shows:\n\n- Active users (avatars)\n- Live cursor positions\n\nYou don’t have to manually sync cursor movement. Velt handles that internally based on user sessions.\n\n### Canvas comments\n\n[Comments](https://docs.velt.dev/async-collaboration/comments/overview) are one of the most important parts of a canvas app.\n\n``` js\n\"use client\";\n\nimport { useCommentAnnotations, VeltCommentPin } from \"@veltdev/react\";\nimport { Point } from \"@/lib/types\";\nimport { useWhiteboardStore } from \"@/lib/useWhiteboardStore\";\n\ninterface CanvasCommentLayerProps {\n  zoom: number;\n  pan: Point;\n}\n```\n\nIn [ CanvasCommentLayer.tsx](https://github.com/Studio1HQ/Velt-Demos/blob/main/excalidraw-velt-demo/components/velt/CanvasCommentLayer.tsx), comments are rendered as an overlay on top of the canvas. Instead of attaching comments to DOM elements, we attach them to canvas coordinates.\n\n```\n {\n              // Use bounds or specific fields\n              // Normalized rect provided by normalizeRect helper? not available here easily.\n              // Just use raw coords if available, or approximate.\n              // Rect/Ellipse/Diamond have x1,y1,x2,y2 usually?\n              // Wait, types.ts says DrawingElement...\n              // Let's assume standard shape properties\n              if (\n                \"x1\" in element &&\n                \"y1\" in element &&\n                \"x2\" in element &&\n                \"y2\" in element\n              ) {\n                worldX = (element.x1 + element.x2) / 2;\n                worldY = (element.y1 + element.y2) / 2;\n              }\n            } else if (element.type === \"line\" || element.type === \"arrow\") {\n              worldX = (element.x1 + element.x2) / 2;\n              worldY = (element.y1 + element.y2) / 2;\n            }\n          }\n        }\n\n        if (typeof worldX !== \"number\" || typeof worldY !== \"number\") {\n          return null;\n        }\n\n        const screenX = (worldX + pan.x) * zoom;\n        const screenY = (worldY + pan.y) * zoom;\n\n        return (\n          <div\n            key={annotation.annotationId}\n            style={{\n              position: \"absolute\",\n              left: `${screenX}px`,\n              top: `${screenY}px`,\n              transform: \"translate(-50%, -100%)\",\n              zIndex: 50,\n              pointerEvents: \"auto\",\n            }}\n          >\n            <VeltCommentPin annotationId={annotation.annotationId} />\n          </div>\n        );\n      })}\n    </div>\n  );\n```\n\nFrom `app[/page.tsx](https://github.com/Studio1HQ/Velt-Demos/blob/main/excalidraw-velt-demo/app/page.tsx)`\n\n, you trigger comments like this:\n\n- Capture the\n`(x, y)`\n\nposition on click - Pass context to Velt\n- Optionally attach to a specific element using\n`elementId`\n\nThis enables:\n\n- Freeform comments anywhere on the canvas\n- Context-aware discussions linked to shapes\n\nThis is very similar to how tools like Miro or Figma handle comments.\n\n### Sidebar and UI controls\n\nThese files handle user-facing UI around collaboration.\n\n-\n`ProfileMenu.tsx`\n\nshows user identity and active participants -\n`ThemeToggle.tsx`\n\nsyncs your app theme with Velt UI\n\n`ProfileMenu.tsx`\n\n``` python\n\"use client\";\n\nimport React, { useEffect, useState } from \"react\";\nimport { ChevronDown, User, Check, LogOut, RefreshCwIcon } from \"lucide-react\";\n// import { useVeltClient } from \"@veltdev/react\";\nimport { TEST_USERS } from \"@/lib/users\";\n\nexport function ProfileMenu() {\n  const [isOpen, setIsOpen] = useState(false);\n  const [currentUser, setCurrentUser] = useState(TEST_USERS[0]); // Default to first user\n\n  // Initialize from URL on mount\n  useEffect(() => {\n    const params = new ", "url": "https://wpnews.pro/news/build-a-real-time-excalidraw-like-collaborative-canvas-using-velt-mcp-and", "canonical_source": "https://dev.to/studio1hq/build-a-real-time-excalidraw-like-collaborative-canvas-using-velt-mcp-and-antigravity-j3f", "published_at": "2026-05-21 16:43:40+00:00", "updated_at": "2026-05-21 17:03:51.457718+00:00", "lang": "en", "topics": ["developer-tools", "products", "startups"], "entities": ["Velt", "Next.js", "HTML5 Canvas", "Antigravity", "Velt MCP", "CRDT"], "alternates": {"html": "https://wpnews.pro/news/build-a-real-time-excalidraw-like-collaborative-canvas-using-velt-mcp-and", "markdown": "https://wpnews.pro/news/build-a-real-time-excalidraw-like-collaborative-canvas-using-velt-mcp-and.md", "text": "https://wpnews.pro/news/build-a-real-time-excalidraw-like-collaborative-canvas-using-velt-mcp-and.txt", "jsonld": "https://wpnews.pro/news/build-a-real-time-excalidraw-like-collaborative-canvas-using-velt-mcp-and.jsonld"}}