Surface Target Mode

Issue: #758

Summary

Add a surface_retrograde attitude mode that orients the ship’s engine against its surface-relative velocity vector. This accounts for body rotation, unlike orbital retrograde. A landing HUD overlay shows descent rate, horizontal speed, and time to impact when close to a body’s surface.

Attitude Mode: Surface Retrograde

Keybinding

  • Shift+M key: engage surface retrograde attitude hold
  • H key: disengage (existing behavior)

Physics

Surface-relative velocity subtracts the body’s rotational velocity at the ship’s position:

omega_body = (2*pi / rotation_period) * spin_axis_icrf
v_rotation = cross(omega_body, r_ship_relative)
v_surface = v_ship_relative - v_rotation
target_direction = -normalize(v_surface)

Where spin_axis_icrf is the body’s north pole direction in ICRF, computed from axial tilt:

spin_axis_icrf = [0, sin(axial_tilt), cos(axial_tilt)]

The attitude controller aligns ship +Z (forward) with this direction, using the existing PD controller. Below 0.1 m/s surface-relative speed, holds the last valid direction.

Difference from Orbital Retrograde

At Luna’s surface, rotational velocity is ~4.6 m/s (27.3-day period). This is negligible at orbital speeds (~1.68 km/s) but significant during final descent when ship speed approaches zero. Surface retrograde properly zeroes ground-relative motion for a soft landing.

Landing HUD

When the ship is within 50 km AGL of any body, a landing HUD overlay appears automatically (independent of attitude mode):

Indicator Label Source
Descent rate VSPD Radial velocity component toward surface (positive = descending)
Horizontal speed HSPD Tangential velocity relative to body center
Time to impact TTI AGL / descent_rate (linear estimate, shown when descending)
Altitude AGL AGL Already exists in orbit diagram

Display format:

  • VSPD: ↓ X.X m/s (descending) or ↑ X.X m/s (ascending)
  • HSPD: X.X m/s
  • TTI: Xm Xs or Xs when < 60s, -- when ascending

The landing HUD is a lightweight HTML overlay, not added to the orbit diagram SVG.

Implementation

Proto

Add ATTITUDE_SURFACE_RETROGRADE = 15 to AttitudeMode enum in physics.proto (all copies).

Physics Service

  • models.py: Add SURFACE_RETROGRADE to AttitudeMode and TRACKING_MODES
  • attitude.py: Add _compute_body_spin_vector(ref_body) helper and SURFACE_RETROGRADE case in compute_attitude_target_direction()
  • grpc_server.py: Add proto ↔ model mappings

API Gateway

  • websocket.py: Add attitude_surface_retrograde message handler

Web Client

  • network.js: Add sendAttitudeSurfaceRetrograde()
  • controlInput.js: Add M key → surface_retrograde mapping
  • cockpitView.js: Wire into _attitudeSenders, init landing HUD
  • cockpitLandingHud.js: New module — computeLandingData() (pure logic, tested), updateLandingHud() (DOM display)
  • cockpitOrbitDiagram.js: Calls updateLandingHud() alongside AGL computation
  • index.html: Landing HUD element (#landing-hud) with CSS styles

Bodies

Works for all bodies. Uses terrain elevation when available (Luna), mean radius as fallback.


Back to top

Galaxy — Kubernetes-based multiplayer space game

This site uses Just the Docs, a documentation theme for Jekyll.