@threlte/xr 1.0.0-next.8 → 1.0.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/README.md +1 -8
- package/dist/components/ARButton.svelte +10 -3
- package/dist/components/ARButton.svelte.d.ts +8 -38
- package/dist/components/Controller.svelte +86 -46
- package/dist/components/Controller.svelte.d.ts +25 -37
- package/dist/components/Hand.svelte +109 -60
- package/dist/components/Hand.svelte.d.ts +21 -33
- package/dist/components/Headset.svelte +6 -4
- package/dist/components/Headset.svelte.d.ts +18 -16
- package/dist/components/VRButton.svelte +8 -3
- package/dist/components/VRButton.svelte.d.ts +2 -32
- package/dist/components/XR.svelte +156 -96
- package/dist/components/XR.svelte.d.ts +32 -45
- package/dist/components/XRButton.svelte +71 -38
- package/dist/components/XRButton.svelte.d.ts +26 -39
- package/dist/components/internal/Cursor.svelte +38 -25
- package/dist/components/internal/Cursor.svelte.d.ts +6 -18
- package/dist/components/internal/PointerCursor.svelte +46 -34
- package/dist/components/internal/PointerCursor.svelte.d.ts +5 -17
- package/dist/components/internal/ScenePortal.svelte +15 -12
- package/dist/components/internal/ScenePortal.svelte.d.ts +18 -16
- package/dist/components/internal/ShortRay.svelte +23 -12
- package/dist/components/internal/ShortRay.svelte.d.ts +5 -17
- package/dist/components/internal/TeleportCursor.svelte +51 -37
- package/dist/components/internal/TeleportCursor.svelte.d.ts +5 -17
- package/dist/components/internal/TeleportRay.svelte +77 -54
- package/dist/components/internal/TeleportRay.svelte.d.ts +6 -18
- package/dist/hooks/useController.d.ts +0 -1
- package/dist/hooks/useHand.d.ts +1 -1
- package/dist/hooks/useHandJoint.d.ts +1 -1
- package/dist/hooks/useHitTest.d.ts +0 -1
- package/dist/hooks/useXR.d.ts +0 -1
- package/dist/internal/stores.d.ts +0 -1
- package/dist/lib/getXRSessionOptions.d.ts +0 -1
- package/dist/lib/getXRSupportState.d.ts +1 -2
- package/dist/lib/toggleXRSession.d.ts +1 -2
- package/dist/plugins/pointerControls/context.d.ts +2 -2
- package/dist/plugins/pointerControls/index.d.ts +1 -1
- package/dist/plugins/pointerControls/index.js +1 -1
- package/dist/plugins/pointerControls/plugin.svelte.js +23 -0
- package/dist/plugins/teleportControls/context.d.ts +3 -3
- package/dist/plugins/teleportControls/index.d.ts +1 -1
- package/dist/plugins/teleportControls/index.js +1 -1
- package/dist/plugins/teleportControls/plugin.svelte.js +73 -0
- package/dist/types.d.ts +0 -1
- package/package.json +12 -12
- package/dist/plugins/pointerControls/plugin.js +0 -26
- package/dist/plugins/teleportControls/plugin.js +0 -54
- /package/dist/plugins/pointerControls/{plugin.d.ts → plugin.svelte.d.ts} +0 -0
- /package/dist/plugins/teleportControls/{plugin.d.ts → plugin.svelte.d.ts} +0 -0
|
@@ -17,104 +17,164 @@ This should be placed within a Threlte `<Canvas />`.
|
|
|
17
17
|
```
|
|
18
18
|
|
|
19
19
|
-->
|
|
20
|
-
<script lang="ts">
|
|
21
|
-
import {
|
|
22
|
-
import {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
import {
|
|
32
|
-
import {
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
try {
|
|
74
|
-
$session?.updateTargetFrameRate(frameRate2);
|
|
75
|
-
} catch {
|
|
20
|
+
<script lang="ts">
|
|
21
|
+
import { onMount, type Snippet } from 'svelte'
|
|
22
|
+
import { useThrelte, watch } from '@threlte/core'
|
|
23
|
+
import type { XRSessionEvent } from '../types'
|
|
24
|
+
import {
|
|
25
|
+
isHandTracking,
|
|
26
|
+
isPresenting,
|
|
27
|
+
referenceSpaceType,
|
|
28
|
+
session,
|
|
29
|
+
xr as xrStore
|
|
30
|
+
} from '../internal/stores'
|
|
31
|
+
import { setupRaf } from '../internal/setupRaf'
|
|
32
|
+
import { setupHeadset } from '../internal/setupHeadset'
|
|
33
|
+
import { setupControllers } from '../internal/setupControllers'
|
|
34
|
+
import { setupHands } from '../internal/setupHands'
|
|
35
|
+
|
|
36
|
+
interface Props {
|
|
37
|
+
/**
|
|
38
|
+
* Enables foveated rendering. Default is `1`, the three.js default.
|
|
39
|
+
*
|
|
40
|
+
* 0 = no foveation, full resolution
|
|
41
|
+
*
|
|
42
|
+
* 1 = maximum foveation, the edges render at lower resolution
|
|
43
|
+
*/
|
|
44
|
+
foveation?: number
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* The target framerate for the XRSystem. Smaller rates give more CPU headroom at the cost of responsiveness.
|
|
48
|
+
* Recommended range is `72`-`120`. Default is unset and left to the device.
|
|
49
|
+
* @note If your experience cannot effectively reach the target framerate, it will be subject to frame reprojection
|
|
50
|
+
* which will halve the effective framerate. Choose a conservative estimate that balances responsiveness and
|
|
51
|
+
* headroom based on your experience.
|
|
52
|
+
* @see https://developer.mozilla.org/en-US/docs/Web/API/WebXR_Device_API/Rendering#refresh_rate_and_frame_rate
|
|
53
|
+
*/
|
|
54
|
+
frameRate?: number | undefined
|
|
55
|
+
|
|
56
|
+
/** Type of WebXR reference space to use. Default is `local-floor` */
|
|
57
|
+
referenceSpace?: XRReferenceSpaceType
|
|
58
|
+
|
|
59
|
+
fallback?: Snippet
|
|
60
|
+
children?: Snippet
|
|
61
|
+
|
|
62
|
+
/** Called as an XRSession is requested */
|
|
63
|
+
onsessionstart?: (event: XRSessionEvent<'sessionstart'>) => void
|
|
64
|
+
|
|
65
|
+
/** Called after an XRSession is terminated */
|
|
66
|
+
onsessionend?: (event: XRSessionEvent<'sessionend'>) => void
|
|
67
|
+
|
|
68
|
+
/** Called when an XRSession is hidden or unfocused. */
|
|
69
|
+
onvisibilitychange?: (event: globalThis.XRSessionEvent) => void
|
|
70
|
+
|
|
71
|
+
/** Called when available inputsources change */
|
|
72
|
+
oninputsourceschange?: (event: globalThis.XRSessionEvent) => void
|
|
76
73
|
}
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
}
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
74
|
+
|
|
75
|
+
let {
|
|
76
|
+
foveation = 1,
|
|
77
|
+
frameRate,
|
|
78
|
+
referenceSpace = 'local-floor',
|
|
79
|
+
onsessionstart,
|
|
80
|
+
onsessionend,
|
|
81
|
+
onvisibilitychange,
|
|
82
|
+
oninputsourceschange,
|
|
83
|
+
fallback,
|
|
84
|
+
children
|
|
85
|
+
}: Props = $props()
|
|
86
|
+
|
|
87
|
+
const { renderer, renderMode } = useThrelte()
|
|
88
|
+
const { xr } = renderer
|
|
89
|
+
|
|
90
|
+
let originalRenderMode = $renderMode
|
|
91
|
+
|
|
92
|
+
setupRaf()
|
|
93
|
+
setupHeadset()
|
|
94
|
+
setupControllers()
|
|
95
|
+
setupHands()
|
|
96
|
+
|
|
97
|
+
const handleSessionStart = () => {
|
|
98
|
+
isPresenting.set(true)
|
|
99
|
+
onsessionstart?.({ type: 'sessionstart', target: $session! })
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
const handleSessionEnd = () => {
|
|
103
|
+
onsessionend?.({ type: 'sessionend', target: $session! })
|
|
104
|
+
isPresenting.set(false)
|
|
105
|
+
session.set(undefined)
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
const handleVisibilityChange = (event: globalThis.XRSessionEvent) => {
|
|
109
|
+
onvisibilitychange?.({ ...event, target: $session! })
|
|
98
110
|
}
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
$
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
}
|
|
111
|
+
|
|
112
|
+
const handleInputSourcesChange = (event: XRInputSourceChangeEvent) => {
|
|
113
|
+
$isHandTracking = Object.values(event.session.inputSources).some((source) => source.hand)
|
|
114
|
+
oninputsourceschange?.({ ...event, target: $session! })
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
const handleFramerateChange = (event: globalThis.XRSessionEvent) => {
|
|
118
|
+
onvisibilitychange?.({ ...event, target: $session! })
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
const updateTargetFrameRate = (frameRate?: number) => {
|
|
122
|
+
if (frameRate === undefined) return
|
|
123
|
+
|
|
124
|
+
try {
|
|
125
|
+
$session?.updateTargetFrameRate(frameRate)
|
|
126
|
+
} catch {
|
|
127
|
+
// Do nothing
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
watch(session, (currentSession) => {
|
|
132
|
+
if (currentSession === undefined) return
|
|
133
|
+
|
|
134
|
+
currentSession.addEventListener('visibilitychange', handleVisibilityChange)
|
|
135
|
+
currentSession.addEventListener('inputsourceschange', handleInputSourcesChange)
|
|
136
|
+
currentSession.addEventListener('frameratechange', handleFramerateChange)
|
|
137
|
+
|
|
138
|
+
xr.setFoveation(foveation)
|
|
139
|
+
|
|
140
|
+
updateTargetFrameRate(frameRate)
|
|
141
|
+
|
|
142
|
+
return () => {
|
|
143
|
+
currentSession.removeEventListener('visibilitychange', handleVisibilityChange)
|
|
144
|
+
currentSession.removeEventListener('inputsourceschange', handleInputSourcesChange)
|
|
145
|
+
currentSession.removeEventListener('frameratechange', handleFramerateChange)
|
|
146
|
+
}
|
|
147
|
+
})
|
|
148
|
+
|
|
149
|
+
watch(isPresenting, (presenting) => {
|
|
150
|
+
if (presenting) {
|
|
151
|
+
originalRenderMode = renderMode.current
|
|
152
|
+
renderMode.set('always')
|
|
153
|
+
} else {
|
|
154
|
+
renderMode.set(originalRenderMode)
|
|
155
|
+
}
|
|
156
|
+
})
|
|
157
|
+
|
|
158
|
+
onMount(() => {
|
|
159
|
+
$xrStore = xr
|
|
160
|
+
xr.enabled = true
|
|
161
|
+
xr.addEventListener('sessionstart', handleSessionStart)
|
|
162
|
+
xr.addEventListener('sessionend', handleSessionEnd)
|
|
163
|
+
|
|
164
|
+
return () => {
|
|
165
|
+
$xrStore = undefined
|
|
166
|
+
xr.enabled = false
|
|
167
|
+
xr.removeEventListener('sessionstart', handleSessionStart)
|
|
168
|
+
xr.removeEventListener('sessionend', handleSessionEnd)
|
|
169
|
+
}
|
|
170
|
+
})
|
|
171
|
+
|
|
172
|
+
$effect.pre(() => updateTargetFrameRate(frameRate))
|
|
173
|
+
$effect.pre(() => xr.setFoveation(foveation))
|
|
174
|
+
$effect.pre(() => {
|
|
175
|
+
xr.setReferenceSpaceType(referenceSpace)
|
|
176
|
+
$referenceSpaceType = referenceSpace
|
|
177
|
+
})
|
|
118
178
|
</script>
|
|
119
179
|
|
|
120
180
|
{#if $isPresenting}
|
|
@@ -1,47 +1,5 @@
|
|
|
1
|
-
/// <reference types="webxr" />
|
|
2
|
-
import { SvelteComponent } from "svelte";
|
|
3
1
|
import { type Snippet } from 'svelte';
|
|
4
2
|
import type { XRSessionEvent } from '../types';
|
|
5
|
-
declare const __propDef: {
|
|
6
|
-
props: {
|
|
7
|
-
/**
|
|
8
|
-
* Enables foveated rendering. Default is `1`, the three.js default.
|
|
9
|
-
*
|
|
10
|
-
* 0 = no foveation, full resolution
|
|
11
|
-
*
|
|
12
|
-
* 1 = maximum foveation, the edges render at lower resolution
|
|
13
|
-
*/
|
|
14
|
-
foveation?: number | undefined;
|
|
15
|
-
/**
|
|
16
|
-
* The target framerate for the XRSystem. Smaller rates give more CPU headroom at the cost of responsiveness.
|
|
17
|
-
* Recommended range is `72`-`120`. Default is unset and left to the device.
|
|
18
|
-
* @note If your experience cannot effectively reach the target framerate, it will be subject to frame reprojection
|
|
19
|
-
* which will halve the effective framerate. Choose a conservative estimate that balances responsiveness and
|
|
20
|
-
* headroom based on your experience.
|
|
21
|
-
* @see https://developer.mozilla.org/en-US/docs/Web/API/WebXR_Device_API/Rendering#refresh_rate_and_frame_rate
|
|
22
|
-
*/
|
|
23
|
-
frameRate?: number | undefined;
|
|
24
|
-
/** Type of WebXR reference space to use. Default is `local-floor` */
|
|
25
|
-
referenceSpace?: XRReferenceSpaceType | undefined;
|
|
26
|
-
fallback?: Snippet<[]> | undefined;
|
|
27
|
-
children?: Snippet<[]> | undefined;
|
|
28
|
-
/** Called as an XRSession is requested */
|
|
29
|
-
onsessionstart?: ((event: XRSessionEvent<'sessionstart'>) => void) | undefined;
|
|
30
|
-
/** Called after an XRSession is terminated */
|
|
31
|
-
onsessionend?: ((event: XRSessionEvent<'sessionend'>) => void) | undefined;
|
|
32
|
-
/** Called when an XRSession is hidden or unfocused. */
|
|
33
|
-
onvisibilitychange?: ((event: globalThis.XRSessionEvent) => void) | undefined;
|
|
34
|
-
/** Called when available inputsources change */
|
|
35
|
-
oninputsourceschange?: ((event: globalThis.XRSessionEvent) => void) | undefined;
|
|
36
|
-
};
|
|
37
|
-
events: {
|
|
38
|
-
[evt: string]: CustomEvent<any>;
|
|
39
|
-
};
|
|
40
|
-
slots: {};
|
|
41
|
-
};
|
|
42
|
-
export type XrProps = typeof __propDef.props;
|
|
43
|
-
export type XrEvents = typeof __propDef.events;
|
|
44
|
-
export type XrSlots = typeof __propDef.slots;
|
|
45
3
|
/**
|
|
46
4
|
* `<XR />` is a WebXR manager that configures your scene for XR rendering and interaction.
|
|
47
5
|
*
|
|
@@ -59,6 +17,35 @@ export type XrSlots = typeof __propDef.slots;
|
|
|
59
17
|
* />
|
|
60
18
|
* ```
|
|
61
19
|
*/
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
20
|
+
declare const Xr: import("svelte").Component<{
|
|
21
|
+
/**
|
|
22
|
+
* Enables foveated rendering. Default is `1`, the three.js default.
|
|
23
|
+
*
|
|
24
|
+
* 0 = no foveation, full resolution
|
|
25
|
+
*
|
|
26
|
+
* 1 = maximum foveation, the edges render at lower resolution
|
|
27
|
+
*/
|
|
28
|
+
foveation?: number;
|
|
29
|
+
/**
|
|
30
|
+
* The target framerate for the XRSystem. Smaller rates give more CPU headroom at the cost of responsiveness.
|
|
31
|
+
* Recommended range is `72`-`120`. Default is unset and left to the device.
|
|
32
|
+
* @note If your experience cannot effectively reach the target framerate, it will be subject to frame reprojection
|
|
33
|
+
* which will halve the effective framerate. Choose a conservative estimate that balances responsiveness and
|
|
34
|
+
* headroom based on your experience.
|
|
35
|
+
* @see https://developer.mozilla.org/en-US/docs/Web/API/WebXR_Device_API/Rendering#refresh_rate_and_frame_rate
|
|
36
|
+
*/
|
|
37
|
+
frameRate?: number | undefined;
|
|
38
|
+
/** Type of WebXR reference space to use. Default is `local-floor` */
|
|
39
|
+
referenceSpace?: XRReferenceSpaceType;
|
|
40
|
+
fallback?: Snippet;
|
|
41
|
+
children?: Snippet;
|
|
42
|
+
/** Called as an XRSession is requested */
|
|
43
|
+
onsessionstart?: (event: XRSessionEvent<"sessionstart">) => void;
|
|
44
|
+
/** Called after an XRSession is terminated */
|
|
45
|
+
onsessionend?: (event: XRSessionEvent<"sessionend">) => void;
|
|
46
|
+
/** Called when an XRSession is hidden or unfocused. */
|
|
47
|
+
onvisibilitychange?: (event: globalThis.XRSessionEvent) => void;
|
|
48
|
+
/** Called when available inputsources change */
|
|
49
|
+
oninputsourceschange?: (event: globalThis.XRSessionEvent) => void;
|
|
50
|
+
}, {}, "">;
|
|
51
|
+
export default Xr;
|
|
@@ -17,43 +17,75 @@ display info about your WebXR session. This is aliased by `ARButton` and
|
|
|
17
17
|
/>
|
|
18
18
|
```
|
|
19
19
|
-->
|
|
20
|
-
<script lang="ts">
|
|
21
|
-
import {
|
|
22
|
-
import {
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
20
|
+
<script lang="ts">
|
|
21
|
+
import type { HTMLButtonAttributes } from 'svelte/elements'
|
|
22
|
+
import { getXRSupportState } from '../lib/getXRSupportState'
|
|
23
|
+
import { toggleXRSession } from '../lib/toggleXRSession'
|
|
24
|
+
import { session, xr } from '../internal/stores'
|
|
25
|
+
import type { Snippet } from 'svelte'
|
|
26
|
+
|
|
27
|
+
type Props = HTMLButtonAttributes & {
|
|
28
|
+
/** The type of `XRSession` to create */
|
|
29
|
+
mode: XRSessionMode
|
|
30
|
+
/**
|
|
31
|
+
* `XRSession` configuration options
|
|
32
|
+
* @see https://immersive-web.github.io/webxr/#feature-dependencies
|
|
33
|
+
*/
|
|
34
|
+
sessionInit?: XRSessionInit & { domOverlay?: { root: HTMLElement } | undefined }
|
|
35
|
+
/** Whether this button should only enter / exit an `XRSession`. Default is to toggle both ways */
|
|
36
|
+
force?: 'enter' | 'exit'
|
|
37
|
+
/** Whether to apply automatic styling to the button. Set false to apply custom styles. Default is true. */
|
|
38
|
+
styled?: boolean
|
|
39
|
+
|
|
40
|
+
children?: Snippet<[{ state: SupportState }]>
|
|
41
|
+
|
|
42
|
+
onclick?: (event: { state: SupportState; nativeEvent: MouseEvent }) => void
|
|
43
|
+
onerror?: (error: Error) => void
|
|
38
44
|
}
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
45
|
+
|
|
46
|
+
let {
|
|
47
|
+
mode,
|
|
48
|
+
sessionInit,
|
|
49
|
+
force,
|
|
50
|
+
styled = true,
|
|
51
|
+
onclick,
|
|
52
|
+
onerror,
|
|
53
|
+
children,
|
|
54
|
+
...props
|
|
55
|
+
}: Props = $props()
|
|
56
|
+
|
|
57
|
+
type SupportState = 'unsupported' | 'insecure' | 'blocked' | 'supported'
|
|
58
|
+
|
|
59
|
+
const handleButtonClick = async (nativeEvent: MouseEvent, state: SupportState) => {
|
|
60
|
+
if (!$xr) {
|
|
61
|
+
throw new Error(
|
|
62
|
+
'The <XR> component was not created. This is required to start an XR session.'
|
|
63
|
+
)
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
onclick?.({ state, nativeEvent })
|
|
67
|
+
|
|
68
|
+
if (state !== 'supported') return
|
|
69
|
+
|
|
70
|
+
try {
|
|
71
|
+
await toggleXRSession(mode, sessionInit, force)
|
|
72
|
+
} catch (error) {
|
|
73
|
+
/** This callback gets fired if XR initialization fails. */
|
|
74
|
+
onerror?.(error as Error)
|
|
75
|
+
}
|
|
46
76
|
}
|
|
47
|
-
|
|
48
|
-
let modeText = $derived(
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
)
|
|
55
|
-
|
|
56
|
-
|
|
77
|
+
|
|
78
|
+
let modeText = $derived(
|
|
79
|
+
{
|
|
80
|
+
'immersive-vr': 'VR',
|
|
81
|
+
'immersive-ar': 'AR',
|
|
82
|
+
inline: 'inline'
|
|
83
|
+
}[mode]
|
|
84
|
+
)
|
|
85
|
+
|
|
86
|
+
let style = $derived(
|
|
87
|
+
styled
|
|
88
|
+
? `
|
|
57
89
|
position: absolute;
|
|
58
90
|
bottom: 24px;
|
|
59
91
|
left: 50%;
|
|
@@ -64,9 +96,10 @@ let style = $derived(
|
|
|
64
96
|
color: white;
|
|
65
97
|
outline: none;
|
|
66
98
|
z-index: 10;
|
|
67
|
-
${props.style ??
|
|
68
|
-
`
|
|
69
|
-
|
|
99
|
+
${props.style ?? ''}
|
|
100
|
+
`
|
|
101
|
+
: props.style
|
|
102
|
+
)
|
|
70
103
|
</script>
|
|
71
104
|
|
|
72
105
|
{#await getXRSupportState(mode) then state}
|
|
@@ -1,41 +1,5 @@
|
|
|
1
|
-
/// <reference types="webxr" />
|
|
2
|
-
import { SvelteComponent } from "svelte";
|
|
3
1
|
import type { HTMLButtonAttributes } from 'svelte/elements';
|
|
4
2
|
import type { Snippet } from 'svelte';
|
|
5
|
-
declare const __propDef: {
|
|
6
|
-
props: HTMLButtonAttributes & {
|
|
7
|
-
/** The type of `XRSession` to create */
|
|
8
|
-
mode: XRSessionMode;
|
|
9
|
-
/**
|
|
10
|
-
* `XRSession` configuration options
|
|
11
|
-
* @see https://immersive-web.github.io/webxr/#feature-dependencies
|
|
12
|
-
*/
|
|
13
|
-
sessionInit?: (XRSessionInit & {
|
|
14
|
-
domOverlay?: {
|
|
15
|
-
root: HTMLElement;
|
|
16
|
-
} | undefined;
|
|
17
|
-
}) | undefined;
|
|
18
|
-
/** Whether this button should only enter / exit an `XRSession`. Default is to toggle both ways */
|
|
19
|
-
force?: "enter" | "exit" | undefined;
|
|
20
|
-
/** Whether to apply automatic styling to the button. Set false to apply custom styles. Default is true. */
|
|
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;
|
|
30
|
-
};
|
|
31
|
-
events: {
|
|
32
|
-
[evt: string]: CustomEvent<any>;
|
|
33
|
-
};
|
|
34
|
-
slots: {};
|
|
35
|
-
};
|
|
36
|
-
export type XrButtonProps = typeof __propDef.props;
|
|
37
|
-
export type XrButtonEvents = typeof __propDef.events;
|
|
38
|
-
export type XrButtonSlots = typeof __propDef.slots;
|
|
39
3
|
/**
|
|
40
4
|
* `<XRButton />` is an HTML `<button />` that can be used to init and
|
|
41
5
|
* display info about your WebXR session. This is aliased by `ARButton` and
|
|
@@ -54,6 +18,29 @@ export type XrButtonSlots = typeof __propDef.slots;
|
|
|
54
18
|
* />
|
|
55
19
|
* ```
|
|
56
20
|
*/
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
21
|
+
declare const XrButton: import("svelte").Component<HTMLButtonAttributes & {
|
|
22
|
+
/** The type of `XRSession` to create */
|
|
23
|
+
mode: XRSessionMode;
|
|
24
|
+
/**
|
|
25
|
+
* `XRSession` configuration options
|
|
26
|
+
* @see https://immersive-web.github.io/webxr/#feature-dependencies
|
|
27
|
+
*/
|
|
28
|
+
sessionInit?: XRSessionInit & {
|
|
29
|
+
domOverlay?: {
|
|
30
|
+
root: HTMLElement;
|
|
31
|
+
} | undefined;
|
|
32
|
+
};
|
|
33
|
+
/** Whether this button should only enter / exit an `XRSession`. Default is to toggle both ways */
|
|
34
|
+
force?: "enter" | "exit";
|
|
35
|
+
/** Whether to apply automatic styling to the button. Set false to apply custom styles. Default is true. */
|
|
36
|
+
styled?: boolean;
|
|
37
|
+
children?: Snippet<[{
|
|
38
|
+
state: "blocked" | "unsupported" | "insecure" | "supported";
|
|
39
|
+
}]>;
|
|
40
|
+
onclick?: (event: {
|
|
41
|
+
state: "blocked" | "unsupported" | "insecure" | "supported";
|
|
42
|
+
nativeEvent: MouseEvent;
|
|
43
|
+
}) => void;
|
|
44
|
+
onerror?: (error: Error) => void;
|
|
45
|
+
}, {}, "">;
|
|
46
|
+
export default XrButton;
|
|
@@ -1,7 +1,16 @@
|
|
|
1
|
-
<script lang="ts">
|
|
2
|
-
import {
|
|
3
|
-
|
|
4
|
-
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { Color, DoubleSide, RawShaderMaterial, type ColorRepresentation } from 'three'
|
|
3
|
+
import { T } from '@threlte/core'
|
|
4
|
+
|
|
5
|
+
interface Props {
|
|
6
|
+
color?: ColorRepresentation
|
|
7
|
+
size?: number
|
|
8
|
+
thickness?: number
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
let { color = new Color('white'), size = 0.03, thickness = 0.035 }: Props = $props()
|
|
12
|
+
|
|
13
|
+
const vertexShader = `
|
|
5
14
|
uniform mat4 projectionMatrix;
|
|
6
15
|
uniform mat4 modelViewMatrix;
|
|
7
16
|
attribute vec2 uv;
|
|
@@ -11,8 +20,9 @@ const vertexShader = `
|
|
|
11
20
|
vUv = uv;
|
|
12
21
|
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
|
|
13
22
|
}
|
|
14
|
-
|
|
15
|
-
|
|
23
|
+
`
|
|
24
|
+
|
|
25
|
+
const fragmentShader = `
|
|
16
26
|
precision mediump float;
|
|
17
27
|
uniform float thickness;
|
|
18
28
|
uniform vec3 color;
|
|
@@ -23,25 +33,28 @@ const fragmentShader = `
|
|
|
23
33
|
float alpha = 1.0 - step(thickness, abs(distance(vUv, vec2(0.5)) - 0.25));
|
|
24
34
|
gl_FragColor = vec4(color, alpha);
|
|
25
35
|
}
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
$effect.pre(() => {
|
|
43
|
-
|
|
44
|
-
})
|
|
36
|
+
`
|
|
37
|
+
|
|
38
|
+
const uniforms = {
|
|
39
|
+
thickness: { value: thickness },
|
|
40
|
+
color: { value: color }
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
const shaderMaterial = new RawShaderMaterial({
|
|
44
|
+
vertexShader,
|
|
45
|
+
fragmentShader,
|
|
46
|
+
uniforms,
|
|
47
|
+
side: DoubleSide,
|
|
48
|
+
transparent: true,
|
|
49
|
+
depthTest: false
|
|
50
|
+
})
|
|
51
|
+
|
|
52
|
+
$effect.pre(() => {
|
|
53
|
+
uniforms.thickness.value = thickness
|
|
54
|
+
})
|
|
55
|
+
$effect.pre(() => {
|
|
56
|
+
uniforms.color.value = color
|
|
57
|
+
})
|
|
45
58
|
</script>
|
|
46
59
|
|
|
47
60
|
<T.Mesh scale={size}>
|
|
@@ -1,19 +1,7 @@
|
|
|
1
|
-
import { SvelteComponent } from "svelte";
|
|
2
1
|
import { type ColorRepresentation } from 'three';
|
|
3
|
-
declare const
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
events: {
|
|
10
|
-
[evt: string]: CustomEvent<any>;
|
|
11
|
-
};
|
|
12
|
-
slots: {};
|
|
13
|
-
};
|
|
14
|
-
export type CursorProps = typeof __propDef.props;
|
|
15
|
-
export type CursorEvents = typeof __propDef.events;
|
|
16
|
-
export type CursorSlots = typeof __propDef.slots;
|
|
17
|
-
export default class Cursor extends SvelteComponent<CursorProps, CursorEvents, CursorSlots> {
|
|
18
|
-
}
|
|
19
|
-
export {};
|
|
2
|
+
declare const Cursor: import("svelte").Component<{
|
|
3
|
+
color?: ColorRepresentation;
|
|
4
|
+
size?: number;
|
|
5
|
+
thickness?: number;
|
|
6
|
+
}, {}, "">;
|
|
7
|
+
export default Cursor;
|