webdevpuneet.com

Pong vs Computer – Free HTML, CSS & JS Neon Canvas Game

Pong vs Computer · Games · Plain HTML, CSS & JS · Live preview

CategoryGames

For supporters

Source Code

Want the source code?

Play the game for free. Become a WebDevPuneet supporter to unlock the complete HTML, CSS and JavaScript source code, the exports (HTML, React, Vue, Angular, Tailwind) and Fork.

Play freeSource code: Patreon

Extend with AI

Take This Snippet Further With AI

The AI prompt for this one is for Patreon supporters ($3 a month), along with a site with no ads. Supporters enter the passcode once and it is remembered in this browser.

· Become a supporter

What's included

Features

Five CPU levels (Rookie to Legend) that raise AI speed, tracking and accuracy, unlocked one by one and saved to localStorage
Rate-limited AI paddle: proportional step clamped to a top speed, with an aim error re-rolled after every return
Angle-reflection bounce physics: the rebound angle comes from the exact contact point, up to plus or minus 60 degrees
Swept paddle collision that interpolates the crossing point, so a fast ball can never tunnel through a paddle
Power-up orbs: grow your paddle, shrink the opponent's, or slow the ball, collected by the last player to hit it
Web Audio synth with no files: hit pitch climbs with the rally, plus goal, power-up and milestone sounds and a mute button
Neon visuals: glowing paddles, ball colour that heats up with speed, fading trail, particle bursts and screen shake
Rally counter with milestone callouts every 5 hits and a saved best rally
Delta-time movement, retina-sharp canvas, and pointer, touch, arrow-key and W/S input
Pause with Space or P, auto-pause when the tab is hidden, and a 3-2-1 countdown before the first serve

About this UI Snippet

Pong vs Computer — Five CPU Levels, Power-Up Orbs, Swept Collision & Rate-Limited AI

Screenshot of the Pong vs Computer snippet rendered live

Pong is the original video game archetype, and what separates a forgettable clone from a fun one is feel: a ball that bounces by where it hits, an opponent that is beatable but never boring, and enough juice and variety to make you want one more match. This snippet is a neon canvas Pong with five unlockable CPU levels, power-up orbs, a Web Audio synth, particle effects and a collision system that cannot be tunnelled through at high speed. It uses no libraries and no audio files.

An AI that is beatable on purpose, tuned by level

A paddle that copies ball.y every frame never misses, so it is unbeatable and no fun. Here the CPU computes how far its paddle centre is from a target and moves a fraction of that distance each frame, capped by a top speed: cpuStep = clamp(diff * lv.k, -lv.speed, lv.speed). The target is the ball's y plus an aimErr offset that is re-rolled every time the player returns the ball, so the CPU sometimes aims slightly off. While the ball travels away from it, the CPU drifts back to the middle. The five entries in the LEVELS array (Rookie, Club Player, Pro, Expert, Legend) raise the top speed, the tracking factor and the aim accuracy, and shorten the gap between power-up orbs.

Levels that unlock as you win

Only level 1 is open at the start. Winning a match (first to 7) unlocks the next level and moves the selection to it, the button changes to "Next Level", and losing offers "Retry Level". The highest unlocked level is saved to localStorage inside a try/catch, so the game also runs in sandboxed iframes where storage is blocked, it just does not remember your progress.

Angle-reflection bounce physics and a speed that heats up

bounceOffPaddle() turns the contact position into a rebound angle: rel = (ball.y - paddleY) / paddleH gives a value from 0 at the top edge to 1 at the bottom, and angle = (rel - 0.5) * (Math.PI / 3) maps it to plus or minus 60 degrees. Every hit multiplies the speed by 1.06 up to MAX_SPEED, and the ball's colour moves from cool blue to red as it gets faster, with a fading trail behind it.

Swept collision instead of a simple range check

Each frame the game keeps the ball's previous position and checks whether the ball crossed a paddle's face between the previous and the new position. It then interpolates the y value at the crossing point and tests that against the paddle. This means a fast ball can never skip over a paddle between two frames, which is the classic tunnelling bug of naive Pong code. Movement is scaled by a delta-time factor, so the game runs at the same speed on 60Hz and 120Hz screens.

Power-up orbs

During a long rally an orb appears in the middle of the court. Whoever hit the ball last collects it when the ball touches it. A green orb grows your paddle for 8 seconds, a pink one shrinks the opponent's paddle, and a blue one slows the ball down. Paddles grow and shrink smoothly around their centre, and a glow shows who has an active power-up.

Juice: sound, particles, shake and rally tracking

Paddle hits, wall hits, goals, power-ups and rally milestones every five hits play short sounds made with an OscillatorNode and a GainNode, and the pitch of the hit sound climbs with the rally. Sparks burst from every impact, the screen shakes on hard hits and goals, a rally counter tracks your streak, and the longest rally is saved as your best. Mouse, touch (through pointermove), Arrow keys and W/S all move the paddle, Space or P pauses, and the game pauses itself when the tab is hidden.

