Overview
About the project
GemCrush is a production-ready match-3 game engineered from scratch without game frameworks. The custom TypeScript engine handles board generation with guaranteed valid moves, flood-fill match detection, cascading combos with special gem chaining (match-4 → line clears, match-5 → bombs with 3×3 blast radius), gravity/refill cycles, and combo-multiplied scoring. The Canvas 2D renderer delivers 60fps animations (swap, fall, particle bursts, spawn) synchronized with React state via a custom animation queue. Touch-first controls support both click-to-select and drag-to-swap with 12px threshold and pointer capture. Three power-ups (Shuffle, Destroy Gem, Extra Moves) integrate directly into the cascade system. Campaign progression spans 8 levels with increasing difficulty (target scores, move limits, color counts); endless mode plays until deadlock. Stars reward skill: over-target scoring + move efficiency. Progress persists via Cloudflare KV with anonymous UUID identity.
Step 1
The Challenge
Build a polished, production-ready match-3 puzzle game that runs entirely in the browser with native-app feel — smooth 60fps animations, responsive touch controls, and persistent progression — while deploying on Cloudflare's edge platform for global low-latency delivery. The core technical challenges were: (1) Custom game engine from scratch (board generation, match detection, cascading combos, special gems, gravity/refill), (2) Canvas animation pipeline synchronized with React state, (3) Touch-first drag-to-swap + click controls with pointer capture, (4) Edge deployment of Next.js 16 + Canvas to Cloudflare Workers via OpenNext with KV persistence.
Step 2
Our Solution
Engine (src/engine/): Pure TS, zero deps. Match-4→Line Clear (row/col), Match-5→Bomb (3×3), BFS chaining (blast triggers other specials). Cascade loop: matches → specials → removal → gravity → refill → repeat. Scoring: 10 pts/gem × combo multiplier (1.5×/cascade) + special bonuses. Power-ups: Shuffle, Destroy Gem, Extra Moves.
Renderer (src/renderer/): Canvas 2D with custom animation queue. Preloaded gem assets (6 colors + bomb + thunder). Particle bursts (8/gem, physics: gravity, drag, fade). 4 animation types: swap/fall/remove/spawn.
Controller (src/game/controller.ts): State machine (Idle/Selected/Animating/GameOver). Drag threshold 12px, pointer capture. Power-up modes integrated.
Frontend: Next.js App Router — Home (stats, campaign/endless entry), Level select (lock progression, stars), Level play (target + moves), Endless (deadlock loss). Floating gems bg, HUD with progress bar, combo banner, power-up bar.
Persistence: localStorage UUID + Cloudflare KV (GAME_KV) via /api/save & /api/load. Stars from skill score: (overTarget/target) + (movesLeft/maxMoves)*0.5.
Step 3
The Results
- 60fps mobile/desktop; Canvas avoids React reconciliation during animations
- ~150KB gzipped (no Phaser/Pixi bloat)
- Single npm run deploy → 300+ edge locations, auto HTTPS, DDoS protection
- 8 campaign levels + endless; star system rewards efficiency + over-scoring
- Polish: particles, combo callouts, power-up states, loading skeleton, staggered animations
