# Feature matrix (/docs/feature-matrix) This is the answer to *"does this work on Unreal?"* The [Platform API](/docs/platform-api) is identical across runtimes by design β€” the differences are confined to rendering, input, and networking. We track them here rather than scattering "N/A on this runtime" notes through the reference. The Web SDK is the frozen contract. A βœ… in the Web column is the source of truth; the Native column reflects mirror status. Anything not yet at parity is marked 🟑. ## Platform API [#platform-api] | Capability | Web | Native (Unreal) | | --------------------------------------------------------- | :-: | :-------------: | | Authentication & Identity (`Helix.auth`, `Helix.profile`) | βœ… | βœ… | | LIX & Economy (`Helix.wallet`, `Helix.marketplace`) | βœ… | βœ… | | Cloud Save (`Helix.cloudSave`) | βœ… | βœ… | | Memory Store (`Helix.memoryStore`) | βœ… | βœ… | | Inventory & Items (`Helix.inventory`) | βœ… | βœ… | | Social & Presence (`Helix.social`) | βœ… | βœ… | | Chat (`Helix.chat`) | βœ… | βœ… | | Voice / proximity (`Helix.voice`) | βœ… | βœ… | | Avatars (`Helix.avatar`) | βœ… | βœ… | | Analytics (`Helix.analytics`) | βœ… | βœ… | ## Runtime-specific [#runtime-specific] | Capability | Web | Native (Unreal) | | ------------------------------------------------ | :-----------------------: | :------------------------------: | | Instant play from a link (no install) | βœ… | β€” | | HELIX multiplayer & networking (`Helix.network`) | βœ… | β€” | | Engine-native dedicated-server networking | β€” | βœ… | | Replication wrappers | β€” | βœ… | | Rendering / scene graph | Web stack (Three.js etc.) | Unreal | | Languages | TypeScript / JS | C++ Β· Blueprint Β· PuerTS Β· UnLua | Legend: βœ… available Β· 🟑 in progress Β· β€” not applicable to this runtime. A CI check compares the generated [Web reference](/docs/web-sdk/reference) against the generated [Native reference](/docs/native-sdk/reference) and flags any Platform API method that exists on one but not the other. This matrix is generated from that check, so it can't silently drift. # HELIX 3 Documentation (/docs) HELIX is an **engine-agnostic virtual-world platform**. You build a world once against a single SDK and HELIX gives you identity, the LIX economy, storage, inventory, social, voice, and multiplayer β€” then runs it on any device from a single link. These docs are organized around one idea: The **Platform API** is engine-agnostic and documented **once**. The **Web SDK** (TypeScript) is the canonical contract; the **Native (Unreal) SDK** mirrors it 1:1 in C++, Blueprint, PuerTS, and UnLua. The same function names mean the same thing everywhere. ## Start here [#start-here] ## The map [#the-map] ## Built for humans and agents [#built-for-humans-and-agents] Every page in these docs is available as clean Markdown for LLMs β€” append `.md`-style content routes, or pull the whole corpus: * [`/llms.txt`](/llms.txt) β€” a structured index of every page. * [`/llms-full.txt`](/llms-full.txt) β€” the entire documentation as one Markdown file. * Use the **Copy Markdown** button at the top of any page to grab that page for an AI agent. We expect most worlds to be built by AI coding agents calling this SDK. The docs are written to be read by both. # Migrating from HELIX 2 (/docs/migrating-from-helix2) HELIX 3 is a new product, not an iteration of HELIX 2. If you built on HELIX 2 β€” QBCore/Lua scripts, FiveM-style roleplay servers, the Lua API or HelixJS β€” this page explains what carries over and what doesn't. The rest of these docs describe HELIX 3 only. HELIX 2 (QBCore, the Lua class API, Creator Kit, Blueprint-as-primary) is being wound down. Treat it as legacy; build new worlds on the [unified SDK](/docs/platform-api). ## What changed at the top [#what-changed-at-the-top] | HELIX 2 | HELIX 3 | | -------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- | | Two siloed scripting layers (Lua API **and** HelixJS) with no shared model | One **unified SDK**: an engine-agnostic [Platform API](/docs/platform-api) + per-runtime SDKs that mirror it 1:1 | | QBCore/Lua FiveM-compat framework as a first-class surface | **Removed.** QBCore is legacy; not part of HELIX 3 | | Engine-specific, UE5-centric (Creator Kit, Blueprint-first) | **Engine-agnostic.** Web is canonical; Unreal mirrors it | | `HInventory` (placeholder), ad-hoc persistence | First-class [Inventory](/docs/platform-api/inventory) + [Cloud Save](/docs/platform-api/cloud-save) / [Memory Store](/docs/platform-api/memory-store) | | `helixId` mentioned but never explained | Full [Authentication & Identity](/docs/platform-api/authentication) model | ## Concept mapping [#concept-mapping] | HELIX 2 | HELIX 3 | | ------------------------------------------------------------ | ------------------------------------------------------------------------------------------------------------------ | | `HPlayer`, `helixId` | [`Helix.auth` / `Helix.profile`](/docs/platform-api/authentication) | | Lua `TriggerServerEvent` / HelixJS `Helix.endpoint()` | [`Helix.network`](/docs/web-sdk/multiplayer) (`send` / `broadcast` / `request`) | | Lua `Database`, `HPlayer:SetValue/GetValue`, HelixJS `State` | [Cloud Save](/docs/platform-api/cloud-save) (durable) + [Memory Store](/docs/platform-api/memory-store) (volatile) | | `HInventory` (unfinished) | [`Helix.inventory`](/docs/platform-api/inventory) + Universal Item Contract | | In-world purchases (concept only) | [`Helix.wallet` / `Helix.marketplace`](/docs/platform-api/lix-economy) | | WebUI bridge (Lua/JS ↔ HTML) | `Helix.ui` + standard web UI in the web runtime | | QBCore packages (qb-inventory, qb-banking, …) | Community packages on top of the Platform API β€” not core docs | ## What's deprecated [#whats-deprecated] * **QBCore / FiveM compatibility layer** β€” entirely. * **The HELIX 2 Lua class API** (`HVehicle`, `HCharacter`, etc. as documented in HELIX 2) β€” replaced by the unified SDK surface. * **Creator Kit** and the UE5-as-primary workflow β€” superseded by HELIX Studio and the [Native SDK](/docs/native-sdk). * **Point-in-time migration guides** (e.g. 5.5β†’5.7) β€” no longer relevant. ## What carries over (conceptually) [#what-carries-over-conceptually] * The **client/server authority** model β€” now formalized as the [golden rule](/docs/introduction/how-helix-works#server-authority--the-golden-rule). * **Packages & the Vault** distribution idea β€” now built on the Platform API. * The **LIX** economy β€” now a first-class, server-authoritative [API](/docs/platform-api/lix-economy). ## How to move a world [#how-to-move-a-world] **Re-target the runtime.** Pick [Web or Native](/docs/introduction/choose-your-runtime). Most HELIX 2 worlds were UE5 β€” Native is the closest home, but consider Web for reach. **Replace the data layer.** Move ad-hoc Lua/SQLite persistence to [Cloud Save](/docs/platform-api/cloud-save) (durable) and [Memory Store](/docs/platform-api/memory-store) (transient). **Rewrite events** against [`Helix.network`](/docs/web-sdk/multiplayer) (web) or Unreal replication with [HELIX wrappers](/docs/native-sdk/networking) (native). **Move value logic server-side.** Anything QBCore did client-side for money/items must become server-authoritative under the [Inventory](/docs/platform-api/inventory) tiers. Start from a template (`helix create --template ...`) rather than porting file by file β€” the shapes are different enough that a fresh scaffold is usually faster. # HELIX CLI (/docs/cli) The `@helix/cli` is the front door for building worlds. It scaffolds projects, runs them locally with a real instance, validates against platform rules, and deploys immutable builds. ```bash npm install -g @helix/cli # or: npx @helix/cli ``` ## Commands [#commands] ### Typical loop [#typical-loop] ```bash npx @helix/cli create my-world --template multiplayer-starter cd my-world && npm install helix dev # iterate helix validate # catch issues early helix deploy # ship a build, get a link ``` ## Templates [#templates] Templates are starting points wired with the SDK, a server `HelixInstance`, and sensible manifest scopes. Start from one rather than an empty directory. ## Auto-generated reference [#auto-generated-reference] The CLI is also where the docs pipeline lives. On every merge to `main`: The **Web SDK reference** is generated from the `@helix/sdk` TypeScript source with **TypeDoc**. The **Native SDK reference** is generated from the Unreal plugin headers with **Doxygen**, then mapped to Blueprint / PuerTS / UnLua. The [`/llms.txt`](/llms.txt) index and [`/llms-full.txt`](/llms-full.txt) bundle are rebuilt, and the site is deployed. This is what keeps [Web reference](/docs/web-sdk/reference) and [Native reference](/docs/native-sdk/reference) in sync with shipped code. See the repo's `.github/workflows/deploy.yml` and `CONTRIBUTING.md` for the exact pipeline. ## For AI agents [#for-ai-agents] Agents drive the same CLI β€” and get a richer interface through the [MCP server](/docs/cli/mcp), which exposes discovery, validation, and publishing as tools. # MCP server for AI agents (/docs/cli/mcp) HELIX expects most worlds to be built by AI agents. The **MCP server** (`@helix/mcp`) gives an agent a structured, typed interface to the platform β€” discovery, validation, and publishing as callable tools β€” instead of scraping a CLI's stdout. Anything a human can do through the [CLI](/docs/cli), an agent can do through MCP. The two are deliberately at parity. ## What it exposes [#what-it-exposes] * **Discovery** β€” list available systems, abilities, templates, and package manifests so the agent builds on what already exists instead of reinventing it. * **Validation** β€” check a world against the manifest schema and platform rules before publishing. * **Publishing** β€” create builds and publish worlds. * **Docs** β€” read these docs as structured Markdown (the same content behind [`/llms.txt`](/llms.txt)). ## Connect it [#connect-it] Point your agent host at the server (example for a Claude/Cursor-style MCP config): ```json { "mcpServers": { "helix": { "command": "npx", "args": ["-y", "@helix/mcp"] } } } ``` ## Why agents like these docs [#why-agents-like-these-docs] These docs are built to be machine-readable from day one: * Every page is available as clean Markdown (the **Copy Markdown** button, and content routes). * [`/llms.txt`](/llms.txt) is a structured index of the whole site. * [`/llms-full.txt`](/llms-full.txt) is the entire corpus in one file for context windows. * Every parameter and error is typed and described β€” what's obvious to a human reader is spelled out for an LLM. Together with the MCP server, an agent can read the docs, scaffold a world, validate it, and publish it without a human in the loop. # Build your first multiplayer world (/docs/guides/first-multiplayer-world) This builds a tiny but real multiplayer world: players see each other, can wave, and can press a button that the **server** validates before rewarding. Uses [Instances & Events](/docs/web-sdk/multiplayer) and the [server authority](/docs/introduction/how-helix-works#server-authority--the-golden-rule) rule. ## 1. Boot and join [#1-boot-and-join] ```ts title="src/client.ts" import { Helix } from '@helix/sdk'; await Helix.init({ worldId: window.HELIX_WORLD_ID, launchTicket: window.HELIX_LAUNCH_TICKET, }); const instance = await Helix.instance.join(); instance.onPlayerJoined((p) => spawnAvatar(p)); instance.onPlayerLeft((p) => removeAvatar(p)); for (const p of instance.getPlayers()) spawnAvatar(p); ``` ## 2. A cosmetic event (client-trusted) [#2-a-cosmetic-event-client-trusted] Waving doesn't affect value, so the client can drive it. ```ts title="src/client.ts" Helix.network.on('wave', ({ from }) => playWave(from)); document.querySelector('#wave')!.addEventListener('click', () => { Helix.network.send('wave', {}); }); ``` ```ts title="src/server.ts" import { HelixInstance } from '@helix/server-sdk'; export default class MyWorld extends HelixInstance { async onEvent(player, event) { if (event === 'wave') this.broadcast('wave', { from: player.id }); } } ``` ## 3. A value event (server-authoritative) [#3-a-value-event-server-authoritative] A "daily bonus" button grants LIX-adjacent value β€” so the **server** decides, enforces the once-per-day rule, and grants. The client only asks. ```ts title="src/client.ts" const res = await Helix.network.request('claim-bonus', {}); if (res.ok) showToast(`+${res.amount} coins!`); else showToast(res.reason); ``` ```ts title="src/server.ts" export default class MyWorld extends HelixInstance { async onEvent(player, event) { if (event === 'wave') this.broadcast('wave', { from: player.id }); } // request/response handler async onRequest(player, event) { if (event !== 'claim-bonus') return; const key = `bonus:${player.id}:${today()}`; const already = await Helix.cloudSave.get(key); if (already) return { ok: false, reason: 'Already claimed today' }; await Helix.cloudSave.set(key, true); // durable, authoritative await this.grantCoins(player.id, 50); // server-side grant return { ok: true, amount: 50 }; } } ``` If the client could grant its own bonus, players would script infinite coins. The wave is harmless client-side; the bonus is decided server-side and recorded in [Cloud Save](/docs/platform-api/cloud-save). That's the [golden rule](/docs/introduction/how-helix-works#server-authority--the-golden-rule) in two handlers. ## 4. Publish [#4-publish] ```bash helix validate && helix deploy ``` Share the link. Open it in two browsers β€” you'll see two players, waves replicate, and the bonus is claimable once per day per player. ## Next [#next] # Guides (/docs/guides) Concept pages explain *what* something is; guides show *how* to build a specific thing end to end. Each one names the [Platform API](/docs/platform-api) surfaces it uses and, where it matters, shows the same task on both runtimes. This section grows with the platform. Proximity voice, avatars, and matchmaking guides are next. If you're an AI agent, the [`/llms-full.txt`](/llms-full.txt) bundle includes every guide in one file. # Persist player data (/docs/guides/persist-player-data) Uses [Cloud Save](/docs/platform-api/cloud-save) (durable) and, for hot counters, [Memory Store](/docs/platform-api/memory-store) (volatile). ## Load on join, save on change [#load-on-join-save-on-change] ```ts title="src/server.ts" import { HelixInstance } from '@helix/server-sdk'; type Progress = { level: number; coins: number }; const DEFAULT: Progress = { level: 1, coins: 0 }; export default class MyWorld extends HelixInstance { async onPlayerJoin(player) { const p = (await Helix.cloudSave.get(key(player.id))) ?? DEFAULT; this.setState(player.id, p); } async onPlayerLeave(player) { await Helix.cloudSave.set(key(player.id), this.getState(player.id)); } } const key = (id: string) => `progress:${id}`; ``` Never let a client write its own `coins`. Loading and saving value-bearing state lives in server-authoritative code. Clients send *intent* (events); the server updates and persists. ## Concurrent edits: read–modify–write [#concurrent-edits-readmodifywrite] Two instances of your world can run at once. For a value many players or sessions can change, don't blind-write β€” read, modify, and write inside a server-guarded step: ```ts async function addCoins(playerId: string, delta: number) { const cur = (await Helix.cloudSave.get(key(playerId))) ?? DEFAULT; const next = { ...cur, coins: cur.coins + delta }; await Helix.cloudSave.set(key(playerId), next); return next.coins; } ``` For **hot** counters (e.g. "players in this zone right now") that don't need durability, use Memory Store's atomic `increment` and only flush a summary to Cloud Save occasionally: ```ts const inZone = await Helix.memoryStore.increment(`zone:${zoneId}`, 1, 60); ``` ## Choosing the store [#choosing-the-store] | Data | Store | Why | | ------------------------------- | ----------------------------------------------- | ------------------------ | | Progress, settings, owned state | [Cloud Save](/docs/platform-api/cloud-save) | Must survive sessions | | Live leaderboard / matchmaking | [Memory Store](/docs/platform-api/memory-store) | Fast, shared, disposable | | Hot counters | Memory Store `increment` | Atomic, cheap | ## Next [#next] # Sell an item for LIX (/docs/guides/sell-item-for-lix) This wires a real [in-world purchase](/docs/platform-api/lix-economy#in-world-purchases-iwp). The rule that shapes everything: **the client requests, the server settles.** LIX is deducted server-side and the grant is idempotent so retries can't double-charge. ## The flow [#the-flow] **Client requests** a purchase. It never touches the wallet directly. **Server validates** (price, eligibility, stock), then **consumes/charges and grants atomically** with an idempotency key. **Wallet & inventory update**; the client reacts to the settled result. ## Simple catalog purchase [#simple-catalog-purchase] For items priced in the platform catalog, one call does it β€” settlement is handled for you: ```ts const result = await Helix.marketplace.purchaseItem('premium_sword_001'); if (result.status === 'completed') equip('premium_sword_001'); else showToast(result.reason); ``` ```ts const result = await Helix.marketplace.purchaseItem('premium_sword_001'); if (result.status === 'completed') equip('premium_sword_001'); ``` ```lua local result = Helix.marketplace.purchaseItem("premium_sword_001") if result.status == "completed" then equip("premium_sword_001") end ``` ## Custom server-authoritative sale [#custom-server-authoritative-sale] When you need custom pricing or bundles, the client asks and your `HelixInstance` server settles: ```ts title="src/client.ts" const res = await Helix.network.request('buy', { sku: 'starter-bundle' }); if (res.ok) showInventory(); else showToast(res.reason); ``` ```ts title="src/server.ts" export default class Shop extends HelixInstance { async onRequest(player, event, payload) { if (event !== 'buy') return; const sku = CATALOG[payload.sku]; if (!sku) return { ok: false, reason: 'Unknown item' }; const { lix } = await Helix.wallet.getBalance(player.id); if (lix < sku.priceLix) return { ok: false, reason: 'Not enough LIX' }; // atomic: charge LIX + grant item, idempotent on requestId const result = await Helix.inventory.purchase({ buyer: player.id, itemId: sku.itemId, priceLix: sku.priceLix, idempotencyKey: this.requestId, }); return result.ok ? { ok: true } : { ok: false, reason: result.error }; } } ``` Networks retry. Without an `idempotencyKey`, a retried purchase can charge twice. The SDK provides a stable key per request β€” pass it through. The grant and the charge are one atomic operation. ## What the platform handles for you [#what-the-platform-handles-for-you] * **Settlement & fees.** Commission and payouts are applied by the platform β€” you don't compute them. * **Anti-fraud & limits.** Server-side checks live in the economy service. * **The provider stays hidden.** You call `Helix.wallet` / `Helix.marketplace` / `Helix.inventory`; payment internals are never in your code. ## Related [#related] # Choose your runtime (/docs/introduction/choose-your-runtime) You write your world logic against the engine-agnostic [Platform API](/docs/platform-api) either way. The runtime decides how it renders, how it networks, and which languages you write in. ## Quick guide [#quick-guide] ## Side by side [#side-by-side] | | Web | Native (Unreal) | | ---------------- | -------------------------------------------------------- | ---------------------------------------- | | **Languages** | TypeScript / JavaScript | C++, Blueprint, PuerTS (TS), UnLua (Lua) | | **Distribution** | Instant, from a link, any device | Engine-native build | | **Multiplayer** | HELIX networking ([web-only](/docs/web-sdk/multiplayer)) | Engine-native dedicated servers | | **Platform API** | βœ… identical | βœ… identical | | **Status** | Canonical contract, available first | Mirrors the web contract 1:1 | | **Best for** | Reach, speed, AI-built worlds | Fidelity, large maps, existing UE teams | You are **not** locked in. Because both runtimes call the same Platform API, world logic written for web ports to Native with minimal change β€” the differences are rendering, input, and networking, not identity/economy/storage. ## Still deciding? [#still-deciding] Start on **Web**. It's the canonical surface, it's the fastest path to a playable link, and everything you learn transfers. Move to Native when you need engine-level fidelity or you already have an Unreal team. Continue to the [Quickstart](/docs/introduction/quickstart). # How HELIX works (/docs/introduction/how-helix-works) HELIX has a small, deliberate vocabulary. Learn these five nouns and the rest of the docs read cleanly. **World Β· Build Β· Instance Β· Player Β· Event.** These are the only words the SDK and docs use for the runtime. Provider-specific terms (rooms, matches, servers) never appear in the public API β€” they're implementation details HELIX hides behind the SDK. ## The nouns [#the-nouns] ## The lifecycle [#the-lifecycle] What happens when someone opens your world from a link: **Launch.** A player opens your World. HELIX authenticates them (or spins up an instant guest) and issues a short-lived **Launch Ticket**. **Init.** Your client boots and calls `Helix.init({ worldId, launchTicket })`. The SDK validates the ticket and exposes the player's identity, wallet, and inventory. **Join an Instance.** The player joins a running Instance of the current Build (or HELIX creates one). The platform issues an **Instance Ticket** that the runtime verifies before admitting them. **Play.** Client and server exchange [Events](/docs/web-sdk/multiplayer). The server is authoritative for anything that touches wallet, inventory, or ownership; the client is trusted only for visuals and local gameplay. **Persist.** State that must survive the session is written through [Cloud Save](/docs/platform-api/cloud-save). Transient cross-instance state (leaderboards, matchmaking) uses [Memory Store](/docs/platform-api/memory-store). ## Server authority β€” the golden rule [#server-authority--the-golden-rule] If an action affects **inventory, currency, or ownership**, the **server is authoritative**. If it only affects **visuals or local gameplay**, the client can be trusted. This single rule decides where every piece of your logic belongs β€” see the [Universal Item Contract](/docs/platform-api/inventory). ## Where this lives in the SDK [#where-this-lives-in-the-sdk] You orchestrate all of this from the [Web SDK](/docs/web-sdk) (client) and the server SDK (`HelixInstance`). The platform pieces β€” auth, wallet, storage, inventory β€” are the [Platform API](/docs/platform-api), identical across runtimes. # What is HELIX 3? (/docs/introduction) HELIX is a **virtual-world platform**. It is not a game engine and it is not a single game β€” it is the layer that sits **on top of** a rendering engine and provides everything a multiplayer virtual world needs but a renderer doesn't: * **Identity** β€” one account across every world, with instant guest play. * **Economy** β€” a real currency (**LIX**), a marketplace, and creator payouts. * **Persistence** β€” durable Cloud Save and volatile Memory Store. * **Items & inventory** β€” universal items that work across worlds and runtimes. * **Social** β€” friends, presence, invites, chat, and proximity voice. * **Multiplayer** β€” instances, networking, and server-authoritative state. * **Hosting & distribution** β€” your world is playable instantly, on any device, from a link. You reach all of it through **one SDK**. HELIX is an AI-native, engine-agnostic virtual-world platform β€” *"Roblox for adults, on the web."* Creation no longer has to happen inside a proprietary studio. AI agents become the studio; HELIX becomes the runtime, economy, identity, and distribution layer. ## One platform, two runtimes [#one-platform-two-runtimes] This is the core idea, and it shapes the whole of these docs.
Platform (engine-agnostic)

