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

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,7 +1,7 @@
1
1
  <script lang="ts">import { T, useTask } from '@threlte/core';
2
2
  import { Group, Vector3 } from 'three';
3
3
  import { useRapier } from '../../hooks/useRapier';
4
- let { strength = 1, range = 50, gravityType = 'static', gravitationalConstant = 6.673e-11, ref = $bindable(), ...props } = $props();
4
+ let { strength = 1, range = 50, gravityType = 'static', gravitationalConstant = 6.673e-11, ref = $bindable(), children, ...props } = $props();
5
5
  const { world, debug } = useRapier();
6
6
  const gravitySource = new Vector3();
7
7
  const group = new Group();
@@ -37,7 +37,7 @@ useTask(() => {
37
37
  bind:ref
38
38
  {...props}
39
39
  >
40
- <slot ref={group} />
40
+ {@render children?.({ ref: group })}
41
41
 
42
42
  {#if $debug}
43
43
  <T.Mesh>
@@ -1,4 +1,4 @@
1
- import { Props, type Events, type Slots } from '@threlte/core'
1
+ import { Props } from '@threlte/core'
2
2
  import { SvelteComponent } from 'svelte'
3
3
  import type { Group } from 'three'
4
4
  import type { GravityType } from '../../types/types'
@@ -31,12 +31,4 @@ type AttractorProps = Props<Group> & {
31
31
  gravitationalConstant?: number
32
32
  }
33
33
 
34
- type AttractorEvents = Events<Group>
35
-
36
- type AttractorSlots = Slots<Group>
37
-
38
- export default class Attractor extends SvelteComponent<
39
- AttractorProps,
40
- AttractorEvents,
41
- AttractorSlots
42
- > {}
34
+ export default class Attractor extends SvelteComponent<AttractorProps> {}
@@ -1,18 +1,18 @@
1
1
  <script lang="ts">import { ActiveCollisionTypes, CoefficientCombineRule } from '@dimforge/rapier3d-compat';
2
- import { SceneGraphObject } from '@threlte/core';
2
+ import { createParentObject3DContext, useParentObject3D, watch } from '@threlte/core';
3
3
  import { onDestroy, onMount } from 'svelte';
4
4
  import { Group } from 'three';
5
5
  import { useCollisionGroups } from '../../hooks/useCollisionGroups';
6
6
  import { useRapier } from '../../hooks/useRapier';
7
7
  import { useRigidBody } from '../../hooks/useRigidBody';
8
- import { useCreateEvent } from '../../lib/useCreateEvent';
9
- import { useParentRigidbodyObject } from '../../lib/rigidBodyObjectContext';
10
8
  import { applyColliderActiveEvents } from '../../lib/applyColliderActiveEvents';
11
9
  import { createCollidersFromChildren } from '../../lib/createCollidersFromChildren';
12
10
  import { eulerToQuaternion } from '../../lib/eulerToQuaternion';
13
- let { shape = 'convexHull', restitution, restitutionCombineRule, friction, frictionCombineRule, sensor, contactForceEventThreshold, density, mass, centerOfMass, principalAngularInertia, angularInertiaLocalFrame, refresh = $bindable(() => create()), colliders = $bindable(), ...props } = $props();
11
+ import { useParentRigidbodyObject } from '../../lib/rigidBodyObjectContext';
12
+ import { useCreateEvent } from '../../lib/useCreateEvent';
13
+ let { shape = 'convexHull', restitution, restitutionCombineRule, friction, frictionCombineRule, sensor, contactForceEventThreshold, density, mass, centerOfMass, principalAngularInertia, angularInertiaLocalFrame, refresh = $bindable(() => create()), colliders = $bindable(), oncreate, oncollisionenter, oncollisionexit, oncontact, onsensorenter, onsensorexit, children } = $props();
14
14
  const group = new Group();
15
- const { updateRef } = useCreateEvent(props.$$events);
15
+ const { updateRef } = useCreateEvent(oncreate);
16
16
  const rigidBody = useRigidBody();
17
17
  const rigidBodyParentObject = useParentRigidbodyObject();
18
18
  const { world, addColliderToContext, removeColliderFromContext } = useRapier();
@@ -27,13 +27,20 @@ const cleanup = () => {
27
27
  });
28
28
  colliders.length = 0;
29
29
  };
30
+ const events = {
31
+ oncollisionenter,
32
+ oncollisionexit,
33
+ oncontact,
34
+ onsensorenter,
35
+ onsensorexit
36
+ };
30
37
  const create = () => {
31
38
  cleanup();
32
39
  colliders = createCollidersFromChildren(group, shape ?? 'convexHull', world, rigidBody, rigidBodyParentObject);
33
- colliders.forEach((c) => addColliderToContext(c, group, props.$$events));
40
+ colliders.forEach((c) => addColliderToContext(c, group, events));
34
41
  collisionGroups.registerColliders(colliders);
35
42
  colliders.forEach((collider) => {
36
- applyColliderActiveEvents(collider, props.$$events, rigidBody?.userData?.events);
43
+ applyColliderActiveEvents(collider, events, rigidBody?.userData?.events);
37
44
  collider.setActiveCollisionTypes(ActiveCollisionTypes.ALL);
38
45
  collider.setRestitution(restitution ?? 0);
39
46
  collider.setRestitutionCombineRule(restitutionCombineRule ?? CoefficientCombineRule.Average);
@@ -63,11 +70,14 @@ onMount(() => {
63
70
  * Cleanup
64
71
  */
65
72
  onDestroy(cleanup);
73
+ const parent3DObject = useParentObject3D();
74
+ createParentObject3DContext(group);
75
+ watch(parent3DObject, (parent) => {
76
+ parent?.add(group);
77
+ return () => {
78
+ parent?.remove(group);
79
+ };
80
+ });
66
81
  </script>
67
82
 
68
- <SceneGraphObject object={group}>
69
- <slot
70
- {colliders}
71
- {refresh}
72
- />
73
- </SceneGraphObject>
83
+ {@render children?.({ colliders: colliders ?? [], refresh })}
@@ -1,7 +1,7 @@
1
1
  import type { CoefficientCombineRule, Collider } from '@dimforge/rapier3d-compat'
2
- import { SvelteComponent } from 'svelte'
2
+ import { SvelteComponent, type Snippet } from 'svelte'
3
3
  import type { Euler, Vector3 } from 'three'
4
- import type { AutoCollidersShapes, ColliderEventMap } from '../../types/types'
4
+ import type { AutoCollidersShapes, ColliderEvents } from '../../types/types'
5
5
 
6
6
  // ------------------ BASE ------------------
7
7
 
@@ -14,7 +14,10 @@ type BaseProps = {
14
14
  sensor?: boolean
15
15
  colliders?: Collider[]
16
16
  contactForceEventThreshold?: number
17
+
17
18
  refresh?: () => void
19
+
20
+ oncreate?: () => void
18
21
  }
19
22
 
20
23
  // ------------------ MASS ------------------
@@ -64,17 +67,18 @@ type MassProps<TMassDef extends MassDef> = TMassDef extends Density
64
67
 
65
68
  // ------------------ COLLIDER ------------------
66
69
 
67
- export type AutoCollidersProps<TMassDef extends MassDef> = BaseProps & MassProps<TMassDef>
68
-
69
- type AutoCollidersSlots = {
70
- default: {
71
- colliders: Collider[]
72
- refresh: () => void
70
+ export type AutoCollidersProps<TMassDef extends MassDef> = BaseProps &
71
+ MassProps<TMassDef> & {
72
+ children?: Snippet<
73
+ [
74
+ {
75
+ colliders: Collider[]
76
+ refresh: () => void
77
+ }
78
+ ]
79
+ >
73
80
  }
74
- }
75
81
 
76
82
  export default class AutoColliders<TMassDef extends MassDef> extends SvelteComponent<
77
- AutoCollidersProps<TMassDef>,
78
- ColliderEventMap,
79
- AutoCollidersSlots
83
+ AutoCollidersProps<TMassDef>
80
84
  > {}
@@ -1,30 +1,37 @@
1
1
  <script lang="ts">import { ActiveCollisionTypes, CoefficientCombineRule, Collider, ColliderDesc } from '@dimforge/rapier3d-compat';
2
- import { SceneGraphObject, useTask } from '@threlte/core';
2
+ import { createParentObject3DContext, useParentObject3D, useTask, watch } from '@threlte/core';
3
3
  import { onDestroy, onMount, tick } from 'svelte';
4
4
  import { Object3D, Quaternion, Vector3 } from 'three';
5
5
  import { useCollisionGroups } from '../../hooks/useCollisionGroups';
6
6
  import { useRapier } from '../../hooks/useRapier';
7
7
  import { useRigidBody } from '../../hooks/useRigidBody';
8
- import { useParentRigidbodyObject } from '../../lib/rigidBodyObjectContext';
9
- import { useCreateEvent } from '../../lib/useCreateEvent';
10
8
  import { applyColliderActiveEvents } from '../../lib/applyColliderActiveEvents';
11
9
  import { eulerToQuaternion } from '../../lib/eulerToQuaternion';
12
10
  import { getWorldPosition, getWorldQuaternion } from '../../lib/getWorldTransforms';
11
+ import { useParentRigidbodyObject } from '../../lib/rigidBodyObjectContext';
13
12
  import { scaleColliderArgs } from '../../lib/scaleColliderArgs';
13
+ import { useCreateEvent } from '../../lib/useCreateEvent';
14
14
  let { shape, args, type, restitution, restitutionCombineRule, friction, frictionCombineRule, sensor, contactForceEventThreshold, density, mass, centerOfMass, principalAngularInertia, angularInertiaLocalFrame, collider = $bindable(), refresh = $bindable(() => {
15
15
  if (!collider)
16
16
  return;
17
17
  collider.setTranslation(getWorldPosition(object));
18
18
  collider.setRotation(getWorldQuaternion(object));
19
- }), ...props } = $props();
19
+ }), oncreate, oncollisionenter, oncollisionexit, oncontact, onsensorenter, onsensorexit, children } = $props();
20
20
  const object = new Object3D();
21
- const { updateRef } = useCreateEvent(props.$$events);
21
+ const { updateRef } = useCreateEvent(oncreate);
22
22
  const rigidBody = useRigidBody();
23
23
  const parentRigidBodyObject = useParentRigidbodyObject();
24
24
  const hasRigidBodyParent = !!rigidBody;
25
25
  const rapierContext = useRapier();
26
26
  const { world } = rapierContext;
27
27
  const collisionGroups = useCollisionGroups();
28
+ const events = {
29
+ oncollisionenter,
30
+ oncollisionexit,
31
+ oncontact,
32
+ onsensorenter,
33
+ onsensorexit
34
+ };
28
35
  /**
29
36
  * Actual collider setup happens onMount as only then
30
37
  * the transforms are finished.
@@ -41,7 +48,7 @@ onMount(async () => {
41
48
  /**
42
49
  * Add collider to context
43
50
  */
44
- rapierContext.addColliderToContext(collider, object, props.$$events);
51
+ rapierContext.addColliderToContext(collider, object, events);
45
52
  /**
46
53
  * For use in conjunction with component <CollisionGroups>
47
54
  */
@@ -98,7 +105,7 @@ $effect.pre(() => {
98
105
  });
99
106
  $effect.pre(() => {
100
107
  if (collider) {
101
- applyColliderActiveEvents(collider, props.$$events, rigidBody?.userData?.events);
108
+ applyColliderActiveEvents(collider, events, rigidBody?.userData?.events);
102
109
  }
103
110
  });
104
111
  /**
@@ -127,8 +134,14 @@ onDestroy(() => {
127
134
  world.removeCollider(collider, true);
128
135
  collider = undefined;
129
136
  });
137
+ const parent3DObject = useParentObject3D();
138
+ createParentObject3DContext(object);
139
+ watch(parent3DObject, (parent) => {
140
+ parent?.add(object);
141
+ return () => {
142
+ parent?.remove(object);
143
+ };
144
+ });
130
145
  </script>
131
146
 
132
- <SceneGraphObject {object}>
133
- <slot {collider} />
134
- </SceneGraphObject>
147
+ {@render children?.({ collider })}
@@ -3,9 +3,9 @@ import type {
3
3
  Collider as RapierCollider,
4
4
  ColliderDesc
5
5
  } from '@dimforge/rapier3d-compat'
6
- import { SvelteComponent } from 'svelte'
6
+ import { SvelteComponent, type Snippet } from 'svelte'
7
7
  import type { Euler, Vector3 } from 'three'
8
- import type { ColliderEventMap } from '../../types/types'
8
+ import type { ColliderEvents } from '../../types/types'
9
9
 
10
10
  // ------------------ BASE ------------------
11
11
 
@@ -97,16 +97,13 @@ type MassProps<TMassDef extends MassDef> = TMassDef extends Density
97
97
  // ------------------ COLLIDER ------------------
98
98
 
99
99
  export type ColliderProps<TShape extends Shape, TMassDef extends MassDef> = BaseProps &
100
+ ColliderEvents &
100
101
  ShapeProps<TShape> &
101
- MassProps<TMassDef>
102
-
103
- export type ColliderSlots = {
104
- default: {
105
- collider: RapierCollider
102
+ MassProps<TMassDef> & {
103
+ children?: Snippet<[{ collider?: RapierCollider }]>
106
104
  }
107
- }
108
105
 
109
106
  export default class Collider<
110
107
  TShape extends Shape,
111
108
  TMassDef extends MassDef
112
- > extends SvelteComponent<ColliderProps<TShape, TMassDef>, ColliderEventMap, ColliderSlots> {}
109
+ > extends SvelteComponent<ColliderProps<TShape, TMassDef>> {}
@@ -1,10 +1,10 @@
1
1
  <script lang="ts">import { setContext } from 'svelte';
2
2
  import { writable } from 'svelte/store';
3
3
  import { computeBitMask } from '../../lib/computeBitMask';
4
- let { groups, filter, memberships } = $props();
4
+ let { groups, filter, memberships, children } = $props();
5
5
  const store = writable(computeBitMask(groups, filter, memberships));
6
6
  $effect.pre(() => store.set(computeBitMask(groups, filter, memberships)));
7
7
  setContext('threlte-rapier-collision-group', store);
8
8
  </script>
9
9
 
10
- <slot />
10
+ {@render children?.()}
@@ -1,4 +1,4 @@
1
- import { SvelteComponent } from 'svelte'
1
+ import { SvelteComponent, type Snippet } from 'svelte'
2
2
 
3
3
  type N = 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15
4
4
 
@@ -11,6 +11,8 @@ type GroupsProps = {
11
11
 
12
12
  filter?: never
13
13
  memberships?: never
14
+
15
+ children?: Snippet
14
16
  }
15
17
 
16
18
  type MembershipsAndFilterProps = {
@@ -18,6 +20,8 @@ type MembershipsAndFilterProps = {
18
20
  memberships: N[]
19
21
 
20
22
  groups?: never
23
+
24
+ children?: Snippet
21
25
  }
22
26
 
23
27
  type GroupsDef = GroupsProps | MembershipsAndFilterProps
@@ -1,17 +1,23 @@
1
- <script lang="ts">import { SceneGraphObject } from '@threlte/core';
1
+ <script lang="ts">import { createParentObject3DContext, useParentObject3D, watch } from '@threlte/core';
2
2
  import { onDestroy, setContext, tick } from 'svelte';
3
3
  import { Object3D, Vector3 } from 'three';
4
4
  import { useRapier } from '../../hooks/useRapier';
5
+ import { initializeRigidBodyUserData, setInitialRigidBodyState } from '../../lib/createPhysicsTasks';
5
6
  import { getWorldPosition, getWorldQuaternion, getWorldScale } from '../../lib/getWorldTransforms';
6
7
  import { parseRigidBodyType } from '../../lib/parseRigidBodyType';
7
8
  import { setParentRigidbodyObject } from '../../lib/rigidBodyObjectContext';
8
9
  import { useCreateEvent } from '../../lib/useCreateEvent';
10
+ import { overrideTeleportMethods } from './overrideTeleportMethods';
9
11
  const { world, rapier, addRigidBodyToContext, removeRigidBodyFromContext } = useRapier();
10
- let { linearVelocity, angularVelocity, type = 'dynamic', canSleep = true, gravityScale = 1, ccd = false, angularDamping = 0, linearDamping = 0, lockRotations = false, lockTranslations = false, enabledRotations = [true, true, true], enabledTranslations = [true, true, true], dominance = 0, enabled = true, userData = {}, rigidBody = $bindable(), ...props } = $props();
11
- const { updateRef } = useCreateEvent(props.$$events);
12
+ let { linearVelocity, angularVelocity, type = 'dynamic', canSleep = true, gravityScale = 1, ccd = false, angularDamping = 0, linearDamping = 0, lockRotations = false, lockTranslations = false, enabledRotations = [true, true, true], enabledTranslations = [true, true, true], dominance = 0, enabled = true, userData = {}, rigidBody = $bindable(), oncreate, oncollisionenter, oncollisionexit, oncontact, onsensorenter, onsensorexit, onsleep, onwake, children } = $props();
13
+ /**
14
+ * Every RigidBody receives and forwards collision-related events
15
+ */
16
+ const { updateRef } = useCreateEvent(oncreate);
12
17
  const object = new Object3D();
18
+ initializeRigidBodyUserData(object);
13
19
  /**
14
- * isSleeping used for events "sleep" and "wake" in `useFrameHandler`
20
+ * isSleeping used for events "sleep" and "wake" in `createPhysicsTasks`
15
21
  */
16
22
  object.userData.isSleeping = false;
17
23
  /**
@@ -22,6 +28,7 @@ const desc = new rapier.RigidBodyDesc(parseRigidBodyType(type)).setCanSleep(canS
22
28
  * Temporary RigidBody init
23
29
  */
24
30
  let rigidBodyInternal = world.createRigidBody(desc);
31
+ overrideTeleportMethods(rigidBodyInternal, object);
25
32
  rigidBody = rigidBodyInternal;
26
33
  /**
27
34
  * Apply transforms after the parent component added "object" to itself
@@ -33,6 +40,7 @@ const initPosition = async () => {
33
40
  const parentWorldScale = object.parent ? getWorldScale(object.parent) : new Vector3(1, 1, 1);
34
41
  const worldPosition = getWorldPosition(object).multiply(parentWorldScale);
35
42
  const worldQuaternion = getWorldQuaternion(object);
43
+ setInitialRigidBodyState(object, worldPosition, worldQuaternion);
36
44
  rigidBodyInternal.setTranslation(worldPosition, true);
37
45
  rigidBodyInternal.setRotation(worldQuaternion, true);
38
46
  updateRef(rigidBodyInternal);
@@ -68,7 +76,15 @@ $effect.pre(() => rigidBodyInternal.setEnabled(enabled));
68
76
  */
69
77
  $effect.pre(() => {
70
78
  rigidBodyInternal.userData = {
71
- events: props.$$events,
79
+ events: {
80
+ oncollisionenter,
81
+ oncollisionexit,
82
+ oncontact,
83
+ onsensorenter,
84
+ onsensorexit,
85
+ onsleep,
86
+ onwake
87
+ },
72
88
  ...userData
73
89
  };
74
90
  });
@@ -84,7 +100,15 @@ setParentRigidbodyObject(object);
84
100
  /**
85
101
  * Add the mesh to the context
86
102
  */
87
- addRigidBodyToContext(rigidBodyInternal, object, props.$$events);
103
+ addRigidBodyToContext(rigidBodyInternal, object, {
104
+ oncollisionenter,
105
+ oncollisionexit,
106
+ oncontact,
107
+ onsensorenter,
108
+ onsensorexit,
109
+ onsleep,
110
+ onwake
111
+ });
88
112
  /**
89
113
  * cleanup
90
114
  */
@@ -92,8 +116,14 @@ onDestroy(() => {
92
116
  removeRigidBodyFromContext(rigidBodyInternal);
93
117
  world.removeRigidBody(rigidBodyInternal);
94
118
  });
119
+ const parent3DObject = useParentObject3D();
120
+ createParentObject3DContext(object);
121
+ watch(parent3DObject, (parent) => {
122
+ parent?.add(object);
123
+ return () => {
124
+ parent?.remove(object);
125
+ };
126
+ });
95
127
  </script>
96
128
 
97
- <SceneGraphObject {object}>
98
- <slot rigidBody={rigidBodyInternal} />
99
- </SceneGraphObject>
129
+ {@render children?.({ rigidBody: rigidBodyInternal })}
@@ -1,13 +1,13 @@
1
1
  import { RigidBody as RapierRigidBody } from '@dimforge/rapier3d-compat'
2
- import { SvelteComponent } from 'svelte'
2
+ import { SvelteComponent, type Snippet } from 'svelte'
3
3
  import type { Euler, Vector3 } from 'three'
4
4
  import type { RigidBodyTypeString } from '../../lib/parseRigidBodyType'
5
- import type { RigidBodyEventMap } from '../../types/types'
5
+ import type { RigidBodyEvents } from '../../types/types'
6
6
 
7
7
  export type Boolean3Array = [x: boolean, y: boolean, z: boolean]
8
8
 
9
9
  export type RigidBodyProps = {
10
- rigidBody: RapierRigidBody
10
+ rigidBody?: RapierRigidBody | undefined
11
11
 
12
12
  /**
13
13
  * Specify the type of this rigid body
@@ -95,18 +95,8 @@ export type RigidBodyProps = {
95
95
  * An arbitrary user-defined object associated with this rigid-body.
96
96
  */
97
97
  userData?: Record<string, any>
98
- }
99
-
100
- type RigidBodyEvents = RigidBodyEventMap
101
98
 
102
- type RigidBodySlots = {
103
- default: {
104
- rigidBody: RapierRigidBody
105
- }
99
+ children?: Snippet<[{ rigidBody: RapierRigidBody }]>
106
100
  }
107
101
 
108
- export default class RigidBody extends SvelteComponent<
109
- RigidBodyProps,
110
- RigidBodyEvents,
111
- RigidBodySlots
112
- > {}
102
+ export default class RigidBody extends SvelteComponent<RigidBodyProps & RigidBodyEvents> {}
@@ -0,0 +1,14 @@
1
+ import type { RigidBody } from '@dimforge/rapier3d-compat';
2
+ import type { Object3D } from 'three';
3
+ export type ExtractMethods<ObjectType> = Pick<ObjectType, {
4
+ [Method in keyof ObjectType]: ObjectType[Method] extends (...args: any[]) => any ? Method : never;
5
+ }[keyof ObjectType]>;
6
+ /**
7
+ * When using a fixed framerate, Threlte is interpolating the position and
8
+ * rotation of RigidBody objects. Sometimes, this is not desirable, especially
9
+ * when using methods on the rigidbody that teleport the object, e.g. should
10
+ * lead to a sudden change in translation/rotation such as `rb.setTranslation`.
11
+ * These methods are overridden to reset the physics simulation position and
12
+ * rotation to the current object position and rotation.
13
+ */
14
+ export declare const overrideTeleportMethods: (rb: RigidBody, object: Object3D) => void;
@@ -0,0 +1,31 @@
1
+ const overrideMethods = {
2
+ position: ['setTranslation', 'setNextKinematicTranslation'],
3
+ rotation: ['setRotation', 'setNextKinematicRotation']
4
+ };
5
+ /**
6
+ * When using a fixed framerate, Threlte is interpolating the position and
7
+ * rotation of RigidBody objects. Sometimes, this is not desirable, especially
8
+ * when using methods on the rigidbody that teleport the object, e.g. should
9
+ * lead to a sudden change in translation/rotation such as `rb.setTranslation`.
10
+ * These methods are overridden to reset the physics simulation position and
11
+ * rotation to the current object position and rotation.
12
+ */
13
+ export const overrideTeleportMethods = (rb, object) => {
14
+ const originalMethods = {};
15
+ overrideMethods.position.forEach((method) => {
16
+ originalMethods[method] = rb[method].bind(rb);
17
+ const proxy = (...args) => {
18
+ object.userData.physics.resetPosition = true;
19
+ return originalMethods[method](...args);
20
+ };
21
+ rb[method] = proxy;
22
+ });
23
+ overrideMethods.rotation.forEach((method) => {
24
+ originalMethods[method] = rb[method].bind(rb);
25
+ const proxy = (...args) => {
26
+ object.userData.physics.resetRotation = true;
27
+ return originalMethods[method](...args);
28
+ };
29
+ rb[method] = proxy;
30
+ });
31
+ };
@@ -1,19 +1,41 @@
1
1
  <script lang="ts">import { onDestroy, setContext, tick } from 'svelte';
2
- import { useFrameHandler } from '../../hooks/useFrameHandler';
3
2
  import { createRapierContext } from '../../lib/createRapierContext';
4
- let { gravity = [0, -9.81, 0], rawIntegrationParameters, rawIslands, rawBroadPhase, rawNarrowPhase, rawBodies, rawColliders, rawImpulseJoints, rawMultibodyJoints, rawCCDSolver, rawQueryPipeline, rawPhysicsPipeline, rawSerializationPipeline, rawDebugRenderPipeline, stage } = $props();
5
- const rapierContext = createRapierContext({ x: gravity[0], y: gravity[1], z: gravity[2] }, rawIntegrationParameters, rawIslands, rawBroadPhase, rawNarrowPhase, rawBodies, rawColliders, rawImpulseJoints, rawMultibodyJoints, rawCCDSolver, rawQueryPipeline, rawPhysicsPipeline, rawSerializationPipeline, rawDebugRenderPipeline);
3
+ let { gravity = [0, -9.81, 0], rawIntegrationParameters, rawIslands, rawBroadPhase, rawNarrowPhase, rawBodies, rawColliders, rawImpulseJoints, rawMultibodyJoints, rawCCDSolver, rawQueryPipeline, rawPhysicsPipeline, rawSerializationPipeline, rawDebugRenderPipeline, framerate, autoStart = true, simulationStageOptions, synchronizationStageOptions, children } = $props();
4
+ const rapierContext = createRapierContext([
5
+ { x: gravity[0], y: gravity[1], z: gravity[2] },
6
+ rawIntegrationParameters,
7
+ rawIslands,
8
+ rawBroadPhase,
9
+ rawNarrowPhase,
10
+ rawBodies,
11
+ rawColliders,
12
+ rawImpulseJoints,
13
+ rawMultibodyJoints,
14
+ rawCCDSolver,
15
+ rawQueryPipeline,
16
+ rawPhysicsPipeline,
17
+ rawSerializationPipeline,
18
+ rawDebugRenderPipeline
19
+ ], {
20
+ framerate,
21
+ autoStart,
22
+ simulationStageOptions,
23
+ synchronizationStageOptions
24
+ });
6
25
  setContext('threlte-rapier-context', rapierContext);
7
26
  $effect.pre(() => {
8
27
  if (gravity !== undefined) {
9
28
  rapierContext.world.gravity = { x: gravity[0], y: gravity[1], z: gravity[2] };
10
29
  }
11
30
  });
12
- useFrameHandler(rapierContext, stage);
31
+ $effect.pre(() => {
32
+ if (framerate !== undefined)
33
+ rapierContext.framerate.set(framerate);
34
+ });
13
35
  onDestroy(async () => {
14
36
  await tick();
15
37
  rapierContext.world.free();
16
38
  });
17
39
  </script>
18
40
 
19
- <slot />
41
+ {@render children?.()}
@@ -1,17 +1,11 @@
1
1
  import { SvelteComponent } from "svelte";
2
2
  import type { WorldProps } from './World.svelte';
3
3
  declare const __propDef: {
4
- props: WorldProps & {
5
- children?: ((this: void) => typeof import("svelte").SnippetReturn & {
6
- _: "functions passed to {@render ...} tags must use the `Snippet` type imported from \"svelte\"";
7
- }) | undefined;
8
- };
4
+ props: WorldProps;
9
5
  events: {
10
6
  [evt: string]: CustomEvent<any>;
11
7
  };
12
- slots: {
13
- default: {};
14
- };
8
+ slots: {};
15
9
  };
16
10
  export type InnerWorldProps = typeof __propDef.props;
17
11
  export type InnerWorldEvents = typeof __propDef.events;
@@ -1,60 +1,12 @@
1
- <script
2
- context="module"
3
- lang="ts"
4
- >import RAPIER from '@dimforge/rapier3d-compat';
5
- import { onMount } from 'svelte';
6
- import { writable } from 'svelte/store';
7
- /**
8
- * RAPIER.init() should only be called once
9
- */
10
- const initialized = writable(false);
1
+ <script lang="ts">import { initRapier } from '../../lib/initRapier.svelte';
2
+ import InnerWorld from './InnerWorld.svelte';
3
+ let { fallback, children, ...rest } = $props();
11
4
  </script>
12
5
 
13
- <script lang="ts">import InnerWorld from './InnerWorld.svelte';
14
- let { gravity, rawIntegrationParameters, rawIslands, rawBroadPhase, rawNarrowPhase, rawBodies, rawColliders, rawImpulseJoints, rawMultibodyJoints, rawCCDSolver, rawQueryPipeline, rawPhysicsPipeline, rawSerializationPipeline, rawDebugRenderPipeline,
15
- /**
16
- * This is passed to the useTask handler.
17
- * Use this to control when the rapier physics engine is updating the scene.
18
- * @default undefined
19
- */
20
- stage } = $props();
21
- let error = $state(false);
22
- const init = async () => {
23
- if ($initialized)
24
- return;
25
- try {
26
- await RAPIER.init();
27
- $initialized = true;
28
- }
29
- catch (e) {
30
- error = true;
31
- }
32
- };
33
- onMount(init);
34
- </script>
35
-
36
- {#if $initialized}
37
- <InnerWorld
38
- {gravity}
39
- {rawIntegrationParameters}
40
- {rawIslands}
41
- {rawBroadPhase}
42
- {rawNarrowPhase}
43
- {rawBodies}
44
- {rawColliders}
45
- {rawImpulseJoints}
46
- {rawMultibodyJoints}
47
- {rawCCDSolver}
48
- {rawQueryPipeline}
49
- {rawPhysicsPipeline}
50
- {rawSerializationPipeline}
51
- {rawDebugRenderPipeline}
52
- {stage}
53
- >
54
- <slot />
6
+ {#await initRapier() then _}
7
+ <InnerWorld {...rest}>
8
+ {@render children?.()}
55
9
  </InnerWorld>
56
- {/if}
57
-
58
- {#if error}
59
- <slot name="fallback" />
60
- {/if}
10
+ {:catch error}
11
+ {@render fallback?.(error)}
12
+ {/await}
@@ -13,11 +13,13 @@ import type {
13
13
  RawRigidBodySet,
14
14
  RawSerializationPipeline
15
15
  } from '@dimforge/rapier3d-compat/raw'
16
- import { SvelteComponent } from 'svelte'
16
+ import { SvelteComponent, type Snippet } from 'svelte'
17
17
  import type { Vector3 } from 'three'
18
18
  import type { Key, Stage } from '@threlte/core'
19
19
 
20
20
  export type WorldProps = {
21
+ framerate?: number | 'varying'
22
+ autoStart?: boolean
21
23
  gravity?: Parameters<Vector3['set']>
22
24
  rawIntegrationParameters?: RawIntegrationParameters
23
25
  rawIslands?: RawIslandManager
@@ -32,7 +34,16 @@ export type WorldProps = {
32
34
  rawPhysicsPipeline?: RawPhysicsPipeline
33
35
  rawSerializationPipeline?: RawSerializationPipeline
34
36
  rawDebugRenderPipeline?: RawDebugRenderPipeline
35
- stage?: Key | Stage
37
+ simulationStageOptions?: {
38
+ before?: (Key | Stage) | (Key | Stage)[]
39
+ after?: (Key | Stage) | (Key | Stage)[]
40
+ }
41
+ synchronizationStageOptions?: {
42
+ before?: (Key | Stage) | (Key | Stage)[]
43
+ after?: (Key | Stage) | (Key | Stage)[]
44
+ }
45
+ children?: Snippet
46
+ fallback?: Snippet<[error: any]>
36
47
  }
37
48
 
38
49
  export default class World extends SvelteComponent<WorldProps> {}
@@ -1,2 +1,3 @@
1
1
  import { type Collider } from '@dimforge/rapier3d-compat';
2
- export declare const applyColliderActiveEvents: (collider: Collider, colliderEvents?: Record<string, (arg: unknown) => void>, rigidBodyEvents?: Record<string, (arg: unknown) => void>) => void;
2
+ import type { ColliderEvents, RigidBodyEvents } from '../types/types';
3
+ export declare const applyColliderActiveEvents: (collider: Collider, colliderEvents?: ColliderEvents, rigidBodyEvents?: RigidBodyEvents) => void;