← run 2026-06-29T212443Z-9dd5ff9-minimal

gemma-4-26b-a4b — web-platformer

rep 1 UNGRADED

pi 28.2s · verify 4.4s · 17875 tok · responded: gemma-4-26b-a4b · transcript

smoke 3/3

screenshot

verify output
CHECK PASS: canvas #game exists and is sized
CHECK PASS: no uncaught JS errors on load
CHECK PASS: keyboard input does not throw
score: 3/3 (100%)
produced code
game.js
/**
 * Mini Platformer Game Logic
 */

const canvas = document.getElementById('game');
const ctx = canvas.getContext('2d');
const scoreElement = document.getElementById('score');

// Game Configuration
const GRAVITY = 0.5;
const FRICTION = 0.8;
const PLAYER_SPEED = 5;
const JUMP_FORCE = -12;

// Game State
let score = 0;
const totalCoins = 5;
let gameActive = true;
let win = false;

// Input handling
const keys = {};
window.addEventListener('keydown', (e) => {
    keys[e.code] = true;
});
window.addEventListener('keyup', (e) => {
    keys[e.code] = false;
});

// Entities
class Player {
    constructor(x, y) {
        this.x = x;
        this.y = y;
        this.width = 30;
        this.height = 30;
        this.vx = 0;
        this.vy = 0;
        this.grounded = false;
        this.color = '#FF5733'; // Reddish player
    }

    update() {
        // Horizontal Movement
        if (keys['ArrowLeft'] || keys['KeyA']) {
            this.vx -= 1;
        } else if (keys['ArrowRight'] || keys['KeyD']) {
            this.vx += 1;
        } else {
            this.vx *= FRICTION;
        }

        // Limit speed
        if (this.vx > PLAYER_SPEED) this.vx = PLAYER_SPEED;
        if (this.vx < -PLAYER_SPEED) this.vx = -PLAYER_SPEED;

        // Jump
        if ((keys['ArrowUp'] || keys['KeyW'] || keys['Space']) && this.grounded) {
            this.vy = JUMP_FORCE;
            this.grounded = false;
        }

        // Apply Gravity
        this.vy += GRAVITY;

        // Apply Velocity
        this.x += this.vx;
        this.y += this.vy;

        // Floor collision (absolute bottom)
        if (this.y + this.height > canvas.height) {
            this.y = canvas.height - this.height;
            this.vy = 0;
            this.grounded = true;
        }

        // Screen boundaries
        if (this.x < 0) this.x = 0;
        if (this.x + this.width > canvas.width) this.x = canvas.width - this.width;
    }

    draw() {
        ctx.fillStyle = this.color;
        ctx.fillRect(this.x, this.y, this.width, this.height);
        
        // Eyes for the player
        ctx.fillStyle = 'white';
        ctx.fillRect(this.x + 5, this.y + 5, 5, 5);
        ctx.fillRect(this.x + 20, this.y + 5, 5, 5);
    }
}

class Platform {
    constructor(x, y, width, height) {
        this.x = x;
        this.y = y;
        this.width = width;
        this.height = height;
        this.color = '#4B2C20'; // Brown platform
    }

    draw() {
        ctx.fillStyle = this.color;
        ctx.fillRect(this.x, this.y, this.width, this.height);
        // Grass top
        ctx.fillStyle = '#2E8B57';
        ctx.fillRect(this.x, this.y, this.width, 5);
    }
}

class Coin {
    constructor(x, y) {
        this.x = x;
        this.y = y;
        this.radius = 10;
        this.collected = false;
        this.floatY = 0;
    }

    update() {
        this.floatY = Math.sin(Date.now() / 200) * 5;
    }

    draw() {
        if (this.collected) return;
        ctx.fillStyle = '#FFD700'; // Gold
        ctx.beginPath();
        ctx.arc(this.x, this.y + this.floatY, this.radius, 0, Math.PI * 2);
        ctx.fill();
        // Shine
        ctx.fillStyle = 'rgba(255, 255, 255, 0.5)';
        ctx.beginPath();
        ctx.arc(this.x - 3, this.y + this.floatY - 3, 3, 0, Math.PI * 2);
        ctx.fill();
    }
}

// Initialize game objects
const player = new Player(50, 350);
const platforms = [
    new Platform(0, 400, 800, 50), // Ground
    new Platform(150, 300, 150, 20),
    new Platform(400, 220, 150, 20),
    new Platform(100, 150, 120, 20),
    new Platform(550, 320, 100, 20),
    new Platform(650, 150, 100, 20)
];

const coins = [
    new Coin(225, 270),
    new Coin(475, 180),
    new Coin(160, 110),
    new Coin(600, 280),
    new Coin(700, 110)
];

function checkCollisions() {
    player.grounded = false;

    // Platform collision
    platforms.forEach(platform => {
        // Simple AABB collision for platform tops
        if (player.vx >= 0 || player.vx < 0) { // Horizontal check not strictly needed for top-only landing
            if (player.x < platform.x + platform.width &&
                player.x + player.width > platform.x &&
                player.y + player.height > platform.y &&
                player.y + player.height < platform.y + platform.height + player.vy + 1 &&
                player.vy >= 0) {
                
                player.y = platform.y - player.height;
                player.vy = 0;
                player.grounded = true;
            }
        }
    });

    // Coin collision
    coins.forEach(coin => {
        if (!coin.collected) {
            const dx = (player.x + player.width / 2) - coin.x;
            const dy = (player.y + player.height / 2) - (coin.y + coin.floatY);
            const distance = Math.sqrt(dx * dx + dy * dy);

            if (distance < player.width / 2 + coin.radius) {
                coin.collected = true;
                score++;
                scoreElement.innerText = `Coins: ${score} / ${totalCoins}`;
                if (score === totalCoins) {
                    win = true;
                }
            }
        }
    });
}

