1
0
Aiden fbdb733f13
All checks were successful
Test / test (push) Successful in 9m33s
Updates
2026-06-11 05:48:19 +10:00
2026-06-10 11:58:18 +10:00
2026-06-11 05:27:20 +10:00
2026-06-11 05:48:19 +10:00
2026-06-11 05:48:19 +10:00
2026-06-11 05:48:19 +10:00
2026-06-10 16:17:08 +10:00
2026-02-19 11:13:56 -06:00
2026-06-11 05:27:20 +10:00
2026-06-10 14:29:23 +10:00
2025-06-04 16:22:25 -05:00
2026-06-10 11:03:43 +10:00
2026-06-11 05:48:19 +10:00
2026-06-10 16:17:08 +10:00
2026-06-10 10:35:14 +10:00

VR Web Player

A CDN-friendly web player for side-by-side stereoscopic video and still images.

The player supports two projection modes:

  • vr180: an immersive 180 degree stereoscopic hemisphere in WebXR, with a draggable rectilinear fallback on non-XR browsers.
  • plane: a flat stereoscopic media plane in WebXR, with a normal flat left-eye fallback on non-XR browsers.

How to use it

Build the player first, then host the generated vr180player/ directory on your CDN and include the module script. The script automatically loads its matching CSS file from the same folder, and it imports its helper modules with relative module paths.

<div data-vr-web-player data-projection="vr180">
	<video poster="poster.jpg" title="Demo Video" crossorigin="anonymous" playsinline preload="metadata">
		<source src="sbs-video.mp4" type="video/mp4">
	</video>
</div>

<script type="module" src="https://cdn.example.com/vr180player/vr180-player.js"></script>

Use data-projection="plane" for flat 3D video on a rectangular plane:

<div data-vr-web-player data-projection="plane">
	<video poster="poster.jpg" title="Demo Video" crossorigin="anonymous" playsinline preload="metadata">
		<source src="sbs-video.mp4" type="video/mp4">
	</video>
</div>

Use data-head-lock="auto|position|none" to control positional comfort in immersive mode. It defaults to auto, which position-locks vr180 media to the headset to avoid false 6DoF parallax, while leaving plane media fixed like a screen. Use position to force locking for either projection, or none to keep all media world-fixed.

Use an img element for a static SBS image:

<div data-vr-web-player data-projection="plane">
	<img src="sbs-image.png" alt="Demo image" title="Demo Image" crossorigin="anonymous">
</div>

Add data-carousel to an image player when you want previous/next controls for multiple SBS still images in one immersive session:

<div data-vr-web-player data-projection="vr180" data-carousel>
	<img src="first-sbs-image.png" alt="First image" title="First Image" crossorigin="anonymous">
	<img src="second-sbs-image.png" alt="Second image" title="Second Image" crossorigin="anonymous">
</div>

Only one player is supported per page in this version. The player logs a clear console message and does not initialize if no [data-vr-web-player] container is found, if multiple containers are found, if the container does not contain exactly one supported video/image element, if an image carousel does not contain at least two images and no videos, or if data-projection is not vr180 or plane.

Media format

This version supports side-by-side media only:

  • Video: 2:1 side-by-side video using H.264 or HEVC in an mp4 file.
  • Image: side-by-side still images in browser-supported image formats such as PNG, JPEG, or WebP.

It does not support over-under, MV-HEVC, APMP, or .aivu.

How it works

When the page loads, the media is embedded normally with an entry button over it. When the user clicks the button, the player checks for navigator.xr and immersive-vr support.

  • In WebXR, vr180 maps the left and right halves of the SBS media onto the matching eyes of a 180 degree sphere. In the default auto head-lock mode, the sphere follows headset position but not headset rotation.
  • In WebXR, plane maps the left and right halves onto the matching eyes of a floating 16:9 plane.
  • Outside WebXR, both modes render only the left half of the SBS media so viewers do not see the raw double image.
  • Video controls include a loop toggle for indefinite replay.
  • Static images show only applicable controls; playback, seek, and mute controls are video-only.
  • Image carousels replace skip buttons with previous/next image controls, so you can change stills without leaving the immersive session.
  • Controller pointers and lightweight hand/controller overlays appear after controller interaction, then fade away after a short idle period so they do not distract from viewing.
  • Control icons are embedded from Lucide SVG definitions, so no PNG icon assets are required.

Demo

Run npm run build, then open test-pages/index.html through a local web server. The test hub links to focused pages for flat 3D image, VR180 3D image, image carousels, flat 3D video, and VR180 3D video. The root index.html redirects there for convenience.

For local experimentation, run:

npm run dev

This builds the TypeScript player once, then serves index.html with Vite at a local URL.

For headset testing, the page must be a secure context before the browser will expose immersive WebXR. A LAN URL such as http://192.168.x.x:5173/ is useful for checking layout and media loading, but it will usually not show the headset's immersive VR prompt. Use an HTTPS URL with a trusted certificate, a trusted tunnel, or a deployed CDN/Pages URL for immersive testing.

Development

The player source is TypeScript in src/vr180player/. Generated JavaScript files in vr180player/ are ignored by git so CI/CD can build and publish them from source.

npm install
npm run dev
npm run build

Edit the TypeScript source files rather than generated JavaScript. A typical CI/CD publish step should run npm ci, npm run build, then publish vr180player/ with its generated .js files and CSS.

Description
No description provided
Readme Unlicense 246 MiB
Languages
TypeScript 68.7%
JavaScript 23%
CSS 6.2%
HTML 2.1%