@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,23 +1,6 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
2
2
|
import type { XRSessionEvent } from '../types';
|
|
3
|
-
|
|
4
|
-
* `<XR />` is a WebXR manager that configures your scene for XR rendering and interaction.
|
|
5
|
-
*
|
|
6
|
-
* This should be placed within a Threlte `<Canvas />`.
|
|
7
|
-
*
|
|
8
|
-
* ```svelte
|
|
9
|
-
* <XR
|
|
10
|
-
* foveation={1}
|
|
11
|
-
* frameRate={90}
|
|
12
|
-
* referenceSpace='local-floor'
|
|
13
|
-
* onsessionstart={(event: XREvent<XRManagerEvent>) => {}}
|
|
14
|
-
* onsessionend={(event: XREvent<XRManagerEvent>) => {}}
|
|
15
|
-
* onvisibilitychange={(event: XREvent<XRSessionEvent>) => {}}
|
|
16
|
-
* oninputsourceschange={(event: XREvent<XRSessionEvent>) => {}}
|
|
17
|
-
* />
|
|
18
|
-
* ```
|
|
19
|
-
*/
|
|
20
|
-
declare const Xr: import("svelte").Component<{
|
|
3
|
+
interface Props {
|
|
21
4
|
/**
|
|
22
5
|
* Enables foveated rendering. Default is `1`, the three.js default.
|
|
23
6
|
*
|
|
@@ -40,12 +23,31 @@ declare const Xr: import("svelte").Component<{
|
|
|
40
23
|
fallback?: Snippet;
|
|
41
24
|
children?: Snippet;
|
|
42
25
|
/** Called as an XRSession is requested */
|
|
43
|
-
onsessionstart?: (event: XRSessionEvent<
|
|
26
|
+
onsessionstart?: (event: XRSessionEvent<'sessionstart'>) => void;
|
|
44
27
|
/** Called after an XRSession is terminated */
|
|
45
|
-
onsessionend?: (event: XRSessionEvent<
|
|
28
|
+
onsessionend?: (event: XRSessionEvent<'sessionend'>) => void;
|
|
46
29
|
/** Called when an XRSession is hidden or unfocused. */
|
|
47
30
|
onvisibilitychange?: (event: globalThis.XRSessionEvent) => void;
|
|
48
31
|
/** Called when available inputsources change */
|
|
49
32
|
oninputsourceschange?: (event: globalThis.XRSessionEvent) => void;
|
|
50
|
-
}
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* `<XR />` is a WebXR manager that configures your scene for XR rendering and interaction.
|
|
36
|
+
*
|
|
37
|
+
* This should be placed within a Threlte `<Canvas />`.
|
|
38
|
+
*
|
|
39
|
+
* ```svelte
|
|
40
|
+
* <XR
|
|
41
|
+
* foveation={1}
|
|
42
|
+
* frameRate={90}
|
|
43
|
+
* referenceSpace='local-floor'
|
|
44
|
+
* onsessionstart={(event: XREvent<XRManagerEvent>) => {}}
|
|
45
|
+
* onsessionend={(event: XREvent<XRManagerEvent>) => {}}
|
|
46
|
+
* onvisibilitychange={(event: XREvent<XRSessionEvent>) => {}}
|
|
47
|
+
* oninputsourceschange={(event: XREvent<XRSessionEvent>) => {}}
|
|
48
|
+
* />
|
|
49
|
+
* ```
|
|
50
|
+
*/
|
|
51
|
+
declare const Xr: import("svelte").Component<Props, {}, "">;
|
|
52
|
+
type Xr = ReturnType<typeof Xr>;
|
|
51
53
|
export default Xr;
|
|
@@ -21,7 +21,7 @@ display info about your WebXR session. This is aliased by `ARButton` and
|
|
|
21
21
|
import type { HTMLButtonAttributes } from 'svelte/elements'
|
|
22
22
|
import { getXRSupportState } from '../lib/getXRSupportState'
|
|
23
23
|
import { toggleXRSession } from '../lib/toggleXRSession'
|
|
24
|
-
import {
|
|
24
|
+
import { isPresenting, xr } from '../internal/state.svelte'
|
|
25
25
|
import type { Snippet } from 'svelte'
|
|
26
26
|
|
|
27
27
|
type Props = HTMLButtonAttributes & {
|
|
@@ -57,7 +57,7 @@ display info about your WebXR session. This is aliased by `ARButton` and
|
|
|
57
57
|
type SupportState = 'unsupported' | 'insecure' | 'blocked' | 'supported'
|
|
58
58
|
|
|
59
59
|
const handleButtonClick = async (nativeEvent: MouseEvent, state: SupportState) => {
|
|
60
|
-
if (
|
|
60
|
+
if (!xr.current) {
|
|
61
61
|
throw new Error(
|
|
62
62
|
'The <XR> component was not created. This is required to start an XR session.'
|
|
63
63
|
)
|
|
@@ -75,7 +75,7 @@ display info about your WebXR session. This is aliased by `ARButton` and
|
|
|
75
75
|
}
|
|
76
76
|
}
|
|
77
77
|
|
|
78
|
-
|
|
78
|
+
const modeText = $derived(
|
|
79
79
|
{
|
|
80
80
|
'immersive-vr': 'VR',
|
|
81
81
|
'immersive-ar': 'AR',
|
|
@@ -83,7 +83,7 @@ display info about your WebXR session. This is aliased by `ARButton` and
|
|
|
83
83
|
}[mode]
|
|
84
84
|
)
|
|
85
85
|
|
|
86
|
-
|
|
86
|
+
const style = $derived(
|
|
87
87
|
styled
|
|
88
88
|
? `
|
|
89
89
|
position: absolute;
|
|
@@ -111,7 +111,7 @@ display info about your WebXR session. This is aliased by `ARButton` and
|
|
|
111
111
|
{style}
|
|
112
112
|
>
|
|
113
113
|
{#if children}
|
|
114
|
-
{@render children
|
|
114
|
+
{@render children({ state })}
|
|
115
115
|
{:else if state === 'unsupported'}
|
|
116
116
|
{modeText} unsupported
|
|
117
117
|
{:else if state === 'insecure'}
|
|
@@ -119,7 +119,7 @@ display info about your WebXR session. This is aliased by `ARButton` and
|
|
|
119
119
|
{:else if state === 'blocked'}
|
|
120
120
|
{modeText} blocked
|
|
121
121
|
{:else if state === 'supported'}
|
|
122
|
-
{
|
|
122
|
+
{isPresenting.current ? 'Exit' : 'Enter'} {modeText}
|
|
123
123
|
{/if}
|
|
124
124
|
</button>
|
|
125
125
|
{/await}
|
|
@@ -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;
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
thickness?: number
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
const { color = new Color('white'), size = 0.03, thickness = 0.035 }: Props = $props()
|
|
12
12
|
|
|
13
13
|
const vertexShader = `
|
|
14
14
|
uniform mat4 projectionMatrix;
|
|
@@ -52,6 +52,7 @@
|
|
|
52
52
|
$effect.pre(() => {
|
|
53
53
|
uniforms.thickness.value = thickness
|
|
54
54
|
})
|
|
55
|
+
|
|
55
56
|
$effect.pre(() => {
|
|
56
57
|
uniforms.color.value = color
|
|
57
58
|
})
|
|
@@ -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;
|
|
@@ -1,7 +1,17 @@
|
|
|
1
|
-
<script
|
|
1
|
+
<script
|
|
2
|
+
module
|
|
3
|
+
lang="ts"
|
|
4
|
+
>
|
|
2
5
|
import { Group, Vector3, Matrix3 } from 'three'
|
|
3
|
-
|
|
4
|
-
|
|
6
|
+
|
|
7
|
+
const vec3 = new Vector3()
|
|
8
|
+
const normalMatrix = new Matrix3()
|
|
9
|
+
const worldNormal = new Vector3()
|
|
10
|
+
</script>
|
|
11
|
+
|
|
12
|
+
<script lang="ts">
|
|
13
|
+
import { T, useTask, useThrelte } from '@threlte/core'
|
|
14
|
+
import { pointerIntersection, pointerState } from '../../internal/state.svelte'
|
|
5
15
|
import Cursor from './Cursor.svelte'
|
|
6
16
|
import type { Snippet } from 'svelte'
|
|
7
17
|
|
|
@@ -10,27 +20,30 @@
|
|
|
10
20
|
children?: Snippet
|
|
11
21
|
}
|
|
12
22
|
|
|
13
|
-
|
|
23
|
+
const { handedness, children }: Props = $props()
|
|
14
24
|
|
|
15
|
-
const
|
|
16
|
-
const
|
|
17
|
-
const
|
|
18
|
-
const worldNormal = new Vector3()
|
|
25
|
+
const { scene } = useThrelte()
|
|
26
|
+
const hovering = $derived(pointerState[handedness].hovering)
|
|
27
|
+
const intersection = $derived(pointerIntersection[handedness])
|
|
19
28
|
|
|
20
|
-
|
|
21
|
-
let intersection = $derived(pointerIntersection[handedness])
|
|
29
|
+
const ref = new Group()
|
|
22
30
|
|
|
23
31
|
const { start, stop } = useTask(
|
|
24
32
|
() => {
|
|
25
|
-
if (intersection
|
|
26
|
-
|
|
33
|
+
if (intersection === undefined) {
|
|
34
|
+
return
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
const { point, face, object } = intersection
|
|
27
38
|
ref.position.lerp(point, 0.4)
|
|
28
39
|
|
|
29
|
-
if (face) {
|
|
30
|
-
|
|
31
|
-
worldNormal.copy(face.normal).applyMatrix3(normalMatrix).normalize()
|
|
32
|
-
ref.lookAt(vec3.addVectors(point, worldNormal))
|
|
40
|
+
if (face === null || face === undefined) {
|
|
41
|
+
return
|
|
33
42
|
}
|
|
43
|
+
|
|
44
|
+
normalMatrix.getNormalMatrix(object.matrixWorld)
|
|
45
|
+
worldNormal.copy(face.normal).applyMatrix3(normalMatrix).normalize()
|
|
46
|
+
ref.lookAt(vec3.addVectors(point, worldNormal))
|
|
34
47
|
},
|
|
35
48
|
{
|
|
36
49
|
autoStart: false
|
|
@@ -38,8 +51,8 @@
|
|
|
38
51
|
)
|
|
39
52
|
|
|
40
53
|
$effect.pre(() => {
|
|
41
|
-
if (hovering) {
|
|
42
|
-
ref.position.copy(intersection.
|
|
54
|
+
if (hovering && intersection) {
|
|
55
|
+
ref.position.copy(intersection.point)
|
|
43
56
|
start()
|
|
44
57
|
} else {
|
|
45
58
|
stop()
|
|
@@ -49,6 +62,7 @@
|
|
|
49
62
|
|
|
50
63
|
<T
|
|
51
64
|
is={ref}
|
|
65
|
+
attach={scene}
|
|
52
66
|
visible={hovering}
|
|
53
67
|
>
|
|
54
68
|
{#if 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 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 {
|
|
@@ -8,12 +8,12 @@
|
|
|
8
8
|
children?: Snippet
|
|
9
9
|
}
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
const { handedness, children }: Props = $props()
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
13
|
+
const hovering = $derived(teleportState[handedness].hovering)
|
|
14
|
+
const intersection = $derived(teleportIntersection[handedness])
|
|
15
|
+
const visible = $derived(
|
|
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;
|
|
@@ -1,8 +1,18 @@
|
|
|
1
|
-
<script
|
|
2
|
-
|
|
1
|
+
<script
|
|
2
|
+
module
|
|
3
|
+
lang="ts"
|
|
4
|
+
>
|
|
3
5
|
import { Group, Matrix3, Vector3 } from 'three'
|
|
4
|
-
|
|
5
|
-
|
|
6
|
+
|
|
7
|
+
const vec3 = new Vector3()
|
|
8
|
+
const normalMatrix = new Matrix3()
|
|
9
|
+
const worldNormal = new Vector3()
|
|
10
|
+
</script>
|
|
11
|
+
|
|
12
|
+
<script lang="ts">
|
|
13
|
+
import { Spring } from 'svelte/motion'
|
|
14
|
+
import { T, useTask, useThrelte } from '@threlte/core'
|
|
15
|
+
import { teleportIntersection } from '../../internal/state.svelte'
|
|
6
16
|
import Cursor from './Cursor.svelte'
|
|
7
17
|
import type { Snippet } from 'svelte'
|
|
8
18
|
|
|
@@ -11,20 +21,20 @@
|
|
|
11
21
|
children?: Snippet
|
|
12
22
|
}
|
|
13
23
|
|
|
14
|
-
|
|
24
|
+
const { handedness, children }: Props = $props()
|
|
15
25
|
|
|
16
|
-
const
|
|
17
|
-
const
|
|
18
|
-
const normalMatrix = new Matrix3()
|
|
19
|
-
const worldNormal = new Vector3()
|
|
26
|
+
const { scene } = useThrelte()
|
|
27
|
+
const intersection = $derived(teleportIntersection[handedness])
|
|
20
28
|
|
|
21
|
-
|
|
29
|
+
const ref = new Group()
|
|
22
30
|
|
|
23
31
|
const { start, stop } = useTask(
|
|
24
32
|
() => {
|
|
25
|
-
if (intersection
|
|
33
|
+
if (intersection === undefined) {
|
|
34
|
+
return
|
|
35
|
+
}
|
|
26
36
|
|
|
27
|
-
const { point, face, object } = intersection
|
|
37
|
+
const { point, face, object } = intersection
|
|
28
38
|
ref.position.lerp(point, 0.4)
|
|
29
39
|
|
|
30
40
|
if (face) {
|
|
@@ -38,15 +48,15 @@
|
|
|
38
48
|
}
|
|
39
49
|
)
|
|
40
50
|
|
|
41
|
-
const size =
|
|
51
|
+
const size = new Spring(0.1, { stiffness: 0.2 })
|
|
42
52
|
|
|
43
53
|
$effect.pre(() => {
|
|
44
|
-
if (
|
|
54
|
+
if (intersection === undefined) {
|
|
45
55
|
size.set(0.1)
|
|
46
56
|
stop()
|
|
47
57
|
} else {
|
|
48
58
|
size.set(1)
|
|
49
|
-
ref.position.copy(
|
|
59
|
+
ref.position.copy(intersection.point)
|
|
50
60
|
start()
|
|
51
61
|
}
|
|
52
62
|
})
|
|
@@ -54,13 +64,14 @@
|
|
|
54
64
|
|
|
55
65
|
<T
|
|
56
66
|
is={ref}
|
|
57
|
-
|
|
67
|
+
attach={scene}
|
|
68
|
+
visible={intersection !== undefined}
|
|
58
69
|
>
|
|
59
70
|
{#if children}
|
|
60
71
|
{@render children()}
|
|
61
72
|
{:else}
|
|
62
73
|
<Cursor
|
|
63
|
-
size={
|
|
74
|
+
size={size.current}
|
|
64
75
|
thickness={0.015}
|
|
65
76
|
/>
|
|
66
77
|
{/if}
|
|
@@ -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;
|
|
@@ -1,11 +1,24 @@
|
|
|
1
|
-
<script
|
|
1
|
+
<script
|
|
2
|
+
module
|
|
3
|
+
lang="ts"
|
|
4
|
+
>
|
|
2
5
|
import { Vector3, QuadraticBezierCurve3, type XRTargetRaySpace, Vector2 } from 'three'
|
|
6
|
+
|
|
7
|
+
const rayStart = new Vector3()
|
|
8
|
+
const rayMidpoint = new Vector3()
|
|
9
|
+
const curve = new QuadraticBezierCurve3()
|
|
10
|
+
const vec3 = new Vector3()
|
|
11
|
+
const v2_1 = new Vector2()
|
|
12
|
+
const v2_2 = new Vector2()
|
|
13
|
+
</script>
|
|
14
|
+
|
|
15
|
+
<script lang="ts">
|
|
16
|
+
import type { Snippet } from 'svelte'
|
|
3
17
|
import { Line2 } from 'three/examples/jsm/lines/Line2.js'
|
|
4
18
|
import { LineGeometry } from 'three/examples/jsm/lines/LineGeometry.js'
|
|
5
19
|
import { LineMaterial } from 'three/examples/jsm/lines/LineMaterial.js'
|
|
6
|
-
import { T, useTask } from '@threlte/core'
|
|
7
|
-
import { teleportIntersection } from '../../internal/
|
|
8
|
-
import type { Snippet } from 'svelte'
|
|
20
|
+
import { T, useTask, useThrelte } from '@threlte/core'
|
|
21
|
+
import { teleportIntersection } from '../../internal/state.svelte'
|
|
9
22
|
|
|
10
23
|
interface Props {
|
|
11
24
|
handedness: 'left' | 'right'
|
|
@@ -13,26 +26,18 @@
|
|
|
13
26
|
children?: Snippet
|
|
14
27
|
}
|
|
15
28
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
let lineGeometry = new LineGeometry()
|
|
29
|
+
const { handedness, targetRay, children }: Props = $props()
|
|
19
30
|
|
|
20
|
-
const
|
|
21
|
-
const rayMidpoint = new Vector3()
|
|
22
|
-
const curve = new QuadraticBezierCurve3()
|
|
31
|
+
const { scene } = useThrelte()
|
|
23
32
|
const rayDivisions = 40
|
|
24
33
|
const positions = new Float32Array(rayDivisions * 3)
|
|
25
|
-
const
|
|
26
|
-
|
|
27
|
-
const v2_1 = new Vector2()
|
|
28
|
-
const v2_2 = new Vector2()
|
|
29
|
-
|
|
30
|
-
let intersection = $derived(teleportIntersection[handedness])
|
|
34
|
+
const lineGeometry = new LineGeometry()
|
|
35
|
+
const intersection = $derived(teleportIntersection[handedness])
|
|
31
36
|
|
|
32
37
|
const setCurvePoints = (alpha = 0.3) => {
|
|
33
|
-
if (intersection
|
|
38
|
+
if (intersection === undefined) return
|
|
34
39
|
|
|
35
|
-
const rayEnd = intersection.
|
|
40
|
+
const rayEnd = intersection.point
|
|
36
41
|
targetRay.getWorldPosition(rayStart)
|
|
37
42
|
|
|
38
43
|
rayMidpoint.x = (rayStart.x + rayEnd.x) / 2
|
|
@@ -69,7 +74,7 @@
|
|
|
69
74
|
)
|
|
70
75
|
|
|
71
76
|
$effect.pre(() => {
|
|
72
|
-
if (
|
|
77
|
+
if (intersection === undefined) {
|
|
73
78
|
stop()
|
|
74
79
|
} else {
|
|
75
80
|
setCurvePoints(1)
|
|
@@ -83,7 +88,8 @@
|
|
|
83
88
|
{:else}
|
|
84
89
|
<T
|
|
85
90
|
is={Line2}
|
|
86
|
-
|
|
91
|
+
attach={scene}
|
|
92
|
+
visible={intersection !== undefined}
|
|
87
93
|
position.z={-0.01}
|
|
88
94
|
>
|
|
89
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 { XRHand } from '../types';
|
|
2
|
+
import { type CurrentReadable } from './currentReadable.svelte';
|
|
3
|
+
declare class Hands {
|
|
4
|
+
left: XRHand | undefined;
|
|
5
|
+
right: XRHand | 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 | XRHand>;
|
|
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>;
|