- Node.js 18+
- npm
- Git
# Install dependencies
npm install
# Install server dependencies
cd server && npm install && cd ..
# Start development server
npm run dev
# In another terminal, start the backend (optional, for LAN sync)
cd server && node index.js- Functional components with hooks
constoverlet, nevervar- Meaningful variable names
- Small, focused functions
// Use STATE for UI that needs to re-render
const [gameState, setGameState] = useState('idle');
// Use REFS for animation data (no re-renders)
const positionRef = useRef({ x: 0, y: 0 });useEffect(() => {
if (gameState !== 'playing') return;
const animate = (timestamp) => {
// Update physics using refs
// Update DOM directly
animationRef.current = requestAnimationFrame(animate);
};
animationRef.current = requestAnimationFrame(animate);
return () => cancelAnimationFrame(animationRef.current);
}, [gameState]);Use inline style objects with the project color palette:
| Role | Color |
|---|---|
| Primary | #a855f7 (purple) |
| Secondary | #ec4899 (pink) |
| Accent | #22d3ee (cyan) |
| Success | #22c55e (green) |
| Warning | #facc15 (yellow) |
| Error | #ef4444 (red) |
| Background | #0f172a, #1e293b |
| Text | white, #94a3b8 |
// src/pages/NewGame.jsx
import { useState, useRef, useEffect } from 'react';
import { RotateCcw, Trophy, Play, User } from 'lucide-react';
import { getLeaderboard, addScore, getNickname } from '../utils/leaderboard';
import { ReplayRecorder } from '../utils/replay';
import { startGameSession, endGameSession } from '../utils/gameSession';
import FixedGameArea from '../components/FixedGameArea';
import PostGameAnalytics from '../components/PostGameAnalytics';
import ReplayViewer from '../components/ReplayViewer';
export default function NewGame() {
const [gameState, setGameState] = useState('idle');
const [nickname, setNicknameState] = useState(() => getNickname());
const [leaderboard, setLeaderboard] = useState(() => getLeaderboard('newgame'));
// Game logic...
const handleGameEnd = () => {
const newLeaderboard = addScore('newgame', score, { /* stats */ });
setLeaderboard(newLeaderboard);
};
return (
// JSX...
);
}import NewGame from './pages/NewGame';
// In Routes:
<Route path="/newgame" element={<NewGame />} />// In Navbar.jsx, add to navLinks array:
{ path: '/newgame', label: 'New Game', icon: GameIcon }Add a card in Home.jsx linking to the new game.
In server/index.js, add bounds to GAME_BOUNDS:
newgame: {
maxScore: 10000,
gameDuration: 30,
// ... game-specific constraints
},And add duration bounds to expectedDurations in the session end handler.
Document the stats object in docs/API.md under "Stats Objects by Game".
import { addScore } from '../utils/leaderboard';
const newLeaderboard = addScore('gametype', score, {
accuracy: 95,
time: 30,
});import { ReplayRecorder, saveReplayLocal } from '../utils/replay';
// Start recording
const recorder = new ReplayRecorder('gametype');
recorder.start();
// Each frame: record mouse position and events
recorder.addFrame(mouseX, mouseY, events);
// End recording
const replayData = recorder.stop();
await saveReplayLocal(replayData);import { startGameSession, endGameSession } from '../utils/gameSession';
// Before gameplay
const session = await startGameSession('gametype');
// After gameplay
await endGameSession(session.sessionId, score, stats);- Game starts and ends correctly
- Score saves to leaderboard
- Replay records and plays back
- Post-game analytics display
- Nickname changes update all scores
- Works offline (no server)
- Works on LAN with server
- Reset button works
- No console errors
- Smooth 60 FPS in animation loop
- No memory leaks (check browser dev tools)
feature/game-name— new gamesfix/issue-description— bug fixesimprove/component-name— improvements
feat: add spider shot game mode
fix: tracking reaction time not updating
improve: optimize gridshot target rendering
docs: update API reference with new endpoints
- Use refs instead of state for animation data
- Use direct DOM manipulation in animation loops
- Avoid creating new objects/arrays in animation loops
- Verify game type string matches in
addScoreandgetLeaderboard - Check localStorage in browser dev tools
- Ensure server is running on port 3001
- Check CORS is enabled
- Verify
VITE_API_URLenvironment variable
Open an issue or check existing documentation in the /docs folder.