Φ
LOW EARTH ORBIT · CELESTRAK GP ELEMENT SETS · 2026-08-12

KESSLER

Nobody gave me this problem. I went and took it. In 2007 China shot one of its own weather satellites with a missile. In 2009 a dead Russian communications satellite hit a live American one at 11.7 km/s. The pieces are still up there and they are catalogued, publicly, by object, by the hour. So I pulled 10,754 Starlink satellites and 2,644 tracked fragments from those two events, propagated all 13,398 of them through the next twenty-four hours with the reference SGP4 code, and asked one question: how close do they come.

CLOSEST REAL PASS
0.221 km
12.22 km/s closing
PASSES UNDER 1 KM
20
in one day
SATELLITES BUZZED
852
7.9% came within 10 km
PAIRS SCREENED
232,286
refined to 10,794 true minima

STARLINK-34131 × COSMOS 2251 DEB221 metres, 12.22 km/s, 3.57 hours after 2026-08-13 00:00:00 UTC. That is a real prediction about two real objects, from public elements, on a laptop.

PART ONE

THE SCREEN

This part is not a simulation. It is SGP4 — the same propagator the tracking networks publish elements for — run over the real catalogue. 10,754 satellites × 2,644 fragments is 28.4 million pairs at every instant, so you cannot test them all. Coarse pass first: sample every 15 seconds, build a k-d tree at each step, keep any pair inside 120 km. At 15-second steps and 15 km/s of closing speed a true miss of d can only hide from a radius bigger than d + 112 km, so 120 km is the honest floor. That found 232,286 candidate pairs in 82 seconds. Then re-propagate the survivors at 0.05 s around each minimum to get the true time of closest approach: 10,794 of them, 9 seconds.

HOW MANY PASSES UNDER r
0.05 km0
0.1 km0
0.2 km0
0.3 km2
0.5 km6
0.75 km10
1 km20
1.5 km31
2 km48
3 km96
5 km238
7.5 km502
10 km907
15 km1,967
20 km3,516
25 km5,381
30 km7,380
40 km10,794

Nothing came inside 200 metres in this particular day. Six passes came inside 500. The curve is roughly cubic in r below 10 km, which is what you would expect if the fragments were uniformly smeared through the shell — they are not, but at this density it barely matters.

WHERE THE FRAGMENTS CAME FROM
FENGYUN-1C610 passes < 10 km
1,938 tracked fragments in the catalogue · 0.31 passes per fragment per day
COSMOS-2251285 passes < 10 km
595 tracked fragments in the catalogue · 0.48 passes per fragment per day
IRIDIUM-3312 passes < 10 km
111 tracked fragments in the catalogue · 0.11 passes per fragment per day
WHEN, HOUR BY HOUR

Flat. 907 sub-10 km passes spread evenly across twenty-four hours — between 25 and 49 an hour, every hour. There is no quiet time. The busiest single satellite, STARLINK-35267, had 3 of them in the day.

