# CLAUDE.md This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. ## Project Overview This is a React-based lucky draw application (Year End Party draw system) built with Vite, featuring an animated slot machine interface for random number selection with persistent state management. ## Development Commands ```bash # Install dependencies npm install # Start development server (with HMR) npm run dev # Build for production npm run build # Preview production build npm run preview # Lint code npm run lint ``` ## Tech Stack - **Frontend Framework**: React 19.2.0 with JSX - **Build Tool**: Vite 7.2.4 - **Styling**: Tailwind CSS 3.4.17 with custom configuration - **Animation**: Framer Motion 12.23.26 (for slot machine animations) - **Icons**: Lucide React 0.559.0 - **Linting**: ESLint 9.39.1 with flat config ## Architecture ### State Management Pattern The app uses a custom hook pattern for state management (`useLuckyDraw` hook) that encapsulates all draw logic and persists state to localStorage. Key features: - **Persistent State**: All draw state (pool, history, maxNumber) is automatically saved to localStorage - **State Shape**: `{ maxNumber, remainingNumbers, drawHistory }` - **Pool Management**: Numbers are removed from pool when drawn, preventing duplicates - **History Tracking**: All drawn numbers are stored in reverse chronological order ### Component Structure ``` App.jsx (Main container) ├── SlotMachine.jsx (Animated 3-digit display) │ └── Uses framer-motion with 3 independent reel controls │ └── Staggered animation (3s, 3.5s, 4s) for luxury effect └── HistoryPanel.jsx (Sidebar with history + controls) └── Shows draw history, max number control, reset button ``` ### Animation System (SlotMachine) The slot machine uses a sophisticated animation approach: - **3 Independent Reels**: Each digit has its own animation control - **Duplicate Strips**: Each reel contains 6 sets of 0-9 (NUM_DUPLICATES=5 + final set) - **Staggered Timing**: Reels stop at different times (delay: 0s, 0.5s, 1.0s) for dramatic effect - **Target Calculation**: `targetY = -((NUM_DUPLICATES * 10) + digit) * SLOT_HEIGHT` - **Animation Callback**: `onAnimationComplete` fires when all reels finish, triggering history update ### Custom Hook: useLuckyDraw Located in `src/hooks/useLuckyDraw.js`, this hook manages: - **Draw Logic**: Random selection from remaining pool - **Pool Management**: Automatic pool updates and persistence - **Animation State**: `isSpinning` flag prevents concurrent draws - **Two-Phase Draw**: `drawNumber()` initiates, `completeDraw(winner)` finalizes after animation ### Styling Approach - **Background**: Full-screen image (`/asset/img/background.jpg`) with overlay gradients - **Glass Morphism**: History panel uses `backdrop-blur-xl` and `bg-white/20` - **Custom Colors**: Tailwind extended with `sky-light`, `sky-dark`, `gold` - **Responsive**: Main slot machine centered, history panel shows only on `xl:` breakpoint ## Important Implementation Details ### Draw Flow Sequence 1. User clicks "DRAW" button (disabled if `isSpinning` or `pool.length === 0`) 2. `drawNumber()` → Selects random number, removes from pool, sets `currentWinner`, sets `isSpinning=true` 3. `SlotMachine` detects winner change → Triggers 3-reel animation (3-4 second duration) 4. Animation completes → Calls `handleAnimationComplete()` 5. `completeDraw(currentWinner)` → Adds to history, sets `isSpinning=false` ### Max Number Changes Changing max number triggers a confirmation dialog and full reset: - Clears pool and regenerates with new max - Clears history - User must confirm to prevent accidental data loss ### Legacy Code The `legacy/` directory contains an older vanilla JS implementation that is not part of the current app. It can be ignored for development purposes but is preserved for reference. ## File Locations - **Config**: `src/config.json` (currently stores default maxNumber, though runtime state overrides this) - **Background Image**: Expected at `public/asset/img/background.jpg` - **Main Entry**: `src/main.jsx` → renders `App.jsx` - **Styles**: `src/index.css` (imports Tailwind) ## ESLint Configuration Uses flat config format (`eslint.config.js`) with: - React Hooks plugin (enforces rules of hooks) - React Refresh plugin (for HMR) - Custom rule: Allows unused variables starting with uppercase (e.g., component imports) ## Notes for Development - The app is NOT a git repository (no version control initialized) - No TypeScript - uses plain JSX - LocalStorage key: `'luckyDrawState'` - Slot machine dimensions: Each reel is 320px (w-80 h-80), digit height is also 320px - History panel is hidden on screens smaller than `xl` breakpoint