```
<!DOCTYPE html>
<html lang="ru">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Snake Game — Поиграй в Змейку</title>
<style>
  @import url('https://fonts.googleapis.com/css2?family=Montserrat:wght@400;700&display=swap');

  * {
    box-sizing: border-box;
  }

  body, html {
    margin: 0;
    padding: 0;
    height: 100%;
    font-family: 'Montserrat', sans-serif;
    background:
      radial-gradient(circle at center, #0f2027 0%, #203a43 60%, #2c5364 100%);
    color: #fff;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: flex-start;
    overflow-x: hidden;
  }

  /* Анимированный фон частиц */
  #particles {
    position: fixed;
    top: 0; left: 0;
    width: 100vw; height: 100vh;
    pointer-events: none;
    z-index: 0;
    mix-blend-mode: screen;
  }

  header {
    width: 100%;
    padding: 2rem 1rem;
    background: #111;
    box-shadow: 0 4px 15px rgba(0,0,0,0.7);
    text-align: center;
    position: sticky;
    top: 0;
    z-index: 10;
  }

  header h1 {
  margin: 0;
  font-size: 3rem;
  letter-spacing: 3px;
  text-transform: uppercase;
  background: linear-gradient(90deg, #00ff99, #00ccff);
  background-clip: text;
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  user-select: none;
  text-shadow:
    0 0 5px #00ff99,
    0 0 10px #00ccff;
  animation: glow 3s ease-in-out infinite alternate;
}

  @keyframes glow {
    from {
      filter: drop-shadow(0 0 10px #00ff99);
    }
    to {
      filter: drop-shadow(0 0 20px #00ccff);
    }
  }

  main {
    margin: 3rem 0 5rem;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 1.8rem;
    width: 100%;
    max-width: 700px;
    padding: 0 1rem;
    z-index: 5;
    position: relative;
  }

  .scoreboard {
    font-size: 1.75rem;
    font-weight: 800;
    color: #00ff99;
    letter-spacing: 1.5px;
    text-shadow:
      0 0 10px #00ff99,
      0 0 18px #00ccff;
    user-select: none;
    min-width: 140px;
    text-align: center;
    background: rgba(0,0,0,0.3);
    padding: 0.5rem 1rem;
    border-radius: 12px;
    backdrop-filter: blur(5px);
  }

  .game-container {
    position: relative;
    width: 600px;
    height: 600px;
    background: #111;
    border-radius: 25px;
    box-shadow:
      0 0 40px #00ff99,
      inset 0 0 50px #00ff99;
    display: flex;
    justify-content: center;
    align-items: center;
    overflow: hidden;
  }

  canvas {
    background: #222;
    border-radius: 25px;
    box-shadow:
      0 0 25px #00ccff;
    cursor: grab;
    image-rendering: pixelated;
  }

  canvas:active {
    cursor: grabbing;
  }

  button {
    margin-top: 1rem;
    padding: 0.85rem 2rem;
    font-size: 1.25rem;
    border: none;
    border-radius: 50px;
    background: linear-gradient(90deg, #00ff99, #00ccff);
    color: #111;
    font-weight: 700;
    cursor: pointer;
    box-shadow:
      0 0 15px #00ff99,
      0 0 30px #00ccff;
    transition: background 0.3s ease, box-shadow 0.3s ease, transform 0.2s ease;
    user-select: none;
    letter-spacing: 0.05em;
  }

  button:hover {
    background: linear-gradient(90deg, #00ccff, #00ff99);
    box-shadow:
      0 0 30px #00ccff,
      0 0 40px #00ff99;
    transform: scale(1.05);
  }

  button:active {
    transform: scale(0.95);
  }

  footer {
    margin-top: auto;
    padding: 1rem;
    width: 100%;
    text-align: center;
    background: #111;
    color: #666;
    font-size: 0.9rem;
    user-select: none;
    position: relative;
    z-index: 5;
  }

  @media (max-width: 700px) {
    .game-container {
      width: 90vw;
      height: 90vw;
    }
    canvas {
      width: 90vw !important;
      height: 90vw !important;
    }
  }
</style>
</head>
<body>

<div id="particles"></div>

<header>
  <h1>Змейка</h1>
</header>

<main>
  <div class="scoreboard" aria-live="polite" aria-atomic="true" id="scoreboard">
    Счёт: <span id="score">0</span>
  </div>

  <div class="game-container" role="region" aria-label="Игра Змейка" tabindex="0">
    <canvas id="gameCanvas" width="600" height="600" aria-label="Игровое поле Змейки"></canvas>
  </div>

  <button id="restartBtn" aria-label="Начать заново">Начать заново</button>
</main>

<footer>
  &copy; 2024 Профессиональный сайт с игрой Змейка. Все права защищены.
</footer>

<script>
(() => {
  const canvas = document.getElementById('gameCanvas');
  const ctx = canvas.getContext('2d');
  const scoreElem = document.getElementById('score');
  const restartBtn = document.getElementById('restartBtn');
  const scoreboard = document.getElementById('scoreboard');

  const COLS = 30;
  const ROWS = 30;
  const CELL_SIZE = canvas.width / COLS;

  // Змейка и еда
  let snake = [];
  let direction = { x: 1, y: 0 };
  let nextDirection = direction; // для плавного обновления направления
  let food = {};
  let score = 0;
  let gameSpeed = 100;  // базовая скорость в мс, чем меньше — тем быстрее
  let speedModifier = 1;
  let gameInterval = null;

  // Бонусы
  const bonusTypes = {
    speedUp: 'speedUp',
    slowDown: 'slowDown',
    doubleScore: 'doubleScore',
  };
  let bonus = null; // {type, x, y, duration, activeTime}
  let bonusActive = null;

  // Аудио сигналы
  const eatSound = new Audio('https://cdn.jsdelivr.net/gh/freeCodeCamp/cdn/audio/score.mp3');
  const bonusSound = new Audio('https://freesound.org/data/previews/250/250629_4486188-lq.mp3');

  // Плавный переход цвета головы змейки
  let headHue = 180;

  // Частицы при поедании еды и бонусов
  class Particle {
    constructor(x, y, color) {
      this.x = x;
      this.y = y;
      this.size = Math.random() * 4 + 2;
      this.color = color;
      this.speedX = (Math.random() - 0.5) * 3;
      this.speedY = (Math.random() - 0.5) * 3;
      this.life = 25;
      this.opacity = 1;
    }
    update() {
      this.x += this.speedX;
      this.y += this.speedY;
      this.life--;
      this.opacity = this.life / 25;
    }
    draw(ctx) {
      ctx.save();
      ctx.globalAlpha = this.opacity;
      ctx.fillStyle = this.color;
      ctx.beginPath();
      ctx.arc(this.x, this.y, this.size, 0, Math.PI * 2);
      ctx.fill();
      ctx.restore();
    }
  }

  let particles = [];

  // Функция для создания частиц
  function createParticles(gridX, gridY, color) {
    const centerX = gridX * CELL_SIZE + CELL_SIZE / 2;
    const centerY = gridY * CELL_SIZE + CELL_SIZE / 2;
    for(let i = 0; i < 15; i++) {
      particles.push(new Particle(centerX, centerY, color));
    }
  }

  // Функция отрисовки частиц
  function drawParticles() {
    particles.forEach((p, i) => {
      p.update();
      p.draw(ctx);
      if (p.life <= 0) particles.splice(i, 1);
    });
  }

  // Генерирует случайное целое число в диапазоне [min, max]
  function randomInt(min, max) {
    return Math.floor(Math.random() * (max - min + 1)) + min;
  }

  // Инициализация змейки и игры
  function init() {
    snake = [
      { x: 10, y: 15 },
      { x: 9, y: 15 },
      { x: 8, y: 15 },
    ];
    direction = { x: 1, y: 0 };
    nextDirection = direction;
    score = 0;
    speedModifier = 1;
    bonus = null;
    bonusActive = null;

    updateScore();
    placeFood();
    placeBonus();

    if (gameInterval) clearInterval(gameInterval);
    gameInterval = setInterval(gameLoop, gameSpeed);

    // обновляем заголовок и доступность кнопок
    restartBtn.disabled = false;
    restartBtn.textContent = "Начать заново";
  }

  function updateScore() {
    scoreElem.textContent = score;
  }

  // Помещаем еду в случайное свободное место
  function placeFood() {
    let newFoodPos;
    do {
      newFoodPos = {
        x: Math.floor(Math.random() * COLS),
        y: Math.floor(Math.random() * ROWS),
      };
    } while (snake.some(s => s.x === newFoodPos.x && s.y === newFoodPos.y) ||
             (bonus && bonus.x === newFoodPos.x && bonus.y === newFoodPos.y));
    food = newFoodPos;
  }

  // Помещаем бонус (с вероятностью 30%) в случайное свободное место
  function placeBonus() {
    // Вероятность появления бонуса
    if (Math.random() > 0.3) {
      bonus = null;
      return;
    }

    const types = Object.values(bonusTypes);
    let newBonusPos;
    do {
      newBonusPos = {
        x: Math.floor(Math.random() * COLS),
        y: Math.floor(Math.random() * ROWS),
      };
    } while (snake.some(s => s.x === newBonusPos.x && s.y === newBonusPos.y) ||
             (food.x === newBonusPos.x && food.y === newBonusPos.y));

    bonus = {
      x: newBonusPos.x,
      y: newBonusPos.y,
      type: types[randomInt(0, types.length-1)],
      duration: 6000, // бонус действует 6 секунд
      activeTime: 0,
    };
  }

  // Рисуем клетку с опцией свечения
  function drawCell(x, y, color, glow = false) {
    ctx.fillStyle = color;
    ctx.shadowColor = glow ? color : 'transparent';
    ctx.shadowBlur = glow ? 15 : 0;
    ctx.fillRect(x * CELL_SIZE, y * CELL_SIZE, CELL_SIZE, CELL_SIZE);
    ctx.shadowBlur = 0;
  }

  // Рисуем сетку
  function drawGrid() {
    ctx.strokeStyle = 'rgba(255,255,255,0.05)';
    ctx.lineWidth = 1;
    for (let i = 0; i <= COLS; i++) {
      ctx.beginPath();
      ctx.moveTo(i * CELL_SIZE, 0);
      ctx.lineTo(i * CELL_SIZE, canvas.height);
      ctx.stroke();
    }
    for (let i = 0; i <= ROWS; i++) {
      ctx.beginPath();
      ctx.moveTo(0, i * CELL_SIZE);
      ctx.lineTo(canvas.width, i * CELL_SIZE);
      ctx.stroke();
    }
  }

  // Плавное изменение цвета головы змейки (меняем hue)
  function getHeadColor() {
    headHue += 1;
    if (headHue > 360) headHue = 0;
    return `hsl(${headHue}, 100%, 50%)`;
  }

  // Отрисовываем змейку, еду, бонус и частицы
  function draw() {
    ctx.clearRect(0, 0, canvas.width, canvas.height);
    drawGrid();

    // Рисуем еду с эффектом свечения
    drawCell(food.x, food.y, '#00ff99', true);

    // Рисуем бонус (если есть) по типу цвета
    if (bonus) {
      let color;
      switch (bonus.type) {
        case bonusTypes.speedUp: color = '#ff4d4d'; break;       // красный - ускорение
        case bonusTypes.slowDown: color = '#4d79ff'; break;      // синий - замедление
        case bonusTypes.doubleScore: color = '#ffcc00'; break;   // желтый - удвоение счета
        default: color = '#fff'; break;
      }
      // Небольшая пульсация бонуса
      const pulse = 0.7 + 0.3 * Math.sin(Date.now() / 300);
      ctx.save();
      ctx.globalAlpha = pulse;
      drawCell(bonus.x, bonus.y, color, true);
      ctx.restore();
    }

    // Змейка с градиентом для тела и меняющейся головой
    const headColor = getHeadColor();
    snake.forEach((segment, i) => {
      if(i === 0) {
        drawCell(segment.x, segment.y, headColor, true);
      } else {
        // тело от зеленого к синим с градиентом по позиции
        const t = i / snake.length;
        const r = Math.floor(0 + t * (0 - 0));
        const g = Math.floor(255 - t * 100);
        const b = Math.floor(153 + t * 102);
        drawCell(segment.x, segment.y, `rgb(${r},${g},${b})`);
      }
    });

    drawParticles();
  }

  // Перемещаем змейку и обрабатываем столкновения
  function moveSnake() {
    // Обновляем направление, если не противоположно текущему
    if (Math.abs(nextDirection.x) !== Math.abs(direction.x) ||
        Math.abs(nextDirection.y) !== Math.abs(direction.y)) {
      direction = nextDirection;
    }

    const head = { x: snake[0].x + direction.x, y: snake[0].y + direction.y };

    // Телепортация через стены
    if (head.x < 0) head.x = COLS - 1;
    if (head.x >= COLS) head.x = 0;
    if (head.y < 0) head.y = ROWS - 1;
    if (head.y >= ROWS) head.y = 0;

    // Проверяем столкновение с телом
    if (snake.some(s => s.x === head.x && s.y === head.y)) {
      gameOver();
      return false;
    }

    snake.unshift(head);

    // Проверяем съедена ли еда
    if (head.x === food.x && head.y === food.y) {
      // Увеличиваем счёт
      if (bonusActive && bonusActive.type === bonusTypes.doubleScore) {
        score += 2;
      } else {
        score += 1;
      }
      updateScore();
      eatSound.currentTime = 0;
      eatSound.play();
      createParticles(food.x, food.y, '#00ff99');
      placeFood();
      // С вероятностью 30% появляется бонус
      if (!bonus) placeBonus();
    } else {
      snake.pop();
    }

    // Проверяем бонус
    if (bonus && head.x === bonus.x && head.y === bonus.y) {
      activateBonus(bonus);
      bonus = null;
    }

    return true;
  }

  // Активируем бонус и запускаем таймер
  function activateBonus(b) {
    bonusActive = b;
    bonusSound.currentTime = 0;
    bonusSound.play();
    createParticles(b.x, b.y, '#ffff55');

    // Изменяем параметры в зависимости от типа бонуса
    switch (b.type) {
      case bonusTypes.speedUp:
        speedModifier = 0.6;  // игра ускоряется
        break;
      case bonusTypes.slowDown:
        speedModifier = 1.6;  // игра замедляется
        break;
      case bonusTypes.doubleScore:
        speedModifier = 1;
        break;
    }

    // Таймер деактивации бонуса
    setTimeout(() => {
      bonusActive = null;
      speedModifier = 1;
    }, b.duration);
  }

  function gameOver() {
    clearInterval(gameInterval);

    ctx.fillStyle = 'rgba(0, 0, 0, 0.85)';
    ctx.fillRect(0, 0, canvas.width, canvas.height);

    ctx.fillStyle = '#00ff99';
    ctx.font = 'bold 60px Montserrat, sans-serif';
    ctx.textAlign = 'center';
    ctx.fillText('Game Over!', canvas.width / 2, canvas.height / 2 - 40);

    ctx.font = '28px Montserrat, sans-serif';
    ctx.fillText(`Ваш счёт: ${score}`, canvas.width / 2, canvas.height / 2 + 20);

    // Отключаем кнопку рестарта на 1 секунду, чтобы избежать спама
    restartBtn.disabled = true;
    setTimeout(() => restartBtn.disabled = false, 1000);
  }

  // Обновляет таймер и скорость игры для плавности
  function gameLoop() {
    if (!moveSnake()) return;

    draw();
  }

  // Обработка клавиш (стрелки и WASD)
  function handleKey(e) {
    const key = e.key.toLowerCase();
    const allowedKeys = ['arrowup', 'w','arrowdown','s','arrowleft','a','arrowright','d'];
    if(!allowedKeys.includes(key)) return;

    // Запрещаем сразу менять направление на противоположное (судя по текущему движению)
    if (key === 'arrowup' || key === 'w') {
      if (direction.y !== 1) nextDirection = { x: 0, y: -1 };
    } else if (key === 'arrowdown' || key === 's') {
      if (direction.y !== -1) nextDirection = { x: 0, y: 1 };
    } else if (key === 'arrowleft' || key === 'a') {
      if (direction.x !== 1) nextDirection = { x: -1, y: 0 };
    } else if (key === 'arrowright' || key === 'd') {
      if (direction.x !== -1) nextDirection = { x: 1, y: 0 };
    }
  }

  // Перезапускаем игру с новой скоростью и учитываем бонус
  function refreshInterval() {
    if (gameInterval) clearInterval(gameInterval);
    gameInterval = setInterval(gameLoop, gameSpeed * speedModifier);
  }

  // Следим за изменением скорости при активации/деактивации бонуса
  let lastSpeedModifier = speedModifier;
  setInterval(() => {
    if(lastSpeedModifier !== speedModifier) {
      refreshInterval();
      lastSpeedModifier = speedModifier;
    }
  }, 100);

  // Акселерация для тач-данных (мобильные устройства)
  let touchStartX = null;
  let touchStartY = null;
  const swipeThreshold = 30;

  function onTouchStart(e) {
    const t = e.touches[0];
    touchStartX = t.clientX;
    touchStartY = t.clientY;
  }
  function onTouchMove(e) {
    if(!touchStartX || !touchStartY) return;
    const t = e.touches[0];
    const dx = t.clientX - touchStartX;
    const dy = t.clientY - touchStartY;

    if (Math.abs(dx) > Math.abs(dy)) {
      if (dx > swipeThreshold && direction.x !== -1) nextDirection = {x:1,y:0};
      else if (dx < -swipeThreshold && direction.x !== 1) nextDirection = {x:-1,y:0};
    } else {
      if (dy > swipeThreshold && direction.y !== -1) nextDirection = {x:0,y:1};
      else if (dy < -swipeThreshold && direction.y !== 1) nextDirection = {x:0,y:-1};
    }

    touchStartX = null;
    touchStartY = null;
  }


  // Частицы фоновая анимация (мелкие светящиеся точки)
  class BackgroundParticle {
    constructor(width, height) {
      this.x = Math.random() * width;
      this.y = Math.random() * height;
      this.radius = Math.random() * 1.2 + 0.3;
      this.alpha = Math.random() * 0.7 + 0.3;
      this.speed = Math.random() * 0.05 + 0.01;
      this.width = width;
      this.height = height;
      this.direction = Math.random() < 0.5 ? 1 : -1;
    }
    update() {
      this.alpha += this.speed * this.direction;
      if (this.alpha >= 1) {
        this.alpha = 1;
        this.direction = -1;
      } else if (this.alpha <= 0.3) {
        this.alpha = 0.3;
        this.direction = 1;
      }
    }
    draw(ctx) {
      ctx.save();
      ctx.globalAlpha = this.alpha;
      ctx.fillStyle = '#00ffcc';
      ctx.shadowColor = '#00ffcc';
      ctx.shadowBlur = 15;
      ctx.beginPath();
      ctx.arc(this.x, this.y, this.radius, 0, 2 * Math.PI);
      ctx.fill();
      ctx.restore();
    }
  }

  // Рендеринг фоновых частиц
  const particlesCanvas = document.createElement('canvas');
  const particlesCtx = particlesCanvas.getContext('2d');
  let particlesArray = [];

  function initBackgroundParticles() {
    const particlesDiv = document.getElementById('particles');
    particlesDiv.appendChild(particlesCanvas);
    particlesCanvas.width = window.innerWidth;
    particlesCanvas.height = window.innerHeight;
    generateParticles();
  }

  function generateParticles() {
    particlesArray = [];
    for (let i = 0; i < 150; i++) {
      particlesArray.push(new BackgroundParticle(particlesCanvas.width, particlesCanvas.height));
    }
  }

  function animateBackgroundParticles() {
    particlesCtx.clearRect(0, 0, particlesCanvas.width, particlesCanvas.height);
    particlesArray.forEach(p => {
      p.update();
      p.draw(particlesCtx);
    });
    requestAnimationFrame(animateBackgroundParticles);
  }

  window.addEventListener('resize', () => {
    particlesCanvas.width = window.innerWidth;
    particlesCanvas.height = window.innerHeight;
    generateParticles();
  });

  // --- Запуск ---
  initBackgroundParticles();
  animateBackgroundParticles();

  restartBtn.addEventListener('click', () => {
    init();
  });

  window.addEventListener('keydown', handleKey);
  canvas.addEventListener('touchstart', onTouchStart, {passive: true});
  canvas.addEventListener('touchmove', onTouchMove, {passive: true});

  init();

})();
</script>

</body>
</html>
```
Преобразуй следующий код, чтобы он соответствовал уровню senior-разработчика: используй объектно-ориентированное программирование с инкапсуляцией, абстракцией и наследованием там, где это уместно, сделай архитектуру модульной, расширяемой и поддерживаемой, оптимизируй производительность и читаемость, улучшай именования переменных, функций и классов, устраняй дублирование кода, применяй подходящие паттерны проектирования для гибкости и масштабируемости, внедри обработку ошибок с информативными сообщениями и обеспечь логирование ключевых событий, добавь подробные комментарии и документацию к основным классам и методам, обеспечь финальный код простым для понимания, тестирования и поддержки.