@viamrobotics/motion-tools 1.12.2 → 1.13.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 (29) hide show
  1. package/dist/assets/ferndale_studio_11_1k.hdr +0 -0
  2. package/dist/components/App.svelte +11 -25
  3. package/dist/components/App.svelte.d.ts +3 -3
  4. package/dist/components/Geometry.svelte +42 -42
  5. package/dist/components/Scene.svelte +4 -1
  6. package/dist/components/SceneProviders.svelte +2 -0
  7. package/dist/components/Selected.svelte +9 -9
  8. package/dist/components/StaticGeometries.svelte +5 -2
  9. package/dist/components/overlay/Details.svelte +3 -3
  10. package/dist/components/overlay/FloatingPanel.svelte +3 -0
  11. package/dist/components/overlay/FloatingPanel.svelte.d.ts +1 -0
  12. package/dist/components/overlay/LiveUpdatesBanner.svelte +3 -3
  13. package/dist/components/overlay/Logs.svelte +75 -0
  14. package/dist/components/overlay/__tests__/__fixtures__/resource.d.ts +10 -1
  15. package/dist/components/overlay/__tests__/__fixtures__/resource.js +1 -0
  16. package/dist/components/overlay/dashboard/Dashboard.svelte +1 -1
  17. package/dist/components/overlay/left-pane/TreeContainer.svelte +0 -3
  18. package/dist/hooks/use3DModels.svelte.js +10 -0
  19. package/dist/hooks/useConfigFrames.svelte.d.ts +9 -0
  20. package/dist/hooks/useConfigFrames.svelte.js +92 -0
  21. package/dist/hooks/useFramelessComponents.svelte.js +2 -2
  22. package/dist/hooks/useFrames.svelte.d.ts +1 -6
  23. package/dist/hooks/useFrames.svelte.js +39 -145
  24. package/dist/hooks/usePartConfig.svelte.d.ts +10 -19
  25. package/dist/hooks/usePartConfig.svelte.js +138 -165
  26. package/dist/hooks/useVisibility.svelte.js +0 -12
  27. package/package.json +1 -1
  28. package/dist/components/overlay/left-pane/Logs.svelte +0 -52
  29. /package/dist/components/overlay/{left-pane/Logs.svelte.d.ts → Logs.svelte.d.ts} +0 -0
@@ -1,11 +1,6 @@
1
1
  import { Transform } from '@viamrobotics/sdk';
2
- interface FrameTransform {
3
- type: 'machine' | 'config' | 'fragment';
4
- transform: Transform;
5
- }
6
2
  interface FramesContext {
7
- current: FrameTransform[];
8
- getParentFrameOptions: (componentName: string) => string[];
3
+ current: Transform[];
9
4
  }
10
5
  export declare const provideFrames: (partID: () => string) => void;
11
6
  export declare const useFrames: () => FramesContext;
@@ -1,27 +1,28 @@
1
1
  import { getContext, setContext, untrack } from 'svelte';
2
- import { Transform } from '@viamrobotics/sdk';
3
- import { useRobotClient, createRobotQuery, useMachineStatus } from '@viamrobotics/svelte-sdk';
2
+ import { MachineConnectionEvent, Transform } from '@viamrobotics/sdk';
3
+ import { useRobotClient, createRobotQuery, useMachineStatus, useConnectionStatus, } from '@viamrobotics/svelte-sdk';
4
4
  import { useLogs } from './useLogs.svelte';
5
5
  import { resourceNameToColor } from '../color';
6
- import { createTransformFromFrame } from '../frame';
7
- import { usePartConfig } from './usePartConfig.svelte';
8
6
  import { useEnvironment } from './useEnvironment.svelte';
9
7
  import { createPose } from '../transform';
10
8
  import { useResourceByName } from './useResourceByName.svelte';
11
9
  import { traits, useWorld } from '../ecs';
10
+ import { useConfigFrames } from './useConfigFrames.svelte';
12
11
  const key = Symbol('frames-context');
