@viamrobotics/motion-tools 1.24.0 → 1.25.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 (43) hide show
  1. package/dist/FrameConfigUpdater.svelte.js +5 -5
  2. package/dist/components/BatchedArrows.svelte +4 -4
  3. package/dist/components/Entities/Arrows/Arrows.svelte +2 -2
  4. package/dist/components/Entities/Capsule.svelte +137 -0
  5. package/dist/components/Entities/Capsule.svelte.d.ts +19 -0
  6. package/dist/components/Entities/Frame.svelte +2 -2
  7. package/dist/components/Entities/GLTF.svelte +2 -2
  8. package/dist/components/Entities/Geometry.svelte +2 -2
  9. package/dist/components/Entities/Line.svelte +2 -2
  10. package/dist/components/Entities/Mesh.svelte +121 -68
  11. package/dist/components/Entities/Points.svelte +2 -2
  12. package/dist/components/Entities/Pose.svelte +2 -2
  13. package/dist/components/SceneProviders.svelte +2 -0
  14. package/dist/components/Snapshot.svelte +20 -10
  15. package/dist/components/overlay/Details.svelte +3 -3
  16. package/dist/components/overlay/__tests__/__fixtures__/entity.js +2 -2
  17. package/dist/components/overlay/left-pane/buildTree.js +3 -3
  18. package/dist/draw.js +7 -8
  19. package/dist/ecs/hierarchy.d.ts +36 -0
  20. package/dist/ecs/hierarchy.js +80 -0
  21. package/dist/ecs/index.d.ts +4 -0
  22. package/dist/ecs/index.js +4 -0
  23. package/dist/ecs/provideHierarchy.svelte.d.ts +17 -0
  24. package/dist/ecs/provideHierarchy.svelte.js +31 -0
  25. package/dist/ecs/relations.d.ts +7 -0
  26. package/dist/ecs/relations.js +8 -1
  27. package/dist/ecs/traits.d.ts +9 -4
  28. package/dist/ecs/traits.js +8 -14
  29. package/dist/ecs/useParentName.svelte.d.ts +11 -0
  30. package/dist/ecs/useParentName.svelte.js +21 -0
  31. package/dist/ecs/useTarget.svelte.d.ts +10 -0
  32. package/dist/ecs/useTarget.svelte.js +42 -0
  33. package/dist/editing/FrameEditSession.js +6 -6
  34. package/dist/hooks/useArmKinematics.svelte.js +12 -8
  35. package/dist/hooks/useDrawAPI.svelte.js +4 -4
  36. package/dist/hooks/useFrames.svelte.js +3 -3
  37. package/dist/hooks/useGeometries.svelte.js +3 -2
  38. package/dist/hooks/usePointcloudObjects.svelte.js +3 -2
  39. package/dist/hooks/usePointclouds.svelte.js +3 -2
  40. package/dist/hooks/usePose.svelte.js +8 -6
  41. package/dist/snapshot.d.ts +7 -0
  42. package/dist/snapshot.js +74 -1
  43. package/package.json +3 -3
@@ -5,7 +5,7 @@ import { getContext, setContext, untrack } from 'svelte';
5
5
  import { Color } from 'three';
6
6
  import { resourceColors } from '../color';
7
7
  import { RefetchRates } from '../components/overlay/RefreshRate.svelte';
8
- import { traits, useWorld } from '../ecs';
8
+ import { hierarchy, traits, useWorld } from '../ecs';
9
9
  import { updateGeometryTrait } from '../ecs/traits';
10
10
  import { createPose } from '../transform';
11
11
  import { useEnvironment } from './useEnvironment.svelte';
