@threlte/xr 1.0.7 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (71) hide show
  1. package/dist/components/ARButton.svelte.d.ts +11 -24
  2. package/dist/components/Controller.svelte +51 -52
  3. package/dist/components/Controller.svelte.d.ts +7 -5
  4. package/dist/components/Hand.svelte +35 -41
  5. package/dist/components/Hand.svelte.d.ts +6 -4
  6. package/dist/components/Headset.svelte +16 -7
  7. package/dist/components/Headset.svelte.d.ts +8 -18
  8. package/dist/components/VRButton.svelte.d.ts +5 -18
  9. package/dist/components/XR.svelte +50 -50
  10. package/dist/components/XR.svelte.d.ts +24 -22
  11. package/dist/components/XRButton.svelte +6 -6
  12. package/dist/components/XRButton.svelte.d.ts +26 -23
  13. package/dist/components/internal/Cursor.svelte +2 -1
  14. package/dist/components/internal/Cursor.svelte.d.ts +4 -2
  15. package/dist/components/internal/PointerCursor.svelte +32 -18
  16. package/dist/components/internal/PointerCursor.svelte.d.ts +5 -3
  17. package/dist/components/internal/ShortRay.svelte +6 -6
  18. package/dist/components/internal/ShortRay.svelte.d.ts +5 -3
  19. package/dist/components/internal/TeleportCursor.svelte +28 -17
  20. package/dist/components/internal/TeleportCursor.svelte.d.ts +5 -3
  21. package/dist/components/internal/TeleportRay.svelte +26 -20
  22. package/dist/components/internal/TeleportRay.svelte.d.ts +5 -3
  23. package/dist/hooks/currentReadable.svelte.d.ts +5 -0
  24. package/dist/hooks/currentReadable.svelte.js +11 -0
  25. package/dist/hooks/useController.svelte.d.ts +13 -0
  26. package/dist/hooks/useController.svelte.js +22 -0
  27. package/dist/hooks/useHand.svelte.d.ts +12 -0
  28. package/dist/hooks/{useHand.js → useHand.svelte.js} +8 -5
  29. package/dist/hooks/{useHandJoint.d.ts → useHandJoint.svelte.d.ts} +1 -1
  30. package/dist/hooks/useHandJoint.svelte.js +21 -0
  31. package/dist/hooks/useHeadset.js +1 -1
  32. package/dist/hooks/useHitTest.svelte.js +67 -0
  33. package/dist/hooks/useTeleport.js +1 -2
  34. package/dist/hooks/useXR.d.ts +6 -7
  35. package/dist/hooks/useXR.js +10 -12
  36. package/dist/index.d.ts +4 -4
  37. package/dist/index.js +4 -4
  38. package/dist/internal/raf.d.ts +1 -0
  39. package/dist/internal/raf.js +2 -0
  40. package/dist/internal/setupControllers.js +13 -14
  41. package/dist/internal/setupHands.js +8 -9
  42. package/dist/internal/{setupHeadset.js → setupHeadset.svelte.js} +6 -6
  43. package/dist/internal/setupRaf.svelte.js +17 -0
  44. package/dist/internal/state.svelte.d.ts +51 -0
  45. package/dist/internal/state.svelte.js +40 -0
  46. package/dist/internal/useHandTrackingState.js +10 -7
  47. package/dist/lib/getXRSessionOptions.d.ts +1 -1
  48. package/dist/lib/toggleXRSession.d.ts +3 -3
  49. package/dist/lib/toggleXRSession.js +3 -3
  50. package/dist/plugins/pointerControls/compute.js +2 -6
  51. package/dist/plugins/pointerControls/index.js +4 -10
  52. package/dist/plugins/pointerControls/{setup.js → setup.svelte.js} +21 -22
  53. package/dist/plugins/teleportControls/compute.js +2 -6
  54. package/dist/plugins/teleportControls/index.js +4 -10
  55. package/dist/plugins/teleportControls/{setup.js → setup.svelte.js} +9 -10
  56. package/package.json +8 -8
  57. package/dist/components/internal/ScenePortal.svelte +0 -23
  58. package/dist/components/internal/ScenePortal.svelte.d.ts +0 -20
  59. package/dist/hooks/useController.d.ts +0 -9
  60. package/dist/hooks/useController.js +0 -19
  61. package/dist/hooks/useHand.d.ts +0 -8
  62. package/dist/hooks/useHandJoint.js +0 -20
  63. package/dist/hooks/useHitTest.js +0 -79
  64. package/dist/internal/setupRaf.js +0 -16
  65. package/dist/internal/stores.d.ts +0 -43
  66. package/dist/internal/stores.js +0 -42
  67. /package/dist/hooks/{useHitTest.d.ts → useHitTest.svelte.d.ts} +0 -0
  68. /package/dist/internal/{setupHeadset.d.ts → setupHeadset.svelte.d.ts} +0 -0
  69. /package/dist/internal/{setupRaf.d.ts → setupRaf.svelte.d.ts} +0 -0
  70. /package/dist/plugins/pointerControls/{setup.d.ts → setup.svelte.d.ts} +0 -0
  71. /package/dist/plugins/teleportControls/{setup.d.ts → setup.svelte.d.ts} +0 -0
