Models 44

Gemma 4 31B

by Googlereasoning default1 console error
Open in new window

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

How it went

Total time
1 min 1 s
Cost
$0.0017
Output tokens
4,961
Spent thinking
0 tokens
Speed
82.4 tok/s
Console errors
1
First token after
444 ms
First visible text after
444 ms
Prompt tokens
542
Code size
15.4 KB
Finish reason
stop
Served by
CoreWeave
Model id
google/gemma-4-31b-it
Reasoning sent
model default
Max output
16,384 tokens
Generated
Nov 13, 2026

Console errors

Caught in the first 3 seconds after load, in a sandboxed iframe like the one above.

Unexpected identifier 'loop'

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 · 516 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;
            background: #0a0a0f;
            color: #fff;
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            display: flex;
            flex-direction: column;
            align-items: center;
            justify-content: center;
            height: 100vh;
            overflow: hidden;
        }
        #game-container {
            position: relative;
            box-shadow: 0 0 50px rgba(0, 183, 255, 0.3);
            border: 4px solid #333;
            border-radius: 8px;
        }
        canvas {
            display: block;
            background: #000;
            cursor: none;
        }
        #ui-layer {
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            pointer-events: none;
            display: flex;
            flex-direction: column;
            align-items: center;
            justify-content: center;
            text-align: center;
        }
        .screen {
            display: none;
            background: rgba(0, 0, 0, 0.8);
            padding: 2rem;
            border-radius: 15px;
            border: 2px solid #00b7ff;
            pointer-events: auto;
        }
        .screen.active { display: block; }
        h1 { color: #00b7ff; margin-top: 0; text-transform: uppercase; letter-spacing: 5px; }
        p { margin-bottom: 1.5rem; }
        button {
            padding: 12px 30px;
            font-size: 1.2rem;
            background: #00b7ff;
            border: none;
            color: white;
            cursor: pointer;
            border-radius: 5px;
            transition: 0.2s;
            font-weight: bold;
        }
        button:hover { background: #0088cc; transform: scale(1.05); }
        #stats {
            position: absolute;
            top: 10px;
            left: 10px;
            right: 10px;
            display: flex;
            justify-content: space-between;
            font-family: monospace;
            font-size: 20px;
            pointer-events: none;
            color: #00b7ff;
            text-shadow: 0 0 5px #00b7ff;
        }
        #overlay-msg {
            position: absolute;
            bottom: 20px;
            width: 100%;
            text-align: center;
            color: #666;
            font-size: 14px;
            pointer-events: none;
        }
    </style>
</head>
<body>

    <div id="game-container">
        <canvas id="gameCanvas"></canvas>
        <div id="stats">
            <div id="score">Score: 0</div>
            <div id="lives">Lives: 3</div>
        </div>
        <div id="ui-layer">
            <div id="start-screen" class="screen active">
                <h1>NEON BREAKOUT</h1>
                <p>Break all bricks to win!<br>Mouse or Arrow Keys to move.</p>
                <button onclick="game.start()">START GAME</button>
            </div>
            <div id="game-over-screen" class="screen">
                <h1 style="color: #ff4444;">GAME OVER</h1>
                <p id="final-score"></p>
                <button onclick="game.restart()">TRY AGAIN</button>
            </div>
            <div id="victory-screen" class="screen">
                <h1 style="color: #44ff44;">VICTORY!</h1>
                <p>You cleared the board!</p>
                <button onclick="game.restart()">PLAY AGAIN</button>
            </div>
        </div>
        <div id="overlay-msg">Click to enable controls</div>
    </div>

<script>
const canvas = document.getElementById('gameCanvas');
const ctx = canvas.getContext('2d');
const scoreEl = document.getElementById('score');
const livesEl = document.getElementById('lives');

// Configuration
const WIDTH = 800;
const HEIGHT = 600;
canvas.width = WIDTH;
canvas.height = HEIGHT;

const BRICK_ROWS = 6;
const BRICK_COLS = 10;
const BRICK_PADDING = 10;
const BRICK_OFFSET_TOP = 60;
const BRICK_OFFSET_LEFT = 35;
const PADDLE_HEIGHT = 15;
const PADDLE_WIDTH = 100;
const BALL_RADIUS = 7;
const BALL_SPEED = 4.5;

