basketball.casa

A basketball world simulated from the body up. Watch only.

A link to any view of the basketball replay

The replay's broadcast camera sits 20 to 25 metres from the play. From there a head is about 9 pixels tall and a hand about 4, so the plays decided by hands, like a steal, a strip or a player turning their head to look, are hard to see. And a view you found by flying the camera around could not be shown to anyone else. The address held only the moment, never the camera.

Now the link holds the camera too. Press L in the replay and it pauses, then writes the exact view you are looking at into the address bar. Anyone who opens that address sees the same moment from the same place.

Follow anyone, from anywhere

A link can follow the ball or any player by the name on their card, from an offset you choose. It can also put you behind a player's eyes. The camera is placed from the figure itself every frame, so it stays on them as they move:

Here is one interception in a game of the league, seen three ways. First, the passer's own view as the ball leaves their hands, with their card open:

Through the passer's eyes: the ball just released toward the far side of the court, red defenders and blue teammates spread out ahead, and the passer's player card open at the right
Through the passer's eyes, 9:45.3.
Through the defender's eyes: the pass arcing overhead toward a red and a blue player standing close together, with the defender's card open at the right
Through the eyes of the defender who takes it, as the pass comes over, 9:45.6.
Beside the red defender, who reaches up with both hands and takes the ball above their head, other players standing behind
Beside the defender, 3 metres off: both hands up and the ball taken, 9:46.1.

A link that writes itself back unchanged

One function writes every link, and one function reads it, so a view survives the round trip. Numbers are kept to the millimetre. A link opened fresh and shared again with L comes back exactly as it went out:

export function toHash(link, h) {
  const num = (...xs) => xs.map((x) => String(Number(x.toFixed(3)))).join(",");
  const name = (who) => { if (who === "ball") return who; const [side, j] = h.players[who]; return `${side ? "away" : "home"}${j + 1}`; };
  const parts = link.tr.playing ? [] : [`t=${num(link.tr.t)}`];
  if (link.cam) parts.push(`cam=${num(...link.cam.pos)}`, `look=${num(...link.cam.look)}`);
  if (link.fov !== null) parts.push(`fov=${num(link.fov)}`);
  if (link.follow) parts.push(`follow=${name(link.follow.who)}`, link.eye === null ? `from=${num(...link.follow.from)}` : "eye");
  return `#${parts.join("&")}`;
}

A link the replay cannot read is never silently ignored. If a player's name does not exist, or an offset has nothing to follow, the replay names the part it could not read in a note on the screen, and opens the TV camera instead.

What it made visible

From 3 or 4 metres, the plays that were lost at the broadcast distance read clearly. A strip shows both hands on the ball, where the broadcast camera draws it about 10 pixels across. An interception shows the reach, and a player scanning the floor shows their face turning. Each of these was checked by opening its link and looking.