Compare commits

...

6 Commits
master ... book

  1. 189
      index.html

@ -782,7 +782,7 @@ function appendToHUD(txt){
if ( textHUD == startingText)
setHUD( txt )
else
setHUD( textHUD + " " + txt )
setHUD( textHUD + txt )
}
function setHUD(txt){
@ -807,6 +807,28 @@ AFRAME.registerComponent('waistattach',{
},
});
AFRAME.registerComponent('attach',{
schema: {
target: {type: 'selector'},
},
init: function () {
var el = this.el
this.worldPosition=new THREE.Vector3();
},
tick: function () {
var worldPosition=this.worldPosition;
worldPosition.copy(this.el.position);
this.el.parent.updateMatrixWorld();
this.el.parent.localToWorld(worldPosition)
rotation = this.el.rotation.x*180/3.14 + " " + this.el.rotation.y*180/3.14 + " " + this.el.rotation.z*180/3.14
this.data.target.setAttribute("rotation", rotation)
this.data.target.setAttribute("position",
AFRAME.utils.coordinates.stringify( worldPosition ) )
},
remove: function() {
}
});
AFRAME.registerComponent('wristattachsecondary',{
schema: {
target: {type: 'selector'},
@ -889,14 +911,15 @@ AFRAME.registerComponent('pinchprimary', { // currently only 1 hand, the right o
// https://github.com/Utopiah/aframe-triggerbox-component/blob/master/aframe-triggerbox-component.js#L66
// could make trigger zones visible as debug mode
var closests = getClosestTargetElements( event.detail.position )
if (closests && closests.length > 0) // avoiding self reference
setFeedbackHUD("close enough, could stack with "+ closests[1].el.getAttribute("value") )
//if (closests && closests.length > 0) // avoiding self reference
// setFeedbackHUD("close enough, could stack with "+ closests[1].el.getAttribute("value") )
var dist = event.detail.position.distanceTo( document.querySelector("#box").object3D.position )
if (dist < .1){
setFeedbackHUD("close enough, replaced shortcut with "+ selectedElement.getAttribute("value") )
wristShortcut = selectedElement.getAttribute("value")
setTimeout( _ => setFeedbackHUD(""), 2000)
}
selectedElements.push({element:selectedElement, timestamp:Date.now(), primary:true})
// unselect current target if any
selectedElement = null;
save()
@ -921,6 +944,7 @@ AFRAME.registerComponent('pinchprimary', { // currently only 1 hand, the right o
newPinchPos.copy(event.detail.position )
pinches.push({position:newPinchPos, timestamp:Date.now(), primary:true})
dl2p = distanceLastTwoPinches()
});
this.el.addEventListener('pinchmoved', function (event) {
// move current target if any
@ -949,7 +973,6 @@ AFRAME.registerComponent('pinchprimary', { // currently only 1 hand, the right o
//selectedElement = clone
selectedElement = getClosestTargetElement( event.detail.position )
selectedElements.push({element:selectedElement, timestamp:Date.now(), primary:true})
// if close enough to a target among a list of potential targets, unselect previous target then select new
});
},
@ -1149,6 +1172,7 @@ function addNewNote( text, position=`-0.2 1.1 -0.1`, scale= "0.1 0.1 0.1", id=nu
newnote.setAttribute("scale", scale)
AFRAME.scenes[0].appendChild( newnote )
targets.push(newnote)
return newnote
}
function interpretAny( code ){
@ -1254,7 +1278,7 @@ function parseJXR( code ){
newcode = newcode.replace(/qs ([^\s]+)/ ,`document.querySelector('$1')`)
// sa X Y => .setAttribute("X", "Y")
newcode = newcode.replace(/ sa ([^\s]+) ([^\s]+)/,`.setAttribute('$1','$2')`)
newcode = newcode.replace(/ sa ([^\s]+) (.*)/,`.setAttribute('$1','$2')`)
// problematic for position as they include spaces
newcode = newcode.replace(/obsv ([^\s]+)/ ,`newNoteFromObservableCell('$1')`)
@ -1274,14 +1298,20 @@ function parseJXR( code ){
}
function interpretJXR( code ){
if (!code) return
if (code.length == 1) { // special case of being a single character, thus keyboard
if (code == ">") { // Enter equivalent
addNewNote( hudTextEl.getAttribute("value") )
content = hudTextEl.getAttribute("value")
if (Number.isFinite(Number(content))) {
loadPageRange(Number(content));
} else {
addNewNote( content )
}
setHUD("")
} else if (code == "<") { // Backspace equivalent
setHUD( hudTextEl.getAttribute("value").slice(0,-1))
} else {
appendToHUD( code )
appendToHUD( code )
}
}
if (!code.match(prefix)) return
@ -1350,12 +1380,12 @@ AFRAME.registerComponent('selectionboxonpinches', {
AFRAME.registerComponent('keyboard', {
init:function(){
let generatorName = this.attrName
const horizontaloffset = .5
const horizontalratio = 1/30
const horizontaloffset = .7
const horizontalratio = 1/20
alphabet.map( (line,ln) => {
for (var i = 0; i < line.length; i++) {
var pos = i * horizontalratio - horizontaloffset
addNewNote( line[i], pos+" "+(1.6-ln*.03)+" -.4", ".1 .1 .1", null, generatorName)
addNewNote( line[i], pos+" "+(1.6-ln*.06)+" -.4", ".1 .1 .1", null, generatorName)
}
})
}
@ -1628,6 +1658,59 @@ function cloneAndDistribute(){
}
}
function loadPageRange(start=1, end=-1, startPosition={x:0, y:1.3, z:-.7}, stepVector={x:.2, y:0, z:0}){
const baseURL = "https://fabien.benetou.fr/pub/home/future_of_text_demo/content/book_as_png/gfg_d-"
const extension = ".png"
// assumes portrait A4-ish
var rootEl = AFRAME.scenes[0]
if (end<0) end = start
let step = 0
for (let i=start; i<=end; i++){
step++
let el = document.createElement("a-box")
el.setAttribute("target", true)
//el.setAttribute("position", ""+ step/5+ " 1.3 -.7") // could be based on selectedElements last position instead
let pos = "" + startPosition.x+stepVector.x*step + " " + startPosition.y+stepVector.y*step + " " + startPosition.z+stepVector.z*step
el.setAttribute("position", pos)
// layout system could be parametric, e.g over x or y or z or another system
el.setAttribute("width", ".1")
el.setAttribute("height", ".15")
el.setAttribute("depth", ".01")
pageNumber = i
if (pageNumber<10) pageNumber = "0"+pageNumber
if (pageNumber<100) pageNumber = "0"+pageNumber
el.setAttribute("src", baseURL+pageNumber+extension)
el.setAttribute("pagenumber", pageNumber)
el.id = pageNumber + "_" + Date.now()
rootEl.appendChild(el)
let posInterface = "" + startPosition.x+stepVector.x*step + " " + startPosition.y+1+stepVector.y*step + " " + startPosition.z+stepVector.z*step
let UI = addNewNote("jxr nextPage('"+el.id+"')", posInterface, "0.1 0.1 0.1", el.id+"_interface")
//el.setAttribute("attach","target:#"+el.id+"_interface")
}
}
function nextPage(id){
console.log("nextpage()")
// assuming only direct parent for now
const baseURL = "https://fabien.benetou.fr/pub/home/future_of_text_demo/content/book_as_png/gfg_d-"
const extension = ".png"
let pageNumber = Number( id.split("_")[0] )
console.log(pageNumber+1)
loadPageRange(pageNumber+1)
}
function loadCodeFromPage(url="https://fabien.benetou.fr/Analysis/BeyondTheCaseAgainstBooks?action=source"){
// alternatively could load from a page number
fetch(url)
.then( r => r.text() )
.then(data => {
let code = data.split("\n").filter( l => (l.slice(0,2) == "[@") )[0].slice(2).slice(0,-2);
// example as PmWiki parsing
eval(code)
} )
}
// could change model opacity based on hand position, fading out when within a (very small here) safe space
</script>
<div id="observablehq-key">
@ -1635,8 +1718,8 @@ function cloneAndDistribute(){
<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 NOcommands-from-external-json >
<!-- screenstack dynamic-view selectionboxonpinches keyboard glossary timeline issues fot
toolbox disable-components-via-url enable-components-via-url NOcommands-from-external-json keyboard >
<!-- screenstack dynamic-view selectionboxonpinches glossary timeline issues fot
networked-scene="serverURL: https://naf.benetou.fr/; adapter: easyrtc; audio: true;"
-->
<a-assets>
@ -1648,69 +1731,45 @@ function cloneAndDistribute(){
<a-entity networked-hand-controls="hand:right"></a-entity>
</template>
</a-assets>
<!--
<a-video src="https://video.benetou.fr/download/videos/318c8408-c34a-430c-846d-f875dc3c343e-480.mp4"></a-video>
<a-video position="0 2 -2" src="https://video.benetou.frstreaming-playlists/hls/91634fb7-116e-43a1-a4e7-144dd92da17c/1.m3u8"></a-video>
<a-video position="0 2 -2" src="https://video.benetou.fr/videos/embed/91634fb7-116e-43a1-a4e7-144dd92da17c"></a-video>
-->
<a-entity id="player" networked="template:#avatar-template;attachTemplateToLocal:false;"
hud camera look-controls wasd-controls waistattach="target: .movebypinch" position="0 1.6 0"></a-entity>
<!-- remove for NAF equivalent
<a-entity id="my-tracked-left-hand" networked-hand-controls="hand:left" networked="template:#left-hand-default-template"
pinchsecondary wristattachsecondary="target: #box" ></a-entity>
<a-entity id="my-tracked-right-hand" networked-hand-controls="hand:right" networked="template:#right-hand-default-template"
pinchprimary ></a-entity>
<a-entity class=movebypinch >
<a-text target value="jxr document.getElementById('player').object3D.position.z++" position="0 1.15 0.1" rotation="-30 0 0" scale="0.1 0.1 0.1"></a-text>
<a-text target value="jxr player.object3D.position.z--" position="0 1.15 -0.1" rotation="-30 0 0" scale="0.1 0.1 0.1"></a-text>
<a-text target value="jxr player.object3D.position.x++" position="-0.3 1.15 0" rotation="-30 0 0" scale="0.1 0.1 0.1"></a-text>
<a-text target value="jxr player.object3D.position.x--" position="0.3 1.15 0" rotation="-30 0 0" scale="0.1 0.1 0.1"></a-text>
</a-entity>
-->
<!-- works on desktop via interpretJXR() but not in VR by trying to pinch... disabled for now for demo clarity-->
<a-entity id="rightHand" pinchprimary hand-tracking-controls="hand: right;"></a-entity>
<a-entity id="leftHand" pinchsecondary wristattachsecondary="target: #box" hand-tracking-controls="hand: left;"></a-entity>
<a-entity id="rig">
<a-entity id="player" networked="template:#avatar-template;attachTemplateToLocal:false;"
hud camera look-controls wasd-controls waistattach="target: .movebypinch" position="0 1.6 0"></a-entity>
<a-entity id="rightHand" pinchprimary hand-tracking-controls="hand: right;"></a-entity>
<a-entity id="leftHand" pinchsecondary wristattachsecondary="target: #box" hand-tracking-controls="hand: left;"></a-entity>
</a-entity>
<a-box pressable start-on-press id="box" scale="0.05 0.05 0.05" color="pink"></a-box>
<!-- could attach functions here... BUT then they have to be activable with the other hand! -->
<a-entity id="scaledworld" class="hidableassets" scale=".05 .05 .05" position="0 1.45 -1"><!-- can't be used for interactions otherwise becomes indirect-->
<a-box position="-0.1 1.2 -0.3" scale="0.5 0.5 0.5" rotation="0 45 0" color="#4CC3D9"></a-box>
<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 hide-on-enter-ar="" id="environment" class="hidableenvironment" gltf-model="../content/virtual_reality_meta_room_2022.glb" scale="" position="-0.10754 0.2 6.25885" rotation="0 90 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-sky hide-on-enter-ar src="../content/nebula.jpg"></a-sky>
<a-text target value="instructions : pinch numbers then > to open a page " position="0 1.65 -0.2" scale="0.1 0.1 0.1"></a-text>
<a-text target value="jxr loadPageRange(1,13)" position="0 1.35 -0.1" scale="0.1 0.1 0.1"></a-text>
<a-text target value="jxr loadCodeFromPage()" position="0 1.45 -0.1" scale="0.1 0.1 0.1"></a-text>
<a-text target value="jxr qs #rig sa position 0 0 10" position="0 1.55 -0.1" scale="0.1 0.1 0.1"></a-text>
<!-- permanent offline persistent e-ink based, rM2 size, reminder
<a-plane position="0 2 -2" scale="4 4 4" mirror></a-plane>
<a-plane position="0 1 -1" scale="0.21 0.15 1" rotation="-30 0 0" wireframe="true"></a-plane>
-->
<a-text target value="instructions : pinch twice for distance then select element then execute cloneAndDistribute() " position="0 1.65 -0.2" scale="0.1 0.1 0.1"></a-text>
<a-text target value="jxr AFRAME.scenes[0].components.inspector.openInspector()" position="0 1.25 -0.2" scale="0.1 0.1 0.1"></a-text>
<a-text target value="jxr observe selectedElement" position="0 1.15 -0.2" scale="0.1 0.1 0.1"></a-text>
<a-text target value="jxr observe dl2p" position="0 1.35 -0.2" scale="0.1 0.1 0.1"></a-text>
<a-text target value="jxr cloneAndDistribute()" position="0 1.45 -0.2" scale="0.1 0.1 0.1"></a-text>
<a-box target position="-0.1 1.2 -0.3" scale=".1 1 0.01" rotation="0 45 0"
src="https://vatelier.benetou.fr/MyDemo/newtooling/textures/fabien.benetou.fr_Analysis_LibrarianMoveWalls.png"></a-box>
<a-troika-text value="SpaSca : Spatial Scaffolding" anchor="left" outline-width="5%" font="../content/ChakraPetch-Regular.ttf" position="-5.26197 6.54224 -1.81284" scale="4 4 5" rotation="90 0 0" troika-text="outlineWidth: 0.01; strokeColor: #ffffff" material="flatShading: true; blending: additive; emissive: #c061cb"></a-troika-text>
<a-entity id="featureN2">
<a-video rotation="0 180 0" position="0 2 10.5" scale=".5 .5 .5" src="../content/features/wrist.mp4"></a-video>
<a-text rotation="0 180 0" target value="wrist" position="0 2.25 10.2" scale=".5 .5 .5"></a-text>
<a-text rotation="0 180 0" target value="tap on your wrist to activate a shortcut" position="0 1.55 10.2" scale=".1 .1 .1"></a-text>
<a-text rotation="0 180 0" target value="jxr shortcut()" position="0 1.35 10.1" scale="0.1 0.1 0.1"></a-text>
</a-entity>
<a-entity id="featureN">
<a-image rotation="0 180 0" position="-2 2 10.5" scale=".5 .5 .5" src="../content/features/containers.jpg"></a-image>
<a-text rotation="0 180 0" target value="containers" position="-2 2.25 10.2" scale=".5 .5 .5"></a-text>
<a-text rotation="0 180 0" target value="use the dxr prefix to send data to containers\n(requires backend)" position="-2 1.55 10.2" scale=".1 .1 .1"></a-text>
<a-text rotation="0 180 0" target value="dxr python print(7)" position="-2 1.35 10.1" scale="0.1 0.1 0.1"></a-text>
</a-entity>
</a-scene>
</body>

Loading…
Cancel
Save