@viamrobotics/motion-tools 1.5.0 → 1.9.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 (35) hide show
  1. package/README.md +16 -9
  2. package/dist/components/App.svelte +17 -0
  3. package/dist/components/Frame.svelte +0 -7
  4. package/dist/components/HoveredEntities.svelte +19 -0
  5. package/dist/components/HoveredEntities.svelte.d.ts +3 -0
  6. package/dist/components/HoveredEntityTooltip.svelte +241 -0
  7. package/dist/components/HoveredEntityTooltip.svelte.d.ts +7 -0
  8. package/dist/components/MeasureTool/MeasurePoint.svelte +47 -0
  9. package/dist/components/MeasureTool/MeasurePoint.svelte.d.ts +8 -0
  10. package/dist/components/MeasureTool/MeasureTool.svelte +176 -0
  11. package/dist/components/MeasureTool/MeasureTool.svelte.d.ts +3 -0
  12. package/dist/components/Overlay/Popover.svelte +28 -0
  13. package/dist/components/Overlay/Popover.svelte.d.ts +9 -0
  14. package/dist/components/Overlay/ToggleGroup.svelte +60 -0
  15. package/dist/components/Overlay/ToggleGroup.svelte.d.ts +13 -0
  16. package/dist/components/Scene.svelte +1 -1
  17. package/dist/components/Tree/Settings.svelte +23 -22
  18. package/dist/components/Tree/Widgets.svelte +44 -0
  19. package/dist/components/Tree/Widgets.svelte.d.ts +2 -17
  20. package/dist/components/dashboard/Button.svelte +7 -3
  21. package/dist/components/dashboard/Button.svelte.d.ts +3 -2
  22. package/dist/components/widgets/Camera.svelte +195 -0
  23. package/dist/components/widgets/Camera.svelte.d.ts +6 -0
  24. package/dist/ecs/traits.d.ts +18 -12
  25. package/dist/ecs/traits.js +17 -11
  26. package/dist/ecs/useQuery.svelte.js +10 -10
  27. package/dist/hooks/use3DModels.svelte.js +1 -3
  28. package/dist/hooks/useObjectEvents.svelte.d.ts +1 -0
  29. package/dist/hooks/useObjectEvents.svelte.js +24 -0
  30. package/dist/hooks/useSettings.svelte.d.ts +5 -0
  31. package/dist/hooks/useSettings.svelte.js +5 -0
  32. package/dist/hooks/useWeblabs.svelte.d.ts +1 -3
  33. package/dist/hooks/useWeblabs.svelte.js +1 -3
  34. package/dist/three/InstancedArrows/raycast.js +2 -6
  35. package/package.json +6 -2