@@ -0,0 +1,21 @@
1
+ import { useTask, useThrelte } from '@threlte/core';
2
+ import { hands } from './useHand.svelte';
3
+ import { toCurrentReadable } from './currentReadable.svelte';
4
+ /**
5
+ * Provides a reference to a requested hand joint, once available.
6
+ */
7
+ export const useHandJoint = (handedness, joint) => {
8
+ const { invalidate } = useThrelte();
9
+ const xrhand = $derived(hands[handedness]);
10
+ let jointSpace = $state.raw();
11
+ const { stop } = useTask(() => {
12
+ const space = xrhand?.hand.joints[joint];
13
+ // The joint radius is a good indicator that the joint is ready
14
+ if (space?.jointRadius !== undefined) {
15
+ jointSpace = space;
16
+ invalidate();
17
+ stop();
18
+ }
19
+ }, { autoInvalidate: false });
20
+ return toCurrentReadable(() => jointSpace);
21
+ };
@@ -1,4 +1,4 @@
1
- import { headset } from '../internal/setupHeadset';
1
+ import { headset } from '../internal/setupHeadset.svelte';
2
2
  export const useHeadset = () => {
3
3
  return headset;
4
4
  };
@@ -0,0 +1,67 @@
1
+ import { Matrix4 } from 'three';
2
+ import { useThrelte, useTask } from '@threlte/core';
3
+ import { controllers } from './useController.svelte';
4
+ import { isPresenting, session } from '../internal/state.svelte';
5
+ /**
6
+ * Use this hook to perform a hit test per frame in an AR environment.
7
+ *
8
+ * ```ts
9
+ * useHitTest((hitMatrix, hit) => {
10
+ * mesh.matrix.copy(hitMatrix)
11
+ * }, {
12
+ * source: 'viewer' | 'leftInput' | 'rightInput' // Default 'viewer'
13
+ * })
14
+ * ```
15
+ */
16
+ export const useHitTest = (hitTestCallback, options = {}) => {
17
+ const source = options.source ?? 'viewer';
18
+ const { xr } = useThrelte().renderer;
19
+ const hitMatrix = new Matrix4();
20
+ let hitTestSource = $state.raw();
21
+ const getHitTestSource = async (space) => {
22
+ if (space === undefined) {
23
+ return;
24
+ }
25
+ hitTestSource = await session.current?.requestHitTestSource?.({ space });
26
+ };
27
+ if (source === 'viewer') {
28
+ $effect.pre(() => {
29
+ session.current?.requestReferenceSpace('viewer').then((space) => {
30
+ getHitTestSource(space);
31
+ });
32
+ });
33
+ }
34
+ else {
35
+ const controller = $derived(controllers[source === 'leftInput' ? 'left' : 'right']);
36
+ $effect.pre(() => {
37
+ getHitTestSource(controller?.inputSource.targetRaySpace);
38
+ });
39
+ }
40
+ const { start, stop } = useTask(() => {
41
+ const referenceSpace = xr.getReferenceSpace();
42
+ if (referenceSpace === null || hitTestSource === undefined) {
43
+ return hitTestCallback(hitMatrix, undefined);
44
+ }
45
+ const [hit] = xr.getFrame().getHitTestResults(hitTestSource);
46
+ const pose = hit?.getPose(referenceSpace);
47
+ if (pose === undefined) {
48
+ return hitTestCallback(hitMatrix, undefined);
49
+ }
50
+ hitMatrix.fromArray(pose.transform.matrix);
51
+ hitTestCallback(hitMatrix, hit);
52
+ }, { autoStart: false });
53
+ $effect.pre(() => {
54
+ if (!isPresenting.current) {
55
+ stop();
56
+ return;
57
+ }
58
+ if (hitTestSource === undefined) {
59
+ stop();
60
+ // Execute callback one last time to inform consumers of no hits.
61
+ hitTestCallback(hitMatrix, undefined);
62
+ }
63
+ else {
64
+ start();
65
+ }
66
+ });
67
+ };
@@ -19,12 +19,11 @@ const offset = { x: 0, y: 0, z: 0 };
19
19
  */
