@viamrobotics/motion-tools 1.34.2 → 1.34.4
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 +0 -2
- package/dist/components/SceneProviders.svelte +0 -2
- package/dist/hooks/useFrames.svelte.js +1 -1
- package/dist/hooks/useGeometries.svelte.js +1 -1
- package/dist/hooks/usePointcloudObjects.svelte.js +1 -1
- package/dist/hooks/usePointclouds.svelte.js +1 -1
- package/dist/hooks/usePose.svelte.js +1 -1
- package/dist/plugins/DrawService/useDrawAPI.svelte.js +1 -1
- package/dist/plugins/LLMSceneBuilder/SceneBuilder.svelte +25 -17
- package/dist/plugins/LLMSceneBuilder/frameDeltaAdapter.js +26 -0
- package/dist/plugins/Logs/Logs.svelte +146 -0
- package/dist/{hooks → plugins/Logs}/useLogs.svelte.d.ts +1 -1
- package/dist/{hooks → plugins/Logs}/useLogs.svelte.js +13 -5
- package/dist/plugins/index.d.ts +2 -0
- package/dist/plugins/index.js +5 -0
- package/package.json +5 -7
- package/dist/components/overlay/Logs.svelte +0 -144
- /package/dist/{components/overlay → plugins/Logs}/Logs.svelte.d.ts +0 -0
|
@@ -30,7 +30,6 @@
|
|
|
30
30
|
import HoveredEntities from './hover/HoveredEntities.svelte'
|
|
31
31
|
import AddFrames from './overlay/AddFrames.svelte'
|
|
32
32
|
import LiveUpdatesBanner from './overlay/LiveUpdatesBanner.svelte'
|
|
33
|
-
import Logs from './overlay/Logs.svelte'
|
|
34
33
|
import ArmPositions from './overlay/widgets/ArmPositions.svelte'
|
|
35
34
|
import Camera from './overlay/widgets/Camera.svelte'
|
|
36
35
|
import FramePov from './overlay/widgets/FramePov.svelte'
|
|
@@ -173,7 +172,6 @@
|
|
|
173
172
|
<PortalTarget id="dom" />
|
|
174
173
|
|
|
175
174
|
<Settings {settingsTabs} />
|
|
176
|
-
<Logs />
|
|
177
175
|
<AddFrames />
|
|
178
176
|
</div>
|
|
179
177
|
</SceneProviders>
|
|
@@ -13,7 +13,6 @@
|
|
|
13
13
|
import { provideGeometries } from '../hooks/useGeometries.svelte'
|
|
14
14
|
import { provideInheritedInvisible } from '../hooks/useInheritedInvisible.svelte'
|
|
15
15
|
import { provideLinkedEntities } from '../hooks/useLinked.svelte'
|
|
16
|
-
import { provideLogs } from '../hooks/useLogs.svelte'
|
|
17
16
|
import { usePartID } from '../hooks/usePartID.svelte'
|
|
18
17
|
import { providePointcloudObjects } from '../hooks/usePointcloudObjects.svelte'
|
|
19
18
|
import { providePointclouds } from '../hooks/usePointclouds.svelte'
|
|
@@ -30,7 +29,6 @@
|
|
|
30
29
|
const partID = usePartID()
|
|
31
30
|
|
|
32
31
|
provideTransformControls()
|
|
33
|
-
provideLogs()
|
|
34
32
|
|
|
35
33
|
provideHierarchy()
|
|
36
34
|
provideWorldMatrix()
|
|
@@ -5,11 +5,11 @@ import { getContext, setContext, untrack } from 'svelte';
|
|
|
5
5
|
import { Matrix4 } from 'three';
|
|
6
6
|
import { resourceNameToColor, subtypeToColor } from '../color';
|
|
7
7
|
import { hierarchy, traits, useWorld } from '../ecs';
|
|
8
|
+
import { useLogs } from '../plugins';
|
|
8
9
|
import { createPose, isPoseEqual, poseToMatrix } from '../transform';
|
|
9
10
|
import { useConfigFrames } from './useConfigFrames.svelte';
|
|
10
11
|
import { useEnvironment } from './useEnvironment.svelte';
|
|
11
12
|
import { useFrameEditSession } from './useFrameEditSession.svelte';
|
|
12
|
-
import { useLogs } from './useLogs.svelte';
|
|
13
13
|
import { usePartConfig } from './usePartConfig.svelte';
|
|
14
14
|
import { useResourceByName } from './useResourceByName.svelte';
|
|
15
15
|
const key = Symbol('frames-context');
|
|
@@ -7,9 +7,9 @@ import { resourceColors } from '../color';
|
|
|
7
7
|
import { RefetchRates } from '../components/overlay/RefreshRate.svelte';
|
|
8
8
|
import { hierarchy, traits, useWorld } from '../ecs';
|
|
9
9
|
import { updateGeometryTrait } from '../ecs/traits';
|
|
10
|
+
import { useLogs } from '../plugins';
|
|
10
11
|
import { createPose, poseToMatrix } from '../transform';
|
|
11
12
|
import { useEnvironment } from './useEnvironment.svelte';
|
|
12
|
-
import { useLogs } from './useLogs.svelte';
|
|
13
13
|
import { useResourceByName } from './useResourceByName.svelte';
|
|
14
14
|
import { RefreshRates, useSettings } from './useSettings.svelte';
|
|
15
15
|
const key = Symbol('geometries-context');
|
|
@@ -6,9 +6,9 @@ import { ColorFormat } from '../buf/draw/v1/metadata_pb';
|
|
|
6
6
|
import { RefetchRates } from '../components/overlay/RefreshRate.svelte';
|
|
7
7
|
import { hierarchy, traits, useWorld } from '../ecs';
|
|
8
8
|
import { parsePcdInWorker } from '../lib';
|
|
9
|
+
import { useLogs } from '../plugins';
|
|
9
10
|
import { createPose } from '../transform';
|
|
10
11
|
import { useEnvironment } from './useEnvironment.svelte';
|
|
11
|
-
import { useLogs } from './useLogs.svelte';
|
|
12
12
|
import { RefreshRates, useSettings } from './useSettings.svelte';
|
|
13
13
|
const key = Symbol('pointcloud-object-context');
|
|
14
14
|
export const providePointcloudObjects = (partID) => {
|
|
@@ -6,8 +6,8 @@ import { ColorFormat } from '../buf/draw/v1/metadata_pb';
|
|
|
6
6
|
import { RefetchRates } from '../components/overlay/RefreshRate.svelte';
|
|
7
7
|
import { hierarchy, traits, useWorld } from '../ecs';
|
|
8
8
|
import { parsePcdInWorker } from '../loaders/pcd';
|
|
9
|
+
import { useLogs } from '../plugins';
|
|
9
10
|
import { useEnvironment } from './useEnvironment.svelte';
|
|
10
|
-
import { useLogs } from './useLogs.svelte';
|
|
11
11
|
import { RefreshRates, useSettings } from './useSettings.svelte';
|
|
12
12
|
const key = Symbol('pointcloud-context');
|
|
13
13
|
export const providePointclouds = (partID) => {
|
|
@@ -2,9 +2,9 @@ import { commonApi, MachineConnectionEvent, Pose } from '@viamrobotics/sdk';
|
|
|
2
2
|
import { createRobotQuery, useConnectionStatus, useRobotClient } from '@viamrobotics/svelte-sdk';
|
|
3
3
|
import { untrack } from 'svelte';
|
|
4
4
|
import { RefetchRates } from '../components/overlay/RefreshRate.svelte';
|
|
5
|
+
import { useLogs } from '../plugins';
|
|
5
6
|
import { useEnvironment } from './useEnvironment.svelte';
|
|
6
7
|
import { useFrames } from './useFrames.svelte';
|
|
7
|
-
import { useLogs } from './useLogs.svelte';
|
|
8
8
|
import { usePartID } from './usePartID.svelte';
|
|
9
9
|
import { useRefetchPoses } from './useRefetchPoses';
|
|
10
10
|
import { useResourceByName } from './useResourceByName.svelte';
|
|
@@ -11,7 +11,7 @@ import { asRGB, STRIDE } from '../../buffer';
|
|
|
11
11
|
import { hierarchy, traits, useWorld } from '../../ecs';
|
|
12
12
|
import { createBox, createCapsule, createSphere } from '../../geometry';
|
|
13
13
|
import { useCameraControls } from '../../hooks/useControls.svelte';
|
|
14
|
-
import { useLogs } from '
|
|
14
|
+
import { useLogs } from '..';
|
|
15
15
|
import { parsePlyInput } from '../../ply';
|
|
16
16
|
import { createPose, createPoseFromFrame, poseToMatrix } from '../../transform';
|
|
17
17
|
import { useDrawConnectionConfig } from './useDrawConnectionConfig.svelte';
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
2
|
import { Portal } from '@threlte/extras'
|
|
3
|
+
import { Icon } from '@viamrobotics/prime-core'
|
|
3
4
|
|
|
4
5
|
import DashboardButton from '../../components/overlay/dashboard/Button.svelte'
|
|
5
6
|
import FloatingPanel from '../../components/overlay/FloatingPanel.svelte'
|
|
@@ -37,7 +38,7 @@
|
|
|
37
38
|
<div class="flex gap-2">
|
|
38
39
|
<textarea
|
|
39
40
|
class="flex-1 resize-none rounded border border-gray-300 p-2 text-xs focus:ring-1 focus:ring-gray-400 focus:outline-none disabled:bg-gray-50 disabled:text-gray-400"
|
|
40
|
-
placeholder="Describe
|
|
41
|
+
placeholder="Describe a frame change — translation, rotation, or parent. e.g. 'Move arm 200mm forward and rotate 90° left'"
|
|
41
42
|
rows={3}
|
|
42
43
|
disabled={sceneBuilder.uiState === 'loading' || sceneBuilder.uiState === 'diff'}
|
|
43
44
|
bind:value={prompt}
|
|
@@ -69,10 +70,6 @@
|
|
|
69
70
|
|
|
70
71
|
<!-- diff ready -->
|
|
71
72
|
{#if sceneBuilder.uiState === 'diff'}
|
|
72
|
-
{#if sceneBuilder.explanation}
|
|
73
|
-
<p class="text-gray-6 italic">{sceneBuilder.explanation}</p>
|
|
74
|
-
{/if}
|
|
75
|
-
|
|
76
73
|
{#if sceneBuilder.diffGroups.length > 0}
|
|
77
74
|
<div class="flex flex-col gap-2 overflow-auto">
|
|
78
75
|
{#each sceneBuilder.diffGroups as group (group.componentName)}
|
|
@@ -111,11 +108,13 @@
|
|
|
111
108
|
{/if}
|
|
112
109
|
|
|
113
110
|
{#if sceneBuilder.updateErrors.length > 0}
|
|
114
|
-
<
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
111
|
+
<div class="border-danger-medium bg-danger-light rounded border p-2">
|
|
112
|
+
<ul class="text-danger-dark space-y-0.5">
|
|
113
|
+
{#each sceneBuilder.updateErrors as err (err.componentName)}
|
|
114
|
+
<li><span class="font-mono">{err.componentName}</span>: {err.reason}</li>
|
|
115
|
+
{/each}
|
|
116
|
+
</ul>
|
|
117
|
+
</div>
|
|
119
118
|
{/if}
|
|
120
119
|
|
|
121
120
|
<div class="mt-auto flex gap-2">
|
|
@@ -136,13 +135,22 @@
|
|
|
136
135
|
|
|
137
136
|
<!-- error -->
|
|
138
137
|
{#if sceneBuilder.uiState === 'error'}
|
|
139
|
-
<
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
138
|
+
<div class="border-danger-medium bg-danger-light flex flex-col gap-2 rounded border p-2.5">
|
|
139
|
+
<div class="text-danger-dark flex items-center gap-1.5 font-medium">
|
|
140
|
+
<Icon
|
|
141
|
+
name="alert-circle-outline"
|
|
142
|
+
aria-hidden="true"
|
|
143
|
+
/>
|
|
144
|
+
Error
|
|
145
|
+
</div>
|
|
146
|
+
<p class="text-danger-dark">{sceneBuilder.errorMessage}</p>
|
|
147
|
+
<button
|
|
148
|
+
class="border-danger-medium text-danger-dark self-start rounded border px-3 py-1.5 hover:bg-[#F8E1DF]"
|
|
149
|
+
onclick={sceneBuilder.resetError}
|
|
150
|
+
>
|
|
151
|
+
Try again
|
|
152
|
+
</button>
|
|
153
|
+
</div>
|
|
146
154
|
{/if}
|
|
147
155
|
</div>
|
|
148
156
|
</FloatingPanel>
|
|
@@ -1,4 +1,12 @@
|
|
|
1
1
|
import { applyEulerDeltaToPose, createPoseFromFrame } from '../../transform';
|
|
2
|
+
function mergeTranslation(a, b) {
|
|
3
|
+
return a || b ? { x: b?.x ?? a?.x, y: b?.y ?? a?.y, z: b?.z ?? a?.z } : undefined;
|
|
4
|
+
}
|
|
5
|
+
function mergeOrientation(a, b) {
|
|
6
|
+
return a || b
|
|
7
|
+
? { roll: b?.roll ?? a?.roll, pitch: b?.pitch ?? a?.pitch, yaw: b?.yaw ?? a?.yaw }
|
|
8
|
+
: undefined;
|
|
9
|
+
}
|
|
2
10
|
/**
|
|
3
11
|
* Validates LLM-proposed frame deltas and computes the resulting changes without
|
|
4
12
|
* applying them. Each PreparedUpdate carries old and new values so the caller
|
|
@@ -8,7 +16,25 @@ export function validateProposedFrameDeltas(deltas, config) {
|
|
|
8
16
|
const errors = [];
|
|
9
17
|
const prepared = [];
|
|
10
18
|
const knownNames = new Set(config.components.map((c) => c.name));
|
|
19
|
+
// Merge multiple deltas for the same component — the LLM sometimes splits
|
|
20
|
+
// translation and orientation into separate entries despite the schema saying one per component.
|
|
21
|
+
const mergedDeltas = new Map();
|
|
11
22
|
for (const delta of deltas) {
|
|
23
|
+
const existing = mergedDeltas.get(delta.componentName);
|
|
24
|
+
if (existing) {
|
|
25
|
+
mergedDeltas.set(delta.componentName, {
|
|
26
|
+
componentName: delta.componentName,
|
|
27
|
+
translation: mergeTranslation(existing.translation, delta.translation),
|
|
28
|
+
orientation: mergeOrientation(existing.orientation, delta.orientation),
|
|
29
|
+
parent: delta.parent ?? existing.parent,
|
|
30
|
+
explanation: [existing.explanation, delta.explanation].filter(Boolean).join(', ') || undefined,
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
else {
|
|
34
|
+
mergedDeltas.set(delta.componentName, delta);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
for (const delta of mergedDeltas.values()) {
|
|
12
38
|
const component = config.components.find((c) => c.name === delta.componentName);
|
|
13
39
|
if (!component) {
|
|
14
40
|
errors.push({ componentName: delta.componentName, reason: 'Component not found in config' });
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { Portal } from '@threlte/extras'
|
|
3
|
+
import { PersistedState } from 'runed'
|
|
4
|
+
|
|
5
|
+
import DashboardButton from '../../components/overlay/dashboard/Button.svelte'
|
|
6
|
+
import FloatingPanel from '../../components/overlay/FloatingPanel.svelte'
|
|
7
|
+
|
|
8
|
+
import { provideLogs } from './useLogs.svelte'
|
|
9
|
+
|
|
10
|
+
const logs = provideLogs()
|
|
11
|
+
|
|
12
|
+
const isOpen = new PersistedState('logs-is-open', false)
|
|
13
|
+
|
|
14
|
+
let levels = new PersistedState('logs-selected-levels', {
|
|
15
|
+
info: true,
|
|
16
|
+
warn: true,
|
|
17
|
+
error: true,
|
|
18
|
+
})
|
|
19
|
+
</script>
|
|
20
|
+
|
|
21
|
+
<Portal id="dashboard">
|
|
22
|
+
<fieldset class="relative">
|
|
23
|
+
<DashboardButton
|
|
24
|
+
active={isOpen.current}
|
|
25
|
+
icon="article"
|
|
26
|
+
description="Logs"
|
|
27
|
+
onclick={() => {
|
|
28
|
+
isOpen.current = !isOpen.current
|
|
29
|
+
}}
|
|
30
|
+
/>
|
|
31
|
+
{#if logs.warnings.length > 0}
|
|
32
|
+
<span
|
|
33
|
+
class="absolute z-4 -mt-1.5 -ml-1.5 h-4 w-4 rounded-full bg-yellow-700 text-center text-[10px] text-white"
|
|
34
|
+
>
|
|
35
|
+
{logs.warnings.length}
|
|
36
|
+
</span>
|
|
37
|
+
{/if}
|
|
38
|
+
|
|
39
|
+
{#if logs.errors.length > 0}
|
|
40
|
+
<span
|
|
41
|
+
class="absolute z-4 -mt-1.5 -ml-1.5 h-4 rounded-full bg-red-700 px-1.25 text-center text-[10px] text-white"
|
|
42
|
+
>
|
|
43
|
+
{logs.errors.length}
|
|
44
|
+
</span>
|
|
45
|
+
{/if}
|
|
46
|
+
</fieldset>
|
|
47
|
+
</Portal>
|
|
48
|
+
|
|
49
|
+
<Portal id="dom">
|
|
50
|
+
<FloatingPanel
|
|
51
|
+
title="Logs"
|
|
52
|
+
bind:isOpen={isOpen.current}
|
|
53
|
+
defaultSize={{ width: 240, height: 315 }}
|
|
54
|
+
resizable
|
|
55
|
+
>
|
|
56
|
+
<div class="flex h-full flex-col">
|
|
57
|
+
<div class="flex gap-1 px-3 py-2">
|
|
58
|
+
<button
|
|
59
|
+
type="button"
|
|
60
|
+
class={[
|
|
61
|
+
'chip border px-2',
|
|
62
|
+
{
|
|
63
|
+
'border-danger-dark bg-danger-dark text-white hover:border-red-700 hover:bg-red-700':
|
|
64
|
+
levels.current.error,
|
|
65
|
+
'bg-light hover:bg-ghost-light hover:border-light border-light text-subtle-1':
|
|
66
|
+
!levels.current.error,
|
|
67
|
+
},
|
|
68
|
+
]}
|
|
69
|
+
onclick={() => {
|
|
70
|
+
levels.current.error = !levels.current.error
|
|
71
|
+
}}
|
|
72
|
+
>
|
|
73
|
+
error
|
|
74
|
+
</button>
|
|
75
|
+
|
|
76
|
+
<button
|
|
77
|
+
type="button"
|
|
78
|
+
class={[
|
|
79
|
+
'chip border',
|
|
80
|
+
{
|
|
81
|
+
'border-amber-400 bg-amber-400 text-white hover:border-amber-500 hover:bg-amber-500':
|
|
82
|
+
levels.current.warn,
|
|
83
|
+
'bg-light hover:bg-ghost-light hover:border-light border-light text-subtle-1':
|
|
84
|
+
!levels.current.warn,
|
|
85
|
+
},
|
|
86
|
+
]}
|
|
87
|
+
onclick={() => {
|
|
88
|
+
levels.current.warn = !levels.current.warn
|
|
89
|
+
}}
|
|
90
|
+
>
|
|
91
|
+
warn
|
|
92
|
+
</button>
|
|
93
|
+
|
|
94
|
+
<button
|
|
95
|
+
type="button"
|
|
96
|
+
class={[
|
|
97
|
+
'chip border',
|
|
98
|
+
{
|
|
99
|
+
'border-blue-400 bg-blue-400 text-white hover:border-blue-500 hover:bg-blue-500':
|
|
100
|
+
levels.current.info,
|
|
101
|
+
'bg-light hover:bg-ghost-light hover:border-light border-light text-subtle-1':
|
|
102
|
+
!levels.current.info,
|
|
103
|
+
},
|
|
104
|
+
]}
|
|
105
|
+
onclick={() => {
|
|
106
|
+
levels.current.info = !levels.current.info
|
|
107
|
+
}}
|
|
108
|
+
>
|
|
109
|
+
info
|
|
110
|
+
</button>
|
|
111
|
+
</div>
|
|
112
|
+
|
|
113
|
+
<div class="flex flex-col gap-2 overflow-auto px-3 pb-3 text-xs">
|
|
114
|
+
{#each logs.current as log (log.uuid)}
|
|
115
|
+
{#if levels.current[log.level]}
|
|
116
|
+
<div>
|
|
117
|
+
<div class="flex flex-wrap items-center gap-1.5">
|
|
118
|
+
<div
|
|
119
|
+
class={[
|
|
120
|
+
'h-2 w-2 rounded-full',
|
|
121
|
+
{
|
|
122
|
+
'bg-danger-dark': log.level === 'error',
|
|
123
|
+
'bg-amber-300': log.level === 'warn',
|
|
124
|
+
'bg-blue-400': log.level === 'info',
|
|
125
|
+
},
|
|
126
|
+
]}
|
|
127
|
+
></div>
|
|
128
|
+
<div class="text-subtle-2">{log.timestamp}</div>
|
|
129
|
+
</div>
|
|
130
|
+
<div>
|
|
131
|
+
{#if log.count > 1}
|
|
132
|
+
<span class="mr-1 rounded bg-green-700 px-1 py-0.5 text-xs text-white">
|
|
133
|
+
{log.count}
|
|
134
|
+
</span>
|
|
135
|
+
{/if}
|
|
136
|
+
{log.message}
|
|
137
|
+
</div>
|
|
138
|
+
</div>
|
|
139
|
+
{/if}
|
|
140
|
+
{:else}
|
|
141
|
+
No logs
|
|
142
|
+
{/each}
|
|
143
|
+
</div>
|
|
144
|
+
</div>
|
|
145
|
+
</FloatingPanel>
|
|
146
|
+
</Portal>
|
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { untrack } from 'svelte';
|
|
2
2
|
import { MathUtils } from 'three';
|
|
3
|
-
const key = Symbol('logs-context');
|
|
4
3
|
const MAX_LOGS = 200;
|
|
4
|
+
// Logs is a singleton. We only have one logger per app and we need to access it anywhere.
|
|
5
|
+
let context;
|
|
5
6
|
export const provideLogs = () => {
|
|
6
7
|
// Plain insertion-ordered Map keyed by `${level}|${timestamp}|${message}`
|
|
7
8
|
// drives storage; a single `$state` version counter drives reactivity.
|
|
@@ -23,7 +24,7 @@ export const provideLogs = () => {
|
|
|
23
24
|
});
|
|
24
25
|
const errors = $derived(all.filter((l) => l.level === 'error'));
|
|
25
26
|
const warnings = $derived(all.filter((l) => l.level === 'warn'));
|
|
26
|
-
|
|
27
|
+
context = {
|
|
27
28
|
get current() {
|
|
28
29
|
return all;
|
|
29
30
|
},
|
|
@@ -58,8 +59,15 @@ export const provideLogs = () => {
|
|
|
58
59
|
version++;
|
|
59
60
|
});
|
|
60
61
|
},
|
|
61
|
-
}
|
|
62
|
+
};
|
|
63
|
+
return context;
|
|
62
64
|
};
|
|
63
65
|
export const useLogs = () => {
|
|
64
|
-
return
|
|
66
|
+
// return a no-op context if the plugin isn't installed
|
|
67
|
+
return (context ?? {
|
|
68
|
+
current: [],
|
|
69
|
+
errors: [],
|
|
70
|
+
warnings: [],
|
|
71
|
+
add: () => undefined,
|
|
72
|
+
});
|
|
65
73
|
};
|
package/dist/plugins/index.d.ts
CHANGED
|
@@ -6,6 +6,8 @@ export { default as MeasureTool } from './MeasureTool/MeasureTool.svelte';
|
|
|
6
6
|
export { default as DrawService } from './DrawService/DrawService.svelte';
|
|
7
7
|
export { default as Skybox } from './Skybox/Skybox.svelte';
|
|
8
8
|
export { default as Debug } from './Debug/Debug.svelte';
|
|
9
|
+
export { default as Logs } from './Logs/Logs.svelte';
|
|
10
|
+
export { useLogs } from './Logs/useLogs.svelte';
|
|
9
11
|
export { default as Focus } from './Focus/Focus.svelte';
|
|
10
12
|
export { default as LLMSceneBuilder } from './LLMSceneBuilder/LLMSceneBuilder.svelte';
|
|
11
13
|
export type { InferCallback, ComponentFrameInfo } from './LLMSceneBuilder/useSceneBuilder.svelte';
|
package/dist/plugins/index.js
CHANGED
|
@@ -10,8 +10,13 @@ export { default as DrawService } from './DrawService/DrawService.svelte';
|
|
|
10
10
|
export { default as Skybox } from './Skybox/Skybox.svelte';
|
|
11
11
|
// Debug
|
|
12
12
|
export { default as Debug } from './Debug/Debug.svelte';
|
|
13
|
+
// Logs
|
|
14
|
+
export { default as Logs } from './Logs/Logs.svelte';
|
|
15
|
+
export { useLogs } from './Logs/useLogs.svelte';
|
|
16
|
+
// Focus
|
|
13
17
|
export { default as Focus } from './Focus/Focus.svelte';
|
|
14
18
|
// LLMSceneBuilder
|
|
15
19
|
export { default as LLMSceneBuilder } from './LLMSceneBuilder/LLMSceneBuilder.svelte';
|
|
20
|
+
// XR
|
|
16
21
|
export { default as XR } from './XR/XR.svelte';
|
|
17
22
|
export { default as XRSettings } from './XR/XRSettings.svelte';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@viamrobotics/motion-tools",
|
|
3
|
-
"version": "1.34.
|
|
3
|
+
"version": "1.34.4",
|
|
4
4
|
"description": "Motion visualization with Viam",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
@@ -11,6 +11,7 @@
|
|
|
11
11
|
"@changesets/cli": "2.29.6",
|
|
12
12
|
"@connectrpc/connect": "1.7.0",
|
|
13
13
|
"@connectrpc/connect-web": "1.7.0",
|
|
14
|
+
"@langchain/anthropic": "^1.4.0",
|
|
14
15
|
"@dimforge/rapier3d-compat": "0.18.2",
|
|
15
16
|
"@eslint/compat": "2.0.2",
|
|
16
17
|
"@eslint/js": "10.0.1",
|
|
@@ -85,7 +86,8 @@
|
|
|
85
86
|
"vite-plugin-devtools-json": "1.0.0",
|
|
86
87
|
"vite-plugin-glsl": "^1.5.5",
|
|
87
88
|
"vite-plugin-mkcert": "1.17.9",
|
|
88
|
-
"vitest": "3.2.6"
|
|
89
|
+
"vitest": "3.2.6",
|
|
90
|
+
"zod": "^4.4.3"
|
|
89
91
|
},
|
|
90
92
|
"peerDependencies": {
|
|
91
93
|
"@ag-grid-community/client-side-row-model": ">=32.3.0",
|
|
@@ -163,17 +165,13 @@
|
|
|
163
165
|
],
|
|
164
166
|
"dependencies": {
|
|
165
167
|
"@bufbuild/protobuf": "1.10.1",
|
|
166
|
-
"@connectrpc/connect": "1.7.0",
|
|
167
|
-
"@connectrpc/connect-web": "1.7.0",
|
|
168
|
-
"@langchain/anthropic": "^1.4.0",
|
|
169
168
|
"@neodrag/svelte": "^2.3.3",
|
|
170
169
|
"d3-force": "^3.0.0",
|
|
171
170
|
"filtrex": "^3.1.0",
|
|
172
171
|
"koota": "0.6.5",
|
|
173
172
|
"lodash-es": "4.18.1",
|
|
174
173
|
"three-mesh-bvh": "^0.9.8",
|
|
175
|
-
"uuid-tool": "^2.0.3"
|
|
176
|
-
"zod": "^4.4.3"
|
|
174
|
+
"uuid-tool": "^2.0.3"
|
|
177
175
|
},
|
|
178
176
|
"scripts": {
|
|
179
177
|
"dev": "concurrently \"pnpm dev:bun\" \"go run cmd/draw-server/main.go -port 3030\"",
|
|
@@ -1,144 +0,0 @@
|
|
|
1
|
-
<script lang="ts">
|
|
2
|
-
import { Portal } from '@threlte/extras'
|
|
3
|
-
import { PersistedState } from 'runed'
|
|
4
|
-
|
|
5
|
-
import { useLogs } from '../../hooks/useLogs.svelte'
|
|
6
|
-
|
|
7
|
-
import DashboardButton from './dashboard/Button.svelte'
|
|
8
|
-
import FloatingPanel from './FloatingPanel.svelte'
|
|
9
|
-
|
|
10
|
-
const logs = useLogs()
|
|
11
|
-
|
|
12
|
-
const isOpen = new PersistedState('logs-is-open', false)
|
|
13
|
-
|
|
14
|
-
let levels = new PersistedState('logs-selected-levels', {
|
|
15
|
-
info: true,
|
|
16
|
-
warn: true,
|
|
17
|
-
error: true,
|
|
18
|
-
})
|
|
19
|
-
</script>
|
|
20
|
-
|
|
21
|
-
<Portal id="dashboard">
|
|
22
|
-
<fieldset class="relative">
|
|
23
|
-
<DashboardButton
|
|
24
|
-
active={isOpen.current}
|
|
25
|
-
icon="article"
|
|
26
|
-
description="Logs"
|
|
27
|
-
onclick={() => {
|
|
28
|
-
isOpen.current = !isOpen.current
|
|
29
|
-
}}
|
|
30
|
-
/>
|
|
31
|
-
{#if logs.warnings.length > 0}
|
|
32
|
-
<span
|
|
33
|
-
class="absolute z-4 -mt-1.5 -ml-1.5 h-4 w-4 rounded-full bg-yellow-700 text-center text-[10px] text-white"
|
|
34
|
-
>
|
|
35
|
-
{logs.warnings.length}
|
|
36
|
-
</span>
|
|
37
|
-
{/if}
|
|
38
|
-
|
|
39
|
-
{#if logs.errors.length > 0}
|
|
40
|
-
<span
|
|
41
|
-
class="absolute z-4 -mt-1.5 -ml-1.5 h-4 rounded-full bg-red-700 px-1.25 text-center text-[10px] text-white"
|
|
42
|
-
>
|
|
43
|
-
{logs.errors.length}
|
|
44
|
-
</span>
|
|
45
|
-
{/if}
|
|
46
|
-
</fieldset>
|
|
47
|
-
</Portal>
|
|
48
|
-
|
|
49
|
-
<FloatingPanel
|
|
50
|
-
title="Logs"
|
|
51
|
-
bind:isOpen={isOpen.current}
|
|
52
|
-
defaultSize={{ width: 240, height: 315 }}
|
|
53
|
-
resizable
|
|
54
|
-
>
|
|
55
|
-
<div class="flex h-full flex-col">
|
|
56
|
-
<div class="flex gap-1 px-3 py-2">
|
|
57
|
-
<button
|
|
58
|
-
type="button"
|
|
59
|
-
class={[
|
|
60
|
-
'chip border px-2',
|
|
61
|
-
{
|
|
62
|
-
'border-danger-dark bg-danger-dark text-white hover:border-red-700 hover:bg-red-700':
|
|
63
|
-
levels.current.error,
|
|
64
|
-
'bg-light hover:bg-ghost-light hover:border-light border-light text-subtle-1':
|
|
65
|
-
!levels.current.error,
|
|
66
|
-
},
|
|
67
|
-
]}
|
|
68
|
-
onclick={() => {
|
|
69
|
-
levels.current.error = !levels.current.error
|
|
70
|
-
}}
|
|
71
|
-
>
|
|
72
|
-
error
|
|
73
|
-
</button>
|
|
74
|
-
|
|
75
|
-
<button
|
|
76
|
-
type="button"
|
|
77
|
-
class={[
|
|
78
|
-
'chip border',
|
|
79
|
-
{
|
|
80
|
-
'border-amber-400 bg-amber-400 text-white hover:border-amber-500 hover:bg-amber-500':
|
|
81
|
-
levels.current.warn,
|
|
82
|
-
'bg-light hover:bg-ghost-light hover:border-light border-light text-subtle-1':
|
|
83
|
-
!levels.current.warn,
|
|
84
|
-
},
|
|
85
|
-
]}
|
|
86
|
-
onclick={() => {
|
|
87
|
-
levels.current.warn = !levels.current.warn
|
|
88
|
-
}}
|
|
89
|
-
>
|
|
90
|
-
warn
|
|
91
|
-
</button>
|
|
92
|
-
|
|
93
|
-
<button
|
|
94
|
-
type="button"
|
|
95
|
-
class={[
|
|
96
|
-
'chip border',
|
|
97
|
-
{
|
|
98
|
-
'border-blue-400 bg-blue-400 text-white hover:border-blue-500 hover:bg-blue-500':
|
|
99
|
-
levels.current.info,
|
|
100
|
-
'bg-light hover:bg-ghost-light hover:border-light border-light text-subtle-1':
|
|
101
|
-
!levels.current.info,
|
|
102
|
-
},
|
|
103
|
-
]}
|
|
104
|
-
onclick={() => {
|
|
105
|
-
levels.current.info = !levels.current.info
|
|
106
|
-
}}
|
|
107
|
-
>
|
|
108
|
-
info
|
|
109
|
-
</button>
|
|
110
|
-
</div>
|
|
111
|
-
|
|
112
|
-
<div class="flex flex-col gap-2 overflow-auto px-3 pb-3 text-xs">
|
|
113
|
-
{#each logs.current as log (log.uuid)}
|
|
114
|
-
{#if levels.current[log.level]}
|
|
115
|
-
<div>
|
|
116
|
-
<div class="flex flex-wrap items-center gap-1.5">
|
|
117
|
-
<div
|
|
118
|
-
class={[
|
|
119
|
-
'h-2 w-2 rounded-full',
|
|
120
|
-
{
|
|
121
|
-
'bg-danger-dark': log.level === 'error',
|
|
122
|
-
'bg-amber-300': log.level === 'warn',
|
|
123
|
-
'bg-blue-400': log.level === 'info',
|
|
124
|
-
},
|
|
125
|
-
]}
|
|
126
|
-
></div>
|
|
127
|
-
<div class="text-subtle-2">{log.timestamp}</div>
|
|
128
|
-
</div>
|
|
129
|
-
<div>
|
|
130
|
-
{#if log.count > 1}
|
|
131
|
-
<span class="mr-1 rounded bg-green-700 px-1 py-0.5 text-xs text-white">
|
|
132
|
-
{log.count}
|
|
133
|
-
</span>
|
|
134
|
-
{/if}
|
|
135
|
-
{log.message}
|
|
136
|
-
</div>
|
|
137
|
-
</div>
|
|
138
|
-
{/if}
|
|
139
|
-
{:else}
|
|
140
|
-
No logs
|
|
141
|
-
{/each}
|
|
142
|
-
</div>
|
|
143
|
-
</div>
|
|
144
|
-
</FloatingPanel>
|
|
File without changes
|