@viamrobotics/motion-tools 0.19.2 → 1.0.3

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 (150) 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 +38 -22
  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 +80 -0
  14. package/dist/components/{WorldObjects.svelte.d.ts → Entities.svelte.d.ts} +3 -3
  15. package/dist/components/FileDrop/FileDrop.svelte +96 -0
  16. package/dist/components/FileDrop/FileDrop.svelte.d.ts +4 -0
  17. package/dist/components/FileDrop/file-dropper.d.ts +36 -0
  18. package/dist/components/FileDrop/file-dropper.js +6 -0
  19. package/dist/components/FileDrop/file-names.d.ts +27 -0
  20. package/dist/components/FileDrop/file-names.js +85 -0
  21. package/dist/components/FileDrop/pcd-dropper.d.ts +2 -0
  22. package/dist/components/FileDrop/pcd-dropper.js +27 -0
  23. package/dist/components/FileDrop/ply-dropper.d.ts +2 -0
  24. package/dist/components/FileDrop/ply-dropper.js +27 -0
  25. package/dist/components/FileDrop/snapshot-dropper.d.ts +2 -0
  26. package/dist/components/FileDrop/snapshot-dropper.js +96 -0
  27. package/dist/components/FileDrop/useFileDrop.svelte.d.ts +9 -0
  28. package/dist/components/FileDrop/useFileDrop.svelte.js +97 -0
  29. package/dist/components/Focus.svelte +2 -3
  30. package/dist/components/Frame.svelte +41 -22
  31. package/dist/components/Frame.svelte.d.ts +4 -6
  32. package/dist/components/GLTF.svelte +36 -0
  33. package/dist/components/GLTF.svelte.d.ts +11 -0
  34. package/dist/components/Geometry2.svelte +206 -0
  35. package/dist/components/Geometry2.svelte.d.ts +18 -0
  36. package/dist/components/KeyboardControls.svelte +3 -3
  37. package/dist/components/Line.svelte +15 -14
  38. package/dist/components/Line.svelte.d.ts +2 -2
  39. package/dist/components/LiveUpdatesBanner.svelte +51 -15
  40. package/dist/components/MeasureTool.svelte +4 -5
  41. package/dist/components/Pointcloud.svelte +27 -14
  42. package/dist/components/Pointcloud.svelte.d.ts +2 -2
  43. package/dist/components/PointerMissBox.svelte +3 -3
  44. package/dist/components/Pose.svelte +31 -6
  45. package/dist/components/Pose.svelte.d.ts +2 -2
  46. package/dist/components/Scene.svelte +7 -6
  47. package/dist/components/SceneProviders.svelte +0 -6
  48. package/dist/components/Selected.svelte +22 -16
  49. package/dist/components/StaticGeometries.svelte +51 -27
  50. package/dist/components/Tree/Tree.svelte +51 -38
  51. package/dist/components/Tree/Tree.svelte.d.ts +3 -4
  52. package/dist/components/Tree/TreeContainer.svelte +75 -40
  53. package/dist/components/Tree/Widgets.svelte +2 -5
  54. package/dist/components/Tree/buildTree.d.ts +7 -6
  55. package/dist/components/Tree/buildTree.js +22 -41
  56. package/dist/components/__tests__/__fixtures__/entity.d.ts +2 -0
  57. package/dist/components/__tests__/__fixtures__/entity.js +20 -0
  58. package/dist/components/__tests__/__fixtures__/resource.d.ts +17 -0
  59. package/dist/components/__tests__/__fixtures__/resource.js +13 -0
  60. package/dist/components/dashboard/Dashboard.svelte +5 -3
  61. package/dist/components/dashboard/Dashboard.svelte.d.ts +7 -2
  62. package/dist/components/widgets/ArmPositions.svelte +19 -7
  63. package/dist/draw/v1/drawing_pb.d.ts +341 -0
  64. package/dist/draw/v1/drawing_pb.js +417 -0
  65. package/dist/draw/v1/metadata_pb.d.ts +23 -0
  66. package/dist/draw/v1/metadata_pb.js +39 -0
  67. package/dist/draw/v1/scene_pb.d.ts +230 -0
  68. package/dist/draw/v1/scene_pb.js +298 -0
  69. package/dist/draw/v1/snapshot_pb.d.ts +42 -0
  70. package/dist/draw/v1/snapshot_pb.js +61 -0
  71. package/dist/draw/v1/transforms_pb.d.ts +23 -0
  72. package/dist/draw/v1/transforms_pb.js +39 -0
  73. package/dist/ecs/index.d.ts +4 -0
  74. package/dist/ecs/index.js +4 -0
  75. package/dist/ecs/traits.d.ts +132 -0
  76. package/dist/ecs/traits.js +85 -0
  77. package/dist/ecs/useQuery.svelte.d.ts +4 -0
  78. package/dist/ecs/useQuery.svelte.js +49 -0
  79. package/dist/ecs/useTrait.svelte.d.ts +19 -0
  80. package/dist/ecs/useTrait.svelte.js +40 -0
  81. package/dist/ecs/useWorld.d.ts +4 -0
  82. package/dist/ecs/useWorld.js +10 -0
  83. package/dist/geometry.js +6 -6
  84. package/dist/hooks/__tests__/fixtures/ResizableTestWrapper.svelte +41 -0
  85. package/dist/hooks/__tests__/fixtures/ResizableTestWrapper.svelte.d.ts +6 -0
  86. package/dist/hooks/use3DModels.svelte.js +6 -4
  87. package/dist/hooks/useDrawAPI.svelte.d.ts +0 -10
  88. package/dist/hooks/useDrawAPI.svelte.js +143 -267
  89. package/dist/hooks/useFramelessComponents.svelte.js +1 -1
  90. package/dist/hooks/useFrames.svelte.d.ts +6 -2
  91. package/dist/hooks/useFrames.svelte.js +123 -19
  92. package/dist/hooks/useGeometries.svelte.d.ts +0 -2
  93. package/dist/hooks/useGeometries.svelte.js +49 -25
  94. package/dist/hooks/useObjectEvents.svelte.d.ts +3 -2
  95. package/dist/hooks/useObjectEvents.svelte.js +11 -7
  96. package/dist/hooks/usePartConfig.svelte.d.ts +1 -1
  97. package/dist/hooks/usePartConfig.svelte.js +2 -1
  98. package/dist/hooks/usePointclouds.svelte.d.ts +0 -2
  99. package/dist/hooks/usePointclouds.svelte.js +52 -21
  100. package/dist/hooks/usePose.svelte.js +15 -7
  101. package/dist/hooks/useResizable.svelte.d.ts +12 -0
  102. package/dist/hooks/useResizable.svelte.js +45 -0
  103. package/dist/hooks/useResourceByName.svelte.js +8 -5
  104. package/dist/hooks/useSelection.svelte.d.ts +13 -23
  105. package/dist/hooks/useSelection.svelte.js +45 -65
  106. package/dist/hooks/useVisibility.svelte.d.ts +2 -1
  107. package/dist/hooks/useWeblabs.svelte.d.ts +0 -1
  108. package/dist/hooks/useWeblabs.svelte.js +0 -1
  109. package/dist/hooks/useWorldState.svelte.d.ts +9 -0
  110. package/dist/hooks/useWorldState.svelte.js +158 -107
  111. package/dist/lib.d.ts +1 -0
  112. package/dist/lib.js +2 -0
  113. package/dist/three/BatchedArrow.d.ts +2 -3
  114. package/dist/three/BatchedArrow.js +3 -11
  115. package/dist/three/CapsuleGeometry.d.ts +1 -1
  116. package/dist/three/CapsuleGeometry.js +3 -1
  117. package/dist/transform.js +0 -15
  118. package/package.json +13 -7
  119. package/dist/components/FileDrop.svelte +0 -158
  120. package/dist/components/FileDrop.svelte.d.ts +0 -3
  121. package/dist/components/WorldObject.svelte +0 -28
  122. package/dist/components/WorldObject.svelte.d.ts +0 -11
  123. package/dist/components/WorldObjects.svelte +0 -159
  124. package/dist/components/WorldState.svelte +0 -92
  125. package/dist/components/WorldState.svelte.d.ts +0 -7
  126. package/dist/components/__tests__/__fixtures__/worldObject.svelte.d.ts +0 -2
  127. package/dist/components/__tests__/__fixtures__/worldObject.svelte.js +0 -35
  128. package/dist/components/portal/Portal.svelte +0 -25
  129. package/dist/components/portal/Portal.svelte.d.ts +0 -8
  130. package/dist/components/portal/PortalTarget.svelte +0 -18
  131. package/dist/components/portal/PortalTarget.svelte.d.ts +0 -6
  132. package/dist/components/portal/index.d.ts +0 -2
  133. package/dist/components/portal/index.js +0 -2
  134. package/dist/components/portal/usePortalContext.svelte.d.ts +0 -5
  135. package/dist/components/portal/usePortalContext.svelte.js +0 -5
  136. package/dist/hooks/useArrows.svelte.d.ts +0 -3
  137. package/dist/hooks/useArrows.svelte.js +0 -9
  138. package/dist/hooks/useDraggable.svelte.d.ts +0 -10
  139. package/dist/hooks/useDraggable.svelte.js +0 -36
  140. package/dist/hooks/useObjects.svelte.d.ts +0 -7
  141. package/dist/hooks/useObjects.svelte.js +0 -35
  142. package/dist/hooks/usePersistentUUIDs.svelte.d.ts +0 -5
  143. package/dist/hooks/usePersistentUUIDs.svelte.js +0 -13
  144. package/dist/hooks/useResourceByName.svelte.d.ts +0 -7
  145. package/dist/hooks/useStaticGeometries.svelte.d.ts +0 -9
  146. package/dist/hooks/useStaticGeometries.svelte.js +0 -47
  147. package/dist/workers/worldStateWorker.d.ts +0 -1
  148. package/dist/workers/worldStateWorker.js +0 -114
  149. package/dist/world-state-messages.d.ts +0 -23
  150. package/dist/world-state-messages.js +0 -1
