Navigate

Unity Integration

Enable players to use Cephable's personal assistant adaptive controls in your Unity game, making it accessible for players with motor or physical disabilities.

Overview

The Cephable Unity Plugin is the official Unity package for integrating Cephable's adaptive controls into your game. Players configure voice commands, facial expressions, head tracking, gestures, and custom switches through the Cephable app — all processed on their device — and your game receives the resulting commands in real time via SignalR.

Plugin repository: github.com/Cephable/Cephable-Unity-Plugin

See it in action: https://youtu.be/cwKVbYTWMt8

Prerequisites

No credit card required. After your trial, contact support@cephable.com to arrange a permanent license.

Installation

Via Unity Package Manager (Git URL)

  1. Open Window → Package Manager
  2. Click the + button and choose Add package from git URL
  3. Enter https://github.com/Cephable/Cephable-Unity-Plugin.git and click Add

Via Local Disk

  1. Clone or download the repository
  2. Open Window → Package Manager
  3. Click +Add package from disk and select package.json

Getting Started

1. Set Up Your Cephable App

Log in to the Cephable Developer Portal and:

  • Create an application to receive your Client ID and Client Secret
  • Create a Device Type for your game and note its Device Type ID
  • Configure the redirect URI: http://127.0.0.1:51772/

2. Add Components to Your Scene

Create a new GameObject (e.g. CephableController) and add two components:

  • OAuth2Manager — handles player sign-in
  • VirtualController — registers the device and receives commands

Link them: drag the VirtualController object into the Controller field on OAuth2Manager.

3. Configure OAuth2Manager

In the Inspector, fill in:

Field Value
Client ID Your Cephable application Client ID
Client Secret Your Cephable application Client Secret

4. Configure VirtualController

In the Inspector, fill in:

Field Value
Device Type ID Your Cephable Device Type ID
Default Device Name Displayed to players in the Cephable app (e.g. "My Game Controller")

5. Add a Login Button

Add a UI Button to your scene (e.g. in a settings or pause menu). Add a LoginButton component to it and wire up:

  • Oauth2Manager → your OAuth2Manager component
  • Login Button → the UI Button component

When the player clicks the button, they are taken to the Cephable sign-in page in their browser. After signing in, the plugin registers a virtual device and opens the SignalR connection automatically.

Handling Commands

When a player performs an adaptive action in Cephable, the plugin fires a DeviceCommand event with the command name and an optional MacroModel. There are three ways to respond:

Option A — Unity Events (Inspector, No Code Required)

Select your VirtualController GameObject and wire up the Unity Events section in the Inspector:

Event When it fires Parameters
OnCommandReceived Every incoming command string command name
OnKeyStateChanged A key is pressed or released by a macro string key name, bool isPressed
OnJoystickChanged Joystick axes change float leftX, leftY, rightX, rightY (-1 to 1)
OnCustomActionTriggered A custom device action fires string deviceTypeId, actionId, additionalContent

Drag your game component into the event slot and choose the method to call. No scripting needed for simple mappings.

Option B — C# Event Subscription

Subscribe to the typed C# events on VirtualController from any MonoBehaviour:

public class PlayerInput : MonoBehaviour
{
    [SerializeField] private VirtualController cephable;

    void OnEnable()
    {
        cephable.MacroCommandReceived  += OnMacroCommand;
        cephable.CustomActionReceived  += OnCustomAction;
        cephable.OnKeyStateChanged.AddListener(OnKeyState);
        cephable.OnJoystickChanged.AddListener(OnJoystick);
    }

    void OnDisable()
    {
        cephable.MacroCommandReceived  -= OnMacroCommand;
        cephable.CustomActionReceived  -= OnCustomAction;
        cephable.OnKeyStateChanged.RemoveListener(OnKeyState);
        cephable.OnJoystickChanged.RemoveListener(OnJoystick);
    }

    void OnMacroCommand(string command, MacroModel macro)
    {
        Debug.Log($"Command received: {command}");
        // Handle command names like "jump", "fire", "crouch", etc.
    }

