> ## Documentation Index
> Fetch the complete documentation index at: https://docs.hyperwisor.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Joystick

> A two-axis controller that emits X/Y — settings and how to send its values to a device.

<Info>
  **Category:** Controls · **Sends commands:** via scripts · **Emits a value:** yes (X/Y, to scripts)
</Info>

## Mental model

A **Joystick is a game controller thumbstick.** It emits a live **X/Y** position as
the user drags it. Perfect for driving movement — a rover, a pan/tilt camera, a
drone.

## When to use it

* Directional / two-axis control (drive, steer, pan-tilt)
* Any input where two values move together

## Settings

### General

* **Widget Title / ID**
* **Min value** · **Max value** — the output range per axis
* **Dead zone** — ignore tiny movements near center
* **Sensitivity** — output scaling
* **Joystick size** · **custom size**

### Style

Base color, handle color, container, label.

### Triggers

| Event                     | Fires when                                                |
| ------------------------- | --------------------------------------------------------- |
| `change`                  | The stick moves (carries `{ x, y }`)                      |
| `touchstart` / `touchend` | Touch begins / ends                                       |
| *(common)*                | `load`, `ready`, `destroy`, `update`, `visible`, `hidden` |

## Sending the X/Y to a device

<Note>
  A Joystick does **not** auto-inject its X/Y into a trigger's command params (only
  [Slider, Color Picker, and Form](/dashboard/triggers#widgets-that-emit-a-value-auto-injected-params)
  do). Use the **[Script API](/script/overview)** to forward the position.
</Note>

```js theme={null}
// Stream joystick position to the device
widget.on('driveStick', 'change', (pos) => {
  ws.send(context.deviceId, { command: 'drive', x: pos.x, y: pos.y });
});
```

**Firmware** (Arduino) — read x/y from the payload:

```cpp theme={null}
device.setUserCommandHandler([](JsonObject &msg) {
  JsonObject p = device.findParams(msg, "drive", "");   // or your command/action
  if (!p.isNull()) {
    int x = p["x"] | 0, y = p["y"] | 0;
    driveMotors(x, y);
  }
});
```

<Tip>
  Throttle high-frequency `change` events in your script (e.g. send at most every
  100–200 ms) so you don't flood the device.
</Tip>

<CardGroup cols={2}>
  <Card title="Script API" icon="code" href="/script/examples#throttle-rapid-slider-changes">
    Throttling and sending patterns.
  </Card>

  <Card title="Slider" icon="sliders" href="/dashboard/widgets/slider">
    For a single-axis value.
  </Card>
</CardGroup>