@@ -0,0 +1,60 @@
1
+ <script lang="ts">
2
+ import { normalizeProps, useMachine } from '@zag-js/svelte'
3
+ import * as toggle from '@zag-js/toggle-group'
4
+
5
+ interface Props {
6
+ multiple: boolean
7
+ buttons: {
8
+ on?: boolean
9
+ disabled?: boolean
10
+ label?: string
11
+ value: string
12
+ }[]
13
+ onclick: (details: string[]) => void
14
+ }
15
+
16
+ let { multiple, buttons, onclick }: Props = $props()
17
+
18
+ const id = $props.id()
19
+ const service = useMachine(toggle.machine, () => ({
20
+ id,
21
+ value: buttons.filter((button) => button.on).map((button) => button.value),
22
+ multiple,
23
+ onValueChange(details) {
24
+ onclick(details.value)
25
+ },
26
+ }))
27
+ const api = $derived(toggle.connect(service, normalizeProps))
28
+ </script>
29
+
30
+ <div
31
+ class="flex items-center"
32
+ {...api.getRootProps()}
33
+ >
34
+ {#each buttons as button (button.value)}
35
+ <button
36
+ class="-ml-px flex h-5 w-5 items-center justify-center border text-xs"
37
+ {...api.getItemProps({ value: button.value })}
38
+ >
39
+ {button.label ?? button.value}
40
+ </button>
41
+ {/each}
42
+ </div>
43
+
44
+ <style>
45
+ button[data-state='on'] {
46
+ background: green;
47
+ border-color: black;
48
+ color: white;
49
+ }
50
+
51
+ button[data-disabled] {
52
+ opacity: 0.5;
53
+
54
+ filter: grayscale(100%);
55
+ }
56
+
57
+ button[data-focus] {
58
+ outline: none;
59
+ }
60
+ </style>
@@ -0,0 +1,13 @@
1
+ interface Props {
2
+ multiple: boolean;
3
+ buttons: {
4
+ on?: boolean;
5
+ disabled?: boolean;
6
+ label?: string;
7
+ value: string;
8
+ }[];
9
+ onclick: (details: string[]) => void;
10
+ }
11
+ declare const ToggleGroup: import("svelte").Component<Props, {}, "">;
12
+ type ToggleGroup = ReturnType<typeof ToggleGroup>;
13
+ export default ToggleGroup;
@@ -14,7 +14,7 @@
14
14
  import { useOrigin } from './xr/useOrigin.svelte'
15
15
  import { useSettings } from '../hooks/useSettings.svelte'
16
16
  import CameraControls from './CameraControls.svelte'
17
- import MeasureTool from './MeasureTool.svelte'
17
+ import MeasureTool from './MeasureTool/MeasureTool.svelte'
18
18
  import PointerMissBox from './PointerMissBox.svelte'
19
19
  import BatchedArrows from './BatchedArrows.svelte'
20
20
  import Arrows from './Arrows/ArrowGroups.svelte'
@@ -6,8 +6,6 @@
6
6
  import { useResourceNames } from '@viamrobotics/svelte-sdk'
7
7
  import { usePartID } from '../../hooks/usePartID.svelte'
8
8
  import { RefreshRates, useMachineSettings } from '../../hooks/useMachineSettings.svelte'
9
- import WeblabActive from '../weblab/WeblabActive.svelte'
10
- import { WEBLABS_EXPERIMENTS } from '../../hooks/useWeblabs.svelte'
11
9
  import { useGeometries } from '../../hooks/useGeometries.svelte'
12
10
  import { usePointClouds } from '../../hooks/usePointclouds.svelte'
13
11
  import { useThrelte } from '@threlte/core'
@@ -195,26 +193,29 @@
195
193
  <label class="flex items-center justify-between gap-2">
196
194
  Render stats <Switch bind:on={settings.current.renderStats} />
197
195
  </label>
198
- <WeblabActive experiment={WEBLABS_EXPERIMENTS.MOTION_TOOLS_RENDER_ARM_MODELS}>
199
- <label class="flex items-center justify-between gap-2">
200
- Render Arm Models
201
- <Select
202
- value={settings.current.renderArmModels}
203
- onchange={(event: InputEvent) => {
204
- if (event.target instanceof HTMLSelectElement) {
205
- settings.current.renderArmModels = event.target.value as
206
- | 'colliders'
207
- | 'colliders+model'
208
- | 'model'
209
- }
210
- }}
211
- >
212
- <option value="colliders">Colliders</option>
213
- <option value="colliders+model">Colliders + Model</option>
214
- <option value="model">Model</option>
215
- </Select>
216
- </label>
217
- </WeblabActive>
196
+ <label class="flex items-center justify-between gap-2">
197
+ Render sub-entity hover detail <Switch
198
+ bind:on={settings.current.renderSubEntityHoverDetail}
199
+ />
200
+ </label>
201
+ <label class="flex items-center justify-between gap-2">
202
+ Render Arm Models
203
+ <Select
204
+ value={settings.current.renderArmModels}
205
+ onchange={(event: InputEvent) => {
206
+ if (event.target instanceof HTMLSelectElement) {
207
+ settings.current.renderArmModels = event.target.value as
208
+ | 'colliders'
209
+ | 'colliders+model'
210
+ | 'model'
211
+ }
212
+ }}
213
+ >
214
+ <option value="colliders">Colliders</option>
215
+ <option value="colliders+model">Colliders + Model</option>
216
+ <option value="model">Model</option>
217
+ </Select>
218
+ </label>
218
219
  </div>
219
220
  </div>
220
221
  </Drawer>
@@ -2,8 +2,20 @@
2
2
  import { Switch } from '@viamrobotics/prime-core'
3
3
  import Drawer from './Drawer.svelte'
4
4
  import { useSettings } from '../../hooks/useSettings.svelte'
5
+ import { useResourceByName } from '../../hooks/useResourceByName.svelte'
6
+ import { usePartID } from '../../hooks/usePartID.svelte'
5
7
 
6
8
  const settings = useSettings()
9
+ const resourceByName = useResourceByName()
10
+ const partID = usePartID()
11
+
12
+ const cameras = $derived(
13
+ Object.values(resourceByName.current).filter((resource) => resource?.subtype === 'camera')
14
+ )
15
+
16
+ const currentRobotCameraWidgets = $derived(
17
+ settings.current.openCameraWidgets[partID.current] || []
18
+ )
7
19
  </script>
8
20
 
9
21
  <Drawer name="Widgets">
@@ -17,5 +29,37 @@
17
29
  }}
