# Local parties, gamepads and phone controllers in PlayDrop games

Read physical gamepads and PlayDrop phone controllers through sdk.device, follow local player slots, declare controller support and local party sizes.

Source: https://www.playdrop.ai/create/learn/local-party

A local party is several people playing on one screen, each with a controller: a physical gamepad or a phone that PlayDrop turns into a controller by scanning a code. Your game reads every controller the same way through the SDK, on the website and in the apps.

## Declare controllers and party sizes

```json
{
  "types": ["solo", "party"],
  "party": { "local": [1, 2, 3, 4] },
  "controller": { "support": "optional", "type": "simpler" }
}
```

- `controller.support` is `off`, `optional` or `required`. Declare it on every game, including `off`.
- `controller.type` names the minimum controls the game needs: `any` (directions, Confirm and Cancel), `simpler` (one stick, four face buttons and Menu; phone controllers qualify) or `standard` (D-pad, two clickable sticks, four face buttons, two shoulders, two triggers and Menu).
- `party.local` lists the exact player counts on one screen; a `1` requires the `solo` type. With controller support on, every listed count must be playable with controllers.

## Read controllers

```js
await sdk.device.enableControllerInput().catch(() => { /* keep keyboard and touch */ });

const stop = sdk.device.onButton(({ playerIndex, button, pressed }) => {
  if (button === "south" && pressed) jump(playerIndex);
});

function update() {
  for (const slot of sdk.device.localPlayers) {
    const pad = sdk.device.gamepad(slot.playerIndex);
    if (pad?.connected) move(slot.playerIndex, pad.axes[0], pad.axes[1]);
  }
  requestAnimationFrame(update);
}
update();
```

- Call `enableControllerInput()` once after `init()`. It rejects with `controller_input_unavailable` or `controller_input_timeout` when the host cannot provide input; the game keeps running.
- `gamepad(playerIndex)` returns a snapshot in the browser's standard layout: `axes` (left x/y, right x/y from -1 to 1), seventeen `buttons`, `source` (`physical` or `virtual`) and `id`. `playerIndex` 0 is player 1.
- Buttons have positional names such as `south` and `east`. `pad.label("south")` gives the prompt to show: "A", "Cross" or "B" depending on the controller. `pad.has("dpad")` tells whether a control exists.
- Menu and Home belong to PlayDrop and always read released.
- Never call `navigator.getGamepads()`: phone controllers only reach games through the SDK, and PlayDrop logs a warning.

## Local player slots

`sdk.device.localPlayers` lists the slots players chose, `{ playerIndex, gamepadKey }`, and `onLocalPlayersChange(callback)` reports changes. A disconnected controller keeps its slot. When the roster changes or becomes empty, return to a sensible menu instead of crashing. One controller on its own is ordinary input, not a party.

From a button, `sdk.social.openParty({ mode: "local" })` opens PlayDrop's pairing window with the phone QR code and connected gamepads. Offer only the modes you declared.

## Local or online, not both

The host starts a game either as a local party or an online one, never both: local players cannot join online rooms. For online play with friends see [online parties and voice](https://www.playdrop.ai/create/learn/online-party).

## Design for the couch

Show each player's color and controller prompt, let anyone press a button to join, and keep the HUD readable from a sofa. Keep touch and keyboard controls for solo play.

## Related guides

- [Online parties and voice](https://www.playdrop.ai/create/learn/online-party): Let friends play together online: declare party sizes, open PlayDrop's party window, join reserved rooms with sdk.multiplayer.join and control room voice.
- [Full screen and safe areas](https://www.playdrop.ai/create/learn/viewport): Make a PlayDrop game fill the screen, keep its HUD inside CSS safe areas and clear of the host's controls using the SDK's measured reservedCorners.
- [catalogue.json](https://www.playdrop.ai/create/learn/catalogue-json): The catalogue.json fields PlayDrop games use: identity, listing, play modes, surfaces, sign-in, Instant, preloading, media, translations, scores and servers.
