Library / SDK
ebitenui/ebitenui avatar
ebitenui/ebitenui

Ebiten UI: a retained mode widget layer for Ebitengine games

User interface engine and widget library for Ebitengine

945 stars77 forksGoMIT

At a glance

What is it?
Ebiten UI is a Go widget library that adds buttons, lists and combo boxes on top of Ebitengine using a retained mode model, with fully replaceable graphics. It is aimed at Go developers shipping game interfaces, and it leaves rendering, layout and input handling of your own game to you.
Who is it for?
Adopt Ebiten UI when your Go game needs a menu, settings panel or inventory list and you would rather compose widgets than draw them yourself, and check the widget set in the _examples/ folder before committing. Skip it if you need a heavyweight application toolkit, if you are on a language other than Go, or if you want a UI that runs outside an Ebitengine game loop, because the package is built on Ebitengine drawing calls.
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 65 days ago.
What is it written in?
Mainly Go, according to GitHub's language statistics.

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

Editorial analysis

Ebiten UI is an extension to Ebitengine, not a fork of it

Ebiten UI is described as a user interface engine and widget library for Ebitengine, and it is careful about its own boundaries. The documentation carries a note that the library is separate from Ebitengine itself, and that questions or suggestions should go to the linked Discord server rather than to the engine project. That is a small administrative point with real consequences: you add a module to your project, you do not patch a rendering engine, and the two can move on their own schedules.

The problem it solves is specific. Ebitengine is a 2D game engine for Go, and drawing a menu means drawing a menu. There is no built-in widget layer, so a developer who wants buttons, lists and combo boxes ends up hand-rolling rectangles, hover states, text layout and input handling for every project. Ebiten UI moves that work into a reusable package, and it does so with the retained mode model, which means the widget tree exists as state that you update rather than a drawing routine that you call every frame.

The audience is Go developers building games and game-like tools with Ebitengine, and the project's own list of users shows that shape: Roboden, BANKWAVE, Networked Game, Sinecord, Cavebots and NebuLeet. The graphics are described as fully customizable, so the intent is that the library supplies behaviour while your art supplies appearance.

The repository is organised around widgets, images, input and themes

Reading the top level of the repository tells you how the library is put together. There is a widget directory, an image directory, an input directory, an event directory, an internal directory, a themes directory and a utilities directory, alongside ui.go and doc.go at the root. That division is the architecture in miniature: widgets are behaviour, images are the drawable assets a widget renders, input is captured and dispatched, events carry user actions, and themes supply the default look.

Because images are a separate layer from widgets, replacing the visuals does not require rewriting the widget code. A button is a widget that knows about its state, and the rectangle, border or sprite it draws comes from the image layer. The documentation makes the promise that all graphics used by Ebiten UI can be fully customized so you can make the interface your own, and the presence of a themes directory backs that up, since a theme is a bundle of images plus the settings that decide which one is used.

The module path is github.com/ebitenui/ebitenui, and the dependency list is short. The go.mod file requires github.com/hajimehoshi/ebiten/v2 at version v2.8.6, plus a small number of direct dependencies including golang.org/x/exp. Most other entries in that file are indirect, pulled in through Ebitengine and its own dependencies, such as golang.org/x/image, golang.org/x/text and the mobile and gomobile tooling.

Go version mismatch: the docs say 1.19, go.mod says 1.23.0

Here is a detail that will bite you on a fresh machine. The quick start text says Ebiten UI is written in Go 1.19, and links to go.dev. The go.mod file in the repository declares a different floor.

go
module github.com/ebitenui/ebitenui

go 1.23.0

require (
	github.com/hajimehoshi/ebiten/v2 v2.8.6
	github.com/matryer/is v1.4.1
	github.com/stretchr/testify v1.10.0
	golang.org/x/image v0.25.0 // indirect
)

The module directive is the one the toolchain enforces. If your CI image ships Go 1.19 or 1.20, the build will refuse to proceed regardless of what the prose says, and the fix is a newer toolchain rather than a patched dependency. The same file also records the exact Ebitengine version the library is developed against, v2.8.6, which is a useful pin for anyone trying to reproduce a build that works.

Two other dependency lines are worth noticing for licensing and packaging reasons. golang.org/x/exp is a direct requirement rather than an indirect one, and the module pulls in golang.design/x/clipboard and gopkg.in/yaml.v3 as indirect dependencies through the Ebitengine graph. Nothing here is unusual for a Go UI library, but the module cache is where your build picks up code you did not write.

Running the demo from the _examples folder with go run

The examples are the intended first contact with the library, and they live in the _examples/ folder. They can be run from the root directory of the project, which means you can look at working code before you write any of your own.

bash
go run github.com/ebitenui/ebitenui/_examples/demo@latest
go run github.com/ebitenui/ebitenui/_examples/widget_demos/<folder_name>@latest

