@remix-gg/game-sdk
v0.3.0
Published
The Farcade SDK enables game developers to integrate their HTML5 games with the Remix platform through a simple messaging interface.
Downloads
132
Readme
Farcade SDK
The Farcade SDK enables game developers to integrate their HTML5 games with the Remix platform through a simple messaging interface.
Installation
Install the SDK using your preferred package manager:
npm install @farcade/game-sdk
# or
bun install @farcade/game-sdk
# or
yarn add @farcade/game-sdk
# or
pnpm add @farcade/game-sdkWhen you upload game code to Remix, a script tag to reference the SDK will automatically be added to your game code. The SDK will be accessible from window.FarcadeSDK.
Example Implementation
import type { GameState, Player, FarcadeSDK } from '@farcade/game-sdk'
class MyGame {
sdk: FarcadeSDK
player: Player
gameState: GameState | null = null
isMuted: boolean = true
// some example values that correlate to items purchased by boosting
canSaveGame: boolean = false
hasSuperSkin: boolean = false
constructor() {
// attach the sdk to the Game class to we can reference it easily
this.sdk = window.FarcadeSDK
// Setup event listeners
this.setupEventListeners()
// Initialize your game
this.initialize()
}
private async setupEventListeners() {
// Listen for play again events
this.sdk.onPlayAgain(() => {
this.resetGame()
})
// Listen for mute state changes
this.sdk.onToggleMute((data) => {
this.isMuted = data.isMuted
})
// Listen for purchase completions (optional)
this.sdk.onPurchaseComplete(() => {
this.checkPurchasedItems()
})
}
private async initialize() {
// wait for the sdk to get game information from Remix
await this.sdk.ready()
// get information the game uses from the SDK
this.player = this.sdk.player
this.gameState = this.sdk.gameState
// check which items the user has already purchased
this.checkPurchasedItems()
//... start the game logic
}
private checkPurchasedItems() {
// check the identifier for each item to see if the user has purchased it
if (this.sdk.hasItem('save-game')) {
this.canSaveGame = true
}
if (this.sdk.hasItem('super-skin')) {
this.hasSuperSkin = true
}
}
private async purchaseItem(itemId: string) {
// trigger the boost UI and then check for new items after
await this.sdk.purchase({ item: itemId })
this.checkPurchasedItems()
}
private gameOver(finalScore: number) {
//
this.sdk.singlePlayer.actions.gameOver({ score: finalScore })
}
private saveGame() {
// return unless the user has purchased the 'save-game' item
// see checkPurchasedItems
if (!this.canSaveGame) return
// push game state updates to save progress for the user
const gameState: GameState = this.getCurrentGameState();
this.sdk.singlePlayer.actions.saveGameState({ gameState })
}
private triggerHapticFeedback() {
this.sdk.hapticFeedback()
}
}API Reference
Properties and Getters
sdk.ready(): Promise<GameInfo>
This function will return when the SDK has recieved all the game information from Remix. You should await the call to this function before getting info from the SDK (sdk.player, sdk.gameState, etc)
sdk.isReady: boolean
Check if the SDK has received game info and is ready. More often, you will just await the call to sdk.ready(), but you may use this value if you prefer.
sdk.player: Player | undefined
Get the current player object.
sdk.players: Player[] | undefined
Get the list of all players in the game. This is useful for multiplayer games. In multiplayer games, it is essential that you use the players array so you can report scores with the associated player ids and notify players it is there turn.
sdk.gameState: GameState | null | undefined
Get the current game state. This will be null when there is no existing GameState for this game and user.
sdk.purchasedItems: string[]
Get the list of item IDs that the current player has purchased. This is a read-only property that reflects the purchasedItems array from the current player's GameInfo.
sdk.hasItem(item: string): boolean
Check if the current player has purchased a specific item.
Parameters:
item: The item identifier to check (string)
Returns:
trueif the player has purchased the item,falseotherwise
sdk.gameInfo: GameInfo | undefined
Get the current GameInfo object. This is all the data passed into the game from Remix. It is recommended that you use the other functions to access the specific data you need instead of pulling data out of this large object.
sdk.hapticFeedback()
Call this method to trigger haptic feedback on supported devices. Use this for important game events like collisions, achievements, or other significant player interactions.
Best Practices for Haptic Feedback
- Use haptic feedback sparingly to avoid overwhelming the player
- Reserve haptic feedback for meaningful interactions and achievements
- Consider using it for:
- Collisions with obstacles
- Collecting power-ups
- Completing levels
- Achieving high scores
- Important game events
sdk.purchase({ item: string }) => Promise<{ success: boolean }>
Call this function to initiate a purchase for an in-game item. This method sends a purchase request to the Remix platform and returns a promise that resolves with the purchase result. Make sure the item identifier matches an item you have added to your game using the Remix web app.
Parameters:
item: The identifier of the item to purchase (string)
Returns:
- A promise that resolves with
{ success: boolean }indicating whether the purchase was successful
The purchase flow works as follows:
- Call
purchase({ item: 'item-id' })to initiate the purchase - The platform handles the purchase transaction (payment processing, etc.)
- The promise resolves with
{ success: true }if the purchase succeeds, or{ success: false }if it fails - You can also listen for
purchase_completeevents usingsdk.onPurchaseComplete()for additional handling
Important: The purchasedItems array in GameInfo will be automatically updated after a successful purchase, and you can check item ownership using sdk.hasItem(item) or sdk.purchasedItems.
Single Player Actions
sdk.singlePlayer.actions.gameOver({ score: number })
Call this method when the game is over to report the final score.
Parameters:
score: The player's final score (number)
sdk.singlePlayer.actions.saveGameState({ gameState: Record<string, unknown> })
Call this method when you wish to persist game state for the user. This will enable users to save their progress in a game between play sessions.
Multi-Player Actions
Muliplayer has the same actions as singlePlayer with 2 updates and 1 addition. It is important to note that YOU
MUST use the gameInfo data from the response to ready() in order to accurately report scores with player ids when the game ends.
sdk.multiplayer.actions.gameOver({ scores: { playerId: string; score: number }[] })
Call this method with the game is over to report the final scores.
Parameters:
scores: The playerId and score for each player in the game.
sdk.multiplayer.actions.saveGameState({ gameState: Record<string, unknown>; alertUserIds: string[] })
Call this method when a player action should update the shared game state for all players. If your game has a concept of turns as most do, you must include the alertUserIds list with the id(s) of the player(s) that should be alerted it is their turn.
Parameters:
gameState: A Record object containing your game state. The shape of the game state is open to the game creator's discretion.alertUserIds: A list of player ids to alert on this game state update. Typically this will be a list of length 1 containing the id of the player who is next to act, but different games may need to alert multiple players.
sdk.multiplayer.actions.refuteGameState({ gameStateId: string })
Call this method when your game client has determined an incoming game state is invalid. It is not strictly required that your game validates game state updates, but it should. Putting game state validation logic in your game client means that bad actors attempting to push unfair updates are invalidated by good actors running valid implementations of your game.
Parameters:
gameStateId: The id from thegame_state_updatedevent that the game client is refutting.
sdk.multiplayer.actions.purchase({ item: string }) => Promise<{ success: boolean }>
Same as the single player purchase method. Call this method to initiate a purchase for an in-game item in multiplayer games. See the single player purchase documentation above for details.
Here is an example function that handles update and refute game state for a Chess game:
handleGameStateUpdate({ gameState }) {
if (!gameState) return;
const { id, gameState: { moves } } = gameState;
try {
this.chess.reset();
if (moves?.length > 0) {
for (const move of moves) {
this.chess.move(move);
}
}
this.renderBoard();
this.updateStatus();
this.updateMoveHistory();
this.updateCapturedPieces();
} catch (error) {
// game state is invalid, refuting this game state update
this.sdk.multiplayer.actions.refuteGameState({ gameStateId: id });
}
}Events
The SDK provides both generic event listeners and specific typed listener methods. We recommend using the specific listener methods for better type safety and clarity.
Event Listeners
sdk.onPlayAgain(callback: () => void)
Register a callback function that is called when the player wants to play again.
sdk.onToggleMute(callback: (data: { isMuted: boolean }) => void)
Register a callback function that is called when receiving mute state changes.
Parameters:
callback: Function that receives{ isMuted: boolean }indicating the current mute state
sdk.onGameStateUpdated(callback: (data: { id: string, gameState: Record<string, unknown> } | null) => void)
Register a callback function that is called when there is an update to the game state. This is essential for multiplayer games to receive state updates from other players.
Parameters:
callback: Function that receives the game state update data, ornullif the game state is cleared
sdk.onGameInfo(callback: (data: GameInfo) => void)
Register a callback function that is called when game information is received. This is typically called automatically when the game initializes, but you can listen for updates.
Parameters:
callback: Function that receives theGameInfoobject
sdk.onPurchaseComplete(callback: (data: { success: boolean }) => void)
Register a callback function that is called when a purchase completes. This can be used for additional handling beyond the promise returned by purchase(). It returns the same value as awaiting the call to purchase(), but sometimes users may boost your game without your game triggering the purchase function.
Parameters:
callback: Function that receives{ success: boolean }indicating whether the purchase succeeded
TypeScript Support
The SDK is written in TypeScript and includes full type definitions.
Example Multiplayer Implementation
Multiplayer game development is not yet available to all users, but the SDK supports it. Watch the Remix Discord for announcements about multiplayer game support.
import type { FarcadeSDK, GameState, Player } from '@farcade/game-sdk'
class Game {
sdk: FarcadeSDK
gameState: GameState
player: Player
players: Player[]
constructor() {
this.sdk = window.FarcadeSDK
// Initialize your game
this.initialize()
// Setup event listeners
this.setupEventListeners()
}
private setupEventListeners() {
// Listen for play again events
this.sdk.onPlayAgain(() => {
this.resetGame()
})
// Listen for mute state changes
this.sdk.onToggleMute((data) => {
this.setMuted(data.isMuted)
})
// Listen for game state updates (essential for multiplayer)
this.sdk.onGameStateUpdated((data) => {
const { id, gameState } = data
const newGameStateIsValid = this.validateGameState(gameState);
if (newGameStateIsValid) {
this.gameState = gameState
} else {
sdk.multiplayer.actions.refuteGameState({ gameStateId: id });
}
})
// Listen for purchase completions (optional)
sdk.onPurchaseComplete((data) => {
if (data.success) {
this.handlePurchaseSuccess()
}
})
}
private async initialize() {
await this.sdk.ready()
this.gameState = this.sdk.gameState
this.player = this.sdk.player
this.players = this.sdk.players
}
private saveGameState(gameState: Record<string, unknown>, nextTurnPlayerId: string) {
sdk.multiplayer.actions.saveGameState({
gameState,
alertUserIds: [nextTurnPlayerId],
})
}
private gameOver(scores: { playerId: string, score: number }[]) {
sdk.multiplayer.actions.gameOver({ scores })
}
private async purchaseItem(itemId: string) {
try {
const result = await sdk.multiplayer.actions.purchase({ item: itemId })
if (result.success) {
console.log(`Successfully purchased ${itemId}`)
// Item is now available via sdk.hasItem(itemId) or sdk.purchasedItems
// The purchasedItems array is automatically updated for all players
} else {
console.log(`Purchase failed for ${itemId}`)
}
} catch (error) {
console.error('Purchase error:', error)
}
}
}License
MIT
