matrix/trystero plugin updates + added simple example

This commit is contained in:
Leon van Kammen 2024-01-29 20:17:57 +01:00
parent b07e38db6e
commit ead6a93171
26 changed files with 135 additions and 37890 deletions

Binary file not shown.

View file

@ -1,262 +0,0 @@
{
"accessors" : [
{
"bufferView" : 0,
"byteOffset" : 0,
"componentType" : 5126,
"count" : 3,
"max" : [
2.000000
],
"min" : [
0.000000
],
"type" : "SCALAR"
},
{
"bufferView" : 1,
"byteOffset" : 0,
"componentType" : 5126,
"count" : 3,
"max" : [
0.000000,
1.000000,
0.000000,
1.000000
],
"min" : [
0.000000,
-8.742278e-008,
0.000000,
-1.000000
],
"type" : "VEC4"
},
{
"bufferView" : 2,
"byteOffset" : 0,
"componentType" : 5123,
"count" : 36,
"max" : [
35
],
"min" : [
0
],
"type" : "SCALAR"
},
{
"bufferView" : 3,
"byteOffset" : 0,
"componentType" : 5126,
"count" : 36,
"max" : [
1.000000,
1.000000,
1.000001
],
"min" : [
-1.000000,
-1.000000,
-1.000000
],
"type" : "VEC3"
},
{
"bufferView" : 4,
"byteOffset" : 0,
"componentType" : 5126,
"count" : 36,
"max" : [
1.000000,
1.000000,
1.000000
],
"min" : [
-1.000000,
-1.000000,
-1.000000
],
"type" : "VEC3"
},
{
"bufferView" : 5,
"byteOffset" : 0,
"componentType" : 5126,
"count" : 36,
"max" : [
1.000000,
-0.000000,
-0.000000,
1.000000
],
"min" : [
0.000000,
-0.000000,
-1.000000,
-1.000000
],
"type" : "VEC4"
},
{
"bufferView" : 6,
"byteOffset" : 0,
"componentType" : 5126,
"count" : 36,
"max" : [
1.000000,
1.000000
],
"min" : [
-1.000000,
-1.000000
],
"type" : "VEC2"
}
],
"animations" : [
{
"channels" : [
{
"sampler" : 0,
"target" : {
"node" : 0,
"path" : "rotation"
}
}
],
"name" : "animation_AnimatedCube",
"samplers" : [
{
"input" : 0,
"interpolation" : "LINEAR",
"output" : 1
}
]
}
],
"asset" : {
"generator" : "VKTS glTF 2.0 exporter",
"version" : "2.0"
},
"bufferViews" : [
{
"buffer" : 0,
"byteLength" : 12,
"byteOffset" : 0
},
{
"buffer" : 0,
"byteLength" : 48,
"byteOffset" : 12
},
{
"buffer" : 0,
"byteLength" : 72,
"byteOffset" : 60,
"target" : 34963
},
{
"buffer" : 0,
"byteLength" : 432,
"byteOffset" : 132,
"target" : 34962
},
{
"buffer" : 0,
"byteLength" : 432,
"byteOffset" : 564,
"target" : 34962
},
{
"buffer" : 0,
"byteLength" : 576,
"byteOffset" : 996,
"target" : 34962
},
{
"buffer" : 0,
"byteLength" : 288,
"byteOffset" : 1572,
"target" : 34962
}
],
"buffers" : [
{
"byteLength" : 1860,
"uri" : "AnimatedCube.bin"
}
],
"images" : [
{
"uri" : "AnimatedCube_BaseColor.png"
},
{
"uri" : "AnimatedCube_MetallicRoughness.png"
}
],
"materials" : [
{
"name" : "AnimatedCube",
"pbrMetallicRoughness" : {
"baseColorTexture" : {
"index" : 0
},
"metallicRoughnessTexture" : {
"index" : 1
}
}
}
],
"meshes" : [
{
"name" : "AnimatedCube",
"primitives" : [
{
"attributes" : {
"NORMAL" : 4,
"POSITION" : 3,
"TANGENT" : 5,
"TEXCOORD_0" : 6
},
"indices" : 2,
"material" : 0,
"mode" : 4
}
]
}
],
"nodes" : [
{
"mesh" : 0,
"name" : "AnimatedCube",
"rotation" : [
0.000000,
-1.000000,
0.000000,
0.000000
]
}
],
"samplers" : [
{}
],
"scene" : 0,
"scenes" : [
{
"nodes" : [
0
]
}
],
"textures" : [
{
"sampler" : 0,
"source" : 0
},
{
"sampler" : 0,
"source" : 1
}
]
}

