# raylib

Compile raylib games to WebAssembly with Emscripten and call the Wavedash SDK from C.

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

<GithubLink href="https://github.com/wvdsh/examples/tree/main/example-raylib" />
<PlaytestLink href="https://wavedash.com/playtest/raylib-example/7e00761d-f594-4b23-b929-085a4ee3f203" />

[raylib](https://www.raylib.com/) compiles to WebAssembly through its official Emscripten backend (`PLATFORM=Web`). You get the same `BeginDrawing` / `EndDrawing` / `IsKeyDown` API in the browser that you use on desktop — just link against a Web-platform build of `libraylib.a`.

## Setup

You need:

- The [Emscripten SDK](https://emscripten.org/docs/getting_started/downloads.html) (activate with `source ./emsdk_env.sh`)
- A Web-platform build of raylib. The example's `build.sh` clones raylib 5.5 and builds `libraylib.a` with `emcmake cmake . -DPLATFORM=Web && emmake make raylib`.

Point the build at your raylib source with `RAYLIB_PATH=/path/to/raylib` if you already have one.

## SDK integration

Wavedash injects `Wavedash` into the page before your Emscripten module loads. Use `EM_JS` to call the SDK from C — same pattern as any Emscripten project:

<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>

```c
#include <raylib.h>
#include <emscripten.h>

EM_JS(void, wavedash_init, (), { Wavedash.init(); });
EM_JS(void, wavedash_progress, (double p), { Wavedash.updateLoadProgressZeroToOne(p); });

static void tick(void) {
    BeginDrawing();
    // ... draw frame ...
    EndDrawing();
}

int main(void) {
    InitWindow(900, 600, "My Game");
    SetTargetFPS(60);

    wavedash_progress(1.0);
    wavedash_init();

    emscripten_set_main_loop(tick, 0, 1);
    return 0;
}
```

Call `wavedash_progress(...)` with intermediate values during async asset loading. `wavedash_init()` automatically signals load completion, so call it last.

## Build script

```bash
#!/usr/bin/env sh
set -eu
RAYLIB_DIR="${RAYLIB_PATH:-$PWD/raylib}"
mkdir -p build

emcc src/main.c -O2 \
  -I"$RAYLIB_DIR/src" \
  "$RAYLIB_DIR/src/raylib/libraylib.a" \
  -DPLATFORM_WEB \
  -s USE_GLFW=3 \
  -s ASYNCIFY \
  -s ALLOW_MEMORY_GROWTH=1 \
  -s MODULARIZE=0 \
  -s ENVIRONMENT=web \
  -s GL_ENABLE_GET_PROC_ADDRESS=1 \
  -o build/game.js

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

`USE_GLFW=3` and `ASYNCIFY` are the core flags raylib needs on Emscripten. Don't add `-s FULL_ES3=1` — raylib's CMake Web build defaults to OpenGL ES 2, and mixing ES3 client-array emulation with an ES2 library leaves the GL context uninitialized at draw time. The `--shell-file` approach also works if you prefer raylib's generated HTML over a custom shell.

## HTML shell

raylib's Emscripten port reads `Module.canvas` during GL context creation, so `Module` has to be set **before** `game.js` starts executing. `window.Wavedash` is installed synchronously by the host before any other script runs, so the EM_JS bridge can call `.init()` directly. Setting `Module` in a module script and then injecting `game.js` dynamically keeps both ordering constraints obvious in one place:

```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>
    <canvas id="canvas" oncontextmenu="event.preventDefault()"></canvas>
    <script>
      window.Module = { canvas: document.getElementById("canvas") };
      const s = document.createElement("script");
      s.src = "./game.js";
      document.body.appendChild(s);
    </script>
  </body>
</html>
```

## wavedash.toml

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

## Other SDK features

Add `EM_JS` wrappers for whatever else you need. `UTF8ToString` converts C strings to JavaScript:

```c
EM_JS(void, wavedash_submit_score, (const char* id, int score), {
  Wavedash.uploadLeaderboardScore(UTF8ToString(id), score, true);
});
```

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