@viamrobotics/motion-tools 1.1.4 → 1.1.6

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.
@@ -22,6 +22,10 @@
22
22
  import { provideEnvironment } from '../hooks/useEnvironment.svelte'
23
23
  import type { CameraPose } from '../hooks/useControls.svelte'
24
24
  import { provideWorld } from '../ecs'
25
+ import {
26
+ provideDrawConnectionConfig,
27
+ type DrawConnectionConfig,
28
+ } from '../hooks/useDrawConnectionConfig.svelte'
25
29
 
26
30
  interface LocalConfigProps {
27
31
  getLocalPartConfig: () => Struct
@@ -36,6 +40,7 @@
36
40
  children?: Snippet
37
41
  dashboard?: Snippet
38
42
  localConfigProps?: LocalConfigProps
43
+ drawConnectionConfig?: DrawConnectionConfig
39
44
 
40
45
  /**
41
46
  * Allows setting the initial camera pose
@@ -48,6 +53,7 @@
48
53
  enableKeybindings = true,
49
54
  localConfigProps,
50
55
  cameraPose,
56
+ drawConnectionConfig,
51
57
  children: appChildren,
52
58
  dashboard,
53
59
  }: Props = $props()
@@ -63,7 +69,7 @@
63
69
  })
64
70
 
65
71
  createPartIDContext(() => partID)
66
-
72
+ provideDrawConnectionConfig(() => drawConnectionConfig)
67
73
  provideWeblabs()
68
74
  provideToast()
69
75
 
@@ -1,6 +1,7 @@
1
1
  import type { Snippet } from 'svelte';
2
2
  import type { Struct } from '@viamrobotics/sdk';
3
3
  import type { CameraPose } from '../hooks/useControls.svelte';
4
+ import { type DrawConnectionConfig } from '../hooks/useDrawConnectionConfig.svelte';
4
5
  interface LocalConfigProps {
5
6
  getLocalPartConfig: () => Struct;
6
7
  setLocalPartConfig: (config: Struct) => void;
@@ -13,6 +14,7 @@ interface Props {
13
14
  children?: Snippet;
14
15
  dashboard?: Snippet;
15
16
  localConfigProps?: LocalConfigProps;
17
+ drawConnectionConfig?: DrawConnectionConfig;
16
18
  /**
17
19
  * Allows setting the initial camera pose
18
20
  */
File without changes
@@ -0,0 +1,26 @@
1
+ export default BatchedGeometry;
2
+ type BatchedGeometry = SvelteComponent<{
3
+ [x: string]: never;
4
+ }, {
5
+ [evt: string]: CustomEvent<any>;
6
+ }, {}> & {
7
+ $$bindings?: string | undefined;
8
+ };
9
+ declare const BatchedGeometry: $$__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
+ }
@@ -1,7 +1,7 @@
1
1
  <script lang="ts">
2
2
  import type { Snippet } from 'svelte'
3
3
  import { useObjectEvents } from '../hooks/useObjectEvents.svelte'
4
- import { Color, type Object3D } from 'three'
4
+ import { Color, Group, type Object3D } from 'three'
5
5
  import Geometry from './Geometry2.svelte'
6
6
  import { useWeblabs } from '../hooks/useWeblabs.svelte'
7
7
  import { useSelectedEntity } from '../hooks/useSelection.svelte'
@@ -13,6 +13,7 @@
13
13
  import { traits, useTrait } from '../ecs'
14
14
  import type { Pose } from '@viamrobotics/sdk'
15
15
  import { useResourceByName } from '../hooks/useResourceByName.svelte'
16
+ import { Portal, PortalTarget } from '@threlte/extras'
16
17
 
