A hobby 2D game engine
written in C++

A free and open-source engine for building 2D games — with a C++ core and gameplay scripted in Lua.

Features

A focused toolkit for building 2D games — fast rendering, real physics, and a scripting workflow that keeps you in the flow.

Rendering

A modern, GPU-accelerated 2D pipeline.

SDL3 + SDL_GPU

Sprites render at a fixed logical resolution into an offscreen target, then upscale cleanly to any window size.

Materials & HLSL shaders

Per-material custom sprite shaders, authored in HLSL and cross-compiled at runtime — no offline build step.

Sprite animation

Define animation clips and play them per entity with a simple sprite animator.

World-space camera

Pan and zoom a world camera with optional physics interpolation for smooth motion.

Physics

Real 2D physics built on Box2D.

Box2D simulation

Rigid bodies and colliders driven by a fixed-timestep loop with configurable sub-steps.

Raycasting & queries

Cast rays into the world for line-of-sight, ground checks, and gameplay queries.

Collision & trigger events

Components receive on_collision_enter/exit and on_trigger_enter/exit callbacks automatically.

Entity & Components

A straightforward composition model: each entity owns a list of components.

Lifecycle hooks

Components hook into init, enter_play, exit_play, tick, physics_tick, and more.

Composition over inheritance

Build behaviour by attaching components — mix and match without deep class trees.

Priority ordering

Control the order components tick so input runs before gameplay logic.

Lua Scripting

All gameplay code is written in Lua, with hot reload while the game runs.

Component inheritance

Share behaviour across components with single inheritance.

Data-driven prefabs

Compose entities from component blocks as declarative data — no boilerplate constructor code.

Hot reload

Edit scripts, assets, and config and see changes without restarting the engine.

A component with lifecycle hooks
DefineComponent.Player = {
    speed = 7.0,
}
---@class Player : LuaComponent
local Player = Player

function Player:init() end
function Player:enter_play() end
function Player:exit_play() end

function Player:tick(delta_time)
    -- per-frame game logic
end

function Player:physics_tick(fixed_delta_time)
    -- fixed-timestep movement
end
A data-driven prefab
DefineEntity.Player = {
    ticking = true,
    input = {},
    character_body = {
        collision_layer = Collision.Kinematic,
        collision_mask = Collision.Static | Collision.Dynamic,
        solver_ignore_mask = Collision.Trigger,
        capsule = Capsule(Vector2.zero(), Vector2.zero(), 1.2),
    },
    sprite = {
        texture = Textures.PlayerIdle01,
        material = Materials.WhiteOutline,
        z_index = 1,
    },
    -- attach the Player component
    lua_components = { Components.Player },
}
Spawn it at runtime
-- spawn the prefab at a world position
EntitySpawner.spawn_entity(Entities.Player, Vector2(0.0, 0.0))

Input Mapping

Bind keys to named actions and axes in JSON — no rebuild to remap controls.

Named actions

Map multiple keys to a single action so gameplay code never references raw key codes.

Smoothed axes

Axis mappings blend opposing keys with configurable acceleration and deceleration.

config/input_config.json
{
  "action_mappings": {
    "jump":     ["Space", "W"],
    "interact": ["E"],
    "cancel":   ["Escape"]
  },
  "axis_mappings": {
    "horizontal": {
      "acceleration": 10,
      "deceleration": 10,
      "positive": ["Right", "D"],
      "negative": ["Left", "A"]
    }
  }
}
Bind it in Lua
function Player:enter_play()
    local input = self.entity:get_input()

    -- react to a smoothed axis
    input:bind_axis("horizontal", function(axis)
        self.movement.x = axis
    end)

    -- react to a named action
    input:bind_action("jump", InputEventType.Pressed, function()
        -- ...
    end)
end

Dev Tooling

A debug-first workflow baked into the engine.

ImGui dev console

A drop-down developer console, toggled with the backtick key, for commands and live tweaking.

Typed CVars

Bool / Int / Float / String console variables with Archive, ReadOnly, and Cheat flags.

Debug drawing

Draw world-space lines, circles, and text that stay crisp across DPI and resolution.

Cross-Platform

One codebase, three desktop platforms.

Windows Linux macOS