{"id":18084875,"url":"https://github.com/coderofsalvation/aframe-verse","last_synced_at":"2026-03-06T20:01:50.917Z","repository":{"id":65270984,"uuid":"560410046","full_name":"coderofsalvation/aframe-verse","owner":"coderofsalvation","description":"deadsimple immersive navigation: a single-player-verse component","archived":false,"fork":false,"pushed_at":"2023-05-22T08:07:35.000Z","size":3886,"stargazers_count":13,"open_issues_count":0,"forks_count":1,"subscribers_count":2,"default_branch":"main","last_synced_at":"2025-07-22T17:44:39.445Z","etag":null,"topics":["aframe","augmented-reality","navigation","oculus-quest","virtual-reality","vr","webxr"],"latest_commit_sha":null,"homepage":"https://coderofsalvation.github.io/aframe-verse/apps","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/coderofsalvation.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2022-11-01T12:49:37.000Z","updated_at":"2024-06-19T01:05:43.000Z","dependencies_parsed_at":"2025-04-12T20:20:45.561Z","dependency_job_id":null,"html_url":"https://github.com/coderofsalvation/aframe-verse","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/coderofsalvation/aframe-verse","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/coderofsalvation%2Faframe-verse","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/coderofsalvation%2Faframe-verse/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/coderofsalvation%2Faframe-verse/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/coderofsalvation%2Faframe-verse/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/coderofsalvation","download_url":"https://codeload.github.com/coderofsalvation/aframe-verse/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/coderofsalvation%2Faframe-verse/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30195529,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-06T19:07:06.838Z","status":"ssl_error","status_checked_at":"2026-03-06T18:57:34.882Z","response_time":250,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["aframe","augmented-reality","navigation","oculus-quest","virtual-reality","vr","webxr"],"created_at":"2024-10-31T15:08:28.790Z","updated_at":"2026-03-06T20:01:50.882Z","avatar_url":"https://github.com/coderofsalvation.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003e LATEST NEWS: for an AFRAME \u0026 file-format-agnostic version see [the XR Fragments standard instead](https://coderofsalvation.github.io/xrfragment/#XR%20Fragments)\n\n## AFRAME-verse, deadsimple immersive navigation\n\n![](.img/demo.gif)\n\nA single-player-verse component for [AFRAME](https://aframe.io):\n\n### TRY THE [ONLINE DEMO](https://coderofsalvation.github.io/aframe-verse/apps/)\n\n* ❤️ easily teleport between aframe apps \u0026 aframe-verse clusters \n* ❤️ does not exit immersive-mode when navigating to different aframe experiences\n* ❤️ standalone \u0026 serverless: no servers (NAF/signaling) needed\n* ❤️ HTML-first: even runs from wordpress, no ninja javascript-skills needed\n* ❤️ #networkless #decentralized #noblockchain #permissionless-first #federatedpullrequests\n\n\u003e Similar to a **WEB**ring, you can easily create **DOM**rings and **VERSE**rings with this component, that can be **Zuckerburgered** by yourself (or friends).\n\n\u003cdetails\u003e\n  \u003csummary\u003e\u003ch2\u003eUsage\u003c/h2\u003e\u003c/summary\u003e\n  \u003cbr\u003e\n\n```html\n\u003cscript src=\"aframe-verse-component.js\"\u003e\u003c/script\u003e\n\n\u003ca-scene\u003e\n  \u003ca-entity aframe-verse=\"register: /aframe-verse.json\"\u003e\n\n    \u003c!-- everything nested under `aframe-verse`, will be replaced upon navigation  --\u003e\n\n    \u003ca-box href=\"/\"\u003e\u003c/a-box\u003e          \u003c!-- home = the cluster-client (index.html) --\u003e\n    \u003ca-box href=\"./app2.html\"\u003e\u003c/a-box\u003e  \n    \u003ca-box href=\"https://somefriend.com/some_aframe_app.html\"\u003e\u003c/a-box\u003e\n    \u003ca-box href=\"https://somefriend.com/supercustom_webxr_app.html\"\u003e\u003c/a-box\u003e\n\n  \u003ca-entity\u003e\n\n  \u003c!-- entities below survive during teleporting                                    --\u003e\n  \u003c!-- use 'wearable' to indicate sticking objects to controller in immersive mode  --\u003e\n  \u003ca-entity id=\"player\"\u003e\n    \u003ca-entity camera position=\"0 1.6 0\" wasd-controls look-controls mouse-cursor\u003e\u003c/a-entity\u003e\n    \u003ca-entity id=\"leftHand\"  laser-controls=\"hand: left\"  raycaster=\"objects: [button]\" raycaster=\"lineColor: #888; lineOpacity:0.5\"\u003e\u003c/a-entity\u003e\n    \u003ca-entity id=\"rightHand\" laser-controls=\"hand: right\" raycaster=\"objects: [button]\" raycaster=\"lineColor: #888; lineOpacity:0.5\"\u003e\u003c/a-entity\u003e\n    \u003ca-entity navigator position=\"0 1.092 -0.595\" rotation=\"-45 0 0\" wearable=\"el: #leftHand; rotation: -45, 0, 0; position: -0.02, -0.03, -0.1\"\u003e\u003c/a-entity\u003e\n  \u003c/a-entity\u003e\n  \n  \u003c!-- ps. multiple (nested) aframe-verse components are supported!                --\u003e\n\n\u003c/a-scene\u003e\n```\n\nRecursive description of a verse (`aframe-verse.json`):\n```json\n{\n  \"schema\":\"aframe-verse/0.1\",\n  \"destinations\":[ \n    {\"url\":\"./index.html\"},               // immersive navigation\n    {\"url\":\"./app2.html\" },               // \n    {\"url\":\"https://coderofsalvation.gitlab.io/aframe-urwhatuthink/experience.html\", \"title\":\"Leon Du Star - URWHATUTHINK\", \"scripts\":true},\n    {\"url\":\"https://fabien.benetou.fr/pub/home/future_of_text_demo/engine/\",\n     \"author\":\"Fabien Benetou\", \n     \"newtab\": true                       // opens in new tab (does not contain aframe-verse component)\n    }\n  ], \n  \"verses\":[  // import trusted destinations\n    {\"url\":\"https://coderofsalvation.github.io/aframe-verse-leondustar/aframe-verse.json\", \"scripts\":true}\n  ]\n}\n```\n\n  \u003cdetails\u003e\n    \u003csummary\u003e\u003ch4\u003eClick here for properties\u003c/h4\u003e\u003c/summary\u003e\n    \u003cbr\u003e\n\n| property   | type | info |\n|------------|------|------|\n| debug      | bool (false) | shows info in the browserconsole     |\n| register   | string | location of aframe-verse.json destinations  |\n| hrefEvents | stringarray (click, collide) | events which trigger teleport to href |\n| fade       | integer (100) | amount (in ms) of fade-in fade-out time       |\n| fadeColor  | string ('black') | (hex)color(name) for fading       |\n  \u003c/details\u003e\n  \n  \u003cdetails\u003e\n    \u003csummary\u003e\u003ch4\u003eClick here for events\u003c/h4\u003e\u003c/summary\u003e\n    \u003cbr\u003e\n\n| component    | property     | promise | info                               |\n|--------------|--------------|---------|------------------------------------|\n| aframe-verse | registerJSON | no      |fires when loading aframe-verse JSON file(s) |\n| href         | beforeNavigate | yes     |fires before navigation fadeout   |\n| href         | navigate       | yes     |fires after navigation fadeout    |\n| href         | loadHTML       | yes     |fires before inserting new DOM content |\n| href         | loaded         | yes     |fires after all DOM content is loaded ('domready' e.g.)|\n\n\u003e See chapter `Customizing (with code)` \u003e `Customizing navigation Further` for flowcontrol using promises.\n  \u003c/details\u003e\n  \n\u003c/details\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003e\u003ch2\u003eHow it works\u003c/h2\u003e\u003c/summary\u003e\n  \u003cbr\u003e\n\n![](.img/flow.jpg)\n\nA visitor in an **aframe-verse** just teleports to other destinations and clusters (\"*beam me up scotty!*\").\u003cbr\u003e\n`aframe-verse.json` is just a telephone-book of destinations.\n\n\u003e  When a visitor surfs to a cluster-client ([index.html](apps/index.html)), it loads all components, which other linked experiences use.\n\n\u003cdetails\u003e\n  \u003csummary\u003eHow does this works in large?\u003c/summary\u003e\n  \u003cbr\u003e\n\n  The concept above is an answer to the fact that each tile-based 'metaverse' will always turn into some kind of **hypercentralized** client-project.\n  Instead, a visitor in the **aframe-verse** just teleports to other destinations and clusters.\u003cbr\u003e\n  When the visitor surfs to a cluster-client ([index.html](apps/index.html)), it basically loads all components, which other linked experiences use.\u003cbr\u003e\n  This is a security-limitation and a performance-feature, because this: \n  \n  * makes traveling between experiences (within a cluster) very fluid and fast.\n  * it creates a decentralized incentive between developer(s) to:\n    * collaborate on a seamless \u0026 secure end-visitor cluster-client ([index.html](apps/index.html))\n    * consistent UX because of:\n      * shared components\n      * shared global objects: wearables, UI, AR/VR controller-support e.g.\n  \n  \u003e As an exception to the rule, the developer(s) (YOU) of a cluster-client ([index.html](apps/index.html)) can load remote (trusted) components/scripts, which is demonstrated by [aframe-verse-component-scripts](https://github.com/coderofsalvation/aframe-verse-component-scripts).\n \n  Worstcase, a destination can be loaded in a new tab (`newtab:true` which exits immersive navigation ), which then basically becomes the new cluster.\n\n\u003cdetails\u003e\n  \u003csummary\u003e\u003ch3\u003eFederated HTML-first verse-clusters\u003c/h2\u003e\u003c/summary\u003e\n  \u003cbr\u003e\n\n\u003e aframe-verse describes a verse using the lowest common denominator between Aframe authors (=a webdirectory)\n\nThis could be a github-repo, or linuxserver where:\n* the **maintainer(s)** maintain a pool of trusted aframe apps (\u0026 components)\n* the **maintainer(s)** allow DOM-sharing (a DOM-ring) between eachothers aframe-apps\n* the **maintainer(s)** agree on shared garbage collection \n\n\u003e Ideally, the maintainers need to approve new (website-specific) scripts/components, and include them in [index.html](apps/index.html) when a new app arrives thru merge requests.\n\n#### But..but..what about privacy \u0026 security?\nThis is all up to the maintainers of a verse, just think of it as running a shared website \u0026 linksharing.\u003cbr\u003e\nFor more info [read this](https://github.com/coderofsalvation/aframe-verse/issues/1)\n\n\u003c/details\u003e\n  \u003cdetails\u003e\n    \u003csummary\u003e\u003ch3\u003eProject scope\u003c/h3\u003e\u003c/h2\u003e\u003c/summary\u003e\n    \u003cbr\u003e\n\nOut of the box, this component is good enough for seamlessly navigating between **simple read-only** aframe experiences (galleries, portfolios, vr movies, viewing scenes e.g.).\u003cbr\u003e\nA monoverse is the opposite of a 'metaverse'-concept (in which multiplayer-communication is fundamental).\nTherefore, the following is out of scope, but can still be used to progressively enhance an `aframe-verse`:\n\n* multiplayer: see the (way more complex) [NAF approach](https://github.com/networked-aframe) which requires you to run your own server.\n* hardened security/privacy: introduce activitypub-layer, p2p webrtc like yjs\n  \u003c/details\u003e\n  \n\u003c/details\u003e\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003e\u003ch2\u003eHow to add experiences?\u003c/h2\u003e\u003c/summary\u003e\n  \u003cbr\u003e\n\n\u003e Just check [index.html](apps/index.html) and [app2.html](apps/app2.html), Basically:\n\n* put your aframe apps in `apps/*` (they should have an `aframe-verse`-attribute set somewhere)\n* add `href`-attributes to clickable items (see example)\n* use `href=\"./afile.html\"` to teleport to relative files \n* whitelist `href=\"https://...\"`-links by including them in `aframe-verse.json` (see browserconsole for errors)\n* use `href=\"/\"` to guide the visitor back to the original cluster\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003e\u003ch2\u003eHow to add components?\u003c/h2\u003e\u003c/summary\u003e\n  \u003cbr\u003e\n\n  Typically these are included in the cluster-client [index.html](apps/index.html).\u003cbr\u003e\n  \n  #### What if other apps require certain components/scripts?\n\n  As an exception to the rule, you can load remote (trusted) components/scripts, which is demonstrated by [aframe-verse-component-scripts](https://github.com/coderofsalvation/aframe-verse-component-scripts).\n\n\n\u003c/details\u003e\n\n\n\u003cdetails\u003e\n  \u003csummary\u003e\u003ch2\u003eCustomizing (with code)\u003c/h2\u003e\u003c/summary\u003e\n  \u003cbr\u003e\n\n  \u003e Rule of thumb: load (or extend loading) components in the cluster-client ([index.html](apps/index.html))\n\n  \u003cdetails\u003e\n    \u003csummary\u003e\u003ch4\u003eExtending navigation interactions\u003c/h2\u003e\u003c/summary\u003e\n    \u003cbr\u003e\n\nBy defining `hrefEvents`, you can trigger navigation for other events too:\n\n```html\n\u003c... aframe-verse=\"register: /yourverse.json; hrefEvents: click, mouseenter, collide, foobar\"\u003e\n   \u003ca-box href=\"./show.html\"/\u003e  \n\u003c/...\u003e\n```\n\n\u003e Profit! Now navigation is triggered to `show.html` whenever it is clicked, mousehovered or colliding with another object\n\ncalling `$('[aframe-verse] [href]').emit('foobar', {})` would trigger navigation too\n  \u003c/details\u003e\n\n  \u003cdetails\u003e\n    \u003csummary\u003e\u003ch4\u003eCustomizing navigation further\u003c/h2\u003e\u003c/summary\u003e\n    \u003cbr\u003e\n\nYou can control navigation-events by creating a custom component:\n\n```\n// use like: \u003ca-entity aframe-verse=\"...\" navigate\u003e\u003c/a-entity\u003e\n\nAFRAME.registerComponent('navigate', {\n  init: function(){\n    console.log(\"initing navigation\")\n    this.el.addEventListener('beforeNavigate', (e) =\u003e this.beforeNavigate(e) )\n    this.el.addEventListener('navigate',       (e) =\u003e this.navigate(e) )\n    this.el.addEventListener('loadHTML',       (e) =\u003e this.loadHTML(e) )\n    this.el.addEventListener('registerJSON',   (e) =\u003e this.registerJSON(e) )\n  }, \n  beforeNavigate(e){\n    // let promise = e.detail.promise()   \n    console.log(\"about to navigate to: \"+e.detail.destination.url)\n    // promise.resolve()\n    // promise.reject(\"not going to happen\")\n  }, \n  navigate(e){\n    // let promise = e.detail.promise()   \n    console.log(\"navigating to: \"+e.detail.destination.url)\n    // promise.resolve()\n    // promise.reject(\"not going to happen\")\n  }, \n  loadHTML(e){\n    let newdom = e.detail.dom.querySelector(\"[aframe-verse]\")\n    // let promise = e.detail.promise()   \n\t\tconsole.log(\"loading html\")\n    // promise.resolve()\n    // promise.reject(\"not going to happen\")\n  },\n  registerJSON(e){\n    let json = e.detail.json\n    /* example: skip non-immersive navigation links */\n    // json.destinations = json.destinations.filter( (d) =\u003e d.newtab ? null : d )\n    /* example: launch external verses in a new tab (so its components get loaded too) */\n    // json.destinations.map( (d) =\u003e d.url.match(/index\\.html$/) ? d.newtab = true : null )\n  }\n})\n```\n\n\u003e This is the place to show a consent popup e.g. (most trusted experiences can do fine without that in the beginning).\n  \u003c/details\u003e\n\n  \u003cdetails\u003e\n    \u003csummary\u003e\u003ch4\u003eConnecting, Nesting \u0026 Securing verse-clusters\u003c/h2\u003e\u003c/summary\u003e\n    \u003cbr\u003e\n\n![](.img/yodawg.jpg)\n\nFor navigation, you can add external verses to the `.verses`-array in `aframe-verse.json`, that's all!\u003cbr\u003e\nOptionally, you can secure the import-behaviour further using the `registerJSON`-event as shown above in 'Customizing navigation further'.\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003e\u003ch4\u003eFadetime \u0026 nesting verses\u003c/h2\u003e\u003c/summary\u003e\n  \u003cbr\u003e\n\nYou can have multiple persisting verses at the same time.\nUsecases for this are: a menu system, mini-games, inventory or a teleporting-maze e.g.:\n\n```html\n\u003ca-entity aframe-verse=\"register: aframe-verse.json\"\u003e\n  ...\n\u003c/a-entity\u003e\n\n\u003ca-entity aframe-verse=\"register: menu.json; fade: 0\"\u003e   \u003c!-- NOTE: superfast fade in ms (0=off) --\u003e\n  ...\n\u003c/a-entity\u003e\n\n```\n\n\u003e NOTE: for heavy scenes you can set `fade: 4000` (4seconds fade) e.g.\n  \u003c/details\u003e\n\u003c/details\u003e\n\n\n\u003cdetails\u003e\n  \u003csummary\u003e\u003ch2\u003ePublish,  selfhost \u0026 connect your verse (for free)\u003c/h2\u003e\u003c/summary\u003e\n  \u003cbr\u003e\n\n3 ways of hosting:\n\n\u003cdetails\u003e\n  \u003csummary\u003e\u003ch3\u003eGITHUB / GITLAB\u003c/h2\u003e\u003c/summary\u003e\n  \u003cbr\u003e\n\n* click the fork-button on [github](https://github.com/coderofsalvation/aframe-verse) or [gitlab](https://gitlab.com/coderofsalvation/aframe-verse)\n* rename the repository to `aframe-verse-*` (aframe-verse-myorganisation e.g.) for easy discoverability\n* github: go to settings-tab \u003e enable github pages (use the main-branch)\n* profit! your verse can now be accessed thru \n  * github: `https://yourusername.github.io/aframe-verse-myorganisation/apps`\n  * gitlab: `https://yourusername.gitlab.io/aframe-verse-myorganisation/apps`\n\u003c/details\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003e\u003ch3\u003eGLITCH\u003c/h2\u003e\u003c/summary\u003e\n  \u003cbr\u003e\n\n* [REMIX this glitch](https://glitch.com/edit/#!/remix/aframe-verse)\n* rename the project to `aframe-verse-*` (aframe-verse-myorganisation e.g.) for easy discoverability\n* your verse can now be accessed thru `https://aframe-verse-myorganisation.glitch.me/apps/` \n\u003c/details\u003e\n \n\u003cdetails\u003e\n  \u003csummary\u003e\u003ch3\u003eSELFHOSTING (redbean/wordpress/apache e.g.)\u003c/h2\u003e\u003c/summary\u003e\n  \u003cbr\u003e\n\n* [download zip](https://github.com/coderofsalvation/aframe-verse/archive/refs/heads/main.zip) and unpack it in your apache/worpress dir e.g.\n\u003c/details\u003e\n\n\u003e Later: please connect your verse to this repo, by submitting a PR or mentioning your json-URL in an issue. That way, future verses (forks) will automatically include your verse too.\n\n\u003c/details\u003e\n\n\u003cdetails\u003e\n  \u003csummary\u003e\u003ch2\u003eScope / Contributing\u003c/h2\u003e\u003c/summary\u003e\n\nAll feedback,bugfixes are very welcome ❤️\u003cbr\u003e\n\nOther things (features/privacy/security/consent-stuff e.g.) should be published as separate components (see the `navigate` custom-component example in the [aframe-verse README.md](https://github.com/coderofsalvation/aframe-verse) in the `Customizing (with code) \u003e Customizing navigation further` section.\n\n\u003e Please publish any useful components under reponame `aframe-verse-component-mycomponent` for discoverability.\n\nAs a startingpoint for extending, you can simply fork the [scripts-component](https://github.com/coderofsalvation/aframe-verse-component-scripts) as well\n\u003c/details\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcoderofsalvation%2Faframe-verse","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcoderofsalvation%2Faframe-verse","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcoderofsalvation%2Faframe-verse/lists"}