@react-three/rapier 0.11.1 → 0.11.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -72,6 +72,7 @@ export declare type UseBodyOptions = Omit<UseRigidBodyOptions, "shape">;
72
72
  export declare type RigidBodyTypeString = "fixed" | "dynamic" | "kinematicPosition" | "kinematicVelocity";
73
73
  export declare type ColliderShape = "cuboid" | "trimesh" | "ball" | "capsule" | "convexHull" | "heightfield" | "polyline" | "roundCuboid" | "cylinder" | "roundCylinder" | "cone" | "roundCone" | "convexMesh" | "roundConvexHull" | "roundConvexMesh";
74
74
  export declare type Vector3Array = [x: number, y: number, z: number];
75
+ export declare type Vector4Array = [x: number, y: number, z: number, w: number];
75
76
  export declare type Boolean3Array = [x: boolean, y: boolean, z: boolean];
76
77
  export interface UseColliderOptions<ColliderArgs extends Array<unknown>> {
77
78
  /**
@@ -324,20 +325,22 @@ export declare type SphericalJointParams = [
324
325
  ];
325
326
  export declare type FixedJointParams = [
326
327
  body1Anchor: Vector3Array,
327
- body1LocalFrame: Vector3Array,
328
+ body1LocalFrame: Vector4Array,
328
329
  body2Anchor: Vector3Array,
329
- body2LocalFrame: Vector3Array
330
+ body2LocalFrame: Vector4Array
330
331
  ];
331
332
  export declare type PrismaticJointParams = [
332
333
  body1Anchor: Vector3Array,
333
334
  body1LocalFrame: Vector3Array,
334
335
  body2Anchor: Vector3Array,
335
- body2LocalFrame: Vector3Array
336
+ body2LocalFrame: Vector3Array,
337
+ limits?: [min: number, max: number]
336
338
  ];
337
339
  export declare type RevoluteJointParams = [
338
340
  body1Anchor: Vector3Array,
339
341
  body2Anchor: Vector3Array,
340
- axis: Vector3Array
342
+ axis: Vector3Array,
343
+ limits?: [min: number, max: number]
341
344
  ];
342
345
  export declare type RigidBodyApiRef = MutableRefObject<undefined | null | RigidBodyApi>;
343
346
  export interface UseImpulseJoint<P> {
@@ -2,6 +2,7 @@ import { Quaternion as RapierQuaternion, Vector3 as RapierVector3 } from "@dimfo
2
2
  import { Euler, Quaternion, Vector3 } from "three";
3
3
  import { RigidBodyTypeString, Vector3Array } from "./types";
4
4
  export declare const vectorArrayToVector3: (arr: Vector3Array) => Vector3;
5
+ export declare const tupleToObject: <T extends readonly any[], K extends readonly string[]>(tuple: T, keys: K) => { [Key in K[number]]: T[number]; };
5
6
  export declare const vector3ToQuaternion: (v: Vector3) => Quaternion;
6
7
  export declare const rapierVector3ToVector3: ({ x, y, z }: RapierVector3) => Vector3;
7
8
  export declare const rapierQuaternionToQuaternion: ({ x, y, z, w }: RapierQuaternion) => Quaternion;
@@ -85,6 +85,12 @@ const vectorArrayToVector3 = arr => {
85
85
  const [x, y, z] = arr;
86
86
  return new three.Vector3(x, y, z);
87
87
  };
88
+ const tupleToObject = (tuple, keys) => {
89
+ return keys.reduce((obj, key, i) => {
90
+ obj[key] = tuple[i];
91
+ return obj;
92
+ }, {});
93
+ };
88
94
  const rapierVector3ToVector3 = ({
89
95
  x,
90
96
  y,
@@ -590,10 +596,12 @@ const useColliderEvents = (collidersRef, props, events) => {
590
596
  };
591
597
 
592
598
  const rigidBodyDescFromOptions = options => {
599
+ var _options$canSleep;
600
+
593
601
  const type = rigidBodyTypeFromString((options === null || options === void 0 ? void 0 : options.type) || "dynamic");
594
602
  const desc = new rapier3dCompat.RigidBodyDesc(type); // Apply immutable options
595
603
 
596
- desc.canSleep = (options === null || options === void 0 ? void 0 : options.canSleep) || true;
604
+ desc.canSleep = (_options$canSleep = options === null || options === void 0 ? void 0 : options.canSleep) !== null && _options$canSleep !== void 0 ? _options$canSleep : true;
597
605
  return desc;
598
606
  };
599
607
  const createRigidBodyState = ({
@@ -858,11 +866,7 @@ const useFixedJoint = (body1, body2, [body1Anchor, body1LocalFrame, body2Anchor,
858
866
  const {
859
867
  rapier
860
868
  } = useRapier();
861
- return useImpulseJoint(body1, body2, rapier.JointData.fixed(vectorArrayToVector3(body1Anchor), _objectSpread2(_objectSpread2({}, vectorArrayToVector3(body1LocalFrame)), {}, {
862
- w: 1
863
- }), vectorArrayToVector3(body2Anchor), _objectSpread2(_objectSpread2({}, vectorArrayToVector3(body2LocalFrame)), {}, {
864
- w: 1
865
- })));
869
+ return useImpulseJoint(body1, body2, rapier.JointData.fixed(vectorArrayToVector3(body1Anchor), tupleToObject(body1LocalFrame, ["x", "y", "z", "w"]), vectorArrayToVector3(body2Anchor), tupleToObject(body2LocalFrame, ["x", "y", "z", "w"])));
866
870
  };
867
871
  /**
868
872
  * The spherical joint ensures that two points on the local-spaces of two rigid-bodies always coincide (it prevents any relative
@@ -883,11 +887,18 @@ const useSphericalJoint = (body1, body2, [body1Anchor, body2Anchor]) => {
883
887
  * They are characterized by one local anchor as well as one local axis on each rigid-body.
884
888
  */
885
889
 
886
- const useRevoluteJoint = (body1, body2, [body1Anchor, body2Anchor, axis]) => {
890
+ const useRevoluteJoint = (body1, body2, [body1Anchor, body2Anchor, axis, limits]) => {
887
891
  const {
888
892
  rapier
889
893
  } = useRapier();
890
- return useImpulseJoint(body1, body2, rapier.JointData.revolute(vectorArrayToVector3(body1Anchor), vectorArrayToVector3(body2Anchor), vectorArrayToVector3(axis)));
894
+ const params = rapier.JointData.revolute(vectorArrayToVector3(body1Anchor), vectorArrayToVector3(body2Anchor), vectorArrayToVector3(axis));
895
+
896
+ if (limits) {
897
+ params.limitsEnabled = true;
898
+ params.limits = limits;
899
+ }
900
+
901
+ return useImpulseJoint(body1, body2, params);
891
902
  };
892
903
  /**
893
904
  * The prismatic joint prevents any relative movement between two rigid-bodies, except for relative translations along one axis.
@@ -895,11 +906,18 @@ const useRevoluteJoint = (body1, body2, [body1Anchor, body2Anchor, axis]) => {
895
906
  * local tangent axis can be specified for each rigid-body.
896
907
  */
897
908
 
898
- const usePrismaticJoint = (body1, body2, [body1Anchor, body2Anchor, axis]) => {
909
+ const usePrismaticJoint = (body1, body2, [body1Anchor, body2Anchor, axis, limits]) => {
899
910
  const {
900
911
  rapier
901
912
  } = useRapier();
902
- return useImpulseJoint(body1, body2, rapier.JointData.prismatic(vectorArrayToVector3(body1Anchor), vectorArrayToVector3(body2Anchor), vectorArrayToVector3(axis)));
913
+ const params = rapier.JointData.prismatic(vectorArrayToVector3(body1Anchor), vectorArrayToVector3(body2Anchor), vectorArrayToVector3(axis));
914
+
915
+ if (limits) {
916
+ params.limitsEnabled = true;
917
+ params.limits = limits;
918
+ }
919
+
920
+ return useImpulseJoint(body1, body2, params);
903
921
  };
904
922
 
905
923
  const calcForceByType = {
@@ -85,6 +85,12 @@ const vectorArrayToVector3 = arr => {
85
85
  const [x, y, z] = arr;
86
86
  return new three.Vector3(x, y, z);
87
87
  };
88
+ const tupleToObject = (tuple, keys) => {
89
+ return keys.reduce((obj, key, i) => {
90
+ obj[key] = tuple[i];
91
+ return obj;
92
+ }, {});
93
+ };
88
94
  const rapierVector3ToVector3 = ({
89
95
  x,
90
96
  y,
@@ -590,10 +596,12 @@ const useColliderEvents = (collidersRef, props, events) => {
590
596
  };
591
597
 
592
598
  const rigidBodyDescFromOptions = options => {
599
+ var _options$canSleep;
600
+
593
601
  const type = rigidBodyTypeFromString((options === null || options === void 0 ? void 0 : options.type) || "dynamic");
594
602
  const desc = new rapier3dCompat.RigidBodyDesc(type); // Apply immutable options
595
603
 
596
- desc.canSleep = (options === null || options === void 0 ? void 0 : options.canSleep) || true;
604
+ desc.canSleep = (_options$canSleep = options === null || options === void 0 ? void 0 : options.canSleep) !== null && _options$canSleep !== void 0 ? _options$canSleep : true;
597
605
  return desc;
598
606
  };
599
607
  const createRigidBodyState = ({
@@ -858,11 +866,7 @@ const useFixedJoint = (body1, body2, [body1Anchor, body1LocalFrame, body2Anchor,
858
866
  const {
859
867
  rapier
860
868
  } = useRapier();
861
- return useImpulseJoint(body1, body2, rapier.JointData.fixed(vectorArrayToVector3(body1Anchor), _objectSpread2(_objectSpread2({}, vectorArrayToVector3(body1LocalFrame)), {}, {
862
- w: 1
863
- }), vectorArrayToVector3(body2Anchor), _objectSpread2(_objectSpread2({}, vectorArrayToVector3(body2LocalFrame)), {}, {
864
- w: 1
865
- })));
869
+ return useImpulseJoint(body1, body2, rapier.JointData.fixed(vectorArrayToVector3(body1Anchor), tupleToObject(body1LocalFrame, ["x", "y", "z", "w"]), vectorArrayToVector3(body2Anchor), tupleToObject(body2LocalFrame, ["x", "y", "z", "w"])));
866
870
  };
867
871
  /**
868
872
  * The spherical joint ensures that two points on the local-spaces of two rigid-bodies always coincide (it prevents any relative
@@ -883,11 +887,18 @@ const useSphericalJoint = (body1, body2, [body1Anchor, body2Anchor]) => {
883
887
  * They are characterized by one local anchor as well as one local axis on each rigid-body.
884
888
  */
885
889
 
886
- const useRevoluteJoint = (body1, body2, [body1Anchor, body2Anchor, axis]) => {
890
+ const useRevoluteJoint = (body1, body2, [body1Anchor, body2Anchor, axis, limits]) => {
887
891
  const {
888
892
  rapier
889
893
  } = useRapier();
890
- return useImpulseJoint(body1, body2, rapier.JointData.revolute(vectorArrayToVector3(body1Anchor), vectorArrayToVector3(body2Anchor), vectorArrayToVector3(axis)));
894
+ const params = rapier.JointData.revolute(vectorArrayToVector3(body1Anchor), vectorArrayToVector3(body2Anchor), vectorArrayToVector3(axis));
895
+
896
+ if (limits) {
897
+ params.limitsEnabled = true;
898
+ params.limits = limits;
899
+ }
900
+
901
+ return useImpulseJoint(body1, body2, params);
891
902
  };
892
903
  /**
893
904
  * The prismatic joint prevents any relative movement between two rigid-bodies, except for relative translations along one axis.
@@ -895,11 +906,18 @@ const useRevoluteJoint = (body1, body2, [body1Anchor, body2Anchor, axis]) => {
895
906
  * local tangent axis can be specified for each rigid-body.
896
907
  */
897
908
 
898
- const usePrismaticJoint = (body1, body2, [body1Anchor, body2Anchor, axis]) => {
909
+ const usePrismaticJoint = (body1, body2, [body1Anchor, body2Anchor, axis, limits]) => {
899
910
  const {
900
911
  rapier
901
912
  } = useRapier();
902
- return useImpulseJoint(body1, body2, rapier.JointData.prismatic(vectorArrayToVector3(body1Anchor), vectorArrayToVector3(body2Anchor), vectorArrayToVector3(axis)));
913
+ const params = rapier.JointData.prismatic(vectorArrayToVector3(body1Anchor), vectorArrayToVector3(body2Anchor), vectorArrayToVector3(axis));
914
+
915
+ if (limits) {
916
+ params.limitsEnabled = true;
917
+ params.limits = limits;
918
+ }
919
+
920
+ return useImpulseJoint(body1, body2, params);
903
921
  };
904
922
 
905
923
  const calcForceByType = {
@@ -60,6 +60,12 @@ const vectorArrayToVector3 = arr => {
60
60
  const [x, y, z] = arr;
61
61
  return new Vector3(x, y, z);
62
62
  };
63
+ const tupleToObject = (tuple, keys) => {
64
+ return keys.reduce((obj, key, i) => {
65
+ obj[key] = tuple[i];
66
+ return obj;
67
+ }, {});
68
+ };
63
69
  const rapierVector3ToVector3 = ({
64
70
  x,
65
71
  y,
@@ -565,10 +571,12 @@ const useColliderEvents = (collidersRef, props, events) => {
565
571
  };
566
572
 
567
573
  const rigidBodyDescFromOptions = options => {
574
+ var _options$canSleep;
575
+
568
576
  const type = rigidBodyTypeFromString((options === null || options === void 0 ? void 0 : options.type) || "dynamic");
569
577
  const desc = new RigidBodyDesc(type); // Apply immutable options
570
578
 
571
- desc.canSleep = (options === null || options === void 0 ? void 0 : options.canSleep) || true;
579
+ desc.canSleep = (_options$canSleep = options === null || options === void 0 ? void 0 : options.canSleep) !== null && _options$canSleep !== void 0 ? _options$canSleep : true;
572
580
  return desc;
573
581
  };
574
582
  const createRigidBodyState = ({
@@ -833,11 +841,7 @@ const useFixedJoint = (body1, body2, [body1Anchor, body1LocalFrame, body2Anchor,
833
841
  const {
834
842
  rapier
835
843
  } = useRapier();
836
- return useImpulseJoint(body1, body2, rapier.JointData.fixed(vectorArrayToVector3(body1Anchor), _objectSpread2(_objectSpread2({}, vectorArrayToVector3(body1LocalFrame)), {}, {
837
- w: 1
838
- }), vectorArrayToVector3(body2Anchor), _objectSpread2(_objectSpread2({}, vectorArrayToVector3(body2LocalFrame)), {}, {
839
- w: 1
840
- })));
844
+ return useImpulseJoint(body1, body2, rapier.JointData.fixed(vectorArrayToVector3(body1Anchor), tupleToObject(body1LocalFrame, ["x", "y", "z", "w"]), vectorArrayToVector3(body2Anchor), tupleToObject(body2LocalFrame, ["x", "y", "z", "w"])));
841
845
  };
842
846
  /**
843
847
  * The spherical joint ensures that two points on the local-spaces of two rigid-bodies always coincide (it prevents any relative
@@ -858,11 +862,18 @@ const useSphericalJoint = (body1, body2, [body1Anchor, body2Anchor]) => {
858
862
  * They are characterized by one local anchor as well as one local axis on each rigid-body.
859
863
  */
860
864
 
861
- const useRevoluteJoint = (body1, body2, [body1Anchor, body2Anchor, axis]) => {
865
+ const useRevoluteJoint = (body1, body2, [body1Anchor, body2Anchor, axis, limits]) => {
862
866
  const {
863
867
  rapier
864
868
  } = useRapier();
865
- return useImpulseJoint(body1, body2, rapier.JointData.revolute(vectorArrayToVector3(body1Anchor), vectorArrayToVector3(body2Anchor), vectorArrayToVector3(axis)));
869
+ const params = rapier.JointData.revolute(vectorArrayToVector3(body1Anchor), vectorArrayToVector3(body2Anchor), vectorArrayToVector3(axis));
870
+
871
+ if (limits) {
872
+ params.limitsEnabled = true;
873
+ params.limits = limits;
874
+ }
875
+
876
+ return useImpulseJoint(body1, body2, params);
866
877
  };
867
878
  /**
868
879
  * The prismatic joint prevents any relative movement between two rigid-bodies, except for relative translations along one axis.
@@ -870,11 +881,18 @@ const useRevoluteJoint = (body1, body2, [body1Anchor, body2Anchor, axis]) => {
870
881
  * local tangent axis can be specified for each rigid-body.
871
882
  */
872
883
 
873
- const usePrismaticJoint = (body1, body2, [body1Anchor, body2Anchor, axis]) => {
884
+ const usePrismaticJoint = (body1, body2, [body1Anchor, body2Anchor, axis, limits]) => {
874
885
  const {
875
886
  rapier
876
887
  } = useRapier();
877
- return useImpulseJoint(body1, body2, rapier.JointData.prismatic(vectorArrayToVector3(body1Anchor), vectorArrayToVector3(body2Anchor), vectorArrayToVector3(axis)));
888
+ const params = rapier.JointData.prismatic(vectorArrayToVector3(body1Anchor), vectorArrayToVector3(body2Anchor), vectorArrayToVector3(axis));
889
+
890
+ if (limits) {
891
+ params.limitsEnabled = true;
892
+ params.limits = limits;
893
+ }
894
+
895
+ return useImpulseJoint(body1, body2, params);
878
896
  };
879
897
 
880
898
  const calcForceByType = {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@react-three/rapier",
3
- "version": "0.11.1",
3
+ "version": "0.11.3",
4
4
  "source": "src/index.ts",
5
5
  "main": "dist/react-three-rapier.cjs.js",
6
6
  "module": "dist/react-three-rapier.esm.js",
package/readme.md CHANGED
@@ -7,9 +7,17 @@
7
7
  <a href="https://discord.gg/ZZjjNvJ"><img src="https://img.shields.io/discord/740090768164651008?style=for-the-badge&colorA=0099DA&colorB=ffffff&label=discord&logo=discord&logoColor=ffffff" /></a>
8
8
  </p>
9
9
 
10
- <p align="center">⚠️ Under heavy development. All APIs are subject to change. ⚠️</p>
10
+ <p align="center">⚠️ Under heavy development. All APIs are subject to change. ⚠️
11
+ <br />
12
+ For contributions, please read the <a href="https://github.com/pmndrs/react-three-rapier/blob/main/packages/react-three-rapier/CONTRIBUTING.md">Contribution Guide</a>.
13
+ </p>
14
+
15
+ ---
16
+
17
+ `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.
18
+
19
+ The goal of this library to is to provide a fast physics engine with minimal friction and small, straight forward API.
11
20
 
12
- For contributions, please read the [contributing guide](https://github.com/pmndrs/react-three-rapier/blob/main/packages/react-three-rapier/CONTRIBUTING.md).
13
21
 
14
22
  ## Basic Usage
15
23
 
@@ -27,7 +35,7 @@ const App = () => {
27
35
  <Torus />
28
36
  </RigidBody>
29
37
 
30
- <CuboidCollider position={[0, -2, 0]} args={[20, .5, 20]}>
38
+ <CuboidCollider position={[0, -2, 0]} args={[20, .5, 20]} />
31
39
 
32
40
  <Debug />
33
41
  </Physics>
@@ -58,6 +66,11 @@ const App = () => {
58
66
  - [Configuring Time Step Size](#configuring-time-step-size)
59
67
  - [Manual stepping](#manual-stepping)
60
68
  - [Joints](#joints)
69
+ - [Fixed Joint](#fixed-joint)
70
+ - [Spherical Joint](#spherical-joint)
71
+ - [Revolute Joint](#revolute-joint)
72
+ - [Prismatic Joint](#prismatic-joint)
73
+ - [Joint APIs](#joint-apis)
61
74
  - [Joints Example](#joints-example)
62
75
 
63
76
  ---
@@ -200,11 +213,15 @@ const Scene = () => {
200
213
  const instancedApi = useRef<InstancedRigidBodyApi>(null);
201
214
 
202
215
  useEffect(() => {
216
+ if (!instancedApi.current) {
217
+ return
218
+ }
219
+
203
220
  // You can access individual instanced by their index
204
- instancedApi.at(40).applyImpulse({ x: 0, y: 10, z: 0 });
221
+ instancedApi.current.at(40).applyImpulse({ x: 0, y: 10, z: 0 });
205
222
 
206
223
  // Or update all instances as if they were in an array
207
- instancedApi.forEach((api) => {
224
+ instancedApi.current.forEach((api) => {
208
225
  api.applyImpulse({ x: 0, y: 10, z: 0 });
209
226
  });
210
227
  }, []);
@@ -379,7 +396,7 @@ Contact force events are triggered on `<RigidBody>` and any collider components
379
396
  console.log(`The total force generated was: ${payload.totalForce}`);
380
397
  }}>
381
398
  <Sphere>
382
- <meshPhysicalMaterial color={'grey'}>
399
+ <meshPhysicalMaterial color={'grey'} />
383
400
  </Sphere>
384
401
  </RigidBody>
385
402
  ```
@@ -496,8 +513,143 @@ step(1 / 60);
496
513
  ```
497
514
 
498
515
  ## Joints
516
+ Joints can be made between two `RigidBodies` to provide a way to restrict a motion of a body in relation to another.
517
+ > Read more about joints in Rapier: https://rapier.rs/docs/user_guides/javascript/joints
518
+
519
+ Joints are available in `r3/rapier` as hooks.
520
+
521
+ There are 4 different joint types available:
522
+ - Fixed (two bodies are fixed together)
523
+ - Spherical (two bodies are connected by a ball and socket, for things like arms or chains)
524
+ - Revolute (two bodies are connected by a hinge, for things like doors or wheels)
525
+ - Prismatic (two bodies are connected by a sliding joint, for things like pistons or sliders)
526
+
527
+ ### Fixed Joint
528
+ 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.
529
+
530
+ ```tsx
531
+ const JointedThing = () => {
532
+ const joint = useFixedJoint(
533
+ bodyA,
534
+ bodyB,
535
+ [
536
+ [0, 0, 0], // Position of the joint in bodyA's local space
537
+ [0, 0, 0, 1], // Orientation of the joint in bodyA's local space
538
+ [0, 0, 0], // Position of the joint in bodyB's local space
539
+ [0, 0, 0, 1], // Orientation of the joint in bodyB's local space
540
+ ]);
541
+
542
+ return (
543
+ <group>
544
+ <RigidBody ref={bodyA}>
545
+ <mesh />
546
+ </RigidBody>
547
+ <RigidBody ref={bodyB}>
548
+ <mesh />
549
+ </RigidBody>
550
+ </group>
551
+ );
552
+ }
553
+ ```
554
+
555
+ ### Spherical Joint
556
+ 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).
557
+
558
+ ```tsx
559
+ const JointedThing = () => {
560
+ const joint = useSphericalJoint(
561
+ bodyA,
562
+ bodyB,
563
+ [
564
+ [0, 0, 0], // Position of the joint in bodyA's local space
565
+ [0, 0, 0], // Position of the joint in bodyB's local space
566
+ ]);
567
+
568
+ return (
569
+ <group>
570
+ <RigidBody ref={bodyA}>
571
+ <mesh />
572
+ </RigidBody>
573
+ <RigidBody ref={bodyB}>
574
+ <mesh />
575
+ </RigidBody>
576
+ </group>
577
+ );
578
+ }
579
+ ```
580
+
581
+ ### Revolute Joint
582
+ 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.
583
+
584
+ ```tsx
585
+ const JointedThing = () => {
586
+ const joint = useRevoluteJoint(
587
+ bodyA,
588
+ bodyB,
589
+ [
590
+ [0, 0, 0], // Position of the joint in bodyA's local space
591
+ [0, 0, 0], // Position of the joint in bodyB's local space
592
+ [0, 0, 0], // Axis of the joint, expressed in the local-space of the rigid-bodies it is attached to.
593
+ ]);
594
+
595
+ return (
596
+ <group>
597
+ <RigidBody ref={bodyA}>
598
+ <mesh />
599
+ </RigidBody>
600
+ <RigidBody ref={bodyB}>
601
+ <mesh />
602
+ </RigidBody>
603
+ </group>
604
+ );
605
+ }
606
+ ```
607
+
608
+ ### Prismatic Joint
609
+ The prismatic joint prevents any relative movement between two rigid-bodies, except for relative translations along one axis.
610
+
611
+ ```tsx
612
+ const JointedThing = () => {
613
+ const joint = usePrismaticJoint(
614
+ bodyA,
615
+ bodyB,
616
+ [
617
+ [0, 0, 0], // Position of the joint in bodyA's local space
618
+ [0, 0, 0], // Position of the joint in bodyB's local space
619
+ [0, 0, 0], // Axis of the joint, expressed in the local-space of the rigid-bodies it is attached to.
620
+ ]);
621
+
622
+ return (
623
+ <group>
624
+ <RigidBody ref={bodyA}>
625
+ <mesh />
626
+ </RigidBody>
627
+ <RigidBody ref={bodyB}>
628
+ <mesh />
629
+ </RigidBody>
630
+ </group>
631
+ );
632
+ }
633
+ ```
634
+
635
+ ### Joint APIs
636
+ Joints can be controlled imperatively similarily to how `RigidBody` components can be controlled.
637
+
638
+ ```tsx
639
+ const JointedThing = () => {
640
+ const joint = useSphericalJoint(...)
641
+
642
+ useEffect(() => {
643
+ joint.configureMotorVelocity(1, 0)
644
+
645
+ // Disable contacts between the two joint bodies
646
+ joint.raw().setContactsEnabled(false)
647
+ }, [])
648
+
649
+ return ...
650
+ }
651
+ ```
499
652
 
500
- - WIP
501
653
 
502
654
  ### Joints Example
503
- <a href="https://codesandbox.io/s/react-three-rapier-sensors-byjmsk"><img src="https://raw.githubusercontent.com/pmndrs/react-three-rapier/HEAD/packages/react-three-rapier/misc/example-joints.jpg" width="240" /></a>
655
+ <a href="https://codesandbox.io/s/react-three-rapier-joints-mhhbd4"><img src="https://raw.githubusercontent.com/pmndrs/react-three-rapier/HEAD/packages/react-three-rapier/misc/example-joints.jpg" width="240" /></a>