# 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
