@viamrobotics/motion-tools 1.27.0 → 1.28.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 (39) hide show
  1. package/dist/components/App.svelte +22 -8
  2. package/dist/components/App.svelte.d.ts +1 -1
  3. package/dist/components/Camera.svelte +1 -1
  4. package/dist/components/CameraControls.svelte +1 -15
  5. package/dist/components/Focus.svelte +5 -19
  6. package/dist/components/MeasureTool/MeasureTool.svelte +2 -1
  7. package/dist/components/Scene.svelte +1 -1
  8. package/dist/components/SceneProviders.svelte +2 -8
  9. package/dist/components/SceneProviders.svelte.d.ts +0 -2
  10. package/dist/components/Selection/Ellipse.svelte +10 -8
  11. package/dist/components/Selection/Lasso.svelte +10 -8
  12. package/dist/components/overlay/Details.svelte +37 -12
  13. package/dist/components/overlay/FloatingPanel.svelte +8 -3
  14. package/dist/components/overlay/FloatingPanel.svelte.d.ts +5 -0
  15. package/dist/components/overlay/controls/Controls.svelte +40 -0
  16. package/dist/components/overlay/controls/Controls.svelte.d.ts +3 -0
  17. package/dist/components/overlay/dashboard/Button.svelte +3 -3
  18. package/dist/components/overlay/dashboard/Button.svelte.d.ts +1 -1
  19. package/dist/components/overlay/dashboard/Dashboard.svelte +15 -38
  20. package/dist/components/overlay/widgets/FramePov.svelte +202 -0
  21. package/dist/components/overlay/widgets/FramePov.svelte.d.ts +6 -0
  22. package/dist/ecs/hierarchy.d.ts +16 -0
  23. package/dist/ecs/hierarchy.js +36 -14
  24. package/dist/ecs/traits.js +2 -0
  25. package/dist/ecs/worldMatrix.js +18 -5
  26. package/dist/hooks/useControls.svelte.d.ts +3 -2
  27. package/dist/hooks/useControls.svelte.js +13 -5
  28. package/dist/hooks/useGeometries.svelte.js +9 -5
  29. package/dist/hooks/useSettings.svelte.d.ts +1 -0
  30. package/dist/hooks/useSettings.svelte.js +1 -0
  31. package/dist/plugins/Skybox/Skybox.svelte +54 -0
  32. package/dist/plugins/Skybox/Skybox.svelte.d.ts +12 -0
  33. package/dist/plugins/index.d.ts +1 -0
  34. package/dist/plugins/index.js +2 -0
  35. package/dist/three/OBBHelper.js +4 -1
  36. package/dist/three/arrow.js +2 -0
  37. package/package.json +6 -2
  38. /package/dist/{plugins → hooks/plugins}/bvh.svelte.d.ts +0 -0
  39. /package/dist/{plugins → hooks/plugins}/bvh.svelte.js +0 -0
@@ -8,15 +8,16 @@
8
8
  import { PortalTarget } from '@threlte/extras'
9
9
  import { useXR } from '@threlte/xr'
10
10
  import { provideToast, ToastContainer } from '@viamrobotics/prime-core'
11
+ import { ThemeUtils } from 'svelte-tweakpane-ui'
11
12
 
12
- import type { CameraPose } from '../hooks/useControls.svelte'
13
-
13
+ import Controls from './overlay/controls/Controls.svelte'
14
14
  import Dashboard from './overlay/dashboard/Dashboard.svelte'
15
15
  import Details from './overlay/Details.svelte'
16
16
  import TreeContainer from './overlay/left-pane/TreeContainer.svelte'
17
17
  import Settings from './overlay/settings/Settings.svelte'
18
18
  import XR from './xr/XR.svelte'
19
19
  import { provideWorld } from '../ecs'
