@viamrobotics/motion-tools 1.32.0 → 1.33.1

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 (132) hide show
  1. package/dist/components/App.svelte +17 -11
  2. package/dist/components/App.svelte.d.ts +14 -7
  3. package/dist/components/Entities/Entities.svelte +18 -25
  4. package/dist/components/Entities/Entities.svelte.d.ts +2 -17
  5. package/dist/components/Entities/Label.svelte +79 -13
  6. package/dist/components/Entities/Label.svelte.d.ts +2 -1
  7. package/dist/components/Entities/Labels.svelte +36 -0
  8. package/dist/components/Entities/Labels.svelte.d.ts +3 -0
  9. package/dist/components/Entities/LineDots.svelte +8 -3
  10. package/dist/components/Entities/labelLayout/applyTeleports.d.ts +9 -0
  11. package/dist/components/Entities/labelLayout/applyTeleports.js +39 -0
  12. package/dist/components/Entities/labelLayout/buildNeighborhood.d.ts +8 -0
  13. package/dist/components/Entities/labelLayout/buildNeighborhood.js +26 -0
  14. package/dist/components/Entities/labelLayout/cameraHash.d.ts +8 -0
  15. package/dist/components/Entities/labelLayout/cameraHash.js +25 -0
  16. package/dist/components/Entities/labelLayout/cost.d.ts +44 -0
  17. package/dist/components/Entities/labelLayout/cost.js +126 -0
  18. package/dist/components/Entities/labelLayout/createLabelLayout.d.ts +27 -0
  19. package/dist/components/Entities/labelLayout/createLabelLayout.js +194 -0
  20. package/dist/components/Entities/labelLayout/geometry.d.ts +20 -0
  21. package/dist/components/Entities/labelLayout/geometry.js +151 -0
  22. package/dist/components/Entities/labelLayout/labelStore.svelte.d.ts +17 -0
  23. package/dist/components/Entities/labelLayout/labelStore.svelte.js +28 -0
  24. package/dist/components/Entities/labelLayout/measure.d.ts +13 -0
  25. package/dist/components/Entities/labelLayout/measure.js +42 -0
  26. package/dist/components/Entities/labelLayout/slots.d.ts +11 -0
  27. package/dist/components/Entities/labelLayout/slots.js +47 -0
  28. package/dist/components/Entities/labelLayout/solve.d.ts +11 -0
  29. package/dist/components/Entities/labelLayout/solve.js +93 -0
  30. package/dist/components/Entities/labelLayout/spatialHash.d.ts +15 -0
  31. package/dist/components/Entities/labelLayout/spatialHash.js +53 -0
  32. package/dist/components/Entities/labelLayout/types.d.ts +105 -0
  33. package/dist/components/Entities/labelLayout/types.js +19 -0
  34. package/dist/components/Entities/labelLayout/writeBack.d.ts +20 -0
  35. package/dist/components/Entities/labelLayout/writeBack.js +51 -0
  36. package/dist/components/Scene.svelte +42 -48
  37. package/dist/components/SceneProviders.svelte +0 -3
  38. package/dist/components/SelectedTransformControls.svelte +65 -47
  39. package/dist/components/overlay/Details.svelte +198 -224
  40. package/dist/components/overlay/Details.svelte.d.ts +1 -1
  41. package/dist/components/overlay/Popover.svelte +6 -4
  42. package/dist/components/overlay/Popover.svelte.d.ts +6 -2
  43. package/dist/components/overlay/dashboard/Button.svelte +7 -2
  44. package/dist/components/overlay/dashboard/Button.svelte.d.ts +2 -1
  45. package/dist/components/overlay/details/AxesHelperDetails.svelte +32 -0
  46. package/dist/components/overlay/details/AxesHelperDetails.svelte.d.ts +7 -0
  47. package/dist/components/overlay/details/ColorDetails.svelte +35 -0
  48. package/dist/components/overlay/details/ColorDetails.svelte.d.ts +7 -0
  49. package/dist/components/overlay/details/GeometryDetails.svelte +104 -0
  50. package/dist/components/overlay/details/GeometryDetails.svelte.d.ts +7 -0
  51. package/dist/components/overlay/details/LineDetails/LineDetails.svelte +196 -0
  52. package/dist/components/overlay/details/LineDetails/LineDetails.svelte.d.ts +7 -0
  53. package/dist/components/overlay/details/LineDetails/linePositions.d.ts +3 -0
  54. package/dist/components/overlay/details/LineDetails/linePositions.js +30 -0
  55. package/dist/components/overlay/details/OpacityDetails.svelte +44 -0
  56. package/dist/components/overlay/details/OpacityDetails.svelte.d.ts +7 -0
  57. package/dist/components/overlay/details/PoseDetails.svelte +189 -0
  58. package/dist/components/overlay/details/PoseDetails.svelte.d.ts +14 -0
  59. package/dist/components/overlay/settings/ConnectionSettings.svelte +42 -0
  60. package/dist/components/overlay/settings/ConnectionSettings.svelte.d.ts +18 -0
  61. package/dist/components/overlay/settings/DebugSettings.svelte +13 -0
  62. package/dist/components/{xr/frame-configure/Controllers.svelte.d.ts → overlay/settings/DebugSettings.svelte.d.ts} +3 -3
  63. package/dist/components/overlay/settings/PointcloudSettings.svelte +61 -0
  64. package/dist/components/overlay/settings/PointcloudSettings.svelte.d.ts +3 -0
  65. package/dist/components/overlay/settings/SceneSettings.svelte +110 -0
  66. package/dist/components/overlay/settings/SceneSettings.svelte.d.ts +18 -0
  67. package/dist/components/overlay/settings/Settings.svelte +27 -312
  68. package/dist/components/overlay/settings/Settings.svelte.d.ts +8 -1
  69. package/dist/components/overlay/settings/Tabs.svelte +5 -3
  70. package/dist/components/overlay/settings/Tabs.svelte.d.ts +3 -3
  71. package/dist/components/overlay/settings/VisionSettings.svelte +31 -0
  72. package/dist/components/overlay/settings/VisionSettings.svelte.d.ts +3 -0
  73. package/dist/components/overlay/settings/WeblabSettings.svelte +27 -0
  74. package/dist/components/overlay/settings/WeblabSettings.svelte.d.ts +18 -0
  75. package/dist/components/overlay/settings/WidgetSettings.svelte +49 -0
  76. package/dist/components/overlay/settings/WidgetSettings.svelte.d.ts +3 -0
  77. package/dist/components/overlay/widgets/FramePov.svelte +1 -12
  78. package/dist/ecs/traits.d.ts +1 -1
  79. package/dist/ecs/traits.js +1 -1
  80. package/dist/hooks/useWorldState.svelte.js +39 -50
  81. package/dist/{components/xr → plugins/XR}/ArmTeleop.svelte +3 -5
  82. package/dist/plugins/XR/DebugPanel.svelte +29 -0
  83. package/dist/plugins/XR/DebugPanel.svelte.d.ts +3 -0
  84. package/dist/plugins/XR/OriginMarker.svelte +341 -0
  85. package/dist/plugins/XR/PendingEditsPanel.svelte +60 -0
  86. package/dist/plugins/XR/PendingEditsPanel.svelte.d.ts +18 -0
  87. package/dist/plugins/XR/WristDisplay.svelte +60 -0
  88. package/dist/plugins/XR/WristDisplay.svelte.d.ts +19 -0
  89. package/dist/{components/xr → plugins/XR}/XR.svelte +69 -23
  90. package/dist/plugins/XR/XRPlugins.svelte +9 -0
  91. package/dist/plugins/XR/XRPlugins.svelte.d.ts +26 -0
  92. package/dist/plugins/XR/XRSettings.svelte +240 -0
  93. package/dist/plugins/XR/XRSettings.svelte.d.ts +3 -0
  94. package/dist/{components/xr → plugins/XR}/XRToast.svelte +6 -9
  95. package/dist/plugins/XR/debug.svelte.d.ts +7 -0
  96. package/dist/plugins/XR/debug.svelte.js +13 -0
  97. package/dist/plugins/XR/frame-configure/Controllers.svelte +413 -0
  98. package/dist/plugins/XR/teleop/Controllers.svelte.d.ts +3 -0
  99. package/dist/{components/xr → plugins/XR}/useAnchors.svelte.d.ts +4 -0
  100. package/dist/{components/xr → plugins/XR}/useAnchors.svelte.js +22 -0
  101. package/dist/plugins/XR/useOrigin.svelte.d.ts +24 -0
  102. package/dist/plugins/XR/useOrigin.svelte.js +50 -0
  103. package/dist/plugins/index.d.ts +2 -0
  104. package/dist/plugins/index.js +2 -0
  105. package/dist/three/OBBHelper.js +1 -0
  106. package/package.json +3 -1
  107. package/dist/components/xr/OriginMarker.svelte +0 -151
  108. package/dist/components/xr/XRControllerSettings.svelte +0 -242
  109. package/dist/components/xr/XRControllerSettings.svelte.d.ts +0 -3
  110. package/dist/components/xr/frame-configure/Controllers.svelte +0 -6
  111. package/dist/components/xr/useOrigin.svelte.d.ts +0 -9
  112. package/dist/components/xr/useOrigin.svelte.js +0 -27
  113. /package/dist/{components/xr → plugins/XR}/ArmTeleop.svelte.d.ts +0 -0
  114. /package/dist/{components/xr → plugins/XR}/BentPlaneGeometry.svelte +0 -0
  115. /package/dist/{components/xr → plugins/XR}/BentPlaneGeometry.svelte.d.ts +0 -0
  116. /package/dist/{components/xr → plugins/XR}/CameraFeed.svelte +0 -0
  117. /package/dist/{components/xr → plugins/XR}/CameraFeed.svelte.d.ts +0 -0
  118. /package/dist/{components/xr → plugins/XR}/JointLimitsWidget.svelte +0 -0
  119. /package/dist/{components/xr → plugins/XR}/JointLimitsWidget.svelte.d.ts +0 -0
  120. /package/dist/{components/xr → plugins/XR}/OriginMarker.svelte.d.ts +0 -0
  121. /package/dist/{components/xr → plugins/XR}/PointDistance.svelte +0 -0
  122. /package/dist/{components/xr → plugins/XR}/PointDistance.svelte.d.ts +0 -0
  123. /package/dist/{components/xr → plugins/XR}/XR.svelte.d.ts +0 -0
  124. /package/dist/{components/xr → plugins/XR}/XRConfigPanel.svelte +0 -0
  125. /package/dist/{components/xr → plugins/XR}/XRConfigPanel.svelte.d.ts +0 -0
  126. /package/dist/{components/xr → plugins/XR}/XRToast.svelte.d.ts +0 -0
  127. /package/dist/{components/xr/teleop → plugins/XR/frame-configure}/Controllers.svelte.d.ts +0 -0
  128. /package/dist/{components/xr → plugins/XR}/math.d.ts +0 -0
  129. /package/dist/{components/xr → plugins/XR}/math.js +0 -0
  130. /package/dist/{components/xr → plugins/XR}/teleop/Controllers.svelte +0 -0
  131. /package/dist/{components/xr → plugins/XR}/toasts.svelte.d.ts +0 -0
  132. /package/dist/{components/xr → plugins/XR}/toasts.svelte.js +0 -0
