gpt-oss-120b
by OpenAIReasoningClean
Running live in a sandboxed frame. Click inside it before using the keyboard.
How it went
- Total time
- 5.9 s
- Cost
- $0.0017
- Output tokens
- 2,662
- Spent thinking
- 434 tokens
- Speed
- 475.8 tok/s
- Console errors
- 0
- First token after
- 312 ms
- First visible text after
- 1.2 s
- Prompt tokens
- 557
- Code size
- 7.1 KB
- Finish reason
- stop
- Served by
- Groq
- Model id
openai/gpt-oss-120b- Reasoning sent
{"effort":"medium"}- Max output
- 64,000 tokens
- Generated
- Nov 11, 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 · 270 lines
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Polished Snake Demo</title>
<style>
html,body{margin:0;height:100%;display:flex;align-items:center;justify-content:center;background:#111;color:#fff;font-family:sans-serif;overflow:hidden;}
#game{position:relative;display:flex;flex-direction:column;align-items:center;}
canvas{background:#222;display:block;border:2px solid #555;}
#info{margin:5px 0;}
#overlay{
position:absolute;top:0;left:0;width:100%;height:100%;
background:rgba(0,0,0,0.7);color:#fff;display:flex;align-items:center;justify-content:center;
font-size:1.5rem;cursor:pointer;text-align:center;padding:20px;box-sizing:border-box;
}
</style>
</head>
<body>
<div id="game">
<div id="info">Score: <span id="score">0</span> | Best: <span id="best">0</span></div>
<canvas id="c"></canvas>
<div id="overlay">Click or press any key to start<br>(Use Arrow keys / WASD to move, P to pause, Space/Enter to restart)</div>
</div>
<script>
(() => {
const canvas = document.getElementById('c');
const ctx = canvas.getContext('2d');
const CELL = 20;
const COLS = 20;
const ROWS = 20;
const WIDTH = COLS * CELL;
const HEIGHT = ROWS * CELL;
canvas.width = WIDTH;
canvas.height = HEIGHT;
const overlay = document.getElementById('overlay');
const scoreEl = document.getElementById('score');
const bestEl = document.getElementById('best');
let bestScore = 0;
let score = 0;
let snake, dir, nextDir, food, particles, tick, lastTime, paused, demoMode;
const DIRS = {
ArrowUp: {x:0, y:-1},
ArrowDown: {x:0, y:1},
ArrowLeft: {x:-1, y:0},
ArrowRight: {x:1, y:0},
w: {x:0, y:-1},
s: {x:0, y:1},
a: {x:-1, y:0},
d: {x:1, y:0}
};
function init() {
snake = [{x:9,y:9},{x:8,y:9},{x:7,y:9}];
dir = {x:1,y:0};
nextDir = dir;
spawnFood();
particles = [];
tick = 0;
lastTime = performance.now();
paused = false;
score = 0;
updateScore();
}
function spawnFood() {
let pos;
do {
pos = {x:Math.floor(Math.random()*COLS), y:Math.floor(Math.random()*ROWS)};
} while (snake.some(s=>s.x===pos.x && s.y===pos.y));
food = pos;
}
function updateScore() {
scoreEl.textContent = score;
if (score > bestScore) bestScore = score;
bestEl.textContent = bestScore;
}
function setDirection(d) {
// prevent reverse
if (d.x===-dir.x && d.y===-dir.y) return;
nextDir = d;
}
function step() {
if (paused) return;
dir = nextDir;
const head = {x: snake[0].x + dir.x, y: snake[0].y + dir.y};
// wall collision
if (head.x<0||head.x>=COLS||head.y<0||head.y>=ROWS) return gameOver();
// self collision
if (snake.some(s=>s.x===head.x && s.y===head.y)) return gameOver();
snake.unshift(head);
// eat
if (head.x===food.x && head.y===food.y) {
score+=10;
updateScore();
spawnFood();
createBurst(head.x,head.y);
} else {
snake.pop();
}
}
function createBurst(cx,cy){
for(let i=0;i<12;i++){
const angle=Math.random()*Math.PI*2;
const speed=Math.random()*0.8+0.2;
particles.push({
x:cx+0.5, y:cy+0.5,
vx:Math.cos(angle)*speed, vy:Math.sin(angle)*speed,
life:0.6
});
}
}
function drawParticles(dt){
particles = particles.filter(p=>{
p.x+=p.vx*dt;
p.y+=p.vy*dt;
p.life-=dt;
if(p.life>0){
ctx.fillStyle=`rgba(255,200,0,${p.life})`;
ctx.beginPath();
ctx.arc(p.x*CELL, p.y*CELL, 3,0,Math.PI*2);
ctx.fill();
return true;
}
return false;
});
}
function draw() {
ctx.clearRect(0,0,WIDTH,HEIGHT);
// grid (optional subtle)
ctx.strokeStyle='#333';
ctx.lineWidth=0.5;
for(let i=0;i<=COLS;i++){
ctx.beginPath();ctx.moveTo(i*CELL,0);ctx.lineTo(i*CELL,HEIGHT);ctx.stroke();
}
for(let i=0;i<=ROWS;i++){
ctx.beginPath();ctx.moveTo(0,i*CELL);ctx.lineTo(WIDTH,i*CELL);ctx.stroke();
}
// food
ctx.fillStyle='red';
ctx.fillRect(food.x*CELL, food.y*CELL, CELL, CELL);
// snake
snake.forEach((seg,i)=>{
ctx.fillStyle = i===0 ? '#0f0' : '#5f5';
ctx.fillRect(seg.x*CELL, seg.y*CELL, CELL, CELL);
// head eyes
if(i===0){
ctx.fillStyle='black';
const eyeSize=2;
const offset=2;
let ex=seg.x*CELL+offset, ey=seg.y*CELL+offset;
if(dir.x===1){ // right
ex=seg.x*CELL+CELL- offset - eyeSize;
ey=seg.y*CELL+offset;
} else if(dir.x===-1){ // left
ey=seg.y*CELL+offset;
} else if(dir.y===1){ // down
ey=seg.y*CELL+CELL- offset - eyeSize;
ex=seg.x*CELL+offset;
} else if(dir.y===-1){ // up
ey=seg.y*CELL+offset;
}
// two eyes
ctx.fillRect(ex,ey,eyeSize,eyeSize);
ctx.fillRect(ex,ey+CELL/2,eyeSize,eyeSize);
}
});
// particles
const now = performance.now();
const dt = (now - lastTime)/1000;
drawParticles(dt);
lastTime = now;
}
function loop(time){
if (!paused) {
const delta = time - lastTime;
if (delta >= 100) { // 100ms per step
step();
lastTime = time;
}
}
draw();
requestAnimationFrame(loop);
}
function gameOver(){
paused = true;
overlay.innerHTML = `Game Over! Score: ${score}<br>Press Space/Enter to restart`;
overlay.style.display = 'flex';
}
// Input handling
window.addEventListener('keydown', e=>{
if (overlay.style.display !== 'none') {
// start demo or player
overlay.style.display = 'none';
if (demoMode) return; // already demo
demoMode = false;
paused = false;
return;
}
const key = e.key;
if (key==='p' || key==='P'){
paused = !paused;
return;
}
if (key===' '||key==='Enter'){
init();
paused = false;
overlay.style.display='none';
return;
}
if (DIRS[key]) {
setDirection(DIRS[key]);
}
});
// Demo AI
function demoAI(){
if (!demoMode) return;
const head = snake[0];
const dx = food.x - head.x;
const dy = food.y - head.y;
let preferred = [];
if (Math.abs(dx)>Math.abs(dy)){
preferred.push(dx>0?DIRS['ArrowRight']:DIRS['ArrowLeft']);
if(dy!==0) preferred.push(dy>0?DIRS['ArrowDown']:DIRS['ArrowUp']);
} else {
if(dy!==0) preferred.push(dy>0?DIRS['ArrowDown']:DIRS['ArrowUp']);
if (dx!==0) preferred.push(dx>0?DIRS['ArrowRight']:DIRS['ArrowLeft']);
}
// fallback random safe direction
for(const d of preferred){
const nx = head.x + d.x;
const ny = head.y + d.y;
if (nx<0||nx>=COLS||ny<0||ny>=ROWS) continue;
if (snake.some(s=>s.x===nx && s.y===ny)) continue;
setDirection(d);
return;
}
// try any safe direction
const dirs = Object.values(DIRS).filter(d=>!snake.some(s=>s.x===head.x+d.x && s.y===head.y+d.y));
if (dirs.length) setDirection(dirs[Math.floor(Math.random()*dirs.length)]);
}
// start everything
init();
demoMode = true;
requestAnimationFrame(loop);
// run AI every step (sync with game step)
setInterval(demoAI, 100);
})();
</script>
</body>
</html>Reasoning trace (434 tokens)
We need to output a single HTML file with canvas snake game meeting requirements. Must be self-contained. Must include message "Click or press a key to start" overlay before start, as keyboard events only after click. The game should start in self-playing demo mode behind that message, so that screenshot shows something. Could automatically start after a short delay or after user click? Requirement: "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." So we need to have a demo AI that controls snake automatically while overlay message displayed. The overlay message visible, but the game runs behind it. After user clicks or presses a key, overlay disappears and user can control. Implement: set up canvas with size based on grid cell size, maybe 20x20 cells each 20px = 400x400 canvas. Center it with CSS flex. Game logic: grid, snake array of positions, direction vector. Input handling: arrow/WASD, ignore reverse. Movement smooth: we can animate between cells using requestAnimationFrame and progress variable. Particle burst: small circles that expand/fade. Score and best score displayed maybe above canvas. Overlay: a semi-transparent div with message and start instructions. Demo AI: simple algorithm that chooses direction towards food while avoiding walls/self. Could be simple: if snake.x < food.x go right, else left; similar for y; but ensure not reverse. Also ensure not colliding with self; simple fallback. Implement main loop: set interval for steps (e.g., 100ms per step) but smooth movement uses interpolation. Simplify: we can move snake by cells each tick, but animate between positions over a duration. Implementation details: Use requestAnimationFrame to draw, track elapsed time. Key handling: add event listeners for keydown. Restart: space or enter. Pause: P. Score displayed. Best score stored in variable (session only) not localStorage. Make sure no external resources. Now produce HTML code. We need to ensure no errors. Let's craft.