Controller+BETADownload

Status codes

A short code identifies what happened. The controller also explains what to do. Quote the code when asking for help. A computer or game can supply its own plain explanation with the same code.

Connection details

Open MENU → Connection details, tap the Remote’s main LCD, or use the Details key beside a notice. The browser keeps the last 100 steps in memory, with UTC timestamps and elapsed milliseconds since the page opened. It records connection attempts, joining, routes, failures, notices and motion availability. Reloading clears the log. Input, join links, tokens, pairing keys, install IDs and player rosters are not logged. Addresses are omitted from exported reports.

Connection history, help, the settings guide and reports appear on a framed LCD inside a gray controller shell. Physical up/down keys scroll the glass. The Remote has a second LCD for notices; its instructions never cover the game readout or sit on the shell.

An attempt says which step is running. A lost connection shows N3 with the attempt number and route. A failed first join shows N2; check the connection and press Join game again. A saved seat rejected by the server is cleared and tried once with the current invitation. Expired invitations, removal and closed rooms stop automatic retries and keep their code until a new join. A later successful ping does not erase them.

Welcome, player join/leave messages and reconnect notices use the controller's LCD. They never change the controller's size or position. Welcome and roster messages clear after every page has been shown, with reading time for the last page. On a scrollable LCD, reach the final lines with the down key. Connection problems remain until resolved. A private game screen replaces stale text and timers with the connection state and suspends game actions until a fresh playable view arrives.

When a relay sends room.host: false in a state frame, G2 says the game is not responding and the phone is waiting. SELECT becomes a red DISCONNECT key at the same position; START and MENU stay as they are. On the Remote, DISCONNECT takes CENTER's place beside the main LCD; MENU and the motion key keep their roles. The full DISCONNECT label fits that fixed key slot. DISCONNECT closes the session, clears its remembered join and returns to scanning. room.host: true restores the normal LCD and key without moving any controls. Omitted or nonboolean host values do not change the last known state; older relays keep their current behavior. A working relay ping cannot dismiss G2. The phone's own reconnect uses N3 on the LCD.

Codes

This is the canonical table for browser, Android, iOS and desktop notices. Each code has one meaning. Platform wording and permission steps may differ, but the meaning must not. N6 is an initial connection attempt; N3 is reconnection after a joined session; G1 waits for a controller view; G2 waits for the game itself. Camera scanning, joins, network failures, unsupported controllers and motion codes can arise in the browser. Local-network permissions, remembered computer identities, desktop permissions and the desktop server link are diagnosed by the native apps or computer and arrive as notices. The browser does not guess a certificate or OS permission failure from a generic timeout.

Code What happened What to do
S1 The camera is off for this page. Allow camera access in browser settings, or use your phone's camera to scan the game code.
S2 That is not a Controller+ code. Scan the code on the game or computer screen, or paste its full join link.
S3 This code has expired. Scan the code that is on the screen now.
S4 This page cannot open the camera. Use your phone's camera to scan the game code, or paste its join link.
J1 Waiting for the computer to let you in. Click Let in next to this phone on the computer.
J2 The game or computer removed this phone. Scan its code to join again.
J3 The computer forgot this phone. Scan its code to play on it again.
J4 The game or computer closed the room. Open it again and scan its new code.
J5 This game is full. Ask a player to leave, or wait.
J6 This controller opened on another screen of this phone. Continue there, or scan the game code to join here again.
J7 The computer did not let this phone in. Ask the person at the computer, then scan its code to try again.
L1 Local Network access is off for Controller+. Allow Local Network access in your phone's settings.
L2 Could not reach the computer on this Wi-Fi. Use the same Wi-Fi and allow Controller+ through the computer's firewall. Touch play can use the game server.
L3 The computer has a new identity. Scan its code again to trust it. It may have been reinstalled or reset.
L4 This phone is not on the computer's Wi-Fi. Join the same Wi-Fi for local controls. Game buttons can use the game server.
L5 The computer’s secure connection could not be verified. Check the date on both devices, then scan the computer’s current code.
N1 This phone is offline. Check Wi-Fi or mobile data, then try again.
N2 Cannot reach the game server. Check your connection and keep the game open. Try again in a minute.
N3 Connection dropped. Keep the game open and check Wi-Fi while this phone reconnects.
N4 The connection is slow or unstable. Move closer to the router, or use Wi-Fi.
N5 The remembered computer is not online. Open Controller+ on it and keep the computer awake.
N6 Connecting to the game, with the attempt and current step. Keep the game or Controller+ open on the computer.
N7 Controller+ is paused in the background. Return to the app. Check Android battery settings if the app is closed.
R1 The computer's link to the server is ready. You can join from your phone.
R2 The computer is connecting to the server. Keep Controller+ open while it connects.
R3 The computer is reconnecting to the server. Check the computer's internet connection.
R4 The computer cannot reach the server. Check its internet connection and try again.
R5 The computer's server link is off. Turn it on in Controller+ on the computer.
D1 The computer cannot press keys yet. On a Mac, allow Controller+ in System Settings, Privacy & Security, Accessibility.
D2 The computer has no virtual gamepad, so buttons press game keys. Use the game's keyboard controls or set up a supported virtual gamepad.
D3 The computer cannot press keys right now. Quit and reopen Controller+ on the computer.
D4 The computer's local connection is busy or blocked. Quit other copies of Controller+ or allow it through the firewall.
D5 Waiting for the computer to allow mouse and keyboard. Approve the request on the computer.
D6 Deck, trackpad and keyboard need a direct connection in the Controller+ app. Use the app and join the computer's Wi-Fi.
V1 This controller needs an update to play. Reload this page, or update the Controller+ app.
V2 The computer's Controller+ needs an update for this feature. Update Controller+ on the computer.
V3 This page cannot show the requested controller. Reload this page. If it still happens, ask the game maker for a supported controller.
M1 Motion needs your permission. Tap Enable motion and allow access, or drag to aim and use the big button.
M2 Motion permission was not granted. Allow motion in browser settings, or drag to aim and use the big button.
M3 Motion is unavailable on this page. Use a supported browser on a secure page, or drag to aim and use the big button.
M4 No motion readings are arriving. Move the phone. If aim stays still, drag to aim and use the big button.
M5 Motion is off. Tap Enable motion, or drag to aim and use the big button.
G1 Waiting for the game's controller. Keep the game open. If nothing appears, reload this page.
G2 The game is not responding, though the phone may still reach the relay. Wait for it to return, or press DISCONNECT to return to scanning.
C1 The game could not accept this controller request. Reload this page. If it happens again, open Connection details and report the code.

N2 refers to controller.plus when that service hosts the game, or to the game's own server for a self-hosted SDK game. S1 means camera permission was blocked; S4 means camera scanning is unavailable or failed for another reason. M1–M5 describe motion permission, refusal, availability, missing readings and the player's off setting. Motion is optional; touch controls stay usable. G1 means the phone has joined but the game's controller has not arrived. C1 means a controller request was rejected for a reason outside the more specific codes. The game maker can use Connection details to investigate it.

Connection states and server names

The scan screen is a controller with its own LCD, up/down keys, name/link fields and Scan/Join keys. Joining uses N6 with its attempt and step. A welcome without a controller uses G1. Waiting for approval uses J1. A supplied approval code appears only on the waiting LCD, beside a request to match it with the computer; it is removed after approval or leaving and never enters the connection journal or report. A malformed code is ignored. The browser accepts a code on welcome or an approval frame, including an approval error that keeps the connection waiting.

Terminal failures stay on the LCD through socket closure, online events and later pings. They stop retries, clear the saved join/seat and offer scanning: the scan key is already visible before joining; a joined controller offers DISCONNECT in the SELECT slot (or Remote motion slot). Leaving shows “Disconnected. Scan a game QR to play again.” and keeps the player name. Long canvas messages page with their code and page count; Remote and scan LCDs have physical scroll keys. Updated ping and attempt values keep the current page or reading position, so frequent samples cannot hide the rest of the advice. Approval, waiting instructions and unsupported-controller status survive pings and network recovery until a valid view arrives. Paging, notices and failures never move the controller geometry.