View file

@ -1,160 +0,0 @@
{
"asset":{
"generator":"Khronos glTF Blender I/O v3.5.30",
"version":"2.0"
},
"scene":0,
"scenes":[
{
"name":"Scene",
"nodes":[
0
]
}
],
"nodes":[
{
"mesh":0,
"name":"AnimatedCube"
}
],
"animations":[
{
"channels":[
{
"sampler":0,
"target":{
"node":0,
"path":"rotation"
}
}
],
"name":"walk",
"samplers":[
{
"input":4,
"interpolation":"LINEAR",
"output":5
}
]
}
],
"materials":[
{
"name":"AnimatedCube",
"pbrMetallicRoughness":{}
}
],
"meshes":[
{
"name":"AnimatedCube",
"primitives":[
{
"attributes":{
"POSITION":0,
"TEXCOORD_0":1,
"NORMAL":2
},
"indices":3,
"material":0
}
]
}
],
"accessors":[
{
"bufferView":0,
"componentType":5126,
"count":36,
"max":[
1,
1,
1.0000009536743164
],
"min":[
-1,
-1,
-1
],
"type":"VEC3"
},
{
"bufferView":1,
"componentType":5126,
"count":36,
"type":"VEC2"
},
{
"bufferView":2,
"componentType":5126,
"count":36,
"type":"VEC3"
},
{
"bufferView":3,
"componentType":5123,
"count":36,
"type":"SCALAR"
},
{
"bufferView":4,
"componentType":5126,
"count":3,
"max":[
2
],
"min":[
0
],
"type":"SCALAR"
},
{
"bufferView":5,
"componentType":5126,
"count":3,
"type":"VEC4"
}
],
"bufferViews":[
{
"buffer":0,
"byteLength":432,
"byteOffset":0,
"target":34962
},
{
"buffer":0,
"byteLength":288,
"byteOffset":432,
"target":34962
},
{
"buffer":0,
"byteLength":432,
"byteOffset":720,
"target":34962
},
{
"buffer":0,
"byteLength":72,
"byteOffset":1152,
"target":34963
},
{
"buffer":0,
"byteLength":12,
"byteOffset":1224
},
{
"buffer":0,
"byteLength":48,
"byteOffset":1236
}
],
"buffers":[
{
"byteLength":1284,
"uri":"data:application/octet-stream;base64,AACAPwAAgL8AAIA/AACAvwAAgL8AAIC/AACAPwAAgL8AAIC/AACAvwAAgD8AAIC/7/9/PwAAgD8IAIA/AACAPwAAgD/v/3+/AACAPwAAgD/v/3+/AACAPwAAgL8AAIA/AACAPwAAgL8AAIC/7/9/PwAAgD8IAIA/AACAvwAAgL8AAIA/AACAPwAAgL8AAIA/AACAvwAAgL8AAIA/AACAvwAAgD8AAIC/AACAvwAAgL8AAIC/AACAPwAAgL8AAIC/AACAvwAAgD8AAIC/AACAPwAAgD/v/3+/AACAPwAAgL8AAIA/AACAvwAAgL8AAIA/AACAvwAAgL8AAIC/AACAvwAAgD8AAIC/AACAvwAAgD8AAIA/7/9/PwAAgD8IAIA/AACAPwAAgD/v/3+/7/9/PwAAgD8IAIA/AACAPwAAgL8AAIA/7/9/PwAAgD8IAIA/AACAvwAAgD8AAIA/AACAvwAAgL8AAIA/AACAvwAAgL8AAIA/AACAvwAAgD8AAIA/AACAvwAAgD8AAIC/AACAPwAAgL8AAIC/AACAvwAAgL8AAIC/AACAvwAAgD8AAIC/AAAAAAAAAAAAAIC/AACAPwAAAAAAAIA/AAAAAAAAAAAAAIA/AACAvwAAgD8AAAAAAACAPwAAAAAAAAAAAACAvwAAgD8AAIC/AACAPwAAAAAAAACAAACAvwAAgD8AAIC/AAAAAAAAAAAAAIA/AACAPwAAgD8AAAAAAAAAAAAAAAAAAIC/AACAPwAAAAAAAIA/AAAAAAAAAAAAAIC/AAAAAAAAgL8AAIA/AAAAAAAAAAAAAACAAACAvwAAgD8AAIC/AACAPwAAAAAAAACAAAAAAAAAAAAAAIC/AACAPwAAAAAAAACAAAAAAAAAAIAAAIC/AAAAAAAAAAAAAAAAAACAPwAAgD8AAIA/AAAAAAAAAAAAAIC/AAAAAAAAgL8AAIA/AAAAAAAAgL8AAACAAAAAAAAAgL8AAACAAAAAAAAAgL8AAACAAAAAAAAAgD8AAACAAAAAAAAAgD8AAACAAAAAAAAAgD8AAACAAACAPwAAAAAAAACAAACAPwAAAAAAAACAAACAPwAAAAAAAACAAAAAAAAAAIAAAIA/AAAAAAAAAIAAAIA/AAAAAAAAAIAAAIA/AACAvwAAAAAAAACAAACAvwAAAAAAAACAAACAvwAAAAAAAACAAAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAgL8AAACAAAAAAAAAgL8AAACAAAAAAAAAgL8AAACAAAAAAAAAgD8AAACAAAAAAAAAgD8AAACAAAAAAAAAgD8AAACAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAACAPwAAAAAAAAAAAAAAgAAAAAAAAIA/AAAAgAAAAAAAAIA/AAAAgAAAAAAAAIA/AACAvwAAAAAAAACAAACAvwAAAAAAAACAAACAvwAAAAAAAACAAAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAAAAAAAAAAAAIC/AAABAAIAAwAEAAUABgAHAAgACQAKAAsADAANAA4ADwAQABEAEgATABQAFQAWABcAGAAZABoAGwAcAB0AHgAfACAAIQAiACMAAAAAAAAAgD8AAABAAAAAAAAAAAAAAACAAACAPwAAAIAAAIC/AAAAAC69OzMAAAAALr27MwAAAIAAAIA/"
}
]
}

