@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.
Files changed (148) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +20 -0
  3. package/dist/WorldObject.d.ts +33 -0
  4. package/dist/WorldObject.js +18 -0
  5. package/dist/assert.d.ts +14 -0
  6. package/dist/assert.js +21 -0
  7. package/dist/color.d.ts +8 -0
  8. package/dist/color.js +14 -0
  9. package/dist/components/App.svelte +63 -0
  10. package/dist/components/App.svelte.d.ts +8 -0
  11. package/dist/components/AxesHelper.svelte +17 -0
  12. package/dist/components/AxesHelper.svelte.d.ts +4 -0
  13. package/dist/components/BentPlaneGeometry.svelte +52 -0
  14. package/dist/components/BentPlaneGeometry.svelte.d.ts +29 -0
  15. package/dist/components/Camera.svelte +45 -0
  16. package/dist/components/Camera.svelte.d.ts +5 -0
  17. package/dist/components/CameraControls.svelte +82 -0
  18. package/dist/components/CameraControls.svelte.d.ts +9 -0
  19. package/dist/components/Details.svelte +161 -0
  20. package/dist/components/Details.svelte.d.ts +3 -0
  21. package/dist/components/Detections.svelte +41 -0
  22. package/dist/components/Detections.svelte.d.ts +3 -0
  23. package/dist/components/DetectionsPlane.svelte +23 -0
  24. package/dist/components/DetectionsPlane.svelte.d.ts +21 -0
  25. package/dist/components/DomPortal.svelte +20 -0
  26. package/dist/components/DomPortal.svelte.d.ts +5 -0
  27. package/dist/components/Focus.svelte +49 -0
  28. package/dist/components/Focus.svelte.d.ts +3 -0
  29. package/dist/components/Frame.svelte +112 -0
  30. package/dist/components/Frame.svelte.d.ts +16 -0
  31. package/dist/components/Frames.svelte +54 -0
  32. package/dist/components/Frames.svelte.d.ts +18 -0
  33. package/dist/components/Pointcloud.svelte +55 -0
  34. package/dist/components/Pointcloud.svelte.d.ts +10 -0
  35. package/dist/components/Pointclouds.svelte +21 -0
  36. package/dist/components/Pointclouds.svelte.d.ts +18 -0
  37. package/dist/components/Pose.svelte +19 -0
  38. package/dist/components/Pose.svelte.d.ts +12 -0
  39. package/dist/components/RefreshRate.svelte +47 -0
  40. package/dist/components/RefreshRate.svelte.d.ts +8 -0
  41. package/dist/components/Scene.svelte +81 -0
  42. package/dist/components/Scene.svelte.d.ts +7 -0
  43. package/dist/components/SceneProviders.svelte +41 -0
  44. package/dist/components/SceneProviders.svelte.d.ts +9 -0
  45. package/dist/components/Selected.svelte +44 -0
  46. package/dist/components/Selected.svelte.d.ts +3 -0
  47. package/dist/components/Shapes.svelte +49 -0
  48. package/dist/components/Shapes.svelte.d.ts +18 -0
  49. package/dist/components/StaticGeometries.svelte +79 -0
  50. package/dist/components/StaticGeometries.svelte.d.ts +18 -0
  51. package/dist/components/Tree/Settings.svelte +54 -0
  52. package/dist/components/Tree/Settings.svelte.d.ts +18 -0
  53. package/dist/components/Tree/Tree.svelte +204 -0
  54. package/dist/components/Tree/Tree.svelte.d.ts +10 -0
  55. package/dist/components/Tree/TreeContainer.svelte +70 -0
  56. package/dist/components/Tree/TreeContainer.svelte.d.ts +3 -0
  57. package/dist/components/Tree/buildTree.d.ts +11 -0
  58. package/dist/components/Tree/buildTree.js +29 -0
  59. package/dist/components/Tree/useExpanded.svelte.d.ts +5 -0
  60. package/dist/components/Tree/useExpanded.svelte.js +21 -0
  61. package/dist/components/WorldObject.svelte +27 -0
  62. package/dist/components/WorldObject.svelte.d.ts +11 -0
  63. package/dist/components/XR.svelte +20 -0
  64. package/dist/components/XR.svelte.d.ts +3 -0
  65. package/dist/components/models/README.md +5 -0
  66. package/dist/components/null-states/Connection.svelte +0 -0
  67. package/dist/components/null-states/Connection.svelte.d.ts +26 -0
  68. package/dist/components/portal/Portal.svelte +25 -0
  69. package/dist/components/portal/Portal.svelte.d.ts +8 -0
  70. package/dist/components/portal/PortalTarget.svelte +18 -0
  71. package/dist/components/portal/PortalTarget.svelte.d.ts +6 -0
  72. package/dist/components/portal/index.d.ts +2 -0
  73. package/dist/components/portal/index.js +2 -0
  74. package/dist/components/portal/usePortalContext.svelte.d.ts +5 -0
  75. package/dist/components/portal/usePortalContext.svelte.js +8 -0
  76. package/dist/components/xr/CameraFeed.svelte +81 -0
  77. package/dist/components/xr/CameraFeed.svelte.d.ts +6 -0
  78. package/dist/components/xr/Controllers.svelte +71 -0
  79. package/dist/components/xr/Controllers.svelte.d.ts +3 -0
  80. package/dist/components/xr/Draggable.svelte +101 -0
  81. package/dist/components/xr/Draggable.svelte.d.ts +11 -0
  82. package/dist/components/xr/HandCollider.svelte +19 -0
  83. package/dist/components/xr/HandCollider.svelte.d.ts +18 -0
  84. package/dist/components/xr/Hands.svelte +24 -0
  85. package/dist/components/xr/Hands.svelte.d.ts +18 -0
  86. package/dist/components/xr/OriginMarker.svelte +100 -0
  87. package/dist/components/xr/OriginMarker.svelte.d.ts +3 -0
  88. package/dist/components/xr/PointDistance.svelte +52 -0
  89. package/dist/components/xr/PointDistance.svelte.d.ts +3 -0
  90. package/dist/hooks/index.d.ts +1 -0
  91. package/dist/hooks/index.js +1 -0
  92. package/dist/hooks/useConnectionConfigs.svelte.d.ts +17 -0
  93. package/dist/hooks/useConnectionConfigs.svelte.js +40 -0
  94. package/dist/hooks/useControls.svelte.d.ts +7 -0
  95. package/dist/hooks/useControls.svelte.js +16 -0
  96. package/dist/hooks/useDraggable.svelte.d.ts +2 -0
  97. package/dist/hooks/useDraggable.svelte.js +25 -0
  98. package/dist/hooks/useFrames.svelte.d.ts +9 -0
  99. package/dist/hooks/useFrames.svelte.js +50 -0
  100. package/dist/hooks/useGeometries.svelte.d.ts +7 -0
  101. package/dist/hooks/useGeometries.svelte.js +58 -0
  102. package/dist/hooks/useMotionClient.svelte.d.ts +8 -0
  103. package/dist/hooks/useMotionClient.svelte.js +31 -0
  104. package/dist/hooks/useObjectEvents.svelte.d.ts +9 -0
  105. package/dist/hooks/useObjectEvents.svelte.js +31 -0
  106. package/dist/hooks/useObjects.svelte.d.ts +7 -0
  107. package/dist/hooks/useObjects.svelte.js +33 -0
  108. package/dist/hooks/usePartID.svelte.d.ts +6 -0
  109. package/dist/hooks/usePartID.svelte.js +14 -0
  110. package/dist/hooks/usePersistentUUIDs.svelte.d.ts +5 -0
  111. package/dist/hooks/usePersistentUUIDs.svelte.js +14 -0
  112. package/dist/hooks/usePointclouds.svelte.d.ts +7 -0
  113. package/dist/hooks/usePointclouds.svelte.js +58 -0
  114. package/dist/hooks/usePose.svelte.d.ts +3 -0
  115. package/dist/hooks/usePose.svelte.js +44 -0
  116. package/dist/hooks/usePoses.svelte.d.ts +12 -0
  117. package/dist/hooks/usePoses.svelte.js +63 -0
  118. package/dist/hooks/useRefreshRates.svelte.d.ts +5 -0
  119. package/dist/hooks/useRefreshRates.svelte.js +23 -0
  120. package/dist/hooks/useSelection.svelte.d.ts +40 -0
  121. package/dist/hooks/useSelection.svelte.js +92 -0
  122. package/dist/hooks/useShapes.svelte.d.ts +17 -0
  123. package/dist/hooks/useShapes.svelte.js +264 -0
  124. package/dist/hooks/useStaticGeometries.svelte.d.ts +9 -0
  125. package/dist/hooks/useStaticGeometries.svelte.js +37 -0
  126. package/dist/hooks/useVisibility.svelte.d.ts +5 -0
  127. package/dist/hooks/useVisibility.svelte.js +22 -0
  128. package/dist/hooks/xr/useAnchors.svelte.d.ts +0 -0
  129. package/dist/hooks/xr/useAnchors.svelte.js +1 -0
  130. package/dist/index.d.ts +1 -0
  131. package/dist/index.js +1 -0
  132. package/dist/keybindings.d.ts +12 -0
  133. package/dist/keybindings.js +12 -0
  134. package/dist/loaders/pcd/index.d.ts +4 -0
  135. package/dist/loaders/pcd/index.js +13 -0
  136. package/dist/loaders/pcd/worker.d.ts +1 -0
  137. package/dist/loaders/pcd/worker.js +26 -0
  138. package/dist/three/AxesHelper.d.ts +5 -0
  139. package/dist/three/AxesHelper.js +35 -0
  140. package/dist/three/BatchedArrow.d.ts +30 -0
  141. package/dist/three/BatchedArrow.js +126 -0
  142. package/dist/three/BoxHelper.d.ts +50 -0
  143. package/dist/three/BoxHelper.js +134 -0
  144. package/dist/three/CapsuleGeometry.d.ts +10 -0
  145. package/dist/three/CapsuleGeometry.js +17 -0
  146. package/dist/transform.d.ts +11 -0
  147. package/dist/transform.js +65 -0
  148. 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>
