← The Lab

04 / Three.js · Physics

Physics Sandbox

Physics sandbox — white spheres and boxes piled on a grey floor with a controls panel

Lab notes

Three.js does not ship with gravity. Meshes are polite—they stay exactly where you put them until you move them. This experiment is the bridge: a physics world that steps forward in time, and a scene graph that copies transforms every frame so what you see is what the solver thinks happened.

The screenshot is the whole thesis. White primitives on a flat plane, piled like someone shook a box of parts. No textures, no HDR—just contact, restitution, and the satisfaction of watching a stack fail slowly.

Two worlds, one clock

The pattern is always the same: create a physics body for each mesh you want to move, keep a reference between them, and in the animation loop call `world.step(delta)` before you read positions and quaternions back into Three.js. Rendering without stepping gives you frozen bodies; stepping without syncing gives you ghosts.

Fixed timesteps matter. Variable frame rates on the web will make stacks jitter if you pass raw `delta` straight into the solver every frame. Sub-stepping—or clamping the delta—keeps piles stable enough to feel real on a laptop trackpad.

Shapes that match the mesh

Spheres get sphere colliders; boxes get box colliders. It sounds obvious until you try to approximate a torus with a convex hull and wonder why the frame time doubled. This lab stays primitive on purpose: the collision shapes are cheap, the contact manifolds are readable, and debugging stays visual.

Mass and size are not the same knob. A large light sphere and a small heavy box teach different lessons about inertia—one floats in a pile, the other punches through if you spawn it high enough. The spawn buttons are not toys; they are how you stress-test the solver.

Floor, friction, and the grey plane

The ground is a static body: infinite mass in solver terms, zero velocity forever. Everything else bounces, slides, or settles based on friction and restitution on both sides of the contact. Tune restitution too high and the pile becomes a pinball machine; too low and it looks like wet clay.

The floor mesh in Three.js is only there to catch light. The physics plane is invisible and infinite. That separation is normal—rendering fidelity and collision fidelity rarely share the same geometry.

Controls as a stress harness

Create sphere, create box, reset—the panel is a minimal test harness. Reset clears bodies and rebuilds the world so you are not chasing stale references after an afternoon of tweaks. Spawn buttons drop new bodies from a fixed height so every run starts with comparable energy.

Shipping the controls in the corner matches how we use lab pieces internally: the demo is the instrument, not just the output. If you cannot break it with a button, you do not yet understand its limits.

Why static hosting still works

Like the other lab builds, this runs on GitHub Pages—WASM or JS physics, a canvas, no server tick. The entire simulation is client-side, which is how most product interactions behave anyway: drop a configurator part, drag a furniture block, preview a collapse.

Open the live build, spawn a dozen boxes, then a dozen spheres into the same corner. If the pile settles instead of exploding, the timestep and material tuning are in the right neighborhood. That quiet stability is what we were aiming for.