1
0

status banner
All checks were successful
Test / test (push) Successful in 9m26s

This commit is contained in:
Aiden
2026-06-10 12:56:57 +10:00
parent 8402fcd640
commit 0879f1685a
8 changed files with 74 additions and 0 deletions

View File

@@ -67,6 +67,8 @@ npm run dev
This builds the TypeScript player once, then serves `index.html` with Vite at a local URL. 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 ## 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. 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.

31
demo-xr-status.js Normal file
View File

@@ -0,0 +1,31 @@
const statusElement = document.querySelector('[data-demo-xr-status]');
if (statusElement) {
updateXrStatus(statusElement);
}
async function updateXrStatus(element) {
if (!window.isSecureContext) {
element.textContent = 'Immersive WebXR is blocked on this origin. Use HTTPS, a trusted tunnel, or a deployed CDN URL for headset testing.';
element.dataset.state = 'blocked';
return;
}
if (!navigator.xr) {
element.textContent = 'Immersive WebXR is unavailable in this browser.';
element.dataset.state = 'blocked';
return;
}
try {
const supported = await navigator.xr.isSessionSupported('immersive-vr');
element.textContent = supported
? 'Immersive WebXR is available. Use the player button to enter VR.'
: 'This browser reports that immersive-vr is not supported.';
element.dataset.state = supported ? 'ready' : 'blocked';
} catch (error) {
element.textContent = 'Unable to check immersive-vr support. See the browser console for details.';
element.dataset.state = 'blocked';
console.error('DEMO_XR_STATUS_ERROR:', error);
}
}

View File

@@ -123,6 +123,29 @@ a {
font-size: 0.95rem; font-size: 0.95rem;
} }
.demo-xr-status {
max-width: 760px;
margin: 0 0 10px;
padding: 10px 12px;
border: 1px solid #d5d5cf;
border-radius: 6px;
background: #fff;
color: #4f4f48;
font-size: 0.95rem;
}
.demo-xr-status[data-state="blocked"] {
border-color: #d7a13a;
background: #fff8e8;
color: #5f4515;
}
.demo-xr-status[data-state="ready"] {
border-color: #7eb07b;
background: #eff8ef;
color: #275425;
}
@media (max-width: 640px) { @media (max-width: 640px) {
.demo-page { .demo-page {
padding: 20px; padding: 20px;

View File

@@ -82,6 +82,11 @@ function onDocumentReady(callback: () => void): void {
function completeXrSupportCheck(playButton: HTMLButtonElement, onComplete: () => void): void { function completeXrSupportCheck(playButton: HTMLButtonElement, onComplete: () => void): void {
if (!navigator.xr) { if (!navigator.xr) {
if (!window.isSecureContext) {
console.warn('VR_WEB_PLAYER_XR: Immersive WebXR requires a secure context. Serve the page over HTTPS, a trusted tunnel, or a deployed CDN URL to test in a headset.');
} else {
console.warn('VR_WEB_PLAYER_XR: navigator.xr is not available in this browser.');
}
markXrUnsupported(playButton); markXrUnsupported(playButton);
onComplete(); onComplete();
return; return;
@@ -91,6 +96,7 @@ function completeXrSupportCheck(playButton: HTMLButtonElement, onComplete: () =>
if (supported) { if (supported) {
playButton.dataset.xrSupported = 'true'; playButton.dataset.xrSupported = 'true';
} else { } else {
console.warn('VR_WEB_PLAYER_XR: immersive-vr is not supported by this browser/device.');
markXrUnsupported(playButton); markXrUnsupported(playButton);
} }

View File

@@ -18,11 +18,14 @@
<a class="demo-back" href="./index.html">Back</a> <a class="demo-back" href="./index.html">Back</a>
</header> </header>
<p class="demo-xr-status" data-demo-xr-status>Checking immersive WebXR support...</p>
<div class="demo-player-frame" data-vr-web-player data-projection="plane"> <div class="demo-player-frame" data-vr-web-player data-projection="plane">
<img src="media/169_3d_test.png" alt="Demo SBS image" title="3D Image Plane" crossorigin="anonymous"> <img src="media/169_3d_test.png" alt="Demo SBS image" title="3D Image Plane" crossorigin="anonymous">
</div> </div>
</div> </div>
</main> </main>
<script type="module" src="./demo-xr-status.js"></script>
<script type="module" src="./vr180player/vr180-player.js"></script> <script type="module" src="./vr180player/vr180-player.js"></script>
</body> </body>
</html> </html>

View File

@@ -18,6 +18,8 @@
<a class="demo-back" href="./index.html">Back</a> <a class="demo-back" href="./index.html">Back</a>
</header> </header>
<p class="demo-xr-status" data-demo-xr-status>Checking immersive WebXR support...</p>
<div class="demo-player-frame" data-vr-web-player data-projection="plane"> <div class="demo-player-frame" data-vr-web-player data-projection="plane">
<video poster="poster.jpg" title="3D Video Plane" crossorigin="anonymous" playsinline preload="metadata"> <video poster="poster.jpg" title="3D Video Plane" crossorigin="anonymous" playsinline preload="metadata">
<source src="media/sbs-video.mp4" type="video/mp4"> <source src="media/sbs-video.mp4" type="video/mp4">
@@ -25,6 +27,7 @@
</div> </div>
</div> </div>
</main> </main>
<script type="module" src="./demo-xr-status.js"></script>
<script type="module" src="./vr180player/vr180-player.js"></script> <script type="module" src="./vr180player/vr180-player.js"></script>
</body> </body>
</html> </html>

View File

@@ -18,11 +18,14 @@
<a class="demo-back" href="./index.html">Back</a> <a class="demo-back" href="./index.html">Back</a>
</header> </header>
<p class="demo-xr-status" data-demo-xr-status>Checking immersive WebXR support...</p>
<div class="demo-player-frame" data-vr-web-player data-projection="vr180"> <div class="demo-player-frame" data-vr-web-player data-projection="vr180">
<img src="media/169_3d_test.png" alt="Demo VR180 SBS image" title="VR180 3D Image" crossorigin="anonymous"> <img src="media/169_3d_test.png" alt="Demo VR180 SBS image" title="VR180 3D Image" crossorigin="anonymous">
</div> </div>
</div> </div>
</main> </main>
<script type="module" src="./demo-xr-status.js"></script>
<script type="module" src="./vr180player/vr180-player.js"></script> <script type="module" src="./vr180player/vr180-player.js"></script>
</body> </body>
</html> </html>

View File

@@ -18,6 +18,8 @@
<a class="demo-back" href="./index.html">Back</a> <a class="demo-back" href="./index.html">Back</a>
</header> </header>
<p class="demo-xr-status" data-demo-xr-status>Checking immersive WebXR support...</p>
<div class="demo-player-frame" data-vr-web-player data-projection="vr180"> <div class="demo-player-frame" data-vr-web-player data-projection="vr180">
<video poster="poster.jpg" title="VR180 3D Video" crossorigin="anonymous" playsinline preload="metadata"> <video poster="poster.jpg" title="VR180 3D Video" crossorigin="anonymous" playsinline preload="metadata">
<source src="media/sbs-video.mp4" type="video/mp4"> <source src="media/sbs-video.mp4" type="video/mp4">
@@ -25,6 +27,7 @@
</div> </div>
</div> </div>
</main> </main>
<script type="module" src="./demo-xr-status.js"></script>
<script type="module" src="./vr180player/vr180-player.js"></script> <script type="module" src="./vr180player/vr180-player.js"></script>
</body> </body>
</html> </html>