@viamrobotics/motion-tools 0.5.3 → 0.5.4

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.
@@ -1,5 +1,5 @@
1
1
  import type { Geometry, Pose } from '@viamrobotics/sdk';
2
- import { BatchedMesh, Box3, Object3D, Vector3 } from 'three';
2
+ import { BatchedMesh, Box3, Object3D, Vector3, type ColorRepresentation } from 'three';
3
3
  export type PointsGeometry = {
4
4
  case: 'points';
5
5
  value: Float32Array<ArrayBuffer>;
@@ -11,11 +11,12 @@ export type LinesGeometry = {
11
11
  export type Geometries = Geometry['geometryType'] | PointsGeometry | LinesGeometry;
12
12
  export type Metadata = {
13
13
  colors?: Float32Array;
14
- color?: string;
14
+ color?: ColorRepresentation;
15
15
  gltf?: {
16
16
  scene: Object3D;
17
17
  };
18
18
  points?: Vector3[];
19
+ pointSize?: number;
19
20
  batched?: {
20
21
  id: number;
21
22
  object: BatchedMesh;
@@ -20,7 +20,7 @@
20
20
 
21
21
  createPartIDContext(() => partID)
22
22
 
23
- let root = $state<HTMLElement>()
23
+ let root = $state.raw<HTMLElement>()
24
24
  </script>
25
25
 
26
26
  <div
@@ -21,7 +21,6 @@
21
21
 
22
22
  const object = $derived(focusedObject.current ?? selectedObject.current)
23
23
  const object3d = $derived(focusedObject3d.current ?? selectedObject3d.current)
24
-
25
24
  const worldPosition = $derived(object3d?.getWorldPosition(new Vector3()))
26
25
  const worldQuaternion = $derived(object3d?.getWorldQuaternion(new Quaternion()))
27
26
  const worldOrientation = $derived(
@@ -12,16 +12,18 @@
12
12
  const vec = new Vector3()
13
13
 
14
14
  let center = $state.raw<[number, number, number]>([0, 0, 0])
15
+ let size = $state.raw<[number, number, number]>([0, 0, 0])
15
16
 
16
17
  $effect(() => {
17
18
  if (object3d) {
18
19
  box.setFromObject(object3d)
20
+ size = box.getSize(vec).toArray()
19
21
  center = box.getCenter(vec).toArray()
20
22
  }
21
23
  })
22
24
  </script>
23
25
 
24
- <Camera position={[2, 0, 0]}>
26
+ <Camera position={[size[0], 0, 0]}>
25
27
  <TrackballControls target={center}>
26
28
  <Gizmo />
27
29
  </TrackballControls>
@@ -20,11 +20,13 @@
20
20
  const s = $derived(keys.has('s'))
21
21
  const a = $derived(keys.has('a'))
22
22
  const d = $derived(keys.has('d'))
23
+ const r = $derived(keys.has('r'))
24
+ const f = $derived(keys.has('f'))
23
25
  const up = $derived(keys.has('arrowup'))
24
26
  const left = $derived(keys.has('arrowleft'))
25
27
  const down = $derived(keys.has('arrowdown'))
26
28
  const right = $derived(keys.has('arrowright'))
27
- const any = $derived(w || s || a || d || up || left || down || right)
29
+ const any = $derived(w || s || a || d || r || f || up || left || down || right)
28
30
 
29
31
  const { start, stop } = useTask(
30
32
  (delta) => {
@@ -46,6 +48,14 @@
46
48
  cameraControls.forward(-0.01 * dt, true)
47
49
  }
48
50
 
51
+ if (r) {
52
+ cameraControls.dolly(0.01 * dt, true)
53
+ }
54
+
55
+ if (f) {
56
+ cameraControls.dolly(-0.01 * dt, true)
57
+ }
58
+
49
59
  if (left) {
50
60
  cameraControls.rotate(-0.1 * MathUtils.DEG2RAD * dt, 0, true)
51
61
  }
@@ -1,6 +1,7 @@
1
1
  <script lang="ts">
2
+ import { Points, BufferAttribute, BufferGeometry, PointsMaterial } from 'three'
3
+
2
4
  import { T } from '@threlte/core'
3
- import { Points, BufferAttribute, BufferGeometry, Color, PointsMaterial } from 'three'
4
5
  import type { WorldObject } from '../WorldObject'
5
6
  import { useObjectEvents } from '../hooks/useObjectEvents.svelte'
6
7
  import { meshBounds } from '@threlte/extras'
@@ -12,18 +13,15 @@
12
13
 
13
14
  let { object }: Props = $props()
14
15
 
15
- const points = new Points()
16
- const geometry = new BufferGeometry()
17
- const material = new PointsMaterial({
18
- size: 0.01,
19
- color: new Color('#888888'),
20
- })
21
-
22
16
  const colors = $derived(object.metadata.colors)
23
17
  const positions = $derived(object.geometry?.value ?? new Float32Array())
24
18
 
25
- $effect(() => {
26
- material.vertexColors = colors !== undefined
19
+ const points = new Points()
20
+ const geometry = new BufferGeometry()
21
+ const material = new PointsMaterial()
22
+
23
+ $effect.pre(() => {
24
+ material.size = object.metadata.pointSize ?? 0.01
27
25
  })
28
26
 
29
27
  $effect.pre(() => {
@@ -31,8 +29,13 @@
31
29
  })
32
30
 
33
31
  $effect.pre(() => {
32
+ material.vertexColors = colors !== undefined
33
+ material.color.set(colors ? 0xffffff : (object.metadata.color ?? '#888888'))
34
+
35
+ material.toneMapped = false
34
36
  if (colors) {
35
37
  geometry.setAttribute('color', new BufferAttribute(colors, 3))
38
+ geometry.attributes.color.needsUpdate = true
36
39
  }
37
40
  })
38
41
 
@@ -82,6 +82,8 @@
82
82
  plane="xy"
83
83
  sectionColor="#333"
84
84
  infiniteGrid
85
+ cellSize={0.5}
86
+ sectionSize={10}
85
87
  fadeOrigin={new Vector3()}
86
88
  fadeDistance={25}
87
89
  />
@@ -39,7 +39,6 @@
39
39
  providePointclouds(() => partID.current)
40
40
  provideMotionClient(() => partID.current)
41
41
  provideObjects()
42
-
43
42
  const { focus } = provideSelection()
44
43
  </script>
45
44
 
@@ -18,9 +18,6 @@
18
18
  class: className = '',
19
19
  onclick,
20
20
  }: Props = $props()
21
-
22
- const activeClasses = 'z-10 border-gray-5 bg-white text-gray-8'
23
- const inactiveClasses = 'bg-light border-medium text-disabled'
24
21
  </script>
25
22
 
26
23
  <Tooltip
@@ -28,7 +25,11 @@
28
25
  location="bottom"
29
26
  >
30
27
  <label
31
- class={[className, 'relative block border', active ? activeClasses : inactiveClasses]}
28
+ class={[
29
+ className,
30
+ 'relative block border',
31
+ active ? 'border-gray-5 text-gray-8 z-10 bg-white' : 'bg-light border-medium text-disabled',
32
+ ]}
32
33
  aria-describedby={tooltipID}
33
34
  >
34
35
  <button
@@ -6,14 +6,14 @@ import { observe } from '@threlte/core';
6
6
  import { useLogs } from './useLogs.svelte';
7
7
  const key = Symbol('frames-context');
8
8
  export const provideFrames = (partID) => {
9
+ const client = useRobotClient(partID);
10
+ const machineStatus = useMachineStatus(partID);
11
+ const logs = useLogs();
9
12
  const refreshRates = useRefreshRates();
10
13
  if (!refreshRates.has('Frames')) {
11
14
  refreshRates.set('Frames', 1);
12
15
  }
13
- const logs = useLogs();
14
- const client = useRobotClient(partID);
15
16
  const query = createRobotQuery(client, 'frameSystemConfig');
16
- const machineStatus = useMachineStatus(partID);
17
17
  const revision = $derived(machineStatus.current?.config.revision);
18
18
  const shouldFetch = $derived(refreshRates.get('Frames') === 1);
19
19
  observe.pre(() => [revision], () => {
@@ -1,26 +1,25 @@
1
1
  import { Object3D } from 'three';
2
2
  import type { WorldObject } from '../WorldObject';
3
- type UUID = string;
4
3
  interface SelectionContext {
5
- readonly current: UUID | undefined;
6
- set(value?: UUID): void;
4
+ readonly current: string | undefined;
5
+ set(value?: string): void;
7
6
  }
8
7
  interface FocusContext {
9
- readonly current: UUID | undefined;
10
- set(value?: UUID): void;
8
+ readonly current: string | undefined;
9
+ set(value?: string): void;
11
10
  }
12
11
  export declare const provideSelection: () => {
13
12
  selection: {
14
13
  readonly current: string | undefined;
15
- set(value?: UUID): void;
14
+ set(value?: string): void;
16
15
  };
17
16
  focus: {
18
17
  readonly current: string | undefined;
19
- set(value?: UUID): void;
18
+ set(value?: string): void;
20
19
  };
21
20
  hover: {
22
21
  readonly current: string | undefined;
23
- set(value?: UUID): void;
22
+ set(value?: string): void;
24
23
  };
25
24
  };
26
25
  export declare const useSelected: () => SelectionContext;
@@ -1,5 +1,5 @@
1
1
  import { getContext, setContext } from 'svelte';
2
- import { Vector3, Vector4 } from 'three';
2
+ import { Color, Vector3, Vector4 } from 'three';
3
3
  import { NURBSCurve } from 'three/addons/curves/NURBSCurve.js';
4
4
  import { parsePcdInWorker } from '../loaders/pcd';
5
5
  import { GLTFLoader } from 'three/examples/jsm/loaders/GLTFLoader.js';
@@ -28,8 +28,12 @@ export const provideShapes = () => {
28
28
  const nurbs = $state([]);
29
29
  const models = $state([]);
30
30
  let connectionStatus = $state('connecting');
31
+ const color = new Color();
32
+ const direction = new Vector3();
33
+ const origin = new Vector3();
34
+ const vec3 = new Vector3();
31
35
  const loader = new GLTFLoader();
32
- const addPcd = async (data) => {
36
+ const addPCD = async (data) => {
33
37
  const buffer = await data.arrayBuffer();
34
38
  const { positions, colors } = await parsePcdInWorker(new Uint8Array(buffer));
35
39
  points.push(new WorldObject(`points ${++pointsIndex}`, undefined, undefined, {
@@ -70,23 +74,41 @@ export const provideShapes = () => {
70
74
  const object = new WorldObject(data.name, data.pose, data.parent, { case: 'line', value: new Float32Array() }, { color, points: curve.getPoints(200) });
71
75
  nurbs.push(object);
72
76
  };
73
- const direction = new Vector3();
74
- const origin = new Vector3();
75
- const vec3 = new Vector3();
76
77
  const batchedArrow = new BatchedArrow();
77
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
78
- const addPoses = (nextPoses, colors, arrowHeadAtPose) => {
79
- for (let i = 0, l = nextPoses.length; i < l; i += 1) {
80
- const pose = nextPoses[i];
81
- const length = 0.1;
82
- direction.set(pose.oX ?? 0, pose.oY ?? 0, pose.oZ ?? 0);
83
- origin.set((pose.x ?? 0) / 1000, (pose.y ?? 0) / 1000, (pose.z ?? 0) / 1000);
84
- if (arrowHeadAtPose) {
78
+ const addPoses = async (data) => {
79
+ const buffer = await data.arrayBuffer();
80
+ const view = new DataView(buffer);
81
+ let offset = 0;
82
+ function readFloat32() {
83
+ const val = view.getFloat32(offset, true); // true = little-endian
84
+ offset += 4;
85
+ return val;
86
+ }
87
+ // Read counts
88
+ const nPoints = readFloat32();
89
+ const nColors = readFloat32();
90
+ const arrowHeadAtPose = readFloat32();
91
+ // Read positions
92
+ const nextPoses = new Float32Array(nPoints * 6);
93
+ for (let i = 0; i < nPoints * 6; i++) {
94
+ nextPoses[i] = readFloat32();
95
+ }
96
+ // Read raw colors
97
+ const colors = new Float32Array(nColors * 3);
98
+ for (let i = 0; i < nColors * 3; i++) {
99
+ colors[i] = readFloat32();
100
+ }
101
+ const length = 0.1;
102
+ for (let i = 0, j = 0, l = nextPoses.length; i < l; i += 6, j += 3) {
103
+ origin.set(nextPoses[i], nextPoses[i + 1], nextPoses[i + 2]).multiplyScalar(0.001);
104
+ direction.set(nextPoses[i + 3], nextPoses[i + 4], nextPoses[i + 5]);
105
+ if (arrowHeadAtPose === 1) {
85
106
  // Compute the base position so the arrow ends at the origin
86
107
  origin.sub(vec3.copy(direction).multiplyScalar(length));
87
108
  }
88
- const arrowId = batchedArrow.addArrow(direction, origin, length, colors[i]);
89
- poses.push(new WorldObject(`pose ${++poseIndex}`, pose, undefined, undefined, {
109
+ color.set(colors[j], colors[j + 1], colors[j + 2]);
110
+ const arrowId = batchedArrow.addArrow(direction, origin, length, color);
111
+ poses.push(new WorldObject(`pose ${++poseIndex}`, undefined, undefined, undefined, {
90
112
  getBoundingBoxAt(box3) {
91
113
  return batchedArrow.getBoundingBoxAt(arrowId, box3);
92
114
  },
@@ -97,6 +119,66 @@ export const provideShapes = () => {
97
119
  }));
98
120
  }
99
121
  };
122
+ const addPoints = async (data) => {
123
+ const buffer = await data.arrayBuffer();
124
+ const view = new DataView(buffer);
125
+ let offset = 0;
126
+ function readFloat32() {
127
+ const val = view.getFloat32(offset, true); // true = little-endian
128
+ offset += 4;
129
+ return val;
130
+ }
131
+ // Read label length
132
+ const labelLen = readFloat32();
133
+ let label = '';
134
+ for (let i = 0; i < labelLen; i++) {
135
+ label += String.fromCharCode(readFloat32());
136
+ }
137
+ // Read counts
138
+ const nPoints = readFloat32();
139
+ const nColors = readFloat32();
140
+ // Read default color
141
+ const r = readFloat32();
142
+ const g = readFloat32();
143
+ const b = readFloat32();
144
+ // Read positions
145
+ const positions = new Float32Array(nPoints * 3);
146
+ for (let i = 0; i < nPoints * 3; i++) {
147
+ positions[i] = readFloat32();
148
+ }
149
+ const getColors = () => {
150
+ // Read raw colors
151
+ const rawColors = new Float32Array(nColors * 3);
152
+ for (let i = 0; i < nColors * 3; i++) {
153
+ rawColors[i] = readFloat32();
154
+ }
155
+ const colors = new Float32Array(nPoints * 3);
156
+ colors.set(rawColors);
157
+ // Cover the gap for any points not colored
158
+ for (let i = nColors; i < nPoints; i++) {
159
+ const offset = i * 3;
160
+ colors[offset] = r;
161
+ colors[offset + 1] = g;
162
+ colors[offset + 2] = b;
163
+ }
164
+ return colors;
165
+ };
166
+ const pointSize = 0.01;
167
+ const metadata = nColors > 0
168
+ ? {
169
+ colors: getColors(),
170
+ color: new Color(r, g, b).convertLinearToSRGB(),
171
+ pointSize,
172
+ }
173
+ : {
174
+ color: new Color(r, g, b).convertLinearToSRGB(),
175
+ pointSize,
176
+ };
177
+ points.push(new WorldObject(label ?? `points ${++pointsIndex}`, undefined, undefined, {
178
+ case: 'points',
179
+ value: positions,
180
+ }, metadata));
181
+ };
100
182
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
101
183
  const addGeometries = (geometries, colors, parent) => {
102
184
  let i = 0;
@@ -105,6 +187,14 @@ export const provideShapes = () => {
105
187
  i += 1;
106
188
  }
107
189
  };
190
+ const addGLTF = async (data) => {
191
+ const buffer = await data.arrayBuffer();
192
+ const blob = new Blob([buffer], { type: 'model/gltf-binary' });
193
+ const url = URL.createObjectURL(blob);
194
+ const gltf = await loader.loadAsync(url);
195
+ models.push(new WorldObject(gltf.scene.name, undefined, undefined, undefined, { gltf }));
196
+ URL.revokeObjectURL(url);
197
+ };
108
198
  const remove = (names) => {
109
199
  let index = -1;
110
200
  for (const name of names) {
@@ -153,20 +243,12 @@ export const provideShapes = () => {
153
243
  let metadata = undefined;
154
244
  const handleMetadata = (data) => {
155
245
  const json = tryParse(data);
156
- if ('ext' in json) {
246
+ if ('type' in json) {
157
247
  metadata = json;
158
248
  return true;
159
249
  }
160
250
  return false;
161
251
  };
162
- const loadGLTF = async (data) => {
163
- const buffer = await data.arrayBuffer();
164
- const blob = new Blob([buffer], { type: 'model/gltf-binary' });
165
- const url = URL.createObjectURL(blob);
166
- const gltf = await loader.loadAsync(url);
167
- models.push(new WorldObject(gltf.scene.name, undefined, undefined, undefined, { gltf }));
168
- URL.revokeObjectURL(url);
169
- };
170
252
  const { BACKEND_IP, BUN_SERVER_PORT } = globalThis;
171
253
  const scheduleReconnect = () => {
172
254
  setTimeout(() => {
@@ -196,13 +278,21 @@ export const provideShapes = () => {
196
278
  }
197
279
  }
198
280
  if (typeof event.data === 'object' && 'arrayBuffer' in event.data) {
199
- if (metadata?.ext === 'glb') {
200
- loadGLTF(event.data);
281
+ if (!metadata) {
282
+ return console.error('metadata is undefined');
201
283
  }
202
- else if (metadata?.ext === 'pcd') {
203
- addPcd(event.data);
284
+ if (metadata.type === 'glb') {
285
+ return addGLTF(event.data);
286
+ }
287
+ else if (metadata.type === 'pcd') {
288
+ return addPCD(event.data);
289
+ }
290
+ else if (metadata.type === 'points') {
291
+ return addPoints(event.data);
292
+ }
293
+ else if (metadata.type === 'poses') {
294
+ return addPoses(event.data);
204
295
  }
205
- return;
206
296
  }
207
297
  const data = tryParse(event.data);
208
298
  if (!data)
@@ -219,9 +309,6 @@ export const provideShapes = () => {
219
309
  if ('Knots' in data) {
220
310
  return addNurbs(data, data.Color);
221
311
  }
222
- if ('poses' in data) {
223
- return addPoses(data.poses, data.colors, data.arrowHeadAtPose);
224
- }
225
312
  if ('geometry' in data) {
226
313
  addGeometry(data.geometry, data.color);
227
314
  }
@@ -1,4 +1,4 @@
1
- import { BatchedMesh, MeshBasicMaterial, Object3D, Vector3, Box3, Matrix4 } from 'three';
1
+ import { BatchedMesh, MeshBasicMaterial, Object3D, Vector3, Box3, Matrix4, type ColorRepresentation } from 'three';
2
2
  interface Arrow {
3
3
  shaftId: number;
4
4
  headId: number;
@@ -17,7 +17,7 @@ export declare class BatchedArrow {
17
17
  shaftWidth?: number | undefined;
18
18
  material?: MeshBasicMaterial | undefined;
19
19
  });
20
- addArrow(dir: Vector3, origin: Vector3, length?: number, color?: string): number;
20
+ addArrow(dir: Vector3, origin: Vector3, length?: number, color?: ColorRepresentation): number;
21
21
  getArrowId(instanceId: number): number | undefined;
22
22
  getBoundingBoxAt(arrowId: number, target: Box3): Box3 | undefined;
23
23
  removeArrow(arrowId: number): void;
@@ -6,6 +6,7 @@ const box1 = new Box3();
6
6
  const box2 = new Box3();
7
7
  const mat4_1 = new Matrix4();
8
8
  const mat4_2 = new Matrix4();
9
+ const col = new Color();
9
10
  let index = 0;
10
11
  export class BatchedArrow {
11
12
  batchedMesh;
@@ -57,7 +58,7 @@ export class BatchedArrow {
57
58
  const coneMatrix = this._computeTransform(coneOrigin, dir, headLength, headWidth * 4);
58
59
  this.batchedMesh.setMatrixAt(headId, coneMatrix);
59
60
  if (color) {
60
- const col = new Color(color);
61
+ col.set(color);
61
62
  this.batchedMesh.setColorAt(shaftId, col);
62
63
  this.batchedMesh.setColorAt(headId, col);
63
64
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@viamrobotics/motion-tools",
3
- "version": "0.5.3",
3
+ "version": "0.5.4",
4
4
  "description": "Motion visualization with Viam",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
@@ -8,65 +8,65 @@
8
8
  "@ag-grid-community/client-side-row-model": "32.3.5",
9
9
  "@ag-grid-community/core": "32.3.5",
10
10
  "@ag-grid-community/styles": "32.3.5",
11
- "@changesets/cli": "2.29.4",
11
+ "@changesets/cli": "2.29.5",
12
12
  "@dimforge/rapier3d-compat": "0.17.3",
13
- "@eslint/compat": "1.3.0",
14
- "@eslint/js": "9.28.0",
15
- "@playwright/test": "1.53.0",
13
+ "@eslint/compat": "1.3.1",
14
+ "@eslint/js": "9.29.0",
15
+ "@playwright/test": "1.53.1",
16
16
  "@skeletonlabs/skeleton": "3.1.3",
17
17
  "@skeletonlabs/skeleton-svelte": "1.2.3",
18
18
  "@sveltejs/adapter-static": "3.0.8",
19
- "@sveltejs/kit": "2.21.4",
20
- "@sveltejs/package": "2.3.11",
19
+ "@sveltejs/kit": "2.22.2",
20
+ "@sveltejs/package": "2.3.12",
21
21
  "@sveltejs/vite-plugin-svelte": "5.1.0",
22
22
  "@tailwindcss/forms": "0.5.10",
23
- "@tailwindcss/vite": "4.1.10",
24
- "@tanstack/svelte-query": "5.80.6",
25
- "@tanstack/svelte-query-devtools": "5.80.6",
23
+ "@tailwindcss/vite": "4.1.11",
24
+ "@tanstack/svelte-query": "5.81.2",
25
+ "@tanstack/svelte-query-devtools": "5.81.2",
26
26
  "@testing-library/jest-dom": "6.6.3",
27
27
  "@testing-library/svelte": "5.2.8",
28
- "@threlte/core": "8.0.4",
28
+ "@threlte/core": "8.0.5",
29
29
  "@threlte/extras": "9.4.0",
30
30
  "@threlte/rapier": "3.1.4",
31
- "@threlte/xr": "1.0.6",
32
- "@types/bun": "1.2.15",
31
+ "@threlte/xr": "1.0.8",
32
+ "@types/bun": "1.2.17",
33
33
  "@types/lodash-es": "4.17.12",
34
34
  "@types/three": "0.177.0",
35
- "@typescript-eslint/eslint-plugin": "8.34.0",
36
- "@typescript-eslint/parser": "8.34.0",
35
+ "@typescript-eslint/eslint-plugin": "8.35.0",
36
+ "@typescript-eslint/parser": "8.35.0",
37
37
  "@viamrobotics/prime-core": "0.1.5",
38
- "@viamrobotics/sdk": "0.43.0",
39
- "@viamrobotics/svelte-sdk": "0.3.3",
38
+ "@viamrobotics/sdk": "0.44.0",
39
+ "@viamrobotics/svelte-sdk": "0.4.0",
40
40
  "@vitejs/plugin-basic-ssl": "2.0.0",
41
- "@zag-js/svelte": "1.15.2",
42
- "@zag-js/tree-view": "1.15.2",
41
+ "@zag-js/svelte": "1.17.1",
42
+ "@zag-js/tree-view": "1.17.1",
43
43
  "camera-controls": "2.10.1",
44
- "eslint": "9.28.0",
44
+ "eslint": "9.29.0",
45
45
  "eslint-config-prettier": "10.1.5",
46
- "eslint-plugin-svelte": "3.9.2",
46
+ "eslint-plugin-svelte": "3.10.0",
47
47
  "globals": "16.2.0",
48
48
  "idb-keyval": "6.2.2",
49
49
  "jsdom": "26.1.0",
50
50
  "lodash-es": "4.17.21",
51
- "lucide-svelte": "0.514.0",
52
- "prettier": "3.5.3",
51
+ "lucide-svelte": "0.523.0",
52
+ "prettier": "3.6.1",
53
53
  "prettier-plugin-svelte": "3.4.0",
54
- "prettier-plugin-tailwindcss": "0.6.12",
54
+ "prettier-plugin-tailwindcss": "0.6.13",
55
55
  "publint": "0.3.12",
56
- "runed": "0.28.0",
57
- "svelte": "5.33.19",
58
- "svelte-check": "4.2.1",
56
+ "runed": "0.29.1",
57
+ "svelte": "5.34.8",
58
+ "svelte-check": "4.2.2",
59
59
  "svelte-virtuallists": "1.4.2",
60
- "tailwindcss": "4.1.10",
60
+ "tailwindcss": "4.1.11",
61
61
  "three": "0.177.0",
62
- "threlte-uikit": "1.1.0",
63
- "tsx": "4.20.1",
62
+ "threlte-uikit": "1.2.0",
63
+ "tsx": "4.20.3",
64
64
  "typescript": "5.8.3",
65
- "typescript-eslint": "8.34.0",
65
+ "typescript-eslint": "8.35.0",
66
66
  "vite": "6.3.5",
67
67
  "vite-plugin-devtools-json": "0.2.0",
68
68
  "vite-plugin-mkcert": "1.17.8",
69
- "vitest": "3.2.3"
69
+ "vitest": "3.2.4"
70
70
  },
71
71
  "peerDependencies": {
72
72
  "@dimforge/rapier3d-compat": ">=0.17",