| 1 | // The page around a game's viewer hands it the replay (Shoal's public/app.js): the viewer runs in a frame with scripts |
| 2 | // only, says it is ready, and gets {shoal: 'replay', name, text}. Opened by itself, it reads ?replay=<file> instead, |
| 3 | // so a replay can be watched from a clone: python3 -m http.server, then viewer/index.html?replay=../replays/x.json |
| 4 | // A live room (docs/games.md §8.4) opens the viewer as index.html?live. shoalLive(fn) says {shoal: 'ready', live: true} |
| 5 | // and calls fn(batch) for each {shoal: 'live', room, you, messages}: you lists the seats this viewer controls, the first |
| 6 | // batch holds all the history it may see, and each message is the room's (§8.3) plus its sequence number n: {n, to, |
| 7 | // version, obs, legal} asks a seat to act, {n, to, obs} tells one seat, {n, event} is public, {n, end} ends the room. |
| 8 | // shoalAct(seat, version, action) plays for a seat in you, answering the request with that version. |
| 9 | window.shoalReplay = start => { |
| 10 | addEventListener('message', e => { if (e.data && e.data.shoal === 'replay') start(e.data.text, e.data.name) }) |
| 11 | const local = new URLSearchParams(location.search).get('replay') |
| 12 | if (local) fetch(local).then(r => r.text()).then(t => start(t, local)) |
| 13 | else if (parent !== window) parent.postMessage({ shoal: 'ready' }, '*') |
| 14 | } |
| 15 | window.shoalLive = fn => { |
| 16 | addEventListener('message', e => { if (e.data && e.data.shoal === 'live') fn(e.data) }) |
| 17 | if (parent !== window) parent.postMessage({ shoal: 'ready', live: true }, '*') |
| 18 | } |
| 19 | window.shoalAct = (seat, version, action) => parent.postMessage({ shoal: 'act', seat, version, action }, '*') |
