<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no" />
<title>Agar.io Simple Clone with Food</title>
<style>
  html, body {
    margin: 0; padding: 0; overflow: hidden; background: #222;
    touch-action: none; /* prevent default gestures */
    -webkit-tap-highlight-color: transparent;
  }
  canvas {
    display: block;
    background: #111;
    margin: 0 auto;
    touch-action: none;
    image-rendering: optimizeSpeed;             /* Older versions of FF          */
    image-rendering: -moz-crisp-edges;          /* Firefox                       */
    image-rendering: -o-crisp-edges;            /* Opera                         */
    image-rendering: -webkit-optimize-contrast; /* Safari                        */
    image-rendering: pixelated;                  /* Chrome                       */
    image-rendering: optimize-contrast;         /* CSS3 Proposed                 */
    -ms-interpolation-mode: nearest-neighbor;   /* IE8+                         */
  }
</style>
</head>
<body>
<canvas id="game"></canvas>
<script>
(() => {
  const canvas = document.getElementById('game');
  const ctx = canvas.getContext('2d');

  // HD scaling for Retina/iPhone
  const dpr = window.devicePixelRatio || 1;

  // Large map size
  const MAP_WIDTH = 4000;
  const MAP_HEIGHT = 4000;

  // Player and bots count
  const BOT_COUNT = 8;
  const FOOD_COUNT = 1000;

  // Food pellet radius
  const FOOD_RADIUS = 5;

  // Cell class
  class Cell {
    constructor(id, x, y, radius, color, isPlayer = false) {
      this.id = id;
      this.x = x;
      this.y = y;
      this.radius = radius;
      this.color = color;
      this.isPlayer = isPlayer;
      this.speed = 2.5; // base speed, will decrease with size
      this.dead = false;
      this.wanderTarget = null;
    }

    draw(ctx, offsetX, offsetY) {
      const screenX = this.x - offsetX;
      const screenY = this.y - offsetY;

      // Draw gradient circle with shadow for nicer effect
      const gradient = ctx.createRadialGradient(screenX, screenY, this.radius*0.3, screenX, screenY, this.radius);
      gradient.addColorStop(0, this.color);
      gradient.addColorStop(1, shadeColor(this.color, -40));

      ctx.shadowColor = this.color;
      ctx.shadowBlur = this.radius * 0.6;

      ctx.beginPath();
      ctx.fillStyle = gradient;
      ctx.arc(screenX, screenY, this.radius, 0, Math.PI * 2);
      ctx.fill();

      ctx.shadowBlur = 0;

      // Draw name for player
      if (this.isPlayer) {
        ctx.fillStyle = '#fff';
        ctx.font = `${Math.max(this.radius / 2, 14)}px Arial`;
        ctx.textAlign = 'center';
        ctx.textBaseline = 'middle';
        ctx.fillText('You', screenX, screenY);
      }
    }

    moveToward(targetX, targetY) {
      let dx = targetX - this.x;
      let dy = targetY - this.y;
      let dist = Math.sqrt(dx*dx + dy*dy);
      if (dist < 1) return;
      // Speed decreases as radius grows
      let speed = this.speed * (30 / this.radius);
      if(speed < 0.5) speed = 0.5;
      let vx = (dx / dist) * speed;
      let vy = (dy / dist) * speed;
      this.x += vx;
      this.y += vy;

      // Clamp inside map
      this.x = Math.min(Math.max(this.radius, this.x), MAP_WIDTH - this.radius);
      this.y = Math.min(Math.max(this.radius, this.y), MAP_HEIGHT - this.radius);
    }

    grow(amount) {
      this.radius = Math.sqrt(this.radius*this.radius + amount);
    }

    canEat(other) {
      if (this.radius > other.radius * 1.1) {
        let dx = this.x - other.x;
        let dy = this.y - other.y;
        let dist = Math.sqrt(dx*dx + dy*dy);
        return dist < this.radius;
      }
      return false;
    }
  }

  // Food pellet class
  class Food {
    constructor(id, x, y, radius, color) {
      this.id = id;
      this.x = x;
      this.y = y;
      this.radius = radius;
      this.color = color;
      this.dead = false;
    }

    draw(ctx, offsetX, offsetY) {
      const screenX = this.x - offsetX;
      const screenY = this.y - offsetY;

      const gradient = ctx.createRadialGradient(screenX, screenY, this.radius*0.2, screenX, screenY, this.radius);
      gradient.addColorStop(0, this.color);
      gradient.addColorStop(1, shadeColor(this.color, -60));

      ctx.shadowColor = this.color;
      ctx.shadowBlur = 8;

      ctx.beginPath();
      ctx.fillStyle = gradient;
      ctx.arc(screenX, screenY, this.radius, 0, Math.PI * 2);
      ctx.fill();

      ctx.shadowBlur = 0;
    }
  }

  // Setup canvas size to window with HD scaling
  function resize() {
    canvas.style.width = window.innerWidth + 'px';
    canvas.style.height = window.innerHeight + 'px';
    canvas.width = window.innerWidth * dpr;
    canvas.height = window.innerHeight * dpr;
    ctx.setTransform(1,0,0,1,0,0); // reset transform
    ctx.scale(dpr, dpr);
  }
  window.addEventListener('resize', resize);
  resize();

  // Initialize player in center of map
  const player = new Cell('player', MAP_WIDTH/2, MAP_HEIGHT/2, 30, '#4CAF50', true);

  // Initialize bots randomly
  const bots = [];
  function randomColor() {
    const colors = ['#e74c3c','#3498db','#f1c40f','#9b59b6','#e67e22','#1abc9c','#ecf0f1','#95a5a6'];
    return colors[Math.floor(Math.random()*colors.length)];
  }
  for(let i=0; i<BOT_COUNT; i++) {
    let x = Math.random()*(MAP_WIDTH-60)+30;
    let y = Math.random()*(MAP_HEIGHT-60)+30;
    let r = 20 + Math.random()*15;
    bots.push(new Cell('bot'+i, x, y, r, randomColor()));
  }

  // Initialize food pellets randomly
  const foods = [];
  function randomBrightColor() {
    // Generate bright colors for food
    const hue = Math.floor(Math.random()*360);
    return `hsl(${hue}, 80%, 60%)`;
  }
  for(let i=0; i<FOOD_COUNT; i++) {
    let x = Math.random()*(MAP_WIDTH-FOOD_RADIUS*2)+FOOD_RADIUS;
    let y = Math.random()*(MAP_HEIGHT-FOOD_RADIUS*2)+FOOD_RADIUS;
    foods.push(new Food('food'+i, x, y, FOOD_RADIUS, randomBrightColor()));
  }

  // Touch/mouse control variables
  let inputX = player.x;
  let inputY = player.y;
  let isTouching = false;

  // Touch events
  canvas.addEventListener('touchstart', e => {
    e.preventDefault();
    const touch = e.touches[0];
    const rect = canvas.getBoundingClientRect();
    inputX = touch.clientX + camera.x;
    inputY = touch.clientY + camera.y;
    isTouching = true;
  }, {passive:false});

  canvas.addEventListener('touchmove', e => {
    e.preventDefault();
    const touch = e.touches[0];
    inputX = touch.clientX + camera.x;
    inputY = touch.clientY + camera.y;
  }, {passive:false});

  canvas.addEventListener('touchend', e => {
    e.preventDefault();
    isTouching = false;
  }, {passive:false});

  // Also support mouse for desktop testing
  canvas.addEventListener('mousedown', e => {
    e.preventDefault();
    inputX = e.clientX + camera.x;
    inputY = e.clientY + camera.y;
    isTouching = true;
  });
  canvas.addEventListener('mousemove', e => {
    if(isTouching) {
      inputX = e.clientX + camera.x;
      inputY = e.clientY + camera.y;
    }
  });
  canvas.addEventListener('mouseup', e => {
    isTouching = false;
  });

  // Camera to follow player
  const camera = {
    x: 0,
    y: 0,
    update() {
      // Center camera on player
      this.x = player.x - canvas.width/(2*dpr);
      this.y = player.y - canvas.height/(2*dpr);
      // Clamp camera inside map
      this.x = Math.min(Math.max(0, this.x), MAP_WIDTH - canvas.width/dpr);
      this.y = Math.min(Math.max(0, this.y), MAP_HEIGHT - canvas.height/dpr);
    }
  };

  // AI bot simple behavior: move randomly, chase smaller cells or food nearby
  function updateBots() {
    for(let bot of bots) {
      if(bot.dead) continue;

      // Find closest edible cell (player or smaller bots)
      let target = null;
      let targetDist = Infinity;

      // Check player
      if(bot.canEat(player)) {
        // Eat player - game over
        player.dead = true;
        continue;
      }
      if(player.radius < bot.radius * 0.9) {
        let dx = bot.x - player.x;
        let dy = bot.y - player.y;
        let dist = Math.sqrt(dx*dx + dy*dy);
        if(dist < targetDist) {
          targetDist = dist;
          target = player;
        }
      }

      // Check other bots
      for(let other of bots) {
        if(other === bot || other.dead) continue;
        if(bot.canEat(other)) {
          // Eat other bot
          other.dead = true;
          bot.grow(other.radius*other.radius);
          continue;
        }
        if(other.radius < bot.radius * 0.9) {
          let dx = bot.x - other.x;
          let dy = bot.y - other.y;
          let dist = Math.sqrt(dx*dx + dy*dy);
          if(dist < targetDist) {
            targetDist = dist;
            target = other;
          }
        }
      }

      // Check nearby food if no bigger target found
      if(!target) {
        for(let food of foods) {
          if(food.dead) continue;
          let dx = bot.x - food.x;
          let dy = bot.y - food.y;
          let dist = Math.sqrt(dx*dx + dy*dy);
          if(dist < 300 && dist < targetDist) {
            targetDist = dist;
            target = food;
          }
        }
      }

      // Move toward target or random wander
      if(target && !target.dead) {
        bot.moveToward(target.x, target.y);
      } else {
        // Random wandering
        if(!bot.wanderTarget || Math.random() < 0.01) {
          bot.wanderTarget = {
            x: Math.random()*(MAP_WIDTH-60)+30,
            y: Math.random()*(MAP_HEIGHT-60)+30
          };
        }
        bot.moveToward(bot.wanderTarget.x, bot.wanderTarget.y);
      }
    }
  }

  // Eating logic: player eats bots, bots eat player, all eat food
  function checkEating() {
    if(player.dead) return;

    // Player eats bots
    for(let bot of bots) {
      if(bot.dead) continue;
      if(player.canEat(bot)) {
        bot.dead = true;
        player.grow(bot.radius*bot.radius);
      }
    }

    // Bots eat player handled in updateBots

    // Player eats food
    for(let food of foods) {
      if(food.dead) continue;
      if(player.radius > FOOD_RADIUS * 1.1) {
        let dx = player.x - food.x;
        let dy = player.y - food.y;
        let dist = Math.sqrt(dx*dx + dy*dy);
        if(dist < player.radius) {
          food.dead = true;
          player.grow(FOOD_RADIUS*FOOD_RADIUS);
        }
      }
    }

    // Bots eat food
    for(let bot of bots) {
      if(bot.dead) continue;
      for(let food of foods) {
        if(food.dead) continue;
        if(bot.radius > FOOD_RADIUS * 1.1) {
          let dx = bot.x - food.x;
          let dy = bot.y - food.y;
          let dist = Math.sqrt(dx*dx + dy*dy);
          if(dist < bot.radius) {
            food.dead = true;
            bot.grow(FOOD_RADIUS*FOOD_RADIUS);
          }
        }
      }
    }

    // Respawn food to keep count stable
    let aliveFood = foods.filter(f => !f.dead);
    let toSpawn = FOOD_COUNT - aliveFood.length;
    for(let i=0; i<toSpawn; i++) {
      let x = Math.random()*(MAP_WIDTH-FOOD_RADIUS*2)+FOOD_RADIUS;
      let y = Math.random()*(MAP_HEIGHT-FOOD_RADIUS*2)+FOOD_RADIUS;
      foods.push(new Food('food'+Date.now()+Math.random(), x, y, FOOD_RADIUS, randomBrightColor()));
    }
  }

  // Game loop
  function loop() {
    if(player.dead) {
      drawGameOver();
      return;
    }

    // Move player toward input if touching
    if(isTouching) {
      player.moveToward(inputX, inputY);
    }

    // Update bots
    updateBots();

    // Eating checks
    checkEating();

    // Update camera
    camera.update();

    // Clear screen
    ctx.clearRect(0, 0, canvas.width/dpr, canvas.height/dpr);

    // Draw map background grid for reference
    drawGrid();

    // Draw food pellets
    for(let food of foods) {
      if(food.dead) continue;
      food.draw(ctx, camera.x, camera.y);
    }

    // Draw bots
    for(let bot of bots) {
      if(bot.dead) continue;
      bot.draw(ctx, camera.x, camera.y);
    }

    // Draw player on top
    player.draw(ctx, camera.x, camera.y);

    // Draw HUD
    drawHUD();

    requestAnimationFrame(loop);
  }

  // Draw grid background
  function drawGrid() {
    const gridSize = 100;
    ctx.strokeStyle = '#333';
    ctx.lineWidth = 1;
    ctx.beginPath();
    for(let x = -camera.x % gridSize; x < canvas.width/dpr; x += gridSize) {
      ctx.moveTo(x, 0);
      ctx.lineTo(x, canvas.height/dpr);
    }
    for(let y = -camera.y % gridSize; y < canvas.height/dpr; y += gridSize) {
      ctx.moveTo(0, y);
      ctx.lineTo(canvas.width/dpr, y);
    }
    ctx.stroke();
  }

  // Draw HUD
  function drawHUD() {
    ctx.fillStyle = '#fff';
    ctx.font = '18px Arial';
    ctx.textAlign = 'left';
    ctx.fillText(`Size: ${player.radius.toFixed(1)}`, 10, 25);
    ctx.fillText(`Food: ${foods.filter(f => !f.dead).length}`, 10, 50);
  }

  // Game Over screen
  function drawGameOver() {
    ctx.fillStyle = 'rgba(0,0,0,0.7)';
    ctx.fillRect(0, 0, canvas.width/dpr, canvas.height/dpr);
    ctx.fillStyle = '#f44336';
    ctx.font = '48px Arial';
    ctx.textAlign = 'center';
    ctx.fillText('Game Over', canvas.width/(2*dpr), canvas.height/(2*dpr) - 20);
    ctx.font = '24px Arial';
    ctx.fillText('Refresh to try again', canvas.width/(2*dpr), canvas.height/(2*dpr) + 30);
  }

  // Utility: shade color by percent (-100 to 100)
  function shadeColor(color, percent) {
    // Support hex or hsl strings
    if(color.startsWith('hsl')) {
      // Parse hsl
      let m = color.match(/hsl\((\d+),\s*(\d+)%,\s*(\d+)%\)/);
      if(!m) return color;
      let h = +m[1], s = +m[2], l = +m[3];
      l = Math.min(100, Math.max(0, l + percent));
      return `hsl(${h},${s}%,${l}%)`;
    }
    // Hex color
    let f=parseInt(color.slice(1),16),t=percent<0?0:255,p=percent<0?percent*-1:percent;
    let R=f>>16,G=f>>8&0x00FF,B=f&0x0000FF;
    let r=Math.round((t-R)*p/100)+R;
    let g=Math.round((t-G)*p/100)+G;
    let b=Math.round((t-B)*p/100)+B;
    return `rgb(${r},${g},${b})`;
  }

  loop();
})();
</script>
</body>
</html> 

Make it so I can move faster, hold down andirection to keep it moving, and stop the auto movement all through touchscreen. Keep it in one html file