Multi-user VR on the Web
Write full-featured multi-user VR experiences entirely in HTML.
Built on top of the wonderful A-Frame.
- Includes everything you need to create multi-user WebVR apps and games.
- Support for WebRTC and/or WebSocket connections.
- Voice chat. Audio streaming to let your users talk in-app (WebRTC only).
- Bandwidth sensitive. Only send network updates when things change. Option to furhter compress network packets.
- Extendable. Sync any A-Frame component, including your own, without changing the component code at all.
- Cross-platform. Works on all modern Desktop and Mobile browsers. Oculus Rift, HTC Vive and Google Cardboard+Daydream supported.
Follow this tutorial to build your own example.
Edit online example with glitch.com/~networked-aframe/.
To get the examples running on your own PC run:
git clone https://github.com/haydenjameslee/networked-aframe.git # Clone the repository.
cd networked-aframe
npm install && npm run easyrtc-install # Install dependencies.
npm run dev # Start the local development server.
With the server running, browse the examples at http://localhost:8080
. Open another browser tab and point it to the same URL to see the other client.
<html>
<head>
<title>My Networked-Aframe Scene</title>
<script src="https://aframe.io/releases/0.5.0/aframe.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/socket.io/1.4.5/socket.io.min.js"></script>
<script src="easyrtc/easyrtc.js"></script>
<script src="https://unpkg.com/networked-aframe/dist/networked-aframe.min.js"></script>
</head>
<body>
<a-scene networked-scene>
<a-assets>
<script id="avatar-template" type="text/html">
<a-sphere></a-sphere>
</script>
</a-assets>
<a-entity id="player" networked="template:#avatar-template;showLocalTemplate:false;" camera wasd-controls look-controls>
</a-entity>
</a-scene>
</body>
</html>
Open in two tabs if nobody else is online.
- Basic
- Dance Club
- 360 Image
- Made something awesome with Networked-Aframe? Let me know and I'll include it here!
Networked-Aframe works by syncing entities and their components to connected users. To connect to a room you need to add the networked-scene
component to the a-scene
element. For an entity to be synced, add the networked
component to it. By default the position
and rotation
components are synced, but if you want to sync other components or child components you need to define a schema. For more advanced control over the network messages see the sections on Broadcasting Custom Messages and Options.
Required on the A-Frame <a-scene>
component.
<a-scene networked-scene="
app: <appId>;
room: <roomName>;
connectOnLoad: true;
signalURL: /;
onConnect: onConnect;
webrtc: false;
webrtcAudio: false;
debug: false;
">
...
</a-scene>
Property | Description | Default Value |
---|---|---|
app | Unique app name. Spaces are not allowed. | default |
room | Unique room name. Can be multiple per app. Spaces are not allowed. | default |
connectOnLoad | Connect to the server as soon as the webpage loads | true |
signalURL | Choose where the WebSocket / signalling server is located | / |
onConnect | Function to be called when client has successfully connected to the server | onConnect |
webrtc | When false use WebSockets for all network messages. When true use a combination of WebSockets and WebRTC connections | false |
webrtcAudio | Turn on / off microphone audio streaming for your app. Only works if webrtc is set to true |
false |
debug | Turn on / off Networked-Aframe debug logs | false |
<a-entity networked="template=YOUR_TEMPLATE, showLocalTemplate=true"></a-entity>
Create an instance of a template to be synced across clients. The position and rotation will be synced by default. The aframe-lerp-component
is added to allow for less network updates while keeping smooth motion.
Parameter | Description | Default |
---|---|---|
template | A css selector to a script tag stored in <a-assets> - Template documentation |
'' |
showLocalTemplate | Set to false to hide the template for the local user. This is most useful for hiding your own avatar's head | true |
Currently only the creator of a network entity can delete it. To delete, simply delete the element from the HTML using regular DOM APIs and Networked-Aframe will handle the syncing automatically.
By default, the A-Frame position
and rotation
components on the root entity are synced when a network entity is created.
To sync other components and components of child entities you need to define a schema per template. Here's how to define and add a schema:
var avatarSchema = {
template: '#avatar-template',
components: [
'position',
'rotation',
'scale',
{
selector: '.head',
component: 'material'
},
{
selector: '.hairs',
component: 'show-child'
}
]
};
NAF.schemas.add(avatarSchema);
Components of the root entity can be defined with the name of the component. Components of child entities can be defined with an object with both the selector
field, which uses a standard CSS selector to be used by document.querySelector
, and the component
field which specifies the name of the component.
Once you've defined the schema then add it to the list of schemas by calling NAF.schemas.add(YOUR_SCHEMA)
.
Component data is retrieved by the A-Frame getData
function. During the network tick each component's data is checked against its previous synced value; if the data object has changed at all it will be synced across the network.
To sync nested templates setup your HTML nodes like so:
<a-entity id="player" networked="template:#player-template;showLocalTemplate:false;" wasd-controls>
<a-entity camera look-controls networked="template:#head-template;showLocalTemplate:false;"></a-entity>
<a-entity hand-controls="left" networked="template:#left-hand-template"></a-entity>
<a-entity hand-controls="right" networked="template:#right-hand-template"></a-entity>
</a-entity>
In this example the head/camera, left and right hands will spawn their own templates which will be networked independently of the root player. Note: this parent-child relationship only works between one level, ie. a child entity's direct parent must have the networked
component.
NAF.connection.subscribeToDataChannel(dataType, callback)
NAF.connection.unsubscribeToDataChannel(dataType)
NAF.connection.broadcastData(dataType, data)
NAF.connection.broadcastDataGuaranteed(dataType, data)
Subscribe and unsubscribe callbacks to network messages specified by dataType
. Send messages to other clients with the broadcastData
functions.
If using WebRTC broadcastData
messages are sent P2P using UDP and are not guaranteed to make it to other clients (although they will most of the time, see why). broadcastDataGuaranteed
messages are always sent via the WebSocket connection to the server using TCP, and hence not using WebRTC at all. These messages are guaranteed to be delivered to all connected clients. In the future a reliable protocol may be added on top of UDP instead of relying on the TCP websocket connection.
Parameter | Description |
---|---|
dataType | String to identify a network message. u is a reserved data type, don't use it pls |
callback | Function to be called when message of type dataType is received. Parameters: function(senderRtcId, dataType, data, targetRtcId) |
data | Object to be sent to all other clients |
NAF.connection.isConnected()
Returns true if a connection has been established to the signalling server.
NAF.options.updateRate
Frequency the network component sync
function is called, per second. 10-20 is normal for most Social VR applications. Default is 15
.
NAF.options.useLerp
By default when an entity is created the aframe-lerp-component
is attached to smooth out position and rotation network updates. Set this to false if you don't want the lerp component to be attached on creation.
NAF.options.compressSyncPackets
Compress each sync packet into a minimized but harder to read JSON object for saving bandwidth. Default is false
.
To measure bandwidth usage, run two clients on Chrome and visit chrome://webrtc-internals
- Follow Hayden on Twitter
- Follow changes on GitHub
- Hang out with the A-Frame community: A-Frame Slack
- Let us know if you've made something with Networked-Aframe! We'd love to see it!
- Getting started tutorial
- Edit live example on glitch.com
- Live demo site
- A-Frame
- WebVR
- EasyRTC WebRTC library
- Bugs and requests can be filed on GitHub Issues
/ (root)
- Licenses and package information
/dist/
- Packaged source code for deployment
/server/
- Server code
/server/static/
- Examples
/src/
- Client source code
/tests/
- Unit tests
- More examples!
- Master client concept
- Positional audio
- Networked physics
Interested in contributing? Shoot me a message or send a pull request.
This program is free software and is distributed under an MIT License.