Models 44

North Mini Code (free)

by CohereReasoning1 console error
Open in new window

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

How it went

Total time
24.4 s
Cost
$0
Output tokens
4,902
Spent thinking
0 tokens
Speed
202.7 tok/s
Console errors
1
First token after
239 ms
First visible text after
239 ms
Prompt tokens
495
Code size
15.6 KB
Finish reason
stop
Served by
Cohere
Model id
cohere/north-mini-code:free
Reasoning sent
{"effort":"none"}
Max output
32,000 tokens
Generated
Nov 9, 2026

Console errors

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

Cannot access 'brickGap' before initialization

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 · 539 lines

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <title>Polished Breakout Game</title>
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <style>
    :root {
      --paddle-width: 100px;
      --paddle-height: 12px;
      --ball-size: 10px;
      --brick-width: 70px;
      --brick-height: 20px;
      --brick-gap: 5px;
      --canvas-bg: #000;
      --paddle-color: #fff;
      --ball-color: #fff;
      --normal-brick: #e74c3c;
      --tough-brick: #f39c12;
      --powerup-brick: #9b59b6;
      --particle-color: rgba(255,255,255,0.8);
      --ui-color: #ddd;
    }
    body {
      margin:0;
      padding:0;
      background:#111;
      color:var(--ui-color);
      font-family:Arial,Helvetica,sans-serif;
      display:flex;
      align-items:center;
      justify-content:center;
      height:100vh;
      overflow:hidden;
    }
    canvas {
      display:block;
      background:var(--canvas-bg);
      border:2px solid var(--ui-color);
      box-shadow:0 0 20px rgba(255,255,255,0.2);
    }
    #overlay {
      position:absolute;
      top:0;left:0;width:100%;height:100%;
      background:rgba(0,0,0,0.7);
      display:flex;
      flex-direction:column;
      align-items:center;
      justify-content:center;
      z-index:10;
      transition:opacity 0.3s;
    }
    #overlay.hidden { opacity:0; pointer-events:none; }
    #overlay h1 { font-size:2.5rem; margin-bottom:0.5rem; }
    #overlay p { font-size:1.2rem; margin:0.5rem 0; }
    #overlay button {
      padding:0.8rem 1.5rem;
      font-size:1rem;
      background:var(--ui-color);
      border:none;
      border-radius:5px;
      cursor:pointer;
    }
    #overlay button:hover { background:#fff; }
    #score, #lives { position:absolute; top:10px; font-size:1.2rem; }
    #score { left:10px; }
    #lives { right:10px; }
    #powerup-icon {
      position:absolute;
      top:50px;
      right:10px;
      width:40px;height:40px;
      background:url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="%239b59b6"><path d="M12 2C6.5 2 2 6.5 2 12s4.5 10 10 10 10-4.5 10-10S17.5 2 12 2zm0 18c-4.41 0-8-3.59-8-8s3.59-8 8-8 8 3.59 8 8-3.59 8-8 8zm.5-13H11v6l5.2 3.2.8-1.3-4.5-2.7V7z"/></svg>') no-repeat center/contain;
      opacity:0;
      transition:opacity 0.3s;
    }
    #powerup-icon.visible { opacity:1; }
    #particle-canvas { position:absolute; top:0; left:0; width:100%; height:100%; pointer-events:none; }
  </style>
</head>
<body>
<div id="score">Score: 0</div>
<div id="lives">Lives: 3</div>
<div id="powerup-icon" title="Power‑up"></div>
<canvas id="gameCanvas" width="800" height="600"></canvas>
<canvas id="particleCanvas" width="800" height="600"></canvas>
<div id="overlay">
  <h1>Breakout</h1>
  <p>Click or press any key to start</p>
  <button id="restartBtn">Restart</button>
</div>

