Skip to main content
Hominid Software — Tech for Personal Growth

Multiuser WebXR using Croquet OS & A-Frame

There's a new network option for A-Frame
About 3 min reading time

Croquet OS is real-time synchronization-as-a-service (and not restricted to WebXR). You don't run your own synchronization server; large traffic volumes require payment.

It's designed around keeping state in its own Model objects, which have a number of restrictions so each client maintains a bit-identical simulation. Web apps which keep all state and modeling in Croquet Models avoid the who-grabbed-it-first problem.

Croquet has Views to handle display and user input, which can differ between users. They mediate between Models and the rest of your code.

Croquet keeps snapshots on the network, so sessions can be resumed, even if no clients are still online. (Unlike networked-aframe and Mozilla Hubs, if I understand them correctly.) Croquet has its Worldcore library to handle scene graph, position, rotation, etc. Worldcore can render using their webgl package or Three.js. Croquet packages cover most, but not all, of what Three.js does. There is no directory of third-party components available for use.

A-Frame maintains a scene graph using Three.js, so you won't use Worldcore with A-Frame. You can the A-Frame Croquet Component to synchronize the attributes of A-Frame entities

Off-the-shelf A-Frame components maintain state internally. When user input or world modeling (such as collision detection) happens in A-Frame, a synthetic DOM event must be emitted for a View to receive. Typically, the View will need to publish a message to one or more Models. The message must be sent over the network to every client. The Model(s) (on each client) would typically publish a message to other Models or their Views, and the View(s) (on each client) will set attributes on A-Frame objects. This can make debugging tedious, but delay comes mainly from the network.

You could rewrite A-Frame components to keep state in Croquet Models, but at that point it may make more sense to switch to Worldcore.

The A-Frame State Component provides a centralized store for state data. An analogous component with similar syntax could be written for Croquet, but that hasn't happened yet.

The A-Frame Croquet Component allows a world to define an HTML Template for user avatars. A different color attribute is applied to each user's avatar, but most primitives (including gltf-model) don't use that.

Xalot world

For other users to join the same session, a current user must share the URL, including the query string.

Croquet Models are typically synced 20 times per second, not coupled to A-Frame tick(). That's fine for low-speed syncing, for example, seeing which way another player's avatar is facing. That's also fine for detecting whether a moving object collides with a stationary object. A-Frame collision detection will not be coupled to Croquet syncing, so high-speed simulation will have issues. For example, calculating if one player's fireball collides with the other player's dodging avatar will depend on which client the calculation is done. Likewise, one client might calculate that one player had grabbed some object first, while another client might calculate that another player had grabbed it first.

A number of edge cases have to be dealt with

It's easy to throw together a multi-user experience (without voice chat) using existing A-Frame components and your A-Frame expertise. However, as an immature library, you might have to code and submit a PR to get advanced capabilities. And it may not be the best choice for an action game or polished experience.

See also this Comparison of Croquet with Networked A-Frame and Mozilla Hubs.