npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

use-ammojs

v0.2.21

Published

Fast physics hooks for use in react-three-fiber. Powered by web-workers and wasm.

Downloads

99

Readme

npm npm npm

use-ammojs

Fast Physics hooks for use with react-three-fiber.

Achieved by running the ammo.js physics library in a web-worker. Ammo itself is a WebAssembly wrapper around the powerful Bullet Physics engine. Data is synced with SharedArrayBuffers having minimal impact on the main thread.

yarn add use-ammojs
npm i use-ammojs

Built on top of three-ammo and its related work.

Examples

API Demos

Stress Tests

⚠️ Note that the codesandbox examples do not support SharedArrayBuffers due to missing cross-origin isolation and use regular ArrayBuffers as a fallback. Currently the debug-drawer has no ArrayBuffer fallback implemented and will not render anything.

Why not use use-cannon instead?

use-cannon is great and a inspiration for this package, but it is missing features like soft-bodies and lacks performance in scenes with large triangle meshes. ammo.js is a direct wrapper around the powerful Bullet Physics engine, which solves these problems.

At the time of writing however use-cannon is more mature and great for most projects.

Roadmap

Main goals:

  • [x] Create a Physics World as a React context and simulate it in a web-worker
  • [x] Sync three objects to physics Rigid Bodies
  • [x] Add Rigid Body support
  • [ ] Add Soft Body support
    • [x] Volumes/Cloth from Triangle Mesh
    • [x] Ropes
    • [ ] Support textures on Soft Bodies
    • [ ] Deformables
  • [ ] Add Constraints between Rigid Bodies
  • [ ] Add Constraints to Soft Bodies (ability to pin nodes in place or to Rigid Bodies)
  • [ ] Improve Physics API
    • [ ] Make all props reactive
    • [ ] Expose more methods trough the hook (e.g. setPosition/applyImpulse/more...)
    • [ ] Support collision callbacks
  • [ ] Add Examples to the documentation
  • [ ] Set up Benchmarks to compare cannon, ammo with ArrayBuffers and ammo with SharedArrayBuffers

Low priority goals (for unchecked tasks):

  • [ ] Automatic refresh rate detection and performance throttling (i.e. match the simulation rate to the requestAnimationFrame-rate and throttle performance if simulation steps take too long)
  • [ ] Add Raycast queries
    • [x] One-time (async) ray-tests
    • [ ] Continuous queries trough a fixed scene component to mitigate worker latency (TODO: check if necessary)
  • [x] Use ArrayBuffers as a fallback for missing cross-origin isolation
    • [x] Rigid Bodies
    • [x] Soft Bodies
    • [ ] Debug Rendering
  • [x] Simulation managment
    • [x] Configurable simulation speed
    • [x] Expose performance info
      • [ ] Integrate to @react-three/drei Stats component
    • [ ] Automatically pause simulation if tab is out of focus or not rendering (as option)
  • [ ] Improve the automatic shape detection (set shapeType automatically based on the three Mesh type)
  • [ ] Raycast Vehicle API
  • [ ] Support for instanced objects
  • [ ] Support and document manual bundling of the wasm file
    • Currently the wasm library is inlined with a base64 string for ease of use. Users who want to save a few bytes can serve it as a seperate file with the application/wasm Content-Type in their own deployment. There should be a bundle available without the inlined wasm for that use-case.

Quick Start

1. Wrap your scene in a Physics Provider

import { Physics } from "use-ammojs";

<Physics drawDebug>[...]</Physics>;

2.a Make objects physical (Rigid Bodies)

Automatically parse Shape parameters from the three Mesh (courtesy of three-to-ammo):

import { Box } from "@react-three/drei";
import { useRigidBody, ShapeType } from "use-ammojs";

function MyBox() {
  const [ref] = useRigidBody(() => ({
    mass: 1,
    position: [0, 2, 4],
    shapeType: ShapeType.BOX,
  }));

  return (
    <Box ref={ref}>
      <meshBasicMaterial attach="material" color="red" />
    </Box>
  );
}

