Models 44

LFM2.5-2.6B (free)

by LiquidAIreasoning 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
12.6 s
Cost
$0
Output tokens
5,182
Spent thinking
722 tokens
Speed
419 tok/s
Console errors
1
First token after
208 ms
First visible text after
4.0 s
Prompt tokens
535
Code size
18.0 KB
Finish reason
stop
Served by
Liquid
Model id
liquid/lfm-2.5-2.6b:free
Reasoning sent
model default
Max output
8,192 tokens
Generated
Nov 9, 2026

Console errors

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

Failed to execute 'fillText' on 'CanvasRenderingContext2D': 3 arguments required, but only 2 present.

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 · 540 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>
        * { margin: 0; padding: 0; box-sizing: border-box; }
        body {
            background: #1a1a2e;
            display: flex;
            flex-direction: column;
            align-items: center;
            justify-content: center;
            height: 100vh;
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            overflow: hidden;
        }
        canvas {
            border: 4px solid #0f0f1a;
            border-radius: 8px;
            box-shadow: 0 0 30px rgba(0, 255, 255, 0.2);
        }
        #ui {
            position: absolute;
            top: 20px;
            left: 20px;
            font-size: 18px;
            color: #fff;
            pointer-events: none;
            text-shadow: 1px 1px 4px rgba(0,0,0,0.5);
        }
        #score {
            color: #00ff88;
            font-weight: bold;
        }
        #lives {
            color: #ff4444;
            font-weight: bold;
        }
        #game-state {
            font-size: 24px;
            font-weight: bold;
            margin-top: 10px;
            color: #fff;
        }
        #start-message {
            position: absolute;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            font-size: 32px;
            color: #fff;
            text-shadow: 2px 2px 4px rgba(0,0,0,0.5);
            display: none;
            z-index: 10;
        }
        #game-over-screen, #victory-screen {
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background: rgba(0, 0, 0, 0.85);
            display: flex;
            flex-direction: column;
            align-items: center;
            justify-content: center;
            z-index: 20;
            color: #fff;
        }
        h1 {
            font-size: 48px;
            margin-bottom: 10px;
            text-shadow: 0 0 20px rgba(0, 255, 255, 0.5);
        }
        p {
            font-size: 16px;
            margin-bottom: 30px;
            color: #aaa;
        }
        #restart-btn {
            margin-top: 20px;
            padding: 12px 40px;
            font-size: 18px;
            background: #00ff88;
            color: #000;
            border: none;
            border-radius: 6px;
            cursor: pointer;
            transition: background 0.3s;
        }
        #restart-btn:hover {
            background: #00cc6a;
        }
    </style>
