@viamrobotics/motion-tools 1.30.0 → 1.32.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 (76) hide show
  1. package/dist/components/App.svelte +51 -46
  2. package/dist/components/App.svelte.d.ts +1 -1
  3. package/dist/components/Entities/Arrows/Arrows.svelte +4 -7
  4. package/dist/components/Entities/hooks/useEntityEvents.svelte.d.ts +0 -1
  5. package/dist/components/Entities/hooks/useEntityEvents.svelte.js +30 -16
  6. package/dist/components/InputBindings.svelte +0 -43
  7. package/dist/components/KeyboardBindings.svelte +38 -0
  8. package/dist/components/KeyboardBindings.svelte.d.ts +18 -0
  9. package/dist/components/PointerMissBox.svelte +6 -3
  10. package/dist/components/Scene.svelte +34 -45
  11. package/dist/components/SceneProviders.svelte +2 -4
  12. package/dist/components/SceneProviders.svelte.d.ts +1 -3
  13. package/dist/components/Selected.svelte +20 -27
  14. package/dist/components/SelectedTransformControls.svelte +10 -8
  15. package/dist/components/StaticGeometries.svelte +3 -5
  16. package/dist/components/hover/HoveredEntities.svelte +15 -14
  17. package/dist/components/hover/HoveredEntities.svelte.d.ts +17 -2
  18. package/dist/components/hover/HoveredEntity.svelte +8 -5
  19. package/dist/components/hover/HoveredEntity.svelte.d.ts +5 -1
  20. package/dist/components/hover/LinkedHoveredEntity.svelte +7 -11
  21. package/dist/components/hover/LinkedHoveredEntity.svelte.d.ts +1 -0
  22. package/dist/components/overlay/Details.svelte +24 -38
  23. package/dist/components/overlay/Details.svelte.d.ts +3 -1
  24. package/dist/components/overlay/controls/Controls.svelte +0 -2
  25. package/dist/components/overlay/dashboard/Button.svelte +5 -3
  26. package/dist/components/overlay/dashboard/Button.svelte.d.ts +1 -1
  27. package/dist/components/overlay/left-pane/Tree.svelte +13 -10
  28. package/dist/components/overlay/left-pane/TreeContainer.svelte +9 -4
  29. package/dist/components/overlay/left-pane/TreeNode.svelte +6 -4
  30. package/dist/draw.d.ts +1 -0
  31. package/dist/draw.js +1 -1
  32. package/dist/ecs/index.d.ts +1 -0
  33. package/dist/ecs/index.js +1 -0
  34. package/dist/ecs/traits.d.ts +22 -5
  35. package/dist/ecs/traits.js +33 -4
  36. package/dist/ecs/useTag.svelte.d.ts +5 -0
  37. package/dist/ecs/useTag.svelte.js +43 -0
  38. package/dist/hooks/useConfigFrames.svelte.js +1 -1
  39. package/dist/hooks/useEnvironment.svelte.d.ts +1 -1
  40. package/dist/hooks/useLinked.svelte.js +7 -8
  41. package/dist/hooks/useMouseRaycaster.svelte.d.ts +4 -3
  42. package/dist/hooks/useMouseRaycaster.svelte.js +1 -0
  43. package/dist/hooks/useSettings.svelte.d.ts +1 -1
  44. package/dist/lib.d.ts +1 -0
  45. package/dist/lib.js +1 -0
  46. package/dist/loaders/pcd/worker.inline.d.ts +1 -1
  47. package/dist/loaders/pcd/worker.inline.js +1 -1
  48. package/dist/loaders/pcd/worker.js +3 -1
  49. package/dist/plugins/Focus/Focus.svelte +45 -0
  50. package/dist/plugins/Focus/Focus.svelte.d.ts +3 -0
  51. package/dist/plugins/Focus/FocusBox.svelte +75 -0
  52. package/dist/plugins/Focus/FocusBox.svelte.d.ts +3 -0
  53. package/dist/plugins/Focus/provideFocus.svelte.d.ts +1 -0
  54. package/dist/plugins/Focus/provideFocus.svelte.js +61 -0
  55. package/dist/{components → plugins}/MeasureTool/MeasureTool.svelte +6 -8
  56. package/dist/plugins/Selection/Ellipse.svelte +21 -16
  57. package/dist/plugins/Selection/Lasso.svelte +21 -16
  58. package/dist/plugins/Selection/SelectionTool.svelte +10 -3
  59. package/dist/plugins/Selection/relations.d.ts +6 -0
  60. package/dist/plugins/Selection/relations.js +7 -0
  61. package/dist/plugins/Selection/traits.d.ts +0 -5
  62. package/dist/plugins/Selection/traits.js +1 -6
  63. package/dist/plugins/index.d.ts +3 -0
  64. package/dist/plugins/index.js +3 -0
  65. package/dist/snapshot.d.ts +14 -0
  66. package/dist/snapshot.js +23 -0
  67. package/dist/three/arrow.d.ts +2 -0
  68. package/dist/three/arrow.js +3 -1
  69. package/package.json +17 -5
  70. package/dist/components/Focus.svelte +0 -46
  71. package/dist/components/Focus.svelte.d.ts +0 -7
  72. package/dist/hooks/useSelection.svelte.d.ts +0 -33
  73. package/dist/hooks/useSelection.svelte.js +0 -94
  74. /package/dist/{components → plugins}/MeasureTool/MeasurePoint.svelte +0 -0
  75. /package/dist/{components → plugins}/MeasureTool/MeasurePoint.svelte.d.ts +0 -0
  76. /package/dist/{components → plugins}/MeasureTool/MeasureTool.svelte.d.ts +0 -0
