Skip to content
Joël Deffner edited this page Sep 4, 2026 · 5 revisions

steamwand.js

TypeScript bindings for the Steamworks SDK with no native build step. The binding layer is generated from steam_api.json, Valve's own machine-readable description of the flat C API, and called through koffi FFI. pnpm add steamwand.js installs one dependency and the steam_api redistributables. There is no node-gyp step, no prebuild matrix, and no C++ in this repo.

Every other Node binding makes you compile someone else's native code to add a function. greenworks is NAN-era C++ built on the pre-2014 RemoteStorage workshop API. steamworks.js is solid, but each contribution means Rust, napi-rs, and a three-platform build matrix; adding one setter (SetItemUpdateLanguage) took two forked repos and a patch file. Here the flat surface is already generated: 25 interfaces, 807 functions, and 191 callback structs with per-platform offset tables. When a new SDK ships, you regenerate instead of porting.

Quickstart

import { init } from 'steamwand.js';

async function main() {
  const steam = init({ appId: 480 }); // 480 is Spacewar, Valve's public test app
  console.log(steam.friends.GetPersonaName()); // 'joel'
  console.log(steam.steamId()); // 76561198000000000n
  console.log(steam.apps.GetCurrentGameLanguage()); // 'english'

  const stop = steam.on<{ m_nPublishedFileId: bigint }>('ItemInstalled_t', (d) =>
    console.log('item installed', d.m_nPublishedFileId),
  );

  const { fileId } = await steam.workshop.createItem();
  console.log('created', fileId);

  stop();
  steam.close();
}

main();

The Steam client must be running and logged in. 64-bit values (Steam ids, file ids, handles) are bigint everywhere.

Pages

Page What it covers
Home This page: what the library is, and where everything else lives.
Getting-Started Requirements, install, app id setup, your first script, process lifecycle.
Core-API init, InitOptions, the Steam class, the error classes, every package export.
Workshop The curated steam.workshop layer: publish, browse, subscribe, download, per-language text.
Stats The curated steam.stats layer: achievements, per-user stats, global percentages.
Cloud The curated steam.cloud layer: read, write, list and delete Steam Cloud files.
Leaderboards The curated steam.leaderboards layer: find or create, upload a score, download entries.
Lobbies The curated steam.lobbies layer: create, join, search, lobby data, lobby chat.
Social The curated steam.social layer: persona, friend list, avatars, rich presence.
Overlay The curated steam.overlay layer: overlay dialogs, invite dialogs, notification placement.
Auth The curated steam.auth layer: session and Web API tickets, session validation, account facts.
System The curated steam.system layer: machine and client facts, gamepad keyboards.
Capture The curated steam.capture layer: screenshots, library entries, tags, the hooked key.
Controllers The curated steam.controllers layer: Steam Input handles, action sets, action data, haptics.
DLC The curated steam.dlc layer: the DLC list, ownership, install, and download progress.
Inventory The curated steam.items layer: Steam Inventory Service items, definitions, prices, purchases.
P2P The curated steam.p2p layer: packets to and from other Steam users by Steam id.
Recording The curated steam.recording layer: Game Recording timeline events and phases.
Flat-API The generated flat namespace: interface classes, enums, consts, struct layouts.
How-It-Works The loader, the manual dispatch pump, and the offset-table struct decoder.
Recipes Short worked examples for common jobs.
Troubleshooting Init failures, missing libraries, calls that never resolve, hard crashes.
Regenerating Pointing the generator at a new SDK and checking the output.
Development Repo layout, tests, offline and live test runs.

Status and scope

The committed output is generated from SDK 1.65 (sdk.lock.json records the version and the steam_api.json hash). Not covered:

  • Game server APIs are not wired up.
  • ISteamNetworkingSockets and ISteamNetworkingMessages take SteamNetworkingIdentity, a union struct (see below), so only their generated methods that avoid it are usable. The curated P2P layer sits on the older ISteamNetworking packet calls instead.
  • 12 of the 819 flat functions are skipped: 9 take C function pointers (debug hooks, netsockets status callbacks), and 3 pass a struct by value whose layout cannot be proven safe (SteamIPAddress_t is a C union, and SteamPartyBeaconLocation_t packs differently per platform). The generator lists every skip when it runs. The Steam Input action-data calls, which used to be part of that list, are bound since 0.3.0.
  • Structs containing C unions (SteamNetworkingIdentity and relatives) get no layout table, because steam_api.json cannot express unions and a guessed layout would read garbage. They are excluded loudly, not wrongly.
  • An FFI mistake crashes the process instead of throwing. If you embed this in something that must survive (a VS Code extension, an editor), run it in a child process.

The SDK itself is not in this repo. Valve's license does not allow redistributing the headers or steam_api.json, so regeneration needs your own SDK download. See Regenerating. Shipping the redistributable binaries (steam_api64.dll and friends) is allowed, and they are in the package under runtime/.

Clone this wiki locally