Library / SDK
17cupsofcoffee/tetra avatar
17cupsofcoffee/tetra

Tetra, a Rust 2D framework that stopped adding features

🎮 A simple 2D game framework written in Rust

1,010 stars64 forksRustMIT

At a glance

What is it?
Tetra is a small 2D game framework for Rust built on SDL and OpenGL 3.2+, with an XNA-style API, batched rendering and a fixed-step loop. Its own README calls it passively maintained since January 2022, which is the first thing to weigh before you adopt it.
Who is it for?
Tetra suits developers who want XNA-shaped 2D scaffolding in Rust and accept a project its own author labels passively maintained since January 2022, with the last push on 2026-07-22 and the newest release 0.9.1 from 2025-09-29. It is the wrong choice for a team that needs 3D, a growing feature set or a steady stream of fixes.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 94 days ago.
What is it written in?
Mainly Rust, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

An XNA-shaped API for people who already know the XNA-shaped API

Tetra is a 2D game framework written in Rust, and its API borrows from XNA and MonoGame rather than from the C++ engines most people picture when they hear the word engine. That borrowing is the entire point for a certain kind of developer. Someone arriving from C# tooling, or from a tutorial series that taught game loops in XNA terms, finds the vocabulary familiar instead of alien, and the examples/ directory reads like a course rather than a specification.

The scope is deliberately small. The README calls it a simple framework, and the feature list is short enough to read in a minute: draw call batching by default, input through polling or events, gamepad support, a deterministic game loop, plus font rendering, cameras and screen scaling as built-in building blocks. There is no 3D pipeline, no scene graph, no asset editor in this crate. A project that needs skeletal animation authoring, a level editor or a physics solver will not find them here.

So the audience is narrow and worth naming precisely: developers writing 2D games in Rust who want a window, a loop and a renderer without assembling those pieces by hand, and who are comfortable with the fact that the surrounding ecosystem moves on.

SDL for events, OpenGL 3.2+ for the pixels, and a crate list you inherit

The architecture is two external layers with a thin Rust layer between them. The README states it plainly: it uses SDL for event handling and OpenGL 3.2+ for rendering. Cargo.toml shows how that maps in practice, and the dependency list is the real specification of what Tetra is. sdl3 0.18.4 handles the platform layer, glow 0.17.0 is the OpenGL binding, lyon_tessellation 1.0.7 deals with geometry, vek 0.17.0 provides the math types, and bytemuck and half cover the byte-level plumbing that GPU buffers need.

Rendering is 2D and batched by default, which is the feature the README leads with for graphics. The example files back that up: mesh.rs, instancing.rs, scissor.rs, stencil.rs, nineslice.rs and shaders.rs. That list defines what a Tetra program can actually draw, and the presence of a stencil example also tells you the renderer is not strictly a sprite blitter. Textures decode through the image crate at version 0.25.0, and the feature flags in Cargo.toml decide which formats are compiled in.

The practical consequence is that a Tetra dependency is really a dozen dependencies. Each one has its own release cadence, so upgrading Tetra is several upgrades at once, and a break in a transitive crate shows up as a break in your game.

Adding the dependency and getting a window up

Installation is a Cargo dependency plus one native prerequisite. Add the crate to your Cargo.toml:

toml
tetra = "0.9"

The README is explicit that this is not enough on its own: you also need to install the SDL native libraries, and it points to docs/installation.md for the full details. That page is where the platform-specific work lives, and it is the step most likely to cost you an afternoon, since the native libraries are not something Cargo can fetch for you.

Once the dependency resolves, the smallest useful program implements the State trait and hands a state to the context. This is the README's own example, and it is worth reading line by line because the entry point is unusual: you build a Context with ContextBuilder, then call run on it and supply your state.

rust
use tetra::graphics::{self, Color};
use tetra::{Context, ContextBuilder, State};

struct GameState;

impl State for GameState {
    fn draw(&mut self, ctx: &mut Context) -> tetra::Result {
        // Cornflower blue, as is tradition
        graphics::clear(ctx, Color::rgb(0.392, 0.584, 0.929));
        Ok(())
    }
}

fn main() -> tetra::Result {
    ContextBuilder::new("Hello, world!", 1280, 720)
        .build()?
        .run(|_| Ok(GameState))
}

A title, a width and a height are the only required inputs, and the draw method returns a tetra::Result so failures travel through the normal error path rather than panicking.

The example ships with the repository, so you can see it run instead of transcribing it:

bash
cargo run --example hello_world

The examples/ directory is the best available map of the API: animation.rs, animation_controller.rs, audio.rs, bunnymark.rs, camera.rs, canvas.rs, ecs.rs, error_handling.rs, events.rs, file_drop.rs, gamepad.rs, instancing.rs, interpolation.rs, keyboard.rs, mesh.rs, mouse.rs, nineslice.rs, scaling.rs, scissor.rs, shaders.rs, shapes.rs, stencil.rs and tetras.rs, plus a resources/ folder.

The fixed-step loop and the choice between polling and events

Tetra's timing model is the one decision that shapes every game written with it. The README lists a deterministic game loop by default, and credits the Fix Your Timestep approach for it. In practice that means the simulation advances in fixed steps rather than in whatever chunk of wall clock time the last frame happened to take, and interpolation is available to smooth the rendering between steps. examples/interpolation.rs exists precisely to demonstrate that separation.

Input is deliberately flexible. The framework supports polling or event based input, and examples/keyboard.rs, examples/mouse.rs and examples/gamepad.rs cover the three obvious devices, while examples/events.rs shows the event stream and examples/file_drop.rs shows the window receiving files from the desktop. A polling style suits a game with a fixed simulation cadence, and an event style suits a title with menus and irregular state changes, and the framework lets you pick per system rather than committing the whole project.

