← run 2026-06-30T130601Z-3ea440b-minimal

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

rep 1 UNGRADED

pi 45.8s · verify 4.1s · 18064 tok · responded: google/gemma-4-26b-a4b-it · 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 Settings
const GRAVITY = 0.8;
const FRICTION = 0.8;
const PLAYER_SPEED = 5;
const JUMP_FORCE = -15;

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

// 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 = 40;
        this.velX = 0;
        this.velY = 0;
        this.grounded = false;
        this.color = '#FF4500'; // OrangeRed
    }

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

        // Apply Physics
        this.velX *= FRICTION;
        this.velY += GRAVITY;

        this.x += this.velX;
        this.y += this.velY;

        // Boundary checks (horizontal)
        if (this.x < 0) this.x = 0;
        if (this.x + this.width > canvas.width) this.x = canvas.width - this.width;

        // World floor (death if falling too far)
        if (this.y > canvas.height) {
            this.reset();
        }
    }

    reset() {
        this.x = 50;
        this.y = 300;
        this.velX = 0;
        this.velY = 0;
        // Note: score doesn't reset if we want it to persist, 
        // but usually you lose progress. Let's reset score too.
        score = 0;
        scoreElement.innerText = score;
    }

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

class Platform {
    constructor(x, y, width, height, color = '#8B4513') {
        this.x = x;
        this.y = y;
        this.width = width;
        this.height = height;
        this.color = color;
    }

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

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

    draw() {
        if (this.collected) return;
        ctx.fillStyle = '#FFD700'; // Gold
        ctx.beginPath();
        ctx.arc(this.x, this.y, this.radius, 0, Math.PI * 2);
        ctx.fill();
        ctx.strokeStyle = '#B8860B';
        ctx.stroke();
    }
}

class Goal {
    constructor(x, y) {
        this.x = x;
        this.y = y;
        this.width = 20;
        this.height = 60;
    }

    draw() {
        // Flag pole
        ctx.fillStyle = '#333';
        ctx.fillRect(this.x, this.y, 5, this.height);
        // Flag
        ctx.fillStyle = 'red';
        ctx.fillRect(this.x + 5, this.y, 25, 15);
    }
}

// Initialization
const player = new Player(50, 300);
const platforms = [
    new Platform(0, 400, 800, 50, '#228B22'), // Main ground
    new Platform(150, 300, 150, 20),          // Platform 1
    new Platform(400, 220, 150, 20),          // Platform 2
    new Platform(600, 150, 100, 20),          // Platform 3
    new Platform(300, 100, 100, 20),          // Platform 4
];

const coins = [
    new Coin(225, 270),
    new Coin(475, 190),
    new Coin(650, 120),
    new Coin(350, 70),
];

const goal = new Goal(750, 340);

function checkCollisions() {
    player.grounded = false;

    // Platform collision
    for (let platform of platforms) {
        if (player.x < platform.x + platform.width &&
            player.x + player.width > platform.x &&
            player.y < platform.y + platform.height &&
            player.y + player.height > platform.y) {
            
            // Determine collision side
            let overlapTop = (player.y + player.height) - platform.y;
            let overlapBottom = (platform.y + platform.height) - player.y;
            let overlapLeft = (player.x + player.width) - platform.x;
            let overlapRight = (platform.x + platform.width) - player.x;

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

            if (minOverlap === overlapTop && player.velY >= 0) {
                // Colliding with top of platform
                player.y = platform.y - player.height;
                player.velY = 0;
                player.grounded = true;
            } else if (minOverlap === overlapBottom && player.velY <= 0) {
                // Colliding with bottom of platform
                player.y = platform.y + platform.height;
                player.velY = 0;
            } else if (minOverlap === overlapLeft) {
                // Colliding with left side
                player.x = platform.x - player.width;
                player.velX = 0;
            } else if (minOverlap === overlapRight) {
                // Colliding with right side
                player.x = platform.x + platform.width;
                player.velX = 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 += 10;
                scoreElement.innerText = score;
            }
        }
    }

    // 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) {
        gameActive = false;
        gameOverMessage = "YOU WIN!";
    }
}

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

    player.update();
    checkCollisions();
}

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

    // Draw Background (optional - sky is already in CSS)
    
    // 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 = 'bold 48px sans-serif';
        ctx.textAlign = 'center';
        ctx.fillText(gameOverMessage, 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 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>Simple 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 #000;
            box-shadow: 0 0 20px rgba(0,0,0,0.5);
        }
        .ui {
            margin-top: 10px;
            font-size: 24px;
        }
        .controls {
            margin-top: 10px;
            font-size: 14px;
            color: #ccc;
        }
    </style>
</head>
<body>
    <div class="ui">Score: <span id="score">0</span></div>
    <canvas id="game" width="800" height="450"></canvas>
    <div class="controls">Use Arrow Keys or WASD to move and jump. Reach the Flag!</div>

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

rep 2 UNGRADED

pi 67.8s · verify 4.1s · 18911 tok · responded: google/gemma-4-26b-a4b-it · 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 ui = document.getElementById('ui');

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

// 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;
});

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, this.y, this.width, this.height);
    }
}

class Player extends Entity {
    constructor(x, y) {
        super(x, y, 30, 30, '#ff0000'); // Red player
        this.velX = 0;
        this.velY = 0;
        this.grounded = false;
    }

    update() {
        // Movement
        if (keys['ArrowLeft'] || keys['KeyA']) {
            if (this.velX > -PLAYER_SPEED) this.velX--;
        }
        if (keys['ArrowRight'] || keys['KeyD']) {
            if (this.velX < PLAYER_SPEED) this.velX++;
        }

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

        // Physics
        this.velX *= FRICTION;
        this.velY += GRAVITY;

        this.x += this.velX;
        this.y += this.velY;

        // Level bounds
        if (this.x < 0) this.x = 0;
        if (this.x + this.width > camera.x + CANVAS_WIDTH) {
            // We'll handle camera scrolling instead of hard stopping for now, 
            // but let's ensure player doesn't go off screen left
        }

        this.grounded = false;
    }

    draw() {
        // Draw player body
        ctx.fillStyle = this.color;
        ctx.fillRect(this.x, this.y, this.width, this.height);
        // Draw eyes to show direction
        ctx.fillStyle = 'white';
        let eyeOffset = this.velX >= 0 ? 15 : 5;
        ctx.fillRect(this.x + eyeOffset, this.y + 5, 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 + this.width/2, this.y + this.height/2, this.width/2, 0, Math.PI * 2);
        ctx.fill();
        // Shine
        ctx.fillStyle = 'white';
        ctx.fillRect(this.x + 4, this.y + 4, 3, 3);
    }
}

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

    draw() {
        // Flag pole
        ctx.fillStyle = '#333';
        ctx.fillRect(this.x + 15, this.y, 10, this.height);
        // Flag
        ctx.fillStyle = 'red';
        ctx.fillRect(this.x + 25, this.y, 20, 15);
    }
}

// Level Data
const platforms = [
    new Platform(0, 400, 1000, 50), // Ground
    new Platform(1200, 400, 800, 50), // Ground gap
    new Platform(2200, 400, 1000, 50), // Ground gap
    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(1300, 300, 100, 20), // Platform 4
    new Platform(1500, 200, 100, 20), // Platform 5
    new Platform(1700, 300, 200, 20), // Platform 6
    new Platform(2400, 300, 200, 20), // Platform 7
];

const coins = [
    new Coin(250, 260),
    new Coin(500, 180),
    new Coin(750, 260),
    new Coin(1350, 260),
    new Coin(1550, 160),
    new Coin(1800, 260),
    new Coin(2500, 260),
];

const goal = new Goal(3000, 300);

const player = new Player(50, 300);
const camera = { x: 0 };