20
+ import { type CameraPose, provideCameraControls } from '../hooks/useControls.svelte'
20
21
  import {
21
22
  type DrawConnectionConfig,
22
23
  provideDrawConnectionConfig,
@@ -35,6 +36,7 @@
35
36
  import Logs from './overlay/Logs.svelte'
36
37
  import ArmPositions from './overlay/widgets/ArmPositions.svelte'
37
38
  import Camera from './overlay/widgets/Camera.svelte'
39
+ import FramePov from './overlay/widgets/FramePov.svelte'
38
40
  import Scene from './Scene.svelte'
39
41
  import SceneProviders from './SceneProviders.svelte'
40
42
 
@@ -88,12 +90,10 @@
88
90
  const settings = provideSettings()
89
91
  const environment = provideEnvironment()
90
92
  const currentRobotCameraWidgets = $derived(settings.current.openCameraWidgets[partID] || [])
93
+ const currentFramePovWidgets = $derived(settings.current.openFramePovWidgets[partID] || [])
91
94
  const { isPresenting } = useXR()
92
95
 
93
- $effect(() => {
94
- environment.current.inputBindingsEnabled = inputBindingsEnabled
95
- })
96
-
96
+ provideCameraControls(() => cameraPose)
97
97
  createPartIDContext(() => partID)
98
98
  provideDrawConnectionConfig(() => drawConnectionConfig)
99
99
  provideWeblabs()
@@ -106,9 +106,18 @@
106
106
  () => localConfigProps
107
107
  )
108
108
 
