diff --git a/.clinerules b/.clinerules
index 3fbdcfad..a8d86dea 100644
--- a/.clinerules
+++ b/.clinerules
@@ -1,3 +1,3 @@
Test via `dotnet watch --project src`
Don't fix warnings and typescript issues unless it relates to your task
-src/ui is svelete 5 please don't use old syntax
\ No newline at end of file
+src/ui is svelete 5 please don't use old syntax
diff --git a/src/ui/package-lock.json b/src/ui/package-lock.json
index fbb467c1..70aa1f71 100644
--- a/src/ui/package-lock.json
+++ b/src/ui/package-lock.json
@@ -19,6 +19,7 @@
"@types/cookie": "^1.0.0",
"@types/d3": "^7.4.3",
"@types/node": "^22.9.1",
+ "@types/three": "^0.171.0",
"@typescript-eslint/eslint-plugin": "^8.15.0",
"@typescript-eslint/parser": "^8.15.0",
"autoprefixer": "^10.4.20",
@@ -36,6 +37,7 @@
"svelte-check": "^4.0.9",
"svelte-eslint-parser": "^0.43.0",
"svelte-table": "^0.6.3",
+ "three": "^0.171.0",
"tslib": "^2.8.1",
"typescript": "^5.6.3",
"typescript-eslint": "^8.18.2",
@@ -1188,6 +1190,12 @@
"tailwindcss": ">=3.0.0 || >= 3.0.0-alpha.1 || >= 4.0.0-alpha.20"
}
},
+ "node_modules/@tweenjs/tween.js": {
+ "version": "23.1.3",
+ "resolved": "https://registry.npmjs.org/@tweenjs/tween.js/-/tween.js-23.1.3.tgz",
+ "integrity": "sha512-vJmvvwFxYuGnF2axRtPYocag6Clbb5YS7kLL+SO/TeVFzHqDIWrNKYtcsPMibjDx9O+bu+psAy9NKfWklassUA==",
+ "dev": true
+ },
"node_modules/@types/cookie": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-1.0.0.tgz",
@@ -1478,6 +1486,32 @@
"undici-types": "~6.19.8"
}
},
+ "node_modules/@types/stats.js": {
+ "version": "0.17.3",
+ "resolved": "https://registry.npmjs.org/@types/stats.js/-/stats.js-0.17.3.tgz",
+ "integrity": "sha512-pXNfAD3KHOdif9EQXZ9deK82HVNaXP5ZIF5RP2QG6OQFNTaY2YIetfrE9t528vEreGQvEPRDDc8muaoYeK0SxQ==",
+ "dev": true
+ },
+ "node_modules/@types/three": {
+ "version": "0.171.0",
+ "resolved": "https://registry.npmjs.org/@types/three/-/three-0.171.0.tgz",
+ "integrity": "sha512-oLuT1SAsT+CUg/wxUTFHo0K3NtJLnx9sJhZWQJp/0uXqFpzSk1hRHmvWvpaAWSfvx2db0lVKZ5/wV0I0isD2mQ==",
+ "dev": true,
+ "dependencies": {
+ "@tweenjs/tween.js": "~23.1.3",
+ "@types/stats.js": "*",
+ "@types/webxr": "*",
+ "@webgpu/types": "*",
+ "fflate": "~0.8.2",
+ "meshoptimizer": "~0.18.1"
+ }
+ },
+ "node_modules/@types/webxr": {
+ "version": "0.5.20",
+ "resolved": "https://registry.npmjs.org/@types/webxr/-/webxr-0.5.20.tgz",
+ "integrity": "sha512-JGpU6qiIJQKUuVSKx1GtQnHJGxRjtfGIhzO2ilq43VZZS//f1h1Sgexbdk+Lq+7569a6EYhOWrUpIruR/1Enmg==",
+ "dev": true
+ },
"node_modules/@typescript-eslint/eslint-plugin": {
"version": "8.18.2",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.18.2.tgz",
@@ -1768,6 +1802,12 @@
"url": "https://opencollective.com/vitest"
}
},
+ "node_modules/@webgpu/types": {
+ "version": "0.1.51",
+ "resolved": "https://registry.npmjs.org/@webgpu/types/-/types-0.1.51.tgz",
+ "integrity": "sha512-ktR3u64NPjwIViNCck+z9QeyN0iPkQCUOQ07ZCV1RzlkfP+olLTeEZ95O1QHS+v4w9vJeY9xj/uJuSphsHy5rQ==",
+ "dev": true
+ },
"node_modules/acorn": {
"version": "8.14.0",
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz",
@@ -3181,6 +3221,12 @@
"reusify": "^1.0.4"
}
},
+ "node_modules/fflate": {
+ "version": "0.8.2",
+ "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.8.2.tgz",
+ "integrity": "sha512-cPJU47OaAoCbg0pBvzsgpTPhmhqI5eJjh/JIu8tPj5q+T7iLvW/JAYUqmE7KOB4R1ZyEhzBaIQpQpardBF5z8A==",
+ "dev": true
+ },
"node_modules/file-entry-cache": {
"version": "8.0.0",
"resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz",
@@ -3693,6 +3739,12 @@
"node": ">= 8"
}
},
+ "node_modules/meshoptimizer": {
+ "version": "0.18.1",
+ "resolved": "https://registry.npmjs.org/meshoptimizer/-/meshoptimizer-0.18.1.tgz",
+ "integrity": "sha512-ZhoIoL7TNV4s5B6+rx5mC//fw8/POGyNxS/DZyCJeiZ12ScLfVwRE/GfsxwiTkMYYD5DmK2/JXnEVXqL4rF+Sw==",
+ "dev": true
+ },
"node_modules/micromatch": {
"version": "4.0.8",
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
@@ -5042,6 +5094,12 @@
"node": ">=0.8"
}
},
+ "node_modules/three": {
+ "version": "0.171.0",
+ "resolved": "https://registry.npmjs.org/three/-/three-0.171.0.tgz",
+ "integrity": "sha512-Y/lAXPaKZPcEdkKjh0JOAHVv8OOnv/NDJqm0wjfCzyQmfKxV7zvkwsnBgPBKTzJHToSOhRGQAGbPJObT59B/PQ==",
+ "dev": true
+ },
"node_modules/tiny-glob": {
"version": "0.2.9",
"resolved": "https://registry.npmjs.org/tiny-glob/-/tiny-glob-0.2.9.tgz",
diff --git a/src/ui/package.json b/src/ui/package.json
index 6a8254fe..8f163e78 100644
--- a/src/ui/package.json
+++ b/src/ui/package.json
@@ -24,6 +24,7 @@
"@types/cookie": "^1.0.0",
"@types/d3": "^7.4.3",
"@types/node": "^22.9.1",
+ "@types/three": "^0.171.0",
"@typescript-eslint/eslint-plugin": "^8.15.0",
"@typescript-eslint/parser": "^8.15.0",
"autoprefixer": "^10.4.20",
@@ -41,6 +42,7 @@
"svelte-check": "^4.0.9",
"svelte-eslint-parser": "^0.43.0",
"svelte-table": "^0.6.3",
+ "three": "^0.171.0",
"tslib": "^2.8.1",
"typescript": "^5.6.3",
"typescript-eslint": "^8.18.2",
diff --git a/src/ui/src/lib/3d/Devices.svelte b/src/ui/src/lib/3d/Devices.svelte
new file mode 100644
index 00000000..f6c375d1
--- /dev/null
+++ b/src/ui/src/lib/3d/Devices.svelte
@@ -0,0 +1,148 @@
+
\ No newline at end of file
diff --git a/src/ui/src/lib/3d/Nodes.svelte b/src/ui/src/lib/3d/Nodes.svelte
new file mode 100644
index 00000000..77a84374
--- /dev/null
+++ b/src/ui/src/lib/3d/Nodes.svelte
@@ -0,0 +1,120 @@
+
\ No newline at end of file
diff --git a/src/ui/src/lib/3d/Rooms.svelte b/src/ui/src/lib/3d/Rooms.svelte
new file mode 100644
index 00000000..d595501f
--- /dev/null
+++ b/src/ui/src/lib/3d/Rooms.svelte
@@ -0,0 +1,88 @@
+
\ No newline at end of file
diff --git a/src/ui/src/lib/images/3d.svg b/src/ui/src/lib/images/3d.svg
new file mode 100644
index 00000000..d187ab77
--- /dev/null
+++ b/src/ui/src/lib/images/3d.svg
@@ -0,0 +1,6 @@
+
+
\ No newline at end of file
diff --git a/src/ui/src/routes/+layout.svelte b/src/ui/src/routes/+layout.svelte
index 3a0fe504..9626e12b 100644
--- a/src/ui/src/routes/+layout.svelte
+++ b/src/ui/src/routes/+layout.svelte
@@ -12,6 +12,7 @@
import devices from '$lib/images/devices.svg';
import calibration from '$lib/images/calibration.svg';
import settings from '$lib/images/settings.svg';
+ import threeD from '$lib/images/3d.svg';
initializeStores();
@@ -25,6 +26,7 @@
{ href: '/devices', name: 'devices', icon: devices, alt: 'Devices' },
{ href: '/nodes', name: 'nodes', icon: nodes, alt: 'Nodes' },
{ href: '/calibration', name: 'calibration', icon: calibration, alt: 'Calibration' },
+ { href: '/3d', name: '3d', icon: threeD, alt: '3D View' },
];
diff --git a/src/ui/src/routes/3d/+page.svelte b/src/ui/src/routes/3d/+page.svelte
new file mode 100644
index 00000000..483dff2c
--- /dev/null
+++ b/src/ui/src/routes/3d/+page.svelte
@@ -0,0 +1,200 @@
+
+
+{#if groupPivot}
+