diff --git a/example/aframe/sandbox/index.html b/example/aframe/sandbox/index.html
index 7b4f656..f4093ba 100644
--- a/example/aframe/sandbox/index.html
+++ b/example/aframe/sandbox/index.html
@@ -5,7 +5,8 @@
-
+
+
diff --git a/example/assets/index.glb b/example/assets/index.glb
index 47b51b8..970009d 100644
Binary files a/example/assets/index.glb and b/example/assets/index.glb differ
diff --git a/make b/make
index 2a9d3bc..a032498 100755
--- a/make
+++ b/make
@@ -105,7 +105,7 @@ build(){
cp src/3rd/js/plugin/frontend/\$editor.js dist/xrfragment.plugin.editor.js
cp src/3rd/js/plugin/frontend/css.js dist/xrfragment.plugin.frontend.css.js
- jscat src/3rd/js/plugin/frontend/{snackbar,accessibility,\$menu,frontend}.js > dist/xrfragment.plugin.frontend.js
+ jscat src/3rd/js/plugin/frontend/{snackbar,accessibility,\$menu,frontend,chatcommand/*}.js > dist/xrfragment.plugin.frontend.js
jscat src/3rd/js/plugin/matrix/{matrix-crdt,matrix}.js > dist/xrfragment.plugin.matrix.js
jscat src/3rd/js/plugin/p2p/{trystero-torrent.min,trystero}.js > dist/xrfragment.plugin.p2p.js
diff --git a/src/3rd/js/aframe/index.js b/src/3rd/js/aframe/index.js
index bd91d91..82f7897 100644
--- a/src/3rd/js/aframe/index.js
+++ b/src/3rd/js/aframe/index.js
@@ -53,10 +53,16 @@ window.AFRAME.registerComponent('xrf', {
VRbutton = document.querySelector('.a-enter-vr-button')
if( ARbutton ) ARbutton.addEventListener('click', () => AFRAME.XRF.hashbus.pub( '#-VR' ) )
if( VRbutton ) VRbutton.addEventListener('click', () => AFRAME.XRF.hashbus.pub( '#VR' ) )
- //if( AFRAME.utils.device.checkARSupport() && VRbutton ){
- // VRbutton.style.display = 'none'
- // ARbutton.parentNode.style.right = '20px'
- //}
+ })
+
+ // (de)active look-controls because of 'rot=' XR Fragment
+ aScene.addEventListener('loaded', () => {
+ // this is just for convenience (not part of spec): enforce AR + hide/show stuff based on VR tags in 3D model
+ aScene.canvas.addEventListener('mousedown', () => xrf.camera.el.setAttribute("look-controls","") )
+ })
+ XRF.addEventListener('rot',(e) => {
+ let lookcontrols = document.querySelector('[look-controls]')
+ if( lookcontrols ) lookcontrols.removeAttribute("look-controls")
})
let repositionUser = (scale) => () => {
diff --git a/src/3rd/js/plugin/frontend/$chat.js b/src/3rd/js/plugin/frontend/$chat.js
index ba3ff79..5479cc9 100644
--- a/src/3rd/js/plugin/frontend/$chat.js
+++ b/src/3rd/js/plugin/frontend/$chat.js
@@ -28,6 +28,7 @@ chatComponent = {
$messages: el.querySelector("#messages"),
$chatline: el.querySelector("#chatline"),
$chatbar: el.querySelector("#chatbar"),
+ $chatsend: el.querySelector("#chatsend"),
install(opts){
this.opts = opts
@@ -40,6 +41,19 @@ chatComponent = {
this.send({message:`Welcome to ${document.location.search.substr(1)}, a 3D scene(file) which simply links to other ones.
You can start a solo offline exploration in XR right away.
Type /help below, or use the arrow- or WASD-keys on your keyboard, and mouse-drag to rotate.
`, class: ["info","guide","multiline"] })
},
+ sendInput(value){
+ if( value[0] == '#' ) return xrf.navigator.to(value)
+ let event = value.match(/^[!\/]/) ? "chat.command" : "network.send"
+ let message = value.replace(/^[!\/]/,'')
+ let raw = {detail:{message:value, halt:false}}
+ document.dispatchEvent( new CustomEvent( event, {detail: {message}} ) )
+ document.dispatchEvent( new CustomEvent( "chat.input", raw ) )
+ if( event == "network.send" && !raw.detail.halt ) this.send({message: value })
+ this.$chatline.lastValue = value
+ this.$chatline.value = ''
+ if( window.innerHeight < 600 ) this.$chatline.blur()
+ },
+
initListeners(){
let {$chatline} = this
@@ -47,12 +61,10 @@ chatComponent = {
$chatline.addEventListener('keydown', (e) => {
if (e.key == 'Enter' ){
- let event = $chatline.value.match(/^[!\/]/) ? "chat.command" : "network.send"
- let message = $chatline.value.replace(/^[!\/]/,'')
- document.dispatchEvent( new CustomEvent( event, {detail: {message}} ) )
- if( event == "network.send" ) this.send({message: $chatline.value })
- $chatline.value = ''
- if( window.innerHeight < 600 ) $chatline.blur()
+ this.sendInput($chatline.value)
+ }
+ if (e.key == 'ArrowUp' ){
+ $chatline.value = $chatline.lastValue || ''
}
})
@@ -76,11 +88,15 @@ chatComponent = {
}
})
+ this.$chatsend.addEventListener('click', (e) => {
+ this.sendInput($chatline.value)
+ })
+
},
inform(){
if( !this.inform.informed && (this.inform.informed = true) ){
- window.notify("Connected via P2P. You can now type message which will be visible to others.")
+ window.notify("You can now type messages in the textfield below.")
}
},
@@ -263,6 +279,7 @@ chatComponent.css = `
max-width: 500px;
*/
width:100%;
+ box-sizing:border-box;
align-items: flex-start;
position: absolute;
transition:1s;
@@ -271,7 +288,7 @@ chatComponent.css = `
bottom: 49px;
padding: 20px;
overflow:hidden;
- overflow-y: scroll;
+ overflow-y: auto;
pointer-events:none;
transition:1s;
z-index: 100;
@@ -283,11 +300,14 @@ chatComponent.css = `
pointer-events:all;
}
#messages *{
+ box-sizing:border-box;
+/*
pointer-events:none;
-webkit-user-select:none;
-moz-user-select:-moz-none;
-ms-user-select:none;
user-select:none;
+*/
}
#messages .msg{
transition:all 1s ease;
@@ -320,9 +340,9 @@ chatComponent.css = `
color:#FFF;
}
#messages .msg.info{
- background: #473f7f;
+ background: var(--xrf-white);
border-radius: 20px;
- color: #FFF;
+ color: var(--xrf-dark-gray);
text-align: left;
line-height: 19px;
}
@@ -411,7 +431,8 @@ chatComponent.css = `
.envelope{
margin-right:15px;
- max-width:80%;
+ width:50%;
+ max-width:700px;
}
.envelope,
diff --git a/src/3rd/js/plugin/frontend/accessibility.js b/src/3rd/js/plugin/frontend/accessibility.js
index e93de4a..7d3e10d 100644
--- a/src/3rd/js/plugin/frontend/accessibility.js
+++ b/src/3rd/js/plugin/frontend/accessibility.js
@@ -4,14 +4,15 @@ window.accessibility = (opts) => new Proxy({
enabled: false,
// features
- speak_movements: true,
- speak_keyboard: true,
+ speak_teleports: true,
+ speak_keyboard: false,
// audio settings
speak_rate: 1,
speak_pitch: 1,
speak_volume: 1,
speak_voice: -1,
+ speak_voices: 0,
toggle(){ this.enabled = !this.enabled },
@@ -33,8 +34,10 @@ window.accessibility = (opts) => new Proxy({
}
let speech = window.speechSynthesis
let utterance = new SpeechSynthesisUtterance( str )
- if( this.speak_voice != -1) utterance.voice = speech.getVoices()[ this.speak_voice ];
- else{
+ this.speak_voices = speech.getVoices().length
+ if( this.speak_voice != -1 && this.speak_voice < this.speak_voices ){
+ utterance.voice = speech.getVoices()[ this.speak_voice ];
+ }else{
let voices = speech.getVoices()
for(let i = 0; i < voices.length; i++ ){
if( voices[i].lang == navigator.lang ) this.speak_voice = i;
@@ -78,6 +81,9 @@ window.accessibility = (opts) => new Proxy({
this.speak( lines.join("."), {override:true,speaksigns:false} )
}
})
+ document.addEventListener('$chat.send', (opts) => {
+ if( opts.detail.message ) this.speak( opts.detail.message)
+ })
})
document.addEventListener('network.send', (e) => {
@@ -87,8 +93,7 @@ window.accessibility = (opts) => new Proxy({
})
opts.xrf.addEventListener('pos', (opts) => {
- if( this.enabled ){
- $chat.send({message: this.posToMessage(opts) })
+ if( this.enabled && this.speak_teleports ){
network.send({message: this.posToMessage(opts), class:["info","guide"]})
}
if( opts.frag.pos.string.match(/,/) ){
@@ -100,7 +105,7 @@ window.accessibility = (opts) => new Proxy({
setTimeout( () => this.initCommands(), 200 )
// auto-enable if previously enabled
- if( window.localStorage.getItem("accessibility") ){
+ if( window.localStorage.getItem("accessibility") === 'true' ){
setTimeout( () => {
this.enabled = true
this.setFontSize()
@@ -111,7 +116,7 @@ window.accessibility = (opts) => new Proxy({
initCommands(){
document.addEventListener('chat.command.help', (e) => {
- e.detail.message += `
/fontsize
/fontsize <number> set fontsize (default=14) `
})
document.addEventListener('chat.command', (e) => {
@@ -179,10 +184,11 @@ window.accessibility = (opts) => new Proxy({
data[k] = v
switch( k ){
case "enabled": {
- let message = "accessibility has been"+(v?"boosted":"lowered")
+ let message = "accessibility mode has been "+(v?"activated":"disabled")+".
Type /help for help."
+ if( v ) message = "
" + message
$('#accessibility.btn').style.filter= v ? 'brightness(1.0)' : 'brightness(0.5)'
if( v ) $chat.visible = true
- $chat.send({message,class:['info','guide']})
+ $chat.send({message,class:['info']})
data.enabled = true
data.speak(message)
data.enabled = v
@@ -212,6 +218,10 @@ document.querySelector('head').innerHTML += `
font-size:24px !important;
line-height:40px;
}
+ .accessibility #messages .msg.self {
+ background:var(--xrf-gray);
+ color:#FFF;
+ }
.accessibility #messages .msg.info,
.accessibility #messages .msg.self {
line-height:unset;
diff --git a/src/3rd/js/plugin/frontend/chatcommand/href.js b/src/3rd/js/plugin/frontend/chatcommand/href.js
new file mode 100644
index 0000000..074ed1c
--- /dev/null
+++ b/src/3rd/js/plugin/frontend/chatcommand/href.js
@@ -0,0 +1,20 @@
+// this allows surfing to a href by typing its node-name
+
+// help screen
+document.addEventListener('chat.command.help', (e) => {
+ e.detail.message += `
+
<destinationname> surf to a destination
+ `
+})
+
+document.addEventListener('chat.input', (e) => {
+
+ let name = e.detail.message.trim()
+ xrf.scene.traverse( (n) => {
+ if( n.userData && n.userData.href && n.userData.href.match(/pos=/) && n.name == name ){
+ $chat.send({message:'activating '+n.name, class:['self','info']})
+ xrf.navigator.to( n.userData.href )
+ }
+ })
+
+})
diff --git a/src/3rd/js/plugin/frontend/chatcommand/mud.js b/src/3rd/js/plugin/frontend/chatcommand/mud.js
new file mode 100644
index 0000000..f4e066a
--- /dev/null
+++ b/src/3rd/js/plugin/frontend/chatcommand/mud.js
@@ -0,0 +1,144 @@
+// this allows a more-or-less MUD type interface
+//
+//
+
+
+// help screen
+document.addEventListener('chat.command.help', (e) => {
+ e.detail.message += `
+
? help screen
+
look view scene and destinations
+
go [left|right|forward|destination] surf [to destination]
+
do [action] list [or perform] action(s)
+
rotate <left|right|up|down> rotate camera
+
back go to previous portal/link
+
forward go to previous portal/link
+
#.... execute XR Fragments
+