Showcase

Snake, with juice, built by Clover 35B A3B Preview

Hostedvia DaBenchCustom endpoint
Running live in your browserNew tab
Speed
422tok/s
First token included
Written
6.3Ktokens
Time to build
14.9s
Clover 35B A3B Preview's builds and scores
Show the code the model wrote
HTML16,953 characters
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Snake</title>
<style>
  * { margin: 0; padding: 0; box-sizing: border-box; }
  body {
    background: #0a0a0f;
    display: flex;
    justify-content: center;
    align-items: center;
    height: 100vh;
    font-family: 'Segoe UI', system-ui, -apple-system, sans-serif;
    overflow: hidden;
    user-select: none;
    -webkit-user-select: none;
  }
  #wrapper {
    position: relative;
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 12px;
  }
  #hud {
    display: flex;
    justify-content: space-between;
    width: 480px;
    padding: 0 4px;
    color: #8888aa;
    font-size: 14px;
    letter-spacing: 1px;
    text-transform: uppercase;
  }
  #hud span { font-weight: 600; }
  #scoreVal { color: #7fdbca; }
  #speedVal { color: #e8a838; }
  canvas {
    display: block;
    border-radius: 6px;
    box-shadow: 0 0 60px rgba(127, 219, 202, 0.06), inset 0 0 1px rgba(255,255,255,0.05);
  }
</style>
</head>
<body>
<div id="wrapper">
  <div id="hud">
    <div>Score <span id="scoreVal">0</span></div>
    <div>Speed <span id="speedVal">1</span></div>
  </div>
  <canvas id="c"></canvas>
</div>

<script>
const COLS = 24, ROWS = 24;
const CELL = 20;
const W = COLS * CELL, H = ROWS * CELL;

const canvas = document.getElementById('c');
const ctx = canvas.getContext('2d');
canvas.width = W;
canvas.height = H;

// --- Audio ---
let audioCtx = null;
function ensureAudio() {
  if (!audioCtx) audioCtx = new (window.AudioContext || window.webkitAudioContext)();
}

function playTick() {
  ensureAudio();
  const t = audioCtx.currentTime;
  const osc = audioCtx.createOscillator();
  const gain = audioCtx.createGain();
  osc.type = 'square';
  osc.frequency.setValueAtTime(600, t);
  osc.frequency.exponentialRampToValueAtTime(300, t + 0.04);
  gain.gain.setValueAtTime(0.06, t);
  gain.gain.exponentialRampToValueAtTime(0.001, t + 0.06);
  osc.connect(gain).connect(audioCtx.destination);
  osc.start(t); osc.stop(t + 0.06);
}

function playEat() {
  ensureAudio();
  const t = audioCtx.currentTime;
  [800, 1100].forEach((freq, i) => {
    const osc = audioCtx.createOscillator();
    const gain = audioCtx.createGain();
    osc.type = 'sine';
    osc.frequency.setValueAtTime(freq, t + i * 0.05);
    gain.gain.setValueAtTime(0.08, t + i * 0.05);
    gain.gain.exponentialRampToValueAtTime(0.001, t + i * 0.05 + 0.12);
    osc.connect(gain).connect(audioCtx.destination);
    osc.start(t + i * 0.05); osc.stop(t + i * 0.05 + 0.12);
  });
}

function playDeath() {
  ensureAudio();
  const t = audioCtx.currentTime;
  const osc = audioCtx.createOscillator();
  const gain = audioCtx.createGain();
  osc.type = 'sawtooth';
  osc.frequency.setValueAtTime(200, t);
  osc.frequency.exponentialRampToValueAtTime(40, t + 0.4);
  gain.gain.setValueAtTime(0.12, t);
  gain.gain.exponentialRampToValueAtTime(0.001, t + 0.4);
  osc.connect(gain).connect(audioCtx.destination);
  osc.start(t); osc.stop(t + 0.4);
}

// --- Game State ---
let snake, direction, nextDirection, food, score, bestScore, speedLevel, tickRate;
let gameState; // 'ready' | 'playing' | 'dying' | 'dead'
let moveTimer, lastMoveTime;
let particles, scorePops, shakeAmount, flashAlpha, speedFlash;
let prevSpeedLevel;

