@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,39 +1,75 @@
1
1
  <script lang="ts">
2
+ import { Button, Icon } from '@viamrobotics/prime-core'
2
3
  import { usePartConfig } from '../hooks/usePartConfig.svelte'
3
4
 
4
5
  const partConfig = usePartConfig()
5
6
 
6
7
  const { ...rest } = $props()
8
+
9
+ const isMacDevice = /Mac|iPod|iPhone|iPad/.test(navigator.platform)
10
+ const iconName = isMacDevice ? ('apple-keyboard-command' as const) : ('chevron-up' as const)
11
+ const iconLabel = isMacDevice ? 'command' : 'control'
7
12
  </script>
8
13
 
14
+ <svelte:window
15
+ onkeydown={(event) => {
16
+ if (event.metaKey) {
17
+ if (event.key.toLowerCase() === 's') {
18
+ event.preventDefault()
19
+ event.stopImmediatePropagation()
20
+ partConfig.saveLocalPartConfig()
21
+ }
22
+ }
23
+ }}
24
+ />
25
+
9
26
  {#if partConfig.isDirty}
10
27
  <div
11
- class="absolute bottom-8 z-1000 flex w-full justify-center gap-2"
28
+ class="absolute bottom-8 z-10 flex w-full justify-center gap-2"
12
29
  {...rest}
13
30
  >
14
31
  <div
15
- class="flex flex-col items-start rounded border-l-4 border-yellow-600 bg-yellow-50 px-4 py-2"
32
+ class="flex items-center gap-8 rounded border-l-4 border-yellow-600 bg-yellow-50 px-4 py-2 shadow-2xl"
16
33
  >
17
- <p>
18
- <strong>Live updates paused</strong>
19
- </p>
34
+ <div class="flex flex-col">
35
+ <p class="text-sm">
36
+ <strong>Live updates paused</strong>
37
+ </p>
20
38
 
21
- <p class="text-sm">
22
- <button
39
+ <p class="text-subtle-2 text-sm">You are currently viewing a snapshot while editing.</p>
40
+ </div>
41
+
42
+ <div class="flex gap-2">
43
+ <Button
23
44
  class="cursor-pointer text-blue-600"
24
45
  onclick={() => {
25
- partConfig.saveLocalPartConfig()
26
- }}>Save</button
46
+ partConfig.resetLocalPartConfig()
47
+ }}
27
48
  >
28
- or
29
- <button
49
+ Discard
50
+ </Button>
51
+
52
+ <Button
53
+ variant="dark"
54
+ aria-label="Save"
30
55
  class="cursor-pointer text-blue-600"
31
56
  onclick={() => {
32
- partConfig.resetLocalPartConfig()
33
- }}>Discard</button
57
+ partConfig.saveLocalPartConfig()
58
+ }}
34
59
  >
35
- to resume.
36
- </p>
60
+ <div class="flex gap-2">
61
+ Save
62
+ <div class="font-roboto-mono text-disabled flex items-center">
63
+ <Icon
64
+ name={iconName}
65
+ size="xs"
66
+ />
67
+ <span class="sr-only">{iconLabel}</span>
68
+ <span>S</span>
69
+ </div>
70
+ </div>
71
+ </Button>
72
+ </div>
37
73
  </div>
38
74
  </div>
39
75
  {/if}
@@ -2,15 +2,14 @@
2
2
  import { untrack } from 'svelte'
3
3
  import { Vector3, type Intersection } from 'three'
4
4
  import { T } from '@threlte/core'
5
- import { HTML, MeshLineGeometry, MeshLineMaterial } from '@threlte/extras'
5
+ import { HTML, MeshLineGeometry, MeshLineMaterial, Portal } from '@threlte/extras'
6
6
  import { useSettings } from '../hooks/useSettings.svelte'
7
7
  import Button from './dashboard/Button.svelte'
8
- import Portal from './portal/Portal.svelte'
9
8
  import DotSprite from './DotSprite.svelte'
10
9
  import { useMouseRaycaster } from '../hooks/useMouseRaycaster.svelte'
11
- import { useFocused } from '../hooks/useSelection.svelte'
10
+ import { useFocusedEntity } from '../hooks/useSelection.svelte'
12
11
 
