@threlte/xr 1.0.0-next.1 → 1.0.0-next.10
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 +8 -6
- package/dist/components/ARButton.svelte.d.ts +10 -2
- package/dist/components/Controller.svelte +55 -41
- package/dist/components/Controller.svelte.d.ts +13 -19
- package/dist/components/Hand.svelte +37 -15
- package/dist/components/Hand.svelte.d.ts +10 -19
- package/dist/components/Headset.svelte.d.ts +1 -3
- package/dist/components/VRButton.svelte +4 -3
- package/dist/components/VRButton.svelte.d.ts +10 -2
- package/dist/components/XR.svelte +18 -13
- package/dist/components/XR.svelte.d.ts +15 -25
- package/dist/components/XRButton.svelte +18 -7
- package/dist/components/XRButton.svelte.d.ts +11 -2
- package/dist/components/internal/Cursor.svelte +12 -11
- package/dist/components/internal/PointerCursor.svelte +9 -8
- package/dist/components/internal/PointerCursor.svelte.d.ts +3 -6
- package/dist/components/internal/ScenePortal.svelte +15 -5
- package/dist/components/internal/ScenePortal.svelte.d.ts +1 -3
- package/dist/components/internal/ShortRay.svelte +28 -27
- package/dist/components/internal/ShortRay.svelte.d.ts +3 -6
- package/dist/components/internal/TeleportCursor.svelte +8 -6
- package/dist/components/internal/TeleportCursor.svelte.d.ts +3 -6
- package/dist/components/internal/TeleportRay.svelte +8 -7
- package/dist/components/internal/TeleportRay.svelte.d.ts +3 -6
- package/dist/internal/defaultFeatures.d.ts +4 -0
- package/dist/internal/defaultFeatures.js +14 -0
- package/dist/internal/setupControllers.js +1 -1
- package/dist/internal/setupHands.js +1 -1
- package/dist/internal/setupHeadset.js +14 -5
- package/dist/internal/setupRaf.js +8 -12
- package/dist/internal/stores.d.ts +5 -4
- package/dist/plugins/pointerControls/context.d.ts +12 -0
- package/dist/plugins/pointerControls/hook.d.ts +1 -1
- package/dist/plugins/pointerControls/hook.js +6 -5
- package/dist/plugins/pointerControls/plugin.js +9 -11
- package/dist/plugins/pointerControls/setup.js +35 -34
- package/dist/plugins/pointerControls/types.d.ts +10 -10
- package/dist/plugins/pointerControls/types.js +9 -9
- package/dist/plugins/teleportControls/context.d.ts +11 -5
- package/dist/plugins/teleportControls/context.js +45 -2
- package/dist/plugins/teleportControls/index.js +4 -13
- package/dist/plugins/teleportControls/plugin.js +11 -11
- package/dist/plugins/teleportControls/setup.js +1 -1
- package/dist/types.d.ts +20 -2
- package/package.json +29 -9
- package/dist/plugins/pointerControls/useComponentEventHandlers.d.ts +0 -4
- package/dist/plugins/pointerControls/useComponentEventHandlers.js +0 -13
- package/dist/plugins/teleportControls/hook.d.ts +0 -7
- package/dist/plugins/teleportControls/hook.js +0 -40
|
@@ -4,21 +4,23 @@
|
|
|
4
4
|
|
|
5
5
|
```svelte
|
|
6
6
|
<ARButton
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
onerror={(event) => {}}
|
|
8
|
+
onclick={(event) => {}}
|
|
9
9
|
/>
|
|
10
10
|
```
|
|
11
11
|
-->
|
|
12
12
|
<script lang="ts">import XRButton from "./XRButton.svelte";
|
|
13
|
-
|
|
13
|
+
import { defaultFeatures } from "../internal/defaultFeatures";
|
|
14
|
+
let { children, ...props } = $props();
|
|
14
15
|
</script>
|
|
15
16
|
|
|
16
17
|
<XRButton
|
|
17
18
|
sessionInit={{
|
|
18
19
|
domOverlay: typeof document !== 'undefined' ? { root: document.body } : undefined,
|
|
19
|
-
|
|
20
|
-
optionalFeatures: ['local-floor', 'bounded-floor', 'hand-tracking', 'layers', 'hit-test']
|
|
20
|
+
...defaultFeatures
|
|
21
21
|
}}
|
|
22
22
|
{...props}
|
|
23
23
|
mode="immersive-ar"
|
|
24
|
-
|
|
24
|
+
>
|
|
25
|
+
{@render children?.()}
|
|
26
|
+
</XRButton>
|
|
@@ -10,6 +10,14 @@ declare const __propDef: {
|
|
|
10
10
|
}) | undefined;
|
|
11
11
|
force?: "enter" | "exit" | undefined;
|
|
12
12
|
styled?: boolean | undefined;
|
|
13
|
+
children?: import("svelte").Snippet<[{
|
|
14
|
+
state: "blocked" | "unsupported" | "insecure" | "supported";
|
|
15
|
+
}]> | undefined;
|
|
16
|
+
onclick?: ((event: {
|
|
17
|
+
state: "blocked" | "unsupported" | "insecure" | "supported";
|
|
18
|
+
nativeEvent: MouseEvent;
|
|
19
|
+
}) => void) | undefined;
|
|
20
|
+
onerror?: ((error: Error) => void) | undefined;
|
|
13
21
|
}, "mode" | "sessionInit"> & {
|
|
14
22
|
sessionInit?: (XRSessionInit & {
|
|
15
23
|
domOverlay?: {
|
|
@@ -30,8 +38,8 @@ export type ArButtonSlots = typeof __propDef.slots;
|
|
|
30
38
|
*
|
|
31
39
|
* ```svelte
|
|
32
40
|
* <ARButton
|
|
33
|
-
*
|
|
34
|
-
*
|
|
41
|
+
* onerror={(event) => {}}
|
|
42
|
+
* onclick={(event) => {}}
|
|
35
43
|
* />
|
|
36
44
|
* ```
|
|
37
45
|
*/
|
|
@@ -19,11 +19,40 @@ const stores = {
|
|
|
19
19
|
};
|
|
20
20
|
</script>
|
|
21
21
|
|
|
22
|
-
<script lang="ts">let {
|
|
22
|
+
<script lang="ts">let {
|
|
23
|
+
left,
|
|
24
|
+
right,
|
|
25
|
+
hand,
|
|
26
|
+
onconnected,
|
|
27
|
+
ondisconnected,
|
|
28
|
+
onselect,
|
|
29
|
+
onselectend,
|
|
30
|
+
onselectstart,
|
|
31
|
+
onsqueeze,
|
|
32
|
+
onsqueezeend,
|
|
33
|
+
onsqueezestart,
|
|
34
|
+
children,
|
|
35
|
+
grip: gripSnippet,
|
|
36
|
+
targetRay: targetRaySnippet,
|
|
37
|
+
pointerRay: pointerRaySnippet,
|
|
38
|
+
pointerCursor: pointerCursorSnippet,
|
|
39
|
+
teleportRay: teleportRaySnippet,
|
|
40
|
+
teleportCursor: teleportCursorSnippet
|
|
41
|
+
} = $props();
|
|
23
42
|
const handedness = writable(left ? "left" : right ? "right" : hand);
|
|
24
43
|
$effect.pre(() => handedness.set(left ? "left" : right ? "right" : hand));
|
|
25
|
-
|
|
26
|
-
|
|
44
|
+
$effect.pre(
|
|
45
|
+
() => controllerEvents[$handedness].set({
|
|
46
|
+
onconnected,
|
|
47
|
+
ondisconnected,
|
|
48
|
+
onselect,
|
|
49
|
+
onselectend,
|
|
50
|
+
onselectstart,
|
|
51
|
+
onsqueeze,
|
|
52
|
+
onsqueezeend,
|
|
53
|
+
onsqueezestart
|
|
54
|
+
})
|
|
55
|
+
);
|
|
27
56
|
let store = $derived(stores[$handedness]);
|
|
28
57
|
let grip = $derived($store?.grip);
|
|
29
58
|
let targetRay = $derived($store?.targetRay);
|
|
@@ -35,26 +64,25 @@ let hasTeleportControls = $derived($teleportState[$handedness].enabled);
|
|
|
35
64
|
{#if !$isHandTracking}
|
|
36
65
|
{#if grip}
|
|
37
66
|
<T is={grip}>
|
|
38
|
-
|
|
67
|
+
{#if children}
|
|
68
|
+
{@render children?.()}
|
|
69
|
+
{:else}
|
|
39
70
|
<T is={model} />
|
|
40
|
-
|
|
71
|
+
{/if}
|
|
41
72
|
|
|
42
|
-
|
|
73
|
+
{@render gripSnippet?.()}
|
|
43
74
|
</T>
|
|
44
75
|
{/if}
|
|
45
76
|
|
|
46
77
|
{#if targetRay}
|
|
47
78
|
<T is={targetRay}>
|
|
48
|
-
|
|
79
|
+
{@render targetRaySnippet?.()}
|
|
49
80
|
|
|
50
81
|
{#if hasPointerControls || hasTeleportControls}
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
{:else}
|
|
56
|
-
<ShortRay handedness={$handedness} />
|
|
57
|
-
{/if}
|
|
82
|
+
<ShortRay
|
|
83
|
+
handedness={$handedness}
|
|
84
|
+
children={pointerRaySnippet}
|
|
85
|
+
/>
|
|
58
86
|
{/if}
|
|
59
87
|
</T>
|
|
60
88
|
{/if}
|
|
@@ -62,36 +90,22 @@ let hasTeleportControls = $derived($teleportState[$handedness].enabled);
|
|
|
62
90
|
|
|
63
91
|
<ScenePortal>
|
|
64
92
|
{#if hasPointerControls}
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
{:else}
|
|
70
|
-
<PointerCursor handedness={$handedness} />
|
|
71
|
-
{/if}
|
|
93
|
+
<PointerCursor
|
|
94
|
+
handedness={$handedness}
|
|
95
|
+
children={pointerCursorSnippet}
|
|
96
|
+
/>
|
|
72
97
|
{/if}
|
|
73
98
|
|
|
74
99
|
{#if hasTeleportControls && targetRay !== undefined}
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
<slot name="teleport-ray" />
|
|
81
|
-
</TeleportRay>
|
|
82
|
-
{:else}
|
|
83
|
-
<TeleportRay
|
|
84
|
-
{targetRay}
|
|
85
|
-
handedness={$handedness}
|
|
86
|
-
/>
|
|
87
|
-
{/if}
|
|
100
|
+
<TeleportRay
|
|
101
|
+
{targetRay}
|
|
102
|
+
handedness={$handedness}
|
|
103
|
+
children={teleportRaySnippet}
|
|
104
|
+
/>
|
|
88
105
|
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
{:else}
|
|
94
|
-
<TeleportCursor handedness={$handedness} />
|
|
95
|
-
{/if}
|
|
106
|
+
<TeleportCursor
|
|
107
|
+
handedness={$handedness}
|
|
108
|
+
children={teleportCursorSnippet}
|
|
109
|
+
/>
|
|
96
110
|
{/if}
|
|
97
111
|
</ScenePortal>
|
|
@@ -1,7 +1,16 @@
|
|
|
1
1
|
import { SvelteComponent } from "svelte";
|
|
2
|
-
import type {
|
|
2
|
+
import type { XRControllerEvents } from '../types';
|
|
3
|
+
import type { Snippet } from 'svelte';
|
|
3
4
|
declare const __propDef: {
|
|
4
5
|
props: {
|
|
6
|
+
children?: Snippet<[]> | undefined;
|
|
7
|
+
grip?: Snippet<[]> | undefined;
|
|
8
|
+
targetRay?: Snippet<[]> | undefined;
|
|
9
|
+
pointerRay?: Snippet<[]> | undefined;
|
|
10
|
+
pointerCursor?: Snippet<[]> | undefined;
|
|
11
|
+
teleportRay?: Snippet<[]> | undefined;
|
|
12
|
+
teleportCursor?: Snippet<[]> | undefined;
|
|
13
|
+
} & XRControllerEvents & ({
|
|
5
14
|
/** Whether the controller should be matched with the left hand. */
|
|
6
15
|
left: true;
|
|
7
16
|
right?: undefined;
|
|
@@ -16,26 +25,11 @@ declare const __propDef: {
|
|
|
16
25
|
hand: 'left' | 'right';
|
|
17
26
|
left?: undefined;
|
|
18
27
|
right?: undefined;
|
|
19
|
-
};
|
|
20
|
-
slots: {
|
|
21
|
-
default: {};
|
|
22
|
-
grip: {};
|
|
23
|
-
'target-ray': {};
|
|
24
|
-
'pointer-ray': {};
|
|
25
|
-
'pointer-cursor': {};
|
|
26
|
-
'teleport-ray': {};
|
|
27
|
-
'teleport-cursor': {};
|
|
28
|
-
};
|
|
28
|
+
});
|
|
29
29
|
events: {
|
|
30
|
-
|
|
31
|
-
disconnected: XRControllerEvent<'disconnected'>;
|
|
32
|
-
select: XRControllerEvent<'select'>;
|
|
33
|
-
selectstart: XRControllerEvent<'selectstart'>;
|
|
34
|
-
selectend: XRControllerEvent<'selectend'>;
|
|
35
|
-
squeeze: XRControllerEvent<'squeeze'>;
|
|
36
|
-
squeezeend: XRControllerEvent<'squeezeend'>;
|
|
37
|
-
squeezestart: XRControllerEvent<'squeezestart'>;
|
|
30
|
+
[evt: string]: CustomEvent<any>;
|
|
38
31
|
};
|
|
32
|
+
slots: {};
|
|
39
33
|
};
|
|
40
34
|
export type ControllerProps = typeof __propDef.props;
|
|
41
35
|
export type ControllerEvents = typeof __propDef.events;
|
|
@@ -13,30 +13,52 @@ const stores = {
|
|
|
13
13
|
};
|
|
14
14
|
</script>
|
|
15
15
|
|
|
16
|
-
<script lang="ts">let {
|
|
17
|
-
|
|
16
|
+
<script lang="ts">let {
|
|
17
|
+
left,
|
|
18
|
+
right,
|
|
19
|
+
hand,
|
|
20
|
+
onconnected,
|
|
21
|
+
ondisconnected,
|
|
22
|
+
onpinchend,
|
|
23
|
+
onpinchstart,
|
|
24
|
+
children,
|
|
25
|
+
targetRay,
|
|
26
|
+
wrist
|
|
27
|
+
} = $props();
|
|
28
|
+
const { renderer, scheduler, renderStage } = useThrelte();
|
|
29
|
+
const { xr } = renderer;
|
|
18
30
|
const space = xr.getReferenceSpace();
|
|
19
31
|
const handedness = writable(left ? "left" : right ? "right" : hand);
|
|
20
32
|
$effect.pre(() => handedness.set(left ? "left" : right ? "right" : hand));
|
|
21
|
-
$effect.pre(
|
|
22
|
-
|
|
33
|
+
$effect.pre(
|
|
34
|
+
() => handEvents[$handedness].set({
|
|
35
|
+
onconnected,
|
|
36
|
+
ondisconnected,
|
|
37
|
+
onpinchend,
|
|
38
|
+
onpinchstart
|
|
39
|
+
})
|
|
40
|
+
);
|
|
41
|
+
let group = new Group();
|
|
23
42
|
const { start, stop } = useTask(
|
|
24
43
|
() => {
|
|
25
44
|
const frame = xr.getFrame();
|
|
26
|
-
const joint = inputSource
|
|
45
|
+
const joint = inputSource?.get("wrist");
|
|
27
46
|
if (joint === void 0 || space === null)
|
|
28
47
|
return;
|
|
29
48
|
const pose = frame.getJointPose?.(joint, space);
|
|
30
49
|
if (pose === void 0 || pose === null)
|
|
31
50
|
return;
|
|
32
51
|
const { position, orientation } = pose.transform;
|
|
33
|
-
|
|
34
|
-
|
|
52
|
+
group.position.set(position.x, position.y, position.z);
|
|
53
|
+
group.quaternion.set(orientation.x, orientation.y, orientation.z, orientation.w);
|
|
35
54
|
},
|
|
36
|
-
{
|
|
55
|
+
{
|
|
56
|
+
autoStart: false,
|
|
57
|
+
stage: scheduler.createStage(Symbol("xr-hand-stage"), { before: renderStage })
|
|
58
|
+
}
|
|
37
59
|
);
|
|
38
60
|
$effect.pre(() => {
|
|
39
|
-
if ($isHandTracking && (
|
|
61
|
+
if ($isHandTracking && (wrist !== void 0 || children !== void 0) && inputSource) {
|
|
40
62
|
start();
|
|
41
63
|
} else {
|
|
42
64
|
stop();
|
|
@@ -49,23 +71,23 @@ let model = $derived($store?.model);
|
|
|
49
71
|
|
|
50
72
|
{#if $store?.hand && $isHandTracking}
|
|
51
73
|
<T is={$store.hand}>
|
|
52
|
-
{#if
|
|
74
|
+
{#if children === undefined}
|
|
53
75
|
<T is={model} />
|
|
54
76
|
{/if}
|
|
55
77
|
</T>
|
|
56
78
|
|
|
57
|
-
{#if
|
|
79
|
+
{#if targetRay !== undefined}
|
|
58
80
|
<T is={$store.targetRay}>
|
|
59
|
-
|
|
81
|
+
{@render targetRay()}
|
|
60
82
|
</T>
|
|
61
83
|
{/if}
|
|
62
84
|
{/if}
|
|
63
85
|
|
|
64
86
|
{#if $isHandTracking}
|
|
65
87
|
<ScenePortal>
|
|
66
|
-
<T is={
|
|
67
|
-
|
|
68
|
-
|
|
88
|
+
<T is={group}>
|
|
89
|
+
{@render wrist?.()}
|
|
90
|
+
{@render children?.()}
|
|
69
91
|
</T>
|
|
70
92
|
</ScenePortal>
|
|
71
93
|
{/if}
|
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
import { SvelteComponent } from "svelte";
|
|
2
|
-
import type {
|
|
2
|
+
import type { XRHandEvents } from '../types';
|
|
3
|
+
import type { Snippet } from 'svelte';
|
|
3
4
|
declare const __propDef: {
|
|
4
|
-
props:
|
|
5
|
+
props: {
|
|
6
|
+
children?: Snippet<[]> | undefined;
|
|
7
|
+
targetRay?: Snippet<[]> | undefined;
|
|
8
|
+
wrist?: Snippet<[]> | undefined;
|
|
9
|
+
} & XRHandEvents & ({
|
|
5
10
|
/** Whether the XRHand should be matched with the left hand. */
|
|
6
11
|
left: true;
|
|
7
12
|
right?: undefined;
|
|
@@ -16,25 +21,11 @@ declare const __propDef: {
|
|
|
16
21
|
hand: 'left' | 'right';
|
|
17
22
|
left?: undefined;
|
|
18
23
|
right?: undefined;
|
|
19
|
-
})
|
|
20
|
-
$$events: {
|
|
21
|
-
connected: XRHandEvent<'connected'>;
|
|
22
|
-
disconnected: XRHandEvent<'disconnected'>;
|
|
23
|
-
pinchstart: XRHandEvent<'pinchstart'>;
|
|
24
|
-
pinchend: XRHandEvent<'pinchend'>;
|
|
25
|
-
};
|
|
26
|
-
};
|
|
27
|
-
slots: {
|
|
28
|
-
'target-ray': {};
|
|
29
|
-
wrist: {};
|
|
30
|
-
default: {};
|
|
31
|
-
};
|
|
24
|
+
});
|
|
32
25
|
events: {
|
|
33
|
-
|
|
34
|
-
disconnected: XRHandEvent<'disconnected'>;
|
|
35
|
-
pinchstart: XRHandEvent<'pinchstart'>;
|
|
36
|
-
pinchend: XRHandEvent<'pinchend'>;
|
|
26
|
+
[evt: string]: CustomEvent<any>;
|
|
37
27
|
};
|
|
28
|
+
slots: {};
|
|
38
29
|
};
|
|
39
30
|
export type HandProps = typeof __propDef.props;
|
|
40
31
|
export type HandEvents = typeof __propDef.events;
|
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
import { SvelteComponent } from "svelte";
|
|
2
2
|
declare const __propDef: {
|
|
3
3
|
props: {
|
|
4
|
-
children?:
|
|
5
|
-
_: "functions passed to {@render ...} tags must use the `Snippet` type imported from \"svelte\"";
|
|
6
|
-
}) | undefined;
|
|
4
|
+
children?: import("svelte").Snippet<[]> | undefined;
|
|
7
5
|
};
|
|
8
6
|
events: {
|
|
9
7
|
[evt: string]: CustomEvent<any>;
|
|
@@ -4,18 +4,19 @@
|
|
|
4
4
|
|
|
5
5
|
```svelte
|
|
6
6
|
<VRButton
|
|
7
|
-
|
|
8
|
-
|
|
7
|
+
onerror={(event) => {}}
|
|
8
|
+
onclick={(event) => {}}
|
|
9
9
|
/>
|
|
10
10
|
```
|
|
11
11
|
-->
|
|
12
12
|
<script lang="ts">import XRButton from "./XRButton.svelte";
|
|
13
|
+
import { defaultFeatures } from "../internal/defaultFeatures";
|
|
13
14
|
let { ...props } = $props();
|
|
14
15
|
</script>
|
|
15
16
|
|
|
16
17
|
<XRButton
|
|
17
18
|
sessionInit={{
|
|
18
|
-
|
|
19
|
+
...defaultFeatures
|
|
19
20
|
}}
|
|
20
21
|
{...props}
|
|
21
22
|
mode="immersive-vr"
|
|
@@ -10,6 +10,14 @@ declare const __propDef: {
|
|
|
10
10
|
}) | undefined;
|
|
11
11
|
force?: "enter" | "exit" | undefined;
|
|
12
12
|
styled?: boolean | undefined;
|
|
13
|
+
children?: import("svelte").Snippet<[{
|
|
14
|
+
state: "blocked" | "unsupported" | "insecure" | "supported";
|
|
15
|
+
}]> | undefined;
|
|
16
|
+
onclick?: ((event: {
|
|
17
|
+
state: "blocked" | "unsupported" | "insecure" | "supported";
|
|
18
|
+
nativeEvent: MouseEvent;
|
|
19
|
+
}) => void) | undefined;
|
|
20
|
+
onerror?: ((error: Error) => void) | undefined;
|
|
13
21
|
}, "mode" | "sessionInit">;
|
|
14
22
|
events: {
|
|
15
23
|
[evt: string]: CustomEvent<any>;
|
|
@@ -24,8 +32,8 @@ export type VrButtonSlots = typeof __propDef.slots;
|
|
|
24
32
|
*
|
|
25
33
|
* ```svelte
|
|
26
34
|
* <VRButton
|
|
27
|
-
*
|
|
28
|
-
*
|
|
35
|
+
* onerror={(event) => {}}
|
|
36
|
+
* onclick={(event) => {}}
|
|
29
37
|
* />
|
|
30
38
|
* ```
|
|
31
39
|
*/
|
|
@@ -9,16 +9,16 @@ This should be placed within a Threlte `<Canvas />`.
|
|
|
9
9
|
foveation={1}
|
|
10
10
|
frameRate={90}
|
|
11
11
|
referenceSpace='local-floor'
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
12
|
+
onsessionstart={(event: XREvent<XRManagerEvent>) => {}}
|
|
13
|
+
onsessionend={(event: XREvent<XRManagerEvent>) => {}}
|
|
14
|
+
onvisibilitychange={(event: XREvent<XRSessionEvent>) => {}}
|
|
15
|
+
oninputsourceschange={(event: XREvent<XRSessionEvent>) => {}}
|
|
16
16
|
/>
|
|
17
17
|
```
|
|
18
18
|
|
|
19
19
|
-->
|
|
20
20
|
<script lang="ts">import { onMount } from "svelte";
|
|
21
|
-
import {
|
|
21
|
+
import { useThrelte, watch } from "@threlte/core";
|
|
22
22
|
import {
|
|
23
23
|
isHandTracking,
|
|
24
24
|
isPresenting,
|
|
@@ -34,7 +34,12 @@ let {
|
|
|
34
34
|
foveation = 1,
|
|
35
35
|
frameRate,
|
|
36
36
|
referenceSpace = "local-floor",
|
|
37
|
-
|
|
37
|
+
onsessionstart,
|
|
38
|
+
onsessionend,
|
|
39
|
+
onvisibilitychange,
|
|
40
|
+
oninputsourceschange,
|
|
41
|
+
fallback,
|
|
42
|
+
children
|
|
38
43
|
} = $props();
|
|
39
44
|
const { renderer, renderMode } = useThrelte();
|
|
40
45
|
const { xr } = renderer;
|
|
@@ -45,22 +50,22 @@ setupControllers();
|
|
|
45
50
|
setupHands();
|
|
46
51
|
const handleSessionStart = () => {
|
|
47
52
|
isPresenting.set(true);
|
|
48
|
-
|
|
53
|
+
onsessionstart?.({ type: "sessionstart", target: $session });
|
|
49
54
|
};
|
|
50
55
|
const handleSessionEnd = () => {
|
|
51
|
-
|
|
56
|
+
onsessionend?.({ type: "sessionend", target: $session });
|
|
52
57
|
isPresenting.set(false);
|
|
53
58
|
session.set(void 0);
|
|
54
59
|
};
|
|
55
60
|
const handleVisibilityChange = (event) => {
|
|
56
|
-
|
|
61
|
+
onvisibilitychange?.({ ...event, target: $session });
|
|
57
62
|
};
|
|
58
63
|
const handleInputSourcesChange = (event) => {
|
|
59
64
|
$isHandTracking = Object.values(event.session.inputSources).some((source) => source.hand);
|
|
60
|
-
|
|
65
|
+
oninputsourceschange?.({ ...event, target: $session });
|
|
61
66
|
};
|
|
62
67
|
const handleFramerateChange = (event) => {
|
|
63
|
-
|
|
68
|
+
onvisibilitychange?.({ ...event, target: $session });
|
|
64
69
|
};
|
|
65
70
|
const updateTargetFrameRate = (frameRate2) => {
|
|
66
71
|
if (frameRate2 === void 0)
|
|
@@ -113,7 +118,7 @@ $effect.pre(() => {
|
|
|
113
118
|
</script>
|
|
114
119
|
|
|
115
120
|
{#if $isPresenting}
|
|
116
|
-
|
|
121
|
+
{@render children?.()}
|
|
117
122
|
{:else}
|
|
118
|
-
|
|
123
|
+
{@render fallback?.()}
|
|
119
124
|
{/if}
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
/// <reference types="webxr" />
|
|
2
2
|
import { SvelteComponent } from "svelte";
|
|
3
|
+
import { type Snippet } from 'svelte';
|
|
3
4
|
import type { XRSessionEvent } from '../types';
|
|
4
5
|
declare const __propDef: {
|
|
5
6
|
props: {
|
|
@@ -22,32 +23,21 @@ declare const __propDef: {
|
|
|
22
23
|
frameRate?: number | undefined;
|
|
23
24
|
/** Type of WebXR reference space to use. Default is `local-floor` */
|
|
24
25
|
referenceSpace?: XRReferenceSpaceType | undefined;
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
/** Called as an XRSession is requested */
|
|
28
|
-
sessionstart(): XRSessionEvent<'sessionstart'>;
|
|
29
|
-
/** Called after an XRSession is terminated */
|
|
30
|
-
sessionend(): XRSessionEvent<'sessionend'>;
|
|
31
|
-
/** Called when an XRSession is hidden or unfocused. */
|
|
32
|
-
visibilitychange(): globalThis.XRSessionEvent;
|
|
33
|
-
/** Called when available inputsources change */
|
|
34
|
-
inputsourceschange(): globalThis.XRSessionEvent;
|
|
35
|
-
};
|
|
36
|
-
};
|
|
37
|
-
slots: {
|
|
38
|
-
default: {};
|
|
39
|
-
fallback: {};
|
|
40
|
-
};
|
|
41
|
-
events: {
|
|
26
|
+
fallback?: Snippet<[]> | undefined;
|
|
27
|
+
children?: Snippet<[]> | undefined;
|
|
42
28
|
/** Called as an XRSession is requested */
|
|
43
|
-
|
|
29
|
+
onsessionstart?: ((event: XRSessionEvent<'sessionstart'>) => void) | undefined;
|
|
44
30
|
/** Called after an XRSession is terminated */
|
|
45
|
-
|
|
31
|
+
onsessionend?: ((event: XRSessionEvent<'sessionend'>) => void) | undefined;
|
|
46
32
|
/** Called when an XRSession is hidden or unfocused. */
|
|
47
|
-
|
|
33
|
+
onvisibilitychange?: ((event: globalThis.XRSessionEvent) => void) | undefined;
|
|
48
34
|
/** Called when available inputsources change */
|
|
49
|
-
|
|
35
|
+
oninputsourceschange?: ((event: globalThis.XRSessionEvent) => void) | undefined;
|
|
36
|
+
};
|
|
37
|
+
events: {
|
|
38
|
+
[evt: string]: CustomEvent<any>;
|
|
50
39
|
};
|
|
40
|
+
slots: {};
|
|
51
41
|
};
|
|
52
42
|
export type XrProps = typeof __propDef.props;
|
|
53
43
|
export type XrEvents = typeof __propDef.events;
|
|
@@ -62,10 +52,10 @@ export type XrSlots = typeof __propDef.slots;
|
|
|
62
52
|
* foveation={1}
|
|
63
53
|
* frameRate={90}
|
|
64
54
|
* referenceSpace='local-floor'
|
|
65
|
-
*
|
|
66
|
-
*
|
|
67
|
-
*
|
|
68
|
-
*
|
|
55
|
+
* onsessionstart={(event: XREvent<XRManagerEvent>) => {}}
|
|
56
|
+
* onsessionend={(event: XREvent<XRManagerEvent>) => {}}
|
|
57
|
+
* onvisibilitychange={(event: XREvent<XRSessionEvent>) => {}}
|
|
58
|
+
* oninputsourceschange={(event: XREvent<XRSessionEvent>) => {}}
|
|
69
59
|
* />
|
|
70
60
|
* ```
|
|
71
61
|
*/
|
|
@@ -12,28 +12,37 @@ display info about your WebXR session. This is aliased by `ARButton` and
|
|
|
12
12
|
}}
|
|
13
13
|
force={'enter' | 'exit' | undefined}
|
|
14
14
|
styled={'true' | 'false'}
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
onerror={(event) => {}}
|
|
16
|
+
onclick={(event) => {}}
|
|
17
17
|
/>
|
|
18
18
|
```
|
|
19
19
|
-->
|
|
20
20
|
<script lang="ts">import { getXRSupportState } from "../lib/getXRSupportState";
|
|
21
21
|
import { toggleXRSession } from "../lib/toggleXRSession";
|
|
22
22
|
import { session, xr } from "../internal/stores";
|
|
23
|
-
let {
|
|
23
|
+
let {
|
|
24
|
+
mode,
|
|
25
|
+
sessionInit,
|
|
26
|
+
force,
|
|
27
|
+
styled = true,
|
|
28
|
+
onclick,
|
|
29
|
+
onerror,
|
|
30
|
+
children,
|
|
31
|
+
...props
|
|
32
|
+
} = $props();
|
|
24
33
|
const handleButtonClick = async (nativeEvent, state) => {
|
|
25
34
|
if (!$xr) {
|
|
26
35
|
throw new Error(
|
|
27
36
|
"The <XR> component was not created. This is required to start an XR session."
|
|
28
37
|
);
|
|
29
38
|
}
|
|
30
|
-
|
|
39
|
+
onclick?.({ state, nativeEvent });
|
|
31
40
|
if (state !== "supported")
|
|
32
41
|
return;
|
|
33
42
|
try {
|
|
34
43
|
await toggleXRSession(mode, sessionInit, force);
|
|
35
44
|
} catch (error) {
|
|
36
|
-
|
|
45
|
+
onerror?.(error);
|
|
37
46
|
}
|
|
38
47
|
};
|
|
39
48
|
let modeText = $derived(
|
|
@@ -62,13 +71,15 @@ let style = $derived(
|
|
|
62
71
|
|
|
63
72
|
{#await getXRSupportState(mode) then state}
|
|
64
73
|
<button
|
|
65
|
-
|
|
74
|
+
onclick={(event) => {
|
|
66
75
|
handleButtonClick(event, state)
|
|
67
76
|
}}
|
|
68
77
|
{...props}
|
|
69
78
|
{style}
|
|
70
79
|
>
|
|
71
|
-
{#if
|
|
80
|
+
{#if children}
|
|
81
|
+
{@render children?.({ state })}
|
|
82
|
+
{:else if state === 'unsupported'}
|
|
72
83
|
{modeText} unsupported
|
|
73
84
|
{:else if state === 'insecure'}
|
|
74
85
|
HTTPS needed
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/// <reference types="webxr" />
|
|
2
2
|
import { SvelteComponent } from "svelte";
|
|
3
3
|
import type { HTMLButtonAttributes } from 'svelte/elements';
|
|
4
|
+
import type { Snippet } from 'svelte';
|
|
4
5
|
declare const __propDef: {
|
|
5
6
|
props: HTMLButtonAttributes & {
|
|
6
7
|
/** The type of `XRSession` to create */
|
|
@@ -18,6 +19,14 @@ declare const __propDef: {
|
|
|
18
19
|
force?: "enter" | "exit" | undefined;
|
|
19
20
|
/** Whether to apply automatic styling to the button. Set false to apply custom styles. Default is true. */
|
|
20
21
|
styled?: boolean | undefined;
|
|
22
|
+
children?: Snippet<[{
|
|
23
|
+
state: "blocked" | "unsupported" | "insecure" | "supported";
|
|
24
|
+
}]> | undefined;
|
|
25
|
+
onclick?: ((event: {
|
|
26
|
+
state: "blocked" | "unsupported" | "insecure" | "supported";
|
|
27
|
+
nativeEvent: MouseEvent;
|
|
28
|
+
}) => void) | undefined;
|
|
29
|
+
onerror?: ((error: Error) => void) | undefined;
|
|
21
30
|
};
|
|
22
31
|
events: {
|
|
23
32
|
[evt: string]: CustomEvent<any>;
|
|
@@ -40,8 +49,8 @@ export type XrButtonSlots = typeof __propDef.slots;
|
|
|
40
49
|
* }}
|
|
41
50
|
* force={'enter' | 'exit' | undefined}
|
|
42
51
|
* styled={'true' | 'false'}
|
|
43
|
-
*
|
|
44
|
-
*
|
|
52
|
+
* onerror={(event) => {}}
|
|
53
|
+
* onclick={(event) => {}}
|
|
45
54
|
* />
|
|
46
55
|
* ```
|
|
47
56
|
*/
|