Models 44

Xing4.0 29B A4B (free)

by XingChenReasoning1 console error
Open in new window

Running live in a sandboxed frame. Click inside it before using the keyboard.

How it went

Total time
1 min 20 s
Cost
$0
Output tokens
5,812
Spent thinking
0 tokens
Speed
74 tok/s
Console errors
1
First token after
1.1 s
First visible text after
1.1 s
Prompt tokens
519
Code size
14.5 KB
Finish reason
stop
Served by
Phala
Model id
xingchen-agi/xing4.0-29b-a4b:free
Reasoning sent
{"effort":"none"}
Max output
32,000 tokens
Generated
Nov 9, 2026

Console errors

Caught in the first 3 seconds after load, in a sandboxed iframe like the one above.

updateHUD is not defined

What it was asked

The prompt
Build a polished Snake game in a single HTML file using vanilla JavaScript and a <canvas>. Requirements: - A grid of at least 20×20 cells, centered on the page. - Arrow keys and WASD control the snake. Quick successive key presses must both be honored, but the snake can never reverse onto itself. - Eating food adds 10 points and grows the snake by one cell; new food never spawns on the snake. - Game over when the snake hits a wall or itself, with an overlay showing the score; Space or Enter restarts, P pauses. - Visual polish: smooth movement, a snake with a distinct head and eyes facing its direction, and a small particle burst when eating. - Display the current score and the best score of the session.
System prompt, sent with every prompt
You are generating a self-contained web demo. It will be rendered automatically in a sandboxed iframe and compared side by side with the output of other AI models given the exact same task.

Output rules:
- Reply with exactly ONE fenced code block containing the complete file: ```html (or ```svg when the task asks for an SVG). No text before or after the code block.
- Everything must be inline: CSS in <style>, JavaScript in <script>. No external files, images, fonts or network requests, except the CDN URLs explicitly allowed by the task.
- Do not use localStorage, sessionStorage, cookies, IndexedDB, alert(), confirm(), prompt() or window.open(): they are blocked in the sandbox and will throw.
- The page must look right in a 1280×800 viewport and adapt gracefully down to 375px wide. No horizontal scrollbar.
- Something meaningful must be visible on first paint: a screenshot is taken automatically about 3 seconds after load, without any interaction.
- Everything that makes the demo interesting must be visible within the first seconds: nothing hidden behind a high score, a later level or a long play session.
- Games must start in a self-playing demo mode (a simple AI plays) behind a "Click or press a key to start" message, so the game can be judged in action without playing.
- The iframe only receives keyboard events after the user clicks it: if the demo uses the keyboard, display a clear "Click or press a key to start" message.
- The code must run with zero errors in the console of the latest Chrome.