function update() {
    if (!gameActive) return;

    player.update();
    coins.forEach(c => c.update());
    checkCollisions();
}

function draw() {
    // Clear canvas
    ctx.clearRect(0, 0, canvas.width, canvas.height);

    // Draw background clouds/decorations (simple)
    ctx.fillStyle = 'rgba(255, 255, 255, 0.5)';
    ctx.beginPath(); ctx.arc(100, 100, 30, 0, Math.PI*2); ctx.fill();
    ctx.beginPath(); ctx.arc(130, 100, 40, 0, Math.PI*2); ctx.fill();
    ctx.beginPath(); ctx.arc(160, 100, 30, 0, Math.PI*2); ctx.fill();
    
    ctx.beginPath(); ctx.arc(600, 80, 25, 0, Math.PI*2); ctx.fill();
    ctx.beginPath(); ctx.arc(630, 80, 35, 0, Math.PI*2); ctx.fill();

    // Draw world
    platforms.forEach(p => p.draw());
    coins.forEach(c => c.draw());
    player.draw();

    // Win overlay
    if (win) {
        ctx.fillStyle = 'rgba(0, 0, 0, 0.5)';
        ctx.fillRect(0, 0, canvas.width, canvas.height);
        ctx.fillStyle = 'white';
        ctx.font = '48px sans-serif';
        ctx.textAlign = 'center';
        ctx.fillText('YOU WIN!', canvas.width / 2, canvas.height / 2);
        ctx.font = '24px sans-serif';
        ctx.fillText('Refresh to play again', canvas.width / 2, canvas.height / 2 + 40);
    }
}

function gameLoop() {
    update();
    draw();
    requestAnimationFrame(gameLoop);
}

// Start the game
gameLoop();
index.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Mini Platformer</title>
    <style>
        body {
            margin: 0;
            padding: 0;
            display: flex;
            flex-direction: column;
            align-items: center;
            justify-content: center;
            height: 100vh;
            background-color: #333;
            color: white;
            font-family: sans-serif;
        }
        canvas {
            background-color: #87CEEB; /* Sky blue */
            border: 4px solid #222;
            box-shadow: 0 0 20px rgba(0,0,0,0.5);
            display: block;
        }
        .ui {
            margin-top: 10px;
            text-align: center;
        }
    </style>
</head>
<body>
    <div class="ui">
        <h1>Mini Platformer</h1>
        <p>Use WASD or Arrow Keys to move & jump. Collect all coins!</p>
    </div>
    <canvas id="game" width="800" height="450"></canvas>
    <div class="ui">
        <div id="score">Coins: 0 / 5</div>
    </div>

    <script src="game.js"></script>
</body>
</html>

rep 2 UNGRADED

pi 32.6s · verify 4.1s · 19148 tok · responded: gemma-4-26b-a4b · transcript

smoke 3/3

screenshot

verify output
CHECK PASS: canvas #game exists and is sized
CHECK PASS: no uncaught JS errors on load
CHECK PASS: keyboard input does not throw
score: 3/3 (100%)
produced code
game.js
/**
 * Super Mario Style Platformer - Game Engine
 */

const canvas = document.getElementById('game');
const ctx = canvas.getContext('2d');
const scoreDisplay = document.getElementById('score-display');
const messageDisplay = document.getElementById('message-display');

// --- Game Configuration ---
const GRAVITY = 0.6;
const FRICTION = 0.8;
const PLAYER_SPEED = 5;
const PLAYER_JUMP = -12;

// --- Game State ---
let score = 0;
let gameOver = false;
let gameWon = false;
let cameraX = 0;

// --- Input Handling ---
const keys = {};
window.addEventListener('keydown', e => keys[e.code] = true);
window.addEventListener('keyup', e => keys[e.code] = false);

// --- Classes ---

class Entity {
    constructor(x, y, width, height, color) {
        this.x = x;
        this.y = y;
        this.width = width;
        this.height = height;
        this.color = color;
    }

    draw() {
        ctx.fillStyle = this.color;
        ctx.fillRect(this.x - cameraX, this.y, this.width, this.height);
    }
}

class Player extends Entity {
    constructor(x, y) {
        super(x, y, 30, 40, '#ff4444'); // Red character
        this.vx = 0;
        this.vy = 0;
        this.onGround = false;
    }

    update() {
        // Horizontal Movement
        if (keys['ArrowLeft'] || keys['KeyA']) {
            this.vx = -PLAYER_SPEED;
        } else if (keys['ArrowRight'] || keys['KeyD']) {
            this.vx = PLAYER_SPEED;
        } else {
            this.vx *= FRICTION;
        }

        // Jump
        if ((keys['Space'] || keys['ArrowUp'] || keys['KeyW']) && this.onGround) {
            this.vy = PLAYER_JUMP;
            this.onGround = false;
        }

        // Gravity
        this.vy += GRAVITY;

        // Apply Velocity
        this.x += this.vx;
        this.y += this.vy;

        // Prevent moving off left edge (optional, but good for gameplay)
        if (this.x < 0) this.x = 0;

        // Screen Bounds (Bottom)
        if (this.y + this.height > canvas.height + 100) {
            this.reset();
        }
    }

    reset() {
        this.x = 50;
        this.y = 100;
        this.vx = 0;
        this.vy = 0;
        // We don't reset score here, just respawn
    }

