@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.
- package/dist/components/ARButton.svelte.d.ts +11 -24
- package/dist/components/Controller.svelte +51 -52
- package/dist/components/Controller.svelte.d.ts +7 -5
- package/dist/components/Hand.svelte +35 -41
- package/dist/components/Hand.svelte.d.ts +6 -4
- package/dist/components/Headset.svelte +16 -7
- package/dist/components/Headset.svelte.d.ts +8 -18
- package/dist/components/VRButton.svelte.d.ts +5 -18
- package/dist/components/XR.svelte +50 -50
- package/dist/components/XR.svelte.d.ts +24 -22
- package/dist/components/XRButton.svelte +6 -6
- package/dist/components/XRButton.svelte.d.ts +26 -23
- package/dist/components/internal/Cursor.svelte +2 -1
- package/dist/components/internal/Cursor.svelte.d.ts +4 -2
- package/dist/components/internal/PointerCursor.svelte +32 -18
- package/dist/components/internal/PointerCursor.svelte.d.ts +5 -3
- package/dist/components/internal/ShortRay.svelte +6 -6
- package/dist/components/internal/ShortRay.svelte.d.ts +5 -3
- package/dist/components/internal/TeleportCursor.svelte +28 -17
- package/dist/components/internal/TeleportCursor.svelte.d.ts +5 -3
- package/dist/components/internal/TeleportRay.svelte +26 -20
- 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 +4 -4
- 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 +8 -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} +21 -22
- 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/package.json +8 -8
- package/dist/components/internal/ScenePortal.svelte +0 -23
- package/dist/components/internal/ScenePortal.svelte.d.ts +0 -20
- 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,3 +1,12 @@
|
|
|
1
|
+
import type { ComponentProps } from 'svelte';
|
|
2
|
+
import XRButton from './XRButton.svelte';
|
|
3
|
+
type Props = Omit<ComponentProps<typeof XRButton>, 'mode' | 'sessionInit'> & {
|
|
4
|
+
sessionInit?: XRSessionInit & {
|
|
5
|
+
domOverlay?: {
|
|
6
|
+
root: HTMLElement;
|
|
7
|
+
} | undefined;
|
|
8
|
+
};
|
|
9
|
+
};
|
|
1
10
|
/**
|
|
2
11
|
* `<ARButton />` is an HTML `<button />` that can be used to init and display info about your immersive AR session.
|
|
3
12
|
*
|
|
@@ -8,28 +17,6 @@
|
|
|
8
17
|
* />
|
|
9
18
|
* ```
|
|
10
19
|
*/
|
|
11
|
-
declare const ArButton: import("svelte").Component<
|
|
12
|
-
|
|
13
|
-
sessionInit?: XRSessionInit & {
|
|
14
|
-
domOverlay?: {
|
|
15
|
-
root: HTMLElement;
|
|
16
|
-
} | undefined;
|
|
17
|
-
};
|
|
18
|
-
force?: "enter" | "exit";
|
|
19
|
-
styled?: boolean;
|
|
20
|
-
children?: import("svelte").Snippet<[{
|
|
21
|
-
state: "unsupported" | "insecure" | "blocked" | "supported";
|
|
22
|
-
}]>;
|
|
23
|
-
onclick?: (event: {
|
|
24
|
-
state: "unsupported" | "insecure" | "blocked" | "supported";
|
|
25
|
-
nativeEvent: MouseEvent;
|
|
26
|
-
}) => void;
|
|
27
|
-
onerror?: (error: Error) => void;
|
|
28
|
-
}, "mode" | "sessionInit"> & {
|
|
29
|
-
sessionInit?: XRSessionInit & {
|
|
30
|
-
domOverlay?: {
|
|
31
|
-
root: HTMLElement;
|
|
32
|
-
} | undefined;
|
|
33
|
-
};
|
|
34
|
-
}, {}, "">;
|
|
20
|
+
declare const ArButton: import("svelte").Component<Props, {}, "">;
|
|
21
|
+
type ArButton = ReturnType<typeof ArButton>;
|
|
35
22
|
export default ArButton;
|
|
@@ -1,29 +1,22 @@
|
|
|
1
1
|
<!--
|
|
2
2
|
@component `<Controller />` represents a THREE.XRTargetRaySpace, a THREE.XRGripSpace, and a controller model.
|
|
3
3
|
-->
|
|
4
|
-
<script
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
4
|
+
<script lang="ts">
|
|
5
|
+
import { T, useThrelte } from '@threlte/core'
|
|
6
|
+
import { controllers } from '../hooks/useController.svelte'
|
|
7
|
+
import {
|
|
8
|
+
isHandTracking,
|
|
9
|
+
pointerState,
|
|
10
|
+
teleportState,
|
|
11
|
+
controllerEvents
|
|
12
|
+
} from '../internal/state.svelte'
|
|
12
13
|
import type { XRControllerEvents } from '../types'
|
|
13
14
|
import PointerCursor from './internal/PointerCursor.svelte'
|
|
14
15
|
import ShortRay from './internal/ShortRay.svelte'
|
|
15
|
-
import ScenePortal from './internal/ScenePortal.svelte'
|
|
16
16
|
import TeleportCursor from './internal/TeleportCursor.svelte'
|
|
17
17
|
import TeleportRay from './internal/TeleportRay.svelte'
|
|
18
18
|
import type { Snippet } from 'svelte'
|
|
19
19
|
|
|
20
|
-
const stores = {
|
|
21
|
-
left: leftStore,
|
|
22
|
-
right: rightStore
|
|
23
|
-
} as const
|
|
24
|
-
</script>
|
|
25
|
-
|
|
26
|
-
<script lang="ts">
|
|
27
20
|
type Props = {
|
|
28
21
|
children?: Snippet
|
|
29
22
|
grip?: Snippet
|
|
@@ -77,11 +70,12 @@
|
|
|
77
70
|
teleportCursor: teleportCursorSnippet
|
|
78
71
|
}: Props = $props()
|
|
79
72
|
|
|
80
|
-
const
|
|
81
|
-
|
|
73
|
+
const { scene } = useThrelte()
|
|
74
|
+
|
|
75
|
+
const handedness = $derived<'left' | 'right'>(left ? 'left' : right ? 'right' : hand ?? 'left')
|
|
82
76
|
|
|
83
|
-
$effect.pre(() =>
|
|
84
|
-
controllerEvents[
|
|
77
|
+
$effect.pre(() => {
|
|
78
|
+
controllerEvents[handedness] = {
|
|
85
79
|
onconnected,
|
|
86
80
|
ondisconnected,
|
|
87
81
|
onselect,
|
|
@@ -90,20 +84,27 @@
|
|
|
90
84
|
onsqueeze,
|
|
91
85
|
onsqueezeend,
|
|
92
86
|
onsqueezestart
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
return () => {
|
|
90
|
+
controllerEvents[handedness] = undefined
|
|
91
|
+
}
|
|
92
|
+
})
|
|
93
|
+
|
|
94
|
+
const xrController = $derived(controllers[handedness])
|
|
95
|
+
const grip = $derived(xrController?.grip)
|
|
96
|
+
const targetRay = $derived(xrController?.targetRay)
|
|
97
|
+
const model = $derived(xrController?.model)
|
|
98
|
+
const hasPointerControls = $derived(pointerState[handedness].enabled)
|
|
99
|
+
const hasTeleportControls = $derived(teleportState[handedness].enabled)
|
|
102
100
|
</script>
|
|
103
101
|
|
|
104
|
-
{#if
|
|
102
|
+
{#if !isHandTracking.current}
|
|
105
103
|
{#if grip}
|
|
106
|
-
<T
|
|
104
|
+
<T
|
|
105
|
+
is={grip}
|
|
106
|
+
attach={scene}
|
|
107
|
+
>
|
|
107
108
|
{#if children}
|
|
108
109
|
{@render children?.()}
|
|
109
110
|
{:else}
|
|
@@ -120,7 +121,7 @@
|
|
|
120
121
|
|
|
121
122
|
{#if hasPointerControls || hasTeleportControls}
|
|
122
123
|
<ShortRay
|
|
123
|
-
|
|
124
|
+
{handedness}
|
|
124
125
|
children={pointerRaySnippet}
|
|
125
126
|
/>
|
|
126
127
|
{/if}
|
|
@@ -128,24 +129,22 @@
|
|
|
128
129
|
{/if}
|
|
129
130
|
{/if}
|
|
130
131
|
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
{/if}
|
|
132
|
+
{#if hasPointerControls}
|
|
133
|
+
<PointerCursor
|
|
134
|
+
{handedness}
|
|
135
|
+
children={pointerCursorSnippet}
|
|
136
|
+
/>
|
|
137
|
+
{/if}
|
|
138
138
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
</ScenePortal>
|
|
139
|
+
{#if hasTeleportControls && targetRay !== undefined}
|
|
140
|
+
<TeleportRay
|
|
141
|
+
{targetRay}
|
|
142
|
+
{handedness}
|
|
143
|
+
children={teleportRaySnippet}
|
|
144
|
+
/>
|
|
145
|
+
|
|
146
|
+
<TeleportCursor
|
|
147
|
+
{handedness}
|
|
148
|
+
children={teleportCursorSnippet}
|
|
149
|
+
/>
|
|
150
|
+
{/if}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import type { XRControllerEvents } from '../types';
|
|
2
2
|
import type { Snippet } from 'svelte';
|
|
3
|
-
|
|
4
|
-
declare const Controller: import("svelte").Component<{
|
|
3
|
+
type Props = {
|
|
5
4
|
children?: Snippet;
|
|
6
5
|
grip?: Snippet;
|
|
7
6
|
targetRay?: Snippet;
|
|
@@ -9,7 +8,7 @@ declare const Controller: import("svelte").Component<{
|
|
|
9
8
|
pointerCursor?: Snippet;
|
|
10
9
|
teleportRay?: Snippet;
|
|
11
10
|
teleportCursor?: Snippet;
|
|
12
|
-
} &
|
|
11
|
+
} & XRControllerEvents & ({
|
|
13
12
|
/** Whether the controller should be matched with the left hand. */
|
|
14
13
|
left: true;
|
|
15
14
|
right?: undefined;
|
|
@@ -21,8 +20,11 @@ declare const Controller: import("svelte").Component<{
|
|
|
21
20
|
hand?: undefined;
|
|
22
21
|
} | {
|
|
23
22
|
/** Whether the controller should be matched with the left or right hand. */
|
|
24
|
-
hand:
|
|
23
|
+
hand: 'left' | 'right';
|
|
25
24
|
left?: undefined;
|
|
26
25
|
right?: undefined;
|
|
27
|
-
})
|
|
26
|
+
});
|
|
27
|
+
/** `<Controller />` represents a THREE.XRTargetRaySpace, a THREE.XRGripSpace, and a controller model. */
|
|
28
|
+
declare const Controller: import("svelte").Component<Props, {}, "">;
|
|
29
|
+
type Controller = ReturnType<typeof Controller>;
|
|
28
30
|
export default Controller;
|
|
@@ -1,23 +1,11 @@
|
|
|
1
|
-
<script
|
|
2
|
-
lang="ts"
|
|
3
|
-
module
|
|
4
|
-
>
|
|
1
|
+
<script lang="ts">
|
|
5
2
|
import { Group } from 'three'
|
|
6
3
|
import { T, useThrelte, useTask } from '@threlte/core'
|
|
7
4
|
import type { XRHandEvents } from '../types'
|
|
8
|
-
import { isHandTracking, handEvents } from '../internal/
|
|
9
|
-
import {
|
|
10
|
-
import ScenePortal from './internal/ScenePortal.svelte'
|
|
11
|
-
import { writable } from 'svelte/store'
|
|
5
|
+
import { isHandTracking, handEvents } from '../internal/state.svelte'
|
|
6
|
+
import { hands } from '../hooks/useHand.svelte'
|
|
12
7
|
import type { Snippet } from 'svelte'
|
|
13
8
|
|
|
14
|
-
const stores = {
|
|
15
|
-
left: leftStore,
|
|
16
|
-
right: rightStore
|
|
17
|
-
} as const
|
|
18
|
-
</script>
|
|
19
|
-
|
|
20
|
-
<script lang="ts">
|
|
21
9
|
type Props = {
|
|
22
10
|
children?: Snippet
|
|
23
11
|
targetRay?: Snippet
|
|
@@ -44,7 +32,7 @@
|
|
|
44
32
|
}
|
|
45
33
|
)
|
|
46
34
|
|
|
47
|
-
|
|
35
|
+
const {
|
|
48
36
|
left,
|
|
49
37
|
right,
|
|
50
38
|
hand,
|
|
@@ -57,23 +45,24 @@
|
|
|
57
45
|
wrist
|
|
58
46
|
}: Props = $props()
|
|
59
47
|
|
|
60
|
-
const { renderer, scheduler, renderStage } = useThrelte()
|
|
61
|
-
const { xr } = renderer
|
|
62
|
-
const space = xr.getReferenceSpace()
|
|
48
|
+
const { scene, renderer, scheduler, renderStage } = useThrelte()
|
|
63
49
|
|
|
64
|
-
const handedness =
|
|
65
|
-
$effect.pre(() => handedness.set(left ? 'left' : right ? 'right' : (hand as 'left' | 'right')))
|
|
50
|
+
const handedness = $derived<'left' | 'right'>(left ? 'left' : right ? 'right' : hand ?? 'left')
|
|
66
51
|
|
|
67
|
-
$effect.pre(() =>
|
|
68
|
-
handEvents[
|
|
52
|
+
$effect.pre(() => {
|
|
53
|
+
handEvents[handedness] = {
|
|
69
54
|
onconnected,
|
|
70
55
|
ondisconnected,
|
|
71
56
|
onpinchend,
|
|
72
57
|
onpinchstart
|
|
73
|
-
}
|
|
74
|
-
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
return () => {
|
|
61
|
+
handEvents[handedness] = undefined
|
|
62
|
+
}
|
|
63
|
+
})
|
|
75
64
|
|
|
76
|
-
|
|
65
|
+
const group = new Group()
|
|
77
66
|
|
|
78
67
|
/**
|
|
79
68
|
* Currently children of a hand XRSpace or model will not
|
|
@@ -85,7 +74,8 @@
|
|
|
85
74
|
*/
|
|
86
75
|
const { start, stop } = useTask(
|
|
87
76
|
() => {
|
|
88
|
-
const frame = xr.getFrame()
|
|
77
|
+
const frame = renderer.xr.getFrame()
|
|
78
|
+
const space = renderer.xr.getReferenceSpace()
|
|
89
79
|
const joint = inputSource?.get('wrist')
|
|
90
80
|
|
|
91
81
|
if (joint === undefined || space === null) return
|
|
@@ -106,37 +96,41 @@
|
|
|
106
96
|
)
|
|
107
97
|
|
|
108
98
|
$effect.pre(() => {
|
|
109
|
-
if (
|
|
99
|
+
if (isHandTracking.current && (wrist !== undefined || children !== undefined) && inputSource) {
|
|
110
100
|
start()
|
|
111
101
|
} else {
|
|
112
102
|
stop()
|
|
113
103
|
}
|
|
114
104
|
})
|
|
115
105
|
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
106
|
+
const xrHand = $derived(hands[handedness])
|
|
107
|
+
const inputSource = $derived(xrHand?.inputSource)
|
|
108
|
+
const model = $derived(xrHand?.model)
|
|
119
109
|
</script>
|
|
120
110
|
|
|
121
|
-
{#if
|
|
122
|
-
<T
|
|
111
|
+
{#if xrHand?.hand && isHandTracking.current}
|
|
112
|
+
<T
|
|
113
|
+
is={xrHand.hand}
|
|
114
|
+
attach={scene}
|
|
115
|
+
>
|
|
123
116
|
{#if children === undefined}
|
|
124
117
|
<T is={model} />
|
|
125
118
|
{/if}
|
|
126
119
|
</T>
|
|
127
120
|
|
|
128
121
|
{#if targetRay !== undefined}
|
|
129
|
-
<T is={
|
|
122
|
+
<T is={xrHand.targetRay}>
|
|
130
123
|
{@render targetRay()}
|
|
131
124
|
</T>
|
|
132
125
|
{/if}
|
|
133
126
|
{/if}
|
|
134
127
|
|
|
135
|
-
{#if
|
|
136
|
-
<
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
128
|
+
{#if isHandTracking.current}
|
|
129
|
+
<T
|
|
130
|
+
is={group}
|
|
131
|
+
attach={scene}
|
|
132
|
+
>
|
|
133
|
+
{@render wrist?.()}
|
|
134
|
+
{@render children?.()}
|
|
135
|
+
</T>
|
|
142
136
|
{/if}
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import type { XRHandEvents } from '../types';
|
|
2
2
|
import type { Snippet } from 'svelte';
|
|
3
|
-
|
|
3
|
+
type Props = {
|
|
4
4
|
children?: Snippet;
|
|
5
5
|
targetRay?: Snippet;
|
|
6
6
|
wrist?: Snippet;
|
|
7
|
-
} &
|
|
7
|
+
} & XRHandEvents & ({
|
|
8
8
|
/** Whether the XRHand should be matched with the left hand. */
|
|
9
9
|
left: true;
|
|
10
10
|
right?: undefined;
|
|
@@ -16,8 +16,10 @@ declare const Hand: import("svelte").Component<{
|
|
|
16
16
|
hand?: undefined;
|
|
17
17
|
} | {
|
|
18
18
|
/** Whether the XRHand should be matched with the left or right hand. */
|
|
19
|
-
hand:
|
|
19
|
+
hand: 'left' | 'right';
|
|
20
20
|
left?: undefined;
|
|
21
21
|
right?: undefined;
|
|
22
|
-
})
|
|
22
|
+
});
|
|
23
|
+
declare const Hand: import("svelte").Component<Props, {}, "">;
|
|
24
|
+
type Hand = ReturnType<typeof Hand>;
|
|
23
25
|
export default Hand;
|
|
@@ -1,13 +1,22 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import {
|
|
2
|
+
import type { Snippet } from 'svelte'
|
|
3
|
+
import type { Group } from 'three'
|
|
4
|
+
import { T, useThrelte } from '@threlte/core'
|
|
3
5
|
import { useHeadset } from '../hooks/useHeadset'
|
|
4
|
-
import ScenePortal from './internal/ScenePortal.svelte'
|
|
5
6
|
|
|
7
|
+
interface Props {
|
|
8
|
+
children?: Snippet<[{ ref: Group }]>
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const { children }: Props = $props()
|
|
12
|
+
|
|
13
|
+
const { scene } = useThrelte()
|
|
6
14
|
const headset = useHeadset()
|
|
7
15
|
</script>
|
|
8
16
|
|
|
9
|
-
<
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
17
|
+
<T
|
|
18
|
+
is={headset}
|
|
19
|
+
attach={scene}
|
|
20
|
+
>
|
|
21
|
+
{@render children?.({ ref: headset })}
|
|
22
|
+
</T>
|
|
@@ -1,20 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
$$slots?: Slots;
|
|
8
|
-
}): Exports & {
|
|
9
|
-
$set?: any;
|
|
10
|
-
$on?: any;
|
|
11
|
-
};
|
|
12
|
-
z_$$bindings?: Bindings;
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
2
|
+
import type { Group } from 'three';
|
|
3
|
+
interface Props {
|
|
4
|
+
children?: Snippet<[{
|
|
5
|
+
ref: Group;
|
|
6
|
+
}]>;
|
|
13
7
|
}
|
|
14
|
-
declare const Headset:
|
|
15
|
-
|
|
16
|
-
}, {
|
|
17
|
-
default: {};
|
|
18
|
-
}, {}, string>;
|
|
19
|
-
type Headset = InstanceType<typeof Headset>;
|
|
8
|
+
declare const Headset: import("svelte").Component<Props, {}, "">;
|
|
9
|
+
type Headset = ReturnType<typeof Headset>;
|
|
20
10
|
export default Headset;
|
|
@@ -1,3 +1,6 @@
|
|
|
1
|
+
import type { ComponentProps } from 'svelte';
|
|
2
|
+
import XRButton from './XRButton.svelte';
|
|
3
|
+
type Props = Omit<ComponentProps<typeof XRButton>, 'mode' | 'sessionInit'>;
|
|
1
4
|
/**
|
|
2
5
|
* `<VRButton />` is an HTML `<button />` that can be used to init and display info about your immersive VR session.
|
|
3
6
|
*
|
|
@@ -8,22 +11,6 @@
|
|
|
8
11
|
* />
|
|
9
12
|
* ```
|
|
10
13
|
*/
|
|
11
|
-
declare const VrButton: import("svelte").Component<
|
|
12
|
-
|
|
13
|
-
sessionInit?: XRSessionInit & {
|
|
14
|
-
domOverlay?: {
|
|
15
|
-
root: HTMLElement;
|
|
16
|
-
} | undefined;
|
|
17
|
-
};
|
|
18
|
-
force?: "enter" | "exit";
|
|
19
|
-
styled?: boolean;
|
|
20
|
-
children?: import("svelte").Snippet<[{
|
|
21
|
-
state: "unsupported" | "insecure" | "blocked" | "supported";
|
|
22
|
-
}]>;
|
|
23
|
-
onclick?: (event: {
|
|
24
|
-
state: "unsupported" | "insecure" | "blocked" | "supported";
|
|
25
|
-
nativeEvent: MouseEvent;
|
|
26
|
-
}) => void;
|
|
27
|
-
onerror?: (error: Error) => void;
|
|
28
|
-
}, "mode" | "sessionInit">, {}, "">;
|
|
14
|
+
declare const VrButton: import("svelte").Component<Props, {}, "">;
|
|
15
|
+
type VrButton = ReturnType<typeof VrButton>;
|
|
29
16
|
export default VrButton;
|
|
@@ -18,18 +18,18 @@ This should be placed within a Threlte `<Canvas />`.
|
|
|
18
18
|
|
|
19
19
|
-->
|
|
20
20
|
<script lang="ts">
|
|
21
|
-
import {
|
|
22
|
-
import { useThrelte
|
|
21
|
+
import type { Snippet } from 'svelte'
|
|
22
|
+
import { useThrelte } from '@threlte/core'
|
|
23
23
|
import type { XRSessionEvent } from '../types'
|
|
24
24
|
import {
|
|
25
25
|
isHandTracking,
|
|
26
26
|
isPresenting,
|
|
27
27
|
referenceSpaceType,
|
|
28
28
|
session,
|
|
29
|
-
xr
|
|
30
|
-
} from '../internal/
|
|
31
|
-
import { setupRaf } from '../internal/setupRaf'
|
|
32
|
-
import { setupHeadset } from '../internal/setupHeadset'
|
|
29
|
+
xr
|
|
30
|
+
} from '../internal/state.svelte'
|
|
31
|
+
import { setupRaf } from '../internal/setupRaf.svelte'
|
|
32
|
+
import { setupHeadset } from '../internal/setupHeadset.svelte'
|
|
33
33
|
import { setupControllers } from '../internal/setupControllers'
|
|
34
34
|
import { setupHands } from '../internal/setupHands'
|
|
35
35
|
|
|
@@ -85,7 +85,6 @@ This should be placed within a Threlte `<Canvas />`.
|
|
|
85
85
|
}: Props = $props()
|
|
86
86
|
|
|
87
87
|
const { renderer, renderMode } = useThrelte()
|
|
88
|
-
const { xr } = renderer
|
|
89
88
|
|
|
90
89
|
let originalRenderMode = $renderMode
|
|
91
90
|
|
|
@@ -95,50 +94,40 @@ This should be placed within a Threlte `<Canvas />`.
|
|
|
95
94
|
setupHands()
|
|
96
95
|
|
|
97
96
|
const handleSessionStart = () => {
|
|
98
|
-
isPresenting.
|
|
99
|
-
onsessionstart?.({ type: 'sessionstart', target:
|
|
97
|
+
isPresenting.current = true
|
|
98
|
+
onsessionstart?.({ type: 'sessionstart', target: session.current } as any)
|
|
100
99
|
}
|
|
101
100
|
|
|
102
101
|
const handleSessionEnd = () => {
|
|
103
|
-
onsessionend?.({ type: 'sessionend', target:
|
|
104
|
-
isPresenting.
|
|
105
|
-
session.
|
|
102
|
+
onsessionend?.({ type: 'sessionend', target: session.current } as any)
|
|
103
|
+
isPresenting.current = false
|
|
104
|
+
session.current = undefined
|
|
106
105
|
}
|
|
107
106
|
|
|
108
107
|
const handleVisibilityChange = (event: globalThis.XRSessionEvent) => {
|
|
109
|
-
onvisibilitychange?.({ ...event, target:
|
|
108
|
+
onvisibilitychange?.({ ...event, target: session.current! })
|
|
110
109
|
}
|
|
111
110
|
|
|
112
111
|
const handleInputSourcesChange = (event: XRInputSourcesChangeEvent) => {
|
|
113
|
-
|
|
114
|
-
oninputsourceschange?.({ ...event, target:
|
|
112
|
+
isHandTracking.current = Object.values(event.session.inputSources).some((source) => source.hand)
|
|
113
|
+
oninputsourceschange?.({ ...event, target: session.current! })
|
|
115
114
|
}
|
|
116
115
|
|
|
117
116
|
const handleFramerateChange = (event: globalThis.XRSessionEvent) => {
|
|
118
|
-
onvisibilitychange?.({ ...event, target:
|
|
117
|
+
onvisibilitychange?.({ ...event, target: session.current! })
|
|
119
118
|
}
|
|
120
119
|
|
|
121
|
-
|
|
122
|
-
|
|
120
|
+
$effect(() => {
|
|
121
|
+
const currentSession = session.current
|
|
123
122
|
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
} catch {
|
|
127
|
-
// Do nothing
|
|
123
|
+
if (currentSession === undefined) {
|
|
124
|
+
return
|
|
128
125
|
}
|
|
129
|
-
}
|
|
130
|
-
|
|
131
|
-
watch(session, (currentSession) => {
|
|
132
|
-
if (currentSession === undefined) return
|
|
133
126
|
|
|
134
127
|
currentSession.addEventListener('visibilitychange', handleVisibilityChange)
|
|
135
128
|
currentSession.addEventListener('inputsourceschange', handleInputSourcesChange)
|
|
136
129
|
currentSession.addEventListener('frameratechange', handleFramerateChange)
|
|
137
130
|
|
|
138
|
-
xr.setFoveation(foveation)
|
|
139
|
-
|
|
140
|
-
updateTargetFrameRate(frameRate)
|
|
141
|
-
|
|
142
131
|
return () => {
|
|
143
132
|
currentSession.removeEventListener('visibilitychange', handleVisibilityChange)
|
|
144
133
|
currentSession.removeEventListener('inputsourceschange', handleInputSourcesChange)
|
|
@@ -146,8 +135,8 @@ This should be placed within a Threlte `<Canvas />`.
|
|
|
146
135
|
}
|
|
147
136
|
})
|
|
148
137
|
|
|
149
|
-
|
|
150
|
-
if (
|
|
138
|
+
$effect.pre(() => {
|
|
139
|
+
if (isPresenting.current) {
|
|
151
140
|
originalRenderMode = renderMode.current
|
|
152
141
|
renderMode.set('always')
|
|
153
142
|
} else {
|
|
@@ -155,35 +144,46 @@ This should be placed within a Threlte `<Canvas />`.
|
|
|
155
144
|
}
|
|
156
145
|
})
|
|
157
146
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
xr.
|
|
162
|
-
xr.
|
|
147
|
+
$effect.pre(() => {
|
|
148
|
+
const currentSession = session.current
|
|
149
|
+
|
|
150
|
+
xr.current = renderer.xr
|
|
151
|
+
renderer.xr.enabled = true
|
|
152
|
+
renderer.xr.addEventListener('sessionstart', handleSessionStart)
|
|
153
|
+
renderer.xr.addEventListener('sessionend', handleSessionEnd)
|
|
163
154
|
|
|
164
155
|
return () => {
|
|
165
|
-
|
|
166
|
-
xr.enabled = false
|
|
167
|
-
xr.removeEventListener('sessionstart', handleSessionStart)
|
|
168
|
-
xr.removeEventListener('sessionend', handleSessionEnd)
|
|
156
|
+
xr.current = undefined
|
|
157
|
+
renderer.xr.enabled = false
|
|
158
|
+
renderer.xr.removeEventListener('sessionstart', handleSessionStart)
|
|
159
|
+
renderer.xr.removeEventListener('sessionend', handleSessionEnd)
|
|
160
|
+
|
|
161
|
+
// if unmounted while presenting (e.g. due to sveltekit navigation), end the session
|
|
162
|
+
currentSession?.end()
|
|
169
163
|
}
|
|
170
164
|
})
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
if (
|
|
174
|
-
|
|
165
|
+
|
|
166
|
+
$effect.pre(() => {
|
|
167
|
+
if (frameRate === undefined) return
|
|
168
|
+
|
|
169
|
+
try {
|
|
170
|
+
session.current?.updateTargetFrameRate(frameRate)
|
|
171
|
+
} catch {
|
|
172
|
+
// Do nothing
|
|
175
173
|
}
|
|
176
174
|
})
|
|
177
175
|
|
|
178
|
-
$effect.pre(() => updateTargetFrameRate(frameRate))
|
|
179
|
-
$effect.pre(() => xr.setFoveation(foveation))
|
|
180
176
|
$effect.pre(() => {
|
|
181
|
-
xr.
|
|
182
|
-
|
|
177
|
+
renderer.xr.setFoveation(foveation)
|
|
178
|
+
})
|
|
179
|
+
|
|
180
|
+
$effect.pre(() => {
|
|
181
|
+
renderer.xr.setReferenceSpaceType(referenceSpace)
|
|
182
|
+
referenceSpaceType.current = referenceSpace
|
|
183
183
|
})
|
|
184
184
|
</script>
|
|
185
185
|
|
|
186
|
-
{#if
|
|
186
|
+
{#if isPresenting.current}
|
|
187
187
|
{@render children?.()}
|
|
188
188
|
{:else}
|
|
189
189
|
{@render fallback?.()}
|