/* @component-map * App — Main container, manages game phase routing and state * Lobby — Room join/create UI with player slots * WordEntry — Secret word input for the setter * WaitingScreen — Spinner while waiting for setter's word * GameBoard — Active hangman game with gallows, word display, keyboard * ResultScreen — Round result with play again button * ScoreBar — Score display for both players * @end-component-map */ import { useCollection } from '@deplixo/sdk'; import { Lobby } from './components/Lobby.jsx'; import { WordEntry } from './components/WordEntry.jsx'; import { WaitingScreen } from './components/WaitingScreen.jsx'; import { GameBoard } from './components/GameBoard.jsx'; import { ResultScreen } from './components/ResultScreen.jsx'; import { useCallback, useEffect, useRef, useState } from 'react'; import { ScoreBar } from './components/ScoreBar.jsx'; function App() { const [myName, setMyName] = useState(''); const [myRole, setMyRole] = useState(''); const [roomCode, setRoomCode] = useState(''); const [entryId, setEntryId] = useState(null); const [gameState, setGameState] = useState(null); const [joined, setJoined] = useState(false); const { items, loading, add, update, collection } = useCollection('rooms'); const gameStateRef = useRef(gameState); useEffect(() => { gameStateRef.current = gameState; }, [gameState]); const entryIdRef = useRef(entryId); useEffect(() => { entryIdRef.current = entryId; }, [entryId]); const roomCodeRef = useRef(roomCode); useEffect(() => { roomCodeRef.current = roomCode; }, [roomCode]); useEffect(() => { if (!joined || !collection) return; const unsub = collection.onChange((event) => { if (event.action === 'reconnect') return; if (!event.value || event.value.roomCode !== roomCodeRef.current) return; if (event.id) setEntryId(event.id); setGameState({ ...event.value }); }); return () => { if (unsub) unsub(); }; }, [joined, collection]); const saveState = useCallback(async (newState) => { if (!entryIdRef.current) return; setGameState({ ...newState }); await update(entryIdRef.current, newState); }, [update]); const phase = gameState?.phase || 'lobby'; const showScores = phase !== 'lobby' && phase !== 'waiting' && gameState; return (

🪢 Hangman

Two-player • Real-time • Online

{showScores && } {(!joined || phase === 'waiting') && ( )} {phase === 'word_entry' && myRole === 'setter' && ( )} {phase === 'word_entry' && myRole === 'guesser' && } {phase === 'playing' && ( )} {phase === 'done' && ( )}
); } ReactDOM.createRoot(document.getElementById("root")).render();