Skip to main content

Physics

PlayCanvas ships with a robust physics system. This enables realistic simulations of objects in 3D space, including gravity, collisions, forces and constraints. The physics system is powered by the ammo.js physics engine.

Getting started​

PlayCanvas uses ammo.js as the physics engine. ammo.js is a WASM library and in React it's lazy loaded. This means you're only shipping ammo.js when you need it, helping you keep your bundle size down. It also means you can render something before ammo.js has loaded, or maybe you only need physics as a result of some user interaction. In any case, lazy loading ammo.js means you can get your content rendering fast.

To use the physics system, you'll need to install the sync-ammo dependency.

npm install sync-ammo

You'll also need to add the <Application usePhysics/> prop to your root <Application/> component.

tip

PlayCanvas React will only load ammo.js when you have the <Application usePhysics/> prop set.

<Application usePhysics>
<Entity>
<Rigidbody type="box" />
</Entity>
</Application>

Usage​

You allow entities to participate in physics simulation by adding a RigidBody and Collision component to them. In the example below, we're creating a static ground, a falling sphere and a falling box.

Physics Properties​

You can customize physics behavior by changing the various properties of the <RigidBody/> and <Collision/> components. Check out the Physics documentation for more information.

<RigidBody
type="dynamic"
mass={1} // Object mass
linearDamping={0.1} // Air resistance for movement
angularDamping={0.1} // Air resistance for rotation
friction={0.5} // Surface friction
restitution={0.3} // Bounciness (0 = no bounce, 1 = perfect bounce)
/>
<Collision
type="box"
halfExtents={[1, 1, 1]} // Size for box collision
radius={0.5} // Radius for sphere/cylinder collision
height={2} // Height for capsule/cylinder collision
/>

The usePhysics Hook​

Because the physics engine is lazily instantiated you'll want to handle this in a reactive way. This is where the usePhysics hook comes in.

import { usePhysics } from '@playcanvas/react/hooks';

const PhysicsStatus = () => {
const { isPhysicsEnabled, isPhysicsLoaded, physicsError } = usePhysics();
// ...
};

The usePhysics hook provides information about the physics engine state. You can read more about the usePhysics hook in the API reference.

For more detailed information about PlayCanvas physics, see the PlayCanvas physics docs.

Troubleshooting​

webpack warns Can't resolve 'sync-ammo'​

sync-ammo is an optional dependency, so it is only needed when you use physics. If you haven't installed it, webpack (including next build --webpack) still reports a warning because it resolves every import at build time:

Module not found: Error: Can't resolve 'sync-ammo'

The warning is harmless. PlayCanvas React only loads sync-ammo when usePhysics is set. Vite and Turbopack handle the missing package without a warning, so they need no changes.

To silence the warning in webpack, ignore the module:

webpack.config.js
const webpack = require('webpack');

module.exports = {
// ...
plugins: [
new webpack.IgnorePlugin({ resourceRegExp: /^sync-ammo$/ })
]
};

In Next.js, add it to next.config.mjs. Only do this if you build with next build --webpack, as the default Turbopack build fails when a webpack config is present:

next.config.mjs
export default {
webpack: (config, { webpack }) => {
config.plugins.push(new webpack.IgnorePlugin({ resourceRegExp: /^sync-ammo$/ }));
return config;
}
};
warning

IgnorePlugin stops webpack from bundling sync-ammo even if it is installed. Remove it if you enable usePhysics.