How the HTTP UI Server Renders the 3D Graph Visualization in codebase-memory-mcp

The HTTP UI server serves a React frontend that renders an interactive 3D graph using React-Three-Fiber, while the C-based backend handles static assets and JSON-RPC requests to fetch graph data from a SQLite store.

The codebase-memory-mcp project provides a high-performance interface for exploring code dependencies in three-dimensional space. While the HTTP UI server built in C manages asset delivery and API endpoints, the actual 3D graph visualization is rendered entirely client-side using a React-Three-Fiber scene built on top of three.js.

Architecture Overview

The rendering pipeline operates across three distinct layers that separate data serving from visual presentation:

  • HTTP Server Layer (src/ui/http_server.c): A lightweight C server that binds to localhost, serves embedded static assets (HTML, JavaScript, CSS), and exposes a JSON-RPC endpoint at /rpc.
  • Data Layer: RPC handlers such as handle_repo_info and handle_graph query the SQLite-backed MCP store and return structured GraphData JSON containing nodes, edges, and project metadata.
  • Frontend 3D Scene (graph-ui/src/components/GraphScene.tsx): A React application that consumes the JSON payload and constructs an interactive WebGL visualization using React-Three-Fiber, complete with illuminated edges, glowing nodes, and fly-to camera animations.

HTTP Server Layer: Asset Delivery and JSON-RPC

The server runs in a background pthread via cbm_http_server_run, binding exclusively to 127.0.0.1 for security. It serves content from compiled-in embedded assets defined in ui/embedded_assets.h, mapping routes such as / to index.html and /assets/ to bundled JavaScript and CSS files.

The /rpc endpoint handles all data requests. When the frontend calls POST /rpc, the server parses the JSON-RPC request using yyjson, dispatches the method to an internal cbm_mcp_server_t instance, and returns the result:

/* src/ui/http_server.c – simplified JSON-RPC handling */
static void handle_rpc(cbm_http_conn_t *c, const cbm_http_req_t *req) {
    /* Parse JSON-RPC body, dispatch to MCP server */
    cbm_http_replyf(c, 200, g_cors_json, "%s", json_result);
}

The server enforces a strict Content Security Policy (CBM_UI_CSP) and limited CORS handling to prevent external network access.

Data Layer: Graph JSON API

When the UI requests graph data, RPC methods query the SQLite store (store/cbm_store_*) and construct a GraphData payload containing arrays of nodes and edges. The handle_graph function assembles this response and serializes it to JSON:

/* src/ui/http_server.c – assembling GraphData response */
static void handle_graph(cbm_http_conn_t *c, const cbm_http_req_t *req) {
    /* Query SQLite store for nodes and edges */
    cbm_http_replyf(c, 200, g_cors_json, 
        "{\"nodes\":%s,\"edges\":%s}", nodes_json, edges_json);
}

The frontend receives this payload through a standard fetch call and stores it in React state via the useGraphData hook.

Frontend 3D Rendering with React-Three-Fiber

The visualization layer is implemented in TypeScript and React, using React-Three-Fiber (R3F) to create a declarative three.js scene.

Canvas Setup

GraphScene.tsx initializes the WebGL context through R3F's <Canvas> component, configuring camera parameters and performance settings:

/* graph-ui/src/components/GraphScene.tsx */
<Canvas
  camera={{ position: [0, 0, 800], fov: 50, near: 0.1, far: 100000 }}
  dpr={GRAPH_CANVAS_DPR}
  gl={{ antialias: false, alpha: false, powerPreference: "high-performance" }}
  onPointerMissed={onBackgroundClick}
>

Geometry Generation

EdgeLines.tsx constructs a THREE.BufferGeometry where each edge contributes two vertices with per-vertex colors. Density-aware intensity scaling via edgeIntensityScale ensures visual balance as graph size increases:

/* graph-ui/src/components/EdgeLines.tsx */
const geometry = useMemo(() => {
  const densityScale = edgeIntensityScale(edges.length) * brightness;
  const srcMap = new Map<number, number>();
  nodes.forEach((n, i) => srcMap.set(n.id, i));

  const positions = new Float32Array(edges.length * 6);
  const colors    = new Float32Array(edges.length * 6);
  let validCount = 0;

  edges.forEach(edge => {
    const si = srcMap.get(edge.source);
    const ti = srcMap.get(edge.target);
    if (si === undefined || ti === undefined) return;

    const s = nodes[si];
    const t = (targetNodes ?? nodes)[ti];
    
    const off = validCount * 6;
    positions.set([s.x, s.y, s.z, t.x, t.y, t.z], off);
    
    const col = new THREE.Color(EDGE_TYPE_COLORS[edge.type] ?? DEFAULT_EDGE_COLOR);
    colors.set([col.r * intensity, col.g * intensity, col.b * intensity,
                col.r * intensity, col.g * intensity, col.b * intensity], off);
    validCount++;
  });

  const geo = new THREE.BufferGeometry();
  geo.setAttribute("position", new THREE.BufferAttribute(positions.slice(0, validCount * 6), 3));
  geo.setAttribute("color", new THREE.BufferAttribute(colors.slice(0, validCount * 6), 3));
  return geo;
}, [nodes, edges, highlightedIds, targetNodes, brightness]);