20
20
  export const useTeleport = () => {
21
21
  const { xr } = useThrelte().renderer;
22
- let space = xr.getReferenceSpace();
23
22
  /**
24
23
  * Teleports a player from the world origin to a position and optional orientation.
25
24
  */
26
25
  return (position, orientation = quaternion) => {
27
- space ??= xr.getReferenceSpace();
26
+ const space = xr.getReferenceSpace();
28
27
  if (space === null)
29
28
  return;
30
29
  if (Array.isArray(position)) {
@@ -1,12 +1,11 @@
1
- import type { CurrentWritable } from '@threlte/core';
1
+ import type { WebXRManager } from 'three';
2
+ import { type CurrentReadable } from './currentReadable.svelte';
2
3
  /**
3
4
  * Provides access to context related to `<XR />`.
4
5
  */
5
6
  export declare const useXR: () => {
6
- isPresenting: CurrentWritable<boolean>;
7
- isHandTracking: CurrentWritable<boolean>;
8
- session: CurrentWritable<XRSession | undefined>;
9
- xrFrame: {
10
- current: XRFrame;
11
- };
7
+ isPresenting: CurrentReadable<boolean>;
8
+ isHandTracking: CurrentReadable<boolean>;
9
+ session: CurrentReadable<XRSession | undefined>;
10
+ xr: CurrentReadable<WebXRManager | undefined>;
12
11
  };
@@ -1,15 +1,13 @@
1
- import { isPresenting, isHandTracking, session, xr } from '../internal/stores';
2
- const stores = {
3
- isPresenting,
4
- isHandTracking,
5
- session,
6
- xrFrame: {
7
- get current() {
8
- return xr.current.getFrame();
9
- }
10
- }
11
- };
1
+ import { isPresenting, isHandTracking, session, xr } from '../internal/state.svelte';
2
+ import { toCurrentReadable } from './currentReadable.svelte';
12
3
  /**
13
4
  * Provides access to context related to `<XR />`.
14
5
  */
15
- export const useXR = () => stores;
6
+ export const useXR = () => {
7
+ return {
8
+ isPresenting: toCurrentReadable(() => isPresenting.current),
9
+ isHandTracking: toCurrentReadable(() => isHandTracking.current),
10
+ session: toCurrentReadable(() => session.current),
11
+ xr: toCurrentReadable(() => xr.current)
12
+ };
13
+ };
package/dist/index.d.ts CHANGED
@@ -10,11 +10,11 @@ export { toggleXRSession } from './lib/toggleXRSession';
10
10
  export { handJoints } from './lib/handJoints';
11
11
  export { pointerControls } from './plugins/pointerControls';
12
12
  export { teleportControls } from './plugins/teleportControls';
13
- export { useController } from './hooks/useController';
14
- export { useHand } from './hooks/useHand';
15
- export { useHandJoint } from './hooks/useHandJoint';
13
+ export { useController } from './hooks/useController.svelte';
14
+ export { useHand } from './hooks/useHand.svelte';
15
+ export { useHandJoint } from './hooks/useHandJoint.svelte';
16
16
  export { useHeadset } from './hooks/useHeadset';
17
- export { useHitTest } from './hooks/useHitTest';
17
+ export { useHitTest } from './hooks/useHitTest.svelte';
18
18
  export { useTeleport } from './hooks/useTeleport';
19
19
  export { useXR } from './hooks/useXR';
20
20
  export type { XRSessionEventType, XRControllerEventType, XRHandEventType, XRSessionEvent, XRControllerEvent, XRController, XRHand, XRHandEvent } from './types';
package/dist/index.js CHANGED
@@ -14,10 +14,10 @@ export { handJoints } from './lib/handJoints';
14
14
  export { pointerControls } from './plugins/pointerControls';
15
15
  export { teleportControls } from './plugins/teleportControls';
16
16
  // Hooks
17
- export { useController } from './hooks/useController';
18
- export { useHand } from './hooks/useHand';
19
- export { useHandJoint } from './hooks/useHandJoint';
17
+ export { useController } from './hooks/useController.svelte';
18
+ export { useHand } from './hooks/useHand.svelte';
19
+ export { useHandJoint } from './hooks/useHandJoint.svelte';
20
20
  export { useHeadset } from './hooks/useHeadset';
21
- export { useHitTest } from './hooks/useHitTest';
21
+ export { useHitTest } from './hooks/useHitTest.svelte';
22
22
  export { useTeleport } from './hooks/useTeleport';
23
23
  export { useXR } from './hooks/useXR';
@@ -0,0 +1 @@
1
+ export { raf } from 'svelte/internal/client';
@@ -0,0 +1,2 @@
1
+ // eslint-disable-next-line svelte/no-svelte-internal
2
+ export { raf } from 'svelte/internal/client';
@@ -2,16 +2,15 @@ import { XRControllerModelFactory } from 'three/examples/jsm/webxr/XRControllerM
2
2
  import { useThrelte } from '@threlte/core';
3
3
  import { onMount } from 'svelte';
4
4
  import { useHandTrackingState } from './useHandTrackingState';
5
- import { gaze, left, right } from '../hooks/useController';
6
- import { controllerEvents } from './stores';
5
+ import { controllers } from '../hooks/useController.svelte';
6
+ import { controllerEvents } from './state.svelte';
7
7
  export const setupControllers = () => {
8
8
  const factory = new XRControllerModelFactory();
9
- const stores = { left, right, none: gaze };
10
9
  const { xr } = useThrelte().renderer;
11
10
  const hasHands = useHandTrackingState();
12
- const controllers = [xr.getController(0), xr.getController(1)];
11
+ const targetRaySpaces = [xr.getController(0), xr.getController(1)];
13
12
  const indexMap = new Map();
14
- controllers.forEach((targetRay, index) => {
13
+ targetRaySpaces.forEach((targetRay, index) => {
15
14
  indexMap.set(targetRay, {
16
15
  targetRay,
17
16
  grip: xr.getControllerGrip(index),
@@ -23,24 +22,24 @@ export const setupControllers = () => {
23
22
  if (hasHands())
24
23
  return;
25
24
  const { data } = event;
26
- controllerEvents[data.handedness]?.current?.[`on${event.type}`]?.(event);
25
+ controllerEvents[data.handedness]?.[`on${event.type}`]?.(event);
27
26
  };
28
27
  function handleConnected(event) {
29
28
  const { model, targetRay, grip } = indexMap.get(this);
30
29
  const { data: inputSource } = event;
31
- stores[event.data.handedness].set({
30
+ controllers[event.data.handedness] = {
32
31
  inputSource,
33
32
  targetRay,
34
33
  grip,
35
34
  model
36
- });
35
+ };
37
36
  dispatch(event);
38
37
  }
39
38
  const handleDisconnected = (event) => {
40
39
  dispatch(event);
41
- stores[event.data.handedness].set(undefined);
40
+ controllers[event.data.handedness] = undefined;
42
41
  };
43
- for (const targetRay of controllers) {
42
+ for (const targetRay of targetRaySpaces) {
44
43
  targetRay.addEventListener('connected', handleConnected);
45
44
  targetRay.addEventListener('disconnected', handleDisconnected);
46
45
  targetRay.addEventListener('select', dispatch);
@@ -51,7 +50,7 @@ export const setupControllers = () => {
51
50
  targetRay.addEventListener('squeezeend', dispatch);
52
51
  }
53
52
  return () => {
54
- for (const targetRay of controllers) {
53
+ for (const targetRay of targetRaySpaces) {
55
54
  targetRay.removeEventListener('connected', handleConnected);
56
55
  targetRay.removeEventListener('disconnected', handleDisconnected);
57
56
  targetRay.removeEventListener('select', dispatch);
@@ -61,9 +60,9 @@ export const setupControllers = () => {
61
60
  targetRay.removeEventListener('squeezestart', dispatch);
62
61
  targetRay.removeEventListener('squeezeend', dispatch);
63
62
  }
64
- stores.left.set(undefined);
65
- stores.right.set(undefined);
66
- stores.none.set(undefined);
63
+ controllers.left = undefined;
64
+ controllers.right = undefined;
65
+ controllers.none = undefined;
67
66
  };
68
67
  });
69
68
  };
@@ -1,12 +1,11 @@
1
1
  import { XRHandModelFactory } from 'three/examples/jsm/webxr/XRHandModelFactory.js';
2
2
  import { useThrelte } from '@threlte/core';
3
3
  import { onMount } from 'svelte';
4
- import { left, right } from '../hooks/useHand';
4
+ import { hands } from '../hooks/useHand.svelte';
5
5
  import { useHandTrackingState } from './useHandTrackingState';
6
- import { handEvents } from './stores';
6
+ import { handEvents } from './state.svelte';
7
7
  export const setupHands = () => {
8
8
  const factory = new XRHandModelFactory();
9
- const stores = { left, right };
10
9
  const { xr } = useThrelte().renderer;
11
10
  const hasHands = useHandTrackingState();
12
11
  const handSpaces = [xr.getHand(0), xr.getHand(1)];
@@ -24,23 +23,23 @@ export const setupHands = () => {
24
23
  return;
25
24
  const handEvent = event;
26
25
  const handedness = 'handedness' in handEvent ? handEvent.handedness : handEvent.data.handedness;
27
- handEvents[handedness]?.current?.[`on${event.type}`]?.(event);
26
+ handEvents[handedness]?.[`on${event.type}`]?.(event);
28
27
  };
29
28
  function handleConnected(event) {
30
29
  const { model, targetRay } = map.get(this);
31
30
  const { data } = event;
32
31
  const { handedness, hand: inputSource } = data;
33
- stores[handedness].set({
32
+ hands[handedness] = {
34
33
  hand: this,
35
34
  model,
36
35
  inputSource,
37
36
  targetRay
38
- });
37
+ };
39
38
  dispatch(event);
40
39
  }
41
40
  const handleDisconnected = (event) => {
42
41
  dispatch(event);
43
- stores[event.data.handedness].set(undefined);
42
+ hands[event.data.handedness] = undefined;
44
43
  };
45
44
  for (const handSpace of handSpaces) {
46
45
  handSpace.addEventListener('connected', handleConnected);
@@ -55,8 +54,8 @@ export const setupHands = () => {
55
54
  handSpace.removeEventListener('pinchstart', dispatch);
56
55
  handSpace.removeEventListener('pinchend', dispatch);
57
56
  }
58
- stores.left.set(undefined);
59
- stores.right.set(undefined);
57
+ hands.left = undefined;
58
+ hands.right = undefined;
60
59
  };
61
60
  });
62
61
  };
@@ -1,6 +1,6 @@
1
1
  import { Group } from 'three';
2
- import { useThrelte, useTask, watch } from '@threlte/core';
3
- import { useXR } from '../hooks/useXR';
2
+ import { useThrelte, useTask } from '@threlte/core';
3
+ import { isPresenting } from './state.svelte';
4
4
  export const headset = new Group();
5
5
  export const setupHeadset = () => {
6
6
  const { renderer, camera, scheduler, renderStage } = useThrelte();
@@ -16,8 +16,8 @@ export const setupHeadset = () => {
16
16
  if (pose === undefined || pose === null)
17
17
  return;
18
18
  const { position, orientation } = pose.transform;
19
- headset.position.set(position.x, position.y, position.z);
20
- headset.quaternion.set(orientation.x, orientation.y, orientation.z, orientation.w);
19
+ headset.position.copy(position);
20
+ headset.quaternion.copy(orientation);
21
21
  }, {
22
22
  autoStart: false,
23
23
  autoInvalidate: false,
@@ -31,8 +31,8 @@ export const setupHeadset = () => {
31
31
  autoInvalidate: false,
32
32
  stage
33
33
  });
34
- watch(useXR().isPresenting, ($isPresenting) => {
35
- if ($isPresenting) {
34
+ $effect.pre(() => {
35
+ if (isPresenting.current) {
36
36
  immersiveFrame.start();
37
37
  nonImmersiveFrame.stop();
38
38
  }
@@ -0,0 +1,17 @@
1
+ import { session } from './state.svelte';
2
+ import { raf } from './raf';
3
+ export const setupRaf = () => {
4
+ if (typeof window === 'undefined')
5
+ return;
6
+ $effect.pre(() => {
7
+ const currentSession = session.current;
8
+ if (currentSession === undefined) {
9
+ return;
10
+ }
11
+ const originalTick = raf.tick;
12
+ raf.tick = (fn) => currentSession.requestAnimationFrame(fn);
13
+ return () => {
14
+ raf.tick = originalTick;
15
+ };
16
+ });
17
+ };
@@ -0,0 +1,51 @@
1
+ import type { WebXRManager, Intersection } from 'three';
2
+ import type { XRControllerEvents, XRHandEvents } from '../types';
3
+ interface ControllerEvents {
4
+ left?: XRControllerEvents;
5
+ right?: XRControllerEvents;
6
+ }
7
+ interface HandEvents {
8
+ left?: XRHandEvents;
9
+ right?: XRHandEvents;
10
+ }
11
+ declare class Presenting {
12
+ current: boolean;
13
+ }
14
+ declare class IsHandTracking {
15
+ current: boolean;
16
+ }
17
+ declare class Session {
18
+ current: XRSession | undefined;
19
+ }
20
+ declare class ReferenceSpaceType {
21
+ current: XRReferenceSpaceType | undefined;
22
+ }
23
+ declare class XR {
24
+ current: WebXRManager | undefined;
25
+ }
26
+ declare class PointerState {
27
+ enabled: boolean;
28
+ hovering: boolean;
29
+ }
30
+ declare class IntersectionState {
31
+ left: Intersection<import("three").Object3D<import("three").Object3DEventMap>> | undefined;
32
+ right: Intersection<import("three").Object3D<import("three").Object3DEventMap>> | undefined;
33
+ }
34
+ export declare const isPresenting: Presenting;
35
+ export declare const isHandTracking: IsHandTracking;
36
+ export declare const session: Session;
37
+ export declare const referenceSpaceType: ReferenceSpaceType;
38
+ export declare const xr: XR;
39
+ export declare const controllerEvents: ControllerEvents;
40
+ export declare const handEvents: HandEvents;
41
+ export declare const teleportState: {
42
+ left: PointerState;
43
+ right: PointerState;
44
+ };
45
+ export declare const pointerState: {
46
+ left: PointerState;
47
+ right: PointerState;
48
+ };
49
+ export declare const teleportIntersection: IntersectionState;
50
+ export declare const pointerIntersection: IntersectionState;
51
+ export {};
@@ -0,0 +1,40 @@
1
+ class Presenting {
2
+ current = $state(false);
3
+ }
4
+ class IsHandTracking {
5
+ current = $state(false);
6
+ }
7
+ class Session {
8
+ current = $state.raw();
9
+ }
10
+ class ReferenceSpaceType {
11
+ current = $state.raw();
12
+ }
13
+ class XR {
14
+ current = $state.raw();
15
+ }
16
+ class PointerState {
17
+ enabled = $state(false);
18
+ hovering = $state(false);
19
+ }
20
+ class IntersectionState {
21
+ left = $state.raw();
22
+ right = $state.raw();
23
+ }
24
+ export const isPresenting = new Presenting();
25
+ export const isHandTracking = new IsHandTracking();
26
+ export const session = new Session();
27
+ export const referenceSpaceType = new ReferenceSpaceType();
28
+ export const xr = new XR();
29
+ export const controllerEvents = {};
30
+ export const handEvents = {};
31
+ export const teleportState = {
32
+ left: new PointerState(),
33
+ right: new PointerState()
34
+ };
35
+ export const pointerState = {
36
+ left: new PointerState(),
37
+ right: new PointerState()
38
+ };
39
+ export const teleportIntersection = new IntersectionState();
40
+ export const pointerIntersection = new IntersectionState();
@@ -4,14 +4,17 @@ import { useThrelte } from '@threlte/core';
4
4
  * connection or disconnection event. This is the way to do that.
5
5
  */
6
6
  export const useHandTrackingState = () => {
7
- const { xr } = useThrelte().renderer;
7
+ const { renderer } = useThrelte();
8
8
  return () => {
9
- let handTracking = false;
10
- xr.getSession()?.inputSources?.forEach((value) => {
11
- if (value.hand) {
12
- handTracking = true;
9
+ const sources = renderer.xr.getSession()?.inputSources;
10
+ if (sources === undefined) {
11
+ return false;
12
+ }
13
+ for (const source of sources) {
14
+ if (source.hand !== undefined) {
15
+ return true;
13
16
  }
14
- });
15
- return handTracking;
17
+ }
18
+ return false;
16
19
  };
17
20
  };
@@ -1 +1 @@
1
- export declare const getXRSessionOptions: (referenceSpaceType: XRReferenceSpaceType | undefined, sessionInit: XRSessionInit | undefined) => XRSessionInit | undefined;
1
+ export declare const getXRSessionOptions: (referenceSpaceType?: XRReferenceSpaceType, sessionInit?: XRSessionInit) => XRSessionInit | undefined;
@@ -6,8 +6,8 @@
6
6
  * @param force Whether this button should only enter / exit an `XRSession`. Default is to toggle both ways
7
7
  * @returns
8
8
  */
9
- export declare const toggleXRSession: (sessionMode: XRSessionMode, sessionInit?: (XRSessionInit & {
9
+ export declare const toggleXRSession: (sessionMode: XRSessionMode, sessionInit?: XRSessionInit & {
10
10
  domOverlay?: {
11
11
  root: HTMLElement;
12
- } | undefined;
13
- }) | undefined, force?: "enter" | "exit") => Promise<XRSession | undefined>;
12
+ };
13
+ }, force?: "enter" | "exit") => Promise<XRSession | undefined>;
@@ -1,4 +1,4 @@
1
- import { session, referenceSpaceType, xr } from '../internal/stores';
1
+ import { session, referenceSpaceType, xr } from '../internal/state.svelte';
2
2
  import { getXRSessionOptions } from './getXRSessionOptions';
3
3
  /**
4
4
  * Starts / ends an XR session.
@@ -18,7 +18,7 @@ export const toggleXRSession = async (sessionMode, sessionInit, force) => {
18
18
  // Exit a session if entered
19
19
  if (hasSession) {
20
20
  await currentSession.end();
21
- session.set(undefined);
21
+ session.current = undefined;
22
22
  return;
23
23
  }
24
24
  if (xr.current === undefined) {
@@ -28,6 +28,6 @@ export const toggleXRSession = async (sessionMode, sessionInit, force) => {
28
28
  const options = getXRSessionOptions(referenceSpaceType.current, sessionInit);
29
29
  const nextSession = await navigator.xr.requestSession(sessionMode, options);
30
30
  await xr.current.setSession(nextSession);
31
- session.set(nextSession);
31
+ session.current = nextSession;
32
32
  return nextSession;
33
33
  };
@@ -1,12 +1,8 @@
1
1
  import { Vector3 } from 'three';
2
- import { useController } from '../../hooks/useController';
3
- const controllers = {
4
- left: useController('left'),
5
- right: useController('right')
6
- };
2
+ import { controllers } from '../../hooks/useController.svelte';
7
3
  const forward = new Vector3();
8
4
  export const defaultComputeFunction = (context, handContext) => {
9
- const targetRay = controllers[handContext.hand].current?.targetRay;
5
+ const targetRay = controllers[handContext.hand]?.targetRay;
10
6
  if (targetRay === undefined)
11
7
  return;
12
8
  forward.set(0, 0, -1).applyQuaternion(targetRay.quaternion);
@@ -2,9 +2,9 @@ import { Raycaster, Vector3 } from 'three';
2
2
  import { currentWritable, watch } from '@threlte/core';
3
3
  import { defaultComputeFunction } from './compute';
4
4
  import { injectPointerControlsPlugin } from './plugin.svelte';
5
- import { setupPointerControls } from './setup';
5
+ import { setupPointerControls } from './setup.svelte';
6
6
  import { getControlsContext, getHandContext, setControlsContext, setHandContext, setInternalContext } from './context';
7
- import { pointerState } from '../../internal/stores';
7
+ import { pointerState } from '../../internal/state.svelte';
8
8
  let controlsCounter = 0;
9
9
  export const pointerControls = (handedness, options) => {
10
10
  if (getControlsContext() === undefined) {
@@ -36,16 +36,10 @@ export const pointerControls = (handedness, options) => {
36
36
  const handContext = getHandContext(handedness);
37
37
  watch(handContext.enabled, (enabled) => {
38
38
  controlsCounter += enabled ? 1 : -1;
39
- pointerState.update((value) => {
40
- value[handedness].enabled = controlsCounter > 0;
41
- return value;
42
- });
39
+ pointerState[handedness].enabled = controlsCounter > 0;
43
40
  });
44
41
  watch(handContext.pointerOverTarget, (hovering) => {
45
- pointerState.update((value) => {
46
- value[handedness].hovering = hovering;
47
- return value;
48
- });
42
+ pointerState[handedness].hovering = hovering;
49
43
  });
50
44
  return {
51
45
  enabled: handContext.enabled,