Skip to content

Instantly share code, notes, and snippets.

@straker
Last active June 24, 2026 20:16
Show Gist options
  • Select an option

  • Save straker/81b59eecf70da93af396f963596dfdc5 to your computer and use it in GitHub Desktop.

Select an option

Save straker/81b59eecf70da93af396f963596dfdc5 to your computer and use it in GitHub Desktop.
Basic Pong HTML and JavaScript Game

ICE Out; Abolish ICE

Basic Pong HTML and JavaScript Game

This is a basic implementation of the Atari Pong game, but it's missing a few things intentionally and they're left as further exploration for the reader.

Further Exploration

  • Score
    • When a ball goes past a paddle, the other player should score a point. Use context.fillText() to display the score to the screen
  • Mobile and touchscreen support
  • Ball trajectory
    • The ball should change trajectory based on where it hit the paddle. For example, if it hit the topmost part of the paddle it should have a sharp angle upward, whereas if it hit the direct middle of the paddle it should move completely flat towards the other payer.

Important note: I will answer questions about the code but will not add more features or answer questions about adding more features. This series is meant to give a basic outline of the game but nothing more.

License

(CC0 1.0 Universal) You're free to use this game and code in any project, personal or commercial. There's no need to ask permission before using these. Giving attribution is not required, but appreciated.

Other Basic Games

Support

Basic HTML Games are made possible by users like you. When you become a Patron, you get access to behind the scenes development logs, the ability to vote on which games I work on next, and early access to the next Basic HTML Game.

Top Patrons

  • Karar Al-Remahy
  • UnbrandedTech
  • Innkeeper Games
  • Nezteb
<!DOCTYPE html>
<html>
<head>
<title>Basic Pong HTML Game</title>
<meta charset="UTF-8">
<style>
html, body {
height: 100%;
margin: 0;
}
body {
background: black;
display: flex;
align-items: center;
justify-content: center;
}
</style>
</head>
<body>
<canvas width="750" height="585" id="game"></canvas>
<script>
const canvas = document.getElementById('game');
const context = canvas.getContext('2d');
const grid = 15;
const paddleHeight = grid * 5; // 80
const maxPaddleY = canvas.height - grid - paddleHeight;
var paddleSpeed = 6;
var ballSpeed = 5;
const leftPaddle = {
// start in the middle of the game on the left side
x: grid * 2,
y: canvas.height / 2 - paddleHeight / 2,
width: grid,
height: paddleHeight,
// paddle velocity
dy: 0
};
const rightPaddle = {
// start in the middle of the game on the right side
x: canvas.width - grid * 3,
y: canvas.height / 2 - paddleHeight / 2,
width: grid,
height: paddleHeight,
// paddle velocity
dy: 0
};
const ball = {
// start in the middle of the game
x: canvas.width / 2,
y: canvas.height / 2,
width: grid,
height: grid,
// keep track of when need to reset the ball position
resetting: false,
// ball velocity (start going to the top-right corner)
dx: ballSpeed,
dy: -ballSpeed
};
// check for collision between two objects using axis-aligned bounding box (AABB)
// @see https://developer.mozilla.org/en-US/docs/Games/Techniques/2D_collision_detection
function collides(obj1, obj2) {
return obj1.x < obj2.x + obj2.width &&
obj1.x + obj1.width > obj2.x &&
obj1.y < obj2.y + obj2.height &&
obj1.y + obj1.height > obj2.y;
}
// game loop
function loop() {
requestAnimationFrame(loop);
context.clearRect(0,0,canvas.width,canvas.height);
// move paddles by their velocity
leftPaddle.y += leftPaddle.dy;
rightPaddle.y += rightPaddle.dy;
// prevent paddles from going through walls
if (leftPaddle.y < grid) {
leftPaddle.y = grid;
}
else if (leftPaddle.y > maxPaddleY) {
leftPaddle.y = maxPaddleY;
}
if (rightPaddle.y < grid) {
rightPaddle.y = grid;
}
else if (rightPaddle.y > maxPaddleY) {
rightPaddle.y = maxPaddleY;
}
// draw paddles
context.fillStyle = 'white';
context.fillRect(leftPaddle.x, leftPaddle.y, leftPaddle.width, leftPaddle.height);
context.fillRect(rightPaddle.x, rightPaddle.y, rightPaddle.width, rightPaddle.height);
// move ball by its velocity
ball.x += ball.dx;
ball.y += ball.dy;
// prevent ball from going through walls by changing its velocity
if (ball.y < grid) {
ball.y = grid;
ball.dy *= -1;
}
else if (ball.y + grid > canvas.height - grid) {
ball.y = canvas.height - grid * 2;
ball.dy *= -1;
}
// reset ball if it goes past paddle (but only if we haven't already done so)
if ( (ball.x < 0 || ball.x > canvas.width) && !ball.resetting) {
ball.resetting = true;
// give some time for the player to recover before launching the ball again
setTimeout(() => {
ball.resetting = false;
ball.x = canvas.width / 2;
ball.y = canvas.height / 2;
}, 400);
}
// check to see if ball collides with paddle. if they do change x velocity
if (collides(ball, leftPaddle)) {
ball.dx *= -1;
// move ball next to the paddle otherwise the collision will happen again
// in the next frame
ball.x = leftPaddle.x + leftPaddle.width;
}
else if (collides(ball, rightPaddle)) {
ball.dx *= -1;
// move ball next to the paddle otherwise the collision will happen again
// in the next frame
ball.x = rightPaddle.x - ball.width;
}
// draw ball
context.fillRect(ball.x, ball.y, ball.width, ball.height);
// draw walls
context.fillStyle = 'lightgrey';
context.fillRect(0, 0, canvas.width, grid);
context.fillRect(0, canvas.height - grid, canvas.width, canvas.height);
// draw dotted line down the middle
for (let i = grid; i < canvas.height - grid; i += grid * 2) {
context.fillRect(canvas.width / 2 - grid / 2, i, grid, grid);
}
}
// listen to keyboard events to move the paddles
document.addEventListener('keydown', function(e) {
// up arrow key
if (e.which === 38) {
rightPaddle.dy = -paddleSpeed;
}
// down arrow key
else if (e.which === 40) {
rightPaddle.dy = paddleSpeed;
}
// w key
if (e.which === 87) {
leftPaddle.dy = -paddleSpeed;
}
// a key
else if (e.which === 83) {
leftPaddle.dy = paddleSpeed;
}
});
// listen to keyboard events to stop the paddle if key is released
document.addEventListener('keyup', function(e) {
if (e.which === 38 || e.which === 40) {
rightPaddle.dy = 0;
}
if (e.which === 83 || e.which === 87) {
leftPaddle.dy = 0;
}
});
// start the game
requestAnimationFrame(loop);
</script>
</body>
</html>
@DANIELLEGOLDOC

