# phy: one physics API over seven engines for three.js

> phy is a JavaScript bridge that puts a single set of add, remove and change calls over seven different physics engines for three.js, from Oimo to Rapier, Jolt and Havok, with a compact and a full build and a worker or direct execution mode. Two of the engines are closed source, and the project says so plainly.

**lo-th/phy** — Physics for three. Game engine 

- Repository: https://github.com/lo-th/phy
- Website: https://lo-th.github.io/phy/
- Stars: 745 · Forks: 54
- Language: JavaScript
- License: MIT
- Published: 2026-10-21 · Updated: 2026-10-21 · Language: en
- Canonical page: https://hysenlabs.com/projects/lo-th-phy

## Seven engines behind one set of calls

phy is a JavaScript physics library for three.js, published to npm as phy-engine at version 0.14.0 and described as a universal physics language. The project lists the engines it bridges at the top of the README, and there are seven of them: Oimo, Ammo, Rapier, Jolt, Havok, PhysX and Box3d.

The pitch is stated in two lines. Phy simplifies game creation and is a bridge between three.js and physics. The second of those is the important word, because a bridge that only wrapped one engine would be an integration and not a bridge. What phy offers is a common layer, so the same scene code can run on a lightweight engine like Oimo or on a full one like Rapier or Jolt, and the choice becomes a configuration decision rather than a rewrite.

The API surface is described in one sentence. The main function is add, remove and change. That is a genuinely small surface, and it is the right shape for a bridge: the three verbs map onto what you actually do with a physics world, and everything engine-specific sits behind them.

There is also a demo and editor, hosted at the project page, with a WebGPU variant at a separate address. The README points at the editor as the place to see and edit the demo code directly, and you can drag a file onto the viewport, either a JavaScript file or an environment HDR file.

The project is MIT licensed, the default branch is main, and the repository has no GitHub releases, so the npm package is the distribution channel rather than the release list.

## Compact build, full build, and a worker or direct mode

Two decisions shape how you install and configure phy, and both are visible in the package manifest.

The first is the build variant. The README says you can use the compressed or the full version of the physics engines, and the exports map in the manifest shows how that is expressed. The main entry offers a build directory for the full version, and there is a separate export path for the compact directory, so a bundler picks up the compact engines when you import from that path and the full ones when you import from the root.

The difference is not cosmetic. A physics engine compiled to WebAssembly is a large download, and a project that only needs one of them should not ship all seven. The compact build is the answer to that, and the feature list calls the engine an ultra fast compact engine.

The second is where the simulation runs. The feature list says worker or direct version, and the project description says phy runs on Worker or Direct. A worker moves the physics loop off the main thread, which keeps rendering smooth while the simulation steps. The direct mode runs it inline, which is simpler to debug and avoids the message passing overhead when the scene is small.

The distribution itself is worth noting. The package is an ES module with a CommonJS build alongside, the main field points at a .cjs file and the module field at a .module.js file, and the exports map covers both the import and require conditions. The files published are the package metadata, the licence, the readme, and the compact and build directories.

## One rollup config per engine, and an extra set of bundles

The build script in the manifest is the clearest description of the project's structure, because it names every engine as its own step:

```json
    "build": "npm run phy && npm run oimo && npm run ammo && npm run physx && npm run havok && npm run rapier && npm run jolt",
```

Each engine then has its own rollup configuration under a rollup/ directory, with the script names matching the config file names, so there is a rollup.config.phy.js for the main bundle and one for each of oimo, ammo, physx, havok, rapier, box3d and jolt. The cannon engine also has a config even though it is not in the top level build chain, which suggests it is built separately rather than dropped.

Above the engine builds there is a set of extra bundles, and the names are a good index of what the project has been working on. There is a main config, a smoke bundle, and then labs for a browser-based visual harness, for animation, for fracture, for speech, for wiggle, and for codeflask. The build script naming these as separate rollup invocations tells you they are standalone artifacts, each small and focused.

The extra.smoke.js bundle in particular is the kind of thing that suggests testing discipline, since a smoke build is normally something you run to check that a change did not break the module graph.

The repository tree matches this. There is a src/ directory, a build/ directory, a compact/ directory, a three/ directory, a demos/ directory with a demos.json manifest, a docs/ directory, a rollup/ directory and an assets/ directory with icons. The top level also holds several HTML entry points, including index.html, index_gpu.html, editor.html, simple.html, double.html and two heroes pages.

