@threlte/xr 1.0.8 → 1.1.1

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 (68) hide show
  1. package/dist/components/ARButton.svelte.d.ts +11 -24
  2. package/dist/components/Controller.svelte +31 -27
  3. package/dist/components/Controller.svelte.d.ts +7 -5
  4. package/dist/components/Hand.svelte +24 -28
  5. package/dist/components/Hand.svelte.d.ts +6 -4
  6. package/dist/components/Headset.svelte.d.ts +4 -2
  7. package/dist/components/VRButton.svelte.d.ts +5 -18
  8. package/dist/components/XR.svelte +55 -54
  9. package/dist/components/XR.svelte.d.ts +29 -27
  10. package/dist/components/XRButton.svelte +3 -3
  11. package/dist/components/XRButton.svelte.d.ts +26 -23
  12. package/dist/components/internal/Cursor.svelte.d.ts +4 -2
  13. package/dist/components/internal/PointerCursor.svelte +8 -7
  14. package/dist/components/internal/PointerCursor.svelte.d.ts +5 -3
  15. package/dist/components/internal/ShortRay.svelte +3 -3
  16. package/dist/components/internal/ShortRay.svelte.d.ts +5 -3
  17. package/dist/components/internal/TeleportCursor.svelte +8 -7
  18. package/dist/components/internal/TeleportCursor.svelte.d.ts +5 -3
  19. package/dist/components/internal/TeleportRay.svelte +5 -5
  20. package/dist/components/internal/TeleportRay.svelte.d.ts +5 -3
  21. package/dist/hooks/currentReadable.svelte.d.ts +5 -0
  22. package/dist/hooks/currentReadable.svelte.js +11 -0
  23. package/dist/hooks/useController.svelte.d.ts +13 -0
  24. package/dist/hooks/useController.svelte.js +22 -0
  25. package/dist/hooks/useHand.svelte.d.ts +12 -0
  26. package/dist/hooks/{useHand.js → useHand.svelte.js} +8 -5
  27. package/dist/hooks/{useHandJoint.d.ts → useHandJoint.svelte.d.ts} +1 -1
  28. package/dist/hooks/useHandJoint.svelte.js +21 -0
  29. package/dist/hooks/useHeadset.js +1 -1
  30. package/dist/hooks/useHitTest.svelte.js +67 -0
  31. package/dist/hooks/useTeleport.js +1 -2
  32. package/dist/hooks/useXR.d.ts +6 -7
  33. package/dist/hooks/useXR.js +10 -12
  34. package/dist/index.d.ts +5 -5
  35. package/dist/index.js +4 -4
  36. package/dist/internal/raf.d.ts +1 -0
  37. package/dist/internal/raf.js +2 -0
  38. package/dist/internal/setupControllers.js +13 -14
  39. package/dist/internal/setupHands.js +11 -9
  40. package/dist/internal/{setupHeadset.js → setupHeadset.svelte.js} +6 -6
  41. package/dist/internal/setupRaf.svelte.js +17 -0
  42. package/dist/internal/state.svelte.d.ts +51 -0
  43. package/dist/internal/state.svelte.js +40 -0
  44. package/dist/internal/useHandTrackingState.js +10 -7
  45. package/dist/lib/getXRSessionOptions.d.ts +1 -1
  46. package/dist/lib/toggleXRSession.d.ts +3 -3
  47. package/dist/lib/toggleXRSession.js +3 -3
  48. package/dist/plugins/pointerControls/compute.js +2 -6
  49. package/dist/plugins/pointerControls/index.js +4 -10
  50. package/dist/plugins/pointerControls/{setup.js → setup.svelte.js} +18 -19
  51. package/dist/plugins/teleportControls/compute.js +2 -6
  52. package/dist/plugins/teleportControls/index.js +4 -10
  53. package/dist/plugins/teleportControls/{setup.js → setup.svelte.js} +9 -10
  54. package/dist/types.d.ts +12 -18
  55. package/package.json +10 -10
  56. package/dist/hooks/useController.d.ts +0 -9
  57. package/dist/hooks/useController.js +0 -19
  58. package/dist/hooks/useHand.d.ts +0 -8
  59. package/dist/hooks/useHandJoint.js +0 -20
  60. package/dist/hooks/useHitTest.js +0 -79
  61. package/dist/internal/setupRaf.js +0 -16
  62. package/dist/internal/stores.d.ts +0 -43
  63. package/dist/internal/stores.js +0 -42
  64. /package/dist/hooks/{useHitTest.d.ts → useHitTest.svelte.d.ts} +0 -0
  65. /package/dist/internal/{setupHeadset.d.ts → setupHeadset.svelte.d.ts} +0 -0
  66. /package/dist/internal/{setupRaf.d.ts → setupRaf.svelte.d.ts} +0 -0
  67. /package/dist/plugins/pointerControls/{setup.d.ts → setup.svelte.d.ts} +0 -0
  68. /package/dist/plugins/teleportControls/{setup.d.ts → setup.svelte.d.ts} +0 -0
