added share button + parent world link

This commit is contained in:
Leon van Kammen 2026-08-18 15:30:10 +02:00
parent 1f4b3d52ec
commit c81f37d2c3
23 changed files with 257 additions and 50 deletions

4
.env
View file

@ -1,6 +1,6 @@
# aliases # aliases
build(){ $(pwd)/src/util/xrforge.sh build; } build(){ $(pwd)/src/util/build.sh build; }
rebuild(){ $(pwd)/src/util/xrforge.sh rebuild; } rebuild(){ $(pwd)/src/util/build.sh rebuild; }
# forgejo server hook # forgejo server hook
#test "$GITEA_ROOT_URL" = "https://xrforge.isvery.ninja/" && { #test "$GITEA_ROOT_URL" = "https://xrforge.isvery.ninja/" && {

View file

@ -54,6 +54,7 @@ app.opts = require('config')(app)
-- load system plugins (in specific order for admin panel) -- load system plugins (in specific order for admin panel)
app.plugin.global = app.addPlugin('plugin/global') app.plugin.global = app.addPlugin('plugin/global')
app.plugin.pubnix = app.addPlugin('plugin/pubnix')
app.plugin.diskscan = app.addPlugin('plugin/diskscan') app.plugin.diskscan = app.addPlugin('plugin/diskscan')
app.plugin.convert = app.addPlugin('plugin/convert') app.plugin.convert = app.addPlugin('plugin/convert')
app.plugin.moderation = app.addPlugin('plugin/moderation') app.plugin.moderation = app.addPlugin('plugin/moderation')
@ -76,7 +77,7 @@ print = function(...) Log(kLogInfo, ... or "''") end -- nice redbean logging fro
-- init URL router -- init URL router
app.url['^/data'] = '/data.lua' -- setup custom file endpoint app.url['^/data'] = '/data.lua' -- setup custom file endpoint
app.get('^/$', app.plugin.global.middleware.homepage_2D_or_3D ) app.use( app.plugin.global.middleware.homepage_2D_or_3D )
app.url['^/admin[/]?$'] = '/page/admin/index.lua' app.url['^/admin[/]?$'] = '/page/admin/index.lua'
app.get('^/design[/]?$', util.pagerender('page/design.html')) app.get('^/design[/]?$', util.pagerender('page/design.html'))

View file

@ -327,7 +327,7 @@ end
function util.stripPath(str) function util.stripPath(str)
return str:gsub("^./",""):gsub("^/",""):gsub("/$","") return str:gsub("^/zip/",""):gsub("^./",""):gsub("^/",""):gsub("/$","")
end end
-- WARNING: this is a destructive function which renders the redbean server inactive -- WARNING: this is a destructive function which renders the redbean server inactive

View file