@@ -1,7 +1,7 @@
1
- import type { PointsGeometry, WorldObject } from '../WorldObject.svelte';
2
1
  import type { Snippet } from 'svelte';
2
+ import type { Entity } from 'koota';
3
3
  interface Props {
4
- object: WorldObject<PointsGeometry>;
4
+ entity: Entity;
5
5
  children?: Snippet;
6
6
  }
7
7
  declare const Pointcloud: import("svelte").Component<Props, {}, "">;
@@ -2,13 +2,13 @@
2
2
  import { BackSide, Mesh, Vector3 } from 'three'
3
3
  import { T, useThrelte } from '@threlte/core'
4
4
  import { MeshDiscardMaterial } from '@threlte/extras'
5
- import { useSelected } from '../hooks/useSelection.svelte'
5
+ import { useSelectedEntity } from '../hooks/useSelection.svelte'
6
6
  import { useTransformControls } from '../hooks/useControls.svelte'
7
7
  import { useSettings } from '../hooks/useSettings.svelte'
8
8
 
9
9
  const { camera } = useThrelte()
10
10
  const settings = useSettings()
11
- const selected = useSelected()
11
+ const selectedEntity = useSelectedEntity()
12
12
  const transformControls = useTransformControls()
13
13
  const cameraDown = new Vector3()
