diff --git a/index.html b/index.html index e835c53..c1ffc3b 100644 --- a/index.html +++ b/index.html @@ -23,23 +23,31 @@ AFRAME.registerComponent('startfunctions', { } }) +// import from https://fabien.benetou.fr/PIMVRdata/SpaSca3DPrinterInstructions?action=source + // but as text editable format, not code + // would be safer to do few examples BEFORE synthesizing to a flexible enough format, just with mini games before //___________________________________________________________________________________________________________________________________ AFRAME.registerComponent('instruction-machine', { // other content next, ideally combinable // tournevie metal workshop // laser cutter at the EP // todo + // split UI versus content // visual timeline and where we are on it, e.g 1/4 steps // a la Lego instruction, i.e horizontal bar with dot on current position // could use a cylinder and a moving sphere -// could be helpful to persist once position is ok, after step 1 then - // https://aframe.io/docs/1.5.0/components/anchored.html - // timeout for increasingly explicit feedback - // jump to specific step via hash to better discussion -// port a text version, i.e no 6DoF or hand tracking, to Monocle/Frame - // adapt from wiki sequential instructions part, possibly with some images -// consider https://threejs.org/docs/?q=grid#api/en/helpers/GridHelper too + // could be helpful to persist once position is ok, after step 1 then + // https://aframe.io/docs/1.5.0/components/anchored.html + // timeout for increasingly explicit feedback + // jump to specific step via hash to better discussion + // port a text version, i.e no 6DoF or hand tracking, to Monocle/Frame + // adapt from wiki sequential instructions part, possibly with some images + // consider https://threejs.org/docs/?q=grid#api/en/helpers/GridHelper too + + schema: {default: + "https://fabien.benetou.fr/PIMVRdata/SpaSca3DPrinterInstructions?action=source" + }, // type: "string" init: function(){ // shortcut to navigate through steps, 2D only @@ -52,13 +60,14 @@ AFRAME.registerComponent('instruction-machine', { let generatorName = this.attrName const idSuffix = "_framing_box" + this.buttonSuffix = "_step_button" let el = this.el + + //---------------------------CONTENT-------------------------- this.scale = 1/10 - this.steps = ["pick the grey box and align it with your 3D printer", "press change filament button", "remove the filament spool"] - // symplistic, could instead be a directed graph of named nodes, each with optionally multiple outgoing edges - this.buttonSuffix = "_step_button" - this.endOfInstructions = "You have finished the instructions. Feel free to reset and try again." - const confirmationStep = "Done" // could also consider a "done" area, moving the text there + // size of the initial bounding box + + // main element let newEl = document.createElement('a-box') newEl.setAttribute("scale", ""+this.scale+" "+this.scale+" "+this.scale) newEl.setAttribute("wireframe", "true") @@ -74,17 +83,7 @@ AFRAME.registerComponent('instruction-machine', { newEl.id = generatorName+idSuffix el.appendChild(newEl) - let timelinegEl = document.createElement('a-cylinder') - timelinegEl.setAttribute("height", "1") - timelinegEl.setAttribute("radius", ".1") - timelinegEl.setAttribute("color", "white") - timelinegEl.setAttribute("rotation", "90 0 0") - timelinegEl.setAttribute("position", "0.1 0.1 0.5") - timelinegEl.setAttribute("visible","false") - timelinegEl.classList.add( generatorName ) - timelinegEl.id = generatorName+"_timeline" - //newEl.appendChild(timelinegEl) - + // button for step 1 with hinting arrow let buttonEl = document.createElement('a-box') buttonEl.setAttribute("scale", ".2 .1 .1") buttonEl.setAttribute("wireframe", "true") @@ -98,6 +97,7 @@ AFRAME.registerComponent('instruction-machine', { newEl.appendChild(buttonEl) this.addArrow([-4.5, 0, 0], buttonEl) + // cylinder example for step 2 with hinting arrow buttonEl = document.createElement('a-cylinder') buttonEl.setAttribute("scale", ".5 .5 .5") buttonEl.setAttribute("wireframe", "true") @@ -111,10 +111,48 @@ AFRAME.registerComponent('instruction-machine', { buttonEl.id = generatorName+this.buttonSuffix+"_2" newEl.appendChild(buttonEl) this.addArrow([-4.5, 0, 0], buttonEl) + + //---------------------------END OF CONTENT-------------------------- + // generic UI + + this.steps = [] + //this.steps = ["pick the grey box and align it with your 3D printer", "press change filament button", "remove the filament spool"] + + fetch(this.data) + .then( r => r.text() ) + .then( r => { + this.steps = r.split('\n') + this.steps.push( this.endOfInstructions ) + document.querySelector("["+generatorName+"]").emit('reset') + }) + let n = addNewNote("jxr qs #"+newEl.id+" sa rotation 0", "0.5 0.9 -.5") n.setAttribute("rotation", "90 0 0") n.setAttribute("annotation", "content: snap") + // symplistic, could instead be a directed graph of named nodes, each with optionally multiple outgoing edges + this.endOfInstructions = "You have finished the instructions. Feel free to reset and try again." + this.steps.push( this.endOfInstructions ) + const confirmationStep = "Done" // could also consider a "done" area, moving the text there + + let timelinegEl = document.createElement('a-cylinder') + timelinegEl.setAttribute("height", "1") + timelinegEl.setAttribute("radius", ".01") + timelinegEl.setAttribute("color", "white") + timelinegEl.setAttribute("rotation", "0 0 90") + timelinegEl.setAttribute("position", "0 1.15 -0.5") + timelinegEl.setAttribute("target","true") + timelinegEl.classList.add( generatorName ) + timelinegEl.id = generatorName+"_timeline" + el.appendChild(timelinegEl) + let tlcursorgEl = document.createElement('a-sphere') + tlcursorgEl.setAttribute("radius", ".02") + tlcursorgEl.setAttribute("color", "red") + tlcursorgEl.setAttribute("position", "0 .5 0") + tlcursorgEl.classList.add( generatorName ) + tlcursorgEl.id = generatorName+"_timelinecursor" + timelinegEl.appendChild(tlcursorgEl) + let actions = [ "translateX(.1)", "translateX(-.1)", "translateY(.1)", "translateY(-.1)", "translateZ(.1)", "translateZ(-.1)", "rotateX(-.1)", "rotateX(.1)", "rotateY(.1)", "rotateY(-.1)", "rotateZ(.1)", "rotateZ(-.1)", @@ -122,7 +160,7 @@ AFRAME.registerComponent('instruction-machine', { actions.reverse().map( (a,i) => { let n = addNewNote("jxr qs #"+newEl.id+" .object3D."+a, ".5 "+(1+i/20)+" -.5") n.setAttribute("rotation", "90 0 0") - n.setAttribute("annotation", "content: "+a.replace(/xxx/,'')) + n.setAttribute("annotation", "content: "+a.replace(/xxx/,'')) // could be simplified a bit }) el.appendChild(newEl) @@ -148,6 +186,7 @@ AFRAME.registerComponent('instruction-machine', { let generatorName = this.attrName this.currentInstructionStep=-1 document.querySelector("["+generatorName+"]").emit('nextStep') + document.getElementById( generatorName+"_timelinecursor" ).object3D.position.y = .5 }, nextStep: function (evt) { let generatorName = this.attrName @@ -155,16 +194,19 @@ AFRAME.registerComponent('instruction-machine', { this.currentInstruction.setAttribute("value",this.steps[++this.currentInstructionStep]) Array.from( document.querySelectorAll( "."+generatorName+this.buttonSuffix) ).map( el => el.setAttribute("visible", "false" ) ) document.getElementById( generatorName+this.buttonSuffix +"_"+this.currentInstructionStep )?.setAttribute("visible", "true" ) - } else { - this.currentInstruction.setAttribute("value", this.endOfInstructions) + document.getElementById( generatorName+"_timelinecursor" ).object3D.translateY( -1/(this.steps.length-1) ) } }, previousStep: function (evt) { + // going back after the end does NOT work as expected! let generatorName = this.attrName if (this.currentInstructionStep>0){ this.currentInstruction.setAttribute("value",this.steps[--this.currentInstructionStep]) Array.from( document.querySelectorAll( "."+generatorName+this.buttonSuffix) ).map( el => el.setAttribute("visible", "false" ) ) document.getElementById( generatorName+this.buttonSuffix +"_"+this.currentInstructionStep )?.setAttribute("visible", "true" ) + document.getElementById( generatorName+"_timelinecursor" ).object3D.translateY( 1/(this.steps.length-1) ) + } else { + document.querySelector("["+generatorName+"]").emit('reset') } }, },