Models 44
Train snakeOne-line

GPT-6 Luna

by OpenAIReasoning1 console error
Open in new window

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

How it went

Total time
1 min 24 s
Cost
$0.0048
Output tokens
9,452
Spent thinking
2,854 tokens
Speed
123.9 tok/s
Console errors
1
First token after
8.1 s
First visible text after
42.5 s
Prompt tokens
361
Code size
18.6 KB
Finish reason
stop
Served by
OpenAI
Model id
openai/gpt-6-luna
Reasoning sent
{"effort":"medium"}
Max output
64,000 tokens
Generated
Nov 10, 2026

Console errors

Caught in the first 3 seconds after load, in a sandboxed iframe like the one above.

Unexpected token ':'

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 · 494 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 {
    color-scheme: dark;
    --ink: #edf7ee;
    --muted: #95aaa5;
    --lime: #c4f269;
    --panel: #112327;
  }
  * { box-sizing: border-box; }
  body {
    margin: 0;
    min-height: 100vh;
    padding: 20px 24px 24px;
    color: var(--ink);
    background:
      radial-gradient(ellipse at 49% -12%, rgba(59, 113, 86, .22), transparent 48%),
      #091518;
    font-family: ui-sans-serif, system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
  }
  .shell { max-width: 1080px; margin: 0 auto; }
  .topbar {
    height: 42px;
    display: flex;
    align-items: center;
    justify-content: space-between;
    margin-bottom: 15px;
  }
  .brand { display: flex; align-items: center; gap: 11px; }
  .brand-mark {
    width: 34px; height: 34px; border-radius: 11px;
    display: grid; place-items: center;
    color: #10201a; background: var(--lime);
    box-shadow: 0 0 24px rgba(196,242,105,.15);
    font-size: 19px;
  }
  .brand-name { font-size: 14px; font-weight: 800; letter-spacing: .14em; }
  .top-note { color: #829894; font-size: 11px; letter-spacing: .12em; text-transform: uppercase; }
  .game-card {
    overflow: hidden;
    border: 1px solid rgba(167, 209, 183, .13);
    border-radius: 18px;
    background: #0d1d20;
    box-shadow: 0 24px 80px rgba(0,0,0,.26), inset 0 1px rgba(255,255,255,.025);
  }
  .game-head {
    min-height: 62px;
    padding: 12px 20px;
    display: flex;
    align-items: center;
    justify-content: space-between;
    gap: 14px;
    background: linear-gradient(100deg, #14282a, #102124);
    border-bottom: 1px solid rgba(176,216,192,.1);
  }
  .title-group { display: flex; align-items: center; gap: 12px; }
  .eyebrow { color: var(--lime); font-size: 9px; font-weight: 800; letter-spacing: .2em; text-transform: uppercase; }
  h1 { margin: 2px 0 0; font-size: 19px; letter-spacing: -.035em; line-height: 1.1; }
  .stats { display: flex; align-items: center; gap: 9px; }
  .stat {
    min-width: 86px;
    padding: 7px 11px;
    border: 1px solid rgba(174,213,190,.12);
    border-radius: 9px;
    background: rgba(4,16,18,.3);
  }
  .stat-label { color: #839b94; font-size: 9px; letter-spacing: .12em; text-transform: uppercase; }
  .stat-value { margin-top: 1px; color: #f1f6eb; font-size: 15px; font-weight: 750; font-variant-numeric: tabular-nums; }
  .stat-value em { color: var(--lime); font-size: 11px; font-style: normal; font-weight: 600; }
  .board-wrap { position: relative; overflow: hidden; background: #102326; }
  canvas {
    width: 100%; height: auto; display: block;
    aspect-ratio: 25 / 14;
    cursor: pointer;
  }
  .hint {
    position: absolute; z-index: 2; top: 14px; left: 50%;
    transform: translateX(-50%);
    display: flex; align-items: center; gap: 9px;
    padding: 9px 14px;
    border: 1px solid rgba(203,232,196,.18);
    border-radius: 999px;
    background: rgba(8,23,24,.83);
    box-shadow: 0 7px 24px rgba(0,0,0,.2);
    color: #e5eee2;
    font-size: 11px; white-space: nowrap;
    backdrop-filter: blur(8px);
    pointer-events: none;
    transition: opacity .3s, transform .3s;
  }
  .hint .pulse {
    width: 7px; height: 7px; flex: 0 0 7px;
    border-radius: 50%; background: var(--lime);
    box-shadow: 0 0 10px rgba(196,242,105,.65);
  }
  .hint strong { color: var(--lime); font-size: 9px; letter-spacing: .12em; }
  .hint.hidden { opacity: 0; transform: translate(-50%, -7px); }
  .game-foot {
    min-height: 52px;
    display: flex; align-items: center; justify-content: space-between; gap: 14px;
    padding: 10px 20px;
    border-top: 1px solid rgba(176,216,192,.1);
    background: #102124;
  }
  .route-note { display: flex; align-items: center; gap: 9px; color: #9bad9f; font-size: 11px; }
  .route-note .star { color: #f6ca65; font-size: 15px; }
  .controls { color: #819691; font-size: 10px; text-align: right; }
  kbd {
    display: inline-block; min-width: 19px; padding: 2px 5px;
    margin: 0 1px;
    border: 1px solid rgba(202,225,208,.2); border-radius: 4px;
    color: #d8e5d9; background: rgba(255,255,255,.04);
    font: 10px ui-monospace, SFMono-Regular, Menlo, monospace;
    text-align: center;
  }
  @media (max-width: 600px) {
    body { padding: 12px 10px 18px; }
    .topbar { height: 36px; margin-bottom: 10px; }
    .brand-name { font-size: 12px; }
    .top-note { font-size: 8px; }
    .game-card { border-radius: 13px; }
    .game-head { min-height: 58px; padding: 10px 11px; }
    h1 { font-size: 16px; }
    .eyebrow { font-size: 8px; }
    .stats { gap: 5px; }
    .stat { min-width: 64px; padding: 6px 7px; }
    .stat-label { font-size: 8px; }
    .stat-value { font-size: 13px; }
    .game-foot { padding: 9px 11px; min-height: 48px; }
    .route-note { font-size: 10px; gap: 6px; }
    .controls { font-size: 9px; }
    .hint { top: 9px; gap: 6px; padding: 7px 10px; font-size: 9px; }
    .hint strong { font-size: 8px; }
  }
  @media (max-width: 390px) {
    .top-note { display: none; }
    .stat { min-width: 58px; }
    .controls { max-width: 145px; line-height: 1.8; }
  }
</style>
</head>
<body>
<div class="shell">
  <header class="topbar">
    <div class="brand">
      <div class="brand-mark" aria-hidden="true">✦</div>
      <div class="brand-name">LITTLE LINE GAMES</div>
    </div>
    <div class="top-note">A tiny trip with a big heart</div>
  </header>

  <main class="game-card">
    <div class="game-head">
      <div class="title-group">
        <div>
          <div class="eyebrow">The evening service</div>
          <h1>Platform Express</h1>
        </div>
      </div>
      <div class="stats">
        <div class="stat">
          <div class="stat-label">Passengers</div>
          <div class="stat-value" id="score">00 <em>aboard</em></div>
        </div>
        <div class="stat">
          <div class="stat-label">Train</div>
          <div class="stat-value" id="length">04 <em>cars</em></div>
        </div>
      </div>
    </div>

    <div class="board-wrap" id="boardWrap">
      <canvas id="game" width="1000" height="560" aria-label="A little train collecting passengers at the station"></canvas>
      <div class="hint" id="hint"><span class="pulse"></span><strong>LIVE DEMO</strong><span>Click or press a key to start driving</span></div>
    </div>

    <div class="game-foot">
      <div class="route-note"><span class="star">✦</span><span id="status">A friendly little train is on its way</span></div>
      <div class="controls">Drive with <kbd>↑</kbd><kbd>←</kbd><kbd>↓</kbd><kbd>→</kbd> or <kbd>W</kbd><kbd>A</kbd><kbd>S</kbd><kbd>D</kbd></div>
    </div>
  </main>
</div>

<script>
(() => {
  const canvas = document.getElementById('game');
  const ctx = canvas.getContext('2d');
  const W = 1000, H = 560, C = 40, COLS = 25, ROWS = 14;
  const scoreEl = document.getElementById('score');
  const lengthEl = document.getElementById('length');
  const statusEl = document.getElementById('status');
  const hint = document.getElementById('hint');

  const stations = [
    { x: 2, y: 1, w: 6, h: 4, name: 'FERNWOOD', color: '#81bd93' },
    { x: 17, y: 1, w: 6, h: 4, name: 'SUNNYBANK', color: '#e7bd69' },
    { x: 2, y: 9, w: 6, h: 4, name: 'MOSSY END', color: '#91b5d1' },
    { x: 17, y: 9, w: 6, h: 4, name: 'HONEY LANE', color: '#d99383' }
  ];
  const passengerSlots = [
    {x:3,y:4},{x:5,y:4},{x:7,y:4},{x:18,y:4},{x:20,y:4},{x:22,y:4},
    {x:3,y:10},{x:5,y:10},{x:7,y:10},{x:18,y:10},{x:20,y:10},{x:22,y:10}
  ];
  const passengerColors = ['#f2c66d','#ef8b78','#8dc9b0','#b7a1e2','#8ec9dc','#e8a9c9'];
  let passengers = [];
  let train = [];
  let dir = {x:1,y:0};
  let queuedDir = null;
  let score = 0, manual = false, steps = 0;
  let lastStep = 0;
  let animationFrame = 0;
  const wagonColors = ['#ef9b61','#79c7b0','#a794d9','#e87578','#86badd','#e5c35d'];
  const same = (a,b) => a.x === b.x && a.y === b.y;
  const wrap = n => (n + (n < 0 ? (n % (n === n ? COLS : ROWS) : 0)));
  function norm(p) { return {x:(p.x+COLS)%COLS, y:(p.y+ROWS)%ROWS}; }

  function freshGame() {
    train = [{x:12,y:7},{x:11,y:7},{x:10,y:7},{x:9,y:7}];
    dir = {x:1,y:0}; queuedDir = null; score = 0; steps = 0;
    passengers = [];
    const initial = [0,1,3,5,8];
    initial.forEach((slot, i) => passengers.push({ ...passengerSlots[slot], color: passengerColors[i % passengerColors.length], bob: Math.random()*6 }));
    updateStats();
  }
  function updateStats() {
    scoreEl.innerHTML = String(score).padStart(2,'0') + ' <em>aboard</em>';
    lengthEl.innerHTML = String(train.length).padStart(2,'0') + ' <em>cars</em>';
  }
  function spawnPassenger() {
    const open = passengerSlots.filter(s =>
      !passengers.some(p => same(p,s)) && !train.some(t => same(t,s))
    );
    if (!open.length) return;
    const p = open[Math.floor(Math.random()*open.length)];
    passengers.push({...p, color: passengerColors[Math.floor(Math.random()*passengerColors.length)], bob: Math.random()*6});
  }

  function aiDirection() {
    const head = train[0];
    const occupied = new Set(train.slice(0,-1).map(p => `${p.x},${p.y}`));
    const q = [head], visited = new Map([[`${head.x},${head.y}`, null]]);
    const dirs = [{x:1,y:0},{x:0,y:1},{x:-1,y:0},{x:0,y:-1}];
    let target = null;
    while (q.length) {
      const p = q.shift();
      if (passengers.some(s => same(s,p))) { target = p; break; }
      for (const d of dirs) {
        const n = norm({x:p.x+d.x,y:p.y+d.y});
        const key = `${n.x},${n.y}`;
        if (visited.has(key) || occupied.has(key)) continue;
        visited.set(key, {prev:`${p.x},${p.y}`, d});
        q.push(n);
      }
    }
    if (target && !same(target,head)) {
      let key = `${target.x},${target.y}`, item = visited.get(key);
      while (item && item.prev !== `${head.x},${head.y}`) {
        key = item.prev;
        item = visited.get(key);
      }
      if (item) return item.d;
    }
    const choices = dirs.filter(d => !(d.x === -dir.x && d.y === -dir.y));
    for (const d of choices) {
      const n = norm({x:head.x+d.x,y:head.y+d.y});
      if (!occupied.has(`${n.x},${n.y}`)) return d;
    }
    return dir;
  }

  function step() {
    const nextDir = manual ? (queuedDir || dir) : aiDirection();
    if (!(nextDir.x === -dir.x && nextDir.y === -dir.y)) dir = nextDir;
    queuedDir = null;
    const head = norm({x:train[0].x+dir.x,y:train[0].y+dir.y});
    const picked = passengers.findIndex(p => same(p,head));
    const tail = train[train.length-1];
    if (train.slice(0, picked >= 0 ? train.length : train.length-1).some(p => same(p,head))) {
      freshGame();
      if (manual) statusEl.textContent = 'Oops! Your train is ready for another little trip.';
      return;
    }
    train.unshift(head);
    if (picked >= 0) {
      passengers.splice(picked,1);
      score++;
      spawnPassenger();
      statusEl.textContent = score === 1 ? 'One happy passenger aboard!' : 'All aboard — your train is growing!';
    } else {
      train.pop();
    }
    steps++;
    updateStats();
  }

  function takeControl(event) {
    if (!manual) {
      manual = true;
      hint.classList.add('hidden');
      statusEl.textContent = 'Your turn to drive — bring everyone aboard!';
    }
    if (!event) return;
    const key = event.key.toLowerCase();
    const map = {
      arrowup:{x:0,y:-1}, w:{x:0,y:-1},
      arrowdown:{x:0,y:1}, s:{x:0,y:1},
      arrowleft:{x:-1,y:0}, a:{x:-1,y:0},
      arrowright:{x:1,y:0}, d:{x:1,y:0}
    };
    if (map[key]) {
      event.preventDefault();
      const d = map[key];
      if (!(d.x === -dir.x && d.y === -dir.y)) queuedDir = d;
    }
  }
  canvas.addEventListener('pointerdown', () => takeControl());
  window.addEventListener('keydown', takeControl);

  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 drawBackground() {
    ctx.fillStyle = '#12282a'; ctx.fillRect(0,0,W,H);
    const grad = ctx.createRadialGradient(500,270,50,500,270,620);
    grad.addColorStop(0,'rgba(53,91,73,.18)');
    grad.addColorStop(1,'rgba(3,15,17,.22)');
    ctx.fillStyle = grad; ctx.fillRect(0,0,W,H);

    // The faint rail-yard grid and sleepers
    ctx.strokeStyle = 'rgba(163,202,170,.055)';
    ctx.lineWidth = 1;
    for (let x=0; x<=W; x+=C) { ctx.beginPath(); ctx.moveTo(x,0); ctx.lineTo(x,H); ctx.stroke(); }
    for (let y=0; y<=H; y+=C) { ctx.beginPath(); ctx.moveTo(0,y); ctx.lineTo(W,y); ctx.stroke(); }

    // A little central stretch of track
    ctx.save();
    ctx.strokeStyle = 'rgba(125,162,134,.15)'; ctx.lineWidth = 2;
    ctx.beginPath(); ctx.moveTo(0,300); ctx.lineTo(W,300); ctx.stroke();
    ctx.beginPath(); ctx.moveTo(500,0); ctx.lineTo(500,H); ctx.stroke();
    ctx.strokeStyle = 'rgba(170,194,151,.11)'; ctx.lineWidth = 1;
    for (let x=10; x<W; x+=22) { ctx.beginPath(); ctx.moveTo(x,292); ctx.lineTo(x+8,308); ctx.stroke(); }
    for (let y=10; y<H; y+=22) { ctx.beginPath(); ctx.moveTo(492,y); ctx.lineTo(508,y+8); ctx.stroke(); }
    ctx.restore();

    // Quiet decorative yard lights
    [[420,125],[580,125],[420,435],[580,435]].forEach(([x,y],i) => {
      ctx.fillStyle = 'rgba(219,195,125,.08)';
      ctx.beginPath(); ctx.arc(x,y,3+(i%2),0,Math.PI*2); ctx.fill();
      ctx.beginPath(); ctx.arc(x,y,11,0,Math.PI*2); ctx.fillStyle = 'rgba(219,195,125,.025)'; ctx.fill();
    });
  }

  function drawStation(s, index) {
    const x=s.x*C, y=s.y*C, w=s.w*C, h=s.h*C;
    ctx.save();
    // drop shadow and platform body
    rounded(x+3,y+5,w,h,12,'rgba(0,0,0,.18)');
    rounded(x,y,w,h,12,'#29413b','rgba(197,218,173,.16)');
    rounded(x+5,y+5,w-10,h-10,9,'#314b42');
    // tile pattern
    ctx.strokeStyle='rgba(221,230,190,.075)'; ctx.lineWidth=1;
    for(let k=1;k<s.w-1;k++){
      ctx.beginPath(); ctx.moveTo(x+k*C,y+9); ctx.lineTo(x+k*C,y+h-9); ctx.stroke();
    }
    // tactile yellow platform edge
    ctx.fillStyle='rgba(239,199,103,.72)';
    for(let k=0;k<8;k++){
      rounded(x+12+k*27,y+h-10,13,2,1,'rgba(240,203,121,.58)');
    }
    // station nameplate
    rounded(x+11,y+10,Math.min(w-22,112),17,5,'rgba(11,26,26,.56)');
    ctx.fillStyle=s.color; ctx.font='700 8px ui-sans-serif, system-ui'; ctx.textBaseline='middle';
    ctx.fillText(s.name,x+18,y+18.5);
    // tiny bench
    rounded(x+w-42,y+14,23,4,2,'rgba(220,211,166,.35)');
    ctx.fillStyle='rgba(229,220,171,.35)';
    ctx.fillRect(x+w-40,y+18,2,7); ctx.fillRect(x+w-22,y+18,2,7);
    // platform lamps
    ctx.fillStyle='rgba(241,204,123,.82)';
    ctx.beginPath();ctx.arc(x+w-14,y+14,2,0,Math.PI*2);ctx.fill();
    ctx.restore();
  }

  function drawPassenger(p, i, time) {
    const cx=(p.x+.5)*C, cy=(p.y+.53)*C + Math.sin(time*.004+p.bob)*1.8;
    ctx.save();
    // little waiting shadow and carry-on
    ctx.fillStyle='rgba(4,14,14,.22)';
    ctx.beginPath();ctx.ellipse(cx,cy+10,8,3,0,0,Math.PI*2);ctx.fill();
    ctx.fillStyle='#d7b36e';
    rounded(cx+5,cy+2,6,8,2,'#d9ad61');
    ctx.fillStyle=p.color;
    ctx.beginPath();ctx.arc(cx,cy-6,4,0,Math.PI*2);ctx.fill();
    rounded(cx-4,cy-2,8,11,3,p.color);
    ctx.strokeStyle=p.color;ctx.lineWidth=2;ctx.lineCap='round';
    ctx.beginPath();ctx.moveTo(cx-2,cy+8);ctx.lineTo(cx-3,cy+11);ctx.moveTo(cx+2,cy+8);ctx.lineTo(cx+3,cy+11);ctx.stroke();
    // little scarf
    ctx.strokeStyle='rgba(255,244,205,.8)';ctx.lineWidth=1.5;
    ctx.beginPath();ctx.moveTo(cx-3,cy);ctx.lineTo(cx+4,cy+2);ctx.stroke();
    ctx.restore();
  }

  function drawTrain(time) {
    // connector links first
    for(let i=1;i<train.length;i++){
      const a=train[i-1], b=train[i];
      let dx=a.x-b.x, dy=a.y-b.y;
      if(dx>COLS/2) dx-=COLS; if(dx<-COLS/2) dx+=COLS;
      if(dy>ROWS/2) dy-=ROWS; if(dy<-ROWS/2) dy+=ROWS;
      const ax=(a.x+.5)*C, ay=(a.y+.5)*C, bx=(b.x+.5)*C, by=(b.y+.5)*C;
      ctx.strokeStyle='#c3a767'; ctx.lineWidth=3;
      ctx.beginPath();ctx.moveTo(ax-dx*10,ay-dy*10);ctx.lineTo(bx+dx*10,by+dy*10);ctx.stroke();
    }
    // wagons, back to front
    for(let i=train.length-1;i>=1;i--){
      const p=train[i], centerX=(p.x+.5)*C, centerY=(p.y+.5)*C;
      const prev=train[i-1];
      let dx=prev.x-p.x, dy=prev.y-p.y;
      if(dx>COLS/2)dx-=COLS;if(dx<-COLS/2)dx+=COLS;
      if(dy>ROWS/2)dy-=ROWS;if(dy<-ROWS/2)dy+=ROWS;
      const angle=Math.atan2(dy,dx);
      ctx.save();ctx.translate(centerX,centerY);ctx.rotate(angle);
      ctx.fillStyle='rgba(0,0,0,.24)';
      rounded(-16,-10+3,31,22,6,'rgba(0,0,0,.24)');
      // wheels
      ctx.fillStyle='#182421';
      [-10,10].forEach(x=>{ctx.beginPath();ctx.arc(x,10,3.3,0,Math.PI*2);ctx.fill();});
      rounded(-16,-11,32,21,6,wagonColors[(i-1)%wagonColors.length],'#f4d5a0');
      rounded(-8,-8,15,8,3,'rgba(255,246,202,.78)');
      ctx.fillStyle='rgba(32,52,43,.63)';
      ctx.fillRect(-1,-8,2,8);
      ctx.fillStyle='rgba(255,255,255,.22)';
      ctx.fillRect(-12,-9,18,2);
      // passenger's tiny waving window face
      ctx.fillStyle='#473e32';ctx.beginPath();ctx.arc(4,-4,1.4,0,Math.PI*2);ctx.fill();
      ctx.restore();
    }
    const h=train[0], angle=Math.atan2(dir.y,dir.x);
    const cx=(h.x+.5)*C, cy=(h.y+.5)*C;
    ctx.save();ctx.translate(cx,cy);ctx.rotate(angle);
    ctx.fillStyle='rgba(0,0,0,.28)';
    rounded(-17,-13,35,29,7,'rgba(0,0,0,.28)');
    // wheels
    ctx.fillStyle='#172321';
    [-10,10].forEach(x=>{ctx.beginPath();ctx.arc(x,11,4,0,Math.PI*2);ctx.fill();});
    // locomotive body
    rounded(-17,-13,29,27,6,'#e6a34f','#ffe0a1');
    // front cowcatcher / nose
    ctx.beginPath();ctx.moveTo(12,-10);ctx.lineTo(18,-6);ctx.lineTo(18,7);ctx.lineTo(12,11);ctx.closePath();
    ctx.fillStyle='#f3c46e';ctx.fill();ctx.strokeStyle='#ffe2a0';ctx.lineWidth=1;ctx.stroke();
    // cabin
    rounded(-12,-10,13,13,3,'#c97550','#f3c38a');
    rounded(-9,-8,7,7,2,'#a6d2be');
    // boiler and headlamp
    rounded(0,-7,13,14,5,'#d97951');
    ctx.fillStyle='#f3e6b6';ctx.beginPath();ctx.arc(15,0,2.7,0,Math.PI*2);ctx.fill();
    ctx.fillStyle='rgba(244,213,139,.18)';ctx.beginPath();ctx.arc(18,0,7,0,Math.PI*2);ctx.fill();
    // stack and steam
    rounded(2,-13,5,5,2,'#6c5946');
    ctx.fillStyle='rgba(228,239,211,.45)';
    ctx.beginPath();ctx.arc(-3,-16+Math.sin(time*.004)*2,3,0,Math.PI*2);ctx.fill();
    ctx.restore();
  }

  function draw(time) {
    drawBackground();
    stations.forEach(drawStation);
    passengers.forEach((p,i)=>drawPassenger(p,i,time));
    drawTrain(time);
    // soft board-edge vignette
    const v=ctx.createRadialGradient(500,280,240,500,280,650);
    v.addColorStop(0,'rgba(0,0,0,0)');
    v.addColorStop(1,'rgba(2,11,13,.28)');
    ctx.fillStyle=v;ctx.fillRect(0,0,W,H);
  }

  function loop(time) {
    if (time-lastStep > 230) { step(); lastStep=time; }
    draw(time);
    animationFrame=requestAnimationFrame(loop);
  }
  freshGame();
  requestAnimationFrame(loop);
})();
</script>
</body>
</html>
Reasoning trace (2,854 tokens)
**Designing a train layout**

I’m thinking about setting up a grid of 25x14. I want to ensure the rail lines are a bit curved for a more natural look. Each tile will represent the grid, and I’m visualizing platforms at rectangular blocks for passengers to wait. For pathfinding, I might use BFS, considering walls. I wonder if making platforms decorative could help with obstacles, so the train doesn't cross them easily. I’ll place passenger pickups at the adjacent track nodes.**Designing a train movement system**

I'm envisioning a game board with subtle rails where the train travels across a dark teal grid with decorative station platforms. The train will navigate using breadth-first search (BFS) to pick up passengers while avoiding crashing into itself, except its tail. If there’s no route available, I might need to consider safe options, perhaps with wrapped edges for easier movement. The train will grow longer with each passenger pickup, and I'll ensure it handles a 25x14 grid with randomized passenger spawn positions.**Designing train station visuals**

I'm visualizing a game layout with four stations at the cardinal points, where passengers wait just inside the platforms. Each station will have defined positions (x,y) around them. I should show a textured floor for the platforms, and the train will move across them, picking up passengers represented by colorful dots or icons. I want to spawn five unique passengers initially, and as each is picked up, a wagon will be added to the train. I also need a semi-transparent overlay message at the top of the canvas that invites user interaction while the game plays automatically.**Setting up control mechanics**

The user requested interactive controls, possibly using arrow keys or WASD for movement, with space to restart. I want to provide a start prompt that activates upon any key press or click. Initially, the demo will be AI-controlled, but after the first interaction, users can switch to manual control. I’ll display an overlay that disappears after the first action, labeling the HUD with "AUTO-PILOT" and "YOUR TURN." I should also consider mobile controls and ensure that the logic prevents reversing.**Visualizing train movement**

I'm considering drawing faint route lines for the train grid, like horizontal rails at y=7.5 and vertical at x=12.5. I'll use a dark stroke color for the rails and plan to depict a network that shows potential train movement. The tracks will align with grid midlines, and I want to ensure trains can move freely within this system. I’m also including stations with name tags and platforms, making sure to allow for passenger spots and adjust initial coordinates for the train's starting position.**Implementing movement strategies**

I'm figuring out how to implement self-collision avoidance for the train movement while keeping directions continuous. When updating, I will compute the target using a BFS grid wrap and ensure there’s no occupancy, except for the tail. If there's no target, I'll skip ahead. I must avoid looping back on the target or body and will compute paths based on the nearest Manhattan distance. I’ll ensure that the train moves in the chosen direction without reversing.**Analyzing train car orientation**

Train cars should be oriented in the direction of travel for consistency. I’m thinking about how to derive the orientation of each segment based on the previous one. The locomotive leads, and the body segments follow the movement direction. For passengers, I’ll draw small silhouettes, positioned circularly around the platform. Each passenger's spot will be marked, with defined grid dimensions of 25x14 for clarity, while designated slots will organize them neatly.**Designing the platform layout**

I'm laying out the platform dimensions, starting with the top-left at (2,1) with a width of 6 and height of 4. The upper right mirrors this. The bottom sections follow suit, creating a consistent design. I want to position passengers on the lower side with coordinates like (3,4) and (5,4). I'll incorporate a yellow-edged station floor and ensure the platform cells are well-defined. The design needs to be responsive at 375, including space for the HUD.**Designing layout parameters**

I'm thinking about how to set up my CSS page title and card layout. I want to use an emoji as a train icon for the header, so I won’t need any external images. The center width is 1120, and I’m considering a top bar. I might have a side panel at the top and a canvas beneath that. For a 1280x800 viewport, the header is 60 and the card heading 70, which makes the canvas height around 627. Hmmm, it all needs to fit within the viewport to avoid cropping.**Calculating layout dimensions**

I'm working on defining the aspect ratio for the board, which I need at 25/14, around 1.786. I'm aiming for a card width of 1100 and a canvas height of 616. When I add up the header, game header, canvas, and footer, it totals to 826. I think if I choose a narrower board width of 1050 and height of 588, I might avoid cropping in screenshots. I want to maximize dimensions while ensuring a dark palette and overall cohesive UI design with margins and headers.**Designing prompt interactions**

I'm thinking about adding a fixed prompt overlay at the center of the canvas that says something like "Click or press a key to start" in a transparent rounded rectangle. It might obscure the train, but that could be fine since the first screenshot is meant for demonstration purposes. I’ll consider placing a ribbon at the top and make sure the canvas listens for clicks and key presses. I want to make the message clear and satisfying, like "AUTOPILOT • click or press a key to take over" with "DEMO MODE" prominently displayed.**Considering game mechanics**

I’m thinking about how a manual failure could reset the train while maybe the score continues. If there's a crash message, the auto mode might reset afterward. Using no walls with wrap and allowing for self-collision sounds intriguing! Wrapping around the board edges should add fun, and I’d like to include station labels that glow, using canvas fonts. I need to define the roundRect support for Chrome, and it’s essential to get the output exactly right.