14
14
 
@@ -32,7 +32,7 @@
32
32
  return
33
33
  }
34
34
 
35
- selected.set()
35
+ selectedEntity.set()
36
36
  }}
37
37
  >
38
38
  <T.BoxGeometry args={[size, size, size]} />
@@ -1,19 +1,44 @@
1
1
  <script lang="ts">
2
+ import { traits, useTrait } from '../ecs'
2
3
  import { usePose } from '../hooks/usePose.svelte'
4
+ import { matrixToPose, poseToMatrix } from '../transform'
3
5
  import type { Pose } from '@viamrobotics/sdk'
6
+ import type { Entity } from 'koota'
4
7
  import type { Snippet } from 'svelte'
5
8
 
6
9
  interface Props {
7
- name?: string
8
- parent?: string
10
+ entity: Entity
9
11
  children: Snippet<[{ pose: Pose | undefined }]>
10
12
  }
11
- let { name, parent, children }: Props = $props()
13
+ let { entity, children }: Props = $props()
14
+
15
+ const name = useTrait(() => entity, traits.Name)
16
+ const parent = useTrait(() => entity, traits.Parent)
17
+ const editedPose = useTrait(() => entity, traits.EditedPose)
18
+ const entityPose = useTrait(() => entity, traits.Pose)
12
19
 
