added baseURLify() to streamline server vs staticwebgen links
This commit is contained in:
parent
c4d5060e32
commit
6bf8b40d1c
17 changed files with 176 additions and 70 deletions
56
README.md
56
README.md
|
|
@ -8,8 +8,12 @@ An open, seamless XR web built from simple URLs and directories, without gatekee
|
|||
<img src="screenshot.jpg"/>
|
||||
</a>
|
||||
|
||||
XRForge transforms standard local or remote file directories into interconnected 3D spaces.
|
||||
<br>Users can seamlessly "surf" the spatial web, turning everyday directories into 3D portals.
|
||||
* turn everyday directories into 3D portals.
|
||||
* seamlessly "surf" interconnected spatial webs on XR headsets
|
||||
* transforms local/remote filesystems into interconnected 3D spaces.
|
||||
* 3D (hyperlink) file browser for AR/VR
|
||||
* automatic portal system, recursive symlinks supported
|
||||
* infinite horizontally scaling ecosystems thanks to URLs (not databases)
|
||||
|
||||
```
|
||||
┌───────────────────────────────────┐ ┌──────────────────────────────────────────┐
|
||||
|
|
@ -56,7 +60,7 @@ Usage: ./xrforge.com <cmd> [opts]
|
|||
Extract and run example 3D content in your browser:
|
||||
|
||||
```bash
|
||||
$ unzip xrforge.com myverse/* # extract example 3D verse
|
||||
$ unzip xrforge.com myverse/* # extract example 3D verse files
|
||||
$ ./xrforge.com server # run as server
|
||||
opening your browser at https://localhost:8080
|
||||
```
|
||||
|
|
@ -149,7 +153,7 @@ page css
|
|||
|
||||
Optionally you can re-distribute `xrforge.com` with your modifications by running `zip xrforge.com page`
|
||||
|
||||
## Distribute your own XRForge
|
||||
## Distribute: your own executable
|
||||
|
||||
You can preload the `xrforge.com` binary with your own experiences <b>as a single-executable-file</b>:
|
||||
|
||||
|
|
@ -160,18 +164,21 @@ $ cp xrforge.com myproject.com
|
|||
|
||||
> Profit!
|
||||
|
||||
## Plugins
|
||||
## Distribute: static website
|
||||
|
||||
xrforge is basically plugins working together.<br>
|
||||
You can create your own plugins by running:
|
||||
Generate a static website:
|
||||
|
||||
```bash
|
||||
$ ./xrforge.com createplugin > xrforge.myplugin.lua
|
||||
```
|
||||
$ ./xrforge.com generate baseurl=/mysubfolder/
|
||||
✅ finished generating 'www' folder
|
||||
```
|
||||
|
||||
Look in the [src/plugin](src/plugin) directory for examples
|
||||
A convenient way is forking [this github repo](https://github.com/coderofsalvation/xrforge-website-example)
|
||||
to automatically obtain a xrforge-generated github page.
|
||||
|
||||
## Run as server
|
||||
> NOTE: passing extra flags (run `xrforge.com help` for all flags) is important when running the website in a subfolder (`baseurl=...` e.g.)
|
||||
|
||||
## Distribute: selfhosting on a server
|
||||
|
||||
<b>BAREMETAL:</b>
|
||||
|
||||
|
|
@ -188,16 +195,17 @@ $ docker run -d -p 8080:8080 -w /app -v $(pwd):/app busybox /app/xrforge.com ser
|
|||
|
||||
```
|
||||
|
||||
## Plugins
|
||||
|
||||
## Scan manyfold
|
||||
xrforge is basically plugins working together.<br>
|
||||
You can create your own plugins by running:
|
||||
|
||||
-------------
|
||||
```
|
||||
manual scan (via cli?)
|
||||
curl -L -X 'GET' 'http://xrforge.isvery.ninja/models?page=1&order=name' -H 'accept: application/vnd.manyfold.v0+json'
|
||||
curl -L -X 'GET' 'http://xrforge.isvery.ninja/models?page=1&order=recent' -H 'accept: application/vnd.manyfold.v0+json'
|
||||
```bash
|
||||
$ ./xrforge.com createplugin > xrforge.myplugin.lua
|
||||
```
|
||||
|
||||
Look in the [src/plugin](src/plugin) directory for examples
|
||||
|
||||
## Developing
|
||||
|
||||
```bash
|
||||
|
|
@ -216,6 +224,8 @@ $ DEBUG=1 result/bin/xrforge.com
|
|||
|
||||
Use `ARCH=x86_64 build` to enforce x86_64 output (instead of a cosmopolitan binary)
|
||||
|
||||
> **NOTE**: this is a **static webgenerator-first**-and-server-**last** project, hence it is restricted to [GET requests](src/middleware/onlyGET.lua) (unless authenticated as admin). Going beyond this paradigm is considered unsafe and out of scope.
|
||||
|
||||
## Permacomputing Spirit
|
||||
|
||||
* developed on [Dillo](https://dillo-browser.github.io/) as lowest common denominator / compatibility
|
||||
|
|
@ -223,7 +233,7 @@ Use `ARCH=x86_64 build` to enforce x86_64 output (instead of a cosmopolitan bina
|
|||
* gracefully degrades to admin/filebrowser for >noscript>/potato-browsers
|
||||
* server is using lua-scripting via cosmopolitan libc's [redbean](https://redbean.dev)
|
||||
|
||||
> So yes, the codebase/html/css is intentionally 90-ish: that's **exactly why it works** on potato-devices AND modern devices.
|
||||
> So yes, the codebase/html/css is intentionally 90-ish: that's **exactly why it gracefully degrades** on potato-devices.
|
||||
|
||||
## Credits / Made with
|
||||
|
||||
|
|
@ -243,6 +253,16 @@ Use `ARCH=x86_64 build` to enforce x86_64 output (instead of a cosmopolitan bina
|
|||
|
||||
NOTES:
|
||||
|
||||
## Scan manyfold
|
||||
|
||||
-------------
|
||||
```
|
||||
manual scan (via cli?)
|
||||
curl -L -X 'GET' 'http://xrforge.isvery.ninja/models?page=1&order=name' -H 'accept: application/vnd.manyfold.v0+json'
|
||||
curl -L -X 'GET' 'http://xrforge.isvery.ninja/models?page=1&order=recent' -H 'accept: application/vnd.manyfold.v0+json'
|
||||
```
|
||||
|
||||
|
||||
```
|
||||
|
||||
/admin.lua <--- define other instances..for CORS allow / mount http
|
||||
|
|
|
|||
|
|
@ -78,6 +78,7 @@ print = function(...) Log(kLogInfo, ... or "''") end -- nice redbean logging fro
|
|||
-- init URL router
|
||||
app.url['^/data'] = '/data.lua' -- setup custom file endpoint
|
||||
|
||||
app.use( require('middleware/onlyGET')({exclude={'^/admin'}}) ) -- we are staticwebgen-first server-last
|
||||
app.use( app.plugin.global.middleware.homepage_2D_or_3D )
|
||||
app.url['^/admin[/]?$'] = '/page/admin/index.lua'
|
||||
|
||||
|
|
|
|||
|
|
@ -5,6 +5,7 @@ return function(app)
|
|||
local config = { -- default
|
||||
name = "XRForge",
|
||||
baseurl="/",
|
||||
host="localhost",
|
||||
admin_title = "admin panel",
|
||||
admin_subtitle = "Manage your XR experiences here",
|
||||
admin_user = "admin",
|
||||
|
|
|
|||
|
|
@ -87,12 +87,23 @@ sb = {
|
|||
|
||||
tpl = function(s, __data)
|
||||
local __env = {}
|
||||
local fallback = function(key)
|
||||
if os.getenv('DEBUG') then
|
||||
print("⚠️ template '" .. key .. "' does not exist")
|
||||
end
|
||||
return setmetatable({}, {
|
||||
__tostring = function() return "" end,
|
||||
__concat = function(a, b) return tostring(a) .. tostring(b) end,
|
||||
__call = function(...) return "" end
|
||||
})
|
||||
end
|
||||
setmetatable(__env, {
|
||||
__index = function(t, key) return __data[key] or _G[key] end,
|
||||
__index = function(t, key) return __data[key] or _G[key] or fallback(key) end,
|
||||
__newindex = function(t, key, value) __data[key] = value end
|
||||
})
|
||||
-- lets evaluate inline lua linearly
|
||||
local luastr = 'local str=""\n print = function(s) str = str .. s .. "\\n" end\n'
|
||||
luastr = luastr .. 'defined = function(v) return tostring(v or "") ~= "" end\n'
|
||||
local islua = false
|
||||
for str in string.gmatch(s, "([^\n]+)") do
|
||||
if str:match("{if ") or str:match("{for ") then
|
||||
|
|
@ -196,7 +207,10 @@ sb = {
|
|||
local res={
|
||||
_status=nil,
|
||||
_header={},
|
||||
_body=""
|
||||
_body="",
|
||||
send = function(req,res,next)
|
||||
sb.response()(req,res,next)
|
||||
end
|
||||
}
|
||||
local params = internal and {} or GetParams()
|
||||
if params ~= nil then
|
||||
|
|
@ -251,7 +265,9 @@ sb = {
|
|||
if type(res._body) == "string" then
|
||||
Write( res._body )
|
||||
else print("[ERROR] res.body is not a string (HINT: use json middleware)") end
|
||||
else next() end
|
||||
else
|
||||
if next then next() end
|
||||
end
|
||||
end
|
||||
end,
|
||||
|
||||
|
|
@ -311,6 +327,7 @@ sb = {
|
|||
return function(data)
|
||||
local app = {}
|
||||
setmetatable(app,sb)
|
||||
sb.arg = arg
|
||||
sb.bin = arg[-1]:gsub(".*/","")
|
||||
sb.bindir = arg[-1]:gsub("/[a-zA-Z0-9-_ ]+.com$","/")
|
||||
sb.app = app
|
||||
|
|
|
|||
|
|
@ -75,6 +75,12 @@ util.templateFile = function(file,data)
|
|||
return util.template( LoadAsset(file), data)
|
||||
end
|
||||
|
||||
util.baseURLify = function(url)
|
||||
if url:match("^" .. app.opts.baseurl) then return url end -- only do once
|
||||
if url:match("://") then return url end
|
||||
return url:gsub("^[/]?", app.opts.baseurl)
|
||||
end
|
||||
|
||||
util.getURL = function(url,opts)
|
||||
opts = opts or {}
|
||||
local port = ''
|
||||
|
|
@ -83,8 +89,9 @@ util.getURL = function(url,opts)
|
|||
return 'http://localhost:' .. app.port .. url
|
||||
else
|
||||
port = ':' .. GetPort()
|
||||
if port == 80 then port = '' end
|
||||
return GetScheme() .. '://' .. GetHost() .. port .. (url or GetPath())
|
||||
if port == ':80' then port = '' end
|
||||
if arg[1] == 'generate' and port == ':8080' then port = '' end
|
||||
return GetScheme() .. '://' .. (app.opts.host or GetHost()) .. port .. (url or GetPath())
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -92,8 +99,8 @@ util.template = function(content,data)
|
|||
local mdata = util.merge(data or app,{})
|
||||
mdata = util.merge(mdata, {opts = app.opts})
|
||||
-- set fallback vars
|
||||
mdata.urlpath = GetPath()
|
||||
mdata.url = mdata.url or util.getURL()
|
||||
mdata.urlpath = util.baseURLify( GetPath() )
|
||||
mdata.url = mdata.url or mdata.urlpath
|
||||
mdata.title = mdata.title or app.opts.subtitle
|
||||
mdata.header_include = mdata.header_include or ''
|
||||
mdata.footerlinks = {}
|
||||
|
|
@ -330,6 +337,13 @@ function util.stripPath(str)
|
|||
return str:gsub("^/zip/",""):gsub("^./",""):gsub("^/",""):gsub("/$","")
|
||||
end
|
||||
|
||||
function util.truncate(str,maxchar,filler)
|
||||
filler = filler or '..'
|
||||
str = str:gsub(".*://",""):gsub("/$",""):gsub("/.*/","/.../")
|
||||
if maxchar ~= nil and #str > maxchar then str = str:sub(0,maxchar) .. filler end
|
||||
return str
|
||||
end
|
||||
|
||||
-- WARNING: this is a destructive function which renders the redbean server inactive
|
||||
-- only to be used in tests or staticwebgen plugin
|
||||
util.queueServerRequest = function(method, path, params, host, headers, body, scheme, port)
|
||||
|
|
|
|||
|
|
@ -40,6 +40,7 @@ body,html {
|
|||
}
|
||||
|
||||
body{
|
||||
overflow-wrap: break-word;
|
||||
background:#000;
|
||||
margin:20px;
|
||||
}
|
||||
|
|
|
|||
24
src/middleware/onlyGET.lua
Normal file
24
src/middleware/onlyGET.lua
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
-- soakbean middleware function
|
||||
return function(opts)
|
||||
opts = opts or {exclude={"^/admin"}}
|
||||
return function(req,res,next)
|
||||
local pass = false
|
||||
if req.method == "GET" then
|
||||
pass = true
|
||||
else
|
||||
foreach(opts.exclude, function(k,path)
|
||||
if req.url:match(path) then
|
||||
pass = true
|
||||
end
|
||||
end)
|
||||
end
|
||||
if pass then
|
||||
next()
|
||||
else
|
||||
res.status(405)
|
||||
res.body("not allowed")
|
||||
res.send(req,res)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
|
@ -19,6 +19,18 @@ end}
|
|||
|
||||
<div class="grid">
|
||||
{if items then
|
||||
|
||||
function getURL(url)
|
||||
if app.arg[1] == 'generate' and url:match("://") then
|
||||
url = 'janusweb/index.html#janus.url=' ..
|
||||
EscapeFragment( url ) .. '&janus.referrer=' .. util.getURL(urlpath )
|
||||
url = util.baseURLify(url)
|
||||
else
|
||||
url = util.stripPath( url )
|
||||
end
|
||||
return url
|
||||
end
|
||||
|
||||
for i=1,#items do
|
||||
local item = items[i]
|
||||
local visible = item.view2D == nil or (item.view2D ~= nil and item.view2D ~= false)
|
||||
|
|
@ -29,10 +41,10 @@ end}
|
|||
if item.view3D or item.portal3D == false then icon = 'play' end
|
||||
print([[
|
||||
<div class="tile">
|
||||
<a href="]] .. util.stripPath(item.url) .. [[">
|
||||
<a href="]] .. getURL(item.url) .. [[">
|
||||
<div class="img" ]] .. util.stripPath(thumbnail) .. [[></div>
|
||||
<div class="text">
|
||||
<img src="img/]] .. icon .. [[.svg" class="icon ]] .. icon .. [["/> <a href="]] .. util.stripPath(item.url) .. [[">]] .. item.title .. [[</a>
|
||||
<img src="img/]] .. icon .. [[.svg" class="icon ]] .. icon .. [["/> <a href="]] .. getURL(item.url) .. [[">]] .. item.title .. [[</a>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
|
|
@ -49,10 +61,10 @@ end}
|
|||
if item.view3D or item.portal3D == false then icon = 'play' end
|
||||
print([[
|
||||
<div class="tile">
|
||||
<a href="]] .. util.stripPath(item.url) .. [[">
|
||||
<a href="]] .. getURL(item.url) .. [[">
|
||||
<div class="img" ]] .. util.stripPath(thumbnail) .. [[></div>
|
||||
<div class="text">
|
||||
<img src="img/]] .. icon .. [[.svg" class="icon ]] .. icon .. [["/> <a href="]] .. util.stripPath(item.url) .. [[">]] .. item.title .. [[</a>
|
||||
<img src="img/]] .. icon .. [[.svg" class="icon ]] .. icon .. [["/> <a href="]] .. getURL(item.url) .. [[">]] .. util.truncate(item.title) .. [[</a>
|
||||
</div>
|
||||
</a>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -14,10 +14,11 @@ return {
|
|||
local nslashes = util.countChar('/',urlpath)
|
||||
local match = function(a,b) return util.stripPath(a) == util.stripPath(b) end
|
||||
local urlhash = urlpath .. util.dump( req.param )
|
||||
local referrer = util.baseURLify( (isroot and not req.param.url) and "" or urlpath )
|
||||
|
||||
if (isroot or urlpath:match("^"..rootpath))
|
||||
and not urlpath:gsub(".*/",""):match("%.") -- no regular file with extension
|
||||
and not req.param.url then
|
||||
then
|
||||
|
||||
local redirect = false
|
||||
if not app.cache.url[ urlhash ] or util.count(req.params) > 0 then
|
||||
|
|
@ -45,14 +46,10 @@ return {
|
|||
res.items[ v.id ] = v
|
||||
res.parent = parent
|
||||
end
|
||||
if not isroot then
|
||||
res.items[ v.parent.id ] = {
|
||||
view2D = false,
|
||||
url = v.parent.parent.url,
|
||||
title = app.opts.plugin_janusxr_portal_up,
|
||||
name = app.opts.plugin_janusxr_portal_up,
|
||||
thumbnail = '',
|
||||
}
|
||||
if isroot then
|
||||
referrer = app.opts.plugin_federation_parent_url
|
||||
else
|
||||
referrer = v.parent.parent.url
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -62,7 +59,8 @@ return {
|
|||
local data = util.merge({
|
||||
url = req.param.url, -- query hint to render janus.url in iframe (index.html)
|
||||
items = {},
|
||||
referrer = isroot and app.opts.plugin_federation_parent_url or util.getURL(),
|
||||
isroot = isroot,
|
||||
referrer = referrer,
|
||||
parent=res.parent,
|
||||
template=res.template
|
||||
},{ opts = app.opts })
|
||||
|
|
@ -78,7 +76,7 @@ return {
|
|||
-- prioritize markup experience above binary 3D files as experience containers
|
||||
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.referrer = util.baseURLify(v.view3D and v.parent.parent.url or v.parent.url)
|
||||
data.item = v
|
||||
data.title = data.item.title
|
||||
data.parent = v.parent
|
||||
|
|
|
|||
|
|
@ -21,7 +21,7 @@
|
|||
<a href="${opts.baseurl}">
|
||||
<div class="logo max">
|
||||
<span class="col1">[</span><span class="col2"><></span><span class="col1">]</span> <span class="col3">${opts.plugin_global_title}
|
||||
{if url:match("admin") then
|
||||
{if urlpath:match("^/admin") then
|
||||
print('<span class="col1">//<span>')
|
||||
print('<span class="col0">${opts.admin_title}</span>')
|
||||
end}
|
||||
|
|
@ -38,7 +38,16 @@
|
|||
print( app.opts.plugin_global_topmenu_html:gsub("\n"," ") )
|
||||
end}
|
||||
{if template == "page/dir.html" then
|
||||
local url = urlpath
|
||||
if not urlpath:match(app.opts.plugin_diskscan_dirname) then
|
||||
-- janusweb workaround (it does not support '/' url somehow)
|
||||
urlpath = urlpath .. app.opts.plugin_diskscan_dirname
|
||||
end
|
||||
if app.arg[1] == "generate" then
|
||||
print([[<div class="btn XR"><a class="border secondary" href="janusweb/#janus.url=]] .. urlpath .. [[&janus.referrer=${referrer}">3D</a></div> ]])
|
||||
else
|
||||
print([[<div class="btn XR"><a class="border secondary" href="${urlpath}?view=3D">3D</a></div> ]])
|
||||
end
|
||||
end}
|
||||
{if template == "page/index.html" then
|
||||
local sharedata = {
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ ${header}
|
|||
|
||||
<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 defined(item) and item.parent and item.parent.info then
|
||||
print([[
|
||||
<div id="popup" class="content">
|
||||
<div class="spectrum span" style="top:-1px">
|
||||
|
|
|
|||
|
|
@ -5,22 +5,23 @@
|
|||
-- optimize janus resource URLs for archive.org
|
||||
app.plugin.archive.flush()
|
||||
function URL(url)
|
||||
url = util.baseURLify(url)
|
||||
app.plugin.archive.add(url)
|
||||
return url
|
||||
end
|
||||
end}
|
||||
|
||||
end}
|
||||
|
||||
<fireboxroom>
|
||||
<assets>
|
||||
{if items and #items > 0 then
|
||||
{if defined(items) and #items > 0 then
|
||||
for i,v in pairs(items) do
|
||||
if #v.thumbnail > 0 then
|
||||
print('\t<assetimage src="' .. URL(v.thumbnail) .. '" id="img' .. i .. '"/>')
|
||||
end
|
||||
end
|
||||
end}
|
||||
{if itemsremote and #itemsremote > 0 then
|
||||
{if defined(itemsremote) and #itemsremote > 0 then
|
||||
for i,v in pairs(itemsremote) do
|
||||
if #v.thumbnail > 0 then
|
||||
print('\t<assetimage src="' .. URL(v.thumbnail) .. '" id="imgremote' .. i .. '"/>')
|
||||
|
|
@ -38,28 +39,27 @@ end}
|
|||
end
|
||||
end}
|
||||
</assets>
|
||||
{if item then
|
||||
print([[
|
||||
<room pos="0 0 0" skybox="true" showavatar="false">
|
||||
<object id="${url}"/>
|
||||
]])
|
||||
else
|
||||
{if true then
|
||||
local room = app.opts.plugin_janusxr_portalroom
|
||||
if item and item.janusxr and item.janusxr.room then
|
||||
if defined(item) and item.janusxr and item.janusxr.room then
|
||||
room = item.janusxr.room
|
||||
end
|
||||
if room == 'random' then room = app.plugin.janusxr.getRandomRoom() end
|
||||
if defined(item) and item.tag.xrfragments and item.tag.xrfragments.qualify then
|
||||
room = '' -- xrfragments 3D files dont need to be wrapped with room
|
||||
end
|
||||
print(' <room skybox="true" showavatar="false" use_local_asset="' .. room .. '">')
|
||||
if defined(item) then
|
||||
print(' <object id="${url}"/>')
|
||||
end
|
||||
end}
|
||||
<light js_id="dan9-janus:light/light_cone_angle=0-6" pos="0 3 2" collision_trigger="false" />
|
||||
{if true then
|
||||
function addPortal(id,x,v,url,i,z,thumb,rotation,scale)
|
||||
local title = v.title
|
||||
local maxchar = 20
|
||||
if #title > maxchar then title = title:sub(0,maxchar) .. '..' end
|
||||
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 <text text="' .. title .. '" pos="0 3.4 0" col="1 1 1" font_scale="false" scale="' .. scale .. '" />')
|
||||
print('\t <link url="' .. util.baseURLify(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="' .. util.truncate(title,20) .. '" pos="0 3.4 0" col="1 1 1" font_scale="false" scale="' .. scale .. '" />')
|
||||
--TODO: fix janusweb paragraph for markdown urls
|
||||
--if v.README ~= nil then
|
||||
-- print('\t <paragraph js_id="README" url="' .. v.README .. '" width="600" height="900" pos="0 1 2" transparent="true"/>')
|
||||
|
|
@ -68,7 +68,7 @@ end}
|
|||
end
|
||||
end}
|
||||
<text js_id="location" pos="0 6 -5" billboard="y" col="#BBFFFF" scale="10 10 1" text="${url}" emissive="0 0 0" roughness="0.3" metalness="0" />
|
||||
{if not item and items and #items > 0 then
|
||||
{if not defined(item) and defined(items) and #items > 0 then
|
||||
for i,v in pairs(items) do
|
||||
local width = 3.2
|
||||
local center = -((#items*width)/1.3) + (i*width)
|
||||
|
|
@ -82,7 +82,7 @@ end}
|
|||
addPortal('dir',center, v, url,i, -4, thumb, '0 0 0', '0.2 0.2 0.2')
|
||||
end
|
||||
end}
|
||||
{if not item and itemsremote and #itemsremote > 0 then
|
||||
{if not defined(item) and defined(itemsremote) and #itemsremote > 0 then
|
||||
for i,v in pairs(itemsremote) do
|
||||
local width = 3.2
|
||||
local center = -((#itemsremote*width)/1.3) + (i*width)
|
||||
|
|
@ -100,8 +100,19 @@ end}
|
|||
]])
|
||||
end}
|
||||
|
||||
{if #referrer > 0 then
|
||||
-- hardcoded reciprocal portal
|
||||
local v = {
|
||||
url = referrer,
|
||||
title = app.opts.plugin_janusxr_portal_up,
|
||||
}
|
||||
addPortal('parent',4, v, v.url, 0, 0, ' shader_id="defaultportal"', '0 -90 0', '0.2 0.2 0.2')
|
||||
end}
|
||||
|
||||
<object id="cube" rotation="0 0 0" position="0 0 0" scale="2 0.1 2"/> <!-- something to stand on -->
|
||||
${janusxr_jml_deco}
|
||||
{if not defined(item) then
|
||||
print('${janusxr_jml_deco}')
|
||||
end}
|
||||
${opts.plugin_janusxr_jml}
|
||||
</room>
|
||||
</fireboxroom>
|
||||
|
|
|
|||
|
|
@ -14,12 +14,10 @@ app.on('init', function()
|
|||
local me = app.plugin.archive
|
||||
if arg[1] == 'server' then
|
||||
local code, pid = unix.fork()
|
||||
|
||||
-- kill thread when main app gets CTRL-c
|
||||
unix.sigaction(unix.SIGINT, function()
|
||||
unix.exit()
|
||||
end)
|
||||
|
||||
function notify()
|
||||
app.plugin.archive.notify()
|
||||
--notify() -- loop forever
|
||||
|
|
|
|||
|
|
@ -24,8 +24,7 @@ app.on('dir', function(opts)
|
|||
table.insert(itemsremote, {
|
||||
title = url:gsub(".*//",""),
|
||||
thumbnail = thumburl,
|
||||
url = '/janusweb/index.html#janus.url=' .. EscapeFragment(url)
|
||||
.. '&janus.referrer=' .. EscapeFragment( util.getURL(opts.urlpath ) )
|
||||
url = url
|
||||
})
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -24,8 +24,7 @@ app.on('dir', function(opts)
|
|||
table.insert(itemsremote, {
|
||||
title = url:gsub(".*//",""),
|
||||
thumbnail = thumburl,
|
||||
url = '/janusweb/index.html#janus.url=' .. EscapeFragment(url)
|
||||
.. '&janus.referrer=' .. EscapeFragment( util.getURL(opts.urlpath ) )
|
||||
url = url
|
||||
})
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -24,8 +24,7 @@ app.on('dir', function(opts)
|
|||
table.insert(itemsremote, {
|
||||
title = url:gsub(".*//",""),
|
||||
thumbnail = thumburl,
|
||||
url = '/janusweb/index.html#janus.url=' .. EscapeFragment(url)
|
||||
.. '&janus.referrer=' .. EscapeFragment( util.getURL(opts.urlpath ) )
|
||||
url = url
|
||||
})
|
||||
end
|
||||
end
|
||||
|
|
|
|||
|
|
@ -34,7 +34,10 @@ app.on('scan_experience_file', function(exp)
|
|||
if util.fileExist( jsonfile ) then
|
||||
exp.sidecarfile.JSONXRF = me.detectHrefInStruct( json.decode( util.readfile(jsonfile) ) )
|
||||
end
|
||||
exp.tag.xrfragments = { qualify = hasHref or hasPNG or hasWebVTT or hasOGG or hasJSONref, href = hasHref }
|
||||
exp.tag.xrfragments = {
|
||||
qualify = (hasHref or exp.sidecarfile.png or exp.sidecarfile.vtt or exp.sidecarfile.ogg or exp.sidecarfile.json) and true or false,
|
||||
href = hasHref
|
||||
}
|
||||
if exp.tag.xrfragments.qualify then
|
||||
exp.view3D = true
|
||||
print("✅ └─ plugin/xrfragments: detected xrfragments experience")
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue