Skip to content
 
 

Repository files navigation

UxSpace

Your space. Any screen.

A head-tracked spatial desktop and 360° cinema for XR glasses, driven from an Android phone — with no vendor SDK anywhere in the build.

Android CI Licence Driver SBOM Android


What it does

Put the glasses on and your phone stops being something you look at. It becomes the machine driving a workspace that hangs in the room around you.

Windows that stay put. Up to three Android apps on virtual displays. They hold their position as you turn your head, so if you look left, the left screen is where you left it. The phone's trackpad drives a cursor across all three.

A cinema with no walls. A 360° or VR180 video wraps the whole sphere instead of sitting in a rectangle. Stereoscopic footage gets the right eye into the right eye. Ordinary films play on a flat screen in front of you, at whatever size you want.

Both eyes, done properly. Software switches the glasses into their 3840×1080 side-by-side mode, and the renderer draws each eye separately using your interpupillary distance. Not the adult average. Yours.

The phone can go dark. The workspace belongs to the glasses' display, not to a window borrowed from the phone. Lock the phone and put it away; the glasses keep going. Pick it up again and it becomes the remote: seek, pause, 2D or 3D, recentre, zoom.

It works out what it is looking at. The st3d and sv3d boxes in the file decide whether it is mono, over-under, side-by-side, anaglyph or row-interleaved, and whether the picture is equirectangular, a hemisphere, a cube map or flat. No naming conventions. No menu to get wrong.


What this fork adds

Upstream darkclad/uxspace is good work, and it is the foundation for everything here: a vendor-agnostic spatial desktop with a Windows side and an Android side. It also needs VITURE's proprietary SDK. Without that SDK the Android app will not compile at all.

Twenty-nine commits separate upstream from this fork.

An open driver The 174 MB vendor SDK is gone. In its place, viture-v2: an MIT-licensed Rust implementation of the Gen2 wire protocol that Gradle builds from source. No account, no blobs, and CI fails the build if a vendor binary shows up again.
360°, VR180 and more Equirectangular spheres and hemispheres, cube maps, equi bounds, and mesh projections drawn from the geometry stored in the file.
Five frame packings Mono, over-under, side-by-side, anaglyph in three colour pairs, row-interleaved. Each one is read out of the container, not guessed from the filename.
Stereo for the desktop too Not just for video. The workspace itself renders per eye.
Head-motion prediction The lookahead comes from the display's own presentation deadline and the pose rate we measured, so it fits the hardware it is running on.
A workspace that owns its display It launches as an activity onto the glasses instead of a Presentation borrowed from the phone. That one change is what lets the phone sleep without taking the workspace down with it.
The whole panel The renderer reads the panel's actual mode and the glasses' real optics. Earlier versions assumed 16:9 and a nominal field of view, and lost several degrees of picture doing it.
A player that takes a URL Streams play at whatever the glasses can show, with track selection aimed at the panel. Kodi libraries work as a media source.
It measures itself One command collects pose rate, frame timing, prediction lookahead, field of view, format detection and stereo disparity from real hardware. Each figure is printed beside what the simulator claimed, so a mismatch turns into a finding instead of a surprise.
A simulator in the driver Good enough to develop against with nothing plugged in, and it injects faults: failing cables, load spikes, poor signal. Two concurrency bugs turned up that way and no other.

Released as a signed APK with a CycloneDX 1.6 and SPDX 2.3 bill of materials, in German and English, with lint set to fail the build.


The glasses this is tuned for

VITURE Pro 2 XR is the reference, and the only hardware this fork is tested on.

Panel 1920×1080 per eye, 60 Hz over USB-C DisplayPort
Field of view 50° diagonal — about 44° across and 26° down, which is what the panorama's default view angle is set to so the image is life-size
Tracking 3DOF, pose at 120 Hz over vendor-defined USB HID
3D 3840×1080 side-by-side, switched from software

Its Gen2 relatives — the VITURE Pro XR, VITURE One and siblings that speak protocol V2 — use the same driver and should work; they differ mainly in field of view. The driver accepts any VITURE product id rather than an allow-list, so a new model does not need a code change to be tried.

Not supported here: Carina and Luma Ultra. Their 6DOF comes from VIO running inside the proprietary SDK, which this fork does not ship. The entry points remain so the code still links, and report that they are unavailable.

Upstream's vendor-agnostic layering is intact, so another vendor is still one provider away — but nothing besides VITURE Gen2 has been written or tested here.


What you need

  • A Pixel 9 or comparable Android phone with USB-C DisplayPort alt mode. Android 13 or newer.
  • The glasses on the phone's USB-C port.
  • Wireless charging if you want to run for long: the phone's only USB-C port is taken by the glasses. A USB-C hub with DisplayPort alt mode and Power Delivery pass-through works too, but a plain data hub does not — the video needs alt mode.
  • ADB wireless debugging enabled once, so UxSpace can start its own shell-uid helper. That helper is what creates trusted virtual displays for the workspace; see Android/docs/PRIVILEGE.md.