13
20
  const pose = usePose(
14
- () => name,
15
- () => parent ?? 'world'
21
+ () => name.current,
22
+ () => parent.current
16
23
  )
24
+
25
+ const resolvedPose = $derived.by(() => {
26
+ if (pose.current === undefined) {
27
+ return editedPose.current
28
+ }
29
+
30
+ if (!entityPose.current || !editedPose.current) {
31
+ return
32
+ }
33
+
34
+ const poseNetwork = poseToMatrix(entityPose.current)
35
+ const poseUsePose = poseToMatrix(pose.current)
36
+ const poseLocalEditedPose = poseToMatrix(editedPose.current)
37
+
38
+ const poseNetworkInverse = poseNetwork.invert()
39
+ const resultMatrix = poseUsePose.multiply(poseNetworkInverse).multiply(poseLocalEditedPose)
40
+ return matrixToPose(resultMatrix)
41
+ })
17
42
  </script>
18
43
 
19
- {@render children({ pose: pose.current })}
44
+ {@render children({ pose: resolvedPose })}
@@ -1,8 +1,8 @@
1
1
  import type { Pose } from '@viamrobotics/sdk';
2
+ import type { Entity } from 'koota';
2
3
  import type { Snippet } from 'svelte';
3
4
  interface Props {
4
- name?: string;
5
- parent?: string;
5
+ entity: Entity;
6
6
  children: Snippet<[{
7
7
  pose: Pose | undefined;
8
8
  }]>;
@@ -1,9 +1,8 @@
1
1
  <script lang="ts">
2
2
  import { Vector3 } from 'three'
3
3
  import { T } from '@threlte/core'
4
- import { Grid, interactivity, PerfMonitor, bvh } from '@threlte/extras'
5
- import { PortalTarget } from './portal'
6
- import WorldObjects from './WorldObjects.svelte'
4
+ import { Grid, interactivity, PerfMonitor, bvh, PortalTarget } from '@threlte/extras'
5
+ import Entities from './Entities.svelte'
7
6
  import Selected from './Selected.svelte'
8
7
  import Focus from './Focus.svelte'
9
8
  import StaticGeometries from './StaticGeometries.svelte'
@@ -17,6 +16,7 @@
17
16
  import CameraControls from './CameraControls.svelte'
18
17
  import MeasureTool from './MeasureTool.svelte'
19
18
  import PointerMissBox from './PointerMissBox.svelte'
19
+ import BatchedArrows from './BatchedArrows.svelte'
20
20
 
21
21
  interface Props {
22
22
  children?: Snippet
@@ -41,6 +41,7 @@
41
41
  enabled.set(!settings.current.enableMeasure)
42
42
  })
43
43
  raycaster.firstHitOnly = true
44
+ raycaster.params.Points.threshold = 0.005
44
45
 
45
46
  bvh(() => ({ helper: false }))
46
47
 
@@ -89,11 +90,11 @@
89
90
  {/if}
90
91
 
91
92
  <T.Group attach={focusedObject ? false : undefined}>
92
- <!-- Capture "default" portals if "world" is not explicit -->
93
- <PortalTarget />
94
93
  <PortalTarget id="world" />
94
+ <PortalTarget />
95
95
 
96
- <WorldObjects />
96
+ <Entities />
97
+ <BatchedArrows />
97
98
  </T.Group>
98
99
 
99
100
  {@render children?.()}
@@ -5,7 +5,6 @@
5
5
  import { providePointclouds } from '../hooks/usePointclouds.svelte'
6
6
  import { usePartID } from '../hooks/usePartID.svelte'
7
7
  import { provideSelection } from '../hooks/useSelection.svelte'
8
- import { provideStaticGeometries } from '../hooks/useStaticGeometries.svelte'
9
8
  import { provideVisibility } from '../hooks/useVisibility.svelte'
10
9
  import { provideDrawAPI } from '../hooks/useDrawAPI.svelte'
11
10
  import { provideMachineSettings } from '../hooks/useMachineSettings.svelte'
@@ -14,13 +13,11 @@
14
13
  provideTransformControls,
15
14
  type CameraPose,
16
15
  } from '../hooks/useControls.svelte'
17
- import { provideObjects } from '../hooks/useObjects.svelte'
18
16
  import { provideMotionClient } from '../hooks/useMotionClient.svelte'
19
17
  import { provideLogs } from '../hooks/useLogs.svelte'
20
18
  import { provideOrigin } from './xr/useOrigin.svelte'
21
19
  import { provideWorldStates } from '../hooks/useWorldState.svelte'
22
20
  import { provideArmClient } from '../hooks/useArmClient.svelte'
23
- import { provideArrows } from '../hooks/useArrows.svelte'
24
21
  import { provideFramelessComponents } from '../hooks/useFramelessComponents.svelte'
25
22
  import { provideResourceByName } from '../hooks/useResourceByName.svelte'
26
23
  import { provide3DModels } from '../hooks/use3DModels.svelte'
@@ -40,9 +37,7 @@
40
37
  provideMachineSettings()
41
38
  provideLogs()
42
39
 
43
- provideArrows()
44
40
  provideOrigin()
45
- provideStaticGeometries()
46
41
  provideDrawAPI()
47
42
 
48
43
  provideResourceByName(() => partID.current)
@@ -52,7 +47,6 @@
52
47
  providePointclouds(() => partID.current)
53
48
  provideMotionClient(() => partID.current)
54
49
  provideArmClient(() => partID.current)
55
- provideObjects()
56
50
  provideWorldStates()
57
51
  provideFramelessComponents()
58
52
 
@@ -1,19 +1,23 @@
1
1
  <script lang="ts">
2
2
  import { T, useTask, useThrelte } from '@threlte/core'
3
- import { useSelectedObject, useSelectedObject3d } from '../hooks/useSelection.svelte'
3
+ import { useSelectedEntity, useSelectedObject3d } from '../hooks/useSelection.svelte'
4
4
  import { OBBHelper } from '../three/OBBHelper'
5
5
  import { OBB } from 'three/addons/math/OBB.js'
6
+ import { traits, useTrait } from '../ecs'
7
+ import { BatchedMesh, Box3 } from 'three'
6
8
 
9
+ const box3 = new Box3()
7
10
  const obb = new OBB()
8
11
  const obbHelper = new OBBHelper()
9
12
 
10
- const { invalidate } = useThrelte()
11
- const selected = useSelectedObject()
13
+ const { scene, invalidate } = useThrelte()
14
+ const selectedEntity = useSelectedEntity()
12
15
  const selectedObject3d = useSelectedObject3d()
16
+ const instance = useTrait(() => selectedEntity.current, traits.Instance)
13
17
 
14
18
  // Create a clone so that our bounding box doesn't include children
