Pixlland

Engine guide

Unity

WebGL export — up to 80 MB compressed

Unity talks to the outside world via a .jslib plugin +SendMessage callbacks. Wire the Pixlland SDK in 3 files: an edited WebGL template, a JSLib bridge, and a MonoBehaviour that calls into it.

1. Edit the WebGL template

Duplicate Assets/WebGLTemplates/Default to Assets/WebGLTemplates/Pixlland and add the SDK script tag to its index.html:

<!-- inside <head> -->
<script src="https://pixlland.com/sdk/v1/pixlland.js" defer></script>

In Player Settings → Resolution and Presentation, pick the Pixlland template.

2. Create the JSLib bridge

Save as Assets/Plugins/WebGL/Pixlland.jslib:

mergeInto(LibraryManager.library, {
  PLL_Init: function() {
    if (!window.PixllandSDK) return;
    window.PixllandSDK.init();
  },
  PLL_LoadingFinished: function() {
    window.PixllandSDK && window.PixllandSDK.gameLoadingFinished();
  },
  PLL_GameplayStart: function() {
    window.PixllandSDK && window.PixllandSDK.gameplayStart();
  },
  PLL_GameplayStop: function() {
    window.PixllandSDK && window.PixllandSDK.gameplayStop();
  },
  PLL_HappyTime: function(delta) {
    window.PixllandSDK && window.PixllandSDK.happyTime(delta);
  },
  PLL_CommercialBreak: function(cbObjPtr, cbMethodPtr) {
    if (!window.PixllandSDK) return;
    var cbObj = UTF8ToString(cbObjPtr);
    var cbMethod = UTF8ToString(cbMethodPtr);
    window.PixllandSDK.commercialBreak().then(function() {
      SendMessage(cbObj, cbMethod);
    });
  },
});

3. C# wrapper

using UnityEngine;
using System.Runtime.InteropServices;

public static class Pixlland
{
#if UNITY_WEBGL && !UNITY_EDITOR
    [DllImport("__Internal")] public static extern void PLL_Init();
    [DllImport("__Internal")] public static extern void PLL_LoadingFinished();
    [DllImport("__Internal")] public static extern void PLL_GameplayStart();
    [DllImport("__Internal")] public static extern void PLL_GameplayStop();
    [DllImport("__Internal")] public static extern void PLL_HappyTime(float delta);
    [DllImport("__Internal")] public static extern void PLL_CommercialBreak(string cbObj, string cbMethod);
#else
    public static void PLL_Init() {}
    public static void PLL_LoadingFinished() {}
    public static void PLL_GameplayStart() {}
    public static void PLL_GameplayStop() {}
    public static void PLL_HappyTime(float d) {}
    public static void PLL_CommercialBreak(string a, string b) {}
#endif
}

4. Fire from a MonoBehaviour

public class PixllandDriver : MonoBehaviour {
    void Start() {
        Pixlland.PLL_Init();
        Pixlland.PLL_LoadingFinished();
        Pixlland.PLL_GameplayStart();
    }
    void Update() {
        if (Time.timeScale > 0)
            Pixlland.PLL_HappyTime(Time.unscaledDeltaTime);
    }
    public void OnPlayerDied() {
        Pixlland.PLL_GameplayStop();
        Pixlland.PLL_CommercialBreak(gameObject.name, nameof(OnAdFinished));
    }
    public void OnAdFinished() {
        // SendMessage → here
        Pixlland.PLL_GameplayStart();
    }
}

Common pitfalls

  • WebGL builds are huge. Strip IL2CPP, enable LTO, and compress with Brotli. Pixlland's ceiling is 80 MB post-compression; beyond that, curation will push back.
  • AudioContext suspended. Unity's WebGL audio starts suspended — resume it inside your first user-click handler, not inside Start().

Alternative: many Unity indies ship a single lightweight scene with vanilla HTML5 + canvas instead. Always worth comparing build sizes.

Unity · Pixlland Engines