From 10bbfd27e21a1b7368c38432178309263662aef6 Mon Sep 17 00:00:00 2001 From: Leon van Kammen Date: Mon, 14 Jul 2025 16:13:13 +0200 Subject: [PATCH] refactored cast.js to new components --- com/cast.js | 109 ++++++++++++++++++++-------------------------------- 1 file changed, 42 insertions(+), 67 deletions(-) diff --git a/com/cast.js b/com/cast.js index 0b5ec56..706a485 100644 --- a/com/cast.js +++ b/com/cast.js @@ -4,11 +4,8 @@ AFRAME.registerComponent('cast', { }, requires: { - dom: "./com/dom.js", // interpret .dom object - xd: "./com/xd.js", // allow switching between 2D/3D - html: "https://unpkg.com/aframe-htmlmesh@2.1.0/build/aframe-html.js", // html to AFRAME - winboxjs: "https://unpkg.com/winbox@0.2.82/dist/winbox.bundle.min.js", // deadsimple windows: https://nextapps-de.github.io/winbox - winboxcss: "https://unpkg.com/winbox@0.2.82/dist/css/winbox.min.css", // + dom: "com/dom.js", + window: "com/window.js", }, dom: { @@ -23,7 +20,7 @@ AFRAME.registerComponent('cast', { init: function () { }, - getInstallables: function(){ + etInstallables: function(){ const installed = document.querySelector('[launcher]').components.launcher.system.getLaunchables() return this.data.comps.map( (c) => { return installed[c] ? null : c @@ -37,77 +34,54 @@ AFRAME.registerComponent('cast', { if( this.el.sceneEl.renderer.xr.isPresenting ){ this.el.sceneEl.exitVR() // *FIXME* we need a gui } - const el = document.querySelector('body'); - const cropTarget = await CropTarget.fromElement(el); - const stream = await navigator.mediaDevices.getDisplayMedia(); - const [track] = stream.getVideoTracks(); - this.track = track - this.stream = stream - this.createWindow() - } + this.el.object3D.quaternion.copy( AFRAME.scenes[0].camera.quaternion ) // face towards camera + // instance this component + this.el.setAttribute("dom","") + }, + + DOMready: function(){ + this.setupCast(); + this.el.setAttribute("html-as-texture-in-xr", `domid: #${this.el.uid}; faceuser: true`) + }, + }, - createWindow: async function(){ + setupCast: async function(){ let s = await AFRAME.utils.require(this.requires) - // instance this component - const instance = this.el.cloneNode(false) - this.el.sceneEl.appendChild( instance ) - instance.setAttribute("dom", "") - instance.setAttribute("xd", "") // allows flipping between DOM/WebGL when toggling XD-button - instance.setAttribute("visible", AFRAME.utils.XD() == '3D' ? 'true' : 'false' ) - instance.setAttribute("position", AFRAME.utils.XD.getPositionInFrontOfCamera(0.5) ) - instance.setAttribute("grabbable","") - instance.object3D.quaternion.copy( AFRAME.scenes[0].camera.quaternion ) // face towards camera - instance.track = this.track - instance.stream = this.stream + const video = this.el.dom.querySelector('video') - const setupWindow = () => { - instance.dom.style.display = 'none' + video.addEventListener( "loadedmetadata", () => { - const video = instance.dom.querySelector('video') - video.addEventListener( "loadedmetadata", function () { - let width = Math.round(window.innerWidth*0.4) - let factor = width / this.videoWidth - let height = Math.round(this.videoHeight * factor) - new WinBox("Casting Tab",{ - width, - height, - x:"center", - y:"center", - id: instance.uid, // important hint for html-mesh - root: document.querySelector("#overlay"), - mount: instance.dom, - onclose: () => { instance.dom.style.display = 'none'; return false; }, - oncreate: () => { + let width = Math.round(window.innerWidth*0.4) + let factor = width / video.videoWidth + let height = Math.round( video.videoHeight * factor) - // instance.setAttribute("html",`html:#${instance.uid}; cursor:#cursor`) - } - }); - instance.dom.style.display = '' // show + const createVideoTexture = () => { + const texture = new THREE.VideoTexture( video ); + texture.colorSpace = THREE.SRGBColorSpace; + const geometry = new THREE.PlaneGeometry( 16, 9 ); + geometry.scale( 0.2, 0.2, 0.2 ); + const material = new THREE.MeshBasicMaterial( { map: texture } ); + const mesh = new THREE.Mesh( geometry, material ); + mesh.lookAt( AFRAME.scenes[0].camera.position ); + this.el.object3D.add(mesh) + } - // hint grabbable's obb-collider to track the window-object - instance.components['obb-collider'].data.trackedObject3D = 'components.html.el.object3D.children.0' - instance.components['obb-collider'].update() - }) - video.srcObject = instance.stream - video.play() + createVideoTexture.apply(this) + //this.el.setAttribute("window", `title: casting tab; uid: ${this.el.uid}; attach: #overlay; dom: #${this.el.dom.id}; width:${width}; height: ${height}`) + }) - this.createVideoTexture.apply(instance) - } - setTimeout( () => setupWindow(), 10 ) // give new components time to init - }, + const el = document.querySelector('body'); + const cropTarget = await CropTarget.fromElement(el); + const stream = await navigator.mediaDevices.getDisplayMedia(); + const [track] = stream.getVideoTracks(); + this.track = track + this.stream = stream + + video.srcObject = this.stream + video.play() - createVideoTexture: function(){ - console.dir(this) - const texture = new THREE.VideoTexture( video ); - texture.colorSpace = THREE.SRGBColorSpace; - const geometry = new THREE.PlaneGeometry( 16, 9 ); - geometry.scale( 0.2, 0.2, 0.2 ); - const material = new THREE.MeshBasicMaterial( { map: texture } ); - const mesh = new THREE.Mesh( geometry, material ); - mesh.lookAt( this.sceneEl.camera.position ); - this.object3D.add(mesh) }, manifest: { // HTML5 manifest to identify app to xrsh @@ -116,6 +90,7 @@ AFRAME.registerComponent('cast', { "icons": [ { "src": "https://css.gg/cast.svg", + "src": "data:image/svg+xml;base64,PHN2ZwogIHdpZHRoPSIyNCIKICBoZWlnaHQ9IjI0IgogIHZpZXdCb3g9IjAgMCAyNCAyNCIKICBmaWxsPSJub25lIgogIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKPgogIDxwYXRoCiAgICBkPSJNMjAgNkg0VjhIMlY2QzIgNC44OTU0MyAyLjg5NTQzIDQgNCA0SDIwQzIxLjEwNDYgNCAyMiA0Ljg5NTQzIDIyIDZWMThDMjIgMTkuMTA0NiAyMS4xMDQ2IDIwIDIwIDIwSDE1VjE4SDIwVjZaIgogICAgZmlsbD0iY3VycmVudENvbG9yIgogIC8+CiAgPHBhdGgKICAgIGQ9Ik0yIDEzQzUuODY1OTkgMTMgOSAxNi4xMzQgOSAyMEg3QzcgMTcuMjM4NiA0Ljc2MTQyIDE1IDIgMTVWMTNaIgogICAgZmlsbD0iY3VycmVudENvbG9yIgogIC8+CiAgPHBhdGggZD0iTTIgMTdDMy42NTY4NSAxNyA1IDE4LjM0MzEgNSAyMEgyVjE3WiIgZmlsbD0iY3VycmVudENvbG9yIiAvPgogIDxwYXRoCiAgICBkPSJNMiA5QzguMDc1MTMgOSAxMyAxMy45MjQ5IDEzIDIwSDExQzExIDE1LjAyOTQgNi45NzA1NiAxMSAyIDExVjlaIgogICAgZmlsbD0iY3VycmVudENvbG9yIgogIC8+Cjwvc3ZnPg==", "type": "image/svg+xml", "sizes": "512x512" }