@react-three/rapier 0.11.3 → 0.12.0

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.
@@ -4,7 +4,7 @@ Object.defineProperty(exports, '__esModule', { value: true });
4
4
 
5
5
  var rapier3dCompat = require('@dimforge/rapier3d-compat');
6
6
  var fiber = require('@react-three/fiber');
7
- var React = require('react');
7
+ var React$1 = require('react');
8
8
  var three = require('three');
9
9
  var useAsset = require('use-asset');
10
10
  var threeStdlib = require('three-stdlib');
@@ -29,7 +29,7 @@ function _interopNamespace(e) {
29
29
  return Object.freeze(n);
30
30
  }
31
31
 
32
- var React__default = /*#__PURE__*/_interopDefault(React);
32
+ var React__default = /*#__PURE__*/_interopDefault(React$1);
33
33
 
34
34
  function _defineProperty(obj, key, value) {
35
35
  if (key in obj) {
@@ -138,7 +138,7 @@ const vectorToTuple = v => {
138
138
  return [v];
139
139
  };
140
140
  function useConst(initialValue) {
141
- const ref = React.useRef();
141
+ const ref = React$1.useRef();
142
142
 
143
143
  if (ref.current === undefined) {
144
144
  ref.current = {
@@ -248,7 +248,7 @@ const createInstancedRigidBodiesApi = bodiesGetter => ({
248
248
  return bodiesGetter.current().length;
249
249
  }
250
250
 
251
- }); // TODO: Flesh this out
251
+ });
252
252
  const createWorldApi = ref => {
253
253
  return {
254
254
  raw: () => ref.current(),
@@ -281,8 +281,7 @@ const createWorldApi = ref => {
281
281
  },
282
282
  debugRender: () => ref.current().debugRender()
283
283
  };
284
- }; // TODO: Broken currently, waiting for Rapier3D to fix
285
-
284
+ };
286
285
  const createJointApi = ref => {
287
286
  return {
288
287
  raw: () => ref.current(),
@@ -427,10 +426,10 @@ const setColliderOptions = (collider, options, states) => {
427
426
  };
428
427
  const useUpdateColliderOptions = (collidersRef, props, states) => {
429
428
  // TODO: Improve this, split each prop into its own effect
430
- const mutablePropsAsFlatArray = React.useMemo(() => mutableColliderOptionKeys.flatMap(key => {
429
+ const mutablePropsAsFlatArray = React$1.useMemo(() => mutableColliderOptionKeys.flatMap(key => {
431
430
  return vectorToTuple(props[key]);
432
431
  }), [props]);
433
- React.useEffect(() => {
432
+ React$1.useEffect(() => {
434
433
  collidersRef.current.forEach(collider => {
435
434
  setColliderOptions(collider, props, states);
436
435
  });
@@ -564,7 +563,7 @@ const useColliderEvents = (collidersRef, props, events) => {
564
563
  onIntersectionExit,
565
564
  onContactForce
566
565
  } = props;
567
- React.useEffect(() => {
566
+ React$1.useEffect(() => {
568
567
  var _collidersRef$current;
569
568
 
570
569
  (_collidersRef$current = collidersRef.current) === null || _collidersRef$current === void 0 ? void 0 : _collidersRef$current.forEach(collider => {
@@ -704,10 +703,10 @@ const setRigidBodyOptions = (rigidBody, options, states, updateTranslations = tr
704
703
  };
705
704
  const useUpdateRigidBodyOptions = (rigidBodyRef, props, states, updateTranslations = true) => {
706
705
  // TODO: Improve this, split each prop into its own effect
707
- const mutablePropsAsFlatArray = React.useMemo(() => mutableRigidBodyOptionKeys.flatMap(key => {
706
+ const mutablePropsAsFlatArray = React$1.useMemo(() => mutableRigidBodyOptionKeys.flatMap(key => {
708
707
  return vectorToTuple(props[key]);
709
708
  }), [props]);
710
- React.useEffect(() => {
709
+ React$1.useEffect(() => {
711
710
  if (Array.isArray(rigidBodyRef.current)) {
712
711
  for (const rigidBody of rigidBodyRef.current) {
713
712
  setRigidBodyOptions(rigidBody, props, states, updateTranslations);
@@ -734,7 +733,7 @@ const useRigidBodyEvents = (rigidBodyRef, props, events) => {
734
733
  onIntersectionEnter,
735
734
  onIntersectionExit
736
735
  };
737
- React.useEffect(() => {
736
+ React$1.useEffect(() => {
738
737
  if (Array.isArray(rigidBodyRef.current)) {
739
738
  for (const rigidBody of rigidBodyRef.current) {
740
739
  events.set(rigidBody.handle, eventHandlers);
@@ -756,11 +755,34 @@ const useRigidBodyEvents = (rigidBodyRef, props, events) => {
756
755
  };
757
756
 
758
757
  const useRapier = () => {
759
- return React.useContext(RapierContext);
758
+ return React$1.useContext(rapierContext);
759
+ };
760
+ const useBeforePhysicsStep = callback => {
761
+ const {
762
+ beforeStepCallbacks
763
+ } = useRapier();
764
+ React$1.useEffect(() => {
765
+ beforeStepCallbacks.add(callback);
766
+ return () => {
767
+ beforeStepCallbacks.delete(callback);
768
+ };
769
+ }, []);
760
770
  };
771
+ const useAfterPhysicsStep = callback => {
772
+ const {
773
+ afterStepCallbacks
774
+ } = useRapier();
775
+ React$1.useEffect(() => {
776
+ afterStepCallbacks.add(callback);
777
+ return () => {
778
+ afterStepCallbacks.delete(callback);
779
+ };
780
+ }, []);
781
+ }; // Internal hooks
782
+
761
783
  const useChildColliderProps = (ref, options, ignoreMeshColliders = true) => {
762
- const [colliderProps, setColliderProps] = React.useState([]);
763
- React.useEffect(() => {
784
+ const [colliderProps, setColliderProps] = React$1.useState([]);
785
+ React$1.useEffect(() => {
764
786
  const object = ref.current;
765
787
 
766
788
  if (object && options.colliders !== false) {
@@ -780,16 +802,16 @@ const useRigidBody = (options = {}) => {
780
802
  physicsOptions,
781
803
  rigidBodyEvents
782
804
  } = useRapier();
783
- const ref = React.useRef();
784
- const mergedOptions = React.useMemo(() => {
805
+ const ref = React$1.useRef();
806
+ const mergedOptions = React$1.useMemo(() => {
785
807
  return _objectSpread2(_objectSpread2(_objectSpread2({}, physicsOptions), options), {}, {
786
808
  children: undefined
787
809
  });
788
810
  }, [physicsOptions, options]);
789
811
  const childColliderProps = useChildColliderProps(ref, mergedOptions); // Create rigidbody
790
812
 
791
- const rigidBodyRef = React.useRef();
792
- const getRigidBodyRef = React.useRef(() => {
813
+ const rigidBodyRef = React$1.useRef();
814
+ const getRigidBodyRef = React$1.useRef(() => {
793
815
  if (!rigidBodyRef.current) {
794
816
  const desc = rigidBodyDescFromOptions(options);
795
817
  const rigidBody = world.createRigidBody(desc);
@@ -799,7 +821,7 @@ const useRigidBody = (options = {}) => {
799
821
  return rigidBodyRef.current;
800
822
  }); // Setup
801
823
 
802
- React.useEffect(() => {
824
+ React$1.useEffect(() => {
803
825
  const rigidBody = getRigidBodyRef.current();
804
826
  rigidBodyRef.current = rigidBody;
805
827
 
@@ -819,105 +841,8 @@ const useRigidBody = (options = {}) => {
819
841
  }, []);
820
842
  useUpdateRigidBodyOptions(rigidBodyRef, mergedOptions, rigidBodyStates);
821
843
  useRigidBodyEvents(rigidBodyRef, mergedOptions, rigidBodyEvents);
822
- const api = React.useMemo(() => createRigidBodyApi(getRigidBodyRef), []);
844
+ const api = React$1.useMemo(() => createRigidBodyApi(getRigidBodyRef), []);
823
845
  return [ref, api, childColliderProps];
824
- }; // Joints
825
-
826
- const useImpulseJoint = (body1, body2, params) => {
827
- const {
828
- world
829
- } = useRapier();
830
- const jointRef = React.useRef();
831
- const getJointRef = React.useRef(() => {
832
- if (!jointRef.current) {
833
- let rb1;
834
- let rb2;
835
-
836
- if ("current" in body1 && body1.current && "current" in body2 && body2.current) {
837
- rb1 = world.getRigidBody(body1.current.handle);
838
- rb2 = world.getRigidBody(body2.current.handle);
839
- const newJoint = world.createImpulseJoint(params, rb1, rb2);
840
- jointRef.current = newJoint;
841
- }
842
- }
843
-
844
- return jointRef.current;
845
- });
846
- React.useEffect(() => {
847
- const joint = getJointRef.current();
848
- return () => {
849
- if (joint) {
850
- world.removeImpulseJoint(joint);
851
- jointRef.current = undefined;
852
- }
853
- };
854
- }, []);
855
- const api = React.useMemo(() => createJointApi(getJointRef), []);
856
- return api;
857
- };
858
- /**
859
- *
860
- * A fixed joint ensures that two rigid-bodies don't move relative to each other.
861
- * Fixed joints are characterized by one local frame (represented by an isometry) on each rigid-body.
862
- * The fixed-joint makes these frames coincide in world-space.
863
- */
864
-
865
- const useFixedJoint = (body1, body2, [body1Anchor, body1LocalFrame, body2Anchor, body2LocalFrame]) => {
866
- const {
867
- rapier
868
- } = useRapier();
869
- return useImpulseJoint(body1, body2, rapier.JointData.fixed(vectorArrayToVector3(body1Anchor), tupleToObject(body1LocalFrame, ["x", "y", "z", "w"]), vectorArrayToVector3(body2Anchor), tupleToObject(body2LocalFrame, ["x", "y", "z", "w"])));
870
- };
871
- /**
872
- * The spherical joint ensures that two points on the local-spaces of two rigid-bodies always coincide (it prevents any relative
873
- * translational motion at this points). This is typically used to simulate ragdolls arms, pendulums, etc.
874
- * They are characterized by one local anchor on each rigid-body. Each anchor represents the location of the
875
- * points that need to coincide on the local-space of each rigid-body.
876
- */
877
-
878
- const useSphericalJoint = (body1, body2, [body1Anchor, body2Anchor]) => {
879
- const {
880
- rapier
881
- } = useRapier();
882
- return useImpulseJoint(body1, body2, rapier.JointData.spherical(vectorArrayToVector3(body1Anchor), vectorArrayToVector3(body2Anchor)));
883
- };
884
- /**
885
- * The revolute joint prevents any relative movement between two rigid-bodies, except for relative
886
- * rotations along one axis. This is typically used to simulate wheels, fans, etc.
887
- * They are characterized by one local anchor as well as one local axis on each rigid-body.
888
- */
889
-
890
- const useRevoluteJoint = (body1, body2, [body1Anchor, body2Anchor, axis, limits]) => {
891
- const {
892
- rapier
893
- } = useRapier();
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);
902
- };
903
- /**
904
- * The prismatic joint prevents any relative movement between two rigid-bodies, except for relative translations along one axis.
905
- * It is characterized by one local anchor as well as one local axis on each rigid-body. In 3D, an optional
906
- * local tangent axis can be specified for each rigid-body.
907
- */
908
-
909
- const usePrismaticJoint = (body1, body2, [body1Anchor, body2Anchor, axis, limits]) => {
910
- const {
911
- rapier
912
- } = useRapier();
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);
921
846
  };
922
847
 
923
848
  const calcForceByType = {
@@ -966,7 +891,7 @@ const applyAttractorForceOnRigidBody = (rigidBody, {
966
891
  }
967
892
  }
968
893
  };
969
- const Attractor = /*#__PURE__*/React.memo(props => {
894
+ const Attractor = /*#__PURE__*/React$1.memo(props => {
970
895
  const {
971
896
  position = [0, 0, 0],
972
897
  strength = 1,
@@ -978,8 +903,8 @@ const Attractor = /*#__PURE__*/React.memo(props => {
978
903
  const {
979
904
  attractorStates
980
905
  } = useRapier();
981
- const object = React.useRef(null);
982
- React.useEffect(() => {
906
+ const object = React$1.useRef(null);
907
+ React$1.useEffect(() => {
983
908
  var _object$current;
984
909
 
985
910
  let uuid = ((_object$current = object.current) === null || _object$current === void 0 ? void 0 : _object$current.uuid) || "_";
@@ -1005,7 +930,7 @@ const Attractor = /*#__PURE__*/React.memo(props => {
1005
930
  });
1006
931
  });
1007
932
 
1008
- const RapierContext = /*#__PURE__*/React.createContext(undefined);
933
+ const rapierContext = /*#__PURE__*/React$1.createContext(undefined);
1009
934
 
1010
935
  const getCollisionPayloadFromSource = (target, other) => {
1011
936
  var _target$collider$stat, _target$rigidBody$sta, _other$collider$state, _other$rigidBody$stat, _other$collider$state2, _other$rigidBody$stat2;
@@ -1046,8 +971,8 @@ const Physics = ({
1046
971
  interpolate: _interpolate = true
1047
972
  }) => {
1048
973
  const rapier = useAsset.useAsset(importRapier);
1049
- const worldRef = React.useRef();
1050
- const getWorldRef = React.useRef(() => {
974
+ const worldRef = React$1.useRef();
975
+ const getWorldRef = React$1.useRef(() => {
1051
976
  if (!worldRef.current) {
1052
977
  const world = new rapier.World(vectorArrayToVector3(_gravity));
1053
978
  worldRef.current = world;
@@ -1060,9 +985,11 @@ const Physics = ({
1060
985
  const rigidBodyEvents = useConst(() => new Map());
1061
986
  const colliderEvents = useConst(() => new Map());
1062
987
  const eventQueue = useConst(() => new rapier3dCompat.EventQueue(false));
1063
- const attractorStates = useConst(() => new Map()); // Init world
988
+ const attractorStates = useConst(() => new Map());
989
+ const beforeStepCallbacks = useConst(() => new Set());
990
+ const afterStepCallbacks = useConst(() => new Set()); // Init world
1064
991
 
1065
- React.useEffect(() => {
992
+ React$1.useEffect(() => {
1066
993
  const world = getWorldRef.current();
1067
994
  return () => {
1068
995
  if (world) {
@@ -1072,14 +999,15 @@ const Physics = ({
1072
999
  };
1073
1000
  }, []); // Update gravity
1074
1001
 
1075
- React.useEffect(() => {
1002
+ React$1.useEffect(() => {
1076
1003
  const world = worldRef.current;
1077
1004
 
1078
1005
  if (world) {
1079
1006
  world.gravity = vectorArrayToVector3(_gravity);
1080
1007
  }
1081
1008
  }, [_gravity]);
1082
- const getSourceFromColliderHandle = React.useCallback(handle => {
1009
+ const api = React$1.useMemo(() => createWorldApi(getWorldRef), []);
1010
+ const getSourceFromColliderHandle = React$1.useCallback(handle => {
1083
1011
  const world = worldRef.current;
1084
1012
 
1085
1013
  if (world) {
@@ -1107,11 +1035,11 @@ const Physics = ({
1107
1035
  return source;
1108
1036
  }
1109
1037
  }, []);
1110
- const [steppingState] = React.useState({
1038
+ const [steppingState] = React$1.useState({
1111
1039
  previousState: {},
1112
1040
  accumulator: 0
1113
1041
  });
1114
- const step = React.useCallback(dt => {
1042
+ const step = React$1.useCallback(dt => {
1115
1043
  const world = worldRef.current;
1116
1044
  if (!world) return;
1117
1045
  /* Check if the timestep is supposed to be variable. We'll do this here
@@ -1125,9 +1053,21 @@ const Physics = ({
1125
1053
 
1126
1054
  const clampedDelta = three.MathUtils.clamp(dt, 0, 0.2);
1127
1055
 
1056
+ const stepWorld = () => {
1057
+ // Trigger beforeStep callbacks
1058
+ beforeStepCallbacks.forEach(callback => {
1059
+ callback(api);
1060
+ });
1061
+ world.step(eventQueue); // Trigger afterStep callbacks
1062
+
1063
+ afterStepCallbacks.forEach(callback => {
1064
+ callback(api);
1065
+ });
1066
+ };
1067
+
1128
1068
  if (timeStepVariable) {
1129
1069
  world.timestep = clampedDelta;
1130
- world.step(eventQueue);
1070
+ stepWorld();
1131
1071
  } else {
1132
1072
  world.timestep = _timeStep; // don't step time forwards if paused
1133
1073
  // Increase accumulator
@@ -1151,7 +1091,7 @@ const Physics = ({
1151
1091
  applyAttractorForceOnRigidBody(body, attractorState);
1152
1092
  });
1153
1093
  });
1154
- world.step(eventQueue);
1094
+ stepWorld();
1155
1095
  steppingState.accumulator -= _timeStep;
1156
1096
  }
1157
1097
  }
@@ -1314,8 +1254,7 @@ const Physics = ({
1314
1254
  fiber.useFrame((_, dt) => {
1315
1255
  if (!_paused) step(dt);
1316
1256
  }, updatePriority);
1317
- const api = React.useMemo(() => createWorldApi(getWorldRef), []);
1318
- const context = React.useMemo(() => ({
1257
+ const context = React$1.useMemo(() => ({
1319
1258
  rapier,
1320
1259
  world: api,
1321
1260
  physicsOptions: {
@@ -1327,10 +1266,12 @@ const Physics = ({
1327
1266
  rigidBodyEvents,
1328
1267
  colliderEvents,
1329
1268
  attractorStates,
1269
+ beforeStepCallbacks,
1270
+ afterStepCallbacks,
1330
1271
  isPaused: _paused,
1331
1272
  step
1332
1273
  }), [_paused, step]);
1333
- return /*#__PURE__*/React__default["default"].createElement(RapierContext.Provider, {
1274
+ return /*#__PURE__*/React__default["default"].createElement(rapierContext.Provider, {
1334
1275
  value: context
1335
1276
  }, children);
1336
1277
  };
@@ -1387,7 +1328,7 @@ function _objectWithoutProperties(source, excluded) {
1387
1328
  }
1388
1329
 
1389
1330
  // Colliders
1390
- const AnyCollider = /*#__PURE__*/React.memo( /*#__PURE__*/React__default["default"].forwardRef((props, forwardedRef) => {
1331
+ const AnyCollider = /*#__PURE__*/React$1.memo( /*#__PURE__*/React__default["default"].forwardRef((props, forwardedRef) => {
1391
1332
  const {
1392
1333
  children,
1393
1334
  position,
@@ -1402,8 +1343,8 @@ const AnyCollider = /*#__PURE__*/React.memo( /*#__PURE__*/React__default["defaul
1402
1343
  colliderStates
1403
1344
  } = useRapier();
1404
1345
  const rigidBodyContext = useRigidBodyContext();
1405
- const ref = React.useRef(null);
1406
- const collidersRef = React.useMemo(() => {
1346
+ const ref = React$1.useRef(null);
1347
+ const collidersRef = React$1.useMemo(() => {
1407
1348
  if (forwardedRef !== null) {
1408
1349
  return forwardedRef;
1409
1350
  }
@@ -1412,7 +1353,7 @@ const AnyCollider = /*#__PURE__*/React.memo( /*#__PURE__*/React__default["defaul
1412
1353
  result.current = [];
1413
1354
  return result;
1414
1355
  }, []);
1415
- React.useEffect(() => {
1356
+ React$1.useEffect(() => {
1416
1357
  const object = ref.current;
1417
1358
  const worldScale = object.getWorldScale(new three.Vector3());
1418
1359
  const colliders = []; // If this is an InstancedRigidBody api
@@ -1444,7 +1385,7 @@ const AnyCollider = /*#__PURE__*/React.memo( /*#__PURE__*/React__default["defaul
1444
1385
  });
1445
1386
  };
1446
1387
  }, []);
1447
- const mergedProps = React.useMemo(() => {
1388
+ const mergedProps = React$1.useMemo(() => {
1448
1389
  return _objectSpread2(_objectSpread2({}, rigidBodyContext === null || rigidBodyContext === void 0 ? void 0 : rigidBodyContext.options), props);
1449
1390
  }, [props, rigidBodyContext === null || rigidBodyContext === void 0 ? void 0 : rigidBodyContext.options]);
1450
1391
  useUpdateColliderOptions(collidersRef, mergedProps, colliderStates);
@@ -1523,9 +1464,9 @@ CylinderCollider.displayName = "CylinderCollider";
1523
1464
  ConvexHullCollider.displayName = "ConvexHullCollider";
1524
1465
 
1525
1466
  const _excluded$1 = ["children", "type", "position", "rotation", "scale", "quaternion"];
1526
- const RigidBodyContext = /*#__PURE__*/React.createContext(undefined);
1527
- const useRigidBodyContext = () => React.useContext(RigidBodyContext);
1528
- const RigidBody = /*#__PURE__*/React.memo( /*#__PURE__*/React.forwardRef((props, ref) => {
1467
+ const RigidBodyContext = /*#__PURE__*/React$1.createContext(undefined);
1468
+ const useRigidBodyContext = () => React$1.useContext(RigidBodyContext);
1469
+ const RigidBody = /*#__PURE__*/React$1.memo( /*#__PURE__*/React$1.forwardRef((props, ref) => {
1529
1470
  const {
1530
1471
  children,
1531
1472
  type,
@@ -1537,8 +1478,8 @@ const RigidBody = /*#__PURE__*/React.memo( /*#__PURE__*/React.forwardRef((props,
1537
1478
  objectProps = _objectWithoutProperties(props, _excluded$1);
1538
1479
 
1539
1480
  const [object, api, childColliderProps] = useRigidBody(props);
1540
- React.useImperativeHandle(ref, () => api);
1541
- const contextValue = React.useMemo(() => ({
1481
+ React$1.useImperativeHandle(ref, () => api);
1482
+ const contextValue = React$1.useMemo(() => ({
1542
1483
  ref: object,
1543
1484
  api,
1544
1485
  options: props
@@ -1558,7 +1499,7 @@ const RigidBody = /*#__PURE__*/React.memo( /*#__PURE__*/React.forwardRef((props,
1558
1499
  }));
1559
1500
  RigidBody.displayName = "RigidBody";
1560
1501
 
1561
- const MeshCollider = props => {
1502
+ const MeshCollider = /*#__PURE__*/React$1.memo(props => {
1562
1503
  const {
1563
1504
  children,
1564
1505
  type
@@ -1567,11 +1508,11 @@ const MeshCollider = props => {
1567
1508
  physicsOptions,
1568
1509
  world
1569
1510
  } = useRapier();
1570
- const object = React.useRef(null);
1511
+ const object = React$1.useRef(null);
1571
1512
  const {
1572
1513
  options
1573
1514
  } = useRigidBodyContext();
1574
- const mergedOptions = React.useMemo(() => {
1515
+ const mergedOptions = React$1.useMemo(() => {
1575
1516
  return _objectSpread2(_objectSpread2(_objectSpread2({}, physicsOptions), options), {}, {
1576
1517
  children: undefined,
1577
1518
  colliders: type
@@ -1586,7 +1527,7 @@ const MeshCollider = props => {
1586
1527
  }, children, childColliderProps.map((colliderProps, index) => /*#__PURE__*/React__default["default"].createElement(AnyCollider, _extends({
1587
1528
  key: index
1588
1529
  }, colliderProps))));
1589
- };
1530
+ });
1590
1531
  MeshCollider.displayName = "MeshCollider";
1591
1532
 
1592
1533
  function mapsEqual(map1, map2) {
@@ -1611,10 +1552,10 @@ const AttractorHelper = props => {
1611
1552
  const {
1612
1553
  scene
1613
1554
  } = fiber.useThree();
1614
- const ref = React.useRef(null);
1615
- const normalsHelper = React.useRef();
1555
+ const ref = React$1.useRef(null);
1556
+ const normalsHelper = React$1.useRef();
1616
1557
  const color = props.strength > 0 ? 0x0000ff : 0xff0000;
1617
- React.useEffect(() => {
1558
+ React$1.useEffect(() => {
1618
1559
  if (ref.current) {
1619
1560
  normalsHelper.current = new threeStdlib.VertexNormalsHelper(ref.current, props.range, color);
1620
1561
  normalsHelper.current.frustumCulled = false;
@@ -1648,14 +1589,14 @@ const AttractorHelper = props => {
1648
1589
  }));
1649
1590
  };
1650
1591
 
1651
- const Debug = () => {
1592
+ const Debug = /*#__PURE__*/React$1.memo(() => {
1652
1593
  const {
1653
1594
  world,
1654
1595
  attractorStates
1655
1596
  } = useRapier();
1656
- const ref = React.useRef(null);
1657
- const [attractors, setAttractors] = React.useState([]);
1658
- const currMap = React.useRef(new Map());
1597
+ const ref = React$1.useRef(null);
1598
+ const [attractors, setAttractors] = React$1.useState([]);
1599
+ const currMap = React$1.useRef(new Map());
1659
1600
  fiber.useFrame(() => {
1660
1601
  const mesh = ref.current;
1661
1602
  if (!mesh) return;
@@ -1677,17 +1618,17 @@ const Debug = () => {
1677
1618
  }), /*#__PURE__*/React__default["default"].createElement("bufferGeometry", null)), attractors.map((attractor, i) => /*#__PURE__*/React__default["default"].createElement(AttractorHelper, _extends({
1678
1619
  key: attractor.object.uuid
1679
1620
  }, attractor))));
1680
- };
1621
+ });
1681
1622
 
1682
1623
  const _excluded = ["positions", "rotations", "children"];
1683
- const InstancedRigidBodies = /*#__PURE__*/React.forwardRef((props, ref) => {
1624
+ const InstancedRigidBodies = /*#__PURE__*/React$1.forwardRef((props, ref) => {
1684
1625
  const {
1685
1626
  world,
1686
1627
  rigidBodyStates,
1687
1628
  physicsOptions,
1688
1629
  rigidBodyEvents
1689
1630
  } = useRapier();
1690
- const object = React.useRef(null);
1631
+ const object = React$1.useRef(null);
1691
1632
 
1692
1633
  const {
1693
1634
  positions,
@@ -1696,20 +1637,20 @@ const InstancedRigidBodies = /*#__PURE__*/React.forwardRef((props, ref) => {
1696
1637
  } = props,
1697
1638
  options = _objectWithoutProperties(props, _excluded);
1698
1639
 
1699
- const instancesRef = React.useRef([]);
1700
- const rigidBodyRefs = React.useRef([]);
1701
- const instancesRefGetter = React.useRef(() => {
1640
+ const instancesRef = React$1.useRef([]);
1641
+ const rigidBodyRefs = React$1.useRef([]);
1642
+ const instancesRefGetter = React$1.useRef(() => {
1702
1643
  if (!instancesRef.current) {
1703
1644
  instancesRef.current = [];
1704
1645
  }
1705
1646
 
1706
1647
  return instancesRef.current;
1707
1648
  });
1708
- const mergedOptions = React.useMemo(() => {
1649
+ const mergedOptions = React$1.useMemo(() => {
1709
1650
  return _objectSpread2(_objectSpread2({}, physicsOptions), options);
1710
1651
  }, [physicsOptions, options]);
1711
1652
  const childColliderProps = useChildColliderProps(object, mergedOptions);
1712
- React.useLayoutEffect(() => {
1653
+ React$1.useLayoutEffect(() => {
1713
1654
  object.current.updateWorldMatrix(true, false);
1714
1655
  const instances = instancesRefGetter.current();
1715
1656
  const invertedWorld = object.current.matrixWorld.clone().invert();
@@ -1770,27 +1711,124 @@ const InstancedRigidBodies = /*#__PURE__*/React.forwardRef((props, ref) => {
1770
1711
  instancesRef.current = [];
1771
1712
  };
1772
1713
  }, []);
1773
- const api = React.useMemo(() => createInstancedRigidBodiesApi(instancesRefGetter), []);
1774
- React.useImperativeHandle(ref, () => api);
1714
+ const api = React$1.useMemo(() => createInstancedRigidBodiesApi(instancesRefGetter), []);
1715
+ React$1.useImperativeHandle(ref, () => api);
1775
1716
  useUpdateRigidBodyOptions(rigidBodyRefs, mergedOptions, rigidBodyStates, false);
1776
1717
  useRigidBodyEvents(rigidBodyRefs, mergedOptions, rigidBodyEvents);
1777
- const contextValue = React.useMemo(() => {
1718
+ const contextValue = React$1.useMemo(() => {
1778
1719
  return {
1779
1720
  ref: object,
1780
1721
  api,
1781
1722
  options: mergedOptions
1782
1723
  };
1783
1724
  }, [api, mergedOptions]);
1784
- return /*#__PURE__*/React__default["default"].createElement(RigidBodyContext.Provider, {
1725
+ return /*#__PURE__*/React.createElement(RigidBodyContext.Provider, {
1785
1726
  value: contextValue
1786
- }, /*#__PURE__*/React__default["default"].createElement("object3D", {
1727
+ }, /*#__PURE__*/React.createElement("object3D", {
1787
1728
  ref: object
1788
- }, props.children, childColliderProps.map((colliderProps, index) => /*#__PURE__*/React__default["default"].createElement(AnyCollider, _extends({
1729
+ }, props.children, childColliderProps.map((colliderProps, index) => /*#__PURE__*/React.createElement(AnyCollider, _extends({
1789
1730
  key: index
1790
1731
  }, colliderProps)))));
1791
1732
  });
1792
1733
  InstancedRigidBodies.displayName = "InstancedRigidBodies";
1793
1734
 
1735
+ const useImpulseJoint = (body1, body2, params) => {
1736
+ const {
1737
+ world
1738
+ } = useRapier();
1739
+ const jointRef = React$1.useRef();
1740
+ const getJointRef = React$1.useRef(() => {
1741
+ if (!jointRef.current) {
1742
+ let rb1;
1743
+ let rb2;
1744
+
1745
+ if ("current" in body1 && body1.current && "current" in body2 && body2.current) {
1746
+ rb1 = world.getRigidBody(body1.current.handle);
1747
+ rb2 = world.getRigidBody(body2.current.handle);
1748
+ const newJoint = world.createImpulseJoint(params, rb1, rb2);
1749
+ jointRef.current = newJoint;
1750
+ }
1751
+ }
1752
+
1753
+ return jointRef.current;
1754
+ });
1755
+ React$1.useEffect(() => {
1756
+ const joint = getJointRef.current();
1757
+ return () => {
1758
+ if (joint) {
1759
+ world.removeImpulseJoint(joint);
1760
+ jointRef.current = undefined;
1761
+ }
1762
+ };
1763
+ }, []);
1764
+ const api = React$1.useMemo(() => createJointApi(getJointRef), []);
1765
+ return api;
1766
+ };
1767
+ /**
1768
+ *
1769
+ * A fixed joint ensures that two rigid-bodies don't move relative to each other.
1770
+ * Fixed joints are characterized by one local frame (represented by an isometry) on each rigid-body.
1771
+ * The fixed-joint makes these frames coincide in world-space.
1772
+ */
1773
+
1774
+ const useFixedJoint = (body1, body2, [body1Anchor, body1LocalFrame, body2Anchor, body2LocalFrame]) => {
1775
+ const {
1776
+ rapier
1777
+ } = useRapier();
1778
+ return useImpulseJoint(body1, body2, rapier.JointData.fixed(vectorArrayToVector3(body1Anchor), tupleToObject(body1LocalFrame, ["x", "y", "z", "w"]), vectorArrayToVector3(body2Anchor), tupleToObject(body2LocalFrame, ["x", "y", "z", "w"])));
1779
+ };
1780
+ /**
1781
+ * The spherical joint ensures that two points on the local-spaces of two rigid-bodies always coincide (it prevents any relative
1782
+ * translational motion at this points). This is typically used to simulate ragdolls arms, pendulums, etc.
1783
+ * They are characterized by one local anchor on each rigid-body. Each anchor represents the location of the
1784
+ * points that need to coincide on the local-space of each rigid-body.
1785
+ */
1786
+
1787
+ const useSphericalJoint = (body1, body2, [body1Anchor, body2Anchor]) => {
1788
+ const {
1789
+ rapier
1790
+ } = useRapier();
1791
+ return useImpulseJoint(body1, body2, rapier.JointData.spherical(vectorArrayToVector3(body1Anchor), vectorArrayToVector3(body2Anchor)));
1792
+ };
1793
+ /**
1794
+ * The revolute joint prevents any relative movement between two rigid-bodies, except for relative
1795
+ * rotations along one axis. This is typically used to simulate wheels, fans, etc.
1796
+ * They are characterized by one local anchor as well as one local axis on each rigid-body.
1797
+ */
1798
+
1799
+ const useRevoluteJoint = (body1, body2, [body1Anchor, body2Anchor, axis, limits]) => {
1800
+ const {
1801
+ rapier
1802
+ } = useRapier();
1803
+ const params = rapier.JointData.revolute(vectorArrayToVector3(body1Anchor), vectorArrayToVector3(body2Anchor), vectorArrayToVector3(axis));
1804
+
1805
+ if (limits) {
1806
+ params.limitsEnabled = true;
1807
+ params.limits = limits;
1808
+ }
1809
+
1810
+ return useImpulseJoint(body1, body2, params);
1811
+ };
1812
+ /**
1813
+ * The prismatic joint prevents any relative movement between two rigid-bodies, except for relative translations along one axis.
1814
+ * It is characterized by one local anchor as well as one local axis on each rigid-body. In 3D, an optional
1815
+ * local tangent axis can be specified for each rigid-body.
1816
+ */
1817
+
1818
+ const usePrismaticJoint = (body1, body2, [body1Anchor, body2Anchor, axis, limits]) => {
1819
+ const {
1820
+ rapier
1821
+ } = useRapier();
1822
+ const params = rapier.JointData.prismatic(vectorArrayToVector3(body1Anchor), vectorArrayToVector3(body2Anchor), vectorArrayToVector3(axis));
1823
+
1824
+ if (limits) {
1825
+ params.limitsEnabled = true;
1826
+ params.limits = limits;
1827
+ }
1828
+
1829
+ return useImpulseJoint(body1, body2, params);
1830
+ };
1831
+
1794
1832
  /**
1795
1833
  * Calculates an InteractionGroup bitmask for use in the `collisionGroups` or `solverGroups`
1796
1834
  * properties of RigidBody or Collider components. The first argument represents a list of
@@ -1856,11 +1894,11 @@ exports.RigidBody = RigidBody;
1856
1894
  exports.RoundCuboidCollider = RoundCuboidCollider;
1857
1895
  exports.TrimeshCollider = TrimeshCollider;
1858
1896
  exports.interactionGroups = interactionGroups;
1859
- exports.useChildColliderProps = useChildColliderProps;
1897
+ exports.useAfterPhysicsStep = useAfterPhysicsStep;
1898
+ exports.useBeforePhysicsStep = useBeforePhysicsStep;
1860
1899
  exports.useFixedJoint = useFixedJoint;
1861
1900
  exports.useImpulseJoint = useImpulseJoint;
1862
1901
  exports.usePrismaticJoint = usePrismaticJoint;
1863
1902
  exports.useRapier = useRapier;
1864
1903
  exports.useRevoluteJoint = useRevoluteJoint;
1865
- exports.useRigidBody = useRigidBody;
1866
1904
  exports.useSphericalJoint = useSphericalJoint;