@@ -1,13 +1,13 @@
1
1
  <script lang="ts">
2
2
  import type { Struct } from '@viamrobotics/sdk'
3
3
  import type { Entity } from 'koota'
4
- import type { Snippet } from 'svelte'
5
4
 
6
5
  import { Canvas } from '@threlte/core'
7
6
  import { PortalTarget } from '@threlte/extras'
8
7
  import { useXR } from '@threlte/xr'
9
8
  import { provideToast, ToastContainer } from '@viamrobotics/prime-core'
10
9
  import { primeTheme } from '@viamrobotics/tweakpane-config'
10
+ import { onMount, type Snippet } from 'svelte'
11
11
  import { ThemeUtils } from 'svelte-tweakpane-ui'
12
12
 
13
13
  import type { FragmentInfo } from '../hooks/usePartConfig.svelte'
@@ -18,7 +18,7 @@
18
18
  import TreeContainer from './overlay/left-pane/TreeContainer.svelte'
19
19
  import Settings from './overlay/settings/Settings.svelte'
20
20
  import XR from './xr/XR.svelte'
21
- import { provideWorld } from '../ecs'
21
+ import { provideWorld, traits, useQuery } from '../ecs'
22
22
  import { type CameraPose, provideCameraControls } from '../hooks/useControls.svelte'
23
23
  import { provideEnvironment } from '../hooks/useEnvironment.svelte'
24
24
  import { providePartConfig } from '../hooks/usePartConfig.svelte'
@@ -107,9 +107,11 @@
107
107
  environment.current.isStandalone = !localConfigProps
108
108
  })
109
109
 