<script>
const canvas = document.getElementById('gameCanvas');
const ctx = canvas.getContext('2d');
const particleCanvas = document.getElementById('particleCanvas');
const particleCtx = particleCanvas.getContext('2d');
const scoreDisplay = document.getElementById('score');
const livesDisplay = document.getElementById('lives');
const powerupIcon = document.getElementById('powerup-icon');
const overlay = document.getElementById('overlay');
const restartBtn = document.getElementById('restartBtn');

let gameState = 'MENU'; // MENU, PLAYING, GAMEOVER, VICTORY
let animationFrameId = null;
let keys = {};

const paddle = {
  x: canvas.width/2 - 50,
  y: canvas.height - 30,
  width: 100,
  height: 12,
  dx: 0,
  color: '#fff'
};

const ball = {
  x: canvas.width/2,
  y: paddle.y - 10,
  radius: 10,
  dx: 0,
  dy: -5,
  speed: 5,
  count: 1 // number of balls (multi‑ball powerup)
};

const bricks = [];
const brickTypes = {
  normal: { hits:1, color:'#e74c3c', hasPowerup:false },
  tough: { hits:2, color:'#f39c12', hasPowerup:false },
  powerup: { hits:1, color:'#9b59b6', hasPowerup:true }
};

const particles = [];

// level layout helper
function createBricks() {
  bricks.length = 0;
  const rows = 6;
  const cols = Math.floor(canvas.width / (paddle.width/1.5)); // approximate
  const brickW = 70, brickH = 20;
  const totalWidth = brickW * cols + brickGap * (cols - 1);
  const startX = (canvas.width - totalWidth) / 2;
  const startY = 80;
  const brickGap = 5;
  const typeOrder = [];
  for (let r = 0; r < rows; r++) {
    for (let c = 0; c < cols; c++) {
      const rnd = Math.random();
      let type;
      if (rnd < 0.6) type = 'normal';
      else if (rnd < 0.9) type = 'tough';
      else type = 'powerup';
      typeOrder.push({type, x: startX + c*(brickW+brickGap), y: startY + r*(brickH+brickGap), w: brickW, h: brickH, hits:0});
    }
  }
  // shuffle a bit
  for (let i = typeOrder.length - 1; i > 0; i--) {
    const j = Math.floor(Math.random() * (i + 1));
    [typeOrder[i], typeOrder[j]] = [typeOrder[j], typeOrder[i]];
  }
  // assign based on order but keep distribution similar
  const counts = {normal:0, tough:0, powerup:0};
  for (let r = 0; r < rows; r++) {
    for (let c = 0; c < cols; c++) {
      const idx = r*cols + c;
      const desired = typeOrder[idx] ? typeOrder[idx].type : (Math.random()<0.6?'normal':Math.random()<0.9?'tough':'powerup');
      const b = {
        type: desired,
        x: startX + c*(brickW+brickGap),
        y: startY + r*(brickH+brickGap),
        w: brickW,
        h: brickH,
        hits: 0,
        maxHits: brickTypes[desired].hits,
        color: brickTypes[desired].color,
        hasPowerup: brickTypes[desired].hasPowerup
      };
      bricks.push(b);
      counts[desired]++;
    }
  }
  // ensure at least one powerup brick
  if (!bricks.some(b=>b.hasPowerup)) {
    const i = Math.floor(Math.random()*bricks.length);
    bricks[i].hasPowerup = true;
    bricks[i].color = brickTypes.powerup.color;
  }
}

function resetGame() {
  paddle.x = canvas.width/2 - paddle.width/2;
  paddle.dx = 0;
  ball.x = canvas.width/2;
  ball.y = paddle.y - ball.radius*2;
  ball.dx = 0;
  ball.dy = -5;
  ball.count = 1;
  lives = 3;
  score = 0;
  paddle.width = 100;
  powerupActive = null; // 'wide'|'multiball'|null
  powerupTimer = 0;
  bricks.length = 0;
  createBricks();
  particles.length = 0;
  scoreDisplay.textContent = `Score: ${score}`;
  livesDisplay.textContent = `Lives: ${lives}`;
  powerupIcon.classList.remove('visible');
  if (gameState !== 'MENU') {
    gameState = 'PLAYING';
    overlay.classList.add('hidden');
    loop();
  }
}

let lives = 3;
let score = 0;
let powerupActive = null;
let powerupTimer = 0;
let lastTime = 0;

function spawnParticles(x, y, count = 8) {
  for (let i = 0; i < count; i++) {
    particles.push({
      x, y,
      vx: (Math.random()-0.5)*6,
      vy: (Math.random()-0.5)*6,
      life: 30,
      color: brickTypes.normal.color // default, will use brick color when called
    });
  }
}

function updateParticles(dt) {
  for (let i = particles.length - 1; i >= 0; i--) {
    const p = particles[i];
    p.x += p.vx;
    p.y += p.vy;
    p.vy += 0.2; // gravity
    p.life -= dt;
    if (p.life <= 0) particles.splice(i, 1);
  }
}

function drawParticles() {
  particleCtx.clearRect(0,0,canvas.width,canvas.height);
  for (const p of particles) {
    particleCtx.beginPath();
    particleCtx.globalAlpha = p.life / 30;
    particleCtx.fillStyle = p.color;
    particleCtx.roundRect(p.x-3, p.y-3, 6, 6, [3]);
    particleCtx.fill();
    particleCtx.globalAlpha = 1;
  }
}

function drawPaddle() {
  ctx.fillStyle = paddle.color;
  ctx.fillRect(paddle.x, paddle.y, paddle.width, paddle.height);
}

function drawBall(b) {
  ctx.beginPath();
  ctx.fillStyle = ball.color;
  ctx.arc(b.x, b.y, b.radius, 0, Math.PI*2);
  ctx.fill();
  ctx.closePath();
}

function drawBricks() {
  bricks.forEach(b => {
    ctx.fillStyle = b.color;
    ctx.fillRect(b.x, b.y, b.w, b.h);
    // draw crack for tough bricks after first hit
    if (b.type==='tough' && b.hits>0) {
      ctx.strokeStyle = '#fff';
      ctx.lineWidth = 2;
      ctx.beginPath();
      ctx.moveTo(b.x, b.y+b.h/2);
      ctx.lineTo(b.x+b.w, b.y+b.h/2);
      ctx.stroke();
      ctx.closePath();
    }
    // draw powerup icon if hasPowerup and not broken
    if (b.hasPowerup && b.hits===0) {
      ctx.fillStyle = '#fff';
      ctx.font = '12px Arial';
      ctx.textAlign = 'center';
      ctx.fillText('●', b.x + b.w/2, b.y + b.h/2 + 5);
    }
  });
}

function drawUI() {
  scoreDisplay.textContent = `Score: ${score}`;
  livesDisplay.textContent = `Lives: ${lives}`;
  if (powerupActive==='wide') {
    const percent = Math.max(0, (powerupTimer-2000)/8000); // show after 2s, full at 10s
    ctx.save();
    ctx.fillStyle = 'rgba(255,255,255,0.3)';
    ctx.fillRect(canvas.width/2-60, 20, 120, 6);
    ctx.fillStyle = '#fff';
    ctx.font = '10px Arial';
    ctx.textAlign = 'center';
    ctx.fillText(`WIDE PADDLE ${Math.ceil(percent*10)}s`, canvas.width/2, 32);
    ctx.restore();
  } else if (powerupActive==='multiball') {
    const percent = Math.max(0, (powerupTimer-2000)/8000);
    ctx.save();
    ctx.fillStyle = 'rgba(255,255,255,0.3)';
    ctx.fillRect(canvas.width/2-60, 20, 120, 6);
    ctx.fillStyle = '#fff';
    ctx.font = '10px Arial';
    ctx.textAlign = 'center';
    ctx.fillText(`MULTI BALL ${Math.ceil(percent*10)}s`, canvas.width/2, 32);
    ctx.restore();
  }
}

