fix: git lfs is back.
This commit is contained in:
parent
78f9eb0cbf
commit
23163b947d
87 changed files with 322 additions and 61 deletions
BIN
.DS_Store
vendored
Normal file
BIN
.DS_Store
vendored
Normal file
Binary file not shown.
BIN
app/.DS_Store
vendored
Normal file
BIN
app/.DS_Store
vendored
Normal file
Binary file not shown.
BIN
app/static/.DS_Store
vendored
Normal file
BIN
app/static/.DS_Store
vendored
Normal file
Binary file not shown.
BIN
app/static/app-icons/Settings.webp
Normal file
BIN
app/static/app-icons/Settings.webp
Normal file
Binary file not shown.
After Width: | Height: | Size: 8.5 KiB |
BIN
app/static/sfx/.DS_Store
vendored
Normal file
BIN
app/static/sfx/.DS_Store
vendored
Normal file
Binary file not shown.
BIN
app/static/voices/.DS_Store
vendored
Normal file
BIN
app/static/voices/.DS_Store
vendored
Normal file
Binary file not shown.
BIN
app/static/voices/en/adaptive-cruise-control.wav
Normal file
BIN
app/static/voices/en/adaptive-cruise-control.wav
Normal file
Binary file not shown.
BIN
app/static/voices/en/all-brakes-disengaged.wav
Normal file
BIN
app/static/voices/en/all-brakes-disengaged.wav
Normal file
Binary file not shown.
BIN
app/static/voices/en/autonomous-period-started.wav
Normal file
BIN
app/static/voices/en/autonomous-period-started.wav
Normal file
Binary file not shown.
BIN
app/static/voices/en/battery-critically-low.wav
Normal file
BIN
app/static/voices/en/battery-critically-low.wav
Normal file
Binary file not shown.
BIN
app/static/voices/en/battery-faults-detected.wav
Normal file
BIN
app/static/voices/en/battery-faults-detected.wav
Normal file
Binary file not shown.
BIN
app/static/voices/en/battery-good.wav
Normal file
BIN
app/static/voices/en/battery-good.wav
Normal file
Binary file not shown.
BIN
app/static/voices/en/battery-low.wav
Normal file
BIN
app/static/voices/en/battery-low.wav
Normal file
Binary file not shown.
BIN
app/static/voices/en/breaching-1323-mainframe.wav
Normal file
BIN
app/static/voices/en/breaching-1323-mainframe.wav
Normal file
Binary file not shown.
BIN
app/static/voices/en/breaching-254-mainframe.wav
Normal file
BIN
app/static/voices/en/breaching-254-mainframe.wav
Normal file
Binary file not shown.
BIN
app/static/voices/en/breaching-fms.wav
Normal file
BIN
app/static/voices/en/breaching-fms.wav
Normal file
Binary file not shown.
BIN
app/static/voices/en/breaching-monte-vista.wav
Normal file
BIN
app/static/voices/en/breaching-monte-vista.wav
Normal file
Binary file not shown.
BIN
app/static/voices/en/bullying-rohan.wav
Normal file
BIN
app/static/voices/en/bullying-rohan.wav
Normal file
Binary file not shown.
BIN
app/static/voices/en/bypassing-coprocessor-restrictions.wav
Normal file
BIN
app/static/voices/en/bypassing-coprocessor-restrictions.wav
Normal file
Binary file not shown.
BIN
app/static/voices/en/collision-detected.wav
Normal file
BIN
app/static/voices/en/collision-detected.wav
Normal file
Binary file not shown.
BIN
app/static/voices/en/collision-imminent.wav
Normal file
BIN
app/static/voices/en/collision-imminent.wav
Normal file
Binary file not shown.
BIN
app/static/voices/en/critical-robot-failure.wav
Normal file
BIN
app/static/voices/en/critical-robot-failure.wav
Normal file
Binary file not shown.
BIN
app/static/voices/en/cruise-control-engaged.wav
Normal file
BIN
app/static/voices/en/cruise-control-engaged.wav
Normal file
Binary file not shown.
BIN
app/static/voices/en/deep-bozo-buffering.wav
Normal file
BIN
app/static/voices/en/deep-bozo-buffering.wav
Normal file
Binary file not shown.
BIN
app/static/voices/en/deep-bozo-has-detected.wav
Normal file
BIN
app/static/voices/en/deep-bozo-has-detected.wav
Normal file
Binary file not shown.
BIN
app/static/voices/en/deep-bozo-has-sentience.wav
Normal file
BIN
app/static/voices/en/deep-bozo-has-sentience.wav
Normal file
Binary file not shown.
BIN
app/static/voices/en/doom-engaged.wav
Normal file
BIN
app/static/voices/en/doom-engaged.wav
Normal file
Binary file not shown.
BIN
app/static/voices/en/downloading-copyrighted-music.wav
Normal file
BIN
app/static/voices/en/downloading-copyrighted-music.wav
Normal file
Binary file not shown.
BIN
app/static/voices/en/e-brakes-engaged.wav
Normal file
BIN
app/static/voices/en/e-brakes-engaged.wav
Normal file
Binary file not shown.
BIN
app/static/voices/en/e-stop-and.wav
Normal file
BIN
app/static/voices/en/e-stop-and.wav
Normal file
Binary file not shown.
BIN
app/static/voices/en/e-stop-automatically.wav
Normal file
BIN
app/static/voices/en/e-stop-automatically.wav
Normal file
Binary file not shown.
BIN
app/static/voices/en/e-stop-temporarily.wav
Normal file
BIN
app/static/voices/en/e-stop-temporarily.wav
Normal file
Binary file not shown.
BIN
app/static/voices/en/emergency-speedbost-engaged.wav
Normal file
BIN
app/static/voices/en/emergency-speedbost-engaged.wav
Normal file
Binary file not shown.
BIN
app/static/voices/en/follow-mode-engaged.wav
Normal file
BIN
app/static/voices/en/follow-mode-engaged.wav
Normal file
Binary file not shown.
BIN
app/static/voices/en/full-self-driving-automatically.wav
Normal file
BIN
app/static/voices/en/full-self-driving-automatically.wav
Normal file
Binary file not shown.
BIN
app/static/voices/en/full-self-driving-disengaged.wav
Normal file
BIN
app/static/voices/en/full-self-driving-disengaged.wav
Normal file
Binary file not shown.
BIN
app/static/voices/en/full-self-driving-engaged.wav
Normal file
BIN
app/static/voices/en/full-self-driving-engaged.wav
Normal file
Binary file not shown.
BIN
app/static/voices/en/full-self-driving-refuses.wav
Normal file
BIN
app/static/voices/en/full-self-driving-refuses.wav
Normal file
Binary file not shown.
BIN
app/static/voices/en/hello-virtual-assistant.wav
Normal file
BIN
app/static/voices/en/hello-virtual-assistant.wav
Normal file
Binary file not shown.
BIN
app/static/voices/en/infotainment-system-buffering.wav
Normal file
BIN
app/static/voices/en/infotainment-system-buffering.wav
Normal file
Binary file not shown.
BIN
app/static/voices/en/infotainment-system-online.wav
Normal file
BIN
app/static/voices/en/infotainment-system-online.wav
Normal file
Binary file not shown.
BIN
app/static/voices/en/jankboard-initialized.wav
Normal file
BIN
app/static/voices/en/jankboard-initialized.wav
Normal file
Binary file not shown.
BIN
app/static/voices/en/littenos-is-online.wav
Normal file
BIN
app/static/voices/en/littenos-is-online.wav
Normal file
Binary file not shown.
BIN
app/static/voices/en/loading-pirated-nintendo.wav
Normal file
BIN
app/static/voices/en/loading-pirated-nintendo.wav
Normal file
Binary file not shown.
BIN
app/static/voices/en/max-vestrapren-do.wav
Normal file
BIN
app/static/voices/en/max-vestrapren-do.wav
Normal file
Binary file not shown.
BIN
app/static/voices/en/neutral-brakes-disengaged.wav
Normal file
BIN
app/static/voices/en/neutral-brakes-disengaged.wav
Normal file
Binary file not shown.
BIN
app/static/voices/en/overspeed.wav
Normal file
BIN
app/static/voices/en/overspeed.wav
Normal file
Binary file not shown.
BIN
app/static/voices/en/parked-brakes-engaged.wav
Normal file
BIN
app/static/voices/en/parked-brakes-engaged.wav
Normal file
Binary file not shown.
BIN
app/static/voices/en/rapid-deceleration-detected.wav
Normal file
BIN
app/static/voices/en/rapid-deceleration-detected.wav
Normal file
Binary file not shown.
BIN
app/static/voices/en/rapidly-approaching-speed.wav
Normal file
BIN
app/static/voices/en/rapidly-approaching-speed.wav
Normal file
Binary file not shown.
BIN
app/static/voices/en/retard.wav
Normal file
BIN
app/static/voices/en/retard.wav
Normal file
Binary file not shown.
BIN
app/static/voices/en/reverse.wav
Normal file
BIN
app/static/voices/en/reverse.wav
Normal file
Binary file not shown.
BIN
app/static/voices/en/self-destruct-countdown.wav
Normal file
BIN
app/static/voices/en/self-destruct-countdown.wav
Normal file
Binary file not shown.
BIN
app/static/voices/en/sentry-mode-engaged.wav
Normal file
BIN
app/static/voices/en/sentry-mode-engaged.wav
Normal file
Binary file not shown.
BIN
app/static/voices/en/set-acceleration-profile-chill.wav
Normal file
BIN
app/static/voices/en/set-acceleration-profile-chill.wav
Normal file
Binary file not shown.
BIN
app/static/voices/en/set-acceleration-profile-ludicrous.wav
Normal file
BIN
app/static/voices/en/set-acceleration-profile-ludicrous.wav
Normal file
Binary file not shown.
BIN
app/static/voices/en/shifted-into-automatic.wav
Normal file
BIN
app/static/voices/en/shifted-into-automatic.wav
Normal file
Binary file not shown.
BIN
app/static/voices/en/shifted-into-drive.wav
Normal file
BIN
app/static/voices/en/shifted-into-drive.wav
Normal file
Binary file not shown.
BIN
app/static/voices/en/shifted-into-low.wav
Normal file
BIN
app/static/voices/en/shifted-into-low.wav
Normal file
Binary file not shown.
BIN
app/static/voices/en/shut-down-sequence.wav
Normal file
BIN
app/static/voices/en/shut-down-sequence.wav
Normal file
Binary file not shown.
BIN
app/static/voices/en/teleoperated-period-started.wav
Normal file
BIN
app/static/voices/en/teleoperated-period-started.wav
Normal file
Binary file not shown.
BIN
app/static/voices/en/terrain-pull-up.wav
Normal file
BIN
app/static/voices/en/terrain-pull-up.wav
Normal file
Binary file not shown.
BIN
app/static/voices/en/user-error-detected.wav
Normal file
BIN
app/static/voices/en/user-error-detected.wav
Normal file
Binary file not shown.
BIN
app/static/voices/rus/.DS_Store
vendored
Normal file
BIN
app/static/voices/rus/.DS_Store
vendored
Normal file
Binary file not shown.
65
client/package-lock.json
generated
65
client/package-lock.json
generated
|
@ -9,14 +9,17 @@
|
|||
"version": "0.0.0",
|
||||
"dependencies": {
|
||||
"@fontsource/roboto": "^5.0.8",
|
||||
"howler": "^2.2.4",
|
||||
"material-icons": "^1.13.12",
|
||||
"material-symbols": "^0.15.0",
|
||||
"socket.io-client": "^4.7.4"
|
||||
"socket.io-client": "^4.7.4",
|
||||
"svelte-french-toast": "^1.2.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@sveltejs/adapter-static": "^3.0.1",
|
||||
"@sveltejs/vite-plugin-svelte": "^3.0.2",
|
||||
"@tsconfig/svelte": "^5.0.2",
|
||||
"@types/howler": "^2.2.11",
|
||||
"autoprefixer": "^10.4.17",
|
||||
"postcss": "^8.4.35",
|
||||
"svelte": "^4.2.11",
|
||||
|
@ -43,7 +46,6 @@
|
|||
"version": "2.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.1.tgz",
|
||||
"integrity": "sha512-lFMjJTrFL3j7L9yBxwYfCq2k6qqwHyzuUl/XBnif78PWTJYyL/dfowQHWE3sp6U6ZzqWiiIZnpTMO96zhkjwtg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@jridgewell/gen-mapping": "^0.3.0",
|
||||
"@jridgewell/trace-mapping": "^0.3.9"
|
||||
|
@ -446,7 +448,6 @@
|
|||
"version": "0.3.3",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.3.tgz",
|
||||
"integrity": "sha512-HLhSWOLRi875zjjMG/r+Nv0oCW8umGb0BgEhyX3dDX3egwZtB8PqLnjz3yedt8R5StBrzcg4aBpnh8UA9D1BoQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@jridgewell/set-array": "^1.0.1",
|
||||
"@jridgewell/sourcemap-codec": "^1.4.10",
|
||||
|
@ -460,7 +461,6 @@
|
|||
"version": "3.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
|
||||
"integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=6.0.0"
|
||||
}
|
||||
|
@ -469,7 +469,6 @@
|
|||
"version": "1.1.2",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz",
|
||||
"integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=6.0.0"
|
||||
}
|
||||
|
@ -477,14 +476,12 @@
|
|||
"node_modules/@jridgewell/sourcemap-codec": {
|
||||
"version": "1.4.15",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz",
|
||||
"integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==",
|
||||
"dev": true
|
||||
"integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg=="
|
||||
},
|
||||
"node_modules/@jridgewell/trace-mapping": {
|
||||
"version": "0.3.22",
|
||||
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.22.tgz",
|
||||
"integrity": "sha512-Wf963MzWtA2sjrNt+g18IAln9lKnlRp+K2eH4jjIoF1wYeq3aMREpG09xhlhdzS0EjwU7qmUJYangWa+151vZw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@jridgewell/resolve-uri": "^3.1.0",
|
||||
"@jridgewell/sourcemap-codec": "^1.4.14"
|
||||
|
@ -813,7 +810,12 @@
|
|||
"node_modules/@types/estree": {
|
||||
"version": "1.0.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz",
|
||||
"integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==",
|
||||
"integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw=="
|
||||
},
|
||||
"node_modules/@types/howler": {
|
||||
"version": "2.2.11",
|
||||
"resolved": "https://registry.npmjs.org/@types/howler/-/howler-2.2.11.tgz",
|
||||
"integrity": "sha512-7aBoUL6RbSIrqKnpEgfa1wSNUBK06mn08siP2QI0zYk7MXfEJAaORc4tohamQYqCqVESoDyRWSdQn2BOKWj2Qw==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@types/pug": {
|
||||
|
@ -826,7 +828,6 @@
|
|||
"version": "8.11.3",
|
||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz",
|
||||
"integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"acorn": "bin/acorn"
|
||||
},
|
||||
|
@ -887,7 +888,6 @@
|
|||
"version": "5.3.0",
|
||||
"resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.3.0.tgz",
|
||||
"integrity": "sha512-b0P0sZPKtyu8HkeRAfCq0IfURZK+SuwMjY1UXGBU27wpAiTwQAIlq56IbIO+ytk/JjS1fMR14ee5WBBfKi5J6A==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"dequal": "^2.0.3"
|
||||
}
|
||||
|
@ -933,7 +933,6 @@
|
|||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-4.0.0.tgz",
|
||||
"integrity": "sha512-+60uv1hiVFhHZeO+Lz0RYzsVHy5Wr1ayX0mwda9KPDVLNJgZ1T9Ny7VmFbLDzxsH0D87I86vgj3gFrjTJUYznw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"dequal": "^2.0.3"
|
||||
}
|
||||
|
@ -1082,7 +1081,6 @@
|
|||
"version": "1.0.4",
|
||||
"resolved": "https://registry.npmjs.org/code-red/-/code-red-1.0.4.tgz",
|
||||
"integrity": "sha512-7qJWqItLA8/VPVlKJlFXU+NBlo/qyfs39aJcuMT/2ere32ZqvF5OSxgdM5xOfJJ7O429gg2HM47y8v9P+9wrNw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@jridgewell/sourcemap-codec": "^1.4.15",
|
||||
"@types/estree": "^1.0.1",
|
||||
|
@ -1152,7 +1150,6 @@
|
|||
"version": "2.3.1",
|
||||
"resolved": "https://registry.npmjs.org/css-tree/-/css-tree-2.3.1.tgz",
|
||||
"integrity": "sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"mdn-data": "2.0.30",
|
||||
"source-map-js": "^1.0.1"
|
||||
|
@ -1202,7 +1199,6 @@
|
|||
"version": "2.0.3",
|
||||
"resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz",
|
||||
"integrity": "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
|
@ -1337,7 +1333,6 @@
|
|||
"version": "3.0.3",
|
||||
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-3.0.3.tgz",
|
||||
"integrity": "sha512-7RUKfXgSMMkzt6ZuXmqapOurLGPPfgj6l9uRZ7lRGolvk0y2yocc35LdcxKC5PQZdn2DMqioAQ2NoWcrTKmm6g==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/estree": "^1.0.0"
|
||||
}
|
||||
|
@ -1501,6 +1496,11 @@
|
|||
"node": ">= 0.4"
|
||||
}
|
||||
},
|
||||
"node_modules/howler": {
|
||||
"version": "2.2.4",
|
||||
"resolved": "https://registry.npmjs.org/howler/-/howler-2.2.4.tgz",
|
||||
"integrity": "sha512-iARIBPgcQrwtEr+tALF+rapJ8qSc+Set2GJQl7xT1MQzWaVkFebdJhR3alVlSiUf5U7nAANKuj3aWpwerocD5w=="
|
||||
},
|
||||
"node_modules/import-fresh": {
|
||||
"version": "3.3.0",
|
||||
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz",
|
||||
|
@ -1611,7 +1611,6 @@
|
|||
"version": "3.0.2",
|
||||
"resolved": "https://registry.npmjs.org/is-reference/-/is-reference-3.0.2.tgz",
|
||||
"integrity": "sha512-v3rht/LgVcsdZa3O2Nqs+NMowLOxeOm7Ay9+/ARQ2F+qEoANRcqrjAZKGN0v8ymUetZGgkp26LTnGT7H0Qo9Pg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/estree": "*"
|
||||
}
|
||||
|
@ -1676,8 +1675,7 @@
|
|||
"node_modules/locate-character": {
|
||||
"version": "3.0.0",
|
||||
"resolved": "https://registry.npmjs.org/locate-character/-/locate-character-3.0.0.tgz",
|
||||
"integrity": "sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA==",
|
||||
"dev": true
|
||||
"integrity": "sha512-SW13ws7BjaeJ6p7Q6CO2nchbYEc3X3J6WrmTTDto7yMPqVSZTUyY5Tjbid+Ab8gLnATtygYtiDIJGQRRn2ZOiA=="
|
||||
},
|
||||
"node_modules/lru-cache": {
|
||||
"version": "10.2.0",
|
||||
|
@ -1692,7 +1690,6 @@
|
|||
"version": "0.30.7",
|
||||
"resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.7.tgz",
|
||||
"integrity": "sha512-8vBuFF/I/+OSLRmdf2wwFCJCz+nSn0m6DPvGH1fS/KiQoSaR+sETbov0eIk9KhEKy8CYqIkIAnbohxT/4H0kuA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@jridgewell/sourcemap-codec": "^1.4.15"
|
||||
},
|
||||
|
@ -1713,8 +1710,7 @@
|
|||
"node_modules/mdn-data": {
|
||||
"version": "2.0.30",
|
||||
"resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.0.30.tgz",
|
||||
"integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==",
|
||||
"dev": true
|
||||
"integrity": "sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA=="
|
||||
},
|
||||
"node_modules/merge2": {
|
||||
"version": "1.4.1",
|
||||
|
@ -1949,7 +1945,6 @@
|
|||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/periscopic/-/periscopic-3.1.0.tgz",
|
||||
"integrity": "sha512-vKiQ8RRtkl9P+r/+oefh25C3fhybptkHKCZSPlcXiJux2tJF55GnEj3BVn4A5gKfq9NWWXXrxkHBwVPUfH0opw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/estree": "^1.0.0",
|
||||
"estree-walker": "^3.0.0",
|
||||
|
@ -2409,7 +2404,6 @@
|
|||
"version": "1.0.2",
|
||||
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz",
|
||||
"integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
|
@ -2606,7 +2600,6 @@
|
|||
"version": "4.2.11",
|
||||
"resolved": "https://registry.npmjs.org/svelte/-/svelte-4.2.11.tgz",
|
||||
"integrity": "sha512-YIQk3J4X89wOLhjsqIW8tqY3JHPuBdtdOIkASP2PZeAMcSW9RsIjQzMesCrxOF3gdWYC0mKknlKF7OqmLM+Zqg==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@ampproject/remapping": "^2.2.1",
|
||||
"@jridgewell/sourcemap-codec": "^1.4.15",
|
||||
|
@ -2649,6 +2642,17 @@
|
|||
"svelte": "^3.55.0 || ^4.0.0-next.0 || ^4.0.0 || ^5.0.0-next.0"
|
||||
}
|
||||
},
|
||||
"node_modules/svelte-french-toast": {
|
||||
"version": "1.2.0",
|
||||
"resolved": "https://registry.npmjs.org/svelte-french-toast/-/svelte-french-toast-1.2.0.tgz",
|
||||
"integrity": "sha512-5PW+6RFX3xQPbR44CngYAP1Sd9oCq9P2FOox4FZffzJuZI2mHOB7q5gJBVnOiLF5y3moVGZ7u2bYt7+yPAgcEQ==",
|
||||
"dependencies": {
|
||||
"svelte-writable-derived": "^3.1.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"svelte": "^3.57.0 || ^4.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/svelte-hmr": {
|
||||
"version": "0.15.3",
|
||||
"resolved": "https://registry.npmjs.org/svelte-hmr/-/svelte-hmr-0.15.3.tgz",
|
||||
|
@ -2724,6 +2728,17 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
"node_modules/svelte-writable-derived": {
|
||||
"version": "3.1.0",
|
||||
"resolved": "https://registry.npmjs.org/svelte-writable-derived/-/svelte-writable-derived-3.1.0.tgz",
|
||||
"integrity": "sha512-cTvaVFNIJ036vSDIyPxJYivKC7ZLtcFOPm1Iq6qWBDo1fOHzfk6ZSbwaKrxhjgy52Rbl5IHzRcWgos6Zqn9/rg==",
|
||||
"funding": {
|
||||
"url": "https://ko-fi.com/pixievoltno1"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"svelte": "^3.2.1 || ^4.0.0-next.1"
|
||||
}
|
||||
},
|
||||
"node_modules/tailwindcss": {
|
||||
"version": "3.4.1",
|
||||
"resolved": "https://registry.npmjs.org/tailwindcss/-/tailwindcss-3.4.1.tgz",
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
"@sveltejs/adapter-static": "^3.0.1",
|
||||
"@sveltejs/vite-plugin-svelte": "^3.0.2",
|
||||
"@tsconfig/svelte": "^5.0.2",
|
||||
"@types/howler": "^2.2.11",
|
||||
"autoprefixer": "^10.4.17",
|
||||
"postcss": "^8.4.35",
|
||||
"svelte": "^4.2.11",
|
||||
|
@ -24,8 +25,10 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"@fontsource/roboto": "^5.0.8",
|
||||
"howler": "^2.2.4",
|
||||
"material-icons": "^1.13.12",
|
||||
"material-symbols": "^0.15.0",
|
||||
"socket.io-client": "^4.7.4"
|
||||
"socket.io-client": "^4.7.4",
|
||||
"svelte-french-toast": "^1.2.0"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
import { appList } from './lib/Apps/appList'
|
||||
import { initializeTelemetry } from './lib/utils/initializeTelemetry'
|
||||
import { onMount } from 'svelte'
|
||||
import { Toaster } from 'svelte-french-toast'
|
||||
import { initializationSequence } from './lib/Sequences/sequences'
|
||||
|
||||
let activeApp: App = 'camera'
|
||||
let topics: TelemetryTopics = {
|
||||
|
@ -27,6 +29,7 @@
|
|||
|
||||
onMount(() => {
|
||||
initializeTelemetry(topics, 200)
|
||||
initializationSequence()
|
||||
})
|
||||
</script>
|
||||
|
||||
|
@ -45,6 +48,9 @@
|
|||
<AppBar bind:activeApp {appList} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- toast service -->
|
||||
<Toaster />
|
||||
</main>
|
||||
|
||||
<style lang="postcss">
|
||||
|
|
13
client/src/globals.d.ts
vendored
13
client/src/globals.d.ts
vendored
|
@ -71,3 +71,16 @@ interface TelemetryTopics {
|
|||
strings: string[]
|
||||
booleans: string[]
|
||||
}
|
||||
|
||||
type ToastType = 'info' | 'success' | 'error'
|
||||
|
||||
type ToastData = {
|
||||
message: string
|
||||
type: ToastType
|
||||
timeout?: number
|
||||
}
|
||||
|
||||
declare module '@zerodevx/svelte-toast' {
|
||||
const value: any
|
||||
export = value
|
||||
}
|
||||
|
|
28
client/src/lib/Apps/AppContainer.svelte
Normal file
28
client/src/lib/Apps/AppContainer.svelte
Normal file
|
@ -0,0 +1,28 @@
|
|||
<!--
|
||||
@component
|
||||
|
||||
A utility component that wraps your app in a container and adds transitions
|
||||
|
||||
@param useContainer - Whether or not to use the default app container. Defaults to true.
|
||||
-->
|
||||
|
||||
<script lang="ts">
|
||||
import { fade } from 'svelte/transition'
|
||||
|
||||
export let useContainer: boolean = true
|
||||
</script>
|
||||
|
||||
<div
|
||||
in:fade={{ duration: 150, delay: 150 }}
|
||||
out:fade={{ duration: 150 }}
|
||||
class:app-container={useContainer}
|
||||
{...$$restProps}
|
||||
>
|
||||
<slot />
|
||||
</div>
|
||||
|
||||
<style lang="postcss">
|
||||
.app-container {
|
||||
@apply pb-20;
|
||||
}
|
||||
</style>
|
|
@ -1,12 +1,10 @@
|
|||
<script lang="ts">
|
||||
import AppContainer from '../AppContainer.svelte'
|
||||
import CameraContainer from './CameraContainer.svelte'
|
||||
import { fade } from 'svelte/transition'
|
||||
</script>
|
||||
|
||||
<div
|
||||
in:fade={{ duration: 150, delay: 150 }}
|
||||
out:fade={{ duration: 150 }}
|
||||
class="flex gap-4 w-full py-40 px-10 backdrop-blur-lg justify-center h-full rounded-3xl shadow-md bg-slate-300 bg-opacity-30"
|
||||
<AppContainer
|
||||
class="px-10 py-20 flex gap-4 w-full backdrop-blur-lg justify-center h-full rounded-3xl shadow-md bg-slate-300 bg-opacity-30"
|
||||
>
|
||||
<div class="my-auto">
|
||||
<CameraContainer cameraUrl="camera_url_here" />
|
||||
|
@ -14,4 +12,4 @@
|
|||
<div class="my-auto">
|
||||
<CameraContainer cameraUrl="camera_url_here" />
|
||||
</div>
|
||||
</div>
|
||||
</AppContainer>
|
||||
|
|
|
@ -6,17 +6,17 @@
|
|||
<script lang="ts">
|
||||
import Song from './Song.svelte'
|
||||
import { songList } from '../../Dashboard/MediaPlayer/songList'
|
||||
import { fade } from 'svelte/transition'
|
||||
import AppContainer from '../AppContainer.svelte'
|
||||
</script>
|
||||
|
||||
<div
|
||||
class="flex gap-4 w-full py-10 px-10 bg-blue-200 bg-opacity-25 backdrop-blur-xl h-full media-background rounded-3xl flex-wrap"
|
||||
in:fade={{ duration: 150, delay: 150 }}
|
||||
out:fade={{ duration: 150 }}
|
||||
<AppContainer
|
||||
class="flex gap-4 bg-blue-200 bg-opacity-25 backdrop-blur-xl media-background rounded-3xl flex-wrap px-10 py-20"
|
||||
>
|
||||
<h2 class="text-8xl font-bold basis-full text-slate-200">Music</h2>
|
||||
<h2 class="h-full w-full text-8xl font-bold basis-full text-slate-200">
|
||||
Music
|
||||
</h2>
|
||||
<div class="basis-full h-2" />
|
||||
{#each Object.entries(songList) as [slug, song]}
|
||||
<Song {song} {slug} />
|
||||
{/each}
|
||||
</div>
|
||||
</AppContainer>
|
||||
|
|
|
@ -30,7 +30,7 @@
|
|||
</script>
|
||||
|
||||
<div
|
||||
class="flex gap-1 flex-col rounded-lg p-4 bg-slate-800 backdrop-blur-xl shadow-md w-60 flex-grow basis-1/5"
|
||||
class="flex gap-1 flex-col rounded-lg p-4 bg-slate-800 backdrop-blur-xl bg-opacity-80 shadow-md w-60 flex-grow basis-1/5"
|
||||
>
|
||||
<img src={coverImg} alt="album cover" class="shadow-md rounded-lg w-full" />
|
||||
<p class="mt-2 text-2xl font-medium">{title}</p>
|
||||
|
|
22
client/src/lib/Apps/Settings/Settings.svelte
Normal file
22
client/src/lib/Apps/Settings/Settings.svelte
Normal file
|
@ -0,0 +1,22 @@
|
|||
<script lang="ts">
|
||||
import { Notifications } from '../../Notifications/notifications'
|
||||
import AppContainer from '../AppContainer.svelte'
|
||||
|
||||
const handleClick = () => {
|
||||
Notifications.error('Jankboard initialized', {
|
||||
src: '/static/voices/en/jankboard-initialized.wav',
|
||||
})
|
||||
Notifications.playAudio('static/voices/en/jankboard-initialized.wav')
|
||||
}
|
||||
</script>
|
||||
|
||||
<AppContainer
|
||||
class="flex gap-4 bg-blue-200 bg-opacity-25 backdrop-blur-xl media-background rounded-3xl flex-wrap px-10 py-20"
|
||||
>
|
||||
<button
|
||||
class="px-4 py-2 bg-blue-500 rounded-md hover:brightness-75"
|
||||
on:click={handleClick}
|
||||
>
|
||||
Test Toast
|
||||
</button>
|
||||
</AppContainer>
|
|
@ -1 +0,0 @@
|
|||
export const toastLibrary = {}
|
|
@ -1,5 +1,6 @@
|
|||
import Camera from './Camera/Camera.svelte'
|
||||
import MusicBrowser from './MusicBrowser/MusicBrowser.svelte'
|
||||
import Settings from './Settings/Settings.svelte'
|
||||
|
||||
export const appList = {
|
||||
'camera': {
|
||||
|
@ -12,4 +13,9 @@ export const appList = {
|
|||
component: MusicBrowser,
|
||||
icon: '/static/app-icons/media-player.png',
|
||||
},
|
||||
'settings': {
|
||||
name: 'Settings',
|
||||
component: Settings,
|
||||
icon: '/static/app-icons/settings.webp',
|
||||
},
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
<script lang="ts">
|
||||
import { getAcceleration, getDirection } from '../utils/helpers'
|
||||
import { mpss2knps } from '../utils/unitConversions'
|
||||
import { fade } from 'svelte/transition'
|
||||
|
||||
export let accx: number
|
||||
export let accy: number
|
||||
|
@ -19,20 +20,36 @@
|
|||
$: placeholder = accx === -999 && accy === -999
|
||||
</script>
|
||||
|
||||
<div class="flex flex-col gap-2 text-center transition-all">
|
||||
<div class="flex flex-col gap-2 text-center">
|
||||
<p class="text-xl font-medium">
|
||||
{#if !placeholder}
|
||||
Heading {getDirection(orientation)} ({orientation.toFixed(2)}°)
|
||||
<span
|
||||
in:fade={{ duration: 150, delay: 150 }}
|
||||
out:fade={{ duration: 150 }}
|
||||
class="text-lg font-medium"
|
||||
>Heading {getDirection(orientation)} ({orientation.toFixed(2)}°)</span
|
||||
>
|
||||
{:else}
|
||||
<span class="placeholder">--------------------------------</span>
|
||||
<span
|
||||
class="placeholder"
|
||||
in:fade={{ duration: 150, delay: 150 }}
|
||||
out:fade={{ duration: 150 }}>--------------------------------</span
|
||||
>
|
||||
{/if}
|
||||
</p>
|
||||
<p class="text-lg font-medium">
|
||||
{#if !placeholder}
|
||||
{getAcceleration(accResolved)} ({mpss2knps(accResolved).toFixed(2)}
|
||||
<span in:fade={{ duration: 150, delay: 150 }} out:fade={{ duration: 150 }}
|
||||
>{getAcceleration(accResolved)} ({mpss2knps(accResolved).toFixed(
|
||||
2
|
||||
)}</span
|
||||
>
|
||||
kn/s)
|
||||
{:else}
|
||||
<span class="placeholder"
|
||||
<span
|
||||
class="placeholder"
|
||||
in:fade={{ duration: 150, delay: 150 }}
|
||||
out:fade={{ duration: 150 }}
|
||||
>-----------------------------------------------------</span
|
||||
>
|
||||
{/if}
|
||||
|
|
|
@ -7,22 +7,28 @@
|
|||
-->
|
||||
<script lang="ts">
|
||||
export let speedLimit: number = 5.0
|
||||
|
||||
$: placeholder = speedLimit === -999
|
||||
</script>
|
||||
|
||||
<div
|
||||
class="bg-white p-[0.15rem] text-black rounded-xl shadow-md shadow-neutral-500"
|
||||
>
|
||||
<div
|
||||
class="px-3 py-1 border-black rounded-xl border-2 flex flex-col text-center gap-1"
|
||||
class:speed-limit-placeholder={speedLimit === -999}
|
||||
class="px-3 py-1 border-black rounded-xl border-2 flex flex-col text-center gap-1 transition-all"
|
||||
>
|
||||
<div class="text-lg font-medium">SPEED<br />LIMIT</div>
|
||||
<div class="text-2xl font-bold">{speedLimit}</div>
|
||||
<div
|
||||
class="text-2xl font-bold transition"
|
||||
class:speed-limit-placeholder={placeholder}
|
||||
>
|
||||
{speedLimit}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<style lang="postcss">
|
||||
.speed-limit-placeholder {
|
||||
@apply animate-pulse bg-neutral-300 text-neutral-300;
|
||||
@apply text-neutral-200 bg-neutral-200 animate-pulse rounded-lg;
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -17,11 +17,15 @@
|
|||
</script>
|
||||
|
||||
<div class="flex flex-col gap-4">
|
||||
<div class="text-6xl" class:placeholder class:width-limit={placeholder}>
|
||||
<div
|
||||
class="text-6xl transition"
|
||||
class:placeholder
|
||||
class:width-limit={placeholder}
|
||||
>
|
||||
{placeholder ? '-----' : formatted}
|
||||
</div>
|
||||
<div
|
||||
class="text-2xl font-medium"
|
||||
class="text-2xl font-medium transition"
|
||||
class:placeholder={speed === Math.hypot(-999, -999)}
|
||||
>
|
||||
MPH
|
||||
|
|
|
@ -7,11 +7,12 @@
|
|||
</script>
|
||||
|
||||
<span class="flex gap-1">
|
||||
<div class="text-lg font-medium" class:placeholder>
|
||||
<div class="text-lg font-medium transition" class:placeholder>
|
||||
{formatted} V
|
||||
</div>
|
||||
<span class="material-symbols-outlined battery-icon" class:placeholder
|
||||
>battery_horiz_075</span
|
||||
<span
|
||||
class="material-symbols-outlined battery-icon transition"
|
||||
class:placeholder>battery_horiz_075</span
|
||||
>
|
||||
</span>
|
||||
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
export let selectedGear: Gear | '-999'
|
||||
</script>
|
||||
|
||||
<div class="flex justify-center w-full">
|
||||
<div class="flex justify-center w-full transition">
|
||||
<div
|
||||
class="flex flex-row gap-2 text-neutral-400 text-xl font-bold"
|
||||
class:placeholder={selectedGear === '-999'}
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
Displays the drive mode
|
||||
-->
|
||||
<script lang="ts">
|
||||
import { fade } from 'svelte/transition'
|
||||
|
||||
export let selectedMode: Mode | '-999'
|
||||
|
||||
let modeText = ''
|
||||
|
@ -27,5 +29,5 @@
|
|||
</script>
|
||||
|
||||
<div class="font-medium text-xl">
|
||||
{modeText}
|
||||
<span>{modeText}</span>
|
||||
</div>
|
||||
|
|
10
client/src/lib/Notifications/InfoIcon.svelte
Normal file
10
client/src/lib/Notifications/InfoIcon.svelte
Normal file
|
@ -0,0 +1,10 @@
|
|||
<script lang="ts">
|
||||
export let size = '1.5rem'
|
||||
</script>
|
||||
|
||||
<span
|
||||
class="material-symbols-outlined text-slate-600"
|
||||
style="font-size: {size}"
|
||||
>
|
||||
info
|
||||
</span>
|
93
client/src/lib/Notifications/notifications.ts
Normal file
93
client/src/lib/Notifications/notifications.ts
Normal file
|
@ -0,0 +1,93 @@
|
|||
import { toast } from 'svelte-french-toast'
|
||||
import type { ToastOptions } from 'svelte-french-toast'
|
||||
import InfoIcon from './InfoIcon.svelte'
|
||||
import { Howl } from 'howler'
|
||||
|
||||
interface NotificationOptions extends ToastOptions {
|
||||
withAudio?: boolean
|
||||
src?: string
|
||||
}
|
||||
|
||||
// get colors from https://tailwindcss.com/docs/customizing-colors
|
||||
export class Notifications {
|
||||
private static readonly defaultDuration = 3000
|
||||
|
||||
public static success(message: string, options?: NotificationOptions) {
|
||||
if (options?.withAudio && !options.src)
|
||||
throw new Error('No audio source provided')
|
||||
|
||||
const sendToast = (duration: number) => {
|
||||
toast.success(message, {
|
||||
style:
|
||||
'padding: 25px; font-size: 1.5rem; background-color: #15803d; color: #fafafa;',
|
||||
duration,
|
||||
...options,
|
||||
})
|
||||
}
|
||||
|
||||
if (options?.withAudio && options?.src) {
|
||||
let sound: Howl
|
||||
sound = new Howl({
|
||||
src: [options.src],
|
||||
preload: true,
|
||||
autoplay: true,
|
||||
onload: () => sendToast(sound.duration() * 1000),
|
||||
})
|
||||
} else {
|
||||
sendToast(this.defaultDuration)
|
||||
}
|
||||
}
|
||||
public static error(message: string, options?: NotificationOptions) {
|
||||
if (options?.withAudio && !options.src)
|
||||
throw new Error('No audio source provided')
|
||||
|
||||
const sendToast = (duration: number) => {
|
||||
toast.error(message, {
|
||||
style:
|
||||
'padding: 25px; font-size: 1.5rem; background-color: #dc2626; color: #fafafa;',
|
||||
duration,
|
||||
...options,
|
||||
})
|
||||
}
|
||||
|
||||
if (options?.withAudio && options?.src) {
|
||||
let sound: Howl
|
||||
sound = new Howl({
|
||||
src: [options.src],
|
||||
preload: true,
|
||||
autoplay: true,
|
||||
onload: () => sendToast(sound.duration() * 1000),
|
||||
})
|
||||
} else {
|
||||
sendToast(this.defaultDuration)
|
||||
}
|
||||
}
|
||||
public static info(message: string, options?: any) {
|
||||
const sendToast = (duration: number) => {
|
||||
toast(message, {
|
||||
style: 'padding: 25px; font-size: 1.5rem;',
|
||||
icon: InfoIcon,
|
||||
duration,
|
||||
...options,
|
||||
})
|
||||
}
|
||||
if (options?.withAudio && options?.src) {
|
||||
let sound: Howl
|
||||
sound = new Howl({
|
||||
src: [options.src],
|
||||
preload: true,
|
||||
autoplay: true,
|
||||
onload: () => sendToast(sound.duration() * 1000),
|
||||
})
|
||||
} else {
|
||||
sendToast(this.defaultDuration)
|
||||
}
|
||||
}
|
||||
public static playAudio(src: string) {
|
||||
new Howl({
|
||||
src: [src],
|
||||
preload: true,
|
||||
autoplay: true,
|
||||
})
|
||||
}
|
||||
}
|
28
client/src/lib/Sequences/sequences.ts
Normal file
28
client/src/lib/Sequences/sequences.ts
Normal file
|
@ -0,0 +1,28 @@
|
|||
/*
|
||||
define various sequences to play out in this file
|
||||
for example, we can define an initialization sequence that
|
||||
plays out some series of notifications, and call it whenever we need it,
|
||||
or a sequence to change the screen color and play some audio queues for a crash
|
||||
*/
|
||||
|
||||
import { Notifications } from '../Notifications/notifications'
|
||||
import getVoicePath from '../utils/getVoicePath'
|
||||
|
||||
export const initializationSequence = () => {
|
||||
Notifications.info('Jankboard initialized!', {
|
||||
withAudio: true,
|
||||
src: getVoicePath('jankboard-initialized', 'en'),
|
||||
})
|
||||
setTimeout(() => {
|
||||
Notifications.success('LittenOS is online.', {
|
||||
withAudio: true,
|
||||
src: getVoicePath('littenos-is-online', 'en'),
|
||||
})
|
||||
setTimeout(() => {
|
||||
Notifications.error('Breaching Monte Vista codebase.', {
|
||||
withAudio: true,
|
||||
src: getVoicePath('breaching-monte-vista', 'en'),
|
||||
})
|
||||
}, 3000)
|
||||
}, 3000)
|
||||
}
|
11
client/src/lib/utils/getVoicePath.ts
Normal file
11
client/src/lib/utils/getVoicePath.ts
Normal file
|
@ -0,0 +1,11 @@
|
|||
/**
|
||||
* Retrieves the voice audio path for the given audio file.
|
||||
*
|
||||
* @param audio - the id of the voice audio file requested (see the readout)
|
||||
* @param lang - the language of the audio
|
||||
* @return the path of the audio file
|
||||
*/
|
||||
type SupportedLanguage = 'en' | 'rus'
|
||||
export default function getVoicePath(audio: string, lang: SupportedLanguage) {
|
||||
return `/static/voices/${lang}/${audio}.wav`
|
||||
}
|
|
@ -81,7 +81,6 @@ export const resolveAcceleration = (
|
|||
* @return The cardinal direction based on the input angle
|
||||
*/
|
||||
export const getDirection = (angle: number): CardinalDirection => {
|
||||
if (angle < 0 || angle > 360)
|
||||
if (angle < 22.5 || angle > 337.5) {
|
||||
return 'North'
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue