feat: add robot visualization via threlte
This commit is contained in:
parent
cb88e800f0
commit
fc82783845
15 changed files with 1450 additions and 43 deletions
190
client/package-lock.json
generated
190
client/package-lock.json
generated
|
@ -9,13 +9,15 @@
|
||||||
"version": "0.0.0",
|
"version": "0.0.0",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@fontsource/roboto": "^5.0.8",
|
"@fontsource/roboto": "^5.0.8",
|
||||||
|
"@threlte/core": "^7.1.0",
|
||||||
|
"@threlte/extras": "^8.8.0",
|
||||||
"howler": "^2.2.4",
|
"howler": "^2.2.4",
|
||||||
"material-icons": "^1.13.12",
|
"material-icons": "^1.13.12",
|
||||||
"material-symbols": "^0.15.0",
|
"material-symbols": "^0.15.0",
|
||||||
"overlayscrollbars-svelte": "^0.5.3",
|
"overlayscrollbars-svelte": "^0.5.3",
|
||||||
"socket.io-client": "^4.7.4",
|
"socket.io-client": "^4.7.4",
|
||||||
"svelte-french-toast": "^1.2.0",
|
"svelte-french-toast": "^1.2.0",
|
||||||
"svrollbar": "^0.12.0"
|
"three": "^0.161.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@svelte-plugins/tooltips": "^3.0.0",
|
"@svelte-plugins/tooltips": "^3.0.0",
|
||||||
|
@ -24,6 +26,7 @@
|
||||||
"@tauri-apps/cli": "^1.5.10",
|
"@tauri-apps/cli": "^1.5.10",
|
||||||
"@tsconfig/svelte": "^5.0.2",
|
"@tsconfig/svelte": "^5.0.2",
|
||||||
"@types/howler": "^2.2.11",
|
"@types/howler": "^2.2.11",
|
||||||
|
"@types/three": "^0.161.2",
|
||||||
"autoprefixer": "^10.4.17",
|
"autoprefixer": "^10.4.17",
|
||||||
"postcss": "^8.4.35",
|
"postcss": "^8.4.35",
|
||||||
"svelte": "^4.2.11",
|
"svelte": "^4.2.11",
|
||||||
|
@ -995,6 +998,37 @@
|
||||||
"node": ">= 10"
|
"node": ">= 10"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/@threlte/core": {
|
||||||
|
"version": "7.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@threlte/core/-/core-7.1.0.tgz",
|
||||||
|
"integrity": "sha512-Qshrrt1Bqu8B0rWuNtFqGJpbmxrFUBNYTHOJZ29Tiqy2kpmwYZfzVSPRoGUfJTqUtpfxGCrDU3S2etWnB0KsUA==",
|
||||||
|
"dependencies": {
|
||||||
|
"mitt": "^3.0.1"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"svelte": ">=4",
|
||||||
|
"three": ">=0.133"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@threlte/extras": {
|
||||||
|
"version": "8.8.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@threlte/extras/-/extras-8.8.0.tgz",
|
||||||
|
"integrity": "sha512-NNGywihQlPGbDoWnr0ZHV59Gkg8nKM4kzdxPY0CVZ93pSxXpGdoua0mQBTaQbJ6w3Qeiz867va+4SQXeVRHs8w==",
|
||||||
|
"dependencies": {
|
||||||
|
"three-mesh-bvh": "^0.7.1",
|
||||||
|
"three-perf": "^1.0.10",
|
||||||
|
"troika-three-text": "^0.49.0"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"svelte": ">=4",
|
||||||
|
"three": ">=0.133"
|
||||||
|
},
|
||||||
|
"peerDependenciesMeta": {
|
||||||
|
"three-mesh-bvh": {
|
||||||
|
"optional": true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/@tsconfig/svelte": {
|
"node_modules/@tsconfig/svelte": {
|
||||||
"version": "5.0.2",
|
"version": "5.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/@tsconfig/svelte/-/svelte-5.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/@tsconfig/svelte/-/svelte-5.0.2.tgz",
|
||||||
|
@ -1025,6 +1059,30 @@
|
||||||
"integrity": "sha512-Sk/uYFOBAB7mb74XcpizmH0KOR2Pv3D2Hmrh1Dmy5BmK3MpdSa5kqZcg6EKBdklU0bFXX9gCfzvpnyUehrPIuA==",
|
"integrity": "sha512-Sk/uYFOBAB7mb74XcpizmH0KOR2Pv3D2Hmrh1Dmy5BmK3MpdSa5kqZcg6EKBdklU0bFXX9gCfzvpnyUehrPIuA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"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.161.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/three/-/three-0.161.2.tgz",
|
||||||
|
"integrity": "sha512-DazpZ+cIfBzbW/p0zm6G8CS03HBMd748A3R1ZOXHpqaXZLv2I5zNgQUrRG//UfJ6zYFp2cUoCQaOLaz8ubH07w==",
|
||||||
|
"dev": true,
|
||||||
|
"dependencies": {
|
||||||
|
"@types/stats.js": "*",
|
||||||
|
"@types/webxr": "*",
|
||||||
|
"fflate": "~0.6.10",
|
||||||
|
"meshoptimizer": "~0.18.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/@types/webxr": {
|
||||||
|
"version": "0.5.14",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/webxr/-/webxr-0.5.14.tgz",
|
||||||
|
"integrity": "sha512-UEMMm/Xn3DtEa+gpzUrOcDj+SJS1tk5YodjwOxcqStNhCfPcwgyC5Srg2ToVKyg2Fhq16Ffpb0UWUQHqoT9AMA==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"node_modules/acorn": {
|
"node_modules/acorn": {
|
||||||
"version": "8.11.3",
|
"version": "8.11.3",
|
||||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz",
|
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz",
|
||||||
|
@ -1144,6 +1202,14 @@
|
||||||
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
|
"integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/bidi-js": {
|
||||||
|
"version": "1.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/bidi-js/-/bidi-js-1.0.3.tgz",
|
||||||
|
"integrity": "sha512-RKshQI1R3YQ+n9YJz2QQ147P66ELpa1FQEg20Dk8oW9t2KgLbpDLLp9aGZ7y8WHSshDknG0bknqGw5/tyCs5tw==",
|
||||||
|
"dependencies": {
|
||||||
|
"require-from-string": "^2.0.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/binary-extensions": {
|
"node_modules/binary-extensions": {
|
||||||
"version": "2.2.0",
|
"version": "2.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.2.0.tgz",
|
||||||
|
@ -1563,6 +1629,12 @@
|
||||||
"reusify": "^1.0.4"
|
"reusify": "^1.0.4"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/fflate": {
|
||||||
|
"version": "0.6.10",
|
||||||
|
"resolved": "https://registry.npmjs.org/fflate/-/fflate-0.6.10.tgz",
|
||||||
|
"integrity": "sha512-IQrh3lEPM93wVCEczc9SaAOvkmcoQn/G8Bo1e8ZPlY3X3bnAxWaBdvTdvM1hP62iZp0BXWDy4vTAy4fF0+Dlpg==",
|
||||||
|
"dev": true
|
||||||
|
},
|
||||||
"node_modules/fill-range": {
|
"node_modules/fill-range": {
|
||||||
"version": "7.0.1",
|
"version": "7.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz",
|
||||||
|
@ -1922,6 +1994,12 @@
|
||||||
"node": ">= 8"
|
"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": {
|
"node_modules/micromatch": {
|
||||||
"version": "4.0.5",
|
"version": "4.0.5",
|
||||||
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz",
|
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz",
|
||||||
|
@ -1974,6 +2052,11 @@
|
||||||
"node": ">=16 || 14 >=14.17"
|
"node": ">=16 || 14 >=14.17"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/mitt": {
|
||||||
|
"version": "3.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.1.tgz",
|
||||||
|
"integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw=="
|
||||||
|
},
|
||||||
"node_modules/mkdirp": {
|
"node_modules/mkdirp": {
|
||||||
"version": "0.5.6",
|
"version": "0.5.6",
|
||||||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz",
|
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.6.tgz",
|
||||||
|
@ -2393,6 +2476,14 @@
|
||||||
"node": ">=8.10.0"
|
"node": ">=8.10.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/require-from-string": {
|
||||||
|
"version": "2.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz",
|
||||||
|
"integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/resolve": {
|
"node_modules/resolve": {
|
||||||
"version": "1.22.8",
|
"version": "1.22.8",
|
||||||
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz",
|
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz",
|
||||||
|
@ -2955,11 +3046,6 @@
|
||||||
"svelte": "^3.2.1 || ^4.0.0-next.1"
|
"svelte": "^3.2.1 || ^4.0.0-next.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/svrollbar": {
|
|
||||||
"version": "0.12.0",
|
|
||||||
"resolved": "https://registry.npmjs.org/svrollbar/-/svrollbar-0.12.0.tgz",
|
|
||||||
"integrity": "sha512-okH0sz8bGtw+tgOfN1mpEtbveifxROcE3mbUMBJ1RQz8Q+1rVr+nVG7EAJ9b0G80cGDu7dskjAWuzj3iru0k5g=="
|
|
||||||
},
|
|
||||||
"node_modules/tailwindcss": {
|
"node_modules/tailwindcss": {
|
||||||
"version": "3.4.1",
|
"version": "3.4.1",
|
||||||
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.1.tgz",
|
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.1.tgz",
|
||||||
|
@ -3030,6 +3116,58 @@
|
||||||
"node": ">=0.8"
|
"node": ">=0.8"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/three": {
|
||||||
|
"version": "0.161.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/three/-/three-0.161.0.tgz",
|
||||||
|
"integrity": "sha512-LC28VFtjbOyEu5b93K0bNRLw1rQlMJ85lilKsYj6dgTu+7i17W+JCCEbvrpmNHF1F3NAUqDSWq50UD7w9H2xQw=="
|
||||||
|
},
|
||||||
|
"node_modules/three-mesh-bvh": {
|
||||||
|
"version": "0.7.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/three-mesh-bvh/-/three-mesh-bvh-0.7.3.tgz",
|
||||||
|
"integrity": "sha512-3W6KjzmupjfE89GuHPT31kxKWZ4YGZPEZJNysJpiOZfQRsBQQgmK7v/VJPpjG6syhAvTnY+5Fr77EvIkTLpGSw==",
|
||||||
|
"peerDependencies": {
|
||||||
|
"three": ">= 0.151.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/three-perf": {
|
||||||
|
"version": "1.0.10",
|
||||||
|
"resolved": "https://registry.npmjs.org/three-perf/-/three-perf-1.0.10.tgz",
|
||||||
|
"integrity": "sha512-lCur/i8U6m0ysWYhQ1yFGWOZB0QA2oVsDsfynYd65HhXxLxJfiAt8OsXmpv9PnTLacfaZclBcZHUOB9QKk3eaw==",
|
||||||
|
"dependencies": {
|
||||||
|
"troika-three-text": "^0.47.2",
|
||||||
|
"tweakpane": "^3.1.10"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"three": ">=0.151"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/three-perf/node_modules/troika-three-text": {
|
||||||
|
"version": "0.47.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/troika-three-text/-/troika-three-text-0.47.2.tgz",
|
||||||
|
"integrity": "sha512-qylT0F+U7xGs+/PEf3ujBdJMYWbn0Qci0kLqI5BJG2kW1wdg4T1XSxneypnF05DxFqJhEzuaOR9S2SjiyknMng==",
|
||||||
|
"dependencies": {
|
||||||
|
"bidi-js": "^1.0.2",
|
||||||
|
"troika-three-utils": "^0.47.2",
|
||||||
|
"troika-worker-utils": "^0.47.2",
|
||||||
|
"webgl-sdf-generator": "1.1.1"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"three": ">=0.125.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/three-perf/node_modules/troika-three-utils": {
|
||||||
|
"version": "0.47.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/troika-three-utils/-/troika-three-utils-0.47.2.tgz",
|
||||||
|
"integrity": "sha512-/28plhCxfKtH7MSxEGx8e3b/OXU5A0xlwl+Sbdp0H8FXUHKZDoksduEKmjQayXYtxAyuUiCRunYIv/8Vi7aiyg==",
|
||||||
|
"peerDependencies": {
|
||||||
|
"three": ">=0.125.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/three-perf/node_modules/troika-worker-utils": {
|
||||||
|
"version": "0.47.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/troika-worker-utils/-/troika-worker-utils-0.47.2.tgz",
|
||||||
|
"integrity": "sha512-mzss4MeyzUkYBppn4x5cdAqrhBHFEuVmMMgLMTyFV23x6GvQMyo+/R5E5Lsbrt7WSt5RfvewjcwD1DChRTA9lA=="
|
||||||
|
},
|
||||||
"node_modules/tiny-glob": {
|
"node_modules/tiny-glob": {
|
||||||
"version": "0.2.9",
|
"version": "0.2.9",
|
||||||
"resolved": "https://registry.npmjs.org/tiny-glob/-/tiny-glob-0.2.9.tgz",
|
"resolved": "https://registry.npmjs.org/tiny-glob/-/tiny-glob-0.2.9.tgz",
|
||||||
|
@ -3063,6 +3201,33 @@
|
||||||
"node": ">=6"
|
"node": ">=6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/troika-three-text": {
|
||||||
|
"version": "0.49.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/troika-three-text/-/troika-three-text-0.49.0.tgz",
|
||||||
|
"integrity": "sha512-sn9BNC6eIX8OO3iAkPwjecJ7Pn21Ve8P1UNFMNeQzXx759rrqS4i4pSZs7FLMYdWyCKVXBFGimBySFwRKLjq/Q==",
|
||||||
|
"dependencies": {
|
||||||
|
"bidi-js": "^1.0.2",
|
||||||
|
"troika-three-utils": "^0.49.0",
|
||||||
|
"troika-worker-utils": "^0.49.0",
|
||||||
|
"webgl-sdf-generator": "1.1.1"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"three": ">=0.125.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/troika-three-utils": {
|
||||||
|
"version": "0.49.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/troika-three-utils/-/troika-three-utils-0.49.0.tgz",
|
||||||
|
"integrity": "sha512-umitFL4cT+Fm/uONmaQEq4oZlyRHWwVClaS6ZrdcueRvwc2w+cpNQ47LlJKJswpqtMFWbEhOLy0TekmcPZOdYA==",
|
||||||
|
"peerDependencies": {
|
||||||
|
"three": ">=0.125.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/troika-worker-utils": {
|
||||||
|
"version": "0.49.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/troika-worker-utils/-/troika-worker-utils-0.49.0.tgz",
|
||||||
|
"integrity": "sha512-1xZHoJrG0HFfCvT/iyN41DvI/nRykiBtHqFkGaGgJwq5iXfIZFBiPPEHFpPpgyKM3Oo5ITHXP5wM2TNQszYdVg=="
|
||||||
|
},
|
||||||
"node_modules/ts-interface-checker": {
|
"node_modules/ts-interface-checker": {
|
||||||
"version": "0.1.13",
|
"version": "0.1.13",
|
||||||
"resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz",
|
"resolved": "https://registry.npmjs.org/ts-interface-checker/-/ts-interface-checker-0.1.13.tgz",
|
||||||
|
@ -3075,6 +3240,14 @@
|
||||||
"integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==",
|
"integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/tweakpane": {
|
||||||
|
"version": "3.1.10",
|
||||||
|
"resolved": "https://registry.npmjs.org/tweakpane/-/tweakpane-3.1.10.tgz",
|
||||||
|
"integrity": "sha512-rqwnl/pUa7+inhI2E9ayGTqqP0EPOOn/wVvSWjZsRbZUItzNShny7pzwL3hVlaN4m9t/aZhsP0aFQ9U5VVR2VQ==",
|
||||||
|
"funding": {
|
||||||
|
"url": "https://github.com/sponsors/cocopon"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/typescript": {
|
"node_modules/typescript": {
|
||||||
"version": "5.3.3",
|
"version": "5.3.3",
|
||||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz",
|
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.3.3.tgz",
|
||||||
|
@ -3193,6 +3366,11 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/webgl-sdf-generator": {
|
||||||
|
"version": "1.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/webgl-sdf-generator/-/webgl-sdf-generator-1.1.1.tgz",
|
||||||
|
"integrity": "sha512-9Z0JcMTFxeE+b2x1LJTdnaT8rT8aEp7MVxkNwoycNmJWwPdzoXzMh0BjJSh/AEFP+KPYZUli814h8bJZFIZ2jA=="
|
||||||
|
},
|
||||||
"node_modules/which": {
|
"node_modules/which": {
|
||||||
"version": "2.0.2",
|
"version": "2.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
"@tauri-apps/cli": "^1.5.10",
|
"@tauri-apps/cli": "^1.5.10",
|
||||||
"@tsconfig/svelte": "^5.0.2",
|
"@tsconfig/svelte": "^5.0.2",
|
||||||
"@types/howler": "^2.2.11",
|
"@types/howler": "^2.2.11",
|
||||||
|
"@types/three": "^0.161.2",
|
||||||
"autoprefixer": "^10.4.17",
|
"autoprefixer": "^10.4.17",
|
||||||
"postcss": "^8.4.35",
|
"postcss": "^8.4.35",
|
||||||
"svelte": "^4.2.11",
|
"svelte": "^4.2.11",
|
||||||
|
@ -28,12 +29,14 @@
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@fontsource/roboto": "^5.0.8",
|
"@fontsource/roboto": "^5.0.8",
|
||||||
|
"@threlte/core": "^7.1.0",
|
||||||
|
"@threlte/extras": "^8.8.0",
|
||||||
"howler": "^2.2.4",
|
"howler": "^2.2.4",
|
||||||
"material-icons": "^1.13.12",
|
"material-icons": "^1.13.12",
|
||||||
"material-symbols": "^0.15.0",
|
"material-symbols": "^0.15.0",
|
||||||
"overlayscrollbars-svelte": "^0.5.3",
|
"overlayscrollbars-svelte": "^0.5.3",
|
||||||
"socket.io-client": "^4.7.4",
|
"socket.io-client": "^4.7.4",
|
||||||
"svelte-french-toast": "^1.2.0",
|
"svelte-french-toast": "^1.2.0",
|
||||||
"svrollbar": "^0.12.0"
|
"three": "^0.161.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
BIN
client/public/static/app-icons/dev-tools.png
Normal file
BIN
client/public/static/app-icons/dev-tools.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 14 KiB |
|
@ -1,50 +1,51 @@
|
||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
import "@fontsource/roboto/latin.css";
|
import '@fontsource/roboto/latin.css'
|
||||||
import "material-icons/iconfont/material-icons.css";
|
import 'material-icons/iconfont/material-icons.css'
|
||||||
import Dashboard from "./lib/Dashboard/Dashboard.svelte";
|
import Dashboard from './lib/Dashboard/Dashboard.svelte'
|
||||||
import "material-symbols";
|
import 'material-symbols'
|
||||||
import AppBar from "./lib/Apps/AppBar.svelte";
|
import AppBar from './lib/Apps/AppBar.svelte'
|
||||||
import { appList } from "./lib/Apps/appList";
|
import { appList } from './lib/Apps/appList'
|
||||||
import { initializeTelemetry } from "./lib/utils/initializeTelemetry";
|
import { initializeTelemetry } from './lib/utils/initializeTelemetry'
|
||||||
import { onMount } from "svelte";
|
import { onMount } from 'svelte'
|
||||||
import { Toaster } from "svelte-french-toast";
|
import { Toaster } from 'svelte-french-toast'
|
||||||
import { initializationSequence } from "./lib/Sequences/sequences";
|
import { initializationSequence } from './lib/Sequences/sequences'
|
||||||
import Loading from "./lib/Loading/Loading.svelte";
|
import Loading from './lib/Loading/Loading.svelte'
|
||||||
import { settingsStore } from "./lib/stores/settingsStore";
|
import { settingsStore } from './lib/stores/settingsStore'
|
||||||
import getSettings from "./lib/utils/getSettings";
|
import getSettings from './lib/utils/getSettings'
|
||||||
|
import { Canvas } from '@threlte/core'
|
||||||
|
|
||||||
let activeApp: App = "camera";
|
let activeApp: App = 'camera'
|
||||||
let topics: TelemetryTopics = {
|
let topics: TelemetryTopics = {
|
||||||
doubles: [
|
doubles: [
|
||||||
"orientation",
|
'orientation',
|
||||||
"chassis-x-speed",
|
'chassis-x-speed',
|
||||||
"chassis-y-speed",
|
'chassis-y-speed',
|
||||||
"accx",
|
'accx',
|
||||||
"accy",
|
'accy',
|
||||||
"accz",
|
'accz',
|
||||||
"jerk-x",
|
'jerk-x',
|
||||||
"jerk-y",
|
'jerk-y',
|
||||||
"voltage",
|
'voltage',
|
||||||
],
|
],
|
||||||
strings: ["acc-profile", "gear"],
|
strings: ['acc-profile', 'gear'],
|
||||||
booleans: ["ebrake", "reorient", "gpws"],
|
booleans: ['ebrake', 'reorient', 'gpws'],
|
||||||
};
|
}
|
||||||
|
|
||||||
let loading = $settingsStore.fastStartup ? false : true;
|
let loading = $settingsStore.fastStartup ? false : true
|
||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
let savedSettings = getSettings();
|
let savedSettings = getSettings()
|
||||||
if (savedSettings !== false) {
|
if (savedSettings !== false) {
|
||||||
settingsStore.set(savedSettings);
|
settingsStore.set(savedSettings)
|
||||||
}
|
}
|
||||||
window.ResizeObserver = ResizeObserver;
|
window.ResizeObserver = ResizeObserver
|
||||||
// disabled while migrating away from python
|
// disabled while migrating away from python
|
||||||
// initializeTelemetry(topics, 200);
|
initializeTelemetry(topics, 200)
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
loading = false;
|
loading = false
|
||||||
initializationSequence();
|
initializationSequence()
|
||||||
}, 3000);
|
}, 3000)
|
||||||
});
|
})
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<main
|
<main
|
||||||
|
@ -76,7 +77,7 @@
|
||||||
|
|
||||||
<style lang="postcss">
|
<style lang="postcss">
|
||||||
main {
|
main {
|
||||||
font-family: "Roboto", sans-serif;
|
font-family: 'Roboto', sans-serif;
|
||||||
}
|
}
|
||||||
|
|
||||||
.infotainment-container {
|
.infotainment-container {
|
||||||
|
|
11
client/src/assets/models/license.txt
Normal file
11
client/src/assets/models/license.txt
Normal file
|
@ -0,0 +1,11 @@
|
||||||
|
Model Information:
|
||||||
|
* title: Low Poly F/A-18 Hornet
|
||||||
|
* source: https://sketchfab.com/3d-models/low-poly-fa-18-hornet-9b48c88e91ba40fc8f518b616f44f714
|
||||||
|
* author: cs09736 (https://sketchfab.com/cs09736)
|
||||||
|
|
||||||
|
Model License:
|
||||||
|
* license type: CC-BY-SA-4.0 (http://creativecommons.org/licenses/by-sa/4.0/)
|
||||||
|
* requirements: Author must be credited. Modified versions must have the same license. Commercial use is allowed.
|
||||||
|
|
||||||
|
If you use this 3D model in your project be sure to copy paste this credit wherever you share it:
|
||||||
|
This work is based on "Low Poly F/A-18 Hornet" (https://sketchfab.com/3d-models/low-poly-fa-18-hornet-9b48c88e91ba40fc8f518b616f44f714) by cs09736 (https://sketchfab.com/cs09736) licensed under CC-BY-SA-4.0 (http://creativecommons.org/licenses/by-sa/4.0/)
|
BIN
client/src/assets/models/scene.bin
Normal file
BIN
client/src/assets/models/scene.bin
Normal file
Binary file not shown.
754
client/src/assets/models/scene.gltf
Normal file
754
client/src/assets/models/scene.gltf
Normal file
|
@ -0,0 +1,754 @@
|
||||||
|
{
|
||||||
|
"accessors": [
|
||||||
|
{
|
||||||
|
"bufferView": 2,
|
||||||
|
"componentType": 5126,
|
||||||
|
"count": 62,
|
||||||
|
"max": [
|
||||||
|
0.28601938486099243,
|
||||||
|
-0.03159094601869583,
|
||||||
|
1.3521472215652466
|
||||||
|
],
|
||||||
|
"min": [
|
||||||
|
-0.28601938486099243,
|
||||||
|
-0.3833470940589905,
|
||||||
|
-2.612701416015625
|
||||||
|
],
|
||||||
|
"type": "VEC3"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"bufferView": 2,
|
||||||
|
"byteOffset": 744,
|
||||||
|
"componentType": 5126,
|
||||||
|
"count": 62,
|
||||||
|
"max": [
|
||||||
|
0.9978463053703308,
|
||||||
|
0.9706209897994995,
|
||||||
|
1.0
|
||||||
|
],
|
||||||
|
"min": [
|
||||||
|
-0.9978463053703308,
|
||||||
|
-0.2406158298254013,
|
||||||
|
-1.0
|
||||||
|
],
|
||||||
|
"type": "VEC3"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"bufferView": 1,
|
||||||
|
"componentType": 5126,
|
||||||
|
"count": 62,
|
||||||
|
"max": [
|
||||||
|
0.7755247354507446,
|
||||||
|
1.0
|
||||||
|
],
|
||||||
|
"min": [
|
||||||
|
0.0,
|
||||||
|
0.0
|
||||||
|
],
|
||||||
|
"type": "VEC2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"bufferView": 0,
|
||||||
|
"componentType": 5125,
|
||||||
|
"count": 90,
|
||||||
|
"type": "SCALAR"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"bufferView": 2,
|
||||||
|
"byteOffset": 1488,
|
||||||
|
"componentType": 5126,
|
||||||
|
"count": 744,
|
||||||
|
"max": [
|
||||||
|
0.26639726758003235,
|
||||||
|
0.11264356225728989,
|
||||||
|
-2.2082409858703613
|
||||||
|
],
|
||||||
|
"min": [
|
||||||
|
-0.26639726758003235,
|
||||||
|
-0.13609451055526733,
|
||||||
|
-2.7548983097076416
|
||||||
|
],
|
||||||
|
"type": "VEC3"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"bufferView": 2,
|
||||||
|
"byteOffset": 10416,
|
||||||
|
"componentType": 5126,
|
||||||
|
"count": 744,
|
||||||
|
"max": [
|
||||||
|
0.9659259915351868,
|
||||||
|
0.9659258723258972,
|
||||||
|
0.15793786942958832
|
||||||
|
],
|
||||||
|
"min": [
|
||||||
|
-0.9659259915351868,
|
||||||
|
-0.9659259915351868,
|
||||||
|
-1.0
|
||||||
|
],
|
||||||
|
"type": "VEC3"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"bufferView": 1,
|
||||||
|
"byteOffset": 496,
|
||||||
|
"componentType": 5126,
|
||||||
|
"count": 744,
|
||||||
|
"max": [
|
||||||
|
0.48029109835624695,
|
||||||
|
0.4802909791469574
|
||||||
|
],
|
||||||
|
"min": [
|
||||||
|
0.01970890536904335,
|
||||||
|
0.019708896055817604
|
||||||
|
],
|
||||||
|
"type": "VEC2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"bufferView": 0,
|
||||||
|
"byteOffset": 360,
|
||||||
|
"componentType": 5125,
|
||||||
|
"count": 1356,
|
||||||
|
"type": "SCALAR"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"bufferView": 2,
|
||||||
|
"byteOffset": 19344,
|
||||||
|
"componentType": 5126,
|
||||||
|
"count": 6762,
|
||||||
|
"max": [
|
||||||
|
1.8555290699005127,
|
||||||
|
0.828994631767273,
|
||||||
|
2.448202133178711
|
||||||
|
],
|
||||||
|
"min": [
|
||||||
|
-1.8555290699005127,
|
||||||
|
-0.4696495532989502,
|
||||||
|
-2.894035577774048
|
||||||
|
],
|
||||||
|
"type": "VEC3"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"bufferView": 2,
|
||||||
|
"byteOffset": 100488,
|
||||||
|
"componentType": 5126,
|
||||||
|
"count": 6762,
|
||||||
|
"max": [
|
||||||
|
1.0,
|
||||||
|
0.9996607303619385,
|
||||||
|
1.0
|
||||||
|
],
|
||||||
|
"min": [
|
||||||
|
-1.0,
|
||||||
|
-1.0,
|
||||||
|
-1.0
|
||||||
|
],
|
||||||
|
"type": "VEC3"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"bufferView": 1,
|
||||||
|
"byteOffset": 6448,
|
||||||
|
"componentType": 5126,
|
||||||
|
"count": 6762,
|
||||||
|
"max": [
|
||||||
|
1.382123351097107,
|
||||||
|
1.0000001192092896
|
||||||
|
],
|
||||||
|
"min": [
|
||||||
|
0.0,
|
||||||
|
-0.3820711672306061
|
||||||
|
],
|
||||||
|
"type": "VEC2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"bufferView": 0,
|
||||||
|
"byteOffset": 5784,
|
||||||
|
"componentType": 5125,
|
||||||
|
"count": 10506,
|
||||||
|
"type": "SCALAR"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"bufferView": 2,
|
||||||
|
"byteOffset": 181632,
|
||||||
|
"componentType": 5126,
|
||||||
|
"count": 108,
|
||||||
|
"max": [
|
||||||
|
0.15389108657836914,
|
||||||
|
0.40167421102523804,
|
||||||
|
1.4429497718811035
|
||||||
|
],
|
||||||
|
"min": [
|
||||||
|
-0.15389108657836914,
|
||||||
|
0.1835811734199524,
|
||||||
|
0.3292185962200165
|
||||||
|
],
|
||||||
|
"type": "VEC3"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"bufferView": 2,
|
||||||
|
"byteOffset": 182928,
|
||||||
|
"componentType": 5126,
|
||||||
|
"count": 108,
|
||||||
|
"max": [
|
||||||
|
0.93450927734375,
|
||||||
|
0.9493585228919983,
|
||||||
|
0.32783323526382446
|
||||||
|
],
|
||||||
|
"min": [
|
||||||
|
-0.93450927734375,
|
||||||
|
0.34994035959243774,
|
||||||
|
-0.14981554448604584
|
||||||
|
],
|
||||||
|
"type": "VEC3"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"bufferView": 1,
|
||||||
|
"byteOffset": 60544,
|
||||||
|
"componentType": 5126,
|
||||||
|
"count": 108,
|
||||||
|
"max": [
|
||||||
|
0.75,
|
||||||
|
0.7012776732444763
|
||||||
|
],
|
||||||
|
"min": [
|
||||||
|
0.0,
|
||||||
|
0.0
|
||||||
|
],
|
||||||
|
"type": "VEC2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"bufferView": 0,
|
||||||
|
"byteOffset": 47808,
|
||||||
|
"componentType": 5125,
|
||||||
|
"count": 156,
|
||||||
|
"type": "SCALAR"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"bufferView": 2,
|
||||||
|
"byteOffset": 184224,
|
||||||
|
"componentType": 5126,
|
||||||
|
"count": 458,
|
||||||
|
"max": [
|
||||||
|
0.25538086891174316,
|
||||||
|
0.1017007827758789,
|
||||||
|
-2.4583163261413574
|
||||||
|
],
|
||||||
|
"min": [
|
||||||
|
-0.25538086891174316,
|
||||||
|
-0.1249837875366211,
|
||||||
|
-3.5668210983276367
|
||||||
|
],
|
||||||
|
"type": "VEC3"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"bufferView": 2,
|
||||||
|
"byteOffset": 189720,
|
||||||
|
"componentType": 5126,
|
||||||
|
"count": 458,
|
||||||
|
"max": [
|
||||||
|
0.9996814727783203,
|
||||||
|
0.9996814727783203,
|
||||||
|
0.6308417916297913
|
||||||
|
],
|
||||||
|
"min": [
|
||||||
|
-0.9996814727783203,
|
||||||
|
-0.9996814727783203,
|
||||||
|
-0.6931174397468567
|
||||||
|
],
|
||||||
|
"type": "VEC3"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"bufferView": 1,
|
||||||
|
"byteOffset": 61408,
|
||||||
|
"componentType": 5126,
|
||||||
|
"count": 458,
|
||||||
|
"max": [
|
||||||
|
0.9998925924301147,
|
||||||
|
0.6052115559577942
|
||||||
|
],
|
||||||
|
"min": [
|
||||||
|
0.0001073777093552053,
|
||||||
|
0.0001073777093552053
|
||||||
|
],
|
||||||
|
"type": "VEC2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"bufferView": 0,
|
||||||
|
"byteOffset": 48432,
|
||||||
|
"componentType": 5125,
|
||||||
|
"count": 1896,
|
||||||
|
"type": "SCALAR"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"bufferView": 2,
|
||||||
|
"byteOffset": 195216,
|
||||||
|
"componentType": 5126,
|
||||||
|
"count": 1993,
|
||||||
|
"max": [
|
||||||
|
0.457694411277771,
|
||||||
|
0.019436508417129517,
|
||||||
|
0.9355756044387817
|
||||||
|
],
|
||||||
|
"min": [
|
||||||
|
-0.457694411277771,
|
||||||
|
-0.5843615531921387,
|
||||||
|
-1.0792063474655151
|
||||||
|
],
|
||||||
|
"type": "VEC3"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"bufferView": 2,
|
||||||
|
"byteOffset": 219132,
|
||||||
|
"componentType": 5126,
|
||||||
|
"count": 1993,
|
||||||
|
"max": [
|
||||||
|
1.0,
|
||||||
|
1.0,
|
||||||
|
1.0
|
||||||
|
],
|
||||||
|
"min": [
|
||||||
|
-1.0,
|
||||||
|
-1.0,
|
||||||
|
-1.0
|
||||||
|
],
|
||||||
|
"type": "VEC3"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"bufferView": 1,
|
||||||
|
"byteOffset": 65072,
|
||||||
|
"componentType": 5126,
|
||||||
|
"count": 1993,
|
||||||
|
"max": [
|
||||||
|
1.0,
|
||||||
|
1.0
|
||||||
|
],
|
||||||
|
"min": [
|
||||||
|
0.0,
|
||||||
|
0.0
|
||||||
|
],
|
||||||
|
"type": "VEC2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"bufferView": 0,
|
||||||
|
"byteOffset": 56016,
|
||||||
|
"componentType": 5125,
|
||||||
|
"count": 5028,
|
||||||
|
"type": "SCALAR"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"bufferView": 2,
|
||||||
|
"byteOffset": 243048,
|
||||||
|
"componentType": 5126,
|
||||||
|
"count": 832,
|
||||||
|
"max": [
|
||||||
|
0.457694411277771,
|
||||||
|
-0.341027170419693,
|
||||||
|
0.7706074714660645
|
||||||
|
],
|
||||||
|
"min": [
|
||||||
|
-0.457694411277771,
|
||||||
|
-0.6231322884559631,
|
||||||
|
-1.1222631931304932
|
||||||
|
],
|
||||||
|
"type": "VEC3"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"bufferView": 2,
|
||||||
|
"byteOffset": 253032,
|
||||||
|
"componentType": 5126,
|
||||||
|
"count": 832,
|
||||||
|
"max": [
|
||||||
|
1.0,
|
||||||
|
0.9659259915351868,
|
||||||
|
0.9659262299537659
|
||||||
|
],
|
||||||
|
"min": [
|
||||||
|
-1.0,
|
||||||
|
-0.965925931930542,
|
||||||
|
-0.9659261107444763
|
||||||
|
],
|
||||||
|
"type": "VEC3"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"bufferView": 1,
|
||||||
|
"byteOffset": 81016,
|
||||||
|
"componentType": 5126,
|
||||||
|
"count": 832,
|
||||||
|
"max": [
|
||||||
|
1.0,
|
||||||
|
1.0
|
||||||
|
],
|
||||||
|
"min": [
|
||||||
|
7.450580596923828e-08,
|
||||||
|
0.5
|
||||||
|
],
|
||||||
|
"type": "VEC2"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"bufferView": 0,
|
||||||
|
"byteOffset": 76128,
|
||||||
|
"componentType": 5125,
|
||||||
|
"count": 1440,
|
||||||
|
"type": "SCALAR"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"asset": {
|
||||||
|
"extras": {
|
||||||
|
"author": "cs09736 (https://sketchfab.com/cs09736)",
|
||||||
|
"license": "CC-BY-SA-4.0 (http://creativecommons.org/licenses/by-sa/4.0/)",
|
||||||
|
"source": "https://sketchfab.com/3d-models/low-poly-fa-18-hornet-9b48c88e91ba40fc8f518b616f44f714",
|
||||||
|
"title": "Low Poly F/A-18 Hornet"
|
||||||
|
},
|
||||||
|
"generator": "Sketchfab-12.68.0",
|
||||||
|
"version": "2.0"
|
||||||
|
},
|
||||||
|
"bufferViews": [
|
||||||
|
{
|
||||||
|
"buffer": 0,
|
||||||
|
"byteLength": 81888,
|
||||||
|
"name": "floatBufferViews",
|
||||||
|
"target": 34963
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"buffer": 0,
|
||||||
|
"byteLength": 87672,
|
||||||
|
"byteOffset": 81888,
|
||||||
|
"byteStride": 8,
|
||||||
|
"name": "floatBufferViews",
|
||||||
|
"target": 34962
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"buffer": 0,
|
||||||
|
"byteLength": 263016,
|
||||||
|
"byteOffset": 169560,
|
||||||
|
"byteStride": 12,
|
||||||
|
"name": "floatBufferViews",
|
||||||
|
"target": 34962
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"buffers": [
|
||||||
|
{
|
||||||
|
"byteLength": 432576,
|
||||||
|
"uri": "scene.bin"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"materials": [
|
||||||
|
{
|
||||||
|
"doubleSided": true,
|
||||||
|
"name": "clay",
|
||||||
|
"pbrMetallicRoughness": {
|
||||||
|
"baseColorFactor": [
|
||||||
|
0.8,
|
||||||
|
0.8,
|
||||||
|
0.8,
|
||||||
|
1.0
|
||||||
|
],
|
||||||
|
"metallicFactor": 0.0,
|
||||||
|
"roughnessFactor": 0.4
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"doubleSided": true,
|
||||||
|
"emissiveFactor": [
|
||||||
|
0.214041,
|
||||||
|
0.000464395,
|
||||||
|
0.0
|
||||||
|
],
|
||||||
|
"name": "engine_inside",
|
||||||
|
"pbrMetallicRoughness": {
|
||||||
|
"baseColorFactor": [
|
||||||
|
0.8,
|
||||||
|
0.212337,
|
||||||
|
0.0981736,
|
||||||
|
1.0
|
||||||
|
],
|
||||||
|
"roughnessFactor": 0.742424
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"doubleSided": true,
|
||||||
|
"name": "body_paint",
|
||||||
|
"pbrMetallicRoughness": {
|
||||||
|
"baseColorFactor": [
|
||||||
|
0.465996,
|
||||||
|
0.488985,
|
||||||
|
0.522522,
|
||||||
|
1.0
|
||||||
|
],
|
||||||
|
"metallicFactor": 0.1,
|
||||||
|
"roughnessFactor": 0.5
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"doubleSided": true,
|
||||||
|
"name": "glass",
|
||||||
|
"pbrMetallicRoughness": {
|
||||||
|
"baseColorFactor": [
|
||||||
|
0.360226,
|
||||||
|
0.603827,
|
||||||
|
0.476213,
|
||||||
|
1.0
|
||||||
|
],
|
||||||
|
"metallicFactor": 0.7,
|
||||||
|
"roughnessFactor": 0.0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"doubleSided": true,
|
||||||
|
"emissiveFactor": [
|
||||||
|
1.0,
|
||||||
|
0.0571504,
|
||||||
|
0.00509488
|
||||||
|
],
|
||||||
|
"name": "after_burner",
|
||||||
|
"pbrMetallicRoughness": {
|
||||||
|
"baseColorFactor": [
|
||||||
|
0.4407909999999996,
|
||||||
|
0.17297200000000015,
|
||||||
|
0.08980889999999998,
|
||||||
|
1.0
|
||||||
|
],
|
||||||
|
"metallicFactor": 0.0,
|
||||||
|
"roughnessFactor": 0.5
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"doubleSided": true,
|
||||||
|
"name": "strut",
|
||||||
|
"pbrMetallicRoughness": {
|
||||||
|
"baseColorFactor": [
|
||||||
|
0.616618,
|
||||||
|
0.6473,
|
||||||
|
0.692071,
|
||||||
|
1.0
|
||||||
|
],
|
||||||
|
"metallicFactor": 0.1,
|
||||||
|
"roughnessFactor": 0.5
|
||||||
|
}
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"doubleSided": true,
|
||||||
|
"name": "tyre",
|
||||||
|
"pbrMetallicRoughness": {
|
||||||
|
"baseColorFactor": [
|
||||||
|
0.00424211,
|
||||||
|
0.00424211,
|
||||||
|
0.00424211,
|
||||||
|
1.0
|
||||||
|
],
|
||||||
|
"metallicFactor": 0.0,
|
||||||
|
"roughnessFactor": 0.6
|
||||||
|
}
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"meshes": [
|
||||||
|
{
|
||||||
|
"name": "Object_0",
|
||||||
|
"primitives": [
|
||||||
|
{
|
||||||
|
"attributes": {
|
||||||
|
"NORMAL": 1,
|
||||||
|
"POSITION": 0,
|
||||||
|
"TEXCOORD_0": 2
|
||||||
|
},
|
||||||
|
"indices": 3,
|
||||||
|
"material": 0,
|
||||||
|
"mode": 4
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Object_1",
|
||||||
|
"primitives": [
|
||||||
|
{
|
||||||
|
"attributes": {
|
||||||
|
"NORMAL": 5,
|
||||||
|
"POSITION": 4,
|
||||||
|
"TEXCOORD_0": 6
|
||||||
|
},
|
||||||
|
"indices": 7,
|
||||||
|
"material": 1,
|
||||||
|
"mode": 4
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Object_2",
|
||||||
|
"primitives": [
|
||||||
|
{
|
||||||
|
"attributes": {
|
||||||
|
"NORMAL": 9,
|
||||||
|
"POSITION": 8,
|
||||||
|
"TEXCOORD_0": 10
|
||||||
|
},
|
||||||
|
"indices": 11,
|
||||||
|
"material": 2,
|
||||||
|
"mode": 4
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Object_3",
|
||||||
|
"primitives": [
|
||||||
|
{
|
||||||
|
"attributes": {
|
||||||
|
"NORMAL": 13,
|
||||||
|
"POSITION": 12,
|
||||||
|
"TEXCOORD_0": 14
|
||||||
|
},
|
||||||
|
"indices": 15,
|
||||||
|
"material": 3,
|
||||||
|
"mode": 4
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Object_4",
|
||||||
|
"primitives": [
|
||||||
|
{
|
||||||
|
"attributes": {
|
||||||
|
"NORMAL": 17,
|
||||||
|
"POSITION": 16,
|
||||||
|
"TEXCOORD_0": 18
|
||||||
|
},
|
||||||
|
"indices": 19,
|
||||||
|
"material": 4,
|
||||||
|
"mode": 4
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Object_5",
|
||||||
|
"primitives": [
|
||||||
|
{
|
||||||
|
"attributes": {
|
||||||
|
"NORMAL": 21,
|
||||||
|
"POSITION": 20,
|
||||||
|
"TEXCOORD_0": 22
|
||||||
|
},
|
||||||
|
"indices": 23,
|
||||||
|
"material": 5,
|
||||||
|
"mode": 4
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Object_6",
|
||||||
|
"primitives": [
|
||||||
|
{
|
||||||
|
"attributes": {
|
||||||
|
"NORMAL": 25,
|
||||||
|
"POSITION": 24,
|
||||||
|
"TEXCOORD_0": 26
|
||||||
|
},
|
||||||
|
"indices": 27,
|
||||||
|
"material": 6,
|
||||||
|
"mode": 4
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"nodes": [
|
||||||
|
{
|
||||||
|
"children": [
|
||||||
|
1
|
||||||
|
],
|
||||||
|
"matrix": [
|
||||||
|
2.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
4.440892098500626e-16,
|
||||||
|
-2.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
2.0,
|
||||||
|
4.440892098500626e-16,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
1.0
|
||||||
|
],
|
||||||
|
"name": "Sketchfab_model"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"children": [
|
||||||
|
2
|
||||||
|
],
|
||||||
|
"name": "root"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"children": [
|
||||||
|
3
|
||||||
|
],
|
||||||
|
"matrix": [
|
||||||
|
1.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
2.220446049250313e-16,
|
||||||
|
1.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
-1.0,
|
||||||
|
2.220446049250313e-16,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
0.0,
|
||||||
|
1.0
|
||||||
|
],
|
||||||
|
"name": "GLTF_SceneRootNode"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"children": [
|
||||||
|
4,
|
||||||
|
5,
|
||||||
|
6,
|
||||||
|
7,
|
||||||
|
8,
|
||||||
|
9,
|
||||||
|
10
|
||||||
|
],
|
||||||
|
"name": "aircraft_0"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"mesh": 0,
|
||||||
|
"name": "Object_4"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"mesh": 1,
|
||||||
|
"name": "Object_5"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"mesh": 2,
|
||||||
|
"name": "Object_6"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"mesh": 3,
|
||||||
|
"name": "Object_7"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"mesh": 4,
|
||||||
|
"name": "Object_8"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"mesh": 5,
|
||||||
|
"name": "Object_9"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"mesh": 6,
|
||||||
|
"name": "Object_10"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"scene": 0,
|
||||||
|
"scenes": [
|
||||||
|
{
|
||||||
|
"name": "Sketchfab_Scene",
|
||||||
|
"nodes": [
|
||||||
|
0
|
||||||
|
]
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
26
client/src/lib/Apps/DevTools/DevTools.svelte
Normal file
26
client/src/lib/Apps/DevTools/DevTools.svelte
Normal file
|
@ -0,0 +1,26 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import AppContainer from '../AppContainer.svelte'
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<AppContainer
|
||||||
|
class="flex gap-6 bg-blue-200 bg-opacity-25 backdrop-blur-xl media-background rounded-3xl flex-wrap px-10 py-20"
|
||||||
|
>
|
||||||
|
<h1 class="text-5xl font-medium text-slate-100 basis-full">
|
||||||
|
Developer Tools
|
||||||
|
</h1>
|
||||||
|
<h2 class="basis-full">
|
||||||
|
This is an app where developers can add buttons that trigger code to help
|
||||||
|
during development.
|
||||||
|
</h2>
|
||||||
|
<p class="basis-full">
|
||||||
|
Make sure the entry for this app is commented out in appList.ts before
|
||||||
|
building for production.
|
||||||
|
</p>
|
||||||
|
<button class="button">Button</button>
|
||||||
|
</AppContainer>
|
||||||
|
|
||||||
|
<style lang="postcss">
|
||||||
|
.button {
|
||||||
|
@apply px-4 py-2 bg-blue-500 hover:brightness-75 font-medium rounded-lg w-min;
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -9,6 +9,7 @@ const resolveIconPath = (slug: keyof typeof appList, format: Format) => {
|
||||||
|
|
||||||
import GBAEmulator from './GBAEmulator/GBAEmulator.svelte'
|
import GBAEmulator from './GBAEmulator/GBAEmulator.svelte'
|
||||||
import JsDoom from './JSDoom/JSDoom.svelte'
|
import JsDoom from './JSDoom/JSDoom.svelte'
|
||||||
|
import DevTools from './DevTools/DevTools.svelte'
|
||||||
|
|
||||||
interface AppList {
|
interface AppList {
|
||||||
[key: string]: {
|
[key: string]: {
|
||||||
|
@ -50,4 +51,10 @@ export const appList: AppList = {
|
||||||
icon: resolveIconPath('settings', 'png'),
|
icon: resolveIconPath('settings', 'png'),
|
||||||
external: false,
|
external: false,
|
||||||
},
|
},
|
||||||
|
'dev-tools': {
|
||||||
|
name: 'DevTools',
|
||||||
|
component: DevTools,
|
||||||
|
icon: resolveIconPath('dev-tools', 'png'),
|
||||||
|
external: false,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
import Compass from './Compass.svelte'
|
import Compass from './Compass.svelte'
|
||||||
import { telemetryReadonlyStore } from '../stores/telemetryStore'
|
import { telemetryReadonlyStore } from '../stores/telemetryStore'
|
||||||
import Bottom from './Bottom.svelte'
|
import Bottom from './Bottom.svelte'
|
||||||
|
import Visualization from './Visualization/Visualization.svelte'
|
||||||
|
|
||||||
$: speedResolved = Math.hypot(
|
$: speedResolved = Math.hypot(
|
||||||
$telemetryReadonlyStore['chassis-x-speed'],
|
$telemetryReadonlyStore['chassis-x-speed'],
|
||||||
|
@ -36,6 +37,10 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="left-0 mt-2 h-[475px] w-[35vw]">
|
||||||
|
<Visualization />
|
||||||
|
</div>
|
||||||
|
|
||||||
<Bottom>
|
<Bottom>
|
||||||
<div class="mb-10">
|
<div class="mb-10">
|
||||||
<Compass
|
<Compass
|
||||||
|
|
178
client/src/lib/Dashboard/Visualization/Controls.svelte
Normal file
178
client/src/lib/Dashboard/Visualization/Controls.svelte
Normal file
|
@ -0,0 +1,178 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { createEventDispatcher, onDestroy } from 'svelte'
|
||||||
|
import { Camera, Vector2, Vector3, Quaternion } from 'three'
|
||||||
|
import { useThrelte, useParent, useTask } from '@threlte/core'
|
||||||
|
|
||||||
|
export let object: Camera
|
||||||
|
export let rotateSpeed = 1.0
|
||||||
|
|
||||||
|
$: if (object) {
|
||||||
|
// console.log(object)
|
||||||
|
// object.position.y = 10
|
||||||
|
// // Calculate the direction vector towards (0, 0, 0)
|
||||||
|
// const target = new Vector3(0, 0, 0)
|
||||||
|
// const direction = target.clone().sub(object.position).normalize()
|
||||||
|
// // Extract the forward direction from the object's current rotation matrix
|
||||||
|
// const currentDirection = new Vector3(0, 1, 0)
|
||||||
|
// currentDirection.applyQuaternion(object.quaternion)
|
||||||
|
// // Calculate the axis and angle to rotate the object
|
||||||
|
// const rotationAxis = currentDirection.clone().cross(direction).normalize()
|
||||||
|
// const rotationAngle = Math.acos(currentDirection.dot(direction))
|
||||||
|
// // Rotate the object using rotateOnAxis()
|
||||||
|
// object.rotateOnAxis(rotationAxis, rotationAngle)
|
||||||
|
}
|
||||||
|
|
||||||
|
export let idealOffset = { x: -0.5, y: 2, z: -3 }
|
||||||
|
export let idealLookAt = { x: 0, y: 1, z: 5 }
|
||||||
|
|
||||||
|
const currentPosition = new Vector3()
|
||||||
|
const currentLookAt = new Vector3()
|
||||||
|
|
||||||
|
let isOrbiting = false
|
||||||
|
let pointerDown = false
|
||||||
|
|
||||||
|
const rotateStart = new Vector2()
|
||||||
|
const rotateEnd = new Vector2()
|
||||||
|
const rotateDelta = new Vector2()
|
||||||
|
|
||||||
|
const axis = new Vector3(0, 1, 0)
|
||||||
|
const rotationQuat = new Quaternion()
|
||||||
|
|
||||||
|
const { renderer, invalidate } = useThrelte()
|
||||||
|
|
||||||
|
const domElement = renderer.domElement
|
||||||
|
const camera = useParent()
|
||||||
|
|
||||||
|
const dispatch = createEventDispatcher()
|
||||||
|
|
||||||
|
const isCamera = (p: any): p is Camera => {
|
||||||
|
return p.isCamera
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!isCamera($camera)) {
|
||||||
|
throw new Error(
|
||||||
|
'Parent missing: <PointerLockControls> need to be a child of a <Camera>'
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
// domElement.addEventListener('pointerdown', onPointerDown)
|
||||||
|
// domElement.addEventListener('pointermove', onPointerMove)
|
||||||
|
// domElement.addEventListener('pointerleave', onPointerLeave)
|
||||||
|
// domElement.addEventListener('pointerup', onPointerUp)
|
||||||
|
|
||||||
|
onDestroy(() => {
|
||||||
|
// domElement.removeEventListener('pointerdown', onPointerDown)
|
||||||
|
// domElement.removeEventListener('pointermove', onPointerMove)
|
||||||
|
// domElement.removeEventListener('pointerleave', onPointerLeave)
|
||||||
|
// domElement.removeEventListener('pointerup', onPointerUp)
|
||||||
|
})
|
||||||
|
|
||||||
|
// This is basically your update function
|
||||||
|
useTask(delta => {
|
||||||
|
// the object's position is bound to the prop
|
||||||
|
if (!object) return
|
||||||
|
|
||||||
|
// camera is based on character so we rotation character first
|
||||||
|
// rotationQuat.setFromAxisAngle(axis, -rotateDelta.x * rotateSpeed * delta)
|
||||||
|
// object.quaternion.multiply(rotationQuat)
|
||||||
|
|
||||||
|
// then we calculate our ideal's
|
||||||
|
const offset = vectorFromObject(idealOffset)
|
||||||
|
const lookAt = vectorFromObject(idealLookAt)
|
||||||
|
|
||||||
|
// and how far we should move towards them
|
||||||
|
const t = 1.0 - Math.pow(0.001, delta)
|
||||||
|
currentPosition.lerp(offset, t)
|
||||||
|
currentLookAt.lerp(lookAt, t)
|
||||||
|
|
||||||
|
// then finally set the camera, a bit behind the model
|
||||||
|
$camera!.position.copy(currentPosition)
|
||||||
|
const behindOffset = currentPosition
|
||||||
|
.clone()
|
||||||
|
.normalize()
|
||||||
|
.multiplyScalar(8)
|
||||||
|
.setY(0.5)
|
||||||
|
|
||||||
|
$camera!.position.copy(currentPosition).add(behindOffset)
|
||||||
|
|
||||||
|
$camera!.lookAt(currentLookAt)
|
||||||
|
})
|
||||||
|
|
||||||
|
function onPointerMove(event: PointerEvent) {
|
||||||
|
const { x, y } = event
|
||||||
|
if (pointerDown && !isOrbiting) {
|
||||||
|
// calculate distance from init down
|
||||||
|
const distCheck =
|
||||||
|
Math.sqrt(
|
||||||
|
Math.pow(x - rotateStart.x, 2) + Math.pow(y - rotateStart.y, 2)
|
||||||
|
) > 10
|
||||||
|
if (distCheck) {
|
||||||
|
isOrbiting = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!isOrbiting) return
|
||||||
|
|
||||||
|
rotateEnd.set(x, y)
|
||||||
|
rotateDelta.subVectors(rotateEnd, rotateStart).multiplyScalar(rotateSpeed)
|
||||||
|
rotateStart.copy(rotateEnd)
|
||||||
|
|
||||||
|
invalidate()
|
||||||
|
dispatch('change')
|
||||||
|
}
|
||||||
|
|
||||||
|
function onPointerDown(event: PointerEvent) {
|
||||||
|
const { x, y } = event
|
||||||
|
rotateStart.set(x, y)
|
||||||
|
pointerDown = true
|
||||||
|
}
|
||||||
|
|
||||||
|
function onPointerUp() {
|
||||||
|
rotateDelta.set(0, 0)
|
||||||
|
pointerDown = false
|
||||||
|
isOrbiting = false
|
||||||
|
}
|
||||||
|
|
||||||
|
function onPointerLeave() {
|
||||||
|
rotateDelta.set(0, 0)
|
||||||
|
pointerDown = false
|
||||||
|
isOrbiting = false
|
||||||
|
}
|
||||||
|
|
||||||
|
function vectorFromObject(vec: { x: number; y: number; z: number }) {
|
||||||
|
const { x, y, z } = vec
|
||||||
|
const ideal = new Vector3(x, y, z)
|
||||||
|
ideal.applyQuaternion(object.quaternion)
|
||||||
|
ideal.add(
|
||||||
|
new Vector3(object.position.x, object.position.y, object.position.z)
|
||||||
|
)
|
||||||
|
return ideal
|
||||||
|
}
|
||||||
|
|
||||||
|
function onKeyDown(event: KeyboardEvent) {
|
||||||
|
switch (event.key) {
|
||||||
|
case 'a':
|
||||||
|
rotateDelta.x = -2 * rotateSpeed
|
||||||
|
break
|
||||||
|
case 'd':
|
||||||
|
rotateDelta.x = 2 * rotateSpeed
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function onKeyUp(event: KeyboardEvent) {
|
||||||
|
switch (event.key) {
|
||||||
|
case 'a':
|
||||||
|
rotateDelta.x = 0
|
||||||
|
break
|
||||||
|
case 'd':
|
||||||
|
rotateDelta.x = 0
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- <svelte:window on:keydown={onKeyDown} on:keyup={onKeyUp} /> -->
|
141
client/src/lib/Dashboard/Visualization/Scene.svelte
Normal file
141
client/src/lib/Dashboard/Visualization/Scene.svelte
Normal file
|
@ -0,0 +1,141 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { T, useTask } from '@threlte/core'
|
||||||
|
import { ContactShadows, Float, Grid, OrbitControls } from '@threlte/extras'
|
||||||
|
import Hornet from './models/Hornet.svelte'
|
||||||
|
import { onMount } from 'svelte'
|
||||||
|
import Controls from './Controls.svelte'
|
||||||
|
import type { Camera, Group, Object3D, Object3DEventMap } from 'three'
|
||||||
|
import {
|
||||||
|
telemetryReadonlyStore,
|
||||||
|
telemetryStore,
|
||||||
|
} from '../../stores/telemetryStore'
|
||||||
|
import { get } from 'svelte/store'
|
||||||
|
|
||||||
|
// const rotate90 = () => {
|
||||||
|
// const originalRot = rot
|
||||||
|
// }
|
||||||
|
|
||||||
|
// onMount(() => {
|
||||||
|
// setTimeout(rotate90, 5000)
|
||||||
|
// })
|
||||||
|
|
||||||
|
// CONSTANTS
|
||||||
|
const maxAngularVelocity = 2 // Max angular velocity, in radians per second
|
||||||
|
const stoppingThreshold = 0.005 // Threshold in radians for when to consider the rotation close enough to stop
|
||||||
|
|
||||||
|
// Proportional control factor
|
||||||
|
const kP = 2 // Adjust this value based on responsiveness and stability needs
|
||||||
|
|
||||||
|
// simulate some turning for testing
|
||||||
|
const simulateTurning = () => {
|
||||||
|
let delay = Math.random() * 4500 + 500
|
||||||
|
let randOffset = Math.random() * 170 * (Math.random() < 0.5 ? -1 : 1)
|
||||||
|
telemetryStore.update({
|
||||||
|
...get(telemetryReadonlyStore),
|
||||||
|
orientation: get(telemetryReadonlyStore)['orientation'] + randOffset,
|
||||||
|
})
|
||||||
|
setTimeout(simulateTurning, delay)
|
||||||
|
}
|
||||||
|
simulateTurning()
|
||||||
|
|
||||||
|
// Sync robot orientation with target rotation
|
||||||
|
let targetRot = 0
|
||||||
|
telemetryReadonlyStore.subscribe(value => {
|
||||||
|
targetRot = (value['orientation'] * Math.PI) / 180 // convert deg to rad
|
||||||
|
})
|
||||||
|
|
||||||
|
// Updates rotation to match target with PID controller (intended to be invoked in useTask)
|
||||||
|
let rot = 0 // (initial) rotation in radians
|
||||||
|
let angularVelocity = 0
|
||||||
|
const updateRotation = (delta: number) => {
|
||||||
|
let angleDifference = targetRot - rot
|
||||||
|
|
||||||
|
// Normalize angle difference to the range [-π, π]
|
||||||
|
angleDifference = ((angleDifference + Math.PI) % (2 * Math.PI)) - Math.PI
|
||||||
|
|
||||||
|
// Calculate the desired angular velocity based on the angle difference
|
||||||
|
let desiredVelocity =
|
||||||
|
Math.sign(angleDifference) *
|
||||||
|
Math.min(maxAngularVelocity, Math.abs(kP * angleDifference))
|
||||||
|
|
||||||
|
// If the object is very close to the target, adjust the desired velocity to zero to prevent overshooting
|
||||||
|
if (Math.abs(angleDifference) < stoppingThreshold) {
|
||||||
|
desiredVelocity = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
// Adjust angular velocity towards desired velocity
|
||||||
|
angularVelocity = desiredVelocity
|
||||||
|
|
||||||
|
// Update rotation
|
||||||
|
rot += angularVelocity * delta
|
||||||
|
|
||||||
|
// Normalize rot to the range [0, 2π]
|
||||||
|
if (rot < 0) rot += 2 * Math.PI
|
||||||
|
else if (rot > 2 * Math.PI) rot -= 2 * Math.PI
|
||||||
|
|
||||||
|
// Snap to the target rotation to prevent tiny oscillations if close enough
|
||||||
|
if (Math.abs(angleDifference) < stoppingThreshold) {
|
||||||
|
rot = targetRot
|
||||||
|
angularVelocity = 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Assuming useTask is called every frame with the time delta
|
||||||
|
useTask(delta => {
|
||||||
|
updateRotation(delta)
|
||||||
|
})
|
||||||
|
|
||||||
|
let capsule: Group<Object3DEventMap>
|
||||||
|
let capRef: Camera
|
||||||
|
$: if (capsule) {
|
||||||
|
// typescript hacks because i dont know what im doing
|
||||||
|
capRef = capsule as unknown as Camera
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<!-- <T.PerspectiveCamera makeDefault position={[-10, 10, 10]} fov={15}>
|
||||||
|
<OrbitControls
|
||||||
|
autoRotate
|
||||||
|
enableZoom={true}
|
||||||
|
enableDamping
|
||||||
|
autoRotateSpeed={0.5}
|
||||||
|
target.y={1.5}
|
||||||
|
/>
|
||||||
|
</T.PerspectiveCamera> -->
|
||||||
|
|
||||||
|
<T.PerspectiveCamera makeDefault position={[0, 8, -20]} fov={75} on:create>
|
||||||
|
<OrbitControls
|
||||||
|
enableZoom={true}
|
||||||
|
enableDamping
|
||||||
|
autoRotateSpeed={5}
|
||||||
|
target.y={1.5}
|
||||||
|
autoRotate
|
||||||
|
/>
|
||||||
|
<Controls bind:object={capRef} />
|
||||||
|
</T.PerspectiveCamera>
|
||||||
|
|
||||||
|
<T.DirectionalLight intensity={0.8} position.x={5} position.y={10} />
|
||||||
|
<T.AmbientLight intensity={0.2} />
|
||||||
|
|
||||||
|
<Grid
|
||||||
|
position.y={1}
|
||||||
|
cellColor="#ffffff"
|
||||||
|
sectionColor="#ffffff"
|
||||||
|
sectionThickness={0}
|
||||||
|
fadeDistance={50}
|
||||||
|
cellSize={2}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<ContactShadows scale={10} blur={2} far={2.5} opacity={0.5} />
|
||||||
|
|
||||||
|
<Float floatIntensity={1} floatingRange={[0, 0.5]}>
|
||||||
|
<!-- <T.Mesh > -->
|
||||||
|
<Hornet
|
||||||
|
position={[0, 1.7, 0]}
|
||||||
|
scale={[0.8, 0.8, 0.8]}
|
||||||
|
bind:ref={capsule}
|
||||||
|
rotation.y={rot}
|
||||||
|
/>
|
||||||
|
<!-- <T.MeshStandardMaterial color="#F8EBCE" /> -->
|
||||||
|
<!-- </T.Mesh> -->
|
||||||
|
</Float>
|
|
@ -0,0 +1,8 @@
|
||||||
|
<script lang="ts">
|
||||||
|
import { Canvas } from '@threlte/core'
|
||||||
|
import Scene from './Scene.svelte'
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<Canvas>
|
||||||
|
<Scene />
|
||||||
|
</Canvas>
|
95
client/src/lib/Dashboard/Visualization/models/Hornet.svelte
Normal file
95
client/src/lib/Dashboard/Visualization/models/Hornet.svelte
Normal file
|
@ -0,0 +1,95 @@
|
||||||
|
<!--
|
||||||
|
Auto-generated by: https://github.com/threlte/threlte/tree/main/packages/gltf
|
||||||
|
Command: npx @threlte/gltf@2.0.1 /Users/youwenw/Projects/JS/threlte-demo/static/models/scene.gltf --root /models/ --types --printwidth 120 --precision 2
|
||||||
|
Author: cs09736 (https://sketchfab.com/cs09736)
|
||||||
|
License: CC-BY-SA-4.0 (http://creativecommons.org/licenses/by-sa/4.0/)
|
||||||
|
Source: https://sketchfab.com/3d-models/low-poly-fa-18-hornet-9b48c88e91ba40fc8f518b616f44f714
|
||||||
|
Title: Low Poly F/A-18 Hornet
|
||||||
|
-->
|
||||||
|
|
||||||
|
<script lang="ts">
|
||||||
|
import type * as THREE from 'three'
|
||||||
|
import { Group } from 'three'
|
||||||
|
import {
|
||||||
|
T,
|
||||||
|
type Props,
|
||||||
|
type Events,
|
||||||
|
type Slots,
|
||||||
|
forwardEventHandlers,
|
||||||
|
} from '@threlte/core'
|
||||||
|
import { useGltf } from '@threlte/extras'
|
||||||
|
|
||||||
|
type $$Props = Props<THREE.Group>
|
||||||
|
type $$Events = Events<THREE.Group>
|
||||||
|
type $$Slots = Slots<THREE.Group> & { fallback: {}; error: { error: any } }
|
||||||
|
|
||||||
|
export const ref = new Group()
|
||||||
|
|
||||||
|
type GLTFResult = {
|
||||||
|
nodes: {
|
||||||
|
Object_4: THREE.Mesh
|
||||||
|
Object_5: THREE.Mesh
|
||||||
|
Object_6: THREE.Mesh
|
||||||
|
Object_7: THREE.Mesh
|
||||||
|
Object_8: THREE.Mesh
|
||||||
|
Object_9: THREE.Mesh
|
||||||
|
Object_10: THREE.Mesh
|
||||||
|
}
|
||||||
|
materials: {
|
||||||
|
clay: THREE.MeshStandardMaterial
|
||||||
|
engine_inside: THREE.MeshStandardMaterial
|
||||||
|
body_paint: THREE.MeshStandardMaterial
|
||||||
|
glass: THREE.MeshStandardMaterial
|
||||||
|
after_burner: THREE.MeshStandardMaterial
|
||||||
|
strut: THREE.MeshStandardMaterial
|
||||||
|
tyre: THREE.MeshStandardMaterial
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const gltf = useGltf<GLTFResult>('/src/assets/models/scene.gltf')
|
||||||
|
|
||||||
|
const component = forwardEventHandlers()
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<T is={ref} dispose={false} {...$$restProps} bind:this={$component}>
|
||||||
|
{#await gltf}
|
||||||
|
<slot name="fallback" />
|
||||||
|
{:then gltf}
|
||||||
|
<T.Group rotation={[-Math.PI / 2, 0, 0]} scale={2}>
|
||||||
|
<T.Group rotation={[Math.PI / 2, 0, 0]}>
|
||||||
|
<T.Mesh
|
||||||
|
geometry={gltf.nodes.Object_4.geometry}
|
||||||
|
material={gltf.materials.clay}
|
||||||
|
/>
|
||||||
|
<T.Mesh
|
||||||
|
geometry={gltf.nodes.Object_5.geometry}
|
||||||
|
material={gltf.materials.engine_inside}
|
||||||
|
/>
|
||||||
|
<T.Mesh
|
||||||
|
geometry={gltf.nodes.Object_6.geometry}
|
||||||
|
material={gltf.materials.body_paint}
|
||||||
|
/>
|
||||||
|
<T.Mesh
|
||||||
|
geometry={gltf.nodes.Object_7.geometry}
|
||||||
|
material={gltf.materials.glass}
|
||||||
|
/>
|
||||||
|
<T.Mesh
|
||||||
|
geometry={gltf.nodes.Object_8.geometry}
|
||||||
|
material={gltf.materials.after_burner}
|
||||||
|
/>
|
||||||
|
<T.Mesh
|
||||||
|
geometry={gltf.nodes.Object_9.geometry}
|
||||||
|
material={gltf.materials.strut}
|
||||||
|
/>
|
||||||
|
<T.Mesh
|
||||||
|
geometry={gltf.nodes.Object_10.geometry}
|
||||||
|
material={gltf.materials.tyre}
|
||||||
|
/>
|
||||||
|
</T.Group>
|
||||||
|
</T.Group>
|
||||||
|
{:catch error}
|
||||||
|
<slot name="error" {error} />
|
||||||
|
{/await}
|
||||||
|
|
||||||
|
<slot {ref} />
|
||||||
|
</T>
|
0
client/src/lib/Dashboard/Visualization/utils.ts
Normal file
0
client/src/lib/Dashboard/Visualization/utils.ts
Normal file
Loading…
Reference in a new issue