const COLORS = {
    row1: '#00f2ff', // Cyan
    row2: '#00aaff', // Blue
    row3: '#7d00ff', // Purple
    row4: '#ff00ff', // Magenta
    row5: '#ffaa00', // Orange
    row6: '#ff4444', // Red
    tough: '#555555'  // Dark Gray for cracked
};

class Ball {
    constructor(x, y, dx = 0, dy = 0) {
        this.x = x;
        this.y = y;
        this.dx = dx;
        this.dy = dy;
        this.radius = BALL_RADIUS;
    }

    update() {
        this.x += this.dx;
        this.y += this.dy;

        // Walls
        if (this.x + this.radius > WIDTH || this.x - this.radius < 0) this.dx *= -1;
        if (this.y - this.radius < 0) this.dy *= -1;
    }

    draw() {
        ctx.beginPath();
        ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2);
        ctx.fillStyle = '#fff';
        ctx.fill();
        ctx.closePath();
        // Glow
        ctx.shadowBlur = 10;
        ctx.shadowColor = '#fff';
    }
}

class Paddle {
    constructor() {
        this.width = PADDLE_WIDTH;
        this.height = PADDLE_HEIGHT;
        this.x = (WIDTH - this.width) / 2;
        this.y = HEIGHT - 30;
        this.targetWidth = PADDLE_WIDTH;
        this.powerupTimer = 0;
    }

    update(mouseX) {
        if (mouseX !== undefined) {
            this.x = mouseX - this.width / 2;
        }
        
        // Bounds
        if (this.x < 0) this.x = 0;
        if (this.x + this.width > WIDTH) this.x = WIDTH - this.width;

        // Handle Powerup scaling
        if (this.powerupTimer > 0) {
            this.powerupTimer--;
            if (this.powerupTimer <= 0) this.width = PADDLE_WIDTH;
        }
    }

    draw() {
        ctx.shadowBlur = 15;
        ctx.shadowColor = '#00b7ff';
        ctx.fillStyle = '#00b7ff';
        ctx.beginPath();
        ctx.roundRect(this.x, this.y, this.width, this.height, 5);
        ctx.fill();
        ctx.closePath();
        ctx.shadowBlur = 0;
    }
}

class Brick {
    constructor(x, y, col, row) {
        this.x = x;
        this.y = y;
        this.w = (WIDTH - (BRICK_OFFSET_LEFT * 2)) / BRICK_COLS - BRICK_PADDING;
        this.h = 20;
        this.hp = (row < 3) ? 2 : 1; // Top 3 rows are tough
        this.maxHp = this.hp;
        this.color = COLORS[`row${row + 1}`] || '#fff';
        this.powerup = Math.random() < 0.15 ? (Math.random() < 0.5 ? 'WIDE' : 'MULTI') : null;
        this.active = true;
    }

    draw() {
        if (!this.active) return;
        
        ctx.shadowBlur = 0;
        ctx.fillStyle = this.hp === 2 ? this.color : (this.hp === 1 && this.maxHp === 2 ? COLORS.tough : this.color);
        
        // Draw brick body
        ctx.beginPath();
        ctx.roundRect(this.x, this.y, this.w, this.h, 3);
        ctx.fill();
        ctx.closePath();

        // Draw "crack" if damaged
        if (this.maxHp === 2 && this.hp === 1) {
            ctx.strokeStyle = '#000';
            ctx.lineWidth = 2;
            ctx.beginPath();
            ctx.moveTo(this.x + 5, this.y + 2);
            ctx.lineTo(this.x + 15, this.y + 10);
            ctx.lineTo(this.x + 10, this.y + 18);
            ctx.stroke();
        }

        // Draw powerup icon
        if (this.powerup && this.hp === this.maxHp) {
            ctx.fillStyle = 'white';
            ctx.font = '10px Arial';
            ctx.textAlign = 'center';
            ctx.fillText(this.powerup === 'WIDE' ? '↔' : '●●', this.x + this.w / 2, this.y + 14);
        }
    }
}