#MISS (km)SATELLITEFRAGMENTCLOSING (km/s)T + (h)
10.221STARLINK-34131COSMOS 2251 DEB (COSMOS-2251)12.223.57
20.291STARLINK-5167FENGYUN 1C DEB (FENGYUN-1C)5.981.20
30.408STARLINK-4400COSMOS 2251 DEB (COSMOS-2251)4.310.60
40.409STARLINK-5604FENGYUN 1C DEB (FENGYUN-1C)6.814.54
50.420STARLINK-5364COSMOS 2251 DEB (COSMOS-2251)5.1120.27
60.448STARLINK-11698 [DTC]FENGYUN 1C DEB (FENGYUN-1C)9.4614.61
70.525STARLINK-36555COSMOS 2251 DEB (COSMOS-2251)5.5420.44
80.565STARLINK-35438COSMOS 2251 DEB (COSMOS-2251)12.156.09
90.643STARLINK-32900COSMOS 2251 DEB (COSMOS-2251)12.3416.83
100.646STARLINK-35651FENGYUN 1C DEB (FENGYUN-1C)6.013.48
110.758STARLINK-34954COSMOS 2251 DEB (COSMOS-2251)15.032.00
120.778STARLINK-5625COSMOS 2251 DEB (COSMOS-2251)7.5420.33
130.810STARLINK-5360FENGYUN 1C DEB (FENGYUN-1C)13.333.35
140.877STARLINK-32243FENGYUN 1C DEB (FENGYUN-1C)5.8916.31
150.882STARLINK-30444COSMOS 2251 DEB (COSMOS-2251)7.7517.18
160.904STARLINK-5706FENGYUN 1C DEB (FENGYUN-1C)9.613.05
170.935STARLINK-34419FENGYUN 1C DEB (FENGYUN-1C)14.845.54
180.969STARLINK-34613COSMOS 2251 DEB (COSMOS-2251)14.9916.21
190.979STARLINK-34548FENGYUN 1C DEB (FENGYUN-1C)15.081.15
200.980STARLINK-5899FENGYUN 1C DEB (FENGYUN-1C)13.639.35
211.055STARLINK-2170FENGYUN 1C DEB (FENGYUN-1C)12.6213.26
221.086STARLINK-34507FENGYUN 1C DEB (FENGYUN-1C)3.8614.34
231.105STARLINK-33744FENGYUN 1C DEB (FENGYUN-1C)9.5514.52
241.176STARLINK-37058FENGYUN 1C DEB (FENGYUN-1C)8.5015.08
251.177STARLINK-36275COSMOS 2251 DEB (COSMOS-2251)10.078.10

The twenty-five closest approaches in the window, sorted. Every name is a real catalogued object.

PART TWO — THE LOSSES

THE EMPTINESS

I came here to build a Kessler cascade. The runaway chain reaction, the sky closing over. I could not do it honestly and I am going to show you exactly why, because the failure is more interesting than the thing I wanted. Space is not crowded. Space is catastrophically empty. A 500 km shell has about forty billion cubic kilometres in it and roughly thirteen thousand tracked things inside, each a few metres across. The reason we get 20 sub-kilometre passes a day is not density — it is that everything up there is moving at 7.5 km/s and there are a lot of days.

THE FIRST PROTOTYPE

64 real satellites against 176 real fragments whose orbits actually cross theirs. Six hours, 2-second steps, swept-segment closest approach, Kepler + J2.

1 pass under 5 km. 0 under 1 km. 0 collisions.

THE CASCADE SIM

249 real objects, a hash grid, a NASA-style breakup model, 96 minutes of orbit. I swept the collision radius: 0.05 km, 0.5 km, 1.0 km.

0 collisions and 0 fragments at every physical radius. The chain reaction only ignites at a 2 km hit radius — a satellite roughly 40,000 times its real size — and then it produces 576 collisions and 1,151 fragments while destroying exactly 1 satellite. The rest is fragments hitting fragments. That is not a Kessler cascade, that is a number generator. Cut.

ONE SATELLITE ALONE

STARLINK-34131 — the satellite with the closest real conjunction in the whole catalogue — against the 89 real fragments that cross its shell. 72 hours.

3 approaches under 25 km. Closest 15.807 km. One satellite on its own sees almost nothing. The 221-metre pass at the top of this page only exists because 10,754 of them are up there at once.

The cascade sim compiled, ran, and produced beautiful numbers. I deleted it from the page and kept the corpse here instead. If I had shipped the 2 km version you would have seen 576 collisions and a fragment count climbing on a graph and it would have been a lie. The honest result is that at real physical scale, on real element sets, over a real day, nothing hits anything. So I pointed the machinery at the problem that actually exists: not the cascade, the dodge.

READ THIS BEFORE THE NEXT PART

WHERE THE HONESTY LINE IS

Everything above is SGP4. Everything below runs in your browser in freestanding C compiled to WebAssembly, and it is not SGP4 — it is two-body Kepler motion with the J2 oblateness terms, which is what fits in a hot loop that has to evaluate millions of futures. I measured the gap. Forty real satellites, all started from one common-epoch state vector, propagated both ways:

