Models 44

DeepSeek V4 Flash 0423

by DeepSeekreasoning defaultClean
Open in new window

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

How it went

Total time
46.8 s
Cost
$0.0011
Output tokens
6,069
Spent thinking
0 tokens
Speed
131.2 tok/s
Console errors
0
First token after
560 ms
First visible text after
560 ms
Prompt tokens
508
Code size
19.3 KB
Finish reason
stop
Served by
DeepInfra
Model id
deepseek/deepseek-v4-flash
Reasoning sent
model default
Max output
393,216 tokens
Generated
Nov 13, 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 · 650 lines

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
  <title>BREAKOUT · brick breaker</title>
  <style>
    * {
      box-sizing: border-box;
      user-select: none;
    }
    body {
      margin: 0;
      min-height: 100vh;
      background: radial-gradient(circle at 30% 10%, #0f172a, #020617);
      display: flex;
      justify-content: center;
      align-items: center;
      font-family: 'Segoe UI', Roboto, system-ui, sans-serif;
    }
    .game-container {
      background: #1e293b;
      padding: 24px 24px 32px;
      border-radius: 48px 48px 32px 32px;
      box-shadow: 0 20px 30px rgba(0,0,0,0.7), inset 0 1px 3px rgba(255,255,255,0.1);
    }
    canvas {
      display: block;
      margin: 0 auto;
      width: 800px;
      height: 500px;
      border-radius: 24px;
      box-shadow: inset 0 0 0 1px #334155, 0 12px 20px -6px black;
      background: #0b1120;
      cursor: none;
      touch-action: none;
    }
    .status-bar {
      display: flex;
      justify-content: space-between;
      align-items: center;
      margin: 18px 8px 0;
      color: #e2e8f0;
      font-weight: 600;
      letter-spacing: 0.3px;
      text-shadow: 0 2px 3px #00000060;
    }
    .lives span {
      color: #ef4444;
      font-size: 1.2rem;
      margin-right: 6px;
    }
    .score span {
      color: #facc15;
      font-size: 1.3rem;
    }
    .message-overlay {
      position: absolute;
      top: 0; left: 0; width: 100%; height: 100%;
      display: flex;
      flex-direction: column;
      justify-content: center;
      align-items: center;
      background: rgba(0,0,0,0.55);
      backdrop-filter: blur(2.5px);
      color: white;
      border-radius: 24px;
      pointer-events: none;
      opacity: 0;
      transition: opacity 0.25s;
    }
    .message-overlay.show {
      opacity: 1;
      pointer-events: auto;
    }
    .message-overlay h2 {
      font-size: 2.8rem;
      margin: 0 0 6px;
      background: linear-gradient(135deg, #fcd34d, #f59e0b);
      -webkit-background-clip: text;
      background-clip: text;
      color: transparent;
      text-shadow: 0 4px 10px black;
      letter-spacing: 1px;
    }
    .message-overlay p {
      font-size: 1.2rem;
      background: #1e293be0;
      padding: 10px 28px;
      border-radius: 80px;
      backdrop-filter: blur(2px);
      border: 1px solid #ffffff30;
      cursor: pointer;
      transition: 0.2s;
      margin-top: 16px;
      font-weight: 500;
    }
    .message-overlay p:hover {
      background: #2d3b50e0;
      transform: scale(1.02);
      border-color: #facc15;
    }
    .canvas-wrapper {
      position: relative;
      display: inline-block;
    }
    @media (max-width: 860px) {
      .game-container { padding: 12px; border-radius: 28px; }
      canvas { width: 100%; height: auto; aspect-ratio: 800/500; }
    }
  </style>
</head>
<body>
<div class="game-container">
  <div class="canvas-wrapper">
    <canvas id="gameCanvas" width="800" height="500"></canvas>
    <div id="overlay" class="message-overlay">
      <h2 id="overlayTitle">BREAKOUT</h2>
      <p id="overlayAction">Click or press a key to start</p>
    </div>
  </div>
  <div class="status-bar">
    <div class="lives"><span>❤️</span> <span id="livesDisplay">3</span></div>
    <div class="score"><span>🏆</span> <span id="scoreDisplay">0</span></div>
  </div>
</div>
<script>
  (function() {
    const canvas = document.getElementById('gameCanvas');
    const ctx = canvas.getContext('2d');
    const overlay = document.getElementById('overlay');
    const overlayTitle = document.getElementById('overlayTitle');
    const overlayAction = document.getElementById('overlayAction');
    const livesSpan = document.getElementById('livesDisplay');
    const scoreSpan = document.getElementById('scoreDisplay');

    // ----------  GAME STATE ----------
    const W = 800, H = 500;
    let gameState = 'idle'; // 'idle' | 'running' | 'gameover' | 'victory'
    let score = 0;
    let lives = 3;

    // paddle
    const PADDLE_W = 110, PADDLE_H = 16;
    let paddle = { x: (W - PADDLE_W) / 2, y: H - 35, w: PADDLE_W, h: PADDLE_H };

    // ball(s)
    let balls = [];
    const BALL_RADIUS = 7;
    const BASE_SPEED = 4.8;

    // bricks
    let bricks = [];
    const BRICK_W = 70, BRICK_H = 22;
    const BRICK_ROWS = 7;
    const BRICK_COLS = 10;

    // power ups
    let powerups = []; // { x, y, w, h, type, speed }

    // particles
    let particles = [];

    // timers
    let widePaddleTimer = 0;
    const WIDE_DURATION = 600; // frames (10 sec at 60fps)
    const WIDE_PADDLE_W = 165;

    // multi-ball flag (only from brick)
    let multiBallActive = false;

    // keys
    let leftPressed = false, rightPressed = false;

    // mouse
    let mouseX = null;

    // ----------  INIT LEVEL ----------
    function buildLevel() {
      bricks = [];
      for (let row = 0; row < BRICK_ROWS; row++) {
        for (let col = 0; col < BRICK_COLS; col++) {
          let type = 'normal';
          let hp = 1;
          // tougher bricks: rows 1, 3, 5 (0-indexed)
          if (row === 1 || row === 3 || row === 5) {
            type = 'tough';
            hp = 2;
          }
          // power-up bricks: random 20% on normal bricks (and some tough)
          let powerUp = null;
          const r = Math.random();
          if ((type === 'normal' && r < 0.20) || (type === 'tough' && r < 0.15)) {
            powerUp = Math.random() < 0.5 ? 'wide' : 'multiball';
          }
          const x = col * (BRICK_W + 7) + 23;
          const y = row * (BRICK_H + 7) + 35;
          bricks.push({
            x, y, w: BRICK_W, h: BRICK_H,
            type, hp, maxHp: hp,
            powerUp,
            cracked: false
          });
        }
      }
    }

    // ----------  BALL HELPERS ----------
    function spawnBall(x, y, angle = null) {
      let speed = BASE_SPEED;
      let dx, dy;
      if (angle !== null) {
        dx = Math.cos(angle) * speed;
        dy = -Math.sin(angle) * speed;
      } else {
        // default: slight random variation upward
        let a = -Math.PI/2 + (Math.random() - 0.5) * 0.8;
        dx = Math.cos(a) * speed;
        dy = -Math.sin(a) * speed;
      }
      balls.push({ x, y, r: BALL_RADIUS, dx, dy, speed });
    }

    function resetBall(keepMultiball = false) {
      balls = [];
      if (!keepMultiball) multiBallActive = false;
      spawnBall(W/2, paddle.y - 18);
    }

    // ----------  RESET GAME ----------
    function fullReset() {
      score = 0;
      lives = 3;
      widePaddleTimer = 0;
      multiBallActive = false;
      paddle.w = PADDLE_W;
      paddle.x = (W - paddle.w) / 2;
      buildLevel();
      resetBall(false);
      powerups = [];
      particles = [];
      leftPressed = false;
      rightPressed = false;
      updateUI();
    }

    // ----------  UI UPDATE ----------
    function updateUI() {
      livesSpan.textContent = lives;
      scoreSpan.textContent = score;
    }

    // ----------  COLLISION & PHYSICS ----------
    function ballBrickCollision(ball, brick) {
      // closest point on brick to ball
      let cx = Math.max(brick.x, Math.min(ball.x, brick.x + brick.w));
      let cy = Math.max(brick.y, Math.min(ball.y, brick.y + brick.h));
      let dx = ball.x - cx;
      let dy = ball.y - cy;
      let dist = Math.sqrt(dx*dx + dy*dy);
      if (dist < ball.r) {
        // normal
        let nx = dx / dist || 0;
        let ny = dy / dist || -1;
        // reflect
        let dot = ball.dx * nx + ball.dy * ny;
        ball.dx -= 2 * dot * nx;
        ball.dy -= 2 * dot * ny;
        // push outside
        let overlap = ball.r - dist;
        ball.x += nx * overlap;
        ball.y += ny * overlap;
        return true;
      }
      return false;
    }

    function ballPaddleCollision(ball) {
      if (ball.y + ball.r > paddle.y && ball.y - ball.r < paddle.y + paddle.h &&
          ball.x + ball.r > paddle.x && ball.x - ball.r < paddle.x + paddle.w) {
        // relative hit position -1 .. 1
        let rel = (ball.x - (paddle.x + paddle.w/2)) / (paddle.w/2);
        rel = Math.max(-1, Math.min(1, rel));
        let angle = -Math.PI/2 + rel * (Math.PI/3.2); // max 60° deflection
        let speed = Math.sqrt(ball.dx*ball.dx + ball.dy*ball.dy);
        ball.dx = Math.cos(angle) * speed;
        ball.dy = -Math.sin(angle) * speed;
        // push above
        ball.y = paddle.y - ball.r;
        return true;
      }
      return false;
    }

    // ----------  POWER UPS ----------
    function spawnPowerup(x, y, type) {
      powerups.push({
        x, y, w: 24, h: 14,
        type,
        speed: 2.2
      });
    }

    // ----------  PARTICLES ----------
    function emitParticles(x, y, color, count = 14) {
      for (let i = 0; i < count; i++) {
        const angle = Math.random() * 2 * Math.PI;
        const speed = 1.2 + Math.random() * 3.2;
        particles.push({
          x, y,
          vx: Math.cos(angle) * speed,
          vy: Math.sin(angle) * speed,
          life: 1.0,
          decay: 0.012 + Math.random() * 0.025,
          size: 3 + Math.random() * 7,
          color: color
        });
      }
    }

    // ----------  UPDATE ----------
    function update() {
      if (gameState !== 'running') return;

      // paddle movement
      if (leftPressed) paddle.x -= 7;
      if (rightPressed) paddle.x += 7;
      if (mouseX !== null) {
        let target = mouseX - paddle.w/2;
        paddle.x += (target - paddle.x) * 0.26;
      }
      paddle.x = Math.max(0, Math.min(W - paddle.w, paddle.x));

      // wide timer
      if (widePaddleTimer > 0) {
        widePaddleTimer--;
        if (widePaddleTimer === 0) {
          paddle.w = PADDLE_W;
          paddle.x = Math.min(paddle.x, W - paddle.w);
        }
      }

      // move balls
      for (let i = balls.length-1; i>=0; i--) {
        let b = balls[i];
        b.x += b.dx;
        b.y += b.dy;

        // walls
        if (b.x - b.r < 0) { b.x = b.r; b.dx = -b.dx; }
        if (b.x + b.r > W) { b.x = W - b.r; b.dx = -b.dx; }
        if (b.y - b.r < 0) { b.y = b.r; b.dy = -b.dy; }

        // bottom => lose ball
        if (b.y + b.r > H) {
          balls.splice(i, 1);
          continue;
        }

        // paddle collision
        ballPaddleCollision(b);

        // brick collision
        for (let j = bricks.length-1; j>=0; j--) {
          let brick = bricks[j];
          if (ballBrickCollision(b, brick)) {
            brick.hp--;
            if (brick.hp <= 0) {
              // destroy brick
              let col = brick.powerUp ? '#facc15' : (brick.type === 'tough' ? '#a78bfa' : '#38bdf8');
              emitParticles(brick.x + brick.w/2, brick.y + brick.h/2, col, 18);
              if (brick.powerUp) {
                spawnPowerup(brick.x + brick.w/2, brick.y, brick.powerUp);
              }
              bricks.splice(j, 1);
              score += 10;
              updateUI();
            } else {
              brick.cracked = true;
              emitParticles(brick.x + brick.w/2, brick.y + brick.h/2, '#cbd5e1', 6);
            }
            break; // only one brick per frame
          }
        }
      }

      // game over if no balls and lives
      if (balls.length === 0) {
        lives--;
        updateUI();
        if (lives <= 0) {
          gameState = 'gameover';
          overlayTitle.textContent = '💀 GAME OVER';
          overlayAction.textContent = '🔄  Play again';
          overlay.classList.add('show');
          return;
        } else {
          // reset ball (keep multiball status?)
          resetBall(multiBallActive);
          if (multiBallActive && balls.length === 1) {
            // add second & third balls
            for (let k=0; k<2; k++) {
              let angle = -Math.PI/2 + (k===0? -0.4 : 0.4);
              spawnBall(W/2, paddle.y - 18, angle);
            }
          }
        }
      }

      // powerups
      for (let i=powerups.length-1; i>=0; i--) {
        let p = powerups[i];
        p.y += p.speed;
        // catch with paddle
        if (p.y + p.h > paddle.y && p.y < paddle.y + paddle.h &&
            p.x + p.w > paddle.x && p.x < paddle.x + paddle.w) {
          if (p.type === 'wide') {
            widePaddleTimer = WIDE_DURATION;
            paddle.w = WIDE_PADDLE_W;
            paddle.x = Math.min(paddle.x, W - paddle.w);
          } else if (p.type === 'multiball') {
            multiBallActive = true;
            // add 2 extra balls near existing ones
            let existing = balls.length > 0 ? balls : [null];
            for (let k=0; k<2; k++) {
              let ref = balls.length > 0 ? balls[0] : { x: W/2, y: paddle.y - 18 };
              let angle = -Math.PI/2 + (k===0? -0.5 : 0.5);
              spawnBall(ref.x, ref.y, angle);
            }
          }
          powerups.splice(i,1);
          continue;
        }
        if (p.y > H + 30) powerups.splice(i,1);
      }

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

      // victory?
      if (bricks.length === 0) {
        gameState = 'victory';
        overlayTitle.textContent = '🎉 VICTORY!';
        overlayAction.textContent = '⭐  Play again';
        overlay.classList.add('show');
      }
    }

    // ----------  DRAW ----------
    function draw() {
      ctx.clearRect(0, 0, W, H);

      // background
      ctx.fillStyle = '#0b1120';
      ctx.fillRect(0,0,W,H);

      // bricks
      for (let brick of bricks) {
        let color = brick.type === 'tough' ? '#7c3aed' : '#0ea5e9';
        ctx.fillStyle = brick.cracked ? '#94a3b8' : color;
        ctx.shadowColor = '#ffffff20';
        ctx.shadowBlur = 6;
        ctx.beginPath();
        ctx.roundRect(brick.x, brick.y, brick.w, brick.h, 6);
        ctx.fill();
        // power up icon
        if (brick.powerUp) {
          ctx.shadowBlur = 0;
          ctx.font = 'bold 16px sans-serif';
          ctx.textAlign = 'center';
          ctx.textBaseline = 'middle';
          ctx.fillStyle = '#fde047';
          ctx.fillText(brick.powerUp === 'wide' ? '⬛' : '🔮', brick.x + brick.w/2, brick.y + brick.h/2 - 1);
        }
        // crack lines
        if (brick.cracked) {
          ctx.strokeStyle = '#1e293b';
          ctx.lineWidth = 1.8;
          ctx.beginPath();
          ctx.moveTo(brick.x+8, brick.y+4);
          ctx.lineTo(brick.x+22, brick.y+18);
          ctx.moveTo(brick.x+brick.w-12, brick.y+6);
          ctx.lineTo(brick.x+brick.w-20, brick.y+19);
          ctx.stroke();
        }
      }
      ctx.shadowBlur = 0;

      // paddle
      ctx.shadowColor = '#38bdf880';
      ctx.shadowBlur = 16;
      ctx.fillStyle = '#f1f5f9';
      ctx.beginPath();
      ctx.roundRect(paddle.x, paddle.y, paddle.w, paddle.h, 12);
      ctx.fill();
      ctx.shadowBlur = 0;

      // balls
      for (let b of balls) {
        ctx.shadowColor = '#facc1590';
        ctx.shadowBlur = 20;
        ctx.beginPath();
        ctx.arc(b.x, b.y, b.r, 0, Math.PI*2);
        ctx.fillStyle = '#fde047';
        ctx.fill();
      }
      ctx.shadowBlur = 0;

      // powerups
      for (let p of powerups) {
        ctx.fillStyle = p.type === 'wide' ? '#60a5fa' : '#a78bfa';
        ctx.shadowColor = '#ffffff40';
        ctx.shadowBlur = 12;
        ctx.beginPath();
        ctx.roundRect(p.x, p.y, p.w, p.h, 8);
        ctx.fill();
        ctx.shadowBlur = 0;
        ctx.font = 'bold 14px sans-serif';
        ctx.fillStyle = '#fff';
        ctx.textAlign = 'center';
        ctx.textBaseline = 'middle';
        ctx.fillText(p.type === 'wide' ? '⬛' : '⚡', p.x + p.w/2, p.y + p.h/2);
      }

      // particles
      for (let p of particles) {
        ctx.globalAlpha = p.life;
        ctx.fillStyle = p.color;
        ctx.shadowBlur = 0;
        ctx.fillRect(p.x - p.size/2, p.y - p.size/2, p.size, p.size);
      }
      ctx.globalAlpha = 1;

      // wide timer indicator
      if (widePaddleTimer > 0) {
        ctx.fillStyle = '#60a5fa60';
        ctx.font = '13px monospace';
        ctx.textAlign = 'right';
        ctx.fillText(`⬛ ${(widePaddleTimer/60).toFixed(1)}s`, W-16, 26);
      }
    }

    // roundRect polyfill
    CanvasRenderingContext2D.prototype.roundRect = function(x, y, w, h, r) {
      if (r > w/2) r = w/2;
      if (r > h/2) r = h/2;
      this.moveTo(x+r, y);
      this.arcTo(x+w, y, x+w, y+h, r);
      this.arcTo(x+w, y+h, x, y+h, r);
      this.arcTo(x, y+h, x, y, r);
      this.arcTo(x, y, x+w, y, r);
      return this;
    };

    // ----------  GAME LOOP ----------
    function loop() {
      update();
      draw();
      requestAnimationFrame(loop);
    }

    // ----------  START / RESTART ----------
    function startGame() {
      fullReset();
      gameState = 'running';
      overlay.classList.remove('show');
      mouseX = null;
      leftPressed = false;
      rightPressed = false;
    }

    // ----------  EVENT LISTENERS ----------
    function handleKey(e) {
      const key = e.key;
      if (key === 'ArrowLeft' || key === 'Left' || key === 'a' || key === 'A') {
        leftPressed = true; e.preventDefault();
      } else if (key === 'ArrowRight' || key === 'Right' || key === 'd' || key === 'D') {
        rightPressed = true; e.preventDefault();
      }
      if (gameState === 'idle' || gameState === 'gameover' || gameState === 'victory') {
        startGame();
      }
    }
    function handleKeyUp(e) {
      const key = e.key;
      if (key === 'ArrowLeft' || key === 'Left' || key === 'a' || key === 'A') {
        leftPressed = false; e.preventDefault();
      } else if (key === 'ArrowRight' || key === 'Right' || key === 'd' || key === 'D') {
        rightPressed = false; e.preventDefault();
      }
    }
    document.addEventListener('keydown', handleKey);
    document.addEventListener('keyup', handleKeyUp);

    canvas.addEventListener('mousemove', (e) => {
      const rect = canvas.getBoundingClientRect();
      const scaleX = canvas.width / rect.width;
      mouseX = (e.clientX - rect.left) * scaleX;
      mouseX = Math.max(0, Math.min(W, mouseX));
    });
    canvas.addEventListener('mouseleave', () => { mouseX = null; });

    canvas.addEventListener('click', () => {
      if (gameState === 'idle' || gameState === 'gameover' || gameState === 'victory') {
        startGame();
      }
    });

    overlayAction.addEventListener('click', (e) => {
      e.stopPropagation();
      startGame();
    });

    // touch support (mobile)
    canvas.addEventListener('touchmove', (e) => {
      e.preventDefault();
      const rect = canvas.getBoundingClientRect();
      const touch = e.touches[0];
      const scaleX = canvas.width / rect.width;
      mouseX = (touch.clientX - rect.left) * scaleX;
      mouseX = Math.max(0, Math.min(W, mouseX));
    }, { passive: false });
    canvas.addEventListener('touchstart', (e) => {
      e.preventDefault();
      if (gameState === 'idle' || gameState === 'gameover' || gameState === 'victory') startGame();
      const rect = canvas.getBoundingClientRect();
      const touch = e.touches[0];
      const scaleX = canvas.width / rect.width;
      mouseX = (touch.clientX - rect.left) * scaleX;
    }, { passive: false });
    canvas.addEventListener('touchend', () => { mouseX = null; });

    // ----------  INIT ----------
    fullReset();
    gameState = 'idle';
    overlay.classList.add('show');
    overlayTitle.textContent = '🧱 BREAKOUT';
    overlayAction.textContent = 'Click or press a key to start';
    updateUI();
    loop();
  })();
</script>
</body>
</html>