@viamrobotics/motion-tools 1.34.3 → 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.
@@ -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 '../../hooks/useLogs.svelte';
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';
@@ -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>
@@ -12,6 +12,6 @@ interface Context {
12
12
  warnings: Log[];
13
13
  add(message: string, level?: Level): void;
14
14
  }
15
- export declare const provideLogs: () => void;
15
+ export declare const provideLogs: () => Context;
16
16
  export declare const useLogs: () => Context;
17
17
  export {};
@@ -1,7 +1,8 @@
1
- import { getContext, setContext, untrack } from 'svelte';
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
- setContext(key, {
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 getContext(key);
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
  };
@@ -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';
@@ -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",
3
+ "version": "1.34.4",
4
4
  "description": "Motion visualization with Viam",
5
5
  "license": "Apache-2.0",
6
6
  "type": "module",
@@ -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>