@viamrobotics/motion-tools 0.19.2 → 1.0.2

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 (135) hide show
  1. package/README.md +56 -26
  2. package/dist/FrameConfigUpdater.svelte.d.ts +11 -17
  3. package/dist/FrameConfigUpdater.svelte.js +109 -109
  4. package/dist/WorldObject.svelte.js +2 -15
  5. package/dist/common/v1/common_pb.d.ts +950 -0
  6. package/dist/common/v1/common_pb.js +1399 -0
  7. package/dist/components/App.svelte +37 -21
  8. package/dist/components/App.svelte.d.ts +1 -0
  9. package/dist/components/BatchedArrows.svelte +102 -0
  10. package/dist/components/BatchedArrows.svelte.d.ts +3 -0
  11. package/dist/components/CameraControls.svelte +2 -3
  12. package/dist/components/Details.svelte +364 -365
  13. package/dist/components/Entities.svelte +73 -0
  14. package/dist/components/{WorldObjects.svelte.d.ts → Entities.svelte.d.ts} +3 -3
  15. package/dist/components/FileDrop.svelte +9 -23
  16. package/dist/components/Focus.svelte +2 -3
  17. package/dist/components/Frame.svelte +41 -22
  18. package/dist/components/Frame.svelte.d.ts +4 -6
  19. package/dist/components/GLTF.svelte +36 -0
  20. package/dist/components/GLTF.svelte.d.ts +11 -0
  21. package/dist/components/Geometry2.svelte +201 -0
  22. package/dist/components/Geometry2.svelte.d.ts +18 -0
  23. package/dist/components/KeyboardControls.svelte +3 -3
  24. package/dist/components/Line.svelte +10 -13
  25. package/dist/components/Line.svelte.d.ts +2 -2
  26. package/dist/components/LiveUpdatesBanner.svelte +51 -15
  27. package/dist/components/MeasureTool.svelte +4 -5
  28. package/dist/components/Pointcloud.svelte +27 -14
  29. package/dist/components/Pointcloud.svelte.d.ts +2 -2
  30. package/dist/components/PointerMissBox.svelte +3 -3
  31. package/dist/components/Pose.svelte +31 -6
  32. package/dist/components/Pose.svelte.d.ts +2 -2
  33. package/dist/components/Scene.svelte +7 -6
  34. package/dist/components/SceneProviders.svelte +0 -6
  35. package/dist/components/Selected.svelte +22 -16
  36. package/dist/components/StaticGeometries.svelte +51 -27
  37. package/dist/components/Tree/Tree.svelte +28 -22
  38. package/dist/components/Tree/Tree.svelte.d.ts +2 -3
  39. package/dist/components/Tree/TreeContainer.svelte +72 -40
  40. package/dist/components/Tree/Widgets.svelte +2 -5
  41. package/dist/components/Tree/buildTree.d.ts +3 -6
  42. package/dist/components/Tree/buildTree.js +19 -39
  43. package/dist/components/__tests__/__fixtures__/entity.d.ts +2 -0
  44. package/dist/components/__tests__/__fixtures__/entity.js +20 -0
  45. package/dist/components/__tests__/__fixtures__/resource.d.ts +17 -0
  46. package/dist/components/__tests__/__fixtures__/resource.js +13 -0
  47. package/dist/components/dashboard/Dashboard.svelte +5 -3
  48. package/dist/components/dashboard/Dashboard.svelte.d.ts +7 -2
  49. package/dist/components/widgets/ArmPositions.svelte +19 -7
  50. package/dist/draw/v1/drawing_pb.d.ts +341 -0
  51. package/dist/draw/v1/drawing_pb.js +417 -0
  52. package/dist/draw/v1/metadata_pb.d.ts +23 -0
  53. package/dist/draw/v1/metadata_pb.js +39 -0
  54. package/dist/draw/v1/scene_pb.d.ts +230 -0
  55. package/dist/draw/v1/scene_pb.js +298 -0
  56. package/dist/draw/v1/snapshot_pb.d.ts +42 -0
  57. package/dist/draw/v1/snapshot_pb.js +61 -0
  58. package/dist/draw/v1/transforms_pb.d.ts +23 -0
  59. package/dist/draw/v1/transforms_pb.js +39 -0
  60. package/dist/ecs/index.d.ts +4 -0
  61. package/dist/ecs/index.js +4 -0
  62. package/dist/ecs/traits.d.ts +128 -0
  63. package/dist/ecs/traits.js +81 -0
  64. package/dist/ecs/useQuery.svelte.d.ts +4 -0
  65. package/dist/ecs/useQuery.svelte.js +49 -0
  66. package/dist/ecs/useTrait.svelte.d.ts +19 -0
  67. package/dist/ecs/useTrait.svelte.js +40 -0
  68. package/dist/ecs/useWorld.d.ts +4 -0
  69. package/dist/ecs/useWorld.js +10 -0
  70. package/dist/geometry.js +6 -6
  71. package/dist/hooks/__tests__/fixtures/ResizableTestWrapper.svelte +41 -0
  72. package/dist/hooks/__tests__/fixtures/ResizableTestWrapper.svelte.d.ts +6 -0
  73. package/dist/hooks/use3DModels.svelte.js +6 -4
  74. package/dist/hooks/useDrawAPI.svelte.d.ts +0 -10
  75. package/dist/hooks/useDrawAPI.svelte.js +143 -267
  76. package/dist/hooks/useFramelessComponents.svelte.js +1 -1
  77. package/dist/hooks/useFrames.svelte.d.ts +6 -2
  78. package/dist/hooks/useFrames.svelte.js +123 -19
  79. package/dist/hooks/useGeometries.svelte.d.ts +0 -2
  80. package/dist/hooks/useGeometries.svelte.js +49 -25
  81. package/dist/hooks/useObjectEvents.svelte.d.ts +3 -2
  82. package/dist/hooks/useObjectEvents.svelte.js +11 -7
  83. package/dist/hooks/usePartConfig.svelte.d.ts +1 -1
  84. package/dist/hooks/usePartConfig.svelte.js +2 -1
  85. package/dist/hooks/usePointclouds.svelte.d.ts +0 -2
  86. package/dist/hooks/usePointclouds.svelte.js +52 -21
  87. package/dist/hooks/usePose.svelte.js +15 -7
  88. package/dist/hooks/useResizable.svelte.d.ts +12 -0
  89. package/dist/hooks/useResizable.svelte.js +45 -0
  90. package/dist/hooks/useResourceByName.svelte.js +8 -5
  91. package/dist/hooks/useSelection.svelte.d.ts +13 -23
  92. package/dist/hooks/useSelection.svelte.js +45 -65
  93. package/dist/hooks/useVisibility.svelte.d.ts +2 -1
  94. package/dist/hooks/useWeblabs.svelte.d.ts +0 -1
  95. package/dist/hooks/useWeblabs.svelte.js +0 -1
  96. package/dist/hooks/useWorldState.svelte.d.ts +9 -0
  97. package/dist/hooks/useWorldState.svelte.js +158 -107
  98. package/dist/lib.d.ts +1 -0
  99. package/dist/lib.js +2 -0
  100. package/dist/three/BatchedArrow.d.ts +2 -3
  101. package/dist/three/BatchedArrow.js +3 -11
  102. package/dist/three/CapsuleGeometry.d.ts +1 -1
  103. package/dist/three/CapsuleGeometry.js +3 -1
  104. package/dist/transform.js +0 -15
  105. package/package.json +12 -7
  106. package/dist/components/WorldObject.svelte +0 -28
  107. package/dist/components/WorldObject.svelte.d.ts +0 -11
  108. package/dist/components/WorldObjects.svelte +0 -159
  109. package/dist/components/WorldState.svelte +0 -92
  110. package/dist/components/WorldState.svelte.d.ts +0 -7
  111. package/dist/components/__tests__/__fixtures__/worldObject.svelte.d.ts +0 -2
  112. package/dist/components/__tests__/__fixtures__/worldObject.svelte.js +0 -35
  113. package/dist/components/portal/Portal.svelte +0 -25
  114. package/dist/components/portal/Portal.svelte.d.ts +0 -8
  115. package/dist/components/portal/PortalTarget.svelte +0 -18
  116. package/dist/components/portal/PortalTarget.svelte.d.ts +0 -6
  117. package/dist/components/portal/index.d.ts +0 -2
  118. package/dist/components/portal/index.js +0 -2
  119. package/dist/components/portal/usePortalContext.svelte.d.ts +0 -5
  120. package/dist/components/portal/usePortalContext.svelte.js +0 -5
  121. package/dist/hooks/useArrows.svelte.d.ts +0 -3
  122. package/dist/hooks/useArrows.svelte.js +0 -9
  123. package/dist/hooks/useDraggable.svelte.d.ts +0 -10
  124. package/dist/hooks/useDraggable.svelte.js +0 -36
  125. package/dist/hooks/useObjects.svelte.d.ts +0 -7
  126. package/dist/hooks/useObjects.svelte.js +0 -35
  127. package/dist/hooks/usePersistentUUIDs.svelte.d.ts +0 -5
  128. package/dist/hooks/usePersistentUUIDs.svelte.js +0 -13
  129. package/dist/hooks/useResourceByName.svelte.d.ts +0 -7
  130. package/dist/hooks/useStaticGeometries.svelte.d.ts +0 -9
  131. package/dist/hooks/useStaticGeometries.svelte.js +0 -47
  132. package/dist/workers/worldStateWorker.d.ts +0 -1
  133. package/dist/workers/worldStateWorker.js +0 -114
  134. package/dist/world-state-messages.d.ts +0 -23
  135. package/dist/world-state-messages.js +0 -1
@@ -1,17 +1,18 @@
1
1
  import { getContext, setContext } from 'svelte';
2
- import { Color, MathUtils, Quaternion, Vector3, Vector4 } from 'three';
2
+ import { Color, Vector3, Vector4 } from 'three';
3
3
  import { NURBSCurve } from 'three/addons/curves/NURBSCurve.js';
4
4
  import { UuidTool } from 'uuid-tool';
5
5
  import { parsePcdInWorker } from '../loaders/pcd';
6
6
  import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
7
- import { WorldObject } from '../WorldObject.svelte';
8
- import { useArrows } from './useArrows.svelte';
9
- import { createGeometry } from '../geometry';
10
7
  import { createPose, createPoseFromFrame } from '../transform';
11
8
  import { useCameraControls } from './useControls.svelte';
9
+ import { useWorld, traits } from '../ecs';
12
10
  import { useThrelte } from '@threlte/core';
13
- import { OrientationVector } from '../three/OrientationVector';
11
+ import {} from 'koota';
12
+ import { parsePlyInput } from '../ply';
14
13
  import { useLogs } from './useLogs.svelte';
14
+ import { createBox, createCapsule, createSphere } from '../geometry';
15
+ const colorUtil = new Color();
15
16
  const bufferTypes = {
16
17
  DRAW_POINTS: 0,
17
18
  DRAW_POSES: 1,
@@ -19,9 +20,6 @@ const bufferTypes = {
19
20
  DRAW_PCD: 3,
20
21
  DRAW_GLTF: 4,
21
22
  };
22
- const axis = new Vector3();
23
- const quaternion = new Quaternion();
24
- const ov = new OrientationVector();
25
23
  const key = Symbol('draw-api-context-key');
26
24
  const tryParse = (json) => {
27
25
  try {
@@ -50,26 +48,25 @@ class Float32Reader {
50
48
  littleEndian = true;
51
49
  offset = 0;
52
50
  buffer = new ArrayBuffer();
51
+ array = new Float32Array();
53
52
  view = new DataView(this.buffer);
54
53
  header = { requestID: '', type: -1 };
55
54
  async init(data) {
56
55
  this.buffer = await data.arrayBuffer();
57
- this.header = {
58
- requestID: UuidTool.toString([...new Uint8Array(this.buffer.slice(0, 16))]),
59
- type: new DataView(this.buffer).getFloat32(16, true),
60
- };
61
- // Slice away the request header and leave the body
56
+ this.header.requestID = UuidTool.toString([...new Uint8Array(this.buffer.slice(0, 16))]);
57
+ this.header.type = new Float32Array(this.buffer.slice(16, 20))[0];
62
58
  this.buffer = this.buffer.slice(20);
63
- this.view = new DataView(this.buffer);
59
+ this.array = new Float32Array(this.buffer);
64
60
  return this;
65
61
  }
66
62
  read() {
67
- const result = this.view.getFloat32(this.offset, this.littleEndian);
68
- this.offset += 4;
63
+ const result = this.array[this.offset];
64
+ this.offset += 1;
69
65
  return result;
70
66
  }
71
67
  }
72
68
  export const provideDrawAPI = () => {
69
+ const world = useWorld();
73
70
  const logs = useLogs();
74
71
  const cameraControls = useCameraControls();
75
72
  const { invalidate } = useThrelte();
@@ -79,148 +76,134 @@ export const provideDrawAPI = () => {
79
76
  let reconnectDelay = 200;
80
77
  const maxReconnectDelay = 5_000;
81
78
  let ws;
82
- const frames = $state([]);
83
- const points = $state([]);
84
- const lines = $state([]);
85
- const meshes = $state([]);
86
- const poses = $state([]);
87
- const nurbs = $state([]);
88
- const models = $state([]);
89
79
  let connectionStatus = $state('connecting');
90
- const color = new Color();
91
80
  const direction = new Vector3();
92
81
  const origin = new Vector3();
93
82
  const loader = new GLTFLoader();
94
- const batchedArrow = useArrows();
83
+ const entities = new Map();
95
84
  const sendResponse = (response) => {
96
85
  ws.send(JSON.stringify(response));
97
86
  };
98
87
  const drawFrames = async (data) => {
99
- for (const frame of data) {
100
- const name = frame.name || frame.id || '';
101
- const pose = createPoseFromFrame(lowercaseKeys(frame));
102
- const geometry = createGeometry();
103
- if (frame.geometry?.type === 'box') {
104
- geometry.label = `${name} geometry (box)`;
105
- geometry.geometryType.case = 'box';
106
- geometry.geometryType.value = {
107
- dimsMm: { x: frame.geometry.x, y: frame.geometry.y, z: frame.geometry.z },
108
- };
88
+ for (const rawFrame of data) {
89
+ const frame = lowercaseKeys(rawFrame);
90
+ const pose = createPoseFromFrame(frame);
91
+ const name = frame.name ?? frame.id ?? '';
92
+ const parent = frame.parent;
93
+ const existing = entities.get(name);
94
+ if (existing) {
95
+ existing.set(traits.Pose, pose);
96
+ if (parent && parent !== 'world') {
97
+ existing.set(traits.Parent, parent);
98
+ }
99
+ continue;
109
100
  }
110
- else if (frame.geometry?.type === 'sphere') {
111
- geometry.label = `${name} geometry (sphere)`;
112
- geometry.geometryType.case = 'sphere';
113
- geometry.geometryType.value = { radiusMm: frame.geometry.r };
101
+ const geometryTrait = () => {
102
+ if (frame.geometry?.type === 'box') {
103
+ return traits.Box(frame.geometry);
104
+ }
105
+ else if (frame.geometry?.type === 'sphere') {
106
+ return traits.Sphere(frame.geometry);
107
+ }
108
+ else if (frame.geometry?.type === 'capsule') {
109
+ return traits.Capsule(frame.geometry);
110
+ }
111
+ return traits.ReferenceFrame;
112
+ };
113
+ const entityTraits = [];
114
+ if (parent && parent !== 'world') {
115
+ entityTraits.push(traits.Parent(parent));
114
116
  }
115
- else if (frame.geometry?.type === 'capsule') {
116
- geometry.label = `${name} geometry (capsule)`;
117
- geometry.geometryType.case = 'capsule';
118
- geometry.geometryType.value = { lengthMm: frame.geometry.l, radiusMm: frame.geometry.r };
117
+ if (frame.geometry) {
118
+ entityTraits.push(geometryTrait());
119
119
  }
120
- const worldObject = new WorldObject(name, pose, frame.parent ?? 'world', frame.geometry ? geometry : undefined);
121
- frames.push(worldObject);
120
+ entityTraits.push(traits.Name(name), traits.Pose(pose), traits.DrawAPI, traits.ReferenceFrame);
121
+ const entity = world.spawn(...entityTraits);
122
+ entities.set(name, entity);
122
123
  }
123
124
  };
124
125
  const drawPCD = async (buffer) => {
125
126
  const { positions, colors } = await parsePcdInWorker(new Uint8Array(buffer));
126
- points.push(new WorldObject(`points ${++pointsIndex}`, undefined, undefined, {
127
- center: undefined,
128
- geometryType: {
129
- case: 'points',
130
- value: positions,
131
- },
132
- }, colors ? { colors } : undefined));
127
+ const entity = world.spawn(traits.Name(`Points ${++pointsIndex}`), traits.PointsGeometry(positions), traits.DrawAPI);
128
+ if (colors) {
129
+ entity.add(traits.VertexColors(colors));
130
+ }
133
131
  };
134
132
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
135
133
  const drawGeometry = (data, color, parent) => {
136
- const result = meshes.find((mesh) => mesh.name === data.label);
137
- if (result) {
138
- result.pose = createPose(data.center);
134
+ const name = data.label ?? `geometry ${++geometryIndex}`;
135
+ const pose = createPose(data.center);
136
+ const existing = entities.get(name);
137
+ if (existing) {
138
+ existing.set(traits.Pose, pose);
139
139
  return;
140
140
  }
141
- const geometry = createGeometry();
142
- if ('mesh' in data) {
143
- geometry.geometryType.case = 'mesh';
144
- geometry.geometryType.value = data.mesh;
145
- }
146
- else if ('box' in data) {
147
- geometry.geometryType.case = 'box';
148
- geometry.geometryType.value = data.box;
149
- }
150
- else if ('sphere' in data) {
151
- geometry.geometryType.case = 'sphere';
152
- geometry.geometryType.value = data.sphere;
153
- }
154
- else if ('capsule' in data) {
155
- geometry.geometryType.case = 'capsule';
156
- geometry.geometryType.value = data.capsule;
141
+ const geometryTrait = () => {
142
+ if ('mesh' in data) {
143
+ const geometry = parsePlyInput(data.mesh.mesh);
144
+ return traits.BufferGeometry(geometry);
145
+ }
146
+ else if ('box' in data) {
147
+ return traits.Box(createBox(data.box));
148
+ }
149
+ else if ('sphere' in data) {
150
+ return traits.Sphere(createSphere(data.sphere));
151
+ }
152
+ else if ('capsule' in data) {
153
+ return traits.Capsule(createCapsule(data.capsule));
154
+ }
155
+ return traits.ReferenceFrame;
156
+ };
157
+ const entityTraits = [];
158
+ if (parent && parent !== 'world') {
159
+ entityTraits.push(traits.Parent(parent));
157
160
  }
158
- const object = new WorldObject(data.label ?? ++geometryIndex, createPose(data.center), parent, geometry, {
159
- color: new Color(color),
160
- });
161
- meshes.push(object);
161
+ entityTraits.push(traits.Name(data.label ?? ++geometryIndex), traits.Pose(pose), traits.Color(colorUtil.set(color)), geometryTrait(), traits.DrawAPI);
162
+ const entity = world.spawn(...entityTraits);
163
+ entities.set(name, entity);
162
164
  };
163
165
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
164
166
  const drawNurbs = (data, color) => {
165
- const index = nurbs.findIndex(({ name }) => name === data.name);
166
- if (index !== -1) {
167
- nurbs.splice(index, 1);
168
- }
167
+ const name = data.Name;
168
+ const existing = entities.get(name);
169
169
  const controlPoints = data.ControlPts.map((point) => new Vector4(point.x / 1000, point.y / 1000, point.z / 1000));
170
170
  const curve = new NURBSCurve(data.Degree, data.Knots, controlPoints);
171
- const object = new WorldObject(data.name, data.pose, data.parent, { center: undefined, geometryType: { case: 'line', value: new Float32Array() } }, { color: new Color(color), points: curve.getPoints(200) });
172
- nurbs.push(object);
171
+ const points = curve.getPoints(200);
172
+ if (existing) {
173
+ existing.set(traits.LineGeometry, points);
174
+ return;
175
+ }
176
+ const entity = world.spawn(traits.Name(name), traits.Color(colorUtil.set(color)), traits.LineGeometry(points), traits.DrawAPI);
177
+ entities.set(name, entity);
173
178
  };
179
+ const vec3 = new Vector3();
180
+ const pose = createPose();
174
181
  const drawPoses = async (reader) => {
175
182
  // Read counts
176
183
  const nPoints = reader.read();
177
184
  const nColors = reader.read();
178
185
  const arrowHeadAtPose = reader.read();
179
- // Read positions
180
- const nextPoses = new Float32Array(nPoints * 6);
181
- for (let i = 0; i < nPoints * 6; i++) {
182
- nextPoses[i] = reader.read();
183
- }
184
- // Read raw colors
185
- const colors = new Float32Array(nColors * 3);
186
- for (let i = 0; i < nColors * 3; i++) {
187
- colors[i] = reader.read();
188
- }
189
- const length = 0.1;
190
- for (let i = 0, j = 0, l = nextPoses.length; i < l; i += 6, j += 3) {
191
- origin.set(nextPoses[i], nextPoses[i + 1], nextPoses[i + 2]).multiplyScalar(0.001);
192
- direction.set(nextPoses[i + 3], nextPoses[i + 4], nextPoses[i + 5]);
193
- color.set(colors[j], colors[j + 1], colors[j + 2]);
194
- const arrowId = batchedArrow.addArrow(direction, origin, length, color, arrowHeadAtPose === 1);
195
- const pose = createPose();
186
+ const entities = [];
187
+ for (let i = 0; i < nPoints; i += 1) {
188
+ origin.set(reader.read(), reader.read(), reader.read()).multiplyScalar(0.001);
189
+ direction.set(reader.read(), reader.read(), reader.read());
190
+ if (arrowHeadAtPose === 1) {
191
+ // Compute the base position so the arrow ends at the origin
192
+ origin.sub(vec3.copy(direction).multiplyScalar(/** arrow length */ 0.1));
193
+ }
196
194
  pose.x = origin.x;
197
195
  pose.y = origin.y;
198
196
  pose.z = origin.z;
199
- if (direction.y > 0.99999) {
200
- quaternion.set(0, 0, 0, 1);
201
- }
202
- else if (direction.y < -0.99999) {
203
- quaternion.set(1, 0, 0, 0);
204
- }
205
- else {
206
- axis.set(direction.z, 0, -direction.x).normalize();
207
- const radians = Math.acos(direction.y);
208
- quaternion.setFromAxisAngle(axis, radians);
209
- }
210
- ov.setFromQuaternion(quaternion);
211
- pose.oX = ov.x;
212
- pose.oY = ov.y;
213
- pose.oZ = ov.z;
214
- pose.theta = MathUtils.radToDeg(ov.th);
215
- poses.push(new WorldObject(`pose ${++poseIndex}`, pose, 'world', undefined, {
216
- getBoundingBoxAt(box3) {
217
- return batchedArrow.getBoundingBoxAt(arrowId, box3);
218
- },
219
- batched: {
220
- id: arrowId,
221
- object: batchedArrow.object3d,
222
- },
223
- }));
197
+ pose.oX = direction.x;
198
+ pose.oY = direction.y;
199
+ pose.oZ = direction.z;
200
+ const entity = world.spawn(traits.Name(`Pose ${++poseIndex}`), traits.Pose(pose), traits.Color, traits.DrawAPI, traits.Arrow);
201
+ entities.push(entity);
202
+ }
203
+ for (let i = 0; i < nColors; i += 1) {
204
+ const entity = entities[i];
205
+ colorUtil.set(reader.read(), reader.read(), reader.read());
206
+ entity.set(traits.Color, colorUtil);
224
207
  }
225
208
  };
226
209
  const drawPoints = async (reader) => {
@@ -230,10 +213,9 @@ export const provideDrawAPI = () => {
230
213
  for (let i = 0; i < labelLen; i++) {
231
214
  label += String.fromCharCode(reader.read());
232
215
  }
233
- const index = points.findIndex(({ name }) => name === label);
234
- if (index !== -1) {
235
- points.splice(index, 1);
236
- }
216
+ const entities = world.query(traits.DrawAPI);
217
+ const entity = entities.find((entity) => entity.get(traits.Name) === label);
218
+ entity?.destroy();
237
219
  // Read counts
238
220
  const nPoints = reader.read();
239
221
  const nColors = reader.read();
@@ -241,45 +223,22 @@ export const provideDrawAPI = () => {
241
223
  const r = reader.read();
242
224
  const g = reader.read();
243
225
  const b = reader.read();
244
- // Read positions
245
- const positions = new Float32Array(nPoints * 3);
246
- for (let i = 0; i < nPoints * 3; i++) {
247
- positions[i] = reader.read();
226
+ const nPointsElements = nPoints * 3;
227
+ const positions = reader.array.slice(reader.offset, reader.offset + nPointsElements);
228
+ reader.offset += nPointsElements;
229
+ const nColorsElements = nColors * 3;
230
+ const rawColors = reader.array.slice(reader.offset, reader.offset + nColorsElements);
231
+ reader.offset += nColorsElements;
232
+ const colors = new Float32Array(nPointsElements);
233
+ colors.set(rawColors);
234
+ // Cover the gap for any points not colored
235
+ for (let i = nColors; i < nPoints; i++) {
236
+ const offset = i * 3;
237
+ colors[offset] = r;
238
+ colors[offset + 1] = g;
239
+ colors[offset + 2] = b;
248
240
  }
249
- const getColors = () => {
250
- // Read raw colors
251
- const rawColors = new Float32Array(nColors * 3);
252
- for (let i = 0; i < nColors * 3; i++) {
253
- rawColors[i] = reader.read();
254
- }
255
- const colors = new Float32Array(nPoints * 3);
256
- colors.set(rawColors);
257
- // Cover the gap for any points not colored
258
- for (let i = nColors; i < nPoints; i++) {
259
- const offset = i * 3;
260
- colors[offset] = r;
261
- colors[offset + 1] = g;
262
- colors[offset + 2] = b;
263
- }
264
- return colors;
265
- };
266
- const metadata = nColors > 0
267
- ? {
268
- colors: getColors(),
269
- color: new Color(r, g, b).convertLinearToSRGB(),
270
- }
271
- : r === -1
272
- ? undefined
273
- : {
274
- color: new Color(r, g, b).convertLinearToSRGB(),
275
- };
276
- points.push(new WorldObject(label, undefined, undefined, {
277
- center: undefined,
278
- geometryType: {
279
- case: 'points',
280
- value: positions,
281
- },
282
- }, metadata));
241
+ world.spawn(traits.Name(label), traits.Color(colorUtil.set(r, g, b)), traits.PointsGeometry(positions), traits.VertexColors(colors), traits.DrawAPI);
283
242
  };
284
243
  const drawLine = async (reader) => {
285
244
  // Read label length
@@ -288,39 +247,24 @@ export const provideDrawAPI = () => {
288
247
  for (let i = 0; i < labelLen; i++) {
289
248
  label += String.fromCharCode(reader.read());
290
249
  }
291
- const index = lines.findIndex(({ name }) => name === label);
292
- if (index !== -1) {
293
- lines.splice(index, 1);
294
- }
250
+ const entities = world.query(traits.DrawAPI);
251
+ const entity = entities.find((entity) => entity.get(traits.Name) === label);
252
+ entity?.destroy();
295
253
  // Read counts
296
254
  const nPoints = reader.read();
297
255
  // Read default color
298
- const lineR = reader.read();
299
- const lineG = reader.read();
300
- const lineB = reader.read();
256
+ const r = reader.read();
257
+ const g = reader.read();
258
+ const b = reader.read();
301
259
  const dotR = reader.read();
302
260
  const dotG = reader.read();
303
261
  const dotB = reader.read();
304
262
  // Read positions
305
- const positions = new Float32Array(nPoints * 3);
306
- for (let i = 0; i < nPoints * 3; i++) {
307
- positions[i] = reader.read();
308
- }
309
263
  const points = [];
310
- for (let i = 0; i < positions.length; i += 3) {
311
- points.push(new Vector3(positions[i], positions[i + 1], positions[i + 2]));
264
+ for (let i = 0; i < nPoints * 3; i += 3) {
265
+ points.push(new Vector3(reader.read(), reader.read(), reader.read()));
312
266
  }
313
- lines.push(new WorldObject(label, undefined, undefined, {
314
- center: undefined,
315
- geometryType: {
316
- case: 'line',
317
- value: positions,
318
- },
319
- }, {
320
- points,
321
- color: lineR === -1 ? undefined : new Color().setRGB(lineR, lineG, lineB),
322
- lineDotColor: dotR === -1 ? undefined : new Color().setRGB(dotR, dotG, dotB),
323
- }));
267
+ world.spawn(traits.Name(label), traits.Color({ r, g, b }), traits.LineGeometry(points), traits.DottedLineColor({ r: dotR, g: dotG, b: dotB }), traits.DrawAPI);
324
268
  };
325
269
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
326
270
  const drawGeometries = (geometries, colors, parent) => {
@@ -334,67 +278,26 @@ export const provideDrawAPI = () => {
334
278
  const blob = new Blob([buffer], { type: 'model/gltf-binary' });
335
279
  const url = URL.createObjectURL(blob);
336
280
  const gltf = await loader.loadAsync(url);
337
- models.push(new WorldObject(gltf.scene.name, undefined, undefined, undefined, { gltf }));
281
+ world.spawn(traits.Name(gltf.scene.name), traits.GLTF(gltf), traits.DrawAPI);
338
282
  URL.revokeObjectURL(url);
339
283
  };
340
284
  const remove = (names) => {
341
- let index = -1;
342
285
  for (const name of names) {
343
- index = frames.findIndex((frame) => frame.name === name);
344
- if (index !== -1) {
345
- frames.slice(index, 1);
346
- continue;
347
- }
348
- index = points.findIndex((p) => p.name === name);
349
- if (index !== -1) {
350
- points.splice(index, 1);
351
- continue;
352
- }
353
- index = meshes.findIndex((m) => m.name === name);
354
- if (index !== -1) {
355
- meshes.splice(index, 1);
356
- continue;
357
- }
358
- index = poses.findIndex((p) => p.name === name);
359
- if (index !== -1) {
360
- const id = poses[index].metadata.batched?.id;
361
- if (id) {
362
- batchedArrow.removeArrow(id);
363
- poses.splice(index, 1);
364
- continue;
286
+ for (const entity of world.query(traits.DrawAPI)) {
287
+ if (entity.get(traits.Name) === name) {
288
+ entity.destroy();
365
289
  }
366
290
  }
367
- index = nurbs.findIndex((n) => n.name === name);
368
- if (index !== -1) {
369
- nurbs.splice(index, 1);
370
- continue;
371
- }
372
- index = models.findIndex((m) => m.name === name);
373
- if (index !== -1) {
374
- models.splice(index, 1);
375
- continue;
376
- }
377
- index = lines.findIndex((m) => m.name === name);
378
- if (index !== -1) {
379
- lines.splice(index, 1);
380
- continue;
381
- }
382
291
  }
383
292
  };
384
293
  const removeAll = () => {
385
- frames.splice(0, frames.length);
386
- points.splice(0, points.length);
387
- lines.splice(0, lines.length);
388
- meshes.splice(0, meshes.length);
389
- nurbs.splice(0, nurbs.length);
390
- models.splice(0, models.length);
391
- poses.splice(0, poses.length);
392
- batchedArrow.clear();
294
+ for (const entity of world.query(traits.DrawAPI)) {
295
+ entity.destroy();
296
+ }
393
297
  pointsIndex = 0;
394
298
  geometryIndex = 0;
395
299
  poseIndex = 0;
396
300
  };
397
- const { BACKEND_IP, BUN_SERVER_PORT } = globalThis;
398
301
  const scheduleReconnect = () => {
399
302
  setTimeout(() => {
400
303
  reconnectDelay = Math.min(reconnectDelay * 2, maxReconnectDelay);
@@ -405,7 +308,7 @@ export const provideDrawAPI = () => {
405
308
  const onOpen = () => {
406
309
  connectionStatus = 'open';
407
310
  reconnectDelay = 1000;
408
- logs.add(`Connected to drawing server at ${BACKEND_IP}:${BUN_SERVER_PORT}`);
311
+ logs.add(`Connected to drawing server at ${BACKEND_IP}:${WS_PORT}`);
409
312
  };
410
313
  const onClose = () => {
411
314
  connectionStatus = 'closed';
@@ -507,9 +410,9 @@ export const provideDrawAPI = () => {
507
410
  invalidate();
508
411
  };
509
412
  const connect = () => {
510
- if (BACKEND_IP && BUN_SERVER_PORT) {
413
+ if (BACKEND_IP && WS_PORT) {
511
414
  const protocol = location.protocol === 'https:' ? 'wss' : 'ws';
512
- ws = new WebSocket(`${protocol}://${BACKEND_IP}:${BUN_SERVER_PORT}/ws`);
415
+ ws = new WebSocket(`${protocol}://${BACKEND_IP}:${WS_PORT}/ws`);
513
416
  ws.onclose = onClose;
514
417
  ws.onerror = onError;
515
418
  ws.onopen = onOpen;
@@ -518,36 +421,9 @@ export const provideDrawAPI = () => {
518
421
  };
519
422
  connect();
520
423
  setContext(key, {
521
- get frames() {
522
- return frames;
523
- },
524
- get points() {
525
- return points;
526
- },
527
- get lines() {
528
- return lines;
529
- },
530
- get meshes() {
531
- return meshes;
532
- },
533
- get poses() {
534
- return poses;
535
- },
536
- get nurbs() {
537
- return nurbs;
538
- },
539
- get models() {
540
- return models;
541
- },
542
424
  get connectionStatus() {
543
425
  return connectionStatus;
544
426
  },
545
- addPoints(worldObject) {
546
- points.push(worldObject);
547
- },
548
- addMesh(worldObject) {
549
- meshes.push(worldObject);
550
- },
551
427
  });
552
428
  };
553
429
  export const useDrawAPI = () => {
@@ -12,7 +12,7 @@ export const provideFramelessComponents = () => {
12
12
  .map((component) => component.name) ?? [];
13
13
  const fragmentComponentsWithNoFrame = [];
14
14
  for (const fragmentComponentName of Object.keys(partConfig.componentNameToFragmentId)) {
15
- if (frames.current.find((worldObject) => worldObject.name === fragmentComponentName)) {
15
+ if (frames.current.find((frame) => frame.transform.referenceFrame === fragmentComponentName)) {
16
16
  continue;
17
17
  }
18
18
  fragmentComponentsWithNoFrame.push(fragmentComponentName);
@@ -1,6 +1,10 @@
1
- import { WorldObject } from '../WorldObject.svelte';
1
+ import { Transform } from '@viamrobotics/sdk';
2
+ interface FrameTransform {
3
+ type: 'machine' | 'config' | 'fragment';
4
+ transform: Transform;
5
+ }
2
6
  interface FramesContext {
3
- current: WorldObject[];
7
+ current: FrameTransform[];
4
8
  getParentFrameOptions: (componentName: string) => string[];
5
9
  }
6
10
  export declare const provideFrames: (partID: () => string) => void;