## Two of the engines are closed, and the project says so

The note in the README is unusual and worth reading carefully before you build on this. For the moment the source on PhysX and Havok is hidden. The stated reason is that it is a long research work to standardize all engines, and the author adds that he is thinking about opening everything but needs more sponsors.

The last line of that note is the one that changes what you can do with the package. It is possible to use the compile version without restriction. So the two commercial engines are available as compiled builds that you can use, but you cannot read or modify their integration source, which is where the standardisation work actually lives.

That is a real limitation for anyone who wants to extend the bridge itself, add a new engine, or understand exactly how a Havok body is mapped onto a three.js object. It is not a limitation for using the library, since the API is the same either way.

The sponsorship framing explains the rest of the project. The README states that phy is under active development and points at GitHub Sponsors for support, and the project is a solo effort with a single author. The feature list is written in the same compressed style as the rest of the README, listing math optimization, assets pool, ES6, extra geometry, advanced character and animation, and the ultra fast compact engine with worker or direct version.

The todo list is short and honest: add more function and demo, standardize and clean code. The documentation is described as in progress.

## Where phy is the wrong tool

The first wrong case is a project that has already committed to one engine with real depth in it. If you have written a custom constraint, a vehicle controller or a character setup against Rapier or Jolt directly, wrapping it in phy's add, remove and change model means giving up access to the parts of those APIs that do not fit the bridge. The bridge is a convenience, and a convenience has a cost when you need the underlying engine's full surface.

The second is a project that needs the two closed engines to be inspectable. The PhysX and Havok sources are hidden, so if your requirement is auditing what happens in the integration, debugging at the boundary, or contributing a fix to that layer, you cannot do it. Compiled builds without restriction cover usage, not collaboration.

The third is a production project that needs a stable, documented API. The version is 0.14.0, the repository publishes no GitHub releases, the documentation is described as in progress, and the todo mentions standardizing and cleaning the code. A bridge whose whole value is a consistent interface is exactly the kind of project where an interface that is still moving is a problem, because the consistency is the promise.

The fourth is a project that needs a maintained upstream. This is one author with a sponsorship model, and the release history is the npm version rather than a tagged release list. If your production system depends on it, you are depending on a single maintainer's continued interest.

The alternative worth weighing is using the engine directly and writing the three.js glue yourself. Rapier and Jolt both ship their own JavaScript bindings and three.js integration examples, and for a straightforward scene that is a small amount of code with no abstraction in the way. phy's advantage is the choice and the comparison, and its cost is a layer you have to learn and trust.

## Conclusion

Adopt phy if you are building on three.js and want to be able to switch physics engine, or to compare engines, without rewriting your scene code, since the whole surface is add, remove and change over a shared interface. Keep away if you need a single engine with a documented, complete public API, because the PhysX and Havok sources are hidden and the documentation is described as in progress. Before you depend on it, read the note in the README about the hidden sources and the compiled builds, and check that the version you install is 0.14.0, with the last push on 2026-07-30 and the project stating it is under active development.

## FAQ

### What is the phy JavaScript library and which physics engines does it support?

It is a universal physics language for three.js, published to npm as phy-engine, and it bridges seven engines: Oimo, Ammo, Rapier, Jolt, Havok, PhysX and Box3d. Its main function is add, remove and change, and you can use either the compressed or the full version of the engines.

### What is the difference between the compact build and the full build of phy?

The compact build is the compressed version of the physics engines, and it is imported through the separate compact export path in the package manifest, while the root export gives the full build. The point is to avoid shipping every engine when a project only needs one.

### Can I use the PhysX and Havok versions of phy freely?

The README says it is possible to use the compile version without restriction, but it also states that the source on PhysX and Havok is hidden for now, describing it as a long research work to standardize all engines. So you can use them but cannot read or modify the integration source.

### How do I run the phy physics simulation in a worker?

The package is published as phy-engine with separate builds, and the project description says phy runs on Worker or Direct, with the worker and direct versions listed among the features. The project also ships a demo and editor with a WebGPU variant at a separate address.

## Sources

- [Issues](https://github.com/lo-th/phy/issues)
- [License: MIT](https://github.com/lo-th/phy/blob/main/LICENSE)
- [lo-th/phy on GitHub](https://github.com/lo-th/phy)
- [Project website](https://lo-th.github.io/phy/)
- [README](https://github.com/lo-th/phy/blob/main/README.md)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/lo-th-phy
