@viamrobotics/motion-tools 0.15.4 → 0.16.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.
@@ -9,7 +9,6 @@
9
9
  import Details from './Details.svelte'
10
10
  import SceneProviders from './SceneProviders.svelte'
11
11
  import XR from './xr/XR.svelte'
12
- import { World } from '@threlte/rapier'
13
12
  import { createPartIDContext } from '../hooks/usePartID.svelte'
14
13
  import Dashboard from './dashboard/Dashboard.svelte'
15
14
  import { domPortal } from '../portal'
@@ -21,6 +20,7 @@
21
20
  import LiveUpdatesBanner from './LiveUpdatesBanner.svelte'
22
21
  import ArmPositions from './widgets/ArmPositions.svelte'
23
22
  import { provideEnvironment } from '../hooks/useEnvironment.svelte'
23
+ import type { CameraPose } from '../hooks/useControls.svelte'
24
24
 
25
25
  interface LocalConfigProps {
26
26
  getLocalPartConfig: () => Struct
@@ -34,6 +34,11 @@
34
34
  enableKeybindings?: boolean
35
35
  children?: Snippet
36
36
  localConfigProps?: LocalConfigProps
37
+
38
+ /**
39
+ * Allows setting the initial camera pose
40
+ */
41
+ cameraPose?: CameraPose
37
42
  }
38
43
 
39
44
  let {
@@ -41,6 +46,7 @@
41
46
  enableKeybindings = true,
42
47
  children: appChildren,
43
48
  localConfigProps,
49
+ cameraPose,
44
50
  }: Props = $props()
45
51
 
46
52
  const appClient = useViamClient()
@@ -87,34 +93,32 @@
87
93
  class="relative h-full w-full overflow-hidden"
88
94
  bind:this={root}
89
95
  >
