PROTO /hoops
reading the run

COURT FILE · TWO PLAYERS

Park court

84 × 50 ft · high-school lines · two hoops

2wrists
15ft · free throw
19'9"three
8spots per hoop
reading the run…
player 1 · movement and releases player 2 release density paint

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.

01

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.

02

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.

03

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.

04

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.

PER-SPOT RELEASE MODEL locked · 0 of 20 labeled blocks
spotlabeled releasestrue distanceconfidence
free throw015 ftawaiting runs
elbow015 ftawaiting runs
wing three019'9"awaiting runs
corner three019'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
}