    void OnCustomAction(string deviceTypeId, string actionId, string content)
    {
        Debug.Log($"Custom action: {actionId}");
    }

    void OnKeyState(string key, bool isPressed)
    {
        Debug.Log($"Key {key} is now {(isPressed ? "pressed" : "released")}");
    }

    void OnJoystick(float lx, float ly, float rx, float ry)
    {
        Debug.Log($"Left stick: ({lx:F2}, {ly:F2})  Right stick: ({rx:F2}, {ry:F2})");
    }
}

Option C — Simulated Input Polling

VirtualController tracks simulated key and axis states as macros execute. Poll these in Update() alongside Unity's Input API:

public class PlayerController : MonoBehaviour
{
    [SerializeField] private VirtualController cephable;
    [SerializeField] private Rigidbody rb;

    void Update()
    {
        // Combine standard keyboard/gamepad with Cephable adaptive input
        bool jump   = Input.GetKeyDown(KeyCode.Space) || cephable.GetKey(KeyCode.Space);
        bool fire   = Input.GetKeyDown(KeyCode.Mouse0) || cephable.GetKey("Fire");
        float moveX = Input.GetAxis("Horizontal") + cephable.GetAxis("LeftX");
        float moveY = Input.GetAxis("Vertical")   + cephable.GetAxis("LeftY");

        moveX = Mathf.Clamp(moveX, -1f, 1f);
        moveY = Mathf.Clamp(moveY, -1f, 1f);

        if (jump) rb.AddForce(Vector3.up * 5f, ForceMode.Impulse);
        rb.velocity = new Vector3(moveX * 5f, rb.velocity.y, moveY * 5f);
    }
}

GetKey(string keyName) — returns true while that key is simulated as held.
GetKey(KeyCode keyCode) — same, accepting a Unity KeyCode.
GetAxis(string axisName) — returns a value from -1 to 1 for "LeftX", "LeftY", "RightX", or "RightY".

Macro Events

The MacroModel passed to MacroCommandReceived contains a list of MacroEvent objects. The plugin executes these automatically, but you can read them for custom handling:

Event Type What happens
KeyPress Sets named keys as held; releases after holdTimeMilliseconds if set
KeyRelease Releases named keys
KeyToggle Toggles named keys between pressed and released
Pause Waits holdTimeMilliseconds before continuing
JoysticksMove Updates left/right joystick axis values
DeviceTypeCustomAction Fires OnCustomActionTriggered / CustomActionReceived
StopOutputs Releases all held keys and resets joystick axes to zero

API Reference

VirtualController

Member Type Description
DeviceTypeId string Your Cephable Device Type ID (set in Inspector)
DefaultDeviceName string Device name shown to the player in Cephable
CephableApiBaseUrl string API base URL (default: https://services.cephable.com)
OnCommandReceived UnityEvent<string> Fires on every incoming command
OnKeyStateChanged UnityEvent<string, bool> Fires when a key is pressed or released
OnJoystickChanged UnityEvent<float,float,float,float> Fires when joystick axes change
OnCustomActionTriggered UnityEvent<string,string,string> Fires for custom device actions
MacroCommandReceived event Action<string, MacroModel> C# event with full macro data
CustomActionReceived event Action<string, string, string> C# event for custom actions
GetKey(string) bool Poll simulated key state by name
GetKey(KeyCode) bool Poll simulated key state by KeyCode
GetAxis(string) float Poll simulated joystick axis (-1 to 1)

Player Experience

From the player's perspective:

  1. They launch your game and click Sign In with Cephable
  2. Their browser opens the Cephable sign-in page
  3. After signing in, the plugin registers a device linked to their Cephable profile
  4. In the Cephable app, they assign their adaptive inputs (voice commands, facial expressions, head movements, switches) to your game's actions
  5. Their inputs arrive in real time as the game runs — no extra setup needed mid-session

Players can update their configuration at any time in the Cephable app without restarting your game. Profile updates are pushed via SignalR automatically.

Next steps