Models 44
Train snakeOne-line

GPT-6 Luna

by OpenAIReasoningClean
Open in new window

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

How it went

Total time
44.9 s
Cost
$0.0026
Output tokens
5,158
Spent thinking
0 tokens
Speed
134 tok/s
Console errors
0
First token after
6.4 s
First visible text after
6.4 s
Prompt tokens
361
Code size
15.4 KB
Finish reason
stop
Served by
OpenAI
Model id
openai/gpt-6-luna
Reasoning sent
{"effort":"none"}
Max output
64,000 tokens
Generated
Nov 10, 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 · 311 lines

<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>Platform Express</title>
<style>
  :root{
    --ink:#173248;--muted:#688095;--cream:#fff8e9;--grass:#b9dcae;
    --rail:#718091;--red:#e66c59;--yellow:#f6c85f;--blue:#56a8ce;--green:#69b88d;
  }
  *{box-sizing:border-box}
  body{
    margin:0;min-height:100vh;display:grid;place-items:center;padding:22px;
    background:#e8f0e8;color:var(--ink);
    font-family:ui-rounded,"Trebuchet MS",system-ui,-apple-system,sans-serif;
  }
  .game{
    width:min(100%,1000px);background:var(--cream);border:4px solid white;
    border-radius:28px;overflow:hidden;box-shadow:0 20px 60px #24485322;
  }
  header{display:flex;align-items:center;justify-content:space-between;gap:16px;padding:20px 26px 15px}
  .brand{display:flex;align-items:center;gap:13px}
  .logo{width:48px;height:48px;border-radius:16px;background:#f6c85f;display:grid;place-items:center;font-size:27px;box-shadow:inset 0 -4px #dda841}
  h1{font-size:clamp(19px,3vw,27px);line-height:1;margin:0;letter-spacing:-.6px}
  .subtitle{font-size:13px;color:var(--muted);margin-top:5px}
  .stats{display:flex;gap:10px}
  .stat{min-width:95px;padding:9px 14px;border-radius:15px;background:#edf2e8;text-align:center}
  .stat strong{display:block;font-size:20px;line-height:1.05}
  .stat span{font-size:10px;text-transform:uppercase;letter-spacing:1.2px;color:var(--muted);font-weight:800}
  .track-wrap{padding:0 18px 16px}
  .board{
    position:relative;border-radius:20px;overflow:hidden;background:#dcedd5;
    border:2px solid #d1e3c9;aspect-ratio: 1.92 / 1;min-height:300px;
  }
  canvas{display:block;width:100%;height:100%}
  .overlay{
    position:absolute;inset:0;display:grid;place-items:center;background:#17324826;
    transition:opacity .25s;
  }
  .overlay.hidden{opacity:0;pointer-events:none}
  .card{
    text-align:center;background:#fff9eb;border:3px solid white;border-radius:22px;
    padding:17px 25px;box-shadow:0 8px 24px #17324825;max-width:calc(100% - 30px);
  }
  .card .emoji{font-size:29px;line-height:1}
  .card h2{font-size:20px;margin:7px 0 4px}
  .card p{font-size:12px;color:var(--muted);margin:0}
  .card kbd{display:inline-block;margin-top:10px;padding:5px 10px;border-radius:8px;background:#eaf0e8;font:700 11px inherit;color:var(--ink)}
  footer{padding:0 24px 18px;display:flex;justify-content:space-between;align-items:center;gap:12px;color:var(--muted);font-size:12px}
  .legend{display:flex;gap:14px;align-items:center}
  .legend span{white-space:nowrap}
  .dot{display:inline-block;width:9px;height:9px;margin-right:5px;border-radius:50%;vertical-align:middle}
  .controls{font-weight:700;color:#527087}
  .touch-controls{display:none;gap:7px;justify-content:center;padding:0 0 17px}
  .touch-controls button{border:0;border-radius:12px;background:#edf2e8;color:var(--ink);font-size:18px;font-weight:800;width:44px;height:38px}
  @media(max-width:650px){
    body{padding:10px}
    .game{border-radius:22px}
    header{padding:15px 15px 12px;align-items:flex-start}
    .logo{width:40px;height:40px;border-radius:13px;font-size:23px}
    .subtitle{font-size:11px}
    .stats{gap:6px}
    .stat{min-width:62px;padding:8px 7px}
    .stat strong{font-size:17px}
    .stat span{font-size:8px;letter-spacing:.7px}
    .track-wrap{padding:0 9px 11px}
    .board{aspect-ratio:1 / 1.08;min-height:0}
    footer{padding:0 14px 12px;font-size:10px;flex-wrap:wrap}
    .legend{gap:8px}
    .controls{display:none}
    .touch-controls{display:flex}
  }
  @media(max-width:390px){.subtitle{max-width:155px}.legend{gap:6px}}
</style>
</head>
<body>
<main class="game">
  <header>
    <div class="brand">
      <div class="logo">🚂</div>
      <div><h1>Platform Express</h1><div class="subtitle">All aboard! Pick up passengers along the line.</div></div>
    </div>
    <div class="stats">
      <div class="stat"><strong id="score">0</strong><span>Passengers</span></div>
      <div class="stat"><strong id="best">0</strong><span>On board</span></div>
    </div>
  </header>
  <div class="track-wrap">
    <div class="board" id="board">
      <canvas id="canvas" aria-label="Snake train game"></canvas>
      <div class="overlay" id="overlay">
        <div class="card">
          <div class="emoji">🚉</div>
          <h2>Ready to depart?</h2>
          <p>Collect every waiting passenger to add a wagon.</p>
          <kbd>Click or press a key to start</kbd>
        </div>
      </div>
    </div>
  </div>
  <div class="touch-controls" aria-label="Directional controls">
    <button data-dir="up" aria-label="Up">▲</button>
    <button data-dir="left" aria-label="Left">◀</button>
    <button data-dir="down" aria-label="Down">▼</button>
    <button data-dir="right" aria-label="Right">▶</button>
  </div>
  <footer>
    <div class="legend">
      <span><i class="dot" style="background:#e66c59"></i>Passengers</span>
      <span><i class="dot" style="background:#f6c85f"></i>Wagons</span>
      <span><i class="dot" style="background:#56a8ce"></i>Track</span>
    </div>
    <div class="controls">Arrow keys / WASD to steer · Space to pause</div>
  </footer>
</main>
<script>
(() => {
  const canvas=document.getElementById('canvas'), ctx=canvas.getContext('2d');
  const board=document.getElementById('board'), overlay=document.getElementById('overlay');
  const scoreEl=document.getElementById('score'), bestEl=document.getElementById('best');
  const dirs={up:{x:0,y:-1},down:{x:0,y:1},left:{x:-1,y:0},right:{x:1,y:0}};
  const passengerColors=['#e66c59','#f3aa52','#8b83c9','#61a8c8','#e67ba0'];
  let cols=24,rows=14,cell=30,train=[],dir='right',nextDir='right',passenger=null;
  let score=0,started=false,paused=false,gameOver=false,lastStep=0,stepMs=220,autoTimer=0;
  let anim=0, dust=[];
  function resize(){
    const rect=board.getBoundingClientRect(), dpr=Math.min(devicePixelRatio||1,2);
    canvas.width=Math.round(rect.width*dpr);canvas.height=Math.round(rect.height*dpr);
    ctx.setTransform(dpr,0,0,dpr,0,0);
    const mobile=rect.width<650;
    cols=mobile?16:24;
    rows=mobile?Math.max(16,Math.round(cols*rect.height/rect.width)):14;
    cell=Math.min(rect.width/cols,rect.height/rows);
    cols=Math.floor(rect.width/cell);rows=Math.floor(rect.height/cell);
    reset(false);draw();
  }
  function reset(show=true){
    const cx=Math.floor(cols*.43), cy=Math.floor(rows/2);
    train=[{x:cx,y:cy},{x:cx-1,y:cy},{x:cx-2,y:cy}];
    dir=nextDir='right';score=0;gameOver=false;paused=false;stepMs=220;
    scoreEl.textContent='0';bestEl.textContent='3';
    placePassenger();
    if(show){started=false;overlay.classList.remove('hidden')}
  }
  function placePassenger(){
    let p,tries=0;
    do{p={x:Math.floor(Math.random()*cols),y:Math.floor(Math.random()*rows),color:passengerColors[Math.floor(Math.random()*passengerColors.length)]};tries++}
    while(train.some(t=>t.x===p.x&&t.y===p.y)&&tries<500);
    passenger=p;
  }
  function start(){
    if(gameOver) reset(false);
    started=true;paused=false;overlay.classList.add('hidden');lastStep=performance.now();
  }
  function setDirection(d){
    if(!dirs[d])return;
    const v=dirs[d],cur=dirs[dir];
    if(v.x===-cur.x&&v.y===-cur.y)return;
    nextDir=d;
    if(!started)start();
  }
  function key(e){
    const k=e.key.toLowerCase();
    const map={arrowup:'up',w:'up',arrowdown:'down',s:'down',arrowleft:'left',a:'left',arrowright:'right',d:'right'};
    if(map[k]){e.preventDefault();setDirection(map[k]);return}
    if(k===' '){e.preventDefault();if(!started){start()}else if(!gameOver){paused=!paused;if(paused)showCard('⏸️','Train paused','Press space or a direction to continue.');else overlay.classList.add('hidden')}}
    else if(!started&&k!=='tab')start();
  }
  function showCard(icon,title,text){
    overlay.innerHTML='<div class="card"><div class="emoji">'+icon+'</div><h2>'+title+'</h2><p>'+text+'</p></div>';
    overlay.classList.remove('hidden');
  }
  function step(){
    dir=nextDir;const v=dirs[dir],head={x:train[0].x+v.x,y:train[0].y+v.y};
    const grow=passenger&&head.x===passenger.x&&head.y===passenger.y;
    const check=train.slice(0,grow?train.length:train.length-1);
    if(head.x<0||head.y<0||head.x>=cols||head.y>=rows||check.some(p=>p.x===head.x&&p.y===head.y)){
      gameOver=true;started=false;
      showCard('🚦','End of the line!','You picked up '+score+' passenger'+(score===1?'':'s')+'. Tap or press a key to ride again.');
      return;
    }
    train.unshift(head);if(!grow)train.pop();
    else{score++;scoreEl.textContent=score;bestEl.textContent=train.length;stepMs=Math.max(112,220-score*5);placePassenger()}
  }
  function roundedRect(x,y,w,h,r,fill,stroke){
    ctx.beginPath();ctx.roundRect(x,y,w,h,r);ctx.fillStyle=fill;ctx.fill();
    if(stroke){ctx.strokeStyle=stroke;ctx.lineWidth=1.2;ctx.stroke()}
  }
  function draw(){
    const w=canvas.clientWidth,h=canvas.clientHeight;
    ctx.clearRect(0,0,w,h);
    ctx.fillStyle='#dcedd5';ctx.fillRect(0,0,w,h);
    // Sunny, softly dotted countryside
    for(let y=0;y<rows;y++)for(let x=0;x<cols;x++){
      const px=x*cell,py=y*cell;
      if((x*7+y*13)%17===0){ctx.fillStyle='#c5e2bb';ctx.beginPath();ctx.arc(px+cell*.22,py+cell*.3,Math.max(1,cell*.045),0,Math.PI*2);ctx.fill()}
    }
    // platform awning along the upper edge
    const pad=cell*.25, platformH=cell*1.05;
    roundedRect(pad,pad,w-pad*2,platformH,cell*.22,'#f7edcf');
    ctx.fillStyle='#f3d987';ctx.fillRect(pad,pad,w-pad*2,cell*.14);
    for(let x=pad+cell*.3;x<w-pad;x+=cell*1.65){
      ctx.fillStyle='#f0bca0';ctx.fillRect(x,pad+cell*.15,cell*.08,platformH-cell*.22);
    }
    // railway sleepers and rails
    const railY=h-cell*1.1, railH=cell*.36;
    ctx.fillStyle='#9baf9b';
    for(let x=cell*.18;x<w;x+=cell*.52)roundedRect(x,railY,cell*.28,railH,cell*.06,'#9ca99e');
    roundedRect(0,railY+cell*.02,w,cell*.075,cell*.035,'#647a86');
    roundedRect(0,railY+cell*.25,w,cell*.075,cell*.035,'#647a86');
    // passenger waiting on platform
    if(passenger){
      const px=(passenger.x+.5)*cell,py=(passenger.y+.5)*cell;
      ctx.save();ctx.translate(px,py);
      const bob=Math.sin(anim/180)*cell*.035;ctx.translate(0,bob);
      ctx.fillStyle='#17324824';ctx.beginPath();ctx.ellipse(0,cell*.24,cell*.22,cell*.07,0,0,Math.PI*2);ctx.fill();
      // little suitcase
      roundedRect(-cell*.25,cell*.02,cell*.18,cell*.2,cell*.04,'#e7ab55');
      ctx.strokeStyle='#bd7e3b';ctx.lineWidth=1.5;ctx.beginPath();ctx.moveTo(-cell*.21,cell*.02);ctx.lineTo(-cell*.21,-cell*.025);ctx.lineTo(-cell*.1,-cell*.025);ctx.lineTo(-cell*.1,cell*.02);ctx.stroke();
      // body + head
      roundedRect(-cell*.12,-cell*.01,cell*.25,cell*.24,cell*.1,passenger.color);
      ctx.fillStyle='#f3c49c';ctx.beginPath();ctx.arc(0,-cell*.13,cell*.13,0,Math.PI*2);ctx.fill();
      ctx.fillStyle='#443b38';ctx.beginPath();ctx.arc(-cell*.04,-cell*.15,cell*.014,0,Math.PI*2);ctx.arc(cell*.045,-cell*.15,cell*.014,0,Math.PI*2);ctx.fill();
      ctx.strokeStyle='#a85d54';ctx.lineWidth=1.2;ctx.beginPath();ctx.arc(0,-cell*.105,cell*.04,.1,Math.PI-.1);ctx.stroke();
      ctx.restore();
    }
    // train wheels and wagons, draw tail to head
    for(let i=train.length-1;i>=0;i--){
      const p=train[i],cx=(p.x+.5)*cell,cy=(p.y+.5)*cell;
      const isHead=i===0,bodyW=cell*.78,bodyH=cell*.67;
      ctx.save();ctx.translate(cx,cy);
      let angle=0;if(isHead)angle={right:0,down:Math.PI/2,left:Math.PI,up:-Math.PI/2}[dir];
      else{
        const prev=train[i-1],dx=prev.x-p.x,dy=prev.y-p.y;
        angle=Math.atan2(dy,dx);
      }
      ctx.rotate(angle);
      if(!isHead){
        // connecting coupler
        ctx.fillStyle='#475b62';ctx.fillRect(-cell*.54,-cell*.045,cell*.16,cell*.09);
        // bright wagon
        const color=['#f6c85f','#56a8ce','#e98165','#69b88d','#aa8bc8'][(i-1)%5];
        roundedRect(-bodyW*.48,-bodyH*.39,bodyW*.88,bodyH*.78,cell*.15,color,'#ffffffaa');
        // windows / seat
        roundedRect(-bodyW*.25,-bodyH*.22,bodyW*.28,bodyH*.25,cell*.06,'#fff5d6');
        roundedRect(bodyW*.08,-bodyH*.22,bodyW*.25,bodyH*.25,cell*.06,'#fff5d6');
        ctx.fillStyle='#243d4b';
        ctx.beginPath();ctx.arc(-bodyW*.23,bodyH*.42,cell*.105,0,Math.PI*2);ctx.arc(bodyW*.22,bodyH*.42,cell*.105,0,Math.PI*2);ctx.fill();
        ctx.fillStyle='#e8eeee';ctx.beginPath();ctx.arc(-bodyW*.23,bodyH*.42,cell*.04,0,Math.PI*2);ctx.arc(bodyW*.22,bodyH*.42,cell*.04,0,Math.PI*2);ctx.fill();
        // tiny waving passenger
        if(i===1){
          ctx.fillStyle='#f3c49c';ctx.beginPath();ctx.arc(0,-bodyH*.12,cell*.09,0,Math.PI*2);ctx.fill();
          ctx.fillStyle='#273f4c';ctx.fillRect(-cell*.045,-bodyH*.08,cell*.09,cell*.18);
        }
      }else{
        // locomotive cab and boiler, oriented nose to the right
        ctx.fillStyle='#263d48';ctx.beginPath();ctx.arc(-cell*.2,cell*.31,cell*.13,0,Math.PI*2);ctx.arc(cell*.26,cell*.31,cell*.13,0,Math.PI*2);ctx.fill();
        ctx.fillStyle='#e9eeee';ctx.beginPath();ctx.arc(-cell*.2,cell*.31,cell*.05,0,Math.PI*2);ctx.arc(cell*.26,cell*.31,cell*.05,0,Math.PI*2);ctx.fill();
        roundedRect(-cell*.44,-cell*.19,cell*.75,cell*.48,cell*.14,'#e66856','#fff7df');
        roundedRect(-cell*.31,-cell*.5,cell*.43,cell*.38,cell*.1,'#d9574c','#fff7df');
        roundedRect(-cell*.23,-cell*.42,cell*.26,cell*.21,cell*.05,'#bde7ef');
        roundedRect(cell*.22,-cell*.1,cell*.31,cell*.2,cell*.06,'#f6c85f');
        roundedRect(cell*.38,-cell*.34,cell*.14,cell*.18,cell*.04,'#445966');
        ctx.fillStyle='#f6c85f';ctx.beginPath();ctx.arc(cell*.43,0,cell*.105,0,Math.PI*2);ctx.fill();ctx.strokeStyle='#fff3c8';ctx.lineWidth=2;ctx.stroke();
        // little steam puffs
        const puff=Math.sin(anim/200)*cell*.03;
        ctx.fillStyle='#ffffffaa';ctx.beginPath();ctx.arc(-cell*.14,-cell*.58-puff,cell*.09,0,Math.PI*2);ctx.arc(-cell*.29,-cell*.67-puff,cell*.065,0,Math.PI*2);ctx.fill();
      }
      ctx.restore();
    }
    // trackside flowers
    for(let x=cell*.5;x<w;x+=cell*2.7){
      const y=h-cell*.34;
      ctx.strokeStyle='#76a66f';ctx.lineWidth=2;ctx.beginPath();ctx.moveTo(x,y+cell*.15);ctx.lineTo(x,y-cell*.04);ctx.stroke();
      ctx.fillStyle=['#f7b86a','#e98ca1','#fff2c2'][Math.floor(x/cell)%3];
      ctx.beginPath();ctx.arc(x,y-cell*.07,cell*.07,0,Math.PI*2);ctx.fill();
    }
    // pause hint / small route marker
  }
  function loop(now){
    anim=now;
    if(started&&!paused&&now-lastStep>stepMs){step();lastStep=now}
    draw();requestAnimationFrame(loop);
  }
  window.addEventListener('keydown',key);
  board.addEventListener('pointerdown',()=>{if(!started||paused||gameOver)start()});
  document.querySelectorAll('.touch-controls button').forEach(btn=>btn.addEventListener('click',()=>setDirection(btn.dataset.dir)));
  window.addEventListener('resize',resize);
  resize();
  // self-playing demo: after the ready screen, the train cruises and seeks each passenger.
  function autopilot(){
    if(!started){autoTimer=setTimeout(autopilot,1100);return}
    if(!paused&&!gameOver&&passenger){
      const head=train[0], options=['right','down','left','up'];
      const candidates=options.map(d=>({d,x:head.x+dirs[d].x,y:head.y+dirs[d].y,dist:0}))
        .filter(a=>!(a.x<0||a.y<0||a.x>=cols||a.y>=rows))
        .filter(a=>!train.slice(0,-1).some(t=>t.x===a.x&&t.y===a.y))
        .filter(a=>{const c=dirs[dir];return !(dirs[a.d].x===-c.x&&dirs[a.d].y===-c.y)});
      candidates.forEach(a=>a.dist=Math.abs(a.x-passenger.x)+Math.abs(a.y-passenger.y));
      candidates.sort((a,b)=>a.dist-b.dist);
      if(candidates.length)nextDir=candidates[0].d;
    }
    autoTimer=setTimeout(autopilot,240);
  }
  autoTimer=setTimeout(autopilot,1300);
  requestAnimationFrame(loop);
})();
</script>
</body>
</html>