• Stars
    star
    1,005
  • Rank 45,700 (Top 1.0 %)
  • Language
    TypeScript
  • License
    MIT License
  • Created over 2 years ago
  • Updated 6 months ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

🤺 Rapier physics in React

@react-three/rapier

⚠️ This library is under development. All APIs are subject to change. ⚠️
For contributions, please read the 🪧 Contribution Guide.
For available APIs, see 🧩 API Docs


react-three/rapier (or r3/rapier) is a wrapper library around the Rapier (https://rapier.rs/docs/user_guides/javascript) WASM-based physics engine, designed to slot seamlessly into a react-three/fiber pipeline.

The goal of this library to is to provide a fast physics engine with minimal friction and small, straight forward API.

Basic Usage

import { Box, Torus } from "@react-three/drei";
import { Canvas } from "@react-three/fiber";
import { Physics, RigidBody, CuboidCollider } from "@react-three/rapier";

const App = () => {
  return (
    <Canvas>
      <Suspense>
        <Physics debug>
          <RigidBody colliders={"hull"} restitution={2}>
            <Torus />
          </RigidBody>

          <CuboidCollider position={[0, -2, 0]} args={[20, 0.5, 20]} />
        </Physics>
      </Suspense>
    </Canvas>
  );
};

📝 Readme note

Below follows a guide on core concepts for react-three/rapier.
For full API outline and documentation, see 🧩 API Docs.


Readme Topics


The Physics Component

The <Physics /> component is the root component of your physics world. It is responsible for creating the physics world and managing the simulation. It relies on lazily initiating Rapier and needs to be wrapped in <Suspense />.

🧩 See PhysicsProps docs for available props.

const Scene = () => {
  return (
    <Canvas>
      <Suspense>
        <Physics gravity={[0, 1, 0]} interpolation={false} colliders={false}>
          ...
        </Physics>
      </Suspense>
    </Canvas>
  );
};

The RigidBody Component

The <RigidBody /> component is used to add a mesh into the physics world. You use it by wrapping one or more meshes and setting desired props. By default, this will automatically generate Colliders based on the shape of the wrapped meshes (see Automatic colliders).

🧩 See RigidBodyProps docs for available props.

const RigidBodyMesh = () => (
  <RigidBody>
    <mesh />
  </RigidBody>
);

Automatic Colliders

RigidBodies generate automatic colliders by default for all meshes that it contains. You can control the default collider by setting the colliders prop on a <RigidBody />, or change it globally by setting colliders on <Physics />. Setting colliders={false} disables auto-generation.

Supported values:

  • "cuboid", creates a CuboidCollider based on the bounding box of the mesh
  • "ball", creates a SphereCollider based on the bounding sphere of the mesh
  • "trimesh", creates a TrimeshCollider based on the mesh's geometry
  • "hull", creates a ConvexHullCollider based on the mesh's geometry
  • false, disables auto-generation

Generate ConvexHull colliders for all meshes in a RigidBody by default:

const Scene = () => (
  <Physics colliders="hull">
    <RigidBody>
      <Box />
    </RigidBody>
    <RigidBody position={[0, 10, 0]}>
      <Sphere />
    </RigidBody>
  </Physics>
);

Turn off automatic collider generation globally, but apply auto generation locally:

const Scene = () => (
  <Physics colliders={false}>
    {/* Use an automatic CuboidCollider for all meshes inside this RigidBody */}
    <RigidBody colliders="cuboid">
      <Box />
    </RigidBody>

    {/* Use an automatic BallCollider for all meshes inside this RigidBody */}
    <RigidBody position={[0, 10, 0]} colliders="ball">
      <Sphere />
    </RigidBody>
  </Physics>
);

Collider Components

You can also create Colliders by hand and add them to a RigidBody to create compound colliders. This is useful for creating more complex shapes, for creating simplified shapes for performance reasons, or for detecting collisions on specific parts of a mesh.

🧩 See ColliderProps docs for available props.

const Scene = () => (<>
  {/* Make a compound shape with two custom BallColliders */}
  <RigidBody position={[0, 10, 0]}>
    <Sphere />
    <BallCollider args={[0.5]} />
    <BallCollider args={[0.5]} position={[1, 0, 0]} />
  </RigidBody>

  {/* Make a compound shape with two custom BallColliders, an automatic BallCollider,
      Two automatic MeshColliders, based on two different shape types */}
  <RigidBody position={[0, 10, 0]} colliders='ball'>
    <MeshCollider type="trimesh">
      <mesh ... />
    </MeshCollider>

    <MeshCollider type="hull">
      <mesh ... />
    </MeshCollider>

    <Sphere />

    <BallCollider args={[0.5]} />
    <BallCollider args={[0.5]} position={[1, 0, 0]} />
  </RigidBody>
<>)

RigidBodies work inside other transformed objects as well. Simulation runs in world space and is transformed to the objects local space, so that things act as you'd expect.

Note It's always best to create RigidBodies where the center of gravity is in the center of the object, otherwise you might get some unexpected behavior during simulation interpolation.

import { Box } from "@react-three/drei";
import { RigidBody, CuboidCollider } from "@react-three/rapier";

const Scene = () => (
  <group position={[2, 5, 0]} rotation={[0, 0.3, 2]}>
    <RigidBody>
      <Box />
      <CuboidCollider args={[0.5, 0.5, 0.5]} />
    </RigidBody>
  </group>
);

If part of our meshes are invisible and you want to include them in the collider creation, use the includeInvisible flag.

<RigidBody colliders="hull" includeInvisible>
  <object3D>
    <Suzanne visible={false} />
  </object3D>
</RigidBody>

🖼 Collider Examples

Instanced Meshes

Instanced meshes can also be used and have automatic colliders generated from their mesh.

By wrapping exactly one Three.InstancedMesh in <InstancedRigidBodies />, each instance will be attached to an individual RigidBody.

🧩 See InstancedRigidBodiesProps docs for available props.

import { InstancedRigidBodies, RapierRigidBody } from "@react-three/rapier";

const COUNT = 1000;

const Scene = () => {
  const rigidBodies = useRef<RapierRigidBody[]>(null);

  useEffect(() => {
    if (!rigidBodies.current) {
      return;
    }

    // You can access individual instanced by their index
    rigidBodies.current[40].applyImpulse({ x: 0, y: 10, z: 0 }, true);
    rigidBodies.current.at(100).applyImpulse({ x: 0, y: 10, z: 0 }, true);

    // Or update all instances
    rigidBodies.current.forEach((api) => {
      api.applyImpulse({ x: 0, y: 10, z: 0 }, true);
    });
  }, []);

  // We can set the initial positions, and rotations, and scales, of
  // the instances by providing an array of InstancedRigidBodyProps
  // which is the same as RigidBodyProps, but with an additional "key" prop.
  const instances = useMemo(() => {
    const instances: InstancedRigidBodyProps[] = [];

    for (let i = 0; i < COUNT; i++) {
      instances.push({
        key: "instance_" + Math.random(),
        position: [Math.random() * 10, Math.random() * 10, Math.random() * 10],
        rotation: [Math.random(), Math.random(), Math.random()]
      });
    }

    return instances;
  }, []);

  return (
    <InstancedRigidBodies
      ref={rigidBodies}
      instances={instances}
      colliders="ball"
    >
      <instancedMesh args={[undefined, undefined, COUNT]} count={COUNT} />
    </InstancedRigidBodies>
  );
};

We can also create compound shapes for instanced meshes by providing an array of Colliders in the colliderNodes prop.

import {
  InstancedRigidBodies,
  BoxCollider,
  SphereCollider
} from "@react-three/rapier";
const COUNT = 500;

const Scene = () => {
  const instances = useMemo(() => {
    const instances: InstancedRigidBodyProps[] = [];

    for (let i = 0; i < COUNT; i++) {
      instances.push({
        key: "instance_" + Math.random(),
        position: [Math.random() * 10, Math.random() * 10, Math.random() * 10],
        rotation: [Math.random(), Math.random(), Math.random()]
      });
    }

    return instances;
  }, []);

  return (
    <InstancedRigidBodies
      instances={instances}
      colliders="ball"
      colliderNodes={[
        <BoxCollider args={[0.5, 0.5, 0.5]} />,
        <SphereCollider args={[0.5]} />
      ]}
    >
      <instancedMesh args={[undefined, undefined, COUNT]} count={COUNT} />
    </InstancedRigidBodies>
  );
};

Debug

Set the debug prop on <Physics /> to see live representations of all colliders in a scene, using the live debug buffer from the physics engine.

import { Box, Sphere } from "@react-three/drei";
import { RigidBody } from "@react-three/rapier";

const Scene = () => {
  return (
    <Physics debug>
      <RigidBody>
        <Box />
      </RigidBody>
      <RigidBody>
        <Sphere />
      </RigidBody>
    </Physics>
  );
};

Moving things around, and applying forces

You can access the instance for a RigidBody by storing its ref. This allows you to perform any operation on the underlying physics object directly.

r3/rapier exposes a RapierRigidBody and RapierCollider as aliases for rapiers underlying base objects.

For all available methods, see the Rapier docs.

import { RigidBody, RapierRigidBody } from "@react-three/rapier";

const Scene = () => {
  const rigidBody = useRef<RapierRigidBody>(null);

  useEffect(() => {
    if (rigidBody.current) {
      // A one-off "push"
      rigidBody.current.applyImpulse({ x: 0, y: 10, z: 0 }, true);

      // A continuous force
      rigidBody.current.addForce({ x: 0, y: 10, z: 0 }, true);

      // A one-off torque rotation
      rigidBody.current.applyTorqueImpulse({ x: 0, y: 10, z: 0 }, true);

      // A continuous torque
      rigidBody.current.addTorque({ x: 0, y: 10, z: 0 }, true);
    }
  }, []);

  return (
    <RigidBody ref={rigidBody}>
      <mesh>
        <boxBufferGeometry />
        <meshStandardMaterial />
      </mesh>
    </RigidBody>
  );
};

Rapier's API returns quaternions and vectors that are not compatible with Three.js, r3/rapier therefore exposes some helper functions (vec3, quat, euler) for quick type conversions. These helper functions can also be used as a shorthand for creating new objects.

import { RapierRigidBody, quat, vec3, euler } from "@react-three/rapier";

const Scene = () => {
  const rigidBody = useRef<RapierRigidBody>(null);

  useEffect(() => {
    if (rigidBody.current) {
      const position = vec3(rigidBody.current.translation());
      const quaternion = quat(rigidBody.current.rotation());
      const eulerRot = euler().setFromQuaternion(
        quat(rigidBody.current.rotation())
      );

      // While Rapier's return types need conversion, setting values can be done directly with Three.js types
      rigidBody.current.setTranslation(position, true);
      rigidBody.current.setRotation(quaternion, true);
      rigidBody.current.setAngVel({ x: 0, y: 2, z: 0 }, true);
    }
  }, []);

  return (
    <RigidBody ref={rigidBody}>
      <mesh>
        <boxBufferGeometry />
        <meshStandardMaterial />
      </mesh>
    </RigidBody>
  );
};

Collision Events

You can subscribe to collision and state events on a RigidBody:

🧩 See onCollisionEnter / onCollisionExit docs for more information.

const RigidBottle = () => {
  const [isAsleep, setIsAsleep] = useState(false);

  return (
    <RigidBody
      colliders="hull"
      onSleep={() => setIsAsleep(true)}
      onWake={() => setIsAsleep(false)}
      name="Bally McBallFace"
      onCollisionEnter={({ manifold, target, other }) => {
        console.log(
          "Collision at world position ",
          manifold.solverContactPoint(0)
        );

        if (other.rigidBodyObject) {
          console.log(
            // this rigid body's Object3D
            target.rigidBodyObject.name,
            " collided with ",
            // the other rigid body's Object3D
            other.rigidBodyObject.name
          );
        }
      }}
    >
      <Sphere>
        <meshPhysicalMaterial color={isAsleep ? "white" : "blue"} />
      </Sphere>
    </RigidBody>
  );
};

You may also subscribe to collision events on individual Colliders:

<CuboidCollider
  onCollisionEnter={(payload) => {
    /* ... */
  }}
  onCollisionExit={(payload) => {
    /* ... */
  }}
/>

The payload object for all collision callbacks contains the following properties:

  • target
    CollisionTarget of the object firing the event.
  • other
    CollisionTarget of the other object involved in the event.
  • manifold (onCollisionEnter only)
    The contact manifold generated by the collision event.
  • flipped (onCollisionEnter only)
    true if the data in the manifold is flipped.

A CollisionTarget is an object containing references to objects involved in a collision event. It has the following properties:

  • rigidBody (if exists): Rapier.RigidBody
  • rigidBodyObject (if exists): Three.Object3D
  • collider: Rapier.Collider
  • colliderObject: Three.Object3D

Configuring collision and solver groups

Both <RigidBody> as well as all collider components allow you to configure collisionsGroups and solverGroups properties that configures which groups the colliders are in, and what other groups they should interact with in potential collision and solving events (you will find more details on this in the Rapier documentation.)

Since these are set as bitmasks and bitmasks can get a bit unwieldy to generate, this library provides a helper called interactionGroups that can be used to generate bitmasks from numbers and arrays of groups, where groups are identified using numbers from 0 to 15.

The first argument is the group, or an array of groups, that the collider is a member of; the second argument is the group, or an array of groups, that the collider should interact with.

Here the collider is in group 0, and interacts with colliders from groups 0, 1 and 2:

<CapsuleCollider collisionGroups={interactionGroups(0, [0, 1, 2])} />

This collider is in multiple groups, but only interacts with colliders from a single group:

<CapsuleCollider collisionGroups={interactionGroups([0, 5], 7)} />

When the second argument is omitted, the collider will interact with all groups:

<CapsuleCollider collisionGroups={interactionGroups(12)} />

Note Please remember that in Rapier, for a collision (or solving) event to occur, both colliders involved in the event must match the related interaction groups -- a one-way match will be ignored.

Note By default, colliders are members of all groups, and will interact with all other groups.

Contact force events

Contact force events are triggered on <RigidBody> and any collider components when two objects collider.

<RigidBody
  colliders="ball"
  onContactForce={(payload) => {
    console.log(`The total force generated was: ${payload.totalForce}`);
  }}
>
  <Sphere>
    <meshPhysicalMaterial color={"grey"} />
  </Sphere>
</RigidBody>

The payload for the contact force event contains the following properties:

  • target
    CollisionTarget of the object firing the event
  • other
    CollisionTarget of the other object involved in the event
  • totalForce
    The sum of all the forces between the two colliders
  • totalForceMagnitude
    The sum of the magnitudes of each force between the two colliders
  • maxForceDirection
    The magnitude of the largest force at a contact point of this contact pair
  • maxForceMagnitude
    The world-space (unit) direction of the force with strongest magnitude

More information about each property can be found in the rapier TempContactForceEvent API documentation.

You can also add the onContactForce event to any collider.

<CapsuleCollider
  onContactForce={(payload) => {
    /* ... */
  }}
/>

Sensors

A Collider can be set to be a sensor, which means that it will not generate any contact points, and will not be affected by forces. This is useful for detecting when a collider enters or leaves another collider, without affecting the other collider.

To detect when a collider enters or leaves another collider, you can use the onIntersectionEnter and onIntersectionExit events on the collider.

🧩 See onIntersectionEnter / onIntersectionExit docs for more information.

<RigidBody>
  <GoalPosts />

  <CuboidCollider
    args={[5, 5, 1]}
    sensor
    onIntersectionEnter={() => console.log("Goal!")}
  />
</RigidBody>

🖼 Sensors Example

Configuring Time Step Size

By default, <Physics> will simulate the physics world at a fixed rate of 60 frames per second. This can be changed by setting the timeStep prop on <Physics>:

<Physics timeStep={1 / 30}>{/* ... */}</Physics>

The timeStep prop may also be set to "vary", which will cause the simulation's time step to adjust to every frame's frame delta:

<Physics timeStep="vary">{/* ... */}</Physics>

Note This is useful for games that run at variable frame rates, but may cause instability in the simulation. It also prevents the physics simulation from being fully deterministic. Please use with care!

Joints

Joints can be made between two RigidBodies to provide a way to restrict a motion of a body in relation to another.

Read more about joints in Rapier: https://rapier.rs/docs/user_guides/javascript/joints

Joints are available in r3/rapier as hooks.

There are 4 different joint types available:

  • Fixed (two bodies are fixed together)
  • Spherical (two bodies are connected by a ball and socket, for things like arms or chains)
  • Revolute (two bodies are connected by a hinge, for things like doors or wheels)
  • Prismatic (two bodies are connected by a sliding joint, for things like pistons or sliders)

Each joint hook returns a RefObject containing the raw reference to the joint instance.

const WheelJoint = ({ bodyA, bodyB }) => {
  const joint = useRevoluteJoint(bodyA, bodyB, [
    [0, 0, 0],
    [0, 0, 0],
    [0, 0, 0]
  ]);

  useFrame(() => {
    if (joint.current) {
      joint.current.configureMotorVelocity(10, 2);
    }
  }, []);

  return null;
};

Fixed Joint

A fixed joint ensures that two rigid-bodies don't move relative to each other. Fixed joints are characterized by one local frame (represented by an isometry) on each rigid-body. The fixed-joint makes these frames coincide in world-space.

🧩 See FixedJoint docs for available options.

const JointedThing = () => {
  const joint = useFixedJoint(bodyA, bodyB, [
    // Position of the joint in bodyA's local space
    [0, 0, 0],
    // Orientation of the joint in bodyA's local space
    [0, 0, 0, 1],
    // Position of the joint in bodyB's local space
    [0, 0, 0],
    // Orientation of the joint in bodyB's local space
    [0, 0, 0, 1]
  ]);

  return (
    <group>
      <RigidBody ref={bodyA}>
        <mesh />
      </RigidBody>
      <RigidBody ref={bodyB}>
        <mesh />
      </RigidBody>
    </group>
  );
};

Spherical Joint

The spherical joint ensures that two points on the local-spaces of two rigid-bodies always coincide (it prevents any relative translational motion at this points).

🧩 See SphericalJoint docs for available options.

const JointedThing = () => {
  const joint = useSphericalJoint(bodyA, bodyB, [
    // Position of the joint in bodyA's local space
    [0, 0, 0],
    // Position of the joint in bodyB's local space
    [0, 0, 0]
  ]);

  return (
    <group>
      <RigidBody ref={bodyA}>
        <mesh />
      </RigidBody>
      <RigidBody ref={bodyB}>
        <mesh />
      </RigidBody>
    </group>
  );
};

Revolute Joint

The revolute joint prevents any relative movement between two rigid-bodies, except for relative rotations along one axis. This is typically used to simulate wheels, fans, etc.

🧩 See RevoluteJoint docs for available options.

const JointedThing = () => {
  const joint = useRevoluteJoint(bodyA, bodyB, [
    // Position of the joint in bodyA's local space
    [0, 0, 0],
    // Position of the joint in bodyB's local space
    [0, 0, 0],
    // Axis of the joint, expressed in the local-space of
    // the rigid-bodies it is attached to. Cannot be [0,0,0].
    [0, 1, 0]
  ]);

  return (
    <group>
      <RigidBody ref={bodyA}>
        <mesh />
      </RigidBody>
      <RigidBody ref={bodyB}>
        <mesh />
      </RigidBody>
    </group>
  );
};

Prismatic Joint

The prismatic joint prevents any relative movement between two rigid-bodies, except for relative translations along one axis.

🧩 See PrismaticJoint docs for available options.

const JointedThing = () => {
  const joint = usePrismaticJoint(bodyA, bodyB, [
    // Position of the joint in bodyA's local space
    [0, 0, 0],
    // Position of the joint in bodyB's local space
    [0, 0, 0],
    // Axis of the joint, expressed in the local-space of
    // the rigid-bodies it is attached to. Cannot be [0,0,0].
    [0, 1, 0]
  ]);

  return (
    <group>
      <RigidBody ref={bodyA}>
        <mesh />
      </RigidBody>
      <RigidBody ref={bodyB}>
        <mesh />
      </RigidBody>
    </group>
  );
};

🖼 Joints Example

Advanced hooks usage

Advanced users might need granular access to the physics loop and direct access to the world instance. This can be done by using the following hooks:

  • useRapier
    Gives you access to the world, direct access to rapier, and more.
    🧩 See useRapier docs for more information.
  • useBeforePhysicsStep
    Allows you to run code before the physics simulation is stepped.
    🧩 See useBeforePhysicsStep docs for more information.
  • useAfterPhysicsStep Allows you to run code after the physics simulation is stepped.
    🧩 See useAfterPhysicsStep docs for more information.

Manual stepping

You can manually step the physics simulation by calling the step method from the useRapier hook.

const { step } = useRapier();

step(1 / 60);

On-demand rendering

By default @react-three/rapier will update the physics simulation when a frame renders. This is fine for most cases, but if you want to only render the scene when things have changed, you need to run the physics simulation independently from the render loop.

Setting <Physics updateLoop="independent" /> will make the physics simulation run in it's own requestAnimationFrame loop, and call invalidate on the canvas only when there are active (moving) bodies.

<Canvas frameloop="demand">
  <Physics updateLoop="independent">...</Physics>
</Canvas>

More Repositories

1

zustand

🐻 Bear necessities for state management in React
TypeScript
45,348
star
2

react-spring

✌️ A spring physics based React animation library
TypeScript
27,857
star
3

react-three-fiber

🇨🇭 A React renderer for Three.js
TypeScript
26,202
star
4

jotai

👻 Primitive and flexible state management for React
TypeScript
18,007
star
5

use-gesture

👇Bread n butter utility for component-tied mouse/touch gestures in React and Vanilla Javascript.
TypeScript
8,861
star
6

valtio

💊 Valtio makes proxy-state simple for React and Vanilla
TypeScript
8,738
star
7

drei

🥉 useful helpers for react-three-fiber
JavaScript
8,042
star
8

leva

🌋 React-first components GUI
TypeScript
4,825
star
9

gltfjsx

🎮 Turns GLTFs into JSX components
JavaScript
4,251
star
10

use-cannon

👋💣 physics based hooks for @react-three/fiber
TypeScript
2,700
star
11

react-three-next

React Three Fiber, Threejs, Nextjs starter
JavaScript
2,370
star
12

postprocessing

A post processing library for three.js.
JavaScript
2,263
star
13

racing-game

🏎 Open source racing game developed by everyone willing
TypeScript
2,120
star
14

xr

🤳 VR/AR for react-three-fiber
TypeScript
2,051
star
15

uikit

🎨 user interfaces for react-three-fiber
TypeScript
2,048
star
16

react-three-flex

💪📦 Flexbox for react-three-fiber
TypeScript
1,640
star
17

suspend-react

🚥 Async/await for React components
TypeScript
1,358
star
18

react-postprocessing

📬 postprocessing for react-three-fiber
JavaScript
1,074
star
19

detect-gpu

Classifies GPUs based on their 3D rendering benchmark score allowing the developer to provide sensible default settings for graphically intensive applications.
TypeScript
1,017
star
20

lamina

🍰 An extensible, layer based shader material for ThreeJS
TypeScript
1,005
star
21

its-fine

🐶🔥 A collection of escape hatches for React.
TypeScript
978
star
22

react-use-measure

🙌 Utility to measure view bounds
TypeScript
832
star
23

react-nil

⃝ A react null renderer
TypeScript
785
star
24

maath

🪶 Math helpers for the rest of us
TypeScript
783
star
25

threejs-journey

⚛️ Bruno Simons journey demos in React
TypeScript
718
star
26

three-stdlib

📚 Stand-alone library of threejs examples designed to run without transpilation in node & browser
JavaScript
651
star
27

react-three-editor

🔌 A one of a kind scene editor that writes changes back into your code
TypeScript
615
star
28

react-three-a11y

♿️ Accessibility tools for React Three Fiber
TypeScript
534
star
29

ecctrl

🕹️ A floating rigibody character controller
TypeScript
498
star
30

react-three-offscreen

📺 Offscreen worker canvas for react-three-fiber
TypeScript
443
star
31

react-zdog

⚡️🐶 React bindings for zdog
JavaScript
441
star
32

drei-vanilla

🍦 drei-inspired helpers for threejs
TypeScript
436
star
33

use-asset

📦 A promise caching strategy for React Suspense
TypeScript
413
star
34

tunnel-rat

🐀 Non gratum anus rodentum
TypeScript
329
star
35

react-three-csg

🚧 Constructive solid geometry for React
TypeScript
264
star
36

react-three-lgl

🔆 A React abstraction for the LGL Raycaster
TypeScript
262
star
37

gltf-react-three

Convert GLTF files to React Three Fiber Components
JavaScript
258
star
38

market

📦 Download CC0 assets ready to use in your next 3D Project
JavaScript
250
star
39

component-material

🧩 Compose modular materials in React
TypeScript
160
star
40

env

💄 An app to create, edit, and preview HDR environment maps in the browser
TypeScript
151
star
41

react-ogl

🦴 A barebones react renderer for ogl.
TypeScript
150
star
42

use-p2

👋💣 2d physics hooks for @react-three/fiber
TypeScript
144
star
43

react-spring-examples

JavaScript
139
star
44

react-three-gpu-pathtracer

⚡️ A React abstraction for the popular three-gpu-pathtracer
TypeScript
132
star
45

react-three-lightmap

In-browser lightmap/AO baker for react-three-fiber and ThreeJS
TypeScript
127
star
46

cannon-es-debugger

Wireframe debugger for use with cannon-es https://github.com/react-spring/cannon-es
HTML
102
star
47

rafz

💍 One loop to frame them all.
TypeScript
96
star
48

docs

🖨️ mdx documentation generator for `pmndrs/*/docs` folders
TypeScript
91
star
49

assets

📦 Importable base64 encoded CC0 assets
Makefile
91
star
50

swc-jotai

Rust
88
star
51

react-three-jolt

⚡ Jolt physics in React
TypeScript
84
star
52

react-three-scissor

✂ Multiple scenes, one canvas! WebGL Scissoring implementation for React Three Fiber.
TypeScript
79
star
53

eslint-plugin-valtio

An eslint plugin for better valtio experience
JavaScript
74
star
54

react-three-babel

🛍 A Babel plugin that automatically builds the extend catalogue of known native Three.js elements
TypeScript
60
star
55

react-spring.io

✌️ A spring physics based React animation library
TypeScript
56
star
56

r3f-website

Website for React Three Fiber
JavaScript
27
star
57

directed

A flexible, minimal scheduler written in TypeScript
TypeScript
24
star
58

market-assets

JavaScript
19
star
59

react-three-8thwall

JavaScript
17
star
60

drei-assets

JavaScript
16
star
61

discord

🤖 Poimandres Discord Bot
TypeScript
10
star
62

branding

TypeScript
7
star
63

market-assets-do

JavaScript
5
star
64

envinfo

Easily collect useful information for bug reports
JavaScript
4
star
65

leva-wg

1
star