Step by step

How to Use

  1. 1
    Pick a level and startChoose an unlocked level from the numbered buttons (only level 1 is open at first), then click "Start Game". A 3-2-1 countdown runs before the first serve.
  2. 2
    Move your paddleMove the mouse over the court, drag a finger on a touch screen, or use Arrow Up/Down or W/S. The paddle is always clamped inside the court, and Space or P pauses the game.
  3. 3
    Aim with the paddle edgesWhere the ball touches your paddle sets the return angle: the centre sends it straight back, the edges send it off at up to 60 degrees, which is how you beat the CPU. Every hit also makes the ball faster and hotter in colour.
  4. 4
    Grab the power-up orbsIn a long rally an orb appears. Hit the ball last and let it touch the orb: G grows your paddle, S shrinks the opponent's, T slows the ball down.
  5. 5
    Play to 7 and unlock the next levelThe first side to 7 points wins the match. Beating a level unlocks the next, up to level 5 (Legend), and your longest rally is recorded as your best.
  6. 6
    Retry or move onAfter a match the overlay offers "Next Level" after a win, or "Retry Level" after a loss, and you can also pick any unlocked level yourself.

Real-world uses

Common Use Cases

Retro arcade mini-game for a portfolio or landing page
Pong is the most recognised arcade game there is, and the neon look, sound and levels make it a fun addition to a personal site or an Easter egg on a static page. It is self-contained canvas code that starts instantly.
Teaching bounce physics, swept collision and beatable AI
The angle-reflection bounce, the swept collision check and the rate-limited CPU are three of the most asked-about game-programming ideas. The level table shows how one set of constants (speed, tracking, aim error) controls difficulty, compare it with the AI tuning in the Connect Four vs Computer snippet.
Reference for canvas scaling and retina rendering
The pointer-to-canvas coordinate mapping and the devicePixelRatio setup (a bigger buffer with ctx.scale) are common sources of blurry or misaligned canvas games. This snippet shows both done correctly with a CSS-responsive canvas.
Game-feel and progression exercise
Particles, screen shake, pitch-climbing sound, power-ups and unlockable levels are small additions that change how a game feels. They make a good worked example for coding exercises or interview prep about game loops and progression.
Themed reskin for a branded promotional game
Swap the indigo and red paddle colours, the dark background and the orb types for brand colours to build a "beat our mascot" mini-game for a campaign landing page, with the five levels as an easy way to add a challenge ladder.
Starting point for a local two-player match
The CPU logic lives in one block of update(), so replacing it with a second set of keyboard controls (for example I and K) turns this into a local two-player Pong, and the power-up system works for both sides without changes.
Related: Rock Paper Scissors vs Computer
See the Rock Paper Scissors vs Computer for a related games pattern worth pairing with this one.

Got questions?

Frequently Asked Questions

The CPU moves toward the ball using a proportional step (the level's k factor times the distance) capped at the level's top speed, and it aims at the ball's y plus a small random error that changes after each of your returns. A fast or sharply angled shot can outrun it, especially on the lower levels. A paddle that snaps to the ball every frame would be unbeatable and not fun, so the game avoids it on purpose.

The LEVELS array holds five entries, each with a name, top speed, tracking factor k, aim error in pixels and the time between power-up orbs. Winning a match unlocks the next level and saves the highest unlocked level to localStorage under pong-unlocked-level. Edit the numbers to retune the difficulty, or add an entry (and a numbered button in the HTML) for a sixth level.

bounceOffPaddle() computes rel as the contact position along the paddle (0 at the top edge, 1 at the bottom) and maps it to an angle between -60 and +60 degrees with (rel - 0.5) * (Math.PI / 3). A centre hit goes nearly straight back, an edge hit goes off steeply. Each hit also multiplies the speed by 1.06, capped at MAX_SPEED.

A simple check tests whether the ball is inside a paddle's x range at the end of a frame. At high speeds the ball can move past the paddle in one frame and never be detected, which is called tunnelling. Here the game remembers the previous position, detects that the ball crossed the paddle face during the frame and interpolates the y position at the crossing, so even the fastest ball is caught.

After a rally has started, a timer (the level's orbEvery value) spawns an orb at a random spot in the middle of the court. If the ball touches it, whoever hit the ball last gets the effect: grow makes their paddle 96px tall for 8 seconds, shrink makes the opponent's 40px tall for 8 seconds, and slow cuts the ball speed to about 70 percent. Uncollected orbs blink and disappear after 7 seconds.

Yes. Reads and writes to localStorage are wrapped in try/catch, so a blocked storage only means that your best rally and unlocked levels are not remembered. The AudioContext is created inside the Start click and every sound call is wrapped in try/catch, so a blocked audio device never stops the game. There is also a mute button.