@threlte/rapier 3.0.0-next.1 → 3.0.0-next.10

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.
Files changed (43) hide show
  1. package/dist/components/Attractor/Attractor.svelte +2 -2
  2. package/dist/components/Attractor/Attractor.svelte.d.ts +2 -10
  3. package/dist/components/Colliders/AutoColliders.svelte +23 -13
  4. package/dist/components/Colliders/AutoColliders.svelte.d.ts +16 -12
  5. package/dist/components/Colliders/Collider.svelte +23 -10
  6. package/dist/components/Colliders/Collider.svelte.d.ts +6 -9
  7. package/dist/components/CollisionGroups/CollisionGroups.svelte +2 -2
  8. package/dist/components/CollisionGroups/CollisionGroups.svelte.d.ts +5 -1
  9. package/dist/components/RigidBody/RigidBody.svelte +39 -9
  10. package/dist/components/RigidBody/RigidBody.svelte.d.ts +5 -15
  11. package/dist/components/RigidBody/overrideTeleportMethods.d.ts +14 -0
  12. package/dist/components/RigidBody/overrideTeleportMethods.js +31 -0
  13. package/dist/components/World/InnerWorld.svelte +27 -5
  14. package/dist/components/World/InnerWorld.svelte.d.ts +2 -8
  15. package/dist/components/World/World.svelte +9 -57
  16. package/dist/components/World/World.svelte.d.ts +13 -2
  17. package/dist/lib/applyColliderActiveEvents.d.ts +2 -1
  18. package/dist/lib/applyColliderActiveEvents.js +9 -9
  19. package/dist/lib/createPhysicsStages.d.ts +15 -0
  20. package/dist/lib/createPhysicsStages.js +43 -0
  21. package/dist/lib/createPhysicsTasks.d.ts +19 -0
  22. package/dist/{hooks/useFrameHandler.js → lib/createPhysicsTasks.js} +132 -65
  23. package/dist/lib/createRapierContext.d.ts +14 -20
  24. package/dist/lib/createRapierContext.js +37 -13
  25. package/dist/lib/initRapier.svelte.d.ts +1 -0
  26. package/dist/lib/initRapier.svelte.js +16 -0
  27. package/dist/lib/keys.d.ts +2 -0
  28. package/dist/lib/keys.js +2 -0
  29. package/dist/lib/rigidBodyObjectContext.d.ts +3 -2
  30. package/dist/lib/useCreateEvent.d.ts +2 -1
  31. package/dist/lib/useCreateEvent.js +3 -3
  32. package/dist/recipes/BasicPlayerController.svelte +6 -5
  33. package/dist/recipes/BasicPlayerController.svelte.d.ts +3 -3
  34. package/dist/types/types.d.ts +55 -28
  35. package/package.json +28 -9
  36. package/dist/hooks/useFixedJoint.d.ts +0 -8
  37. package/dist/hooks/useFrameHandler.d.ts +0 -3
  38. package/dist/hooks/useHasEventListener.d.ts +0 -3
  39. package/dist/hooks/useHasEventListener.js +0 -11
  40. package/dist/hooks/useJoint.d.ts +0 -8
  41. package/dist/hooks/usePrismaticJoint.d.ts +0 -8
  42. package/dist/hooks/useRevoluteJoint.d.ts +0 -8
  43. package/dist/hooks/useSphericalJoint.d.ts +0 -8
@@ -1,17 +1,17 @@
1
1
  import { ActiveEvents } from '@dimforge/rapier3d-compat';
2
2
  export const applyColliderActiveEvents = (collider, colliderEvents = {}, rigidBodyEvents = {}) => {
3
3
  let events = 0;
4
- if (colliderEvents.collisionenter ||
5
- colliderEvents.collisionexit ||
6
- rigidBodyEvents.collisionenter ||
7
- rigidBodyEvents.collisionexit ||
8
- colliderEvents.sensorenter ||
9
- colliderEvents.sensorexit ||
10
- rigidBodyEvents.sensorenter ||
11
- rigidBodyEvents.sensorexit) {
4
+ if (colliderEvents.oncollisionenter ||
5
+ colliderEvents.oncollisionexit ||
6
+ rigidBodyEvents.oncollisionenter ||
7
+ rigidBodyEvents.oncollisionexit ||
8
+ colliderEvents.onsensorenter ||
9
+ colliderEvents.onsensorexit ||
10
+ rigidBodyEvents.onsensorenter ||
11
+ rigidBodyEvents.onsensorexit) {
12
12
  events = events | ActiveEvents.COLLISION_EVENTS;
13
13
  }
14
- if (colliderEvents.contact || rigidBodyEvents.contact) {
14
+ if (colliderEvents.oncontact || rigidBodyEvents.oncontact) {
15
15
  events = events | ActiveEvents.CONTACT_FORCE_EVENTS;
16
16
  }
17
17
  if (events > 0) {
@@ -0,0 +1,15 @@
1
+ import { type CurrentWritable, type Key, type Stage } from '@threlte/core';
2
+ import type { Framerate } from '../types/types';
3
+ export declare const createPhysicsStages: (framerate: CurrentWritable<Framerate>, simulationOffset: CurrentWritable<number>, updateRigidBodySimulationData: CurrentWritable<boolean>, options?: {
4
+ simulationStageOptions?: {
5
+ before?: (Key | Stage) | (Key | Stage)[];
6
+ after?: (Key | Stage) | (Key | Stage)[];
7
+ };
8
+ synchronizationStageOptions?: {
9
+ before?: (Key | Stage) | (Key | Stage)[];
10
+ after?: (Key | Stage) | (Key | Stage)[];
11
+ };
12
+ }) => {
13
+ simulationStage: Stage;
14
+ synchronizationStage: Stage;
15
+ };
@@ -0,0 +1,43 @@
1
+ import { useStage, useThrelte } from '@threlte/core';
2
+ import { simulationKey, synchronizationKey } from './keys';
3
+ export const createPhysicsStages = (framerate, simulationOffset, updateRigidBodySimulationData, options) => {
4
+ let fixedStepTimeAccumulator = 0;
5
+ let simulationTime = 0;
6
+ let lastSimulationTime = 0;
7
+ const { renderStage } = useThrelte();
8
+ const simulationStage = useStage(simulationKey, {
9
+ after: options?.simulationStageOptions?.after,
10
+ before: options?.simulationStageOptions?.before,
11
+ callback(delta, runTasks) {
12
+ if (framerate.current === 'varying') {
13
+ runTasks();
14
+ }
15
+ else {
16
+ const rate = 1 / framerate.current;
17
+ simulationTime += delta;
18
+ fixedStepTimeAccumulator += delta;
19
+ const iterations = Math.ceil(fixedStepTimeAccumulator / rate);
20
+ for (let iteration = 0; iteration < iterations; iteration++) {
21
+ updateRigidBodySimulationData.set(iteration >= iterations - 2);
22
+ runTasks(rate);
23
+ fixedStepTimeAccumulator -= rate;
24
+ lastSimulationTime += rate;
25
+ }
26
+ simulationOffset.set((simulationTime - lastSimulationTime) / rate + 1);
27
+ }
28
+ }
29
+ });
30
+ const synchronizationStage = useStage(synchronizationKey, {
31
+ after: options?.synchronizationStageOptions?.after
32
+ ? Array.isArray(options.synchronizationStageOptions.after)
33
+ ? [...options.synchronizationStageOptions.after, simulationKey]
34
+ : [options.synchronizationStageOptions.after, simulationKey]
35
+ : simulationKey,
36
+ before: options?.synchronizationStageOptions?.before
37
+ ? Array.isArray(options.synchronizationStageOptions.before)
38
+ ? [...options.synchronizationStageOptions.before, renderStage]
39
+ : [options.synchronizationStageOptions.before, renderStage]
40
+ : renderStage
41
+ });
42
+ return { simulationStage, synchronizationStage };
43
+ };
@@ -0,0 +1,19 @@
1
+ import { type World } from '@dimforge/rapier3d-compat';
2
+ import { type CurrentWritable, type Stage } from '@threlte/core';
3
+ import { Object3D, Quaternion, Vector3 } from 'three';
4
+ import type { ColliderEvents, Framerate, RigidBodyEvents } from '../types/types';
5
+ type PhysicsUserData = {
6
+ currentPosition: Vector3;
7
+ currentQuaternion: Quaternion;
8
+ lastPosition: Vector3;
9
+ lastQuaternion: Quaternion;
10
+ resetPosition: boolean;
11
+ resetRotation: boolean;
12
+ };
13
+ export declare const initializeRigidBodyUserData: (obj: Object3D) => PhysicsUserData;
14
+ export declare const setInitialRigidBodyState: (obj: Object3D, initialPosition: Vector3, initialQuaternion: Quaternion) => void;
15
+ export declare const createPhysicsTasks: (world: World, framerate: CurrentWritable<Framerate>, simulationOffset: CurrentWritable<number>, rigidBodyObjects: Map<number, Object3D>, updateRigidBodySimulationData: CurrentWritable<boolean>, colliderEventDispatchers: Map<number, ColliderEvents>, rigidBodyEventDispatchers: Map<number, RigidBodyEvents>, simulationStage: Stage, synchronizationStage: Stage) => {
16
+ simulationTask: import("@threlte/core").Task;
17
+ synchronizationTask: import("@threlte/core").Task;
18
+ };
19
+ export {};
@@ -1,21 +1,17 @@
1
1
  import { EventQueue } from '@dimforge/rapier3d-compat';
2
2
  import { useTask } from '@threlte/core';
3
- import { derived } from 'svelte/store';
4
3
  import { Object3D, Quaternion, Vector3 } from 'three';
4
+ import { simulationKey, synchronizationKey } from './keys';
5
5
  const tempObject = new Object3D();
6
6
  const tempVector3 = new Vector3();
7
7
  const tempQuaternion = new Quaternion();
8
- const getEventDispatchers = (ctx, collider1, collider2) => {
9
- const collider1Events = ctx.colliderEventDispatchers.get(collider1.handle);
10
- const collider2Events = ctx.colliderEventDispatchers.get(collider2.handle);
8
+ const getEventDispatchers = (collider1, collider2, colliderEventDispatchers, rigidBodyEventDispatchers) => {
9
+ const collider1Events = colliderEventDispatchers.get(collider1.handle);
10
+ const collider2Events = colliderEventDispatchers.get(collider2.handle);
11
11
  const rigidBody1 = collider1.parent();
12
12
  const rigidBody2 = collider2.parent();
13
- const rigidBody1Events = rigidBody1
14
- ? ctx.rigidBodyEventDispatchers.get(rigidBody1.handle)
15
- : undefined;
16
- const rigidBody2Events = rigidBody2
17
- ? ctx.rigidBodyEventDispatchers.get(rigidBody2.handle)
18
- : undefined;
13
+ const rigidBody1Events = rigidBody1 ? rigidBodyEventDispatchers.get(rigidBody1.handle) : undefined;
14
+ const rigidBody2Events = rigidBody2 ? rigidBodyEventDispatchers.get(rigidBody2.handle) : undefined;
19
15
  return {
20
16
  collider1Events,
21
17
  collider2Events,
@@ -23,50 +19,89 @@ const getEventDispatchers = (ctx, collider1, collider2) => {
23
19
  rigidBody2Events
24
20
  };
25
21
  };
26
- export const useFrameHandler = (ctx, stage) => {
22
+ const objectHasPhysicsUserData = (obj) => {
23
+ return obj.userData.physics !== undefined;
24
+ };
25
+ export const initializeRigidBodyUserData = (obj) => {
26
+ const userData = {
27
+ currentPosition: new Vector3(),
28
+ currentQuaternion: new Quaternion(),
29
+ lastPosition: new Vector3(),
30
+ lastQuaternion: new Quaternion(),
31
+ resetPosition: false,
32
+ resetRotation: false
33
+ };
34
+ obj.userData.physics = userData;
35
+ return userData;
36
+ };
37
+ export const setInitialRigidBodyState = (obj, initialPosition, initialQuaternion) => {
38
+ if (!objectHasPhysicsUserData(obj)) {
39
+ initializeRigidBodyUserData(obj);
40
+ }
41
+ const userData = obj.userData.physics;
42
+ userData.currentPosition.copy(initialPosition);
43
+ userData.lastPosition.copy(initialPosition);
44
+ userData.currentQuaternion.copy(initialQuaternion);
45
+ userData.lastQuaternion.copy(initialQuaternion);
46
+ };
47
+ export const createPhysicsTasks = (world, framerate, simulationOffset, rigidBodyObjects, updateRigidBodySimulationData, colliderEventDispatchers, rigidBodyEventDispatchers, simulationStage, synchronizationStage) => {
27
48
  const eventQueue = new EventQueue(false);
28
- const { start, started, stop } = useTask((delta) => {
29
- // if (!eventQueue) return
30
- const { world } = ctx;
49
+ const simulation = useTask(simulationKey, (delta) => {
31
50
  // Set timestep to current delta, to allow for variable frame rates
32
51
  // We cap the delta at 100, so that the physics simulation doesn't get wild
33
- world.timestep = Math.min(0.1, delta);
52
+ if (framerate.current === 'varying') {
53
+ world.timestep = Math.min(delta, 0.1);
54
+ }
55
+ else {
56
+ world.timestep = delta;
57
+ }
34
58
  world.step(eventQueue);
35
- // Update meshes
36
- ctx.rigidBodyObjects.forEach((mesh, handle) => {
59
+ rigidBodyObjects.forEach((mesh, handle) => {
37
60
  const rigidBody = world.getRigidBody(handle);
38
- if (!rigidBody)
39
- return;
40
- const events = ctx.rigidBodyEventDispatchers.get(handle);
41
61
  if (!rigidBody || !rigidBody.isValid())
42
62
  return;
63
+ const events = rigidBodyEventDispatchers.get(handle);
43
64
  if (events) {
44
65
  if (rigidBody.isSleeping() && !mesh.userData.isSleeping) {
45
- events.sleep?.();
66
+ events.onsleep?.();
46
67
  }
47
68
  if (!rigidBody.isSleeping() && mesh.userData.isSleeping) {
48
- events.wake?.();
69
+ events.onwake?.();
49
70
  }
50
71
  mesh.userData.isSleeping = rigidBody.isSleeping();
51
72
  }
52
- if (!rigidBody || rigidBody.isSleeping() || rigidBody.isFixed() || !mesh.parent) {
73
+ if (rigidBody.isSleeping() || rigidBody.isFixed() || !mesh.parent) {
53
74
  return;
54
75
  }
55
- // Position
56
- const { x, y, z } = rigidBody.translation();
57
- tempObject.position.set(x, y, z);
58
- // Rotation
59
- const rotation = rigidBody.rotation();
60
- tempQuaternion.set(rotation.x, rotation.y, rotation.z, rotation.w);
61
- tempObject.rotation.setFromQuaternion(tempQuaternion);
62
- // Scale
63
- mesh.getWorldScale(tempVector3);
64
- tempObject.scale.copy(tempVector3);
65
- tempObject.updateMatrix();
66
- tempObject.applyMatrix4(mesh.parent.matrixWorld.clone().invert());
67
- tempObject.updateMatrix();
68
- mesh.position.setFromMatrixPosition(tempObject.matrix);
69
- mesh.rotation.setFromRotationMatrix(tempObject.matrix);
76
+ if (updateRigidBodySimulationData.current) {
77
+ const translation = rigidBody.translation();
78
+ const rotation = rigidBody.rotation();
79
+ if (objectHasPhysicsUserData(mesh)) {
80
+ const userData = mesh.userData.physics;
81
+ if (userData.resetPosition) {
82
+ userData.resetPosition = false;
83
+ userData.lastPosition.set(translation.x, translation.y, translation.z);
84
+ userData.currentPosition.set(translation.x, translation.y, translation.z);
85
+ }
86
+ else {
87
+ userData.lastPosition.copy(userData.currentPosition);
88
+ userData.currentPosition.set(translation.x, translation.y, translation.z);
89
+ }
90
+ if (userData.resetRotation) {
91
+ userData.resetRotation = false;
92
+ userData.lastQuaternion.set(rotation.x, rotation.y, rotation.z, rotation.w);
93
+ userData.currentQuaternion.set(rotation.x, rotation.y, rotation.z, rotation.w);
94
+ }
95
+ else {
96
+ userData.lastQuaternion.copy(userData.currentQuaternion);
97
+ userData.currentQuaternion.set(rotation.x, rotation.y, rotation.z, rotation.w);
98
+ }
99
+ }
100
+ else {
101
+ initializeRigidBodyUserData(mesh);
102
+ setInitialRigidBodyState(mesh, tempVector3.set(translation.x, translation.y, translation.z), tempQuaternion.set(rotation.x, rotation.y, rotation.z, rotation.w));
103
+ }
104
+ }
70
105
  });
71
106
  eventQueue.drainContactForceEvents((e) => {
72
107
  const collider1 = world.getCollider(e.collider1());
@@ -75,11 +110,11 @@ export const useFrameHandler = (ctx, stage) => {
75
110
  if (!collider1 || !collider2) {
76
111
  return;
77
112
  }
78
- const { collider1Events, collider2Events, rigidBody1Events, rigidBody2Events } = getEventDispatchers(ctx, collider1, collider2);
113
+ const { collider1Events, collider2Events, rigidBody1Events, rigidBody2Events } = getEventDispatchers(collider1, collider2, colliderEventDispatchers, rigidBodyEventDispatchers);
79
114
  const rigidBody1 = collider1.parent();
80
115
  const rigidBody2 = collider2.parent();
81
116
  // Collider events
82
- collider1Events?.contact?.({
117
+ collider1Events?.oncontact?.({
83
118
  targetCollider: collider2,
84
119
  targetRigidBody: rigidBody2,
85
120
  maxForceDirection: e.maxForceDirection(),
@@ -87,7 +122,7 @@ export const useFrameHandler = (ctx, stage) => {
87
122
  totalForce: e.totalForce(),
88
123
  totalForceMagnitude: e.totalForceMagnitude()
89
124
  });
90
- collider2Events?.contact?.({
125
+ collider2Events?.oncontact?.({
91
126
  targetCollider: collider1,
92
127
  targetRigidBody: rigidBody1,
93
128
  maxForceDirection: e.maxForceDirection(),
@@ -96,7 +131,7 @@ export const useFrameHandler = (ctx, stage) => {
96
131
  totalForceMagnitude: e.totalForceMagnitude()
97
132
  });
98
133
  // RigidBody Events
99
- rigidBody1Events?.contact?.({
134
+ rigidBody1Events?.oncontact?.({
100
135
  targetCollider: collider2,
101
136
  targetRigidBody: rigidBody2,
102
137
  maxForceDirection: e.maxForceDirection(),
@@ -104,7 +139,7 @@ export const useFrameHandler = (ctx, stage) => {
104
139
  totalForce: e.totalForce(),
105
140
  totalForceMagnitude: e.totalForceMagnitude()
106
141
  });
107
- rigidBody2Events?.contact?.({
142
+ rigidBody2Events?.oncontact?.({
108
143
  targetCollider: collider1,
109
144
  targetRigidBody: rigidBody1,
110
145
  maxForceDirection: e.maxForceDirection(),
@@ -121,7 +156,7 @@ export const useFrameHandler = (ctx, stage) => {
121
156
  if (!collider1 || !collider2) {
122
157
  return;
123
158
  }
124
- const { collider1Events, collider2Events, rigidBody1Events, rigidBody2Events } = getEventDispatchers(ctx, collider1, collider2);
159
+ const { collider1Events, collider2Events, rigidBody1Events, rigidBody2Events } = getEventDispatchers(collider1, collider2, colliderEventDispatchers, rigidBodyEventDispatchers);
125
160
  if (!collider1Events && !collider2Events && !rigidBody1Events && !rigidBody2Events) {
126
161
  return;
127
162
  }
@@ -132,20 +167,20 @@ export const useFrameHandler = (ctx, stage) => {
132
167
  const isIntersection = world.intersectionPair(collider1, collider2);
133
168
  if (isIntersection) {
134
169
  // Collider Events
135
- collider1Events?.sensorenter?.({
170
+ collider1Events?.onsensorenter?.({
136
171
  targetCollider: collider2,
137
172
  targetRigidBody: rigidBody2
138
173
  });
139
- collider2Events?.sensorenter?.({
174
+ collider2Events?.onsensorenter?.({
140
175
  targetCollider: collider1,
141
176
  targetRigidBody: rigidBody1
142
177
  });
143
178
  // RigidBody Events
144
- rigidBody1Events?.sensorenter?.({
179
+ rigidBody1Events?.onsensorenter?.({
145
180
  targetCollider: collider2,
146
181
  targetRigidBody: rigidBody2
147
182
  });
148
- rigidBody2Events?.sensorenter?.({
183
+ rigidBody2Events?.onsensorenter?.({
149
184
  targetCollider: collider1,
150
185
  targetRigidBody: rigidBody1
151
186
  });
@@ -154,26 +189,26 @@ export const useFrameHandler = (ctx, stage) => {
154
189
  }
155
190
  world.contactPair(collider1, collider2, (manifold, flipped) => {
156
191
  // Collider events
157
- collider1Events?.collisionenter?.({
192
+ collider1Events?.oncollisionenter?.({
158
193
  flipped,
159
194
  manifold,
160
195
  targetCollider: collider2,
161
196
  targetRigidBody: rigidBody2
162
197
  });
163
- collider2Events?.collisionenter?.({
198
+ collider2Events?.oncollisionenter?.({
164
199
  flipped,
165
200
  manifold,
166
201
  targetCollider: collider1,
167
202
  targetRigidBody: rigidBody1
168
203
  });
169
204
  // RigidBody Events
170
- rigidBody1Events?.collisionenter?.({
205
+ rigidBody1Events?.oncollisionenter?.({
171
206
  flipped,
172
207
  manifold,
173
208
  targetCollider: collider2,
174
209
  targetRigidBody: rigidBody2
175
210
  });
176
- rigidBody2Events?.collisionenter?.({
211
+ rigidBody2Events?.oncollisionenter?.({
177
212
  flipped,
178
213
  manifold,
179
214
  targetCollider: collider1,
@@ -188,20 +223,20 @@ export const useFrameHandler = (ctx, stage) => {
188
223
  collider1.isSensor() ||
189
224
  collider2.isSensor();
190
225
  if (isIntersection) {
191
- collider1Events?.sensorexit?.({
226
+ collider1Events?.onsensorexit?.({
192
227
  targetCollider: collider2,
193
228
  targetRigidBody: rigidBody2
194
229
  });
195
- collider2Events?.sensorexit?.({
230
+ collider2Events?.onsensorexit?.({
196
231
  targetCollider: collider1,
197
232
  targetRigidBody: rigidBody1
198
233
  });
199
234
  // RigidBody Events
200
- rigidBody1Events?.sensorexit?.({
235
+ rigidBody1Events?.onsensorexit?.({
201
236
  targetCollider: collider2,
202
237
  targetRigidBody: rigidBody2
203
238
  });
204
- rigidBody2Events?.sensorexit?.({
239
+ rigidBody2Events?.onsensorexit?.({
205
240
  targetCollider: collider1,
206
241
  targetRigidBody: rigidBody1
207
242
  });
@@ -209,28 +244,60 @@ export const useFrameHandler = (ctx, stage) => {
209
244
  return;
210
245
  }
211
246
  // Collider events
212
- collider1Events?.collisionexit?.({
247
+ collider1Events?.oncollisionexit?.({
213
248
  targetCollider: collider2,
214
249
  targetRigidBody: rigidBody2
215
250
  });
216
- collider2Events?.collisionexit?.({
251
+ collider2Events?.oncollisionexit?.({
217
252
  targetCollider: collider1,
218
253
  targetRigidBody: rigidBody1
219
254
  });
220
255
  // RigidBody Events
221
- rigidBody1Events?.collisionexit?.({
256
+ rigidBody1Events?.oncollisionexit?.({
222
257
  targetCollider: collider2,
223
258
  targetRigidBody: rigidBody2
224
259
  });
225
- rigidBody2Events?.collisionexit?.({
260
+ rigidBody2Events?.oncollisionexit?.({
226
261
  targetCollider: collider1,
227
262
  targetRigidBody: rigidBody1
228
263
  });
229
264
  }
230
265
  });
231
- }, { stage });
232
- // replacing the original pause and resume functions as well as the paused property
233
- ctx.pause = () => stop();
234
- ctx.resume = () => start();
235
- ctx.paused = derived(started, (started) => !started);
266
+ }, {
267
+ stage: simulationStage
268
+ });
269
+ const synchronization = useTask(synchronizationKey, () => {
270
+ rigidBodyObjects.forEach((mesh) => {
271
+ if (!objectHasPhysicsUserData(mesh))
272
+ return;
273
+ const userData = mesh.userData.physics;
274
+ if (framerate.current === 'varying') {
275
+ tempObject.position.copy(userData.currentPosition);
276
+ tempObject.quaternion.copy(userData.currentQuaternion);
277
+ }
278
+ else {
279
+ tempObject.position
280
+ .copy(userData.lastPosition)
281
+ .lerp(userData.currentPosition, simulationOffset.current);
282
+ tempObject.quaternion
283
+ .copy(userData.lastQuaternion)
284
+ .slerp(userData.currentQuaternion, simulationOffset.current);
285
+ }
286
+ // Rapier has no concept of scale, so we use the mesh's scale
287
+ mesh.getWorldScale(tempVector3);
288
+ tempObject.scale.copy(tempVector3);
289
+ tempObject.updateMatrix();
290
+ if (mesh.parent)
291
+ tempObject.applyMatrix4(mesh.parent.matrixWorld.clone().invert());
292
+ tempObject.updateMatrix();
293
+ mesh.position.setFromMatrixPosition(tempObject.matrix);
294
+ mesh.rotation.setFromRotationMatrix(tempObject.matrix);
295
+ });
296
+ }, {
297
+ stage: synchronizationStage
298
+ });
299
+ return {
300
+ simulationTask: simulation.task,
301
+ synchronizationTask: synchronization.task
302
+ };
236
303
  };
@@ -1,21 +1,15 @@
1
- /// <reference types="svelte" />
2
- import type { Collider, RigidBody } from '@dimforge/rapier3d-compat';
3
1
  import RAPIER from '@dimforge/rapier3d-compat';
4
- import type { Object3D } from 'three';
5
- import type { ColliderEventDispatchers, RigidBodyEventDispatchers } from '../types/types';
6
- export declare const createRapierContext: (gravity: RAPIER.Vector, rawIntegrationParameters?: import("@dimforge/rapier3d-compat/rapier_wasm3d").RawIntegrationParameters | undefined, rawIslands?: import("@dimforge/rapier3d-compat/rapier_wasm3d").RawIslandManager | undefined, rawBroadPhase?: import("@dimforge/rapier3d-compat/rapier_wasm3d").RawBroadPhase | undefined, rawNarrowPhase?: import("@dimforge/rapier3d-compat/rapier_wasm3d").RawNarrowPhase | undefined, rawBodies?: import("@dimforge/rapier3d-compat/rapier_wasm3d").RawRigidBodySet | undefined, rawColliders?: import("@dimforge/rapier3d-compat/rapier_wasm3d").RawColliderSet | undefined, rawImpulseJoints?: import("@dimforge/rapier3d-compat/rapier_wasm3d").RawImpulseJointSet | undefined, rawMultibodyJoints?: import("@dimforge/rapier3d-compat/rapier_wasm3d").RawMultibodyJointSet | undefined, rawCCDSolver?: import("@dimforge/rapier3d-compat/rapier_wasm3d").RawCCDSolver | undefined, rawQueryPipeline?: import("@dimforge/rapier3d-compat/rapier_wasm3d").RawQueryPipeline | undefined, rawPhysicsPipeline?: import("@dimforge/rapier3d-compat/rapier_wasm3d").RawPhysicsPipeline | undefined, rawSerializationPipeline?: import("@dimforge/rapier3d-compat/rapier_wasm3d").RawSerializationPipeline | undefined, rawDebugRenderPipeline?: import("@dimforge/rapier3d-compat/rapier_wasm3d").RawDebugRenderPipeline | undefined) => {
7
- rapier: typeof RAPIER;
8
- world: RAPIER.World;
9
- colliderObjects: Map<number, Object3D<import("three").Object3DEventMap>>;
10
- rigidBodyObjects: Map<number, Object3D<import("three").Object3DEventMap>>;
11
- rigidBodyEventDispatchers: RigidBodyEventDispatchers;
12
- colliderEventDispatchers: ColliderEventDispatchers;
13
- addColliderToContext: (collider: Collider, object: Object3D, events: Record<string, (arg: unknown) => void>) => void;
14
- removeColliderFromContext: (collider: Collider) => void;
15
- addRigidBodyToContext: (rigidBody: RigidBody, object: Object3D, events: Record<string, (arg: unknown) => void>) => void;
16
- removeRigidBodyFromContext: (rigidBody: RigidBody) => void;
17
- debug: import("svelte/store").Writable<boolean>;
18
- pause: () => void;
19
- resume: () => void;
20
- paused: import("svelte/store").Readable<boolean>;
21
- };
2
+ import { type Key, type Stage } from '@threlte/core';
3
+ import type { Framerate, RapierContext } from '../types/types';
4
+ export declare const createRapierContext: (worldArgs: [gravity: RAPIER.Vector, rawIntegrationParameters?: import("@dimforge/rapier3d-compat/rapier_wasm3d").RawIntegrationParameters | undefined, rawIslands?: import("@dimforge/rapier3d-compat/rapier_wasm3d").RawIslandManager | undefined, rawBroadPhase?: import("@dimforge/rapier3d-compat/rapier_wasm3d").RawBroadPhase | undefined, rawNarrowPhase?: import("@dimforge/rapier3d-compat/rapier_wasm3d").RawNarrowPhase | undefined, rawBodies?: import("@dimforge/rapier3d-compat/rapier_wasm3d").RawRigidBodySet | undefined, rawColliders?: import("@dimforge/rapier3d-compat/rapier_wasm3d").RawColliderSet | undefined, rawImpulseJoints?: import("@dimforge/rapier3d-compat/rapier_wasm3d").RawImpulseJointSet | undefined, rawMultibodyJoints?: import("@dimforge/rapier3d-compat/rapier_wasm3d").RawMultibodyJointSet | undefined, rawCCDSolver?: import("@dimforge/rapier3d-compat/rapier_wasm3d").RawCCDSolver | undefined, rawQueryPipeline?: import("@dimforge/rapier3d-compat/rapier_wasm3d").RawQueryPipeline | undefined, rawPhysicsPipeline?: import("@dimforge/rapier3d-compat/rapier_wasm3d").RawPhysicsPipeline | undefined, rawSerializationPipeline?: import("@dimforge/rapier3d-compat/rapier_wasm3d").RawSerializationPipeline | undefined, rawDebugRenderPipeline?: import("@dimforge/rapier3d-compat/rapier_wasm3d").RawDebugRenderPipeline | undefined], options: {
5
+ framerate?: Framerate;
6
+ autoStart?: boolean;
7
+ simulationStageOptions?: {
8
+ before?: (Key | Stage) | (Key | Stage)[];
9
+ after?: (Key | Stage) | (Key | Stage)[];
10
+ };
11
+ synchronizationStageOptions?: {
12
+ before?: (Key | Stage) | (Key | Stage)[];
13
+ after?: (Key | Stage) | (Key | Stage)[];
14
+ };
15
+ }) => RapierContext;
@@ -1,7 +1,10 @@
1
1
  import RAPIER from '@dimforge/rapier3d-compat';
2
- import { readable, writable } from 'svelte/store';
3
- export const createRapierContext = (...args) => {
4
- const world = new RAPIER.World(...args);
2
+ import { currentWritable } from '@threlte/core';
3
+ import { derived, writable } from 'svelte/store';
4
+ import { createPhysicsStages } from './createPhysicsStages';
5
+ import { createPhysicsTasks } from './createPhysicsTasks';
6
+ export const createRapierContext = (worldArgs, options) => {
7
+ const world = new RAPIER.World(...worldArgs);
5
8
  const colliderObjects = new Map();
6
9
  const rigidBodyObjects = new Map();
7
10
  const rigidBodyEventDispatchers = new Map();
@@ -12,9 +15,9 @@ export const createRapierContext = (...args) => {
12
15
  * @param object
13
16
  * @param eventDispatcher
14
17
  */
15
- const addColliderToContext = (collider, object, events) => {
18
+ const addColliderToContext = (collider, object, props) => {
16
19
  colliderObjects.set(collider.handle, object);
17
- colliderEventDispatchers.set(collider.handle, events);
20
+ colliderEventDispatchers.set(collider.handle, props);
18
21
  };
19
22
  /**
20
23
  * Removes the collider from the context
@@ -42,11 +45,17 @@ export const createRapierContext = (...args) => {
42
45
  rigidBodyObjects.delete(rigidBody.handle);
43
46
  rigidBodyEventDispatchers.delete(rigidBody.handle);
44
47
  };
45
- // Dummy functions, will be replaced by useFrameHandler fn
46
- // eslint-disable-next-line @typescript-eslint/no-empty-function
47
- const pause = () => { };
48
- // eslint-disable-next-line @typescript-eslint/no-empty-function
49
- const resume = () => { };
48
+ const framerate = currentWritable(options.framerate ?? 'varying');
49
+ const simulationOffset = currentWritable(1);
50
+ const updateRigidBodySimulationData = currentWritable(framerate.current === 'varying');
51
+ const { simulationStage, synchronizationStage } = createPhysicsStages(framerate, simulationOffset, updateRigidBodySimulationData, options);
52
+ const autostart = options.autoStart ?? true;
53
+ const paused = writable(!autostart);
54
+ if (!autostart) {
55
+ simulationStage.stop();
56
+ synchronizationStage.stop();
57
+ }
58
+ const { simulationTask, synchronizationTask } = createPhysicsTasks(world, framerate, simulationOffset, rigidBodyObjects, updateRigidBodySimulationData, colliderEventDispatchers, rigidBodyEventDispatchers, simulationStage, synchronizationStage);
50
59
  return {
51
60
  rapier: RAPIER,
52
61
  world,
@@ -59,8 +68,23 @@ export const createRapierContext = (...args) => {
59
68
  addRigidBodyToContext,
60
69
  removeRigidBodyFromContext,
61
70
  debug: writable(false),
62
- pause,
63
- resume,
64
- paused: readable(false)
71
+ pause: () => {
72
+ paused.set(true);
73
+ simulationStage.stop();
74
+ synchronizationStage.stop();
75
+ },
76
+ resume: () => {
77
+ paused.set(false);
78
+ simulationStage.start();
79
+ synchronizationStage.start();
80
+ },
81
+ paused: derived(paused, (a) => a),
82
+ framerate,
83
+ simulationOffset,
84
+ simulationStage,
85
+ synchronizationStage,
86
+ updateRigidBodySimulationData,
87
+ simulationTask,
88
+ synchronizationTask
65
89
  };
66
90
  };
@@ -0,0 +1 @@
1
+ export declare const initRapier: () => true | Promise<void>;
@@ -0,0 +1,16 @@
1
+ import RAPIER from '@dimforge/rapier3d-compat';
2
+ let initialized = false;
3
+ let promise;
4
+ export const initRapier = () => {
5
+ if (initialized)
6
+ return true;
7
+ if (!promise) {
8
+ promise = new Promise((resolve) => {
9
+ RAPIER.init().then(() => {
10
+ initialized = true;
11
+ resolve();
12
+ });
13
+ });
14
+ }
15
+ return promise;
16
+ };
@@ -0,0 +1,2 @@
1
+ export declare const simulationKey: unique symbol;
2
+ export declare const synchronizationKey: unique symbol;
@@ -0,0 +1,2 @@
1
+ export const simulationKey = Symbol('simulation');
2
+ export const synchronizationKey = Symbol('synchronization');
@@ -1,2 +1,3 @@
1
- export declare const useParentRigidbodyObject: () => THREE.Object3D | undefined;
2
- export declare const setParentRigidbodyObject: (object3d: THREE.Object3D) => void;
1
+ import type { Object3D } from 'three';
2
+ export declare const useParentRigidbodyObject: () => Object3D | undefined;
3
+ export declare const setParentRigidbodyObject: (object3d: Object3D) => void;
@@ -1,3 +1,4 @@
1
- export declare const useCreateEvent: <T>(events: Record<string, (arg: unknown) => void>) => {
1
+ import type { ColliderEvents } from '../types/types';
2
+ export declare const useCreateEvent: <T>(oncreate?: ColliderEvents['oncreate']) => {
2
3
  updateRef: (newRef: T) => void;
3
4
  };
@@ -1,7 +1,7 @@
1
1
  import { onDestroy } from 'svelte';
2
- export const useCreateEvent = (events) => {
2
+ export const useCreateEvent = (oncreate) => {
3
3
  const cleanupFunctions = [];
4
- let ref = undefined;
4
+ let ref;
5
5
  const dispatchCreateEvent = () => {
6
6
  // call every cleanup function
7
7
  cleanupFunctions.forEach((cleanup) => cleanup());
@@ -13,7 +13,7 @@ export const useCreateEvent = (events) => {
13
13
  };
14
14
  if (ref === undefined)
15
15
  return;
16
- events?.create?.({ ref, cleanup });
16
+ oncreate?.({ ref, cleanup });
17
17
  };
18
18
  const updateRef = (newRef) => {
19
19
  ref = newRef;