The first command starts the complete demo, the second runs a single widget demo from a subfolder you name. The @latest suffix tells the Go tool to resolve the example module at its newest published version rather than from your working tree, so you are running the same code a user would get, which makes it a good check before you pin a version.

The examples can also be exercised in a browser, which is a fast way to see widget behaviour without a desktop build. The documented commands use wasmserve and open a local port.

bash
go run github.com/hajimehoshi/wasmserve@latest -http=:6262 ./_examples/demo
go run github.com/hajimehoshi/wasmserve@latest -http=:6262 ./_examples/widget_demos/<folder_name>

You then open http://localhost:6262. The port is fixed in the documented command, so if something else on your machine already listens on 6262 you will need to stop it or change the port yourself, since the documentation does not describe any other configuration.

Retained mode buys you state handling but costs you direct rendering control

The retained mode model is the central design decision, and it has consequences in both directions. In a retained mode library, a widget is an object that holds its own state, updates when something changes, and is drawn by the library during the render pass. Buttons know whether they are hovered, pressed or disabled, and they report activation as an event rather than by changing a colour directly.

The cost is that you give up the ability to paint the interface arbitrarily. Anything you want on screen has to go through a widget, an image or the theme that configures them. For a game menu that is a good trade, because the fiddly parts, focus handling, hover transitions and text placement are exactly the parts people get wrong. For a settings screen with unusual custom drawing, a flow layout, or an effect that animates freely per frame, the retained tree can feel like a straitjacket, and you end up fighting the widget system instead of using it.

The split into widget, image, theme and event packages reflects this. Behaviour is delegated to the library, appearance to your assets, and integration to events that your game code reacts to. Whether that division matches your project depends on how much of your interface is standard and how much of it is a piece of art that has to move in a specific way.

Maintenance is a single maintainer with a MIT licence

Ebiten UI is licensed under the MIT licence, which is a short permissive grant with no requirement that derived work be published, though the licence text does require the copyright notice to be kept. Reading the LICENSE file for the exact terms is still the right step before you ship a game, and none of this is legal advice. For a game UI library that you embed in a commercial title, MIT is about as frictionless as licences get.

On maintenance, the project names its people rather than an organisation. The project is currently maintained by Mark Carpenter, and it was originally written by Maik Schreiber. That continuity is visible in the commit history, since the last push was on 2026-08-19, and the repository is not archived.

The release tags show a steady 0.x line rather than a 1.0. Version 0.7.1 landed on 2025-08-20, 0.7.2 on 2025-09-24, and 0.7.3 on 2026-03-16. The tag notes describe them as minor bug fixes, additional bug fixes and enhancements from the community, which is an honest signal that you are consuming a 0.x API. In Go, a 0.x module carries no compatibility promise, so pin a specific version in go.mod and read the release notes when you upgrade, particularly since the widget and theme APIs are the parts most likely to move. The project also maintains a Discord and a subreddit for support, and a separate Discord is the channel for questions about the library itself.

Editorial conclusion

Adopt Ebiten UI when your Go game needs a menu, settings panel or inventory list and you would rather compose widgets than draw them yourself, and check the widget set in the _examples/ folder before committing. Skip it if you need a heavyweight application toolkit, if you are on a language other than Go, or if you want a UI that runs outside an Ebitengine game loop, because the package is built on Ebitengine drawing calls. First verify that your toolchain matches the go 1.23.0 directive in go.mod, that Ebitengine v2.8.6 resolves in your module graph, and that the theme images under themes/ can be replaced with your own art without fighting the layout.

Frequently asked questions

What is the difference between Ebiten UI and Ebitengine?

Ebitengine is the game engine, and Ebiten UI is a separate extension that adds a user interface layer with widgets such as buttons, lists and combo boxes. The documentation explicitly notes that the library is separate from Ebitengine.

How do I run the Ebiten UI examples?

From the root of the project, run go run github.com/ebitenui/ebitenui/_examples/demo@latest for the complete demo, or point the same command at a folder under _examples/widget_demos for a single widget. The examples can also be served to a browser with wasmserve on port 6262.

What Go version does Ebiten UI need?

The quick start text says Go 1.19, but the go.mod file declares go 1.23.0, and the module directive is what the toolchain enforces. The same file requires Ebitengine v2.8.6.

Can I replace the default look of Ebiten UI widgets?

Yes. The documentation states that all graphics used by Ebiten UI can be fully customized, and the repository separates images, themes and widgets into their own directories so visuals can be swapped without rewriting widget code.

Is Ebiten UI API stable?

The project is on a 0.x line, with tags 0.7.1, 0.7.2 and 0.7.3 released between 2025-08-20 and 2026-03-16, described as bug fixes and community enhancements. Since a 0.x module carries no compatibility promise, pin a version and check the release notes when upgrading.

Official sources

  1. ebitenui/ebitenui on GitHub
  2. License: MIT
  3. Project website
  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/ebitenui-ebitenui.svg)](https://hysenlabs.com/projects/ebitenui-ebitenui)

Was this useful?