In game development, UIs are often a source of frustration. They're hard to build, hard to maintain, and hard to make look good. Ambient's UI solution aims to change that.
Ambient UI is a UI framework built on top of Element, Ambient's React-like system for building, diffing and mutating arbitrary trees of game entities. It’s versatile and can be used to build any kind of UI, from a simple text box to a full-blown game UI.
Ambient UI features many of the features you'd expect from a UI framework, including widgets, layouting, styling, and more. All of this is built using Element without any magic, so you can implement your own widgets, too.
The real superpower of Ambient UI comes into play when combined with the rest of our runtime. Because we provide integrated multiplayer, an ECS, and messaging, you have an all-in-one solution for multiplayer UI. This is a powerful combination, and we're excited to see what people build with it.
To demonstrate this, we present a whirlwind tour of a simple multiplayer beat sequencer with a synchronized beat map and samples - in just over a hundred lines of code. This is a minimalistic version of the music_sequencer example, which also features BPM control and per-player colors for notes.
First, create a project with ambient new:
This will create a new Ambient project that is prepopulated with Rust code. Our plan is to represent each track of the sequencer as a separate entity in the ECS, with each track having a component attached to it with the notes.
To do this, we’ll need to add the relevant components to the ambient.toml, which is the project manifest. All components, messages and more are defined in the manifest - this allows them to be used from any compatible language.
This is sufficient to get started with the server code. Place your favourite sounds into an assets folder next to src; for the example in the repository, we’ve used these sounds.
Next, open server.rs, and add the following code to spawn in the track entities:
This will create an entity for each of our predefined tracks - feel free to use your own sounds! - which will be automatically replicated to each client, thanks to Ambient’s tightly-integrated ECS and networking.
Of course, you’ll need a way to view and edit the notes. That’s where the clientside WASM comes in - open up client.rs and add the following in:
This uses Ambient UI to render the state of the tracks in the ECS. Every time the track state changes, each track is rendered using the Track component, which displays the track name and the state of each note. That’s all you need to get this:
Now, let’s make these buttons clickable. We know that these buttons are mirroring the state of the ECS, so we’ll need to update the ECS on the server. To do this, we can use Ambient’s messages, which offer structured communication between client, server and other modules. Add the following to your ambient.toml:
This defines a click message that the server can subscribe to, and the client can send.
On the server, add the following code:
This tells the server to update the ECS when it receives a message from the client, and to toggle the corresponding note for the requested track.
Now all we have to do is to wire up the client. Our present implementation uses buttons with an empty callback - all we need to do is send a message in the callback:
We’re now more or less done, except for one little thing: actually playing notes! To get across to the finish line, let’s add a cursor that automatically moves in accordance with the beat.
Add the following to the App:
This will create a cursor that will be updated on every note. This can then be passed down to the Track, and the Button can be highlighted based on the cursor:
And now that it’s been wired up, you can see the cursor sweeping across the tracks:
All that remains is to play a sound when the cursor changes to a note. To do this, add the following to Track:
This code will load the sound for the track the first time the Track is rendered. Every time the cursor or the note selection changes, the cursor will be checked against the note selection, and a sound will be played. With this, we finally complete our basic music sequencer.
Of course, as this is Ambient, you get multiplayer for free. Invite a friend to join you using the Ambient Proxy (described below), and enjoy sequencing together!
We recommend using the full music_sequencer example, which is styled to look more like a traditional sequencer, and features more advanced features.