⚔️ Joust · Admin & Dev Reference
Running a round
- Start / reset a unit: in the OUT state, hold the button ~1.2s to begin a fresh round (5s grace while it settles).
- Grace: first 5s of a round, no eliminations (lets the sensor settle and players get set).
- Escalation (optional, off by default): the movement threshold ramps down over time so rounds can't stall, making everyone touchier as the round drags on. Toggle it in the dashboard's Advanced section.
- Multi-unit start/reset across 20+ controllers by touch is impractical: that is what the ESP-NOW round-broadcast layer (roadmap) is for.
Button gesture grammar (single button)
| Gesture | Who | Action |
| Tap ×1 | player | Status blink (safe no-op) |
| Hold 1.2s (in OUT) | player | Acknowledge, then start next round |
| Hold 1.2s (while strobing) | player | Acknowledge elimination (only after 1s of forced strobe) |
| Tap ×2, then hold 10s | admin | Mark THIS unit OUT mid-round. No LED feedback during the hold, so players can't discover it. |
Live tuning (dashboard or serial)
Open the live dashboard (the deployed React console at
joust.nyc, or run
bun dev and open localhost:3000) in desktop Chrome/Edge, click
Connect, pick the USB serial port. Watch movement, threshold, and the meter live; drag the sliders to tune. Or type these over any serial monitor at 115200:
| Cmd | Effect |
| f | Inject a synthetic strike (tests the real detector) |
| a | Arm now (skip grace) |
| r | Reset round |
| k | Acknowledge elimination |
| o | Mark this unit out |
| t | Run the built-in self-test (still safe / moving / knock / drop) |
| S2.0 | Set movement threshold to 2.0g |
| J0 | Set jerk gate (0 = off, any movement counts) |
| E1 / E0 | Enable / disable escalation |
How elimination is detected
It's a
keep-still game: a player is out when the controller's dynamic movement
hitPk ≥ threshold (default
~2g). Any real acceleration counts (a jostle, flinch, walk, or
drop), plus a free-fall branch so a drop always registers. Gravity is tracked and subtracted, so holding at any
angle is fine as long as you hold still. The
jerk gate is OFF by default; enable it only if you want to
require a sharp jolt and ignore slow pushes.
More sensitive: lower the threshold
Ignore slow pushes: raise the jerk gate
±16g sensor, 500Hz
Config defaults (game_config.h)
| Knob | Default | Meaning |
| movement threshold | 2.0 g | How much movement gets you out (main knob) |
| jerk gate | 0 (off) | Require a sharp jolt; off = any movement counts |
| escalation | off | Optional: threshold ramps down over time |
| free-fall | 0.4 g / 60 ms | A drop eliminates even before impact |
| grace | 5 s | No detection at round start |
| ack hold | 1.2 s | Hold to acknowledge / reset |
| strobe minimum | 1.0 s | Forced strobe before ack honored |
| LED brightness cap | 20/255 | Heat and battery current |
Hardware & bulk buy
Before buying 20–30 units: the current ATOM Matrix v1.1 ships a Bosch BMI270 IMU, while this
prototype has the older MPU6886. The firmware fully drives MPU6886 and cleanly shows an amber X
(never a fake hit) on a BMI270. Add BMI270 support and re-tune thresholds on one v1.1 unit first.
Recommended controller (~$23/unit):
- M5Stack ATOM Matrix v1.1 (~$15.50) — the 25-LED panel is the only indicator visible to opponents across a field.
- Atomic Battery Base 200mAh (~$5.95) for a tidy stack, or a small USB-C power bank for all-day runtime.
- Optional Grove piezo buzzer (~$1.50) for the audible "you're out" beep (ATOM has no speaker).
Waterproofing (none are IP-rated): clear silicone/TPU pouch or a small clear dome over the LED face, plus conformal coating on the board and a sealed USB port. Bench-test dry first.
Runtime: 200mAh base ≈ 2–3h; a 2000mAh USB-C bank on an armband ≈ all day.
Roadmap (deferred, not in this prototype)
- ESP-NOW swarm: decentralized, no central node; elimination events gossip node to node with a shared alive-map. Foundation is compiled behind a build flag. Enables shared game state, admin round START/RESET broadcast, and outdoor range via relay hops.
- Tournament: last-person-standing winner calc from the shared alive-map.
- Sudden-death, second-life, and time-since-last-elimination escalation (need the swarm layer).
- Phone read-out: a gateway unit could bridge the swarm to a mobile page showing live roster and stats.