Three-Stage Hold & Burst

0.65 / 1.2 / 1.9 SECONDS
Discrete ring segments illuminate while the core moves from idle through charge to press. Release creates one primary commit, then starts an automatic burst for the reached stage.
State machine
IDLE
└─ down → HOLDING
├─ travel ≥ 12 px → CANCELLED (latched)
├─ 0.65 s → STAGE 1
├─ 1.20 s → STAGE 2
├─ 1.90 s → STAGE 3
└─ up → one coreAction(chargeRatio) → optional BURSTBurst tiers
| Tier | Duration | Interval | Purpose |
|---|---|---|---|
| 1 | 1.8 s | 300 ms | Light automatic combo |
| 2 | 3.0 s | 220 ms | Mid-stage output and heat |
| 3 | 4.5 s | 160 ms | High-intensity burst |
After a stall, the scheduler emits at most one missed beat instead of replaying a backlog. Browser tab jitter or one long ESP32 frame cannot create an economy exploit.
Ownership
Canvas hold, simulator HOLD and keyboard Space/Enter use the same transaction-token model. One physical action cannot trigger both custom release and the native click generated afterwards; pendingHoldClick consumes that follow-up click.
Cancellation
- Total travel reaches 12 px.
pointercancelor lost pointer capture.- Navigation, ambient, launch, restart or factory-reset sequence.
- First wake input: the entire down–move–up transaction is consumed.
Visual/economy separation
The ring, core compression and stage label are previews. Release recomputes elapsed chargeRatio and clamps it to 0–1, preventing a dropped frame from showing stage three while logic resolves stage two.