Copy link
Copy Markdown

Hi there, this is great! Is there a way I can just embed this into my site? (Sorry Im not a developer !)

@Githubissupercool

Copy link
Copy Markdown

what is the mobile code

@jeumahjongfr

Copy link
Copy Markdown

The code structure of this Pong game is very clear and easy to understand — if we apply that same thinking to a Mahjong project (e.g., card management, game rules, user interface), I believe it is also possible to write a simple Mahjong version on the web.

@mahjongsolitarioes

Copy link
Copy Markdown

Great example, thanks for sharing! The rendering loop explanation here is super helpful for anyone working with HTML5 games.

I’ve been experimenting with a similar setup while testing Mahjongsolitario.es, and the performance boost after optimizing draw calls and reducing canvas reflows was noticeable.

Has anyone else tried lightweight browser games to benchmark their animation performance?

@huchi0016-design

Copy link
Copy Markdown

Gg

@monivaa

monivaa commented Apr 20, 2026

Copy link
Copy Markdown

이 Pong 코드 보니까 옛날에 제가 점수 넣고 공 궤적 바꾸려고 삽질했던 기억 나네요. 게임 구조 보다 보니 다른 플랫폼은 어떻게 설계됐는지 궁금하더라고요. 그래서 찾아본 게 1win 공식 입니다 - 거기 가면 1Win 한국 플랫폼에 대한 상세한 개요를 읽을 수 있습니다. 퀴라소 라이선스, 슬롯, 라이브 딜러, 스포츠 베팅 옵션에 대한 정보만 있고 직접 베팅은 안 됩니다. 정보 확인만 가능해요. 이 Pong 예제는 CC0 라이선스라 자유롭게 수정 가능합니다. 점수 표시랑 패들 충돌 각도부터 직접 고쳐보세요.

@billy00xv-sudo

billy00xv-sudo commented Apr 29, 2026

Copy link
Copy Markdown

이 포스트 보니까 옛날 추억 돋네요. 저도 처음 코딩 배울 때 이 기본 구조로 시작했었는데, 점수 표시나 공 궤적 변경 같은 기능을 직접 붙여보는 게 진짜 실력에 도움 많이 됐어요. 그런데 게임 로직 공부하다가 문득 배팅 시스템 구조가 궁금해서 찾아보던 중, https://1-win-korea.kr/ 이곳에서 1Win Korea에 대한 상세한 개요와 함께 퀴라소 라이선스, 입금 조건, 슬롯과 라이브 딜러 게임 구성에 대한 중립적인 사실들을 읽을 수 있었습니다. 물론 거기서 직접 플레이는 못 하지만, 정보만으로도 구조 비교에 도움이 되더라고요.

@royashish61190-dot

Copy link
Copy Markdown

Jjj

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment