@viamrobotics/test-widgets 0.1.9 → 0.1.11
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/widgets/camera/camera.svelte +146 -78
- package/dist/components/widgets/camera/get-source-names.d.ts +4 -0
- package/dist/components/widgets/camera/get-source-names.js +4 -0
- package/dist/components/widgets/vision-service/use-slow-request.svelte.d.ts +3 -0
- package/dist/components/widgets/vision-service/use-slow-request.svelte.js +22 -0
- package/dist/components/widgets/vision-service/vision-service.svelte +31 -0
- package/package.json +29 -29
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<script lang="ts">
|
|
2
|
-
import { Button, Label, Switch, ToggleButtons } from '@viamrobotics/prime-core'
|
|
2
|
+
import { Button, Label, Select, Switch, ToggleButtons } from '@viamrobotics/prime-core'
|
|
3
3
|
import { CameraClient } from '@viamrobotics/sdk'
|
|
4
4
|
import { createResourceClient, createResourceQuery } from '@viamrobotics/svelte-sdk'
|
|
5
5
|
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
|
|
15
15
|
import PCDWidget from '../pcd/pcd-widget.svelte'
|
|
16
16
|
import ExportScreenshot from './export-screenshot.svelte'
|
|
17
|
+
import { getSourceNames } from './get-source-names'
|
|
17
18
|
import LiveOrPollingVideo from './live-or-polling-video.svelte'
|
|
18
19
|
import PictureInPictureButton from './picture-in-picture-button.svelte'
|
|
19
20
|
|
|
@@ -29,7 +30,17 @@
|
|
|
29
30
|
() => resourceName,
|
|
30
31
|
'camera'
|
|
31
32
|
)
|
|
33
|
+
let isPlaying = $state(false)
|
|
34
|
+
$effect(() => {
|
|
35
|
+
// Reset the play gate whenever the camera identity changes so a swapped
|
|
36
|
+
// resource doesn't auto-start using the previous instance's state.
|
|
37
|
+
void resourceName
|
|
38
|
+
void partID
|
|
39
|
+
isPlaying = false
|
|
40
|
+
})
|
|
32
41
|
let isShowingPointcloud = $state(false)
|
|
42
|
+
let selectedSource = $state('')
|
|
43
|
+
let sourceNames = $state<string[]>([])
|
|
33
44
|
|
|
34
45
|
const { addImageToDataset } = useAddImageToDataset()
|
|
35
46
|
const setIsShowingPointcloud = (event: CustomEvent<boolean>) => {
|
|
@@ -42,10 +53,25 @@
|
|
|
42
53
|
() => resourceName
|
|
43
54
|
)
|
|
44
55
|
|
|
45
|
-
const imageQuery = createResourceQuery(
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
56
|
+
const imageQuery = createResourceQuery(
|
|
57
|
+
client,
|
|
58
|
+
'getImages',
|
|
59
|
+
() => (selectedSource ? ([[selectedSource]] as [string[]]) : ([] as [])),
|
|
60
|
+
() => ({
|
|
61
|
+
enabled: isPlaying && refetchInterval.current !== RefetchIntervals.LIVE,
|
|
62
|
+
refetchInterval: refetchInterval.current,
|
|
63
|
+
})
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
$effect(() => {
|
|
67
|
+
if (sourceNames.length === 0 && imageQuery.data?.images) {
|
|
68
|
+
const names = getSourceNames(imageQuery.data.images)
|
|
69
|
+
if (names.length > 0) {
|
|
70
|
+
sourceNames = names
|
|
71
|
+
selectedSource = names[0]!
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
})
|
|
49
75
|
|
|
50
76
|
const pointcloudQuery = createResourceQuery(client, 'getPointCloud', () => ({
|
|
51
77
|
enabled: isShowingPointcloud,
|
|
@@ -59,15 +85,25 @@
|
|
|
59
85
|
// A separate, disabled query for exporting a screenshot
|
|
60
86
|
// since this button should work regardless of refetch
|
|
61
87
|
// interval and not affect the image feed.
|
|
62
|
-
const exportScreenshotQuery = createResourceQuery(
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
88
|
+
const exportScreenshotQuery = createResourceQuery(
|
|
89
|
+
client,
|
|
90
|
+
'getImages',
|
|
91
|
+
() => (selectedSource ? ([[selectedSource]] as [string[]]) : ([] as [])),
|
|
92
|
+
{
|
|
93
|
+
enabled: false,
|
|
94
|
+
refetchInterval: false,
|
|
95
|
+
}
|
|
96
|
+
)
|
|
66
97
|
|
|
67
98
|
// Firefox has native support for picture-in-picture and does not need
|
|
68
99
|
// to be requested separately. Don't show a "toggle pip" button in Firefox.
|
|
69
100
|
const isFirefox = navigator.userAgent.toLowerCase().includes('firefox')
|
|
70
101
|
|
|
102
|
+
const onSourceSelect = (event: Event) => {
|
|
103
|
+
const { value } = event.target as HTMLSelectElement
|
|
104
|
+
selectedSource = value
|
|
105
|
+
}
|
|
106
|
+
|
|
71
107
|
let mousePostionTooltip = $state<'On' | 'Off'>('Off')
|
|
72
108
|
const setMousePostionTooltip = (event: CustomEvent<string>) => {
|
|
73
109
|
mousePostionTooltip = event.detail as 'On' | 'Off'
|
|
@@ -78,81 +114,113 @@
|
|
|
78
114
|
|
|
79
115
|
<ConnectionStatus {partID}>
|
|
80
116
|
{#snippet connected()}
|
|
81
|
-
|
|
82
|
-
<
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
</div>
|
|
88
|
-
<div class="flex h-full w-full gap-4 p-4">
|
|
89
|
-
<div class="grow">
|
|
90
|
-
<LiveOrPollingVideo
|
|
91
|
-
{partID}
|
|
92
|
-
{resourceName}
|
|
93
|
-
showResolutionOptions
|
|
94
|
-
isLive={refetchInterval.current === RefetchIntervals.LIVE}
|
|
95
|
-
data={imageQuery.data}
|
|
96
|
-
error={imageQuery.error}
|
|
97
|
-
isLoading={imageQuery.isLoading}
|
|
98
|
-
refetch={imageQuery.refetch}
|
|
99
|
-
showMousePositionTooltip={mousePostionTooltip === 'On'}
|
|
117
|
+
{#if isPlaying}
|
|
118
|
+
<div class="flex gap-4 p-4 pb-3">
|
|
119
|
+
<RefetchController
|
|
120
|
+
{refetchInterval}
|
|
121
|
+
allowLive
|
|
122
|
+
queries={[imageQuery, pointcloudQuery]}
|
|
100
123
|
/>
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
if (!isSuccess) return
|
|
115
|
-
imgData = data
|
|
116
|
-
} else {
|
|
117
|
-
imgData = imageQuery.data
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
const image = imgData?.images?.[0]?.image
|
|
121
|
-
const mimeType = imgData?.images?.[0]?.mimeType
|
|
122
|
-
|
|
123
|
-
if (image) {
|
|
124
|
-
addImageToDataset({
|
|
125
|
-
binaryData: new Uint8Array(image),
|
|
126
|
-
partID,
|
|
127
|
-
componentType: 'camera',
|
|
128
|
-
componentName: resourceName,
|
|
129
|
-
methodName: 'captureAllFromCamera',
|
|
130
|
-
mimeType: mimeType ?? 'image/png',
|
|
131
|
-
dataRequestTimes: [new Date(), new Date()],
|
|
132
|
-
})
|
|
133
|
-
}
|
|
134
|
-
}}
|
|
135
|
-
>
|
|
136
|
-
Add current image to dataset
|
|
137
|
-
</Button>
|
|
124
|
+
{#if sourceNames.length > 0 && refetchInterval.current !== RefetchIntervals.LIVE}
|
|
125
|
+
<Label position="left">
|
|
126
|
+
Source
|
|
127
|
+
<Select
|
|
128
|
+
value={selectedSource}
|
|
129
|
+
on:change={onSourceSelect}
|
|
130
|
+
slot="input"
|
|
131
|
+
>
|
|
132
|
+
{#each sourceNames as name (name)}
|
|
133
|
+
<option value={name}>{name}</option>
|
|
134
|
+
{/each}
|
|
135
|
+
</Select>
|
|
136
|
+
</Label>
|
|
138
137
|
{/if}
|
|
139
|
-
|
|
140
|
-
|
|
138
|
+
</div>
|
|
139
|
+
{/if}
|
|
140
|
+
<div class="flex h-full w-full gap-4 p-4">
|
|
141
|
+
<div class="grow">
|
|
142
|
+
{#if isPlaying}
|
|
143
|
+
<LiveOrPollingVideo
|
|
144
|
+
{partID}
|
|
141
145
|
{resourceName}
|
|
142
|
-
|
|
146
|
+
showResolutionOptions
|
|
147
|
+
isLive={refetchInterval.current === RefetchIntervals.LIVE}
|
|
148
|
+
data={imageQuery.data}
|
|
149
|
+
error={imageQuery.error}
|
|
150
|
+
isLoading={imageQuery.isLoading}
|
|
151
|
+
refetch={imageQuery.refetch}
|
|
152
|
+
showMousePositionTooltip={mousePostionTooltip === 'On'}
|
|
143
153
|
/>
|
|
154
|
+
{:else}
|
|
155
|
+
<div class="bg-medium flex h-64 w-80 items-center justify-center">
|
|
156
|
+
<Button
|
|
157
|
+
icon="play-circle-outline"
|
|
158
|
+
variant="dark"
|
|
159
|
+
onclick={() => {
|
|
160
|
+
isPlaying = true
|
|
161
|
+
}}
|
|
162
|
+
>
|
|
163
|
+
Start feed
|
|
164
|
+
</Button>
|
|
165
|
+
</div>
|
|
144
166
|
{/if}
|
|
145
|
-
<Label>
|
|
146
|
-
Mouse Position Tooltip
|
|
147
|
-
|
|
148
|
-
<ToggleButtons
|
|
149
|
-
slot="input"
|
|
150
|
-
options={['On', 'Off']}
|
|
151
|
-
selected={mousePostionTooltip}
|
|
152
|
-
on:input={setMousePostionTooltip}
|
|
153
|
-
/>
|
|
154
|
-
</Label>
|
|
155
167
|
</div>
|
|
168
|
+
{#if isPlaying}
|
|
169
|
+
<div class="flex flex-col items-start gap-2">
|
|
170
|
+
<ExportScreenshot
|
|
171
|
+
name={client.current?.name ?? ''}
|
|
172
|
+
getImage={exportScreenshotQuery.refetch}
|
|
173
|
+
/>
|
|
174
|
+
{#if addImageToDataset}
|
|
175
|
+
<Button
|
|
176
|
+
icon="layers-triple-outline"
|
|
177
|
+
onclick={async () => {
|
|
178
|
+
let imgData
|
|
179
|
+
if (refetchInterval.current === RefetchIntervals.LIVE) {
|
|
180
|
+
const { isSuccess, data } = await imageQuery.refetch()
|
|
181
|
+
if (!isSuccess) return
|
|
182
|
+
imgData = data
|
|
183
|
+
} else {
|
|
184
|
+
imgData = imageQuery.data
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
const image = imgData?.images?.[0]?.image
|
|
188
|
+
const mimeType = imgData?.images?.[0]?.mimeType
|
|
189
|
+
|
|
190
|
+
if (image) {
|
|
191
|
+
addImageToDataset({
|
|
192
|
+
binaryData: new Uint8Array(image),
|
|
193
|
+
partID,
|
|
194
|
+
componentType: 'camera',
|
|
195
|
+
componentName: resourceName,
|
|
196
|
+
methodName: 'captureAllFromCamera',
|
|
197
|
+
mimeType: mimeType ?? 'image/png',
|
|
198
|
+
dataRequestTimes: [new Date(), new Date()],
|
|
199
|
+
})
|
|
200
|
+
}
|
|
201
|
+
}}
|
|
202
|
+
>
|
|
203
|
+
Add current image to dataset
|
|
204
|
+
</Button>
|
|
205
|
+
{/if}
|
|
206
|
+
{#if !isFirefox}
|
|
207
|
+
<PictureInPictureButton
|
|
208
|
+
{resourceName}
|
|
209
|
+
rate={refetchInterval.current}
|
|
210
|
+
/>
|
|
211
|
+
{/if}
|
|
212
|
+
<Label>
|
|
213
|
+
Mouse Position Tooltip
|
|
214
|
+
|
|
215
|
+
<ToggleButtons
|
|
216
|
+
slot="input"
|
|
217
|
+
options={['On', 'Off']}
|
|
218
|
+
selected={mousePostionTooltip}
|
|
219
|
+
on:input={setMousePostionTooltip}
|
|
220
|
+
/>
|
|
221
|
+
</Label>
|
|
222
|
+
</div>
|
|
223
|
+
{/if}
|
|
156
224
|
</div>
|
|
157
225
|
|
|
158
226
|
<section
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
const SLOW_REQUEST_THRESHOLD_MS = 5000;
|
|
2
|
+
export const useSlowRequest = (isFetching) => {
|
|
3
|
+
let isSlow = $state(false);
|
|
4
|
+
$effect(() => {
|
|
5
|
+
if (!isFetching()) {
|
|
6
|
+
isSlow = false;
|
|
7
|
+
return;
|
|
8
|
+
}
|
|
9
|
+
isSlow = false;
|
|
10
|
+
const timeout = setTimeout(() => {
|
|
11
|
+
isSlow = true;
|
|
12
|
+
}, SLOW_REQUEST_THRESHOLD_MS);
|
|
13
|
+
return () => {
|
|
14
|
+
clearTimeout(timeout);
|
|
15
|
+
};
|
|
16
|
+
});
|
|
17
|
+
return {
|
|
18
|
+
get isSlow() {
|
|
19
|
+
return isSlow;
|
|
20
|
+
},
|
|
21
|
+
};
|
|
22
|
+
};
|
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
|
|
16
16
|
import Image from './image.svelte'
|
|
17
17
|
import ObjectPointClouds from './object-point-clouds.svelte'
|
|
18
|
+
import { useSlowRequest } from './use-slow-request.svelte.js'
|
|
18
19
|
|
|
19
20
|
const { addImageToDataset } = useAddImageToDataset()
|
|
20
21
|
|
|
@@ -106,10 +107,16 @@
|
|
|
106
107
|
: (Math.max(getObjectPointCloudsRefetchInterval.current, 1000 / 20) as number | false),
|
|
107
108
|
}))
|
|
108
109
|
|
|
110
|
+
const captureAllSlow = useSlowRequest(() => captureAllQuery.isFetching)
|
|
111
|
+
const propertiesSlow = useSlowRequest(() => propertiesQuery.isFetching)
|
|
112
|
+
const objectPointCloudsSlow = useSlowRequest(() => getObjectPointCloudsQuery.isFetching)
|
|
113
|
+
|
|
109
114
|
const onCameraSelect = (event: Event) => {
|
|
110
115
|
const { value } = event.target as HTMLSelectElement
|
|
111
116
|
cameraName = value
|
|
112
117
|
}
|
|
118
|
+
|
|
119
|
+
const detectionsSlow = $derived(captureAllSlow.isSlow || propertiesSlow.isSlow)
|
|
113
120
|
</script>
|
|
114
121
|
|
|
115
122
|
<ConnectionStatus {partID}>
|
|
@@ -123,6 +130,12 @@
|
|
|
123
130
|
on:change={onCameraSelect}
|
|
124
131
|
slot="input"
|
|
125
132
|
>
|
|
133
|
+
<option
|
|
134
|
+
value=""
|
|
135
|
+
selected={cameraName === ''}
|
|
136
|
+
>
|
|
137
|
+
Default camera
|
|
138
|
+
</option>
|
|
126
139
|
{#each cameras.current as { name } (name)}
|
|
127
140
|
<option
|
|
128
141
|
selected={cameraName === name}
|
|
@@ -183,10 +196,19 @@
|
|
|
183
196
|
{/if}
|
|
184
197
|
</div>
|
|
185
198
|
|
|
199
|
+
{#if detectionsSlow}
|
|
200
|
+
<p class="text-subtle-2 text-xs italic">This request is taking a long time to complete.</p>
|
|
201
|
+
{/if}
|
|
202
|
+
|
|
186
203
|
<Queries
|
|
187
204
|
queries={[propertiesQuery, captureAllQuery]}
|
|
188
205
|
contentCx="p-4 h-14"
|
|
189
206
|
>
|
|
207
|
+
{#if detectionsSlow}
|
|
208
|
+
<p class="text-subtle-2 text-xs italic">
|
|
209
|
+
This request is taking a long time to complete.
|
|
210
|
+
</p>
|
|
211
|
+
{/if}
|
|
190
212
|
{#if captureAllQuery.data}
|
|
191
213
|
<Image
|
|
192
214
|
data={captureAllQuery.data}
|
|
@@ -213,11 +235,20 @@
|
|
|
213
235
|
/>
|
|
214
236
|
</div>
|
|
215
237
|
|
|
238
|
+
{#if showObjectPointClouds && objectPointCloudsSlow}
|
|
239
|
+
<p class="text-subtle-2 text-xs italic">This request is taking a long time to complete.</p>
|
|
240
|
+
{/if}
|
|
241
|
+
|
|
216
242
|
{#if showObjectPointClouds}
|
|
217
243
|
<Queries
|
|
218
244
|
queries={[getObjectPointCloudsQuery]}
|
|
219
245
|
contentCx="p-4 h-14"
|
|
220
246
|
>
|
|
247
|
+
{#if objectPointCloudsSlow.isSlow}
|
|
248
|
+
<p class="text-subtle-2 text-xs italic">
|
|
249
|
+
This request is taking a long time to complete.
|
|
250
|
+
</p>
|
|
251
|
+
{/if}
|
|
221
252
|
{#if getObjectPointCloudsQuery.data !== undefined}
|
|
222
253
|
<ObjectPointClouds objects={getObjectPointCloudsQuery.data} />
|
|
223
254
|
{/if}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@viamrobotics/test-widgets",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.11",
|
|
4
4
|
"license": "Apache-2.0",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"files": [
|
|
@@ -41,71 +41,71 @@
|
|
|
41
41
|
"threlte-uikit": ">=2"
|
|
42
42
|
},
|
|
43
43
|
"devDependencies": {
|
|
44
|
-
"@changesets/cli": "^2.
|
|
44
|
+
"@changesets/cli": "^2.31.0",
|
|
45
45
|
"@eslint/compat": "^2.0.5",
|
|
46
46
|
"@eslint/js": "^10.0.1",
|
|
47
47
|
"@fontsource-variable/public-sans": "^5.2.7",
|
|
48
48
|
"@fontsource-variable/roboto-mono": "^5.2.8",
|
|
49
49
|
"@fontsource-variable/space-grotesk": "^5.2.10",
|
|
50
50
|
"@playwright/test": "^1.59.1",
|
|
51
|
-
"@sentry/svelte": "^10.
|
|
51
|
+
"@sentry/svelte": "^10.50.0",
|
|
52
52
|
"@sveltejs/adapter-static": "^3.0.10",
|
|
53
|
-
"@sveltejs/kit": "^2.
|
|
53
|
+
"@sveltejs/kit": "^2.58.0",
|
|
54
54
|
"@sveltejs/package": "^2.5.7",
|
|
55
55
|
"@sveltejs/vite-plugin-svelte": "^7.0.0",
|
|
56
|
-
"@tailwindcss/postcss": "^4.2.
|
|
57
|
-
"@tailwindcss/vite": "^4.2.
|
|
58
|
-
"@tanstack/svelte-query": "^6.1.
|
|
59
|
-
"@tanstack/svelte-query-devtools": "^6.1.
|
|
56
|
+
"@tailwindcss/postcss": "^4.2.4",
|
|
57
|
+
"@tailwindcss/vite": "^4.2.4",
|
|
58
|
+
"@tanstack/svelte-query": "^6.1.24",
|
|
59
|
+
"@tanstack/svelte-query-devtools": "^6.1.24",
|
|
60
60
|
"@testing-library/dom": "^10.4.1",
|
|
61
61
|
"@testing-library/jest-dom": "^6.9.1",
|
|
62
62
|
"@testing-library/svelte": "^5.3.1",
|
|
63
63
|
"@testing-library/user-event": "^14.6.1",
|
|
64
64
|
"@threlte/core": "^8.5.9",
|
|
65
|
-
"@threlte/extras": "^9.
|
|
66
|
-
"@threlte/test": "^2.0
|
|
65
|
+
"@threlte/extras": "^9.15.0",
|
|
66
|
+
"@threlte/test": "^2.1.0",
|
|
67
67
|
"@types/lodash-es": "^4.17.12",
|
|
68
|
-
"@types/node": "^25",
|
|
68
|
+
"@types/node": "^25.6.0",
|
|
69
69
|
"@types/three": "^0.183.1",
|
|
70
|
-
"@viamrobotics/motion-tools": "^1.
|
|
71
|
-
"@viamrobotics/prime-core": "^0.1.
|
|
70
|
+
"@viamrobotics/motion-tools": "^1.19.1",
|
|
71
|
+
"@viamrobotics/prime-core": "^0.1.19",
|
|
72
72
|
"@viamrobotics/prime-editor": "^0.0.2",
|
|
73
73
|
"@viamrobotics/sdk": "^0.68.2",
|
|
74
|
-
"@viamrobotics/svelte-sdk": "^1.1
|
|
74
|
+
"@viamrobotics/svelte-sdk": "^1.2.1",
|
|
75
75
|
"@viamrobotics/tailwind-config": "^1.0.0",
|
|
76
76
|
"@viamrobotics/three": "^0.0.9",
|
|
77
|
-
"@vitest/browser": "^4.1.
|
|
78
|
-
"@vitest/browser-playwright": "^4.1.
|
|
79
|
-
"@vitest/coverage-v8": "^4.1.
|
|
80
|
-
"eslint": "^10.2.
|
|
77
|
+
"@vitest/browser": "^4.1.5",
|
|
78
|
+
"@vitest/browser-playwright": "^4.1.5",
|
|
79
|
+
"@vitest/coverage-v8": "^4.1.5",
|
|
80
|
+
"eslint": "^10.2.1",
|
|
81
81
|
"eslint-config-prettier": "^10.1.8",
|
|
82
|
-
"eslint-plugin-perfectionist": "^5.
|
|
83
|
-
"eslint-plugin-svelte": "^3.17.
|
|
82
|
+
"eslint-plugin-perfectionist": "^5.9.0",
|
|
83
|
+
"eslint-plugin-svelte": "^3.17.1",
|
|
84
84
|
"eslint-plugin-unicorn": "^64.0.0",
|
|
85
85
|
"globals": "^17.5.0",
|
|
86
86
|
"lodash-es": "^4.18.1",
|
|
87
|
-
"maplibre-gl": "^5.
|
|
87
|
+
"maplibre-gl": "^5.24.0",
|
|
88
88
|
"mock-match-media": "^1.0.3",
|
|
89
89
|
"playwright": "^1.59.1",
|
|
90
90
|
"prettier": "^3.8.3",
|
|
91
91
|
"prettier-plugin-svelte": "^3.5.1",
|
|
92
|
-
"prettier-plugin-tailwindcss": "^0.7.
|
|
92
|
+
"prettier-plugin-tailwindcss": "^0.7.4",
|
|
93
93
|
"publint": "^0.3.18",
|
|
94
94
|
"runed": "^0.37.1",
|
|
95
|
-
"svelte": "^5.55.
|
|
95
|
+
"svelte": "^5.55.5",
|
|
96
96
|
"svelte-check": "^4.4.6",
|
|
97
97
|
"svelte-splitpanes": "^8.0.12",
|
|
98
98
|
"tailwind-merge": "^3.5.0",
|
|
99
|
-
"tailwindcss": "^4.2.
|
|
99
|
+
"tailwindcss": "^4.2.4",
|
|
100
100
|
"three": "^0.183.2",
|
|
101
101
|
"threlte-uikit": "^2.0.0",
|
|
102
|
-
"type-fest": "^5.
|
|
103
|
-
"typescript": "^6.0.
|
|
104
|
-
"typescript-eslint": "^8.
|
|
105
|
-
"vite": "^8.0.
|
|
102
|
+
"type-fest": "^5.6.0",
|
|
103
|
+
"typescript": "^6.0.3",
|
|
104
|
+
"typescript-eslint": "^8.59.1",
|
|
105
|
+
"vite": "^8.0.10",
|
|
106
106
|
"vite-plugin-devtools-json": "^1.0.0",
|
|
107
107
|
"vite-plugin-glsl": "^1.6.0",
|
|
108
|
-
"vitest": "^4.1.
|
|
108
|
+
"vitest": "^4.1.5",
|
|
109
109
|
"vitest-browser-svelte": "^2.1.1"
|
|
110
110
|
},
|
|
111
111
|
"engines": {
|