Files
Syplheed-Reborn/docs/re/flight-speed-law.md
Claude (auto-RE) 4dbd4f6cef re(flight): the throttle is analogue — target speed interpolates cruise -> maximum
RT is an analogue trigger, so "held" was one point on a curve. Walking it 0.00 ->
1.00 (throttle_curve.py) gives a straight ramp: 438, 626, 879, 1094, 1342 units/s.
Dividing by the ~1.2 time-base factor, the endpoints land on the definition's own
numbers (365 vs CruisingVelocity 350; 1118 vs MaximumVelocity 1200) and the midpoint
follows, so

  target speed = CruisingVelocity + RT * (MaximumVelocity - CruisingVelocity)

which refines the earlier "selects one of three targets" reading: those three are the
curve's endpoints.

It also refutes the standing afterburner hypothesis that full RT is the burner: the
curve is smooth through full deflection with no step, and the shield does not move.

The LT half is not measured yet — the entity scan needs the craft moving when it
runs, so a mission left idling drops out of it. Bind early.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NptfmpjdpNCKEez6d2xvA9
2026-08-13 16:14:47 +00:00

9.1 KiB
Raw Blame History

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), but not how the game applies them. This measures it.

Method — 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 and the craft converges to it; releasing either trigger returns it to cruise. (Refined below: the trigger is analogue, so the target is a continuous interpolation and these three are its endpoints.) 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 (~470560 units/s², against Acceleration 600).

🟡 The unit scale

Measured world-space speeds run ≈1.21.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.


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, measuredLX is roll (the forward vector barely moves under it: 35 °/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.


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 125200 °/s, pitch-up 30 vs 70150). 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 — hold RT for a max-speed baseline, then hold each candidate: speed stayed inside the baseline's own noise band (1 2001 580 units/s) for every one.
  • 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 — so those were not held here.)


The throttle is ANALOGUE: the target speed interpolates cruise → maximum

RT is an analogue trigger, so "held" was only ever one point on a curve. Walking it in five steps (tools/re-capture/throttle_curve.py, 2.5 s to converge then 5 s of sampling per step):

RT settled speed (1 s windows) mean
0.00 465 · 411 · 373 · 504 438
0.25 648 · 554 · 678 · 622 626
0.50 739 · 961 · 897 · 919 879
0.75 1028 · 1086 · 977 · 1283 1094
1.00 1359 · 1306 · 1517 · 1186 1342

A straight ramp. Dividing by the ~1.2 time-base factor established above, the endpoints land on the definition's own numbers — 438/1.2 ≈ 365 against CruisingVelocity 350, and 1342/1.2 ≈ 1118 against MaximumVelocity 1200 — and the midpoint follows: 879/1.2 ≈ 733 against the predicted 350 + 0.5·(1200350) = 775. So

target speed = CruisingVelocity + RT · (MaximumVelocity  CruisingVelocity)

with LT presumably mirroring it down to MinimumVelocity (measured only at full deflection so far: ~125 against 100).

This also refutes a live hypothesis about the afterburner. Full RT producing more than MaximumVelocity looked like it might be the burner; it is not — the curve is smooth through full deflection, with no step, and the shield does not move. Full throttle is simply full throttle.

Raw samples: captures/throttle-curve-rt.csv.

The LT half of the curve is not measured: the entity scan that locks onto the player needs the craft to be moving when it runs (it searches changing position triples), and a mission left idling long enough for the craft to slow or die drops out of the scan. Bind early, while the craft still has speed.