# Working in The Clanked Game ## Stack - **React 19** — UI rendering - **Vite 8** — Dev server and build tooling - **WebAudio API** — All sound synthesis (no audio files) - **pnpm** — Package manager ## Project Layout ``` src/ App.jsx — Root component, screen state (home/main-menu/game) components/ Game.jsx — Core game loop: canvas rendering, state, collision, input soundEffects.js — WebAudio sound synthesis functions ``` ## Key Implementation Notes - The game loop runs in `Game.jsx` via `requestAnimationFrame`. All game logic (`updateStars`, `updatePlayer`, `updateAliens`, `checkCollisions`, etc.) is defined inside the `useEffect` and operates on `gameStateRef.current`. - Sound effects use the WebAudio API and are stateless helpers in `soundEffects.js`. Call `getAudioContext()` lazily on first use (browser autoplay policy). - Shields are stored as 2D boolean grids (pixel-level destruction without canvas complexity). - The canvas renders at **800×600** (`CANVAS_WIDTH`, `CANVAS_HEIGHT`). ## Adding Sound Effects Functions in `soundEffects.js` follow the same pattern: ```js export const playXSound = () => { const ctx = getAudioContext(); const currentTime = ctx.currentTime; const oscillator = ctx.createOscillator(); const gainNode = ctx.createGain(); oscillator.type = 'square'; // or 'sine', 'sawtooth', or white noise via AudioBuffer // configure frequency... // configure gain envelope... oscillator.connect(gainNode); gainNode.connect(ctx.destination); oscillator.start(currentTime); oscillator.stop(currentTime + duration); }; ``` For white noise, create an `AudioBuffer` filled with `Math.random() * 2 - 1` values and use a `BufferSourceNode`. ## Adding Gameplay Features - New game state fields go in `gameStateRef.current` (line ~95). - New per-frame update functions follow `updateStars`, `updatePlayer`, etc. pattern and are called in the game loop in order. - New draw functions follow `drawStars`, `drawPlayer`, etc. pattern and are called in the render section of `gameLoop()`. - Screen transitions happen via `setCurrentScreen()` in `App.jsx` — pass an `onExit` callback from `Game` to return to main menu. ## Git Workflow - Branch: `develop` - Push to `origin/develop` after meaningful changes. ## npm Scripts | Command | Description | |---------|-------------| | `pnpm dev` | Start Vite dev server with HMR | | `pnpm build` | Production build to `dist/` | | `pnpm lint` | Run ESLint | | `pnpm preview` | Preview production build locally |