CTRLLR - Mobile game controller SDK
npm install ctrllr-sdkTurn any smartphone into a game controller. CTRLLR provides WebRTC-powered low-latency input for multiplayer games.
Example: https://ctrllr-sdk-vanilla.vercel.app/
| Package | Description | Status |
| ------------------------------- | ---------------------------------------------- | -------------- |
| @ctrllr/core | Core SDK with WebRTC, events, state management | ā
Ready |
| @ctrllr/react | React hooks and components | š Coming soon |
```
āāāāāāāāāāāāāāāāāāā āāāāāāāāāāāāāāāāāāāā āāāāāāāāāāāāāāāāāāā
ā Game App ā ā Signaling Server ā ā Mobile App ā
ā (@ctrllr/core) ā ā (socket.io) ā ā (Controller) ā
āāāāāāāāāā¬āāāāāāāāā āāāāāāāāāā¬āāāāāāāāāā āāāāāāāāāā¬āāāāāāāāā
ā ā ā
āāāāāā 1. Connect āāāāāāŗāāāāāā 2. Connect āāāāāāāŗā
ā ā ā
ā 3. Get socket ID ā ā
ā 4. Show QR code āāāāāāā¼āāāāāāāāŗ 5. Scan QR ā
ā ā ā
āāāāāāāāāāāāāāāāā 6. WebRTC Signaling āāāāāāāāāāāŗā
ā ā ā
āāāāāāāāāāāāāāāāā 7. WebRTC DataChannel āāāāāāāāāŗā
ā ā ā
āāāāāāāāāāāāā 8. Controller Input āāāāāāāāāāāāāāā
Connection Flow:
1. Game app connects to your signaling server ā receives socket ID ā displays QR code
2. Mobile controller app connects to signaling server ā opens camera, ready to scan
3. Player scans QR code ā controller reads socket ID ā tells server "connect me to this game"
4. Signaling server brokers WebRTC handshake (offer/answer/ICE)
5. Direct WebRTC DataChannel established for low-latency input
6. SDK emits input events to your game logic
`bash`Install
pnpm add @ctrllr/core
`typescript
import { CtrllrManager } from '@ctrllr/core';
const ctrllr = new CtrllrManager({
signalingUrl: 'wss://your-signaling-server.com',
});
await ctrllr.connect();
// Show QR code
document.getElementById('qr').src = await ctrllr.getQRCodeDataURL();
// Handle controllers
ctrllr.on('controllerconnected', (e) => {
const controller = e.controller;
console.log(Player ${controller.index} joined: ${controller.username});
// Read input in game loop
function gameLoop() {
const { joystick } = controller.state;
player.move(joystick.x, joystick.y);
requestAnimationFrame(gameLoop);
}
gameLoop();
// Or use events for button presses
controller.on('buttondown', (e) => {
if (e.input === 'a') player.jump();
});
});
`
``
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
ā ā
ā āāāāā [Y] ā
ā ā ā ā
ā ā J ā [X] [Z] ā
ā ā ā ā
ā āāāāā [A] ā
ā ā
ā Joystick Aimable Buttons ā
ā (movement) (with direction)ā
āāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāāā
All inputs share the same interface:
`typescript`
interface InputState {
pressed: boolean; // Is the input active
x: number; // Horizontal axis (-1 to 1)
y: number; // Vertical axis (-1 to 1)
}
Manager Events:
- controllerconnected - New controller connectedcontrollerdisconnected
- - Controller disconnectedstatechange
- - Any controller input changedbuttondown
- - Button pressed on any controllerbuttonup
- - Button released on any controller
Controller Events:
- statechange - This controller's input changedbuttondown
- - Button pressed (edge detected)buttonup
- - Button released (edge detected)
`bashInstall dependencies
pnpm install
Project Structure
`
ctrllr-sdk/
āāā packages/
ā āāā core/ # @ctrllr/core - Base SDK
ā ā āāā src/
ā ā ā āāā index.ts
ā ā ā āāā CtrllrManager.ts
ā ā ā āāā Controller.ts
ā ā ā āāā EventEmitter.ts
ā ā ā āāā QRCode.ts
ā ā ā āāā types.ts
ā ā ā āāā signaling/
ā ā ā āāā SignalingAdapter.ts
ā ā ā āāā SocketIOAdapter.ts
ā ā āāā package.json
ā ā
ā āāā react/ # @ctrllr/react (coming soon)
ā
āāā examples/ # Demo apps
āāā package.json # Workspace root
āāā pnpm-workspace.yaml
āāā turbo.json
``MIT