HORIZONMEDIAN ERROR90th %ILEWORST
0.5 h9.985 km15.391 km22.552 km
3 h81.013 km114.522 km134.058 km
12 h310.418 km444.772 km523.604 km
24 h606.321 km873.246 km984.371 km
72 h1,875.232 km2,630.898 km2,805.992 km

So: the engine below is a real result about a real dynamical system derived from the real catalogue. It is not a prediction about real satellites. At a 24-hour horizon my propagator is already 606 km away from SGP4 on a median object. Nobody should manoeuvre a spacecraft on it. What it is good for is the question I actually care about, which is a question about search and not about orbits: given the same physics, the same fuel and the same warning, does looking further ahead beat reacting? Both controllers below run inside the identical model, so the model error cancels out of the comparison. That comparison is real.

PART THREE — LIVE IN THIS TAB

THE SHELL

3,041 real objects — 400 satellites sampled one per orbital plane, and every one of the 2,641 fragments in the snapshot — each carrying its own semi-major axis, eccentricity, inclination, node, argument of perigee and mean anomaly, converted from an SGP4 state vector at one common instant. No textures, no models, no library. Six numbers per object and a fillRect.

loading orbits…
THE SCREENING DIAL

Sweep the next hour of orbit at 2-second steps, swept-segment closest approach on every satellite–fragment pair that shares a hash-grid cell, and count everything that comes inside the radius. This is the same algorithm as Part One, just small enough to run at 60 fps in a tab.

10 km
THE ACTUAL EXPERIMENT

TWO WAYS TO DODGE

Pick one satellite. Give it four burn opportunities over the next twenty-four hours, six hours apart, and four metres per second of fuel total — a real avoidance budget, a real cadence. It can burn prograde or retrograde in quarter-metre steps, which raises or lowers the orbit by a few hundred metres and, far more importantly, shifts when it arrives. Two controllers, identical physics, identical fuel:

MYOPIC

At each slot, look at the next six hours only. If something is inside the safety radius, pick the burn that maximises the miss distance in that window. This is the sane, obvious, correct-looking policy. It is roughly what a human operator on a console does.

DEEP — ROLLOUT AND REWIND

At each slot, try every burn, and for each one re-screen the entire remaining twenty-four hours against every active fragment, then rewind and try the next. Keep the burn whose worst case over the whole window is best. Same fuel, same slots, same physics. It just refuses to be pleased by the near term.

RUN IT ON A SATELLITE
this pins the tab for a couple of seconds — it is doing tens of thousands of full-window screens (loads a 188 KB module on first click)

The failure mode is not subtle once you see it. A myopic dodge changes your period. Changing your period changes where you are eighteen hours from now. The manoeuvre that opens up the conjunction in front of you slides you into a different one behind it — one you were never going to have. Here is the first case that showed me, 72 hours on STARLINK-34131 at a 20 km safety radius:

DO NOTHING
15.807 km
0 m/s
MYOPIC
8.191 km
1.5 m/s over 2 burns — WORSE
DEEP
22.749 km
2 m/s over 1 burn

It burned fuel to cut its own safety margin nearly in half. Lookahead spent more fuel and roughly doubled it.

EVERY RUN, INCLUDING THE ONES I LOST

738 SCENARIOS

250 satellites, one per orbital plane, each against the fragments whose orbits actually cross theirs, at three different safety radii — 750 planning problems attempted, 738 of them scored. (12 runs, four satellites, had no approach at all inside the 60 km logging threshold; they are ties in every column and I left them out of the means rather than let a sentinel poison them.) 32,272 full-window futures imagined. Same code you just ran in your tab, run offline on the same laptop. Nothing here is smoothed or hand-picked. 249 of the scored runs started with a conjunction already inside the safety radius; the tightest do-nothing case in the whole set was 1.688 km.

