2 releases
| 0.1.1 | Feb 20, 2026 |
|---|---|
| 0.1.0 | Jan 21, 2026 |
#384 in Visualization
Used in 2 crates
(via vibe-graph-viz)
57KB
1K
SLoC
vibe-graph-layout-gpu
GPU-accelerated force-directed graph layout using WebGPU/wgpu.
Features
- Barnes-Hut approximation for O(n log n) force calculation instead of O(n²)
- WebGPU compute shaders via wgpu for massive parallelization
- Cross-platform: works on native (Vulkan/Metal/DX12) and web (WebGPU)
- Real-time performance: 60+ FPS for graphs with 10,000+ nodes
Performance
| Graph Size | Traditional CPU | GPU Barnes-Hut | Speedup |
|---|---|---|---|
| 1,000 nodes | ~10 FPS | 185 FPS | ~18x |
| 9,000 nodes | ~1 FPS | 110 FPS | ~110x |
| 10,000+ nodes | <1 FPS | 60+ FPS | >60x |
Algorithm
The layout uses a modified Fruchterman-Reingold force-directed algorithm with:
- Repulsive forces: Calculated using Barnes-Hut quadtree approximation
- Attractive forces: Spring-like forces between connected nodes
- Center gravity: Pulls nodes toward the center to prevent drift
- Velocity damping: Stabilizes the simulation over time
Barnes-Hut Approximation
The Barnes-Hut algorithm reduces force calculation complexity from O(n²) to O(n log n):
- Build a quadtree partitioning all nodes spatially
- For each node, traverse the tree:
- If a cell is "far enough" (width/distance < θ), treat it as a single body
- Otherwise, recurse into children
- θ = 0.8 provides a good balance of accuracy and speed
Usage
use vibe_graph_layout_gpu::{GpuLayout, LayoutConfig, Position, Edge};
// Create positions and edges
let positions = vec![
Position::new(0.0, 0.0),
Position::new(100.0, 0.0),
// ...
];
let edges = vec![
Edge::new(0, 1),
// ...
];
// Initialize GPU layout
let config = LayoutConfig {
use_barnes_hut: true,
theta: 0.8,
..Default::default()
};
let mut layout = pollster::block_on(GpuLayout::new(config))?;
layout.init(positions, edges)?;
// Run simulation
layout.start();
loop {
let updated_positions = layout.step()?;
// Render positions...
}
Architecture
┌─────────────────────────────────────────────────────────────┐
│ CPU Side │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Graph Data │───▶│ Quadtree │───▶│ GPU Buffers │ │
│ │ (positions) │ │ (Barnes-Hut)│ │ (upload) │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
└─────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ GPU Side │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ Repulsive │───▶│ Attractive │───▶│ Integrate │ │
│ │ Forces │ │ Forces │ │ Positions │ │
│ │ (BH approx) │ │ (edges) │ │ │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
└─────────────────────────────────────────────────────────────┘
WASM Support
The crate compiles to WebAssembly and uses WebGPU:
cargo build --target wasm32-unknown-unknown -p vibe-graph-layout-gpu
Examples
# Simple 1000-node test
cargo run --example simple_layout
# Large 9000-node benchmark (matches mathlib4 scale)
cargo run --example large_graph --release
Configuration
| Parameter | Default | Description |
|---|---|---|
dt |
0.016 | Time step per iteration |
damping |
0.9 | Velocity damping (0-1) |
repulsion |
1000.0 | Node repulsion strength |
attraction |
0.01 | Edge attraction strength |
theta |
0.8 | Barnes-Hut threshold (0.5-1.0) |
gravity |
0.1 | Center gravity strength |
ideal_length |
50.0 | Target edge length |
max_tree_depth |
12 | Quadtree depth limit |
License
MIT
Dependencies
~8–44MB
~545K SLoC