@threlte/rapier 3.0.0-next.2 → 3.0.0-next.20

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 (69) hide show
  1. package/dist/components/Attractor/Attractor.svelte.d.ts +3 -34
  2. package/dist/components/Attractor/types.d.ts +30 -0
  3. package/dist/components/Attractor/types.js +1 -0
  4. package/dist/components/Colliders/{AutoColliders.svelte → AutoColliders/AutoColliders.svelte} +27 -14
  5. package/dist/components/Colliders/AutoColliders/AutoColliders.svelte.d.ts +22 -0
  6. package/dist/components/Colliders/AutoColliders/types.d.ts +74 -0
  7. package/dist/components/Colliders/AutoColliders/types.js +1 -0
  8. package/dist/components/Colliders/{Collider.svelte → Collider/Collider.svelte} +30 -20
  9. package/dist/components/Colliders/Collider/Collider.svelte.d.ts +20 -0
  10. package/dist/components/Colliders/Collider/types.d.ts +83 -0
  11. package/dist/components/Colliders/Collider/types.js +1 -0
  12. package/dist/components/CollisionGroups/CollisionGroups.svelte +4 -1
  13. package/dist/components/CollisionGroups/CollisionGroups.svelte.d.ts +16 -33
  14. package/dist/components/CollisionGroups/types.d.ts +19 -0
  15. package/dist/components/CollisionGroups/types.js +1 -0
  16. package/dist/components/Debug/Debug.svelte +5 -5
  17. package/dist/components/Debug/Debug.svelte.d.ts +3 -7
  18. package/dist/components/Debug/types.d.ts +3 -0
  19. package/dist/components/Debug/types.js +1 -0
  20. package/dist/components/RigidBody/RigidBody.svelte +17 -6
  21. package/dist/components/RigidBody/RigidBody.svelte.d.ts +3 -102
  22. package/dist/components/RigidBody/overrideTeleportMethods.d.ts +14 -0
  23. package/dist/components/RigidBody/overrideTeleportMethods.js +31 -0
  24. package/dist/components/RigidBody/types.d.ts +85 -0
  25. package/dist/components/RigidBody/types.js +1 -0
  26. package/dist/components/World/InnerWorld.svelte +27 -5
  27. package/dist/components/World/InnerWorld.svelte.d.ts +3 -21
  28. package/dist/components/World/World.svelte +9 -57
  29. package/dist/components/World/World.svelte.d.ts +3 -38
  30. package/dist/components/World/types.d.ts +32 -0
  31. package/dist/components/World/types.js +1 -0
  32. package/dist/hooks/useFixedJoint.d.ts +2 -3
  33. package/dist/hooks/useJoint.d.ts +0 -1
  34. package/dist/hooks/usePhysicsTask.d.ts +16 -0
  35. package/dist/hooks/usePhysicsTask.js +32 -0
  36. package/dist/hooks/usePrismaticJoint.d.ts +1 -2
  37. package/dist/hooks/useRevoluteJoint.d.ts +1 -2
  38. package/dist/hooks/useRopeJoint.d.ts +10 -0
  39. package/dist/hooks/useRopeJoint.js +14 -0
  40. package/dist/hooks/useSphericalJoint.d.ts +1 -2
  41. package/dist/hooks/utils.js +3 -2
  42. package/dist/index.d.ts +5 -4
  43. package/dist/index.js +4 -4
  44. package/dist/lib/applyColliderActiveEvents.d.ts +1 -1
  45. package/dist/lib/applyTransforms.d.ts +1 -1
  46. package/dist/lib/createCollidersFromChildren.d.ts +1 -1
  47. package/dist/lib/createCollidersFromChildren.js +18 -3
  48. package/dist/lib/createPhysicsStages.d.ts +15 -0
  49. package/dist/lib/createPhysicsStages.js +43 -0
  50. package/dist/lib/createPhysicsTasks.d.ts +19 -0
  51. package/dist/{hooks/useFrameHandler.js → lib/createPhysicsTasks.js} +109 -40
  52. package/dist/lib/createRapierContext.d.ts +14 -20
  53. package/dist/lib/createRapierContext.js +35 -11
  54. package/dist/lib/eulerToQuaternion.d.ts +2 -2
  55. package/dist/lib/initRapier.svelte.d.ts +1 -0
  56. package/dist/lib/initRapier.svelte.js +16 -0
  57. package/dist/lib/keys.d.ts +2 -0
  58. package/dist/lib/keys.js +2 -0
  59. package/dist/lib/useCreateEvent.d.ts +2 -2
  60. package/dist/lib/useCreateEvent.js +3 -5
  61. package/dist/types/types.d.ts +36 -9
  62. package/package.json +33 -14
  63. package/dist/components/Colliders/AutoColliders.svelte.d.ts +0 -84
  64. package/dist/components/Colliders/Collider.svelte.d.ts +0 -109
  65. package/dist/hooks/useFrameHandler.d.ts +0 -3
  66. package/dist/hooks/useHasEventListener.d.ts +0 -3
  67. package/dist/hooks/useHasEventListener.js +0 -11
  68. package/dist/recipes/BasicPlayerController.svelte +0 -142
  69. package/dist/recipes/BasicPlayerController.svelte.d.ts +0 -31
