@viamrobotics/motion-tools 0.11.8 → 0.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 (63) hide show
  1. package/dist/Detail.svelte.d.ts +41 -0
  2. package/dist/Detail.svelte.js +147 -0
  3. package/dist/WorldObject.svelte.d.ts +18 -27
  4. package/dist/WorldObject.svelte.js +48 -3
  5. package/dist/components/App.svelte +80 -30
  6. package/dist/components/App.svelte.d.ts +8 -0
  7. package/dist/components/Details.svelte +320 -37
  8. package/dist/components/FileDrop.svelte +5 -2
  9. package/dist/components/Geometry.svelte +86 -70
  10. package/dist/components/Geometry.svelte.d.ts +3 -3
  11. package/dist/components/LiveUpdatesBanner.svelte +39 -0
  12. package/dist/components/LiveUpdatesBanner.svelte.d.ts +3 -0
  13. package/dist/components/Pointcloud.svelte +3 -3
  14. package/dist/components/Pointcloud.svelte.d.ts +2 -5
  15. package/dist/components/RefreshRate.svelte +11 -6
  16. package/dist/components/RefreshRate.svelte.d.ts +3 -1
  17. package/dist/components/SceneProviders.svelte +5 -1
  18. package/dist/components/Selected.svelte +10 -10
  19. package/dist/components/StaticGeometries.svelte +2 -2
  20. package/dist/components/Tree/Settings.svelte +10 -4
  21. package/dist/components/Tree/TreeContainer.svelte +2 -0
  22. package/dist/components/Tree/Widgets.svelte +24 -0
  23. package/dist/components/Tree/Widgets.svelte.d.ts +18 -0
  24. package/dist/components/Tree/buildTree.js +1 -1
  25. package/dist/components/WorldObjects.svelte +12 -10
  26. package/dist/components/shared/Table.svelte +37 -0
  27. package/dist/components/shared/Table.svelte.d.ts +7 -0
  28. package/dist/components/weblab/WeblabActive.svelte +21 -0
  29. package/dist/components/weblab/WeblabActive.svelte.d.ts +9 -0
  30. package/dist/components/weblab/WeblabProvider.svelte +8 -0
  31. package/dist/components/weblab/WeblabProvider.svelte.d.ts +5 -0
  32. package/dist/components/widgets/ArmPositions.svelte +76 -0
  33. package/dist/components/widgets/ArmPositions.svelte.d.ts +3 -0
  34. package/dist/format.d.ts +1 -0
  35. package/dist/format.js +15 -0
  36. package/dist/hooks/useArmClient.svelte.d.ts +7 -0
  37. package/dist/hooks/useArmClient.svelte.js +36 -0
  38. package/dist/hooks/useArrows.svelte.d.ts +3 -0
  39. package/dist/hooks/useArrows.svelte.js +9 -0
  40. package/dist/hooks/useDrawAPI.svelte.d.ts +0 -4
  41. package/dist/hooks/useDrawAPI.svelte.js +34 -29
  42. package/dist/hooks/useFrames.svelte.d.ts +1 -0
  43. package/dist/hooks/useFrames.svelte.js +172 -11
  44. package/dist/hooks/useGeometries.svelte.js +4 -7
  45. package/dist/hooks/useMachineSettings.svelte.d.ts +4 -0
  46. package/dist/hooks/useMachineSettings.svelte.js +8 -1
  47. package/dist/hooks/usePartConfig.svelte.d.ts +98 -0
  48. package/dist/hooks/usePartConfig.svelte.js +230 -0
  49. package/dist/hooks/usePointclouds.svelte.js +3 -6
  50. package/dist/hooks/usePose.svelte.js +8 -3
  51. package/dist/hooks/useSettings.svelte.d.ts +2 -0
  52. package/dist/hooks/useSettings.svelte.js +2 -0
  53. package/dist/hooks/useStaticGeometries.svelte.js +1 -1
  54. package/dist/hooks/useWeblabs.svelte.d.ts +12 -0
  55. package/dist/hooks/useWeblabs.svelte.js +25 -0
  56. package/dist/hooks/useWorldState.svelte.d.ts +2 -38
  57. package/dist/three/BatchedArrow.d.ts +4 -3
  58. package/dist/three/BatchedArrow.js +14 -7
  59. package/dist/three/OBBHelper.d.ts +14 -0
  60. package/dist/three/OBBHelper.js +71 -0
  61. package/package.json +1 -1
  62. package/dist/hooks/usePoses.svelte.d.ts +0 -12
  63. package/dist/hooks/usePoses.svelte.js +0 -63
