A blazing-fast, ergonomic 2D game library for Rust — no macros, no magic, just gems.
A modern, modular alternative to macroquad — built on miniquad + glam + rodio,
with batteries included for scenes, particles, tweens, animation, collision, audio, and UI.
macroquad is great, but it leans on proc macros, global state, and a monolithic API.
game-gem is a rethink for developers who want the ergonomics of macroquad with the
architecture of a real engine:
- No proc macros — Plain
trait GameState+Game::run()instead of#[macroquad::main]. - Explicit context — All engine state passed via
&mut Context. No hidden globals, no surprises. - Feature-gated modules — Compile only what you use. Disable
audio,ui,particles, etc. and they vanish from your binary. - Batteries included — systems that macroquad ships without:
- Scene management with transitions (fade, slide, push/pop stack)
- Particle system with emitters, shapes, and pooling
- Tweening with 30+ easing functions
- Sprite-sheet animation with a state machine
- Collision detection (AABB, circle, ray casting, spatial hash)
- Immediate-mode UI toolkit
- Spatial 2D audio with distance falloff
- Multi-camera system with shake, follow, and split-screen
- Asset manager with reference-counted handles and hot-reload hooks
- Proper error handling —
Resulttypes instead of panics. - Zero-cost abstractions — Feature flags mean unused modules don't exist in your binary.
use game_gem::prelude::*;
struct MyGame;
impl GameState for MyGame {
fn update(&mut self, ctx: &mut Context) {
if ctx.input.keyboard.is_pressed(KeyCode::Escape) {
ctx.quit();
}
}
fn render(&mut self, ctx: &mut Context) {
ctx.graphics.clear(Color::SKY_BLUE);
ctx.graphics.draw_rect(100.0, 100.0, 200.0, 150.0, Color::GOLD);
ctx.graphics.draw_text("Hello, game-gem!", 50.0, 50.0, 32.0, Color::WHITE);
}
}
fn main() {
Game::new()
.window_title("Hello game-gem!")
.window_size(800, 600)
.run(MyGame);
}That's it — no #[macroquad::main("Conf")], no global functions, no hidden setup.
The Context is the single point of access for everything: time, input, graphics,
audio, UI, particles, tweens, and the window.
Add game-gem to your Cargo.toml:
[dependencies]
game-gem = "0.1"All optional modules are enabled by default. To slim down your build, disable what you don't need:
game-gem = { version = "0.1", default-features = false, features = ["collision"] }- Rust 1.85+ (uses Rust 2024 edition)
- Platform toolchain for
miniquad:- Linux:
libx11/libxi/libgldev packages - macOS: Xcode command line tools
- Windows: MSVC build tools
- Web:
wasm32-unknown-unknowntarget + a JS bundler
- Linux:
Three runnable examples ship in examples/. Clone the repo and try them:
# Bouncing ball with camera shake, trail, and tweening
cargo run --example basics
# Menu scene with stack-based navigation and transitions
cargo run --example scene_demo
# Fire + sparkle particle emitters reacting to the mouse
cargo run --example particles| Example | What it demonstrates |
|---|---|
basics.rs |
Game loop, input actions, camera follow & shake, color HSL, mouse interaction, FPS HUD |
scene_demo.rs |
SceneManager, Scene trait, Transition::Fade, keyboard-driven menu |
particles.rs |
ParticleEmitter configuration, emitter shapes, color/size interpolation, bursts |
| Module | Feature flag | What it gives you |
|---|---|---|
[math] |
(always) | Vec2 / Vec3 / Mat4 (via glam), Rect, Transform, Lerp, Angle, shorthand constructors |
[color] |
(always) | Color with HSL/HSV, hex parsing, CSS named constants, lerp, alpha helpers |
[time] |
(always) | Time resource with delta time, FPS, Timer, fixed timestep, time scaling |
[input] |
(always) | Keyboard, mouse, gamepad state, remappable InputActions, gestures |
[camera] |
(always) | Multi-camera, smooth follow with deadzone, screen shake, zoom clamps, split-screen viewports |
[engine] |
(always) | Game builder, WindowConfig, Context, GameState trait, main loop |
[scene] |
(always) | Scene trait, SceneManager, Transition (fade / slide), SceneEvents |
[assets] |
(always) | AssetHandle<T>, AssetManager, ImageAsset, SpriteSheet, hot-reload hooks |
[collision] |
collision |
AABB, circle, ray casting, SpatialHash broad phase, CollisionInfo with penetration & normal |
[particles] |
particles |
ParticleEmitter, EmitterShape (point/line/circle/rect), per-particle easing, pooling |
[tween] |
tween |
30+ Ease functions, generic Tween<T: Lerp>, TweenManager, callbacks, chaining |
[animation] |
animation |
Animation from sprite sheets, AnimationPlayer, state machine, frame events |
[ui] |
ui |
Immediate-mode button, slider, text_input, checkbox, progress_bar, layouts |
[audio] |
audio |
Sound builder, AudioManager, music/SFX channels, fade in/out, 2D spatial positioning |
Import everything with a single line:
use game_gem::prelude::*;The prelude is feature-aware — only items from enabled modules are re-exported.
[features]
default = ["audio", "ui", "particles", "animation", "tween", "collision"]
audio = ["dep:rodio"]
ui = []
particles = []
animation = []
tween = []
collision = []
serde = ["dep:serde", "glam/serde"] # Serde derive for math + color types
debug = ["collision"] # Extra debug overlays / inspectors| Flag | Default | What it pulls in |
|---|---|---|
audio |
✅ | rodio — cross-platform audio output |
ui |
✅ | Immediate-mode UI toolkit |
particles |
✅ | Particle emitters & shapes |
animation |
✅ | Sprite-sheet animation system |
tween |
✅ | Tweening & easing functions |
collision |
✅ | Collision detection & spatial hashing |
serde |
❌ | Serialize / Deserialize for math & color types |
debug |
❌ | Enables collision + debug visualization helpers |
| Concern | macroquad |
game-gem |
|---|---|---|
| Entry point | #[macroquad::main] proc macro |
Plain fn main() + Game::run(state) |
| State management | Global variables | Trait-based GameState |
| Context passing | Global functions (draw_circle(...)) |
Explicit &mut Context parameter |
| Error handling | Panics | Result types |
| Modularity | All-or-nothing | Feature-gated modules |
| Scene management | None built-in | Stack-based SceneManager with transitions |
| Particles | None built-in | ParticleEmitter with shapes, easing, pooling |
| Tweening | None built-in | 30+ easing functions, TweenManager |
| Sprite animation | DIY | AnimationPlayer with state machine & events |
| Collision | DIY | AABB / circle / ray / SpatialHash |
| UI | Separate ui crate, tree-based |
Drop-in immediate-mode button(ctx, ...) |
| Audio | Basic | Spatial 2D audio, music/SFX channels, fades |
| Cameras | Single global camera | Multi-camera, follow, shake, split-screen |
| Binary size | Larger (everything linked) | Smaller (only pay for what you use) |
game-gem doesn't replace macroquad for every use case — if you want a 50-line
game jam with zero ceremony, macroquad is hard to beat. game-gem is for projects
that have outgrown globals and want a real architecture without leaving the
miniquad ecosystem.
┌─────────────────────────────────────────────────────────┐
│ Your Game (GameState) │
└──────────────────────────┬──────────────────────────────┘
│ &mut Context
┌──────────────────────────▼──────────────────────────────┐
│ Context │
│ ┌─────────┐ ┌───────┐ ┌──────────┐ ┌────────┐ ┌─────┐ │
│ │ Time │ │ Input │ │ Graphics │ │ Camera │ │ ... │ │
│ └─────────┘ └───────┘ └──────────┘ └────────┘ └─────┘ │
│ ┌────────┐ ┌────────┐ ┌──────────┐ ┌────────┐ ┌─────┐ │
│ │ Audio │ │ UI │ │ Particles│ │ Tweens │ │ ... │ │
│ └────────┘ └────────┘ └──────────┘ └────────┘ └─────┘ │
└──────────────────────────┬──────────────────────────────┘
│ Draw commands / events
┌──────────────────────────▼──────────────────────────────┐
│ Game loop (fixed + variable) │
└──────────────────────────┬──────────────────────────────┘
│
┌──────────────────────────▼──────────────────────────────┐
│ miniquad (rendering + windowing + GL) │
└─────────────────────────────────────────────────────────┘
The engine runs a standard fixed_update → update → render loop with a
configurable fixed timestep. Each frame:
Time::tick()advances clock, FPS, and the fixed-step accumulator.- Per-frame input deltas (pressed-this-frame, scroll, mouse delta) are cleared.
GameState::fixed_update()runs zero or more times at the fixed timestep.GameState::update()runs once with variabledt(skipped while paused).- Engine subsystems (
audio,particles,tweens,ui,camera) are updated. GameState::render()issues draw commands intoGraphicsContext.- Commands are flushed and submitted to the GPU.
- If
ctx.is_quitting(), the loop exits andon_exit()is called.
| Platform | Status |
|---|---|
| Linux (X11/Wayland) | ✅ Supported (via miniquad) |
| macOS | ✅ Supported (via miniquad) |
| Windows | ✅ Supported (via miniquad) |
| Web (wasm32) | ✅ Supported (via miniquad + rodio web audio) |
| Android | 🔧 Planned (miniquad supports it, engine plumbing WIP) |
| iOS | 🔧 Planned |
game-gem is actively developed. The public API surface (GameState, Context,
Game builder, all feature-gated modules) is stable in shape, but the underlying
miniquad rendering bridge is still being filled in — the GraphicsContext
currently records draw commands and the GPU submission path is being completed
upstream. If you want to build on game-gem today, expect minor API churn on
the rendering side; the higher-level systems (scenes, particles, tweens, audio,
collision, input, UI) are stable.
- Core engine:
Game,Context,GameState,WindowConfig - Math (via
glam),Color,Time,Input,Camera - Scene management with transitions
- Particle system with emitters
- Tweening with 30+ easing functions
- Sprite-sheet animation
- Collision detection & spatial hashing
- Immediate-mode UI toolkit
- Spatial audio manager
- Full
miniquadrendering bridge (batched draw calls, textures, fonts) - Asset hot-reload on debug builds
- Android & iOS support
- Multi-window support
- Custom shader pipelines
- Scene Inspector / debug overlays (
debugfeature)
Contributions are welcome — bug reports, feature requests, docs, and PRs.
git clone https://github.com/himanshmewada/game-gem
cd game-gem
cargo build
cargo test
cargo run --example basics- Follow the existing code style — no proc macros, explicit
&mut Context, no panics in public APIs. - New modules should be feature-gated behind a flag in
Cargo.tomland re-exported conditionally fromprelude.rs. - Document every public item with
///doc comments and at least one# Examplesblock where reasonable. - Run
cargo fmtandcargo clippy -- -D warningsbefore submitting.
Licensed under the MIT License — see LICENSE for the full text.
Copyright © 2026 Himansh Mewada.
miniquad— the cross-platform rendering & windowing foundation.glam— fast, ergonomic math types.rodio— cross-platform audio playback.macroquad— the inspiration for this project's ergonomics goals.
Report Bug · Request Feature · Crates.io · Docs
Made with Rust and care.