Skip to main content
Version: 5.x
Supported on
Snapchat

Turn Based

Turn Based is a component for building turn-based game flows using Snapchat's Turn Based Dynamic Response API. This component enables two player asynchronous Lenses where users take sequential actions and share game state between turns.

Turn Based Lens

The Turn Based Component extends the standard Dynamic Response system to enable a unique Lens format that supports back-and-forth responses for turn based games and experiences:

  1. Player 1 (Poster) opens the Lens equipped with the Turn Based custom component, makes their move by setting turnVariables, takes a Snap, and sends it to Player 2.
  1. Player 2 (Responder) receives the Snap, taps a Tappable Area or the Your Turn CTA button to enter the Lens.
  2. Player 2 loads the game state from the promptVariables, makes their own move, sets the turnVariables, takes a Snap, and sends it back to Player 1.
  3. The game continues alternating between players until the turn limit is reached or a player manually ends the game using setIsFinalTurn(true).

Unlike standard Dynamic Response which supports one-way data transfer, Turn Based Dynamic Response creates a bidirectional game loop where each player's turn becomes the starting state for the next player's turn. Game state, turn history, and user data are automatically serialized and transferred between players through associatedData.

Please note that this feature does not support image/texture transfer.

The component handles the complexity of turn management, data serialization, user role detection, and scene object toggling, allowing creators to focus on game logic rather than the underlying Dynamic Response infrastructure.

Common use cases include:

  • Word Games - Players take turns adding letters or words.
  • Strategy Games - Chess, checkers, or custom board games.
  • Quiz Games - Players answer questions in sequence.
  • Puzzle Games - Building or solving puzzles together.

Turn Data

Turn data allows Lenses to share interactive states across Snaps. Turn data is serialized automatically and passed using associatedData.

Turn data includes:

  • tappableAreas - Array of tappable areas, each tappable area consists of key and screen transform. If screen transform or its scene object is disabled area will be skipped.
  • turnVariables - Array of variables to be set in the current turn and passed to the next turn.
  • promptVariables - Array of turn variables from the previous turn.
  • turnHistory - Historical record of previous turns (if enabled).

Understanding Turn Data Flow:

The Turn Based Component uses a simple model for managing game state across turns. Data is passed between players using Prompt Variables and Turn Variables.

You can think of this as sending and receiving packages:

  • Prompt Variables: When the player’s turn begins, they receive a package from the previous player. This package contains Prompt Variables — data the previous player included in their Turn Variables before ending their turn. You can inspect these values using getPromptVariable() or getPromptVariables().

  • Turn Variables: During your turn, you prepare a new package to send. This is your set of Turn Variables — the game state you define using setTurnVariable(). When the player takes a Snap, the package is sealed and sent to the next player, where it will arrive as their Prompt Variables. If requireTurnSubmission is enabled, calling endTurn() will seal the package early and make sure it can't be modified before a Snap is taken.

  • Passing Data Forward: If you want the next player to have access to something from your current Prompt Variables, you must explicitly copy it into your Turn Variables. Prompt data is read-only — it won’t automatically persist unless you send it forward.

Peristent Variables
Turn variables will not persist between turns. In order to persist any variable between turn, first get the value using getPromptValue(), and then set the value using setTurnValue().

Installing the Component

The Turn Based custom component is available in LS Asset Library. Press Install or Update and then add it to the Asset Browser panel by clicking the + button and looking up Turn Based.

Basic Setup

  1. Add to Scene - Add the Turn Based component to a scene object or drag it into the Scene Hierarchy from the Asset Browser.
  2. Setup Component Inputs - Configure turn limit, tappable areas, and turn variables.
  3. Call Component API - Use the provided methods to control game flow in your custom game logic.

Component Inputs

Game Configuration

InputDescription
Require Turn SubmissionIf true, component will emit onError events for incomplete turn data. Call endTurn() to mark turn data as complete.
Use Turn LimitIf true, user can set turn limit for game session. Game ends when turn limit is exceeded.
Turn LimitMaximum number of turns (used if Use Turn Limit is enabled).
Use Turn HistoryIf true, turn history data will be serialized.
Turns Saved LimitMaximum number of entries stored in turn history.
Turn VariablesArray of initial variables for turn data storage.

Interactive Areas and Scene Objects

InputDescription
Tappable AreasArray of tappable areas consisting of key and screen transform. Disabled areas will be skipped.
User 1 Scene ObjectsScene objects enabled for User 1's turn.
User 2 Scene ObjectsScene objects enabled for User 2's turn.
Game Over Scene ObjectsScene objects shown when game ends (if Require Turn Submission enabled).

