Add animation system documentation and project context

- client/ANIMATIONS.md: Full documentation of the CardAnimations API, timing config, CSS rules, and common patterns
- CLAUDE.md: Project context for AI assistants with architecture overview and development guidelines

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
adlee-was-taken 2026-02-01 23:14:04 -05:00
parent df422907b0
commit a5d108f4f2
2 changed files with 395 additions and 0 deletions

134
CLAUDE.md Normal file
View File

@ -0,0 +1,134 @@
# Golf Card Game - Project Context
A real-time multiplayer 6-card Golf card game with CPU opponents and smooth anime.js animations.
## Quick Start
```bash
# Install dependencies
pip install -r server/requirements.txt
# Run the server
python server/main.py
# Visit http://localhost:5000
```
## Architecture
```
golfgame/
├── server/ # Python FastAPI backend
│ ├── main.py # HTTP routes, WebSocket handling
│ ├── game.py # Game logic, state machine
│ └── ai.py # CPU opponent AI with timing/personality
├── client/ # Vanilla JS frontend
│ ├── app.js # Main game controller
│ ├── card-animations.js # Unified anime.js animation system
│ ├── card-manager.js # DOM management for cards
│ ├── animation-queue.js # Animation sequencing
│ ├── timing-config.js # Centralized timing configuration
│ ├── state-differ.js # Diff game state for animations
│ ├── style.css # Styles (NO card transitions)
│ └── ANIMATIONS.md # Animation system documentation
└── docs/v3/ # Feature planning documents
```
## Key Technical Decisions
### Animation System
**All card animations use anime.js.** No CSS transitions on card elements.
- See `client/ANIMATIONS.md` for full documentation
- `CardAnimations` class in `card-animations.js` handles everything
- Timing configured in `timing-config.js`
### State Management
- Server is source of truth
- Client receives full game state on each update
- `state-differ.js` computes diffs to trigger appropriate animations
- `isDrawAnimating` flag prevents UI updates during animations
### CPU Players
- AI logic in `server/ai.py`
- Configurable timing delays for natural feel
- Multiple personality types affect decision-making
## Common Development Tasks
### Adjusting Animation Speed
Edit `timing-config.js` - all timings are centralized there.
### Adding New Animations
1. Add method to `CardAnimations` class in `card-animations.js`
2. Use anime.js, not CSS transitions
3. Track in `activeAnimations` Map for cancellation support
4. Add timing config to `timing-config.js` if needed
### Debugging Animations
```javascript
// Check what's animating
console.log(window.cardAnimations.activeAnimations);
// Force cleanup
window.cardAnimations.cancelAll();
// Check timing config
console.log(window.TIMING);
```
### Testing CPU Behavior
Adjust delays in `server/ai.py` `CPU_TIMING` dict.
## Important Patterns
### No CSS Transitions on Cards
Cards animate via anime.js only. The following should NOT have `transition`:
- `.card`, `.card-inner`
- `.real-card`, `.swap-card`
- `.held-card-floating`
### Animation Overlays
Complex animations create temporary overlay elements:
1. Create `.draw-anim-card` positioned over source
2. Hide original card
3. Animate overlay
4. Remove overlay, reveal updated card
### Fire-and-Forget for Opponents
Opponent animations don't block - no callbacks needed:
```javascript
cardAnimations.animateOpponentFlip(cardElement, cardData);
```
## Dependencies
### Server
- FastAPI
- uvicorn
- websockets
### Client
- anime.js (animations)
- No other frameworks
## Game Rules Reference
- 6 cards per player in 2x3 grid
- Lower score wins
- Matching columns cancel out (0 points)
- Jokers are -2 points
- Kings are 0 points
- Game ends when a player flips all cards

261
client/ANIMATIONS.md Normal file
View File

