Joystick
A two-axis analog input. Drag the handle to send X and Y continuously; release to snap back to center (Sticky) or stay where you left it (Free). Perfect for robot driving, pan/tilt, drone-style controls.
[image] Joystick on canvas, idle (centered), base ring and indicator arc visible
What it does
Joystick reports a pair of values in -100..+100 on the X and Y axes while you drag the handle. In Sticky mode, the handle springs back to center on release. In Free mode, it stays wherever you left it.
Visual cues are tunable: a base ring, a handle ring, an indicator arc that points in the drag direction, and a soft shadow under the handle.
When to use it
- Tank-drive robot — Differential drive:
left = y + x,right = y - x. Stop motors inWHEN_RELEASED. - Pan / tilt camera — Map X to a horizontal servo, Y to a vertical servo.
Properties
The Inspector opens as a bottom sheet with a Widget ID field at the top, then these sections in order.
Widget ID
| Property | Type | What it controls |
|---|---|---|
| Widget ID | text | Identifier used by your sketch (IJoystick("…")). |
1. Essential
| Property | Type | Default | What it controls |
|---|---|---|---|
| Enabled | toggle | on | Allow user interaction. |
| Target Devices | multi-select dropdown | — | Pick which device(s) this widget communicates with. Server Mode only. |
| Mode | Sticky / Free | Sticky | Whether the handle returns to center on release. |
| Animate return | toggle | on | Smooth snap-back animation. |
2. Header
| Property | Type | Default | What it controls |
|---|---|---|---|
| Show header | toggle | off | Display a text label above the joystick. |
| Header text | text | empty (placeholder Label) | Header text. Only when Show header is on. |
| Alignment | Left / Center / Right | Center | Header text position. Only when Show header is on. |
3. Appearance
| Property | Type | Default | What it controls |
|---|---|---|---|
| Show indicator | toggle | on | Direction arc on the base. |
| Show base ring | toggle | on | Outer ring around the base. |
| Show handle ring | toggle | on | Ring around the handle. |
| Show shadow | toggle | on | Shadow under the handle. |
| Press effect | toggle | on | Subtle scale and glow when held. |
4. Colors · Base
| Property | Type | What it controls |
|---|---|---|
| Background | color | Base circle fill. |
| Ring | color | Outer ring color. |
| Shadow | color | Shadow color under the handle. |
5. Colors · Handle (Idle)
| Property | Type | What it controls |
|---|---|---|
| Fill | color | Handle fill at rest. |
| Ring | color | Handle ring at rest. |
| Indicator | color | Direction arc at rest. |
6. Colors · Handle (Active)
| Property | Type | What it controls |
|---|---|---|
| Fill | color | Handle fill while held. |
| Ring | color | Handle ring while held. |
| Indicator | color | Direction arc while held. |
States and behavior
[image] Two states side by side: idle (centered) and active (handle pulled to upper-right)
Two states: Idle (centered, base colors) and Active (handle moved, Active color set, indicator arc points in the drag direction).
The X and Y values your sketch receives are normalized to -100..+100. Center is (0, 0). In Sticky mode, releasing the handle snaps it back to center.
In code
The joystick mirrors the user’s drag on the dashboard. To react to it in your sketch:
IJoystick("drive") {
WHEN_MOVED(x, y) {
int left = constrain(y + x, -100, 100);
int right = constrain(y - x, -100, 100);
setMotors(left, right);
}
};
That’s the minimum — one event block, X and Y arrive live during the drag. Use WHEN_RELEASED if you want a « stop » trigger when the user lifts off. See InstantIoT Library / Receive Command from App for details.
Working Arduino code example
A complete sketch you can flash. The Widget ID drive matches the one you set on your Joystick in the app.
[gif] Joystick on the dashboard driving a tank-style robot — diagonal drag mixes turn and forward
Direct Mode
Your phone connects directly to the ESP32’s SoftAP — no router, no server. Best for prototyping and standalone setups.
#include <InstantIoTWiFiAP.hpp>
const char* AP_SSID = "InstantIoT-Greenhouse";
const char* AP_PASS = "12345678";
InstantIoTWiFiAP instant(AP_SSID, AP_PASS);
void setMotors(int left, int right) {
Serial.print("L="); Serial.print(left);
Serial.print(" R="); Serial.println(right);
}
void stopAll() {
setMotors(0, 0);
}
IJoystick("drive") {
WHEN_MOVED(x, y) {
int left = constrain(y + x, -100, 100);
int right = constrain(y - x, -100, 100);
setMotors(left, right);
}
WHEN_RELEASED {
stopAll();
}
};
void setup() {
Serial.begin(115200);
instant.begin();
}
void loop() {
instant.loop();
}
Server Mode
The ESP32 connects to your self-hosted InstantIoT Server over WiFi. Multiple devices, persistent state, history.
#include <InstantIoTWiFiServer.hpp>
const char* WIFI_SSID = "YOUR_WIFI_SSID";
const char* WIFI_PASS = "YOUR_WIFI_PASSWORD";
const char* SERVER_IP = "192.168.1.42";
const uint16_t SERVER_PORT = 9001;
const char* DEVICE_TOKEN = "YOUR_DEVICE_TOKEN";
InstantIoTWiFiServer instant(SERVER_IP, SERVER_PORT, DEVICE_TOKEN);
void setMotors(int left, int right) {
Serial.print("L="); Serial.print(left);
Serial.print(" R="); Serial.println(right);
}
void stopAll() {
setMotors(0, 0);
}
IJoystick("drive") {
WHEN_MOVED(x, y) {
int left = constrain(y + x, -100, 100);
int right = constrain(y - x, -100, 100);
setMotors(left, right);
}
WHEN_RELEASED {
stopAll();
}
};
void setup() {
Serial.begin(115200);
instant.begin(WIFI_SSID, WIFI_PASS);
}
void loop() {
instant.loop();
}
The widget code is identical — only the include and constructor change.
Notes
- In Free mode,
WHEN_RELEASEDstill fires, but the handle keeps its position visually. Your sketch decides whether to stop motion or hold the last command. - For discrete directions (no analog mix), use Direction Pad instead.
Next
→ Direction Pad — Discrete directional input.
→ Horizontal / Vertical Slider — Single-axis continuous input.