@viamrobotics/motion-tools 1.10.0 → 1.11.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.
Files changed (106) hide show
  1. package/dist/HoverUpdater.svelte.d.ts +0 -3
  2. package/dist/HoverUpdater.svelte.js +8 -50
  3. package/dist/WorldObject.svelte.d.ts +27 -0
  4. package/dist/WorldObject.svelte.js +8 -55
  5. package/dist/{draw → buf/draw}/v1/drawing_pb.d.ts +6 -0
  6. package/dist/{draw → buf/draw}/v1/drawing_pb.js +7 -0
  7. package/dist/buf/draw/v1/service_connect.d.ts +122 -0
  8. package/dist/buf/draw/v1/service_connect.js +126 -0
  9. package/dist/buf/draw/v1/service_pb.d.ts +382 -0
  10. package/dist/buf/draw/v1/service_pb.js +612 -0
  11. package/dist/components/App.svelte +0 -1
  12. package/dist/components/Arrows/Arrows.svelte +16 -3
  13. package/dist/components/FileDrop/file-dropper.d.ts +1 -1
  14. package/dist/components/FileDrop/snapshot-dropper.js +1 -1
  15. package/dist/components/FileDrop/useFileDrop.svelte.d.ts +2 -1
  16. package/dist/components/Frame.svelte +1 -1
  17. package/dist/components/Geometry.svelte +113 -71
  18. package/dist/components/Geometry.svelte.d.ts +6 -7
  19. package/dist/components/SceneProviders.svelte +2 -0
  20. package/dist/components/Snapshot.svelte +1 -1
  21. package/dist/components/Snapshot.svelte.d.ts +1 -1
  22. package/dist/components/overlay/Details.svelte +20 -0
  23. package/dist/components/overlay/left-pane/TreeContainer.svelte +0 -2
  24. package/dist/components/overlay/settings/Settings.svelte +51 -0
  25. package/dist/components/overlay/widgets/Camera.svelte +20 -12
  26. package/dist/components/xr/ArmTeleop.svelte +469 -0
  27. package/dist/components/xr/ArmTeleop.svelte.d.ts +10 -0
  28. package/dist/components/xr/CameraFeed.svelte +191 -47
  29. package/dist/components/xr/CameraFeed.svelte.d.ts +7 -0
  30. package/dist/components/xr/Controllers.svelte +45 -38
  31. package/dist/components/xr/Controllers.svelte.d.ts +2 -17
  32. package/dist/components/xr/Hands.svelte +2 -4
  33. package/dist/components/xr/JointLimitsWidget.svelte +209 -0
  34. package/dist/components/xr/JointLimitsWidget.svelte.d.ts +13 -0
  35. package/dist/components/xr/OriginMarker.svelte +1 -15
  36. package/dist/components/xr/XR.svelte +78 -5
  37. package/dist/components/xr/XRConfigPanel.svelte +449 -0
  38. package/dist/components/xr/XRConfigPanel.svelte.d.ts +11 -0
  39. package/dist/components/xr/XRControllerSettings.svelte +240 -0
  40. package/dist/components/xr/XRControllerSettings.svelte.d.ts +3 -0
  41. package/dist/components/xr/XRToast.svelte +215 -0
  42. package/dist/components/xr/XRToast.svelte.d.ts +3 -0
  43. package/dist/components/xr/math.d.ts +14 -0
  44. package/dist/components/xr/math.js +26 -0
  45. package/dist/components/xr/toasts.svelte.d.ts +20 -0
  46. package/dist/components/xr/toasts.svelte.js +32 -0
  47. package/dist/components/xr/useOrigin.svelte.d.ts +2 -2
  48. package/dist/components/xr/useOrigin.svelte.js +4 -4
  49. package/dist/ecs/traits.d.ts +9 -0
  50. package/dist/ecs/traits.js +9 -0
  51. package/dist/ecs/useTrait.svelte.d.ts +3 -3
  52. package/dist/frame.d.ts +0 -3
  53. package/dist/hooks/useArmKinematics.svelte.d.ts +12 -0
  54. package/dist/hooks/useArmKinematics.svelte.js +31 -0
  55. package/dist/hooks/useGeometries.svelte.js +46 -35
  56. package/dist/hooks/useObjectEvents.svelte.js +24 -7
  57. package/dist/hooks/usePartConfig.svelte.d.ts +0 -35
  58. package/dist/hooks/usePartConfig.svelte.js +2 -2
  59. package/dist/hooks/usePointcloudObjects.svelte.js +44 -63
  60. package/dist/hooks/usePointclouds.svelte.js +10 -6
  61. package/dist/hooks/usePose.svelte.js +4 -1
  62. package/dist/hooks/useResourceByName.svelte.d.ts +7 -0
  63. package/dist/hooks/useResourceByName.svelte.js +2 -2
  64. package/dist/hooks/useSettings.svelte.d.ts +14 -0
  65. package/dist/hooks/useSettings.svelte.js +10 -0
  66. package/dist/hooks/useWorldState.svelte.d.ts +0 -8
  67. package/dist/lib.d.ts +1 -3
  68. package/dist/lib.js +1 -3
  69. package/dist/snapshot.d.ts +2 -2
  70. package/dist/snapshot.js +2 -2
  71. package/dist/three/InstancedArrows/raycast.d.ts +2 -4
  72. package/dist/three/InstancedArrows/raycast.js +5 -5
  73. package/dist/transform.js +1 -0
  74. package/package.json +4 -5
  75. package/dist/assert.d.ts +0 -14
  76. package/dist/assert.js +0 -21
  77. package/dist/components/BatchedGeometry.svelte +0 -0
  78. package/dist/components/BatchedGeometry.svelte.d.ts +0 -26
  79. package/dist/components/Detections.svelte +0 -41
  80. package/dist/components/Detections.svelte.d.ts +0 -3
  81. package/dist/components/DetectionsPlane.svelte +0 -23
  82. package/dist/components/DetectionsPlane.svelte.d.ts +0 -21
  83. package/dist/components/Geometry2.svelte +0 -211
  84. package/dist/components/Geometry2.svelte.d.ts +0 -19
  85. package/dist/components/overlay/left-pane/Widgets.svelte +0 -65
  86. package/dist/components/overlay/left-pane/Widgets.svelte.d.ts +0 -3
  87. package/dist/entries.d.ts +0 -1
  88. package/dist/entries.js +0 -3
  89. package/dist/hooks/index.d.ts +0 -0
  90. package/dist/hooks/index.js +0 -1
  91. package/dist/test.d.ts +0 -1
  92. package/dist/test.js +0 -1
  93. package/dist/three/BoxHelper.d.ts +0 -50
  94. package/dist/three/BoxHelper.js +0 -134
  95. /package/dist/{common → buf/common}/v1/common_pb.d.ts +0 -0
  96. /package/dist/{common → buf/common}/v1/common_pb.js +0 -0
  97. /package/dist/{draw → buf/draw}/v1/metadata_pb.d.ts +0 -0
  98. /package/dist/{draw → buf/draw}/v1/metadata_pb.js +0 -0
  99. /package/dist/{draw → buf/draw}/v1/scene_pb.d.ts +0 -0
  100. /package/dist/{draw → buf/draw}/v1/scene_pb.js +0 -0
  101. /package/dist/{draw → buf/draw}/v1/snapshot_pb.d.ts +0 -0
  102. /package/dist/{draw → buf/draw}/v1/snapshot_pb.js +0 -0
  103. /package/dist/{draw → buf/draw}/v1/transforms_pb.d.ts +0 -0
  104. /package/dist/{draw → buf/draw}/v1/transforms_pb.js +0 -0
  105. /package/dist/components/{BentPlaneGeometry.svelte → xr/BentPlaneGeometry.svelte} +0 -0
  106. /package/dist/components/{BentPlaneGeometry.svelte.d.ts → xr/BentPlaneGeometry.svelte.d.ts} +0 -0
