Build 2D games fast. Keep the engine understandable.
A C++17 2D game engine built on SDL2, Box2D, and SDL_mixer, with grid gameplay, an LLM-playable interface, and a large runnable example catalog.
Version: v1.0.0 — see CHANGELOG.md.
License: dual-licensed under the GPL-3.0-or-later or a proprietary
commercial license — see LICENSE.
- Game loop & windowing —
Gamebase class (Engine/Core/SDLApp.h): window, renderer, physics, audio, asset manager, scene list, FPS limiting. - Grid-based games —
Game2D(Engine/Core/Game2D.h): tile grid, entities, bindable input, UI helpers, and delta-time game loop. - LLM-playable games —
LLMPlayableinterface (Engine/Core/GameState.h): export game state as text/JSON, register named actions, and let an LLM (or any agent) drive the game. - Physics — Box2D v3 wrapper (
Engine/Core/Physics.h): worlds, rigid bodies, collision callbacks. - Audio — SDL_mixer groups and players (
Engine/Audio/AudioEngine.h): WAV chunks and MP3/OGG music. - Versioned API —
Engine/Version.h(generated by CMake) exposesUMBRA_VERSION_MAJOR/MINOR/PATCHandUMBRA_VERSION_STRING. - Rendering — sprites with hierarchical parts, tile maps, grid rendering, UI text/buttons/stats, and 2D effects examples (bloom, lighting, particles, meshes, procedural terrain, and more).
- Cross-platform — macOS, Linux, Windows (vendored deps), and WebAssembly via Emscripten.
#include "Engine/Core/Game2D.h"
class MyGame : public Game2D {
public:
MyGame() : Game2D("My Game", 800, 600, /*tileSize=*/20) {}
void initGame() override {
createGrid(40, 30, 20);
player = createEntity<GridEntity>(getGrid(), 5, 5);
player->setColor({0, 200, 255, 255});
bindKey(KEY_UP).onPress([this]{ player->tryMove(0, -1); });
bindKey(KEY_DOWN).onPress([this]{ player->tryMove(0, 1); });
}
private:
std::shared_ptr<GridEntity> player;
};
int main() {
MyGame game;
game.run();
}See DOCS.md for the full API reference and Examples/ for 50+ working examples.
The engine is built to ship games fast. Scaffold, edit, build, ship — zero build wiring:
make new-game GAME=Pong # copies the template into Games/Pong/
make game GAME=Pong # builds it (CMake auto-registers Games/*)
./build-games/Pong_game # play
./tools/build_web_game.sh Pong # optional: WASM export into web/Every new game starts from a complete, playable, LLM-aware template (Coin Collector) — see GAME_DEV_GUIDE.md for the 30-minute walkthrough, and GAMES.md for the curated catalog of 100 games (5 already shipped) with the engine features each one exercises.
# macOS
brew install sdl2 sdl2_image sdl2_ttf sdl2_mixer cmake
# Debian/Ubuntu
sudo apt install libsdl2-dev libsdl2-image-dev libsdl2-ttf-dev libsdl2-mixer-dev cmakecmake -S . -B build -DCMAKE_BUILD_TYPE=Release
cmake --build build -j./build/sdl_app # Default demo (Procedural tile map)
./build/snake_example # Example games
./build/minesweeper_example
./build/tictactoe_example
./build/roguelike_examplectest --test-dir build --output-on-failure
# or run directly:
./build/sdl_app_tests
./build/sdl_app_backend_testsemcmake cmake -S . -B build_wasm -DCMAKE_BUILD_TYPE=Release
cmake --build build_wasm -j
# or use the helper script - builds ALL examples AND every shipped game
# in Games/ into web/ (examples at web/*.html, games at web/games/*/)
./build_wasm.sh
# equivalent make target (uses the local emsdk config + bin_shims)
make wasm| Option | Default | Description |
|---|---|---|
UMBRA_BUILD_EXAMPLES |
ON |
Build example games/effects |
UMBRA_BUILD_TESTS |
ON |
Build the unit test suite |
MYGAME_VENDORED |
OFF |
Use vendored SDL2 (Windows) |
USE_VENDORED_RTAUDIO |
ON |
Use vendored RtAudio (optional) |
├── main.cpp # Entry point / default game
├── Games/ # The 100-game program: auto-registered games
│ ├── _template/ # collector starter (default new-game template)
│ ├── _twin_stick/ # arena-shooter starter (--twin-stick)
│ ├── _platformer/ # jump-and-run starter (--platformer)
│ └── <name>/ # one folder per game, zero CMake edits
├── tools/ # new_game.sh, build_web_game.sh, memcheck/callgrind
├── Engine/
│ ├── Audio/ # AudioEngine, AudioFile (SDL_mixer + WAV)
│ ├── Core/ # SDLApp (Game base), AssetManager, Game2D, Grid,
│ │ # Helpers, InputManager, Physics, Script, UI, ...
│ ├── EntityAndScene/ # Scene, Sprite, TileMap
│ ├── Rendering/ # Renderer, ParticleSystem
│ ├── ResourceHandling/ # Texture
│ └── Text/ # TextWriter
├── Examples/ # Example games and 2D rendering demos
├── tests/ # Unit tests (CTest)
└── dependencies/ # Vendored SDL2, SDL2_image, SDL_ttf, SDL2_mixer,
# Box2D v3, RtAudio, libgamepad
dependencies/ is the single canonical vendored location — root-level copies
of those trees (e.g. a stray sdl/ or box2d/) fail every CI job, the CMake
configure, and make check-layout (runs tools/check_vendored_layout.sh, no
build needed), so a duplicate can never silently drift back in.
The Shadow Engine is a proprietary asset: it is not released under any permissive (MIT/ISC/BSD) license. It is dual-licensed — you may use it under either of these two options:
- GNU General Public License v3 or later (
LICENSE.GPL-3.0) — for free, open games. If you release your game's source under the GPL, you may use the engine at no cost. This is ideal for open-source and free games. - Proprietary commercial license (
LICENSE.COMMERCIAL) — for commercial games. To distribute a game commercially — closed- source, sold, or monetized in any way — you must obtain a commercial license from the copyright holder and pay the agreed royalties.
There is no fee for GPL-licensed games; commercial releases require a commercial license and royalties. Forking, reselling, or re-licensing the engine itself is not permitted outside the GPL terms.
Source files carry the SPDX identifier GPL-3.0-or-later OR LicenseRef-Commercial.
Third-party components remain under their own licenses (SDL2 zlib, Box2D MIT, RtAudio MIT, AudioFile MIT, hidapi BSD-3/GPL-3). See LICENSE for details.
