JustPaste
HomeCategoriesAboutDonateContactTerms of UsePrivacy Policy
JustPaste

Free online notepad — write and share instantly

Navigate

  • Home
  • Timeline
  • Categories

Info

  • About
  • Donate
  • Contact

Legal

  • Terms of Use
  • Privacy Policy

© 2026 JustPaste.app. All rights reserved.

Made with ♥ by JustPaste

game | JustPaste.app
about 1 month ago3 views
👨‍💻Programming

game

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Star Runner</title>
  <style>
    * {
      box-sizing: border-box;
    }

    body {
      min-height: 100vh;
      margin: 0;
      display: grid;
      place-items: center;
      overflow: hidden;
      color: white;
      background: #070b20;
      font-family: system-ui, sans-serif;
    }

    #game {
      width: min(92vw, 800px);
      height: min(82vh, 560px);
      border: 2px solid #6474ff;
      border-radius: 16px;
      background: linear-gradient(#10173c, #080b1d);
      box-shadow: 0 0 40px #3949ab66;
      touch-action: none;
    }

    #instructions {
      position: fixed;
      bottom: 12px;
      margin: 0;
      padding: 8px 12px;
      color: #bec6ff;
      text-align: center;
      font-size: 14px;
    }
  </style>
</head>
<body>
  <canvas id="game"></canvas>
  <p id="instructions">
    Move with WASD, arrow keys, mouse, or touch. Collect stars. Avoid enemies.
  </p>

  <script>
    "use strict";

    const canvas = document.querySelector("#game");
    const ctx = canvas.getContext("2d");

    const state = {
      running: true,
      score: 0,
      best: Number(localStorage.getItem("starRunnerBest") || 0),
      time: 0,
      keys: new Set(),
      pointer: null,
      enemies: [],
      particles: []
    };

    const player = {
      x: 100,
      y: 100,
      radius: 16,
      speed: 260
    };

    const star = {
      x: 300,
      y: 200,
      radius: 12
    };

    function resize() {
      const rect = canvas.getBoundingClientRect();
      const scale = window.devicePixelRatio || 1;

      canvas.width = Math.round(rect.width * scale);
      canvas.height = Math.round(rect.height * scale);

      ctx.setTransform(scale, 0, 0, scale, 0, 0);
    }

    function width() {
      return canvas.clientWidth;
    }

    function height() {
      return canvas.clientHeight;
    }

    function random(min, max) {
      return Math.random() * (max - min) + min;
    }

    function distance(a, b) {
      return Math.hypot(a.x - b.x, a.y - b.y);
    }

    function placeStar() {
      star.x = random(30, width() - 30);
      star.y = random(60, height() - 30);
    }

    function addEnemy() {
      const side = Math.floor(Math.random() * 4);
      let x;
      let y;

      if (side === 0) {
        x = -25;
        y = random(0, height());
      } else if (side === 1) {
        x = width() + 25;
        y = random(0, height());
      } else if (side === 2) {
        x = random(0, width());
        y = -25;
      } else {
        x = random(0, width());
        y = height() + 25;
      }

      state.enemies.push({
        x,
        y,
        radius: random(12, 21),
        speed: random(75, 120) + state.score * 2
      });
    }

    function burst(x, y, color, count = 14) {
      for (let i = 0; i < count; i++) {
        const angle = Math.random() * Math.PI * 2;
        const speed = random(50, 180);

        state.particles.push({
          x,
          y,
          vx: Math.cos(angle) * speed,
          vy: Math.sin(angle) * speed,
          life: 1,
          color
        });
      }
    }

    function reset() {
      state.running = true;
      state.score = 0;
      state.time = 0;
      state.enemies = [];
      state.particles = [];
      state.pointer = null;

      player.x = width() / 2;
      player.y = height() / 2;

      placeStar();
      addEnemy();
    }

    function gameOver() {
      state.running = false;
      state.best = Math.max(state.best, state.score);
      localStorage.setItem("starRunnerBest", String(state.best));
      burst(player.x, player.y, "#ff496c", 35);
    }

    function update(dt) {
      updateParticles(dt);

      if (!state.running) {
        return;
      }

      state.time += dt;

      let dx = 0;
      let dy = 0;

      if (state.keys.has("arrowleft") || state.keys.has("a")) dx -= 1;
      if (state.keys.has("arrowright") || state.keys.has("d")) dx += 1;
      if (state.keys.has("arrowup") || state.keys.has("w")) dy -= 1;
      if (state.keys.has("arrowdown") || state.keys.has("s")) dy += 1;

      if (dx || dy) {
        const length = Math.hypot(dx, dy);
        player.x += (dx / length) * player.speed * dt;
        player.y += (dy / length) * player.speed * dt;
      } else if (state.pointer) {
        const pointerDistance = Math.hypot(
          state.pointer.x - player.x,
          state.pointer.y - player.y
        );

        if (pointerDistance > 5) {
          const movement = Math.min(player.speed * dt, pointerDistance);
          player.x += ((state.pointer.x - player.x) / pointerDistance) * movement;
          player.y += ((state.pointer.y - player.y) / pointerDistance) * movement;
        }
      }

      player.x = Math.max(player.radius, Math.min(width() - player.radius, player.x));
      player.y = Math.max(45 + player.radius, Math.min(height() - player.radius, player.y));

      if (distance(player, star) < player.radius + star.radius) {
        state.score++;
        burst(star.x, star.y, "#ffd84d");
        placeStar();

        if (state.score % 2 === 0) {
          addEnemy();
        }
      }

      for (const enemy of state.enemies) {
        const angle = Math.atan2(player.y - enemy.y, player.x - enemy.x);
        enemy.x += Math.cos(angle) * enemy.speed * dt;
        enemy.y += Math.sin(angle) * enemy.speed * dt;

        if (distance(player, enemy) < player.radius + enemy.radius) {
          gameOver();
          break;
        }
      }
    }

    function updateParticles(dt) {
      for (const particle of state.particles) {
        particle.x += particle.vx * dt;
        particle.y += particle.vy * dt;
        particle.vx *= 0.97;
        particle.vy *= 0.97;
        particle.life -= dt * 1.8;
      }

      state.particles = state.particles.filter(particle => particle.life > 0);
    }

    function drawBackground() {
      ctx.fillStyle = "#090d25";
      ctx.fillRect(0, 0, width(), height());

      ctx.fillStyle = "#ffffff22";

      for (let i = 0; i < 60; i++) {
        const x = (i * 97) % width();
        const y = (i * 53) % height();
        ctx.fillRect(x, y, 2, 2);
      }

      ctx.strokeStyle = "#6574ff22";
      ctx.lineWidth = 1;

      for (let x = 0; x < width(); x += 40) {
        ctx.beginPath();
        ctx.moveTo(x, 45);
        ctx.lineTo(x, height());
        ctx.stroke();
      }

      for (let y = 45; y < height(); y += 40) {
        ctx.beginPath();
        ctx.moveTo(0, y);
        ctx.lineTo(width(), y);
        ctx.stroke();
      }
    }

    function drawStar(x, y, outerRadius, innerRadius, color) {
      ctx.save();
      ctx.translate(x, y);
      ctx.rotate(state.time * 2);
      ctx.beginPath();

      for (let i = 0; i < 10; i++) {
        const radius = i % 2 === 0 ? outerRadius : innerRadius;
        const angle = -Math.PI / 2 + i * Math.PI / 5;
        const px = Math.cos(angle) * radius;
        const py = Math.sin(angle) * radius;

        if (i === 0) {
          ctx.moveTo(px, py);
        } else {
          ctx.lineTo(px, py);
        }
      }

      ctx.closePath();
      ctx.fillStyle = color;
      ctx.shadowColor = color;
      ctx.shadowBlur = 20;
      ctx.fill();
      ctx.restore();
    }

    function draw() {
      drawBackground();

      ctx.fillStyle = "#131a45dd";
      ctx.fillRect(0, 0, width(), 45);

      ctx.font = "bold 18px system-ui";
      ctx.textBaseline = "middle";
      ctx.fillStyle = "white";
      ctx.fillText(`Score: ${state.score}`, 16, 23);

      ctx.textAlign = "right";
      ctx.fillStyle = "#aeb8ff";
      ctx.fillText(`Best: ${state.best}`, width() - 16, 23);
      ctx.textAlign = "left";

      drawStar(star.x, star.y, star.radius, 5, "#ffd84d");

      for (const enemy of state.enemies) {
        ctx.beginPath();
        ctx.arc(enemy.x, enemy.y, enemy.radius, 0, Math.PI * 2);
        ctx.fillStyle = "#ff385f";
        ctx.shadowColor = "#ff385f";
        ctx.shadowBlur = 15;
        ctx.fill();
        ctx.shadowBlur = 0;

        ctx.fillStyle = "#5e0b25";
        ctx.fillRect(enemy.x - 7, enemy.y - 4, 4, 4);
        ctx.fillRect(enemy.x + 3, enemy.y - 4, 4, 4);
      }

      if (state.running) {
        ctx.beginPath();
        ctx.arc(player.x, player.y, player.radius, 0, Math.PI * 2);
        ctx.fillStyle = "#55d9ff";
        ctx.shadowColor = "#55d9ff";
        ctx.shadowBlur = 20;
        ctx.fill();
        ctx.shadowBlur = 0;

        ctx.beginPath();
        ctx.arc(player.x - 5, player.y - 4, 3, 0, Math.PI * 2);
        ctx.arc(player.x + 5, player.y - 4, 3, 0, Math.PI * 2);
        ctx.fillStyle = "#07162b";
        ctx.fill();
      }

      for (const particle of state.particles) {
        ctx.globalAlpha = particle.life;
        ctx.fillStyle = particle.color;
        ctx.fillRect(particle.x - 3, particle.y - 3, 6, 6);
      }

      ctx.globalAlpha = 1;

      if (!state.running) {
        ctx.fillStyle = "#050817cc";
        ctx.fillRect(0, 45, width(), height() - 45);

        ctx.textAlign = "center";
        ctx.fillStyle = "white";
        ctx.font = "bold 46px system-ui";
        ctx.fillText("GAME OVER", width() / 2, height() / 2 - 35);

        ctx.font = "22px system-ui";
        ctx.fillStyle = "#ffd84d";
        ctx.fillText(`Score: ${state.score}`, width() / 2, height() / 2 + 10);

        ctx.font = "18px system-ui";
        ctx.fillStyle = "#c9ceff";
        ctx.fillText(
          "Press Space or tap to restart",
          width() / 2,
          height() / 2 + 52
        );

        ctx.textAlign = "left";
      }
    }

    function pointerPosition(event) {
      const rect = canvas.getBoundingClientRect();

      return {
        x: event.clientX - rect.left,
        y: event.clientY - rect.top
      };
    }

    window.addEventListener("keydown", event => {
      const key = event.key.toLowerCase();
      state.keys.add(key);

      if (key === " " && !state.running) {
        reset();
      }

      if (key.startsWith("arrow") || key === " ") {
        event.preventDefault();
      }
    });

    window.addEventListener("keyup", event => {
      state.keys.delete(event.key.toLowerCase());
    });

    canvas.addEventListener("pointerdown", event => {
      if (!state.running) {
        reset();
        return;
      }

      state.pointer = pointerPosition(event);
      canvas.setPointerCapture(event.pointerId);
    });

    canvas.addEventListener("pointermove", event => {
      if (event.buttons || event.pointerType === "touch") {
        state.pointer = pointerPosition(event);
      }
    });

    canvas.addEventListener("pointerup", () => {
      state.pointer = null;
    });

    window.addEventListener("resize", resize);

    resize();
    reset();

    let previousTime = performance.now();

    function loop(currentTime) {
      const dt = Math.min((currentTime - previousTime) / 1000, 0.033);
      previousTime = currentTime;

      update(dt);
      draw();
      requestAnimationFrame(loop);
    }

    requestAnimationFrame(loop);
  </script>
</body>
</html>
← Back to timeline