screenshot

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%)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Super Mario Platformer</title>
<style>
body {
margin: 0;
padding: 0;
background: #87CEEB;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
overflow: hidden;
}
#game {
border: 2px solid #333;
background: #000;
}
#ui {
position: absolute;
top: 10px;
left: 10px;
color: white;
font-family: Arial, sans-serif;
font-size: 20px;
text-shadow: 2px 2px 4px rgba(0,0,0,0.8);
}
#win-screen {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
color: yellow;
font-size: 48px;
font-weight: bold;
text-align: center;
text-shadow: 4px 4px 8px rgba(0,0,0,0.8);
display: none;
}
#controls {
position: absolute;
bottom: 20px;
left: 50%;
transform: translateX(-50%);
color: white;
font-family: Arial, sans-serif;
font-size: 14px;
text-align: center;
}
</style>
</head>
<body>
<canvas id="game" width="800" height="450"></canvas>
<div id="ui">
<div>Coins: <span id="coin-count">0</span></div>
<div>Time: <span id="timer">0</span>s</div>
</div>
<div id="win-screen">You Win!<br>Level Complete!</div>
<script>
const canvas = document.getElementById('game');
const ctx = canvas.getContext('2d');
// Game state
let keys = {};
let player = {
x: 50,
y: 350,
width: 30,
height: 40,
velocityX: 0,
velocityY: 0,
onGround: false,
jumping: false
};
let coins = [];
let score = 0;
let gameTime = 0;
let gameWon = false;
let startTime = Date.now();
// Platform data
const platforms = [
{ x: 0, y: 410, width: 800, height: 40 }, // ground
{ x: 200, y: 320, width: 150, height: 20 }, // platform 1
{ x: 450, y: 250, width: 150, height: 20 }, // platform 2
{ x: 650, y: 180, width: 120, height: 20 }, // platform 3
];
// Coin data
const coinPositions = [
{ x: 100, y: 360, collected: false },
{ x: 350, y: 280, collected: false },
{ x: 550, y: 210, collected: false },
{ x: 750, y: 140, collected: false },
];
// Draw functions
function drawPlatform(platform) {
ctx.fillStyle = '#8B4513';
ctx.fillRect(platform.x, platform.y, platform.width, platform.height);
// Add some texture
ctx.fillStyle = '#A0522D';
for (let i = platform.x; i < platform.x + platform.width; i += 10) {
ctx.fillRect(i, platform.y, 5, Math.random() * 10 + 5);
}
}
function drawCoin(coin) {
if (!coin.collected) {
ctx.fillStyle = '#FFD700';
ctx.beginPath();
ctx.arc(coin.x + 15, coin.y + 15, 15, 0, Math.PI * 2);
ctx.fill();
ctx.fillStyle = '#FFA500';
ctx.font = '12px Arial';
ctx.fillText('O', coin.x + 5, coin.y + 30);
}
}
function drawPlayer() {
// Draw player as a simple rectangle with details
ctx.fillStyle = '#FF0000';
ctx.fillRect(player.x, player.y, player.width, player.height);
// Add player details
ctx.fillStyle = '#00FF00';
ctx.fillRect(player.x + 5, player.y + 5, player.width - 10, player.height - 10);
// Add eyes
ctx.fillStyle = '#000';
ctx.fillRect(player.x + 8, player.y + 8, 5, 5);
ctx.fillRect(player.x + player.width - 13, player.y + 8, 5, 5);
// Add mouth
ctx.fillStyle = '#000';
ctx.fillRect(player.x + 10, player.y + 15, player.width - 20, 3);
}
function drawFinishLine() {
const lineY = 50;
ctx.strokeStyle = '#FF00FF';
ctx.lineWidth = 3;
ctx.setLineDash([10, 10]);
ctx.beginPath();
ctx.moveTo(0, lineY);
ctx.lineTo(800, lineY);
ctx.stroke();
ctx.setLineDash([]);
// Add flag
ctx.fillStyle = '#FF0000';
ctx.fillRect(375, 50, 50, 100);
ctx.fillStyle = '#FFFFFF';
ctx.fillRect(385, 110, 30, 30);
}
// Update functions
function update() {
if (gameWon) return;
// Update timer
gameTime = Math.floor((Date.now() - startTime) / 1000);
document.getElementById('timer').textContent = gameTime;
// Player movement
const moveSpeed = 5;
const gravity = 0.5;
const jumpPower = 15;
if (keys['ArrowLeft'] || keys['KeyA']) {
player.velocityX = -moveSpeed;
} else if (keys['ArrowRight'] || keys['KeyD']) {
player.velocityX = moveSpeed;
} else {
player.velocityX = 0;
}
// Jump
if ((keys['ArrowUp'] || keys['KeyW'] || keys['Space']) && player.onGround && !player.jumping) {
player.velocityY = -jumpPower;
player.onGround = false;
player.jumping = true;
}
// Apply gravity
player.velocityY += gravity;
// Update player position
player.x += player.velocityX;
player.y += player.velocityY;
// Ground collision
if (player.y + player.height >= 450) {
player.y = 450 - player.height;
player.velocityY = 0;
player.onGround = true;
player.jumping = false;
}
// Platform collision
player.onGround = false;
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
) {
// Check if player is above the platform
if (player.velocityY > 0) {
player.y = platform.y - player.height;
player.velocityY = 0;
player.onGround = true;
player.jumping = false;
}
// Check if player is hitting the side
if (player.velocityX > 0 && player.x + player.width > platform.x && player.x < platform.x) {
player.x = platform.x - player.width;
player.velocityX = 0;
} else if (player.velocityX < 0 && player.x < platform.x + platform.width && player.x + player.width > platform.x + platform.width) {
player.x = platform.x + platform.width;
player.velocityX = 0;
}
}
}
// Check coin collection
for (let coin of coinPositions) {
if (!coin.collected &&
player.x < coin.x + 50 &&
player.x + player.width > coin.x &&
player.y < coin.y + 50 &&
player.y + player.height > coin.y) {
coin.collected = true;
score++;
document.getElementById('coin-count').textContent = score;
}
}
// Check win condition (reaching the finish line area)
if (player.x > 350 && player.x < 450 && player.y < 150) {
gameWon = true;
document.getElementById('win-screen').style.display = 'block';
}
}
function draw() {
// Clear canvas
ctx.fillStyle = '#000000';
ctx.fillRect(0, 0, canvas.width, canvas.height);
// Draw ground line
ctx.strokeStyle = '#333';
ctx.lineWidth = 1;
ctx.beginPath();
ctx.moveTo(0, 450);
ctx.lineTo(800, 450);
ctx.stroke();
// Draw platforms
for (let platform of platforms) {
drawPlatform(platform);
}
// Draw coins
for (let coin of coinPositions) {
drawCoin(coin);
}
// Draw player
drawPlayer();
// Draw finish line
drawFinishLine();
// Draw UI text
ctx.fillStyle = '#FFFFFF';
ctx.font = '16px Arial';
ctx.fillText('Coins: ' + score, 10, 30);
ctx.fillText('Time: ' + gameTime + 's', 10, 50);
}
// Event listeners
document.addEventListener('keydown', (e) => {
keys[e.code] = true;
});
document.addEventListener('keyup', (e) => {
keys[e.code] = false;
if (e.code === 'Space') player.jumping = false;
});
// Game loop
function gameLoop() {
update();
draw();
requestAnimationFrame(gameLoop);
}
// Start the game when page loads
window.addEventListener('load', () => {
gameLoop();
});
// Add restart functionality
document.addEventListener('keydown', (e) => {
if (gameWon && (e.code === 'KeyR' || e.code === 'Enter')) {
// Restart game
player.x = 50;
player.y = 350;
player.velocityX = 0;
player.velocityY = 0;
player.onGround = false;
player.jumping = false;
coins = [];
score = 0;
gameTime = 0;
gameWon = false;
startTime = Date.now();
document.getElementById('coin-count').textContent = score;
document.getElementById('timer').textContent = '0';
document.getElementById('win-screen').style.display = 'none';
for (let coin of coinPositions) {
coin.collected = false;
}
}
});
</script>
</body>
</html>screenshot

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%)
// Game logic moved to a separate file for modularity
// This file contains the same game logic as in index.html
// Game state
const state = {
keys: {},
player: {
x: 100,
y: 250,
width: 40,
height: 60,
velocityX: 0,
velocityY: 0,
gravity: 0.8,
jumpStrength: -15,
groundLevel: 300,
isJumping: false
},
platforms: [
{ x: 0, y: 350, width: 800, height: 50, isGround: true },
{ x: 300, y: 250, width: 200, height: 30, isGround: false },
{ x: 550, y: 150, width: 150, height: 30, isGround: false }
],
coins: [
{ x: 400, y: 230, width: 20, height: 20, collected: false },
{ x: 700, y: 130, width: 20, height: 20, collected: false },
{ x: 200, y: 200, width: 20, height: 20, collected: false }
],
score: 0,
gameOver: false,
win: false
};
// Input handling
function setupInput(canvas) {
document.addEventListener('keydown', (e) => {
state.keys[e.code] = true;
if ((e.code === 'Space' || e.code === 'ArrowUp') && !state.player.isJumping && !state.gameOver && !state.win) {
state.player.velocityY = state.player.jumpStrength;
state.player.isJumping = true;
}
});
document.addEventListener('keyup', (e) => {
state.keys[e.code] = false;
});
}
// Update game state
function update(canvas) {
if (state.gameOver || state.win) return;
// Player movement
if (state.keys['ArrowLeft'] || state.keys['KeyA']) {
state.player.velocityX = -5;
} else if (state.keys['ArrowRight'] || state.keys['KeyD']) {
state.player.velocityX = 5;
} else {
state.player.velocityX *= 0.9;
if (Math.abs(state.player.velocityX) < 0.1) state.player.velocityX = 0;
}
state.player.x += state.player.velocityX;
// Apply gravity
state.player.velocityY += state.player.gravity;
state.player.y += state.player.velocityY;
// Ground collision
if (state.player.y >= state.player.groundLevel - state.player.height / 2) {
state.player.y = state.player.groundLevel - state.player.height / 2;
state.player.velocityY = 0;
state.player.isJumping = false;
}
// Platform collision
for (let platform of state.platforms) {
const platformTop = platform.y;
const playerBottom = state.player.y + state.player.height / 2;
const playerTop = state.player.y - state.player.height / 2;
const playerLeft = state.player.x - state.player.width / 2;
const playerRight = state.player.x + state.player.width / 2;
const platformLeft = platform.x;
const platformRight = platform.x + platform.width;
if (
playerLeft < platformRight &&
playerRight > platformLeft &&
playerBottom > platformTop &&
playerTop < platformTop + platform.height
) {
if (state.player.velocityY > 0) {
// Falling down
state.player.y = platform.y - state.player.height / 2 - platform.height;
state.player.velocityY = 0;
state.player.isJumping = false;
}
}
}
// Coin collection
for (let coin of state.coins) {
if (!coin.collected) {
const coinLeft = coin.x - coin.width / 2;
const coinRight = coin.x + coin.width / 2;
const coinTop = coin.y - coin.height / 2;
const coinBottom = coin.y + coin.height / 2;
const playerLeft = state.player.x - state.player.width / 2;
const playerRight = state.player.x + state.player.width / 2;
const playerTop = state.player.y - state.player.height / 2;
const playerBottom = state.player.y + state.player.height / 2;
if (
playerLeft < coinRight &&
playerRight > coinLeft &&
playerTop < coinBottom &&
playerBottom > coinTop
) {
coin.collected = true;
state.score++;
}
}
}
// Check win condition
if (state.score >= 3) {
state.win = true;
document.getElementById('win-screen').style.display = 'block';
}
// Check game over (player fell off)
if (state.player.y > canvas.height + 100) {
state.gameOver = true;
state.player.velocityX = 0;
state.player.velocityY = 0;
}
}
// Draw game
function draw(ctx, canvas) {
ctx.clearRect(0, 0, canvas.width, canvas.height);
// Draw ground
ctx.fillStyle = '#2e7d32';
ctx.fillRect(0, 300, 800, 50);
// Draw platforms
for (let platform of state.platforms) {
if (!platform.isGround) {
ctx.fillStyle = '#8b4513';
ctx.fillRect(platform.x, platform.y, platform.width, platform.height);
}
}
// Draw player
ctx.fillStyle = '#FF0000';
ctx.fillRect(state.player.x - state.player.width / 2, state.player.y - state.player.height / 2, state.player.width, state.player.height);
// Draw coins
for (let coin of state.coins) {
if (!coin.collected) {
ctx.fillStyle = '#FFD700';
ctx.beginPath();
ctx.arc(coin.x, coin.y, coin.width / 2, 0, Math.PI * 2);
ctx.fill();
ctx.fillStyle = '#B8860B';
ctx.beginPath();
ctx.moveTo(coin.x, coin.y - coin.width / 2);
ctx.lineTo(coin.x + coin.width / 2, coin.y);
ctx.lineTo(coin.x, coin.y + coin.width / 2);
ctx.closePath();
ctx.fill();
}
}
// Draw score
ctx.fillStyle = 'white';
ctx.font = '24px Arial';
ctx.fillText(`Coins: ${state.score}`, 20, 40);
}
// Reset game
function resetGame() {
state.player.x = 100;
state.player.y = 250;
state.player.velocityX = 0;
state.player.velocityY = 0;
state.player.isJumping = false;
state.score = 0;
state.gameOver = false;
state.win = false;
state.coins.forEach(coin => coin.collected = false);
document.getElementById('win-screen').style.display = 'none';
}
// Initialize game
function init() {
const canvas = document.getElementById('game');
const ctx = canvas.getContext('2d');
setupInput(canvas);
document.getElementById('restart-btn').addEventListener('click', resetGame);
// Game loop
function gameLoop() {
update(canvas);
draw(ctx, canvas);
requestAnimationFrame(gameLoop);
}
gameLoop();
}
// Start game when DOM is loaded
if (document.readyState === 'loading') {
document.addEventListener('DOMContentLoaded', init);
} else {
init();
}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Super Platformer</title>
<style>
body {
margin: 0;
padding: 0;
background: #87CEEB;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
overflow: hidden;
}
#game {
border: 2px solid #333;
background: #87CEEB;
display: block;
}
#score {
position: absolute;
top: 20px;
left: 20px;
color: white;
font-size: 24px;
font-family: Arial, sans-serif;
text-shadow: 2px 2px 4px rgba(0,0,0,0.5);
}
#win-screen {
display: none;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: rgba(0,0,0,0.8);
color: white;
padding: 30px;
border-radius: 10px;
font-size: 36px;
font-family: Arial, sans-serif;
text-align: center;
z-index: 100;
}
#restart-btn {
background: #4CAF50;
color: white;
border: none;
padding: 10px 20px;
font-size: 20px;
margin-top: 20px;
cursor: pointer;
border-radius: 5px;
}
#restart-btn:hover {
background: #45a049;
}
</style>
</head>
<body>
<canvas id="game" width="800" height="450"></canvas>
<div id="score">Coins: 0</div>
<div id="win-screen">
You Win!<br>
<button id="restart-btn">Play Again</button>
</div>
<script src="game.js"></script>
</body>
</html>screenshot

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%)
// Game class - encapsulates all game logic
class MarioPlatformer {
constructor() {
this.canvas = document.getElementById('game');
this.ctx = this.canvas.getContext('2d');
this.lastTime = 0;
this.keys = {};
this.score = 0;
this.gameState = 'playing'; // playing, win, gameover
// Initialize game objects
this.initPlayer();
this.initPlatforms();
this.initCoins();
this.initGoal();
this.setupInputHandlers();
}
initPlayer() {
this.player = {
x: 100,
y: 300,
width: 32,
height: 32,
velocityX: 0,
velocityY: 0,
grounded: false,
moveSpeed: 5,
jumpPower: -15,
gravity: 0.8,
color: '#FF0000'
};
}
initPlatforms() {
this.platforms = [
{ x: 0, y: 420, width: 800, height: 50, color: '#8B4513' },
{ x: 200, y: 350, width: 150, height: 20, color: '#556B2F' },
{ x: 500, y: 250, width: 150, height: 20, color: '#556B2F' },
{ x: 350, y: 150, width: 100, height: 20, color: '#556B2F' }
];
}
initCoins() {
this.coins = [];
const coinColors = ['#FFD700', '#FFA500', '#FF6347'];
for (let i = 0; i < 10; i++) {
this.coins.push({
x: 100 + i * 60,
y: 280,
width: 20,
height: 20,
color: coinColors[Math.floor(Math.random() * coinColors.length)],
collected: false
});
}
}
initGoal() {
this.goal = {
x: 700,
y: 100,
width: 40,
height: 60,
color: '#FF0000'
};
}
setupInputHandlers() {
document.addEventListener('keydown', (e) => {
this.keys[e.code] = true;
if (e.code === 'KeyW' || e.code === 'ArrowUp' || e.code === 'Space') {
e.preventDefault();
}
});
document.addEventListener('keyup', (e) => {
this.keys[e.code] = false;
});
}
updatePlayer() {
// Horizontal movement
if (this.keys['KeyD'] || this.keys['ArrowRight']) {
this.player.velocityX = this.player.moveSpeed;
} else if (this.keys['KeyA'] || this.keys['ArrowLeft']) {
this.player.velocityX = -this.player.moveSpeed;
} else {
this.player.velocityX = 0;
}
// Apply gravity
this.player.velocityY += this.player.gravity;
// Update position
this.player.x += this.player.velocityX;
this.player.y += this.player.velocityY;
// Ground collision
if (this.player.y + this.player.height >= 420) {
this.player.y = 420 - this.player.height;
this.player.velocityY = 0;
this.player.grounded = true;
} else {
this.player.grounded = false;
}
// Platform collision
this.player.grounded = false;
for (let platform of this.platforms) {
if (this.checkRectangleCollision(this.player, platform)) {
// Horizontal collision
if (this.player.velocityX > 0) {
this.player.x = platform.x - this.player.width;
} else if (this.player.velocityX < 0) {
this.player.x = platform.x + platform.width;
}
// Vertical collision
if (this.player.velocityY > 0) {
this.player.y = platform.y - this.player.height;
this.player.velocityY = 0;
this.player.grounded = true;
} else if (this.player.velocityY < 0) {
this.player.y = platform.y + platform.height;
this.player.velocityY = 0;
}
}
}
// Jump
if ((this.keys['Space'] || this.keys['KeyW'] || this.keys['ArrowUp']) && this.player.grounded) {
this.player.velocityY = this.player.jumpPower;
this.player.grounded = false;
}
// Keep player in bounds
this.player.x = Math.max(0, Math.min(this.player.x, this.canvas.width - this.player.width));
this.player.y = Math.max(0, Math.min(this.player.y, this.canvas.height - this.player.height));
}
checkRectangleCollision(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;
}
checkCoinCollision() {
this.coins.forEach(coin => {
if (!coin.collected && this.checkRectangleCollision(this.player, coin)) {
coin.collected = true;
this.score++;
document.getElementById('coin-count').textContent = this.score;
}
});
}
checkGoalCollision() {
if (this.checkRectangleCollision(this.player, this.goal)) {
this.gameState = 'win';
return true;
}
return false;
}
draw() {
// Clear canvas with sky gradient
const gradient = this.ctx.createLinearGradient(0, 0, 0, this.canvas.height);
gradient.addColorStop(0, '#87CEEB');
gradient.addColorStop(1, '#98D8E8');
this.ctx.fillStyle = gradient;
this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height);
// Draw platforms
this.platforms.forEach(platform => {
this.ctx.fillStyle = platform.color;
this.ctx.fillRect(platform.x, platform.y, platform.width, platform.height);
// Add platform details
this.ctx.strokeStyle = '#444';
this.ctx.lineWidth = 2;
this.ctx.beginPath();
this.ctx.moveTo(platform.x, platform.y);
this.ctx.lineTo(platform.x + platform.width, platform.y);
this.ctx.stroke();
});
// Draw coins
this.coins.forEach(coin => {
this.ctx.fillStyle = coin.collected ? '#808080' : coin.color;
this.ctx.beginPath();
this.ctx.arc(coin.x + coin.width/2, coin.y + coin.height/2, coin.width/2, 0, Math.PI * 2);
this.ctx.fill();
if (!coin.collected) {
this.ctx.fillStyle = '#333';
this.ctx.font = '12px Arial';
this.ctx.textAlign = 'center';
this.ctx.fillText('$', coin.x + coin.width/2, coin.y + coin.height/2 + 5);
}
});
// Draw goal
this.ctx.fillStyle = '#00FF00';
this.ctx.fillRect(this.goal.x, this.goal.y, this.goal.width, this.goal.height);
// Draw player
this.ctx.fillStyle = this.player.color;
this.ctx.fillRect(this.player.x, this.player.y, this.player.width, this.player.height);
// Add pixel art style details to player
this.ctx.fillStyle = '#FFFF00';
this.ctx.fillRect(this.player.x + 8, this.player.y + 8, 8, 8);
this.ctx.fillStyle = '#000';
this.ctx.fillRect(this.player.x + 18, this.player.y + 10, 3, 3);
// Draw win message
if (this.gameState === 'win') {
this.ctx.fillStyle = 'rgba(0, 255, 0, 0.7)';
this.ctx.fillRect(0, 0, this.canvas.width, this.canvas.height);
this.ctx.fillStyle = '#000';
this.ctx.font = '48px Arial';
this.ctx.textAlign = 'center';
this.ctx.fillText('You Win!', this.canvas.width/2, this.canvas.height/2);
this.ctx.font = '24px Arial';
this.ctx.fillText('Coins: ' + this.score, this.canvas.width/2, this.canvas.height/2 + 50);
}
// Draw game over overlay
if (this.gameState === 'gameover') {
document.getElementById('game-over').style.display = 'block';
} else {
document.getElementById('game-over').style.display = 'none';
}
}
resetGame() {
this.player.x = 100;
this.player.y = 300;
this.player.velocityX = 0;
this.player.velocityY = 0;
this.player.grounded = false;
this.score = 0;
this.gameState = 'playing';
document.getElementById('coin-count').textContent = '0';
// Reset coins
this.coins.forEach(coin => {
coin.collected = false;
});
}
gameLoop(currentTime) {
const deltaTime = (currentTime - this.lastTime) / 1000;
this.lastTime = currentTime;
if (this.gameState === 'playing') {
this.updatePlayer();
this.checkCoinCollision();
if (this.checkGoalCollision()) {
this.gameState = 'win';
}
// Check if player fell off the map
if (this.player.y > this.canvas.height) {
this.gameState = 'gameover';
}
}
this.draw();
requestAnimationFrame((time) => this.gameLoop(time));
}
start() {
requestAnimationFrame((time) => this.gameLoop(time));
}
}
// Initialize and start the game when the page loads
window.addEventListener('load', () => {
const game = new MarioPlatformer();
window.currentGame = game;
game.start();
});
// Keyboard restart handler
document.addEventListener('keydown', (e) => {
if (window.currentGame && (e.code === 'Space' || e.code === 'KeyW' || e.code === 'ArrowUp')) {
window.currentGame.resetGame();
}
});
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Super Mario Platformer</title>
<style>
body {
margin: 0;
padding: 0;
display: flex;
justify-content: center;
align-items: center;
min-height: 100vh;
background: linear-gradient(to bottom, #87CEEB, #98D8E8);
font-family: Arial, sans-serif;
overflow: hidden;
}
#game {
border: 4px solid #333;
background: #fff;
display: block;
image-rendering: pixelated;
image-rendering: -moz-crisp-edges;
image-rendering: crisp-edges;
}
.game-over {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: rgba(0, 0, 0, 0.8);
color: white;
padding: 30px;
border-radius: 10px;
text-align: center;
font-size: 24px;
display: none;
}
.score-display {
position: absolute;
top: 20px;
left: 20px;
background: rgba(0, 0, 0, 0.7);
color: white;
padding: 10px 15px;
border-radius: 8px;
font-size: 18px;
}
.controls {
position: absolute;
bottom: 30px;
left: 50%;
transform: translateX(-50%);
background: rgba(255, 255, 255, 0.8);
padding: 15px 25px;
border-radius: 25px;
text-align: center;
font-size: 14px;
}
</style>
</head>
<body>
<canvas id="game" width="800" height="450"></canvas>
<div class="score-display">Coins: <span id="coin-count">0</span></div>
<div class="game-over" id="game-over">
<h2>Game Over!</h2>
<p>Press SPACE to restart</p>
</div>
<div class="controls">
Arrow Keys / WASD to move | SPACE / Up to jump | Collect coins to win!
</div>
<script src="game.js"></script>
</body>
</html>screenshot

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%)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Super Mario Platformer</title>
<style>
body {
margin: 0;
padding: 0;
background-color: #87CEEB;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
overflow: hidden;
}
#game {
border: 2px solid #333;
background-color: #87CEEB;
display: block;
}
#ui {
position: absolute;
top: 10px;
left: 10px;
color: white;
font-family: Arial, sans-serif;
font-size: 18px;
text-shadow: 2px 2px 4px rgba(0,0,0,0.8);
}
#controls-info {
position: absolute;
bottom: 10px;
left: 10px;
color: white;
font-family: Arial, sans-serif;
font-size: 14px;
text-shadow: 2px 2px 4px rgba(0,0,0,0.8);
}
#start-screen {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
color: white;
font-family: Arial, sans-serif;
font-size: 24px;
text-align: center;
text-shadow: 2px 2px 4px rgba(0,0,0,0.8);
}
#start-screen button {
margin-top: 20px;
padding: 15px 30px;
font-size: 20px;
background-color: #FF6B35;
color: white;
border: none;
border-radius: 10px;
cursor: pointer;
font-weight: bold;
}
#start-screen button:hover {
background-color: #FF8547;
}
#game-over {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
color: white;
font-family: Arial, sans-serif;
font-size: 24px;
text-align: center;
text-shadow: 2px 2px 4px rgba(0,0,0,0.8);
display: none;
}
#game-over button {
margin-top: 20px;
padding: 15px 30px;
font-size: 20px;
background-color: #FF6B35;
color: white;
border: none;
border-radius: 10px;
cursor: pointer;
font-weight: bold;
}
#game-over button:hover {
background-color: #FF8547;
}
.hidden {
display: none;
}
</style>
</head>
<body>
<canvas id="game" width="800" height="450"></canvas>
<div id="ui">
<div>Coins: <span id="coin-count">0</span></div>
<div id="win-message" class="hidden">You win! Press R to restart</div>
</div>
<div id="controls-info">
Use Arrow keys or WASD to move, Space or Up to jump
</div>
<div id="start-screen">
<h1>Super Mario Platformer</h1>
<p>Collect 10 coins to win!</p>
<button onclick="game.startGame()">Start Game</button>
</div>
<div id="game-over">
<h1>Game Over!</h1>
<p>You collected <span id="final-coins">0</span> coins</p>
<button onclick="game.restartGame()">Try Again</button>
</div>
<script>
const canvas = document.getElementById('game');
const ctx = canvas.getContext('2d');
// Game state
let gameState = 'waiting'; // 'waiting', 'playing', 'gameover'
let lastTime = 0;
// Initialize game
const game = {
startGame: function() {
document.getElementById('start-screen').classList.add('hidden');
gameState = 'playing';
resetGame();
lastTime = performance.now();
requestAnimationFrame(game.loop);
},
restartGame: function() {
document.getElementById('game-over').classList.add('hidden');
game.startGame();
}
};
// Game reset
function resetGame() {
player.x = 100;
player.y = 350;
player.velocityX = 0;
player.velocityY = 0;
player.onGround = false;
coins = [];
for (let i = 0; i < 10; i++) {
coins.push({
x: 500 + i * 60,
y: 250 - (i % 3) * 40,
collected: false
});
}
score = 0;
document.getElementById('coin-count').textContent = '0';
document.getElementById('win-message').classList.add('hidden');
document.getElementById('final-coins').textContent = '0';
}
// Draw functions
function drawRect(x, y, w, h, color) {
ctx.fillStyle = color;
ctx.fillRect(x, y, w, h);
}
function drawCircle(x, y, r, color) {
ctx.fillStyle = color;
ctx.beginPath();
ctx.arc(x, y, r, 0, Math.PI * 2);
ctx.fill();
}
// Player class
class Player {
constructor(x, y) {
this.x = x;
this.y = y;
this.width = 30;
this.height = 40;
this.velocityX = 0;
this.velocityY = 0;
this.gravity = 0.5;
this.jumpForce = 12;
this.moveSpeed = 5;
this.onGround = false;
this.color = '#FF0000';
}
draw() {
// Draw player as a simple rectangle with a head
drawRect(this.x, this.y, this.width, this.height, this.color);
drawCircle(this.x + this.width/2, this.y - 5, 10, this.color);
}
update() {
// Apply gravity
if (!this.onGround) {
this.velocityY += this.gravity;
}
// Update position
this.x += this.velocityX;
this.y += this.velocityY;
// Ground collision
if (this.y + this.height > 450) {
this.y = 450 - this.height;
this.velocityY = 0;
this.onGround = true;
}
// Platform collisions
for (let platform of platforms) {
if (this.x < platform.x + platform.width &&
this.x + this.width > platform.x &&
this.y < platform.y + platform.height &&
this.y + this.height > platform.y) {
// Check if falling down
if (this.velocityY > 0 && this.y + this.height - this.velocityY <= platform.y) {
this.y = platform.y - this.height;
this.velocityY = 0;
this.onGround = true;
}
// Check if jumping up
else if (this.velocityY < 0 && this.y - this.velocityY >= platform.y + platform.height) {
this.y = platform.y + platform.height;
this.velocityY = 0;
}
}
}
// Screen boundaries
if (this.x < 0) this.x = 0;
if (this.x + this.width > canvas.width) {
this.x = canvas.width - this.width;
}
}
jump() {
if (this.onGround) {
this.velocityY = -this.jumpForce;
this.onGround = false;
}
}
move(direction) {
this.velocityX = direction * this.moveSpeed;
}
}
// Create player
const player = new Player(100, 350);
// Platforms
const platforms = [
{ x: 0, y: 420, width: 800, height: 30, color: '#228B22' }, // Ground
{ x: 300, y: 320, width: 150, height: 20, color: '#8B4513' }, // Platform
{ x: 550, y: 220, width: 150, height: 20, color: '#8B4513' }, // Platform
{ x: 750, y: 120, width: 150, height: 20, color: '#8B4513' } // Platform
];
// Coins
let coins = [];
let score = 0;
// Input handling
const keys = {};
document.addEventListener('keydown', (e) => {
keys[e.key.toLowerCase()] = true;
if (e.key === ' ') e.preventDefault(); // Prevent space from scrolling
});
document.addEventListener('keyup', (e) => {
keys[e.key.toLowerCase()] = false;
});
// Update player movement based on keys
function updatePlayerInput() {
player.velocityX = 0;
if (keys['arrowleft'] || keys['a']) {
player.move(-1);
}
if (keys['arrowright'] || keys['d']) {
player.move(1);
}
if ((keys['arrowup'] || keys['w'] || keys[' ']) && player.onGround) {
player.jump();
}
}
// Game loop
game.loop = function(currentTime) {
if (gameState !== 'playing') return;
const deltaTime = (currentTime - lastTime) / 1000;
lastTime = currentTime;
// Clear canvas
drawRect(0, 0, canvas.width, canvas.height, '#87CEEB');
// Update player input
updatePlayerInput();
// Update player
player.update();
player.draw();
// Draw platforms
for (let platform of platforms) {
drawRect(platform.x, platform.y, platform.width, platform.height, platform.color);
}
// Update and draw coins
for (let coin of coins) {
if (!coin.collected) {
// Draw coin as yellow circle
drawCircle(coin.x, coin.y, 10, '#FFD700');
// Check collision with player
if (player.x < coin.x + 20 &&
player.x + player.width > coin.x &&
player.y < coin.y + 20 &&
player.y + player.height > coin.y) {
coin.collected = true;
score++;
document.getElementById('coin-count').textContent = score;
if (score >= 10) {
document.getElementById('win-message').classList.remove('hidden');
gameState = 'gameover';
document.getElementById('final-coins').textContent = score;
document.getElementById('game-over').classList.remove('hidden');
}
}
}
}
// Draw ground line
drawRect(0, 445, 800, 5, '#2F4F4F');
requestAnimationFrame(game.loop);
};
// Start game on load
window.addEventListener('load', () => {
document.getElementById('start-screen').classList.remove('hidden');
});
</script>
</body>
</html>
screenshot

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%)
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Super Mario Platformer</title>
<style>
body {
margin: 0;
padding: 0;
background: #87CEEB;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
overflow: hidden;
}
#game {
border: 2px solid #333;
background: #fff;
display: block;
}
#ui {
position: absolute;
top: 10px;
left: 10px;
color: white;
font-family: 'Courier New', monospace;
font-size: 20px;
text-shadow: 2px 2px 2px black;
}
#game-over {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
color: white;
font-size: 48px;
font-weight: bold;
text-align: center;
display: none;
text-shadow: 2px 2px 2px black;
}
</style>
</head>
<body>
<canvas id="game" width="800" height="450"></canvas>
<div id="ui">Coins: 0</div>
<div id="game-over">Game Over!<br>Press SPACE to restart</div>
<script>
// Game state
const game = {
canvas: null,
ctx: null,
player: {
x: 100,
y: 300,
width: 30,
height: 40,
vx: 0,
vy: 0,
grounded: false,
jumpPower: -15
},
gravity: 0.5,
groundY: 430,
platforms: [
{ x: 0, y: 430, width: 800, height: 20 }, // ground
{ x: 400, y: 350, width: 200, height: 20 }, // platform
{ x: 150, y: 250, width: 150, height: 20 }, // platform
{ x: 550, y: 150, width: 150, height: 20 }, // platform
],
coins: [
{ x: 200, y: 330, width: 20, height: 20, collected: false },
{ x: 500, y: 200, width: 20, height: 20, collected: false },
{ x: 350, y: 100, width: 20, height: 20, collected: false },
],
goal: { x: 700, y: 100, width: 50, height: 50, reached: false },
score: 0,
keys: { left: false, right: false, up: false, space: false },
gameOver: false,
velocityX: 5
};
// Initialize game
function init() {
game.canvas = document.getElementById('game');
game.ctx = game.canvas.getContext('2d');
// Set up event listeners
document.addEventListener('keydown', keyDown);
document.addEventListener('keyup', keyUp);
// Start game loop
requestAnimationFrame(gameLoop);
}
// Key down handler
function keyDown(e) {
switch(e.key.toLowerCase()) {
case 'arrowleft':
case 'a':
game.keys.left = true;
break;
case 'arrowright':
case 'd':
game.keys.right = true;
break;
case 'arrowup':
case 'w':
case ' ':
game.keys.up = true;
game.keys.space = true;
break;
}
}
// Key up handler
function keyUp(e) {
switch(e.key.toLowerCase()) {
case 'arrowleft':
case 'a':
game.keys.left = false;
break;
case 'arrowright':
case 'd':
game.keys.right = false;
break;
case 'arrowup':
case 'w':
case ' ':
game.keys.up = false;
game.keys.space = false;
break;
}
}
// Game loop
function gameLoop() {
if (!game.gameOver) {
update();
draw();
}
requestAnimationFrame(gameLoop);
}
// Update game state
function update() {
// Player movement
if (game.keys.left) {
game.player.vx = -5;
} else if (game.keys.right) {
game.player.vx = 5;
} else {
game.player.vx = 0;
}
// Jump
if ((game.keys.up || game.keys.space) && game.player.grounded) {
game.player.vy = game.player.jumpPower;
game.player.grounded = false;
}
// Apply gravity
game.player.vy += game.gravity;
// Update position
game.player.x += game.player.vx;
game.player.y += game.player.vy;
// Ground collision
if (game.player.y + game.player.height >= game.groundY) {
game.player.y = game.groundY - game.player.height;
game.player.vy = 0;
game.player.grounded = true;
} else {
game.player.grounded = false;
}
// Platform collisions
for (let platform of game.platforms) {
// Left/right collision
if (game.player.x < platform.x + platform.width &&
game.player.x + game.player.width > platform.x &&
game.player.y < platform.y + platform.height &&
game.player.y + game.player.height > platform.y) {
// Check if player is falling onto platform
if (game.player.vy > 0 &&
game.player.y + game.player.height <= platform.y + 10) {
game.player.y = platform.y - game.player.height;
game.player.vy = 0;
game.player.grounded = true;
}
// Check if player is jumping off platform
else if (game.player.vy < 0 &&
game.player.y >= platform.y - 10) {
game.player.y = platform.y + platform.height;
game.player.vy = 0;
}
}
}
// Coin collection
for (let coin of game.coins) {
if (!coin.collected &&
game.player.x < coin.x + coin.width &&
game.player.x + game.player.width > coin.x &&
game.player.y < coin.y + coin.height &&
game.player.y + game.player.height > coin.y) {
coin.collected = true;
game.score++;
}
}
// Goal reached
if (!game.goal.reached &&
game.player.x < game.goal.x + game.goal.width &&
game.player.x + game.player.width > game.goal.x &&
game.player.y < game.goal.y + game.goal.height &&
game.player.y + game.player.height > game.goal.y) {
game.goal.reached = true;
showWinMessage();
}
// Check if player fell off
if (game.player.y > game.canvas.height + 50) {
gameOver();
}
}
// Draw everything
function draw() {
// Clear canvas
game.ctx.fillStyle = '#87CEEB';
game.ctx.fillRect(0, 0, game.canvas.width, game.canvas.height);
// Draw ground
game.ctx.fillStyle = '#8B4513';
for (let platform of game.platforms) {
if (platform.y === game.groundY) {
game.ctx.fillRect(platform.x, platform.y, platform.width, platform.height);
}
}
// Draw platforms
game.ctx.fillStyle = '#556B2F';
for (let platform of game.platforms) {
if (platform.y !== game.groundY) {
game.ctx.fillRect(platform.x, platform.y, platform.width, platform.height);
}
}
// Draw player
game.ctx.fillStyle = '#FF0000';
game.ctx.fillRect(game.player.x, game.player.y, game.player.width, game.player.height);
// Draw coins
for (let coin of game.coins) {
game.ctx.fillStyle = coin.collected ? '#FFD700' : '#FFFF00';
game.ctx.fillRect(coin.x, coin.y, coin.width, coin.height);
}
// Draw goal
game.ctx.fillStyle = game.goal.reached ? '#00FF00' : '#FF0000';
game.ctx.fillRect(game.goal.x, game.goal.y, game.goal.width, game.goal.height);
// Update UI
document.getElementById('ui').innerHTML = `Coins: ${game.score}`;
}
// Show win message
function showWinMessage() {
const gameOverElement = document.getElementById('game-over');
gameOverElement.innerHTML = 'You Win!<br>Press SPACE to restart';
gameOverElement.style.display = 'block';
}
// Game over
function gameOver() {
game.gameOver = true;
const gameOverElement = document.getElementById('game-over');
gameOverElement.innerHTML = 'Game Over!<br>Press SPACE to restart';
gameOverElement.style.display = 'block';
}
// Restart game
function restart() {
// Reset player position
game.player.x = 100;
game.player.y = 300;
game.player.vx = 0;
game.player.vy = 0;
game.player.grounded = false;
// Reset coins
for (let coin of game.coins) {
coin.collected = false;
}
// Reset goal
game.goal.reached = false;
// Reset score
game.score = 0;
// Reset game over state
game.gameOver = false;
// Hide game over message
document.getElementById('game-over').style.display = 'none';
}
// Handle restart on space key
function handleRestart(e) {
if ((e.key === ' ' || e.key === 'Spacebar') && game.gameOver) {
restart();
}
}
// Initialize when page loads
window.addEventListener('load', init);
document.addEventListener('keydown', handleRestart);
</script>
</body>
</html>