Identity, LIX, storage, inventory, marketplace, social, analytics, moderation. The same backend serves every runtime. Documented once, in the Platform API.

Runtime (engine-specific)

Where your world actually renders and runs. Web (TypeScript, the canonical contract) and Native (Unreal: C++, Blueprint, PuerTS, UnLua) both call the same Platform API.

The **Web SDK is the canonical, frozen contract.** The Native runtime mirrors it 1:1 β€” every function, including character and world functions. If you learn the API on one runtime, you know it on the other. See [Platform vs Engine SDK](/docs/introduction/platform-vs-engine) for the full mental model. ## Who HELIX is for [#who-helix-is-for] * **AI-assisted creators** shipping multiplayer web-3D experiences who don't want to build identity, economy, or netcode from scratch. * **Studios and teams** that want their world on web today and on Unreal later β€” without rewriting game logic against a different API. * **AI agents** building worlds autonomously through the [CLI](/docs/cli) and [MCP server](/docs/cli/mcp). ## Next [#next] # Platform vs Engine SDK (/docs/introduction/platform-vs-engine) Everything in the HELIX SDK falls into one of two buckets. Knowing which bucket you're in tells you where to find the docs, whether the code is portable, and what to expect on another runtime. ## Platform API β€” engine-agnostic [#platform-api--engine-agnostic] The **Platform API** is the shared layer. It has nothing to do with rendering. It's the same behavior, the same guarantees, and the same function names on every runtime: | Capability | Namespace | Docs | | ------------------------- | ----------------------------------- | --------------------------------------------------- | | Authentication & identity | `Helix.auth`, `Helix.profile` | [Authentication](/docs/platform-api/authentication) | | LIX & economy | `Helix.wallet`, `Helix.marketplace` | [LIX & economy](/docs/platform-api/lix-economy) | | Durable storage | `Helix.cloudSave` | [Cloud Save](/docs/platform-api/cloud-save) | | Volatile storage | `Helix.memoryStore` | [Memory Store](/docs/platform-api/memory-store) | | Items & inventory | `Helix.inventory` | [Inventory](/docs/platform-api/inventory) | | Social & presence | `Helix.social` | [Social](/docs/platform-api/social) | Write against the Platform API and your logic is **portable**: it behaves identically whether your world runs on the web or inside Unreal. ## Engine-specific runtime [#engine-specific-runtime] A **runtime** is where your world actually renders and executes. Runtimes add the things only an engine can provide β€” scene graph, input, physics, rendering β€” plus engine-flavored conveniences. * **[Web SDK](/docs/web-sdk)** β€” TypeScript. This is the **canonical contract**. It also ships a full **multiplayer & networking** API (HELIX's own implementation) that is web-specific. * **[Native (Unreal) SDK](/docs/native-sdk)** β€” the same Platform API exposed to **C++**, **Blueprint**, **PuerTS** (TypeScript) and **UnLua** (Lua), plus engine-specific helpers like replication wrappers. Native worlds use the engine's own networking rather than the web stack. The Web TypeScript SDK is frozen first and treated as the canonical API surface. The Native runtime **mirrors it 1:1** β€” every function, including character and world functions. When the two ever differ, the web signature wins and the difference is documented in the [feature matrix](/docs/feature-matrix). ## The same call, five ways [#the-same-call-five-ways] Because the Platform API is identical across runtimes, the *same* operation looks like idiomatic code in each language. Here's reading the current player's LIX balance: ```ts const wallet = await Helix.wallet.getBalance(); console.log(`You have ${wallet.lix} LIX`); ``` ```cpp UHelixWallet* Wallet = UHelix::Get()->Wallet(); Wallet->GetBalance(FOnBalance::CreateLambda([](const FHelixBalance& B) { UE_LOG(LogHelix, Display, TEXT("You have %lld LIX"), B.Lix); })); ``` ```text Helix β†’ Wallet β†’ Get Balance (latent node) ↳ On Success β†’ Break Helix Balance β†’ "Lix" β†’ Print String ``` ```ts // PuerTS runs the same TypeScript API as the Web SDK, inside Unreal. const wallet = await Helix.wallet.getBalance(); console.log(`You have ${wallet.lix} LIX`); ``` ```lua local wallet = Helix.wallet.getBalance() UE.Log(string.format("You have %d LIX", wallet.lix)) ``` This `groupId` is shared across the docs: pick **PuerTS** once and every runtime-tabbed example on every page follows you. ## How to use this distinction [#how-to-use-this-distinction] * Reading about a **concept** (auth, LIX, storage)? You're in the [Platform API](/docs/platform-api). It applies to every runtime. * Reading about **rendering, input, networking, or engine conveniences**? You're in a runtime section β€” [Web SDK](/docs/web-sdk) or [Native SDK](/docs/native-sdk). # Quickstart (/docs/introduction/quickstart) This builds and publishes a real multiplayer world on the **Web** runtime β€” the fastest path to a playable link. Native (Unreal) setup lives in the [Native SDK](/docs/native-sdk) section. ## Prerequisites [#prerequisites] * Node.js 20+ * A HELIX account ([helixgame.com](https://helixgame.com)) ## 1. Create a world [#1-create-a-world] **Scaffold from a template.** ```bash npx @helix/cli create my-world --template multiplayer-starter cd my-world npm install ``` **Run it locally.** This starts the world with a local instance and hot reload. ```bash helix dev ``` Open the printed URL. You're now in your world as an authenticated player. ## 2. Write a little logic [#2-write-a-little-logic] Client code talks to the [Platform API](/docs/platform-api) and to your server via [Events](/docs/web-sdk/multiplayer). Here we greet the player and read their balance: ```ts title="src/client.ts" import { Helix } from '@helix/sdk'; await Helix.init({ worldId: window.HELIX_WORLD_ID, launchTicket: window.HELIX_LAUNCH_TICKET, }); const me = await Helix.profile.getMyProfile(); const wallet = await Helix.wallet.getBalance(); console.log(`Welcome, ${me.displayName} β€” you have ${wallet.lix} LIX`); ``` Server code extends `HelixInstance` and owns authoritative state: ```ts title="src/server.ts" import { HelixInstance } from '@helix/server-sdk'; export default class MyInstance extends HelixInstance { async onPlayerJoin(player) { this.broadcast('player-joined', { id: player.id, name: player.displayName }); } async onEvent(player, event, payload) { if (event === 'wave') this.broadcast('wave', { from: player.id }); } } ``` ## 3. Publish & play [#3-publish--play] **Validate** your world against the platform manifest and rules: ```bash helix validate ``` **Deploy.** This creates an immutable Build and makes it playable from a link. ```bash helix deploy ``` **Share the link.** Anyone can open it and play instantly β€” as a guest if they're not signed in. ## Where to go next [#where-to-go-next] # Native (Unreal) SDK (/docs/native-sdk) The Native SDK brings HELIX to **Unreal Engine**. It exposes the exact same [Platform API](/docs/platform-api) as the web β€” identity, LIX, storage, inventory, social β€” and adds engine-native rendering, physics, and networking. Native worlds are the high-fidelity path. The Native SDK **mirrors the [Web SDK](/docs/web-sdk) exactly** β€” every function, including character and world functions. If a method exists on `Helix.*` in TypeScript, it exists here with the same name and meaning. The web signature is canonical; differences are tracked in the [feature matrix](/docs/feature-matrix). ## Four languages, one API [#four-languages-one-api] The HELIX Unreal runtime ships with multiple scripting environments layered on native Unreal. All of them call the **same** SDK: See [Languages](/docs/native-sdk/languages) for setup and the same call written in each. ## Getting started [#getting-started] **Install the HELIX plugin** into your Unreal project (`HELIX` plugin, UE 5.x). It bundles the C++ SDK, the Blueprint nodes, and the PuerTS + UnLua runtimes. **Initialize** the subsystem with the world id and launch ticket the platform provides at boot: ```cpp FHelixInitParams Params; Params.WorldId = WorldId; Params.LaunchTicket = LaunchTicket; UHelix::Get()->Init(Params); ``` **Call the Platform API.** Auth, wallet, inventory, cloud save β€” identical to web. Pick your language in [Languages](/docs/native-sdk/languages). ## What's different from web [#whats-different-from-web] * **Networking.** Native worlds use Unreal's own dedicated-server networking, with HELIX [wrappers](/docs/native-sdk/networking) for replication β€” *not* the web multiplayer stack. * **Rendering & input** are the engine's. HELIX doesn't abstract the scene graph. * **The Platform API is unchanged.** That's the whole point. # Languages (/docs/native-sdk/languages) The HELIX Unreal runtime exposes the same Platform API to four environments. Choose by team and task β€” they're interoperable within a project, and they all hit the identical backend. ## One operation, four languages [#one-operation-four-languages] Granting nothing, just reading: fetch the player's profile and LIX balance. ```cpp UHelix* H = UHelix::Get(); H->Profile()->GetMyProfile(FOnProfile::CreateLambda([](const FHelixProfile& P) { UE_LOG(LogHelix, Display, TEXT("Hi %s"), *P.DisplayName); })); H->Wallet()->GetBalance(FOnBalance::CreateLambda([](const FHelixBalance& B) { UE_LOG(LogHelix, Display, TEXT("%lld LIX"), B.Lix); })); ``` ```text Event BeginPlay β†’ Helix Β· Profile Β· Get My Profile (latent) On Success β†’ Break Profile β†’ "Display Name" β†’ Print String β†’ Helix Β· Wallet Β· Get Balance (latent) On Success β†’ Break Balance β†’ "Lix" β†’ Print String ``` Every SDK call is a node. Async calls are **latent** nodes with `On Success` / `On Error` exec pins. ```ts // Identical to the Web SDK β€” this is the same TypeScript surface, inside Unreal. const me = await Helix.profile.getMyProfile(); const wallet = await Helix.wallet.getBalance(); console.log(`Hi ${me.displayName} β€” ${wallet.lix} LIX`); ``` ```lua local me = Helix.profile.getMyProfile() local wallet = Helix.wallet.getBalance() UE.Log(string.format("Hi %s - %d LIX", me.displayName, wallet.lix)) ``` ## Choosing a language [#choosing-a-language] | Language | Reach for it when | | ------------- | ----------------------------------------------------------------------------------------------------------- | | **C++** | You want the lowest-level binding, maximum performance, or you're already in C++ gameplay code. | | **Blueprint** | Designers/artists wire logic visually; rapid iteration without compiling. | | **PuerTS** | Your team knows TypeScript, or you're porting web world logic β€” the API shape is identical to `@helix/sdk`. | | **UnLua** | You prefer Lua, or you're bringing across Lua-based logic. | Because PuerTS runs the same TypeScript API as the [Web SDK](/docs/web-sdk), platform logic written for the web often moves to Unreal with little more than swapping the rendering/input layer. This is the 1:1 contract paying off. ## Async conventions [#async-conventions] * **C++** uses typed delegates (`FOnX::CreateLambda`). * **Blueprint** uses latent nodes with `On Success` / `On Error`. * **PuerTS** uses `async`/`await` and Promises, exactly like web. * **UnLua** calls are synchronous-looking (the binding yields under the hood). # Networking (Native) (/docs/native-sdk/networking) Native worlds **do not** use the web [multiplayer stack](/docs/web-sdk/multiplayer). They use Unreal's own networking β€” dedicated servers, actor replication, RPCs β€” and HELIX adds thin **wrappers** that make identity, tickets, and authoritative value checks ergonomic inside that model. The web runtime needs a networking layer because the browser has none; HELIX provides one. Unreal already has battle-tested networking, so forcing the web stack on it would be a downgrade. The [Platform API](/docs/platform-api) stays identical β€” only the transport differs. ## What HELIX wraps [#what-helix-wraps] * **Instance tickets β†’ connection.** Players arrive with a platform-issued Instance Ticket; the HELIX wrapper verifies it during Unreal's login/connection handshake so only authorized players join. * **Identity on the server.** Replicated player state is tied to the HELIX `Player` identity, not a raw connection β€” so `Helix.*` calls on the server know who they're for. * **Authoritative value checks.** Helpers to keep wallet/inventory/ownership decisions on the server, mirroring the [item execution tiers](/docs/platform-api/inventory#execution-tiers). ## The model [#the-model] Use Unreal replication as you normally would: * Server is authoritative; clients send input/RPCs. * Movement and cosmetic state replicate via Unreal's replication graph. * **Value-bearing actions** (grant item, charge LIX, award reward) go through the server-side [Platform API](/docs/platform-api), never a client RPC you trust blindly. ```cpp // server-side authoritative grant, same Platform API as web void AArenaGameMode::AwardWin(const FHelixPlayer& Player) { UHelix::Get()->Inventory()->ConsumeAndGrant(/* atomic, idempotent */); } ``` If it affects inventory, currency, or ownership, it's decided on the **server** via the Platform API β€” regardless of runtime. Unreal RPCs from clients are input, not authority. ## Scale [#scale] Native dedicated servers scale through Unreal's standard tooling and HELIX's hosting. Large-map, high-population worlds are a primary reason to choose Native over Web. # Reference (Native SDK) (/docs/native-sdk/reference) The C++ reference is generated from the HELIX Unreal plugin headers with **Doxygen** and converted to Markdown, refreshed when the plugin changes. Blueprint nodes, PuerTS, and UnLua bindings are generated 1:1 from the same C++ surface. The sample below shows the shape. ## `UHelixWallet` [#uhelixwallet] Concept: [LIX & Economy](/docs/platform-api/lix-economy). Web equivalent: [`Helix.wallet`](/docs/web-sdk/reference). ### `GetBalance` [#getbalance] ```cpp void GetBalance(const FOnHelixBalance& OnComplete); ``` Reads the current player's balances and invokes `OnComplete` with an `FHelixBalance`. **Bindings** | Runtime | Call | | --------- | ----------------------------------------------- | | C++ | `UHelix::Get()->Wallet()->GetBalance(Delegate)` | | Blueprint | `Helix Β· Wallet Β· Get Balance` (latent) | | PuerTS | `await Helix.wallet.getBalance()` | | UnLua | `Helix.wallet.getBalance()` | *** Because every binding is generated from the same C++ surface, the four languages can't drift from each other β€” and the whole surface is kept aligned with the canonical [Web SDK](/docs/web-sdk/reference) by the [feature matrix](/docs/feature-matrix) check in CI. # Authentication & Identity (/docs/platform-api/authentication) Every player has **one HELIX identity**. There is no per-world signup: when a player opens a world, they're already signed in (or they play instantly as a guest and can upgrade later). Your world never handles passwords β€” it receives a verified identity from the platform. ## The launch flow [#the-launch-flow] When a player opens a world, HELIX issues a short-lived **Launch Ticket**. Your client hands it to the SDK at init; the SDK validates it and exposes the player. ```ts await Helix.init({ worldId: window.HELIX_WORLD_ID, launchTicket: window.HELIX_LAUNCH_TICKET, }); const user = await Helix.auth.getCurrentUser(); const me = await Helix.profile.getMyProfile(); ``` ```cpp FHelixInitParams Params; Params.WorldId = WorldId; Params.LaunchTicket = LaunchTicket; UHelix::Get()->Init(Params); UHelix::Get()->Auth()->GetCurrentUser(/* delegate */); ``` ```ts await Helix.init({ worldId, launchTicket }); const user = await Helix.auth.getCurrentUser(); ``` ```lua Helix.init({ worldId = WorldId, launchTicket = LaunchTicket }) local user = Helix.auth.getCurrentUser() ``` When a player later **joins a multiplayer instance**, the platform issues a separate **Instance Ticket** that the runtime verifies before admitting them. You don't manage tickets by hand β€” the SDK and CLI wire them up. ## `Helix.auth` [#helixauth] ## `Helix.profile` [#helixprofile] ## Guests and virality [#guests-and-virality] Guest play is a first-class path, not a fallback. A visitor who opens your link plays **immediately** as a guest; the platform surfaces a signup prompt at a natural moment (often with a small LIX incentive). Your code treats guests like any other player β€” they have an id, a profile, and a (stipend) wallet. ## Permissions [#permissions] A world declares the scopes it needs in its manifest β€” e.g. `auth.profile`, `instance.join`, `network.events`, `social.friends`. Players grant them on first launch. Request only what you use. HELIX is a 16+ platform with self-declared age gating and no forced ID verification, except privacy-preserving age assurance for 18+ worlds and KYC for real-money cashout. These are enforced by the platform β€” your world doesn't implement them. ## Reference [#reference] * Web SDK β†’ [`Helix.auth` / `Helix.profile`](/docs/web-sdk/reference) * REST β†’ `GET /v1/me` # Cloud Save (/docs/platform-api/cloud-save) `Helix.cloudSave` is HELIX's **durable** key–value store, scoped per world. It's the right place for anything that must outlive an instance: player progress, settings, world state. If you know Roblox, this is **DataStore**. Cloud Save is **durable and authoritative** β€” the source of truth. [Memory Store](/docs/platform-api/memory-store) is **volatile and fast** β€” caches, leaderboards, matchmaking β€” and always expires. When in doubt about where data belongs, ask: *"would losing this be a bug?"* If yes, it's Cloud Save. ## API [#api] ## Example [#example] ```ts type Progress = { level: number; coins: number }; // load on join const progress = (await Helix.cloudSave.get(`progress:${playerId}`)) ?? { level: 1, coins: 0, }; // save on change await Helix.cloudSave.set(`progress:${playerId}`, progress); ``` ```cpp UHelix::Get()->CloudSave()->Get( FString::Printf(TEXT("progress:%s"), *PlayerId), FOnJson::CreateLambda([](const FHelixJson& Value) { /* ... */ })); ``` ```lua local key = "progress:" .. playerId local progress = Helix.cloudSave.get(key) or { level = 1, coins = 0 } Helix.cloudSave.set(key, progress) ``` ## Semantics & guarantees [#semantics--guarantees] * **Per-world namespace.** Keys are isolated to your world; you can't read another world's data. * **Authoritative.** Writes are durable once `set` resolves. * **Write from the server for value-bearing data.** Persisting currency/inventory-adjacent state belongs to server-authoritative code β€” never let a client write its own balance. See the [golden rule](/docs/introduction/how-helix-works#server-authority--the-golden-rule). * **No direct database access.** Creator code reaches persistence only through this API, never a raw DB connection. Two instances of the same world can run at once. For counters or state edited by many players, prefer an atomic update pattern (read-modify-write guarded server-side) or use [Memory Store's `increment`](/docs/platform-api/memory-store) for hot, transient counters and flush to Cloud Save periodically. ## Reference [#reference] * Web SDK β†’ [`Helix.cloudSave`](/docs/web-sdk/reference) * REST β†’ `GET/PUT /v1/cloudsave/:worldId/:key` * Guide β†’ [Persist player data](/docs/guides/persist-player-data) # Platform API overview (/docs/platform-api) The Platform API is the part of HELIX that has nothing to do with rendering. It's the same on web and Native, with the same function names and the same guarantees. These pages describe the **semantics** β€” what each capability does, what the server guarantees, and what the error cases are. Runtime-specific signatures live in each runtime's reference, linked from every page. Each Platform API page is **language-neutral**. Code samples use the runtime tabs you've seen β€” pick your runtime once and it sticks. The Web (TS) signature is canonical; other runtimes mirror it. ## The surface [#the-surface] ## The `Helix` namespace [#the-helix-namespace] On every runtime, the platform is reached through a single `Helix` object. The full set: ```ts Helix.auth Helix.profile Helix.avatar Helix.world Helix.instance Helix.network Helix.social Helix.chat Helix.voice Helix.wallet Helix.inventory Helix.marketplace Helix.cloudSave Helix.memoryStore Helix.assets Helix.analytics Helix.moderation Helix.ui ``` Initialize it once at startup: ```ts await Helix.init({ worldId, launchTicket }); ``` ## Two rules that run through everything [#two-rules-that-run-through-everything] Anything affecting **inventory, currency, or ownership** is server-authoritative. Clients are trusted only for visuals and local gameplay. See the [Universal Item Contract](/docs/platform-api/inventory#execution-tiers). **Cloud Save** is durable and authoritative β€” the source of truth. **Memory Store** is volatile, fast, and always requires a TTL β€” never the source of truth. Don't reach for one when you mean the other. # Inventory & Items (/docs/platform-api/inventory) Items in HELIX are **universal**: an item a player owns exists across worlds and renders on every runtime (each item ships per-runtime renditions β€” e.g. a web GLB and an Unreal static mesh). `Helix.inventory` is how a world reads and uses what a player owns. ## Reading inventory [#reading-inventory] ```ts if (await Helix.inventory.hasItem('vip_hat_001')) { await Helix.inventory.equipItem('vip_hat_001'); } ``` ## Execution tiers [#execution-tiers] The most important thing to understand about items is **who is allowed to run their logic**. Every item declares a tier: **If it affects inventory, currency, or ownership, the server is authoritative. If it only affects visuals or local gameplay, the client can be trusted.** Tier 3 logic runs on the server, full stop. ## Consuming an item (Tier 3) [#consuming-an-item-tier-3] Consumption is server-authoritative and **idempotent** β€” a retried network call can't double-spend: ```ts // server-side (HelixServer / HelixInstance context) const result = await Helix.inventory.consumeItem({ itemId: 'health_potion_001', quantity: 1, idempotencyKey: requestId, }); // result.mintResults describes any items/currency atomically granted in return ``` ## Item lifecycle hooks [#item-lifecycle-hooks] Interactive items implement lifecycle hooks the runtime calls for you: ```ts onEquip, onUnequip, onPlace, onRemove, onInteract, onUpdate, onStateChanged ``` ## Reference [#reference] * Web SDK β†’ [`Helix.inventory`](/docs/web-sdk/reference) * Server authority β†’ [How HELIX works](/docs/introduction/how-helix-works#server-authority--the-golden-rule) * Economy β†’ [LIX & Economy](/docs/platform-api/lix-economy) # LIX & Economy (/docs/platform-api/lix-economy) HELIX has a real, platform-wide economy. Two currencies: * **Coins** β€” soft currency, earned and spent across worlds. * **LIX** β€” hard currency, bought with real money. **100 LIX = $1.** LIX pays for premium items, collectibles, platform services, and in-world purchases. Creators earn LIX and can cash it out; stipend LIX is spend-only. Every LIX-affecting action is settled on the server. Clients **request** purchases; they never grant currency or items. All in-world purchase charges deduct LIX server-side. Treat any client-reported balance or grant as untrusted. ## The wallet [#the-wallet] `Helix.wallet` reads balances and initiates purchases. ```ts const { lix, coins } = await Helix.wallet.getBalance(); ``` ## In-world purchases (IWP) [#in-world-purchases-iwp] To sell something for LIX, the **client requests** and the **server authorizes and settles**. The SDK gives you an idempotency key so retries can't double-charge. ```ts // client: request a purchase const result = await Helix.marketplace.purchaseItem('premium_sword_001'); if (result.status === 'completed') { // item is now in the player's inventory, charged server-side } ``` ```lua local result = Helix.marketplace.purchaseItem("premium_sword_001") if result.status == "completed" then -- granted + charged server-side end ``` For full control (consumables, custom pricing) the server validates and calls the authoritative grant/charge APIs β€” see the [Inventory](/docs/platform-api/inventory) execution tiers and the [Sell an item for LIX](/docs/guides/sell-item-for-lix) guide. ## The marketplace [#the-marketplace] `Helix.marketplace` lists items, collectibles, and listings, and initiates purchases. Rare collectibles trade **peer-to-peer** for LIX (redistribution, never minted), which is the core anti-inflation mechanism β€” low drop rates protect LIX value. ## Fees & payouts (platform policy) [#fees--payouts-platform-policy] * Platform commission β‰ˆ **25%** (creators keep \~75%), down to \~10% for top tiers. * Resale/trade fee β‰ˆ **10%**, down to \~3% by tier. * Creator earnings are cashable (with KYC); stipend LIX is not. These are platform-enforced β€” you don't implement them. Payment processors and ledger internals are never part of the public SDK. You call `Helix.wallet` and `Helix.marketplace`; HELIX handles settlement. ## Reference [#reference] * Web SDK β†’ [`Helix.wallet` / `Helix.marketplace`](/docs/web-sdk/reference) * Guide β†’ [Sell an item for LIX](/docs/guides/sell-item-for-lix) # Memory Store (/docs/platform-api/memory-store) `Helix.memoryStore` is HELIX's **volatile** store: fast, shared across every running instance of your world, and **always expiring**. It's for live state that's cheap to lose. If you know Roblox, this is **MemoryStore**. Every Memory Store entry **requires a TTL** and may vanish when it expires or under pressure. It has **no economic authority** β€” it cannot grant items or LIX. For anything that must survive, write to [Cloud Save](/docs/platform-api/cloud-save). ## API [#api] ## Live leaderboard example [#live-leaderboard-example] ```ts // record a score (atomic, ranked, shared across instances) const board = Helix.memoryStore.sortedMap('round-scores'); await board.set(playerId, score, 300); // 5-minute TTL // read the top 10 const top = await board.getRange({ limit: 10, descending: true }); ``` ## Hot counter example [#hot-counter-example] ```ts // count concurrent players in a zone without hammering Cloud Save const inZone = await Helix.memoryStore.increment(`zone:${zoneId}`, 1, 60); ``` ## When to use which [#when-to-use-which] | Need | Use | | -------------------------------------- | ------------------------------------------- | | Player progress, settings, owned state | [Cloud Save](/docs/platform-api/cloud-save) | | Live leaderboard for a round | Memory Store `sortedMap` | | Matchmaking / cross-instance handoff | Memory Store `queue` | | Hot counter (players in a zone) | Memory Store `increment` | | Anything you'd be upset to lose | [Cloud Save](/docs/platform-api/cloud-save) | ## Reference [#reference] * Web SDK β†’ [`Helix.memoryStore`](/docs/web-sdk/reference) * REST β†’ `/v1/memorystore/:worldId/...` # Social & Presence (/docs/platform-api/social) `Helix.social` exposes the player's social graph: who their friends are, who's online, and how to pull them into your world. Because identity is platform-wide, friendships and presence work across every world automatically. ## API [#api] ## Invite a friend into your world [#invite-a-friend-into-your-world] ```ts const friends = await Helix.social.getFriends(); const online = []; for (const f of friends) { const p = await Helix.social.getPresence(f.id); if (p.online) online.push(f); } // pull an online friend into this instance if (online[0]) await Helix.social.inviteToInstance(online[0].id); ``` ## Presence [#presence] Presence tells you whether a friend is online and, when permitted, what world they're in β€” the basis for "join friend" buttons and for surfacing active sessions. Respect the player's privacy settings; the platform enforces visibility. Real-time chat is `Helix.chat`; spatial/proximity voice is `Helix.voice` (see the [Add proximity voice](/docs/guides) guides). Friend discovery can optionally link external accounts (e.g. Discord) through official SDKs β€” never by scraping. ## Reference [#reference] * Web SDK β†’ [`Helix.social`](/docs/web-sdk/reference) # Web SDK (/docs/web-sdk) The Web SDK is HELIX's **TypeScript** runtime and the **canonical API contract**. Worlds built here are playable instantly from a link on any device. Everything in the [Platform API](/docs/platform-api) is available, plus a full **multiplayer & networking** stack that is specific to the web runtime. The Web SDK's surface is frozen first; the [Native (Unreal) SDK](/docs/native-sdk) mirrors it 1:1. When you read a Platform API page, the Web (TS) tab is the canonical signature. ## Packages [#packages] | Package | Purpose | | ------------------- | ------------------------------------------------------------------ | | `@helix/sdk` | The client SDK β€” the `Helix` namespace used in browser/world code. | | `@helix/server-sdk` | The server SDK β€” `HelixInstance` and authoritative APIs. | | `@helix/cli` | Scaffold, run, validate, and deploy worlds. | ## Client [#client] ```ts import { Helix } from '@helix/sdk'; await Helix.init({ worldId: window.HELIX_WORLD_ID, launchTicket: window.HELIX_LAUNCH_TICKET, }); const me = await Helix.profile.getMyProfile(); ``` From here, the whole [Platform API](/docs/platform-api) is available on `Helix.*`, and the [networking API](/docs/web-sdk/multiplayer) on `Helix.network` / `Helix.instance`. ## Server [#server] Server logic extends `HelixInstance` and owns authoritative state. The runtime calls your lifecycle hooks: ```ts import { HelixInstance } from '@helix/server-sdk'; export default class MyInstance extends HelixInstance { async onCreate(ctx) {} async onPlayerJoin(player) {} async onPlayerLeave(player) {} async onEvent(player, event, payload) {} async onTick(dt) {} async onClose() {} } ``` ## Get started [#get-started] # Multiplayer & Networking (/docs/web-sdk/multiplayer) This networking stack is part of the **Web** runtime. Native (Unreal) worlds use the engine's own dedicated-server networking β€” see [Native networking](/docs/native-sdk/networking). The [Platform API](/docs/platform-api) (auth, LIX, storage, inventory) is shared; *this page is not.* HELIX ships its own real-time layer β€” built on **Colyseus** β€” so you never touch a raw socket or a room API directly. You work with **Instances**, **Events**, and the [`HelixInstance`](/docs/web-sdk#server) server class. The transport is an implementation detail: the public vocabulary stays World / Build / Instance / Player / Event, and you import `@helix/sdk` / `@helix/server-sdk` rather than `colyseus` directly. ## Instances [#instances] A player joins an **Instance** β€” a running session of your Build. Default capacity is 32 players (higher with review). ## Events [#events] Networking is message-based. Events flow clientβ†’server, serverβ†’client, and serverβ†’all. ### Client [#client] ```ts // listen Helix.network.on('wave', ({ from }) => showWave(from)); // send Helix.network.send('wave', {}); // request/response const { rank } = await Helix.network.request('get-rank', { boardId: 'arena' }); ``` ### Server [#server] ```ts import { HelixInstance } from '@helix/server-sdk'; export default class Arena extends HelixInstance { async onEvent(player, event, payload) { if (event === 'wave') { this.broadcast('wave', { from: player.id }); // relay to everyone } } } ``` ## The networking model [#the-networking-model] HELIX web multiplayer is a **hybrid social model**: * **Movement** is client-authoritative and server-relayed (default transform & broadcast \~10 Hz, 100–200 ms interpolation) β€” smooth, cheap, good enough for social worlds. * **Value** (wallet, inventory, rewards, moderation, membership) is **server-owned**. The server never trusts client events for these. Movement and cosmetic events can come from the client. Anything that grants currency, items, or rewards must be decided by your `HelixInstance` server code. This mirrors the [item execution tiers](/docs/platform-api/inventory#execution-tiers). A future authoritative mode (higher tick, fully server-owned state) is planned for competitive/ranked worlds. ## The realtime envelope [#the-realtime-envelope] Every message on the wire is a typed envelope β€” useful when debugging: ```ts { id: string; type: 'event' | 'request' | 'response' | 'error' | 'system'; event: string; payload: unknown; requestId?: string; senderId?: string; timestamp: number; } ``` ## Reference [#reference] * Web SDK β†’ [`Helix.network` / `Helix.instance` / `HelixInstance`](/docs/web-sdk/reference) * Guide β†’ [Build your first multiplayer world](/docs/guides/first-multiplayer-world) # Reference (Web SDK) (/docs/web-sdk/reference) This reference is generated from the `@helix/sdk` TypeScript source with **TypeDoc** and refreshed automatically when the SDK changes on `main`. See [the pipeline](/docs/cli#auto-generated-reference) for how it works. The page below is a **representative sample** of the generated output until the SDK source is wired in. ## `Helix.wallet` [#helixwallet] The player's economy surface. See the [LIX & Economy](/docs/platform-api/lix-economy) concept page for semantics. ### `getBalance()` [#getbalance] ```ts getBalance(): Promise ``` Returns the current player's balances. **Throws** β€” `HelixError('NOT_INITIALIZED')` if called before `Helix.init`. ### `onBalanceChanged(callback)` [#onbalancechangedcallback] ```ts onBalanceChanged(cb: (balance: Balance) => void): Unsubscribe ``` Subscribes to wallet changes; returns an unsubscribe function. Fires after a purchase settles server-side. *** ## `Helix.cloudSave` [#helixcloudsave] Durable per-world key–value storage. Concept: [Cloud Save](/docs/platform-api/cloud-save). ### `get(key)` [#gettkey] ```ts get(key: string): Promise ``` ### `set(key, value)` [#settkey-value] ```ts set(key: string, value: T): Promise ``` Writes durably; resolves once the write is committed. *** When the SDK source is connected, this section lists **every** namespace, class, method, parameter, return type, and error β€” auto-generated and always in sync with the shipped `@helix/sdk`. The hand-written [Platform API](/docs/platform-api) pages link here for exact signatures, and this reference links back to them for semantics.