Gemini 3.1 Flash Lite
by GoogleReasoningClean
Running live in a sandboxed frame. Click inside it before using the keyboard.
How it went
- Total time
- 19.5 s
- Cost
- $0.011
- Output tokens
- 6,986
- Spent thinking
- 3,841 tokens
- Speed
- 379.2 tok/s
- Console errors
- 0
- First token after
- 1.1 s
- First visible text after
- 12.5 s
- Prompt tokens
- 507
- Code size
- 9.8 KB
- Finish reason
- stop
- Served by
- Model id
google/gemini-3.1-flash-lite- Reasoning sent
{"effort":"high"}- Max output
- 65,536 tokens
- Generated
- Nov 12, 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 · 312 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>
:root {
--bg: #0f172a;
--snake: #22c55e;
--food: #ef4444;
--text: #f8fafc;
}
body {
margin: 0;
background: var(--bg);
color: var(--text);
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
height: 100vh;
font-family: system-ui, -apple-system, sans-serif;
overflow: hidden;
}
#game-container {
position: relative;
width: 90vw;
max-width: 500px;
aspect-ratio: 1/1;
box-shadow: 0 0 20px rgba(0,0,0,0.5);
border: 2px solid #334155;
border-radius: 8px;
overflow: hidden;
}
canvas {
display: block;
width: 100%;
height: 100%;
background: #1e293b;
}
#ui-overlay {
position: absolute;
inset: 0;
background: rgba(15, 23, 42, 0.85);
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
text-align: center;
transition: opacity 0.3s;
}
.hidden { display: none !important; }
.score-board {
position: absolute;
top: -40px;
width: 100%;
display: flex;
justify-content: space-between;
font-size: 1.2rem;
font-weight: bold;
}
h1 { margin: 0 0 1rem 0; color: var(--snake); }
button {
padding: 10px 20px;
font-size: 1rem;
cursor: pointer;
background: var(--snake);
border: none;
color: white;
border-radius: 4px;
margin-top: 1rem;
}
</style>
</head>
<body>
<div id="game-container">
<div class="score-board">
<div>Score: <span id="score">0</span></div>
<div>Best: <span id="best">0</span></div>
</div>
<canvas id="gameCanvas" width="400" height="400"></canvas>
<div id="ui-overlay">
<h1 id="title">Neon Snake</h1>
<p id="msg">Click or press any key to start</p>
</div>
</div>
<script>
const canvas = document.getElementById('gameCanvas');
const ctx = canvas.getContext('2d');
const scoreEl = document.getElementById('score');
const bestEl = document.getElementById('best');
const overlay = document.getElementById('ui-overlay');
const msgEl = document.getElementById('msg');
const titleEl = document.getElementById('title');
const GRID_SIZE = 20;
const TILE_SIZE = canvas.width / GRID_SIZE;
let snake = [];
let food = {x: 0, y: 0};
let direction = {x: 1, y: 0};
let nextDirection = {x: 1, y: 0};
let dirQueue = [];
let score = 0;
let bestScore = 0;
let particles = [];
let gameState = 'demo'; // demo, playing, paused, gameover
let lastTick = 0;
const tickSpeed = 120;
function resetGame() {
snake = [{x: 10, y: 10}, {x: 9, y: 10}, {x: 8, y: 10}];
direction = {x: 1, y: 0};
nextDirection = {x: 1, y: 0};
dirQueue = [];
score = 0;
scoreEl.innerText = score;
particles = [];
spawnFood();
}
function spawnFood() {
let valid = false;
while (!valid) {
food.x = Math.floor(Math.random() * GRID_SIZE);
food.y = Math.floor(Math.random() * GRID_SIZE);
valid = !snake.some(segment => segment.x === food.x && segment.y === food.y);
}
}
function spawnParticles(x, y) {
for (let i = 0; i < 8; i++) {
particles.push({
x: x * TILE_SIZE + TILE_SIZE/2,
y: y * TILE_SIZE + TILE_SIZE/2,
vx: (Math.random() - 0.5) * 4,
vy: (Math.random() - 0.5) * 4,
life: 1.0,
color: '#ef4444'
});
}
}
function handleInput(key) {
if (gameState === 'demo') {
gameState = 'playing';
overlay.classList.add('hidden');
resetGame();
return;
}
if (gameState === 'gameover') {
if (key === 'Enter' || key === ' ') {
resetGame();
gameState = 'playing';
overlay.classList.add('hidden');
}
return;
}
if (key === 'p' || key === 'P') {
if (gameState === 'playing') {
gameState = 'paused';
titleEl.innerText = "Paused";
msgEl.innerText = "Press P to resume";
overlay.classList.remove('hidden');
} else if (gameState === 'paused') {
gameState = 'playing';
overlay.classList.add('hidden');
}
return;
}
if (gameState !== 'playing') return;
let newDir = null;
if (key === 'ArrowUp' || key === 'w') newDir = {x: 0, y: -1};
else if (key === 'ArrowDown' || key === 's') newDir = {x: 0, y: 1};
else if (key === 'ArrowLeft' || key === 'a') newDir = {x: -1, y: 0};
else if (key === 'ArrowRight' || key === 'd') newDir = {x: 1, y: 0};
if (newDir) {
const lastDir = dirQueue.length > 0 ? dirQueue[dirQueue.length - 1] : direction;
if (newDir.x !== -lastDir.x || newDir.y !== -lastDir.y) {
if (dirQueue.length < 2) dirQueue.push(newDir);
}
}
}
document.addEventListener('keydown', (e) => handleInput(e.key));
function update() {
if (gameState === 'demo') {
// AI simple pathing
const head = snake[0];
const possible = [{x:0, y:-1}, {x:0, y:1}, {x:-1, y:0}, {x:1, y:0}];
let bestMove = direction;
let minScore = Infinity;
possible.forEach(m => {
if (m.x === -direction.x && m.y === -direction.y) return;
const next = {x: head.x + m.x, y: head.y + m.y};
const dist = Math.abs(next.x - food.x) + Math.abs(next.y - food.y);
if (dist < minScore) {
minScore = dist;
bestMove = m;
}
});
direction = bestMove;
moveSnake();
} else if (gameState === 'playing') {
if (dirQueue.length > 0) direction = dirQueue.shift();
moveSnake();
}
particles.forEach(p => {
p.x += p.vx;
p.y += p.vy;
p.life -= 0.05;
});
particles = particles.filter(p => p.life > 0);
}
function moveSnake() {
const head = {x: snake[0].x + direction.x, y: snake[0].y + direction.y};
// Wall collision
if (head.x < 0 || head.x >= GRID_SIZE || head.y < 0 || head.y >= GRID_SIZE ||
snake.some(s => s.x === head.x && s.y === head.y)) {
if (gameState === 'playing') {
gameState = 'gameover';
titleEl.innerText = "Game Over!";
msgEl.innerText = "Score: " + score + ". Press Space/Enter to restart.";
overlay.classList.remove('hidden');
if (score > bestScore) {
bestScore = score;
bestEl.innerText = bestScore;
}
} else if (gameState === 'demo') {
resetGame();
}
return;
}
snake.unshift(head);
if (head.x === food.x && head.y === food.y) {
score += 10;
scoreEl.innerText = score;
spawnParticles(food.x, food.y);
spawnFood();
} else {
snake.pop();
}
}
function draw() {
ctx.fillStyle = '#1e293b';
ctx.fillRect(0, 0, canvas.width, canvas.height);
// Grid
ctx.strokeStyle = '#334155';
ctx.lineWidth = 0.5;
for(let i=0; i<=GRID_SIZE; i++) {
ctx.beginPath(); ctx.moveTo(i*TILE_SIZE, 0); ctx.lineTo(i*TILE_SIZE, canvas.height); ctx.stroke();
ctx.beginPath(); ctx.moveTo(0, i*TILE_SIZE); ctx.lineTo(canvas.width, i*TILE_SIZE); ctx.stroke();
}
// Food
ctx.fillStyle = '#ef4444';
ctx.beginPath();
ctx.arc(food.x * TILE_SIZE + TILE_SIZE/2, food.y * TILE_SIZE + TILE_SIZE/2, TILE_SIZE/3, 0, Math.PI*2);
ctx.fill();
// Snake
snake.forEach((s, i) => {
ctx.fillStyle = i === 0 ? '#16a34a' : '#22c55e';
ctx.fillRect(s.x * TILE_SIZE + 1, s.y * TILE_SIZE + 1, TILE_SIZE - 2, TILE_SIZE - 2);
// Eyes
if (i === 0) {
ctx.fillStyle = 'white';
const eyeX = s.x * TILE_SIZE + TILE_SIZE/2 + (direction.x * 4);
const eyeY = s.y * TILE_SIZE + TILE_SIZE/2 + (direction.y * 4);
ctx.beginPath(); ctx.arc(eyeX - (direction.y ? 3 : 0), eyeY - (direction.x ? 3 : 0), 2, 0, Math.PI*2); ctx.fill();
ctx.beginPath(); ctx.arc(eyeX + (direction.y ? 3 : 0), eyeY + (direction.x ? 3 : 0), 2, 0, Math.PI*2); ctx.fill();
}
});
// Particles
particles.forEach(p => {
ctx.fillStyle = `rgba(239, 68, 68, ${p.life})`;
ctx.beginPath();
ctx.arc(p.x, p.y, 3, 0, Math.PI*2);
ctx.fill();
});
}
function gameLoop(time) {
if (time - lastTick > tickSpeed) {
update();
lastTick = time;
}
draw();
requestAnimationFrame(gameLoop);
}
// Init
resetGame();
requestAnimationFrame(gameLoop);
</script>
</body>
</html>Reasoning trace (3,841 tokens)
**Designing Game Core** I'm currently solidifying the foundational elements for the Snake game. My focus is on establishing the 20x20 grid within a single HTML file and ensuring its responsiveness and centered alignment. The immediate priority is implementing the core movement logic, including preventing reverse movement and handling input buffering. **Implementing Game Mechanics** I'm now concentrating on the core game loop and essential mechanics. This involves integrating the score increment and snake growth logic, ensuring a safe food spawn, and refining the collision detection for game over conditions. I'm also exploring the implementation of pause functionality and a self-playing demo mode. **Optimizing Movement Logic** I'm refining the snake's AI for the demo mode, aiming to have it intelligently navigate towards food while avoiding immediate self-collision. Simultaneously, I'm fine-tuning the input handling to ensure smooth, buffered movement and robust collision detection for game over states. **Adding Game Features** I'm refining input handling to queue successive key presses and prevent invalid 180-degree turns. I'm also preparing to implement visual enhancements like snake eyes and particles, alongside establishing a responsive design using `vw`/`vh` for the 20x20 grid. The pause functionality via the 'P' key is also being integrated. **Refining Game Logic** I'm currently refining the game loop using `requestAnimationFrame`, managing game speed with `lastTickTime`, and implementing robust input buffering to handle rapid key presses while preventing reverse movement. The drawing and update cycles are being structured for clarity. **Improving AI Pathfinding** I'm focusing on enhancing the AI's ability to navigate the maze. It's learning to pathfind towards the food while avoiding self-collision by implementing directional choices based on relative positions. The input queue logic is also being adjusted for smoother responses. **Structuring Game Components** I'm now abstracting the drawing and update functions for better modularity and maintainability. The movement logic is being refined to handle input queuing effectively, and I'm beginning to integrate the AI's pathfinding decisions into the main game loop for smoother demo playback. **Implementing Movement Controls** I'm solidifying the input handling, ensuring successive key presses are queued and that invalid 180-degree turns are prevented. I'm also refining the AI's pathfinding logic to make its movement towards the food more deterministic and less prone to self-collision within the game grid. **Refining AI and Controls** I'm currently working on making the AI more intelligent by improving its pathfinding to consistently reach the food without self-collision. I'm also refining the input handling to ensure a responsive and deterministic movement, especially when dealing with rapid key presses and preventing unwanted reversals. **Enhancing AI and Collision** I'm refining the AI's pathfinding to be more intelligent about avoiding self-collision while moving towards the food. I'm also ensuring new food never spawns on the snake itself, and I'm considering how to scale the canvas effectively using attributes and CSS for responsiveness. **Updating Input Buffering** I'm simplifying the input handling. Instead of a complex queue, I'm using a `nextDirection` variable that stores the latest valid input. This ensures smooth responsiveness and prevents illegal 180-degree turns, effectively handling rapid key presses by processing the most recent direction at each game tick. **Drawing Visuals** I'm refining the visual elements, focusing on drawing the snake's eyes using arcs and implementing a canvas size that fits well within typical viewports. I'm also setting up local storage for high scores and ensuring the self-playing demo mode is the default experience for users. **Simplifying Input Handling** I've moved from a complex input queue to a single `nextDirection` variable. This approach effectively captures the latest valid input for each tick, ensuring responsiveness and preventing illegal 180-degree turns, which simplifies the control logic significantly. **Addressing Input Logic** I'm re-evaluating the input handling to ensure quick successive key presses are both honored, rather than just the last one. This requires a shift back towards a queue-based system to manage these rapid inputs correctly, while still preventing illegal 180-degree turns. **Implementing Particle Effects** I'm now focusing on particle effects for when the snake eats food. This involves implementing a `spawnParticles` function and an `updateParticles` loop that manages particle movement and life cycles. I'm also mapping grid coordinates to pixel coordinates for accurate drawing within the canvas.