This is the actual root cause of the Windows handshake failure.
The kRPC server sends a minimal ConnectionResponse that omits the
default-value `status` and `message` fields, leaving only the
`clientIdentifier`. Our schema declared the status field as
`type: 'ConnectionResponse.Status'` (a nested enum reference).
When protobufjs decodes the response and the field is absent, it
tries to look up the default value from the nested-enum type
descriptor — but the descriptor resolves to null somewhere in
protobufjs 7.6, and the next thing the code does is
`someDescriptor.code` to look up the default enum value. That
throws the TypeError: 'Cannot read properties of null (reading code)'.
The wire format is identical: status is just a varint. So we model
it as 'uint32' and our code already does `resp.status !== 0`
which works for the happy path (0 = OK). The redundant `!== 'OK'`
check is kept for forward compat — if anyone ever flips the schema
back to nested-enum and protobufjs fixes the bug, the string check
would still work.
Same fix applied to ProcedureResult.error (uses 'Error' which is
the actual top-level Error type, not a nested-enum type).
The raw-bytes diagnostic from the previous commit showed both
handshakes returning 18 bytes:
1a 10 <16 bytes>
which is just field 3 (clientIdentifier), confirming the server is
sending minimal responses. Decoding those 18 bytes as
ConnectionResponse with the old schema triggered the bug; with
uint32 status, it decodes cleanly to {status: 0, message: "",
clientIdentifier: <16 bytes>}, the handshake succeeds, and the
bridge connects to real KSP.
Kerbal RT
A real-time web mirror of a no-warp Kerbal Space Program multiplayer server: mission hub + 3D live solar system map.
Status: Phase 1 — data pipeline working end-to-end. Mock telemetry publisher drives the API, the API stores snapshots, the hub debug page and the live map both consume the WebSocket. Real KSP bridge (Phase 1c) is documented and ready to plug in once you have KSP.
See kerbalrealtime-clone-plan.md for the
full implementation plan.
Stack
| Layer | Tech |
|---|---|
| Hub | Next.js 14 (App Router) + TypeScript |
| Live map | Vite + React + Three.js + TypeScript |
| API | Hono on Node 22 + WebSocket (ws) + Zod |
| Shared | @kerbal-rt/shared-types, @kerbal-rt/orbital-math, @kerbal-rt/ui |
| Data (Phase 1) | Postgres 16 + TimescaleDB, Redis 7, MinIO (S3) |
| Package mgr | pnpm workspaces |
| Linter | Prettier (ESLint coming per-app) |
Layout
.
├── apps/
│ ├── hub/ # Next.js — marketing + calendar + media + /debug
│ ├── live-map/ # Vite + Three.js — 3D solar system viewer
│ ├── api/ # Hono — REST + WS gateway
│ └── tools/
│ └── mock-telemetry/ # Node script that drives the pipeline with fake KSP state
├── packages/
│ ├── shared-types/ # TS types + Zod schemas for every API boundary
│ ├── orbital-math/ # Pure keplerian propagation, occultation, transfers
│ ├── db/ # Postgres+Timescale+Redis wrapper, StateStore interface
│ └── ui/ # Shared React components (Pill, Card, …)
├── ksp/ # KSP-side bridge (Phase 1c) — see ./ksp/README.md
├── infra/ # docker-compose, nginx, grafana, init SQL
└── scripts/ # dev.sh and friends
Quick start
# 1. Install deps
pnpm install
# 2. Run the three apps in parallel
pnpm dev
# hub: http://localhost:3000
# live-map: http://localhost:3001
# api: http://localhost:4000
# Or run them individually
pnpm dev:hub
pnpm dev:map
pnpm dev:api
The
devscript forlive-mapproxies/api/*to:4000, so the live map's WebSocket and REST calls work out of the box.
Tests
pnpm test
Build
pnpm build
Data tier (Phase 1)
The API starts in-memory (in-process StateStore) for development. To wire
up the real data tier:
docker compose -f infra/docker-compose.yml up -d
This brings up:
- TimescaleDB on
:5432(with the full KSP body catalog pre-seeded) - Redis on
:6379 - MinIO on
:9000(S3-compatible object store for media) - pgAdmin on
:5050(only if you start with--profile dev)
CI
GitHub Actions runs format:check → typecheck → test → build on every
push / PR to main. See .github/workflows/ci.yml.
Phases
See kerbalrealtime-clone-plan.md for the
roadmap. Quick map:
- Phase 0 — monorepo, skeletons, docker-compose, CI
- Phase 1a — persistence layer (Postgres+Timescale+Redis) with in-memory fallback
- Phase 1b — mock telemetry publisher + WebSocket fan-out + hub /debug page
- Phase 1c — real kRPC bridge (see
ksp/README.md) - Phase 2 — Live map 3D scene (time controls, focus, eclipses, overpass)
- Phase 3 — Mission calendar, media, crew, YouTube/Twitch embeds
- Phase 4 — Spacenomicon tools (delta-v, transfer calculator, etc.)
- Phase 5 — Admin panel + polish
- Phase 6 — Production deploy
Verifying the Phase 1 pipeline
# Terminal 1: API
cd apps/api && PORT=4000 USE_IN_MEMORY=1 pnpm start
# Terminal 2: mock publisher
cd apps/tools/mock-telemetry && MOCK_API_URL=http://localhost:4000 pnpm start
# Terminal 3: hub
cd apps/hub && PORT=3000 pnpm start
# → open http://localhost:3000/debug to see the live state
For the WebSocket version, open the hub /debug page or use wscat:
npx wscat -c ws://localhost:4000/api/v1/live
License
This project is unaffiliated with Kerbal Space Program, Intercept Games, or Private Division. All trademarks belong to their respective owners.