@ -151,7 +151,7 @@ form > table > tbody > tr > td:nth-child(3) {
.primary { color: #ff33Ff;} .primary { color: #ff33Ff;}
.secondary { color: #7070ff;} .secondary { color: #7070ff;}
.btn a.primary{ background: #ff33Ff; color:#000} .btn a.primary{ background: #ff33Ff; color:#000}
.btn a.secondary{ background: #224; color: #83f; } .btn a.secondary{ background: #000; color: #83f; }
.pad1{ .pad1{
padding:20px; padding:20px;

12
src/img/share.svg Normal file
View file

@ -0,0 +1,12 @@
<svg
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M18 9C19.6569 9 21 7.65685 21 6C21 4.34315 19.6569 3 18 3C16.3431 3 15 4.34315 15 6C15 6.12549 15.0077 6.24919 15.0227 6.37063L8.08261 9.84066C7.54305 9.32015 6.80891 9 6 9C4.34315 9 3 10.3431 3 12C3 13.6569 4.34315 15 6 15C6.80891 15 7.54305 14.6798 8.08261 14.1593L15.0227 17.6294C15.0077 17.7508 15 17.8745 15 18C15 19.6569 16.3431 21 18 21C19.6569 21 21 19.6569 21 18C21 16.3431 19.6569 15 18 15C17.1911 15 16.457 15.3202 15.9174 15.8407L8.97733 12.3706C8.99229 12.2492 9 12.1255 9 12C9 11.8745 8.99229 11.7508 8.97733 11.6294L15.9174 8.15934C16.457 8.67985 17.1911 9 18 9Z"
fill="currentColor"
/>
</svg>

After

Width:  |  Height:  |  Size: 736 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 32 KiB

After

Width:  |  Height:  |  Size: 91 KiB

View file

@ -1,3 +1,4 @@
<!-- https://aframe.io/aframe/examples/boilerplate/hello-world/ -->
<a-scene> <a-scene>
<a-assets> <a-assets>
<a-asset-item id="tree" src="tree2.glb"></a-asset-item> <a-asset-item id="tree" src="tree2.glb"></a-asset-item>

View file

@ -5,7 +5,7 @@ ${header}
<div style="height:90px;" class="jumbotron"> <div style="height:90px;" class="jumbotron">
<h1 style="display:none">${opts.title}</h1> <h1 style="display:none">${opts.title}</h1>
<br> <br>
<center class="col3">${opts.plugin_global_subtitle}</center> <center class="col3">${opts.plugin_global_subtitle} </center>
</div> </div>
<hr style="margin-top:0"/> <hr style="margin-top:0"/>
]]) ]])
@ -21,20 +21,23 @@ end}
{if items then {if items then
for i=1,#items do for i=1,#items do
local item = items[i] local item = items[i]
local icon = 'list-tree' local visible = item.view2D == nil or (item.view2D ~= nil and item.view2D ~= false)
local thumbnail = '' if visible then
if #item.thumbnail > 0 then thumbnail = 'style="background-image: url(' .. EscapeFragment( util.stripPath(item.thumbnail) ) .. ');"' end local icon = 'list-tree'
if item.view3D or item.portal3D == false then icon = 'play' end local thumbnail = ''
print([[ if #item.thumbnail > 0 then thumbnail = 'style="background-image: url(' .. EscapeFragment( util.stripPath(item.thumbnail) ) .. ');"' end
<div class="tile"> if item.view3D or item.portal3D == false then icon = 'play' end
<a href="]] .. util.stripPath(item.url) .. [["> print([[
<div class="img" ]] .. util.stripPath(thumbnail) .. [[></div> <div class="tile">
<div class="text"> <a href="]] .. util.stripPath(item.url) .. [[">
<img src="img/]] .. icon .. [[.svg" class="icon ]] .. icon .. [["/>&nbsp;<a href="]] .. util.stripPath(item.url) .. [[">]] .. item.title .. [[</a> <div class="img" ]] .. util.stripPath(thumbnail) .. [[></div>
</div> <div class="text">
</a> <img src="img/]] .. icon .. [[.svg" class="icon ]] .. icon .. [["/>&nbsp;<a href="]] .. util.stripPath(item.url) .. [[">]] .. item.title .. [[</a>
</div> </div>
]]) </a>
</div>
]])
end
end end
end} end}
{if itemsremote then {if itemsremote then
@ -46,7 +49,7 @@ end}
if item.view3D or item.portal3D == false then icon = 'play' end if item.view3D or item.portal3D == false then icon = 'play' end
print([[ print([[
<div class="tile"> <div class="tile">
<a href="]] .. util.stripPath(item.url) .. [["> <a href="]] .. util.stripPath(item.url) .. [[">
<div class="img" ]] .. util.stripPath(thumbnail) .. [[></div> <div class="img" ]] .. util.stripPath(thumbnail) .. [[></div>
<div class="text"> <div class="text">
<img src="img/]] .. icon .. [[.svg" class="icon ]] .. icon .. [["/>&nbsp;<a href="]] .. util.stripPath(item.url) .. [[">]] .. item.title .. [[</a> <img src="img/]] .. icon .. [[.svg" class="icon ]] .. icon .. [["/>&nbsp;<a href="]] .. util.stripPath(item.url) .. [[">]] .. item.title .. [[</a>

View file

@ -30,17 +30,13 @@ return {
-- "parent = " .. util.stripPath(v.parent.path) .. " " .. -- "parent = " .. util.stripPath(v.parent.path) .. " " ..
-- "matchpath = " .. util.stripPath(matchpath) -- "matchpath = " .. util.stripPath(matchpath)
-- ) -- )
if match(v.path, matchpath) then -- show parent folder if any --if match(v.path, matchpath) then -- add parent folder if any
local parent = app.cache.items[ v.parent.id ] --res.items[ v.parent.id ] = v.parent
if v.portal then -- if match(v.parent.path, app.opts.plugin_diskscan_dir) then -- add rootfolder if needed
trace("-- portal redirect") -- local root = app.cache.items[ app.opts.plugin_diskscan_dir ]
redirect = v.portal.url -- res.items[ root.id ] = root
end -- end
if match(parent.path, app.opts.plugin_diskscan_dir) then -- add rootfolder if needed --end
local root = app.cache.items[ app.opts.plugin_diskscan_dir ]
--res.items[ root.id ] = root
end
end
-- add items from dir -- add items from dir
if match(v.parent.path, matchpath) then if match(v.parent.path, matchpath) then
@ -49,6 +45,15 @@ return {
res.items[ v.id ] = v res.items[ v.id ] = v
res.parent = parent res.parent = parent
end end
if not isroot then
res.items[ v.parent.id ] = {
view2D = false,
url = v.parent.url,
title = "parent world",
name = "parent world",
thumbnail = '',
}
end
end end
end end
end end
@ -57,7 +62,9 @@ return {
local data = util.merge({ local data = util.merge({
url = req.param.url, -- query hint to render janus.url in iframe (index.html) url = req.param.url, -- query hint to render janus.url in iframe (index.html)
items = {}, items = {},
parent=res.parent referrer = isroot and app.opts.plugin_federation_parent_url or util.getURL(),
parent=res.parent,
template=res.template
},{ opts = app.opts }) },{ opts = app.opts })
local i = 0 local i = 0
foreach( res.items, function(k,v) foreach( res.items, function(k,v)
@ -70,10 +77,13 @@ return {
end end
-- prioritize markup experience above binary 3D files as experience containers -- prioritize markup experience above binary 3D files as experience containers
if not data.item or (isMarkupExperience(v) and not isMarkupExperience(data.item)) then if not data.item or (isMarkupExperience(v) and not isMarkupExperience(data.item)) then
-- update referrer url
data.referrer = util.getURL( v.view3D and v.parent.parent.url or v.parent.url )
data.item = v data.item = v
data.title = data.item.title data.title = data.item.title
data.parent = v.parent data.parent = v.parent
data.url = app.opts.baseurl .. util.stripPath(v.url) -- because we are running in iframe data.url = app.opts.baseurl .. util.stripPath(v.url) -- because we are running in iframe
-- .. EscapeFragment( (v.url:match("#") and "&" or "#" ) .. 'janus.referrer=' .. EscapeFragment(v.referrer) )
if v.janusxr and (v.janusxr.jml or v.janusxr.aframe) then if v.janusxr and (v.janusxr.jml or v.janusxr.aframe) then
-- what to do here? no generated portals? -- what to do here? no generated portals?
data.janusxr = app.tpl( util.readfile(v.path), data ) data.janusxr = app.tpl( util.readfile(v.path), data )

View file

@ -17,7 +17,7 @@
<a href="https://nlnet.nl">NLNET</a><br/> <a href="https://nlnet.nl">NLNET</a><br/>
</td> </td>
<td class="col3"> <td class="col3">
<a href="?view=3D">View from XR Device</a><br/> <a href="${urlpath}?view=3D">View from XR Device</a><br/>
<a href="${opts.plugin_diskscan_dirname}">Content overview</a><br/> <a href="${opts.plugin_diskscan_dirname}">Content overview</a><br/>
<a href="about">About</a><br/> <a href="about">About</a><br/>
</td> </td>

View file

@ -37,6 +37,32 @@
{if true then {if true then
print( app.opts.plugin_global_topmenu_html:gsub("\n","&nbsp;") ) print( app.opts.plugin_global_topmenu_html:gsub("\n","&nbsp;") )
end} end}
{if template == "page/dir.html" then
print([[<div class="btn"><a class="border secondary" href="${urlpath}?view=3D">3D</a></div>&nbsp;]])
end}
{if template == "page/index.html" then
local sharedata = {
title = (item and item.title or opts.plugin_global_title)
}
print([[
<a id="share" href="mailto:friend@your.org?subject=${util.getURL()}&body=check%20this%20on%20your%20XR%20headset">
<img src="img/share.svg" class="icon share"/>
</a>
<script>
if( navigator.share ){
const sharebtn = document.querySelector('#share')
const title = "]] .. (item and item.title or opts.plugin_global_title) .. [["
sharebtn.setAttribute('href', '') // override mailto:
sharebtn.addEventListener('click', (e) => {
navigator.share({title, url: document.location.href})
e.stopPropagation()
e.preventDefault()
return false
})
}
</script>
]])
end}
</td> </td>
</tr> </tr>
</table> </table>

View file

@ -3,7 +3,7 @@ ${header}
<div></div> <div></div>
</div> </div>
<iframe border="0" frameborder="0" src="janusweb/index.html#janus.url=${url}" id="viewer"></iframe> <iframe border="0" frameborder="0" src="janusweb/index.html#janus.url=${url}&janus.referrer=${referrer}" id="viewer"></iframe>
{if item and item.parent and item.parent.info then {if item and item.parent and item.parent.info then
print([[ print([[
@ -35,8 +35,9 @@ end}
url = document.location.origin + document.location.pathname + '?url=' + url url = document.location.origin + document.location.pathname + '?url=' + url
} }
}catch(e){} }catch(e){}
const isFileWithExtension = url.replace( new RegExp('./','g'),"").match("\\.") const isFileWithExtension = url.replace( new RegExp('.*/','g'),"").match("\\.") ? true : false
if( !isFileWithExtension ){ //url = url.replace(/#.*/,'') + '#janus.referrer=' + encodeURIComponent(document.location.href)
if( !isFileWithExtension ){
window.history.replaceState( url, iframe.contentDocument.title, url ); window.history.replaceState( url, iframe.contentDocument.title, url );
} }
setTimeout( () => { setTimeout( () => {

View file

@ -34,8 +34,8 @@ end}
</assets> </assets>
{if item then {if item then
print([[ print([[
<room pos="0 0 0" skybox="true" showavatar="false"> <room pos="0 0 0" skybox="true" showavatar="false">
<object id="${url}"/> <object id="${url}"/>
]]) ]])
else else
local room = app.opts.plugin_janusxr_portalroom local room = app.opts.plugin_janusxr_portalroom
@ -47,10 +47,14 @@ end}
end} end}
<light js_id="dan9-janus:light/light_cone_angle=0-6" pos="0 3 2" collision_trigger="false" /> <light js_id="dan9-janus:light/light_cone_angle=0-6" pos="0 3 2" collision_trigger="false" />
{if true then {if true then
function addPortal(id,x,v,url,i,z,thumb,rotation,scale) function addPortal(id,x,v,url,i,z,thumb,rotation,scale,item)
print('\t<object js_id="' .. id .. '_' .. i .. '" pos="' .. x .. ' 0 ' .. z .. '" rotation="' .. rotation .. '">') print('\t<object js_id="' .. id .. '_' .. i .. '" pos="' .. x .. ' 0 ' .. z .. '" rotation="' .. rotation .. '">')
print('\t <link url="' .. url .. '" ' .. thumb .. ' title_col="0.4 0.37 0.4" pos="0 0 0.001" draw_glow="' .. (thumb:match("shader") and 'false' or 'true') .. '" scale="3 3 0.1" />') print('\t <link url="' .. url .. '" ' .. thumb .. ' title_col="0.4 0.37 0.4" pos="0 0 0.001" draw_glow="' .. (thumb:match("shader") and 'false' or 'true') .. '" scale="3 3 0.1" />')
print('\t <text text="' .. v.title .. '" pos="0 3.4 0" col="1 1 1" font_scale="false" scale="' .. scale .. '" />') print('\t <text text="' .. v.title .. '" pos="0 3.4 0" col="1 1 1" font_scale="false" scale="' .. scale .. '" />')
--TODO: fix janusweb paragraph for markdown urls
--if item.README ~= nil then
-- print('\t <paragraph js_id="README" url="' .. item.README .. '" width="600" height="900" pos="0 1 2" transparent="true"/>')
--end
print('\t</object>') print('\t</object>')
end end
end} end}
@ -66,7 +70,7 @@ end}
end end
if v.dir then url = url .. "/" end if v.dir then url = url .. "/" end
if v.redirect then url = v.redirect end -- dont wrap standalone glb's in janusxr if v.redirect then url = v.redirect end -- dont wrap standalone glb's in janusxr
addPortal('dir',center, v, url,i, -4, thumb, '0 0 0', '0.2 0.2 0.2') addPortal('dir',center, v, url,i, -4, thumb, '0 0 0', '0.2 0.2 0.2', v)
end end
end} end}
{if not item and itemsremote and #itemsremote > 0 then {if not item and itemsremote and #itemsremote > 0 then
@ -80,7 +84,7 @@ end}
end end
if v.dir then url = url .. "/" end if v.dir then url = url .. "/" end
if v.redirect then url = v.redirect end -- dont wrap standalone glb's in janusxr if v.redirect then url = v.redirect end -- dont wrap standalone glb's in janusxr
addPortal('remote',center, v, url,i, 4, thumb, '0 180 0', '0.2 0.2 0.2') addPortal('remote',center, v, url,i, 4, thumb, '0 180 0', '0.2 0.2 0.2',v)
end end
print([[ print([[
<text js_id="locationremote" pos="0 6 5" billboard="y" col="#BBFFFF" scale="10 10 1" text="${opts.plugin_global_remote_title}" emissive="0 0 0" roughness="0.3" metalness="0" /> <text js_id="locationremote" pos="0 6 5" billboard="y" col="#BBFFFF" scale="10 10 1" text="${opts.plugin_global_remote_title}" emissive="0 0 0" roughness="0.3" metalness="0" />
@ -88,6 +92,7 @@ end}
end} end}
<object id="cube" rotation="0 0 0" position="0 0 0" scale="2 0.1 2"/> <!-- something to stand on --> <object id="cube" rotation="0 0 0" position="0 0 0" scale="2 0.1 2"/> <!-- something to stand on -->
${janusxr_jml_deco}
${opts.plugin_janusxr_jml} ${opts.plugin_janusxr_jml}
</room> </room>
</fireboxroom> </fireboxroom>

View file

@ -3,6 +3,20 @@ local dir = require "opendirectory"
app.on('init', function() app.on('init', function()
print("scanning experiences (this make take a while..)") print("scanning experiences (this make take a while..)")
app.opts.plugin_diskscan_dirname = app.opts.plugin_diskscan_dir:gsub("^[.]?[/]?","") app.opts.plugin_diskscan_dirname = app.opts.plugin_diskscan_dir:gsub("^[.]?[/]?","")
-- swap between internal / external version of diskscan_dir
if app.opts.plugin_diskscan_dir:match("^/zip/") then
if util.fileExist(app.opts.plugin_diskscan_dir) then
print(" serving " .. app.opts.plugin_diskscan_dir .. " from local disk")
app.opts.plugin_diskscan_dir = app.opts.plugin_diskscan_dir:gsub("^/zip/","")
app.set('app.opts', app.opts)
end
else
if not util.fileExist(app.opts.plugin_diskscan_dir) then
print(" serving " .. app.opts.plugin_diskscan_dir .. " from internal (executable)")
app.opts.plugin_diskscan_dir = '/zip/' .. util.stripPath(app.opts.plugin_diskscan_dir)
app.set('app.opts', app.opts)
end
end
app.plugin.diskscan.scan(app.opts.plugin_diskscan_dir) app.plugin.diskscan.scan(app.opts.plugin_diskscan_dir)
end) end)
@ -36,6 +50,7 @@ return {
path = scandir, path = scandir,
url = "/" .. util.stripPath(scandir), url = "/" .. util.stripPath(scandir),
name = scandir:gsub(".*/",""), name = scandir:gsub(".*/",""),
thumbnail = "",
title = scandir:gsub(".*/",""):gsub("-"," "), title = scandir:gsub(".*/",""):gsub("-"," "),
file = { ino = scandir }, file = { ino = scandir },
id = scandir id = scandir

View file

@ -25,6 +25,7 @@ app.on('dir', function(opts)
title = url:gsub(".*//",""), title = url:gsub(".*//",""),
thumbnail = thumburl, thumbnail = thumburl,
url = '/janusweb/index.html#janus.url=' .. EscapeFragment(url) url = '/janusweb/index.html#janus.url=' .. EscapeFragment(url)
.. '&janus.referrer=' .. EscapeFragment( util.getURL(opts.urlpath ) )
}) })
end end
end end
@ -34,7 +35,7 @@ end)
local plugin = { local plugin = {
name = 'Federation', name = 'Federation',
tab = "<img src='img/link.svg' class='icon invert'/> Federation", tab = "<img src='img/link.svg' class='icon invert'/> Federation",
info = 'Add links to other (janus)XR(forges), and have them show up as extra portals in portalrooms', info = 'Add links to other (janus)XR(forges), and have them show up as extra portals in portalrooms.<br><b>NOTE:</b> please leave at the <b>Parent World URL</b> non-empty, as it promotes interconnected ecosystems of experiences ♥',
opts = { -- TODO populate this based on xrforge-federation.json opts = { -- TODO populate this based on xrforge-federation.json
{ {
key='app.opts.plugin_federation_strategy', key='app.opts.plugin_federation_strategy',
@ -43,6 +44,14 @@ local plugin = {
default="homepage", default="homepage",
values={always='always',homepage='only homepage'} values={always='always',homepage='only homepage'}
}, },
{
key='app.opts.plugin_federation_parent_url',
title='Parent World URL',
info="3D portal (entrypoint) in homepage",
default="https://www.janusxr.org",
placeholder="https://www.janusxr.org",
values=''
},
{ {
key='app.opts.plugin_federation_url_1', key='app.opts.plugin_federation_url_1',
title='Federated URL 1', title='Federated URL 1',
@ -54,7 +63,7 @@ local plugin = {
key='app.opts.plugin_federation_url_2', key='app.opts.plugin_federation_url_2',
title='Federated URL 2', title='Federated URL 2',
info="URL and/or Thumbnail URL (space separated)", info="URL and/or Thumbnail URL (space separated)",
default="https://www.janusxr.org https://www.janusvr.com/images/logos/logotextoverlight.png", default="https://aframe.io/aframe/examples/boilerplate/hello-world/ /myverse/janusxr_tutorial/AFRAME.jpg",
values='' values=''
}, },
{ {

View file

@ -113,7 +113,7 @@ local plugin = {
}, },
middleware = { middleware = {
homepage_2D_or_3D = function(req,res,next) homepage_2D_or_3D = function(req,res,next)
if (app.opts.plugin_global_homepage == '3D') or (req.param.view == '3D') or (req.param.url) then if (req.url == '/' or req.url == '/index.html' and app.opts.plugin_global_homepage == '3D') or (req.param.view == '3D') or (req.param.url) then
res.template = 'page/index.html' res.template = 'page/index.html'
else else
res.template = 'page/dir.html' res.template = 'page/dir.html'

View file

@ -8,6 +8,15 @@ app.on('scan_experience', function(exp)
--print_r(exp) --print_r(exp)
end) end)
app.on('dir', function(opts)
local hash = GetPath()
if #app.opts.plugin_janusxr_random_objects > 0 and
#app.opts.plugin_janusxr_random_colors > 0 then
opts.data.janusxr_jml_deco = app.plugin.janusxr.getRandomDeco(7,50,hash,0,30) ..
app.plugin.janusxr.getRandomDeco(7,50,hash .. hash,30,30)
end
end)
app.on('scan_experience_file', function(exp) app.on('scan_experience_file', function(exp)
local me = app.plugin.janusxr local me = app.plugin.janusxr
local size = exp.file.attr:size() local size = exp.file.attr:size()
@ -56,8 +65,7 @@ app.on('scan_experience_file', function(exp)
end end
end) end)
app.on('set', function(k,v) app.on('set', function(k,v) end)
end)
-- this registers the plugin UI -- this registers the plugin UI
local rooms = {random="random room",room_plane="wirefloor",room1="room1",room2="room2",room3="room3",room4="room4",room5="room5",room6="room6",room7="room7"} local rooms = {random="random room",room_plane="wirefloor",room1="room1",room2="room2",room3="room3",room4="room4",room5="room5",room6="room6",room7="room7"}
@ -118,6 +126,22 @@ local plugin = {
default="room_plane", default="room_plane",
values={random="random room",room_plane="wirefloor",room1="room1",room2="room2",room3="room3",room4="room4",room5="room5",room6="room6",room7="room7"} values={random="random room",room_plane="wirefloor",room1="room1",room2="room2",room3="room3",room4="room4",room5="room5",room6="room6",room7="room7"}
}, },
{
key='app.opts.plugin_janusxr_random_objects',
title='Random objects',
info="Random object id's in portal rooms",
default="capsule cone cube cylinder pyramid sphere torus",
placeholder="capsule cone cube cylinder pipe pyramid sphere torus",
values="",
},
{
key='app.opts.plugin_janusxr_random_colors',
title='Random colors',
info="Random object colors in portal rooms",
default="#ffffff #111122 #FF33FF #8833FF #7070FF #404070 #222244",
placeholder="#ffffff #111122 #FF33FF #8833FF #7070FF #404070 #222244",
values="",
},
{ {
key='app.opts.plugin_janusxr_scraper', key='app.opts.plugin_janusxr_scraper',
title='Scraper', title='Scraper',
@ -141,6 +165,7 @@ local plugin = {
values='' values=''
} }
}, },
getRandomRoom = function() getRandomRoom = function()
local me = app.plugin.janusxr local me = app.plugin.janusxr
local room= '' local room= ''
@ -153,6 +178,52 @@ local plugin = {
end end
end) end)
return room return room
end,
getRandomDeco = function(num_objects, radius, seed_string, y, scale)
num_objects = num_objects or 6
y = y or 0
radius = radius or 2 -- Configurable distance from (0, 0, 0)
seed_string = seed_string or 'xf2dxf2dxf3f23' -- Given hashstring
local JML = ''
local colors = util.split( app.opts.plugin_janusxr_random_colors, ' ')
local ids = util.split( app.opts.plugin_janusxr_random_objects, ' ')
local function hash_string_to_number(str)
local hash = 5381
for i = 1, #str do
local char = string.byte(str, i)
hash = (hash * 33 + char) % 2147483647
end
return hash
end
local index = {
color= hash_string_to_number(seed_string) % #colors,
id = hash_string_to_number(seed_string) % #ids
}
for i = 1, num_objects do
-- Calculate angle in radians to space objects evenly around a circle
local angle = (i - 1) * (2 * math.pi / num_objects)
-- Calculate X and Z positions along the circle radius
local x = radius * math.cos(angle)
local z = radius * math.sin(angle)
local y = y -- Height level
local selected_id = ids[ index.id+1]
local selected_color = colors[ index.color+1 ]
local pos_str = string.format("%.2f %g %.2f", x, y, z)
local xml_tag = string.format('<object id="%s" pos="%s" col="%s" rotation="0 45 0" scale="%s %s %s" roughness="0.1" metalness="0.5"/>',
selected_id, pos_str, selected_color, scale, scale, scale)
JML = JML .. xml_tag .. "\n"
-- increase indexes
index.id = (index.id + 1 ) % #ids
index.color = (index.color + 1 ) % #colors
end
return JML
end end
} }

View file

@ -12,6 +12,7 @@ app.on('scan_experience_file', function(exp)
if exp.path:match(v) then if exp.path:match(v) then
print("✅ └─ plugin/markdown: detected " .. v) print("✅ └─ plugin/markdown: detected " .. v)
exp.parent.info = '<div id="info">' .. markdown( util.readfile(exp.path) ) .. '</div>' exp.parent.info = '<div id="info">' .. markdown( util.readfile(exp.path) ) .. '</div>'
exp.parent.README = util.stripPath( exp.path )
end end
end) end)
end) end)

View file

@ -25,6 +25,7 @@ app.on('dir', function(opts)
title = url:gsub(".*//",""), title = url:gsub(".*//",""),
thumbnail = thumburl, thumbnail = thumburl,
url = '/janusweb/index.html#janus.url=' .. EscapeFragment(url) url = '/janusweb/index.html#janus.url=' .. EscapeFragment(url)
.. '&janus.referrer=' .. EscapeFragment( util.getURL(opts.urlpath ) )
}) })
end end
end end

50
src/plugin/pubnix.lua Normal file
View file

@ -0,0 +1,50 @@
local util = require('util')
app.on('scan_experience', function(exp)
--print_r(exp)
end)
app.on('scan_experience_file', function(exp)
end)
app.on('set', function(k,v)
end)
-- this registers the plugin UI
local plugin = {
name = "PubNIX",
info = '<b class="tag">disabled</b> Turn server into a <a href="https://tildeverse.org/" target="_blank">pubnix</a>: automatically scan userdirectories in /home/* for XR experiences, and add them as 3D portals.',
opts = {
{
key='app.opts.plugin_pubnix_enabled',
title='Add homedirs',
info='Scan for experiences in /home/*',
default = "enabled",
values={enabled="enabled",disabled="disabled"}
},
{
key='app.opts.plugin_pubnix_folder',
title='Require folder',
info='Require specific folder (/home/john/xrforge e.g.)',
default = "./xrforge",
values=''
},
{
key='app.opts.plugin_pubnix_thumbnail',
title='User thumbnail',
info='look for /home/john/xrforge/~john.jpg sidecarfile',
default = "enabled",
values={enabled="enabled",disabled="disabled"}
},
{
key='app.opts.plugin_pubnix_exclude',
title='Exclude pattern',
info='Space-separated, <a href="http://lua-users.org/wiki/PatternsTutorial" target="_blank">lua patterns</a> for directories',
default = "",
placeholder = "admin root",
values=''
},
}
}
return plugin

View file

@ -25,6 +25,7 @@ app.on('dir', function(opts)
title = url:gsub(".*//",""), title = url:gsub(".*//",""),
thumbnail = thumburl, thumbnail = thumburl,
url = '/janusweb/index.html#janus.url=' .. EscapeFragment(url) url = '/janusweb/index.html#janus.url=' .. EscapeFragment(url)
.. '&janus.referrer=' .. EscapeFragment( util.getURL(opts.urlpath ) )
}) })
end end
end end

View file

@ -13,7 +13,7 @@ app.on('scan_experience_file', function(exp)
local hasHref = false local hasHref = false
if ext == 'glb' then if ext == 'glb' then
-- detect XR Fragment exp https://xrfragment.org/#%F0%9F%93%9C%20level0%3A%20File -- detect XR Fragment exp https://xrfragment.org/#%F0%9F%93%9C%20level0%3A%20File
local tree = me.extract_glb_json( util.stripPath(exp.path) ) local tree = me.extract_glb_json( exp.path ) --util.stripPath(exp.path) )
hasHref = me.detectHrefInStruct(tree) hasHref = me.detectHrefInStruct(tree)
end end
-- check sidecarfiles: https://xrfragment.org/#sidecar%20files -- check sidecarfiles: https://xrfragment.org/#sidecar%20files

View file

@ -36,7 +36,7 @@ download(){
wget "https://github.com/coderofsalvation/janusweb/releases/download/v${version}-rc/janusweb-${version}.tar.gz" wget "https://github.com/coderofsalvation/janusweb/releases/download/v${version}-rc/janusweb-${version}.tar.gz"
} }
test -d janusweb-${version} || tar -xvf janusweb-${version}.tar.gz test -d janusweb-${version} || tar -xvf janusweb-${version}.tar.gz
test -d src/janusweb || cp -r janusweb-${version} src/janusweb test -d src/janusweb || cp -Lr janusweb-${version} src/janusweb
} }
"$@" "$@"