Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/VKSFY/keel/llms.txt

Use this file to discover all available pages before exploring further.

Keel is a Python game engine whose tagline is “the backbone of your game.” It gives you a real archetype-based Entity Component System at the core, a ModernGL renderer for both 2D sprites and 3D meshes, physics bridges to pymunk and pybullet, audio via miniaudio, and a CLI with hot-reloading — all in plain Python. The tradeoff is honest: Python has interpreter overhead, so Keel pushes hot paths into numpy and C extensions (ModernGL, pymunk, pybullet) and exposes the rest as clean Python APIs you can read, debug, and extend without leaving your editor.

Why Keel?

Pygame is old, single-threaded, and bound to CPU blits. Panda3D is a Python wrapper around a C++ engine, carrying the cognitive load that implies. Other Python options stop at hobby scope or no longer maintain a release. None of them provide a modern, data-oriented ECS as the core data model. Keel is for developers who want to stay in Python and write structured game code on top of a real archetype-based ECS. Components are plain dataclasses. Systems are plain functions. Queries return numpy array views that mutate in place. You get the same data-oriented discipline found in modern C++ engines without leaving the Python ecosystem.

Feature Overview

Archetype ECS

Struct-of-arrays storage with one numpy structured array per component type per archetype. Query DSL, typed event bus, deferred command buffer, and resource injection — all composable.

Systems & Phases

Six execution phases from PRE_UPDATE through POST_RENDER, with topological ordering within each phase and automatic resource injection into extra parameters.

Events

Typed event bus with @keel.event classes, per-frame queues cleared at the start of each visual frame, and built-in events for input, physics, and window resize.

App & Loop

Fixed-timestep loop at 60 Hz simulation, render once per visual frame. App wires together the World, Scheduler, Window, and InputState in one call.

Quickstart

From zero to a running game in five steps: spawn a sprite, move it with WASD, add a bouncing physics ball, and enable the built-in developer tools.

Installation

Install from PyPI (pip install keelpy), choose optional extras for 3D physics and ImGui dev tools, and verify the setup in one import.

Architecture

App is the single top-level object. It owns:
  • World — the ECS database: archetypes, component storage, event queues, resources, and the command buffer.
  • Scheduler — a phase-ordered system runner that drives PRE_UPDATE → UPDATE → POST_UPDATE → PRE_RENDER → RENDER → POST_RENDER each tick.
  • Window — a GLFW window plus a shared ModernGL context exposed as app.ctx.
  • InputState — held-state and edge-detected helpers for keyboard, mouse, and gamepad, updated once per simulation tick.
The fixed-timestep loop runs at 60 Hz simulation. Rendering happens once per visual frame regardless of how many simulation ticks accumulated. Renderers are plain systems registered at Phase.RENDER; they read components through world.query and issue draw calls via ModernGL. Physics bridges run at Phase.POST_UPDATE, sync ECS state into the physics engine, step it, and write results back into Transform components. Every layer communicates with the next through public ECS APIs only, so adding or replacing a layer does not require changes to the others.
App
├── World  (archetypes · event bus · resources · command buffer)
├── Scheduler  (PRE_UPDATE → UPDATE → POST_UPDATE → PRE_RENDER → RENDER → POST_RENDER)
├── Window  (GLFW + ModernGL context)
└── InputState  (keyboard · mouse · gamepad)
The Scheduler registered on App and the scheduler accessible via World.scheduler are the same object. Systems registered with @app.system(phase) and @world.system(phase) both target the same registry.

Deferred Structural Changes

Calling world.spawn, world.despawn, world.add_component, or world.remove_component queues a command in an internal buffer. Nothing moves between archetypes until world.flush() runs. The main loop calls world.flush() after every simulation tick (after POST_UPDATE completes), so changes become visible to the next simulation tick within the same visual frame. This keeps query iteration stable for the duration of each tick — you can spawn entities from inside a system without invalidating the views you are currently iterating.

License

Keel is released under the MIT License. Pull requests are welcome — run pytest before submitting; the suite covers every phase and is fast.

Roadmap

The following features are planned for future releases:
  • Skeletal animation — bone hierarchies, blend trees, and animation clips for 2D and 3D meshes.
  • Parallel system execution — opt-in multi-threaded scheduler for CPU-bound systems.
  • WASM export via Pyodide — ship a Keel game as a browser-playable bundle.
  • Visual scene editor — drag-and-drop entity authoring with live ECS inspection.
  • World-space text (text that moves with the camera)
  • 3D audio / positional audio
Keel is currently at v0.8.5 with 451 passing tests across Windows, Linux, and macOS. The public API is stable for all documented features; roadmap items are not yet part of the stable surface.

Build docs developers (and LLMs) love