286. Manual pygame main loop
Add a manual pygame main loop for the framebuffer smoke runner.
Lesson 286 of 356 · tests/chapter_05_rendering_pipeline/test_286_manual_pygame_main_loop.py
Files to update/create
tools/show_framebuffer.pyWhy this step exists
The previous step added helpers that can draw a Framebuffer onto a pygame Surface. This step adds the manual window loop so a developer can visually confirm that the pure Framebuffer data can be displayed.
Important
This is a manual smoke runner, not an automated rendering test. Automated tests must not open a real pygame window.
Run the tool as a Python module
uv run python -m tools.show_framebufferPython's -m flag expects a module name, not a file path. The module name uses dots:
tools.show_framebuffernot as a file path:
tools/show_framebuffer.pyModern Python supports this project layout as a namespace package, so this lesson does not require an __init__.py file.
Manual commands
Correct:
uv run python -m tools.show_framebuffer
Incorrect:
uv run python -m tools/show_framebuffer.py
uv run python -m tools.show_framebuffer.pyWhat is the pygame main loop?
A pygame main loop keeps a window alive by repeatedly
1. reading events
2. drawing to the window surface
3. presenting the drawn imageMinimal shape
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
draw_framebuffer(window, framebuffer, SCALE)
pygame.display.flip()What is pygame.display.flip()? It presents the current contents of the window surface to the display. In simple terms:
draw pixels -> flip -> user sees pixelsExpected manual visual result
The checkerboard framebuffer should show a black/white or dark/white pattern like:
+----------------+
| ██ ██ ██ ██ |
| ██ ██ ██ ██ |
| ██ ██ ██ |
| ██ ██ ██ |
| ██ ██ ██ ██ |
| ██ ██ ██ ██ |
+----------------+The exact block size depends on the framebuffer size and SCALE, but the important visual check is:
alternating light and dark squares are visible
closing the window exits cleanlySuggested implementation example
SCALE = 3
def main() -> None:
framebuffer = make_checkerboard_framebuffer()
pygame.init()
try:
window = pygame.display.set_mode(
(framebuffer.width * SCALE, framebuffer.height * SCALE)
)
pygame.display.set_caption("Framebuffer Smoke Test")
running = True
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
draw_framebuffer(window, framebuffer, SCALE)
pygame.display.flip()
finally:
pygame.quit()
if __name__ == "__main__":
main()Architecture rule
pygame remains outside emulator core. This file may import pygame because it lives under tools/. Do not import pygame from emulator/rendering, emulator/ppu, or emulator/console.
Out of scope
- testing the real pygame window in pytest
- loading ROMs
- rendering live Console output
- controller input
- sprites
Run this lesson
uv run pytest tests/chapter_05_rendering_pipeline/test_286_manual_pygame_main_loop.py -v