4.7 KiB
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
# 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:
onAnimationCompletefires 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:
isSpinningflag 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-xlandbg-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
- User clicks "DRAW" button (disabled if
isSpinningorpool.length === 0) drawNumber()→ Selects random number, removes from pool, setscurrentWinner, setsisSpinning=trueSlotMachinedetects winner change → Triggers 3-reel animation (3-4 second duration)- Animation completes → Calls
handleAnimationComplete() completeDraw(currentWinner)→ Adds to history, setsisSpinning=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→ rendersApp.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
xlbreakpoint