ScriptsApr 15, 2026·3 min read

Ebitengine — A Dead Simple 2D Game Engine for Go

Ebitengine is a simple 2D game library for Go with a tiny API that takes minutes to learn. It compiles to WASM, iOS, Android, Nintendo Switch, and desktop — ideal for game jams and indie titles written in Go.

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() errorgame 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 SDK

Key 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

Discussion

Sign in to join the discussion.
No comments yet. Be the first to share your thoughts.

Related Assets