HydraNeck

Getting Started Overview

Traffic Flows

Three streaming scenarios exist depending on where the Head is relative to the Body. Each uses different components and network paths.

1. Local Streaming (Native Head)

The Head and Body are at the same venue, on the same or bridged VLANs.

sequenceDiagram
    participant EL as Experience Library
    participant H as Head (HydraHead Flatscreen)
    participant API as HydraHead API
    participant B as Body (Sunshine)

    H->>EL: Fetch available experiences
    EL-->>H: Experience list
    Note over H: User selects experience
    H->>API: Query eligible Bodies in district
    API-->>H: Eligible Bodies (LAN IP + WireGuard IP)
    H->>B: TCP probe LAN IP :47990 (1s timeout)
    B-->>H: Reachable
    Note over H: discoverBody() selects LAN IP
    H->>B: Moonlight pairing (PIN exchange)
    H->>B: Moonlight stream (LAN direct, 1080p60, 150 Mbps)

Flow:

  1. The Head runs in self-service kiosk mode and shows available experiences from the Experience Library
  2. The user selects an experience to run
  3. The Head calls discoverBody() which queries the HydraHead API for eligible Bodies in the district
  4. For each eligible Body, it probes the LAN IP on TCP port 47990 (Sunshine API) with a 1-second timeout
  5. If a Body is reachable on LAN: stream goes direct over the local network (no WireGuard overhead, lowest latency)
  6. HydraHead pairs with Sunshine (PIN exchange) then launches Moonlight for streaming
  7. Stream runs at 1080p60, up to 150 Mbps (LAN quality)

Key code: hydrahead/pkg/client/discovery.go -- discoverBody()

Partner relevance: At partner-managed locations, the partner configures the firewall rule allowing Head VLAN to Body VLAN traffic. This local path is the preferred path for co-located Heads and Bodies.

2. Remote Streaming (Native Head)

The Head is at a different location: another venue, home WiFi, or public 4G/5G. Not on the same LAN as the Body.

sequenceDiagram
    participant H as Head (HydraHead Flatscreen)
    participant API as HydraHead API
    participant HUB as District Server (HydraGuard Hub)
    participant B as Body (Sunshine)

    H->>API: Query eligible Bodies in district
    API-->>H: Eligible Bodies (LAN IP + WireGuard IP)
    H->>B: TCP probe LAN IP :47990 (1s timeout)
    B--xH: Unreachable
    Note over H: discoverBody() falls back to WireGuard IP
    H->>HUB: WireGuard tunnel
    HUB->>B: WireGuard tunnel
    H->>B: Moonlight stream (via WireGuard mesh)

Flow:

  1. The Head queries eligible Bodies in the district (same as local flow)
  2. discoverBody() probes each Body's LAN IP -- fails (1s timeout, not on same network)
  3. Falls back to the Body's WireGuard IP
  4. Traffic routes: Head -> WireGuard tunnel -> Hub (10.10.0.1) -> WireGuard tunnel -> Body
  5. Same Moonlight protocol, but over the encrypted WireGuard mesh

Key code: hydrahead/pkg/client/discovery.go -- discoverBody() WireGuard fallback path

Partner relevance: Remote Heads on HYDRA-managed locations or public internet use their own WireGuard tunnel to the district server. The network partner does not manage these connections.

3. Remote Streaming (Browser / WebRTC)

The Head is a web browser. No native client installed. Uses WebRTC for streaming.

sequenceDiagram
    participant BR as Browser
    participant WS as HydraHead WebStream
    participant CTL as HydraNeck Controller
    participant WK as HydraNeck Worker
    participant B as Body (Sunshine)

    BR->>WS: WebSocket (district, experience, round-trip time)
    WS->>WS: FindBodyForDistrict()
    WS->>CTL: POST /api/v1/sessions (body_ip, profile)
    CTL->>CTL: Pick least-loaded worker
    CTL->>WK: Route session
    WK->>B: Spawn moonlight-web-stream (via WireGuard)
    WK->>B: Sunshine pairing + app launch
    WK-->>BR: stream_url
    BR--)WK: WebRTC stream (STUN/TURN)

Flow:

  1. Browser connects to HydraHead WebStream via WebSocket
  2. Browser sends district, experience, and connectivity metrics (round-trip time, network type, bandwidth)
  3. WebStream calls FindBodyForDistrict() to find an eligible Body in the requested district
  4. WebStream calls HydraNeck WebRTC controller to create a session with the Body's WireGuard IP
  5. Controller routes the request to the least-loaded worker
  6. Worker spawns moonlight-web-stream which connects to the Body's Sunshine via WireGuard
  7. WebRTC stream is relayed from the worker back to the browser
  8. Quality tier is selected based on the connection profile (round-trip time, device type, network)

Quality tiers:

Profile Resolution FPS Bitrate
Excellent (desktop, <50ms round-trip) 1080p 60 15 Mbps
Good (desktop, 50-100ms) 1080p 60 10 Mbps
Mobile Good (<75ms) 720p 60 7 Mbps
Poor (>200ms) 720p 30 5 Mbps

Key code:

Partner relevance: Browser-based Heads do not need any partner infrastructure. They connect to HydraNeck WebRTC workers directly over the public internet. The workers reach Bodies via the WireGuard mesh.

Path Selection Summary

Head Location Head Type Path Latency Managed By
Same venue Native Direct LAN (VLAN) Lowest Partner (firewall)
Same venue Browser WebRTC via district Medium HYDRA
Different venue Native WireGuard via district Medium HYDRA
Home / public Native WireGuard via district Higher HYDRA
Home / public Browser WebRTC via district Higher HYDRA