Introduction
Ebitengine (formerly Ebiten), by Hajime Hoshi, is the answer to "what would a minimal game engine in Go look like?" The entire public API fits in a handful of functions: an Update() and Draw() method, sprite drawing, input, audio. That's it. Despite the simplicity, commercial games ship on Steam, Switch, iOS, and Android using Ebitengine.
With over 13,000 GitHub stars, Ebitengine is the most popular Go-based game engine. It compiles to native, WASM, iOS, Android, and Nintendo Switch (with the official porting toolkit). The "Odyssey" Switch game and many itch.io hits are made with it.
What Ebitengine Does
Ebitengine gives you a game loop via ebiten.Game interface (Update, Draw, Layout), image/sprite rendering, input (keyboard, mouse, gamepad, touch), audio (WAV/OGG/MP3), shaders (Kage shader language), and helpers for tilemaps + text. The engine doesn't impose scene graphs or ECS — you structure your game however you want.
Architecture Overview
Your Go code
|
[ebiten.Game interface]
Update() error — game logic, 60Hz
Draw(*Image) — render each frame
Layout(ow, oh) — logical vs screen size
|
[Ebitengine runtime]
input subsystem (keyboard, mouse, gamepad, touch)
audio player (OggVorbis, MP3, WAV)
image API (Image, DrawImage, shader hooks)
|
[Kage shaders]
WGSL-like DSL compiled to GLSL/MSL/WebGPU
|
[Backends]
OpenGL / Metal / DirectX / WebGPU / WebGL
Desktop (GLFW), Mobile (NDK / iOS frameworks), WASM (canvas + WebGL)
|
[Deploy]
native binary, WASM bundle, APK/AAB, IPA, Switch (via toolkit)Self-Hosting & Configuration
// Sprite example
type Game struct {
img *ebiten.Image
x, y float64
}
func (g *Game) Update() error {
if ebiten.IsKeyPressed(ebiten.KeyArrowRight) { g.x += 2 }
if ebiten.IsKeyPressed(ebiten.KeyArrowLeft) { g.x -= 2 }
return nil
}
func (g *Game) Draw(screen *ebiten.Image) {
op := &ebiten.DrawImageOptions{}
op.GeoM.Translate(g.x, g.y)
screen.DrawImage(g.img, op)
}
func main() {
img, _, err := ebitenutil.NewImageFromFile("assets/player.png")
if err != nil { log.Fatal(err) }
g := &Game{img: img, x: 50, y: 50}
ebiten.SetWindowSize(800, 600)
ebiten.RunGame(g)
}# WebAssembly build (itch.io, personal site)
GOOS=js GOARCH=wasm go build -o game.wasm .
# Grab wasm_exec.js from Go toolchain
cp "$(go env GOROOT)/misc/wasm/wasm_exec.js" .
# Host via any static server
# iOS / Android (requires gomobile + native tooling)
gomobile bind -target=ios ./...
# Switch port via official Ebitengine Switch SDKKey Features
- Tiny API — 3-method game interface, discoverable in minutes
- Cross-platform — desktop + WASM + iOS + Android + Switch
- Kage shader language — single shader source, multiple backends
- Input everywhere — keyboard / mouse / touch / gamepad abstracted uniformly
- Audio support — WAV, OGG, MP3 via native codec libraries
- Text rendering — bitmap + vector font via golang.org/x/image/font
- No GC spikes — sensible Image caching, careful allocations
- Commercial-friendly — Apache-2.0, no royalties
Comparison with Similar Tools
| Feature | Ebitengine | raylib (Go bindings) | Godot | Bevy | pixel (pure Go) |
|---|---|---|---|---|---|
| Language | Go (native) | Go via C binding | GDScript / C# | Rust | Go (native) |
| Learning curve | Very shallow | Shallow | Moderate | Steeper | Shallow |
| Dimensions | 2D | 2D + 3D | 2D + 3D | 2D + 3D | 2D |
| WASM | Yes | Yes (via emsdk) | Yes | Yes | Partial |
| Switch support | Official toolkit | Via C port | Via 3rd party | Via 3rd party | No |
| Best For | Go devs writing 2D games | Go devs wanting raylib API | Full-feature engine | Rust devs | Pure-Go 2D |
FAQ
Q: Ebitengine vs raylib-go? A: Both are simple. Ebitengine is pure Go (no CGO, easier cross-compile). raylib-go binds to C raylib. Ebitengine fits idiomatic Go projects better; raylib-go if you want raylib's exact API.
Q: Can I make commercial games? A: Yes — Apache-2.0 license, no royalties. Examples: Odyssey (Steam + Switch), A Short Hike (partial), various itch.io hits.
Q: Is it fast enough? A: Yes for most 2D games. Large tilemaps, hundreds of sprites, custom shaders — all run at 60 FPS on modest hardware. For bullet-hell games with 10k particles, use custom draw batching.
Q: Switch support? A: There's an official Ebitengine Nintendo Switch SDK (requires Nintendo dev agreement). Many commercial Ebitengine games ship on Switch.
Sources
- GitHub: https://github.com/hajimehoshi/ebiten
- Website: https://ebitengine.org
- Author: Hajime Hoshi
- License: Apache-2.0