Webphysics Avbd Engine

by reason-machines2384a003145aNo licenseListed Oct 8, 2026Updated Oct 8, 2026

WebGPU rigid-body/soft-body physics engine based on the AVBD (Augmented Vertex Block Descent) solver

Instructions onlySoftware Development
AI-generated overview

Guides integration of the experimental WebGPU AVBD rigid-body and soft-body physics engine into browser projects.

What it does
This skill documents the webphysics WebGPU physics engine, which implements the AVBD solver for rigid-body and soft-body simulation. It covers installation, project structure, engine initialization, adding bodies, joints and springs, stepping the simulation, and reading body states for rendering. It also provides solver configuration patterns, common setups such as box stacks and pendulum chains, and troubleshooting notes.
When to use it
Use it when adding GPU-accelerated rigid-body or soft-body physics to a WebGPU project in the browser. It suits setting up collision detection, constraints, joints or springs with the AVBD solver, and tuning simulation stability.
Requirements
Requires a WebGPU-capable browser (Chrome only), Node.js 18 or newer, npm, and a GPUDevice obtained through navigator.gpu. The engine is cloned from its repository and integrated manually; the skill itself ships no scripts and is instructions only.

webphysics-avbd-engine

Skill by 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). 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.gitcd webphysicsnpm installnpm run dev        # development servernpm 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 GPUDeviceconst 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 planeengine.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 boxengine.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 transformsconst 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 bodiesengine.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:

StageFile
Orchestrationsrc/physics/PhysicsEngine.ts
Broad phasesrc/physics/gpu/broadPhase.ts
Narrow phasesrc/physics/gpu/contactGeneration.ts
Contact recordssrc/physics/gpu/contactRecord.ts
AVBD solvesrc/physics/gpu/avbdState.ts
LBVH buildersrc/lvbh/GPULBVHBuilder.ts

Configuration Patterns

Solver Parameters

typescript
// Passed during engine construction or stepengine.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 >= 18node --version# Clear cacherm -rf node_modules distnpm installnpm 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

Source and attribution

Source:reason-machines/trending-skillsinskills/webphysics-avbd-engineat commit2384a00

License: No license

Content belongs to its original authors. SourceWeft indexes it from a public repository.

Report or request removal