@viamrobotics/motion-tools 1.16.0 → 1.18.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 (77) hide show
  1. package/dist/attribute.d.ts +3 -2
  2. package/dist/attribute.js +24 -16
  3. package/dist/buf/draw/v1/drawing_pb.d.ts +33 -16
  4. package/dist/buf/draw/v1/drawing_pb.js +35 -17
  5. package/dist/buf/draw/v1/metadata_pb.d.ts +44 -3
  6. package/dist/buf/draw/v1/metadata_pb.js +54 -3
  7. package/dist/buf/draw/v1/scene_pb.d.ts +6 -6
  8. package/dist/buf/draw/v1/scene_pb.js +7 -7
  9. package/dist/buffer.d.ts +54 -45
  10. package/dist/buffer.js +91 -57
  11. package/dist/color.d.ts +1 -2
  12. package/dist/color.js +5 -12
  13. package/dist/components/App.svelte +18 -3
  14. package/dist/components/App.svelte.d.ts +15 -2
  15. package/dist/components/Entities/Arrows/ArrowGroups.svelte +5 -6
  16. package/dist/components/Entities/Arrows/Arrows.svelte +9 -0
  17. package/dist/components/Entities/Entities.svelte +18 -1
  18. package/dist/components/Entities/Frame.svelte +7 -1
  19. package/dist/components/Entities/GLTF.svelte +13 -2
  20. package/dist/components/Entities/Line.svelte +46 -18
  21. package/dist/components/Entities/LineDots.svelte +38 -8
  22. package/dist/components/Entities/LineDots.svelte.d.ts +2 -2
  23. package/dist/components/Entities/LineGeometry.svelte +2 -1
  24. package/dist/components/Entities/LineGeometry.svelte.d.ts +2 -0
  25. package/dist/components/Entities/Mesh.svelte +8 -1
  26. package/dist/components/Entities/Points.svelte +22 -11
  27. package/dist/components/Entities/hooks/useEntityEvents.svelte.js +6 -2
  28. package/dist/components/FileDrop/FileDrop.svelte +5 -1
  29. package/dist/components/KeyboardControls.svelte +2 -10
  30. package/dist/components/PCD.svelte +11 -4
  31. package/dist/components/PCD.svelte.d.ts +3 -1
  32. package/dist/components/SceneProviders.svelte +2 -0
  33. package/dist/components/Selected.svelte +2 -12
  34. package/dist/components/Selection/Ellipse.svelte +1 -0
  35. package/dist/components/Selection/Lasso.svelte +2 -0
  36. package/dist/components/Selection/Tool.svelte +7 -56
  37. package/dist/components/Selection/Tool.svelte.d.ts +2 -2
  38. package/dist/components/Selection/useSelectionPlugin.svelte.d.ts +8 -0
  39. package/dist/components/Selection/useSelectionPlugin.svelte.js +24 -0
  40. package/dist/components/Snapshot.svelte +4 -2
  41. package/dist/components/overlay/AddRelationship.svelte +1 -2
  42. package/dist/components/overlay/AddRelationship.svelte.d.ts +1 -1
  43. package/dist/components/overlay/Details.svelte +12 -12
  44. package/dist/components/overlay/Details.svelte.d.ts +8 -1
  45. package/dist/components/overlay/settings/Settings.svelte +8 -1
  46. package/dist/components/xr/XR.svelte +1 -1
  47. package/dist/draw.d.ts +13 -0
  48. package/dist/draw.js +428 -0
  49. package/dist/ecs/traits.d.ts +31 -13
  50. package/dist/ecs/traits.js +25 -8
  51. package/dist/geometry.js +3 -0
  52. package/dist/hooks/useDrawAPI.svelte.js +61 -24
  53. package/dist/hooks/useDrawService.svelte.d.ts +12 -0
  54. package/dist/hooks/useDrawService.svelte.js +240 -0
  55. package/dist/hooks/usePointcloudObjects.svelte.js +7 -2
  56. package/dist/hooks/usePointclouds.svelte.js +7 -2
  57. package/dist/hooks/useSettings.svelte.d.ts +2 -1
  58. package/dist/hooks/useSettings.svelte.js +1 -1
  59. package/dist/hooks/useWorldState.svelte.js +5 -52
  60. package/dist/index.d.ts +8 -0
  61. package/dist/index.js +9 -0
  62. package/dist/lib.d.ts +2 -0
  63. package/dist/lib.js +2 -0
  64. package/dist/loaders/pcd/index.d.ts +1 -1
  65. package/dist/loaders/pcd/messages.d.ts +2 -2
  66. package/dist/loaders/pcd/worker.inline.d.ts +1 -1
  67. package/dist/loaders/pcd/worker.inline.js +229 -187
  68. package/dist/loaders/pcd/worker.js +2 -2
  69. package/dist/metadata.d.ts +9 -15
  70. package/dist/metadata.js +45 -9
  71. package/dist/plugins/bvh.svelte.js +6 -2
  72. package/dist/snapshot.d.ts +3 -9
  73. package/dist/snapshot.js +11 -204
  74. package/dist/three/InstancedArrows/InstancedArrows.js +3 -2
  75. package/package.json +14 -11
  76. package/dist/components/xr/Hands.svelte +0 -23
  77. package/dist/components/xr/Hands.svelte.d.ts +0 -18
