XRForge is a tiny, powerful tool to interconnect XR experiences.
An open, seamless XR web built from simple URLs and directories, without gatekeepers.
XRForge transforms standard local or remote file directories into interconnected 3D spaces.
Users can seamlessly "surf" the spatial web, turning everyday directories into 3D portals.
```
┌───────────────────────────────────┐ ┌──────────────────────────────────────────┐
│ local disk │ │ Surf via 3D portals │
├───────────────────────────────────┤ └──────────────────────────────────────────┘
│ │
│ /myverse │ https://my.org/myverse
│ /elearnings │ https://my.org/myverse/elearnings
│ /elearning1/1.glb │ https://my.org/myverse/elearning/elearning1
│ /elearning2/2.glb │ https://my.org/myverse/elearning/elearning2
│ │
│ ┌──────────────────────────────┐ │
│ │ github / webdav / dropbox etc│ │
│ │ │ │
│ │ /mygames │ │ https://my.org/myverse/mygames
│ │ /biggusgateWebXR │ │ https://my.org/myverse/mygames/biggusgate
│ │ /spasca │ │ https://my.org/myverse/mygames/spasca
│ │ /otherxrforge │ │ https://my.org/myverse/otherxrforge
│ │ │ │
│ │ ┌───────────┐ ┌───────────┐ │ │
│ │ │/manyfold │ │archive.org│ │ │ https://my.org/myverse/manyfold
│ │ └───────────┘ └───────────┘ │ │ https://my.org/myverse/myarchive
│ │ │ │
│ │ +40 integrations! │ │
│ └──────────────────────────────┘ │
└───────────────────────────────────┘
```
## Usage / Radical Opensource
```bash
$ ./xrforge.com
Usage: ./xrforge.com [opts]
./xrforge.com test run testsuite (selftest)
./xrforge.com admin launch adminpanel to configure stuff (/admin)
./xrforge.com generate generate www-folder with XR experiences
./xrforge.com help display all possible flags
./xrforge.com createplugin generates skeleton plugin
./xrforge.com server starts the webserver [without --nobrowser]
./xrforge.com build build
$ unzip xrforge.com
Archive: result/bin/xrforge.com
Length Date Time Name
--------- ---------- ----- ----
3992 08-03-2026 09:54 .init.lua
242 08-03-2026 09:46 cmd/server.lua
1014 07-23-2026 16:13 cmd/createplugin.lua
580 07-24-2026 16:12 cmd/help.lua
....
```
> Profit! you have aqcuired the sourcecode from the binary: run and distribute modified versions if needed ♥
## Adding content
First you need a directory with glTF or JanusXR experiences.
Just run this in the terminal:
```bash
$ unzip xrforge.com myverse
$ tree myverse
myverse
├── janusxr
│ ├── helloworld
│ │ └── janusxr.xml
│ ├── janusxr.png
│ └── tronverse -> ../tronverse <---
└── tronverse | recursive portals allowed
├── janusxr -> ../janusxr <--- via symlinks
├── tron
│ ├── README.md
│ ├── tron.glb
│ ├── tron.mp3
│ └── tron.png
└── tronverse.png
```
> optionally you can run `./xrforge.com admin` and change the `myverse` directory if needed.
Now xrforge.com will scan that local folder:
```bash
$ ./xrforge.gom
scanning experiences (this make take a while..)
✅ └─ plugin/diskscan: detected .png thumbnail file
✅ ./myverse/janusxr 10927498
✅ ./myverse/janusxr/helloworld 10927500
✅ └─ plugin/janusxr: janusxr.xml
✅ └─ plugin/diskscan: detected .png thumbnail file
✅ └─ plugin/diskscan: detected .png thumbnail file
✅ ./myverse/tronverse 10927503
✅ └─ plugin/diskscan: detected .png thumbnail file
✅ ./myverse/tronverse/tron 10927504
✅ └─ plugin/xrfragments: detected .png sidecarfile
✅ └─ plugin/markdown: detected README.md
✅ └─ plugin/diskscan: detected .png thumbnail file
ℹ️ ./myverse/janusxr/tronverse
✅ └─ plugin/diskscan: detected symlink..creating portal
ℹ️ ./myverse/tronverse/janusxr
✅ └─ plugin/diskscan: detected symlink..creating portal
```
## Customizing
After first (in the terminal) run a lua config file is created, which you can edit:
```bash
$ xrforge.com
$ ls
xrforge.com
xrforge.lua
```
With basic HTML/CSS skills you can edit the templates by running this in the terminal:
```bash
$ unzip xrforge.com page css
$ ls
page css
```
> Profit! You can now edit the extracted html-templates and css-files, they will be detected automatically when running xrforge.com
Optionally you can re-distribute `xrforge.com` with your modifications by running `zip xrforge.com page`
## Plugins
xrforge is basically plugins working together.
You can create your own plugins by running:
```bash
$ ./xrforge.com createplugin > xrforge.myplugin.lua
```
Look in the [src/plugin](src/plugin) directory for examples
## 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'
```
## Developing
```bash
$ source .env # not needed if your system has autoenv
$ build # fast: repeatable build
$ rebuild # faster: lua-repeatable build
$ nix-build # slow: reproducable nix build (for experts)
```
Then run with debug flag to see output of `trace()` calls
```bash
$ DEBUG=1 result/bin/xrforge.com
```
## Permacomputing Spirit
* developed on [Dillo](https://dillo-browser.github.io/) as lowest common denominator / compatibility
* does not use javascript (WebXR viewer being the exception)
* 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.
## Credits / Made with
* [redbean](https://redbean.dev)
* [soakbean](https://github.com/coderofsalvation/soakbean)
* [xrfragments](https://xrfragment.org)
* [janusxr](https://github.com/jbaicoianu/janusweb)
* [janusweb](https://janusxr.org)
## Ideas
* tabs horizontal stacked for xrforge.max.css
* fuzzy search: https://github.com/ssimonp/FuzzySearch-Roblox
* landingpage = /about
* scan functions in xrforge.lua / .xrforge
* video-hover: https://codepen.io/coderofsalvation/pen/YPNOyqx
NOTES:
```
/admin.lua <--- define other instances..for CORS allow / mount http
configure in-zip or filesystem-cache
opendirectory.lua <--- mount other instances over http (via xrforge or rclone)
.xrforge/hook/scandir <-- event to hook
scan files
---------- middleware/xrexperience.lua
| events: ---------------------
+ file type: sidecarfile
+ sidecarfiles ---> regex = {"\.glb", "\.png", "\.vtt"}
| regex_minmatch = 2
+ folder viewer = /view/janusweb/#janus.url=${file}.glb
template = [[
...
]]
```