Compare commits

...

82 Commits

Author SHA1 Message Date
Uriel
439f60b89e New Pontoon translations (#1076) 2024-09-20 16:43:07 +02:00
Meow Wei
21f4468c00 Pontoon: Update Traditional Chinese (zh-Hant) localization of GUI
Co-authored-by: JaydenHa <jayden@jaydenha.uk>
Co-authored-by: Meow Wei <medicalwei@gmail.com>
2024-09-20 16:33:41 +02:00
VocalFan
00f46f01b1 Pontoon: Update Japanese (ja) localization of GUI
Co-authored-by: beq <beqbdean@gmail.com>
Co-authored-by: VocalFan <auronhines@gmail.com>
2024-09-20 16:33:41 +02:00
Iris
af8e6fc3f3 Pontoon: Update Finnish (fi) localization of GUI
Co-authored-by: Iris <vakotoneva@gmail.com>
2024-09-20 16:33:41 +02:00
VocalFan
28d4199f12 Pontoon: Update Czech (cs) localization of GUI
Co-authored-by: VocalFan <auronhines@gmail.com>
2024-09-20 16:33:41 +02:00
Flar
0c309da528 Pontoon: Update Russian (ru) localization of GUI
Co-authored-by: viberbread <panfilov.iva2015@yandex.ru>
Co-authored-by: VocalFan <auronhines@gmail.com>
Co-authored-by: SummerArtz <summerpzmail@gmail.com>
Co-authored-by: Flar <kani.dragonflar@gmail.com>
2024-09-20 16:33:41 +02:00
Renka
3c765dbd8a Pontoon: Update Spain Spanish (es-ES) localization of GUI
Co-authored-by: adriangoldenhero <adriangoldenhero@gmail.com>
Co-authored-by: Renka <lunastarletvr@gmail.com>
Co-authored-by: Uriel <urielfontan2002@gmail.com>
2024-09-20 16:33:41 +02:00
Uriel
eb9928ad08 Pontoon: Update Latinamerican Spanish (es-419) localization of GUI
Co-authored-by: Renka <lunastarletvr@gmail.com>
Co-authored-by: Uriel <urielfontan2002@gmail.com>
Co-authored-by: Alejandro <moctezumaalejandro25@gmail.com>
2024-09-20 16:33:41 +02:00
Mama-Gen
90dcf986f8 Pontoon: Update Brazilian Portuguese (pt-BR) localization of GUI
Co-authored-by: Mama-Gen <tiodapamonha145@gmail.com>
2024-09-20 16:33:41 +02:00
SebastianZ
eb602df452 Pontoon: Update German (de) localization of GUI
Co-authored-by: SebastianZ <sebastianzockt@gmail.com>
Co-authored-by: Piranja <info@hollihn.ch>
Co-authored-by: TheDevMinerTV <devminer@devminer.xyz>
Co-authored-by: unlogisch <unlogisch@gmx.ch>
2024-09-20 16:33:41 +02:00
michael091
e157fe7ed5 Pontoon: Update Polish (pl) localization of GUI
Co-authored-by: ReDoX <redox01@o2.pl>
Co-authored-by: michael091 <michael_m1@o2.pl>
Co-authored-by: stronzo <adam_skur@wp.pl>
Co-authored-by: MenacingExiler <menacingexiler@gmail.com>
Co-authored-by: Tailsy <tailsy13@gmail.com>
2024-09-20 16:33:41 +02:00
Vyolex
e3e48d3b0f Pontoon: Update Dutch (nl) localization of GUI
Co-authored-by: timovandegriend <timovandegriend@gmail.com>
Co-authored-by: SaabAerospace <SaabAerospace@hotmail.com>
Co-authored-by: Rat. <staf.dierickx@gmail.com>
Co-authored-by: Vyolex <25586367+Vyolex@users.noreply.github.com>
2024-09-20 16:33:41 +02:00
infopcgood
018056b728 Pontoon: Update Korean (ko) localization of GUI
Co-authored-by: infopcgood <sshs_student_412@outlook.kr>
Co-authored-by: Kamilake <exjang0@gmail.com>
2024-09-20 16:33:41 +02:00
MenacingExiler
d1b21f2f17 Pontoon: Update Vietnamese (vi) localization of GUI
Co-authored-by: MenacingExiler <menacingexiler@gmail.com>
2024-09-20 16:33:41 +02:00
beq
8eeaa62760 Pontoon: Update Engwish (en-x-owo) localization of GUI
Co-authored-by: Butterscotch! <bscotchvanilla@gmail.com>
Co-authored-by: beq <beqbdean@gmail.com>
Co-authored-by: infopcgood <sshs_student_412@outlook.kr>
Co-authored-by: Mini <alexanderawatson64@gmail.com>
2024-09-20 16:33:41 +02:00
namakeingo
564e99c52c Pontoon: Update Italian (it) localization of GUI
Co-authored-by: namakeingo <namakeingo@gmail.com>
Co-authored-by: Etch9 <mario.mazzara30@gmail.com>
2024-09-20 16:33:41 +02:00
VocalFan
b483699cf0 Pontoon: Update French (fr) localization of GUI
Co-authored-by: VocalFan <auronhines@gmail.com>
Co-authored-by: Erimel <loukalemire@gmail.com>
2024-09-20 16:33:34 +02:00
Uriel
7cea1c7b47 remove fastutil as it has weird behavior and its not used 2024-09-13 23:20:29 +02:00
Uriel
7c96ee89c1 Fix audio/video issues not playing on Linux (#1151) 2024-09-13 11:19:50 -03:00
Butterscotch!
1c867efe16 Fix tracker reset logic (#1150) 2024-09-13 02:41:56 +02:00
Uriel
2c146169ac Add scripts for checking licenses (#1099) 2024-08-28 16:51:11 +02:00
John Marshall
5c0d3e9932 Fix SlimeVR server from not working reliably on Quest standalone (#1141) 2024-08-28 15:19:15 +02:00
Uriel
456485071b Convert to WebP in mounting reset once again (#1146) 2024-08-21 19:32:32 -03:00
Uriel
e2d268df2d Update mounting reset image to a newer one (#1145) 2024-08-20 16:19:58 +02:00
dependabot[bot]
2beb449171 Bump gradle/actions from 3 to 4 (#1143)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-08-20 15:52:58 +02:00
dependabot[bot]
49865f8e2e Bump pnpm/action-setup from 3 to 4 (#1144)
Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2024-08-20 15:45:00 +02:00
Butterscotch!
25f7d8fe95 Add dependabot for GitHub Actions (#1137) 2024-08-20 09:17:16 -03:00
Uriel
62563ab1c2 remove discord log that includes user information (#1139) 2024-08-20 09:11:57 -03:00
Ondrej Hruska
9bec98f8f5 Add small top padding to show highlighting on tracker assignment page (#1138) 2024-08-20 13:29:19 +02:00
Ondrej Hruska
60f8db7079 show current direction on manual mounting (#1108)
Co-authored-by: Uriel <imurx@proton.me>
2024-08-14 00:20:49 +02:00
Uriel
b06f038777 Change automatic mounting pose image to new one (#1135) 2024-08-13 15:43:43 +02:00
Butterscotch!
1fba4e67ab Fix Android build & OSC support (#1133) 2024-08-12 22:44:06 -03:00
Erimel
1950a419a8 Reset upper chest tracker (#1134) 2024-08-12 22:31:58 -03:00
Uriel
9238c7211b Fix many GUI bugs found (#1129) 2024-08-07 19:03:18 -03:00
Butterscotch!
518fe8d2ef Fix skeleton issues (#1132) 2024-08-07 17:41:01 -03:00
Butterscotch!
8b97c0eb27 Change Android webserver port to 34536 (#1131) 2024-08-07 20:14:34 +02:00
Uriel
9bf7f1fa5c Fix git version script trimming wrong command (#1128) 2024-08-01 18:55:27 -03:00
Butterscotch!
4abd171efc Use default security attributes for named pipes (#1116) 2024-08-01 23:35:08 +02:00
Erimel
af4f9a96bf Computed head reset (#1057) 2024-08-01 00:05:34 -03:00
Erimel
58ca3fe8c1 OSCQuery support (#958)
Co-authored-by: Uriel <imurx@proton.me>
2024-07-31 18:01:38 +02:00
gale
0859abf08d Update flake nixpkgs revision (#1121) 2024-07-24 22:13:33 -03:00
Uriel
b32e1cad50 Add a way to save serial logs as a file (#1029) 2024-07-24 22:00:55 -03:00
Butterscotch!
c2566afa5e Update jSerialComm library (#1117) 2024-07-23 20:32:53 -03:00
VocalFan
7a9a23c3d4 Improvement on firewall batch scripts (#1030) 2024-07-23 20:27:16 -03:00
Uriel
76b29c4af6 Update to latest tauri again (#1097) 2024-07-19 20:38:51 -03:00
ShineBrightMeow
0be9b34320 Updated IMU Constants (#1100) 2024-07-12 17:38:04 +02:00
Ondrej Hruska
0b01a4d67a Issue#1079 - Add a background to the 3d preview skeleton (#1107) 2024-07-11 21:37:24 -03:00
Ondrej Hruska
c316313d2a Issue#1082 - The Exit Modals does not go on top of other (#1105) 2024-07-11 21:30:20 +03:00
Uriel
d8695d3e88 Add missing head tracker status (#962) 2024-07-11 17:50:18 +02:00
Ondrej Hruska
6e942780de Issue#1092 - White theme has correct manual mounting colors (#1103) 2024-07-11 05:02:05 +02:00
Erimel
0d9f9289fb Don't use neck length if head tracker doesn't have position (#1019) 2024-07-03 16:46:27 +02:00
Erimel
a6d0517a5b Fix VMC foot offset (#1020) 2024-07-03 16:37:07 +02:00
AxisAngles
708135ff4c Fix Quaternion biAlign (#1094) 2024-07-03 16:23:40 +02:00
JovannMC
1f434e1c88 Sync server constants with firmware (#1093) 2024-07-02 16:09:20 +02:00
lucas lelievre
7ab8435595 assignments enhancements (#1083)
Co-authored-by: Ondrej Hruska <11602729+ZycaR@users.noreply.github.com>
2024-06-26 16:39:46 +02:00
lucas lelievre
94aec1f4ba Remove useLayout (#1080) 2024-06-25 12:10:34 +02:00
Ondrej Hruska
6a268fbbad Issue#1066 - Show the current selected direction on the tracker mounting radial menu (#1077) 2024-06-18 11:15:01 -07:00
Ondrej Hruska
5ade5eb626 Issue#1074 - Icon of the body part in correct color (#1075) 2024-06-18 00:06:11 +02:00
Uriel
63384f40b5 Update to latest Tauri v2 (#1023) 2024-06-17 18:18:51 +02:00
Ondrej Hruska
d9da5544bb GUI - Tracker assignment options (#1009)
Co-authored-by: Erimel <marioluigivideo@gmail.com>
Co-authored-by: loucass003 <loucass003@gmail.com>
2024-06-17 08:45:06 -07:00
rcelyte
cfd9223390 Fix WebSocketVRBridge HMD (#1072) 2024-06-17 08:18:59 -07:00
Uriel
a135ca3459 Add Futura back to codeowners 2024-06-17 13:22:29 +02:00
Uriel
9bcccc6c36 Delete old resources from java (#984) 2024-06-17 13:02:48 +02:00
Uriel
00ef667c58 Add Discord Rich Presence support (#1027)
Co-authored-by: Erimel <marioluigivideo@gmail.com>
2024-06-14 18:32:00 +02:00
Uriel
fbb0b8a460 Override tauri config version with git tag (#994) 2024-06-14 17:55:09 +02:00
Zhenfu Shi
6626cabeaa macOS app naming improvements (#991) 2024-06-14 17:50:25 +02:00
nekomona
d23c92dec2 De-duplicate repeated HID packets (#1036) 2024-06-14 17:36:38 +02:00
Uriel
1356e7fbe6 Create tarball of GUI bundle on release (#1004) 2024-06-14 17:31:28 +02:00
Uriel
ec2909406b fix waitUntil failing with arrays and objects (#1028) 2024-06-14 17:21:16 +02:00
Uriel
37de960c1b Update how Linux bundling is done (#983) 2024-06-14 17:03:09 +02:00
Uriel
638d4e3fb1 Update metainfo to latest (#1024) 2024-06-14 15:40:39 +02:00
Uriel
a6f377992d Don't check for waist or hip on hasChest (#1031) 2024-06-14 14:51:27 +02:00
Uriel
27386d5b29 Use `Exit event instead of ExitRequested` (#1062) 2024-06-13 18:50:49 +02:00
Uriel
d67acf6c28 keep up with quality guidelines in Flathub (#1063) 2024-06-13 18:22:32 +02:00
Erimel
4471aaaa49 Add VMC toggle to mirror tracking (#1065) 2024-06-13 18:12:19 +02:00
Erimel
a3faad4a72 Update serial console description (#1064) 2024-06-13 17:13:55 +02:00
Uriel
4e4edc24da Add padding to tracker list on onboarding (#1058) 2024-06-13 16:20:36 +02:00
Collin
e64edb76dd Fix mocap mode breaking on startup (#1046) 2024-06-07 01:25:57 +03:00
Erimel
721a74aacc Fix VMC floating (#1039) 2024-06-06 01:25:01 +03:00
Erimel
775f5e9f30 Fix update button not redirecting to the installer directly on Windows (#1037) 2024-06-06 01:22:35 +03:00
VocalFan
6ca2eb6905 Begone Slimevr-ui.exe (#1018) 2024-06-06 01:21:47 +03:00
sctanf
9808ea8709 Use assigned vid/pid for HID tracker (#1044) 2024-05-31 12:31:10 -03:00
148 changed files with 9283 additions and 9298 deletions

8
.github/CODEOWNERS vendored
View File

@@ -2,12 +2,12 @@
* @Eirenliel
# Make everyone be able to approve SolarXR submodule changes
/solarxr-protocol @ButterscotchV @Erimelowo @ImUrX
/solarxr-protocol @ButterscotchV @Erimelowo @ImUrX @loucass003
# Make Loucas and Uriel the owners of all GUI stuff
/gui/ @ImUrX
/pnpm-lock.yaml @ImUrX
/pnpm-workspace.yaml @ImUrX
/gui/ @ImUrX @loucass003
/pnpm-lock.yaml @ImUrX @loucass003
/pnpm-workspace.yaml @ImUrX @loucass003
# Uriel and Erimel responsible for i18n
/gui/public/i18n/ @ImUrX @Erimelowo

8
.github/dependabot.yml vendored Normal file
View File

@@ -0,0 +1,8 @@
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
# Check for updates to GitHub Actions every week
interval: "weekly"

View File

@@ -25,7 +25,7 @@ jobs:
with:
submodules: recursive
- uses: pnpm/action-setup@v3
- uses: pnpm/action-setup@v4
- name: Use Node.js
uses: actions/setup-node@v4
with:
@@ -72,22 +72,18 @@ jobs:
with:
shared-key: "${{ matrix.os }}"
- uses: pnpm/action-setup@v3
- uses: pnpm/action-setup@v4
- name: Use Node.js
uses: actions/setup-node@v4
with:
node-version-file: '.node-version'
cache: 'pnpm'
# Tauri has a broken cache issue in windows, let's clean it for now
- name: Clean cache in Windows (Fixes tauri-apps/tauri#9045)
if: matrix.os == 'windows-latest'
run: cargo clean
- name: Build
shell: bash
run: |
pnpm i
pnpm run skipbundler
pnpm run skipbundler --config $( ./gui/scripts/gitversion.mjs )
- if: matrix.os == 'windows-latest'
name: Upload a Build Artifact (Windows)

View File

@@ -33,7 +33,7 @@ jobs:
distribution: "adopt"
- name: Setup Gradle
uses: gradle/actions/setup-gradle@v3
uses: gradle/actions/setup-gradle@v4
- run: mkdir ./gui/dist && touch ./gui/dist/somefile
shell: bash
@@ -63,7 +63,7 @@ jobs:
distribution: "adopt"
- name: Setup Gradle
uses: gradle/actions/setup-gradle@v3
uses: gradle/actions/setup-gradle@v4
- name: Build with Gradle
run: ./gradlew shadowJar
@@ -103,9 +103,9 @@ jobs:
distribution: "adopt"
- name: Setup Gradle
uses: gradle/actions/setup-gradle@v3
uses: gradle/actions/setup-gradle@v4
- uses: pnpm/action-setup@v3
- uses: pnpm/action-setup@v4
- name: Use Node.js
uses: actions/setup-node@v4
with:
@@ -173,7 +173,7 @@ jobs:
with:
shared-key: "ubuntu-22.04"
- uses: pnpm/action-setup@v3
- uses: pnpm/action-setup@v4
- name: Use Node.js
uses: actions/setup-node@v4
with:
@@ -183,38 +183,38 @@ jobs:
- name: Build
run: |
pnpm i
pnpm run tauri build
pnpm run tauri build --config $( ./gui/scripts/gitversion.mjs )
- name: Make GUI tarball
run: |
tar czf slimevr-gui-dist.tar.gz -C gui/dist/ .
- uses: actions/upload-artifact@v4
with:
name: SlimeVR-GUI-Dist
path: ./slimevr-gui-dist.tar.gz
- uses: actions/upload-artifact@v4
with:
name: SlimeVR-GUI-Deb
path: target/release/bundle/deb/slimevr*.deb
- name: Install appimage-builder
run: |
wget "https://github.com/AppImage/AppImageKit/releases/download/continuous/appimagetool-x86_64.AppImage"
chmod a+x appimagetool-x86_64.AppImage
sudo mv appimagetool-x86_64.AppImage /usr/local/bin/appimagetool
- name: Modify and Build AppImage
run: |
cd target/release/bundle/appimage
chmod a+x slimevr*.AppImage
./slimevr*.AppImage --appimage-extract
cp $( git rev-parse --show-toplevel )/server/desktop/build/libs/slimevr.jar squashfs-root/slimevr.jar
chmod 644 squashfs-root/slimevr.jar
appimagetool squashfs-root slimevr*.AppImage
- uses: actions/upload-artifact@v4
with:
name: SlimeVR-GUI-AppImage
path: target/release/bundle/appimage/slimevr*.AppImage
- uses: actions/upload-artifact@v4
with:
name: SlimeVR-GUI-RPM
path: target/release/bundle/rpm/slimevr*.rpm
- name: Prepare for release
if: startsWith(github.ref, 'refs/tags/')
run: |
cp target/release/bundle/appimage/slimevr*.AppImage ./SlimeVR-amd64.appimage
cp target/release/bundle/deb/slimevr*.deb ./SlimeVR-amd64.deb
cp target/release/bundle/rpm/slimevr*.rpm ./SlimeVR-amd64.rpm
- name: Upload to draft release
uses: softprops/action-gh-release@v2
@@ -223,8 +223,10 @@ jobs:
draft: true
generate_release_notes: true
files: |
./slimevr-gui-dist.tar.gz
./SlimeVR-amd64.appimage
./SlimeVR-amd64.deb
./SlimeVR-amd64.rpm
bundle-mac:
@@ -246,7 +248,7 @@ jobs:
with:
shared-key: "macos-latest"
- uses: pnpm/action-setup@v3
- uses: pnpm/action-setup@v4
- name: Use Node.js
uses: actions/setup-node@v4
with:
@@ -257,22 +259,27 @@ jobs:
run: |
rustup target add x86_64-apple-darwin
pnpm i
pnpm run tauri build --target universal-apple-darwin
pnpm run tauri build --target universal-apple-darwin --config $( ./gui/scripts/gitversion.mjs )
- name: Modify Application
run: |
cd target/universal-apple-darwin/release/bundle/macos/slimevr.app/Contents/MacOS
cp $( git rev-parse --show-toplevel )/server/desktop/build/libs/slimevr.jar ./
cd ../../../../dmg/
./bundle_dmg.sh --volname slimevr --icon slimevr 180 170 --app-drop-link 480 170 \
--window-size 660 400 --hide-extension ../macos/slimevr.app \
--volicon ../macos/slimevr.app/Contents/Resources/icon.icns --skip-jenkins \
--eula ../../../../LICENSE-MIT slimevr.dmg ../macos/slimevr.app
cd ../../../
/usr/libexec/PlistBuddy -c "Set :CFBundleDisplayName SlimeVR" slimevr.app/Contents/Info.plist
/usr/libexec/PlistBuddy -c "Set :CFBundleName SlimeVR" slimevr.app/Contents/Info.plist
codesign --sign - --deep --force slimevr.app
mv slimevr.app SlimeVR.app
cd ../dmg/
./bundle_dmg.sh --volname SlimeVR --icon slimevr 180 170 --app-drop-link 480 170 \
--window-size 660 400 --hide-extension ../macos/SlimeVR.app \
--volicon ../macos/SlimeVR.app/Contents/Resources/icon.icns --skip-jenkins \
--eula ../../../../LICENSE-MIT slimevr.dmg ../macos/SlimeVR.app
- uses: actions/upload-artifact@v4
with:
name: SlimeVR-GUI-MacApp
path: target/universal-apple-darwin/release/bundle/macos/slimevr*.app
path: target/universal-apple-darwin/release/bundle/macos/SlimeVR*.app
- uses: actions/upload-artifact@v4
with:
@@ -313,20 +320,18 @@ jobs:
with:
shared-key: "windows-latest"
- uses: pnpm/action-setup@v3
- uses: pnpm/action-setup@v4
- name: Use Node.js
uses: actions/setup-node@v4
with:
node-version-file: '.node-version'
cache: 'pnpm'
- name: Clean cache in Windows (Fixes tauri-apps/tauri#9045)
run: cargo clean
- name: Build
shell: bash
run: |
pnpm i
pnpm run skipbundler
pnpm run skipbundler --config $( ./gui/scripts/gitversion.mjs )
- name: Bundle to zips
shell: bash
@@ -338,9 +343,6 @@ jobs:
cp target/release/slimevr.exe ./SlimeVR/
7z a -tzip SlimeVR-win64.zip ./SlimeVR/
mv ./SlimeVR/slimevr.exe ./SlimeVR/slimevr-ui.exe
7z a -tzip SlimeVR.zip ./SlimeVR/
- uses: actions/upload-artifact@v4
with:
name: SlimeVR-GUI-Windows
@@ -352,6 +354,4 @@ jobs:
with:
draft: true
generate_release_notes: true
files: |
./SlimeVR-win64.zip
./SlimeVR.zip
files: ./SlimeVR-win64.zip

1
.gitignore vendored
View File

@@ -17,6 +17,7 @@
# VSCode stuff
/.vscode/settings.json
/.vscode/launch.json
# Ignore eclipse stuff
.project

1515
Cargo.lock generated

File diff suppressed because it is too large Load Diff

View File

@@ -9,7 +9,7 @@ members = ["gui/src-tauri"]
[workspace.package]
edition = "2021"
license = "MIT OR Apache-2.0"
rust-version = "1.75" # This version stabilized GATs and let-else
rust-version = "1.75" # Tauri's MSRV
repository = "https://github.com/SlimeVR/SlimeVR-Server"
[profile.release]

242
deny.toml Normal file
View File

@@ -0,0 +1,242 @@
# This template contains all of the possible sections and their default values
# Note that all fields that take a lint level have these possible values:
# * deny - An error will be produced and the check will fail
# * warn - A warning will be produced, but the check will not fail
# * allow - No warning or error will be produced, though in some cases a note
# will be
# The values provided in this template are the default values that will be used
# when any section or field is not specified in your own configuration
# Root options
# The graph table configures how the dependency graph is constructed and thus
# which crates the checks are performed against
[graph]
# If 1 or more target triples (and optionally, target_features) are specified,
# only the specified targets will be checked when running `cargo deny check`.
# This means, if a particular package is only ever used as a target specific
# dependency, such as, for example, the `nix` crate only being used via the
# `target_family = "unix"` configuration, that only having windows targets in
# this list would mean the nix crate, as well as any of its exclusive
# dependencies not shared by any other crates, would be ignored, as the target
# list here is effectively saying which targets you are building for.
targets = [
# The triple can be any string, but only the target triples built in to
# rustc (as of 1.40) can be checked against actual config expressions
#"x86_64-unknown-linux-musl",
# You can also specify which target_features you promise are enabled for a
# particular target. target_features are currently not validated against
# the actual valid features supported by the target architecture.
#{ triple = "wasm32-unknown-unknown", features = ["atomics"] },
]
# When creating the dependency graph used as the source of truth when checks are
# executed, this field can be used to prune crates from the graph, removing them
# from the view of cargo-deny. This is an extremely heavy hammer, as if a crate
# is pruned from the graph, all of its dependencies will also be pruned unless
# they are connected to another crate in the graph that hasn't been pruned,
# so it should be used with care. The identifiers are [Package ID Specifications]
# (https://doc.rust-lang.org/cargo/reference/pkgid-spec.html)
#exclude = []
# If true, metadata will be collected with `--all-features`. Note that this can't
# be toggled off if true, if you want to conditionally enable `--all-features` it
# is recommended to pass `--all-features` on the cmd line instead
all-features = false
# If true, metadata will be collected with `--no-default-features`. The same
# caveat with `all-features` applies
no-default-features = false
# If set, these feature will be enabled when collecting metadata. If `--features`
# is specified on the cmd line they will take precedence over this option.
#features = []
# The output table provides options for how/if diagnostics are outputted
[output]
# When outputting inclusion graphs in diagnostics that include features, this
# option can be used to specify the depth at which feature edges will be added.
# This option is included since the graphs can be quite large and the addition
# of features from the crate(s) to all of the graph roots can be far too verbose.
# This option can be overridden via `--feature-depth` on the cmd line
feature-depth = 1
# This section is considered when running `cargo deny check advisories`
# More documentation for the advisories section can be found here:
# https://embarkstudios.github.io/cargo-deny/checks/advisories/cfg.html
[advisories]
# The path where the advisory databases are cloned/fetched into
#db-path = "$CARGO_HOME/advisory-dbs"
# The url(s) of the advisory databases to use
#db-urls = ["https://github.com/rustsec/advisory-db"]
# A list of advisory IDs to ignore. Note that ignored advisories will still
# output a note when they are encountered.
ignore = [
#"RUSTSEC-0000-0000",
#{ id = "RUSTSEC-0000-0000", reason = "you can specify a reason the advisory is ignored" },
#"a-crate-that-is-yanked@0.1.1", # you can also ignore yanked crate versions if you wish
#{ crate = "a-crate-that-is-yanked@0.1.1", reason = "you can specify why you are ignoring the yanked crate" },
]
# If this is true, then cargo deny will use the git executable to fetch advisory database.
# If this is false, then it uses a built-in git library.
# Setting this to true can be helpful if you have special authentication requirements that cargo-deny does not support.
# See Git Authentication for more information about setting up git authentication.
#git-fetch-with-cli = true
# This section is considered when running `cargo deny check licenses`
# More documentation for the licenses section can be found here:
# https://embarkstudios.github.io/cargo-deny/checks/licenses/cfg.html
[licenses]
# List of explicitly allowed licenses
# See https://spdx.org/licenses/ for list of possible licenses
# [possible values: any SPDX 3.11 short identifier (+ optional exception)].
allow = [
"MIT",
"Apache-2.0",
"Apache-2.0 WITH LLVM-exception",
"Unicode-3.0",
"Unicode-DFS-2016",
"MIT-0",
"ISC",
"BSD-3-Clause",
"Zlib",
"MPL-2.0",
]
# The confidence threshold for detecting a license from license text.
# The higher the value, the more closely the license text must be to the
# canonical license text of a valid SPDX license file.
# [possible values: any between 0.0 and 1.0].
confidence-threshold = 0.8
# Allow 1 or more licenses on a per-crate basis, so that particular licenses
# aren't accepted for every possible crate as with the normal allow list
exceptions = [
# Each entry is the crate and version constraint, and its specific allow
# list
#{ allow = ["Zlib"], crate = "adler32" },
]
# Some crates don't have (easily) machine readable licensing information,
# adding a clarification entry for it allows you to manually specify the
# licensing information
#[[licenses.clarify]]
# The package spec the clarification applies to
#crate = "ring"
# The SPDX expression for the license requirements of the crate
#expression = "MIT AND ISC AND OpenSSL"
# One or more files in the crate's source used as the "source of truth" for
# the license expression. If the contents match, the clarification will be used
# when running the license check, otherwise the clarification will be ignored
# and the crate will be checked normally, which may produce warnings or errors
# depending on the rest of your configuration
#license-files = [
# Each entry is a crate relative path, and the (opaque) hash of its contents
#{ path = "LICENSE", hash = 0xbd0eed23 }
#]
[licenses.private]
# If true, ignores workspace crates that aren't published, or are only
# published to private registries.
# To see how to mark a crate as unpublished (to the official registry),
# visit https://doc.rust-lang.org/cargo/reference/manifest.html#the-publish-field.
ignore = false
# One or more private registries that you might publish crates to, if a crate
# is only published to private registries, and ignore is true, the crate will
# not have its license(s) checked
registries = [
#"https://sekretz.com/registry
]
# This section is considered when running `cargo deny check bans`.
# More documentation about the 'bans' section can be found here:
# https://embarkstudios.github.io/cargo-deny/checks/bans/cfg.html
[bans]
# Lint level for when multiple versions of the same crate are detected
multiple-versions = "warn"
# Lint level for when a crate version requirement is `*`
wildcards = "allow"
# The graph highlighting used when creating dotgraphs for crates
# with multiple versions
# * lowest-version - The path to the lowest versioned duplicate is highlighted
# * simplest-path - The path to the version with the fewest edges is highlighted
# * all - Both lowest-version and simplest-path are used
highlight = "all"
# The default lint level for `default` features for crates that are members of
# the workspace that is being checked. This can be overridden by allowing/denying
# `default` on a crate-by-crate basis if desired.
workspace-default-features = "allow"
# The default lint level for `default` features for external crates that are not
# members of the workspace. This can be overridden by allowing/denying `default`
# on a crate-by-crate basis if desired.
external-default-features = "allow"
# List of crates that are allowed. Use with care!
allow = [
#"ansi_term@0.11.0",
#{ crate = "ansi_term@0.11.0", reason = "you can specify a reason it is allowed" },
]
# List of crates to deny
deny = [
#"ansi_term@0.11.0",
#{ crate = "ansi_term@0.11.0", reason = "you can specify a reason it is banned" },
# Wrapper crates can optionally be specified to allow the crate when it
# is a direct dependency of the otherwise banned crate
#{ crate = "ansi_term@0.11.0", wrappers = ["this-crate-directly-depends-on-ansi_term"] },
]
# List of features to allow/deny
# Each entry the name of a crate and a version range. If version is
# not specified, all versions will be matched.
#[[bans.features]]
#crate = "reqwest"
# Features to not allow
#deny = ["json"]
# Features to allow
#allow = [
# "rustls",
# "__rustls",
# "__tls",
# "hyper-rustls",
# "rustls",
# "rustls-pemfile",
# "rustls-tls-webpki-roots",
# "tokio-rustls",
# "webpki-roots",
#]
# If true, the allowed features must exactly match the enabled feature set. If
# this is set there is no point setting `deny`
#exact = true
# Certain crates/versions that will be skipped when doing duplicate detection.
skip = [
#"ansi_term@0.11.0",
#{ crate = "ansi_term@0.11.0", reason = "you can specify a reason why it can't be updated/removed" },
]
# Similarly to `skip` allows you to skip certain crates during duplicate
# detection. Unlike skip, it also includes the entire tree of transitive
# dependencies starting at the specified crate, up to a certain depth, which is
# by default infinite.
skip-tree = [
#"ansi_term@0.11.0", # will be skipped along with _all_ of its direct and transitive dependencies
#{ crate = "ansi_term@0.11.0", depth = 20 },
]
# This section is considered when running `cargo deny check sources`.
# More documentation about the 'sources' section can be found here:
# https://embarkstudios.github.io/cargo-deny/checks/sources/cfg.html
[sources]
# Lint level for what to happen when a crate from a crate registry that is not
# in the allow list is encountered
unknown-registry = "warn"
# Lint level for what to happen when a crate from a git repository that is not
# in the allow list is encountered
unknown-git = "warn"
# List of URLs for allowed crate registries. Defaults to the crates.io index
# if not specified. If it is specified but empty, no registries are allowed.
allow-registry = ["https://github.com/rust-lang/crates.io-index"]
# List of URLs for allowed Git repositories
allow-git = []
[sources.allow-org]
# 1 or more github.com organizations to allow git sources for
github = [""]
# 1 or more gitlab.com organizations to allow git sources for
gitlab = [""]
# 1 or more bitbucket.org organizations to allow git sources for
bitbucket = [""]

View File

@@ -13,7 +13,7 @@ work. If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
<id>dev.slimevr.SlimeVR</id>
<name>SlimeVR</name>
<summary>An app for facilitating full-body tracking in virtual reality</summary>
<summary>Accessible full-body tracking in VR</summary>
<developer_name>SlimeVR Team</developer_name>
<!-- CC0 so attribution is not required -->
@@ -40,7 +40,8 @@ work. If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
</supports>
<branding>
<color type="primary">#663499</color>
<color type="primary" scheme_preference="light">#BB8AE5</color>
<color type="primary" scheme_preference="dark">#663499</color>
</branding>
<description>
@@ -53,7 +54,7 @@ work. If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
<launchable type="desktop-id">dev.slimevr.SlimeVR.desktop</launchable>
<screenshots>
<screenshot type="default">
<screenshot type="default" xml:lang="en">
<caption>The onboarding for the GUI</caption>
<image>https://raw.githubusercontent.com/SlimeVR/SlimeVR-Server/main/assets/img/onboarding.png</image>
</screenshot>
@@ -64,6 +65,12 @@ work. If not, see <http://creativecommons.org/publicdomain/zero/1.0/>.
</provides>
<releases>
<release version="0.12.1" date="2024-04-29"><url>https://github.com/SlimeVR/SlimeVR-Server/releases/tag/v0.12.1</url></release>
<release version="0.12.0" date="2024-04-26"><url>https://github.com/SlimeVR/SlimeVR-Server/releases/tag/v0.12.0</url></release>
<release version="0.12.0~rc.4" type="development" date="2024-04-21"><url>https://github.com/SlimeVR/SlimeVR-Server/releases/tag/v0.12.0-rc.4</url></release>
<release version="0.12.0~rc.3" type="development" date="2024-04-14"><url>https://github.com/SlimeVR/SlimeVR-Server/releases/tag/v0.12.0-rc.3</url></release>
<release version="0.12.0~rc.2" type="development" date="2024-04-09"><url>https://github.com/SlimeVR/SlimeVR-Server/releases/tag/v0.12.0-rc.2</url></release>
<release version="0.12.0~rc.1" type="development" date="2024-04-04"><url>https://github.com/SlimeVR/SlimeVR-Server/releases/tag/v0.12.0-rc.1</url></release>
<release version="0.11.0" date="2023-12-23"><url>https://github.com/SlimeVR/SlimeVR-Server/releases/tag/v0.11.0</url></release>
<release version="0.11.0~rc.2" type="development" date="2023-12-08"><url>https://github.com/SlimeVR/SlimeVR-Server/releases/tag/v0.11.0-rc.2</url></release>
<release version="0.11.0~rc.1" type="development" date="2023-11-23"><url>https://github.com/SlimeVR/SlimeVR-Server/releases/tag/v0.11.0-rc.1</url></release>

47
flake.lock generated
View File

@@ -23,7 +23,9 @@
},
"fenix": {
"inputs": {
"nixpkgs": "nixpkgs_2",
"nixpkgs": [
"nixpkgs"
],
"rust-analyzer-src": "rust-analyzer-src"
},
"locked": {
@@ -225,7 +227,9 @@
"nixgl": {
"inputs": {
"flake-utils": "flake-utils_3",
"nixpkgs": "nixpkgs_3"
"nixpkgs": [
"nixpkgs"
]
},
"locked": {
"lastModified": 1685908677,
@@ -309,42 +313,11 @@
},
"nixpkgs_2": {
"locked": {
"lastModified": 1699099776,
"narHash": "sha256-X09iKJ27mGsGambGfkKzqvw5esP1L/Rf8H3u3fCqIiU=",
"owner": "nixos",
"repo": "nixpkgs",
"rev": "85f1ba3e51676fa8cc604a3d863d729026a6b8eb",
"type": "github"
},
"original": {
"owner": "nixos",
"ref": "nixos-unstable",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs_3": {
"locked": {
"lastModified": 1660551188,
"narHash": "sha256-a1LARMMYQ8DPx1BgoI/UN4bXe12hhZkCNqdxNi6uS0g=",
"owner": "nixos",
"repo": "nixpkgs",
"rev": "441dc5d512153039f19ef198e662e4f3dbb9fd65",
"type": "github"
},
"original": {
"owner": "nixos",
"repo": "nixpkgs",
"type": "github"
}
},
"nixpkgs_4": {
"locked": {
"lastModified": 1699099776,
"narHash": "sha256-X09iKJ27mGsGambGfkKzqvw5esP1L/Rf8H3u3fCqIiU=",
"lastModified": 1721562059,
"narHash": "sha256-Tybxt65eyOARf285hMHIJ2uul8SULjFZbT9ZaEeUnP8=",
"owner": "NixOS",
"repo": "nixpkgs",
"rev": "85f1ba3e51676fa8cc604a3d863d729026a6b8eb",
"rev": "68c9ed8bbed9dfce253cc91560bf9043297ef2fe",
"type": "github"
},
"original": {
@@ -390,7 +363,7 @@
"mk-shell-bin": "mk-shell-bin",
"nix2container": "nix2container",
"nixgl": "nixgl",
"nixpkgs": "nixpkgs_4"
"nixpkgs": "nixpkgs_2"
}
},
"rust-analyzer-src": {

View File

@@ -4,11 +4,19 @@
inputs = {
nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
devenv.url = "github:cachix/devenv";
nix2container.url = "github:nlewo/nix2container";
nix2container.inputs.nixpkgs.follows = "nixpkgs";
nix2container = {
url = "github:nlewo/nix2container";
inputs.nixpkgs.follows = "nixpkgs";
};
mk-shell-bin.url = "github:rrbutani/nix-mk-shell-bin";
nixgl.url = "github:guibou/nixGL";
fenix.url = "github:nix-community/fenix";
nixgl = {
url = "github:guibou/nixGL";
inputs.nixpkgs.follows = "nixpkgs";
};
fenix = {
url = "github:nix-community/fenix";
inputs.nixpkgs.follows = "nixpkgs";
};
};
nixConfig = {
@@ -81,7 +89,7 @@
harfbuzz
libffi
libsoup_3
openssl.out
openssl
pango
pkg-config
treefmt
@@ -96,7 +104,6 @@
expat
libayatana-appindicator
libusb1
libudev-zero
])
++ lib.optionals pkgs.stdenv.isDarwin [
pkgs.darwin.apple_sdk.frameworks.Security
@@ -118,7 +125,7 @@
enable = true;
toolchain = fenixpkgs.fromToolchainName {
name = rust_toolchain.toolchain.channel;
sha256 = "sha256-3St/9/UKo/6lz2Kfq2VmlzHyufduALpiIKaaKX4Pq0g=";
sha256 = "sha256-Ngiz76YP4HTY75GGdH2P+APE/DEIx2R/Dn+BwwOyzZU=";
};
components = rust_toolchain.toolchain.components;
};
@@ -128,6 +135,11 @@
};
enterShell = with pkgs; ''
# Export a LD_LIBRARY_PATH without libudev-zero as libgudev not likey
export SLIMEVR_RUST_LD_LIBRARY_PATH="$LD_LIBRARY_PATH"
export LD_LIBRARY_PATH="${libudev-zero}/lib:$LD_LIBRARY_PATH"
# GStreamer plugins won't be found without this
export GST_PLUGIN_SYSTEM_PATH_1_0="${pkgs.gst_all_1.gstreamer.out}/lib/gstreamer-1.0:${pkgs.gst_all_1.gst-plugins-base}/lib/gstreamer-1.0:${pkgs.gst_all_1.gst-plugins-good}/lib/gstreamer-1.0:${pkgs.gst_all_1.gst-plugins-bad}/lib/gstreamer-1.0"
'';
};
};

View File

@@ -5,43 +5,35 @@
"dependencies": {
"@fluent/bundle": "^0.18.0",
"@fluent/react": "^0.15.2",
"@fontsource/poppins": "^5.0.12",
"@fontsource/poppins": "^5.0.14",
"@formatjs/intl-localematcher": "^0.2.32",
"@react-three/drei": "^9.105.1",
"@react-three/fiber": "^8.16.1",
"@tauri-apps/api": "=2.0.0-beta.7",
"@tauri-apps/plugin-dialog": "=2.0.0-beta.2",
"@tauri-apps/plugin-fs": "=2.0.0-beta.2",
"@tauri-apps/plugin-os": "=2.0.0-beta.2",
"@tauri-apps/plugin-shell": "=2.0.0-beta.2",
"@tauri-apps/plugin-store": "=2.0.0-beta.2",
"@vitejs/plugin-react": "^4.2.1",
"@react-three/drei": "^9.107.0",
"@react-three/fiber": "^8.16.8",
"@tauri-apps/api": "2.0.0-beta.14",
"@tauri-apps/plugin-dialog": "2.0.0-beta.6",
"@tauri-apps/plugin-fs": "2.0.0-beta.6",
"@tauri-apps/plugin-os": "2.0.0-beta.6",
"@tauri-apps/plugin-shell": "2.0.0-beta.7",
"@tauri-apps/plugin-store": "2.0.0-beta.6",
"browser-fs-access": "^0.35.0",
"browserslist": "^4.23.0",
"classnames": "^2.5.1",
"eslint-config-react-app": "^7.0.1",
"flatbuffers": "^22.10.26",
"identity-obj-proxy": "^3.0.0",
"flatbuffers": "22.10.26",
"intl-pluralrules": "^2.0.1",
"ip-num": "^1.5.1",
"postcss-flexbugs-fixes": "^5.0.2",
"postcss-normalize": "^10.0.1",
"postcss-preset-env": "^9.5.2",
"prompts": "^2.4.2",
"react": "^18.2.0",
"react-dev-utils": "^12.0.1",
"react-dom": "^18.2.0",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-error-boundary": "^4.0.13",
"react-helmet": "^6.1.0",
"react-hook-form": "^7.51.0",
"react-hook-form": "^7.52.0",
"react-modal": "^3.16.1",
"react-responsive": "^10.0.0",
"react-router-dom": "^6.22.3",
"semver": "^7.6.0",
"react-router-dom": "^6.23.1",
"semver": "^7.6.2",
"solarxr-protocol": "file:../solarxr-protocol",
"three": "^0.163.0",
"ts-pattern": "^5.0.8",
"typescript": "^5.4.3"
"ts-pattern": "^5.2.0",
"typescript": "^5.4.5"
},
"scripts": {
"start": "vite --force",
@@ -49,42 +41,26 @@
"dev": "tauri dev",
"skipbundler": "tauri build --no-bundle",
"tauri": "tauri",
"lint": "tsc --noEmit && eslint --max-warnings=0 \"src/**/*.{js,jsx,ts,tsx,json}\" && prettier --check \"src/**/*.{js,jsx,ts,tsx,css,md,json}\"",
"lint": "tsc --noEmit && eslint --max-warnings=0 \"src/**/*.{js,jsx,ts,tsx,json}\" && prettier --check \"src/**/*.{js,jsx,ts,tsx,css,scss,md,json}\"",
"lint:fix": "tsc --noEmit && eslint --fix --max-warnings=0 \"src/**/*.{js,jsx,ts,tsx,json}\" && pnpm run format",
"format": "prettier --write \"src/**/*.{js,jsx,ts,tsx,css,md,json}\"",
"format": "prettier --write \"src/**/*.{js,jsx,ts,tsx,css,scss,md,json}\"",
"preview-vite": "vite preview",
"javaversion-build": "cd src-tauri/src/ && javac JavaVersion.java && jar cvfe JavaVersion.jar JavaVersion JavaVersion.class"
},
"eslintConfig": {
"extends": [
"react-app"
]
},
"browserslist": {
"production": [
">0.2%",
"not dead",
"not op_mini all"
],
"development": [
"last 1 chrome version",
"last 1 firefox version",
"last 1 safari version"
]
},
"devDependencies": {
"@dword-design/eslint-plugin-import-alias": "^4.0.9",
"@tailwindcss/forms": "^0.5.7",
"@tauri-apps/cli": "=2.0.0-beta.12",
"@tauri-apps/cli": "2.0.0-beta.21",
"@types/file-saver": "^2.0.7",
"@types/react": "^18.2.73",
"@types/react-dom": "^18.2.23",
"@types/react": "^18.3.3",
"@types/react-dom": "^18.3.0",
"@types/react-helmet": "^6.1.11",
"@types/react-modal": "3.16.3",
"@types/semver": "^7.5.8",
"@types/three": "^0.163.0",
"@typescript-eslint/eslint-plugin": "^7.4.0",
"@typescript-eslint/parser": "^7.4.0",
"@typescript-eslint/eslint-plugin": "^7.13.0",
"@typescript-eslint/parser": "^7.13.0",
"@vitejs/plugin-react": "^4.3.1",
"autoprefixer": "^10.4.19",
"cross-env": "^7.0.3",
"eslint": "^8.57.0",
@@ -92,14 +68,14 @@
"eslint-import-resolver-typescript": "^3.6.1",
"eslint-plugin-import": "^2.29.1",
"eslint-plugin-jsx-a11y": "^6.8.0",
"eslint-plugin-react": "^7.34.1",
"eslint-plugin-react-hooks": "^4.6.0",
"postcss": "^8.4.38",
"prettier": "^3.2.5",
"pretty-quick": "^4.0.0",
"eslint-plugin-react": "^7.34.2",
"eslint-plugin-react-hooks": "^4.6.2",
"prettier": "^3.3.2",
"rollup-plugin-visualizer": "^5.12.0",
"sass": "^1.77.5",
"spdx-satisfies": "^5.0.1",
"tailwind-gradient-mask-image": "^1.2.0",
"tailwindcss": "^3.4.3",
"vite": "^5.2.7"
"tailwindcss": "^3.4.4",
"vite": "^5.3.1"
}
}

View File

@@ -244,7 +244,7 @@ body_assignment_menu-unassign_tracker = Zrušit přiřazení trackeru
-tracker_selection-part = { "Který tracker přiřadit k" }
tracker_selection_menu-NONE = Který tracker chcete aby byl nezařazený?
tracker_selection_menu-HEAD = { -tracker_selection-part } hlavě?
tracker_selection_menu-NECK = Který tracker přiřadit ke krku?
tracker_selection_menu-NECK = { -tracker_selection-part } krku?
tracker_selection_menu-RIGHT_SHOULDER = { -tracker_selection-part } pravému rameni?
tracker_selection_menu-RIGHT_UPPER_ARM = { -tracker_selection-part } pravýmu nadloktí?
tracker_selection_menu-RIGHT_LOWER_ARM = { -tracker_selection-part } pravýmu podloktí?
@@ -256,7 +256,7 @@ tracker_selection_menu-RIGHT_CONTROLLER = { -tracker_selection-part } pravému o
tracker_selection_menu-UPPER_CHEST = { -tracker_selection-part } k horní část hrudníku?
tracker_selection_menu-CHEST = { -tracker_selection-part } hrudníku?
tracker_selection_menu-WAIST = { -tracker_selection-part } pasu?
tracker_selection_menu-HIP = Který tracker přiřadit ke kyčli?
tracker_selection_menu-HIP = { -tracker_selection-part } kyčle?
tracker_selection_menu-LEFT_SHOULDER = { -tracker_selection-part } levému rameni?
tracker_selection_menu-LEFT_UPPER_ARM = { -tracker_selection-part } levýmu nadloktí?
tracker_selection_menu-LEFT_LOWER_ARM = { -tracker_selection-part } levýmu podloktí?
@@ -492,15 +492,10 @@ settings-osc-router-network-address-placeholder = Adresa IPV4
## OSC VRChat settings
settings-osc-vrchat = Trackery VRChat OSC
# This cares about multilines
settings-osc-vrchat-description =
Úprava nastavení specifických pro VRChat pro příjem dat HMD a odesílání
data trackerů pro FBT (funguje na samostatném Questu).
settings-osc-vrchat-enable = Zapnout
settings-osc-vrchat-enable-description = Vypnutí a zapnutí odesílání a přijímání dat.
settings-osc-vrchat-enable-label = Zapnout
settings-osc-vrchat-network = Síťové porty
settings-osc-vrchat-network-description = Nastavení portů pro naslouchání a odesílání dat do VRChat.
settings-osc-vrchat-network-port_in =
.label = Vstup portu
.placeholder = Vstup portu (výchozí: 9001)
@@ -508,7 +503,6 @@ settings-osc-vrchat-network-port_out =
.label = Výstup portu
.placeholder = Výstup portu (výchozí: 9000)
settings-osc-vrchat-network-address = Síťová adresa
settings-osc-vrchat-network-address-description = Zvolte adresu, ze které se mají odesílat data na VRChat (zkontrolujte nastavení Wi-Fi v zařízení).
settings-osc-vrchat-network-address-placeholder = VRChat ip adresa
settings-osc-vrchat-network-trackers = Trackery
settings-osc-vrchat-network-trackers-description = Vypnuti a zapnutí odesílání konkrétních trackerů přes OSC.
@@ -702,12 +696,8 @@ onboarding-choose_mounting = Jakou metodu nasazení trackerů použít?
# Multiline text
onboarding-choose_mounting-description = Správná orientace nasazení zajistí přesné sledování trackerů na těle.
onboarding-choose_mounting-auto_mounting = Automatická detekce nasazení
# Italized text
onboarding-choose_mounting-auto_mounting-label = Experimentální
onboarding-choose_mounting-auto_mounting-description = Orientace nasazení všech trackerů bude automaticky rozpoznána ze 2 pozic.
onboarding-choose_mounting-manual_mounting = Manuální nastavení
# Italized text
onboarding-choose_mounting-manual_mounting-label = Doporučeno
onboarding-choose_mounting-manual_mounting-description = Ručně zadejte orientaci nasazení každého trackeru.
# Multiline text
onboarding-choose_mounting-manual_modal-title =

View File

@@ -13,7 +13,7 @@ websocket-connection_lost = Verbindung zum Server verloren. Versuche Verbindung
## Update notification
version_update-title = Neue Version verfügbar: { $version }
version_update-description = Wenn Sie auf "Aktualisieren" klicken, wird der SlimeVR-Installationsassistent für dich heruntergeladen.
version_update-description = Wenn Sie auf "{ version_update-update }" klicken, wird das SlimeVR-Installationsprogramm heruntergeladen.
version_update-update = Aktualisieren
version_update-close = Schließen
@@ -383,6 +383,9 @@ settings-general-fk_settings-leg_fk-reset_mounting_feet = Fußausrichtung zurüc
settings-general-fk_settings-arm_fk = Arm-Tracking
settings-general-fk_settings-arm_fk-description = Ändern Sie die Art und Weise, wie die Arme berechnet werden.
settings-general-fk_settings-arm_fk-force_arms = Arme vom VR-Headset erzwingen
settings-general-fk_settings-reset_settings = Einstellungen zurücksetzen
settings-general-fk_settings-reset_settings-reset_hmd_pitch-description = Setzen Sie die Neigung (vertikale Drehung) Ihres Headsets zurück, wenn Sie einen vollständigen Reset durchführen. Nützlich, wenn Sie ein Headset auf der Stirn für VTubing oder Mocap tragen. Nicht für VR aktivieren.
settings-general-fk_settings-reset_settings-reset_hmd_pitch = Headset-Nick (vertikale Drehung) zurücksetzen
settings-general-fk_settings-arm_fk-reset_mode-description = Ändern Sie, welche Armhaltung für den Befestigungs-Reset erwartet wird.
settings-general-fk_settings-arm_fk-back = nach Hinten
settings-general-fk_settings-arm_fk-back-description = Der Standardmodus, bei dem die Oberarme nach hinten und die Unterarme nach vorne gehen.
@@ -479,6 +482,15 @@ settings-general-interface-connected_trackers_warning-label = Warnung vor verbun
settings-general-interface-use_tray = In den Infobereich minimieren
settings-general-interface-use_tray-description = Erlaubt Ihnen, das Fenster zu schließen, ohne den SlimeVR-Server zu beenden. Dies erlaubt Ihnen diesen weiterzuverwenden, ohne dass das Fenster stört.
settings-general-interface-use_tray-label = In den Infobereich minimieren
settings-general-interface-discord_presence = Aktivität auf Discord teilen
settings-general-interface-discord_presence-description = Teilt Ihrem Discord-Client mit, dass Sie SlimeVR verwenden, zusammen mit der Anzahl der IMU-Tracker, die Sie benutzen.
settings-general-interface-discord_presence-label = Aktivität auf Discord teilen
settings-general-interface-discord_presence-message =
{ $amount ->
[0] Sliming around
[one] nutzt 1 Tracker
*[other] nutzt { $amount } Tracker
}
## Serial settings
@@ -501,6 +513,8 @@ settings-serial-get_infos = Informationen abrufen
settings-serial-serial_select = Wählen Sie einen seriellen Anschluss
settings-serial-auto_dropdown_item = Auto
settings-serial-get_wifi_scan = WLAN-Scan
settings-serial-file_type = Klartext
settings-serial-save_logs = In Datei speichern
## OSC router settings
@@ -531,12 +545,16 @@ settings-osc-router-network-address-placeholder = IPv4 Adresse
settings-osc-vrchat = VRChat-OSC-Trackers
# This cares about multilines
settings-osc-vrchat-description = Ändern Sie VRChat-spezifische Einstellungen, um Headset- und Tracker-Daten für FBT zu empfangen und zu senden (funktioniert auch im Standalone-Modus auf der Meta Quest).
settings-osc-vrchat-description-v1 =
Ändern Sie die Einstellungen, die speziell für den OSC-Trackers-Standard verwendet werden, um Tracking-Daten an Anwendungen ohne SteamVR zu senden (z. B. für Quest Standalone).
Stellen Sie sicher, dass Sie OSC in VRChat über das Aktionsmenü unter OSC > Aktiviert einschalten.
Um das Empfangen von HMD- und Controller-Daten von VRChat zu ermöglichen, gehen Sie in Ihrem Hauptmenü
zu den Einstellungen unter Tracking & IK > Erlaube das Senden von Kopf- und Handgelenk-VR-Tracking-OSC-Daten.
settings-osc-vrchat-enable = Aktivieren
settings-osc-vrchat-enable-description = Ein- und Ausschalten des Sendens und Empfangen von Daten
settings-osc-vrchat-enable-label = Aktivieren
settings-osc-vrchat-network = Netzwerk-Ports
settings-osc-vrchat-network-description = Festlegen der Ports zum Empfangen und Senden von Daten an VRChat
settings-osc-vrchat-network-description-v1 = Legt die Ports für das Empfangen und Senden von Daten fest. Kann für VRChat unverändert bleiben.
settings-osc-vrchat-network-port_in =
.label = Eingangsport
.placeholder = Eingangsport (Standard: 9001)
@@ -544,7 +562,7 @@ settings-osc-vrchat-network-port_out =
.label = Ausgangsport
.placeholder = Ausgangsport (Standard: 9000)
settings-osc-vrchat-network-address = Netzwerkadresse
settings-osc-vrchat-network-address-description = Wählen Sie, an welche Adresse die Daten an VRChat gesendet werden sollen (überprüfen Sie Ihre WLAN-Einstellungen auf Ihrem Gerät)
settings-osc-vrchat-network-address-description-v1 = Wählen Sie die IP-Adresse, an die die Daten gesendet werden sollen. Kann für VRChat unverändert bleiben.
settings-osc-vrchat-network-address-placeholder = VRChat-IP-Adresse
settings-osc-vrchat-network-trackers = Tracker
settings-osc-vrchat-network-trackers-description = Ein- und Ausschalten des Sendens und Empfangens von Daten
@@ -585,6 +603,9 @@ settings-osc-vmc-vrm-file_select = Modell per Drag & Drop laden oder <u>durchsuc
settings-osc-vmc-anchor_hip = Hüftenverankerung
settings-osc-vmc-anchor_hip-description = Die Hüften-Verankerung für das Tracking ist nützlich für VTubing im Sitzen. Beim Deaktivieren muss ein VRM-Model geladen werden.
settings-osc-vmc-anchor_hip-label = Hüftenverankerung
settings-osc-vmc-mirror_tracking = Tracking spiegeln
settings-osc-vmc-mirror_tracking-description = Tracking horizontal spiegeln
settings-osc-vmc-mirror_tracking-label = Tracking spiegeln
## Setup/onboarding menu
@@ -723,6 +744,27 @@ onboarding-assign_trackers-assigned =
onboarding-assign_trackers-advanced = Erweiterte Zuweisungspositionen anzeigen
onboarding-assign_trackers-next = Ich habe alle Tracker zugewiesen
onboarding-assign_trackers-mirror_view = Ansicht spiegeln
onboarding-assign_trackers-option-amount =
{ $trackersCount ->
[one] x{ $trackersCount }
*[other] x{ $trackersCount }
}
onboarding-assign_trackers-option-label =
{ $mode ->
[lower-body] Lower-Body Set
[core] Core Set
[enhanced-core] Enhanced Core Set
[full-body] Full-Body Set
*[all] Alle Tracker
}
onboarding-assign_trackers-option-description =
{ $mode ->
[lower-body] Minimum für VR Full-Body Tracking
[core] + Erweitertes Rücken-Tracking
[enhanced-core] + Fuß-Rotation
[full-body] + Ellbogen-Tracking
*[all] Alle verfügbaren Tracker-Zuweisungen
}
## Tracker assignment warnings
@@ -799,11 +841,11 @@ onboarding-choose_mounting = Welche Kalibrierungsmethode ist zu verwenden?
onboarding-choose_mounting-description = Die Montageausrichtung korrigiert die Platzierung von Trackern am Körper.
onboarding-choose_mounting-auto_mounting = Befestigung automatisch ermitteln
# Italized text
onboarding-choose_mounting-auto_mounting-label = Experimentell
onboarding-choose_mounting-auto_mounting-label-v2 = Empfohlen
onboarding-choose_mounting-auto_mounting-description = Dadurch werden die Befestigungsausrichtungen für alle Ihrer Tracker automatisch aus 2 Posen erkannt
onboarding-choose_mounting-manual_mounting = Manuelle Befestigungsposition
# Italized text
onboarding-choose_mounting-manual_mounting-label = Empfohlen
onboarding-choose_mounting-manual_mounting-label-v2 = Möglicherweise nicht präzise genug
onboarding-choose_mounting-manual_mounting-description = Auf diese Weise können Sie die Montagerichtung für jeden Tracker manuell auswählen
# Multiline text
onboarding-choose_mounting-manual_modal-title =
@@ -907,7 +949,7 @@ onboarding-automatic_proportions-check_height-hmd_height1 = Ihre Headset-Höhe i
onboarding-automatic_proportions-check_height-height1 = Ihre tatsächliche Körpergröße ist
onboarding-automatic_proportions-check_height-next_step = Werte sind korrekt
onboarding-automatic_proportions-start_recording-title = Bereiten Sie sich auf ein paar Bewegungen vor
onboarding-automatic_proportions-start_recording-description = Wir werden nun einige bestimmte Posen und Bewegungen aufnehmen. Diese werden im nächsten Bildschirm angezeigt. Bereiten Sie sicht darauf vor, wenn Sie den Knopf drücken!
onboarding-automatic_proportions-start_recording-description = Wir werden nun einige bestimmte Posen und Bewegungen aufnehmen. Diese werden im nächsten Schritt angezeigt. Sei bereit damit zu beginnen, wenn du auf den Knopf drückst!
onboarding-automatic_proportions-start_recording-next = Aufnahme starten
onboarding-automatic_proportions-recording-title = Aufnahme
onboarding-automatic_proportions-recording-description-p0 = Aufnahme läuft...
@@ -962,6 +1004,7 @@ status_system-StatusSteamVRDisconnected =
*[other] Derzeit nicht über den SlimeVR-Treiber mit SteamVR verbunden.
}
status_system-StatusTrackerError = Der Tracker "{ $trackerName }" weist einen Fehler auf.
status_system-StatusUnassignedHMD = Das VR-Headset sollte als Kopf-Tracker zugewiesen sein.
## Tray Menu

View File

@@ -23,6 +23,8 @@ tips-find_tracker = nawt suwe whicsh twayckyaw is whicsh? shayke a twackaw and i
tips-do_not_move_heels = ensuwe yoowr pawsies do nawt mowve duwing wecowding! ^w^
tips-file_select = dwag & dwop fiwes to use OwO, ow <u>bwowse</u>.
tips-tap_setup = u can swowly tap youw twackew 2 times to choose it insted of sewecting it fwom the menyu.
tips-turn_on_tracker = erm.. are u using offishal SlaiemVR twackews??! rember to <b><em>tuwn on yuor twackew</em></b> aftwew coneccting it to teh PC!
tips-failed_webgl = oh nooooo :( faiwled to initiawizwe WebGL...
## Body parts
@@ -196,6 +198,7 @@ tracker-infos-hardware_rev = hawdwawe revision
tracker-infos-hardware_identifier = hawdwawe id
tracker-infos-imu = imu sensow
tracker-infos-board_type = mane bored
tracker-infos-network_version = pwotocol vewsiowon
## Tracker settings
@@ -215,6 +218,9 @@ tracker-settings-drift_compensation_section-edit = awwow dwift compensation
tracker-settings-name_section = twackaw name
tracker-settings-name_section-description = owo whats dis?
tracker-settings-name_section-placeholder = ewimewl's weft pawb
tracker-settings-forget = *forgors the tracker*
tracker-settings-forget-description = remooves teh twackew fwom da SwimeVR sewvew n pwevent it frum conecting to it til fhe sewvew iz westawtied. the cowonfigyuwatsin of da twackew woant b wost.
tracker-settings-forget-label = *forgors the tracker*
## Tracker part card info
@@ -304,10 +310,22 @@ settings-general-steamvr-description =
usefuw if yew want mowwe contwoww owew what swimevr does.
settings-general-steamvr-trackers-waist = wyayst~
settings-general-steamvr-trackers-chest = chwest~
settings-general-steamvr-trackers-feet = pweets~
settings-general-steamvr-trackers-knees = knyees~
settings-general-steamvr-trackers-elbows = ewbows~
settings-general-steamvr-trackers-hands = pawbsies~
settings-general-steamvr-trackers-left_foot = weft lower pawb
settings-general-steamvr-trackers-right_foot = wight lower pawb
settings-general-steamvr-trackers-left_knee = weft knee
settings-general-steamvr-trackers-right_knee = wight knee
settings-general-steamvr-trackers-left_elbow = weft elbow
settings-general-steamvr-trackers-right_elbow = wight elbow
settings-general-steamvr-trackers-left_hand = weft upper pawb
settings-general-steamvr-trackers-right_hand = wight upper pawb
settings-general-steamvr-trackers-tracker_toggling = awtomawtic twackaws assigwment
settings-general-steamvr-trackers-tracker_toggling-description = aUwUtomaticawwy handels tawggling SteemVR twackews on oar off depening on yoar cuwwent twackew assaingmentz
settings-general-steamvr-trackers-tracker_toggling-label = awtomawtic twackaws assigwment
settings-general-steamvr-trackers-hands-warning =
<b>OwOarning:</b> paw twackows wiww owovewwide youw contwowworz.
r u sure??
settings-general-steamvr-trackers-hands-warning-cancel = cancew :o
settings-general-steamvr-trackers-hands-warning-done = yes!!
## Tracker mechanics
@@ -325,6 +343,7 @@ settings-general-tracker_mechanics-filtering-type-smoothing-description = smowth
settings-general-tracker_mechanics-filtering-type-prediction = pwediction~
settings-general-tracker_mechanics-filtering-type-prediction-description = wowduces wowcyancy and makes wowvements mowe wowappy, but may incwease jiwitty
settings-general-tracker_mechanics-filtering-amount = amownt
settings-general-tracker_mechanics-yaw-reset-smooth-time = nyaw weset smootse taim (0s disaeblez smooting)
settings-general-tracker_mechanics-drift_compensation = dwift compensation
# This cares about multilines
settings-general-tracker_mechanics-drift_compensation-description =
@@ -333,6 +352,11 @@ settings-general-tracker_mechanics-drift_compensation-description =
settings-general-tracker_mechanics-drift_compensation-enabled-label = dwift compensation
settings-general-tracker_mechanics-drift_compensation-amount-label = compensation amownt
settings-general-tracker_mechanics-drift_compensation-max_resets-label = nuwmbew of wesets uwsed
settings-general-tracker_mechanics-save_mounting_reset = saiv awtomatic meownting weset calibwaytion
settings-general-tracker_mechanics-save_mounting_reset-description =
saves the auwtoemyatic meownting weset cawybwationz for da twackews betwean westawts. useful
wen weawing a sUwUit whewe twackews dont move between sesshuns. <b>nawt wecomended for noarmal UwUsews!</b>
settings-general-tracker_mechanics-save_mounting_reset-enabled-label = save meownting weset
## FK/Tracking settings
@@ -359,6 +383,9 @@ settings-general-fk_settings-leg_fk-reset_mounting_feet = Pawb Meownting Weset
settings-general-fk_settings-arm_fk = awm twacking
settings-general-fk_settings-arm_fk-description = chawnge teh way teh awms awe twacked.
settings-general-fk_settings-arm_fk-force_arms = fowce awms fwom hmd
settings-general-fk_settings-reset_settings = weset setings
settings-general-fk_settings-reset_settings-reset_hmd_pitch-description = weset da HMD's pitch (vewticaw wowtaytion) upawn doin a fuww weset. uwusefuw if weaewing an HMD on da foawrhed fow VTuwubing ow mocap. do nyat enaebwew fow VR.
settings-general-fk_settings-reset_settings-reset_hmd_pitch = weset HMD pitch
settings-general-fk_settings-arm_fk-reset_mode-description = Change which awm pose is expected fow meownting weset.
settings-general-fk_settings-arm_fk-back = bak
settings-general-fk_settings-arm_fk-back-description = The defauwt mode, wit da uppew awms going back and wowew awms going fowwawd.
@@ -452,6 +479,18 @@ settings-general-interface-feedback_sound-volume = feedback sownd volyume
settings-general-interface-connected_trackers_warning = Connected twackews wawning
settings-general-interface-connected_trackers_warning-description = This option wiww show a pop-up evewy time you twy exiting SwimeVR whiwe having one ow mowe connected twackews. It weminds you to tuwn off youw twackews when you awe done to pwesewve battewy wife.
settings-general-interface-connected_trackers_warning-label = Connected twackews wawning on exit
settings-general-interface-use_tray = minimaize to systewm tway
settings-general-interface-use_tray-description = wets u cwose the wimdOwOw wifhout cwosing da SwimeVR Sewvew so uou can keep using it withowt da GUI bohtewing u.
settings-general-interface-use_tray-label = minimaize to systewm tway
settings-general-interface-discord_presence = shaer activitey on discowd
settings-general-interface-discord_presence-description = tewws ur discoard cwient dat ur using SlyimeVR awong wif teh nuhmbew of IMU twackewrz u r using.
settings-general-interface-discord_presence-label = shaer activitey on discowd
settings-general-interface-discord_presence-message =
{ $amount ->
[0] slimin awaound :3
[one] using 1 twackew
*[other] using { $amount } twackewz
}
## Serial settings
@@ -473,6 +512,9 @@ settings-serial-factory_reset-warning-cancel = cancew
settings-serial-get_infos = get infows
settings-serial-serial_select = sewect a shewyaw pawt
settings-serial-auto_dropdown_item = awto
settings-serial-get_wifi_scan = get wifi scan uwu
settings-serial-file_type = plane text
settings-serial-save_logs = saeve to file
## OSC router settings
@@ -502,15 +544,11 @@ settings-osc-router-network-address-placeholder = IPV4 addwess
## OSC VRChat settings
settings-osc-vrchat = VRChawt OSC Twayckaws
# This cares about multilines
settings-osc-vrchat-description =
change vwchat-specific settwings to wweceive hmd data awnd send
twayckaws data fow fbt (wawwks on quest standalone).
settings-osc-vrchat-enable = enaybwe
settings-osc-vrchat-enable-description = toggle teh sending awnd wweceiving of data
settings-osc-vrchat-enable-label = enaybwe
settings-osc-vrchat-network = newtwowk pawts
settings-osc-vrchat-network-description = set the pawts fow wistening awnd sending data to vwchawt
settings-osc-vrchat-network-description-v1 = set da powrts fow wistening and sending data. can b left untouwched fow vrawrchat
settings-osc-vrchat-network-port_in =
.label = pawt in
.placeholder = pawt in (defawwt: 9001)
@@ -518,7 +556,6 @@ settings-osc-vrchat-network-port_out =
.label = pawt out
.placeholder = pawt out (defawwt: 9000)
settings-osc-vrchat-network-address = network addwess
settings-osc-vrchat-network-address-description = choose which addwess to send out data to vwchat (check yuw wi-fi settwings on yuw device)
settings-osc-vrchat-network-address-placeholder = vwchat ip addwess
settings-osc-vrchat-network-trackers = trayckawws
settings-osc-vrchat-network-trackers-description = toggle teh sending of spweciwic twackers viwa OSC
@@ -561,6 +598,9 @@ settings-osc-vmc-vrm-file_select = dwag & dwop a modew to use OwO, ow <u>bwowse<
settings-osc-vmc-anchor_hip = anchow at hips
settings-osc-vmc-anchor_hip-description = anchow the twacking at the hips, usefuw fow seated vtubing
settings-osc-vmc-anchor_hip-label = anchow at hips
settings-osc-vmc-mirror_tracking = miwwow twacking
settings-osc-vmc-mirror_tracking-description = miwwow da twacking howizawntawwy.
settings-osc-vmc-mirror_tracking-label = miwwow twacking
## Setup/onboarding menu
@@ -638,8 +678,8 @@ onboarding-done-close = cwose the guide
onboarding-connect_tracker-back = gaww bawwk to wi-fi cwedentials
onboarding-connect_tracker-title = connect twackaws
onboarding-connect_tracker-description-p0 = now onto teh fun pawwt, connecting awe teh twackaws!
onboarding-connect_tracker-description-p1 = simply connect awe that awe nawt cownyected yet, through a usb powwt.
onboarding-connect_tracker-description-p0-v1 = now onto teh fun pawrt, connyecting twackews!1! :D
onboarding-connect_tracker-description-p1-v1 = conect each twackew wun at a taim thru a USB pawrt.
onboarding-connect_tracker-issue-serial = i'm having twouble connecting!
onboarding-connect_tracker-usb = usb twackew
onboarding-connect_tracker-connection_status-none = wooking fow twackaws
@@ -699,6 +739,28 @@ onboarding-assign_trackers-assigned =
} assigned
onboarding-assign_trackers-advanced = show advanced assign wocations
onboarding-assign_trackers-next = i assigned awe the twackaws
onboarding-assign_trackers-mirror_view = miwwow vyew
onboarding-assign_trackers-option-amount =
{ $trackersCount ->
[one] x{ $trackersCount }
*[other] x{ $trackersCount }
}
onboarding-assign_trackers-option-label =
{ $mode ->
[lower-body] wower-bawdy set
[core] coar set
[enhanced-core] enhaynced coar set
[full-body] fuww-bawdy set
*[all] all twackewz
}
onboarding-assign_trackers-option-description =
{ $mode ->
[lower-body] minimum fow VR fuww-bawdy twacking
[core] + enhanced spine twacking
[enhanced-core] + paw wowtation
[full-body] + ewbOwOw twacking
*[all] all awvaiwabule twackew assaignments
}
## Tracker assignment warnings
@@ -775,11 +837,11 @@ onboarding-choose_mounting = wut meownting cawibwation mefod to use?
onboarding-choose_mounting-description = meownting owientation correct fow da pwacement of twackews on u body.
onboarding-choose_mounting-auto_mounting = awtomawic meownting
# Italized text
onboarding-choose_mounting-auto_mounting-label = expewimentaw
onboarding-choose_mounting-auto_mounting-label-v2 = wecommended
onboarding-choose_mounting-auto_mounting-description = dis will automaticawwy detec da meownting diwecshuns fow aww of ya twackews fwom 2 poses
onboarding-choose_mounting-manual_mounting = manyul meownting
# Italized text
onboarding-choose_mounting-manual_mounting-label = wecommended
onboarding-choose_mounting-manual_mounting-label-v2 = might nawt b pwecise enuff ;w;
onboarding-choose_mounting-manual_mounting-description = dis will let u chose da meownting diwecshun manuwawwy fow eech twackew
# Multiline text
onboarding-choose_mounting-manual_modal-title =
@@ -822,9 +884,10 @@ onboarding-automatic_mounting-put_trackers_on-next = i haff awe my twackaws on
onboarding-choose_proportions = wut pwopowshun cawibwation mefod to use?
# Multiline string
onboarding-choose_proportions-description =
body pawpowtions awe used to know the measuwements of uw body. dey wequiwed to cawcuwate the twackews' pawsitions.
wen pawpowtions of youw body dun mach da onyes saved, youw twacking pwecision wiwl be wowse and you wiwl nyotice tings wike skating or swiding, ow youw body nyot matching youw avataw wewl.
onboarding-choose_proportions-description-v1 =
bawdy pwopowotions r used to knwo da mehsuwementz of youw bawdy. they'we wequiewed to cawcuwate da twackews' pawsitshons.
wen pwopowotiosn of ur bawdey don match teh ones saeved, yow twacking pwecisiown wiww b wowse and u wiww nowotice tingz wike skayting ow slaiding, ow yor bodiey matching uor avataw wel.
<b>u only need to mewhsuwe your bawdee once!!</b> unwess dey awe rong ow yer boady haz chaenged, you dont need to do them agen. UwU
onboarding-choose_proportions-auto_proportions = awtomatic pwopowtions
# Italized text
onboarding-choose_proportions-auto_proportions-subtitle = wecommended
@@ -873,6 +936,9 @@ onboarding-automatic_proportions-check_height-title = check youw height
onboarding-automatic_proportions-check_height-description = we use youw height as a basis of ouw measuwements by using da hmd's height as an appwoximashun of youw actuwaw height, but is better to check if they are right youwsewf!
# All the text is in bold!
onboarding-automatic_proportions-check_height-calculation_warning = pwease pwess da button while standing <u>upwight</u> to cawcuwate youw height. you hav 3 second aftew you pwess da button! >w<
onboarding-automatic_proportions-check_height-guardian_tip =
if u r using a standowone VR hedset, make suwe to have youw gawrdian /
bowndawy tuwned on so ur heit iz cowwect!!
onboarding-automatic_proportions-check_height-fetch_height = am standing!
# Context is that the height is unknown
onboarding-automatic_proportions-check_height-unknown = unnown
@@ -937,3 +1003,32 @@ status_system-StatusSteamVRDisconnected =
*[other] cuwwentwly nawt conected to SwimeVR wiff da SwimeVR dwiver.
}
status_system-StatusTrackerError = da { $trackerName } twackew has ewwow. >~<
status_system-StatusUnassignedHMD = teh VR hedset shud be awssaignd as a hed twackew.
## Tray Menu
tray_menu-show = show
tray_menu-hide = hoide
tray_menu-quit = qwit
## First exit modal
tray_or_exit_modal-title = owo wat shud da cwose button do?
# Multiline text
tray_or_exit_modal-description =
dis lets u choose wether u wanna exit te sewvew ow to minimaize it to da tway wen pwessing teh cwose buttin.
yuow can cheange dis latew in da intewfayce setings! :D
tray_or_exit_modal-radio-exit = exit on cwose
tray_or_exit_modal-radio-tray = minimaize to systehm tway
tray_or_exit_modal-submit = save :3
tray_or_exit_modal-cancel = cancew :o
## Unknown device modal
unknown_device-modal-title = da twackew was find owo
unknown_device-modal-description =
therwe is a nyew twackew wif MAC addwess <b>{ $deviceId }</b>..
d-do u wanna conect it to SwimeVR?
unknown_device-modal-confirm = sure!!
unknown_device-modal-forget = ignowe it

View File

@@ -355,6 +355,9 @@ settings-general-fk_settings-leg_fk-reset_mounting_feet = Feet Mounting Reset
settings-general-fk_settings-arm_fk = Arm tracking
settings-general-fk_settings-arm_fk-description = Force arms to be tracked from the headset (HMD) even if positional hand data is available.
settings-general-fk_settings-arm_fk-force_arms = Force arms from HMD
settings-general-fk_settings-reset_settings = Reset settings
settings-general-fk_settings-reset_settings-reset_hmd_pitch-description = Reset the HMD's pitch (vertical rotation) upon doing a full reset. Useful if wearing an HMD on the forehead for VTubing or mocap. Do not enable for VR.
settings-general-fk_settings-reset_settings-reset_hmd_pitch = Reset HMD pitch
settings-general-fk_settings-arm_fk-reset_mode-description = Change which arm pose is expected for mounting reset.
settings-general-fk_settings-arm_fk-back = Back
settings-general-fk_settings-arm_fk-back-description = The default mode, with the upper arms going back and lower arms going forward.
@@ -448,13 +451,21 @@ settings-general-interface-connected_trackers_warning-label = Connected trackers
settings-general-interface-use_tray = Minimize to system tray
settings-general-interface-use_tray-description = Lets you close the window without closing the SlimeVR Server so you can continue using it without having the GUI bothering you.
settings-general-interface-use_tray-label = Minimize to system tray
settings-general-interface-discord_presence = Share activity on Discord
settings-general-interface-discord_presence-description = Tells your Discord client that you are using SlimeVR along with the number of IMU trackers you are using.
settings-general-interface-discord_presence-label = Share activity on Discord
settings-general-interface-discord_presence-message = { $amount ->
[0] Sliming around
[one] Using 1 tracker
*[other] Using { $amount } trackers
}
## Serial settings
settings-serial = Serial Console
# This cares about multilines
settings-serial-description =
This is a live information feed for serial communication.
May be useful if you need to know the firmware is acting up.
May be useful to debug firmware or hardware issues.
settings-serial-connection_lost = Connection to serial lost, Reconnecting...
settings-serial-reboot = Reboot
settings-serial-factory_reset = Factory Reset
@@ -469,6 +480,8 @@ settings-serial-get_infos = Get Infos
settings-serial-serial_select = Select a serial port
settings-serial-auto_dropdown_item = Auto
settings-serial-get_wifi_scan = Get WiFi Scan
settings-serial-file_type = Plain text
settings-serial-save_logs = Save To File
## OSC router settings
settings-osc-router = OSC router
@@ -497,14 +510,17 @@ settings-osc-router-network-address-placeholder = IPV4 address
## OSC VRChat settings
settings-osc-vrchat = VRChat OSC Trackers
# This cares about multilines
settings-osc-vrchat-description =
Change VRChat-specific settings to receive headset (HMD) data and send
tracker data for FBT without SteamVR (ex. Quest standalone).
settings-osc-vrchat-description-v1 =
Change settings specific to the OSC Trackers standard used for sending
tracking data to applications without SteamVR (ex. Quest standalone).
Make sure to enable OSC in VRChat via the Action Menu under OSC > Enabled.
To allow receiving HMD and controller data from VRChat, go in your main menu's
settings under Tracking & IK > Allow Sending Head and Wrist VR Tracking OSC Data.
settings-osc-vrchat-enable = Enable
settings-osc-vrchat-enable-description = Toggle the sending and receiving of data.
settings-osc-vrchat-enable-label = Enable
settings-osc-vrchat-network = Network ports
settings-osc-vrchat-network-description = Set the ports for listening and sending data to VRChat.
settings-osc-vrchat-network-description-v1 = Set the ports for listening and sending data. Can be left untouched for VRChat.
settings-osc-vrchat-network-port_in =
.label = Port In
.placeholder = Port in (default: 9001)
@@ -512,7 +528,7 @@ settings-osc-vrchat-network-port_out =
.label = Port Out
.placeholder = Port out (default: 9000)
settings-osc-vrchat-network-address = Network address
settings-osc-vrchat-network-address-description = Choose which address to send out data to VRChat (check your Wi-Fi settings on your device).
settings-osc-vrchat-network-address-description-v1 = Choose which address to send out data to. Can be left untouched for VRChat.
settings-osc-vrchat-network-address-placeholder = VRChat ip address
settings-osc-vrchat-network-trackers = Trackers
settings-osc-vrchat-network-trackers-description = Toggle the sending of specific trackers via OSC.
@@ -553,6 +569,9 @@ settings-osc-vmc-vrm-file_select = Drag & drop a model to use, or <u>browse</u>
settings-osc-vmc-anchor_hip = Anchor at hips
settings-osc-vmc-anchor_hip-description = Anchor the tracking at the hips, useful for seated VTubing. If disabling, load a VRM model.
settings-osc-vmc-anchor_hip-label = Anchor at hips
settings-osc-vmc-mirror_tracking = Mirror tracking
settings-osc-vmc-mirror_tracking-description = Mirror the tracking horizontally.
settings-osc-vmc-mirror_tracking-label = Mirror tracking
## Setup/onboarding menu
onboarding-skip = Skip setup
@@ -677,6 +696,24 @@ onboarding-assign_trackers-assigned = { $assigned } of { $trackers ->
onboarding-assign_trackers-advanced = Show advanced assign locations
onboarding-assign_trackers-next = I assigned all the trackers
onboarding-assign_trackers-mirror_view = Mirror view
onboarding-assign_trackers-option-amount = { $trackersCount ->
[one] x{ $trackersCount }
*[other] x{ $trackersCount }
}
onboarding-assign_trackers-option-label = { $mode ->
[lower-body] Lower-Body Set
[core] Core Set
[enhanced-core] Enhanced Core Set
[full-body] Full-Body Set
*[all] All Trackers
}
onboarding-assign_trackers-option-description = { $mode ->
[lower-body] Minimum for VR full-body tracking
[core] + Enhanced spine tracking
[enhanced-core] + Foot rotation
[full-body] + Elbow tracking
*[all] All available tracker assignments
}
## Tracker assignment warnings
# Note for devs, number is used for representing boolean states per bit.
@@ -743,11 +780,11 @@ onboarding-choose_mounting = What mounting calibration method to use?
onboarding-choose_mounting-description = Mounting orientation corrects for the placement of trackers on your body.
onboarding-choose_mounting-auto_mounting = Automatic mounting
# Italized text
onboarding-choose_mounting-auto_mounting-label = Experimental
onboarding-choose_mounting-auto_mounting-label-v2 = Recommended
onboarding-choose_mounting-auto_mounting-description = This will automatically detect the mounting orientations for all of your trackers from 2 poses
onboarding-choose_mounting-manual_mounting = Manual mounting
# Italized text
onboarding-choose_mounting-manual_mounting-label = Recommended
onboarding-choose_mounting-manual_mounting-label-v2 = Might not be precise enough
onboarding-choose_mounting-manual_mounting-description = This will let you choose the mounting orientation manually for each tracker
# Multiline text
onboarding-choose_mounting-manual_modal-title = Are you sure you want to do
@@ -896,6 +933,7 @@ status_system-StatusSteamVRDisconnected = { $type ->
[steamvr_feeder] Currently not connected to the SlimeVR Feeder App.
}
status_system-StatusTrackerError = The { $trackerName } tracker has an error.
status_system-StatusUnassignedHMD = The VR headset should be assigned as a head tracker.
## Tray Menu
tray_menu-show = Show

View File

@@ -22,7 +22,7 @@ version_update-close = Cerrar
tips-find_tracker = ¿No estás seguro de cuál sensor es cuál? Agita un sensor y se resaltará donde está asignado.
tips-do_not_move_heels = ¡Asegúrate de no mover los talones en la grabación!
tips-file_select = Arrastra y suelta archivos para usarlos, o <u>selecciónalos<u>.
tips-tap_setup = Puedes tocar lentamente 2 veces el tracker para seleccionarlo en lugar de seleccionarlo desde el menú.
tips-tap_setup = Puedes tocar lentamente 2 veces el sensor para seleccionarlo en lugar de seleccionarlo desde el menú.
tips-turn_on_tracker = ¿Estas usando trackers de SlimeVR oficiales? ¡Recuerda <b><em>encender tus trackers<em><b> después de conectarlos al PC!
tips-failed_webgl = Fallo al inicializar WebGL.
@@ -383,6 +383,9 @@ settings-general-fk_settings-leg_fk-reset_mounting_feet = Reinicio de montura de
settings-general-fk_settings-arm_fk = Trackeo de brazos
settings-general-fk_settings-arm_fk-description = Cambia cómo el movimiento de los brazos es detectado.
settings-general-fk_settings-arm_fk-force_arms = Forzar brazos desde el HMD
settings-general-fk_settings-reset_settings = Reiniciar ajustes
settings-general-fk_settings-reset_settings-reset_hmd_pitch-description = Restablece la inclinación del HMD (rotación vertical) al realizar un reinicio completo. Útil si se lleva un HMD en la frente para VTubing o mocap. No habilitar para VR.
settings-general-fk_settings-reset_settings-reset_hmd_pitch = Reiniciar la inclinación del HMD
settings-general-fk_settings-arm_fk-reset_mode-description = Cambiar que pose de brazos es esperada para el reinicio de montura.
settings-general-fk_settings-arm_fk-back = Detrás
settings-general-fk_settings-arm_fk-back-description = El modo predeterminado, con el brazo yendo por detrás y el antebrazo yendo para adelante.
@@ -479,6 +482,16 @@ settings-general-interface-connected_trackers_warning-label = Advertencia de tra
settings-general-interface-use_tray = Minimizar a la bandeja del sistema
settings-general-interface-use_tray-description = Permite cerrar la ventana sin cerrar el servidor de SlimeVR para que puedas continuar usándolo sin que te moleste la interfaz.
settings-general-interface-use_tray-label = Minimizar a la bandeja del sistema
settings-general-interface-discord_presence = Compartir actividad en Discord
settings-general-interface-discord_presence-description = Le dice a tu cliente de Discord que estás usando SlimeVR junto con la cantidad de sensores IMU que estás usando.
settings-general-interface-discord_presence-label = Compartir actividad en Discord
settings-general-interface-discord_presence-message =
{ $amount ->
[0] Recolectando slimes
[one] Usando 1 sensor
[many] Usando { $amount } de sensores
*[other] Usando { $amount } sensores
}
## Serial settings
@@ -501,6 +514,8 @@ settings-serial-get_infos = Obtener información
settings-serial-serial_select = Selecciona un puerto serial
settings-serial-auto_dropdown_item = Auto
settings-serial-get_wifi_scan = Obtener escaneo WiFi
settings-serial-file_type = Texto sin formato
settings-serial-save_logs = Guardar en archivo
## OSC router settings
@@ -531,14 +546,17 @@ settings-osc-router-network-address-placeholder = Dirección IPv4
settings-osc-vrchat = Sensores OSC de VRChat
# This cares about multilines
settings-osc-vrchat-description =
Cambiar ajustes específicos de VRChat para recibir datos del HMD y enviar
datos de los sensores para seguimiento de cuerpo completo (funciona en Quest nativo).
settings-osc-vrchat-description-v1 =
Cambia los ajustes específicos de los trackers OSC utilizados para enviar
datos de seguimiento a aplicaciones sin SteamVR (ej. VRChat en Quest).
Asegúrate de activar OSC en VRChat a través del menú Acción en OSC > Activado.
Para permitir la recepción de datos del HMD y de los mandos desde VRChat, ve a los ajustes de tu menú principal
en Tracking & IK > Permitir el envío de datos OSC de seguimiento de RV de cabeza y muñeca.
settings-osc-vrchat-enable = Habilitar
settings-osc-vrchat-enable-description = Habilita el envio y recibo de datos.
settings-osc-vrchat-enable-label = Habilitar
settings-osc-vrchat-network = Puertos de conexión
settings-osc-vrchat-network-description = Establece los puertos de entrada y salida de datos a VRChat.
settings-osc-vrchat-network-description-v1 = Establece los puertos para recibir y enviar datos. Se puede dejar sin cambiar para VRChat.
settings-osc-vrchat-network-port_in =
.label = Puerto de entrada
.placeholder = Puerto de entrada (por defecto: 9001)
@@ -546,7 +564,7 @@ settings-osc-vrchat-network-port_out =
.label = Puerto de salida
.placeholder = Puerto de salida (por defecto: 9000)
settings-osc-vrchat-network-address = Dirección de red
settings-osc-vrchat-network-address-description = Establece la dirección donde se enviarán los datos de VRChat (revisa los ajustes de Wi-Fi de tu dispositivo que tenga el juego).
settings-osc-vrchat-network-address-description-v1 = Elige a qué dirección enviar los datos. Se puede dejar sin cambiar para VRChat.
settings-osc-vrchat-network-address-placeholder = Dirección IP de VRChat
settings-osc-vrchat-network-trackers = Sensores
settings-osc-vrchat-network-trackers-description = Habilita el envío de sensores específicos mediante OSC.
@@ -589,6 +607,9 @@ settings-osc-vmc-vrm-file_select = Arrastra y suelta un modelo para usar, o <u>s
settings-osc-vmc-anchor_hip = Anclaje por cadera
settings-osc-vmc-anchor_hip-description = Anclar el tracking a la cadera, útil para hacer de VTuber sentado. Si lo desactivas, carga un modelo VRM.
settings-osc-vmc-anchor_hip-label = Anclaje por cadera
settings-osc-vmc-mirror_tracking = Invertir el tracking
settings-osc-vmc-mirror_tracking-description = invierte el tracking horizontalmente.
settings-osc-vmc-mirror_tracking-label = Invertir el tracking
## Setup/onboarding menu
@@ -728,6 +749,28 @@ onboarding-assign_trackers-assigned =
onboarding-assign_trackers-advanced = Mostrar ubicación de asignaciones avanzados.
onboarding-assign_trackers-next = He asignado todos los sensores
onboarding-assign_trackers-mirror_view = Vista espejo
onboarding-assign_trackers-option-amount =
{ $trackersCount ->
[one] x{ $trackersCount }
[many] x{ $trackersCount }
*[other] x{ $trackersCount }
}
onboarding-assign_trackers-option-label =
{ $mode ->
[lower-body] Conjunto para inferior del cuerpo
[core] Conjunto básico
[enhanced-core] Conjunto básico mejorado
[full-body] Conjunto para cuerpo completo
*[all] Todos los sensores
}
onboarding-assign_trackers-option-description =
{ $mode ->
[lower-body] El mínimo para el full-body tracking en RV
[core] + Mejor seguimiento de la columna vertebral
[enhanced-core] + Rotación de pies
[full-body] + Seguimiento de codos
*[all] Todas las asignaciones de sensores disponibles
}
## Tracker assignment warnings
@@ -804,11 +847,11 @@ onboarding-choose_mounting = ¿Qué método de calibración de montura quiere us
onboarding-choose_mounting-description = La orientación de montura corrige la colocación (o orientación) de los trackers en tu cuerpo.
onboarding-choose_mounting-auto_mounting = Montura automática
# Italized text
onboarding-choose_mounting-auto_mounting-label = Experimental
onboarding-choose_mounting-auto_mounting-label-v2 = Recomendado
onboarding-choose_mounting-auto_mounting-description = Esto detectará automáticamente las direcciones de montura para todos tus trackers a partir de 2 poses
onboarding-choose_mounting-manual_mounting = Montura manual
# Italized text
onboarding-choose_mounting-manual_mounting-label = Recomendado
onboarding-choose_mounting-manual_mounting-label-v2 = Puede que no sea lo suficientemente preciso
onboarding-choose_mounting-manual_mounting-description = Esto te permitirá elegir la dirección de montura manualmente para cada tracker.
# Multiline text
onboarding-choose_mounting-manual_modal-title =
@@ -970,6 +1013,7 @@ status_system-StatusSteamVRDisconnected =
*[other] Actualmente no está conectado a SteamVR a través del driver de SlimeVR.
}
status_system-StatusTrackerError = El tracker { $trackerName } tiene un error.
status_system-StatusUnassignedHMD = El casco de RV debe ser asignado como un sensor de cabeza.
## Tray Menu

View File

@@ -381,6 +381,9 @@ settings-general-fk_settings-leg_fk-reset_mounting_feet = Reinicio de montura de
settings-general-fk_settings-arm_fk = Tracking de brazos
settings-general-fk_settings-arm_fk-description = Forzar el seguimiento de los brazos desde el HMD incluso si hay datos de posición de la mano disponibles.
settings-general-fk_settings-arm_fk-force_arms = Forzar brazos desde el HMD
settings-general-fk_settings-reset_settings = Restablecer la configuración
settings-general-fk_settings-reset_settings-reset_hmd_pitch-description = Restablecer la inclinación del HMD (rotación vertical) al realizar un reinicio completo. Útil si se lleva un HMD en la frente para VTubing o mocap. No habilitar para VR.
settings-general-fk_settings-reset_settings-reset_hmd_pitch = Reiniciar la inclinación del HMD
settings-general-fk_settings-arm_fk-reset_mode-description = Cambia la posición por defecto para el restablecimiento de montura
settings-general-fk_settings-arm_fk-back = Parte posterior del brazo
settings-general-fk_settings-arm_fk-back-description = Modo predeterminado, con los brazos hacia atrás y los antebrazos hacia adelante.
@@ -479,6 +482,15 @@ settings-general-interface-connected_trackers_warning-label = Aviso de trackers
settings-general-interface-use_tray = Minimizar a la bandeja
settings-general-interface-use_tray-description = Te permite cerrar la ventana sin cerrar SlimeVR para que pueda seguir usándolo sin que la interfaz te moleste.
settings-general-interface-use_tray-label = Minimizar en la bandeja del sistema
settings-general-interface-discord_presence = Compartir actividad en Discord
settings-general-interface-discord_presence-description = Le indica a tu cliente de Discord que estás usando SlimeVR junto con el número de rastreadores IMU que estás usando.
settings-general-interface-discord_presence-label = Compartir actividad en Discord
settings-general-interface-discord_presence-message =
{ $amount ->
[0] Recolectando slimes
[one] Usando 1 tracker
*[other] Usando { $amount } trackers
}
## Serial settings
@@ -501,6 +513,8 @@ settings-serial-get_infos = Obtener información
settings-serial-serial_select = Selecciona un puerto serial
settings-serial-auto_dropdown_item = Automático
settings-serial-get_wifi_scan = Obtener escaneo WiFi
settings-serial-file_type = Texto sin formato
settings-serial-save_logs = Guardar en archivo
## OSC router settings
@@ -531,12 +545,17 @@ settings-osc-router-network-address-placeholder = Dirección IPV4
settings-osc-vrchat = VRChat OSC Trackers
# This cares about multilines
settings-osc-vrchat-description = Cambia la configuración específica de VRChat para recibir datos del visor (HMD) y enviar datos a los trackers para FBT sin SteamVR (ej. Quest standalone).
settings-osc-vrchat-description-v1 =
Change settings specific to the OSC Trackers standard used for sending
tracking data to applications without SteamVR (ex. Quest standalone).
Make sure to enable OSC in VRChat via the Action Menu under OSC > Enabled.
To allow receiving HMD and controller data from VRChat, go in your main menu's
settings under Tracking & IK > Allow Sending Head and Wrist VR Tracking OSC Data.
settings-osc-vrchat-enable = Habilitar
settings-osc-vrchat-enable-description = Alternar el envío y la recepción de datos
settings-osc-vrchat-enable-label = Habilitar
settings-osc-vrchat-network = Puertos de red
settings-osc-vrchat-network-description = Configura los puertos para escuchar y enviar datos a VRChat.
settings-osc-vrchat-network-description-v1 = Establece los puertos para recibir y enviar datos. Se puede dejar sin modificar para VRChat.
settings-osc-vrchat-network-port_in =
.label = Puerto de entrada
.placeholder = Puerto de entrada (Por defecto: 9001)
@@ -544,7 +563,7 @@ settings-osc-vrchat-network-port_out =
.label = Puerto de salida
.placeholder = Puerto de salida (Por defecto: 9000)
settings-osc-vrchat-network-address = Dirección de red
settings-osc-vrchat-network-address-description = Elige a qué dirección enviar los datos a VRChat (Comprueba la configuración Wi-Fi de tu dispositivo).
settings-osc-vrchat-network-address-description-v1 = Elige a qué dirección enviar los datos. Se puede dejar sin modificar para VRChat.
settings-osc-vrchat-network-address-placeholder = Dirección IP de VRChat
settings-osc-vrchat-network-trackers = Trackers
settings-osc-vrchat-network-trackers-description = Activar el envío de trackers específicos a través de OSC.
@@ -563,12 +582,31 @@ settings-osc-vmc-enable = Habilitar
settings-osc-vmc-enable-description = Alterna el envío y recepción de datos.
settings-osc-vmc-enable-label = Habilitar
settings-osc-vmc-network = Puertos de red
settings-osc-vmc-network-description = Establece los puertos para escuchar y enviar datos via VMC.
settings-osc-vmc-network-port_in =
.label = Puerto de entrada
.placeholder = Puerto de entrada (Por defecto: 39540)
settings-osc-vmc-network-port_out =
.label = Puerto de salida
.placeholder = Puerto de salida (Por defecto: 39539)
settings-osc-vmc-network-address = Dirección de red
settings-osc-vmc-network-address-description = Elige la dirección a la que se enviarán los datos vía VMC.
settings-osc-vmc-network-address-placeholder = Dirección IPV4
settings-osc-vmc-vrm = Modelo VRM
settings-osc-vmc-vrm-description = Cargar un modelo VRM para permitir el anclaje de la cabeza y posibilitar una mayor compatibilidad con otras aplicaciones.
settings-osc-vmc-vrm-model_unloaded = No hay modelo cargado
settings-osc-vmc-vrm-model_loaded =
{ $titled ->
[true] Modelo cargado: { $name }
*[false] Modelo sin título cargado
}
settings-osc-vmc-vrm-file_select = Arrastre y suelte un modelo para utilizarlo, o <u>busquelo</u>
settings-osc-vmc-anchor_hip = Anclar a la cadera
settings-osc-vmc-anchor_hip-description = Ancla el tracking a la cadera, útil para VTubing sentado. Si se deshabilita, carga un modelo VRM.
settings-osc-vmc-anchor_hip-label = Anclar a la cadera
settings-osc-vmc-mirror_tracking = Invertir el tracking
settings-osc-vmc-mirror_tracking-description = Invierte el tracking horizontalmente.
settings-osc-vmc-mirror_tracking-label = Invertir el tracking
## Setup/onboarding menu
@@ -576,6 +614,9 @@ onboarding-skip = Omitir configuración
onboarding-continue = Continuar
onboarding-wip = Trabajo en progreso
onboarding-previous_step = Paso anterior
onboarding-setup_warning =
<b>Advertencia:</b> La configuración inicial es necesaria para un buen tracking,
es necesaria si es la primera vez que usas SlimeVR
onboarding-setup_warning-skip = Omitir configuración
onboarding-setup_warning-cancel = Continuar con la configuración
@@ -598,9 +639,28 @@ onboarding-wifi_creds-password =
## Mounting setup
onboarding-reset_tutorial-back = Volver a la calibración de montura
onboarding-reset_tutorial = Tutorial para resetteo de trackers
onboarding-reset_tutorial-explanation = Mientras usas tus trackers, es posible que se desalineen debido al balanceo de la IMU o porque es posible que se hayan movido físicamente. Tienes varias formas de solucionar este problema.
onboarding-reset_tutorial-skip = Omitir paso
# Cares about multiline
onboarding-reset_tutorial-0 =
Toque { $taps } veces el rastreador resaltado para activar el restablecimiento horizontal.
Esto hará que los trackers miren en la misma dirección que tu visor (HMD).
# Cares about multiline
onboarding-reset_tutorial-1 =
Toque { $taps } veces el rastreador resaltado para activar el reinicio completo.
Para ello es necesario estar de pie (pose i). Hay un retraso de 3 segundos (configurable) antes de que realmente suceda.
Esto restablece completamente la posición y la rotación de todos sus trackers. Debería solucionar la mayoría de los problemas.
# Cares about multiline
onboarding-reset_tutorial-2 =
Toque { $taps } veces el tracker resaltado para activar el restablecimiento de montura.
El restablecimiento de montura ayuda en cómo los trackers están realmente colocados en ti, así que si accidentalmente los moviste y cambiaste su orientación por una gran cantidad, esto ayudará.
Necesitas estar en una pose como si estuvieras esquiando como se muestra en el asistente de montaje automático y tienes un retraso de 3 segundos (configurable) antes de que se active.
## Setup start
@@ -624,6 +684,8 @@ onboarding-done-close = Cerrar configuración
onboarding-connect_tracker-back = Volver a credenciales de Wi-Fi
onboarding-connect_tracker-title = Conectar trackers
onboarding-connect_tracker-description-p0-v1 = ¡Ahora a la parte divertida, conectar los trackers!
onboarding-connect_tracker-description-p1-v1 = Conecte cada tracker de uno en uno a través de un puerto USB.
onboarding-connect_tracker-issue-serial = ¡Tengo problemas para conectarme!
onboarding-connect_tracker-usb = Tracker USB
onboarding-connect_tracker-connection_status-none = Buscando trackers
@@ -634,12 +696,24 @@ onboarding-connect_tracker-connection_status-looking_for_server = Buscando servi
onboarding-connect_tracker-connection_status-connection_error = No se puede conectar al Wi-Fi
onboarding-connect_tracker-connection_status-could_not_find_server = No se pudo encontrar el servidor
onboarding-connect_tracker-connection_status-done = Conectado al Server
# $amount (Number) - Amount of trackers connected (this is a number, but you can use CLDR plural rules for your language)
# More info on https://www.unicode.org/cldr/cldr-aux/charts/22/supplemental/language_plural_rules.html
# English in this case only has 2 plural rules, which are "one" and "other",
# we use 0 in an explicit way because there is no plural rule in english for 0, so we directly say
# if $amount is 0 then we say "No trackers connected"
onboarding-connect_tracker-connected_trackers =
{ $amount ->
[0] No hay tracker conectados
[one] 1 tracker conectado
*[other] { $amount } trackers conectados
}
onboarding-connect_tracker-next = He conectado todos mis trackers
## Tracker calibration tutorial
onboarding-calibration_tutorial = Tutorial de calibración de IMU
onboarding-calibration_tutorial-subtitle = ¡Esto ayudará a reducir el drift de los trackers!
onboarding-calibration_tutorial-description = Cada vez que enciendas tus trackers, estos necesitan descansar sobre una superficie plana para calibrarse. Hagamos lo mismo pulsando el botón «{ onboarding-calibration_tutorial-calibrate }», <b>¡no los muevas!</b>
onboarding-calibration_tutorial-calibrate = Mis trackers estan en una superficie plana
onboarding-calibration_tutorial-status-waiting = Esperando por ti
onboarding-calibration_tutorial-status-calibrating = Calibrando
@@ -661,8 +735,38 @@ onboarding-assignment_tutorial-done = ¡Le puse pegatinas y correas!
onboarding-assign_trackers-back = Volver a credenciales de Wi-Fi
onboarding-assign_trackers-title = Asignar trackers
onboarding-assign_trackers-description = Elije qué tracker va a dónde. Haz clic en la ubicación donde deseas colocar un tracker
# Look at translation of onboarding-connect_tracker-connected_trackers on how to use plurals
# $assigned (Number) - Trackers that have been assigned a body part
# $trackers (Number) - Trackers connected to the server
onboarding-assign_trackers-assigned =
{ $trackers ->
[one] { $assigned } de 1 tracker asignado
*[other] { $assigned } de { $trackers } trackers asignados
}
onboarding-assign_trackers-advanced = Mostrar ubicaciones de asignación avanzadas
onboarding-assign_trackers-next = He asignado todos los trackers
onboarding-assign_trackers-mirror_view = Vista en espejo
onboarding-assign_trackers-option-amount =
{ $trackersCount ->
[one] x{ $trackersCount }
*[other] x{ $trackersCount }
}
onboarding-assign_trackers-option-label =
{ $mode ->
[lower-body] Set de Cuerpo Inferior
[core] Set Básico
[enhanced-core] Set Básico Mejorado
[full-body] Set de Cuerpo Completo
*[all] Todos los Trackers
}
onboarding-assign_trackers-option-description =
{ $mode ->
[lower-body] Mínimo para el seguimiento de cuerpo completo en RV
[core] + Tracking de columna mejorado
[enhanced-core] + Rotación de los pies
[full-body] + Tracking de codos
*[all] Todas las asignaciones de tracker disponibles
}
## Tracker assignment warnings
@@ -691,69 +795,246 @@ onboarding-assign_trackers-warning-RIGHT_FOOT =
[6] El pie derecho está asignado, pero es necesario que también se asigne el tobillo derecho!
*[other] Pie derecho asignado, pero necesitas asignar Desconocido
}
# $unassigned (Number) - Bits are based on BodyAssignment.ASSIGNMENT_RULES order
onboarding-assign_trackers-warning-LEFT_LOWER_LEG =
{ $unassigned ->
[2] El tobillo izquierdo está asignado, ¡pero necesitas que el muslo izquierdo también lo esté!
[1] El tobillo izquierdo está asignado, ¡pero necesitas que el pecho, la cadera o la cintura también lo estén!
[0] El tobillo izquierdo está asignado, ¡pero necesitas que el muslo izquierdo y el pecho, la cadera o la cintura también lo estén!
*[unknown] El tobillo izquierdo está asignado, ¡pero necesitas que la parte del cuerpo desconocida no asignada también lo esté!
}
# $unassigned (Number) - Bits are based on BodyAssignment.ASSIGNMENT_RULES order
onboarding-assign_trackers-warning-RIGHT_LOWER_LEG =
{ $unassigned ->
[2] El tobillo derecho está asignado, ¡pero necesitas que el muslo derecho también lo esté!
[1] El tobillo derecho está asignado, ¡pero necesitas que el pecho, la cadera o la cintura también lo estén!
[0] El tobillo derecho está asignado, ¡pero necesitas que el muslo derecho y el pecho, la cadera o la cintura también lo estén!
*[unknown] El tobillo derecho está asignado, ¡pero necesitas que la parte del cuerpo desconocida no asignada también lo esté!
}
# $unassigned (Number) - Bits are based on BodyAssignment.ASSIGNMENT_RULES order
onboarding-assign_trackers-warning-LEFT_UPPER_LEG =
{ $unassigned ->
[0] El muslo izquierdo está asignado, ¡pero necesitas que el pecho, la cadera o la cintura también lo estén!
*[unknown] El muslo izquierdo está asignado, ¡pero necesitas que la parte del cuerpo desconocida no asignada también lo esté!
}
# $unassigned (Number) - Bits are based on BodyAssignment.ASSIGNMENT_RULES order
onboarding-assign_trackers-warning-RIGHT_UPPER_LEG =
{ $unassigned ->
[0] El muslo derecho está asignado, ¡pero necesitas que el pecho, la cadera o la cintura también lo estén!
*[unknown] El muslo derecho está asignado, ¡pero necesitas que la parte del cuerpo desconocida no asignada también lo esté!
}
# $unassigned (Number) - Bits are based on BodyAssignment.ASSIGNMENT_RULES order
onboarding-assign_trackers-warning-HIP =
{ $unassigned ->
[0] La cadera está asignada, ¡pero necesitas que el pecho también lo esté!
*[unknown] La cadera está asignada, ¡pero necesitas que la parte del cuerpo desconocida no asignada también lo esté!
}
# $unassigned (Number) - Bits are based on BodyAssignment.ASSIGNMENT_RULES order
onboarding-assign_trackers-warning-WAIST =
{ $unassigned ->
[0] La cintura está asignada, ¡pero necesitas que el pecho también lo esté!
*[unknown] La cintura está asignada, ¡pero necesitas que la parte del cuerpo desconocida no asignada también lo esté!
}
## Tracker mounting method choose
onboarding-choose_mounting = ¿Qué método de calibración de montura usara?
# Multiline text
onboarding-choose_mounting-description = La posición de montura corrige la colocación de los trackers en el cuerpo.
onboarding-choose_mounting-auto_mounting = Calibración de montura automatica
# Italized text
onboarding-choose_mounting-auto_mounting-label = Experimental
onboarding-choose_mounting-auto_mounting-label-v2 = Recomendada
onboarding-choose_mounting-auto_mounting-description = Esto detectará automáticamente la posición de montura para todos sus trackers a partir de 2 poses
onboarding-choose_mounting-manual_mounting = Calibración de montura manual
# Italized text
onboarding-choose_mounting-manual_mounting-label = Recomendado
onboarding-choose_mounting-manual_mounting-label-v2 = Puede que no sea lo suficientemente precisa
onboarding-choose_mounting-manual_mounting-description = Esto te permitirá elegir la posición de montura para cada tracker de manera manual
# Multiline text
onboarding-choose_mounting-manual_modal-title =
¿Está seguro de que desea realizar
la calibración automática de montura?
onboarding-choose_mounting-manual_modal-description = <b>La calibración de montaje manual se recomienda para nuevos usuarios</b>, ya que las poses de la calibración de montaje automática pueden ser difíciles de acertar a la primera y pueden requerir algo de práctica.
onboarding-choose_mounting-manual_modal-confirm = Sé lo que estoy haciendo
onboarding-choose_mounting-manual_modal-cancel = Cancelar
## Tracker manual mounting setup
onboarding-manual_mounting-back = Volver atrás para entrar en VR
onboarding-manual_mounting = Calibración de montura manual
onboarding-manual_mounting-description = Haz clic en cada tracker y selecciona la forma en la que están montados
onboarding-manual_mounting-auto_mounting = Calibración de montura automatica
onboarding-manual_mounting-next = Siguiente paso
## Tracker automatic mounting setup
onboarding-automatic_mounting-back = Volver para entrar en VR
onboarding-automatic_mounting-title = Calibración de montura
onboarding-automatic_mounting-description = Para que los trackers de SlimeVR funcionen, necesitamos asignar una posición de montura a tus trackers para alinearlos con la posicion física del tracker.
onboarding-automatic_mounting-manual_mounting = Calibración de montura manual
onboarding-automatic_mounting-next = Siguiente paso
onboarding-automatic_mounting-prev_step = Paso anterior
onboarding-automatic_mounting-done-title = Posiciones de monturas calibradas.
onboarding-automatic_mounting-done-description = ¡Su calibración de montura está completa!
onboarding-automatic_mounting-done-restart = Volver a intentarlo
onboarding-automatic_mounting-mounting_reset-title = Reinicio de montura
onboarding-automatic_mounting-mounting_reset-step-0 = 1. Ponte en cuclillas en postura de "esquí" con las piernas dobladas, la parte superior del cuerpo inclinada hacia adelante y los brazos doblados.
onboarding-automatic_mounting-mounting_reset-step-1 = 2. Presiona el botón "Restablecer montaje" y espera 3 segundos antes de que se restablezcan las orientaciones de montaje de los trackers.
onboarding-automatic_mounting-preparation-title = Preparación
onboarding-automatic_mounting-preparation-step-0 = 1. Mantente erguido con los brazos a los lados.
onboarding-automatic_mounting-preparation-step-1 = 2. Pulse el botón "Reinicio completo" y espere 3 segundos antes de que los trackers se reinicien.
onboarding-automatic_mounting-put_trackers_on-title = Ponte los trackers
onboarding-automatic_mounting-put_trackers_on-description = Para calibrar la posiciones de montura, vamos a utilizar los trackers que acabas de asignar. Colocate todos tus trackers, puedes ver cuales son cuales en la figura de la derecha.
onboarding-automatic_mounting-put_trackers_on-next = Tengo todos mis trackers en posicion
## Tracker proportions method choose
onboarding-choose_proportions = ¿Qué método de calibración de proporciones utilizara?
# Multiline string
onboarding-choose_proportions-description-v1 =
Las proporciones corporales se utilizaran para conocer las medidas de tu cuerpo. Son necesarias para calcular las posiciones de los trackers.
Cuando las proporciones de tu cuerpo no coincidan con las guardadas, la precisión del tracking será peor y notarás cosas como que patinas o te deslizas, o que tu cuerpo no se ajusta bien a tu avatar.
<b>¡Sólo necesitas medir tu cuerpo una vez!</b> A menos que estén mal o tu cuerpo haya cambiado, entonces no necesitas volver a hacerlo.
onboarding-choose_proportions-auto_proportions = Proporciones automáticas
# Italized text
onboarding-choose_proportions-auto_proportions-subtitle = Recomendado
onboarding-choose_proportions-auto_proportions-descriptionv3 =
Adivinará tus proporciones grabando una muestra de tus movimientos y pasándola por un algoritmo.
<b>¡Esto requiere tener tu visor (HMD) conectado a SlimeVR y en tu cabeza!</b>
onboarding-choose_proportions-manual_proportions = Proporciones manuales
# Italized text
onboarding-choose_proportions-manual_proportions-subtitle = Para pequeños retoques
onboarding-choose_proportions-manual_proportions-description = Esto te permitirá ajustar tus proporciones manualmente modificándolas directamente
onboarding-choose_proportions-export = Exportar proporciones
onboarding-choose_proportions-import = Importar proporciones
onboarding-choose_proportions-import-success = Importado
onboarding-choose_proportions-import-failed = Fallido
onboarding-choose_proportions-file_type = Archivo de proporciones físicas
## Tracker manual proportions setup
onboarding-manual_proportions-back = Volver al tutorial de reinicios
onboarding-manual_proportions-title = Proporciones físicas manuales
onboarding-manual_proportions-precision = Ajuste por precisión
onboarding-manual_proportions-auto = Proporciones automáticas
onboarding-manual_proportions-ratio = Ajustar por grupos de ratio
## Tracker automatic proportions setup
onboarding-automatic_proportions-back = Volver al tutorial de reinicio
onboarding-automatic_proportions-title = Mide tu cuerpo
onboarding-automatic_proportions-description = Para que los trackers de SlimeVR funcionen, necesitamos saber tus proporciones corporales. Esta breve calibración lo medirá por ti.
onboarding-automatic_proportions-manual = Proporciones manuales
onboarding-automatic_proportions-prev_step = Paso anterior
onboarding-automatic_proportions-put_trackers_on-title = Ponte los trackers
onboarding-automatic_proportions-put_trackers_on-description = Para calibrar tus proporciones, vamos a utilizar los trackers que acabas de asignar. Ponte todos tus trackers, puedes ver cuáles son cuáles en la figura de la derecha.
onboarding-automatic_proportions-put_trackers_on-next = Tengo todos mis trackers puestos
onboarding-automatic_proportions-requirements-title = Requisitos
# Each line of text is a different list item
onboarding-automatic_proportions-requirements-descriptionv2 =
Tienes al menos suficientes trackers para trackear tus pies (generalmente 5 trackers).
Los trackers y tu visor están encendidos y los llevas puestos.
Tus trackers y visor está conectados al servidor de SlimeVR y funcionan correctamente (ej. sin cortes, sin desconexiones, etc).
Tu visor están reportando datos de posición al servidor de SlimeVR (esto generalmente significa tener SteamVR ejecutándose y conectado a SlimeVR usando el driver para SteamVR de SlimeVR).
Su tracking está funcionando y está representando con precisión sus movimientos (ej. usted ha realizado un reinicio completo y se mueven en la dirección correcta al patear, agacharse, sentarse, etc).
onboarding-automatic_proportions-requirements-next = He leído los requisitos
onboarding-automatic_proportions-check_height-title = Comprueba tu altura
onboarding-automatic_proportions-check_height-description = Utilizamos tu estatura como base de nuestras mediciones utilizando la altura de tu visor (HMD) como aproximación a tu estatura real, ¡pero es mejor que compruebes tú mismo si son correctas!
# All the text is in bold!
onboarding-automatic_proportions-check_height-calculation_warning = Por favor, pulse el botón mientras esté <u>derecho</u> para calcular su altura. ¡Tienes 3 segundos después de pulsar el botón!
onboarding-automatic_proportions-check_height-guardian_tip =
Si usted está usando un visor VR standalone, ¡asegúrese de tener su guardián /
limite activado para que tu altura sea la correcta!
onboarding-automatic_proportions-check_height-fetch_height = ¡Estoy de pie!
# Context is that the height is unknown
onboarding-automatic_proportions-check_height-unknown = Desconocida
# Shows an element below it
onboarding-automatic_proportions-check_height-hmd_height1 = La altura de tu HMD es
# Shows an element below it
onboarding-automatic_proportions-check_height-height1 = por lo que tu altura real es
onboarding-automatic_proportions-check_height-next_step = Están bien
onboarding-automatic_proportions-start_recording-title = Prepárate para moverte
onboarding-automatic_proportions-start_recording-description = Ahora vamos a grabar algunas poses y movimientos específicos. Se le indicarán en la siguiente pantalla. ¡Prepárate para empezar cuando pulse el botón!
onboarding-automatic_proportions-start_recording-next = Iniciar grabación
onboarding-automatic_proportions-recording-title = REC
onboarding-automatic_proportions-recording-description-p0 = Grabación en curso...
onboarding-automatic_proportions-recording-description-p1 = Realiza los movimientos que se muestran a continuación:
# Each line of text is a different list item
onboarding-automatic_proportions-recording-steps =
Parado derecho, gira tu cabeza en un circulo.
Dobla la espalda hacia delante y ponte en cuclillas. En cuclillas, mira a la izquierda y luego a la derecha.
Gira la parte superior de tu cuerpo hacia la izquierda (en el sentido contrario a las agujas del reloj) y luego estira los brazos hacia el suelo.
Gira la parte superior de tu cuerpo hacia la derecha (en el sentido de las agujas del reloj) y luego estira los brazos hacia el suelo.
Gira las caderas en un movimiento circular como si estuvieras usando un aro redondo.
Si queda tiempo de grabación, puedes repetir estos pasos hasta que termine.
onboarding-automatic_proportions-recording-processing = Procesando los resultados
# $time (Number) - Seconds left for the automatic calibration recording to finish (max 20)
onboarding-automatic_proportions-recording-timer =
{ $time ->
[one] Queda 1 segundo
*[other] Quedan { $time } segundos
}
onboarding-automatic_proportions-verify_results-title = Verificar resultados
onboarding-automatic_proportions-verify_results-description = Revisa los resultados a continuación, ¿Son correctos?
onboarding-automatic_proportions-verify_results-results = Resultados de la grabación
onboarding-automatic_proportions-verify_results-processing = Procesando los resultados
onboarding-automatic_proportions-verify_results-redo = Rehacer la grabación
onboarding-automatic_proportions-verify_results-confirm = Estan correctas
onboarding-automatic_proportions-done-title = Proporciones medidas y guardadas.
onboarding-automatic_proportions-done-description = ¡Calibración de las proporciones físicas completada!
onboarding-automatic_proportions-error_modal =
<b>Atención:</b> ¡Se ha encontrado un error al estimar las proporciones!
Por favor <docs>comprueba la documentación</docs> o únete a nuestro <discord>Discord</discord> para obtener ayuda ^_^
onboarding-automatic_proportions-error_modal-confirm = ¡Entendido!
## Home
home-no_trackers = No se han detectado ni asignado trackers
## Trackers Still On notification
trackers_still_on-modal-title = Los trackers siguen encendidos
trackers_still_on-modal-description =
Uno o más trackers siguen encendidos.
Aún quieres salir de SlimeVR?
trackers_still_on-modal-confirm = Salir de SlimeVR
trackers_still_on-modal-cancel = Un momento...
## Status system
status_system-StatusTrackerReset = Se recomienda realizar un reinicio completo ya que uno o más trackers están desajustados.
status_system-StatusSteamVRDisconnected =
{ $type ->
[steamvr_feeder] Actualmente no está conectado a la SlimeVR Feeder App.
*[steamvr] Actualmente no está conectado a SteamVR a través del controlador de SlimeVR.
}
status_system-StatusTrackerError = El tracker { $trackerName } tiene un error.
status_system-StatusUnassignedHMD = El casco de RV debe asignarse como tracker de cabeza.
## Tray Menu
tray_menu-show = Mostrar
tray_menu-hide = Ocultar
tray_menu-quit = Salir
## First exit modal
tray_or_exit_modal-title = ¿Qué debe hacer el botón de cierre?
# Multiline text
tray_or_exit_modal-description =
Esto te permite elegir si quieres salir de la aplicación o minimizarlo a la bandeja al pulsar el botón de cerrar.
¡Puedes cambiar esto más tarde en la configuración de la interfaz!
tray_or_exit_modal-radio-exit = Salir al cerrar
tray_or_exit_modal-radio-tray = Minimizar a la bandeja
tray_or_exit_modal-submit = Guardar
tray_or_exit_modal-cancel = Cancelar
## Unknown device modal
unknown_device-modal-title = ¡Se ha encontrado un nuevo tracker!
unknown_device-modal-description =
Hay un nuevo tracker con dirección MAC <b>{ $deviceId }</b>.
¿Quieres conectarlo a SlimeVR?
unknown_device-modal-confirm = ¡Claro!
unknown_device-modal-forget = Ignóralo

View File

@@ -196,6 +196,7 @@ tracker-infos-hardware_rev = Laitteston Tarkistus
tracker-infos-hardware_identifier = Laitteiston ID
tracker-infos-imu = IMU-Sensor
tracker-infos-board_type = Päälevy
tracker-infos-network_version = Protokollan versio
## Tracker settings
@@ -304,10 +305,16 @@ settings-general-steamvr-description =
Hyödyllinen peleille tai sovelluksille, jotka tukevat vain tiettyjä jäljittimiä.
settings-general-steamvr-trackers-waist = Vyötärö
settings-general-steamvr-trackers-chest = Rinta
settings-general-steamvr-trackers-feet = Jalat
settings-general-steamvr-trackers-knees = Polvet
settings-general-steamvr-trackers-elbows = Kyynärpäät
settings-general-steamvr-trackers-hands = Kädet
settings-general-steamvr-trackers-left_foot = Vasen jalkaterä
settings-general-steamvr-trackers-right_foot = Oikea jalkaterä
settings-general-steamvr-trackers-left_knee = Vasen polvi
settings-general-steamvr-trackers-right_knee = Oikea polvi
settings-general-steamvr-trackers-left_elbow = Vasen kyynärpää
settings-general-steamvr-trackers-right_elbow = Oikea kyynärpää
settings-general-steamvr-trackers-left_hand = Vasen käsi
settings-general-steamvr-trackers-right_hand = Oikea käsi
settings-general-steamvr-trackers-hands-warning-cancel = Peruuta
settings-general-steamvr-trackers-hands-warning-done = Kyllä
## Tracker mechanics
@@ -359,6 +366,8 @@ settings-general-fk_settings-leg_fk-reset_mounting_feet = Jalkojen asennuksen no
settings-general-fk_settings-arm_fk = Käsivarsien jäljitys
settings-general-fk_settings-arm_fk-description = Muuta tapaa, jolla käsivarsia jäljitetään.
settings-general-fk_settings-arm_fk-force_arms = Pakota kädet HMD:ltä
settings-general-fk_settings-reset_settings = Palauta asetukset
settings-general-fk_settings-reset_settings-reset_hmd_pitch = Nollaa HMD-sävelkorkeus
settings-general-fk_settings-arm_fk-reset_mode-description = Muuta, mikä käsivarren asentoa odotetaan asennuksen nollaukselle.
settings-general-fk_settings-arm_fk-back = Takaisin
settings-general-fk_settings-arm_fk-tpose_up = T-asento (ylös)
@@ -446,6 +455,12 @@ settings-general-interface-feedback_sound-label = Palaute ääni
settings-general-interface-feedback_sound-volume = Palaute äänen voimakkuus
settings-general-interface-connected_trackers_warning = Yhdistettyjen jäljittimien varoitus
settings-general-interface-connected_trackers_warning-description = Tämä vaihtoehto näyttää ponnahdusikkunan aina, kun yrität poistua SlimeVR:stä, kun sinulla on yksi tai useampi yhdistetty jäljitin. Se muistuttaa sinua sammuttamaan jäljittimet, kun olet valmis, akun käyttöiän säästämiseksi.
settings-general-interface-use_tray = Pienennä ilmaisinalueelle
settings-general-interface-use_tray-description = Voit sulkea ikkunan sulkematta SlimeVR-palvelinta, jotta voit jatkaa sen käyttöä ilman, että graafinen käyttöliittymä häiritsee sinua.
settings-general-interface-use_tray-label = Pienennä ilmaisinalueelle
settings-general-interface-discord_presence = Jaa toiminta Discordissa
settings-general-interface-discord_presence-description = Kertoo Discordille, että käytät SlimeVR:ää, sekä käyttämiesi IMU-seurantalaitteiden määrän.
settings-general-interface-discord_presence-label = Jaa toiminta Discordissa
## Serial settings
@@ -467,6 +482,8 @@ settings-serial-factory_reset-warning-cancel = Peruuta
settings-serial-get_infos = Hanki tietoja
settings-serial-serial_select = Valitse sarjaportti
settings-serial-auto_dropdown_item = Autom.
settings-serial-file_type = Teksti
settings-serial-save_logs = Tallenna tiedostoon
## OSC router settings
@@ -496,15 +513,11 @@ settings-osc-router-network-address-placeholder = IPV4-osoite
## OSC VRChat settings
settings-osc-vrchat = VRChat OSC -jäljittimet
# This cares about multilines
settings-osc-vrchat-description =
Muuta VRChat-kohtaisia asetuksia vastaanottamaan HMD-dataa ja
lähettämään jäljitindataa FBT:tä varten (toimii Quest-standalone:ssa).
settings-osc-vrchat-enable = Käytä
settings-osc-vrchat-enable-description = Vaihda tietojen lähettäminen ja vastaanottaminen.
settings-osc-vrchat-enable-label = Käytä
settings-osc-vrchat-network = Verkkoportit
settings-osc-vrchat-network-description = Aseta portit kuuntelua ja tietojen lähettämistä varten VRChatiin.
settings-osc-vrchat-network-description-v1 = Aseta portit tietojen kuuntelua ja lähettämistä varten. Voidaan jättää koskematta VRChatille.
settings-osc-vrchat-network-port_in =
.label = Portti sisään
.placeholder = Portti sisään (oletus: 9001)
@@ -512,7 +525,7 @@ settings-osc-vrchat-network-port_out =
.label = Portti ulos
.placeholder = Portti ulos (oletus: 9000)
settings-osc-vrchat-network-address = Verkon osoite
settings-osc-vrchat-network-address-description = Valitse, mi osoite lähettää tietoja VRChatiin (tarkista laitteesi Wi-Fi-asetukset).
settings-osc-vrchat-network-address-description-v1 = Valitse, mihin osoitteeseen tiedot lähetetään. Voidaan jättää koskematta VRChatille.
settings-osc-vrchat-network-address-placeholder = VRChat IP-osoite
settings-osc-vrchat-network-trackers = Jäljittimet
settings-osc-vrchat-network-trackers-description = Vaihda tiettyjen jäljittimien lähettäminen OSC:n kautta.
@@ -632,8 +645,6 @@ onboarding-done-close = Sulje opas
onboarding-connect_tracker-back = Palaa Wi-Fi-tunnistetietoihin
onboarding-connect_tracker-title = Yhdistä jäljittimet
onboarding-connect_tracker-description-p0 = Nyt hauskaan osaan, kaikkien jäljittimien yhdistämiseen!
onboarding-connect_tracker-description-p1 = Yhdistä vain kaikki, joita ei ole vielä yhdistetty, USB-portin kautta.
onboarding-connect_tracker-issue-serial = Minulla on ongelmia yhteyden muodostamisessa!
onboarding-connect_tracker-usb = USB-jäljitin
onboarding-connect_tracker-connection_status-none = Etsitään jäljittimiä
@@ -768,12 +779,8 @@ onboarding-choose_mounting = Mitä asennuskalibrointimenetelmää käytetään?
# Multiline text
onboarding-choose_mounting-description = Asennussuuntaus korjaa jäljittimien sijoittelun kehossasi.
onboarding-choose_mounting-auto_mounting = Automaattinen asennus
# Italized text
onboarding-choose_mounting-auto_mounting-label = Kokeellinen
onboarding-choose_mounting-auto_mounting-description = Tämä tunnistaa automaattisesti kaikkien jäljittimiesi asennussuunnat 2 asennosta
onboarding-choose_mounting-manual_mounting = Manuaalinen asennus
# Italized text
onboarding-choose_mounting-manual_mounting-label = Suositeltu
onboarding-choose_mounting-manual_mounting-description = Näin voit valita asennussuunnan manuaalisesti kullekin jäljittimelle
# Multiline text
onboarding-choose_mounting-manual_modal-title =
@@ -895,3 +902,12 @@ status_system-StatusSteamVRDisconnected =
*[other] Tällä hetkellä ei ole yhdistetty SteamVR:ään SlimeVR-ajurin kautta.
}
status_system-StatusTrackerError = { $trackerName } jäljittimessä on virhe
## Tray Menu
## First exit modal
## Unknown device modal

View File

@@ -310,10 +310,14 @@ settings-general-steamvr-description =
Utile pour les jeux ou applications qui ne supportent que certains capteurs.
settings-general-steamvr-trackers-waist = Taille
settings-general-steamvr-trackers-chest = Poitrine
settings-general-steamvr-trackers-feet = Pieds
settings-general-steamvr-trackers-knees = Genoux
settings-general-steamvr-trackers-elbows = Coudes
settings-general-steamvr-trackers-hands = Mains
settings-general-steamvr-trackers-left_foot = Pied gauche
settings-general-steamvr-trackers-right_foot = Pied droit
settings-general-steamvr-trackers-left_knee = Genou gauche
settings-general-steamvr-trackers-right_knee = Genou droit
settings-general-steamvr-trackers-left_elbow = Coude gauche
settings-general-steamvr-trackers-right_elbow = Coude droit
settings-general-steamvr-trackers-left_hand = Main gauche
settings-general-steamvr-trackers-right_hand = Main droite
settings-general-steamvr-trackers-tracker_toggling = Assignation automatique des capteurs
settings-general-steamvr-trackers-tracker_toggling-description = Gère automatiquement lactivation ou la désactivation des capteurs SteamVR en fonction de vos capteurs actuellement affectés
settings-general-steamvr-trackers-tracker_toggling-label = Assignation automatique des capteurs
@@ -379,6 +383,9 @@ settings-general-fk_settings-leg_fk-reset_mounting_feet = Réinitialisation de l
settings-general-fk_settings-arm_fk = Capture des bras
settings-general-fk_settings-arm_fk-description = Changez la façon dont les bras sont captés.
settings-general-fk_settings-arm_fk-force_arms = Forcer les bras en provenance du casque VR
settings-general-fk_settings-reset_settings = Paramètres de réinitialisations
settings-general-fk_settings-reset_settings-reset_hmd_pitch-description = Réinitialisez la rotation verticale du casque VR lors dune réinitialisation complète. Utile pour porter un casque VR sur le front pour le VTubing ou l'animation. Ne pas activer pour la VR.
settings-general-fk_settings-reset_settings-reset_hmd_pitch = Réinitialiser la rotation verticale du casque VR
settings-general-fk_settings-arm_fk-reset_mode-description = Changer la pose des bras attendue pour la réinitialisation de l'alignement.
settings-general-fk_settings-arm_fk-back = En arrière
settings-general-fk_settings-arm_fk-back-description = Le mode par défaut, avec les bras vers larrière et les avant-bras vers lavant.
@@ -475,6 +482,15 @@ settings-general-interface-connected_trackers_warning-label = Avertissement de c
settings-general-interface-use_tray = Minimiser dans la zone de notifications
settings-general-interface-use_tray-description = Vous permet de fermer la fenêtre sans fermer le serveur SlimeVR afin que vous puissiez continuer à lutiliser sans linterface graphique.
settings-general-interface-use_tray-label = Minimiser dans la zone de notifications
settings-general-interface-discord_presence = Partager l'activité sur Discord
settings-general-interface-discord_presence-description = Indique à votre client Discord que vous utilisez SlimeVR avec le nombre de capteurs IMU que vous utilisez.
settings-general-interface-discord_presence-label = Partager l'activité sur Discord
settings-general-interface-discord_presence-message =
{ $amount ->
[0] Aucun capteur
[one] Utilise { $amount } capteur
*[other] Utilise { $amount } capteurs
}
## Serial settings
@@ -497,6 +513,8 @@ settings-serial-get_infos = Obtenir des informations
settings-serial-serial_select = Sélectionnez un port série
settings-serial-auto_dropdown_item = Automatique
settings-serial-get_wifi_scan = Obtenir scan WiFi
settings-serial-file_type = Texte brut
settings-serial-save_logs = Enregistrer dans un fichier
## OSC router settings
@@ -527,14 +545,17 @@ settings-osc-router-network-address-placeholder = Adresse IPv4
settings-osc-vrchat = Capteurs OSC VRChat
# This cares about multilines
settings-osc-vrchat-description =
Modifiez les paramètres spécifiques à VRChat pour recevoir et envoyer
des capteurs par OSC (fonctionne sur Quest sans PC).
settings-osc-vrchat-description-v1 =
Modifier les paramètres spécifiques à la norme « OSC Trackers » utilisée pour lenvoi
des données de suivi vers des applications sans SteamVR (par exemple, sur Quest).
Assurez-vous dactiver le protocole OSC dans VRChat via le menu d'action (rond) sous OSC > Enabled.
Pour permettre de recevoir les données de suivi du casque VR et des manettes à partir de VRChat,
allez dans le menu principal sous Tracking & IK > Allow Sending Head and Wrist VR Tracking OSC Data.
settings-osc-vrchat-enable = Activer
settings-osc-vrchat-enable-description = Activer/désactiver l'envoi et la réception de données.
settings-osc-vrchat-enable-label = Activer
settings-osc-vrchat-network = Ports réseau
settings-osc-vrchat-network-description = Définissez les ports pour écouter et envoyer des données à VRChat.
settings-osc-vrchat-network-description-v1 = Définissez les ports d'écoute et d'envoi des données. Peut être laissé intact pour VRChat.
settings-osc-vrchat-network-port_in =
.label = Port d'entrée
.placeholder = Port d'entrée (par défaut : 9001)
@@ -542,7 +563,7 @@ settings-osc-vrchat-network-port_out =
.label = Port de sortie
.placeholder = Port de sortie (par défaut : 9000)
settings-osc-vrchat-network-address = Adresse réseau
settings-osc-vrchat-network-address-description = Choisissez l'adresse à laquelle envoyer les données à VRChat (vérifiez les réseaux Wi-Fi de votre appareil).
settings-osc-vrchat-network-address-description-v1 = Choisissez l'adresse à laquelle envoyer des données. Peut être laissé intact pour VRChat.
settings-osc-vrchat-network-address-placeholder = Adresse IP VRChat
settings-osc-vrchat-network-trackers = capteurs
settings-osc-vrchat-network-trackers-description = Sélectionner quels capteurs envoyer via OSC.
@@ -585,6 +606,9 @@ settings-osc-vmc-vrm-file_select = Glissez et déposez un modèle à utiliser, o
settings-osc-vmc-anchor_hip = Ancrage aux hanches
settings-osc-vmc-anchor_hip-description = Ancrer la capture des mouvements aux hanches, utile pour le VTubing assis.
settings-osc-vmc-anchor_hip-label = Ancrage aux hanches
settings-osc-vmc-mirror_tracking = Inverser les mouvements
settings-osc-vmc-mirror_tracking-description = Inverse les mouvements horizontalement
settings-osc-vmc-mirror_tracking-label = Inverser les mouvements
## Setup/onboarding menu
@@ -724,6 +748,27 @@ onboarding-assign_trackers-assigned =
onboarding-assign_trackers-advanced = Afficher les emplacements d'attribution avancés
onboarding-assign_trackers-next = J'ai attribué tous mes capteurs
onboarding-assign_trackers-mirror_view = Vue miroir
onboarding-assign_trackers-option-amount =
{ $trackersCount ->
[one] x{ $trackersCount }
*[other] x{ $trackersCount }
}
onboarding-assign_trackers-option-label =
{ $mode ->
[lower-body] Kit du bas du corps
[core] Kit de base
[enhanced-core] Kit de base renforcé
[full-body] Kit du corps complet
*[all] Tous les capteurs
}
onboarding-assign_trackers-option-description =
{ $mode ->
[lower-body] Minimum pour le suivi du corps en réalité virtuelle
[core] + Suivi amélioré de la colonne vertébrale
[enhanced-core] + Rotation des pieds
[full-body] + Suivi des coudes
*[all] Toutes les attributions de capteurs disponibles
}
## Tracker assignment warnings
@@ -800,11 +845,11 @@ onboarding-choose_mounting = Quelle méthode de calibration de lalignement ut
onboarding-choose_mounting-description = La calibration de l'alignement ajuste pour l'orientation des capteurs sur votre corps.
onboarding-choose_mounting-auto_mounting = Alignement automatique
# Italized text
onboarding-choose_mounting-auto_mounting-label = Expérimentale
onboarding-choose_mounting-auto_mounting-label-v2 = Recommendée
onboarding-choose_mounting-auto_mounting-description = Ceci permettra de détecter automatiquement la direction de tous vos capteurs à partir de 2 poses
onboarding-choose_mounting-manual_mounting = Alignement manuel
# Italized text
onboarding-choose_mounting-manual_mounting-label = Recommendée
onboarding-choose_mounting-manual_mounting-label-v2 = Peut manquer de précision
onboarding-choose_mounting-manual_mounting-description = Ceci vous permettra de choisir la direction de chaque capteur manuellement
# Multiline text
onboarding-choose_mounting-manual_modal-title =
@@ -966,6 +1011,7 @@ status_system-StatusSteamVRDisconnected =
*[other] Impossible de se connecter à SteamVR via le pilote SlimeVR.
}
status_system-StatusTrackerError = Le capteur { $trackerName } a une erreur.
status_system-StatusUnassignedHMD = Le casque VR devrait être attribué en tant que capteur de la tête.
## Tray Menu

View File

@@ -381,6 +381,9 @@ settings-general-fk_settings-leg_fk-reset_mounting_feet = Reset posizionamento d
settings-general-fk_settings-arm_fk = Tracking delle braccia
settings-general-fk_settings-arm_fk-description = Forza il calcolo della posizione delle braccia a utilizzare il visore anche se la posizione delle mani é disponibile.
settings-general-fk_settings-arm_fk-force_arms = Forza il calcolo delle braccia dal visore
settings-general-fk_settings-reset_settings = Ripristina impostazioni
settings-general-fk_settings-reset_settings-reset_hmd_pitch-description = Ripristina l'inclinazione dell'HMD (rotazione verticale) dopo un reset completo. Utile se si indossa un HMD sulla fronte per VTubing o mocap. Non abilitare per VR.
settings-general-fk_settings-reset_settings-reset_hmd_pitch = Ripristina l'inclinazione dell'HMD
settings-general-fk_settings-arm_fk-reset_mode-description = Cambia la posa delle braccia usata per il reset posizionamento.
settings-general-fk_settings-arm_fk-back = Indietro
settings-general-fk_settings-arm_fk-back-description = La modalità predefinita, con la parte superiori delle braccia che vanno indietro e le parte inferiori delle braccia che vanno avanti.
@@ -478,6 +481,15 @@ settings-general-interface-connected_trackers_warning-label = Avviso di tracker
settings-general-interface-use_tray = Riduci a icona nella barra delle applicazioni
settings-general-interface-use_tray-description = Ti consente di chiudere la finestra senza chiudere il server SlimeVR in modo da poter continuare a usarlo senza che la GUI ti infastidisca.
settings-general-interface-use_tray-label = Riduci a icona nella barra delle applicazioni
settings-general-interface-discord_presence = Condividi attività su Discord
settings-general-interface-discord_presence-description = Dice al tuo client di Discord che stai utilizzando SlimeVR insieme al numero di tracker IMU che stai utilizzando.
settings-general-interface-discord_presence-label = Condividi attività su Discord
settings-general-interface-discord_presence-message =
{ $amount ->
[0] Slimeggiando qua e là
[one] Sta usando 1 tracker
*[other] Sta usando { $amount } tracker
}
## Serial settings
@@ -500,6 +512,8 @@ settings-serial-get_infos = Ottieni informazioni
settings-serial-serial_select = Seleziona una porta seriale
settings-serial-auto_dropdown_item = Automatico
settings-serial-get_wifi_scan = Elenca WiFi Network
settings-serial-file_type = Testo normale
settings-serial-save_logs = Salva su file
## OSC router settings
@@ -530,14 +544,17 @@ settings-osc-router-network-address-placeholder = Indirizzo IPV4
settings-osc-vrchat = Tracker OSC per VRChat
# This cares about multilines
settings-osc-vrchat-description =
Modifica le impostazioni specifiche a VRChat per ricevere e inviare dati del HMD
Dati dei tracker per FBT (funziona su Quest standalone).
settings-osc-vrchat-description-v1 =
Modifica impostazioni specifiche dello standard dei Tracker OSC utilizzato per l'invio
di dati di tracciamento alle applicazioni senza l'utlizzo di SteamVR (es. Quest standalone).
Assicurarsi di abilitare l'OSC in VRChat tramite il menu Azione alla voce OSC > Abilitato.
Per consentire la ricezione dei dati dell'HMD e del controller da VRChat, vai nella sezione impostazioni del menu principale
in Tracciamento e IK > Consenti invio dati OSC tracciamento VR testa e polso.
settings-osc-vrchat-enable = Attiva
settings-osc-vrchat-enable-description = Attiva o disattiva l'invio e la ricezione dei dati
settings-osc-vrchat-enable-label = Attiva
settings-osc-vrchat-network = Porte di rete
settings-osc-vrchat-network-description = Impostare le porte di rete per ascoltare e inviare dati a VRChat
settings-osc-vrchat-network-description-v1 = Imposta le porte per l'ascolto e l'invio dei dati. Può essere lasciato come predefinito per utilizzo con VRChat.
settings-osc-vrchat-network-port_in =
.label = Porta in ingresso
.placeholder = Porta in ingresso (predefinito: 9002)
@@ -545,7 +562,7 @@ settings-osc-vrchat-network-port_out =
.label = Porta in uscita
.placeholder = Porta in uscita (predefinito: 9000)
settings-osc-vrchat-network-address = Indirizzo di rete
settings-osc-vrchat-network-address-description = Scegli a quale indirizzo di rete inviare i dati di VRChat (controlla le impostazioni Wi-Fi sul tuo dispositivo)
settings-osc-vrchat-network-address-description-v1 = Scegli a quale indirizzo inviare i dati. Può essere lasciato come predefinito per utilizzo con VRChat.
settings-osc-vrchat-network-address-placeholder = Indirizzo IP di VRChat
settings-osc-vrchat-network-trackers = Tracker
settings-osc-vrchat-network-trackers-description = Attiva o disattiva l'invio e la ricezione dei dati
@@ -588,6 +605,9 @@ settings-osc-vmc-vrm-file_select = Trascina qui un modello da usare, o <u>sfogli
settings-osc-vmc-anchor_hip = Ancoraggio sul bacino
settings-osc-vmc-anchor_hip-description = Ancora la posizione del tracciamento del bacino; utile per VTubing da seduti. Se disabilitato, carica un modello VRM.
settings-osc-vmc-anchor_hip-label = Ancoraggio sul bacino
settings-osc-vmc-mirror_tracking = Tracciamento speculare
settings-osc-vmc-mirror_tracking-description = Specchia il tracciamento orizzontalmente.
settings-osc-vmc-mirror_tracking-label = Tracciamento speculare
## Setup/onboarding menu
@@ -727,6 +747,27 @@ onboarding-assign_trackers-assigned =
onboarding-assign_trackers-advanced = Mostra impostazioni avanzate di assegnazione
onboarding-assign_trackers-next = Ho assegnato tutti i miei tracker
onboarding-assign_trackers-mirror_view = Inverti interfaccia
onboarding-assign_trackers-option-amount =
{ $trackersCount ->
[one] x{ $trackersCount }
*[other] x{ $trackersCount }
}
onboarding-assign_trackers-option-label =
{ $mode ->
[lower-body] Pacchetto "Lower-Body"
[core] Pacchetto "Core"
[enhanced-core] Pacchetto "Enhanced Core"
[full-body] Pacchetto "Full-Body"
*[all] Tutti i tracker
}
onboarding-assign_trackers-option-description =
{ $mode ->
[lower-body] Il minimo per full-body tracking in VR
[core] + Miglior tracciamento della spina dorsale
[enhanced-core] + Rotazione dei piedi
[full-body] + Tracciamento dei gomiti
*[all] Tutte le assegnazioni di tracker disponibili
}
## Tracker assignment warnings
@@ -803,11 +844,11 @@ onboarding-choose_mounting = Quale metodo di calibrazione del posizionamento vuo
onboarding-choose_mounting-description = L'orientamento di posizionamento corregge la posizione dei tracker sul corpo.
onboarding-choose_mounting-auto_mounting = Posizionamento automatico
# Italized text
onboarding-choose_mounting-auto_mounting-label = Sperimentale
onboarding-choose_mounting-auto_mounting-label-v2 = Raccomandato
onboarding-choose_mounting-auto_mounting-description = Questo processo identificherá automaticamente le direzioni per la posizione di montaggio di tutti i traker facendo 2 pose
onboarding-choose_mounting-manual_mounting = Posizionamento manuale
# Italized text
onboarding-choose_mounting-manual_mounting-label = Raccomandato
onboarding-choose_mounting-manual_mounting-label-v2 = Potrebbe non essere abbastanza preciso
onboarding-choose_mounting-manual_mounting-description = Questo processo ti lascerá scegliere manualmente le direzioni per la posizione di montaggio di tutti i tracker
# Multiline text
onboarding-choose_mounting-manual_modal-title =
@@ -970,6 +1011,7 @@ status_system-StatusSteamVRDisconnected =
*[other] Attualmente non è connesso a SteamVR tramite il driver SlimeVR.
}
status_system-StatusTrackerError = Il tracker { $trackerName } ha un errore.
status_system-StatusUnassignedHMD = Il visore deve essere assegnato come tracker della testa.
## Tray Menu

View File

@@ -23,6 +23,8 @@ tips-find_tracker = どのトラッカーがどれだかわからない?トラ
tips-do_not_move_heels = レコーディング中にかかとが動かないように注意しましょう!
tips-file_select = 使用するファイルをドラッグ&ドロップするか、 <u>参照</u>します。
tips-tap_setup = 追跡装置をゆっくり2回軽くタップして選択することができます、メニューから選ぶ必要はありません
tips-turn_on_tracker = SlimeVRの公式トラッカーを使っていますかトラッカーをPCに接続した後は<b><em>必ず電源を入れて</em></b>ください!
tips-failed_webgl = WebGLの初期化に失敗しました。
## Body parts
@@ -161,8 +163,8 @@ tracker-status-timed_out = タイムアウト
## Tracker status columns
tracker-table-column-name = Name
tracker-table-column-type = Type
tracker-table-column-name = 名前
tracker-table-column-type = タイプ
tracker-table-column-battery = バッテリー
tracker-table-column-ping = Ping
tracker-table-column-tps = TPS
@@ -196,6 +198,7 @@ tracker-infos-hardware_rev = ハードウエアのリビジョン
tracker-infos-hardware_identifier = ハードウェアID
tracker-infos-imu = 慣性計測センサー
tracker-infos-board_type = メインボード
tracker-infos-network_version = プロトコル・バージョン
## Tracker settings
@@ -215,6 +218,8 @@ tracker-settings-drift_compensation_section-edit = ドリフト補正を行う
tracker-settings-name_section = トラッカー名称
tracker-settings-name_section-description = 自由に名称をつけてください
tracker-settings-name_section-placeholder = NightyBeast's left leg
tracker-settings-forget = フォーゲット・トラッカー
tracker-settings-forget-label = フォーゲット・トラッカー
## Tracker part card info
@@ -302,10 +307,8 @@ settings-general-steamvr-description =
SlimeVRが行うことをよりコントロールしたい場合に便利です。
settings-general-steamvr-trackers-waist = 腰
settings-general-steamvr-trackers-chest = 胸
settings-general-steamvr-trackers-feet = 足
settings-general-steamvr-trackers-knees =
settings-general-steamvr-trackers-elbows = 肘
settings-general-steamvr-trackers-hands = 手
settings-general-steamvr-trackers-hands-warning-cancel = キャンセル
settings-general-steamvr-trackers-hands-warning-done = はい
## Tracker mechanics
@@ -390,6 +393,9 @@ settings-general-gesture_control-taps =
[one] 1 tap
*[other] { $amount } タップ
}
# This is a unit: 3 trackers, 2 trackers, 1 tracker
# $amount (Number) - Amount of trackers
settings-general-gesture_control-trackers = { $amount } トラッカー
settings-general-gesture_control-yawResetEnabled = タップによるヨーリセットを有効にします
settings-general-gesture_control-yawResetDelay = ヨーリセット遅延
settings-general-gesture_control-yawResetTaps = ヨーリセット用のタップ
@@ -402,6 +408,7 @@ settings-general-gesture_control-mountingResetTaps = タップによるマウン
## Appearance settings
settings-interface-appearance = 外観
settings-general-interface-dev_mode = 開発者モード
settings-general-interface-dev_mode-description = このモードは、詳細なデータが必要な場合や、接続されたトラッカーをより高度なレベルで操作する場合に役立ちます。
settings-general-interface-dev_mode-label = 開発者モード
@@ -411,7 +418,9 @@ settings-general-interface-lang-description = 使用したいデフォルトの
settings-general-interface-lang-placeholder = 使用する言語を選択する
# Keep the font name untranslated
settings-interface-appearance-font = GUIフォント
settings-interface-appearance-font-placeholder = デフォルトフォント
settings-interface-appearance-font-os_font = OSフォント
settings-interface-appearance-font-slime_font = デフォルトフォント
## Notification settings
@@ -422,6 +431,8 @@ settings-general-interface-serial_detection-label = シリアルデバイスの
settings-general-interface-feedback_sound = フィードバック音
settings-general-interface-feedback_sound-label = フィードバック音
settings-general-interface-feedback_sound-volume = フィードバック音量
settings-general-interface-connected_trackers_warning = 接続されたトラッカー警告
settings-general-interface-use_tray-label = システムトレイに最小化する
## Serial settings
@@ -467,15 +478,10 @@ settings-osc-router-network-address-placeholder = IPV4アドレス
## OSC VRChat settings
settings-osc-vrchat = VRChat OSCトラッカー
# This cares about multilines
settings-osc-vrchat-description =
HMDのデータを受信して送信するためにVRChat固有の設定を変更する。
FBT用のトラッカーデータQuestスタンドアロンで動作します
settings-osc-vrchat-enable = 有効
settings-osc-vrchat-enable-description = データの送受信を切り替える。
settings-osc-vrchat-enable-label = 有効
settings-osc-vrchat-network = ネットワークポート
settings-osc-vrchat-network-description = VRChatへのデータを送受信するためのポートを設定します。
settings-osc-vrchat-network-port_in =
.label = ポートイン
.placeholder = ポートイン (デフォルト: 9001)
@@ -483,7 +489,6 @@ settings-osc-vrchat-network-port_out =
.label = ポートアウト
.placeholder = ポートアウト (デフォルト: 9000)
settings-osc-vrchat-network-address = ネットワークアドレス
settings-osc-vrchat-network-address-description = VRChatにデータを送信するアドレスを選択してくださいデバイスのWi-Fi設定を確認してください
settings-osc-vrchat-network-address-placeholder = VRChatのIPアドレス
settings-osc-vrchat-network-trackers = トラッカー
settings-osc-vrchat-network-trackers-description = データの送受信を切り替える。
@@ -587,7 +592,9 @@ onboarding-connect_tracker-next = すべてのトラッカーを接続しまし
onboarding-calibration_tutorial = IMU校正チュートリアル
onboarding-calibration_tutorial-subtitle = これにより、センサーのドリフトを減らすことが役立ちます
onboarding-calibration_tutorial-status-waiting = あなたを待っている...
onboarding-calibration_tutorial-status-calibrating = 校正中
onboarding-calibration_tutorial-status-success = ナイス!
## Tracker assignment tutorial
@@ -615,8 +622,7 @@ onboarding-assign_trackers-next = すべてのトラッカーを割り当てま
## Tracker mounting method choose
# Italized text
onboarding-choose_mounting-auto_mounting-label = 実験的な
onboarding-choose_mounting-manual_modal-cancel = キャンセル
## Tracker manual mounting setup
@@ -651,6 +657,7 @@ onboarding-automatic_mounting-put_trackers_on-next = すべてのトラッカー
# Italized text
onboarding-choose_proportions-auto_proportions-subtitle = おすすめされた
onboarding-choose_proportions-import-failed = 失敗
## Tracker manual proportions setup
@@ -671,6 +678,8 @@ onboarding-automatic_proportions-put_trackers_on-description = プロポーシ
onboarding-automatic_proportions-put_trackers_on-next = すべてのトラッカーを装着しました
onboarding-automatic_proportions-requirements-title = 要件
onboarding-automatic_proportions-requirements-next = 要件を読みました
# Context is that the height is unknown
onboarding-automatic_proportions-check_height-unknown = 不明
onboarding-automatic_proportions-start_recording-title = 測定の準備をする
onboarding-automatic_proportions-start_recording-description = これから具体的なポーズや動きを記録します。これらは次の画面に表示されます。ボタンが押されたらすぐに始められるように準備しておいてください!
onboarding-automatic_proportions-start_recording-next = レコーディングスタート
@@ -692,6 +701,7 @@ onboarding-automatic_proportions-verify_results-redo = レコーディングや
onboarding-automatic_proportions-verify_results-confirm = 正確です
onboarding-automatic_proportions-done-title = 体を測定して保存
onboarding-automatic_proportions-done-description = ボディプロポーションのキャリブレーションが完了しました!
onboarding-automatic_proportions-error_modal-confirm = 了解!
## Home
@@ -699,6 +709,8 @@ home-no_trackers = トラッカーを検出できません。もしくは割り
## Trackers Still On notification
trackers_still_on-modal-confirm = SlimeVRを終了する
trackers_still_on-modal-cancel = ちょっと待って...
## Status system
@@ -712,9 +724,16 @@ status_system-StatusTrackerError = { $trackerName } トラッカーにエラー
## Tray Menu
tray_menu-show = ショー
tray_menu-hide = 隠す
tray_menu-quit = 辞める
## First exit modal
tray_or_exit_modal-submit = セーブ
tray_or_exit_modal-cancel = キャンセル
## Unknown device modal
unknown_device-modal-confirm = もちろん!
unknown_device-modal-forget = 無視する

View File

@@ -383,6 +383,9 @@ settings-general-fk_settings-leg_fk-reset_mounting_feet = 발 트래커 착용
settings-general-fk_settings-arm_fk = 팔 트래킹
settings-general-fk_settings-arm_fk-description = 손 컨트롤러 위치 데이터를 사용할 수 없는 경우에도 VR 헤드셋(HMD)으로부터 팔을 추적하도록 할 수 있어요.
settings-general-fk_settings-arm_fk-force_arms = 팔을 HMD에서만 받아오기
settings-general-fk_settings-reset_settings = 정렬 설정
settings-general-fk_settings-reset_settings-reset_hmd_pitch-description = 전체 정렬을 수행하면 HMD의 피치(앞뒤 회전각)도 재설정해요. VTubing 또는 모션 캡처에서 이마에 HMD를 걸쳐두거나 할 때 유용해요. VR에서는 사용하지 마세요.
settings-general-fk_settings-reset_settings-reset_hmd_pitch = HMD 피치 정렬
settings-general-fk_settings-arm_fk-reset_mode-description = 착용 방향 정렬에 사용되는 팔 자세 설정
settings-general-fk_settings-arm_fk-back = 뒤쪽
settings-general-fk_settings-arm_fk-back-description = 기본값. 위쪽 팔은 뒤를 향하고 아래쪽 팔은 앞을 향하게 하는 자세.
@@ -474,6 +477,14 @@ settings-general-interface-connected_trackers_warning-label = 종료 시 작동
settings-general-interface-use_tray = 작업 표시줄로 최소화
settings-general-interface-use_tray-description = SlimeVR 서버를 닫지 않고 창만 닫을 수 있게 하여 사용 시 항상 GUI를 띄워 놓을 필요가 없게 해요.
settings-general-interface-use_tray-label = 작업 표시줄로 최소화
settings-general-interface-discord_presence = Discord에서 활동 공유
settings-general-interface-discord_presence-description = Discord 활동 상태에 SlimeVR을 사용 중이라는 것과 사용 중인 트래커의 개수를 같이 표시합니다.
settings-general-interface-discord_presence-label = DIscord에서 활동 공유
settings-general-interface-discord_presence-message =
{ $amount ->
[0] 슬라임 갖고 노는 중
*[other] 트래커 { $amount } 개 사용 중
}
## Serial settings
@@ -496,6 +507,8 @@ settings-serial-get_infos = 정보 가져오기
settings-serial-serial_select = 시리얼 포트 선택
settings-serial-auto_dropdown_item = 자동
settings-serial-get_wifi_scan = WiFi 검색
settings-serial-file_type = 텍스트 문서
settings-serial-save_logs = 파일에 저장
## OSC router settings
@@ -526,14 +539,15 @@ settings-osc-router-network-address-placeholder = IPV4 주소
settings-osc-vrchat = VRChat OSC Trackers
# This cares about multilines
settings-osc-vrchat-description =
헤드셋 (HMD) 데이터를 수신하고 SteamVR 없이도 (예: Quest 단독 사용)
트래커 정보를 전송하도록 VRChat 관련 설정을 변경
settings-osc-vrchat-description-v1 =
SteamVR는 애플리케이션(예: Quest 단독 실행)에 추적 데이터를 전송하는 데 사용되는 OSC 트래커 표준에 관한 설정.
VRChat에서 OSC를 사용하려면 액션 메뉴에서 '옵션' > 'OSC' > '활성화됨' 토글 스위치를 켜 주세요.
그리고 HMD 및 컨트롤러 데이터를 수신하려면 '트래킹 및 IK' > 'OSC를 통한 머리와 손목 트래킹 데이터 전송'을 활성화 해주세요.
settings-osc-vrchat-enable = 활성화
settings-osc-vrchat-enable-description = 데이터 송/수신 활성화
settings-osc-vrchat-enable-label = 활성화
settings-osc-vrchat-network = 네트워크 포트
settings-osc-vrchat-network-description = VRChat과 데이터를 주고받는 포트 설정
settings-osc-vrchat-network-description-v1 = 들어오는 포트와 나가는 포트 설정하기, VRChat에서 사용하려면 그냥 두세요.
settings-osc-vrchat-network-port_in =
.label = 들어오는 포트
.placeholder = Port in (기본값: 9001)
@@ -541,7 +555,7 @@ settings-osc-vrchat-network-port_out =
.label = 나가는 포트
.placeholder = Port out (기본값: 9000)
settings-osc-vrchat-network-address = 네트워크 주소
settings-osc-vrchat-network-address-description = VRChat으로 데이터를 보낼 주소를 선택하세요(장치의 Wi-Fi 설정 확인).
settings-osc-vrchat-network-address-description-v1 = OSC 데이터를 보낼 주소, VRChat에서 사용하려면 그냥 두세요.
settings-osc-vrchat-network-address-placeholder = VRChat IP 주소
settings-osc-vrchat-network-trackers = 트래커
settings-osc-vrchat-network-trackers-description = OSC를 통한 특정 트래커의 전송 여부 설정
@@ -584,6 +598,9 @@ settings-osc-vmc-vrm-file_select = 모델을 <u>열거나,</u> 여기에 드래
settings-osc-vmc-anchor_hip = 골반에 앵커 설정
settings-osc-vmc-anchor_hip-description = 추적을 엉덩이에 고정해요. 앉은 자세로 VTubing할 때 유용해요. 비활성화하는 경우 VRM 모델에서 가져와요.
settings-osc-vmc-anchor_hip-label = 골반에 앵커 설정
settings-osc-vmc-mirror_tracking = 움직임 좌우 반전
settings-osc-vmc-mirror_tracking-description = 움직임을 수평 방향으로 반전시킵니다.
settings-osc-vmc-mirror_tracking-label = 움직임 좌우 반전
## Setup/onboarding menu
@@ -619,7 +636,7 @@ onboarding-wifi_creds-password =
onboarding-reset_tutorial-back = 착용 방향 정렬로 돌아가기
onboarding-reset_tutorial = 정렬 튜토리얼
onboarding-reset_tutorial-explanation = 트래커를 사용하다 보면 IMU의 yaw 드리프트 또는 트래커의 위치가 달라져서 틀어짐이 발생할 수 있어요. 이러한 문제들을 해결하는 몇 가지 방법을 알려 드릴게요.
onboarding-reset_tutorial-skip = 무시하고 건너뛰기
onboarding-reset_tutorial-skip = 단계 건너뛰기
# Cares about multiline
onboarding-reset_tutorial-0 =
Yaw 정렬을 시도하려면 강조된 트래커를 { $taps }번 탭하세요.
@@ -718,6 +735,23 @@ onboarding-assign_trackers-assigned = 트래커 { $trackers }개 중 { $assigned
onboarding-assign_trackers-advanced = 고급 할당 위치 보기
onboarding-assign_trackers-next = 모든 트래커를 배치했어요
onboarding-assign_trackers-mirror_view = 좌우 반전
onboarding-assign_trackers-option-amount = x{ $trackersCount }
onboarding-assign_trackers-option-label =
{ $mode ->
[lower-body] 하반신 세트
[core] 코어 세트
[enhanced-core] 향상된 코어 세트
[full-body] 풀 바디 세트
*[all] 전부 다
}
onboarding-assign_trackers-option-description =
{ $mode ->
[lower-body] VR 신체 추적에 필요한 최소 할당
[core] + 골반 추적 향상
[enhanced-core] + 발 회전 감지
[full-body] + 팔꿈치 추적
*[all] 가능한 모든 트래커 할당
}
## Tracker assignment warnings
@@ -794,11 +828,11 @@ onboarding-choose_mounting = 착용 방향 보정을 위해 어떤 방법을 사
onboarding-choose_mounting-description = 착용 방향 정렬은 트래커가 몸에 착용된 방향을 찾아 수정하도록 도와줘요.
onboarding-choose_mounting-auto_mounting = 자동으로 방향 설정
# Italized text
onboarding-choose_mounting-auto_mounting-label = 실험적
onboarding-choose_mounting-auto_mounting-label-v2 = 권장됨
onboarding-choose_mounting-auto_mounting-description = 이렇게 하면 2가지 자세로 모든 트래커의 착용 방향을 자동으로 설정할 수 있어요
onboarding-choose_mounting-manual_mounting = 수동으로 방향 설정
# Italized text
onboarding-choose_mounting-manual_mounting-label = 권장됨
onboarding-choose_mounting-manual_mounting-label-v2 = 정확하지 않을 수도 있어요
onboarding-choose_mounting-manual_mounting-description = 이렇게 하면 각 트래커의 착용 방향을 직접 고를 수 있어요
# Multiline text
onboarding-choose_mounting-manual_modal-title = 자동으로 착용 방향을 설정하시겠어요?
@@ -954,6 +988,7 @@ status_system-StatusSteamVRDisconnected =
*[other] SlimeVR 드라이버가 SteamVR과 연결되지 않음
}
status_system-StatusTrackerError = { $trackerName } 트래커에 문제가 발생했어요.
status_system-StatusUnassignedHMD = VR 헤드셋은 머리 트래커로 할당되어야 해요.
## Tray Menu

View File

@@ -100,7 +100,7 @@ serial_detection-close = Sluiten
navbar-home = Startpagina
navbar-body_proportions = Lichaamsverhoudingen
navbar-trackers_assign = Tracker-toewijzing
navbar-mounting = Bevestigings-kalibratie
navbar-mounting = Montage-kalibratie
navbar-onboarding = Installatiewizard
navbar-settings = Instellingen
@@ -207,9 +207,9 @@ tracker-settings-title = Trackersinstellingen
tracker-settings-assignment_section = Toewijzing
tracker-settings-assignment_section-description = Aan welk lichaamsdeel de tracker is toegewezen.
tracker-settings-assignment_section-edit = Toewijzing bewerken
tracker-settings-mounting_section = Bevestigingsorientatie
tracker-settings-mounting_section = Montage oriëntatie
tracker-settings-mounting_section-description = Waar is de tracker gemonteerd?
tracker-settings-mounting_section-edit = Bevestiging bewerken
tracker-settings-mounting_section-edit = Montage bewerken
tracker-settings-drift_compensation_section = Laat drift compensatie toe
tracker-settings-drift_compensation_section-description = Moet deze tracker compenseren voor drift wanneer drift compensatie is ingeschakeld?
tracker-settings-drift_compensation_section-edit = Laat drift compensatie toe
@@ -310,6 +310,14 @@ settings-general-steamvr-description =
Handig voor games of apps die alleen bepaalde trackers ondersteunen.
settings-general-steamvr-trackers-waist = Taille
settings-general-steamvr-trackers-chest = Borst
settings-general-steamvr-trackers-left_foot = Linkervoet
settings-general-steamvr-trackers-right_foot = Rechtervoet
settings-general-steamvr-trackers-left_knee = Linkerknie
settings-general-steamvr-trackers-right_knee = Rechterknie
settings-general-steamvr-trackers-left_elbow = Linker elleboog
settings-general-steamvr-trackers-right_elbow = Rechter elleboog
settings-general-steamvr-trackers-left_hand = Linkerhand
settings-general-steamvr-trackers-right_hand = Rechterhand
settings-general-steamvr-trackers-tracker_toggling = Automatische tracker toewijzing
settings-general-steamvr-trackers-tracker_toggling-description = Zorgt automatisch voor het in- en uitschakelen van SteamVR-trackers, afhankelijk van je huidige tracker toewijzingen.
settings-general-steamvr-trackers-tracker_toggling-label = Automatische tracker toewijzing
@@ -342,8 +350,9 @@ settings-general-tracker_mechanics-drift_compensation-description =
settings-general-tracker_mechanics-drift_compensation-enabled-label = Drift compensate
settings-general-tracker_mechanics-drift_compensation-amount-label = Compensatiesterkte
settings-general-tracker_mechanics-drift_compensation-max_resets-label = Gebruik de laatste x resets
settings-general-tracker_mechanics-save_mounting_reset = Sla automatische mounting reset kalibratie op
settings-general-tracker_mechanics-save_mounting_reset-description = Slaat de automatische mounting reset kalibraties van de trackers op tussen herstarts. Nuttig als je een pak draagt waarbij trackers niet bewegen tussen sessies. <b>Niet aanbevolen voor normale gebruikers!</b>
settings-general-tracker_mechanics-save_mounting_reset = Sla de automatische montage reset kalibratie op
settings-general-tracker_mechanics-save_mounting_reset-description = Slaat de automatische montage reset kalibraties van de trackers op tussen herstarts. Nuttig als je een pak draagt waarbij trackers niet bewegen tussen sessies. <b>Niet aanbevolen voor normale gebruikers!</b>
settings-general-tracker_mechanics-save_mounting_reset-enabled-label = Montage configuratie opslaan
## FK/Tracking settings
@@ -372,6 +381,9 @@ settings-general-fk_settings-leg_fk-reset_mounting_feet = Voeten montage reset.
settings-general-fk_settings-arm_fk = Arm tracking
settings-general-fk_settings-arm_fk-description = Verander de manier waarop de armen worden getrackt.
settings-general-fk_settings-arm_fk-force_arms = Dwing armen vanuit HMD
settings-general-fk_settings-reset_settings = Instellingen resetten
settings-general-fk_settings-reset_settings-reset_hmd_pitch-description = Reset de pitch (verticale rotatie) van de HMD na een volledige reset. Dit is handig als je de HMD op je voorhoofd draagt voor VTubing of mocap. Niet inschakelen voor VR.
settings-general-fk_settings-reset_settings-reset_hmd_pitch = HMD pitch resetten
settings-general-fk_settings-arm_fk-reset_mode-description = Pas de verwachte armhouding aan voor het resetten van de montage.
settings-general-fk_settings-arm_fk-back = Achterzijde
settings-general-fk_settings-arm_fk-back-description = De standaardmodus, waarbij de bovenarmen naar achteren gaan en de onderarmen naar voren.
@@ -405,7 +417,7 @@ settings-general-fk_settings-vive_emulation-label = Vive-emulatie inschakelen
settings-general-gesture_control = Gesture control
settings-general-gesture_control-subtitle = Op tik gebaseerde resets
settings-general-gesture_control-description = Maakt het mogelijk om resets te activeren door op een tracker te tikken. De tracker het hoogst op je bovenlichaam wordt gebruikt voor Quick Reset, de tracker het hoogst op je linkerbeen voor Reset en de tracker het hoogst op je rechterbeen voor Mounting Reset. Het moet worden vermeld dat tikken binnen 0,6 seconden moeten gebeuren om geregistreerd te worden.
settings-general-gesture_control-description = Maakt het mogelijk om resets te activeren door op een tracker te tikken. De tracker het hoogst op je bovenlichaam wordt gebruikt voor Quick Reset, de tracker het hoogst op je linkerbeen voor Reset en de tracker het hoogst op je rechterbeen voor Montage Reset. Het moet worden vermeld dat tikken binnen 0,6 seconden moeten gebeuren om geregistreerd te worden.
# This is a unit: 3 taps, 2 taps, 1 tap
# $amount (Number) - Amount of taps (touches to the tracker's case)
settings-general-gesture_control-taps =
@@ -426,9 +438,9 @@ settings-general-gesture_control-yawResetTaps = Hoeveelheid tikken voor horizont
settings-general-gesture_control-fullResetEnabled = Activeer tikken voor volledige reset
settings-general-gesture_control-fullResetDelay = Vertraging volledige reset
settings-general-gesture_control-fullResetTaps = Hoeveelheid tikken voor volledige reset
settings-general-gesture_control-mountingResetEnabled = Activeer tikken voor bevestigingskalibratie
settings-general-gesture_control-mountingResetDelay = Vertraging bevestigingskalibratie
settings-general-gesture_control-mountingResetTaps = Hoeveelheid tikken voor bevestigingskalibratie
settings-general-gesture_control-mountingResetEnabled = Activeer tikken voor montage-kalibratie
settings-general-gesture_control-mountingResetDelay = Vertraging montage-kalibratie
settings-general-gesture_control-mountingResetTaps = Hoeveelheid tikken voor montage-kalibratie
# The number of trackers that can have higher acceleration before a tap is rejected
settings-general-gesture_control-numberTrackersOverThreshold = Trackers over drempelwaarde
settings-general-gesture_control-numberTrackersOverThreshold-description = Verhoog deze waarde als de tik detectie niet werkt. Zet deze waarde niet te hoog om tik detectie te laten werken, dit kan vals positieve resultaten creëren.
@@ -463,10 +475,20 @@ settings-general-interface-feedback_sound-description = Speelt een geluid telken
settings-general-interface-feedback_sound-label = Feedback geluid
settings-general-interface-feedback_sound-volume = Feedback geluid volume
settings-general-interface-connected_trackers_warning = Waarschuwing voor verbonden trackers
settings-general-interface-connected_trackers_warning-description = Deze optie toont een pop-up bericht telkens wanneer je SlimeVR probeert af te sluiten terwijl er nog trackers verbonden zijn. Dit bericht herinnert je eraan om je trackers uit te schakelen wanneer je klaar bent om de batterijduur te sparen.
settings-general-interface-connected_trackers_warning-label = Waarschuwing voor verbonden trackers bij het afsluiten
settings-general-interface-use_tray = Minimaliseren naar systeem vak
settings-general-interface-use_tray-description = Hiermee kun je het venster sluiten zonder de SlimeVR server te beëindigen, zodat je deze op de achtergrond kunt blijven gebruiken zonder dat de GUI in de weg zit.
settings-general-interface-use_tray-label = Minimaliseren naar systeem vak
settings-general-interface-discord_presence = Activiteit delen op Discord
settings-general-interface-discord_presence-description = Deelt op Discord dat je de SlimeVR server gebruikt, tezamen met het aantal IMU-Trackers.
settings-general-interface-discord_presence-label = Activiteit delen op Discord
settings-general-interface-discord_presence-message =
{ $amount ->
[0] Aan het slimen
[one] Gebruikt 1 tracker
*[other] Gebruikt { $amount } trackers
}
## Serial settings
@@ -489,6 +511,8 @@ settings-serial-get_infos = Informatie ophalen
settings-serial-serial_select = Selecteer een seriële poort
settings-serial-auto_dropdown_item = Automatisch
settings-serial-get_wifi_scan = WiFi-scan uitvoeren
settings-serial-file_type = Gewone tekst
settings-serial-save_logs = Opslaan in bestand
## OSC router settings
@@ -519,14 +543,12 @@ settings-osc-router-network-address-placeholder = IPV4-adres
settings-osc-vrchat = VRChat OSC Trackers
# This cares about multilines
settings-osc-vrchat-description =
Wijzig VRChat-specifieke instellingen om HMD-data te ontvangen en te verzenden
trackergegevens voor FBT (werkt op Quest standalone).
settings-osc-vrchat-description-v1 = Wijzig instellingen die specifiek zijn voor de OSC Trackers-standaard die wordt gebruikt voor het verzenden van trackinggegevens naar applicaties zonder SteamVR (bijv. Quest standalone). Zorg ervoor dat OSC is ingeschakeld in VRChat via het Actiemenu onder OSC > Ingeschakeld. Om het ontvangen van HMD- en controllergegevens van VRChat mogelijk te maken, ga in je hoofdmenu naar Instellingen onder Tracking & IK > Allow Sending Head and Wrist VR Tracking OSC Data.
settings-osc-vrchat-enable = Inschakelen
settings-osc-vrchat-enable-description = Schakel het verzenden en ontvangen van gegevens in en uit.
settings-osc-vrchat-enable-label = Inschakelen
settings-osc-vrchat-network = Netwerkpoorten
settings-osc-vrchat-network-description = Stel de poorten in voor het zenden en ontvangen van OSC-gegevens naar VRChat.
settings-osc-vrchat-network-description-v1 = Stel de poorten in voor het ontvangen en verzenden van tracking data. Kan op standaardinstellingen blijven voor VRChat.
settings-osc-vrchat-network-port_in =
.label = Poort In
.placeholder = Poort in (standaard: 9001)
@@ -534,7 +556,7 @@ settings-osc-vrchat-network-port_out =
.label = Poort Out
.placeholder = Poort uit (standaard: 9000)
settings-osc-vrchat-network-address = Netwerkadres
settings-osc-vrchat-network-address-description = Kies naar welk adres je gegevens naar VRChat wilt verzenden (controleer de wifi-instellingen op je apparaat).
settings-osc-vrchat-network-address-description-v1 = Kies naar welk adres u gegevens wilt verzenden. Kan op standaardinstellingen blijven voor VRChat.
settings-osc-vrchat-network-address-placeholder = VRChat IP-adres
settings-osc-vrchat-network-trackers = Trackers
settings-osc-vrchat-network-trackers-description = Schakel het verzenden van specifieke trackers via OSC in en uit.
@@ -577,6 +599,9 @@ settings-osc-vmc-vrm-file_select = Sleep een modelbestand naar hier om ze te geb
settings-osc-vmc-anchor_hip = Heupverankering
settings-osc-vmc-anchor_hip-description = Veranker de tracking aan de heupen, handig voor zittende VTubing. Als u deze uitschakelt, laadt u een VRM-model.
settings-osc-vmc-anchor_hip-label = Heupverankering
settings-osc-vmc-mirror_tracking = Gespiegelde tracking
settings-osc-vmc-mirror_tracking-description = De tracking horizontaal spiegelen.
settings-osc-vmc-mirror_tracking-label = Gespiegelde tracking
## Setup/onboarding menu
@@ -609,7 +634,7 @@ onboarding-wifi_creds-password =
## Mounting setup
onboarding-reset_tutorial-back = Ga terug naar de bevestigingskalibratie
onboarding-reset_tutorial-back = Ga terug naar de montage-kalibratie
onboarding-reset_tutorial = Reset tutorial
onboarding-reset_tutorial-explanation = Terwijl je jouw trackers gebruikt, kunnen ze uit de lijn raken vanwege IMU-yaw-drift, of omdat je ze fysiek hebt verplaatst. Je hebt verschillende manieren om dit op te lossen.
onboarding-reset_tutorial-skip = Stap overslaan
@@ -716,6 +741,27 @@ onboarding-assign_trackers-assigned =
onboarding-assign_trackers-advanced = Geavanceerde toewijzingslocaties weergeven
onboarding-assign_trackers-next = Ik heb alle trackers toegewezen
onboarding-assign_trackers-mirror_view = Gespiegelde weergave
onboarding-assign_trackers-option-amount =
{ $trackersCount ->
[one] x{ $trackersCount }
*[other] x{ $trackersCount }
}
onboarding-assign_trackers-option-label =
{ $mode ->
[lower-body] Lower-Body Set
[core] Core Set
[enhanced-core] Enhanced Core Set
[full-body] Full-Body Set
*[all] Alle trackers
}
onboarding-assign_trackers-option-description =
{ $mode ->
[lower-body] Minimaal aantal voor VR full-body tracking
[core] + betere torso tracking
[enhanced-core] + voeten rotatie
[full-body] + elleboog tracking
*[all] Alle beschikbare tracker locaties
}
## Tracker assignment warnings
@@ -792,44 +838,45 @@ onboarding-choose_mounting = Welke montagekalibratiemethode moet worden gebruikt
onboarding-choose_mounting-description = De oriëntatie van de montage corrigeert de plaatsing van trackers op uw lichaam.
onboarding-choose_mounting-auto_mounting = Automatische bevestiging
# Italized text
onboarding-choose_mounting-auto_mounting-label = Experimenteel
onboarding-choose_mounting-auto_mounting-label-v2 = Aanbevolen
onboarding-choose_mounting-auto_mounting-description = Dit detecteert automatisch de montagerichtingen voor al uw trackers door middel van 2 poses
onboarding-choose_mounting-manual_mounting = Handmatige bevestiging
# Italized text
onboarding-choose_mounting-manual_mounting-label = Aanbevolen
onboarding-choose_mounting-manual_mounting-label-v2 = Misschien niet precies genoeg
onboarding-choose_mounting-manual_mounting-description = Hiermee kunt u de montagerichting handmatig kiezen voor elke tracker
# Multiline text
onboarding-choose_mounting-manual_modal-title = Ben je zeker dat je de automatische kalibratie wilt uitvoeren?
onboarding-choose_mounting-manual_modal-description = <b>De handmatige montagekalibratie word aangeraden voor nieuwe gebruikers.</b>, De posities die je moet doen voor de automatische kalibratie kunnen lastig zijn om in één keer goed te krijgen en vereisen mogelijk wat oefening.
onboarding-choose_mounting-manual_modal-confirm = Ik weet zeker wat ik doe
onboarding-choose_mounting-manual_modal-cancel = Annuleren
## Tracker manual mounting setup
onboarding-manual_mounting-back = Ga terug naar de VR sectie
onboarding-manual_mounting = Handmatige bevestiging
onboarding-manual_mounting = Handmatige montage
onboarding-manual_mounting-description = Klik op elke tracker en selecteer op welke manier ze zijn bevestigd
onboarding-manual_mounting-auto_mounting = Automatische bevestiging
onboarding-manual_mounting-auto_mounting = Automatische montage
onboarding-manual_mounting-next = Volgende stap
## Tracker automatic mounting setup
onboarding-automatic_mounting-back = Ga terug naar de VR sectie
onboarding-automatic_mounting-title = Bevestigingskalibratie
onboarding-automatic_mounting-title = Montage-kalibratie
onboarding-automatic_mounting-description = Om je trackers te laten werken, moet de rotatie worden ingesteld hoe deze zijn bevestigd op je lichaam.
onboarding-automatic_mounting-manual_mounting = Bevestiging handmatig instellen
onboarding-automatic_mounting-manual_mounting = Montage handmatig instellen
onboarding-automatic_mounting-next = Volgende stap
onboarding-automatic_mounting-prev_step = Vorige stap
onboarding-automatic_mounting-done-title = Bevestigingsrotaties gekalibreerd.
onboarding-automatic_mounting-done-description = Je bevestigingskalibratie is compleet!
onboarding-automatic_mounting-done-title = Montagerichtingen gekalibreerd.
onboarding-automatic_mounting-done-description = Je montage-kalibratie is compleet!
onboarding-automatic_mounting-done-restart = Terug naar start
onboarding-automatic_mounting-mounting_reset-title = Bevestiging kalibreren
onboarding-automatic_mounting-mounting_reset-title = Montage-reset
onboarding-automatic_mounting-mounting_reset-step-0 = 1. Ga staan in een "skie"-houding met gebogen benen, je bovenlichaam naar voren gekanteld en armen gebogen.
onboarding-automatic_mounting-mounting_reset-step-1 = 2. Druk op de knop "Bevestiging resetten" en wacht 3 seconden voordat de bevestigingsrotaties van de trackers opnieuw worden ingesteld.
onboarding-automatic_mounting-mounting_reset-step-1 = 2. Druk op de knop "Reset montage" en wacht 3 seconden voordat de montagerichtingen van de trackers opnieuw worden ingesteld.
onboarding-automatic_mounting-preparation-title = Voorbereiding
onboarding-automatic_mounting-preparation-step-0 = 1. Sta rechtop met je armen langs je zij.
onboarding-automatic_mounting-preparation-step-1 = 2. Druk op de knop "Resetten" en wacht 3 seconden voordat de trackers opnieuw worden ingesteld.
onboarding-automatic_mounting-put_trackers_on-title = Doe je trackers aan
onboarding-automatic_mounting-put_trackers_on-description = Om bevestigingsrotaties te kalibreren, gaan we gebruik maken van de trackers die je net hebt toegewezen. Doe al je trackers aan, je kunt zien welke trackers welke zijn in de figuur rechts.
onboarding-automatic_mounting-put_trackers_on-description = Om montagerichtingen te kalibreren gaan we gebruik maken van de trackers die je net hebt toegewezen. Doe al je trackers aan, je kunt zien welke trackers welke zijn in de figuur rechts.
onboarding-automatic_mounting-put_trackers_on-next = Ik heb al mijn trackers aan
## Tracker proportions method choose
@@ -875,6 +922,8 @@ onboarding-automatic_proportions-put_trackers_on-title = Doe je trackers aan
onboarding-automatic_proportions-put_trackers_on-description = Om je verhoudingen te kalibreren, gaan we gebruik maken van de trackers die je net hebt toegewezen. Doe al je trackers aan, je kunt zien welke trackers welke zijn in de figuur rechts.
onboarding-automatic_proportions-put_trackers_on-next = Ik heb al mijn trackers aan
onboarding-automatic_proportions-requirements-title = Vereisten
# Each line of text is a different list item
onboarding-automatic_proportions-requirements-descriptionv2 = Je hebt voldaan aan de minimale vereisten om je voeten te tracken (over het algemeen 5 trackers). Je hebt je trackers en headset aan en draagt ze. Je trackers en headset zijn verbonden met de SlimeVR server en werken naar behoren (zonder haperingen, loskoppelingen etc.). Je headset stuurt positiedata naar de SlimeVR server (dit vereist doorgaans dat SteamVR draait en verbonden is met SlimeVR via de SlimeVR SteamVR-driver). De tracking werkt en registreert je bewegingen nauwkeurig (je hebt bijvoorbeeld een volledige reset uitgevoerd en de trackers bewegen in de juiste richting bij schoppen, bukken, zitten etc.).
onboarding-automatic_proportions-requirements-next = Ik heb de vereisten gelezen
onboarding-automatic_proportions-check_height-title = Controleer je lengte
onboarding-automatic_proportions-check_height-description =
@@ -882,6 +931,7 @@ onboarding-automatic_proportions-check_height-description =
Maar het is beter om zelf te controleren of dit klopt.
# All the text is in bold!
onboarding-automatic_proportions-check_height-calculation_warning = Druk op de knop terwijl je <u>rechtop</u> staat om je lengte te berekenen. Je hebt 3 seconden na dat je op de knop drukt!
onboarding-automatic_proportions-check_height-guardian_tip = Als je een losse VR-bril gebruikt, zorg er dan voor dat je guardian/veilige zone is ingeschakeld zodat je lengte correct is gekalibreerd!
onboarding-automatic_proportions-check_height-fetch_height = Ik sta!
# Context is that the height is unknown
onboarding-automatic_proportions-check_height-unknown = Onbekend
@@ -946,6 +996,7 @@ status_system-StatusSteamVRDisconnected =
*[other] Momenteel niet verbonden naar SteamVR via de SlimeVR driver.
}
status_system-StatusTrackerError = De { $trackerName } tracker heeft een error.
status_system-StatusUnassignedHMD = De VR-headset moet worden toegewezen als hoofdtracker.
## Tray Menu

View File

@@ -13,14 +13,14 @@ websocket-connection_lost = Połączenie z serwerem zostało utracone. Próba po
## Update notification
version_update-title = Dostępna jest nowa wersja: { $version }
version_update-description = Kliknięcie „Aktualizuj” spowoduje pobranie instalatora SlimeVR.
version_update-description = Kliknięcie "{ version_update-update }" spowoduje pobranie instalatora SlimeVR.
version_update-update = Aktualizacja
version_update-close = Zamknij
## Tips
tips-find_tracker = Nie wiesz który tracker to który? Poruszaj trackerem, a będzie sie on podświetlał na serwerze.
tips-do_not_move_heels = Upewnij się, aby pięty pozostały w bezruchu podczas nagrywania.
tips-find_tracker = Nie jesteś pewien, który tracker jest który? Potrząśnij trackerem, a podświetli on odpowiedni element.
tips-do_not_move_heels = Upewnij się, aby pięty nie ruszały się podczas nagrywania.
tips-file_select = Przeciągnij i upuść pliki, których chcesz użyć, lub <u>przeglądaj</u>.
tips-tap_setup = Możesz powoli stuknąć 2 razy tracker, aby go wybrać, zamiast wybierać go z menu.
tips-turn_on_tracker = Używasz oficjalnych trackerów SlimeVR? Pamiętaj, <b><em>aby włączyć tracker</em></b> po podłączeniu go do komputera!
@@ -107,7 +107,7 @@ navbar-settings = Ustawienia
## Biovision hierarchy recording
bvh-start_recording = Nagraj BVH
bvh-recording = Nagrywam...
bvh-recording = Nagrywanie...
## Tracking pause
@@ -141,7 +141,7 @@ widget-developer_mode-more_info = Więcej info
## Widget: IMU Visualizer
widget-imu_visualizer = Obrót
widget-imu_visualizer = Rotacja
widget-imu_visualizer-rotation_raw = Raw
widget-imu_visualizer-rotation_preview = Podgląd
widget-imu_visualizer-rotation_hide = Ukryj
@@ -169,7 +169,7 @@ tracker-table-column-battery = Bateria
tracker-table-column-ping = Ping
tracker-table-column-tps = TPS
tracker-table-column-temperature = Temp. °C
tracker-table-column-linear-acceleration = Accel. X/Y/Z
tracker-table-column-linear-acceleration = Akceleracja X/Y/Z
tracker-table-column-rotation = Rotacja X/Y/Z
tracker-table-column-position = Pozycja X/Y/Z
tracker-table-column-url = URL
@@ -244,7 +244,7 @@ body_assignment_menu-unassign_tracker = Usuń przydzielenie
# maybe your language does.
-tracker_selection-part = Which tracker to assign to your
tracker_selection_menu-NONE = Któremu trackerowi chcesz cofnąć przypisanie?
tracker_selection_menu-HEAD = { -tracker_selection-part } head?
tracker_selection_menu-HEAD = { -tracker_selection-part } głowa?
tracker_selection_menu-NECK = { -tracker_selection-part } szyja?
tracker_selection_menu-RIGHT_SHOULDER = { -tracker_selection-part } prawe ramię?
tracker_selection_menu-RIGHT_UPPER_ARM = { -tracker_selection-part } right upper arm?
@@ -483,6 +483,9 @@ settings-general-interface-connected_trackers_warning-label = Ostrzeżenie o pod
settings-general-interface-use_tray = Minimalizuj do zasobnika systemowego
settings-general-interface-use_tray-description = Pozwala zamknąć okno bez wyłączania serwera SlimeVR, aby używać trackerów bez interfejsu graficznego.
settings-general-interface-use_tray-label = Minimalizuj do zasobnika systemowego
settings-general-interface-discord_presence = Udostępniaj aktywność na Discordzie
settings-general-interface-discord_presence-description = Informuje Twojego klienta Discord o korzystaniu ze SlimeVR oraz o liczbie używanych trackerów IMU.
settings-general-interface-discord_presence-label = Udostępniaj aktywność na Discordzie
## Serial settings
@@ -505,6 +508,8 @@ settings-serial-get_infos = Uzyskaj informacje
settings-serial-serial_select = Wybierz port szeregowy
settings-serial-auto_dropdown_item = Auto
settings-serial-get_wifi_scan = Skanuj sieci WiFi
settings-serial-file_type = Zwykły tekst
settings-serial-save_logs = Zapisz do pliku
## OSC router settings
@@ -534,15 +539,10 @@ settings-osc-router-network-address-placeholder = IPV4 address
## OSC VRChat settings
settings-osc-vrchat = VRChat OSC Trackers
# This cares about multilines
settings-osc-vrchat-description =
Zmień ustawienia specyficzne dla VRChat, aby odbierać i wysyłać dane HMD
dane trackerów dla FBT (działa na samodzielnym Quest).
settings-osc-vrchat-enable = Zezwól
settings-osc-vrchat-enable-description = Zezwól na wysyłanie i odbieranie danych.
settings-osc-vrchat-enable-label = Zezwól
settings-osc-vrchat-network = Porty sieciowe
settings-osc-vrchat-network-description = Ustaw porty do odbierania i wysyłania danych do VRChat.
settings-osc-vrchat-network-port_in =
.label = Port In
.placeholder = Port in (default: 9001)
@@ -550,7 +550,6 @@ settings-osc-vrchat-network-port_out =
.label = Port Out
.placeholder = Port out (default: 9000)
settings-osc-vrchat-network-address = Adres sieciowy
settings-osc-vrchat-network-address-description = Wybierz adres, na który chcesz wysłać dane do VRChat (sprawdź ustawienia Wi-Fi na swoim urządzeniu).
settings-osc-vrchat-network-address-placeholder = Adres IP VRChata
settings-osc-vrchat-network-trackers = Trackers
settings-osc-vrchat-network-trackers-description = Przełącz wysyłanie określonych trackerów przez OSC.
@@ -736,6 +735,22 @@ onboarding-assign_trackers-assigned =
onboarding-assign_trackers-advanced = Pokaż zaawansowane ustawienia pozycji
onboarding-assign_trackers-next = Przydzieliłem już wszystkie trackery
onboarding-assign_trackers-mirror_view = Widok lustrzany
onboarding-assign_trackers-option-label =
{ $mode ->
[lower-body] Zestaw na dolną część ciała
[core] Zestaw podstawowy
[enhanced-core] Rozszerzony zestaw podstawowy
[full-body] Pełny zestaw
*[all] Wszystkie trackery
}
onboarding-assign_trackers-option-description =
{ $mode ->
[lower-body] Minimum do śledzenia ciała w rzeczywistości wirtualnej
[core] + Ulepszone śledzenie kręgosłupa
[enhanced-core] + Śledzenie stóp
[full-body] + Śledzenie łokci
*[all] Wszystkie możliwe przypisania trackerów
}
## Tracker assignment warnings
@@ -812,11 +827,9 @@ onboarding-choose_mounting = Jakiej metody kalibracji montażu użyć?
onboarding-choose_mounting-description = Orientacja montażu koryguje umieszczenie trackerów na ciele.
onboarding-choose_mounting-auto_mounting = Automatyczne mocowanie
# Italized text
onboarding-choose_mounting-auto_mounting-label = Eksperymentalny
onboarding-choose_mounting-auto_mounting-label-v2 = Zalecane
onboarding-choose_mounting-auto_mounting-description = To automatycznie wykryje kierunki montażu dla wszystkich twoich trackerów z 2 pozycji
onboarding-choose_mounting-manual_mounting = Montaż ręczny
# Italized text
onboarding-choose_mounting-manual_mounting-label = Zalecany
onboarding-choose_mounting-manual_mounting-description = Umożliwi to ręczne wybranie kierunku montażu dla każdego trackera
# Multiline text
onboarding-choose_mounting-manual_modal-title =
@@ -969,7 +982,7 @@ trackers_still_on-modal-description =
Jeden lub więcej modułów śledzących jest nadal włączonych.
Czy nadal chcesz wyjść ze SlimeVR?
trackers_still_on-modal-confirm = Wyjdź ze SlimeVR
trackers_still_on-modal-cancel = Poczekaj!
trackers_still_on-modal-cancel = Poczekaj...
## Status system
@@ -980,6 +993,7 @@ status_system-StatusSteamVRDisconnected =
*[other] Nie można połączyć się ze SteamVR przez sterownik SlimeVR.
}
status_system-StatusTrackerError = Tracker { $trackerName } ma błąd.
status_system-StatusUnassignedHMD = Headset powinien być przypisany do śledzenia głowy.
## Tray Menu
@@ -1004,7 +1018,7 @@ tray_or_exit_modal-cancel = Anuluj
unknown_device-modal-title = Znaleziono nowy tracker!
unknown_device-modal-description =
Dostępny jest nowy tracker z adresem MAC b { $deviceId } /b .¶
Dostępny jest nowy tracker z adresem MAC <b> { $deviceId } </b>
Czy chcesz podłączyć go do SlimeVR?
unknown_device-modal-confirm = Jasne!
unknown_device-modal-forget = Ignoruj

View File

@@ -383,6 +383,9 @@ settings-general-fk_settings-leg_fk-reset_mounting_feet = Reset de Posição dos
settings-general-fk_settings-arm_fk = Opções do Braço
settings-general-fk_settings-arm_fk-description = Muda o jeito que os braços são rastreados.
settings-general-fk_settings-arm_fk-force_arms = Forçar braços do HMD
settings-general-fk_settings-reset_settings = Redefinir configurações
settings-general-fk_settings-reset_settings-reset_hmd_pitch-description = Redefine a inclinação (rotação vertical) do HMD ao fazer um reset completo. Útil se estiver usando um HMD na testa para VTubing ou captura de movimento. Não ative para VR.
settings-general-fk_settings-reset_settings-reset_hmd_pitch = Redefinir a inclinação do HMD
settings-general-fk_settings-arm_fk-reset_mode-description = Mudar a pose do braço esperada para o reset de posição.
settings-general-fk_settings-arm_fk-back = Atrás
settings-general-fk_settings-arm_fk-back-description = O modo padrão, com os braços voltados para trás e os antebraços para frente.
@@ -480,6 +483,15 @@ settings-general-interface-connected_trackers_warning-label = Aviso de trackers
settings-general-interface-use_tray = Minimizar para bandeja do sistema
settings-general-interface-use_tray-description = Permite que você feche a janela sem fechar o servidor do SlimeVR, para que possa continuar usando-o sem que a interface gráfica o incomode.
settings-general-interface-use_tray-label = Minimizar para a bandeja do sistema
settings-general-interface-discord_presence = Compartilhar atividade no Discord
settings-general-interface-discord_presence-description = Informa ao seu Discord que o SlimeVR está aberto, juntamente com o número de trackers IMU que você está utilizando.
settings-general-interface-discord_presence-label = Compartilhar atividade no Discord
settings-general-interface-discord_presence-message =
{ $amount ->
[0] Dando uma voltinha
[one] Usando 1 tracker
*[other] Usando { $amount } trackers
}
## Serial settings
@@ -502,6 +514,8 @@ settings-serial-get_infos = Obter informações
settings-serial-serial_select = Selecione uma porta serial
settings-serial-auto_dropdown_item = Auto
settings-serial-get_wifi_scan = Obter varredura WiFi
settings-serial-file_type = Texto simples
settings-serial-save_logs = Salvar em arquivo
## OSC router settings
@@ -532,14 +546,17 @@ settings-osc-router-network-address-placeholder = Endereço IPV4
settings-osc-vrchat = VRChat OSC Trackers
# This cares about multilines
settings-osc-vrchat-description =
Mudar opções específicas do VRChat para receber e mandar dados do HMD
dados de trackers para FBT (funciona no Quest standalone).
settings-osc-vrchat-description-v1 =
Altere as configurações específicas do padrão de trackers OSC usado para enviar
dados de rastreamento para aplicativos sem o SteamVR (por exemplo, Quest standalone).
Certifique-se de habilitar o OSC no VRChat através do menu de ações em OSC > Habilitado.
Para permitir o recebimento de dados do HMD e dos controles do VRChat, vá nas configurações do menu principal
em Rastreamento e IK > Permitir o envio de dados OSC de Rastreio de RV da cabeça e do pulso.
settings-osc-vrchat-enable = Ativar
settings-osc-vrchat-enable-description = Ligar ou desligar o envio e recebimento de dados
settings-osc-vrchat-enable-label = Ativar
settings-osc-vrchat-network = Portas de rede
settings-osc-vrchat-network-description = Defina as portas para receber e enviar dados para o VRChat
settings-osc-vrchat-network-description-v1 = Define as portas para receber e enviar dados. Pode ser deixado como está para o VRChat.
settings-osc-vrchat-network-port_in =
.label = Porta de entrada
.placeholder = Porta de entrada (padrão: 9001)
@@ -547,7 +564,7 @@ settings-osc-vrchat-network-port_out =
.label = Porta de saída
.placeholder = Porta de saída (padrão: 9000)
settings-osc-vrchat-network-address = Endereço de rede
settings-osc-vrchat-network-address-description = Escolha qual o endereço para enviar dados para o VRChat (verifique as suas opções de Wi-Fi no seu dispositivo)
settings-osc-vrchat-network-address-description-v1 = Escolha o endereço para enviar os dados. Pode ser deixado como está para o VRChat.
settings-osc-vrchat-network-address-placeholder = Endereço de ip do VRChat
settings-osc-vrchat-network-trackers = Trackers
settings-osc-vrchat-network-trackers-description = Ligar ou desligar o envio e recepção de dados.
@@ -590,6 +607,9 @@ settings-osc-vmc-vrm-file_select = Arraste e solte um modelo para usar, ou <u>na
settings-osc-vmc-anchor_hip = Ancorar no quadril
settings-osc-vmc-anchor_hip-description = Ancorar o rastreamento no quadril, útil para VTubing sentado. Se desativar, carregue um modelo VRM.
settings-osc-vmc-anchor_hip-label = Ancorar no quadril
settings-osc-vmc-mirror_tracking = Espelhar rastreamento
settings-osc-vmc-mirror_tracking-description = Espelhar o rastreamento horizontalmente.
settings-osc-vmc-mirror_tracking-label = Espelhar rastreamento
## Setup/onboarding menu
@@ -729,6 +749,27 @@ onboarding-assign_trackers-assigned =
onboarding-assign_trackers-advanced = Mostrar locais de atribuição avançados
onboarding-assign_trackers-next = Atribui todos os trackers
onboarding-assign_trackers-mirror_view = Inverter visão
onboarding-assign_trackers-option-amount =
{ $trackersCount ->
[one] x
*[other] x
}
onboarding-assign_trackers-option-label =
{ $mode ->
[lower-body] Conjunto Lower-Body
[core] Conjunto Core
[enhanced-core] Conjunto Enhanced
[full-body] Conjunto Full-Body
*[all] Todos os trackers
}
onboarding-assign_trackers-option-description =
{ $mode ->
[lower-body] O mínimo para rastrear seu corpo no VR
[core] + Rastreamento melhorado da coluna
[enhanced-core] + Rotação dos pés
[full-body] + Rastreamento dos cotovelos
*[all] Todas as atribuições de trackers disponíveis
}
## Tracker assignment warnings
@@ -805,11 +846,11 @@ onboarding-choose_mounting = Qual método de calibração de posição você des
onboarding-choose_mounting-description = A orientação de posição corrige a colocação dos trackers no seu corpo.
onboarding-choose_mounting-auto_mounting = Posição automática
# Italized text
onboarding-choose_mounting-auto_mounting-label = Experimental
onboarding-choose_mounting-auto_mounting-label-v2 = Recomendado
onboarding-choose_mounting-auto_mounting-description = Isso detectará automaticamente as direções de posição para todos os seus trackers a partir de 2 poses
onboarding-choose_mounting-manual_mounting = Posição manual
# Italized text
onboarding-choose_mounting-manual_mounting-label = Recomendado
onboarding-choose_mounting-manual_mounting-label-v2 = Pode não ser precisa o suficiente
onboarding-choose_mounting-manual_mounting-description = Isso permitirá que você escolha manualmente a direção de posição para cada tracker
# Multiline text
onboarding-choose_mounting-manual_modal-title =
@@ -843,7 +884,7 @@ onboarding-automatic_mounting-mounting_reset-step-0 = 1. Agache-se em uma pose d
onboarding-automatic_mounting-mounting_reset-step-1 = 2. Pressione o botão "Resetar Posição" e aguarde 3 segundos antes que as rotações de posição dos trackers sejam redefinidas.
onboarding-automatic_mounting-preparation-title = Preparação
onboarding-automatic_mounting-preparation-step-0 = 1. Fique de pé com os braços ao lado do corpo.
onboarding-automatic_mounting-preparation-step-1 = 2. Pressione o botão "Reset" e aguarde 3 segundos antes que os rastreadores sejam reiniciados.
onboarding-automatic_mounting-preparation-step-1 = 2. Pressione o botão "Reset" e aguarde 3 segundos antes que os trackers sejam reiniciados.
onboarding-automatic_mounting-put_trackers_on-title = Coloque seus trackers
onboarding-automatic_mounting-put_trackers_on-description = Para calibrar as rotações de posicionamento, usaremos os trackers que você atribuiu. Coloque todos os seus trackers, você pode ver qual é qual na figura na direita.
onboarding-automatic_mounting-put_trackers_on-next = Coloquei todos os meus trackers
@@ -971,6 +1012,7 @@ status_system-StatusSteamVRDisconnected =
*[other] Atualmente não conectado ao SteamVR via driver SlimeVR.
}
status_system-StatusTrackerError = O tracker { $trackerName } tem um erro.
status_system-StatusUnassignedHMD = O headset (HMD) deve ser designado como o tracker da cabeça.
## Tray Menu

View File

@@ -21,7 +21,7 @@ version_update-close = Закрыть
tips-find_tracker = Не уверены, какой трекер какой? Встряхните его, и трекер выделится в списке.
tips-do_not_move_heels = Убедитесь, что ваши пятки не двигаются во время записи!
tips-file_select = Выберите или перетащите файлы для использования <u>выбрать</u>.
tips-file_select = Выберите и перетащите файлы, чтобы использовать, или нажмите <u>выбрать</u>.
tips-tap_setup = Вы можете медленно нажать 2 раза на свой трекер, чтобы выбрать его, вместо того чтобы выбирать его из меню.
tips-turn_on_tracker = Используете официальные трекеры SlimeVR? Не забудьте <b><em>включить трекер</em></b> после его подключения к ПК!
tips-failed_webgl = Не удалось инициализировать WebGL.
@@ -310,6 +310,14 @@ settings-general-steamvr-description =
Полезно для игр или приложений, которые поддерживают только определенные трекеры.
settings-general-steamvr-trackers-waist = Талия
settings-general-steamvr-trackers-chest = Грудь
settings-general-steamvr-trackers-left_foot = Левая ступня
settings-general-steamvr-trackers-right_foot = Правая ступня
settings-general-steamvr-trackers-left_knee = Левое колено
settings-general-steamvr-trackers-right_knee = Правое колено
settings-general-steamvr-trackers-left_elbow = Левый локоть
settings-general-steamvr-trackers-right_elbow = Правый локоть
settings-general-steamvr-trackers-left_hand = Левая рука
settings-general-steamvr-trackers-right_hand = Правая рука
settings-general-steamvr-trackers-tracker_toggling = Автоматическое назначение трекеров
settings-general-steamvr-trackers-tracker_toggling-description = Автоматически занимается включением и выключением трекеров SlimeVR в зависимости от текущих назначений ваших трекеров
settings-general-steamvr-trackers-tracker_toggling-label = Автоматическое назначение трекеров
@@ -375,6 +383,7 @@ settings-general-fk_settings-leg_fk-reset_mounting_feet = Сброс крепл
settings-general-fk_settings-arm_fk = Отслеживание рук
settings-general-fk_settings-arm_fk-description = Измените способ отслеживания рук.
settings-general-fk_settings-arm_fk-force_arms = Руки от HMD
settings-general-fk_settings-reset_settings = Сбросить настройки
settings-general-fk_settings-arm_fk-reset_mode-description = Изменение ожидаемой позы руки для сброса крепления.
settings-general-fk_settings-arm_fk-back = Назад
settings-general-fk_settings-arm_fk-back-description = Режим по умолчанию, в котором плечи идут назад, а предплечья — вперед.
@@ -474,6 +483,16 @@ settings-general-interface-connected_trackers_warning-label = Предупреж
settings-general-interface-use_tray = Свернуть в системный трей
settings-general-interface-use_tray-description = Позволяет закрыть окно, не закрывая сервер SlimeVR, так что вы можете продолжать использовать его, не беспокоясь о графическом интерфейсе.
settings-general-interface-use_tray-label = Свернуть в системный трей
settings-general-interface-discord_presence = Поделиться активностью в Discord
settings-general-interface-discord_presence-description = Сообщает вашему приложению Discord, что вы используете SlimeVR, вместе с количеством IMU трекеров, которые вы используете.
settings-general-interface-discord_presence-label = Поделиться активностью в Discord
settings-general-interface-discord_presence-message =
{ $amount ->
[0] Чиллим со Слаймами
[one] Используется { $amount } трекер
[few] Используется { $amount } трекера
*[many] Используется { $amount } трекеров
}
## Serial settings
@@ -496,6 +515,8 @@ settings-serial-get_infos = Получить информацию
settings-serial-serial_select = Выбрать серийный порт
settings-serial-auto_dropdown_item = Авто
settings-serial-get_wifi_scan = Получить сканирование Wi-Fi
settings-serial-file_type = Обычный текст
settings-serial-save_logs = Сохранить в файл
## OSC router settings
@@ -526,14 +547,17 @@ settings-osc-router-network-address-placeholder = IPV4 адрес
settings-osc-vrchat = VRChat OSC Трекеры
# This cares about multilines
settings-osc-vrchat-description =
Измените настройки, специфичные для VRChat, чтобы получать данные HMD и отправлять
данные трекеров для FBT (работает с Quest).
settings-osc-vrchat-description-v1 =
Изменение настроек, специфичных для стандарта OSC Трекеров, используемых для отправки
данных о трекинге приложениям без SteamVR (например, Oculus Quest).
Убедитесь, что вы включили OSC в VRChat через меню действия в OSC > Включено.
Чтобы разрешить получение данных об HMD и контроллерах от VRChat, перейдите в настройки в главном меню,
и далее перейдите в Tracking & IK > Allow Sending Head and Wrist VR Tracking OSC Data.
settings-osc-vrchat-enable = Включить
settings-osc-vrchat-enable-description = Переключайте отправку и получение данных.
settings-osc-vrchat-enable-label = Включить
settings-osc-vrchat-network = Порты сети
settings-osc-vrchat-network-description = Установите порты для прослушивания и отправки данных в VRChat.
settings-osc-vrchat-network-description-v1 = Настройте порты для прослушивания и отправки данных. Можно оставить нетронутым для VRChat.
settings-osc-vrchat-network-port_in =
.label = Порт вход
.placeholder = Порт вход (default: 9001)
@@ -541,7 +565,7 @@ settings-osc-vrchat-network-port_out =
.label = Порт выход
.placeholder = Порт выход (default: 9000)
settings-osc-vrchat-network-address = Адрес сети
settings-osc-vrchat-network-address-description = Выберите, на какой адрес отправлять данные в VRChat (проверьте настройки Wi-Fi на вашем устройстве).
settings-osc-vrchat-network-address-description-v1 = Выберите, на какой адрес отправлять данные. Можно оставить нетронутым для VRChat.
settings-osc-vrchat-network-address-placeholder = VRChat ip адрес
settings-osc-vrchat-network-trackers = Трекеры
settings-osc-vrchat-network-trackers-description = Переключите отправку определенных трекеров через OSC.
@@ -584,6 +608,9 @@ settings-osc-vmc-vrm-file_select = Перетащите модель для ис
settings-osc-vmc-anchor_hip = Привязать к бедрам
settings-osc-vmc-anchor_hip-description = Привязать трекинг к бедрам, полезно для сидячего VTubing'а. Если выключено, загрузите VRM модель.
settings-osc-vmc-anchor_hip-label = Привязать к бедрам
settings-osc-vmc-mirror_tracking = Отзеркалить отслеживание
settings-osc-vmc-mirror_tracking-description = Отзеркалить отслеживание горизонтально.
settings-osc-vmc-mirror_tracking-label = Отзеркалить отслеживание
## Setup/onboarding menu
@@ -727,6 +754,28 @@ onboarding-assign_trackers-assigned =
onboarding-assign_trackers-advanced = Показать дополнительные места привязки
onboarding-assign_trackers-next = Я привязал все трекеры
onboarding-assign_trackers-mirror_view = Зеркальный вид
onboarding-assign_trackers-option-amount =
{ $trackersCount ->
[one] x{ $trackersCount }
[few] x{ $trackersCount }
*[many] x{ $trackersCount }
}
onboarding-assign_trackers-option-label =
{ $mode ->
[lower-body] Комплект нижней части тела
[core] Базовый комплект
[enhanced-core] Улучшенный базовый комплект
[full-body] Комплект для всего тела
*[all] Все трекеры
}
onboarding-assign_trackers-option-description =
{ $mode ->
[lower-body] Минимум для отслеживания тела в VR
[core] + Улучшенное отслеживание позвоночника
[enhanced-core] + Отслеживание поворота ступней
[full-body] + Отслеживание локтей
*[all] Все доступные привязки для трекеров
}
## Tracker assignment warnings
@@ -803,11 +852,11 @@ onboarding-choose_mounting = Какой метод калибровки креп
onboarding-choose_mounting-description = Ориентация крепления корректирует размещение трекеров на вашем теле.
onboarding-choose_mounting-auto_mounting = Автоматическая привязка
# Italized text
onboarding-choose_mounting-auto_mounting-label = Экспериментальный
onboarding-choose_mounting-auto_mounting-label-v2 = Рекомендуется
onboarding-choose_mounting-auto_mounting-description = Это автоматически определит направления монтажа для всех ваших трекеров из 2 поз
onboarding-choose_mounting-manual_mounting = Ручная привязка
# Italized text
onboarding-choose_mounting-manual_mounting-label = Рекомендованный
onboarding-choose_mounting-manual_mounting-label-v2 = Может быть недостаточно точным
onboarding-choose_mounting-manual_mounting-description = Это позволит вам выбрать направление монтажа вручную для каждого трекера
# Multiline text
onboarding-choose_mounting-manual_modal-title =
@@ -969,6 +1018,7 @@ status_system-StatusSteamVRDisconnected =
*[other] В настоящее время не подключен к SteamVR через драйвер SlimeVR.
}
status_system-StatusTrackerError = В трекере { $trackerName } обнаружена ошибка.
status_system-StatusUnassignedHMD = VR гарнитура должна быть назначена как трекер головы.
## Tray Menu

View File

@@ -23,6 +23,8 @@ tips-find_tracker = Không rõ tracker nào đang được chọn? Di chuyển n
tips-do_not_move_heels = Không di chuyển gót chân trong khi đo
tips-file_select = Kéo và thả tệp để sử dụng hoặc <u>duyệt</u>.
tips-tap_setup = Bạn có thể từ từ nhấn vào 2 lần trình theo dõi của mình để chọn nó thay vì chọn nó từ menu.
tips-turn_on_tracker = Sử dụng thiết bị SlimeVR chính thức? Hãy nhớ <b><em>bật trình theo dõi của bạn</em></b> sau khi kết nối thiết bị với máy tính!
tips-failed_webgl = Không thể khởi tạo WebGL.
## Body parts
@@ -81,7 +83,7 @@ skeleton_bone-ELBOW_OFFSET = Sai số khuỷu tay
reset-reset_all = Đặt lại tất cả bộ phận
reset-full = Đặt lại
reset-mounting = Đặt lại hướng gắn tracker
reset-yaw = Reset Yaw
reset-yaw = Đặt lại chiều quay lệch
## Serial detection stuff
@@ -196,6 +198,7 @@ tracker-infos-hardware_rev = Revision phần cứng
tracker-infos-hardware_identifier = Hardware ID
tracker-infos-imu = Cảm biến IMU (IMU Sensor)
tracker-infos-board_type = Bảng mạch chính
tracker-infos-network_version = Phiên bản giao thức
## Tracker settings
@@ -215,6 +218,9 @@ tracker-settings-drift_compensation_section-edit = Cho phép bù trừ sai số
tracker-settings-name_section = Tên tracker
tracker-settings-name_section-description = Đặt cho nó một cái tên đẹp :3
tracker-settings-name_section-placeholder = Chân trái của JINODK
tracker-settings-forget = Quên thiết bị
tracker-settings-forget-description = Xóa thiết bị khỏi phần mềm SlimeVR và ngăn nó kết nối với nó cho đến khi máy chủ được khởi động lại. Cấu hình của trình theo dõi sẽ không bị mất.
tracker-settings-forget-label = Quên thiết bị
## Tracker part card info
@@ -304,10 +310,22 @@ settings-general-steamvr-description =
Hữu dụng nếu game chỉ hỗ trợ số lượng tracker giới hạn.
settings-general-steamvr-trackers-waist = Eo
settings-general-steamvr-trackers-chest = Ngực
settings-general-steamvr-trackers-feet = Bàn chân
settings-general-steamvr-trackers-knees = Đầu gối
settings-general-steamvr-trackers-elbows = Khuỷu tay
settings-general-steamvr-trackers-hands = Tay
settings-general-steamvr-trackers-left_foot = Bàn chân trái
settings-general-steamvr-trackers-right_foot = Bàn chân phải
settings-general-steamvr-trackers-left_knee = Đầu gối trái
settings-general-steamvr-trackers-right_knee = Đầu gối phải
settings-general-steamvr-trackers-left_elbow = Khuỷu tay trái
settings-general-steamvr-trackers-right_elbow = Khuỷu tay phải
settings-general-steamvr-trackers-left_hand = Tay trái
settings-general-steamvr-trackers-right_hand = Tay phải
settings-general-steamvr-trackers-tracker_toggling = Tự động giao thiết bị
settings-general-steamvr-trackers-tracker_toggling-description = Tự động xử lý bật hoặc tắt thiết bị đo SteamVR chuyển đổi tùy thuộc vào thiết bị đã giao của bạn
settings-general-steamvr-trackers-tracker_toggling-label = Tự động giao thiết bị
settings-general-steamvr-trackers-hands-warning =
<b>Lưu ý:</b> bộ theo dõi tay sẽ dùng đè tay cầm điều khiển của bạn.
Bạn có chắc không?
settings-general-steamvr-trackers-hands-warning-cancel = Hủy
settings-general-steamvr-trackers-hands-warning-done = Có
## Tracker mechanics
@@ -325,6 +343,7 @@ settings-general-tracker_mechanics-filtering-type-smoothing-description = Làm c
settings-general-tracker_mechanics-filtering-type-prediction = Dự đoán
settings-general-tracker_mechanics-filtering-type-prediction-description = Giảm độ trễ và làm chuyển động chân thật hơn, có thể khiến chuyển động không mượt mà
settings-general-tracker_mechanics-filtering-amount = Mức độ lọc
settings-general-tracker_mechanics-yaw-reset-smooth-time = Thời gian thiết lập lại chiều quay lệch (0s tắt làm mượt)
settings-general-tracker_mechanics-drift_compensation = Bù trừ sai số
# This cares about multilines
settings-general-tracker_mechanics-drift_compensation-description =
@@ -333,6 +352,11 @@ settings-general-tracker_mechanics-drift_compensation-description =
settings-general-tracker_mechanics-drift_compensation-enabled-label = Bù trừ sai số
settings-general-tracker_mechanics-drift_compensation-amount-label = Mức độ bù trừ
settings-general-tracker_mechanics-drift_compensation-max_resets-label = Số lần đặt lại được áp dụng bù trừ
settings-general-tracker_mechanics-save_mounting_reset = Lưu thiết bị đã giao tự động
settings-general-tracker_mechanics-save_mounting_reset-description =
Lưu thiết bị đã giao tự động cho các thiết bị giữa các lần khởi động lại. Có ích
khi mặc một bộ đồ SlimeVR mà trình theo dõi không di chuyển giữa các phiên. <b>Không được khuyến khích cho người dùng bình thường!</b>
settings-general-tracker_mechanics-save_mounting_reset-enabled-label = Đặt lại hướng gắn thiết bị
## FK/Tracking settings
@@ -359,6 +383,9 @@ settings-general-fk_settings-leg_fk-reset_mounting_feet = Đặt lại hướng
settings-general-fk_settings-arm_fk = Track cánh tay
settings-general-fk_settings-arm_fk-description = Thay đổi cách cánh tay được track
settings-general-fk_settings-arm_fk-force_arms = Lấy dữ liệu cánh tay từ kính
settings-general-fk_settings-reset_settings = Đặt lại cài đặt
settings-general-fk_settings-reset_settings-reset_hmd_pitch-description = Đặt lại cao độ của HMD (xoay dọc) khi thiết lập lại toàn bộ. Hữu ích nếu đeo HMD trên trán cho VTubing hoặc mocap. Lưu ý không bật VR khi sử dụng.
settings-general-fk_settings-reset_settings-reset_hmd_pitch = Đặt lại cao độ HMD
settings-general-fk_settings-arm_fk-reset_mode-description = Thay đổi tư thế cánh tay để đặt lại hướng gắn tracker.
settings-general-fk_settings-arm_fk-back = Khuỷu tay ra sau
settings-general-fk_settings-arm_fk-back-description = Chế độ mặc định, với cánh tay trên trỏ về phía sau và cánh tay dưới hướng về phía trước.
@@ -368,8 +395,22 @@ settings-general-fk_settings-arm_fk-tpose_down = T-pose (ngược lại)
settings-general-fk_settings-arm_fk-tpose_down-description = Hai tay của bạn sẽ đưa lên 90 độ sang hai bên khi đặt lại hoàn toàn, và hai tay hướng xuống hai bên khi đặt lại hướng gắn tracker.
settings-general-fk_settings-arm_fk-forward = Hai tay ra trước
settings-general-fk_settings-arm_fk-forward-description = Hai cánh tay của bạn nâng lên 90 độ về phía trước. Hữu dụng cho việc VTubing.
settings-general-fk_settings-skeleton_settings-toggles = Bật tắt bộ xương
settings-general-fk_settings-skeleton_settings-description = Bật hoặc tắt các cài đặt về khung cơ thể. Các lựa chọn này nên được giữ bật
settings-general-fk_settings-skeleton_settings-extended_spine_model = Mô hình cột sống mở rộng
settings-general-fk_settings-skeleton_settings-extended_pelvis_model = Mô hình xương chậu mở rộng
settings-general-fk_settings-skeleton_settings-extended_knees_model = Mô hình đầu gối mở rộng
settings-general-fk_settings-skeleton_settings-ratios = Tỷ lệ khung xương
settings-general-fk_settings-skeleton_settings-ratios-description = Thay đổi các giá trị của cài đặt bộ xương. Bạn có thể cần phải điều chỉnh tỷ lệ của bạn sau khi thay đổi những điều này.
settings-general-fk_settings-skeleton_settings-impute_waist_from_chest_hip = Quy kết eo từ ngực đến hông
settings-general-fk_settings-skeleton_settings-impute_waist_from_chest_legs = Quy kết eo từ ngực đến hông
settings-general-fk_settings-skeleton_settings-impute_hip_from_chest_legs = Gán hông từ ngực đến chân
settings-general-fk_settings-skeleton_settings-impute_hip_from_waist_legs = Gán hông từ eo đến chân
settings-general-fk_settings-skeleton_settings-interp_hip_legs = Tính trung bình số quay hông và lăn bằng chân.
settings-general-fk_settings-skeleton_settings-interp_knee_tracker_ankle = Tính trung bình của máy theo dõi đầu gối ngáp và lăn bằng mắt cá chân '
settings-general-fk_settings-skeleton_settings-interp_knee_ankle = Tính trung bình của chiều quay đầu gối ngáp và lăn bằng mắt cá chân '
settings-general-fk_settings-self_localization-title = Chế độ Mocap
settings-general-fk_settings-self_localization-description = Chế độ Mocap cho phép bộ xương theo dõi đại khái vị trí của chính nó mà không cần kính VR hoặc các thiết bị theo dõi khác. Lưu ý rằng điều này yêu cầu bộ theo dõi chân và đầu để hoạt động và chức năng này vẫn đang trong quá trình thử nghiệm.
settings-general-fk_settings-vive_emulation-title = Giả lập tracker Vive
settings-general-fk_settings-vive_emulation-description = Giả lập cách tracker của Vive gặp vấn đề với việc theo dõi eo, đây là 1 tính năng được làm cho vui và sẽ làm giảm độ chính xác
settings-general-fk_settings-vive_emulation-label = Giả lập tracker Vive
@@ -389,9 +430,18 @@ settings-general-gesture_control-taps =
# This is a unit: 3 trackers, 2 trackers, 1 tracker
# $amount (Number) - Amount of trackers
settings-general-gesture_control-trackers = { $amount } trackers
settings-general-gesture_control-yawResetEnabled = Bật chạm để đặt lại chiều quay
settings-general-gesture_control-yawResetDelay = Thời gian delay trước khi đặt lại
settings-general-gesture_control-yawResetTaps = Số lần chạm để đặt lại chiều quay
settings-general-gesture_control-fullResetEnabled = Bật chạm để đặt lại chiều quay
settings-general-gesture_control-fullResetDelay = Thời gian delay trước khi đặt lại full
settings-general-gesture_control-fullResetTaps = Số lần chạm để đặt lại full
settings-general-gesture_control-mountingResetEnabled = Chạm để đặt lại hướng gắn tracker
settings-general-gesture_control-mountingResetDelay = Thời gian delay trước khi đặt lại hướng gắn tracker
settings-general-gesture_control-mountingResetTaps = Số lần chạm cho đặt lại hướng gắn tracker
# The number of trackers that can have higher acceleration before a tap is rejected
settings-general-gesture_control-numberTrackersOverThreshold = Số thiết bị có thể vượt phát hiện
settings-general-gesture_control-numberTrackersOverThreshold-description = Tăng số này nếu tính năng chạm thiết bị không hoạt động. Không tăng nó quá trên mức cần thiết để làm cho phát hiện chạm hoạt động vì nó sẽ gây ra nhiều kết quả sai hơn.
## Appearance settings
@@ -405,9 +455,12 @@ settings-general-interface-lang-description = Đổi ngôn ngữ hiển thị (C
settings-general-interface-lang-placeholder = Chọn ngôn ngữ để sử dụng (Select the language to use)
# Keep the font name untranslated
settings-interface-appearance-font = Phông chữ cho GUI
settings-interface-appearance-font-description = Cài đặt này thay đổi phông chữ được sử dụng bởi giao diện.
settings-interface-appearance-font-placeholder = Phông chữ mặc định
settings-interface-appearance-font-os_font = Phông chữ hệ điều hành
settings-interface-appearance-font-slime_font = Phông chữ mặc định
settings-interface-appearance-font_size = Tỷ lệ phông chữ cơ bản
settings-interface-appearance-font_size-description = Điều này ảnh hưởng đến kích thước phông chữ của toàn bộ giao diện ngoại trừ bảng cài đặt này.
## Notification settings
@@ -415,7 +468,24 @@ settings-interface-notifications = Thông báo
settings-general-interface-serial_detection = Nhận dạng thiết bị Serial mới
settings-general-interface-serial_detection-description = Hiển thị pop-up mỗi lần một thiết bị Serial mới được kết nối qua USB (có thể là tracker), giúp cải thiện quá trình thiết lập tracker
settings-general-interface-serial_detection-label = Nhận dạng thiết bị Serial mới
settings-general-interface-feedback_sound = Âm thanh phản hồi
settings-general-interface-feedback_sound-description = Tùy chọn này sẽ phát âm thanh khi thiết lập lại được kích hoạt.
settings-general-interface-feedback_sound-label = Âm thanh phản hồi
settings-general-interface-feedback_sound-volume = Âm lượng phản hồi
settings-general-interface-connected_trackers_warning = Cảnh báo với thiết bị đã kết nối
settings-general-interface-connected_trackers_warning-description = Tùy chọn này sẽ hiển thị cửa sổ bật lên mỗi khi bạn thử thoát khỏi SlimeVR trong khi có một hoặc nhiều thiết bị theo dõi được kết nối. Nó nhắc nhở bạn tắt trình theo dõi khi bạn hoàn tất để duy trì tuổi thọ pin.
settings-general-interface-connected_trackers_warning-label = Cảnh báo thiết bị đã kết nối khi thoát chương trình
settings-general-interface-use_tray = Thu nhỏ vào khay hệ thống
settings-general-interface-use_tray-description = Cho phép bạn đóng cửa sổ mà không cần đóng máy chủ SlimeVR để bạn có thể tiếp tục sử dụng nó mà không bị GUI làm phiền.
settings-general-interface-use_tray-label = Thu nhỏ vào khay hệ thống
settings-general-interface-discord_presence = Chia sẻ hoạt động trên Discord
settings-general-interface-discord_presence-description = Cho Discord của bạn biết rằng bạn đang sử dụng SlimeVR cùng với số lượng trình theo dõi IMU bạn đang sử dụng.
settings-general-interface-discord_presence-label = Chia sẻ hoạt động trên Discord
settings-general-interface-discord_presence-message =
{ $amount ->
[0] Đang quay trên Slime
*[other] Đang dùng { $amount } điểm full body
}
## Serial settings
@@ -427,11 +497,19 @@ settings-serial-description =
settings-serial-connection_lost = Kết nối đến Serial đã mất, đang kết nối lại...
settings-serial-reboot = Khởi động lại
settings-serial-factory_reset = Khôi phục cài đặt gốc
# This cares about multilines
# <b>text</b> means that the text should be bold
settings-serial-factory_reset-warning =
<b>Lưu ý:</b> Thao tác này sẽ đặt lại trình theo dõi về cài đặt gốc.
Đặt lại bao gồm tất cả các cài đặt Wi-Fi và hiệu chuẩn (Calibrate) <b>sẽ bị mất!</b>
settings-serial-factory_reset-warning-ok = Tôi biết mình đang làm gì
settings-serial-factory_reset-warning-cancel = Hủy
settings-serial-get_infos = Lấy thông tin
settings-serial-serial_select = Chọn cổng Serial
settings-serial-auto_dropdown_item = Tự động
settings-serial-get_wifi_scan = Quét WiFi
settings-serial-file_type = Văn bản thô
settings-serial-save_logs = Lưu vào tệp
## OSC router settings
@@ -462,14 +540,17 @@ settings-osc-router-network-address-placeholder = Địa chỉ IPv4
settings-osc-vrchat = VRChat OSC Trackers
# This cares about multilines
settings-osc-vrchat-description =
Thay đổi các cài đặt liên quan đến VRChat để nhận dữ liệu từ kính và
gửi dữ liệu tracker cho Full-body tracking (hoạt động với kính ở chế độ standalone)
settings-osc-vrchat-description-v1 =
Thay đổi cài đặt cụ thể cho OSC Trackers được sử dụng để gửi
dữ liệu đo đến các ứng dụng không có SteamVR (ví dụ: Quest Standalone).
Hãy đảm bảo bật OSC trong VRChat thông qua Menu hành động trong OSC > Enabled.
Để cho phép nhận kính thực tế ảo HMD và dữ liệu bộ điều khiển từ VRChat, hãy vào menu chính của bạn
cài đặt trong Tracking & IK > Allow Sending Head and Wrist VR Tracking OSC Data.
settings-osc-vrchat-enable = Dữ liệu OSC
settings-osc-vrchat-enable-description = Cho phép nhận và gửi dữ liệu OSC
settings-osc-vrchat-enable-label = Giao tiếp dữ liệu OSC
settings-osc-vrchat-network = Cổng mạng
settings-osc-vrchat-network-description = Chọn cổng mạng để nhận và gửi dữ liệu OSC đến VRChat
settings-osc-vrchat-network-description-v1 = Đặt các cổng để lấy và gửi dữ liệu. Có thể giữ nguyên cho VRChat.
settings-osc-vrchat-network-port_in =
.label = Cổng vào
.placeholder = Cổng vào (Mặc định: 9001)
@@ -477,7 +558,7 @@ settings-osc-vrchat-network-port_out =
.label = Cổng ra
.placeholder = Cổng ra (Mặc định: 9000)
settings-osc-vrchat-network-address = Địa chỉ mạng
settings-osc-vrchat-network-address-description = Địa chỉ mạng mà SlimeVR sẽ gửi dữ liệu OSC đến VRChat (có thể tìm thấy địa chỉ mạng trong menu cài đặt Wi-Fi)
settings-osc-vrchat-network-address-description-v1 = Chọn địa chỉ để gửi dữ liệu đến. Có thể giữ nguyên cho VRChat.
settings-osc-vrchat-network-address-placeholder = Địa chỉ IP của thiết bị chơi VRChat
settings-osc-vrchat-network-trackers = Cấu hình Tracker
settings-osc-vrchat-network-trackers-description = Chọn các tracker mà SlimeVR sẽ gửi dữ liệu OSC đến VRChat
@@ -490,6 +571,10 @@ settings-osc-vrchat-network-trackers-elbows = Khuỷu tay
## VMC OSC settings
settings-osc-vmc = Virtual Motion Capture
# This cares about multilines
settings-osc-vmc-description =
Thay đổi cài đặt cụ thể cho giao thức VMC (Virtual Motion Capture)
để gửi dữ liệu thân của SlimeVR và nhận dữ liệu thân từ các ứng dụng khác.
settings-osc-vmc-enable = Bật
settings-osc-vmc-enable-description = Cho phép nhận và gửi dữ liệu OSC
settings-osc-vmc-enable-label = Chuyển tiếp dữ liệu OSC
@@ -513,6 +598,12 @@ settings-osc-vmc-vrm-model_loaded =
*[other] Mô hình chưa có tiêu đề đã được tải
}
settings-osc-vmc-vrm-file_select = Kéo và thả mô hình để sử dụng hoặc <u>duyệt file</u>
settings-osc-vmc-anchor_hip = Cố định ở hông
settings-osc-vmc-anchor_hip-description = Cố định theo dõi ở hông, hữu ích cho VTubing ngồi. Nếu tắt, hãy tải mô hình VRM.
settings-osc-vmc-anchor_hip-label = Cố định ở hông
settings-osc-vmc-mirror_tracking = Phản chiếu ngược theo dõi cơ thể
settings-osc-vmc-mirror_tracking-description = Phản chiếu theo dõi theo chiều ngang.
settings-osc-vmc-mirror_tracking-label = Phản chiếu ngược theo dõi cơ thể
## Setup/onboarding menu
@@ -520,6 +611,9 @@ onboarding-skip = Bỏ qua cài đặt
onboarding-continue = Tiếp tục
onboarding-wip = Chưa hoàn thiện
onboarding-previous_step = Quay lại
onboarding-setup_warning =
<b>Lưu ý:</b> Trình thiết lập ban đầu là cần thiết để theo dõi tốt,
bước này cần thiết nếu đây là lần đầu tiên bạn sử dụng SlimeVR.
onboarding-setup_warning-skip = Bỏ qua cài đặt
onboarding-setup_warning-cancel = Tiếp tục thiết lập
@@ -546,6 +640,24 @@ onboarding-reset_tutorial-back = Quay lại cân chỉnh vị trí gắn tracker
onboarding-reset_tutorial = Làm lại
onboarding-reset_tutorial-explanation = Trong khi bạn sử dụng trình theo dõi của mình, tracker có thể bị lệch khỏi căn chỉnh do IMU bị trượt, trôi dạt hoặc vì bạn có thể đã di chuyển chúng về mặt vật lý. Bạn có một số cách để khắc phục điều này.
onboarding-reset_tutorial-skip = Bỏ qua bước
# Cares about multiline
onboarding-reset_tutorial-0 =
Nhấn { $taps } lần thiết bị được đánh dấu để kích hoạt đặt lại chiều quay.
Điều này sẽ làm cho các trình theo dõi quay mặt về cùng hướng với kính thực thế ảo (HMD) của bạn.
# Cares about multiline
onboarding-reset_tutorial-1 =
Nhấn vào { $taps } lần thiết bị được đánh dấu để kích hoạt đặt lại toàn bộ.
Bạn cần phải đứng thẳng tay để làm việc này (i-pose). Có độ trễ 3 giây (có thể định cấu hình) trước khi nó thực sự xảy ra.
Điều này đặt lại hoàn toàn vị trí và xoay của tất cả các trình theo dõi của bạn. Nó sẽ khắc phục hầu hết các vấn đề.
# Cares about multiline
onboarding-reset_tutorial-2 =
Nhấn vào { $taps } lần thiết bị được đánh dấu để kích hoạt đặt lại lắp.
Thiết lập lại gắn kết giúp ích cho cách các trình theo dõi thực sự được đặt vào bạn, vì vậy nếu bạn vô tình di chuyển chúng và thay đổi cách chúng được định hướng với số lượng lớn, điều này sẽ hữu ích.
Bạn cần phải ở trên một tư thế như bạn đang trượt tuyết như nó được hiển thị trên trình hướng dẫn gắn tự động và bạn có độ trễ 3 giây (có thể định cấu hình) trước khi nó được kích hoạt.
## Setup start
@@ -569,8 +681,8 @@ onboarding-done-close = Đóng hướng dẫn
onboarding-connect_tracker-back = Quay lại cài đặt Wi-Fi
onboarding-connect_tracker-title = Kết nối tracker
onboarding-connect_tracker-description-p0 = Cập nhật thông tin Wi-Fi cho tracker
onboarding-connect_tracker-description-p1 = Hãy kết nối các tracker chưa thiết lập qua cổng USB
onboarding-connect_tracker-description-p0-v1 = Bây giờ vào phần thú vị, kết nối thiết bị!
onboarding-connect_tracker-description-p1-v1 = Kết nối từng thiết bị một lần thông qua cổng USB.
onboarding-connect_tracker-issue-serial = Có vấn đề với việc kết nối? Kiểm tra thông tin qua cổng Serial
onboarding-connect_tracker-usb = USB Tracker
onboarding-connect_tracker-connection_status-none = Đang tìm tracker
@@ -596,10 +708,14 @@ onboarding-connect_tracker-next = Đã kết nối với tất cả tracker
## Tracker calibration tutorial
onboarding-calibration_tutorial = Hướng dẫn hiệu chuẩn IMU
onboarding-calibration_tutorial-subtitle = Cái này sẽ giúp giảm trôi trượt theo dõi!
onboarding-calibration_tutorial-description = Mỗi khi bạn bật thiết bị theo dõi, chúng cần nghỉ ngơi một lúc trên bề mặt phẳng để hiệu chỉnh. Hãy làm điều tương tự bằng cách nhấp vào nút "{ onboarding-calibration_tutorial-calibrate }", <b>và không di chuyển chúng!</b>
onboarding-calibration_tutorial-calibrate = Tôi đã đặt thiết bị theo dõi của mình lên bàn
onboarding-calibration_tutorial-status-waiting = Đang chờ bạn hoàn thành
onboarding-calibration_tutorial-status-calibrating = Đang hiệu chuẩn
onboarding-calibration_tutorial-status-success = Nice!
onboarding-calibration_tutorial-status-error = Thiết bị đã di chuyển
## Tracker assignment tutorial
@@ -607,6 +723,8 @@ onboarding-assignment_tutorial = Làm thế nào để chuẩn bị một Slime
onboarding-assignment_tutorial-first_step = 1. Đặt nhãn dán bộ phận cơ thể (nếu có) trên tracker theo lựa chọn của bạn
# This text has a character limit of around 11 characters, so please keep it short
onboarding-assignment_tutorial-sticker = Sticker
onboarding-assignment_tutorial-second_step-v2 = 2. Gắn dây đeo vào thiết bị theo dõi của bạn, giữ cho mặt Velcro của dây đeo hướng cùng hướng với hướng thiết bị của trình theo dõi của bạn:
onboarding-assignment_tutorial-second_step-continuation-v2 = Mặt Velcro cho extension phải hướng lên như hình ảnh sau:
onboarding-assignment_tutorial-done = Tôi đã dán nhãn dán và dây đai!
## Tracker assignment setup
@@ -624,14 +742,112 @@ onboarding-assign_trackers-assigned =
} đã giao
onboarding-assign_trackers-advanced = Xem thêm vị trí đặt
onboarding-assign_trackers-next = Hoàn thành
onboarding-assign_trackers-mirror_view = Xem hình phản chiếu
onboarding-assign_trackers-option-amount = x{ $trackersCount }
onboarding-assign_trackers-option-label =
{ $mode ->
[lower-body] Tất cả thiết bị
[core] { "" }
[enhanced-core] { "" }
[full-body] { "" }
*[all] { "" }
}
onboarding-assign_trackers-option-description =
{ $mode ->
[lower-body] Tối thiều để có full body tracking
[core] + Thân eo
[enhanced-core] + Quay bàn chân
[full-body] + Khửu tay
*[all] Tất cả thiết bị được giao
}
## Tracker assignment warnings
# Note for devs, number is used for representing boolean states per bit.
# $unassigned (Number) - Bits are based on BodyAssignment.ASSIGNMENT_RULES order
onboarding-assign_trackers-warning-LEFT_FOOT =
{ $unassigned ->
[6] Bàn chân trái được xác định nhưng bạn cần thêm chân dưới kèm theo để hoạt động!
[5] Bàn chân trái được xác định nhưng bạn cần thêm chân trên kèm theo để hoạt động!
[4] Bàn chân trái được xác định nhưng bạn cần thêm chân trên và chân dưới kèm theo để hoạt động!
[3] Bàn chân trái được xác định nhưng bạn cần thêm ngực, eo hoặc bụng kèm theo để hoạt động!
[2] Bàn chân trái được xác định nhưng bạn cần thêm chân trên, ngực, eo hoặc bụng kèm theo để hoạt động!
[1] Bàn chân trái được xác định nhưng bạn cần thêm chân dưới, ngực, eo hoặc bụng kèm theo để hoạt động!
[0] Bàn chân trái được xác định nhưng bạn cần thêm chân trên, chân dưới, ngực, eo hoặc bụng kèm theo để hoạt động!
*[unknown] Bàn chân trái được xác định nhưng cần thêm bộ phận cơ thể thiếu!
}
# $unassigned (Number) - Bits are based on BodyAssignment.ASSIGNMENT_RULES order
onboarding-assign_trackers-warning-RIGHT_FOOT =
{ $unassigned ->
[0] Bàn chân phải được xác định nhưng bạn cần thêm chân trên, chân dưới, ngực, eo hoặc bụng kèm theo để hoạt động!
[1] Bàn chân phải được xác định nhưng bạn cần thêm chân dưới, ngực, eo hoặc bụng kèm theo để hoạt động!
[2] Bàn chân phải được xác định nhưng bạn cần thêm chân trên, ngực, eo hoặc bụng kèm theo để hoạt động!
[3] Bàn chân phải được xác định nhưng bạn cần thêm ngực, eo hoặc bụng kèm theo để hoạt động!
[4] Bàn chân phải được xác định nhưng bạn cần thêm chân trên và chân dưới kèm theo để hoạt động!
[5] Bàn chân phải được xác định nhưng bạn cần thêm chân trên kèm theo để hoạt động!
[6] Bàn chân phải được xác định nhưng bạn cần thêm chân dưới kèm theo để hoạt động!
*[unknown] Bàn chân phải được xác định nhưng cần thêm bộ phận cơ thể thiếu!
}
# $unassigned (Number) - Bits are based on BodyAssignment.ASSIGNMENT_RULES order
onboarding-assign_trackers-warning-LEFT_LOWER_LEG =
{ $unassigned ->
[0] Chân trên trái được xác định nhưng cần thêm chân trên!
[1] Chân trên trái được xác định nhưng cần thêm ngực, eo và bụng được giao!
[2] Chân trên trái được xác định nhưng cần thêm chân trên!
*[unknown] Chân trên trái được xác định nhưng cần thêm bộ phận cơ thể thiếu!
}
# $unassigned (Number) - Bits are based on BodyAssignment.ASSIGNMENT_RULES order
onboarding-assign_trackers-warning-RIGHT_LOWER_LEG =
{ $unassigned ->
[0] Chân trên phải được xác định nhưng cần thêm chân trên!
[1] Chân trên phải được xác định nhưng cần thêm ngực, eo và bụng được giao!
[2] Chân trên phải được xác định nhưng cần thêm chân trên!
*[unknown] Chân trên phải được xác định nhưng cần thêm bộ phận cơ thể thiếu!
}
# $unassigned (Number) - Bits are based on BodyAssignment.ASSIGNMENT_RULES order
onboarding-assign_trackers-warning-LEFT_UPPER_LEG =
{ $unassigned ->
[0] Chân trái trên được xác định nhưng cần thêm ngực, eo hoặc bụng!
*[unknown] Chân trái trên được xác định nhưng cần thêm bộ phận cơ thể thiếu!
}
# $unassigned (Number) - Bits are based on BodyAssignment.ASSIGNMENT_RULES order
onboarding-assign_trackers-warning-RIGHT_UPPER_LEG =
{ $unassigned ->
[0] Chân phải trên được xác định nhưng cần thêm ngực, eo hoặc bụng!
*[unknown] Chân phải trên được xác định nhưng cần thêm bộ phận cơ thể thiếu!
}
# $unassigned (Number) - Bits are based on BodyAssignment.ASSIGNMENT_RULES order
onboarding-assign_trackers-warning-HIP =
{ $unassigned ->
[0] Eo được xác định được xác định nhưng cần thêm ngực!
*[unknown] Eo được xác định được xác định nhưng cần thêm bộ phận cơ thể thiếu!
}
# $unassigned (Number) - Bits are based on BodyAssignment.ASSIGNMENT_RULES order
onboarding-assign_trackers-warning-WAIST =
{ $unassigned ->
[0] Bụng được xác định nhưng cần thêm ngực!
*[unknown] Bụng được xác định được xác định nhưng cần thêm bộ phận cơ thể thiếu!
}
## Tracker mounting method choose
onboarding-choose_mounting = Bạn muốn dùng phương pháp hiểu chuần nào?
# Multiline text
onboarding-choose_mounting-description = Hướng lắp đặt chính xác cho vị trí của thiết bị theo dõi trên cơ thể của bạn.
onboarding-choose_mounting-auto_mounting = Cân chỉnh tự động
# Italized text
onboarding-choose_mounting-auto_mounting-label = Thử nghiệm
onboarding-choose_mounting-auto_mounting-label-v2 = Khuyến khích dùng
onboarding-choose_mounting-auto_mounting-description = Điều này sẽ tự động phát hiện các hướng lắp đặt cho tất cả các thiết bị của bạn từ 2 tư thế
onboarding-choose_mounting-manual_mounting = Cân chỉnh thủ công
# Italized text
onboarding-choose_mounting-manual_mounting-label-v2 = Có thể không đủ chính xác
onboarding-choose_mounting-manual_mounting-description = Điều này sẽ cho phép bạn chọn hướng lắp theo cách thủ công cho từng thiết bị
# Multiline text
onboarding-choose_mounting-manual_modal-title =
Bạn có chắc chắn muốn
đo hướng quay tự động?
onboarding-choose_mounting-manual_modal-description = <b>Hiệu chuẩn lắp thủ công được khuyến nghị cho người dùng mới</b>, vì các tư thế của hiệu chuẩn lắp tự động có thể khó thực hiện ngay trước và có thể cần một số thực hành.
onboarding-choose_mounting-manual_modal-confirm = Tôi chắc chắn về những gì tôi đang làm
onboarding-choose_mounting-manual_modal-cancel = Hủy
## Tracker manual mounting setup
@@ -665,6 +881,12 @@ onboarding-automatic_mounting-put_trackers_on-next = Tiếp tục
## Tracker proportions method choose
onboarding-choose_proportions = Phương pháp hiệu chuẩn tỷ lệ nào để sử dụng?
# Multiline string
onboarding-choose_proportions-description-v1 =
Tỷ lệ cơ thể được sử dụng để biết các số đo của cơ thể bạn. Họ được yêu cầu tính toán vị trí của trình theo dõi.
Khi tỷ lệ cơ thể của bạn không khớp với tỷ lệ được lưu, độ chính xác theo dõi của bạn sẽ kém hơn và bạn sẽ nhận thấy những thứ như trượt băng hoặc trượt, hoặc cơ thể của bạn không khớp với hình đại diện của bạn.
<b>Bạn chỉ cần đo cơ thể của bạn một lần!</b> Trừ khi chúng sai hoặc cơ thể bạn đã thay đổi, thì bạn không cần phải làm lại.
onboarding-choose_proportions-auto_proportions = Đo kích thước cơ thể tự động
# Italized text
onboarding-choose_proportions-auto_proportions-subtitle = Khuyến khích dùng
@@ -688,6 +910,7 @@ onboarding-manual_proportions-back = Quay lại cân chỉnh hướng gắn
onboarding-manual_proportions-title = Đo kích thước cơ thể thủ công
onboarding-manual_proportions-precision = Cân chỉnh cụ thể (giảm hệ số chỉnh)
onboarding-manual_proportions-auto = Đo kích thước cơ thể tự động
onboarding-manual_proportions-ratio = Điều chỉnh theo nhóm tỷ lệ
## Tracker automatic proportions setup
@@ -712,6 +935,9 @@ onboarding-automatic_proportions-check_height-title = Kiểm tra chiều cao c
onboarding-automatic_proportions-check_height-description = Chúng tôi sử dụng chiều cao của bạn làm cơ sở cho các phép đo của chúng tôi bằng cách sử dụng chiều cao của headset (HMD) làm chiều cao ước tính thực tế của bạn, nhưng tốt hơn hết bạn nên tự kiểm tra xem chúng có đúng không!
# All the text is in bold!
onboarding-automatic_proportions-check_height-calculation_warning = Vui lòng nhấn nút trong khi đứng <u>thẳng</u> để tính chiều cao của bạn. Bạn có 3 giây sau khi nhấn nút!
onboarding-automatic_proportions-check_height-guardian_tip =
Nếu bạn đang sử dụng Kính VR Standalone, hãy đảm bảo có guardian /
Ranh giới được bật để chiều cao của bạn là chính xác!
onboarding-automatic_proportions-check_height-fetch_height = Tôi đang đứng!
# Context is that the height is unknown
onboarding-automatic_proportions-check_height-unknown = Không rõ
@@ -750,13 +976,13 @@ onboarding-automatic_proportions-verify_results-confirm = Kết quả tương đ
onboarding-automatic_proportions-done-title = Đã lưu chỉ số đo
onboarding-automatic_proportions-done-description = Quá trình đo đã hoàn tất
onboarding-automatic_proportions-error_modal =
<b>Cảnh báo:</b> Một lỗi đã được tìm thấy trong khi ước tính tỷ lệ cơ thể!
Vui lòng <docs>kiểm tra tài liệu</docs> hoặc tham gia <discord>Discord</discord> của chúng tôi để được trợ giúp ^_^
<b>Lưu ý:</b> Một lỗi đã được tìm thấy trong khi ước tính tỷ lệ cơ thể!
Vui lòng <docs>kiểm tra hướng dẫn</docs> hoặc tham gia <discord>Discord</discord> của chúng tôi để được trợ giúp ^_^
onboarding-automatic_proportions-error_modal-confirm = Đã hiểu!
## Home
home-no_trackers = Không tìm thấy tracker / Tracker chưa được gán
home-no_trackers = Chưa có thiết bị nào được phát hiện hoặc điều ra
## Trackers Still On notification
@@ -772,7 +998,36 @@ trackers_still_on-modal-cancel = Vui lòng đợi...
status_system-StatusTrackerReset = Bạn nên thực hiện thiết lập lại toàn bộ vì một hoặc nhiều trình theo dõi không được điều chỉnh.
status_system-StatusSteamVRDisconnected =
{ $type ->
[steamvr_feeder] Hiện đang không kết nối với SteamVR thông qua trình điều khiển SlimeVR Feeder App.
*[other] Hiện đang không kết nối với SteamVR thông qua driver SlimeVR.
[steamvr_feeder] Chưa kết nối với SteamVR thông qua trình điều khiển SlimeVR Feeder App.
*[other] Chưa kết nối với SteamVR thông qua driver SlimeVR.
}
status_system-StatusTrackerError = Tracker { $trackerName } có lỗi.
status_system-StatusUnassignedHMD = Kính thực tế ảo VR này nên được giao là bộ theo dõi đầu.
## Tray Menu
tray_menu-show = Xem
tray_menu-hide = Ẩn
tray_menu-quit = Thoát
## First exit modal
tray_or_exit_modal-title = Nút đóng nên làm gì?
# Multiline text
tray_or_exit_modal-description =
Điều này cho phép bạn chọn xem bạn muốn thoát khỏi chương trình hoặc thu nhỏ nó vào khay khi nhấn nút đóng.
Bạn có thể thay đổi điều này sau trong cài đặt giao diện.
tray_or_exit_modal-radio-exit = Thoát khi đóng
tray_or_exit_modal-radio-tray = Thu nhỏ vào khay hệ thống
tray_or_exit_modal-submit = Lưu
tray_or_exit_modal-cancel = Hủy
## Unknown device modal
unknown_device-modal-title = Thiết bị mới đã được tìm thấy!
unknown_device-modal-description =
Có thiết bị mới với địa chỉ MAC <b>{ $deviceId }</b>.
Bạn có muốn kết nối nó với SlimeVR không?
unknown_device-modal-confirm = Chắc!
unknown_device-modal-forget = Bỏ qua

View File

@@ -383,6 +383,9 @@ settings-general-fk_settings-leg_fk-reset_mounting_feet = 腳部配戴重置
settings-general-fk_settings-arm_fk = 手臂追蹤
settings-general-fk_settings-arm_fk-description = 強制透過頭戴顯示器來追蹤手臂,即使有手部的定位資料。
settings-general-fk_settings-arm_fk-force_arms = 強制從頭戴顯示器進行手臂追蹤
settings-general-fk_settings-reset_settings = 重置設定
settings-general-fk_settings-reset_settings-reset_hmd_pitch-description = 進行完整重置時,也重置頭戴顯示器的仰角(垂直旋轉),適用於將頭顯戴在額頭上,以進行虛擬直播或是動作捕捉的情境。若用於 VR 請勿啟用本設定。
settings-general-fk_settings-reset_settings-reset_hmd_pitch = 重置頭戴顯示器仰角
settings-general-fk_settings-arm_fk-reset_mode-description = 更改配戴重置時,手臂需要做出的姿勢。
settings-general-fk_settings-arm_fk-back = 收肘姿勢
settings-general-fk_settings-arm_fk-back-description = 預設模式,重置時手肘朝後,前臂向前。
@@ -474,6 +477,14 @@ settings-general-interface-connected_trackers_warning-label = 當退出程式時
settings-general-interface-use_tray = 最小化到系統列
settings-general-interface-use_tray-description = 本選項可以讓您在關閉視窗時不會關閉 SlimeVR 的伺服器程式,讓您在不受圖形介面的打擾下繼續使用追蹤器。
settings-general-interface-use_tray-label = 最小化到系統列
settings-general-interface-discord_presence = 在 Discord 上分享活動
settings-general-interface-discord_presence-description = 在 Discord 上顯示您正在使用 SlimeVR以及使用中的追蹤器的數量。
settings-general-interface-discord_presence-label = 在 Discord 上分享活動
settings-general-interface-discord_presence-message =
{ $amount ->
[0] 正在捕捉史萊姆
*[other] 正在使用 { $amount } 個追蹤器
}
## Serial settings
@@ -494,6 +505,8 @@ settings-serial-get_infos = 取得資訊
settings-serial-serial_select = 選擇串列埠
settings-serial-auto_dropdown_item = 自動
settings-serial-get_wifi_scan = 取得 Wi-Fi 掃描
settings-serial-file_type = 純文字格式
settings-serial-save_logs = 儲存到檔案
## OSC router settings
@@ -524,14 +537,15 @@ settings-osc-router-network-address-placeholder = IPV4 地址
settings-osc-vrchat = VRChat OSC 追蹤器
# This cares about multilines
settings-osc-vrchat-description =
此處可更改 VRChat 專用的設定以取得頭戴顯示器的資料,並傳送追蹤器
資料以進行全身追蹤,不須透過 SteamVR例如 Quest 單機版本)
settings-osc-vrchat-description-v1 =
變更 OSC 追蹤器標準的設定,該標準可用於傳送追蹤器資料到不使用 SteamVR 的應用程式(例如 Quest 單機版)。
請確保 VRChat 中的動作選單內OSC 設定「選項→OSC→已啟用」已經開啟
SlimeVR 若要能透過 VRChat 接收頭戴顯示器以及控制器的資料,請進入主選單的設定,並開啟「追蹤 & IK→允許透過 OSC 發送頭部與腕部的 VR 追蹤數據」。
settings-osc-vrchat-enable = 啟用
settings-osc-vrchat-enable-description = 切換資料的傳送和接收。
settings-osc-vrchat-enable-label = 啟用
settings-osc-vrchat-network = 連接埠
settings-osc-vrchat-network-description = 設定與 VRChat 監聽和傳送資料的連接埠
settings-osc-vrchat-network-description-v1 = 設定收發追蹤器資料的連接埠埠號,使用 VRChat 不須更改
settings-osc-vrchat-network-port_in =
.label = 輸入埠
.placeholder = 輸入埠預設9001
@@ -539,7 +553,7 @@ settings-osc-vrchat-network-port_out =
.label = 輸出埠
.placeholder = 輸出埠預設9000
settings-osc-vrchat-network-address = 網路位址
settings-osc-vrchat-network-address-description = 設定用來發送資料到 VRChat 的位址(請檢查裝置的 Wi-Fi 設定)
settings-osc-vrchat-network-address-description-v1 = 設定收發追蹤器資料的 IP 位址,使用 VRChat 不須更改
settings-osc-vrchat-network-address-placeholder = VRChat IP 位址
settings-osc-vrchat-network-trackers = 追蹤器
settings-osc-vrchat-network-trackers-description = 切換傳送指定追蹤器的資料。
@@ -582,6 +596,9 @@ settings-osc-vmc-vrm-file_select = 拖曳檔案或 <u>瀏覽檔案</u> 以載入
settings-osc-vmc-anchor_hip = 臀部錨定
settings-osc-vmc-anchor_hip-description = 將追蹤錨定在臀部,有利於坐姿進行虛擬直播。若本選項無法切換,請載入 VRM 模型。
settings-osc-vmc-anchor_hip-label = 臀部錨定
settings-osc-vmc-mirror_tracking = 鏡像追蹤
settings-osc-vmc-mirror_tracking-description = 將追蹤的結果水平鏡像。
settings-osc-vmc-mirror_tracking-label = 鏡像追蹤
## Setup/onboarding menu
@@ -660,7 +677,7 @@ onboarding-done-close = 關閉設定
onboarding-connect_tracker-back = 返回到 Wi-Fi 認證資訊設定
onboarding-connect_tracker-title = 連接追蹤器
onboarding-connect_tracker-description-p0-v1 = 來到了我第二喜歡的環節,連接追蹤器!
onboarding-connect_tracker-description-p1-v1 = 透過 USB一次連接一個追蹤器。
onboarding-connect_tracker-description-p1-v1 = 透過 USB,一次連接一個追蹤器。
onboarding-connect_tracker-issue-serial = 我在連接時碰到問題了!
onboarding-connect_tracker-usb = USB 追蹤器
onboarding-connect_tracker-connection_status-none = 正在尋找追蹤器
@@ -716,6 +733,23 @@ onboarding-assign_trackers-assigned = { $assigned }/{ $trackers } 個追蹤器
onboarding-assign_trackers-advanced = 顯示進階分配部位
onboarding-assign_trackers-next = 所有的追蹤器都分配好了
onboarding-assign_trackers-mirror_view = 鏡像顯示
onboarding-assign_trackers-option-amount = { $trackersCount } 點
onboarding-assign_trackers-option-label =
{ $mode ->
[lower-body] 腿部追蹤套裝
[core] 核心套裝
[enhanced-core] 核心套裝加強版
[full-body] 全身追蹤套裝
*[all] 全部部位
}
onboarding-assign_trackers-option-description =
{ $mode ->
[lower-body] VR 全身追蹤的基本需求
[core] + 強化脊椎追蹤
[enhanced-core] + 腳部旋轉
[full-body] + 手肘追蹤
*[all] 顯示全部可供追蹤器分配的部位
}
## Tracker assignment warnings
@@ -792,11 +826,11 @@ onboarding-choose_mounting = 要使用哪一種配戴校正方式?
onboarding-choose_mounting-description = 配戴校正可以校正追蹤器放在身上的位置。
onboarding-choose_mounting-auto_mounting = 自動配戴校正
# Italized text
onboarding-choose_mounting-auto_mounting-label = 實驗功能
onboarding-choose_mounting-auto_mounting-label-v2 = 推薦使用
onboarding-choose_mounting-auto_mounting-description = 本選項會透過兩個身體姿勢,判斷所有追蹤器的配戴方位
onboarding-choose_mounting-manual_mounting = 手動配戴校正
# Italized text
onboarding-choose_mounting-manual_mounting-label = 推薦使用
onboarding-choose_mounting-manual_mounting-label-v2 = 可能不夠精確
onboarding-choose_mounting-manual_mounting-description = 本選項可以讓你選擇每個追蹤器的配戴方位
# Multiline text
onboarding-choose_mounting-manual_modal-title = 確定要進行自動配戴校正?
@@ -888,10 +922,10 @@ onboarding-automatic_proportions-requirements-descriptionv2 =
追蹤狀態正常且能反映你的移動姿態(例如,進行完全重置後,踢腿、彎曲、坐下時的肢體方向是正確的)。
onboarding-automatic_proportions-requirements-next = 我已閱讀使用需求
onboarding-automatic_proportions-check_height-title = 檢查您的身高
onboarding-automatic_proportions-check_height-description = 我們會透過頭戴顯示器回報的高度來推算您的實際身高,但我們仍建議檢查一下數值是否正確。
onboarding-automatic_proportions-check_height-description = 我們會透過頭戴顯示器回報的高度來推算您的實際身高,但仍建議檢查數值是否正確。
# All the text is in bold!
onboarding-automatic_proportions-check_height-calculation_warning = 請<u>站直</u>並按下按鈕以計算身高,按下按鈕後您有 3 秒鐘來調整姿勢。
onboarding-automatic_proportions-check_height-guardian_tip = 如果您使用的是一體式 VR 頭,請確認頭盔的守護神/邊界設定已經開啟,以確保身高能正確測量。
onboarding-automatic_proportions-check_height-guardian_tip = 如果您使用的是一體式 VR 頭,請確認頭盔的守護神/邊界設定已經開啟,以確保身高能正確測量。
onboarding-automatic_proportions-check_height-fetch_height = 我站著了!
# Context is that the height is unknown
onboarding-automatic_proportions-check_height-unknown = 不明
@@ -918,11 +952,11 @@ onboarding-automatic_proportions-recording-processing = 正在處理結果
# $time (Number) - Seconds left for the automatic calibration recording to finish (max 20)
onboarding-automatic_proportions-recording-timer = 倒數 { $time } 秒
onboarding-automatic_proportions-verify_results-title = 檢查結果
onboarding-automatic_proportions-verify_results-description = 檢查下面的結果,它們看起來是正確的嗎?
onboarding-automatic_proportions-verify_results-description = 檢查以下測量結果,看起來是正確的嗎?
onboarding-automatic_proportions-verify_results-results = 錄製結果
onboarding-automatic_proportions-verify_results-processing = 正在處理結果
onboarding-automatic_proportions-verify_results-redo = 重新錄製
onboarding-automatic_proportions-verify_results-confirm = 他們是正確的!
onboarding-automatic_proportions-verify_results-confirm = 看起來沒問題
onboarding-automatic_proportions-done-title = 身體資料已測量並儲存。
onboarding-automatic_proportions-done-description = 你的身體比例校正已完成!
onboarding-automatic_proportions-error_modal =
@@ -948,10 +982,11 @@ trackers_still_on-modal-cancel = 先不要…
status_system-StatusTrackerReset = 有至少一個追蹤器尚未進行調整,建議執行完整重置。
status_system-StatusSteamVRDisconnected =
{ $type ->
[steamvr_feeder] 尚未連接 SlimeVR 資料迴送程式
*[other] 尚未透過 SlimeVR 驅動程式連接到 SteamVR
[steamvr_feeder] 尚未連接 SlimeVR 資料迴送程式
*[other] 尚未透過 SlimeVR 驅動程式連接到 SteamVR
}
status_system-StatusTrackerError = { $trackerName } 追蹤器發生錯誤
status_system-StatusUnassignedHMD = VR 頭戴顯示器應被分配為頭部追蹤器。
## Tray Menu

Binary file not shown.

Before

Width:  |  Height:  |  Size: 108 KiB

After

Width:  |  Height:  |  Size: 480 KiB

19
gui/scripts/gitversion.mjs Executable file
View File

@@ -0,0 +1,19 @@
#!/usr/bin/env node
import { promisify } from 'node:util';
import { exec as execCallback } from 'node:child_process';
const exec = promisify(execCallback);
const [commitHash, versionTag, gitClean] = await Promise.all([
exec('git rev-parse --verify --short HEAD').then((res) => res.stdout.trim()),
exec('git --no-pager tag --sort -taggerdate --points-at HEAD').then((res) =>
res.stdout.split('\n')[0].trim().substring(1)
),
// If not empty then it's not clean
exec('git status --porcelain').then((res) => (res.stdout ? false : true)),
]);
console.log(
JSON.stringify({
version: `${versionTag || `0.0.0-${commitHash}`}${gitClean ? '' : '-dirty'}`,
})
);

40
gui/scripts/license-list.mjs Executable file
View File

@@ -0,0 +1,40 @@
#!/usr/bin/env node
/* eslint-env node */
import { promisify } from 'node:util';
import { exec as execCallback } from 'node:child_process';
import satisfies from 'spdx-satisfies';
const exec = promisify(execCallback);
const ACCEPTED_KEYS = 'MIT OR ISC OR Apache-2.0 OR BSD-3-Clause OR 0BSD OR OFL-1.1';
const licenses = await exec('pnpm licenses ls -P --json').then((res) =>
JSON.parse(res.stdout)
);
if (licenses['Unknown'].find((p) => p.name !== 'flatbuffers')) {
console.error(
'Found more than one library with unknown license: ' +
licenses['Unknown'].map((p) => p.name).join()
);
process.exit(1);
}
if (licenses['BSD'].find((p) => p.name !== 'css-mediaquery')) {
console.error(
'Found more than one library with invalid SPDX BSD license: ' +
licenses['BSD'].map((p) => p.name).join()
);
process.exit(1);
}
for(let [license, pkgs] of Object.entries(licenses)) {
if(license === 'BSD' || license === 'Unknown') continue;
if(license === 'MIT or APACHE-2.0') {
license = 'MIT OR Apache-2.0';
}
if(!satisfies(license, ACCEPTED_KEYS)) {
console.error(`Found more than one library with incompatible license ${license}: ${pkgs.map((p) => p.name).join()}`)
process.exit(1);
}
}
console.log(Object.keys(licenses));

View File

@@ -3,11 +3,11 @@ name = "slimevr"
version = "0.0.0"
description = "SlimeVR GUI Application"
license = "MIT OR Apache-2.0"
repository = "https://github.com/SlimeVR/SlimeVR-Server"
license.workspace = true
repository.workspace = true
edition = "2021"
rust-version = "1.65"
edition.workspace = true
rust-version.workspace = true
default-run = "slimevr"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
@@ -21,20 +21,20 @@ default = ["custom-protocol"]
custom-protocol = ["tauri/custom-protocol"]
[build-dependencies]
tauri-build = { version = "=2.0.0-beta.11", features = [] }
tauri-build = { version = "=2.0.0-beta.18", features = [] }
cfg_aliases = "0.2"
shadow-rs = "0.27"
[dependencies]
serde_json = "1"
serde = { version = "1", features = ["derive"] }
tauri = { version = "=2.0.0-beta.14", features = ["devtools", "tray-icon", "image-png"] }
tauri-runtime = "=2.0.0-beta.11"
tauri-plugin-dialog = "=2.0.0-beta.4"
tauri-plugin-fs = "=2.0.0-beta.4"
tauri-plugin-os = "=2.0.0-beta.3"
tauri-plugin-shell = "=2.0.0-beta.3"
tauri-plugin-store = "=2.0.0-beta.4"
tauri = { version = "=2.0.0-beta.23", features = ["devtools", "tray-icon", "image-png"] }
tauri-runtime = "=2.0.0-beta.19"
tauri-plugin-dialog = "=2.0.0-beta.10"
tauri-plugin-fs = "=2.0.0-beta.10"
tauri-plugin-os = "=2.0.0-beta.7"
tauri-plugin-shell = "=2.0.0-beta.8"
tauri-plugin-store = "=2.0.0-beta.9"
flexi_logger = "0.28"
log-panics = { version = "2", features = ["with-backtrace"] }
log = "0.4"
@@ -51,6 +51,8 @@ cfg-if = "1"
color-eyre = "0.6"
rfd = { version = "0.14", features = ["gtk3"], default-features = false }
dirs-next = "2.0.0"
discord-sdk = "0.3.6"
tokio = { version = "1.37.0", features = ["time"] }
[target.'cfg(windows)'.dependencies]
win32job = "1"

View File

@@ -1,6 +1,11 @@
use cfg_aliases::cfg_aliases;
fn main() -> shadow_rs::SdResult<()> {
// Bypass for Nix script having libudev-zero and Tauri not liking it
if let Some(path) = option_env!("SLIMEVR_RUST_LD_LIBRARY_PATH") {
println!("cargo:rustc-env=LD_LIBRARY_PATH={path}");
}
tauri_build::build();
cfg_aliases! {
mobile: { any(target_os = "ios", target_os = "android") },

View File

@@ -1,13 +1,13 @@
[Desktop Entry]
Version=1.5
Categories=Game;Development;GTK;
Exec=slimevr
Icon=dev.slimevr.SlimeVR
Exec={{exec}}
Icon={{icon}}
Name=SlimeVR
GenericName=Full-body tracking
Comment=An app for facilitating full-body tracking in virtual reality
Keywords=FBT
Keywords=FBT;VR;Steam;VRChat;IMU
Terminal=false
Type=Application

View File

@@ -18,6 +18,7 @@ use crate::util::{
get_launch_path, show_error, valid_java_paths, Cli, JAVA_BIN, MINIMUM_JAVA_VERSION,
};
mod presence;
mod state;
mod tray;
mod util;
@@ -177,7 +178,11 @@ fn main() -> Result<()> {
erroring,
warning,
tray::update_translations,
tray::update_tray_text
tray::update_tray_text,
presence::discord_client_exists,
presence::update_presence,
presence::clear_presence,
presence::create_discord_client,
])
.setup(move |app| {
let window_state =
@@ -196,6 +201,8 @@ fn main() -> Result<()> {
.visible(true)
.decorations(false)
.fullscreen(false)
// This allows drag & drop via HTML5 for Windows
.disable_drag_drop_handler()
.build()?;
if window_state.is_old() {
window_state.update_window(&window.as_ref().window(), false)?;
@@ -204,7 +211,8 @@ fn main() -> Result<()> {
#[cfg(desktop)]
{
let handle = app.handle();
tray::create_tray(&handle)?;
tray::create_tray(handle)?;
presence::create_presence(handle)?;
}
app.manage(Mutex::new(window_state));
@@ -262,15 +270,15 @@ fn main() -> Result<()> {
}
}
// See https://github.com/tauri-apps/tauri/issues/4012#issuecomment-1449499149
#[cfg(windows)]
WindowEvent::Resized(_) => std::thread::sleep(std::time::Duration::from_nanos(1)),
// #[cfg(windows)]
// WindowEvent::Resized(_) => std::thread::sleep(std::time::Duration::from_nanos(1)),
_ => (),
})
.build(tauri_context);
match build_result {
Ok(app) => {
app.run(move |app_handle, event| match event {
RunEvent::ExitRequested { .. } => {
RunEvent::Exit => {
let window_state = app_handle.state::<Mutex<WindowState>>();
let lock = window_state.lock().unwrap();
let config_dir = app_handle.path().app_config_dir().unwrap();

View File

@@ -0,0 +1,212 @@
use std::time::{Duration, SystemTime};
use color_eyre::{eyre::bail, Result};
use discord_sdk as ds;
use ds::wheel::{UserSpoke, UserState};
use tauri::{async_runtime::Mutex, AppHandle, Manager, Runtime, State};
const APP_ID: ds::AppId = 1237970689009647639;
pub struct DiscordClient {
pub discord: ds::Discord,
pub wheel: ds::wheel::Wheel,
}
pub struct DiscordTimestamp(SystemTime);
pub struct ExposedClient(Mutex<Option<DiscordClient>>);
async fn make_client(subs: ds::Subscriptions) -> Result<Option<DiscordClient>> {
let (wheel, handler) = ds::wheel::Wheel::new(Box::new(|err| {
log::error!(target: "discord_presence", "encountered a discord presence error: {err}");
}));
let mut user = wheel.user();
let discord =
ds::Discord::new(ds::DiscordApp::PlainId(APP_ID), subs, Box::new(handler))?;
log::debug!(target: "discord_presence", "waiting for handshake...");
let Ok(e) = tokio::time::timeout(Duration::from_secs(5), user.0.changed()).await
else {
return Ok(None);
};
e?;
let _ = match &*user.0.borrow() {
ds::wheel::UserState::Connected(user) => user.clone(),
ds::wheel::UserState::Disconnected(err) => {
bail!("failed to connect to Discord: {err}");
}
};
log::info!(target: "discord_presence", "connected to Discord!");
Ok(Some(DiscordClient { discord, wheel }))
}
async fn client_exists(client: &State<'_, ExposedClient>) -> bool {
let lock = client.0.lock().await;
lock.is_some()
}
#[tauri::command]
pub async fn discord_client_exists(
client: State<'_, ExposedClient>,
) -> Result<bool, ()> {
Ok(client_exists(&client).await)
}
#[tauri::command]
pub async fn update_presence(
client: State<'_, ExposedClient>,
timestamp: State<'_, DiscordTimestamp>,
details: String,
state: Option<String>,
small_icon: Option<(String, String)>,
button: Option<ds::activity::Button>,
) -> Result<(), ()> {
if !client_exists(&client).await {
return Err(());
}
let rp = ds::activity::ActivityBuilder::default()
.details(details)
.start_timestamp(timestamp.0);
let rp = if let Some(state) = state {
rp.state(state)
} else {
rp
};
let rp = if let Some((id, desc)) = small_icon {
rp.assets(
ds::activity::Assets::default()
.large("icon".to_owned(), Some("SlimeVR".to_owned()))
.small(id, Some(desc)),
)
} else {
rp.assets(
ds::activity::Assets::default()
.large("icon".to_owned(), Some("SlimeVR".to_owned())),
)
};
let rp = if let Some(button) = button {
rp.button(button)
} else {
rp
};
let lock = client.0.lock().await;
lock.as_ref()
.unwrap()
.discord
.update_activity(rp)
.await
.map_err(|_e| ())?;
Ok(())
}
#[tauri::command]
pub async fn clear_presence(client: State<'_, ExposedClient>) -> Result<(), String> {
if !client_exists(&client).await {
return Err("Missing discord client".to_owned());
}
let lock = client.0.lock().await;
lock.as_ref()
.unwrap()
.discord
.clear_activity()
.await
.map_err(|e| e.to_string())?;
Ok(())
}
#[tauri::command]
pub async fn create_discord_client<R: Runtime>(
app: AppHandle<R>,
client: State<'_, ExposedClient>,
) -> Result<(), String> {
if client_exists(&client).await {
return Err("Trying to create a client when there is one already".to_owned());
}
let Some(discord_client) = make_client(ds::Subscriptions::ACTIVITY)
.await
.map_err(|e| e.to_string())?
else {
log::debug!(target: "discord_presence", "discord took too long to answer (probably not open)");
return Ok(());
};
let user_wheel = discord_client.wheel.user();
{
let mut lock = client.0.lock().await;
*lock = Some(discord_client);
}
tauri::async_runtime::spawn(async move {
drop_client_on_loss(app, user_wheel).await;
});
Ok(())
}
async fn drop_client_on_loss<R: Runtime>(
app: tauri::AppHandle<R>,
mut user_wheel: UserSpoke,
) {
while let Ok(_) = user_wheel.0.changed().await {
if let UserState::Disconnected(e) = &*user_wheel.0.borrow() {
match e {
ds::Error::NoConnection
| ds::Error::TimedOut
| ds::Error::Close(_)
| ds::Error::CorruptConnection => break,
_ => {
log::error!(target: "discord_presence", "unhandled discord error: {e}")
}
}
}
}
log::info!(target: "discord_presence", "lost connection to discord, dropping client...");
let mutex = app.state::<ExposedClient>();
let opt = {
let mut lock = mutex.0.lock().await;
lock.take()
};
let Some(client) = opt else {
return;
};
client.discord.disconnect().await;
}
pub fn create_presence<R: Runtime>(app: &tauri::AppHandle<R>) -> tauri::Result<()> {
app.manage(ExposedClient(Mutex::new(None)));
app.manage(DiscordTimestamp(SystemTime::now()));
{
let app = app.clone();
tauri::async_runtime::spawn(async move {
let client = make_client(ds::Subscriptions::ACTIVITY).await;
if let Err(e) = client {
log::error!(target: "discord_presence", "couldn't initialize discord client: {e}");
return;
}
let Some(client) = client.unwrap() else {
log::debug!(target: "discord_presence", "discord took too long to answer (probably not open)");
return;
};
let user_wheel = client.wheel.user();
{
let mutex = app.state::<ExposedClient>();
let mut lock = mutex.0.lock().await;
*lock = Some(client)
}
tauri::async_runtime::spawn(async move {
drop_client_on_loss(app, user_wheel).await;
});
});
}
Ok(())
}

View File

@@ -3,7 +3,7 @@ use std::{collections::HashMap, sync::Mutex};
use tauri::{
image::Image,
menu::{Menu, MenuBuilder, MenuItemBuilder, MenuItemKind},
tray::{ClickType, TrayIconBuilder},
tray::{MouseButton, MouseButtonState, TrayIconBuilder, TrayIconEvent},
AppHandle, Manager, Runtime, State,
};
@@ -100,15 +100,24 @@ pub fn create_tray<R: Runtime>(app: &tauri::AppHandle<R>) -> tauri::Result<()> {
}
_ => {}
})
.on_tray_icon_event(|tray, event| {
if event.click_type == ClickType::Left {
.on_tray_icon_event(|tray, event| match event {
TrayIconEvent::Click {
button,
button_state,
..
} if button == MouseButton::Left
&& button_state == MouseButtonState::Up =>
{
let app = tray.app_handle();
if let Some(window) = app.get_webview_window("main") {
let _ = window.show();
let _ = window.set_focus();
}
}
_ => {}
})
// We don't want this as we open the window on left click
.menu_on_left_click(false)
.build(app)?;
app.manage(TrayMenu(menu1));

View File

@@ -62,7 +62,7 @@ pub fn get_launch_path(cli: Cli) -> Option<PathBuf> {
let paths = [
cli.launch_from_path,
// AppImage passes the fakeroot in `APPDIR` env var.
env::var_os("APPDIR").map(PathBuf::from),
env::var_os("APPDIR").map(|a| PathBuf::from(a).join("usr/share/slimevr/")),
env::current_dir().ok(),
// getcwd in Mac can't be trusted, so let's get the executable's path
env::current_exe()

View File

@@ -14,10 +14,23 @@
],
"files": {
"/usr/share/slimevr/slimevr.jar": "../../server/desktop/build/libs/slimevr.jar"
}
},
"desktopTemplate": "./dev.slimevr.SlimeVR.desktop"
},
"appimage": {
"bundleMediaFramework": true
"bundleMediaFramework": true,
"files": {
"/usr/share/slimevr/slimevr.jar": "../../server/desktop/build/libs/slimevr.jar"
}
},
"rpm": {
"depends": [
"java-17-openjdk"
],
"files": {
"/usr/share/slimevr/slimevr.jar": "../../server/desktop/build/libs/slimevr.jar"
},
"desktopTemplate": "./dev.slimevr.SlimeVR.desktop"
}
},
"category": "DeveloperTool",

View File

@@ -6,11 +6,11 @@ import {
Routes,
} from 'react-router-dom';
import { Home } from './components/home/Home';
import { MainLayoutRoute } from './components/MainLayout';
import { MainLayout } from './components/MainLayout';
import { AppContextProvider } from './components/providers/AppContext';
import { GeneralSettings } from './components/settings/pages/GeneralSettings';
import { Serial } from './components/settings/pages/Serial';
import { SettingsLayoutRoute } from './components/settings/SettingsLayout';
import { SettingsLayout } from './components/settings/SettingsLayout';
import {
useProvideWebsocketApi,
WebSocketApiContext,
@@ -54,6 +54,7 @@ import { error, log } from './utils/logging';
import { AppLayout } from './AppLayout';
import { Preload } from './components/Preload';
import { UnknownDeviceModal } from './components/UnknownDeviceModal';
import { useDiscordPresence } from './hooks/discord-presence';
export const GH_REPO = 'SlimeVR/SlimeVR-Server';
export const VersionContext = createContext('');
@@ -62,6 +63,7 @@ export const SLIMEVR_DISCORD = 'https://discord.gg/slimevr';
function Layout() {
const { isMobile } = useBreakpoint('mobile');
useDiscordPresence();
return (
<>
@@ -73,33 +75,33 @@ function Layout() {
<Route
path="/"
element={
<MainLayoutRoute isMobile={isMobile}>
<MainLayout isMobile={isMobile}>
<Home />
</MainLayoutRoute>
</MainLayout>
}
/>
<Route
path="/vr-mode"
element={
<MainLayoutRoute isMobile={isMobile}>
<MainLayout isMobile={isMobile}>
<VRModePage />
</MainLayoutRoute>
</MainLayout>
}
/>
<Route
path="/tracker/:trackernum/:deviceid"
element={
<MainLayoutRoute background={false} isMobile={isMobile}>
<MainLayout background={false} isMobile={isMobile}>
<TrackerSettingsPage />
</MainLayoutRoute>
</MainLayout>
}
/>
<Route
path="/settings"
element={
<SettingsLayoutRoute>
<SettingsLayout>
<Outlet />
</SettingsLayoutRoute>
</SettingsLayout>
}
>
<Route path="trackers" element={<GeneralSettings />} />
@@ -198,15 +200,10 @@ export default function App() {
if (isTauri) {
useEffect(() => {
os.type()
.then((type) => document.body.classList.add(type.toLowerCase()))
.catch(error);
const type = os.type();
document.body.classList.add(type.toLowerCase());
return () => {
os.type()
.then((type) => document.body.classList.remove(type.toLowerCase()))
.catch(error);
};
return () => document.body.classList.remove(type.toLowerCase());
}, []);
}

View File

@@ -0,0 +1,22 @@
.main-layout {
display: grid;
grid-template:
't t' var(--topbar-h)
's c' calc(100% - var(--topbar-h))
/ var(--navbar-w) calc(100% - var(--navbar-w));
&:has(.widgets) {
grid-template:
't t t' var(--topbar-h)
's c w' calc(100% - var(--topbar-h))
/ var(--navbar-w) calc(100% - var(--navbar-w) - var(--widget-w)) var(--widget-w);
}
@screen mobile {
grid-template:
't' var(--topbar-h)
'c' calc(100% - var(--topbar-h) - var(--navbar-h))
's' calc(var(--navbar-h))
/ 100%;
}
}

View File

@@ -6,13 +6,13 @@ import {
RpcMessage,
SettingsRequestT,
} from 'solarxr-protocol';
import { useElemSize, useLayout } from '@/hooks/layout';
import { Navbar } from './Navbar';
import { TopBar } from './TopBar';
import { useWebsocketAPI } from '@/hooks/websocket-api';
import { WidgetsComponent } from './WidgetsComponent';
import './MainLayout.scss';
export function MainLayoutRoute({
export function MainLayout({
children,
background = true,
widgets = true,
@@ -23,9 +23,6 @@ export function MainLayoutRoute({
isMobile?: boolean;
widgets?: boolean;
}) {
const { height, ref: navRef } = useElemSize<HTMLDivElement>();
const { layoutHeight, ref } = useLayout<HTMLDivElement>();
const { layoutWidth, ref: refw } = useLayout<HTMLDivElement>();
const { sendRPCPacket } = useWebsocketAPI();
const [ProportionsLastPageOpen, setProportionsLastPageOpen] = useState(true);
@@ -61,37 +58,33 @@ export function MainLayoutRoute({
});
return (
<>
<TopBar></TopBar>
<div
ref={ref}
className="flex-grow"
style={{ height: layoutHeight - height }}
>
<div className="flex h-full xs:pb-3">
{!isMobile && <Navbar></Navbar>}
<div
className="flex gap-2 xs:pr-3 w-full"
ref={refw}
style={{ minWidth: layoutWidth }}
>
<div
className={classNames(
'flex flex-col rounded-xl w-full overflow-clip mobile:overflow-y-auto',
background && 'bg-background-70'
)}
>
{children}
</div>
{!isMobile && widgets && (
<div className="flex flex-col px-2 min-w-[274px] w-[274px] gap-2 pt-2 rounded-xl overflow-y-auto bg-background-70">
<WidgetsComponent></WidgetsComponent>
</div>
)}
</div>
<div className="">
<div className="main-layout w-full h-screen">
<div style={{ gridArea: 't' }}>
<TopBar></TopBar>
</div>
<div ref={navRef}>{isMobile && <Navbar></Navbar>}</div>
<div style={{ gridArea: 's' }} className="overflow-y-auto">
<Navbar></Navbar>
</div>
<div
style={{ gridArea: 'c' }}
className={classNames(
'overflow-y-auto mr-2 my-2 mobile:m-0',
'flex flex-col rounded-xl',
background && 'bg-background-70'
)}
>
{children}
</div>
{!isMobile && widgets && (
<div
style={{ gridArea: 'w' }}
className="overflow-y-auto mr-2 my-2 rounded-xl bg-background-70 flex flex-col gap-2 p-2 widgets"
>
<WidgetsComponent></WidgetsComponent>
</div>
)}
</div>
</>
</div>
);
}

View File

@@ -110,7 +110,7 @@ export function Navbar() {
<MainLinks></MainLinks>
</div>
) : (
<div className="flex flex-col px-2 pt-2">
<div className="flex flex-col h-full p-2 gap-2">
<div className="flex flex-col flex-grow gap-2">
<MainLinks></MainLinks>
</div>

View File

@@ -160,7 +160,7 @@ export function TopBar({
<div
className="cursor-pointer"
onClick={() => {
const url = document.body.classList.contains('windows_nt')
const url = document.body.classList.contains('windows')
? 'https://slimevr.dev/download'
: `https://github.com/${GH_REPO}/releases/latest`;
open(url).catch(() => window.open(url, '_blank'));

View File

@@ -24,7 +24,7 @@ export function TrackersStillOnModal({
const { l10n } = useLocalization();
return (
<BaseModal isOpen={isOpen} onRequestClose={cancel}>
<BaseModal isOpen={isOpen} onRequestClose={cancel} important>
<div className="flex flex-col gap-3">
<>
<div className="flex flex-col items-center gap-3 fill-accent-background-20">

View File

@@ -36,7 +36,7 @@ export function TrayOrExitModal({
});
return (
<BaseModal isOpen={isOpen} onRequestClose={cancel}>
<BaseModal isOpen={isOpen} onRequestClose={cancel} important>
<form
className="flex flex-col gap-3 w-[27rem]"
onSubmit={handleSubmit((form) => accept(form.exitType === '1'))}

View File

@@ -51,7 +51,7 @@ export function VersionUpdateModal() {
<Button
variant="primary"
onClick={async () => {
const url = document.body.classList.contains('windows_nt')
const url = document.body.classList.contains('windows')
? 'https://slimevr.dev/download'
: `https://github.com/${GH_REPO}/releases/latest`;
await open(url).catch(() => window.open(url, '_blank'));

View File

@@ -4,10 +4,12 @@ import ReactModal from 'react-modal';
export function BaseModal({
children,
important = false,
...props
}: {
isOpen: boolean;
children: ReactNode;
important?: boolean;
} & ReactModal.Props) {
return (
<ReactModal
@@ -18,7 +20,8 @@ export function BaseModal({
props.overlayClassName ||
classNames(
'fixed top-0 right-0 left-0 bottom-0 flex flex-col justify-center',
'items-center w-full h-full bg-background-90 bg-opacity-60 z-20'
'items-center w-full h-full bg-background-90 bg-opacity-60',
important ? 'z-50' : 'z-40'
)
}
className={

View File

@@ -173,8 +173,7 @@ export function BodyInteractions({
({ top, left, height, width, id, hidden, buttonOffset }) => (
<div
key={id}
hidden={hidden}
className="absolute z-10"
className={classNames('absolute z-10', hidden && 'hidden')}
onClick={() => onSelectRole((BodyPart as any)[id])}
style={{
top: top + height / 2 - dotsSize / 2 + buttonOffset.top,

View File

@@ -84,7 +84,7 @@ export function Button({
};
return classNames(
variantsMap[variant],
'focus:ring-4 text-center relative',
'focus:ring-4 text-center relative flex items-center justify-center',
{
'rounded-full p-2 text-center min-h-[35px] min-w-[35px]': rounded,
'rounded-md px-5 py-2.5': !rounded,

View File

@@ -1,9 +1,8 @@
import classNames from 'classnames';
import { useEffect, useRef, useState } from 'react';
import { ReactNode, useEffect, useLayoutEffect, useRef, useState } from 'react';
import { Control, Controller, UseControllerProps } from 'react-hook-form';
import { a11yClick } from '@/utils/a11y';
import { createPortal } from 'react-dom';
import { useElemSize } from '@/hooks/layout';
import { ArrowDownIcon } from './icon/ArrowIcons';
interface DropdownProps {
@@ -30,7 +29,8 @@ type DropdownItemsProps = Pick<
};
export interface DropdownItem {
label: string;
label?: string;
component?: ReactNode;
value: string;
fontName?: string;
}
@@ -49,7 +49,17 @@ export function DropdownItems({
onSelectItem,
onBackdropClick,
}: DropdownItemsProps) {
const { height, width, ref } = useElemSize<HTMLDivElement>();
const ref = useRef<HTMLDivElement | null>(null);
const [itemBounds, setItemBounds] = useState<DOMRect>();
const updateBounds = () => {
if (!ref.current) return;
setItemBounds(ref.current?.getBoundingClientRect());
};
useLayoutEffect(() => {
updateBounds();
}, []);
const GAP = 8;
@@ -67,18 +77,20 @@ export function DropdownItems({
variant == 'primary' && 'bg-background-60',
variant == 'secondary' && 'bg-background-70',
variant == 'tertiary' && 'bg-accent-background-30',
height == 0 && 'opacity-0' // Avoid flicker while the component find its position
itemBounds?.height == 0 && 'opacity-0' // Avoid flicker while the component find its position
)}
style={{
maxHeight: maxHeight,
left:
alignment === 'left'
? dropdownBounds.left
: dropdownBounds.left + dropdownBounds.width - width,
: dropdownBounds.left +
dropdownBounds.width -
(itemBounds?.width ?? 0),
top:
direction == 'down'
? dropdownBounds.bottom + GAP
: dropdownBounds.top - height - GAP,
: dropdownBounds.top - (itemBounds?.height ?? 0) - GAP,
minWidth: display === 'block' ? dropdownBounds.width : 'inherit',
}}
>
@@ -87,7 +99,7 @@ export function DropdownItems({
<li
style={item.fontName ? { fontFamily: item.fontName } : {}}
className={classNames(
'py-2 px-4 min-w-max cursor-pointer',
'py-2 px-4 min-w-max cursor-pointer first-of-type:*:pointer-events-none',
variant == 'primary' &&
'checked-hover:bg-background-50 text-background-20 ' +
'checked-hover:text-background-10',
@@ -108,7 +120,7 @@ export function DropdownItems({
tabIndex={0}
data-checked={item.value === value}
>
{item.label}
{item.component || item.label}
</li>
))}
</ul>
@@ -184,12 +196,14 @@ export function Dropdown({
onKeyDown={(ev) => a11yClick(ev) && setOpen((open) => !open)}
tabIndex={0}
>
<div className="flex-grow text-standard">
{items.find((i) => i.value == value)?.label || placeholder}
<div className="flex-grow text-standard first:pointer-events-none">
{items.find((i) => i.value == value)?.component ||
items.find((i) => i.value == value)?.label ||
placeholder}
</div>
<div
className={classNames(
'ml-2 fill-background-10',
'ml-2 fill-background-10 flex items-center',
direction == 'up' && 'rotate-180',
direction == 'down' && 'rotate-0'
)}

View File

@@ -57,7 +57,7 @@ export const FileInputInside = forwardRef<
className={classNames(
'flex justify-center w-full h-32 px-4 transition border-2',
'border-background-20 border-dashed rounded-md appearance-none cursor-pointer',
'hover:border-background-40 focus:outline-none'
'hover:border-accent-background-20 focus:outline-none'
)}
onClick={() => typeof ref !== 'function' && ref?.current?.click()}
onDragOver={(ev) => ev.preventDefault()}

View File

@@ -1,6 +1,7 @@
import classNames from 'classnames';
import { Control, Controller } from 'react-hook-form';
import { Typography } from './Typography';
import { ReactNode } from 'react';
export function Radio({
control,
@@ -8,15 +9,17 @@ export function Radio({
label,
value,
description,
children,
// input props
disabled,
...props
}: {
control: Control<any>;
name: string;
label: string;
label?: string;
value: string;
description?: string | null;
children?: ReactNode;
} & React.HTMLProps<HTMLInputElement>) {
return (
<Controller
@@ -27,7 +30,7 @@ export function Radio({
className={classNames('w-full p-3 rounded-md flex gap-3 border-2', {
'border-accent-background-30': value == checked,
'border-transparent': value != checked,
'bg-background-60 cursor-pointer': !disabled,
'bg-background-60 cursor-pointer hover:bg-background-50': !disabled,
'bg-background-80 cursor-not-allowed': disabled,
})}
>
@@ -45,8 +48,8 @@ export function Radio({
checked={value == checked}
{...props}
/>
<div className="flex flex-col gap-2">
<Typography bold>{label}</Typography>
<div className="flex flex-col gap-2 pointer-events-none">
{children ? children : <Typography bold>{label}</Typography>}
{description && (
<Typography variant="standard" color="secondary">
{description}

View File

@@ -1,3 +1,4 @@
import { useConfig } from '@/hooks/config';
import classNames from 'classnames';
import { createElement, ReactNode, useMemo } from 'react';
@@ -8,6 +9,7 @@ export function Typography({
whitespace = 'whitespace-normal',
children,
italic = false,
truncate = false,
textAlign,
}: {
variant?:
@@ -18,6 +20,7 @@ export function Typography({
| 'mobile-title';
bold?: boolean;
italic?: boolean;
truncate?: boolean;
block?: boolean;
color?: 'primary' | 'secondary' | string;
whitespace?:
@@ -45,6 +48,7 @@ export function Typography({
};
return tags[variant];
}, [variant]);
const { config } = useConfig();
return createElement(
tag,
@@ -65,6 +69,9 @@ export function Typography({
whitespace,
textAlign,
italic && 'italic',
truncate && 'leading-3 text-ellipsis',
truncate && (config?.textSize ?? 12) > 12 && 'line-clamp-1',
truncate && (config?.textSize ?? 12) <= 12 && 'line-clamp-2',
]),
},
children || []

View File

@@ -51,7 +51,7 @@ export function Home() {
<div className="h-full overflow-y-auto">
<div
className={classNames(
'px-2 pt-4 gap-3 w-full grid md:grid-cols-2 mobile:grid-cols-1',
'px-2 pt-2 gap-3 w-full grid md:grid-cols-2 mobile:grid-cols-1',
filteredStatuses.filter(([, status]) => status.prioritized)
.length === 0 && 'hidden'
)}

View File

@@ -1,19 +1,29 @@
import { useMemo } from 'react';
import { useCallback, useMemo } from 'react';
import { BodyPart } from 'solarxr-protocol';
import { FlatDeviceTracker } from '@/hooks/app';
import { AssignMode } from '@/hooks/config';
import { useTrackers } from '@/hooks/tracker';
import { BodyInteractions } from '@/components/commons/BodyInteractions';
import { TrackerPartCard } from '@/components/tracker/TrackerPartCard';
import { BodyPartError } from './pages/trackers-assign/TrackerAssignment';
import { SIDES } from '@/components/commons/PersonFrontIcon';
export const ARMS_PARTS = new Set([
BodyPart.LEFT_UPPER_ARM,
BodyPart.RIGHT_UPPER_ARM,
BodyPart.LEFT_LOWER_ARM,
BodyPart.RIGHT_LOWER_ARM,
]);
export const LEGS_PARTS = new Set([
BodyPart.LEFT_UPPER_LEG,
BodyPart.RIGHT_UPPER_LEG,
BodyPart.LEFT_LOWER_LEG,
BodyPart.RIGHT_LOWER_LEG,
]);
export const LOWER_BODY = new Set([
BodyPart.LEFT_FOOT,
BodyPart.RIGHT_FOOT,
BodyPart.LEFT_LOWER_LEG,
BodyPart.RIGHT_LOWER_LEG,
BodyPart.LEFT_UPPER_LEG,
BodyPart.RIGHT_UPPER_LEG,
...LEGS_PARTS,
]);
export const SPINE_PARTS = [
BodyPart.UPPER_CHEST,
@@ -44,22 +54,63 @@ export const ASSIGNMENT_RULES: Partial<
// Also don't warn if no legs.
};
export const ASSIGNMENT_MODES: Record<AssignMode, BodyPart[]> = {
// x5
[AssignMode.LowerBody]: [BodyPart.CHEST, ...LEGS_PARTS],
// x6 (5 + 1)
[AssignMode.Core]: [BodyPart.CHEST, BodyPart.HIP, ...LEGS_PARTS],
// x8 (5 + 3)
[AssignMode.EnhancedCore]: [
BodyPart.CHEST,
BodyPart.HIP,
...LEGS_PARTS,
BodyPart.LEFT_FOOT,
BodyPart.RIGHT_FOOT,
],
// x10 (7 + 3)
[AssignMode.FullBody]: [
BodyPart.CHEST,
BodyPart.HIP,
BodyPart.LEFT_UPPER_ARM,
BodyPart.RIGHT_UPPER_ARM,
...LEGS_PARTS,
BodyPart.LEFT_FOOT,
BodyPart.RIGHT_FOOT,
],
// special case with all body parts
[AssignMode.All]: [
BodyPart.HEAD,
BodyPart.NECK,
BodyPart.LEFT_SHOULDER,
BodyPart.RIGHT_SHOULDER,
BodyPart.LEFT_HAND,
BodyPart.RIGHT_HAND,
BodyPart.LEFT_FOOT,
BodyPart.RIGHT_FOOT,
...SPINE_PARTS,
...ARMS_PARTS,
...LEGS_PARTS,
],
};
export function BodyAssignment({
advanced,
assignMode,
mirror,
onRoleSelected,
rolesWithErrors = {},
highlightedRoles = [],
onlyAssigned = false,
width,
dotSize,
}: {
advanced: boolean;
assignMode: AssignMode;
mirror: boolean;
onlyAssigned?: boolean;
rolesWithErrors?: Partial<Record<BodyPart, BodyPartError>>;
highlightedRoles?: BodyPart[];
onRoleSelected: (role: BodyPart) => void;
width?: number;
dotSize?: number;
}) {
const { useAssignedTrackers } = useTrackers();
@@ -94,18 +145,26 @@ export function BodyAssignment({
const left = +!mirror;
const right = +mirror;
const hasBodyPart = useCallback(
(part: BodyPart) =>
assignMode === AssignMode.All ||
ASSIGNMENT_MODES[assignMode].indexOf(part) > -1,
[assignMode]
);
return (
<>
<BodyInteractions
width={width}
mirror={mirror}
dotsSize={dotSize}
assignedRoles={assignedRoles}
highlightedRoles={highlightedRoles}
onSelectRole={onRoleSelected}
leftControls={
<div className="flex flex-col justify-between h-full text-right">
<div className="flex flex-col gap-2">
{advanced && (
{hasBodyPart(BodyPart.HEAD) && (
<TrackerPartCard
onlyAssigned={onlyAssigned}
roleError={rolesWithErrors[BodyPart.HEAD]?.label}
@@ -115,7 +174,8 @@ export function BodyAssignment({
direction="right"
/>
)}
{advanced && (
{hasBodyPart(BodyPart.NECK) && (
<TrackerPartCard
onlyAssigned={onlyAssigned}
roleError={rolesWithErrors[BodyPart.NECK]?.label}
@@ -126,9 +186,8 @@ export function BodyAssignment({
/>
)}
</div>
<div className="flex flex-col gap-2">
{advanced && (
{hasBodyPart(SIDES[left].shoulder) && (
<TrackerPartCard
onlyAssigned={onlyAssigned}
roleError={rolesWithErrors[SIDES[left].shoulder]?.label}
@@ -138,26 +197,31 @@ export function BodyAssignment({
direction="right"
/>
)}
<TrackerPartCard
onlyAssigned={onlyAssigned}
roleError={rolesWithErrors[SIDES[left].upperArm]?.label}
td={trackerPartGrouped[SIDES[left].upperArm]}
role={SIDES[left].upperArm}
onClick={() => onRoleSelected(SIDES[left].upperArm)}
direction="right"
/>
{hasBodyPart(SIDES[left].upperArm) && (
<TrackerPartCard
onlyAssigned={onlyAssigned}
roleError={rolesWithErrors[SIDES[left].upperArm]?.label}
td={trackerPartGrouped[SIDES[left].upperArm]}
role={SIDES[left].upperArm}
onClick={() => onRoleSelected(SIDES[left].upperArm)}
direction="right"
/>
)}
</div>
<div className="flex flex-col gap-2">
<TrackerPartCard
onlyAssigned={onlyAssigned}
roleError={rolesWithErrors[SIDES[left].lowerArm]?.label}
td={trackerPartGrouped[SIDES[left].lowerArm]}
role={SIDES[left].lowerArm}
onClick={() => onRoleSelected(SIDES[left].lowerArm)}
direction="right"
/>
{hasBodyPart(SIDES[left].lowerArm) && (
<TrackerPartCard
onlyAssigned={onlyAssigned}
roleError={rolesWithErrors[SIDES[left].lowerArm]?.label}
td={trackerPartGrouped[SIDES[left].lowerArm]}
role={SIDES[left].lowerArm}
onClick={() => onRoleSelected(SIDES[left].lowerArm)}
direction="right"
/>
)}
{advanced && (
{hasBodyPart(SIDES[left].hand) && (
<TrackerPartCard
onlyAssigned={onlyAssigned}
roleError={rolesWithErrors[SIDES[left].hand]?.label}
@@ -169,37 +233,44 @@ export function BodyAssignment({
)}
</div>
<div className="flex flex-col gap-2">
<TrackerPartCard
onlyAssigned={onlyAssigned}
roleError={rolesWithErrors[SIDES[left].upperLeg]?.label}
td={trackerPartGrouped[SIDES[left].upperLeg]}
role={SIDES[left].upperLeg}
onClick={() => onRoleSelected(SIDES[left].upperLeg)}
direction="right"
/>
{hasBodyPart(SIDES[left].upperLeg) && (
<TrackerPartCard
onlyAssigned={onlyAssigned}
roleError={rolesWithErrors[SIDES[left].upperLeg]?.label}
td={trackerPartGrouped[SIDES[left].upperLeg]}
role={SIDES[left].upperLeg}
onClick={() => onRoleSelected(SIDES[left].upperLeg)}
direction="right"
/>
)}
<TrackerPartCard
onlyAssigned={onlyAssigned}
roleError={rolesWithErrors[SIDES[left].lowerLeg]?.label}
td={trackerPartGrouped[SIDES[left].lowerLeg]}
role={SIDES[left].lowerLeg}
onClick={() => onRoleSelected(SIDES[left].lowerLeg)}
direction="right"
/>
<TrackerPartCard
onlyAssigned={onlyAssigned}
roleError={rolesWithErrors[SIDES[left].foot]?.label}
td={trackerPartGrouped[SIDES[left].foot]}
role={SIDES[left].foot}
onClick={() => onRoleSelected(SIDES[left].foot)}
direction="right"
/>
{hasBodyPart(SIDES[left].lowerLeg) && (
<TrackerPartCard
onlyAssigned={onlyAssigned}
roleError={rolesWithErrors[SIDES[left].lowerLeg]?.label}
td={trackerPartGrouped[SIDES[left].lowerLeg]}
role={SIDES[left].lowerLeg}
onClick={() => onRoleSelected(SIDES[left].lowerLeg)}
direction="right"
/>
)}
{hasBodyPart(SIDES[left].foot) && (
<TrackerPartCard
onlyAssigned={onlyAssigned}
roleError={rolesWithErrors[SIDES[left].foot]?.label}
td={trackerPartGrouped[SIDES[left].foot]}
role={SIDES[left].foot}
onClick={() => onRoleSelected(SIDES[left].foot)}
direction="right"
/>
)}
</div>
</div>
}
rightControls={
<div className="flex flex-col justify-between h-full">
{advanced && (
{hasBodyPart(BodyPart.UPPER_CHEST) && (
<TrackerPartCard
onlyAssigned={onlyAssigned}
roleError={rolesWithErrors[BodyPart.UPPER_CHEST]?.label}
@@ -210,17 +281,19 @@ export function BodyAssignment({
/>
)}
<TrackerPartCard
onlyAssigned={onlyAssigned}
roleError={rolesWithErrors[BodyPart.CHEST]?.label}
td={trackerPartGrouped[BodyPart.CHEST]}
role={BodyPart.CHEST}
onClick={() => onRoleSelected(BodyPart.CHEST)}
direction="left"
/>
{hasBodyPart(BodyPart.CHEST) && (
<TrackerPartCard
onlyAssigned={onlyAssigned}
roleError={rolesWithErrors[BodyPart.CHEST]?.label}
td={trackerPartGrouped[BodyPart.CHEST]}
role={BodyPart.CHEST}
onClick={() => onRoleSelected(BodyPart.CHEST)}
direction="left"
/>
)}
<div className="flex flex-col gap-2">
{advanced && (
{hasBodyPart(SIDES[right].shoulder) && (
<TrackerPartCard
onlyAssigned={onlyAssigned}
roleError={rolesWithErrors[SIDES[right].shoulder]?.label}
@@ -231,45 +304,53 @@ export function BodyAssignment({
/>
)}
<TrackerPartCard
onlyAssigned={onlyAssigned}
roleError={rolesWithErrors[SIDES[right].upperArm]?.label}
td={trackerPartGrouped[SIDES[right].upperArm]}
role={SIDES[right].upperArm}
onClick={() => onRoleSelected(SIDES[right].upperArm)}
direction="left"
/>
{hasBodyPart(SIDES[right].upperArm) && (
<TrackerPartCard
onlyAssigned={onlyAssigned}
roleError={rolesWithErrors[SIDES[right].upperArm]?.label}
td={trackerPartGrouped[SIDES[right].upperArm]}
role={SIDES[right].upperArm}
onClick={() => onRoleSelected(SIDES[right].upperArm)}
direction="left"
/>
)}
</div>
<div className="flex flex-col gap-2">
<TrackerPartCard
onlyAssigned={onlyAssigned}
roleError={rolesWithErrors[BodyPart.WAIST]?.label}
td={trackerPartGrouped[BodyPart.WAIST]}
onClick={() => onRoleSelected(BodyPart.WAIST)}
role={BodyPart.WAIST}
direction="left"
/>
<TrackerPartCard
onlyAssigned={onlyAssigned}
roleError={rolesWithErrors[BodyPart.HIP]?.label}
td={trackerPartGrouped[BodyPart.HIP]}
onClick={() => onRoleSelected(BodyPart.HIP)}
role={BodyPart.HIP}
direction="left"
/>
{hasBodyPart(BodyPart.WAIST) && (
<TrackerPartCard
onlyAssigned={onlyAssigned}
roleError={rolesWithErrors[BodyPart.WAIST]?.label}
td={trackerPartGrouped[BodyPart.WAIST]}
onClick={() => onRoleSelected(BodyPart.WAIST)}
role={BodyPart.WAIST}
direction="left"
/>
)}
{hasBodyPart(BodyPart.HIP) && (
<TrackerPartCard
onlyAssigned={onlyAssigned}
roleError={rolesWithErrors[BodyPart.HIP]?.label}
td={trackerPartGrouped[BodyPart.HIP]}
onClick={() => onRoleSelected(BodyPart.HIP)}
role={BodyPart.HIP}
direction="left"
/>
)}
</div>
<div className="flex flex-col gap-2">
<TrackerPartCard
onlyAssigned={onlyAssigned}
roleError={rolesWithErrors[SIDES[right].lowerArm]?.label}
td={trackerPartGrouped[SIDES[right].lowerArm]}
role={SIDES[right].lowerArm}
onClick={() => onRoleSelected(SIDES[right].lowerArm)}
direction="left"
/>
{advanced && (
{hasBodyPart(SIDES[right].lowerArm) && (
<TrackerPartCard
onlyAssigned={onlyAssigned}
roleError={rolesWithErrors[SIDES[right].lowerArm]?.label}
td={trackerPartGrouped[SIDES[right].lowerArm]}
role={SIDES[right].lowerArm}
onClick={() => onRoleSelected(SIDES[right].lowerArm)}
direction="left"
/>
)}
{hasBodyPart(SIDES[right].hand) && (
<TrackerPartCard
onlyAssigned={onlyAssigned}
roleError={rolesWithErrors[SIDES[right].hand]?.label}
@@ -280,33 +361,39 @@ export function BodyAssignment({
/>
)}
</div>
<div className="flex flex-col gap-2">
<TrackerPartCard
onlyAssigned={onlyAssigned}
roleError={rolesWithErrors[SIDES[right].upperLeg]?.label}
td={trackerPartGrouped[SIDES[right].upperLeg]}
role={SIDES[right].upperLeg}
onClick={() => onRoleSelected(SIDES[right].upperLeg)}
direction="left"
/>
{hasBodyPart(SIDES[right].upperLeg) && (
<TrackerPartCard
onlyAssigned={onlyAssigned}
roleError={rolesWithErrors[SIDES[right].upperLeg]?.label}
td={trackerPartGrouped[SIDES[right].upperLeg]}
role={SIDES[right].upperLeg}
onClick={() => onRoleSelected(SIDES[right].upperLeg)}
direction="left"
/>
)}
<TrackerPartCard
onlyAssigned={onlyAssigned}
roleError={rolesWithErrors[SIDES[right].lowerLeg]?.label}
td={trackerPartGrouped[SIDES[right].lowerLeg]}
role={SIDES[right].lowerLeg}
onClick={() => onRoleSelected(SIDES[right].lowerLeg)}
direction="left"
/>
<TrackerPartCard
onlyAssigned={onlyAssigned}
roleError={rolesWithErrors[SIDES[right].foot]?.label}
td={trackerPartGrouped[SIDES[right].foot]}
role={SIDES[right].foot}
onClick={() => onRoleSelected(SIDES[right].foot)}
direction="left"
/>
{hasBodyPart(SIDES[right].lowerLeg) && (
<TrackerPartCard
onlyAssigned={onlyAssigned}
roleError={rolesWithErrors[SIDES[right].lowerLeg]?.label}
td={trackerPartGrouped[SIDES[right].lowerLeg]}
role={SIDES[right].lowerLeg}
onClick={() => onRoleSelected(SIDES[right].lowerLeg)}
direction="left"
/>
)}
{hasBodyPart(SIDES[right].foot) && (
<TrackerPartCard
onlyAssigned={onlyAssigned}
roleError={rolesWithErrors[SIDES[right].foot]?.label}
td={trackerPartGrouped[SIDES[right].foot]}
role={SIDES[right].foot}
onClick={() => onRoleSelected(SIDES[right].foot)}
direction="left"
/>
)}
</div>
</div>
}

View File

@@ -0,0 +1,11 @@
.onboarding-layout {
display: grid;
grid-template:
't' var(--topbar-h)
'c' calc(100% - var(--topbar-h))
/ 100%;
@screen mobile {
--topbar-h: 74px;
}
}

View File

@@ -1,26 +1,23 @@
import { ReactNode, useState } from 'react';
import { useLayout } from '@/hooks/layout';
import { useOnboarding } from '@/hooks/onboarding';
import { MainLayoutRoute } from '@/components/MainLayout';
import { MainLayout } from '@/components/MainLayout';
import { TopBar } from '@/components/TopBar';
import { useBreakpoint } from '@/hooks/breakpoint';
import { SkipSetupButton } from './SkipSetupButton';
import { SkipSetupWarningModal } from './SkipSetupWarningModal';
import './OnboardingLayout.scss';
export function OnboardingLayout({ children }: { children: ReactNode }) {
const { layoutHeight, ref } = useLayout<HTMLDivElement>();
const { isMobile } = useBreakpoint('mobile');
const { state, skipSetup } = useOnboarding();
const [skipWarning, setSkipWarning] = useState(false);
return !state.alonePage ? (
<>
<TopBar progress={state.progress}></TopBar>
<div
ref={ref}
className="flex-grow relative"
style={{ height: layoutHeight }}
>
<div className="onboarding-layout h-full">
<div style={{ gridArea: 't' }}>
<TopBar progress={state.progress}></TopBar>
</div>
<div style={{ gridArea: 'c' }} className="mt-2 relative">
<div className="absolute top-12 mobile:top-0 right-2 z-50">
<SkipSetupButton
visible={true}
@@ -28,17 +25,17 @@ export function OnboardingLayout({ children }: { children: ReactNode }) {
onClick={() => setSkipWarning(true)}
></SkipSetupButton>
</div>
{children}
<div className="h-full w-full overflow-y-auto">{children}</div>
<SkipSetupWarningModal
accept={skipSetup}
onClose={() => setSkipWarning(false)}
isOpen={skipWarning}
></SkipSetupWarningModal>
</div>
</>
</div>
) : (
<MainLayoutRoute widgets={false} isMobile={isMobile}>
<div className="flex-grow xs:pt-10 mobile:pt-2">{children}</div>
</MainLayoutRoute>
<MainLayout widgets={false} isMobile={isMobile}>
{children}
</MainLayout>
);
}

View File

@@ -2,12 +2,16 @@ import { Localized, useLocalization } from '@fluent/react';
import { useOnboarding } from '@/hooks/onboarding';
import { Button } from '@/components/commons/Button';
import { Typography } from '@/components/commons/Typography';
import { useMemo, useState } from 'react';
import { useEffect, useMemo, useRef, useState } from 'react';
import { ProgressBar } from '@/components/commons/ProgressBar';
import { LoaderIcon, SlimeState } from '@/components/commons/icon/LoaderIcon';
import { useCountdown } from '@/hooks/countdown';
import classNames from 'classnames';
import { TaybolIcon } from '@/components/commons/icon/TaybolIcon';
import { useTrackers } from '@/hooks/tracker';
import { useRestCalibrationTrackers } from '@/hooks/imu-logic';
import { averageVector, Vector3FromVec3fT } from '@/maths/vector3';
import { Vector3 } from 'three';
export enum CalibrationStatus {
SUCCESS,
@@ -17,6 +21,7 @@ export enum CalibrationStatus {
}
export const IMU_CALIBRATION_TIME = 4;
const ACCEL_TOLERANCE = 0.2; // m/s^2
export function CalibrationTutorialPage() {
const { l10n } = useLocalization();
@@ -24,10 +29,50 @@ export function CalibrationTutorialPage() {
const [calibrationStatus, setCalibrationStatus] = useState(
CalibrationStatus.WAITING
);
const { timer, isCounting, startCountdown } = useCountdown({
const { timer, isCounting, startCountdown, abortCountdown } = useCountdown({
duration: IMU_CALIBRATION_TIME,
onCountdownEnd: () => setCalibrationStatus(CalibrationStatus.SUCCESS),
});
const { useConnectedIMUTrackers } = useTrackers();
const connectedIMUTrackers = useConnectedIMUTrackers();
const restCalibrationTrackers =
useRestCalibrationTrackers(connectedIMUTrackers);
const [rested, setRested] = useState(false);
const lastValueMap = useRef(new Map<number, Vector3[]>());
useEffect(() => {
const accelLength = restCalibrationTrackers.every((x) => {
if (
x.tracker.trackerId?.trackerNum === undefined ||
x.tracker.trackerId.deviceId?.id === undefined ||
!x.tracker.linearAcceleration
)
return false;
const trackerId =
x.tracker.trackerId.trackerNum + (x.tracker.trackerId.trackerNum << 8);
const lastValues = lastValueMap.current.get(trackerId) ?? [];
lastValueMap.current.set(trackerId, lastValues);
const vec3 = Vector3FromVec3fT(x.tracker.linearAcceleration);
if (lastValues.length > 5) {
lastValues.shift();
const avg = averageVector(lastValues).lengthSq();
lastValues.push(vec3);
return vec3.lengthSq() <= avg + ACCEL_TOLERANCE ** 2;
}
lastValues.push(vec3);
return false;
});
setRested(accelLength || restCalibrationTrackers.length === 0);
}, [restCalibrationTrackers]);
useEffect(() => {
if (calibrationStatus === CalibrationStatus.CALIBRATING && !rested) {
setCalibrationStatus(CalibrationStatus.ERROR);
abortCountdown();
}
}, [calibrationStatus, rested]);
const progressBarClass = useMemo(() => {
switch (calibrationStatus) {
@@ -101,7 +146,8 @@ export function CalibrationTutorialPage() {
progress={
isCounting
? (IMU_CALIBRATION_TIME - timer) / IMU_CALIBRATION_TIME
: calibrationStatus === CalibrationStatus.SUCCESS
: calibrationStatus === CalibrationStatus.SUCCESS ||
calibrationStatus === CalibrationStatus.ERROR
? 1
: 0
}
@@ -127,9 +173,11 @@ export function CalibrationTutorialPage() {
setCalibrationStatus(CalibrationStatus.CALIBRATING);
startCountdown();
}}
disabled={isCounting}
hidden={CalibrationStatus.SUCCESS === calibrationStatus}
className="xs:ml-auto"
disabled={isCounting || !rested}
className={classNames(
'xs:ml-auto',
CalibrationStatus.SUCCESS === calibrationStatus && 'hidden'
)}
>
{l10n.getString('onboarding-calibration_tutorial-calibrate')}
</Button>
@@ -148,7 +196,7 @@ export function CalibrationTutorialPage() {
</div>
<div className="mobile:hidden flex self-center w-[32rem] mobile:absolute">
<div className="stroke-none xs:fill-background-10 mobile:fill-background-50 mobile:blur-sm">
<TaybolIcon width="500"></TaybolIcon>
<TaybolIcon width="450"></TaybolIcon>
</div>
</div>
</div>

View File

@@ -0,0 +1,26 @@
:root {
--connect-tracker-layout-sidebar: 350px;
--connect-tracker-layout-top: 20px;
@screen lg {
--connect-tracker-layout-sidebar: 400px;
}
}
.connect-tracker-layout {
display: grid;
grid-template:
's t' var(--connect-tracker-layout-top)
's c' calc(100% - var(--connect-tracker-layout-top))
/ calc(var(--connect-tracker-layout-sidebar)) calc(100% - var(
--connect-tracker-layout-sidebar
));
@screen mobile {
grid-template:
's' auto
't' auto
'c' auto
/ 100%;
}
}

View File

@@ -11,7 +11,6 @@ import {
WifiProvisioningStatus,
WifiProvisioningStatusResponseT,
} from 'solarxr-protocol';
import { useLayout } from '@/hooks/layout';
import { useOnboarding } from '@/hooks/onboarding';
import { useTrackers } from '@/hooks/tracker';
import { useWebsocketAPI } from '@/hooks/websocket-api';
@@ -22,10 +21,8 @@ import { ProgressBar } from '@/components/commons/ProgressBar';
import { TipBox } from '@/components/commons/TipBox';
import { Typography } from '@/components/commons/Typography';
import { TrackerCard } from '@/components/tracker/TrackerCard';
import { useBnoExists } from '@/hooks/imu-logic';
import { useBreakpoint } from '@/hooks/breakpoint';
const BOTTOM_HEIGHT = 80;
import { useIsRestCalibrationTrackers } from '@/hooks/imu-logic';
import './ConnectTracker.scss';
const statusLabelMap = {
[WifiProvisioningStatus.NONE]:
@@ -58,9 +55,7 @@ const statusProgressMap = {
};
export function ConnectTrackersPage() {
const { isMobile } = useBreakpoint('mobile');
const { l10n } = useLocalization();
const { layoutHeight, ref } = useLayout<HTMLDivElement>();
const { useConnectedIMUTrackers } = useTrackers();
const { applyProgress, state } = useOnboarding();
const navigate = useNavigate();
@@ -72,7 +67,7 @@ export function ConnectTrackersPage() {
const connectedIMUTrackers = useConnectedIMUTrackers();
const bnoExists = useBnoExists(connectedIMUTrackers);
const bnoExists = useIsRestCalibrationTrackers(connectedIMUTrackers);
useEffect(() => {
if (!state.wifi) {
@@ -146,146 +141,123 @@ export function ConnectTrackersPage() {
);
return (
<div className="flex flex-col h-full items-center px-4 pb-4">
<div className="flex gap-10 mobile:flex-col w-full xs:max-w-7xl">
<div className="flex flex-col w-full xs:max-w-sm">
<Typography variant="main-title">
{l10n.getString('onboarding-connect_tracker-title')}
</Typography>
<Typography color="secondary">
{l10n.getString('onboarding-connect_tracker-description-p0-v1')}
</Typography>
<Typography color="secondary">
{l10n.getString('onboarding-connect_tracker-description-p1-v1')}
</Typography>
<div className="flex flex-col gap-2 py-5">
{/* <ArrowLink
to="/onboarding/connect"
direction="right"
variant="boxed"
>
I have other types of trackers
</ArrowLink> */}
<ArrowLink
to="/settings/serial"
state={{ SerialPort: 'Auto' }}
direction="right"
variant={state.alonePage ? 'boxed-2' : 'boxed'}
>
{l10n.getString('onboarding-connect_tracker-issue-serial')}
</ArrowLink>
</div>
<Localized
id={currentTip}
elems={{ em: <em className="italic"></em>, b: <b></b> }}
<div className="connect-tracker-layout h-full">
<div style={{ gridArea: 's' }} className="p-4">
<Typography variant="main-title">
{l10n.getString('onboarding-connect_tracker-title')}
</Typography>
<Typography color="secondary">
{l10n.getString('onboarding-connect_tracker-description-p0-v1')}
</Typography>
<Typography color="secondary">
{l10n.getString('onboarding-connect_tracker-description-p1-v1')}
</Typography>
<div className="flex flex-col gap-2 py-5">
<ArrowLink
to="/settings/serial"
state={{ SerialPort: 'Auto' }}
direction="right"
variant={state.alonePage ? 'boxed-2' : 'boxed'}
>
<TipBox>Conditional tip</TipBox>
</Localized>
{l10n.getString('onboarding-connect_tracker-issue-serial')}
</ArrowLink>
</div>
<Localized
id={currentTip}
elems={{ em: <em className="italic"></em>, b: <b></b> }}
>
<TipBox>Conditional tip</TipBox>
</Localized>
<div
className={classNames(
'rounded-xl h-24 flex gap-2 p-3 lg:w-full mt-4 relative',
state.alonePage ? 'bg-background-60' : 'bg-background-70',
isError && 'border-2 border-status-critical'
)}
>
<div
className={classNames(
'rounded-xl h-24 flex gap-2 p-3 lg:w-full mt-4 relative',
state.alonePage ? 'bg-background-60' : 'bg-background-70',
isError && 'border-2 border-status-critical'
'flex flex-col justify-center fill-background-10 absolute',
'right-5 bottom-8'
)}
>
<div
className={classNames(
'flex flex-col justify-center fill-background-10 absolute',
'right-5 bottom-8'
)}
>
<LoaderIcon slimeState={slimeStatus}></LoaderIcon>
</div>
<div className="flex flex-col grow self-center">
<Typography bold>
{l10n.getString('onboarding-connect_tracker-usb')}
</Typography>
<div className="flex fill-background-10 gap-1">
{/* <SpinIcon
youSpinMeRightRoundBabyRightRound={!isError}
></SpinIcon> */}
<Typography color="secondary">
{l10n.getString(statusLabelMap[provisioningStatus])}
</Typography>
</div>
<ProgressBar
progress={statusProgressMap[provisioningStatus]}
height={14}
animated={true}
colorClass={progressBarClass}
></ProgressBar>
</div>
<LoaderIcon slimeState={slimeStatus}></LoaderIcon>
</div>
<div className="flex flex-row mt-4 gap-3">
<Button
variant="secondary"
state={{ alonePage: state.alonePage }}
to="/onboarding/wifi-creds"
>
{state.alonePage
? l10n.getString('onboarding-connect_tracker-back')
: l10n.getString('onboarding-previous_step')}
</Button>
<Button
variant="primary"
to={
state.alonePage
? '/'
: bnoExists
? '/onboarding/calibration-tutorial'
: '/onboarding/assign-tutorial'
}
className="ml-auto"
>
{l10n.getString('onboarding-connect_tracker-next')}
</Button>
<div className="flex flex-col grow self-center">
<Typography bold>
{l10n.getString('onboarding-connect_tracker-usb')}
</Typography>
<div className="flex fill-background-10 gap-1">
<Typography color="secondary">
{l10n.getString(statusLabelMap[provisioningStatus])}
</Typography>
</div>
<ProgressBar
progress={statusProgressMap[provisioningStatus]}
height={14}
animated={true}
colorClass={progressBarClass}
></ProgressBar>
</div>
</div>
<div className="flex flex-col xs:flex-grow">
<Typography color="secondary" bold>
{l10n.getString('onboarding-connect_tracker-connected_trackers', {
amount: connectedIMUTrackers.length,
})}
</Typography>
<div
className="overflow-y-scroll mt-2"
ref={ref}
style={
isMobile && state.alonePage
? { height: layoutHeight - BOTTOM_HEIGHT }
: { height: layoutHeight }
}
<div className="flex flex-row mt-4 gap-3">
<Button
variant="secondary"
state={{ alonePage: state.alonePage }}
to="/onboarding/wifi-creds"
>
<div className="grid lg:grid-cols-2 md:grid-cols-1 gap-2 pr-1">
{Array.from({
...connectedIMUTrackers,
length: Math.max(connectedIMUTrackers.length, 1),
}).map((tracker, index) => (
<div key={index}>
{!tracker && (
<div
className={classNames(
'rounded-xl h-16 animate-pulse',
state.alonePage
? 'bg-background-80'
: 'bg-background-70'
)}
></div>
{state.alonePage
? l10n.getString('onboarding-connect_tracker-back')
: l10n.getString('onboarding-previous_step')}
</Button>
<Button
variant="primary"
to={
state.alonePage
? '/'
: bnoExists
? '/onboarding/calibration-tutorial'
: '/onboarding/assign-tutorial'
}
className="ml-auto"
>
{l10n.getString('onboarding-connect_tracker-next')}
</Button>
</div>
</div>
<div style={{ gridArea: 't' }} className="flex items-center px-5">
<Typography color="secondary" bold>
{l10n.getString('onboarding-connect_tracker-connected_trackers', {
amount: connectedIMUTrackers.length,
})}
</Typography>
</div>
<div style={{ gridArea: 'c' }} className="xs:overflow-y-auto">
<div className="grid lg:grid-cols-2 md:grid-cols-1 gap-2 pr-1 mx-5 py-4">
{Array.from({
...connectedIMUTrackers,
length: Math.max(connectedIMUTrackers.length, 1),
}).map((tracker, index) => (
<div key={index}>
{!tracker && (
<div
className={classNames(
'rounded-xl h-16 animate-pulse',
state.alonePage ? 'bg-background-80' : 'bg-background-70'
)}
{tracker && (
<TrackerCard
tracker={tracker.tracker}
device={tracker.device}
smol
></TrackerCard>
)}
</div>
))}
></div>
)}
{tracker && (
<TrackerCard
tracker={tracker.tracker}
device={tracker.device}
smol
></TrackerCard>
)}
</div>
</div>
))}
</div>
</div>
</div>

View File

@@ -134,9 +134,11 @@ export function ResetTutorialPage() {
</Button>
<Button
hidden={curIndex + 1 >= order.length}
variant="secondary"
className="ml-auto"
className={classNames(
'ml-auto',
curIndex + 1 >= order.length && 'hidden'
)}
onClick={() => {
setCurIndex(curIndex + 1);
}}

View File

@@ -6,7 +6,7 @@ import { Input } from '@/components/commons/Input';
import { Typography } from '@/components/commons/Typography';
import classNames from 'classnames';
import { useTrackers } from '@/hooks/tracker';
import { useBnoExists } from '@/hooks/imu-logic';
import { useIsRestCalibrationTrackers } from '@/hooks/imu-logic';
export function WifiCredsPage() {
const { l10n } = useLocalization();
@@ -17,7 +17,7 @@ export function WifiCredsPage() {
applyProgress(0.2);
const bnoExists = useBnoExists(connectedIMUTrackers);
const isRestCalibration = useIsRestCalibrationTrackers(connectedIMUTrackers);
return (
<form
@@ -97,7 +97,7 @@ export function WifiCredsPage() {
variant="secondary"
className={state.alonePage ? 'opacity-0' : ''}
to={
bnoExists
isRestCalibration
? '/onboarding/calibration-tutorial'
: '/onboarding/assign-tutorial'
}

View File

@@ -3,7 +3,7 @@ import { useOnboarding } from '@/hooks/onboarding';
import { Button } from '@/components/commons/Button';
import { Typography } from '@/components/commons/Typography';
import { useTrackers } from '@/hooks/tracker';
import { useBnoExists } from '@/hooks/imu-logic';
import { useIsRestCalibrationTrackers } from '@/hooks/imu-logic';
import { StickerSlime } from './StickerSlime';
import { TrackerArrow } from './TrackerArrow';
import { ExtensionArrow } from './ExtensionArrow';
@@ -13,7 +13,7 @@ export function AssignmentTutorialPage() {
const { applyProgress } = useOnboarding();
const { useConnectedIMUTrackers } = useTrackers();
const connectedIMUTrackers = useConnectedIMUTrackers();
const bnoExists = useBnoExists(connectedIMUTrackers);
const isRestCalibration = useIsRestCalibrationTrackers(connectedIMUTrackers);
applyProgress(0.46);
@@ -67,7 +67,7 @@ export function AssignmentTutorialPage() {
<Button
variant="secondary"
to={
bnoExists
isRestCalibration
? '/onboarding/calibration-tutorial'
: '/onboarding/wifi-creds'
}

View File

@@ -66,11 +66,11 @@ export function ManualProportionsPage() {
return (
<>
<div className="flex flex-col gap-5 h-full items-center w-full xs:justify-center overflow-y-auto relative">
<div className="flex flex-col gap-5 h-full items-center w-full xs:justify-center relative">
<div className="flex flex-col w-full h-full xs:max-w-5xl xs:justify-center">
<div className="flex gap-8 justify-center h-full xs:items-center">
<div className="flex flex-col w-full xs:max-w-2xl gap-3 items-center mobile:justify-around">
<div className="flex flex-col">
<div className="flex flex-col mx-4">
<Typography variant="main-title">
{l10n.getString('onboarding-manual_proportions-title')}
</Typography>

View File

@@ -105,7 +105,7 @@ export function CheckHeight({
</Typography>
</Localized>
<div className="flex flex-row items-center mt-2 gap-2">
<div className="flex flex-row items-center mt-2 gap-2 mobile:flex-col">
<Button
variant="primary"
onClick={startCountdown}

View File

@@ -7,6 +7,8 @@ import { useLocalization } from '@fluent/react';
import { P, match } from 'ts-pattern';
import { AutoboneErrorModal } from './AutoboneErrorModal';
import { PlayCircleIcon } from '@/components/commons/icon/PlayIcon';
import { useDebouncedEffect } from '@/hooks/timeout';
import { AUTOBONE_VIDEO } from './StartRecording';
export function Recording({
nextStep,
@@ -52,6 +54,14 @@ export function Recording({
setPaused(videoRef.current.paused);
}
useDebouncedEffect(
() => {
if (paused) videoRef.current?.pause();
},
[paused],
250
);
useEffect(() => {
if (!active && !paused) {
toggleVideo();
@@ -154,9 +164,9 @@ export function Recording({
</div>
<video
preload=""
preload="auto"
ref={videoRef}
src="/videos/autobone.webm"
src={AUTOBONE_VIDEO}
className="min-w-[12rem] w-[12rem]"
muted
loop

View File

@@ -5,6 +5,10 @@ import { Typography } from '@/components/commons/Typography';
import { useLocalization } from '@fluent/react';
import { useEffect, useRef, useState } from 'react';
import { PlayCircleIcon } from '@/components/commons/icon/PlayIcon';
import { useDebouncedEffect } from '@/hooks/timeout';
import { fetchResourceUrl } from '@/utils/tauri';
export const AUTOBONE_VIDEO = await fetchResourceUrl('/videos/autobone.webm');
export function StartRecording({
nextStep,
@@ -33,6 +37,14 @@ export function StartRecording({
setPaused(videoRef.current.paused);
}
useDebouncedEffect(
() => {
if (paused) videoRef.current?.pause();
},
[paused],
250
);
useEffect(() => {
if (!active && !paused) toggleVideo();
}, [active]);
@@ -87,9 +99,9 @@ export function StartRecording({
</div>
<video
preload=""
preload="auto"
ref={videoRef}
src="/videos/autobone.webm"
src={AUTOBONE_VIDEO}
className="min-w-[12rem] w-[12rem]"
muted
loop

View File

@@ -1,10 +1,14 @@
import { useEffect, useMemo, useState } from 'react';
import { useCallback, useMemo, useState } from 'react';
import { AssignTrackerRequestT, BodyPart, RpcMessage } from 'solarxr-protocol';
import { FlatDeviceTracker } from '@/hooks/app';
import { useOnboarding } from '@/hooks/onboarding';
import { useTrackers } from '@/hooks/tracker';
import { useWebsocketAPI } from '@/hooks/websocket-api';
import { MountingOrientationDegreesToQuatT } from '@/maths/quaternion';
import {
MountingOrientationDegreesToQuatT,
QuaternionFromQuatT,
similarQuaternions,
} from '@/maths/quaternion';
import { Button } from '@/components/commons/Button';
import { TipBox } from '@/components/commons/TipBox';
import { Typography } from '@/components/commons/Typography';
@@ -13,14 +17,14 @@ import { MountingSelectionMenu } from './MountingSelectionMenu';
import { useLocalization } from '@fluent/react';
import { useBreakpoint } from '@/hooks/breakpoint';
import { Quaternion } from 'three';
import { defaultConfig, useConfig } from '@/hooks/config';
import { AssignMode, defaultConfig, useConfig } from '@/hooks/config';
export function ManualMountingPage() {
const { isMobile } = useBreakpoint('mobile');
const { l10n } = useLocalization();
const { applyProgress, state } = useOnboarding();
const { sendRPCPacket } = useWebsocketAPI();
const { setConfig, config } = useConfig();
const { config } = useConfig();
const [selectedRole, setSelectRole] = useState<BodyPart>(BodyPart.NONE);
@@ -29,10 +33,6 @@ export function ManualMountingPage() {
const { useAssignedTrackers } = useTrackers();
const assignedTrackers = useAssignedTrackers();
useEffect(() => {
setConfig({ doneManualMounting: true });
}, []);
const trackerPartGrouped = useMemo(
() =>
assignedTrackers.reduce<{ [key: number]: FlatDeviceTracker[] }>(
@@ -66,10 +66,31 @@ export function ManualMountingPage() {
setSelectRole(BodyPart.NONE);
};
const getCurrRotation = useCallback(
(role: BodyPart) => {
if (role === BodyPart.NONE) return undefined;
const trackers = trackerPartGrouped[role] || [];
const [mountingOrientation, ...orientation] = trackers
.map((td) => td.tracker.info?.mountingOrientation)
.filter((orientation) => !!orientation)
.map((orientation) => QuaternionFromQuatT(orientation));
const identicalOrientations =
mountingOrientation !== undefined &&
orientation.every((quat) =>
similarQuaternions(quat, mountingOrientation)
);
return identicalOrientations ? mountingOrientation : undefined;
},
[trackerPartGrouped]
);
return (
<>
<MountingSelectionMenu
bodyPart={selectedRole}
currRotation={getCurrRotation(selectedRole)}
isOpen={selectedRole !== BodyPart.NONE}
onClose={() => setSelectRole(BodyPart.NONE)}
onDirectionSelected={onDirectionSelected}
@@ -104,7 +125,7 @@ export function ManualMountingPage() {
width={isMobile ? 160 : undefined}
mirror={config?.mirrorView ?? defaultConfig.mirrorView}
onlyAssigned={true}
advanced={true}
assignMode={AssignMode.All}
onRoleSelected={setSelectRole}
></BodyAssignment>
</div>

View File

@@ -5,18 +5,12 @@ import { SkipSetupWarningModal } from '@/components/onboarding/SkipSetupWarningM
import classNames from 'classnames';
import { Typography } from '@/components/commons/Typography';
import { Button } from '@/components/commons/Button';
import { TryManualFirstModal } from './TryManualFirstModal';
import { useConfig } from '@/hooks/config';
import { useNavigate } from 'react-router-dom';
export function MountingChoose() {
const { l10n } = useLocalization();
const { applyProgress, skipSetup, state } = useOnboarding();
const navigate = useNavigate();
const { config, setConfig } = useConfig();
const [animated, setAnimated] = useState(false);
const [skipWarning, setSkipWarning] = useState(false);
const [manualModal, setManualModal] = useState(false);
applyProgress(0.65);
@@ -58,7 +52,7 @@ export function MountingChoose() {
</Typography>
<Typography variant="vr-accessible" italic>
{l10n.getString(
'onboarding-choose_mounting-auto_mounting-label'
'onboarding-choose_mounting-auto_mounting-label-v2'
)}
</Typography>
</div>
@@ -71,17 +65,8 @@ export function MountingChoose() {
</div>
</div>
<Button
variant={!state.alonePage ? 'secondary' : 'tertiary'}
to={
config?.doneManualMounting
? '/onboarding/mounting/auto'
: undefined
}
onClick={
!config?.doneManualMounting
? () => setManualModal(true)
: undefined
}
variant="primary"
to={'/onboarding/mounting/auto'}
className="self-start mt-auto"
state={{ alonePage: state.alonePage }}
>
@@ -115,7 +100,7 @@ export function MountingChoose() {
</Typography>
<Typography variant="vr-accessible" italic>
{l10n.getString(
'onboarding-choose_mounting-manual_mounting-label'
'onboarding-choose_mounting-manual_mounting-label-v2'
)}
</Typography>
</div>
@@ -129,7 +114,7 @@ export function MountingChoose() {
</div>
<Button
variant="primary"
variant={!state.alonePage ? 'secondary' : 'tertiary'}
to="/onboarding/mounting/manual"
className="self-start mt-auto"
state={{ alonePage: state.alonePage }}
@@ -152,14 +137,6 @@ export function MountingChoose() {
)}
</div>
</div>
<TryManualFirstModal
isOpen={manualModal}
accept={() => {
setConfig({ doneManualMounting: true });
navigate('/onboarding/mounting/auto');
}}
cancel={() => setManualModal(false)}
></TryManualFirstModal>
<SkipSetupWarningModal
accept={skipSetup}
onClose={() => setSkipWarning(false)}

View File

@@ -1,12 +1,10 @@
import classNames from 'classnames';
import { MouseEventHandler } from 'react';
import ReactModal from 'react-modal';
import { useElemSize, useLayout } from '@/hooks/layout';
import { Button } from '@/components/commons/Button';
import { Typography } from '@/components/commons/Typography';
import { useLocalization } from '@fluent/react';
import { FootIcon } from '@/components/commons/icon/FootIcon';
import { rotationToQuatMap } from '@/maths/quaternion';
import { rotationToQuatMap, similarQuaternions } from '@/maths/quaternion';
import { Quaternion } from 'three';
import { SlimeUpIcon } from '@/components/commons/icon/SlimeUpIcon';
import { BodyPart } from 'solarxr-protocol';
@@ -113,14 +111,18 @@ export function MountingBodyPartIcon({
}
function PieSliceOfFeet({
onClick,
direction,
onDirectionSelected,
currRotation,
id,
d,
noText = false,
trackerTransform,
trackerWidth = 10,
}: {
onClick?: MouseEventHandler<SVGGElement>;
direction: Quaternion;
onDirectionSelected: (direction: Quaternion) => void;
currRotation?: Quaternion;
id: string;
d: string;
noText?: boolean;
@@ -131,7 +133,7 @@ function PieSliceOfFeet({
return (
<g
onClick={onClick}
onClick={() => onDirectionSelected(direction)}
className={classNames('group fill-background-10 stroke-background-10')}
>
<path
@@ -150,7 +152,12 @@ function PieSliceOfFeet({
</text>
<g
transform={trackerTransform}
className="fill-none stroke-none group-hover:fill-accent-background-20"
className={classNames(
'stroke-none group-hover:fill-accent-background-20',
currRotation && similarQuaternions(currRotation, direction)
? 'fill-background-90'
: 'fill-none'
)}
>
<SlimeUpIcon width={trackerWidth}></SlimeUpIcon>
</g>
@@ -163,17 +170,15 @@ export function MountingSelectionMenu({
onClose,
onDirectionSelected,
bodyPart,
currRotation,
}: {
isOpen: boolean;
onClose: () => void;
onDirectionSelected: (direction: Quaternion) => void;
bodyPart?: BodyPart;
currRotation?: Quaternion;
}) {
const { l10n } = useLocalization();
const { ref: refTrackers, layoutHeight: trackersHeight } =
useLayout<HTMLDivElement>();
const { ref: refOptions, height: optionsHeight } =
useElemSize<HTMLDivElement>();
return (
<ReactModal
@@ -182,104 +187,101 @@ export function MountingSelectionMenu({
shouldCloseOnEsc
onRequestClose={onClose}
overlayClassName={classNames(
'fixed top-0 right-0 left-0 bottom-0 flex flex-col items-center w-full h-full bg-black bg-opacity-90 z-20'
'fixed top-0 right-0 left-0 bottom-0 flex flex-col items-center w-full h-full bg-background-90 bg-opacity-90 z-20'
)}
className={classNames(
'focus:ring-transparent focus:ring-offset-transparent focus:outline-transparent outline-none mt-20 z-10 px-2'
'focus:ring-transparent focus:ring-offset-transparent focus:outline-transparent outline-none mt-20 z-10'
)}
>
<div className="flex w-full h-full flex-col ">
<Typography variant="main-title" bold>
<div className="flex flex-col p-4">
<Typography variant="main-title" bold textAlign="text-center">
{l10n.getString('mounting_selection_menu')}
</Typography>
<div
className="flex w-full flex-col flex-grow items-center gap-3 xs:justify-center"
ref={refTrackers}
style={{ height: trackersHeight - optionsHeight }}
>
<div className="flex justify-center items-center gap-6 w-full">
<svg
width="400"
viewBox="0 0 250 250"
className="fill-background-40"
>
<g transform="translate(80, 0)" className="fill-background-10">
<MountingBodyPartIcon width={100} bodyPart={bodyPart} />
</g>
<g strokeWidth="4" className="stroke-background-90">
<PieSliceOfFeet
d="M0 0-89 44A99 99 0 0 1-89-44Z"
onClick={() => onDirectionSelected(rotationToQuatMap.LEFT)}
id="tracker-rotation-left"
trackerTransform="translate(75, 0) scale(-1, 1)"
></PieSliceOfFeet>
<PieSliceOfFeet
d="M0 0-89-44A99 99 0 0 1-44-89Z"
onClick={() =>
onDirectionSelected(rotationToQuatMap.FRONT_LEFT)
}
id="tracker-rotation_left_front"
noText={true}
trackerTransform="translate(-2, 175) rotate(-135)"
trackerWidth={7}
></PieSliceOfFeet>
<PieSliceOfFeet
onClick={() => onDirectionSelected(rotationToQuatMap.FRONT)}
d="M0 0-44-89A99 99 0 0 1 44-89Z"
id="tracker-rotation-front"
trackerTransform="translate(0, 75) rotate(-90)"
></PieSliceOfFeet>
<PieSliceOfFeet
d="M0 0 44-89A99 99 0 0 1 89-44Z"
onClick={() =>
onDirectionSelected(rotationToQuatMap.FRONT_RIGHT)
}
id="tracker-rotation-front_right"
noText={true}
trackerTransform="translate(73, 0) rotate(-45)"
trackerWidth={7}
></PieSliceOfFeet>
<PieSliceOfFeet
d="M0 0 89-44A99 99 0 0 1 89 44Z"
onClick={() => onDirectionSelected(rotationToQuatMap.RIGHT)}
id="tracker-rotation-right"
trackerTransform="translate(175,0)"
></PieSliceOfFeet>
<PieSliceOfFeet
d="M0 0 89 44A99 99 0 0 1 44 89Z"
onClick={() =>
onDirectionSelected(rotationToQuatMap.BACK_RIGHT)
}
id="tracker-rotation-back_right"
noText={true}
trackerTransform="translate(252, 75) rotate(45)"
trackerWidth={7}
></PieSliceOfFeet>
<PieSliceOfFeet
d="M0 0 44 89A99 99 0 0 1-44 89Z"
onClick={() => onDirectionSelected(rotationToQuatMap.BACK)}
id="tracker-rotation-back"
trackerTransform="translate(250, 175) rotate(90)"
></PieSliceOfFeet>
<PieSliceOfFeet
d="M0 0-44 89A99 99 0 0 1-89 44Z"
onClick={() =>
onDirectionSelected(rotationToQuatMap.BACK_LEFT)
}
id="tracker-rotation-back_left"
noText={true}
trackerTransform="translate(177, 250) rotate(135)"
trackerWidth={7}
></PieSliceOfFeet>
</g>
</svg>
</div>
<div className="flex w-full flex-col flex-grow items-center gap-3 justify-center">
<svg width="400" viewBox="0 0 250 250" className="fill-background-40">
<g transform="translate(80, 0)" className="fill-background-10">
<MountingBodyPartIcon width={100} bodyPart={bodyPart} />
</g>
<g strokeWidth="4" className="stroke-background-90">
<PieSliceOfFeet
d="M0 0-89 44A99 99 0 0 1-89-44Z"
direction={rotationToQuatMap.LEFT}
onDirectionSelected={onDirectionSelected}
currRotation={currRotation}
id="tracker-rotation-left"
trackerTransform="translate(75, 0) scale(-1, 1)"
></PieSliceOfFeet>
<PieSliceOfFeet
d="M0 0-89-44A99 99 0 0 1-44-89Z"
direction={rotationToQuatMap.FRONT_LEFT}
onDirectionSelected={onDirectionSelected}
currRotation={currRotation}
id="tracker-rotation_left_front"
noText={true}
trackerTransform="translate(-2, 175) rotate(-135)"
trackerWidth={7}
></PieSliceOfFeet>
<PieSliceOfFeet
d="M0 0-44-89A99 99 0 0 1 44-89Z"
direction={rotationToQuatMap.FRONT}
onDirectionSelected={onDirectionSelected}
currRotation={currRotation}
id="tracker-rotation-front"
trackerTransform="translate(0, 75) rotate(-90)"
></PieSliceOfFeet>
<PieSliceOfFeet
d="M0 0 44-89A99 99 0 0 1 89-44Z"
direction={rotationToQuatMap.FRONT_RIGHT}
onDirectionSelected={onDirectionSelected}
currRotation={currRotation}
id="tracker-rotation-front_right"
noText={true}
trackerTransform="translate(73, 0) rotate(-45)"
trackerWidth={7}
></PieSliceOfFeet>
<PieSliceOfFeet
d="M0 0 89-44A99 99 0 0 1 89 44Z"
direction={rotationToQuatMap.RIGHT}
onDirectionSelected={onDirectionSelected}
currRotation={currRotation}
id="tracker-rotation-right"
trackerTransform="translate(175,0)"
></PieSliceOfFeet>
<PieSliceOfFeet
d="M0 0 89 44A99 99 0 0 1 44 89Z"
direction={rotationToQuatMap.BACK_RIGHT}
onDirectionSelected={onDirectionSelected}
currRotation={currRotation}
id="tracker-rotation-back_right"
noText={true}
trackerTransform="translate(252, 75) rotate(45)"
trackerWidth={7}
></PieSliceOfFeet>
<PieSliceOfFeet
d="M0 0 44 89A99 99 0 0 1-44 89Z"
direction={rotationToQuatMap.BACK}
onDirectionSelected={onDirectionSelected}
currRotation={currRotation}
id="tracker-rotation-back"
trackerTransform="translate(250, 175) rotate(90)"
></PieSliceOfFeet>
<PieSliceOfFeet
d="M0 0-44 89A99 99 0 0 1-89 44Z"
direction={rotationToQuatMap.BACK_LEFT}
onDirectionSelected={onDirectionSelected}
currRotation={currRotation}
id="tracker-rotation-back_left"
noText={true}
trackerTransform="translate(177, 250) rotate(135)"
trackerWidth={7}
></PieSliceOfFeet>
</g>
</svg>
</div>
</div>
<div
className="flex w-full justify-between absolute bottom-0 left-0 p-10 z-0"
onClick={onClose}
ref={refOptions}
>
<div className="flex flex-col justify-end pointer-events-auto">
<Button variant="primary" onClick={onClose}>

View File

@@ -1,64 +0,0 @@
import { BaseModal } from '@/components/commons/BaseModal';
import { Button } from '@/components/commons/Button';
import { Typography } from '@/components/commons/Typography';
import { Localized, useLocalization } from '@fluent/react';
export function TryManualFirstModal({
isOpen = true,
cancel,
accept,
}: {
/**
* Is the parent/sibling component opened?
*/
isOpen: boolean;
/**
* Function to trigger when they want to do automatic anyways
*/
accept: () => void;
/**
* Function to trigger when they agree to do manual
*/
cancel?: () => void;
}) {
const { l10n } = useLocalization();
return (
<BaseModal isOpen={isOpen} onRequestClose={cancel}>
<div className="flex flex-col gap-3">
<>
<div className="flex flex-col items-center gap-3 fill-accent-background-20">
<div className="flex flex-col items-center gap-2">
<Typography
variant="main-title"
whitespace="whitespace-pre"
textAlign="text-center"
>
{l10n.getString(
'onboarding-choose_mounting-manual_modal-title'
)}
</Typography>
<div className="w-[30vw] min-w-fit">
<Localized
id="onboarding-choose_mounting-manual_modal-description"
elems={{ b: <b></b> }}
>
<Typography variant="standard">
You should do manual mounting first!
</Typography>
</Localized>
</div>
</div>
</div>
<Button variant="primary" onClick={accept}>
{l10n.getString('onboarding-choose_mounting-manual_modal-confirm')}
</Button>
<Button variant="tertiary" onClick={cancel}>
{l10n.getString('onboarding-choose_mounting-manual_modal-cancel')}
</Button>
</>
</div>
</BaseModal>
);
}

View File

@@ -41,10 +41,10 @@ export function MountingResetStep({
</div>
{isMobile && (
<div className="flex flex-col pt-1 items-center fill-background-50 justify-center px-12">
<div className="flex flex-col items-center fill-background-50 justify-center">
<img
src="/images/mounting-reset-pose.webp"
width={125}
width={450}
alt="mounting reset ski pose"
/>
</div>
@@ -65,10 +65,10 @@ export function MountingResetStep({
</div>
</div>
{!isMobile && (
<div className="flex flex-col pt-1 items-center fill-background-50 justify-center px-12">
<div className="flex flex-col pt-1 items-center fill-background-50 justify-center">
<img
src="/images/mounting-reset-pose.webp"
width={125}
width={600}
alt="mounting reset ski pose"
/>
</div>

View File

@@ -0,0 +1,125 @@
import { Radio } from '@/components/commons/Radio';
import { Typography } from '@/components/commons/Typography';
import { AssignMode, defaultConfig, useConfig } from '@/hooks/config';
import { ASSIGNMENT_MODES } from '@/components/onboarding/BodyAssignment';
import { useLocalization } from '@fluent/react';
import { useTrackers } from '@/hooks/tracker';
import { useForm } from 'react-hook-form';
import { useEffect } from 'react';
import { Dropdown } from '@/components/commons/Dropdown';
// Ordered collection of assign modes with the number of IMU trackers
const ASSIGN_MODE_OPTIONS = [
AssignMode.LowerBody,
AssignMode.Core,
AssignMode.EnhancedCore,
AssignMode.FullBody,
AssignMode.All,
].reduce(
(options, mode) => ({ ...options, [mode]: ASSIGNMENT_MODES[mode].length }),
{} as Record<AssignMode, number>
);
export function TrackerAssignOptions({
variant = 'radio',
}: {
variant: 'radio' | 'dropdown';
}) {
const { l10n } = useLocalization();
const { useConnectedIMUTrackers } = useTrackers();
const connectedIMUTrackers = useConnectedIMUTrackers().length;
const { config, setConfig } = useConfig();
const { control, watch, setValue } = useForm<{
assignMode: AssignMode;
}>({
defaultValues: {
assignMode: config?.assignMode ?? defaultConfig.assignMode,
},
});
const { assignMode } = watch();
useEffect(() => {
setConfig({ assignMode });
}, [assignMode]);
useEffect(() => {
if (connectedIMUTrackers <= ASSIGN_MODE_OPTIONS[assignMode]) return;
const selectedAssignMode =
(Object.entries(ASSIGN_MODE_OPTIONS).find(
([_, count]) => count >= connectedIMUTrackers
)?.[0] as AssignMode) ?? AssignMode.All;
if (assignMode !== selectedAssignMode) {
setValue('assignMode', selectedAssignMode);
}
}, [connectedIMUTrackers, assignMode]);
const ItemContent = ({
mode,
trackersCount,
}: {
mode: string;
trackersCount: number;
}) => (
<>
<Typography variant="main-title" textAlign="text-right">
{l10n.getString('onboarding-assign_trackers-option-amount', {
trackersCount,
})}
</Typography>
<div className="flex flex-col">
<Typography>
{l10n.getString('onboarding-assign_trackers-option-label', {
mode,
})}
</Typography>
<Typography variant="standard" color="secondary">
{l10n.getString('onboarding-assign_trackers-option-description', {
mode,
})}
</Typography>
</div>
</>
);
if (variant == 'dropdown')
return (
<Dropdown
control={control}
name="assignMode"
display="block"
direction="down"
placeholder={''}
items={Object.entries(ASSIGN_MODE_OPTIONS).map(
([mode, trackersCount]) => ({
component: (
<div className="flex flex-row gap-2 py-1 text-left">
<ItemContent
mode={mode}
trackersCount={trackersCount}
></ItemContent>
</div>
),
value: mode,
})
)}
></Dropdown>
);
return Object.entries(ASSIGN_MODE_OPTIONS).map(([mode, trackersCount]) => (
<Radio
key={mode}
name="assignMode"
control={control}
value={mode}
disabled={connectedIMUTrackers > trackersCount && mode !== AssignMode.All}
className="hidden"
>
<div className="flex flex-row md:gap-4 gap-2">
<ItemContent mode={mode} trackersCount={trackersCount}></ItemContent>
</div>
</Radio>
));
}

View File

@@ -30,9 +30,10 @@ import {
} from '@/components/onboarding/BodyAssignment';
import { NeckWarningModal } from '@/components/onboarding/NeckWarningModal';
import { TrackerSelectionMenu } from './TrackerSelectionMenu';
import { useConfig } from '@/hooks/config';
import { defaultConfig, useConfig } from '@/hooks/config';
import { playTapSetupSound } from '@/sounds/sounds';
import { useBreakpoint } from '@/hooks/breakpoint';
import { TrackerAssignOptions } from './TrackerAssignOptions';
export type BodyPartError = {
label: string | undefined;
@@ -54,19 +55,17 @@ export function TrackersAssignPage() {
const { applyProgress, state } = useOnboarding();
const { sendRPCPacket, useRPCPacket } = useWebsocketAPI();
const defaultValues = {
advanced: config?.advancedAssign ?? false,
mirrorView: config?.mirrorView ?? true,
mirrorView: config?.mirrorView ?? defaultConfig.mirrorView,
};
const { control, watch } = useForm<{
advanced: boolean;
mirrorView: boolean;
}>({ defaultValues });
const { advanced, mirrorView } = watch();
const { mirrorView } = watch();
const [selectedRole, setSelectRole] = useState<BodyPart>(BodyPart.NONE);
const assignedTrackers = useAssignedTrackers();
useEffect(() => {
setConfig({ advancedAssign: advanced, mirrorView });
}, [advanced, mirrorView]);
setConfig({ mirrorView });
}, [mirrorView]);
const [tapDetectionSettings, setTapDetectionSettings] = useState<Omit<
TapDetectionSettingsT,
@@ -78,7 +77,9 @@ export function TrackersAssignPage() {
}, []);
useRPCPacket(RpcMessage.SettingsResponse, (settings: SettingsResponseT) => {
setTapDetectionSettings(settings.tapDetectionSettings);
if (settings.tapDetectionSettings) {
setTapDetectionSettings(settings.tapDetectionSettings);
}
});
useEffect(() => {
@@ -266,7 +267,7 @@ export function TrackersAssignPage() {
<NeckWarningModal
isOpen={shouldShowChokerWarn}
overlayClassName={classNames(
'fixed top-0 right-0 left-0 bottom-0 flex flex-col items-center w-full h-full justify-center bg-black bg-opacity-90 z-20'
'fixed top-0 right-0 left-0 bottom-0 flex flex-col items-center w-full h-full justify-center bg-background-90 bg-opacity-90 z-20'
)}
onClose={() => closeChokerWarning(true)}
accept={() => closeChokerWarning(false)}
@@ -290,13 +291,17 @@ export function TrackersAssignPage() {
</Typography>
</div>
<TipBox>{l10n.getString('tips-find_tracker')}</TipBox>
<div>
<CheckBox
control={control}
label={l10n.getString('onboarding-assign_trackers-advanced')}
name="advanced"
variant="toggle"
></CheckBox>
{!!firstError && (
<div className="bg-status-warning text-background-60 px-3 py-2 text-justify rounded-md">
<div className="flex flex-col gap-1 whitespace-normal">
<span>{firstError.label}</span>
</div>
</div>
)}
<div className="flex flex-col md:gap-4 sm:gap-2 xs:gap-1 mobile:gap-4">
<TrackerAssignOptions
variant={isMobile ? 'dropdown' : 'radio'}
/>
<CheckBox
control={control}
label={l10n.getString(
@@ -306,13 +311,6 @@ export function TrackersAssignPage() {
variant="toggle"
></CheckBox>
</div>
{!!firstError && (
<div className="bg-status-warning text-background-60 px-3 py-2 text-justify rounded-md">
<div className="flex flex-col gap-1 whitespace-normal">
<span>{firstError.label}</span>
</div>
</div>
)}
<div className="flex flex-row">
{!state.alonePage && (
<>
@@ -336,14 +334,15 @@ export function TrackersAssignPage() {
)}
</div>
</div>
<div className="flex flex-col rounded-xl fill-background-50">
<div className="flex flex-col rounded-xl fill-background-50 pt-1">
<BodyAssignment
width={isMobile ? 150 : undefined}
dotSize={isMobile ? 10 : undefined}
onlyAssigned={false}
highlightedRoles={firstError?.affectedRoles || []}
rolesWithErrors={rolesWithErrors}
advanced={advanced ?? defaultValues.advanced}
mirror={mirrorView ?? defaultValues.mirrorView}
assignMode={config?.assignMode ?? defaultConfig.assignMode}
mirror={mirrorView}
onRoleSelected={tryOpenChokerWarning}
></BodyAssignment>
</div>

View File

@@ -2,7 +2,6 @@ import classNames from 'classnames';
import ReactModal from 'react-modal';
import { BodyPart } from 'solarxr-protocol';
import { FlatDeviceTracker } from '@/hooks/app';
import { useElemSize, useLayout } from '@/hooks/layout';
import { useTrackers } from '@/hooks/tracker';
import { Button } from '@/components/commons/Button';
import { TipBox } from '@/components/commons/TipBox';
@@ -22,12 +21,6 @@ export function TrackerSelectionMenu({
onTrackerSelected: (tracker: FlatDeviceTracker | null) => void;
}) {
const { l10n } = useLocalization();
const { ref: refTrackers, layoutHeight: trackersHeight } =
useLayout<HTMLDivElement>();
const { ref: refOptions, height: optionsHeight } =
useElemSize<HTMLDivElement>();
// This is true when the neck warning has been accepted
// It is used for showing or not showing the actual modal
const { useAssignedTrackers, useUnassignedTrackers } = useTrackers();
const unassignedTrackers = useUnassignedTrackers();
@@ -41,55 +34,28 @@ export function TrackerSelectionMenu({
shouldCloseOnEsc
onRequestClose={onClose}
overlayClassName={classNames(
'fixed top-0 right-0 left-0 bottom-0 flex flex-col items-center w-full h-full bg-black bg-opacity-90 z-20'
'fixed top-0 right-0 left-0 bottom-0 flex flex-col items-center w-full h-full bg-background-90 bg-opacity-90 z-20'
)}
className={classNames(
'focus:ring-transparent focus:ring-offset-transparent focus:outline-transparent outline-none mt-20 z-10'
'focus:ring-transparent focus:ring-offset-transparent focus:outline-transparent outline-none z-10 h-full pt-10'
)}
>
<div className="flex w-full h-full flex-col ">
<div className="flex w-full flex-col flex-grow items-center gap-3">
<Typography variant="mobile-title" bold>
<div className="flex w-full h-full flex-col px-4">
<div className="flex w-full flex-col flex-grow h-0 items-center gap-3 py-4">
<Typography variant="main-title" bold>
{l10n.getString('tracker_selection_menu-' + BodyPart[bodyPart])}
</Typography>
<div className="w-full max-w-sm">
<TipBox>{l10n.getString('tips-tap_setup')}</TipBox>
</div>
<div className="relative">
<div
className="w-full h-full xs:min-w-[700px] overflow-y-auto p-2 pt-0 flex flex-col gap-6"
ref={refTrackers}
style={{ height: trackersHeight - optionsHeight }}
>
<div className="flex flex-col gap-3">
{unassignedTrackers.length && (
<div className="flex flex-col gap-3">
<Typography>
{l10n.getString('tracker_selection_menu-unassigned')}
</Typography>
<div className="grid xs:grid-cols-2 mobile:grid-cols-1 gap-3">
{unassignedTrackers.map((fd, index) => (
<TrackerCard
key={index}
tracker={fd.tracker}
device={fd.device}
onClick={() => onTrackerSelected(fd)}
smol
interactable
outlined={
bodyPart ===
(fd.tracker.info?.bodyPart || BodyPart.NONE)
}
></TrackerCard>
))}
</div>
</div>
)}
<div className="w-full p-2 flex flex-col flex-grow h-0 gap-4 overflow-y-auto">
{unassignedTrackers.length && (
<>
<Typography>
{l10n.getString('tracker_selection_menu-assigned')}
{l10n.getString('tracker_selection_menu-unassigned')}
</Typography>
<div className=" grid xs:grid-cols-2 mobile:grid-cols-1 gap-3">
{assignedTrackers.map((fd, index) => (
<div className="grid xs:grid-cols-2 mobile:grid-cols-1 gap-3">
{unassignedTrackers.map((fd, index) => (
<TrackerCard
key={index}
tracker={fd.tracker}
@@ -104,23 +70,37 @@ export function TrackerSelectionMenu({
></TrackerCard>
))}
</div>
</div>
</>
)}
<Typography>
{l10n.getString('tracker_selection_menu-assigned')}
</Typography>
<div className=" grid xs:grid-cols-2 mobile:grid-cols-1 gap-3">
{assignedTrackers.map((fd, index) => (
<TrackerCard
key={index}
tracker={fd.tracker}
device={fd.device}
onClick={() => onTrackerSelected(fd)}
smol
interactable
outlined={
bodyPart === (fd.tracker.info?.bodyPart || BodyPart.NONE)
}
></TrackerCard>
))}
</div>
</div>
<div className="flex w-full justify-end" onClick={onClose}>
<div className="flex flex-col justify-end pointer-events-auto">
<Button
variant="primary"
onClick={() => onTrackerSelected(null)}
>
{l10n.getString('tracker_selection_menu-dont_assign')}
</Button>
</div>
</div>
</div>
</div>
<div
className="flex w-full justify-between absolute bottom-0 left-0 p-10 z-0"
onClick={onClose}
ref={refOptions}
>
<div className="w-full max-w-sm">
{/* <TipBox>{l10n.getString('tips-find_tracker')}</TipBox> */}
</div>
<div className="flex flex-col justify-end pointer-events-auto">
<Button variant="primary" onClick={() => onTrackerSelected(null)}>
{l10n.getString('tracker_selection_menu-dont_assign')}
</Button>
</div>
</div>
</ReactModal>

View File

@@ -0,0 +1,25 @@
:root {
--settings-sidebar-w: 200px;
}
.settings-layout {
display: grid;
grid-template:
't t t' var(--topbar-h)
'n s c' calc(100% - var(--topbar-h))
/ var(--navbar-w) var(--settings-sidebar-w) calc(100% - var(--navbar-w) - var(
--settings-sidebar-w
));
@screen lg {
--settings-sidebar-w: 270px;
}
@screen mobile {
grid-template:
't' var(--topbar-h)
'c' calc(100% - var(--topbar-h) - var(--navbar-h))
'n' calc(var(--navbar-h))
/ 100%;
}
}

View File

@@ -1,5 +1,4 @@
import { ReactNode, useEffect } from 'react';
import { useElemSize, useLayout } from '@/hooks/layout';
import { Navbar } from '@/components/Navbar';
import { TopBar } from '@/components/TopBar';
import { SettingsSidebar } from './SettingsSidebar';
@@ -8,6 +7,7 @@ import { Dropdown } from '@/components/commons/Dropdown';
import { useForm } from 'react-hook-form';
import { useLocalization } from '@fluent/react';
import { useLocation, useNavigate } from 'react-router-dom';
import './SettingsLayout.scss';
export function SettingSelectorMobile() {
const { l10n } = useLocalization();
@@ -84,29 +84,26 @@ export function SettingSelectorMobile() {
);
}
export function SettingsLayoutRoute({ children }: { children: ReactNode }) {
const { layoutHeight, ref } = useLayout<HTMLDivElement>();
const { height, ref: navRef } = useElemSize<HTMLDivElement>();
export function SettingsLayout({ children }: { children: ReactNode }) {
const { isMobile } = useBreakpoint('mobile');
return (
<>
<TopBar></TopBar>
<div ref={ref} className="flex-grow" style={{ height: layoutHeight }}>
<div className="flex h-full xs:pb-3">
{!isMobile && <Navbar></Navbar>}
<div className="h-full w-full gap-2 flex">
{!isMobile && <SettingsSidebar></SettingsSidebar>}
<div className="w-full flex flex-col">
{isMobile && <SettingSelectorMobile></SettingSelectorMobile>}
<div
className="flex flex-col overflow-y-auto xs:pr-1 xs:mr-1 mobile:pt-7 pb-3"
style={{ minHeight: layoutHeight - height }}
>
{children}
</div>
<div ref={navRef}>{isMobile && <Navbar></Navbar>}</div>
</div>
</div>
<div className="settings-layout h-full">
<div style={{ gridArea: 't' }}>
<TopBar></TopBar>
</div>
<div style={{ gridArea: 'n' }}>
<Navbar></Navbar>
</div>
<div style={{ gridArea: 's' }} className="my-2">
<SettingsSidebar></SettingsSidebar>
</div>
<div
style={{ gridArea: 'c' }}
className="xs:pl-2 xs:pb-2 xs:mt-2 mobile:mt-7 overflow-y-auto"
>
{isMobile && <SettingSelectorMobile></SettingSelectorMobile>}
{children}
</div>
</div>
</>

View File

@@ -29,8 +29,8 @@ export function SettingsPageLayout({
'.overflow-y-auto'
) as HTMLElement | null;
if (closestScroll) {
// The 40 is just enough padding for making the scroll look perfect
const topPadding = isMobile ? 80 : 40;
// The 45 is just enough padding for making the scroll look perfect
const topPadding = isMobile ? 80 : 45;
closestScroll.scroll({
top: elem.offsetTop - topPadding,
behavior: 'smooth',
@@ -58,7 +58,7 @@ export function SettingsPagePaneLayout({
return (
<div
className={classNames(
'mobile:scroll-mt-7 bg-background-70 rounded-lg px-4 py-8 flex xs:gap-4 w-full relative',
'bg-background-70 rounded-lg px-4 py-8 flex xs:gap-4 w-full relative',
className
)}
{...props}

View File

@@ -42,7 +42,7 @@ export function SettingsLink({
export function SettingsSidebar() {
const { l10n } = useLocalization();
return (
<div className="flex flex-col px-5 w-[280px] min-w-[280px] py-5 gap-3 overflow-y-auto bg-background-70 rounded-lg">
<div className="flex flex-col px-5 py-5 gap-3 overflow-y-auto bg-background-70 rounded-lg h-full">
<Typography variant="main-title">
{l10n.getString('settings-sidebar-title')}
</Typography>

View File

@@ -96,6 +96,7 @@ interface SettingsForm {
armsMountingResetMode: number;
yawResetSmoothTime: number;
saveMountingReset: boolean;
resetHmdPitch: boolean;
};
}
@@ -158,6 +159,7 @@ const defaultValues: SettingsForm = {
armsMountingResetMode: 0,
yawResetSmoothTime: 0.0,
saveMountingReset: false,
resetHmdPitch: false,
},
};
@@ -294,6 +296,7 @@ export function GeneralSettings() {
values.resetsSettings.yawResetSmoothTime;
resetsSettings.saveMountingReset =
values.resetsSettings.saveMountingReset;
resetsSettings.resetHmdPitch = values.resetsSettings.resetHmdPitch;
settings.resetsSettings = resetsSettings;
}
@@ -326,7 +329,7 @@ export function GeneralSettings() {
if (settings.steamVrTrackers) {
formData.trackers = settings.steamVrTrackers;
if (
settings.steamVrTrackers.leftHand &&
settings.steamVrTrackers.leftHand ||
settings.steamVrTrackers.rightHand
) {
setHandsWarning(false);
@@ -859,24 +862,6 @@ export function GeneralSettings() {
)}
/>
</div>
<div className="flex flex-col pt-2 pb-3">
<Typography color="secondary">
{l10n.getString(
'settings-general-fk_settings-leg_fk-reset_mounting_feet-description'
)}
</Typography>
</div>
<div className="grid sm:grid-cols-1 gap-3 pb-3">
<CheckBox
variant="toggle"
outlined
control={control}
name="resetsSettings.resetMountingFeet"
label={l10n.getString(
'settings-general-fk_settings-leg_fk-reset_mounting_feet'
)}
/>
</div>
<div className="flex flex-col pt-2 pb-3">
<Typography bold>
@@ -900,12 +885,53 @@ export function GeneralSettings() {
/>
</div>
<div className="flex flex-col pt-2">
<Typography bold>
{l10n.getString('settings-general-fk_settings-reset_settings')}
</Typography>
</div>
<div className="flex flex-col pt-2 pb-3">
<Typography color="secondary">
{l10n.getString(
'settings-general-fk_settings-reset_settings-reset_hmd_pitch-description'
)}
</Typography>
</div>
<div className="grid sm:grid-cols-1 gap-3 pb-3">
<CheckBox
variant="toggle"
outlined
control={control}
name="resetsSettings.resetHmdPitch"
label={l10n.getString(
'settings-general-fk_settings-reset_settings-reset_hmd_pitch'
)}
/>
</div>
<div className="flex flex-col pt-2 pb-3">
<Typography color="secondary">
{l10n.getString(
'settings-general-fk_settings-leg_fk-reset_mounting_feet-description'
)}
</Typography>
</div>
<div className="grid sm:grid-cols-1 gap-3 pb-3">
<CheckBox
variant="toggle"
outlined
control={control}
name="resetsSettings.resetMountingFeet"
label={l10n.getString(
'settings-general-fk_settings-leg_fk-reset_mounting_feet'
)}
/>
</div>
<Typography color="secondary">
{l10n.getString(
'settings-general-fk_settings-arm_fk-reset_mode-description'
)}
</Typography>
<div className="grid md:grid-cols-2 flex-col gap-3 pt-2">
<div className="grid md:grid-cols-2 flex-col gap-3 pt-2 pb-3">
<Radio
control={control}
name="resetsSettings.armsMountingResetMode"
@@ -951,6 +977,7 @@ export function GeneralSettings() {
value={'3'}
></Radio>
</div>
{config?.debug && (
<>
<div className="flex flex-col pt-2 pb-3">

View File

@@ -30,6 +30,7 @@ interface InterfaceSettingsForm {
feedbackSoundVolume: number;
connectedTrackersWarning: boolean;
useTray: boolean;
discordPresence: boolean;
};
}
@@ -55,6 +56,8 @@ export function InterfaceSettings() {
config?.connectedTrackersWarning ??
defaultConfig.connectedTrackersWarning,
useTray: config?.useTray ?? defaultConfig.useTray ?? false,
discordPresence:
config?.discordPresence ?? defaultConfig.discordPresence,
},
},
});
@@ -70,6 +73,7 @@ export function InterfaceSettings() {
textSize: values.appearance.textSize,
connectedTrackersWarning: values.notifications.connectedTrackersWarning,
useTray: values.notifications.useTray,
discordPresence: values.notifications.discordPresence,
});
};
@@ -204,6 +208,28 @@ export function InterfaceSettings() {
)}
/>
</div>
<Typography bold>
{l10n.getString('settings-general-interface-discord_presence')}
</Typography>
<div className="flex flex-col pt-1 pb-2">
<Typography color="secondary">
{l10n.getString(
'settings-general-interface-discord_presence-description'
)}
</Typography>
</div>
<div className="grid sm:grid-cols-2 pb-4">
<CheckBox
variant="toggle"
control={control}
outlined
name="notifications.discordPresence"
label={l10n.getString(
'settings-general-interface-discord_presence-label'
)}
/>
</div>
</>
</SettingsPagePaneLayout>

View File

@@ -1,4 +1,4 @@
import { useEffect, useRef, useState } from 'react';
import { useEffect, useLayoutEffect, useRef, useState } from 'react';
import { useForm } from 'react-hook-form';
import { useLocation } from 'react-router-dom';
import {
@@ -14,7 +14,6 @@ import {
SerialUpdateResponseT,
SerialTrackerGetWifiScanRequestT,
} from 'solarxr-protocol';
import { useElemSize, useLayout } from '@/hooks/layout';
import { useWebsocketAPI } from '@/hooks/websocket-api';
import { Button } from '@/components/commons/Button';
import { Dropdown } from '@/components/commons/Dropdown';
@@ -22,27 +21,23 @@ import { Typography } from '@/components/commons/Typography';
import { Localized, useLocalization } from '@fluent/react';
import { BaseModal } from '@/components/commons/BaseModal';
import { WarningBox } from '@/components/commons/TipBox';
import { useBreakpoint } from '@/hooks/breakpoint';
import { useIsTauri } from '@/hooks/breakpoint';
import { fileSave } from 'browser-fs-access';
import { save } from '@tauri-apps/plugin-dialog';
import { writeTextFile } from '@tauri-apps/plugin-fs';
import { error } from '@/utils/logging';
import { waitUntil } from '@/utils/a11y';
export interface SerialForm {
port: string;
}
export function Serial() {
const {
layoutHeight,
layoutWidth,
ref: consoleRef,
} = useLayout<HTMLDivElement>();
const { isMobile } = useBreakpoint('mobile');
const { l10n } = useLocalization();
const { state } = useLocation();
const toolbarRef = useRef<HTMLDivElement>(null);
const { height } = useElemSize(toolbarRef);
const { useRPCPacket, sendRPCPacket } = useWebsocketAPI();
// const consoleRef = useRef<HTMLPreElement>(null);
const consoleRef = useRef<HTMLDivElement>(null);
const [consoleContent, setConsole] = useState('');
const [isSerialOpen, setSerialOpen] = useState(false);
@@ -100,7 +95,7 @@ export function Serial() {
setSerialOpen(true);
}
if (data.log && consoleRef.current) {
if (data.log) {
setConsole((console) => console + data.log);
}
}
@@ -167,6 +162,50 @@ export function Serial() {
);
};
const isTauri = useIsTauri();
const consoleContentRef = useRef(consoleContent);
useLayoutEffect(() => {
consoleContentRef.current = consoleContent;
}, [consoleContent]);
const saveLogToFile = async () => {
// Check if we have getInfos and fetch them if we don't
if (!consoleContentRef.current.includes('GET INFO')) {
getInfos();
await waitUntil(
() => consoleContentRef.current.includes('GET INFO'),
100,
10
);
}
if (isTauri) {
save({
filters: [
{
name: l10n.getString('settings-serial-file_type'),
extensions: ['txt'],
},
],
defaultPath: 'serial-logs.txt',
})
.then((path) =>
path ? writeTextFile(path, consoleContentRef.current) : undefined
)
.catch((err) => {
error(err);
});
} else {
const blob = new Blob([consoleContentRef.current], {
type: 'text/plain',
});
fileSave(blob, {
fileName: 'serial-logs.txt',
extensions: ['.txt'],
});
}
};
return (
<>
<BaseModal
@@ -191,8 +230,8 @@ export function Serial() {
</Button>
</div>
</BaseModal>
<div className="flex flex-col bg-background-70 h-full p-5 rounded-md">
<div className="flex flex-col pb-2">
<div className="flex flex-col bg-background-70 h-full p-4 mobile:p-2 rounded-md">
<div className="flex flex-col pb-2 mobile:pt-4">
<Typography variant="main-title">
{l10n.getString('settings-serial')}
</Typography>
@@ -207,16 +246,12 @@ export function Serial() {
))}
</>
</div>
<div className="bg-background-80 rounded-lg flex flex-col p-2">
<div className="bg-background-80 rounded-lg flex-grow h-0 flex flex-col p-2">
<div
className="flex-grow overflow-x-auto overflow-y-auto"
ref={consoleRef}
className="overflow-x-auto overflow-y-auto"
style={{
height: layoutHeight - height - 30 - (isMobile ? 88 : 0),
width: layoutWidth - 24,
}}
>
<div className="flex select-text px-3">
<div className="flex select-text">
<pre>
{isSerialOpen
? consoleContent
@@ -224,52 +259,42 @@ export function Serial() {
</pre>
</div>
</div>
<div className="" ref={toolbarRef}>
<div className="border-t-2 pt-2 border-background-60 border-solid m-2 gap-2 flex flex-row">
<div className="flex flex-grow flex-wrap gap-2 mobile:grid mobile:grid-cols-2 mobile:grid-rows-2">
<Button variant="quaternary" onClick={reboot}>
{l10n.getString('settings-serial-reboot')}
</Button>
<Button
variant="quaternary"
onClick={() => setTryFactoryReset(true)}
>
{l10n.getString('settings-serial-factory_reset')}
</Button>
<Button variant="quaternary" onClick={getInfos}>
{l10n.getString('settings-serial-get_infos')}
</Button>
<Button variant="quaternary" onClick={getWifiScan}>
{l10n.getString('settings-serial-get_wifi_scan')}
</Button>
{isMobile && (
<Dropdown
control={control}
name="port"
display="block"
placeholder={l10n.getString(
'settings-serial-serial_select'
)}
items={serialDevices.map((device) => ({
label: device.name?.toString() || 'error',
value: device.port?.toString() || 'error',
}))}
></Dropdown>
)}
</div>
{!isMobile && (
<div className="border-t-2 pt-2 border-background-60 border-solid gap-2 flex flex-row">
<div className="xs:flex flex-grow xs:flex-wrap gap-2 grid grid-cols-2">
<Button variant="quaternary" onClick={reboot}>
{l10n.getString('settings-serial-reboot')}
</Button>
<Button
variant="quaternary"
onClick={() => setTryFactoryReset(true)}
>
{l10n.getString('settings-serial-factory_reset')}
</Button>
<Button variant="quaternary" onClick={getInfos}>
{l10n.getString('settings-serial-get_infos')}
</Button>
<Button variant="quaternary" onClick={getWifiScan}>
{l10n.getString('settings-serial-get_wifi_scan')}
</Button>
<Button
variant="quaternary"
onClick={saveLogToFile}
disabled={!isSerialOpen || !consoleContent.trim()}
>
{l10n.getString('settings-serial-save_logs')}
</Button>
<div className="w-full mobile:col-span-2">
<Dropdown
control={control}
name="port"
display="fit"
display="block"
placeholder={l10n.getString('settings-serial-serial_select')}
items={serialDevices.map((device) => ({
label: device.name?.toString() || 'error',
value: device.port?.toString() || 'error',
}))}
></Dropdown>
)}
</div>
</div>
</div>
</div>

View File

@@ -32,6 +32,7 @@ interface VMCSettingsForm {
};
vrmJson?: FileList;
anchorHip: boolean;
mirrorTracking: boolean;
};
}
@@ -44,6 +45,7 @@ const defaultValues = {
address: '127.0.0.1',
},
anchorHip: true,
mirrorTracking: true,
},
};
@@ -80,6 +82,7 @@ export function VMCSettings() {
}
}
vmcOsc.anchorHip = values.vmc.anchorHip;
vmcOsc.mirrorTracking = values.vmc.mirrorTracking;
settings.vmcOsc = vmcOsc;
}
@@ -115,6 +118,7 @@ export function VMCSettings() {
}
formData.vmc.anchorHip = settings.vmcOsc.anchorHip;
formData.vmc.mirrorTracking = settings.vmcOsc.mirrorTracking;
}
reset(formData);
@@ -272,6 +276,23 @@ export function VMCSettings() {
label={l10n.getString('settings-osc-vmc-anchor_hip-label')}
/>
</div>
<Typography bold>
{l10n.getString('settings-osc-vmc-mirror_tracking')}
</Typography>
<div className="flex flex-col pb-2">
<Typography color="secondary">
{l10n.getString('settings-osc-vmc-mirror_tracking-description')}
</Typography>
</div>
<div className="grid grid-cols-2 gap-3 pb-5">
<CheckBox
variant="toggle"
outlined
control={control}
name="vmc.mirrorTracking"
label={l10n.getString('settings-osc-vmc-mirror_tracking-label')}
/>
</div>
</>
</SettingsPagePaneLayout>
</form>
@@ -281,6 +302,7 @@ export function VMCSettings() {
const gltfHeaderStart = 0;
const gltfHeaderEnd = 20;
async function parseVRMFile(vrm: File): Promise<string | null> {
const headerView = new DataView(
await vrm.slice(gltfHeaderStart, gltfHeaderEnd).arrayBuffer()

View File

@@ -131,7 +131,7 @@ export function VRCOSCSettings() {
<div className="flex flex-col pt-2 pb-4">
<>
{l10n
.getString('settings-osc-vrchat-description')
.getString('settings-osc-vrchat-description-v1')
.split('\n')
.map((line, i) => (
<Typography color="secondary" key={i}>
@@ -162,7 +162,7 @@ export function VRCOSCSettings() {
</Typography>
<div className="flex flex-col pb-2">
<Typography color="secondary">
{l10n.getString('settings-osc-vrchat-network-description')}
{l10n.getString('settings-osc-vrchat-network-description-v1')}
</Typography>
</div>
<div className="grid grid-cols-2 gap-3 pb-5">
@@ -199,7 +199,7 @@ export function VRCOSCSettings() {
<div className="flex flex-col pb-2">
<Typography color="secondary">
{l10n.getString(
'settings-osc-vrchat-network-address-description'
'settings-osc-vrchat-network-address-description-v1'
)}
</Typography>
</div>

View File

@@ -1,9 +1,7 @@
import classNames from 'classnames';
import { useForm } from 'react-hook-form';
import ReactModal from 'react-modal';
import { BodyPart } from 'solarxr-protocol';
import { Button } from '@/components/commons/Button';
import { CheckBox } from '@/components/commons/Checkbox';
import { Typography } from '@/components/commons/Typography';
import { BodyAssignment } from '@/components/onboarding/BodyAssignment';
import { useLocalization } from '@fluent/react';
@@ -11,6 +9,7 @@ import { NeckWarningModal } from '@/components/onboarding/NeckWarningModal';
import { useChokerWarning } from '@/hooks/choker-warning';
import { useBreakpoint } from '@/hooks/breakpoint';
import { defaultConfig, useConfig } from '@/hooks/config';
import { TrackerAssignOptions } from '@/components/onboarding/pages/trackers-assign/TrackerAssignOptions';
export function SingleTrackerBodyAssignmentMenu({
isOpen,
@@ -24,9 +23,6 @@ export function SingleTrackerBodyAssignmentMenu({
const { isMobile } = useBreakpoint('mobile');
const { l10n } = useLocalization();
const { config } = useConfig();
const defaultValues = { advanced: false };
const { control, watch } = useForm<{ advanced: boolean }>({ defaultValues });
const { advanced } = watch();
const { closeChokerWarning, tryOpenChokerWarning, shouldShowChokerWarn } =
useChokerWarning({
@@ -41,7 +37,7 @@ export function SingleTrackerBodyAssignmentMenu({
shouldCloseOnEsc
onRequestClose={onClose}
overlayClassName={classNames(
'fixed top-0 right-0 left-0 bottom-0 flex flex-col items-center w-full h-full justify-center bg-black bg-opacity-90 z-20'
'fixed top-0 right-0 left-0 bottom-0 flex flex-col items-center w-full h-full justify-center bg-background-90 bg-opacity-90 z-20'
)}
className={classNames(
'focus:ring-transparent focus:ring-offset-transparent focus:outline-transparent outline-none mt-12 z-10 overflow-y-auto'
@@ -56,14 +52,6 @@ export function SingleTrackerBodyAssignmentMenu({
<Typography color="secondary">
{l10n.getString('body_assignment_menu-description')}
</Typography>
<CheckBox
control={control}
label={l10n.getString(
'body_assignment_menu-show_advanced_locations'
)}
name="advanced"
variant="toggle"
></CheckBox>
<div className="flex">
<Button
variant="secondary"
@@ -73,13 +61,14 @@ export function SingleTrackerBodyAssignmentMenu({
{l10n.getString('body_assignment_menu-manage_trackers')}
</Button>
</div>
<TrackerAssignOptions variant={isMobile ? 'dropdown' : 'radio'} />
</div>
<div className="flex flex-col xs:flex-grow gap-3 rounded-xl fill-background-50 py-2">
<BodyAssignment
mirror={config?.mirrorView ?? defaultConfig.mirrorView}
width={isMobile ? 160 : undefined}
onlyAssigned={false}
advanced={advanced ?? defaultValues.advanced}
assignMode={config?.assignMode ?? defaultConfig.assignMode}
onRoleSelected={tryOpenChokerWarning}
></BodyAssignment>
<div className="flex justify-center">
@@ -98,7 +87,7 @@ export function SingleTrackerBodyAssignmentMenu({
<NeckWarningModal
isOpen={shouldShowChokerWarn}
overlayClassName={classNames(
'fixed top-0 right-0 left-0 bottom-0 flex flex-col items-center w-full h-full justify-center bg-black bg-opacity-90 z-20'
'fixed top-0 right-0 left-0 bottom-0 flex flex-col items-center w-full h-full justify-center bg-background-90 bg-opacity-90 z-20'
)}
onClose={() => closeChokerWarning(true)}
accept={() => closeChokerWarning(false)}

View File

@@ -29,7 +29,9 @@ function TrackerBig({
<BodyPartIcon bodyPart={tracker.info?.bodyPart}></BodyPartIcon>
</div>
<div className="flex justify-center">
<Typography bold>{trackerName}</Typography>
<Typography bold truncate>
{trackerName}
</Typography>
</div>
<div className="flex justify-center">
<TrackerStatus status={tracker.status}></TrackerStatus>
@@ -76,8 +78,10 @@ function TrackerSmol({
<div className="flex flex-col justify-center items-center fill-background-10">
<BodyPartIcon bodyPart={tracker.info?.bodyPart}></BodyPartIcon>
</div>
<div className="flex flex-col flex-grow">
<Typography bold>{trackerName}</Typography>
<div className="flex flex-col flex-grow ">
<Typography bold truncate>
{trackerName}
</Typography>
<TrackerStatus status={tracker.status}></TrackerStatus>
</div>
{device && device.hardwareStatus && (

View File

@@ -170,6 +170,7 @@ export function TrackerSettingsPage() {
></SingleTrackerBodyAssignmentMenu>
<MountingSelectionMenu
bodyPart={tracker?.tracker.info?.bodyPart}
currRotation={currRotation}
isOpen={selectRotation}
onClose={() => setSelectRotation(false)}
onDirectionSelected={onDirectionSelected}
@@ -307,7 +308,7 @@ export function TrackerSettingsPage() {
)}
</Typography>
<div className="flex justify-between bg-background-80 w-full p-3 rounded-lg">
<div className="flex gap-3 items-center">
<div className="flex gap-3 items-center fill-background-10">
{tracker?.tracker.info?.bodyPart !== BodyPart.NONE && (
<BodyPartIcon
bodyPart={tracker?.tracker.info?.bodyPart}

View File

@@ -110,7 +110,7 @@ export function ToggleableSkeletonVisualizerWidget(
</Button>
)}
{enabled && (
<>
<div className="flex flex-col gap-2">
<Button
className="w-full"
variant="secondary"
@@ -121,9 +121,8 @@ export function ToggleableSkeletonVisualizerWidget(
>
{l10n.getString('widget-skeleton_visualizer-hide')}
</Button>
<SkeletonVisualizerWidget {...props} />
</>
</div>
)}
</>
);
@@ -197,7 +196,7 @@ export function SkeletonVisualizerWidget({
if (!skeleton.current) return <></>;
return (
<div className="bg-background-70 flex flex-col p-3 rounded-lg gap-2">
<div className="bg-background-60 flex flex-col p-3 rounded-lg gap-2">
<ErrorBoundary
fallback={
<Typography color="primary" textAlign="text-center">

View File

@@ -24,9 +24,5 @@ export function useBreakpoint<K extends BreakpointKey>(breakpointKey: K) {
}
export function useIsTauri() {
if ('__TAURI_INTERNALS__' in window) {
return true;
} else {
return false;
}
return window.isTauri;
}

View File

@@ -13,6 +13,14 @@ export interface WindowConfig {
y: number;
}
export enum AssignMode {
LowerBody = 'lower-body',
Core = 'core',
EnhancedCore = 'enhanced-core',
FullBody = 'full-body',
All = 'all',
}
export interface Config {
debug: boolean;
lang: string;
@@ -25,10 +33,10 @@ export interface Config {
theme: string;
textSize: number;
fonts: string[];
advancedAssign: boolean;
useTray: boolean | null;
doneManualMounting: boolean;
mirrorView: boolean;
assignMode: AssignMode;
discordPresence: boolean;
}
export interface ConfigContext {
@@ -50,10 +58,10 @@ export const defaultConfig: Omit<Config, 'devSettings'> = {
theme: 'slime',
textSize: 12,
fonts: ['poppins'],
advancedAssign: false,
useTray: null,
doneManualMounting: false,
mirrorView: true,
assignMode: AssignMode.Core,
discordPresence: false,
};
interface CrossStorage {
@@ -103,8 +111,10 @@ export function useConfigProvider(): ConfigContext {
const newConfig: Partial<Config> = JSON.parse(
(await store.get('config.json')) ?? '{}'
);
return Object.entries(config).every(
([key, value]) => newConfig[key as keyof Config] === value
return Object.entries(config).every(([key, value]) =>
typeof value === 'object'
? JSON.stringify(newConfig[key as keyof Config]) === JSON.stringify(value)
: newConfig[key as keyof Config] === value
);
},
100,
@@ -116,8 +126,10 @@ export function useConfigProvider(): ConfigContext {
const newConfig: Partial<Config> = JSON.parse(
localStorage.getItem('config.json') ?? '{}'
);
return Object.entries(config).every(
([key, value]) => newConfig[key as keyof Config] === value
return Object.entries(config).every(([key, value]) =>
typeof value === 'object'
? JSON.stringify(newConfig[key as keyof Config]) === JSON.stringify(value)
: newConfig[key as keyof Config] === value
);
},
100,

View File

@@ -0,0 +1,71 @@
import { useCallback, useEffect } from 'react';
import { useConfig } from './config';
import { useInterval } from './timeout';
import { useTrackers } from './tracker';
import { invoke } from '@tauri-apps/api/core';
import { warn } from '@/utils/logging';
import { useLocalization } from '@fluent/react';
export function useDiscordPresence() {
const { config } = useConfig();
const { useConnectedIMUTrackers } = useTrackers();
const { l10n } = useLocalization();
const imuTrackers = useConnectedIMUTrackers();
const updatePresence = useCallback(() => {
(async () => {
try {
if (await checkDiscordClient()) {
// If discord client exists, try updating presence
await updateDiscordPresence({
details: l10n.getString(
'settings-general-interface-discord_presence-message',
{ amount: imuTrackers.length }
),
});
} else {
// else, try creating a discord client
await createDiscordClient();
}
} catch (e) {
warn(`failed to update presence, error: ${e}`);
}
})();
}, [imuTrackers.length, l10n]);
// Update presence every 6.9 seconds
useInterval(updatePresence, config?.discordPresence ? 6900 : null);
// Clear presence on config being disabled
useEffect(() => {
if (config?.discordPresence !== false) return;
(async () => {
if (!(await checkDiscordClient())) return;
clearDiscordPresence().catch((e) =>
warn(`failed to clear discord presence, error: ${e}`)
);
})();
}, [config?.discordPresence]);
}
export function checkDiscordClient(): Promise<boolean> {
return invoke('discord_client_exists');
}
export function createDiscordClient(): Promise<void> {
return invoke('create_discord_client');
}
export function clearDiscordPresence(): Promise<void> {
return invoke('clear_presence');
}
export function updateDiscordPresence(obj: {
details: string;
state?: string;
small_icon?: [string, string];
button?: { label: string; url: string };
}): Promise<void> {
return invoke('update_presence', obj);
}

View File

@@ -1,19 +1,24 @@
import { useMemo } from 'react';
import { FlatDeviceTracker } from './app';
import { ImuType } from 'solarxr-protocol';
export function useBnoExists(connectedTrackers: FlatDeviceTracker[]): boolean {
const bnoExists = useMemo(
() =>
connectedTrackers.some(
(tracker) =>
tracker.tracker.info?.imuType &&
[ImuType.BNO055, ImuType.BNO080, ImuType.BNO085].includes(
tracker.tracker.info?.imuType
)
),
export function useIsRestCalibrationTrackers(
connectedTrackers: FlatDeviceTracker[]
): boolean {
const imuExists = useMemo(
() => connectedTrackers.some((tracker) => tracker.tracker.info?.isImu),
[connectedTrackers]
);
return bnoExists;
return imuExists;
}
export function useRestCalibrationTrackers(
connectedTrackers: FlatDeviceTracker[]
): FlatDeviceTracker[] {
const restTrackers = useMemo(
() => connectedTrackers.filter((tracker) => tracker.tracker.info?.isImu),
[connectedTrackers]
);
return restTrackers;
}

View File

@@ -1,39 +1,5 @@
import { MutableRefObject, useLayoutEffect, useRef, useState } from 'react';
export function useLayout<T extends HTMLElement>() {
const [layoutHeight, setLayoutHeigt] = useState(window.innerHeight);
const [layoutWidth, setLayoutWidth] = useState(window.innerWidth);
const ref = useRef<T | null>(null);
const computeLayoutHeight = (windowHeight: number, windowWidth: number) => {
if (ref.current) {
setLayoutHeigt(windowHeight - ref.current.getBoundingClientRect().top);
setLayoutWidth(windowWidth - ref.current.getBoundingClientRect().left);
}
};
const onWindowResize = () => {
computeLayoutHeight(window.innerHeight, window.innerWidth);
};
useLayoutEffect(() => {
window.addEventListener('resize', onWindowResize);
// Fix a bug where the layout would not update when the window is unfocused then focused again
window.addEventListener('focus', onWindowResize);
computeLayoutHeight(window.innerHeight, window.innerWidth);
return () => {
window.removeEventListener('focus', onWindowResize);
window.removeEventListener('resize', onWindowResize);
};
}, []);
return {
layoutHeight,
layoutWidth,
ref,
};
}
export function useElemSize<T extends HTMLElement>(
forwardRef?: MutableRefObject<T | null>
) {

View File

@@ -11,6 +11,7 @@ import {
StatusSystemUpdateT,
StatusTrackerErrorT,
StatusTrackerResetT,
StatusUnassignedHMDT,
TrackerDataT,
} from 'solarxr-protocol';
import { useWebsocketAPI } from './websocket-api';
@@ -122,6 +123,7 @@ export function parseStatusToLocale(
switch (status.dataType) {
case StatusData.NONE:
case StatusData.StatusTrackerReset:
case StatusData.StatusUnassignedHMD:
return {};
case StatusData.StatusSteamVRDisconnected: {
const data = status.data as StatusSteamVRDisconnectedT;
@@ -157,8 +159,6 @@ export function parseStatusToLocale(
}
return { trackerName: name };
}
case StatusData.StatusUnassignedHMD:
return { trackerName: 'Not implemented.' }; // TODO
}
}
@@ -186,6 +186,13 @@ export function trackerStatusRelated(
data.trackerId?.deviceId?.id === tracker.trackerId?.deviceId?.id
);
}
case StatusData.StatusUnassignedHMD: {
const data = status.data as StatusUnassignedHMDT;
return (
data.trackerId?.trackerNum == tracker.trackerId?.trackerNum &&
data.trackerId?.deviceId?.id === tracker.trackerId?.deviceId?.id
);
}
default:
return false;
}

View File

@@ -1,17 +1,31 @@
import { useEffect } from 'react';
import { useEffect, useLayoutEffect, useRef } from 'react';
export function useTimeout(fn: () => void, delay: number | null) {
const saved = useRef(fn);
useLayoutEffect(() => {
saved.current = fn;
}, [fn]);
export function useTimeout(fn: () => void, delay: number) {
useEffect(() => {
const id = setTimeout(fn, delay);
if (delay === null) return;
const id = setTimeout(() => saved.current(), delay);
return () => clearTimeout(id);
});
}, [delay]);
}
export function useInterval(fn: () => void, delay: number) {
export function useInterval(fn: () => void, delay: number | null) {
const saved = useRef(fn);
useLayoutEffect(() => {
saved.current = fn;
}, [fn]);
useEffect(() => {
const id = setInterval(fn, delay);
if (delay === null) return;
const id = setInterval(() => saved.current(), delay);
return () => clearInterval(id);
});
}, [delay]);
}
export const useDebouncedEffect = (effect: () => void, deps: any[], delay: number) => {

View File

@@ -12,7 +12,7 @@ body {
background: theme('colors.background.20');
/*Scrollbar for firefox */
scrollbar-color: theme('colors.background.50') theme('colors.background.60');
scrollbar-color: theme('colors.background.50') transparent;
scrollbar-width: thin;
}
@@ -86,6 +86,15 @@ body {
:root {
overflow: hidden;
background: theme('colors.background.20');
--navbar-w: 101px;
--widget-w: 274px;
--topbar-h: 38px;
@screen mobile {
--topbar-h: 44px;
--navbar-h: 90px;
}
}
/* Colors have to be in RGB format currently */

View File

@@ -5,7 +5,7 @@ import * as ReactDOMClient from 'react-dom/client';
import Modal from 'react-modal';
import App from './App';
import { AppLocalizationProvider } from './i18n/config';
import './index.css';
import './index.scss';
Modal.setAppElement('#root');

View File

@@ -3,6 +3,12 @@ import { Vector3 } from 'three';
export type Vector3Object = { x: number; y: number; z: number };
export function averageVector(vecs: Vector3[]) {
if (vecs.length === 0) return new Vector3();
const sum = vecs.reduce((prev, curr) => prev.add(curr), new Vector3());
return sum.divideScalar(vecs.length);
}
export function Vector3FromVec3fT(vec?: Vector3Object | null) {
return vec ? new Vector3(vec.x, vec.y, vec.z) : new Vector3();
}

Some files were not shown because too many files have changed in this diff Show More