@@ -0,0 +1,41 @@
1
+ import type { WorldObject } from './lib';
2
+ import type { Geometries } from './WorldObject.svelte';
3
+ import type { Pose } from '@viamrobotics/sdk';
4
+ type UpdateFrameCallback = {
5
+ (componentName: string, referenceFrame: string, pose: Pose, geometry?: {
6
+ type: 'none' | 'box' | 'sphere' | 'capsule';
7
+ r?: number;
8
+ l?: number;
9
+ x?: number;
10
+ y?: number;
11
+ z?: number;
12
+ }): void;
13
+ };
14
+ export declare class DetailConfigUpdater {
15
+ private object;
16
+ private referenceFrame;
17
+ private updateFrame;
18
+ constructor(object: () => WorldObject<Geometries> | undefined, updateFrame: UpdateFrameCallback, referenceFrame: () => string);
19
+ updateLocalPosition: ({ x, y, z }: {
20
+ x?: number;
21
+ y?: number;
22
+ z?: number;
23
+ }) => void;
24
+ updateLocalOrientation: ({ oX, oY, oZ, theta, }: {
25
+ oX?: number;
26
+ oY?: number;
27
+ oZ?: number;
28
+ theta?: number;
29
+ }) => void;
30
+ updateGeometry: (geometry: {
31
+ type: "none" | "box" | "sphere" | "capsule";
32
+ r?: number;
33
+ l?: number;
34
+ x?: number;
35
+ y?: number;
36
+ z?: number;
37
+ }) => void;
38
+ setFrameParent: (parentName: string) => void;
39
+ setGeometryType: (type: "none" | "box" | "sphere" | "capsule") => void;
40
+ }
41
+ export {};
@@ -0,0 +1,147 @@
1
+ export class DetailConfigUpdater {
2
+ object;
3
+ referenceFrame;
4
+ updateFrame;
5
+ constructor(object, updateFrame, referenceFrame) {
6
+ this.referenceFrame = referenceFrame;
7
+ this.object = object;
8
+ this.updateFrame = updateFrame;
9
+ }
10
+ updateLocalPosition = ({ x, y, z }) => {
11
+ const object = this.object();
12
+ if (!object)
13
+ return;
14
+ object.localEditedPose.x = x ?? object.localEditedPose.x;
15
+ object.localEditedPose.y = y ?? object.localEditedPose.y;
16
+ object.localEditedPose.z = z ?? object.localEditedPose.z;
17
+ this.updateFrame(object.name ?? '', this.referenceFrame(), {
18
+ x: x ?? object.localEditedPose.x,
19
+ y: y ?? object.localEditedPose.y,
20
+ z: z ?? object.localEditedPose.z,
21
+ oX: object.localEditedPose.oX,
22
+ oY: object.localEditedPose.oY,
23
+ oZ: object.localEditedPose.oZ,
24
+ theta: object.localEditedPose.theta,
25
+ });
26
+ };
27
+ updateLocalOrientation = ({ oX, oY, oZ, theta, }) => {
28
+ const object = this.object();
29
+ if (!object)
30
+ return;
31
+ object.localEditedPose.oX = oX ?? object.localEditedPose.oX;
32
+ object.localEditedPose.oY = oY ?? object.localEditedPose.oY;
33
+ object.localEditedPose.oZ = oZ ?? object.localEditedPose.oZ;
34
+ object.localEditedPose.theta = theta ?? object.localEditedPose.theta;
35
+ this.updateFrame(object.name ?? '', this.referenceFrame(), {
36
+ oX: oX ?? object.localEditedPose.oX,
37
+ oY: oY ?? object.localEditedPose.oY,
38
+ oZ: oZ ?? object.localEditedPose.oZ,
39
+ theta: theta ?? object.localEditedPose.theta,
40
+ x: object.localEditedPose.x,
41
+ y: object.localEditedPose.y,
42
+ z: object.localEditedPose.z,
43
+ });
44
+ };
45
+ updateGeometry = (geometry) => {
46
+ const object = this.object();
47
+ if (!object)
48
+ return;
49
+ let geometryObject;
50
+ if (geometry.type === 'box') {
51
+ const currentGeometry = object.geometry?.geometryType.value;
52
+ geometryObject = {
53
+ type: 'box',
54
+ x: geometry.x ?? currentGeometry?.dimsMm?.x,
55
+ y: geometry.y ?? currentGeometry?.dimsMm?.y,
56
+ z: geometry.z ?? currentGeometry?.dimsMm?.z,
57
+ };
58
+ }
59
+ else if (geometry.type === 'sphere') {
60
+ const currentGeometry = object.geometry?.geometryType.value;
61
+ geometryObject = {
62
+ type: 'sphere',
63
+ r: geometry.r ?? currentGeometry?.radiusMm,
64
+ };
65
+ }
66
+ else if (geometry.type === 'capsule') {
67
+ const currentGeometry = object.geometry?.geometryType.value;
68
+ geometryObject = {
69
+ type: 'capsule',
70
+ r: geometry.r ?? currentGeometry?.radiusMm,
71
+ l: geometry.l ?? currentGeometry?.lengthMm,
72
+ };
73
+ }
74
+ this.updateFrame(object.name ?? '', this.referenceFrame(), {
75
+ x: object.localEditedPose.x,
76
+ y: object.localEditedPose.y,
77
+ z: object.localEditedPose.z,
78
+ oX: object.localEditedPose.oX,
79
+ oY: object.localEditedPose.oY,
80
+ oZ: object.localEditedPose.oZ,
81
+ theta: object.localEditedPose.theta,
82
+ }, { ...geometryObject });
83
+ };
84
+ setFrameParent = (parentName) => {
85
+ const object = this.object();
86
+ if (!object)
87
+ return;
88
+ this.updateFrame(object.name ?? '', parentName, {
89
+ x: object.localEditedPose.x,
90
+ y: object.localEditedPose.y,
91
+ z: object.localEditedPose.z,
92
+ oX: object.localEditedPose.oX,
93
+ oY: object.localEditedPose.oY,
94
+ oZ: object.localEditedPose.oZ,
95
+ theta: object.localEditedPose.theta,
96
+ });
97
+ };
98
+ setGeometryType = (type) => {
99
+ const object = this.object();
100
+ if (!object)
101
+ return;
102
+ if (type === 'none') {
103
+ this.updateFrame(object.name ?? '', this.referenceFrame(), {
104
+ x: object.localEditedPose.x,
105
+ y: object.localEditedPose.y,
106
+ z: object.localEditedPose.z,
107
+ oX: object.localEditedPose.oX,
108
+ oY: object.localEditedPose.oY,
109
+ oZ: object.localEditedPose.oZ,
110
+ theta: object.localEditedPose.theta,
111
+ }, { type: 'none' });
112
+ }
113
+ else if (type === 'box') {
114
+ this.updateFrame(object.name ?? '', this.referenceFrame(), {
115
+ x: object.localEditedPose.x,
116
+ y: object.localEditedPose.y,
117
+ z: object.localEditedPose.z,
118
+ oX: object.localEditedPose.oX,
119
+ oY: object.localEditedPose.oY,
120
+ oZ: object.localEditedPose.oZ,
121
+ theta: object.localEditedPose.theta,
122
+ }, { type: 'box', x: 100, y: 100, z: 100 });
123
+ }
124
+ else if (type === 'sphere') {
125
+ this.updateFrame(object.name ?? '', this.referenceFrame(), {
126
+ x: object.localEditedPose.x,
127
+ y: object.localEditedPose.y,
128
+ z: object.localEditedPose.z,
129
+ oX: object.localEditedPose.oX,
130
+ oY: object.localEditedPose.oY,
131
+ oZ: object.localEditedPose.oZ,
132
+ theta: object.localEditedPose.theta,
133
+ }, { type: 'sphere', r: 100 });
134
+ }
135
+ else if (type === 'capsule') {
136
+ this.updateFrame(object.name ?? '', this.referenceFrame(), {
137
+ x: object.localEditedPose.x,
138
+ y: object.localEditedPose.y,
139
+ z: object.localEditedPose.z,
140
+ oX: object.localEditedPose.oX,
141
+ oY: object.localEditedPose.oY,
142
+ oZ: object.localEditedPose.oZ,
143
+ theta: object.localEditedPose.theta,
144
+ }, { type: 'capsule', r: 20, l: 100 });
145
+ }
146
+ };
147
+ }
@@ -1,14 +1,21 @@
1
1
  import type { Geometry, Pose, TransformWithUUID } from '@viamrobotics/sdk';
