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-godotand exposeswindow.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.pckinto 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:
lifecyclefor boot, ready, and stage transitionssettingsfor room settings such as volumeparticipantsfor connected players and surfacesshared-statefor durable room-wide game factsplayer-statefor participant-owned factsmessagefor 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_GODOTexists inside the host and controller iframes- controller lane buttons and charge input update player state
- Signal broadcasts a
godot:signalruntime 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_GODOTis undefined: confirm the host/controller page callsbootIframeGame(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 formessageevents with the same message type. - Published assets 404: inspect
dist/manifest.jsonand 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-godotis a browser-side bridge and manifest helper, not a full Godot editor plugin.- The checked-in example does not include generated
.wasmor.pckartifacts; it is shaped for CI-verifiable TPG packaging. - Godot scripts must still call
window.TPG_GODOTthroughJavaScriptBridge. - 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.