From Language to Live Canvas
A robust, real-time system that translates AI instructions into precise visual diagrams on a Tldraw canvas.
A project by Vedant Bhor
Core Architecture
A clean, decoupled data flow ensures stability and real-time updates from the AI to the user's canvas.
1. AI Instruction
The process starts when an AI model sends a command to the MCP Server.
2. Validation & Sanitization
The server validates the data, corrects errors, and adds missing properties.
3. API & WebSocket
Clean data is sent to the API, which then broadcasts it to all clients in real-time.
Code Deep Dive
Explore the core logic of each key file in the project.
The AI Butler
This is the entry point for all AI instructions. It uses the Model Context Protocol (MCP) to define tools the AI can call. Its primary job is to rigorously validate and sanitize incoming data using Zod schemas before forwarding it to the main application API.
// Simplified mcp-server.ts
import { Server }
from
'@modelcontextprotocol/sdk';
import {
StrictTldrawShapeSchema }
from
'./validation';
server.setRequestHandler('CallTool', async (req) => {
// 1. Receive raw arguments from AI
const rawArgs =
req.params.arguments;
// 2. Validate and sanitize using Zod
const
cleanParams = StrictTldrawShapeSchema.parse(rawArgs);
// 3. Forward clean data to the Next.js API
await
sendToAPI('create',
cleanParams);
});
The Central Hub
This Next.js API route is the backend endpoint that manages the state of the shapes. It receives validated data from the MCP server, performs CRUD operations on the in-memory storage, and then triggers the WebSocket service to notify all connected clients of the change.
// Simplified api/shapes/route.ts
import { shapeStorage,
webSocketService } from
'@/services';
export async function
POST(request: Request) {
// 1. Get validated data from MCP Server
const body =
await
request.json();
// 2. Save the shape to storage
const newShape
=
await
shapeStorage.createShape(body);
// 3. Broadcast the update to all clients
webSocketService.broadcast({
type:
'shape_created',
shape: newShape
});
}
The Frontend Canvas
This React component renders the Tldraw editor. It establishes a WebSocket connection to the backend and listens for messages. When a message like `'shape_created'` is received, it uses the Tldraw editor instance to render the new shape on the user's screen in real-time.
// Simplified TldrawCanvas.tsx
import { useEditor }
from
'tldraw';
useEffect(() => {
// 1. Connect to WebSocket server
const ws =
new WebSocket('ws://...');
// 2. Listen for messages from the server
ws.onmessage = (event) => {
const
data = JSON.parse(event.data);
if
(data.type ===
'shape_created') {
// 3. Render the shape on the canvas
editor.createShapes([data.shape]);
}
};
}, [editor]);
The Data Gatekeeper
This crucial service acts as the final gatekeeper. It converts the generic shape data from the API into the strictly-typed format that the Tldraw library requires. It performs a final round of validation and provides safe default values, ensuring the application never crashes due to malformed data.
// Simplified shape-converter.ts
import type { TLShape }
from
'tldraw';
class ShapeConverterService
{
toTldrawShape(mcpShape: any): TLShape {
// 1. Validate shape type, color, size etc.
const
safeType = validateShapeType(mcpShape.type);
// 2. Sanitize all properties
const
sanitizedProps = sanitizeProps(safeType,
mcpShape.props);
// 3. Return a perfectly-formed shape object
return
{ id: mcpShape.id, ..., props: sanitizedProps };
}
}
Integration & Deployment Strategy
A technical guide for integrating Prompt2Sketch into a production environment like Tldraw.
Create a Private NPM Package
The first step is to isolate the MCP server logic into a self-contained, versioned package. This promotes reusability and clean separation of concerns. This package would be published to a private NPM registry (like GitHub Packages) for secure internal use.
- ✓Establish a monorepo structure (e.g., using Turborepo) to manage the server package and the main Tldraw application.
- ✓Define a clear API for the server package, exposing a `startServer` function that accepts configuration options (e.g., API endpoint URLs).
// packages/mcp-server/package.json
{
"name":
"@tldraw/mcp-server",
"version":
"1.0.0",
"main":
"dist/index.js",
"publishConfig":
{
"registry":
"https://npm.pkg.github.com"
}
}
Run as a Standalone Microservice
The MCP server should run as a separate microservice within Tldraw's existing infrastructure. This decoupled approach ensures that the AI processing load does not impact the performance of the core Tldraw application. The Tldraw backend would then communicate with this service via internal API calls.
Integration Flow
Tldraw Backend → Internal API Call → MCP Service → AI Model
MCP Service → Tldraw Websocket → Client Update
Containerize and Orchestrate
For production, the MCP server microservice should be containerized using Docker. This ensures a consistent and isolated runtime environment. The Docker container can then be deployed and managed using an orchestration platform like Kubernetes or a simpler service like AWS Fargate, fitting seamlessly into a modern cloud-native workflow.
# Dockerfile for the MCP Server
FROM node:18-alpine
WORKDIR
/usr/src/app
# Install dependencies from the package
COPY
packages/mcp-server/package*.json ./
RUN npm install --production
# Copy compiled code
COPY --from=builder
/usr/src/app/packages/mcp-server/dist ./dist
CMD [ "node", "dist/index.js" ]
Enterprise Roadmap
Next steps for enhancing Prompt2Sketch within the Tldraw ecosystem.
Conversational Editing
Enable stateful, conversational interactions. Allow users to make follow-up requests like, "Okay, now make that rectangle blue," or "Connect the server to the database with a dashed arrow."
Deep Tldraw API Integration
Expand the MCP toolset to give the AI programmatic access to all of Tldraw's core features, including pages, camera controls, asset management, and user presence.
Collaborative AI Agent
Develop the AI into a true collaborative partner. It could act as a participant in a multi-user session, suggesting layout improvements, organizing messy diagrams, or adding annotations based on the conversation.