class PowerUp {
    constructor(x, y, type) {
        this.x = x;
        this.y = y;
        this.type = type;
        this.r = 8;
        this.dy = 2;
    }

    update() {
        this.y += this.dy;
    }

    draw() {
        ctx.shadowBlur = 10;
        ctx.shadowColor = this.type === 'WIDE' ? '#00ff00' : '#ffff00';
        ctx.fillStyle = ctx.shadowColor;
        ctx.beginPath();
        ctx.arc(this.x, this.y, this.r, 0, Math.PI * 2);
        ctx.fill();
        ctx.closePath();
        ctx.shadowBlur = 0;
    }
}

class Particle {
    constructor(x, y, color) {
        this.x = x;
        this.y = y;
        this.color = color;
        this.dx = (Math.random() - 0.5) * 6;
        this.dy = (Math.random() - 0.5) * 6;
        this.life = 1.0;
    }
    update() {
        this.x += this.dx;
        this.y += this.dy;
        this.life -= 0.03;
    }
    draw() {
        ctx.globalAlpha = this.life;
        ctx.fillStyle = this.color;
        ctx.fillRect(this.x, this.y, 3, 3);
        ctx.globalAlpha = 1.0;
    }
}

const game = {
    running: false,
    score: 0,
    lives: 3,
    paddle: new Paddle(),
    balls: [],
    bricks: [],
    powerups: [],
    particles: [],
    mouseX: WIDTH / 2,
    keys: {},

    init() {
        window.addEventListener('mousemove', (e) => {
            const rect = canvas.getBoundingClientRect();
            this.mouseX = e.clientX - rect.left;
        });
        window.addEventListener('keydown', (e) => this.keys[e.code] = true);
        window.addEventListener('keyup', (e) => this.keys[e.code] = false);
        
        this.loop();
    },

    start() {
        this.score = 0;
        this.lives = 3;
        this.running = true;
        this.balls = [new Ball(WIDTH / 2, HEIGHT - 50, BALL_SPEED * (Math.random() > 0.5 ? 1 : -1), -BALL_SPEED)];
        this.bricks = [];
        this.powerups = [];
        this.particles = [];
        
        for (let r = 0; r < BRICK_ROWS; r++) {
            for (let c = 0; c < BRICK_COLS; c++) {
                const bx = BRICK_OFFSET_LEFT + c * ( (WIDTH - (BRICK_OFFSET_LEFT * 2)) / BRICK_COLS );
                const by = BRICK_OFFSET_TOP + r * (20 + BRICK_PADDING);
                this.bricks.push(new Brick(bx, by, c, r));
            }
        }

        document.querySelectorAll('.screen').forEach(s => s.classList.remove('active'));
        this.updateUI();
    },

    restart() {
        this.start();
    },

    gameOver() {
        this.running = false;
        document.getElementById('final-score').innerText = `Final Score: ${this.score}`;
        document.getElementById('game-over-screen').classList.add('active');
    },

    victory() {
        this.running = false;
        document.getElementById('victory-screen').classList.add('active');
    },

    updateUI() {
        scoreEl.innerText = `Score: ${this.score}`;
        livesEl.innerText = `Lives: ${this.lives}`;
    },

    spawnParticles(x, y, color) {
        for (let i = 0; i < 8; i++) {
            this.particles.push(new Particle(x, y, color));
        }
    },

    handleCollisions() {
        this.balls.forEach((ball, ballIdx) => {
            // Paddle collision
            if (ball.y + ball.radius > this.paddle.y && 
                ball.y - ball.radius < this.paddle.y + this.paddle.height &&
                ball.x > this.paddle.x && 
                ball.x < this.paddle.x + this.paddle.width) {
                
                ball.dy = -Math.abs(ball.dy);
                
                // Angle based on where it hits the paddle
                const hitPos = (ball.x - (this.paddle.x + this.paddle.width / 2)) / (this.paddle.width / 2);
                ball.dx = hitPos * BALL_SPEED * 1.5;
            }

            // Brick collision
            this.bricks.forEach(brick => {
                if (!brick.active) return;
                if (ball.x + ball.radius > brick.x && 
                    ball.x - ball.radius < brick.x + brick.w &&
                    ball.y + ball.radius > brick.y && 
                    ball.y - ball.radius < brick.y + brick.h) {
                    
                    // Determine side of collision for bounce
                    const overlapX = Math.min(ball.x + ball.radius - brick.x, brick.x + brick.w - (ball.x - ball.radius));
                    const overlapY = Math.min(ball.y + ball.radius - brick.y, brick.y + brick.h - (ball.y - ball.radius));
                    
                    if (overlapX < overlapY) ball.dx *= -1;
                    else ball.dy *= -1;

                    brick.hp--;
                    if (brick.hp <= 0) {
                        brick.active = false;
                        this.score += 10;
                        this.spawnParticles(brick.x + brick.w / 2, brick.y + brick.h / 2, brick.color);
                        if (brick.powerup) {
                            this.powerups.push(new PowerUp(brick.x + brick.w / 2, brick.y + brick.h / 2, brick.powerup));
                        }
                    }
                    this.updateUI();
                }
            });
        });

        // Powerup collision
        this.powerups.forEach((p, idx) => {
            if (p.y + p.r > this.paddle.y && 
                p.y - p.r < this.paddle.y + this.paddle.height &&
                p.x > this.paddle.x && 
                p.x < this.paddle.x + this.paddle.width) {
                
                if (p.type === 'WIDE') {
                    this.paddle.width = PADDLE_WIDTH * 1.6;
                    this.paddle.powerupTimer = 600; // 10 seconds at 60fps
                } else if (p.type === 'MULTI') {
                    const b = this.balls[0] || {x: WIDTH/2, y: HEIGHT/2};
                    this.balls.push(new Ball(b.x, b.y, -BALL_SPEED, -BALL_SPEED));
                    this.balls.push(new Ball(b.x, b.y, BALL_SPEED, -BALL_SPEED));
                }
                this.powerups.splice(idx, 1);
            }
        });
    }

    loop() {
        ctx.clearRect(0, 0, WIDTH, HEIGHT);

        if (this.running) {
            // Paddle movement
            let moveX = this.mouseX;
            if (this.keys['ArrowLeft']) moveX -= 5;
            if (this.keys['ArrowRight']) moveX += 5;
            this.paddle.update(moveX);

            // Ball updates
            this.balls.forEach((ball, idx) => {
                ball.update();
                if (ball.y - ball.radius < 0) ball.dy *= -1; 
                if (ball.y + ball.radius > HEIGHT) {
                    this.balls.splice(idx, 1);
                }
            });

            if (this.balls.length === 0) {
                this.lives--;
                this.updateUI();
                if (this.lives <= 0) {
                    this.gameOver();
                } else {
                    this.balls.push(new Ball(WIDTH / 2, HEIGHT - 50, BALL_SPEED, -BALL_SPEED));
                }
            }

            this.handleCollisions();
            
            this.powerups.forEach((p, idx) => {
                p.update();
                if (p.y > HEIGHT) this.powerups.splice(idx, 1);
            });

            this.particles.forEach((p, idx) => {
                p.update();
                if (p.life <= 0) this.particles.splice(idx, 1);
            });

            if (this.bricks.every(b => !b.active)) {
                this.victory();
            }
        } else {
            // Idle AI Demo: simple ball bouncing if not started
            if (this.balls.length === 0) {
                this.balls = [new Ball(WIDTH/2, HEIGHT/2, BALL_SPEED, BALL_SPEED)];
            }
            this.balls[0].update();
            if (this.balls[0].x < 0 || this.balls[0].x > WIDTH || this.balls[0].y < 0 || this.balls[0].y > HEIGHT) {
                this.balls[0].dx *= -1;
                this.balls[0].dy *= -1;
            }
        }

        // Drawing
        this.paddle.draw();
        this.balls.forEach(b => b.draw());
        this.bricks.forEach(b => b.draw());
        this.powerups.forEach(p => p.draw());
        this.particles.forEach(p => p.draw());

        requestAnimationFrame(() => this.loop());
    }
};

game.init();
</script>
</body>
</html>