> ## Documentation Index
> Fetch the complete documentation index at: https://docs.kinematic.run/llms.txt
> Use this file to discover all available pages before exploring further.

> ## Agent Instructions
> These are the customer docs for kinematic, a name written in lowercase except at the start of a sentence. Kinematic provides provably fair casino games, served to a casino's site by a game server: a Cloudflare Worker that the kinematic dashboard deploys into the casino's own Cloudflare account.
> Never put SESSION_SECRET or WALLET_SECRET in code, prompts, logs, commits or chat. Read them from environment variables and ask the person you work with to set them. The dashboard's Integration page shows each secret once.
> Values such as lucky-star, luckystar.example, og-rgs-lucky-star.luckystar.workers.dev, games.luckystar.example and player_48213 are examples. Use the casino's own casino ID, game server origin, element tag, session issuer and currencies: the Instructions for your coding agent on the dashboard's Integration page hold them, or ask the person you work with.
> To debug, start at https://docs.kinematic.run/troubleshooting and https://docs.kinematic.run/reference/errors. The wallet contract is at https://docs.kinematic.run/api/wallet.openapi.yaml.
> Sandbox bets are recorded on Solana devnet. Live game servers record nothing on Solana until the audited mainnet program is deployed.

# Embed the games

> Load the games from your game server, connect each element to your session endpoint, show errors in your page, and handle several games, sizes and single-page apps.

Your game server serves the games to your pages. A page imports the loader from your game server, places an element, and connects it with a function that fetches a session token from your backend.

## The embed

The **Put the games on your page** step on **Integration** shows the embed under **Your page**, with your game server's origin, your element's tag and your first game filled in:

```html theme={null}
<og-game game="dice" controls></og-game>
<script type="module">
  import { connect } from "https://og-rgs-lucky-star.luckystar.workers.dev/element/v1/loader.js";
  connect(document.querySelector("og-game"), {
    token: ({ publicKey }) =>
      fetch("/api/game-session", { method: "POST", body: JSON.stringify({ publicKey }) }).then((r) => r.text()),
  });
</script>
```

