# KSP-side Telemetry Bridge This directory will hold the bridge between a running Kerbal Space Program game and the kerbal-rt API. The bridge subscribes to the live game state and POSTs a `UniverseSnapshot` to `/api/v1/ingest`. > **Status: Phase 1c — not yet implemented.** > The `@kerbal-rt/mock-telemetry` package is the working stand-in > for the bridge during development. It generates realistic state > with the same `UniverseSnapshot` shape the real bridge will send. ## Two implementation options ### Option A — kRPC (recommended, fastest to ship) [kRPC](https://github.com/krpc/krpc) is the modern, well-maintained RPC framework for KSP 1.12.x. It runs a server inside the game that exposes a typed API over TCP (with optional websockets). **Setup:** 1. Install KSP 1.12.5 + [ckan](https://github.com/KSP-CKAN/CKAN) 2. `ckan install kRPC` — pulls in the server mod + protobuf defs 3. Start KSP, load your save, start a kRPC server (default port 50000) 4. Run a small Node client that subscribes to streams: - `vessel.orbit` (returns a tuple of orbital elements) - `vessel.situation` - `space_center.ut` - `body.orbit` for each body - `space_center.transform_position`/`rotation` for ground stations 5. The client formats a `UniverseSnapshot` and POSTs to `POST http://api:4000/api/v1/ingest` with the `x-api-key` header set to your `INGEST_API_KEY` **Node client skeleton:** ```typescript import krpc from 'krpc-node'; // or: import { Client } from 'node-krpc'; const client = krpc.connect({ host: 'localhost', rpcPort: 50000 }); const sc = client.spaceCenter; // Subscribe to streams (push every 1s) const ut = client.addStream(() => sc.ut); const vessels = await sc.vessels; setInterval(async () => { const snap = { ut: ut.get(), capturedAt: new Date().toISOString(), activeVesselId: sc.activeVessel?.id.toString() ?? null, bodies: await buildBodies(client), vessels: await Promise.all(vessels.map(v => buildVessel(client, v))), groundStations: await buildGroundStations(client), }; await fetch('http://localhost:4000/api/v1/ingest', { method: 'POST', headers: { 'content-type': 'application/json', 'x-api-key': process.env.INGEST_API_KEY! }, body: JSON.stringify(snap), }); }, 1000); ``` (There's no official kRPC Node client, but a quick `protobufjs` setup using the .proto files from the kRPC mod works in <300 lines.) ### Option B — Custom KSP mod (most flexible) A C# KSP mod that uses Harmony to patch into `FlightGlobals` and publishes state on each physics tick. Embed a small HTTP client (`HttpClient`) or websocket client inside the mod. - **Pro:** Total control, can publish *events* (stage, maneuver node, collision) not just state. Can disable the publish path with a toggle in the mod's UI. - **Con:** You own the codebase forever. Have to maintain it across KSP updates. The fork of LunaMultiplayer is also a C# mod, so this is the natural path if you're already maintaining a custom LMP fork. **When to use this:** only if kRPC can't give you the data you need (e.g. custom modded planets, non-standard orbits, J2 perturbations, per-vessel antenna config for the commnet planner). For the stock Kerbol system, kRPC is enough. ## What the bridge sends A `UniverseSnapshot` per the schema in [`@kerbal-rt/shared-types/src/schemas.ts`](../packages/shared-types/src/schemas.ts). The mock publisher's output ([`apps/tools/mock-telemetry/src/index.ts`](../apps/tools/mock-telemetry/src/index.ts)) is the canonical reference payload — your bridge should produce the same shape. ## Running the real bridge ```bash # 1. Make sure KSP is running with the kRPC mod enabled # 2. Make sure the API is running (Phase 1a) # 3. Run the bridge (Phase 1c — TBD) pnpm --filter @kerbal-rt/ksp-bridge start # (this script doesn't exist yet; see Option A/B above) ``` ## Why this isn't done yet The real bridge requires: 1. A real KSP 1.12.5 install with kRPC mod loaded 2. A save with vessels, in a state interesting enough to publish 3. Iterating on the protocol against the real game (KSP exposes orbital data in KSP-specific frames; you have to translate to the heliocentric ecliptic frame for the API) We can do all of that, but the value of a working mock-driven pipeline (which the user already has) is much higher than a real bridge sitting unused. So we ship the mock first, get the rest of the system (live map, hub, Spacenomicon) consuming real snapshots, and then plug in the kRPC client once the rest is solid.