* Refactor HID subsystem to support zwlr_virtual_pointer_v1/zwp_virtual_keyboard_v1, and only use uinput as a fallback
* Add keymap support to HID providers and refactor related functionality
* Replace `expect` with `context` for improved error handling in wl_virtual.rs
* Run `cargo fmt`
* Replace hard panic with Err on failed seat binding
* add watch toggle setting
* previous commit broke monado workaround, this fixes it
* use active_state to toggle watch
* use the other monado workaround
* fix whitespace
* cargo fmt
the change in rotation is computed in the untransformed stage space. To produce the correct rotation change the quaternion needs to be rotated using the space offset
* add a toast for uinput errors
this makes it more obvious if missing uinput permissions are the reason your keyboard and mouse aren't working.
* uinput toaster part 2: the cargo formattening
* increase uinput error toast's timeout to 30 seconds
---------
Co-authored-by: galister <22305755+galister@users.noreply.github.com>
* start to integrate swipetype with keyboardstate
* successful debug implementation
* change to git dependency
* add manual trigger to app image build to test
* use latest swipeType lib to test including binaries
* use clipboard to paste swipe output
* use new prediction engine, move swipe type related logic to its own module
* update appimage bulid to support building ort runtime
* implement swipe selection ui in keyboard overlay
* only add motion data for the device that started the swipe
* process swipes on separate thread to not block ui
* add toggle to settings.rs
* default swipe to type config to false
* remove println, minor fix
* use correct key_dimensions
* use latest swipe_type library version
* optionally use wayvr compositor clipboard when pasting
* remove unused imports
* fix typo in log::error
* fix within key positioning
* run swipes on AltGr keycaps
Current implementation picks up the first available color format, which could be HDR (A2R10G10B10_UNORM_PACK32 in my case), but we don't have any color profiles. Stick back to SDR-only instead.
* fix: delete hand bindings from openxr_actions.json5
Presumably fixes handtracking causing laser offsets to tear off of controllers when hands switch to and from handtrack.
* Comment out fallback controller
* OscSend: support strings poc
- change value delimiter to `;`
- default convert values to String when not converted to another type
* add `_arg<n>="<value>"` format instead of `;` delimiter
that is, vrchat chatbox is controlled like `_press="::OscSend /chatbox/input" _arg0="${send}" _arg1="true" _arg2="true"` now
old format still supported as shorthand, with same "strings can't have spaces" limit as before. `_arg<n>` are appended after these.
* fix accidentally resetting `osc_args` to empty between formats
* update readme to document `::OscSend` paramter-form
* clean up, use `while let` instead of `while match`
* merge `parse_osc_value` into while condition
* remove second log from shortform arg parsing
* reimplement custom audio loading for `toast` and `key_click` using `from_mp3`
* run cargo fmt
* `try_bytes_from_config`: output with `log::trace` when file cannot be opened
* rewrite `try_bytes_from_config`
* use file `read_to_end`, log categories
* edit `register_wgui_samples`
* rework audio functions for loading custom wgui sounds
oh hey, it works!
* clean up
* allow custom `startup` and `app_start` sounds
these sounds are loaded on-demand and never registered; this behaviour is unchanged
* edit `bytes_from_config` outputs
* use return value of `read_to_end` instead of `len()` for reported file size
* implement suggested changes
- remove now-unused `register_mp3_sample_from_assets` function
- replace implementation of `try_bytes_from_config`
- missing the `real_path` context
* swap out `context`s for `inspect_err`s with closures to output `real_path`
* clean up `audio.rs`
- remove unused import
- unify capitalisation + quotes in output messages.
- Rename state -> wayland_state
- Move WayVR IPC server outside "wayvr" (wayland server) feature
- WayVR IPC server is now available without "wayvr" (wayland server) feature
- Remove run_compositor_at_start (run wayland server instantly)
This change is part of a new initiative in Envision to revamp the plugin
system. The new system is such that Envision will no longer install plugins on
its own, instead it will detect system provided plugin applications via
the X-XR-Plugin flag, and be instructed on a specific command to use
with the optional X-XR-Plugin-Exec.
This proposed specification is detailed in the following issue:
<https://gitlab.com/gabmus/envision/-/issues/250>
* add `lowestBattery` parameter to match the casing of other parameters
* add the following parameters:
`isEditModeActive`, `ToggleEditMode`, `currentWorkingSet`, `CurrentProfile`, and `totalWorkingSets`
* treat fully transparent overlays as "not visible"
this fixes the `isWristVisible` parameter; it was always True even when not looking at it since the watch is usually always "active", which was the only condition before.
there are a few gzip-compressed ttf as for now, looks like variable fonts aren't parsed properly by cosmic_text. Not sure why. Also, we probably need to have a fallback for CJK characters in the future, or just fallback to the built-in ones in the OS.
- use parking_lot for mutex (less restrictive and easier to use)
- simplify event callbacks and widget type casting
- defer component initialization at start (required for setting the initial state of sliders)
- fix non-working scroll events
- update testbed.xml
- replace slider with the real one in bar.xml
- show slider text on its handle
* Bring back using dpad for click modifiers
* Use system button for show_hide on WMR controllers
---------
Co-authored-by: hare_ware <3469405-hare_ware@users.noreply.gitlab.com>
Update openxrs to get the fix for a cmake error: "requires target
'jsoncpp_interface' that is not in any export set" [1], and update call
to create_space() to take an API change [2] into account.
[1] https://github.com/Ralith/openxrs/issues/148
[2] d8ea5553d5
* Converted tabs to spaces for consistency
* Added default space_reset binding as space_drag's double click variant for all controllers
* Fixed duplicate space_resets
* try adding config to load different sound
looks like include_bytes!() doesn't take a variable parameter, so will need a different solution lol.
* no errors in loading, but toast.rs now has a lifetime issue
* hey, config toast sound works now!
the sound is loaded in AppState now, since Toast are created in several different places at different times, and i don't want to load the sound every time a toast is made.
also put back the original sound since i accidentally commited my custom one.
* clean up
* change custom toast sound leak to happen on load rather than every play
* move toast sound loading into a function
so it can be reused in the future, for example if we want to load arbitrary keypress sounds or other [u8] data.
* remove label from try_load_bytes, return early when failing
* Switch to HiResScroll. Add horizontal scrolling
* Fix OpenVR compilation for horizontal scrolling
* fix OpenXR scroll using x axis for both scroll axes
* osc: start adding osc buttons
a button action that sends an osc parameter.
struggling with borrows in openxr.rs and openvr.rs when getting the osc sender.
* osc: fix osc sender buttons
by passing a ref to the device list to send_params instead of the entire app state.
* osc: fix warnings
* osc: conditionally use OscSender crate in state.rs
* osc: fix button.rs compile errors without osc/wayvr features
* osc: add other types: int, bool, string. play thump noise when sent.
* osc: fix build without osc feature
i just want to use OscType directly, but since it doesn't derive serde::Deserialize, i can't just have one OscType action or list of actions...
* merge typed actions to one action, support multiple values.
i added a new struct OscValue that has Deserialize, and now the action just converts that to the corresponding OscType when sending the parameters.
perhaps not the most elegant solution, but it's the best i can think of without modifying the rosc crate.
* run `cargo fmt`
* config: add use_passthrough
* do not use ALPHA_BLEND if passthrough is off
* keyboard.yaml auto_labels
* OSC: Finish XSOverlay parity (#124)
* osc-battery - utilise match return value to set parameter
this just lets parameter be a `&str` instead of a `String`, and reduces repetition.
* osc-battery - fix error where trackers were 1-indexed instead of 0-indexed
* osc-battery: xsoverlay parity! add average tracker and controller battery parameters.
this should now be in parity with xsoverlay's parameters.
gone back to 1-indexing trackers because it's more user-friendly, so other programs can standardise more easily.
* osc battery: ...that was not 1-indexed.
no idea how I made that mistake but the sent tracker parameters were actually still 0-indexed.
* Update Envision section (#123)
add directions for appimage autostart
* Add Flatpak instructions (#127)
* Add Flatpak instructions
fix small inconsistencies between instructions
* Clarify Flatpak Steam setup for SteamVR and Monado/WiVRn users
* Additional instructions
* default AltLayout is None
* WayVR: IPC [1]: Local socket server, handshake receiver
* WayVR : IPC [2]: `ListDisplays`, `GetDisplay` commands
* WayVR: IPC [3]: `ListProcesses`, `TerminateProcess` commands
* WayVR: IPC [4]: Minor refactoring
* WayVR: Move IPC to separate Git repository
* Restore default features in Cargo.toml
* WayVR: Implement `WvrDisplayCreate`, Implement `WvrProcessLaunch`, Refactoring
* WayVR: Dashboard toggle support, minor refactoring
* Update Cargo.toml
* fix formatting for openxr_actions.json5
---------
Co-authored-by: galister <22305755+galister@users.noreply.github.com>
Co-authored-by: Jay <157681441+cubee-cb@users.noreply.github.com>
Co-authored-by: Marcus Howser <mhowser.git@mailbox.org>
Co-authored-by: Joshua Vandaële <joshua@vandaele.software>
* osc-battery - utilise match return value to set parameter
this just lets parameter be a `&str` instead of a `String`, and reduces repetition.
* osc-battery - fix error where trackers were 1-indexed instead of 0-indexed
* osc-battery: xsoverlay parity! add average tracker and controller battery parameters.
this should now be in parity with xsoverlay's parameters.
gone back to 1-indexing trackers because it's more user-friendly, so other programs can standardise more easily.
* osc battery: ...that was not 1-indexed.
no idea how I made that mistake but the sent tracker parameters were actually still 0-indexed.
this means parameter can be immutable if left unset at initialisation, and we can use format!() macro in the match statements. silly workarounds no more!
i _understand_ now!
basically, i did it the "wrong" way first by modifying openxr.rs and openvr.rs to pass battery levels to osc, when really i could have just made osc get the pre-formatted device details from AppState. live and learn, i'm new to rust anyway.
- Support for foreign wayland clients, WayVR process is now separated into
managed and external one
- Add `run_compositor_at_start` global param
- Add `primary` display param
- Export WAYLAND_DISPLAY number into XDG_RUNTIME_DIR directory
- Bugfix: Redraw event is not triggered after despawning a process
- Sanitization in WayVRConfig::post_load()
A lightweight OpenXR/OpenVR overlay for Wayland and X11 desktops, inspired by XSOverlay.
# WayVR (previously WlxOverlay-S)
WlxOverlay-S allows you to access your desktop screens while in VR.
A lightweight OpenXR/OpenVR overlay for Wayland and X11 desktops.
In comparison to similar overlays, WlxOverlay-S aims to run alongside VR games and experiences while having as little performance impact as possible. The UI appearance and rendering techniques are kept as simple and efficient as possible, while still allowing a high degree of customizability.
WayVR lets you access your desktop screens while in VR, and even launch apps directly in VR.
This is the coming-together of two of my previous projects:
- [WlxOverlay](https://github.com/galister/WlxOverlay) (SteamVR overlay written in C#)
- [WlxOverlay-X](https://github.com/galister/wlx-overlay-x) (OpenXR overlay using StereoKit, written in Rust)
In comparison to similar overlays, WayVR aims to run alongside VR games and experiences while having as little performance impact as possible. The UI appearance and rendering techniques are kept as simple and efficient as possible, while still allowing a high degree of customizability.


# Join the Linux VR Community
## Join the Linux VR Community
We are available on either:
- Discord: https://discord.gg/gHwJ2vwSWV
- Matrix Space: `#linux-vr-adventures:matrix.org`
We are available on either **Discord** or **Matrix space**:
Questions/issues specific to WlxOverlay-S will be handled in the `wlxoverlay` chat room.
Questions/issues specific to WayVR will be handled in the `wayvr` chat room. Feel free to ask anything.
## Setup
### Installation
There are multiple ways to install WayVR:
1. AppImage: Download from [Releases](https://github.com/wayvr-org/wayvr/releases)
1. AUR package: [wayvr](https://aur.archlinux.org/packages/wayvr) or [wayvr-git](https://aur.archlinux.org/packages/wayvr-git)
1. Nix package: [wayvr](https://search.nixos.org/packages?channel=unstable&show=wayvr&query=wayvr) or [unstable package from nixpkgs-xr](https://github.com/nix-community/nixpkgs-xr)
1. [Docs: Building from source](https://wayvr.org/docs/basics/building-from-source/).
### General Setup
1. Grab the latest AppImage from [Releases](https://github.com/galister/wlx-overlay-s/releases).
1. `chmod +x WlxOverlay-S-*.AppImage`
1. Start Monado, WiVRn or SteamVR.
1. Run the overlay
AUR package is [wlx-overlay-s-git](https://aur.archlinux.org/packages/wlx-overlay-s-git).
**Note:** If you are using Monado or WiVRn, no additional setup steps are required for Flatpak Steam compatibility—most people use WayVR seamlessly with Monado/WiVRn.
You may also want to [build from source](https://github.com/galister/wlx-overlay-s/wiki/Building-from-Source).
### SteamVR via Steam Flatpak
# First Start
For users specifically running **SteamVR via Steam Flatpak**, follow these steps:
**If you get a screen share pop-up, check the terminal and select the screens in the order it tells you to.**
1. Grab the latest AppImage from [Releases](https://github.com/wayvr-org/wayvr/releases).
1. `WayVR-*.AppImage --appimage-extract`
1. `chmod +x squashfs-root/AppRun`
1. Move the newly created `squashfs-root` folder to a location accessible by the Steam Flatpak.
1. `flatpak run --command='/path/to/squashfs-root/AppRun' com.valvesoftware.Steam`
If you selected the screens in the wrong order:
- `rm ~/.config/wlxoverlay/conf.d/pw_tokens.yaml` then restart
## First Start
SteamVR users: WlxOverlay-S will register itself for auto-start, so you will not need to start it every time.
**When the screen share pop-up appears, check your notifications or the terminal and select the screens in the order it requests.**
In case screens were selected in the wrong order:
- Go to Settings and press `Clear PipeWire tokens` and then `Restart software`
- Pay attention to your notifications, which tell you in which order to pick the screens.
- If notifications don't show, try starting WayVR from the terminal and look for instructions in there.
**WiVRn users**: Select WayVR from the `Application` drop-down. If there's no such entry, select `Custom` and browse to your WayVR executable or AppImage.
**Envision users**: Go to the Plugins menu and select the WayVR plugin. This will download and run the AppImage version of the overlay.
To run a standalone installation (for instance, from the AUR), create a bash script containing `wayvr --openxr --show` and then set this bash script as a custom Envision plugin.
This will show a home environment with headset passthrough enabled by default or a [customizable background](https://wayvr.org/docs/various/openxr-skybox/)!
**SteamVR users**: WayVR will register itself for auto-start, so there is no need to start it every time. Disclaimer: SteamVR will sometimes disregard this and not start WayVR anyway.
**Please continue reading the guide below.**
# Getting Started
## Getting Started
### Working Set
Your working set consists of your currently selected overlays; screens, mirrors, keyboard, etc.
The working set consists of all currently selected overlays: screens, mirrors, keyboard, etc.
The working set appears in front of you when shown, and can be re-centered by hiding and showing again.
The working set appears in front of the headset when shown, and can be re-centered by hiding and showing again.
Show and hide your working set using:
- Non-vive controller: double-tap B or Y on your left controller.
- Vive controller: double-tap the menu button on your left controller (OpenXR, for SteamVR, you might need to bind `showhide` yourself.)
Show and hide the working set using:
- Non-vive controller: double-tap B or Y on the left controller.
- Vive controller: double-tap the menu button on the left controller (for SteamVR, the `showhide` binding must be bound)
Moving overlays: Grab + Joystick
Resizing overlays: Grab + Click + Joystick
### Pointer Modes AKA Laser Colors
Much of the functionality in WlxOverlay-S depends on what color of laser you are using to interact with a UI element. \
Much of the functionality in WayVR depends on what color of laser is used to interact with a UI element. \
Using the default settings, there are 3 modes:
- Regular Mode: Blue laser
- Right-click Mode: Orange laser
- Middle-click Mode: Purple laser
@ -66,70 +101,118 @@ Please see the bindings section below on how to activate these modes.
The guide here uses the colors for ease of getting started.
### The Watch
### Edit mode
Check your left wrist for the watch. The watch is your primary tool for controlling the app.
Ways to enter Edit mode:
- Edit mode button on Watch face
- Taskbar (top of keyboard) hamburger menu
- Edit mode button on the title bar of WayVR apps (next to X button)
Edit mode lets you grab overlays and reposition them in yourset.
### The Screens
It's also possible to change overlay behavior and tweak your overlays in different way.
Hovering a pointer over a screen will move the mouse. If there are more than one pointers hovering a screen, the pointer that was last used to click will take precedence.
While in edit mode, try hovering over various overlays to see their options!
### The watch
Check your left wrist for the watch. The watch is the primary tool for controlling the app.
The top of the watch shows device batteries, and the bottom shows your overlay controls.
While in edit mode, the watch can also be grabbed and passed between your hands.
After grabbing, the watch will automatically attach to the hand that's opposite from the one that held it.
### The screens
Hovering a pointer over a screen will move the mouse. If more than one pointer is hovering over a screen, the pointer that was last used to click will take precedence.
The click type depends on the laser color:
The click depends on the laser color:
- Blue laser: Left click
- Orange laser: Right click
- Purple laser: Middle click
- Stick up/down: Scroll wheel
To **curve a screen**, grab it with one hand. Then, using your other hand, hover the laser over the screen and use the scroll action.
See the [bindings](#default-bindings) section on how to grab, move and resize screens.
### The keyboard
The keyboard is fully customizable via the [keyboard.yaml](https://raw.githubusercontent.com/galister/wlx-overlay-s/main/src/res/keyboard.yaml) file. \
Download it into your `~/.config/wlxoverlay/` folder and edit it to your liking.
The keyboard sends keys to the screen or WayVR application with the most recent mouse interaction.
On top of the keyboard is the taskbar, which lists WayVR apps as well as screens, mirrors and panels overlays.
Typing
- Use the BLUE laser when typing regularly.
- While using ORANGE laser, all keystrokes will have SHIFT applied.
- Purple laser has no effect as of now.
**Modifier Keys** are sticky. They will remain pressed until you press a non-modifier key, or toggle them off.
- Use the BLUE laser when typing regularly.
- While using the ORANGE laser, all keystrokes will have SHIFT applied.
- Purple laser is customizable via the settings, no modifier by default.
**Modifier Keys are sticky**. They will remain pressed until either:
- a non-modifier key is pressed
- the modifier is toggled off by clicking again
- the keyboard is hidden (including via show-hide)
If your bindings are not supported, please reach out. \
We would like to work with you and include additional bindings.
### Changing Bindings
# Troubleshooting
- SteamVR: Simply change the bindings from the SteamVR bindings section.
- If WayVR doesn't show up on the list, select any other title and then press back on the top left. (SteamVR bug)
- Monado/WiVRn: See WayVR Dashboard → Settings → Controls.
Check [here](https://github.com/galister/wlx-overlay-s/wiki/Troubleshooting) for tips.
## Customization
# Known Issues
See these relevant wiki pages:
## Mouse is not where it should be
Hyprland users: Hyprland v0.41.0 changed their absolute input implementation to one that does not respect existing absolute input standards. Make your voice heard: [Hyprland#6023](https://github.com/hyprwm/Hyprland/issues/6023)・[Hyprland#6889](https://github.com/hyprwm/Hyprland/issues/6889)
- For all available config options, check [Docs: Configuration](https://wayvr.org/docs/basics/configuration/)
- Looking to customize look & feel, or add functionality? See [Docs: Customization](https://wayvr.org/docs/basics/customization/)
- Looking to change the OpenXR background? See [Docs: OpenXR Skybox](https://wayvr.org/docs/various/openxr-skybox/)
Niri users: use on Niri 0.1.7 or later.
## Troubleshooting
Other desktops: You may have selected the screens in the wrong order, see [First Start](#first-start).
When an error is detected, we often print tips for fixing it into the log file.
## Space-drag crashes SteamVR
Logs will be at `/tmp/wayvr.log` for most distros.
This has been idenfitied as an issue with SteamVR versions 2.5.5 and above (latest tested 2.7.2). One way to avoid the crash is by switching to the `temp-v1.27.5` branch of SteamVR (via beta selection) and selecting [Steam-Play-None](https://github.com/Scrumplex/Steam-Play-None) under the compatibility tab.
Check [here](https://wayvr.org/docs/various/troubleshooting/) for tips.
## Modifiers get stuck in weird ways
## Known Issues
This is a rare issue that can make your desktop not react to click or keys due to a modifier being stuck somewhere. Restarting the overlay fixes this.
### Mouse movement is wrong
## X11 limitations
- X11 capture can generally seem slow. This is because zero-copy GPU capture is not supported on the general X11 desktop. Consider trying Wayland or Picom.
**If the mouse is moving on a completely different screen**, the screens were likely selected in the wrong order:
- Go to Settings and press `Clear PipeWire tokens` and then `Restart software`
- Pay attention to your notifications, which tell you in which order to pick the screens.
- If notifications don't show, try starting WayVR from the terminal and look for instructions in there.
**If the mouse is on the correct screen but moves in weird ways**, enter Edit Mode, hover the screen and under Mouse Fixes, select the mode that works.
COSMIC desktop:
- Due to limitations with COSMIC, the mouse can only move on a single display.
X11 users:
- Might be dealing with a [Phantom Monitor](https://wiki.archlinux.org/title/Xrandr#Disabling_phantom_monitor).
- DPI scaling is not supported and will mess with the mouse.
- Upright screens are not supported and will mess with the mouse.
### Screens or launched apps don't work when auto-started by SteamVR or WiVRn
SteamVR starts WayVR in the Steam runtime, and systemd/flatpak WiVRn can also start WayVR in a sub-optimal environment.
The easiest fix is to start WayVR separately. It's possible to start WayVR before starting SteamVR/WiVRn by passing `--wait`:
- `wayvr --wait` or `/path/to/WayVR.AppImage --wait`
### X11 limitations
- X11 capture can generally seem slow. This is because zero-copy GPU capture is not supported on the general X11 desktop. Consider trying Wayland.
- DPI scaling is not supported and may cause the mouse to not follow the laser properly.
- Upright screens are not supported and can cause the mouse to act weirdly.
- Screen changes (connecting / disconnecting a display, resolution changes, etc) are not handled at runtime. Restart the overlay for these to take effect.
- Upright screens are not supported and can cause the mouse to not follow the laser properly.
- Screen changes (connecting/disconnecting a display, resolution changes, etc) are not handled at runtime. Restart the overlay for these to take effect.
<svgxmlns="http://www.w3.org/2000/svg"width="32"height="32"viewBox="0 0 24 24"><!-- Icon from Material Symbols by Google - https://github.com/google/material-design-icons/blob/master/LICENSE -->
<svgxmlns="http://www.w3.org/2000/svg"width="32"height="32"viewBox="0 0 24 24"><!-- Icon from Material Symbols by Google - https://github.com/google/material-design-icons/blob/master/LICENSE -->
<svgxmlns="http://www.w3.org/2000/svg"width="32"height="32"viewBox="0 0 24 24"><!-- Icon from Tabler Icons by Paweł Kuna - https://github.com/tabler/tabler-icons/blob/master/LICENSE -->
<svgxmlns="http://www.w3.org/2000/svg"width="32"height="32"viewBox="0 0 24 24"><!-- Icon from Material Symbols by Google - https://github.com/google/material-design-icons/blob/master/LICENSE --><pathfill="#33FF99"d="m9.55 18l-5.7-5.7l1.425-1.425L9.55 15.15l9.175-9.175L20.15 7.4z"/></svg>
<svgxmlns="http://www.w3.org/2000/svg"width="32"height="32"viewBox="0 0 24 24"><!-- Icon from Material Symbols by Google - https://github.com/google/material-design-icons/blob/master/LICENSE -->
<!-- Icon from Phosphor by Phosphor Icons - https://github.com/phosphor-icons/core/blob/main/LICENSE -->
<path
fill="currentColor"
d="m 223.99926,120.14002 v 90.93 c 0,46.2 -36.85,84.55 -83,85.06 a 83.7,83.7 0 0 1 -60.400003,-24.59 c -21.81,-23.07 -46.45,-79.4 -46.45,-79.4 a 16,16 0 0 1 6.53,-22.23 c 7.66,-4 17.1,-0.84 21.4,6.62 l 21,36.44 a 6.09,6.09 0 0 0 6,3.09 h 0.12 a 8.19,8.19 0 0 0 6.800001,-8.18 v -103.74 A 16,16 0 0 1 112.76926,88.140018 c 8.61,0.4 15.23,7.82 15.23,16.430002 v 63.57 a 8,8 0 0 0 8.53,8 8.17,8.17 0 0 0 7.47,-8.25 V 88.140018 a 16,16 0 0 1 16.77,-15.999999 c 8.61,0.4 15.23,7.82 15.23,16.429999 v 87.570002 a 8,8 0 0 0 8.53,8 8.17,8.17 0 0 0 7.47,-8.25 v -55.3 c 0,-8.61 6.62,-16 15.23,-16.43 a 16,16 0 0 1 16.77,15.98"
id="path1" />
<path
fill="currentColor"
d="M 263.19112,258.73409 V 112.03922 h 18.49095 v 130.25847 h 64.10196 v 16.4364 z"
<!-- Icon from Phosphor by Phosphor Icons - https://github.com/phosphor-icons/core/blob/main/LICENSE -->
<path
fill="currentColor"
d="M 30.079989,119.60999 V 210.54 c 0,46.2 36.85,84.55 83.000011,85.06 a 83.7,83.7 0 0 0 60.4,-24.59 c 21.81,-23.07 46.45,-79.4 46.45,-79.4 a 16,16 0 0 0 -6.53,-22.23 c -7.66,-4.00001 -17.1,-0.84 -21.4,6.62 l -21,36.44 a 6.09,6.09 0 0 1 -6,3.09 h -0.12 a 8.19,8.19 0 0 1 -6.8,-8.18 V 103.60999 a 16,16 0 0 0 -16.77,-16 c -8.61,0.4 -15.23,7.82 -15.23,16.43 V 167.61 a 8,8 0 0 1 -8.53,8 8.17,8.17 0 0 1 -7.47,-8.25 V 87.60999 A 16,16 0 0 0 93.309986,71.609992 c -8.609997,0.4 -15.229997,7.819999 -15.229997,16.429998 V 175.61 a 8,8 0 0 1 -8.53,8 8.17,8.17 0 0 1 -7.47,-8.25 v -55.30001 c 0,-8.61 -6.62,-16 -15.23,-16.43 a 16,16 0 0 0 -16.77,15.98"
id="path1" />
<path
d="m 301.74274,111.50919 q 27.32551,0 40.26918,10.4782 13.14912,10.27275 13.14912,31.22916 0,11.71094 -4.31456,19.51824 -4.31455,7.80729 -11.09457,12.53275 -6.57456,4.52001 -13.97094,7.19093 l 40.26918,65.7456 h -21.57277 l -35.54372,-60.60923 h -29.17461 v 60.60923 H 261.2681 V 111.50919 Z m -1.02728,16.02549 h -20.95641 v 54.44558 h 21.98369 q 17.87458,0 26.09278,-6.98547 8.2182,-7.19092 8.2182,-20.95642 0,-14.38185 -8.62911,-20.34004 -8.62911,-6.16365 -26.70915,-6.16365 z"
<svgxmlns="http://www.w3.org/2000/svg"width="32"height="32"viewBox="0 0 24 24"><!-- Icon from Material Design Icons by Pictogrammers - https://github.com/Templarian/MaterialDesign/blob/master/LICENSE -->
<svgxmlns="http://www.w3.org/2000/svg"width="32"height="32"viewBox="0 0 24 24"><!-- Icon from Material Symbols by Google - https://github.com/google/material-design-icons/blob/master/LICENSE -->
<svgxmlns="http://www.w3.org/2000/svg"width="32"height="32"viewBox="0 0 24 24"><!-- Icon from Material Symbols by Google - https://github.com/google/material-design-icons/blob/master/LICENSE -->
<svgxmlns="http://www.w3.org/2000/svg"width="32"height="32"viewBox="0 0 24 24"><!-- Icon from Material Symbols by Google - https://github.com/google/material-design-icons/blob/master/LICENSE -->
style="opacity:1;fill:url(#linearGradient5);stroke:url(#linearGradient3);stroke-width:109.387;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke fill markers"
id="rect1"
width="402.61319"
height="402.61276"
x="54.693188"
y="-457.30637"
transform="rotate(90)" /><path
style="opacity:1;fill:url(#linearGradient15);fill-opacity:1;stroke:#000000;stroke-width:25.2217;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke fill markers"
style="opacity:1;fill:url(#linearGradient20);fill-opacity:1;stroke:#000000;stroke-width:9;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke fill markers"
style="opacity:1;fill:url(#linearGradient18);fill-opacity:1;stroke:#000000;stroke-width:9;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke fill markers"
style="opacity:1;fill:url(#linearGradient22);fill-opacity:1;stroke:#000000;stroke-width:9;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-opacity:1;paint-order:stroke fill markers"
style="fill:none;stroke:#ffffff;stroke-width:14.99999998;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:stroke fill markers"
style="fill:none;stroke:#ffffff;stroke-width:14.99999998;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:stroke fill markers"
d="m 188.46876,110.26038 -5.21956,9.63246 -22.58647,-0.33215 c -6.90616,-0.0316 -7.30738,-7.07013 -13.85556,-7.07013 l -25.10134,0.80665 c -4.79251,0.18981 -5.81439,7.39991 -11.05598,7.96931 l -18.885326,1.4259 -12.960463,-22.50447 C 76.839174,95.928995 77.695768,91.866643 80.139132,87.863715 L 95.797837,62.429456 c 2.039918,-2.678813 4.159493,-5.023837 8.321053,-5.435523 l 74.41968,-3.237827 c 5.0906,-0.295214 8.73208,1.737803 11.00526,5.250985 l 11.20838,18.604622 -0.009,-0.01397"
id="path18-6" /><path
style="fill:none;stroke:#ffffff;stroke-width:14.99999998;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:stroke fill markers"
d="m 134.47003,55.383809 c 4.67387,-5.765243 7.35483,-13.381057 7.35483,-13.381057 0,0 3.55879,6.714253 4.17565,12.147342"
id="path42-8" /><path
style="fill:none;stroke:#ffffff;stroke-width:14.99999998;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:stroke fill markers"
style="fill:none;stroke:#ffffff;stroke-width:14.99999998;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:stroke fill markers"
d="m 200.75221,77.611713 c 9.05609,7.170997 12.00082,10.65054 15.89737,19.107608"
id="path44-5" /><path
style="fill:none;stroke:#ffffff;stroke-width:14.99999998;stroke-linecap:round;stroke-linejoin:round;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;paint-order:stroke fill markers"
d="m 211.10506,148.90717 c 18.09388,-17.60049 9.68681,-45.03368 5.54452,-52.187849 -5.07761,-8.122981 -5.86539,-15.251314 -17.01296,-19.574554 l -10.98381,32.405743 v 0 c 10.01156,2.93429 24.20554,12.33526 29.85215,19.21559"
id="path45-0" /></g></g><metadata
id="metadata1"><rdf:RDF><cc:Work
rdf:about=""><dc:title>WiVRn Wyvern yippe</dc:title><dc:date>1/25/25</dc:date><dc:creator><cc:Agent><dc:title>Yaya, y.a.y.a on Discord.</dc:title></cc:Agent></dc:creator><cc:license