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.0 s
Cost
$0.0043
Output tokens
2,796
Spent thinking
492 tokens
Speed
421.6 tok/s
Console errors
0
First token after
1.4 s
First visible text after
2.3 s
Prompt tokens
524
Code size
6.4 KB
Finish reason
stop
Served by
Google
Model id
google/gemini-3.1-flash-lite
Reasoning sent
{"effort":"medium"}
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 · 154 lines

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Breakout Pro</title>
    <style>
        body { margin: 0; background: #111; color: white; font-family: sans-serif; display: flex; justify-content: center; align-items: center; height: 100vh; overflow: hidden; }
        #game-container { position: relative; width: 100vw; max-width: 800px; height: 600px; background: #000; border: 2px solid #333; cursor: none; }
        canvas { display: block; width: 100%; height: 100%; }
        #ui { position: absolute; top: 10px; left: 10px; pointer-events: none; font-size: 20px; text-shadow: 1px 1px 2px #000; }
        #overlay { position: absolute; top: 0; left: 0; width: 100%; height: 100%; background: rgba(0,0,0,0.7); display: flex; flex-direction: column; justify-content: center; align-items: center; z-index: 10; }
        button { padding: 15px 30px; font-size: 20px; cursor: pointer; background: #44f; color: white; border: none; border-radius: 5px; }
    </style>
</head>
<body>
    <div id="game-container">
        <div id="ui">Score: <span id="score">0</span> | Lives: <span id="lives">3</span></div>
        <div id="overlay">
            <h1 id="msg">BREAKOUT PRO</h1>
            <button onclick="startGame()">Click to Start</button>
        </div>
        <canvas id="game"></canvas>
    </div>

<script>
    const canvas = document.getElementById('game');
    const ctx = canvas.getContext('2d');
    canvas.width = 800; canvas.height = 600;

    let score = 0, lives = 3, gameActive = false, autoPlay = true;
    let paddle = { x: 350, w: 100, h: 15, speed: 8, dx: 0, powerupStart: 0 };
    let balls = [{ x: 400, y: 550, dx: 4, dy: -4, active: true }];
    let bricks = [], particles = [], powerups = [];

    function initLevel() {
        bricks = [];
        for(let r=0; r<6; r++) {
            for(let c=0; c<10; c++) {
                bricks.push({
                    x: c * 78 + 12, y: r * 30 + 50, w: 70, h: 20,
                    health: r > 3 ? 2 : 1, cracked: false,
                    powerup: Math.random() < 0.15 ? (Math.random() > 0.5 ? 'wide' : 'multi') : null
                });
            }
        }
    }

    function startGame() {
        gameActive = true; autoPlay = false;
        document.getElementById('overlay').style.display = 'none';
        initLevel();
        score = 0; lives = 3;
    }

    window.addEventListener('keydown', (e) => {
        if(autoPlay) startGame();
        if(e.key === 'ArrowLeft') paddle.dx = -15;
        if(e.key === 'ArrowRight') paddle.dx = 15;
    });
    window.addEventListener('keyup', () => paddle.dx = 0);
    canvas.addEventListener('mousemove', (e) => {
        if(!autoPlay) {
            const rect = canvas.getBoundingClientRect();
            paddle.x = (e.clientX - rect.left) / (rect.width / 800) - paddle.w/2;
        }
    });

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

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

        if(autoPlay) {
            paddle.x += (balls[0].x - (paddle.x + paddle.w/2)) * 0.1;
        } else {
            paddle.x = Math.max(0, Math.min(800 - paddle.w, paddle.x + paddle.dx));
        }

        if(Date.now() - paddle.powerupStart > 10000) paddle.w = 100;

        balls.forEach((b, bi) => {
            b.x += b.dx; b.y += b.dy;
            if(b.x < 0 || b.x > 800) b.dx *= -1;
            if(b.y < 0) b.dy *= -1;
            if(b.y > 600) {
                balls.splice(bi, 1);
                if(balls.length === 0) {
                    lives--;
                    if(lives > 0) balls.push({ x: 400, y: 550, dx: 4, dy: -4 });
                    else { gameActive = false; document.getElementById('overlay').style.display = 'flex'; document.getElementById('msg').innerText = "GAME OVER"; }
                }
            }

            // Paddle hit
            if(b.y + 8 > 570 && b.y < 585 && b.x > paddle.x && b.x < paddle.x + paddle.w) {
                let hitPoint = (b.x - (paddle.x + paddle.w/2)) / (paddle.w/2);
                b.dx = hitPoint * 8;
                b.dy = -Math.abs(b.dy);
            }

            // Bricks hit
            bricks.forEach((brick, i) => {
                if(b.x > brick.x && b.x < brick.x + brick.w && b.y > brick.y && b.y < brick.y + brick.h) {
                    b.dy *= -1;
                    if(brick.health > 1) { brick.health--; brick.cracked = true; } 
                    else {
                        if(brick.powerup) powerups.push({ x: brick.x, y: brick.y, type: brick.powerup });
                        spawnParticles(brick.x, brick.y, '#fff');
                        bricks.splice(i, 1);
                        score += 100;
                    }
                }
            });
        });

        powerups.forEach((p, i) => {
            p.y += 3;
            if(p.y > 570 && p.x > paddle.x && p.x < paddle.x + paddle.w) {
                if(p.type === 'wide') { paddle.w = 150; paddle.powerupStart = Date.now(); }
                else { balls.push({x: 400, y: 300, dx: -4, dy: 4}); }
                powerups.splice(i, 1);
            }
        });

        particles.forEach((p, i) => { p.x += p.vx; p.y += p.vy; p.life--; if(p.life < 0) particles.splice(i, 1); });
        
        document.getElementById('score').innerText = score;
        document.getElementById('lives').innerText = lives;
        if(bricks.length === 0) { gameActive = false; document.getElementById('overlay').style.display = 'flex'; document.getElementById('msg').innerText = "VICTORY!"; }
    }

    function draw() {
        ctx.fillStyle = '#000'; ctx.fillRect(0, 0, 800, 600);
        ctx.fillStyle = '#44f'; ctx.fillRect(paddle.x, 575, paddle.w, 15);
        
        balls.forEach(b => { ctx.fillStyle = '#fff'; ctx.beginPath(); ctx.arc(b.x, b.y, 8, 0, Math.PI*2); ctx.fill(); });
        
        bricks.forEach(b => {
            ctx.fillStyle = b.health > 1 ? '#888' : '#f44';
            ctx.fillRect(b.x, b.y, b.w, b.h);
            if(b.cracked) { ctx.strokeStyle = '#000'; ctx.strokeRect(b.x+2, b.y+2, b.w-4, b.h-4); }
        });
        
        powerups.forEach(p => { ctx.fillStyle = '#ff0'; ctx.fillRect(p.x, p.y, 10, 10); });
        particles.forEach(p => { ctx.fillStyle = p.color; ctx.fillRect(p.x, p.y, 3, 3); });
        requestAnimationFrame(() => { update(); draw(); });
    }
    initLevel(); draw();
</script>
</body>
</html>
Reasoning trace (492 tokens)
**Developing Game Elements**

I'm currently solidifying the core mechanics, focusing on the self-contained HTML canvas implementation. The paddle's responsiveness to both mouse and keyboard input is a priority, as is refining the ball's bounce angle based on impact. I'm also working on the distinct brick types and visual feedback for 2-hit bricks.

**Implementing Power-Ups**

My current focus is on integrating the power-up system. I'm refining the logic for the wider paddle effect and the multi-ball activation, ensuring a smooth and engaging player experience. The goal is to make these additions feel impactful and fun.