2
- import { BatchedMesh, Box3, Object3D, Vector3, type ColorRepresentation } from 'three';
2
+ import { BatchedMesh, Object3D, Vector3, type ColorRepresentation } from 'three';
3
+ import type { OBB } from 'three/addons/math/OBB.js';
3
4
  export type PointsGeometry = {
4
- case: 'points';
5
- value: Float32Array<ArrayBuffer>;
5
+ center: undefined;
6
+ geometryType: {
7
+ case: 'points';
8
+ value: Float32Array<ArrayBuffer>;
9
+ };
6
10
  };
7
11
  export type LinesGeometry = {
8
- case: 'line';
9
- value: Float32Array;
12
+ center: undefined;
13
+ geometryType: {
14
+ case: 'line';
15
+ value: Float32Array;
16
+ };
10
17
  };
11
- export type Geometries = Geometry['geometryType'] | PointsGeometry | LinesGeometry;
18
+ export type Geometries = Geometry | PointsGeometry | LinesGeometry;
12
19
  export type Metadata = {
13
20
  colors?: Float32Array;
14
21
  color?: ColorRepresentation;
@@ -24,33 +31,17 @@ export type Metadata = {
24
31
  id: number;
25
32
  object: BatchedMesh;
26
33
  };
27
- getBoundingBoxAt?: (box: Box3) => void;
34
+ getBoundingBoxAt?: (box: OBB) => void;
28
35
  };
