← back to Model Arena

data/artifacts/08a1b73bf7ac/qwen3-14b.html

490 lines

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8" />
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
  <title>Comet's Gravity Dance</title>
  <style>
    * {
      box-sizing: border-box;
      margin: 0;
      padding: 0;
    }
    body {
      background: #000;
      color: #fff;
      font-family: 'Arial', sans-serif;
      overflow: hidden;
      user-select: none;
    }
    canvas {
      display: block;
      width: 100%;
      height: 100vh;
      background: radial-gradient(ellipse at center, #000 0%, #111 100%);
    }
    #controls {
      position: absolute;
      top: 20px;
      left: 20px;
      z-index: 10;
      background: rgba(0, 0, 0, 0.7);
      padding: 15px;
      border-radius: 10px;
      font-size: 16px;
    }
    #controls h2 {
      margin-bottom: 10px;
    }
    #status {
      position: absolute;
      bottom: 20px;
      left: 50%;
      transform: translateX(-50%);
      z-index: 10;
      text-align: center;
      background: rgba(0, 0, 0, 0.7);
      padding: 10px 20px;
      border-radius: 10px;
      font-size: 16px;
      max-width: 80%;
    }
    #score {
      position: absolute;
      top: 20px;
      right: 20px;
      z-index: 10;
      background: rgba(0, 0, 0, 0.7);
      padding: 10px 15px;
      border-radius: 10px;
      font-size: 16px;
      min-width: 100px;
    }
    .input-group {
      margin-bottom: 10px;
    }
    .input-group label {
      display: block;
      margin-bottom: 5px;
    }
    .input-group input, .input-group select {
      width: 100%;
      padding: 6px;
      font-size: 14px;
      border: 1px solid #666;
      border-radius: 6px;
      background: #111;
      color: #fff;
    }
    .input-group input:focus, .input-group select:focus {
      outline: none;
      border-color: #00f;
    }
    .input-group .error {
      color: #f00;
      font-size: 12px;
      margin-top: 4px;
    }
    .empty-state {
      display: none;
      padding: 10px;
      background: rgba(255, 255, 255, 0.1);
      border-radius: 6px;
      color: #ccc;
    }
    .error-state {
      display: none;
      padding: 10px;
      background: rgba(255, 0, 0, 0.2);
      border-radius: 6px;
      color: #f00;
    }
    .success-state {
      display: none;
      padding: 10px;
      background: rgba(0, 255, 0, 0.2);
      border-radius: 6px;
      color: #0f0;
    }
    @media (min-width: 768px) {
      #controls {
        left: 50%;
        transform: translateX(-50%);
        max-width: 400px;
        width: 100%;
      }
    }
  </style>
</head>
<body>
  <div id="controls">
    <h2>Comet's Gravity Dance</h2>
    <div class="input-group">
      <label for="constellationName">Constellation Name:</label>
      <input type="text" id="constellationName" placeholder="e.g., Orion's Veil" />
      <div class="error error-state" id="nameError"></div>
    </div>
    <div class="input-group">
      <label for="highScore">High Score (optional):</label>
      <input type="number" id="highScore" min="0" />
      <div class="error error-state" id="scoreError"></div>
    </div>
    <button id="saveScore">Save Constellation</button>
    <div class="success success-state" id="saveSuccess">Saved constellation: <span id="savedName"></span></div>
    <div class="empty empty-state" id="emptyState">No constellation saved yet.</div>
  </div>
  <div id="score">Score: 0</div>
  <div id="status">Welcome to the shrinking galaxy. Control your comet with arrow keys. Eat stars to grow your tail and bend gravity. Avoid collisions or slow down time!</div>
  <canvas id="galaxy"></canvas>

  <script>
    const canvas = document.getElementById('galaxy');
    const ctx = canvas.getContext('2d');
    const controls = document.getElementById('controls');
    const saveScoreButton = document.getElementById('saveScore');
    const constellationNameInput = document.getElementById('constellationName');
    const highScoreInput = document.getElementById('highScore');
    const nameError = document.getElementById('nameError');
    const scoreError = document.getElementById('scoreError');
    const saveSuccess = document.getElementById('saveSuccess');
    const savedName = document.getElementById('savedName');
    const emptyState = document.getElementById('emptyState');
    const status = document.getElementById('status');

    let score = 0;
    let savedConstellation = null;
    let isPaused = false;
    let isSlowMo = false;
    let slowMoTimer = 0;

    let comet = {
      x: canvas.width / 2,
      y: canvas.height / 2,
      vx: 0,
      vy: 0,
      radius: 8,
      color: 'white',
      tail: []
    };

    let stars = [];
    let gravityPoints = [];
    let gravityPointsActive = [];
    let gravityActive = false;
    let shrinkFactor = 0.999;
    let galaxyRadius = canvas.width / 2;
    let lastStarEaten = null;

    function resizeCanvas() {
      canvas.width = window.innerWidth;
      canvas.height = window.innerHeight;
      galaxyRadius = Math.min(canvas.width, canvas.height) / 2;
      generateStars();
      generateGravityPoints();
    }

    function generateStars() {
      stars = [];
      for (let i = 0; i < 150; i++) {
        let angle = Math.random() * 2 * Math.PI;
        let radius = Math.random() * galaxyRadius * 0.8;
        let x = canvas.width / 2 + Math.cos(angle) * radius;
        let y = canvas.height / 2 + Math.sin(angle) * radius;
        let size = Math.random() * 4 + 1;
        let speed = Math.random() * 0.1 + 0.05;
        stars.push({ x, y, size, speed, color: `hsl(${Math.random() * 360}, 100%, 80%)` });
      }
    }

    function generateGravityPoints() {
      gravityPoints = [];
      gravityPointsActive = [];
      for (let i = 0; i < 30; i++) {
        let angle = Math.random() * 2 * Math.PI;
        let radius = Math.random() * galaxyRadius * 0.6;
        let x = canvas.width / 2 + Math.cos(angle) * radius;
        let y = canvas.height / 2 + Math.sin(angle) * radius;
        let mass = Math.random() * 10 + 10;
        gravityPoints.push({ x, y, mass, color: `hsl(${Math.random() * 360}, 70%, 60%)` });
      }
    }

    function drawGalaxy() {
      ctx.clearRect(0, 0, canvas.width, canvas.height);

      // Draw shrinking galaxy background
      ctx.beginPath();
      ctx.arc(canvas.width / 2, canvas.height / 2, galaxyRadius * shrinkFactor, 0, Math.PI * 2);
      ctx.fillStyle = 'rgba(0, 0, 0, 0.2)';
      ctx.fill();

      // Draw stars
      ctx.fillStyle = 'white';
      stars.forEach(star => {
        ctx.beginPath();
        ctx.arc(star.x, star.y, star.size, 0, Math.PI * 2);
        ctx.fill();
      });

      // Draw gravity points
      gravityPoints.forEach(gp => {
        ctx.beginPath();
        ctx.arc(gp.x, gp.y, Math.sqrt(gp.mass) * 1.5, 0, Math.PI * 2);
        ctx.fillStyle = gp.color;
        ctx.fill();
      });

      // Draw comet and tail
      ctx.strokeStyle = comet.color;
      ctx.lineWidth = 2;
      comet.tail.forEach((pos, idx) => {
        ctx.beginPath();
        ctx.arc(pos.x, pos.y, 3, 0, Math.PI * 2);
        ctx.fillStyle = comet.color;
        ctx.fill();
      });
      ctx.beginPath();
      ctx.arc(comet.x, comet.y, comet.radius, 0, Math.PI * 2);
      ctx.fillStyle = comet.color;
      ctx.fill();
    }

    function updateStars() {
      stars.forEach(star => {
        star.x += Math.cos(star.angle) * star.speed;
        star.y += Math.sin(star.angle) * star.speed;
        if (Math.random() < 0.01) {
          star.angle = Math.random() * 2 * Math.PI;
        }
      });
    }

    function updateGravityPoints() {
      gravityPoints.forEach(gp => {
        // Orbit around galaxy center
        let distanceToCenter = Math.sqrt(Math.pow(gp.x - canvas.width / 2, 2) + Math.pow(gp.y - canvas.height / 2, 2));
        let maxDistance = galaxyRadius * 0.6;
        if (distanceToCenter > maxDistance) {
          // Move inward
          let dx = gp.x - canvas.width / 2;
          let dy = gp.y - canvas.height / 2;
          let angle = Math.atan2(dy, dx);
          gp.x -= Math.cos(angle) * 1;
          gp.y -= Math.sin(angle) * 1;
        } else {
          // Orbit
          let speed = 0.01;
          let angle = Math.atan2(gp.y - canvas.height / 2, gp.x - canvas.width / 2);
          gp.x += Math.cos(angle) * speed;
          gp.y += Math.sin(angle) * speed;
        }
      });
    }

    function moveComet() {
      let dx = comet.vx;
      let dy = comet.vy;
      comet.x += dx;
      comet.y += dy;

      // Tail
      if (comet.tail.length > 50) {
        comet.tail.shift();
      }
      comet.tail.push({ x: comet.x, y: comet.y });

      // Boundaries
      if (comet.x < 0 || comet.x > canvas.width || comet.y < 0 || comet.y > canvas.height) {
        if (!isPaused) {
          triggerSlowMo();
        }
      }
    }

    function detectCollisions() {
      // Check for star collisions
      for (let i = stars.length - 1; i >= 0; i--) {
        let star = stars[i];
        let dx = comet.x - star.x;
        let dy = comet.y - star.y;
        let distance = Math.sqrt(dx * dx + dy * dy);
        if (distance < star.size + comet.radius) {
          // Eat star
          score++;
          comet.radius += 1;
          comet.tail.forEach((pos, idx) => {
            pos.x += dx * 0.02;
            pos.y += dy * 0.02;
          });
          stars.splice(i, 1);
          lastStarEaten = star;
          triggerGravityBend();
        }
      }

      // Check for gravity points
      for (let i = gravityPoints.length - 1; i >= 0; i--) {
        let gp = gravityPoints[i];
        let dx = comet.x - gp.x;
        let dy = comet.y - gp.y;
        let distance = Math.sqrt(dx * dx + dy * dy);
        if (distance < Math.sqrt(gp.mass)) {
          // Gravity point consumed
          comet.tail.forEach((pos, idx) => {
            pos.x += dx * 0.05;
            pos.y += dy * 0.05;
          });
          gravityPoints.splice(i, 1);
        }
      }
    }

    function triggerGravityBend() {
      if (lastStarEaten && !gravityActive) {
        gravityActive = true;
        let radius = lastStarEaten.size * 5;
        gravityPointsActive = [];
        for (let i = 0; i < 10; i++) {
          let angle = Math.random() * 2 * Math.PI;
          let x = lastStarEaten.x + Math.cos(angle) * radius;
          let y = lastStarEaten.y + Math.sin(angle) * radius;
          let mass = lastStarEaten.size * 0.5;
          gravityPointsActive.push({ x, y, mass });
        }
        setTimeout(() => gravityActive = false, 1500);
      }
    }

    function applyGravityBend() {
      gravityPointsActive.forEach(gp => {
        let dx = comet.x - gp.x;
        let dy = comet.y - gp.y;
        let distance = Math.sqrt(dx * dx + dy * dy);
        let force = 0.01 * gp.mass / (distance * distance);
        comet.vx += dx * force;
        comet.vy += dy * force;
      });
    }

    function triggerSlowMo() {
      if (isSlowMo) return;
      isSlowMo = true;
      slowMoTimer = 10;
      status.textContent = "Slow-mo triggered. Avoid collisions!";
    }

    function update() {
      if (isSlowMo) {
        slowMoTimer--;
        if (slowMoTimer <= 0) isSlowMo = false;
        return;
      }

      galaxyRadius *= shrinkFactor;

      moveComet();
      detectCollisions();

      updateStars();
      updateGravityPoints();

      if (gravityActive) applyGravityBend();

      drawGalaxy();

      document.getElementById('score').textContent = 'Score: ' + score;
    }

    function gameLoop() {
      if (isPaused) return;
      update();
      requestAnimationFrame(gameLoop);
    }

    function resetGame() {
      score = 0;
      comet = {
        x: canvas.width / 2,
        y: canvas.height / 2,
        vx: 0,
        vy: 0,
        radius: 8,
        color: 'white',
        tail: []
      };
      generateStars();
      generateGravityPoints();
    }

    window.addEventListener('keydown', e => {
      if (isPaused) return;

      switch (e.key) {
        case 'ArrowUp':
          comet.vy -= 0.2;
          break;
        case 'ArrowDown':
          comet.vy += 0.2;
          break;
        case 'ArrowLeft':
          comet.vx -= 0.2;
          break;
        case 'ArrowRight':
          comet.vx += 0.2;
          break;
        case ' ':
          comet.vx = 0;
          comet.vy = 0;
          break;
      }
    });

    window.addEventListener('resize', () => {
      resizeCanvas();
    });

    resizeCanvas();

    gameLoop();

    // Save constellation
    saveScoreButton.addEventListener('click', () => {
      let name = constellationNameInput.value.trim();
      let scoreValue = highScoreInput.value;

      if (name === '') {
        nameError.textContent = 'Please enter a constellation name.';
        nameError.style.display = 'block';
        return;
      }
      nameError.style.display = 'none';

      if (scoreValue && isNaN(scoreValue) || scoreValue < 0) {
        scoreError.textContent = 'Please enter a valid score (optional).';
        scoreError.style.display = 'block';
        return;
      }
      scoreError.style.display = 'none';

      savedConstellation = {
        name: name,
        score: scoreValue ? parseInt(scoreValue) : null
      };
      saveSuccess.style.display = 'block';
      savedName.textContent = name;
      setTimeout(() => {
        saveSuccess.style.display = 'none';
      }, 3000);
    });

    // Initialize state
    if (savedConstellation) {
      savedName.textContent = savedConstellation.name;
      saveSuccess.style.display = 'none';
      emptyState.style.display = 'none';
    } else {
      emptyState.style.display = 'block';
    }
  </script>
</body>
</html>