@@ -15,8 +15,8 @@ globalThis.onmessage = async (event) => {
15
15
  */
16
16
  const positions = pcd.geometry.attributes.position?.array ??
17
17
  new Float32Array(0);
18
- const colorsFloat = pcd.geometry.attributes.color?.array ?? null;
19
- const colors = colorsFloat ? new Uint8Array(colorsFloat.length) : null;
18
+ const colorsFloat = pcd.geometry.attributes.color?.array ?? undefined;
19
+ const colors = colorsFloat ? new Uint8Array(colorsFloat.length) : undefined;
20
20
  if (colors) {
21
21
  for (let i = 0, l = colorsFloat.length; i < l; i++) {
22
22
  colors[i] = Math.round(colorsFloat[i] * 255);
@@ -1,22 +1,16 @@
1
1
  import type { PlainMessage, Struct } from '@viamrobotics/sdk';
2
- /**
3
- * Metadata for a Viam `Transform`.
4
- *
5
- * Per the API this can be a struct of any data, so we type this version for
6
- * fields we use and how we expect them to be defined.
7
- */
8
- export type Metadata = {
9
- colors?: Uint8Array<ArrayBuffer>;
10
- };
11
- /** Type guard that checks whether a string is a recognised {@link Metadata} field name. */
12
- export declare const isMetadataKey: (key: string) => key is keyof Metadata;
2
+ import { Metadata as MetadataProto } from './buf/draw/v1/metadata_pb';
3
+ /** Metadata for a `Drawing` or `Transform`. */
4
+ export type Metadata = PlainMessage<MetadataProto>;
5
+ /** Type guard that checks whether a string is a recognised metadata wire key. */
6
+ export declare const isMetadataField: (key: string) => boolean;
13
7
  /**
14
8
  * Extracts typed {@link Metadata} from a proto `Struct` fields map.
15
9
  *
16
- * The `colors` field is expected as a base64-encoded string (the only way to
17
- * represent binary data in a `google.protobuf.Value`), which is decoded into
18
- * a `Uint8Array`.
10
+ * The `colors` and `opacities` fields are base64-encoded strings (the only way
11
+ * to represent binary data in a `google.protobuf.Value`), which are decoded into
12
+ * `Uint8Array`s.
19
13
  *
20
14
  * Unknown keys are silently ignored.
21
15
  */
22
- export declare const parseMetadata: (fields?: PlainMessage<Struct>["fields"]) => Metadata;
16
+ export declare const metadataFromStruct: (fields?: PlainMessage<Struct>["fields"]) => Metadata;
package/dist/metadata.js CHANGED
@@ -1,20 +1,27 @@
1
- /** Type guard that checks whether a string is a recognised {@link Metadata} field name. */
2
- export const isMetadataKey = (key) => {
3
- return key === 'colors';
1
+ import { ColorFormat, Metadata as MetadataProto } from './buf/draw/v1/metadata_pb';
2
+ /** Type guard that checks whether a string is a recognised metadata wire key. */
3
+ export const isMetadataField = (key) => {
4
+ return (key === 'colors' ||
5
+ key === 'color_format' ||
6
+ key === 'opacities' ||
7
+ key === 'show_axes_helper' ||
8
+ key === 'invisible');
4
9
  };
5
10
  /**
6
11
  * Extracts typed {@link Metadata} from a proto `Struct` fields map.
7
12
  *
8
- * The `colors` field is expected as a base64-encoded string (the only way to
9
- * represent binary data in a `google.protobuf.Value`), which is decoded into
10
- * a `Uint8Array`.
13
+ * The `colors` and `opacities` fields are base64-encoded strings (the only way
14
+ * to represent binary data in a `google.protobuf.Value`), which are decoded into
15
+ * `Uint8Array`s.
11
16
  *
12
17
  * Unknown keys are silently ignored.
13
18
  */
14
- export const parseMetadata = (fields = {}) => {
15
- const json = {};
19
+ export const metadataFromStruct = (fields = {}) => {
20
+ const json = {
21
+ colorFormat: ColorFormat.UNSPECIFIED,
22
+ };
16
23
  for (const [k, v] of Object.entries(fields)) {
17
- if (!isMetadataKey(k))
24
+ if (!isMetadataField(k))
18
25
  continue;
19
26
  const unwrappedValue = unwrapValue(v);
20
27
  switch (k) {
@@ -29,6 +36,35 @@ export const parseMetadata = (fields = {}) => {
29
36
  }
30
37
  break;
31
38
  }
39
+ case 'color_format': {
40
+ if (typeof unwrappedValue === 'number') {
41
+ json.colorFormat = unwrappedValue;
42
+ }
43
+ break;
44
+ }
45
+ case 'opacities': {
46
+ if (typeof unwrappedValue === 'string') {
47
+ const binary = atob(unwrappedValue);
48
+ const opacityBytes = new Uint8Array(binary.length);
49
+ for (let i = 0; i < binary.length; i++) {
50
+ opacityBytes[i] = binary.charCodeAt(i);
51
+ }
52
+ json.opacities = opacityBytes;
53
+ }
54
+ break;
55
+ }
56
+ case 'show_axes_helper': {
57
+ if (typeof unwrappedValue === 'boolean') {
58
+ json.showAxesHelper = unwrappedValue;
59
+ }
60
+ break;
61
+ }
62
+ case 'invisible': {
63
+ if (typeof unwrappedValue === 'boolean') {
64
+ json.invisible = unwrappedValue;
65
+ }
66
+ break;
67
+ }
32
68
  }
33
69
  }
34
70
  return json;
@@ -22,7 +22,11 @@ export const bvh = (raycaster, options) => {
22
22
  if (opts.enabled === false) {
23
23
  return;
24
24
  }
25
- if (isInstanceOf(ref, 'Points')) {
25
+ if (isInstanceOf(ref, 'Points') &&
26
+ /**
27
+ * This check is necessary, there are some strange cases where points are coming in from PCDs without any position data
28
+ */
29
+ ref.geometry?.attributes.position) {
26
30
  ref.geometry.computeBoundsTree = computeBoundsTree;
27
31
  ref.geometry.disposeBoundsTree = disposeBoundsTree;
28
32
  ref.raycast = acceleratedRaycast;
@@ -55,7 +59,7 @@ export const bvh = (raycaster, options) => {
55
59
  * (mp) Line2s sort of suck. Their buffer attribute design internally is much different
56
60
  * but they give no indication other than this that they are different.
57
61
  */
58
- ref.geometry.attributes.position) {
62
+ ref.geometry?.attributes.position) {
59
63
  ref.geometry.computeBoundsTree = computeBoundsTree;
60
64
  ref.geometry.disposeBoundsTree = disposeBoundsTree;
61
65
  ref.raycast = acceleratedRaycast;
@@ -4,8 +4,8 @@ import type { Settings } from './hooks/useSettings.svelte';
4
4
  import { type SceneMetadata } from './buf/draw/v1/scene_pb';
5
5
  /**
6
6
  * Merges scene-level metadata (grid, camera, point/line settings) into the
7
- * current viewer settings. Millimetre values from the proto are converted
8
- * to metres.
7
+ * current viewer settings. Millimeter values from the proto are converted
8
+ * to meters.
9
9
  */
10
10
  export declare const applySceneMetadata: (settings: Settings, metadata: SceneMetadata) => Settings;
11
11
  /**
@@ -16,12 +16,6 @@ export declare const applySceneMetadata: (settings: Settings, metadata: SceneMet
16
16
  * depending on the geometry type (arrows, points, line, nurbs, model, or
17
17
  * simple shapes like box/sphere/capsule).
18
18
  *
19
- * @returns The spawned entities — pass them to {@link destroyEntities} to
20
- * clean up before loading a new snapshot.
19
+ * @returns The spawned entities
21
20
  */
22
21
  export declare const spawnSnapshotEntities: (world: World, snapshot: Snapshot) => Entity[];
23
- /**
24
- * Destroys a list of entities that are still alive in the given world.
25
- * Silently skips entities that have already been removed.
26
- */
27
- export declare const destroyEntities: (world: World, entities: Entity[]) => void;
package/dist/snapshot.js CHANGED
@@ -1,19 +1,11 @@
1
- import { Geometry } from '@viamrobotics/sdk';
2
- import { Color, Vector3, Vector4 } from 'three';
3
- import { NURBSCurve } from 'three/addons/curves/NURBSCurve.js';
4
- import {} from './buf/draw/v1/drawing_pb';
5
1
  import { RenderArmModels } from './buf/draw/v1/scene_pb';
6
2
  import { traits } from './ecs';
7
- import { parseMetadata } from './metadata';
8
- import { createBufferGeometry } from './attribute';
9
- import { asColor, asFloat32Array, asOpacity, isPerVertexColors, STRIDE } from './buffer';
10
- import { rgbaToHex } from './color';
11
- const vec3 = new Vector3();
12
- const colorUtil = new Color();
3
+ import { rgbToHex } from './color';
4
+ import { drawDrawing, drawTransform } from './draw';
13
5
  /**
14
6
  * Merges scene-level metadata (grid, camera, point/line settings) into the
15
- * current viewer settings. Millimetre values from the proto are converted
16
- * to metres.
7
+ * current viewer settings. Millimeter values from the proto are converted
8
+ * to meters.
17
9
  */
18
10
  export const applySceneMetadata = (settings, metadata) => {
19
11
  const next = { ...settings };
@@ -33,13 +25,13 @@ export const applySceneMetadata = (settings, metadata) => {
33
25
  next.pointSize = metadata.pointSize / 1000;
34
26
  }
35
27
  if (metadata.pointColor !== undefined) {
36
- next.pointColor = rgbaToHex(metadata.pointColor);
28
+ next.pointColor = rgbToHex(metadata.pointColor);
37
29
  }
38
30
  if (metadata.lineWidth !== undefined) {
39
31
  next.lineWidth = metadata.lineWidth / 1000;
40
32
  }
41
- if (metadata.linePointSize !== undefined) {
42
- next.lineDotSize = metadata.linePointSize / 1000;
33
+ if (metadata.lineDotSize !== undefined) {
34
+ next.lineDotSize = metadata.lineDotSize / 1000;
43
35
  }
44
36
  if (metadata.renderArmModels !== undefined) {
45
37
  next.renderArmModels = getRenderArmModels(metadata.renderArmModels);
@@ -60,33 +52,22 @@ export const applySceneMetadata = (settings, metadata) => {
60
52
  * depending on the geometry type (arrows, points, line, nurbs, model, or
61
53
  * simple shapes like box/sphere/capsule).
62
54
  *
63
- * @returns The spawned entities — pass them to {@link destroyEntities} to
64
- * clean up before loading a new snapshot.
55
+ * @returns The spawned entities
65
56
  */
66
57
  export const spawnSnapshotEntities = (world, snapshot) => {
67
58
  const entities = [];
59
+ const options = { removable: true, showAxesHelper: false };
68
60
  for (const transform of snapshot.transforms) {
69
- entities.push(spawnTransformEntity(world, transform));
61
+ entities.push(drawTransform(world, transform, traits.SnapshotAPI, options));
70
62
  }
71
63
  for (const drawing of snapshot.drawings) {
72
- const drawingEntities = spawnEntitiesFromDrawing(world, drawing);
64
+ const drawingEntities = drawDrawing(world, drawing, traits.SnapshotAPI, options);
73
65
  for (const e of drawingEntities) {
74
66
  entities.push(e);
75
67
  }
76
68
  }
77
69
  return entities;
78
70
  };
79
- /**
80
- * Destroys a list of entities that are still alive in the given world.
81
- * Silently skips entities that have already been removed.
82
- */
83
- export const destroyEntities = (world, entities) => {
84
- for (const entity of entities) {
85
- if (world.has(entity)) {
86
- entity.destroy();
87
- }
88
- }
89
- };
90
71
  const getRenderArmModels = (renderArmModels) => {
91
72
  switch (renderArmModels) {
92
73
  case RenderArmModels.COLLIDERS: {
@@ -101,177 +82,3 @@ const getRenderArmModels = (renderArmModels) => {
101
82
  }
102
83
  }
103
84
  };
104
- const spawnTransformEntity = (world, transform) => {
105
- const entityTraits = [
106
- traits.Name(transform.referenceFrame),
107
- traits.Geometry(transform.physicalObject ?? Geometry.fromJson({})),
108
- traits.Center(transform.physicalObject?.center),
109
- traits.SnapshotAPI,
110
- traits.Removable,
111
- ];
112
- const poseInFrame = transform.poseInObserverFrame;
113
- entityTraits.push(traits.Pose(poseInFrame?.pose), traits.Parent(poseInFrame?.referenceFrame));
114
- if (transform.metadata) {
115
- const metadata = parseMetadata(transform.metadata.fields);
116
- if (metadata.colors)
117
- addColorTraits(entityTraits, metadata.colors);
118
- }
119
- return world.spawn(...entityTraits);
120
- };
121
- const spawnEntitiesFromDrawing = (world, drawing) => {
122
- const entities = [];
123
- const poseInFrame = drawing.poseInObserverFrame;
124
- const parent = poseInFrame?.referenceFrame;
125
- const { geometryType } = drawing.physicalObject ?? {};
126
- if (geometryType?.case === 'arrows') {
127
- const poses = asFloat32Array(geometryType.value.poses);
128
- const colors = drawing.metadata?.colors;
129
- const entityTraits = [
130
- traits.Name(drawing.referenceFrame),
131
- traits.Pose(poseInFrame?.pose),
132
- traits.Positions(poses),
133
- ];
134
- if (parent) {
135
- entityTraits.push(traits.Parent(parent));
136
- }
137
- if (colors) {
138
- entityTraits.push(traits.Colors(colors));
139
- }
140
- const entity = world.spawn(...entityTraits, traits.Arrows({ headAtPose: true }), traits.Instances({ count: poses.length / STRIDE.ARROWS }), traits.SnapshotAPI, traits.Removable);
141
- entities.push(entity);
142
- }
143
- else if (geometryType?.case === 'model') {
144
- const rootEntityTraits = [
145
- traits.Name(drawing.referenceFrame),
146
- traits.Pose(poseInFrame?.pose),
147
- traits.ReferenceFrame,
148
- ];
149
- if (parent) {
150
- rootEntityTraits.push(traits.Parent(parent));
151
- }
152
- const rootEntity = world.spawn(...rootEntityTraits, traits.SnapshotAPI, traits.Removable);
153
- entities.push(rootEntity);
154
- let i = 1;
155
- for (const asset of geometryType.value.assets) {
156
- const entityTraits = [
157
- traits.Name(`${drawing.referenceFrame} model ${i++}`),
158
- traits.Parent(drawing.referenceFrame),
159
- ];
160
- if (geometryType.value.scale) {
161
- entityTraits.push(traits.Scale(geometryType.value.scale));
162
- }
163
- if (asset.content.case === 'url') {
164
- entityTraits.push(traits.GLTF({
165
- source: { url: asset.content.value },
166
- animationName: geometryType.value.animationName ?? '',
167
- }));
168
- }
169
- else if (asset.content.value) {
170
- entityTraits.push(traits.GLTF({
171
- source: { glb: asset.content.value },
172
- animationName: geometryType.value.animationName ?? '',
173
- }));
174
- }
175
- const entity = world.spawn(...entityTraits, traits.SnapshotAPI, traits.Removable);
176
- entities.push(entity);
177
- }
178
- }
179
- else {
180
- const entityTraits = [
181
- traits.Name(drawing.referenceFrame),
182
- traits.Pose(poseInFrame?.pose),
183
- ];
184
- if (parent && parent !== 'world') {
185
- entityTraits.push(traits.Parent);
186
- }
187
- if (drawing.physicalObject?.center) {
188
- entityTraits.push(traits.Center(drawing.physicalObject.center));
189
- }
190
- if (geometryType?.case === 'line') {
191
- const positions = asFloat32Array(geometryType.value.positions);
192
- for (let i = 0, l = positions.length; i < l; i += 1) {
193
- positions[i] *= 0.001;
194
- }
195
- entityTraits.push(traits.LinePositions(positions), traits.LineWidth(geometryType.value.lineWidth), traits.PointSize((geometryType.value.pointSize ?? 0) * 0.001));
196
- // Lines pack exactly 2 colors: [lineColor, pointColor]
197
- const colors = drawing.metadata?.colors;
198
- if (colors && colors.length >= STRIDE.COLORS_RGB) {
199
- const stride = colors.length % STRIDE.COLORS_RGBA === 0 ? STRIDE.COLORS_RGBA : STRIDE.COLORS_RGB;
200
- asColor(colors, colorUtil, 0);
201
- entityTraits.push(traits.Color({ r: colorUtil.r, g: colorUtil.g, b: colorUtil.b }));
202
- if (colors.length >= stride * 2) {
203
- asColor(colors, colorUtil, stride);
204
- entityTraits.push(traits.PointColor({ r: colorUtil.r, g: colorUtil.g, b: colorUtil.b }));
205
- if (stride === STRIDE.COLORS_RGBA) {
206
- entityTraits.push(traits.Opacity(asOpacity(colors, 1, 3)));
207
- }
208
- }
209
- }
210
- }
211
- else if (geometryType?.case === 'points') {
212
- const positions = asFloat32Array(geometryType.value.positions);
213
- for (let i = 0, l = positions.length; i < l; i += 1) {
214
- positions[i] *= 0.001;
215
- }
216
- const colors = drawing.metadata?.colors;
217
- const numPoints = positions.length / STRIDE.POSITIONS;
218
- const vertexColors = colors && isPerVertexColors(colors, numPoints) ? colors : undefined;
219
- const geometry = createBufferGeometry(positions, vertexColors);
220
- entityTraits.push(traits.BufferGeometry(geometry));
221
- if (colors && !vertexColors) {
222
- addColorTraits(entityTraits, colors);
223
- }
224
- if (geometryType.value.pointSize) {
225
- entityTraits.push(traits.PointSize(geometryType.value.pointSize * 0.001));
226
- }
227
- entityTraits.push(traits.Points);
228
- }
229
- else if (geometryType?.case === 'nurbs') {
230
- const { degree = 3, knots: knotsBuffer, weights: weightsBuffer, controlPoints: controlPointsBuffer, } = geometryType.value;
231
- const knots = [...asFloat32Array(knotsBuffer)];
232
- const weights = weightsBuffer
233
- ? [...asFloat32Array(weightsBuffer)]
234
- : [];
235
- const controlPointsArray = [...asFloat32Array(controlPointsBuffer)];
236
- const controlPoints = [];
237
- for (let i = 0, j = 0, l = controlPointsArray.length / STRIDE.NURBS_CONTROL_POINTS; i < l; i += STRIDE.NURBS_CONTROL_POINTS, j += 1) {
238
- vec3
239
- .set(controlPointsArray[0], controlPointsArray[1], controlPointsArray[2])
240
- .multiplyScalar(0.001);
241
- controlPoints.push(new Vector4(vec3.x, vec3.y, vec3.z, weights[j] ?? 0));
242
- }
243
- const curve = new NURBSCurve(degree, knots, controlPoints);
244
- const numPoints = 600;
245
- const points = new Float32Array(numPoints * 3);
246
- const l = numPoints * 3;
247
- for (let i = 0; i < l; i += 3) {
248
- curve.getPointAt(i / (l - 1), vec3);
249
- points[i + 0] = vec3.x;
250
- points[i + 1] = vec3.y;
251
- points[i + 2] = vec3.z;
252
- }
253
- entityTraits.push(traits.LinePositions(points));
254
- const colors = drawing.metadata?.colors;
255
- if (colors) {
256
- addColorTraits(entityTraits, colors);
257
- }
258
- }
259
- else {
260
- // Box, sphere, capsule, and other geometry shapes with a single color
261
- const colors = drawing.metadata?.colors;
262
- if (colors) {
263
- addColorTraits(entityTraits, colors);
264
- }
265
- }
266
- const entity = world.spawn(...entityTraits, traits.SnapshotAPI, traits.Removable);
267
- entities.push(entity);
268
- }
269
- return entities;
270
- };
271
- const addColorTraits = (entityTraits, bytes) => {
272
- asColor(bytes, colorUtil);
273
- entityTraits.push(traits.Color(colorUtil));
274
- const isRgba = bytes.length % STRIDE.COLORS_RGBA === 0;
275
- if (isRgba)
276
- entityTraits.push(traits.Opacity(asOpacity(bytes)));
277
- };
@@ -1,4 +1,5 @@
1
1
  import { Box3, BufferGeometry, Color, DynamicDrawUsage, FrontSide, Group, InstancedBufferAttribute, InstancedInterleavedBuffer, InterleavedBufferAttribute, Material, Mesh, RawShaderMaterial, Vector3, } from 'three';
2
+ import { STRIDE } from '../../buffer';
2
3
  import { computeBoundingBox } from './box';
3
4
  import fragmentShader from './fragment.glsl';
4
5
  import { createHeadGeometry, createShaftGeometry, toInstanced } from './geometry';
@@ -64,8 +65,8 @@ export class InstancedArrows extends Group {
64
65
  instanceDirection,
65
66
  };
66
67
  if (!options.uniformColor) {
67
- const colors = new Uint8Array(this.count * (options?.alpha ? 4 : 3));
68
- const instanceColor = new InstancedBufferAttribute(colors, options?.alpha ? 4 : 3, true);
68
+ const colors = new Uint8Array(this.count * STRIDE.COLORS_RGB);
69
+ const instanceColor = new InstancedBufferAttribute(colors, STRIDE.COLORS_RGB, true);
69
70
  instanceColor.setUsage(DynamicDrawUsage);
70
71
  this.attributes.instanceColor = instanceColor;
71
72
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@viamrobotics/motion-tools",
3
- "version": "1.16.0",
3
+ "version": "1.18.0",
4
4
  "description": "Motion visualization with Viam",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
@@ -25,19 +25,20 @@
25
25
  "@testing-library/jest-dom": "6.8.0",
26
26
  "@testing-library/svelte": "5.2.8",
27
27
  "@testing-library/user-event": "^14.6.1",
28
- "@threlte/core": "8.5.0",
29
- "@threlte/extras": "9.9.0",
30
- "@threlte/rapier": "3.4.0",
31
- "@threlte/xr": "1.4.0",
28
+ "@threlte/core": "8.5.5",
29
+ "@threlte/extras": "9.14.1",
30
+ "@threlte/rapier": "3.4.1",
31
+ "@threlte/xr": "1.5.2",
32
32
  "@types/bun": "1.2.21",
33
33
  "@types/earcut": "^3.0.0",
34
34
  "@types/lodash-es": "4.17.12",
35
- "@types/three": "0.181.0",
35
+ "@types/three": "0.183.1",
36
36
  "@typescript-eslint/eslint-plugin": "8.56.1",
37
37
  "@typescript-eslint/parser": "8.56.1",
38
38
  "@viamrobotics/prime-core": "0.1.5",
39
39
  "@viamrobotics/sdk": "0.58.0",
40
40
  "@viamrobotics/svelte-sdk": "1.0.1",
41
+ "@vitest/browser": "3.2.4",
41
42
  "@vitest/coverage-v8": "^3.2.4",
42
43
  "@zag-js/collapsible": "1.22.1",
43
44
  "@zag-js/floating-panel": "1.22.1",
@@ -47,6 +48,7 @@
47
48
  "@zag-js/toggle-group": "1.22.1",
48
49
  "@zag-js/tree-view": "1.22.1",
49
50
  "camera-controls": "3.1.0",
51
+ "concurrently": "^9.2.1",
50
52
  "esbuild": "^0.27.3",
51
53
  "eslint": "10.0.2",
52
54
  "eslint-config-prettier": "10.1.8",
@@ -55,7 +57,6 @@
55
57
  "eslint-plugin-unicorn": "^63.0.0",
56
58
  "globals": "16.3.0",
57
59
  "idb-keyval": "6.2.2",
58
- "jsdom": "26.1.0",
59
60
  "lucide-svelte": "0.542.0",
60
61
  "prettier": "3.6.2",
61
62
  "prettier-plugin-svelte": "3.4.0",
@@ -66,13 +67,13 @@
66
67
  "svelte-check": "4.4.5",
67
68
  "svelte-virtuallists": "1.4.2",
68
69
  "tailwindcss": "4.1.13",
69
- "three": "0.182.0",
70
+ "three": "0.183.2",
70
71
  "threlte-uikit": "1.2.1",
71
72
  "tsx": "4.20.5",
72
73
  "type-fest": "^5.0.1",
73
74
  "typescript": "5.9.2",
74
75
  "typescript-eslint": "8.56.1",
75
- "vite": "7.1.11",
76
+ "vite": "7.3.2",
76
77
  "vite-plugin-devtools-json": "1.0.0",
77
78
  "vite-plugin-glsl": "^1.5.5",
78
79
  "vite-plugin-mkcert": "1.17.8",
@@ -138,12 +139,14 @@
138
139
  "earcut": "^3.0.2",
139
140
  "filtrex": "^3.1.0",
140
141
  "koota": "0.6.5",
141
- "lodash-es": "4.17.23",
142
+ "lodash-es": "4.18.1",
142
143
  "three-mesh-bvh": "^0.9.8",
143
144
  "uuid-tool": "^2.0.3"
144
145
  },
145
146
  "scripts": {
146
- "dev": "tsx server/check-bun && bun run server/server.ts",
147
+ "dev": "pnpm dev:bun",
148
+ "dev:bun": "tsx server/check-bun && bun run server/server.ts",
149
+ "dev:next": "concurrently \"pnpm dev:bun\" \"go run cmd/draw-server/main.go -port 3030\"",
147
150
  "dev:https": "vite dev -- --https",
148
151
  "build": "vite build && npm run prepack",
149
152
  "build:workers": "node scripts/build-workers.js",
@@ -1,23 +0,0 @@
1
- <script lang="ts">
2
- import { Hand } from '@threlte/xr'
3
-
4
- const onpinchstart = () => {
5
- // Pinch started
6
- }
7
-
8
- const onpinchend = () => {
9
- // Pinch ended
10
- }
11
- </script>
12
-
13
- <Hand
14
- left
15
- {onpinchstart}
16
- {onpinchend}
17
- ></Hand>
18
-
19
- <Hand
20
- right
21
- {onpinchstart}
22
- {onpinchend}
23
- ></Hand>
@@ -1,18 +0,0 @@
1
- interface $$__sveltets_2_IsomorphicComponent<Props extends Record<string, any> = any, Events extends Record<string, any> = any, Slots extends Record<string, any> = any, Exports = {}, Bindings = string> {
2
- new (options: import('svelte').ComponentConstructorOptions<Props>): import('svelte').SvelteComponent<Props, Events, Slots> & {
3
- $$bindings?: Bindings;
4
- } & Exports;
5
- (internal: unknown, props: {
6
- $$events?: Events;
7
- $$slots?: Slots;
8
- }): Exports & {
9
- $set?: any;
10
- $on?: any;
11
- };
12
- z_$$bindings?: Bindings;
13
- }
14
- declare const Hands: $$__sveltets_2_IsomorphicComponent<Record<string, never>, {
15
- [evt: string]: CustomEvent<any>;
16
- }, {}, {}, string>;
17
- type Hands = InstanceType<typeof Hands>;
18
- export default Hands;