@viamrobotics/motion-tools 0.5.2 → 0.5.3

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 CHANGED
@@ -9,31 +9,6 @@ To visit the visualizer, go to `http://localhost:5173/`
9
9
 
10
10
  Open the machine config page (bottom right) and enter in connection details to visualize a specific machine.
11
11
 
12
- ## Todo
13
-
14
- ----- hard -----
15
-
16
- - animated sequence of motion plan
17
- - Give better fetching / connection state info
18
- - configure frames in app
19
- - embed in teleop
20
-
21
- ----- medium -----
22
-
23
- - remote IP access when custom drawing, to draw on remote computers
24
- - geometries need to be parented to parent
25
- - color pallet for resource to color
26
- - measurement tool
27
-
28
- ----- easy ------
29
-
30
- - double click to set trackball center in object view
31
- - Set default pointcloud color in settings
32
- - points are not sized right in ortho cam view
33
- - bounding boxes should include just the thing and not children
34
-
35
- --- action items ----
36
-
37
12
  ## Env files
38
13
 
39
14
  To add a list of connection configs in an `.env.local` file, use the following format:
package/dist/color.js CHANGED
@@ -14,7 +14,7 @@ const toHex = (x) => {
14
14
  const oklchToHex = (raw) => {
15
15
  const match = raw.match(/oklch\(\s*([\d.]+)%\s+([\d.]+)\s+([\d.]+)\s*\)/);
16
16
  if (!match) {
17
- return '#000000';
17
+ return raw;
18
18
  }
19
19
  const l = parseFloat(match[1]) / 100;
20
20
  const c = parseFloat(match[2]);
@@ -33,10 +33,10 @@
33
33
  {#snippet children({ focus })}
34
34
  <Scene>
35
35
  {@render appChildren?.()}
36
-
37
- <XR />
38
36
  </Scene>
39
37
 
38
+ <XR />
39
+
40
40
  <DomPortal element={root}>
41
41
  <Dashboard />
42
42
  <Details />
@@ -64,7 +64,8 @@
64
64
  {...rest}
65
65
  >
66
66
  {#if geometry?.case === 'mesh'}
67
- {@const meshGeometry = plyLoader.parse(atob(geometry.value.mesh as unknown as string))}
67
+ {@const mesh = geometry.value.mesh as Uint8Array<ArrayBuffer>}
68
+ {@const meshGeometry = plyLoader.parse(typeof mesh === 'string' ? atob(mesh) : mesh.buffer)}
68
69
  <T
69
70
  is={meshGeometry}
70
71
  {oncreate}
@@ -1,13 +1,13 @@
1
1
  <script lang="ts">
2
2
  import { MathUtils } from 'three'
3
3
  import { useTask } from '@threlte/core'
4
- import type CameraController from 'camera-controls'
4
+ import type { CameraControlsRef } from '@threlte/extras'
5
5
  import { PressedKeys } from 'runed'
6
6
  import { useFocused } from '../hooks/useSelection.svelte'
7
7
  import { useSettings } from '../hooks/useSettings.svelte'
8
8
 
9
9
  interface Props {
10
- cameraControls: CameraController
10
+ cameraControls: CameraControlsRef
11
11
  }
12
12
 
13
13
  let { cameraControls }: Props = $props()
@@ -1,6 +1,6 @@
1
- import type CameraController from 'camera-controls';
1
+ import type { CameraControlsRef } from '@threlte/extras';
2
2
  interface Props {
3
- cameraControls: CameraController;
3
+ cameraControls: CameraControlsRef;
4
4
  }
5
5
  declare const KeyboardControls: import("svelte").Component<Props, {}, "">;
6
6
  type KeyboardControls = ReturnType<typeof KeyboardControls>;
@@ -1,11 +1,16 @@
1
1
  <script lang="ts">
2
2
  import { Color, Vector3 } from 'three'
3
3
  import { T } from '@threlte/core'
4
- import { Gizmo, Grid, interactivity } from '@threlte/extras'
4
+ import {
5
+ CameraControls,
6
+ type CameraControlsRef,
7
+ Gizmo,
8
+ Grid,
9
+ interactivity,
10
+ } from '@threlte/extras'
5
11
  import { PortalTarget } from './portal'
6
12
  import Frames from './Frames.svelte'
7
13
  import Pointclouds from './Pointclouds.svelte'
8
- import CameraControls from './CameraControls.svelte'
9
14
  import Selected from './Selected.svelte'
10
15
  import Focus from './Focus.svelte'
11
16
  import StaticGeometries from './StaticGeometries.svelte'
@@ -16,6 +21,7 @@
16
21
  import { useXR } from '@threlte/xr'
17
22
  import { useTransformControls } from '../hooks/useControls.svelte'
18
23
  import KeyboardControls from './KeyboardControls.svelte'
24
+ import { useOrigin } from './xr/useOrigin.svelte'
19
25
 
20
26
  interface Props {
21
27
  children?: Snippet
@@ -35,6 +41,7 @@
35
41
 
36
42
  const focused = useFocused()
37
43
  const transformControls = useTransformControls()
44
+ const origin = useOrigin()
38
45
 
39
46
  const { isPresenting } = useXR()
40
47
  </script>
@@ -44,12 +51,16 @@
44
51
  args={[new Color('white')]}
45
52
  />
46
53
 
47
- <T.Group rotation.x={$isPresenting ? -Math.PI / 2 : 0}>
54
+ <T.Group
55
+ position={origin.position}
56
+ rotation.x={$isPresenting ? -Math.PI / 2 : 0}
57
+ rotation.z={origin.rotation}
58
+ >
48
59
  {#if focused.current === undefined}
49
60
  {#if !$isPresenting}
50
61
  <Camera position={[3, 3, 3]}>
51
62
  <CameraControls enabled={!transformControls.active}>
52
- {#snippet children({ ref })}
63
+ {#snippet children({ ref }: { ref: CameraControlsRef })}
53
64
  <KeyboardControls cameraControls={ref} />
54
65
  <Gizmo />
55
66
  {/snippet}
@@ -14,6 +14,7 @@
14
14
  import { provideMotionClient } from '../hooks/useMotionClient.svelte'
15
15
  import { provideLogs } from '../hooks/useLogs.svelte'
16
16
  import { provideSettings } from '../hooks/useSettings.svelte'
17
+ import { provideOrigin } from './xr/useOrigin.svelte'
17
18
 
18
19
  interface Props {
19
20
  children: Snippet<[{ focus: boolean }]>
@@ -29,6 +30,7 @@
29
30
  provideRefreshRates()
30
31
  provideLogs()
31
32
 
33
+ provideOrigin()
32
34
  provideStaticGeometries()
33
35
  provideShapes()
34
36
 
@@ -8,11 +8,11 @@
8
8
  let { id = 'default' }: Props = $props()
9
9
 
10
10
  const portals = usePortalContext()
11
- const childArray = $derived(portals.get(id))
11
+ const childrenArray = $derived(portals.get(id))
12
12
  </script>
13
13
 
14
- {#if childArray}
15
- {#each childArray as children (children)}
16
- {@render children?.()}
14
+ {#if childrenArray !== undefined}
15
+ {#each childrenArray as children (children)}
16
+ {@render children()}
17
17
  {/each}
18
18
  {/if}
@@ -1,56 +1,48 @@
1
1
  <script lang="ts">
2
2
  import { Controller } from '@threlte/xr'
3
- import { useGamepad } from '@threlte/extras'
3
+ // import { useGamepad } from '@threlte/extras'
4
4
 
5
- import { BaseClient } from '@viamrobotics/sdk'
5
+ // import { BaseClient } from '@viamrobotics/sdk'
6
6
 
7
7
  import { RigidBody } from '@threlte/rapier'
8
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 = () => {}
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
+ // })
47
43
  </script>
48
44
 
49
- <Controller
50
- left
51
- {onselectstart}
52
- {onselectend}
53
- >
45
+ <Controller left>
54
46
  {#snippet grip()}
55
47
  <RigidBody type="kinematicPosition">
56
48
  <HandCollider />
@@ -58,11 +50,7 @@
58
50
  {/snippet}
59
51
  </Controller>
60
52
 
61
- <Controller
62
- right
63
- {onselectstart}
64
- {onselectend}
65
- >
53
+ <Controller right>
66
54
  {#snippet grip()}
67
55
  <RigidBody type="kinematicPosition">
68
56
  <HandCollider />
@@ -1,3 +1,18 @@
1
- declare const Controllers: import("svelte").Component<Record<string, never>, {}, "">;
2
- type Controllers = ReturnType<typeof Controllers>;
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 Controllers: $$__sveltets_2_IsomorphicComponent<Record<string, never>, {
15
+ [evt: string]: CustomEvent<any>;
16
+ }, {}, {}, string>;
17
+ type Controllers = InstanceType<typeof Controllers>;
3
18
  export default Controllers;
@@ -2,6 +2,7 @@
2
2
  import { Hand } from '@threlte/xr'
3
3
 
4
4
  console.log('hands')
5
+
5
6
  const onpinchstart = () => {
6
7
  console.log('start')
7
8
  }
@@ -4,62 +4,112 @@
4
4
  import { Collider, RigidBody } from '@threlte/rapier'
5
5
  import { RigidBody as RigidBodyType } from '@dimforge/rapier3d-compat'
6
6
  import { useController } from '@threlte/xr'
7
- import { Group, Mesh, Quaternion, Vector3 } from 'three'
7
+ import { Euler, Group, Quaternion, Vector3 } from 'three'
8
+ import { useOrigin } from './useOrigin.svelte'
9
+
10
+ const origin = useOrigin()
8
11
 
9
12
  const height = 0.1
10
13
  const radius = 0.05
11
14
 
12
15
  const group = new Group()
13
- const mesh = new Mesh()
16
+ const innerGroup = new Group()
14
17
 
15
18
  const vec3 = new Vector3()
19
+
16
20
  const quaternion = new Quaternion()
21
+ const euler = new Euler()
17
22
 
18
23
  const offset = new Vector3()
24
+
19
25
  const position = new Vector3()
20
26
 
21
- let hovering = $state(false)
22
27
  let dragging = $state(false)
23
28
  let rotating = $state(false)
24
29
 
25
- let rigidBody: RigidBodyType | undefined = $state()
30
+ let currentDistance = 0
31
+ const rotateDown = new Vector3()
32
+
33
+ let rigidBody = $state<RigidBodyType>()
26
34
 
27
35
  const left = useController('left')
36
+ const right = useController('right')
37
+
28
38
  const leftPad = useGamepad({ xr: true, hand: 'left' })
39
+ const rightPad = useGamepad({ xr: true, hand: 'right' })
29
40
 
30
41
  leftPad.trigger.on('down', () => {
42
+ const grip = $left?.grip
43
+
44
+ if (!grip) {
45
+ return
46
+ }
47
+
31
48
  dragging = true
32
- mesh.getWorldPosition(vec3)
49
+ innerGroup.getWorldPosition(vec3)
33
50
  offset.copy($left!.grip.position).sub(vec3)
34
51
  })
35
52
  leftPad.trigger.on('up', () => (dragging = false))
36
53
 
37
- leftPad.squeeze.on('down', () => {
54
+ rightPad.trigger.on('down', () => {
55
+ const grip = $right?.grip
56
+
57
+ if (!grip) {
58
+ return
59
+ }
60
+
38
61
  rotating = true
39
- mesh.getWorldQuaternion(quaternion)
62
+ rotateDown.copy($right?.grip.position)
63
+ currentDistance = euler.z
40
64
  })
41
- leftPad.squeeze.on('up', () => (rotating = false))
42
-
43
- const onsensorenter = () => (hovering = true)
44
- const onsensorexit = () => (hovering = false)
65
+ rightPad.trigger.on('up', () => (rotating = false))
45
66
 
46
- const { start, stop } = useTask(
67
+ const dragTask = useTask(
47
68
  () => {
48
69
  if (!$left || !rigidBody) return
49
70
 
50
71
  position.copy($left.grip.position).sub(offset)
51
72
 
73
+ origin.set(position)
74
+
52
75
  rigidBody.setNextKinematicTranslation({ x: position.x, y: position.y, z: position.z })
53
76
  },
54
77
  { autoStart: false }
55
78
  )
56
79
 
57
- $effect(() => (hovering && dragging ? start() : stop()))
58
- </script>
80
+ const rotateTask = useTask(
81
+ () => {
82
+ if (!$right || !rigidBody) return
59
83
 
60
- {#if rotating}
61
- <!-- TODO -->
62
- {/if}
84
+ const distance = rotateDown.distanceToSquared($right.grip.position)
85
+
86
+ const rotation = rigidBody.rotation()
87
+ quaternion.copy(rotation)
88
+ euler.setFromQuaternion(quaternion)
89
+ euler.z = distance + currentDistance
90
+ origin.set(undefined, euler.z)
91
+
92
+ rigidBody.setNextKinematicRotation(quaternion.setFromEuler(euler))
93
+ },
94
+ { autoStart: false }
95
+ )
96
+
97
+ $effect.pre(() => {
98
+ if (dragging) {
99
+ dragTask.start()
100
+ } else {
101
+ dragTask.stop()
102
+ }
103
+ })
104
+
105
+ $effect.pre(() => {
106
+ if (rotating) {
107
+ rotateTask.start()
108
+ } else {
109
+ rotateTask.stop()
110
+ }
111
+ })
112
+ </script>
63
113
 
64
114
  <T
65
115
  is={group}
@@ -73,23 +123,13 @@
73
123
  sensor
74
124
  shape="cone"
75
125
  args={[height / 2, radius]}
76
- {onsensorenter}
77
- {onsensorexit}
78
126
  >
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
-
127
+ <T is={innerGroup}>
89
128
  <Grid
90
129
  plane="xy"
91
130
  position.y={0.05}
92
- fadeDistance={1}
131
+ fadeDistance={5}
132
+ fadeOrigin={new Vector3()}
93
133
  cellSize={0.1}
94
134
  cellColor="#fff"
95
135
  sectionColor="#fff"
@@ -1,16 +1,23 @@
1
1
  <script lang="ts">
2
- import { XR, XRButton } from '@threlte/xr'
2
+ import { T } from '@threlte/core'
3
+ import { useXR, XR, XRButton } from '@threlte/xr'
3
4
  import OriginMarker from './OriginMarker.svelte'
4
5
  import DomPortal from '../DomPortal.svelte'
5
6
  import { useSettings } from '../../hooks/useSettings.svelte'
7
+ import Controllers from './Controllers.svelte'
6
8
 
9
+ const { isPresenting } = useXR()
7
10
  const settings = useSettings()
8
11
  const enableXR = $derived(settings.current.enableXR)
9
12
  </script>
10
13
 
11
14
  {#if enableXR}
12
15
  <XR>
13
- <OriginMarker />
16
+ <T.Group rotation.x={$isPresenting ? -Math.PI / 2 : 0}>
17
+ <OriginMarker />
18
+ </T.Group>
19
+
20
+ <Controllers />
14
21
  </XR>
15
22
 
16
23
  <DomPortal>
@@ -0,0 +1,2 @@
1
+ export declare const provideAnchors: () => void;
2
+ export declare const useAnchors: () => void;
@@ -0,0 +1,55 @@
1
+ import { useTask, useThrelte, watch } from '@threlte/core';
2
+ import { useXR } from '@threlte/xr';
3
+ import { getContext, setContext } from 'svelte';
4
+ import { Matrix4 } from 'three';
5
+ const key = Symbol('anchors-context');
6
+ export const provideAnchors = () => {
7
+ const matrix4 = new Matrix4();
8
+ const { renderer } = useThrelte();
9
+ const { xrFrame, isPresenting } = useXR();
10
+ const map = new WeakMap();
11
+ let space = renderer.xr.getReferenceSpace();
12
+ const createAnchor = (position, orientation) => {
13
+ space ??= renderer.xr.getReferenceSpace();
14
+ if (space === null)
15
+ return;
16
+ const pose = new XRRigidTransform(position, orientation);
17
+ return xrFrame.current.createAnchor?.(pose, space);
18
+ };
19
+ const { start, stop } = useTask(() => {
20
+ space ??= renderer.xr.getReferenceSpace();
21
+ if (!space) {
22
+ return;
23
+ }
24
+ const frame = xrFrame.current;
25
+ if (!frame.trackedAnchors) {
26
+ return;
27
+ }
28
+ for (const anchor of frame.trackedAnchors) {
29
+ const object3d = map.get(anchor);
30
+ if (!object3d) {
31
+ continue;
32
+ }
33
+ const anchorPose = frame.getPose(anchor.anchorSpace, space);
34
+ if (!anchorPose) {
35
+ continue;
36
+ }
37
+ matrix4.fromArray(anchorPose.transform.matrix);
38
+ object3d.applyMatrix4(matrix4);
39
+ }
40
+ });
41
+ watch(isPresenting, ($isPresenting) => {
42
+ if ($isPresenting) {
43
+ start();
44
+ }
45
+ else {
46
+ stop();
47
+ }
48
+ });
49
+ setContext(key, {
50
+ createAnchor,
51
+ });
52
+ };
53
+ export const useAnchors = () => {
54
+ getContext(key);
55
+ };
@@ -0,0 +1,9 @@
1
+ import type { Vector3, Vector3Tuple } from 'three';
2
+ interface Context {
3
+ position: Vector3Tuple;
4
+ rotation: number;
5
+ set: (pos?: Vector3, rot?: number) => void;
6
+ }
7
+ export declare const provideOrigin: () => void;
8
+ export declare const useOrigin: () => Context;
9
+ export {};
@@ -0,0 +1,27 @@
1
+ import { getContext, setContext } from 'svelte';
2
+ const key = Symbol('origin-context');
3
+ export const provideOrigin = () => {
4
+ const position = $state([0, 0, 0]);
5
+ let rotation = $state(0);
6
+ setContext(key, {
7
+ get position() {
8
+ return position;
9
+ },
10
+ get rotation() {
11
+ return rotation;
12
+ },
13
+ set(pos, rot) {
14
+ if (pos) {
15
+ position[0] = pos.x;
16
+ position[1] = pos.y;
17
+ position[2] = pos.z;
18
+ }
19
+ if (rot) {
20
+ rotation = rot;
21
+ }
22
+ },
23
+ });
24
+ };
25
+ export const useOrigin = () => {
26
+ return getContext(key);
27
+ };
package/dist/lib.d.ts CHANGED
@@ -1,5 +1,3 @@
1
- export { default as CameraControls } from './components/CameraControls.svelte';
2
- export { type default as CameraController } from 'camera-controls';
3
1
  export { default as Geometry } from './components/Geometry.svelte';
4
2
  export { default as AxesHelper } from './components/AxesHelper.svelte';
5
3
  export { BatchedArrow } from './three/BatchedArrow';
package/dist/lib.js CHANGED
@@ -1,6 +1,4 @@
1
1
  // Components
2
- export { default as CameraControls } from './components/CameraControls.svelte';
3
- export {} from 'camera-controls';
4
2
  export { default as Geometry } from './components/Geometry.svelte';
5
3
  export { default as AxesHelper } from './components/AxesHelper.svelte';
6
4
  // Classes
package/package.json CHANGED
@@ -1,71 +1,72 @@
1
1
  {
2
2
  "name": "@viamrobotics/motion-tools",
3
- "version": "0.5.2",
3
+ "version": "0.5.3",
4
4
  "description": "Motion visualization with Viam",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
7
7
  "devDependencies": {
8
- "@ag-grid-community/client-side-row-model": "^32.3.5",
9
- "@ag-grid-community/core": "^32.3.5",
10
- "@ag-grid-community/styles": "^32.3.5",
11
- "@changesets/cli": "^2.29.4",
12
- "@dimforge/rapier3d-compat": "^0.17.3",
13
- "@eslint/compat": "^1.2.9",
14
- "@eslint/js": "^9.28.0",
15
- "@playwright/test": "^1.52.0",
8
+ "@ag-grid-community/client-side-row-model": "32.3.5",
9
+ "@ag-grid-community/core": "32.3.5",
10
+ "@ag-grid-community/styles": "32.3.5",
11
+ "@changesets/cli": "2.29.4",
12
+ "@dimforge/rapier3d-compat": "0.17.3",
13
+ "@eslint/compat": "1.3.0",
14
+ "@eslint/js": "9.28.0",
15
+ "@playwright/test": "1.53.0",
16
16
  "@skeletonlabs/skeleton": "3.1.3",
17
17
  "@skeletonlabs/skeleton-svelte": "1.2.3",
18
- "@sveltejs/adapter-static": "^3.0.8",
19
- "@sveltejs/kit": "^2.21.4",
20
- "@sveltejs/package": "^2.3.11",
21
- "@sveltejs/vite-plugin-svelte": "^5.1.0",
22
- "@tailwindcss/forms": "^0.5.10",
23
- "@tailwindcss/vite": "^4.1.8",
24
- "@tanstack/svelte-query": "^5.80.6",
25
- "@tanstack/svelte-query-devtools": "^5.80.6",
26
- "@testing-library/jest-dom": "^6.6.3",
27
- "@testing-library/svelte": "^5.2.8",
28
- "@threlte/core": "^8.0.4",
29
- "@threlte/extras": "^9.2.1",
30
- "@threlte/rapier": "^3.1.4",
31
- "@threlte/xr": "^1.0.6",
32
- "@types/bun": "^1.2.15",
33
- "@types/lodash-es": "^4.17.12",
34
- "@types/three": "^0.177.0",
35
- "@typescript-eslint/eslint-plugin": "^8.34.0",
36
- "@typescript-eslint/parser": "^8.34.0",
37
- "@viamrobotics/prime-core": "^0.1.5",
18
+ "@sveltejs/adapter-static": "3.0.8",
19
+ "@sveltejs/kit": "2.21.4",
20
+ "@sveltejs/package": "2.3.11",
21
+ "@sveltejs/vite-plugin-svelte": "5.1.0",
22
+ "@tailwindcss/forms": "0.5.10",
23
+ "@tailwindcss/vite": "4.1.10",
24
+ "@tanstack/svelte-query": "5.80.6",
25
+ "@tanstack/svelte-query-devtools": "5.80.6",
26
+ "@testing-library/jest-dom": "6.6.3",
27
+ "@testing-library/svelte": "5.2.8",
28
+ "@threlte/core": "8.0.4",
29
+ "@threlte/extras": "9.4.0",
30
+ "@threlte/rapier": "3.1.4",
31
+ "@threlte/xr": "1.0.6",
32
+ "@types/bun": "1.2.15",
33
+ "@types/lodash-es": "4.17.12",
34
+ "@types/three": "0.177.0",
35
+ "@typescript-eslint/eslint-plugin": "8.34.0",
36
+ "@typescript-eslint/parser": "8.34.0",
37
+ "@viamrobotics/prime-core": "0.1.5",
38
38
  "@viamrobotics/sdk": "0.43.0",
39
39
  "@viamrobotics/svelte-sdk": "0.3.3",
40
- "@vitejs/plugin-basic-ssl": "^2.0.0",
41
- "@zag-js/svelte": "1.15.1",
42
- "@zag-js/tree-view": "1.15.1",
43
- "camera-controls": "^2.10.1",
44
- "eslint": "^9.28.0",
45
- "eslint-config-prettier": "^10.1.5",
46
- "eslint-plugin-svelte": "^3.9.2",
47
- "globals": "^16.2.0",
48
- "idb-keyval": "^6.2.2",
49
- "jsdom": "^26.1.0",
50
- "lodash-es": "^4.17.21",
51
- "lucide-svelte": "^0.513.0",
52
- "prettier": "^3.5.3",
53
- "prettier-plugin-svelte": "^3.4.0",
54
- "prettier-plugin-tailwindcss": "^0.6.12",
55
- "publint": "^0.3.12",
56
- "runed": "^0.28.0",
40
+ "@vitejs/plugin-basic-ssl": "2.0.0",
41
+ "@zag-js/svelte": "1.15.2",
42
+ "@zag-js/tree-view": "1.15.2",
43
+ "camera-controls": "2.10.1",
44
+ "eslint": "9.28.0",
45
+ "eslint-config-prettier": "10.1.5",
46
+ "eslint-plugin-svelte": "3.9.2",
47
+ "globals": "16.2.0",
48
+ "idb-keyval": "6.2.2",
49
+ "jsdom": "26.1.0",
50
+ "lodash-es": "4.17.21",
51
+ "lucide-svelte": "0.514.0",
52
+ "prettier": "3.5.3",
53
+ "prettier-plugin-svelte": "3.4.0",
54
+ "prettier-plugin-tailwindcss": "0.6.12",
55
+ "publint": "0.3.12",
56
+ "runed": "0.28.0",
57
57
  "svelte": "5.33.19",
58
- "svelte-check": "^4.2.1",
59
- "svelte-virtuallists": "^1.4.2",
60
- "tailwindcss": "^4.1.8",
61
- "three": "^0.177.0",
62
- "threlte-uikit": "^1.1.0",
63
- "tsx": "^4.19.4",
64
- "typescript": "^5.8.3",
65
- "typescript-eslint": "^8.34.0",
66
- "vite": "^6.3.5",
67
- "vite-plugin-mkcert": "^1.17.8",
68
- "vitest": "^3.2.3"
58
+ "svelte-check": "4.2.1",
59
+ "svelte-virtuallists": "1.4.2",
60
+ "tailwindcss": "4.1.10",
61
+ "three": "0.177.0",
62
+ "threlte-uikit": "1.1.0",
63
+ "tsx": "4.20.1",
64
+ "typescript": "5.8.3",
65
+ "typescript-eslint": "8.34.0",
66
+ "vite": "6.3.5",
67
+ "vite-plugin-devtools-json": "0.2.0",
68
+ "vite-plugin-mkcert": "1.17.8",
69
+ "vitest": "3.2.3"
69
70
  },
70
71
  "peerDependencies": {
71
72
  "@dimforge/rapier3d-compat": ">=0.17",
@@ -1,81 +0,0 @@
1
- <script
2
- module
3
- lang="ts"
4
- >
5
- import {
6
- Box3,
7
- Matrix4,
8
- PerspectiveCamera,
9
- Quaternion,
10
- Raycaster,
11
- Sphere,
12
- Spherical,
13
- Vector2,
14
- Vector3,
15
- Vector4,
16
- } from 'three'
17
- import CameraController from 'camera-controls'
18
- import { T, useTask, useThrelte } from '@threlte/core'
19
- import type { Snippet } from 'svelte'
20
-
21
- let installed = false
22
-
23
- const install = () => {
24
- CameraController.install({
25
- THREE: {
26
- Box3,
27
- Matrix4,
28
- Quaternion,
29
- Raycaster,
30
- Sphere,
31
- Spherical,
32
- Vector2,
33
- Vector3,
34
- Vector4,
35
- },
36
- })
37
- installed = true
38
- }
39
- </script>
40
-
41
- <script lang="ts">
42
- interface Props {
43
- ref?: CameraController
44
- enabled?: boolean
45
- children?: Snippet<[{ ref: CameraController }]>
46
- }
47
-
48
- let { ref = $bindable(), enabled = true, children }: Props = $props()
49
-
50
- if (!installed) {
51
- install()
52
- }
53
-
54
- const { camera, dom, invalidate } = useThrelte()
55
-
56
- const controls = new CameraController(camera.current as PerspectiveCamera, dom)
57
-
58
- $effect.pre(() => {
59
- controls.camera = $camera as PerspectiveCamera
60
- })
61
-
62
- $effect.pre(() => {
63
- controls.enabled = enabled
64
- })
65
-
66
- useTask(
67
- (delta) => {
68
- if (controls.update(delta)) {
69
- invalidate()
70
- }
71
- },
72
- { autoInvalidate: false }
73
- )
74
- </script>
75
-
76
- <T
77
- is={controls}
78
- bind:ref
79
- >
80
- {@render children?.({ ref: controls })}
81
- </T>
@@ -1,12 +0,0 @@
1
- import CameraController from 'camera-controls';
2
- import type { Snippet } from 'svelte';
3
- interface Props {
4
- ref?: CameraController;
5
- enabled?: boolean;
6
- children?: Snippet<[{
7
- ref: CameraController;
8
- }]>;
9
- }
10
- declare const CameraControls: import("svelte").Component<Props, {}, "ref">;
11
- type CameraControls = ReturnType<typeof CameraControls>;
12
- export default CameraControls;