@@ -0,0 +1,31 @@
1
+ import { ArmClient } from '@viamrobotics/sdk';
2
+ import { createResourceClient, createResourceQuery, useResourceNames, } from '@viamrobotics/svelte-sdk';
3
+ import { getContext, setContext } from 'svelte';
4
+ const key = Symbol('arm-kinematics-context');
5
+ export const provideArmKinematics = (partID) => {
6
+ const arms = useResourceNames(partID, 'arm');
7
+ // Kinematics are static config data, so fetch once and cache indefinitely
8
+ const options = { staleTime: Infinity, refetchOnMount: false, refetchInterval: false };
9
+ const names = $derived(arms.current.map((arm) => arm.name));
10
+ const clients = $derived(arms.current.map((arm) => createResourceClient(ArmClient, partID, () => arm.name)));
11
+ const kinematicsQueries = $derived(clients.map((client) => [client.current?.name, createResourceQuery(client, 'getKinematics', () => options)]));
12
+ const kinematics = $derived(Object.fromEntries(kinematicsQueries.map(([name, query]) => [
13
+ name,
14
+ query.data?.joints.map((j) => ({
15
+ id: j.id,
16
+ min: j.min,
17
+ max: j.max,
18
+ })),
19
+ ])));
20
+ setContext(key, {
21
+ get names() {
22
+ return names;
23
+ },
24
+ get kinematics() {
25
+ return kinematics;
26
+ },
27
+ });
28
+ };
29
+ export const useArmKinematics = () => {
30
+ return getContext(key);
31
+ };
@@ -1,5 +1,5 @@
1
1
  import { ArmClient, CameraClient, GantryClient, GripperClient } from '@viamrobotics/sdk';
