44[ ![ Deploy to GitHub Pages] ( https://github.com/top-5/klondike/actions/workflows/deploy.yml/badge.svg )] ( https://github.com/top-5/klondike/actions/workflows/deploy.yml )
55[ ![ License] ( https://img.shields.io/badge/license-Custom%20Non--Commercial-blue.svg )] ( LICENSE )
66
7- A modern, type-safe implementation of Classic Klondike Solitaire, built with React, TypeScript, and Vite, featuring beautiful spritesheet cards, intuitive drag & drop, auto-move functionality, and full move validation logic.
7+ A modern, type-safe implementation of Classic Klondike Solitaire, built with React, TypeScript, and Vite, featuring beautiful spritesheet-based card graphics, custom mouse-driven drag & drop, auto-move functionality, and full move validation logic.
88
99🎮 ** [ Play Now on GitHub Pages] ( https://top-5.github.io/klondike/ ) **
1010
11+ ![ Klondike Solitaire Screenshot] ( public/screenshot.png )
12+
1113## ✨ Features
1214
1315- ♠️ ** Classic Klondike Rules** – Traditional solitaire gameplay
1416- 🎨 ** Beautiful Card Graphics** – High-quality spritesheet rendering with subtle animations
15- - 🎮 ** Drag & Drop Interface** – Intuitive card movement with smooth animations
17+ - 🖱️ ** Custom Drag & Drop** – Precise mouse-driven card movement with real-time visual feedback
18+ - 🎯 ** Multi-Card Stack Dragging** – Drag entire card sequences smoothly with proper offset
1619- 🚀 ** Auto-Move to Foundation** – Double-click cards to automatically send them to foundations
1720- ✨ ** Flying Animation** – Cards fly to their destination with beautiful arc motion
1821- ✅ ** Move Validation** – Only valid moves allowed
@@ -44,7 +47,7 @@ npm run preview
4447npm test
4548```
4649
47- Open http://localhost:5173 / to play.
50+ Open http://localhost:10010 / to play.
4851
4952## 🛠️ Development
5053
@@ -74,6 +77,8 @@ npm run test:coverage
7477| Layer | Technology | Purpose |
7578| -------| -----------| ---------|
7679| UI | React 18 | Game interface |
80+ | Graphics | Spritesheet | Card rendering via canvas extraction |
81+ | Drag System | Custom Mouse Events | Precise positioning & multi-card stacks |
7782| Build | Vite 5 | Lightning-fast dev + build |
7883| Language | TypeScript 5.7 | Type-safe logic |
7984| Tests | Vitest 2.1 | Unit testing |
@@ -92,8 +97,13 @@ cardserver/
9297│ ├── main.tsx # React entry point
9398│ ├── App.tsx # Main game component
9499│ ├── App.css # Styling
95- │ ├── types.ts # Type definitions & glyphs
100+ │ ├── types.ts # Type definitions
101+ │ ├── cardSprites.ts # Spritesheet loader
96102│ └── gameLogic.ts # Klondike rules engine
103+ ├── public/
104+ │ ├── deck.png # Card spritesheet (4x13 grid)
105+ │ ├── back.jpg # Card back image
106+ │ └── screenshot.png # Game screenshot
97107├── test/
98108│ └── *.test.ts # Unit tests
99109└── .github/
@@ -187,14 +197,70 @@ interface GameState {
187197}
188198```
189199
190- ## 🎨 Card Colors (CSS Technique)
200+ ## 🎨 Card Graphics Implementation
201+
202+ The game uses a ** spritesheet-based card rendering system** for optimal performance and visual quality:
203+
204+ ### Spritesheet Layout
205+ - ** File** : ` public/deck.png ` (4 rows × 13 columns)
206+ - ** Row mapping** : 0=Clubs, 1=Hearts, 2=Spades, 3=Diamonds
207+ - ** Column mapping** : 0=A, 1=2, ..., 9=10, 10=J, 11=Q, 12=K
208+ - ** Card back** : ` public/back.jpg `
209+
210+ ### Loading Process (` cardSprites.ts ` )
211+ 1 . Load ` deck.png ` spritesheet into memory
212+ 2 . Calculate frame dimensions (width/13, height/4)
213+ 3 . Extract each card using canvas ` drawImage() ` with precise coordinates
214+ 4 . Convert to data URLs for React img elements
215+ 5 . Cache all 52 cards for instant rendering
216+
217+ This approach provides:
218+ - ✅ High-quality card graphics with smooth edges
219+ - ✅ Fast rendering (pre-extracted, cached data URLs)
220+ - ✅ Single spritesheet download (better than 52 separate images)
221+ - ✅ Subtle animations via CSS transforms
222+
223+ ## 🖱️ Custom Drag & Drop System
224+
225+ The game implements a ** custom mouse-driven drag system** (not HTML5 drag API) for precise control:
226+
227+ ### Why Custom Implementation?
228+ - HTML5 drag API forces semi-transparency on drag images (browser limitation)
229+ - Needed pixel-perfect positioning without "jump" on drag start
230+ - Required multi-card stack dragging with proper visual offset
231+ - Wanted full control over cursor states and visual feedback
232+
233+ ### How It Works
234+ 1 . ** Mouse Down** : Calculate offset from card's top-left to click position
235+ 2 . ** Mouse Move** : Track global mouse position, update drag overlay position
236+ 3 . ** Drag Overlay** : Fixed-position div at ` mouseX - offsetX ` , ` mouseY - offsetY `
237+ 4 . ** Original Cards** : Set to ` opacity: 0 ` during drag (fully invisible, no ghosting)
238+ 5 . ** Drop Detection** : Use ` elementFromPoint() ` to find drop zone under cursor
239+ 6 . ** Mouse Up** : Validate move, update game state, reset cursor
240+
241+ ### Features
242+ - 🎯 ** Precise positioning** – Card stays under cursor at click point
243+ - 📚 ** Multi-card stacks** – Drag sequences with 25px offset per card
244+ - 👁️ ** Clean visuals** – No ghostly images or transparency issues
245+ - 🖱️ ** Cursor feedback** – grab → grabbing → normal states
246+ - ⚡ ** High performance** – No unnecessary re-renders
247+
248+ ## 🎨 CSS Animations
191249
192250``` css
193- .red { color : #dc143c ; text-shadow : 0 0 1px #dc143c ; }
194- .black { color : #000 ; text-shadow : 0 0 1px #000 ; }
195- ```
251+ /* Shimmer effect on cards */
252+ @keyframes cardShimmer {
253+ 0% , 100% { box-shadow : 0 2px 8px rgba (0 ,0 ,0 ,0.15 ); }
254+ 50% { box-shadow : 0 4px 16px rgba (0 ,0 ,0 ,0.25 ); }
255+ }
196256
197- Applies transparent glyphs with shadow tint for vibrant Unicode cards.
257+ /* Flying animation for auto-move */
258+ @keyframes flyToFoundation {
259+ 0% { transform : scale (1 ) translateY (0 ); }
260+ 50% { transform : scale (0.9 ) translateY (-30px ); }
261+ 100% { transform : scale (1 ) translateY (0 ); opacity : 0 ; }
262+ }
263+ ```
198264
199265## 🚀 Deployment
200266
0 commit comments