17
18
  interface Props {
18
19
  entity: Entity
@@ -22,14 +23,20 @@
22
23
 
23
24
  let { entity, pose, children }: Props = $props()
24
25
 
26
+ let ref = $state<Group>()
27
+
25
28
  const colorUtil = new Color()
29
+
26
30
  const settings = useSettings()
27
31
  const componentModels = use3DModels()
28
32
  const selectedEntity = useSelectedEntity()
29
33
  const resourceByName = useResourceByName()
30
34
  const weblabs = useWeblabs()
35
+
31
36
  const name = useTrait(() => entity, traits.Name)
37
+ const parent = useTrait(() => entity, traits.Parent)
32
38
  const entityColor = useTrait(() => entity, traits.Color)
39
+
33
40
  const events = useObjectEvents(() => entity)
34
41
  const resourceColor = $derived.by(() => {
35
42
  if (!name.current) {
@@ -66,14 +73,24 @@
66
73
  })
67
74
  </script>
68
75
 
69
- <Geometry
70
- {entity}
71
- {model}
72
- {pose}
73
- {children}
74
- renderMode={settings.current.renderArmModels}
75
- color={selectedEntity.current === entity
76
- ? `#${darkenColor(color, 75).getHexString()}`
77
- : `#${colorUtil.set(color).getHexString()}`}
78
- {...events}
79
- />
76
+ <Portal id={parent.current}>
77
+ <Geometry
78
+ bind:ref
79
+ {entity}
80
+ {model}
81
+ {pose}
82
+ renderMode={settings.current.renderArmModels}
83
+ color={selectedEntity.current === entity
84
+ ? `#${darkenColor(color, 75).getHexString()}`
85
+ : `#${colorUtil.set(color).getHexString()}`}
86
+ {...events}
87
+ >
88
+ {#if name.current}
89
+ <PortalTarget id={name.current} />
90
+ {/if}
91
+
92
+ {#if ref}
93
+ {@render children?.({ ref })}
94
+ {/if}
95
+ </Geometry>
96
+ </Portal>
@@ -1,13 +1,7 @@
1
1
  <script lang="ts">
2
2
  import { T, useThrelte, type Props as ThrelteProps } from '@threlte/core'
3
3
  import { type Snippet } from 'svelte'
4
- import {
5
- meshBounds,
6
- MeshLineMaterial,
7
- MeshLineGeometry,
8
- Portal,
9
- PortalTarget,
10
- } from '@threlte/extras'
4
+ import { meshBounds, MeshLineMaterial, MeshLineGeometry } from '@threlte/extras'
11
5
  import { BufferGeometry, Color, DoubleSide, FrontSide, Group, Mesh } from 'three'
12
6
  import { CapsuleGeometry } from '../three/CapsuleGeometry'
13
7
  import { colors, darkenColor } from '../color'
@@ -23,6 +17,7 @@
23
17
  model?: Group
24
18
  pose?: Pose
25
19
  renderMode?: 'model' | 'colliders' | 'colliders+model'
20
+ ref?: Group
26
21
  children?: Snippet<[{ ref: Group }]>
27
22
  }
28
23
 
@@ -32,6 +27,7 @@
32
27
  model,
33
28
  renderMode = 'colliders',
34
29
  pose,
30
+ ref = $bindable(),
35
31
  children,
36
32
  ...rest
37
33
  }: Props = $props()
@@ -40,7 +36,6 @@
40
36
 
41
37
  const { invalidate } = useThrelte()
42
38
  const name = useTrait(() => entity, traits.Name)
43
- const parent = useTrait(() => entity, traits.Parent)
44
39
  const entityColor = useTrait(() => entity, traits.Color)
45
40
  const opacity = useTrait(() => entity, traits.Opacity)
46
41
  const box = useTrait(() => entity, traits.Box)
@@ -71,6 +66,8 @@
71
66
  })
72
67
 
73
68
  const group = new Group()
