# Flame

Ship Flame/Flutter games to the web and wire the SDK from Dart.

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

<GithubLink href="https://github.com/wvdsh/examples/tree/main/example-flame" />
<PlaytestLink href="https://wavedash.com/playtest/flame-example/1180f455-cf16-4018-bb09-30f8609a3b81" />

[Flame](https://flame-engine.org/) is a 2D game engine built on top of Flutter. It runs anywhere Flutter runs — including the browser via `flutter build web`, which outputs a static bundle with a JS loader and your Dart code compiled to JavaScript (using CanvasKit for rendering).

<Note>
Flutter has a `--wasm` flag for dart2wasm output, but as of Flutter 3.41 the skwasm assets it loads from Google's CDN are missing for some engine hashes, which breaks the build at runtime. Stick with the default CanvasKit output below until that stabilizes.
</Note>

## Setup

Install [Flutter](https://docs.flutter.dev/get-started/install) (3.22+). `pubspec.yaml` only needs `flame` — `dart:js_interop` is part of the SDK:

```yaml
dependencies:
  flutter:
    sdk: flutter
  flame: ^1.18.0
```

## Build for web

```bash
flutter pub get
flutter build web --release --no-web-resources-cdn
```

The output lands in `build/web/` with `index.html`, `flutter_bootstrap.js`, your compiled app, and a self-contained `canvaskit/` directory (~30 MB). Point `upload_dir` at `build/web/`.

<Note>
`--no-web-resources-cdn` tells Flutter to bundle CanvasKit with the build instead of fetching it from `gstatic.com` at runtime. The default CDN fetch is faster to ship but has had gaps on some Flutter engine hashes (`canvaskit.js` / `skwasm.js` 404s), so self-hosting is the safer default for production.
</Note>

## SDK integration

Flutter for web compiles Dart to JavaScript. Use `dart:js_interop` and the `@JS` annotation to bind straight to the Wavedash globals — no dynamic `getProperty`/`callMethod` needed:

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

```dart
import 'dart:js_interop';
import 'package:flame/game.dart';
import 'package:flutter/material.dart';

@JS('Wavedash.init')
external void _wavedashInit();

@JS('Wavedash.updateLoadProgressZeroToOne')
external void _wavedashUpdateProgress(double p);

class MyGame extends FlameGame {
  @override
  Future<void> onLoad() async {
    _wavedashUpdateProgress(0.3);  // engine ready
    // ... load assets ...
    _wavedashUpdateProgress(0.7);  // assets loaded
    // ... build world ...
    _wavedashUpdateProgress(1.0);  // all done
    _wavedashInit();
  }
}

void main() {
  runApp(GameWidget(game: MyGame()));
}
```

Call `updateLoadProgressZeroToOne(...)` with intermediate values while `onLoad` is fetching assets. `init()` automatically signals load completion, so call it last.

## HTML shell

Flutter's generated `build/web/index.html` already bootstraps the engine. Wavedash injects `window.Wavedash` before Flutter mounts, so no extra wiring is needed in the shell.

Flutter manages its own service worker for asset caching. Disable it to avoid clashing with Wavedash's local dev service worker:

```html
<script>
  window.flutterConfiguration = {
    serviceWorkerSettings: { serviceWorkerVersion: null }
  };
</script>
```

## wavedash.toml

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

## Other SDK features

Add an `@JS` binding for each SDK method you need:

```dart
@JS('Wavedash.uploadLeaderboardScore')
external void _submitScore(String leaderboardId, int score, bool autoAuth);

@JS('Wavedash.setAchievement')
external void _setAchievement(String id, bool storeNow);
```

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