three.js passes the renderer's antialias setting on to the XR layer, so
this turns on multisampling in VR.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Where the browser supports immersive-ar (Chrome Canary on the Steam Frame),
sessions start as AR and a panel button shows the room around the video.
The player clears the frame itself, opaque or transparent, since three.js
always clears AR frames to transparent. Recenter and Exit VR on the panel
become icons to make room. YouTube's Enter VR button is now our own, so it
can start AR sessions too.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A Steam Frame styled panel with play/pause, seek, skip, volume, projection,
recenter and exit, used with a laser from each controller. The panel and
the flat screen can be moved with the bar below them or the grip, and the
screen resized from its corner; dragged windows stay upright, face the
viewer and are smoothed. Clicking the screen plays/pauses, double clicking
its sides skips. Also lowers the camera's near plane so close objects
aren't clipped.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Pre-selects the projection when the cardboard icon is clicked: 360, VR180
or flat from YouTube's player data, read by a new script in the page's own
world, and 3D from the frame itself, since YouTube doesn't report stereo
layouts. The two eyes' halves of a 3D frame are nearly identical.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Chrome's guidelines ask for 96x96 artwork with 16px of transparent
padding in the 128px icon, which shows in the install dialog and on
the extensions page. The 16-48px toolbar sizes stay unpadded.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Use a 3D 360° (EAC) YouTube video in the headset, the YouTube controls
and the toolbar popup, resized to 1280px wide JPEGs in
docs/screenshots/, instead of the 1-4.5MB PNGs in the repo root.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Chrome only reports "The specified session configuration is not
supported" when SteamVR refuses a session, usually because another
browser holds the headset. Show what to do in the popup instead.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Only the click event was stopped, but players and lightboxes often act
on pointerdown/mousedown/pointerup/mouseup and paused the video or
closed. Swallow every event of that gesture over the video at the
window capture phase, and start VR on pointerdown, the first event
Chrome accepts as user activation (touchend for touch).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The floating panel took focus from video lightboxes, which then
closed or lost their state. The toolbar button now opens a popup with
the projection (remembered between uses), Enter VR and Stop; the page
gets no controls. Since browsers only start VR from a gesture in the
page, Enter VR arms the video and the next click on it enters VR and
starts playback.
When a video's frames can't be read because its <video> doesn't
request CORS, reload it with crossorigin="anonymous" at the same
position, and restore it if the server doesn't allow that (fixes
Wikimedia Commons). Failed VR starts are reported in the popup.
The popup replaces the background service worker.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
googlevideo.com only serves video data, so the content script never
ran there; the match only widened the install permission warning.
The author string isn't the documented manifest format, and credits
live in the README and LICENSE.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
SteamVR running plus the OpenXR WebXR runtime flag is all that's
needed. The Steam Frame's own browser doesn't support WebXR yet; link
the community Chromium build.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Show a VR180 video in the headset and the generic-site panel instead
of the original project's YouTube screenshots.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Biome lints and formats (npm run check / fix), and CI fails on
violations. Releases now use git-cliff notes grouped by Conventional
Commits prefix instead of GitHub's PR-based notes, which were empty
for direct pushes. Document the commit convention and release steps.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Stop committing built files: scripts/build.mjs bundles src/ with
esbuild (replacing webpack) and writes the complete extension to
dist/. The Build workflow runs it on every push and PR, uploads dist/
as an artifact, and publishes a release zip for v* tags that match the
manifest version. package-lock.json is now committed for npm ci.
Replace the cardboard image, which wasn't openly licensed, with Tabler
Icons' "cardboards" outline (MIT): white in the YouTube player, and on
a blue tile for the extension icons (16-128px).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Hard fork of EnableYoutubePCVR by feedthedogs as video2webxr, now that
it isn't YouTube-only. Add the ISC license the original package.json
declared, crediting the original author.
Move the sources into src/ (youtube.js, generic.js, vr-player.js):
the previous commit's webpack entry and output were both generic.js,
so the build had overwritten the generic-site source with its bundle.
Add npm build/watch scripts and rewrite the README for both modes.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Move the renderer, projections and controls into a shared VRPlayer
(vr-player.js) used by both the YouTube integration and a new generic
mode. Clicking the toolbar button finds the largest video in the tab
(including accessible iframes and shadow DOM), and shows the Enter VR
button and projection dropdown in a floating panel, defaulting to 180°
side by side. Clicking again or Close turns it off; it also stops when
the site removes or swaps the video.
DRM-protected videos and cross-origin videos without CORS can't be
used as WebGL textures; those get an explanation instead.
Uses activeTab + scripting, so the extension only touches other sites
after the button is clicked.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
YouTube switches videos without a page load, so the canvas, buttons
and render loop stayed on the next video and the cardboard icon
refused to enable VR again. End the session and clean up on
yt-navigate-start.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The Oculus user agent made YouTube serve VR180 videos as flat 16:9 and
was only partially applied anyway. Without it YouTube serves 360°
videos as EAC and VR180 videos as 180° frames, so drop the
declarativeNetRequest rule and render those formats instead.
A dropdown next to Enter VR picks the projection, matching the
videojs-vr options:
- 360° EAC (default), EAC 3D and cubemap, ported to BufferGeometry
- 360° equirectangular, mono and 3D top/bottom / side by side
- 180°, mono and 3D side by side; the vertical field of view follows
the frame's aspect ratio (YouTube VR180 is 4:3, 180° x 135°)
- flat screen for videos only available as a normal picture
Spheres are now centred in front of the viewer instead of 90° to the
left.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Chrome exposes XRWebGLBinding.createProjectionLayer even when the
session is not granted the 'layers' feature. three.js only checks that
the method exists, sets up a projection layer the session can't use,
and Chrome never delivers an XR frame, so SteamVR reports the page as
not responding. Hide the method in the extension's isolated world so
three.js falls back to XRWebGLLayer.
Also:
- update three.js 0.155 -> 0.186
- ignore repeat cardboard clicks instead of stacking renderers
- skip renderer resize while presenting
- remove the spherical control instead of the (possibly absent) webgl canvas
- bump version to 1.0.2
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>