Repository navigation
Breakout Task paddle can move past the canvas walls #1640
Description
The Breakout Task paddle can move past the canvas walls. The keyboard clamp checks the paddle position before moving it 7px, so the last step goes over the edge. In the 480px canvas (scale 1) the paddle stops at x = 405.5 against a limit of 405 on the right, and at x = -0.5 against 0 on the left. The overshoot depends on the scale: at scale 1.25 it is about 6px. The mouse handler has no clamp at all. It centers the paddle on any pointer inside the canvas, so the paddle can hang up to half its width (37.5px at scale 1) off either side. The patient sees part of the paddle cut off at the edge of the game.
Where
packages/instrument-library/src/interactive/DNP_BREAKOUT_TASK/index.ts:203-207 (keyboard):
if (rightPressed && paddleX < width - paddleWidth) {
paddleX += 7;
} else if (leftPressed && paddleX > 0) {
paddleX -= 7;
}packages/instrument-library/src/interactive/DNP_BREAKOUT_TASK/index.ts:94-99 (mouse): paddleX = relativeX - paddleWidth / 2 for any 0 < relativeX < width.
Reproduce
- Open the Breakout Task in a viewport that gives the 480x320 canvas, and press Start.
- Hold the right arrow until the paddle stops.
Actual: the paddle comes to rest at x = 405.5, so its right edge is at 480.5, past the 480px canvas. Holding the left arrow leaves it at x = -0.5.
Expected: the paddle stops flush with the wall, at x = 405 on the right and x = 0 on the left.
You can also move the mouse to the far right edge of the canvas. Actual: half the paddle is drawn off the canvas. Expected: the paddle stops at the wall.
Tests
packages/instrument-library/src/__tests__/DNP_BREAKOUT_TASK.test.ts. The tests should stop the paddle at the right wall and should stop the paddle at the left wall were written loosely on purpose: they only assert that the paddle stops within one 7px step of the wall, so they pass with or without the fix. When fixing, tighten them to expect(stoppedX).toBe(CANVAS_WIDTH - PADDLE_WIDTH) and expect(stoppedX).toBe(0). If the mouse path is clamped too, add a case that moves the mouse near each edge.
Suggested fix
Clamp after moving, e.g. paddleX = Math.min(paddleX + 7, width - paddleWidth) and paddleX = Math.max(paddleX - 7, 0). Apply the same [0, width - paddleWidth] clamp in mouseMoveHandler.
Found while raising unit test coverage in #1632.
Activity