@@ -0,0 +1,3 @@
1
+ declare const Xr: import("svelte").Component<Record<string, never>, {}, "">;
2
+ type Xr = ReturnType<typeof Xr>;
3
+ export default Xr;
@@ -0,0 +1,5 @@
1
+ # Threlte Model Pipeline Components
2
+
3
+ This directory holds automatically generated Threlte components from GLTF models.
4
+
5
+ Place your models in `static/models` and run `npm run model-pipeline:run` to generate the components.
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,8 @@
1
+ import type { Snippet } from 'svelte';
2
+ interface Props {
3
+ id?: string;
4
+ children?: Snippet;
5
+ }
6
+ declare const Portal: import("svelte").Component<Props, {}, "">;
7
+ type Portal = ReturnType<typeof Portal>;
8
+ export default Portal;
@@ -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,6 @@
1
+ interface Props {
2
+ id?: string;
3
+ }
4
+ declare const PortalTarget: import("svelte").Component<Props, {}, "">;
5
+ type PortalTarget = ReturnType<typeof PortalTarget>;
6
+ export default PortalTarget;
@@ -0,0 +1,2 @@
1
+ export { default as Portal } from './Portal.svelte';
2
+ export { default as PortalTarget } from './PortalTarget.svelte';
@@ -0,0 +1,2 @@
1
+ export { default as Portal } from './Portal.svelte';
2
+ export { default as PortalTarget } from './PortalTarget.svelte';
@@ -0,0 +1,5 @@
1
+ import type { Snippet } from 'svelte';
2
+ import { SvelteMap, SvelteSet } from 'svelte/reactivity';
3
+ type PortalContext = SvelteMap<string, SvelteSet<Snippet>>;
4
+ export declare const usePortalContext: () => PortalContext;
5
+ export {};
@@ -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,6 @@
1
+ interface CameraFeedProps {
2
+ resourceName: string;
3
+ }
4
+ declare const CameraFeed: import("svelte").Component<CameraFeedProps, {}, "">;
5
+ type CameraFeed = ReturnType<typeof CameraFeed>;
6
+ export default CameraFeed;
@@ -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,3 @@
1
+ declare const Controllers: import("svelte").Component<Record<string, never>, {}, "">;
2
+ type Controllers = ReturnType<typeof Controllers>;
3
+ export default Controllers;
@@ -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>
@@ -0,0 +1,3 @@
1
+ declare const OriginMarker: import("svelte").Component<Record<string, never>, {}, "">;
2
+ type OriginMarker = ReturnType<typeof OriginMarker>;
3
+ export default OriginMarker;