Mistral Small 4
by MistralReasoningClean
Running live in a sandboxed frame. Click inside it before using the keyboard.
How it went
- Total time
- 23.5 s
- Cost
- $0.0032
- Output tokens
- 4,828
- Spent thinking
- 0 tokens
- Speed
- 209.8 tok/s
- Console errors
- 0
- First token after
- 504 ms
- First visible text after
- 504 ms
- Prompt tokens
- 532
- Code size
- 22.4 KB
- Finish reason
- stop
- Served by
- Mistral
- Model id
mistralai/mistral-small-2603- Reasoning sent
model default- 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 · 628 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;
background: #111;
color: #eee;
font-family: Arial, sans-serif;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
height: 100vh;
overflow: hidden;
}
#game-container {
position: relative;
width: 100%;
max-width: 800px;
height: 600px;
background: #000;
border-radius: 8px;
overflow: hidden;
}
canvas {
display: block;
background: #000;
}
#ui {
position: absolute;
top: 20px;
left: 20px;
right: 20px;
display: flex;
justify-content: space-between;
font-size: 18px;
}
#start-screen, #game-over, #victory {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.8);
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
z-index: 10;
display: none;
}
#start-screen h1, #game-over h1, #victory h1 {
font-size: 48px;
margin-bottom: 20px;
text-shadow: 0 0 10px #fff;
}
#start-screen button, #game-over button, #victory button {
padding: 12px 24px;
font-size: 18px;
background: #4CAF50;
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
transition: background 0.3s;
}
#start-screen button:hover, #game-over button:hover, #victory button:hover {
background: #45a049;
}
#power-up-indicator {
position: absolute;
bottom: 20px;
left: 50%;
transform: translateX(-50%);
background: rgba(0, 0, 0, 0.7);
padding: 8px 16px;
border-radius: 4px;
font-size: 16px;
display: none;
}
.particle {
position: absolute;
width: 4px;
height: 4px;
background: #fff;
border-radius: 50%;
}
</style>
</head>
<body>
<div id="game-container">
<div id="ui">
<div>Lives: <span id="lives">3</span></div>
<div>Score: <span id="score">0</span></div>
</div>
<canvas id="game-canvas" width="800" height="600"></canvas>
<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">
<h1>Game Over</h1>
<p id="final-score">Score: 0</p>
<button id="restart-button">Play Again</button>
</div>
<div id="victory">
<h1>Victory!</h1>
<p id="final-victory-score">Score: 0</p>
<button id="victory-restart-button">Play Again</button>
</div>
<div id="power-up-indicator"></div>
</div>
<script>
document.addEventListener('DOMContentLoaded', () => {
const canvas = document.getElementById('game-canvas');
const ctx = canvas.getContext('2d');
const livesDisplay = document.getElementById('lives');
const scoreDisplay = document.getElementById('score');
const finalScoreDisplay = document.getElementById('final-score');
const finalVictoryScoreDisplay = document.getElementById('final-victory-score');
const startScreen = document.getElementById('start-screen');
const gameOverScreen = document.getElementById('game-over');
const victoryScreen = document.getElementById('victory');
const startButton = document.getElementById('start-button');
const restartButton = document.getElementById('restart-button');
const victoryRestartButton = document.getElementById('victory-restart-button');
const powerUpIndicator = document.getElementById('power-up-indicator');
// Game state
let gameRunning = false;
let gameOver = false;
let victory = false;
let powerUpActive = false;
let powerUpType = '';
let powerUpEndTime = 0;
let multiBallActive = false;
// Game dimensions
const PADDLE_WIDTH = 100;
const PADDLE_HEIGHT = 15;
const BALL_RADIUS = 8;
const BRICK_WIDTH = 80;
const BRICK_HEIGHT = 20;
const BRICK_GAP = 4;
const PADDLE_SPEED = 8;
const BALL_SPEED = 5;
// Game elements
let paddle = {
x: canvas.width / 2 - PADDLE_WIDTH / 2,
y: canvas.height - 30,
width: PADDLE_WIDTH,
height: PADDLE_HEIGHT,
speed: PADDLE_SPEED,
leftKey: false,
rightKey: false
};
let ball = {
x: canvas.width / 2,
y: canvas.height - 50,
radius: BALL_RADIUS,
dx: BALL_SPEED,
dy: -BALL_SPEED,
visible: false
};
let bricks = [];
let particles = [];
let powerUps = [];
// Game stats
let score = 0;
let lives = 3;
// Initialize bricks
function initBricks() {
bricks = [];
const rows = 6;
const cols = Math.floor(canvas.width / (BRICK_WIDTH + BRICK_GAP));
for (let r = 0; r < rows; r++) {
for (let c = 0; c < cols; c++) {
const brickX = c * (BRICK_WIDTH + BRICK_GAP) + BRICK_GAP;
const brickY = r * (BRICK_HEIGHT + BRICK_GAP) + 50;
const isSpecial = Math.random() < 0.2;
const isPowerUp = Math.random() < 0.3 && r > 1;
bricks.push({
x: brickX,
y: brickY,
width: BRICK_WIDTH,
height: BRICK_HEIGHT,
hits: isSpecial ? 2 : 1,
active: true,
isSpecial: isSpecial,
isPowerUp: isPowerUp,
powerUpType: isPowerUp ? (Math.random() < 0.5 ? 'paddle' : 'multi') : null
});
}
}
}
// Initialize game
function initGame() {
paddle.x = canvas.width / 2 - PADDLE_WIDTH / 2;
paddle.y = canvas.height - 30;
ball.x = canvas.width / 2;
ball.y = canvas.height - 50;
ball.dx = BALL_SPEED;
ball.dy = -BALL_SPEED;
ball.visible = false;
score = 0;
lives = 3;
livesDisplay.textContent = lives;
scoreDisplay.textContent = score;
gameOver = false;
victory = false;
powerUpActive = false;
powerUpType = '';
multiBallActive = false;
powerUpIndicator.style.display = 'none';
initBricks();
particles = [];
powerUps = [];
startScreen.style.display = 'none';
gameOverScreen.style.display = 'none';
victoryScreen.style.display = 'none';
gameRunning = false;
}
// Draw paddle
function drawPaddle() {
ctx.beginPath();
ctx.rect(paddle.x, paddle.y, paddle.width, paddle.height);
ctx.fillStyle = '#4CAF50';
ctx.fill();
ctx.closePath();
}
// Draw ball
function drawBall() {
ctx.beginPath();
ctx.arc(ball.x, ball.y, ball.radius, 0, Math.PI * 2);
ctx.fillStyle = '#fff';
ctx.fill();
ctx.closePath();
}
// Draw bricks
function drawBricks() {
bricks.forEach(brick => {
if (brick.active) {
ctx.beginPath();
ctx.rect(brick.x, brick.y, brick.width, brick.height);
ctx.fillStyle = brick.isSpecial ? '#F44336' : '#2196F3';
ctx.fill();
ctx.closePath();
// Draw cracks for special bricks
if (brick.isSpecial && brick.hits === 1) {
ctx.beginPath();
ctx.moveTo(brick.x + 5, brick.y + 5);
ctx.lineTo(brick.x + brick.width - 5, brick.y + brick.height - 5);
ctx.moveTo(brick.x + brick.width - 5, brick.y + 5);
ctx.lineTo(brick.x + 5, brick.y + brick.height - 5);
ctx.strokeStyle = '#fff';
ctx.lineWidth = 2;
ctx.stroke();
ctx.closePath();
}
// Draw power-up icon
if (brick.isPowerUp) {
ctx.beginPath();
ctx.arc(brick.x + brick.width / 2, brick.y + brick.height / 2, 5, 0, Math.PI * 2);
ctx.fillStyle = brick.powerUpType === 'paddle' ? '#FFEB3B' : '#9C27B0';
ctx.fill();
ctx.closePath();
}
}
});
}
// Draw particles
function drawParticles() {
particles.forEach(particle => {
ctx.beginPath();
ctx.arc(particle.x, particle.y, particle.radius, 0, Math.PI * 2);
ctx.fillStyle = particle.color;
ctx.fill();
ctx.closePath;
});
}
// Draw power-ups
function drawPowerUps() {
powerUps.forEach(powerUp => {
ctx.beginPath();
ctx.arc(powerUp.x, powerUp.y, powerUp.radius, 0, Math.PI * 2);
ctx.fillStyle = powerUp.type === 'paddle' ? '#FFEB3B' : '#9C27B0';
ctx.fill();
ctx.closePath;
// Draw icon
ctx.beginPath();
if (powerUp.type === 'paddle') {
ctx.rect(powerUp.x - 4, powerUp.y - 4, 8, 8);
} else {
ctx.arc(powerUp.x, powerUp.y, 4, 0, Math.PI * 2);
}
ctx.fillStyle = '#000';
ctx.fill();
ctx.closePath;
});
}
// Update paddle position
function updatePaddle() {
if (paddle.leftKey) {
paddle.x -= paddle.speed;
if (paddle.x < 0) paddle.x = 0;
}
if (paddle.rightKey) {
paddle.x += paddle.speed;
if (paddle.x + paddle.width > canvas.width) {
paddle.x = canvas.width - paddle.width;
}
}
// Mouse control
canvas.addEventListener('mousemove', (e) => {
if (!gameRunning && !gameOver && !victory) return;
const rect = canvas.getBoundingClientRect();
const mouseX = e.clientX - rect.left;
paddle.x = mouseX - paddle.width / 2;
if (paddle.x < 0) paddle.x = 0;
if (paddle.x + paddle.width > canvas.width) {
paddle.x = canvas.width - paddle.width;
}
});
}
// Update ball position
function updateBall() {
if (!ball.visible) return;
ball.x += ball.dx;
ball.y += ball.dy;
// Wall collision (left/right)
if (ball.x - ball.radius < 0 || ball.x + ball.radius > canvas.width) {
ball.dx = -ball.dx;
}
// Wall collision (top)
if (ball.y - ball.radius < 0) {
ball.dy = -ball.dy;
}
// Paddle collision
if (ball.y + ball.radius > paddle.y &&
ball.y - ball.radius < paddle.y + paddle.height &&
ball.x > paddle.x &&
ball.x < paddle.x + paddle.width) {
// Calculate bounce angle based on where ball hits paddle
const hitPosition = (ball.x - (paddle.x + paddle.width / 2)) / (paddle.width / 2);
const angle = hitPosition * (Math.PI / 3); // Max angle of 60 degrees
// Reflect ball with new angle
ball.dy = -Math.abs(BALL_SPEED * Math.cos(angle));
ball.dx = BALL_SPEED * Math.sin(angle);
// Ensure minimum speed
if (Math.abs(ball.dx) < 2) {
ball.dx = ball.dx > 0 ? 2 : -2;
}
}
// Bottom collision (lose life)
if (ball.y + ball.radius > canvas.height) {
lives--;
livesDisplay.textContent = lives;
resetBall();
if (lives <= 0) {
gameOver = true;
finalScoreDisplay.textContent = `Score: ${score}`;
gameOverScreen.style.display = 'flex';
}
}
}
// Reset ball to paddle
function resetBall() {
ball.x = paddle.x + paddle.width / 2;
ball.y = paddle.y - ball.radius;
ball.dx = 0;
ball.dy = 0;
ball.visible = false;
gameRunning = false;
}
// Check brick collisions
function checkBrickCollisions() {
bricks.forEach(brick => {
if (!brick.active) return;
// Ball collision with brick
if (ball.x + ball.radius > brick.x &&
ball.x - ball.radius < brick.x + brick.width &&
ball.y + ball.radius > brick.y &&
ball.y - ball.radius < brick.y + brick.height) {
// Calculate bounce angle based on where ball hits brick
const hitPosition = (ball.x - brick.x) / brick.width;
const angle = (hitPosition - 0.5) * (Math.PI / 2);
ball.dx = BALL_SPEED * Math.sin(angle);
ball.dy = -Math.abs(BALL_SPEED * Math.cos(angle));
// Ensure minimum speed
if (Math.abs(ball.dx) < 2) {
ball.dx = ball.dx > 0 ? 2 : -2;
}
// Decrease brick hits or destroy it
if (brick.isSpecial) {
brick.hits--;
if (brick.hits <= 0) {
brick.active = false;
createParticles(brick.x + brick.width / 2, brick.y + brick.height / 2);
score += 50;
scoreDisplay.textContent = score;
} else {
createParticles(brick.x + brick.width / 2, brick.y + brick.height / 2);
}
} else {
brick.active = false;
createParticles(brick.x + brick.width / 2, brick.y + brick.height / 2);
score += 10;
scoreDisplay.textContent = score;
}
// Check for power-up drop
if (brick.isPowerUp && brick.active === false) {
powerUps.push({
x: brick.x + brick.width / 2,
y: brick.y + brick.height / 2,
radius: 8,
type: brick.powerUpType,
speed: 2
});
}
// Check for victory
if (bricks.every(b => !b.active)) {
victory = true;
finalVictoryScoreDisplay.textContent = `Score: ${score}`;
victoryScreen.style.display = 'flex';
}
}
});
}
// Create particles
function createParticles(x, y) {
const particleCount = 20;
for (let i = 0; i < particleCount; i++) {
particles.push({
x: x,
y: y,
radius: Math.random() * 3 + 1,
dx: (Math.random() - 0.5) * 4,
dy: (Math.random() - 0.5) * 4,
color: `hsl(${Math.random() * 60 + 200}, 100%, 50%)`,
life: 30
});
}
}
// Update particles
function updateParticles() {
for (let i = particles.length - 1; i >= 0; i--) {
particles[i].x += particles[i].dx;
particles[i].y += particles[i].dy;
particles[i].life--;
if (particles[i].life <= 0) {
particles.splice(i, 1);
}
}
}
// Update power-ups
function updatePowerUps() {
for (let i = powerUps.length - 1; i >= 0; i--) {
powerUps[i].y += powerUps[i].speed;
// Check if power-up is caught by paddle
if (powerUps[i].y + powerUps[i].radius > paddle.y &&
powerUps[i].y - powerUps[i].radius < paddle.y + paddle.height &&
powerUps[i].x > paddle.x &&
powerUps[i].x < paddle.x + paddle.width) {
// Activate power-up
powerUpType = powerUps[i].type;
powerUpActive = true;
powerUpEndTime = Date.now() + 10000; // 10 seconds
if (powerUpType === 'paddle') {
paddle.width = 150;
powerUpIndicator.textContent = 'Paddle enlarged!';
} else if (powerUpType === 'multi') {
multiBallActive = true;
powerUpIndicator.textContent = 'Multi-ball!';
}
powerUpIndicator.style.display = 'block';
powerUps.splice(i, 1);
}
// Remove power-ups that fall off screen
if (powerUps[i].y > canvas.height) {
powerUps.splice(i, 1);
}
}
// Check if power-up duration has ended
if (powerUpActive && Date.now() > powerUpEndTime) {
powerUpActive = false;
if (powerUpType === 'paddle') {
paddle.width = PADDLE_WIDTH;
} else if (powerUpType === 'multi') {
multiBallActive = false;
}
powerUpIndicator.style.display = 'none';
}
}
// Game loop
function gameLoop() {
if (gameOver || victory) return;
ctx.clearRect(0, 0, canvas.width, canvas.height);
updatePaddle();
updateBall();
checkBrickCollisions();
updateParticles();
updatePowerUps();
drawBricks();
drawPowerUps();
drawParticles();
drawPaddle();
drawBall();
if (!ball.visible && !gameRunning) {
ball.x = paddle.x + paddle.width / 2;
ball.y = paddle.y - ball.radius;
}
requestAnimationFrame(gameLoop);
}
// Start game
function startGame() {
initGame();
gameLoop();
}
// Event listeners
startButton.addEventListener('click', () => {
startScreen.style.display = 'none';
gameRunning = true;
ball.visible = true;
});
restartButton.addEventListener('click', startGame);
victoryRestartButton.addEventListener('click', startGame);
document.addEventListener('keydown', (e) => {
if (e.key === 'ArrowLeft') paddle.leftKey = true;
if (e.key === 'ArrowRight') paddle.rightKey = true;
if (e.key === ' ' && !gameRunning && !gameOver && !victory) {
startScreen.style.display = 'none';
gameRunning = true;
ball.visible = true;
}
});
document.addEventListener('keyup', (e) => {
if (e.key === 'ArrowLeft') paddle.leftKey = false;
if (e.key === 'ArrowRight') paddle.rightKey = false;
});
// Initialize game on load
initGame();
});
</script>
</body>
</html>