PlayDrop
PlayDrop could not load

A required part of the page failed to download. Try loading it again.

STYLESHEET_ERROR
PlayDrop logoPlayDrop Studio
PlayDrop logoPlayDrop Studio
CreatePlayTradeEarnLearnConnectorsCommunitySupport
Client SDK
Documentation

Start here

OverviewYour first game

Create with Cloud

Cloud creationPublish & importPlans & generationsCredits & rewards

Connect your agent

All connectorsClaudeChatGPTClaude CodeCodexCursorGeminiAntigravityGrok BuildGrok BotGrok ChatLovableReplit

Technical reference

Game filescatalogue.jsonClient SDKServer SDKTroubleshootingFAQ
DocumentationClient SDK
Technical reference

PlayDrop client SDK for browser games

Browser SDK for PlayDrop games: host lifecycle, sign-in, saves, leaderboards, purchases, ads, friends, controllers, multiplayer and shared libraries, with one script tag.

Games played inside PlayDrop integrate the SDK for host-managed pause, audio and HUD clearance. Saves, achievements, purchases, social features, multiplayer and AI are optional services. PlayDrop Cloud integrates the SDK; with PlayDrop Connector, your agent adds its script tag.

Add the SDK and follow the host lifecycle

html
<script src="https://assets.playdrop.ai/sdk/playdrop.js"></script>
<script type="module">
  const sdk = await playdrop.init();
  setAudioEnabled(sdk.host.audioAllowed);
  setPaused(sdk.host.isPaused);
  layoutHud(sdk.host.reservedCorners);
  sdk.host.onAudioAllowedChange(setAudioEnabled);
  sdk.host.onPause(() => setPaused(true));
  sdk.host.onResume(() => setPaused(false));
  sdk.host.onReservedCornersChange(layoutHud);
  // Render the first playable frame and prepare input, then:
  sdk.host.ready();
</script>

Load the SDK from PlayDrop's CDN. Read initial host state and subscribe before ready(). Render the first playable frame and prepare input before signaling readiness. Keep simulation paused while the host is paused; resume without duplicate loops or elapsed-time jumps.

reservedCorners contains topLeft and topRight width/height in CSS pixels measured from the game viewport corners. Render game content edge-to-edge; HUD avoids the union of these rectangles and CSS hardware safe areas, never their sum or a full-width top band. Zero means clear; null means an older host, so keep the existing layout. Bounds update as the host layout changes. Unsubscribe when tearing down the game.

Host mute overrides game preferences. audioAllowed combines host policy, phase and pause, but permits audio during a hidden-browser-tab pause. Readiness warnings report missing integration, not proof of correct gameplay behavior.

Identity, saves and language

sdk.me exposes player identity and sdk.me.appData stores private saves; sdk.achievements and sdk.leaderboards handle achievements and scores. Saves, achievements and leaderboards work without a login pre-check. Use sdk.me.isLoggedIn for features that require a real account, such as purchases or multiplayer. Preview and capture modes must not write player progress. sdk.host.language gives the player's language, any of PlayDrop's 20; sdk.host.locale keeps to the original ten for older games and reads en for the others. Ship English plus your own language when it is different. Translating a listing does not translate game content. At a natural break, such as a win, sdk.host.requestReview() lets PlayDrop ask the player for a review, at most once per game; your game never learns the answer, so never reward it.

Libraries, assets and multiplayer

sdk.libs loads supported Three.js, Phaser, Rapier, nipplejs and Colyseus versions. sdk.assets provides catalog, pack and asset references; sdk.social provides friends, game cards and share actions. For hosted multiplayer, sdk.multiplayer.getConnection() returns the server address and the signed-in player's token; join with the Colyseus client. The server SDK page covers hosted servers; a server you run yourself needs nothing from the SDK. The old relay room APIs are retired.

Test with the SDK before you publish

Run your usual dev server and open https://www.playdrop.ai/creators/<username>/apps/game/<slug>/dev?url=http://localhost:5173/ in Chrome to play it inside the real PlayDrop frame with the SDK host. Any localhost port or https URL works. Features that need an account, such as saves and purchases, work once the game has been uploaded once; a private upload is enough. Browser media generation runs as asynchronous tasks with a host-confirmed credit cost. See catalogue.json for listing metadata.

Play together

Use await sdk.multiplayer.join("game") in the play phase. It joins independently or consumes the host's party reservation. A party failure rejects instead of silently splitting players into another room. getConnection() remains the immediate connection-details API for existing games. Keep the same room across rounds, and keep networking alive while host overlays pause game input.

Use sdk.social.openParty() from a player action to open the host's party popup. Read membership with await sdk.social.getParty() or sdk.social.onPartyChange(callback). Games cannot mutate platform parties or control microphones. Party and room voice live in the web/native host and remain subject to player consent, mute, blocks and rollout eligibility.

For smooth room playback, call sdk.multiplayer.voice.updateSpatialState({ listener: { position, forward, up }, speakers: [{ userId, position }] }), using finite { x, y, z } vectors. Hints affect volume and panning, never authorization. The server enforces teams and proximity eligibility.

Use sdk.device.localPlayers and sdk.device.onLocalPlayersChange(callback) for the selected local controller slots { playerIndex, gamepadKey }. Connected controller inventory is separate; a disconnected slot keeps its identity. Local mode cannot join online rooms. The copyable playdrop-metagame/recipes/play-together recipe demonstrates both modes, two destinations and room policies.

Controllers

Read physical controllers and PlayDrop phone controllers through sdk.device, the same way on every platform. Call enableControllerInput() once after init(), read gamepad(playerIndex) in the game loop (0 is P1), and use onButton for presses and releases. Axes and buttons follow the browser's standard gamepad order; buttons have positional names such as south and east, and pad.label("south") returns the prompt for that controller, such as "A" or "Cross". Menu belongs to PlayDrop and pauses the game.

js
await sdk.device.enableControllerInput();
const stop = sdk.device.onButton(({ playerIndex, button, pressed }) => {
  if (button === "south" && pressed) jump(playerIndex);
});
function update() {
  const pad = sdk.device.gamepad(0);
  if (pad?.connected) move(pad.axes[0], pad.axes[1]);
  requestAnimationFrame(update);
}
update();

Do not call navigator.getGamepads(): phone controllers reach games only through the SDK, and PlayDrop logs a warning when a game reads the browser API directly. If the host cannot provide controller input, enableControllerInput() rejects with controller_input_unavailable or controller_input_timeout and the game keeps running. pad.has("dpad") tells whether a control exists; declare the controls your game needs in catalogue.json.

Previouscatalogue.json: PlayDrop game metadata and localizationNextPlayDrop game servers: Colyseus, MongoDB and the server SDK
View Markdown
EnglishFrançaisDeutsch日本語한국어EspañolPortuguês (Brasil)Bahasa Indonesia繁體中文简体中文ItalianoPolskiNederlandsSvenskaNorsk bokmålSuomiTürkçeไทยTiếng Việtالعربية

On this page

Add the SDK and follow the host lifecycleIdentity, saves and languageLibraries, assets and multiplayerTest with the SDK before you publishPlay togetherControllers
View Markdown