function initGame() {
  const startX = Math.floor(COLS / 2);
  const startY = Math.floor(ROWS / 2);
  snake = [
    { x: startX, y: startY },
    { x: startX, y: startY + 1 },
    { x: startX, y: startY + 2 },
  ];
  direction = { x: 0, y: -1 };
  nextDirection = { x: 0, y: -1 };
  score = 0;
  speedLevel = 1;
  tickRate = 130;
  prevSpeedLevel = 1;
  particles = [];
  scorePops = [];
  shakeAmount = 0;
  flashAlpha = 0;
  speedFlash = 0;
  spawnFood();
}

function spawnFood() {
  let attempts = 0;
  while (attempts < 1000) {
    const x = Math.floor(Math.random() * COLS);
    const y = Math.floor(Math.random() * ROWS);
    if (!snake.some(s => s.x === x && s.y === y)) {
      food = { x, y };
      return;
    }
    attempts++;
  }
}

// --- Particles ---
function spawnParticles(x, y, color, count) {
  for (let i = 0; i < count; i++) {
    const angle = Math.random() * Math.PI * 2;
    const speed = 40 + Math.random() * 120;
    particles.push({
      x: x * CELL + CELL / 2,
      y: y * CELL + CELL / 2,
      vx: Math.cos(angle) * speed,
      vy: Math.sin(angle) * speed,
      life: 0.6 + Math.random() * 0.4,
      maxLife: 0.6 + Math.random() * 0.4,
      size: 2 + Math.random() * 3,
      color,
    });
  }
}

function spawnScorePop(x, y, text) {
  scorePops.push({
    x: x * CELL + CELL / 2,
    y: y * CELL + CELL / 2,
    text,
    life: 0.8,
    vy: -60,
  });
}

// --- Input ---
document.addEventListener('keydown', e => {
  if (gameState === 'dead') {
    if (e.code === 'Space') {
      e.preventDefault();
      initGame();
      gameState = 'playing';
      lastMoveTime = performance.now();
      tickRate = 130;
      speedLevel = 1;
      prevSpeedLevel = 1;
      return;
    }
  }
  if (e.code === 'KeyP') {
    if (gameState === 'playing') gameState = 'paused';
    else if (gameState === 'paused') { gameState = 'playing'; lastMoveTime = performance.now(); }
    return;
  }
  if (gameState !== 'playing') return;

  switch (e.code) {
    case 'ArrowUp': case 'KeyW':
      if (direction.y !== -1) nextDirection = { x: 0, y: -1 };
      break;
    case 'ArrowDown': case 'KeyS':
      if (direction.y !== 1) nextDirection = { x: 0, y: 1 };
      break;
    case 'ArrowLeft': case 'KeyA':
      if (direction.x !== -1) nextDirection = { x: -1, y: 0 };
      break;
    case 'ArrowRight': case 'KeyD':
      if (direction.x !== 1) nextDirection = { x: 1, y: 0 };
      break;
  }
  e.preventDefault();
});

// --- Update ---
function update(dt) {
  if (gameState === 'playing') {
    // Speed up
    const newSpeedLevel = Math.min(10, 1 + Math.floor(score / 5));
    if (newSpeedLevel > speedLevel) {
      speedLevel = newSpeedLevel;
      tickRate = Math.max(55, 130 - (speedLevel - 1) * 8);
      playTick();
      speedFlash = 1.0;
      prevSpeedLevel = speedLevel;
    }

    // Movement timer
    lastMoveTime += dt * 1000;
    while (lastMoveTime >= tickRate) {
      lastMoveTime -= tickRate;
      direction = { ...nextDirection };

      const head = snake[0];
      const nx = head.x + direction.x;
      const ny = head.y + direction.y;

      // Wall collision
      if (nx < 0 || nx >= COLS || ny < 0 || ny >= ROWS) {
        die();
        return;
      }

      // Self collision
      if (snake.some(s => s.x === nx && s.y === ny)) {
        die();
        return;
      }

      snake.unshift({ x: nx, y: ny });

      // Eat food
      if (nx === food.x && ny === food.y) {
        score++;
        playEat();
        spawnParticles(nx, ny, '#ff6b6b', 18);
        spawnParticles(nx, ny, '#ffd93d', 10);
        spawnScorePop(nx, ny, '+1');
        food = null;
        spawnFood();
      } else {
        snake.pop();
      }
    }
  }

  // Dying animation
  if (gameState === 'dying') {
    flashAlpha += dt * 3;
    shakeAmount = Math.max(0, shakeAmount - dt * 600);
    if (flashAlpha > 1) {
      gameState = 'dead';
      flashAlpha = 1;
      if (score > bestScore) bestScore = score;
    }
  }

  // Decay effects
  if (speedFlash > 0) speedFlash -= dt * 2.5;
  if (shakeAmount < 0.5) shakeAmount = 0;

  // Particles
  for (let i = particles.length - 1; i >= 0; i--) {
    const p = particles[i];
    p.life -= dt;
    p.x += p.vx * dt;
    p.y += p.vy * dt;
    p.vy += 150 * dt; // gravity
    p.vx *= 0.98;
    if (p.life <= 0) particles.splice(i, 1);
  }

  // Score pops
  for (let i = scorePops.length - 1; i >= 0; i--) {
    const sp = scorePops[i];
    sp.life -= dt;
    sp.y += sp.vy * dt;
    if (sp.life <= 0) scorePops.splice(i, 1);
  }
}

