Models 44

Gemini 3.1 Flash Lite

by GoogleReasoningClean
Open in new window

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

How it went

Total time
8.6 s
Cost
$0.0054
Output tokens
3,484
Spent thinking
118 tokens
Speed
463.1 tok/s
Console errors
0
First token after
1.1 s
First visible text after
1.1 s
Prompt tokens
524
Code size
10.2 KB
Finish reason
stop
Served by
Google
Model id
google/gemini-3.1-flash-lite
Reasoning sent
{"effort":"low"}
Max output
65,536 tokens
Generated
Nov 12, 2026

What it was asked

The prompt
Build a polished Breakout (brick breaker) game in a single HTML file using vanilla JavaScript and a <canvas>. Requirements: - A paddle controlled with the mouse and with the left/right arrow keys. - The bounce angle off the paddle depends on where the ball hits it (center = straight up, edges = sharp angle). - One level with at least 6 rows of bricks, mixing normal bricks and tougher bricks that need 2 hits and visibly crack after the first one. - Some bricks visibly carry a power-up icon; when broken they drop it, and catching it with the paddle gives either a wider paddle (10 seconds) or multi-ball (3 balls). - The ball must never pass through bricks or the paddle. - Particles when a brick breaks. - 3 lives, score displayed. Game over and victory screens with a restart option.
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 · 328 lines

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Neon Breakout</title>
    <style>
        body {
            margin: 0;
            padding: 0;
            background: #0f0f13;
            color: #fff;
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            display: flex;
            justify-content: center;
            align-items: center;
            height: 100vh;
            overflow: hidden;
            user-select: none;
        }
        #game-container {
            position: relative;
            width: 100%;
            max-width: 800px;
            aspect-ratio: 4 / 3;
            box-shadow: 0 0 50px rgba(0,0,0,0.5);
            border: 2px solid #333;
            background: linear-gradient(to bottom, #1a1a2e, #16213e);
        }
        canvas {
            display: block;
            width: 100%;
            height: 100%;
            cursor: none;
        }
        #ui-layer {
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            pointer-events: none;
            display: flex;
            flex-direction: column;
            justify-content: center;
            align-items: center;
            text-align: center;
        }
        .message-box {
            background: rgba(0,0,0,0.8);
            padding: 20px 40px;
            border-radius: 10px;
            border: 2px solid #4ecca3;
            pointer-events: auto;
            cursor: pointer;
        }
        h1 { margin: 0 0 10px 0; color: #4ecca3; }
        .stats {
            position: absolute;
            top: 10px;
            left: 10px;
            font-size: 18px;
            color: #fff;
            pointer-events: none;
        }
    </style>
</head>
<body>

<div id="game-container">
    <div class="stats">Lives: <span id="lives">3</span> | Score: <span id="score">0</span></div>
    <canvas id="gameCanvas"></canvas>
    <div id="ui-layer">
        <div class="message-box" id="msg-box">
            <h1 id="msg-title">Neon Breakout</h1>
            <p id="msg-text">Click or Press any key to start</p>
        </div>
    </div>
</div>

<script>
    const canvas = document.getElementById('gameCanvas');
    const ctx = canvas.getContext('2d');
    const livesEl = document.getElementById('lives');
    const scoreEl = document.getElementById('score');
    const msgBox = document.getElementById('msg-box');
    const msgTitle = document.getElementById('msg-title');
    const msgText = document.getElementById('msg-text');

    // Resolution setup
    canvas.width = 800;
    canvas.height = 600;

    // Game state
    let gameRunning = false;
    let demoMode = true;
    let score = 0;
    let lives = 3;
    let paddle = { x: 350, w: 100, h: 20, dx: 0, speed: 8, baseW: 100 };
    let balls = [{ x: 400, y: 550, dx: 4, dy: -4, radius: 8, active: true }];
    let bricks = [];
    let particles = [];
    let powerups = [];
    let keys = { ArrowLeft: false, ArrowRight: false };

    // Config
    const BRICK_ROWS = 6;
    const BRICK_COLS = 10;
    const BRICK_H = 30;
    const BRICK_W = 70;
    const BRICK_PAD = 8;
    const OFFSET_X = (canvas.width - (BRICK_COLS * (BRICK_W + BRICK_PAD))) / 2 + BRICK_PAD/2;
    const OFFSET_Y = 60;

    // Initialize level
    function initBricks() {
        bricks = [];
        for (let r = 0; r < BRICK_ROWS; r++) {
            for (let c = 0; c < BRICK_COLS; c++) {
                let type = Math.random() > 0.8 ? 2 : 1; // 2 = tough, 1 = normal
                let hasPowerup = Math.random() > 0.85;
                bricks.push({
                    x: OFFSET_X + c * (BRICK_W + BRICK_PAD),
                    y: OFFSET_Y + r * (BRICK_H + BRICK_PAD),
                    w: BRICK_W,
                    h: BRICK_H,
                    type: type,
                    health: type,
                    hasPowerup: hasPowerup,
                    active: true
                });
            }
        }
    }

    // Input handlers
    window.addEventListener('keydown', (e) => { 
        if (!gameRunning) startGame();
        keys[e.key] = true; 
    });
    window.addEventListener('keyup', (e) => { keys[e.key] = false; });
    canvas.addEventListener('mousemove', (e) => {
        const rect = canvas.getBoundingClientRect();
        const mouseX = (e.clientX - rect.left) * (canvas.width / rect.width);
        paddle.x = mouseX - paddle.w / 2;
        if(paddle.x < 0) paddle.x = 0;
        if(paddle.x + paddle.w > canvas.width) paddle.x = canvas.width - paddle.w;
    });
    msgBox.addEventListener('click', startGame);

    function startGame() {
        if(gameRunning) return;
        gameRunning = true;
        demoMode = false;
        lives = 3;
        score = 0;
        updateStats();
        initBricks();
        balls = [{ x: 400, y: 550, dx: 4, dy: -4, radius: 8, active: true }];
        msgBox.style.display = 'none';
    }

    function gameOver(win) {
        gameRunning = false;
        demoMode = true;
        msgBox.style.display = 'block';
        msgTitle.innerText = win ? "VICTORY!" : "GAME OVER";
        msgText.innerText = "Score: " + score + ". Click to restart.";
    }

    function spawnParticles(x, y, color) {
        for(let i=0; i<8; i++) {
            particles.push({
                x, y, 
                vx: (Math.random() - 0.5) * 6,
                vy: (Math.random() - 0.5) * 6,
                life: 30,
                color
            });
        }
    }

    function updateStats() {
        livesEl.innerText = lives;
        scoreEl.innerText = score;
    }

    function update() {
        if (!gameRunning) return;

        // Paddle movement (Keyboard)
        if (keys.ArrowLeft) paddle.x -= paddle.speed;
        if (keys.ArrowRight) paddle.x += paddle.speed;
        paddle.x = Math.max(0, Math.min(canvas.width - paddle.w, paddle.x));

        // Demo AI
        if (demoMode && balls.length > 0) {
            let target = balls[0].x - paddle.w / 2;
            paddle.x += (target - paddle.x) * 0.1;
        }

        // Balls
        balls.forEach((ball, bIdx) => {
            if (!ball.active) return;
            ball.x += ball.dx;
            ball.y += ball.dy;

            // Walls
            if (ball.x - ball.radius < 0 || ball.x + ball.radius > canvas.width) ball.dx *= -1;
            if (ball.y - ball.radius < 0) ball.dy *= -1;
            
            // Floor
            if (ball.y + ball.radius > canvas.height) {
                ball.active = false;
            }

            // Paddle hit
            if (ball.y + ball.radius > canvas.height - 40 && ball.y < canvas.height - 20 &&
                ball.x > paddle.x && ball.x < paddle.x + paddle.w) {
                ball.dy = -Math.abs(ball.dy);
                let hitPoint = (ball.x - (paddle.x + paddle.w / 2)) / (paddle.w / 2);
                ball.dx = hitPoint * 8;
            }

            // Brick hit
            bricks.forEach(b => {
                if (b.active && ball.x > b.x && ball.x < b.x + b.w && ball.y > b.y && ball.y < b.y + b.h) {
                    ball.dy *= -1;
                    b.health--;
                    score += 10;
                    spawnParticles(b.x + b.w/2, b.y + b.h/2, b.type === 2 ? '#ff4d4d' : '#4ecca3');
                    if (b.health <= 0) {
                        b.active = false;
                        if(b.hasPowerup) powerups.push({ x: b.x + b.w/2, y: b.y + b.h/2, type: Math.random() > 0.5 ? 'wide' : 'multi', vy: 2 });
                    }
                    updateStats();
                }
            });
        });

        // Powerups
        powerups.forEach((p, i) => {
            p.y += p.vy;
            if(p.y > canvas.height) powerups.splice(i, 1);
            if(p.y > canvas.height - 40 && p.x > paddle.x && p.x < paddle.x + paddle.w) {
                if(p.type === 'wide') {
                    paddle.w = 160;
                    setTimeout(() => paddle.w = paddle.baseW, 10000);
                } else {
                    let b = balls[0];
                    balls.push({x: b.x, y: b.y, dx: -4, dy: -4, radius: 8, active: true});
                    balls.push({x: b.x, y: b.y, dx: 0, dy: -5, radius: 8, active: true});
                }
                powerups.splice(i, 1);
            }
        });

        balls = balls.filter(b => b.active);
        if (balls.length === 0) {
            lives--;
            updateStats();
            if (lives <= 0) gameOver(false);
            else balls = [{ x: 400, y: 550, dx: 4, dy: -4, radius: 8, active: true }];
        }
        if (bricks.filter(b => b.active).length === 0) gameOver(true);

        // Particles
        particles.forEach((p, i) => {
            p.x += p.vx; p.y += p.vy; p.life--;
            if(p.life <= 0) particles.splice(i, 1);
        });
    }

    function draw() {
        ctx.clearRect(0, 0, canvas.width, canvas.height);

        // Paddle
        ctx.fillStyle = '#4ecca3';
        ctx.shadowBlur = 10;
        ctx.shadowColor = '#4ecca3';
        ctx.fillRect(paddle.x, canvas.height - 40, paddle.w, paddle.h);
        ctx.shadowBlur = 0;

        // Bricks
        bricks.forEach(b => {
            if (!b.active) return;
            ctx.fillStyle = b.type === 2 ? (b.health === 2 ? '#ff4d4d' : '#8b0000') : '#4ecca3';
            ctx.fillRect(b.x, b.y, b.w, b.h);
            if(b.hasPowerup) {
                ctx.fillStyle = 'white';
                ctx.font = 'bold 12px Arial';
                ctx.fillText('+', b.x + 5, b.y + 20);
            }
        });

        // Balls
        ctx.fillStyle = 'white';
        balls.forEach(b => {
            ctx.beginPath();
            ctx.arc(b.x, b.y, b.radius, 0, Math.PI * 2);
            ctx.fill();
            ctx.closePath();
        });

        // Powerups
        powerups.forEach(p => {
            ctx.fillStyle = p.type === 'wide' ? '#f1c40f' : '#3498db';
            ctx.beginPath();
            ctx.arc(p.x, p.y, 8, 0, Math.PI * 2);
            ctx.fill();
        });

        // Particles
        particles.forEach(p => {
            ctx.fillStyle = p.color;
            ctx.fillRect(p.x, p.y, 4, 4);
        });

        requestAnimationFrame(() => {
            update();
            draw();
        });
    }

    draw();
</script>
</body>
</html>