Skip docs navigation
Public Examples
Tutorial
Engine-authored gameplay exported to a web surface through a TPG bridge layer.

Godot Game Tutorial

Build Godot Signal Toss from a Godot 4.x Web export when you want engine-authored gameplay while TPG owns room lifecycle, controller identity, state sync, and publishing.

What You Build

Godot Signal Toss is a compact host-display plus controller example that mirrors a Godot Web export without requiring the Godot editor in CI:

  • the host display boots @tpgames/bridge-godot and exposes window.TPG_GODOT
  • exported Godot scripts call the bridge through Godot 4.x JavaScriptBridge
  • TPG shared state owns round-level facts such as active lane and total signals
  • TPG player state owns each controller lane, charge, and signal count
  • transient signal effects travel through runtime.broadcast("godot:signal", ...)
  • the bundle includes the web surface files plus godot-export/ project metadata
  • the registration script uploads, reviews, publishes, and verifies the game through the registry API

The tutorial below includes the complete fixture source. The browser bridge is published as @tpgames/bridge-godot.

Supported Godot Path

Target Godot 4.x Web exports. The current TPG package is a browser-side bridge, not an editor plugin that runs Godot exports for you.

Use this path when your exported Godot project can:

  • call JavaScript from GDScript with JavaScriptBridge
  • load inside a TPG host or controller iframe
  • keep authoritative room facts in TPG shared/player state instead of in engine-only globals
  • export web artifacts such as .html, .js, .wasm, and .pck into a bundle folder

The checked-in example keeps the CI payload lightweight by including godot-export/project.godot and a reference Main.gd script. A production project should export the real Godot web artifacts into the same godot-export/ folder.

Create the Project

Start with the canonical TP Games project so the game inherits the tested scripts, CI workflow, validation, and bundled AI development skill:

If the author CLI is already installed, tpgames init godot-signal-toss replaces the first scaffold command.

This tutorial intentionally replaces the starter surface layout with the checked-in Godot example. Copy the example's root host.html and controller.html in place of host.html and controller.html, then remove vite.config.mjs before creating the vite.config.ts shown below. Do not keep both Vite config files.

Use the checked-in example as the reference layout:

Install the normal game kit, the Godot bridge, and the authoring CLI:

For a real Godot game, export your web build into godot-export/, then adapt host.html to load the generated Godot loader. Keep controller.html as a normal DOM surface unless you specifically need a second Godot export for controller UI.

Configure the Author Tools

Add the device, bundle, and registry commands to package.json:

Configure vite.config.ts with the wrapper surfaces and workbench:

Create tpgames.json; the copy rule carries the real Godot export into a registry bundle:

Boot the Bridge

Both host and controller pages boot a normal TPG runtime and install the Godot bridge:

createGodotBridgeGame() exposes a browser runtime API on window.TPG_GODOT. The default global name is deliberate: Godot scripts can reach it through JavaScriptBridge.eval(...) without importing TPG TypeScript directly inside the Godot project.

Map Godot Lifecycle Events

The bridge relays TPG runtime events into browser events that Godot can subscribe to:

  • lifecycle for boot, ready, and stage transitions
  • settings for room settings such as volume
  • participants for connected players and surfaces
  • shared-state for durable room-wide game facts
  • player-state for participant-owned facts
  • message for transient runtime messages

In a Godot Web export, a GDScript can call the global bridge like this:

Use reportReady() when the Godot scene can receive runtime events. Use durable state methods for facts that should survive reconnect, and use broadcast() or sendToParticipant() for effects that are safe to miss.

Keep State in TPG

Godot can own rendering, animation, physics, and scene-local effects. TPG should own the synchronized facts that need to reach host, controller, spectator, or future dedicated-runtime surfaces.

The example models shared state separately from engine objects:

Each controller writes its own player state:

The host display listens for godot:signal messages and updates its local feed, while durable shared/player snapshots remain available after refresh or reconnect.

