The model can now move, but a player needs to see it. Add a one-way rendering boundary: World → render plan → Pygame surface. Drawing reads the state; it does not move the ball, score a catch or consume a life.
A render plan is a plain list of dictionaries describing a fill, rectangle, circle and text. It may look more explicit than drawing directly from game objects. For this small course it gives us an important seam: hosted checks can inspect shapes and labels without installing a graphics package or opening a display.
A rectangle uses a top-left position and size, while our paddle stores a center. Subtract half the width to obtain its left edge. The circle takes the ball center and radius. Keep model coordinates as floats and use round only for the plan’s integer drawing coordinates.
These runnable calculations are the same coordinate conversion used in the supplied base plan.
center, width, y, height = 240.6, 90, 288, 12
rect = [round(center - width / 2), y, width, height]
ball = [round(100.4), round(20.6)]
print("paddle rectangle", rect)
print("ball center", ball)Every frame starts with a fill command so old ball pixels do not trail across the screen. The adapter then draws the paddle and ball, renders text through a font, and calls display.flip once. The actual adapter is included in the download; it uses Pygame’s documented draw.rect and draw.circle APIs.
Our hosted exercise completes the mode overlay. A paused game says Paused; a finished round says Game over - R to restart; a stopped replay says Stopped. Running mode needs only the base plan. Return a newly created plan each call so one caller’s edits cannot contaminate a later render.
Font size and layout are tuned for the supplied 480 × 320 desktop configuration. The model also supports custom board sizes for tests; building a fully responsive desktop HUD is an extension, not a claim of this lab.
labels = {"paused": "Paused", "over": "Game over - R to restart", "stopped": "Stopped"}
for mode in ("running", "paused", "over", "stopped"):
plan = ["background", "paddle", "ball", "score"]
if mode != "running":
plan.append(labels[mode])
print(mode, plan[-1])Complete the overlay block and verify every mode. Run rendering twice against the same state and check that the input stays equal. Then try the desktop lab: its background, blue paddle and amber ball are generated shapes, so no external image assets are needed.
Primary references: Pygame drawing and display updates. The next lesson adds the rule that resolves a descending ball.