git clone --recurse-submodules https://github.com/elasticjava/uxspace.git
cd uxspace/Android
./gradlew installDebug

The Rust driver is built for aarch64-linux-android as part of that. You need a Rust toolchain with that target and the Android NDK; everything else Gradle fetches.


Repository layout

UxSpace/
├── Android/                  the app — see Android/README.md
│   └── glasses/viture-v2/    the open driver, as a submodule
├── Windows/                  the Windows app and its IddCx display driver
└── tools/                    the holodeck panorama renderer

The Windows side is upstream's and is untouched by this fork; it still expects the proprietary SDK.

Both projects were merged in with their full upstream histories preserved via git subtree, so the original commits are reachable as ancestors.




Related work

Three projects have solved a version of this problem. Comparing them is more useful than ranking them, because they made different trade-offs and the trade-offs are the interesting part.

By Wayne Heaney. This is the most complete open XR glasses support that exists. XRLinuxDriver (C/C++, GPL-3.0) covers VITURE, XREAL and Rokid across a dozen models. Breezy Desktop builds a virtual workspace on top of it for GNOME 45+ and KDE Plasma 6, and decky-XRGaming does the same for the Steam Deck. Years of field reports across hardware nobody here owns.

For VITURE it goes through the vendor SDK. lib/aarch64/viture/ holds libcarina_vio.so at 40.8 MB, libglasses.so, and 27 OpenCV shared objects, all committed to the repository and repeated for x86_64. They ship as -libs- tarballs with each release. That is also what buys the 6DOF: Carina is VITURE's visual-inertial odometry, and it does something we cannot do at all.

There is a paid Supporter Tier as well, verified against a backend using license_public_key.pem. That backend receives the user's email address and a hashed MAC address.

By Michael Gschwandtner. C, MIT, and a genuinely different idea: an OrangePi with an HDMI input turns the glasses into a monitor for anything with a video output. A console, a laptop, a camera. It was discussed on Hacker News in June 2025.

This one bundles the vendor SDK too, and run_viture_sdk.sh says so outright: "Sets LD_LIBRARY_PATH to include the bundled SDK libs so that all transitive OpenCV/Carina dependencies are resolved from the 3rdparty tree." It also needs hardware you have to buy and wire up.

Where this project sits

XRLinuxDriver / Breezy viture_virtual_display UxSpace (this fork)
Vendor SDK bundled, ~65 MB per arch bundled none
Driver C/C++ plus proprietary blobs C plus proprietary blobs Rust, 627 KB, ours
Platform Linux, GNOME 45+ / KDE 6 OrangePi with HDMI capture Android 11+
Extra hardware no yes no
Devices VITURE, XREAL, Rokid, a dozen models VITURE Pro XR VITURE Gen2, tested on Pro 2
Tracking 3DOF plus 6DOF via Carina n/a 3DOF
Telemetry email and hashed MAC for the paid tier none none
Licence GPL-3.0 MIT Apache-2.0 / MIT
SBOM none none CycloneDX 1.6 and SPDX 2.3

Where they are ahead. Device coverage is not close: a dozen models across three vendors against one tested pair of glasses. 6DOF positional tracking is a real capability we do not have, and we cannot add it without the SDK we removed. Breezy integrates with two desktop environments properly, instead of putting apps on virtual displays inside a single app. And 748 stars mean years of problems found by people, not by a test harness.

Where this one differs. The vendor SDK is not vendored, wrapped or bundled here. It is gone. A Rust driver built from source in the normal build replaces it, and CI fails if a vendor binary reappears. That is not a matter of taste. libcarina_vio.so exists for x86_64 and aarch64 because VITURE compiled it for x86_64 and aarch64, so anything built on it runs where they decided and nowhere else. A 627 KB Rust driver with no C dependencies cross-compiles to a new target in one line. Nothing here talks to a backend, checks an entitlement, or has anything to send. All 61 shipped components are inventoried in two standard formats with their licences traced back to source. And the only hardware you need is the phone in your pocket.

Which one to use. For a desktop on Linux, use Breezy Desktop. The UxSpace app is Android-only and that is the whole answer. For 6DOF, or for XREAL and Rokid glasses, use XRLinuxDriver. For a monitor fed from an HDMI source, use viture_virtual_display. For a spatial desktop on an Android phone with no proprietary code in it, this is the only one of the four that qualifies.

The driver is a separate question. viture-v2 is not Android software. It talks to /dev/hidraw, the same kernel interface XRLinuxDriver uses, and it builds for an ordinary Linux desktop today:

git clone https://github.com/elasticjava/viture-v2 && cd viture-v2
cargo build --release --features render,sim
./target/release/viture-v2 probe        # also: info, pose, raw, pointer

Eleven seconds, 601 KB, no vendor blobs and no SDK to request. For VITURE Gen2 that covers what the 40.8 MB Carina path covers, minus 6DOF. So if you are building for these glasses on Linux and would rather not vendor a proprietary binary, you no longer have to.

On the hardware itself


Take it further