Generate the Manifest

Use createGodotManifest() when rendering the bundle manifest:

The helper creates a display-plus-controller manifest aligned with the public TPG manifest contract. The public tpgames bundle command follows tpgames.json, copies the built assets, manifest, and godot-export/ into dist/, then zips the archive for registry upload.

Test on Multiple Devices Without Uploading

After exporting the current Godot Web build, the example's @tpgames/sdk-dev-kit Vite plugin exposes its display and controller to the normal TPG room flow. Install cloudflared, then run:

The command starts Vite and a temporary Cloudflare Quick Tunnel, then opens the host room on https://play.tp.games. Scan the room QR with two or more phones. No registry upload, API key, or bundle build is required, but the current Godot Web export must already exist locally.

To use a tunnel you already manage, keep its origin port aligned with the CLI:

A Quick Tunnel exposes the local Vite server and source modules publicly. Treat the generated host link as private because it contains the temporary development-manifest descriptor; share only the room QR or controller invite. Keep .env files, credentials, and private assets outside Vite's served root, and stop the command and tunnel when finished. Use --no-open when you only want the private host link printed.

Export, Bundle, and Register

Render the bundle:

The output should include:

For local interactive publishing, start the registry and browser approval shell from a TPG repository checkout in two terminals:

Then sign in and register from the Godot example repo:

The registration script uploads the archive to /creator/uploads, submits the version, creator-publishes it with the selected credential, fetches /games/{gameId}/manifest, and verifies a published Godot asset under /published-assets/{gameId}/{version}/godot-export/project.godot.

Registration delivers a built game version; it does not create a developer account. Its default upload mode stops after upload, --mode submit requests review, and --mode publish --yes deliberately completes creator publication. Browser login stores a session only for the exact registry origin. Use TPG_API_KEY only for CI or another unattended environment, keep it in the environment rather than arguments or project configuration, and grant only the scopes required by the selected mode.

Launch Verification

After publishing, open the web shell, select Godot Signal Toss, join with at least two controllers, and start the game. Verify:

  • the host iframe shows the Godot stage shell and recent signal feed
  • window.TPG_GODOT exists inside the host and controller iframes
  • controller lane buttons and charge input update player state
  • Signal broadcasts a godot:signal runtime message and records an analytics milestone
  • refreshing a controller preserves the participant seat and can continue play
  • returning to the lobby stops the surface without leaving a runaway render loop

For browser QA, test mobile, tablet, laptop, and desktop widths. Godot exports often have fixed canvas sizes, so verify no horizontal overflow, readable controller controls, and visible keyboard focus on every button.

Troubleshooting

  • window.TPG_GODOT is undefined: confirm the host/controller page calls bootIframeGame(createGodotBridgeGame(), ...) before the Godot scene script calls JavaScript.
  • Godot calls run before TPG boot: wait for your scene _ready() and retry only after the page bridge exists.
  • Controller effects do not reach the host: verify the controller calls broadcast("godot:signal", payload) and the host listens for message events with the same message type.
  • Published assets 404: inspect dist/manifest.json and confirm every entry path is relative to the bundle root, not an absolute /assets/... path.
  • The Godot canvas overflows on phones: use a responsive wrapper around the exported canvas and keep critical controller actions in the DOM controller surface.
  • CI cannot run the Godot editor: keep editor export as a local author step, then commit or upload only the generated web export artifacts needed by TPG packaging.

Current Limitations

  • @tpgames/bridge-godot is a browser-side bridge and manifest helper, not a full Godot editor plugin.
  • The checked-in example does not include generated .wasm or .pck artifacts; it is shaped for CI-verifiable TPG packaging.
  • Godot scripts must still call window.TPG_GODOT through JavaScriptBridge.
  • Spectator-specific Godot surfaces are not included.
  • Registry review and publish are API-driven for automation, so product creator/reviewer flows should still be tested separately for production submissions.