Skip to content
Work in progress. These docs describe Spawnite at launch, and some parts are still being built.

Controls

Five controls take a value from a player: <Slider>, <NumberField>, <TextField>, <Select> and <Toggle>. Each draws the control alone, on the menu tokens, so a game that sets its menu’s colours sets its controls with them.

Their props are in Slider, NumberField, TextField, Select and Toggle.

Every control works the same way:

  • label is its accessible name. The control draws no label of its own, as Unity’s Slider and Godot’s HSlider draw none: the layout around it does, with a Text.
  • value and onChange are the caller’s. The control holds no state, so the value it shows is the one the game holds. A NumberField is the one exception: it shows what the player is typing until Enter or the field loses focus.
  • disabled dims it, and it takes no change.
  • className goes on the control, for its width in a row.
  • Any other attribute of the element passes through, as name, autoComplete, maxLength or aria-describedby do, and a ref on a TextField reaches its input. The control keeps the ones it sets: value, onChange and the label.
import { useState } from "react";
import {
Hud,
NumberField,
Panel,
Select,
Slider,
Slot,
Text,
TextField,
Toggle,
} from "@spawnite/engine";
export function CharacterSetup() {
const [name, setName] = useState("");
const [weapon, setWeapon] = useState("Sword");
const [hue, setHue] = useState(200);
const [gold, setGold] = useState(100);
const [helmet, setHelmet] = useState(true);
return (
<Hud>
<Panel slot={Slot.Center} freeCursor>
<Text as="label" className="flex items-center gap-3">
Name
<TextField
label="Name"
value={name}
placeholder="Character"
onChange={setName}
/>
</Text>
<Text as="label" className="flex items-center gap-3">
Weapon
<Select
label="Weapon"
options={["Sword", "Bow", "Staff"]}
value={weapon}
onChange={setWeapon}
/>
</Text>
<Text as="label" className="flex items-center gap-3">
Hair
<Slider
label="Hair"
value={hue}
min={0}
max={360}
onChange={setHue}
className="w-48"
/>
</Text>
<Text as="label" className="flex items-center gap-3">
Gold
<NumberField
label="Gold"
value={gold}
min={0}
onChange={setGold}
/>
</Text>
<Text as="label" className="flex items-center gap-3">
Helmet
<Toggle
label="Helmet"
value={helmet}
onChange={setHelmet}
/>
</Text>
</Panel>
</Hud>
);
}

A Panel that holds a control sets freeCursor, so a player under a camera that captures the cursor can reach it.

<Slider label value min max onChange> picks a number along a track, filled in the accent up to the value. step is 1 unless set. onChange runs at each value the slider moves to; onCommit runs once where a drag or a key press ends, for a change worth making once, such as a save. valueText words the value for a screen reader, such as “50 percent”. style takes what comes from data: --slider-track paints the track, as a colour ramp does.

<NumberField label value onChange> takes a typed number. It calls onChange when the player presses Enter or leaves the field, never at each key, because “0.” on the way to “0.5” is no number. Text that is not a number keeps the value. min and max hold what it reports between them, and display words the value the field shows, such as two decimals.

<TextField label value onChange> takes a line of text and calls onChange at each key. onCommit runs on Enter and when the field loses focus. placeholder is what the empty field shows.

A key typed in a NumberField or a TextField stops at the field, so a game’s own key listener never takes a letter as a move or a digit as a card pick. Escape and Tab pass through, for a dialog that closes on Escape or traps the focus.

<Select label options value onChange> picks one choice from a list that opens. It is the browser’s own, so a phone opens its wheel for it. An option is a string, or { value, label } where the words it shows differ from the value it reports. placeholder is what it shows while value is empty, and a player cannot pick it.

<Toggle label value onChange> is an on-and-off switch, filled in the accent while on. A press calls onChange with the other state. For a choice among a few buttons, use a Button with pressed.

A setting the engine’s Settings panel should hold is a row on the settings page, which lays out its own label, description and cost. These controls are for a game’s own windows.