Skip to content

Latest commit

 

History

History
284 lines (222 loc) · 10.4 KB

File metadata and controls

284 lines (222 loc) · 10.4 KB

🐍 Snake — React + TypeScript Edition

A minimalist Snake clone built with React, TypeScript, and HTML Canvas — focused on mastering game loops, keyboard input, and UI feedback using React hooks and refs.

CI Built with React TypeScript TailwindCSS License Last Commit Contributions welcome

🧩 This project is part of my ongoing React fundamentals journey exploring how to handle real-time loops, keyboard input, and canvas drawing inside React without heavy frameworks.


🕹️ Preview

🎥 Gameplay Sneak Peek

Gameplay preview


🌐 Live Demo

Try Snake here: https://snake-beryl-six.vercel.app/


🎯 Features

🧠 Core Gameplay

  • Smooth Canvas Rendering — real-time updates without unnecessary re-renders
  • 🎮 Arrow Key Controls — responsive movement with spacebar restart
  • 🍎 Dynamic Food Spawning — random positions, never overlaps the snake
  • 💥 Collision Detection — walls and self-collision instantly end the game
  • 🔁 Clean Restart Logic — quick replay loop with instant feedback
  • 💫 Animated Score Pop — subtle CSS bump when you eat food
  • 🌑 Dark Grid Aesthetic — modern look with subtle borders and Tailwind styling

🚀 Enhanced Features

  • 🔊 Sound Effects — satisfying audio feedback for moves, food, and game-over
  • 🧩 Difficulty Presets — easy, medium, and hard options that scale board size and speed
  • 🥕 Emoji Food Items — random fruits and veggies add playful variety
  • 💾 Persistent Best Score — keeps your top score across sessions (local leaderboard per difficulty)
  • 🎉 Celebrations — confetti on new high score and every 5 points
  • ⏸️ Pause / Resume Hotkey — toggle with the P key
  • 🧱 Dynamic Speed Scaling — snake speeds up as you grow
  • 🧭 Modular Hook Architecture — reusable logic with useSnakeGame, useTicker, and friends
  • ⚙️ Strict TypeScript + ESLint — clean, type-safe codebase with zero warnings

🏆 Leaderboard

Scores are stored locally in your browser. Your best scores per difficulty appear in the Leaderboard from the main menu.


Contributing

We love contributions of all kinds! Whether it’s fixing a bug, suggesting a feature, or polishing docs, your help makes this game better.

How to join in:

Every contribution, big or small, helps keep this project alive 🎉


🚧 Roadmap

Check upcoming ideas and milestones in the Project Roadmap.


Acknowledgements

Snake is a community project, shaped by everyone who’s played, tested, and contributed.
Every commit, idea, and bug report makes the game better.

Contributors

Meet all our amazing Contributors


📂 Project Structure

📁 Click to expand project file structure
.
├── .github
│   ├── ISSUE_TEMPLATE
│   │   ├── bug.yml
│   │   ├── config.yml
│   │   ├── documentation.yml
│   │   ├── enhancement_refactor.yml
│   │   ├── feature_request.yml
│   │   └── question_discussion.yml
│   ├── workflows
│   │   ├── snake-ci.yml
│   │   └── vercel-production.yml
│   └── pull_request_template.md
├── .gitignore
├── .husky
│   ├── pre-commit
│   └── pre-push
├── .prettierignore
├── .prettierrc
├── .prettierrc.json
├── .prettierrc.yml
├── .stylelintrc.json
├── CONTRIBUTORS.md
├── eslint.config.js
├── index.html
├── package-lock.json
├── package.json
├── playwright.config.ts
├── public
│   ├── snake.svg
│   └── sounds
│       ├── food.mp3
│       ├── gameover.mp3
│       └── move.mp3
├── README.md
├── scripts
│   └── precheck.sh
├── e2e
│   └── app.spec.ts
├── src
│   └── app
│       ├── App.tsx
│       ├── assets
│       │   └── snake-gameplay.gif
│       ├── components
│       │   ├── AchievementsModal.tsx
│       │   ├── CountdownOverlay.tsx
│       │   ├── GameOverOverlay.tsx
│       │   ├── HUD.tsx
│       │   ├── HowToPlayModal.tsx
│       │   ├── LeaderboardModal.tsx
│       │   ├── MenuScreen.tsx
│       │   ├── MobileControls.tsx
│       │   ├── SettingsModal.tsx
│       │   ├── SnakeCanvas.tsx
│       │   └── StatsScreen.tsx
│       ├── constants
│       │   ├── foodThemes.ts
│       │   ├── game.ts
│       │   ├── skins.ts
│       │   └── themes.ts
│       ├── data
│       │   └── achievements.ts
│       ├── hooks
│       │   ├── useBestScore.ts
│       │   ├── useCanvas2D.ts
│       │   ├── useGameScale.ts
│       │   ├── useGameSession.ts
│       │   ├── useGameSetup.ts
│       │   ├── useInput.ts
│       │   ├── useLeaderboard.ts
│       │   ├── usePauseHotkey.ts
│       │   ├── useSettings.ts
│       │   ├── useSnakeGame.ts
│       │   ├── useSwipe.ts
│       │   └── useTicker.ts
│       ├── main.tsx
│       ├── services
│       │   ├── achievementService.ts
│       │   ├── achievementService.test.ts
│       │   ├── statsService.ts
│       │   └── statsService.test.ts
│       ├── styles
│       │   └── App.css
│       ├── types
│       │   ├── game.ts
│       │   ├── index.ts
│       │   └── ui.ts
│       └── utils
│           ├── canvas.ts
│           ├── gameTick.ts
│           ├── haptics.ts
│           ├── logic.ts
│           ├── logic.test.ts
│           ├── seedRandom.ts
│           ├── share.ts
│           ├── soundGenerator.ts
│           └── speed.ts
├── tsconfig.json
├── tsconfig.node.json
└── vite.config.ts

Getting Started

Requirements: Node 18+

Clone & Run

  1. Clone repo
git clone git@github.com:NickTheDevOpsGuy/Snake.git
  1. Install dependencies
npm install
  1. Start dev server
npm run dev
  1. Run tests (optional):
npm test
  1. In your browser, visit http://localhost:5173

Tech Stack

Name Version Description
React ^19.x UI library for building components.
Vite ^7.x Fast dev server & bundler.

Scripts

Run with npm run <script> (see package.json for full list).

Category Script What it does
Dev dev Start Vite dev server
build Type-check (tsc -b) then build with Vite
preview Preview the production build
Test test Placeholder test script (exits 0)
test:watch Run Vitest in watch mode
Deploy predeploy Build before deploy
deploy Publish dist/ to GitHub Pages via gh-pages
Lint/Format lint ESLint for JS/TS (., extensions: js, jsx, ts, tsx)
lint:fix ESLint with --fix
format Prettier write across the repo
format:check Prettier check (no writes)
lint:css Stylelint for **/*.{css,scss} (includes build output unless ignored)
lint:css:fix Stylelint --fix for src/**/*.{css,scss}
Checks check Run Prettier (write) then ESLint
check:fix Run Prettier (write) then ESLint with --fix
TypeScript tscheck TypeScript type-check only (no emit)
Tooling precheck Run scripts/precheck.sh (project preflight)
Git Hooks prepare Run Husky setup on install

🦝 Built by NickDoesDevOps

Created with ☕, curiosity, and a bit of chaos by Nicholas Clark.
Follow my learning-in-public journey:
GitHub: @NickTheDevOpsGuyLinkedIn: @NickDoesDevOps

🏷 #NickDoesDevOps#LearningInPublic#BuiltInPublic