36
+ export declare const determinePose: (object: WorldObject, pose: WorldObject["pose"] | undefined) => WorldObject["pose"];
29
37
  export declare class WorldObject<T extends Geometries = Geometries> {
30
38
  uuid: string;
31
39
  name: string;
32
- referenceFrame: string;
40
+ referenceFrame: string | undefined;
33
41
  pose: import("@viamrobotics/sdk").PlainMessage<import("@viamrobotics/sdk/dist/gen/common/v1/common_pb").Pose>;
34
42
  geometry?: T;
35
43
  metadata: Metadata;
44
+ localEditedPose: import("@viamrobotics/sdk").PlainMessage<import("@viamrobotics/sdk/dist/gen/common/v1/common_pb").Pose>;
36
45
  constructor(name: string, pose?: Pose, parent?: string, geometry?: T, metadata?: Metadata);
37
46
  }
38
- export declare const fromTransform: (transform: TransformWithUUID) => WorldObject<{
39
- case: undefined;
40
- value?: undefined;
41
- } | {
42
- case: "sphere";
43
- value: import("@viamrobotics/sdk").PlainMessage<import("@viamrobotics/sdk/dist/gen/common/v1/common_pb").Sphere>;
44
- } | {
45
- case: "box";
46
- value: import("@viamrobotics/sdk").PlainMessage<import("@viamrobotics/sdk/dist/gen/common/v1/common_pb").RectangularPrism>;
47
- } | {
48
- case: "capsule";
49
- value: import("@viamrobotics/sdk").PlainMessage<import("@viamrobotics/sdk/dist/gen/common/v1/common_pb").Capsule>;
50
- } | {
51
- case: "mesh";
52
- value: import("@viamrobotics/sdk").PlainMessage<import("@viamrobotics/sdk/dist/gen/common/v1/common_pb").Mesh>;
53
- } | {
54
- case: "pointcloud";
55
- value: import("@viamrobotics/sdk").PlainMessage<import("@viamrobotics/sdk/dist/gen/common/v1/common_pb").PointCloud>;
56
- }>;
47
+ export declare const fromTransform: (transform: TransformWithUUID) => WorldObject<import("@viamrobotics/sdk").PlainMessage<import("@viamrobotics/sdk/dist/gen/common/v1/common_pb").Geometry>>;
@@ -1,12 +1,26 @@
1
- import { BatchedMesh, Box3, Color, MathUtils, Object3D, Vector3, } from 'three';
1
+ import { BatchedMesh, Color, MathUtils, Matrix4, Object3D, Quaternion, Vector3, } from 'three';
2
2
  import { createPose } from './transform';
