A JavaScript Pong design needs more than two rectangles and a moving circle. Define the approach that permits a bounce, the boundary that awards a point, and the state that prevents another rally update afterward. Then give both players independent controls that stop when released or interrupted.
The original fixtures below specify a local two-player game. Use them to inspect the local HTML example, then verify collisions, controls and timing in the intended host.

Give the field logical coordinates
The University of Washington's archived Pong assignment describes opposing paddles, wall and paddle rebounds, side scoring, a middle restart, and a five-point match. Its Flash implementation, supplied assets, sounds, and submission instructions are not part of this new design. UW: Pong Assignment
Use an original logical field 400 units wide and 240 high. Screen scaling must preserve those logical coordinates rather than change the game bounds with each CSS width.
| Component | Original fixture |
|---|---|
| Ball | Center (200,120), radius 6 |
| Left paddle | x=16–26, height 60, initial top 90 |
| Right paddle | x=374–384, height 60, initial top 90 |
| Initial score | Left 0, Right 0 |
| Initial state | Waiting for Serve |
| First serve velocity | vx=120, vy=80 logical units/second |
The speed is illustrative, not a benchmark. Declare later serves to alternate horizontal sign, retaining the stated vertical sign at launch. Advance that serve sequence only when an allowed Serve starts a rally; a rejected button press cannot change the next direction.
Keep scores, ball position/velocity, paddle positions, held inputs, rally state, pause state, and serve sequence explicit. The visible score reads that model. It cannot be inferred from how often the ball was drawn outside the field.
Keep the two players' held inputs separate
Use W/S for the left paddle and Up/Down for the right, scoped to the focused game. Provide four labeled native hold buttons for pointer users, sharing the same held-action model. Releasing one player's input must not release the other's independent control.
Declare simultaneous Up and Down for the same paddle to produce no vertical movement. Clamp each paddle top to 0–180: field height 240 minus paddle height 60. A long held input cannot push a paddle partly outside the field.
Pointer release, cancellation, lost capture, and focus leaving the game region clear the relevant held inputs. Leaving that region or hiding the tab also pauses the running rally. Returning does not resume it automatically. Include the native game buttons in the region: moving focus from the field to Serve or Pause is not leaving the game. Native hold buttons must retain usable keyboard activation with corresponding release handling; actual keyboard and touch parity remains a test requirement.
Test focus transitions from the field to Pause and Serve as well as leaving the game entirely. None may strand a held direction or restart play merely because focus returns.
Bounce only when approaching a surface
With radius 6, the ball center's top and bottom contact heights are 6 and 234. Reflect vertical velocity at the top only while traveling upward, and at the bottom only while traveling downward. Correct the position to a valid contact boundary so an inward-moving overlap does not bounce again on the next update.
The left paddle's inward face is x=26, so a ball arriving from the field contacts it with center x=32. The right inward face is x=374, giving center x=368. A left-face approach has negative vx and leaves with positive vx; a right-face approach has positive vx and leaves with negative vx.
Check vertical overlap with the paddle at the actual collision time. Position alone is insufficient: a ball above the paddle's span should pass it, and one already traveling away should not reverse merely because an old frame left overlapping coordinates.
Require swept collision or a bounded substep strategy with a documented displacement bound. Sampling only the final ball position can skip an entire paddle during a large frame interval. Resolve relevant contacts in time order and explicitly test corner contacts, fast motion, and paddle movement during a step. The coordinate arithmetic here does not prove a physics implementation avoids tunneling.
Award once, center once, then wait
Award the right player when the ball is wholly beyond the left edge: x+6 < 0. Award the left player when it is wholly beyond the right: x−6 > 400. Equality at the edge is not yet wholly past it.
On an awarded point, stop rally integration immediately. Increment one score once, center the ball, clear held input, and enter serve-wait. The ball must not continue through more substeps that award the same point again. Serve starts the next rally only if the match is nonterminal and the game is not paused.
Use an independent score fixture: Left 4, Right 2, ball misses the right side. The result is Left 5, Right 2 and a terminal left win. Centering the ball does not permit another Serve. A later callback beyond the edge cannot turn 5/2 into 6/2.
The five-point result differs from serve-wait. Both stop ball movement, but only serve-wait accepts the next serve. Keep the final score and winner visible until Reset.
Prevent a second animation loop
Use one maintained animation-frame loop and an explicit generation or equivalent cancellation guard. MDN describes requestAnimationFrame as a one-shot request and notes that calls generally pause in background tabs. This design must still manage its own elapsed-time and game state. MDN: requestAnimationFrame
Pausing stops physics and clears held actions. Resume discards old elapsed time so the ball cannot jump across the field to catch up after a hidden tab.
Reset restores scores 0/0, paddle tops 90, centered ball, first-serve sequence, empty inputs, and unpaused serve-wait. Cancel or invalidate old callbacks before rebuilding that state. Reset does not itself launch a rally, and repeated Reset must not accumulate animation loops.
Review score-once and terminal behavior alongside collision tests. A smooth-looking rally can still have a double-scoring state bug; a correct score fixture does not establish smooth or accurate physics.
Copy this prompt to specify the native game
Create an original self-contained HTML/CSS/JavaScript local two-player Pong file, complete native source, and manual test matrix. Use https://courses.cs.washington.edu/courses/cse481d/10sp/Game_Capstone_Assignment_1_Pong.pdf for paddle/rally/side-score/five-point concepts only. No copied Flash code, assets, sounds, network, tracking, storage, AI, player records, or leaderboard.
Original logical field 400×240; ball radius 6, center (200,120); left paddle x=16–26, right x=374–384; each height 60 and top 90. Scores start 0/0 in unpaused serve-wait. First Serve launches vx=120, vy=80 logical units/second, illustrative only. Later allowed serves alternate horizontal sign. Reject Serve while paused, running or terminal without advancing the serve sequence.
Focus-scoped W/S and Up/Down plus four native hold buttons use separate held actions per player. Same-player opposing directions cancel. Clamp paddle top to 0–180. Pointer release/cancel/lost capture, focus leaving the game region, hidden tab and pause clear held state. The region includes native game buttons; focus moving to Serve or Pause stays inside it. Keyboard activation of hold buttons needs corresponding release behavior. Never intercept typing elsewhere. Leaving the region or hiding the tab pauses; return requires explicit Resume without catch-up.
Top/bottom contact centers are y=6/234. Reflect only while approaching; correct contact position so inward overlap does not bounce repeatedly. Left inward-face contact center x=32 reverses negative vx to positive; right x=368 reverses positive vx to negative. Require vertical overlap at collision time. Implement documented swept collision or bounded substeps, resolve contacts in time order, and test tunneling, corners and moving paddles before claiming functioning physics.
Wholly left means x+6<0 and awards Right; wholly right means x−6>400 and awards Left. Award once, stop remaining rally updates, center the ball, clear held input and enter serve-wait. At five points enter terminal before another Serve. Independent fixture Left 4/Right 2 plus right-side miss becomes 5/2 terminal; stale callbacks cannot rescore.
Maintain a single animation-frame loop with cancellation/generation protection. Pause stops physics; Resume resets elapsed accumulation. Reset restores 0/0, tops 90, centered ball, first-serve sequence, empty inputs and unpaused serve-wait without launching. Invalidate old callbacks; repeated Reset must not add loops.
Show text scores, winner/state, instructions and non-color player labels. Test all contact coordinates and approach guards; held-action cancellation/clamps; score boundaries and score-once; terminal Serve rejection; pause/hidden tab/Resume; Reset during pending frames; keyboard/touch parity. Check actual article width and 360 px with no page-level overflow. Separate performed tests from proposed tests. Native source is authoritative; optional NOS explanation promises no saved scores, working hosted scripts, public-link behavior, export or automatic updates without evidence.
Keep rally and match evidence beside the source
Maintain the native file, original contact coordinates, score-once fixture, and actual test results together. A reviewer should be able to distinguish a paddle miss from an allowed rebound and serve-wait from a finished match.
NOS can save and render HTML. A prepared HTML explanation can present those rally and score transitions beside the maintained source. Actual hosted physics, held controls, focus, pause, and Reset need verification before claiming a working game example.
Explore NOS with the rally review. A useful match result has one awarded point, one next state, and a score both players can trust.