--- name: webphysics-avbd-engine description: WebGPU rigid-body/soft-body physics engine based on the AVBD (Augmented Vertex Block Descent) solver triggers: - add physics simulation to my WebGPU project - set up webphysics engine - implement rigid body physics in the browser - use AVBD solver for collision detection - WebGPU physics simulation setup - add collision detection with webphysics - configure physics bodies and constraints - run GPU accelerated physics in TypeScript --- # webphysics-avbd-engine > Skill by [ara.so](https://ara.so) — Daily 2026 Skills collection. ## What It Does `webphysics` is an experimental WebGPU-accelerated rigid-body and soft-body physics engine implementing the **AVBD (Augmented Vertex Block Descent)** solver from [Giles et al. (2025)](https://graphics.cs.utah.edu/research/projects/avbd/Augmented_VBD-SIGGRAPH25.pdf). It runs entirely on the GPU using WebGPU compute shaders and supports: - Rigid-body simulation with contacts, friction, and joints - GPU broad-phase collision detection via LBVH (Linear BVH) - Narrow-phase manifold generation with warm-start persistence - Graph-coloring-based parallel body solves - Springs and soft-body constraints - Body sleeping/diagnostics > **Browser support:** Chrome only (requires WebGPU). This is an experimental proof-of-concept, not a production library. ## Installation & Setup ```sh git clone https://github.com/jure/webphysics.git cd webphysics npm install npm run dev # development server npm run build # production build ``` The dev server typically starts at `http://localhost:5173` (Vite-based). ## Project Structure ``` src/ ├── physics/ │ ├── PhysicsEngine.ts # Main orchestration: substep loop, init, step │ └── gpu/ │ ├── avbdState.ts # Primal/dual solve, coloring, velocity finalization │ ├── broadPhase.ts # LBVH broad-phase candidate generation │ ├── contactGeneration.ts # Narrow-phase manifolds, per-body constraint lists │ ├── contactRecord.ts # Warm-start state persistence │ └── avbdState.ts # Inertial targets, primal init, iteration ├── lvbh/ │ └── GPULBVHBuilder.ts # GPU LBVH construction └── ... ``` ## Core API Usage ### Initializing the Physics Engine ```typescript import { PhysicsEngine } from './src/physics/PhysicsEngine'; // Requires an existing GPUDevice const adapter = await navigator.gpu.requestAdapter(); const device = await adapter.requestDevice(); const engine = new PhysicsEngine(device); await engine.init(); ``` ### Adding Rigid Bodies ```typescript // Add a static ground plane engine.addBody({ type: 'box', position: [0, -1, 0], rotation: [0, 0, 0, 1], // quaternion [x, y, z, w] halfExtents: [10, 0.5, 10], mass: 0, // 0 = static/infinite mass restitution: 0.3, friction: 0.5, }); // Add a dynamic rigid box engine.addBody({ type: 'box', position: [0, 5, 0], rotation: [0, 0, 0, 1], halfExtents: [0.5, 0.5, 0.5], mass: 1.0, restitution: 0.2, friction: 0.6, }); ``` ### Stepping the Simulation ```typescript const TIMESTEP = 1 / 60; const SUBSTEPS = 10; function gameLoop(dt: number) { engine.step(dt, SUBSTEPS); // Read back positions for rendering const bodyStates = engine.getBodyStates(); renderBodies(bodyStates); requestAnimationFrame(gameLoop); } requestAnimationFrame(gameLoop); ``` ### Reading Body State for Rendering ```typescript // After engine.step(), retrieve updated transforms const states = engine.getBodyStates(); for (const state of states) { const { position, rotation, bodyIndex } = state; // position: [x, y, z] // rotation: quaternion [x, y, z, w] updateMeshTransform(bodyIndex, position, rotation); } ``` ### Adding Joints / Constraints ```typescript // Distance joint between two bodies engine.addJoint({ type: 'distance', bodyA: 0, bodyB: 1, anchorA: [0, 0.5, 0], // local-space anchor on body A anchorB: [0, -0.5, 0], // local-space anchor on body B restLength: 1.0, stiffness: 1e4, }); ``` ### Adding Springs (Soft Bodies) ```typescript engine.addSpring({ bodyA: 2, bodyB: 3, anchorA: [0, 0, 0], anchorB: [0, 0, 0], restLength: 0.8, stiffness: 500, damping: 10, }); ``` ## AVBD Pipeline Reference The solver follows Algorithm 1 from the AVBD paper: ``` 1. collision detection (x^t) ↓ 2. broad phase (LBVH) → src/lvbh/GPULBVHBuilder.ts ↓ 3. narrow phase + warm start → src/physics/gpu/contactGeneration.ts ↓ 4. per-body constraint lists → src/physics/gpu/avbdState.ts ↓ 5. graph coloring → src/physics/gpu/avbdState.ts ↓ 6. inertial target y, primal init, warm-start α/γ ↓ 7. [loop] colored primal body solve (approx Hessian) ↓ 8. [loop] dual + stiffness update ↓ 9. finalize velocities ``` Key files per stage: | Stage | File | |-------|------| | Orchestration | `src/physics/PhysicsEngine.ts` | | Broad phase | `src/physics/gpu/broadPhase.ts` | | Narrow phase | `src/physics/gpu/contactGeneration.ts` | | Contact records | `src/physics/gpu/contactRecord.ts` | | AVBD solve | `src/physics/gpu/avbdState.ts` | | LBVH builder | `src/lvbh/GPULBVHBuilder.ts` | ## Configuration Patterns ### Solver Parameters ```typescript // Passed during engine construction or step engine.step(dt, substeps, { gravity: [0, -9.81, 0], iterations: 10, // AVBD inner iterations per substep restitutionThreshold: 1.0, }); ``` ### Tuning Stability - Increase `substeps` (e.g., 20) for stiff stacks or fast-moving bodies - Increase `iterations` for better constraint convergence - Use `mass: 0` for static bodies (never moves, acts as infinite mass) - Lower `stiffness` values for softer, more stable joints - Set `restitution: 0` + high `friction` for non-bouncy stacking ## Common Patterns ### Stack of Boxes ```typescript const groundIndex = engine.addBody({ type: 'box', position: [0, 0, 0], halfExtents: [5, 0.25, 5], mass: 0, friction: 0.7, restitution: 0.1, }); for (let i = 0; i < 8; i++) { engine.addBody({ type: 'box', position: [0, 0.5 + i * 1.05, 0], halfExtents: [0.5, 0.5, 0.5], mass: 1.0, friction: 0.5, restitution: 0.1, }); } ``` ### Pendulum Chain with Distance Joints ```typescript let prevIndex = engine.addBody({ type: 'box', position: [0, 5, 0], halfExtents: [0.1, 0.1, 0.1], mass: 0, friction: 0, restitution: 0, }); for (let i = 1; i <= 5; i++) { const curr = engine.addBody({ type: 'box', position: [0, 5 - i, 0], halfExtents: [0.15, 0.15, 0.15], mass: 1.0, friction: 0.1, restitution: 0, }); engine.addJoint({ type: 'distance', bodyA: prevIndex, bodyB: curr, anchorA: [0, -0.15, 0], anchorB: [0, 0.15, 0], restLength: 0.7, stiffness: 1e5, }); prevIndex = curr; } ``` ### Integrate with Three.js Rendering ```typescript import * as THREE from 'three'; const meshes: THREE.Mesh[] = []; function syncPhysicsToRender() { const states = engine.getBodyStates(); states.forEach((state, i) => { if (!meshes[i]) return; meshes[i].position.set(...state.position); meshes[i].quaternion.set( state.rotation[0], state.rotation[1], state.rotation[2], state.rotation[3] ); }); } function animate() { engine.step(1 / 60, 10); syncPhysicsToRender(); renderer.render(scene, camera); requestAnimationFrame(animate); } ``` ## Troubleshooting ### WebGPU Not Available ``` Error: navigator.gpu is undefined ``` - Only Chrome 113+ supports WebGPU by default - Enable via `chrome://flags/#enable-unsafe-webgpu` on older versions - Firefox/Safari do not currently support WebGPU ### Simulation Explodes / Bodies Flying Off - Reduce timestep or increase `substeps` - Lower joint `stiffness` values - Ensure static bodies have `mass: 0` - Check that `halfExtents` are positive and non-zero ### Bodies Sinking Through Ground - Increase `iterations` (try 15–20) - Increase `substeps` - Check collision shape sizing matches visual mesh ### Performance Issues - This is a Chrome-only WebGPU project; GPU driver issues can cause slowdowns - Reduce body count or iteration count - Check `chrome://gpu` to ensure hardware acceleration is active ### Build Errors ```sh # Ensure Node.js >= 18 node --version # Clear cache rm -rf node_modules dist npm install npm run build ``` ## Limitations & Roadmap Notes - **Chrome only** — no Firefox/Safari support yet - Not a drop-in npm package; must clone and integrate manually - Double-buffered position updates (for same-color conflict safety) not yet implemented — current path uses in-place colored body solve in `avbdState.ts` - Experimental API — breaking changes expected - No TypeScript type declarations exported for external use yet ## References - [Live Demo](https://jure.github.io/webphysics/) - [AVBD Paper (Giles et al., SIGGRAPH 2025)](https://graphics.cs.utah.edu/research/projects/avbd/Augmented_VBD-SIGGRAPH25.pdf) - [WebGPU Spec](https://gpuweb.github.io/gpuweb/)