Gemma 4 31B
by Googlereasoning default1 console error
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>