API Reference

Every method on the carver object, with its signature and when to call it. Import the singleton once and use it anywhere:

ts
import { carver } from "@carverjs/embed-sdk";
// or: import carver from "@carverjs/embed-sdk";  // default export, same object

All methods are safe no-ops outside the marketplace iframe and never throw.

Overview #

MethodSignatureWhen to call it
ready() => voidFirst frame rendered. Required — the shell loader waits for it.
progress(percent: number) => voidLoading progress, clamped to 0–100.
score(value: number, label?: string) => voidReport a score (finite numbers only).
event(name: string, payload?: unknown) => voidGameplay events for stat aggregation.
error(code: string, message: string) => voidFatal error — the shell shows an error card.
requestFullscreen() => voidAsk the shell to go fullscreen (needs a user gesture).
exit() => voidGame finished; hand control back to the shell.
getIdentity() => Promise<CarverIdentity>Signed token proving which player this is. See Player Identity.
subscribe(handler) => () => voidListen for shell → game messages. Returns an unsubscribe function.
configure(config) => voidOptional origin pinning.
isEmbedded() => booleantrue when running inside the marketplace shell.

ready #

ts
carver.ready(): void

Signals 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.

ts
startRenderLoop();
carver.ready();

progress(percent) #

ts
carver.progress(percent: number): void

Reports load or level progress. percent is clamped to [0, 100]; non-finite values become 0. Drives the numeric readout inside the shell loader.

ts
await loadAssets((pct) => carver.progress(pct));

score(value, label) #

ts
carver.score(value: number, label?: string): void

Reports 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.

ts
carver.score(1280, "points");
carver.score(coins, "coins");

event(name, payload) #

ts
carver.event(name: string, payload?: unknown): void

Emits 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).

ts
carver.event("level-complete", { level: 3, timeMs: 48210 });
carver.event("boss-defeated");

error(code, message) #

ts
carver.error(code: string, message: string): void

Reports 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).

ts
carver.error("asset-load-failed", "texture atlas returned 404");

requestFullscreen() #

ts
carver.requestFullscreen(): void

Asks 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.

ts
button.addEventListener("click", () => carver.requestFullscreen());

exit() #

ts
carver.exit(): void

Signals 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() #

ts
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:

ts
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.

ts
const id = await carver.getIdentity();
if (id.ok) {
  await saveToMyBackend(id.token, id.userId);
} else if (id.reason === "signin-required") {
  showSignInPrompt();
}

subscribe(handler) #

ts
carver.subscribe(handler: (message: CarverInboundMessage) => void): () => void

Listens 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.

ts
const unsubscribe = carver.subscribe((msg) => {
  if (msg.type === "carver:pause") pauseLoop();
});

// later, on teardown
unsubscribe();

configure(config) #

ts
carver.configure(config: { targetOrigin?: string; parentOrigin?: string }): void

Optional 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:

ts
carver.configure({ targetOrigin: "https://carverjs.dev" });
OptionDefaultDescription
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() #

ts
carver.isEmbedded(): boolean

Returns 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:

ts
if (!carver.isEmbedded()) {
  showLocalDevBanner(); // running your build directly, not on the marketplace
}