From a5d108f4f2a3e59c41968fe68eb50a12aec592f6 Mon Sep 17 00:00:00 2001 From: adlee-was-taken Date: Sun, 1 Feb 2026 23:14:04 -0500 Subject: [PATCH] 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 --- CLAUDE.md | 134 ++++++++++++++++++++++ client/ANIMATIONS.md | 261 +++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 395 insertions(+) create mode 100644 CLAUDE.md create mode 100644 client/ANIMATIONS.md diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..f323044 --- /dev/null +++ b/CLAUDE.md @@ -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 diff --git a/client/ANIMATIONS.md b/client/ANIMATIONS.md new file mode 100644 index 0000000..01c519b --- /dev/null +++ b/client/ANIMATIONS.md @@ -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