v1.12.0

September 3, 2026

This release adds a live controller test sheet with on-screen pad visualizer, remap, deadzone and calibration, brings OpenCritic review scores to the game detail view, refactors the library sort picker with new "Time Played" and "Longer to Beat" orders, and polishes the holo FX pipeline: reverse-foil transparency is now correctly visible, fitted box-art alignment is fixed for non-vertical covers, dead Holo settings are pruned, and TV mode gets a 3D pivoting effect on list rows plus a wizard-style auto holo for the focused tile and selected hero. A bogus PC Engine CD001 magic header is removed so DOS CD images no longer mis-identify as PCE.

Highlights

  • Live controller test sheet: An auto-presented sheet on new gamepads (and a manual "Test Controller" entry in settings) shows the current binding layout on a SwiftUI-drawn Xbox layout, lets the user remap face/shoulder/trigger/stick/dpad buttons, adjust stick deadzones, and run a stick calibration session. Conflicts are highlighted in yellow.
  • OpenCritic integration: The game detail view now shows critic score, tier, percent recommended, review count, and a deep link. Results are cached in ROMMetadata; the API key and connectivity test live in Settings, and everything is localized across en/es/ja/pt.
  • Library sort refactor + new orders: The legacy two-boolean sort is replaced by a single LibrarySortOrder enum, with "Time Played" (by totalPlaytimeSeconds) and "Longer to Beat" (by hltbMainStoryHours) added in the chip bar's "Other" popover. Pills now cycle inactive → descending → ascending with directional arrows.
  • Holo FX polish: Reverse-holo foil transparency is correctly visible in the bright mid-tones (new ReverseHoloMask Metal shader with luminance gating), fitted box art and holo foil are centered in the fill-blurred all-games card, nine dead Holo settings are pruned, and TV mode gets a 3D pivoting effect on list rows plus an auto-holo on the focused tile and selected hero.

Detailed Changes

  • Controller test sheet — new PadButton enum covers the full Xbox layout (face, shoulders, triggers, sticks, dpad, share, 8 stick directions); ControllerInputObserver owns a single set of valueChangedHandler chains (or SDL observer callbacks) and synthesizes stick-direction press events from analog axes so remap capture works for any input source; SDLInputManager gains startButtonObservation / startTriggerObservation mirroring the existing single-slot axis pattern; updateMapping dedup logic removed (duplicates allowed; test sheet highlights conflicts); ControllerService.updateMapping / stopObserving now broadcasts a controllerInputObserverStopped notification so StickVisualizerView re-attaches its handlers when the test sheet closes; NewGamepadPresenter auto-presents the sheet for unseen vendor names after a 2s startup warm-up and when no game is running; NavBlocker gamepad context swallows library nav actions while the test sheet is open so A/Start don't accidentally launch games.
  • OpenCritic — new OpenCriticService (RapidAPI) with search, details, and test-connection; Settings UI for the API key with connectivity feedback and logging; new OpenCritic section in the game detail view showing score, tier, percent recommended, review count, and link; results persisted to ROMMetadata; refresh reuses cached game ID to cut API usage from 2 hits to 1 on refresh; localized settings.openCritic.* and openCritic.* across en/es/ja/pt.
  • Library sort refactor — replaces sortByLastPlayed / sortByLastAdded AppSettings keys with a single LibrarySortOrder enum plus a sortAscending flag; new LibrarySortPicker renders both the macOS Sort menu (NSMenu rows + "Other" submenu) and the filter-chip bar (capsule chips); new "Time Played" and "Longer to Beat" sorts in the "Other" popover (unplayed / no-HLTB entries sink to bottom); pill click cycle: inactive → descending → ascending → inactive; "Name" default sort is implicit (no pill); FilterChipView gained a fillsWidth parameter for full-width "Other" rows; legacy keys are read once on first run then left on disk (inert) for rollback safety.
  • Holo alignment — center fitted box art and holo foil/glare in the fill-blurred all-games card so non-vertical art is no longer zoomed/cropped to fill and the mask no longer drifts off-center; documented the holo box-art invariants in AGENTS.md.
  • Reverse holo foil — new ReverseHoloMask Metal shader: reverse holo foil is transparent at max dark and max bright and most visible in the bright mid-tones, with the light/dark sweep gated by the luminance mask in every mode so the transparency is actually visible.
  • Holo settings prune — removed nine Holo settings only consumed by a dead fallback branch in HoloFoilLayers.body (title/chrome/hero/background intensity and pattern, plus maskDeviationChance); removed holofoilRareBeamStrength, randomFoilSize, the heroHolo / titleBackgroundHolo / chromeBackgroundHolo flags, the HoloMaskMeta sidecar, and writeMeta / metaFileURL plumbing; Settings → Holo now exposes only the show-play-button toggle in the Holo Levels section (intensity and pattern are driven by HoloCardRandomization's per-card variant roll).
  • TV mode 3D pivot — list rows now feature a 3D pivoting effect on their box art.
  • TV mode auto holo — TVModeHoloBoxart: wizard-style auto holo (self-driven light + card motion, user's weighted random variant) applied to the focused games-row tile and the selected game's hero boxart.
  • TV mode cold-start fix — skip the default .recent initialEntryID on cold-start resume and defer the persisted filter restore until the library loads.
  • TV mode stale-art fix — the stale detail-art download no longer overwrites the current hero ROM (download is handled solely by the detail view).
  • TV mode MainActor fix — read auto_generate_holo_masks on the main actor.
  • ROM identifier — removed bogus CD001 magic header from the pce system (it was the generic ISO 9660 Primary Volume Descriptor marker present in every cooked CD image, not just PC Engine discs); true PC Engine HuCards still match via the "PC ENGINE" signature at offset 0; PC Engine CD-ROMs handled by the dedicated pcecd system.
  • Box art assets — added zelda_oot_usa_chrome.png and zelda_oot_usa_title.png for The Legend of Zelda: Ocarina of Time (USA).
  • Project cleanup — removed TestWrite.swift references from project configuration.
  • Bump marketing version to 1.12.0 and build number to 35 across project.yml, both Info.plists, and docs/_config.yml.