function die() {
  gameState = 'dying';
  playDeath();
  shakeAmount = 12;
  flashAlpha = 0;
  // Death particles along the snake
  for (let i = 0; i < snake.length; i++) {
    setTimeout(() => {
      spawnParticles(snake[i].x, snake[i].y, '#ff4444', 6);
      spawnParticles(snake[i].x, snake[i].y, '#ff8800', 4);
    }, i * 30);
  }
}

// --- Render ---
function render() {
  ctx.save();

  // Screen shake
  if (shakeAmount > 0) {
    const sx = (Math.random() - 0.5) * shakeAmount;
    const sy = (Math.random() - 0.5) * shakeAmount;
    ctx.translate(sx, sy);
  }

  // Background
  ctx.fillStyle = '#0d0d18';
  ctx.fillRect(0, 0, W, H);

  // Grid lines (subtle)
  ctx.strokeStyle = 'rgba(255,255,255,0.018)';
  ctx.lineWidth = 0.5;
  for (let x = 0; x <= COLS; x++) {
    ctx.beginPath();
    ctx.moveTo(x * CELL, 0);
    ctx.lineTo(x * CELL, H);
    ctx.stroke();
  }
  for (let y = 0; y <= ROWS; y++) {
    ctx.beginPath();
    ctx.moveTo(0, y * CELL);
    ctx.lineTo(W, y * CELL);
    ctx.stroke();
  }

  // Food glow
  if (food) {
    const pulse = 0.7 + 0.3 * Math.sin(performance.now() / 300);
    const fx = food.x * CELL + CELL / 2;
    const fy = food.y * CELL + CELL / 2;
    const glowR = CELL * 1.2 * pulse;
    const grad = ctx.createRadialGradient(fx, fy, 0, fx, fy, glowR);
    grad.addColorStop(0, `rgba(255, 100, 100, ${0.3 * pulse})`);
    grad.addColorStop(1, 'rgba(255, 100, 100, 0)');
    ctx.fillStyle = grad;
    ctx.fillRect(fx - glowR, fy - glowR, glowR * 2, glowR * 2);

    // Food body
    const fr = CELL * 0.32 * pulse;
    ctx.fillStyle = '#ff6b6b';
    ctx.beginPath();
    ctx.arc(fx, fy, fr, 0, Math.PI * 2);
    ctx.fill();

    // Food shine
    ctx.fillStyle = 'rgba(255,255,255,0.35)';
    ctx.beginPath();
    ctx.arc(fx - fr * 0.25, fy - fr * 0.25, fr * 0.35, 0, Math.PI * 2);
    ctx.fill();
  }

  // Snake body
  if (snake.length > 0) {
    const len = snake.length;
    for (let i = len - 1; i >= 0; i--) {
      const seg = snake[i];
      const sx = seg.x * CELL;
      const sy = seg.y * CELL;
      const isHead = i === 0;
      const t = isHead ? 0 : i / Math.max(1, len - 1);

      // Gradient from bright head to darker tail
      const r = Math.round(127 - t * 60);
      const g = Math.round(219 - t * 90);
      const b = Math.round(202 - t * 80);
      const color = `rgb(${r},${g},${b})`;

      // Shadow
      ctx.fillStyle = 'rgba(0,0,0,0.3)';
      roundRect(ctx, sx + 1.5, sy + 1.5, CELL - 3, CELL - 3, isHead ? 7 : 5);
      ctx.fill();

      // Body segment
      ctx.fillStyle = color;
      roundRect(ctx, sx + 1.5, sy + 1.5, CELL - 3, CELL - 3, isHead ? 7 : 5);
      ctx.fill();

      // Highlight on top
      ctx.fillStyle = 'rgba(255,255,255,0.12)';
      roundRect(ctx, sx + 2, sy + 2, CELL - 4, CELL * 0.45, isHead ? 6 : 4);
      ctx.fill();

      // Joints between segments
      if (i > 0) {
        const prev = snake[i - 1];
        const dx = seg.x - prev.x;
        const dy = seg.y - prev.y;
        // Draw a rounded connector
        ctx.fillStyle = color;
        const jointW = CELL - 5;
        const jointH = CELL - 5;
        let jx, jy;
        if (dx === 1) { jx = sx + CELL - 2; jy = sy + 2; }
        else if (dx === -1) { jx = sx - 2; jy = sy + 2; }
        else if (dy === 1) { jx = sx + 2; jy = sy + CELL - 2; }
        else if (dy === -1) { jx = sx + 2; jy = sy - 2; }
        else { continue; }
        roundRect(ctx, jx, jy, jointW, jointH, 4);
        ctx.fill();
      }

      // Head details
      if (isHead) {
        // Eyes
        const eyeSize = 3;
        const pupilSize = 1.5;
        let ex1, ey1, ex2, ey2;
        const cx = sx + CELL / 2;
        const cy = sy + CELL / 2;

        if (direction.x === 1) {
          ex1 = cx + 3; ey1 = cy - 4;
          ex2 = cx + 3; ey2 = cy + 4;
        } else if (direction.x === -1) {
          ex1 = cx - 3; ey1 = cy - 4;
          ex2 = cx - 3; ey2 = cy + 4;
        } else if (direction.y === -1) {
          ex1 = cx - 4; ey1 = cy - 3;
          ex2 = cx + 4; ey2 = cy - 3;
        } else {
          ex1 = cx - 4; ey1 = cy + 3;
          ex2 = cx + 4; ey2 = cy + 3;
        }

        // Eye whites
        ctx.fillStyle = '#fff';
        ctx.beginPath(); ctx.arc(ex1, ey1, eyeSize, 0, Math.PI * 2); ctx.fill();
        ctx.beginPath(); ctx.arc(ex2, ey2, eyeSize, 0, Math.PI * 2); ctx.fill();

        // Pupils looking in movement direction
        ctx.fillStyle = '#111';
        ctx.beginPath(); ctx.arc(ex1 + direction.x * 1.2, ey1 + direction.y * 1.2, pupilSize, 0, Math.PI * 2); ctx.fill();
        ctx.beginPath(); ctx.arc(ex2 + direction.x * 1.2, ey2 + direction.y * 1.2, pupilSize, 0, Math.PI * 2); ctx.fill();
      }
    }
  }

  // Particles
  for (const p of particles) {
    const alpha = p.life / p.maxLife;
    ctx.globalAlpha = alpha;
    ctx.fillStyle = p.color;
    ctx.beginPath();
    ctx.arc(p.x, p.y, p.size * alpha, 0, Math.PI * 2);
    ctx.fill();
  }
  ctx.globalAlpha = 1;

  // Score pops
  for (const sp of scorePops) {
    const alpha = Math.min(1, sp.life / 0.3);
    ctx.globalAlpha = alpha;
    ctx.fillStyle = '#ffd93d';
    ctx.font = 'bold 16px "Segoe UI", system-ui, sans-serif';
    ctx.textAlign = 'center';
    ctx.textBaseline = 'middle';
    ctx.fillText(sp.text, sp.x, sp.y);
  }
  ctx.globalAlpha = 1;

  // Speed flash overlay
  if (speedFlash > 0) {
    ctx.fillStyle = `rgba(232, 168, 56, ${speedFlash * 0.08})`;
    ctx.fillRect(0, 0, W, H);
  }

  // Death flash
  if (flashAlpha > 0) {
    const fa = Math.min(1, flashAlpha);
    ctx.fillStyle = `rgba(255, 40, 40, ${fa * 0.35})`;
    ctx.fillRect(0, 0, W, H);
  }

  // Overlay screens
  if (gameState === 'ready') {
    ctx.fillStyle = 'rgba(0,0,0,0.5)';
    ctx.fillRect(0, 0, W, H);
    ctx.fillStyle = '#7fdbca';
    ctx.font = 'bold 32px "Segoe UI", system-ui, sans-serif';
    ctx.textAlign = 'center';
    ctx.textBaseline = 'middle';
    ctx.fillText('SNAKE', W / 2, H / 2 - 20);
    ctx.fillStyle = '#8888aa';
    ctx.font = '14px "Segoe UI", system-ui, sans-serif';
    ctx.fillText('Arrow keys or WASD to move', W / 2, H / 2 + 20);
    ctx.fillText('Press any arrow key to start', W / 2, H / 2 + 42);
  }

  if (gameState === 'paused') {
    ctx.fillStyle = 'rgba(0,0,0,0.45)';
    ctx.fillRect(0, 0, W, H);
    ctx.fillStyle = '#e8a838';
    ctx.font = 'bold 28px "Segoe UI", system-ui, sans-serif';
    ctx.textAlign = 'center';
    ctx.textBaseline = 'middle';
    ctx.fillText('PAUSED', W / 2, H / 2);
    ctx.fillStyle = '#8888aa';
    ctx.font = '13px "Segoe UI", system-ui, sans-serif';
    ctx.fillText('Press P to resume', W / 2, H / 2 + 28);
  }

  if (gameState === 'dead') {
    ctx.fillStyle = 'rgba(0,0,0,0.55)';
    ctx.fillRect(0, 0, W, H);

    // Flash fade
    if (flashAlpha > 0) {
      const fa = Math.min(1, flashAlpha);
      ctx.fillStyle = `rgba(255, 40, 40, ${fa * 0.25})`;
      ctx.fillRect(0, 0, W, H);
    }

    ctx.fillStyle = '#ff6b6b';
    ctx.font = 'bold 30px "Segoe UI", system-ui, sans-serif';
    ctx.textAlign = 'center';
    ctx.textBaseline = 'middle';
    ctx.fillText('GAME OVER', W / 2, H / 2 - 30);

    ctx.fillStyle = '#7fdbca';
    ctx.font = 'bold 20px "Segoe UI", system-ui, sans-serif';
    ctx.fillText(`Score: ${score}`, W / 2, H / 2 + 5);

    ctx.fillStyle = '#e8a838';
    ctx.font = '14px "Segoe UI", system-ui, sans-serif';
    ctx.fillText(`Best: ${bestScore}`, W / 2, H / 2 + 28);

    const blink = Math.sin(performance.now() / 300) > 0;
    if (blink) {
      ctx.fillStyle = '#ffffff';
      ctx.font = '14px "Segoe UI", system-ui, sans-serif';
      ctx.fillText('Press SPACE to restart', W / 2, H / 2 + 60);
    }
  }

  ctx.restore();
}