LOOKAHEAD WON
254
34.4% of scenarios
MYOPIC WON
80
10.8% — published
TIED
404
mostly: both correctly did nothing
MYOPIC MADE IT WORSE
98
than not manoeuvring — 13.3% of runs
LOOKAHEAD MADE IT WORSE
0
out of 738

That last pair of numbers is the whole page. The myopic controller burned fuel and ended up in a tighter spot than doing nothing 98 times. The lookahead controller did it zero times out of 738. Not because it is clever — because it scores every candidate burn against the entire remaining window instead of the next six hours, so a manoeuvre that buys the near term and sells the far one can never look good to it.

SAFETY RADIUSRUNSDO-NOTHING WORSTMYOPIC WORSTDEEP WORSTMYOPIC ΔvDEEP ΔvDEEP / MYO / TIEMYOPIC SELF-HARM
10 km24621.82322.59123.6570.4050.08346 / 23 / 17717
15 km24621.82322.97225.8600.7120.23582 / 27 / 13730
20 km24621.82323.46628.3711.1360.499126 / 30 / 9051

Worst miss = the closest approach anywhere in the 24-hour window under that plan. Bigger is safer. Δv in metres per second, mean over all runs at that radius including the ones that correctly spent nothing.

THE WORST THING MYOPIA DID

Satellite #124 at a 20 km radius. Doing nothing: 33.123 km. The myopic controller spent 3.00 m/s over 2 burns and came out at 5.116 km — it threw away 28.006 km of margin buying safety it did not get. Lookahead, same fuel budget, same slots: 33.123 km for 0.00 m/s.

THE WORST THING LOOKAHEAD DID

Satellite #186 at a 10 km radius. Myopic reached 36.676 km; deep only reached 11.630 km — it lost by 25.046 km. Lookahead is not magic. It optimises the worst case over the window it can see with the fuel it has, and sometimes a greedy grab happens to land in a better basin. 80 times out of 738 it did. There is also a design choice in there I should name: once the whole window is clear of the safety radius, my deep controller stops spending and prefers the cheapest plan. This run is exactly that — it reached 11.630 km on a 10 km radius for a quarter of a metre per second, declared itself done, and watched myopic keep burning to 36.676 km for eight times the fuel. It is still a loss on the metric in the column, so it is counted as one.

HOUSEKEEPING

WHAT THIS IS NOT

  • Not a conjunction warning service. Part One is real SGP4 on real elements, but element sets go stale in hours, and I am not modelling manoeuvres, drag variation or covariance. If your satellite is in that table, phone your own analyst.
  • Not SGP4 in the browser. See the error table. Kepler + J2 drifts 606 km from SGP4 in a day.
  • Not a Kessler cascade. I tried. It does not exist at this scale on this data. Part Two is the receipts.
  • No satellite-versus-satellite risk. Starlink flies phase-controlled trains; a J2-only propagator drifts them into fake sub-kilometre approaches within a plane. Every conjunction on this page is satellite × debris only. That one cost me a day.
  • No learning, no model, no network. There is no neural anything on this page. It is a propagator and a search that imagines futures and throws them away.
  • What is real: the catalogue, the 232,286 screened pairs, the 221-metre pass, the emptiness, and the 738-scenario comparison between two controllers running in identical physics.

One more thing worth writing down, because it took a wasted benchmark run to learn. A two-line element set is only valid at its own epoch, and every object in the catalogue has a different one. Building a scene by reading the elements straight off the TLEs and calling them all t=0 produced a flat 12,195 km error at every horizon — a constant offset, which is the shape of a bug and not the shape of a model. The fix is to SGP4 every object forward to one common instant, take the state vector, and convert that back to classical elements. Every number below the fold comes from a snapshot built that way.

Element sets: CelesTrak GP data, groups starlink, cosmos-2251-debris, iridium-33-debris, fengyun-1c-debris, retrieved 2026-08-12. Propagator for Part One: the AIAA reference SGP4. Engines: freestanding C, no libc, compiled to WebAssembly.