@ -0,0 +1,261 @@
# Card Animation System
This document describes the unified animation system for the Golf card game client.
## Architecture
**All card animations use anime.js.** There are no CSS transitions on card elements.
| What | How |
|------|-----|
| Card movements | anime.js |
| Card flips | anime.js |
| Swap animations | anime.js |
| Pulse/glow effects | anime.js |
| Hover states | CSS `:hover` only |
| Show/hide | CSS `.hidden` class only |
### Why anime.js?
- Consistent timing and easing across all animations
- Coordinated multi-element sequences via timelines
- Proper animation cancellation via `activeAnimations` tracking
- No conflicts between CSS and JS animation systems
---
## Core Files
| File | Purpose |
|------|---------|
| `card-animations.js` | Unified `CardAnimations` class - all animation logic |
| `timing-config.js` | Centralized timing/easing configuration |
| `style.css` | Static styles only (no transitions on cards) |
---
## CardAnimations Class API
Global instance available at `window.cardAnimations`.
### Draw Animations
```javascript
// Draw from deck - lift, move to hold area, flip to reveal
cardAnimations.animateDrawDeck(cardData, onComplete)
// Draw from discard - quick grab, no flip
cardAnimations.animateDrawDiscard(cardData, onComplete)
// For opponent draw-then-discard - deck to discard with flip
cardAnimations.animateDeckToDiscard(card, onComplete)
```
### Flip Animations
```javascript
// Generic flip animation on any card element
cardAnimations.animateFlip(element, cardData, onComplete)
// Initial flip at game start (local player)
cardAnimations.animateInitialFlip(cardElement, cardData, onComplete)
// Opponent card flip (fire-and-forget)
cardAnimations.animateOpponentFlip(cardElement, cardData, rotation)
```
### Swap Animations
```javascript
// Player swaps drawn card with hand card
cardAnimations.animateSwap(position, oldCard, newCard, handCardElement, onComplete)
// Opponent swap (fire-and-forget)
cardAnimations.animateOpponentSwap(playerId, position, discardCard, sourceCardElement, rotation, wasFaceUp)
```
### Discard Animations
```javascript
// Animate held card swooping to discard pile
cardAnimations.animateDiscard(heldCardElement, targetCard, onComplete)
```
### Ambient Effects (Looping)
```javascript
// "Your turn to draw" shake effect
cardAnimations.startTurnPulse(element)
cardAnimations.stopTurnPulse(element)
// CPU thinking glow
cardAnimations.startCpuThinking(element)
cardAnimations.stopCpuThinking(element)
// Initial flip phase - clickable cards glow
cardAnimations.startInitialFlipPulse(element)
cardAnimations.stopInitialFlipPulse(element)
cardAnimations.stopAllInitialFlipPulses()
```
### One-Shot Effects
```javascript
// Pulse when card lands on discard
cardAnimations.pulseDiscard()
// Pulse effect on face-up swap
cardAnimations.pulseSwap(element)
// Pop-in when element appears (use sparingly)
cardAnimations.popIn(element)
// Gold ring expanding effect before draw
cardAnimations.startDrawPulse(element)
```
### Utility Methods
```javascript
// Check if animation is in progress
cardAnimations.isBusy()
// Cancel all running animations
cardAnimations.cancel()
cardAnimations.cancelAll()
// Clean up animation elements
cardAnimations.cleanup()
```
---
## Animation Overlay Pattern
For complex animations (flips, swaps), the system:
1. Creates a temporary overlay element (`.draw-anim-card`)
2. Positions it exactly over the source card
3. Hides the original card (`opacity: 0` or `.swap-out`)
4. Animates the overlay
5. Removes overlay and reveals updated original card
This ensures smooth animations without modifying the DOM structure of game cards.
---
## Timing Configuration
All timing values are in `timing-config.js` and exposed as `window.TIMING`.
### Key Durations
| Animation | Duration | Notes |
|-----------|----------|-------|
| Flip | 245ms | 3D rotateY animation |
| Deck lift | 63ms | Before moving to hold |
| Deck move | 105ms | To hold position |
| Discard lift | 25ms | Quick grab |
| Discard move | 76ms | To hold position |
| Swap pulse | 400ms | Scale + brightness |
| Turn shake | 400ms | Every 3 seconds |
### Easing Functions
```javascript
window.TIMING.anime.easing = {
flip: 'easeInOutQuad', // Smooth acceleration/deceleration
move: 'easeOutCubic', // Fast start, gentle settle
lift: 'easeOutQuad', // Quick lift
pulse: 'easeInOutSine', // Smooth oscillation
}
```
---
## CSS Rules
### What CSS Does
- Static card appearance (colors, borders, sizing)
- Layout and positioning
- Hover states (`:hover` scale/shadow)
- Show/hide via `.hidden` class
### What CSS Does NOT Do
- No `transition` on any card element
- No `@keyframes` for card animations
- No `.flipped`, `.moving`, `.flipping` transition triggers
### Important Classes
| Class | Purpose |
|-------|---------|
| `.draw-anim-card` | Temporary overlay during animation |
| `.draw-anim-inner` | 3D flip container |
| `.swap-out` | Hides original during swap animation |
| `.hidden` | Opacity 0, no display change |
| `.draw-pulse` | Gold ring expanding effect |
---
## Common Patterns
### Preventing Premature UI Updates
The `isDrawAnimating` flag in `app.js` prevents the held card from appearing before the draw animation completes:
```javascript
// In renderGame()
if (!this.isDrawAnimating && /* other conditions */) {
// Show held card
}
```
### Animation Sequencing
Use anime.js timelines for coordinated sequences:
```javascript
const timeline = anime.timeline({
easing: 'easeOutQuad',
complete: () => { /* cleanup */ }
});
timeline.add({ targets: el, translateY: -15, duration: 100 });
timeline.add({ targets: el, left: x, top: y, duration: 200 });
timeline.add({ targets: inner, rotateY: 0, duration: 245 });
```
### Fire-and-Forget Animations
For opponent/CPU animations that don't block game flow:
```javascript
// No onComplete callback needed
cardAnimations.animateOpponentFlip(cardElement, cardData);
```
---
## Debugging
### Check Active Animations
```javascript
console.log(window.cardAnimations.activeAnimations);
```
### Force Cleanup
```javascript
window.cardAnimations.cancelAll();
```
### Animation Not Working?
1. Check that anime.js is loaded before card-animations.js
2. Verify element exists and is visible
3. Check for CSS transitions that might conflict
4. Look for errors in console