@@ -1,3 +1,3 @@
1
- import type { ColliderEvents, RigidBodyEvents } from '../types/types';
2
1
  import { type Collider } from '@dimforge/rapier3d-compat';
2
+ import type { ColliderEvents, RigidBodyEvents } from '../types/types';
3
3
  export declare const applyColliderActiveEvents: (collider: Collider, colliderEvents?: ColliderEvents, rigidBodyEvents?: RigidBodyEvents) => void;
@@ -1,2 +1,2 @@
1
1
  import type { Euler, Object3D, Vector3 } from 'three';
2
- export declare const applyTransforms: (object: Object3D, position?: Parameters<Vector3['set']>, rotation?: Parameters<Euler['set']>, scale?: Parameters<Vector3['set']>) => void;
2
+ export declare const applyTransforms: (object: Object3D, position?: Parameters<Vector3["set"]>, rotation?: Parameters<Euler["set"]>, scale?: Parameters<Vector3["set"]>) => void;
@@ -1,4 +1,4 @@
1
- import { Collider, World, RigidBody } from '@dimforge/rapier3d-compat';
1
+ import { Collider, RigidBody, World } from '@dimforge/rapier3d-compat';
2
2
  import { type Object3D } from 'three';
3
3
  import type { AutoCollidersShapes } from '../types/types';