    draw() {
        // Draw body
        ctx.fillStyle = this.color;
        ctx.fillRect(this.x - cameraX, this.y, this.width, this.height);
        
        // Draw "eyes" to show direction
        ctx.fillStyle = 'white';
        let eyeX = this.vx >= 0 ? this.x - cameraX + 20 : this.x - cameraX + 5;
        ctx.fillRect(eyeX, this.y + 10, 5, 5);
    }
}

class Platform extends Entity {
    constructor(x, y, width, height, color = '#8B4513') {
        super(x, y, width, height, color);
    }
}

class Coin extends Entity {
    constructor(x, y) {
        super(x, y, 15, 15, '#ffd700');
        this.collected = false;
    }

    draw() {
        if (this.collected) return;
        ctx.fillStyle = this.color;
        ctx.beginPath();
        ctx.arc(this.x - cameraX + this.width/2, this.y + this.height/2, this.width/2, 0, Math.PI * 2);
        ctx.fill();
    }
}

class Goal extends Entity {
    constructor(x, y) {
        super(x, y, 40, 100, '#00ff00');
    }

    draw() {
        // Draw a flag pole
        ctx.fillStyle = '#555';
        ctx.fillRect(this.x - cameraX, this.y, 5, this.height);
        // Draw flag
        ctx.fillStyle = 'red';
        ctx.fillRect(this.x - cameraX, this.y, 30, 20);
    }
}

// --- World Data ---
const player = new Player(50, 100);
const platforms = [
    new Platform(0, 400, 1000, 50),         // Floor 1
    new Platform(1100, 400, 800, 50),       // Floor 2 (with a pit)
    new Platform(1200, 300, 150, 20),       // Platform 1
    new Platform(1450, 200, 150, 20),     // Platform 2
    new Platform(1700, 300, 200, 20),      // Platform 3
    new Platform(2000, 400, 1000, 50),      // Floor 3
    new Platform(2200, 250, 100, 20),       // High platform
    new Platform(2500, 320, 150, 20),       // High platform
    new Platform(2800, 400, 500, 50),       // Floor 4
];

const coins = [
    new Coin(300, 350),
    new Coin(1250, 250),
    new Coin(1500, 150),
    new Coin(1750, 250),
    new Coin(2250, 200),
    new Coin(2550, 270),
    new Coin(2900, 350),
];

const goal = new Goal(3100, 300);

// --- Collision Logic ---

function checkCollisions() {
    player.onGround = false;

    // Platforms
    for (const p of platforms) {
        // Standard AABB collision
        if (player.x < p.x + p.width &&
            player.x + player.width > p.x &&
            player.y < p.y + p.height &&
            player.y + player.height > p.y) {
            
            // Determine which side the collision happened on
            const overlapTop = (player.y + player.height) - p.y;
            const overlapBottom = (p.y + p.height) - player.y;
            const overlapLeft = (player.x + player.width) - p.x;
            const overlapRight = (p.x + p.width) - player.x;

            const minOverlap = Math.min(overlapTop, overlapBottom, overlapLeft, overlapRight);

            if (minOverlap === overlapTop && player.vy > 0) {
                // Landing on top
                player.y = p.y - player.height;
                player.vy = 0;
                player.onGround = true;
            } else if (minOverlap === overlapBottom && player.vy < 0) {
                // Hitting bottom
                player.y = p.y + p.height;
                player.vy = 0;
            } else if (minOverlap === overlapLeft && player.vx > 0) {
                // Hitting left
                player.x = p.x - player.width;
                player.vx = 0;
            } else if (minOverlap === overlapRight && player.vx < 0) {
                // Hitting right
                player.x = p.x + p.width;
                player.vx = 0;
            }
        }
    }

    // Coins
    for (const c of coins) {
        if (!c.collected &&
            player.x < c.x + c.width &&
            player.x + player.width > c.x &&
            player.y < c.y + c.height &&
            player.y + player.height > c.y) {
            c.collected = true;
            score += 10;
            scoreDisplay.innerText = `Coins: ${score}`;
        }
    }

    // Goal
    if (player.x < goal.x + goal.width &&
        player.x + player.width > goal.x &&
        player.y < goal.y + goal.height &&
        player.y + player.height > goal.y) {
        gameWon = true;
    }
}

// --- Game Loop ---

function update() {
    if (gameOver || gameWon) return;

    player.update();
    checkCollisions();

    // Camera follow
    // Center the camera on player, but clamp to world boundaries (roughly)
    // For simplicity, we'll just follow player X with some smoothing
    const targetCameraX = player.x - canvas.width / 2;
    cameraX += (targetCameraX - cameraX) * 0.1;
    
    if (cameraX < 0) cameraX = 0;
}

function draw() {
    // Clear canvas
    ctx.clearRect(0, 0, canvas.width, canvas.height);

    // Draw sky/background (already handled by canvas background color)

    // Draw platforms
    for (const p of platforms) p.draw();

    // Draw coins
    for (const c of coins) c.draw();

    // Draw goal
    goal.draw();

    // Draw player
    player.draw();

    // Draw Win Message
    if (gameWon) {
        ctx.fillStyle = 'rgba(0, 0, 0, 0.5)';
        ctx.fillRect(0, 0, canvas.width, canvas.height);
        ctx.fillStyle = 'white';
        ctx.font = '48px sans-serif';
        ctx.textAlign = 'center';
        ctx.fillText('YOU WIN!', canvas.width / 2, canvas.height / 2);
        ctx.font = '24px sans-serif';
        ctx.fillText(`Final Score: ${score}`, canvas.width / 2, canvas.height / 2 + 50);
    }
}

function loop() {
    update();
    draw();
    requestAnimationFrame(loop);
}

// Start game
loop();
index.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Super Mario Style Platformer</title>
    <style>
        body {
            margin: 0;
            padding: 0;
            display: flex;
            flex-direction: column;
            align-items: center;
            justify-content: center;
            height: 100vh;
            background-color: #333;
            color: white;
            font-family: sans-serif;
            overflow: hidden;
        }
        canvas {
            border: 4px solid #000;
            background-color: #5c94fa; /* Classic Mario Sky Blue */
            box-shadow: 0 0 20px rgba(0,0,0,0.5);
        }
        .ui {
            margin-top: 10px;
            text-align: center;
        }
        .controls {
            font-size: 0.8em;
            color: #ccc;
            margin-top: 5px;
        }
    </style>
</head>
<body>

    <div id="game-container">
        <canvas id="game" width="800" height="450"></canvas>
    </div>

    <div class="ui">
        <div id="score-display">Coins: 0</div>
        <div id="message-display"></div>
        <div class="controls">Use ARROWS or WASD to Move & Jump</div>
    </div>

    <script src="game.js"></script>
</body>
</html>

rep 3 UNGRADED

pi 34.8s · verify 4.1s · 19865 tok · responded: gemma-4-26b-a4b · transcript

smoke 3/3

screenshot

verify output
CHECK PASS: canvas #game exists and is sized
CHECK PASS: no uncaught JS errors on load
CHECK PASS: keyboard input does not throw
score: 3/3 (100%)
produced code
game.js
const canvas = document.getElementById('game');
const ctx = canvas.getContext('2d');
const scoreElement = document.getElementById('score');
const messageElement = document.getElementById('message');

// Game Constants
const GRAVITY = 0.6;
const FRICTION = 0.8;
const PLAYER_SPEED = 5;
const JUMP_FORCE = -12;
const WORLD_WIDTH = 2000; // The level is wider than the canvas

// Game State
let score = 0;
let gameOver = false;
let win = false;

// Input handling
const keys = {};
window.addEventListener('keydown', (e) => keys[e.code] = true);
window.addEventListener('keyup', (e) => keys[e.code] = false);

// Entities
class Player {
    constructor() {
        this.width = 30;
        this.height = 40;
        this.x = 50;
        this.y = 300;
        this.vx = 0;
        this.vy = 0;
        this.grounded = false;
        this.color = '#e74c3c'; // Red character
    }

    update() {
        // Input
        if (keys['ArrowLeft'] || keys['KeyA']) {
            if (this.vx > -PLAYER_SPEED) this.vx--;
        }
        if (keys['ArrowRight'] || keys['KeyD']) {
            if (this.vx < PLAYER_SPEED) this.vx++;
        }
        if ((keys['ArrowUp'] || keys['KeyW'] || keys['Space']) && this.grounded) {
            this.vy = JUMP_FORCE;
            this.grounded = false;
        }

        // Physics
        this.vx *= FRICTION;
        this.vy += GRAVITY;

        this.x += this.vx;
        this.y += this.vy;

        // Boundary checks (left/right)
        if (this.x < 0) this.x = 0;
        if (this.x + this.width > WORLD_WIDTH) this.x = WORLD_WIDTH - this.width;

        // Ground/Platform collision is handled in the main loop
    }

    draw(cameraX) {
        ctx.fillStyle = this.color;
        ctx.fillRect(this.x - cameraX, this.y, this.width, this.height);
        
        // Draw a little "eye" to show direction
        ctx.fillStyle = 'white';
        let eyeOffset = this.vx >= 0 ? 18 : 5;
        ctx.fillRect(this.x - cameraX + eyeOffset, this.y + 8, 7, 7);
    }
}

class Platform {
    constructor(x, y, w, h, color = '#2ecc71') {
        this.x = x;
        this.y = y;
        this.w = w;
        this.h = h;
        this.color = color;
    }

    draw(cameraX) {
        ctx.fillStyle = this.color;
        ctx.fillRect(this.x - cameraX, this.y, this.w, this.h);
        // Add a little detail
        ctx.strokeStyle = 'rgba(0,0,0,0.1)';
        ctx.strokeRect(this.x - cameraX, this.y, this.w, this.h);
    }
}

class Coin {
    constructor(x, y) {
        this.x = x;
        this.y = y;
        this.radius = 10;
        this.collected = false;
        this.angle = 0;
    }

    update() {
        this.angle += 0.1;
    }

    draw(cameraX) {
        if (this.collected) return;
        ctx.fillStyle = '#f1c40f';
        ctx.beginPath();
        let wobble = Math.sin(this.angle) * 3;
        ctx.arc(this.x - cameraX, this.y + wobble, this.radius, 0, Math.PI * 2);
        ctx.fill();
        ctx.strokeStyle = '#d4ac0d';
        ctx.lineWidth = 2;
        ctx.stroke();
    }
}

class Goal {
    constructor(x, y) {
        this.x = x;
        this.y = y;
        this.w = 40;
        this.h = 100;
    }

    draw(cameraX) {
        // Flag pole
        ctx.fillStyle = '#7f8c8d';
        ctx.fillRect(this.x - cameraX, this.y, 5, this.h);
        // Flag
        ctx.fillStyle = '#f1c40f';
        ctx.fillRect(this.x - cameraX + 5, this.y, 30, 20);
    }
}

// Initialize Game Objects
const player = new Player();
const platforms = [
    new Platform(0, 400, 1000, 50), // Ground 1
    new Platform(1100, 400, 900, 50), // Ground 2 (gap in between)
    new Platform(200, 300, 150, 20),  // Platform 1
    new Platform(450, 220, 150, 20), // Platform 2
    new Platform(700, 300, 150, 20),  // Platform 3
    new Platform(1200, 300, 200, 20), // Platform 4
    new Platform(1500, 200, 100, 20), // Platform 5
];