@@ -1,5 +1,5 @@
1
1
  <script lang="ts">
2
- import type { Snippet } from 'svelte'
2
+ import type { Component } from 'svelte'
3
3
 
4
4
  import { normalizeProps, useMachine } from '@zag-js/svelte'
5
5
  import * as tabs from '@zag-js/tabs'
@@ -9,7 +9,7 @@
9
9
  onValueChange: (value: string) => void
10
10
  items: {
11
11
  label: string
12
- content: Snippet
12
+ component: Component
13
13
  }[]
14
14
  }
15
15
 
@@ -45,11 +45,13 @@
45
45
  </div>
46
46
 
47
47
  {#each items as item (item.label)}
48
+ {@const Component = item.component}
49
+
48
50
  <div
49
51
  {...api.getContentProps({ value: item.label })}
50
52
  class="h-full w-full overflow-y-auto p-4"
51
53
  >
52
- {@render item.content()}
54
+ <Component />
53
55
  </div>
54
56
  {/each}
55
57
  </div>
@@ -1,12 +1,12 @@
1
- import type { Snippet } from 'svelte';
1
+ import type { Component } from 'svelte';
2
2
  interface Props {
3
3
  defaultTab?: string;
4
4
  onValueChange: (value: string) => void;
5
5
  items: {
6
6
  label: string;
7
- content: Snippet;
7
+ component: Component;
8
8
  }[];
9
9
  }
10
- declare const Tabs: import("svelte").Component<Props, {}, "">;
10
+ declare const Tabs: Component<Props, {}, "">;
11
11
  type Tabs = ReturnType<typeof Tabs>;
12
12
  export default Tabs;
@@ -0,0 +1,31 @@
1
+ <script lang="ts">
2
+ import { Switch } from '@viamrobotics/prime-core'
3
+ import { useResourceNames } from '@viamrobotics/svelte-sdk'
4
+
5
+ import { usePartID } from '../../../hooks/usePartID.svelte'
6
+ import { useSettings } from '../../../hooks/useSettings.svelte'
7
+
8
+ const partID = usePartID()
9
+
10
+ const visionServices = useResourceNames(() => partID.current, 'vision')
11
+ const settings = useSettings()
12
+ const { disabledVisionServices } = $derived(settings.current)
13
+ </script>
14
+
15
+ <div class="text-gray-9 flex flex-col gap-1 text-xs">
16
+ <h3 class="border-gray-3 border-b py-1 text-sm"><strong>Enabled vision services</strong></h3>
17
+
18
+ {#each visionServices.current as visionService (visionService)}
19
+ <div class="flex items-center justify-between py-0.5">
20
+ {visionService.name}
21
+ <Switch
22
+ on={disabledVisionServices[visionService.name] !== true}
23
+ on:change={(event) => {
24
+ disabledVisionServices[visionService.name] = !event.detail
25
+ }}
26
+ />
27
+ </div>
28
+ {:else}
29
+ No vision services detected
30
+ {/each}
31
+ </div>
@@ -0,0 +1,3 @@
1
+ declare const VisionSettings: import("svelte").Component<Record<string, never>, {}, "">;
2
+ type VisionSettings = ReturnType<typeof VisionSettings>;
3
+ export default VisionSettings;
@@ -0,0 +1,27 @@
1
+ <script lang="ts">
2
+ import { Switch } from '@viamrobotics/prime-core'
3
+ import { onMount } from 'svelte'
4
+
5
+ import { useWeblabs, WEBLABS_EXPERIMENTS } from '../../../hooks/useWeblabs.svelte'
6
+
7
+ const weblabs = useWeblabs()
8
+ const knownWeblabs = Object.keys(WEBLABS_EXPERIMENTS)
9
+
10
+ onMount(() => {
11
+ weblabs.load(knownWeblabs)
12
+ })
13
+ </script>
14
+
15
+ <div class="flex flex-col gap-1 text-xs">
16
+ {#each knownWeblabs as experiment (experiment)}
17
+ <label class="flex items-center justify-between gap-2 py-0.5">
18
+ {experiment}
19
+ <Switch
20
+ on={weblabs.isActive(experiment)}
21
+ on:change={() => weblabs.toggle(experiment)}
22
+ />
23
+ </label>
24
+ {:else}
25
+ No weblabs defined
26
+ {/each}
27
+ </div>
@@ -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 WeblabSettings: $$__sveltets_2_IsomorphicComponent<Record<string, never>, {
15
+ [evt: string]: CustomEvent<any>;
16
+ }, {}, {}, string>;
17
+ type WeblabSettings = InstanceType<typeof WeblabSettings>;
18
+ export default WeblabSettings;
@@ -0,0 +1,49 @@
1
+ <script lang="ts">
2
+ import { Switch } from '@viamrobotics/prime-core'
3
+ import { useResourceNames } from '@viamrobotics/svelte-sdk'
4
+
5
+ import { usePartID } from '../../../hooks/usePartID.svelte'
6
+ import { useSettings } from '../../../hooks/useSettings.svelte'
7
+
8
+ const partID = usePartID()
9
+ const cameras = useResourceNames(() => partID.current, 'camera')
10
+ const settings = useSettings()
11
+
12
+ const currentRobotCameraWidgets = $derived(
13
+ settings.current.openCameraWidgets[partID.current] || []
14
+ )
15
+ </script>
16
+
17
+ <div class="text-gray-9 flex flex-col gap-1 text-xs">
18
+ <label class="flex items-center justify-between gap-2 py-1">
19
+ Arm positions
20
+ <Switch bind:on={settings.current.enableArmPositionsWidget} />
21
+ </label>
22
+
23
+ <h3 class="border-gray-3 border-b py-1 text-sm"><strong>Camera widgets</strong></h3>
24
+
25
+ {#each cameras.current as camera (camera)}
26
+ {@const isWidgetOpen = currentRobotCameraWidgets.includes(camera.name)}
27
+ <div class="flex items-center justify-between gap-2 py-0.5">
28
+ <span class="min-w-0 truncate">{camera.name}</span>
29
+ <Switch
30
+ on={isWidgetOpen}
31
+ on:change={(event) => {
32
+ settings.current.openCameraWidgets = event.detail
33
+ ? {
34
+ ...settings.current.openCameraWidgets,
35
+ [partID.current]: [...currentRobotCameraWidgets, camera.name],
36
+ }
37
+ : {
38
+ ...settings.current.openCameraWidgets,
39
+ [partID.current]: currentRobotCameraWidgets.filter(
40
+ (widget) => widget !== camera.name
41
+ ),
42
+ }
43
+ }}
44
+ />
45
+ </div>
46
+ {:else}
47
+ No cameras detected
48
+ {/each}
49
+ </div>
@@ -0,0 +1,3 @@
1
+ declare const WidgetSettings: import("svelte").Component<Record<string, never>, {}, "">;
2
+ type WidgetSettings = ReturnType<typeof WidgetSettings>;
3
+ export default WidgetSettings;
@@ -7,7 +7,6 @@
7
7
  import { usePartID } from '../../../hooks/usePartID.svelte'
8
8
  import { useSettings } from '../../../hooks/useSettings.svelte'
9
9
 
10
- import { useOrigin } from '../../xr/useOrigin.svelte'
11
10
  import Button from '../dashboard/Button.svelte'
12
11
  import FloatingPanel from '../FloatingPanel.svelte'
13
12
 
@@ -20,7 +19,6 @@
20
19
  const { scene, renderer: mainRenderer, renderStage, invalidate } = useThrelte()
21
20
  const settings = useSettings()
22
21
  const partID = usePartID()
23
- const origin = useOrigin()
24
22
 
25
23
  // Three.js cameras look down -Z; Viam camera frames conventionally have the
26
24
  // optical axis along +Z with image-down along +Y. A 180° rotation around X
@@ -53,7 +51,6 @@
53
51
  const orthoHeight = $derived(BASE_ORTHO_HEIGHT / orthoZoom)
54
52
 
55
53
  const composed = new Matrix4()
56
- const originMat = new Matrix4()
57
54
 
58
55
  $effect(() => {
59
56
  if (!canvasEl) return
@@ -121,15 +118,7 @@
121
118
 
122
119
  const povCamera = cameraMode === 'perspective' ? perspectiveCamera : orthographicCamera
123
120
 
124
- // Compose origin × worldMatrix × VIAM_TO_THREE_CAMERA. The frame
125
- // entities' WorldMatrix lives in ECS world space; the rendered scene
126
- // is wrapped in a T.Group that applies `origin` on top, so the POV
127
- // camera needs the same origin transform to share coordinate space
128
- // with the meshes it's rendering.
129
- originMat
130
- .makeRotationZ(origin.rotation)
131
- .setPosition(origin.position[0], origin.position[1], origin.position[2])
132
- composed.copy(originMat).multiply(worldMat).multiply(VIAM_TO_THREE_CAMERA)
121
+ composed.multiplyMatrices(worldMat, VIAM_TO_THREE_CAMERA)
133
122
  composed.decompose(povCamera.position, povCamera.quaternion, povCamera.scale)
134
123
 
135
124
  const aspect = width / height
@@ -71,7 +71,7 @@ export declare const Invisible: import("koota").Trait<() => boolean>;
71
71
  * `details-extensions` portal target (e.g. gizmo plugin entities) opt in by
72
72
  * adding this trait.
73
73
  */
74
- export declare const CustomDetails: import("koota").Trait<() => boolean>;
74
+ export declare const CustomDetails: import("koota").TagTrait;
75
75
  /**
76
76
  * True when the entity itself, or any of its parents up the `ChildOf`
77
77
  * chain, has `Invisible`. Maintained by `provideInheritedInvisible`;
@@ -68,7 +68,7 @@ export const Invisible = trait(() => true);
68
68
  * `details-extensions` portal target (e.g. gizmo plugin entities) opt in by
69
69
  * adding this trait.
70
70
  */
71
- export const CustomDetails = trait(() => true);
71
+ export const CustomDetails = trait();
72
72
  /**
73
73
  * True when the entity itself, or any of its parents up the `ChildOf`
74
74
  * chain, has `Invisible`. Maintained by `provideInheritedInvisible`;
@@ -1,6 +1,6 @@
1
1
  import { useThrelte } from '@threlte/core';
2
2
  import { Struct, TransformChangeType, WorldStateStoreClient, } from '@viamrobotics/sdk';
3
- import { createResourceClient, createResourceQuery, createResourceStream, useResourceNames, } from '@viamrobotics/svelte-sdk';
3
+ import { createResourceClient, createResourceQuery, useResourceNames, } from '@viamrobotics/svelte-sdk';
4
4
  import { Matrix4 } from 'three';
5
5
  import { asFloat32Array, inMeters } from '../buffer';
6
6
  import { createChunkLoader } from '../chunking';
@@ -161,14 +161,12 @@ const createWorldState = (client) => {
161
161
  };
162
162
  let initialized = false;
163
163
  let flushScheduled = false;
164
+ let rafId = 0;
164
165
  let pendingEvents = [];
165
166
  const listUUIDs = createResourceQuery(client, 'listUUIDs');
166
167
  const getTransformQueries = $derived(listUUIDs.data?.map((uuid) => {
167
168
  return createResourceQuery(client, 'getTransform', () => [uuid], () => ({ refetchInterval: false }));
168
169
  }));
169
- const changeStream = createResourceStream(client, 'streamTransformChanges', {
170
- refetchMode: 'replace',
171
- });
172
170
  const applyEvents = (events) => {
173
171
  for (const event of events) {
174
172
  if (event.changeType === TransformChangeType.ADDED) {
@@ -190,11 +188,12 @@ const createWorldState = (client) => {
190
188
  if (flushScheduled)
191
189
  return;
192
190
  flushScheduled = true;
193
- requestAnimationFrame(() => {
194
- const toApply = pendingEvents;
195
- applyEvents(toApply);
191
+ rafId = requestAnimationFrame(() => {
192
+ rafId = 0;
196
193
  flushScheduled = false;
194
+ const toApply = pendingEvents;
197
195
  pendingEvents = [];
196
+ applyEvents(toApply);
198
197
  });
199
198
  };
200
199
  $effect(() => {
@@ -213,55 +212,45 @@ const createWorldState = (client) => {
213
212
  invalidate();
214
213
  initialized = true;
215
214
  });
216
- $effect(() => {
217
- if (changeStream?.data === undefined)
215
+ /**
216
+ * Consumes the `streamTransformChanges` server stream directly.
217
+ * Transform changes are write-once into the ECS world, so we drain
218
+ * each event into `pendingEvents` (cleared every flush) and never
219
+ * retain history. Mirrors `useDrawService`'s stream consumption.
220
+ */
221
+ const consumeChanges = async (signal) => {
222
+ const activeClient = client.current;
223
+ if (!activeClient)
218
224
  return;
219
- const eventsByUUID = new Map();
220
- for (const event of changeStream.data) {
221
- if (!event.transform) {
222
- continue;
223
- }
224
- const uuid = event.transform.uuidString;
225
- const existing = eventsByUUID.get(uuid);
226
- if (!existing) {
227
- eventsByUUID.set(uuid, event);
228
- continue;
229
- }
230
- switch (event.changeType) {
231
- case TransformChangeType.REMOVED: {
232
- eventsByUUID.set(uuid, event);
233
- break;
234
- }
235
- case TransformChangeType.ADDED: {
236
- if (existing.changeType !== TransformChangeType.REMOVED) {
237
- eventsByUUID.set(uuid, event);
238
- }
239
- break;
240
- }
241
- case TransformChangeType.UPDATED: {
242
- // merge with existing updated event
243
- if (existing.changeType === TransformChangeType.UPDATED) {
244
- existing.updatedFields ??= { paths: [] };
245
- const paths = event.updatedFields?.paths ?? [];
246
- for (const path of paths) {
247
- if (existing.updatedFields.paths.includes(path)) {
248
- continue;
249
- }
250
- existing.updatedFields.paths.push(path);
251
- }
252
- existing.transform = event.transform;
253
- }
254
- else {
255
- eventsByUUID.set(uuid, event);
256
- }
225
+ try {
226
+ for await (const event of activeClient.streamTransformChanges(undefined, { signal })) {
227
+ if (signal.aborted)
257
228
  break;
258
- }
229
+ if (!event.transform)
230
+ continue;
231
+ pendingEvents.push(event);
232
+ scheduleFlush();
233
+ }
234
+ }
235
+ catch (error) {
236
+ if (!signal.aborted) {
237
+ console.error('World state transform stream error:', error);
259
238
  }
260
239
  }
261
- pendingEvents.push(...eventsByUUID.values());
262
- scheduleFlush();
240
+ };
241
+ $effect(() => {
242
+ if (!client.current)
243
+ return;
244
+ const controller = new AbortController();
245
+ void consumeChanges(controller.signal);
246
+ return () => {
247
+ controller.abort();
248
+ };
263
249
  });
264
250
  return () => {
251
+ if (rafId)
252
+ cancelAnimationFrame(rafId);
253
+ pendingEvents = [];
265
254
  chunkLoader.dispose();
266
255
  for (const [, entity] of entities) {
267
256
  if (world.has(entity)) {
@@ -6,14 +6,12 @@
6
6
  import { createResourceClient } from '@viamrobotics/svelte-sdk'
7
7
  import { Quaternion, Vector3 } from 'three'
8
8
 
9
- import {
10
- calculatePositionTarget,
11
- getFrameTransformationQuaternion,
12
- } from './math'
13
- import { xrToast } from './toasts.svelte'
14
9
  import { usePartID } from '../../hooks/usePartID.svelte'
15
10
  import { OrientationVector } from '../../three/OrientationVector'
16
11
 
12
+ import { calculatePositionTarget, getFrameTransformationQuaternion } from './math'
13
+ import { xrToast } from './toasts.svelte'
14
+
17
15
  interface Props {
18
16
  armName: string
19
17
  gripperName?: string
@@ -0,0 +1,29 @@
1
+ <script lang="ts">
2
+ import { Text } from 'threlte-uikit'
3
+ import { Panel } from 'threlte-uikit/horizon'
4
+
5
+ import { xrDebug } from './debug.svelte'
6
+ import WristDisplay from './WristDisplay.svelte'
7
+
8
+ const messages = $derived(xrDebug.messages)
9
+ </script>
10
+
11
+ <WristDisplay position={[0, 0.005, 0.2]}>
12
+ <Panel
13
+ flexDirection="column"
14
+ padding={12}
15
+ gap={4}
16
+ backgroundColor="#0a0a0a"
17
+ borderRadius={8}
18
+ minWidth={400}
19
+ minHeight={40}
20
+ >
21
+ {#each messages as message, i (i)}
22
+ <Text
23
+ text={message}
24
+ fontSize={14}
25
+ color="#ffffff"
26
+ />
27
+ {/each}
28
+ </Panel>
29
+ </WristDisplay>
@@ -0,0 +1,3 @@
1
+ declare const DebugPanel: import("svelte").Component<Record<string, never>, {}, "">;
2
+ type DebugPanel = ReturnType<typeof DebugPanel>;
3
+ export default DebugPanel;