Server error names Code
invalid_qr S2
unauthorized, invalid_token, invalid_resume, token_rejected S3
pending, approval_required, waiting_approval J1
kicked, removed J2
pairing_revoked, unpaired J3
room_expired, room_closed, host_left, closed J4
room_full J5
resumed_elsewhere, seat_moved, moved J6
approval_refused, refused, denied J7
computer_offline, computer_not_found N5
secure_phone_required D6
app_update_required, invalid_hello, version_unsupported, version_mismatch V1
Other rejected requests C1

J7 reserves an explicit approval refusal; the current relay’s pairing_revoked still means J3. Pending and approval errors keep waiting instead of failing the join. Close 4001/4005 means J6, 4003 with reason Removed means J2 (otherwise S3), 4004 means J4, and 1009 means V1. An ordinary transport close reconnects with N3 only after a successful join. Native implementations should adopt these aliases too; unknown host notice codes continue to display their supplied explanation.

Notices from a computer or game

Any view can include:

notice: {
  code: 'D1', level: 'warning',
  text: 'The computer cannot press keys yet. Allow Controller+ in System Settings, Privacy & Security, Accessibility.',
}

code is one uppercase ASCII letter and one or two digits. text is nonblank, at most 160 UTF-16 code units and contains no control characters. level is info, warning or error. The phone displays the text as supplied, with its code, and records it in Connection details. Unknown codes work too, so a newer computer can explain a problem to an older controller. Omit the notice in the next full view to clear it. A network failure takes priority; the view's notice remains visible below it. Notices survive conversion of waiting/choices views to surfaces and an older-app legacy fallback.

Do not put private information in notices. They are visible on the phone and can be included in the player's report. Hosts validate notices before saving or sending views. Notices have no authority to press keys or change desktop permissions.

Report a problem

The browser offers Report a problem and Copy report in Connection details only when the hosting page supplies a support address. Self-hosted SDK games have no default vendor address. To enable it on the included controller:

// Your own Node HTTP(S) request handler:
if (await serveControllerAssets(req, res, { supportEmail: 'help@example.com' })) return;

For a custom hosting page, set this before loading the controller module:

<meta name="controller-plus-support" content="help@example.com">

Or assign window.controllerPlusOptions = { supportEmail: 'help@example.com' }. The option is not read from the join link. An invalid email address is rejected by the asset server, or ignored by a custom page. controller.plus can supply hello@controller.plus; the SDK does not contact it automatically.

Report a problem first opens an editable LCD report. Email report then opens a mailto: draft. Copy report preserves the edits. The report has prompts for what happened, what was expected, steps, and a request to attach screenshots or a screen recording. Below an editable/removable divider it includes the browser controller version, OS/browser information exposed by the browser, device model when provided, network type when known, current game/computer name and version when provided, route, player number, mode, current code and recent steps. A browser that withholds OS/model/network information says so. It never substitutes a guessed model or Wi-Fi name.

The report excludes join links, room and resume tokens, pairing secrets, install IDs and other players' names known from the roster. Generated logs use safe connection steps rather than raw server errors. Additional redaction removes URLs, addresses and long identifiers from game-supplied text. No report is uploaded. A browser cannot reliably tell whether a mail app is configured, so Copy report is always offered beside the email link. If clipboard access fails, a selectable report appears for manual copying. Save picture optionally saves a PNG of the Remote, gamepad, wheel or flight controller. It captures only the controller, including its visible LCD text; it does not request camera or screen-recording access, capture the report or pairing page, or upload anything. Attach the saved picture in your mail app. If the browser cannot create it, take a screenshot instead. Private game surfaces do not offer this key. Nothing is captured automatically.

MENU → Contact & desktop app opens computer setup instructions and the configured support address, when supplied. Its Downloads key opens Downloads in a new tab. With no support address, help and connection history still work; report and email actions stay hidden.