SpaSca : open SCAffolding to SPAcially and textualy explore interfaces
https://fabien.benetou.fr/pub/home/future_of_text_demo/engine/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
221 lines
11 KiB
221 lines
11 KiB
<!DOCTYPE html>
|
|
<html>
|
|
<title>SpaSca : Spatial Scaffolding</title>
|
|
<head>
|
|
<!-- Suggestions? https://git.benetou.fr/utopiah/text-code-xr-engine/issues/ -->
|
|
|
|
<!--<script src='dependencies/aframe.min.js'></script>-->
|
|
<script src='dependencies/aframe.offline.min.js'></script>
|
|
<script src="dependencies/a-console.js"></script>
|
|
<script src='dependencies/aframe-html.js'></script>
|
|
<script src='dependencies/aframe-mirror.js'></script>
|
|
<script src='dependencies/aframe-troika-text.min.js'></script>
|
|
<!--<script type="module" id=immersbundle src='dependencies/immers-client.js?save=true'></script>-->
|
|
<!--<script type="module" id=immersbundle src="https://cdn.jsdelivr.net/npm/immers-client/dist/destination.bundle.js?role=modFull"></script>-->
|
|
<!--<script src="https://threejs.org/examples/js/exporters/GLTFExporter.js"></script>-->
|
|
|
|
<script src="https://cdn.jsdelivr.net/gh/c-frame/aframe-extras@7.1.0/dist/aframe-extras.min.js"></script>
|
|
|
|
<script src="dependencies/shiki0.14.1.js"></script>
|
|
|
|
<!-- for input sharing -->
|
|
<script src='dependencies/peerjs.min.js'></script>
|
|
<!-- for content sharing, using NAF
|
|
<script src='dependencies/socket.io.slim.js'></script>
|
|
<script src="https://naf.benetou.fr/easyrtc/easyrtc.js"></script>
|
|
<script src='dependencies/networked-aframe.min.js'></script>
|
|
-->
|
|
|
|
<script src="dependencies/aframe-physics-system.min.js"></script>
|
|
|
|
<!-- still experimenting, see webdav.html -->
|
|
<script src='dependencies/webdav.js'></script>
|
|
<script src='jxr.js?123456'></script>
|
|
<!-- replacing with local copies as CDNs are like unpkg tend to be slow
|
|
<script type="module" src="https://unpkg.com/immers-client/dist/destination.bundle.js"></script>
|
|
<script src="https://aframe.io/releases/1.3.0/aframe.min.js"></script>
|
|
|
|
<script src="https://unpkg.com/aframe-troika-text/dist/aframe-troika-text.min.js"></script>
|
|
<script src="aframe-html.js"></script>
|
|
|
|
<script src="https://unpkg.com/peerjs@1.4.5/dist/peerjs.min.js"></script>
|
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/2.4.0/socket.io.slim.js"></script>
|
|
<script src="https://naf.benetou.fr/easyrtc/easyrtc.js"></script>
|
|
<script src="https://unpkg.com/networked-aframe@^0.10.0/dist/networked-aframe.min.js"></script>
|
|
|
|
<script src="https://cdn.jsdelivr.net/npm/aframe-mirror@latest/index.js"></script>
|
|
-->
|
|
|
|
<link rel="apple-touch-icon" sizes="180x180" href="apple-touch-icon.png">
|
|
<link rel="icon" type="image/png" sizes="32x32" href="favicon-32x32.png">
|
|
<link rel="icon" type="image/png" sizes="16x16" href="favicon-16x16.png">
|
|
<link rel="manifest" href="site.webmanifest">
|
|
</head>
|
|
<body>
|
|
|
|
<script>
|
|
function loadFile(element){
|
|
const file = element.files[0]
|
|
const reader = new FileReader();
|
|
reader.addEventListener( "load", () => {
|
|
writecsljsonback(reader.result)
|
|
}, false,);
|
|
|
|
if (file) {
|
|
reader.readAsText(file);
|
|
}
|
|
}
|
|
|
|
const libraryURL = 'https://webdav.benetou.fr/fotsave/ExportedItems-FromZoteroAsCSLJSON.json'
|
|
AFRAME.registerComponent('getcsljson', {
|
|
schema: {
|
|
url: {type: 'string', default: libraryURL },
|
|
},
|
|
init: function(){
|
|
let generatorName = this.attrName
|
|
fetch(this.data.url).then(res => res.json() ).then(res => { notesFromArray(res, generatorName, "title", 2, -1/10) })
|
|
//fetch(this.data.url).then(res => res.json() ).then(res => { notesFromArray(res, generatorName) })
|
|
// could use citeproc instead
|
|
// see also https://citation.js.org
|
|
}
|
|
})
|
|
|
|
function notesFromArray(data, generatorName="", field="title", offset=1, ratio=1/10, depth=-.5 ){
|
|
data.slice(0,maxItemsFromSources).map( (n,i) => {
|
|
addNewNote( n[field], "0 "+(offset+i*ratio)+" "+depth, ".1 .1 .1", null, generatorName )
|
|
.setAttribute("onreleased","spreadItemsFromCollection('getcsljson', 1.5)")
|
|
})
|
|
}
|
|
|
|
function getDataToSaveBack(){
|
|
let dataToSave = []
|
|
let unsorted = []
|
|
fetch(libraryURL).then(res => res.json() ).then(res => {
|
|
// assume unique title always present
|
|
getArrayFromClass('getcsljson').map(i=>{
|
|
unsorted.push( {data: res.filter(citation=>citation.title==i.getAttribute('value'))[0],
|
|
position: i.getAttribute('position')
|
|
})
|
|
})
|
|
dataToSave = unsorted.sort((a,b)=>b.position.y-a.position.y)
|
|
.map(i=> { if (!i.data.note) { i.data.note = JSON.stringify(i.position) } else {i.data.note += '\n' + JSON.stringify(i.position) } ; return i.data } )
|
|
// this is also where piggy-backing on CSL-JSON could be tested, e.g spatial position (or stringifoied pose) field added
|
|
// could consider appending to the .note field instead
|
|
// .position does get saved, and does not prevent to be loaded from Zotero, but does get lost after when exported again
|
|
// cf https://citeproc-js.readthedocs.io/en/latest/csl-json/markup.html#cheater-syntax-for-odd-fields
|
|
writecsljsonback(JSON.stringify(dataToSave))
|
|
})
|
|
}
|
|
|
|
//function bumpItemUp(id, generatorName){
|
|
function bumpItemUp(id, generatorName){
|
|
if (!id || !generatorName) return
|
|
// could use annotation symbols with jxr
|
|
// sets x and z to 0 though
|
|
// requires to exist for each list item
|
|
// could bump on y by ratio*1.1
|
|
|
|
document.getElementById(id).object3D.position.y += 1/10*1.1
|
|
// assuming here they are already aligned, which is there case if they have onreleased already set with spreadItemsFromCollection()
|
|
spreadItemsFromCollection(generatorName, 1.5)
|
|
}
|
|
|
|
function spreadItemsFromCollection( generatorName, offset=1, ratio=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*ratio)+" "+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
|
|
|
|
})
|
|
}
|
|
|
|
// data could come from parsing back order from getArrayFromClass('getcsljson').map(i=>i.getAttribute('position').y)
|
|
// cf https://gist.github.com/Utopiah/26bae9fecc7a921f8bfd38cf5fc91612#file-logo_vr_hubs-js-L44
|
|
// yet still needs the actual data itself and adding a comment field for position if to be used back here rather than e.g Zotero
|
|
function writecsljsonback(data){
|
|
const webdavurl = "https://webdav.benetou.fr";
|
|
const client = window.WebDAV.createClient(webdavurl)
|
|
async function w(path, data){ return await client.putFileContents(path, data); }
|
|
w("/fotsave/ExportedItems-FromZoteroAsCSLJSON.json", data )
|
|
setFeedbackHUD( "file saved" )
|
|
}
|
|
|
|
</script>
|
|
<input style='position:fixed;z-index:1; top: 0%; left: 20%; display:float'
|
|
type="file" name="file-input" accept=".json" id="file-input" onchange="loadFile(this)" />
|
|
<div style='position:fixed;z-index:1; top: 0%; left: 0%; border-bottom: 70px solid transparent; border-left: 70px solid #eee; '>
|
|
<a href="https://git.benetou.fr/utopiah/text-code-xr-engine/issues/">
|
|
<img style='position:fixed;left:10px;' title='code repository' src='gitea_logo.svg'>
|
|
</a>
|
|
</div>
|
|
|
|
<button id=mainbutton style="display:none; z-index: 1; position: absolute; width:50%; margin: auto; text-align:center; top:45%; left:30%; height:30%;" onclick="startExperience()">Start the experience (hand tracking recommended)</button>
|
|
|
|
<a-scene startfunctions getcsljson>
|
|
<!-- screenstack dynamic-view selectionboxonpinches glossary timeline issues fot
|
|
toolbox commands-from-external-json disable-components-via-url enable-components-via-url
|
|
physics="debug:true; friction: 0.01;"
|
|
networked-scene="serverURL: https://naf.benetou.fr/; adapter: easyrtc; audio: true;"
|
|
refresh-text-content-from-wiki-page="pagename:TestingPairCollaboration"
|
|
-->
|
|
<a-assets>
|
|
<template id="avatar-template"></template>
|
|
<template id="left-hand-default-template">
|
|
<a-entity networked-hand-controls="hand:left"></a-entity>
|
|
</template>
|
|
<template id="right-hand-default-template">
|
|
<a-entity networked-hand-controls="hand:right"></a-entity>
|
|
</template>
|
|
</a-assets>
|
|
|
|
<a-gltf-model hide-on-enter-ar="" src="../content/MinimalisticJapaneseRoom.glb" rotation="0 -90 0" position="2 1 -1" scale="" ></a-gltf-model>
|
|
<!-- from https://poly.pizza/m/8cWuXx5BASV -->
|
|
<!-- alt https://poly.pizza/m/cA_lcvRC4NA -->
|
|
|
|
<a-troika-text anchor=left target annotation="content:saves data back to Zotero library over WebDAV backend"
|
|
value="jxr getDataToSaveBack()" position=" -0.3 0.60 -.5" rotation="0 0 0" scale="0.1 0.1 0.1"></a-troika-text>
|
|
|
|
<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! -->
|
|
<!-- visual reminders of shortcuts, a poster on the far left/right of keyboard shortcuts -->
|
|
|
|
<a-entity light="type: ambient; color: #BBB; intensity: 0.6"></a-entity>
|
|
<a-entity light="type: directional; color: #FFF; intensity: 1.4" position="-0.5 1 1"></a-entity>
|
|
|
|
<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-sky hide-on-enter-ar color="lightgray"></a-sky>
|
|
<a-troika-text anchor=left target value="instructions : \n--right pinch to move\n--left pinch to execute" position="0 0.65 -0.2" scale="0.1 0.1 0.1"></a-troika-text>
|
|
|
|
<a-troika-text anchor=left value="jxr location.reload()" target position=" -0.3 1.30 0" rotation="0 40 0" scale="0.1 0.1 0.1"></a-troika-text>
|
|
|
|
<!--
|
|
<a-troika-text anchor=left target id="startdraw2d" annotation="content:dessiner en 2D"
|
|
value="jxr startDraw2D()" position="0 1.45 -0.1" scale="0.1 0.1 0.1"></a-troika-text>
|
|
|
|
<a-troika-text anchor=left target id="displaypred" value="jxr displayPred()" position="0 1.40 -0.1" scale="0.1 0.1 0.1"></a-troika-text>
|
|
<a-troika-text anchor=left target value="jxr tiltUpId('codeditor')" position=" -0.3 1.65 0" rotation="0 90 0" scale="0.1 0.1 0.1"></a-troika-text>
|
|
<a-troika-text anchor=left target value="jxr tiltDownId('codeditor')" position=" -0.3 1.60 0" rotation="0 90 0" scale="0.1 0.1 0.1"></a-troika-text>
|
|
-->
|
|
|
|
<!-- somehow disable hand interaction despite, according to the documentation, it should rely on world position
|
|
<a-text target value="jxr qs #rig sa position 0 0 10" position="0 1.55 .5" rotation="0 180 0" scale="0.1 0.1 0.1"></a-text>
|
|
-->
|
|
<a-console position="2 2 0" rotation="0 -45 0" font-size="34" height=1 skip-intro=true></a-console>
|
|
|
|
<!-- for Wolvic on Lynx support test -->
|
|
<a-entity thumbstick-shifting oculus-touch-controls="hand: left"></a-entity>
|
|
<a-entity thumbstick-shifting oculus-touch-controls="hand: right"></a-entity>
|
|
|
|
</a-scene>
|
|
</body>
|
|
</script>
|
|
</html>
|
|
|