110
- $effect(() => {
110
+ onMount(() => {
111
111
  ThemeUtils.setGlobalDefaultTheme(primeTheme)
112
112
  })
113
+
114
+ const selected = useQuery(traits.Selected)
113
115
  </script>
114
116
 
115
117
  <div
@@ -118,53 +120,56 @@
118
120
  >
119
121
  <Canvas renderMode="on-demand">
120
122
  <SceneProviders>
121
- {#snippet children({ focus })}
122
- <Scene>
123
- {@render appChildren?.()}
124
- </Scene>
123
+ <Scene>
124
+ {@render appChildren?.()}
125
+ </Scene>
126
+
127
+ <XR {@attach domPortal(root)} />
128
+
129
+ {#if settings.current.renderSubEntityHoverDetail}
130
+ <HoveredEntities />
131
+ {/if}
132
+
133
+ <!-- Overlays that need Threlte context -->
134
+ <div {@attach domPortal(root)}>
135
+ <FileDrop />
136
+ <Dashboard {dashboard} />
137
+ <Controls />
138
+
139
+ {#each selected.current as entity, index (entity)}
140
+ <Details
141
+ {entity}
142
+ {details}
143
+ style="transform: translate(0, {index * 40}px)"
144
+ />
145
+ {/each}
146
+
147
+ {#if environment.current.isStandalone}
148
+ <LiveUpdatesBanner />
149
+ {/if}
125
150
 
126
- <XR {@attach domPortal(root)} />
151
+ <TreeContainer />
127
152
 
128
- {#if settings.current.renderSubEntityHoverDetail}
129
- <HoveredEntities />
153
+ {#if settings.current.enableArmPositionsWidget}
154
+ <ArmPositions />
130
155
  {/if}
131
156
 
132
- <!-- Overlays that need Threlte context -->
133
- <div {@attach domPortal(root)}>
134
- <FileDrop />
135
- <Dashboard {dashboard} />
136
- <Controls />
137
- <Details {details} />
138
-
139
- {#if environment.current.isStandalone}
140
- <LiveUpdatesBanner />
141
- {/if}
142
-
143
- {#if !focus}
144
- <TreeContainer />
145
- {/if}
146
-
147
- {#if !focus && settings.current.enableArmPositionsWidget}
148
- <ArmPositions />
149
- {/if}
150
-
151
- {#if !focus && !$isPresenting}
152
- {#each currentRobotCameraWidgets as cameraName (cameraName)}
153
- <Camera name={cameraName} />
154
- {/each}
155
-
156
- {#each currentFramePovWidgets as povFrameName (povFrameName)}
157
- <FramePov frameName={povFrameName} />
158
- {/each}
159
- {/if}
160
-
161
- <PortalTarget id="dom" />
162
-
163
- <Settings />
164
- <Logs />
165
- <AddFrames />
166
- </div>
167
- {/snippet}
157
+ {#if !$isPresenting}
158
+ {#each currentRobotCameraWidgets as cameraName (cameraName)}
159
+ <Camera name={cameraName} />
160
+ {/each}
161
+
162
+ {#each currentFramePovWidgets as povFrameName (povFrameName)}
163
+ <FramePov frameName={povFrameName} />
164
+ {/each}
165
+ {/if}
166
+
167
+ <PortalTarget id="dom" />
168
+
169
+ <Settings />
170
+ <Logs />
171
+ <AddFrames />
172
+ </div>
168
173
  </SceneProviders>
169
174
  </Canvas>
170
175
 
@@ -1,6 +1,6 @@
1
1
  import type { Struct } from '@viamrobotics/sdk';
2
2
  import type { Entity } from 'koota';
3
- import type { Snippet } from 'svelte';
3
+ import { type Snippet } from 'svelte';
4
4
  import type { FragmentInfo } from '../hooks/usePartConfig.svelte';
5
5
  import { type CameraPose } from '../hooks/useControls.svelte';
6
6
  interface LocalConfigProps {
@@ -7,8 +7,7 @@
7
7
 
8
8
  import AxesHelper from '../../AxesHelper.svelte'
9
9
  import { useEntityEvents } from '../hooks/useEntityEvents.svelte'
10
- import { traits, useTrait } from '../../../ecs'
11
- import { useFocusedEntity, useSelectedEntity } from '../../../hooks/useSelection.svelte'
10
+ import { traits, useTag, useTrait } from '../../../ecs'
12
11
  import { meshBoundsRaycast, raycast } from '../../../three/InstancedArrows/raycast'
13
12
 
14
13
  interface Props {
@@ -20,19 +19,17 @@
20
19
 
21
20
  const { invalidate } = useThrelte()
22
21
  const worldMatrix = useTrait(() => entity, traits.WorldMatrix)
22
+ const selected = useTag(() => entity, traits.Selected)
23
23
  const invisible = useTrait(() => entity, traits.InheritedInvisible)
24
24
  const showAxesHelper = useTrait(() => entity, traits.ShowAxesHelper)
25
25
 
26
26
  const events = useEntityEvents(() => entity)
27
- const selectedEntity = useSelectedEntity()
28
- const focusedEntity = useFocusedEntity()
29
-
30
- const displayEntity = $derived(selectedEntity.current ?? focusedEntity.current)
31
27
 
32
28
  const raycastFunction = $derived.by(() => {
33
- if (displayEntity) {
29
+ if (selected.current) {
34
30
  return raycast
35
31
  }
32
+
36
33
  return meshBoundsRaycast
37
34
  })
38
35
 
@@ -4,7 +4,6 @@ export declare const useEntityEvents: (entity: () => Entity | undefined) => {
4
4
  onpointerenter: (event: IntersectionEvent<MouseEvent>) => void;
5
5
  onpointermove: (event: IntersectionEvent<MouseEvent>) => void;
6
6
  onpointerleave: (event: IntersectionEvent<MouseEvent>) => void;
7
- ondblclick: (event: IntersectionEvent<MouseEvent>) => void;
8
7
  onpointerdown: (event: IntersectionEvent<MouseEvent>) => void;
9
8
  onclick: (event: IntersectionEvent<MouseEvent>) => void;
10
9
  };
@@ -1,7 +1,6 @@
1
1
  import { useCursor } from '@threlte/extras';
2
2
  import { MathUtils, Matrix4, Quaternion, Vector2 } from 'three';
3
- import { traits, useTrait } from '../../../ecs';
4
- import { useFocusedEntity, useSelectedEntity } from '../../../hooks/useSelection.svelte';
3
+ import { traits, useTrait, useWorld } from '../../../ecs';
5
4
  import { updateHoverInfo } from '../../../HoverUpdater.svelte';
6
5
  import { OrientationVector } from '../../../three/OrientationVector';
7
6
  const tempHoverMatrix = new Matrix4();
@@ -15,8 +14,7 @@ const infoToLocalMatrix = (info, out) => {
15
14
  };
16
15
  export const useEntityEvents = (entity) => {
17
16
  const down = new Vector2();
18
- const selectedEntity = useSelectedEntity();
19
- const focusedEntity = useFocusedEntity();
17
+ const world = useWorld();
20
18
  const cursor = useCursor();
21
19
  const invisible = useTrait(entity, traits.InheritedInvisible);
22
20
  const onpointerenter = (event) => {
@@ -80,25 +78,42 @@ export const useEntityEvents = (entity) => {
80
78
  currentEntity.remove(traits.InstancedMatrix);
81
79
  }
82
80
  };
83
- const ondblclick = (event) => {
84
- if (invisible.current)
85
- return;
86
- event.stopPropagation();
87
- const currentEntity = entity();
88
- focusedEntity.set(currentEntity, event.instanceId ?? event.batchId);
89
- };
90
81
  const onpointerdown = (event) => {
91
82
  if (invisible.current)
92
83
  return;
93
84
  down.copy(event.pointer);
94
85
  };
95
86
  const onclick = (event) => {
96
- if (invisible.current)
87
+ if (invisible.current) {
97
88
  return;
89
+ }
98
90
  event.stopPropagation();
99
- if (down.distanceToSquared(event.pointer) < 0.1) {
100
- const currentEntity = entity();
101
- selectedEntity.set(currentEntity, event.instanceId ?? event.batchId);
91
+ if (down.distanceToSquared(event.pointer) >= 0.1) {
92
+ return;
93
+ }
94
+ const currentEntity = entity();
95
+ if (!currentEntity)
96
+ return;
97
+ if (event.nativeEvent.shiftKey) {
98
+ if (currentEntity.has(traits.Selected)) {
99
+ currentEntity.remove(traits.Selected);
100
+ }
101
+ else {
102
+ currentEntity.add(traits.Selected);
103
+ }
104
+ }
105
+ else {
106
+ for (const entity of world.query(traits.Selected)) {
107
+ if (entity !== currentEntity) {
108
+ entity.remove(traits.Selected);
109
+ }
110
+ }
111
+ if (!currentEntity.has(traits.Selected)) {
112
+ currentEntity.add(traits.Selected);
113
+ }
114
+ }
115
+ if (event.instanceId || event.batchId) {
116
+ currentEntity.add(traits.InstanceId(event.instanceId ?? event.batchId));
102
117
  }
103
118
  };
104
119
  $effect(() => {
@@ -117,7 +132,6 @@ export const useEntityEvents = (entity) => {
117
132
  onpointerenter,
118
133
  onpointermove,
119
134
  onpointerleave,
120
- ondblclick,
121
135
  onpointerdown,
122
136
  onclick,
123
137
  };
@@ -3,26 +3,14 @@
3
3
 
4
4
  import { isInstanceOf, useTask } from '@threlte/core'
5
5
  import { useGamepad, useInputMap, useKeyboard } from '@threlte/extras'
6
- import { PressedKeys } from 'runed'
7
6
  import { MathUtils, Vector3 } from 'three'
8
7
 
9
- import { traits } from '../ecs'
10
- import { useFocusedEntity, useSelectedEntity } from '../hooks/useSelection.svelte'
11
- import { useSettings } from '../hooks/useSettings.svelte'
12
-
13
8
  interface Props {
14
9
  cameraControls: CameraControlsRef
15
10
  }
16
11
 
17
12
  let { cameraControls }: Props = $props()
18
13
 
19
- const focusedEntity = useFocusedEntity()
20
- const selectedEntity = useSelectedEntity()
21
-
22
- const entity = $derived(focusedEntity.current ?? selectedEntity.current)
23
-
24
- const settings = useSettings()
25
-
26
14
  const keyboard = useKeyboard()
27
15
  const gamepad = useGamepad()
28
16
  const input = useInputMap(
@@ -125,35 +113,4 @@
125
113
  autoInvalidate: false,
126
114
  }
127
115
  )
128
-
129
- const keys = new PressedKeys()
130
-
131
- keys.onKeys('escape', () => {
132
- focusedEntity.set()
133
- })
134
-
135
- keys.onKeys('c', () => {
136
- settings.current.cameraMode =
137
- settings.current.cameraMode === 'perspective' ? 'orthographic' : 'perspective'
138
- })
139
-
140
- keys.onKeys('1', () => {
141
- settings.current.transformMode = 'translate'
142
- })
143
-
144
- keys.onKeys('2', () => {
145
- settings.current.transformMode = 'rotate'
146
- })
147
-
148
- keys.onKeys('3', () => {
149
- settings.current.transformMode = 'scale'
150
- })
151
-
152
- keys.onKeys('h', () => {
153
- if (entity?.has(traits.Invisible)) {
154
- entity.remove(traits.Invisible)
155
- } else {
156
- entity?.add(traits.Invisible)
157
- }
158
- })
159
116
  </script>
@@ -0,0 +1,38 @@
1
+ <script lang="ts">
2
+ import { PressedKeys } from 'runed'
3
+
4
+ import { traits, useQuery } from '../ecs'
5
+ import { useSettings } from '../hooks/useSettings.svelte'
6
+
7
+ const selected = useQuery(traits.Selected)
8
+
9
+ const settings = useSettings()
10
+ const keys = new PressedKeys()
11
+
12
+ keys.onKeys('c', () => {
13
+ settings.current.cameraMode =
14
+ settings.current.cameraMode === 'perspective' ? 'orthographic' : 'perspective'
15
+ })
16
+
17
+ keys.onKeys('1', () => {
18
+ settings.current.transformMode = 'translate'
19
+ })
20
+
21
+ keys.onKeys('2', () => {
22
+ settings.current.transformMode = 'rotate'
23
+ })
24
+
25
+ keys.onKeys('3', () => {
26
+ settings.current.transformMode = 'scale'
27
+ })
28
+
29
+ keys.onKeys('h', () => {
30
+ for (const entity of selected.current) {
31
+ if (entity?.has(traits.Invisible)) {
32
+ entity.remove(traits.Invisible)
33
+ } else {
34
+ entity?.add(traits.Invisible)
35
+ }
36
+ }
37
+ })
38
+ </script>
@@ -0,0 +1,18 @@
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 KeyboardBindings: $$__sveltets_2_IsomorphicComponent<Record<string, never>, {
15
+ [evt: string]: CustomEvent<any>;
16
+ }, {}, {}, string>;
17
+ type KeyboardBindings = InstanceType<typeof KeyboardBindings>;
18
+ export default KeyboardBindings;
@@ -3,14 +3,15 @@
3
3
  import { MeshDiscardMaterial } from '@threlte/extras'
4
4
  import { BackSide, Mesh, Vector3 } from 'three'
5
5
 
6
+ import { traits, useQuery } from '../ecs'
6
7
  import { useTransformControls } from '../hooks/useControls.svelte'
7
- import { useSelectedEntity } from '../hooks/useSelection.svelte'
8
8
  import { useSettings } from '../hooks/useSettings.svelte'
9
9
 
10
10
  const { camera } = useThrelte()
11
11
  const settings = useSettings()
12
- const selectedEntity = useSelectedEntity()
13
12
  const transformControls = useTransformControls()
13
+ const selected = useQuery(traits.Selected)
14
+
14
15
  const cameraDown = new Vector3()
15
16
 
16
17
  const enabled = $derived(settings.current.interactionMode === 'navigate')
@@ -32,7 +33,9 @@
32
33
  return
33
34
  }
34
35
 
35
- selectedEntity.set()
36
+ for (const entity of selected.current) {
37
+ entity.remove(traits.Selected)
38
+ }
36
39
  }}
37
40
  >
38
41
  <T.BoxGeometry args={[size, size, size]} />
@@ -4,22 +4,20 @@
4
4
  import { T, useThrelte } from '@threlte/core'
5
5
  import { Environment, Grid, interactivity, PerfMonitor, PortalTarget } from '@threlte/extras'
6
6
  import { useXR } from '@threlte/xr'
7
- import { ShaderMaterial, Vector3 } from 'three'
7
+ import { ShaderMaterial } from 'three'
8
8
 
9
9
  import Camera from './Camera.svelte'
10
10
  import Entities from './Entities/Entities.svelte'
11
- import Focus from './Focus.svelte'
12
11
  import Selected from './Selected.svelte'
13
12
  import SelectedTransformControls from './SelectedTransformControls.svelte'
14
13
  import StaticGeometries from './StaticGeometries.svelte'
15
14
  import { bvh } from '../hooks/plugins/bvh.svelte'
16
- import { useFocusedObject3d } from '../hooks/useSelection.svelte'
17
15
  import { useSettings } from '../hooks/useSettings.svelte'
18
16
 
19
17
  import hdrImage from '../assets/ferndale_studio_11_1k.hdr'
20
18
  import BatchedArrows from './BatchedArrows.svelte'
21
19
  import CameraControls from './CameraControls.svelte'
22
- import MeasureTool from './MeasureTool/MeasureTool.svelte'
20
+ import KeyboardBindings from './KeyboardBindings.svelte'
23
21
  import PointerMissBox from './PointerMissBox.svelte'
24
22
  import { useOrigin } from './xr/useOrigin.svelte'
25
23
 
@@ -31,7 +29,6 @@
31
29
 
32
30
  const threlte = useThrelte()
33
31
  const settings = useSettings()
34
- const focusedObject3d = useFocusedObject3d()
35
32
  const origin = useOrigin()
36
33
 
37
34
  // @ts-expect-error This is for debugging
@@ -59,8 +56,6 @@
59
56
 
60
57
  bvh(raycaster, () => ({ helper: false, enabled: bvhEnabled }))
61
58
 
62
- const focusedObject = $derived(focusedObject3d.current)
63
-
64
59
  const { isPresenting } = useXR()
65
60
  </script>
66
61
 
@@ -68,6 +63,7 @@
68
63
  <PerfMonitor anchorX="right" />
69
64
  {/if}
70
65
 
66
+ <KeyboardBindings />
71
67
  <Environment url={hdrImage} />
72
68
 
73
69
  <T.Group
@@ -75,47 +71,40 @@
75
71
  rotation.z={origin.rotation}
76
72
  >
77
73
  <PointerMissBox />
78
- <MeasureTool />
79
-
80
- {#if focusedObject}
81
- <Focus object3d={focusedObject} />
82
- {:else}
83
- {#if !$isPresenting}
84
- <Camera position={[3, 3, 3]}>
85
- <CameraControls />
86
- </Camera>
87
- {/if}
88
-
89
- <StaticGeometries />
90
- <Selected />
91
- <SelectedTransformControls />
92
-
93
- {#if !$isPresenting && settings.current.grid}
94
- <Grid
95
- oncreate={(ref) => {
96
- const material = ref.material as ShaderMaterial
97
- material.depthWrite = false
98
- }}
99
- raycast={() => null}
100
- bvh={{ enabled: false }}
101
- plane="xy"
102
- sectionColor="#333"
103
- infiniteGrid
104
- renderOrder={999}
105
- cellSize={settings.current.gridCellSize}
106
- sectionSize={settings.current.gridSectionSize}
107
- fadeOrigin={new Vector3()}
108
- fadeDistance={settings.current.gridFadeDistance}
109
- />
110
- {/if}
74
+ <SelectedTransformControls />
75
+
76
+ {#if !$isPresenting && settings.current.grid}
77
+ <Grid
78
+ oncreate={(ref) => {
79
+ const material = ref.material as ShaderMaterial
80
+ material.depthWrite = false
81
+ }}
82
+ raycast={() => null}
83
+ bvh={{ enabled: false }}
84
+ plane="xy"
85
+ sectionColor="#333"
86
+ infiniteGrid
87
+ renderOrder={999}
88
+ cellSize={settings.current.gridCellSize}
89
+ sectionSize={settings.current.gridSectionSize}
90
+ fadeOrigin={[0, 0, 0]}
91
+ fadeDistance={settings.current.gridFadeDistance}
92
+ />
93
+ {/if}
94
+
95
+ {#if !$isPresenting}
96
+ <Camera position={[3, 3, 3]}>
97
+ <CameraControls />
98
+ </Camera>
111
99
  {/if}
112
100
 
113
- <T.Group attach={focusedObject ? false : undefined}>
114
- <PortalTarget />
101
+ <StaticGeometries />
102
+ <Selected />
103
+
104
+ <PortalTarget />
115
105
 
116
- <Entities />
117
- <BatchedArrows />
118
- </T.Group>
106
+ <Entities />
107
+ <BatchedArrows />
119
108
 
120
109
  {@render children?.()}
121
110
 
@@ -19,13 +19,12 @@
19
19
  import { providePointclouds } from '../hooks/usePointclouds.svelte'
20
20
  import { provideRelationships } from '../hooks/useRelationships.svelte'
21
21
  import { provideResourceByName } from '../hooks/useResourceByName.svelte'
22
- import { provideSelection } from '../hooks/useSelection.svelte'
23
22
  import { provideWorldStates } from '../hooks/useWorldState.svelte'
24
23
 
25
24
  import { provideOrigin } from './xr/useOrigin.svelte'
26
25
 
27
26
  interface Props {
28
- children: Snippet<[{ focus: boolean }]>
27
+ children: Snippet
29
28
  }
30
29
 
31
30
  let { children }: Props = $props()
@@ -55,8 +54,7 @@
55
54
  provideWorldStates()
56
55
  provideFramelessComponents()
57
56
 
58
- const { focus } = provideSelection()
59
57
  provideLinkedEntities()
60
58
  </script>
61
59
 
62
- {@render children({ focus: focus.current !== undefined })}
60
+ {@render children()}
@@ -1,8 +1,6 @@
1
1
  import type { Snippet } from 'svelte';
2
2
  interface Props {
3
- children: Snippet<[{
4
- focus: boolean;
5
- }]>;
3
+ children: Snippet;
6
4
  }
7
5
  declare const SceneProviders: import("svelte").Component<Props, {}, "">;
8
6
  type SceneProviders = ReturnType<typeof SceneProviders>;
@@ -1,55 +1,48 @@
1
1
  <script lang="ts">
2
- import { isInstanceOf, T, useTask, useThrelte } from '@threlte/core'
2
+ import { T, useTask, useThrelte } from '@threlte/core'
3
3
  import { BatchedMesh, Box3 } from 'three'
4
4
  import { OBB } from 'three/addons/math/OBB.js'
5
5
 
6
- import type { InstancedArrows } from '../three/InstancedArrows/InstancedArrows'
7
-
8
- import { useSelectedEntity, useSelectedObject3d } from '../hooks/useSelection.svelte'
6
+ import { traits, useQuery } from '../ecs'
9
7
  import { OBBHelper } from '../three/OBBHelper'
10
8
 
11
9
  const box3 = new Box3()
12
10
  const obb = new OBB()
13
- const obbHelper = new OBBHelper()
14
11
 
15
- const { invalidate } = useThrelte()
16
- const selectedEntity = useSelectedEntity()
17
- const selectedObject3d = useSelectedObject3d()
12
+ const { scene, invalidate } = useThrelte()
13
+ const selected = useQuery(traits.Selected)
18
14
 
19
- const object = $derived(selectedObject3d.current)
15
+ const obbHelpers = $derived(selected.current.map((entity) => [entity, new OBBHelper()] as const))
20
16
 
21
17
  useTask(
22
18
  () => {
23
- if (object === undefined) {
24
- return
25
- }
26
-
27
- if (
28
- selectedEntity.instance &&
29
- (isInstanceOf(object, 'BatchedMesh') || (object as InstancedArrows).isInstancedArrows)
30
- ) {
31
- const mesh = object as BatchedMesh | InstancedArrows
32
- mesh.getBoundingBoxAt(selectedEntity.instance, box3)
33
- obb.fromBox3(box3)
34
- obbHelper.setFromOBB(obb)
35
- } else {
36
- obbHelper.setFromObject(object)
19
+ for (const [entity, obbHelper] of obbHelpers) {
20
+ const object = scene.getObjectByName(entity as unknown as string)
21
+ if (!object) continue
22
+
23
+ const instance = entity.get(traits.InstanceId)
24
+ if (instance !== undefined && instance >= 0) {
25
+ ;(object as BatchedMesh).getBoundingBoxAt(instance, box3)
26
+ obb.fromBox3(box3)
27
+ obbHelper.setFromOBB(obb)
28
+ } else {
29
+ obbHelper.setFromObject(object)
30
+ }
37
31
  }
38
32
 
39
33
  invalidate()
40
34
  },
41
35
  {
42
- running: () => selectedEntity.current !== undefined,
36
+ running: () => selected.current.length > 0,
43
37
  autoInvalidate: false,
44
38
  }
45
39
  )
46
40
  </script>
47
41
 
48
- {#if selectedEntity.current}
42
+ {#each obbHelpers as [entity, obbHelper] (entity)}
49
43
  <T
50
44
  is={obbHelper}
51
- dispose={false}
52
45
  raycast={() => null}
53
46
  bvh={{ enabled: false }}
54
47
  />
55
- {/if}
48
+ {/each}