Train snakeOne-line
MiniMax M3.1 Flash
by MiniMaxReasoningClean
Running live in a sandboxed frame. Click inside it before using the keyboard.
How it went
- Total time
- 23.1 s
- Cost
- $0.0037
- Output tokens
- 6,173
- Spent thinking
- 362 tokens
- Speed
- 273.9 tok/s
- Console errors
- 0
- First token after
- 522 ms
- First visible text after
- 3.4 s
- Prompt tokens
- 532
- Code size
- 16.9 KB
- Finish reason
- stop
- Served by
- DigitalOcean
- Model id
minimax/minimax-m3.1-flash- Reasoning sent
{"effort":"low"}- Max output
- 64,000 tokens
- Generated
- Nov 11, 2026
What it was asked
The prompt
“make me a snake game where the snake is a little train with a locomotive and colorful wagons, picking up passengers waiting on the platform”
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 · 432 lines
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Platform Express — Train Snake</title>
<style>
* { box-sizing: border-box; }
html, body {
margin: 0; min-height: 100%; background: #101827; color: #f8fafc;
font-family: ui-rounded, "Trebuchet MS", system-ui, sans-serif;
overflow-x: hidden;
}
body {
display: flex; flex-direction: column; align-items: center;
background: radial-gradient(circle at 50% -20%, #2d4664 0, #101827 65%);
padding: 18px 12px 24px;
}
header {
width: min(880px, 100%); display: flex; align-items: center;
justify-content: space-between; gap: 14px; margin-bottom: 12px; flex-wrap: wrap;
}
.brand { display: flex; align-items: center; gap: 12px; }
.logo {
width: 48px; height: 48px; display: grid; place-items: center; font-size: 29px;
background: linear-gradient(145deg, #fbbf24, #f97316); border-radius: 14px;
box-shadow: 0 8px 22px #f9731640; border: 2px solid #fde68a;
}
h1 { margin: 0; font-size: clamp(21px, 4vw, 30px); letter-spacing: .3px; }
.subtitle { color: #a9bbd3; font-size: 13px; margin-top: 2px; }
.stats { display: flex; gap: 8px; }
.stat {
min-width: 92px; padding: 8px 13px; border-radius: 12px;
background: #1b2a40; border: 1px solid #33465f; box-shadow: inset 0 1px #ffffff12;
}
.stat small { display: block; color: #9fb2ca; font-size: 10px; letter-spacing: 1.2px; text-transform: uppercase; }
.stat strong { font-size: 20px; color: #fde68a; }
.stage {
position: relative; width: min(880px, 100%); border-radius: 20px; overflow: hidden;
border: 3px solid #3b526d; box-shadow: 0 22px 55px #0008, 0 0 0 6px #0b1422;
background: #142135;
}
canvas { display: block; width: 100%; height: auto; aspect-ratio: 864/576; }
.overlay {
position: absolute; inset: 0; display: grid; place-items: center;
background: #07111bd9; backdrop-filter: blur(3px); transition: opacity .25s;
}
.overlay.hidden { opacity: 0; pointer-events: none; }
.card {
text-align: center; padding: 28px 34px; max-width: 430px; margin: 16px;
background: linear-gradient(145deg, #20344eea, #142035ee);
border: 1px solid #4b6686; border-radius: 22px; box-shadow: 0 18px 45px #0007;
}
.card .train-icon { font-size: 46px; margin-bottom: 6px; }
.card h2 { margin: 0 0 8px; font-size: 26px; }
.card p { margin: 6px 0; color: #c4d2e4; line-height: 1.45; }
.key {
display: inline-block; padding: 2px 7px; border-radius: 6px; background: #0b1625;
border: 1px solid #526985; box-shadow: 0 2px 0 #02070d; color: white; font-size: 12px;
}
.start-btn {
margin-top: 16px; border: 0; border-radius: 999px; padding: 12px 25px;
background: linear-gradient(#fcd34d, #f59e0b); color: #392005; font-weight: 900;
font-size: 15px; cursor: pointer; box-shadow: 0 5px 0 #b45309;
}
.start-btn:active { transform: translateY(3px); box-shadow: 0 2px 0 #b45309; }
footer {
width: min(880px, 100%); margin-top: 12px; color: #91a5bd; font-size: 12px;
display: flex; justify-content: space-between; gap: 12px; flex-wrap: wrap;
}
.legend { display: flex; gap: 15px; align-items: center; flex-wrap: wrap; }
.dot { display: inline-block; width: 10px; height: 10px; border-radius: 50%; margin-right: 5px; }
@media (max-width: 560px) {
body { padding: 8px 8px 16px; }
header { margin-bottom: 8px; }
.subtitle { display: none; }
.stat { min-width: 66px; padding: 6px 9px; }
.stat strong { font-size: 16px; }
.stage { border-radius: 13px; }
.card { padding: 18px; }
.card h2 { font-size: 21px; }
.card .train-icon { font-size: 34px; }
}
</style>
</head>
<body>
<header>
<div class="brand">
<div class="logo">🚂</div>
<div>
<h1>Platform Express</h1>
<div class="subtitle">Collect every passenger before the next stop!</div>
</div>
</div>
<div class="stats">
<div class="stat"><small>Passengers</small><strong id="score">0</strong></div>
<div class="stat"><small>Best</small><strong id="best">0</strong></div>
<div class="stat"><small>Speed</small><strong id="speed">1×</strong></div>
</div>
</header>
<div class="stage">
<canvas id="game" width="864" height="576" aria-label="Platform Express train snake game"></canvas>
<div class="overlay" id="overlay">
<div class="card">
<div class="train-icon">🚂</div>
<h2 id="overlayTitle">All aboard!</h2>
<p id="overlayText">Drive your colorful train along the rails and collect passengers waiting on the platform.</p>
<p><span class="key">← ↑ ↓ →</span> or <span class="key">WASD</span> to steer</p>
<p style="font-size:12px;color:#8fa6c0">The station conductor will demo the route automatically.</p>
<button class="start-btn" id="startBtn">Click or press a key to start</button>
</div>
</div>
</div>
<footer>
<div class="legend">
<span><i class="dot" style="background:#fbbf24"></i>Locomotive</span>
<span><i class="dot" style="background:#f472b6"></i>Passenger cars</span>
<span><i class="dot" style="background:#38bdf8"></i>Waiting passengers</span>
</div>
<div>Tip: collect a passenger to add a colorful wagon.</div>
</footer>
<script>
(() => {
const canvas = document.getElementById('game');
const ctx = canvas.getContext('2d');
const overlay = document.getElementById('overlay');
const overlayTitle = document.getElementById('overlayTitle');
const overlayText = document.getElementById('overlayText');
const startBtn = document.getElementById('startBtn');
const scoreEl = document.getElementById('score');
const bestEl = document.getElementById('best');
const speedEl = document.getElementById('speed');
const COLS = 24, ROWS = 16, CELL = 36;
const DIRS = {
up: {x:0,y:-1}, down:{x:0,y:1}, left:{x:-1,y:0}, right:{x:1,y:0}
};
const colors = ['#ef476f','#06d6a0','#118ab2','#8b5cf6','#ff9f1c','#22c55e'];
let train, passengers, direction, nextDirection, running, demo, score, best = 0;
let stepTimer = 0, lastTime = 0, particles = [], flash = 0, level = 1;
const keyMap = {
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 reset() {
train = [{x:12,y:8},{x:11,y:8},{x:10,y:8},{x:9,y:8}];
direction = DIRS.right;
nextDirection = DIRS.right;
passengers = [];
score = 0; level = 1; stepTimer = 0; particles = []; flash = 0;
spawnPassenger();
spawnPassenger();
updateHUD();
}
function spawnPassenger() {
let spots = [];
for (let x=1;x<COLS-1;x++) {
spots.push({x,y:0}, {x,y:ROWS-1});
}
for (let y=2;y<ROWS-2;y++) {
spots.push({x:0,y}, {x:COLS-1,y});
}
spots = spots.filter(p => !train.some(s => s.x===p.x && s.y===p.y) &&
!passengers.some(p2 => p2.x===p.x && p2.y===p.y));
if (!spots.length) return;
const p = spots[Math.floor(Math.random()*spots.length)];
passengers.push({x:p.x,y:p.y,color:colors[Math.floor(Math.random()*colors.length)], phase:Math.random()*6});
}
function start() {
reset();
running = true; demo = true;
overlay.classList.add('hidden');
lastTime = performance.now();
requestAnimationFrame(loop);
}
function gameOver() {
running = false; demo = false;
if (score > best) best = score;
updateHUD();
overlayTitle.textContent = 'End of the line!';
overlayText.textContent = `You collected ${score} passenger${score===1?'':'s'}. The station is cheering for your railway!`;
startBtn.textContent = 'Run the train again';
overlay.classList.remove('hidden');
}
function isBlocked(p) {
if (p.x<0 || p.x>=COLS || p.y<0 || p.y>=ROWS) return true;
return train.slice(0,-1).some(s => s.x===p.x && s.y===p.y);
}
function chooseDemoDirection() {
const options = Object.values(DIRS).filter(d => {
const h = train[0];
return !isBlocked({x:h.x+d.x,y:h.y+d.y});
});
if (!options.length) return direction;
// BFS toward the nearest passenger, avoiding the train.
const h = train[0], targetSet = new Set(passengers.map(p=>p.x+','+p.y));
const queue = [{x:h.x,y:h.y,d:null,first:null}], seen = new Set([h.x+','+h.y]);
let found = null;
while(queue.length) {
const n = queue.shift();
for (const d of Object.values(DIRS)) {
const nx=n.x+d.x, ny=n.y+d.y, k=nx+','+ny;
if (nx<0||nx>=COLS||ny<0||ny>=ROWS||seen.has(k)) continue;
if (train.some((s,i)=>i<train.length-1&&s.x===nx&&s.y===ny)) continue;
seen.add(k);
const first = n.first || d;
if (targetSet.has(k)) { found=first; queue.length=0; break; }
queue.push({x:nx,y:ny,first});
}
}
if (found && !(found.x===-direction.x && found.y===-direction.y)) return found;
if (options.includes(direction)) return direction;
return options[Math.floor(Math.random()*options.length)];
}
function update() {
if (demo) direction = chooseDemoDirection();
else direction = nextDirection;
const h = train[0];
const nh = {x:h.x+direction.x, y:h.y+direction.y};
if (isBlocked(nh)) { gameOver(); return; }
train.unshift(nh);
const caught = passengers.findIndex(p=>p.x===nh.x&&p.y===nh.y);
if (caught>=0) {
const p = passengers.splice(caught,1)[0];
score++; level = 1 + Math.floor(score/4);
flash = .3;
for(let i=0;i<14;i++) particles.push({
x:nh.x*CELL+CELL/2, y:nh.y*CELL+CELL/2,
vx:(Math.random()-.5)*150, vy:(Math.random()-.5)*150,
color:p.color, life:1
});
spawnPassenger();
if (passengers.length<2 && score%2===0) spawnPassenger();
updateHUD();
}
train.pop();
particles.forEach(p=>{p.x+=p.vx/60;p.y+=p.vy/60;p.vy+=90/60;p.life-=.025;});
particles = particles.filter(p=>p.life>0);
}
function updateHUD() {
scoreEl.textContent = score;
bestEl.textContent = Math.max(best,score);
speedEl.textContent = level + '×';
}
function roundedRect(x,y,w,h,r) {
r=Math.min(r,w/2,h/2); ctx.beginPath();
ctx.moveTo(x+r,y); ctx.arcTo(x+w,y,x+w,y+h,r); ctx.arcTo(x+w,y+h,x,y+h,r);
ctx.arcTo(x,y+h,x,y,r); ctx.arcTo(x,y,x+w,y,r); ctx.closePath();
}
function drawBackground(t) {
const g = ctx.createLinearGradient(0,0,0,canvas.height);
g.addColorStop(0,'#15263a'); g.addColorStop(1,'#0d1929');
ctx.fillStyle=g; ctx.fillRect(0,0,canvas.width,canvas.height);
// Ballast and sleepers.
ctx.fillStyle='#1d2c3d';
for(let y=0;y<ROWS;y++) for(let x=0;x<COLS;x++) {
if ((x+y)%2===0) ctx.fillRect(x*CELL,y*CELL,CELL,CELL);
}
ctx.strokeStyle='#314354'; ctx.lineWidth=3;
for(let x=0;x<COLS;x++) {
ctx.beginPath(); ctx.moveTo(x*CELL+7,0); ctx.lineTo(x*CELL+7,canvas.height); ctx.stroke();
}
ctx.strokeStyle='#61707d'; ctx.lineWidth=2;
for(const y of [17,53]) {
ctx.beginPath(); ctx.moveTo(0,y); ctx.lineTo(canvas.width,y); ctx.stroke();
}
// Platform edges.
const platH=34;
ctx.fillStyle='#526478'; ctx.fillRect(0,0,canvas.width,platH); ctx.fillRect(0,canvas.height-platH,canvas.width,platH);
ctx.fillStyle='#f5c451'; ctx.fillRect(0,platH-6,canvas.width,6); ctx.fillRect(0,canvas.height-platH,canvas.width,6);
ctx.fillStyle='#d9e1e8';
for(let x=8;x<canvas.width;x+=28) {
ctx.fillRect(x,9,15,4); ctx.fillRect(x,canvas.height-13,15,4);
}
ctx.fillStyle='#3f5266'; ctx.fillRect(0,0,10,canvas.height); ctx.fillRect(canvas.width-10,0,10,canvas.height);
ctx.fillStyle='#f5c451'; ctx.fillRect(8,0,4,canvas.height); ctx.fillRect(canvas.width-12,0,4,canvas.height);
// Station signs.
ctx.font='bold 10px Trebuchet MS'; ctx.textAlign='center';
for(let x=90;x<canvas.width;x+=170) {
ctx.fillStyle='#273a4e'; roundedRect(x-36,6,72,20,5); ctx.fill();
ctx.fillStyle='#d9e8f5'; ctx.fillText('PLATFORM '+(1+Math.floor(x/170)),x,20);
ctx.fillStyle='#273a4e'; roundedRect(x-36,canvas.height-26,72,20,5); ctx.fill();
ctx.fillStyle='#d9e8f5'; ctx.fillText('STATION',x,canvas.height-12);
}
}
function drawPassenger(p,t) {
const cx=p.x*CELL+CELL/2, cy=p.y*CELL+CELL/2;
const py = p.y===0 ? cy+1 : cy-1;
ctx.save();
ctx.fillStyle='#0005'; ctx.beginPath(); ctx.ellipse(cx,py+10,10,4,0,0,Math.PI*2); ctx.fill();
// body
ctx.fillStyle=p.color; roundedRect(cx-9,py-1,18,13,5); ctx.fill();
// head
ctx.fillStyle='#ffd7b0'; ctx.beginPath(); ctx.arc(cx,py-8,8,0,Math.PI*2); ctx.fill();
// hair
ctx.fillStyle='#392b2a'; ctx.beginPath(); ctx.arc(cx,py-10,8,Math.PI,Math.PI*2); ctx.fill();
// eyes
ctx.fillStyle='#182230'; ctx.beginPath(); ctx.arc(cx-3,py-7,1.2,0,7); ctx.arc(cx+3,py-7,1.2,0,7); ctx.fill();
// waving arm
ctx.strokeStyle=p.color; ctx.lineWidth=4; ctx.lineCap='round';
ctx.beginPath(); ctx.moveTo(cx+7,py+3); ctx.lineTo(cx+12,py-3+Math.sin(t/180+p.phase)*2); ctx.stroke();
// sign
ctx.fillStyle='#f8fafc'; roundedRect(cx-12,py-16,24,9,3); ctx.fill();
ctx.fillStyle='#2563eb'; ctx.font='bold 7px Trebuchet MS'; ctx.textAlign='center';
ctx.fillText('WAIT',cx,py-9);
ctx.restore();
}
function drawWagon(x,y,index,t) {
const pad=2, w=CELL-pad*2, h=CELL-pad*2;
const color=colors[index%colors.length];
ctx.save();
ctx.translate(x*CELL+pad, y*CELL+pad);
ctx.fillStyle='#0006'; roundedRect(2,4,w,h-2,7); ctx.fill();
ctx.fillStyle=color; roundedRect(0,0,w,h-3,7); ctx.fill();
ctx.fillStyle='#ffffff22'; roundedRect(3,3,w-6,8,4); ctx.fill();
// windows
for(let i=0;i<3;i++) {
ctx.fillStyle='#bdeaff'; roundedRect(6+i*8,10,6,8,2); ctx.fill();
}
// little passenger faces
ctx.fillStyle='#ffd7b0';
for(let i=0;i<3;i++) { ctx.beginPath(); ctx.arc(9+i*8,14,3.2,0,7); ctx.fill(); }
ctx.fillStyle='#26364a';
for(let i=0;i<3;i++) { ctx.beginPath(); ctx.arc(8+i*8,13,1,0,7); ctx.arc(10+i*8,13,1,0,7); ctx.fill(); }
// coupling and wheels
ctx.fillStyle='#d9e2ec'; ctx.fillRect(-2,12,4,4);
ctx.fillStyle='#111827';
for(const wx of [7,w-7]) { ctx.beginPath(); ctx.arc(wx,h-1,5,0,7); ctx.fill(); ctx.fillStyle='#94a3b8'; ctx.beginPath(); ctx.arc(wx,h-1,2,0,7); ctx.fill(); ctx.fillStyle='#111827'; }
ctx.restore();
}
function drawLocomotive(x,y,t) {
const pad=2, w=CELL-pad*2, h=CELL-pad*2;
ctx.save();
ctx.translate(x*CELL+pad,y*CELL+pad);
ctx.fillStyle='#0007'; roundedRect(3,4,w,h-2,7); ctx.fill();
// boiler
ctx.fillStyle='#f59e0b'; roundedRect(0,8,w,19,7); ctx.fill();
ctx.fillStyle='#fbbf24'; roundedRect(2,8,w-4,7,4); ctx.fill();
// cab
ctx.fillStyle='#dc2626'; roundedRect(0,1,12,25,5); ctx.fill();
ctx.fillStyle='#bdeaff'; roundedRect(3,5,7,9,2); ctx.fill();
ctx.fillStyle='#334155'; ctx.beginPath(); ctx.arc(6.5,9.5,1.5,0,7); ctx.fill();
// chimney and steam
ctx.fillStyle='#374151'; roundedRect(w-12,1,6,11,2); ctx.fill();
ctx.fillStyle='#e2e8f0'; roundedRect(w-13,-1,8,4,2); ctx.fill();
const puff = (t/60)%1;
ctx.fillStyle=`rgba(226,232,240,${.7-puff*.6})`;
ctx.beginPath(); ctx.arc(w-8,-3-puff*9,3+puff*4,0,7); ctx.fill();
// headlight
ctx.fillStyle='#fff7b2'; ctx.beginPath(); ctx.arc(w-2,15,4,0,7); ctx.fill();
ctx.strokeStyle='#fef08a'; ctx.beginPath(); ctx.moveTo(w+1,15); ctx.lineTo(w+8+Math.sin(t/100)*2,10); ctx.lineTo(w+8,20); ctx.stroke();
// wheels
ctx.fillStyle='#111827';
for(const wx of [8,w-8]) { ctx.beginPath(); ctx.arc(wx,h-1,6,0,7); ctx.fill(); ctx.fillStyle='#94a3b8'; ctx.beginPath(); ctx.arc(wx,h-1,2.6,0,7); ctx.fill(); ctx.fillStyle='#111827'; }
ctx.restore();
}
function drawTrain(t) {
for(let i=train.length-1;i>=1;i--) drawWagon(train[i].x,train[i].y,i-1,t);
drawLocomotive(train[0].x,train[0].y,t);
}
function draw(t) {
drawBackground(t);
passengers.forEach(p=>drawPassenger(p,t));
drawTrain(t);
particles.forEach(p=>{
ctx.globalAlpha=p.life; ctx.fillStyle=p.color;
ctx.fillRect(p.x-2,p.y-2,4,4);
});
ctx.globalAlpha=1;
if(flash>0) {
ctx.fillStyle=`rgba(253,224,71,${flash*.35})`; ctx.fillRect(0,0,canvas.width,canvas.height);
flash-=.02;
}
}
function loop(now) {
if(!running) return;
const dt=now-lastTime; lastTime=now;
const interval=Math.max(75,145-(level-1)*12);
stepTimer+=dt;
if(stepTimer>=interval) { stepTimer=0; update(); }
if(running) draw(now);
if(running) requestAnimationFrame(loop);
}
window.addEventListener('keydown',e=>{
const d=keyMap[e.key];
if(d) {
e.preventDefault();
if(!running) { start(); return; }
const nd=DIRS[d];
if(nd.x!==-direction.x || nd.y!==-direction.y) nextDirection=nd;
demo=false;
} else if(e.key===' ' && !running) {
e.preventDefault(); start();
}
});
startBtn.addEventListener('click',start);
canvas.addEventListener('click',()=>{ if(!running) start(); });
reset();
let idleT=0;
function idleLoop(t){ if(!running){ idleT=t; draw(t); requestAnimationFrame(idleLoop);} }
requestAnimationFrame(idleLoop);
})();
</script>
</body>
</html>Reasoning trace (362 tokens)
We need create HTML snake train game, visible, self-playing demo behind click/press key message. Need single code block. Let's design polished canvas game. Train snake moving in grid, locomotive head + colorful wagons, passengers on platform waiting; train collects by passing over passenger. Self-play AI. Controls arrow/WASD; click to start. Score, passengers, level. Canvas 900x600 maybe responsive. Include instructions overlay. Implementation: grid 24x16 cell 32? canvas logical 768x512. Use canvas responsive CSS. Station platforms along edges with waiting passengers; pickups at any cell on platform edge. Train grows wagons. Speed increases slightly. AI demo: simple pathfinding-ish random safe moves; snake train body grid. To avoid complexity: direction changes at random when safe, prefer toward nearest passenger with basic BFS on occupied grid. Implement BFS from head to any passenger avoiding train occupancy, choose first step. Occasionally random. Fine. Rendering: background dark, tracks grid rails, platforms edges (top and bottom rows? platforms along left/right columns better). Let's do canvas 900x600, grid 25x17 of 36px? 25*36=900, 17*36=612. Use 24x16 cell 36 = 864x576. Canvas logical 864x576. Train occupies cells list head first. Locomotive drawn oriented with wheels, chimney, light. Wagons colorful with windows passengers inside. Passengers waiting on platforms (top and bottom rows, maybe columns edges). Pick up by head on passenger cell. Scoring, passenger counter. When pick up, spawn new passenger elsewhere. Game over on collision; demo AI hopefully plays well. Overlay with start message on top. Need exactly one code block.