# Swift

Compile Swift games to WebAssembly with the Swift WebAssembly SDK and JavaScriptKit.

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

<GithubLink href="https://github.com/wvdsh/examples/tree/main/example-swift" />
<PlaytestLink href="https://wavedash.com/playtest/swift-example/7179456e-8c10-46b4-9cd2-3310b969a8d9" />

Swift compiles to WebAssembly via the official Swift WebAssembly SDK, and [JavaScriptKit](https://github.com/swiftwasm/JavaScriptKit) gives you typed access to browser globals. Any Swift program that can drive a `<canvas>` through JavaScriptKit runs on Wavedash.

## Toolchain

Apple's bundled toolchain doesn't ship a wasm-capable clang, so install a standalone Swift 6.3+ toolchain from [swift.org](https://www.swift.org/install/). [swiftly](https://swiftlang.github.io/swiftly/) is the easiest path:

```bash
swiftly install 6.3.0
```

Then install the Swift WebAssembly SDK once:

```bash
swift sdk install https://download.swift.org/swift-6.3-release/wasm-sdk/swift-6.3-RELEASE/swift-6.3-RELEASE_wasm.artifactbundle.tar.gz \
  --checksum 9fa4016ee632c7e9e906608ec3b55cf13dfc4dff44e47574c5af58064dc33fd9
```

## Build for web

In your `Package.swift`, add `JavaScriptKit` and its `PackageToJS` plugin. Build with:

```bash
swift package --swift-sdk swift-6.3-RELEASE_wasm js -c release
cp -R .build/plugins/PackageToJS/outputs/Package/. dist/
cp Public/index.html dist/
```

The `PackageToJS` plugin emits the WASM binary plus a loader in `.build/plugins/PackageToJS/outputs/Package/`. Point `upload_dir` at the `dist/` folder you assemble.

## SDK integration

Wavedash injects `window.Wavedash` before your wasm loads. Progress reporting happens in two phases:

1. **JS loader (`index.js`)** — stream `Pong.wasm` byte-by-byte, reporting 0 → 0.95 as bytes arrive.
2. **Swift (`main.swift`)** — call `updateLoadProgressZeroToOne(1.0)` then `init()` once the game is ready.

In your `index.js` entrypoint (generated by `PackageToJS`, then customized):

```javascript
const sdk = await window.Wavedash;
sdk.updateLoadProgressZeroToOne(0);

const response = await fetch(new URL("Pong.wasm", import.meta.url));
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);
// then instantiate and run as normal
```

In your Swift entry point, once the game is ready to play:

```swift
import JavaScriptKit

let window = JSObject.global

// Set up canvas, input, game loop with requestAnimationFrame...

if let sdk = window.Wavedash.object {
  _ = sdk.updateLoadProgressZeroToOne!(1.0)

  let opts = JSObject.global.Object.function!.new()
  opts.debug = .boolean(true)
  _ = sdk.`init`!(opts)
}
```

Calling async SDK methods (leaderboards, UGC, etc.) works through JavaScriptKit's `JSPromise` — see the [SDK setup](/sdk/setup) and [Functions reference](/sdk/functions) pages for the full API.

## wavedash.toml

```toml
game_id = "YOUR_GAME_ID_HERE"
upload_dir = "./dist"
entrypoint = "index.html"
```

<Note>
The example repo commits a prebuilt `dist/` so you can run `wavedash dev` without a Swift wasm toolchain. Regenerate it by re-running the `swift package ... js -c release` command whenever you change Swift sources.
</Note>
