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 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;
overflow: hidden;
}
#game-container {
position: relative;
box-shadow: 0 0 20px rgba(0,0,0,0.5);
}
canvas {
background-color: #5c94fc; /* Classic Mario sky blue */
display: block;
}
#ui {
position: absolute;
top: 10px;
left: 10px;
font-size: 20px;
font-weight: bold;
text-shadow: 2px 2px #000;
pointer-events: none;
}
#overlay {
position: absolute;
top: 0;
left: 0;
width: 800px;
height: 450px;
display: none;
flex-direction: column;
justify-content: center;
align-items: center;
background: rgba(0,0,0,0.6);
font-size: 40px;
text-align: center;
}
</style>
</head>
<body>
<div id="game-container">
<div id="ui">Coins: <span id="score">0</span></div>
<div id="overlay">
<div id="message">YOU WIN!</div>
<div style="font-size: 20px; margin-top: 20px;">Press R to Restart</div>
</div>
<canvas id="game" width="800" height="450"></canvas>
</div>
<script>
const canvas = document.getElementById('game');
const ctx = canvas.getContext('2d');
const scoreEl = document.getElementById('score');
const overlay = document.getElementById('overlay');
const messageEl = document.getElementById('message');
// Game Constants
const GRAVITY = 0.8;
const FRICTION = 0.8;
const JUMP_FORCE = -16;
const MOVE_SPEED = 5;
// Game State
let score = 0;
let gameActive = true;
let cameraX = 0;
const keys = {};
window.addEventListener('keydown', e => {
keys[e.code] = true;
if (e.code === 'KeyR' && !gameActive) resetGame();
});
window.addEventListener('keyup', e => keys[e.code] = false);
class Player {
constructor() {
this.width = 32;
this.height = 48;
this.x = 50;
this.y = 300;
this.vx = 0;
this.vy = 0;
this.grounded = false;
this.color = '#ff0000';
}
update() {
if (keys['ArrowLeft'] || keys['KeyA']) this.vx -= 1;
if (keys['ArrowRight'] || keys['KeyD']) this.vx += 1;
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;
this.grounded = false;
}
draw() {
ctx.fillStyle = this.color;
ctx.fillRect(this.x - cameraX, this.y, this.width, this.height);
// Hat/Detail
ctx.fillStyle = '#a00';
ctx.fillRect(this.x - cameraX, this.y, this.width, 10);
}
}
class Platform {
constructor(x, y, w, h, color = '#8B4513') {
this.x = x;
this.y = y;
this.w = w;
this.h = h;
this.color = color;
}
draw() {
ctx.fillStyle = this.color;
ctx.fillRect(this.x - cameraX, this.y, this.w, this.h);
// Grass top
if (this.color === '#8B4513') {
ctx.fillStyle = '#228B22';
ctx.fillRect(this.x - cameraX, this.y, this.w, 10);
}
}
}
class Coin {
constructor(x, y) {
this.x = x;
this.y = y;
this.w = 20;
this.h = 20;
this.collected = false;
}
draw() {
if (this.collected) return;
ctx.fillStyle = '#FFD700';
ctx.beginPath();
ctx.arc(this.x + 10 - cameraX, this.y + 10, 10, 0, Math.PI * 2);
ctx.fill();
ctx.strokeStyle = '#B8860B';
ctx.stroke();
}
}
class Goal {
constructor(x, y) {
this.x = x;
this.y = y;
this.w = 40;
this.h = 150;
}
draw() {
ctx.fillStyle = '#fff';
ctx.fillRect(this.x - cameraX, this.y, 10, this.h);
ctx.fillStyle = '#ff0000';
ctx.beginPath();
ctx.moveTo(this.x + 10 - cameraX, this.y);
ctx.lineTo(this.x + 40 - cameraX, this.y + 20);
ctx.lineTo(this.x + 10 - cameraX, this.y + 40);
ctx.fill();
}
}
let player;
let platforms = [];
let coins = [];
let goal;
function initLevel() {
player = new Player();
score = 0;
scoreEl.innerText = score;
cameraX = 0;
gameActive = true;
overlay.style.display = 'none';
platforms = [
new Platform(0, 400, 1200, 50), // Ground 1
new Platform(1300, 400, 800, 50), // Ground 2 (gap)
new Platform(2200, 400, 1000, 50), // Ground 3
new Platform(200, 300, 150, 20), // Platform 1
new Platform(450, 220, 150, 20), // Platform 2
new Platform(700, 140, 150, 20), // Platform 3
new Platform(1400, 300, 200, 20), // Platform 4
new Platform(1700, 200, 200, 20), // Platform 5
new Platform(1900, 100, 200, 20), // Platform 6
];
coins = [
new Coin(250, 270),
new Coin(500, 190),
new Coin(750, 110),
new Coin(1450, 270),
new Coin(1750, 170),
new Coin(1950, 70),
];
goal = new Goal(3000, 250);
}
function resetGame() {
initLevel();
requestAnimationFrame(gameLoop);
}
function checkCollision(p, plat) {
return p.x < plat.x + plat.w &&
p.x + p.width > plat.x &&
p.y < plat.y + plat.h &&
p.y + p.height > plat.y;
}
function update() {
if (!gameActive) return;
player.update();
// Platform Collisions
player.grounded = false;
for (let plat of platforms) {
if (checkCollision(player, plat)) {
// Resolve collision from top
if (player.vy > 0 && player.y + player.height - player.vy <= plat.y) {
player.y = plat.y - player.height;
player.vy = 0;
player.grounded = true;
}
// Resolve collision from bottom
else if (player.vy < 0 && player.y - player.vy >= plat.y + plat.h) {
player.y = plat.y + plat.h;
player.vy = 0;
}
// Resolve collision from sides
else if (player.vx > 0 && player.x + player.width - player.vx <= plat.x) {
player.x = plat.x - player.width;
player.vx = 0;
}
else if (player.vx < 0 && player.x - player.vx >= plat.x + plat.w) {
player.x = plat.x + plat.w;
player.vx = 0;
}
}
}
// Coin Collection
for (let coin of coins) {
if (!coin.collected && checkCollision(player, {x: coin.x, y: coin.y, w: coin.w, h: coin.h})) {
coin.collected = true;
score++;
scoreEl.innerText = score;
}
}
// Goal Reach
if (checkCollision(player, goal)) {
gameActive = false;
messageEl.innerText = "YOU WIN!";
overlay.style.display = 'flex';
}
// Fall off map
if (player.y > 600) {
player.x = 50;
player.y = 300;
player.vx = 0;
player.vy = 0;
}
// Camera follow
cameraX = Math.max(0, player.x - 300);
}
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
// Draw Background clouds (simple shapes)
ctx.fillStyle = 'rgba(255,255,255,0.5)';
ctx.beginPath(); ctx.arc(100 - cameraX*0.2, 100, 30, 0, Math.PI*2); ctx.fill();
ctx.beginPath(); ctx.arc(130 - cameraX*0.2, 100, 40, 0, Math.PI*2); ctx.fill();
ctx.beginPath(); ctx.arc(160 - cameraX*0.2, 100, 30, 0, Math.PI*2); ctx.fill();
ctx.beginPath(); ctx.arc(500 - cameraX*0.2, 150, 30, 0, Math.PI*2); ctx.fill();
ctx.beginPath(); ctx.arc(530 - cameraX*0.2, 150, 40, 0, Math.PI*2); ctx.fill();
ctx.beginPath(); ctx.arc(560 - cameraX*0.2, 150, 30, 0, Math.PI*2); ctx.fill();
platforms.forEach(p => p.draw());
coins.forEach(c => c.draw());
goal.draw();
player.draw();
}
function gameLoop() {
update();
draw();
if (gameActive) {
requestAnimationFrame(gameLoop);
} else {
draw();
}
}
initLevel();
gameLoop();
</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>Simple Mario Platformer</title>
<style>
body {
margin: 0;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
background-color: #333;
color: white;
font-family: sans-serif;
overflow: hidden;
}
#game-container {
position: relative;
box-shadow: 0 0 20px rgba(0,0,0,0.5);
}
canvas {
background-color: #5c94fc; /* Classic Mario Sky Blue */
display: block;
border: 4px solid #000;
}
#ui {
position: absolute;
top: 10px;
left: 10px;
font-size: 20px;
text-shadow: 2px 2px 0 #000;
pointer-events: none;
}
#message {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
font-size: 48px;
text-align: center;
text-shadow: 4px 4px 0 #000;
display: none;
}
</style>
</head>
<body>
<div id="game-container">
<div id="ui">Coins: <span id="score">0</span></div>
<div id="message">YOU WIN!</div>
<canvas id="game" width="800" height="450"></canvas>
</div>
<script>
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 JUMP_FORCE = -12;
const MOVE_SPEED = 5;
// Game State
let score = 0;
let gameActive = true;
let cameraX = 0;
const keys = {
left: false,
right: false,
up: false
};
const player = {
x: 50,
y: 300,
width: 30,
height: 40,
vx: 0,
vy: 0,
grounded: false,
color: '#e74c3c'
};
const platforms = [
// Floor
{ x: 0, y: 400, width: 2000, height: 50, color: '#8B4513' },
// Platforms
{ x: 200, y: 300, width: 150, height: 20, color: '#2ecc71' },
{ x: 450, y: 220, width: 150, height: 20, color: '#2ecc71' },
{ x: 700, y: 300, width: 150, height: 20, color: '#2ecc71' },
{ x: 950, y: 200, width: 150, height: 20, color: '#2ecc71' },
{ x: 1200, y: 300, width: 150, height: 20, color: '#2ecc71' },
];
const coins = [
{ x: 250, y: 260, width: 20, height: 20, collected: false },
{ x: 500, y: 180, width: 20, height: 20, collected: false },
{ x: 750, y: 260, width: 20, height: 20, collected: false },
{ x: 1000, y: 160, width: 20, height: 20, collected: false },
{ x: 1250, y: 260, width: 20, height: 20, collected: false },
];
const goal = {
x: 1500,
y: 300,
width: 40,
height: 100,
color: '#f1c40f'
};
// Input handling
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 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 (!gameActive) return;
// Movement
if (keys.left) player.vx = -MOVE_SPEED;
else if (keys.right) player.vx = MOVE_SPEED;
else player.vx *= FRICTION;
if (keys.up && player.grounded) {
player.vy = JUMP_FORCE;
player.grounded = false;
}
player.vy += GRAVITY;
player.x += player.vx;
player.y += player.vy;
// Collision with platforms
player.grounded = false;
for (let plat of platforms) {
if (checkCollision(player, plat)) {
// Resolve collision from top
if (player.vy > 0 && player.y + player.height - player.vy <= plat.y) {
player.y = plat.y - player.height;
player.vy = 0;
player.grounded = true;
}
// Resolve collision from bottom
else if (player.vy < 0 && player.y - player.vy >= plat.y + plat.height) {
player.y = plat.y + plat.height;
player.vy = 0;
}
// Resolve collision from sides
else if (player.vx > 0) {
player.x = plat.x - player.width;
} else if (player.vx < 0) {
player.x = plat.x + plat.width;
}
}
}
// Collect coins
for (let coin of coins) {
if (!coin.collected && checkCollision(player, coin)) {
coin.collected = true;
score++;
scoreElement.innerText = score;
}
}
// Reach goal
if (checkCollision(player, goal)) {
gameActive = false;
messageElement.style.display = 'block';
}
// Bounds
if (player.x < 0) player.x = 0;
// Camera follows player
cameraX = player.x - canvas.width / 2;
if (cameraX < 0) cameraX = 0;
}
function draw() {
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);
// Grass top
if (plat.color === '#2ecc71') {
ctx.fillStyle = '#27ae60';
ctx.fillRect(plat.x, plat.y, plat.width, 5);
}
}
// Draw Coins
ctx.fillStyle = '#f1c40f';
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);
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);
// Eye
ctx.fillStyle = 'white';
ctx.fillRect(player.x + (player.vx >= 0 ? 20 : 5), player.y + 5, 5, 5);
ctx.restore();
requestAnimationFrame(() => {
update();
draw();
});
}
draw();
</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>Simple Platformer</title>
<style>
body {
margin: 0;
padding: 0;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
background-color: #222;
color: white;
font-family: sans-serif;
overflow: hidden;
}
#game-container {
position: relative;
box-shadow: 0 0 20px rgba(0,0,0,0.5);
}
canvas {
background-color: #5C94FC; /* Mario sky blue */
display: block;
border: 4px solid #fff;
}
#ui {
position: absolute;
top: 10px;
left: 10px;
font-size: 20px;
font-weight: bold;
text-shadow: 2px 2px #000;
pointer-events: none;
}
#message {
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
font-size: 48px;
text-align: center;
display: none;
text-shadow: 4px 4px #000;
pointer-events: none;
}
</style>
</head>
<body>
<div id="game-container">
<div id="ui">Coins: <span id="score">0</span></div>
<div id="message">YOU WIN!</div>
<canvas id="game" width="800" height="450"></canvas>
</div>
<script>
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 JUMP_FORCE = -12;
const MOVE_SPEED = 5;
// Game State
const keys = {};
let score = 0;
let gameActive = true;
let cameraX = 0;
const player = {
x: 50,
y: 300,
width: 32,
height: 32,
velX: 0,
velY: 0,
jumping: false,
color: '#E74C3C'
};
const platforms = [
// Floor
{ x: 0, y: 400, width: 2000, height: 50, color: '#8B4513' },
// Platforms
{ x: 200, y: 300, width: 150, height: 20, color: '#CD853F' },
{ x: 450, y: 220, width: 150, height: 20, color: '#CD853F' },
{ x: 700, y: 300, width: 150, height: 20, color: '#CD853F' },
{ x: 950, y: 200, width: 200, height: 20, color: '#CD853F' },
{ x: 1250, y: 300, width: 100, height: 20, color: '#CD853F' },
];
const coins = [
{ x: 250, y: 260, width: 20, height: 20, collected: false },
{ x: 500, y: 180, width: 20, height: 20, collected: false },
{ x: 750, y: 260, width: 20, height: 20, collected: false },
{ x: 1000, y: 160, width: 20, height: 20, collected: false },
{ x: 1100, y: 160, width: 20, height: 20, collected: false },
];
const goal = {
x: 1500,
y: 300,
width: 40,
height: 100,
color: '#FFD700'
};
// Input handling
window.addEventListener('keydown', e => keys[e.code] = true);
window.addEventListener('keyup', e => keys[e.code] = false);
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 (!gameActive) return;
// Horizontal movement
if (keys['ArrowRight'] || keys['KeyD']) {
if (player.velX < MOVE_SPEED) player.velX++;
} else if (keys['ArrowLeft'] || keys['KeyA']) {
if (player.velX > -MOVE_SPEED) player.velX--;
}
player.velX *= FRICTION;
// Jump
if ((keys['ArrowUp'] || keys['KeyW'] || keys['Space']) && !player.jumping) {
player.velY = JUMP_FORCE;
player.jumping = true;
}
// Apply Gravity
player.velY += GRAVITY;
// Apply velocity
player.x += player.velX;
player.y += player.velY;
// Platform Collision
player.jumping = true;
for (let plat of platforms) {
if (checkCollision(player, plat)) {
// Resolve collision from top
if (player.velY > 0 && player.y + player.height - player.velY <= plat.y) {
player.y = plat.y - player.height;
player.velY = 0;
player.jumping = false;
}
// Resolve collision from bottom
else if (player.velY < 0 && player.y - player.velY >= plat.y + plat.height) {
player.y = plat.y + plat.height;
player.velY = 0;
}
// Resolve collision from sides
else {
if (player.velX > 0) player.x = plat.x - player.width;
else if (player.velX < 0) player.x = plat.x + plat.width;
player.velX = 0;
}
}
}
// Coin collection
for (let coin of coins) {
if (!coin.collected && checkCollision(player, coin)) {
coin.collected = true;
score++;
scoreElement.innerText = score;
}
}
// Goal check
if (checkCollision(player, goal)) {
gameActive = false;
messageElement.style.display = 'block';
}
// Bound player to world
if (player.x < 0) player.x = 0;
// Camera follows player
cameraX = player.x - canvas.width / 4;
if (cameraX < 0) cameraX = 0;
}
function draw() {
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);
// Add some detail to platforms
ctx.strokeStyle = 'rgba(0,0,0,0.2)';
ctx.strokeRect(plat.x, plat.y, plat.width, plat.height);
}
// Draw Coins
ctx.fillStyle = '#F1C40F';
for (let coin of coins) {
if (!coin.collected) {
ctx.beginPath();
ctx.arc(coin.x + 10, coin.y + 10, 10, 0, Math.PI * 2);
ctx.fill();
ctx.strokeStyle = '#B8860B';
ctx.stroke();
}
}
// Draw Goal
ctx.fillStyle = goal.color;
ctx.fillRect(goal.x, goal.y, goal.width, goal.height);
ctx.fillStyle = '#000';
ctx.fillRect(goal.x, goal.y, 10, goal.height); // Goal pole
// Draw Player
ctx.fillStyle = player.color;
ctx.fillRect(player.x, player.y, player.width, player.height);
// Player eyes
ctx.fillStyle = 'white';
ctx.fillRect(player.x + 18, player.y + 6, 6, 6);
ctx.fillRect(player.x + 6, player.y + 6, 6, 6);
ctx.restore();
requestAnimationFrame(() => {
update();
draw();
});
}
draw();
</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 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;
overflow: hidden;
}
#ui {
margin-bottom: 10px;
font-size: 24px;
}
canvas {
background-color: #5c94fc; /* Mario Sky Blue */
border: 4px solid #000;
box-shadow: 0 0 20px rgba(0,0,0,0.5);
}
</style>
</head>
<body>
<div id="ui">Coins: <span id="score">0</span></div>
<canvas id="game" width="800" height="450"></canvas>
<script>
const canvas = document.getElementById('game');
const ctx = canvas.getContext('2d');
const scoreElement = document.getElementById('score');
// Game Configuration
const GRAVITY = 0.6;
const FRICTION = 0.8;
const JUMP_FORCE = -12;
const MOVE_SPEED = 5;
let score = 0;
let gameActive = true;
let cameraX = 0;
const keys = {
left: false,
right: false,
up: false
};
// Player Object
const player = {
x: 50,
y: 300,
width: 32,
height: 32,
velX: 0,
velY: 0,
jumping: false,
color: '#e74c3c'
};
// Platforms
const platforms = [
{ x: 0, y: 400, width: 2000, height: 50, color: '#8B4513' }, // Ground
{ x: 200, y: 300, width: 100, height: 20, color: '#2ecc71' },
{ x: 400, y: 220, width: 150, height: 20, color: '#2ecc71' },
{ x: 650, y: 320, width: 100, height: 20, color: '#2ecc71' },
{ x: 850, y: 250, width: 200, height: 20, color: '#2ecc71' },
{ x: 1100, y: 180, width: 100, height: 20, color: '#2ecc71' },
{ x: 1300, y: 300, width: 200, height: 20, color: '#2ecc71' },
];
// Collectibles
const coins = [
{ x: 230, y: 270, width: 20, height: 20, collected: false },
{ x: 450, y: 190, width: 20, height: 20, collected: false },
{ x: 700, y: 290, width: 20, height: 20, collected: false },
{ x: 900, y: 220, width: 20, height: 20, collected: false },
{ x: 1130, y: 150, width: 20, height: 20, collected: false },
{ x: 1400, y: 270, width: 20, height: 20, collected: false },
];
// Goal
const goal = {
x: 1600,
y: 300,
width: 40,
height: 100,
color: '#f1c40f'
};
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 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 (!gameActive) return;
// Movement
if (keys.left) player.velX = -MOVE_SPEED;
else if (keys.right) player.velX = MOVE_SPEED;
else player.velX *= FRICTION;
if (keys.up && !player.jumping) {
player.velY = JUMP_FORCE;
player.jumping = true;
}
player.velY += GRAVITY;
player.x += player.velX;
player.y += player.velY;
// Ground/Platform collision
let onGround = false;
for (let plat of platforms) {
if (player.x < plat.x + plat.width &&
player.x + player.width > plat.x &&
player.y + player.height > plat.y &&
player.y + player.height < plat.y + plat.height + player.velY + 1 &&
player.velY >= 0) {
player.y = plat.y - player.height;
player.velY = 0;
player.jumping = false;
onGround = true;
}
}
// Coin collection
for (let coin of coins) {
if (!coin.collected && checkCollision(player, coin)) {
coin.collected = true;
score++;
scoreElement.innerText = score;
}
}
// Goal check
if (checkCollision(player, goal)) {
gameActive = false;
setTimeout(() => {
alert("You Win! Final Score: " + score);
location.reload();
}, 10);
}
// Out of bounds (bottom)
if (player.y > canvas.height) {
player.x = 50;
player.y = 300;
player.velX = 0;
player.velY = 0;
}
// Camera follow
cameraX = player.x - canvas.width / 4;
if (cameraX < 0) cameraX = 0;
}
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.save();
ctx.translate(-cameraX, 0);
// Draw Platforms
platforms.forEach(plat => {
ctx.fillStyle = plat.color;
ctx.fillRect(plat.x, plat.y, plat.width, plat.height);
if (plat.height > 20) {
ctx.fillStyle = 'rgba(0,0,0,0.1)';
ctx.fillRect(plat.x, plat.y + 10, plat.width, 5);
}
});
// Draw Coins
ctx.fillStyle = '#f1c40f';
coins.forEach(coin => {
if (!coin.collected) {
ctx.beginPath();
ctx.arc(coin.x + 10, coin.y + 10, 10, 0, Math.PI * 2);
ctx.fill();
ctx.strokeStyle = '#d4ac0d';
ctx.stroke();
}
});
// Draw Goal
ctx.fillStyle = goal.color;
ctx.fillRect(goal.x, goal.y, goal.width, goal.height);
ctx.fillStyle = '#000';
ctx.fillRect(goal.x, goal.y, 5, goal.height);
// Draw Player
ctx.fillStyle = player.color;
ctx.fillRect(player.x, player.y, player.width, player.height);
ctx.fillStyle = 'white';
ctx.fillRect(player.x + 20, player.y + 5, 5, 5);
ctx.restore();
requestAnimationFrame(() => {
update();
draw();
});
}
draw();
</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 Mini 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;
overflow: hidden;
}
#game-container {
position: relative;
box-shadow: 0 0 20px rgba(0,0,0,0.5);
}
canvas {
background-color: #5c94fc; /* Classic Mario sky blue */
display: block;
}
#ui {
position: absolute;
top: 10px;
left: 10px;
font-size: 20px;
font-weight: bold;
text-shadow: 2px 2px 0 #000;
pointer-events: none;
}
#win-screen {
position: absolute;
top: 0;
left: 0;
width: 800px;
height: 450px;
background: rgba(0,0,0,0.7);
display: none;
flex-direction: column;
justify-content: center;
align-items: center;
text-align: center;
}
#win-screen h1 {
font-size: 48px;
margin-bottom: 10px;
}
</style>
</head>
<body>
<div id="game-container">
<div id="ui">Coins: <span id="score">0</span></div>
<canvas id="game" width="800" height="450"></canvas>
<div id="win-screen">
<h1>YOU WIN!</h1>
<p>Press F5 to restart</p>
</div>
</div>
<script>
const canvas = document.getElementById('game');
const ctx = canvas.getContext('2d');
const scoreEl = document.getElementById('score');
const winScreen = document.getElementById('win-screen');
// Game Constants
const GRAVITY = 0.6;
const FRICTION = 0.8;
const JUMP_FORCE = -12;
const SPEED = 0.8;
const MAX_SPEED = 5;
// Game State
let score = 0;
let gameActive = true;
const keys = {};
const player = {
x: 50,
y: 300,
width: 32,
height: 48,
vx: 0,
vy: 0,
grounded: false,
color: '#ff4444'
};
const world = {
offsetX: 0,
platforms: [
// Ground
{ x: 0, y: 400, width: 2000, height: 50, color: '#8b4513' },
// Platforms
{ x: 200, y: 300, width: 150, height: 20, color: '#ccaa00' },
{ x: 450, y: 220, width: 150, height: 20, color: '#ccaa00' },
{ x: 700, y: 300, width: 150, height: 20, color: '#ccaa00' },
{ x: 950, y: 200, width: 100, height: 20, color: '#ccaa00' },
{ x: 1200, y: 300, width: 200, height: 20, color: '#ccaa00' },
{ x: 1500, y: 250, width: 100, height: 20, color: '#ccaa00' },
],
coins: [
{ x: 250, y: 260, width: 20, height: 20, collected: false },
{ x: 500, y: 180, width: 20, height: 20, collected: false },
{ x: 750, y: 260, width: 20, height: 20, collected: false },
{ x: 980, y: 160, width: 20, height: 20, collected: false },
{ x: 1300, y: 260, width: 20, height: 20, collected: false },
],
goal: { x: 1800, y: 300, width: 40, height: 100, color: '#00ff00' }
};
// Input handling
window.addEventListener('keydown', e => keys[e.code] = true);
window.addEventListener('keyup', e => keys[e.code] = false);
function update() {
if (!gameActive) return;
// Horizontal movement
if (keys['ArrowRight'] || keys['KeyD']) {
if (player.vx < MAX_SPEED) player.vx += SPEED;
} else if (keys['ArrowLeft'] || keys['KeyA']) {
if (player.vx > -MAX_SPEED) player.vx -= SPEED;
} else {
player.vx *= FRICTION;
}
// Jump
if ((keys['ArrowUp'] || keys['KeyW'] || keys['Space']) && player.grounded) {
player.vy = JUMP_FORCE;
player.grounded = false;
}
// Apply gravity
player.vy += GRAVITY;
// Move player
player.x += player.vx;
player.y += player.vy;
// Collision detection
player.grounded = false;
for (let plat of world.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) {
// Resolve collision from top
if (player.vy > 0 && player.y + player.height - player.vy <= plat.y) {
player.y = plat.y - player.height;
player.vy = 0;
player.grounded = true;
}
// Resolve collision from bottom
else if (player.vy < 0 && player.y - player.vy >= plat.y + plat.height) {
player.y = plat.y + plat.height;
player.vy = 0;
}
// Resolve collision from sides
else {
if (player.vx > 0) {
player.x = plat.x - player.width;
} else if (player.vx < 0) {
player.x = plat.x + plat.width;
}
}
}
}
// Coin collection
for (let coin of world.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++;
scoreEl.innerText = score;
}
}
// Goal check
if (player.x < world.goal.x + world.goal.width &&
player.x + player.width > world.goal.x &&
player.y < world.goal.y + world.goal.height &&
player.y + player.height > world.goal.y) {
gameActive = false;
winScreen.style.display = 'flex';
}
// Camera follow
world.offsetX = player.x - canvas.width / 2;
if (world.offsetX < 0) world.offsetX = 0;
if (world.offsetX > 2000 - canvas.width) world.offsetX = 2000 - canvas.width;
}
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.save();
ctx.translate(-world.offsetX, 0);
// Draw Platforms
for (let plat of world.platforms) {
ctx.fillStyle = plat.color;
ctx.fillRect(plat.x, plat.y, plat.width, plat.height);
// Adding a simple highlight for "3D" look
ctx.fillStyle = 'rgba(255,255,255,0.2)';
ctx.fillRect(plat.x, plat.y, plat.width, 4);
}
// Draw Coins
ctx.fillStyle = '#ffff00';
for (let coin of world.coins) {
if (!coin.collected) {
ctx.beginPath();
ctx.arc(coin.x + 10, coin.y + 10, 10, 0, Math.PI * 2);
ctx.fill();
// Coin shine
ctx.fillStyle = '#fff';
ctx.fillRect(coin.x + 12, coin.y + 6, 3, 8);
ctx.fillStyle = '#ffff00';
}
}
// Draw Goal
ctx.fillStyle = world.goal.color;
ctx.fillRect(world.goal.x, world.goal.y, world.goal.width, world.goal.height);
ctx.fillStyle = 'white';
ctx.fillRect(world.goal.x, world.goal.y, 10, world.goal.height);
// Draw Player
ctx.fillStyle = player.color;
ctx.fillRect(player.x, player.y, player.width, player.height);
// Player eyes
ctx.fillStyle = 'white';
ctx.fillRect(player.x + 20, player.y + 10, 6, 6);
ctx.fillStyle = 'black';
ctx.fillRect(player.x + 24, player.y + 12, 3, 3);
ctx.restore();
}
function loop() {
update();
draw();
requestAnimationFrame(loop);
}
loop();
</script>
</body>
</html>