90
- <Canvas renderMode="always">
91
- <World>
92
- <SceneProviders>
93
- {#snippet children({ focus })}
94
- <Scene>
95
- {@render appChildren?.()}
96
- </Scene>
97
-
98
- <XR {@attach domPortal(root)} />
99
-
100
- <Dashboard {@attach domPortal(root)} />
101
- <Details {@attach domPortal(root)} />
102
- {#if environment.current.isStandalone}
103
- <LiveUpdatesBanner {@attach domPortal(root)} />
104
- {/if}
105
-
106
- {#if !focus}
107
- <TreeContainer {@attach domPortal(root)} />
108
- {/if}
109
-
110
- {#if !focus && settings.current.enableArmPositionsWidget}
111
- <ArmPositions {@attach domPortal(root)} />
112
- {/if}
113
-
114
- <FileDrop {@attach domPortal(root)} />
115
- {/snippet}
116
- </SceneProviders>
117
- </World>
96
+ <Canvas renderMode="on-demand">
97
+ <SceneProviders {cameraPose}>
98
+ {#snippet children({ focus })}
99
+ <Scene>
100
+ {@render appChildren?.()}
101
+ </Scene>
102
+
103
+ <XR {@attach domPortal(root)} />
104
+
105
+ <Dashboard {@attach domPortal(root)} />
106
+ <Details {@attach domPortal(root)} />
107
+ {#if environment.current.isStandalone}
108
+ <LiveUpdatesBanner {@attach domPortal(root)} />
109
+ {/if}
110
+
111
+ {#if !focus}
112
+ <TreeContainer {@attach domPortal(root)} />
113
+ {/if}
114
+
115
+ {#if !focus && settings.current.enableArmPositionsWidget}
116
+ <ArmPositions {@attach domPortal(root)} />
117
+ {/if}
118
+
119
+ <FileDrop {@attach domPortal(root)} />
120
+ {/snippet}
121
+ </SceneProviders>
118
122
  </Canvas>
119
123
 
120
124
  <ToastContainer />
@@ -1,5 +1,6 @@
1
1
  import type { Snippet } from 'svelte';
2
2
  import type { Struct } from '@viamrobotics/sdk';
3
+ import type { CameraPose } from '../hooks/useControls.svelte';
3
4
  interface LocalConfigProps {
4
5
  getLocalPartConfig: () => Struct;
5
6
  setLocalPartConfig: (config: Struct) => void;
@@ -11,6 +12,10 @@ interface Props {
11
12
  enableKeybindings?: boolean;
12
13
  children?: Snippet;
13
14
  localConfigProps?: LocalConfigProps;
15
+ /**
16
+ * Allows setting the initial camera pose
17
+ */
18
+ cameraPose?: CameraPose;
14
19
  }
15
20
  declare const App: import("svelte").Component<Props, {}, "">;
16
21
  type App = ReturnType<typeof App>;
@@ -1,36 +1,17 @@
1
1
  <script lang="ts">
2
2
  import { MathUtils } from 'three'
3
3
  import { CameraControls, type CameraControlsRef, Gizmo } from '@threlte/extras'
4
- import { useTransformControls } from '../hooks/useControls.svelte'
4
+ import { useCameraControls, useTransformControls } from '../hooks/useControls.svelte'
5
5
  import KeyboardControls from './KeyboardControls.svelte'
6
6
  import Portal from './portal/Portal.svelte'
7
7
  import Button from './dashboard/Button.svelte'
8
- import { useDrawAPI } from '../hooks/useDrawAPI.svelte'
9
8
  import { useSettings } from '../hooks/useSettings.svelte'
10
9
 
10
+ const cameraControls = useCameraControls()
11
11
  const settings = useSettings()
12
- const drawAPI = useDrawAPI()
13
12
  const transformControls = useTransformControls()
14
13
 
15
14
  const enableKeybindings = $derived(settings.current.enableKeybindings)
16
-
17
- let ref = $state.raw<CameraControlsRef>()
18
-
19
- $effect(() => {
20
- if (drawAPI.camera) {
21
- const { position, lookAt, animate } = drawAPI.camera
22
- ref?.setPosition(position.x, position.y, position.z, animate)
23
- ref?.setLookAt(position.x, position.y, position.z, lookAt.x, lookAt.y, lookAt.z, animate)
24
- drawAPI.clearCamera()
25
- }
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
- })
34
15
  </script>
35
16
 
36
17
  <Portal id="dashboard">
@@ -40,15 +21,19 @@
40
21
  icon="camera-outline"
41
22
  description="Reset camera"
42
23
  onclick={() => {
43
- ref?.reset(true)
24
+ cameraControls.current?.reset(true)
44
25
  }}
45
26
  />
46
27
  </fieldset>
47
28
  </Portal>
48
29
 
49
30
  <CameraControls
50
- bind:ref
51
31
  enabled={!transformControls.active}
32
+ oncreate={(ref) => {
33
+ cameraControls.set(ref)
34
+ ;(window as unknown as { MathUtils: typeof MathUtils }).MathUtils = MathUtils
35
+ ;(window as unknown as { cameraControls: CameraControlsRef }).cameraControls = ref
36
+ }}
52
37
  >
53
38
  {#snippet children({ ref }: { ref: CameraControlsRef })}
54
39
  {#if enableKeybindings}
@@ -93,7 +93,10 @@
93
93
  worldOrientation.th = ov.th
94
94
  }
95
95
  },
96
- { autoStart: false }
96
+ {
97
+ autoStart: false,
98
+ autoInvalidate: false,
99
+ }
97
100
  )
98
101
 
99
102
  $effect.pre(() => {
@@ -77,7 +77,10 @@
77
77
  cameraControls.rotate(0, 0.05 * MathUtils.DEG2RAD * dt, true)
78
78
  }
79
79
  },
80
- { autoStart: false, autoInvalidate: false }
80
+ {
81
+ autoStart: false,
82
+ autoInvalidate: false,
83
+ }
81
84
  )
82
85
 
83
86
  $effect.pre(() => {
@@ -66,7 +66,10 @@
66
66
  // resized to half zoom to take up the same screen space.
67
67
  material.size = pointSize * ((camera.current as OrthographicCamera).zoom / 2)
68
68
  },
69
- { autoStart: false }
69
+ {
70
+ autoStart: false,
71
+ autoInvalidate: false,
72
+ }
70
73
  )
71
74
 
72
75
  $effect(() => {
@@ -9,7 +9,11 @@
9
9
  import { provideVisibility } from '../hooks/useVisibility.svelte'
10
10
  import { provideDrawAPI } from '../hooks/useDrawAPI.svelte'
11
11
  import { provideMachineSettings } from '../hooks/useMachineSettings.svelte'
12
- import { provideTransformControls } from '../hooks/useControls.svelte'
12
+ import {
13
+ provideCameraControls,
14
+ provideTransformControls,
15
+ type CameraPose,
16
+ } from '../hooks/useControls.svelte'
13
17
  import { provideObjects } from '../hooks/useObjects.svelte'
14
18
  import { provideMotionClient } from '../hooks/useMotionClient.svelte'
15
19
  import { provideLogs } from '../hooks/useLogs.svelte'
@@ -19,14 +23,17 @@
19
23
  import { provideArrows } from '../hooks/useArrows.svelte'
20
24
  import { provideFramelessComponents } from '../hooks/useFramelessComponents.svelte'
21
25
  import { provideResourceByName } from '../hooks/useResourceByName.svelte'
26
+
22
27
  interface Props {
28
+ cameraPose?: CameraPose
23
29
  children: Snippet<[{ focus: boolean }]>
24
30
  }
25
31
 
26
- let { children }: Props = $props()
32
+ let { cameraPose, children }: Props = $props()
27
33
 
28
34
  const partID = usePartID()
29
35
 
36
+ provideCameraControls(() => cameraPose)
30
37
  provideTransformControls()
31
38
  provideVisibility()
32
39
  provideMachineSettings()
@@ -1,5 +1,7 @@
1
1
  import type { Snippet } from 'svelte';
2
+ import { type CameraPose } from '../hooks/useControls.svelte';
2
3
  interface Props {
4
+ cameraPose?: CameraPose;
3
5
  children: Snippet<[{
4
6
  focus: boolean;
5
7
  }]>;
@@ -36,7 +36,10 @@
36
36
  obbHelper.setFromObject(clone)
37
37
  }
38
38
  },
39
- { autoStart: false }
39
+ {
40
+ autoStart: false,
41
+ autoInvalidate: false,
42
+ }
40
43
  )
41
44
 
42
45
  $effect.pre(() => {
@@ -51,7 +51,9 @@
51
51
 
52
52
  mesh.lookAt(headset.position)
53
53
  },
54
- { autoStart: false }
54
+ {
55
+ autoStart: false,
56
+ }
55
57
  )
56
58
 
57
59
  $effect(() => {
@@ -74,7 +74,9 @@
74
74
 
75
75
  rigidBody.setNextKinematicTranslation({ x: position.x, y: position.y, z: position.z })
76
76
  },
77
- { autoStart: false }
77
+ {
78
+ autoStart: false,
79
+ }
78
80
  )
79
81
 
80
82
  const rotateTask = useTask(
@@ -1,7 +1,20 @@
1
- interface Context {
1
+ import type { CameraControlsRef } from '@threlte/extras';
2
+ import type { Vector3Tuple } from 'three';
3
+ export interface CameraPose {
4
+ position: Vector3Tuple;
5
+ lookAt: Vector3Tuple;
6
+ }
7
+ interface CameraControlsContext {
8
+ current: CameraControlsRef | undefined;
9
+ set(current: CameraControlsRef): void;
10
+ setPose(pose: CameraPose, animate?: boolean): void;
11
+ }
12
+ export declare const provideCameraControls: (cameraPose: () => CameraPose | undefined) => void;
13
+ export declare const useCameraControls: () => CameraControlsContext;
14
+ interface TransformControlsContext {
2
15
  active: boolean;
3
16
  setActive: (value: boolean) => void;
4
17
  }
5
18
  export declare const provideTransformControls: () => void;
6
- export declare const useTransformControls: () => Context;
19
+ export declare const useTransformControls: () => TransformControlsContext;
7
20
  export {};
@@ -1,8 +1,36 @@
1
1
  import { getContext, setContext } from 'svelte';
2
- const key = Symbol('tranform-controls-context');
2
+ const TRANSFORM_CONTROLS_KEY = Symbol('tranform-controls-context');
3
+ const CAMERA_CONTROLS_KEY = Symbol('camera-controls-context');
4
+ export const provideCameraControls = (cameraPose) => {
5
+ let controls = $state.raw();
6
+ const setPose = (pose, animate = false) => {
7
+ const [x, y, z] = pose.position;
8
+ const [lookAtX, lookAtY, lookAtZ] = pose.lookAt;
9
+ controls?.setPosition(x, y, z, animate);
10
+ controls?.setLookAt(x, y, z, lookAtX, lookAtY, lookAtZ, animate);
11
+ };
12
+ $effect(() => {
13
+ const pose = cameraPose();
14
+ if (pose) {
15
+ setPose(pose);
16
+ }
17
+ });
18
+ setContext(CAMERA_CONTROLS_KEY, {
19
+ get current() {
20
+ return controls;
21
+ },
22
+ set(current) {
23
+ controls = current;
24
+ },
25
+ setPose,
26
+ });
27
+ };
28
+ export const useCameraControls = () => {
29
+ return getContext(CAMERA_CONTROLS_KEY);
30
+ };
3
31
  export const provideTransformControls = () => {
4
32
  let active = $state(false);
5
- setContext(key, {
33
+ setContext(TRANSFORM_CONTROLS_KEY, {
6
34
  get active() {
7
35
  return active;
8
36
  },
@@ -12,5 +40,5 @@ export const provideTransformControls = () => {
12
40
  });
13
41
  };
14
42
  export const useTransformControls = () => {
15
- return getContext(key);
43
+ return getContext(TRANSFORM_CONTROLS_KEY);
16
44
  };
@@ -1,4 +1,3 @@
1
- import { Vector3 } from 'three';
2
1
  import { WorldObject, type PointsGeometry } from '../WorldObject.svelte';
3
2
  type ConnectionStatus = 'connecting' | 'open' | 'closed';
4
3
  interface Context {
@@ -10,14 +9,8 @@ interface Context {
10
9
  nurbs: WorldObject[];
11
10
  models: WorldObject[];
12
11
  connectionStatus: ConnectionStatus;
13
- camera: {
14
- position: Vector3;
15
- lookAt: Vector3;
16
- animate: boolean;
17
- } | undefined;
18
12
  addPoints(worldObject: WorldObject<PointsGeometry>): void;
19
13
  addMesh(worldObject: WorldObject): void;
20
- clearCamera: () => void;
21
14
  }
22
15
  export declare const provideDrawAPI: () => void;
23
16
  export declare const useDrawAPI: () => Context;
@@ -7,6 +7,7 @@ import { WorldObject } from '../WorldObject.svelte';
7
7
  import { useArrows } from './useArrows.svelte';
8
8
  import { createGeometry } from '../geometry';
9
9
  import { createPose, createPoseFromFrame } from '../transform';
10
+ import { useCameraControls } from './useControls.svelte';
10
11
  const key = Symbol('draw-api-context-key');
11
12
  const tryParse = (json) => {
12
13
  try {
@@ -49,6 +50,7 @@ class Float32Reader {
49
50
  }
50
51
  }
51
52
  export const provideDrawAPI = () => {
53
+ const cameraControls = useCameraControls();
52
54
  let pointsIndex = 0;
53
55
  let geometryIndex = 0;
54
56
  let poseIndex = 0;
@@ -62,7 +64,6 @@ export const provideDrawAPI = () => {
62
64
  const poses = $state([]);
63
65
  const nurbs = $state([]);
64
66
  const models = $state([]);
65
- let camera = $state.raw();
66
67
  let connectionStatus = $state('connecting');
67
68
  const color = new Color();
68
69
  const direction = new Vector3();
@@ -394,11 +395,11 @@ export const provideDrawAPI = () => {
394
395
  if (!data)
395
396
  return;
396
397
  if ('setCameraPose' in data) {
397
- camera = {
398
- position: new Vector3(data.Position.X, data.Position.Y, data.Position.Z),
399
- lookAt: new Vector3(data.LookAt.X, data.LookAt.Y, data.LookAt.Z),
400
- animate: data.Animate,
401
- };
398
+ cameraControls.setPose({
399
+ position: [data.Position.X, data.Position.Y, data.Position.Z],
400
+ lookAt: [data.LookAt.X, data.LookAt.Y, data.LookAt.Z],
401
+ }, data.Animate);
402
+ return;
402
403
  }
403
404
  if ('geometries' in data) {
404
405
  return drawGeometries(data.geometries, data.colors, data.parent);
@@ -455,18 +456,12 @@ export const provideDrawAPI = () => {
455
456
  get connectionStatus() {
456
457
  return connectionStatus;
457
458
  },
458
- get camera() {
459
- return camera;
460
- },
461
459
  addPoints(worldObject) {
462
460
  points.push(worldObject);
463
461
  },
464
462
  addMesh(worldObject) {
465
463
  meshes.push(worldObject);
466
464
  },
467
- clearCamera: () => {
468
- camera = undefined;
469
- },
470
465
  });
471
466
  };
472
467
  export const useDrawAPI = () => {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@viamrobotics/motion-tools",
3
- "version": "0.15.4",
3
+ "version": "0.16.0",
4
4
  "description": "Motion visualization with Viam",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",