- Extract WebSocket handlers from main.py into handlers.py - Add V3 feature docs (dealer rotation, dealing animation, round end reveal, column pair celebration, final turn urgency, opponent thinking, score tallying, card hover/selection, knock early drama, column pair indicator, swap animation improvements, draw source distinction, card value tooltips, active rules context, discard pile history, realistic card sounds) - Add V3 refactoring docs (ai.py, main.py/game.py, misc improvements) - Add installation guide with Docker, systemd, and nginx setup - Add helper scripts (install.sh, dev-server.sh, docker-build.sh) - Add animation flow diagrams documentation - Add test files for handlers, rooms, and V3 features - Add e2e test specs for V3 features - Update README with complete project structure and current tech stack - Update CLAUDE.md with full architecture tree and server layer descriptions - Update .env.example to reflect PostgreSQL (remove SQLite references) - Update .gitignore to exclude virtualenv files, .claude/, and .db files - Remove tracked virtualenv files (bin/, lib64, pyvenv.cfg) - Remove obsolete game_log.py (SQLite) and games.db Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
11 KiB
Golf Card Game - V3 Master Plan
Overview
Transform the current Golf card game into a more natural, physical-feeling experience through enhanced animations, visual feedback, and gameplay flow improvements. The goal is to make the digital game feel as satisfying as playing with real cards.
Theme: "Make it feel like a real card game"
Document Structure (VDD)
This plan is split into independent vertical slices ordered by priority and impact. Each document is self-contained and can be worked on by a separate agent.
| Document | Scope | Priority | Effort | Dependencies |
|---|---|---|---|---|
V3_01_DEALER_ROTATION.md |
Rotate dealer/first player each round | High | Low | None (server change) |
V3_02_DEALING_ANIMATION.md |
Animated card dealing at round start | High | Medium | 01 |
V3_03_ROUND_END_REVEAL.md |
Dramatic sequential card reveal | High | Medium | None |
V3_04_COLUMN_PAIR_CELEBRATION.md |
Visual feedback for matching pairs | High | Low | None |
V3_05_FINAL_TURN_URGENCY.md |
Enhanced final turn visual tension | High | Low | None |
V3_06_OPPONENT_THINKING.md |
Visible opponent consideration phase | Medium | Low | None |
V3_07_SCORE_TALLYING.md |
Animated score counting | Medium | Medium | 03 |
V3_08_CARD_HOVER_SELECTION.md |
Enhanced card selection preview | Medium | Low | None |
V3_09_KNOCK_EARLY_DRAMA.md |
Dramatic knock early presentation | Medium | Low | None |
V3_10_COLUMN_PAIR_INDICATOR.md |
Visual connector for paired columns | Medium | Low | 04 |
V3_11_SWAP_ANIMATION_IMPROVEMENTS.md |
More physical swap motion | Medium | Medium | None |
V3_12_DRAW_SOURCE_DISTINCTION.md |
Visual distinction deck vs discard draw | Low | Low | None |
V3_13_CARD_VALUE_TOOLTIPS.md |
Long-press card value display | Low | Medium | None |
V3_14_ACTIVE_RULES_CONTEXT.md |
Contextual rule highlighting | Low | Low | None |
V3_15_DISCARD_PILE_HISTORY.md |
Show recent discards fanned | Low | Medium | None |
V3_16_REALISTIC_CARD_SOUNDS.md |
Improved audio feedback | Nice | Medium | None |
Current State (V2)
Client (Vanilla JS)
├── app.js - Main game logic (2500+ lines)
├── card-manager.js - DOM card element management (3D flip structure)
├── animation-queue.js - Sequential animation processing
├── card-animations.js - Unified anime.js animation system (replaces draw-animations.js)
├── state-differ.js - State change detection
├── timing-config.js - Centralized animation timing + anime.js easing config
├── anime.min.js - Anime.js library for all animations
└── style.css - Minimal CSS, mostly layout
What works well:
- Unified anime.js system - All card animations use
window.cardAnimations(CardAnimations class) - State diffing detects changes and triggers appropriate animations
- Animation queue ensures sequential, non-overlapping animations
- Centralized timing config with anime.js easing presets (
TIMING.anime.easing) - Sound effects via Web Audio API
- CardAnimations provides: draw, flip, swap, discard, ambient loops (turn pulse, CPU thinking)
- Opponent turn visibility with CPU action announcements
Limitations:
- Cards appear instantly at round start (no dealing animation)
- Round end reveals all cards simultaneously
- No visual celebration for column pairs
- Final turn phase lacks urgency/tension
- Swap animation uses crossfade rather than physical motion
- Limited feedback during card selection
- Discard pile shows only top card
V3 Target Experience
Physical Card Game Feel Checklist
| Aspect | Physical Game | Current Digital | V3 Target |
|---|---|---|---|
| Dealer Rotation | Deal passes clockwise each round | Always starts with host | Rotating dealer/first player |
| Dealing | Cards dealt one at a time | Cards appear instantly | Animated dealing sequence |
| Drawing | Card lifts, player considers | Card pops in | Source-appropriate pickup |
| Swapping | Old card slides out, new slides in | Teleport swap | Cross-over motion |
| Pairing | "Nice!" moment when match noticed | No feedback | Visual celebration |
| Round End | Dramatic reveal, one player at a time | All cards flip at once | Staggered reveal |
| Scoring | Count card by card | Score appears | Animated tally |
| Final Turn | Tension in the room | Badge shows | Visual urgency |
| Sounds | Shuffle, flip, slap | Synth beeps | Realistic card sounds |
Tech Approach
Animation Strategy
All card animations use the unified CardAnimations class (card-animations.js):
- Anime.js timelines for all card animations (flip, swap, draw, discard)
- CardAnimations methods -
animateDrawDeck(),animateFlip(),animateSwap(), etc. - Ambient loops -
startTurnPulse(),startCpuThinking(),startInitialFlipPulse() - One-shot effects -
pulseDiscard(),pulseSwap(),popIn() - Animation queue for sequencing multi-step animations
- State differ to trigger animations on state changes
When to use CSS vs anime.js:
- Anime.js (CardAnimations): Card movements, flips, swaps, draws - anything involving card elements
- CSS keyframes/transitions: Simple UI feedback (button hover, badge entrance, status message fades) - non-card elements
General rule: If it moves a card, use anime.js. If it's UI chrome, CSS is fine.
Timing Philosophy
From timing-config.js:
// Current values - animations are smooth but quick
card: {
flip: 400, // Card flip duration
move: 400, // Card movement
},
pause: {
afterFlip: 0, // No pause - flow into next action
betweenAnimations: 0, // No gaps
},
// Anime.js easing presets
anime: {
easing: {
flip: 'easeInOutQuad',
move: 'easeOutCubic',
lift: 'easeOutQuad',
pulse: 'easeInOutSine',
},
loop: {
turnPulse: { duration: 2000 },
cpuThinking: { duration: 1500 },
initialFlipGlow: { duration: 1500 },
}
}
V3 will introduce optional pauses for drama without slowing normal gameplay:
- Quick pauses at key moments (pair formed, round end)
- Staggered timing for dealing/reveal (perceived faster than actual)
- User preference for animation speed (future consideration)
Sound Strategy
Current sounds are oscillator-based (Web Audio API synthesis). V3 options:
- Enhanced synthesis - More realistic waveforms, envelopes
- Audio sprites - Short recordings of real card sounds
- Hybrid - Synthesis for some, samples for others
Recommendation: Start with enhanced synthesis (no asset loading), consider audio sprites later.
Phases & Milestones
Phase 1: Core Feel (High Priority)
Goal: Make the game feel noticeably more physical
| Item | Description | Document |
|---|---|---|
| Dealer rotation | First player rotates each round (like real cards) | 01 |
| Dealing animation | Cards dealt sequentially at round start | 02 |
| Round end reveal | Dramatic staggered flip at round end | 03 |
| Column pair celebration | Glow/pulse when pairs form | 04 |
| Final turn urgency | Visual tension enhancement | 05 |
Phase 2: Turn Polish (Medium Priority)
Goal: Improve the feel of individual turns
| Item | Description | Document |
|---|---|---|
| Opponent thinking | Visible consideration phase | 06 |
| Score tallying | Animated counting | 07 |
| Card hover/selection | Better swap preview | 08 |
| Knock early drama | Dramatic knock presentation | 09 |
| Column pair indicator | Visual pair connector | 10 |
| Swap improvements | Physical swap motion | 11 |
Phase 3: Polish & Extras (Low Priority)
Goal: Nice-to-have improvements
| Item | Description | Document |
|---|---|---|
| Draw distinction | Deck vs discard visual difference | 12 |
| Card value tooltips | Long-press to see points | 13 |
| Active rules context | Highlight relevant rules | 14 |
| Discard history | Show fanned recent cards | 15 |
| Realistic sounds | Better audio feedback | 16 |
File Structure (Changes)
server/
├── game.py # Add dealer rotation logic (V3_01)
client/
├── app.js # Enhance existing methods
├── timing-config.js # Add new timing values + anime.js config
├── card-animations.js # Extend with new animation methods
├── animation-queue.js # Add new animation types
├── style.css # Minimal additions (mostly layout)
└── sounds/ # OPTIONAL: Audio sprites
├── shuffle.mp3
├── deal.mp3
└── flip.mp3
Note: All new animations should be added to CardAnimations class in card-animations.js. Do not add CSS keyframe animations for card movements.
Acceptance Criteria (V3 Complete)
- Dealer rotates properly - First player advances clockwise each round
- Dealing feels physical - Cards dealt one by one with shuffle sound
- Round end is dramatic - Staggered reveal with tension pause
- Pairs are satisfying - Visual celebration when columns match
- Final turn has urgency - Clear visual indication of tension
- Swaps look natural - Cards appear to exchange positions
- No performance regression - Animations run at 60fps on mobile
- Timing is tunable - All values in timing-config.js
Design Principles
1. Enhance, Don't Slow Down
Animations should make the game feel better without making it slower. Use perceived timing tricks:
- Start next animation before previous fully completes
- Stagger start times, not end times
- Quick movements with slight ease-out
2. Respect the Player's Time
- First-time experience: full animations
- Repeat plays: consider faster mode option
- Never block input unnecessarily
3. Clear Visual Hierarchy
- Active player highlighted
- Current action obvious
- Next expected action hinted
4. Consistent Feedback
- Same action = same animation
- Similar duration for similar actions
- Predictable timing helps player flow
5. Graceful Degradation
- Animations enhance but aren't required
- State updates should work without animations
- Handle animation interruption gracefully
How to Use These Documents
Each V3_XX_*.md document is designed to be:
- Self-contained - Has all context needed to implement that feature
- Agent-ready - Can be given to a Claude agent as the primary context
- Testable - Includes visual verification criteria
- Incremental - Can be implemented and shipped independently
Workflow:
- Pick a document based on current priority
- Start a new Claude session with that document as context
- Implement the feature
- Verify against acceptance criteria
- Test on mobile and desktop
- Merge and move to next
Notes for Implementation
- Don't break existing functionality - All current animations must still work
- Use existing infrastructure - Build on animation-queue, timing-config
- Test on mobile - Animations must run smoothly on phones
- Consider reduced motion - Respect
prefers-reduced-motionmedia query - Keep it vanilla - No new frameworks, Anime.js is sufficient
Success Metrics
After V3 implementation, the game should:
- Feel noticeably more satisfying to play
- Get positive feedback on "polish" or "feel"
- Not feel slower despite more animations
- Work smoothly on all devices
- Be easy to tune timing via config