Search documentation

Find pages, sections, and content across all docs.

WavedashDocs

Unity

Add the Wavedash Unity package and publish through WebGL builds.

Add the Wavedash Unity package, configure your WebGL build settings, and call the C# SDK through the JavaScript bridge.

View the SDK on GitHub Playtest the example project

Install the SDK

The SDK requires Unity 6 (6000.x), and [unity].version in wavedash.toml must be a 6000.x version such as 6000.0.73f1.

Open Window > Package Manager, click + > Install package from git URL..., and paste:

https://github.com/wvdsh/sdk-unity.git

WebGL build settings

  1. Switch to WebGL platform in File > Build Settings
  2. In Player Settings, set compression to Gzip or Brotli and enable decompression fallback
  3. Select the Default WebGL template (not Minimal)
  4. Build to a folder you set as upload_dir in wavedash.toml

The Minimal template omits the buildUrl variable in index.html. Wavedash's upload processing reads that variable and rejects the build without it ("Could not find buildUrl in the HTML file"). Use Default.

Your index.html never runs on Wavedash

Wavedash reads your index.html to find the build files (buildUrl and the standard createUnityInstance config), but it never serves or executes the page itself. The embed constructs its own page: it creates its own canvas and calls createUnityInstance directly with a config assembled at upload time.

That means anything you add to index.html — or patch into it in a post-build step — is dead code in production:

  • Custom <script> blocks, analytics, polyfills
  • Canvas sizing/styling, loading bars, fullscreen buttons, error handlers
  • Config changes made after the var config = { … } literal

The var config = { … } literal itself is parsed at upload and passed to createUnityInstance. Besides the standard fields, it may set memoryUrl, symbolsUrl, workerUrl, matchWebGLToCanvasSize, devicePixelRatio, autoSyncPersistentDataPath, and fullscreenElementID; those ship. Any other key (for example webglContextAttributes or powerPreference) makes the upload fail with a config error.

What does ship exactly as you built it:

  • The build files themselves: *.loader.js, *.framework.js, *.data, *.wasm — including any post-build patches to those files
  • StreamingAssets/ and Addressables content
  • Everything you do from C# at runtime

To cap devicePixelRatio, set it in that config literal.

This is a recurring trap for post-build scripts (and for AI coding agents): patching index.html looks like it works because the file is in the upload, but only local previews of that file will ever reflect the change. Verify template-level fixes on a Wavedash playtest link, not by opening index.html.

Use the SDK from C#

Calling Init() is required. It opts your game into Wavedash platform features and is how the SDK confirms you're set up. Call it once your game is ready to play.

using System;
using System.Collections.Generic;

void Awake()
{
    Wavedash.SDK.Init(new Dictionary<string, object> { { "debug", true } });
    // Init() automatically calls ReadyForEvents() unless you pass { "deferEvents", true }
    // in the config. If you do defer, call Wavedash.SDK.ReadyForEvents() manually after
    // your pre-game setup is complete.
}

async void LogPlayerAndScore()
{
    var user = Wavedash.SDK.GetUser();
    Debug.Log(user != null ? user["username"] : "no user");

    try
    {
        var lb = await Wavedash.SDK.GetLeaderboard("high-scores");
        if (lb == null) return; // null only outside a WebGL build
        var result = await Wavedash.SDK.UploadLeaderboardScore((string)lb["id"], 1500, keepBest: true);
        Debug.Log($"rank {result["globalRank"]} (this run: {result["submittedRank"]})");
    }
    catch (Exception ex)
    {
        Debug.LogException(ex); // a failed call throws "Request failed: ..." in WebGL builds
    }
}

Async calls return null (or false) only outside a WebGL build (the Editor or a standalone player), where the SDK isn't available. In a WebGL build a failed call throws an Exception (Request failed: …), so wrap awaits in try/catch.

P2P messaging

Unity exposes the same WebRTC P2P API as the JavaScript SDK. Messages are binary (byte[] or ArraySegment<byte>). Reliable messages are ordered and guaranteed; unreliable messages are faster but lossy.

void SendExamples(byte[] payload, string targetUserId)
{
    // Broadcast to every peer in the lobby
    Wavedash.SDK.BroadcastP2PMessage(payload, channel: 0, reliable: true);

    // Send to a specific peer
    Wavedash.SDK.SendP2PMessage(targetUserId, payload, channel: 0, reliable: true);
}

// Drain queued incoming messages once per frame
private readonly List<Wavedash.P2PMessage> _messageBuffer = new();

void Update()
{
    int count = Wavedash.SDK.DrainP2PChannel(0, _messageBuffer);
    for (int i = 0; i < count; i++)
    {
        var msg = _messageBuffer[i];
        HandleMessage(msg.SenderId, msg.Channel, msg.Payload);
    }
}

Wavedash.SDK.MAX_PAYLOAD_SIZE reports the maximum payload bytes for a single P2P message, derived from your P2PConfig at Init() time. See Multiplayer networking for the cross-language reference and channel conventions.

For Mirror or Netcode for GameObjects projects, import the Mirror Transport or Netcode for GameObjects Transport sample from Package Manager → Wavedash SDK → Samples. Each requires Mirror or com.unity.netcode.gameobjects respectively.

wavedash.toml

game_id = "YOUR_GAME_ID_HERE"
upload_dir = "./Builds/WebGL"

[unity]
version = "6000.0.73f1"