@@ -1,24 +1,7 @@
1
1
  import type { HTMLButtonAttributes } from 'svelte/elements';
2
2
  import type { Snippet } from 'svelte';
3
- /**
4
- * `<XRButton />` is an HTML `<button />` that can be used to init and
5
- * display info about your WebXR session. This is aliased by `ARButton` and
6
- * `VRButton` with sensible session defaults.
7
- *
8
- * ```svelte
9
- * <XRButton
10
- * mode={'immersive-ar' | 'immersive-vr' | 'inline'}
11
- * sessionInit={{
12
- * optionalFeatures: ['local-floor', 'bounded-floor', 'hand-tracking', 'layers']
13
- * }}
14
- * force={'enter' | 'exit' | undefined}
15
- * styled={'true' | 'false'}
16
- * onerror={(event) => {}}
17
- * onclick={(event) => {}}
18
- * />
19
- * ```
20
- */
21
- declare const XrButton: import("svelte").Component<HTMLButtonAttributes & {
3
+ type SupportState = 'unsupported' | 'insecure' | 'blocked' | 'supported';
4
+ type Props = HTMLButtonAttributes & {
22
5
  /** The type of `XRSession` to create */
23
6
  mode: XRSessionMode;
24
7
  /**
@@ -31,16 +14,36 @@ declare const XrButton: import("svelte").Component<HTMLButtonAttributes & {
31
14
  } | undefined;
32
15
  };
33
16
  /** Whether this button should only enter / exit an `XRSession`. Default is to toggle both ways */
34
- force?: "enter" | "exit";
17
+ force?: 'enter' | 'exit';
35
18
  /** Whether to apply automatic styling to the button. Set false to apply custom styles. Default is true. */
36
19
  styled?: boolean;
37
20
  children?: Snippet<[{
38
- state: "unsupported" | "insecure" | "blocked" | "supported";
21
+ state: SupportState;
39
22
  }]>;
40
23
  onclick?: (event: {
41
- state: "unsupported" | "insecure" | "blocked" | "supported";
24
+ state: SupportState;
42
25
  nativeEvent: MouseEvent;
43
26
  }) => void;
44
27
  onerror?: (error: Error) => void;
45
- }, {}, "">;
28
+ };
29
+ /**
30
+ * `<XRButton />` is an HTML `<button />` that can be used to init and
31
+ * display info about your WebXR session. This is aliased by `ARButton` and
32
+ * `VRButton` with sensible session defaults.
33
+ *
34
+ * ```svelte
35
+ * <XRButton
36
+ * mode={'immersive-ar' | 'immersive-vr' | 'inline'}
37
+ * sessionInit={{
38
+ * optionalFeatures: ['local-floor', 'bounded-floor', 'hand-tracking', 'layers']
39
+ * }}
40
+ * force={'enter' | 'exit' | undefined}
41
+ * styled={'true' | 'false'}
42
+ * onerror={(event) => {}}
43
+ * onclick={(event) => {}}
44
+ * />
45
+ * ```
46
+ */
47
+ declare const XrButton: import("svelte").Component<Props, {}, "">;
48
+ type XrButton = ReturnType<typeof XrButton>;
46
49
  export default XrButton;
@@ -1,7 +1,9 @@
1
1
  import { type ColorRepresentation } from 'three';
2
- declare const Cursor: import("svelte").Component<{
2
+ interface Props {
3
3
  color?: ColorRepresentation;
4
4
  size?: number;
5
5
  thickness?: number;
6
- }, {}, "">;
6
+ }
7
+ declare const Cursor: import("svelte").Component<Props, {}, "">;
8
+ type Cursor = ReturnType<typeof Cursor>;
7
9
  export default Cursor;
@@ -11,7 +11,7 @@
11
11
 
12
12
  <script lang="ts">
13
13
  import { T, useTask, useThrelte } from '@threlte/core'
14
- import { pointerIntersection, pointerState } from '../../internal/stores'
14
+ import { pointerIntersection, pointerState } from '../../internal/state.svelte'
15
15
  import Cursor from './Cursor.svelte'
16
16
  import type { Snippet } from 'svelte'
17
17
 
@@ -23,17 +23,18 @@
23
23
  const { handedness, children }: Props = $props()
24
24
 
25
25
  const { scene } = useThrelte()
26
- const ref = new Group()
27
- const hovering = $derived($pointerState[handedness].hovering)
26
+ const hovering = $derived(pointerState[handedness].hovering)
28
27
  const intersection = $derived(pointerIntersection[handedness])
29
28
 
29
+ const ref = new Group()
30
+
30
31
  const { start, stop } = useTask(
31
32
  () => {
32
- if (intersection.current === undefined) {
33
+ if (intersection === undefined) {
33
34
  return
34
35
  }
35
36
 
36
- const { point, face, object } = intersection.current
37
+ const { point, face, object } = intersection
37
38
  ref.position.lerp(point, 0.4)
38
39
 
39
40
  if (face === null || face === undefined) {
@@ -50,8 +51,8 @@
50
51
  )
51
52
 
52
53
  $effect.pre(() => {
53
- if (hovering && intersection.current) {
54
- ref.position.copy(intersection.current?.point)
54
+ if (hovering && intersection) {
55
+ ref.position.copy(intersection.point)
55
56
  start()
56
57
  } else {
57
58
  stop()
@@ -1,6 +1,8 @@
1
1
  import type { Snippet } from 'svelte';
2
- declare const PointerCursor: import("svelte").Component<{
3
- handedness: "left" | "right";
2
+ interface Props {
3
+ handedness: 'left' | 'right';
4
4
  children?: Snippet;
5
- }, {}, "">;
5
+ }
6
+ declare const PointerCursor: import("svelte").Component<Props, {}, "">;
7
+ type PointerCursor = ReturnType<typeof PointerCursor>;
6
8
  export default PointerCursor;
@@ -1,6 +1,6 @@
1
1
  <script lang="ts">
2
2
  import { T } from '@threlte/core'
3
- import { pointerState, teleportState, teleportIntersection } from '../../internal/stores'
3
+ import { pointerState, teleportState, teleportIntersection } from '../../internal/state.svelte'
4
4
  import type { Snippet } from 'svelte'
5
5
 
6
6
  interface Props {
@@ -10,10 +10,10 @@
10
10
 
11
11
  const { handedness, children }: Props = $props()
12
12
 
13
- const hovering = $derived($teleportState[handedness].hovering)
13
+ const hovering = $derived(teleportState[handedness].hovering)
14
14
  const intersection = $derived(teleportIntersection[handedness])
15
15
  const visible = $derived(
16
- $pointerState[handedness].enabled || (hovering && $intersection === undefined)
16
+ pointerState[handedness].enabled || (hovering && intersection === undefined)
17
17
  )
18
18
 
19
19
  const vertexShader = `
@@ -1,6 +1,8 @@
1
1
  import type { Snippet } from 'svelte';
2
- declare const ShortRay: import("svelte").Component<{
3
- handedness: "left" | "right";
2
+ interface Props {
3
+ handedness: 'left' | 'right';
4
4
  children?: Snippet;
5
- }, {}, "">;
5
+ }
6
+ declare const ShortRay: import("svelte").Component<Props, {}, "">;
7
+ type ShortRay = ReturnType<typeof ShortRay>;
6
8
  export default ShortRay;
@@ -12,7 +12,7 @@
12
12
  <script lang="ts">
13
13
  import { Spring } from 'svelte/motion'
14
14
  import { T, useTask, useThrelte } from '@threlte/core'
15
- import { teleportIntersection } from '../../internal/stores'
15
+ import { teleportIntersection } from '../../internal/state.svelte'
16
16
  import Cursor from './Cursor.svelte'
17
17
  import type { Snippet } from 'svelte'
18
18
 
@@ -24,16 +24,17 @@
24
24
  const { handedness, children }: Props = $props()
25
25
 
26
26
  const { scene } = useThrelte()
27
- const ref = new Group()
28
27
  const intersection = $derived(teleportIntersection[handedness])
29
28
 
29
+ const ref = new Group()
30
+
30
31
  const { start, stop } = useTask(
31
32
  () => {
32
- if (intersection.current === undefined) {
33
+ if (intersection === undefined) {
33
34
  return
34
35
  }
35
36
 
36
- const { point, face, object } = intersection.current
37
+ const { point, face, object } = intersection
37
38
  ref.position.lerp(point, 0.4)
38
39
 
39
40
  if (face) {
@@ -50,12 +51,12 @@
50
51
  const size = new Spring(0.1, { stiffness: 0.2 })
51
52
 
52
53
  $effect.pre(() => {
53
- if ($intersection === undefined) {
54
+ if (intersection === undefined) {
54
55
  size.set(0.1)
55
56
  stop()
56
57
  } else {
57
58
  size.set(1)
58
- ref.position.copy($intersection.point)
59
+ ref.position.copy(intersection.point)
59
60
  start()
60
61
  }
61
62
  })
@@ -64,7 +65,7 @@
64
65
  <T
65
66
  is={ref}
66
67
  attach={scene}
67
- visible={$intersection !== undefined}
68
+ visible={intersection !== undefined}
68
69
  >
69
70
  {#if children}
70
71
  {@render children()}
@@ -1,6 +1,8 @@
1
1
  import type { Snippet } from 'svelte';
2
- declare const TeleportCursor: import("svelte").Component<{
3
- handedness: "left" | "right";
2
+ interface Props {
3
+ handedness: 'left' | 'right';
4
4
  children?: Snippet;
5
- }, {}, "">;
5
+ }
6
+ declare const TeleportCursor: import("svelte").Component<Props, {}, "">;
7
+ type TeleportCursor = ReturnType<typeof TeleportCursor>;
6
8
  export default TeleportCursor;
@@ -18,7 +18,7 @@
18
18
  import { LineGeometry } from 'three/examples/jsm/lines/LineGeometry.js'
19
19
  import { LineMaterial } from 'three/examples/jsm/lines/LineMaterial.js'
20
20
  import { T, useTask, useThrelte } from '@threlte/core'
21
- import { teleportIntersection } from '../../internal/stores'
21
+ import { teleportIntersection } from '../../internal/state.svelte'
22
22
 
23
23
  interface Props {
24
24
  handedness: 'left' | 'right'
@@ -35,9 +35,9 @@
35
35
  const intersection = $derived(teleportIntersection[handedness])
36
36
 
37
37
  const setCurvePoints = (alpha = 0.3) => {
38
- if (intersection.current === undefined) return
38
+ if (intersection === undefined) return
39
39
 
40
- const rayEnd = intersection.current.point
40
+ const rayEnd = intersection.point
41
41
  targetRay.getWorldPosition(rayStart)
42
42
 
43
43
  rayMidpoint.x = (rayStart.x + rayEnd.x) / 2
@@ -74,7 +74,7 @@
74
74
  )
75
75
 
76
76
  $effect.pre(() => {
77
- if ($intersection === undefined) {
77
+ if (intersection === undefined) {
78
78
  stop()
79
79
  } else {
80
80
  setCurvePoints(1)
@@ -89,7 +89,7 @@
89
89
  <T
90
90
  is={Line2}
91
91
  attach={scene}
92
- visible={$intersection !== undefined}
92
+ visible={intersection !== undefined}
93
93
  position.z={-0.01}
94
94
  >
95
95
  <T is={lineGeometry} />
@@ -1,8 +1,10 @@
1
1
  import { type XRTargetRaySpace } from 'three';
2
2
  import type { Snippet } from 'svelte';
3
- declare const TeleportRay: import("svelte").Component<{
4
- handedness: "left" | "right";
3
+ interface Props {
4
+ handedness: 'left' | 'right';
5
5
  targetRay: XRTargetRaySpace;
6
6
  children?: Snippet;
7
- }, {}, "">;
7
+ }
8
+ declare const TeleportRay: import("svelte").Component<Props, {}, "">;
9
+ type TeleportRay = ReturnType<typeof TeleportRay>;
8
10
  export default TeleportRay;
@@ -0,0 +1,5 @@
1
+ import { type Readable } from 'svelte/store';
2
+ export type CurrentReadable<T> = Readable<T> & {
3
+ current: T;
4
+ };
5
+ export declare const toCurrentReadable: <T>(getter: () => T) => CurrentReadable<T>;
@@ -0,0 +1,11 @@
1
+ import { toStore } from 'svelte/store';
2
+ export const toCurrentReadable = (getter) => {
3
+ const store = toStore(getter);
4
+ store.current = getter();
5
+ $effect.pre(() => {
6
+ return store.subscribe((value) => {
7
+ store.current = value;
8
+ });
9
+ });
10
+ return store;
11
+ };
@@ -0,0 +1,13 @@
1
+ import type { XRController } from '../types';
2
+ import { type CurrentReadable } from './currentReadable.svelte';
3
+ declare class Controllers {
4
+ left: XRController | undefined;
5
+ right: XRController | undefined;
6
+ none: XRController | undefined;
7
+ }
8
+ export declare const controllers: Controllers;
9
+ /**
10
+ * Provides a reference to a current XRController, filtered by handedness.
11
+ */
12
+ export declare const useController: (handedness: XRHandedness) => CurrentReadable<XRController | undefined>;
13
+ export {};
@@ -0,0 +1,22 @@
1
+ import { toCurrentReadable } from './currentReadable.svelte';
2
+ class Controllers {
3
+ left = $state.raw();
4
+ right = $state.raw();
5
+ none = $state.raw();
6
+ }
7
+ export const controllers = new Controllers();
8
+ /**
9
+ * Provides a reference to a current XRController, filtered by handedness.
10
+ */
11
+ export const useController = (handedness) => {
12
+ switch (handedness) {
13
+ case 'left':
14
+ return toCurrentReadable(() => controllers.left);
15
+ case 'right':
16
+ return toCurrentReadable(() => controllers.right);
17
+ case 'none':
18
+ return toCurrentReadable(() => controllers.none);
19
+ default:
20
+ throw new Error('useController handedness must be left, right, or none.');
21
+ }
22
+ };
@@ -0,0 +1,12 @@
1
+ import type { XRHandObject } from '../types';
2
+ import { type CurrentReadable } from './currentReadable.svelte';
3
+ declare class Hands {
4
+ left: XRHandObject | undefined;
5
+ right: XRHandObject | undefined;
6
+ }
7
+ export declare const hands: Hands;
8
+ /**
9
+ * Provides a reference to a current XRHand, filtered by handedness.
10
+ */
11
+ export declare const useHand: (handedness: "left" | "right") => CurrentReadable<undefined | XRHandObject>;
12
+ export {};
@@ -1,15 +1,18 @@
1
- import { currentWritable } from '@threlte/core';
2
- export const left = currentWritable(undefined);
3
- export const right = currentWritable(undefined);
1
+ import { toCurrentReadable } from './currentReadable.svelte';
2
+ class Hands {
3
+ left = $state.raw();
4
+ right = $state.raw();
5
+ }
6
+ export const hands = new Hands();
4
7
  /**
5
8
  * Provides a reference to a current XRHand, filtered by handedness.
6
9
  */
7
10
  export const useHand = (handedness) => {
8
11
  switch (handedness) {
9
12
  case 'left':
10
- return left;
13
+ return toCurrentReadable(() => hands.left);
11
14
  case 'right':
12
- return right;
15
+ return toCurrentReadable(() => hands.right);
13
16
  default:
14
17
  throw new Error('useHand handedness must be left or right.');
15
18
  }
@@ -3,4 +3,4 @@ import type { HandJoints } from '../lib/handJoints';
3
3
  /**
4
4
  * Provides a reference to a requested hand joint, once available.
5
5
  */
6
- export declare const useHandJoint: (handedness: "left" | "right", joint: HandJoints) => import("@threlte/core").CurrentWritable<XRJointSpace | undefined>;
6
+ export declare const useHandJoint: (handedness: "left" | "right", joint: HandJoints) => import("./currentReadable.svelte").CurrentReadable<XRJointSpace | undefined>;
@@ -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
- export type { XRSessionEventType, XRControllerEventType, XRHandEventType, XRSessionEvent, XRControllerEvent, XRController, XRHand, XRHandEvent } from './types';
20
+ export type { XRSessionEventType, XRControllerEventType, XRHandEventType, XRControllerEvent, XRController, XRHandObject, 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';