Models 44

Gemma 4 31B

by Googlereasoning defaultClean
Open in new window

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

How it went

Total time
22.4 s
Cost
$0.0015
Output tokens
3,618
Spent thinking
0 tokens
Speed
164.4 tok/s
Console errors
0
First token after
377 ms
First visible text after
377 ms
Prompt tokens
526
Code size
12.4 KB
Finish reason
stop
Served by
NextBit
Model id
google/gemma-4-31b-it
Reasoning sent
model default
Max output
16,384 tokens
Generated
Nov 13, 2026

What it was asked

The prompt
Build a polished Snake game in a single HTML file using vanilla JavaScript and a <canvas>. Requirements: - A grid of at least 20×20 cells, centered on the page. - Arrow keys and WASD control the snake. Quick successive key presses must both be honored, but the snake can never reverse onto itself. - Eating food adds 10 points and grows the snake by one cell; new food never spawns on the snake. - Game over when the snake hits a wall or itself, with an overlay showing the score; Space or Enter restarts, P pauses. - Visual polish: smooth movement, a snake with a distinct head and eyes facing its direction, and a small particle burst when eating. - Display the current score and the best score of the session.
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 · 385 lines

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Neon Snake Pro</title>
    <style>
        :root {
            --bg-color: #0f172a;
            --grid-color: #1e293b;
            --snake-color: #4ade80;
            --snake-head: #22c55e;
            --food-color: #f87171;
            --text-color: #f8fafc;
            --accent-color: #38bdf8;
        }

        body {
            margin: 0;
            padding: 0;
            display: flex;
            flex-direction: column;
            align-items: center;
            justify-content: center;
            min-height: 100vh;
            background-color: var(--bg-color);
            color: var(--text-color);
            font-family: 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
            overflow: hidden;
        }

        #game-container {
            position: relative;
            box-shadow: 0 0 50px rgba(0, 0, 0, 0.5);
            border: 4px solid #334155;
            border-radius: 8px;
        }

        canvas {
            display: block;
            background-color: var(--bg-color);
        }

        #ui {
            position: absolute;
            top: -60px;
            left: 0;
            width: 100%;
            display: flex;
            justify-content: space-between;
            font-size: 20px;
            font-weight: bold;
            text-transform: uppercase;
            letter-spacing: 2px;
        }

        .overlay {
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background: rgba(15, 23, 42, 0.85);
            display: flex;
            flex-direction: column;
            align-items: center;
            justify-content: center;
            text-align: center;
            backdrop-filter: blur(4px);
            z-index: 10;
        }

        h1 { margin: 0 0 10px 0; color: var(--accent-color); font-size: 42px; }
        p { margin: 5px 0; font-size: 18px; }
        .btn-hint { 
            margin-top: 20px; 
            padding: 10px 20px; 
            background: var(--accent-color); 
            color: var(--bg-color); 
            border-radius: 5px; 
            font-weight: bold; 
            cursor: pointer;
        }

        .hidden { display: none !important; }
    </style>
