This guide takes you from a fresh Python environment to a running Keel game in five steps. You will build a movable sprite, add a bouncing physics ball, and turn on the built-in developer tools — all without creating any image or audio files. Every example on this page is a complete, runnable program.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.
Install Keel
Install Keel from PyPI. The distribution name is Need 3D physics or the ImGui dev tools? See the Installation page for optional extras.
keelpy; the import name you use in code is keel.Scaffold a project
The Keel CLI creates the standard project layout and a hot-reloading dev loop in one command:This produces:
assets/ is monitored by the asset hot-reload system. scenes/ is the conventional home for Scene.save JSON output. You can skip scaffolding and write a main.py directly — the scaffold just saves the boilerplate.Minimal sprite example
Replace Run it:A few things to notice:
main.py (or create it fresh) with the following. It opens an 800×600 window and lets you drive a white square around with WASD.texture_id=0 is always the engine’s built-in 1×1 white pixel texture. The renderer multiplies the sprite’s RGB tint into it, giving you solid-colored quads with zero asset setup. You never need an image file to get started.main.py
@keel.componentturns a plain dataclass into an ECS component.floatfields map tofloat64numpy columns automatically.world.query(keel.Transform2D, Player)returns per-archetype numpy array views — the in-place assignments (transform['x'] += ...) write directly back to ECS storage.app.input.is_key_downchecks held state every simulation tick at 60 Hz. For one-shot actions (fire, jump), useis_key_pressedinstead.
Physics example: bouncing ball
This standalone program adds 2D physics. A dynamic ball falls under gravity and bounces on a static floor. Paste it into a new file or replace Run it:With
main.py.main.py
tools.debug_draw.set_visible(True) you will see the collider outlines drawn over the window: green for dynamic bodies, gray for static ones. Press F3 to toggle the debug draw at runtime.Key concepts from this example:setup_physics_2dmust be called beforekeel.dev_toolsfor the debug draw to attach automatically.keel.BodyType.DYNAMICis required forCollisionEvent2Dto fire.STATICvsSTATICandKINEMATICvsSTATICdo not emit events — only pairings involving at least oneDYNAMICbody do.world.read_events(keel.CollisionEvent2D)drains the event queue for the current frame. The queue is cleared at the start of every new frame.
Enable developer tools
The Once the window is open:
keel.dev_tools call registers the profiler, inspector, and (if physics is set up) debug draw in one line. Add it right after your setup calls:main.py
| Shortcut | Tool | What it shows |
|---|---|---|
| F1 | World Inspector | Every archetype and entity with live component field values. Filter by component name. |
| F2 | Frame Profiler | Per-system 60-frame rolling average in milliseconds with a bar chart. |
| F3 | Debug Draw | Collider outlines colored by body type (green = dynamic, gray = static, blue = kinematic). |
tools is a DevTools instance. You can access sub-tools directly:The F-key shortcuts use edge-detected polling via
app.input.is_key_down, checked once per simulation tick. They do not rely on KeyEvent from the event bus, so they fire reliably even on visual frames where no simulation tick ran.Run with hot reload
Instead of
python main.py, use the Keel CLI for a hot-reloading dev loop:keel run watches every .py file in the current directory and restarts the process automatically on save. This means you can edit a system, hit save, and see the result in the window within a second — no manual restart needed.Other useful CLI commands:What’s Next?
ECS Concepts
Deep dive into archetypes, queries, the command buffer, events, and resource injection. Learn when to use
query, query_one, get, and set.App & Loop
How the fixed-timestep loop works, phase execution order, the
FIXED_DT constant, and App properties — everything that drives your game each frame.Systems & Phases
Phase ordering from
PRE_UPDATE through POST_RENDER, after dependencies for intra-phase ordering, and resource injection into system parameters.Events
Define custom events with
@keel.event, emit and read them within a frame, and use the built-in KeyEvent, CollisionEvent2D, and more.