@ -116,6 +116,7 @@ var generators = "line-link-entities link screenstack dynamic-view selectionboxo
+ "commands-from-external-json glossary timeline issues web-url background-via-url observableui hidableenvironmentfot fot"
// could be an array proper completed on each relevant component registration
var heightAdjustableClasses = ["commands-from-external-json"]
const feedbackHUBClearTime = 5000
// could add a dedicated MakeyMakey mode with a fixed camera, e.g bird eye view, and an action based on some physical input that others, thanks to NAF, could see or even use.
// ?inputmode=makeymakey
@ -640,7 +641,7 @@ AFRAME.registerComponent('screenstack', {
});
function getClosestTargetElements( pos, threshold=0.05 ){
// TODO Bbox intersects rather than position
// TODO Bbox intersects rather than position, especially as most people try to pick from center rather than beginning
return targets.filter( e => e.getAttribute("visible") == true).map( t => { return { el: t, dist : pos.distanceTo(t.getAttribute("position") ) } })
.filter( t => t.dist < threshold )
.sort( (a,b) => a.dist > b.dist)
@ -748,6 +749,7 @@ function appendToFeedbackHUD(txt){
function setFeedbackHUD(txt){
document.querySelector("#feedbackhud").setAttribute("value",txt)
setTimeout( _ => document.querySelector("#feedbackhud").setAttribute("value",""), feedbackHUBClearTime)
}
function appendToHUD(txt){
@ -897,7 +899,21 @@ AFRAME.registerComponent('pinchprimary', { // currently only 1 hand, the right o
//targets.push( clone )
//selectedElement = clone
//setFeedbackHUD( "pinched" ) // works well even close to the HMD, closer than the HUD
selectedElement = getClosestTargetElement( event.detail.position )
if (selectedElement) { // never works with #typinghud
setFeedbackHUD( "selectedElement:"+selectedElement.getAttribute("value") )
// somehow never happens trying to get text from HUD
if (selectedElement.id == "typinghud"){
setFeedbackHUD( "cloned typinghud" )
var clone = selectedElement.cloneNode()
clone.removeAttribute("id")
clone.className += "typinghud"
AFRAME.scenes[0].appendChild( clone )
targets.push( clone )
selectedElement = clone
}
}
// if close enough to a target among a list of potential targets, unselect previous target then select new
});
},
@ -1052,6 +1068,7 @@ AFRAME.registerComponent('hud', {
this.el.appendChild( feedbackHUDel )
var typingHUDel = document.createElement("a-troika-text")
typingHUDel.id = "typinghud"
targets.push(typingHUDel)
typingHUDel.setAttribute("value", startingText)
typingHUDel.setAttribute("position", "-0.05 0 -0.2")
typingHUDel.setAttribute("scale", "0.05 0.05 0.05")
@ -1310,6 +1327,31 @@ AFRAME.registerComponent('glossary', {
},
});
AFRAME.registerComponent('fossxr', {
init:function(){
let generatorName = this.attrName
fetch("https://fabien.benetou.fr/Testing/FOSSXR2022?action=source#" + Date.now()).then(res => res.text() ).then(res => {
res.split("\n").filter(e => (e.match(/^\* /))).slice(0,maxItemsFromSources).map( (n,i) => {
found = added.find((str) => str === n)
if (typeof found === 'undefined'){
added.push(n)
addNewNote( n, "-.1 "+(1+i/10)+" -.5", ".1 .1 .1", null, generatorName )
}
})
})
}
});
function saveBackList(){
data = Array.from( document.querySelectorAll(".fossxr") ).sort((a, b) => a.object3D.position.y - b.object3D.position.y ).map( e => e.getAttribute("value")).join("%0a")
configurableURL="https://fabien.benetou.fr/PIMVRdata/FOSSXR?action="
fetch(configurableURL+'edit', {
method: 'POST',
headers: {'Content-Type':'application/x-www-form-urlencoded'},
body: "post=1& author=PIMVR& authpw=edit_password& text="+JSON.stringify( data )
}).then(res => res).then(res => setFeedbackHUD("saved remotely"+ res))
}
AFRAME.registerComponent('fot', {
init:function(){
},
@ -1399,6 +1441,7 @@ AFRAME.registerComponent('adjust-height-in-vr', {
max = Math.max.apply(null, Array.from( document.querySelectorAll("."+c) ).map( e => e.object3D.position.y) )
min = Math.min.apply(null, Array.from( document.querySelectorAll("."+c) ).map( e => e.object3D.position.y) )
pushDownClass(c, userHeight - (max-min)/2 )
// to adjust, works well while seated but now on floor or standing up
setFeedbackHUD( "adjusted height by:" + ( userHeight - (max-min)/2 ) )
} )
}, 100 )
@ -1437,8 +1480,9 @@ fetch('./templates.json')
]
links = []
//fetch("commands.json").then(res => res.json() ).then(res => {
var commandsURL = "https://fabien.benetou.fr/PIMVRdata/CabinCommands?action=source"
commandsURL = "https://fabien.benetou.fr/PIMVRdata/EngineSequentialTutorialCommands?action=source" // new default
var commandsURL = "https://fabien.benetou.fr/PIMVRdata/CabinCommands?action=source" // should become a global parameter
// commandsURL = "https://fabien.benetou.fr/PIMVRdata/EngineSequentialTutorialCommands?action=source" // new default
commandsURL = "https://fabien.benetou.fr/PIMVRdata/EngineFOSSXRCommands?action=source" // new default
var src = AFRAME.utils.getUrlParameter('commands-url')
if (src & & src != "") commandsURL = src
fetch(commandsURL).then(res => res.json() ).then(res => {
@ -1458,7 +1502,7 @@ fetch('./templates.json')
},
});
function save(){
function save(classname=null ){
var data = targets.map( e => { return {
localname: e.localName,
src: e.getAttribute("src"),
@ -1498,8 +1542,9 @@ function remoteLoad(){
// both might not be ideal directly in the original JSON but could be attachement as URLs
}
function remoteSave(){
fetch(url+'edit', {
function remoteSave(configurableURL="https://fabien.benetou.fr/PIMVRdata/CabinData?action="){
// targets could be filtered down, e.g .fossxr only
fetch(configurableURL+'edit', {
method: 'POST',
headers: {'Content-Type':'application/x-www-form-urlencoded'},
body: "post=1& author=PIMVR& authpw=edit_password& text="+JSON.stringify( cabin )
@ -1530,12 +1575,13 @@ function switchSide(){
< div id = "observablehq-viewof-offsetExample-ab4c1560" > < / div >
< div id = "observablehq-result_as_html-ab4c1560" > < / div >
< / div >
< a-scene cursor = "rayOrigin: mouse" raycaster = "objects: [html]; interval:100;" adjust-height-in-vr
toolbox disable-components-via-url enable-components-via-url commands-from-external-json >
< a-scene cursor = "rayOrigin: mouse" raycaster = "objects: [html]; interval:100;"
disable-components-via-url enable-components-via-url >
<!-- screenstack dynamic - view selectionboxonpinches keyboard glossary timeline issues fot
networked-scene="serverURL: https://naf.benetou.fr/; adapter: easyrtc; audio: true;"
-->
< a-assets >
< img id = "bookpageconverted" crossOrigin = "anonymous" src = "/pub/home/moby_p10.epub.pdf.inverted.jpg" >
< template id = "avatar-template" > < a-cylinder opacity = .3 scale = ".2 1.2 .2" networked-audio-source > < / a-cylinder > < / template >
< template id = "left-hand-default-template" >
< a-entity networked-hand-controls = "hand:left" > < / a-entity >
@ -1569,23 +1615,11 @@ function switchSide(){
< a-sphere position = "0 1.25 -5" radius = "1.25" color = "#EF2D5E" > < / a-sphere >
< a-cylinder position = "1 0.75 -3" radius = "0.5" height = "1.5" color = "#FFC65D" > < / a-cylinder >
< / a-entity >
< a-image id = background background-via-url visible = false position = "0 1.5 -1.02" scale = "2 1 1" src = "" > < / a-image >
< a-image visible = false class = mural-instructions src = "../content/future_of_text_symposium/mappinghypertext_typesofdiagrams2.png"
rotation="0 -45 0" position="1.5 1.7 -.7" scale=".4 .2 .2" >< / a-image >
< a-image visible = false class = mural-instructions src = "../content/future_of_text_symposium/mappinghypertext_typesofdiagrams1.png"
rotation="0 -45 0" position="1.5 1.4 -.7" scale=".4 .2 .2" >< / a-image >
< a-image visible = false class = mural-instructions src = "../content/future_of_text_symposium/mappinghypertext_semanticanalysisofdiagrams.png"
rotation="0 45 0" position="-1.5 1.7 -.7" scale=".4 .2 .2" >< / a-image >
< a-image visible = false class = mural-instructions src = "../content/future_of_text_symposium/mappinghypertext_mappingfusion.png"
rotation="0 45 0" position="-1.5 1.4 -.7" scale=".4 .2 .2" >< / a-image >
<!-- visual reminders of shortcuts, a poster on the far left/right of keyboard shortcuts -->
<!-- assets CabanaAndCurtains.glb Pond.glb TempleOfLife.glb JapaneseRoom.glb -->
< a-entity hide-on-enter-ar id = "environment" class = "hidableenvironment" gltf-model = "url(../content/Pond.glb)" scale = "80 80 80" position = "0 0.2 0.15" rotation = "0 -90 0" > < / a-entity >
< a-entity hide-on-enter-ar class = "hidableenvironment" gltf-model = "url(../content/CabanaAndCurtains.glb)" scale = ".010 .010 .010" position = "0 0.2 0.15" rotation = "0 0 0" > < / a-entity >
< a-entity light = "type: ambient; color: #BBB; intensity: 0.6" > < / a-entity >
< a-entity light = "type: directional; color: #FFF; intensity: 0.6" position = "-0.5 1 1" > < / a-entity >
< a-sky hide-on-enter-ar color = "#add8e6" > < / a-sky >
< a-entity layer = "type: quad; src:#bookpageconverted" rotation = "45 0 0" position = "0 5 -5" > < / a-entity >
< a-troika-text anchor = "left" target = "" id = "locationreload" value = "jxr location.reload()" position = "0 1.20 -0.1" scale = "0.1 0.1 0.1" troika-text = "" class = "collidable" > < / a-troika-text >
< a-sky hide-on-enter-ar color = "black" > < / a-sky >
<!-- permanent offline persistent e - ink based, rM2 size, reminder
< a-plane position = "0 2 -2" scale = "4 4 4" mirror > < / a-plane >