Engineering Journal
Schema Editor
Schema Editor

No Framework, No Problem: Building a High-Performance CAD Engine with Vanilla JS

2026-05-11

TLDR

Interactive CAD applications (handling thousands of SVG elements, real-time Manhattan wire routing, and $O(\log N)$ spatial queries) suffer severe frame drops when built on reactive virtual DOM frameworks (React, Vue). The GINEXYS Schema Editor achieves a stable 60fps performance profile under 100KB gzipped by utilizing zero dependencies: direct SVG DOM attribute mutations, KD-tree spatial indexing, and a 4-phase geometry pipeline.
Architecture ChoiceVirtual DOM FrameworksPure Vanilla JS CAD Engine
State ReconciliationVDOM diffing overhead per frameDirect SVG DOM attribute mutation (x, y, d)
Spatial Hit Testing$O(N)$ full array iterations$O(\log N)$ KD-Tree spatial index queries
Bundle Footprint200KB to 500KB framework overhead< 100KB Gzipped (Zero dependencies)

Problem statement: the VDOM re-render overhead in CAD applications

Modern frontend web frameworks excel at standard CRUD user interfaces. However, they impose a severe performance penalty on interactive CAD engines.

In a diagram editor, dragging a component requires:

  1. Updating element position transforms.
  2. Recalculating connected orthogonal wire paths in real time.
  3. Updating selection handles and alignment guide overlays.
Executing these updates through virtual DOM reconciliation or reactive dependency graphs adds several milliseconds of latency per frame, causing noticeable stutter on complex diagrams.


Technical failure mode: $O(N)$ hit testing in large schematics

When a user moves their mouse over a canvas containing 2,000 components and wires, determining which element or pin lies beneath the cursor via array iteration ($O(N)$) freezes the UI thread.

In a framework environment where hit tests trigger reactive state changes, every mouse move stalls the main render loop.


The fix & architecture: direct mutations, KD-trees & geometry pipelines

1. Direct SVG DOM attribute mutation

During active mouse drag operations, update target SVG element attributes (x, y, d) directly inside the mousemove event handler, bypassing reactive state loops:
// Direct DOM mutation for 60fps dragging
function onDragMove(e) {
  const worldPos = screenToWorld(e.clientX, e.clientY);
  targetSvgElement.setAttribute('transform', translate(${worldPos.x}, ${worldPos.y}));
  updateConnectedWiresDirectly(targetSvgElement, worldPos);
}

2. $O(\log N)$ KD-tree spatial indexing

To make spatial queries instantaneous, build a KD-tree index over all canvas element bounding boxes, reducing hit-test queries from $O(N)$ to $O(\log N)$:
// Spatial Query using KD-Tree Index
const candidateElements = spatialKdTree.queryPoint(worldCursorPos, hitRadius);
const hoveredElement = findExactHit(candidateElements, worldCursorPos);

3. 4-Phase geometry pipeline

Separate canvas calculations into discrete, non-DOM phases before applying changes:
  1. Raw Input Capture: Screen coordinates to world space transformation.
  2. Snap & Constraint Pass: Axis-independent snapping and grid alignment.
  3. Routing & Layout Pass: Orthogonal Manhattan pathfinding calculation.
  4. DOM Paint Pass: Direct SVG attribute application.
Rule of thumb: Eliminate virtual DOM reconciliation when building high-density canvas editors. Mutate SVG attributes directly during interactive drag events and use $O(\log N)$ spatial indexing for hit testing.
Read this post in the full Engineering Journal →