Here is that you are looking for a fun HTML5 game project to practice JavaScript, this Flappy Bird-style game is a great choice.
The game is simple: control the bird, keep it in the air, and try to pass through the gaps between the pipes without hitting them.
This project is built using HTML, CSS, and JavaScript. It uses the HTML5 Canvas element for the game graphics, so you do not need any external library or framework.
Everything is included in one HTML file, making it easy to copy, run, and customize.
Flappy Bird Game Source Code
Flappy Bird is a simple arcade-style game based on timing and quick reactions.
The player controls a bird that continuously moves forward while gravity pulls it downward. The player needs to press a button or tap the screen to make the bird move upward.
At the same time, pipes appear from the right side of the screen. The player must guide the bird through the gaps between the pipes.
The game becomes challenging because the pipes continue moving and the player needs to react at the right time.
Features of This Flappy Bird Game
This free Flappy Bird-style game includes:
- Simple arcade gameplay code
- HTML5 Canvas
- JavaScript game code
- Gravity effect
- Bird jump/flap movement
- Moving pipes
- Random pipe gaps
- Score counter
- Start and restart button
- Keyboard controls
- Mobile tap support
- Responsive game area
- No external libraries code
- Only Single HTML file
You can copy the complete code below into a new HTML file and run it directly in your browser.
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Flappy Bird Game</title>
<style>
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family: Arial, sans-serif;
background: linear-gradient(135deg, #0f172a, #1e3a8a);
min-height: 100vh;
display: flex;
justify-content: center;
align-items: center;
padding: 20px;
color: white;
}
.game-container {
width: 100%;
max-width: 520px;
text-align: center;
}
h1 {
font-size: 38px;
margin-bottom: 8px;
}
.description {
color: #cbd5e1;
margin-bottom: 15px;
}
.score {
font-size: 25px;
font-weight: bold;
margin-bottom: 12px;
}
.game-box {
width: 100%;
background: #020617;
border: 3px solid #334155;
border-radius: 14px;
padding: 8px;
}
canvas {
display: block;
width: 100%;
height: auto;
background: linear-gradient(
#38bdf8,
#bae6fd
);
border-radius: 8px;
touch-action: manipulation;
}
.start-btn {
margin-top: 18px;
padding: 12px 28px;
border: none;
border-radius: 9px;
background: #22c55e;
color: white;
font-size: 17px;
font-weight: bold;
cursor: pointer;
}
.start-btn:hover {
background: #16a34a;
}
.controls {
margin-top: 15px;
color: #cbd5e1;
line-height: 1.6;
}
@media (max-width: 500px) {
h1 {
font-size: 30px;
}
.score {
font-size: 21px;
}
}
</style>
</head>
<body>
<div class="game-container">
<h1>Flappy Bird</h1>
<p class="description">
Tap or press Space to fly through the pipes.
</p>
<div class="score">
Score: <span id="score">0</span>
</div>
<div class="game-box">
<canvas
id="gameCanvas"
width="480"
height="640">
</canvas>
</div>
<button
class="start-btn"
id="startBtn">
Start Game
</button>
<div class="controls">
Press <strong>Space</strong> or
<strong>tap the screen</strong> to flap.
</div>
</div>
<script>
const canvas =
document.getElementById("gameCanvas");
const ctx =
canvas.getContext("2d");
const scoreElement =
document.getElementById("score");
const startBtn =
document.getElementById("startBtn");
const bird = {
x: 90,
y: canvas.height / 2,
width: 30,
height: 24,
velocity: 0
};
const gravity = 0.42;
const flapStrength = -7;
const pipeWidth = 65;
const pipeGap = 155;
const pipeSpeed = 2.7;
let pipes = [];
let score = 0;
let gameRunning = false;
let gameOver = false;
let animationFrame;
function resetGame() {
bird.y =
canvas.height / 2;
bird.velocity = 0;
pipes = [];
score = 0;
gameOver = false;
scoreElement.textContent = score;
addPipe();
}
function addPipe() {
const minimumTop = 70;
const maximumTop =
canvas.height - pipeGap - 100;
const topHeight =
Math.floor(
Math.random() *
(maximumTop - minimumTop)
) + minimumTop;
pipes.push({
x: canvas.width,
top: topHeight,
bottom:
topHeight + pipeGap,
counted: false
});
}
function flap() {
if (!gameRunning) {
startGame();
return;
}
if (!gameOver) {
bird.velocity =
flapStrength;
}
}
function startGame() {
cancelAnimationFrame(animationFrame);
resetGame();
gameRunning = true;
startBtn.textContent =
"Restart Game";
gameLoop();
}
function endGame() {
gameRunning = false;
gameOver = true;
startBtn.textContent =
"Start Again";
draw();
}
function update() {
if (!gameRunning) {
return;
}
// Bird movement
bird.velocity += gravity;
bird.y += bird.velocity;
// Add new pipes
if (
pipes.length === 0 ||
pipes[pipes.length - 1].x
< canvas.width - 220
) {
addPipe();
}
// Move pipes
pipes.forEach(pipe => {
pipe.x -= pipeSpeed;
});
// Remove old pipes
pipes =
pipes.filter(
pipe =>
pipe.x + pipeWidth > 0
);
// Score
pipes.forEach(pipe => {
if (
!pipe.counted &&
pipe.x + pipeWidth < bird.x
) {
score++;
pipe.counted = true;
scoreElement.textContent =
score;
}
});
// Collision with top/bottom
if (
bird.y < 0 ||
bird.y + bird.height >
canvas.height
) {
endGame();
return;
}
// Pipe collision
for (const pipe of pipes) {
const birdRight =
bird.x + bird.width;
const birdBottom =
bird.y + bird.height;
const horizontalCollision =
birdRight > pipe.x &&
bird.x < pipe.x + pipeWidth;
const verticalCollision =
bird.y < pipe.top ||
birdBottom > pipe.bottom;
if (
horizontalCollision &&
verticalCollision
) {
endGame();
return;
}
}
}
function drawBackground() {
// Sky
const gradient =
ctx.createLinearGradient(
0,
0,
0,
canvas.height
);
gradient.addColorStop(
0,
"#38bdf8"
);
gradient.addColorStop(
1,
"#bae6fd"
);
ctx.fillStyle = gradient;
ctx.fillRect(
0,
0,
canvas.width,
canvas.height
);
// Clouds
ctx.fillStyle =
"rgba(255,255,255,0.75)";
drawCloud(80, 100);
drawCloud(330, 160);
drawCloud(220, 60);
// Ground
ctx.fillStyle = "#65a30d";
ctx.fillRect(
0,
canvas.height - 45,
canvas.width,
45
);
}
function drawCloud(x, y) {
ctx.beginPath();
ctx.arc(
x,
y,
20,
0,
Math.PI * 2
);
ctx.arc(
x + 25,
y - 10,
25,
0,
Math.PI * 2
);
ctx.arc(
x + 55,
y,
20,
0,
Math.PI * 2
);
ctx.fill();
}
function drawBird() {
// Body
ctx.fillStyle = "#facc15";
ctx.beginPath();
ctx.arc(
bird.x + 15,
bird.y + 12,
14,
0,
Math.PI * 2
);
ctx.fill();
// Wing
ctx.fillStyle = "#eab308";
ctx.beginPath();
ctx.ellipse(
bird.x + 8,
bird.y + 17,
10,
6,
0,
0,
Math.PI * 2
);
ctx.fill();
// Eye
ctx.fillStyle = "white";
ctx.beginPath();
ctx.arc(
bird.x + 20,
bird.y + 7,
5,
0,
Math.PI * 2
);
ctx.fill();
ctx.fillStyle = "#111827";
ctx.beginPath();
ctx.arc(
bird.x + 22,
bird.y + 7,
2,
0,
Math.PI * 2
);
ctx.fill();
// Beak
ctx.fillStyle = "#f97316";
ctx.beginPath();
ctx.moveTo(
bird.x + 28,
bird.y + 12
);
ctx.lineTo(
bird.x + 40,
bird.y + 16
);
ctx.lineTo(
bird.x + 28,
bird.y + 20
);
ctx.closePath();
ctx.fill();
}
function drawPipes() {
pipes.forEach(pipe => {
ctx.fillStyle = "#16a34a";
// Top pipe
ctx.fillRect(
pipe.x,
0,
pipeWidth,
pipe.top
);
// Top pipe cap
ctx.fillRect(
pipe.x - 5,
pipe.top - 18,
pipeWidth + 10,
18
);
// Bottom pipe
ctx.fillRect(
pipe.x,
pipe.bottom,
pipeWidth,
canvas.height -
pipe.bottom
);
// Bottom pipe cap
ctx.fillRect(
pipe.x - 5,
pipe.bottom,
pipeWidth + 10,
18
);
});
}
function drawGameOver() {
if (!gameOver) {
return;
}
ctx.fillStyle =
"rgba(0,0,0,0.55)";
ctx.fillRect(
0,
0,
canvas.width,
canvas.height
);
ctx.fillStyle = "#ffffff";
ctx.textAlign = "center";
ctx.font =
"bold 42px Arial";
ctx.fillText(
"Game Over",
canvas.width / 2,
canvas.height / 2 - 20
);
ctx.font =
"24px Arial";
ctx.fillText(
"Score: " + score,
canvas.width / 2,
canvas.height / 2 + 25
);
ctx.font =
"18px Arial";
ctx.fillText(
"Press Start Again to play",
canvas.width / 2,
canvas.height / 2 + 60
);
}
function draw() {
drawBackground();
drawPipes();
drawBird();
drawGameOver();
}
function gameLoop() {
update();
draw();
if (gameRunning) {
animationFrame =
requestAnimationFrame(
gameLoop
);
}
}
document.addEventListener(
"keydown",
function(event) {
if (
event.code === "Space" ||
event.key === "ArrowUp"
) {
event.preventDefault();
flap();
}
}
);
canvas.addEventListener(
"pointerdown",
function() {
flap();
}
);
startBtn.addEventListener(
"click",
function() {
startGame();
}
);
resetGame();
draw();
</script>
</body>
</html>
How to Run the Game Code
Running this game is very simple.
Step 1: Create an HTML File
Open Notepad, VS Code, or any other code editor.
Create a new file named:
index.html
Step 2: Paste the Code
Copy the complete Flappy Bird source code above and paste it into the file.
Save the file.
Step 3: Open It in Your Browser
Open index.html in Chrome, Edge, Firefox, or another modern browser.
The game will appear immediately.
Press the Start Game button to begin.
How Users Will Play
The controls and commands to play game are very simple.
On a computer, press the Space key or Arrow Up key to make the bird fly upward.
On a mobile device, simply tap the game area.
The bird will automatically move forward while gravity pulls it down.
Your job is to keep the bird between the pipes.
Every time you successfully pass a pipe, your score increases.
Try to get the highest score possible without hitting a pipe or the ground.
How the Game Works
The game uses the HTML5 Canvas element to draw the bird, pipes, clouds, sky, and ground.
JavaScript controls the complete game logic.
When the player presses Space, Arrow Up, or taps the screen, the bird receives an upward movement.
The pipes are created at random heights and move from right to left.
JavaScript checks the bird’s position against each pipe. If the bird touches a pipe, the game ends.
The same collision system also checks whether the bird reaches the top or bottom of the game