2
- import { setContext, getContext } from 'svelte';
2
+ import { untrack, setContext, getContext } from 'svelte';
3
3
  import { RefreshRates, useMachineSettings } from './useMachineSettings.svelte';
4
4
  import { createResourceClient, createResourceQuery, useResourceNames, } from '@viamrobotics/svelte-sdk';
5
5
  import { useLogs } from './useLogs.svelte';
@@ -27,8 +27,8 @@ export const provideGeometries = (partID) => {
27
27
  const gripperClients = $derived(grippers.current.map((gripper) => createResourceClient(GripperClient, partID, () => gripper.name)));
28
28
  const cameraClients = $derived(cameras.current.map((camera) => createResourceClient(CameraClient, partID, () => camera.name)));
29
29
  const gantryClients = $derived(gantries.current.map((gantry) => createResourceClient(GantryClient, partID, () => gantry.name)));
30
+ const interval = $derived(refreshRates.get(RefreshRates.poses));
30
31
  const options = $derived.by(() => {
31
- const interval = refreshRates.get(RefreshRates.poses);
32
32
  return {
33
33
  enabled: refreshRates.get(RefreshRates.poses) !== RefetchRates.OFF &&
34
34
  environment.current.viewerMode === 'monitor',
@@ -40,13 +40,20 @@ export const provideGeometries = (partID) => {
40
40
  const cameraQueries = $derived(cameraClients.map((client) => [client.current?.name, createResourceQuery(client, 'getGeometries', () => options)]));
41
41
  const gantryQueries = $derived(gantryClients.map((client) => [client.current?.name, createResourceQuery(client, 'getGeometries', () => options)]));
42
42
  $effect(() => {
43
+ if (interval === RefetchRates.FPS_30 || interval === RefetchRates.FPS_60) {
44
+ return logs.add(`Fetching geometries every ${interval}ms...`);
45
+ }
43
46
  for (const [name, query] of queries) {
44
- if (query.isFetching) {
45
- logs.add(`Fetching geometries for ${name}...`);
46
- }
47
- else if (query.error) {
48
- logs.add(`Error fetching geometries from ${name}: ${query.error.message}`, 'error');
49
- }
47
+ untrack(() => {
48
+ $effect(() => {
49
+ if (query.isFetching) {
50
+ logs.add(`Fetching geometries for ${name}...`);
51
+ }
52
+ else if (query.error) {
53
+ logs.add(`Error fetching geometries from ${name}: ${query.error.message}`, 'error');
54
+ }
55
+ });
56
+ });
50
57
  }
51
58
  });
52
59
  const queries = $derived([...armQueries, ...gripperQueries, ...cameraQueries, ...gantryQueries]);
@@ -54,34 +61,38 @@ export const provideGeometries = (partID) => {
54
61
  $effect(() => {
55
62
  const active = {};
56
63
  for (const [name, query] of queries) {
57
- if (name && query.data) {
58
- let index = 0;
59
- for (const geometry of query.data) {
60
- index += 1;
61
- const resourceName = resources.current[name];
62
- const label = geometry.label ? geometry.label : `${name} geometry ${index}`;
63
- active[`${name}:${label}`] = true;
64
- const pose = createPose(geometry.center);
65
- const subtype = resourceName?.subtype;
66
- const existing = entities.get(`${name}:${label}`);
67
- if (existing) {
68
- existing.set(traits.Pose, pose);
69
- continue;
70
- }
71
- const entityTraits = [
72
- traits.Parent(name),
73
- traits.Name(label),
74
- traits.Pose(pose),
75
- traits.GeometriesAPI,
76
- traits.Geometry(geometry),
77
- ];
78
- if (subtype) {
79
- entityTraits.push(traits.Color(subtype ? colorUtil.set(resourceColors[subtype]) : undefined));
64
+ untrack(() => {
65
+ $effect(() => {
66
+ if (name && query.data) {
67
+ let index = 0;
68
+ for (const geometry of query.data) {
69
+ index += 1;
70
+ const resourceName = resources.current[name];
71
+ const label = geometry.label ? geometry.label : `${name} geometry ${index}`;
72
+ active[`${name}:${label}`] = true;
73
+ const pose = createPose(geometry.center);
74
+ const subtype = resourceName?.subtype;
75
+ const existing = entities.get(`${name}:${label}`);
76
+ if (existing) {
77
+ existing.set(traits.Pose, pose);
78
+ continue;
79
+ }
80
+ const entityTraits = [
81
+ traits.Parent(name),
82
+ traits.Name(label),
83
+ traits.Pose(pose),
84
+ traits.GeometriesAPI,
85
+ traits.Geometry(geometry),
86
+ ];
87
+ if (subtype) {
88
+ entityTraits.push(traits.Color(subtype ? colorUtil.set(resourceColors[subtype]) : undefined));
89
+ }
90
+ const entity = world.spawn(...entityTraits);
91
+ entities.set(`${name}:${label}`, entity);
92
+ }
80
93
  }
81
- const entity = world.spawn(...entityTraits);
82
- entities.set(`${name}:${label}`, entity);
83
- }
84
- }
94
+ });
95
+ });
85
96
  }
86
97
  // Clean up non-active entities
87
98
  for (const [label, entity] of entities) {
@@ -4,6 +4,7 @@ import { useVisibility } from './useVisibility.svelte';
4
4
  import { Vector2 } from 'three';
5
5
  import { traits } from '../ecs';
6
6
  import { updateHoverInfo } from '../HoverUpdater.svelte';
7
+ import { createPose, matrixToPose, poseToMatrix } from '../transform';
7
8
  export const useObjectEvents = (entity) => {
8
9
  const down = new Vector2();
9
10
  const selectedEntity = useSelectedEntity();
@@ -36,16 +37,32 @@ export const useObjectEvents = (entity) => {
36
37
  event.stopPropagation();
37
38
  if (currentEntity && currentEntity.has(traits.Hovered)) {
38
39
  const hoverInfo = updateHoverInfo(currentEntity, event);
39
- if (hoverInfo) {
40
- currentEntity.set(traits.InstancedPose, {
41
- index: hoverInfo.index,
40
+ const hoverPose = createPose(hoverInfo
41
+ ? {
42
42
  x: hoverInfo.x,
43
43
  y: hoverInfo.y,
44
44
  z: hoverInfo.z,
45
- oX: hoverInfo.oX,
46
- oY: hoverInfo.oY,
47
- oZ: hoverInfo.oZ,
48
- theta: hoverInfo.theta,
45
+ oX: 0,
46
+ oY: 0,
47
+ oZ: 1,
48
+ theta: 0,
49
+ }
50
+ : undefined);
51
+ const worldPose = currentEntity.get(traits.WorldPose) ?? createPose();
52
+ const hoverPoseMatrix = poseToMatrix(hoverPose);
53
+ const worldPoseMatrix = poseToMatrix(worldPose);
54
+ const resultMatrix = worldPoseMatrix.multiply(hoverPoseMatrix);
55
+ const resultPose = matrixToPose(resultMatrix);
56
+ if (hoverInfo) {
57
+ currentEntity.set(traits.InstancedPose, {
58
+ index: hoverInfo.index,
59
+ x: resultPose.x,
60
+ y: resultPose.y,
61
+ z: resultPose.z,
62
+ oX: resultPose.oX,
63
+ oY: resultPose.oY,
64
+ oZ: resultPose.oZ,
65
+ theta: resultPose.theta,
49
66
  });
50
67
  }
51
68
  }
@@ -28,49 +28,14 @@ interface PartConfigContext {
28
28
  }
29
29
  export declare const providePartConfig: (params: () => PartConfigParams) => void;
30
30
  export declare const usePartConfig: () => PartConfigContext;
31
- interface LocalPartConfig {
32
- isDirty: () => boolean;
33
- hasEditPermissions: () => boolean;
34
- getLocalPartConfig: () => Struct;
35
- setLocalPartConfig: (config: Struct) => void;
36
- componentNameToFragmentId: () => Record<string, string>;
37
- saveLocalPartConfig?: () => void;
38
- resetLocalPartConfig?: () => void;
39
- }
40
31
  interface AppEmbeddedPartConfigProps {
41
32
  isDirty: () => boolean;
42
33
  getLocalPartConfig: () => Struct;
43
34
  setLocalPartConfig: (config: Struct) => void;
44
35
  getComponentToFragId: () => Record<string, string>;
45
36
  }
46
- export declare class AppEmbeddedPartConfig implements LocalPartConfig {
47
- private _appEmbeddedPartConfigProps;
48
- constructor(appEmbeddedPartConfigProps: AppEmbeddedPartConfigProps);
49
- isDirty(): boolean;
50
- getLocalPartConfig(): Struct;
51
- setLocalPartConfig(config: Struct): void;
52
- componentNameToFragmentId(): Record<string, string>;
53
- hasEditPermissions(): boolean;
54
- }
55
37
  interface StandalonePartConfigProps {
56
38
  viamClient: () => ViamClient | undefined;
57
39
  partID: () => string;
58
40
  }
59
- export declare class StandalonePartConfig implements LocalPartConfig {
60
- private _standalonePartConfigProps;
61
- private _isDirty;
62
- private _hasEditPermissions;
63
- private _networkPartConfig;
64
- private _localPartConfig;
65
- private _partName;
66
- private _componentNameToFragmentId;
67
- constructor(standalonePartConfigProps: StandalonePartConfigProps);
68
- getLocalPartConfig(): Struct;
69
- setLocalPartConfig(config: Struct): void;
70
- isDirty(): boolean;
71
- hasEditPermissions(): boolean;
72
- componentNameToFragmentId(): Record<string, string>;
73
- saveLocalPartConfig(): Promise<void>;
74
- resetLocalPartConfig(): Promise<void>;
75
- }
76
41
  export {};
@@ -218,7 +218,7 @@ export const providePartConfig = (params) => {
218
218
  export const usePartConfig = () => {
219
219
  return getContext(key);
220
220
  };
221
- export class AppEmbeddedPartConfig {
221
+ class AppEmbeddedPartConfig {
222
222
  _appEmbeddedPartConfigProps;
223
223
  constructor(appEmbeddedPartConfigProps) {
224
224
  this._appEmbeddedPartConfigProps = appEmbeddedPartConfigProps;
@@ -239,7 +239,7 @@ export class AppEmbeddedPartConfig {
239
239
  return true;
240
240
  }
241
241
  }
242
- export class StandalonePartConfig {
242
+ class StandalonePartConfig {
243
243
  _standalonePartConfigProps;
244
244
  _isDirty = $state(false);
245
245
  _hasEditPermissions = $state(false);
@@ -1,9 +1,9 @@
1
- import { GeometriesInFrame, PointCloudObject, VisionClient } from '@viamrobotics/sdk';
1
+ import { VisionClient } from '@viamrobotics/sdk';
2
2
  import { createResourceClient, createResourceQuery, useResourceNames, } from '@viamrobotics/svelte-sdk';
3
3
  import { RefreshRates, useMachineSettings } from './useMachineSettings.svelte';
4
4
  import { useLogs } from './useLogs.svelte';
5
5
  import { parsePcdInWorker } from '../lib';
6
- import { getContext, setContext } from 'svelte';
6
+ import { getContext, setContext, untrack } from 'svelte';
7
7
  import { traits, useWorld } from '../ecs';
8
8
  import { createBufferGeometry, updateBufferGeometry } from '../attribute';
9
9
  import { useEnvironment } from './useEnvironment.svelte';
@@ -66,71 +66,50 @@ export const providePointcloudObjects = (partID) => {
66
66
  ]));
67
67
  $effect(() => {
68
68
  for (const [name, query] of queries) {
69
- if (query.isFetching) {
70
- logs.add(`Fetching pointcloud for ${name}...`);
71
- }
72
- else if (query.error) {
73
- logs.add(`Error fetching pointcloud from ${name}: ${query.error.message}`, 'error');
74
- }
75
- }
76
- });
77
- let pcResults = $state.raw([]);
78
- $effect(() => {
79
- const responses = [];
80
- for (const [name, query] of queries) {
81
- const { data } = query;
82
- if (name && data) {
83
- responses.push([name, data]);
84
- }
69
+ untrack(() => {
70
+ $effect(() => {
71
+ if (query.isFetching) {
72
+ logs.add(`Fetching pointcloud for ${name}...`);
73
+ }
74
+ else if (query.error) {
75
+ logs.add(`Error fetching pointcloud from ${name}: ${query.error.message}`, 'error');
76
+ }
77
+ });
78
+ });
85
79
  }
86
- Promise.allSettled(responses.map(async ([name, pointcloudObjects]) => {
87
- const pointclouds = await Promise.all(pointcloudObjects
88
- .filter((value) => value !== undefined)
89
- .map((value) => {
90
- return parsePcdInWorker(new Uint8Array(value.pointCloud));
91
- }));
92
- return {
93
- name,
94
- pointclouds,
95
- geometries: pointcloudObjects.map((value) => value.geometries),
96
- };
97
- })).then((results) => {
98
- const fulfilledResults = [];
99
- for (const result of results) {
100
- if (result.status === 'fulfilled') {
101
- fulfilledResults.push(result.value);
102
- }
103
- else if (result.status === 'rejected') {
104
- logs.add(result.reason, 'error');
105
- }
106
- }
107
- pcResults = fulfilledResults;
108
- });
109
80
  });
110
81
  const entities = new Map();
111
82
  $effect(() => {
112
83
  const active = {};
113
- for (const { name, pointclouds, geometries } of pcResults) {
114
- for (const [pointcloudIndex, pointcloud] of pointclouds.entries()) {
115
- const poincloudLabel = `${name} pointcloud ${pointcloudIndex + 1}`;
116
- const existing = entities.get(poincloudLabel);
117
- active[poincloudLabel] = true;
118
- if (existing) {
119
- const geometry = existing.get(traits.BufferGeometry);
120
- if (geometry) {
121
- updateBufferGeometry(geometry, pointcloud.positions, pointcloud.colors);
122
- }
123
- }
124
- else {
125
- const geometry = createBufferGeometry(pointcloud.positions, pointcloud.colors);
126
- const entity = world.spawn(traits.Name(poincloudLabel), traits.BufferGeometry(geometry), traits.Points);
127
- entities.set(poincloudLabel, entity);
128
- }
129
- if (geometries) {
130
- for (const geometriesInFrame of geometries) {
84
+ for (const [name, query] of queries) {
85
+ untrack(() => {
86
+ $effect(() => {
87
+ const { data } = query;
88
+ if (!data || data.length === 0)
89
+ return;
90
+ let index = 0;
91
+ for (const { geometries: geometriesInFrame, pointCloud } of data) {
92
+ if (pointCloud.length > 0) {
93
+ parsePcdInWorker(pointCloud).then(({ positions, colors }) => {
94
+ const poincloudLabel = `${name} pointcloud ${index + 1}`;
95
+ const existing = entities.get(poincloudLabel);
96
+ if (existing) {
97
+ const geometry = existing.get(traits.BufferGeometry);
98
+ if (geometry) {
99
+ updateBufferGeometry(geometry, positions, colors);
100
+ }
101
+ }
102
+ else {
103
+ const geometry = createBufferGeometry(positions, colors);
104
+ const entity = world.spawn(traits.Name(poincloudLabel), traits.BufferGeometry(geometry), traits.Points);
105
+ entities.set(poincloudLabel, entity);
106
+ }
107
+ });
108
+ }
131
109
  if (geometriesInFrame) {
132
- for (const [geometryIndex, geometry] of geometriesInFrame.geometries.entries()) {
133
- const geometryLabel = `${name} pointcloud ${pointcloudIndex} geometry ${geometryIndex + 1}`;
110
+ let geometryIndex = 0;
111
+ for (const geometry of geometriesInFrame.geometries) {
112
+ const geometryLabel = `${name} pointcloud ${index} geometry ${geometryIndex + 1}`;
134
113
  const pose = createPose(geometry.center);
135
114
  active[geometryLabel] = true;
136
115
  const existing = entities.get(geometryLabel);
@@ -152,11 +131,13 @@ export const providePointcloudObjects = (partID) => {
152
131
  const entity = world.spawn(...entityTraits);
153
132
  entities.set(geometryLabel, entity);
154
133
  }
134
+ geometryIndex += 1;
155
135
  }
156
136
  }
137
+ index += 1;
157
138
  }
158
- }
159
- }
139
+ });
140
+ });
160
141
  }
161
142
  // Clean up old entities
162
143
  for (const [label, entity] of entities) {
@@ -65,12 +65,16 @@ export const providePointclouds = (partID) => {
65
65
  const queryMap = $derived(typeSafeObjectFromEntries(queries));
66
66
  $effect(() => {
67
67
  for (const [name, query] of queries) {
68
- if (query.isFetching) {
69
- logs.add(`Fetching pointcloud for ${name}...`);
70
- }
71
- else if (query.error) {
72
- logs.add(`Error fetching pointcloud from ${name}: ${query.error.message}`, 'error');
73
- }
68
+ untrack(() => {
69
+ $effect(() => {
70
+ if (query.isFetching) {
71
+ logs.add(`Fetching pointcloud for ${name}...`);
72
+ }
73
+ else if (query.error) {
74
+ logs.add(`Error fetching pointcloud from ${name}: ${query.error.message}`, 'error');
75
+ }
76
+ });
77
+ });
74
78
  }
75
79
  });
76
80
  const entities = new Map();
@@ -24,7 +24,7 @@ export const usePose = (name, parent) => {
24
24
  const resource = $derived(currentName ? resourceByName.current[currentName] : undefined);
25
25
  const parentResource = $derived(currentParent ? resourceByName.current[currentParent] : undefined);
26
26
  const frames = useFrames();
27
- let pose = $state(undefined);
27
+ let pose = $state();
28
28
  const interval = $derived(refreshRates.get(RefreshRates.poses));
29
29
  const resolvedParent = $derived(origingFrameComponentTypes.includes(parentResource?.subtype ?? '')
30
30
  ? `${parent()}_origin`
@@ -43,6 +43,9 @@ export const usePose = (name, parent) => {
43
43
  });
44
44
  $effect(() => addQueryToRefetch(query));
45
45
  $effect(() => {
46
+ if (interval === RefetchRates.FPS_30 || interval === RefetchRates.FPS_60) {
47
+ return logs.add(`Fetching pose for ${currentName} every ${interval}ms...`);
48
+ }
46
49
  if (query.isFetching) {
47
50
  logs.add(`Fetching pose for ${currentName}...`);
48
51
  }
@@ -0,0 +1,7 @@
1
+ import type { ResourceName } from '@viamrobotics/sdk';
2
+ interface Context {
3
+ current: Record<string, ResourceName | undefined>;
4
+ }
5
+ export declare const provideResourceByName: (partID: () => string) => void;
6
+ export declare const useResourceByName: () => Context;
7
+ export {};
@@ -1,7 +1,7 @@
1
1
  import { useResourceNames } from '@viamrobotics/svelte-sdk';
2
2
  import { getContext, setContext } from 'svelte';
3
- export const RESOURCE_BY_NAME_CONTEXT_KEY = Symbol('resource-by-name-context');
4
- export const createResourceByName = (partID) => {
3
+ const RESOURCE_BY_NAME_CONTEXT_KEY = Symbol('resource-by-name-context');
4
+ const createResourceByName = (partID) => {
5
5
  const resourceNames = useResourceNames(partID);
6
6
  const resourceByName = $derived.by(() => {
7
7
  const results = {};
@@ -25,6 +25,20 @@ export interface Settings {
25
25
  renderStats: boolean;
26
26
  renderArmModels: 'colliders' | 'colliders+model' | 'model';
27
27
  renderSubEntityHoverDetail: boolean;
28
+ xrController: {
29
+ left: {
30
+ armName?: string;
31
+ gripperName?: string;
32
+ scaleFactor: number;
33
+ rotationEnabled: boolean;
34
+ };
35
+ right: {
36
+ armName?: string;
37
+ gripperName?: string;
38
+ scaleFactor: number;
39
+ rotationEnabled: boolean;
40
+ };
41
+ };
28
42
  }
29
43
  interface Context {
30
44
  current: Settings;
@@ -28,6 +28,16 @@ const defaults = () => ({
28
28
  renderStats: false,
29
29
  renderArmModels: 'colliders+model',
30
30
  renderSubEntityHoverDetail: false,
31
+ xrController: {
32
+ left: {
33
+ scaleFactor: 1.0,
34
+ rotationEnabled: true,
35
+ },
36
+ right: {
37
+ scaleFactor: 1.0,
38
+ rotationEnabled: true,
39
+ },
40
+ },
31
41
  });
32
42
  export const provideSettings = () => {
33
43
  let settings = $state(defaults());
@@ -1,9 +1 @@
1
- import { type TransformChangeEvent, type TransformWithUUID } from '@viamrobotics/sdk';
2
- export type ChangeMessage = {
3
- type: 'change';
4
- events: TransformChangeEvent[];
5
- };
6
- export type TransformEvent = TransformChangeEvent & {
7
- transform: TransformWithUUID;
8
- };
9
1
  export declare const provideWorldStates: () => void;
package/dist/lib.d.ts CHANGED
@@ -1,9 +1,7 @@
1
- export { default as Geometry } from './components/Geometry.svelte';
2
1
  export { default as AxesHelper } from './components/AxesHelper.svelte';
3
2
  export { default as Snapshot } from './components/Snapshot.svelte';
4
- export { Snapshot as SnapshotProto } from './draw/v1/snapshot_pb';
3
+ export { Snapshot as SnapshotProto } from './buf/draw/v1/snapshot_pb';
5
4
  export { BatchedArrow } from './three/BatchedArrow';
6
5
  export { CapsuleGeometry } from './three/CapsuleGeometry';
7
6
  export { OrientationVector } from './three/OrientationVector';
8
- export { WorldObject } from './WorldObject.svelte';
9
7
  export { parsePcdInWorker } from './loaders/pcd';
package/dist/lib.js CHANGED
@@ -1,15 +1,13 @@
1
1
  // Components
2
2
  // NOTE: These components should be pure and not use any hooks if you add a new component to export here
3
3
  // ensure you write a corresponding unit test to assert the component works in absence of parent providers in /src/lib/__tests__/PureComponents.svelte.spec.ts
4
- export { default as Geometry } from './components/Geometry.svelte';
5
4
  export { default as AxesHelper } from './components/AxesHelper.svelte';
6
5
  // Snapshot component (uses context, requires MotionTools parent)
7
6
  export { default as Snapshot } from './components/Snapshot.svelte';
8
- export { Snapshot as SnapshotProto } from './draw/v1/snapshot_pb';
7
+ export { Snapshot as SnapshotProto } from './buf/draw/v1/snapshot_pb';
9
8
  // Classes
10
9
  export { BatchedArrow } from './three/BatchedArrow';
11
10
  export { CapsuleGeometry } from './three/CapsuleGeometry';
12
11
  export { OrientationVector } from './three/OrientationVector';
13
- export { WorldObject } from './WorldObject.svelte';
14
12
  // Functions
15
13
  export { parsePcdInWorker } from './loaders/pcd';
@@ -1,6 +1,6 @@
1
1
  import type { World, Entity } from 'koota';
2
- import type { Snapshot } from './draw/v1/snapshot_pb';
3
- import { type SceneMetadata } from './draw/v1/scene_pb';
2
+ import type { Snapshot } from './buf/draw/v1/snapshot_pb';
3
+ import { type SceneMetadata } from './buf/draw/v1/scene_pb';
4
4
  import type { Settings } from './hooks/useSettings.svelte';
5
5
  export declare const applySceneMetadata: (settings: Settings, metadata: SceneMetadata) => Settings;
6
6
  export declare const spawnSnapshotEntities: (world: World, snapshot: Snapshot) => Entity[];
package/dist/snapshot.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { Vector3, Vector4 } from 'three';
2
2
  import { NURBSCurve } from 'three/addons/curves/NURBSCurve.js';
3
- import { RenderArmModels } from './draw/v1/scene_pb';
4
- import {} from './draw/v1/drawing_pb';
3
+ import { RenderArmModels } from './buf/draw/v1/scene_pb';
4
+ import {} from './buf/draw/v1/drawing_pb';
5
5
  import { traits } from './ecs';
6
6
  import { Geometry } from '@viamrobotics/sdk';
7
7
  import { parseMetadata } from './WorldObject.svelte';
@@ -1,8 +1,6 @@
1
- import { Object3D, BufferGeometry, Raycaster, type Intersection } from 'three';
1
+ import { Raycaster, type Intersection } from 'three';
2
2
  import type { InstancedArrows } from './InstancedArrows';
3
- export declare function meshBoundsRaycast(this: Object3D & {
4
- geometry: BufferGeometry;
5
- }, raycaster: Raycaster, intersects: Intersection[]): void;
3
+ export declare function meshBoundsRaycast(this: InstancedArrows, raycaster: Raycaster, intersects: Intersection[]): void;
6
4
  /**
7
5
  * Currently unused. In the future will be used for click only (not mousemove) due to complexity.
8
6
  */
@@ -1,4 +1,4 @@
1
- import { Object3D, BufferGeometry, Ray, Matrix4, Raycaster, Vector3, Box3, RawShaderMaterial, } from 'three';
1
+ import { Ray, Matrix4, Raycaster, Vector3, Box3, RawShaderMaterial } from 'three';
2
2
  const vec3 = new Vector3();
3
3
  const inverseMatrix = new Matrix4();
4
4
  const localRay = new Ray();
@@ -41,10 +41,10 @@ function closestPointsRaySegment(ray, a, b, outRay, outSeg) {
41
41
  return outRay.distanceToSquared(outSeg);
42
42
  }
43
43
  export function meshBoundsRaycast(raycaster, intersects) {
44
- if (this.geometry.boundingBox === null) {
45
- this.geometry.computeBoundingBox();
44
+ if (this.shaftMesh.geometry.boundingBox === null) {
45
+ this.shaftMesh.geometry.computeBoundingBox();
46
46
  }
47
- box.copy(this.geometry.boundingBox ?? box);
47
+ box.copy(this.shaftMesh.geometry.boundingBox ?? box);
48
48
  if (!raycaster.ray.intersectsBox(box)) {
49
49
  return;
50
50
  }
@@ -119,7 +119,7 @@ export function raycast(raycaster, intersects) {
119
119
  distance: bestDistance,
120
120
  point: bestPointWorld,
121
121
  object: this.shaftMesh,
122
- instanceId: bestInstanceId,
122
+ index: bestInstanceId,
123
123
  });
124
124
  }
125
125
  }
package/dist/transform.js CHANGED
@@ -8,6 +8,7 @@ const scale = new Vector3();
8
8
  export const createPose = (pose) => {
9
9
  // We should only default to the 0,0,1,0 orientation vector if the entire vector component is missing
10
10
  const oZ = pose?.oX === undefined && pose?.oY === undefined && pose?.oZ === undefined ? 1 : (pose?.oZ ?? 0);
11
+ // pose expects theta in degrees
11
12
  return {
12
13
  x: pose?.x ?? 0,
13
14
  y: pose?.y ?? 0,