function checkCollisions() {
  // ball vs walls
  if (ball.x - ball.radius < 0 || ball.x + ball.radius > canvas.width) {
    ball.dx = -ball.dx;
  }
  if (ball.y - ball.radius < 0) {
    ball.dy = -ball.dy;
  }
  // paddle
  if (ball.y + ball.radius >= paddle.y &&
      ball.x >= paddle.x && ball.x <= paddle.x + paddle.width) {
    // hit
    const hitPos = (ball.x - paddle.x) / paddle.width; // 0 to 1
    let angle = (hitPos - 0.5) * Math.PI / 3; // max ±30°
    ball.dx = Math.sin(angle) * ball.speed * 2;
    ball.dy = -Math.abs(ball.dy); // always bounce up
    // add some velocity based on speed
    if (Math.abs(ball.dx) < 1) ball.dx = ball.dx >=0 ? 1 : -1;
  } else if (ball.y + ball.radius > canvas.height) {
    // miss
    lives--;
    resetBallPosition();
    if (lives <= 0) {
      gameState = 'GAMEOVER';
      overlay.classList.remove('hidden');
      document.querySelector('#overlay h1').textContent = 'Game Over';
      document.querySelector('#overlay p').textContent = `Final Score: ${score}`;
    }
  }

  // ball vs bricks
  for (let i = bricks.length - 1; i >= 0; i--) {
    const b = bricks[i];
    if (ball.x + ball.radius > b.x && ball.x - ball.radius < b.x + b.w &&
        ball.y - ball.radius < b.y + b.h && ball.y + ball.radius > b.y) {
      // determine side
      const left = ball.x - ball.radius < b.x + b.w/2;
      const right = !left;
      const top = ball.y - ball.radius < b.y + b.h/2;
      const bottom = !top;
      // push away
      if (left) ball.dx = -Math.abs(ball.dx) - 2;
      if (right) ball.dx = Math.abs(ball.dx) + 2;
      if (top) ball.dy = -Math.abs(ball.dy) - 2;
      if (bottom) ball.dy = Math.abs(ball.dy) + 2;
      // damage brick
      b.hits++;
      if (b.hasPowerup && b.hits===1) {
        // powerup appears after first hit (normal or tough)
        powerupIcon.classList.add('visible');
        powerupTimer = Date.now();
      }
      if (b.hits >= b.maxHits) {
        // brick broken
        score += 100 + b.maxHits*50;
        spawnParticles(b.x + b.w/2, b.y + b.h/2, 12);
        // drop powerup chance
        if (b.hasPowerup && b.maxHits===1) {
          // drop icon at brick center, will be caught by paddle
          droppedPowerup = {x: b.x + b.w/2, y: b.y + b.h/2, radius:5, active:true};
        }
        bricks.splice(i,1);
      } else {
        // spawn particles for first hit of tough brick
        spawnParticles(b.x + b.w/2, b.y + b.h/2, 6);
        // change color visual? maybe keep same
      }
    }
  }

  // paddle catching dropped powerup
  if (droppedPowerup && droppedPowerup.active) {
    if (ball.x >= droppedPowerup.x - droppedPowerup.radius &&
        ball.x <= droppedPowerup.x + droppedPowerup.radius &&
        ball.y >= paddle.y && ball.y <= paddle.y + paddle.height) {
      // catch
      applyPowerup();
      droppedPowerup.active = false;
    }
    droppedPowerup.y += 2; // fall down
    if (droppedPowerup.y > canvas.height) droppedPowerup.active = false;
  }
}

function applyPowerup() {
  powerupIcon.classList.remove('visible');
  // choose randomly between wide and multi-ball (or toggle)
  const choice = Math.random() > 0.5 ? 'wide' : 'multiball';
  powerupActive = choice;
  powerupTimer = Date.now();
  if (choice === 'wide') {
    paddle.width = 150;
    // extra ball?
  } else if (choice === 'multiball') {
    ball.count = 3;
    // create extra balls if not already
    extraBalls = [{...ball, dx: -ball.dx, dy: -ball.dy}]; // placeholder
  }
}

