No description
Find a file
2026-08-18 22:21:48 +02:00
src css polish 2026-08-18 22:21:48 +02:00
.env added share button + parent world link 2026-08-18 15:30:10 +02:00
.gitignore 🔧 master: work in progress [might break] 2026-07-31 20:03:24 +02:00
default.nix 1st commit 2026-05-15 13:22:33 +02:00
LICENSE added license 2026-08-13 17:27:04 +02:00
README.md improved rssatom/federation/peertube plugins + ttemplates 2026-08-17 13:42:27 +02:00
run.sh optimized scanner 2026-08-02 14:00:56 +02:00
screenshot.jpg 🔧 master: work in progress [might break] 2026-08-13 17:19:27 +02:00
shell.nix show fediportals in dir.html + convert plugin now works with X3D 2026-08-11 17:47:40 +02:00

XRForge is a tiny, powerful tool to interconnect XR experiences via 3D portals...like a federated viverse.com

An open, seamless XR web built from simple URLs and directories, without gatekeepers, built upon Next Generation Internet (NGI) specs:


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 via rclone  │ │
    │  └──────────────────────────────┘ │
    └───────────────────────────────────┘ 

Usage / Radical Opensource

$ ./xrforge.com 
Usage: ./xrforge.com <cmd> [opts]

  ./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 test         run testsuite (selftest)

Extract and run example 3D content in your browser:

$ unzip xrforge.com myverse/*       # extract example 3D verse
$ ./xrforge.com server              # run as server
opening your browser at https://localhost:8080

Radical opensource

$ 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:

$ 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:

$ ./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:

$ xrforge.com 
$ ls
xrforge.com
xrforge.lua

With basic HTML/CSS skills you can edit the templates by running this in the terminal:

$ 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

Distribute your own XRForge

You can preload the xrforge.com binary with your own experiences as a single-executable-file:

$ zip -r xrforge.com myverse    # add my 3D experiences to the binary
$ cp xrforge.com myproject.com

Profit!

Plugins

xrforge is basically plugins working together.
You can create your own plugins by running:

$ ./xrforge.com createplugin > xrforge.myplugin.lua

Look in the src/plugin directory for examples

Run as server

BAREMETAL:

$ ./xrforge.com server

NOTE: if the binary does not work on your server, use xrforge-x86_64 from the releases section instead.

DOCKER: to prevent polluting the environment with terabytes of docker-images, just run this:

$ docker run -d -p 8080:8080 -w /app -v $(pwd):/app busybox /app/xrforge.com server

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

$ 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

$ DEBUG=1 result/bin/xrforge.com

Testing: run the builtin testrunner: cd src && ../result/bin/xrforge.com test

Use ARCH=x86_64 build to enforce x86_64 output (instead of a cosmopolitan binary)

Permacomputing Spirit

  • developed on Dillo 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

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

Ideas

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 = [[
                         <div class="tile"> ... </div>
                       ]]