From af7e83755467a9478e3eeea316f995832d6f3e13 Mon Sep 17 00:00:00 2001 From: Leon van Kammen Date: Wed, 4 Sep 2024 18:44:49 +0000 Subject: [PATCH] bugfix: terminal now works in AR & immersive-pause mode again --- com/data2event.js | 48 ++++---- com/dom.js | 179 +++++++++++++++-------------- com/example/helloworld-htmlform.js | 10 +- com/example/helloworld-iframe.js | 2 + com/example/helloworld-window.js | 11 +- com/html-as-texture-in-xr.js | 123 ++++++++++++++++++++ com/isoterminal.js | 15 ++- com/isoterminal/feat/9pfs_utils.js | 26 +++++ com/isoterminal/feat/index.html.js | 10 ++ com/isoterminal/mnt/profile | 2 +- com/isoterminal/mnt/profile.xrsh | 19 +-- com/window.js | 3 - com/xd.js | 111 ------------------ 13 files changed, 311 insertions(+), 248 deletions(-) create mode 100644 com/html-as-texture-in-xr.js create mode 100644 com/isoterminal/feat/index.html.js delete mode 100644 com/xd.js diff --git a/com/data2event.js b/com/data2event.js index ff7d628..54118a5 100644 --- a/com/data2event.js +++ b/com/data2event.js @@ -18,29 +18,33 @@ * */ -AFRAME.registerComponent('data2event',{ +if( !AFRAME.components.data2event ){ - init: function(){ - setTimeout( () => { - for( let i in this.el.components ){ - let com = this.el.components[i] - if( typeof com.data == 'object' ){ - com.data = this.reactify( this.el, com.data) + AFRAME.registerComponent('data2event',{ + + init: function(){ + setTimeout( () => { + for( let i in this.el.components ){ + let com = this.el.components[i] + if( typeof com.data == 'object' ){ + com.data = this.reactify( this.el, com.data) + } } - } - },50) - }, + },50) + }, - reactify: function(el,data){ - return new Proxy(data, { - get(me,k,v) { - return me[k] - }, - set(me,k,v){ - me[k] = v - el.emit(k,{el,k,v}) - } - }) - }, + reactify: function(el,data){ + return new Proxy(data, { + get(me,k,v) { + return me[k] + }, + set(me,k,v){ + me[k] = v + el.emit(k,{el,k,v}) + } + }) + }, -}) + }) + +} diff --git a/com/dom.js b/com/dom.js index 1c1bf9a..e157249 100644 --- a/com/dom.js +++ b/com/dom.js @@ -32,105 +32,108 @@ * | `DOMready` | self | fired when dom component (`this.dom`) is created | */ -AFRAME.registerComponent('dom',{ +if( !AFRAME.components.dom ){ - init: function(){ - Object.values(this.el.components) - .map( (c) => { - if( c.dom && c.attrName != "dom"){ - this.dom = c.dom - this.com = c + AFRAME.registerComponent('dom',{ + + init: function(){ + Object.values(this.el.components) + .map( (c) => { + if( c.dom && c.attrName != "dom"){ + this.dom = c.dom + this.com = c + } + }) + if( !this.dom || !this.com){ + return console.warn('dom.js did not find a .dom object inside component') } - }) - if( !this.dom || !this.com){ - return console.warn('dom.js did not find a .dom object inside component') - } - this - .ensureOverlay() - .addCSS() - .createReactiveDOMElement() - .assignUniqueID() - .scaleDOMvsXR() - .triggerKeyboardForInputs() - .stubRequestAnimationFrame() + this + .ensureOverlay() + .addCSS() + .createReactiveDOMElement() + .assignUniqueID() + .scaleDOMvsXR() + .triggerKeyboardForInputs() + .stubRequestAnimationFrame() - document.querySelector('#overlay').appendChild(this.el.dom) - this.el.emit('DOMready',{el: this.el.dom}) - }, + document.querySelector('#overlay').appendChild(this.el.dom) + this.el.emit('DOMready',{el: this.el.dom}) + }, - ensureOverlay: function(){ - // ensure overlay - let overlay = document.querySelector('#overlay') - if( !overlay ){ - overlay = document.createElement('div') - overlay.id = "overlay" - overlay.setAttribute('style','position:fixed;top:0px;left:0px;right:0px;bottom:0px') - document.body.appendChild(overlay) - // sceneEl.setAttribute("webxr","overlayElement:#overlay") - } - return this - }, - - reactify: function(el,data){ - return new Proxy(data, { - get(me,k,v) { - return me[k] - }, - set(me,k,v){ - me[k] = v - el.emit(k,{el,k,v}) + ensureOverlay: function(){ + // ensure overlay + let overlay = document.querySelector('#overlay') + if( !overlay ){ + overlay = document.createElement('div') + overlay.id = "overlay" + overlay.setAttribute('style','position:fixed;top:0px;left:0px;right:0px;bottom:0px') + document.body.appendChild(overlay) + // sceneEl.setAttribute("webxr","overlayElement:#overlay") } - }) - }, + return this + }, - // creates el.dom (the 2D DOM object) - createReactiveDOMElement: function(){ - this.el.dom = document.createElement('div') - this.el.dom.innerHTML = this.dom.html(this) - this.el.dom.className = this.dom.attrName - this.com.data = this.reactify( this.el, this.com.data ) - if( this.dom.events ) this.dom.events.map( (e) => this.el.dom.addEventListener(e, (ev) => this.el.emit(e,ev) ) ) - this.el.dom = this.el.dom.children[0] - return this - }, + reactify: function(el,data){ + return new Proxy(data, { + get(me,k,v) { + return me[k] + }, + set(me,k,v){ + me[k] = v + el.emit(k,{el,k,v}) + } + }) + }, - assignUniqueID: function(){ - // assign unique app id so it's easy to reference (by html-mesh component e.g.) - if( !this.el.uid ) this.el.uid = this.el.dom.id = '_'+String(Math.random()).substr(10) - return this - }, + // creates el.dom (the 2D DOM object) + createReactiveDOMElement: function(){ + this.el.dom = document.createElement('div') + this.el.dom.innerHTML = this.dom.html(this) + this.el.dom.className = this.dom.attrName + this.com.data = this.reactify( this.el, this.com.data ) + if( this.dom.events ) this.dom.events.map( (e) => this.el.dom.addEventListener(e, (ev) => this.el.emit(e,ev) ) ) + this.el.dom = this.el.dom.children[0] + return this + }, - addCSS: function(){ - if( this.dom.css && !document.head.querySelector(`style#${this.com.attrName}`) ){ - document.head.innerHTML += `` - } - return this - }, + assignUniqueID: function(){ + // assign unique app id so it's easy to reference (by html-mesh component e.g.) + if( !this.el.uid ) this.el.uid = this.el.dom.id = '_'+String(Math.random()).substr(10) + return this + }, - scaleDOMvsXR: function(){ - if( this.dom.scale ) this.el.setAttribute('scale',`${this.dom.scale} ${this.dom.scale} ${this.dom.scale}`) - return this - }, - - triggerKeyboardForInputs: function(){ - // https://developer.oculus.com/documentation/web/webxr-keyboard ; - [...this.el.dom.querySelectorAll('[type=text]')].map( (input) => { - let triggerKeyboard = function(){ - this.focus() - console.log("focus") + addCSS: function(){ + if( this.dom.css && !document.head.querySelector(`style#${this.com.attrName}`) ){ + document.head.innerHTML += `` } - input.addEventListener('click', triggerKeyboard ) - }) - return this - }, + return this + }, - stubRequestAnimationFrame: function(){ - // stub, because WebXR with overrule this (it will not call the callback as expected in immersive mode) - const requestAnimationFrame = window.requestAnimationFrame - window.requestAnimationFrame = (cb) => { - setTimeout( cb, 25 ) + scaleDOMvsXR: function(){ + if( this.dom.scale ) this.el.setAttribute('scale',`${this.dom.scale} ${this.dom.scale} ${this.dom.scale}`) + return this + }, + + triggerKeyboardForInputs: function(){ + // https://developer.oculus.com/documentation/web/webxr-keyboard ; + [...this.el.dom.querySelectorAll('[type=text]')].map( (input) => { + let triggerKeyboard = function(){ + this.focus() + console.log("focus") + } + input.addEventListener('click', triggerKeyboard ) + }) + return this + }, + + stubRequestAnimationFrame: function(){ + // stub, because WebXR with overrule this (it will not call the callback as expected in immersive mode) + const requestAnimationFrame = window.requestAnimationFrame + window.requestAnimationFrame = (cb) => { + setTimeout( cb, 25 ) + } } - } -}) + }) +} diff --git a/com/example/helloworld-htmlform.js b/com/example/helloworld-htmlform.js index 511fe0d..92ad6a1 100644 --- a/com/example/helloworld-htmlform.js +++ b/com/example/helloworld-htmlform.js @@ -57,9 +57,7 @@ AFRAME.registerComponent('helloworld-htmlform', { 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("show-texture-in-xr", "") // only show aframe-html in xr instance.setAttribute("grabbable","") instance.object3D.quaternion.copy( AFRAME.scenes[0].camera.quaternion ) // face towards camera @@ -75,7 +73,11 @@ AFRAME.registerComponent('helloworld-htmlform', { root: document.querySelector("#overlay"), mount: instance.dom, onclose: () => { instance.dom.style.display = 'none'; return false; }, - oncreate: () => instance.setAttribute("html",`html:#${instance.uid}; cursor:#cursor`) + oncreate: () => { + instance.setAttribute("position", AFRAME.utils.XD.getPositionInFrontOfCamera(0.5) ) + instance.setAttribute("html",`html:#${instance.uid}; cursor:#cursor`) + instance.setAttribute("show-texture-in-xr","") // only show aframe-html texture in xr mode + } }); instance.dom.style.display = AFRAME.utils.XD() == '3D' ? 'none' : '' // show/hide diff --git a/com/example/helloworld-iframe.js b/com/example/helloworld-iframe.js index ae1776e..2ecf5f9 100644 --- a/com/example/helloworld-iframe.js +++ b/com/example/helloworld-iframe.js @@ -87,7 +87,9 @@ AFRAME.registerComponent('helloworld-iframe', { onclose: () => { instance.dom.style.display = 'none'; return false; }, oncreate: () => { com.data.url = URL + instance.setAttribute("position", AFRAME.utils.XD.getPositionInFrontOfCamera(0.5) ) instance.setAttribute("html",`html:#${instance.uid}; cursor:#cursor`) + instance.setAttribute("show-texture-in-xr","") // only show aframe-html texture in xr mode } }); instance.dom.style.display = '' diff --git a/com/example/helloworld-window.js b/com/example/helloworld-window.js index 580f6f5..3ef4019 100644 --- a/com/example/helloworld-window.js +++ b/com/example/helloworld-window.js @@ -5,7 +5,7 @@ AFRAME.registerComponent('helloworld-window', { requires: { dom: "./com/dom.js", // interpret .dom object - xd: "./com/dom.js", // allow switching between 2D/3D + xrtexture: "./com/html-as-texture-in-xr.js", // allow switching between 3D/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", // @@ -39,10 +39,7 @@ AFRAME.registerComponent('helloworld-window', { // 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("dom", "") instance.setAttribute("grabbable","") instance.object3D.quaternion.copy( AFRAME.scenes[0].camera.quaternion ) // face towards camera @@ -59,7 +56,9 @@ AFRAME.registerComponent('helloworld-window', { root: document.querySelector("#overlay"), mount: instance.dom, onclose: () => { instance.dom.style.display = 'none'; return false; }, - oncreate: () => instance.setAttribute("html",`html:#${instance.uid}; cursor:#cursor`) + oncreate: () => { + instance.setAttribute("show-texture-in-xr",`domid: #${instance.uid}`) // only show aframe-html texture in xr mode + } }); instance.dom.style.display = '' // show diff --git a/com/html-as-texture-in-xr.js b/com/html-as-texture-in-xr.js new file mode 100644 index 0000000..990f2ef --- /dev/null +++ b/com/html-as-texture-in-xr.js @@ -0,0 +1,123 @@ +if( !AFRAME.components['html-as-textre-in-xr'] ){ + + AFRAME.registerComponent('html-as-texture-in-xr', { + schema: { + domid: { type:"string"} + }, + + dependencies:{ + html: "https://unpkg.com/aframe-htmlmesh@2.1.0/build/aframe-html.js", // html to AFRAME + }, + + init: async function () { + let s = await AFRAME.utils.require(this.dependencies) + this.el.setAttribute("html",`html: ${this.data.domid}; cursor:#cursor`) + this.el.setAttribute("visible", AFRAME.utils.XD() == '3D' ? 'true' : 'false' ) + this.el.setAttribute("position", AFRAME.utils.XD.getPositionInFrontOfCamera(0.5) ) + }, + + manifest: { // HTML5 manifest to identify app to xrsh + "short_name": "show-texture-in-xr", + "name": "2D/3D switcher", + "icons": [], + "id": "/?source=pwa", + "start_url": "/?source=pwa", + "background_color": "#3367D6", + "display": "standalone", + "scope": "/", + "theme_color": "#3367D6", + "category":"system", + "shortcuts": [ + { + "name": "What is the latest news?", + "cli":{ + "usage": "helloworld [options]", + "example": "helloworld news", + "args":{ + "--latest": {type:"string"} + } + }, + "short_name": "Today", + "description": "View weather information for today", + "url": "/today?source=pwa", + "icons": [{ "src": "/images/today.png", "sizes": "192x192" }] + } + ], + "description": "use ESC-key to toggle between 2D / 3D", + "screenshots": [ + { + "src": "/images/screenshot1.png", + "type": "image/png", + "sizes": "540x720", + "form_factor": "narrow" + } + ], + "help":` + Helloworld application + + ` + } + + }); + + AFRAME.utils.XD = function(){ + return document.body.classList.contains('XR') ? '3D' : '2D' + } + + AFRAME.utils.XD.toggle = function(state){ + state = state != undefined ? state : state || !document.body.className.match(/XR/) + document.body.classList[ state ? 'add' : 'remove'](['XR']) + AFRAME.scenes[0].emit( state ? '3D' : '2D') + } + + AFRAME.utils.XD.getPositionInFrontOfCamera = function(distance){ + const camera = AFRAME.scenes[0].camera; + let pos = new THREE.Vector3() + let direction = new THREE.Vector3(); + // Get camera's forward direction (without rotation) + camera.getWorldDirection(direction); + camera.getWorldPosition(pos) + direction.normalize(); + // Scale the direction by 1 meter + if( !distance ) distance = 1.5 + direction.multiplyScalar(distance); + // Add the camera's position to the scaled direction to get the target point + pos.add(direction); + return pos + } + + AFRAME.registerSystem('html-as-texture-in-xr',{ + + init: function(){ + this.sceneEl.addEventListener('enter-vr',() => AFRAME.utils.XD.toggle(true) ) + this.sceneEl.addEventListener('exit-vr', () => AFRAME.utils.XD.toggle(false) ) + this.sceneEl.addEventListener('2D', () => this.showElements(false) ) + this.sceneEl.addEventListener('3D', () => this.showElements(true) ) + + // toggle immersive with ESCAPE + //document.body.addEventListener('keydown', (e) => e.key == 'Escape' && this.toggle() ) + + document.head.innerHTML += `` + + }, + + showElements: function(state){ + let els = [...document.querySelectorAll('[html-as-texture-in-xr]')] + els = els.filter( (el) => el != this.el ? el : null ) // filter out self + els.map( (el) => el.setAttribute("visible", state ? true : false ) ) + } + + }) + +} diff --git a/com/isoterminal.js b/com/isoterminal.js index e2eb21b..9ec2682 100644 --- a/com/isoterminal.js +++ b/com/isoterminal.js @@ -46,6 +46,9 @@ if( typeof AFRAME != 'undefined '){ xtermjs: "https://unpkg.com/@xterm/xterm@5.5.0/lib/xterm.js", xtermcss: "https://unpkg.com/@xterm/xterm@5.5.0/css/xterm.css", v86: "com/isoterminal/libv86.js", + // html to texture + htmlinxr: "com/html-as-texture-in-xr.js", + html: "https://unpkg.com/aframe-htmlmesh@2.1.0/build/aframe-html.js", // html to AFRAME // isoterminal features core: "com/isoterminal/core.js", utils_9p: "com/isoterminal/feat/9pfs_utils.js", @@ -53,10 +56,11 @@ if( typeof AFRAME != 'undefined '){ xterm: "com/isoterminal/feat/xterm.js", jsconsole: "com/isoterminal/feat/jsconsole.js", javascript: "com/isoterminal/feat/javascript.js", + index: "com/isoterminal/feat/index.html.js", }, dom: { - scale: 0.7, + scale: 0.5, events: ['click','keydown'], html: (me) => `
`, @@ -77,7 +81,7 @@ if( typeof AFRAME != 'undefined '){ .isoterminal style{ display:none } .wb-body:has(> .isoterminal){ - background: #000c; + background: #000F; overflow:hidden; } @@ -147,6 +151,9 @@ if( typeof AFRAME != 'undefined '){ this.isoterminal.addEventListener('ready', function(e){ instance.dom.classList.remove('blink') instance.winbox.maximize() + setTimeout( () => { // important: after window maximize animation to get true size + instance.setAttribute("html-as-texture-in-xr", `domid: #${instance.uid}`) // only show aframe-html in xr + },1500) }) this.isoterminal.addEventListener('status', function(e){ @@ -172,13 +179,11 @@ if( typeof AFRAME != 'undefined '){ instance.addEventListener('window.onmaximize', resize ) 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) ) const focus = () => document.querySelector('canvas.a-canvas').focus() instance.addEventListener('obbcollisionstarted', focus ) this.el.sceneEl.addEventListener('enter-vr', focus ) + this.el.sceneEl.addEventListener('enter-ar', focus ) instance.object3D.quaternion.copy( AFRAME.scenes[0].camera.quaternion ) // face towards camera } diff --git a/com/isoterminal/feat/9pfs_utils.js b/com/isoterminal/feat/9pfs_utils.js index 18ca419..53a225b 100644 --- a/com/isoterminal/feat/9pfs_utils.js +++ b/com/isoterminal/feat/9pfs_utils.js @@ -2,6 +2,32 @@ ISOTerminal.addEventListener('emulator-started', function(){ let emulator = this.emulator let isoterminal = this + emulator.fs9p.Read = async function(inodeid, offset, count){ + let file + const inode = this.inodes[inodeid]; + const inodeDir = this.GetParent(inode.fid) + + if( !inodeDir ){ // undefined = /mnt + for( const [name,childid] of this.inodes[0].direntries ){ + if( childid == inode.fid ){ file = name } + } + } + + if( file ){ + let data = {promise:false, file} + isoterminal.emit('file-read', data) + // if( data.promise ){ return await data.promise } // *FIX* size already + } + + if(this.is_forwarder(inode)) + { + const foreign_id = inode.foreign_id; + return await this.follow_fs(inode).Read(foreign_id, offset, count); + } + + return await this.get_data(inodeid, offset, count); + }; + emulator.fs9p.update_file = async function(file,data){ const p = this.SearchPath(file); diff --git a/com/isoterminal/feat/index.html.js b/com/isoterminal/feat/index.html.js new file mode 100644 index 0000000..c6765aa --- /dev/null +++ b/com/isoterminal/feat/index.html.js @@ -0,0 +1,10 @@ +ISOTerminal.addEventListener('ready', function(){ + this.addEventListener('file-read', (e) => { + const data = e.detail + if( data.file == 'index.html'){ + data.promise = new Promise( (resolve,reject) => { + resolve( this.toUint8Array(document.documentElement.outerHTML) ) + }) + } + }) +}) diff --git a/com/isoterminal/mnt/profile b/com/isoterminal/mnt/profile index e587a0f..01135c0 100644 --- a/com/isoterminal/mnt/profile +++ b/com/isoterminal/mnt/profile @@ -26,6 +26,6 @@ command_not_found_handle(){ resize test $HOSTNAME = localhost || clear cat /mnt/motd -export PATH=$PATH:/mnt +export PATH=$PATH:/mnt:~/bin export PS1="\n\[\033[38;5;57m\]x\[\033[38;5;93m\]r\[\033[38;5;129m\]s\[\033[38;5;165m\]h \[\033[38;5;201m\]# \[\033[0m\]" diff --git a/com/isoterminal/mnt/profile.xrsh b/com/isoterminal/mnt/profile.xrsh index abeae4b..31ccdbe 100644 --- a/com/isoterminal/mnt/profile.xrsh +++ b/com/isoterminal/mnt/profile.xrsh @@ -20,26 +20,29 @@ test -d /dev/browser || { setup_browser_dev(){ mkdir -p /mnt/dev/browser touch /mnt/dev/browser/js - touch /mnt/dev/browser/html touch /mnt/console.tty ln -s /mnt/dev/browser /dev/browser - ln -s /dev/browser/html ~/index.html - # setup console goodies - ln -s /mnt/console.tty /dev/browser/console.tty # emulator.write_file() only writes to /mnt/. :( - echo 0 > /dev/browser/console.tty # should be in /proc, but v86 gives 'no such file or dir' when creating it there - touch /mnt/console - ln -s /mnt/console /dev/browser/console + # emulator.write_file() only writes to /mnt/. :( + # should be in /proc, but v86 gives 'no such file or dir' when creating it there + ln -s /mnt/console.tty /dev/browser/console.tty + echo 0 > /dev/browser/console.tty + touch /mnt/console && ln -s /mnt/console /dev/browser/console + touch /mnt/index.html && ln -s /mnt/index.html /dev/browser/index.html + ln -s /dev/browser/index.html ~/index.html test -f /etc/profile && rm /etc/profile ln -s /mnt/profile /etc/profile } setup_hook_dirs(){ # see /mnt/hook for usage + mkdir ~/bin mkdir -p ~/hook.d/alert - echo -e "#!/bin/sh\necho hook.d/alert/yo: yo \$*" > ~/hook.d/alert/yo + echo -e "#!/bin/sh\necho hook.d/alert/yo: yo \$*" > ~/hook.d/alert/yo echo -e "#!/bin/js\nalert(\"hook.d/alert/yo.js \"+args.slice(1).join(' '))" > ~/hook.d/alert/yo.js echo -e "#!/usr/bin/env lua\nprint(\"hook.d/alert/yo.lua: yo \" .. arg[1])" > ~/hook.d/alert/yo.lua echo -e "#!/usr/bin/awk -f\nBEGIN{\n\tprint \"hook.d/alert/yo.awk: yo \" ARGV[1]\n}" > ~/hook.d/alert/yo.awk + echo -e "#!/bin/sh\necho hello \$*" > ~/bin/hello + chmod +x ~/bin/hello } setup_network(){ diff --git a/com/window.js b/com/window.js index e53b485..846d8d6 100644 --- a/com/window.js +++ b/com/window.js @@ -12,7 +12,6 @@ AFRAME.registerComponent('window', { dependencies:{ dom: "com/dom.js", - 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", // main theme }, @@ -41,7 +40,6 @@ AFRAME.registerComponent('window', { // resize after the dom content has been rendered & updated setTimeout( () => { winbox.resize( this.el.dom.offsetWidth+'px', this.el.dom.offsetHeight+'px' ) - setTimeout( () => this.el.setAttribute("html",`html:#${this.data.uid}; cursor:#cursor`), 1000) // hint grabbable's obb-collider to track the window-object this.el.components['obb-collider'].data.trackedObject3D = 'components.html.el.object3D.children.0' this.el.components['obb-collider'].update() @@ -53,7 +51,6 @@ AFRAME.registerComponent('window', { if( e.halt ) return true this.data.dom.style.display = 'none'; this.data.dom.parentElement.remove() - debugger this.el.parentElement.remove( this.el ) return false }, diff --git a/com/xd.js b/com/xd.js deleted file mode 100644 index d331104..0000000 --- a/com/xd.js +++ /dev/null @@ -1,111 +0,0 @@ -AFRAME.registerComponent('xd', { - schema: { - foo: { type:"string"} - }, - - init: function () { - if( Object.keys(this.el.components).length > 1 ) return // we collect a-entities which wish to be toggled in this.showElements() - - this.el.sceneEl.addEventListener('enter-vr',() => this.toggle(true) ) - this.el.sceneEl.addEventListener('exit-vr', () => this.toggle(false) ) - this.el.sceneEl.addEventListener('2D', () => this.showElements(false) ) - this.el.sceneEl.addEventListener('3D', () => this.showElements(true) ) - - // toggle immersive with ESCAPE - document.body.addEventListener('keydown', (e) => e.key == 'Escape' && this.toggle() ) - - document.head.innerHTML += `` - - this.events.launcher = () => this.toggle() - }, - - showElements: function(state){ - let els = [...document.querySelectorAll('[xd]')] - els = els.filter( (el) => el != this.el ? el : null ) // filter out self - els.map( (el) => el.setAttribute("visible", state ? "true" : false ) ) - }, - - // draw a button so we can toggle apps between 2D / XR - toggle: function(state){ - state = state != undefined ? state : state || !document.body.className.match(/XR/) - document.body.classList[ state ? 'add' : 'remove'](['XR']) - AFRAME.scenes[0].emit( state ? '3D' : '2D') - }, - - manifest: { // HTML5 manifest to identify app to xrsh - "short_name": "XD", - "name": "2D/3D switcher", - "icons": [], - "id": "/?source=pwa", - "start_url": "/?source=pwa", - "background_color": "#3367D6", - "display": "standalone", - "scope": "/", - "theme_color": "#3367D6", - "category":"system", - "shortcuts": [ - { - "name": "What is the latest news?", - "cli":{ - "usage": "helloworld [options]", - "example": "helloworld news", - "args":{ - "--latest": {type:"string"} - } - }, - "short_name": "Today", - "description": "View weather information for today", - "url": "/today?source=pwa", - "icons": [{ "src": "/images/today.png", "sizes": "192x192" }] - } - ], - "description": "use ESC-key to toggle between 2D / 3D", - "screenshots": [ - { - "src": "/images/screenshot1.png", - "type": "image/png", - "sizes": "540x720", - "form_factor": "narrow" - } - ], - "help":` -Helloworld application - -This is a help file which describes the application. -It will be rendered thru troika text, and will contain -headers based on non-punctualized lines separated by linebreaks, -in above's case "\nHelloworld application\n" will qualify as header. - ` - } - -}); - -AFRAME.utils.XD = function(){ - return document.body.classList.contains('XR') ? '3D' : '2D' -} - - -AFRAME.utils.XD.getPositionInFrontOfCamera = function(distance){ - const camera = AFRAME.scenes[0].camera; - let pos = new THREE.Vector3() - let direction = new THREE.Vector3(); - // Get camera's forward direction (without rotation) - camera.getWorldDirection(direction); - camera.getWorldPosition(pos) - direction.normalize(); - // Scale the direction by 1 meter - if( !distance ) distance = 1.5 - direction.multiplyScalar(distance); - // Add the camera's position to the scaled direction to get the target point - pos.add(direction); - return pos -}