# MonoGame

MonoGame doesn't officially support web builds. For the browser, use KNI — the community-maintained MonoGame-compatible fork with a Blazor WebAssembly target.

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

<GithubLink href="https://github.com/wvdsh/examples/tree/main/example-kni" />

MonoGame itself does not officially support web or WebAssembly targets ([issue #8102](https://github.com/MonoGame/MonoGame/issues/8102), closed as "not planned"). To ship a MonoGame-style game to the browser, the community path is **KNI** — [nkast/kni](https://github.com/kniEngine/kni), a MonoGame-compatible fork with a `BlazorGL` web target. Your `Game` subclass, `SpriteBatch`, `GraphicsDeviceManager`, and input APIs work unchanged — you swap `MonoGame.Framework.*` package references for `nkast.Xna.Framework.*` and publish as a Blazor WebAssembly project.

KNI is actively maintained and used in the community by projects like SadConsole, FlatRedBall, and Apos.Gui.

## Prerequisites

- [.NET 8 SDK](https://dotnet.microsoft.com/download/dotnet/8.0) (.NET 9 works too)
- The `wasm-tools` workload if you want AOT compilation:
  ```bash
  dotnet workload install wasm-tools
  ```

## Build for web

Scaffold a new project with nkast's template:

```bash
dotnet new install nkast.Kni.Templates
dotnet new kni-blazor-gl -n MyGame
```

Then publish:

```bash
dotnet publish -c Release
```

The Blazor output lands in `bin/Release/net8.0/publish/wwwroot/`. Point `upload_dir` at that directory.

## SDK integration

Wavedash injects `Wavedash` into the page before your game loads. Call it from C# via `IJSRuntime`. A small `wavedash-bridge.js` exposes thin wrappers on `window`, and Blazor invokes them:

```javascript
// wwwroot/wavedash-bridge.js
(function () {
  const Wavedash = window.Wavedash;

  window.wavedashInit = function () {
    Wavedash.init({ debug: true });
  };

  window.wavedashUpdateLoadProgress = function (value) {
    Wavedash.updateLoadProgressZeroToOne(Math.max(0, Math.min(1, Number(value) || 0)));
  };
})();
```

Reference it from `wwwroot/index.html`:

```html
<script src="wavedash-bridge.js"></script>
```

Then call it from your Blazor component (typically `Pages/Index.razor.cs`) once the page renders:

```csharp
protected override async void OnAfterRender(bool firstRender)
{
    base.OnAfterRender(firstRender);
    if (!firstRender) return;

    await JsRuntime.InvokeVoidAsync("wavedashUpdateLoadProgress", 1.0);
    await JsRuntime.InvokeVoidAsync("wavedashInit");

    // hand control to the KNI render loop
    await JsRuntime.InvokeAsync<object>("initRenderJS", DotNetObjectReference.Create(this));
}
```

To expose more SDK methods, add a handler to `wavedash-bridge.js` and invoke it with `JsRuntime.InvokeVoidAsync("yourMethod", args...)`.

## Load progress

KNI's Blazor template boots the game from `TickDotNet` inside the Razor page. By the time `OnAfterRender(firstRender: true)` fires, the runtime is live and the canvas is ready, so reporting `1.0` there is the simplest "first playable" signal. If you want intermediate progress, hook `Blazor.start({ loadBootResource })` in `index.html` to observe resource downloads and call `wavedashUpdateLoadProgress()` as each one resolves.

## wavedash.toml

```toml
game_id = "YOUR_GAME_ID_HERE"
upload_dir = "./bin/Release/net8.0/publish/wwwroot"
entrypoint = "index.html"
```

## Notes

- **AOT compilation** dramatically speeds up startup. Add `<RunAOTCompilation>true</RunAOTCompilation>` and `<WasmStripILAfterAOT>false</WasmStripILAfterAOT>` to your `.csproj`. First build takes several minutes; subsequent builds are fast. Leaving strip on causes MONO interpreter assertions at runtime.
- **Routing inside iframes**: if `wavedash dev` serves your game from a subpath, add `@page "/{*path:nonfile}"` to `Pages/Index.razor` and a `[Parameter] public string Path { get; set; }` to absorb the matched route.
- **Content Pipeline** (`.mgcb` files) requires Windows or Wine on macOS. For simple examples, skip it and use `Texture2D.SetData` on a 1×1 pixel at runtime.

## Other options

- **FNA**, the other XNA reimplementation, has a community-driven Emscripten path via [FNA-WASM-Build](https://github.com/wattsyart/fna-wasm) — used by [Celeste-WASM](https://github.com/MercuryWorkshop/celeste-wasm). Separate ecosystem from MonoGame proper.
- **NativeAOT-LLVM** is a theoretical alternative but only supported on Windows x64 and Linux x64 build hosts, and is not what MonoGame devs use in practice.
