API Reference
Every method on the carver object, with its signature and when to call it. Import the singleton once and use it anywhere:
import { carver } from "@carverjs/embed-sdk";
// or: import carver from "@carverjs/embed-sdk"; // default export, same objectAll methods are safe no-ops outside the marketplace iframe and never throw.
Overview #
| Method | Signature | When to call it |
|---|---|---|
ready | () => void | First frame rendered. Required — the shell loader waits for it. |
progress | (percent: number) => void | Loading progress, clamped to 0–100. |
score | (value: number, label?: string) => void | Report a score (finite numbers only). |
event | (name: string, payload?: unknown) => void | Gameplay events for stat aggregation. |
error | (code: string, message: string) => void | Fatal error — the shell shows an error card. |
requestFullscreen | () => void | Ask the shell to go fullscreen (needs a user gesture). |
exit | () => void | Game finished; hand control back to the shell. |
getIdentity | () => Promise<CarverIdentity> | Signed token proving which player this is. See Player Identity. |
subscribe | (handler) => () => void | Listen for shell → game messages. Returns an unsubscribe function. |
configure | (config) => void | Optional origin pinning. |
isEmbedded | () => boolean | true when running inside the marketplace shell. |
ready #
carver.ready(): voidSignals that the game has booted and rendered its first frame. The shell hides its loader and begins counting the play. Call this exactly once per boot, as early as the first frame is actually visible.
startRenderLoop();
carver.ready();progress(percent) #
carver.progress(percent: number): voidReports load or level progress. percent is clamped to [0, 100]; non-finite values become 0. Drives the numeric readout inside the shell loader.
await loadAssets((pct) => carver.progress(pct));score(value, label) #
carver.score(value: number, label?: string): voidReports a score for the player-profile stats. value must be a finite number — NaN and ±Infinity are dropped by the shell. label is an optional display unit (e.g. "coins", "points"); the shell truncates it at 64 characters.
carver.score(1280, "points");
carver.score(coins, "coins");event(name, payload) #
carver.event(name: string, payload?: unknown): voidEmits an arbitrary gameplay event for play-stat aggregation. name is rejected by the shell if it exceeds 128 characters. payload is any JSON-cloneable value (passed by reference into postMessage).
carver.event("level-complete", { level: 3, timeMs: 48210 });
carver.event("boss-defeated");error(code, message) #
carver.error(code: string, message: string): voidReports a fatal error. The shell replaces the game iframe with an error card showing the code and message. Use a short machine-readable code (truncated at 64 chars) and a human-readable message (truncated at 500 chars).
carver.error("asset-load-failed", "texture atlas returned 404");requestFullscreen() #
carver.requestFullscreen(): voidAsks the shell to take the game fullscreen on its behalf. Call it from inside a user-gesture handler (click, key, tap) — browsers refuse fullscreen requests without a recent user activation. The game can also call the native element.requestFullscreen() itself; both paths are supported.
button.addEventListener("click", () => carver.requestFullscreen());exit() #
carver.exit(): voidSignals that the game is finished. The shell may navigate back or show an end card. Use it on game-over or when the player chooses to quit.
getIdentity() #
carver.getIdentity(): Promise<CarverIdentity>Requests a short-lived signed token identifying the signed-in marketplace player, so your own backend can tie its data to that player. Always resolves — never rejects — with a discriminated union:
type CarverIdentity =
| { ok: true; token: string; userId: string; expiresAt: number }
| { ok: false; reason:
| "signin-required" | "not-embedded" | "timeout" | "rate-limited" | "error" };Full walkthrough, including how to verify the token on your server: Player Identity.
const id = await carver.getIdentity();
if (id.ok) {
await saveToMyBackend(id.token, id.userId);
} else if (id.reason === "signin-required") {
showSignInPrompt();
}subscribe(handler) #
carver.subscribe(handler: (message: CarverInboundMessage) => void): () => voidListens for shell → game messages and returns an unsubscribe function. Only messages whose source is the direct parent window are delivered. No inbound message types are emitted by the shell today; the channel exists so future hints (pause/resume on tab-hide, volume, locale) arrive without an SDK upgrade. Treat unknown type values as no-ops.
const unsubscribe = carver.subscribe((msg) => {
if (msg.type === "carver:pause") pauseLoop();
});
// later, on teardown
unsubscribe();configure(config) #
carver.configure(config: { targetOrigin?: string; parentOrigin?: string }): voidOptional origin pinning. Call once at boot, before subscribe. By default outbound messages use targetOrigin: "*" (they carry no secrets, and a sandboxed game cannot know which shell origin embeds it). If your game only ever ships to one shell, you can pin it:
carver.configure({ targetOrigin: "https://carverjs.dev" });| Option | Default | Description |
|---|---|---|
targetOrigin | "*" | Target origin for outbound postMessage. |
parentOrigin | (unset) | When set, inbound messages must also come from this exact origin, on top of the always-on parent-window check. |
isEmbedded() #
carver.isEmbedded(): booleanReturns true when the game is running inside another frame (the marketplace shell) in a browser, false otherwise (top-level window, SSR, tests). Useful for branching dev-only UI:
if (!carver.isEmbedded()) {
showLocalDevBanner(); // running your build directly, not on the marketplace
}