@@ -90,12 +90,13 @@ export const provideGeometries = (partID) => {
90
90
  const center = createPose(geometry.center);
91
91
  const existing = entities.get(entityKey);
92
92
  if (existing) {
93
+ hierarchy.setParent(existing, name);
93
94
  existing.set(traits.Center, center);
94
95
  updateGeometryTrait(existing, geometry);
95
96
  continue;
96
97
  }
97
98
  const entityTraits = [
98
- traits.Parent(name),
99
+ ...hierarchy.parentTraits(name),
99
100
  traits.Name(label),
100
101
  traits.Center(center),
101
102
  traits.GeometriesAPI,
@@ -4,7 +4,7 @@ import { getContext, setContext, untrack } from 'svelte';
4
4
  import { createBufferGeometry, updateBufferGeometry } from '../attribute';
5
5
  import { ColorFormat } from '../buf/draw/v1/metadata_pb';
6
6
  import { RefetchRates } from '../components/overlay/RefreshRate.svelte';
7
- import { traits, useWorld } from '../ecs';
7
+ import { hierarchy, traits, useWorld } from '../ecs';
8
8
  import { parsePcdInWorker } from '../lib';
9
9
  import { createPose } from '../transform';
10
10
  import { useEnvironment } from './useEnvironment.svelte';
@@ -160,13 +160,14 @@ export const providePointcloudObjects = (partID) => {
160
160
  const center = createPose(geometry.center);
161
161
  const existing = entities.get(geometryLabel);
162
162
  if (existing) {
163
+ hierarchy.setParent(existing, geometriesInFrame.referenceFrame);
163
164
  existing.set(traits.Center, center);
164
165
  traits.updateGeometryTrait(existing, geometry);
165
166
  }
166
167
  else {
167
168
  const entityTraits = [
168
169
  traits.Name(geometryLabel),
169
- ...traits.getParentTrait(geometriesInFrame.referenceFrame),
170
+ ...hierarchy.parentTraits(geometriesInFrame.referenceFrame),
170
171
  traits.Center(center),
171
172
  traits.GeometriesAPI,
172
173
  traits.Geometry(geometry),
@@ -4,7 +4,7 @@ import { getContext, setContext, untrack } from 'svelte';
4
4
  import { createBufferGeometry, updateBufferGeometry } from '../attribute';
5
5
  import { ColorFormat } from '../buf/draw/v1/metadata_pb';
6
6
  import { RefetchRates } from '../components/overlay/RefreshRate.svelte';
7
- import { traits, useWorld } from '../ecs';
7
+ import { hierarchy, traits, useWorld } from '../ecs';
8
8
  import { parsePcdInWorker } from '../loaders/pcd';
9
9
  import { useEnvironment } from './useEnvironment.svelte';
10
10
  import { useLogs } from './useLogs.svelte';
@@ -108,6 +108,7 @@ export const providePointclouds = (partID) => {
108
108
  colorFormat: ColorFormat.RGB,
109
109
  };
110
110
  if (existing) {
111
+ hierarchy.setParent(existing, name);
111
112
  const geometry = existing.get(traits.BufferGeometry);
112
113
  if (geometry) {
113
114
  updateBufferGeometry(geometry, positions, metadata);
@@ -115,7 +116,7 @@ export const providePointclouds = (partID) => {
115
116
  }
116
117
  }
117
118
  const geometry = createBufferGeometry(positions, metadata);
118
- const entity = world.spawn(traits.Parent(name), traits.Name(`${name} pointcloud`), traits.BufferGeometry(geometry), traits.Points);
119
+ const entity = world.spawn(...hierarchy.parentTraits(name), traits.Name(`${name} pointcloud`), traits.BufferGeometry(geometry), traits.Points);
119
120
  entities.set(queryKey, entity);
120
121
  })
121
122
  .catch((error) => {
@@ -1,6 +1,5 @@
1
- import { observe } from '@threlte/core';
2
- import { commonApi, Pose } from '@viamrobotics/sdk';
3
- import { createRobotQuery, useRobotClient } from '@viamrobotics/svelte-sdk';
1
+ import { commonApi, MachineConnectionEvent, Pose } from '@viamrobotics/sdk';
2
+ import { createRobotQuery, useConnectionStatus, useRobotClient } from '@viamrobotics/svelte-sdk';
4
3
  import { untrack } from 'svelte';
5
4
  import { RefetchRates } from '../components/overlay/RefreshRate.svelte';
6
5
  import { useEnvironment } from './useEnvironment.svelte';
@@ -12,10 +11,11 @@ import { useResourceByName } from './useResourceByName.svelte';
12
11
  import { RefreshRates, useSettings } from './useSettings.svelte';
13
12
  const originFrameComponentTypes = new Set(['arm', 'gantry', 'gripper', 'base']);
14
13
  export const usePose = (name, parent) => {
14
+ const partID = usePartID();
15
+ const connectionStatus = useConnectionStatus(() => partID.current);
15
16
  const environment = useEnvironment();
16
17
  const logs = useLogs();
17
18
  const settings = useSettings();
18
- const partID = usePartID();
19
19
  const robotClient = useRobotClient(() => partID.current);
20
20
  const currentName = $derived(name());
21
21
  const currentParent = $derived(parent());
@@ -49,8 +49,10 @@ export const usePose = (name, parent) => {
49
49
  logs.add(`Error fetching pose for ${currentName}: ${query.error.message}`, 'error');
50
50
  }
51
51
  });
52
- observe.pre(() => [environment.current.viewerMode, frames.current], () => {
53
- if (environment.current.viewerMode === 'monitor') {
52
+ $effect(() => {
53
+ if (environment.current.viewerMode === 'monitor' &&
54
+ frames.current &&
55
+ connectionStatus.current === MachineConnectionEvent.CONNECTED) {
54
56
  untrack(() => query.refetch());
55
57
  }
56
58
  });
@@ -24,3 +24,10 @@ export declare const applySceneMetadata: (settings: Settings, metadata: SceneMet
24
24
  * @returns The spawned entities
25
25
  */
26
26
  export declare const spawnSnapshotEntities: (world: World, snapshot: Snapshot) => SnapshotEntity[];
27
+ export interface ReconcileResult {
28
+ current: Map<string, SnapshotEntity>;
29
+ unkeyed: SnapshotEntity[];
30
+ spawned: SnapshotEntity[];
31
+ updated: SnapshotEntity[];
32
+ }
33
+ export declare const reconcileSnapshotEntities: (world: World, snapshot: Snapshot, prev: Map<string, SnapshotEntity>) => ReconcileResult;
package/dist/snapshot.js CHANGED
@@ -1,7 +1,7 @@
1
1
  import { RenderArmModels } from './buf/draw/v1/scene_pb';
2
2
  import { traits } from './ecs';
3
3
  import { rgbToHex } from './color';
4
- import { drawDrawing, drawTransform } from './draw';
4
+ import { drawDrawing, drawTransform, updateDrawing, updateModel, updateTransform, uuidBytesToString, } from './draw';
5
5
  /**
6
6
  * Merges scene-level metadata (grid, camera, point/line settings) into the
7
7
  * current viewer settings. Millimeter values from the proto are converted
@@ -73,6 +73,79 @@ export const spawnSnapshotEntities = (world, snapshot) => {
73
73
  }
74
74
  return entities;
75
75
  };
76
+ export const reconcileSnapshotEntities = (world, snapshot, prev) => {
77
+ const options = { removable: true, showAxesHelper: false };
78
+ const next = new Map(prev);
79
+ const seen = new Set();
80
+ const unkeyed = [];
81
+ const spawned = [];
82
+ const updated = [];
83
+ for (const transform of snapshot.transforms) {
84
+ const uuidStr = uuidBytesToString(transform.uuid);
85
+ if (!uuidStr) {
86
+ const result = drawTransform(world, transform, traits.SnapshotAPI, options);
87
+ const entry = { entity: result.entity, relationships: result.relationships };
88
+ unkeyed.push(entry);
89
+ spawned.push(entry);
90
+ continue;
91
+ }
92
+ const existing = next.get(uuidStr);
93
+ if (existing && world.has(existing.entity)) {
94
+ const result = updateTransform(existing.entity, transform, options);
95
+ const entry = { entity: result.entity, relationships: result.relationships };
96
+ next.set(uuidStr, entry);
97
+ updated.push(entry);
98
+ }
99
+ else {
100
+ const result = drawTransform(world, transform, traits.SnapshotAPI, options);
101
+ const entry = { entity: result.entity, relationships: result.relationships };
102
+ next.set(uuidStr, entry);
103
+ spawned.push(entry);
104
+ }
105
+ seen.add(uuidStr);
106
+ }
107
+ for (const drawing of snapshot.drawings) {
108
+ const uuidStr = uuidBytesToString(drawing.uuid);
109
+ if (!uuidStr) {
110
+ const result = drawDrawing(world, drawing, traits.SnapshotAPI, options);
111
+ const entry = { entity: result.entity, relationships: result.relationships };
112
+ unkeyed.push(entry);
113
+ spawned.push(entry);
114
+ continue;
115
+ }
116
+ const existing = next.get(uuidStr);
117
+ const isModel = drawing.physicalObject?.geometryType.case === 'model';
118
+ if (existing && world.has(existing.entity)) {
119
+ if (isModel) {
120
+ const result = updateModel(world, existing.entity, drawing, traits.SnapshotAPI, options);
121
+ const entry = { entity: result.entity, relationships: result.relationships };
122
+ next.set(uuidStr, entry);
123
+ spawned.push(entry);
124
+ }
125
+ else {
126
+ const result = updateDrawing(world, existing.entity, drawing, options);
127
+ const entry = { entity: result.entity, relationships: result.relationships };
128
+ next.set(uuidStr, entry);
129
+ updated.push(entry);
130
+ }
131
+ }
132
+ else {
133
+ const result = drawDrawing(world, drawing, traits.SnapshotAPI, options);
134
+ const entry = { entity: result.entity, relationships: result.relationships };
135
+ next.set(uuidStr, entry);
136
+ spawned.push(entry);
137
+ }
138
+ seen.add(uuidStr);
139
+ }
140
+ for (const [uuid, entry] of prev) {
141
+ if (seen.has(uuid))
142
+ continue;
143
+ if (world.has(entry.entity))
144
+ entry.entity.destroy();
145
+ next.delete(uuid);
146
+ }
147
+ return { current: next, unkeyed, spawned, updated };
148
+ };
76
149
  const getRenderArmModels = (renderArmModels) => {
77
150
  switch (renderArmModels) {
78
151
  case RenderArmModels.COLLIDERS: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@viamrobotics/motion-tools",
3
- "version": "1.24.0",
3
+ "version": "1.25.1",
4
4
  "description": "Motion visualization with Viam",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
@@ -37,8 +37,8 @@
37
37
  "@typescript-eslint/eslint-plugin": "8.56.1",
38
38
  "@typescript-eslint/parser": "8.56.1",
39
39
  "@viamrobotics/prime-core": "0.1.5",
40
- "@viamrobotics/sdk": "0.58.0",
41
- "@viamrobotics/svelte-sdk": "1.0.1",
40
+ "@viamrobotics/sdk": "0.69.0",
41
+ "@viamrobotics/svelte-sdk": "1.2.2",
42
42
  "@vitest/browser": "3.2.4",
43
43
  "@vitest/coverage-v8": "^3.2.4",
44
44
  "@zag-js/collapsible": "1.22.1",