diff --git a/index.html b/index.html
new file mode 100644
index 0000000..480d363
--- /dev/null
+++ b/index.html
@@ -0,0 +1,27 @@
+
+
+
+
+
+ Space Jump
+
+
+
+
+
0
+
Нажми ПРОБЕЛ, чтобы начать
+
+
+
+
+
+
Игра окончена
+
Счёт: 0
+
Рекорд: 0
+
Пробел — заново
+
+
+
+
+
+
diff --git a/script.js b/script.js
new file mode 100644
index 0000000..3e9894a
--- /dev/null
+++ b/script.js
@@ -0,0 +1,134 @@
+const game = document.getElementById("game");
+const player = document.getElementById("player");
+const scoreEl = document.getElementById("score");
+const hintEl = document.getElementById("hint");
+const gameOverEl = document.getElementById("gameOver");
+const finalScoreEl = document.getElementById("finalScore");
+const bestScoreEl = document.getElementById("bestScore");
+
+const GROUND = 50; // высота земли
+const GRAVITY = 0.55;
+const JUMP_FORCE = 12;
+const START_SPEED = 5;
+
+let running = false;
+let gameOver = false;
+let playerY = 0; // высота над землёй
+let velocity = 0;
+let speed = START_SPEED;
+let score = 0;
+let best = Number(localStorage.getItem("spaceJumpBest")) || 0;
+let obstacles = [];
+let spawnTimer = 0;
+let lastTime = 0;
+
+function startGame() {
+ obstacles.forEach((o) => o.el.remove());
+ obstacles = [];
+ playerY = 0;
+ velocity = 0;
+ speed = START_SPEED;
+ score = 0;
+ spawnTimer = 0;
+ running = true;
+ gameOver = false;
+ hintEl.style.display = "none";
+ gameOverEl.classList.remove("visible");
+ scoreEl.textContent = "0";
+ lastTime = performance.now();
+ requestAnimationFrame(loop);
+}
+
+function jump() {
+ if (playerY === 0) {
+ velocity = JUMP_FORCE;
+ }
+}
+
+function spawnObstacle() {
+ const el = document.createElement("div");
+ el.className = "obstacle";
+ const height = 30 + Math.random() * 35;
+ el.style.height = height + "px";
+ game.appendChild(el);
+ obstacles.push({ el, x: game.clientWidth, height });
+}
+
+function endGame() {
+ running = false;
+ gameOver = true;
+ best = Math.max(best, score);
+ localStorage.setItem("spaceJumpBest", best);
+ finalScoreEl.textContent = score;
+ bestScoreEl.textContent = best;
+ gameOverEl.classList.add("visible");
+}
+
+function loop(now) {
+ if (!running) return;
+ const dt = Math.min((now - lastTime) / 16.67, 3); // нормализация к 60 FPS
+ lastTime = now;
+
+ // физика игрока
+ velocity -= GRAVITY * dt;
+ playerY += velocity * dt;
+ if (playerY <= 0) {
+ playerY = 0;
+ velocity = 0;
+ }
+ player.style.bottom = GROUND + playerY + "px";
+
+ // спавн препятствий
+ spawnTimer -= dt;
+ if (spawnTimer <= 0) {
+ spawnObstacle();
+ spawnTimer = 60 + Math.random() * 70;
+ }
+
+ // движение препятствий и столкновения
+ const playerLeft = 80;
+ const playerRight = playerLeft + 36;
+
+ for (let i = obstacles.length - 1; i >= 0; i--) {
+ const o = obstacles[i];
+ o.x -= speed * dt;
+ o.el.style.left = o.x + "px";
+
+ if (o.x + 22 < 0) {
+ o.el.remove();
+ obstacles.splice(i, 1);
+ score++;
+ scoreEl.textContent = score;
+ speed += 0.15; // чуть быстрее с каждым очком
+ continue;
+ }
+
+ const hitX = o.x < playerRight - 6 && o.x + 22 > playerLeft + 6;
+ const hitY = playerY < o.height - 4;
+ if (hitX && hitY) {
+ endGame();
+ return;
+ }
+ }
+
+ requestAnimationFrame(loop);
+}
+
+document.addEventListener("keydown", (e) => {
+ if (e.code !== "Space") return;
+ e.preventDefault();
+ if (!running) {
+ startGame();
+ } else {
+ jump();
+ }
+});
+
+// поддержка тапа/клика для мобильных
+game.addEventListener("pointerdown", () => {
+ if (!running) {
+ startGame();
+ } else {
+ jump();
+ }
+});
diff --git a/style.css b/style.css
new file mode 100644
index 0000000..2327a47
--- /dev/null
+++ b/style.css
@@ -0,0 +1,130 @@
+* {
+ margin: 0;
+ padding: 0;
+ box-sizing: border-box;
+}
+
+body {
+ min-height: 100vh;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ background: #12121c;
+ font-family: "Segoe UI", system-ui, sans-serif;
+}
+
+.game {
+ position: relative;
+ width: 800px;
+ max-width: 95vw;
+ height: 300px;
+ overflow: hidden;
+ border-radius: 12px;
+ background: linear-gradient(#1b2340, #2c3e66 70%, #3a5080);
+ box-shadow: 0 10px 40px rgba(0, 0, 0, 0.5);
+}
+
+.score {
+ position: absolute;
+ top: 14px;
+ right: 20px;
+ font-size: 28px;
+ font-weight: bold;
+ color: #fff;
+ text-shadow: 0 2px 4px rgba(0, 0, 0, 0.4);
+ z-index: 5;
+}
+
+.hint {
+ position: absolute;
+ top: 40%;
+ width: 100%;
+ text-align: center;
+ color: rgba(255, 255, 255, 0.85);
+ font-size: 20px;
+ letter-spacing: 1px;
+ z-index: 5;
+ animation: pulse 1.2s ease-in-out infinite;
+}
+
+@keyframes pulse {
+ 0%, 100% { opacity: 0.5; }
+ 50% { opacity: 1; }
+}
+
+.ground {
+ position: absolute;
+ bottom: 0;
+ width: 100%;
+ height: 50px;
+ background: #263238;
+ border-top: 4px solid #4caf7d;
+}
+
+.player {
+ position: absolute;
+ left: 80px;
+ bottom: 50px;
+ width: 36px;
+ height: 36px;
+ border-radius: 8px;
+ background: #ffca3a;
+ box-shadow: 0 0 12px rgba(255, 202, 58, 0.6);
+ z-index: 3;
+}
+
+.player::before,
+.player::after {
+ content: "";
+ position: absolute;
+ top: 9px;
+ width: 6px;
+ height: 6px;
+ border-radius: 50%;
+ background: #12121c;
+}
+
+.player::before { left: 7px; }
+.player::after { right: 7px; }
+
+.obstacle {
+ position: absolute;
+ bottom: 50px;
+ width: 22px;
+ border-radius: 4px 4px 0 0;
+ background: #e5484d;
+ box-shadow: 0 0 10px rgba(229, 72, 77, 0.5);
+ z-index: 2;
+}
+
+.game-over {
+ position: absolute;
+ inset: 0;
+ display: none;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ gap: 8px;
+ background: rgba(10, 10, 20, 0.75);
+ color: #fff;
+ z-index: 10;
+}
+
+.game-over.visible {
+ display: flex;
+}
+
+.game-over h1 {
+ font-size: 34px;
+ margin-bottom: 6px;
+}
+
+.game-over p {
+ font-size: 18px;
+ color: rgba(255, 255, 255, 0.9);
+}
+
+.restart-hint {
+ margin-top: 10px;
+ animation: pulse 1.2s ease-in-out infinite;
+}