{msg.message}
++ Tip: Type @username to send a private message +
+{variant.description}
+Share this code with your friends
+Room Code
++ {generatedCode} +
+ +{variant.description}
+Players reaching this score will be disqualified
++ Arrange your 13 cards into valid sequences and sets, then declare to win the round. +
++ Disqualification: First player to reach the target score (default 200) is eliminated. +
+No rounds completed yet
+Disqualified:
+Choose your game variant
+{variant.description}
+ + {/* Features */} +Enter the 6-letter room code shared by your friend
+Enter details to join the table
+Please sign in to join a room
+ )} ++ {name} +
++ {position} +
+| Player | + {roundHistory.map((round, idx) => ( ++ R{round.round_number} + | + ))} ++ Total + | +
|---|---|---|
|
+
+ {player.display_name || 'Player'}
+
+ |
+ {roundHistory.map((round, idx) => {
+ const isWinner = round.winner_user_id === player.user_id;
+ const roundScore = round.scores[player.user_id] || 0;
+ return (
+
+
+
+ {roundScore}
+
+ {isWinner &&
+ |
+ );
+ })}
+ + + {totalScore} + + | +
Sign in to manage your profile.
+ +{error}
} +User ID: {profile.user_id}
+ )} ++ Request permission from the host to spectate the remaining players +
+ +{title} (3 cards)
+Leftover / 4-Card Seq
+Missing tableId.
+ +Loading…
} + {!loading && info && ( +Room Code
+{info.code}
+Players
+Seat {p.seat}
+{p.display_name || p.user_id.slice(0,6)}
+Round #{info.current_round_number}
+ {isMyTurn ? ( +Your turn!
+ ) : ( +Wait for your turn
+ )} +STOCK PILE
+ {myRound.stock_count > 0 && ( ++ {myRound.wild_joker_revealed ? ( + WILD JOKER + ) : ( + WILD JOKER + )} +
+DISCARD PILE
++ {hasDrawn ? "Organize your 13 cards into melds (drag cards to slots)" : "Organize melds (draw a card first)"} +
+ + {/* Three 3-card meld boxes */} ++ Your Hand ({availableHand.length} cards) + {lastDrawnCard && ★ New card highlighted} +
++ ✓ Card selected - Click to discard +
+Organize 13 cards into valid melds, then declare. The 14th card will be auto-discarded.
++ 🎉 Winner: {info.players.find(p => p.user_id === scoreboard.winner_user_id)?.display_name || "Unknown"} +
+| Player | +Points | +
|---|---|
|
+
+ {isWinner &&
+ |
+ + {score.points} + | +
Waiting for host to start next round...
+ )} +Loading…
} + {!loading && info && ( + <> + {/* Room Code */} +Room Code
+
+ {info.code}
+
+ Players ({info.players.length})
+Seat {p.seat}
+{p.display_name || p.user_id.slice(0,6)}
+Status: {info?.status ?? "-"}
+ {user && info.host_user_id === user.id && ( +Waiting for host to start...
+ )} +| Player | + {roundHistory.map((round, idx) => ( ++ R{round.round_number} + | + ))} ++ Total + | +
|---|---|---|
|
+
+ {player.display_name || 'Player'}
+
+ |
+ {roundHistory.map((round, idx) => {
+ const isWinner = round.winner_user_id === player.user_id;
+ const roundScore = round.scores[player.user_id] || 0;
+ runningTotal += roundScore;
+ return (
+
+
+
+ {roundScore}
+
+ {isWinner &&
+ |
+ );
+ })}
+ + {runningTotal} + | +
Join the voice call to see participants
+Waiting for others to join...
++ {participant.display_name || participant.user_id.slice(0, 8)} + {isMe && ' (You)'} +
+ {participant.is_speaking && ( +Speaking...
+ )} +