replayFrames function
The full ordered frame history of a finished game, fetched once.
A finished game's history is immutable, so this is fetched a single time and cached for the life of the replay screen. A participant receives their own seat's projection; a non-participant replaying a public game receives the observer projection - the shape is identical either way, so the replay UI does not branch on it.
The same range endpoint backs live gap recovery; replay is just the whole range rather than a missing slice of it.
Implementation
@riverpod
Future<List<Frame>> replayFrames(Ref ref, {required String gameId}) async {
// A game played on this device already holds every seat's projection per
// version, which is exactly what the server re-projects for its own replay.
// Reading them here is what lets a finished offline game be replayed offline.
final record = await ref.watch(
localGameRecordProvider(gameId: gameId).future,
);
if (record != null) {
final seat = record.humanSeat;
if (seat != null) return localReplayFrames(record, seat: seat);
}
return ref.watch(gameRepositoryProvider).getFrames(gameId);
}