const coins = [
    new Coin(250, 250),
    new Coin(500, 180),
    new Coin(750, 250),
    new Coin(1250, 250),
    new Coin(1550, 150),
    new Coin(1800, 350),
];

const goal = new Goal(1900, 300);

let cameraX = 0;

function checkCollisions() {
    player.grounded = false;

    for (let p of platforms) {
        // AABB collision
        if (player.x < p.x + p.w &&
            player.x + player.width > p.x &&
            player.y < p.y + p.h &&
            player.y + player.height > p.y) {
            
            // Calculate overlap depths to find collision direction
            let overlapX = Math.min(player.x + player.width - p.x, p.x + p.w - player.x);
            let overlapY = Math.min(player.y + player.height - p.y, p.y + p.h - player.y);

            if (overlapX < overlapY) {
                // Collision on X axis
                if (player.x < p.x) {
                    player.x = p.x - player.width;
                } else {
                    player.x = p.x + p.w;
                }
                player.vx = 0;
            } else {
                // Collision on Y axis
                if (player.y + player.height / 2 < p.y + player.h / 2) {
                    // Falling onto platform
                    player.y = p.y - player.height;
                    player.vy = 0;
                    player.grounded = true;
                } else {
                    // Hitting head on platform
                    player.y = p.y + p.h;
                    player.vy = 0;
                }
            }
        }
    }

    // Coin collection
    for (let coin of coins) {
        if (!coin.collected) {
            let dx = (player.x + player.width/2) - coin.x;
            let dy = (player.y + player.height/2) - coin.y;
            let distance = Math.sqrt(dx * dx + dy * dy);
            if (distance < player.width/2 + coin.radius) {
                coin.collected = true;
                score += 100;
                scoreElement.innerText = score;
            }
        }
    }

    // Goal check
    if (player.x + player.width > goal.x && player.x < goal.x + goal.w &&
        player.y + player.height > goal.y && player.y < goal.y + goal.h) {
        win = true;
        messageElement.innerText = "YOU WIN!";
        messageElement.style.color = "#2ecc71";
        messageElement.style.display = "block";
        gameOver = true;
    }

    // Fall off world
    if (player.y > canvas.height) {
        gameOver = true;
        messageElement.innerText = "GAME OVER";
        messageElement.style.color = "#e74c3c";
        messageElement.style.display = "block";
    }
}

function update() {
    if (gameOver) return;

    player.update();
    
    for (let coin of coins) {
        coin.update();
    }

    checkCollisions();

    // Camera follows player
    // Center camera on player
    let targetCameraX = player.x - canvas.width / 2;
    // Clamp camera
    if (targetCameraX < 0) targetCameraX = 0;
    if (targetCameraX > WORLD_WIDTH - canvas.width) targetCameraX = WORLD_WIDTH - canvas.width;
    
    // Smooth camera
    cameraX += (targetCameraX - cameraX) * 0.1;
}

function draw() {
    // Clear canvas
    ctx.clearRect(0, 0, canvas.width, canvas.height);

    // Draw background clouds/decoration (static simple shapes)
    ctx.fillStyle = 'rgba(255, 255, 255, 0.3)';
    ctx.beginPath(); ctx.arc(100 - cameraX * 0.2, 100, 40, 0, Math.PI*2); ctx.fill();
    ctx.beginPath(); ctx.arc(140 - cameraX * 0.2, 110, 50, 0, Math.PI*2); ctx.fill();
    ctx.beginPath(); ctx.arc(500 - cameraX * 0.2, 80, 30, 0, Math.PI*2); ctx.fill();
    ctx.beginPath(); ctx.arc(800 - cameraX * 0.2, 150, 60, 0, Math.PI*2); ctx.fill();

    // Draw platforms
    for (let p of platforms) {
        p.draw(cameraX);
    }

    // Draw coins
    for (let coin of coins) {
        coin.draw(cameraX);
    }

    // Draw goal
    goal.draw(cameraX);

    // Draw player
    player.draw(cameraX);
}

function gameLoop() {
    update();
    draw();
    requestAnimationFrame(gameLoop);
}

// Start the game
gameLoop();
index.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Super Mario Style Platformer</title>
    <style>
        body {
            margin: 0;
            padding: 0;
            display: flex;
            justify-content: center;
            align-items: center;
            height: 100vh;
            background-color: #333;
            font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            color: white;
            overflow: hidden;
        }
        #game-container {
            position: relative;
            box-shadow: 0 0 50px rgba(0,0,0,0.5);
        }
        canvas {
            background-color: #5c94fc; /* Sky blue */
            display: block;
        }
        #ui {
            position: absolute;
            top: 10px;
            left: 10px;
            pointer-events: none;
            text-shadow: 2px 2px 2px rgba(0,0,0,0.5);
            font-size: 24px;
        }
        #message {
            position: absolute;
            top: 50%;
            left: 50%;
            transform: translate(-50%, -50%);
            font-size: 48px;
            text-align: center;
            display: none;
            text-shadow: 3px 3px 5px rgba(0,0,0,0.8);
        }
    </style>
</head>
<body>
    <div id="game-container">
        <canvas id="game" width="800" height="450"></canvas>
        <div id="ui">Coins: <span id="score">0</span></div>
        <div id="message"></div>
    </div>
    <script src="game.js"></script>
</body>
</html>

rep 4 UNGRADED

pi 31.7s · verify 4.1s · 18830 tok · responded: gemma-4-26b-a4b · transcript

smoke 3/3

