Controlspreview
Define buttons, sliders, keys, taps and on-screen text in controls.ui.yaml, and handle them in Motoko.
The player draws your game's controls and on-screen text from controls.ui.yaml, and handles keyboard, mouse and touch input. Your actor receives named actions in moxzi_input.
The file's metadata must have kind: ui and address: ui/main, or the player won't find it.
version: 1
title: Drift
labels:
- id: position
fallback: "x = 0.0 m"
buttons:
- id: center
label: Center
action: center
key: space
axes:
- id: steer
action: steer
range: [-5000, 5000]
initial: 0
negative_key: a
positive_key: d
units_per_second: 4000
Top-level fields#
| Field | Required | Meaning |
|---|---|---|
version | Yes | 1 |
title | Yes | Shown in the control panel |
buttons | Yes | Buttons. Can be empty ([]) |
axes | No | Sliders driven by keys or dragging |
labels | No | Text your actor sets each tick |
point | No | An action sent when the player taps or clicks the world |
theme | No | Panel colours: background, button, accent, text, each sRGB [r, g, b] from 0 to 1 |
gameplay_aspect | No | Width-to-height ratio to keep for the game view |
help | No | Help text, up to 4096 bytes |
Unknown fields are an error.
Buttons#
| Field | Meaning |
|---|---|
id | Unique id |
label | Button text |
action | Sent to moxzi_input when pressed |
payload | Optional text sent with the action |
key | Optional keyboard shortcut. See Keys |
background | Optional button colour, sRGB [r, g, b] |
label_from | Optional label id: the button shows that label's current text instead of label |
Handle the action in moxzi_input:
public shared ({ caller }) func moxzi_input(command : Input.Command) : async Hud.InputAck {
assert host == ?caller and not suspended;
assert command.epoch == epoch and command.at_tick == tick;
assert command.sequence == sequence + 1;
sequence := command.sequence;
let accepted = switch (command.action) {
case "steer" {
// Axis values arrive as decimal text, such as "-2500".
switch (parseInt(command.payload)) {
case (?mm) { target := mm; true };
case null false;
}
};
case "center" { target := 0; clickPending := true; true };
case _ false;
};
{ epoch; sequence; at_tick = tick; accepted; paused = false; output = ""; hud = ?hud() }
};
Player-only buttons#
A button with local instead of action controls the player itself and never reaches your actor:
local | Effect |
|---|---|
reduced_effects | Turns bloom and shadows down |
help | Shows the help text |
home_view | Resets the camera view |
Axes#
An axis is a value in a range that keys or dragging change. The player sends the value to your actor as decimal text whenever it changes.
| Field | Meaning |
|---|---|
id, action | Id, and the action sent to moxzi_input |
range | [min, max] whole numbers |
initial | Starting value |
negative_key, positive_key | Keys that move the value down and up |
units_per_second | How fast a held key changes the value |
pointer | Whether dragging changes the value. Default true |
direction | horizontal (default) or vertical drag |
region | Part of the screen where dragging works, [x, y, width, height] as fractions. Default the whole screen |
invert | Reverse the drag direction |
plane | Drag along a surface in the 3D scene instead of across the screen. See below |
Values arrive as UTF-8 text such as "-2500". Parse them as in Drift's parseInt, and reject anything that doesn't parse.
Dragging in the scene#
With plane, the player projects the pointer onto a plane in the world, so the value follows the finger or mouse exactly. Pong uses this for the paddle:
| Field | Meaning |
|---|---|
origin | A point on the plane |
normal | The plane's normal (unit vector) |
axis | The direction along the plane that the value measures (unit vector) |
half_extent | Half the size of the draggable area, in metres |
units_per_meter | Value units per metre |
Tapping the world#
point sends an action when the player taps or clicks the scene:
point:
action: select
plane:
origin: [0, 0, 0]
normal: [0, 1, 0]
axis: [1, 0, 0]
half_extent: [50, 50]
units_per_meter: 1000
The payload is the position on the plane as "U,V" text.
Labels#
labels:
- id: position
fallback: "x = 0.0 m"
The player shows fallback until your actor sets the text. Set label text by returning hud = ?[{ id; text }] from moxzi_advance, moxzi_input or moxzi_snapshot. The list replaces all label text: labels you leave out show their fallback again. Return hud = null to keep the current text.
| Limit | Value |
|---|---|
| Labels | 64 |
| Text per label | 4096 bytes |
| Total text | 16384 bytes |
Keys#
| Keys you can use |
|---|
arrow_up, arrow_down, arrow_left, arrow_right |
w, a, s, d |
space, tab |
r, v, m |
Any other key is rejected when the game is played, with invalid UI YAML: … unknown variant.
Rules for handling input#
- Check that
command.at_tickis the current tick andcommand.sequenceis one more than the last. Commands arrive between ticks, in order. command.playeridentifies a player in multiplayer setups. It's game data, not authentication;calleris the player process.- Return
accepted = falsefor actions or payloads you don't recognise. Don't change state in that case. - While the game is suspended (see
moxzi_lifecycle), the player sends no input.
Limitations#
| Limitation | What to do |
|---|---|
| Only the keys above can be bound | Use buttons and axes for other inputs |