A web application that visualizes C++ data structures with real-time animations. It compiles and executes real C++ code via a backend g++ compiler, traces actual memory operations at runtime using GDB MI, and renders step-by-step animated visualizations.
C++ Code --> g++ Compile --> GDB MI Session --> Line-by-line Snapshots --> gdbMapper --> TraceStep[] --> Visualization
(-g -O0) (--interpreter=mi2) (locals + struct fields) (ALLOC/SET_PTR/ (React + Framer Motion)
SET_FIELD/LOCAL_VAR)
- User writes C++ code with custom structs / pointers
- Backend compiles code with debug symbols (
g++ -g -O0) - GDB runs the binary line-by-line in MI mode, capturing local variables and struct field values at every step
gdbMapperconverts raw GDB snapshots intoTraceStep[]events (ALLOC, SET_PTR, SET_FIELD, LOCAL_VAR)- Runtime pattern analysis builds a pointer graph and detects data structure types by analyzing actual graph topology (out-degree, cycles, depth)
- Frontend replays commands as animated visualizations
C++ Code --> AI Analysis --> Instrumenter --> g++ Compile --> Execute --> Trace Output --> Runtime Analysis --> Visualization
(Groq LLM) (inject trace (real binary) (real run) (__TRACE__ JSON) (graph topology) (React + Framer Motion)
struct hints calls)
- Groq AI (optional) pre-analyzes struct definitions and provides classification hints
- Backend instrumenter injects trace calls (
__vt::alloc,__vt::set_ptr, etc.) using AI hints - Code is compiled and executed with g++ (C++17)
- Runtime trace output is parsed into step-by-step commands
- Real C++ Execution: Compiles and runs actual C++ code via g++ backend. No simulation or pseudo-code parsing.
- GDB-Powered Tracing: Uses GDB Machine Interface (MI) to step through code line by line and capture exact memory state — no source code transformation needed.
- AI-Assisted Classification (fallback mode): Optional Groq AI (free tier) pre-analyzes struct definitions to handle ambiguous field names and non-standard patterns.
- Smart Auto-Detection: Three-layer detection system:
- AI analysis: Groq LLM classifies struct types before instrumentation (if
GROQ_API_KEYis set, fallback mode only) - Static analysis: Method names (
push/pop= Stack) and self-type pointer counts (2+ = Tree, 1 = Linked List) - Runtime analysis: Builds actual pointer graph from execution traces and reclassifies based on graph topology (branching, cycles, depth)
- AI analysis: Groq LLM classifies struct types before instrumentation (if
- Memory Graph Visualization: Traces pointers (
->), allocations (new), and deallocations (delete) to draw memory relationships. - Step-by-Step Execution: Run / Pause / Step / Prev controls with precise state tracking.
- Adjustable Speed: Playback speed control from 0.25x to 4x.
- Resizable Panels: Editor, visualizer, and terminal panels are all draggable.
- Interactive Views: Drag-to-pan and Ctrl+Scroll zoom in visualization boxes.
- C++ Autocomplete: IDE-style code completion for C++ keywords, types, and STL containers.
- Terminal Output: Real-time
coutoutput display with stdin input support.
| Data Structure | Color | Detection Method | Visualization |
|---|---|---|---|
| Stack | Purple | push() + pop() methods, or std::stack/vector |
Vertical plate stacking with TOP indicator |
| Queue | Cyan | enqueue() + dequeue() methods, or std::queue/deque/priority_queue |
Horizontal conveyor belt with FRONT/BACK labels |
| Tree (BST / N-ary) | Green | 2+ self-type pointers OR runtime branching pattern (parent pointers tolerated) | Hierarchical bucket layout with ROOT badge, drag-to-pan |
| Linked List | Purple | 1 self-type pointer, linear chain | Graph view with arrow connections |
| Doubly Linked List | Cyan / Amber | Linear chain with bidirectional next/prev pairs |
Horizontal chain — solid cyan next arrows + dashed amber prev arrows |
| Circular Linked List | Amber | Runtime cycle detection (single outgoing pointer with loop) | Polygon layout with HEAD badge, amber dashed cycle-back edge |
| General Graph | Rose | Branching + cycle that survives back-edge stripping | Graph view with all edges |
| Memory (Heap) | Purple | Fallback for pointer structures | Graph view with memory addresses |
Static Hint (compile-time) Runtime Analysis (post-execution, GDB mode)
push/pop methods → Stack (already classified)
enqueue/dequeue → Queue (already classified)
std::stack/vector → Stack (instrumenter + GDB modes)
std::queue/deque/priority_queue → Queue
┌─ strip bidirectional pairs from one field ─┐
│ (the "back-edge" / prev / parent field) │
└─────────────────┬──────────────────────────┘
▼
primary graph cyclic + branching → Graph
primary graph cyclic + max-out-deg ≤ 1 → Circular Linked List
primary graph acyclic + branching → Tree
primary graph acyclic + back-edges → Doubly Linked List
primary graph acyclic + chain → Linked List
Field names don't matter: left/right, a/b, child1/child2, ptr1/ptr2, next/prev, child/parent — the system detects structure from actual runtime pointer topology.
Supported C++ patterns: struct, class, private/public/protected, friend class, constructors with initializer lists, const/static qualifiers, array fields, multi-variable declarations, delete[].
Supported Value Types: int, double, string, bool, char
Supported STL Containers (both GDB and instrumenter modes):
std::stack, std::queue, std::priority_queue, std::vector, std::deque. The
GDB-mode tracer evaluates .size() / .top() / .back() per snapshot and
synthesises PUSH / POP commands; the instrumenter mode rewrites
push/push_back/push_front/enqueue and pop/pop_back/pop_front/dequeue
calls into trace events.
#include <iostream>
using namespace std;
struct Stack {
int data[100];
int top;
Stack() : top(-1) {}
void push(int val) { data[++top] = val; }
void pop() { if (top >= 0) top--; }
};
int main() {
Stack s;
s.push(10);
s.push(20);
s.push(30);
s.pop();
s.push(40);
return 0;
}#include <iostream>
using namespace std;
class Node {
private:
int data;
Node* next;
Node(int d) : data(d), next(nullptr) {}
friend class LLQueue;
};
class LLQueue {
private:
Node* front;
Node* rear;
public:
LLQueue() : front(nullptr), rear(nullptr) {}
void enqueue(int val) {
Node* node = new Node(val);
if (!rear) { front = rear = node; return; }
rear->next = node;
rear = node;
}
void dequeue() {
if (!front) return;
Node* temp = front;
front = front->next;
if (!front) rear = nullptr;
delete temp;
}
};
int main() {
LLQueue q;
q.enqueue(100);
q.enqueue(200);
q.enqueue(300);
q.dequeue();
q.enqueue(400);
return 0;
}#include <iostream>
using namespace std;
struct BBB {
int val;
BBB* a;
BBB* b;
BBB(int v) : val(v), a(nullptr), b(nullptr) {}
};
int main() {
BBB* root = new BBB(42);
root->a = new BBB(10);
root->b = new BBB(99);
root->a->a = new BBB(5);
root->a->b = new BBB(25);
return 0;
}#include <iostream>
using namespace std;
struct Node {
int data;
Node* next;
Node(int v) : data(v), next(nullptr) {}
};
int main() {
Node* head = new Node(1);
head->next = new Node(2);
head->next->next = new Node(3);
head->next->next->next = new Node(4);
// Delete middle node
Node* temp = head->next;
head->next = temp->next;
delete temp;
return 0;
}#include <iostream>
using namespace std;
struct Node {
int data;
Node* next;
Node(int v) : data(v), next(nullptr) {}
};
int main() {
Node* head = new Node(1);
head->next = new Node(2);
head->next->next = new Node(3);
head->next->next->next = head; // cycle back to head
return 0;
}#include <iostream>
using namespace std;
struct Node {
int data;
Node* next;
Node* prev;
Node(int v) : data(v), next(nullptr), prev(nullptr) {}
};
int main() {
Node* a = new Node(1);
Node* b = new Node(2);
Node* c = new Node(3);
a->next = b; b->prev = a;
b->next = c; c->prev = b;
return 0;
}#include <stack>
#include <queue>
using namespace std;
int main() {
stack<int> s;
s.push(10); s.push(20); s.push(30);
s.pop();
queue<int> q;
q.push(1); q.push(2); q.push(3);
q.pop();
return 0;
}- Node.js 18+
- npm 9+
- g++ (MSYS2 on Windows, or system g++ on Linux/Mac)
- GDB (MSYS2 on Windows:
pacman -S mingw-w64-ucrt-x86_64-gdb, Linux/Mac:apt install gdb/brew install gdb)
GDB is required for the default execution mode. If GDB is not installed, the server automatically falls back to instrumenter mode.
# Frontend
npm install
npm run dev
# Backend (separate terminal)
cd server
npm install
npm run devOpen http://localhost:5173 in your browser.
| Variable | Default | Description |
|---|---|---|
VITE_COMPILER_API_URL |
http://localhost:3001 |
Backend API URL (frontend) |
PORT |
3001 |
Server port (backend) |
GPP_PATH |
Auto-detected | Path to g++ compiler |
GDB_PATH |
Auto-detected | Path to GDB debugger |
USE_GDB |
true |
Set to false to force instrumenter mode |
FRONTEND_URL |
— | Allowed CORS origin for production |
GROQ_API_KEY |
— | Groq API key for AI struct classification (optional, fallback mode only) |
RATE_LIMIT_COMPILE |
20 |
Compile requests per minute per IP |
RATE_LIMIT_GENERAL |
120 |
Other /api requests per minute per IP |
RATE_LIMIT_WINDOW_MS |
60000 |
Rate-limit window in milliseconds |
TRUST_PROXY |
— | Express trust-proxy setting (set to 1 or a CIDR list when behind a load balancer so rate limit keys on the real client IP) |
RLIMIT_CPU_SEC |
8 |
Per-program CPU-time cap in seconds (Linux, applied via prlimit) |
RLIMIT_AS_BYTES |
268435456 |
Per-program virtual-memory cap (256 MiB default) |
RLIMIT_STACK_BYTES |
16777216 |
Per-program stack cap (16 MiB default) |
RLIMIT_FSIZE_BYTES |
8388608 |
Max file size a program may write (8 MiB) |
RLIMIT_NOFILE |
64 |
Max open file descriptors |
RLIMIT_NPROC |
64 |
Max user processes |
PRLIMIT_PATH |
/usr/bin/prlimit |
Path to prlimit. If missing, resource limits are skipped with a warning |
DISABLE_RLIMIT |
— | Set to true to skip resource limiting even when prlimit exists |
- Connect GitHub repo to Vercel
- Set
VITE_COMPILER_API_URLto your backend URL - Deploy
- Connect GitHub repo to Render
- Set root directory to
server, runtime to Docker - Set env vars:
GPP_PATH=/usr/bin/g++,USE_GDB=false(Render does not allow ptrace),FRONTEND_URL=https://your-app.vercel.app,GROQ_API_KEY=gsk_...(optional) - Deploy
On cloud platforms that restrict ptrace (e.g. Render free tier), set
USE_GDB=falseto use instrumenter mode.
The server compiles and runs arbitrary C++ submitted over HTTP. Always combine
the built-in resource limits (prlimit) with container-level isolation:
docker run \
--read-only \
--tmpfs /tmp:exec --tmpfs /dev/shm:exec \
--memory=512m --cpus=1 --pids-limit=128 \
--security-opt=no-new-privileges \
--security-opt seccomp=server/seccomp-profile.json \
-p 3001:3001 server-imageA conservative seccomp profile is included at server/seccomp-profile.json. The
Express server also rate-limits /api/compile (default 20 req/min/IP); tune via
the RATE_LIMIT_* env vars above.
src/
├── types.ts # Type definitions (Command, State, etc.)
├── App.tsx # Main layout with resizable panels
├── api/
│ └── compilerApi.ts # Frontend -> Backend API client
├── engine/
│ └── stepMapper.ts # TraceStep[] -> Commands + runtime pattern analysis
├── hooks/
│ └── useVisualizer.ts # State management (useReducer)
├── utils/
│ └── ids.ts # ID generation utility
└── components/
├── CodeInput.tsx # Monaco C++ editor with autocomplete
├── Controls.tsx # Execution controls & speed slider
├── Terminal.tsx # Output / Input / Command Log tabs
├── Visualizer.tsx # Routes structures to visualization components
└── DataStructures/
├── StackPlate.tsx # Stack: vertical plate stacking
├── QueueBlock.tsx # Queue: horizontal conveyor belt
├── GraphView.tsx # Memory / Linked List / General Graph: graph with arrows
├── TreeChart.tsx # Tree: hierarchical bucket layout (N-ary)
├── CircularListView.tsx # Circular Linked List: polygon layout
└── DoublyListView.tsx # Doubly Linked List: forward/back arrows
server/
├── Dockerfile # Docker image for deployment (Node.js + g++ + util-linux)
├── seccomp-profile.json # Conservative syscall whitelist for `--security-opt seccomp=...`
├── src/
│ ├── index.ts # Express server with CORS + rate-limit
│ ├── routes/compile.ts # POST /api/compile endpoint (GDB or instrumenter)
│ └── services/
│ ├── compiler.ts # g++ compilation + prlimit wrapper (Linux)
│ ├── gdbDriver.ts # GDB MI driver: spawns GDB, steps line-by-line, captures snapshots, exec-wrapper rlimit
│ ├── gdbMapper.ts # Converts GDB snapshots → TraceStep[] events (incl. STL containers)
│ ├── instrumenter.ts # C++ code instrumentation (fallback mode)
│ └── codeAnalyzer.ts # Groq AI struct classifier (fallback mode, optional)
└── sandbox/
└── __tracer.h # C++ tracing header (injected in instrumenter mode)
This project is built with the following open-source libraries:
| Library | License | Description |
|---|---|---|
| React | MIT | UI component library |
| React DOM | MIT | React rendering for web |
| TypeScript | Apache-2.0 | Typed superset of JavaScript |
| Vite | MIT | Next-generation frontend build tool |
| Tailwind CSS | MIT | Utility-first CSS framework |
| Framer Motion | MIT | Animation library for React |
| Monaco Editor (React) | MIT | VS Code editor component for React |
| ESLint | MIT | JavaScript/TypeScript linter |
| Library | License | Description |
|---|---|---|
| Express | MIT | Web framework for Node.js |
| CORS | MIT | Cross-Origin Resource Sharing middleware |
| Node.js | MIT | JavaScript runtime |
| tsx | MIT | TypeScript execution for Node.js |
| groq-sdk | Apache-2.0 | Groq API client for AI struct classification (optional) |
| Tool | License | Description |
|---|---|---|
| g++ (GCC) | GPL-3.0 | C++ compiler (runtime dependency, not bundled) |
| GDB | GPL-3.0 | GNU Debugger for line-by-line tracing (runtime dependency, not bundled) |
MIT License - see LICENSE for details.