screenshot

verify output
CHECK PASS: canvas #game exists and is sized
CHECK PASS: no uncaught JS errors on load
CHECK PASS: keyboard input does not throw
score: 3/3 (100%)
produced code
game.js
const canvas = document.getElementById('game');
const ctx = canvas.getContext('2d');
const scoreElement = document.getElementById('score');

// Game Constants
const GRAVITY = 0.6;
const FRICTION = 0.8;
const PLAYER_SPEED = 5;
const JUMP_FORCE = -12;
const CANVAS_WIDTH = 800;
const CANVAS_HEIGHT = 450;

// Game State
let score = 0;
let gameActive = true;
let gameOverReason = "";

// Input state
const keys = {};

// Entity Classes
class Player {
    constructor() {
        this.width = 30;
        this.height = 40;
        this.x = 50;
        this.y = CANVAS_HEIGHT - 100;
        this.vx = 0;
        this.vy = 0;
        this.grounded = false;
        this.color = "#ff4444";
    }

    update() {
        if (keys['ArrowLeft'] || keys['KeyA']) {
            if (this.vx > -PLAYER_SPEED) this.vx--;
        }
        if (keys['ArrowRight'] || keys['KeyD']) {
            if (this.vx < PLAYER_SPEED) this.vx++;
        }
        if ((keys['ArrowUp'] || keys['KeyW'] || keys['Space']) && this.grounded) {
            this.vy = JUMP_FORCE;
            this.grounded = false;
        }

        this.vx *= FRICTION;
        this.vy += GRAVITY;

        this.x += this.vx;
        this.y += this.vy;

        // Collision with screen bounds
        if (this.x < 0) this.x = 0;
        if (this.x + this.width > CANVAS_WIDTH) this.x = CANVAS_WIDTH - this.width;
        
        // Basic floor collision (hardcoded floor at bottom for safety)
        if (this.y + this.height > CANVAS_HEIGHT - 20) {
            this.y = CANVAS_HEIGHT - 20 - this.height;
            this.vy = 0;
            this.grounded = true;
        } else {
            this.grounded = false;
        }

        // Check if fell off map (if we had a real camera, but here it's fixed)
        if (this.y > CANVAS_HEIGHT) {
            gameOver("You fell!");
        }
    }

    draw() {
        ctx.fillStyle = this.color;
        ctx.fillRect(this.x, this.y, this.width, this.height);
        // Eyes to show direction
        ctx.fillStyle = "white";
        let eyeOffset = this.vx >= 0 ? 20 : 5;
        ctx.fillRect(this.x + eyeOffset, this.y + 10, 5, 5);
    }
}

class Platform {
    constructor(x, y, w, h) {
        this.x = x;
        this.y = y;
        this.w = w;
        this.h = h;
        this.color = "#8B4513";
    }

    draw() {
        ctx.fillStyle = this.color;
        ctx.fillRect(this.x, this.y, this.w, this.h);
        // Grass top
        ctx.fillStyle = "#228B22";
        ctx.fillRect(this.x, this.y, this.w, 5);
    }
}

class Coin {
    constructor(x, y) {
        this.x = x;
        this.y = y;
        this.radius = 10;
        this.collected = false;
        this.floatY = 0;
    }

    update() {
        this.floatY = Math.sin(Date.now() / 200) * 5;
    }

    draw() {
        if (this.collected) return;
        ctx.beginPath();
        ctx.arc(this.x, this.y + this.floatY, this.radius, 0, Math.PI * 2);
        ctx.fillStyle = "#FFD700";
        ctx.fill();
        ctx.strokeStyle = "#DAA520";
        ctx.lineWidth = 2;
        ctx.stroke();
        ctx.closePath();
    }
}

class Goal {
    constructor(x, y) {
        this.x = x;
        this.y = y;
        this.w = 30;
        this.h = 60;
    }

    draw() {
        // Flag pole
        ctx.fillStyle = "#ddd";
        ctx.fillRect(this.x, this.y, 5, this.h);
        // Flag
        ctx.fillStyle = "red";
        ctx.beginPath();
        ctx.moveTo(this.x + 5, this.y);
        ctx.lineTo(this.x + 30, this.y + 15);
        ctx.lineTo(this.x + 5, this.y + 30);
        ctx.fill();
    }
}

// Game instance
let player;
let platforms = [];
let coins = [];
let goal;

function init() {
    player = new Player();
    platforms = [
        new Platform(0, CANVAS_HEIGHT - 20, CANVAS_WIDTH, 20), // Floor
        new Platform(150, 300, 150, 20),
        new Platform(400, 220, 150, 20),
        new Platform(100, 150, 100, 20),
        new Platform(600, 300, 150, 20),
    ];
    coins = [
        new Coin(225, 270),
        new Coin(475, 190),
        new Coin(150, 120),
        new Coin(675, 270),
    ];
    goal = new Goal(750, CANVAS_HEIGHT - 80);
    score = 0;
    scoreElement.innerText = score;
    gameActive = true;
    gameOverReason = "";
}

