diff --git a/index.html b/index.html index f2e321e..9b19bc2 100644 --- a/index.html +++ b/index.html @@ -33,203 +33,15 @@ setTimeout( _ => { let rot = "0 0 0" let positions = [ "-1 1 -3.5", "-1 2 -3.5", "0 0 -3.5", "0 1 -3.5", "1 0 -3.5", "-1 0 -3.5" ] // triangle example, could be based on room boundaries instead - positions.map( pos => { - let el = document.createElement("a-entity") - el.innerHTML = scaffoldingInnerHTMLTemplate - AFRAME.scenes[0].appendChild(el) - el.setAttribute("position", pos) - el.setAttribute("rotation", rot) - }) + positions.map( pos => { addFromTemplate(pos, rot, scaffoldingInnerHTMLTemplate) }) }, 2000) -var forceXaxis -// setInterval( _ => console.log(forceXaxis), 1000) - -var translatingTargets = false -var clearRot -function toggleTranslateTargets(){ - translatingTargets = !translatingTargets - let scene = AFRAME.scenes[0].object3D - if (translatingTargets){ - let anchor = new THREE.Object3D() - let latest = selectedElements[selectedElements.length-1].element - latest.object3D.add( anchor ) - // also inherits rotation, could try cancel it as the opposite of latest rotation - // might be easier to copy the position only every few ms instead - anchor.position.sub( latest.object3D.position ) - //targets.map( t => anchor.attach(t.object3D) ) - // should attach all BUT the current moving entity! - Array.from(document.querySelectorAll('.mab')).map( t => anchor.attach(t.object3D) ) - // they don't move... despite - } else { - clearInterval( clearRot ) - Array.from(document.querySelectorAll('.mab')).map( t => scene.attach(t.object3D) ) - //targets.map( t => scene.attach(t.object3D) ) - // could delete anchor, cleaner - } -} - -var attachToPlayer = false -function toggleAttachToSelf(){ - attachToPlayer = !attachToPlayer - attachToPlayer ? parent=document.querySelector("#player") : parent=AFRAME.scenes[0] - targets.map( t => parent.object3D.attach(t.object3D) ) -} - -function checkIntersection(latest, nearby){ - //let latest = selectedElements[selectedElements.length-1].element - //let nearby = getClosestTargetElements( latest.getAttribute('position') ) - // https://threejs.org/docs/?q=box#api/en/math/Box3.containsBox - // https://threejs.org/docs/?q=box#api/en/math/Box3.expandByObject - let a = new THREE.Box3().expandByObject( latest.object3D ) // consider mesh.geometry.computeBoundingBox() first - let b = new THREE.Box3().expandByObject( nearby.object3D ) - console.log(a,b, a.containsBox(b)) - // testable as checkIntersection( document.querySelector("[color='yellow']"), document.querySelector("[color='purple']") ) - // - // -} - -setTimeout( _ => { - let newPostIt = addNewNoteAsPostItNote("jxr console.log(222);", "0 1.2 -.5") - .setAttribute("onreleased", "grammarBasedSnap()") - let otherPostIt = addNewNoteAsPostItNote("jxr console.log(111);", "0 1.4 -.5") - .setAttribute("onreleased", "grammarBasedSnap()") - let postIt = addNewNoteAsPostItNote("hi this is a post-it note.", "0 1.6 -.5") - .setAttribute("onreleased", "runClosestJXR(); grammarBasedSnap()") // dunno how to share the event context back here... - // .setAttribute("onreleased", "snapNext()") // does NOT support multiple instances for now - // see https://aframe.io/docs/1.5.0/core/component.html#multiple - // maybe bind could help - - //let cloneMe = addNewNote('jxr clone me from corner', '0 0 .1', '1 1 1', 'cmd') - // should rebind parent... - //setTimeout( _ => { _ => cloneMe.object3D.parent = postIt.object3D }, 1000 ) - // should try object3D.attach() instead - //.addEventListener('loaded', - // entityIndexes( document.querySelector("[color='blue']").object3D.children[0] ) -}, 1000 ) - -// e.g document.querySelector("[color='blue']").object3D.children[0] -function entityIndexes(mesh){ // needs a mesh with a geometry, not a group - // could also traverse - let gp = mesh.geometry.attributes.position; - let wPos = []; - for(let i = 0;i < gp.count; i++){ - let p = new THREE.Vector3().fromBufferAttribute(gp, i); // set p from `position` - mesh.localToWorld(p); // p has wordl coords - wPos.push(p); - } - // many are duplicates, i.e a a cube will return 24 indexes (4 per 6 faces), not 8 - //let l = [...new Set(wPos)].length; console.log( l ) - [...new Set(wPos)].map( p => addNewNote("x", p)) - console.log( [...new Set(wPos)].length ) - // seems to add the duplicates again - // try to "de-dup" via .distanceTo() below a threshold instead -} - - -function snapToGrid(gridSize=1){ // default as 1 decimeter - let latest = selectedElements[selectedElements.length-1].element - latest.setAttribute("rotation", "0 0 0") - let pos = latest.getAttribute("position") - pos.multiplyScalar(gridSize*10).round().divideScalar(gridSize*10) - latest.setAttribute("position", pos ) -} - -// deeper question, making the rules themselves manipulable? JXR? - // So the result of the grammar becomes manipulable, but could you make the rules of the grammar itself visual? Even manipulable? - // could start by visualizing examples first e.g https://writer.com/wp-content/uploads/2024/03/grammar-1.webp -function snapMAB(){ - // multibase arithmetic blocks aka MAB cf https://en.wikipedia.org/wiki/Base_ten_block - let latest = selectedElements[selectedElements.length-1].element - let nearby = getClosestTargetElements( latest.getAttribute('position') ) - let linked = [] - if (nearby.length>0){ - latest.setAttribute("rotation", AFRAME.utils.coordinates.stringify( nearby[0].el.getAttribute("rotation") ) ) - latest.setAttribute("position", AFRAME.utils.coordinates.stringify( nearby[0].el.getAttribute("position") ) ) - latest.object3D.translateX( 1/10 ) - linked.push( latest ) - linked.push( nearby[0].el ) - let overlap = Array.from( document.querySelectorAll(".mab") ).filter( e => e.object3D.position.distanceTo( latest.object3D.position ) < 0.01 && e!=latest ) - while (overlap.length > 0 ){ - latest.object3D.translateX( 1/10 ) - linked.push( overlap[0] ) - overlap = Array.from( document.querySelectorAll(".mab") ).filter( e => e.object3D.position.distanceTo( latest.object3D.position ) < 0.01 && e!=latest ) - } - // do something special if it becomes 10, e.g become a single line, removing the "ridges" - if (linked.length > 3) - linked.map( e => Array.from( e.querySelectorAll("a-box") ).setAttribute("color", "orange") ) - - // also need to go backward too to see if it's the latest added - } -} - -function snapRightOf(){ - let latest = selectedElements[selectedElements.length-1].element - let nearby = getClosestTargetElements( latest.getAttribute('position') ) - if (nearby.length>0){ - latest.setAttribute("rotation", AFRAME.utils.coordinates.stringify( nearby[0].el.getAttribute("rotation") ) ) - latest.setAttribute("position", AFRAME.utils.coordinates.stringify( nearby[0].el.getAttribute("position") ) ) - latest.object3D.translateX( 1/10 ) - // somehow... works only the 2nd time, not the 1st?! - } -} - -function grammarBasedSnap(){ - // verify if snappable, e.g of same type (or not) - // e.g check if both have .getAttribute('value').match(prefix) or not - let latest = selectedElements[selectedElements.length-1].element - let nearby = getClosestTargetElements( latest.getAttribute('position') ) - if (nearby.length>0){ - let closest = nearby[0].el - let latestTypeJXR = latest.getAttribute('value').match(prefix) - let closestTypeJXR = latest.getAttribute('value').match(prefix) - latest.setAttribute("rotation", AFRAME.utils.coordinates.stringify( closest.getAttribute("rotation") ) ) - latest.setAttribute("position", AFRAME.utils.coordinates.stringify( closest.getAttribute("position") ) ) - if ( latestTypeJXR && closestTypeJXR ) - latest.object3D.translateX( 1/10 ) // same JXR type, snap close - else - latest.object3D.translateX( 2/10 ) // different types, snap away - // somehow... works only the 2nd time, not the 1st?! - } -} - -function cloneTarget(target){ - let el = target.cloneNode(true) - if (!el.id) - el.id = "clone_" + crypto.randomUUID() - else - el.id += "_clone_" + crypto.randomUUID() +function addFromTemplate(pos="0 0 0", rot="0 0 0", template=""){ + let el = document.createElement("a-entity") + el.innerHTML = template AFRAME.scenes[0].appendChild(el) -} - -function deleteTarget(target){ - targets = targets.filter( e => e != target) - target.remove() -} - -function runClosestJXR(){ - // ideally this would come from event details - let latest = selectedElements[selectedElements.length-1].element - let nearby = getClosestTargetElements( latest.getAttribute('position') ) - // if (nearby.length>0){ interpretJXR( nearby[0].el.getAttribute("value") ) } - nearby.map( n => interpretJXR( n.el.getAttribute("value") ) ) -} - -function notesFromArray(data, generatorName="", field="title", offset=1, step=1/10, depth=-.5 ){ - data.slice(0,maxItemsFromSources).map( (n,i) => { - addNewNote( n[field], "0 "+(offset+i*step)+" "+depth, ".1 .1 .1", null, generatorName ) - .setAttribute("onreleased","spreadItemsFromCollection('getcsljson', 1.5)") - }) -} - -function spreadItemsFromCollection( generatorName, offset=1, step=1/10, depth=-.5 ){ - getArrayFromClass(generatorName).sort((a,b)=>a.getAttribute('position').y-b.getAttribute('position').y).map( (n,i) => { - n.setAttribute('position', "0 "+(offset+i*step)+" "+depth) - n.setAttribute('rotation', "0 0 0") // could also be based on the average of all items, the first item, last one, etc - // see also snap-on-pinchended component - }) - let items = getArrayFromClass(generatorName).sort((b,a)=>a.getAttribute('position').y-b.getAttribute('position').y).map( n => n.getAttribute('value') ) - shareLiveEvent('modified list', items) + el.setAttribute("position", pos) + el.setAttribute("rotation", rot) } AFRAME.registerComponent('onemptypinch', { // changed from ondrop to be coherent with event name @@ -255,39 +67,6 @@ AFRAME.registerComponent('onemptypinch', { // changed from ondrop to be coherent } }) -function onHoveredTeleport(){ - // iterate over targets - // see instead of teleportable https://aframe.io/docs/1.5.0/components/cursor.html#configuring-the-cursor-through-the-raycaster-component - Array.from( document.querySelectorAll("[teleporter]") ).map( target => { - if ( target.states.includes( "cursor-hovered" ) ){ - target.setAttribute("material", "color", "magenta") // visited - document.getElementById('rig').setAttribute('position', target.getAttribute("position") ) - } - }) -} - -AFRAME.registerComponent('teleporter', { - init: function(){ - this.el.setAttribute("opacity", .5) - if (window.location.hash && document.querySelector(window.location.hash+"[teleporter]")) - document.getElementById('rig').setAttribute('position', document.querySelector(window.location.hash+"[teleporter]").getAttribute("position") ) - }, - events: { - mouseenter: function (e) { this.el.setAttribute("opacity", .8) }, - mouseleave: function (e) { this.el.setAttribute("opacity", .5) }, - click: function (e) { - let posTarget = new THREE.Vector3() - this.el.object3D.getWorldPosition( posTarget ) - console.log( posTarget) - document.getElementById('rig').setAttribute('position', posTarget) - // seems to work, maybe inteference with others teleporters activated unknowingly, e.g in succession - } - // this.el.getAttribute("position") ) } - // does not get proper world position - // makes it compatible with mouse on desktop ... but also somehow enable the wrist shortcut?! - } -}); - AFRAME.registerComponent('scaffolding', { init: function(){ console.log(this.el.innerHTML) @@ -310,15 +89,6 @@ AFRAME.registerComponent('scaffolding', { } }); -let page = "Wiki.VirtualRealityInterface"; -let pageFromParam = AFRAME.utils.getUrlParameter('page') -if (pageFromParam) page = pageFromParam -setTimeout( _ => { - Array.from( document.querySelectorAll("[value='"+page+"']") ).map( n => - n.setAttribute("onreleased", "console.log('dropped, should toggle display children,"+n.id+"')")); - Array.from( document.querySelectorAll("[value='"+page+"']>a-sphere") ).map( n => n.setAttribute("color", "purple")) -}, 5000) -
@@ -351,66 +121,21 @@ setTimeout( _ => { - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - + + + + + + + -