vapour
Copyright (c) 2025 Renata Amutio SPDX-License-Identifier: MIT
Vapour - Steamworks SDK Bindings for Gleam
Vapour provides type-safe, idiomatic Gleam bindings for the Steamworks SDK via steamworks-ffi-node.
Features
- Core API: Initialize Steamworks, run callbacks, check connection status
- Achievements: Unlock/lock achievements, list achievements, track progress, get global unlock percentages (async with Promises)
- Cloud Storage: Save/load files to Steam Cloud, manage cloud settings
- Rich Presence: Set player status visible to friends (e.g., “In Menu”, “Playing Level 3”)
- Overlay: Trigger Steam overlay dialogs (friends, achievements, store, web pages, invite multiplayer)
- Stats: Track player statistics, get/set int and float stats, global stats, user stats, average rate stats (async with Promises)
- Friends: Get friends list, check online status, view friend info, avatars, relationship status, coplay (recently played with) features
- Leaderboards: Find/create leaderboards, upload scores, download entries with custom sort/display options (async with Promises)
Quick Start
import gleam/option
import vapour
pub fn main() {
// Initialize with your app ID (or use 480 for testing with Spacewar)
let assert Ok(client) = vapour.init(option.Some(480))
// Run callbacks regularly to keep the connection alive
vapour.run_callbacks(client)
// Use the API
let name = vapour.display_name(client)
let _result = vapour.write_file(client, "save.dat", "game data")
}
Important Notes
- Call
run_callbacks()regularly (every frame or every 100ms) to process Steam events - Achievement, Stats, and Leaderboard functions return Promises - use
gleam/javascript/promiseto handle them - Steam must be running for initialization to succeed
- Cloud storage requires Steam Cloud to be enabled for your app and the user’s account
Types
Steam Cloud storage quota information.
pub type CloudQuota {
CloudQuota(
total_bytes: Int,
available_bytes: Int,
used_bytes: Int,
percent_used: Float,
)
}
Constructors
-
CloudQuota( total_bytes: Int, available_bytes: Int, used_bytes: Int, percent_used: Float, )
pub type Dialog {
FriendsDialog
CommunityDialog
PlayersDialog
SettingsDialog
OfficialGameGroupDialog
StatsDialog
AchievementsDialog
}
Constructors
-
FriendsDialog -
CommunityDialog -
PlayersDialog -
SettingsDialog -
OfficialGameGroupDialog -
StatsDialog -
AchievementsDialog
Information about a file stored in Steam Cloud.
pub type FileInfo {
FileInfo(name: String, bytes: Int)
}
Constructors
-
FileInfo(name: String, bytes: Int)
Information about a friend.
pub type FriendInfo {
FriendInfo(
steam_id: String,
persona_name: String,
persona_state: PersonaState,
)
}
Constructors
-
FriendInfo( steam_id: String, persona_name: String, persona_state: PersonaState, )
Steam friend relationship status.
Describes the relationship between the current user and another Steam user. This includes friend status, pending requests, and blocked users.
pub type FriendRelationship {
RelationshipNone
RelationshipBlocked
RelationshipRequestRecipient
RelationshipFriend
RelationshipRequestInitiator
RelationshipIgnored
RelationshipIgnoredFriend
RelationshipSuggested
RelationshipMax
}
Constructors
-
RelationshipNoneNo relationship
-
RelationshipBlockedUser has blocked this person
-
RelationshipRequestRecipientThis person sent you a friend request (pending)
-
RelationshipFriendThis person is your friend
-
RelationshipRequestInitiatorYou sent this person a friend request (pending)
-
RelationshipIgnoredYou have ignored this person
-
RelationshipIgnoredFriendYou were friends but now ignored
-
RelationshipSuggestedSteam suggested this person as a friend
-
RelationshipMaxUnknown/max relationship value
Opaque type representing a Steam leaderboard.
This handle is obtained from find_leaderboard() or find_or_create_leaderboard()
and is used to interact with that specific leaderboard (uploading scores, downloading entries, etc.).
pub type LeaderBoard
Leaderboard data request type.
Specifies which subset of leaderboard entries to download.
pub type LeaderboardDataRequest {
Global
GlobalAroundUser
Friends
}
Constructors
-
GlobalDownload the top entries from the entire global leaderboard
-
GlobalAroundUserDownload entries around the current user’s position
-
FriendsDownload entries for friends only
Leaderboard display type.
Determines how scores are formatted and displayed in the Steam UI.
pub type LeaderboardDisplayType {
DisplayNone
Numeric
TimeSeconds
TimeMilliseconds
}
Constructors
-
DisplayNoneNo special display format
-
NumericDisplay as a plain number (e.g., “12345”)
-
TimeSecondsDisplay as time in seconds (e.g., “1:23.45”)
-
TimeMillisecondsDisplay as time in milliseconds (e.g., “1:23.456”)
Leaderboard entry.
pub type LeaderboardEntry {
LeaderboardEntry(
steam_id: String,
global_rank: Int,
score: Int,
)
}
Constructors
-
LeaderboardEntry(steam_id: String, global_rank: Int, score: Int)
Leaderboard sort method.
Determines how leaderboard entries are ranked.
pub type LeaderboardSortMethod {
SortNone
Ascending
Descending
}
Constructors
-
SortNoneNo sorting
-
AscendingLower scores are better (e.g., speedruns, golf scores)
-
DescendingHigher scores are better (e.g., high scores, points)
Steam user’s online status (persona state).
This represents the current online status that a user has set in Steam. The status is visible to friends and affects how the user appears in friend lists.
pub type PersonaState {
Offline
Online
Busy
Away
Snooze
LookingToTrade
LookingToPlay
Invisible
Max
}
Constructors
-
OfflineUser is offline or appear offline
-
OnlineUser is online and available
-
BusyUser is online but busy (Do Not Disturb)
-
AwayUser is away from keyboard
-
SnoozeUser is snoozing/sleeping
-
LookingToTradeUser is looking to trade items
-
LookingToPlayUser is looking for people to play with
-
InvisibleUser is online but invisible to others
-
MaxUnknown/max state value
Steam API status information.
pub type Status {
Status(is_initialized: Bool, app_id: Int, steam_id: String)
}
Constructors
-
Status(is_initialized: Bool, app_id: Int, steam_id: String)
Opaque type representing a connected Steamworks client.
This is obtained by calling init() and is required for all other API calls.
pub type SteamworksClient
Leaderboard score upload method.
Determines how new scores are handled when uploading to a leaderboard.
pub type UploadScoreMethod {
KeepBest
ForceUpdate
}
Constructors
-
KeepBestOnly update if the new score is better than the current score
-
ForceUpdateAlways update, regardless of whether it’s better or worse
Values
pub fn achievement_achieved_percent(
client: SteamworksClient,
achievement: String,
) -> promise.Promise(Result(Float, Nil))
Get global unlock percentage for an achievement (async).
Returns what percentage of all players have unlocked this achievement (0-100).
Must call request_global_achievement_percentages() first.
Example
import gleam/javascript/promise
use request_successful <- promise.await(
vapour.request_global_achievement_percentages(client),
)
case request_successful {
True -> {
vapour.achievement_achieved_percent(client, "ACH_WIN_ONE_GAME")
|> promise.await(fn(result) {
case result {
Ok(percent) ->
io.println(float.to_string(percent) <> "% of players have this")
Error(_) -> io.println("Data not available")
}
promise.resolve(Nil)
})
}
False -> promise.resolve(Nil)
}
pub fn activate_dialog(
client: SteamworksClient,
dialog: Dialog,
) -> Nil
Activate a Steam overlay dialog.
Opens the Steam overlay to a specific dialog.
Example
// Open achievements dialog
vapour.activate_dialog(client, AchievementsDialog)
// Open friends list
vapour.activate_dialog(client, FriendsDialog)
pub fn activate_store(
client: SteamworksClient,
app_id: Int,
) -> Nil
Activate the Steam overlay to a store page.
Opens the Steam store to the specified app’s page.
Parameters
app_id: The Steam App ID to show in the store
Example
// Open your game's DLC store page
vapour.activate_store(client, 12345)
// Open your game's main store page
vapour.activate_store(client, YOUR_APP_ID)
pub fn activate_user_page_dialog(
client: SteamworksClient,
steam_id: SteamId,
) -> Nil
Activate the Steam overlay to a specific user’s profile.
Parameters
steam_idThe user’s Steam ID
Example
// Open a friend's profile
vapour.activate_user_page_dialog(client, steam_id)
pub fn activate_web_page(
client: SteamworksClient,
url: String,
) -> Nil
Activate the Steam overlay browser to a web page.
Opens the specified URL in the Steam overlay browser.
Example
// Open game website
vapour.activate_web_page(client, "https://mygame.com")
// Open wiki page
vapour.activate_web_page(client, "https://wiki.mygame.com/walkthrough")
pub fn all_friends(client: SteamworksClient) -> List(FriendInfo)
Get all friends with their information.
Returns a list of all friends with their Steam ID, name, and online status.
Example
let friends = vapour.all_friends(client)
list.each(friends, fn(friend) {
io.println(friend.persona_name <> " (" <> friend.steam_id <> ")")
})
pub fn clear_rich_presence(client: SteamworksClient) -> Nil
Clear all Rich Presence data.
Removes all Rich Presence information for the current player. Friends will no longer see detailed status about what you’re doing in the game.
Call this when the player exits your game or when you want to hide their current activity.
Example
// Clear rich presence when exiting game
vapour.clear_rich_presence(client)
pub fn cloud_enabled_for_account(
client: SteamworksClient,
) -> Bool
Check if Steam Cloud is enabled for the current user’s account.
Returns True if the user has Steam Cloud enabled in their Steam settings.
Example
case vapour.cloud_enabled_for_account(client) {
True -> io.println("Cloud enabled for account")
False -> io.println("Cloud disabled - user must enable it in Steam settings")
}
pub fn cloud_enabled_for_app(client: SteamworksClient) -> Bool
Check if Steam Cloud is enabled for the current app.
Returns True if Steam Cloud is enabled for this app. This can be toggled
using toggle_cloud_for_app().
pub fn cloud_quota(client: SteamworksClient) -> CloudQuota
Get Steam Cloud storage quota information.
Returns detailed information about cloud storage usage including total, available, and used bytes, plus the percentage used.
Important: This helps prevent “out of space” errors when saving files. Always check available space before writing large files to Steam Cloud.
Example
let quota = vapour.cloud_quota(client)
io.println("Cloud Storage:")
io.println(" Total: " <> int.to_string(quota.total_bytes) <> " bytes")
io.println(" Used: " <> int.to_string(quota.used_bytes) <> " bytes")
io.println(" Available: " <> int.to_string(quota.available_bytes) <> " bytes")
io.println(" Usage: " <> float.to_string(quota.percent_used) <> "%")
// Check before saving
let save_size = 1_000_000 // 1 MB
case quota.available_bytes > save_size {
True -> vapour.write_file(client, "savegame.dat", save_data)
False -> io.println("Not enough cloud storage space!")
}
pub fn coplay_friend(
client: SteamworksClient,
index: Int,
) -> String
Get a coplay friend by index.
Use this with coplay_friend_count() to iterate through all friends you’ve
recently played with.
Parameters
index: Zero-based index (0 to coplay_friend_count() - 1)
Returns
The Steam ID of the coplay friend at the specified index.
Example
let count = vapour.coplay_friend_count(client)
let first_coplay_friend = vapour.coplay_friend(client, 0)
io.println("Recently played with: " <> first_coplay_friend)
pub fn coplay_friend_count(client: SteamworksClient) -> Int
Get the count of coplay friends.
What is Coplay? “Coplay” refers to Steam users you have recently played multiplayer games with. Steam tracks which friends you’ve played together with in the same game session, and this data is used to suggest friends to play with and show recent gaming partners.
Returns the number of friends in your coplay list (friends you’ve recently played with).
Example
let coplay_count = vapour.coplay_friend_count(client)
io.println("You've recently played with " <> int.to_string(coplay_count) <> " friends")
pub fn delete_file(
client: SteamworksClient,
name: String,
) -> Bool
Delete a file from Steam Cloud.
Returns True if the file was successfully deleted, False otherwise.
Example
case vapour.delete_file(client, "old_save.dat") {
True -> io.println("File deleted")
False -> io.println("Failed to delete file")
}
pub fn display_name(client: SteamworksClient) -> String
Get the local player’s display name (persona name).
Returns the Steam display name that other users see.
Example
let name = vapour.display_name(client)
io.println("Welcome, " <> name <> "!")
pub fn do_activate_user_page_dialog(
client: SteamworksClient,
dialog: String,
steam_id_64: String,
) -> Nil
pub fn download_scores(
client: SteamworksClient,
leaderboard_handle: LeaderBoard,
data_request: LeaderboardDataRequest,
start: Int,
end: Int,
) -> promise.Promise(List(LeaderboardEntry))
Download leaderboard entries (async).
pub fn file_exists(
client: SteamworksClient,
name: String,
) -> Bool
Check if a file exists in Steam Cloud.
Returns True if the file exists, False otherwise.
Example
case vapour.file_exists(client, "savegame.json") {
True -> load_save_file(client)
False -> create_new_game()
}
pub fn find_leaderboard(
client: SteamworksClient,
leaderboard_name: String,
) -> promise.Promise(Result(LeaderBoard, Nil))
Find a leaderboard by name (async).
Returns a leaderboard handle, or Error(Nil) if not found.
pub fn find_or_create_leaderboard(
client: SteamworksClient,
name: String,
sort_method: LeaderboardSortMethod,
display_type: LeaderboardDisplayType,
) -> promise.Promise(Result(LeaderBoard, Nil))
Find or create a leaderboard with sort and display settings (async).
Searches for a leaderboard by name and creates it if it doesn’t exist. Allows you to specify how scores are sorted and displayed.
Parameters
name: Leaderboard name (max 128 UTF-8 bytes)sort_method: How entries should be sorted (Ascending for times, Descending for scores)display_type: How scores should be displayed (Numeric, TimeSeconds, etc.)
Returns
A Promise that resolves to Ok(leaderboard) or Error(Nil).
Example
import gleam/javascript/promise
import vapour.{Descending, Numeric}
// Create a high score leaderboard
vapour.find_or_create_leaderboard(client, "HighScores", Descending, Numeric)
|> promise.await(fn(result) {
case result {
Ok(leaderboard) -> io.println("Leaderboard ready")
Error(_) -> io.println("Failed to create leaderboard")
}
promise.resolve(Nil)
})
// Create a speedrun leaderboard (lower time is better)
vapour.find_or_create_leaderboard(client, "Speedrun", Ascending, TimeSeconds)
|> promise.await(fn(result) {
case result {
Ok(lb) -> io.println("Speedrun leaderboard ready")
Error(_) -> io.println("Failed")
}
promise.resolve(Nil)
})
pub fn friend_coplay_game(
client: SteamworksClient,
steam_id: String,
) -> Int
Get which game you last played with a specific user.
Returns the Steam App ID of the game you most recently played together. Returns 0 if you’ve never played together or the data is unavailable.
Example
let app_id = vapour.friend_coplay_game(client, friend_id)
case app_id {
0 -> io.println("No coplay game")
_ -> io.println("Last played together in App ID: " <> int.to_string(app_id))
}
pub fn friend_coplay_time(
client: SteamworksClient,
steam_id: String,
) -> Int
Get when you last played with a specific user.
Returns a Unix timestamp (seconds since January 1, 1970) of when you last played a multiplayer game together with this friend. Returns 0 if you’ve never played together or the data is unavailable.
Example
let timestamp = vapour.friend_coplay_time(client, friend_id)
case timestamp {
0 -> io.println("Never played together")
_ -> io.println("Last played together: " <> int.to_string(timestamp))
}
pub fn friend_count(client: SteamworksClient) -> Int
Get the count of friends.
Returns the total number of friends in your friends list.
Example
let count = vapour.friend_count(client)
io.println("You have " <> int.to_string(count) <> " friends")
pub fn friend_game_played(
client: SteamworksClient,
steam_id: String,
) -> Result(Int, Nil)
Get the game a friend is currently playing.
Returns the App ID of the game the friend is playing, or Error(Nil) if not playing.
Example
case vapour.friend_game_played(client, friend_id) {
Ok(app_id) -> io.println("Friend is playing App " <> int.to_string(app_id))
Error(_) -> io.println("Friend is not playing any game")
}
pub fn friend_persona_name(
client: SteamworksClient,
steam_id: String,
) -> String
Get a friend’s persona name (display name).
Returns the friend’s Steam display name.
Example
let name = vapour.friend_persona_name(client, "76561197960287930")
io.println("Friend name: " <> name)
pub fn friend_persona_state(
client: SteamworksClient,
steam_id: String,
) -> PersonaState
Get a friend’s persona state (online status).
Returns the friend’s current online status.
Example
let state = vapour.friend_persona_state(client, friend_id)
case state {
vapour.Online -> io.println("Friend is online")
vapour.Offline -> io.println("Friend is offline")
_ -> io.println("Friend has other status")
}
pub fn friend_relationship(
client: SteamworksClient,
steam_id: String,
) -> FriendRelationship
Get the relationship with another user.
pub fn friend_steam_level(
client: SteamworksClient,
steam_id: String,
) -> Int
Get a friend’s Steam level.
Returns the friend’s Steam level (0 if unavailable).
Example
let level = vapour.friend_steam_level(client, friend_id)
io.println("Friend is Level " <> int.to_string(level))
pub fn global_stat_float(
client: SteamworksClient,
stat_name: String,
) -> promise.Promise(Result(Float, Nil))
Get a global float stat (async).
pub fn global_stat_int(
client: SteamworksClient,
stat_name: String,
) -> promise.Promise(Result(Int, Nil))
Get a global integer stat (async).
pub fn indicate_achievement_progress(
client: SteamworksClient,
achievement: String,
current_progress: Int,
max_progress: Int,
) -> promise.Promise(Bool)
Show achievement progress notification (async).
Displays a progress notification in the Steam overlay (e.g., “Win 50 games: 25/50”). Useful for achievements that require multiple steps.
Parameters
achievement: Achievement API namecurrent_progress: Current progress valuemax_progress: Maximum progress value needed to unlock
Example
import gleam/javascript/promise
vapour.indicate_achievement_progress(client, "ACH_WIN_50_GAMES", 25, 50)
|> promise.await(fn(success) {
case success {
True -> io.println("Progress notification shown")
False -> io.println("Failed to show progress")
}
promise.resolve(Nil)
})
pub fn init(
app_id: option.Option(Int),
) -> Result(SteamworksClient, Nil)
Initialize the Steamworks API.
This must be called before using any other Steamworks functionality. Steam must be running for initialization to succeed.
Parameters
app_id: Your Steam App ID. Passoption.Noneto read from asteam_appid.txtfile in the current directory. Useoption.Some(480)for testing with Spacewar (Steam’s test app).
Returns
Ok(client): Successfully initialized. Use this client for all API calls.Error(Nil): Initialization failed (Steam not running or invalid app ID).
Example
import gleam/option
import vapour
// Initialize with your app ID
let assert Ok(client) = vapour.init(option.Some(YOUR_APP_ID))
// Or use Spacewar for testing
let assert Ok(client) = vapour.init(option.Some(480))
// Or read from steam_appid.txt
let assert Ok(client) = vapour.init(option.None)
pub fn invite_friends_to_lobby(
client: SteamworksClient,
lobby_steam_id: String,
) -> Nil
Open the Steam overlay invite dialog for a lobby.
Opens the invite dialog where players can select friends to invite to the specified lobby. Essential for multiplayer games.
Parameters
lobby_steam_id: The Steam ID of the lobby to invite friends to
Example
// Open invite dialog for a lobby
vapour.invite_friends_to_lobby(client, "109775241021923456")
pub fn invite_friends_with_connect_string(
client: SteamworksClient,
connect_string: String,
) -> Nil
Open the Steam overlay invite dialog with a custom connect string.
Opens the invite dialog and sends the connect string with the invitation. When friends accept, they receive this connect string (e.g., server IP, session ID).
Parameters
connect_string: Custom connection information (e.g., “+connect 192.168.1.100:27015”)
Example
// Invite with server connection info
let connect_str = "+connect 192.168.1.100:27015"
vapour.invite_friends_with_connect_string(client, connect_str)
// Invite with session ID
let connect_str = "+join_session abc123-def456"
vapour.invite_friends_with_connect_string(client, connect_str)
pub fn is_achievement_unlocked(
client: SteamworksClient,
achievement: String,
) -> promise.Promise(Bool)
Check if an achievement is unlocked (async).
Returns a Promise that resolves to True if the achievement is unlocked,
False otherwise.
Example
import gleam/javascript/promise
vapour.is_achievement_unlocked(client, "ACH_WIN_ONE_GAME")
|> promise.await(fn(is_unlocked) {
case is_unlocked {
True -> io.println("Already unlocked")
False -> io.println("Not yet unlocked")
}
promise.resolve(Nil)
})
pub fn leaderboard_display_type(
leaderboard_handle: LeaderBoard,
) -> LeaderboardDisplayType
Get the display type of a leaderboard.
Returns how scores should be displayed (Numeric, TimeSeconds, etc.).
Example
use result <- promise.await(vapour.find_leaderboard(client, "Speedrun"))
case result {
Ok(leaderboard) -> {
let display = vapour.leaderboard_display_type(client, leaderboard)
case display {
vapour.TimeSeconds -> io.println("Scores shown as time in seconds")
vapour.Numeric -> io.println("Scores shown as numbers")
_ -> io.println("Other display format")
}
}
Error(_) -> io.println("Leaderboard not found")
}
pub fn leaderboard_entry_count(
leaderboard_handle: LeaderBoard,
) -> Int
Get the entry count for a leaderboard.
Returns the total number of entries (scores) in the leaderboard.
Example
use result <- promise.await(vapour.find_leaderboard(client, "HighScores"))
case result {
Ok(leaderboard) -> {
let count = vapour.leaderboard_entry_count(client, leaderboard)
io.println("Leaderboard has " <> int.to_string(count) <> " entries")
}
Error(_) -> io.println("Leaderboard not found")
}
pub fn leaderboard_name(
leaderboard_handle: LeaderBoard,
) -> String
Get the name of a leaderboard.
Returns the leaderboard’s name as configured in Steam.
Example
use result <- promise.await(vapour.find_leaderboard(client, "HighScores"))
case result {
Ok(leaderboard) -> {
let name = vapour.leaderboard_name(client, leaderboard)
io.println("Leaderboard name: " <> name)
}
Error(_) -> io.println("Leaderboard not found")
}
pub fn leaderboard_sort_method(
leaderboard_handle: LeaderBoard,
) -> LeaderboardSortMethod
Get the sort method of a leaderboard.
Returns how the leaderboard entries are sorted (Ascending, Descending, or None).
Example
use result <- promise.await(vapour.find_leaderboard(client, "Speedrun"))
case result {
Ok(leaderboard) -> {
let sort_method = vapour.leaderboard_sort_method(client, leaderboard)
case sort_method {
vapour.Ascending -> io.println("Lower scores are better")
vapour.Descending -> io.println("Higher scores are better")
_ -> io.println("No sorting")
}
}
Error(_) -> io.println("Leaderboard not found")
}
pub fn list_achievements(
client: SteamworksClient,
) -> promise.Promise(List(String))
Get a list of all achievement names (async).
Returns a Promise that resolves to a list of all achievement IDs defined for this app.
Example
import gleam/javascript/promise
import gleam/list
vapour.list_achievements(client)
|> promise.await(fn(achievements) {
io.println("Found " <> int.to_string(list.length(achievements)) <> " achievements")
list.each(achievements, io.println)
promise.resolve(Nil)
})
pub fn list_files(client: SteamworksClient) -> List(FileInfo)
List all files in Steam Cloud.
Returns a list of FileInfo records containing file names and sizes in bytes.
Example
let files = vapour.list_files(client)
list.each(files, fn(file) {
io.println(file.name <> ": " <> int.to_string(file.bytes) <> " bytes")
})
pub fn lock_achievement(
client: SteamworksClient,
achievement: String,
) -> promise.Promise(Bool)
Lock an achievement (async) - primarily for testing.
Returns a Promise that resolves to True if the achievement was successfully
locked, False otherwise.
Example
import gleam/javascript/promise
vapour.lock_achievement(client, "ACH_WIN_ONE_GAME")
|> promise.await(fn(success) {
case success {
True -> io.println("Achievement locked for testing")
False -> io.println("Failed to lock achievement")
}
promise.resolve(Nil)
})
pub fn number_of_current_players(
client: SteamworksClient,
) -> promise.Promise(Result(Int, Nil))
Get the number of players currently playing the game (async).
Returns a Promise that resolves to the player count, or Error(Nil) on error.
Example
import gleam/javascript/promise
vapour.number_of_current_players(client)
|> promise.await(fn(result) {
case result {
Ok(count) -> io.println(int.to_string(count) <> " players online!")
Error(_) -> io.println("Failed to get player count")
}
promise.resolve(Nil)
})
pub fn persona_state(client: SteamworksClient) -> PersonaState
Get the current user’s persona state (online status).
Returns the user’s current online status.
Example
let state = vapour.persona_state(client)
case state {
vapour.Online -> io.println("You are online")
vapour.Offline -> io.println("You appear offline")
_ -> io.println("Other status")
}
pub fn read_file(
client: SteamworksClient,
name: String,
) -> String
Read a file from Steam Cloud.
Returns the file contents as a string, or an empty string if the file doesn’t exist or the read fails.
Example
let content = vapour.read_file(client, "savegame.json")
case content {
"" -> io.println("File not found")
data -> process_save_data(data)
}
pub fn request_global_achievement_percentages(
client: SteamworksClient,
) -> promise.Promise(Bool)
Request global achievement unlock percentages (async).
Must be called before using achievement_achieved_percent().
Returns True if the request was sent successfully.
Example
import gleam/javascript/promise
vapour.request_global_achievement_percentages(client)
|> promise.await(fn(success) {
case success {
True -> io.println("Global data requested")
False -> io.println("Request failed")
}
promise.resolve(Nil)
})
pub fn request_global_stats(
client: SteamworksClient,
history_days: Int,
) -> promise.Promise(Bool)
Request global stats from Steam (async).
Must be called before getting global stats. Returns True if request sent successfully.
pub fn request_user_stats(
client: SteamworksClient,
steam_id: String,
) -> promise.Promise(Bool)
Request stats for another user (async).
pub fn run_callbacks(client: SteamworksClient) -> Nil
Run Steam callbacks to process pending events.
This should be called regularly (ideally every frame or every 100ms) to keep the Steam connection alive and process asynchronous operations.
Example
import vapour
pub fn game_loop(client: vapour.SteamworksClient) {
// Process Steam callbacks each frame
vapour.run_callbacks(client)
// Rest of your game loop...
}
pub fn running_steam(client: SteamworksClient) -> Bool
Check if the Steam client is running.
Returns True if Steam is currently running on the system, False otherwise.
Example
import vapour
case vapour.running_steam(client) {
True -> io.println("Steam is running")
False -> io.println("Steam is not running")
}
pub fn set_rich_presence(
client: SteamworksClient,
key: String,
value: String,
) -> Nil
Set a Rich Presence key/value pair.
What is Rich Presence? Rich Presence is a Steam feature that allows your game to display detailed information about what players are currently doing. This information appears in the Steam friends list, chat, and on user profiles. It helps friends see at a glance what you’re up to in the game (e.g., “In Multiplayer Lobby”, “Playing Campaign - Level 5”, “Score: 12,500 points”).
You can set multiple key/value pairs to provide detailed status information. Steam will format and display this data according to your game’s Rich Presence configuration in the Steamworks partner site.
Parameters
key: Rich Presence key (e.g., “status”, “score”, “level”, “steam_display”)value: Rich Presence value (e.g., “In Menu”, “1000”, “Level 3”)
Common Keys
"steam_display": Controls which localization token to use for display"status": Current game mode or activity"score": Player’s current score"level": Current level or map name
Example
// Set player status
vapour.set_rich_presence(client, "status", "In Main Menu")
// Set current level
vapour.set_rich_presence(client, "level", "Level 3")
// Set score
vapour.set_rich_presence(client, "score", "1500")
// Tell Steam which display format to use
vapour.set_rich_presence(client, "steam_display", "#Status_Playing")
pub fn set_stat_float(
client: SteamworksClient,
stat_name: String,
value: Float,
) -> promise.Promise(Bool)
Set a float stat value for the current user (async).
Returns a Promise that resolves to True if successful, False otherwise.
Example
import gleam/javascript/promise
vapour.set_stat_float(client, "accuracy", 0.85)
|> promise.await(fn(success) {
case success {
True -> io.println("Stat updated!")
False -> io.println("Failed to update stat")
}
promise.resolve(Nil)
})
pub fn set_stat_int(
client: SteamworksClient,
stat_name: String,
value: Int,
) -> promise.Promise(Bool)
Set an integer stat value for the current user (async).
Returns a Promise that resolves to True if successful, False otherwise.
Example
import gleam/javascript/promise
vapour.set_stat_int(client, "total_kills", 100)
|> promise.await(fn(success) {
case success {
True -> io.println("Stat updated!")
False -> io.println("Failed to update stat")
}
promise.resolve(Nil)
})
pub fn stat_float(
client: SteamworksClient,
stat_name: String,
) -> promise.Promise(Result(Float, Nil))
Get a float stat value for the current user (async).
Returns a Promise that resolves to the stat value, or Error(Nil) if not found.
Example
import gleam/javascript/promise
vapour.stat_float(client, "accuracy")
|> promise.await(fn(result) {
case result {
Ok(accuracy) -> io.println("Accuracy: " <> float.to_string(accuracy))
Error(_) -> io.println("Stat not found")
}
promise.resolve(Nil)
})
pub fn stat_int(
client: SteamworksClient,
stat_name: String,
) -> promise.Promise(Result(Int, Nil))
Get an integer stat value for the current user (async).
Returns a Promise that resolves to the stat value, or Error(Nil) if not found.
Example
import gleam/javascript/promise
vapour.stat_int(client, "total_kills")
|> promise.await(fn(result) {
case result {
Ok(kills) -> io.println("Total kills: " <> int.to_string(kills))
Error(_) -> io.println("Stat not found")
}
promise.resolve(Nil)
})
pub fn status(client: SteamworksClient) -> Status
Get Steam API status including Steam ID and connection state.
Returns information about the current Steam connection including the logged-in user’s Steam ID.
Example
import vapour
import gleam/io
let status = vapour.status(client)
io.println("Steam ID: " <> status.steam_id)
io.println("Connected: " <> bool.to_string(status.is_initialized))
pub fn toggle_cloud_for_app(
client: SteamworksClient,
enabled: Bool,
) -> Nil
Enable or disable Steam Cloud for the current app.
Parameters
enabled:Trueto enable cloud storage,Falseto disable it
Example
// Enable cloud storage
vapour.toggle_cloud_for_app(client, True)
// Disable cloud storage
vapour.toggle_cloud_for_app(client, False)
pub fn total_achievement_count(
client: SteamworksClient,
) -> promise.Promise(Int)
Get the total number of achievements configured for this game (async).
Returns the count of all achievements defined in the Steamworks Partner site, including both locked and unlocked achievements.
Example
import gleam/javascript/promise
vapour.total_achievement_count(client)
|> promise.await(fn(total) {
io.println("This game has " <> int.to_string(total) <> " achievements")
promise.resolve(Nil)
})
pub fn unlock_achievement(
client: SteamworksClient,
achievement: String,
) -> promise.Promise(Bool)
Unlock an achievement (async).
Returns a Promise that resolves to True if the achievement was successfully
unlocked, False otherwise.
Example
import gleam/javascript/promise
vapour.unlock_achievement(client, "ACH_WIN_ONE_GAME")
|> promise.await(fn(success) {
case success {
True -> io.println("Achievement unlocked!")
False -> io.println("Failed to unlock achievement")
}
promise.resolve(Nil)
})
pub fn unlocked_achievement_count(
client: SteamworksClient,
) -> promise.Promise(Int)
Get the number of achievements the user has unlocked (async).
Returns the count of achievements the current user has unlocked. Useful for displaying progress like “15/50 achievements unlocked”.
Example
import gleam/javascript/promise
// Show achievement progress
use total <- promise.await(vapour.total_achievement_count(client))
use unlocked <- promise.await(vapour.unlocked_achievement_count(client))
let percent = case total {
0 -> 0.0
_ -> int.to_float(unlocked) /. int.to_float(total) *. 100.0
}
io.println(
"Progress: "
<> int.to_string(unlocked)
<> "/"
<> int.to_string(total)
<> " ("
<> float.to_string(percent)
<> "%)",
)
promise.resolve(Nil)
pub fn update_avg_rate_stat(
client: SteamworksClient,
stat_name: String,
count_this_session: Int,
session_length: Int,
) -> promise.Promise(Bool)
Update an average rate stat (async).
For stats like “kills per hour”, Steam maintains the average calculation.
pub fn upload_score(
client: SteamworksClient,
leaderboard_handle: LeaderBoard,
score: Int,
upload_method: UploadScoreMethod,
) -> promise.Promise(Bool)
Upload a score to a leaderboard (async).
pub fn user_stat_float(
client: SteamworksClient,
steam_id: String,
stat_name: String,
) -> promise.Promise(Result(Float, Nil))
Get a float stat for another user (async).
pub fn user_stat_int(
client: SteamworksClient,
steam_id: String,
stat_name: String,
) -> promise.Promise(Result(Int, Nil))
Get an integer stat for another user (async).
pub fn write_file(
client: SteamworksClient,
name: String,
content: String,
) -> Bool
Write a file to Steam Cloud.
Parameters
name: Filename to write (e.g., “savegame.json”)content: File content as a string
Returns
True if the write was successful, False otherwise.
Example
let save_data = json.encode(game_state)
case vapour.write_file(client, "savegame.json", save_data) {
True -> io.println("Game saved to cloud")
False -> io.println("Failed to save to cloud")
}