Code run-1.html · 564 lines

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Neon Snake</title>
<style>
  * { margin: 0; padding: 0; box-sizing: border-box; }

  body {
    background: #0a0a12;
    color: #e0e0e0;
    font-family: 'Segoe UI', system-ui, -apple-system, sans-serif;
    display: flex;
    justify-content: center;
    align-items: center;
    min-height: 100vh;
    overflow: hidden;
    user-select: none;
  }

  .game-wrap {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 10px;
    padding: 16px;
  }

  #scoreboard {
    display: flex;
    justify-content: space-between;
    width: 520px;
    max-width: 96vw;
    font-size: 14px;
    font-weight: 600;
    letter-spacing: 0.1em;
  }

  #scoreboard .label {
    color: #6a6a8a;
    font-size: 11px;
    text-transform: uppercase;
  }

  #scoreboard .value {
    font-variant-numeric: tabular-nums;
    font-size: 24px;
  }

  #board-container {
    position: relative;
    border-radius: 14px;
    overflow: hidden;
    box-shadow: 0 0 30px rgba(0, 200, 255, 0.12), inset 0 0 2px rgba(0, 200, 255, 0.3);
  }

  canvas {
    display: block;
    background: #0e0e1a;
  }

  /* Overlay */
  .overlay {
    position: absolute;
    inset: 0;
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    background: rgba(10, 10, 20, 0.78);
    backdrop-filter: blur(4px);
    z-index: 10;
    text-align: center;
    transition: opacity 0.25s ease;
  }

  .overlay.hidden { opacity: 0; pointer-events: none; }

  .overlay h1 {
    font-size: 38px;
    letter-spacing: 0.06em;
    margin-bottom: 6px;
    background: linear-gradient(135deg, #00ffcc, #00aaff);
    -webkit-background-clip: text;
    -webkit-text-fill-color: transparent;
    background-clip: text;
  }

  .overlay p {
    color: #8a8aa0;
    font-size: 14px;
    margin-bottom: 20px;
  }

  .overlay .restart-hint {
    font-size: 13px;
    color: #555570;
    margin-top: 18px;
  }

  #best-label { color: #8a8aa0; font-size: 11px; text-transform: uppercase; letter-spacing: 0.1em; }

  /* Footer controls hint */
  .controls-hint {
    font-size: 11px;
    color: #3a3a50;
    text-align: center;
  }
</style>
</head>
<body>

<div class="game-wrap">
  <div id="scoreboard">
    <span>
      <span class="label">Score</span>
      <br>
      <span class="value" id="score" style="color:#00ffcc;">0</span>
    </span>
    <span>
      <span class="label">Best</span>
      <br>
      <span class="value" id="best" style="color:#ffd700;">0</span>
    </span>
  </div>

  <div id="board-container">
    <canvas id="game" width="520" height="520"></canvas>
    <div class="overlay" id="overlay">
      <h1>NEON SNAKE</h1>
      <p>WASD or Arrow keys to move</p>
      <div class="restart-hint">Space or Enter to restart · P to pause</div>
    </div>
  </div>
</div>

<p class="controls-hint">Arrow keys / WASD &nbsp;|&nbsp; Space/Enter restart &nbsp;|&nbsp; P pause</p>

<script>
(() => {
  'use strict';

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

  // ---- Game constants ----
  const GRID_SIZE = 20; // cells per side
  const CELL_SIZE = W / GRID_SIZE; // = 26
  const MOVE_INTERVAL = 110; // ms between steps
  const MAX_SPEED = 180; // ms per step cap
  const INITIAL_LENGTH = 3;
  const FOOD_POINTS = 10;

  // ---- DOM refs ----
  const scoreEl = document.getElementById('score');
  const bestEl = document.getElementById('best');
  const overlay = document.getElementById('overlay');

  // ---- State ----
  let snake = [];        // array of {x, y} from head to tail
  let direction = { x: 1, y: 0 };
  let nextDirection = { x: 1, y: 0 };
  let food = {};
  let score = 0;
  let bestScore = 0;
  let running = false;
  let paused = false;
  let gameOver = false;
  let particles = [];
  let highScoreLocal = null;
  let tickTimer = null;
  let lastMoveTime = 0;
  let animationFrameId = null;
  let blinkTimer = null;
  let showStartBanner = true;

  // ---- Init snake ----
  function createSnake() {
    snake = [];
    const startX = Math.floor(GRID_SIZE / 2);
    const startY = Math.floor(GRID_SIZE / 2);
    for (let i = 0; i < INITIAL_LENGTH; i++) {
      snake.push({ x: startX - i, y: startY });
    }
  }

  // ---- Food placement ----
  function placeFood() {
    let attempts = 0;
    while (attempts < 500) {
      const fx = Math.floor(Math.random() * GRID_SIZE);
      const fy = Math.floor(Math.random() * GRID_SIZE);
      if (!snake.some(s => s.x === fx && s.y === fy)) {
        food = { x: fx, y: fy };
        return;
      }
      attempts++;
    }
  }

  // ---- Input handling ----
  function handleKeyDown(e) {
    if (running && !gameOver) {
      switch (e.key.toLowerCase()) {
        case 'arrowup': case 'w': if (direction.y !== 1) { nextDirection = { x: 0, y: -1 }; e.preventDefault(); } break;
        case 'arrowdown': case 's': if (direction.y !== -1) { nextDirection = { x: 0, y: 1 }; e.preventDefault(); } break;
        case 'arrowleft': case 'a': if (direction.x !== 1) { nextDirection = { x: -1, y: 0 }; e.preventDefault(); } break;
        case 'arrowright': case 'd': if (direction.x !== -1) { nextDirection = { x: 1, y: 0 }; e.preventDefault(); } break;
        case 'p': togglePause(); break;
        default: break;
      }
      return;
    }
    // During non-running states (start screen / game over), Space/Enter restarts
    if (e.code === 'Space' || e.code === 'Enter') {
      restart();
      e.preventDefault();
    }
  }

  document.addEventListener('keydown', handleKeyDown);
  document.addEventListener('touchstart', handleTouch);

  function handleTouch(e) {
    if (!running || gameOver) return;
    const t = e.changedTouches[0];
    const rect = canvas.getBoundingClientRect();
    const scale = canvas.width / rect.width;
    const tx = Math.round((t.clientX - rect.left) * scale / CELL_SIZE);
    const ty = Math.round((t.clientY - rect.top) * scale / CELL_SIZE);
    tryDirection(tx, ty);
  }

  function tryDirection(targetX, targetY) {
    if (targetX > 0 && direction.x < 1) nextDirection = { x: 1, y: 0 };
    else if (targetX < 0 && direction.x > -1) nextDirection = { x: -1, y: 0 };
    else if (targetY > 0 && direction.y < 1) nextDirection = { x: 0, y: 1 };
    else if (targetY < 0 && direction.y > -1) nextDirection = { x: 0, y: -1 };
    // else ignore — would reverse
  }

  // ---- Core game loop ----
  function gameTick() {
    if (!running || paused || gameOver) return;

    direction = nextDirection;

    const head = snake[0];
    const newHead = { x: head.x + direction.x, y: head.y + direction.y };

    // Wall collision
    if (newHead.x < 0 || newHead.x >= GRID_SIZE || newHead.y < 0 || newHead.y >= GRID_SIZE) {
      endGame();
      return;
    }

    // Self collision (skip the tail cell that will move away, unless eating food)
    const eating = (newHead.x === food.x && newHead.y === food.y);
    const checkCollision = snake.slice(0, 1).concat(eating ? snake : snake.slice(1));
    if (checkCollision.some(s => s.x === newHead.x && s.y === newHead.y)) {
      endGame();
      return;
    }

    snake.unshift(newHead);

    if (eating) {
      score += FOOD_POINTS;
      spawnParticles(newHead.x * CELL_SIZE + CELL_SIZE / 2, newHead.y * CELL_SIZE + CELL_SIZE / 2);
      placeFood();
      updateHUD();
    } else {
      snake.pop();
    }

    draw();
    scheduleNextTick();
  }

  function scheduleNextTick() {
    lastMoveTime = performance.now();
    tickTimer = setTimeout(gameTick, MOVE_INTERVAL);
  }

  function gameLoopAnimation() {
    if (running && !paused && !gameOver) {
      updateParticles();
    }
    animationFrameId = requestAnimationFrame(renderLoop);
  }

  function renderLoop() {
    if (running && !paused && !gameOver) {
      draw();
    }
    animationFrameId = requestAnimationFrame(renderLoop);
  }

  // ---- Particles ----
  function spawnParticles(cx, cy) {
    const count = 14;
    for (let i = 0; i < count; i++) {
      const angle = (Math.PI * 2 * i) / count + Math.random() * 0.4;
      const speed = 1.2 + Math.random() * 2.5;
      particles.push({
        x: cx,
        y: cy,
        vx: Math.cos(angle) * speed,
        vy: Math.sin(angle) * speed,
        life: 1.0,
        decay: 0.02 + Math.random() * 0.02,
        size: 1.5 + Math.random() * 2.5
      });
    }
  }

  function updateParticles() {
    for (let i = particles.length - 1; i >= 0; i--) {
      const p = particles[i];
      p.x += p.vx;
      p.y += p.vy;
      p.vx *= 0.94;
      p.vy *= 0.94;
      p.life -= p.decay;
      if (p.life <= 0) particles.splice(i, 1);
    }
  }

  // ---- Drawing ----
  function draw() {
    ctx.clearRect(0, 0, W, H);

    // Grid background
    drawGrid();

    // Draw food
    drawFood();

    // Draw snake
    drawSnake();

    // Draw particles
    drawParticles();
  }

  function drawGrid() {
    ctx.strokeStyle = 'rgba(40, 40, 70, 0.4)';
    ctx.lineWidth = 1;
    for (let i = 0; i <= GRID_SIZE; i++) {
      const p = i * CELL_SIZE;
      ctx.beginPath();
      ctx.moveTo(p, 0);
      ctx.lineTo(p, H);
      ctx.stroke();
      ctx.beginPath();
      ctx.moveTo(0, p);
      ctx.lineTo(W, p);
      ctx.stroke();
    }
  }

  function drawFood() {
    const cx = food.x * CELL_SIZE + CELL_SIZE / 2;
    const cy = food.y * CELL_SIZE + CELL_SIZE / 2;
    const r = CELL_SIZE * 0.38;

    // Glow pulse
    const pulse = 0.6 + 0.4 * Math.sin(performance.now() * 0.005);
    ctx.save();
    ctx.shadowColor = '#ff3377';
    ctx.shadowBlur = 18 * pulse;
    ctx.fillStyle = '#ff3377';
    ctx.beginPath();
    ctx.arc(cx, cy, r, 0, Math.PI * 2);
    ctx.fill();
    ctx.restore();

    // Inner highlight
    ctx.save();
    ctx.shadowBlur = 0;
    ctx.fillStyle = '#ffcce8';
    ctx.beginPath();
    ctx.arc(cx - r * 0.25, cy - r * 0.25, r * 0.35, 0, Math.PI * 2);
    ctx.fill();
    ctx.restore();
  }

  function drawSnake() {
    for (let i = 0; i < snake.length; i++) {
      const seg = snake[i];
      const px = seg.x * CELL_SIZE;
      const py = seg.y * CELL_SIZE;
      const isHead = (i === 0);
      const pad = isHead ? 1 : 2;

      // Color gradient from head (bright) to tail (dim)
      const t = i / Math.max(snake.length - 1, 1);
      const r = Math.round(0 + t * 0 * 0);
      const g = Math.round(255 * (1 - t * 0.35));
      const b = Math.round(200 + t * 55);
      const alpha = 1 - t * 0.25;

      ctx.save();

      if (isHead) {
        ctx.shadowColor = '#00ffcc';
        ctx.shadowBlur = 12;
        ctx.fillStyle = `rgba(${r},${g},${b},${alpha})`;
      } else {
        ctx.fillStyle = `rgba(${r},${g},${b},${alpha})`;
      }

      roundRect(ctx, px + pad, py + pad, CELL_SIZE - pad * 2, CELL_SIZE - pad * 2, 6);
      ctx.fill();
      ctx.restore();
    }
  }

  function drawEyes(headX, headY, dirX, dirY) {
    const cx = headX * CELL_SIZE + CELL_SIZE / 2;
    const cy = headY * CELL_SIZE + CELL_SIZE / 2;
    const eyeR = 2.2;

    // Offset eye positions based on direction
    const off = CELL_SIZE * 0.16;
    let ex1, ey1, ex2, ey2;
    const dx = dirX, dy = dirY;
    // Perpendicular offset for eye separation
    let px = -dy, py = dx;

    ex1 = cx + dx * off + px * 3;
    ey1 = cy + dy * off + py * 3;
    ex2 = cx + dx * off - px * 3;
    ey2 = cy + dy * off - py * 3;

    ctx.fillStyle = '#ffffff';
    ctx.beginPath();
    ctx.arc(ex1, ey1, eyeR, 0, Math.PI * 2);
    ctx.arc(ex2, ey2, eyeR, 0, Math.PI * 2);
    ctx.fill();

    // Pupils
    ctx.fillStyle = '#0e0e1a';
    ctx.beginPath();
    ctx.arc(ex1 + dx * 0.6, ey1 + dy * 0.6, eyeR * 0.45, 0, Math.PI * 2);
    ctx.arc(ex2 + dx * 0.6, ey2 + dy * 0.6, eyeR * 0.45, 0, Math.PI * 2);
    ctx.fill();
  }

  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();
  }

  function drawParticles() {
    for (const p of particles) {
      ctx.save();
      ctx.globalAlpha = Math.max(0, p.life);
      ctx.fillStyle = '#00ffcc';
      ctx.shadowColor = '#00ffcc';
      ctx.shadowBlur = 8;
      ctx.beginPath();
      ctx.arc(p.x, p.y, p.size * p.life, 0, Math.PI * 2);
      ctx.fill();
      ctx.restore();
    }
  }

  // ---- Game control ----
  function startGame() {
    createSnake();
    placeFood();
    score = 0;
    scoreEl.textContent = '0';
    particles = [];
    updateHUD();
    running = true;
    gameOver = false;
    paused = false;
    showStartBanner = false;
    if (blinkTimer) clearInterval(blinkTimer);
    overlay.classList.add('hidden');
    scheduleNextTick();
  }

  function restart() {
    startGame();
  }

  function endGame() {
    gameOver = true;
    running = false;
    if (tickTimer) clearTimeout(tickTimer);

    // Best score tracking
    if (score > bestScore) {
      bestScore = score;
    }
    highScoreLocal = bestScore;
    updateHUD();

    // Show overlay
    overlay.classList.remove('hidden');
    overlay.innerHTML = '';
    const h1 = document.createElement('h1');
    h1.textContent = 'GAME OVER';
    const p1 = document.createElement('p');
    p1.textContent = `Score: ${score}`;
    const hints = document.createElement('div');
    hints.className = 'restart-hint';
    hints.textContent = 'Press Space or Enter to play again · Press P to pause';
    overlay.appendChild(h1);
    overlay.appendChild(p1);
    overlay.appendChild(hints);
  }

  function togglePause() {
    if (!running || gameOver) return;
    paused = !paused;
    if (paused) {
      if (tickTimer) clearTimeout(tickTimer);
      overlay.innerHTML = '';
      const h1 = document.createElement('h1');
      h1.textContent = 'PAUSED';
      h1.style.fontSize = '34px';
      const p = document.createElement('p');
      p.textContent = 'Press P or Esc to resume';
      const hints = document.createElement('div');
      hints.className = 'restart-hint';
      hints.textContent = 'Press P to resume';
      overlay.appendChild(h1);
      overlay.appendChild(p);
      overlay.appendChild(hints);
      overlay.classList.remove('hidden');
    } else {
      overlay.classList.add('hidden');
      scheduleNextTick();
    }
  }

  // Start render loop so the game animates in the background immediately
  renderLoop();

  // Auto-start demo after a short delay so something meaningful shows on first paint
  setTimeout(() => {
    startGame();
  }, 600);

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