Tappable Areas Limitations
All excess tappable areas that do not comply with these limitations will be skipped:

  • Max number of tappable areas sent: 16.
  • Max total screen area coverage of tappable areas: 0.4.
  • Max length of tappable area key: 24 symbols.
  • Limits of tappable area center position in screen coordinates: 0.05 < x < 0.95, 0.05 < y < 0.95.
  • Min tappable area aspect ratio in screen coordinates (ratio of minimum and maximum sides): 0.125.

Debug Settings

InputDescription
Debug ModeChoose debug type: None, Single Turn, or Simulate Turns.
Tapped KeyKey of tappable area for testing in editor.
Reset Simulate TurnsReset simulated game session in editor (Simulate Turns mode).
Turn CountTurn count for debug (Single Turn mode).
Test Data TypeInput type for test data: JSON String or Studio Inputs (Single Turn mode).
Test Is Turn CompleteFlag if editor turn is complete (Single Turn mode).
Test DataDebug prompt data input (Single Turn mode).
Test Turn HistoryDebug turn history input (Single Turn mode).
Print LogsIf true, component will print debug logs.

Component API

Methods

MethodReturn TypeDescription
getCurrentUserIndex()Promise<number>Returns index of current user, starting from 0.
getTappedKey()stringKey of tappable area which was tapped by current user before lens opened. Empty string if no tappable area was tapped.
addTappableArea(key: string, screenTransform: ScreenTransform)voidAdd tappable area described by screenTransform with key.
removeTappableArea(key: string)voidRemove tappable area by key.
clearTappableAreas()voidClear tappable areas array.
getTurnCount()Promise<number>Current turn count, starting from 0.
getPromptVariable(key: string)Promise<UserDefinedGameVariable | undefined>Get prompt data variable by key, where UserDefinedGameVariable is number, string, boolean or dictionary or array of these values.
getPromptVariables()Promise<UserDefinedGameVariablesMap>Get prompt data (data received with snap) variables (dictionary with strings as key and UserDefinedGameVariable as value). Will be empty if it is the first turn.
getTurnVariable(key: string)UserDefinedGameVariable | undefinedGet turn variable (data which will be sent with snap to next user). If value is an object or array, please call setTurnVariable after updating it to ensure that changes are properly handled.
setTurnVariable(key: string, value: UserDefinedGameVariable)voidSet turn variable.
removeTurnVariable(key: string)voidSet turn variable to undefined.
clearTurnVariables()voidClear all turn variables.
getCurrentUserDisplayName()Promise<string>Get display name of current user.
getOtherUserDisplayName()Promise<string>Get display name of other user.
isFinalTurn()Promise<boolean>Returns true if turn is final turn because turn limit has been reached or user set is final turn to true.
getTurnHistory()Promise<TurnHistoryEntry[]>Get array of turn history entries for several last turns ordered by turn count. Turn history is empty if it is the first turn. If it is not empty, the last turn will always have the same data as in the prompt. TurnHistoryEntry has following properties: turnCount: number; userDefinedGameVariables: UserDefinedGameVariablesMap; isTurnComplete: boolean.
getTurn(turnCount: number)Promise<TurnHistoryEntry>Turn history entry for turn with provided turn count. May be null if this turn does not exist in turn history.
getPreviousTurn()Promise<TurnHistoryEntry>Get turn history entry of previous turn. May be null if this turn does not exist in turn history. Has the same data as in the prompt.
setIsFinalTurn(isFinalTurn: boolean)voidIf true is set, this turn will be the last in game session.
endTurn()voidMarks turn as complete if requireTurnSubmission is enabled. Changing turn variables is not possible after it.
getUser(index: number)Promise<SnapchatUser | null>Returns Snapchat user for user with provided index, returns null if it is the current user. Can be used to load bitmoji of this user. Promise is rejected if there was an error while loading the user.

Object/Array Variables
If the turn variable is an object or array, please call setTurnVariable after updating it to ensure that changes are properly handled. For example:

turnBased.getTurnVariable('throw_data').force = 100; // may not be saved
// correct usage:
const throwData = turnBased.getTurnVariable('throw_data');
throwData.force = 100;
turnBased.setTurnVariable('throw_data', throwData);

User Loading
getUser(index: number) returns null for the current user and rejects the promise if there was an error while loading the user.

Events

