Full fix shipped across three builds:
v0.2.102 — config.optimizeGameSettings = YES in HydraStreamSession.m. Sunshine now receives the signal to switch the VDD to the client-requested resolution. Previously NO meant Sunshine ignored the portrait resolution hint and kept the display at 1920×1080.
v0.2.111 — ContentView.nativeStreamDimensions() derives stream width/height from UIWindowScene.screen.nativeBounds (device physical pixels) matching the experience orientation, instead of the catalog-fixed 1080×1920 / 1920×1080. Stream AR now matches device AR exactly.
v0.2.112 — VideoDecoderRenderer and StreamView simplified to displayLayer.frame = view.bounds — no aspect calculation. Since stream AR = device AR, no scaling is needed. All aspect-arithmetic removed.
Sunshine log now shows Desktop resolution [<native_w>x<native_h>] (e.g. 1640×2360 for iPad 10th gen in portrait). No bars, no cropping, no UI elements cut off.
MVP shipped in agent v2.0.33 (commit 1a31461).
What landed:
pkg/client/moonlight.gomoonlightStreamArgs(host, orientation)selects 1080x1920 forportrait, 1920x1080 otherwise.pkg/client/catalog.goaddsexperienceOrientation(catalog, name)+(*Client).orientationFor(name). Reads from existing~/.hydraheadflatscreen/catalog_cache.json; never crashes on missing/malformed entries (defaults to empty → landscape).pkg/client/localapi.goandpkg/client/client.gothread the orientation hint throughstartMoonlightStream(host, app, orientation).moonlight_test.goandcatalog_test.go.Verified end-to-end on cheeky-cactus:
orientation="portrait", Moonlight--resolution 1080x1920, body renders portrait Mercator scene.orientation="", Moonlight--resolution 1920x1080, body renders landscape, no regression.Out of scope (the half deferred to a follow-up if needed):