@react-three/rapier 0.13.1 → 0.14.0-rc.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.
@@ -12,13 +12,13 @@ export interface AttractorProps {
12
12
  * The strength of the attractor.
13
13
  * Positive values attract, negative values repel.
14
14
  *
15
- * @default 1
15
+ * @defaultValue 1
16
16
  */
17
17
  strength?: number;
18
18
  /**
19
19
  * The range of the attractor. Will not affect objects outside of this range.
20
20
  *
21
- * @default 10
21
+ * @defaultValue 10
22
22
  * @min 0
23
23
  */
24
24
  range?: number;
@@ -27,12 +27,12 @@ export interface AttractorProps {
27
27
  * - static: The gravity is constant and does not change over time.
28
28
  * - linear: The gravity is linearly interpolated the closer the object is to the attractor.
29
29
  * - newtonian: The gravity is calculated using the newtonian gravity formula.
30
- * @default "static"
30
+ * @defaultValue "static"
31
31
  */
32
32
  type?: AttractorGravityType;
33
33
  /**
34
34
  * The mass of the attractor. Used when type is `newtonian`.
35
- * @default 6.673e-11
35
+ * @defaultValue 6.673e-11
36
36
  */
37
37
  gravitationalConstant?: number;
38
38
  /**
@@ -140,18 +140,11 @@ export interface PhysicsProps {
140
140
  * @defaultValue false
141
141
  */
142
142
  paused?: boolean;
143
- /**
144
- * The update priority at which the physics simulation should run.
145
- *
146
- * @see https://docs.pmnd.rs/react-three-fiber/api/hooks#taking-over-the-render-loop
147
- * @defaultValue undefined
148
- */
149
- updatePriority?: number;
150
143
  /**
151
144
  * Interpolate the world transform using the frame delta times.
152
145
  * Has no effect if timeStep is set to "vary".
153
146
  *
154
- * @default true
147
+ * @defaultValue true
155
148
  **/
156
149
  interpolate?: boolean;
157
150
  }
@@ -228,31 +228,41 @@ export interface RigidBodyOptions extends ColliderProps {
228
228
  * Specify the type of this rigid body
229
229
  */
230
230
  type?: RigidBodyTypeString;
231
- /** Whether or not this body can sleep.
232
- * default: true
231
+ /**
232
+ * Whether or not this body can sleep.
233
+ * @defaultValue true
233
234
  */
234
235
  canSleep?: boolean;
235
236
  /** The linear damping coefficient of this rigid-body.*/
236
237
  linearDamping?: number;
237
238
  /** The angular damping coefficient of this rigid-body.*/
238
239
  angularDamping?: number;
239
- /** The initial linear velocity of this body.
240
- * default: zero velocity
240
+ /**
241
+ * The initial linear velocity of this body.
242
+ * @defaultValue [0,0,0]
241
243
  */
242
244
  linearVelocity?: Vector3Array;
243
- /** The initial angular velocity of this body.
244
- * Default: zero velocity.
245
+ /**
246
+ * The initial angular velocity of this body.
247
+ * @defaultValue [0,0,0]
245
248
  */
246
249
  angularVelocity?: Vector3Array;
247
250
  /**
248
251
  * The scaling factor applied to the gravity affecting the rigid-body.
249
- * Default: 1.0
252
+ * @defaultValue 1.0
250
253
  */
251
254
  gravityScale?: number;
255
+ /**
256
+ * The dominance group of this RigidBody. If a rigid body has a higher domiance group,
257
+ * on collision it will be immune to forces originating from the other bodies.
258
+ * https://rapier.rs/docs/user_guides/javascript/rigid_bodies#dominance
259
+ * Default: 0
260
+ */
261
+ dominanceGroup?: number;
252
262
  /**
253
263
  * Whether or not Continous Collision Detection is enabled for this rigid-body.
254
264
  * https://rapier.rs/docs/user_guides/javascript/rigid_bodies#continuous-collision-detection
255
- * @default false
265
+ * @defaultValue false
256
266
  */
257
267
  ccd?: boolean;
258
268
  /**
@@ -308,7 +318,7 @@ export interface RigidBodyOptions extends ColliderProps {
308
318
  */
309
319
  enabledRotations?: Boolean3Array;
310
320
  /**
311
- * Allow rotation of this rigid-body only along specific axes.
321
+ * Allow translation of this rigid-body only along specific axes.
312
322
  */
313
323
  enabledTranslations?: Boolean3Array;
314
324
  /**
@@ -0,0 +1 @@
1
+ export declare const useRaf: (callback: (dt: number) => void) => void;
@@ -178,6 +178,27 @@ function useConst(initialValue) {
178
178
  return ref.current.value;
179
179
  }
180
180
 
181
+ const useRaf = callback => {
182
+ const cb = React.useRef(callback);
183
+ const raf = React.useRef(0);
184
+ const lastFrame = React.useRef(0);
185
+ React.useEffect(() => {
186
+ cb.current = callback;
187
+ }, [callback]);
188
+ React.useEffect(() => {
189
+ const loop = () => {
190
+ const now = performance.now();
191
+ const delta = now - lastFrame.current;
192
+ raf.current = requestAnimationFrame(loop);
193
+ cb.current(delta / 1000);
194
+ lastFrame.current = now;
195
+ };
196
+
197
+ raf.current = requestAnimationFrame(loop);
198
+ return () => cancelAnimationFrame(raf.current);
199
+ }, []);
200
+ };
201
+
181
202
  const scaleColliderArgs = (shape, args, scale) => {
182
203
  const newArgs = args.slice(); // Heightfield uses a vector
183
204
 
@@ -675,10 +696,12 @@ const Physics = ({
675
696
  children,
676
697
  timeStep: _timeStep = 1 / 60,
677
698
  paused: _paused = false,
678
- updatePriority,
679
699
  interpolate: _interpolate = true
680
700
  }) => {
681
701
  const rapier = useAsset.useAsset(importRapier);
702
+ const {
703
+ invalidate
704
+ } = fiber.useThree();
682
705
  const worldRef = React.useRef();
683
706
  const getWorldRef = React.useRef(() => {
684
707
  if (!worldRef.current) {
@@ -959,10 +982,13 @@ const Physics = ({
959
982
  maxForceMagnitude: event.maxForceMagnitude()
960
983
  }));
961
984
  });
985
+ world.forEachActiveRigidBody(body => {
986
+ invalidate();
987
+ });
962
988
  }, [_paused, _timeStep, _interpolate]);
963
- fiber.useFrame((_, dt) => {
989
+ useRaf(dt => {
964
990
  if (!_paused) step(dt);
965
- }, updatePriority);
991
+ });
966
992
  const context = React.useMemo(() => ({
967
993
  rapier,
968
994
  world: api,
@@ -1135,12 +1161,17 @@ const AnyCollider = /*#__PURE__*/React.memo( /*#__PURE__*/React.forwardRef((prop
1135
1161
  const getInstance = useImperativeInstance(() => {
1136
1162
  const worldScale = ref.current.getWorldScale(vec3());
1137
1163
  const collider = createColliderFromOptions(props, world, worldScale, rigidBodyContext === null || rigidBodyContext === void 0 ? void 0 : rigidBodyContext.getRigidBody);
1138
- colliderStates.set(collider.handle, createColliderState(collider, ref.current, rigidBodyContext === null || rigidBodyContext === void 0 ? void 0 : rigidBodyContext.ref.current));
1139
1164
  return collider;
1140
1165
  }, collider => {
1141
- colliderStates.delete(collider.handle);
1142
1166
  world.removeCollider(collider);
1143
1167
  });
1168
+ React.useEffect(() => {
1169
+ const collider = getInstance();
1170
+ colliderStates.set(collider.handle, createColliderState(collider, ref.current, rigidBodyContext === null || rigidBodyContext === void 0 ? void 0 : rigidBodyContext.ref.current));
1171
+ return () => {
1172
+ colliderStates.delete(collider.handle);
1173
+ };
1174
+ }, []);
1144
1175
  React.useImperativeHandle(forwardedRef, () => getInstance());
1145
1176
  const mergedProps = React.useMemo(() => {
1146
1177
  return _objectSpread2(_objectSpread2({}, rigidBodyContext === null || rigidBodyContext === void 0 ? void 0 : rigidBodyContext.options), props);
@@ -1307,6 +1338,9 @@ const mutableRigidBodyOptions = {
1307
1338
  angularDamping: (rb, value) => {
1308
1339
  rb.setAngularDamping(value);
1309
1340
  },
1341
+ dominanceGroup: (rb, value) => {
1342
+ rb.setDominanceGroup(value);
1343
+ },
1310
1344
  enabledRotations: (rb, [x, y, z]) => {
1311
1345
  rb.setEnabledRotations(x, y, z, true);
1312
1346
  },
@@ -1442,21 +1476,27 @@ const RigidBody = /*#__PURE__*/React.memo( /*#__PURE__*/React.forwardRef((props,
1442
1476
  children: undefined
1443
1477
  });
1444
1478
  }, [physicsOptions, props]);
1445
- const childColliderProps = useChildColliderProps(ref, mergedOptions); // Create rigidbody
1479
+ const childColliderProps = useChildColliderProps(ref, mergedOptions); // Provide a way to eagerly create rigidbody
1446
1480
 
1447
1481
  const getInstance = useImperativeInstance(() => {
1448
1482
  const desc = rigidBodyDescFromOptions(mergedOptions);
1449
1483
  const rigidBody = world.createRigidBody(desc);
1484
+ return rigidBody;
1485
+ }, rigidBody => {
1486
+ world.removeRigidBody(rigidBody);
1487
+ }); // Only provide a object state after the ref has been set
1488
+
1489
+ React.useEffect(() => {
1490
+ const rigidBody = getInstance();
1450
1491
  const state = createRigidBodyState({
1451
1492
  rigidBody,
1452
1493
  object: ref.current
1453
1494
  });
1454
1495
  rigidBodyStates.set(rigidBody.handle, props.transformState ? props.transformState(state) : state);
1455
- return rigidBody;
1456
- }, rigidBody => {
1457
- world.removeRigidBody(rigidBody);
1458
- rigidBodyStates.delete(rigidBody.handle);
1459
- });
1496
+ return () => {
1497
+ rigidBodyStates.delete(rigidBody.handle);
1498
+ };
1499
+ }, []);
1460
1500
  useUpdateRigidBodyOptions(getInstance, mergedOptions, rigidBodyStates);
1461
1501
  useRigidBodyEvents(getInstance, mergedOptions, rigidBodyEvents);
1462
1502
  React.useImperativeHandle(forwardedRef, () => getInstance());
@@ -178,6 +178,27 @@ function useConst(initialValue) {
178
178
  return ref.current.value;
179
179
  }
180
180
 
181
+ const useRaf = callback => {
182
+ const cb = React.useRef(callback);
183
+ const raf = React.useRef(0);
184
+ const lastFrame = React.useRef(0);
185
+ React.useEffect(() => {
186
+ cb.current = callback;
187
+ }, [callback]);
188
+ React.useEffect(() => {
189
+ const loop = () => {
190
+ const now = performance.now();
191
+ const delta = now - lastFrame.current;
192
+ raf.current = requestAnimationFrame(loop);
193
+ cb.current(delta / 1000);
194
+ lastFrame.current = now;
195
+ };
196
+
197
+ raf.current = requestAnimationFrame(loop);
198
+ return () => cancelAnimationFrame(raf.current);
199
+ }, []);
200
+ };
201
+
181
202
  const scaleColliderArgs = (shape, args, scale) => {
182
203
  const newArgs = args.slice(); // Heightfield uses a vector
183
204
 
@@ -675,10 +696,12 @@ const Physics = ({
675
696
  children,
676
697
  timeStep: _timeStep = 1 / 60,
677
698
  paused: _paused = false,
678
- updatePriority,
679
699
  interpolate: _interpolate = true
680
700
  }) => {
681
701
  const rapier = useAsset.useAsset(importRapier);
702
+ const {
703
+ invalidate
704
+ } = fiber.useThree();
682
705
  const worldRef = React.useRef();
683
706
  const getWorldRef = React.useRef(() => {
684
707
  if (!worldRef.current) {
@@ -959,10 +982,13 @@ const Physics = ({
959
982
  maxForceMagnitude: event.maxForceMagnitude()
960
983
  }));
961
984
  });
985
+ world.forEachActiveRigidBody(body => {
986
+ invalidate();
987
+ });
962
988
  }, [_paused, _timeStep, _interpolate]);
963
- fiber.useFrame((_, dt) => {
989
+ useRaf(dt => {
964
990
  if (!_paused) step(dt);
965
- }, updatePriority);
991
+ });
966
992
  const context = React.useMemo(() => ({
967
993
  rapier,
968
994
  world: api,
@@ -1135,12 +1161,17 @@ const AnyCollider = /*#__PURE__*/React.memo( /*#__PURE__*/React.forwardRef((prop
1135
1161
  const getInstance = useImperativeInstance(() => {
1136
1162
  const worldScale = ref.current.getWorldScale(vec3());
1137
1163
  const collider = createColliderFromOptions(props, world, worldScale, rigidBodyContext === null || rigidBodyContext === void 0 ? void 0 : rigidBodyContext.getRigidBody);
1138
- colliderStates.set(collider.handle, createColliderState(collider, ref.current, rigidBodyContext === null || rigidBodyContext === void 0 ? void 0 : rigidBodyContext.ref.current));
1139
1164
  return collider;
1140
1165
  }, collider => {
1141
- colliderStates.delete(collider.handle);
1142
1166
  world.removeCollider(collider);
1143
1167
  });
1168
+ React.useEffect(() => {
1169
+ const collider = getInstance();
1170
+ colliderStates.set(collider.handle, createColliderState(collider, ref.current, rigidBodyContext === null || rigidBodyContext === void 0 ? void 0 : rigidBodyContext.ref.current));
1171
+ return () => {
1172
+ colliderStates.delete(collider.handle);
1173
+ };
1174
+ }, []);
1144
1175
  React.useImperativeHandle(forwardedRef, () => getInstance());
1145
1176
  const mergedProps = React.useMemo(() => {
1146
1177
  return _objectSpread2(_objectSpread2({}, rigidBodyContext === null || rigidBodyContext === void 0 ? void 0 : rigidBodyContext.options), props);
@@ -1307,6 +1338,9 @@ const mutableRigidBodyOptions = {
1307
1338
  angularDamping: (rb, value) => {
1308
1339
  rb.setAngularDamping(value);
1309
1340
  },
1341
+ dominanceGroup: (rb, value) => {
1342
+ rb.setDominanceGroup(value);
1343
+ },
1310
1344
  enabledRotations: (rb, [x, y, z]) => {
1311
1345
  rb.setEnabledRotations(x, y, z, true);
1312
1346
  },
@@ -1442,21 +1476,27 @@ const RigidBody = /*#__PURE__*/React.memo( /*#__PURE__*/React.forwardRef((props,
1442
1476
  children: undefined
1443
1477
  });
1444
1478
  }, [physicsOptions, props]);
1445
- const childColliderProps = useChildColliderProps(ref, mergedOptions); // Create rigidbody
1479
+ const childColliderProps = useChildColliderProps(ref, mergedOptions); // Provide a way to eagerly create rigidbody
1446
1480
 
1447
1481
  const getInstance = useImperativeInstance(() => {
1448
1482
  const desc = rigidBodyDescFromOptions(mergedOptions);
1449
1483
  const rigidBody = world.createRigidBody(desc);
1484
+ return rigidBody;
1485
+ }, rigidBody => {
1486
+ world.removeRigidBody(rigidBody);
1487
+ }); // Only provide a object state after the ref has been set
1488
+
1489
+ React.useEffect(() => {
1490
+ const rigidBody = getInstance();
1450
1491
  const state = createRigidBodyState({
1451
1492
  rigidBody,
1452
1493
  object: ref.current
1453
1494
  });
1454
1495
  rigidBodyStates.set(rigidBody.handle, props.transformState ? props.transformState(state) : state);
1455
- return rigidBody;
1456
- }, rigidBody => {
1457
- world.removeRigidBody(rigidBody);
1458
- rigidBodyStates.delete(rigidBody.handle);
1459
- });
1496
+ return () => {
1497
+ rigidBodyStates.delete(rigidBody.handle);
1498
+ };
1499
+ }, []);
1460
1500
  useUpdateRigidBodyOptions(getInstance, mergedOptions, rigidBodyStates);
1461
1501
  useRigidBodyEvents(getInstance, mergedOptions, rigidBodyEvents);
1462
1502
  React.useImperativeHandle(forwardedRef, () => getInstance());
@@ -1,7 +1,7 @@
1
1
  import { ActiveEvents, ColliderDesc, EventQueue, RigidBodyDesc } from '@dimforge/rapier3d-compat';
2
2
  export { CoefficientCombineRule, Collider as RapierCollider, RigidBody as RapierRigidBody } from '@dimforge/rapier3d-compat';
3
- import { useFrame, useThree } from '@react-three/fiber';
4
- import React, { useRef, useMemo, useEffect, useContext, useState, memo, createContext, useCallback, forwardRef, useImperativeHandle, Fragment } from 'react';
3
+ import { useThree, useFrame } from '@react-three/fiber';
4
+ import React, { useRef, useEffect, useMemo, useContext, useState, memo, createContext, useCallback, forwardRef, useImperativeHandle, Fragment } from 'react';
5
5
  import { Quaternion, Euler, Vector3, Object3D, Matrix4, MathUtils, BufferAttribute, DynamicDrawUsage } from 'three';
6
6
  import { useAsset } from 'use-asset';
7
7
  import { mergeVertices, VertexNormalsHelper } from 'three-stdlib';
@@ -153,6 +153,27 @@ function useConst(initialValue) {
153
153
  return ref.current.value;
154
154
  }
155
155
 
156
+ const useRaf = callback => {
157
+ const cb = useRef(callback);
158
+ const raf = useRef(0);
159
+ const lastFrame = useRef(0);
160
+ useEffect(() => {
161
+ cb.current = callback;
162
+ }, [callback]);
163
+ useEffect(() => {
164
+ const loop = () => {
165
+ const now = performance.now();
166
+ const delta = now - lastFrame.current;
167
+ raf.current = requestAnimationFrame(loop);
168
+ cb.current(delta / 1000);
169
+ lastFrame.current = now;
170
+ };
171
+
172
+ raf.current = requestAnimationFrame(loop);
173
+ return () => cancelAnimationFrame(raf.current);
174
+ }, []);
175
+ };
176
+
156
177
  const scaleColliderArgs = (shape, args, scale) => {
157
178
  const newArgs = args.slice(); // Heightfield uses a vector
158
179
 
@@ -650,10 +671,12 @@ const Physics = ({
650
671
  children,
651
672
  timeStep: _timeStep = 1 / 60,
652
673
  paused: _paused = false,
653
- updatePriority,
654
674
  interpolate: _interpolate = true
655
675
  }) => {
656
676
  const rapier = useAsset(importRapier);
677
+ const {
678
+ invalidate
679
+ } = useThree();
657
680
  const worldRef = useRef();
658
681
  const getWorldRef = useRef(() => {
659
682
  if (!worldRef.current) {
@@ -934,10 +957,13 @@ const Physics = ({
934
957
  maxForceMagnitude: event.maxForceMagnitude()
935
958
  }));
936
959
  });
960
+ world.forEachActiveRigidBody(body => {
961
+ invalidate();
962
+ });
937
963
  }, [_paused, _timeStep, _interpolate]);
938
- useFrame((_, dt) => {
964
+ useRaf(dt => {
939
965
  if (!_paused) step(dt);
940
- }, updatePriority);
966
+ });
941
967
  const context = useMemo(() => ({
942
968
  rapier,
943
969
  world: api,
@@ -1110,12 +1136,17 @@ const AnyCollider = /*#__PURE__*/memo( /*#__PURE__*/forwardRef((props, forwarded
1110
1136
  const getInstance = useImperativeInstance(() => {
1111
1137
  const worldScale = ref.current.getWorldScale(vec3());
1112
1138
  const collider = createColliderFromOptions(props, world, worldScale, rigidBodyContext === null || rigidBodyContext === void 0 ? void 0 : rigidBodyContext.getRigidBody);
1113
- colliderStates.set(collider.handle, createColliderState(collider, ref.current, rigidBodyContext === null || rigidBodyContext === void 0 ? void 0 : rigidBodyContext.ref.current));
1114
1139
  return collider;
1115
1140
  }, collider => {
1116
- colliderStates.delete(collider.handle);
1117
1141
  world.removeCollider(collider);
1118
1142
  });
1143
+ useEffect(() => {
1144
+ const collider = getInstance();
1145
+ colliderStates.set(collider.handle, createColliderState(collider, ref.current, rigidBodyContext === null || rigidBodyContext === void 0 ? void 0 : rigidBodyContext.ref.current));
1146
+ return () => {
1147
+ colliderStates.delete(collider.handle);
1148
+ };
1149
+ }, []);
1119
1150
  useImperativeHandle(forwardedRef, () => getInstance());
1120
1151
  const mergedProps = useMemo(() => {
1121
1152
  return _objectSpread2(_objectSpread2({}, rigidBodyContext === null || rigidBodyContext === void 0 ? void 0 : rigidBodyContext.options), props);
@@ -1282,6 +1313,9 @@ const mutableRigidBodyOptions = {
1282
1313
  angularDamping: (rb, value) => {
1283
1314
  rb.setAngularDamping(value);
1284
1315
  },
1316
+ dominanceGroup: (rb, value) => {
1317
+ rb.setDominanceGroup(value);
1318
+ },
1285
1319
  enabledRotations: (rb, [x, y, z]) => {
1286
1320
  rb.setEnabledRotations(x, y, z, true);
1287
1321
  },
@@ -1417,21 +1451,27 @@ const RigidBody = /*#__PURE__*/memo( /*#__PURE__*/forwardRef((props, forwardedRe
1417
1451
  children: undefined
1418
1452
  });
1419
1453
  }, [physicsOptions, props]);
1420
- const childColliderProps = useChildColliderProps(ref, mergedOptions); // Create rigidbody
1454
+ const childColliderProps = useChildColliderProps(ref, mergedOptions); // Provide a way to eagerly create rigidbody
1421
1455
 
1422
1456
  const getInstance = useImperativeInstance(() => {
1423
1457
  const desc = rigidBodyDescFromOptions(mergedOptions);
1424
1458
  const rigidBody = world.createRigidBody(desc);
1459
+ return rigidBody;
1460
+ }, rigidBody => {
1461
+ world.removeRigidBody(rigidBody);
1462
+ }); // Only provide a object state after the ref has been set
1463
+
1464
+ useEffect(() => {
1465
+ const rigidBody = getInstance();
1425
1466
  const state = createRigidBodyState({
1426
1467
  rigidBody,
1427
1468
  object: ref.current
1428
1469
  });
1429
1470
  rigidBodyStates.set(rigidBody.handle, props.transformState ? props.transformState(state) : state);
1430
- return rigidBody;
1431
- }, rigidBody => {
1432
- world.removeRigidBody(rigidBody);
1433
- rigidBodyStates.delete(rigidBody.handle);
1434
- });
1471
+ return () => {
1472
+ rigidBodyStates.delete(rigidBody.handle);
1473
+ };
1474
+ }, []);
1435
1475
  useUpdateRigidBodyOptions(getInstance, mergedOptions, rigidBodyStates);
1436
1476
  useRigidBodyEvents(getInstance, mergedOptions, rigidBodyEvents);
1437
1477
  useImperativeHandle(forwardedRef, () => getInstance());
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@react-three/rapier",
3
- "version": "0.13.1",
3
+ "version": "0.14.0-rc.0",
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
@@ -66,6 +66,7 @@ For full API outline and documentation, see 🧩 [API Docs](https://pmndrs.githu
66
66
  - [Collider Components](#collider-components)
67
67
  - [🖼 Collider Examples](#-collider-examples)
68
68
  - [Instanced Meshes](#instanced-meshes)
69
+ - [Debug](#debug)
69
70
  - [Moving things around, and applying forces](#moving-things-around-and-applying-forces)
70
71
  - [Collision Events](#collision-events)
71
72
  - [Configuring collision and solver groups](#configuring-collision-and-solver-groups)
@@ -83,6 +84,7 @@ For full API outline and documentation, see 🧩 [API Docs](https://pmndrs.githu
83
84
  - [🖼 Joints Example](#-joints-example)
84
85
  - [Advanced hooks usage](#advanced-hooks-usage)
85
86
  - [Manual stepping](#manual-stepping)
87
+ - [On-demand rendering](#on-demand-rendering)
86
88
 
87
89
  ---
88
90
 
@@ -130,7 +132,7 @@ Supported values:
130
132
 
131
133
  - `"cuboid"`, creates a CuboidCollider based on the bounding box of the mesh
132
134
  - `"ball"`, creates a SphereCollider based on the bounding sphere of the mesh
133
- - `"trimesh"`, creates a TrimeshCollider based on the mesh's geometry -- note trimeshes are massless by default (https://rapier.rs/docs/user_guides/javascript/common_mistakes#rigid-body-isnt-affected-by-gravity)
135
+ - `"trimesh"`, creates a TrimeshCollider based on the mesh's geometry
134
136
  - `"hull"`, creates a ConvexHullCollider based on the mesh's geometry
135
137
  - `false`, disables auto-generation
136
138
 
@@ -255,11 +257,12 @@ const Scene = () => {
255
257
  }
256
258
 
257
259
  // You can access individual instanced by their index
258
- rigidBodies.current.at(40).applyImpulse({ x: 0, y: 10, z: 0 });
260
+ rigidBodies.current[40].applyImpulse({ x: 0, y: 10, z: 0 }, true);
261
+ rigidBodies.at(100).applyImpulse({ x: 0, y: 10, z: 0 }, true);
259
262
 
260
263
  // Or update all instances
261
264
  rigidBodies.current.forEach((api) => {
262
- api.applyImpulse({ x: 0, y: 10, z: 0 });
265
+ api.applyImpulse({ x: 0, y: 10, z: 0 }, true);
263
266
  });
264
267
  }, []);
265
268
 
@@ -328,8 +331,6 @@ const Scene = () => {
328
331
  );
329
332
  };
330
333
  ```
331
- }
332
- ```
333
334
 
334
335
  ## Debug
335
336
 
@@ -589,8 +590,6 @@ To detect when a collider enters or leaves another collider, you can use the `on
589
590
 
590
591
  🧩 See [onIntersectionEnter / onIntersectionExit docs](https://pmndrs.github.io/react-three-rapier/interfaces/RigidBodyProps.html#onIntersectionEnter) for more information.
591
592
 
592
- ```tsx
593
-
594
593
  ```tsx
595
594
  <RigidBody>
596
595
  <GoalPosts />
@@ -674,6 +673,7 @@ There are 4 different joint types available:
674
673
  - Prismatic (two bodies are connected by a sliding joint, for things like pistons or sliders)
675
674
 
676
675
  Each joint hook returns a RefObject containing the raw reference to the joint instance.
676
+
677
677
  ```tsx
678
678
  const WheelJoint = ({bodyA, bodyB}) => {
679
679
  const joint = useRevoluteJoint(bodyA, bodyB, [[0,0,0],[0,0,0],[0,0,0]])
@@ -723,8 +723,6 @@ The spherical joint ensures that two points on the local-spaces of two rigid-bod
723
723
 
724
724
  🧩 See [SphericalJoint docs](https://pmndrs.github.io/react-three-rapier/functions/useSphericalJoint.html) for available options.
725
725
 
726
- ```tsx
727
-
728
726
  ```tsx
729
727
  const JointedThing = () => {
730
728
  const joint = useSphericalJoint(
@@ -761,7 +759,7 @@ const JointedThing = () => {
761
759
  [
762
760
  [0, 0, 0], // Position of the joint in bodyA's local space
763
761
  [0, 0, 0], // Position of the joint in bodyB's local space
764
- [0, 0, 0], // Axis of the joint, expressed in the local-space of the rigid-bodies it is attached to.
762
+ [0, 1, 0], // Axis of the joint, expressed in the local-space of the rigid-bodies it is attached to. Cannot be [0,0,0].
765
763
  ]);
766
764
 
767
765
  useEffect(() => {
@@ -788,8 +786,6 @@ The prismatic joint prevents any relative movement between two rigid-bodies, exc
788
786
 
789
787
  🧩 See [PrismaticJoint docs](https://pmndrs.github.io/react-three-rapier/functions/usePrismaticJoint.html) for available options.
790
788
 
791
- ```tsx
792
-
793
789
  ```tsx
794
790
  const JointedThing = () => {
795
791
  const joint = usePrismaticJoint(
@@ -798,7 +794,7 @@ const JointedThing = () => {
798
794
  [
799
795
  [0, 0, 0], // Position of the joint in bodyA's local space
800
796
  [0, 0, 0], // Position of the joint in bodyB's local space
801
- [0, 0, 0], // Axis of the joint, expressed in the local-space of the rigid-bodies it is attached to.
797
+ [0, 1, 0], // Axis of the joint, expressed in the local-space of the rigid-bodies it is attached to. Cannot be [0,0,0].
802
798
  ]);
803
799
 
804
800
  return (
@@ -839,4 +835,7 @@ You can manually step the physics simulation by calling the `step` method from t
839
835
  const { step } = useRapier();
840
836
 
841
837
  step(1 / 60);
842
- ```
838
+ ```
839
+
840
+ ### On-demand rendering
841
+ `@react-three/rapier` runs the physics simulation independently from the render loop, and will tell `@react-three/fiber` to render if the scene has active (non-sleeping) RigidBodies. This allows you to use the `<Canvas frameloop="demand" />` (https://docs.pmnd.rs/react-three-fiber/advanced/scaling-performance#on-demand-rendering) strategy to only render the scene when needed.