The real pygame, in your browser, zero install.
Live: https://fgallaire.github.io/brygame/
Brygame runs the upstream C of pygame-ce compiled to WebAssembly — not a JavaScript rewrite, not a subset — on wasthon's C-API bridge and the Brython Python runtime. Standard pygame code, straight in a web page. Built for education: it runs on anything with a browser, Chromebooks included.
A page is a canvas, one script include, and your pygame code:
<canvas id="canvas" width="720" height="480" tabindex="0"></canvas>
<script src="wasthon-pygame.js"></script>
<script type="text/x-pygame">
import pygame, sys
pygame.init()
screen = pygame.display.set_mode((720, 480))
clock = pygame.time.Clock()
ball = pygame.Rect(100, 100, 24, 24)
v = [4, 3]
while True:
for event in pygame.event.get():
if event.type == pygame.QUIT:
sys.exit()
ball.move_ip(v)
if ball.left < 0 or ball.right > 720: v[0] = -v[0]
if ball.top < 0 or ball.bottom > 480: v[1] = -v[1]
screen.fill((16, 16, 24))
pygame.draw.ellipse(screen, (240, 170, 70), ball)
pygame.display.flip()
clock.tick(60)
</script>Yes — that is the verbatim desktop code, while True and clock.tick(60)
included. The browser cannot be blocked, so at load time the loader lifts the
top-level game loop onto the browser's frame clock (an AST-guided source
transform: loop body → per-frame function, bound names promoted, break/
sys.exit() mapped to a clean stop; clock.tick becomes the non-blocking
frame pacer). Game speed is framerate-independent — on a throttled laptop the
rendering drops to 30 fps but the game keeps its speed. The explicit
pygame.run(frame) API remains available (and is what the transform targets
under the hood).
All live on the hub, all served from
loader/:
- Animated breakout — a full game at 60 fps: paddle, ball, bricks, keyboard, sound.
- Standard pygame —
literal student code (
import pygame,set_mode,Rect, …) executed as-is. - Feature suite — 40+ checks across surfaces, rects, events, images, fonts, sound.
- Runtime probe — boot diagnostics: module init, submodules, SDL2 driver, pixel round-trips.
- Sprite perf bench and API tests.
- Dear ImGui — bonus: a C++ widget GUI (cimgui + ImPlot) driven from Python through the same bridge.
Brygame Studio — the classroom editor built on Brygame (code left, game right, examples included; in French, for the French education system): https://brygame.forge.apps.education.fr
Run them locally:
python3 -m http.server --directory loader
No blobs are committed. ./build.sh rebuilds everything the site serves:
it clones wasthon (the generic C-API
bridge and the Brython runtime), pins the upstream trees to known-good commits
(pygame-ce, cimgui, cimplot), compiles _pygame.{mjs,wasm} and
_imgui.{mjs,wasm} with Emscripten, and collects the artifacts into loader/.
src/pygame/ port recipe: build script + shims for pygame-ce
src/imgui/ port recipe: cimgui + ImPlot binding
loader/ the site: hub, demo pages, wasthon-pygame.js (+ built artifacts)
build.sh orchestrator: clone wasthon@main, inject src/, collect to loader/
Copyright (C) 2026 Florent Gallaire fgallaire@gmail.com
BSD 3-Clause License — same as Brython. See LICENSE for the full text.