Binary file not shown.

Binary file not shown.

BIN
example/assets/example.glb Normal file

Binary file not shown.

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Binary file not shown.

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

Binary file not shown.

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -1,11 +1,12 @@
chatComponent = {
html: `
<div id="chat">
<div id="videos" style="pointer-events:none"></div>
<div id="messages" aria-live="assertive" aria-relevant></div>
<div id="chatfooter">
<div id="chatbar">
<input id="chatline" type="text" placeholder="type here"></input>
<input id="chatline" type="text" placeholder="chat here"></input>
</div>
<button id="showchat" class="btn">show chat</button>
</div>
@ -16,8 +17,8 @@ chatComponent = {
scene: null,
visible: true,
visibleChatbar: false,
messages: [],
oneMessagePerUser: false,
username: '', // configured by 'network.connected' event
@ -29,10 +30,10 @@ chatComponent = {
install(opts){
this.opts = opts
this.scene = opts.scene
this.$chatbar.style.display = 'none'
el.className = "xrf"
el.style.display = 'none' // start hidden
document.body.appendChild( el )
this.visibleChatbar = false
document.dispatchEvent( new CustomEvent("$chat:ready", {detail: opts}) )
this.send({message:`Welcome to <b>${document.location.search.substr(1)}</b>, a 3D scene(file) which simply links to other ones.<br>You can start a solo offline exploration in XR right away.<br>Type /help below, or use the arrow- or WASD-keys on your keyboard, and mouse-drag to rotate.<br>`, class: ["info","guide","multiline"] })
},
@ -41,6 +42,7 @@ chatComponent = {
let {$chatline} = this
$chatline.addEventListener('click', (e) => this.inform() )
$chatline.addEventListener('keydown', (e) => {
if (e.key == 'Enter' ){
if( $chatline.value[0] != '/' ){
@ -52,16 +54,20 @@ chatComponent = {
}
})
document.addEventListener('network.connect', (e) => {
this.visible = true
this.$chatbar.style.display = '' // show
})
document.addEventListener('network.connected', (e) => {
if( e.detail.username ) this.username = e.detail.username
})
console.dir(this.scene)
},
inform(){
if( !this.inform.informed && (this.inform.informed = true) ){
window.notify("Here you can update your statusline.<br>Protocols like [Matrix] allow you to view the full transcript<br>in a dedicated client like <a href='https://element.io' target='_blank'>element.io</a>")
window.notify("Connected via P2P. You can now type message which will be visible to others.")
}
},
@ -83,6 +89,7 @@ chatComponent = {
let {$messages} = this
opts = { linebreak:true, message:"", class:[], ...opts }
if( window.frontend && window.frontend.emit ) window.frontend.emit('$chat.send', opts )
opts.pos = opts.pos || network.posName || network.pos
let div = document.createElement('div')
let msg = document.createElement('div')
let br = document.createElement('br')
@ -98,9 +105,9 @@ chatComponent = {
br.classList.add.apply(br.classList, opts.class)
div.classList.add.apply(div.classList, opts.class.concat(["envelope"]))
}
if( !opts.from && !msg.className.match(/(info|guide)/) ){
if( !msg.className.match(/(info|guide|ui)/) ){
let frag = xrf.URI.parse(document.location.hash)
opts.from = this.username
opts.from = 'you'
if( frag.pos ) opts.pos = frag.pos.string
msg.classList.add('self')
}
@ -116,7 +123,7 @@ chatComponent = {
}
div.appendChild(msg)
// force one message per user
if( opts.from ){
if( this.oneMessagePerUser && opts.from ){
div.id = this.hyphenate(opts.from)
let oldMsg = $messages.querySelector(`#${div.id}`)
if( oldMsg ) oldMsg.remove()
@ -148,9 +155,6 @@ chatComponent = {
if( !el.inited && (el.inited = true) ) me.initListeners()
break;
}
case "visibleChatbar": {
me.$chatbar.style.display = v ? 'block' : 'none'
}
}
}
@ -234,25 +238,25 @@ chatComponent.css = `
max-width:unset;
}
#messages{
/*
display: flex;
flex-direction: column-reverse;
flex-direction: column;
width: 91%;
max-width: 500px;
*/
width:100%;
align-items: flex-start;
position: absolute;
transition:1s;
top: 0px;
top: 77px;
left: 0;
bottom: 49px;
padding: 20px;
overflow:hidden;
overflow-y: scroll;
pointer-events:none;
transition:1s;
width: 91%;
max-width: 500px;
z-index: 100;
-webkit-user-select:none;
-moz-user-select:-moz-none;
-ms-user-select:none;
user-select:none;
}
body.menu #messages{
top:50px;
@ -261,7 +265,11 @@ chatComponent.css = `
pointer-events:all;
}
#messages *{
pointer-events:all;
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;
@ -272,11 +280,18 @@ chatComponent.css = `
color: #000c;
margin-bottom: 10px;
line-height:23px;
pointer-events:visible;
line-height:33px;
cursor:grabbing;
border: 1px solid #0002;
}
#messages .msg *{
pointer-events:all;
-webkit-user-select:text;
-moz-user-select:-moz-text;
-ms-user-select:text;
user-select:text;
}
#messages .msg.self{
border-radius: 20px;
background:var(--xrf-box-shadow);
@ -303,7 +318,7 @@ chatComponent.css = `
transition:0.3s;
}
#messages .msg.info a,
#messages .ruler a{
#messages a.ruler{
color:#FFF;
}
#messages .msg a:hover{
@ -375,10 +390,19 @@ chatComponent.css = `
margin:0;
}
.envelope{
height:unset;
.envelope,
.envelope * {
overflow:hidden;
transition:1s;
pointer-events:none;
}
.envelope a,
.envelope button,
.envelope input,
.envelope textarea,
.envelope msg,
.envelope msg * {
pointer-events:all;
}
.user{

View file

@ -2,7 +2,7 @@ connectionsComponent = {
html: `
<div id="connections">
<i class="gg-close-o" id="close" onclick="$connections.toggle()"></i>
<i class="gg-close-o" id="close" onclick="$connections.visible = false"></i>
<br>
<div class="tab-frame">
<input type="radio" name="tab" id="login" checked>
@ -83,6 +83,8 @@ connectionsComponent = {
init: (el) => new Proxy({
visible: true,
webcam: [{profile:{name:"No thanks"},config: () => document.createElement('div')}],
chatnetwork: [{profile:{name:"No thanks"},config: () => document.createElement('div')}],
scene: [{profile:{name:"No thanks"},config: () => document.createElement('div')}],
@ -117,8 +119,7 @@ connectionsComponent = {
},
toggle(){
let parent = el.closest('.envelope')
parent.style.display = parent.style.display == 'none' ? parent.style.display = '' : 'none'
$chat.visible = !$chat.visible
},
change(id,e){
@ -130,13 +131,14 @@ connectionsComponent = {
show(opts){
opts = opts || {}
if( opts.hide ){
el.parentElement.parentElement.style.display = 'none'
if( el.parentElement ) el.parentElement.parentElement.style.display = 'none' // hide along with wrapper elements
if( !opts.showChat ) $chat.visible = false
}else{
$chat.visible = true
this.visible = true
// hide networking settings if entering thru meetinglink
$networking.style.display = document.location.href.match(/meet=/) ? 'none' : 'block'
if( !network.connected ){
if( el.parentElement ) el.parentElement.parentElement.remove()
document.querySelector('body > .xrf').appendChild(el)
$chat.send({message:"", el, class:['ui']})
if( !network.meetinglink ){ // set default
@ -233,7 +235,7 @@ connectionsComponent = {
reactToNetwork(){ // *TODO* move to network?
document.addEventListener('network.connect', () => {
this.show({hide:true})
this.show({hide:true, showChat: true})
})
document.addEventListener('network.disconnect', () => {
this.connected = false
@ -247,6 +249,7 @@ connectionsComponent = {
set(data,k,v){
data[k] = v
switch( k ){
case "visible": el.style.display = v ? '' : 'none'; break;
case "webcam": $webcam.innerHTML = `<option>${data[k].map((p)=>p.profile.name).join('</option><option>')}</option>`; break;
case "chatnetwork": $chatnetwork.innerHTML = `<option>${data[k].map((p)=>p.profile.name).join('</option><option>')}</option>`; break;
case "scene": $scene.innerHTML = `<option>${data[k].map((p)=>p.profile.name).join('</option><option>')}</option>`; break;

View file

@ -16,8 +16,8 @@ menuComponent = (el) => new Proxy({
$buttons: $buttons = el.querySelector('#buttons'),
$btnMore: $btnMore = el.querySelector('#more'),
toggle(){
this.collapsed = !this.collapsed
toggle(state){
this.collapsed = state !== undefined ? state : !this.collapsed
el.querySelector("i#icon").className = this.collapsed ? 'gg-close' : 'gg-menu'
document.body.classList[ this.collapsed ? 'add' : 'remove' ](['menu'])
},

View file

@ -43,6 +43,7 @@ window.frontend = (opts) => new Proxy({
.setupUserHints()
.setupNetworkListeners()
.hidetopbarWhenMenuCollapse()
.hideUIWhenNavigating()
window.notify = this.notify
setTimeout( () => {
@ -130,6 +131,29 @@ window.frontend = (opts) => new Proxy({
return this
},
hideUIWhenNavigating(){
// hide ui when user is navigating the scene using mouse/touch
let showUI = (show) => (e) => {
let isChatMsg = e.target.closest('.msg')
let isChatLine = e.target.id == 'chatline'
let isChatEmptySpace = e.target.id == 'messages'
let isUI = e.target.closest('.ui')
//console.dir({class: e.target.className, id: e.target.id, isChatMsg,isChatLine,isChatEmptySpace,isUI, tagName: e.target.tagName})
if( isUI || e.target.tagName.match(/^(BUTTON|TEXTAREA|INPUT|A)/) || e.target.className.match(/(btn)/) ) return
if( show ){
$chat.visible = true
}else{
$chat.visible = false
$menu.toggle(false)
}
return true
}
document.addEventListener('mousedown', showUI(false) )
document.addEventListener('mouseup', showUI(true) )
document.addEventListener('touchstart', showUI(false) )
document.addEventListener('touchend', showUI(true) )
},
loadFile(contentLoaders, multiple){
return () => {
window.notify("if you're on Meta browser, file-uploads might be disabled")
@ -218,10 +242,11 @@ window.frontend = (opts) => new Proxy({
share(opts){
opts = opts || {notify:true,qr:true,share:true,linkonly:false}
if( network.connected && !document.location.hash.match(/meet=/) ){
let p = $connections.chatnetwork.find( (p) => p.profile.name == $connections.selectedChatnetwork )
console.dir(p)
if( p.link ) document.location.hash = `${ network.pos ? `pos=${network.pos}` : ''}&meet=${p.link}`
if( network.meetingLink && !document.location.hash.match(/meet=/) ){
document.location.hash += `&meet=${network.meetingLink}`
}
if( !document.location.hash.match(/pos=/) ){
document.location.hash += `&pos=${ network.posName || network.pos }`
}
let url = window.location.href
if( opts.linkonly ) return url

View file

@ -60,8 +60,7 @@ window.network = (opts) => new Proxy({
for ( var i in String.prototype ) add(i)
var a = names[Math.floor(Math.random() * names.length)];
var b = names[Math.floor(Math.random() * names.length)];
var c = names[Math.floor(Math.random() * names.length)];
return String(`${a}-${b}-${c}`).toLowerCase()
return String(`${a}-${b}-${String(Math.random()).substr(13)}`).toLowerCase()
}
},

View file

@ -49,7 +49,7 @@ window.matrix = (opts) => new Proxy({
<tr>
<td>user</td>
<td>
<input type="text" id="username" placeholder="@you:matrix.org"/>
<input type="text" id="username" placeholder="@you:matrix.org" value="${opts.plugin.username}"/>
</td>
</tr>
<tr>
@ -76,7 +76,8 @@ window.matrix = (opts) => new Proxy({
init(){
frontend.plugin['matrix'] = this
$connections.chatnetwork = $connections.chatnetwork.concat([this])
$connections.scene = $connections.chatnetwork.concat([this])
$connections.scene = $connections.scene.concat([this])
if( window.localStorage.getItem("username") ) this.username = window.localStorage.getItem("username")
this.reactToConnectionHrefs()
document.addEventListener('network.connect', (e) => this.connect(e.detail) )
@ -93,8 +94,8 @@ window.matrix = (opts) => new Proxy({
if( opts.selectedChatnetwork == this.profile.name ) this.useChat = true
if( opts.selectedScene == this.profile.name ) this.useScene = true
if( this.useWebcam || this.useScene || this.useChat ){
this.createLink() // ensure link
this.link = `matrix://r/${this.channel.replace(/^#/,'')}`
this.createLink() // ensure link
this.channel = document.querySelector("#matrix input#channel").value
this.server = document.querySelector("#matrix input#server").value
this.username = document.querySelector("#matrix input#username").value
@ -156,7 +157,10 @@ window.matrix = (opts) => new Proxy({
.then( (o) => {
console.log(`${this.channel} has id ${o.room_id}`)
this.roomId = o.room_id
this.setupListeners()
// join room if we haven't already
this.client.joinRoom(this.roomId)
.then( () => this.setupListeners() )
.catch( () => this.setupListeners() )
})
.catch((e) => {
console.error(e)
@ -242,7 +246,7 @@ window.matrix = (opts) => new Proxy({
formatted_body: message,
msgtype:"m.text"
}
this.client.sendEvent( this.roomId, "m.room.message", content, "", (err,res) => console.error(err) )
this.client.sendEvent( this.roomId, "m.room.message", content, "", (err,res) => console.error({err,res}) )
})
},
@ -292,7 +296,7 @@ window.matrix = (opts) => new Proxy({
let hash = document.location.hash
if( !this.link ){
const meeting = network.getMeetingFromUrl(document.location.href)
this.link = meeting.match("matrix://") ? meeting : ''
this.link = network.meetingLink = meeting.match("matrix://") ? meeting : ''
}
if( !hash.match('meet=') ) document.location.hash += `${hash.length > 1 ? '&' : '#'}meet=${this.link}`
},

View file

@ -88,8 +88,8 @@ window.trystero = (opts) => new Proxy({
console.log("trystero link: "+this.link)
this.room = joinRoom( {appId: 'xrfragment'}, this.link )
$chat.send({message:`Share the meeting link <a onclick="frontend.share()">by clicking here</a>`,class:['info'],timeout:10000})
$chat.send({message:"waiting for other humans..",class:['info'], timeout:5000})
$chat.send({message:`Share the meeting link <a onclick="frontend.share()">by clicking here</a>`,class:['info']})
$chat.send({message:"waiting for other humans..",class:['info']})
// setup trystero events
const [sendPing, getPing] = this.room.makeAction('ping')
@ -132,6 +132,7 @@ window.trystero = (opts) => new Proxy({
this.chat.get = getChat
document.addEventListener('network.send', (e) => {
console.log("trystero")
this.chat.send({...e.detail, from: this.nickname, pos: network.pos }) // send to P2P network
})
// prime chatlog of other people joining
@ -159,7 +160,7 @@ window.trystero = (opts) => new Proxy({
video: $connections.$videoInput.value
})
this.room.addStream(this.selfStream)
this.videos[ this.selfId ] = this.getVideo(this.selfId,{stream: this.selfStream})
this.getVideo(this.selfId,{create:true,stream: this.selfStream})
// send stream + chatlog to peers who join later
this.room.onPeerJoin( (peerId) => this.room.addStream( this.selfStream, peerId))
@ -198,7 +199,8 @@ window.trystero = (opts) => new Proxy({
// add video element to the DOM
if( opts.stream ) video.srcObject = opts.stream
console.log("creating video for peerId")
console.log("creating video for peerId "+this.selfId)
this.videos[ this.selfId ] = video
$chat.$videos.appendChild(video)
}
},
@ -209,7 +211,7 @@ window.trystero = (opts) => new Proxy({
let hash = document.location.hash
if( !this.link ){
const meeting = network.getMeetingFromUrl(document.location.href)
this.link = meeting.match("trystero://") ? meeting : `trystero://r/${network.randomRoom()}:bittorrent`
this.link = network.meetingLink = meeting.match("trystero://") ? meeting : `trystero://r/${network.randomRoom()}:bittorrent`
}
if( !hash.match('meet=') ) document.location.hash += `${hash.length > 1 ? '&' : '#'}meet=${this.link}`
},

View file

@ -53,15 +53,6 @@ xrf.getFile = (url) => url.split("/").pop().replace(/#.*/,'')
xrf.parseModel = function(model,url){
let file = xrf.getFile(url)
model.file = file
model.animations.map( (a) => console.log("anim: "+a.name) )
// spec: 2. init metadata inside model for non-SRC data
if( !model.isSRC ){
model.scene.traverse( (mesh) => xrf.hashbus.pub.mesh(mesh,model) )
}
// spec: 1. execute the default predefined view '#' (if exist) (https://xrfragment.org/#predefined_view)
xrf.frag.defaultPredefinedViews({model,scene:model.scene})
// spec: predefined view(s) & objects-of-interest-in-XRWG from URL (https://xrfragment.org/#predefined_view)
let frag = xrf.hashbus.pub( url, model) // and eval URI XR fragments
xrf.emit('parseModel',{model,url,file})
}
@ -93,6 +84,8 @@ xrf.reset = () => {
// remove mixers
xrf.mixers.map( (m) => m.stop())
xrf.mixers = []
// set the player to position 0,0,0
xrf.camera.position.set(0,0,0)
}
xrf.parseUrl = (url) => {

View file

@ -38,29 +38,42 @@ xrf.navigator.to = (url,flags,loader,data) => {
return resolve(xrf.model)
}
// clear xrf objects from scene
if( xrf.model && xrf.model.scene ) xrf.model.scene.visible = false
xrf.reset()
// force relative path for files which dont include protocol or relative path
if( dir ) dir = dir[0] == '.' || dir.match("://") ? dir : `.${dir}`
url = url.replace(dir,"")
loader = loader || new Loader().setPath( dir )
const onLoad = (model) => {
xrf.reset() // clear xrf objects from scene
model.file = file
// only change url when loading *another* file
if( xrf.model ) xrf.navigator.pushState( `${dir}${file}`, hash )
xrf.model = model
if(xrf.debug ) model.animations.map( (a) => console.log("anim: "+a.name) )
// spec: 2. init metadata inside model for non-SRC data
if( !model.isSRC ){
model.scene.traverse( (mesh) => xrf.hashbus.pub.mesh(mesh,model) )
}
// spec: 1. generate the XRWG
xrf.XRWG.generate({model,scene:model.scene})
// spec: 1. execute the default predefined view '#' (if exist) (https://xrfragment.org/#predefined_view)
xrf.frag.defaultPredefinedViews({model,scene:model.scene})
// spec: predefined view(s) & objects-of-interest-in-XRWG from URL (https://xrfragment.org/#predefined_view)
let frag = xrf.hashbus.pub( url, model) // and eval URI XR fragments
xrf.add( model.scene )
if( hash ) xrf.navigator.updateHash(hash)
xrf.emit('navigateLoaded',{url,model})
resolve(model)
}
if( data ) loader.parse(data, "", onLoad )
else loader.load(url, onLoad )
if( data ){ // file upload
loader.parse(data, "", onLoad )
}else loader.load(url, onLoad )
})
})
})

View file

@ -4,9 +4,11 @@ xrf.frag.defaultPredefinedViews = (opts) => {
if( n.userData && n.userData['#'] ){
let frag = xrf.URI.parse( n.userData['#'] )
if( n.parent && n.parent.parent.isScene && document.location.hash.length < 2 ){
xrf.navigator.to( n.userData['#'] ) // evaluate main scene XR fragments and update URL
xrf.navigator.to( n.userData['#'] ) // evaluate static XR fragments
console.log("to")
}else{
xrf.hashbus.pub( n.userData['#'] ) // evaluate static XR fragments
console.log("pub")
}
}
})

View file

@ -47,12 +47,12 @@ xrf.frag.href = function(v, opts){
let toFrag = xrf.URI.parse( v.string, xrf.XRF.NAVIGATOR | xrf.XRF.PV_OVERRIDE | xrf.XRF.METADATA )
// always commit current location in case of teleport (keep a trail of last positions before we navigate)
if( isLocal && !hasPos ){
xrf.hashbus.pub( v.string, xrf.model ) // publish to hashbus
}else{
//if( isLocal && !hasPos ){
// xrf.hashbus.pub( v.string, xrf.model ) // publish to hashbus
//}else{
//if( !e.nocommit && !document.location.hash.match(lastPos) ) xrf.navigator.updateHash(`#${lastPos}`)
xrf.navigator.to(v.string) // let's surf
}
//}
})
.catch( console.error )
}

View file

@ -9,7 +9,7 @@ xrf.addEventListener('env', (opts) => {
//scene.texture = env.material.map
// renderer.toneMapping = THREE.ACESFilmicToneMapping;
// renderer.toneMappingExposure = 2;
console.log(` └ applied image '${frag.env.string}' as environment map`)
// console.log(` └ applied image '${frag.env.string}' as environment map`)
}
})