109
- $effect.pre(() => {
109
+ $effect(() => {
110
+ environment.current.inputBindingsEnabled = inputBindingsEnabled
110
111
  environment.current.isStandalone = !localConfigProps
111
112
  })
113
+
114
+ $effect(() => {
115
+ ThemeUtils.setGlobalDefaultTheme({
116
+ ...ThemeUtils.presets.light,
117
+ baseBackgroundColor: '#fbfbfc',
118
+ baseShadowColor: 'transparent',
119
+ })
120
+ })
112
121
  </script>
113
122
 
114
123
  {#if settings.current.enableQueryDevtools}
@@ -123,7 +132,7 @@
123
132
  renderMode="on-demand"
124
133
  dpr={[1, 2]}
125
134
  >
126
- <SceneProviders {cameraPose}>
135
+ <SceneProviders>
127
136
  {#snippet children({ focus })}
128
137
  <Scene>
129
138
  {@render appChildren?.()}
@@ -139,6 +148,7 @@
139
148
  <div {@attach domPortal(root)}>
140
149
  <FileDrop />
141
150
  <Dashboard {dashboard} />
151
+ <Controls />
142
152
  <Details {details} />
143
153
 
144
154
  {#if environment.current.isStandalone}
@@ -157,6 +167,10 @@
157
167
  {#each currentRobotCameraWidgets as cameraName (cameraName)}
158
168
  <Camera name={cameraName} />
159
169
  {/each}
170
+
171
+ {#each currentFramePovWidgets as povFrameName (povFrameName)}
172
+ <FramePov frameName={povFrameName} />
173
+ {/each}
160
174
  {/if}
161
175
 
162
176
  <PortalTarget id="dom" />
@@ -1,7 +1,7 @@
1
1
  import type { Struct } from '@viamrobotics/sdk';
2
2
  import type { Entity } from 'koota';
3
3
  import type { Snippet } from 'svelte';
4
- import type { CameraPose } from '../hooks/useControls.svelte';
4
+ import { type CameraPose } from '../hooks/useControls.svelte';
5
5
  import { type DrawConnectionConfig } from '../hooks/useDrawConnectionConfig.svelte';
6
6
  interface LocalConfigProps {
7
7
  current: Struct;
@@ -12,7 +12,7 @@
12
12
  {#if mode === 'perspective'}
13
13
  <T.PerspectiveCamera
14
14
  makeDefault
15
- near={0.01}
15
+ near={0.001}
16
16
  up={[0, 0, 1]}
17
17
  oncreate={(ref) => {
18
18
  ref.lookAt(0, 0, 0)
@@ -1,8 +1,7 @@
1
1
  <script lang="ts">
2
- import { CameraControls, type CameraControlsRef, Gizmo, Portal } from '@threlte/extras'
2
+ import { CameraControls, type CameraControlsRef, Gizmo } from '@threlte/extras'
3
3
  import { MathUtils } from 'three'
4
4
 
5
- import Button from './overlay/dashboard/Button.svelte'
6
5
  import { useCameraControls, useTransformControls } from '../hooks/useControls.svelte'
7
6
  import { useEnvironment } from '../hooks/useEnvironment.svelte'
8
7
 
@@ -15,19 +14,6 @@
15
14
  const inputBindingsEnabled = $derived(environment.current.inputBindingsEnabled)
16
15
  </script>
17
16
 
18
- <Portal id="dashboard">
19
- <fieldset>
20
- <Button
21
- active
22
- icon="camera-outline"
23
- description="Reset camera"
24
- onclick={() => {
25
- cameraControls.setInitialPose()
26
- }}
27
- />
28
- </fieldset>
29
- </Portal>
30
-
31
17
  <CameraControls
32
18
  enabled={!transformControls.active}
33
19
  oncreate={(ref) => {
@@ -1,10 +1,9 @@
1
1
  <script lang="ts">
2
2
  import { T } from '@threlte/core'
3
- import { Gizmo, Portal, TrackballControls } from '@threlte/extras'
3
+ import { Gizmo, TrackballControls } from '@threlte/extras'
4
4
  import { Box3, type Object3D, Vector3 } from 'three'
5
- import { TrackballControls as ThreeTrackballControls } from 'three/examples/jsm/controls/TrackballControls.js'
6
5
 
7
- import Button from './overlay/dashboard/Button.svelte'
6
+ import { useCameraControls } from '../hooks/useControls.svelte'
8
7
 
9
8
  import Camera from './Camera.svelte'
10
9
 
@@ -14,14 +13,14 @@
14
13
 
15
14
  let { object3d }: Props = $props()
16
15
 
16
+ const cameraControls = useCameraControls()
17
+
17
18
  const box = new Box3()
18
19
  const vec = new Vector3()
19
20
 
20
21
  let center = $state.raw<[number, number, number]>([0, 0, 0])
21
22
  let size = $state.raw<[number, number, number]>([0, 0, 0])
22
23
 
23
- let controls = $state.raw<ThreeTrackballControls>()
24
-
25
24
  $effect.pre(() => {
26
25
  box.setFromObject(object3d)
27
26
  size = box.getSize(vec).toArray()
@@ -29,23 +28,10 @@
29
28
  })
30
29
  </script>
31
30
 
32
- <Portal id="dashboard">
33
- <fieldset>
34
- <Button
35
- active
36
- icon="camera-outline"
37
- description="Reset camera"
38
- onclick={() => {
39
- controls?.reset()
40
- }}
41
- />
42
- </fieldset>
43
- </Portal>
44
-
45
31
  <Camera position={[size[0] + 1, size[0] + 1, size[0] + 1]}>
46
32
  <TrackballControls
47
- bind:ref={controls}
48
33
  target={center}
34
+ oncreate={(ref) => cameraControls.set(ref)}
49
35
  >
50
36
  <Gizmo placement="bottom-right" />
51
37
  </TrackballControls>
@@ -84,6 +84,7 @@
84
84
  <div class="flex">
85
85
  <Button
86
86
  active={enabled}
87
+ class="rounded-r-none"
87
88
  icon="ruler"
88
89
  description="{enabled ? 'Disable' : 'Enable'} measurement"
89
90
  onclick={() => {
@@ -95,7 +96,7 @@
95
96
  <Button
96
97
  {...triggerProps}
97
98
  active={enabled}
98
- class="border-l-0"
99
+ class="rounded-l-none border-l-0"
99
100
  icon="filter-sliders"
100
101
  description="Measurement settings"
101
102
  />
@@ -12,9 +12,9 @@
12
12
  import Selected from './Selected.svelte'
13
13
  import SelectedTransformControls from './SelectedTransformControls.svelte'
14
14
  import StaticGeometries from './StaticGeometries.svelte'
15
+ import { bvh } from '../hooks/plugins/bvh.svelte'
15
16
  import { useFocusedObject3d } from '../hooks/useSelection.svelte'
16
17
  import { useSettings } from '../hooks/useSettings.svelte'
17
- import { bvh } from '../plugins/bvh.svelte'
18
18
 
19
19
  import hdrImage from '../assets/ferndale_studio_11_1k.hdr'
20
20
  import BatchedArrows from './BatchedArrows.svelte'
@@ -6,11 +6,7 @@
6
6
  import { provideArmClient } from '../hooks/useArmClient.svelte'
7
7
  import { provideArmKinematics } from '../hooks/useArmKinematics.svelte'
8
8
  import { provideConfigFrames } from '../hooks/useConfigFrames.svelte'
9
- import {
10
- type CameraPose,
11
- provideCameraControls,
12
- provideTransformControls,
13
- } from '../hooks/useControls.svelte'
9
+ import { provideTransformControls } from '../hooks/useControls.svelte'
14
10
  import { provideDrawAPI } from '../hooks/useDrawAPI.svelte'
15
11
  import { provideDrawService } from '../hooks/useDrawService.svelte'
16
12
  import { provideFrameEditSession } from '../hooks/useFrameEditSession.svelte'
@@ -30,15 +26,13 @@
30
26
  import { provideOrigin } from './xr/useOrigin.svelte'
31
27
 
32
28
  interface Props {
33
- cameraPose?: CameraPose
34
29
  children: Snippet<[{ focus: boolean }]>
35
30
  }
36
31
 
37
- let { cameraPose, children }: Props = $props()
32
+ let { children }: Props = $props()
38
33
 
39
34
  const partID = usePartID()
40
35
 
41
- provideCameraControls(() => cameraPose)
42
36
  provideTransformControls()
43
37
  provideLogs()
44
38
 
@@ -1,7 +1,5 @@
1
1
  import type { Snippet } from 'svelte';
2
- import { type CameraPose } from '../hooks/useControls.svelte';
3
2
  interface Props {
4
- cameraPose?: CameraPose;
5
3
  children: Snippet<[{
6
4
  focus: boolean;
7
5
  }]>;
@@ -263,16 +263,18 @@
263
263
 
264
264
  const currentControls = controls.current
265
265
 
266
- const { minPolarAngle, maxPolarAngle } = currentControls
266
+ if ('minPolarAngle' in currentControls) {
267
+ const { minPolarAngle, maxPolarAngle } = currentControls
267
268
 
268
- // Locks the camera to top down while this component is mounted
269
- currentControls.polarAngle = 0
270
- currentControls.minPolarAngle = 0
271
- currentControls.maxPolarAngle = 0
269
+ // Locks the camera to top down while this component is mounted
270
+ currentControls.polarAngle = 0
271
+ currentControls.minPolarAngle = 0
272
+ currentControls.maxPolarAngle = 0
272
273
 
273
- return () => {
274
- currentControls.minPolarAngle = minPolarAngle
275
- currentControls.maxPolarAngle = maxPolarAngle
274
+ return () => {
275
+ currentControls.minPolarAngle = minPolarAngle
276
+ currentControls.maxPolarAngle = maxPolarAngle
277
+ }
276
278
  }
277
279
  })
278
280
 
@@ -244,16 +244,18 @@
244
244
 
245
245
  const currentControls = controls.current
246
246
 
247
- const { minPolarAngle, maxPolarAngle } = currentControls
247
+ if ('minPolarAngle' in currentControls) {
248
+ const { minPolarAngle, maxPolarAngle } = currentControls
248
249
 
249
- // Locks the camera to top down while this component is mounted
250
- currentControls.polarAngle = 0
251
- currentControls.minPolarAngle = 0
252
- currentControls.maxPolarAngle = 0
250
+ // Locks the camera to top down while this component is mounted
251
+ currentControls.polarAngle = 0
252
+ currentControls.minPolarAngle = 0
253
+ currentControls.maxPolarAngle = 0
253
254
 
254
- return () => {
255
- currentControls.minPolarAngle = minPolarAngle
256
- currentControls.maxPolarAngle = maxPolarAngle
255
+ return () => {
256
+ currentControls.minPolarAngle = minPolarAngle
257
+ currentControls.maxPolarAngle = maxPolarAngle
258
+ }
257
259
  }
258
260
  })
259
261
 
@@ -2,7 +2,6 @@
2
2
  module
3
3
  lang="ts"
4
4
  >
5
- import { ThemeUtils } from 'svelte-tweakpane-ui'
6
5
  import { BufferAttribute, Euler, MathUtils, Quaternion } from 'three'
7
6
 
8
7
  import { OrientationVector } from '../../three/OrientationVector'
@@ -46,6 +45,7 @@
46
45
  import { useEnvironment } from '../../hooks/useEnvironment.svelte'
47
46
  import { useLinkedEntities } from '../../hooks/useLinked.svelte'
48
47
  import { usePartConfig } from '../../hooks/usePartConfig.svelte'
48
+ import { usePartID } from '../../hooks/usePartID.svelte'
49
49
  import { useResourceByName } from '../../hooks/useResourceByName.svelte'
50
50
  import {
51
51
  useFocusedEntity,
@@ -53,6 +53,7 @@
53
53
  useSelectedEntity,
54
54
  useSelectedObject3d,
55
55
  } from '../../hooks/useSelection.svelte'
56
+ import { useSettings } from '../../hooks/useSettings.svelte'
56
57
  import { createPose, matrixToPose } from '../../transform'
57
58
 
58
59
  interface Props {
@@ -68,6 +69,8 @@
68
69
  const resourceByName = useResourceByName()
69
70
  const configFrames = useConfigFrames()
70
71
  const partConfig = usePartConfig()
72
+ const partID = usePartID()
73
+ const settings = useSettings()
71
74
  const selectedEntity = useSelectedEntity()
72
75
  const selectedObject3d = useSelectedObject3d()
73
76
  const environment = useEnvironment()
@@ -280,12 +283,6 @@
280
283
  2
281
284
  )
282
285
  }
283
-
284
- ThemeUtils.setGlobalDefaultTheme({
285
- ...ThemeUtils.presets.light,
286
- baseBackgroundColor: '#fbfbfc',
287
- baseShadowColor: 'transparent',
288
- })
289
286
  </script>
290
287
 
291
288
  {#snippet ImmutableField({
@@ -338,11 +335,13 @@
338
335
  onclick={() => {
339
336
  const padding = 0.4
340
337
 
341
- if (!controls.current) return
338
+ const currentControls = controls.current
339
+
340
+ if (!currentControls || !('fitToBox' in currentControls)) return
342
341
 
343
- const { azimuthAngle, polarAngle } = controls.current
342
+ const { azimuthAngle, polarAngle } = currentControls
344
343
 
345
- controls.current.fitToBox(object3d, true, {
344
+ currentControls.fitToBox(object3d, true, {
346
345
  paddingTop: padding,
347
346
  paddingBottom: padding,
348
347
  paddingLeft: padding,
@@ -350,8 +349,8 @@
350
349
  })
351
350
 
352
351
  // Preserve previous rotation
353
- controls.current?.rotateAzimuthTo(azimuthAngle, true)
354
- controls.current?.rotatePolarTo(polarAngle, true)
352
+ currentControls.rotateAzimuthTo(azimuthAngle, true)
353
+ currentControls.rotatePolarTo(polarAngle, true)
355
354
  }}
356
355
  >
357
356
  <Icon name="image-filter-center-focus" />
@@ -360,6 +359,32 @@
360
359
  </Tooltip>
361
360
  {/if}
362
361
 
362
+ {#if name.current}
363
+ <Tooltip
364
+ let:tooltipID
365
+ location="bottom"
366
+ >
367
+ <button
368
+ class="text-subtle-2"
369
+ aria-describedby={tooltipID}
370
+ aria-label="Open view from this frame"
371
+ onclick={() => {
372
+ const frameName = name.current
373
+ if (!frameName) return
374
+ const list = settings.current.openFramePovWidgets[partID.current] ?? []
375
+ if (list.includes(frameName)) return
376
+ settings.current.openFramePovWidgets = {
377
+ ...settings.current.openFramePovWidgets,
378
+ [partID.current]: [...list, frameName],
379
+ }
380
+ }}
381
+ >
382
+ <Icon name="camera-outline" />
383
+ </button>
384
+ <p slot="description">View from this frame</p>
385
+ </Tooltip>
386
+ {/if}
387
+
363
388
  {#if removable.current}
364
389
  <Tooltip
365
390
  let:tooltipID
@@ -1,5 +1,6 @@
1
1
  <script lang="ts">
2
2
  import type { Snippet } from 'svelte'
3
+ import type { ClassValue } from 'svelte/elements'
3
4
 
4
5
  import { useThrelte } from '@threlte/core'
5
6
  import { Icon } from '@viamrobotics/prime-core'
@@ -14,6 +15,9 @@
14
15
  resizable?: boolean
15
16
  persistRect?: boolean
16
17
  isOpen?: boolean
18
+ bodyClass?: ClassValue
19
+ onPositionChange?: (details: floatingPanel.PositionChangeDetails) => void
20
+ onSizeChange?: (details: floatingPanel.SizeChangeDetails) => void
17
21
  children: Snippet
18
22
  }
19
23
 
@@ -25,6 +29,7 @@
25
29
  resizable = false,
26
30
  persistRect = true,
27
31
  isOpen = $bindable(false),
32
+ bodyClass = 'bg-white',
28
33
  children,
29
34
  ...props
30
35
  }: Props = $props()
@@ -56,7 +61,7 @@
56
61
  >
57
62
  <div
58
63
  {...api.getContentProps()}
59
- class="border-medium border-1 bg-white dark:text-black"
64
+ class="border-medium border-1 dark:text-black"
60
65
  >
61
66
  <div
62
67
  {...api.getDragTriggerProps()}
@@ -64,7 +69,7 @@
64
69
  >
65
70
  <div
66
71
  {...api.getHeaderProps()}
67
- class="border-medium flex items-center justify-between border-b p-2"
72
+ class="border-medium flex items-center justify-between border-b bg-white p-2"
68
73
  >
69
74
  <h3
70
75
  {...api.getTitleProps()}
@@ -97,7 +102,7 @@
97
102
  -->
98
103
  <div
99
104
  {...api.getBodyProps()}
100
- class="relative h-[calc(100%-33px)]"
105
+ class={['relative h-[calc(100%-33px)]', bodyClass]}
101
106
  >
102
107
  {#if isOpen}
103
108
  {@render children()}
@@ -1,4 +1,6 @@
1
1
  import type { Snippet } from 'svelte';
2
+ import type { ClassValue } from 'svelte/elements';
3
+ import * as floatingPanel from '@zag-js/floating-panel';
2
4
  interface Props {
3
5
  title?: string;
4
6
  defaultSize?: {
@@ -13,6 +15,9 @@ interface Props {
13
15
  resizable?: boolean;
14
16
  persistRect?: boolean;
15
17
  isOpen?: boolean;
18
+ bodyClass?: ClassValue;
19
+ onPositionChange?: (details: floatingPanel.PositionChangeDetails) => void;
20
+ onSizeChange?: (details: floatingPanel.SizeChangeDetails) => void;
16
21
  children: Snippet;
17
22
  }
18
23
  declare const FloatingPanel: import("svelte").Component<Props, {}, "isOpen">;
@@ -0,0 +1,40 @@
1
+ <script lang="ts">
2
+ import { PortalTarget } from '@threlte/extras'
3
+
4
+ import Button from '../dashboard/Button.svelte'
5
+ import { useCameraControls } from '../../../hooks/useControls.svelte'
6
+ import { useSettings } from '../../../hooks/useSettings.svelte'
7
+
8
+ const settings = useSettings()
9
+ const cameraControls = useCameraControls()
10
+
11
+ const isOrthographic = $derived(settings.current.cameraMode === 'orthographic')
12
+ </script>
13
+
14
+ <div class="absolute right-2 bottom-26 z-4 flex flex-col items-end gap-2">
15
+ <PortalTarget id="controls" />
16
+
17
+ <fieldset class="flex flex-col">
18
+ <Button
19
+ active
20
+ class="rounded-b-none"
21
+ icon="camera-outline"
22
+ description="Reset camera"
23
+ tooltipLocation="left"
24
+ onclick={() => {
25
+ cameraControls.setInitialPose()
26
+ }}
27
+ />
28
+ <Button
29
+ active
30
+ class="-my-0.5 rounded-t-none"
31
+ icon={isOrthographic ? 'grid-orthographic' : 'grid-perspective'}
32
+ description={isOrthographic ? 'Switch to perspective view' : 'Switch to orthographic view'}
33
+ hotkey="C"
34
+ tooltipLocation="left"
35
+ onclick={() => {
36
+ settings.current.cameraMode = isOrthographic ? 'perspective' : 'orthographic'
37
+ }}
38
+ />
39
+ </fieldset>
40
+ </div>
@@ -0,0 +1,3 @@
1
+ declare const Controls: import("svelte").Component<Record<string, never>, {}, "">;
2
+ type Controls = ReturnType<typeof Controls>;
3
+ export default Controls;
@@ -10,7 +10,7 @@
10
10
  description: string
11
11
  hotkey?: string
12
12
  class?: ClassValue | null | undefined
13
- tooltipLocation?: 'bottom' | 'right'
13
+ tooltipLocation?: 'bottom' | 'right' | 'left' | 'top'
14
14
  onclick?: MouseEventHandler<HTMLButtonElement> | null | undefined
15
15
  }
16
16
 
@@ -33,13 +33,13 @@
33
33
  <label
34
34
  class={[
35
35
  className,
36
- 'relative block border',
36
+ 'relative block rounded-md border',
37
37
  active ? 'border-gray-5 text-gray-8 z-4 bg-white' : 'bg-light border-medium text-disabled',
38
38
  ]}
39
39
  aria-describedby={tooltipID}
40
40
  >
41
41
  <button
42
- class="p-1.5"
42
+ class=" p-1.5"
43
43
  role="radio"
44
44
  aria-label={description}
45
45
  aria-checked={active}
@@ -6,7 +6,7 @@ interface Props extends HTMLButtonAttributes {
6
6
  description: string;
7
7
  hotkey?: string;
8
8
  class?: ClassValue | null | undefined;
9
- tooltipLocation?: 'bottom' | 'right';
9
+ tooltipLocation?: 'bottom' | 'right' | 'left' | 'top';
10
10
  onclick?: MouseEventHandler<HTMLButtonElement> | null | undefined;
11
11
  }
12
12
  declare const Button: import("svelte").Component<Props, {}, "">;
@@ -14,33 +14,11 @@
14
14
  class="absolute top-2 z-4 flex w-full items-center justify-center gap-2"
15
15
  {...rest}
16
16
  >
17
- <!-- camera view -->
18
- <fieldset class="flex">
19
- <Button
20
- icon="grid-orthographic"
21
- active={settings.current.cameraMode === 'orthographic'}
22
- description="Orthographic view"
23
- hotkey="C"
24
- onclick={() => {
25
- settings.current.cameraMode = 'orthographic'
26
- }}
27
- />
28
- <Button
29
- icon="grid-perspective"
30
- active={settings.current.cameraMode === 'perspective'}
31
- description="Perspective view"
32
- hotkey="C"
33
- class="-ml-px"
34
- onclick={() => {
35
- settings.current.cameraMode = 'perspective'
36
- }}
37
- />
38
- </fieldset>
39
-
40
17
  <!-- transform -->
41
18
  <fieldset class="flex">
42
19
  <Button
43
20
  icon="mouse-pointer"
21
+ class="rounded-r-none"
44
22
  active={settings.current.transformMode === 'none'}
45
23
  description="No transform controls"
46
24
  hotkey="0"
@@ -50,30 +28,30 @@
50
28
  />
51
29
  <Button
52
30
  icon="cursor-move"
31
+ class="-ml-px rounded-none"
53
32
  active={settings.current.transformMode === 'translate'}
54
33
  description="Translate"
55
34
  hotkey="1"
56
- class="-ml-px"
57
35
  onclick={() => {
58
36
  settings.current.transformMode = 'translate'
59
37
  }}
60
38
  />
61
39
  <Button
62
40
  icon="sync"
41
+ class="-ml-px rounded-none"
63
42
  active={settings.current.transformMode === 'rotate'}
64
43
  description="Rotate"
65
44
  hotkey="2"
66
- class="-ml-px"
67
45
  onclick={() => {
68
46
  settings.current.transformMode = 'rotate'
69
47
  }}
70
48
  />
71
49
  <Button
72
50
  icon="resize"
51
+ class="-ml-px rounded-l-none"
73
52
  active={settings.current.transformMode === 'scale'}
74
53
  description="Scale"
75
54
  hotkey="3"
76
- class="-ml-px"
77
55
  onclick={() => {
78
56
  settings.current.transformMode = 'scale'
79
57
  }}
@@ -81,18 +59,17 @@
81
59
  </fieldset>
82
60
 
83
61
  <!-- snapping -->
84
- {#if settings.current.transformMode !== 'none'}
85
- <fieldset class="flex">
86
- <Button
87
- icon={settings.current.snapping ? 'magnet' : 'magnet-off'}
88
- active={settings.current.snapping}
89
- description="Snapping"
90
- onclick={() => {
91
- settings.current.snapping = !settings.current.snapping
92
- }}
93
- />
94
- </fieldset>
95
- {/if}
62
+
63
+ <fieldset class="flex">
64
+ <Button
65
+ icon={settings.current.snapping ? 'magnet' : 'magnet-off'}
66
+ active={settings.current.snapping}
67
+ description="Snapping"
68
+ onclick={() => {
69
+ settings.current.snapping = !settings.current.snapping
70
+ }}
71
+ />
72
+ </fieldset>
96
73
 
97
74
  <PortalTarget id="dashboard" />
98
75