COURT FILE · TWO PLAYERS
Park court
84 × 50 ft · high-school lines · two hoops
Recorded on the watch: time, heart rate. Calculated by Proto: body cost, zones. An indoor file has no fix, so the court above stays a court until a registered court and a GPS fix say otherwise.
Eight spots, eight labels
Tap a spot to zoom. A drill from a painted spot is a known distance every time: ten from the line is fifteen feet, ten from the wing is 19'9". The court is the calibration lab, same logic as a par 3 tee.
Start Round, any sport
The Start Round tap on the Watch is generic. One tap arms the wrist gate for the whole run, and only the seconds around each event are written. A swing, a stroke, a release. The same gate that counted a round at Wirth counts a shootaround at the park, and every event gets a fix on a court like this one. What no shot tracker can copy is what sits underneath: the blood and sleep wallet. Both players' runs land next to their labs and their nights, and the verdict reads all three.
The validation loop
No ball sensor. No net sensor. No camera. The drill labels itself.
Release at point A
The Watch reads the wrist at 100 Hz. A release is one sharp gyro peak, then a still follow-through. The phone stamps the fix. Raw motion stays in the vault.
Dribble is the noise
A dribble is rhythmic and low. Two or more peaks a second at half the amplitude never open the gate. A pass is a peak with no follow-through hold. Both are counted, neither is a release.
The drill is the label
Ten from the free-throw line gives ten releases a true distance. The tally at the end of the block, seven of ten, is the outcome, tapped once on the phone. The wrist never guesses a make.
Two wrists, one court
Two players in one session double the labels and give a head-to-head on the one thing a wrist measures cleanly: release tempo and its spread under load, block by block, with heart rate beside every release.
| spot | labeled releases | true distance | confidence |
|---|---|---|---|
| free throw | 0 | 15 ft | awaiting runs |
| elbow | 0 | 15 ft | awaiting runs |
| wing three | 0 | 19'9" | awaiting runs |
| corner three | 0 | 19'9" | awaiting runs |
The scan, Sep 1 2026
Every Apple Watch shot tracker on the store today is told the outcome. The wrist reads the shot; the player reports the make. The category is honest about it once you read the listings.
What /hoops does that none of them do: no tap per shot, the Start Round gate catches every release in 100 Hz windows; two wrists in one session; heart rate beside every release and the wallet underneath it, so the fatigue cliff can read last night's sleep and this month's labs, not only today's BPM; and raw motion that never leaves the device pair. The make stays an entered number until a sensor sees the ball, and the page says so.
Run contract
The page renders whatever the Worker serves at /api/hoops/run/latest. Bounded summaries only, same egress rule as /swing and /course. Two players is two account-keyed vaults in one session.
{
"court": "park",
"kind": "shootaround|oneonone|pickup",
"score_entered": true, // game modes only; the phone keeps score
"session_stamp": "2026-09-06T23:10Z", // coarse, rounded
"players": [{
"key": "p1", "name": "…", // account-keyed, name is a display label
"walk": [[x, y, t], ...], // 1 Hz position, meters from court datum
"hr": [[t, bpm], ...], // heart rate every few seconds, from the workout session
"releases": [{ "t": 412.3, "at": [x, y],
"zone": "rim|paint|mid|three",
"dist_m": 4.6, "spot": "ft|le|re|lw|rw|tk|lc|rc|null",
"hz": 99.1, // effective capture rate, degraded below 80
"hr": 148, // bpm at the gate
"made": true, // game modes only, entered on the phone, never inferred
"peak_rads": 11.2, "hold_ms": 470, "win_n": 500 }], // gyro peak, follow-through hold, samples kept (3 s pre, 2 s post)
"blocks": [{ "spot": "ft", "n": 10, "made": 7 }], // shootaround tally, entered, never inferred
"truth": { "distance_m": 172.5, "top_speed_mps": 3.0, "onball_s": 63,
"kcal": 37, "hr_zones_s": [0, 24, 66, 84, 7],
"hr_end": 171, "hr_recovery_60s": 132, // bpm at the last release, then one minute later
"peak_rads_avg": 10.5, "hold_ms_avg": 480 } // release mechanics, wrist-native
}],
"gates": { "min_gap_s": 2.5, "dribble_hz": 1.6, "hold_ms": 350 } // plausibility, same spirit as the junk gate
}