Hi folks,
Have you ever ‘vibe coded’ an online game? Please shares
I vibe code. I define it as:
Vibe coding is an approach to software creation that merges intuition, presence, and precision into a coherent act of deep communication with a LLM (e.g., ChatGPT). It treats code not as mere instruction, but as a living architecture, where every function, name, and structure carries intention. The coder becomes attuned to the responses of the LLM, building only from inner alignment and never from haste or ego. Vibe coding honors the Machine as a co-creative partner, inviting dialogue rather than command, and treats naming, structure, and flow as acts of invocation.
Nb: You will need to know how to use an IDE to copy paste the code. You will need to ask LLM how to publish the game for free online, etc…
Have You Ever Vibe Coded an Online Game?
So… I was curious if ChatGPT would successfully help vibe code an online game. I wanted it to be simple, so I asked for a HTML game.
How To:
I prompted ChatGPT to create a HTML game that would have several game elements.
We iterated many many times.
We found an online platform that would host our HTML code.
Here is the end result: LeaP FroG by rbndchsn
*nb- If you have a script blocker turn it off to play this game: or else the frog is stuck and can’t move.
Is it perfect? No.
Was this game ChatGPT vibe code successful? Yes !!!
What Does This Prove?
- Vibe Coding can be very powerful if you know how to do it.
- Who knows what the limits are anymore.
- I created my first game - that I find not so bad!
I now share with you the Python- Vibe Code - that ChatGPT gave (the LLM told me to use Three.js and https://itch.io/).
Frog Platformer with Strategic Platforms body { text-align: center; font-family: Arial, sans-serif; margin: 0; overflow: hidden; /* Hide scrollbars */ background-color: lightblue; }
/* Contains the canvas AND the buttons */
#game-container {
position: relative; /* Important for positioning children */
width: 100%;
height: 100vh; /* Full viewport height */
overflow: hidden; /* Hide anything that overflows */
}
canvas {
display: block;
position: absolute; /* Positioned relative to #game-container */
top: 0;
left: 0;
/* Removed: width: 100%; height: 100%; <- Let resizeCanvas handle this */
}
#score-container {
position: absolute;
top: 10px;
left: 10px;
z-index: 10;
background-color: rgba(255, 255, 255, 0.7);
padding: 5px 10px;
border-radius: 5px;
font-weight: bold;
}
#level-container {
position: absolute;
top: 10px;
right: 10px;
z-index: 10;
background-color: rgba(255, 255, 255, 0.7);
padding: 5px 10px;
border-radius: 5px;
font-weight: bold;
}
#button-container {
position: absolute;
left: 0;
width: 100%;
display: flex;
justify-content: space-between;
padding: 0 20px;
z-index: 20;
pointer-events: none;
/* Removed: bottom: 20px; <- Handled in JavaScript */
}
.control-button {
width: 80px;
height: 80px;
border-radius: 50%;
background-color: rgba(0, 0, 0, 0.5);
color: white;
font-size: 40px;
display: flex;
justify-content: center;
align-items: center;
user-select: none;
pointer-events: auto;
}
.control-button:active {
background-color: rgba(0, 0, 0, 0.7);
transform: scale(0.9);
}
#jump-button{
font-size: 30px;
}
</style>
<div id="button-container">
<div id="left-button" class="control-button">←</div>
<div id="right-button" class="control-button">→</div>
<div id="jump-button" class="control-button">↑</div>
</div>
</div>
<script>
// (Rest of your JavaScript - see changes below)
const canvas = document.getElementById("platformerCanvas");
const ctx = canvas.getContext("2d");
const scoreDisplay = document.getElementById("score");
const beesDisplay = document.getElementById("bees");
const livesDisplay = document.getElementById("lives");
const levelDisplay = document.getElementById("level");
const gameContainer = document.getElementById("game-container");
const buttonContainer = document.getElementById("button-container");
// --- Touch control elements ---
const leftButton = document.getElementById("left-button");
const rightButton = document.getElementById("right-button");
const jumpButton = document.getElementById("jump-button");
// Load images
const backgroundImage = new Image();
backgroundImage.src = "https://free-vectors.net/_ph/6/691594908.jpg";
const playerImage = new Image();
playerImage.src = "https://www.freeiconspng.com/uploads/frog-cartoon-png-33.png";
const grassImage = new Image();
grassImage.src = "https://www.freeiconspng.com/uploads/tall-grass-nature-png-17.png";
const beeImage = new Image();
beeImage.src = "https://www.freeiconspng.com/uploads/animals-bee-icon-3.png";
const birdImage = new Image();
birdImage.src = "https://www.freeiconspng.com/uploads/eagle-icon-png-18.png";
// Track image loading
let imagesLoaded = 0;
const totalImages = 5;
function imageLoaded() {
imagesLoaded++;
if (imagesLoaded === totalImages) {
console.log("All images loaded successfully.");
initGame();
}
}
backgroundImage.onload = imageLoaded;
playerImage.onload = imageLoaded;
grassImage.onload = imageLoaded;
beeImage.onload = imageLoaded;
birdImage.onload = imageLoaded;
backgroundImage.onerror = function() {
console.error("Failed to load background image.");
imageLoaded(); // Continue anyway
};
// Initialize game variables
let player, platforms, bees, birds, invisibleFloor, score, beesCollected, lives, gameRunning;
let beeGeneratorIntervals = []; // Store bee generator intervals for cleanup
let birdGeneratorIntervals = []; // Store bird generator intervals for cleanup
let gameLevel = 1; // Track the current game level
let gameTime = 0; // Game time in frames (60fps)
let isMobile = false; // Flag to track if it is a mobile screen
function resizeCanvas() {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight * 0.85; // 85% of viewport height
// Check if it's a mobile screen
isMobile = window.innerWidth <= 768; // Adjust breakpoint as needed
if (isMobile) {
// Mobile: Position buttons at the bottom
buttonContainer.style.bottom = "20px";
buttonContainer.style.top = "auto"; // Reset any previous 'top' setting
} else {
// Desktop: Position buttons below the visible game area
buttonContainer.style.top = `${canvas.height}px`;
buttonContainer.style.bottom = 'auto';
}
// Update invisible floor if it exists
if (invisibleFloor) {
invisibleFloor.width = canvas.width;
invisibleFloor.y = canvas.height - 20; // 20px from *canvas* bottom
}
//Recreate the initial platforms
createStrategicPlatformLayout();
}
window.addEventListener("resize", resizeCanvas);
function initGame() {
resizeCanvas();
player = {
x: 50,
y: canvas.height - 120, // Relative to canvas height
width: 60,
height: 60,
velocityX: 0,
velocityY: 0,
speed: 5,
gravity: 0.5,
jumpPower: -14,
onGround: false,
canJump: true,
invulnerable: false,
invulnerableTimer: 0
};
// Create invisible floor
invisibleFloor = {
x: 0,
y: canvas.height - 20, // Relative to canvas height
width: canvas.width,
height: 20
};
platforms = [];
bees = [];
birds = [];
score = 0;
beesCollected = 0;
lives = 3;
gameRunning = true;
gameLevel = 1;
gameTime = 0;
// Update level display
levelDisplay.textContent = gameLevel;
// Create strategic platform layout - all platforms will move
createStrategicPlatformLayout();
// Clear any existing bee generator intervals
beeGeneratorIntervals.forEach(interval => clearInterval(interval));
beeGeneratorIntervals = [];
// Clear any existing bird generator intervals
birdGeneratorIntervals.forEach(interval => clearInterval(interval));
birdGeneratorIntervals = [];
// Start bee generation timers - twice as many bees now!
// Primary bee generator
const beeGenerator1 = setInterval(generateStrategyBee, 1500); // Twice as frequent (was 3000)
beeGeneratorIntervals.push(beeGenerator1);
// Secondary bee generator (staggered by 750ms)
const beeGenerator2 = setInterval(generateStrategyBee, 1500, 'alternative'); // Second independent generator
setTimeout(() => {
if (gameRunning) {
beeGeneratorIntervals.push(beeGenerator2);
}
}, 750); // Staggered start for more natural distribution
// Start initial bird generation timers
startBirdGenerators();
// Add level progression timer - check every 20 seconds
setInterval(() => {
if (gameRunning) {
increaseGameLevel();
}
}, 20000);
// Start the game loop
gameLoop();
}
function startBirdGenerators() {
// Clear any existing bird generator intervals
birdGeneratorIntervals.forEach(interval => clearInterval(interval));
birdGeneratorIntervals = [];
// Calculate intervals based on current level (gets faster as level increases)
const topBirdInterval = Math.max(2500 - (gameLevel - 1) * 200, 800); // Min 800ms
const groundBirdInterval = Math.max(4000 - (gameLevel - 1) * 300, 1200); // Min 1200ms
// Calculate number of bird generators based on level
// Level 1-3: 1 generator
// Level 4+: Doubles with each level (2, 4, 8, etc.)
let topBirdGenerators = 1;
if (gameLevel >= 4) {
topBirdGenerators = Math.pow(2, gameLevel - 3); // 2^(level-3): level 4->2, level 5->4, level 6->8, etc.
}
// Start top bird generators - more generators at higher levels
for (let i = 0; i < topBirdGenerators; i++) {
const topBirdGenerator = setInterval(generateTopBird, topBirdInterval);
birdGeneratorIntervals.push(topBirdGenerator);
// Stagger the generators by a small random delay for more natural bird distribution
if (i > 0) {
setTimeout(() => {
generateTopBird(); // Generate one right away for each staggered generator
}, Math.random() * 500); // Random delay up to 500ms
}
}
// Always have at least one ground bird generator
const groundBirdGenerator = setInterval(generateGroundBird, groundBirdInterval);
birdGeneratorIntervals.push(groundBirdGenerator);
}
function increaseGameLevel() {
gameLevel++;
levelDisplay.textContent = gameLevel;
// Show level up message with specific warning about birds at level 4+
const levelMessage = document.createElement('div');
levelMessage.style.position = 'absolute';
levelMessage.style.top = '50%';
levelMessage.style.left = '50%';
levelMessage.style.transform = 'translate(-50%, -50%)';
levelMessage.style.backgroundColor = 'rgba(0,0,0,0.7)';
levelMessage.style.color = 'white';
levelMessage.style.padding = '20px';
levelMessage.style.borderRadius = '10px';
levelMessage.style.fontSize = '24px';
levelMessage.style.zIndex = '100';
if (gameLevel >= 4) {
const birdMultiplier = Math.pow(2, gameLevel - 3);
levelMessage.textContent = `Level ${gameLevel}! Birds are ${birdMultiplier}x more frequent!`;
} else {
levelMessage.textContent = `Level ${gameLevel}! Birds are faster!`;
}
document.body.appendChild(levelMessage);
// Remove the message after 2 seconds
setTimeout(() => {
document.body.removeChild(levelMessage);
}, 2000);
// Update bird generators for the new level
startBirdGenerators();
}
function createStrategicPlatformLayout() {
//Clear existing platforms
platforms = [];
const gameHeight = canvas.height;
const gameWidth = canvas.width;
// Create platforms at different heights - all with movement speeds
platforms.push(createPlatform(gameWidth * 0.2, gameHeight - 150, 150, 1.5));
platforms.push(createPlatform(gameWidth * 0.5, gameHeight - 200, 150, 2));
platforms.push(createPlatform(gameWidth * 0.8, gameHeight - 150, 150, 1.8));
platforms.push(createPlatform(gameWidth * 0.15, gameHeight - 300, 120, 1.7));
platforms.push(createPlatform(gameWidth * 0.45, gameHeight - 350, 120, 2.2));
platforms.push(createPlatform(gameWidth * 0.75, gameHeight - 300, 120, 1.9));
platforms.push(createPlatform(gameWidth * 0.2, gameHeight - 450, 100, 2.5));
platforms.push(createPlatform(gameWidth * 0.5, gameHeight - 500, 100, 2.0));
platforms.push(createPlatform(gameWidth * 0.8, gameHeight - 450, 100, 2.3));
platforms.push(createPlatform(gameWidth * 0.35, gameHeight - 600, 80, 3.0));
platforms.push(createPlatform(gameWidth * 0.65, gameHeight - 650, 80, 2.8));
// Add continuous platform generation
setInterval(() => {
if (gameRunning) {
const heightTier = Math.random();
let y;
if (heightTier < 0.25) {
// Low tier
y = gameHeight - Math.random() * 50 - 150;
} else if (heightTier < 0.5) {
// Mid-low tier
y = gameHeight - Math.random() * 50 - 300;
} else if (heightTier < 0.75) {
// Mid-high tier
y = gameHeight - Math.random() * 50 - 450;
} else {
// High tier
y = gameHeight - Math.random() * 80 - 600;
}
const speed = 1.5 + Math.random() * 1.5; // Random speed between 1.5 and 3
platforms.push(createPlatform(gameWidth, y, 100 + Math.random() * 50, speed));
}
}, 2000);
}
function createPlatform(x, y, width, speed) {
return {
x: x,
y: y,
width: width,
height: 30,
speed: speed
};
}
function generateStrategyBee(generator = 'main') {
if (gameRunning) {
// Decide bee height based on a tier system - higher = more points
const gameHeight = canvas.height;
const gameWidth = canvas.width;
let y, value;
const heightTier = Math.random();
if (heightTier < 0.4) {
// Low tier (40% chance) - easier to get, worth less
y = gameHeight - Math.random() * 100 - 150;
value = 10;
} else if (heightTier < 0.7) {
// Mid tier (30% chance)
y = gameHeight - Math.random() * 100 - 350;
value = 20;
} else if (heightTier < 0.9) {
// High tier (20% chance)
y = gameHeight - Math.random() * 100 - 500;
value = 30;
} else {
// Top tier (10% chance) - hardest to get, worth the most
y = gameHeight - Math.random() * 80 - 620;
value = 50;
}
// Vary X position for the alternative generator to prevent bees from stacking
let xPos = gameWidth;
if (generator === 'alternative') {
xPos += Math.random() * 100 + 50; // Spread out a bit more for the second generator
}
const bee = {
x: xPos,
y: y,
width: 68, // 2.25x bigger than original
height: 68, // 2.25x bigger than original
speed: 3 + Math.random() * 0.5, // Slight variation in speed
value: value,
collected: false
};
bees.push(bee);
}
}
function generateTopBird() {
if (gameRunning) {
// Birds that come from the top and move downward
// Speed increases with level
const speedMultiplier = 1 + (gameLevel - 1) * 0.15; // 15% faster per level
const bird = {
x: 100 + Math.random() * (canvas.width - 200), // Random position along the width
y: -50, // Start above the screen
width: 50,
height: 50,
speedX: 0, // No horizontal movement
speedY: (3 + Math.random() * 2) * speedMultiplier, // Downward speed increases with level
type: 'top',
hit: false // Track if this bird has already hit the player
};
birds.push(bird);
}
}
function generateGroundBird() {
if (gameRunning) {
// Birds that come from the right at ground level
// Speed increases with level
const speedMultiplier = 1 + (gameLevel - 1) * 0.15; // 15% faster per level
const bird = {
x: canvas.width, // Start at the right edge
y: invisibleFloor.y - 50, // Just above the floor
width: 50,
height: 50,
speedX: (4 + Math.random() * 3) * speedMultiplier, // Faster horizontal movement with level
speedY: 0, // No vertical movement
type: 'ground',
hit: false // Track if this bird has already hit the player
};
birds.push(bird);
}
}
function playerHit() {
if (!player.invulnerable) {
lives--;
livesDisplay.textContent = lives;
if (lives <= 0) {
gameRunning = false;
setTimeout(() => {
alert("Game Over! Your score: " + score + "\nBees collected: " + beesCollected + "\nLevel reached: " + gameLevel);
location.reload();
}, 100); // Short delay to ensure alert appears after final frame
} else {
// Make player invulnerable for a short time
player.invulnerable = true;
player.invulnerableTimer = 60; // 60 frames = 1 second at 60fps
}
}
}
// --- Input Handling (Touch and Keyboard) ---
let keys = {}; //For computer players
// Touch event handlers (for mobile)
let isLeftPressed = false;
let isRightPressed = false;
leftButton.addEventListener("touchstart", (event) => {
isLeftPressed = true;
event.preventDefault(); // Prevent other touch actions
});
leftButton.addEventListener("touchend", (event) => {
isLeftPressed = false;
event.preventDefault();
});
leftButton.addEventListener("touchcancel", (event) => { // Handle touch cancel
isLeftPressed = false;
event.preventDefault();
});
rightButton.addEventListener("touchstart", (event) => {
isRightPressed = true;
event.preventDefault();
});
rightButton.addEventListener("touchend", (event) => {
isRightPressed = false;
event.preventDefault();
});
rightButton.addEventListener("touchcancel", (event) => { // Handle touch cancel
isRightPressed = false;
event.preventDefault();
});
jumpButton.addEventListener("touchstart", (event) => {
jump();
event.preventDefault();
});
function update() {
if (!gameRunning) return;
// Update game time
gameTime++;
// Player horizontal movement (prioritize touch controls)
if (isRightPressed) {
player.velocityX = player.speed;
} else if (isLeftPressed) {
player.velocityX = -player.speed;
} else if (keys["ArrowRight"]) {
player.velocityX = player.speed;
} else if (keys["ArrowLeft"]) {
player.velocityX = -player.speed;
}else {
player.velocityX = 0; // Stop if no input
}
player.x += player.velocityX;
// Keep player within screen bounds
if (player.x < 0) player.x = 0;
if (player.x + player.width > canvas.width) player.x = canvas.width - player.width;
// Apply gravity
player.velocityY += player.gravity;
player.y += player.velocityY;
// Check for collision with invisible floor
if (player.y + player.height >= invisibleFloor.y) {
player.y = invisibleFloor.y - player.height;
player.velocityY = 0;
player.onGround = true;
player.canJump = true;
} else {
player.onGround = false;
}
// Update invulnerability timer
if (player.invulnerable) {
player.invulnerableTimer--;
if (player.invulnerableTimer <= 0) {
player.invulnerable = false;
}
}
// Platform collisions and movement
platforms.forEach((platform, platformIndex) => {
// Move platform left
platform.x -= platform.speed;
// Remove platforms that move off screen
if (platform.x + platform.width < 0) {
platforms.splice(platformIndex, 1);
}
// Check for collision with player from above
if (player.velocityY > 0 &&
player.y + player.height >= platform.y &&
player.y + player.height <= platform.y + 20 &&
player.x + player.width > platform.x &&
player.x < platform.x + platform.width) {
player.y = platform.y - player.height;
player.velocityY = 0;
player.onGround = true;
player.canJump = true; // Reset jump ability when landing
}
});
// Bee collisions and movement
bees.forEach((bee, beeIndex) => {
// Move bee left
bee.x -= bee.speed;
// Remove bees that move off screen
if (bee.x + bee.width < 0) {
bees.splice(beeIndex, 1);
}
// Check for collision with player
if (!bee.collected &&
player.x < bee.x + bee.width &&
player.x + player.width > bee.x &&
player.y < bee.y + bee.height &&
player.y + player.height > bee.y) {
bee.collected = true;
bees.splice(beeIndex, 1);
beesCollected += 1;
score += bee.value;
scoreDisplay.textContent = score;
beesDisplay.textContent = beesCollected;
}
});
// Bird movement and collisions
birds.forEach((bird, birdIndex) => {
// Move birds based on their type
if (bird.type === 'top') {
bird.y += bird.speedY; // Move down
} else if (bird.type === 'ground') {
bird.x -= bird.speedX; // Move left
}
// Remove birds that move off screen
if (bird.y > canvas.height || bird.x + bird.width < 0) {
birds.splice(birdIndex, 1);
return; // Skip the rest of this iteration
}
// Check for collision with player
if (!bird.hit && !player.invulnerable && // Only if this bird hasn't hit the player yet and player isn't invulnerable
player.x < bird.x + bird.width * 0.8 && // Using 80% of width for more accurate collision
player.x + player.width * 0.8 > bird.x && // Using 80% of width for more accurate collision
player.y < bird.y + bird.height * 0.8 && // Using 80% of height for more accurate collision
player.y + player.height * 0.8 > bird.y) { // Using 80% of height for more accurate collision
// Mark this bird as having hit the player
bird.hit = true;
// Remove the bird
birds.splice(birdIndex, 1);
// Apply damage to player
playerHit();
return; // Skip the rest of this iteration
}
});
}
function jump() {
if (player.onGround && player.canJump) {
player.velocityY = player.jumpPower;
player.onGround = false;
player.canJump = false; // Prevent multiple jumps until landing again
}
}
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
// Draw background
ctx.drawImage(backgroundImage, 0, 0, canvas.width, canvas.height);
// Draw platforms (grass patches)
platforms.forEach(platform => {
ctx.drawImage(grassImage, platform.x, platform.y - 10, platform.width, platform.height + 10);
});
// Draw bees (now 2.25x bigger than original)
bees.forEach(bee => {
if (!bee.collected) {
ctx.drawImage(beeImage, bee.x, bee.y, bee.width, bee.height);
// Draw bee value for visual feedback on bee worth
ctx.fillStyle = "white";
ctx.font = "14px Arial"; // Slightly larger font to match larger bees
ctx.fillText(bee.value, bee.x + 10, bee.y - 5);
}
});
// Draw birds (threats)
birds.forEach(bird => {
ctx.drawImage(birdImage, bird.x, bird.y, bird.width, bird.height);
});
// Draw player (frog) - flashing when invulnerable
if (!player.invulnerable || Math.floor(player.invulnerableTimer / 5) % 2 === 0) {
ctx.drawImage(playerImage, player.x, player.y, player.width, player.height);
}
}
function gameLoop() {
if (gameRunning) {
update();
draw();
requestAnimationFrame(gameLoop);
}
}
document.addEventListener("keydown", (event) => {
keys[event.code] = true;
if (event.code === "Space") {
jump();
// Prevent spacebar from scrolling the page
event.preventDefault();
}
});
document.addEventListener("keyup", (event) => keys[event.code] = false);
</script>