mirror of
https://github.com/SlimeVR/SlimeVR-Server.git
synced 2026-04-06 02:01:58 +02:00
Compare commits
82 Commits
motion-com
...
v0.13.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
439f60b89e | ||
|
|
21f4468c00 | ||
|
|
00f46f01b1 | ||
|
|
af8e6fc3f3 | ||
|
|
28d4199f12 | ||
|
|
0c309da528 | ||
|
|
3c765dbd8a | ||
|
|
eb9928ad08 | ||
|
|
90dcf986f8 | ||
|
|
eb602df452 | ||
|
|
e157fe7ed5 | ||
|
|
e3e48d3b0f | ||
|
|
018056b728 | ||
|
|
d1b21f2f17 | ||
|
|
8eeaa62760 | ||
|
|
564e99c52c | ||
|
|
b483699cf0 | ||
|
|
7cea1c7b47 | ||
|
|
7c96ee89c1 | ||
|
|
1c867efe16 | ||
|
|
2c146169ac | ||
|
|
5c0d3e9932 | ||
|
|
456485071b | ||
|
|
e2d268df2d | ||
|
|
2beb449171 | ||
|
|
49865f8e2e | ||
|
|
25f7d8fe95 | ||
|
|
62563ab1c2 | ||
|
|
9bec98f8f5 | ||
|
|
60f8db7079 | ||
|
|
b06f038777 | ||
|
|
1fba4e67ab | ||
|
|
1950a419a8 | ||
|
|
9238c7211b | ||
|
|
518fe8d2ef | ||
|
|
8b97c0eb27 | ||
|
|
9bf7f1fa5c | ||
|
|
4abd171efc | ||
|
|
af4f9a96bf | ||
|
|
58ca3fe8c1 | ||
|
|
0859abf08d | ||
|
|
b32e1cad50 | ||
|
|
c2566afa5e | ||
|
|
7a9a23c3d4 | ||
|
|
76b29c4af6 | ||
|
|
0be9b34320 | ||
|
|
0b01a4d67a | ||
|
|
c316313d2a | ||
|
|
d8695d3e88 | ||
|
|
6e942780de | ||
|
|
0d9f9289fb | ||
|
|
a6d0517a5b | ||
|
|
708135ff4c | ||
|
|
1f434e1c88 | ||
|
|
7ab8435595 | ||
|
|
94aec1f4ba | ||
|
|
6a268fbbad | ||
|
|
5ade5eb626 | ||
|
|
63384f40b5 | ||
|
|
d9da5544bb | ||
|
|
cfd9223390 | ||
|
|
a135ca3459 | ||
|
|
9bcccc6c36 | ||
|
|
00ef667c58 | ||
|
|
fbb0b8a460 | ||
|
|
6626cabeaa | ||
|
|
d23c92dec2 | ||
|
|
1356e7fbe6 | ||
|
|
ec2909406b | ||
|
|
37de960c1b | ||
|
|
638d4e3fb1 | ||
|
|
a6f377992d | ||
|
|
27386d5b29 | ||
|
|
d67acf6c28 | ||
|
|
4471aaaa49 | ||
|
|
a3faad4a72 | ||
|
|
4e4edc24da | ||
|
|
e64edb76dd | ||
|
|
721a74aacc | ||
|
|
775f5e9f30 | ||
|
|
6ca2eb6905 | ||
|
|
9808ea8709 |
8
.github/CODEOWNERS
vendored
8
.github/CODEOWNERS
vendored
@@ -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
8
.github/dependabot.yml
vendored
Normal file
@@ -0,0 +1,8 @@
|
||||
version: 2
|
||||
updates:
|
||||
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "/"
|
||||
schedule:
|
||||
# Check for updates to GitHub Actions every week
|
||||
interval: "weekly"
|
||||
12
.github/workflows/build-gui.yml
vendored
12
.github/workflows/build-gui.yml
vendored
@@ -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)
|
||||
|
||||
80
.github/workflows/gradle.yaml
vendored
80
.github/workflows/gradle.yaml
vendored
@@ -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
1
.gitignore
vendored
@@ -17,6 +17,7 @@
|
||||
|
||||
# VSCode stuff
|
||||
/.vscode/settings.json
|
||||
/.vscode/launch.json
|
||||
|
||||
# Ignore eclipse stuff
|
||||
.project
|
||||
|
||||
1515
Cargo.lock
generated
1515
Cargo.lock
generated
File diff suppressed because it is too large
Load Diff
@@ -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
242
deny.toml
Normal 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 = [""]
|
||||
@@ -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
47
flake.lock
generated
@@ -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": {
|
||||
|
||||
26
flake.nix
26
flake.nix
@@ -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"
|
||||
'';
|
||||
};
|
||||
};
|
||||
|
||||
@@ -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"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 =
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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, mikä 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
|
||||
|
||||
|
||||
@@ -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 l’activation 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 d’une 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 l’arrière et les avant-bras vers l’avant.
|
||||
@@ -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 à l’utiliser sans l’interface 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 l’envoi
|
||||
des données de suivi vers des applications sans SteamVR (par exemple, sur Quest).
|
||||
Assurez-vous d’activer 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 l’alignement 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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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 = 無視する
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
19
gui/scripts/gitversion.mjs
Executable 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
40
gui/scripts/license-list.mjs
Executable 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));
|
||||
@@ -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"
|
||||
|
||||
@@ -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") },
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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();
|
||||
|
||||
212
gui/src-tauri/src/presence.rs
Normal file
212
gui/src-tauri/src/presence.rs
Normal 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(())
|
||||
}
|
||||
@@ -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));
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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",
|
||||
|
||||
@@ -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());
|
||||
}, []);
|
||||
}
|
||||
|
||||
|
||||
22
gui/src/components/MainLayout.scss
Normal file
22
gui/src/components/MainLayout.scss
Normal 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%;
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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'));
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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'))}
|
||||
|
||||
@@ -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'));
|
||||
|
||||
@@ -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={
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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'
|
||||
)}
|
||||
|
||||
@@ -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()}
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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 || []
|
||||
|
||||
@@ -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'
|
||||
)}
|
||||
|
||||
@@ -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>
|
||||
}
|
||||
|
||||
11
gui/src/components/onboarding/OnboardingLayout.scss
Normal file
11
gui/src/components/onboarding/OnboardingLayout.scss
Normal 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;
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
26
gui/src/components/onboarding/pages/ConnectTracker.scss
Normal file
26
gui/src/components/onboarding/pages/ConnectTracker.scss
Normal 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%;
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
|
||||
@@ -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);
|
||||
}}
|
||||
|
||||
@@ -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'
|
||||
}
|
||||
|
||||
@@ -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'
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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)}
|
||||
|
||||
@@ -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}>
|
||||
|
||||
@@ -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>
|
||||
);
|
||||
}
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
));
|
||||
}
|
||||
@@ -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>
|
||||
|
||||
@@ -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>
|
||||
|
||||
25
gui/src/components/settings/SettingsLayout.scss
Normal file
25
gui/src/components/settings/SettingsLayout.scss
Normal 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%;
|
||||
}
|
||||
}
|
||||
@@ -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>
|
||||
</>
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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>
|
||||
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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>
|
||||
|
||||
@@ -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)}
|
||||
|
||||
@@ -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 && (
|
||||
|
||||
@@ -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}
|
||||
|
||||
@@ -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">
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
|
||||
71
gui/src/hooks/discord-presence.ts
Normal file
71
gui/src/hooks/discord-presence.ts
Normal 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);
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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>
|
||||
) {
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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) => {
|
||||
|
||||
@@ -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 */
|
||||
@@ -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');
|
||||
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user