function checkCollision(rect1, rect2) {
    return rect1.x < rect2.x + rect2.width &&
           rect1.x + rect1.width > rect2.x &&
           rect1.y < rect2.y + rect2.height &&
           rect1.y + rect1.height > rect2.y;
}

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

    player.update();

    // Platform collisions
    platforms.forEach(p => {
        if (checkCollision(player, p)) {
            // Determine collision side
            const overlapX = Math.min(player.x + player.width, p.x + p.width) - Math.max(player.x, p.x);
            const overlapY = Math.min(player.y + player.height, p.y + p.height) - Math.max(player.y, p.y);

            if (overlapX > overlapY) {
                // Vertical collision
                if (player.velY > 0 && player.y < p.y) {
                    // Falling onto platform
                    player.y = p.y - player.height;
                    player.velY = 0;
                    player.grounded = true;
                } else if (player.velY < 0 && player.y > p.y) {
                    // Hitting head
                    player.y = p.y + p.height;
                    player.velY = 0;
                }
            } else {
                // Horizontal collision
                if (player.velX > 0 && player.x < p.x) {
                    player.x = p.x - player.width;
                    player.velX = 0;
                } else if (player.velX < 0 && player.x > p.x) {
                    player.x = p.x + p.width;
                    player.velX = 0;
                }
            }
        }
    });

    // Coin collisions
    coins.forEach(c => {
        if (!c.collected && checkCollision(player, c)) {
            c.collected = true;
            score += 10;
            ui.innerText = `Score: ${score}`;
        }
    });

    // Goal collision
    if (checkCollision(player, goal)) {
        win = true;
    }

    // Death condition (fall off map)
    if (player.y > CANVAS_HEIGHT) {
        gameOver = true;
    }

    // Camera follow
    camera.x = player.x - CANVAS_WIDTH / 4;
    if (camera.x < 0) camera.x = 0;
}

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

    ctx.save();
    ctx.translate(-camera.x, 0);

    // Draw platforms
    platforms.forEach(p => p.draw());

    // Draw coins
    coins.forEach(c => c.draw());

    // Draw goal
    goal.draw();

    // Draw player
    player.draw();

    ctx.restore();

    if (gameOver) {
        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('GAME OVER', CANVAS_WIDTH / 2, CANVAS_HEIGHT / 2);
        ctx.font = '24px Arial';
        ctx.fillText('Press F5 to restart', CANVAS_WIDTH / 2, CANVAS_HEIGHT / 2 + 40);
    }

    if (win) {
        ctx.fillStyle = 'rgba(0,0,0,0.5)';
        ctx.fillRect(0, 0, CANVAS_WIDTH, CANVAS_HEIGHT);
        ctx.fillStyle = 'gold';
        ctx.font = '48px Arial';
        ctx.textAlign = 'center';
        ctx.fillText('YOU WIN!', CANVAS_WIDTH / 2, CANVAS_HEIGHT / 2);
        ctx.font = '24px Arial';
        ctx.fillText(`Final Score: ${score}`, CANVAS_WIDTH / 2, CANVAS_HEIGHT / 2 + 40);
    }
}

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

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: Arial, sans-serif;
            overflow: hidden;
        }
        canvas {
            background-color: #5c94fc; /* Classic Mario Sky Blue */
            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 #000;
            pointer-events: none;
            user-select: none;
        }
    </style>
</head>
<body>
    <div id="ui">Score: 0</div>
    <canvas id="game" width="800" height="450"></canvas>
    <script src="game.js"></script>
</body>
</html>

rep 3 UNGRADED

pi 174.4s · verify 4.1s · 18512 tok · responded: google/gemma-4-26b-a4b-it · 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.5;
const FRICTION = 0.8;
const PLAYER_SPEED = 5;
const JUMP_FORCE = -12;
const TILE_SIZE = 30;

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

const keys = {};

// Player Object
const player = {
    x: 50,
    y: 300,
    width: 30,
    height: 30,
    velX: 0,
    velY: 0,
    jumping: false,
    color: '#ff0000' // Red character
};

