Projet personnel · Jeu navigateur

Snake
Game

Recréation du classique Snake en vanilla JavaScript — moteur de jeu maison, rendu canvas, responsive mobile-first avec d-pad tactile et système de niveaux.

Déployé · GitHub Pages Vanilla JS · No Framework HTML · CSS · JavaScript Responsive · Mobile-first

Aperçu de l'interface

Rendu navigateur — état en jeu
the-web-girl.github.io/snake-game/
🐍 SNAKE MEILLEUR 150
090
2
9
Langages
JS 65%
CSS 27%
HTML 8%
Structure
3
fichiers sources
index.html · style.css · game.js
Compatibilité
320px+
largeur minimale supportée
PC & mobile, tous navigateurs modernes
Présentation du projet

Snake Game est une réinterprétation complète du jeu classique, développée entièrement en JavaScript natif sans aucune bibliothèque externe. Le moteur de jeu gère une boucle d'animation fluide via requestAnimationFrame, le rendu sur un élément <canvas>, et une gestion d'états complète (menu, jeu, pause, game over).

Le projet met l'accent sur l'accessibilité multi-plateforme : contrôles clavier classiques sur desktop, swipe gestuel et D-pad virtuel sur mobile, avec un layout entièrement responsive dès 320 px.

Fonctionnalités clés
  • Moteur de jeu maison — boucle game loop avec RAF, gestion d'états finie
  • Système de niveaux — vitesse progressive, +1 niveau tous les 5 fruits (max 10)
  • Score dynamique — calcul niveau × 10 par pomme + meilleur score persistant
  • D-pad tactile — contrôles on-screen + swipe gesture sur la grille
  • Pause / reprise — Espace, P, ou bouton d-pad
  • Zéro dépendance — vanilla JS, déploiement sans build tool

Extraits de code

index.html HTML
<!-- Structure HTML minimaliste — 44 lignes -->
<div id="arena">
  <canvas id="gameCanvas"></canvas>

  <div id="overlay">
    <div id="overlay-title">SNAKE</div>
    <div id="overlay-sub">Flèches / WASD<br>ou balayage tactile</div>
    <button id="btn-start">JOUER</button>
  </div>
</div>

<!-- D-Pad mobile —>
<div id="dpad">
  <div class="dpad-btn" id="btn-up"></div>
  <div class="dpad-btn" id="btn-left"></div>
  <div class="dpad-btn" id="btn-pause"></div>
  <div class="dpad-btn" id="btn-right"></div>
  <div class="dpad-btn" id="btn-down"></div>
</div>

<script src="game.js"></script>
game.js — Logique principale JavaScript
// ── Constantes de configuration ──────────────────────
const GRID     = 20;          // cellules par côté
const BASE_MS  = 200;         // intervalle initial (ms)
const SCORE_PER_APPLE = 10;  // × niveau courant
const APPLE_PER_LEVEL = 5;   // pommes avant niveau+1
const MAX_LEVEL = 10;

// ── Boucle de jeu ────────────────────────────────────
function gameLoop(timestamp) {
  if (timestamp - lastTime < getInterval()) {
    requestAnimationFrame(gameLoop); return;
  }
  lastTime = timestamp;
  update();   // avance le serpent, détecte collisions
  render();   // redessine le canvas
  requestAnimationFrame(gameLoop);
}

// ── Vitesse progressive selon le niveau ──────────────
function getInterval() {
  return BASE_MS - (level - 1) * 18;
}

// ── Détection de collision ────────────────────────────
function checkCollision(head) {
  if (head.x < 0 || head.x >= GRID ||
      head.y < 0 || head.y >= GRID) return true;
  return snake.some(seg => seg.x === head.x
                            && seg.y === head.y);
}

// ── Swipe tactile ─────────────────────────────────────
arena.addEventListener('touchstart', e => {
  touchStart = { x: e.touches[0].clientX,
                  y: e.touches[0].clientY };
});
arena.addEventListener('touchend', e => {
  const dx = e.changedTouches[0].clientX - touchStart.x;
  const dy = e.changedTouches[0].clientY - touchStart.y;
  handleSwipe(dx, dy);
});
style.css — Responsive & D-pad CSS
/* Grille centrale responsive */
#arena {
  position: relative;
  width: min(90vw, 90vh, 480px);
  aspect-ratio: 1 / 1;
  margin: 0 auto;
}

/* D-pad mobile — disposition en croix */
#dpad {
  display: grid;
  grid-template-columns: repeat(3, 52px);
  grid-template-rows: repeat(3, 52px);
  gap: 4px;
  justify-content: center;
  margin-top: 16px;
}

/* Masqué sur desktop (pointer: fine) */
@media (pointer: fine) {
  #dpad { display: none; }
}

/* Score bar */
#score-bar {
  display: flex;
  justify-content: space-around;
  max-width: min(90vw, 480px);
  margin: 8px auto;
}

Architecture du projet

Organisation des fichiers
snake-game/ ├── index.html Structure HTML, HUD (score/niveau/pommes), canvas, D-pad ├── style.css Layout responsive, overlay menu, D-pad, animations ├── game.js Moteur complet : game loop, états, rendu canvas, input ├── Capt.png Capture d'écran pour le README ├── README.md Documentation (contrôles, règles, compatibilité) └── Snake-Game.zip Archive téléchargeable du projet
Flux de données
Input clavier / swipe / D-pad directionQueue file de directions (anti-retournement instantané) update() avance tête, détecte collision mur / corps, mange pomme render() redessine canvas (clearRect + fillRect par segment) updateHUD() met à jour score, niveau, pommes dans le DOM
Contrôles
PlateformeActionTouches
DesktopDéplacement / WASD
DesktopPauseEspace / P
MobileDéplacementSwipe sur la grille
MobileD-padBoutons ▲◀⏸▶▼
Règles du jeu
  • Scoreniveau × 10 points par pomme mangée
  • Progression — niveau +1 tous les 5 fruits, jusqu'au niveau 10 maximum
  • Vitesse — intervalle réduit de 18 ms par niveau (de 200 ms à ~38 ms)
  • Fin de partie — collision avec un mur ou avec son propre corps
  • Meilleur score — persisté dans localStorage entre les parties
Stack technique
JavaScript ES6+
HTML5 Canvas
CSS Grid
requestAnimationFrame
Touch Events API
LocalStorage
GitHub Pages
No build tool
Compatibilité
Chrome Firefox Safari Edge iOS Safari Android Chrome 320 px+

Aucune installation requise. Ouvrir index.html directement dans un navigateur, ou accéder à la démo GitHub Pages déployée automatiquement.

Points forts techniques

Moteur de jeu
Game Loop RAF

Utilisation de requestAnimationFrame avec delta-time pour un framerate stable indépendant du matériel. La vitesse du serpent est contrôlée par un intervalle configurable décroissant avec le niveau.

Mobile UX
Double input tactile

Support simultané du swipe gestuel sur la grille canvas ET d'un D-pad visuel CSS Grid. Le D-pad est affiché uniquement sur les appareils tactiles via @media (pointer: coarse).

Architecture
Zero dépendance

Projet 100 % vanilla — aucun framework, aucun bundler, aucun npm. Déploiement immédiat sur GitHub Pages sans pipeline CI/CD. Idéal pour démontrer la maîtrise des API natives du navigateur.