@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.
- package/dist/components/App.svelte +22 -8
- package/dist/components/App.svelte.d.ts +1 -1
- package/dist/components/Camera.svelte +1 -1
- package/dist/components/CameraControls.svelte +1 -15
- package/dist/components/Focus.svelte +5 -19
- package/dist/components/MeasureTool/MeasureTool.svelte +2 -1
- package/dist/components/Scene.svelte +1 -1
- package/dist/components/SceneProviders.svelte +2 -8
- package/dist/components/SceneProviders.svelte.d.ts +0 -2
- package/dist/components/Selection/Ellipse.svelte +10 -8
- package/dist/components/Selection/Lasso.svelte +10 -8
- package/dist/components/overlay/Details.svelte +37 -12
- package/dist/components/overlay/FloatingPanel.svelte +8 -3
- package/dist/components/overlay/FloatingPanel.svelte.d.ts +5 -0
- package/dist/components/overlay/controls/Controls.svelte +40 -0
- package/dist/components/overlay/controls/Controls.svelte.d.ts +3 -0
- package/dist/components/overlay/dashboard/Button.svelte +3 -3
- package/dist/components/overlay/dashboard/Button.svelte.d.ts +1 -1
- package/dist/components/overlay/dashboard/Dashboard.svelte +15 -38
- package/dist/components/overlay/widgets/FramePov.svelte +202 -0
- package/dist/components/overlay/widgets/FramePov.svelte.d.ts +6 -0
- package/dist/ecs/hierarchy.d.ts +16 -0
- package/dist/ecs/hierarchy.js +36 -14
- package/dist/ecs/traits.js +2 -0
- package/dist/ecs/worldMatrix.js +18 -5
- package/dist/hooks/useControls.svelte.d.ts +3 -2
- package/dist/hooks/useControls.svelte.js +13 -5
- package/dist/hooks/useGeometries.svelte.js +9 -5
- package/dist/hooks/useSettings.svelte.d.ts +1 -0
- package/dist/hooks/useSettings.svelte.js +1 -0
- package/dist/plugins/Skybox/Skybox.svelte +54 -0
- package/dist/plugins/Skybox/Skybox.svelte.d.ts +12 -0
- package/dist/plugins/index.d.ts +1 -0
- package/dist/plugins/index.js +2 -0
- package/dist/three/OBBHelper.js +4 -1
- package/dist/three/arrow.js +2 -0
- package/package.json +6 -2
- /package/dist/{plugins → hooks/plugins}/bvh.svelte.d.ts +0 -0
- /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
|
|
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
|
-
|
|
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
|
|
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
|
|
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
|
|
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;
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import { CameraControls, type CameraControlsRef, Gizmo
|
|
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,
|
|
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
|
|
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 {
|
|
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
|
|
|
@@ -263,16 +263,18 @@
|
|
|
263
263
|
|
|
264
264
|
const currentControls = controls.current
|
|
265
265
|
|
|
266
|
-
|
|
266
|
+
if ('minPolarAngle' in currentControls) {
|
|
267
|
+
const { minPolarAngle, maxPolarAngle } = currentControls
|
|
267
268
|
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
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
|
-
|
|
274
|
-
|
|
275
|
-
|
|
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
|
-
|
|
247
|
+
if ('minPolarAngle' in currentControls) {
|
|
248
|
+
const { minPolarAngle, maxPolarAngle } = currentControls
|
|
248
249
|
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
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
|
-
|
|
255
|
-
|
|
256
|
-
|
|
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
|
-
|
|
338
|
+
const currentControls = controls.current
|
|
339
|
+
|
|
340
|
+
if (!currentControls || !('fitToBox' in currentControls)) return
|
|
342
341
|
|
|
343
|
-
const { azimuthAngle, polarAngle } =
|
|
342
|
+
const { azimuthAngle, polarAngle } = currentControls
|
|
344
343
|
|
|
345
|
-
|
|
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
|
-
|
|
354
|
-
|
|
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
|
|
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=
|
|
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>
|
|
@@ -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
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
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
|
|