@viamrobotics/motion-tools 0.9.2 → 0.9.4

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
@@ -1,6 +1,6 @@
1
1
  ## motion-tools
2
2
 
3
- `motion-tools` is visualizer for motion-related monitoring, testing, and debugging.
3
+ `motion-tools` aims to provide a visualization interface for any spatial information using Viam's APIs. This typically means motion-related monitoring, testing, and debugging.
4
4
 
5
5
  ### Getting started
6
6
 
@@ -30,6 +30,7 @@ VITE_CONFIGS='
30
30
  "signalingAddress": "https://app.viam.com:443"
31
31
  }
32
32
  }
33
+ '
33
34
  ```
34
35
 
35
36
  ### Executing drawing commands
@@ -1,6 +1,8 @@
1
1
  <script lang="ts">
2
2
  import type { Snippet } from 'svelte'
3
3
  import { Canvas } from '@threlte/core'
4
+ import { SvelteQueryDevtools } from '@tanstack/svelte-query-devtools'
5
+
4
6
  import Scene from './Scene.svelte'
5
7
  import TreeContainer from './Tree/TreeContainer.svelte'
6
8
  import Details from './Details.svelte'
@@ -10,19 +12,31 @@
10
12
  import { createPartIDContext } from '../hooks/usePartID.svelte'
11
13
  import Dashboard from './dashboard/Dashboard.svelte'
12
14
  import { domPortal } from '../portal'
15
+ import { provideSettings } from '../hooks/useSettings.svelte'
13
16
 
14
17
  interface Props {
15
18
  partID?: string
19
+ enableKeybindings?: boolean
16
20
  children?: Snippet
17
21
  }
18
22
 
19
- let { partID = '', children: appChildren }: Props = $props()
23
+ let { partID = '', enableKeybindings = true, children: appChildren }: Props = $props()
24
+
25
+ const settings = provideSettings()
26
+
27
+ $effect(() => {
28
+ settings.current.enableKeybindings = enableKeybindings
29
+ })
20
30
 
21
31
  createPartIDContext(() => partID)
22
32
 
23
33
  let root = $state.raw<HTMLElement>()
24
34
  </script>
25
35
 
36
+ {#if settings.current.enableQueryDevtools}
37
+ <SvelteQueryDevtools initialIsOpen />
38
+ {/if}
39
+
26
40
  <div
27
41
  class="relative h-full w-full overflow-hidden"
28
42
  bind:this={root}
@@ -1,6 +1,7 @@
1
1
  import type { Snippet } from 'svelte';
2
2
  interface Props {
3
3
  partID?: string;
4
+ enableKeybindings?: boolean;
4
5
  children?: Snippet;
5
6
  }
6
7
  declare const App: import("svelte").Component<Props, {}, "">;
@@ -1,11 +1,17 @@
1
1
  <script lang="ts">
2
- import { T } from '@threlte/core'
2
+ import { T, useThrelte } from '@threlte/core'
3
3
  import { useSettings } from '../hooks/useSettings.svelte'
4
+ import type { Camera } from 'three'
4
5
 
5
6
  let { children, ...rest } = $props()
6
7
 
8
+ const { camera } = useThrelte()
7
9
  const settings = useSettings()
8
10
  const mode = $derived(settings.current.cameraMode)
11
+
12
+ $effect(() => {
13
+ ;(window as unknown as { camera: Camera }).camera = $camera
14
+ })
9
15
  </script>
10
16
 
11
17
  {#if mode === 'perspective'}
@@ -1,3 +1,4 @@
1
+ import type { Camera } from 'three';
1
2
  declare const Camera: import("svelte").Component<{
2
3
  children: any;
3
4
  } & Record<string, any>, {}, "">;
@@ -1,14 +1,19 @@
1
1
  <script lang="ts">
2
+ import { MathUtils } from 'three'
2
3
  import { CameraControls, type CameraControlsRef, Gizmo } from '@threlte/extras'
3
4
  import { useTransformControls } from '../hooks/useControls.svelte'
4
5
  import KeyboardControls from './KeyboardControls.svelte'
5
6
  import Portal from './portal/Portal.svelte'
6
7
  import Button from './dashboard/Button.svelte'
7
8
  import { useDrawAPI } from '../hooks/useDrawAPI.svelte'
9
+ import { useSettings } from '../hooks/useSettings.svelte'
8
10
 
11
+ const settings = useSettings()
9
12
  const drawAPI = useDrawAPI()
10
13
  const transformControls = useTransformControls()
11
14
 
15
+ const enableKeybindings = $derived(settings.current.enableKeybindings)
16
+
12
17
  let ref = $state.raw<CameraControlsRef>()
13
18
 
14
19
  $effect(() => {
@@ -19,6 +24,13 @@
19
24
  drawAPI.clearCamera()
20
25
  }
21
26
  })
27
+
28
+ $effect(() => {
29
+ if (ref) {
30
+ ;(window as unknown as { MathUtils: typeof MathUtils }).MathUtils = MathUtils
31
+ ;(window as unknown as { cameraControls: CameraControlsRef }).cameraControls = ref
32
+ }
33
+ })
22
34
  </script>
23
35
 
24
36
  <Portal id="dashboard">
@@ -39,7 +51,9 @@
39
51
  enabled={!transformControls.active}
40
52
  >
41
53
  {#snippet children({ ref }: { ref: CameraControlsRef })}
42
- <KeyboardControls cameraControls={ref} />
54
+ {#if enableKeybindings}
55
+ <KeyboardControls cameraControls={ref} />
56
+ {/if}
43
57
  <Gizmo />
44
58
  {/snippet}
45
59
  </CameraControls>
@@ -0,0 +1,34 @@
1
+ <script lang="ts">
2
+ import { BackSide, Vector3 } from 'three'
3
+ import { T, useThrelte } from '@threlte/core'
4
+ import { MeshDiscardMaterial } from '@threlte/extras'
5
+ import { useSelected } from '../hooks/useSelection.svelte'
6
+ import { useTransformControls } from '../hooks/useControls.svelte'
7
+
8
+ const { camera } = useThrelte()
9
+ const selected = useSelected()
10
+ const transformControls = useTransformControls()
11
+ const cameraDown = new Vector3()
12
+
13
+ const size = 1_000
14
+ </script>
15
+
16
+ <T.Mesh
17
+ onpointerdown={() => {
18
+ cameraDown.copy(camera.current.position)
19
+ }}
20
+ onpointerup={() => {
21
+ if (transformControls.active) {
22
+ return
23
+ }
24
+
25
+ if (cameraDown.distanceToSquared(camera.current.position) > 0.2) {
26
+ return
27
+ }
28
+
29
+ selected.set()
30
+ }}
31
+ >
32
+ <T.BoxGeometry args={[size, size, size]} />
33
+ <MeshDiscardMaterial side={BackSide} />
34
+ </T.Mesh>
@@ -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 PointerMissBox: $$__sveltets_2_IsomorphicComponent<Record<string, never>, {
15
+ [evt: string]: CustomEvent<any>;
16
+ }, {}, {}, string>;
17
+ type PointerMissBox = InstanceType<typeof PointerMissBox>;
18
+ export default PointerMissBox;
@@ -16,6 +16,7 @@
16
16
  import { useSettings } from '../hooks/useSettings.svelte'
17
17
  import CameraControls from './CameraControls.svelte'
18
18
  import MeasureTool from './MeasureTool.svelte'
19
+ import PointerMissBox from './PointerMissBox.svelte'
19
20
 
20
21
  interface Props {
21
22
  children?: Snippet
@@ -66,6 +67,7 @@
66
67
  <StaticGeometries />
67
68
 
68
69
  <WorldObjects />
70
+ <PointerMissBox />
69
71
 
70
72
  <Selected />
71
73
 
@@ -13,7 +13,6 @@
13
13
  import { provideObjects } from '../hooks/useObjects.svelte'
14
14
  import { provideMotionClient } from '../hooks/useMotionClient.svelte'
15
15
  import { provideLogs } from '../hooks/useLogs.svelte'
16
- import { provideSettings } from '../hooks/useSettings.svelte'
17
16
  import { provideOrigin } from './xr/useOrigin.svelte'
18
17
 
19
18
  interface Props {
@@ -24,7 +23,6 @@
24
23
 
25
24
  const partID = usePartID()
26
25
 
27
- provideSettings()
28
26
  provideTransformControls()
29
27
  provideVisibility()
30
28
  provideMachineSettings()
@@ -1,48 +1,56 @@
1
1
  <script lang="ts">
2
2
  import { Box3, Object3D } from 'three'
3
- import { T, useTask, useThrelte } from '@threlte/core'
4
- import { useSelectedObject } from '../hooks/useSelection.svelte'
3
+ import { T, useTask } from '@threlte/core'
4
+ import { useSelectedObject, useSelectedObject3d } from '../hooks/useSelection.svelte'
5
5
  import { BoxHelper } from '../three/BoxHelper'
6
6
 
7
- const { scene } = useThrelte()
8
-
7
+ const box3 = new Box3()
9
8
  const box = new BoxHelper(new Object3D(), 0x000000)
10
9
  const selected = useSelectedObject()
10
+ const selectedObject3d = useSelectedObject3d()
11
11
 
12
- const { start, stop } = useTask(() => box.update(), { autoStart: false })
12
+ // Create a clone so that our bounding box doesn't include children
13
+ const clone = $derived.by(() => {
14
+ if (selected.current?.metadata.batched) {
15
+ return
16
+ }
13
17
 
14
- const box3 = new Box3()
18
+ return selectedObject3d.current?.clone(false)
19
+ })
20
+
21
+ const { start, stop } = useTask(
22
+ () => {
23
+ if (selected.current === undefined) {
24
+ return
25
+ }
26
+
27
+ if (selected.current.metadata.batched) {
28
+ selected.current.metadata.getBoundingBoxAt?.(box3)
29
+ box.setFromBox3(box3)
30
+ return
31
+ }
32
+
33
+ if (clone) {
34
+ selectedObject3d.current?.getWorldPosition(clone.position)
35
+ selectedObject3d.current?.getWorldQuaternion(clone.quaternion)
36
+ box.setFromObject(clone)
37
+ }
38
+ },
39
+ { autoStart: false }
40
+ )
15
41
 
16
42
  $effect.pre(() => {
17
43
  if (selected.current) {
18
44
  start()
45
+ box.visible = true
19
46
  } else {
20
47
  stop()
21
- }
22
- })
23
-
24
- $effect.pre(() => {
25
- if (!selected.current) {
26
48
  box.visible = false
27
- return
28
- }
29
-
30
- box.visible = true
31
-
32
- if (selected.current.metadata.batched) {
33
- selected.current.metadata.getBoundingBoxAt?.(box3)
34
- box.setFromBox3(box3)
35
- } else {
36
- const object3d = scene.getObjectByProperty('uuid', selected.current.uuid)
37
- if (object3d) {
38
- // Create a clone so that our bounding box doesn't include children
39
- const clone = object3d.clone(false)
40
- object3d.getWorldPosition(clone.position)
41
- object3d.getWorldQuaternion(clone.quaternion)
42
- box.setFromObject(clone)
43
- }
44
49
  }
45
50
  })
46
51
  </script>
47
52
 
48
- <T is={box} />
53
+ <T
54
+ is={box}
55
+ raycast={() => null}
56
+ />
@@ -155,6 +155,9 @@
155
155
 
156
156
  <h3 class="pt-2 text-sm"><strong>Misc</strong></h3>
157
157
  <div class="flex flex-col gap-2.5">
158
+ <label class="flex items-center justify-between gap-2">
159
+ Query devtools <Switch bind:on={settings.current.enableQueryDevtools} />
160
+ </label>
158
161
  <label class="flex items-center justify-between gap-2">
159
162
  Render stats <Switch bind:on={settings.current.renderStats} />
160
163
  </label>
@@ -1,8 +1,5 @@
1
- import { useThrelteUserContext } from '@threlte/core';
2
1
  import { SvelteMap, SvelteSet } from 'svelte/reactivity';
3
- const createPortalContext = () => {
4
- return new SvelteMap();
5
- };
2
+ const context = new SvelteMap();
6
3
  export const usePortalContext = () => {
7
- return useThrelteUserContext('threlte-portals', createPortalContext());
4
+ return context;
8
5
  };
@@ -6,5 +6,4 @@ export declare const useObjectEvents: (uuid: () => string) => {
6
6
  ondblclick: (event: IntersectionEvent<MouseEvent>) => void;
7
7
  onpointerdown: (event: IntersectionEvent<MouseEvent>) => void;
8
8
  onclick: (event: IntersectionEvent<MouseEvent>) => void;
9
- onpointermissed: () => void;
10
9
  };
@@ -44,11 +44,5 @@ export const useObjectEvents = (uuid) => {
44
44
  selected.set(uuid());
45
45
  }
46
46
  },
47
- onpointermissed: () => {
48
- if (measuring) {
49
- return;
50
- }
51
- selected.set();
52
- },
53
47
  };
54
48
  };
@@ -11,14 +11,16 @@ interface Settings {
11
11
  pointColor: string;
12
12
  lineWidth: number;
13
13
  lineDotSize: number;
14
- enableXR: boolean;
15
14
  enableMeasure: boolean;
16
15
  enableLabels: boolean;
16
+ enableKeybindings: boolean;
17
+ enableQueryDevtools: boolean;
18
+ enableXR: boolean;
17
19
  renderStats: boolean;
18
20
  }
19
21
  interface Context {
20
22
  current: Settings;
21
23
  }
22
- export declare const provideSettings: () => void;
24
+ export declare const provideSettings: () => Context;
23
25
  export declare const useSettings: () => Context;
24
26
  export {};
@@ -16,6 +16,8 @@ const defaults = () => ({
16
16
  lineDotSize: 0.01,
17
17
  enableMeasure: false,
18
18
  enableLabels: false,
19
+ enableKeybindings: true,
20
+ enableQueryDevtools: false,
19
21
  enableXR: false,
20
22
  renderStats: false,
21
23
  });
@@ -29,11 +31,13 @@ export const provideSettings = () => {
29
31
  $effect(() => {
30
32
  set('motion-tools-settings', $state.snapshot(settings));
31
33
  });
32
- setContext(key, {
34
+ const context = {
33
35
  get current() {
34
36
  return settings;
35
37
  },
36
- });
38
+ };
39
+ setContext(key, context);
40
+ return context;
37
41
  };
38
42
  export const useSettings = () => {
39
43
  return getContext(key);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@viamrobotics/motion-tools",
3
- "version": "0.9.2",
3
+ "version": "0.9.4",
4
4
  "description": "Motion visualization with Viam",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
@@ -87,7 +87,6 @@
87
87
  "svelte": ">=5",
88
88
  "svelte-virtuallists": ">=1"
89
89
  },
90
- "packageManager": "pnpm@8.15.6+sha256.01c01eeb990e379b31ef19c03e9d06a14afa5250b82e81303f88721c99ff2e6f",
91
90
  "svelte": "./dist/index.js",
92
91
  "types": "./dist/index.d.ts",
93
92
  "exports": {