3
+ export const determinePose = (object, pose) => {
4
+ if (pose === undefined) {
5
+ return object.localEditedPose;
6
+ }
7
+ else {
8
+ const poseNetwork = poseToMatrix(object.pose);
9
+ const poseUsePose = poseToMatrix(pose);
10
+ const poseLocalEditedPose = poseToMatrix(object.localEditedPose);
11
+ const poseNetworkInverse = poseNetwork.invert();
12
+ const resultMatrix = poseUsePose.multiply(poseNetworkInverse).multiply(poseLocalEditedPose);
13
+ return matrixToPose(resultMatrix);
14
+ }
15
+ };
3
16
  export class WorldObject {
4
17
  uuid;
5
18
  name;
6
- referenceFrame;
19
+ referenceFrame = $state.raw();
7
20
  pose = $state.raw(createPose());
8
21
  geometry;
9
22
  metadata;
23
+ localEditedPose = $state.raw(createPose());
10
24
  constructor(name, pose, parent = 'world', geometry, metadata) {
11
25
  this.uuid = MathUtils.generateUUID();
12
26
  this.name = name;
@@ -15,6 +29,7 @@ export class WorldObject {
15
29
  this.metadata = metadata ?? {};
16
30
  if (pose) {
17
31
  this.pose = pose;
32
+ this.localEditedPose = { ...pose };
18
33
  }
19
34
  }
20
35
  }
@@ -61,7 +76,37 @@ export const fromTransform = (transform) => {
61
76
  const metadata = transform.metadata
62
77
  ? parseMetadata(transform.metadata.fields)
63
78
  : {};
64
- const worldObject = new WorldObject(transform.referenceFrame, transform.poseInObserverFrame?.pose, transform.poseInObserverFrame?.referenceFrame, transform.physicalObject?.geometryType, metadata);
79
+ const worldObject = new WorldObject(transform.referenceFrame, transform.poseInObserverFrame?.pose, transform.poseInObserverFrame?.referenceFrame, transform.physicalObject, metadata);
65
80
  worldObject.uuid = transform.uuidString;
66
81
  return worldObject;
67
82
  };
83
+ const poseToMatrix = (pose) => {
84
+ const matrix = new Matrix4();
85
+ const poseQuaternion = new Quaternion().setFromAxisAngle(new Vector3(pose.oX, pose.oY, pose.oZ), pose.theta * (Math.PI / 180));
86
+ matrix.makeRotationFromQuaternion(poseQuaternion);
87
+ matrix.setPosition(new Vector3(pose.x, pose.y, pose.z));
88
+ return matrix;
89
+ };
90
+ const matrixToPose = (matrix) => {
91
+ const pose = createPose();
92
+ const translation = new Vector3();
93
+ const quaternion = new Quaternion();
94
+ matrix.decompose(translation, quaternion, new Vector3());
95
+ pose.x = translation.x;
96
+ pose.y = translation.y;
97
+ pose.z = translation.z;
98
+ const s = Math.sqrt(1 - quaternion.w * quaternion.w);
99
+ if (s < 0.000001) {
100
+ pose.oX = 0;
101
+ pose.oY = 0;
102
+ pose.oZ = 1;
103
+ pose.theta = 0;
104
+ }
105
+ else {
106
+ pose.oX = quaternion.x / s;
107
+ pose.oY = quaternion.y / s;
108
+ pose.oZ = quaternion.z / s;
109
+ pose.theta = Math.acos(quaternion.w) * 2 * (180 / Math.PI);
110
+ }
111
+ return pose;
112
+ };
@@ -3,6 +3,7 @@
3
3
  import { Canvas } from '@threlte/core'
4
4
  import { SvelteQueryDevtools } from '@tanstack/svelte-query-devtools'
5
5
  import { provideToast, ToastContainer } from '@viamrobotics/prime-core'
6
+ import type { Struct } from '@viamrobotics/sdk'
6
7
 
7
8
  import Scene from './Scene.svelte'
8
9
  import TreeContainer from './Tree/TreeContainer.svelte'
@@ -15,15 +16,34 @@
15
16
  import { domPortal } from '../portal'
16
17
  import { provideSettings } from '../hooks/useSettings.svelte'
17
18
  import FileDrop from './FileDrop.svelte'
19
+ import WeblabProvider from './weblab/WeblabProvider.svelte'
20
+ import { providePartConfig } from '../hooks/usePartConfig.svelte'
21
+ import { useViamClient } from '@viamrobotics/svelte-sdk'
22
+ import LiveUpdatesBanner from './LiveUpdatesBanner.svelte'
23
+ import ArmPositions from './widgets/ArmPositions.svelte'
24
+
25
+ interface LocalConfigProps {
26
+ getLocalPartConfig: () => Struct
27
+ setLocalPartConfig: (config: Struct) => void
28
+ isDirty: () => boolean
29
+ getComponentToFragId: () => Record<string, string>
30
+ }
18
31
 
19
32
  interface Props {
20
33
  partID?: string
21
34
  enableKeybindings?: boolean
22
35
  children?: Snippet
36
+ localConfigProps?: LocalConfigProps
23
37
  }
24
38
 
25
- let { partID = '', enableKeybindings = true, children: appChildren }: Props = $props()
39
+ let {
40
+ partID = '',
41
+ enableKeybindings = true,
42
+ children: appChildren,
43
+ localConfigProps,
44
+ }: Props = $props()
26
45
 
46
+ const appClient = useViamClient()
27
47
  const settings = provideSettings()
28
48
 
29
49
  $effect(() => {
@@ -35,38 +55,68 @@
35
55
  provideToast()
36
56
 
37
57
  let root = $state.raw<HTMLElement>()
58
+ let isStandalone = $state(false)
59
+
60
+ if (localConfigProps) {
61
+ isStandalone = false
62
+ providePartConfig({
63
+ appEmbeddedPartConfigProps: {
64
+ isDirty: () => localConfigProps.isDirty(),
65
+ getLocalPartConfig: () => localConfigProps.getLocalPartConfig(),
66
+ setLocalPartConfig: (config: Struct) => localConfigProps.setLocalPartConfig(config),
67
+ getComponentToFragId: () => localConfigProps.getComponentToFragId(),
68
+ },
69
+ })
70
+ } else {
71
+ isStandalone = true
72
+ providePartConfig({
73
+ standalonePartConfigProps: {
74
+ viamClient: () => appClient?.current,
75
+ partID: () => partID,
76
+ },
77
+ })
78
+ }
38
79
  </script>
39
80
 
40
81
  {#if settings.current.enableQueryDevtools}
41
82
  <SvelteQueryDevtools initialIsOpen />
42
83
  {/if}
43
84
 
44
- <div
45
- class="relative h-full w-full overflow-hidden"
46
- bind:this={root}
47
- >
48
- <Canvas renderMode="always">
49
- <World>
50
- <SceneProviders>
51
- {#snippet children({ focus })}
52
- <Scene>
53
- {@render appChildren?.()}
54
- </Scene>
55
-
56
- <XR {@attach domPortal(root)} />
57
-
58
- <Dashboard {@attach domPortal(root)} />
59
- <Details {@attach domPortal(root)} />
60
-
61
- {#if !focus}
62
- <TreeContainer {@attach domPortal(root)} />
63
- {/if}
64
-
65
- <FileDrop {@attach domPortal(root)} />
66
- {/snippet}
67
- </SceneProviders>
68
- </World>
69
- </Canvas>
70
-
71
- <ToastContainer />
72
- </div>
85
+ <WeblabProvider>
86
+ <div
87
+ class="relative h-full w-full overflow-hidden"
88
+ bind:this={root}
89
+ >
90
+ <Canvas renderMode="always">
91
+ <World>
92
+ <SceneProviders>
93
+ {#snippet children({ focus })}
94
+ <Scene>
95
+ {@render appChildren?.()}
96
+ </Scene>
97
+
98
+ <XR {@attach domPortal(root)} />
99
+
100
+ <Dashboard {@attach domPortal(root)} />
101
+ <Details {@attach domPortal(root)} />
102
+ {#if isStandalone}
103
+ <LiveUpdatesBanner {@attach domPortal(root)} />
104
+ {/if}
105
+
106
+ {#if !focus}
107
+ <TreeContainer {@attach domPortal(root)} />
108
+ {/if}
109
+
110
+ {#if !focus && settings.current.enableArmPositionsWidget}
111
+ <ArmPositions {@attach domPortal(root)} />
112
+ {/if}
113
+
114
+ <FileDrop {@attach domPortal(root)} />
115
+ {/snippet}
116
+ </SceneProviders>
117
+ </World>
118
+ </Canvas>
119
+
120
+ <ToastContainer />
121
+ </div>
122
+ </WeblabProvider>
@@ -1,8 +1,16 @@
1
1
  import type { Snippet } from 'svelte';
2
+ import type { Struct } from '@viamrobotics/sdk';
3
+ interface LocalConfigProps {
4
+ getLocalPartConfig: () => Struct;
5
+ setLocalPartConfig: (config: Struct) => void;
6
+ isDirty: () => boolean;
7
+ getComponentToFragId: () => Record<string, string>;
8
+ }
2
9
  interface Props {
3
10
  partID?: string;
4
11
  enableKeybindings?: boolean;
5
12
  children?: Snippet;
13
+ localConfigProps?: LocalConfigProps;
6
14
  }
7
15
  declare const App: import("svelte").Component<Props, {}, "">;
8
16
  type App = ReturnType<typeof App>;