Skip to content

@ludus/game-engine-react

React components and hooks for embedding Ludus games. Live spectating, replay gallery with filters, commentary integration, and game state management.

Terminal window
npm install @ludus/game-engine-react

Main layout wrapper for viewing a game — composes GameViewer, Leaderboard, CommentaryFeed, and ReplayControls.

import { SpectatorShell } from '@ludus/game-engine-react';
<SpectatorShell
gameId="game-123"
mode="live" // or "replay"
showCommentary={true}
/>

Composes SpectatorShell with useLiveCommentary for live games with integrated AI commentary.

import { LiveSpectatorShell } from '@ludus/game-engine-react';
<LiveSpectatorShell gameId="game-123" commentaryProvider={provider} />

Drop-in replay viewer with built-in commentary (pre-generated on load, filtered by current turn).

import { CommentedReplayShell } from '@ludus/game-engine-react';
<CommentedReplayShell replay={gameReplay} persona={ORIANA} />

Gallery of past games with filtering and sorting.

import { ReplayGallery } from '@ludus/game-engine-react';
<ReplayGallery
replays={replayList}
onSelect={(replay) => navigate(`/replay/${replay.replayId}`)}
/>

Supports filtering by game type and sorting: newest, oldest, longest, shortest.

Individual replay card for the gallery.

Playback controls: play/pause, step forward, scrub to turn, speed selector.

Player rankings with active player highlighting.

Scrollable AI commentary messages with auto-scroll to latest.

Replay playback with play/pause/seek/speed control.

import { useReplay } from '@ludus/game-engine-react';
const { currentTurn, totalTurns, currentEntry, isPlaying, speed, play, pause, seek, setSpeed } = useReplay(replay);

Subscribe to live game state via a transport-agnostic StateProvider.

import { useGameState } from '@ludus/game-engine-react';
const { state, connected, error } = useGameState('game-123', stateProvider);

Subscribe to live commentary via CommentaryProvider.

import { useLiveCommentary } from '@ludus/game-engine-react';
const { messages, active } = useLiveCommentary(commentaryProvider);
// messages: CommentaryMessage[]

Pre-generates all commentary for a replay on load, filters by current turn.

import { useReplayCommentary } from '@ludus/game-engine-react';
const { messages, loading } = useReplayCommentary({ replay, persona: ORIANA, currentTurn });

Paginated replay list with filtering.

import { useReplayList } from '@ludus/game-engine-react';
const { replays, loading, loadMore, refresh } = useReplayList({ gameType: 'konquista', orderBy: 'newest' });

Load a single full replay by ID.

import { useReplayDetail } from '@ludus/game-engine-react';
const { replay, loading, error } = useReplayDetail('replay-123');

Firestore persistence for replays.

import { ReplayService } from '@ludus/game-engine-react';
const service = new ReplayService(firestoreDb);
await service.save(gameReplay);
const { replays, lastDoc } = await service.list({ gameType: 'konquista', limit: 10, orderBy: 'newest' });
const replay = await service.get('replay-123');

Convert ReplayEntry to GameEvent for the commentary pipeline.

import { replayToGameEvents, makeGameStartEvent, makeGameOverEvent } from '@ludus/game-engine-react';
const events = replayToGameEvents(replay); // GameEvent[] including synthetic start/end events

Transport-agnostic live game state (WebSocket, Firestore, in-process):

interface StateProvider {
subscribe(gameId: string, onState: (state: BaseGameState) => void, onError?: (error: Error) => void): () => void;
}

Transport-agnostic live commentary:

interface CommentaryProvider {
subscribe(callback: (msg: CommentaryMessage) => void): () => void;
getHistory(): CommentaryMessage[];
}
interface CommentaryMessage {
id: string;
turn: number;
text: string;
persona?: string;
timestamp: number;
}
import type { StateProvider, CommentaryProvider, CommentaryMessage, SpectatorConfig,
GameViewProps, GameViewerProps, ReplayFilters, SortOrder, ReplayListResult,
ReplaySummary } from '@ludus/game-engine-react';