Add spectator mode for late-joining players

- Server: Late joiners are added as spectators instead of players
- Server: Send forced-spectator event only to joining spectator (not broadcast)
- Server: Track spectators separately and move them to players after game ends
- Client: Handle forced-spectator event to show all player boards
- Client: Spectators see all boards equally without main/spectator highlighting
- Client: Mobile view shows scrollable vertical list of all boards for spectators
- Fix: All cleared lines are sent as garbage to each opponent (not randomized)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-20 18:26:48 +00:00
parent 75cd5b0e44
commit a0ab4ff5cd
7 changed files with 281 additions and 21 deletions
+63 -1
View File
@@ -151,6 +151,44 @@ button:active {
color: #0f0;
}
.player-item .status.spectator-status {
color: #888;
font-style: italic;
}
/* Spectator list in lobby */
#spectator-list {
display: flex;
flex-direction: column;
gap: 10px;
margin: 20px 0;
min-height: 0;
}
#spectator-list:empty {
display: none;
}
#spectator-list .player-item {
background: #0a0a1a;
border: 2px solid #555;
}
#spectator-list .player-item .status {
color: #aaa;
}
/* Spectator mode header */
#game-room-name.spectator-mode {
color: #ff8800;
animation: pulse 2s infinite;
}
@keyframes pulse {
0%, 100% { opacity: 1; }
50% { opacity: 0.7; }
}
/* Battle Grid - Focused Layout */
#battle-grid {
position: relative;
@@ -538,7 +576,31 @@ button:active {
height: 50px !important;
}
.player-board.spectator {
/* Hide spectator boards on mobile when playing (has main board) */
#battle-grid:has(.main) .player-board.spectator {
display: none;
}
/* In spectator mode (no main board), show all boards in a scrollable container */
#battle-grid:not(:has(.main)) {
transform: none;
height: auto;
flex-direction: column;
overflow-y: auto;
margin-bottom: 0;
padding-bottom: 100px;
}
#battle-grid:not(:has(.main)) .player-board {
position: relative;
transform: none;
opacity: 1;
margin: 10px 0;
width: 90%;
}
#battle-grid:not(:has(.main)) .player-board canvas {
width: 100%;
height: auto;
}
}