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