// Level Data
// Platforms: { x, y, width, height }
const platforms = [
    { x: 0, y: 420, width: 2000, height: 30 },    // Ground
    { x: 200, y: 320, width: 100, height: 20 },   // Platform 1
    { x: 400, y: 240, width: 150, height: 20 },   // Platform 2
    { x: 650, y: 320, width: 100, height: 20 },   // Platform 3
    { x: 850, y: 220, width: 120, height: 20 },   // Platform 4
    { x: 1100, y: 320, width: 200, height: 20 },  // Platform 5
    { x: 1400, y: 200, width: 100, height: 20 },  // Platform 6
];

// Collectibles: { x, y, radius, collected }
const collectibles = [
    { x: 250, y: 290, radius: 8, collected: false },
    { x: 475, y: 210, radius: 8, collected: false },
    { x: 700, y: 290, radius: 8, collected: false },
    { x: 910, y: 190, radius: 8, collected: false },
    { x: 1150, y: 290, radius: 8, collected: false },
    { x: 1450, y: 170, radius: 8, collected: false },
];

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

// Camera
const camera = {
    x: 0
};

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

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

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

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

    // Apply Physics
    player.velX *= FRICTION;
    player.velY += GRAVITY;

    player.x += player.velX;
    player.y += player.velY;

    // Collisions with Platforms
    player.jumping = true; // Assume jumping until proven on ground
    for (const plat of platforms) {
        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) {
            
            // Simple collision resolution
            // Check if player is falling onto the platform
            if (player.velY > 0 && (player.y + player.height - player.velY) <= plat.y) {
                player.y = plat.y - player.height;
                player.velY = 0;
                player.jumping = false;
            } 
            // Check if player is hitting the bottom of the platform
            else if (player.velY < 0 && (player.y - player.velY) >= plat.y + plat.height) {
                player.y = plat.y + plat.height;
                player.velY = 0;
            }
            // Side collisions (basic)
            else {
                // For simplicity in this small demo, we'll just prevent passing through sides
                // but mostly focus on top/bottom for platformer feel.
                // If we hit a side, let's just push the player back a bit or stop movement.
                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
    for (const coin of collectibles) {
        if (!coin.collected) {
            const dx = player.x + player.width/2 - coin.x;
            const dy = player.y + player.height/2 - coin.y;
            const distance = Math.sqrt(dx * dx + dy * dy);
            if (distance < player.width/2 + coin.radius) {
                coin.collected = true;
                score += 10;
                scoreElement.innerText = score;
            }
        }
    }

    // Goal Check
    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) {
        win = true;
    }

    // Falling off world
    if (player.y > canvas.height + 100) {
        gameOver = true;
    }

    // Camera follows player
    camera.x = player.x - canvas.width / 2;
    if (camera.x < 0) camera.x = 0;
}

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

    ctx.save();
    ctx.translate(-camera.x, 0);

    // Draw Platforms
    ctx.fillStyle = '#8B4513'; // Brown
    for (const plat of platforms) {
        ctx.fillRect(plat.x, plat.y, plat.width, plat.height);
        // Add a little "grass" top
        ctx.fillStyle = '#228B22'; // Green
        ctx.fillRect(plat.x, plat.y, plat.width, 5);
        ctx.fillStyle = '#8B4513';
    }

    // Draw Collectibles
    ctx.fillStyle = '#FFD700'; // Gold
    for (const coin of collectibles) {
        if (!coin.collected) {
            ctx.beginPath();
            ctx.arc(coin.x, coin.y, coin.radius, 0, Math.PI * 2);
            ctx.fill();
        }
    }

    // Draw Goal
    ctx.fillStyle = goal.color;
    ctx.fillRect(goal.x, goal.y, goal.width, goal.height);
    ctx.fillStyle = 'white';
    ctx.fillRect(goal.x, goal.y, 5, goal.height); // Flag pole

    // Draw Player
    ctx.fillStyle = player.color;
    ctx.fillRect(player.x, player.y, player.width, player.height);
    // Simple "eye" to see direction
    ctx.fillStyle = 'black';
    const eyeX = player.velX >= 0 ? player.x + 20 : player.x + 5;
    ctx.fillRect(eyeX, player.y + 5, 5, 5);

    ctx.restore();

    // UI Overlays
    if (gameOver) {
        ctx.fillStyle = 'rgba(0, 0, 0, 0.5)';
        ctx.fillRect(0, 0, canvas.width, canvas.height);
        ctx.fillStyle = 'white';
        ctx.font = '40px sans-serif';
        ctx.textAlign = 'center';
        ctx.fillText('GAME OVER', canvas.width / 2, canvas.height / 2);
        ctx.font = '20px sans-serif';
        ctx.fillText('Refresh to try again', canvas.width / 2, canvas.height / 2 + 40);
    }

    if (win) {
        ctx.fillStyle = 'rgba(0, 0, 0, 0.5)';
        ctx.fillRect(0, 0, canvas.width, canvas.height);
        ctx.fillStyle = '#FFD700';
        ctx.font = '40px sans-serif';
        ctx.textAlign = 'center';
        ctx.fillText('YOU WIN!', canvas.width / 2, canvas.height / 2);
        ctx.fillStyle = 'white';
        ctx.font = '20px sans-serif';
        ctx.fillText(`Final Score: ${score}`, canvas.width / 2, canvas.height / 2 + 40);
    }
}

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

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: sans-serif;
            overflow: hidden;
        }
        #game-container {
            position: relative;
            box-shadow: 0 0 20px rgba(0,0,0,0.5);
        }
        canvas {
            display: block;
            background-color: #5c94fc; /* Classic Mario Sky Blue */
        }
        #ui {
            position: absolute;
            top: 10px;
            left: 10px;
            color: white;
            font-size: 20px;
            text-shadow: 2px 2px 2px black;
            pointer-events: none;
        }
    </style>
