Models 44

Mistral Small 4

by MistralReasoningClean
Open in new window

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

How it went

Total time
24.7 s
Cost
$0.0036
Output tokens
5,248
Spent thinking
0 tokens
Speed
216.6 tok/s
Console errors
0
First token after
479 ms
First visible text after
479 ms
Prompt tokens
532
Code size
23.5 KB
Finish reason
stop
Served by
Mistral
Model id
mistralai/mistral-small-2603
Reasoning sent
{"effort":"none"}
Max output
209,715 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 · 689 lines

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Breakout</title>
    <style>
        body {
            margin: 0;
            padding: 0;
            display: flex;
            justify-content: center;
            align-items: center;
            height: 100vh;
            background: #111;
            color: #fff;
            font-family: Arial, sans-serif;
            overflow: hidden;
            user-select: none;
        }

        #game-container {
            position: relative;
            width: 100%;
            max-width: 800px;
            height: 600px;
            background: #000;
        }

        #game-canvas {
            background: #000;
            display: block;
        }

        #start-screen, #game-over, #victory {
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            display: flex;
            flex-direction: column;
            justify-content: center;
            align-items: center;
            background: rgba(0, 0, 0, 0.8);
            z-index: 10;
            display: none;
        }

        #start-screen h1, #game-over h1, #victory h1 {
            font-size: 3em;
            margin: 0 0 20px;
            text-shadow: 0 0 10px #fff;
        }

        #start-screen p, #game-over p, #victory p {
            font-size: 1.2em;
            margin: 0 0 30px;
            text-align: center;
        }

        #restart-btn {
            padding: 12px 24px;
            font-size: 1.2em;
            background: #4CAF50;
            color: white;
            border: none;
            border-radius: 5px;
            cursor: pointer;
            transition: background 0.3s;
        }

        #restart-btn:hover {
            background: #45a049;
        }

        #score-display {
            position: absolute;
            top: 20px;
            left: 20px;
            font-size: 1.2em;
            z-index: 5;
        }

        #lives-display {
            position: absolute;
            top: 20px;
            right: 20px;
            font-size: 1.2em;
            z-index: 5;
        }

        #powerup-indicator {
            position: absolute;
            bottom: 20px;
            left: 50%;
            transform: translateX(-50%);
            font-size: 1em;
            z-index: 5;
            background: rgba(0, 0, 0, 0.7);
            padding: 5px 10px;
            border-radius: 5px;
            display: none;
        }
    </style>
