# Networked-Aframe: multi-user VR in the browser on top of A-Frame

> Networked-Aframe is an MIT licensed JavaScript framework that adds networked avatars, voice and video to A-Frame scenes, syncing entities and components over WebRTC or WebSocket with change-only updates, and it ships with a signalling server for local development. It suits a web team prototyping a shared VR space, and it is the wrong tool for anything beyond browser-based headsets.

**networked-aframe/networked-aframe** — A web framework for building multi-user virtual reality experiences.

- Repository: https://github.com/networked-aframe/networked-aframe
- Website: https://cf9dc236-8b31-41d7-a0f0-3a87c89c70ea.pub.instances.scw.cloud
- Stars: 1,207 · Forks: 302
- Language: JavaScript
- License: MIT
- Published: 2026-10-19 · Updated: 2026-10-19 · Language: en
- Canonical page: https://hysenlabs.com/projects/networked-aframe-networked-aframe

## Two components, one on the scene and one on the entity

The framework works by syncing entities and their components to connected users, and it does so with two pieces of markup. The networked-scene component is required on the a-scene element and configures the connection, while the networked component on an entity marks it as something to synchronise. By default the position and rotation components are synced, and if you want other components or child components synchronised you have to define a schema for them. That separation is the design to understand, because the scene component is where the connection lives and the entity component is where the state lives, and the two meet only through the room the scene joined.

## The scene component is where rooms, adapters and media live

The networked-scene element takes a set of properties, and the README documents each with a default. The serverURL chooses where the WebSocket or signalling server is, defaulting to /. The app is a unique app name with no spaces allowed, defaulting to default. The room is a unique room name, and there can be multiple rooms per app, with clients able to connect only to clients in the same app and room. connectOnLoad defaults to true, onConnect names the function called once connected, and the adapter picks the network service, defaulting to wseasyrtc. Audio and video both default to false and only work if the chosen adapter supports them, and debug defaults to false.

```html
<a-scene networked-scene="
  serverURL: /;
  app: <appId>;
  room: <roomName>;
  connectOnLoad: true;
  onConnect: onConnect;
  adapter: wseasyrtc;
  audio: false;
  video: false;
  debug: false;
">
  ...
</a-scene>
```

The room and app pair is the isolation boundary. Two people in different rooms under the same app never see each other, which is what makes multi-tenant use of a single server possible without extra configuration.

## Connection and disconnection are events you control

By default the scene connects as soon as the page loads, and the README explains how to take that control. Setting connectOnLoad to false lets you decide when to join, and when you are ready you emit a connect event on the a-scene element.

```javascript
AFRAME.scenes[0].emit('connect');
```

Disconnecting is done by removing the component from the scene element entirely.

```javascript
AFRAME.scenes[0].removeAttribute('networked-scene');
```

Both are worth knowing precisely, because a scene that connects on load and a scene that connects on a user gesture behave differently in a browser that blocks the microphone until a gesture, and the audio and video flags interact with that.

## A minimal scene is a template and a networked entity

The basic example in the README shows the smallest working setup, and it is short enough to read as a template for the whole API. The page pulls A-Frame 1.8.0 from aframe.io, socket.io 4.8.1 from cdnjs, the EasyRTC client from the server's easyrtc path, and the Networked-Aframe bundle from unpkg. The scene contains a template with a sphere, and a player entity that references the template, with attachTemplateToLocal set to false, and carries the camera, wasd-controls and look-controls components.

```html
<a-entity id="player" networked="template:#avatar-template;attachTemplateToLocal:false;" camera wasd-controls look-controls>
</a-entity>
```

The template mechanism is what makes avatars possible without a server round trip per avatar, and the fact that the networked property is a semicolon-separated string inside the attribute is the A-Frame convention for component parameters, which matters if you are writing the scene from a templating language rather than by hand.

## The bandwidth claim is about change detection, not compression