</head>
<body>
    <div id="game-container">
        <canvas id="game" width="800" height="450"></canvas>
        <div id="ui">Score: <span id="score">0</span></div>
    </div>
    <script src="game.js"></script>
</body>
</html>

rep 4 UNGRADED

pi 145.5s · verify 4.1s · 18988 tok · responded: google/gemma-4-26b-a4b-it · 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 msgElement = document.getElementById('msg');

// Game Constants
const GRAVITY = 0.8;
const FRICTION = 0.8;
const PLAYER_SPEED = 5;
const PLAYER_JUMP_FORCE = -15;
const CANVAS_WIDTH = 800;
const CANVAS_HEIGHT = 450;

// Game State
let score = 0;
let gameActive = true;
let cameraX = 0;

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

class Player {
    constructor(x, y) {
        this.x = x;
        this.y = y;
        this.width = 32;
        this.height = 32;
        this.vx = 0;
        this.vy = 0;
        this.onGround = false;
        this.color = '#ff4444'; // Red character
    }

    update(platforms) {
        // 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.onGround) {
            this.vy = PLAYER_JUMP_FORCE;
            this.onGround = false;
        }

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

        // Proposed movement
        this.x += this.vx;
        this.y += this.vy;

        // Collision with platforms
        this.onGround = false;
        for (const platform of platforms) {
            if (this.checkCollision(this, platform)) {
                // Check if falling onto top of platform
                if (this.vy > 0 && this.y + this.height - this.vy <= platform.y) {
                    this.y = platform.y - this.height;
                    this.vy = 0;
                    this.onGround = true;
                } 
                // Check if hitting bottom of platform
                else if (this.vy < 0 && this.y - this.vy >= platform.y + platform.height) {
                    this.y = platform.y + platform.height;
                    this.vy = 0;
                }
                // Check left/right collision
                else {
                    // This is a very basic AABB collision.
                    // For a simple platformer, we prioritize vertical landing.
                    // If we are moving horizontally, we push the player out.
                    if (this.vx > 0) {
                        this.x = platform.x - this.width;
                        this.vx = 0;
                    } else if (this.vx < 0) {
                        this.x = platform.x + platform.width;
                        this.vx = 0;
                    }
                }
            }
        }

