Models 44
Train snakeOne-line

GPT-6.1 Terra

by OpenAIReasoningClean
Open in new window

Running live in a sandboxed frame. Click inside it before using the keyboard.

How it went

Total time
1 min 5 s
Cost
$0.027
Output tokens
5,296
Spent thinking
219 tokens
Speed
92.3 tok/s
Console errors
0
First token after
7.2 s
First visible text after
7.2 s
Prompt tokens
361
Code size
14.3 KB
Finish reason
stop
Served by
OpenAI
Model id
openai/gpt-6.1-terra
Reasoning sent
{"effort":"low"}
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 · 209 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</title>
<style>
  @import url('data:text/css,');
  *{box-sizing:border-box}
  :root{color-scheme:dark;--ink:#f8f4e7;--muted:#a9b7b7;--lime:#d9ed91;--orange:#f7ac6c}
  body{margin:0;background:#101b1c;color:var(--ink);font-family:ui-rounded,"Trebuchet MS",system-ui,sans-serif}
  body:before{content:"";position:fixed;inset:0;background:radial-gradient(circle at 15% 0%,#29433a 0,transparent 33%),radial-gradient(circle at 92% 80%,#243c35 0,transparent 30%);pointer-events:none}
  .wrap{position:relative;max-width:1280px;margin:auto;padding:26px 38px 22px}
  header{display:flex;align-items:center;justify-content:space-between;margin-bottom:23px}
  .brand{display:flex;align-items:center;gap:12px}
  .brand-icon{width:43px;height:43px;background:var(--lime);border-radius:13px;display:grid;place-items:center;color:#21392b;font-size:24px}
  .brand-name{font-weight:900;letter-spacing:-.04em;font-size:21px;line-height:1}
  .brand-sub{font-size:10px;letter-spacing:.19em;text-transform:uppercase;color:#9eafa8;margin-top:5px}
  .top-tag{font-size:11px;letter-spacing:.13em;text-transform:uppercase;color:#aec0b6;border:1px solid #40544a;border-radius:30px;padding:9px 13px}
  .layout{display:grid;grid-template-columns:minmax(0,1fr) 252px;gap:23px}
  .game-area{min-width:0}
  .title-row{display:flex;align-items:end;justify-content:space-between;gap:15px;margin-bottom:17px}
  .eyebrow{font-size:10px;text-transform:uppercase;letter-spacing:.2em;color:#c9df91;font-weight:800;margin-bottom:7px}
  h1{font-size:clamp(27px,3vw,38px);letter-spacing:-.055em;line-height:1;margin:0;font-weight:900}
  .subtitle{color:#a8b9b1;font-size:13px;margin:7px 0 0}
  .live{display:flex;align-items:center;gap:7px;color:#b5cbbd;font-size:11px;white-space:nowrap;padding-bottom:4px}
  .dot{width:7px;height:7px;background:#bfdf84;border-radius:50%;box-shadow:0 0 12px #b5ea7b}
  .board-shell{background:#243a31;border:1px solid #496052;border-radius:16px;padding:7px;box-shadow:0 16px 45px #07110d55}
  .board{position:relative;overflow:hidden;border-radius:10px;background:#1b3028;aspect-ratio:3/2}
  canvas{width:100%;height:100%;display:block}
  .start-banner{position:absolute;bottom:16px;left:50%;transform:translateX(-50%);background:#f2f1dc;color:#26382b;border-radius:9px;padding:10px 18px;box-shadow:0 5px 20px #09140db0;text-align:center;white-space:nowrap;cursor:pointer;font-size:12px;font-weight:900}
  .start-banner small{display:block;color:#768171;font-size:9px;letter-spacing:.09em;text-transform:uppercase;margin-top:3px}
  .board-bottom{display:flex;justify-content:space-between;color:#80988a;font-size:10px;letter-spacing:.09em;text-transform:uppercase;padding:11px 4px 0}
  aside{padding-top:2px}
  .ticket{background:#e9ead7;color:#253b2d;border-radius:14px;overflow:hidden;box-shadow:0 10px 30px #09140d44}
  .ticket-head{padding:20px 20px 16px;border-bottom:1px dashed #abb7a2}
  .ticket-label{font-size:10px;letter-spacing:.18em;font-weight:900;color:#6a8069;text-transform:uppercase}
  .ticket h2{font-size:23px;letter-spacing:-.05em;margin:8px 0 3px}
  .ticket p{font-size:12px;line-height:1.5;color:#748171;margin:0}
  .stats{display:grid;grid-template-columns:1fr 1fr;padding:18px 20px;gap:8px}
  .stat-label{font-size:9px;letter-spacing:.13em;text-transform:uppercase;color:#7d8c7c;font-weight:bold}
  .stat-value{font-size:30px;font-weight:900;letter-spacing:-.05em;line-height:1.15;margin-top:5px}
  .ticket-foot{background:#d9e1c8;padding:11px 20px;display:flex;justify-content:space-between;align-items:center;font-size:10px;color:#61765e;font-weight:800;letter-spacing:.1em}
  .mini-train{font-size:19px;letter-spacing:0}
  .side-block{border:1px solid #405349;border-radius:14px;padding:18px 19px;margin-top:14px;background:#21332c99}
  .side-title{font-size:10px;letter-spacing:.17em;color:#a5b9a9;font-weight:800;text-transform:uppercase;margin-bottom:14px}
  .instruction{display:flex;gap:11px;align-items:flex-start;margin:13px 0;color:#c1cec1;font-size:12px;line-height:1.4}
  .instruction .icon{width:27px;height:27px;flex:none;border-radius:7px;background:#354b3d;display:grid;place-items:center;font-size:14px}
  .instruction strong{color:#f1f2dc;display:block;font-size:12px}
  .keys{display:flex;gap:4px;margin-top:14px}
  kbd{font:700 11px system-ui;background:#344a3d;color:#e0ead8;border:1px solid #506756;border-bottom-width:3px;border-radius:5px;min-width:27px;text-align:center;padding:5px}
  .or{font-size:10px;color:#91a596;align-self:center;margin:0 5px}
  button{width:100%;border:1px solid #566b59;background:transparent;color:#d7e1ce;border-radius:9px;padding:11px;font:700 12px inherit;cursor:pointer;margin-top:14px}
  button:hover{background:#344a3b}
  .footer{display:flex;justify-content:space-between;margin-top:20px;font-size:10px;color:#728a7c;letter-spacing:.08em;text-transform:uppercase}
  @media(max-width:800px){.wrap{padding:20px 16px}.layout{grid-template-columns:1fr}.title-row{margin-top:4px}aside{display:grid;grid-template-columns:1fr 1fr;gap:12px}.side-block{margin:0}.footer{margin-top:15px}}
  @media(max-width:480px){.top-tag{display:none}.brand-name{font-size:19px}.subtitle{font-size:12px}.live{display:none}.start-banner{font-size:10px;bottom:8px;padding:7px 12px}.board-bottom{font-size:8px}aside{grid-template-columns:1fr}.side-block{padding:15px}.instruction{margin:8px 0}.footer span:last-child{display:none}}
</style>
</head>
<body>
<div class="wrap">
  <header>
    <div class="brand"><div class="brand-icon">▰</div><div><div class="brand-name">platform express</div><div class="brand-sub">A little journey, a lot of joy</div></div></div>
    <div class="top-tag">✦ &nbsp; The scenic route &nbsp; ✦</div>
  </header>
  <main class="layout">
    <section class="game-area">
      <div class="title-row"><div><div class="eyebrow">All aboard! &nbsp; / &nbsp; No. 01</div><h1>Next stop: everywhere.</h1><p class="subtitle">Pick up passengers, grow your train, and enjoy the ride.</p></div><div class="live"><span class="dot"></span><span id="status">AUTOPILOT IS ON</span></div></div>
      <div class="board-shell"><div class="board"><canvas id="game" width="900" height="600"></canvas><div class="start-banner" id="banner">Click or press a key to start<small>You're watching the train take a little test drive</small></div></div></div>
      <div class="board-bottom"><span>✳ &nbsp; A railway adventure</span><span>Mind the tracks &nbsp; • &nbsp; Enjoy the journey</span></div>
    </section>
    <aside>
      <div class="ticket">
        <div class="ticket-head"><div class="ticket-label">✦ &nbsp; Your journey ticket</div><h2>All aboard!</h2><p>There's always room for one more.</p></div>
        <div class="stats"><div><div class="stat-label">Passengers</div><div class="stat-value" id="score">00</div></div><div><div class="stat-label">Train cars</div><div class="stat-value" id="cars">04</div></div></div>
        <div class="ticket-foot"><span>ONE WAY · ADVENTURE</span><span class="mini-train">▰ ▰ ▰</span></div>
      </div>
      <div class="side-block"><div class="side-title">The conductor's guide</div>
        <div class="instruction"><span class="icon">☺</span><div><strong>Pick up passengers</strong>Find the folks waiting at the platforms.</div></div>
        <div class="instruction"><span class="icon">✦</span><div><strong>Keep on track</strong>Don't run into the edge or your own train.</div></div>
        <div class="keys"><kbd>↑</kbd><kbd>←</kbd><kbd>↓</kbd><kbd>→</kbd><span class="or">or</span><kbd>W</kbd><kbd>A</kbd><kbd>S</kbd><kbd>D</kbd></div>
      </div>
      <button id="restart">↻ &nbsp; Restart journey</button>
    </aside>
  </main>
  <div class="footer"><span>Made for the long way around</span><span>Take your time. Enjoy the view. ✳</span></div>
</div>
<script>
const canvas=document.getElementById('game'),ctx=canvas.getContext('2d');
const banner=document.getElementById('banner'),statusEl=document.getElementById('status');
const W=18,H=12,S=50;
let train,dir,nextDir,passengers,score,demo=true,ended=false,last=0,steps=0;
const colors=['#f2b15e','#e97968','#91b7a5','#d6bd77','#aa9bc7','#eb8f79','#8bbac3'];
function init(isDemo){
  demo=isDemo;ended=false;score=0;steps=0;
  train=[{x:7,y:6},{x:6,y:6},{x:5,y:6},{x:4,y:6}];
  dir={x:1,y:0};nextDir={...dir};
  passengers=[{x:12,y:3,c:'#f5b86c'},{x:14,y:9,c:'#ef927b'},{x:3,y:2,c:'#9ec9c3'}];
  updateUI();draw();
}
function updateUI(){
  document.getElementById('score').textContent=String(score).padStart(2,'0');
  document.getElementById('cars').textContent=String(train.length).padStart(2,'0');
  statusEl.textContent=ended?'JOURNEY COMPLETE':demo?'AUTOPILOT IS ON':'YOU ARE THE CONDUCTOR';
  banner.style.display=(demo||ended)?'block':'none';
  banner.innerHTML=ended?'End of the line! Click or press a key to ride again<small>Every journey deserves another go</small>':'Click or press a key to start<small>You’re watching the train take a little test drive</small>';
}
function spawn(){
  let free=[];for(let y=1;y<H-1;y++)for(let x=1;x<W-1;x++)if(!train.some(a=>a.x===x&&a.y===y)&&!passengers.some(a=>a.x===x&&a.y===y))free.push({x,y});
  if(free.length){let p=free[Math.floor(Math.random()*free.length)];p.c=['#f5b86c','#ef927b','#9ec9c3','#d8a6bf'][Math.floor(Math.random()*4)];passengers.push(p)}
}
function auto(){
  const head=train[0], blocked=new Set(train.slice(0,-1).map(p=>p.x+','+p.y));
  let queue=[{x:head.x,y:head.y,first:null}],seen=new Set([head.x+','+head.y]);
  const dirs=[dir,{x:-dir.y,y:dir.x},{x:dir.y,y:-dir.x}];
  for(let i=0;i<queue.length;i++){
    let a=queue[i];
    if(a.first&&passengers.some(p=>p.x===a.x&&p.y===a.y))return a.first;
    for(const d of dirs){let x=a.x+d.x,y=a.y+d.y,k=x+','+y;
      if(x<0||x>=W||y<0||y>=H||blocked.has(k)||seen.has(k))continue;
      seen.add(k);queue.push({x,y,first:a.first||d});
    }
  }
  for(const d of dirs){let x=head.x+d.x,y=head.y+d.y;if(x>=0&&x<W&&y>=0&&y<H&&!blocked.has(x+','+y))return d}
  return dir;
}
function tick(){
  if(ended)return;
  if(demo)nextDir=auto();
  dir=nextDir;
  const head={x:train[0].x+dir.x,y:train[0].y+dir.y};
  const pi=passengers.findIndex(p=>p.x===head.x&&p.y===head.y);
  if(head.x<0||head.x>=W||head.y<0||head.y>=H||train.slice(0,pi<0?-1:undefined).some(p=>p.x===head.x&&p.y===head.y)){
    if(demo){init(true);return}
    ended=true;updateUI();return;
  }
  train.unshift(head);
  if(pi>=0){passengers.splice(pi,1);score++;spawn()}else train.pop();
  steps++;updateUI();
}
function round(x,y,w,h,r,fill){ctx.fillStyle=fill;ctx.beginPath();ctx.roundRect(x,y,w,h,r);ctx.fill()}
function draw(){
  ctx.fillStyle='#20382d';ctx.fillRect(0,0,900,600);
  // Quiet checkerboard and subtle railway-map lines
  for(let y=0;y<H;y++)for(let x=0;x<W;x++){
    ctx.fillStyle=(x+y)%2?'#233c30':'#263f32';ctx.fillRect(x*S,y*S,S,S);
    ctx.strokeStyle='#ffffff08';ctx.strokeRect(x*S+.5,y*S+.5,S,S);
  }
  // decorative landscape
  const shrubs=[[1,1],[9,1],[16,1],[2,5],[15,5],[1,10],[8,10],[16,10],[11,7]];
  shrubs.forEach(([x,y],i)=>{let px=x*S+13,py=y*S+17;ctx.fillStyle='#496951';ctx.beginPath();ctx.arc(px,py,3,0,7);ctx.arc(px+8,py-3,4,0,7);ctx.arc(px+14,py+2,3,0,7);ctx.fill();ctx.fillStyle='#8ca47a';ctx.fillRect(px+5,py+7,2,2)});
  // Platform tiles and waiting passengers
  passengers.forEach((p,i)=>{
    let x=p.x*S,y=p.y*S;
    round(x+3,y+4,44,42,6,'#b6b49a');round(x+6,y+7,38,36,4,'#dedbc1');
    ctx.fillStyle='#a5a48c';for(let j=0;j<5;j++)ctx.fillRect(x+8+j*7,y+38,4,2);
    ctx.fillStyle='#c5aa75';ctx.fillRect(x+8,y+9,34,2);
    // shadow, body, head and hair
    ctx.fillStyle='#61705c55';ctx.beginPath();ctx.ellipse(x+25,y+36,11,4,0,0,7);ctx.fill();
    round(x+19,y+22,12,14,4,p.c);
    ctx.fillStyle='#4d5147';ctx.fillRect(x+20,y+33,3,4);ctx.fillRect(x+27,y+33,3,4);
    ctx.fillStyle='#f4ceaa';ctx.beginPath();ctx.arc(x+25,y+17,6,0,7);ctx.fill();
    ctx.fillStyle=i%2?'#735044':'#514e43';ctx.beginPath();ctx.arc(x+25,y+15,6,Math.PI,Math.PI*2);ctx.fill();
    ctx.fillStyle='#f7e9ba';ctx.beginPath();ctx.arc(x+39,y+13,2,0,7);ctx.fill();
  });
  // connections between cars
  ctx.strokeStyle='#a9b1a0';ctx.lineWidth=5;ctx.lineCap='round';ctx.beginPath();
  train.forEach((p,i)=>{let x=p.x*S+25,y=p.y*S+25;if(i===0)ctx.moveTo(x,y);else ctx.lineTo(x,y)});ctx.stroke();
  train.forEach((p,i)=>{
    let d=i===0?dir:{x:train[i-1].x-p.x,y:train[i-1].y-p.y};
    if(Math.abs(d.x)+Math.abs(d.y)!==1)d={x:1,y:0};
    ctx.save();ctx.translate(p.x*S+25,p.y*S+25);ctx.rotate(Math.atan2(d.y,d.x));
    // wheels
    round(-17,-20,12,5,2,'#17251e');round(6,-20,12,5,2,'#17251e');round(-17,15,12,5,2,'#17251e');round(6,15,12,5,2,'#17251e');
    if(i===0){
      round(-21,-15,42,30,7,'#c96751');round(-19,-13,38,26,6,'#eb8a6b');
      round(-18,-12,14,24,4,'#f8c68f');round(-15,-9,8,18,2,'#527c72');
      round(0,-10,17,20,5,'#d76e58');round(4,-6,8,12,4,'#3b4c3f');
      round(17,-10,5,20,2,'#f3c276');
      ctx.fillStyle='#fff0bd';ctx.beginPath();ctx.arc(21,0,3,0,7);ctx.fill();
      round(-20,-2,3,4,1,'#e8d29e');
    }else{
      let color=colors[(i-1)%colors.length];round(-20,-15,40,30,6,'#526357');round(-19,-14,38,28,6,color);
      round(-14,-10,28,20,4,'#f4dfb8');round(-11,-8,22,16,3,'#52786e');
      ctx.fillStyle='#d0e3c9';ctx.fillRect(-2,-8,3,16);
      ctx.fillStyle='#ffffff3d';ctx.fillRect(-10,-7,5,3);ctx.fillRect(3,-7,5,3);
      round(-18,-13,36,3,2,'#ffffff40');
    }
    ctx.restore();
  });
  // little map details
  ctx.fillStyle='#a7bb9a';ctx.font='bold 9px system-ui';ctx.letterSpacing='2px';ctx.fillText('NORTH',22,28);ctx.letterSpacing='0px';
  ctx.strokeStyle='#9cb398';ctx.lineWidth=1;ctx.beginPath();ctx.moveTo(25,39);ctx.lineTo(25,52);ctx.moveTo(21,43);ctx.lineTo(25,38);ctx.lineTo(29,43);ctx.stroke();
}
function start(){if(demo||ended)init(false)}
banner.addEventListener('click',start);
canvas.addEventListener('click',start);
document.getElementById('restart').addEventListener('click',()=>init(false));
window.addEventListener('keydown',e=>{
  const map={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}};
  let d=map[e.key]||map[e.key.toLowerCase()];
  if(d||e.key===' '){e.preventDefault();if(demo||ended){start();if(d&&!(d.x===-dir.x&&d.y===-dir.y))nextDir=d;return}if(d&&!(d.x===-dir.x&&d.y===-dir.y))nextDir=d}
  else if(demo||ended)start();
});
function loop(t){if(t-last>180){tick();last=t}draw();requestAnimationFrame(loop)}
init(true);requestAnimationFrame(loop);
</script>
</body>
</html>