GLM 5.3 Flash
by Z.aiReasoningClean
Running live in a sandboxed frame. Click inside it before using the keyboard.
How it went
- Total time
- 56.9 s
- Cost
- $0.0026
- Output tokens
- 4,953
- Spent thinking
- 523 tokens
- Speed
- 87.7 tok/s
- Console errors
- 0
- First token after
- 468 ms
- First visible text after
- 9.9 s
- Prompt tokens
- 492
- Code size
- 12.6 KB
- Finish reason
- stop
- Served by
- BaseTen
- Model id
z-ai/glm-5.3-flash- Reasoning sent
{"effort":"low"}- 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 · 327 lines
<!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>
:root { --bg1:#0e1220; --bg2:#1a2138; }
* { box-sizing: border-box; margin:0; padding:0; }
html,body { height:100%; }
body {
background: radial-gradient(1200px 700px at 50% 20%, var(--bg2), var(--bg1));
color:#e8ecff;
font-family: 'Segoe UI', system-ui, sans-serif;
display:flex; flex-direction:column; align-items:center; justify-content:center;
min-height:100vh; overflow:hidden; padding:12px;
}
h1 { font-size:clamp(20px,4vw,30px); letter-spacing:6px; font-weight:700;
color:#9fe870; text-transform:uppercase; margin-bottom:10px;
text-shadow:0 0 18px rgba(159,232,112,.35); }
.hud { display:flex; gap:28px; margin-bottom:10px; font-size:15px; letter-spacing:1px; }
.hud b { color:#ffd86b; font-variant-numeric: tabular-nums; }
.hud .lbl { color:#8b93b8; font-size:11px; letter-spacing:2px; display:block; margin-bottom:2px; }
.wrap { position:relative; }
canvas {
display:block; border-radius:14px;
background:#12182c;
box-shadow: 0 0 0 3px #2a3357, 0 18px 50px rgba(0,0,0,.55), inset 0 0 60px rgba(0,0,0,.3);
max-width: min(92vw, 480px);
width:480px; height:480px;
}
.overlay {
position:absolute; inset:0; display:flex; flex-direction:column;
align-items:center; justify-content:center; gap:14px;
background:rgba(10,13,25,.72); border-radius:14px; text-align:center;
backdrop-filter: blur(2px); transition:opacity .25s; padding:20px;
}
.overlay.hidden { opacity:0; pointer-events:none; }
.overlay .title { font-size:clamp(22px,5vw,34px); font-weight:800; letter-spacing:3px; }
.overlay .sub { color:#aab2d5; font-size:14px; line-height:1.7; }
.overlay .score-big { font-size:44px; font-weight:800; color:#ffd86b; }
.kbd { display:inline-block; background:#2a3357; border:1px solid #45507f; border-bottom-width:3px;
border-radius:6px; padding:2px 9px; font-size:12px; font-weight:700; margin:0 2px; }
.blink { animation: blink 1.4s ease-in-out infinite; color:#9fe870; font-weight:700; letter-spacing:2px; font-size:14px; }
@keyframes blink { 50% { opacity:.35; } }
.tag { margin-top:10px; font-size:11px; color:#5e678f; letter-spacing:1px; }
</style>
</head>
<body>
<h1>Snake</h1>
<div class="hud">
<div><span class="lbl">SCORE</span><b id="score">0</b></div>
<div><span class="lbl">BEST</span><b id="best">0</b></div>
</div>
<div class="wrap">
<canvas id="c" width="480" height="480"></canvas>
<div class="overlay" id="overlay">
<div class="title" id="oTitle">SNAKE</div>
<div class="score-big" id="oScore" style="display:none">0</div>
<div class="sub" id="oSub">Click or press a key to start<br>
<span class="kbd">↑↓←→</span>/<span class="kbd">WASD</span> move · <span class="kbd">P</span> pause</div>
<div class="blink" id="oBlink">PRESS ANY KEY</div>
<div class="tag" id="oTag">demo mode — the snake is playing itself</div>
</div>
</div>
<script>
(() => {
const N = 22;
const canvas = document.getElementById('c');
const ctx = canvas.getContext('2d');
const overlay = document.getElementById('overlay');
const oTitle = document.getElementById('oTitle'), oScore = document.getElementById('oScore'),
oSub = document.getElementById('oSub'), oBlink = document.getElementById('oBlink'),
oTag = document.getElementById('oTag');
const scoreEl = document.getElementById('score'), bestEl = document.getElementById('best');
const CS = canvas.width / N;
let snake, prevSnake, dir, queue, food, particles, score, best = 0,
mode = 'demo', // demo | play | paused | over
tickInterval, lastTick = 0, lastFrame = 0, foodPulse = 0;
const DIRS = { up:[0,-1], down:[0,1], left:[-1,0], right:[1,0] };
const keyDir = { ArrowUp:'up', ArrowDown:'down', ArrowLeft:'left', ArrowRight:'right',
w:'up', s:'down', a:'left', d:'right', W:'up', S:'down', A:'left', D:'right' };
function freeCell() {
const occ = new Set(snake.map(p => p[0] + ',' + p[1]));
let c;
do { c = [Math.floor(Math.random()*N), Math.floor(Math.random()*N)]; } while (occ.has(c[0]+','+c[1]));
return c;
}
function reset(m) {
mode = m;
const mid = [Math.floor(N/2), Math.floor(N/2)];
snake = [[mid[0], mid[1]], [mid[0]-1, mid[1]], [mid[0]-2, mid[1]]];
prevSnake = snake.map(p => p.slice());
dir = 'right'; queue = [];
food = freeCell();
particles = [];
score = 0; scoreEl.textContent = '0';
tickInterval = 130;
lastTick = performance.now();
}
function setOverlay(show, title, scoreVal, sub, tag) {
overlay.classList.toggle('hidden', !show);
oTitle.textContent = title;
oScore.style.display = scoreVal === null ? 'none' : '';
oScore.textContent = scoreVal || '';
oSub.innerHTML = sub;
oTag.textContent = tag;
oBlink.style.display = show ? '' : 'none';
}
function safe(cell, body, ignoreTail) {
if (cell[0] < 0 || cell[1] < 0 || cell[0] >= N || cell[1] >= N) return false;
const lim = body.length - (ignoreTail ? 1 : 0);
for (let i = 0; i < lim; i++) if (body[i][0] === cell[0] && body[i][1] === cell[1]) return false;
return true;
}
function aiPick() {
const head = snake[0];
const cands = ['up','down','left','right'].sort((a,b) => {
const pa = [head[0]+DIRS[a][0], head[1]+DIRS[a][1]];
const pb = [head[0]+DIRS[b][0], head[1]+DIRS[b][1]];
return (Math.abs(pa[0]-food[0])+Math.abs(pa[1]-food[1])) - (Math.abs(pb[0]-food[0])+Math.abs(pb[1]-food[1]));
});
for (const d of cands) {
const nx = [head[0]+DIRS[d][0], head[1]+DIRS[d][1]];
if (safe(nx, snake, true) && !(d === 'left' && dir === 'right') && !(d === 'right' && dir === 'left')
&& !(d === 'up' && dir === 'down') && !(d === 'down' && dir === 'up')) return d;
}
return dir;
}
function burst(cell) {
const cx = (cell[0]+0.5)*CS, cy = (cell[1]+0.5)*CS;
for (let i = 0; i < 22; i++) {
const a = Math.random()*Math.PI*2, sp = 60 + Math.random()*140;
particles.push({ x:cx, y:cy, vx:Math.cos(a)*sp, vy:Math.sin(a)*sp,
life:1, size:2+Math.random()*3.5, hue: 80 + Math.random()*60 });
}
}
function tick() {
if (mode === 'demo') dir = aiPick();
else if (queue.length) dir = queue.shift();
prevSnake = snake.map(p => p.slice());
const head = [snake[0][0]+DIRS[dir][0], snake[0][1]+DIRS[dir][1]];
const hitWall = head[0]<0 || head[1]<0 || head[0]>=N || head[1]>=N;
const hitSelf = snake.some((p,i) => i < snake.length-1 && p[0]===head[0] && p[1]===head[1]);
if (hitWall || hitSelf) {
if (mode === 'play') {
best = Math.max(best, score); bestEl.textContent = best;
setOverlay(true, 'GAME OVER', score,
'Press <span class="kbd">Space</span> or <span class="kbd">Enter</span> to restart',
'');
mode = 'over';
} else { reset('demo'); }
return;
}
snake.unshift(head);
if (head[0]===food[0] && head[1]===food[1]) {
score += 10; scoreEl.textContent = score;
burst(head);
food = freeCell();
foodPulse = 1;
tickInterval = Math.max(75, 130 - score*0.6);
} else snake.pop();
}
function roundRectPath(x, y, r) {
ctx.beginPath();
ctx.moveTo(x+r, y);
ctx.arcTo(x+CS, y, x+CS, y+CS, r);
ctx.arcTo(x+CS, y+CS, x, y+CS, r);
ctx.arcTo(x, y+CS, x, y, r);
ctx.arcTo(x, y, x+CS, y, r);
ctx.closePath();
}
function lerp(a, b, t) { return a + (b-a)*t; }
function draw(now) {
const t = Math.min(1, (now - lastTick) / tickInterval);
ctx.clearRect(0, 0, canvas.width, canvas.height);
// checkerboard
for (let y = 0; y < N; y++) for (let x = 0; x < N; x++) {
if ((x+y) % 2 === 0) { ctx.fillStyle = 'rgba(255,255,255,0.022)'; ctx.fillRect(x*CS, y*CS, CS, CS); }
}
// grid lines
ctx.strokeStyle = 'rgba(255,255,255,0.03)'; ctx.lineWidth = 1;
for (let i = 1; i < N; i++) {
ctx.beginPath(); ctx.moveTo(i*CS, 0); ctx.lineTo(i*CS, canvas.height); ctx.stroke();
ctx.beginPath(); ctx.moveTo(0, i*CS); ctx.lineTo(canvas.width, i*CS); ctx.stroke();
}
// food
foodPulse = Math.max(0, foodPulse - 0.05);
const pulse = 1 + Math.sin(now/200)*0.08 + foodPulse*0.35;
const fx = (food[0]+0.5)*CS, fy = (food[1]+0.5)*CS;
ctx.beginPath(); ctx.arc(fx, fy, CS*0.30*pulse, 0, Math.PI*2);
ctx.fillStyle = '#ff5470'; ctx.shadowColor = '#ff5470'; ctx.shadowBlur = 14; ctx.fill();
ctx.shadowBlur = 0;
ctx.beginPath(); ctx.arc(fx - CS*0.09, fy - CS*0.09, CS*0.09, 0, Math.PI*2);
ctx.fillStyle = 'rgba(255,255,255,.7)'; ctx.fill();
// snake interpolated points (head -> tail)
const pts = snake.map((p, i) => {
const pv = prevSnake[i] || p;
return [ lerp(pv[0], p[0], t), lerp(pv[1], pv[1], t) ];
});
// body as a stroked path
const lineW = CS*0.78;
ctx.lineCap = 'round'; ctx.lineJoin = 'round';
for (let pass = 0; pass < 2; pass++) {
const grad = ctx.createLinearGradient(0, 0, canvas.width, canvas.height);
if (pass === 0) { grad.addColorStop(0,'#2f7d3f'); grad.addColorStop(1,'#2f7d3f'); ctx.globalAlpha=.5; }
else { grad.addColorStop(0,'#9fe870'); grad.addColorStop(1,'#4fc46a'); ctx.globalAlpha=1; }
ctx.strokeStyle = grad; ctx.lineWidth = pass === 0 ? lineW+5 : lineW;
ctx.beginPath();
ctx.moveTo((pts[0][0]+0.5)*CS, (pts[0][1]+0.5)*CS);
for (let i = 1; i < pts.length; i++) ctx.lineTo((pts[i][0]+0.5)*CS, (pts[i][1]+0.5)*CS);
if (pts.length === 1) ctx.lineTo((pts[0][0]+0.51)*CS, (pts[0][1]+0.5)*CS);
ctx.stroke();
}
ctx.globalAlpha = 1;
// scale highlights on body
ctx.fillStyle = 'rgba(255,255,255,.10)';
for (let i = 2; i < pts.length; i += 2) {
ctx.beginPath();
ctx.arc((pts[i][0]+0.5)*CS, (pts[i][1]+0.5)*CS, CS*0.12, 0, Math.PI*2);
ctx.fill();
}
// head with eyes
const h = pts[0];
const hx = (h[0]+0.5)*CS, hy = (h[1]+0.5)*CS;
const d = DIRS[dir];
ctx.beginPath(); ctx.arc(hx, hy, CS*0.46, 0, Math.PI*2);
ctx.fillStyle = '#b6f58a'; ctx.shadowColor = 'rgba(159,232,112,.6)'; ctx.shadowBlur = 10;
ctx.fill(); ctx.shadowBlur = 0;
const perp = [-d[1], d[0]];
const eo = CS*0.19, fo = CS*0.16;
for (const s of [-1, 1]) {
const ex = hx + d[0]*fo + perp[0]*eo*s;
const ey = hy + d[1]*fo + perp[1]*eo*s;
ctx.beginPath(); ctx.arc(ex, ey, CS*0.115, 0, Math.PI*2); ctx.fillStyle = '#10182b'; ctx.fill();
ctx.beginPath(); ctx.arc(ex + d[0]*CS*0.04, ey + d[1]*CS*0.04, CS*0.05, 0, Math.PI*2);
ctx.fillStyle = '#fff'; ctx.fill();
}
// particles
for (const p of particles) {
ctx.globalAlpha = Math.max(0, p.life);
ctx.fillStyle = `hsl(${p.hue},90%,62%)`;
ctx.beginPath(); ctx.arc(p.x, p.y, p.size*p.life, 0, Math.PI*2); ctx.fill();
}
ctx.globalAlpha = 1;
if (mode === 'paused') {
ctx.fillStyle = 'rgba(10,13,25,.6)';
ctx.fillRect(0, 0, canvas.width, canvas.height);
ctx.fillStyle = '#e8ecff'; ctx.font = '800 34px Segoe UI, sans-serif';
ctx.textAlign = 'center';
ctx.fillText('PAUSED', canvas.width/2, canvas.height/2);
ctx.font = '400 14px Segoe UI, sans-serif'; ctx.fillStyle = '#aab2d5';
ctx.fillText('Press P to resume', canvas.width/2, canvas.height/2 + 28);
}
}
function loop(now) {
const dt = Math.min(100, now - lastFrame); lastFrame = now;
if (mode !== 'paused' && mode !== 'over') {
while (now - lastTick >= tickInterval) { lastTick += tickInterval; tick(); }
} else if (mode === 'over') { lastTick = now - tickInterval; } // freeze
for (const p of particles) { p.x += p.vx*dt/1000; p.y += p.vy*dt/1000; p.vy += 260*dt/1000; p.life -= dt/700; }
particles = particles.filter(p => p.life > 0);
draw(now);
requestAnimationFrame(loop);
}
function startPlay() {
reset('play');
setOverlay(false);
}
window.addEventListener('keydown', e => {
const k = e.key;
if (mode === 'demo' || mode === 'over') {
if (k === ' ' || k === 'Enter' || keyDir[k]) { e.preventDefault(); startPlay(); }
return;
}
if (k === 'p' || k === 'P') {
e.preventDefault();
if (mode === 'play') { mode = 'paused'; }
else if (mode === 'paused') { mode = 'play'; lastTick = performance.now(); }
return;
}
const d = keyDir[k];
if (d) {
e.preventDefault();
const last = queue.length ? queue[queue.length-1] : dir;
if ((d === 'up' && last === 'down') || (d === 'down' && last === 'up') ||
(d === 'left' && last === 'right') || (d === 'right' && last === 'left')) return;
if (queue.length < 3) queue.push(d);
}
});
window.addEventListener('mousedown', () => { if (mode === 'demo' || mode === 'over') startPlay(); });
reset('demo');
setOverlay(true, 'SNAKE', null,
'Click or press a key to start<br><span class="kbd">↑↓←→</span>/<span class="kbd">WASD</span> move · <span class="kbd">P</span> pause',
'demo mode — the snake is playing itself');
bestEl.textContent = best;
requestAnimationFrame(now => { lastFrame = now; lastTick = now; loop(now); });
})();
</script>
</body>
</html>Reasoning trace (523 tokens)
Write a snake game with smooth interpolation, particles, eyes, key buffer. Self-playing demo mode before start? Requirement says games must start in self-playing demo mode behind overlay. Implement AI autoplay behind "Click or press a key to start". Grid 22×22, canvas. Smooth: render interpolated positions between ticks. Keep body positions history. Simple approach: each tick store prev positions; render lerp. Let me code concisely. Key buffer: queue of directions; ignore reverse relative to last queued dir. AI demo: simple pathing — move toward food avoiding collisions; if stuck, pick safe direction. Simple: choose direction reducing distance to food if next cell safe, else any safe. Rendering: rounded snake segments connected — draw as thick line path with round joins, head circle with eyes. Implementation details: - grid N=22, cell size computed from canvas 440 (plus responsive: canvas fixed 440 CSS max-width 100%). - tick rate ~7.5 fps base, speed up slightly with score maybe. - state: snake array of cells (head first), prevSnake for lerp, dir, queued dirs, food, score, best, particles, mode: 'demo'|'play'|'paused'|'over'. - lerp t = timeSinceTick/tickInterval. Draw snake: compute interpolated points for each segment = lerp(prev[i], cur[i]). prev[i] = prevSnake[i] if exists else snake[i]. When growing, prevSnake shorter — for tail extra segment, prev = same cell. Draw path: ctx.beginPath through points, lineWidth = cell*0.8, round cap/join, stroke gradient-ish — just stroke body color, then head circle with eyes facing dir. Particles on eat. Wall/sself collision game over. Overlay: draw on canvas or DOM? DOM overlay div easier for text. Use DOM overlay positioned over canvas. Demo mode AI runs tick loop too but score not counted? Just run it; show overlay "Click or press a key to start". On restart from game over: press space/enter restarts to play mode. Keyboard: click on page or keydown -> if demo/over: start play. In play: arrows/wasd queue dirs; p pause; space/enter restart when over. Canvas focus: keydown on window; sandbox iframe — instructions say click needed; fine. AI: at each tick, candidate dirs sorted by distance to food; pick first whose next cell is not wall/body (excluding tail). If none, any non-reverse. Write code.