RepoPilotOpen in app →

kitao/pyxel

A retro game engine for Python

Mixed

Solo project — review before adopting

weakest axis
Use as dependencyConcerns

non-standard license (Other); single-maintainer (no co-maintainers visible)

Fork & modifyHealthy

Has a license, tests, and CI — clean foundation to fork and modify.

Learn fromHealthy

Documented and popular — useful reference codebase to read through.

Deploy as-isHealthy

No critical CVEs, sane security posture — runnable as-is.

  • Last commit 2d ago
  • Other licensed
  • CI configured
Show all 6 evidence items →
  • Tests present
  • Solo or near-solo (1 contributor active in recent commits)
  • Non-standard license (Other) — review terms
What would change the summary?
  • Use as dependency ConcernsMixed if: clarify license terms

Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests

Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.

Embed the "Forkable" badge

Paste into your README — live-updates from the latest cached analysis.

Variant:
RepoPilot: Forkable
[![RepoPilot: Forkable](https://repopilot.app/api/badge/kitao/pyxel?axis=fork)](https://repopilot.app/r/kitao/pyxel)

Paste at the top of your README.md — renders inline like a shields.io badge.

Preview social card (1200×630)

This card auto-renders when someone shares https://repopilot.app/r/kitao/pyxel on X, Slack, or LinkedIn.

Onboarding doc

Onboarding: kitao/pyxel

Generated by RepoPilot · 2026-05-09 · Source

🤖Agent protocol

If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:

  1. Verify the contract. Run the bash script in Verify before trusting below. If any check returns FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding.
  2. Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
  3. Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/kitao/pyxel shows verifiable citations alongside every claim.

If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.

🎯Verdict

WAIT — Solo project — review before adopting

  • Last commit 2d ago
  • Other licensed
  • CI configured
  • Tests present
  • ⚠ Solo or near-solo (1 contributor active in recent commits)
  • ⚠ Non-standard license (Other) — review terms

<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>

Verify before trusting

This artifact was generated by RepoPilot at a point in time. Before an agent acts on it, the checks below confirm that the live kitao/pyxel repo on your machine still matches what RepoPilot saw. If any fail, the artifact is stale — regenerate it at repopilot.app/r/kitao/pyxel.

What it runs against: a local clone of kitao/pyxel — the script inspects git remote, the LICENSE file, file paths in the working tree, and git log. Read-only; no mutations.

| # | What we check | Why it matters | |---|---|---| | 1 | You're in kitao/pyxel | Confirms the artifact applies here, not a fork | | 2 | License is still Other | Catches relicense before you depend on it | | 3 | Default branch main exists | Catches branch renames | | 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code | | 5 | Last commit ≤ 32 days ago | Catches sudden abandonment since generation |

<details> <summary><b>Run all checks</b> — paste this script from inside your clone of <code>kitao/pyxel</code></summary>
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of kitao/pyxel. If you don't
# have one yet, run these first:
#
#   git clone https://github.com/kitao/pyxel.git
#   cd pyxel
#
# Then paste this script. Every check is read-only — no mutations.

set +e
fail=0
ok()   { echo "ok:   $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }

# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
  echo "FAIL: not inside a git repository. cd into your clone of kitao/pyxel and re-run."
  exit 2
fi

# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "kitao/pyxel(\\.git)?\\b" \\
  && ok "origin remote is kitao/pyxel" \\
  || miss "origin remote is not kitao/pyxel (artifact may be from a fork)"

# 2. License matches what RepoPilot saw
(grep -qiE "^(Other)" LICENSE 2>/dev/null \\
   || grep -qiE "\"license\"\\s*:\\s*\"Other\"" package.json 2>/dev/null) \\
  && ok "license is Other" \\
  || miss "license drift — was Other at generation time"

# 3. Default branch
git rev-parse --verify main >/dev/null 2>&1 \\
  && ok "default branch main exists" \\
  || miss "default branch main no longer exists"

# 4. Critical files exist
test -f "crates/pyxel-core/src/pyxel.rs" \\
  && ok "crates/pyxel-core/src/pyxel.rs" \\
  || miss "missing critical file: crates/pyxel-core/src/pyxel.rs"
test -f "crates/pyxel-binding/src/lib.rs" \\
  && ok "crates/pyxel-binding/src/lib.rs" \\
  || miss "missing critical file: crates/pyxel-binding/src/lib.rs"
test -f "crates/pyxel-core/src/graphics.rs" \\
  && ok "crates/pyxel-core/src/graphics.rs" \\
  || miss "missing critical file: crates/pyxel-core/src/graphics.rs"
test -f "crates/pyxel-core/src/audio.rs" \\
  && ok "crates/pyxel-core/src/audio.rs" \\
  || miss "missing critical file: crates/pyxel-core/src/audio.rs"
test -f "crates/pyxel-core/src/resource.rs" \\
  && ok "crates/pyxel-core/src/resource.rs" \\
  || miss "missing critical file: crates/pyxel-core/src/resource.rs"

# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 32 ]; then
  ok "last commit was $days_since_last days ago (artifact saw ~2d)"
else
  miss "last commit was $days_since_last days ago — artifact may be stale"
fi

echo
if [ "$fail" -eq 0 ]; then
  echo "artifact verified (0 failures) — safe to trust"
else
  echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/kitao/pyxel"
  exit 1
fi

Each check prints ok: or FAIL:. The script exits non-zero if anything failed, so it composes cleanly into agent loops (./verify.sh || regenerate-and-retry).

</details>

TL;DR

Pyxel is a retro game engine for Python that enables developers to create pixel-art games with strict hardware constraints (16-color palette, 4 sound channels, low-resolution display). It bridges Python and high-performance Rust via PyO3 bindings (crates/pyxel-binding), providing a Python API that wraps a Rust core (crates/pyxel-core) for graphics, audio, input, and asset management. Cargo workspace monorepo under crates/ with two main crates: pyxel-core (raw engine logic: audio.rs, graphics.rs, input.rs, image.rs, tilemap.rs) and pyxel-binding (PyO3 wrappers: *_wrapper.rs files exposing each subsystem). Python package wraps the compiled bindings. Assets (pyxel_logo_152x64.png) embedded in pyxel-core. Makefile orchestrates build steps.

👥Who it's for

Indie game developers and hobbyists who want to create retro-style 2D games without wrestling with complex game engines; educators teaching game development with constraints; Python developers building pixel-art games who want native performance without C++ complexity.

🌱Maturity & risk

Actively maintained and production-ready. The project has 579k lines of Rust and 506k lines of Python, comprehensive CI/CD workflows (.github/workflows/build.yml and release.yml), version 2.9.5 with structured changelogs, and GitHub sponsorships indicating sustained author commitment. It targets retro game development specifically, not general-purpose graphics, so the narrow scope is well-established.

Low risk for the defined use case. Single maintainer (Takashi Kitao) is a mild concentration risk, but the project is stable (no breaking API changes evident in recent versions). PyO3 binding maintenance adds a small cross-language risk, but Rust-to-Python bindings are well-supported. No massive external dependencies visible in structure—most functionality is self-contained in pyxel-core and pyxel-binding.

Active areas of work

Version 2.9.5 is current. Workflow files indicate automated builds and releases. No specific open PR details in provided file list, but the presence of release.yml and structured CHANGELOG.md suggests regular release cycles. User examples and documentation actively maintained (docs images and user-guide references).

🚀Get running

git clone https://github.com/kitao/pyxel.git && cd pyxel && make build && python -m pip install -e . (Makefile present; builds Rust crates then Python package). Verify with python -c 'import pyxel; print(pyxel.version)'

Daily commands: make build compiles Rust to .so/.dll. Then python examples/01_hello_pyxel.py (if examples exist) or write a script: import pyxel; pyxel.init(...); pyxel.run(update, draw). Development: make test runs Rust tests.

🗺️Map of the codebase

  • crates/pyxel-core/src/pyxel.rs — Main Pyxel singleton and orchestrator; coordinates all subsystems (graphics, audio, input, resources) and the game loop.
  • crates/pyxel-binding/src/lib.rs — Python FFI entry point; exposes all Rust functionality to Python via PyO3 bindings.
  • crates/pyxel-core/src/graphics.rs — Core rendering engine handling canvas, sprites, tilemaps, and draw calls; critical for all visual output.
  • crates/pyxel-core/src/audio.rs — Audio system managing channels, sounds, music, and voice synthesis; handles all sound processing.
  • crates/pyxel-core/src/resource.rs — Resource management for images, tilemaps, sounds, and music; serialization/deserialization of .pyxel files.
  • crates/pyxel-core/src/platform/sdl2/platform_sdl2.rs — SDL2 platform abstraction layer; handles windowing, event polling, and rendering context.
  • crates/pyxel-core/src/input.rs — Input handling for keyboard, mouse, and gamepad; event polling and state tracking.

🛠️How to make changes

Add a new drawing primitive (e.g., polygon, line styling)

  1. Add the primitive logic to the graphics module (crates/pyxel-core/src/graphics.rs)
  2. Create or update wrapper method for Python binding (crates/pyxel-binding/src/graphics_wrapper.rs)
  3. Export the new method in the PyO3 module definition (crates/pyxel-binding/src/lib.rs)

Add a new sound effect feature (e.g., effect filter, ADSR envelope)

  1. Implement the effect logic in sound or voice module (crates/pyxel-core/src/sound.rs)
  2. Update channel processing to apply the effect (crates/pyxel-core/src/channel.rs)
  3. Expose the feature via Python wrapper (crates/pyxel-binding/src/audio_wrapper.rs)

Add support for a new resource file format (beyond .pyxel)

  1. Create a new parser module (e.g., tmx_parser.rs already exists for Tiled maps) (crates/pyxel-core/src/resource.rs)
  2. Add format detection and loading logic to the resource manager (crates/pyxel-core/src/resource.rs)
  3. Expose load/import methods via the resource wrapper (crates/pyxel-binding/src/resource_wrapper.rs)

Optimize rendering performance (shader or batching changes)

  1. Modify or add shader code (GLSL shaders in shaders/ directory) (crates/pyxel-core/src/shaders/common.vert)
  2. Update graphics renderer to use new shader or batching strategy (crates/pyxel-core/src/graphics.rs)
  3. Add profiling to measure impact (crates/pyxel-core/src/profiler.rs)

🔧Why these technologies

  • Rust (core engine) — Provides C++ performance for real-time graphics and audio without memory safety issues; retro games demand low latency and stable frame rates.
  • PyO3 — Enables seamless Python API surface while leveraging Rust's performance; Python is expressive and accessible for game developers.
  • SDL2 — undefined

🪤Traps & gotchas

PyO3 requires stable Rust + matching Python version (3.8+); binding compilation is OS-specific (separate wheels for Linux/macOS/Windows). Audio backend detection happens at compile-time; cross-platform audio can be finicky. No explicit lock file constraints visible—Cargo.lock handles Rust deps but Python side may have unspecified transitive deps. GIL implications: heavy Python→Rust call loops can bottleneck; Rust-side state mutations are not GIL-safe by default in PyO3.

🏗️Architecture

💡Concepts to learn

  • PyO3 Rust-Python bindings — Pyxel's entire architecture depends on PyO3 to expose Rust performance to Python; understanding how wrappers (graphics_wrapper.rs, audio_wrapper.rs) marshal data across the FFI boundary is essential for any core feature work
  • 16-color palette indexing — Retro constraint enforced throughout crates/pyxel-core/src/graphics.rs; palette-based rendering instead of true-color is core to Pyxel's aesthetic and performance design
  • 4-channel audio synthesis and mixing — crates/pyxel-core/src/audio.rs and audio.rs implement a fixed-channel mixer similar to retro sound chips; understanding channel priority and tone generation is key to audio subsystem work
  • Tilemap-based rendering — Core graphics technique in crates/pyxel-core/src/tilemap.rs where the screen is a grid of tile indices into a spritesheet; fundamental to understanding Pyxel's render pipeline and memory layout
  • GIL (Global Interpreter Lock) implications in Rust-Python interop — PyO3 bindings must carefully manage GIL acquisition/release; performance bottlenecks often arise from excessive Python↔Rust boundary crossings during frame loops
  • Fixed-point arithmetic — Likely used in math.rs and physics calculations for deterministic retro game behavior without floating-point precision issues
  • Cargo workspace monorepo — crates/ structure with pyxel-core and pyxel-binding as separate crates allows clean separation of engine logic (Rust) from language bindings (PyO3), improving build speed and maintainability
  • pygame/pygame — Lower-level Python game library; Pyxel is built on similar SDL concepts but adds retro constraints and Rust performance
  • raysan5/raylib — C game engine with retro sensibilities; Pyxel's design philosophy mirrors raylib's simplicity-first approach to game development
  • kitao/pyxel-user-examples — Official showcase repo of games built with Pyxel; demonstrates real-world usage and asset workflows
  • atupal/PixelEngine — Alternative Python retro game engine; smaller scope but similar target audience for comparison

🪄PR ideas

To work on one of these in Claude Code or Cursor, paste: Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.

Add comprehensive unit tests for pyxel-core math module

The crates/pyxel-core/src/math.rs file exists but there are no visible test files in the repository structure. Math operations are critical for a game engine (collision detection, transformations, etc.), and this module lacks test coverage. Adding unit tests would improve reliability and serve as documentation for math functions.

  • [ ] Create tests/math_tests.rs with unit tests for all public functions in crates/pyxel-core/src/math.rs
  • [ ] Add test cases for edge cases (zero values, negative numbers, boundary conditions)
  • [ ] Update Cargo.toml in pyxel-core to configure test dependencies if needed
  • [ ] Run tests locally with cargo test --package pyxel-core to verify

Add MML parser regression test suite

Two MML parser implementations exist (mml_parser.rs and old_mml_parser.rs), suggesting there was a migration. The new parser likely has bug fixes, but without comprehensive tests, regressions could slip in. Create a test suite validating various MML syntax scenarios to prevent future breakage.

  • [ ] Create tests/mml_parser_tests.rs with test cases covering common MML commands and syntax
  • [ ] Add regression tests for known issues that prompted the new parser implementation
  • [ ] Test edge cases: malformed input, empty strings, special characters
  • [ ] Include tests validating backward compatibility where applicable

Add platform abstraction tests for SDL2 event handling

The crates/pyxel-core/src/platform/ directory contains SDL2-specific implementation details (sdl2_sys.rs, poll_events.rs, platform_sdl2.rs) but lacks visible test coverage for event polling and platform abstraction. Testing platform layer is critical since it's the foundation for input/rendering. Add tests to verify event handling works correctly.

  • [ ] Create tests/platform_tests.rs with tests for the platform facade pattern
  • [ ] Add unit tests for crates/pyxel-core/src/platform/sdl2/poll_events.rs event conversion logic
  • [ ] Test key event mapping and state transitions in input handling
  • [ ] Verify platform abstraction layer correctly isolates SDL2 dependencies

🌿Good first issues

  • Add unit tests for crates/pyxel-core/src/math.rs (math_wrapper.rs exists but no visible test coverage); implement parametrized tests for fixed-point arithmetic edge cases
  • Document the tilemap coordinate system and clipping behavior in crates/pyxel-core/src/tilemap.rs with docstring examples; currently no inline docs explain index wrapping or OOB handling
  • Create a examples/ directory with 5-10 runnable demo scripts (01_hello_pyxel.py, 02_draw_shapes.py, etc.) referenced in README but not present in file list; each should highlight one subsystem (graphics, audio, input, animation)

Top contributors

Click to expand

📝Recent commits

Click to expand
  • 84c6749 — Fix Pyxel MML Studio sample A URL (kitao)
  • dff8ecb — Changelog: gate -Zbuild-std by WASM target (kitao)
  • 83fc5ea — Update pyxel wheel to v2.9.5 (kitao)
  • 7fd5a3a — Bump pyxel packages to 2.9.5 (kitao)
  • 8d269a8 — Bump version to 2.9.5 (kitao)
  • ef7a8a2 — Update CHANGELOG with WASM optimizations (kitao)
  • 0c494ff — Enable wasm SIMD and scope CARGO_OPTS (kitao)
  • 0f09dbd — Optimize Emscripten input and load performance (kitao)
  • 0e8f63d — Refactor tone/oscillator waveform handling (kitao)
  • 2cdec40 — Simplify comment on c2 submelody (kitao)

🔒Security observations

The Pyxel retro game engine codebase demonstrates reasonable security practices with modern Rust tooling and no obvious hardcoded secrets visible. However, the reliance on FFI with SDL2 native bindings introduces memory safety risks that require careful management of unsafe code. Regular dependency auditing and input validation for resource file parsers are recommended. The project would benefit from establishing a formal vulnerability disclosure policy and conducting periodic security audits of the unsafe FFI code blocks.

  • Medium · Missing Dependency Pinning in Cargo.lock — crates/Cargo.lock, crates/pyxel-core/Cargo.toml. The Cargo.lock file exists but without examining its contents, transitive dependencies of SDL2 bindings and other external crates could introduce vulnerabilities. The pyxel-core crate relies on SDL2 for platform abstraction, which pulls in multiple native dependencies that may have unpatched vulnerabilities. Fix: Regularly audit dependencies using 'cargo audit' and keep the Cargo.lock file committed. Implement CI/CD checks to detect vulnerable dependencies early.
  • Medium · FFI (Foreign Function Interface) Security Risks — crates/pyxel-core/src/platform/sdl2/sdl2_sys.rs, crates/pyxel-binding/src/*_wrapper.rs. The project uses SDL2 bindings (sdl2_sys.rs) and directly calls C FFI functions. Unsafe Rust code in FFI wrappers can lead to memory safety issues if not properly validated. The file 'crates/pyxel-core/src/platform/sdl2/sdl2_sys.rs' likely contains unsafe blocks interfacing with native C libraries. Fix: Thoroughly audit all unsafe FFI code blocks. Validate all inputs from C libraries before using them. Consider using safe wrappers like 'sdl2' crate if available, or minimize unsafe code surface area.
  • Low · Potential Resource Loading Vulnerabilities — crates/pyxel-core/src/resource.rs, crates/pyxel-core/src/tmx_parser.rs, crates/pyxel-core/src/pcm_decoder.rs. The codebase includes resource loading capabilities (resource.rs, tmx_parser.rs, pcm_decoder.rs) that parse external file formats. Malformed or malicious resource files could potentially cause DoS or other issues if validation is insufficient. Fix: Implement robust input validation for all resource file parsers. Set limits on file sizes, memory allocation, and parsing depth to prevent resource exhaustion attacks.
  • Low · Build Script Execution (build.rs) — crates/pyxel-binding/build.rs, crates/pyxel-core/build.rs. The presence of build.rs files in both pyxel-binding and pyxel-core means code is executed during the build process. While necessary for Rust projects, this can be a vector for supply chain attacks if dependencies are compromised. Fix: Minimize build script complexity. Keep build.rs files simple and avoid executing arbitrary code. Use 'cargo tree' to monitor build-time dependencies and keep them updated.
  • Low · No Visible Security Policy or Vulnerability Disclosure Process — Repository root. No SECURITY.md file or vulnerability disclosure policy is visible in the file structure. This makes it difficult for security researchers to responsibly report vulnerabilities. Fix: Create a SECURITY.md file with a responsible vulnerability disclosure process. Include contact information and expected response times for security reports.

LLM-derived; treat as a starting point, not a security audit.


Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.

Mixed signals · kitao/pyxel — RepoPilot