Keep one coordinate system for the rules

A canvas has an internal drawing size and a displayed size. EduBuzz's moving games use a 400 by 400 drawing area, but the page can display it smaller on a phone. A pointer event reports a position in viewport pixels. Using that number directly as a game coordinate produces a growing offset as the canvas is resized.

Cosmic Breakout and Orbit Dodge solve this by reading the canvas rectangle and scaling the pointer into the 400-pixel internal board. Keep the simulation in that board's coordinates. The surrounding CSS can then change the displayed size without changing collision math.

Convert a pointer position

function pointer(e) {
  const rect = canvas.getBoundingClientRect();
  const x = (e.clientX - rect.left) * 400 / rect.width;
  // Breakout: paddle is an 80-pixel-wide rectangle.
  paddle = Math.max(0, Math.min(320, x - 40));
}

This expanded version of Breakout's pointer function centers the paddle under the pointer. Subtracting rect.left removes the canvas's page offset. Multiplying by the ratio between internal and displayed widths converts the distance. The final clamp leaves enough room for the entire paddle.

Try the arithmetic: if the canvas displays at 300 pixels wide and the pointer is 150 pixels from its left edge, the game coordinate is 200. The paddle's left edge becomes 160, which centers an 80-pixel paddle at 200. Test the same calculation near both edges.

Keep a drag attached to the board

The templates call canvas.setPointerCapture(e.pointerId) on pointerdown. That keeps the active drag's pointer events directed to the canvas while the finger or mouse moves outside its bounds. Without capture, an edge drag may stop updating just when the player needs it most.

Touch scrolling and game steering can compete for the same gesture. The moving game boards use a touch-action rule on the canvas so a drag controls the game. Scope that behavior to the play surface: people still need to scroll the surrounding page to read the instructions. Provide enough visible space around the board to do so.

Keep keyboard state separate from movement

Breakout and Orbit Dodge set left and right flags on keydown, then clear them on keyup. The update function reads those flags and moves using elapsed time. This avoids tying movement speed to the operating system's key-repeat setting. On window blur, both flags clear so a lost keyup event does not leave the paddle moving.

Snake uses discrete direction requests instead, because its rules advance one cell at a time. Reuse its steer function from both keyboard listeners and direction buttons. Maintaining one rules function prevents touch controls from allowing turns that keyboard controls reject.

Test interaction as well as layout

A narrow screenshot cannot prove that touch controls work. In a real round, try steering at the left and right edges, dragging out of the board, lifting your finger, and starting another drag. Test portrait and landscape where possible. On a keyboard, confirm that game keys control the game when its frame has focus and that Tab still reaches Start and the surrounding links.

  • Keep instructions visible near the board.
  • Use descriptive button names and a visible focus style.
  • Keep essential status text outside the canvas as ordinary HTML.
  • Do not rely on hover to reveal a required control.

For a small improvement, add a touch-only hint beside the board describing the exact gesture. Keep the hint outside the drawing area so it cannot hide a falling obstacle or a last brick.

Put this lesson into practice: download Cosmic Breakout or play the original before making your changes.

Keep building