This is a starting point, not a finished product. It is licensed so you can do what you like with it: Apache-2.0 for the app, MIT for the driver. Fork it, gut it, build something else out of it. There is no CLA, no permission to ask for, and no attribution wanted beyond what the licences already require.

Issues are open, discussions are open, and pull requests are welcome. So are bug reports from people who cannot fix them. A clear account of something going wrong on hardware nobody here owns is worth more than most patches.

A few things are genuinely open, roughly in order of how much they would matter.

6DOF without the SDK. This is the one capability we gave up by dropping the vendor blob. The IMU delivers 118.9 poses a second and the glasses have no camera, so it means fusing visual odometry from the phone with rotation from the glasses. Hard, well defined, and nobody has done it in the open for this hardware. It would close the last real gap against the proprietary path.

Other vendors. The driver is built around a wire protocol, not around VITURE. XREAL and Rokid speak their own, and others have documented both. Someone with the hardware and a free weekend could turn this into a driver for three vendors instead of one.

A Linux desktop on top of it. The driver already builds and runs there, as above. What is missing is everything that sits above it, and Breezy Desktop shows what that looks like when it is done well.

Newer VITURE models. Beast and Luma Ultra are untested here. The driver accepts any VITURE product id instead of an allow-list, exactly so that trying a new model needs no code change. It may simply work. Nobody has looked.

The measurement harness. It reads pose rate, frame timing, field of view, format detection and stereo disparity off real hardware and prints each figure next to what the simulator claimed. It was built for the Pro 2. Point it at other glasses and you would have the comparison table this whole area is missing.

Whatever else you want. Ports, bindings, a different renderer, a use nobody here thought of. If the protocol gets in your way, PROTOCOL.md has what we worked out, and an issue asking a question is fine. A question costs both of us less than a wrong assumption.

CONTRIBUTING.md covers how to build and what counts as verified, if you want to send something back. You are under no obligation to.


Acknowledgements

Almost nothing that makes this work was invented here, and the parts that were only exist because of the parts that were not.

Demian Vladi wrote UxSpace, which this is a fork of. The spatial desktop, the vendor-agnostic layering that made swapping out the driver a contained change, the Windows side with its IddCx display driver: all his. Replacing one dependency in someone else's well-built project is a much smaller job than building the project, and the layering he designed is the reason it was possible at all.

Muntashir Al-Islam wrote libadb-android, spake2-java and sun-security-android. Between them they are why an ordinary app can hold shell privileges at all. He also dual-licensed libadb-android so that projects like this one would not be forced into copyleft, which is a deliberate kindness and easy to miss.

Rikka and the Shizuku project established the technique everything here rests on: bootstrap a shell-uid helper over wireless debugging, and type the pairing code into a notification while the dialog is still open. That last detail is not obvious, and someone had to work it out first.

Wayne Heaney and Michael Gschwandtner each built working XR glasses support and published all of it, years before this existed. Both chose to bundle the vendor SDK and this project chose not to. That is a difference in what we were each willing to trade, not in the quality of the work. Knowing someone else had already made the hardware behave was worth a lot on the evenings when it would not.

The Android team at Google, for AndroidX, for Media3/ExoPlayer, which parses the spatial video metadata this depends on and which MediaPlayer never exposed, for Conscrypt, and for publishing the Spherical Video V2 specification openly so a 360° file can say what it is instead of being guessed at.

JetBrains, for Kotlin and kotlinx.coroutines.

Cameron Hart for glam, whose SIMD quaternion and projection maths runs in the driver's render path. Frommi and oyvindln for miniz_oxide, which inflates mesh projections without a C dependency and keeps cross-compiling to one line.

The Legion of the Bouncy Castle, for the cryptography under the pairing handshake.

Ragnar di Marzo filmed The Motorist revisited and released it CC BY-ND. Real stereoscopic 360° footage with correct st3d and sv3d boxes is genuinely hard to find. Generated test material proves the maths and proves nothing about the world.

OWASP CycloneDX and SPDX, for inventory formats that made two licence obligations visible which a hand-written list had missed.

VITURE, for building glasses worth this much effort. This project is not affiliated with VITURE, endorsed by them, or supported by them. The protocol was worked out by watching our own hardware, and the name appears here only to say what it is compatible with.

And everyone whose work ships inside the APK without being named above. THIRD-PARTY-NOTICES.md lists all 61 components and the terms they arrive under.


Licence

The Android project is Apache-2.0 (LICENSE). The Windows driver/ is a fork of Microsoft's IddSampleDriver and keeps its MIT licence (Windows/driver/UPSTREAM_LICENSE). The viture-v2 driver is MIT.

One shipped component carries an obligation: spake2-android is LGPL-3.0 and is included as a separate shared library, with source and licence linked in THIRD-PARTY-NOTICES.md. It does not restrict use or redistribution of UxSpace.

Security issues: please see SECURITY.md.

About

Head-tracked spatial desktop and 360°/VR180 cinema for VITURE XR glasses, driven from an Android phone — with the vendor SDK replaced by an open Rust driver.

Topics

Resources

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages