OKONAONLINE
Developer Docs
OkonaPad
A lightweight Unity SDK for integrating smartphone controllers into your WebGL games. Drop it in, map your inputs, and let Okona handle the rest.
Introduction
OkonaPad is a lightweight Unity SDK for integrating smartphone controllers into WebGL games hosted on the Okona Online platform. The SDK receives controller input from the website shell via JavaScript interop, translating it into Unity Input System events.
Key Features
- Seamless Unity Input System integration
- Support for up to 6 concurrent controllers
- Binary protocol for efficient input transmission
- Controller slot system with disconnect/reconnect handling
- Custom InputDevice with buttons, D-pad, and joystick
- Haptic feedback support via rumble callbacks
Architecture
The Okona Online website handles all networking (WebSocket connections, QR codes, controller UI). Your Unity WebGL game only needs to receive input through the OkonaInputBridge component.
System Requirements
Unity Requirements
- Unity 6 (6000.3.2f1) or higher
- Input System package (com.unity.inputsystem) v1.17.0+
Build Target
- WebGL (primary target for Okona Online integration)
Project Settings
- Open
Edit > Project Settings > Player > Other Settings - Set
Active Input Handlingto Both or Input System (New) - Ensure the Input System package is installed via Package Manager
Quick Start Guide
Add OkonaInputBridge to Your Scene
Create an empty GameObject and add the OkonaInputBridge component:
using OkonaPad.Input;
using UnityEngine;
public class GameManager : MonoBehaviour
{
[SerializeField] private OkonaInputBridge inputBridge;
void Awake()
{
// OkonaInputBridge automatically registers the
// OkonaPadControllerDevice with Unity's Input System
}
}
Or simply add the OkonaInputBridge component to any GameObject in your scene via the Unity Inspector.
Configure Input Actions
- Open or create an Input Actions asset
- Map your actions to OkonaPad controls using
<OkonaPad>/buttonA,<OkonaPad>/leftStick, etc. - The
OkonaPadControllerDeviceappears asOkonaPadin the Input System - Use
<OkonaPad>as the device requirement in your control scheme
Build for WebGL
- File > Build Settings > WebGL
- Build your project
- Deploy to Okona Online platform
The website shell automatically establishes connections with phone controllers and forwards input to your game.
API Reference
OkonaInputBridge
OkonaPad.Input.OkonaInputBridge
The main component that receives input from the website and updates Unity Input System devices.
Lifecycle Methods
Called by the website shell via JavaScript SendMessage:
// Called when a phone controller connects or reconnects
public void OnControllerConnected(int controllerId)
// Called when a phone controller temporarily disconnects
public void OnControllerDisconnected(int controllerId)
// Called when a phone controller is permanently removed
public void OnControllerRemoved(int controllerId)
// Called with binary input data (JSON with base64 payload)
// Format: {"controllerId":1,"data":"base64string"}
public void ReceiveControllerMessageBase64(string jsonData)
Events
// New device created for the first time
event Action<int, OkonaPadControllerDevice> OnDeviceConnected;
// Temporary disconnect - device preserved
event Action<int> OnDeviceDisconnected;
// Previously disconnected device has reconnected
event Action<int, OkonaPadControllerDevice> OnDeviceReconnected;
// Permanent removal - device destroyed
event Action<int> OnDeviceRemoved;
Helper Methods
// Get device for a specific controller ID (null if not found)
public OkonaPadControllerDevice GetDevice(int controllerId)
// Get connection state for a controller
public DeviceConnectionState? GetConnectionState(int controllerId)
// Get all controller IDs (connected and disconnected)
public int[] GetAllControllerIds()
// Get only connected controller IDs
public int[] GetConnectedControllerIds()
// Enable/disable debug logging
public void EnableDebugLogging(bool enable)
OkonaPadControllerDevice
OkonaPad.Input.OkonaPadControllerDevice
Custom Unity InputDevice representing a smartphone controller. This is not a Gamepad — it only exposes controls that physically exist on the phone controller.
Controls
| Control | Type | Description |
|---|---|---|
ButtonA | ButtonControl | A button |
ButtonB | ButtonControl | B button |
ButtonX | ButtonControl | X button |
ButtonY | ButtonControl | Y button |
StartButton | ButtonControl | Start button |
SelectButton | ButtonControl | Select button |
DPad | DpadControl | Directional pad |
LeftStick | StickControl | Analog joystick |
Input Binding Paths
| Control | Binding Path |
|---|---|
| A button | <OkonaPad>/buttonA |
| B button | <OkonaPad>/buttonB |
| X button | <OkonaPad>/buttonX |
| Y button | <OkonaPad>/buttonY |
| Start | <OkonaPad>/startButton |
| Select | <OkonaPad>/selectButton |
| D-pad | <OkonaPad>/dpad |
| Left Stick | <OkonaPad>/leftStick |
Properties
| Property | Type | Description |
|---|---|---|
ControllerId | int | Controller slot identifier (1-6) |
Haptic Feedback
OkonaPadControllerDevice implements IDualMotorRumble. Subscribe to the static event to forward rumble to controllers:
OkonaPadControllerDevice.OnRumbleRequested += (controllerId, lowFreq, highFreq) =>
{
// Forward haptic feedback to the phone controller
};
Usage Example
using OkonaPad.Input;
using UnityEngine;
using UnityEngine.InputSystem;
public class PlayerController : MonoBehaviour
{
private OkonaPadControllerDevice controller;
void Start()
{
var bridge = OkonaInputBridge.Instance;
if (bridge != null)
{
bridge.OnDeviceConnected += (id, device) =>
controller = device;
bridge.OnDeviceRemoved += (id) =>
{
if (controller?.ControllerId == id)
controller = null;
};
}
}
void Update()
{
if (controller == null) return;
// Read button states
if (controller.ButtonA.wasPressedThisFrame)
Jump();
// Read joystick
Vector2 movement = controller.LeftStick.ReadValue();
Move(movement);
// Read D-Pad
if (controller.DPad.up.isPressed)
MoveUp();
}
}
Using PlayerInputManager (Recommended)
For multiplayer, use Unity's PlayerInputManager with "Join Players When Button Is Pressed". Players auto-destroy when their device is removed:
private PlayerInput _playerInput;
void Awake()
{
_playerInput = GetComponent<PlayerInput>();
_playerInput.onDeviceLost += (pi) => Destroy(gameObject);
}
BinaryProtocol
OkonaPad.Networking.Binary
Defines the binary message format for controller input. Messages use a length-prefixed format:
[Length: 2 bytes BE] [MessageType: 1 byte] [Payload: variable]
Message Types
| Type | Value | Payload | Description |
|---|---|---|---|
| Button | 0x00 | [buttonCode:1][pressed:1] | Button press/release |
| Dpad | 0x01 | [direction:1][pressed:1] | D-pad direction |
| Joystick | 0x02 | [x:2][y:2] (int16 BE) | Left joystick |
| Join | 0x03 | (none) | Connection handshake |
| Pong | 0x04 | (none) | Keep-alive response |
| Rumble | 0x05 | [duration:2] (uint16 BE) | Haptic feedback |
Button Codes
| Button | Value |
|---|---|
| A | 0x00 |
| B | 0x01 |
| X | 0x02 |
| Y | 0x03 |
| Start | 0x04 |
| Select | 0x05 |
D-pad Directions
| Direction | Value |
|---|---|
| Up | 0x00 |
| Down | 0x01 |
| Left | 0x02 |
| Right | 0x03 |
Integration with Okona Online
How It Works
- Website Shell — The Okona Online website hosts your WebGL game in a container
- Controller Management — The website handles phone connections via WebSocket and manages controller slots (1-6)
- Input Forwarding — Controller input is forwarded to your game via Unity's
SendMessage() - Rumble Feedback — Your game sends haptic feedback through
OkonaSendRumbleToController, which callswindow.okonaOnRumble()on the website
JavaScript Interop
The SDK includes OkonaInterop.jslib which sets up communication between Unity and the website shell.
Website → Unity (via SendMessage)
// When a phone controller connects:
unityInstance.SendMessage('OkonaInputBridge',
'OnControllerConnected', controllerId);
// When a phone controller temporarily disconnects:
unityInstance.SendMessage('OkonaInputBridge',
'OnControllerDisconnected', controllerId);
// When a phone controller is permanently removed:
unityInstance.SendMessage('OkonaInputBridge',
'OnControllerRemoved', controllerId);
// When input data arrives:
unityInstance.SendMessage('OkonaInputBridge',
'ReceiveControllerMessageBase64',
JSON.stringify({
controllerId: controllerId,
data: base64EncodedData
}));
Unity → Website (via jslib)
// The website shell should define this to receive rumble:
window.okonaOnRumble = function(controllerId, durationMs) {
// Forward haptic feedback to the phone controller
};
Deployment
- Build your Unity project for WebGL
- Upload to Okona Online via the Developer Portal
- Configure your game settings in the Okona dashboard
- The platform handles controller connections automatically
Troubleshooting
Controller Not Detected
- Verify
OkonaInputBridgecomponent is in the scene - Ensure the GameObject is named exactly
OkonaInputBridge(required for SendMessage) - Check browser console for JavaScript errors
- Verify Input System package is installed and configured
Input Not Responding
- Check that Input Actions use
<OkonaPad>/binding paths (not<Gamepad>/) - Verify the device is registered: check
InputSystem.devicesforOkonaPadControllerDevice - Enable debug logging:
OkonaInputBridge.Instance.EnableDebugLogging(true)
Rumble Not Working
- Ensure
window.okonaOnRumblecallback is defined in the website shell - Check that the controller supports haptic feedback
- Verify the device implements
IDualMotorRumble
WebGL Build Issues
- Ensure "Input System (New)" is enabled in Project Settings
- Check that assembly definitions are properly configured
- Verify no server-side code is included (WebGL cannot run HTTP/WebSocket servers)
Debug Logging
Enable verbose logging via the bridge:
OkonaInputBridge.Instance.EnableDebugLogging(true);
Check the browser's developer console (F12) for log output.
Ready to build?
Download the SDK and start integrating smartphone controllers into your Unity WebGL game.