@tpgames/sdk-dev-kit
v0.3.0
Published
Local authoring tools for games built with `@tpgames/game-kit` and `@tpgames/sdk`.
Readme
@tpgames/sdk-dev-kit
Local authoring tools for games built with @tpgames/game-kit and
@tpgames/sdk.
The package includes:
- a standalone multi-surface browser workbench for normal
npm run devuse - an in-memory harness for focused unit tests
- deterministic network-fault helpers for repeatable latency and reconnect tests
- the
tpgamesCLI for project initialization, physical-device development, source-boundary checks, registry bundle assembly, authentication, and publication
Author delivery CLI
Detached game repositories describe delivery inputs in tpgames.json and use
the package binary directly:
{
"game": {
"id": "signal-rally",
"version": "1.0.0",
"title": "Signal Rally"
},
"bundle": {
"manifest": "bundle/manifest.template.json",
"output": "dist",
"clean": false,
"copies": []
}
}tpgames init signal-rally
tpgames check-boundaries
tpgames dev --devices
tpgames bundle
tpgames login
tpgames whoami
tpgames registertpgames init <target-dir> creates the same renderer-neutral canonical starter
as npm create @tpgames/game@latest. A kebab-case directory name becomes the
default game ID and display title; explicit identity flags are also available.
The command requires a target path that does not already exist. The
project includes local and physical-device workflows, CI, and a standalone TP
Games development skill.
The bundle command renders the configured manifest, applies any explicit copy
rules for framework or engine assets, and writes dist/<game-id>-<version>.zip.
The CLI defaults to the production registry at
https://tpg-registry.tp-games.workers.dev and accepts --registry-url or
TPG_REGISTRY_URL for an explicit staging or loopback registry. Registration
uploads a game version; it does not register a developer account. It defaults
to the safe upload mode. Use --mode submit, or use
--mode publish --yes when publication is the intended result.
For interactive development, run tpgames login. The CLI prints a short code,
opens the TP Games approval page, and saves an origin-scoped session in the
operating system's user configuration directory only after you explicitly
approve it. Use tpgames whoami to verify the saved session and tpgames
logout to revoke it remotely and remove the local copy. Pass --no-open to
login when you want to open the printed URL yourself.
Production and loopback approval pages open automatically after strict URL and
code validation. For a custom HTTPS registry, the CLI prints the URL without
opening it unless you explicitly trust its shell with --approval-origin
https://shell.example.com or TPG_APPROVAL_ORIGIN. The configured origin must
exactly match the registry response.
tpgames register uses TPG_API_KEY first when it is set, then the saved
session for the exact registry origin. Keep TPG_API_KEY for CI and other
non-interactive environments; secrets are deliberately not accepted as command
arguments or project configuration. Use tpgames logout --local-only only when
the registry is unreachable and you intentionally cannot revoke the remote
session. Browser-created CLI sessions expire after 90 days and can be revoked
earlier from the CLI or creator portal.
Routine values have command-line flags, so local use does not require temporary environment variables:
tpgames bundle \
--game-id signal-rally \
--game-version 1.1.0 \
--game-title "Signal Rally" \
--output-dir dist
tpgames register \
--game-id signal-rally \
--game-version 1.1.0 \
--mode submitFlags override matching TPG_* environment variables, which override
tpgames.json. Run tpgames help bundle or tpgames help register for the
complete option list.
Saved sessions are isolated by normalized registry origin. Signing in to a
loopback or staging registry does not expose that credential to production, and
changing --registry-url requires a separate login.
Multi-surface workbench
Add the public Vite plugin to your game repository:
import { tpgWorkbench } from "@tpgames/sdk-dev-kit/vite";
import { defineConfig } from "vite";
export default defineConfig({
plugins: [
tpgWorkbench({
title: "Signal Rally",
surfaces: {
host: "/host.html",
controller: "/controller.html",
spectator: "/spectator.html",
},
controllers: 2,
spectator: true,
}),
],
});Then run:
npm run devVite opens /__tpg/workbench. The workbench mounts one host display, one to
sixteen configurable controllers, and an optional spectator. It provides:
- lifecycle, readiness, settings, join/leave, reconnect, and authority controls
- canonical shared state, per-player state, and transient message inspection
- a searchable, pausable, exportable bridge log capped at 500 entries
- seeded latency, jitter, packet-loss, and reconnect simulation
- responsive surface previews with the same public iframe/runtime bridge used by packaged games
- independent 50–125% zoom controls for seeing more or less of each surface
- live pop-out windows that stay synchronized with the embedded workbench session
The browser workbench renders its visible interface with React. Session orchestration, iframe messaging, pop-out lifecycle, and other browser effects remain behind focused adapters, so author projects continue to use the same Vite plugin and mount API.
Physical devices without an upload
With the Vite plugin configured, start a real shell room backed by the current local source:
tpgames dev --devicesThe command starts Vite on loopback, creates a temporary Cloudflare Quick
Tunnel, and opens a host URL on https://play.tp.games. Scan the room QR from
one or more phones; controllers and spectators receive the same validated
development manifest through the host-authoritative room snapshot. No registry
upload, API key, or package build is involved.
Install cloudflared first, or provide a tunnel you manage:
cloudflared tunnel --url http://127.0.0.1:5173
tpgames dev --devices --port 5173 --public-url https://random-name.trycloudflare.comFor a named tunnel, configure its public hostname to forward to
http://127.0.0.1:5173, run cloudflared tunnel run <name>, then pass that
hostname with --port 5173 --public-url https://game-dev.example.com. The port
must match the tunnel origin. When --public-url is present, tpgames does
not start, own, or stop that tunnel.
Use --shell-url for a local or preview shell, --port to choose the Vite
port, and --no-open in headless environments. Each room's development
selection expires eight hours after launch, uses an unguessable one-run
manifest descriptor, and runs with the unreviewed iframe capability policy.
Treat the generated host link as private because it contains that descriptor.
Quick Tunnel URLs expose the Vite server and source modules publicly, so share
only the shell's room QR or controller invite, keep .env files, credentials,
and private assets outside Vite's served root, and stop the command and tunnel
when testing is finished.
By default the host link opens automatically. With --no-open, open the printed
host link; the QR and device invite appear after that host connects and creates
the room.
Controller definitions can supply stable IDs and names:
tpgWorkbench({
title: "Signal Rally",
surfaces: { host: "/host.html", controller: "/controller.html" },
controllers: [
{ id: "blue-team", screenName: "Blue Team" },
{ id: "gold-team", screenName: "Gold Team" },
],
networkProfile: {
latencyMs: 80,
jitterMs: 20,
lossRate: 0.02,
reconnectDelayMs: 1500,
seed: 42,
},
});The simulator is host-authoritative and exercises public bridge contracts, but
it does not replace final packaged-bundle verification. Use it for the fast
author loop, use dev --devices for real transport and device input, then
verify the uploaded bundle paths and reviewed permissions before publishing.
In-memory harness
Use the root export for lifecycle and state unit tests without a browser:
import {
createFakeParticipants,
createGameDevHarness,
} from "@tpgames/sdk-dev-kit";
import game from "./game";
const harness = createGameDevHarness({ game });
harness.pushParticipants(createFakeParticipants(["Casey", "Riley"]));
harness.pushLifecycle("started");
harness.pushSharedState({ round: 1 });The lower-level createWorkbenchSession export is also available for tooling
that needs to orchestrate several public bridge adapters without mounting the
built-in interface.
