Models 44
Train snakeOne-line

GPT-5 Nano

by OpenAIReasoningClean
Open in new window

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

How it went

Total time
28.3 s
Cost
$0.0017
Output tokens
4,157
Spent thinking
320 tokens
Speed
160.1 tok/s
Console errors
0
First token after
2.3 s
First visible text after
6.0 s
Prompt tokens
361
Code size
12.2 KB
Finish reason
stop
Served by
OpenAI
Model id
openai/gpt-5-nano
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 · 441 lines

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Train Passengers — auto-playing Snake Train</title>
<style>
  :root{
    --bg: #0b1020;
    --platform: #2b2b2b;
    --passenger: #ffd166;
    --rail: #8e8e8e;
  }
  html,body{
    margin:0;
    height:100%;
    font-family: system-ui, -apple-system, "Segoe UI", Roboto, Arial;
    background: linear-gradient(#1a1a2e, #0b1020);
    color:white;
    overflow:hidden;
  }
  .wrap{
    display:flex;
    flex-direction:column;
    height:100%;
    width:100%;
  }
  header{
    padding:12px 16px;
    display:flex;
    align-items:center;
    justify-content:space-between;
    border-bottom:1px solid rgba(255,255,255,.08);
    background: rgba(0,0,0,.15);
    position: sticky;
    top:0;
    z-index:5;
  }
  .brand{ display:flex; align-items:center; gap:12px; }
  .brand .logo{
    width:28px; height:28px; border-radius:4px;
    background: conic-gradient(from 180deg at 50% 50%, #f44336, #ffeb3b, #4caf50, #2196f3, #9c27b0);
    box-shadow:0 0 12px rgba(255,255,255,.4);
  }
  .brand h1{ font-size:14px; margin:0; letter-spacing:.5px; }
  .brand small{ display:block; font-size:11px; opacity:.7; }
  .panel{ display:flex; align-items:center; gap:12px; }

  main{
    flex:1;
    display:flex;
    align-items:center;
    justify-content:center;
    padding:20px;
  }

  #stage{
    width: min(92vw, 900px);
    aspect-ratio: 16/9;
    background: #11152b;
    border-radius:14px;
    box-shadow: 0 20px 60px rgba(0,0,0,.4);
    position:relative;
    overflow:hidden;
  }

  canvas{ width:100%; height:100%; display:block; }

  /* Overlay message */
  .overlay{
    position:absolute; inset:0;
    display:flex; align-items:center; justify-content:center;
    background: rgba(0,0,0,.45);
    font-family: system-ui, sans-serif;
    text-align:center;
    padding:20px;
    pointer-events:auto;
  }
  .overlay .box{
    background: rgba(0,0,0,.65);
    border:1px solid rgba(255,255,255,.15);
    border-radius:12px;
    padding:22px 26px;
    max-width: 90%;
  }
  .overlay h2{ margin:0 0 8px; font-size:22px; }
  .overlay p{ margin:6px 0 0; font-size:14px; opacity:.9; }
  .btn{
    display:inline-block; padding:10px 14px; border-radius:8px;
    background:#3b82f6; color:white; font-weight:600;
    border:0; cursor:pointer; margin-top:12px;
  }
  .hint{ font-size:12px; opacity:.8; margin-top:6px; }

  @media (max-width: 700px){
    #stage{ aspect-ratio: 1/1; }
  }
</style>
</head>
<body>
<div class="wrap">
  <header>
    <div class="brand">
      <div class="logo" aria-label="Train logo"></div>
      <div>
        <h1>Train Passengers — Auto Train</h1>
        <small>A colorful locomotive and wagons collect passengers on the platform</small>
      </div>
    </div>
    <div class="panel" aria-label="Status panel">
      <span style="opacity:.8;font-size:12px" id="statusLabel">Status: Waiting</span>
    </div>
  </header>

  <main>
    <section id="stage" aria-label="Playfield">
      <canvas id="cv" width="900" height="506"></canvas>
      <div id="overlay" class="overlay" style="display:flex">
        <div class="box">
          <h2>Click or press a key to start</h2>
          <p>Watch the train pick up passengers on the platform. The locomotive leads colorful wagons. AI guides the train to the passengers.</p>
          <button class="btn" id="startBtn">Start</button>
          <div class="hint">Tip: It’s all in auto-play for this demo.</div>
        </div>
      </div>
    </section>
  </main>
</div>

<script>
(() => {
  // Grid config
  const COLS = 26;
  const ROWS = 18;
  const BASE_CELL = 28; // base px, scaled by canvas size

  const canvas = document.getElementById('cv');
  const ctx = canvas.getContext('2d');
  const overlay = document.getElementById('overlay');
  const startBtn = document.getElementById('startBtn');
  const statusLabel = document.getElementById('statusLabel');

  let w = 900, h = 506;
  let cellW = 10, cellH = 10;
  let running = false;
  let started = false;
  let tick = null;

  // Train representation: locomotive (head) + wagons
  // Each piece is {x,y,color,kind} where kind: 'locomotive'|'wagon'
  let train = [];
  let direction = {x:1, y:0}; // initial move right
  let nextDirection = {x:1, y:0};

  // Passengers on platform (targets)
  let passengers = [];

  // Color palette for wagons
  const wagonColors = ['#FF6B6B','#FFD166','#6BCB77','#4D96FF','#C77DFF','#FF9F1C','#6DE1FF'];

  // AI: simple greedy toward nearest passenger avoiding collision with self
  function aiNextDir(head) {
    // If there are no passengers, wander right
    if (passengers.length === 0) {
      return {x:1, y:0};
    }

    // Find nearest passenger by Manhattan distance
    let nearest = null, bestD = Infinity;
    for (const p of passengers) {
      const d = Math.abs(p.x - head.x) + Math.abs(p.y - head.y);
      if (d < bestD) { bestD = d; nearest = p; }
    }

    // Prefer horizontal move toward target, then vertical
    let cand = [];
    if (nearest) {
      if (nearest.x > head.x) cand.push({x:1,y:0});
      if (nearest.x < head.x) cand.push({x:-1,y:0});
      if (nearest.y > head.y) cand.push({x:0,y:1});
      if (nearest.y < head.y) cand.push({x:0,y:-1});
    }

    // Add common safe directions to avoid dead ends
    const dirs = [{x:1,y:0},{x:-1,y:0},{x:0,y:1},{x:0,y:-1}];
    // Try preferred cand first
    for (const d of cand) {
      if (isSafeMove(d, head)) return d;
    }
    // Fallback: pick any safe direction that's not reversing
    for (const d of dirs) {
      if (!((d.x === -direction.x) && (d.y === -direction.y)) && isSafeMove(d, head)) {
        return d;
      }
    }
    // If blocked, stay (will be caught as end game in a robust version)
    return {x:0,y:0};
  }

  function isSafeMove(dir, head) {
    const nx = head.x + dir.x;
    const ny = head.y + dir.y;
    // bounds
    if (nx < 0 || ny < 0 || nx >= COLS || ny >= ROWS) return false;
    // self-collision
    for (const seg of train) {
      if (seg.x === nx && seg.y === ny) return false;
    }
    return true;
  }

  function spawnPassenger() {
    // place on a grid cell not occupied by train
    let tries = 0;
    while (tries < 100) {
      const x = Math.floor(Math.random() * COLS);
      const y = Math.floor(Math.random() * ROWS);
      if (!train.some(s => s.x===x && s.y===y)) {
        // also avoid platform edges? We'll allow anywhere
        passengers.push({x,y});
        return;
      }
      tries++;
    }
  }

  function resetGame() {
    // Init train in middle
    const midx = Math.floor(COLS/4);
    const midy = Math.floor(ROWS/2);
    train = [
      {x: midx, y: midy, color: '#111', kind:'locomotive'},
      {x: midx-1, y: midy, color: wagonColors[0], kind:'wagon'},
      {x: midx-2, y: midy, color: wagonColors[1], kind:'wagon'}
    ];
    direction = {x:1, y:0};
    nextDirection = {x:1, y:0};
    passengers = [];
    // spawn a few passengers
    for (let i=0;i<5;i++) spawnPassenger();

    // reset timer
    running = true;
    started = true;
    overlay.style.display = 'none';
    statusLabel.textContent = 'Status: Running';
  }

  // Resize handler
  function resize() {
    const rect = canvas.getBoundingClientRect();
    // compute cell size to fit
    // maintain aspect ratio roughly to grid
    const stageW = rect.width;
    const stageH = rect.height;
    const cw = Math.floor(stageW / COLS);
    const ch = Math.floor(stageH / ROWS);
    cellW = Math.max(8, Math.min(cw, ch)); // sane min
    cellH = cellW;
    // update canvas pixel size
    const pxW = cellW * COLS;
    const pxH = cellH * ROWS;
    canvas.style.width = pxW + 'px';
    canvas.style.height = pxH + 'px';
    canvas.width = pxW;
    canvas.height = pxH;
  }

  // Drawing helpers
  function drawGridBG() {
    // background with platform/rails look
    ctx.fillStyle = '#0a0e1a';
    ctx.fillRect(0,0,canvas.width, canvas.height);
    // subtle platform stripe
    for (let y=0; y<ROWS; y++) {
      for (let x=0; x<COLS; x++) {
        const isPlatform = (y === ROWS-2) || (y === ROWS-3);
        if (isPlatform) {
          ctx.fillStyle = ( (x+y) % 2 ? '#1a1a2e' : '#1a1a2e' );
          ctx.fillRect(x*cellW, y*cellH, cellW, cellH);
        }
      }
    }
    // rails line near bottom
    ctx.fillStyle = '#2b2b2b';
    for (let x=0; x<COLS; x++) {
      ctx.fillRect(x*cellW, (ROWS-2)*cellH, cellW, cellH);
    }
  }

  function drawPassengers() {
    for (const p of passengers) {
      const px = p.x * cellW;
      const py = p.y * cellH;
      ctx.fillStyle = '#ffd166';
      ctx.fillRect(px+4, py+4, cellW-8, cellH-8);
      // little seat symbol
      ctx.fillStyle = '#e0a800';
      ctx.fillRect(px+cellW/2-2, py+8, 4, cellH-16);
    }
  }

  function drawTrain() {
    // draw tail wagons as connected rectangles
    for (let i = 0; i < train.length; i++) {
      const seg = train[i];
      const px = seg.x * cellW;
      const py = seg.y * cellH;
      if (i === 0) {
        // locomotive head
        ctx.fillStyle = '#1a1a1a';
        ctx.fillRect(px, py, cellW, cellH);
        // cabin highlight
        ctx.fillStyle = '#ff5555';
        ctx.fillRect(px+2, py+2, cellW-4, cellH-4);
        // chimney
        ctx.fillStyle = '#333';
        ctx.fillRect(px+6, py-4, 6, 6);
        // wheel dots
        ctx.fillStyle = '#222';
        ctx.fillRect(px+6, py+cellH-6, 6, 4);
        ctx.fillRect(px+cellW-12, py+cellH-6, 6, 4);
      } else {
        ctx.fillStyle = seg.color;
        ctx.fillRect(px, py, cellW, cellH);
      }
    }

    // draw coupling lines for wagons
    ctx.strokeStyle = '#666';
    ctx.lineWidth = 2;
    for (let i=0; i<train.length-1; i++) {
      const a = train[i], b = train[i+1];
      const ax = a.x*cellW + cellW/2;
      const ay = a.y*cellH + cellH/2;
      const bx = b.x*cellW + cellW/2;
      const by = b.y*cellH + cellH/2;
      ctx.beginPath();
      ctx.moveTo(ax, ay);
      ctx.lineTo(bx, by);
      ctx.stroke();
    }
  }

  function draw() {
    drawGridBG();
    drawPassengers();
    drawTrain();
  }

  // Game loop
  function step() {
    // compute next direction
    const head = train[0];
    const nd = aiNextDir({x: head.x, y: head.y});
    // ensure not reversing into the second segment
    if (!((nd.x === -direction.x) && (nd.y === -direction.y))) {
      nextDirection = nd;
    }

    // move head
    const newHead = { x: head.x + nextDirection.x, y: head.y + nextDirection.y };
    // wrap or end? We'll end on bounds to be safer
    if (newHead.x < 0 || newHead.y < 0 || newHead.x >= COLS || newHead.y >= ROWS) {
      // reset game on boundary collision
      statusLabel.textContent = 'Status: Collision with boundary — restarting';
      resetGame();
      return;
    }

    // insert new head
    train.unshift(newHead);

    // check passenger pickup
    const pickedIndex = passengers.findIndex(p => p.x === newHead.x && p.y === newHead.y);
    if (pickedIndex >= 0) {
      // grow by not removing tail, and spawn new passenger
      passengers.splice(pickedIndex, 1);
      spawnPassenger();
    } else {
      // normal move: remove tail
      train.pop();
    }

    // keep colors for wagons (the wagons retain their color order, locomotive is dark)
    // ensure wagons exist
    // set wagon colors for existing wagons if missing
    for (let i=1; i<train.length; i++){
      if (!train[i].color) {
        train[i].color = wagonColors[(i-1) % wagonColors.length];
      }
    }

    direction = {x: nextDirection.x, y: nextDirection.y};
    // redraw
    draw();

    // schedule next
    if (running) tick = setTimeout(step, 140);
  }

  // Start interaction
  function init() {
    resize();
    // initial render
    resetGame();
    draw();
    // set up timer after a tiny delay to render first frame
    setTimeout(() => { draw(); }, 0);
  }

  window.addEventListener('resize', () => {
    resize();
    // redraw after resize
    draw();
  });

  // Start on click or keypress
  function startAuto() {
    if (started) return;
    resetGame();
    // begin loop
    started = true;
    overlay.style.display = 'none';
    statusLabel.textContent = 'Status: Running';
    if (tick) clearTimeout(tick);
    tick = setTimeout(step, 150);
  }

  startBtn.addEventListener('click', startAuto);
  window.addEventListener('keydown', (e) => {
    // any key to start
    if (!started) startAuto();
  }, { passive: true });

  // Init stage
  init();
})();
</script>
</body>
</html>
Reasoning trace (320 tokens)
**Designing a Snake Train Game**

I’m thinking about creating a single HTML file for a snake-like train game that features a colorful locomotive with wagons and passengers on a platform. The game will auto-play with the AI controlling the train's movement, and there will be a start screen that says "Click or press a key to start." I want to implement simple grid-based movement on a 25x18 grid, where the train grows as it picks up passengers, with animations and inline CSS and JS. Let's keep it responsive and self-contained!**Planning Train Game Features**

I need to consider a screenshot feature that captures the screen automatically about three seconds after loading, even though we can't technically implement a screenshot. Instead, I'll make sure something is visible on the first paint. I'll craft the code with a responsive canvas size, calculating the cell size based on the canvas dimensions. The game will have a grid of 26x18, with the locomotive as the head represented in black and red, while the wagons will be colorful. 

For movement, I'll implement an AI to navigate towards the nearest passenger while avoiding obstacles, using a simple BFS-like pathfinding approach. I want to ensure smooth gameplay that starts upon clicking. Let's get this going!