function checkCollisions() {
    // Platform collisions
    player.grounded = false;
    // We check against the ground-floor which is already handled in player.update,
    // but we need to handle the other platforms.
    
    // Re-check grounding based on all platforms
    platforms.forEach(p => {
        // Collision detection (AABB)
        if (player.x < p.x + p.w &&
            player.x + player.width > p.x &&
            player.y < p.y + p.h &&
            player.y + player.height > p.y) {
            
            // Determine collision side
            // To keep it simple for a platformer:
            // If player is falling and above the platform, land on top.
            if (player.vy > 0 && player.y + player.height - player.vy <= p.y) {
                player.y = p.y - player.height;
                player.vy = 0;
                player.grounded = true;
            }
        }
    });

    // Coin collisions
    coins.forEach(c => {
        if (!c.collected) {
            let dx = player.x + player.width/2 - c.x;
            let dy = player.y + player.height/2 - (c.y + c.floatY);
            let distance = Math.sqrt(dx*dx + dy*dy);
            if (distance < player.width/2 + c.radius) {
                c.collected = true;
                score += 10;
                scoreElement.innerText = score;
            }
        }
    });

    // Goal collision
    if (player.x < goal.x + goal.w &&
        player.x + player.width > goal.x &&
        player.y < goal.y + goal.h &&
        player.y + player.height > goal.y) {
        gameOver("YOU WIN!");
    }
}

function gameOver(reason) {
    gameActive = false;
    gameOverReason = reason;
}

function update() {
    if (!gameActive) return;

    player.update();
    coins.forEach(c => c.update());
    checkCollisions();
}

function draw() {
    // Clear canvas
    ctx.clearRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT);

    // Draw Background (Clouds/Sun simple shapes)
    ctx.fillStyle = "white";
    ctx.beginPath(); ctx.arc(100, 80, 30, 0, Math.PI*2); ctx.fill();
    ctx.beginPath(); ctx.arc(130, 80, 40, 0, Math.PI*2); ctx.fill();
    ctx.beginPath(); ctx.arc(160, 80, 30, 0, Math.PI*2); ctx.fill();
    
    ctx.fillStyle = "#FFD700";
    ctx.beginPath(); ctx.arc(700, 60, 40, 0, Math.PI*2); ctx.fill();

    // Draw entities
    platforms.forEach(p => p.draw());
    coins.forEach(c => c.draw());
    goal.draw();
    player.draw();

    if (!gameActive) {
        ctx.fillStyle = "rgba(0, 0, 0, 0.5)";
        ctx.fillRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT);
        ctx.fillStyle = "white";
        ctx.font = "48px Arial";
        ctx.textAlign = "center";
        ctx.fillText(gameOverReason, CANVAS_WIDTH/2, CANVAS_HEIGHT/2);
        ctx.font = "24px Arial";
        ctx.fillText("Press 'R' to restart", CANVAS_WIDTH/2, CANVAS_HEIGHT/2 + 50);
    }
}

function loop() {
    update();
    draw();
    requestAnimationFrame(loop);
}

// Event Listeners
window.addEventListener('keydown', e => {
    keys[e.code] = true;
    if (e.code === 'KeyR' && !gameActive) {
        init();
    }
});
window.addEventListener('keyup', e => {
    keys[e.code] = false;
});

// Start game
init();
loop();
index.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Super Mario Style Platformer</title>
    <style>
        body {
            margin: 0;
            padding: 0;
            display: flex;
            justify-content: center;
            align-items: center;
            height: 100vh;
            background-color: #333;
            font-family: Arial, sans-serif;
            overflow: hidden;
        }
        canvas {
            background-color: #5c94fc;
            border: 4px solid #000;
            box-shadow: 0 0 20px rgba(0,0,0,0.5);
        }
        #ui {
            position: absolute;
            top: 20px;
            left: 50%;
            transform: translateX(-50%);
            color: white;
            font-size: 24px;
            text-shadow: 2px 2px 4px rgba(0,0,0,0.5);
            pointer-events: none;
        }
    </style>
</head>
<body>
    <div id="ui">Coins: <span id="score">0</span></div>
    <canvas id="game" width="800" height="450"></canvas>
    <script src="game.js"></script>
</body>
</html>

rep 5 UNGRADED

pi 27.5s · verify 4.2s · 17515 tok · responded: gemma-4-26b-a4b · transcript

smoke 3/3

screenshot

verify output
CHECK PASS: canvas #game exists and is sized
CHECK PASS: no uncaught JS errors on load
CHECK PASS: keyboard input does not throw
score: 3/3 (100%)
produced code
game.js
const canvas = document.getElementById('game');
const ctx = canvas.getContext('2d');

// Game constants
const GRAVITY = 0.6;
const FRICTION = 0.8;
const PLAYER_SPEED = 5;
const JUMP_FORCE = -12;
const GROUND_HEIGHT = 40;

// Game state
let score = 0;
let gameActive = true;
let winState = false;

// Input state
const keys = {};

// Player object
const player = {
    x: 50,
    y: 300,
    width: 30,
    height: 30,
    velX: 0,
    velY: 0,
    color: '#ff4444',
    onGround: false
};

// Platforms
const platforms = [
    { x: 0, y: 410, width: 2000, height: 40, color: '#8B4513' }, // Main ground
    { x: 200, y: 300, width: 150, height: 20, color: '#555' },
    { x: 450, y: 220, width: 150, height: 20, color: '#555' },
    { x: 150, y: 150, width: 100, height: 20, color: '#555' },
    { x: 700, y: 320, width: 100, height: 20, color: '#555' }
];

// Collectibles (Coins)
const coins = [
    { x: 250, y: 260, width: 15, height: 15, collected: false },
    { x: 480, y: 180, width: 15, height: 15, collected: false },
    { x: 180, y: 110, width: 15, height: 15, collected: false },
    { x: 720, y: 280, width: 15, height: 15, collected: false },
    { x: 1000, y: 370, width: 15, height: 15, collected: false }
];

// Goal
const goal = {
    x: 1200,
    y: 310,
    width: 40,
    height: 100,
    color: '#ffd700' // Gold flag pole
};

// Camera offset
let cameraX = 0;

// Event listeners
window.addEventListener('keydown', (e) => {
    keys[e.code] = true;
});