or define Collision Shapes manually:

const [playerCapsuleRef] = useRigidBody(() => ({
  bodyType: BodyType.DYNAMIC,
  shapeType: ShapeType.CAPSULE,
  angularFactor: new Vector3(0, 0, 0),
  shapeConfig: {
    fit: ShapeFit.MANUAL,
    halfExtents: new Vector3(0.3, 0.6, 0.3),
  },
}));

or add collisions to an imported gltf scene:

useRigidBody(
  () => ({
    shapeType: ShapeType.MESH,
    bodyType: BodyType.STATIC,
  }),
  gltf.scene
);

2.a Make objects squishy (Soft Bodies)

const [ref] = useSoftBody(() => ({
  type: SoftBodyType.TRIMESH,
}));

return (
  <Sphere position={[0, 2, 7]} args={[1, 16, 16]} ref={ref}>
    <meshPhysicalMaterial attach="material" color="blue" />
  </Sphere>
);

2.c Add Constraints

TODO;

3.a Raycasts

const { rayTest } = useAmmo();

[...]

const hits = await rayTest({
  from: new Vector3(0, 5, 7),
  to: new Vector3(0, -1, 7),
  multiple: true
})

if (hits.length) {
    console.log(hits[0].object.name, hits[0].hitPosition)
}

3.b Update Motion State

const [playerRef, api] = useRigidBody(() => ({
  bodyType: BodyType.DYNAMIC,
  shapeType: ShapeType.CAPSULE,
  angularFactor: new Vector3(0, 0, 0),
  shapeConfig: {
    fit: ShapeFit.MANUAL,
    halfExtents: new Vector3(0.3, 0.6, 0.3),
  },
}));

function handleRespawn() {
  api.setPosition(new Vector3(0, 0, 0));
  api.setLinearVelocity(new Vector3(0, 0, 0));
}

Documentation

Components

<Physics />

Phyiscs Context. Use to wrap all physical objects within the same physics world.

<PhysicsStats />

Shows a stats.js panel with physics timing info. Use within a <Physics /> Context

Hooks

const { rayTest } = useAmmo();

Utility funcionts available anywhere in the <Physics /> context.

const [ref, api] = useRigidBody();
const [ref, api] = useSoftBody();

Cross-origin isolation

To use SharedArrayBuffers for better communication between the main-thread and the web-worker-thread, a cross-origin isolated environment is necessary in modern browsers. This requires sending the following HTTP headers in the response of the main html document (Learn more):

Cross-Origin-Embedder-Policy: require-corp
Cross-Origin-Opener-Policy: same-origin

use-ammojs will fallback to using ArrayBuffers and postMessage() transfers if SharedArrayBuffers are not available. This is not as bad as a full copy on each transfer, but it does not allow the data to be availble on both threads at the same time.

Developing locally using use-ammojs

  1. yarn add @craco/craco --dev
  2. Replace react-scripts with craco in your package.json (see @craco/craco documentation)
  3. Add craco.config.js to project root:
const path = require("path");

module.exports = {
  webpack: {
    configure: (webpackConfig) => {
      // Fix that prevents a duplicate react library being imported when using a linked yarn package
      webpackConfig.resolve.alias = {
        ...webpackConfig.resolve.alias,
        react: path.resolve("./node_modules/react"),
        "@react-three/fiber": path.resolve("./node_modules/@react-three/fiber"),
        three: path.resolve("./node_modules/three"),
      };

      return webpackConfig;
    },
  },

  // Make sure SharedArrayBuffers are available locally
  devServer: {
    headers: {
      "Cross-Origin-Embedder-Policy": "require-corp",
      "Cross-Origin-Opener-Policy": "same-origin",
    },
  },
};
  1. Run yarn link in use-ammojs root directory
  2. Run yarn link use-ammojs in your project's directory
  3. Run yarn start in use-ammojs to start the development bundler
  4. Build and run your project as usual