        // Bounds
        if (this.x < 0) this.x = 0;
        // Fall off map (death)
        if (this.y > CANVAS_HEIGHT) {
            resetGame();
        }
    }

    checkCollision(rect1, rect2) {
        return rect1.x < rect2.x + rect2.width &&
               rect1.x + rect1.width > rect2.x &&
               rect1.y < rect2.y + rect2.height &&
               rect1.y + rect1.height > rect2.y;
    }

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

class Platform {
    constructor(x, y, width, height, color = '#8B4513') {
        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);
        
        // Add some texture (grass on top if it's a ground)
        if (this.color === '#8B4513') {
            ctx.fillStyle = '#228B22';
            ctx.fillRect(this.x - cameraX, this.y, this.width, 5);
        }
    }
}

class Coin {
    constructor(x, y) {
        this.x = x;
        this.y = y;
        this.width = 15;
        this.height = 15;
        this.collected = false;
    }

    draw() {
        if (this.collected) return;
        ctx.fillStyle = '#FFD700'; // Gold
        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 {
    constructor(x, y) {
        this.x = x;
        this.y = y;
        this.width = 40;
        this.height = 100;
    }

    draw() {
        // Flag pole
        ctx.fillStyle = '#ddd';
        ctx.fillRect(this.x - cameraX + 15, this.y, 10, this.height);
        // Flag
        ctx.fillStyle = '#FFD700';
        ctx.fillRect(this.x - cameraX + 25, this.y + 10, 30, 20);
    }
}

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

function resetGame() {
    score = 0;
    scoreElement.innerText = `Coins: ${score}`;
    msgElement.innerText = "";
    gameActive = true;
    cameraX = 0;

    player = new Player(50, 300);
    
    // Level design
    platforms = [
        new Platform(0, 400, 1000, 50), // Floor
        new Platform(1200, 400, 800, 50), // Second floor
        new Platform(300, 300, 150, 20), // Floating platform
        new Platform(550, 220, 150, 20), // Floating platform
        new Platform(850, 300, 150, 20), // Floating platform
        new Platform(1300, 280, 100, 20), // Floating platform
        new Platform(1500, 180, 100, 20), // Floating platform
        new Platform(1800, 300, 300, 20), // Platform before goal
    ];

    coins = [
        new Coin(350, 250),
        new Coin(600, 180),
        new Coin(900, 250),
        new Coin(1350, 240),
        new Coin(1550, 140),
        new Coin(1900, 250),
    ];

    goal = new Goal(2000, 300);
}

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

    player.update(platforms);

    // Camera follow (smoothly)
    const targetCameraX = player.x - CANVAS_WIDTH / 2;
    cameraX += (targetCameraX - cameraX) * 0.1;
    if (cameraX < 0) cameraX = 0;

    // Coin collection
    coins.forEach(coin => {
        if (!coin.collected && player.checkCollision(player, coin)) {
            coin.collected = true;
            score++;
            scoreElement.innerText = `Coins: ${score}`;
        }
    });

    // Goal check
    if (player.checkCollision(player, goal)) {
        gameActive = false;
        msgElement.innerText = "YOU WIN!";
        msgElement.style.color = "#FFD700";
    }
}

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

    // Draw Background (sky already done by CSS, but let's add some clouds for depth)
    // We can draw simple clouds
    ctx.fillStyle = "rgba(255, 255, 255, 0.5)";
    ctx.beginPath();
    ctx.arc(100 - (cameraX * 0.2 % 800), 100, 30, 0, Math.PI * 2);
    ctx.arc(130 - (cameraX * 0.2 % 800), 100, 40, 0, Math.PI * 2);
    ctx.arc(160 - (cameraX * 0.2 % 800), 100, 30, 0, Math.PI * 2);
    ctx.fill();

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

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

// Start the game
resetGame();
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: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
            color: white;
            overflow: hidden;
        }
        canvas {
            background-color: #5c94fc; /* Classic Mario Sky Blue */
            box-shadow: 0 0 20px rgba(0, 0, 0, 0.5);
            border: 4px solid #000;
        }
        #ui {
            position: absolute;
            top: 20px;
            left: 50%;
            transform: translateX(-50%);
            text-align: center;
            pointer-events: none;
        }
        .instructions {
            position: absolute;
            bottom: 20px;
            left: 50%;
            transform: translateX(-50%);
            color: #ddd;
            font-size: 0.9em;
        }
    </style>
