# Ebiten

Ship Ebiten games to the web with Go's built-in js/wasm target.

Source: https://docs.wavedash.com/engines/ebiten

<GithubLink href="https://github.com/wvdsh/examples/tree/main/example-ebiten" />
<PlaytestLink href="https://wavedash.com/playtest/ebiten-example/1f1362d1-dec1-481a-b182-9c04a4564f00" />

[Ebiten](https://ebitengine.org/) runs on any platform Go runs on, including the browser via `GOOS=js GOARCH=wasm`. Ebiten handles canvas creation and the game loop, so you just write `Update`/`Draw`/`Layout` and call `ebiten.RunGame`.

## Setup

The Go toolchain includes the `js/wasm` target out of the box. No extra install.

```bash
GOOS=js GOARCH=wasm go build -ldflags="-s -w" -o build/game.wasm .
```

You also need the `wasm_exec.js` shim that ships with your Go install:

```bash
cp "$(go env GOROOT)/lib/wasm/wasm_exec.js" build/wasm_exec.js
# (older Go versions keep it under misc/wasm/)
```

## SDK integration

Go accesses browser globals through `syscall/js`. Ebiten's game loop is synchronous from Go's perspective — call the SDK just before `RunGame`:

<Urgent>
**Calling `Wavedash.init()` is required.** Your game stays hidden behind the Wavedash loading screen until you do. Call it once your game is ready to play.
</Urgent>

```go
package main

import (
    "syscall/js"

    "github.com/hajimehoshi/ebiten/v2"
)

type Game struct{}

func (g *Game) Update() error                            { return nil }
func (g *Game) Draw(screen *ebiten.Image)                {}
func (g *Game) Layout(_, _ int) (int, int)               { return 900, 600 }

func main() {
    sdk := js.Global().Get("Wavedash")
    sdk.Call("updateLoadProgressZeroToOne", 1)
    sdk.Call("init")

    if err := ebiten.RunGame(&Game{}); err != nil {
        panic(err)
    }
}
```

Call `updateLoadProgressZeroToOne(...)` with intermediate values during async asset loading (embedded files, HTTP fetches, etc.). `init()` automatically signals load completion, so call it last.

## HTML shell

A minimal shell that loads `wasm_exec.js`, instantiates the module, and hands off to Ebiten:

```html
<!doctype html>
<html>
  <head>
    <meta charset="utf-8" />
    <style>
      html, body { margin: 0; width: 100%; height: 100%; overflow: hidden; background: #000; }
      canvas { display: block; width: 100%; height: 100%; outline: none; }
    </style>
  </head>
  <body>
    <script src="./wasm_exec.js"></script>
    <script type="module">
      const sdk = window.WavedashJS = await window.WavedashJS;
      sdk.updateLoadProgressZeroToOne(0);

      const response = await fetch("./game.wasm");
      const total = +response.headers.get("Content-Length") || 0;
      let bytes;
      if (!total || !response.body) {
        bytes = new Uint8Array(await response.arrayBuffer());
      } else {
        const reader = response.body.getReader();
        const chunks = [];
        let received = 0;
        while (true) {
          const { done, value } = await reader.read();
          if (done) break;
          chunks.push(value);
          received += value.length;
          sdk.updateLoadProgressZeroToOne((received / total) * 0.95);
        }
        bytes = new Uint8Array(received);
        let pos = 0;
        for (const c of chunks) { bytes.set(c, pos); pos += c.length; }
      }
      sdk.updateLoadProgressZeroToOne(0.95);

      const go = new Go();
      const { instance } = await WebAssembly.instantiate(bytes, go.importObject);
      go.run(instance);
    </script>
  </body>
</html>
```

## Build script

```bash
#!/usr/bin/env sh
set -eu
mkdir -p build

GOOS=js GOARCH=wasm go build -ldflags="-s -w" -o build/game.wasm .

if   [ -f "$(go env GOROOT)/lib/wasm/wasm_exec.js" ];  then cp "$(go env GOROOT)/lib/wasm/wasm_exec.js"  build/wasm_exec.js
elif [ -f "$(go env GOROOT)/misc/wasm/wasm_exec.js" ]; then cp "$(go env GOROOT)/misc/wasm/wasm_exec.js" build/wasm_exec.js
fi

cp web/index.html build/index.html
```

## wavedash.toml

```toml
game_id = "YOUR_GAME_ID_HERE"
upload_dir = "./build"
```

## Other SDK features

Once initialized, `Wavedash` exposes leaderboards, achievements, stats, and user data. Call them the same way:

```go
sdk.Call("setAchievement", "first_win", true)
user := sdk.Call("getUser")
```

See the [SDK reference](/sdk/overview) for the full API.
