Files
KSP-MissionControl/ksp/README.md
T
Mavis a457b9d96f
CI / Lint, typecheck, test, build (pull_request) Failing after 10s
Phase 1: data pipeline (Postgres+Redis with in-memory fallback, mock telemetry publisher, WebSocket fan-out, hub /debug page)
- packages/db: postgres.js + ioredis wrapper, StateStore interface with
  InMemory + Postgres implementations, schema migration runner
- apps/api: refactored to use @kerbal-rt/db; live WebSocket hub subscribes
  to store changes and broadcasts to all clients
- apps/tools/mock-telemetry: Node script that generates realistic KSP
  state and POSTs to /api/v1/ingest at 1Hz (uses same keplerian math
  as the live-map renderer)
- apps/hub: new /debug page that connects to /api/v1/live and shows
  the live state
- ksp/README.md: documents Phase 1c (real kRPC bridge) and the two
  implementation options
- Tests: 17 total (5 kepler math, 5 db store, 5 API health/state,
  2 API WebSocket fan-out)

End-to-end verified: mock publisher → API → hub /debug page,
11 snapshots/5s over WebSocket, vessels advancing in mean anomaly.
2026-06-02 18:54:46 +00:00

4.4 KiB

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

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
  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:

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. The mock publisher's output (apps/tools/mock-telemetry/src/index.ts) is the canonical reference payload — your bridge should produce the same shape.

Running the real bridge

# 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.