Train snakeOne-line
GPT-5 Nano
by OpenAIReasoningClean
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!