@viamrobotics/motion-tools 0.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/LICENSE +21 -0
- package/README.md +20 -0
- package/dist/WorldObject.d.ts +33 -0
- package/dist/WorldObject.js +18 -0
- package/dist/assert.d.ts +14 -0
- package/dist/assert.js +21 -0
- package/dist/color.d.ts +8 -0
- package/dist/color.js +14 -0
- package/dist/components/App.svelte +63 -0
- package/dist/components/App.svelte.d.ts +8 -0
- package/dist/components/AxesHelper.svelte +17 -0
- package/dist/components/AxesHelper.svelte.d.ts +4 -0
- package/dist/components/BentPlaneGeometry.svelte +52 -0
- package/dist/components/BentPlaneGeometry.svelte.d.ts +29 -0
- package/dist/components/Camera.svelte +45 -0
- package/dist/components/Camera.svelte.d.ts +5 -0
- package/dist/components/CameraControls.svelte +82 -0
- package/dist/components/CameraControls.svelte.d.ts +9 -0
- package/dist/components/Details.svelte +161 -0
- package/dist/components/Details.svelte.d.ts +3 -0
- package/dist/components/Detections.svelte +41 -0
- package/dist/components/Detections.svelte.d.ts +3 -0
- package/dist/components/DetectionsPlane.svelte +23 -0
- package/dist/components/DetectionsPlane.svelte.d.ts +21 -0
- package/dist/components/DomPortal.svelte +20 -0
- package/dist/components/DomPortal.svelte.d.ts +5 -0
- package/dist/components/Focus.svelte +49 -0
- package/dist/components/Focus.svelte.d.ts +3 -0
- package/dist/components/Frame.svelte +112 -0
- package/dist/components/Frame.svelte.d.ts +16 -0
- package/dist/components/Frames.svelte +54 -0
- package/dist/components/Frames.svelte.d.ts +18 -0
- package/dist/components/Pointcloud.svelte +55 -0
- package/dist/components/Pointcloud.svelte.d.ts +10 -0
- package/dist/components/Pointclouds.svelte +21 -0
- package/dist/components/Pointclouds.svelte.d.ts +18 -0
- package/dist/components/Pose.svelte +19 -0
- package/dist/components/Pose.svelte.d.ts +12 -0
- package/dist/components/RefreshRate.svelte +47 -0
- package/dist/components/RefreshRate.svelte.d.ts +8 -0
- package/dist/components/Scene.svelte +81 -0
- package/dist/components/Scene.svelte.d.ts +7 -0
- package/dist/components/SceneProviders.svelte +41 -0
- package/dist/components/SceneProviders.svelte.d.ts +9 -0
- package/dist/components/Selected.svelte +44 -0
- package/dist/components/Selected.svelte.d.ts +3 -0
- package/dist/components/Shapes.svelte +49 -0
- package/dist/components/Shapes.svelte.d.ts +18 -0
- package/dist/components/StaticGeometries.svelte +79 -0
- package/dist/components/StaticGeometries.svelte.d.ts +18 -0
- package/dist/components/Tree/Settings.svelte +54 -0
- package/dist/components/Tree/Settings.svelte.d.ts +18 -0
- package/dist/components/Tree/Tree.svelte +204 -0
- package/dist/components/Tree/Tree.svelte.d.ts +10 -0
- package/dist/components/Tree/TreeContainer.svelte +70 -0
- package/dist/components/Tree/TreeContainer.svelte.d.ts +3 -0
- package/dist/components/Tree/buildTree.d.ts +11 -0
- package/dist/components/Tree/buildTree.js +29 -0
- package/dist/components/Tree/useExpanded.svelte.d.ts +5 -0
- package/dist/components/Tree/useExpanded.svelte.js +21 -0
- package/dist/components/WorldObject.svelte +27 -0
- package/dist/components/WorldObject.svelte.d.ts +11 -0
- package/dist/components/XR.svelte +20 -0
- package/dist/components/XR.svelte.d.ts +3 -0
- package/dist/components/models/README.md +5 -0
- package/dist/components/null-states/Connection.svelte +0 -0
- package/dist/components/null-states/Connection.svelte.d.ts +26 -0
- package/dist/components/portal/Portal.svelte +25 -0
- package/dist/components/portal/Portal.svelte.d.ts +8 -0
- package/dist/components/portal/PortalTarget.svelte +18 -0
- package/dist/components/portal/PortalTarget.svelte.d.ts +6 -0
- package/dist/components/portal/index.d.ts +2 -0
- package/dist/components/portal/index.js +2 -0
- package/dist/components/portal/usePortalContext.svelte.d.ts +5 -0
- package/dist/components/portal/usePortalContext.svelte.js +8 -0
- package/dist/components/xr/CameraFeed.svelte +81 -0
- package/dist/components/xr/CameraFeed.svelte.d.ts +6 -0
- package/dist/components/xr/Controllers.svelte +71 -0
- package/dist/components/xr/Controllers.svelte.d.ts +3 -0
- package/dist/components/xr/Draggable.svelte +101 -0
- package/dist/components/xr/Draggable.svelte.d.ts +11 -0
- package/dist/components/xr/HandCollider.svelte +19 -0
- package/dist/components/xr/HandCollider.svelte.d.ts +18 -0
- package/dist/components/xr/Hands.svelte +24 -0
- package/dist/components/xr/Hands.svelte.d.ts +18 -0
- package/dist/components/xr/OriginMarker.svelte +100 -0
- package/dist/components/xr/OriginMarker.svelte.d.ts +3 -0
- package/dist/components/xr/PointDistance.svelte +52 -0
- package/dist/components/xr/PointDistance.svelte.d.ts +3 -0
- package/dist/hooks/index.d.ts +1 -0
- package/dist/hooks/index.js +1 -0
- package/dist/hooks/useConnectionConfigs.svelte.d.ts +17 -0
- package/dist/hooks/useConnectionConfigs.svelte.js +40 -0
- package/dist/hooks/useControls.svelte.d.ts +7 -0
- package/dist/hooks/useControls.svelte.js +16 -0
- package/dist/hooks/useDraggable.svelte.d.ts +2 -0
- package/dist/hooks/useDraggable.svelte.js +25 -0
- package/dist/hooks/useFrames.svelte.d.ts +9 -0
- package/dist/hooks/useFrames.svelte.js +50 -0
- package/dist/hooks/useGeometries.svelte.d.ts +7 -0
- package/dist/hooks/useGeometries.svelte.js +58 -0
- package/dist/hooks/useMotionClient.svelte.d.ts +8 -0
- package/dist/hooks/useMotionClient.svelte.js +31 -0
- package/dist/hooks/useObjectEvents.svelte.d.ts +9 -0
- package/dist/hooks/useObjectEvents.svelte.js +31 -0
- package/dist/hooks/useObjects.svelte.d.ts +7 -0
- package/dist/hooks/useObjects.svelte.js +33 -0
- package/dist/hooks/usePartID.svelte.d.ts +6 -0
- package/dist/hooks/usePartID.svelte.js +14 -0
- package/dist/hooks/usePersistentUUIDs.svelte.d.ts +5 -0
- package/dist/hooks/usePersistentUUIDs.svelte.js +14 -0
- package/dist/hooks/usePointclouds.svelte.d.ts +7 -0
- package/dist/hooks/usePointclouds.svelte.js +58 -0
- package/dist/hooks/usePose.svelte.d.ts +3 -0
- package/dist/hooks/usePose.svelte.js +44 -0
- package/dist/hooks/usePoses.svelte.d.ts +12 -0
- package/dist/hooks/usePoses.svelte.js +63 -0
- package/dist/hooks/useRefreshRates.svelte.d.ts +5 -0
- package/dist/hooks/useRefreshRates.svelte.js +23 -0
- package/dist/hooks/useSelection.svelte.d.ts +40 -0
- package/dist/hooks/useSelection.svelte.js +92 -0
- package/dist/hooks/useShapes.svelte.d.ts +17 -0
- package/dist/hooks/useShapes.svelte.js +264 -0
- package/dist/hooks/useStaticGeometries.svelte.d.ts +9 -0
- package/dist/hooks/useStaticGeometries.svelte.js +37 -0
- package/dist/hooks/useVisibility.svelte.d.ts +5 -0
- package/dist/hooks/useVisibility.svelte.js +22 -0
- package/dist/hooks/xr/useAnchors.svelte.d.ts +0 -0
- package/dist/hooks/xr/useAnchors.svelte.js +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +1 -0
- package/dist/keybindings.d.ts +12 -0
- package/dist/keybindings.js +12 -0
- package/dist/loaders/pcd/index.d.ts +4 -0
- package/dist/loaders/pcd/index.js +13 -0
- package/dist/loaders/pcd/worker.d.ts +1 -0
- package/dist/loaders/pcd/worker.js +26 -0
- package/dist/three/AxesHelper.d.ts +5 -0
- package/dist/three/AxesHelper.js +35 -0
- package/dist/three/BatchedArrow.d.ts +30 -0
- package/dist/three/BatchedArrow.js +126 -0
- package/dist/three/BoxHelper.d.ts +50 -0
- package/dist/three/BoxHelper.js +134 -0
- package/dist/three/CapsuleGeometry.d.ts +10 -0
- package/dist/three/CapsuleGeometry.js +17 -0
- package/dist/transform.d.ts +11 -0
- package/dist/transform.js +65 -0
- package/package.json +110 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { get, set } from 'idb-keyval';
|
|
2
|
+
import { getContext, setContext } from 'svelte';
|
|
3
|
+
import { SvelteSet } from 'svelte/reactivity';
|
|
4
|
+
const key = Symbol('tree-item-expanded-context');
|
|
5
|
+
export const provideTreeExpandedContext = () => {
|
|
6
|
+
const expanded = new SvelteSet();
|
|
7
|
+
get('tree-item-expanded').then((stored) => {
|
|
8
|
+
if (stored) {
|
|
9
|
+
for (const value of stored) {
|
|
10
|
+
expanded.add(value);
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
});
|
|
14
|
+
$effect(() => {
|
|
15
|
+
set('tree-item-expanded', [...expanded]);
|
|
16
|
+
});
|
|
17
|
+
setContext(key, expanded);
|
|
18
|
+
};
|
|
19
|
+
export const useExpanded = () => {
|
|
20
|
+
return getContext(key);
|
|
21
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { T, type Props as ThrelteProps } from '@threlte/core'
|
|
3
|
+
import type { Snippet } from 'svelte'
|
|
4
|
+
import type { Object3D } from 'three'
|
|
5
|
+
import type { WorldObject } from '../WorldObject'
|
|
6
|
+
import { useObjectEvents } from '../hooks/useObjectEvents.svelte'
|
|
7
|
+
|
|
8
|
+
interface Props extends ThrelteProps<Object3D> {
|
|
9
|
+
object: WorldObject
|
|
10
|
+
children?: Snippet
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
let { object, children, ...rest }: Props = $props()
|
|
14
|
+
|
|
15
|
+
const objectProps = useObjectEvents(() => object.uuid)
|
|
16
|
+
</script>
|
|
17
|
+
|
|
18
|
+
{#if object.metadata.gltf?.scene}
|
|
19
|
+
<T
|
|
20
|
+
is={object.metadata.gltf.scene}
|
|
21
|
+
name={object.name}
|
|
22
|
+
{...objectProps}
|
|
23
|
+
{...rest}
|
|
24
|
+
>
|
|
25
|
+
{@render children?.()}
|
|
26
|
+
</T>
|
|
27
|
+
{/if}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { type Props as ThrelteProps } from '@threlte/core';
|
|
2
|
+
import type { Snippet } from 'svelte';
|
|
3
|
+
import type { Object3D } from 'three';
|
|
4
|
+
import type { WorldObject } from '../WorldObject';
|
|
5
|
+
interface Props extends ThrelteProps<Object3D> {
|
|
6
|
+
object: WorldObject;
|
|
7
|
+
children?: Snippet;
|
|
8
|
+
}
|
|
9
|
+
declare const WorldObject: import("svelte").Component<Props, {}, "">;
|
|
10
|
+
type WorldObject = ReturnType<typeof WorldObject>;
|
|
11
|
+
export default WorldObject;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { useXR, XR } from '@threlte/xr'
|
|
3
|
+
import OriginMarker from './xr/OriginMarker.svelte'
|
|
4
|
+
import { useThrelte } from '@threlte/core'
|
|
5
|
+
|
|
6
|
+
const { renderer } = useThrelte()
|
|
7
|
+
const { isPresenting } = useXR()
|
|
8
|
+
|
|
9
|
+
$effect.pre(() => {
|
|
10
|
+
if ($isPresenting) {
|
|
11
|
+
const [left, right] = renderer.xr.getCamera().cameras
|
|
12
|
+
|
|
13
|
+
console.log(left, right)
|
|
14
|
+
}
|
|
15
|
+
})
|
|
16
|
+
</script>
|
|
17
|
+
|
|
18
|
+
<XR>
|
|
19
|
+
<OriginMarker />
|
|
20
|
+
</XR>
|
|
File without changes
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export default Connection;
|
|
2
|
+
type Connection = SvelteComponent<{
|
|
3
|
+
[x: string]: never;
|
|
4
|
+
}, {
|
|
5
|
+
[evt: string]: CustomEvent<any>;
|
|
6
|
+
}, {}> & {
|
|
7
|
+
$$bindings?: string | undefined;
|
|
8
|
+
};
|
|
9
|
+
declare const Connection: $$__sveltets_2_IsomorphicComponent<{
|
|
10
|
+
[x: string]: never;
|
|
11
|
+
}, {
|
|
12
|
+
[evt: string]: CustomEvent<any>;
|
|
13
|
+
}, {}, {}, string>;
|
|
14
|
+
interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
|
|
15
|
+
new (options: import("svelte").ComponentConstructorOptions<Props>): import("svelte").SvelteComponent<Props, Events, Slots> & {
|
|
16
|
+
$$bindings?: Bindings;
|
|
17
|
+
} & Exports;
|
|
18
|
+
(internal: unknown, props: {
|
|
19
|
+
$$events?: Events;
|
|
20
|
+
$$slots?: Slots;
|
|
21
|
+
}): Exports & {
|
|
22
|
+
$set?: any;
|
|
23
|
+
$on?: any;
|
|
24
|
+
};
|
|
25
|
+
z_$$bindings?: Bindings;
|
|
26
|
+
}
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import type { Snippet } from 'svelte'
|
|
3
|
+
import { usePortalContext } from './usePortalContext.svelte'
|
|
4
|
+
import { SvelteSet } from 'svelte/reactivity'
|
|
5
|
+
|
|
6
|
+
interface Props {
|
|
7
|
+
id?: string
|
|
8
|
+
children?: Snippet
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
let { id = 'default', children }: Props = $props()
|
|
12
|
+
|
|
13
|
+
const portals = usePortalContext()
|
|
14
|
+
|
|
15
|
+
$effect.pre(() => {
|
|
16
|
+
if (!children) return
|
|
17
|
+
|
|
18
|
+
if (!portals.has(id)) {
|
|
19
|
+
portals.set(id, new SvelteSet())
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
portals.get(id)?.add(children)
|
|
23
|
+
return () => portals.get(id)?.delete(children)
|
|
24
|
+
})
|
|
25
|
+
</script>
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { usePortalContext } from './usePortalContext.svelte'
|
|
3
|
+
|
|
4
|
+
interface Props {
|
|
5
|
+
id?: string
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
let { id = 'default' }: Props = $props()
|
|
9
|
+
|
|
10
|
+
const portals = usePortalContext()
|
|
11
|
+
const childArray = $derived(portals.get(id))
|
|
12
|
+
</script>
|
|
13
|
+
|
|
14
|
+
{#if childArray}
|
|
15
|
+
{#each childArray as children (children)}
|
|
16
|
+
{@render children?.()}
|
|
17
|
+
{/each}
|
|
18
|
+
{/if}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { useThrelteUserContext } from '@threlte/core';
|
|
2
|
+
import { SvelteMap, SvelteSet } from 'svelte/reactivity';
|
|
3
|
+
const createPortalContext = () => {
|
|
4
|
+
return new SvelteMap();
|
|
5
|
+
};
|
|
6
|
+
export const usePortalContext = () => {
|
|
7
|
+
return useThrelteUserContext('threlte-portals', createPortalContext());
|
|
8
|
+
};
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { T, useTask } from '@threlte/core'
|
|
3
|
+
import { createStreamClient } from '@viamrobotics/svelte-sdk'
|
|
4
|
+
import BentPlaneGeometry from '../BentPlaneGeometry.svelte'
|
|
5
|
+
import { useHeadset } from '@threlte/xr'
|
|
6
|
+
import { Euler, Group, Mesh, Vector3, Quaternion, VideoTexture } from 'three'
|
|
7
|
+
import { usePartID } from '../../hooks/usePartID.svelte'
|
|
8
|
+
|
|
9
|
+
interface CameraFeedProps {
|
|
10
|
+
resourceName: string
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
let { resourceName }: CameraFeedProps = $props()
|
|
14
|
+
|
|
15
|
+
const partID = usePartID()
|
|
16
|
+
const streamClient = createStreamClient(
|
|
17
|
+
() => partID.current,
|
|
18
|
+
() => resourceName
|
|
19
|
+
)
|
|
20
|
+
|
|
21
|
+
let video = document.createElement('video')
|
|
22
|
+
let aspect = $state(1)
|
|
23
|
+
let ready = $state(false)
|
|
24
|
+
|
|
25
|
+
video.addEventListener('canplaythrough', () => {
|
|
26
|
+
aspect = video.videoWidth / video.videoHeight
|
|
27
|
+
video.play()
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
$effect.pre(() => {
|
|
31
|
+
video.srcObject = streamClient.mediaStream
|
|
32
|
+
ready = true
|
|
33
|
+
})
|
|
34
|
+
|
|
35
|
+
const headset = useHeadset()
|
|
36
|
+
|
|
37
|
+
let group = new Group()
|
|
38
|
+
let mesh = new Mesh()
|
|
39
|
+
let euler = new Euler()
|
|
40
|
+
let quaternion = new Quaternion()
|
|
41
|
+
let direction = new Vector3()
|
|
42
|
+
|
|
43
|
+
const { start, stop } = useTask(
|
|
44
|
+
(delta) => {
|
|
45
|
+
group.position.lerp(headset.position, delta * 5)
|
|
46
|
+
|
|
47
|
+
headset.getWorldDirection(direction)
|
|
48
|
+
euler.set(0, Math.atan2(direction.x, direction.z), 0)
|
|
49
|
+
quaternion.setFromEuler(euler)
|
|
50
|
+
group.quaternion.slerp(quaternion, delta * 5)
|
|
51
|
+
|
|
52
|
+
mesh.lookAt(headset.position)
|
|
53
|
+
},
|
|
54
|
+
{ autoStart: false }
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
$effect(() => {
|
|
58
|
+
if (ready) {
|
|
59
|
+
start()
|
|
60
|
+
} else {
|
|
61
|
+
stop()
|
|
62
|
+
}
|
|
63
|
+
})
|
|
64
|
+
|
|
65
|
+
const texture = new VideoTexture(video)
|
|
66
|
+
</script>
|
|
67
|
+
|
|
68
|
+
{#if ready}
|
|
69
|
+
<T is={group}>
|
|
70
|
+
<T.Group>
|
|
71
|
+
<T
|
|
72
|
+
is={mesh}
|
|
73
|
+
position={[0, 0, -1.5]}
|
|
74
|
+
scale={0.7}
|
|
75
|
+
>
|
|
76
|
+
<BentPlaneGeometry args={[0.1, aspect, 1, 20, 20]} />
|
|
77
|
+
<T.MeshBasicMaterial map={texture} />
|
|
78
|
+
</T>
|
|
79
|
+
</T.Group>
|
|
80
|
+
</T>
|
|
81
|
+
{/if}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { Controller } from '@threlte/xr'
|
|
3
|
+
import { useGamepad } from '@threlte/extras'
|
|
4
|
+
|
|
5
|
+
import { BaseClient } from '@viamrobotics/sdk'
|
|
6
|
+
|
|
7
|
+
import { RigidBody } from '@threlte/rapier'
|
|
8
|
+
import HandCollider from './HandCollider.svelte'
|
|
9
|
+
import { usePartID } from '../../hooks/usePartID.svelte'
|
|
10
|
+
import { useResourceNames, useRobotClient } from '@viamrobotics/svelte-sdk'
|
|
11
|
+
|
|
12
|
+
const gamepadLeft = useGamepad({ xr: true, hand: 'left' })
|
|
13
|
+
|
|
14
|
+
const partID = usePartID()
|
|
15
|
+
const resources = useResourceNames(() => partID.current)
|
|
16
|
+
const robotClient = useRobotClient(() => partID.current)
|
|
17
|
+
const resource = $derived(resources.current.find((r) => r.subtype === 'base'))
|
|
18
|
+
const baseClient = $derived(
|
|
19
|
+
robotClient.current && resource ? new BaseClient(robotClient.current, resource.name) : undefined
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
const linear = { x: 0, y: 0, z: 0 }
|
|
23
|
+
const angular = { x: 0, y: 0, z: 0 }
|
|
24
|
+
|
|
25
|
+
gamepadLeft.squeeze.on('change', (event) => {
|
|
26
|
+
linear.y = -event.value
|
|
27
|
+
baseClient?.setPower(linear, angular)
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
gamepadLeft.trigger.on('change', (event) => {
|
|
31
|
+
if (typeof event.value === 'number') {
|
|
32
|
+
linear.y = event.value
|
|
33
|
+
baseClient?.setPower(linear, angular)
|
|
34
|
+
}
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
gamepadLeft.thumbstick.on('change', (event) => {
|
|
38
|
+
if (typeof event.value === 'object') {
|
|
39
|
+
angular.z = event.value.x
|
|
40
|
+
baseClient?.setPower(linear, angular)
|
|
41
|
+
}
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
const onselectstart = () => {}
|
|
45
|
+
|
|
46
|
+
const onselectend = () => {}
|
|
47
|
+
</script>
|
|
48
|
+
|
|
49
|
+
<Controller
|
|
50
|
+
left
|
|
51
|
+
{onselectstart}
|
|
52
|
+
{onselectend}
|
|
53
|
+
>
|
|
54
|
+
{#snippet grip()}
|
|
55
|
+
<RigidBody type="kinematicPosition">
|
|
56
|
+
<HandCollider />
|
|
57
|
+
</RigidBody>
|
|
58
|
+
{/snippet}
|
|
59
|
+
</Controller>
|
|
60
|
+
|
|
61
|
+
<Controller
|
|
62
|
+
right
|
|
63
|
+
{onselectstart}
|
|
64
|
+
{onselectend}
|
|
65
|
+
>
|
|
66
|
+
{#snippet grip()}
|
|
67
|
+
<RigidBody type="kinematicPosition">
|
|
68
|
+
<HandCollider />
|
|
69
|
+
</RigidBody>
|
|
70
|
+
{/snippet}
|
|
71
|
+
</Controller>
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { T, useTask } from '@threlte/core'
|
|
3
|
+
import { useGamepad } from '@threlte/extras'
|
|
4
|
+
import { useController } from '@threlte/xr'
|
|
5
|
+
import { RigidBody as RigidBodyType } from '@dimforge/rapier3d-compat'
|
|
6
|
+
import type { Snippet } from 'svelte'
|
|
7
|
+
import { Group, Vector3 } from 'three'
|
|
8
|
+
import { AutoColliders, RigidBody } from '@threlte/rapier'
|
|
9
|
+
|
|
10
|
+
interface Props {
|
|
11
|
+
children: Snippet
|
|
12
|
+
onPointerEnter?: () => void
|
|
13
|
+
onPointerLeave?: () => void
|
|
14
|
+
onPointerDown?: () => void
|
|
15
|
+
onPointerUp?: () => void
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
let { onPointerEnter, onPointerLeave, onPointerDown, onPointerUp, children }: Props = $props()
|
|
19
|
+
|
|
20
|
+
let hovering = $state(false)
|
|
21
|
+
|
|
22
|
+
let dragging = $state(false)
|
|
23
|
+
let rigidBody: RigidBodyType | undefined = $state()
|
|
24
|
+
|
|
25
|
+
const group = new Group()
|
|
26
|
+
const vec3 = new Vector3()
|
|
27
|
+
const offset = new Vector3()
|
|
28
|
+
const position = new Vector3()
|
|
29
|
+
|
|
30
|
+
const left = useController('left')
|
|
31
|
+
const right = useController('right')
|
|
32
|
+
const leftPad = useGamepad({ xr: true, hand: 'left' })
|
|
33
|
+
const rightPad = useGamepad({ xr: true, hand: 'right' })
|
|
34
|
+
|
|
35
|
+
leftPad.trigger.on('down', () => {
|
|
36
|
+
if (!$left) return
|
|
37
|
+
|
|
38
|
+
dragging = true
|
|
39
|
+
group.getWorldPosition(vec3)
|
|
40
|
+
offset.copy($left.grip.position).sub(vec3)
|
|
41
|
+
onPointerDown?.()
|
|
42
|
+
})
|
|
43
|
+
|
|
44
|
+
leftPad.trigger.on('up', () => {
|
|
45
|
+
dragging = false
|
|
46
|
+
onPointerUp?.()
|
|
47
|
+
})
|
|
48
|
+
|
|
49
|
+
rightPad.trigger.on('down', () => {
|
|
50
|
+
if (!$right) return
|
|
51
|
+
|
|
52
|
+
dragging = true
|
|
53
|
+
group.getWorldPosition(vec3)
|
|
54
|
+
offset.copy($right.grip.position).sub(vec3)
|
|
55
|
+
onPointerDown?.()
|
|
56
|
+
})
|
|
57
|
+
|
|
58
|
+
rightPad.trigger.on('up', () => {
|
|
59
|
+
dragging = true
|
|
60
|
+
onPointerUp?.()
|
|
61
|
+
})
|
|
62
|
+
|
|
63
|
+
const onsensorenter = () => {
|
|
64
|
+
hovering = true
|
|
65
|
+
onPointerEnter?.()
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const onsensorexit = () => {
|
|
69
|
+
hovering = false
|
|
70
|
+
onPointerLeave?.()
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const { start, stop } = useTask(
|
|
74
|
+
() => {
|
|
75
|
+
if (!$left || !rigidBody) return
|
|
76
|
+
|
|
77
|
+
position.copy($left.grip.position).sub(offset)
|
|
78
|
+
|
|
79
|
+
rigidBody.setNextKinematicTranslation({ x: position.x, y: position.y, z: position.z })
|
|
80
|
+
},
|
|
81
|
+
{ autoStart: false }
|
|
82
|
+
)
|
|
83
|
+
|
|
84
|
+
$effect(() => (hovering && dragging ? start() : stop()))
|
|
85
|
+
</script>
|
|
86
|
+
|
|
87
|
+
<T is={group}>
|
|
88
|
+
<RigidBody
|
|
89
|
+
bind:rigidBody
|
|
90
|
+
type="kinematicPosition"
|
|
91
|
+
>
|
|
92
|
+
<AutoColliders
|
|
93
|
+
sensor
|
|
94
|
+
shape="convexHull"
|
|
95
|
+
{onsensorenter}
|
|
96
|
+
{onsensorexit}
|
|
97
|
+
>
|
|
98
|
+
{@render children?.()}
|
|
99
|
+
</AutoColliders>
|
|
100
|
+
</RigidBody>
|
|
101
|
+
</T>
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { Snippet } from 'svelte';
|
|
2
|
+
interface Props {
|
|
3
|
+
children: Snippet;
|
|
4
|
+
onPointerEnter?: () => void;
|
|
5
|
+
onPointerLeave?: () => void;
|
|
6
|
+
onPointerDown?: () => void;
|
|
7
|
+
onPointerUp?: () => void;
|
|
8
|
+
}
|
|
9
|
+
declare const Draggable: import("svelte").Component<Props, {}, "">;
|
|
10
|
+
type Draggable = ReturnType<typeof Draggable>;
|
|
11
|
+
export default Draggable;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { useParent, useTask } from '@threlte/core'
|
|
3
|
+
import { Collider, useRigidBody } from '@threlte/rapier'
|
|
4
|
+
import type { Group } from 'three'
|
|
5
|
+
|
|
6
|
+
const parent = useParent()
|
|
7
|
+
const rb = useRigidBody()
|
|
8
|
+
|
|
9
|
+
useTask(() => {
|
|
10
|
+
const { position } = $parent as Group
|
|
11
|
+
rb?.setNextKinematicTranslation({ x: position.x, y: position.y, z: position.z })
|
|
12
|
+
})
|
|
13
|
+
</script>
|
|
14
|
+
|
|
15
|
+
<Collider
|
|
16
|
+
sensor
|
|
17
|
+
shape="ball"
|
|
18
|
+
args={[0.1]}
|
|
19
|
+
/>
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
|
|
2
|
+
new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
|
|
3
|
+
$$bindings?: Bindings;
|
|
4
|
+
} & Exports;
|
|
5
|
+
(internal: unknown, props: {
|
|
6
|
+
$$events?: Events;
|
|
7
|
+
$$slots?: Slots;
|
|
8
|
+
}): Exports & {
|
|
9
|
+
$set?: any;
|
|
10
|
+
$on?: any;
|
|
11
|
+
};
|
|
12
|
+
z_$$bindings?: Bindings;
|
|
13
|
+
}
|
|
14
|
+
declare const HandCollider: $$__sveltets_2_IsomorphicComponent<Record<string, never>, {
|
|
15
|
+
[evt: string]: CustomEvent<any>;
|
|
16
|
+
}, {}, {}, string>;
|
|
17
|
+
type HandCollider = InstanceType<typeof HandCollider>;
|
|
18
|
+
export default HandCollider;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { Hand } from '@threlte/xr'
|
|
3
|
+
|
|
4
|
+
console.log('hands')
|
|
5
|
+
const onpinchstart = () => {
|
|
6
|
+
console.log('start')
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
const onpinchend = () => {
|
|
10
|
+
console.log('end')
|
|
11
|
+
}
|
|
12
|
+
</script>
|
|
13
|
+
|
|
14
|
+
<Hand
|
|
15
|
+
left
|
|
16
|
+
{onpinchstart}
|
|
17
|
+
{onpinchend}
|
|
18
|
+
></Hand>
|
|
19
|
+
|
|
20
|
+
<Hand
|
|
21
|
+
right
|
|
22
|
+
{onpinchstart}
|
|
23
|
+
{onpinchend}
|
|
24
|
+
></Hand>
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
|
|
2
|
+
new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
|
|
3
|
+
$$bindings?: Bindings;
|
|
4
|
+
} & Exports;
|
|
5
|
+
(internal: unknown, props: {
|
|
6
|
+
$$events?: Events;
|
|
7
|
+
$$slots?: Slots;
|
|
8
|
+
}): Exports & {
|
|
9
|
+
$set?: any;
|
|
10
|
+
$on?: any;
|
|
11
|
+
};
|
|
12
|
+
z_$$bindings?: Bindings;
|
|
13
|
+
}
|
|
14
|
+
declare const Hands: $$__sveltets_2_IsomorphicComponent<Record<string, never>, {
|
|
15
|
+
[evt: string]: CustomEvent<any>;
|
|
16
|
+
}, {}, {}, string>;
|
|
17
|
+
type Hands = InstanceType<typeof Hands>;
|
|
18
|
+
export default Hands;
|
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { T, useTask } from '@threlte/core'
|
|
3
|
+
import { Grid, useGamepad } from '@threlte/extras'
|
|
4
|
+
import { Collider, RigidBody } from '@threlte/rapier'
|
|
5
|
+
import { RigidBody as RigidBodyType } from '@dimforge/rapier3d-compat'
|
|
6
|
+
import { useController } from '@threlte/xr'
|
|
7
|
+
import { Group, Mesh, Quaternion, Vector3 } from 'three'
|
|
8
|
+
|
|
9
|
+
const height = 0.1
|
|
10
|
+
const radius = 0.05
|
|
11
|
+
|
|
12
|
+
const group = new Group()
|
|
13
|
+
const mesh = new Mesh()
|
|
14
|
+
|
|
15
|
+
const vec3 = new Vector3()
|
|
16
|
+
const quaternion = new Quaternion()
|
|
17
|
+
|
|
18
|
+
const offset = new Vector3()
|
|
19
|
+
const position = new Vector3()
|
|
20
|
+
|
|
21
|
+
let hovering = $state(false)
|
|
22
|
+
let dragging = $state(false)
|
|
23
|
+
let rotating = $state(false)
|
|
24
|
+
|
|
25
|
+
let rigidBody: RigidBodyType | undefined = $state()
|
|
26
|
+
|
|
27
|
+
const left = useController('left')
|
|
28
|
+
const leftPad = useGamepad({ xr: true, hand: 'left' })
|
|
29
|
+
|
|
30
|
+
leftPad.trigger.on('down', () => {
|
|
31
|
+
dragging = true
|
|
32
|
+
mesh.getWorldPosition(vec3)
|
|
33
|
+
offset.copy($left!.grip.position).sub(vec3)
|
|
34
|
+
})
|
|
35
|
+
leftPad.trigger.on('up', () => (dragging = false))
|
|
36
|
+
|
|
37
|
+
leftPad.squeeze.on('down', () => {
|
|
38
|
+
rotating = true
|
|
39
|
+
mesh.getWorldQuaternion(quaternion)
|
|
40
|
+
})
|
|
41
|
+
leftPad.squeeze.on('up', () => (rotating = false))
|
|
42
|
+
|
|
43
|
+
const onsensorenter = () => (hovering = true)
|
|
44
|
+
const onsensorexit = () => (hovering = false)
|
|
45
|
+
|
|
46
|
+
const { start, stop } = useTask(
|
|
47
|
+
() => {
|
|
48
|
+
if (!$left || !rigidBody) return
|
|
49
|
+
|
|
50
|
+
position.copy($left.grip.position).sub(offset)
|
|
51
|
+
|
|
52
|
+
rigidBody.setNextKinematicTranslation({ x: position.x, y: position.y, z: position.z })
|
|
53
|
+
},
|
|
54
|
+
{ autoStart: false }
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
$effect(() => (hovering && dragging ? start() : stop()))
|
|
58
|
+
</script>
|
|
59
|
+
|
|
60
|
+
{#if rotating}
|
|
61
|
+
<!-- TODO -->
|
|
62
|
+
{/if}
|
|
63
|
+
|
|
64
|
+
<T
|
|
65
|
+
is={group}
|
|
66
|
+
position={[0, 0.05, 0]}
|
|
67
|
+
>
|
|
68
|
+
<RigidBody
|
|
69
|
+
bind:rigidBody
|
|
70
|
+
type="kinematicPosition"
|
|
71
|
+
>
|
|
72
|
+
<Collider
|
|
73
|
+
sensor
|
|
74
|
+
shape="cone"
|
|
75
|
+
args={[height / 2, radius]}
|
|
76
|
+
{onsensorenter}
|
|
77
|
+
{onsensorexit}
|
|
78
|
+
>
|
|
79
|
+
<T is={mesh}>
|
|
80
|
+
<T.ConeGeometry
|
|
81
|
+
args={[radius, height]}
|
|
82
|
+
oncreate={(ref) => {
|
|
83
|
+
ref.rotateX(-Math.PI / 2)
|
|
84
|
+
ref.translate(0, 0, height / 2)
|
|
85
|
+
}}
|
|
86
|
+
/>
|
|
87
|
+
<T.MeshStandardMaterial color={hovering ? 'hotpink' : 'red'} />
|
|
88
|
+
|
|
89
|
+
<Grid
|
|
90
|
+
plane="xy"
|
|
91
|
+
position.y={0.05}
|
|
92
|
+
fadeDistance={1}
|
|
93
|
+
cellSize={0.1}
|
|
94
|
+
cellColor="#fff"
|
|
95
|
+
sectionColor="#fff"
|
|
96
|
+
/>
|
|
97
|
+
</T>
|
|
98
|
+
</Collider>
|
|
99
|
+
</RigidBody>
|
|
100
|
+
</T>
|