Train snakeOne-line
GPT-6.1 Terra
by OpenAIReasoningClean
Running live in a sandboxed frame. Click inside it before using the keyboard.
How it went
- Total time
- 1 min 31 s
- Cost
- $0.041
- Output tokens
- 8,178
- Spent thinking
- 1,088 tokens
- Speed
- 95.3 tok/s
- Console errors
- 0
- First token after
- 5.5 s
- First visible text after
- 28.6 s
- Prompt tokens
- 361
- Code size
- 20.3 KB
- Finish reason
- stop
- Served by
- OpenAI
- Model id
openai/gpt-6.1-terra- Reasoning sent
{"effort":"medium"}- Max output
- 128,000 tokens
- Generated
- Nov 12, 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 · 385 lines
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Little Train, Big Adventure</title>
<style>
:root {
--ink: #253d32;
--muted: #788579;
--green: #315d48;
--cream: #f8f7ee;
--line: #e4e9db;
--yellow: #f4c95d;
}
* { box-sizing: border-box; }
body {
margin: 0;
background: #f5f5eb;
color: var(--ink);
font-family: "Trebuchet MS", "Segoe UI", sans-serif;
}
button { font: inherit; }
.shell { max-width: 1216px; margin: auto; padding: 0 24px 20px; }
header {
height: 69px;
display: flex;
align-items: center;
justify-content: space-between;
border-bottom: 1px solid #e2e7d9;
}
.brand { display: flex; align-items: center; gap: 10px; font-weight: 900; letter-spacing: -.5px; font-size: 17px; }
.brand-icon {
width: 34px; height: 34px; border-radius: 11px;
display: grid; place-items: center; background: #dcebd5; font-size: 20px;
}
.header-right { display: flex; align-items: center; gap: 18px; }
.edition { color: #879487; font-size: 11px; font-weight: bold; letter-spacing: 1.5px; }
.pill {
border: 1px solid #dbe5d5; background: #fffef8; color: #52705a;
border-radius: 20px; padding: 7px 12px; font-size: 11px; font-weight: bold;
}
.intro { display: flex; align-items: end; justify-content: space-between; padding: 20px 0 17px; gap: 15px; }
.eyebrow { color: #da8d57; font-size: 10px; letter-spacing: 2px; font-weight: 900; text-transform: uppercase; margin-bottom: 5px; }
h1 { font-size: clamp(27px, 3vw, 37px); line-height: 1; margin: 0; letter-spacing: -1.6px; }
.intro p { margin: 7px 0 0; font-size: 13px; color: #839083; }
.intro-note { color: #8c998a; font-size: 12px; padding-bottom: 3px; white-space: nowrap; }
.layout { display: grid; grid-template-columns: minmax(0, 1fr) 260px; gap: 17px; align-items: start; }
.game-card, .side-card { border: 1px solid #e3e8da; background: #fffef9; border-radius: 18px; box-shadow: 0 5px 20px rgba(59, 83, 54, .045); }
.game-card { padding: 12px; }
.game-top { height: 42px; display: flex; justify-content: space-between; align-items: center; padding: 0 5px 10px; }
.route { display: flex; align-items: center; gap: 9px; font-size: 12px; font-weight: 900; }
.route-icon { background: #e7f1df; color: #65916a; border-radius: 8px; width: 27px; height: 27px; display: grid; place-items: center; font-size: 15px; }
.route small { color: #9aa69a; font-size: 10px; font-weight: normal; margin-left: 4px; }
.live { display: flex; align-items: center; gap: 6px; color: #819485; font-size: 10px; font-weight: 900; letter-spacing: 1px; }
.live i { width: 7px; height: 7px; border-radius: 50%; background: #8aba83; box-shadow: 0 0 0 3px #e9f3e4; }
.board-wrap { position: relative; overflow: hidden; border-radius: 11px; background: #b9d7a5; line-height: 0; cursor: pointer; }
canvas { display: block; width: 100%; height: auto; aspect-ratio: 26 / 16; }
.message {
position: absolute; top: 13px; left: 50%; transform: translateX(-50%);
display: flex; align-items: center; gap: 9px; white-space: nowrap;
padding: 9px 15px; border: 1px solid rgba(255,255,255,.8); border-radius: 24px;
background: rgba(255, 254, 246, .94); color: #41634d;
box-shadow: 0 4px 15px rgba(49, 85, 48, .12);
font-size: 11px; font-weight: bold; line-height: 1;
pointer-events: none;
}
.message .sparkle { color: #e4a948; font-size: 14px; }
.message.hidden { display: none; }
.game-bottom { min-height: 43px; display: flex; align-items: center; justify-content: space-between; padding: 10px 4px 0; gap: 8px; }
.hint { color: #89978a; font-size: 11px; }
.hint strong { color: #5b7360; }
.key { display: inline-block; border: 1px solid #dee5d9; border-bottom-width: 2px; background: #f8faf4; border-radius: 4px; padding: 2px 5px; color: #69806d; font-weight: bold; font-size: 10px; }
.restart { background: none; border: 0; color: #6a806d; font-size: 11px; font-weight: bold; cursor: pointer; padding: 6px; }
.restart:hover { color: #2e6044; }
.side { display: grid; gap: 12px; }
.side-card { padding: 17px; }
.card-label { font-size: 10px; font-weight: 900; color: #9ba99a; letter-spacing: 1.5px; text-transform: uppercase; }
.score-line { display: flex; justify-content: space-between; align-items: end; margin-top: 7px; }
.score { font-size: 42px; line-height: 1; font-weight: 900; letter-spacing: -2px; }
.score-caption { color: #91a091; font-size: 11px; margin-top: 5px; }
.ticket { width: 44px; height: 44px; display: grid; place-items: center; background: #fff3d4; border-radius: 13px; font-size: 22px; }
.divider { height: 1px; background: #eef1e9; margin: 15px 0 13px; }
.journey-row { display: flex; align-items: center; justify-content: space-between; font-size: 11px; }
.journey-row span { color: #9aa89a; }
.journey-row strong { color: #648a68; }
.wagon-row { display: flex; align-items: center; gap: 4px; padding-top: 12px; }
.mini-engine { width: 24px; height: 17px; border-radius: 5px 4px 4px 4px; background: #426f58; position: relative; }
.mini-engine:after { content:""; position:absolute; right:4px; top:4px; width:6px; height:5px; background:#cce7ca; border-radius:1px; }
.mini-wagon { width: 20px; height: 14px; border-radius: 4px; position: relative; }
.mini-wagon:after { content:""; position:absolute; left:5px; top:4px; width:10px; height:4px; border-radius:2px; background:rgba(255,255,255,.65); }
.wagon-dots { color: #b9c8b5; font-size: 14px; letter-spacing: 1px; margin-left: 2px; }
.how-title { font-size: 14px; font-weight: 900; margin: 8px 0 13px; }
.step { display: flex; align-items: flex-start; gap: 10px; margin: 12px 0; }
.step-icon { flex: 0 0 31px; width: 31px; height: 31px; display: grid; place-items: center; border-radius: 9px; background: #eef4e9; font-size: 15px; }
.step:nth-of-type(3) .step-icon { background: #fff3db; }
.step:nth-of-type(4) .step-icon { background: #fce9e2; }
.step b { display: block; font-size: 11px; margin: 1px 0 3px; }
.step p { color: #98a598; font-size: 10px; line-height: 1.4; margin: 0; }
.tip { background: #f2f7ec; border-radius: 10px; padding: 10px 11px; color: #79927a; font-size: 10px; line-height: 1.5; margin-top: 14px; }
.tip b { color: #608265; }
.controls { display: none; justify-content: center; gap: 5px; padding: 10px 0 2px; }
.controls button { border: 1px solid #d8e4d3; background: #f4f8ef; color: #4d7357; border-radius: 8px; width: 42px; height: 36px; font-weight: 900; cursor: pointer; }
.controls button:active { background: #d7ead0; }
footer { display: flex; justify-content: space-between; padding: 15px 3px 0; color: #a3afa2; font-size: 10px; }
@media(max-width: 800px) {
.layout { grid-template-columns: 1fr; }
.side { grid-template-columns: 1fr 1fr; }
.controls { display: flex; }
.intro-note { display: none; }
}
@media(max-width: 520px) {
.shell { padding: 0 12px 20px; }
header { height: 57px; }
.edition { display: none; }
.intro { padding: 18px 2px 15px; }
.intro p { font-size: 12px; }
.game-card { padding: 8px; border-radius: 14px; }
.route small { display: none; }
.message { top: 8px; font-size: 10px; padding: 7px 10px; }
.game-bottom .hint { font-size: 10px; }
.side { grid-template-columns: 1fr; }
.side-card { padding: 15px; }
.how-card { display: none; }
footer { padding-top: 12px; }
}
</style>
</head>
<body>
<div class="shell">
<header>
<div class="brand"><span class="brand-icon">🚂</span> little train club</div>
<div class="header-right"><span class="edition">A LITTLE GAME FOR A LITTLE BREAK</span><span class="pill">✿ All aboard!</span></div>
</header>
<section class="intro">
<div><div class="eyebrow">The countryside express</div><h1>Little train, big adventure.</h1><p>Pick up passengers, grow your train, and enjoy the ride.</p></div>
<div class="intro-note">A charming little snake game ✳</div>
</section>
<main class="layout">
<section class="game-card">
<div class="game-top">
<div class="route"><span class="route-icon">⌁</span> THE MEADOW LINE <small>• scenic route</small></div>
<div class="live"><i></i><span id="mode">DEMO RIDE</span></div>
</div>
<div class="board-wrap" id="boardWrap">
<canvas id="game" width="832" height="512" aria-label="Train snake game in a meadow"></canvas>
<div class="message" id="message"><span class="sparkle">✦</span><span id="messageText">Click or press a key to start</span></div>
</div>
<div class="game-bottom">
<div class="hint">Steer with <span class="key">↑</span> <span class="key">←</span> <span class="key">↓</span> <span class="key">→</span> or <strong>W A S D</strong></div>
<button class="restart" id="restart">↻ Start over</button>
</div>
<div class="controls" aria-label="Touch steering controls">
<button data-dir="left" aria-label="Left">←</button><button data-dir="up" aria-label="Up">↑</button><button data-dir="down" aria-label="Down">↓</button><button data-dir="right" aria-label="Right">→</button>
</div>
</section>
<aside class="side">
<section class="side-card">
<div class="card-label">Your journey</div>
<div class="score-line"><div><div class="score" id="score">0</div><div class="score-caption">passengers picked up</div></div><div class="ticket">🎟️</div></div>
<div class="divider"></div>
<div class="journey-row"><span>Train status</span><strong id="status">Enjoying the view</strong></div>
<div class="wagon-row" id="wagonRow"></div>
</section>
<section class="side-card how-card">
<div class="card-label">The conductor's guide</div>
<div class="how-title">A lovely little ride</div>
<div class="step"><div class="step-icon">⌨</div><div><b>Take the controls</b><p>Use your arrow keys or WASD to steer the train.</p></div></div>
<div class="step"><div class="step-icon">🧍</div><div><b>Pick up passengers</b><p>Visit the platforms to add colorful wagons.</p></div></div>
<div class="step"><div class="step-icon">🚂</div><div><b>Mind your train</b><p>Don't run into the edge or your own wagons!</p></div></div>
<div class="tip"><b>Conductor's tip ✦</b><br>There's no rush. Every passenger makes the journey a little brighter.</div>
</section>
</aside>
</main>
<footer><span>MADE FOR THE JOY OF THE JOURNEY</span><span>✿ Enjoy the ride</span></footer>
</div>
<script>
(() => {
const canvas = document.getElementById('game');
const ctx = canvas.getContext('2d');
const board = document.getElementById('boardWrap');
const message = document.getElementById('message');
const messageText = document.getElementById('messageText');
const modeEl = document.getElementById('mode');
const scoreEl = document.getElementById('score');
const statusEl = document.getElementById('status');
const wagonRow = document.getElementById('wagonRow');
const W = 26, H = 16, S = 32;
const colors = ['#e9a05e','#e77f79','#eac458','#779fc2','#aa8fb6','#83ad89','#da9171'];
const directions = {up:{x:0,y:-1},down:{x:0,y:1},left:{x:-1,y:0},right:{x:1,y:0}};
let snake, dir, queued, passengers, score, state, lastMove, tick, gameOver;
let seed = 7219;
function random() { seed = (seed * 16807) % 2147483647; return (seed - 1) / 2147483646; }
function rounded(x,y,w,h,r,fill,stroke) {
ctx.beginPath(); ctx.roundRect(x,y,w,h,r);
if (fill) { ctx.fillStyle=fill; ctx.fill(); }
if (stroke) { ctx.strokeStyle=stroke; ctx.stroke(); }
}
function reset(demo) {
snake = [{x:9,y:8},{x:8,y:8},{x:7,y:8},{x:6,y:8}];
dir = {x:1,y:0}; queued = null;
passengers = [{x:17,y:4,c:0},{x:21,y:11,c:1},{x:5,y:3,c:2}];
score = 0; state = demo ? 'demo' : 'play'; gameOver = false; tick = 0; lastMove = performance.now();
updateUI(); draw();
}
function updateUI() {
scoreEl.textContent = score;
modeEl.textContent = state === 'demo' ? 'DEMO RIDE' : gameOver ? 'JOURNEY ENDED' : state === 'paused' ? 'PAUSED' : 'NOW BOARDING';
statusEl.textContent = gameOver ? 'End of the line' : state === 'paused' ? 'Taking a break' : state === 'demo' ? 'Enjoying the view' : 'On the move';
message.classList.toggle('hidden', state === 'play' && !gameOver);
messageText.textContent = gameOver ? 'End of the line! Click to ride again' : state === 'paused' ? 'Paused · press space to continue' : 'Click or press a key to start';
wagonRow.innerHTML = '<span class="mini-engine"></span>' + Array.from({length:Math.min(3+score,7)},(_,i) => '<span class="mini-wagon" style="background:'+colors[i%colors.length]+'"></span>').join('') + (score > 4 ? '<span class="wagon-dots">···</span>' : '');
}
function spawn() {
let x,y, attempts=0;
do {
x=2+Math.floor(random()*(W-4)); y=2+Math.floor(random()*(H-4)); attempts++;
} while (attempts<200 && (snake.some(p=>p.x===x&&p.y===y) || passengers.some(p=>Math.abs(p.x-x)+Math.abs(p.y-y)<4)));
passengers.push({x,y,c:Math.floor(random()*colors.length)});
}
function aiDirection() {
const head=snake[0];
const blocked=new Set(snake.slice(0,-1).map(p=>p.x+','+p.y));
const queue=[{x:head.x,y:head.y,first:null}], visited=new Set([head.x+','+head.y]);
const choices=[dir,{x:dir.y,y:-dir.x},{x:-dir.y,y:dir.x},{x:-dir.x,y:-dir.y}];
for(let i=0;i<queue.length;i++) {
const p=queue[i];
if (p.first && passengers.some(f=>f.x===p.x&&f.y===p.y)) return p.first;
for(const d of choices) {
if (!p.first && d.x===-dir.x && d.y===-dir.y) continue;
const x=p.x+d.x,y=p.y+d.y,key=x+','+y;
if(x<0||y<0||x>=W||y>=H||blocked.has(key)||visited.has(key)) continue;
visited.add(key); queue.push({x,y,first:p.first||d});
}
}
for(const d of choices) {
const x=head.x+d.x,y=head.y+d.y;
if (!(d.x===-dir.x&&d.y===-dir.y) && x>=0&&x<W&&y>=0&&y<H&&!blocked.has(x+','+y)) return d;
}
return dir;
}
function move() {
if (state === 'demo') dir=aiDirection();
else if (queued) { dir=queued; queued=null; }
const next={x:snake[0].x+dir.x,y:snake[0].y+dir.y};
const index=passengers.findIndex(p=>p.x===next.x&&p.y===next.y);
const hit=next.x<0||next.x>=W||next.y<0||next.y>=H||snake.slice(0,index>=0?snake.length:snake.length-1).some(p=>p.x===next.x&&p.y===next.y);
if(hit) {
if(state==='demo') { reset(true); return; }
gameOver=true; state='over'; updateUI(); return;
}
snake.unshift(next);
if(index>=0) { passengers.splice(index,1); score++; spawn(); updateUI(); }
else snake.pop();
tick++;
}
function ground() {
ctx.fillStyle='#bbd8a9'; ctx.fillRect(0,0,832,512);
for(let y=0;y<H;y++) for(let x=0;x<W;x++) {
if ((x+y)%2===0) { ctx.fillStyle='rgba(255,255,255,.035)'; ctx.fillRect(x*S,y*S,S,S); }
let n=(x*73+y*127+x*y*17)%43;
if(n===3 || n===11) {
let px=x*S+8+(n%5), py=y*S+12;
ctx.strokeStyle='rgba(94,145,88,.25)'; ctx.lineWidth=1.5;
ctx.beginPath();ctx.moveTo(px-3,py);ctx.lineTo(px,py+3);ctx.lineTo(px+3,py);ctx.stroke();
}
if(n===21) {
ctx.fillStyle='rgba(255,252,220,.62)';
ctx.beginPath();ctx.arc(x*S+18,y*S+20,2,0,Math.PI*2);ctx.fill();
ctx.fillStyle='#e8bd68';ctx.beginPath();ctx.arc(x*S+18,y*S+20,0.8,0,Math.PI*2);ctx.fill();
}
}
ctx.strokeStyle='rgba(255,255,255,.32)';ctx.lineWidth=2;ctx.setLineDash([5,7]);
ctx.strokeRect(7,7,818,498);ctx.setLineDash([]);
// A few little clusters of meadow foliage
[[28,45],[795,62],[35,465],[793,448],[390,474],[454,39]].forEach(([x,y],i)=>{
ctx.fillStyle='rgba(102,158,95,.22)';
ctx.beginPath();ctx.ellipse(x,y,13,7,-.4,0,7);ctx.fill();
ctx.beginPath();ctx.ellipse(x+10,y+3,10,5,.4,0,7);ctx.fill();
ctx.fillStyle=i%2?'#f6efcd':'#eeb9a4';
for(let j=0;j<3;j++){ctx.beginPath();ctx.arc(x+j*5,y-2+(j%2)*4,2,0,7);ctx.fill();}
});
}
function platform(p) {
const x=p.x*S+S/2, y=p.y*S+S/2;
ctx.save();ctx.translate(x,y);
ctx.fillStyle='rgba(71,105,66,.15)';ctx.beginPath();ctx.ellipse(0,13,23,10,0,0,7);ctx.fill();
rounded(-23,-11,46,24,6,'#f3e9cb','#c9bca0');
rounded(-20,5,40,4,2,'#e4ba58');
ctx.strokeStyle='#fff9e5';ctx.lineWidth=1;ctx.setLineDash([3,3]);ctx.beginPath();ctx.moveTo(-18,7);ctx.lineTo(18,7);ctx.stroke();ctx.setLineDash([]);
// Platform sign and waiting passenger
ctx.strokeStyle='#789379';ctx.lineWidth=2;ctx.beginPath();ctx.moveTo(-17,2);ctx.lineTo(-17,-14);ctx.stroke();
rounded(-21,-19,9,7,2,'#6d9675');
ctx.fillStyle='#fff9de';ctx.beginPath();ctx.arc(-16.5,-15.5,1.3,0,7);ctx.fill();
ctx.fillStyle='#526857';ctx.beginPath();ctx.ellipse(3,4,8,3,0,0,7);ctx.fill();
ctx.strokeStyle='#415e50';ctx.lineWidth=2;ctx.beginPath();ctx.moveTo(0,2);ctx.lineTo(-1,7);ctx.moveTo(5,2);ctx.lineTo(6,7);ctx.stroke();
rounded(-3,-7,11,11,4,colors[p.c]);
ctx.fillStyle='#f3d2a9';ctx.beginPath();ctx.arc(2.5,-10,5,0,7);ctx.fill();
ctx.fillStyle='#5c5144';ctx.beginPath();ctx.arc(2.5,-12,4.5,Math.PI,Math.PI*2);ctx.fill();
ctx.restore();
}
function train() {
// Couplers beneath the cars
ctx.lineCap='round';ctx.lineJoin='round';
ctx.strokeStyle='rgba(62,90,61,.24)';ctx.lineWidth=9;
ctx.beginPath();snake.forEach((p,i)=>{let x=p.x*S+16,y=p.y*S+18;i?ctx.lineTo(x,y):ctx.moveTo(x,y)});ctx.stroke();
ctx.strokeStyle='#657665';ctx.lineWidth=4;
ctx.beginPath();snake.forEach((p,i)=>{let x=p.x*S+16,y=p.y*S+16;i?ctx.lineTo(x,y):ctx.moveTo(x,y)});ctx.stroke();
for(let i=snake.length-1;i>=0;i--) {
let p=snake[i], d;
if(i===0) d=dir;
else d={x:snake[i-1].x-p.x,y:snake[i-1].y-p.y};
const angle=Math.atan2(d.y,d.x);
ctx.save();ctx.translate(p.x*S+16,p.y*S+16);ctx.rotate(angle);
ctx.fillStyle='rgba(54,82,52,.18)';rounded(-13,-8,27,22,6,'rgba(54,82,52,.18)');
// wheels
rounded(-10,-13,7,4,2,'#405b4d');rounded(4,-13,7,4,2,'#405b4d');
rounded(-10,9,7,4,2,'#405b4d');rounded(4,9,7,4,2,'#405b4d');
if(i===0) {
rounded(-14,-10,27,20,5,'#35664e','#2f5a46');
rounded(-13,-9,10,18,3,'#4c8063');
rounded(-11,-6,6,12,2,'#c2dfca');
rounded(-1,-7,11,14,4,'#4d8060');
ctx.fillStyle='#294f3d';ctx.beginPath();ctx.arc(4,0,4,0,7);ctx.fill();
ctx.fillStyle='#d8b758';ctx.beginPath();ctx.arc(4,0,2,0,7);ctx.fill();
rounded(11,-6,4,12,2,'#e5ba63');
ctx.fillStyle='#fff5c9';ctx.beginPath();ctx.arc(14,0,2,0,7);ctx.fill();
} else {
let col=colors[(i-1)%colors.length];
rounded(-13,-10,26,20,5,col,'rgba(70,80,55,.20)');
rounded(-9,-7,18,14,3,'rgba(255,255,255,.18)');
rounded(-7,-5,6,10,2,'#fff7de');
rounded(2,-5,6,10,2,'#fff7de');
ctx.fillStyle='rgba(255,255,255,.55)';ctx.fillRect(-11,-8,22,1);
}
ctx.restore();
}
}
function draw() {
ground();
passengers.forEach(platform);
train();
}
function start() {
if(gameOver) { reset(false); return; }
if(state==='demo') { state='play'; lastMove=performance.now(); updateUI(); }
}
function setDirection(name) {
if(gameOver) { reset(false); }
else start();
if(state==='paused') { state='play'; updateUI(); }
let d=directions[name];
if(d && !(d.x===-dir.x && d.y===-dir.y)) queued=d;
}
board.addEventListener('click', () => {
if(state==='paused') {state='play';lastMove=performance.now();updateUI();}
else start();
});
document.getElementById('restart').addEventListener('click', () => reset(false));
document.querySelectorAll('[data-dir]').forEach(b=>b.addEventListener('click',()=>setDirection(b.dataset.dir)));
window.addEventListener('keydown', e => {
const map={ArrowUp:'up',ArrowDown:'down',ArrowLeft:'left',ArrowRight:'right',w:'up',s:'down',a:'left',d:'right'};
let key=e.key.length===1?e.key.toLowerCase():e.key;
if(map[key]) { e.preventDefault(); setDirection(map[key]); }
else if(key===' ') {
e.preventDefault();
if(gameOver) reset(false);
else if(state==='demo') start();
else { state=state==='paused'?'play':'paused';lastMove=performance.now();updateUI(); }
} else if(state==='demo') start();
});
function loop(now) {
if((state==='demo'||state==='play') && now-lastMove> (state==='demo'?180:150)) {
lastMove=now; move(); draw();
}
requestAnimationFrame(loop);
}
reset(true); requestAnimationFrame(loop);
})();
</script>
</body>
</html>Reasoning trace (1,088 tokens)
**Designing a Game** I need to create a polished game featuring a train on a top-down track grid. It will have colorful wagons and waiting passengers at platforms. I'll develop a demo with self-play AI, ensuring visible paint and actions. The interaction will utilize keyboard arrows, WASD, and mobile controls. I’m thinking of a layout that includes a header, game panel, and sidebar, with a responsive design in warm cream and forest greens. The train will need smooth movement on the grid, with detailed rendering on a canvas.**Developing Game Mechanics** I need to show waiting passengers on small platform rectangles, possibly floating, and include one to three food items. Establishing a game story is essential! The board will be a grid of 24x16, with a canvas aspect of 1.5. I'll draw platforms as food icons at tile positions, with some fixed stations and moving spawned passengers. The AI will use BFS to pick up passengers and select targets on the grid. I have to consider the UI layout, adjusting the heights and widths for a clear and functional design.**Finalizing Game Layout** I need to set up the board's measurements—top 54, bottom 42, totaling 607, which fits nicely with a header of 75, hero also at 75, and a footer of 20, giving a total of 777. The sidebar will be 286. The main title shouldn’t be too prominent. I’m thinking about adding an interactive overlay to prompt users to start by clicking or pressing a key, positioned non-obstructively at the top center over the canvas. I also want to implement toggle controls for AI demos.**Designing game mechanics** I’m thinking about a game overlay with the initial snake length of 4 and movement timings of 180ms for the demo and 160ms for user input. The visual clarity is key, so I’ll set a grid layout using canvas for rendering. I’m considering how to design passenger stations and pickups with distinct colors. The side panel will show important info and colorful dots. I'll also include a scoreboard and decorative elements, ensuring everything is clear and engaging for the player.**Visualizing train mechanics** I’m considering how to represent a train traveling on rails, maybe drawing a faint route behind it. I think using gray lines to connect segments will work well and indicate movement. The wagons can be positioned based on direction and previous segments. I’ll design the locomotive with specific measurements and add details like steam puffs and coloring for contrast. Passengers will have simple designs, and I can include floating markers. I want to ensure everything looks good while building this in JavaScript!**Updating game mechanics** I’m focusing on how to handle score updates and game speed for the demo, making sure that the AI uses breadth-first search to target the nearest item while avoiding the body except for the tail—that should keep things safe. The game shouldn’t have a reverse feature for the user and should ideally reset upon failure. I need to design a clear game over panel with start and pause buttons and ensure a mobile-friendly layout without horizontal scrolling. I’ll keep the canvas visible alongside sidebar text and footer controls.**Planning layout dimensions** I’m thinking about rendering the tile properly with CSS and adjusting the sidebar style. For the height of the viewport screenshot, I estimate that the main header will be around 60 pixels, the intro about 72, the canvas might be 508, and the footer is 45. Adding the header panel, that all adds up to 682 pixels. Overall, it looks good. Now, I’m ready to jump into coding!