@viamrobotics/motion-tools 1.22.0 → 1.23.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/README.md +18 -100
- package/dist/components/App.svelte +3 -3
- package/dist/components/App.svelte.d.ts +1 -1
- package/dist/components/CameraControls.svelte +6 -6
- package/dist/components/{KeyboardControls.svelte → InputBindings.svelte} +50 -77
- package/dist/components/InputBindings.svelte.d.ts +7 -0
- package/dist/components/overlay/Details.svelte +34 -1
- package/dist/hooks/useEnvironment.svelte.d.ts +1 -0
- package/dist/hooks/useEnvironment.svelte.js +1 -0
- package/dist/hooks/useFrames.svelte.js +10 -5
- package/dist/hooks/useSettings.svelte.d.ts +0 -1
- package/dist/hooks/useSettings.svelte.js +0 -1
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/package.json +6 -4
- package/dist/components/KeyboardControls.svelte.d.ts +0 -7
package/README.md
CHANGED
|
@@ -1,119 +1,37 @@
|
|
|
1
|
-
#
|
|
1
|
+
# Viam Visualization
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
3D visualization interface for spatial data using Viam's APIs — frame systems, geometries, point clouds, drawings — for motion-related monitoring, testing, and debugging.
|
|
4
4
|
|
|
5
|
-
##
|
|
5
|
+
## Documentation
|
|
6
6
|
|
|
7
|
-
|
|
8
|
-
to your machines if required.
|
|
7
|
+
📚 **[viamrobotics.github.io/visualization](https://viamrobotics.github.io/visualization/)** is the canonical guide. It covers:
|
|
9
8
|
|
|
10
|
-
|
|
9
|
+
- [Running locally](https://viamrobotics.github.io/visualization/guides/local-usage/) — set up the app and drive it from Go via `client/api`.
|
|
10
|
+
- [Embedding `<MotionTools />`](https://viamrobotics.github.io/visualization/guides/embedding/) — drop the visualizer into your own Svelte app.
|
|
11
|
+
- [Implementing WorldStateStoreService](https://viamrobotics.github.io/visualization/guides/worldstatestore/) — produce `Transform`s for a Viam WSS module with `draw`.
|
|
12
|
+
- API reference for [`client/api`](https://viamrobotics.github.io/visualization/api/client-api/) and [`draw`](https://viamrobotics.github.io/visualization/api/draw/).
|
|
13
|
+
- [v1 → v2 migration guide](https://viamrobotics.github.io/visualization/migration/v1-to-v2/).
|
|
14
|
+
- A live [playground](https://viamrobotics.github.io/visualization/playground/) rendering a baked snapshot.
|
|
11
15
|
|
|
12
|
-
|
|
16
|
+
## Quick start
|
|
13
17
|
|
|
14
18
|
```bash
|
|
15
|
-
make setup
|
|
19
|
+
make setup # one-time: install Node 22, pnpm, bun, Go, buf, project deps
|
|
20
|
+
make up # http://localhost:5173
|
|
16
21
|
```
|
|
17
22
|
|
|
18
|
-
|
|
23
|
+
For manual setup, machine configs, multiple instances, and troubleshooting see the [local-usage guide](https://viamrobotics.github.io/visualization/guides/local-usage/).
|
|
19
24
|
|
|
20
|
-
|
|
21
|
-
2. Install **pnpm** package manager
|
|
22
|
-
3. Install **bun** runtime
|
|
23
|
-
4. Install **Go** and **buf** (for protobuf generation)
|
|
24
|
-
5. Install all project dependencies
|
|
25
|
-
6. Generate protobuf code
|
|
25
|
+
## Contributing
|
|
26
26
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
#### Manual setup
|
|
30
|
-
|
|
31
|
-
If the above does not work for you, or if you prefer to install dependencies manually:
|
|
32
|
-
|
|
33
|
-
1. [Install fnm](https://github.com/Schniz/fnm#installation): `curl -fsSL https://fnm.vercel.app/install | bash`
|
|
34
|
-
2. Install Node.js: `fnm install 22 && fnm use 22`
|
|
35
|
-
3. [Install pnpm](https://pnpm.io/installation): `curl -fsSL https://get.pnpm.io/install.sh | sh -`
|
|
36
|
-
4. [Install bun](https://bun.sh/docs/installation): `curl -fsSL https://bun.sh/install | bash`
|
|
37
|
-
5. [Install Go](https://go.dev/doc/install)
|
|
38
|
-
6. [Install buf](https://buf.build/docs/installation): download from GitHub releases
|
|
39
|
-
7. Install Go tools: `go install google.golang.org/protobuf/cmd/protoc-gen-go@latest`
|
|
40
|
-
8. Install dependencies: `pnpm install`
|
|
41
|
-
9. Generate protobufs: `make proto`
|
|
42
|
-
|
|
43
|
-
### Env files for machine configs
|
|
44
|
-
|
|
45
|
-
To add a list of connection configs in an `.env.local` file, use the following format:
|
|
46
|
-
|
|
47
|
-
```
|
|
48
|
-
VITE_CONFIGS='
|
|
49
|
-
{
|
|
50
|
-
"fleet-rover-01": {
|
|
51
|
-
"host": "fleet-rover-01-main.ve4ba7w5qr.viam.cloud",
|
|
52
|
-
"partId": "myPartID",
|
|
53
|
-
"apiKeyId": "myApiKeyId",
|
|
54
|
-
"apiKeyValue": "MyApiKeyValue",
|
|
55
|
-
"signalingAddress": "https://app.viam.com:443"
|
|
56
|
-
}
|
|
57
|
-
}
|
|
58
|
-
'
|
|
59
|
-
```
|
|
60
|
-
|
|
61
|
-
### Running the app locally
|
|
62
|
-
|
|
63
|
-
After setup completes, you can start a local app server with:
|
|
27
|
+
Run the dev server with HMR:
|
|
64
28
|
|
|
65
29
|
```bash
|
|
66
|
-
make up
|
|
67
|
-
```
|
|
68
|
-
|
|
69
|
-
This starts the app as a static site. The build part of the process will only run if you have not built the app yet as a part of `make up`, or your build is out of date.
|
|
70
|
-
|
|
71
|
-
#### Running multiple apps
|
|
72
|
-
|
|
73
|
-
If you want to be able to run multiple versions of the app, you can configure how the servers run. The `make up` command can accept two options:
|
|
74
|
-
|
|
75
|
-
1. `STATIC_PORT` is the port for the static file server, and defaults to `5173`
|
|
76
|
-
2. `WS_PORT` is the port for the websocket server used to communicate with the draw client API
|
|
77
|
-
|
|
78
|
-
> [!NOTE]
|
|
79
|
-
> The `WS_PORT` is not fully configurable at the moment, so passing it will only affect where the frontend listens for the websocket server, but calls with the draw client API are currently hardcoded to point to `"http://localhost:3000/"`. If this is a feature you require, please submit a request to the viz team!
|
|
80
|
-
|
|
81
|
-
To run two apps using the same web socket server, run:
|
|
82
|
-
|
|
83
|
-
```
|
|
84
|
-
# in one terminal
|
|
85
|
-
make up
|
|
86
|
-
|
|
87
|
-
# in another terminal
|
|
88
|
-
make up STATIC_PORT=5174
|
|
89
|
-
```
|
|
90
|
-
|
|
91
|
-
The apps should be available on `http://localhost:5173/` and `http://localhost:5174/`, and calls to the draw client API should render in both.
|
|
92
|
-
|
|
93
|
-
### Local development
|
|
94
|
-
|
|
95
|
-
If you are contributing to `motion-tools`, you should just run the development web server with:
|
|
96
|
-
|
|
97
|
-
```
|
|
98
30
|
pnpm dev
|
|
99
31
|
```
|
|
100
32
|
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
To visit the visualizer, go to `http://localhost:5173/`
|
|
104
|
-
|
|
105
|
-
Open the machine config page (bottom right) and enter in connection details to visualize a specific machine. You can also add machine configs from an env file (see below).
|
|
106
|
-
|
|
107
|
-
## Executing drawing commands
|
|
108
|
-
|
|
109
|
-
The visualizer includes a golang package that allows executing commands to the visualizer.
|
|
110
|
-
|
|
111
|
-
The list of available commands [can be found here](https://pkg.go.dev/github.com/viam-labs/motion-tools@v0.9.0/client/client).
|
|
33
|
+
See [CLAUDE.md](CLAUDE.md) for contributor conventions.
|
|
112
34
|
|
|
113
35
|
## Programmatic camera control
|
|
114
36
|
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
To do this, open the Javascript console while using the visualizer and call methods or set properties on the `cameraControls` object.
|
|
118
|
-
|
|
119
|
-
The following APIs are available: https://github.com/yomotsu/camera-controls?tab=readme-ov-file#properties
|
|
37
|
+
The visualizer exposes a `cameraControls` object on `window`. Open the browser console and call methods on it to move the camera or tweak its settings at runtime. Full API: <https://github.com/yomotsu/camera-controls#properties>.
|
|
@@ -47,7 +47,7 @@
|
|
|
47
47
|
|
|
48
48
|
interface Props {
|
|
49
49
|
partID?: string
|
|
50
|
-
|
|
50
|
+
inputBindingsEnabled?: boolean
|
|
51
51
|
localConfigProps?: LocalConfigProps
|
|
52
52
|
drawConnectionConfig?: DrawConnectionConfig
|
|
53
53
|
|
|
@@ -74,7 +74,7 @@
|
|
|
74
74
|
|
|
75
75
|
let {
|
|
76
76
|
partID = '',
|
|
77
|
-
|
|
77
|
+
inputBindingsEnabled = true,
|
|
78
78
|
localConfigProps,
|
|
79
79
|
cameraPose,
|
|
80
80
|
drawConnectionConfig,
|
|
@@ -91,7 +91,7 @@
|
|
|
91
91
|
const { isPresenting } = useXR()
|
|
92
92
|
|
|
93
93
|
$effect(() => {
|
|
94
|
-
|
|
94
|
+
environment.current.inputBindingsEnabled = inputBindingsEnabled
|
|
95
95
|
})
|
|
96
96
|
|
|
97
97
|
createPartIDContext(() => partID)
|
|
@@ -4,15 +4,15 @@
|
|
|
4
4
|
|
|
5
5
|
import Button from './overlay/dashboard/Button.svelte'
|
|
6
6
|
import { useCameraControls, useTransformControls } from '../hooks/useControls.svelte'
|
|
7
|
-
import {
|
|
7
|
+
import { useEnvironment } from '../hooks/useEnvironment.svelte'
|
|
8
8
|
|
|
9
|
-
import
|
|
9
|
+
import InputBindings from './InputBindings.svelte'
|
|
10
10
|
|
|
11
11
|
const cameraControls = useCameraControls()
|
|
12
|
-
const
|
|
12
|
+
const environment = useEnvironment()
|
|
13
13
|
const transformControls = useTransformControls()
|
|
14
14
|
|
|
15
|
-
const
|
|
15
|
+
const inputBindingsEnabled = $derived(environment.current.inputBindingsEnabled)
|
|
16
16
|
</script>
|
|
17
17
|
|
|
18
18
|
<Portal id="dashboard">
|
|
@@ -37,8 +37,8 @@
|
|
|
37
37
|
}}
|
|
38
38
|
>
|
|
39
39
|
{#snippet children({ ref }: { ref: CameraControlsRef })}
|
|
40
|
-
{#if
|
|
41
|
-
<
|
|
40
|
+
{#if inputBindingsEnabled}
|
|
41
|
+
<InputBindings cameraControls={ref} />
|
|
42
42
|
{/if}
|
|
43
43
|
<Gizmo placement="bottom-right" />
|
|
44
44
|
{/snippet}
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
import type { CameraControlsRef } from '@threlte/extras'
|
|
3
3
|
|
|
4
4
|
import { isInstanceOf, useTask } from '@threlte/core'
|
|
5
|
+
import { useGamepad, useInputMap, useKeyboard } from '@threlte/extras'
|
|
5
6
|
import { PressedKeys } from 'runed'
|
|
6
7
|
import { MathUtils, Vector3 } from 'three'
|
|
7
8
|
|
|
@@ -22,19 +23,33 @@
|
|
|
22
23
|
|
|
23
24
|
const settings = useSettings()
|
|
24
25
|
|
|
25
|
-
const
|
|
26
|
-
const
|
|
27
|
-
const
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
26
|
+
const keyboard = useKeyboard()
|
|
27
|
+
const gamepad = useGamepad()
|
|
28
|
+
const input = useInputMap(
|
|
29
|
+
({ key, gamepadAxis, gamepadButton }) => ({
|
|
30
|
+
truckLeft: [key('a'), gamepadAxis('leftStick', 'x', -1)],
|
|
31
|
+
truckRight: [key('d'), gamepadAxis('leftStick', 'x', 1)],
|
|
32
|
+
forward: [key('w'), gamepadAxis('leftStick', 'y', -1)],
|
|
33
|
+
backward: [key('s'), gamepadAxis('leftStick', 'y', 1)],
|
|
34
|
+
dollyIn: [key('r'), gamepadButton('rightBumper')],
|
|
35
|
+
dollyOut: [key('f'), gamepadButton('leftBumper')],
|
|
36
|
+
rotateLeft: [key('arrowleft'), gamepadAxis('rightStick', 'x', -1)],
|
|
37
|
+
rotateRight: [key('arrowright'), gamepadAxis('rightStick', 'x', 1)],
|
|
38
|
+
tiltUp: [key('arrowup'), gamepadAxis('rightStick', 'y', 1)],
|
|
39
|
+
tiltDown: [key('arrowdown'), gamepadAxis('rightStick', 'y', -1)],
|
|
40
|
+
}),
|
|
41
|
+
{ keyboard, gamepad }
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
const truckAxis = $derived(input.axis('truckLeft', 'truckRight'))
|
|
45
|
+
const forwardAxis = $derived(input.axis('backward', 'forward'))
|
|
46
|
+
const dollyAxis = $derived(input.axis('dollyOut', 'dollyIn'))
|
|
47
|
+
const yawAxis = $derived(input.axis('rotateLeft', 'rotateRight'))
|
|
48
|
+
const pitchAxis = $derived(input.axis('tiltUp', 'tiltDown'))
|
|
49
|
+
|
|
50
|
+
const anyKeysPressed = $derived(
|
|
51
|
+
truckAxis !== 0 || forwardAxis !== 0 || dollyAxis !== 0 || yawAxis !== 0 || pitchAxis !== 0
|
|
52
|
+
)
|
|
38
53
|
|
|
39
54
|
const target = new Vector3()
|
|
40
55
|
|
|
@@ -70,7 +85,7 @@
|
|
|
70
85
|
const dt = delta * 1000
|
|
71
86
|
|
|
72
87
|
// Disallow keyboard navigation if the user is holding down the meta key
|
|
73
|
-
if (meta) {
|
|
88
|
+
if (keyboard.key('meta').pressed) {
|
|
74
89
|
return
|
|
75
90
|
}
|
|
76
91
|
|
|
@@ -80,64 +95,41 @@
|
|
|
80
95
|
const dollySpeed = 0.005 * dt
|
|
81
96
|
const zoomSpeed = 0.5 * dt
|
|
82
97
|
|
|
83
|
-
if (
|
|
84
|
-
cameraControls.truck(
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
if (d) {
|
|
88
|
-
cameraControls.truck(moveSpeed * dt, 0, true)
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
if (w) {
|
|
92
|
-
cameraControls.forward(moveSpeed * dt, true)
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
if (s) {
|
|
96
|
-
cameraControls.forward(-moveSpeed * dt, true)
|
|
98
|
+
if (truckAxis !== 0) {
|
|
99
|
+
cameraControls.truck(truckAxis * moveSpeed * dt, 0, true)
|
|
97
100
|
}
|
|
98
101
|
|
|
99
|
-
if (
|
|
100
|
-
|
|
101
|
-
cameraControls.dolly(dollySpeed, true)
|
|
102
|
-
} else {
|
|
103
|
-
cameraControls.zoom(zoomSpeed, true)
|
|
104
|
-
}
|
|
102
|
+
if (forwardAxis !== 0) {
|
|
103
|
+
cameraControls.forward(forwardAxis * moveSpeed * dt, true)
|
|
105
104
|
}
|
|
106
105
|
|
|
107
|
-
if (
|
|
106
|
+
if (dollyAxis !== 0) {
|
|
108
107
|
if (isInstanceOf(cameraControls.camera, 'PerspectiveCamera')) {
|
|
109
|
-
cameraControls.dolly(
|
|
108
|
+
cameraControls.dolly(dollyAxis * dollySpeed, true)
|
|
110
109
|
} else {
|
|
111
|
-
cameraControls.zoom(
|
|
110
|
+
cameraControls.zoom(dollyAxis * zoomSpeed, true)
|
|
112
111
|
}
|
|
113
112
|
}
|
|
114
113
|
|
|
115
|
-
if (
|
|
116
|
-
cameraControls.rotate(
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
if (right) {
|
|
120
|
-
cameraControls.rotate(rotateSpeed, 0, true)
|
|
114
|
+
if (yawAxis !== 0) {
|
|
115
|
+
cameraControls.rotate(yawAxis * rotateSpeed, 0, true)
|
|
121
116
|
}
|
|
122
117
|
|
|
123
|
-
if (
|
|
124
|
-
cameraControls.rotate(0,
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
if (down) {
|
|
128
|
-
cameraControls.rotate(0, tiltSpeed, true)
|
|
118
|
+
if (pitchAxis !== 0) {
|
|
119
|
+
cameraControls.rotate(0, pitchAxis * tiltSpeed, true)
|
|
129
120
|
}
|
|
130
121
|
},
|
|
131
122
|
{
|
|
123
|
+
after: input.task,
|
|
132
124
|
running: () => anyKeysPressed,
|
|
133
125
|
autoInvalidate: false,
|
|
134
126
|
}
|
|
135
127
|
)
|
|
136
128
|
|
|
129
|
+
const keys = new PressedKeys()
|
|
130
|
+
|
|
137
131
|
keys.onKeys('escape', () => {
|
|
138
|
-
|
|
139
|
-
focusedEntity.set()
|
|
140
|
-
}
|
|
132
|
+
focusedEntity.set()
|
|
141
133
|
})
|
|
142
134
|
|
|
143
135
|
keys.onKeys('c', () => {
|
|
@@ -157,30 +149,11 @@
|
|
|
157
149
|
settings.current.transformMode = 'scale'
|
|
158
150
|
})
|
|
159
151
|
|
|
160
|
-
keys.onKeys('
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
* Handler for any keybindings that need to access the event object
|
|
166
|
-
*/
|
|
167
|
-
const onkeydown = (event: KeyboardEvent) => {
|
|
168
|
-
const key = event.key.toLowerCase()
|
|
169
|
-
|
|
170
|
-
if (key === 'h') {
|
|
171
|
-
if (!entity) return
|
|
172
|
-
|
|
173
|
-
event.stopImmediatePropagation()
|
|
174
|
-
|
|
175
|
-
if (entity.has(traits.Invisible)) {
|
|
176
|
-
entity.remove(traits.Invisible)
|
|
177
|
-
} else {
|
|
178
|
-
entity.add(traits.Invisible)
|
|
179
|
-
}
|
|
180
|
-
|
|
181
|
-
return
|
|
152
|
+
keys.onKeys('h', () => {
|
|
153
|
+
if (entity?.has(traits.Invisible)) {
|
|
154
|
+
entity.remove(traits.Invisible)
|
|
155
|
+
} else {
|
|
156
|
+
entity?.add(traits.Invisible)
|
|
182
157
|
}
|
|
183
|
-
}
|
|
158
|
+
})
|
|
184
159
|
</script>
|
|
185
|
-
|
|
186
|
-
<svelte:window {onkeydown} />
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { CameraControlsRef } from '@threlte/extras';
|
|
2
|
+
interface Props {
|
|
3
|
+
cameraControls: CameraControlsRef;
|
|
4
|
+
}
|
|
5
|
+
declare const InputBindings: import("svelte").Component<Props, {}, "">;
|
|
6
|
+
type InputBindings = ReturnType<typeof InputBindings>;
|
|
7
|
+
export default InputBindings;
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
import type { Snippet } from 'svelte'
|
|
19
19
|
|
|
20
20
|
import { draggable } from '@neodrag/svelte'
|
|
21
|
-
import { isInstanceOf, useTask } from '@threlte/core'
|
|
21
|
+
import { isInstanceOf, useTask, useThrelte } from '@threlte/core'
|
|
22
22
|
import { Button, Icon, Tooltip } from '@viamrobotics/prime-core'
|
|
23
23
|
import { Check, Copy } from 'lucide-svelte'
|
|
24
24
|
import {
|
|
@@ -62,6 +62,7 @@
|
|
|
62
62
|
const { details }: Props = $props()
|
|
63
63
|
|
|
64
64
|
const world = useWorld()
|
|
65
|
+
const { invalidate } = useThrelte()
|
|
65
66
|
const drawService = useDrawService()
|
|
66
67
|
const controls = useCameraControls()
|
|
67
68
|
const resourceByName = useResourceByName()
|
|
@@ -86,6 +87,7 @@
|
|
|
86
87
|
const removable = useTrait(() => entity, traits.Removable)
|
|
87
88
|
const points = useTrait(() => entity, traits.Points)
|
|
88
89
|
const arrows = useTrait(() => entity, traits.Arrows)
|
|
90
|
+
const opacity = useTrait(() => entity, traits.Opacity)
|
|
89
91
|
|
|
90
92
|
const framesAPI = useTrait(() => entity, traits.FramesAPI)
|
|
91
93
|
const isFrameNode = $derived(!!framesAPI.current)
|
|
@@ -197,6 +199,23 @@
|
|
|
197
199
|
detailConfigUpdater.updateGeometry(entity, { type: 'capsule', l: event.detail.value })
|
|
198
200
|
}
|
|
199
201
|
|
|
202
|
+
const opacityValue = $derived(opacity.current ?? 1)
|
|
203
|
+
|
|
204
|
+
const handleOpacityChange = (event: SliderChangeEvent) => {
|
|
205
|
+
if (event.detail.origin !== 'internal' || !entity) return
|
|
206
|
+
const next = event.detail.value
|
|
207
|
+
// No trait === fully opaque, so drop the trait when the user returns to 1
|
|
208
|
+
// instead of leaving an Opacity(1) entry on the entity.
|
|
209
|
+
if (next >= 1) {
|
|
210
|
+
entity.remove(traits.Opacity)
|
|
211
|
+
} else if (entity.has(traits.Opacity)) {
|
|
212
|
+
entity.set(traits.Opacity, next)
|
|
213
|
+
} else {
|
|
214
|
+
entity.add(traits.Opacity(next))
|
|
215
|
+
}
|
|
216
|
+
invalidate()
|
|
217
|
+
}
|
|
218
|
+
|
|
200
219
|
const handleParentChange = (event: ListChangeEvent) => {
|
|
201
220
|
if (event.detail.origin !== 'internal' || !entity) return
|
|
202
221
|
const value = event.detail.value as string
|
|
@@ -668,6 +687,20 @@
|
|
|
668
687
|
</div>
|
|
669
688
|
{/if}
|
|
670
689
|
|
|
690
|
+
<div>
|
|
691
|
+
<strong class="font-semibold">opacity</strong>
|
|
692
|
+
<div aria-label="mutable opacity">
|
|
693
|
+
<Slider
|
|
694
|
+
value={opacityValue}
|
|
695
|
+
min={0}
|
|
696
|
+
max={1}
|
|
697
|
+
step={0.01}
|
|
698
|
+
format={(v) => v.toFixed(2)}
|
|
699
|
+
on:change={handleOpacityChange}
|
|
700
|
+
/>
|
|
701
|
+
</div>
|
|
702
|
+
</div>
|
|
703
|
+
|
|
671
704
|
{#if isInstanceOf(object3d, 'Points')}
|
|
672
705
|
<div>
|
|
673
706
|
<strong class="font-semibold">points</strong>
|
|
@@ -29,8 +29,9 @@ export const provideFrames = (partID) => {
|
|
|
29
29
|
$effect.pre(() => {
|
|
30
30
|
const id = partID();
|
|
31
31
|
if (lastPartID !== undefined && lastPartID !== id) {
|
|
32
|
-
//
|
|
33
|
-
//
|
|
32
|
+
// Don't let an edited flag from the previous part bleed into the
|
|
33
|
+
// new one — the merge condition would otherwise stay forced on for
|
|
34
|
+
// a freshly-switched part the user hasn't touched.
|
|
34
35
|
didRecentlyEdit = false;
|
|
35
36
|
}
|
|
36
37
|
lastPartID = id;
|
|
@@ -59,11 +60,15 @@ export const provideFrames = (partID) => {
|
|
|
59
60
|
frames[frame.referenceFrame] = frame;
|
|
60
61
|
}
|
|
61
62
|
}
|
|
62
|
-
// Let config frames take priority if the user has made edits,
|
|
63
|
-
//
|
|
63
|
+
// Let config frames take priority if the user has made edits, has a
|
|
64
|
+
// pending save, or we don't have a live robot connection. The latter
|
|
65
|
+
// covers DISCONNECTED, CONNECTING, and the undefined case where the
|
|
66
|
+
// embedder never provided a dial config (e.g. the Viam app's
|
|
67
|
+
// dialConfigsForParts filters to live parts only, so offline parts
|
|
68
|
+
// never transition through DISCONNECTED).
|
|
64
69
|
if (didRecentlyEdit ||
|
|
65
70
|
partConfig.hasPendingSave ||
|
|
66
|
-
connectionStatus.current
|
|
71
|
+
connectionStatus.current !== MachineConnectionEvent.CONNECTED) {
|
|
67
72
|
const mergedFrames = {
|
|
68
73
|
...frames,
|
|
69
74
|
...configFrames.current,
|
|
@@ -23,7 +23,6 @@ export interface Settings {
|
|
|
23
23
|
enableMeasureAxisY: boolean;
|
|
24
24
|
enableMeasureAxisZ: boolean;
|
|
25
25
|
enableLabels: boolean;
|
|
26
|
-
enableKeybindings: boolean;
|
|
27
26
|
enableQueryDevtools: boolean;
|
|
28
27
|
enableArmPositionsWidget: boolean;
|
|
29
28
|
openCameraWidgets: Record<string, string[]>;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
/** @deprecated MotionTools has been renamed to Visualizer. This export will be removed in v2. */
|
|
1
2
|
export { default as MotionTools } from './components/App.svelte';
|
|
3
|
+
export { default as Visualizer } from './components/App.svelte';
|
|
2
4
|
export { default as SelectionTool } from './components/Selection/Tool.svelte';
|
|
3
5
|
export { default as PCD } from './components/PCD.svelte';
|
|
4
6
|
export * as relations from './ecs/relations';
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
|
+
/** @deprecated MotionTools has been renamed to Visualizer. This export will be removed in v2. */
|
|
1
2
|
export { default as MotionTools } from './components/App.svelte';
|
|
3
|
+
export { default as Visualizer } from './components/App.svelte';
|
|
2
4
|
// Plugins
|
|
3
5
|
export { default as SelectionTool } from './components/Selection/Tool.svelte';
|
|
4
6
|
export { default as PCD } from './components/PCD.svelte';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@viamrobotics/motion-tools",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.23.0",
|
|
4
4
|
"description": "Motion visualization with Viam",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
@@ -147,9 +147,8 @@
|
|
|
147
147
|
"uuid-tool": "^2.0.3"
|
|
148
148
|
},
|
|
149
149
|
"scripts": {
|
|
150
|
-
"dev": "pnpm dev:bun",
|
|
150
|
+
"dev": "concurrently \"pnpm dev:bun\" \"go run cmd/draw-server/main.go -port 3030\"",
|
|
151
151
|
"dev:bun": "tsx server/check-bun && bun run server/server.ts",
|
|
152
|
-
"dev:next": "concurrently \"pnpm dev:bun\" \"go run cmd/draw-server/main.go -port 3030\"",
|
|
153
152
|
"dev:https": "vite dev -- --https",
|
|
154
153
|
"build": "vite build && npm run prepack",
|
|
155
154
|
"build:workers": "node scripts/build-workers.js",
|
|
@@ -174,6 +173,9 @@
|
|
|
174
173
|
"vet:client": "go vet ./client/...",
|
|
175
174
|
"vet": "pnpm vet:draw && pnpm vet:client",
|
|
176
175
|
"model-pipeline:run": "node scripts/model-pipeline.js",
|
|
177
|
-
"release": "changeset publish"
|
|
176
|
+
"release": "changeset publish",
|
|
177
|
+
"docs:dev": "pnpm --dir docs dev",
|
|
178
|
+
"docs:build": "pnpm --dir docs build",
|
|
179
|
+
"docs:preview": "pnpm --dir docs preview"
|
|
178
180
|
}
|
|
179
181
|
}
|
|
@@ -1,7 +0,0 @@
|
|
|
1
|
-
import type { CameraControlsRef } from '@threlte/extras';
|
|
2
|
-
interface Props {
|
|
3
|
-
cameraControls: CameraControlsRef;
|
|
4
|
-
}
|
|
5
|
-
declare const KeyboardControls: import("svelte").Component<Props, {}, "">;
|
|
6
|
-
type KeyboardControls = ReturnType<typeof KeyboardControls>;
|
|
7
|
-
export default KeyboardControls;
|