diff --git a/snake_game.css b/snake_game.css
new file mode 100644
index 0000000..b14d1dd
--- /dev/null
+++ b/snake_game.css
@@ -0,0 +1,150 @@
+:root {
+ color-scheme: dark;
+ font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif;
+ --bg: #0f1116;
+ --card: #171b24;
+ --accent: #51d06c;
+ --accent-dark: #3aa653;
+ --grid: #1f2430;
+ --snake: #8cf5a9;
+ --food: #ff6666;
+ --text: #f5f7fa;
+}
+
+* {
+ box-sizing: border-box;
+}
+
+body {
+ margin: 0;
+ min-height: 100vh;
+ background: radial-gradient(circle at top, #202632, var(--bg));
+ color: var(--text);
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ padding: 1.5rem;
+}
+
+.layout {
+ width: min(720px, 100%);
+}
+
+.game-card {
+ background: var(--card);
+ border-radius: 18px;
+ box-shadow: 0 20px 40px rgba(0, 0, 0, 0.45);
+ padding: 2rem;
+ display: grid;
+ gap: 1.5rem;
+}
+
+.game-header h1 {
+ margin: 0 0 0.25rem;
+ font-size: clamp(1.6rem, 2vw + 1rem, 2.4rem);
+}
+
+.description {
+ margin: 0;
+ line-height: 1.5;
+ color: rgba(245, 247, 250, 0.78);
+}
+
+.scoreboard {
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ background: rgba(31, 36, 48, 0.9);
+ border-radius: 12px;
+ padding: 0.75rem 1rem;
+ font-weight: 600;
+ letter-spacing: 0.03em;
+}
+
+.score span {
+ font-variant-numeric: tabular-nums;
+ font-weight: 700;
+}
+
+canvas {
+ width: 100%;
+ max-width: 480px;
+ justify-self: center;
+ background: repeating-linear-gradient(
+ 0deg,
+ rgba(255, 255, 255, 0.025),
+ rgba(255, 255, 255, 0.025) 24px,
+ rgba(15, 17, 22, 0.1) 24px,
+ rgba(15, 17, 22, 0.1) 48px
+ ),
+ repeating-linear-gradient(
+ 90deg,
+ rgba(255, 255, 255, 0.025),
+ rgba(255, 255, 255, 0.025) 24px,
+ rgba(15, 17, 22, 0.1) 24px,
+ rgba(15, 17, 22, 0.1) 48px
+ ),
+ var(--grid);
+ border-radius: 12px;
+ border: 1px solid rgba(255, 255, 255, 0.08);
+}
+
+.controls {
+ display: flex;
+ gap: 0.75rem;
+ justify-content: center;
+}
+
+button {
+ border: none;
+ border-radius: 999px;
+ padding: 0.6rem 1.6rem;
+ font-size: 1rem;
+ font-weight: 600;
+ cursor: pointer;
+ transition: transform 0.15s ease, box-shadow 0.15s ease;
+ background: rgba(255, 255, 255, 0.08);
+ color: var(--text);
+}
+
+button.primary {
+ background: linear-gradient(135deg, var(--accent), var(--accent-dark));
+ color: #0c150f;
+ box-shadow: 0 12px 20px rgba(81, 208, 108, 0.35);
+}
+
+button:hover,
+button:focus-visible {
+ transform: translateY(-2px);
+ box-shadow: 0 14px 22px rgba(0, 0, 0, 0.2);
+ outline: none;
+}
+
+button:disabled {
+ cursor: not-allowed;
+ opacity: 0.55;
+ transform: none;
+ box-shadow: none;
+}
+
+.message {
+ min-height: 1.5rem;
+ text-align: center;
+ font-weight: 600;
+ letter-spacing: 0.04em;
+}
+
+@media (max-width: 640px) {
+ body {
+ padding: 1rem;
+ }
+
+ .game-card {
+ padding: 1.5rem;
+ gap: 1rem;
+ }
+
+ .scoreboard {
+ font-size: 0.95rem;
+ }
+}
diff --git a/snake_game.html b/snake_game.html
new file mode 100644
index 0000000..392c7db
--- /dev/null
+++ b/snake_game.html
@@ -0,0 +1,40 @@
+
+
+
+
+
+ Snake
+
+
+
+
+
+
+
+
+
+ Start game
+ Pause
+
+
+
+
+
+
+
diff --git a/snake_game.js b/snake_game.js
new file mode 100644
index 0000000..ec2cff8
--- /dev/null
+++ b/snake_game.js
@@ -0,0 +1,223 @@
+const canvas = document.getElementById("game-canvas");
+const ctx = canvas.getContext("2d");
+const scoreValue = document.getElementById("score-value");
+const bestValue = document.getElementById("best-value");
+const message = document.getElementById("message");
+const startButton = document.getElementById("start-button");
+const pauseButton = document.getElementById("pause-button");
+
+const tileCount = 24;
+const tileSize = canvas.width / tileCount;
+const baseSpeed = 120;
+
+const directionMap = {
+ ArrowUp: { x: 0, y: -1 },
+ ArrowDown: { x: 0, y: 1 },
+ ArrowLeft: { x: -1, y: 0 },
+ ArrowRight: { x: 1, y: 0 },
+ w: { x: 0, y: -1 },
+ s: { x: 0, y: 1 },
+ a: { x: -1, y: 0 },
+ d: { x: 1, y: 0 },
+};
+
+let snake = [];
+let direction = { x: 1, y: 0 };
+let pendingDirection = { x: 1, y: 0 };
+let food = null;
+let score = 0;
+let bestScore = Number(localStorage.getItem("snake-best-score")) || 0;
+let intervalId = null;
+let isPaused = false;
+let isRunning = false;
+
+bestValue.textContent = bestScore.toString();
+
+function resetGame() {
+ snake = [
+ { x: Math.floor(tileCount / 2), y: Math.floor(tileCount / 2) },
+ { x: Math.floor(tileCount / 2) - 1, y: Math.floor(tileCount / 2) },
+ ];
+ direction = { x: 1, y: 0 };
+ pendingDirection = { x: 1, y: 0 };
+ score = 0;
+ food = spawnFood();
+ updateScore(0);
+ message.textContent = "";
+}
+
+function spawnFood() {
+ while (true) {
+ const position = {
+ x: Math.floor(Math.random() * tileCount),
+ y: Math.floor(Math.random() * tileCount),
+ };
+
+ if (!snake.some((segment) => segment.x === position.x && segment.y === position.y)) {
+ return position;
+ }
+ }
+}
+
+function updateScore(delta) {
+ score += delta;
+ scoreValue.textContent = score.toString();
+ if (score > bestScore) {
+ bestScore = score;
+ bestValue.textContent = bestScore.toString();
+ localStorage.setItem("snake-best-score", bestScore.toString());
+ }
+}
+
+function drawBoard() {
+ ctx.fillStyle = "#0f1116";
+ ctx.fillRect(0, 0, canvas.width, canvas.height);
+}
+
+function drawSnake() {
+ ctx.fillStyle = "#8cf5a9";
+ snake.forEach((segment, index) => {
+ const radius = index === 0 ? 10 : 8;
+ drawCell(segment.x, segment.y, radius);
+ });
+}
+
+function drawFood() {
+ if (!food) return;
+ ctx.fillStyle = "#ff6666";
+ drawCell(food.x, food.y, 10);
+}
+
+function drawCell(x, y, radius) {
+ const centerX = x * tileSize + tileSize / 2;
+ const centerY = y * tileSize + tileSize / 2;
+ ctx.beginPath();
+ ctx.arc(centerX, centerY, radius, 0, Math.PI * 2);
+ ctx.fill();
+}
+
+function step() {
+ if (isPaused) {
+ return;
+ }
+
+ direction = validateDirectionChange(direction, pendingDirection);
+
+ const nextHead = {
+ x: snake[0].x + direction.x,
+ y: snake[0].y + direction.y,
+ };
+
+ if (hasCollision(nextHead)) {
+ endGame();
+ return;
+ }
+
+ snake.unshift(nextHead);
+
+ if (food && nextHead.x === food.x && nextHead.y === food.y) {
+ updateScore(1);
+ food = spawnFood();
+ adjustSpeed();
+ } else {
+ snake.pop();
+ }
+
+ draw();
+}
+
+function validateDirectionChange(current, next) {
+ if (current.x + next.x === 0 && current.y + next.y === 0) {
+ return current;
+ }
+ return next;
+}
+
+function hasCollision(head) {
+ const outOfBounds =
+ head.x < 0 || head.x >= tileCount || head.y < 0 || head.y >= tileCount;
+ if (outOfBounds) {
+ return true;
+ }
+
+ return snake.some((segment) => segment.x === head.x && segment.y === head.y);
+}
+
+function draw() {
+ drawBoard();
+ drawFood();
+ drawSnake();
+}
+
+function startGame() {
+ resetGame();
+ draw();
+ isRunning = true;
+ isPaused = false;
+ setButtons();
+ scheduleNextTick(baseSpeed);
+}
+
+function pauseGame() {
+ if (!isRunning) {
+ return;
+ }
+ isPaused = !isPaused;
+ setButtons();
+}
+
+function endGame() {
+ clearInterval(intervalId);
+ intervalId = null;
+ isRunning = false;
+ message.textContent = `Game over! Final score: ${score}. Press Space to try again.`;
+ startButton.disabled = false;
+ pauseButton.disabled = true;
+}
+
+function scheduleNextTick(speed) {
+ clearInterval(intervalId);
+ intervalId = setInterval(step, speed);
+}
+
+function adjustSpeed() {
+ const speed = Math.max(60, baseSpeed - Math.floor(score / 5) * 10);
+ scheduleNextTick(speed);
+}
+
+function setButtons() {
+ startButton.disabled = isRunning;
+ pauseButton.disabled = !isRunning;
+ pauseButton.textContent = isPaused ? "Resume" : "Pause";
+ message.textContent = isPaused ? "Paused" : "";
+}
+
+function handleKeydown(event) {
+ const key = event.key;
+ if (directionMap[key]) {
+ event.preventDefault();
+ pendingDirection = directionMap[key];
+ } else if (key === " " || key === "Spacebar") {
+ event.preventDefault();
+ if (!isRunning) {
+ startGame();
+ } else {
+ pauseGame();
+ }
+ } else if (key === "Enter" && !isRunning) {
+ startGame();
+ }
+}
+
+startButton.addEventListener("click", () => {
+ if (!isRunning) {
+ startGame();
+ }
+});
+
+pauseButton.addEventListener("click", pauseGame);
+window.addEventListener("keydown", handleKeydown, { passive: false });
+
+draw();
+setButtons();
+message.textContent = "Press Start or Space to begin.";