RMHbox — Reusable UI Components¶
Version: 1.0
Last Updated: 2026-02-22
Status: Draft
This document catalogs all reusable UI components built for RMHbox. Each component is designed for reuse across minigames and core UI. Components will be documented here as they are built in subsequent phases.
Planned Components¶
Modals¶
ConfirmModal — Generic confirmation dialog (kick player, end session)
ResultsModal — Post-game results overlay
Timer Bars¶
TimerBar — Horizontal countdown bar with configurable duration and styling
CircularTimer — Circular countdown for compact displays
Displays¶
RoomCodeDisplay — Large room code with copy-to-clipboard
PlayerList — Avatar + name list with connection status indicators
SpectatorBanner — “You are spectating” persistent banner
ScoreBoard — Session standings with rank changes
Chat¶
ChatOverlay — In-lobby text chat with auto-scroll and system messages
Component API Documentation¶
Components implemented in Phase 4. All components use 'use client' directive and are located in components/rmhbox/.
RoomCodeDisplay¶
File: components/rmhbox/RoomCodeDisplay.tsx
Props:
Prop |
Type |
Default |
Description |
|---|---|---|---|
|
|
— |
The 6-character room code to display |
Usage:
<RoomCodeDisplay code="ABC123" />
PlayerList¶
File: components/rmhbox/PlayerList.tsx
Props:
Prop |
Type |
Default |
Description |
|---|---|---|---|
|
|
— |
Array of player info objects |
|
|
— |
User ID of the current host (shows crown icon) |
Usage:
<PlayerList players={lobby.players} hostUserId={lobby.hostUserId} />
HostControls¶
File: components/rmhbox/HostControls.tsx
Props:
Prop |
Type |
Default |
Description |
|---|---|---|---|
|
|
— |
Whether the current user is the host |
|
|
— |
Current lobby ID |
|
|
— |
Current lobby state |
Usage:
<HostControls isHost={true} lobbyId="ABCDEF" lobbyState="WAITING" />
ChatOverlay¶
File: components/rmhbox/ChatOverlay.tsx
Props:
Prop |
Type |
Default |
Description |
|---|---|---|---|
|
|
— |
Array of chat messages |
|
|
— |
Callback when a message is sent |
Usage:
<ChatOverlay messages={lobby.chat} onSend={(msg) => emit('rmhbox:lobby:chat', { content: msg })} />
LeaderboardPanel¶
File: components/rmhbox/LeaderboardPanel.tsx
Props: None. Self-fetching component.
Usage:
<LeaderboardPanel />
LobbyView¶
File: components/rmhbox/LobbyView.tsx
Props: None. Reads from Zustand store.
Composes: RoomCodeDisplay, PlayerList, ReadyButton, HostControls, ChatOverlay.
Usage:
<LobbyView />
GameVoting¶
File: components/rmhbox/GameVoting.tsx
Props:
Prop |
Type |
Default |
Description |
|---|---|---|---|
|
|
— |
5 candidate minigames |
|
|
— |
Vote timer duration |
|
|
— |
Unix timestamp when voting ends |
|
|
— |
Callback on vote cast |
Usage:
<GameVoting candidates={[...]} durationSeconds={30} endsAt={Date.now() + 30000} onVote={handleVote} />
InstructionsScreen¶
File: components/rmhbox/InstructionsScreen.tsx
Props:
Prop |
Type |
Default |
Description |
|---|---|---|---|
|
|
— |
Minigame display name |
|
|
— |
Minigame description |
|
|
— |
Bullet-point rules |
|
|
— |
Helpful tips |
|
|
— |
Countdown duration |
|
|
— |
Whether to show skip button |
|
|
— |
Callback for host skip |
Usage:
<InstructionsScreen title="Rhyme Time" description="..." rules={[...]} tips={[...]} durationSeconds={15} isHost={true} onSkip={handleSkip} />
PreloadScreen¶
File: components/rmhbox/PreloadScreen.tsx
Props:
Prop |
Type |
Default |
Description |
|---|---|---|---|
|
|
— |
Player readiness list |
Auto-emits rmhbox:game:ready_to_render on mount.
Usage:
<PreloadScreen players={preloadPlayers} />
ResultsScreen¶
File: components/rmhbox/ResultsScreen.tsx
Props:
Prop |
Type |
Default |
Description |
|---|---|---|---|
|
|
— |
Player rankings for the round |
|
|
— |
Cumulative session standings |
|
|
— |
Round awards |
|
|
— |
Current round number |
Uses framer-motion for staggered animations, canvas-confetti for winner celebration.
Usage:
<ResultsScreen rankings={[...]} sessionStandings={[...]} awards={[...]} roundNumber={1} />
MinigameRenderer¶
File: components/rmhbox/minigames/MinigameRenderer.tsx
Props:
Prop |
Type |
Default |
Description |
|---|---|---|---|
|
|
— |
ID of the minigame to render |
Uses React.lazy() and Suspense for code-splitting. Shows loading fallback during load, error fallback for unknown games.
Usage:
<MinigameRenderer minigameId="rhyme-time" />
GameShell¶
File: components/rmhbox/GameShell.tsx
Props:
Prop |
Type |
Default |
Description |
|---|---|---|---|
|
|
— |
Display name of the minigame |
|
|
— |
Seconds remaining (null hides timer) |
|
|
— |
Current round number |
|
|
— |
Player’s current score |
|
|
— |
Number of players |
|
|
— |
Game content |
Usage:
<GameShell gameName="Rhyme Time" timeRemaining={30} roundNumber={1} score={500} playerCount={4}>
<MinigameRenderer minigameId="rhyme-time" />
</GameShell>
Server-Side Data Contracts (Phase 2)¶
The following client-safe types are available for component development:
Type |
Source |
Description |
|---|---|---|
|
|
Full lobby state snapshot sent to clients |
|
|
Player info without internal fields (no socketId, joinedAt) |
|
|
Spectator info for display |
|
|
Current game info with phase and public/private state |
|
|
Lobby browser entry with player count and status |
|
|
Chat message with id, userId, content, type |
|
|
Broadcast action with seq counter and type |
|
|
Vote candidate with minigameId, displayName, description |
|
|
Vote started event with candidates and duration |
|
|
Vote update with tallies and voter counts |
|
|
Vote result with winner and tallies |
|
|
Round results with rankings and awards |
|
|
Cumulative session standings |
|
|
Match history entry |
WebSocket Events (Phase 2–3)¶
Key events for UI component integration:
Event |
Direction |
Description |
|---|---|---|
|
S→C |
Lobby creation confirmation with lobbyId |
|
S→C |
Full state snapshot on join/reconnect |
|
S→C |
Game actions (PLAYER_JOINED, CHAT_MESSAGE, TIMER_TICK, STATE_CHANGED, etc.) |
|
S→C |
Public lobby browser results |
|
S→C |
Kicked notification |
|
S→C |
Lobby disbanded notification |
|
S→C |
Vote initiated with candidates and timer |
|
S→C |
Vote tallies updated after a cast |
|
S→C |
Vote resolved with winning minigame |
|
S→C |
Game instructions with rules, tips, controls |
|
S→C |
Preload manifest for game assets |
|
S→C |
Player readiness during preloading |
|
S→C |
Countdown started with seconds |
|
S→C |
Game has started playing |
|
S→C |
Round results with rankings and awards |
|
S→C |
Per-player game state snapshot (reconnection) |
Game Lifecycle Phases (Phase 3)¶
Components should be aware of the game lifecycle state machine:
WAITING → VOTING → INSTRUCTIONS → PRELOADING → COUNTDOWN → PLAYING → ROUND_RESULTS → WAITING
The ClientGameInfo.phase field reflects the current phase:
'instructions'— Show game rules, tips, controls'preloading'— Show asset loading progress'countdown'— Show countdown timer (3 seconds)'playing'— Show game UI'results'— Show round results and standings
Game Action Types (Phase 3)¶
The following action types are broadcast via rmhbox:game:action:
Action Type |
Payload |
Description |
|---|---|---|
|
|
Lobby state transition |
|
|
1-second countdown tick |
|
|
Player reconnected |
|
|
Player disconnected |
|
|
Player left lobby |
|
|
Player joined lobby |
|
|
Spectator joined |
|
|
Spectator left |
|
|
Host changed |
|
|
Player was kicked |
|
|
Chat message sent |
|
|
Player ready toggle |
Template¶
### ComponentName
**File:** `components/rmhbox/ComponentName.tsx`
**Props:**
| Prop | Type | Default | Description |
|------|------|---------|-------------|
| ... | ... | ... | ... |
**Usage:**
\`\`\`tsx
<ComponentName prop="value" />
\`\`\`