Desktop CAD software has been the norm for decades — you buy a license, install a 2GB executable, and edit drawings on a dedicated workstation. That model works, but it creates real friction: version conflicts when files are emailed around, no collaboration, no browser access, and expensive per-seat licensing.
The web has changed nearly every other tool category. It's taken longer with CAD, because the problem is genuinely hard: CAD geometry is complex, files are large and binary, rendering precision matters, and users expect the same commands they've used for 20 years.
This post covers VJCAD — a web-based CAD editor built on TypeScript, WebGL, and WebAssembly — and walks through how to embed it in your own application. It also covers the AI agent integration via MCP, which lets you drive the CAD engine with natural language.
What's in the WebCAD

Before getting into code, here's what the platform actually provides:
Drawing engine: 20+ entity types (Line, Circle, Arc, Polyline, Spline, Text, MText, Insert/Block, Hatch, Dimension, etc.), 80+ commands (COPY, MOVE, ROTATE, SCALE, TRIM, EXTEND, OFFSET, MIRROR…), full Undo/Redo stack, layer management, linetype and lineweight support, TrueType and SHX font rendering.
DWG compatibility: Native read/write of DWG and DXF formats across multiple AutoCAD versions. Layers, blocks, external references, text styles, and linetypes all round-trip correctly. Export back to standard DWG for use in desktop AutoCAD.
Tile editing mode: For very large drawings (city-scale site plans, large infrastructure drawings), the server pre-renders the file into a multi-resolution tile pyramid. The browser loads only the tiles in the current viewport. You then use TILEEDITAREA or TILEEDITLAYER commands to pull down the entity data for just the region or layer you need to edit.
Version control: Branching and patch-based versioning inspired by Git. Each save creates an incremental patch recording added, modified, and deleted entities. Multiple team members can work on branches and merge with conflict detection.
Plugin system: Highly modular architecture. The built-in AI, 3D view, annotation, table extraction, and industry-specific features are all plugins. Developers can write and distribute their own.
AI agent via MCP: Plug the official MCP server into Cursor, Trae, or any MCP-compatible client and drive the CAD engine with natural language instructions.
Getting Started
Requirements
- Node.js 16+
- npm, yarn, or pnpm
- A modern browser with WebGL support
Install
# New project with Vite + TypeScript (recommended)
npm create vite@latest my-webcad-app -- --template vanilla-ts
cd my-webcad-app
npm install vjcad
npm run dev
# Or add to an existing project
npm install vjcad
Minimal Setup
index.html:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>WebCAD App</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
html, body { width: 100%; height: 100%; overflow: hidden; }
#cad-app { width: 100%; height: 100%; }
</style>
</head>
<body>
<div id="cad-app"></div>
<script type="module" src="/src/main.ts"></script>
</body>
</html>
src/main.ts:
import { MainView, initCadContainer } from 'vjcad';
const cadView = new MainView({
appname: "My CAD App",
version: "v1.0.0"
});
initCadContainer("cad-app", cadView);
That's it. initCadContainer mounts the full CAD editor — Ribbon toolbar, command line, canvas, layer panel — into the #cad-app div.
Full Configuration
MainView accepts a configuration object. Here's the complete interface:
import { MainView, initCadContainer } from 'vjcad';
const cadView = new MainView({
// Basic info
appname: "My CAD App",
version: "v1.0.0",
// Backend service (for file operations, tile generation, version control)
serviceUrl: "http://127.0.0.1:27660/api/v1",
accessToken: "your-token",
accessKey: "", // for encrypted drawings
// UI layout
sidebarStyle: "right", // "both" | "left" | "right" | "none"
locale: "en-US", // "en-US" | "zh-CN"
// omit to auto-detect from browser
// Plugin marketplace
pluginMarketUrl: "./plugins/plugins.json",
// Font files (for rendering text entities in DWG)
fonts: [
{ path: "./fonts/simkai.woff", name: "simkai", kind: "woff" },
{ path: "./fonts/_default.shx", name: "_default", kind: "shx" }
]
});
initCadContainer("cad-app", cadView);
Locale auto-detection priority order: URL ?lang= → localStorage → navigator.language → zh-CN.
Drawing Entities Programmatically
Initialization is asynchronous (canvas setup, WASM loading, plugin loading). Always await cadView.onLoad() before doing anything with the engine:
import { MainView, initCadContainer, Engine, LineEnt, CircleEnt, ArcEnt, PolylineEnt, TextEnt } from 'vjcad';
const cadView = new MainView({ appname: "WebCAD", version: "v1.0.0" });
initCadContainer("cad-app", cadView);
await cadView.onLoad();
// Draw a line from (0,0) to (100,100)
// Arrays are shorthand for Point2D objects
const line = new LineEnt([0, 0], [100, 100]);
line.setDefaults();
Engine.addEnt(line);
// Draw a circle: center (50,50), radius 30
const circle = new CircleEnt([50, 50], 30);
circle.setDefaults();
Engine.addEnt(circle);
// Draw an arc: center, radius, start angle, end angle (degrees)
const arc = new ArcEnt([0, 0], 40, 0, 270);
arc.setDefaults();
Engine.addEnt(arc);
// Draw a polyline
const polyline = new PolylineEnt([[0,0], [100,0], [100,100], [0,100]]);
polyline.closed = true;
polyline.setDefaults();
Engine.addEnt(polyline);
// Add single-line text
const text = new TextEnt("Hello WebCAD", [10, 10], 5);
text.setDefaults();
Engine.addEnt(text);
Engine.updateScreen();
Setting Entity Properties
import { Engine, LineEnt, McColor } from 'vjcad';
await cadView.onLoad();
const line = new LineEnt([0, 0], [200, 0]);
line.setDefaults();
// Color: use McColor or a CSS color string
line.color = new McColor(255, 0, 0); // red
// or: line.color = McColor.fromCssColor("#FF0000");
// Layer: assign to an existing layer
line.layer = "WALLS";
// Linetype
line.linetype = "DASHED";
// Lineweight (in mm × 100, e.g. 25 = 0.25mm)
line.lineweight = 25;
Engine.addEnt(line);
Engine.updateScreen();
Getting User Input
The input methods are async and resolve when the user completes the action in the canvas:
import { Engine } from 'vjcad';
await cadView.onLoad();
// Prompt user to pick a point on the canvas
const ptResult = await Engine.getPoint({ prompt: "Pick start point" });
if (ptResult.isOk()) {
const pt = ptResult.val();
console.log(`User picked: ${pt.x}, ${pt.y}`);
}
// Prompt for a selection set (the user draws a selection box or clicks entities)
const ssResult = await Engine.getSelectSet({ prompt: "Select entities" });
if (ssResult.isOk()) {
const ss = ssResult.val();
console.log(`Selected ${ss.count()} entities`);
}
// Prompt for a numeric value
const distResult = await Engine.getReal({ prompt: "Enter distance", default: 100 });
if (distResult.isOk()) {
console.log(`Distance: ${distResult.val()}`);
}
// Prompt with keyword options (like AutoCAD command keywords)
const kwResult = await Engine.getKeywords({
prompt: "Select mode [Rect/Circle/Polygon]",
keywords: "Rect Circle Polygon",
default: "Rect"
});
if (kwResult.isOk()) {
console.log(`User chose: ${kwResult.val()}`);
}
Writing a Custom Command
VJCAD's command system uses the same pattern as AutoCAD: commands are named strings that users type at the command line, and they can prompt for user input mid-execution.
import { Engine, McCommand, LineEnt, McColor } from 'vjcad';
// Register a custom command called "REDLINE"
Engine.addCommand("REDLINE", async () => {
// Ask user for start point
const startResult = await Engine.getPoint({ prompt: "Pick start point" });
if (!startResult.isOk()) return;
// Ask user for end point, showing a rubber-band preview line
const endResult = await Engine.getPoint({
prompt: "Pick end point",
basePoint: startResult.val()
});
if (!endResult.isOk()) return;
// Draw a red line between the two points
const line = new LineEnt(startResult.val(), endResult.val());
line.setDefaults();
line.color = new McColor(255, 0, 0);
Engine.addEnt(line);
Engine.updateScreen();
});
// The user can now type "REDLINE" in the command bar to trigger this
Writing a Plugin
Plugins are the primary extension mechanism. They hook into the Ribbon toolbar, command system, and event lifecycle:
import { PluginBase, Engine, LineEnt } from 'vjcad';
export class MyPlugin extends PluginBase {
// Unique plugin ID
id = "my-plugin";
name = "My Plugin";
// Called when the plugin is loaded
async onLoad() {
// Register commands
Engine.addCommand("MY_DRAW_GRID", () => this.drawGrid());
// Add a Ribbon button
this.addRibbonButton({
tabName: "Tools",
groupName: "My Plugin",
label: "Draw Grid",
icon: "grid",
command: "MY_DRAW_GRID"
});
}
private async drawGrid() {
const spacing = 50;
const count = 10;
for (let i = 0; i <= count; i++) {
// Horizontal lines
const h = new LineEnt([0, i * spacing], [count * spacing, i * spacing]);
h.setDefaults();
Engine.addEnt(h);
// Vertical lines
const v = new LineEnt([i * spacing, 0], [i * spacing, count * spacing]);
v.setDefaults();
Engine.addEnt(v);
}
Engine.updateScreen();
}
}
Register the plugin in your main.ts:
import { MainView, initCadContainer } from 'vjcad';
import { MyPlugin } from './plugins/MyPlugin';
const cadView = new MainView({ appname: "WebCAD", version: "v1.0.0" });
// Register plugins before mounting
cadView.registerPlugin(new MyPlugin());
initCadContainer("cad-app", cadView);
The official plugins use the same API — you can inspect their source code in the GitHub repository as reference.
Version Control (Git-Style for Drawings)
Every save creates a Patch — an incremental record of added, modified, and deleted entities. Patches chain together into a version history, and you can create branches:
main ──●──●──●──────────────● (merge)
\ /
feature ●──●──●──●
Multiple team members work on separate branches. When merging, the system detects conflicts (two people edited the same entity) and offers three resolution strategies: server-priority, local-priority, or manual.
This is managed through the backend service API, and VJCAD's built-in version panel provides a UI for it without any custom code.
AI Agent via MCP
This is the most forward-looking part of the platform. VJCAD exposes an official MCP (Model Context Protocol) server, which you can connect to any MCP-compatible AI client.
Connect Cursor or Trae
Add this to your MCP client configuration:
{
"mcpServers": {
"vjcad": {
"url": "https://vjmap.com/server/aicad/mcp"
}
}
}
Once connected, your AI assistant can read and modify the open drawing through three interaction modes:
Ask — Read-only. The AI queries drawing data, counts entities, extracts layer info, reads attribute values. No modifications. Good for drawing review and reporting.
Agent — Default execution mode. The AI receives an instruction and calls the VJCAD API directly to draw or modify. Good for concrete, well-defined tasks.
Plan — For complex tasks. The AI decomposes the instruction into numbered steps, shows you the plan, then executes step by step. For example, "Draw a floor plan":
- Create layers (WALLS, DOORS, WINDOWS, DIMS)
- Draw outer wall perimeter
- Draw interior walls
- Insert door/window blocks
- Add dimension annotations
What you can ask it to do
The AI's capability depends on what "skills" (system prompts + API docs) are loaded. With the base SDK skill:
- "Draw a 10×10 grid with 50mm spacing."
- "Change all red lines to blue dashed lines."
- "Add a text label 'Entry' at coordinate (200, 100), height 5mm."
- "Select all entities on the DIMENSIONS layer and delete them."
With a domain-specific skill (e.g., floor plan rules), you can go further:
- "Draw a 3-bedroom apartment, approximately 120 sq meters."
The AI generates and executes the API calls. Non-CAD users can accomplish tasks that would otherwise require hours of manual work by someone with CAD training.
Build your own skill
The skill mechanism is open. You write a skill as a structured prompt that teaches the AI your domain rules and the relevant API methods. This is how you build a vertical industry platform on top of VJCAD:
- Electrical schematic rules → electrical diagram CAD tool
- Pipe network topology → utility/infrastructure CAD tool
- Structural detailing standards → structural engineering CAD tool
The platform provides the engine; you bring the domain knowledge.
Source Code and Resources
The example source code (HTML, Vue, and React scaffolds) is available on both GitHub and Gitee:
- GitHub: github.com/vjmap/vjmap-webcad
- Gitee: gitee.com/vjmap/webcad
Other links:
- 🖥️ Live WebCAD Editor
- 🎮 100+ Live Examples
- 📖 Developer Documentation (EN)
- 📦 npm: vjcad
- 📧 Contact: vjmapcom@163.com

Top comments (0)