</head>
<body>
    <div id="game-container">
        <div id="score-display">Score: 0</div>
        <div id="lives-display">Lives: 3</div>
        <div id="powerup-indicator"></div>
        <canvas id="game-canvas" width="800" height="600"></canvas>

        <div id="start-screen">
            <h1>Breakout</h1>
            <p>Click or press any key to start</p>
        </div>

        <div id="game-over">
            <h1>Game Over</h1>
            <p>Your score: <span id="final-score">0</span></p>
            <button id="restart-btn">Play Again</button>
        </div>

        <div id="victory">
            <h1>Victory!</h1>
            <p>Your score: <span id="victory-score">0</span></p>
            <button id="restart-btn">Play Again</button>
        </div>
    </div>

    <script>
        const canvas = document.getElementById('game-canvas');
        const ctx = canvas.getContext('2d');
        const startScreen = document.getElementById('start-screen');
        const gameOverScreen = document.getElementById('game-over');
        const victoryScreen = document.getElementById('victory');
        const finalScoreDisplay = document.getElementById('final-score');
        const victoryScoreDisplay = document.getElementById('victory-score');
        const scoreDisplay = document.getElementById('score-display');
        const livesDisplay = document.getElementById('lives-display');
        const powerupIndicator = document.getElementById('powerup-indicator');
        const restartBtn = document.getElementById('restart-btn');

        // Game state
        let gameActive = false;
        let gameOver = false;
        let victory = false;
        let score = 0;
        let lives = 3;
        let powerupActive = false;
        let powerupTimer = 0;
        let powerupType = '';

        // Paddle
        const paddleWidth = 100;
        const paddleHeight = 15;
        let paddleX = (canvas.width - paddleWidth) / 2;
        let paddleY = canvas.height - paddleHeight - 20;
        let paddleSpeed = 8;
        let mouseX = 0;
        let keyLeftPressed = false;
        let keyRightPressed = false;

        // Ball
        let balls = [{ x: canvas.width / 2, y: canvas.height / 2, radius: 8, dx: 4, dy: -4 }];
        const ballRadius = 8;

        // Bricks
        const brickRowCount = 6;
        const brickColumnCount = 10;
        const brickWidth = 75;
        const brickHeight = 20;
        const brickPadding = 10;
        const brickOffsetTop = 60;
        const brickOffsetLeft = 30;

        const bricks = [];
        for (let c = 0; c < brickColumnCount; c++) {
            bricks[c] = [];
            for (let r = 0; r < brickRowCount; r++) {
                const brickType = Math.floor(Math.random() * 10);
                bricks[c][r] = {
                    x: 0,
                    y: 0,
                    status: brickType < 7 ? 1 : 2, // 1 = normal, 2 = tough
                    broken: false,
                    powerup: Math.random() < 0.2 ? (Math.random() < 0.5 ? 'paddle' : 'multiball') : null
                };
            }
        }

        // Power-ups
        let powerups = [];

        // Particles
        let particles = [];

        // Event listeners
        canvas.addEventListener('mousemove', (e) => {
            mouseX = e.clientX - canvas.getBoundingClientRect().left;
            if (gameActive) {
                paddleX = mouseX - paddleWidth / 2;
                paddleX = Math.max(0, Math.min(canvas.width - paddleWidth, paddleX));
            }
        });

        document.addEventListener('keydown', (e) => {
            if (e.key === 'ArrowLeft') {
                keyLeftPressed = true;
            } else if (e.key === 'ArrowRight') {
                keyRightPressed = true;
            } else if (e.key === ' ' && !gameActive && !gameOver && !victory) {
                startGame();
            }
        });

        document.addEventListener('keyup', (e) => {
            if (e.key === 'ArrowLeft') {
                keyLeftPressed = false;
            } else if (e.key === 'ArrowRight') {
                keyRightPressed = false;
            }
        });

        restartBtn.addEventListener('click', startGame);

        // Start screen
        function showStartScreen() {
            startScreen.style.display = 'flex';
            gameOverScreen.style.display = 'none';
            victoryScreen.style.display = 'none';
            gameActive = false;
            gameOver = false;
            victory = false;
        }

        // Game over screen
        function showGameOverScreen() {
            gameOver = true;
            gameActive = false;
            finalScoreDisplay.textContent = score;
            gameOverScreen.style.display = 'flex';
            startScreen.style.display = 'none';
            victoryScreen.style.display = 'none';
        }

        // Victory screen
        function showVictoryScreen() {
            victory = true;
            gameActive = false;
            victoryScoreDisplay.textContent = score;
            victoryScreen.style.display = 'flex';
            startScreen.style.display = 'none';
            gameOverScreen.style.display = 'none';
        }

        // Start game
        function startGame() {
            // Reset game state
            balls = [{ x: canvas.width / 2, y: canvas.height / 2, radius: 8, dx: 4, dy: -4 }];
            paddleX = (canvas.width - paddleWidth) / 2;
            score = 0;
            lives = 3;
            powerupActive = false;
            powerupTimer = 0;
            powerupType = '';
            powerups = [];
            particles = [];

            // Reset bricks
            for (let c = 0; c < brickColumnCount; c++) {
                for (let r = 0; r < brickRowCount; r++) {
                    const brickType = Math.floor(Math.random() * 10);
                    bricks[c][r] = {
                        x: 0,
                        y: 0,
                        status: brickType < 7 ? 1 : 2,
                        broken: false,
                        powerup: Math.random() < 0.2 ? (Math.random() < 0.5 ? 'paddle' : 'multiball') : null
                    };
                }
            }

            // Update displays
            scoreDisplay.textContent = `Score: ${score}`;
            livesDisplay.textContent = `Lives: ${lives}`;
            powerupIndicator.style.display = 'none';

            // Hide screens
            startScreen.style.display = 'none';
            gameOverScreen.style.display = 'none';
            victoryScreen.style.display = 'none';
            gameActive = true;
            gameOver = false;
            victory = false;
        }

        // Check collision with bricks
        function collision(ball) {
            for (let c = 0; c < brickColumnCount; c++) {
                for (let r = 0; r < brickRowCount; r++) {
                    const brick = bricks[c][r];
                    if (brick.status > 0 && !brick.broken) {
                        const brickX = c * (brickWidth + brickPadding) + brickOffsetLeft;
                        const brickY = r * (brickHeight + brickPadding) + brickOffsetTop;

                        if (
                            ball.x + ball.radius > brickX &&
                            ball.x - ball.radius < brickX + brickWidth &&
                            ball.y + ball.radius > brickY &&
                            ball.y - ball.radius < brickY + brickHeight
                        ) {
                            // Calculate bounce angle based on where ball hits brick
                            const hitX = (ball.x - (brickX + brickWidth / 2)) / (brickWidth / 2);
                            ball.dx = hitX * 5;

                            // Reverse direction
                            ball.dy = -Math.abs(ball.dy);

                            // Reduce brick status
                            brick.status--;

                            // Create particles
                            for (let i = 0; i < 15; i++) {
                                particles.push({
                                    x: ball.x,
                                    y: ball.y,
                                    dx: (Math.random() - 0.5) * 4,
                                    dy: (Math.random() - 0.5) * 4,
                                    size: Math.random() * 3 + 1,
                                    color: brick.status === 0 ? '#ff5555' : '#ffaa55',
                                    life: 30
                                });
                            }

                            // Check if brick is destroyed
                            if (brick.status <= 0) {
                                brick.broken = true;

                                // Add to score
                                score += brick.status === 0 ? 10 : 20;
                                scoreDisplay.textContent = `Score: ${score}`;

                                // Drop powerup if available
                                if (brick.powerup) {
                                    powerups.push({
                                        x: brickX + brickWidth / 2,
                                        y: brickY + brickHeight / 2,
                                        type: brick.powerup,
                                        width: 20,
                                        height: 20,
                                        speed: 2
                                    });
                                }

                                // Check for victory
                                if (checkVictory()) {
                                    showVictoryScreen();
                                }
                            }

                            return true;
                        }
                    }
                }
            }
            return false;
        }

        // Check collision with paddle
        function collisionWithPaddle(ball) {
            if (
                ball.x + ball.radius > paddleX &&
                ball.x - ball.radius < paddleX + paddleWidth &&
                ball.y + ball.radius > paddleY &&
                ball.y - ball.radius < paddleY + paddleHeight
            ) {
                // Calculate bounce angle based on where ball hits paddle
                const hitX = (ball.x - (paddleX + paddleWidth / 2)) / (paddleWidth / 2);
                ball.dx = hitX * 5;
                ball.dy = -Math.abs(ball.dy);

                // Create particles
                for (let i = 0; i < 10; i++) {
                    particles.push({
                        x: ball.x,
                        y: ball.y,
                        dx: (Math.random() - 0.5) * 3,
                        dy: (Math.random() - 0.5) * 3,
                        size: Math.random() * 2 + 1,
                        color: '#aaaaff',
                        life: 20
                    });
                }

                return true;
            }
            return false;
        }

        // Check collision with walls
        function checkWallCollision(ball) {
            // Left wall
            if (ball.x - ball.radius < 0) {
                ball.x = ball.radius;
                ball.dx = Math.abs(ball.dx);
                return true;
            }

            // Right wall
            if (ball.x + ball.radius > canvas.width) {
                ball.x = canvas.width - ball.radius;
                ball.dx = -Math.abs(ball.dx);
                return true;
            }

            // Top wall
            if (ball.y - ball.radius < 0) {
                ball.y = ball.radius;
                ball.dy = Math.abs(ball.dy);
                return true;
            }

            // Bottom wall (lose a life)
            if (ball.y + ball.radius > canvas.height) {
                return true;
            }

            return false;
        }

        // Check if all bricks are broken
        function checkVictory() {
            for (let c = 0; c < brickColumnCount; c++) {
                for (let r = 0; r < brickRowCount; r++) {
                    if (bricks[c][r].status > 0 && !bricks[c][r].broken) {
                        return false;
                    }
                }
            }
            return true;
        }

        // Update powerup timer
        function updatePowerupTimer(deltaTime) {
            if (powerupActive) {
                powerupTimer -= deltaTime;
                if (powerupTimer <= 0) {
                    powerupActive = false;
                    powerupType = '';
                    powerupIndicator.style.display = 'none';

                    // Reset paddle width
                    if (powerupType === 'paddle') {
                        paddleWidth = 100;
                    }
                }
            }
        }

        // Update game state
        function update(deltaTime) {
            if (!gameActive) return;

            // Update powerup timer
            updatePowerupTimer(deltaTime);

            // Move paddle with keyboard
            if (keyLeftPressed && paddleX > 0) {
                paddleX -= paddleSpeed;
            }
            if (keyRightPressed && paddleX < canvas.width - paddleWidth) {
                paddleX += paddleSpeed;
            }

            // Move balls
            for (let i = balls.length - 1; i >= 0; i--) {
                const ball = balls[i];

                ball.x += ball.dx;
                ball.y += ball.dy;

                // Check wall collisions
                if (checkWallCollision(ball)) {
                    if (ball.y + ball.radius > canvas.height) {
                        // Ball fell off bottom
                        balls.splice(i, 1);
                        if (balls.length === 0) {
                            lives--;
                            livesDisplay.textContent = `Lives: ${lives}`;
                            if (lives <= 0) {
                                showGameOverScreen();
                            } else {
                                // Reset ball
                                balls.push({
                                    x: canvas.width / 2,
                                    y: canvas.height / 2,
                                    radius: 8,
                                    dx: 4,
                                    dy: -4
                                });
                            }
                        }
                    }
                }

                // Check brick collisions
                if (collision(ball)) {
                    continue;
                }

                // Check paddle collision
                if (collisionWithPaddle(ball)) {
                    continue;
                }
            }

            // Move powerups
            for (let i = powerups.length - 1; i >= 0; i--) {
                const powerup = powerups[i];
                powerup.y += powerup.speed;

                // Check if powerup is caught
                if (
                    powerup.y + powerup.height > paddleY &&
                    powerup.y < paddleY + paddleHeight &&
                    powerup.x + powerup.width > paddleX &&
                    powerup.x < paddleX + paddleWidth
                ) {
                    // Activate powerup
                    powerupActive = true;
                    powerupType = powerup.type;
                    powerupTimer = 10000; // 10 seconds

                    // Update indicator
                    powerupIndicator.textContent = powerupType === 'paddle' ? 'Paddle Width: 10s' : 'Multi-ball: 10s';
                    powerupIndicator.style.display = 'block';

                    // Apply powerup effect
                    if (powerupType === 'paddle') {
                        paddleWidth = 150;
                    } else if (powerupType === 'multiball') {
                        // Add two more balls
                        balls.push(
                            { x: canvas.width / 2, y: canvas.height / 2, radius: 8, dx: 3, dy: -3 },
                            { x: canvas.width / 2, y: canvas.height / 2, radius: 8, dx: -3, dy: -3 }
                        );
                    }

                    powerups.splice(i, 1);
                } else if (powerup.y > canvas.height) {
                    // Powerup fell off bottom
                    powerups.splice(i, 1);
                }
            }

            // Update particles
            for (let i = particles.length - 1; i >= 0; i--) {
                const particle = particles[i];
                particle.x += particle.dx;
                particle.y += particle.dy;
                particle.life--;

                if (particle.life <= 0) {
                    particles.splice(i, 1);
                }
            }
        }

        // Draw game
        function draw() {
            // Clear canvas
            ctx.clearRect(0, 0, canvas.width, canvas.height);

            // Draw bricks
            for (let c = 0; c < brickColumnCount; c++) {
                for (let r = 0; r < brickRowCount; r++) {
                    const brick = bricks[c][r];
                    if (brick.status > 0 && !brick.broken) {
                        const brickX = c * (brickWidth + brickPadding) + brickOffsetLeft;
                        const brickY = r * (brickHeight + brickPadding) + brickOffsetTop;

                        // Store position for collision detection
                        brick.x = brickX;
                        brick.y = brickY;

                        // Draw brick
                        ctx.beginPath();
                        ctx.rect(brickX, brickY, brickWidth, brickHeight);
                        ctx.fillStyle = brick.status === 1 ? '#55ff55' : '#ff5555';
                        ctx.fill();
                        ctx.closePath();

                        // Draw crack if tough brick has been hit once
                        if (brick.status === 1) {
                            ctx.beginPath();
                            ctx.moveTo(brickX + 5, brickY + 5);
                            ctx.lineTo(brickX + brickWidth - 5, brickY + brickHeight - 5);
                            ctx.moveTo(brickX + brickWidth - 5, brickY + 5);
                            ctx.lineTo(brickX + 5, brickY + brickHeight - 5);
                            ctx.strokeStyle = '#000';
                            ctx.lineWidth = 2;
                            ctx.stroke();
                        }

                        // Draw powerup icon if available
                        if (brick.powerup) {
                            ctx.beginPath();
                            if (brick.powerup === 'paddle') {
                                ctx.rect(brickX + brickWidth / 2 - 5, brickY + brickHeight / 2 - 5, 10, 10);
                            } else {
                                ctx.arc(brickX + brickWidth / 2, brickY + brickHeight / 2, 5, 0, Math.PI * 2);
                            }
                            ctx.fillStyle = brick.powerup === 'paddle' ? '#5555ff' : '#ffff55';
                            ctx.fill();
                            ctx.closePath();
                        }
                    }
                }
            }

            // Draw paddle
            ctx.beginPath();
            ctx.rect(paddleX, paddleY, paddleWidth, paddleHeight);
            ctx.fillStyle = powerupActive && powerupType === 'paddle' ? '#5555ff' : '#aaaaff';
            ctx.fill();
            ctx.closePath();

            // Draw balls
            balls.forEach(ball => {
                ctx.beginPath();
                ctx.arc(ball.x, ball.y, ball.radius, 0, Math.PI * 2);
                ctx.fillStyle = '#ffffff';
                ctx.fill();
                ctx.closePath();
            });

            // Draw powerups
            powerups.forEach(powerup => {
                ctx.beginPath();
                if (powerup.type === 'paddle') {
                    ctx.rect(powerup.x - powerup.width / 2, powerup.y - powerup.height / 2, powerup.width, powerup.height);
                    ctx.fillStyle = '#5555ff';
                } else {
                    ctx.arc(powerup.x, powerup.y, powerup.width / 2, 0, Math.PI * 2);
                    ctx.fillStyle = '#ffff55';
                }
                ctx.fill();
                ctx.closePath();
            });

            // Draw particles
            particles.forEach(particle => {
                ctx.beginPath();
                ctx.arc(particle.x, particle.y, particle.size, 0, Math.PI * 2);
                ctx.fillStyle = particle.color;
                ctx.fill();
                ctx.closePath();
            });
        }

        // Game loop
        let lastTime = 0;
        function gameLoop(timestamp) {
            const deltaTime = timestamp - lastTime;
            lastTime = timestamp;

            update(deltaTime / 1000);
            draw();

            if (!gameOver && !victory) {
                requestAnimationFrame(gameLoop);
            }
        }

        // Initialize
        showStartScreen();

        // Start game loop when clicking
        canvas.addEventListener('click', () => {
            if (!gameActive && !gameOver && !victory) {
                startGame();
                requestAnimationFrame(gameLoop);
            }
        });
    </script>
</body>
</html>