13
- const focus = useFocused()
12
+ const focusedEntity = useFocusedEntity()
14
13
  const settings = useSettings()
15
14
 
16
15
  const htmlPosition = new Vector3()
@@ -55,7 +54,7 @@
55
54
 
56
55
  $effect(() => {
57
56
  // eslint-disable-next-line @typescript-eslint/no-unused-expressions
58
- ;(focus.current, enabled)
57
+ ;(focusedEntity.current, enabled)
59
58
  untrack(() => clear())
60
59
  })
61
60
  </script>
@@ -7,25 +7,29 @@
7
7
  OrthographicCamera,
8
8
  } from 'three'
9
9
  import { T, useTask, useThrelte } from '@threlte/core'
10
- import type { PointsGeometry, WorldObject } from '../WorldObject.svelte'
11
10
  import { useObjectEvents } from '../hooks/useObjectEvents.svelte'
12
11
  import { poseToObject3d } from '../transform'
13
12
  import { useSettings } from '../hooks/useSettings.svelte'
14
13
  import type { Snippet } from 'svelte'
14
+ import type { Entity } from 'koota'
15
+ import { traits, useTrait } from '../ecs'
15
16
 
16
17
  interface Props {
17
- object: WorldObject<PointsGeometry>
18
+ entity: Entity
18
19
  children?: Snippet
19
20
  }
20
21
 
21
- let { object, children }: Props = $props()
22
+ let { entity, children }: Props = $props()
22
23
 
23
24
  const { camera } = useThrelte()
24
25
  const settings = useSettings()
25
26
 
26
- const colors = $derived(object.metadata.colors)
27
- const pointSize = $derived(object.metadata.pointSize ?? settings.current.pointSize)
28
- const positions = $derived(object.geometry?.geometryType?.value ?? new Float32Array())
27
+ const name = useTrait(() => entity, traits.Name)
28
+ const pose = useTrait(() => entity, traits.Pose)
29
+ const positions = useTrait(() => entity, traits.PointsGeometry)
30
+ const color = useTrait(() => entity, traits.Color)
31
+ const colors = useTrait(() => entity, traits.VertexColors)
32
+ const pointSize = $derived(settings.current.pointSize)
29
33
  const orthographic = $derived(settings.current.cameraMode === 'orthographic')
30
34
 
31
35
  const points = new Points()
@@ -38,27 +42,37 @@
38
42
  })
39
43
 
40
44
  $effect.pre(() => {
41
- material.color.set(colors ? 0xffffff : (object.metadata.color ?? settings.current.pointColor))
45
+ if (colors) {
46
+ material.color.set(0xffffff)
47
+ } else if (color.current) {
48
+ material.color.setRGB(color.current.r, color.current.g, color.current.b)
49
+ } else {
50
+ material.color.set(settings.current.pointColor)
51
+ }
42
52
  })
43
53
 
44
54
  $effect.pre(() => {
45
- geometry.setAttribute('position', new BufferAttribute(positions, 3))
55
+ if (positions.current) {
56
+ geometry.setAttribute('position', new BufferAttribute(positions.current, 3))
57
+ }
46
58
  })
47
59
 
48
60
  $effect.pre(() => {
49
61
  material.vertexColors = colors !== undefined
50
62
 
51
- if (colors) {
52
- geometry.setAttribute('color', new BufferAttribute(colors, 3))
63
+ if (colors.current) {
64
+ geometry.setAttribute('color', new BufferAttribute(colors.current, 3))
53
65
  geometry.attributes.color.needsUpdate = true
54
66
  }
55
67
  })
56
68
 
57
69
  $effect.pre(() => {
58
- poseToObject3d(object.pose, points)
70
+ if (pose.current) {
71
+ poseToObject3d(pose.current, points)
72
+ }
59
73
  })
60
74
 
61
- const events = useObjectEvents(() => object.uuid)
75
+ const events = useObjectEvents(() => entity)
62
76
 
63
77
  const { start, stop } = useTask(
64
78
  () => {
@@ -84,8 +98,7 @@
84
98
 
85
99
  <T
86
100
  is={points}
87
- name={object.name}
88
- uuid={object.uuid}
101
+ name={name.current}
89
102
  {...events}
90
103
  bvh={{ maxDepth: 40, maxLeafTris: 20 }}
91
104
  >
@@ -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}