@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.
- package/dist/components/ARButton.svelte.d.ts +11 -24
- package/dist/components/Controller.svelte +31 -27
- package/dist/components/Controller.svelte.d.ts +7 -5
- package/dist/components/Hand.svelte +24 -28
- package/dist/components/Hand.svelte.d.ts +6 -4
- package/dist/components/Headset.svelte.d.ts +4 -2
- package/dist/components/VRButton.svelte.d.ts +5 -18
- package/dist/components/XR.svelte +55 -54
- package/dist/components/XR.svelte.d.ts +29 -27
- package/dist/components/XRButton.svelte +3 -3
- package/dist/components/XRButton.svelte.d.ts +26 -23
- package/dist/components/internal/Cursor.svelte.d.ts +4 -2
- package/dist/components/internal/PointerCursor.svelte +8 -7
- package/dist/components/internal/PointerCursor.svelte.d.ts +5 -3
- package/dist/components/internal/ShortRay.svelte +3 -3
- package/dist/components/internal/ShortRay.svelte.d.ts +5 -3
- package/dist/components/internal/TeleportCursor.svelte +8 -7
- package/dist/components/internal/TeleportCursor.svelte.d.ts +5 -3
- package/dist/components/internal/TeleportRay.svelte +5 -5
- package/dist/components/internal/TeleportRay.svelte.d.ts +5 -3
- package/dist/hooks/currentReadable.svelte.d.ts +5 -0
- package/dist/hooks/currentReadable.svelte.js +11 -0
- package/dist/hooks/useController.svelte.d.ts +13 -0
- package/dist/hooks/useController.svelte.js +22 -0
- package/dist/hooks/useHand.svelte.d.ts +12 -0
- package/dist/hooks/{useHand.js → useHand.svelte.js} +8 -5
- package/dist/hooks/{useHandJoint.d.ts → useHandJoint.svelte.d.ts} +1 -1
- package/dist/hooks/useHandJoint.svelte.js +21 -0
- package/dist/hooks/useHeadset.js +1 -1
- package/dist/hooks/useHitTest.svelte.js +67 -0
- package/dist/hooks/useTeleport.js +1 -2
- package/dist/hooks/useXR.d.ts +6 -7
- package/dist/hooks/useXR.js +10 -12
- package/dist/index.d.ts +5 -5
- package/dist/index.js +4 -4
- package/dist/internal/raf.d.ts +1 -0
- package/dist/internal/raf.js +2 -0
- package/dist/internal/setupControllers.js +13 -14
- package/dist/internal/setupHands.js +11 -9
- package/dist/internal/{setupHeadset.js → setupHeadset.svelte.js} +6 -6
- package/dist/internal/setupRaf.svelte.js +17 -0
- package/dist/internal/state.svelte.d.ts +51 -0
- package/dist/internal/state.svelte.js +40 -0
- package/dist/internal/useHandTrackingState.js +10 -7
- package/dist/lib/getXRSessionOptions.d.ts +1 -1
- package/dist/lib/toggleXRSession.d.ts +3 -3
- package/dist/lib/toggleXRSession.js +3 -3
- package/dist/plugins/pointerControls/compute.js +2 -6
- package/dist/plugins/pointerControls/index.js +4 -10
- package/dist/plugins/pointerControls/{setup.js → setup.svelte.js} +18 -19
- package/dist/plugins/teleportControls/compute.js +2 -6
- package/dist/plugins/teleportControls/index.js +4 -10
- package/dist/plugins/teleportControls/{setup.js → setup.svelte.js} +9 -10
- package/dist/types.d.ts +12 -18
- package/package.json +10 -10
- package/dist/hooks/useController.d.ts +0 -9
- package/dist/hooks/useController.js +0 -19
- package/dist/hooks/useHand.d.ts +0 -8
- package/dist/hooks/useHandJoint.js +0 -20
- package/dist/hooks/useHitTest.js +0 -79
- package/dist/internal/setupRaf.js +0 -16
- package/dist/internal/stores.d.ts +0 -43
- package/dist/internal/stores.js +0 -42
- /package/dist/hooks/{useHitTest.d.ts → useHitTest.svelte.d.ts} +0 -0
- /package/dist/internal/{setupHeadset.d.ts → setupHeadset.svelte.d.ts} +0 -0
- /package/dist/internal/{setupRaf.d.ts → setupRaf.svelte.d.ts} +0 -0
- /package/dist/plugins/pointerControls/{setup.d.ts → setup.svelte.d.ts} +0 -0
- /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
|
-
|
|
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?:
|
|
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:
|
|
21
|
+
state: SupportState;
|
|
39
22
|
}]>;
|
|
40
23
|
onclick?: (event: {
|
|
41
|
-
state:
|
|
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
|
-
|
|
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/
|
|
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
|
|
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
|
|
33
|
+
if (intersection === undefined) {
|
|
33
34
|
return
|
|
34
35
|
}
|
|
35
36
|
|
|
36
|
-
const { point, face, object } = intersection
|
|
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
|
|
54
|
-
ref.position.copy(intersection.
|
|
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
|
-
|
|
3
|
-
handedness:
|
|
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/
|
|
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(
|
|
13
|
+
const hovering = $derived(teleportState[handedness].hovering)
|
|
14
14
|
const intersection = $derived(teleportIntersection[handedness])
|
|
15
15
|
const visible = $derived(
|
|
16
|
-
|
|
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
|
-
|
|
3
|
-
handedness:
|
|
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/
|
|
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
|
|
33
|
+
if (intersection === undefined) {
|
|
33
34
|
return
|
|
34
35
|
}
|
|
35
36
|
|
|
36
|
-
const { point, face, object } = intersection
|
|
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 (
|
|
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(
|
|
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={
|
|
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
|
-
|
|
3
|
-
handedness:
|
|
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/
|
|
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
|
|
38
|
+
if (intersection === undefined) return
|
|
39
39
|
|
|
40
|
-
const rayEnd = intersection.
|
|
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 (
|
|
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={
|
|
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
|
-
|
|
4
|
-
handedness:
|
|
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,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 {
|
|
2
|
-
|
|
3
|
-
|
|
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("
|
|
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
|
+
};
|
package/dist/hooks/useHeadset.js
CHANGED
|
@@ -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
|
|
26
|
+
const space = xr.getReferenceSpace();
|
|
28
27
|
if (space === null)
|
|
29
28
|
return;
|
|
30
29
|
if (Array.isArray(position)) {
|
package/dist/hooks/useXR.d.ts
CHANGED
|
@@ -1,12 +1,11 @@
|
|
|
1
|
-
import type {
|
|
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:
|
|
7
|
-
isHandTracking:
|
|
8
|
-
session:
|
|
9
|
-
|
|
10
|
-
current: XRFrame;
|
|
11
|
-
};
|
|
7
|
+
isPresenting: CurrentReadable<boolean>;
|
|
8
|
+
isHandTracking: CurrentReadable<boolean>;
|
|
9
|
+
session: CurrentReadable<XRSession | undefined>;
|
|
10
|
+
xr: CurrentReadable<WebXRManager | undefined>;
|
|
12
11
|
};
|
package/dist/hooks/useXR.js
CHANGED
|
@@ -1,15 +1,13 @@
|
|
|
1
|
-
import { isPresenting, isHandTracking, session, xr } from '../internal/
|
|
2
|
-
|
|
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 = () =>
|
|
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,
|
|
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';
|