</head>
<body>
    <canvas id="gameCanvas" width="1280" height="800"></canvas>
    <div id="ui">
        <div id="score">Score: 0</div>
        <div id="lives">Lives: 3</div>
    </div>
    <div id="start-message">Click or press a key to start</div>
    <div id="game-over-screen" style="display:none;">
        <h1>Game Over</h1>
        <p>Final Score: <span id="final-score">0</span></p>
        <button id="restart-btn">Play Again</button>
    </div>
    <div id="victory-screen" style="display:none;">
        <h1>Victory!</h1>
        <p>You cleared the board!</p>
        <button id="restart-btn">Play Again</button>
    </div>

    <script>
        const canvas = document.getElementById('gameCanvas');
        const ctx = canvas.getContext('2d');
        
        // Game state
        let gameState = 'start'; // start, playing, gameover, victory
        let score = 0;
        let lives = 3;
        let paddle = { x: 350, y: 650, width: 100, height: 15, dx: 0, dy: 0 };
        let ball = { x: 400, y: 600, dx: 4, dy: -4, radius: 8 };
        let bricks = [];
        let particles = [];
        let powerUp = null; // null, 'wide', 'multi'
        let powerUpTimer = 0;
        let gameSpeed = 5;
        let wideTimer = 0;
        let multiBallCount = 1;
        let multiBallBalls = [];
        
        // Brick configuration: { row, col, type, hitsLeft, crack }
        const brickTypes = {
            normal: { color: '#ff6b6b', hits: 1, crackColor: '#ff6b6b' },
            tough: { color: '#feca57', hits: 2, crackColor: '#feca57' },
            powerup: { color: '#54a0ff', hits: 1, crackColor: '#54a0ff' }
        };
        
        function initBricks() {
            bricks = [];
            const rows = 6;
            const cols = 10;
            const brickWidth = 70;
            const brickHeight = 20;
            const gap = 5;
            
            for (let row = 0; row < rows; row++) {
                for (let col = 0; col < cols; col++) {
                    // Vary brick positions slightly
                    const offsetX = (col - (cols - 1) / 2) * (brickWidth + gap);
                    const offsetY = (row - (rows - 1) / 2) * (brickHeight + gap);
                    
                    // Some bricks are tougher
                    const isTough = (row * 2 + col) % 3 === 0;
                    const type = isTough ? 'tough' : 'normal';
                    
                    bricks.push({
                        x: offsetX + brickWidth / 2,
                        y: offsetY + brickHeight / 2,
                        type: type,
                        hitsLeft: isTough ? 2 : 1,
                        crack: false
                    });
                }
            }
        }
        
        function createParticles(x, y, color, count) {
            for (let i = 0; i < count; i++) {
                const angle = (Math.PI * 2 / count) * i + Math.random() * 0.5;
                const speed = 2 + Math.random() * 4;
                particles.push({
                    x: x,
                    y: y,
                    vx: Math.cos(angle) * speed,
                    vy: Math.sin(angle) * speed,
                    life: 1.0,
                    decay: 0.02 + Math.random() * 0.02,
                    size: 3 + Math.random() * 4,
                    color: color
                });
            }
        }
        
        function updateParticles() {
            for (let i = particles.length - 1; i >= 0; i--) {
                const p = particles[i];
                p.x += p.vx;
                p.y += p.vy;
                p.life -= p.decay;
                if (p.life <= 0) {
                    particles.splice(i, 1);
                }
            }
        }
        
        function checkCollision(ball, paddle) {
            return (
                ball.x > paddle.x - paddle.width &&
                ball.x < paddle.x + paddle.width &&
                ball.y > paddle.y - paddle.height/2 &&
                ball.y < paddle.y + paddle.height/2
            );
        }
        
        function updateBall() {
            ball.x += ball.dx;
            ball.y += ball.dy;
            
            // Wall collisions
            if (ball.x + ball.radius > canvas.width - 10) {
                ball.x = canvas.width - 10 - ball.radius;
                ball.dx = -ball.dx;
            } else if (ball.x - ball.radius < 10) {
                ball.x = 10 + ball.radius;
                ball.dx = -ball.dx;
            }
            
            if (ball.y + ball.radius > canvas.height - 10) {
                ball.y = canvas.height - 10 - ball.radius;
                ball.dy = -ball.dy;
            } else if (ball.y - ball.radius < 10) {
                ball.y = 10 + ball.radius;
                ball.dy = -ball.dy;
            }
            
            // Paddle collision
            if (checkCollision(ball, paddle)) {
                // Calculate bounce angle based on hit position
                const hitPos = (ball.x - paddle.x) / paddle.width; // 0 to 1
                const angle = hitPos * Math.PI * 0.6; // Max 60 degrees from vertical
                ball.dx = Math.cos(angle) * ball.speed;
                ball.dy = -ball.speed;
            }
            
            // Score when ball goes below paddle
            if (ball.y + ball.radius < paddle.y - 10) {
                score += 10;
                createParticles(ball.x, ball.y, '#00ff88', 8);
                updateScore();
            }
        }
        
        function updateBricks() {
            for (let i = bricks.length - 1; i >= 0; i--) {
                const b = bricks[i];
                if (b.hitsLeft > 0) {
                    b.hitsLeft--;
                    if (b.hitsLeft === 0) {
                        b.crack = true;
                        createParticles(b.x, b.y, b.color, 15);
                        bricks.splice(i, 1);
                        updateScore();
                    }
                }
            }
        }
        
        function updatePowerUp() {
            if (powerUp === 'wide') {
                wideTimer--;
                if (wideTimer <= 0) {
                    paddle.width = 150;
                    powerUp = null;
                    wideTimer = 0;
                }
            } else if (powerUp === 'multi') {
                multiBallCount++;
                multiBallBalls.push({
                    x: paddle.x + paddle.width / 2,
                    y: paddle.y - 10,
                    dx: 0,
                    dy: 0,
                    radius: 8,
                    count: multiBallCount
                });
            }
        }
        
        function updateMultiBalls() {
            for (let i = multiBallBalls.length - 1; i >= 0; i--) {
                const mb = multiBallBalls[i];
                mb.x += mb.dx;
                mb.y += mb.dy;
                
                // Remove if off screen
                if (mb.x < -50 || mb.x > canvas.width + 50) {
                    multiBallBalls.splice(i, 1);
                    continue;
                }
                
                // Check collision with paddle
                if (checkCollision(mb, paddle)) {
                    // Add to ball pool
                    multiBallBalls[i].count++;
                    updateScore();
                }
            }
        }
        
        function updateScore() {
            document.getElementById('score').textContent = 'Score: ' + score;
            document.getElementById('lives').textContent = 'Lives: ' + lives;
        }
        
        function gameOver() {
            gameState = 'gameover';
            document.getElementById('game-over-screen').style.display = 'flex';
            document.getElementById('final-score').textContent = score;
        }
        
        function victory() {
            gameState = 'victory';
            document.getElementById('victory-screen').style.display = 'flex';
        }
        
        function startGame() {
            gameState = 'playing';
            document.getElementById('start-message').style.display = 'none';
            document.getElementById('game-over-screen').style.display = 'none';
            document.getElementById('victory-screen').style.display = 'none';
            
            initBricks();
            paddle.width = 100;
            powerUp = null;
            powerUpTimer = 0;
            multiBallCount = 1;
            multiBallBalls = [];
            ball.dx = 4 * gameSpeed;
            ball.dy = -4 * gameSpeed;
            ball.x = canvas.width / 2;
            ball.y = canvas.height - 80;
        }
        
        function handleInput() {
            // Mouse control
            if (canvas.getBoundingClientRect().width > 0) {
                const rect = canvas.getBoundingClientRect();
                const mouseX = (rect.left + (canvas.width - rect.left) * (paddle.x - rect.left) / canvas.width);
                paddle.x = Math.max(10, Math.min(canvas.width - paddle.width - 10, mouseX));
            }
            
            // Keyboard control
            if (keyDownEvent) {
                if (keyDownEvent.key === 'ArrowLeft' || keyDownEvent.key === 'a') {
                    paddle.x -= gameSpeed * 0.8;
                } else if (keyDownEvent.key === 'ArrowRight' || keyDownEvent.key === 'd') {
                    paddle.x += gameSpeed * 0.8;
                } else if (keyDownEvent.key === ' ' || keyDownEvent.key === 'Enter') {
                    if (gameState === 'start') {
                        startGame();
                    } else if (gameState === 'gameover' || gameState === 'victory') {
                        startGame();
                    }
                }
            }
        }
        
        function keyDownEvent(e) {
            if (e.key === 'ArrowLeft' || e.key === 'a') {
                paddle.x -= gameSpeed * 0.8;
            } else if (e.key === 'ArrowRight' || e.key === 'd') {
                paddle.x += gameSpeed * 0.8;
            } else if (e.key === ' ' || e.key === 'Enter') {
                if (gameState === 'start' || gameState === 'gameover' || gameState === 'victory') {
                    startGame();
                }
            }
        }
        
        function resetGame() {
            gameState = 'start';
            score = 0;
            lives = 3;
            paddle.width = 100;
            powerUp = null;
            powerUpTimer = 0;
            multiBallCount = 1;
            multiBallBalls = [];
            ball.dx = 4 * gameSpeed;
            ball.dy = -4 * gameSpeed;
            ball.x = canvas.width / 2;
            ball.y = canvas.height - 80;
            bricks = [];
            initBricks();
        }
        
        function drawBricks() {
            for (const b of bricks) {
                if (b.crack) {
                    // Cracked brick - show crack line
                    ctx.beginPath();
                    ctx.moveTo(b.x + 5, b.y);
                    ctx.lineTo(b.x + b.width - 5, b.y + b.height);
                    ctx.strokeStyle = b.crackColor;
                    ctx.lineWidth = 2;
                    ctx.stroke();
                } else {
                    // Normal brick
                    ctx.fillStyle = brickTypes[b.type].color;
                    ctx.beginPath();
                    ctx.roundRect(b.x, b.y, b.width, b.height, 4);
                    ctx.fill();
                    
                    // Hit indicator for tough bricks
                    if (b.type === 'tough' && b.hitsLeft > 1) {
                        ctx.fillStyle = '#ffd93d';
                        ctx.beginPath();
                        ctx.arc(b.x + b.width/2, b.y + b.height/2, 3, 0, Math.PI * 2);
                        ctx.fill();
                    }
                }
            }
        }
        
        function drawPaddle() {
            ctx.fillStyle = '#00d4ff';
            ctx.beginPath();
            ctx.roundRect(paddle.x, paddle.y, paddle.width, paddle.height, 8);
            ctx.fill();
            
            // Paddle glow
            ctx.shadowColor = '#00d4ff';
            ctx.shadowBlur = 10;
            ctx.beginPath();
            ctx.roundRect(paddle.x, paddle.y, paddle.width, paddle.height, 8);
            ctx.fill();
            ctx.shadowBlur = 0;
        }
        
        function drawBall() {
            ctx.fillStyle = '#ffffff';
            ctx.beginPath();
            ctx.arc(ball.x, ball.y, ball.radius, 0, Math.PI * 2);
            ctx.fill();
            
            // Ball trail
            ctx.beginPath();
            ctx.arc(ball.x - ball.dx * 0.5, ball.y - ball.dy * 0.5, ball.radius * 0.8, 0, Math.PI * 2);
            ctx.fillStyle = 'rgba(255, 255, 255, 0.3)';
            ctx.fill();
        }
        
        function drawParticles() {
            for (const p of particles) {
                ctx.globalAlpha = p.life;
                ctx.fillStyle = p.color;
                ctx.beginPath();
                ctx.arc(p.x, p.y, p.size * p.life, 0, Math.PI * 2);
                ctx.fill();
            }
            ctx.globalAlpha = 1;
        }
        
        function drawUI() {
            // Score
            ctx.font = 'bold 24px Arial';
            ctx.fillStyle = '#00ff88';
            ctx.textAlign = 'left';
            ctx.fillText('Score: ' + score, 20, 30);
            
            // Lives
            ctx.font = 'bold 20px Arial';
            ctx.fillStyle = '#ff4444';
            ctx.textAlign = 'left';
            for (let i = 0; i < lives; i++) {
                ctx.fillText('L', 20 + i * 25);
            }
            
            // Game state
            const stateEl = document.getElementById('game-state');
            if (gameState === 'start') {
                stateEl.textContent = 'Start Game';
            } else if (gameState === 'playing') {
                stateEl.textContent = 'Playing';
            } else if (gameState === 'gameover') {
                stateEl.textContent = 'Game Over';
            } else if (gameState === 'victory') {
                stateEl.textContent = 'Victory!';
            }
        }
        
        function gameLoop() {
            if (gameState === 'playing') {
                updateBall();
                updateBricks();
                updatePowerUp();
                updateMultiBalls();
                updateParticles();
            }
            
            drawBricks();
            drawPaddle();
            drawBall();
            drawParticles();
            drawUI();
            
            requestAnimationFrame(gameLoop);
        }
        
        // Initialize
        initBricks();
        
        // Handle mouse move for paddle
        canvas.addEventListener('mousemove', (e) => {
            if (gameState === 'start') {
                paddle.x = e.clientX - 50;
                paddle.x = Math.max(10, Math.min(canvas.width - paddle.width - 10, e.clientX - 50));
            }
        });
        
        // Handle click to start
        canvas.addEventListener('click', () => {
            if (gameState === 'start') {
                startGame();
            }
        });
        
        // Handle keyboard
        document.addEventListener('keydown', (e) => {
            if (e.key === ' ' || e.key === 'Enter') {
                if (gameState === 'start' || gameState === 'gameover' || gameState === 'victory') {
                    startGame();
                }
            }
        });
        
        // Restart buttons
        document.getElementById('restart-btn').addEventListener('click', () => {
            resetGame();
        });
        
        // Start the game loop
        gameLoop();
    </script>
