@viamrobotics/motion-tools 0.18.1 → 0.18.3
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/__tests__/fixtures/MockCanvas.svelte +11 -0
- package/dist/__tests__/fixtures/MockCanvas.svelte.d.ts +11 -0
- package/dist/components/Frame.svelte +23 -1
- package/dist/components/Geometry.svelte +15 -41
- package/dist/components/Geometry.svelte.d.ts +3 -1
- package/dist/hooks/useDrawAPI.svelte.js +16 -8
- package/dist/hooks/useFrames.svelte.js +5 -1
- package/dist/lib.js +2 -0
- package/package.json +3 -1
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export default MockCanvas;
|
|
2
|
+
type MockCanvas = {
|
|
3
|
+
$on?(type: string, callback: (e: any) => void): () => void;
|
|
4
|
+
$set?(props: Partial<$$ComponentProps>): void;
|
|
5
|
+
};
|
|
6
|
+
declare const MockCanvas: import("svelte").Component<{
|
|
7
|
+
child: any;
|
|
8
|
+
} & Record<string, any>, {}, "">;
|
|
9
|
+
type $$ComponentProps = {
|
|
10
|
+
child: any;
|
|
11
|
+
} & Record<string, any>;
|
|
@@ -8,8 +8,12 @@
|
|
|
8
8
|
import { useObjectEvents } from '../hooks/useObjectEvents.svelte'
|
|
9
9
|
import { Color, type Object3D } from 'three'
|
|
10
10
|
import Geometry from './Geometry.svelte'
|
|
11
|
+
import { useWeblabs } from '../hooks/useWeblabs.svelte'
|
|
11
12
|
import { useSelected } from '../hooks/useSelection.svelte'
|
|
13
|
+
import { useSettings } from '../hooks/useSettings.svelte'
|
|
14
|
+
import { use3DModels } from '../hooks/use3DModels.svelte'
|
|
12
15
|
import { colors, darkenColor } from '../color'
|
|
16
|
+
import { WEBLABS_EXPERIMENTS } from '../hooks/useWeblabs.svelte'
|
|
13
17
|
|
|
14
18
|
interface Props {
|
|
15
19
|
uuid: string
|
|
@@ -20,16 +24,34 @@
|
|
|
20
24
|
children?: Snippet<[{ ref: Object3D }]>
|
|
21
25
|
}
|
|
22
26
|
|
|
23
|
-
let { uuid, ...rest }: Props = $props()
|
|
27
|
+
let { uuid, name, ...rest }: Props = $props()
|
|
24
28
|
|
|
29
|
+
const settings = useSettings()
|
|
30
|
+
const componentModels = use3DModels()
|
|
25
31
|
const selected = useSelected()
|
|
32
|
+
const weblabs = useWeblabs()
|
|
26
33
|
const events = useObjectEvents(() => uuid)
|
|
27
34
|
|
|
28
35
|
const color = $derived(rest.metadata.color ?? colors.default)
|
|
36
|
+
|
|
37
|
+
const model = $derived.by(() => {
|
|
38
|
+
if (!weblabs.isActive(WEBLABS_EXPERIMENTS.MOTION_TOOLS_RENDER_ARM_MODELS)) {
|
|
39
|
+
return
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
const [componentName, id] = name.split(':')
|
|
43
|
+
if (!componentName || !id) {
|
|
44
|
+
return
|
|
45
|
+
}
|
|
46
|
+
return componentModels.current?.[componentName]?.[id]
|
|
47
|
+
})
|
|
29
48
|
</script>
|
|
30
49
|
|
|
31
50
|
<Geometry
|
|
32
51
|
{uuid}
|
|
52
|
+
{name}
|
|
53
|
+
{model}
|
|
54
|
+
renderMode={settings.current.renderArmModels}
|
|
33
55
|
color={selected.current === uuid
|
|
34
56
|
? `#${darkenColor(color, 75).getHexString()}`
|
|
35
57
|
: `#${colorUtil.set(color).getHexString()}`}
|
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
<!--
|
|
2
|
+
|
|
3
|
+
This component is consumed as a library export
|
|
4
|
+
and should remain pure, i.e. no hooks should be used.
|
|
5
|
+
|
|
6
|
+
-->
|
|
1
7
|
<script lang="ts">
|
|
2
8
|
import { T, type Props as ThrelteProps } from '@threlte/core'
|
|
3
9
|
import { type Snippet } from 'svelte'
|
|
@@ -10,14 +16,7 @@
|
|
|
10
16
|
import type { WorldObject } from '../WorldObject.svelte'
|
|
11
17
|
import { PLYLoader } from 'three/addons/loaders/PLYLoader.js'
|
|
12
18
|
|
|
13
|
-
import { WEBLABS_EXPERIMENTS } from '../hooks/useWeblabs.svelte'
|
|
14
|
-
import { useSettings } from '../hooks/useSettings.svelte'
|
|
15
|
-
import { useWeblabs } from '../hooks/useWeblabs.svelte'
|
|
16
|
-
import { use3DModels } from '../hooks/use3DModels.svelte'
|
|
17
|
-
const settings = useSettings()
|
|
18
19
|
const plyLoader = new PLYLoader()
|
|
19
|
-
const weblabs = useWeblabs()
|
|
20
|
-
const componentModels = use3DModels()
|
|
21
20
|
|
|
22
21
|
interface Props extends ThrelteProps<Group> {
|
|
23
22
|
uuid: string
|
|
@@ -25,8 +24,10 @@
|
|
|
25
24
|
geometry?: WorldObject['geometry']
|
|
26
25
|
pose: WorldObject['pose']
|
|
27
26
|
metadata: WorldObject['metadata']
|
|
28
|
-
children?: Snippet<[{ ref: Group }]>
|
|
29
27
|
color?: string
|
|
28
|
+
model?: Group
|
|
29
|
+
renderMode?: 'model' | 'colliders' | 'colliders+model'
|
|
30
|
+
children?: Snippet<[{ ref: Group }]>
|
|
30
31
|
}
|
|
31
32
|
|
|
32
33
|
let {
|
|
@@ -36,32 +37,15 @@
|
|
|
36
37
|
metadata,
|
|
37
38
|
pose,
|
|
38
39
|
color: overrideColor,
|
|
40
|
+
model,
|
|
41
|
+
renderMode = 'colliders',
|
|
39
42
|
children,
|
|
40
43
|
...rest
|
|
41
44
|
}: Props = $props()
|
|
42
45
|
|
|
43
|
-
const gltfModel = $derived.by(() => {
|
|
44
|
-
const [componentName, id] = name.split(':')
|
|
45
|
-
if (!componentName || !id) {
|
|
46
|
-
return undefined
|
|
47
|
-
}
|
|
48
|
-
return componentModels.current?.[componentName]?.[id]
|
|
49
|
-
})
|
|
50
|
-
|
|
51
46
|
const type = $derived(geometry?.geometryType?.case)
|
|
52
47
|
const color = $derived(overrideColor ?? metadata.color ?? colors.default)
|
|
53
48
|
|
|
54
|
-
const renderModels = $derived(
|
|
55
|
-
(settings.current.renderArmModels === 'model' ||
|
|
56
|
-
settings.current.renderArmModels === 'colliders+model') &&
|
|
57
|
-
gltfModel
|
|
58
|
-
)
|
|
59
|
-
const renderPrimitives = $derived(
|
|
60
|
-
settings.current.renderArmModels === 'colliders' ||
|
|
61
|
-
settings.current.renderArmModels === 'colliders+model' ||
|
|
62
|
-
!gltfModel
|
|
63
|
-
)
|
|
64
|
-
|
|
65
49
|
const group = new Group()
|
|
66
50
|
const mesh = $derived.by(() => {
|
|
67
51
|
if (type === undefined) {
|
|
@@ -76,16 +60,6 @@
|
|
|
76
60
|
return result
|
|
77
61
|
})
|
|
78
62
|
|
|
79
|
-
$effect.pre(() => {
|
|
80
|
-
if (
|
|
81
|
-
weblabs.isActive(WEBLABS_EXPERIMENTS.MOTION_TOOLS_RENDER_ARM_MODELS) &&
|
|
82
|
-
renderModels &&
|
|
83
|
-
!renderPrimitives
|
|
84
|
-
) {
|
|
85
|
-
geo = undefined
|
|
86
|
-
}
|
|
87
|
-
})
|
|
88
|
-
|
|
89
63
|
$effect.pre(() => {
|
|
90
64
|
if (geometry?.center && mesh) {
|
|
91
65
|
poseToObject3d(geometry.center, mesh)
|
|
@@ -139,11 +113,11 @@
|
|
|
139
113
|
{uuid}
|
|
140
114
|
bvh={{ enabled: false }}
|
|
141
115
|
>
|
|
142
|
-
{#if
|
|
143
|
-
<T is={
|
|
116
|
+
{#if model && renderMode.includes('model')}
|
|
117
|
+
<T is={model} />
|
|
144
118
|
{/if}
|
|
145
119
|
|
|
146
|
-
{#if
|
|
120
|
+
{#if renderMode.includes('colliders')}
|
|
147
121
|
{#if geometry.geometryType.case === 'bufferGeometry'}
|
|
148
122
|
<T
|
|
149
123
|
is={geometry.geometryType.value}
|
|
@@ -193,7 +167,7 @@
|
|
|
193
167
|
opacity={metadata.opacity ?? 0.7}
|
|
194
168
|
/>
|
|
195
169
|
|
|
196
|
-
{#if geo}
|
|
170
|
+
{#if geo && renderMode.includes('colliders')}
|
|
197
171
|
<T.LineSegments
|
|
198
172
|
raycast={() => null}
|
|
199
173
|
bvh={{ enabled: false }}
|
|
@@ -8,10 +8,12 @@ interface Props extends ThrelteProps<Group> {
|
|
|
8
8
|
geometry?: WorldObject['geometry'];
|
|
9
9
|
pose: WorldObject['pose'];
|
|
10
10
|
metadata: WorldObject['metadata'];
|
|
11
|
+
color?: string;
|
|
12
|
+
model?: Group;
|
|
13
|
+
renderMode?: 'model' | 'colliders' | 'colliders+model';
|
|
11
14
|
children?: Snippet<[{
|
|
12
15
|
ref: Group;
|
|
13
16
|
}]>;
|
|
14
|
-
color?: string;
|
|
15
17
|
}
|
|
16
18
|
declare const Geometry: import("svelte").Component<Props, {}, "">;
|
|
17
19
|
type Geometry = ReturnType<typeof Geometry>;
|
|
@@ -10,17 +10,17 @@ import { createPose, createPoseFromFrame } from '../transform';
|
|
|
10
10
|
import { useCameraControls } from './useControls.svelte';
|
|
11
11
|
import { useThrelte } from '@threlte/core';
|
|
12
12
|
import { OrientationVector } from '../three/OrientationVector';
|
|
13
|
+
import { useLogs } from './useLogs.svelte';
|
|
13
14
|
const axis = new Vector3();
|
|
14
15
|
const quaternion = new Quaternion();
|
|
15
16
|
const ov = new OrientationVector();
|
|
16
17
|
const key = Symbol('draw-api-context-key');
|
|
17
18
|
const tryParse = (json) => {
|
|
18
19
|
try {
|
|
19
|
-
return JSON.parse(json);
|
|
20
|
+
return [null, JSON.parse(json)];
|
|
20
21
|
}
|
|
21
22
|
catch (error) {
|
|
22
|
-
|
|
23
|
-
return;
|
|
23
|
+
return [error, null];
|
|
24
24
|
}
|
|
25
25
|
};
|
|
26
26
|
/**
|
|
@@ -55,6 +55,7 @@ class Float32Reader {
|
|
|
55
55
|
}
|
|
56
56
|
}
|
|
57
57
|
export const provideDrawAPI = () => {
|
|
58
|
+
const logs = useLogs();
|
|
58
59
|
const cameraControls = useCameraControls();
|
|
59
60
|
const { invalidate } = useThrelte();
|
|
60
61
|
let pointsIndex = 0;
|
|
@@ -380,23 +381,27 @@ export const provideDrawAPI = () => {
|
|
|
380
381
|
const scheduleReconnect = () => {
|
|
381
382
|
setTimeout(() => {
|
|
382
383
|
reconnectDelay = Math.min(reconnectDelay * 2, maxReconnectDelay);
|
|
383
|
-
|
|
384
|
+
logs.add(`Reconnecting to drawing server in ${reconnectDelay / 1000} seconds...`, 'warn');
|
|
384
385
|
connect();
|
|
385
386
|
}, reconnectDelay);
|
|
386
387
|
};
|
|
387
388
|
const onOpen = () => {
|
|
388
389
|
connectionStatus = 'open';
|
|
389
390
|
reconnectDelay = 1000;
|
|
390
|
-
|
|
391
|
+
logs.add(`Connected to drawing server at ${BACKEND_IP}:${BUN_SERVER_PORT}`);
|
|
391
392
|
};
|
|
392
393
|
const onClose = () => {
|
|
393
394
|
connectionStatus = 'closed';
|
|
394
|
-
|
|
395
|
+
logs.add('Disconnected from drawing server', 'warn');
|
|
395
396
|
scheduleReconnect();
|
|
396
397
|
};
|
|
397
398
|
const onError = (event) => {
|
|
398
|
-
|
|
399
|
+
const stringified = JSON.stringify(event);
|
|
399
400
|
ws.close();
|
|
401
|
+
if (stringified === '{"isTrusted":true}') {
|
|
402
|
+
return;
|
|
403
|
+
}
|
|
404
|
+
logs.add(`Drawing server error: ${JSON.stringify(event)}`, 'error');
|
|
400
405
|
};
|
|
401
406
|
const onMessage = async (event) => {
|
|
402
407
|
if (typeof event.data === 'object' && 'arrayBuffer' in event.data) {
|
|
@@ -418,7 +423,10 @@ export const provideDrawAPI = () => {
|
|
|
418
423
|
return drawGLTF(reader.buffer);
|
|
419
424
|
}
|
|
420
425
|
}
|
|
421
|
-
const data = tryParse(event.data);
|
|
426
|
+
const [error, data] = tryParse(event.data);
|
|
427
|
+
if (error) {
|
|
428
|
+
logs.add(`Failed to parse JSON from drawing server: ${JSON.stringify(error)}`, 'error');
|
|
429
|
+
}
|
|
422
430
|
if (!data)
|
|
423
431
|
return;
|
|
424
432
|
if ('setCameraPose' in data) {
|
|
@@ -24,7 +24,11 @@ export const provideFrames = (partID) => {
|
|
|
24
24
|
if (revision) {
|
|
25
25
|
untrack(() => query.current).refetch();
|
|
26
26
|
}
|
|
27
|
-
|
|
27
|
+
});
|
|
28
|
+
$effect.pre(() => {
|
|
29
|
+
if (query.current.isFetching) {
|
|
30
|
+
logs.add('Fetching frames...');
|
|
31
|
+
}
|
|
28
32
|
});
|
|
29
33
|
$effect.pre(() => {
|
|
30
34
|
if (partConfig.isDirty) {
|
package/dist/lib.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
// Components
|
|
2
|
+
// NOTE: These components should be pure and not use any hooks if you add a new component to export here
|
|
3
|
+
// ensure you write a corresponding unit test to assert the component works in absence of parent providers in /src/lib/__tests__/PureComponents.svelte.spec.ts
|
|
2
4
|
export { default as Geometry } from './components/Geometry.svelte';
|
|
3
5
|
export { default as AxesHelper } from './components/AxesHelper.svelte';
|
|
4
6
|
// Classes
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@viamrobotics/motion-tools",
|
|
3
|
-
"version": "0.18.
|
|
3
|
+
"version": "0.18.3",
|
|
4
4
|
"description": "Motion visualization with Viam",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
@@ -40,6 +40,7 @@
|
|
|
40
40
|
"@viamrobotics/sdk": "0.55.0",
|
|
41
41
|
"@viamrobotics/svelte-sdk": "0.7.1",
|
|
42
42
|
"@vitejs/plugin-basic-ssl": "2.1.0",
|
|
43
|
+
"@vitest/coverage-v8": "^3.2.4",
|
|
43
44
|
"@zag-js/svelte": "1.22.1",
|
|
44
45
|
"@zag-js/tree-view": "1.22.1",
|
|
45
46
|
"camera-controls": "3.1.0",
|
|
@@ -129,6 +130,7 @@
|
|
|
129
130
|
"test:unit": "vitest",
|
|
130
131
|
"test:client": "go test ./client/... -count=1",
|
|
131
132
|
"test": "pnpm test:unit -- --run",
|
|
133
|
+
"test:coverage": "npx vitest run --coverage",
|
|
132
134
|
"test:e2e": "playwright test",
|
|
133
135
|
"model-pipeline:run": "node scripts/model-pipeline.js",
|
|
134
136
|
"release": "changeset publish"
|