Skip to main content

Documentation Index

Fetch the complete documentation index at: https://openturn.io/docs/llms.txt

Use this file to discover all available pages before exploring further.

openturn deploy ships your game to the openturn.io cloud. The control plane provisions a hosted backend per game and returns a play URL anyone can open. openturn build produces the bundle; openturn deploy uploads it. Under the hood, openturn cloud runs your bundle on Cloudflare Workers and Durable Objects (one DO per room) — but you don’t manage any of that. You only interact with openturn login and openturn deploy.

Project layout

You need the same three files as tutorial: tic-tac-toe multiplayer:
  • app/game.ts — exports game and match.
  • app/page.tsx — the React entry point.
  • app/openturn.ts — metadata with runtime: "multiplayer".

The openturn.ts metadata

export const metadata = {
  name: "Tic Tac Toe Multiplayer",
  runtime: "multiplayer",
  multiplayer: {
    gameKey: "tic-tac-toe-multiplayer",   // stable identifier for this game
    schemaVersion: "1",                    // bump to reset persisted rooms
  },
};
gameKey is the identifier the cloud control plane uses to route play URLs. schemaVersion lets you force-reset persisted rooms when you change G in an incompatible way.

Build

openturn build app
This produces, by default, .openturn/deploy/:
  • Static assets (index.html, client JS, CSS).
  • entry.<hash>.js — the client bundle Vite emitted.
  • worker.js + openturn.worker-meta.json — the server bundle and its room bindings.
  • openturn.manifest.json — a manifest summarizing the build.
Inspect the manifest:
cat .openturn/deploy/openturn.manifest.json
Fields of interest:
  • deploymentID, projectID, runtime — identifiers.
  • entry — the JS entry the HTML shell loads.
  • assets, styles — static files.
  • multiplayer.gameKey, multiplayer.schemaVersion, multiplayer.digest — hash of the server bundle, used for versioning rooms.
  • build.openturnPackages — the resolved @openturn/* versions baked in.

Log in

openturn login --token <your-cloud-token>
This writes the token to ~/.openturn/cloud-auth.json. The CLI defaults to openturn.io; pass --url to point at a staging environment.

Deploy

openturn deploy app
The CLI:
  1. Builds the project (equivalent to openturn build app).
  2. Uploads the static bundle and server script to the openturn cloud control plane.
  3. Registers or updates the deployment under the gameKey from openturn.ts.
  4. Prints the play URL — a URL that encodes the backend in a fragment, so any browser can open it and join a room.
You can pass a project slug or display name explicitly:
openturn deploy app --project my-tic-tac-toe --name "Tic Tac Toe"

Play URL fragments

Deployed apps read window.location.hash for a HOSTED_FRAGMENT_KEY value (encoded JSON from @openturn/bridge). Share the full play URL — the fragment is what tells the React app how to find the hosted backend.

Static assets and images

There are two supported ways to ship images, fonts, or other static files:
  1. Import from JS or CSSimport logo from "./logo.png" or background-image: url("./bg.svg"). Vite emits the file under assets/<name>-<hash>.<ext> so the URL is stable forever; small images (< 4 KiB by default) are inlined as data URLs. This is the right pattern for assets your code references directly.
  2. Drop into public/ — files under <projectDir>/public/** are copied into the deployment root verbatim and served at the same path. A file at public/banner.png is reachable at /banner.png from your page. These files are not hashed; the per-deployment cache key comes from the deployment ID, so a redeploy with a changed file invalidates downstream caches.

Bundle size limits

openturn deploy enforces these limits before contacting the cloud, and the cloud re-validates them on receipt:
LimitCap
Per-asset size25 MiB
Total assets25 MiB
Total images25 MiB
Multiplayer worker bundle (gzipped)3 MiB
The worker-bundle ceiling matches the Cloudflare Workers Free-tier script size. The asset and image caps keep iframe load times reasonable. If a build breaches a limit, the CLI fails fast with a structured error like bundle_too_large_per_asset and prints the offending file. To shrink: optimize images (squoosh, oxipng), code-split with dynamic import(), or drop unused dependencies.

Schema versioning

If you change G in a way the reducer no longer accepts old action logs for, bump schemaVersion in app/openturn.ts. Deployed rooms with the old version are closed on next restart; new rooms start fresh. You do not need to bump schemaVersion for additive changes (new optional fields, new moves that do not invalidate old sequences).

Debugging a deploy

  • openturn_deploy_error — the cloud returned an error. The CLI prints the JSON body.
  • Play URL opens to “missing_hosted_backend” — the page loaded without the fragment. Share the exact URL the CLI printed, or ensure your hosting environment preserves URL fragments.
  • Moves fail with unauthorized — the player’s room token expired. Refresh the page; @openturn/bridge handles token refresh automatically after that.

A deploy-ready reference

examples/games/splendor/app is wired end-to-end for cloud deploy — runtime: "browser" metadata, all bundle prerequisites in place, plus attachBots(splendor, splendorBotRegistry) so the deployed lobby exposes the three bots (random, greedy, strategic). To walk it:
cd openturn/examples/games/splendor/app
bun run deploy
The CLI builds the browser bundle, generates and uploads the multiplayer Worker, and prints the openturn-cloud play URL. Use the splendor app’s package.json deploy script (--project splendor --name "Splendor") as a template for your own.