Claude Haiku 4.5
by AnthropicReasoningClean
Running live in a sandboxed frame. Click inside it before using the keyboard.
How it went
- Total time
- 52.7 s
- Cost
- $0.096
- Output tokens
- 19,105
- Spent thinking
- 14,868 tokens
- Speed
- 369.6 tok/s
- Console errors
- 0
- First token after
- 953 ms
- First visible text after
- 51.1 s
- Prompt tokens
- 554
- Code size
- 11.3 KB
- Finish reason
- stop
- Served by
- Amazon Bedrock
- Model id
anthropic/claude-haiku-4.5- Reasoning sent
{"enabled":true}- Max output
- 64,000 tokens
- Generated
- Nov 10, 2026
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 · 379 lines
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Snake Game</title>
<style>
* {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
}
#gameContainer {
position: relative;
background: #1a1a2e;
border-radius: 12px;
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.5);
padding: 20px;
display: flex;
flex-direction: column;
align-items: center;
gap: 15px;
}
canvas {
display: block;
background: #0f0f1e;
border: 3px solid #667eea;
border-radius: 8px;
}
.ui {
display: flex;
gap: 30px;
color: #fff;
font-size: 18px;
font-weight: bold;
}
.ui div {
background: rgba(102, 126, 234, 0.3);
padding: 10px 25px;
border-radius: 6px;
border: 2px solid #667eea;
}
.overlay {
position: absolute;
top: 20px;
left: 20px;
right: 20px;
bottom: 20px;
background: rgba(0, 0, 0, 0.85);
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
border-radius: 8px;
color: #fff;
z-index: 100;
backdrop-filter: blur(4px);
}
.overlay.hidden {
display: none;
}
.overlay h1 {
font-size: 48px;
margin-bottom: 20px;
color: #ffd700;
text-shadow: 0 2px 10px rgba(255, 215, 0, 0.3);
}
.overlay p {
margin: 12px 0;
font-size: 22px;
}
.overlay .subtitle {
font-size: 16px;
color: #aaa;
margin-top: 20px;
}
@media (max-width: 600px) {
#gameContainer {
padding: 12px;
}
canvas {
max-width: 100vw;
height: auto;
}
.overlay h1 {
font-size: 32px;
}
.overlay p {
font-size: 18px;
}
}
</style>
</head>
<body>
<div id="gameContainer">
<canvas id="gameCanvas"></canvas>
<div class="ui">
<div>Score: <span id="score">0</span></div>
<div>Best: <span id="bestScore">0</span></div>
</div>
<div id="overlay" class="overlay">
<h1>Snake Game</h1>
<p id="overlayText">Click to start playing</p>
<div class="subtitle" id="overlaySubtext">Demo mode running...</div>
</div>
</div>
<script>
const GRID_WIDTH = 20;
const GRID_HEIGHT = 20;
const CELL_SIZE = 30;
const GAME_SPEED = 120;
const canvas = document.getElementById('gameCanvas');
const ctx = canvas.getContext('2d');
canvas.width = GRID_WIDTH * CELL_SIZE;
canvas.height = GRID_HEIGHT * CELL_SIZE;
let snake = [{ x: 10, y: 10 }];
let food = { x: 15, y: 15 };
let direction = { x: 1, y: 0 };
let nextDirection = { x: 1, y: 0 };
let score = 0;
let bestScore = 0;
let gameState = 'demo';
let particles = [];
let lastMoveTime = 0;
const overlay = document.getElementById('overlay');
const overlayText = document.getElementById('overlayText');
const overlaySubtext = document.getElementById('overlaySubtext');
function spawnFood() {
let valid = false;
while (!valid) {
food = {
x: Math.floor(Math.random() * GRID_WIDTH),
y: Math.floor(Math.random() * GRID_HEIGHT)
};
valid = !snake.some(s => s.x === food.x && s.y === food.y);
}
}
function aiDecision() {
const head = snake[0];
const dx = food.x - head.x;
const dy = food.y - head.y;
if (Math.abs(dx) > Math.abs(dy)) {
if (dx > 0 && direction.x === 0) nextDirection = { x: 1, y: 0 };
else if (dx < 0 && direction.x === 0) nextDirection = { x: -1, y: 0 };
else if (dy > 0 && direction.y === 0) nextDirection = { x: 0, y: 1 };
else if (dy < 0 && direction.y === 0) nextDirection = { x: 0, y: -1 };
} else {
if (dy > 0 && direction.y === 0) nextDirection = { x: 0, y: 1 };
else if (dy < 0 && direction.y === 0) nextDirection = { x: 0, y: -1 };
else if (dx > 0 && direction.x === 0) nextDirection = { x: 1, y: 0 };
else if (dx < 0 && direction.x === 0) nextDirection = { x: -1, y: 0 };
}
}
function update(deltaTime) {
lastMoveTime += deltaTime;
if (lastMoveTime < GAME_SPEED) return;
lastMoveTime -= GAME_SPEED;
if (gameState === 'demo') aiDecision();
if (gameState === 'paused' || gameState === 'gameOver') return;
direction = nextDirection;
const head = snake[0];
const newHead = { x: head.x + direction.x, y: head.y + direction.y };
if (newHead.x < 0 || newHead.x >= GRID_WIDTH || newHead.y < 0 || newHead.y >= GRID_HEIGHT) {
if (gameState === 'demo') {
resetGame();
} else {
endGame();
}
return;
}
if (snake.some(s => s.x === newHead.x && s.y === newHead.y)) {
if (gameState === 'demo') {
resetGame();
} else {
endGame();
}
return;
}
snake.unshift(newHead);
if (newHead.x === food.x && newHead.y === food.y) {
score += 10;
document.getElementById('score').textContent = score;
createParticles(food.x, food.y);
spawnFood();
} else {
snake.pop();
}
}
function createParticles(x, y) {
for (let i = 0; i < 8; i++) {
const angle = (Math.PI * 2 * i) / 8;
particles.push({
x: x + 0.5,
y: y + 0.5,
vx: Math.cos(angle) * 3,
vy: Math.sin(angle) * 3,
life: 0.5,
maxLife: 0.5
});
}
}
function updateParticles(deltaTime) {
particles = particles.filter(p => {
p.life -= deltaTime / 1000;
p.x += p.vx;
p.y += p.vy;
return p.life > 0;
});
}
function draw() {
ctx.fillStyle = '#0f0f1e';
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.strokeStyle = 'rgba(102, 126, 234, 0.1)';
ctx.lineWidth = 0.5;
for (let i = 0; i <= GRID_WIDTH; i++) {
ctx.beginPath();
ctx.moveTo(i * CELL_SIZE, 0);
ctx.lineTo(i * CELL_SIZE, canvas.height);
ctx.stroke();
}
for (let i = 0; i <= GRID_HEIGHT; i++) {
ctx.beginPath();
ctx.moveTo(0, i * CELL_SIZE);
ctx.lineTo(canvas.width, i * CELL_SIZE);
ctx.stroke();
}
ctx.fillStyle = '#ff6b6b';
ctx.shadowColor = 'rgba(255, 107, 107, 0.5)';
ctx.shadowBlur = 10;
ctx.beginPath();
ctx.arc((food.x + 0.5) * CELL_SIZE, (food.y + 0.5) * CELL_SIZE, CELL_SIZE * 0.35, 0, Math.PI * 2);
ctx.fill();
ctx.shadowColor = 'transparent';
snake.forEach((segment, index) => {
if (index === 0) {
ctx.fillStyle = '#4ecca3';
ctx.shadowColor = 'rgba(76, 204, 163, 0.5)';
ctx.shadowBlur = 10;
ctx.fillRect(segment.x * CELL_SIZE + 2, segment.y * CELL_SIZE + 2, CELL_SIZE - 4, CELL_SIZE - 4);
ctx.fillStyle = '#000';
const eyeSize = 3;
if (direction.x === 1) { // Right
ctx.fillRect(segment.x * CELL_SIZE + 20, segment.y * CELL_SIZE + 8, eyeSize, eyeSize);
ctx.fillRect(segment.x * CELL_SIZE + 20, segment.y * CELL_SIZE + 19, eyeSize, eyeSize);
} else if (direction.x === -1) { // Left
ctx.fillRect(segment.x * CELL_SIZE + 7, segment.y * CELL_SIZE + 8, eyeSize, eyeSize);
ctx.fillRect(segment.x * CELL_SIZE + 7, segment.y * CELL_SIZE + 19, eyeSize, eyeSize);
} else if (direction.y === -1) { // Up
ctx.fillRect(segment.x * CELL_SIZE + 8, segment.y * CELL_SIZE + 7, eyeSize, eyeSize);
ctx.fillRect(segment.x * CELL_SIZE + 19, segment.y * CELL_SIZE + 7, eyeSize, eyeSize);
} else if (direction.y === 1) { // Down
ctx.fillRect(segment.x * CELL_SIZE + 8, segment.y * CELL_SIZE + 20, eyeSize, eyeSize);
ctx.fillRect(segment.x * CELL_SIZE + 19, segment.y * CELL_SIZE + 20, eyeSize, eyeSize);
}
ctx.shadowColor = 'transparent';
} else {
const shade = Math.max(100, 200 - index * 5);
ctx.fillStyle = `rgb(76, ${shade}, 163)`;
ctx.shadowColor = `rgba(76, ${shade}, 163, 0.3)`;
ctx.shadowBlur = 5;
ctx.fillRect(segment.x * CELL_SIZE + 1, segment.y * CELL_SIZE + 1, CELL_SIZE - 2, CELL_SIZE - 2);
}
});
ctx.shadowColor = 'transparent';
particles.forEach(p => {
ctx.fillStyle = `rgba(255, 107, 107, ${(p.life / p.maxLife) * 0.8})`;
ctx.shadowColor = `rgba(255, 107, 107, ${(p.life / p.maxLife) * 0.5})`;
ctx.shadowBlur = 5;
ctx.beginPath();
ctx.arc(p.x * CELL_SIZE, p.y * CELL_SIZE, 3, 0, Math.PI * 2);
ctx.fill();
});
ctx.shadowColor = 'transparent';
}
function endGame() {
gameState = 'gameOver';
if (score > bestScore) {
bestScore = score;
document.getElementById('bestScore').textContent = bestScore;
}
overlayText.textContent = `Game Over! Score: ${score}`;
overlaySubtext.textContent = 'Press SPACE or ENTER to restart';
overlay.classList.remove('hidden');
}
function resetGame() {
snake = [{ x: 10, y: 10 }];
direction = { x: 1, y: 0 };
nextDirection = { x: 1, y: 0 };
score = 0;
document.getElementById('score').textContent = score;
particles = [];
spawnFood();
gameState = 'demo';
overlayText.textContent = 'Click to start playing';
overlaySubtext.textContent = 'Demo mode running...';
overlay.classList.remove('hidden');
}
function startGame() {
if (gameState === 'demo') {
gameState = 'playing';
overlay.classList.add('hidden');
}
}
canvas.addEventListener('click', startGame);
window.addEventListener('keydown', (e) => {
const key = e.key.toLowerCase();
if (gameState === 'demo') {
startGame();
return;
}
if (key === ' ' || key === 'enter') {
if (gameState === 'gameOver') {
resetGame();
}
} else if (key === 'p') {
gameState = gameState === 'playing' ? 'paused' : 'playing';
} else if (key === 'arrowup' || key === 'w') {
if (direction.y === 0) nextDirection = { x: 0, y: -1 };
} else if (key === 'arrowdown' || key === 's') {
if (direction.y === 0) nextDirection = { x: 0, y: 1 };
} else if (key === 'arrowleft' || key === 'a') {
if (direction.x === 0) nextDirection = { x: -1, y: 0 };
} else if (key === 'arrowright' || key === 'd') {
if (direction.x === 0) nextDirection = { x: 1, y: 0 };
}
});
let lastTime = 0;
function gameLoop(currentTime) {
const deltaTime = lastTime ? currentTime - lastTime : 0;
lastTime = currentTime;
update(deltaTime);
updateParticles(deltaTime);
draw();
requestAnimationFrame(gameLoop);
}
spawnFood();
requestAnimationFrame(gameLoop);
</script>
</body>
</html>Reasoning trace (14,868 tokens)
Let me create a polished Snake game with all the required features. I need to:
1. Create a 20×20 grid (or larger for more fun)
2. Implement arrow keys and WASD controls
3. Handle quick successive key presses properly (input buffering)
4. Prevent snake from reversing onto itself
5. Food spawning with +10 points and snake growth
6. Game over detection with overlay showing score
7. Space/Enter to restart, P to pause
8. Visual polish with:
- Smooth movement
- Snake with distinct head and eyes
- Particle burst when eating
9. Display current score and best score
Let me structure this:
```html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Snake Game</title>
<style>
/* CSS here */
</style>
</head>
<body>
<canvas id="gameCanvas"></canvas>
<script>
/* JavaScript here */
</script>
</body>
</html>
```
Key implementation details:
1. **Grid System**: 20×20 cells with each cell being a certain pixel size
2. **Snake Movement**: Use a queue/deque for the snake body. On each frame, move the head in the current direction, add to body, and remove tail (unless eating)
3. **Input Handling**: Store the next direction and current direction separately. For buffering, keep track of pending inputs
4. **Collision Detection**: Check if head hits walls or body
5. **Food Spawning**: Random position, but not on snake
6. **Visual Polish**:
- Snake head has eyes
- Smooth animation with delta time or lerping
- Particle effects when eating
7. **Game States**: Playing, Paused, GameOver
- box-sizing: border-box;
}
body {
display: flex; justify-content: center; align-items: center; min-height: 100vh; background: linear-gradient(135deg, #667eea
Starting with the full document skeleton, I set up a reset stylesheet and center the canvas with flexbox on a gradient background for visual appeal.
The game container uses a dark navy card style with rounded corners and shadow for depth, housing the canvas and a UI bar showing score. I style the canvas with a border and the score/UI divs with semi-transparent backgrounds matching the accent color. I also add an overlay class for game-over or start screens, positioned absolutely over the canvas with centered flex content and a dark semi-transparent background.
The HTML body sets up the game container, canvas, score display, and the overlay with a title, score paragraph, and restart instructions. I move into the script section, defining constants for grid dimensions, cell size, and game speed to establish the base game logic.
') {
if (gameState === 'gameOver') resetGame();
}
if (e.key === 'p' || e.key === 'P') {
gameState = gameState === 'playing' ? 'paused' : (gameState === 'paused' ? 'playing' : gameState);
}
const key = e.key.toLowerCase();
if ((key === 'arrowup' || key === 'w') && direction.y === 0) nextDirection = { x: 0, y: -1 };
else if ((key === 'arrowdown' || key === 's') && direction.y === 0) nextDirection = { x: 0, y: 1 };
else if ((key === 'arrowleft' || key === 'a') && direction.x === 0) nextDirection = { x: -1, y: 0 };
else if ((key === 'arrowright' || key === 'd') && direction.x === 0) nextDirection = { x: 1, y: 0 };
});
Setting up keyup tracking and a spawnFood function to place food randomly on the grid, avoiding the snake's body.
The update function handles game timing with deltaTime, applies the buffered direction, moves the snake head, and checks for wall collisions triggering game over.
collision with itself ends the game too. Eating food increments score by 10, spawns particles, and generates new food; otherwise the tail segment gets removed to maintain length. Particles spawn in 8 directions radiating outward with a short lifespan, and updateParticles handles their movement and decay, filtering out dead ones.
For drawing, I clear the canvas with a dark background, then draw a subtle grid using translucent lines. Food gets rendered as a glowing red circle using shadow effects for a nice visual touch.
Resetting shadow to transparent before drawing the snake. Each segment renders as a rounded square, with the head getting special treatment - a teal color with glow, plus directional eyes positioned based on current movement direction (handling right and left cases with different offsets).
For up and down directions, eyes go at the top or bottom of the head cell. After drawing eyes, clearing the shadow again. Body segments get a gradient effect, shade darkening slightly further down the tail, each with a subtle glow matching its color.
Once all segments render, particles get drawn as fading red circles sized by remaining life, with matching glow. Then gameOver() handles updating best score display and showing the overlay, while resetGame() reinitializes the snake position, direction, and score back to defaults.
The game loop uses requestAnimationFrame with delta time tracking, calling update, particle updates, and draw each frame before scheduling the next one.
Going back through requirements to verify coverage - grid size, dual control schemes, input buffering, reverse prevention, scoring, food spawn validation, collision detection, overlay, restart/pause keys, smooth movement all check out.
But I'm missing something: the spec calls for a self-playing demo mode with simple AI behind a "click or press a key to start" message, ensuring something's visible on first paint. I need to add this demo behavior to the implementation.
I'll build a small AI that steers the snake toward food during the demo phase, then switches to player control once they interact, overlaying a start message until then.
y .instruction {
margin-top: 30px;
font-size: 18px;
color: #aaa;
text-align: center;
}
I set up the HTML structure next—canvas inside a gameContainer, UI showing score and best score, plus an overlay div for start/game-over messages with instructions. Then I move into the script, defining grid constants (20x20 at 30px cells) and initializing the canvas dimensions and 2D context before setting up game state variables.
(e.key === ' ' || e.key === 'Enter') {
if (gameState === 'gameOver') {
resetGame();
}
}
});
I'm wiring up pause toggling with 'p', and direction changes with arrow keys/WASD, making sure to block reversing into the snake's own body by checking the current direction axis. Next I need a spawnFood function that picks random coordinates and validates they don't overlap the snake.
For movement logic, I'm building a simple greedy AI that compares the food's x/y offset from the head and prioritizes moving along whichever axis has the larger distance, falling back to the other axis if blocked.
Now setting up the update loop, which handles AI movement during demo mode or regular gameplay, timing moves based on GAME_SPEED, and beginning to calculate the new head position for the snake.
For wall collisions, I reset the game in demo mode but trigger game over otherwise. Self-collision gets the same treatment. After moving the head, I check for food collisions - score increments, particles spawn, and new food appears, otherwise just pop the tail to maintain length.
I spin off eight particles radiating outward when food is eaten, each with velocity based on angle and a half-second lifespan. The update function decrements particle life and moves them, filtering out dead ones.
Drawing happens in layers - background, subtle grid lines, food with a glow effect, then the snake with a distinct head showing eyes that point in the current direction, and body segments with gradient shading by index. Particles render last with fading opacity based on remaining life.
Game over updates best score if needed and shows the overlay with restart instructions. Reset reinitializes everything and switches to demo mode with appropriate messaging. The game loop ties updates and drawing together via requestAnimationFrame.
Looking back at this, I realize I should simplify the overlay text handling and ensure proper responsiveness. Let me revisit the core requirements: 20×20 grid minimum, WASD/arrow controls with no reversal, scoring, food spawning away from the snake, game over with overlay, pause/restart keys, and visual polish with particles and animated head. I also need the self-playing demo mode per the general game requirements, so the game should start with AI control until the player interacts.
I'll restructure the HTML with cleaner styling - gradient background, rounded container, distinct overlay styling with proper z-index and backdrop blur, plus responsive media queries for smaller screens. The JavaScript will define grid constants, canvas setup, and initialize the snake, food, and direction state before building out the demo AI and game loop logic.