</head>
<body>

    <div id="ui">
        <h2 id="score">Coins: 0</h2>
        <h1 id="msg"></h1>
    </div>

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

    <div class="instructions">
        Use ARROW KEYS or WASD to Move & Jump | Reach the Golden Flag!
    </div>

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

rep 5 UNGRADED

pi 148.0s · verify 4.1s · 18614 tok · responded: google/gemma-4-26b-a4b-it · 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
 * Vanilla JavaScript
 */

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 TILE_SIZE = 40;

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

const keys = {
    left: false,
    right: false,
    up: false
};

// Player Object
const player = {
    x: 50,
    y: 300,
    width: 32,
    height: 40,
    vx: 0,
    vy: 0,
    grounded: false,
    color: '#ff4444'
};

// Level Data
// Platforms: {x, y, width, height}
const platforms = [
    { x: 0, y: 410, width: 2000, height: 40 }, // Ground
    { x: 200, y: 300, width: 120, height: 20 },
    { x: 400, y: 220, width: 120, height: 20 },
    { x: 600, y: 300, width: 120, height: 20 },
    { x: 850, y: 200, width: 200, height: 20 },
    { x: 1100, y: 300, width: 150, height: 20 },
    { x: 1400, y: 200, width: 100, height: 20 },
];

// Collectibles: {x, y, radius, collected}
const collectibles = [
    { x: 250, y: 270, radius: 10, collected: false },
    { x: 450, y: 190, radius: 10, collected: false },
    { x: 650, y: 270, radius: 10, collected: false },
    { x: 950, y: 170, radius: 10, collected: false },
    { x: 1150, y: 270, radius: 10, collected: false },
    { x: 1450, y: 170, radius: 10, collected: false },
];

// Goal: {x, y, width, height}
const goal = { x: 1700, y: 310, width: 40, height: 100 };

// Camera
const camera = {
    x: 0
};

// Input Listeners
window.addEventListener('keydown', (e) => {
    if (e.code === 'ArrowLeft' || e.code === 'KeyA') keys.left = true;
    if (e.code === 'ArrowRight' || e.code === 'KeyD') keys.right = true;
    if (e.code === 'ArrowUp' || e.code === 'KeyW' || e.code === 'Space') keys.up = true;
});