EventTypeDescription
onTurnStartEvent<>Event is triggered when prompt data has been loaded and turn started. Event passed in callback provides following properties: currentUserIndex: number - index of current user (0 or 1), tappedKey: string - key of tappable area which was tapped by current user before lens opened, turnCount: number - current turn count, promptDataVariables: IUserDefinedGameVariablesMap - prompt data variables (dictionary).
onTurnEndEvent<>Event is triggered when endTurn has been called and it is not the last turn, if requireTurnSubmission is enabled.
onGameOverEvent<>Event is triggered when endTurn has been called and it is last turn, if requireTurnSubmission is enabled.
onErrorEvent<>Event is triggered if an error has occurred. Event passed in callback provides following properties: code: string - possible values: INCOMPLETE_TURN_DATA_SENT, INCOMPLETE_TURN_DATA_RECEIVED, description: string.

Usage Example

LoadOtherUserBitmoji

Loads the other user's Bitmoji avatar using the Bitmoji 3D component. Note that the "Auto Download" option should be disabled on the Bitmoji 3D component.

@component
export class LoadOtherUserBitmoji extends BaseScriptComponent {
@input('Component.ScriptComponent')
turnBased: TurnBased;

@input('Component.ScriptComponent')
bitmojiComponent: ScriptComponent & {
downloadAvatarForUser: (user: SnapchatUser) => void;
};

onAwake() {
this.createEvent('OnStartEvent').bind(() => {
this.loadAvatarForOtherUser().catch((e) =>
print('Error loading avatar for other player: ' + e)
);
});
}

private async loadAvatarForOtherUser(): Promise<void> {
const turnCount = await this.turnBased.getTurnCount();
// We can only load the avatar for the other user if there is at least one turn
if (turnCount > 0) {
// Get the index of the current user and the other user
const currentUserIndex = await this.turnBased.getCurrentUserIndex();
const otherUserIndex = currentUserIndex === 0 ? 1 : 0;

// Retrieve the other user by index
const otherUser = await this.turnBased.getUser(otherUserIndex);
if (otherUser) {
// Download the avatar for the other user
this.bitmojiComponent.downloadAvatarForUser(otherUser);
}
}
}
}

Best Practices

User Experience:

  • Provide clear visual feedback for whose turn it is.
  • Include turn history playback for complex games.

Error Handling:

  • Always listen for onError events and provide user feedback.
  • Use requireTurnSubmission for games requiring complete data.
  • Validate game state before calling endTurn().

Debugging and Testing

Debug Modes

Debug settings only work in Lens Studio editor and have no effect in published lenses.

The component provides three debug modes for testing:

  • None - Normal operation (use in production)
  • Single Turn - Test specific turn scenarios in editor
  • Simulate Turns - Full turn sequence simulation in editor

Simulate Turns


When debugMode is set to Simulate Turns, the Turn Based Custom Component stores session data in Lens Studio's persistent editor memory. Each time the Snap Capture button is pressed, the following sequence occurs:

Current Turn is Serialized - The current turn data—including any turn variables set via setTurnVariable() are saved internally as if a Snap were sent.

Turn Advances - The session progresses to the next turn. This simulates the responder receiving the Snap and loading the Lens with updated data. After pressing the capture button, the user must close the captured Snap (Click the "x" in the top-left corner of the preview) and reset the preview window to load the next turn.

Preview Reset Required
You must reset the preview after capturing a Snap to iterate to the next turn. The turn will not advance until you stop and restart the preview.

Role Swaps - The user role alternates between Poster (User 1) and Responder (User 2) based on the turn count.

Prompt Variables Propagation - The final state of the previous turn and any turn variables set using setTurnVariable() are passed forward as promptVariables, allowing you to confirm correct data handoff between turns using getPromptVariables().

Scene Objects Update - The user1SceneObjects or user2SceneObjects are toggled automatically based on the simulated user role and turn count.

Reset Simulate Turns - In order to reset the turn count to 0, you must toggle on Reset Simulate Turns. The preview will be reset automatically as if it is the first game turn (turn count 0). After playing the first turn, take a Snap, close the Snap, and toggle off Reset Simulate Turns to progress to the next turn.

Previewing Your Lens

To preview your Turn Based Lens in Snapchat, follow the Pairing to Snapchat guide. A helpful testing flow to follow is:

  1. Push the lens to your device in order to test Player 1 (Poster) flow
  2. Take a Snap after making your first move
  3. Send the Snap to yourself to simulate sending to Player 2
  4. Open the Snap to test Player 2 (Responder) flow and make the next move
  5. Take another Snap and send it back to yourself to continue the turn sequence
  6. Repeat steps 4-5 to test the complete turn-based game flow

Note that you must send Snaps to yourself during development, since other users will not be able to interact with your lens while you are using push to device flow.

Was this page helpful?
Yes
No