NodeCloud.tsx renders nodes as a THREE.Points cloud, applying a boost factor calculated by nodeBoostScale to maintain visibility across different graph densities.

Camera and Interaction

User navigation combines OrbitControls from @react-three/drei for manual rotation and zoom, with a custom CameraAnimator component that implements smooth "fly-to" transitions when focusing on specific nodes:

/* Smooth fly-to animation within CameraAnimator */
useFrame(() => {
  if (!targetRef.current || progress.current >= 1) return;
  progress.current = Math.min(1, progress.current + 0.02);
  const t = 1 - Math.pow(1 - progress.current, 3);
  camera.position.lerp(targetRef.current.position, t * 0.08);
  controls?.target.lerp(targetRef.current.lookAt, t * 0.08);
});

Post-Processing Effects

An EffectComposer wraps the scene to apply bloom effects via @react-three/postprocessing, creating a soft glow around highlight nodes:

<EffectComposer multisampling={GRAPH_COMPOSER_MULTISAMPLING}>
  <Bloom
    luminanceThreshold={0.3}
    luminanceSmoothing={0.7}
    intensity={bloomIntensity}
    mipmapBlur
    radius={0.6}
  />
</EffectComposer>

The bloom intensity adapts to graph size through bloomIntensityScale, preventing oversaturation in large codebases.

Practical Implementation Examples

Starting the HTTP Server (C)

cbm_http_server_t *srv = cbm_http_server_new(0);   // port 0 lets OS assign free port
cbm_http_server_set_watcher(srv, watcher);
cbm_thread_t tid;
cbm_thread_create(&tid, 0, (void *(*)(void *))cbm_http_server_run, srv);

Fetching Graph Data (React/TypeScript)

// graph-ui/src/hooks/useGraphData.ts
const loadGraph = async (project: string) => {
  const resp = await fetch('/rpc', {
    method: 'POST',
    body: JSON.stringify({ 
      jsonrpc: "2.0", 
      method: "graph.get", 
      params: { project }, 
      id: 1 
    })
  });
  const { result } = await resp.json();
  setGraphData(result);
};

Rendering the Scene (TSX)

<GraphScene
  data={graphData}
  highlightedIds={selectedIds}
  cameraTarget={cameraTarget}
  showLabels={showLabels}
  display={displaySettings}
  onNodeClick={handleNodeClick}
/>

Summary

  • The C-based HTTP UI server (src/ui/http_server.c) serves static assets from embedded memory and handles JSON-RPC requests via the /rpc endpoint using yyjson.
  • Graph data is fetched from a SQLite-backed store and returned as structured JSON containing nodes and edges for the frontend to consume.
  • The React frontend (graph-ui/src/main.tsx) mounts a React-Three-Fiber <Canvas> that renders an interactive WebGL scene.
  • EdgeLines and NodeCloud components generate geometry with density-aware scaling functions (edgeIntensityScale, nodeBoostScale) to maintain visual clarity across different graph sizes.
  • Camera navigation combines OrbitControls with a custom CameraAnimator for smooth, interpolated fly-to transitions.
  • Post-processing bloom effects add visual depth and highlight important nodes using adaptive intensity scaling (bloomIntensityScale).

Frequently Asked Questions

What technology stack renders the 3D graph visualization?

The browser-side rendering uses React-Three-Fiber (R3F), a React renderer for three.js, with post-processing effects provided by @react-three/postprocessing. The backend is implemented in C and serves data via JSON-RPC.

How does the HTTP UI server communicate graph data to the frontend?

The server exposes a /rpc endpoint that accepts JSON-RPC requests. Methods like graph.get query the SQLite store and return a GraphData structure containing nodes and edges, which the frontend fetches using the standard fetch API.

Is the HTTP server accessible from external networks?

No. According to the source code in src/ui/http_server.c, the server binds exclusively to 127.0.0.1 (localhost) and enforces a strict Content Security Policy (CBM_UI_CSP). CORS headers are limited to localhost origins only.

How does the visualization handle large codebases with thousands of nodes?

The implementation uses density-aware scaling functions defined in graph-ui/src/lib/density.ts. These include edgeIntensityScale, nodeBoostScale, and bloomIntensityScale, which automatically reduce visual intensity and adjust geometry density as the graph grows, preventing visual clutter and maintaining performance.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →