parent
f4810a6ab7
commit
07c397dc56
@ -0,0 +1 @@ |
||||
node_modules |
@ -1,21 +0,0 @@ |
||||
MIT License |
||||
|
||||
Copyright (c) 2020 Fabien Benetou |
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy |
||||
of this software and associated documentation files (the "Software"), to deal |
||||
in the Software without restriction, including without limitation the rights |
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell |
||||
copies of the Software, and to permit persons to whom the Software is |
||||
furnished to do so, subject to the following conditions: |
||||
|
||||
The above copyright notice and this permission notice shall be included in all |
||||
copies or substantial portions of the Software. |
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE |
||||
SOFTWARE. |
@ -0,0 +1,2 @@ |
||||
CreativeCommons Attribution-NonCommercial-ShareAlike 4.0 International. |
||||
http://creativecommons.org/licenses/by-nc-sa/4.0/ |
@ -1,35 +1 @@ |
||||
# relax-plus-think-space |
||||
an infinite space for your big ideas |
||||
|
||||
## Principle |
||||
Natural interaction (6DoF controllers) |
||||
in an immersive environment (relaxing setup to induce state of flow) |
||||
with work related content (e.g. Github issues, photos of work posters and post-it notes) |
||||
to be freely organised in visual categories (e.g. kanban). |
||||
|
||||
## UX flow for demos and tests |
||||
### new user on phone without own photos : |
||||
1. visit https://learnwebvr.xyz and get redirected to https://learnwebvr.xyz/setup/ |
||||
1. upload photos |
||||
1. generate a personalised link |
||||
1. share that link to target device (e.g. Firefox Send Tab to Devices on Oculus Quest) |
||||
1. experience on device |
||||
1. remove device and visit 2D links e.g. https://learnwebvr.xyz/flat.html?email=fabien@benetou.fr |
||||
|
||||
### returning user on 6DoF device |
||||
1. visit https://learnwebvr.xyz |
||||
1 ... |
||||
|
||||
### new user on 6DoF device |
||||
1. visit https://learnwebvr.xyz |
||||
1 ... |
||||
|
||||
## Code |
||||
* frontend : `index.html` and `setup/index.html` |
||||
* backend : `setup/server/upload.php` |
||||
|
||||
## License |
||||
MIT. |
||||
|
||||
## Property and rights |
||||
Iterative Explorations SCS based in Belgium |
||||
# relax-think |
After Width: | Height: | Size: 68 KiB |
After Width: | Height: | Size: 92 KiB |
After Width: | Height: | Size: 92 KiB |
@ -0,0 +1,32 @@ |
||||
<!DOCTYPE html> |
||||
<html lang="en"> |
||||
<head> |
||||
<title>Relax-Think</title> |
||||
<meta charset="utf-8"> |
||||
<meta name="viewport" content="width=device-width, user-scalable=no, minimum-scale=1.0, maximum-scale=1.0"> |
||||
<meta name="theme-color" content="#353449"> |
||||
<style> |
||||
body { |
||||
margin: 0; |
||||
} |
||||
canvas { |
||||
display: block; |
||||
-webkit-touch-callout: none; |
||||
-webkit-user-select: none; |
||||
-khtml-user-select: none; |
||||
-moz-user-select: none; |
||||
-ms-user-select: none; |
||||
user-select: none; |
||||
outline: none; |
||||
-webkit-tap-highlight-color: rgba(255, 255, 255, 0); /* mobile webkit */ |
||||
} |
||||
</style> |
||||
<link rel="shortcut icon" href="assets/img/favicon.png" type="image/x-icon"> |
||||
<script src="https://aframe.io/releases/1.0.3/aframe.min.js"></script> |
||||
<script src="bundle.js"></script> |
||||
</head> |
||||
<body> |
||||
<div id="app"></div> |
||||
<a id="vrButton" href="#" title="Enter VR / Fullscreen"></a> |
||||
</body> |
||||
</html> |
@ -1,111 +0,0 @@ |
||||
<!DOCTYPE html> |
||||
<html lang="en"> |
||||
<head> |
||||
<!-- Required meta tags --> |
||||
<meta charset="utf-8"> |
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> |
||||
|
||||
<!-- Bootstrap CSS --> |
||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/css/bootstrap.min.css" integrity="sha384-/Y6pD6FV/Vv2HJnA6t+vslU6fwYXjCFtcEpHbNJ0lyAFsXTsjBbfaDjzALeQsN6M" crossorigin="anonymous"> |
||||
<link href="https://getbootstrap.com/docs/4.0/examples/signin/signin.css" rel="stylesheet"> |
||||
|
||||
<script src="setup/upload/server/php/files/usersdb.js"></script> |
||||
<script src="https://aframe.io/releases/1.0.0/aframe.min.js"></script> |
||||
</head> |
||||
<style> |
||||
body { background-color: transparent; } |
||||
|
||||
#email, #sms { |
||||
font-size: xx-large; |
||||
} |
||||
</style> |
||||
|
||||
<body> |
||||
|
||||
<img src="setup/productlogo.png"> |
||||
|
||||
<h3>flat viewer by category sorted by position</h3> |
||||
|
||||
<div id="spacesholder">Your spaces: |
||||
<ul id="spaces"></ul> |
||||
</div> |
||||
|
||||
<div>Already have an account? <span onclick="login()" style="text-decoration: underline;">Log-in</span> |
||||
<form> |
||||
<div id="login" style="display:none"><input id="useremail"/> |
||||
<button style="margin-top:2px;" type="button" onclick="loginViaEmail()" id="loginemail" class="btn btn-lg btn-primary btn-block">Login</button> |
||||
</div> |
||||
</form> |
||||
<div style="display:none" id="nouser">User not found. Double check your email address then contact fabien@iterative-explorations.com</a></div> |
||||
</div> |
||||
|
||||
<script> |
||||
const urlParams = new URLSearchParams(window.location.search); |
||||
const email = urlParams.get('email'); |
||||
if (email) loginViaEmail() |
||||
|
||||
var uploadedURL = "setup/upload/server/php/files/"; |
||||
var images = [] |
||||
var url = "/" |
||||
var urlParameters = "?customimages=" |
||||
var userspace |
||||
|
||||
function login(){ |
||||
document.querySelector("#login").style.display = "block" |
||||
} |
||||
|
||||
function findCategory(image){ |
||||
if (!userspace) return |
||||
console.log(image.filename) |
||||
var imagePos = new THREE.Vector3(); |
||||
imagePos.copy ( AFRAME.utils.coordinates.parse(image.position) ) |
||||
|
||||
var closest |
||||
var smallestDistance = 1000 |
||||
for (var category of userspace.categories){ |
||||
var categoryPos = new THREE.Vector3(); |
||||
categoryPos.copy ( AFRAME.utils.coordinates.parse(category.position) ) |
||||
var distance = categoryPos.distanceTo( imagePos ) |
||||
if (distance < smallestDistance){ |
||||
smallestDistance = distance |
||||
closest = category.label |
||||
} |
||||
console.log(distance, category.label) |
||||
} |
||||
|
||||
return closest |
||||
} |
||||
|
||||
function loginViaEmail(){ |
||||
var path = "setup/" |
||||
if (!email) |
||||
email = document.querySelector("#useremail").value |
||||
userspace = database[email] |
||||
if (!userspace){ |
||||
document.querySelector("#nouser").style.display = "block" |
||||
return |
||||
} |
||||
|
||||
document.querySelector("#spacesholder").style.display = "block" |
||||
var spaces = document.querySelector("#spaces") |
||||
var space = document.createElement("li") |
||||
var spacelink = document.createElement("a") |
||||
var images = userspace.files |
||||
spacelink.href = url + urlParameters |
||||
spacelink.target = "_blank" |
||||
spacelink.innerHTML = userspace.last_login |
||||
space.appendChild(spacelink) |
||||
for (var image of images){ |
||||
urlParameters += image.filename + "," |
||||
space.innerHTML += path + image.filename + " " + findCategory( image ) |
||||
} |
||||
console.log(space) |
||||
spaces.appendChild(space) |
||||
console.log("userspace", userspace) |
||||
} |
||||
</script> |
||||
|
||||
<h3 style="position:absolute; bottom:0px; right:0px;">A product by <a href="https://iterative-explorations.com"><img width="200px" src="https://iterative-explorations.com/logo.svg"></a>.</h3> |
||||
|
||||
</body> |
||||
</html> |
@ -1,150 +0,0 @@ |
||||
<head> |
||||
<meta charset="UTF-8"> |
||||
<title>Think + Relax space by Iterative Explorations</title> |
||||
<script src="https://aframe.io/releases/1.0.0/aframe.min.js"></script> |
||||
<script src="https://rawgit.com/feiss/aframe-environment-component/master/dist/aframe-environment-component.min.js"></script> |
||||
<script src="https://cdn.rawgit.com/donmccurdy/aframe-extras/v4.1.2/dist/aframe-extras.min.js"></script> |
||||
<script src="https://unpkg.com/super-hands@3.0.0/dist/super-hands.min.js"></script> |
||||
<script src="pimvrhelpers.js"></script> |
||||
</head> |
||||
<script> |
||||
// could add an in VR edit mode for the categories, to position them, name them, etc |
||||
// should be mostly for adjustments |
||||
var timer = AFRAME.utils.getUrlParameter('timer') |
||||
if (!timer) timer = 300 //5min |
||||
|
||||
function saveNewItemsPosition(){ |
||||
var selector = ".notes"; |
||||
var pos = "" |
||||
document.querySelectorAll(selector).forEach( |
||||
e => pos += "\n" + AFRAME.utils.coordinates.stringify( e.getAttribute("position") ) |
||||
) |
||||
pimvrSaveRemote("WeWorkTest", pos) // from pimvrhelpers.js |
||||
// should be saved by username by space |
||||
// could be pointed at from the database file (thus having multiple storages) |
||||
} |
||||
|
||||
AFRAME.registerComponent("watch", { |
||||
init: function() { |
||||
document.querySelector("#timer").setAttribute("text","value:"+timer) |
||||
this.tick = AFRAME.utils.throttleTick(this.tick, 1000, this); |
||||
// details https://aframe.io/docs/1.0.0/core/utils.html#aframe-utils-throttle-function-minimuminterval-optionalcontext |
||||
}, |
||||
|
||||
tick: function (t, dt) { |
||||
var time = Number( document.querySelector("#timer").getAttribute("text").value ) |
||||
time-- |
||||
document.querySelector("#timer").setAttribute("text","value:"+(time)) |
||||
}, |
||||
}) |
||||
|
||||
AFRAME.registerComponent("relaxing-introduction", { |
||||
init: function() { |
||||
// get in flow state |
||||
// for now controlled just with AFrame animation |
||||
// cf https://aframe.io/docs/1.0.0/components/animation.html |
||||
|
||||
setTimeout(function(){ |
||||
for (var note of document.querySelectorAll(".notes")){ note.emit("fadein") } |
||||
}, 10 * 1000) // arbitrary 10s, should be instead after the introduction is finished |
||||
} |
||||
}) |
||||
|
||||
AFRAME.registerComponent("decompression-conclusion", { |
||||
init: function() { |
||||
// cf PoC at 2017 W3C web authoring workshop with Roland Dubois |
||||
setTimeout(function(){ |
||||
var intructions = document.querySelector("#instructions") |
||||
instructions.setAttribute("position", "-1 1.5 -1") // assumes the user is roughtly centered... could force on camera instead |
||||
instructions.setAttribute("text", "value", "Your session will end soon\n\nVisit https://learnWebVR.xyz/flat.html\n\nto work outside of VR.") |
||||
instructions.setAttribute("opacity", "1") // could be animated instead |
||||
|
||||
console.log("X min voice over and notes fade-out with contextual information (time, weather, etc)") |
||||
|
||||
document.querySelector("[environment]").setAttribute("environment", "preset:checkerboard") |
||||
}, timer * 1000); |
||||
|
||||
} |
||||
}) |
||||
|
||||
AFRAME.registerComponent("environment-by-url", { |
||||
schema: {}, |
||||
init: function() { |
||||
var environment = AFRAME.utils.getUrlParameter('environment') |
||||
if (environment) document.querySelector("[environment]").setAttribute("environment", "preset:" + environment) |
||||
} |
||||
}) |
||||
|
||||
AFRAME.registerComponent("photo-importer", { |
||||
schema: {}, |
||||
init: function() { |
||||
var baseURL = "setup/" |
||||
var images = AFRAME.utils.getUrlParameter('customimages').split(','); |
||||
if (images.length == 1) window.location = baseURL; // no images? must be configured first |
||||
// could also display a tutorial instead |
||||
var i=1 |
||||
for (var image of images){ |
||||
if (image){ |
||||
var id = "placeholder"+i |
||||
var placeholder = document.querySelector("#"+id) |
||||
if (!placeholder){ |
||||
// TODO somehow not interactable anymore?! |
||||
// had a similar silly issue before but can't recall how I fixed it :( |
||||
// something basic about entities or hierarchy... |
||||
placeholder = document.createElement("a-box") |
||||
placeholder.id = id |
||||
placeholder.setAttribute("material", "shader:flat") |
||||
placeholder.setAttribute("hoverable", "") |
||||
placeholder.setAttribute("grabbable", "") |
||||
placeholder.setAttribute("draggable", "") |
||||
placeholder.setAttribute("dropppable", "") |
||||
// somehow does appear visually correct but are NOT interactable! |
||||
placeholder.setAttribute("position", "" + i/1.5-1.5 + " 1.5 -0.7") |
||||
placeholder.setAttribute("scale", "0.5 0.3 0.01") |
||||
// assume 1 * 1.5 photo ratio (landscape) |
||||
AFRAME.scenes[0].appendChild(placeholder) |
||||
} |
||||
placeholder.className += "notes" |
||||
placeholder.setAttribute("opacity", "0") |
||||
placeholder.setAttribute("animation", "property: components.material.material.opacity; to: 1; dur: 1500; easing: linear; startEvents: fadein;") |
||||
placeholder.setAttribute("src", baseURL+image) |
||||
i++ |
||||
} |
||||
} |
||||
} |
||||
}) |
||||
|
||||
|
||||
</script> |
||||
<body> |
||||
<a-scene photo-importer environment-by-url relaxing-introduction decompression-conclusion> |
||||
<a-entity environment="preset: forest;"></a-entity> |
||||
|
||||
<a-entity sphere-collider="objects: a-box" super-hands hand-controls="left"></a-entity> |
||||
<a-entity sphere-collider="objects: a-box" super-hands hand-controls="right"></a-entity> |
||||
|
||||
<!-- could be wrist watch as I've done via Twitter years ago --> |
||||
<a-text watch id="timer" rotation="180 0 180" position="0 1 2" value="time"></a-text> |
||||
|
||||
<a-text id="instructions" position="-1 1.5 -0.65" value="welcome to your\n\nthink+relax space" opacity="0" |
||||
animation__fadein="property: components.text.material.uniforms.opacity.value; to: 0.99; dur: 1500; easing: linear" |
||||
animation__fadeout="property: components.text.material.uniforms.opacity.value; to: 0.01; dur: 1500; easing: linear; startEvents: fadeout;" |
||||
animation__leave="property: object3D.position.z; to: -100; dur: 15000; easing: linear; delay: 2500;" |
||||
></a-text> |
||||
|
||||
|
||||
<a-text rotation="-20 20 0" position="-2 0.2 -2" scale="1 1 1" value="waiting"></a-text> |
||||
<a-box material="wireframe:true" color="orange" position="-2 1 -2" scale="2 2 2"></a-box> |
||||
<a-text rotation="-20 0 0" position=" 0 0.2 -2" scale="1 1 1" value="in progress"></a-text> |
||||
<a-box material="wireframe:true" color="red" position="0 1 -2" scale="2 2 2"></a-box> |
||||
<a-text rotation="-20 -20 0" position=" 2 0.2 -2" scale="1 1 1" value="completed"></a-text> |
||||
<a-box material="wireframe:true" color="green" position="2 1 -2" scale="2 2 2"></a-box> |
||||
|
||||
<a-box material="shader:flat" id="placeholder1" hoverable grabbable stretchable draggable dropppable position="0.5 1.5 -0.5" scale="0.5 0.3 0.01"></a-box> |
||||
<a-box material="shader:flat" id="placeholder2" hoverable grabbable stretchable draggable dropppable position="0 1.9 -0.7" scale="0.5 0.3 0.01"></a-box> |
||||
<a-box material="shader:flat" id="placeholder3" hoverable grabbable stretchable draggable dropppable position="-0.5 1.5 -0.7" scale="0.5 0.3 0.01"></a-box> |
||||
<!-- somehow creating dynamically fails... even though it did (!) work at some point (but wasn't saved via git)--> |
||||
<!-- until then will rely on a pool of objects --> |
||||
|
||||
</a-scene> |
||||
</body> |
@ -0,0 +1,42 @@ |
||||
{ |
||||
"name": "relax-think", |
||||
"version": "0.0.1", |
||||
"license": "CC-BY-NC-SA-4.0", |
||||
"description": "An infinite space for your big ideas", |
||||
"repository": { |
||||
"type": "git", |
||||
"url": "" |
||||
}, |
||||
"main": "index.js", |
||||
"dependencies": {}, |
||||
"scripts": { |
||||
"start": "webpack-dev-server --mode development --host 192.168.0.12", |
||||
"build": "webpack --mode production --config webpack.config.js" |
||||
}, |
||||
"keywords": [], |
||||
"author": "Arturo Paracuellos", |
||||
"devDependencies": { |
||||
"aframe-environment-component": "^2.0.0", |
||||
"aframe-super-hot-loader": "^1.7.0", |
||||
"aframe-super-hot-html-loader": "^2.1.0", |
||||
"babel-core": "^6.26.3", |
||||
"babel-loader": "^7.1.4", |
||||
"babel-preset-env": "^1.7.0", |
||||
"css-loader": "^3.4.1", |
||||
"html-require-loader": "^1.0.1", |
||||
"json-loader": "^0.5.7", |
||||
"super-hands": "^3.0.0", |
||||
"style-loader": "^0.23.1", |
||||
"url-loader": "^1.1.2", |
||||
"webpack": "^4.39.3", |
||||
"webpack-cli": "^3.3.7", |
||||
"webpack-dev-server": "^3.8.0", |
||||
"webpack-glsl-loader": "^1.0.1" |
||||
}, |
||||
"standard": { |
||||
"globals": [ |
||||
"AFRAME", |
||||
"THREE" |
||||
] |
||||
} |
||||
} |
@ -1,173 +0,0 @@ |
||||
//---------PIM helper functions-----------------------------------------------------------
|
||||
/* |
||||
currently PmWiki backend |
||||
could use http://fabien.benetou.fr/Site/AllRecentChanges?action=source to check for update
|
||||
heavy but nearly no processing required |
||||
enough if done once per minute or so |
||||
if update, request serverrender on modified page |
||||
IFF it's being displayed |
||||
planned Evernote backend |
||||
https://github.com/evernote/evernote-sdk-js
|
||||
https://github.com/wanasit/everest-js
|
||||
https://stackoverflow.com/questions/24580588/how-to-list-all-the-notes-from-an-evernote-notebook-javascript-node-js
|
||||
https://dev.evernote.com/doc/articles/polling_notification.php
|
||||
or other popular PIMs |
||||
https://developers.trello.com/
|
||||
http://www.xmind.net/developer/
|
||||
ideally with webhooks on a backend abstraction with coherent API
|
||||
|
||||
*/ |
||||
|
||||
function pimvrSaveItemsStates(callback) { |
||||
function updateItemsStates(globalStates){
|
||||
let pageStates = {}; |
||||
let [group, page] = getPageGroup(); |
||||
let elements = document.body.querySelectorAll('.pimvr-item'); |
||||
for (let item of elements) { |
||||
let id = item.getAttribute("id"); |
||||
let position = item.getComputedAttribute("position"); |
||||
pageStates[id] = {"position": position}; |
||||
} |
||||
globalStates[group+"_"+page] = pageStates; |
||||
pimvrSaveRemote("ItemsStates", JSON.stringify(globalStates)); |
||||
return "Items states saved"; |
||||
|
||||
} |
||||
pimvrLoadRemote("ItemsStates", updateItemsStates); |
||||
}
|
||||
|
||||
function pimvrSaveConfiguration(callback) { |
||||
let configuration = {}; |
||||
let elements = document.body.querySelectorAll('.pimvr-configuration'); |
||||
for (let item of elements) { |
||||
let id = item.getAttribute("id"); |
||||
let position = item.getComputedAttribute("position"); |
||||
configuration[id] = {"position": position}; |
||||
} |
||||
|
||||
pimvrSaveRemote("Configuration", JSON.stringify(configuration)); |
||||
return "Configuration saved"; |
||||
} |
||||
|
||||
function pimvrLoadIoTData(callback) { |
||||
// should give min/max ranges, here seems to be 0-1010
|
||||
// to use (once normalized) as an attribute value
|
||||
// used on http://jsbin.com/nucanat/edit?html,output
|
||||
// warning HTTPS on tick is really hammering
|
||||
const readURL = "https://fabien.benetou.fr/PIMVRdata/IoTData?action=source"; |
||||
|
||||
var myRequest = new XMLHttpRequest(); |
||||
myRequest.open('GET', readURL); |
||||
myRequest.onreadystatechange = function () { |
||||
if (myRequest.readyState === 4) { |
||||
callback(myRequest.responseText); |
||||
} |
||||
}; |
||||
myRequest.send(); |
||||
}
|
||||
|
||||
function pimvrServerRender(group, page, callback) { |
||||
const readURL = "https://fabien.benetou.fr/"+group+"/"+page+"?action=serverrender"; |
||||
|
||||
var myRequest = new XMLHttpRequest(); |
||||
myRequest.open('GET', readURL); |
||||
myRequest.onreadystatechange = function () { |
||||
if (myRequest.readyState === 4) { |
||||
callback(JSON.parse(myRequest.responseText).res); |
||||
} |
||||
}; |
||||
myRequest.send(); |
||||
} |
||||
|
||||
function pimvrLoadRemoteSmarthWatchConfiguration(callback) { |
||||
|
||||
const readURL = "https://fabien.benetou.fr/PIMVRdata/SmartWatchConfiguration?action=source"; |
||||
|
||||
var myRequest = new XMLHttpRequest(); |
||||
myRequest.open('GET', readURL); |
||||
myRequest.onreadystatechange = function () { |
||||
if (myRequest.readyState === 4) { |
||||
callback(JSON.parse(myRequest.responseText)); |
||||
} |
||||
}; |
||||
myRequest.send(); |
||||
} |
||||
//pimvrLoadRemoteSmarthWatchConfiguration(console.log);
|
||||
// usage unclear, can be used as
|
||||
// haptic feedback on interactible items e.g. vibrate on gaze
|
||||
// controller backup e.g. gaze+click
|
||||
// controller locator e.g. making 2 bright columns
|
||||
// heart rate monitor (sadly not with PebbleTime) to reshape experience
|
||||
|
||||
function pimvrLoadRemoteMetadata(group, page, callback, query) { |
||||
|
||||
const readURL = "https://fabien.benetou.fr/"+group+"/"+page+"?action=metajson"; |
||||
|
||||
var myRequest = new XMLHttpRequest(); |
||||
myRequest.open('GET', readURL+"&query="+query, true); |
||||
myRequest.onreadystatechange = function () { |
||||
if (myRequest.readyState === 4) { |
||||
callback(JSON.parse(myRequest.responseText)); |
||||
} |
||||
}; |
||||
myRequest.send(); |
||||
} |
||||
|
||||
function pimvrLoadRemote(page, callback) { |
||||
|
||||
const readURL = "https://fabien.benetou.fr/PIMVRdata/"+page+"?action=source"; |
||||
// assumes JSON
|
||||
|
||||
var myRequest = new XMLHttpRequest(); |
||||
myRequest.open('GET', readURL); |
||||
myRequest.onreadystatechange = function () { |
||||
if (myRequest.readyState === 4) { |
||||
callback(JSON.parse(myRequest.responseText)); |
||||
} |
||||
}; |
||||
myRequest.send(); |
||||
} |
||||
|
||||
function pimvrSaveRemote(page, data) { |
||||
const writeURL = "https://fabien.benetou.fr/PIMVRdata/"+page+"?action=edit"; |
||||
|
||||
var myWriteRequest = new XMLHttpRequest(); |
||||
myWriteRequest.open('POST', writeURL, true); |
||||
myWriteRequest.setRequestHeader("Content-Type", |
||||
"application/x-www-form-urlencoded"); |
||||
myWriteRequest.onreadystatechange = function () { |
||||
if (myWriteRequest.readyState === 4) { |
||||
//console.log(myWriteRequest.responseText);
|
||||
console.log("Save on "+page+" sucessful"); |
||||
} |
||||
}; |
||||
console.log("trying to open "+writeURL+"post=1&author=PIMVR&authpw=edit_password&text="+data) |
||||
myWriteRequest.send("post=1&author=PIMVR&authpw=edit_password&text="+data); |
||||
// cf http://www.pmwiki.org/wiki/PmWiki/EditingAPI
|
||||
} |
||||
|
||||
function loadRemoteGraph(callback, params){ |
||||
const myDataURL = "https://vatelier.net/MyDemo/newtooling/wiki_graph.json"; |
||||
// not that as agressive as it gets cached
|
||||
|
||||
var myRequest = new XMLHttpRequest(); |
||||
myRequest.open('GET', myDataURL); |
||||
myRequest.onreadystatechange = function () { |
||||
if (myRequest.readyState === 4) { |
||||
//window.PIMgraph = JSON.parse(myRequest.responseText).Nodes;
|
||||
callback(JSON.parse(myRequest.responseText).Nodes, params); |
||||
} |
||||
}; |
||||
myRequest.send(); |
||||
} |
||||
|
||||
function getMyNeighbours(nodes, page){ |
||||
console.log(nodes[page].Targets); |
||||
} |
||||
|
||||
function getPageGroup(){
|
||||
let group = QueryString.group || "Main"; |
||||
let page = QueryString.page || "HomePage"; |
||||
return [group, page]; |
||||
} |
||||
|
@ -1,187 +0,0 @@ |
||||
<!DOCTYPE html> |
||||
<html lang="en"> |
||||
<head> |
||||
<!-- Required meta tags --> |
||||
<meta charset="utf-8"> |
||||
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no"> |
||||
|
||||
<!-- Bootstrap CSS --> |
||||
<link rel="stylesheet" href="https://maxcdn.bootstrapcdn.com/bootstrap/4.0.0-beta/css/bootstrap.min.css" integrity="sha384-/Y6pD6FV/Vv2HJnA6t+vslU6fwYXjCFtcEpHbNJ0lyAFsXTsjBbfaDjzALeQsN6M" crossorigin="anonymous"> |
||||
<link href="https://getbootstrap.com/docs/4.0/examples/signin/signin.css" rel="stylesheet"> |
||||
|
||||
<script src="clipboard.min.js"></script> |
||||
<script src="upload/server/php/files/usersdb.js"></script> |
||||
</head> |
||||
<style> |
||||
body { background-color: transparent; } |
||||
|
||||
#email, #sms { |
||||
font-size: xx-large; |
||||
} |
||||
</style> |
||||
|
||||
<body> |
||||
|
||||
<img src="productlogo.png"> |
||||
|
||||
<script> |
||||
var tickMark = "✔"; |
||||
var uploadedURL = "upload/server/php/files/"; |
||||
var images = [] |
||||
var url = "/" |
||||
var urlParameters = "?customimages=" |
||||
|
||||
function generateURL(){ |
||||
//var url = "https://learnwebvr.xyz/importer.html" |
||||
for (var image of images){ |
||||
urlParameters += image + "," |
||||
} |
||||
console.log ("URL", urlParameters ); |
||||
|
||||
var encodedURL = url + urlParameters |
||||
|
||||
encodedURL += "&environment=" + document.querySelector("#environment").value |
||||
document.querySelector("#link").href = encodedURL |
||||
document.querySelector("#copyBtn").setAttribute("data-clipboard-text", encodedURL) |
||||
document.querySelector("#generateURL").style.display = "block" |
||||
|
||||
document.querySelector("#email").href = "mailto:?&subject=session&body=" + encodeURIComponent( encodedURL ) |
||||
// tested on iPhone 6S and Pixel2 and desktop |
||||
|
||||
if( /Android|webOS|iPhone|iPad|iPod|BlackBerry|IEMobile|Opera Mini/i.test(navigator.userAgent) ) { |
||||
} |
||||
else { |
||||
document.querySelector("#copydiv").className = "cold-md-6" |
||||
document.querySelector("#emaildiv").className = "cold-md-6" |
||||
} |
||||
} |
||||
</script> |
||||
<div class="container"> |
||||
|
||||
<form class="form-signin"> |
||||
|
||||
Environment: |
||||
<select id="environment"> |
||||
<option name="contact">contact</option> |
||||
<option name="egypt">egypt</option> |
||||
<option name="checkerboard">checkerboard</option> |
||||
<option name="forest" selected="selected">forest</option> |
||||
<option name="goaland">goaland</option> |
||||
<option name="yavapai">yavapai</option> |
||||
<option name="goldmine">goldmine</option> |
||||
<option name="threetowers">threetowers</option> |
||||
<option name="poison">poison</option> |
||||
<option name="arches">arches</option> |
||||
<option name="tron">tron</option> |
||||
<option name="japan">japan</option> |
||||
<option name="dream">dream</option> |
||||
<option name="volcano">volcano</option> |
||||
<option name="starry">starry</option> |
||||
<option name="osiris">osiris</option> |
||||
</select> |
||||
|
||||
<button style="margin-top:2px;" type="button" onclick="unhide('#fileupload2');" class="btn btn-primary btn-block">Upload your office photos<br/>(post-its, white board, etc)</button> |
||||
|
||||
No content available? Try <a target="_blank" href="https://learnwebvr.xyz/?customimages=upload/server/php/files/photo6035074301452988871.jpg,upload/server/php/files/photo6035074301452988870.jpg,upload/server/php/files/IMG_6496 (1).jpg"> this example instead</a>! |
||||
|
||||
<input style="display:none;" id="fileupload2" type="file" name="files[]" data-url="upload/server/php/" multiple> |
||||
<div style="display:none;" id="fileuploaded2">Files uploaded: </div> |
||||
<div style="opacity:0.7;" id="uploadrate"></div> |
||||
<script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js"></script> |
||||
<script src="upload/js/vendor/jquery.ui.widget.js"></script> |
||||
<script src="upload/js/jquery.iframe-transport.js"></script> |
||||
<script src="upload/js/jquery.fileupload.js"></script> |
||||
<script> |
||||
|
||||
function unhide( element ){ |
||||
document.querySelector(element).style.display = "block"; |
||||
} |
||||
|
||||
$(function () { |
||||
|
||||
$('#fileupload2').fileupload({ |
||||
dataType: 'json', |
||||
done: function (e, data) { |
||||
$.each(data.result.files, function (index, file) { |
||||
var imageURL = uploadedURL + (file.name) |
||||
images.push(imageURL) |
||||
var uploaded = document.querySelector("#fileuploaded2"); |
||||
uploaded.style.display = "block"; |
||||
uploaded.innerHTML += tickMark; |
||||
}); |
||||
} |
||||
}); |
||||
|
||||
}); |
||||
</script> |
||||
|
||||
<button style="margin-top:2px;" type="button" onclick="generateURL()" id="generate-simulation" class="btn btn-lg btn-primary btn-block">Generate your<br/>relax+think space</button> |
||||
</form> |
||||
</div> |
||||
|
||||
<div id="generateURL" style="display:none; text-align:center;" class="container"> |
||||
<div class="container"> |
||||
<a id="link" target="_blank" href=""><button type="button" class="btn btn-lg btn-primary btn-block">Launch relax+think space</button></a> |
||||
</div> |
||||
<br/> |
||||
<div class="container"> |
||||
<div class="row"> |
||||
<div class="col-md-4" id="copydiv"> |
||||
<button class="btn" data-clipboard-text="" id="copyBtn">Copy to clipboard</button> |
||||
<script> |
||||
new Clipboard('.btn'); |
||||
</script> |
||||
</div> |
||||
<div class="col-md-4" id="emaildiv"> |
||||
<a id="email" href="" target="_blank">email link</a> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
</div> |
||||
|
||||
<script> |
||||
function login(){ |
||||
document.querySelector("#login").style.display = "block" |
||||
} |
||||
function loginViaEmail(){ |
||||
var email = document.querySelector("#useremail").value |
||||
var userspace = database[email] |
||||
if (!userspace){ |
||||
document.querySelector("#nouser").style.display = "block" |
||||
return |
||||
} |
||||
|
||||
document.querySelector("#spacesholder").style.display = "block" |
||||
var spaces = document.querySelector("#spaces") |
||||
var space = document.createElement("li") |
||||
var spacelink = document.createElement("a") |
||||
var images = userspace.files |
||||
for (var image of images){ |
||||
urlParameters += image.filename + "," |
||||
} |
||||
spacelink.href = url + urlParameters |
||||
spacelink.target = "_blank" |
||||
spacelink.innerHTML = userspace.last_login |
||||
space.appendChild(spacelink) |
||||
console.log(space) |
||||
spaces.appendChild(space) |
||||
console.log("userspace", userspace) |
||||
} |
||||
</script> |
||||
|
||||
<div>Already have an account? <span onclick="login()" style="text-decoration: underline;">Log-in</span> |
||||
<form> |
||||
<div id="login" style="display:none"><input id="useremail"/> |
||||
<button style="margin-top:2px;" type="button" onclick="loginViaEmail()" id="loginemail" class="btn btn-lg btn-primary btn-block">Login</button> |
||||
</div> |
||||
</form> |
||||
<div style="display:none" id="nouser">User not found. Double check your email address then contact fabien@iterative-explorations.com</a></div> |
||||
<div style="display:none" id="spacesholder">Your spaces: |
||||
<ul id="spaces"></ul> |
||||
</div> |
||||
</div> |
||||
|
||||
<h3 style="position:absolute; bottom:0px; right:0px;">A product by <a href="https://iterative-explorations.com"><img width="200px" src="https://iterative-explorations.com/logo.svg"></a>.</h3> |
||||
|
||||
</body> |
||||
</html> |
File diff suppressed because it is too large
Load Diff
@ -1,18 +0,0 @@ |
||||
var database = { |
||||
"fabien@benetou.fr" : { |
||||
"username": "fabien", |
||||
"password": "test", |
||||
"last_login": 1576749381516, |
||||
"environment": "forest", |
||||
"files" : [ |
||||
{ "position": "-2 1 -2", "filename" : "upload/server/php/files/C1C4E2F7-865A-4DB4-9274-1EA69B6C4A7E.jpeg" }, |
||||
{ "position": "0 1 -2", "filename" : "upload/server/php/files/4A21A76C-F375-4884-9040-BC51A24057A6.jpeg" }, |
||||
{ "position": "2 1 -2", "filename" : "upload/server/php/files/2CD9932F-891C-4BA5-BDDA-A3B39B39CF09.jpeg" } |
||||
], |
||||
"categories" : [ |
||||
{ "position": "-2 1 -2", "color" : "orange", "label" : "waiting" }, |
||||
{ "position": "0 1 -2", "color" : "red", "label" : "in progress" }, |
||||
{ "position": "2 1 -2", "color" : "green", "label" : "completed" } |
||||
] |
||||
} |
||||
} |
@ -1,17 +0,0 @@ |
||||
<?php |
||||
/* |
||||
* jQuery File Upload Plugin PHP Example |
||||
* https://github.com/blueimp/jQuery-File-Upload |
||||
* |
||||
* Copyright 2010, Sebastian Tschan |
||||
* https://blueimp.net |
||||
* |
||||
* Licensed under the MIT license: |
||||
* https://opensource.org/licenses/MIT |
||||
*/ |
||||
|
||||
error_reporting(E_ALL | E_STRICT); |
||||
require('UploadHandler.php'); |
||||
$upload_handler = new UploadHandler(array( |
||||
'accept_file_types' => '/\.(png|jpe?g|mp4)$/i' |
||||
)); |
@ -0,0 +1,6 @@ |
||||
<a-scene background="color: #FAFAFA" vr-mode-ui="enterVRButton: #vrButton"> |
||||
<a-box position="-1 0.5 -3" rotation="0 45 0" color="#4CC3D9" shadow></a-box> |
||||
<a-sphere position="0 1.25 -5" radius="1.25" color="#EF2D5E" shadow></a-sphere> |
||||
<a-cylinder position="1 0.75 -3" radius="0.5" height="1.5" color="#FFC65D" shadow></a-cylinder> |
||||
<a-plane position="0 0 -4" rotation="-90 0 0" width="4" height="4" color="#7BC8A4" shadow></a-plane> |
||||
</a-scene> |
@ -0,0 +1,58 @@ |
||||
html { |
||||
background: #000; |
||||
} |
||||
|
||||
#vrButton { |
||||
position: absolute; |
||||
background: url('../dist/assets/img/enter-vr-button-background.png') no-repeat; |
||||
background-size: cover; |
||||
border: 0; |
||||
cursor: pointer; |
||||
right: 20px; |
||||
bottom: 20px; |
||||
text-decoration: none; |
||||
z-index: 9999999; |
||||
width: 64px; |
||||
height: 64px; |
||||
} |
||||
|
||||
#vrButton.a-hidden { |
||||
visibility: hidden; |
||||
} |
||||
|
||||
#vrButton:active { |
||||
border: 0; |
||||
} |
||||
|
||||
#vrButton:hover { |
||||
background-position: 0 -64.5px; |
||||
} |
||||
|
||||
#vrButton p { |
||||
bottom: 45px; |
||||
color: #FFF; |
||||
font-size: 12px; |
||||
font-family: monospace; |
||||
font-weight: bold; |
||||
text-align: center; |
||||
text-transform: uppercase; |
||||
position: relative; |
||||
} |
||||
|
||||
.a-loader-title { |
||||
animation: loaderTitle 1s infinite alternate; |
||||
color: rgba(0,0,0,0); |
||||
background: none; |
||||
background-image: url('../dist/assets/img/loadingLogo.png'); |
||||
height: 36.2vh; |
||||
background-repeat: no-repeat; |
||||
background-position: center; |
||||
margin-top: 0; |
||||
background-size: contain; |
||||
} |
||||
|
||||
@keyframes loaderTitle { |
||||
0% { opacity: 1; } |
||||
50% { opacity: 0.8; } |
||||
100% { opacity: 1; } |
||||
} |
@ -0,0 +1,13 @@ |
||||
function requireAll (req) { req.keys().forEach(req); } |
||||
|
||||
console.time = () => {}; |
||||
console.timeEnd = () => {}; |
||||
|
||||
require('aframe-environment-component') |
||||
require('super-hands') |
||||
|
||||
require('./index.css') |
||||
|
||||
require('./home.html') |
||||
|
||||
if (module.hot) { module.hot.accept(); } |
@ -0,0 +1,66 @@ |
||||
const path = require('path') |
||||
|
||||
module.exports = { |
||||
entry: { |
||||
index: './src/index.js' |
||||
}, |
||||
output: { |
||||
filename: 'bundle.js', |
||||
path: path.resolve(__dirname, 'dist') |
||||
}, |
||||
devServer: { |
||||
https: true, |
||||
port: 3000, |
||||
contentBase: './dist' |
||||
}, |
||||
devtool: 'source-map', |
||||
plugins: [ |
||||
], |
||||
optimization: { |
||||
}, |
||||
module: { |
||||
rules: [ |
||||
{ |
||||
test: /\.js/, |
||||
exclude: /(node_modules)/, |
||||
use: ['babel-loader', 'aframe-super-hot-loader'] |
||||
}, |
||||
{ |
||||
test: /\.json/, |
||||
exclude: /(node_modules)/, |
||||
type: 'javascript/auto', |
||||
loader: ['json-loader'] |
||||
}, |
||||
{ |
||||
test: /\.html/, |
||||
exclude: /(node_modules)/, |
||||
use: [ |
||||
'aframe-super-hot-html-loader', |
||||
{ |
||||
loader: 'html-require-loader', |
||||
options: { |
||||
root: path.resolve(__dirname, 'src') |
||||
} |
||||
} |
||||
] |
||||
}, |
||||
{ |
||||
test: /\.glsl/, |
||||
exclude: /(node_modules)/, |
||||
loader: 'webpack-glsl-loader' |
||||
}, |
||||
{ |
||||
test: /\.css$/, |
||||
exclude: /(node_modules)/, |
||||
use: ['style-loader', 'css-loader'] |
||||
}, |
||||
{ |
||||
test: /\.(png|jpg)/, |
||||
loader: 'url-loader' |
||||
} |
||||
] |
||||
}, |
||||
resolve: { |
||||
modules: [path.join(__dirname, 'node_modules')] |
||||
} |
||||
} |
Loading…
Reference in new issue