window.addEventListener('keyup', (e) => {
    keys[e.code] = false;
});

function update() {
    if (!gameActive) return;

    // Movement
    if (keys['ArrowRight'] || keys['KeyD']) {
        if (player.velX < PLAYER_SPEED) player.velX++;
    }
    if (keys['ArrowLeft'] || keys['KeyA']) {
        if (player.velX > -PLAYER_SPEED) player.velX--;
    }
    if ((keys['Space'] || keys['ArrowUp'] || keys['KeyW']) && player.onGround) {
        player.velY = JUMP_FORCE;
        player.onGround = false;
    }

    // Apply physics
    player.velX *= FRICTION;
    player.velY += GRAVITY;
    player.x += player.velX;
    player.y += player.velY;

    // Platform collisions
    player.onGround = false;
    for (let plat of platforms) {
        // Check if player is within the platform bounds horizontally
        if (player.x < plat.x + plat.width &&
            player.x + player.width > plat.x &&
            player.y < plat.y + plat.height &&
            player.y + player.height > plat.y) {
            
            // Check collision from top (landing)
            if (player.velY > 0 && player.y + player.height - player.velY <= plat.y) {
                player.y = plat.y - player.height;
                player.velY = 0;
                player.onGround = true;
            } 
            // Check collision from bottom (hitting head)
            else if (player.velY < 0 && player.y - player.velY >= plat.y + plat.height) {
                player.y = plat.y + plat.height;
                player.velY = 0;
            }
            // Check collision from sides
            else {
                // Simple side collision: push out
                if (player.x + player.width/2 < plat.x + plat.width/2) {
                    player.x = plat.x - player.width;
                } else {
                    player.x = plat.x + plat.width;
                }
                player.velX = 0;
            }
        }
    }

    // Collectibles collision
    for (let coin of coins) {
        if (!coin.collected &&
            player.x < coin.x + coin.width &&
            player.x + player.width > coin.x &&
            player.y < coin.y + coin.height &&
            player.y + player.height > coin.y) {
            coin.collected = true;
            score += 10;
        }
    }

    // Goal collision
    if (player.x < goal.x + goal.width &&
        player.x + player.width > goal.x &&
        player.y < goal.y + goal.height &&
        player.y + player.height > goal.y) {
        winState = true;
        gameActive = false;
    }

    // Screen bounds (fall off map)
    if (player.y > canvas.height) {
        // Reset player
        player.x = 50;
        player.y = 300;
        player.velX = 0;
        player.velY = 0;
    }

    // Camera follow
    // We center the camera on the player but keep it within reasonable bounds
    cameraX = player.x - canvas.width / 4;
    if (cameraX < 0) cameraX = 0;

    // Check if all coins collected for a bonus win or just to check?
    // Let's just say reaching the flag is the win state.
}

function draw() {
    // Clear canvas
    ctx.clearRect(0, 0, canvas.width, canvas.height);

    ctx.save();
    ctx.translate(-cameraX, 0);

    // Draw platforms
    for (let plat of platforms) {
        ctx.fillStyle = plat.color;
        ctx.fillRect(plat.x, plat.y, plat.width, plat.height);
    }

    // Draw coins
    ctx.fillStyle = '#ffd700';
    for (let coin of coins) {
        if (!coin.collected) {
            ctx.beginPath();
            ctx.arc(coin.x + coin.width/2, coin.y + coin.height/2, coin.width/2, 0, Math.PI * 2);
            ctx.fill();
        }
    }

    // Draw goal
    ctx.fillStyle = goal.color;
    ctx.fillRect(goal.x, goal.y, goal.width, goal.height);
    // Add a small flag at top
    ctx.fillStyle = '#ff0000';
    ctx.fillRect(goal.x - 10, goal.y, 20, 15);

    // Draw player
    ctx.fillStyle = player.color;
    ctx.fillRect(player.x, player.y, player.width, player.height);

    ctx.restore();

    // UI (Score)
    ctx.fillStyle = 'white';
    ctx.font = '24px Arial';
    ctx.fillText(`Score: ${score}`, 20, 40);

    if (winState) {
        ctx.fillStyle = 'rgba(0, 0, 0, 0.5)';
        ctx.fillRect(0, 0, canvas.width, canvas.height);
        ctx.fillStyle = 'white';
        ctx.font = '48px Arial';
        ctx.textAlign = 'center';
        ctx.fillText('YOU WIN!', canvas.width / 2, canvas.height / 2);
        ctx.font = '24px Arial';
        ctx.fillText('Press F5 to play again', canvas.width / 2, canvas.height / 2 + 40);
    }
}

function gameLoop() {
    update();
    draw();
    requestAnimationFrame(gameLoop);
}

// Start game
gameLoop();
index.html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Super Mario Style Platformer</title>
    <style>
        body {
            margin: 0;
            padding: 0;
            display: flex;
            justify-content: center;
            align-items: center;
            height: 100vh;
            background-color: #333;
            color: white;
            font-family: sans-serif;
            flex-direction: column;
        }
        canvas {
            background-color: #5c94fc; /* Sky blue */
            border: 4px solid #000;
            box-shadow: 0 0 20px rgba(0,0,0,0.5);
            display: block;
        }
        .instructions {
            margin-top: 20px;
            text-align: center;
        }
    </style>
</head>
<body>
    <canvas id="game" width="800" height="450"></canvas>
    <div class="instructions">
        <p>Use <b>WASD</b> or <b>Arrow Keys</b> to move and jump!</p>
        <p>Collect all coins to reach the goal!</p>
    </div>
    <script src="game.js"></script>
</body>
</html>