15
19
  const clone = $derived.by(() => {
16
- if (selected.current?.metadata.batched) {
20
+ if (instance.current) {
17
21
  return
18
22
  }
19
23
 
@@ -22,12 +26,14 @@
22
26
 
23
27
  const { start, stop } = useTask(
24
28
  () => {
25
- if (selected.current === undefined) {
29
+ if (selectedEntity.current === undefined) {
26
30
  return
27
31
  }
28
32
 
29
- if (selected.current.metadata.batched) {
30
- selected.current.metadata.getBoundingBoxAt?.(obb)
33
+ if (instance.current) {
34
+ const mesh = scene.getObjectById(instance.current.meshID) as BatchedMesh
35
+ mesh?.getBoundingBoxAt(instance.current.instanceID, box3)
36
+ obb.fromBox3(box3)
31
37
  obbHelper.setFromOBB(obb)
32
38
  invalidate()
33
39
  return
@@ -47,21 +53,21 @@
47
53
  )
48
54
 
49
55
  $effect.pre(() => {
50
- if (selected.current) {
56
+ if (selectedEntity.current) {
51
57
  start()
52
- obbHelper.visible = true
53
58
  } else {
54
59
  stop()
55
-
56
- obbHelper.visible = false
57
60
  }
58
61
 
59
62
  invalidate()
60
63
  })
61
64
  </script>
62
65
 
63
- <T
64
- is={obbHelper}
65
- raycast={() => null}
66
- bvh={{ enabled: false }}
67
- />
66
+ {#if selectedEntity.current}
67
+ <T
68
+ is={obbHelper}
69
+ dispose={false}
70
+ raycast={() => null}
71
+ bvh={{ enabled: false }}
72
+ />
73
+ {/if}
@@ -1,18 +1,32 @@
1
+ <script
2
+ module
3
+ lang="ts"
4
+ >
5
+ let index = 0
6
+ </script>
7
+
1
8
  <script lang="ts">
2
9
  import { TransformControls } from '@threlte/extras'
3
- import { useSelected } from '../hooks/useSelection.svelte'
4
- import { useStaticGeometries } from '../hooks/useStaticGeometries.svelte'
10
+ import { useSelectedEntity } from '../hooks/useSelection.svelte'
5
11
  import { useTransformControls } from '../hooks/useControls.svelte'
6
12
  import { PressedKeys } from 'runed'
7
- import { quaternionToPose, scaleToDimensions, vector3ToPose } from '../transform'
13
+ import { quaternionToPose, vector3ToPose } from '../transform'
8
14
  import { Quaternion, Vector3 } from 'three'
9
15
  import Frame from './Frame.svelte'
10
16
  import { useSettings } from '../hooks/useSettings.svelte'
17
+ import { useWorld, traits } from '../ecs'
18
+ import type { Entity } from 'koota'
19
+ import { SvelteSet } from 'svelte/reactivity'
11
20
 
21
+ const world = useWorld()
12
22
  const settings = useSettings()
13
23
  const transformControls = useTransformControls()
14
- const geometries = useStaticGeometries()
15
- const selected = useSelected()
24
+ const selectedEntity = useSelectedEntity()
25
+
26
+ const entities = new SvelteSet<Entity>()
27
+ const selectedCustomGeometry = $derived(
28
+ [...entities].find((entity) => entity === selectedEntity.current)
29
+ )
16
30
 
17
31
  const mode = $derived(settings.current.transformMode)
18
32
 
@@ -21,26 +35,33 @@
21
35
 
22
36
  const keys = new PressedKeys()
23
37
 
24
- keys.onKeys('=', () => geometries.add())
25
- keys.onKeys('-', () => geometries.remove(selected.current ?? ''))
38
+ keys.onKeys('=', () => {
39
+ const entity = world.spawn(
40
+ traits.Name(`custom geometry ${++index}`),
41
+ traits.Pose,
42
+ traits.Box({ x: 0.1, y: 0.1, z: 0.1 })
43
+ )
44
+
45
+ entities.add(entity)
46
+ })
47
+
48
+ keys.onKeys('-', () => {
49
+ if (selectedCustomGeometry) {
50
+ selectedCustomGeometry.destroy()
51
+ entities.delete(selectedCustomGeometry)
52
+ selectedEntity.set()
53
+ }
54
+ })
26
55
 
27
56
  $effect(() => {
28
- settings.current.transforming = geometries.current.some(
29
- (geometry) => selected.current === geometry.uuid
30
- )
57
+ settings.current.transforming = selectedCustomGeometry !== undefined
31
58
  })
32
59
  </script>
33
60
 
34
- {#each geometries.current as object (object.uuid)}
35
- <Frame
36
- uuid={object.uuid}
37
- name={object.name}
38
- pose={object.pose}
39
- geometry={object.geometry}
40
- metadata={object.metadata}
41
- >
61
+ {#each entities as entity (entity)}
62
+ <Frame {entity}>
42
63
  {#snippet children({ ref })}
43
- {#if selected.current === object.uuid}
64
+ {#if selectedEntity.current === entity}
44
65
  {#key mode}
45
66
  <TransformControls
46
67
  object={ref}
@@ -54,17 +75,20 @@
54
75
  onmouseUp={() => {
55
76
  transformControls.setActive(false)
56
77
 
57
- if (mode === 'translate') {
58
- vector3ToPose(ref.getWorldPosition(vector3), object.pose)
59
- } else if (mode === 'rotate') {
60
- quaternionToPose(ref.getWorldQuaternion(quaternion), object.pose)
78
+ const pose = entity.get(traits.Pose)
79
+ const box = entity.get(traits.Box)
80
+
81
+ if (pose && mode === 'translate') {
82
+ vector3ToPose(ref.getWorldPosition(vector3), pose)
83
+ entity.set(traits.Pose, pose)
84
+ } else if (pose && mode === 'rotate') {
85
+ quaternionToPose(ref.getWorldQuaternion(quaternion), pose)
61
86
  ref.quaternion.copy(quaternion)
62
- } else if (mode === 'scale' && object.geometry?.geometryType.case === 'box') {
63
- scaleToDimensions(ref.scale, object.geometry.geometryType)
87
+ entity.set(traits.Pose, pose)
88
+ } else if (box && mode === 'scale') {
89
+ entity.set(traits.Box, ref.scale)
64
90
  ref.scale.setScalar(1)
65
91
  }
66
-
67
- object.pose = { ...object.pose }
68
92
  }}
69
93
  />
70
94
  {/key}
@@ -1,60 +1,76 @@
1
1
  <script lang="ts">
2
2
  import * as tree from '@zag-js/tree-view'
3
3
  import { useMachine, normalizeProps } from '@zag-js/svelte'
4
- import { untrack } from 'svelte'
5
4
  import { ChevronRight, Eye, EyeOff } from 'lucide-svelte'
6
5
  import { useVisibility } from '../../hooks/useVisibility.svelte'
7
6
  import type { TreeNode } from './buildTree'
8
- import { useExpanded } from './useExpanded.svelte'
9
7
  import { VirtualList } from 'svelte-virtuallists'
10
- import { observe } from '@threlte/core'
11
8
  import { Icon } from '@viamrobotics/prime-core'
9
+ import { traits } from '../../ecs'
10
+ import { useSelectedEntity } from '../../hooks/useSelection.svelte'
11
+ import { SvelteSet } from 'svelte/reactivity'
12
12
 
13
+ const selected = useSelectedEntity()
13
14
  const visibility = useVisibility()
14
- const expanded = useExpanded()
15
15
 
16
16
  interface Props {
17
17
  rootNode: TreeNode
18
- selections: string[]
18
+ nodeMap: Record<string, TreeNode | undefined>
19
+ dragElement?: HTMLElement
19
20
  onSelectionChange?: (event: tree.SelectionChangeDetails) => void
20
- onDragStart?: (event: MouseEvent) => void
21
- onDragEnd?: (event: MouseEvent) => void
22
21
  }
23
22
 
24
- let { rootNode, selections, onSelectionChange, onDragStart, onDragEnd }: Props = $props()
23
+ let { rootNode, nodeMap, onSelectionChange, dragElement = $bindable() }: Props = $props()
25
24
 
26
- const collection = tree.collection<TreeNode>({
27
- nodeToValue: (node) => node.id,
28
- nodeToString: (node) => node.name,
29
- rootNode,
25
+ const collection = $derived(
26
+ tree.collection<TreeNode>({
27
+ nodeToValue: (node) => `${node.entity}`,
28
+ nodeToString: (node) => node.entity.get(traits.Name) ?? '',
29
+ rootNode,
30
+ })
31
+ )
32
+
33
+ const selectedValue = $derived(selected.current ? [`${selected.current}`] : [])
34
+ const expandedValues = new SvelteSet<string>()
35
+
36
+ $effect(() => {
37
+ let name = selected.current?.get(traits.Name)
38
+ let node = nodeMap[name ?? '']
39
+ while (node) {
40
+ expandedValues.add(`${node.entity}`)
41
+ node = node.parent
42
+ }
30
43
  })
31
44
 
32
- const service = useMachine(tree.machine, {
45
+ const id = $props.id()
46
+ const service = useMachine(tree.machine, () => ({
47
+ id,
33
48
  collection,
49
+ selectedValue,
50
+ expandedValue: [...expandedValues],
34
51
  onSelectionChange(details) {
35
52
  onSelectionChange?.(details)
36
53
  },
37
54
  onExpandedChange(details) {
38
- expanded.clear()
55
+ expandedValues.clear()
39
56
  for (const value of details.expandedValue) {
40
- expanded.add(value)
57
+ expandedValues.add(value)
41
58
  }
42
59
  },
43
- })
60
+ }))
44
61
 
45
62
  const api = $derived(tree.connect(service, normalizeProps))
63
+ const rootChildren = $derived(collection.rootNode.children ?? [])
46
64
 
47
- observe(
48
- () => [selections],
49
- () => untrack(() => api.setSelectedValue(selections))
50
- )
51
-
52
- observe(
53
- () => [expanded],
54
- () => untrack(() => api.setExpandedValue([...expanded]))
55
- )
65
+ $effect(() => {
66
+ const element = document.querySelector(
67
+ `[data-scope="tree-view"][data-value="${selected.current}"]`
68
+ )
56
69
 
57
- const rootChildren = $derived(collection.rootNode.children ?? [])
70
+ requestAnimationFrame(() => {
71
+ element?.scrollIntoView({ block: 'nearest' })
72
+ })
73
+ })
58
74
  </script>
59
75
 
60
76
  {#snippet treeNode({
@@ -68,7 +84,7 @@
68
84
  })}
69
85
  {@const nodeProps = { indexPath, node }}
70
86
  {@const nodeState = api.getNodeState(nodeProps)}
71
- {@const isVisible = visibility.get(node.id) ?? true}
87
+ {@const isVisible = visibility.get(node.entity) ?? true}
72
88
  {@const { selected } = nodeState}
73
89
 
74
90
  {#if nodeState.isBranch}
@@ -93,14 +109,14 @@
93
109
  class="flex items-center"
94
110
  {...api.getBranchTextProps(nodeProps)}
95
111
  >
96
- {node.name}
112
+ {node.entity.get(traits.Name)}
97
113
  </span>
98
114
 
99
115
  <button
100
116
  class="text-gray-6"
101
117
  onclick={(event) => {
102
118
  event.stopPropagation()
103
- visibility.set(node.id, !isVisible)
119
+ visibility.set(node.entity, !isVisible)
104
120
  }}
105
121
  >
106
122
  {#if isVisible}
@@ -113,7 +129,7 @@
113
129
  <div {...api.getBranchContentProps(nodeProps)}>
114
130
  <div {...api.getBranchIndentGuideProps(nodeProps)}></div>
115
131
 
116
- {#each children as node, index (node.id)}
132
+ {#each children as node, index (node.entity)}
117
133
  {@render treeNode({ node, indexPath: [...indexPath, index], api })}
118
134
  {/each}
119
135
  </div>
@@ -124,14 +140,14 @@
124
140
  {...api.getItemProps(nodeProps)}
125
141
  >
126
142
  <span class="flex items-center gap-1.5">
127
- {node.name}
143
+ {node.entity.get(traits.Name)}
128
144
  </span>
129
145
 
130
146
  <button
131
147
  class="text-gray-6"
132
148
  onclick={(event) => {
133
149
  event.stopPropagation()
134
- visibility.set(node.id, !isVisible)
150
+ visibility.set(node.entity, !isVisible)
135
151
  }}
136
152
  >
137
153
  {#if isVisible}
@@ -147,13 +163,10 @@
147
163
  <div class="root-node">
148
164
  <div {...api.getRootProps() as object}>
149
165
  <div class="border-medium flex items-center gap-1 border-b p-2">
150
- <button
151
- onmousedown={onDragStart}
152
- onmouseup={onDragEnd}
153
- >
166
+ <button bind:this={dragElement}>
154
167
  <Icon name="drag" />
155
168
  </button>
156
- <h3 {...api.getLabelProps() as object}>{rootNode.name}</h3>
169
+ <h3 {...api.getLabelProps() as object}>{rootNode.entity.get(traits.Name)}</h3>
157
170
  </div>
158
171
 
159
172
  <div {...api.getTreeProps()}>
@@ -174,7 +187,7 @@
174
187
  style="height:{Math.min(8, Math.max(rootChildren.length, 5)) * 32}px;"
175
188
  class="overflow-auto"
176
189
  >
177
- {#each rootChildren as node, index (node.id)}
190
+ {#each rootChildren as node, index (node.entity)}
178
191
  {@render treeNode({ node, indexPath: [Number(index)], api })}
179
192
  {/each}
180
193
  </div>
@@ -2,11 +2,10 @@ import * as tree from '@zag-js/tree-view';
2
2
  import type { TreeNode } from './buildTree';
3
3
  interface Props {
4
4
  rootNode: TreeNode;
5
- selections: string[];
5
+ nodeMap: Record<string, TreeNode | undefined>;
6
+ dragElement?: HTMLElement;
6
7
  onSelectionChange?: (event: tree.SelectionChangeDetails) => void;
7
- onDragStart?: (event: MouseEvent) => void;
8
- onDragEnd?: (event: MouseEvent) => void;
9
8
  }
10
- declare const Tree: import("svelte").Component<Props, {}, "">;
9
+ declare const Tree: import("svelte").Component<Props, {}, "dragElement">;
11
10
  type Tree = ReturnType<typeof Tree>;
12
11
  export default Tree;