You are on a circular orbit. The station is on the same circular orbit, 60° ahead of you, going the same speed, and it has been exactly 60° ahead since before you woke up. You have one control: an engine that points along your velocity, forward or back.
The obvious move is wrong, and — this is the part worth building — the instrument agrees with you while you make it.
The throttle is a clock
Everything here comes out of two lines. Vis-viva,
v² = μ(2/r − 1/a)
and Kepler’s third law, T = 2π√(a³/μ). Differentiate the second: dT/T = (3/2)(da/a). Differentiate the first at fixed r, because an impulse changes
your speed where you are and not where you are:
2v dv = μ da/a² ⇒ da/a = 2 v a dv / μ
On a circular orbit a = r and v² = μ/r, so a/μ = 1/v², and the whole
thing collapses:
da/a = 2 dv/v dT/T = 3 dv/v
A burn of one percent of circular speed makes your orbit three percent
longer. Not faster. Longer. And the period is the only thing that decides
whether you arrive: after one of your laps the station has gone round T′/T of
a lap, so the gap you close per lap is
Δθ = 2π(1 − T′/T) = −6π·(Δv/v_c) radians per lap
which is −10.8° per lap for a 1% prograde burn, forever, in the direction
you did not want. The exact version — no small-angle anything, just vis-viva
rearranged — is in periodRatio:
T′/T = (2 − (1+f)²)^(−3/2), f = Δv/v_c
and it runs away from the linear one fast, because a blows up at f = √2 − 1 = 0.41421, where the period is infinite and you have left.
| Δv / v_c | T′/T closed form | T′/T measured | 1 + 3f | drift/lap | −6πf | other apsis |
|---|---|---|---|---|---|---|
| +0.005 | 1.01523 | 1.01523 | 1.01500 | −5.48° | −5.40° | 1.0203 |
| +0.010 | 1.03093 | 1.03093 | 1.03000 | −11.13° | −10.80° | 1.0410 |
| +0.020 | 1.06381 | 1.06381 | 1.06000 | −22.97° | −21.60° | 1.0842 |
| +0.050 | 1.17611 | 1.17611 | 1.15000 | −63.40° | −54.00° | 1.2284 |
| +0.100 | 1.42416 | 1.42416 | 1.30000 | −152.70° | −108.00° | 1.5316 |
| −0.010 | 0.97088 | 0.97088 | 0.97000 | +10.48° | +10.80° | 0.9610 |
| −0.050 | 0.86975 | 0.86975 | 0.85000 | +46.89° | +54.00° | 0.8223 |
| −0.100 | 0.77033 | 0.77033 | 0.70000 | +82.68° | +108.00° | 0.6807 |
| −0.200 | 0.63051 | 0.63051 | 0.40000 | +133.02° | +216.00° | 0.4706 |
“Measured” is the period recovered by integrating the orbit and bisecting on the position angle coming back round, so the second column is the algebra and the third is the solar system.
Note the last two columns diverging in opposite directions, because 1 + 3f is
an underestimate going up and an overestimate going down. That asymmetry is not
a rounding detail — it is the reason for half of the rest of this page.
The instrument, and exactly how convincing it is
Burn toward the station and the range starts falling. It does this for a real reason and the number is exact.
Both of you were on one circular orbit, so the separation was constant and
d(range)/dt was exactly zero. All the reading you get afterwards is your own
impulse. With the target θ ahead:
Δr = r(1 − cos θ, −sin θ) Δv⃗ = v(sin θ, 1 − cos θ) + Δv(0, 1)
Δr · Δv⃗ = −r·Δv·sin θ the v terms cancel, exactly
|Δr| = 2r sin(θ/2)
range rate = −Δv·sin θ / (2 sin(θ/2)) = −Δv·cos(θ/2)
The range rate reports cos(θ/2) of your burn as closing speed. Nearly all
of it for a near target; none of it only at 180°. The instrument is most
convincing exactly when the station is closest — which is exactly when you are
most tempted to chase it.
| lead | measured range rate | −Δv·cos(θ/2) | fraction of the burn | believable for (laps) |
|---|---|---|---|---|
| 10° | −0.02989 | −0.02989 | 0.9962 | 0.102 |
| 30° | −0.02898 | −0.02898 | 0.9659 | 0.094 |
| 60° | −0.02598 | −0.02598 | 0.8660 | 0.076 |
| 90° | −0.02121 | −0.02121 | 0.7071 | 0.059 |
| 120° | −0.01500 | −0.01500 | 0.5000 | 0.040 |
| 150° | −0.00776 | −0.00776 | 0.2588 | 0.021 |
| 179° | −0.00026 | −0.00026 | 0.0087 | 0.001 |
The last column is the honest one. A tenth of a lap. The drift it bought you is
−6π·Δv/v_c per lap regardless of θ, so the ratio of what the instrument
says to what the manoeuvre costs is fixed, and it is terrible.
The same 60° lead, the same 0.03 of Δv, twice, differing only in sign:
| burn | range rate at t=0 | flips at | closest range | at | lead after 1 lap | after 2 | after 3 |
|---|---|---|---|---|---|---|---|
| prograde +0.03 (toward it) | −0.0260 | 0.076 laps | 0.9929 | 0.076 | 95.6° | 131.2° | 166.7° |
| retrograde −0.03 (away) | +0.0260 | 0.783 laps | 0.0031 | 1.788 | 30.3° | 0.6° | −29.1° |
The burn that reads as closing never gets within 0.993 of a station it started 1.000 from — it moves the range by seven parts in a thousand and then spends three laps putting the station on the far side of the planet. The burn that reads as opening passes within 0.003 without a second impulse. One number in that table is what the HUD shows; the rest is what happened.
So “to catch up, slow down” — and where it expires
That is the folklore, it is right, and like every good folklore rule it is right over a band and nobody tells you where the band ends. There are two edges, and they are at different places.
Edge one: the ground. The retrograde burn that shortens your period lowers
the other side of the orbit. Burning at radius r makes that point your
apoapsis, so
r_p = 2a′ − r = r(2(T′/T)^(2/3) − 1)
and to close a lead θ in n revolutions you need T′/T = 1 − θ/(2πn).
Setting r_p ≥ R_planet gives a closed form for how impatient you are allowed
to be:
θ_max = 2πn·(1 − ((1 + R/r)/2)^(3/2))
With the planet at half the station’s orbital radius, that is 126.17° in one revolution, and the demo’s measured ceiling — bisecting on the periapsis actually dipping under the surface — agrees to two decimals:
| revolutions n | ceiling, closed form | measured | Δv there | periapsis there |
|---|---|---|---|---|
| 1 | 126.17° | 126.17° | 0.3664 | 0.5005 |
| 2 | 252.35° | 252.35° | 0.3664 | 0.5005 |
| 3 | 378.5° — past a lap | every lead | 0.3386 | 0.5268 |
| 4 | 504.7° — past a lap | every lead | 0.2236 | 0.6513 |
Past 126°, in one lap, there is no such manoeuvre. Not an expensive one. None.
Edge two, which arrives first: the price. The map from Δv to period ratio
is violently asymmetric, and the reason is that a is unbounded above and
bounded below. You can make your period infinite for Δv = +0.414 v_c; you
would need Δv = −1.000 v_c — your entire orbital velocity — to make it zero.
So the same impulse always moves the clock further forward than back: +0.1
buys T′/T = 1.424, −0.1 buys 0.770, and in log terms that is 1.36× more
clock for the same fuel.
Which means going the long way round — raising your orbit and letting the station lap you — is often cheaper than chasing it:
| lead | Δv chasing | Δv going high | ratio | cheaper |
|---|---|---|---|---|
| 30° | 0.0606 | 0.3254 | 5.37 | chase |
| 60° | 0.1337 | 0.3086 | 2.31 | chase |
| 90° | 0.2240 | 0.2903 | 1.30 | chase |
| 105.6° | 0.2801 | 0.2802 | 1.00 | — |
| 120° | 0.3391 | 0.2703 | 0.80 | go high |
| 150° | into the planet (r_p 0.396) | 0.2484 | — | go high |
| 180° | into the planet (r_p 0.260) | 0.2243 | — | go high |
| 300° | no such orbit | 0.0954 | — | go high |
105.62°, not 180°. Twenty degrees before the ground rules chasing out, the price already has. Nobody chose that number either.
And it is not a constant — it is a fact about being in a hurry. Give yourself more revolutions and the crossover walks outward toward the halfway point you expected in the first place:
| revolutions n | crossover | Δv either way | wait chasing | wait high |
|---|---|---|---|---|
| 1 | 105.62° | 0.2801 | 0.71 laps | 1.71 laps |
| 2 | 137.55° | 0.1581 | 1.62 | 2.62 |
| 3 | 150.80° | 0.1084 | 2.58 | 3.58 |
| 4 | 157.85° | 0.0822 | 3.56 | 4.56 |
Patience is the fuel tank
The other thing the closed form says out loud. To close a 90° lead:
| revolutions n | T′/T | Δv each burn | Δv total | periapsis | time (target laps) |
|---|---|---|---|---|---|
| 1 | 0.75000 | −0.1120 | 0.2240 | 0.6510 | 0.75 |
| 2 | 0.87500 | −0.0477 | 0.0954 | 0.8297 | 1.75 |
| 3 | 0.91667 | −0.0303 | 0.0606 | 0.8873 | 2.75 |
| 4 | 0.93750 | −0.0222 | 0.0445 | 0.9158 | 3.75 |
| 8 | 0.96875 | −0.0108 | 0.0215 | 0.9581 | 7.75 |
| 12 | 0.97917 | −0.0071 | 0.0142 | 0.9721 | 11.75 |
Sixteen times the fuel to arrive eleven laps sooner. That is the only knob this mechanic has, and it is why the demo’s solver is capped at six revolutions: with unlimited patience the answer to every scenario is “wait longer” and the trade disappears.
Two burns, and the second one is not optional
The whole manoeuvre is: burn once to put your period off by exactly the
fraction of a lap you owe, coast n of them, and burn the mirror image at the
same point in space. Both burns happen in the same place — that is why the cost
is exactly twice one of them, and why the demo draws one ring and labels it
“and again in 6 laps.”
Computed up front and flown open-loop through the integrator, with no correction of any kind:
| lead | direction | n | Δv each | Δv total | range at arrival | relative speed |
|---|---|---|---|---|---|---|
| 30° | down | 8 | −0.0035 | 0.0070 | 2.00e−12 | 2.02e−12 |
| 75° | down | 8 | −0.0089 | 0.0178 | 1.89e−13 | 1.57e−13 |
| 90° | down | 8 | −0.0108 | 0.0215 | 1.23e−12 | 1.20e−12 |
| 150° | down | 8 | −0.0183 | 0.0366 | 4.08e−12 | 4.16e−12 |
| 210° | up | 8 | +0.0165 | 0.0330 | 3.24e−12 | 3.22e−12 |
| 300° | up | 8 | +0.0068 | 0.0136 | 7.88e−13 | 7.65e−13 |
Twelve decimal places, which is the integrator’s noise floor and not the manoeuvre’s. The plan is exact; there is nothing to steer.
The second burn is the one people skip, and the first version of this piece let them. The docking gate was a relative speed of 0.02, and a patient phasing orbit arrives with its relative speed equal to the impulse that set it up — 0.0095 for a six-lap plan — so the craft sailed through the gate still on its transfer ellipse and the demo called it a dock. Correct-looking, and it deleted half the idea. The gate is 0.006 now, and arriving in the right place at the right time with the wrong velocity is the failure it should always have been.
Four beliefs about the throttle
The game layer is thin on purpose: get inside 0.02 of the station at under
0.006 of relative speed, on a Δv budget. Nothing in it knows any of the above.
So scripts/measure.mjs flies 17 leads, 20° to 340°, under four autopilots
that share one control loop — brake when close, thrust while the gap is open,
null the drift when it isn’t — and differ in one line: which way to point.
| pilot | docked | crashes | mean closest approach | mean Δv spent | mean laps |
|---|---|---|---|---|---|
| “burn toward it” | 0.0% | 17 | 1.104 | 0.357 | 4.8 |
| “follow the range rate” | 0.0% | 0 | 1.284 | 0.450 | 8.7 |
| “burn away from it” | 0.0% | 8 | 0.099 | 0.408 | 4.9 |
| “the phasing solution” | 100.0% | 0 | 0.001 | 0.021 | 8.0 |
A twentieth of the fuel and it is the only one that ever arrives.
Three things in that table are worth more than the headline. “Burn toward it” crashes every single time, which looks like a strawman and isn’t: it chases a gap that runs away from it, the gap wraps past 180°, the pilot dutifully reverses, and now it is dumping retrograde into a lower and lower periapsis. The failure mode of the wrong sign is not “arrives late”, it is “flies into the planet while doing exactly what it meant to.”
“Follow the range rate” never crashes and never gets anywhere, burning its entire budget over 8.7 laps. It is the most defensible of the three — it is optimising a real measured quantity, in the direction that quantity says to go — and it is the one that spends everything for nothing.
And “burn away from it” gets the sign right and still docks 0%, at a mean closest approach of 0.099 — five times closer than the others and not once inside 0.02. Knowing which way to point buys you the neighbourhood. It does not buy you the arrival, because closing the phase gap and matching the orbit are two manoeuvres, and folklore only ever contained the first.
What is physics here and what isn’t
- Derived:
dT/T = 3Δv/v, the exactT′/T, the drift per lap, the escape threshold at 0.41421, the range rate−Δv·cos(θ/2), the phasing solution and its cost, the 126.17° ceiling, the 105.62° crossover and its walk outward. Every one of them is checked against the integrator bymeasure.mjs, and the three the demo shows on screen are checked again against the running demo byscreenshot-demo.mjs. - Chosen, not derived: μ = 1 and the station’s orbit at r = 1 (so every Δv on screen is already a fraction of circular speed and every duration is already a fraction of a lap); the planet at r = 0.5, which is what sets the ceiling at 126.17° rather than anywhere else; the gates; the budget.
- Not modelled, and it doesn’t change the lesson: drag, oblateness, a third body, and finite burn duration — a real burn lasting minutes smears the apsis it is applied at, which costs a little efficiency and no understanding.
- Not modelled, and it would change the lesson: plane change. Everything
here is coplanar. An out-of-plane rendezvous adds a cost with nothing to do
with phasing — you pay
2v·sin(Δi/2), which for a 1° inclination error is already 0.017 of circular speed, comparable to the entire phasing budget of most scenarios here — and it is paid at a node whether you are early or late. Real mission planning is mostly about that, and this piece is entirely about the other thing. - A game, not physics: the Δv budget is a scalar rather than a propellant mass and a rocket equation; the docking gate is two numbers instead of an approach corridor and an attitude; and time warp exists because a six-lap phasing orbit is forty seconds of correct, uneventful coasting.
Reuse
src/rendezvous.mjs is framework-free with no canvas in it.
elements(state)→a, e, ecc, h, T, rp, ra, argfor a 2D two-body orbit;circular(theta, r),visViva,period,axisForPeriod.propagate(state, dt)— RK4, default substep 1e-3, which holds specific energy to 9.0e−14 over fifty circular laps and 5.6e−13 at e = 0.30. Tighter than anything the notes claim, on purpose.burn(state, dv)for the impulse.periodRatio(f)/burnForPeriodRatio(k)/driftPerOrbit(f)/turningRadius(f)— the exchange rate and its inverse.initialRangeRate(dv, theta)— the lie, in closed form.phasingSolution(theta, n, dir)/bestPhasing(theta, maxN)/crossoverPhase(n)/maxChaseablePhase(n)— the plan, the cheapest plan, and the two edges of the band it works in.makeWorld/step/applyBurn/relative/driftOf/canStillDock— the game layer. Nothing is on rails: both bodies are integrated.flyScenario(pilot, opts)andPILOT_NAMES— the four beliefs, for scoring.
The demo is demo/index.html with its own copy of the module (ADR-0002): ↑
and ↓ (or W/S, or holding the on-screen buttons, or tapping the upper and
lower half of the orbit view) to burn, space for warp, H for the closed-form
solution, P to swap the phase tape for the cost curve, N for the next setup,
R to reset. It sizes itself to its viewport, so the site’s full-screen button
just works.
The phase tape is the part that earns its space. It plots lead angle against time, with the station as the zero line and the dashed projection showing where the current orbit is taking you. The trace wobbles — angular velocity varies around an ellipse — and the wobble is precisely why the instantaneous range rate is worthless: the straight dashed line under it is the per-lap drift, which is the only thing that decides anything.
node scripts/measure.mjs regenerates every table above. node scripts/screenshot-demo.mjs regenerates the thumb and media and is the smoke
test: 20 assertions, any page error fails the run, and it checks the live demo’s
own readouts against the closed forms — that a +0.03 burn at a 60° lead reports
exactly −0.025981 as closing speed, that the same burn has moved the lead to
95.58° one lap later, and that the plan the demo offers, flown open-loop through
the demo, docks for the Δv the algebra said.