18
30
  />
19
31
  </div>
32
+
33
+ <div class="mt-4">
34
+ <h3 class="text-sm"><strong>Camera Widgets</strong></h3>
35
+ {#each cameras as camera (camera?.name)}
36
+ {#if camera}
37
+ {@const isOpen = currentRobotCameraWidgets.includes(camera.name)}
38
+ <div class="flex items-center justify-between gap-4 py-2">
39
+ {camera.name}
40
+ <Switch
41
+ on={isOpen}
42
+ on:change={(event) => {
43
+ if (event.detail) {
44
+ settings.current.openCameraWidgets = {
45
+ ...settings.current.openCameraWidgets,
46
+ [partID.current]: [...currentRobotCameraWidgets, camera.name],
47
+ }
48
+ } else {
49
+ settings.current.openCameraWidgets = {
50
+ ...settings.current.openCameraWidgets,
51
+ [partID.current]: currentRobotCameraWidgets.filter(
52
+ (widget) => widget !== camera.name
53
+ ),
54
+ }
55
+ }
56
+ }}
57
+ />
58
+ </div>
59
+ {/if}
60
+ {:else}
61
+ <div class="py-2">No cameras detected</div>
62
+ {/each}
63
+ </div>
20
64
  </div>
21
65
  </Drawer>
@@ -1,18 +1,3 @@
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 Widgets: $$__sveltets_2_IsomorphicComponent<Record<string, never>, {
15
- [evt: string]: CustomEvent<any>;
16
- }, {}, {}, string>;
17
- type Widgets = InstanceType<typeof Widgets>;
1
+ declare const Widgets: import("svelte").Component<Record<string, never>, {}, "">;
2
+ type Widgets = ReturnType<typeof Widgets>;
18
3
  export default Widgets;
@@ -1,14 +1,15 @@
1
1
  <script lang="ts">
2
2
  import { Icon, type IconName, Tooltip } from '@viamrobotics/prime-core'
3
3
  import { Ruler } from 'lucide-svelte'
4
- import type { ClassValue, MouseEventHandler } from 'svelte/elements'
4
+ import type { ClassValue, HTMLButtonAttributes, MouseEventHandler } from 'svelte/elements'
5
5
 
6
- interface Props {
6
+ interface Props extends HTMLButtonAttributes {
7
7
  icon: IconName | 'ruler'
8
8
  active?: boolean
9
9
  description: string
10
10
  hotkey?: string
11
11
  class?: ClassValue | null | undefined
12
+ tooltipLocation?: 'bottom' | 'right'
12
13
  onclick?: MouseEventHandler<HTMLButtonElement> | null | undefined
13
14
  }
14
15
 
@@ -18,13 +19,15 @@
18
19
  description,
19
20
  hotkey = '',
20
21
  class: className = '',
22
+ tooltipLocation,
21
23
  onclick,
24
+ ...rest
22
25
  }: Props = $props()
23
26
  </script>
24
27
 
25
28
  <Tooltip
26
29
  let:tooltipID
27
- location="bottom"
30
+ location={tooltipLocation ?? 'bottom'}
28
31
  >
29
32
  <label
30
33
  class={[
@@ -40,6 +43,7 @@
40
43
  aria-label={description}
41
44
  aria-checked={active}
42
45
  {onclick}
46
+ {...rest}
43
47
  >
44
48
  {#if icon === 'ruler'}
45
49
  <Ruler size="16" />
@@ -1,11 +1,12 @@
1
1
  import { type IconName } from '@viamrobotics/prime-core';
2
- import type { ClassValue, MouseEventHandler } from 'svelte/elements';
3
- interface Props {
2
+ import type { ClassValue, HTMLButtonAttributes, MouseEventHandler } from 'svelte/elements';
3
+ interface Props extends HTMLButtonAttributes {
4
4
  icon: IconName | 'ruler';
5
5
  active?: boolean;
6
6
  description: string;
7
7
  hotkey?: string;
8
8
  class?: ClassValue | null | undefined;
9
+ tooltipLocation?: 'bottom' | 'right';
9
10
  onclick?: MouseEventHandler<HTMLButtonElement> | null | undefined;
10
11
  }
11
12
  declare const Button: import("svelte").Component<Props, {}, "">;
@@ -0,0 +1,195 @@
1
+ <script lang="ts">
2
+ import { draggable } from '@neodrag/svelte'
3
+ import { Icon, Select } from '@viamrobotics/prime-core'
4
+ import { CameraStream, useRobotClient } from '@viamrobotics/svelte-sdk'
5
+ import { StreamClient } from '@viamrobotics/sdk'
6
+ import { useSettings } from '../../hooks/useSettings.svelte'
7
+ import { usePartID } from '../../hooks/usePartID.svelte'
8
+ import { useEnvironment } from '../../hooks/useEnvironment.svelte'
9
+
10
+ interface Resolution {
11
+ width: number
12
+ height: number
13
+ }
14
+
15
+ const { name, ...rest } = $props<{ name: string }>()
16
+
17
+ const settings = useSettings()
18
+ const partID = usePartID()
19
+ const client = useRobotClient(() => partID.current)
20
+ const environment = useEnvironment()
21
+
22
+ let dragElement = $state.raw<HTMLElement>()
23
+ let aspectRatio = $state.raw<number | undefined>(undefined)
24
+ let fps = $state(0)
25
+ let resolutions = $state<Resolution[]>([])
26
+ let currentResolution = $state<string>('')
27
+ let isLoading = $state(true)
28
+ let error = $state<string | undefined>(undefined)
29
+
30
+ let fpsInterval: ReturnType<typeof setInterval> | undefined
31
+ let fpsCounterActive = false
32
+
33
+ // Cleanup on destroy
34
+ $effect(() => {
35
+ return () => {
36
+ if (fpsInterval) clearInterval(fpsInterval)
37
+ fpsCounterActive = false
38
+ }
39
+ })
40
+
41
+ const onMediaLoad = (e: Event) => {
42
+ const target = e.target as HTMLVideoElement
43
+
44
+ // Update aspect ratio
45
+ if (target.videoWidth && target.videoHeight) {
46
+ aspectRatio = target.videoWidth / target.videoHeight
47
+ }
48
+
49
+ // Start FPS counter
50
+ if ('requestVideoFrameCallback' in target) {
51
+ if (fpsInterval) clearInterval(fpsInterval)
52
+ fpsCounterActive = false
53
+
54
+ let frameCount = 0
55
+ fpsCounterActive = true
56
+
57
+ const onFrame = () => {
58
+ if (!fpsCounterActive) return
59
+ frameCount++
60
+ target.requestVideoFrameCallback(onFrame)
61
+ }
62
+ target.requestVideoFrameCallback(onFrame)
63
+
64
+ // Update FPS state every 500ms
65
+ fpsInterval = setInterval(() => {
66
+ // FPS = frames / 0.5s = frames * 2
67
+ fps = frameCount * 2
68
+ frameCount = 0
69
+ }, 500)
70
+ }
71
+ }
72
+
73
+ // Create a single StreamClient instance per robot client
74
+ let streamClient = $derived(client.current ? new StreamClient(client.current) : undefined)
75
+
76
+ $effect(() => {
77
+ if (streamClient) {
78
+ isLoading = true
79
+ error = undefined
80
+ streamClient
81
+ .getOptions(name)
82
+ .then((options) => {
83
+ resolutions = options.map((opt) => ({ width: opt.width, height: opt.height }))
84
+ isLoading = false
85
+ })
86
+ .catch((e) => {
87
+ error = e instanceof Error ? e.message : 'Failed to get stream options'
88
+ isLoading = false
89
+ })
90
+ }
91
+ })
92
+
93
+ const handleResolutionChange = async (e: Event) => {
94
+ const target = e.target as HTMLSelectElement
95
+ if (!target.value || !streamClient) return
96
+
97
+ const [w, h] = target.value.split('x').map(Number)
98
+ if (isNaN(w) || isNaN(h)) return
99
+
100
+ try {
101
+ await streamClient.setOptions(name, w, h)
102
+ error = undefined
103
+ } catch (err) {
104
+ error = err instanceof Error ? err.message : 'Failed to set resolution'
105
+ }
106
+ }
107
+ </script>
108
+
109
+ <div
110
+ class="bg-extralight border-medium absolute top-0 left-0 z-1000 m-2 flex resize-x flex-col overflow-hidden border text-xs"
111
+ style:width="320px"
112
+ style:height="auto !important"
113
+ use:draggable={{
114
+ bounds: 'body',
115
+ handle: dragElement,
116
+ }}
117
+ {...rest}
118
+ >
119
+ <div class="flex h-full min-w-0 flex-col">
120
+ <div class="flex w-full shrink-0 items-center justify-between">
121
+ <div class="border-medium flex w-full items-center gap-1 border-b p-2">
122
+ <button bind:this={dragElement}>
123
+ <Icon name="drag" />
124
+ </button>
125
+ <h3 class="min-w-0 truncate">{name}</h3>
126
+ <div class="flex-1"></div>
127
+
128
+ {#if isLoading}
129
+ <span class="text-subtle mr-2">Loading...</span>
130
+ {:else if resolutions.length > 0}
131
+ <div class="mr-2 w-32">
132
+ <Select
133
+ bind:value={currentResolution}
134
+ onchange={handleResolutionChange}
135
+ >
136
+ <option value="">Default</option>
137
+ {#each resolutions as res (`${res.width}x${res.height}`)}
138
+ <option value={`${res.width}x${res.height}`}>{res.width}x{res.height}</option>
139
+ {/each}
140
+ </Select>
141
+ </div>
142
+ {/if}
143
+
144
+ <button
145
+ aria-label="close"
146
+ class="hover:text-default"
147
+ onclick={() => {
148
+ const widgets = settings.current.openCameraWidgets[partID.current] || []
149
+ settings.current.openCameraWidgets = {
150
+ ...settings.current.openCameraWidgets,
151
+ [partID.current]: widgets.filter((widget) => widget !== name),
152
+ }
153
+ }}
154
+ >
155
+ <Icon
156
+ name="close"
157
+ size="xs"
158
+ />
159
+ </button>
160
+ </div>
161
+ </div>
162
+
163
+ <div
164
+ class="relative min-h-0 w-full flex-1 overflow-hidden bg-black [&_img]:h-full [&_img]:w-full [&_img]:object-fill [&_video]:h-full [&_video]:w-full [&_video]:object-fill"
165
+ style:aspect-ratio={aspectRatio}
166
+ >
167
+ {#key environment.current.viewerMode === 'monitor'}
168
+ <CameraStream
169
+ {name}
170
+ partID={partID.current}
171
+ onloadedmetadata={onMediaLoad}
172
+ onload={onMediaLoad}
173
+ />
174
+ {/key}
175
+
176
+ <!-- FPS Pill -->
177
+ {#if fps > 0}
178
+ <div
179
+ class="absolute bottom-2 left-2 z-10 rounded-[3px] bg-black/30 px-1 py-0.5 text-right font-mono text-xs text-white"
180
+ >
181
+ {fps.toFixed(1)}fps
182
+ </div>
183
+ {/if}
184
+
185
+ <!-- Error display -->
186
+ {#if error}
187
+ <div
188
+ class="absolute inset-0 flex items-center justify-center bg-black/50 p-2 text-center text-white"
189
+ >
190
+ {error}
191
+ </div>
192
+ {/if}
193
+ </div>
194
+ </div>
195
+ </div>
@@ -0,0 +1,6 @@
1
+ type $$ComponentProps = {
2
+ name: string;
3
+ };
4
+ declare const Camera: import("svelte").Component<$$ComponentProps, {}, "">;
5
+ type Camera = ReturnType<typeof Camera>;
6
+ export default Camera;
@@ -30,11 +30,17 @@ export declare const Center: import("koota").Trait<{
30
30
  oZ: number;
31
31
  theta: number;
32
32
  }>;
33
+ export declare const Hover: import("koota").Trait<{
34
+ index: number;
35
+ x: number;
36
+ y: number;
37
+ z: number;
38
+ }>;
33
39
  /**
34
40
  * Represents that an entity is composed of many instances, so that the treeview and
35
41
  * details panel may display all instances
36
42
  */
37
- export declare const Instanced: import("koota").TagTrait;
43
+ export declare const Instanced: import("koota").Trait<() => boolean>;
38
44
  export declare const Instance: import("koota").Trait<{
39
45
  meshID: number;
40
46
  instanceID: number;
@@ -49,7 +55,7 @@ export declare const Color: import("koota").Trait<{
49
55
  g: number;
50
56
  b: number;
51
57
  }>;
52
- export declare const Arrow: import("koota").TagTrait;
58
+ export declare const Arrow: import("koota").Trait<() => boolean>;
53
59
  export declare const Positions: import("koota").Trait<() => Float32Array<ArrayBuffer>>;
54
60
  export declare const Colors: import("koota").Trait<() => Uint8Array<ArrayBuffer>>;
55
61
  export declare const Instances: import("koota").Trait<{
@@ -61,7 +67,7 @@ export declare const Arrows: import("koota").Trait<{
61
67
  /**
62
68
  * Render entity as points
63
69
  */
64
- export declare const Points: import("koota").TagTrait;
70
+ export declare const Points: import("koota").Trait<() => boolean>;
65
71
  /**
66
72
  * A box, in mm
67
73
  */
@@ -108,15 +114,15 @@ export declare const Scale: import("koota").Trait<{
108
114
  y: number;
109
115
  z: number;
110
116
  }>;
111
- export declare const FramesAPI: import("koota").TagTrait;
112
- export declare const GeometriesAPI: import("koota").TagTrait;
113
- export declare const DrawAPI: import("koota").TagTrait;
114
- export declare const WorldStateStoreAPI: import("koota").TagTrait;
115
- export declare const SnapshotAPI: import("koota").TagTrait;
117
+ export declare const FramesAPI: import("koota").Trait<() => boolean>;
118
+ export declare const GeometriesAPI: import("koota").Trait<() => boolean>;
119
+ export declare const DrawAPI: import("koota").Trait<() => boolean>;
120
+ export declare const WorldStateStoreAPI: import("koota").Trait<() => boolean>;
121
+ export declare const SnapshotAPI: import("koota").Trait<() => boolean>;
116
122
  /**
117
123
  * Marker trait for entities created from user-dropped files (PLY, PCD, etc.)
118
124
  */
119
- export declare const DroppedFile: import("koota").TagTrait;
125
+ export declare const DroppedFile: import("koota").Trait<() => boolean>;
120
126
  /**
121
127
  * Point size, in mm
122
128
  */
@@ -125,12 +131,12 @@ export declare const PointSize: import("koota").Trait<() => number>;
125
131
  * Line width, in mm
126
132
  */
127
133
  export declare const LineWidth: import("koota").Trait<() => number>;
128
- export declare const ReferenceFrame: import("koota").TagTrait;
134
+ export declare const ReferenceFrame: import("koota").Trait<() => boolean>;
129
135
  /**
130
136
  * This entity can be safetly removed from the scene by the user
131
137
  */
132
- export declare const Removable: import("koota").TagTrait;
133
- export declare const Geometry: (geometry: ViamGeometry) => import("koota").TagTrait | [import("koota").Trait<{
138
+ export declare const Removable: import("koota").Trait<() => boolean>;
139
+ export declare const Geometry: (geometry: ViamGeometry) => import("koota").Trait<() => boolean> | [import("koota").Trait<{
134
140
  x: number;
135
141
  y: number;
136
142
  z: number;
@@ -8,11 +8,17 @@ export const Parent = trait(() => 'world');
8
8
  export const Pose = trait({ x: 0, y: 0, z: 0, oX: 0, oY: 0, oZ: 1, theta: 0 });
9
9
  export const EditedPose = trait({ x: 0, y: 0, z: 0, oX: 0, oY: 0, oZ: 1, theta: 0 });
10
10
  export const Center = trait({ x: 0, y: 0, z: 0, oX: 0, oY: 0, oZ: 1, theta: 0 });
11
+ export const Hover = trait({
12
+ index: -1, // Sub-entity index, -1 if not applicable
13
+ x: 0, // World position X in meters
14
+ y: 0, // World position Y in meters
15
+ z: 0, // World position Z in meters
16
+ });
11
17
  /**
12
18
  * Represents that an entity is composed of many instances, so that the treeview and
13
19
  * details panel may display all instances
14
20
  */
15
- export const Instanced = trait();
21
+ export const Instanced = trait(() => true);
16
22
  export const Instance = trait({
17
23
  meshID: -1,
18
24
  instanceID: -1,
@@ -23,7 +29,7 @@ export const Opacity = trait(() => 1);
23
29
  * @default { r: 1, g: 0, b: 0 }
24
30
  */
25
31
  export const Color = trait({ r: 0, g: 0, b: 0 });
26
- export const Arrow = trait();
32
+ export const Arrow = trait(() => true);
27
33
  export const Positions = trait(() => new Float32Array());
28
34
  export const Colors = trait(() => new Uint8Array());
29
35
  export const Instances = trait({
@@ -35,7 +41,7 @@ export const Arrows = trait({
35
41
  /**
36
42
  * Render entity as points
37
43
  */
38
- export const Points = trait();
44
+ export const Points = trait(() => true);
39
45
  /**
40
46
  * A box, in mm
41
47
  */
@@ -59,15 +65,15 @@ export const GLTF = trait(() => ({
59
65
  animationName: '',
60
66
  }));
61
67
  export const Scale = trait({ x: 1, y: 1, z: 1 });
62
- export const FramesAPI = trait();
63
- export const GeometriesAPI = trait();
64
- export const DrawAPI = trait();
65
- export const WorldStateStoreAPI = trait();
66
- export const SnapshotAPI = trait();
68
+ export const FramesAPI = trait(() => true);
69
+ export const GeometriesAPI = trait(() => true);
70
+ export const DrawAPI = trait(() => true);
71
+ export const WorldStateStoreAPI = trait(() => true);
72
+ export const SnapshotAPI = trait(() => true);
67
73
  /**
68
74
  * Marker trait for entities created from user-dropped files (PLY, PCD, etc.)
69
75
  */
70
- export const DroppedFile = trait();
76
+ export const DroppedFile = trait(() => true);
71
77
  // === Shape Properties ===
72
78
  /**
73
79
  * Point size, in mm
@@ -77,11 +83,11 @@ export const PointSize = trait(() => 10);
77
83
  * Line width, in mm
78
84
  */
79
85
  export const LineWidth = trait(() => 5);
80
- export const ReferenceFrame = trait();
86
+ export const ReferenceFrame = trait(() => true);
81
87
  /**
82
88
  * This entity can be safetly removed from the scene by the user
83
89
  */
84
- export const Removable = trait();
90
+ export const Removable = trait(() => true);
85
91
  export const Geometry = (geometry) => {
86
92
  if (geometry.geometryType.case === 'box') {
87
93
  return Box(createBox(geometry.geometryType.value));
@@ -1,29 +1,29 @@
1
1
  import { untrack } from 'svelte';
2
- import { $internal as internal, cacheQuery } from 'koota';
2
+ import { $internal as internal, createQuery } from 'koota';
3
3
  import { useWorld } from './useWorld';
4
4
  export function useQuery(...parameters) {
5
5
  const world = useWorld();
6
- const hash = cacheQuery(...parameters);
6
+ const createdQuery = createQuery(...parameters);
7
7
  // Using internals to get the query data.
8
- const query = world[internal].queriesHashMap.get(hash);
8
+ const query = world[internal].queriesHashMap.get(createdQuery.hash);
9
9
  const initialQueryVersion = query?.version;
10
10
  let version = $state.raw(0);
11
- let entities = $state.raw(world.query(hash));
11
+ let entities = $state.raw(world.query(createdQuery));
12
12
  $effect(() => {
13
13
  // eslint-disable-next-line @typescript-eslint/no-unused-expressions
14
14
  version;
15
15
  // Compare the initial version to the current version to
16
16
  // see it the query has changed.
17
- const query = world[internal].queriesHashMap.get(hash);
17
+ const query = world[internal].queriesHashMap.get(createdQuery.hash);
18
18
  if (query?.version !== initialQueryVersion) {
19
- entities = world.query(hash);
19
+ entities = world.query(createdQuery);
20
20
  }
21
21
  return untrack(() => {
22
- const unsubAdd = world.onQueryAdd(hash, () => {
23
- entities = world.query(hash);
22
+ const unsubAdd = world.onQueryAdd(createdQuery, () => {
23
+ entities = world.query(createdQuery);
24
24
  });
25
- const unsubRemove = world.onQueryRemove(hash, () => {
26
- entities = world.query(hash);
25
+ const unsubRemove = world.onQueryRemove(createdQuery, () => {
26
+ entities = world.query(createdQuery);
27
27
  });
28
28
  return () => {
29
29
  unsubAdd();