One feature in the list is phrased as bandwidth sensitive, with only network updates sent when things change. That is the design decision that makes a browser-based multi-user experience viable at all, since a naive implementation would broadcast every entity's transform every frame. The rest of the feature list follows from the same constraint of keeping everything in the browser. Voice chat is listed as audio streaming to let users talk in-app, with a WebRTC only note, and video chat lets you see video streams in-app. Cross-platform support covers all modern desktop and mobile browsers and names Oculus Rift, Oculus Quest, HTC Vive and Google Cardboard. The extendability claim is the one developers care about most: you can sync any A-Frame component, including your own, without changing the component code at all.

## Running the examples locally needs a signalling server

The getting started section gives a fork of the naf-project template on StackBlitz and points at a tutorial for building an example from scratch including setting up a local server. To run the examples on your own machine, four commands are enough.

```sh
git clone https://github.com/networked-aframe/networked-aframe.git  # Clone the repository.
cd networked-aframe
npm install  # Install dependencies.
npm run dev  # Start the local development server.
```

With the server up, the examples are browsed at http://localhost:8080, and the README's instruction for seeing another client is simply to open a second tab at the same URL. The package.json shows what the dev script actually starts, a cross-env with NODE_ENV set to development running the easyrtc server, and there is a parallel dev-socketio script for the socket.io variant, along with start and start-socketio for the production forms. That is the whole deployment story for the signalling layer, and the NAF Hosting Guide is where to read about putting it on the internet.

## Examples, adapters and a MIT licence

The examples directory in the repository is the fastest way to see what the framework can do, and the file names are a feature list. There are basic.html and basic-2.html and basic-4.html for one and multiple clients, basic-audio.html for positional audio, basic-video.html for video streaming, basic-chat.html, basic-events.html for custom message events, basic-multi-streams.html, basic-persistent.html, nametag.html, tracked-controllers.html, child-entities.html for child entity syncing, disconnect.html, dynamic-room.html for changing room at runtime, ownership-transfer.html for handing control of an object, persistent-peer-to-peer.html, basic-ar.html and 360.html for augmented reality, google-blocks.html, and an adapter-test directory. Two more complete examples live in separate repositories, nametags with a UI in SolidJS and Tailwind CSS, and realistic animated avatars with a UI to choose your avatar. The licence is MIT, and the package version is 0.14.3 with the main entry point at src/index.js, with the server living in a server/ directory and the bundle built by webpack.

## Conclusion

Networked-Aframe fits a web team that wants to put a shared VR space in front of users without running a native client, since the whole stack is HTML and JavaScript, the avatar is an ordinary A-Frame entity, and the local server makes the multi-user behaviour testable in two browser tabs before any headset is involved. It is a poor fit if you need more than browser rendering, and a poor fit for a production deployment that expects a turnkey signalling stack, since the project ships a development server and a hosting guide rather than a managed service. Verify first which network adapter you need, since the default wseasyrtc adapter and the socket.io server are different stacks, and check whether the voice and video features are available in the adapter you choose, since the README states they only work if the adapter supports them.

## FAQ

### What does Networked-Aframe add to A-Frame?

It syncs entities and their components to connected users. You add the networked-scene component to the a-scene element to join a room, and the networked component to an entity to have it synchronised, with position and rotation synced by default.

### How do I join a room in Networked-Aframe?

Set the app and room properties on the networked-scene component and either let connectOnLoad handle it, which is the default, or set it to false and emit the connect event on the a-scene element when you are ready. Clients can only see clients in the same app and room.

### Can I use voice and video chat?

Yes, with the audio and video properties of the networked-scene component, which default to false. The README notes that both only work if the chosen network adapter supports them, and that audio streaming for voice chat is WebRTC only.

### How do I run the Networked-Aframe examples locally?

Clone the repository, run npm install and then npm run dev, which starts the local development server. The examples are then browsed at http://localhost:8080, and opening a second tab at the same URL shows the other client.

## Sources

- [License: MIT](https://github.com/networked-aframe/networked-aframe/blob/master/LICENSE)
- [networked-aframe/networked-aframe on GitHub](https://github.com/networked-aframe/networked-aframe)
- [Project website](https://cf9dc236-8b31-41d7-a0f0-3a87c89c70ea.pub.instances.scw.cloud)
- [README](https://github.com/networked-aframe/networked-aframe/blob/master/README.md)
- [Releases](https://github.com/networked-aframe/networked-aframe/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/networked-aframe-networked-aframe
