Files
2026-09-27 16:54:35 +10:00

208 lines
9.3 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Chromium with WebXR for the Steam Frame
A build recipe and installer for **Chromium with immersive WebXR on Valve's
Steam Frame** headset. Press the
**Enter VR** button on a WebXR site and it opens in the headset, through
SteamVR, as a full VR experience.
The Chromium that SteamOS offers (Flathub) can't do this. Websites see
`navigator.xr`, but `isSessionSupported("immersive-vr")` returns `false`, so
VR buttons are greyed out or missing. Upstream Chromium only wires up its
OpenXR backend on Windows and Android. This repo builds Chromium with the
in-progress Linux OpenXR changes, adds a small fix so it works with SteamVR,
and installs it on the Frame as a normal app in your Steam library.
## What you can do with it
The web has a lot of VR content that only needs a browser:
- **360° and 3D video.** Travel, nature, concerts, sports and documentaries
from players that support WebXR, shown around you instead of in a flat
window.
- **Games and toys.** WebXR games and experiments made with
[three.js](https://threejs.org/examples/?q=webxr),
[A-Frame](https://aframe.io/) or [Babylon.js](https://www.babylonjs.com/),
with nothing to install.
- **Learning.** Virtual museum tours, space and anatomy explorers, and other
educational experiences built for the web.
- **Art and music.** Painting, sculpting and music toys that run in a page.
- **Building WebXR sites.** Test your own WebXR app on real headset hardware
from a normal URL, with Chromium's DevTools.
## Status
Tested on a Steam Frame (SteamOS 0.3.0, build 20260922.6101926,
SteamVR 2.17.10) with Chromium **156.0.8071.0**, built for arm64:
| | |
|---|---|
| `isSessionSupported("immersive-vr")` | `true` |
| [WebXR Samples](https://immersive-web.github.io/webxr-samples/) Immersive VR Session | shows its scene in the headset |
| three.js [stereo 360 video](https://threejs.org/examples/webxr_vr_video.html) | plays in 3D |
| Launch from the Steam library | opens as its own panel, like any app; WebXR renders in the headset |
| Controllers inside WebXR pages | tracked pose every frame; squeeze events and button state reach the page (trigger, thumbstick and left controller not tested) |
| Frame rate | 72 fps, every frame 13.9–14 ms over 16 s (simple scene); SteamVR dropped frames only at startup |
This is an unofficial, experimental build. See [Limitations](#limitations)
before you use it for anything other than VR sites.
## Requirements
- A Steam Frame with SteamVR, and a way to run commands on it: the terminal
in Desktop Mode, or SSH.
- To build: an **x86-64 Linux machine** with about **90 GB free disk**, git,
Python 3, tmux (or another way to keep a long job running) and a few
hours. No root access is needed. The first build took about 9.5 hours on
a 6-core, 12-thread desktop CPU; rebuilds take minutes.
## Build
On the Linux build machine:
```sh
git clone https://github.com/saphid/chromium-webxr-steam-frame
cd chromium-webxr-steam-frame
mkdir -p ~/chromium-xr
tmux new -d -s chromium-xr 'build/build.sh > ~/chromium-xr/build.log 2>&1'
```
`build.sh` fetches Chromium with the Linux OpenXR changes, applies the patch
in [`patches/`](patches), cross-compiles for arm64 and packs the result into
`~/chromium-xr/chromium-xr-arm64.tar.xz` (about 145 MB).
- Follow progress with `tail -F ~/chromium-xr/stage` (milestones) or
`tail -F ~/chromium-xr/build.log` (everything).
- If it stops (reboot, full disk, network), run the same command again. It
picks up where it left off.
- To build on another disk, set `CHROMIUM_XR_DIR` and use that directory
in place of `~/chromium-xr` in the commands above, including the log path.
- It stops itself if free disk space drops below 12 GB.
## Install on the Frame
Copy the tarball and this repo to the Frame, then run the installer there.
For example, over SSH from the build machine (replace `steamframe` with your
Frame's hostname or IP address):
```sh
scp ~/chromium-xr/chromium-xr-arm64.tar.xz steamos@steamframe:
ssh steamos@steamframe
git clone https://github.com/saphid/chromium-webxr-steam-frame
chromium-webxr-steam-frame/frame/install.sh ~/chromium-xr-arm64.tar.xz
```
The installer:
- unpacks the build into `~/chromium-xr`, after checking the new binary runs;
- installs the `chromium-xr` launcher in `~/.local/bin`;
- adds **Chromium XR** to the Desktop Mode app menu;
- adds **Chromium XR** to your Steam library, without restarting Steam.
Run it again with a newer tarball to update. Your profile
(`~/.config/chromium-xr`) and the Steam shortcut are kept. You can delete
the repo clone afterwards; the installer keeps what it needs to uninstall.
If the Steam shortcut can't be added automatically, add it by hand: in
Desktop Mode, open Steam, choose **Games → Add a Non-Steam Game to My
Library**, and pick Chromium XR.
## Use it
1. Open **Chromium XR** from your Steam library. It appears as a panel in
the headset.
2. Go to a WebXR site, for example the
[WebXR Samples](https://immersive-web.github.io/webxr-samples/).
3. Press the site's **Enter VR** button.
4. Chromium asks **Allow VR?** in the browser panel. Choose *Allow this time*
or *Allow while visiting the site*.
5. To leave VR, use the site's exit button or the Steam button.
The first time you launch it, Steam may show an **External Controller
Translation** notice. It's only information about controller button icons;
choose OK.
From a terminal on the Frame, `chromium-xr https://example.com` opens a
page directly.
## Limitations
- **Part of the sandbox is off.** The launcher passes
`--disable-seccomp-filter-sandbox`, which turns off Chrome's system-call
filter for every process; the namespace sandbox stays on. Without it,
SteamVR refuses the session (details in
[docs/technical-notes.md](docs/technical-notes.md)). Use Chromium XR for VR
sites and keep another browser for everyday browsing.
- **Saved passwords aren't encrypted.** The launcher uses
`--password-store=basic` so startup doesn't stop at a keyring prompt, so
passwords you save are stored unencrypted in `~/.config/chromium-xr`.
- **No automatic updates.** It won't get Chromium security fixes until you
rebuild it.
- **No controller vibration.** SteamVR reports no haptic actuators to the page.
- **No DRM video.** There's no Widevine, so paid streaming services that
need it won't play.
- **One window at a time per profile.** If Chromium XR is already open,
launching it again opens the page in the existing window.
- **Not a default browser.** It works as one (the desktop entry registers
for web links), but for the reasons above it's better kept for VR.
## Remove it
```sh
~/.local/share/chromium-xr/uninstall.sh # keeps your profile
~/.local/share/chromium-xr/uninstall.sh --remove-profile # also deletes settings and logins
```
This removes the build, the launcher, the menu entry and the Steam shortcut.
## Updating
The Chromium changes are still under review upstream, so this repo pins one
revision of them (`CL_REF` in [`build/build.sh`](build/build.sh), currently
patch set 44 of CL 8132979). To build a newer patch set, set `CL_REF` when
you run the build, for example
`CL_REF=refs/changes/79/8132979/45 build/build.sh`. The script fetches it,
syncs, re-applies the local patch and rebuilds. A newer patch set may need
the patch in [`patches/`](patches) updated. Then install the new tarball on
the Frame as above.
## How it works
- **Chromium changes.** [CL 8441736](https://chromium-review.googlesource.com/c/chromium/src/+/8441736)
(a sandboxed XR process on Linux) and
[CL 8132979](https://chromium-review.googlesource.com/c/chromium/src/+/8132979)
(the OpenXR device provider on Linux, patch set 44), tracked in Chromium
[issue 506004811](https://issues.chromium.org/issues/506004811). CL 8441736
has since merged; CL 8132979 is still in review. The OpenXR device is behind
`--enable-features=OpenXR`, which the launcher passes.
- **SteamVR fix.** SteamVR's OpenXR runtime asks the kernel who is on the
other end of its socket (`getsockopt(SO_PEERCRED)`). The XR sandbox policy
blocks all `getsockopt` calls, which crashed the XR process.
[`patches/0001-…`](patches/0001-xr-sandbox-allow-getsockopt-SO_PEERCRED.patch)
allows only that one option. It's reported upstream, with the seccomp
issue below, in
[utzcoz/chromium-webxr-linux#7](https://github.com/utzcoz/chromium-webxr-linux/issues/7).
- **Steam integration.** `frame/steam-shortcut.py` adds the shortcut through
the Steam client's local DevTools port, the same API the Steam UI uses.
Steam runs each app as its own panel, so Chromium gets one too.
More detail, including why the seccomp filter is off, is in
[docs/technical-notes.md](docs/technical-notes.md).
## Related work
- [utzcoz/chromium-webxr-linux](https://github.com/utzcoz/chromium-webxr-linux):
a fuller patch series for WebXR over OpenXR on Linux desktops, including
the in-headset permission UI and crash fixes, tested with
[Monado](https://monado.dev/). If you're on an x86-64 Linux PC rather than
the Steam Frame, start there.
- [Chromium issue 506004811](https://issues.chromium.org/issues/506004811):
upstream tracking for WebXR on Linux.
## License
The scripts in this repo are under the [BSD 3-Clause License](LICENSE). The
patch in [`patches/`](patches) modifies Chromium and is under
[Chromium's license](https://chromium.googlesource.com/chromium/src/+/main/LICENSE).
Chromium is a trademark of Google LLC; this project is not affiliated with
Google or Valve.