4
4
  /**
@@ -1,4 +1,5 @@
1
1
  import { ActiveEvents, ColliderDesc } from '@dimforge/rapier3d-compat';
2
+ import { isInstanceOf } from '@threlte/core';
2
3
  import { Quaternion, Vector3 } from 'three';
3
4
  const offset = new Vector3();
4
5
  const worldPosition = new Vector3();
@@ -33,7 +34,7 @@ export const createCollidersFromChildren = (object, collidersType, world, rigidB
33
34
  rigidBodyParentObject?.getWorldPosition(rigidBodyWorldPos);
34
35
  rigidBodyParentObject?.getWorldQuaternion(rigidBodyWorldQuatInversed).invert();
35
36
  object.traverse((child) => {
36
- if ('isMesh' in child) {
37
+ if (isInstanceOf(child, 'Mesh')) {
37
38
  const { geometry } = child;
38
39
  const worldPos = child.getWorldPosition(worldPosition);
39
40
  const translation = worldPos.sub(rigidBodyWorldPos);
@@ -62,7 +63,14 @@ export const createCollidersFromChildren = (object, collidersType, world, rigidB
62
63
  break;
63
64
  case 'trimesh':
64
65
  {
65
- description = ColliderDesc.trimesh(new Float32Array(geometry.attributes.position.array), new Uint32Array(geometry.index?.array ?? []));
66
+ const scaleX = scale.x;
67
+ const vertices = new Float32Array(geometry.attributes.position.array);
68
+ if (scaleX !== 1) {
69
+ for (let i = 0; i < vertices.length; i++) {
70
+ vertices[i] *= scaleX;
71
+ }
72
+ }
73
+ description = ColliderDesc.trimesh(vertices, new Uint32Array(geometry.index?.array ?? []));
66
74
  }
67
75
  break;
68
76
  case 'capsule':
@@ -77,7 +85,14 @@ export const createCollidersFromChildren = (object, collidersType, world, rigidB
77
85
  break;
78
86
  case 'convexHull':
79
87
  {
80
- description = ColliderDesc.convexHull(new Float32Array(geometry.attributes.position.array));
88
+ const scaleX = scale.x;
89
+ const vertices = new Float32Array(geometry.attributes.position.array);
90
+ if (scaleX !== 1) {
91
+ for (let i = 0; i < vertices.length; i++) {
92
+ vertices[i] *= scaleX;
93
+ }
94
+ }
95
+ description = ColliderDesc.convexHull(vertices);
81
96
  }
82
97
  break;
83
98
  }
@@ -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,21 +19,48 @@ 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
61
  if (!rigidBody || !rigidBody.isValid())
39
62
  return;
40
- const events = ctx.rigidBodyEventDispatchers.get(handle);
63
+ const events = rigidBodyEventDispatchers.get(handle);
41
64
  if (events) {
42
65
  if (rigidBody.isSleeping() && !mesh.userData.isSleeping) {
43
66
  events.onsleep?.();
@@ -50,21 +73,35 @@ export const useFrameHandler = (ctx, stage) => {
50
73
  if (rigidBody.isSleeping() || rigidBody.isFixed() || !mesh.parent) {
51
74
  return;
52
75
  }
53
- // Position
54
- const { x, y, z } = rigidBody.translation();
55
- tempObject.position.set(x, y, z);
56
- // Rotation
57
- const rotation = rigidBody.rotation();
58
- tempQuaternion.set(rotation.x, rotation.y, rotation.z, rotation.w);
59
- tempObject.rotation.setFromQuaternion(tempQuaternion);
60
- // Scale
61
- mesh.getWorldScale(tempVector3);
62
- tempObject.scale.copy(tempVector3);
63
- tempObject.updateMatrix();
64
- tempObject.applyMatrix4(mesh.parent.matrixWorld.clone().invert());
65
- tempObject.updateMatrix();
66
- mesh.position.setFromMatrixPosition(tempObject.matrix);
67
- 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
+ }
68
105
  });
69
106
  eventQueue.drainContactForceEvents((e) => {
70
107
  const collider1 = world.getCollider(e.collider1());
@@ -73,7 +110,7 @@ export const useFrameHandler = (ctx, stage) => {
73
110
  if (!collider1 || !collider2) {
74
111
  return;
75
112
  }
76
- const { collider1Events, collider2Events, rigidBody1Events, rigidBody2Events } = getEventDispatchers(ctx, collider1, collider2);
113
+ const { collider1Events, collider2Events, rigidBody1Events, rigidBody2Events } = getEventDispatchers(collider1, collider2, colliderEventDispatchers, rigidBodyEventDispatchers);
77
114
  const rigidBody1 = collider1.parent();
78
115
  const rigidBody2 = collider2.parent();
79
116
  // Collider events
@@ -119,7 +156,7 @@ export const useFrameHandler = (ctx, stage) => {
119
156
  if (!collider1 || !collider2) {
120
157
  return;
121
158
  }
122
- const { collider1Events, collider2Events, rigidBody1Events, rigidBody2Events } = getEventDispatchers(ctx, collider1, collider2);
159
+ const { collider1Events, collider2Events, rigidBody1Events, rigidBody2Events } = getEventDispatchers(collider1, collider2, colliderEventDispatchers, rigidBodyEventDispatchers);
123
160
  if (!collider1Events && !collider2Events && !rigidBody1Events && !rigidBody2Events) {
124
161
  return;
125
162
  }
@@ -226,9 +263,41 @@ export const useFrameHandler = (ctx, stage) => {
226
263
  });
227
264
  }
228
265
  });
229
- }, { stage });
230
- // replacing the original pause and resume functions as well as the paused property
231
- ctx.pause = () => stop();
232
- ctx.resume = () => start();
233
- 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
+ };
234
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 { ColliderEvents, RigidBodyEvents } 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: Map<number, RigidBodyEvents>;
12
- colliderEventDispatchers: Map<number, ColliderEvents>;
13
- addColliderToContext: (collider: Collider, object: Object3D, props: ColliderEvents) => void;
14
- removeColliderFromContext: (collider: Collider) => void;
15
- addRigidBodyToContext: (rigidBody: RigidBody, object: Object3D, events: RigidBodyEvents) => 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: ConstructorParameters<typeof RAPIER.World>, 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();
@@ -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
  };
@@ -1,7 +1,7 @@
1
- import { Quaternion } from 'three';
1
+ import { Euler, Quaternion } from 'three';
2
2
  /**
3
3
  * Sets the values of a temporary Euler and returns the quaternion from that
4
4
  * @param values
5
5
  * @returns
6
6
  */
7
- export declare const eulerToQuaternion: (values: [x: number, y: number, z: number, order?: import("three").EulerOrder | undefined]) => Quaternion;
7
+ export declare const eulerToQuaternion: (values: Parameters<Euler["set"]>) => Quaternion;
@@ -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,4 +1,4 @@
1
- import type { ColliderEvents } from '../types/types';
2
- export declare const useCreateEvent: <T>(oncreate?: ColliderEvents['oncreate']) => {
1
+ import type { CreateEvent } from '../types/types';
2
+ export declare const useCreateEvent: <T>(oncreate?: CreateEvent<T>["oncreate"]) => {
3
3
  updateRef: (newRef: T) => void;
4
4
  };
@@ -7,13 +7,11 @@ export const useCreateEvent = (oncreate) => {
7
7
  cleanupFunctions.forEach((cleanup) => cleanup());
8
8
  // clear the cleanup functions array
9
9
  cleanupFunctions.length = 0;
10
- const cleanup = (callback) => {
11
- // add cleanup function to array
12
- cleanupFunctions.push(callback);
13
- };
14
10
  if (ref === undefined)
15
11
  return;
16
- oncreate?.({ ref, cleanup });
12
+ const cleanup = oncreate?.(ref);
13
+ if (cleanup)
14
+ cleanupFunctions.push(cleanup);
17
15
  };
18
16
  const updateRef = (newRef) => {
19
17
  ref = newRef;
@@ -1,14 +1,14 @@
1
- /// <reference types="svelte" />
2
- import type { Collider, RigidBody, TempContactManifold, Vector } from '@dimforge/rapier3d-compat';
3
- import type { Writable } from 'svelte/store';
4
- import type { createRapierContext } from '../lib/createRapierContext';
1
+ import { World, type Collider, type RigidBody, type TempContactManifold, type Vector } from '@dimforge/rapier3d-compat';
2
+ import RAPIER from '@dimforge/rapier3d-compat';
3
+ import type { CurrentWritable, Stage, Task } from '@threlte/core';
4
+ import type { Readable, Writable } from 'svelte/store';
5
+ import type { Object3D } from 'three';
5
6
  export type ColliderShapes = 'ball' | 'capsule' | 'segment' | 'triangle' | 'roundTriangle' | 'polyline' | 'trimesh' | 'cuboid' | 'roundCuboid' | 'heightfield' | 'cylinder' | 'roundCylinder' | 'cone' | 'roundCone' | 'convexHull' | 'convexMesh' | 'roundConvexHull' | 'roundConvexMesh';
6
7
  export type AutoCollidersShapes = 'cuboid' | 'ball' | 'trimesh' | 'convexHull' | 'capsule';
8
+ export type CreateEvent<T> = {
9
+ oncreate?: (ref: T) => void | (() => void);
10
+ };
7
11
  export type ColliderEvents = {
8
- oncreate?: (event: {
9
- ref: Collider;
10
- cleanup: (callback: () => void) => void;
11
- }) => void;
12
12
  oncollisionenter?: (event: {
13
13
  targetCollider: Collider;
14
14
  targetRigidBody: RigidBody | null;
@@ -45,7 +45,6 @@ export type RigidBodyEvents = ColliderEvents & {
45
45
  onsleep?: () => void;
46
46
  onwake?: () => void;
47
47
  };
48
- export type RapierContext = ReturnType<typeof createRapierContext>;
49
48
  export type CollisionGroupsContext = Writable<number> | undefined;
50
49
  export type RigidBodyUserData = {
51
50
  events?: RigidBodyEvents;
@@ -59,3 +58,31 @@ export type CollisionGroupsBitMask = (0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10
59
58
  * Used in the <Attractor> component
60
59
  */
61
60
  export type GravityType = 'static' | 'linear' | 'newtonian';
61
+ export type Framerate = number | 'varying';
62
+ export type RapierContext = {
63
+ rapier: typeof RAPIER;
64
+ world: World;
65
+ colliderObjects: Map<number, Object3D>;
66
+ rigidBodyObjects: Map<number, Object3D>;
67
+ rigidBodyEventDispatchers: Map<number, RigidBodyEvents>;
68
+ colliderEventDispatchers: Map<number, ColliderEvents>;
69
+ addColliderToContext: (collider: Collider, object: Object3D, props: ColliderEvents) => void;
70
+ removeColliderFromContext: (collider: Collider) => void;
71
+ addRigidBodyToContext: (rigidBody: RigidBody, object: Object3D, events: RigidBodyEvents) => void;
72
+ removeRigidBodyFromContext: (rigidBody: RigidBody) => void;
73
+ debug: Writable<boolean>;
74
+ pause: () => void;
75
+ resume: () => void;
76
+ paused: Readable<boolean>;
77
+ framerate: CurrentWritable<Framerate>;
78
+ simulationStage: Stage;
79
+ simulationTask: Task;
80
+ synchronizationStage: Stage;
81
+ synchronizationTask: Task;
82
+ /**
83
+ * This number tells us how far we're off in the simulation stage as opposed
84
+ * to the render stage
85
+ */
86
+ simulationOffset: CurrentWritable<number>;
87
+ updateRigidBodySimulationData: CurrentWritable<boolean>;
88
+ };