</body>
</html>
Reasoning trace (722 tokens)
The user wants a Breakout game in a single HTML file with specific features. Let me plan the implementation:

1. **Canvas setup**: 1280×800 viewport, centered canvas
2. **Paddle**: Controlled by mouse (click/drag) and arrow keys
3. **Ball physics**: Bounce angle depends on hit position on paddle
4. **Bricks**: At least 6 rows, mix normal and tougher bricks (2 hits)
5. **Power-ups**: Some bricks have power-up icons, drop when broken, can be caught for effects
6. **Particles**: When bricks break
7. **Lives**: 3 lives, score display
8. **Game states**: Playing, Game Over, Victory
9. **Self-play demo**: Simple AI plays when clicked

Let me design the HTML structure:
- Canvas element
- UI overlay for score, lives, game state
- Power-up icons (visual indicators)

Key features to implement:
- Paddle movement with mouse and keyboard
- Ball physics with angle calculation based on hit position
- Brick array with different types (normal, tough, power-up)
- Particle system for brick breaks
- Power-up collection (wider paddle, multi-ball)
- Game states management
- Restart functionality

Let me write the code carefully:

```html
<!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>
        /* CSS for the game */
    </style>
</head>
<body>
    <canvas id="gameCanvas"></canvas>
    <div id="ui">...</div>
    <script>
        // Game logic
    </script>
</body>
</html>
```

I need to be careful about:
- No external files (only CDN allowed if needed, but vanilla JS is fine)
- No alert(), confirm(), prompt(), window.open()
- Self-play demo mode
- All requirements met

Let me structure the game:

**Game State:**
- score, lives, livesLeft, score
- gameState: 'start', 'playing', 'gameover', 'victory'
- paddle: x, y, width, height, dx, dy
- ball: x, y, dx, dy, radius
- bricks: array of brick objects
- particles: array for particle effects
- powerUp: current power-up type (none, wide, multi)

**Brick Types:**
- Normal: 1 hit to break
- Tough: 2 hits to break
- Power-up: drops when broken, can be collected

**Physics:**
- Paddle movement: mouse drag or arrow keys
- Ball bounce: angle = (hitPosition - center) * multiplier
- Collision detection: ball vs paddle, ball vs bricks

**Power-ups:**
- Wide paddle (10 seconds): increases paddle width
- Multi-ball (3 balls): creates additional ball

**Particles:**
- When brick breaks, create particle effects

Let me write the complete code now. I'll make it polished with good visuals.

For the canvas size, I'll use 1280×800 as requested. The game area will be a subset.

Brick layout: 6 rows, maybe 10-12 columns. Each row has decreasing number of bricks.

Let me code this step by step in the HTML file.