What is not in the crate is equally relevant. There is no physics integration, no collision query, no animation curve system beyond what examples/animation.rs and examples/animation_controller.rs demonstrate, and no ECS, although examples/ecs.rs and the hecs dev-dependency show that people prototype one against the framework. The line between what the framework provides and what your game supplies is drawn much closer than in a larger engine.

Feature flags decide which codecs and APIs you compile in

Cargo.toml gives Tetra a full set of cargo features, and they are the mechanism that lets you adjust the framework's weight rather than editing it. The default set is long: audio, audio_mp3, audio_vorbis, audio_wav, font_ttf, texture_png, texture_jpeg, texture_gif and texture_bmp. That default is deliberately generous, so a quick prototype pulls in decoders it will never use.

The audio flag is the interesting one because the comment next to it says the feature enables the tetra::audio API and can be disabled if you want to use a different audio API in your game, naming FMod and WWise as examples. Turning off audio removes the rodio dependency entirely, which is how you keep a project that already has a licensed audio solution from linking two of them. The rest of the codec flags, including audio_flac, texture_ico, texture_tiff, texture_webp and texture_pnm, let you compile only the formats your assets actually use.

Font handling follows the same pattern with font_ttf, which pulls in ab_glyph for TrueType rendering. The MIT licence declared in Cargo.toml and covered by the LICENSE file applies to the framework itself, and each optional dependency carries its own licence terms that you would need to review separately for anything you ship.

Passively maintained since January 2022, with three releases since 2023

The Status section of the README is the most important paragraph in the project, and it is unusually honest. It describes Tetra as being passively maintained, as of January 2022, states that no new features are planned, and says occasional bugfix updates may still be released from time to time. Pull requests are accepted if they do not have a large maintenance burden, which is a small standing invitation with a clear condition attached.

The release list is consistent with that description. Version 0.8.0 shipped on 2023-03-17, then nothing for more than two years until 0.9.0 on 2025-09-20 and 0.9.1 on 2025-09-29. The repository itself is not archived, and the last push was on 2026-07-22, which is recent enough to show the tree is not abandoned even though the feature work is over. The crate version in Cargo.toml is 0.9.1, matching the newest release tag, and the edition is 2021.

The README also carries a candid warning: it says Tetra is fairly early in development, so you might run into bugs, flaky docs or general weirdness, and it asks readers to open an issue or pull request when they do. Treat a 0.x crate with a single author and a self declared passive status accordingly, and check the CHANGELOG.md in the repository root before relying on a specific fix being present in the version you pull.

The README itself points elsewhere, and that is part of the decision

Tetra's author does not pretend the framework is the best current option in Rust game development. The Status section suggests that if you want a similar framework that is more actively developed, you should try macroquad or GGEZ, and it also points to nova, described as a spiritual successor to this library with a much smaller scope that is still very experimental. That recommendation is the clearest signal in the whole project about how to read the framework: it is finished rather than stalled, and the author would rather you use something else.

The difference in approach between the options matters for an adopter. Between Tetra and the alternatives the README names, the practical difference is maintenance cadence and API lineage, not feature set, since the alternatives are not described in detail there. Within Tetra itself, the difference is more concrete: the audio feature flag lets you drop the built in audio path for FMod or WWise, and the codec flags let you keep the dependency tree small.

Tetra is the wrong tool in a few clear situations. It is wrong if your game is 3D, because the renderer and the feature list are 2D throughout. It is wrong if you need a component the crate does not ship, since you will build physics, asset pipelines and editor tooling yourself. It is wrong if your release process depends on frequent upstream fixes, because the project is explicitly not taking new features and only occasionally takes bugfixes. It is also wrong if shipping a build on several platforms has to be frictionless, since every target needs the SDL native libraries installed before the crate will link.

Editorial conclusion

Tetra suits developers who want XNA-shaped 2D scaffolding in Rust and accept a project its own author labels passively maintained since January 2022, with the last push on 2026-07-22 and the newest release 0.9.1 from 2025-09-29. It is the wrong choice for a team that needs 3D, a growing feature set or a steady stream of fixes. Before committing, check that the SDL native libraries install cleanly on your target platforms, confirm your texture and audio formats are covered by the Cargo feature flags, and read the current CHANGELOG.md to see whether the bugfixes you would depend on have actually landed.

Frequently asked questions

How do I add Tetra to a Rust project and get a window on screen?

Add tetra = "0.9" to your Cargo.toml and install the SDL native libraries, which the README points to docs/installation.md for. Then run cargo run --example hello_world to see the example window without writing any code of your own.

Is Tetra still being actively developed?

No. The README describes the project as passively maintained as of January 2022, with no new features planned and only occasional bugfix updates. The repository is not archived and the last push was on 2026-07-22, and the newest release is 0.9.1 from 2025-09-29.

Can I use a different audio engine with Tetra?

Yes. The audio feature in Cargo.toml enables the tetra::audio API and can be disabled if you want to use a different audio API in your game, with FMod and WWise given as examples. Disabling it also drops the optional rodio dependency.

What licence is Tetra released under?

Tetra is released under the MIT licence, as declared in Cargo.toml and covered by the LICENSE file in the repository root. Dependencies such as rodio, image and ab_glyph carry their own separate terms.

Official sources

  1. 17cupsofcoffee/tetra on GitHub
  2. Issues
  3. License: MIT
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/17cupsofcoffee-tetra.svg)](https://hysenlabs.com/projects/17cupsofcoffee-tetra)

Was this useful?