Four reworks from the on-glass review of the post-#66/#74 iOS gamepad UI.
Theme follows the palette now
The reported "background changes but the theme doesn't" had a one-line root cause: ink.glass — the palette-derived surface colour, the same one pf-console-ui fills every panel with — was defined and consumed nowhere. Every surface was OS material with only a light/dark flip.
consoleGlass washes all three tiers with it: Glass.tint on 26+ (mixed 60 % toward the caller's focus tint so the focused row still reads accented), a fill overlay on the pre-26 material, and on tvOS. In passing this fixes a latent bug: the pre-26 branch dropped tint entirely, so focused rows there had no accent wash at all.
The gamepad close buttons move to a new ink-aware consoleGlassBackground (plain glassBackground follows the system appearance — wrong frost under a pale palette). Non-gamepad floating surfaces are untouched.
Literal-colour sweep: ConnectOverlay's console takeover rides ink.fg (it was the one console surface that stayed white-on-white on pale palettes), card shadows soften on pale fields via ink.shadow, the focused keycap reads ink.onAccent. The online pip stays status-green on purpose — a status colour must not change meaning with the wallpaper.
The header breathes
Title top padding 4/10 → 10/18 (compact/regular), plus shared gamepadHeaderSpacing / gamepadTitleBottomPadding helpers mapped from the console shell's rhythm — applied to the launcher, Settings and Add Host alike, and the Add Host close ✕ is re-anchored to the title row the way Settings' is. First row now sits ~22 pt below the tab pills instead of shoulder-to-shoulder with them.
Screens present in place (iOS)
Settings, Add Host and the Library are no longer opaque bottom-up fullScreenCovers that each mount their own backdrop. GamepadHomeView is now a layered shell (GamepadShell.swift): one persistent aurora that never unmounts, its calm chased (GamepadScreenBackground gained a continuous calmMix — the console's bg_mix), and screens as transparent layers with the console's exact choreography: 0.26 s ease-out cubic, incoming slides up out of a fade at 0.985→1, launcher recedes to 0.96; pop mirrors. Controller input is dropped for the transition (epoch-guarded), and the poll hands off through injected close/controllerActive — the coverflow also stops polling under the connect takeover, a latent double-poll. The screen enum is derived from the existing triggers, so returnToLibrary and every writer keep working; a controller arriving/leaving mid-browse hands the open library to whichever presentation the new mode owns.
macOS keeps its windowed sheets, tvOS its focus-engine covers — their paths compile and behave exactly as before.
The select is a real band
GamepadOptionBand replaces the faked ±14 pt value slip on choice rows: options ride a spring-driven drum about a vertical axis (View + Animatable, so intermediate options genuinely enter and leave mid-spin), ring-distance math makes A's wrap keep spinning forward, and spring retargeting turns rapid steps into one continuous accelerating spin instead of five restarted crossfades. Neighbours appear only under focus (an unfocused row is one flat Text — yesterday's look and cost), Reduce Motion falls back to a plain crossfade, and the fixed band frame means a step never reflows the row (the old chevron shimmy is gone). Toggles deliberately keep the quiet slip — a two-position switch on a drum reads as a coin flip.
Verification
swift build (macOS) — green
swift build --triple arm64-apple-ios17.0 against the iPhoneOS SDK — green
swift test — 208 passed, 5 skipped, 0 failures
On-glass QA owed before merge:
palette switch recolours rows/tiles/hint bar/close buttons on one dark + one pale palette; focused row still reads accented (escape hatch documented in code: tint ?? wash)
push/pop fade composites the material trays as one unit (fallback: .compositingGroup())
Four reworks from the on-glass review of the post-#66/#74 iOS gamepad UI.
## Theme follows the palette now
The reported "background changes but the theme doesn't" had a one-line root cause: `ink.glass` — the palette-derived surface colour, the same one `pf-console-ui` fills every panel with — was defined and consumed **nowhere**. Every surface was OS material with only a light/dark flip.
- `consoleGlass` washes all three tiers with it: `Glass.tint` on 26+ (mixed 60 % toward the caller's focus tint so the focused row still reads accented), a fill overlay on the pre-26 material, and on tvOS. In passing this fixes a latent bug: the pre-26 branch dropped `tint` entirely, so focused rows there had no accent wash at all.
- The gamepad close buttons move to a new ink-aware `consoleGlassBackground` (plain `glassBackground` follows the *system* appearance — wrong frost under a pale palette). Non-gamepad floating surfaces are untouched.
- Literal-colour sweep: ConnectOverlay's console takeover rides `ink.fg` (it was the one console surface that stayed white-on-white on pale palettes), card shadows soften on pale fields via `ink.shadow`, the focused keycap reads `ink.onAccent`. The online pip stays status-green on purpose — a status colour must not change meaning with the wallpaper.
## The header breathes
Title top padding 4/10 → **10/18** (compact/regular), plus shared `gamepadHeaderSpacing` / `gamepadTitleBottomPadding` helpers mapped from the console shell's rhythm — applied to the launcher, Settings and Add Host alike, and the Add Host close ✕ is re-anchored to the title row the way Settings' is. First row now sits ~22 pt below the tab pills instead of shoulder-to-shoulder with them.
## Screens present in place (iOS)
Settings, Add Host **and the Library** are no longer opaque bottom-up `fullScreenCover`s that each mount their own backdrop. `GamepadHomeView` is now a layered shell (`GamepadShell.swift`): one persistent aurora that never unmounts, its calm **chased** (`GamepadScreenBackground` gained a continuous `calmMix` — the console's `bg_mix`), and screens as transparent layers with the console's exact choreography: 0.26 s ease-out cubic, incoming slides up out of a fade at 0.985→1, launcher recedes to 0.96; pop mirrors. Controller input is dropped for the transition (epoch-guarded), and the poll hands off through injected `close`/`controllerActive` — the coverflow also stops polling under the connect takeover, a latent double-poll. The screen enum is *derived* from the existing triggers, so `returnToLibrary` and every writer keep working; a controller arriving/leaving mid-browse hands the open library to whichever presentation the new mode owns.
macOS keeps its windowed sheets, tvOS its focus-engine covers — their paths compile and behave exactly as before.
## The select is a real band
`GamepadOptionBand` replaces the faked ±14 pt value slip on choice rows: options ride a spring-driven drum about a vertical axis (`View + Animatable`, so intermediate options genuinely enter and leave mid-spin), ring-distance math makes A's wrap keep spinning forward, and spring retargeting turns rapid steps into one continuous accelerating spin instead of five restarted crossfades. Neighbours appear only under focus (an unfocused row is one flat Text — yesterday's look and cost), Reduce Motion falls back to a plain crossfade, and the fixed band frame means a step never reflows the row (the old chevron shimmy is gone). Toggles deliberately keep the quiet slip — a two-position switch on a drum reads as a coin flip.
## Verification
- `swift build` (macOS) — green
- `swift build --triple arm64-apple-ios17.0` against the iPhoneOS SDK — green
- `swift test` — 208 passed, 5 skipped, 0 failures
**On-glass QA owed before merge:**
- [ ] palette switch recolours rows/tiles/hint bar/close buttons on one dark + one pale palette; focused row still reads accented (escape hatch documented in code: `tint ?? wash`)
- [ ] push/pop fade composites the material trays as one unit (fallback: `.compositingGroup()`)
- [ ] drum feel on device; rapid L/R spin; A-wrap; Reduce Motion crossfade
- [ ] iPhone landscape + iPad header spacing; touch UI / macOS sheets / tvOS covers unchanged
Four reworks from the first palette-era on-glass review, all iOS-facing:
- Surfaces carry the palette now, not just the text on them: ConsoleGlass
washes every tier (Liquid Glass tint, pre-26 material, tvOS material)
with ink.glass — the same colour the desktop console fills its panels
with — and the close buttons move to an ink-aware consoleGlassBackground.
The pre-26 branch also gains the focus tint it had silently dropped.
Stray literals follow: ConnectOverlay text rides ink in the console
takeover, card shadows soften on pale fields, the focused keycap reads
onAccent. The online pip stays status-green on purpose.
- The header breathes: title top padding 4/10 -> 10/18 plus shared
header-spacing and title-bottom helpers mapped from the console shell's
rhythm, applied to the launcher, settings and add-host alike, with the
add-host close X re-anchored to the title row.
- Settings, Add Host and the Library present IN PLACE on iOS: one
persistent aurora whose calm is chased (the console's bg_mix), screens
as transparent layers with the console's 0.26 s ease-out-cubic push/pop,
an input drop for the transition, and the controller handed off through
isActive — no more opaque bottom-up covers, no backdrop teardown.
macOS keeps its sheets, tvOS its focus-engine covers.
- The settings select is a real band: choice rows mount GamepadOptionBand,
a spring-driven drum (Animatable body, ring-distance wrap, neighbours
gated by focus and flight) whose retargeting spring accumulates rapid
steps into one continuous spin. Reduce Motion falls back to a plain
crossfade; toggles keep the quiet 14 pt slip.
Verified: swift build (macOS), swift build --triple arm64-apple-ios17.0,
swift test 208 passed / 0 failed. On-glass QA still owed: palette sweep on
a pale palette, transition compositing over materials, drum feel on device.
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Four reworks from the on-glass review of the post-#66/#74 iOS gamepad UI.
Theme follows the palette now
The reported "background changes but the theme doesn't" had a one-line root cause:
ink.glass— the palette-derived surface colour, the same onepf-console-uifills every panel with — was defined and consumed nowhere. Every surface was OS material with only a light/dark flip.consoleGlasswashes all three tiers with it:Glass.tinton 26+ (mixed 60 % toward the caller's focus tint so the focused row still reads accented), a fill overlay on the pre-26 material, and on tvOS. In passing this fixes a latent bug: the pre-26 branch droppedtintentirely, so focused rows there had no accent wash at all.consoleGlassBackground(plainglassBackgroundfollows the system appearance — wrong frost under a pale palette). Non-gamepad floating surfaces are untouched.ink.fg(it was the one console surface that stayed white-on-white on pale palettes), card shadows soften on pale fields viaink.shadow, the focused keycap readsink.onAccent. The online pip stays status-green on purpose — a status colour must not change meaning with the wallpaper.The header breathes
Title top padding 4/10 → 10/18 (compact/regular), plus shared
gamepadHeaderSpacing/gamepadTitleBottomPaddinghelpers mapped from the console shell's rhythm — applied to the launcher, Settings and Add Host alike, and the Add Host close ✕ is re-anchored to the title row the way Settings' is. First row now sits ~22 pt below the tab pills instead of shoulder-to-shoulder with them.Screens present in place (iOS)
Settings, Add Host and the Library are no longer opaque bottom-up
fullScreenCovers that each mount their own backdrop.GamepadHomeViewis now a layered shell (GamepadShell.swift): one persistent aurora that never unmounts, its calm chased (GamepadScreenBackgroundgained a continuouscalmMix— the console'sbg_mix), and screens as transparent layers with the console's exact choreography: 0.26 s ease-out cubic, incoming slides up out of a fade at 0.985→1, launcher recedes to 0.96; pop mirrors. Controller input is dropped for the transition (epoch-guarded), and the poll hands off through injectedclose/controllerActive— the coverflow also stops polling under the connect takeover, a latent double-poll. The screen enum is derived from the existing triggers, soreturnToLibraryand every writer keep working; a controller arriving/leaving mid-browse hands the open library to whichever presentation the new mode owns.macOS keeps its windowed sheets, tvOS its focus-engine covers — their paths compile and behave exactly as before.
The select is a real band
GamepadOptionBandreplaces the faked ±14 pt value slip on choice rows: options ride a spring-driven drum about a vertical axis (View + Animatable, so intermediate options genuinely enter and leave mid-spin), ring-distance math makes A's wrap keep spinning forward, and spring retargeting turns rapid steps into one continuous accelerating spin instead of five restarted crossfades. Neighbours appear only under focus (an unfocused row is one flat Text — yesterday's look and cost), Reduce Motion falls back to a plain crossfade, and the fixed band frame means a step never reflows the row (the old chevron shimmy is gone). Toggles deliberately keep the quiet slip — a two-position switch on a drum reads as a coin flip.Verification
swift build(macOS) — greenswift build --triple arm64-apple-ios17.0against the iPhoneOS SDK — greenswift test— 208 passed, 5 skipped, 0 failuresOn-glass QA owed before merge:
tint ?? wash).compositingGroup())