Skip to content


Created: 2021-01-02 09:10:03 -0800 Modified: 2021-01-02 12:09:28 -0800

(note: I don’t recommend using Ebiten - it’s too barebones)

Section titled (note: I don’t recommend using Ebiten - it’s too barebones)
  • Overview: Ebiten is for game programming. It provides very little in the way of game-engine functionality that you may expect, and for that reason, I don’t recommend it. For example, it covers rendering, input, and audio, but each of those is relatively limited; in general, most of the techniques that you see in the examples have to be coded by you as opposed to being provided by the game engine.
    • There is no built-in collision detection
    • While there are shaders (reference), the only real effects that the examples show are from CompositeMode blending (reference) or clever techniques (e.g. blurring by rendering the same sprite at different coordinates with low alpha).
    • You can render to images or control individual bytes that make up an image.
    • Polygons are all drawn via drawTriangles.
  • Shaders (reference): Ebiten uses a language called Kage (Ebiten document Kage here).
  • Installation: follow the instructions at this link. It’s basically just “go mod init yourproject” → copy/paste some code → “go run main.go”.
  • Cheat sheet (reference): this has links to a bunch of resources, e.g. ebitenutil, ebiten.Game, etc.
  • General structure: modify the Game struct to have any game-related variables that you want and initialize them in init or main. In main itself, make a new instance of the Game struct and pass it to RunGame. Their camera.go is a pretty good example of this structure.
    • init vs. main: I don’t know why you’d use one over the other for Ebiten.
    • Simple example: here’s a quick example I made that’ll move “Hello world” to the side every frame just to show the structure here:
package main
import (
type Game struct {
x int
func init() {
func (g *Game) Update() error {
g.x += 1
return nil
func (g *Game) Draw(screen *ebiten.Image) {
ebitenutil.DebugPrint(screen, "Hello, World!")
ebitenutil.DebugPrintAt(screen, "Hello, World!", g.x, 100)
func (g *Game) Layout(outsideWidth, outsideHeight int) (screenWidth, screenHeight int) {
return 320, 240
func main() {
g := &Game{
x: 50,
ebiten.SetWindowSize(800, 600)
ebiten.SetWindowTitle("Hello, World!")
if err := ebiten.RunGame(g); err != nil {
  • Quirks
    • Colors are matrices: if you’re trying to set the color of something, you actually have to scale and then translate the color values (example here) since it’s internally represented as a matrix (reference).