window.addEventListener('keyup', (e) => {
    if (e.code === 'ArrowLeft' || e.code === 'KeyA') keys.left = false;
    if (e.code === 'ArrowRight' || e.code === 'KeyD') keys.right = false;
    if (e.code === 'ArrowUp' || e.code === 'KeyW' || e.code === 'Space') keys.up = false;
});

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

    // Player movement
    if (keys.left) {
        player.vx -= 0.8;
    }
    if (keys.right) {
        player.vx += 0.8;
    }

    // Apply friction and gravity
    player.vx *= FRICTION;
    player.vy += GRAVITY;

    // Apply velocity to position
    player.x += player.vx;
    player.y += player.vy;

    // Collision detection with platforms
    player.grounded = false;
    for (const platform of platforms) {
        if (player.x < platform.x + platform.width &&
            player.x + player.width > platform.x &&
            player.y < platform.y + platform.height &&
            player.y + player.height > platform.y) {
            
            // Collision detected. We need to resolve it based on which side it hit.
            // For a simple platformer, we check the overlap.
            
            const overlapTop = (player.y + player.height) - platform.y;
            const overlapBottom = (platform.y + platform.height) - player.y;
            const overlapLeft = (player.x + player.width) - platform.x;
            const overlapRight = (platform.x + platform.width) - player.x;

            // Find the smallest overlap to determine collision side
            const minOverlap = Math.min(overlapTop, overlapBottom, overlapLeft, overlapRight);

            if (minOverlap === overlapTop && player.vy >= 0) {
                // Hit top of platform (falling)
                player.y = platform.y - player.height;
                player.vy = 0;
                player.grounded = true;
            } else if (minOverlap === overlapBottom && player.vy < 0) {
                // Hit bottom of platform (jumping)
                player.y = platform.y + platform.height;
                player.vy = 0;
            } else if (minOverlap === overlapLeft) {
                // Hit left side
                player.x = platform.x - player.width;
                player.vx = 0;
            } else if (minOverlap === overlapRight) {
                // Hit right side
                player.x = platform.x + platform.width;
                player.vx = 0;
            }
        }
    }

    // Jumping
    if (player.grounded && keys.up) {
        player.vy = JUMP_FORCE;
        player.grounded = false;
    }

    // Boundary checks
    if (player.x < 0) player.x = 0;
    // If player falls off world (if there was a pit, but here ground is long)
    if (player.y > canvas.height + 500) {
        gameOver = true;
        gameRunning = false;
    }

    // Collectibles collision
    for (const coin of collectibles) {
        if (!coin.collected) {
            const dx = player.x + player.width/2 - coin.x;
            const dy = player.y + player.height/2 - coin.y;
            const distance = Math.sqrt(dx * dx + dy * dy);
            if (distance < player.width/2 + coin.radius) {
                coin.collected = true;
                score += 10;
                scoreElement.innerText = score;
            }
        }
    }

    // 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) {
        win = true;
        gameRunning = false;
    }

    // Camera movement (follows player)
    camera.x = player.x - canvas.width / 4;
    if (camera.x < 0) camera.x = 0;
}

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

    ctx.save();
    ctx.translate(-camera.x, 0);

    // Draw Platforms
    ctx.fillStyle = '#8B4513'; // Brownish ground
    for (const platform of platforms) {
        ctx.fillRect(platform.x, platform.y, platform.width, platform.height);
        // Grass top
        ctx.fillStyle = '#228B22';
        ctx.fillRect(platform.x, platform.y, platform.width, 5);
        ctx.fillStyle = '#8B4513';
    }

    // Draw Collectibles
    ctx.fillStyle = '#FFD700'; // Gold
    for (const coin of collectibles) {
        if (!coin.collected) {
            ctx.beginPath();
            ctx.arc(coin.x, coin.y, coin.radius, 0, Math.PI * 2);
            ctx.fill();
        }
    }

    // Draw Goal (a flag)
    ctx.fillStyle = '#00FF00';
    ctx.fillRect(goal.x, goal.y, goal.width, goal.height);
    ctx.fillStyle = '#000';
    ctx.fillRect(goal.x, goal.y, 5, goal.height); // Flag pole

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

    ctx.restore();

    // UI Overlay
    if (gameOver) {
        ctx.fillStyle = 'rgba(0,0,0,0.5)';
        ctx.fillRect(0,0, canvas.width, canvas.height);
        ctx.fillStyle = 'white';
        ctx.font = '40px Arial';
        ctx.textAlign = 'center';
        ctx.fillText('GAME OVER', canvas.width/2, canvas.height/2);
    }

    if (win) {
        ctx.fillStyle = 'rgba(0,0,0,0.5)';
        ctx.fillRect(0,0, canvas.width, canvas.height);
        ctx.fillStyle = 'white';
        ctx.font = '40px Arial';
        ctx.textAlign = 'center';
        ctx.fillText('YOU WIN!', canvas.width/2, canvas.height/2);
        ctx.font = '20px Arial';
        ctx.fillText(`Final Score: ${score}`, canvas.width/2, canvas.height/2 + 40);
    }
}

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

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; /* Classic Mario sky blue */
            box-shadow: 0 0 20px rgba(0,0,0,0.5);
            display: block;
        }
        #ui {
            position: absolute;
            top: 20px;
            left: 20px;
            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">Score: <span id="score">0</span></div>
    <canvas id="game" width="800" height="450"></canvas>
    <script src="game.js"></script>
</body>
</html>