@threlte/xr 1.0.0-next.0 → 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 +9 -7
- package/dist/components/ARButton.svelte.d.ts +10 -2
- package/dist/components/Controller.svelte +56 -42
- package/dist/components/Controller.svelte.d.ts +13 -19
- package/dist/components/Hand.svelte +38 -16
- package/dist/components/Hand.svelte.d.ts +10 -19
- package/dist/components/Headset.svelte +1 -1
- package/dist/components/Headset.svelte.d.ts +3 -1
- package/dist/components/VRButton.svelte +5 -4
- package/dist/components/VRButton.svelte.d.ts +10 -2
- package/dist/components/XR.svelte +19 -14
- package/dist/components/XR.svelte.d.ts +15 -25
- package/dist/components/XRButton.svelte +19 -8
- package/dist/components/XRButton.svelte.d.ts +11 -2
- package/dist/components/internal/Cursor.svelte +13 -12
- package/dist/components/internal/PointerCursor.svelte +10 -9
- package/dist/components/internal/PointerCursor.svelte.d.ts +3 -3
- package/dist/components/internal/ScenePortal.svelte +15 -5
- package/dist/components/internal/ScenePortal.svelte.d.ts +3 -1
- package/dist/components/internal/ShortRay.svelte +29 -28
- package/dist/components/internal/ShortRay.svelte.d.ts +3 -3
- package/dist/components/internal/TeleportCursor.svelte +9 -7
- package/dist/components/internal/TeleportCursor.svelte.d.ts +3 -3
- package/dist/components/internal/TeleportRay.svelte +9 -8
- package/dist/components/internal/TeleportRay.svelte.d.ts +3 -3
- 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 +34 -14
- 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
|
@@ -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
|
*/
|
|
@@ -1,8 +1,6 @@
|
|
|
1
|
-
<script>import { Color, DoubleSide, RawShaderMaterial } from "three";
|
|
1
|
+
<script lang="ts">import { Color, DoubleSide, RawShaderMaterial } from "three";
|
|
2
2
|
import { T } from "@threlte/core";
|
|
3
|
-
|
|
4
|
-
export let size = 0.03;
|
|
5
|
-
export let thickness = 0.035;
|
|
3
|
+
let { color = new Color("white"), size = 0.03, thickness = 0.035 } = $props();
|
|
6
4
|
const vertexShader = `
|
|
7
5
|
uniform mat4 projectionMatrix;
|
|
8
6
|
uniform mat4 modelViewMatrix;
|
|
@@ -26,21 +24,24 @@ const fragmentShader = `
|
|
|
26
24
|
gl_FragColor = vec4(color, alpha);
|
|
27
25
|
}
|
|
28
26
|
`;
|
|
27
|
+
const uniforms = {
|
|
28
|
+
thickness: { value: thickness },
|
|
29
|
+
color: { value: color }
|
|
30
|
+
};
|
|
29
31
|
const shaderMaterial = new RawShaderMaterial({
|
|
30
32
|
vertexShader,
|
|
31
33
|
fragmentShader,
|
|
32
|
-
uniforms
|
|
33
|
-
thickness: { value: thickness },
|
|
34
|
-
color: { value: color }
|
|
35
|
-
},
|
|
34
|
+
uniforms,
|
|
36
35
|
side: DoubleSide,
|
|
37
36
|
transparent: true,
|
|
38
37
|
depthTest: false
|
|
39
38
|
});
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
39
|
+
$effect.pre(() => {
|
|
40
|
+
uniforms.thickness.value = thickness;
|
|
41
|
+
});
|
|
42
|
+
$effect.pre(() => {
|
|
43
|
+
uniforms.color.value = color;
|
|
44
|
+
});
|
|
44
45
|
</script>
|
|
45
46
|
|
|
46
47
|
<T.Mesh scale={size}>
|
|
@@ -1,16 +1,14 @@
|
|
|
1
|
-
<script>import { Group, Vector3, Matrix3 } from "three";
|
|
1
|
+
<script lang="ts">import { Group, Vector3, Matrix3 } from "three";
|
|
2
2
|
import { T, useTask } from "@threlte/core";
|
|
3
3
|
import { pointerIntersection, pointerState } from "../../internal/stores";
|
|
4
4
|
import Cursor from "./Cursor.svelte";
|
|
5
|
-
|
|
5
|
+
let { handedness, children } = $props();
|
|
6
6
|
const ref = new Group();
|
|
7
7
|
const vec3 = new Vector3();
|
|
8
8
|
const normalMatrix = new Matrix3();
|
|
9
9
|
const worldNormal = new Vector3();
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
$:
|
|
13
|
-
intersection = pointerIntersection[handedness];
|
|
10
|
+
let hovering = $derived($pointerState[handedness].hovering);
|
|
11
|
+
let intersection = $derived(pointerIntersection[handedness]);
|
|
14
12
|
const { start, stop } = useTask(
|
|
15
13
|
() => {
|
|
16
14
|
if (intersection.current === void 0)
|
|
@@ -27,20 +25,23 @@ const { start, stop } = useTask(
|
|
|
27
25
|
autoStart: false
|
|
28
26
|
}
|
|
29
27
|
);
|
|
30
|
-
|
|
28
|
+
$effect.pre(() => {
|
|
31
29
|
if (hovering) {
|
|
32
30
|
ref.position.copy(intersection.current.point);
|
|
33
31
|
start();
|
|
34
32
|
} else {
|
|
35
33
|
stop();
|
|
36
34
|
}
|
|
35
|
+
});
|
|
37
36
|
</script>
|
|
38
37
|
|
|
39
38
|
<T
|
|
40
39
|
is={ref}
|
|
41
40
|
visible={hovering}
|
|
42
41
|
>
|
|
43
|
-
|
|
42
|
+
{#if children}
|
|
43
|
+
{@render children()}
|
|
44
|
+
{:else}
|
|
44
45
|
<Cursor />
|
|
45
|
-
|
|
46
|
+
{/if}
|
|
46
47
|
</T>
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { SvelteComponent } from "svelte";
|
|
2
|
+
import type { Snippet } from 'svelte';
|
|
2
3
|
declare const __propDef: {
|
|
3
4
|
props: {
|
|
4
5
|
handedness: 'left' | 'right';
|
|
6
|
+
children?: Snippet<[]> | undefined;
|
|
5
7
|
};
|
|
6
8
|
events: {
|
|
7
9
|
[evt: string]: CustomEvent<any>;
|
|
8
10
|
};
|
|
9
|
-
slots: {
|
|
10
|
-
default: {};
|
|
11
|
-
};
|
|
11
|
+
slots: {};
|
|
12
12
|
};
|
|
13
13
|
export type PointerCursorProps = typeof __propDef.props;
|
|
14
14
|
export type PointerCursorEvents = typeof __propDef.events;
|
|
@@ -1,10 +1,20 @@
|
|
|
1
|
-
<script>import {
|
|
1
|
+
<script lang="ts">import { T, useThrelte } from "@threlte/core";
|
|
2
|
+
import { Object3D } from "three";
|
|
2
3
|
const { scene } = useThrelte();
|
|
4
|
+
const proxy = new Object3D();
|
|
5
|
+
proxy.add = (child) => {
|
|
6
|
+
scene.add(child);
|
|
7
|
+
return child;
|
|
8
|
+
};
|
|
9
|
+
proxy.remove = (child) => {
|
|
10
|
+
scene.remove(child);
|
|
11
|
+
return child;
|
|
12
|
+
};
|
|
3
13
|
</script>
|
|
4
14
|
|
|
5
|
-
<
|
|
6
|
-
|
|
7
|
-
|
|
15
|
+
<T
|
|
16
|
+
is={proxy}
|
|
17
|
+
attach={false}
|
|
8
18
|
>
|
|
9
19
|
<slot />
|
|
10
|
-
</
|
|
20
|
+
</T>
|
|
@@ -1,16 +1,33 @@
|
|
|
1
|
-
<script>import { T } from "@threlte/core";
|
|
1
|
+
<script lang="ts">import { T } from "@threlte/core";
|
|
2
2
|
import { pointerState, teleportState, teleportIntersection } from "../../internal/stores";
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
intersection
|
|
8
|
-
|
|
9
|
-
|
|
3
|
+
let { handedness, children } = $props();
|
|
4
|
+
let hovering = $derived($teleportState[handedness].hovering);
|
|
5
|
+
let intersection = $derived(teleportIntersection[handedness]);
|
|
6
|
+
let visible = $derived(
|
|
7
|
+
$pointerState[handedness].enabled || hovering && $intersection === void 0
|
|
8
|
+
);
|
|
9
|
+
const vertexShader = `
|
|
10
|
+
uniform mat4 modelViewMatrix;
|
|
11
|
+
uniform mat4 projectionMatrix;
|
|
12
|
+
attribute vec2 uv;
|
|
13
|
+
attribute vec3 position;
|
|
14
|
+
varying vec2 vUv;
|
|
15
|
+
void main() {
|
|
16
|
+
vUv = uv;
|
|
17
|
+
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
|
|
18
|
+
}`;
|
|
19
|
+
const fragmentShader = `
|
|
20
|
+
precision mediump float;
|
|
21
|
+
varying vec2 vUv;
|
|
22
|
+
void main() {
|
|
23
|
+
gl_FragColor = vec4(1.0, 1.0, 1.0, pow(vUv.y - 1.0, 2.0));
|
|
24
|
+
}`;
|
|
10
25
|
</script>
|
|
11
26
|
|
|
12
27
|
<T.Group {visible}>
|
|
13
|
-
|
|
28
|
+
{#if children}
|
|
29
|
+
{@render children()}
|
|
30
|
+
{:else}
|
|
14
31
|
<T.Mesh
|
|
15
32
|
rotation.x={-Math.PI / 2}
|
|
16
33
|
position.z={-0.1}
|
|
@@ -18,25 +35,9 @@ $:
|
|
|
18
35
|
<T.CylinderGeometry args={[0.002, 0.002, 0.2, 16, 1, false]} />
|
|
19
36
|
<T.RawShaderMaterial
|
|
20
37
|
transparent
|
|
21
|
-
vertexShader
|
|
22
|
-
|
|
23
|
-
uniform mat4 projectionMatrix;
|
|
24
|
-
attribute vec2 uv;
|
|
25
|
-
attribute vec3 position;
|
|
26
|
-
varying vec2 vUv;
|
|
27
|
-
void main() {
|
|
28
|
-
vUv = uv;
|
|
29
|
-
gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
|
|
30
|
-
}
|
|
31
|
-
`}
|
|
32
|
-
fragmentShader={`
|
|
33
|
-
precision mediump float;
|
|
34
|
-
varying vec2 vUv;
|
|
35
|
-
void main() {
|
|
36
|
-
gl_FragColor = vec4(1.0, 1.0, 1.0, pow(vUv.y - 1.0, 2.0));
|
|
37
|
-
}
|
|
38
|
-
`}
|
|
38
|
+
{vertexShader}
|
|
39
|
+
{fragmentShader}
|
|
39
40
|
/>
|
|
40
41
|
</T.Mesh>
|
|
41
|
-
|
|
42
|
+
{/if}
|
|
42
43
|
</T.Group>
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { SvelteComponent } from "svelte";
|
|
2
|
+
import type { Snippet } from 'svelte';
|
|
2
3
|
declare const __propDef: {
|
|
3
4
|
props: {
|
|
4
5
|
handedness: 'left' | 'right';
|
|
6
|
+
children?: Snippet<[]> | undefined;
|
|
5
7
|
};
|
|
6
8
|
events: {
|
|
7
9
|
[evt: string]: CustomEvent<any>;
|
|
8
10
|
};
|
|
9
|
-
slots: {
|
|
10
|
-
default: {};
|
|
11
|
-
};
|
|
11
|
+
slots: {};
|
|
12
12
|
};
|
|
13
13
|
export type ShortRayProps = typeof __propDef.props;
|
|
14
14
|
export type ShortRayEvents = typeof __propDef.events;
|
|
@@ -1,15 +1,14 @@
|
|
|
1
|
-
<script>import { spring } from "svelte/motion";
|
|
1
|
+
<script lang="ts">import { spring } from "svelte/motion";
|
|
2
2
|
import { Group, Matrix3, Vector3 } from "three";
|
|
3
3
|
import { T, useTask } from "@threlte/core";
|
|
4
4
|
import { teleportIntersection } from "../../internal/stores";
|
|
5
5
|
import Cursor from "./Cursor.svelte";
|
|
6
|
-
|
|
6
|
+
let { handedness, children } = $props();
|
|
7
7
|
const ref = new Group();
|
|
8
8
|
const vec3 = new Vector3();
|
|
9
9
|
const normalMatrix = new Matrix3();
|
|
10
10
|
const worldNormal = new Vector3();
|
|
11
|
-
|
|
12
|
-
intersection = teleportIntersection[handedness];
|
|
11
|
+
let intersection = $derived(teleportIntersection[handedness]);
|
|
13
12
|
const { start, stop } = useTask(
|
|
14
13
|
() => {
|
|
15
14
|
if (intersection.current === void 0)
|
|
@@ -27,7 +26,7 @@ const { start, stop } = useTask(
|
|
|
27
26
|
}
|
|
28
27
|
);
|
|
29
28
|
const size = spring(0.1, { stiffness: 0.2 });
|
|
30
|
-
|
|
29
|
+
$effect.pre(() => {
|
|
31
30
|
if ($intersection === void 0) {
|
|
32
31
|
size.set(0.1);
|
|
33
32
|
stop();
|
|
@@ -36,16 +35,19 @@ $:
|
|
|
36
35
|
ref.position.copy($intersection.point);
|
|
37
36
|
start();
|
|
38
37
|
}
|
|
38
|
+
});
|
|
39
39
|
</script>
|
|
40
40
|
|
|
41
41
|
<T
|
|
42
42
|
is={ref}
|
|
43
43
|
visible={$intersection !== undefined}
|
|
44
44
|
>
|
|
45
|
-
|
|
45
|
+
{#if children}
|
|
46
|
+
{@render children()}
|
|
47
|
+
{:else}
|
|
46
48
|
<Cursor
|
|
47
49
|
size={$size}
|
|
48
50
|
thickness={0.015}
|
|
49
51
|
/>
|
|
50
|
-
|
|
52
|
+
{/if}
|
|
51
53
|
</T>
|
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import { SvelteComponent } from "svelte";
|
|
2
|
+
import type { Snippet } from 'svelte';
|
|
2
3
|
declare const __propDef: {
|
|
3
4
|
props: {
|
|
4
5
|
handedness: 'left' | 'right';
|
|
6
|
+
children?: Snippet<[]> | undefined;
|
|
5
7
|
};
|
|
6
8
|
events: {
|
|
7
9
|
[evt: string]: CustomEvent<any>;
|
|
8
10
|
};
|
|
9
|
-
slots: {
|
|
10
|
-
default: {};
|
|
11
|
-
};
|
|
11
|
+
slots: {};
|
|
12
12
|
};
|
|
13
13
|
export type TeleportCursorProps = typeof __propDef.props;
|
|
14
14
|
export type TeleportCursorEvents = typeof __propDef.events;
|
|
@@ -1,11 +1,10 @@
|
|
|
1
|
-
<script>import { Vector3, QuadraticBezierCurve3, Vector2 } from "three";
|
|
1
|
+
<script lang="ts">import { Vector3, QuadraticBezierCurve3, Vector2 } from "three";
|
|
2
2
|
import { Line2 } from "three/examples/jsm/lines/Line2.js";
|
|
3
3
|
import { LineGeometry } from "three/examples/jsm/lines/LineGeometry.js";
|
|
4
4
|
import { LineMaterial } from "three/examples/jsm/lines/LineMaterial.js";
|
|
5
5
|
import { T, useTask } from "@threlte/core";
|
|
6
6
|
import { teleportIntersection } from "../../internal/stores";
|
|
7
|
-
|
|
8
|
-
export let targetRay;
|
|
7
|
+
let { handedness, targetRay, children } = $props();
|
|
9
8
|
let lineGeometry = new LineGeometry();
|
|
10
9
|
const rayStart = new Vector3();
|
|
11
10
|
const rayMidpoint = new Vector3();
|
|
@@ -15,8 +14,7 @@ const positions = new Float32Array(rayDivisions * 3);
|
|
|
15
14
|
const vec3 = new Vector3();
|
|
16
15
|
const v2_1 = new Vector2();
|
|
17
16
|
const v2_2 = new Vector2();
|
|
18
|
-
|
|
19
|
-
intersection = teleportIntersection[handedness];
|
|
17
|
+
let intersection = $derived(teleportIntersection[handedness]);
|
|
20
18
|
const setCurvePoints = (alpha = 0.3) => {
|
|
21
19
|
if (intersection.current === void 0)
|
|
22
20
|
return;
|
|
@@ -47,16 +45,19 @@ const { start, stop } = useTask(
|
|
|
47
45
|
},
|
|
48
46
|
{ autoStart: false }
|
|
49
47
|
);
|
|
50
|
-
|
|
48
|
+
$effect.pre(() => {
|
|
51
49
|
if ($intersection === void 0) {
|
|
52
50
|
stop();
|
|
53
51
|
} else {
|
|
54
52
|
setCurvePoints(1);
|
|
55
53
|
start();
|
|
56
54
|
}
|
|
55
|
+
});
|
|
57
56
|
</script>
|
|
58
57
|
|
|
59
|
-
|
|
58
|
+
{#if children}
|
|
59
|
+
{@render children()}
|
|
60
|
+
{:else}
|
|
60
61
|
<T
|
|
61
62
|
is={Line2}
|
|
62
63
|
visible={$intersection !== undefined}
|
|
@@ -68,4 +69,4 @@ $:
|
|
|
68
69
|
linewidth={0.004}
|
|
69
70
|
/>
|
|
70
71
|
</T>
|
|
71
|
-
|
|
72
|
+
{/if}
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
import { SvelteComponent } from "svelte";
|
|
2
2
|
import { type XRTargetRaySpace } from 'three';
|
|
3
|
+
import type { Snippet } from 'svelte';
|
|
3
4
|
declare const __propDef: {
|
|
4
5
|
props: {
|
|
5
6
|
handedness: 'left' | 'right';
|
|
6
7
|
targetRay: XRTargetRaySpace;
|
|
8
|
+
children?: Snippet<[]> | undefined;
|
|
7
9
|
};
|
|
8
10
|
events: {
|
|
9
11
|
[evt: string]: CustomEvent<any>;
|
|
10
12
|
};
|
|
11
|
-
slots: {
|
|
12
|
-
default: {};
|
|
13
|
-
};
|
|
13
|
+
slots: {};
|
|
14
14
|
};
|
|
15
15
|
export type TeleportRayProps = typeof __propDef.props;
|
|
16
16
|
export type TeleportRayEvents = typeof __propDef.events;
|
|
@@ -23,7 +23,7 @@ export const setupControllers = () => {
|
|
|
23
23
|
if (hasHands())
|
|
24
24
|
return;
|
|
25
25
|
const { data } = event;
|
|
26
|
-
controllerEvents[data.handedness]?.[event.type]?.(event);
|
|
26
|
+
controllerEvents[data.handedness]?.current?.[`on${event.type}`]?.(event);
|
|
27
27
|
};
|
|
28
28
|
function handleConnected(event) {
|
|
29
29
|
const { model, targetRay, grip } = indexMap.get(this);
|
|
@@ -24,7 +24,7 @@ export const setupHands = () => {
|
|
|
24
24
|
return;
|
|
25
25
|
const handEvent = event;
|
|
26
26
|
const handedness = 'handedness' in handEvent ? handEvent.handedness : handEvent.data.handedness;
|
|
27
|
-
handEvents[handedness]?.[event.type]?.(event);
|
|
27
|
+
handEvents[handedness]?.current?.[`on${event.type}`]?.(event);
|
|
28
28
|
};
|
|
29
29
|
function handleConnected(event) {
|
|
30
30
|
const hand = this;
|
|
@@ -3,8 +3,9 @@ import { useThrelte, useTask, watch } from '@threlte/core';
|
|
|
3
3
|
import { useXR } from '../hooks/useXR';
|
|
4
4
|
export const headset = new Group();
|
|
5
5
|
export const setupHeadset = () => {
|
|
6
|
-
const { renderer, camera } = useThrelte();
|
|
6
|
+
const { renderer, camera, scheduler, renderStage } = useThrelte();
|
|
7
7
|
const { xr } = renderer;
|
|
8
|
+
const stage = scheduler.createStage(Symbol('xr-headset-stage'), { before: renderStage });
|
|
8
9
|
const immersiveFrame = useTask(() => {
|
|
9
10
|
const space = xr.getReferenceSpace();
|
|
10
11
|
if (space === null)
|
|
@@ -17,13 +18,21 @@ export const setupHeadset = () => {
|
|
|
17
18
|
const { position, orientation } = pose.transform;
|
|
18
19
|
headset.position.set(position.x, position.y, position.z);
|
|
19
20
|
headset.quaternion.set(orientation.x, orientation.y, orientation.z, orientation.w);
|
|
20
|
-
}, {
|
|
21
|
+
}, {
|
|
22
|
+
autoStart: false,
|
|
23
|
+
autoInvalidate: false,
|
|
24
|
+
stage
|
|
25
|
+
});
|
|
21
26
|
const nonImmersiveFrame = useTask(() => {
|
|
22
27
|
headset.position.copy(camera.current.position);
|
|
23
28
|
headset.quaternion.copy(camera.current.quaternion);
|
|
24
|
-
}, {
|
|
25
|
-
|
|
26
|
-
|
|
29
|
+
}, {
|
|
30
|
+
autoStart: false,
|
|
31
|
+
autoInvalidate: false,
|
|
32
|
+
stage
|
|
33
|
+
});
|
|
34
|
+
watch(useXR().isPresenting, ($isPresenting) => {
|
|
35
|
+
if ($isPresenting) {
|
|
27
36
|
immersiveFrame.start();
|
|
28
37
|
nonImmersiveFrame.stop();
|
|
29
38
|
}
|
|
@@ -1,21 +1,17 @@
|
|
|
1
|
-
// @ts-expect-error svelte/internal is untyped.
|
|
2
|
-
// import { set_raf } from 'svelte/internal'
|
|
3
1
|
import { onDestroy } from 'svelte';
|
|
2
|
+
// @ts-expect-error untyped internal import, when have you ever done me wrong?
|
|
3
|
+
import { raf } from 'svelte/internal/client';
|
|
4
4
|
import { watch } from '@threlte/core';
|
|
5
5
|
import { session } from './stores';
|
|
6
6
|
export const setupRaf = () => {
|
|
7
7
|
if (typeof window === 'undefined')
|
|
8
8
|
return;
|
|
9
|
-
const
|
|
10
|
-
const currentRaf = { fn: browserRaf };
|
|
11
|
-
// set_raf((fn: FrameRequestCallback) => currentRaf.fn(fn))
|
|
9
|
+
const originalTick = raf.tick;
|
|
12
10
|
watch(session, (session) => {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
currentRaf.fn = browserRaf;
|
|
18
|
-
}
|
|
11
|
+
raf.tick =
|
|
12
|
+
session === undefined
|
|
13
|
+
? originalTick
|
|
14
|
+
: (fn) => session.requestAnimationFrame(fn);
|
|
19
15
|
});
|
|
20
|
-
onDestroy(() => (
|
|
16
|
+
onDestroy(() => (raf.tick = originalTick));
|
|
21
17
|
};
|
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
/// <reference types="webxr" />
|
|
2
2
|
import type { WebXRManager, Intersection } from 'three';
|
|
3
|
+
import type { XRControllerEvents, XRHandEvents } from '../types';
|
|
3
4
|
export declare const isPresenting: import("@threlte/core").CurrentWritable<boolean>;
|
|
4
5
|
export declare const isHandTracking: import("@threlte/core").CurrentWritable<boolean>;
|
|
5
6
|
export declare const session: import("@threlte/core").CurrentWritable<XRSession | undefined>;
|
|
6
7
|
export declare const referenceSpaceType: import("@threlte/core").CurrentWritable<XRReferenceSpaceType | undefined>;
|
|
7
8
|
export declare const xr: import("@threlte/core").CurrentWritable<WebXRManager | undefined>;
|
|
8
9
|
export declare const controllerEvents: {
|
|
9
|
-
left: import("@threlte/core").CurrentWritable<
|
|
10
|
-
right: import("@threlte/core").CurrentWritable<
|
|
10
|
+
left: import("@threlte/core").CurrentWritable<XRControllerEvents | undefined>;
|
|
11
|
+
right: import("@threlte/core").CurrentWritable<XRControllerEvents | undefined>;
|
|
11
12
|
};
|
|
12
13
|
export declare const handEvents: {
|
|
13
|
-
left: import("@threlte/core").CurrentWritable<
|
|
14
|
-
right: import("@threlte/core").CurrentWritable<
|
|
14
|
+
left: import("@threlte/core").CurrentWritable<XRHandEvents | undefined>;
|
|
15
|
+
right: import("@threlte/core").CurrentWritable<XRHandEvents | undefined>;
|
|
15
16
|
};
|
|
16
17
|
export declare const teleportState: import("@threlte/core").CurrentWritable<{
|
|
17
18
|
left: {
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { Object3D } from 'three';
|
|
2
|
+
import type { ControlsContext, HandContext } from './types';
|
|
3
|
+
export declare const getHandContext: (hand: 'left' | 'right') => HandContext;
|
|
4
|
+
export declare const setHandContext: (hand: 'left' | 'right', context: HandContext) => void;
|
|
5
|
+
export declare const getControlsContext: () => ControlsContext;
|
|
6
|
+
export declare const setControlsContext: (context: ControlsContext) => void;
|
|
7
|
+
interface InternalContext {
|
|
8
|
+
dispatchers: WeakMap<Object3D, Record<string, (arg: unknown) => void>>;
|
|
9
|
+
}
|
|
10
|
+
export declare const getInternalContext: () => InternalContext;
|
|
11
|
+
export declare const setInternalContext: () => void;
|
|
12
|
+
export {};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Object3D } from 'three';
|
|
2
2
|
export declare const usePointerControls: () => {
|
|
3
|
-
addInteractiveObject: (object: Object3D) => void;
|
|
3
|
+
addInteractiveObject: (object: Object3D, events: Record<string, (arg: unknown) => void>) => void;
|
|
4
4
|
removeInteractiveObject: (object: Object3D) => void;
|
|
5
5
|
};
|
|
@@ -1,15 +1,16 @@
|
|
|
1
|
-
import { createRawEventDispatcher } from '@threlte/core';
|
|
2
1
|
import { getControlsContext, getInternalContext } from './context';
|
|
3
2
|
export const usePointerControls = () => {
|
|
4
|
-
const { dispatchers } = getInternalContext();
|
|
5
3
|
const context = getControlsContext();
|
|
6
|
-
const
|
|
7
|
-
|
|
4
|
+
const { dispatchers } = getInternalContext();
|
|
5
|
+
if (!context) {
|
|
6
|
+
throw new Error('No pointer controls context found. Did you forget to implement pointerControls()?');
|
|
7
|
+
}
|
|
8
|
+
const addInteractiveObject = (object, events) => {
|
|
8
9
|
// check if the object is already in the list
|
|
9
10
|
if (context.interactiveObjects.indexOf(object) > -1) {
|
|
10
11
|
return;
|
|
11
12
|
}
|
|
12
|
-
dispatchers.set(object,
|
|
13
|
+
dispatchers.set(object, events);
|
|
13
14
|
context.interactiveObjects.push(object);
|
|
14
15
|
};
|
|
15
16
|
const removeInteractiveObject = (object) => {
|
|
@@ -1,23 +1,21 @@
|
|
|
1
1
|
import { injectPlugin, watch } from '@threlte/core';
|
|
2
2
|
import { writable } from 'svelte/store';
|
|
3
3
|
import { usePointerControls } from './hook';
|
|
4
|
-
import {
|
|
4
|
+
import { events } from './types';
|
|
5
5
|
export const injectPointerControlsPlugin = () => {
|
|
6
|
-
injectPlugin('threlte-pointer-controls', ({ ref }) => {
|
|
7
|
-
if (ref.
|
|
6
|
+
injectPlugin('threlte-pointer-controls', ({ ref, props }) => {
|
|
7
|
+
if (!ref.isObject3D)
|
|
8
8
|
return;
|
|
9
9
|
const { addInteractiveObject, removeInteractiveObject } = usePointerControls();
|
|
10
10
|
const refStore = writable(ref);
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
// remove the object from the list of interactive objects when
|
|
16
|
-
// hasEventHandlers is false.
|
|
11
|
+
watch(refStore, ($refStore) => {
|
|
12
|
+
const hasEventHandlers = Object.entries(props).some(([key, value]) => {
|
|
13
|
+
return value !== undefined && events.includes(key);
|
|
14
|
+
});
|
|
17
15
|
if (!hasEventHandlers)
|
|
18
16
|
return;
|
|
19
|
-
addInteractiveObject(
|
|
20
|
-
return () => removeInteractiveObject(
|
|
17
|
+
addInteractiveObject($refStore, props);
|
|
18
|
+
return () => removeInteractiveObject($refStore);
|
|
21
19
|
});
|
|
22
20
|
return {
|
|
23
21
|
onRefChange(ref) {
|