* With several game servers, a **Game server** select above the code chooses the one the code and the Content Security Policy use.
* Before your first game server is deployed, the code shows `https://rgs.your-casino.example` in its place, with the banner `Your game server is not deployed yet, so the code shows rgs.your-casino.example in its place.` and **Open game server**.
* Below the code, **Content Security Policy, for pages that send one** holds the directives for that game server. See [Content Security Policy](https://docs.kinematic.run/integrate/csp.md).
* Under it, the step lists the origins your game server serves pages on, with a link to **Settings** to add another. With no allowed origin, it shows `Add your page's origin to Allowed origins. Your game server refuses pages on any other origin.` and **Open settings**.

### A fuller example

This example from these docs adds what the dashboard's embed leaves out: it reads the tag from `config`, checks your endpoint's answer, and shows errors in your page's own words.

```html theme={null}
<og-game game="dice" controls></og-game>
<p id="game-message" role="status"></p>

<script type="module">
  import { connect, config } from "https://og-rgs-lucky-star.luckystar.workers.dev/element/v1/loader.js";

  const messages = {
    insufficient_funds: "Your balance is too low for this bet.",
    bet_limit: "This bet is outside the table limits.",
    bets_disabled: "Betting is paused. Try again later.",
    round_active: "Finish your open round first.",
  };

  connect(document.querySelector(config.tag), {
    token: ({ publicKey }) =>
      fetch("/api/game-session", {
        method: "POST",
        headers: { "content-type": "application/json" },
        body: JSON.stringify({ publicKey }),
      }).then((response) => {
        if (!response.ok) throw new Error(`game-session answered ${response.status}`);
        return response.text();
      }),
    onError: (error) => {
      const code = error instanceof Error ? error.message : String(error);
      document.getElementById("game-message").textContent = messages[code] ?? "Something went wrong. Try again.";
      console.warn(error);
    },
  });
</script>
```

Replace the origin with your game server's. If you renamed the element on **Appearance**, write your tag in place of `og-game`; `config.tag` holds it, so the script finds the element.

## The loader

`https://<game server>/element/v1/loader.js` is a JavaScript module, built for your casino on each request. It exports two names:

* `config`: your casino's element settings. `config.tag` is your element's tag, `config.games` the games you turned on, `config.theme` your saved theme, `config.logo` your logo as a PNG data URL, or `null`, and `config.mode` the mode your game server runs, `"sandbox"` or `"live"`.
* `connect(element, options)`: connects one element to your game server.

Import it from a `<script type="module">` or with `import()`, in the browser only. In a framework that renders on the server, import it in code that runs on the client, after the element is in the page.

Your page's origin must be in **Allowed origins**, under **Players and sessions** in [Settings](https://docs.kinematic.run/dashboard/settings.md#players-and-sessions), or your game server refuses the loader with `403`. If your pages send a Content-Security-Policy, add the directives in [Content Security Policy](https://docs.kinematic.run/integrate/csp.md).

## The element

| Attribute | Meaning |
| - | - |
| `game` | The game to show, by ID: `mines`, `plinko`, `dice`, `limbo`, `crash`, `roulette`, `keno`, `baccarat`, `wheel`, `pump`, `diamonds`, `hilo` or `blackjack`. A game you did not turn on falls back to your first game. |
| `controls` | Shows the bet controls: the amount, the game's options, **BET** and Auto. Players can bet only through them. |
| `minimal` | Shows the game's screen and readouts without the title bar and toolbar. |
| `stats` | Adds a **Live stats** button. Pressing it fires `og-intent` with the action `stats`, and your page shows its own panel. |

The loader adds the **Provably fair** button to every element and opens the dialog when a player presses it. Write the element with an end tag, `<og-game ...></og-game>`: custom elements cannot close themselves.

## The token function

`connect()` calls your `token` function whenever the element needs a session token, and expects the token's text back:

1. First with `{}`, to read the player and currency from the token.
2. Then with `{ publicKey }`, the player's device key, which your endpoint puts in the token's `cnf`. A browser that cannot keep a device key never makes this call.
3. Again shortly before each token expires.

Let the function reject when your endpoint fails. A call that takes longer than 10 seconds fails with `token_timeout`, and an answer that is not a token fails with `token_invalid`; the element tries again with a growing delay. [Session tokens](https://docs.kinematic.run/integrate/session-tokens.md) shows the endpoint.

## Show errors

The element shows no error text on the game itself. Your `onError` function receives every failure: a `connect()` call that could not start, and every bet your game server refused, as an `Error` whose `message` is the code. The same errors fire as `og-error` events on the element.

Show the codes your players act on, such as `insufficient_funds`, `bet_limit`, `bets_disabled` and `round_active`, in your own words, and log the rest. [Errors](https://docs.kinematic.run/reference/errors.md) lists every code. Two outcomes are not reported, because the stake comes back on its own: a bet refunded after a key rotation, and an abandoned bet.

## When the game is ready

`connect()` resolves as soon as the element is bound, before the connection opens, to a connection object, or to `undefined` after it reported a failure to `onError`. The element fires `og-ready` once its scene is built. While the connection opens, the element shows **Connecting**: a **BET** pressed then goes out once the connection is ready, or is dropped after 4 seconds. The balance shows a placeholder until it is known.

## Several games

Place one element per game, and call `connect()` for each. Elements of the same player and currency share one connection to your game server.

To switch the game in an element, set its `game` attribute. The loader loads the new game and connects it again. Build your own picker from `config.games`:

```js theme={null}
const element = document.querySelector(config.tag);
for (const id of config.games) {
  const button = document.createElement("button");
  button.textContent = id;
  button.onclick = () => element.setAttribute("game", id);
  document.querySelector("#game-picker").append(button);
}
```

## Single-page apps

Call `connect()` once per element, and keep what it returns. Before you remove the element from the page, call the connection's `disconnect()`: the loader does not notice a removed element. The page's connection to your game server closes once no element uses it.

```js theme={null}
const connection = await connect(element, { token, onError });
// When the route unmounts:
connection?.disconnect();
```

## Size

The element lays itself out by its own width, not the window's: from 701 pixels wide it uses the desktop layout, and below that the compact layout. Set the heights with two tokens:

```css theme={null}
og-game {
  --og-height: 720px; /* desktop height, at least 600px */
  --og-mobile-height: calc(100svh - 96px); /* the compact screen and controls */
}
```

## Balance changes

When a player deposits or withdraws in your cashier, post a wallet event from your backend: your game server reads the balance again and updates every open tab. See [Balance changes outside the games](https://docs.kinematic.run/integrate/wallet.md#balance-changes-outside-the-games). In sandbox the game server keeps the test balances itself.

## Your logo

The games never draw your logo. `config.logo` holds the logo you uploaded on **Appearance**, so your page can show it next to the games:

```js theme={null}
if (config.logo) document.querySelector("#casino-logo").src = config.logo;
```


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.