Ministral 3 14B 2512
by Mistralreasoning default1 console error
Running live in a sandboxed frame. Click inside it before using the keyboard.
How it went
- Total time
- 59.7 s
- Cost
- $0.0013
- Output tokens
- 6,136
- Spent thinking
- 0 tokens
- Speed
- 103.6 tok/s
- Console errors
- 1
- First token after
- 492 ms
- First visible text after
- 492 ms
- Prompt tokens
- 520
- Code size
- 26.6 KB
- Finish reason
- stop
- Served by
- Mistral
- Model id
mistralai/ministral-14b-2512- Reasoning sent
model default- Max output
- 209,715 tokens
- Generated
- Nov 13, 2026
Console errors
Caught in the first 3 seconds after load, in a sandboxed iframe like the one above.
Cannot read properties of undefined (reading 'icon')
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 · 754 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-color: #222;
font-family: Arial, sans-serif;
overflow: hidden;
user-select: none;
}
#game-container {
position: relative;
width: 100%;
max-width: 800px;
height: 600px;
background-color: #111;
border: 4px solid #444;
box-shadow: 0 0 20px rgba(0, 0, 0, 0.5);
overflow: hidden;
}
#canvas {
display: block;
background-color: #000;
}
#ui {
position: absolute;
top: 10px;
left: 10px;
color: white;
font-size: 18px;
z-index: 10;
}
#start-screen, #game-over-screen, #victory-screen {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background-color: rgba(0, 0, 0, 0.8);
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
color: white;
font-size: 24px;
z-index: 20;
display: none;
}
#start-screen h1, #game-over-screen h1, #victory-screen h1 {
margin-bottom: 20px;
font-size: 48px;
}
#start-screen button, #game-over-screen button, #victory-screen button {
padding: 12px 24px;
font-size: 18px;
background-color: #4CAF50;
color: white;
border: none;
border-radius: 5px;
cursor: pointer;
margin-top: 20px;
}
#start-screen button:hover, #game-over-screen button:hover, #victory-screen button:hover {
background-color: #45a049;
}
.powerup-icon {
width: 20px;
height: 20px;
display: inline-block;
margin-left: 5px;
}
.particle {
position: absolute;
background-color: rgba(255, 255, 255, 0.8);
border-radius: 50%;
pointer-events: none;
z-index: 1;
}
@media (max-width: 600px) {
#game-container {
max-width: 100%;
height: 500px;
}
#ui {
font-size: 14px;
}
#start-screen h1, #game-over-screen h1, #victory-screen h1 {
font-size: 32px;
}
}
</style>
</head>
<body>
<div id="game-container">
<canvas id="canvas"></canvas>
<div id="ui">
<div>Lives: <span id="lives">3</span></div>
<div>Score: <span id="score">0</span></div>
</div>
<div id="start-screen">
<h1>Breakout</h1>
<p>Click or press a key to start</p>
<button id="start-button">Start Game</button>
</div>
<div id="game-over-screen">
<h1>Game Over</h1>
<p>Final Score: <span id="final-score">0</span></p>
<button id="restart-button">Play Again</button>
</div>
<div id="victory-screen">
<h1>Victory!</h1>
<p>Final Score: <span id="final-score-victory">0</span></p>
<button id="restart-button-victory">Play Again</button>
</div>
</div>
<script>
// Game constants
const CANVAS_WIDTH = 800;
const CANVAS_HEIGHT = 600;
const PADDLE_WIDTH = 100;
const PADDLE_HEIGHT = 15;
const BALL_RADIUS = 10;
const BRICK_WIDTH = 75;
const BRICK_HEIGHT = 30;
const BRICK_COLS = 8;
const BRICK_ROWS = 6;
const PADDLE_SPEED = 8;
const BALL_SPEED = 4;
const POWERUP_DURATION = 10000; // 10 seconds
// Game state
let gameState = {
running: false,
paused: false,
lives: 3,
score: 0,
level: 1,
balls: [],
paddle: {
x: (CANVAS_WIDTH - PADDLE_WIDTH) / 2,
y: CANVAS_HEIGHT - 50,
width: PADDLE_WIDTH,
height: PADDLE_HEIGHT,
speed: PADDLE_SPEED,
widthMultiplier: 1
},
bricks: [],
powerups: [],
particles: [],
lastPowerupTime: 0,
powerupActive: null,
powerupTimer: null,
mouseDown: false,
gameOver: false,
victory: false
};
// Powerup types
const POWERUP_TYPES = {
WIDER: { id: 'wider', icon: '🔥', duration: POWERUP_DURATION, description: 'Wider Paddle' },
MULTI_BALL: { id: 'multi-ball', icon: '⚡', duration: POWERUP_DURATION, description: 'Multi-ball' }
};
// DOM elements
const canvas = document.getElementById('canvas');
const ctx = canvas.getContext('2d');
const startScreen = document.getElementById('start-screen');
const gameOverScreen = document.getElementById('game-over-screen');
const victoryScreen = document.getElementById('victory-screen');
const livesDisplay = document.getElementById('lives');
const scoreDisplay = document.getElementById('score');
const finalScoreDisplay = document.getElementById('final-score');
const finalScoreVictoryDisplay = document.getElementById('final-score-victory');
const startButton = document.getElementById('start-button');
const restartButton = document.getElementById('restart-button');
const restartButtonVictory = document.getElementById('restart-button-victory');
// Initialize canvas
canvas.width = CANVAS_WIDTH;
canvas.height = CANVAS_HEIGHT;
// Event listeners
startButton.addEventListener('click', startGame);
restartButton.addEventListener('click', startGame);
restartButtonVictory.addEventListener('click', startGame);
canvas.addEventListener('mousedown', () => {
gameState.mouseDown = true;
});
canvas.addEventListener('mouseup', () => {
gameState.mouseDown = false;
});
canvas.addEventListener('mousemove', handleMouseMove);
document.addEventListener('keydown', handleKeyDown);
// Start game
function startGame() {
// Hide all screens
startScreen.style.display = 'none';
gameOverScreen.style.display = 'none';
victoryScreen.style.display = 'none';
// Reset game state
gameState = {
running: true,
paused: false,
lives: 3,
score: 0,
level: 1,
balls: [],
paddle: {
x: (CANVAS_WIDTH - PADDLE_WIDTH) / 2,
y: CANVAS_HEIGHT - 50,
width: PADDLE_WIDTH,
height: PADDLE_HEIGHT,
speed: PADDLE_SPEED,
widthMultiplier: 1
},
bricks: [],
powerups: [],
particles: [],
lastPowerupTime: 0,
powerupActive: null,
powerupTimer: null,
mouseDown: false,
gameOver: false,
victory: false
};
// Initialize game
initGame();
// Start game loop
requestAnimationFrame(gameLoop);
// Show "Click or press a key to start" message
setTimeout(() => {
if (!gameState.running) {
showStartMessage();
}
}, 100);
}
// Show start message
function showStartMessage() {
ctx.fillStyle = 'rgba(0, 0, 0, 0.7)';
ctx.fillRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT);
ctx.fillStyle = 'white';
ctx.font = '24px Arial';
ctx.textAlign = 'center';
ctx.fillText('Click or press a key to start', CANVAS_WIDTH / 2, CANVAS_HEIGHT / 2);
ctx.textAlign = 'left';
}
// Initialize game
function initGame() {
// Create paddle
gameState.paddle.x = (CANVAS_WIDTH - PADDLE_WIDTH * gameState.paddle.widthMultiplier) / 2;
// Create balls
gameState.balls = [];
for (let i = 0; i < (gameState.powerupActive === POWERUP_TYPES.MULTI_BALL.id ? 3 : 1); i++) {
gameState.balls.push({
x: CANVAS_WIDTH / 2,
y: CANVAS_HEIGHT / 2,
radius: BALL_RADIUS,
dx: (Math.random() > 0.5 ? 1 : -1) * BALL_SPEED,
dy: -BALL_SPEED,
speed: BALL_SPEED
});
}
// Create bricks
gameState.bricks = [];
for (let r = 0; r < BRICK_ROWS; r++) {
for (let c = 0; c < BRICK_COLS; c++) {
// Randomly decide if brick is tough (2 hits) or normal (1 hit)
const isTough = Math.random() < 0.3;
const hits = isTough ? 2 : 1;
// Randomly decide if brick has a powerup (10% chance)
const hasPowerup = Math.random() < 0.1;
let powerupType = null;
if (hasPowerup) {
// Randomly choose between powerup types
const types = Object.values(POWERUP_TYPES);
powerupType = types[Math.floor(Math.random() * types.length)].id;
}
gameState.bricks.push({
x: c * (BRICK_WIDTH + 5) + 35,
y: r * (BRICK_HEIGHT + 5) + 50,
width: BRICK_WIDTH,
height: BRICK_HEIGHT,
hits: hits,
color: isTough ? '#8B4513' : '#800080',
cracked: false,
powerupType: powerupType
});
}
}
// Clear any existing powerup timer
if (gameState.powerupTimer) {
clearTimeout(gameState.powerupTimer);
}
// Update UI
livesDisplay.textContent = gameState.lives;
scoreDisplay.textContent = gameState.score;
}
// Handle mouse movement
function handleMouseMove(e) {
if (!gameState.running || gameState.paused) return;
const rect = canvas.getBoundingClientRect();
const mouseX = e.clientX - rect.left;
// Update paddle position
gameState.paddle.x = mouseX - (PADDLE_WIDTH * gameState.paddle.widthMultiplier) / 2;
// Keep paddle within bounds
gameState.paddle.x = Math.max(0, Math.min(CANVAS_WIDTH - PADDLE_WIDTH * gameState.paddle.widthMultiplier, gameState.paddle.x));
}
// Handle key down
function handleKeyDown(e) {
if (!gameState.running || gameState.paused) {
if (e.code === 'Space' || e.key === 'Enter' || e.key === ' ') {
startGame();
}
return;
}
if (e.code === 'ArrowLeft') {
gameState.paddle.x -= gameState.paddle.speed;
// Keep paddle within bounds
gameState.paddle.x = Math.max(0, gameState.paddle.x);
} else if (e.code === 'ArrowRight') {
gameState.paddle.x += gameState.paddle.speed;
// Keep paddle within bounds
gameState.paddle.x = Math.max(0, Math.min(CANVAS_WIDTH - PADDLE_WIDTH * gameState.paddle.widthMultiplier, gameState.paddle.x));
}
}
// Game loop
function gameLoop() {
if (!gameState.running) {
showStartMessage();
return;
}
// Clear canvas
ctx.clearRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT);
// Draw everything
drawBricks();
drawPowerups();
drawParticles();
drawPaddle();
drawBalls();
// Update game state
updatePowerups();
updateParticles();
updateBalls();
// Check for game over or victory
checkGameOver();
checkVictory();
// Continue the game loop
requestAnimationFrame(gameLoop);
}
// Draw bricks
function drawBricks() {
gameState.bricks.forEach(brick => {
// Draw brick
ctx.fillStyle = brick.color;
ctx.fillRect(brick.x, brick.y, brick.width, brick.height);
// Draw border
ctx.strokeStyle = '#000';
ctx.lineWidth = 2;
ctx.strokeRect(brick.x, brick.y, brick.width, brick.height);
// Draw powerup icon if exists
if (brick.powerupType) {
const powerup = POWERUP_TYPES[brick.powerupType];
ctx.fillStyle = 'white';
ctx.font = '16px Arial';
ctx.fillText(powerup.icon, brick.x + 5, brick.y + 20);
}
// Draw cracks if brick is cracked
if (brick.cracked) {
ctx.strokeStyle = 'rgba(255, 255, 255, 0.5)';
ctx.lineWidth = 2;
ctx.beginPath();
ctx.moveTo(brick.x, brick.y);
ctx.lineTo(brick.x + brick.width, brick.y + brick.height);
ctx.stroke();
ctx.beginPath();
ctx.moveTo(brick.x + brick.width, brick.y);
ctx.lineTo(brick.x, brick.y + brick.height);
ctx.stroke();
}
});
}
// Draw powerups
function drawPowerups() {
gameState.powerups.forEach(powerup => {
const powerupType = POWERUP_TYPES[powerup.type];
ctx.fillStyle = '#FFD700';
ctx.beginPath();
ctx.arc(powerup.x, powerup.y, 10, 0, Math.PI * 2);
ctx.fill();
// Draw powerup icon
ctx.fillStyle = 'white';
ctx.font = '12px Arial';
ctx.fillText(powerupType.icon, powerup.x - 5, powerup.y + 5);
});
}
// Draw particles
function drawParticles() {
gameState.particles.forEach(particle => {
ctx.fillStyle = `rgba(255, 255, 255, ${particle.opacity})`;
ctx.beginPath();
ctx.arc(particle.x, particle.y, particle.radius, 0, Math.PI * 2);
ctx.fill();
});
}
// Draw paddle
function drawPaddle() {
ctx.fillStyle = '#0095DD';
ctx.fillRect(
gameState.paddle.x,
gameState.paddle.y,
PADDLE_WIDTH * gameState.paddle.widthMultiplier,
gameState.paddle.height
);
// Draw border
ctx.strokeStyle = '#000';
ctx.lineWidth = 2;
ctx.strokeRect(
gameState.paddle.x,
gameState.paddle.y,
PADDLE_WIDTH * gameState.paddle.widthMultiplier,
gameState.paddle.height
);
}
// Draw balls
function drawBalls() {
gameState.balls.forEach(ball => {
ctx.fillStyle = '#FFF';
ctx.beginPath();
ctx.arc(ball.x, ball.y, ball.radius, 0, Math.PI * 2);
ctx.fill();
// Draw border
ctx.strokeStyle = '#000';
ctx.lineWidth = 1;
ctx.stroke();
});
}
// Update powerups
function updatePowerups() {
// Remove powerups that are out of bounds
gameState.powerups = gameState.powerups.filter(powerup => {
// Check if powerup is caught by paddle
if (powerup.y + 10 > gameState.paddle.y &&
powerup.y < gameState.paddle.y + gameState.paddle.height &&
powerup.x > gameState.paddle.x &&
powerup.x < gameState.paddle.x + PADDLE_WIDTH * gameState.paddle.widthMultiplier) {
// Activate powerup
activatePowerup(powerup.type);
return false;
}
// Move powerup down
powerup.y += 2;
// Check if powerup is out of bounds
return powerup.y < CANVAS_HEIGHT;
});
}
// Update particles
function updateParticles() {
gameState.particles = gameState.particles.filter(particle => {
// Update particle position
particle.x += particle.dx;
particle.y += particle.dy;
particle.opacity -= 0.02;
particle.radius *= 0.98;
// Check if particle is still visible
return particle.opacity > 0 && particle.radius > 0.5;
});
}
// Update balls
function updateBalls() {
gameState.balls.forEach((ball, index) => {
// Move ball
ball.x += ball.dx;
ball.y += ball.dy;
// Ball collision with top and bottom
if (ball.y - ball.radius < 0) {
ball.dy = -ball.dy;
ball.y = ball.radius;
} else if (ball.y + ball.radius > CANVAS_HEIGHT) {
// Ball fell off the bottom - lose a life
gameState.balls.splice(index, 1);
gameState.lives--;
// If no balls left and lives > 0, add a new ball
if (gameState.balls.length === 0 && gameState.lives > 0) {
gameState.balls.push({
x: CANVAS_WIDTH / 2,
y: CANVAS_HEIGHT / 2,
radius: BALL_RADIUS,
dx: (Math.random() > 0.5 ? 1 : -1) * BALL_SPEED,
dy: -BALL_SPEED,
speed: BALL_SPEED
});
}
return;
}
// Ball collision with left and right walls
if (ball.x - ball.radius < 0) {
ball.dx = -ball.dx;
ball.x = ball.radius;
} else if (ball.x + ball.radius > CANVAS_WIDTH) {
ball.dx = -ball.dx;
ball.x = CANVAS_WIDTH - ball.radius;
}
// Ball collision with paddle
if (ball.y + ball.radius > gameState.paddle.y &&
ball.y - ball.radius < gameState.paddle.y + gameState.paddle.height &&
ball.x > gameState.paddle.x &&
ball.x < gameState.paddle.x + PADDLE_WIDTH * gameState.paddle.widthMultiplier) {
// Calculate bounce angle based on where ball hits paddle
const relativeIntersectX = (ball.x - (gameState.paddle.x + (PADDLE_WIDTH * gameState.paddle.widthMultiplier) / 2));
const normalizedRelativeIntersectionX = relativeIntersectX / (PADDLE_WIDTH * gameState.paddle.widthMultiplier / 2);
const bounceAngle = normalizedRelativeIntersectionX * Math.PI / 4;
// Calculate new direction
ball.dx = -ball.speed * Math.sin(bounceAngle);
ball.dy = -Math.abs(ball.speed * Math.cos(bounceAngle));
// Add some randomness to the bounce
ball.dx += (Math.random() - 0.5) * ball.speed * 0.5;
ball.dy += (Math.random() - 0.5) * ball.speed * 0.5;
// Ensure ball doesn't get stuck
if (ball.dy > 0) ball.dy = -Math.abs(ball.dy);
// Create particles
createParticles(ball.x, ball.y, 10, '#0095DD');
return;
}
// Ball collision with bricks
gameState.bricks.forEach((brick, brickIndex) => {
if (ball.y + ball.radius > brick.y &&
ball.y - ball.radius < brick.y + brick.height &&
ball.x + ball.radius > brick.x &&
ball.x - ball.radius < brick.x + brick.width) {
// Determine which side of the brick was hit
const brickTop = brick.y;
const brickBottom = brick.y + brick.height;
const brickLeft = brick.x;
const brickRight = brick.x + brick.width;
let hitFromTop = ball.y + ball.radius < brickTop + (brick.height / 2);
let hitFromBottom = ball.y - ball.radius > brickBottom - (brick.height / 2);
let hitFromLeft = ball.x + ball.radius < brickLeft + (brick.width / 2);
let hitFromRight = ball.x - ball.radius > brickRight - (brick.width / 2);
// If ball is hitting the corner, prioritize top/bottom or left/right
if (hitFromLeft && hitFromRight) hitFromLeft = ball.y + ball.radius < brick.y + (brick.height / 2);
if (hitFromTop && hitFromBottom) hitFromTop = ball.x + ball.radius < brick.x + (brick.width / 2);
// Reverse the appropriate velocity component
if (hitFromTop || hitFromBottom) {
ball.dy = -ball.dy;
} else {
ball.dx = -ball.dx;
}
// Reduce brick hits
brick.hits--;
// Create particles
createParticles(ball.x, ball.y, 15, brick.color);
// Check if brick is destroyed
if (brick.hits <= 0) {
// Remove brick
gameState.bricks.splice(brickIndex, 1);
// Add score
gameState.score += 10 * (brick.cracked ? 2 : 1);
// If brick had a powerup, add it to the powerups array
if (brick.powerupType) {
gameState.powerups.push({
x: brick.x + brick.width / 2,
y: brick.y,
type: brick.powerupType
});
}
// Update score display
scoreDisplay.textContent = gameState.score;
return;
} else if (brick.hits === 1) {
// Brick is now cracked
brick.cracked = true;
}
// Ensure ball doesn't get stuck in the brick
if (ball.dy > 0) ball.y = brick.y - ball.radius;
if (ball.dy < 0) ball.y = brick.y + brick.height + ball.radius;
if (ball.dx > 0) ball.x = brick.x - ball.radius;
if (ball.dx < 0) ball.x = brick.x + brick.width + ball.radius;
}
});
});
}
// Create particles
function createParticles(x, y, count, color) {
for (let i = 0; i < count; i++) {
gameState.particles.push({
x: x,
y: y,
radius: Math.random() * 5 + 2,
dx: (Math.random() - 0.5) * 3,
dy: (Math.random() - 0.5) * 3,
opacity: 1,
color: color
});
}
}
// Activate powerup
function activatePowerup(type) {
const powerup = POWERUP_TYPES[type];
if (type === POWERUP_TYPES.WIDER.id) {
gameState.paddle.widthMultiplier = 2;
} else if (type === POWERUP_TYPES.MULTI_BALL.id) {
// Add 2 more balls
for (let i = 0; i < 2; i++) {
gameState.balls.push({
x: CANVAS_WIDTH / 2,
y: CANVAS_HEIGHT / 2,
radius: BALL_RADIUS,
dx: (Math.random() > 0.5 ? 1 : -1) * BALL_SPEED,
dy: -BALL_SPEED,
speed: BALL_SPEED
});
}
}
// Set powerup active and start timer
gameState.powerupActive = type;
gameState.powerupTimer = setTimeout(() => {
gameState.paddle.widthMultiplier = 1;
gameState.powerupActive = null;
}, powerup.duration);
}
// Check game over
function checkGameOver() {
if (gameState.lives <= 0 && gameState.balls.length === 0) {
gameState.running = false;
gameState.gameOver = true;
finalScoreDisplay.textContent = gameState.score;
gameOverScreen.style.display = 'flex';
}
}
// Check victory
function checkVictory() {
if (gameState.bricks.length === 0 && !gameState.victory) {
gameState.running = false;
gameState.victory = true;
finalScoreVictoryDisplay.textContent = gameState.score;
victoryScreen.style.display = 'flex';
}
}
// Auto-start demo mode after a delay
setTimeout(() => {
if (!gameState.running) {
// Simulate mouse click to start
const event = new MouseEvent('click', {
view: window,
bubbles: true,
cancelable: true
});
startButton.dispatchEvent(event);
}
}, 1000);
</script>
</body>
</html>