# The throttle is a TARGET-SPEED selector โ€” measured against the definition (2026-08-13) **Status: โœ… for the shape of the law, ๐ŸŸก for the unit scale.** The unit definition gives `MinimumVelocity 100`, `CruisingVelocity 350`, `MaximumVelocity 1200`, `Acceleration 600` and `Deceleration 500` for `UN_f001_TCAF_DeltaSaber_T_Player` ([values](captures/unit-runtime-fields.csv)), but not **how** the game applies them. This measures it. Method โ€” [`tools/re-capture/speed_law.py`](../../tools/re-capture/speed_law.py): lock onto the player entity once, then sample its own position triple in guest RAM while holding each throttle input in turn (8 s per phase, 20 Hz). Speed is differentiated over **1-second windows**, never per sample. ## Result | phase | measured speed (1 s windows) | settles to | definition field | |---|---|---|---| | no throttle | 367 403 471 365 463 463 365 | **~420** | `CruisingVelocity` 350 | | `RT` held | 1041 1376 1551 1379 1596 1510 1620 | **~1 530** | `MaximumVelocity` 1200 | | release | 1314 672 432 452 432 450 408 | back to **~440** | โ€” | | `LT` held | 203 121 135 121 115 146 122 | **~125** | `MinimumVelocity` 100 | | release | 369 451 427 425 445 390 465 | back to **~430** | โ€” | So the throttle **selects a target speed** โ€” minimum / cruise / maximum โ€” and the craft converges to it; releasing either trigger returns it to cruise. It is not a force model with the throttle adding thrust, which is what a reimplementation would most likely have assumed from `Acceleration`/`Deceleration` alone. Those two fields govern the **convergence rate**: the release phase falls ~1 314 โ†’ ~432 in about two seconds (~440 units/sยฒ, against `Deceleration` 500) and the `RT` phase climbs ~420 โ†’ ~1 550 in two to three seconds (~470โ€“560 units/sยฒ, against `Acceleration` 600). ## ๐ŸŸก The unit scale Measured world-space speeds run **โ‰ˆ1.2โ€“1.3ร— the definition numbers** in all three regimes (cruise 1.21, maximum 1.28, minimum 1.32). The HUD, meanwhile, reads **350** at cruise โ€” the definition value exactly. So the definition's velocity unit is the HUD's, and entity world coordinates are a constant multiple of it, close to **1.25**. The spread across regimes is larger than the constant itself is precise, because the craft is manoeuvring under fire while sampled (straight-line displacement per window under-reads a curving path), so this is recorded as a measured range rather than a pinned constant. ## Traps * **`RT`/`LT` are analogue triggers**, so `vgamepad trig RT 1.0` holds the throttle; the button verb `hold RT` is a **silent no-op**. The first run of this probe measured the drift of a craft nobody was flying. * **Do not differentiate per sample.** The guest updates the position slower than 20 Hz, so per-sample differences alternate between 0 and a double step โ€” `0, 1519, 1985, 0, 2681โ€ฆ` for a craft flying smoothly. * **Bind late, measure fast.** The player entity is not in the typed-entity scan for the first ~15 s of a mission, and the craft dies within a few minutes if nobody is flying it โ€” one earlier attempt ended at `GAME OVER` mid-probe. Raw samples: [`captures/speed-law-throttle-phases.csv`](captures/speed-law-throttle-phases.csv). --- # Turn rates: `AV_*` are rate caps, and `_Min`/`_Max` mean *at minimum/maximum speed* `tools/re-capture/turn_law.py` pins the speed regime with a throttle, holds a stick axis, and differentiates the craft's **own forward vector** over 1-second windows. **Control mapping, measured** โ€” `LX` is **roll** (the forward vector barely moves under it: 3โ€“5 ยฐ/s residual), `LY` is **pitch** (`vgamepad` documents `LY: -1 = up`, so `+1` is nose down = the `PitchMinus` family), and the **right stick does not steer at all** (0 ยฐ/s). | phase | measured (1 s windows) | definition | |---|---|---| | slow + nose down | 85 ยท 96 ยท 82 โ†’ **~87** | `AV_PitchMinus_Min` **75** | | fast + nose down | 55 ยท 45 ยท 63 โ†’ **~54** | `AV_PitchMinus_Max` **40** | | slow + nose up | 181 ยท 164 ยท 181 โ†’ **~175** | `AV_PitchPlus_Min` **150** | | fast + nose up | 103 ยท 130 ยท 175 โ†’ **~136** | `AV_PitchPlus_Max` **70** | Two claims of the field names are confirmed: * **Agility falls with speed** โ€” every rate drops when the throttle goes from `LT` to `RT`, so `_Min`/`_Max` are *at minimum / maximum speed*, not floor/ceiling of the rate. * **Pitching up is about twice as fast as pitching down**, exactly as the pair 150/75 (slow) and 70/40 (fast) says. ## The ~1.2ร— factor is a TIME BASE, not a unit scale The speed law measured 1.21 / 1.28 / 1.32 ร— its definition values; the pitch rates measure 1.16 / 1.35 / 1.17 / 1.94 ร— theirs. A **unit scale** would have to differ between metres-per-second and degrees-per-second โ€” it cannot explain both. A **time base** does: if the guest's simulated second is shorter than the wall-clock second this probe measures against, every rate reads high by the same factor. So the definition numbers are self-consistent and a reimplementation should take them at face value; these measurements confirm the **shape** of the law (which field governs what, and how the regimes switch), not a scale correction. ๐ŸŸก **No yaw input was found.** `AV_Yaw_{Min,Max}` (45 / 25 ยฐ/s) exists, but neither stick yaws the craft. With `MaximumBank_Normal` (60) and roll on `LX`, a **bank-to-turn** model is the obvious reading โ€” sustained turns come from rolling and pitching โ€” but the yaw fields may equally belong to the AI or to an input this probe has not driven. Raw samples: [`captures/turn-law-pitch-phases.csv`](captures/turn-law-pitch-phases.csv). --- # The afterburner is not on the obvious buttons โ€” a bounded negative The definition describes the burner without naming its input: `AB_ConsumeShield_Begin` **50**, `AB_ConsumeShield` **10**, and a set of `AB_AV_*` turn caps far below the normal ones (roll 40 vs 125โ€“200 ยฐ/s, pitch-up 30 vs 70โ€“150). Notably there is **no `AB_*Velocity`**, so the burner may not raise the speed target at all. Two independent probes, both negative for `A`, `B`, `X`, `LB` (and `LS`/`RS` on the first): * [`tools/re-capture/ab_probe.py`](../../tools/re-capture/ab_probe.py) โ€” hold `RT` for a max-speed baseline, then hold each candidate: speed stayed inside the baseline's own noise band (1 200โ€“1 580 units/s) for every one. * [`tools/re-capture/ab_state_probe.py`](../../tools/re-capture/ab_state_probe.py) โ€” sample a window of the player object while each candidate is held and report any float that falls during the hold: **nothing fell**. * And the cheapest oracle of the three, needing no offsets at all: **count the green pixels of the HUD's SHIELD bar** before and after each hold, on a freshly spawned craft with a full shield. `AB_ConsumeShield_Begin 50` should take a visible bite; the bar read **156, 156, 156, 157, 157** across baseline and all four buttons. So the burner is **not a simple hold on `A`/`B`/`X`/`LB`/`LS`/`RS`**. What remains: a chord (something plus `RT`), an input this pad cannot reach, a craft variant that has it, or fields that belong to the AI rather than the player. Worth knowing before anyone re-probes the obvious buttons. (`RB` is the nose gun, `Y` the missile mount and the d-pad the tactical map โ€” see [flight controls](flight-controls-runtime.md) โ€” so those were not held here.)