69
+ ref = group
70
+
74
71
  const mesh = $derived.by(() => {
75
72
  if (geometryType === undefined) {
76
73
  return
@@ -103,8 +100,8 @@
103
100
 
104
101
  let geo = $state.raw<BufferGeometry>()
105
102
 
106
- const oncreate = (ref: BufferGeometry) => {
107
- geo = ref
103
+ const oncreate = (bufferGeometry: BufferGeometry) => {
104
+ geo = bufferGeometry
108
105
  }
109
106
 
110
107
  $effect.pre(() => {
@@ -120,87 +117,81 @@
120
117
  })
121
118
  </script>
122
119
 
123
- <Portal id={parent.current}>
124
- <T
125
- is={group}
126
- {...rest}
127
- >
128
- {#if geometryType}
129
- <AxesHelper
130
- width={3}
131
- length={0.1}
132
- />
133
-
134
- <T
135
- is={mesh}
136
- name={name.current}
137
- bvh={{ enabled: geometryType === 'buffer' }}
138
- >
139
- {#if model && renderMode.includes('model')}
140
- <T is={model} />
141
- {/if}
142
-
143
- {#if !model || renderMode.includes('colliders')}
144
- {#if lineGeometry.current}
145
- <MeshLineGeometry points={lineGeometry.current} />
146
- {:else if box.current}
147
- {@const { x, y, z } = box.current ?? { x: 0, y: 0, z: 0 }}
148
- <T.BoxGeometry
149
- args={[x * 0.001, y * 0.001, z * 0.001]}
150
- {oncreate}
151
- />
152
- {:else if sphere.current}
153
- {@const { r } = sphere.current ?? { r: 0 }}
154
- <T.SphereGeometry
155
- args={[r * 0.001]}
156
- {oncreate}
157
- />
158
- {:else if capsule.current}
159
- {@const { r, l } = capsule.current ?? { r: 0, l: 0 }}
160
- <T
161
- is={CapsuleGeometry}
162
- args={[r * 0.001, l * 0.001]}
163
- {oncreate}
164
- />
165
- {/if}
166
- {/if}
167
-
120
+ <T
121
+ is={group}
122
+ {...rest}
123
+ >
124
+ {#if geometryType}
125
+ <AxesHelper
126
+ width={3}
127
+ length={0.1}
128
+ />
129
+
130
+ <T
131
+ is={mesh}
132
+ name={name.current}
133
+ bvh={{ enabled: geometryType === 'buffer' }}
134
+ >
135
+ {#if model && renderMode.includes('model')}
136
+ <T is={model} />
137
+ {/if}
138
+
139
+ {#if !model || renderMode.includes('colliders')}
168
140
  {#if lineGeometry.current}
169
- <MeshLineMaterial
170
- {color}
171
- width={0.005}
141
+ <MeshLineGeometry points={lineGeometry.current} />
142
+ {:else if box.current}
143
+ {@const { x, y, z } = box.current ?? { x: 0, y: 0, z: 0 }}
144
+ <T.BoxGeometry
145
+ args={[x * 0.001, y * 0.001, z * 0.001]}
146
+ {oncreate}
172
147
  />
173
- {:else}
174
- <T.MeshToonMaterial
175
- {color}
176
- side={geometryType === 'buffer' ? DoubleSide : FrontSide}
177
- transparent
178
- opacity={opacity.current ?? 0.7}
148
+ {:else if sphere.current}
149
+ {@const { r } = sphere.current ?? { r: 0 }}
150
+ <T.SphereGeometry
151
+ args={[r * 0.001]}
152
+ {oncreate}
179
153
  />
180
-
181
- {#if geo}
182
- <T.LineSegments
183
- raycast={() => null}
184
- bvh={{ enabled: false }}
185
- >
186
- <T.EdgesGeometry args={[geo, 0]} />
187
- <T.LineBasicMaterial color={darkenColor(color, 10)} />
188
- </T.LineSegments>
189
- {/if}
154
+ {:else if capsule.current}
155
+ {@const { r, l } = capsule.current ?? { r: 0, l: 0 }}
156
+ <T
157
+ is={CapsuleGeometry}
158
+ args={[r * 0.001, l * 0.001]}
159
+ {oncreate}
160
+ />
161
+ {/if}
162
+ {/if}
163
+
164
+ {#if lineGeometry.current}
165
+ <MeshLineMaterial
166
+ {color}
167
+ width={0.005}
168
+ />
169
+ {:else}
170
+ <T.MeshToonMaterial
171
+ {color}
172
+ side={geometryType === 'buffer' ? DoubleSide : FrontSide}
173
+ transparent
174
+ opacity={opacity.current ?? 0.7}
175
+ />
176
+
177
+ {#if geo}
178
+ <T.LineSegments
179
+ raycast={() => null}
180
+ bvh={{ enabled: false }}
181
+ >
182
+ <T.EdgesGeometry args={[geo, 0]} />
183
+ <T.LineBasicMaterial color={darkenColor(color, 10)} />
184
+ </T.LineSegments>
190
185
  {/if}
191
- </T>
192
- {:else}
193
- <AxesHelper
194
- name={name.current}
195
- width={3}
196
- length={0.1}
197
- />
198
- {/if}
199
-
200
- {@render children?.({ ref: group })}
201
-
202
- {#if name.current}
203
- <PortalTarget id={name.current} />
204
- {/if}
205
- </T>
206
- </Portal>
186
+ {/if}
187
+ </T>
188
+ {:else}
189
+ <AxesHelper
190
+ name={name.current}
191
+ width={3}
192
+ length={0.1}
193
+ />
194
+ {/if}
195
+
196
+ {@render children?.({ ref: group })}
197
+ </T>
@@ -9,10 +9,11 @@ interface Props extends ThrelteProps<Group> {
9
9
  model?: Group;
10
10
  pose?: Pose;
11
11
  renderMode?: 'model' | 'colliders' | 'colliders+model';
12
+ ref?: Group;
12
13
  children?: Snippet<[{
13
14
  ref: Group;
14
15
  }]>;
15
16
  }
16
- declare const Geometry2: import("svelte").Component<Props, {}, "">;
17
+ declare const Geometry2: import("svelte").Component<Props, {}, "ref">;
17
18
  type Geometry2 = ReturnType<typeof Geometry2>;
18
19
  export default Geometry2;
@@ -69,41 +69,39 @@
69
69
  })
70
70
  </script>
71
71
 
72
- {#if resizable.isLoaded}
73
- <div
74
- bind:this={container}
75
- class="bg-extralight border-medium absolute top-0 left-0 z-1000 m-2 resize overflow-y-auto border text-xs"
76
- style:min-width="{MIN_DIMENSIONS.width}px"
77
- style:min-height="{MIN_DIMENSIONS.height}px"
78
- style:width={resizable.current ? `${resizable.current.width}px` : undefined}
79
- style:height={resizable.current ? `${resizable.current.height}px` : undefined}
80
- use:draggable={{
81
- bounds: 'body',
82
- handle: dragElement,
83
- defaultPosition: dragPosition.current,
84
- onDragEnd(data) {
85
- dragPosition.current = { x: data.offsetX, y: data.offsetY }
86
- },
87
- }}
88
- {...rest}
89
- >
90
- <Tree
91
- {rootNode}
92
- {nodeMap}
93
- bind:dragElement
94
- onSelectionChange={(event) => {
95
- const value = event.selectedValue[0]
72
+ <div
73
+ bind:this={container}
74
+ class="bg-extralight border-medium absolute top-0 left-0 z-1000 m-2 resize overflow-y-auto border text-xs"
75
+ style:min-width="{MIN_DIMENSIONS.width}px"
76
+ style:min-height="{MIN_DIMENSIONS.height}px"
77
+ style:width={resizable.current ? `${resizable.current.width}px` : undefined}
78
+ style:height={resizable.current ? `${resizable.current.height}px` : undefined}
79
+ use:draggable={{
80
+ bounds: 'body',
81
+ handle: dragElement,
82
+ defaultPosition: dragPosition.current,
83
+ onDragEnd(data) {
84
+ dragPosition.current = { x: Math.max(data.offsetX, 0), y: Math.max(data.offsetY, 0) }
85
+ },
86
+ }}
87
+ {...rest}
88
+ >
89
+ <Tree
90
+ {rootNode}
91
+ {nodeMap}
92
+ bind:dragElement
93
+ onSelectionChange={(event) => {
94
+ const value = event.selectedValue[0]
96
95
 
97
- selectedEntity.set(value ? (Number(value) as Entity) : undefined)
98
- }}
99
- />
96
+ selectedEntity.set(value ? (Number(value) as Entity) : undefined)
97
+ }}
98
+ />
100
99
 
101
- {#if environment.current.isStandalone && partID.current && partConfig.hasEditPermissions}
102
- <AddFrames />
103
- {/if}
100
+ {#if environment.current.isStandalone && partID.current && partConfig.hasEditPermissions}
101
+ <AddFrames />
102
+ {/if}
104
103
 
105
- <Logs />
106
- <Settings />
107
- <Widgets />
108
- </div>
109
- {/if}
104
+ <Logs />
105
+ <Settings />
106
+ <Widgets />
107
+ </div>
@@ -1,14 +1,15 @@
1
1
  <script lang="ts">
2
2
  import { Icon, type IconName, Tooltip } from '@viamrobotics/prime-core'
3
3
  import { Ruler } from 'lucide-svelte'
4
+ import type { ClassValue, MouseEventHandler } from 'svelte/elements'
4
5
 
5
6
  interface Props {
6
7
  icon: IconName | 'ruler'
7
8
  active?: boolean
8
9
  description: string
9
10
  hotkey?: string
10
- class?: string
11
- onclick?: () => void
11
+ class?: ClassValue | null | undefined
12
+ onclick?: MouseEventHandler<HTMLButtonElement> | null | undefined
12
13
  }
13
14
 
14
15
  let {
@@ -1,11 +1,12 @@
1
1
  import { type IconName } from '@viamrobotics/prime-core';
2
+ import type { ClassValue, MouseEventHandler } from 'svelte/elements';
2
3
  interface Props {
3
4
  icon: IconName | 'ruler';
4
5
  active?: boolean;
5
6
  description: string;
6
7
  hotkey?: string;
7
- class?: string;
8
- onclick?: () => void;
8
+ class?: ClassValue | null | undefined;
9
+ onclick?: MouseEventHandler<HTMLButtonElement> | null | undefined;
9
10
  }
10
11
  declare const Button: import("svelte").Component<Props, {}, "">;
11
12
  type Button = ReturnType<typeof Button>;
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Variables that are string-replaced by vite.
3
+ *
4
+ * These should not be imported into `$lib`,
5
+ * due to them not being replaced when shipped to NPM.
6
+ */
7
+ export declare const backendIP: any;
8
+ export declare const websocketPort: any;
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Variables that are string-replaced by vite.
3
+ *
4
+ * These should not be imported into `$lib`,
5
+ * due to them not being replaced when shipped to NPM.
6
+ */
7
+ export const backendIP = BACKEND_IP;
8
+ export const websocketPort = WS_PORT;
@@ -12,6 +12,7 @@ import {} from 'koota';
12
12
  import { parsePlyInput } from '../ply';
13
13
  import { useLogs } from './useLogs.svelte';
14
14
  import { createBox, createCapsule, createSphere } from '../geometry';
15
+ import { useDrawConnectionConfig } from './useDrawConnectionConfig.svelte';
15
16
  const colorUtil = new Color();
16
17
  const bufferTypes = {
17
18
  DRAW_POINTS: 0,
@@ -70,6 +71,9 @@ export const provideDrawAPI = () => {
70
71
  const logs = useLogs();
71
72
  const cameraControls = useCameraControls();
72
73
  const { invalidate } = useThrelte();
74
+ const drawConnectionConfig = useDrawConnectionConfig();
75
+ const backendIP = $derived(drawConnectionConfig.current?.backendIP);
76
+ const websocketPort = $derived(drawConnectionConfig.current?.websocketPort);
73
77
  let pointsIndex = 0;
74
78
  let geometryIndex = 0;
75
79
  let poseIndex = 0;
@@ -82,7 +86,7 @@ export const provideDrawAPI = () => {
82
86
  const loader = new GLTFLoader();
83
87
  const entities = new Map();
84
88
  const sendResponse = (response) => {
85
- ws.send(JSON.stringify(response));
89
+ ws?.send(JSON.stringify(response));
86
90
  };
87
91
  const drawFrames = async (data) => {
88
92
  for (const rawFrame of data) {
@@ -286,6 +290,7 @@ export const provideDrawAPI = () => {
286
290
  for (const entity of world.query(traits.DrawAPI)) {
287
291
  if (entity.get(traits.Name) === name) {
288
292
  entity.destroy();
293
+ entities.delete(name);
289
294
  }
290
295
  }
291
296
  }
@@ -294,21 +299,27 @@ export const provideDrawAPI = () => {
294
299
  for (const entity of world.query(traits.DrawAPI)) {
295
300
  entity.destroy();
296
301
  }
302
+ entities.clear();
297
303
  pointsIndex = 0;
298
304
  geometryIndex = 0;
299
305
  poseIndex = 0;
300
306
  };
301
307
  const scheduleReconnect = () => {
302
308
  setTimeout(() => {
303
- reconnectDelay = Math.min(reconnectDelay * 2, maxReconnectDelay);
304
- logs.add(`Reconnecting to drawing server in ${reconnectDelay / 1000} seconds...`, 'warn');
305
- connect();
309
+ if (backendIP && websocketPort) {
310
+ reconnectDelay = Math.min(reconnectDelay * 2, maxReconnectDelay);
311
+ logs.add(`Reconnecting to drawing server in ${reconnectDelay / 1000} seconds...`, 'warn');
312
+ connect(backendIP, websocketPort);
313
+ }
314
+ else {
315
+ logs.add('No provided backend IP or websocket port', 'error');
316
+ }
306
317
  }, reconnectDelay);
307
318
  };
308
319
  const onOpen = () => {
309
320
  connectionStatus = 'open';
310
321
  reconnectDelay = 1000;
311
- logs.add(`Connected to drawing server at ${BACKEND_IP}:${WS_PORT}`);
322
+ logs.add(`Connected to drawing server at ${backendIP}:${websocketPort}`);
312
323
  };
313
324
  const onClose = () => {
314
325
  connectionStatus = 'closed';
@@ -317,7 +328,7 @@ export const provideDrawAPI = () => {
317
328
  };
318
329
  const onError = (event) => {
319
330
  const stringified = JSON.stringify(event);
320
- ws.close();
331
+ ws?.close();
321
332
  if (stringified === '{"isTrusted":true}') {
322
333
  return;
323
334
  }
@@ -409,17 +420,31 @@ export const provideDrawAPI = () => {
409
420
  }
410
421
  invalidate();
411
422
  };
412
- const connect = () => {
413
- if (BACKEND_IP && WS_PORT) {
414
- const protocol = location.protocol === 'https:' ? 'wss' : 'ws';
415
- ws = new WebSocket(`${protocol}://${BACKEND_IP}:${WS_PORT}/ws`);
416
- ws.onclose = onClose;
417
- ws.onerror = onError;
418
- ws.onopen = onOpen;
419
- ws.onmessage = onMessage;
420
- }
423
+ const connect = (backendIP, websocketPort) => {
424
+ const protocol = location.protocol === 'https:' ? 'wss' : 'ws';
425
+ ws = new WebSocket(`${protocol}://${backendIP}:${websocketPort}/ws`);
426
+ ws.onclose = onClose;
427
+ ws.onerror = onError;
428
+ ws.onopen = onOpen;
429
+ ws.onmessage = onMessage;
430
+ };
431
+ const disconnect = () => {
432
+ ws?.removeEventListener('close', onClose);
433
+ ws?.removeEventListener('error', onError);
434
+ ws?.removeEventListener('open', onOpen);
435
+ ws?.removeEventListener('message', onMessage);
436
+ ws?.close();
437
+ ws = undefined;
421
438
  };
422
- connect();
439
+ $effect(() => {
440
+ if (!backendIP || !websocketPort) {
441
+ return;
442
+ }
443
+ connect(backendIP, websocketPort);
444
+ return () => {
445
+ disconnect();
446
+ };
447
+ });
423
448
  setContext(key, {
424
449
  get connectionStatus() {
425
450
  return connectionStatus;
@@ -0,0 +1,10 @@
1
+ export interface DrawConnectionConfig {
2
+ backendIP: string;
3
+ websocketPort: string;
4
+ }
5
+ interface Context {
6
+ current: DrawConnectionConfig | undefined;
7
+ }
8
+ export declare const provideDrawConnectionConfig: (args: () => DrawConnectionConfig | undefined) => void;
9
+ export declare const useDrawConnectionConfig: () => Context;
10
+ export {};
@@ -0,0 +1,13 @@
1
+ import { getContext, setContext } from 'svelte';
2
+ const key = Symbol('draw-connection-config-key');
3
+ export const provideDrawConnectionConfig = (args) => {
4
+ const current = $derived(args());
5
+ setContext(key, {
6
+ get current() {
7
+ return current;
8
+ },
9
+ });
10
+ };
11
+ export const useDrawConnectionConfig = () => {
12
+ return getContext(key);
13
+ };
@@ -18,7 +18,7 @@ export const provideFrames = (partID) => {
18
18
  const machineStatus = useMachineStatus(partID);
19
19
  const logs = useLogs();
20
20
  const query = createRobotQuery(client, 'frameSystemConfig', () => ({
21
- enabled: environment.current.viewerMode === 'monitor',
21
+ enabled: partID() !== '' && environment.current.viewerMode === 'monitor',
22
22
  }));
23
23
  const revision = $derived(machineStatus.current?.config?.revision);
24
24
  const partConfig = usePartConfig();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@viamrobotics/motion-tools",
3
- "version": "1.1.4",
3
+ "version": "1.1.6",
4
4
  "description": "Motion visualization with Viam",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
@@ -39,6 +39,8 @@
39
39
  "@viamrobotics/svelte-sdk": "1.0.1",
40
40
  "@vitejs/plugin-basic-ssl": "2.1.0",
41
41
  "@vitest/coverage-v8": "^3.2.4",
42
+ "@zag-js/collapsible": "1.22.1",
43
+ "@zag-js/floating-panel": "1.22.1",
42
44
  "@zag-js/svelte": "1.22.1",
43
45
  "@zag-js/tree-view": "1.22.1",
44
46
  "camera-controls": "3.1.0",
@@ -78,6 +80,8 @@
78
80
  "@viamrobotics/prime-core": ">=0.1",
79
81
  "@viamrobotics/sdk": ">=0.38",
80
82
  "@viamrobotics/svelte-sdk": ">=0.1",
83
+ "@zag-js/collapsible": ">=1",
84
+ "@zag-js/floating-panel": ">=1",
81
85
  "@zag-js/svelte": ">=1",
82
86
  "@zag-js/tree-view": ">=1",
83
87
  "camera-controls": ">=3",