13
12
  export const provideFrames = (partID) => {
13
+ const configFrames = useConfigFrames();
14
14
  const environment = useEnvironment();
15
15
  const world = useWorld();
16
16
  const resourceByName = useResourceByName();
17
17
  const client = useRobotClient(partID);
18
+ const connectionStatus = useConnectionStatus(partID);
18
19
  const machineStatus = useMachineStatus(partID);
19
20
  const logs = useLogs();
21
+ const isEditMode = $derived(environment.current.viewerMode === 'edit');
20
22
  const query = createRobotQuery(client, 'frameSystemConfig', () => ({
21
- enabled: partID() !== '' && environment.current.viewerMode === 'monitor',
23
+ enabled: partID() !== '' && !isEditMode,
22
24
  }));
23
25
  const revision = $derived(machineStatus.current?.config?.revision);
24
- const partConfig = usePartConfig();
25
26
  $effect(() => {
26
27
  if (query.isFetching) {
27
28
  logs.add('Fetching frames...');
@@ -30,131 +31,40 @@ export const provideFrames = (partID) => {
30
31
  logs.add(`Frames: ${query.error.message}`, 'error');
31
32
  }
32
33
  });
33
- $effect(() => {
34
- if (partConfig.isDirty) {
35
- environment.current.viewerMode = 'edit';
36
- }
37
- else {
38
- environment.current.viewerMode = 'monitor';
39
- }
40
- });
41
- const machineFrames = $derived.by(() => {
34
+ const frames = $derived.by(() => {
42
35
  const frames = {};
43
36
  for (const { frame } of query.data ?? []) {
44
37
  if (frame === undefined) {
45
38
  continue;
46
39
  }
47
- frames[frame.referenceFrame] = {
48
- type: 'machine',
49
- transform: frame,
50
- };
40
+ frames[frame.referenceFrame] = frame;
51
41
  }
52
- return frames;
53
- });
54
- const [configFrames, configUnsetFrameNames] = $derived.by(() => {
55
- const components = partConfig.localPartConfig.toJson().components;
56
- const results = {};
57
- const unsetResults = [];
58
- for (const { name, frame } of components ?? []) {
59
- if (!frame) {
60
- unsetResults.push(name);
61
- continue;
62
- }
63
- results[name] = {
64
- type: 'config',
65
- transform: createTransformFromFrame(name, frame),
42
+ if (isEditMode || connectionStatus.current === MachineConnectionEvent.DISCONNECTED) {
43
+ const mergedFrames = {
44
+ ...frames,
45
+ ...configFrames.current,
66
46
  };
47
+ /**
48
+ * Remove frames that have just been deleted locally for optimistic updates,
49
+ * or frames that have been removed by fragment overrides
50
+ */
51
+ for (const name of configFrames.unsetFrames) {
52
+ delete mergedFrames[name];
53
+ }
54
+ return mergedFrames;
67
55
  }
68
- return [results, unsetResults];
69
- });
70
- const [fragmentFrames, fragmentUnsetFrameNames] = $derived.by(() => {
71
- const { fragment_mods: fragmentMods = [] } = partConfig.localPartConfig.toJson() ?? {};
72
- const fragmentDefinedComponents = Object.keys(partConfig.componentNameToFragmentId);
73
- const results = {};
74
- const unsetResults = [];
75
- // deal with fragment defined components
76
- for (const fragmentComponentName of fragmentDefinedComponents || []) {
77
- const fragmentId = partConfig.componentNameToFragmentId[fragmentComponentName];
78
- const fragmentMod = fragmentMods?.find((mod) => mod.fragment_id === fragmentId);
79
- if (!fragmentMod) {
80
- continue;
81
- }
82
- const setComponentModIndex = fragmentMod.mods.findLastIndex((mod) => mod['$set']?.[`components.${fragmentComponentName}.frame`] !== undefined);
83
- const unsetComponentModIndex = fragmentMod.mods.findLastIndex((mod) => mod['$unset']?.[`components.${fragmentComponentName}.frame`] !== undefined);
84
- if (setComponentModIndex < unsetComponentModIndex) {
85
- unsetResults.push(fragmentComponentName);
86
- }
87
- else if (unsetComponentModIndex < setComponentModIndex) {
88
- const frameData = fragmentMod.mods[setComponentModIndex]['$set'][`components.${fragmentComponentName}.frame`];
89
- results[fragmentComponentName] = {
90
- type: 'fragment',
91
- transform: createTransformFromFrame(fragmentComponentName, frameData),
92
- };
93
- }
94
- }
95
- return [results, unsetResults];
96
- });
97
- const frames = $derived.by(() => {
98
- const result = {
99
- ...machineFrames,
100
- ...configFrames,
101
- ...fragmentFrames,
102
- };
103
- // Remove frames that have just been deleted locally for optimistic updates
104
- for (const name of configUnsetFrameNames) {
105
- delete result[name];
106
- }
107
- // Remove frames that have been removed by fragment overrides
108
- for (const name of fragmentUnsetFrameNames) {
109
- delete result[name];
110
- }
111
- return result;
56
+ /**
57
+ * If we're not in edit mode and we have a robot connection,
58
+ * we only use frames reported by the machine
59
+ *
60
+ */
61
+ return frames;
112
62
  });
113
63
  const current = $derived(Object.values(frames));
114
64
  const entities = new Map();
115
65
  $effect.pre(() => {
116
66
  if (revision) {
117
- untrack(async () => {
118
- await query.refetch();
119
- for (const [name, machineFrame] of Object.entries(machineFrames)) {
120
- if (machineFrame === undefined) {
121
- continue;
122
- }
123
- const existing = entities.get(name);
124
- if (existing) {
125
- const pose = createPose(machineFrame.transform.poseInObserverFrame?.pose);
126
- existing.set(traits.Pose, pose);
127
- if (environment.current.viewerMode === 'monitor') {
128
- // if we are in monitor mode, we want the network pose to overwrite any leftover edited poses
129
- existing.set(traits.EditedPose, pose);
130
- }
131
- }
132
- }
133
- });
134
- }
135
- });
136
- $effect.pre(() => {
137
- for (const [name, configFrame] of Object.entries(configFrames)) {
138
- if (configFrame === undefined) {
139
- continue;
140
- }
141
- const existing = entities.get(name);
142
- if (existing) {
143
- const pose = createPose(configFrame.transform.poseInObserverFrame?.pose);
144
- existing.set(traits.EditedPose, pose);
145
- }
146
- }
147
- });
148
- $effect.pre(() => {
149
- for (const [name, fragmentFrame] of Object.entries(fragmentFrames)) {
150
- if (fragmentFrame === undefined) {
151
- continue;
152
- }
153
- const existing = entities.get(name);
154
- if (existing) {
155
- const pose = createPose(fragmentFrame.transform.poseInObserverFrame?.pose);
156
- existing.set(traits.EditedPose, pose);
157
- }
67
+ untrack(() => query.refetch());
158
68
  }
159
69
  });
160
70
  $effect.pre(() => {
@@ -162,13 +72,13 @@ export const provideFrames = (partID) => {
162
72
  if (frame === undefined) {
163
73
  continue;
164
74
  }
165
- const name = frame.transform.referenceFrame;
166
- const parent = frame.transform.poseInObserverFrame?.referenceFrame;
167
- const pose = createPose(frame.transform.poseInObserverFrame?.pose);
168
- const center = frame.transform.physicalObject?.center
169
- ? createPose(frame.transform.physicalObject.center)
75
+ const name = frame.referenceFrame;
76
+ const parent = frame.poseInObserverFrame?.referenceFrame;
77
+ const pose = createPose(frame.poseInObserverFrame?.pose);
78
+ const center = frame.physicalObject?.center
79
+ ? createPose(frame.physicalObject.center)
170
80
  : undefined;
171
- const resourceName = resourceByName.current[frame.transform.referenceFrame];
81
+ const resourceName = resourceByName.current[frame.referenceFrame];
172
82
  const color = resourceNameToColor(resourceName);
173
83
  const existing = entities.get(name);
174
84
  if (existing) {
@@ -188,10 +98,11 @@ export const provideFrames = (partID) => {
188
98
  existing.set(traits.Center, center);
189
99
  }
190
100
  existing.remove(traits.Box, traits.Sphere, traits.BufferGeometry, traits.Capsule);
191
- if (frame.transform.physicalObject) {
192
- const geometry = traits.Geometry(frame.transform.physicalObject);
101
+ if (frame.physicalObject) {
102
+ const geometry = traits.Geometry(frame.physicalObject);
193
103
  existing.add(geometry);
194
104
  }
105
+ existing.set(traits.EditedPose, pose);
195
106
  continue;
196
107
  }
197
108
  const entityTraits = [
@@ -210,8 +121,8 @@ export const provideFrames = (partID) => {
210
121
  if (center) {
211
122
  entityTraits.push(traits.Center(center));
212
123
  }
213
- if (frame.transform.physicalObject) {
214
- entityTraits.push(traits.Geometry(frame.transform.physicalObject));
124
+ if (frame.physicalObject) {
125
+ entityTraits.push(traits.Geometry(frame.physicalObject));
215
126
  }
216
127
  const entity = world.spawn(...entityTraits);
217
128
  entities.set(name, entity);
@@ -224,24 +135,7 @@ export const provideFrames = (partID) => {
224
135
  }
225
136
  }
226
137
  });
227
- const getParentFrameOptions = (componentName) => {
228
- const validFrames = new Set(current.map((frame) => frame.transform.referenceFrame));
229
- validFrames.add('world');
230
- const frameNameQueue = [componentName];
231
- while (frameNameQueue.length > 0) {
232
- const frameName = frameNameQueue.shift();
233
- if (frameName) {
234
- validFrames.delete(frameName);
235
- const frames = current.filter((frame) => frame.transform.poseInObserverFrame?.referenceFrame === frameName);
236
- for (const frame of frames) {
237
- frameNameQueue.push(frame.transform.referenceFrame);
238
- }
239
- }
240
- }
241
- return Array.from(validFrames);
242
- };
243
138
  setContext(key, {
244
- getParentFrameOptions,
245
139
  get current() {
246
140
  return current;
247
141
  },
@@ -1,6 +1,5 @@
1
1
  import { type Frame } from '../frame';
2
2
  import { Struct, Pose } from '@viamrobotics/sdk';
3
- import type { ViamClient } from '@viamrobotics/sdk';
4
3
  export interface PartConfig {
5
4
  components: {
6
5
  name: string;
@@ -11,31 +10,23 @@ export interface PartConfig {
11
10
  mods: any[];
12
11
  }[];
13
12
  }
14
- interface PartConfigParams {
15
- appEmbeddedPartConfigProps?: AppEmbeddedPartConfigProps;
16
- standalonePartConfigProps?: StandalonePartConfigProps;
17
- }
18
13
  interface PartConfigContext {
14
+ current: PartConfig;
15
+ isDirty: boolean;
16
+ hasEditPermissions: boolean;
17
+ componentNameToFragmentId: Record<string, string>;
19
18
  updateFrame: (componentName: string, referenceFrame: string, pose: Pose, geometry?: Frame['geometry']) => void;
20
- saveLocalPartConfig: () => void;
21
- resetLocalPartConfig: () => void;
22
19
  deleteFrame: (componentName: string) => void;
23
20
  createFrame: (componentName: string) => void;
24
- componentNameToFragmentId: Record<string, string>;
25
- localPartConfig: Struct;
26
- isDirty: boolean;
27
- hasEditPermissions: boolean;
21
+ save: () => void;
22
+ discardChanges: () => void;
28
23
  }
29
- export declare const providePartConfig: (params: () => PartConfigParams) => void;
24
+ export declare const providePartConfig: (partID: () => string, params: () => AppEmbeddedPartConfigProps | undefined) => void;
30
25
  export declare const usePartConfig: () => PartConfigContext;
31
26
  interface AppEmbeddedPartConfigProps {
32
- isDirty: () => boolean;
33
- getLocalPartConfig: () => Struct;
27
+ current: Struct;
28
+ isDirty: boolean;
29
+ componentToFragId: Record<string, string>;
34
30
  setLocalPartConfig: (config: Struct) => void;
35
- getComponentToFragId: () => Record<string, string>;
36
- }
37
- interface StandalonePartConfigProps {
38
- viamClient: () => ViamClient | undefined;
39
- partID: () => string;
40
31
  }
41
32
  export {};