Models 44

Xing4.0 29B A4B (free)

by XingChenReasoningClean
Open in new window

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

How it went

Total time
1 min 17 s
Cost
$0
Output tokens
6,985
Spent thinking
0 tokens
Speed
91.4 tok/s
Console errors
0
First token after
779 ms
First visible text after
779 ms
Prompt tokens
374
Code size
15.9 KB
Finish reason
stop
Served by
Phala
Model id
xingchen-agi/xing4.0-29b-a4b:free
Reasoning sent
{"effort":"none"}
Max output
32,000 tokens
Generated
Nov 9, 2026

What it was asked

The prompt
“i want a breakout game where the paddle is a hamburger and every brick you break explodes into tons of little hearts”
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 · 660 lines

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Hamburger Breakout - Hearts Explosion</title>
<style>
  * { margin: 0; padding: 0; box-sizing: border-box; }
  body {
    background: #1a1a2e;
    display: flex;
    justify-content: center;
    align-items: center;
    min-height: 100vh;
    font-family: 'Segoe UI', Arial, sans-serif;
    overflow: hidden;
  }
  #gameContainer {
    position: relative;
    width: 100%;
    max-width: 900px;
    aspect-ratio: 4 / 3;
    background: #16213e;
    border: 3px solid #e94560;
    border-radius: 12px;
    overflow: hidden;
    box-shadow: 0 0 30px rgba(233, 69, 96, 0.4);
  }
  canvas {
    display: block;
    width: 100%;
    height: 100%;
  }
  #startOverlay {
    position: absolute;
    inset: 0;
    background: rgba(22, 33, 62, 0.9);
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    z-index: 10;
    cursor: pointer;
    transition: opacity 0.3s;
  }
  #startOverlay h1 {
    color: #f5c542;
    font-size: clamp(28px, 5vw, 48px);
    text-shadow: 3px 3px 0 #e94560, 6px 6px 0 rgba(0,0,0,0.5);
    margin-bottom: 10px;
    text-align: center;
  }
  #startOverlay p {
    color: #eee;
    font-size: clamp(14px, 2vw, 18px);
    margin-top: 15px;
    text-align: center;
    max-width: 80%;
  }
  #startOverlay .hint {
    color: #f5c542;
    font-size: clamp(16px, 2.5vw, 22px);
    margin-top: 20px;
    animation: pulse 1.5s infinite;
  }
  @keyframes pulse {
    0%, 100% { opacity: 1; }
    50% { opacity: 0.4; }
  }
  #overlayHidden { display: none; }
  #hud {
    position: absolute;
    top: 0; left: 0; right: 0;
    padding: 8px 14px;
    display: flex;
    justify-content: space-between;
    color: #fff;
    font-size: clamp(12px, 1.8vw, 16px);
    z-index: 5;
    pointer-events: none;
    text-shadow: 1px 1px 2px rgba(0,0,0,0.7);
  }
  #gameOverOverlay, #winOverlay {
    position: absolute;
    inset: 0;
    background: rgba(22, 33, 62, 0.95);
    display: flex;
    flex-direction: column;
    justify-content: center;
    align-items: center;
    z-index: 10;
    display: none;
  }
  #gameOverOverlay h2, #winOverlay h2 {
    font-size: clamp(32px, 6vw, 52px);
    text-shadow: 3px 3px 0 #e94560;
    margin-bottom: 10px;
  }
  #gameOverOverlay h2 { color: #e94560; }
  #winOverlay h2 { color: #f5c542; }
  #gameOverOverlay p, #winOverlay p {
    color: #ddd;
    font-size: clamp(14px, 2vw, 18px);
    margin-bottom: 20px;
  }
  button {
    padding: 12px 32px;
    font-size: clamp(14px, 2vw, 18px);
    background: linear-gradient(135deg, #f5c542, #e94560);
    color: #1a1a2e;
    border: none;
    border-radius: 30px;
    cursor: pointer;
    font-weight: bold;
    margin: 5px;
    transition: transform 0.1s;
  }
  button:hover { transform: scale(1.05); }
  @media (max-width: 500px) {
    #gameContainer { border-radius: 8px; }
  }
</style>
</head>
<body>
<div id="gameContainer">
  <canvas id="gameCanvas"></canvas>
  <div id="hud">
    <span id="scoreLabel">SCORE: 0</span>
    <span id="livesLabel">LIVES: 3</span>
  </div>
  <div id="startOverlay">
    <h1>🍔 BREAKOUT HEARTS</h1>
    <p>A hamburger-themed breakout game! Break all the burger bricks to win.</p>
    <p class="hint">Click or press any key to start</p>
  </div>
  <div id="gameOverOverlay">
    <h2>GAME OVER</h2>
    <p id="gameOverMsg">Better luck next time!</p>
    <button onclick="restartGame()">Play Again</button>
  </div>
  <div id="winOverlay">
    <h2>🏆 YOU WIN! 🏆</h2>
    <p id="winMsg">All burgers cleared!</p>
    <button onclick="restartGame()">Play Again</button>
  </div>
</div>

<script>
const canvas = document.getElementById('gameCanvas');
const ctx = canvas.getContext('2d');
const W = 900, H = 675;
canvas.width = W;
canvas.height = H;

// ---- Game State ----
let state = 'menu'; // menu, playing, over, win
let score = 0;
let lives = 3;
let ball = null;
let paddle = null;
let bricks = [];
let hearts = []; // floating hearts from explosions
let particles = []; // small sparkle particles
let animationId = null;
let keys = {};

// ---- Ball ----
function createBall() {
  return {
    x: W / 2, y: H - 60,
    dx: 2.5 * (Math.random() > 0.5 ? 1 : -1),
    dy: -3.5,
    r: 7,
    speed: 3.8
  };
}

function resetBall() {
  ball = createBall();
  ball.x = paddle.w / 2;
  ball.y = paddle.y - ball.r - 2;
  ball.dx = 2.5 * (Math.random() > 0.5 ? 1 : -1);
  ball.dy = -3.5;
}

// ---- Paddle (Hamburger shape) ----
function createPaddle() {
  return {
    x: W / 2 - 60,
    y: H - 35,
    w: 120,
    h: 20,
    thickness: 4,
    sep: 6
  };
}

function drawPaddle() {
  const px = paddle.x, py = paddle.y;
  const pw = paddle.w, ph = paddle.h;
  const ww = paddle.thickness, sep = paddle.sep;

  ctx.save();
  // Patty (darker brown base)
  ctx.fillStyle = '#7a4a2b';
  roundRect(px + sep, py, pw - sep*2, ph, 5);
  ctx.fill();

  // Lettuce (green strip on top)
  ctx.fillStyle = '#3fb83f';
  roundRect(px + sep + 2, py, pw - sep*2 - 4, ph/2 - 1, 4);
  ctx.fill();

  // Tomato (red layer)
  ctx.fillStyle = '#e94560';
  roundRect(px + sep + 3, py + ph/2 - 1, pw - sep*2 - 6, 3, 2);
  ctx.fill();

  // Cheese (yellow strip)
  ctx.fillStyle = '#f5c542';
  roundRect(px + sep, py + ph/2 + 1, pw - sep*2, ph/2 - 3, 3);
  ctx.fill();

  // Bun (two sesame buns on sides - drawn as darker top edge)
  ctx.fillStyle = '#c68642';
  // bun top
  roundRect(px + sep, py - 2, pw - sep*2, 5, 2);
  ctx.fill();
  // bun bottom
  ctx.fillStyle = '#8B5E3C';
  roundRect(px + sep, py + ph - 5, pw - sep*2, 5, 2);
  ctx.fill();

  // Sesame seeds
  ctx.fillStyle = '#fff5d6';
  for (let i = 0; i < 3; i++) {
    ctx.beginPath();
    ctx.ellipse(px + 30 + i*25, py + 2, 3, 1.5, 0, 0, Math.PI*2);
    ctx.fill();
  }

  ctx.restore();
}

function roundRect(x, y, w, h, r) {
  ctx.beginPath();
  ctx.moveTo(x + r, y);
  ctx.arcTo(x + w, y, x + w, y + h, r);
  ctx.arcTo(x + w, y + h, x, y + h, r);
  ctx.arcTo(x, y + h, x, y, r);
  ctx.arcTo(x, y, x + w, y, r);
  ctx.closePath();
}

// ---- Bricks (Burger-shaped) ----
function buildBricks() {
  bricks = [];
  const rows = 5;
  const cols = 11;
  const brickW = 72;
  const brickH = 26;
  const padX = 8;
  const padY = 8;
  const totalPad = padX * (cols + 1);
  const availW = W - totalPad;
  const bw = availW / cols;

  const colors = ['#e94560','#f5c542','#e8a830','#d4a017','#ff6b35'];

  for (let r = 0; r < rows; r++) {
    for (let c = 0; c < cols; c++) {
      if (Math.random() < 0.15 && r === 0) continue; // skip a few for difficulty
      const x = padX + c * bw + 4;
      const y = 50 + r * (brickH + 6);
      bricks.push({
        x, y, w: bw - 8, h: brickH,
        rows: r, col: c,
        alive: true,
        color: colors[r % colors.length],
        hitFlash: 0
      });
    }
  }
}

function drawBrick(b) {
  if (!b.alive) return;
  ctx.save();
  // shadow
  ctx.fillStyle = 'rgba(0,0,0,0.3)';
  roundRect(b.x+2, b.y+3, b.w, b.h, 6);
  ctx.fill();

  // body - burger patty color
  ctx.fillStyle = b.color;
  roundRect(b.x, b.y, b.w, b.h, 6);
  ctx.fill();

  // lettuce strip on top
  ctx.fillStyle = '#3fb83f';
  roundRect(b.x+2, b.y, b.w-4, b.h*0.35, 5);
  ctx.fill();

  // tomato
  ctx.fillStyle = '#e94560';
  roundRect(b.x+2, b.y + b.h*0.38, b.w-4, b.h*0.25, 4);
  ctx.fill();

  // cheese
  ctx.fillStyle = '#f5c542';
  roundRect(b.x+1, b.y + b.h*0.58, b.w-2, b.h*0.2, 3);
  ctx.fill();

  // sesame dots
  ctx.fillStyle = '#fff5d6';
  for (let i = 0; i < 4; i++) {
    ctx.beginPath();
    ctx.ellipse(b.x + 12 + i*(b.w-24)/3, b.y + b.h*0.3, 3, 1.8, 0, 0, Math.PI*2);
    ctx.fill();
  }

  // highlight
  ctx.fillStyle = 'rgba(255,255,255,0.18)';
  roundRect(b.x+3, b.y+3, b.w-6, 4, 2);
  ctx.fill();

  if (b.hitFlash > 0) {
    ctx.globalAlpha = b.hitFlash;
    ctx.fillStyle = '#fff';
    roundRect(b.x, b.y, b.w, b.h, 6);
    ctx.fill();
    ctx.globalAlpha = 1;
  }
  ctx.restore();
}

// ---- Hearts from explosions ----
function spawnHearts(bx, by, count) {
  for (let i = 0; i < count; i++) {
    const angle = Math.random() * Math.PI * 2;
    const speed = 1 + Math.random() * 3;
    hearts.push({
      x: bx, y: by,
      dx: Math.cos(angle) * speed,
      dy: Math.sin(angle) * speed - 1.5,
      vx: (Math.random()-0.5)*0.5,
      vy: -1 - Math.random()*2,
      size: 4 + Math.random()*6,
      life: 60 + Math.random()*40,
      maxLife: 100,
      rotation: Math.random()*Math.PI*2,
      rotSpeed: (Math.random()-0.5)*0.1
    });
  }
}

function drawHeart(hx, hy, s, alpha) {
  ctx.save();
  ctx.translate(hx, hy);
  ctx.rotate(0);
  ctx.globalAlpha = alpha;
  ctx.beginPath();
  const sz = s;
  ctx.moveTo(0, sz * 0.3);
  ctx.bezierCurveTo(-sz, -sz*0.5, -sz*0.3, -sz, 0, -sz*0.3);
  ctx.bezierCurveTo(sz*0.3, -sz, sz, -sz*0.5, 0, sz*0.3);
  ctx.closePath();
  ctx.fillStyle = '#e94560';
  ctx.fill();
  ctx.fillStyle = '#ff8fa3';
  ctx.beginPath();
  ctx.arc(-sz*0.15, -sz*0.1, sz*0.12, 0, Math.PI*2);
  ctx.fill();
  ctx.restore();
}

function updateHearts() {
  for (let i = hearts.length - 1; i >= 0; i--) {
    const h = hearts[i];
    h.x += h.dx;
    h.y += h.dy;
    h.dy += 0.04; // gravity
    h.dx *= 0.99;
    h.life--;
    if (h.life <= 0 || h.y > H) {
      hearts.splice(i, 1);
    }
  }
}

function drawHearts() {
  for (const h of hearts) {
    const t = h.life / h.maxLife;
    drawHeart(h.x, h.y, h.size, t < 0.2 ? t*2 : t);
  }
}

// ---- Particles (sparkles) ----
function spawnParticles(x, y, count) {
  for (let i = 0; i < count; i++) {
    particles.push({
      x, y,
      dx: (Math.random()-0.5)*5,
      dy: (Math.random()-0.5)*5 - 1,
      life: 30 + Math.random()*20,
      maxLife: 50,
      size: 2 + Math.random()*3,
      color: ['#f5c542','#ff6b35','#3fb83f','#e94560','#fff5d6'][Math.floor(Math.random()*5)]
    });
  }
}

function updateAndDrawParticles() {
  for (let i = particles.length - 1; i >= 0; i--) {
    const p = particles[i];
    p.x += p.dx;
    p.y += p.dy;
    p.dy += 0.1;
    p.life--;
    if (p.life <= 0) { particles.splice(i, 1); continue; }
    const alpha = p.life / p.maxLife;
    ctx.globalAlpha = alpha;
    ctx.fillStyle = p.color;
    ctx.beginPath();
    ctx.arc(p.x, p.y, p.size, 0, Math.PI*2);
    ctx.fill();
    ctx.globalAlpha = 1;
  }
}

// ---- Background ----
function drawBackground() {
  // gradient
  const grad = ctx.createLinearGradient(0, 0, 0, H);
  grad.addColorStop(0, '#1a1a4e');
  grad.addColorStop(1, '#0f0f2a');
  ctx.fillStyle = grad;
  ctx.fillRect(0, 0, W, H);

  // subtle grid
  ctx.strokeStyle = 'rgba(255,255,255,0.03)';
  ctx.lineWidth = 1;
  for (let x = 0; x < W; x += 40) {
    ctx.beginPath(); ctx.moveTo(x, 0); ctx.lineTo(x, H); ctx.stroke();
  }
  for (let y = 0; y < H; y += 40) {
    ctx.beginPath(); ctx.moveTo(0, y); ctx.lineTo(W, y); ctx.stroke();
  }

  // decorative hearts in background
  ctx.fillStyle = 'rgba(233, 69, 96, 0.05)';
  for (let i = 0; i < 8; i++) {
    const bx = (i * 137) % W;
    const by = (i * 211 + Date.now()*0.01) % H;
    drawHeart(bx, by, 12, 1);
  }
}

// ---- Physics ----
function update() {
  if (state !== 'playing') return;

  // paddle movement
  if (keys['ArrowLeft'] || keys['KeyA']) paddle.x -= 6;
  if (keys['ArrowRight'] || keys['KeyD']) paddle.x += 6;
  paddle.x = Math.max(0, Math.min(W - paddle.w, paddle.x));

  // ball movement
  ball.x += ball.dx;
  ball.y += ball.dy;

  // wall collisions
  if (ball.x + ball.r > W || ball.x - ball.r < 0) {
    ball.dx *= -1;
    if (ball.x + ball.r > W) ball.x = W - ball.r;
  }
  if (ball.y - ball.r < 0) {
    ball.dy *= -1;
    ball.y = ball.r;
  }

  // bottom - lose life
  if (ball.y - ball.r > H) {
    lives--;
    updateHUD();
    if (lives <= 0) {
      state = 'over';
      document.getElementById('gameOverOverlay').style.display = 'flex';
    } else {
      resetBall();
    }
    return;
  }

  // paddle collision
  if (ball.y + ball.r >= paddle.y &&
      ball.y - ball.r <= paddle.y + paddle.h &&
      ball.x >= paddle.x &&
      ball.x <= paddle.x + paddle.w &&
      ball.dy > 0) {
    ball.dy = -Math.abs(ball.dy);
    // angle based on hit position
    const hitPos = (ball.x - (paddle.x + paddle.w/2)) / (paddle.w/2);
    ball.dx = hitPos * 4;
    // ensure minimum speed
    const spd = Math.sqrt(ball.dx*ball.dx + ball.dy*ball.dy);
    if (spd < 3.8) {
      ball.dx *= 3.8 / spd;
      ball.dy *= 3.8 / spd;
    }
  }

  // brick collisions
  for (const b of bricks) {
    if (!b.alive) continue;
    if (ball.x + ball.r > b.x &&
        ball.x - ball.r < b.x + b.w &&
        ball.y + ball.r > b.y &&
        ball.y - ball.r < b.y + b.h) {
      // determine collision side
      const prevY = ball.y - ball.dy;
      const prevX = ball.x - ball.dx;
      if (prevY + ball.r <= b.y) {
        ball.dy = -Math.abs(ball.dy);
      } else if (prevY - ball.r >= b.y + b.h) {
        ball.dy = Math.abs(ball.dy);
      } else if (prevX + ball.r <= b.x) {
        ball.dx = -Math.abs(ball.dx);
      } else if (prevX - ball.r >= b.x + b.w) {
        ball.dx = Math.abs(ball.dx);
      }
      b.alive = false;
      b.hitFlash = 1;
      score += 10;
      spawnHearts(b.x + b.w/2, b.y + b.h/2, 15);
      spawnParticles(b.x + b.w/2, b.y + b.h/2, 8);
      updateHUD();
    }
    if (b.hitFlash > 0) b.hitFlash -= 0.05;
  }

  // check win
  if (bricks.every(b => !b.alive)) {
    state = 'win';
    document.getElementById('winOverlay').style.display = 'flex';
  }
}

function render() {
  drawBackground();
  for (const b of bricks) drawBrick(b);
  drawPaddle();
  drawHearts();
  updateAndDrawParticles();

  // ball with glow
  ctx.save();
  ctx.shadowColor = '#f5c542';
  ctx.shadowBlur = 12;
  ctx.fillStyle = '#fff5d6';
  ctx.beginPath();
  ctx.arc(ball.x, ball.y, ball.r, 0, Math.PI*2);
  ctx.fill();
  ctx.restore();

  // instructions overlay during play
  if (state === 'playing') {
    ctx.fillStyle = 'rgba(255,255,255,0.3)';
    ctx.font = '12px sans-serif';
    ctx.textAlign = 'center';
    ctx.fillText('← → / A D to move  |  Paddle is a Hamburger!', W/2, H - 8);
  }
}

function loop() {
  update();
  render();
  animationId = requestAnimationFrame(loop);
}

// ---- Game Control ----
function startGame() {
  document.getElementById('startOverlay').classList.add('hidden');
  state = 'playing';
  score = 0;
  lives = 3;
  bricks = [];
  hearts = [];
  particles = [];
  paddle = createPaddle();
  buildBricks();
  resetBall();
  updateHUD();
  if (!animationId) loop();
}

function restartGame() {
  document.getElementById('gameOverOverlay').style.display = 'none';
  document.getElementById('winOverlay').style.display = 'none';
  startGame();
}

function updateHUD() {
  document.getElementById('scoreLabel').textContent = 'SCORE: ' + score;
  document.getElementById('livesLabel').textContent = 'LIVES: ' + lives;
}

// ---- Input ----
document.addEventListener('keydown', e => {
  keys[e.code] = true;
  if (state === 'menu' && (e.code === 'Space' || e.code === 'Enter' || e.code === 'ArrowLeft')) {
    startGame();
  }
});
document.addEventListener('keyup', e => { keys[e.code] = false; });

document.getElementById('startOverlay').addEventListener('click', () => {
  startGame();
});

// handle touch for mobile
let touchStartX = null;
canvas.addEventListener('touchstart', e => {
  touchStartX = e.touches[0].clientX;
  if (state === 'menu') startGame();
});
canvas.addEventListener('touchmove', e => {
  if (state !== 'playing' || touchStartX === null) return;
  const rect = canvas.getBoundingClientRect();
  const scaleX = W / rect.width;
  const tx = (e.touches[0].clientX - rect.left) * scaleX;
  paddle.x = Math.max(0, Math.min(W - paddle.w, tx - paddle.w/2));
  touchStartX = null;
});
canvas.addEventListener('touchend', () => { touchStartX = null; });

// init
paddle = createPaddle();
buildBricks();
ball = createBall();
// pre-populate some hearts for visual flair behind menu
for (let i = 0; i < 30; i++) {
  hearts.push({
    x: Math.random()*W,
    y: Math.random()*H,
    dx: (Math.random()-0.5)*0.5,
    dy: -1 - Math.random()*1.5,
    vx: (Math.random()-0.5)*0.3,
    vy: -1 - Math.random()*1.5,
    size: 4 + Math.random()*6,
    life: 200 + Math.random()*100,
    maxLife: 300,
    rotation: 0,
    rotSpeed: 0
  });
}
loop();
</script>
</body>
</html>