Skip to content
Agentmart
Submit a tool

pygame-patterns

Pygame-specific best practices, architecture patterns, and antipatterns for Python games.

Skill by jwd83

IndexedUnlicense★ 1
Write a review

Install

Works with Claude Code, Claude apps, Codex, Cursor, Gemini CLI, GitHub Copilot, VS Code, OpenCode, Goose, Windsurf. Read the repository before you give any tool access to your data.

npx agentmarket install skill/jwd83-pygame-patterns

Asks which of your tools to add it to (Claude Code, Codex, Cursor, VS Code, Windsurf, Gemini CLI, Claude Desktop) and shows the change first. See https://agentmart.dev/cli.

Get the weekly diff

The weekly diff: one email a week with new agent tools, notable updates and grade changes, plus security alerts for tools you follow. Double opt-in, one-click unsubscribe.

We use your email only for this newsletter. Privacy

About

Pygame-specific best practices, architecture patterns, and antipatterns for Python games. Use when building, refactoring, debugging, or reviewing pygame projects, including game loops, sprites, scenes/states, assets, input, collision, timing, rendering, packaging, and tests.

No reviews yet. Installed it? Reviews come from verified installers only. How reviews work

Permissions

What this skill can do and what it asks for, from its SKILL.md. Checked Oct 25, 2026.

Tools
No tools found
Secrets
None asked for
Install scripts
None found

Network hosts it talks to 1

  • codeload.github.com · found in install command

Files it touches

  • ~/.claude/skills/pygame-patterns

What's inside

Skill name
pygame-patterns
Description
Pygame-specific best practices, architecture patterns, and antipatterns for Python games. Use when building, refactoring, debugging, or reviewing pygame projects, including game loops, sprites, scenes/states, assets, input, collision, timing, rendering, packaging, and tests.
License
Unlicense
Instructions
306 lines in SKILL.md · view on GitHub

Files (1)

  • SKILL.md

SKILL.md (first lines)

# Pygame Patterns

## Purpose

Build, refactor, debug, and review pygame projects using idiomatic Python and pygame-specific practices. Use this skill with `python-refactor` when cleaning up pygame code.

Optimize for a stable main loop, explicit input/update/draw boundaries, predictable timing, cached assets, testable core logic, and architecture that fits the game's actual size.

## First Inspection Checklist

Before editing, inspect:

- Python tooling: `pyproject.toml`, `uv.lock`, `.python-version`, test config, run scripts, package layout, and supported Python versions.
- Which package is installed: `pygame` or `pygame-ce`. They both import as `pygame`; choose one and do not mix them.
- Entry point and initialization: where `pygame.init()`, mixer/display setup, `display.set_mode()`, and the main loop happen.
- Main loop order: event pumping, input handling, update timing, drawing, `display.flip()`/`update()`, and `Clock.tick()`.
- Asset paths/loading for images, sounds, fonts, maps, and data.
- Scene/state model for menus, gameplay, pause, settings, and game-over flows.
- Sprite/entity organization, collision code, coordinate system, and camera/viewport logic.
- Input model: one-shot events versus held-key state.
- Tests, headless support, and any CI constraints.

For uv projects, prefer commands like:

```bash
uv run python -m your_game
uv run pytest -q
uv run ruff check .
uv add pygame      # original package
uv add pygame-ce   # community fork
```

Do not migrate a non-uv project to uv unless asked.

## Core Shape

For small and medium games, prefer a `Game` application object plus explicit scenes/states. Keep pygame initialization and display creation at the application boundary, not import time.

```python
class Game:
    def __init__(self) -> None:
        pygame.init()
        self.screen = pygame.display.set_mode((1280, 720))
        self.clock = pygame.time.Clock()
        self.running = True
        self.scene: Scene = TitleScene(self)

    def run(self) -> None:
        while self.running:
            dt = self.clock.tick(60) / 1000.0
            events = pygame.event.get()

            for event in events:
                if event.type == pygame.QUIT:
                    self.running = False

            self.scene.handle_events(events)
            self.scene.update(dt)
            if self.scene.next_scene is not None:
                self.scene = self.scene.next_scene
            self.scene.draw(self.screen)
            pygame.display.flip()

        pygame.quit()
```

A scene owns the sprites, UI, and transition decisions for one mode. Let the main loop perform scene swaps so scenes do not mutate each other directly.

```python
class Scene:
    def __init__(self) -> None:
        self.next_scene: "Scene | None" = None

    def handle_events(self, events) -> None: ...
    def update(self, dt: float) -> None: ...
    def draw(self, surface: pygame.Surface) -> None: ...
```

Avoid one giant loop with branches for every menu, pause, gameplay, and game-over mode.

## Main Loop, Timing, and Input

- Pump events every frame with `pygame.event.get()` or equivalent; otherwise the OS may mark the window unresponsive.
- Use `pygame.time.Clock().tick(fps)` to cap frame rate and compute `dt` in seconds.
- Use `dt` for movement, cooldowns, animation timers, and other frame-rate-sensitive behavior.
- Keep loop order consistent: collect events, handle input, update simulation, draw, flip/update display.
- Draw the whole frame unless deliberately using dirty rectangles; use `display.update(rects)` only when tracking dirty regions intentionally.
- Clamp extreme `dt` values after stalls/debug pauses when large jumps would break gameplay.
- Keep shutdown explicit: exit the loop, call `pygame.quit()`, and return an exit code from `main()`.

Use events for one-shot actions such as quit, pause toggles, menu selection, clicks, and jump/button presses. Use held-key state for continuous actions:

```python
keys = pygame.key.get_pressed()
if keys[pygame.K_LEFT]:
    player.velocity.x = -PLAYER_SPEED
```

Avoid scattering direct keyboard checks across unrelated objects. Prefer a small input layer or pass actions to the objects that need them.

For high-volume events such as mouse motion or joystick axes, consider `pygame.event.set_blocked(...)` / `set_allowed(...)` only after measuring or seeing queue pressure. Never block `QUIT` or events required by the current scene/window behavior.

## Sprites and Entities

Use `pygame.sprite.Sprite` and groups when they simplify update, draw, and collision.

```python
class Player(pygame.sprite.Sprite):
    def __init__(self, pos: pygame.Vector2, image: pygame.Surface) -> None:
        super().__init__()
        self.image = image
        self.rect = image.get_rect(center=pos)
        self.position = pygame.Vector2(self.rect.center)
        self.velocity = pygame.Vector2(0, 0)

    def update(self, dt: float) -> None:
        self.position += self.velocity * dt
        self.rect.center = round(self.position.x), round(self.position.y)
```

From jwd83/skills, Unlicense.

More from jwd83/skills

Signals

Stars
1
Forks
0
Open issues
0
Last commit (this folder)
Jun 12, 2026 (4 months ago)

From GitHub (fetched Oct 24, 2026).

Details

License
Unlicense
First seen
Oct 24, 2026
Last checked
Oct 24, 2026

More from jwd83

Cite this page

pygame-patterns skill. Agent Mart. https://agentmart.dev/skills/jwd83-pygame-patterns (last updated 2026-10-24)