function resetBallPosition() {
  ball.x = canvas.width/2;
  ball.y = paddle.y - ball.radius*2;
  ball.dx = 0;
  ball.dy = -5;
  ball.count = 1;
  extraBalls = [];
}

function drawGame() {
  ctx.clearRect(0,0,canvas.width,canvas.height);
  drawBricks();
  drawPaddle();
  // draw multiple balls
  drawBall(ball);
  if (extraBalls) extraBalls.forEach(drawBall);
  drawUI();
  updateParticles(16);
  drawParticles();
  if (droppedPowerup && droppedPowerup.active) {
    ctx.beginPath();
    ctx.fillStyle = '#fff';
    ctx.arc(droppedPowerup.x, droppedPowerup.y, droppedPowerup.radius, 0, Math.PI*2);
    ctx.fill();
  }
}

function update(dt) {
  if (gameState !== 'PLAYING') return;
  // paddle movement
  paddle.x += paddle.dx;
  paddle.x = Math.max(0, Math.min(canvas.width - paddle.width, paddle.x));
  // ball movement
  ball.x += ball.dx;
  ball.y += ball.dy;
  // powerup timers
  if (powerupActive) {
    const elapsed = Date.now() - powerupTimer;
    if (elapsed > 10000) { // 10 seconds
      // deactivate
      if (powerupActive==='wide') paddle.width = 100;
      else if (powerupActive==='multiball') ball.count = 1;
      powerupActive = null;
    }
  }
  // check victory
  if (bricks.length === 0) {
    gameState = 'VICTORY';
    overlay.classList.remove('hidden');
    document.querySelector('#overlay h1').textContent = 'Victory!';
    document.querySelector('#overlay p').textContent = `Score: ${score}`;
  }
  checkCollisions();
  drawGame();
}

function loop(timestamp = 0) {
  const dt = Math.min(timestamp - lastTime, 32);
  lastTime = timestamp;
  update(dt);
  animationFrameId = requestAnimationFrame(loop);
}

// input
canvas.addEventListener('click', e => {
  if (gameState==='MENU') {
    gameState='PLAYING';
    overlay.classList.add('hidden');
    loop();
  } else if (gameState==='GAMEOVER' || gameState==='VICTORY') {
    resetGame();
  }
});

document.addEventListener('keydown', e => {
  if (e.code==='ArrowLeft') keys.left = true;
  if (e.code==='ArrowRight') keys.right = true;
  if (gameState==='MENU' && !(e.code==='ArrowLeft'||e.code==='ArrowRight')) {
    gameState='PLAYING';
    overlay.classList.add('hidden');
    loop();
  }
});
document.addEventListener('keyup', e => {
  if (e.code==='ArrowLeft') keys.left = false;
  if (e.code==='ArrowRight') keys.right = false;
});

canvas.addEventListener('mousemove', e => {
  const rect = canvas.getBoundingClientRect();
  const mx = e.clientX - rect.left;
  if (mx >= 0 && mx <= canvas.width) {
    paddle.x = mx - paddle.width/2;
  }
});

// start paddle movement on keydown
document.addEventListener('keydown', () => {
  paddle.dx = (keys.right ? 5 : (keys.left ? -5 : 0));
});

// ensure paddle moves when keys held
document.addEventListener('keyup', () => {
  paddle.dx = (keys.right ? 5 : (keys.left ? -5 : 0));
});

let extraBalls = [];
let droppedPowerup = {active:false};

createBricks();
resetGame();
// initial hide overlay for menu state
overlay.querySelector('h1').textContent = 'Breakout';
overlay.querySelector('p').textContent = 'Click or press any key to start';
overlay.querySelector('#restartBtn').style.display = 'none';
overlay.classList.add('hidden'); // hide while menu
</script>
</body>
</html>