|
|
|
@ -9,61 +9,12 @@ |
|
|
|
|
<script src='dependencies/webdav.js'></script> |
|
|
|
|
<script src='jxr-core.js?12345'></script> |
|
|
|
|
<script src='jxr-postitnote.js?13235'></script> |
|
|
|
|
<!-- <script src="https://unpkg.com/aframe-curves@1.0.0/build/curve.min.js"></script> --> |
|
|
|
|
<script src="dependencies/aframe-curve.js"></script> |
|
|
|
|
</head> |
|
|
|
|
<body> |
|
|
|
|
|
|
|
|
|
<script> |
|
|
|
|
/* |
|
|
|
|
SpaSca circular menu inspired by https://www.olegfrolov.design/spatialcomputing or the Meta OS menu |
|
|
|
|
|
|
|
|
|
on empty pinch moving, if (moving duration above threshold 500ms) |
|
|
|
|
then |
|
|
|
|
show menu nearby position with JXR commands that hides on released, |
|
|
|
|
on moving |
|
|
|
|
highlight closest snippet |
|
|
|
|
rewrite nearby getClosestTargetElements() to be only over a subset or targets, i.e the ones from active menu |
|
|
|
|
on release |
|
|
|
|
if (nearby one of the created JXR snippets), execute it |
|
|
|
|
remove those JXR commands |
|
|
|
|
|
|
|
|
|
<a-troika-text id="spatial-introspection-test" anchor=left value="console.log('executing from secondary pinch');" |
|
|
|
|
onreleased="console.log('run on released')" |
|
|
|
|
onpicked="console.log('run on picked')" |
|
|
|
|
target position=" -0.3 1.35 0" rotation="0 40 0" scale="0.1 0.1 0.1"> |
|
|
|
|
</a-troika-text> |
|
|
|
|
*/ |
|
|
|
|
var library |
|
|
|
|
AFRAME.registerComponent('library-load', { |
|
|
|
|
init: function(){ |
|
|
|
|
//fetch("../content/library-acm22.json").then( res => res.json() ).then( res => { |
|
|
|
|
fetch("https://webdav.benetou.fr/fotsave/test_newfot.json").then( res => res.json() ).then( res => { |
|
|
|
|
library = res |
|
|
|
|
console.log(res) |
|
|
|
|
res.documents.map( (doc,i) => { |
|
|
|
|
if (doc.customData[0].position) |
|
|
|
|
addNewNote( doc.title, doc.customData[0].position ) |
|
|
|
|
else |
|
|
|
|
addNewNote( doc.title, '.5 '+(1+i/50)+' -.5' ) |
|
|
|
|
.setAttribute("onreleased", "updateDatasetThenSave(e.detail.element)") |
|
|
|
|
}) |
|
|
|
|
|
|
|
|
|
}) |
|
|
|
|
} |
|
|
|
|
}) |
|
|
|
|
|
|
|
|
|
function updateDatasetThenSave(element){ |
|
|
|
|
if (!library) return |
|
|
|
|
let pos = element.getAttribute('position') |
|
|
|
|
let title = element.getAttribute('value') |
|
|
|
|
console.log(pos, title) |
|
|
|
|
library.documents.filter( el => el.title == title ).map( found => found.customData[0].position = pos ) |
|
|
|
|
//library.documents.filter( el => el.title == title ).map( found => console.log( found.customData[0] ) ) |
|
|
|
|
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/test_newfot.json", JSON.stringify(library) ) |
|
|
|
|
setFeedbackHUD( "file saved" ) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
function cloneTarget(target){ |
|
|
|
|
let el = target.cloneNode(true) |
|
|
|
@ -86,106 +37,6 @@ function runClosestJXR(){ |
|
|
|
|
if (el) interpretJXR( el.getAttribute("value") ) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
// should move to jxr-core.js |
|
|
|
|
AFRAME.registerComponent('onemptypinch', { // changed from ondrop to be coherent with event name |
|
|
|
|
init: function(){ |
|
|
|
|
AFRAME.scenes[0].addEventListener('enter-vr', e => { |
|
|
|
|
console.log('entered vr') |
|
|
|
|
document.querySelector("[cursor]").setAttribute("visible", "true") |
|
|
|
|
document.querySelector("[camera]").setAttribute("cursor", "") |
|
|
|
|
}) |
|
|
|
|
this.menuTargets = [] |
|
|
|
|
|
|
|
|
|
this.menuEl = document.createElement("a-box") |
|
|
|
|
this.menuEl.setAttribute("width", ".01") |
|
|
|
|
this.menuEl.setAttribute("height", ".01") |
|
|
|
|
this.menuEl.setAttribute("depth", ".01") |
|
|
|
|
//this.menuEl.setAttribute("scale", ".01 .01 .01") // breaking moving targets as children |
|
|
|
|
this.menuEl.setAttribute("opacity", 0) |
|
|
|
|
this.menuEl.setAttribute("color", "red") |
|
|
|
|
this.menuEl.setAttribute("wireframe", "true") |
|
|
|
|
this.menuEl.id = "handprimarymenu" |
|
|
|
|
this.menuOpacity = 0 |
|
|
|
|
AFRAME.scenes[0].appendChild(this.menuEl) |
|
|
|
|
|
|
|
|
|
let namedCSSColors = [ "aliceblue", "antiquewhite", "aqua", "aquamarine", "azure", "beige", "bisque", "black", "blanchedalmond", "blue", "blueviolet", "brown", "burlywood", "cadetblue", "chartreuse", "chocolate", "coral", "cornflowerblue", "cornsilk", "crimson", "cyan", "darkblue", "darkcyan", "darkgoldenrod", "darkgray", "darkgreen", "darkkhaki", "darkmagenta", "darkolivegreen", "darkorange", "darkorchid", "darkred", "darksalmon", "darkseagreen", "darkslateblue", "darkslategray", "darkturquoise", "darkviolet", "deeppink", "deepskyblue", "dimgray", "dodgerblue", "firebrick", "floralwhite", "forestgreen", "fuchsia", "gainsboro", "ghostwhite", "gold", "goldenrod", "gray", "green", "greenyellow", "honeydew", "hotpink", "indianred", "indigo", "ivory", "khaki", "lavender", "lavenderblush", "lawngreen", "lemonchiffon", "lightblue", "lightcoral", "lightcyan", "lightgoldenrodyellow", "lightgreen", "lightgrey", "lightpink", "lightsalmon", "lightseagreen", "lightskyblue", "lightslategray", "lightsteelblue", "lightyellow", "lime", "limegreen", "linen", "magenta", "maroon", "mediumaquamarine", "mediumblue", "mediumorchid", "mediumpurple", "mediumseagreen", "mediumslateblue", "mediumspringgreen", "mediumturquoise", "mediumvioletred", "midnightblue", "mintcream", "mistyrose", "moccasin", "navajowhite", "navy", "navyblue", "oldlace", "olive", "olivedrab", "orange", "orangered", "orchid", "palegoldenrod", "palegreen", "paleturquoise", "palevioletred", "papayawhip", "peachpuff", "peru", "pink", "plum", "powderblue", "purple", "red", "rosybrown", "royalblue", "saddlebrown", "salmon", "sandybrown", "seagreen", "seashell", "sienna", "silver", "skyblue", "slateblue", "slategray", "snow", "springgreen", "steelblue", "tan", "teal", "thistle", "tomato", "turquoise", "violet", "wheat", "white", "whitesmoke", "yellow", "yellowgreen"] |
|
|
|
|
|
|
|
|
|
//let colors =["green", "blue", "orange", "yellow", "brown", "black"].map( (c,i) => { |
|
|
|
|
let colors = namedCSSColors.slice(0,20).map( (c,i) => { |
|
|
|
|
let newEl = document.createElement("a-box") |
|
|
|
|
let x = (i/100+.01) |
|
|
|
|
let z = -.1 // i%10 |
|
|
|
|
newEl.setAttribute("position", "" + x + " 0 " + z) |
|
|
|
|
newEl.setAttribute("opacity", 0) |
|
|
|
|
newEl.setAttribute("scale", ".01 .01 .01") |
|
|
|
|
newEl.setAttribute("wireframe", "true") |
|
|
|
|
newEl.setAttribute("color", c ) |
|
|
|
|
newEl.setAttribute("target", "true" ) // does not work as on same hand |
|
|
|
|
// requires to enter a mode, i.e edit mode, that would let it be visible and movable |
|
|
|
|
// seems to lose position while rotation does work |
|
|
|
|
// wondering if truly empty, should be exclusive events, can't have emptypinch and pinched at the same time |
|
|
|
|
// note that getClosestElements() filter out non visible element, but not when opacity is 0 |
|
|
|
|
// currently we can move now elements that are with opacity 0 yet visible |
|
|
|
|
// maybe position works but scale is not taking into account the parent scale, only its position, so we move too little |
|
|
|
|
// try to then stick to scale 1 for now then |
|
|
|
|
this.menuEl.appendChild( newEl ) |
|
|
|
|
this.menuTargets.push( newEl ) |
|
|
|
|
}) |
|
|
|
|
this.menuTargets.push( this.menuEl ) |
|
|
|
|
|
|
|
|
|
}, |
|
|
|
|
// could support multi |
|
|
|
|
events: { |
|
|
|
|
emptypinch: function (e) { |
|
|
|
|
this.menuEl.setAttribute("position", e.detail.position) |
|
|
|
|
// works with AFRAME.scenes[0].emit('emptypinch', {position:"0 0 0"}) |
|
|
|
|
let code = this.el.getAttribute('onemptypinch') |
|
|
|
|
// if multi, should also look for onreleased__ not just onreleased |
|
|
|
|
try { |
|
|
|
|
eval( code ) // should be jxr too e.g if (txt.match(prefix)) interpretJXR(txt) |
|
|
|
|
} catch (error) { |
|
|
|
|
console.error(`Evaluation failed with ${error}`); |
|
|
|
|
} |
|
|
|
|
}, |
|
|
|
|
emptypinchmoved: function (e) { |
|
|
|
|
let foundElement = getClosestElement( e.detail.position, threshold=0.01, this.menuTargets ) |
|
|
|
|
this.menuTargets.map( mt => mt.setAttribute("wireframe", "true") ) |
|
|
|
|
if ( foundElement ) foundElement.setAttribute("wireframe", "false") |
|
|
|
|
|
|
|
|
|
if (this.menuOpacity < 1) { |
|
|
|
|
this.menuOpacity += .01 |
|
|
|
|
this.menuTargets.map( mt => mt.setAttribute("opacity", this.menuOpacity) ) |
|
|
|
|
} |
|
|
|
|
let code = this.el.getAttribute('onemptypinchmoved') |
|
|
|
|
// if multi, should also look for onreleased__ not just onreleased |
|
|
|
|
try { |
|
|
|
|
eval( code ) // should be jxr too e.g if (txt.match(prefix)) interpretJXR(txt) |
|
|
|
|
} catch (error) { |
|
|
|
|
console.error(`Evaluation failed with ${error}`); |
|
|
|
|
} |
|
|
|
|
}, |
|
|
|
|
emptypinchreleased: function (e) { |
|
|
|
|
// could also check if above this.menuOpacity threshold, e.g not doing below .3 to avoid unexpected action |
|
|
|
|
let foundElement = getClosestElement( e.detail.position, threshold=0.02, this.menuTargets ) |
|
|
|
|
// does not seem to execute anymore after teleporting, did work before though |
|
|
|
|
if ( foundElement ){ |
|
|
|
|
document.getElementById("box").setAttribute("color", foundElement.getAttribute("color") ) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
this.menuOpacity = 0 |
|
|
|
|
this.menuEl.setAttribute("opacity", this.menuOpacity) |
|
|
|
|
this.menuTargets.map( mt => mt.setAttribute("opacity", this.menuOpacity) ) |
|
|
|
|
let code = this.el.getAttribute('onemptypinchreleased') |
|
|
|
|
// if multi, should also look for onreleased__ not just onreleased |
|
|
|
|
try { |
|
|
|
|
eval( code ) // should be jxr too e.g if (txt.match(prefix)) interpretJXR(txt) |
|
|
|
|
} catch (error) { |
|
|
|
|
console.error(`Evaluation failed with ${error}`); |
|
|
|
|
} |
|
|
|
|
}, |
|
|
|
|
} |
|
|
|
|
}) |
|
|
|
|
|
|
|
|
|
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 |
|
|
|
@ -197,18 +48,6 @@ function onHoveredTeleport(){ |
|
|
|
|
}) |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
AFRAME.registerComponent('teleporter', { |
|
|
|
|
init: function(){ |
|
|
|
|
this.el.setAttribute("opacity", .5) |
|
|
|
|
}, |
|
|
|
|
events: { |
|
|
|
|
mouseenter: function (e) { this.el.setAttribute("opacity", .8) }, |
|
|
|
|
mouseleave: function (e) { this.el.setAttribute("opacity", .5) }, |
|
|
|
|
click: function (e) { document.getElementById('rig').setAttribute('position', this.el.getAttribute("position") ) } |
|
|
|
|
// makes it compatible with mouse on desktop ... but also somehow enable the wrist shortcut?! |
|
|
|
|
} |
|
|
|
|
}); |
|
|
|
|
|
|
|
|
|
</script> |
|
|
|
|
<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/"> |
|
|
|
@ -217,9 +56,42 @@ AFRAME.registerComponent('teleporter', { |
|
|
|
|
</div> |
|
|
|
|
|
|
|
|
|
<a-scene startfunctions library-load onemptypinch="onHoveredTeleport()" > |
|
|
|
|
<a-gltf-model hide-on-enter-ar="" id="environment" src="../content/CubeRoom.glb" rotation="0 -90 0" position="0 0 1" scale="" ></a-gltf-model> |
|
|
|
|
<a-gltf-model visible="false" hide-on-enter-ar="" id="environment" src="../content/CubeRoom.glb" rotation="0 -90 0" position="0 0 1" scale="" ></a-gltf-model> |
|
|
|
|
<!-- Cube Room by Anonymous [CC-BY] via Poly Pizza --> |
|
|
|
|
|
|
|
|
|
<a-sphere animation="property: rotation; to: 0 360 0; dur: 20000; easing: linear; loop: true" position="-2 1 -1" radius=".5" src="../content/earth.jpg"></a-sphere> |
|
|
|
|
<a-sphere animation="property: rotation; to: 0 360 0; dur: 20000; easing: linear; loop: true" position="1 1 -1" radius=".2" src="../content/moon.jpg"></a-sphere> |
|
|
|
|
|
|
|
|
|
<a-draw-curve curveref="#track1" color="#0000ff"></a-draw-curve> |
|
|
|
|
|
|
|
|
|
<a-curve id="track1"> |
|
|
|
|
<a-curve-point position="-3 2 -1"></a-curve-point> |
|
|
|
|
<a-curve-point position="-3 0 -1"></a-curve-point> |
|
|
|
|
<a-curve-point position="1 1.5 -1"></a-curve-point> |
|
|
|
|
<a-curve-point position="1.5 1 -1"></a-curve-point> |
|
|
|
|
<a-curve-point position="1 0.5 -1"></a-curve-point> |
|
|
|
|
<a-curve-point position="-3 2 -1"></a-curve-point> |
|
|
|
|
</a-curve> |
|
|
|
|
|
|
|
|
|
<a-entity follow-path="incrementBy:0.01; throttleTo:30" rotation="0 0 -90" position="-1 0 -1"> |
|
|
|
|
<a-cylinder position="-0.06 0 0" height=".4" radius=".02" color="white"> |
|
|
|
|
<a-cone position="0 0.23 0" height=".05" radius-top="0" radius-bottom=".02" color="white"></a-cone> |
|
|
|
|
</a-cylinder> |
|
|
|
|
<a-cylinder position="0 0.1 0" height=".6" radius=".04" color="orange"> |
|
|
|
|
<a-cone position="0 0.35 0" height=".1" radius-top="0" radius-bottom=".04" color="orange"></a-cone> |
|
|
|
|
</a-cylinder> |
|
|
|
|
<a-cylinder position="0 0.4 0" height=".2" radius=".03" color="white"> |
|
|
|
|
<a-cone position="0 .15 0" height=".1" radius-top="0" radius-bottom=".03" color="white"></a-cone> |
|
|
|
|
</a-cylinder> |
|
|
|
|
<a-cylinder position="0.06 0 0" height=".4" radius=".02" color="white"> |
|
|
|
|
<a-cone position="0 0.23 0" height=".05" radius-top="0" radius-bottom=".02" color="white"></a-cone> |
|
|
|
|
</a-cylinder> |
|
|
|
|
</a-entity> |
|
|
|
|
|
|
|
|
|
<!-- |
|
|
|
|
<a-gltf-model scale=".01 .01 .01" position="0 1 -.4" src="../content/artemis_from_fbx_optim.glb" target></a-gltf-model> |
|
|
|
|
--> |
|
|
|
|
|
|
|
|
|
<a-entity id="rig"> |
|
|
|
|
<a-entity id="player" networked="template:#avatar-template;attachTemplateToLocal:false;" |
|
|
|
|
hud camera look-controls wasd-controls position="0 1.6 0"> |
|
|
|
@ -238,7 +110,7 @@ AFRAME.registerComponent('teleporter', { |
|
|
|
|
|
|
|
|
|
<a-troika-text value="SpaSca : Spatial Scaffolding" anchor="left" outline-width="5%" font="../content/ChakraPetch-Regular.ttf" position="-3 5 -2" |
|
|
|
|
scale="3 3 3" rotation="80 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-sky hide-on-enter-ar src="../content/TychoSkymapII.t3_04096x02048.jpg"></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 onNextPrimaryPinch(deleteTarget)" target position=" -0.3 1.50 0" rotation="0 40 0" scale="0.1 0.1 0.1"></a-troika-text> |
|
|
|
@ -247,41 +119,6 @@ AFRAME.registerComponent('teleporter', { |
|
|
|
|
<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 value="jxr makeAnchorsVisibleOnTargets()" target position=" -0.3 1.20 0" rotation="0 40 0" scale="0.1 0.1 0.1"></a-troika-text> |
|
|
|
|
|
|
|
|
|
<a-troika-text anchor=left value="forceXaxis toggling" |
|
|
|
|
onreleased="console.log('run on released');forceXaxis=!forceXaxis" |
|
|
|
|
onpicked="console.log('run on picked');forceXaxis=!forceXaxis" |
|
|
|
|
target position=" -0.3 1.45 0" rotation="0 40 0" scale="0.1 0.1 0.1"></a-troika-text> |
|
|
|
|
|
|
|
|
|
<a-troika-text anchor=left value="translate targets" |
|
|
|
|
onreleased="toggleTranslateTargets()" |
|
|
|
|
onpicked="toggleTranslateTargets()" |
|
|
|
|
target position=" 1 1.45 -.2" rotation="0 -40 0" scale="0.1 0.1 0.1"></a-troika-text> |
|
|
|
|
|
|
|
|
|
<a-troika-text anchor=left value="jxr setTimeout( _ => toggleAttachToSelf(), 1000); toggleAttachToSelf()" target position=" -0.3 1.25 0" rotation="0 40 0" scale="0.1 0.1 0.1"></a-troika-text> |
|
|
|
|
|
|
|
|
|
<a-box teleporter height=".1" class="teleportable" material="color: cyan" position="3.5 0 -3.5" ></a-box> |
|
|
|
|
<a-box teleporter height=".1" class="teleportable" material="color: cyan" position="-4 0 4" ></a-box> |
|
|
|
|
<a-box teleporter height=".1" class="teleportable" material="color: cyan" position="3 3 4" > |
|
|
|
|
<a-troika-text anchor=left value="jxr location.reload()" target position="0 1.30 -.5" rotation="0 0 0" scale="0.1 0.1 0.1"></a-troika-text> |
|
|
|
|
<!-- works to execute but not to move, should either reparent or take into account the parent offset while moving --> |
|
|
|
|
<!-- see pinchmoved in primary pinch in jxr-core.js as potential solution --> |
|
|
|
|
</a-box> |
|
|
|
|
<a-box teleporter height=".1" class="teleportable" material="color: cyan" position="0 0 0" ></a-box> |
|
|
|
|
|
|
|
|
|
<a-troika-text id="spatial-introspection-test" anchor=left value="console.log('executing from secondary pinch');" |
|
|
|
|
onreleased="console.log('run on released')" |
|
|
|
|
onpicked="console.log('run on picked')" |
|
|
|
|
target position=" -0.3 1.35 0" rotation="0 40 0" scale="0.1 0.1 0.1"> |
|
|
|
|
</a-troika-text> |
|
|
|
|
|
|
|
|
|
<!-- should probably do so for the menu root too --> |
|
|
|
|
<a-troika-text anchor=left value="jxr Array.from( document.getElementById('handprimarymenu').children ).map( el => el.setAttribute('opacity', 0))" |
|
|
|
|
target position=" -0.3 1.53 0" rotation="0 40 0" scale="0.1 0.1 0.1"> |
|
|
|
|
</a-troika-text> |
|
|
|
|
<a-troika-text anchor=left value="jxr Array.from( document.getElementById('handprimarymenu').children ).map( el => el.setAttribute('opacity', 1))" |
|
|
|
|
target position=" -0.3 1.55 0" rotation="0 40 0" scale="0.1 0.1 0.1"> |
|
|
|
|
</a-troika-text> |
|
|
|
|
|
|
|
|
|
</a-scene> |
|
|
|
|
</body> |
|
|
|
|
</script> |
|
|
|
|