// Rounded rect helper
function roundRect(ctx, x, y, w, h, r) {
  ctx.beginPath();
  ctx.moveTo(x + r, y);
  ctx.lineTo(x + w - r, y);
  ctx.quadraticCurveTo(x + w, y, x + w, y + r);
  ctx.lineTo(x + w, y + h - r);
  ctx.quadraticCurveTo(x + w, y + h, x + w - r, y + h);
  ctx.lineTo(x + r, y + h);
  ctx.quadraticCurveTo(x, y + h, x, y + h - r);
  ctx.lineTo(x, y + r);
  ctx.quadraticCurveTo(x, y, x + r, y);
  ctx.closePath();
}

// --- Start ---
initGame();
gameState = 'ready';
lastMoveTime = performance.now();

// Listen for first key to start
document.addEventListener('keydown', function startHandler(e) {
  if (gameState === 'ready' && ['ArrowUp','ArrowDown','ArrowLeft','ArrowRight','KeyW','KeyS','KeyA','KeyD'].includes(e.code)) {
    gameState = 'playing';
    lastMoveTime = performance.now();
    tickRate = 130;
    speedLevel = 1;
    prevSpeedLevel = 1;
    document.removeEventListener('keydown', startHandler);
  }
}, { once: false });

let prevTime = performance.now();
function loop(now) {
  let dt = (now - prevTime) / 1000;
  prevTime = now;
  // Clamp dt to avoid huge jumps
  if (dt > 0.1) dt = 0.016;

  update(dt);
  render();

  // Update HUD
  document.getElementById('scoreVal').textContent = score;
  document.getElementById('speedVal').textContent = speedLevel;

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

Same prompt, other models

2 more
Compare side by side

One email when a new model lands on the board or in the showcase. Unsubscribe anytime.