</head>
<body>

    <div id="game-container">
        <div id="ui">
            <div>Score: <span id="score">0</span></div>
            <div>Best: <span id="best">0</span></div>
        </div>
        <canvas id="gameCanvas" width="600" height="600"></canvas>
        
        <div id="start-screen" class="overlay">
            <h1>NEON SNAKE</h1>
            <p>Use Arrow Keys or WASD to move</p>
            <p>P to Pause | Space to Start</p>
            <div class="btn-hint">CLICK TO START</div>
        </div>

        <div id="game-over-screen" class="overlay hidden">
            <h1 style="color: var(--food-color);">GAME OVER</h1>
            <p>Final Score: <span id="final-score">0</span></p>
            <p>Press SPACE or ENTER to Restart</p>
        </div>

        <div id="pause-screen" class="overlay hidden">
            <h1>PAUSED</h1>
            <p>Press P to Resume</p>
        </div>
    </div>

    <script>
        const canvas = document.getElementById('gameCanvas');
        const ctx = canvas.getContext('2d');
        const scoreEl = document.getElementById('score');
        const bestEl = document.getElementById('best');
        const finalScoreEl = document.getElementById('final-score');
        const startScreen = document.getElementById('start-screen');
        const gameOverScreen = document.getElementById('game-over-screen');
        const pauseScreen = document.getElementById('pause-screen');

        const GRID_SIZE = 20;
        const TILE_COUNT = canvas.width / GRID_SIZE;
        
        let score = 0;
        let bestScore = 0;
        let paused = false;
        let gameOver = true;
        let gameRunning = false;

        let snake = [];
        let food = { x: 0, y: 0 };
        let dx = 0;
        let dy = 0;
        
        // Input queue to handle rapid key presses
        let inputQueue = [];
        
        // Particles for eating effect
        let particles = [];

        function init() {
            score = 0;
            scoreEl.innerText = score;
            snake = [
                { x: 10, y: 10 },
                { x: 10, y: 11 },
                { x: 10, y: 12 }
            ];
            dx = 0;
            dy = -1;
            inputQueue = [];
            spawnFood();
            gameOver = false;
            gameRunning = true;
            startScreen.classList.add('hidden');
            gameOverScreen.classList.add('hidden');
            pauseScreen.classList.add('hidden');
        }

        function spawnFood() {
            food = {
                x: Math.floor(Math.random() * TILE_COUNT),
                y: Math.floor(Math.random() * TILE_COUNT)
            };
            // Ensure food doesn't spawn on snake
            for (let part of snake) {
                if (part.x === food.x && part.y === food.y) {
                    spawnFood();
                    break;
                }
            }
        }

        function handleInput(key) {
            const nowDir = { x: dx, y: dy };
            let nextDir = { x: dx, y: dy };

            if (key === 'ArrowUp' || key === 'w') nextDir = { x: 0, y: -1 };
            else if (key === 'ArrowDown' || key === 's') nextDir = { x: 0, y: 1 };
            else if (key === 'ArrowLeft' || key === 'a') nextDir = { x: -1, y: 0 };
            else if (key === 'ArrowRight' || key === 'd') nextDir = { x: 1, y: 0 };
            else return;

            // Prevent reversing
            if (nextDir.x === -nowDir.x && nextDir.y === -nowDir.y) return;
            
            // Queue the input if the last queued move isn't opposing
            let lastQueued = inputQueue.length > 0 ? inputQueue[inputQueue.length - 1] : nowDir;
            if (nextDir.x === -lastQueued.x && nextDir.y === -lastQueued.y) return;

            inputQueue.push(nextDir);
        }

        function createParticles(x, y) {
            for (let i = 0; i < 8; i++) {
                particles.push({
                    x: x * GRID_SIZE + GRID_SIZE/2,
                    y: y * GRID_SIZE + GRID_SIZE/2,
                    vx: (Math.random() - 0.5) * 4,
                    vy: (Math.random() - 0.5) * 4,
                    life: 1.0,
                    color: 'var(--food-color)'
                });
            }
        }

        function update() {
            if (gameOver || paused) return;

            // Process the input queue
            if (inputQueue.length > 0) {
                const nextMove = inputQueue.shift();
                dx = nextMove.x;
                dy = nextMove.y;
            }

            const head = { x: snake[0].x + dx, y: snake[0].y + dy };

            // Wall collision
            if (head.x < 0 || head.x >= TILE_COUNT || head.y < 0 || head.y >= TILE_COUNT) {
                endGame();
                return;
            }

            // Self collision
            for (let i = 0; i < snake.length; i++) {
                if (snake[i].x === head.x && snake[i].y === head.y) {
                    endGame();
                    return;
                }
            }

            snake.unshift(head);

            // Food collision
            if (head.x === food.x && head.y === food.y) {
                score += 10;
                scoreEl.innerText = score;
                createParticles(food.x, food.y);
                spawnFood();
            } else {
                snake.pop();
            }
        }

        function endGame() {
            gameOver = true;
            gameRunning = false;
            if (score > bestScore) {
                bestScore = score;
                bestEl.innerText = bestScore;
            }
            finalScoreEl.innerText = score;
            gameOverScreen.classList.remove('hidden');
        }

        function draw() {
            // Clear background
            ctx.fillStyle = '#0f172a';
            ctx.fillRect(0, 0, canvas.width, canvas.height);

            // Draw Grid
            ctx.strokeStyle = '#1e293b';
            ctx.lineWidth = 1;
            for (let i = 0; i <= TILE_COUNT; i++) {
                ctx.beginPath();
                ctx.moveTo(i * GRID_SIZE, 0);
                ctx.lineTo(i * GRID_SIZE, canvas.height);
                ctx.stroke();
                ctx.beginPath();
                ctx.moveTo(0, i * GRID_SIZE);
                ctx.lineTo(canvas.width, i * GRID_SIZE);
                ctx.stroke();
            }

            // Draw Food
            ctx.fillStyle = '#f87171';
            ctx.shadowBlur = 15;
            ctx.shadowColor = '#f87171';
            ctx.beginPath();
            ctx.arc(food.x * GRID_SIZE + GRID_SIZE/2, food.y * GRID_SIZE + GRID_SIZE/2, GRID_SIZE/2.5, 0, Math.PI * 2);
            ctx.fill();
            ctx.shadowBlur = 0;

            // Draw Snake
            snake.forEach((part, index) => {
                const isHead = index === 0;
                ctx.fillStyle = isHead ? '#22c55e' : '#4ade80';
                
                // Slightly rounded rectangles for snake
                const r = 4;
                const x = part.x * GRID_SIZE + 2;
                const y = part.y * GRID_SIZE + 2;
                const w = GRID_SIZE - 4;
                const h = GRID_SIZE - 4;
                
                ctx.beginPath();
                ctx.roundRect(x, y, w, h, 5);
                ctx.fill();

                if (isHead) {
                    // Eyes
                    ctx.fillStyle = 'white';
                    const eyeSize = 3;
                    let eyeX1, eyeY1, eyeX2, eyeY2;
                    
                    if (dx === 1) { // East
                        eyeX1 = x + w - 6; eyeY1 = y + 4;
                        eyeX2 = x + w - 6; eyeY2 = y + h - 6;
                    } else if (dx === -1) { // West
                        eyeX1 = x + 4; eyeY1 = y + 4;
                        eyeX2 = x + 4; eyeY2 = y + h - 6;
                    } else if (dy === -1) { // North
                        eyeX1 = x + 4; eyeY1 = y + 4;
                        eyeX2 = x + w - 6; eyeY2 = y + 4;
                    } else { // South
                        eyeX1 = x + 4; eyeY1 = y + h - 6;
                        eyeX2 = x + w - 6; eyeY2 = y + h - 6;
                    }
                    
                    ctx.fillRect(eyeX1, eyeY1, eyeSize, eyeSize);
                    ctx.fillRect(eyeX2, eyeY2, eyeSize, eyeSize);
                }
            });

            // Particles
            particles.forEach((p, i) => {
                p.x += p.vx;
                p.y += p.vy;
                p.life -= 0.02;
                ctx.fillStyle = `rgba(248, 113, 113, ${p.life})`;
                ctx.fillRect(p.x, p.y, 3, 3);
                if (p.life <= 0) particles.splice(i, 1);
            });
        }

        function gameLoop() {
            update();
            draw();
            setTimeout(gameLoop, 120);
        }

        // Input Handling
        window.addEventListener('keydown', (e) => {
            if (e.target === document.body || e.target === canvas) {
                if (e.key === 'p' || e.key === 'P') {
                    paused = !paused;
                    pauseScreen.classList.toggle('hidden', !paused);
                }
                if (e.key === ' ' || e.key === 'Enter') {
                    if (gameOver) init();
                }
                handleInput(e.key);
            }
        });

        canvas.addEventListener('click', () => {
            if (!gameRunning) init();
        });

        // Auto-play simulation for demo
        setInterval(() => {
            if (gameRunning && !paused && !gameOver) {
                // Simple AI: move towards food
                const head = snake[0];
                if (inputQueue.length === 0) {
                    if (head.x < food.x && dx !== -1) handleInput('ArrowRight');
                    else if (head.x > food.x && dx !== 1) handleInput('ArrowLeft');
                    else if (head.y < food.y && dy !== 1) handleInput('ArrowDown');
                    else if (head.y > food.y && dy !== -1) handleInput('ArrowUp');
                }
            }
        }, 200);

        // Init Best Score Display
        bestEl.innerText = bestScore;
        gameLoop();
    </script>
</body>
</html>