diff --git a/CHANGELOG.md b/CHANGELOG.md index dca1957..16087db 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ## [Unreleased] +## [1.20.0] "Aperture" - 2026-07-15 + +Phase A of the new UI/UX-parity ladder: brings the wasm demo's menus and the desktop frontend's +peripheral/overscan/inspection controls up from placeholder or dormant to actually functional, +closing several gaps found in a systematic audit against RustyNES's own frontend. + ### Fixed - **Wasm demo: `Cheats`/`Debugger overlay` menu items now real, not placeholders** (Phase A of the diff --git a/Cargo.lock b/Cargo.lock index effdcc1..a63d735 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3703,7 +3703,7 @@ checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" [[package]] name = "rustysnes-android" -version = "1.19.0" +version = "1.20.0" dependencies = [ "android_logger", "bytemuck", @@ -3719,7 +3719,7 @@ dependencies = [ [[package]] name = "rustysnes-apu" -version = "1.19.0" +version = "1.20.0" dependencies = [ "bitflags 2.13.0", "rustysnes-savestate", @@ -3727,7 +3727,7 @@ dependencies = [ [[package]] name = "rustysnes-cart" -version = "1.19.0" +version = "1.20.0" dependencies = [ "bitflags 2.13.0", "rustysnes-savestate", @@ -3736,7 +3736,7 @@ dependencies = [ [[package]] name = "rustysnes-cheevos" -version = "1.19.0" +version = "1.20.0" dependencies = [ "cc", "ureq", @@ -3744,7 +3744,7 @@ dependencies = [ [[package]] name = "rustysnes-core" -version = "1.19.0" +version = "1.20.0" dependencies = [ "criterion", "rustysnes-apu", @@ -3759,7 +3759,7 @@ dependencies = [ [[package]] name = "rustysnes-cpu" -version = "1.19.0" +version = "1.20.0" dependencies = [ "bitflags 2.13.0", "rustysnes-savestate", @@ -3767,7 +3767,7 @@ dependencies = [ [[package]] name = "rustysnes-frontend" -version = "1.19.0" +version = "1.20.0" dependencies = [ "anstyle", "bytemuck", @@ -3808,11 +3808,11 @@ dependencies = [ [[package]] name = "rustysnes-gfx-shaders" -version = "1.19.0" +version = "1.20.0" [[package]] name = "rustysnes-ios" -version = "1.19.0" +version = "1.20.0" dependencies = [ "bytemuck", "log", @@ -3825,7 +3825,7 @@ dependencies = [ [[package]] name = "rustysnes-libretro" -version = "1.19.0" +version = "1.20.0" dependencies = [ "libc", "rust-libretro", @@ -3834,7 +3834,7 @@ dependencies = [ [[package]] name = "rustysnes-mobile" -version = "1.19.0" +version = "1.20.0" dependencies = [ "rustysnes-cart", "rustysnes-core", @@ -3844,14 +3844,14 @@ dependencies = [ [[package]] name = "rustysnes-monetization" -version = "1.19.0" +version = "1.20.0" dependencies = [ "uniffi", ] [[package]] name = "rustysnes-netplay" -version = "1.19.0" +version = "1.20.0" dependencies = [ "js-sys", "rustysnes-core", @@ -3863,7 +3863,7 @@ dependencies = [ [[package]] name = "rustysnes-ppu" -version = "1.19.0" +version = "1.20.0" dependencies = [ "bitflags 2.13.0", "rustysnes-cart", @@ -3873,14 +3873,14 @@ dependencies = [ [[package]] name = "rustysnes-savestate" -version = "1.19.0" +version = "1.20.0" dependencies = [ "thiserror 2.0.18", ] [[package]] name = "rustysnes-script" -version = "1.19.0" +version = "1.20.0" dependencies = [ "mlua", "rustysnes-core", @@ -3889,7 +3889,7 @@ dependencies = [ [[package]] name = "rustysnes-test-harness" -version = "1.19.0" +version = "1.20.0" dependencies = [ "insta", "rustysnes-apu", diff --git a/Cargo.toml b/Cargo.toml index 284082f..c4be9f8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -21,7 +21,7 @@ members = [ ] [workspace.package] -version = "1.19.0" +version = "1.20.0" edition = "2024" rust-version = "1.96" license = "MIT OR Apache-2.0" diff --git a/crates/rustysnes-android/Cargo.toml b/crates/rustysnes-android/Cargo.toml index 6d44580..1af9898 100644 --- a/crates/rustysnes-android/Cargo.toml +++ b/crates/rustysnes-android/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustysnes-android" description = "RustySNES: Android JNI presentation host (wgpu-on-Surface, no emulation logic)" -version = "1.19.0" +version = "1.20.0" edition.workspace = true rust-version.workspace = true license.workspace = true diff --git a/crates/rustysnes-apu/Cargo.toml b/crates/rustysnes-apu/Cargo.toml index 3abe979..cf9116a 100644 --- a/crates/rustysnes-apu/Cargo.toml +++ b/crates/rustysnes-apu/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rustysnes-apu" -version = "1.19.0" +version = "1.20.0" edition.workspace = true rust-version.workspace = true license.workspace = true diff --git a/crates/rustysnes-cart/Cargo.toml b/crates/rustysnes-cart/Cargo.toml index 2fb9a90..e2d36b8 100644 --- a/crates/rustysnes-cart/Cargo.toml +++ b/crates/rustysnes-cart/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rustysnes-cart" -version = "1.19.0" +version = "1.20.0" edition.workspace = true rust-version.workspace = true license.workspace = true diff --git a/crates/rustysnes-cheevos/Cargo.toml b/crates/rustysnes-cheevos/Cargo.toml index 11d3d72..653dd76 100644 --- a/crates/rustysnes-cheevos/Cargo.toml +++ b/crates/rustysnes-cheevos/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustysnes-cheevos" description = "Native-only RetroAchievements (rcheevos) FFI wrapper for RustySNES" -version = "1.19.0" +version = "1.20.0" edition.workspace = true rust-version.workspace = true license.workspace = true diff --git a/crates/rustysnes-core/Cargo.toml b/crates/rustysnes-core/Cargo.toml index 85a5dba..186d9a6 100644 --- a/crates/rustysnes-core/Cargo.toml +++ b/crates/rustysnes-core/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rustysnes-core" -version = "1.19.0" +version = "1.20.0" edition.workspace = true rust-version.workspace = true license.workspace = true diff --git a/crates/rustysnes-cpu/Cargo.toml b/crates/rustysnes-cpu/Cargo.toml index 89329b0..006cd9d 100644 --- a/crates/rustysnes-cpu/Cargo.toml +++ b/crates/rustysnes-cpu/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rustysnes-cpu" -version = "1.19.0" +version = "1.20.0" edition.workspace = true rust-version.workspace = true license.workspace = true diff --git a/crates/rustysnes-frontend/Cargo.toml b/crates/rustysnes-frontend/Cargo.toml index a1fc937..685c27d 100644 --- a/crates/rustysnes-frontend/Cargo.toml +++ b/crates/rustysnes-frontend/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustysnes-frontend" description = "RustySNES: cross-platform SNES emulator binary (winit + wgpu + cpal + egui)" -version = "1.19.0" +version = "1.20.0" edition.workspace = true rust-version.workspace = true license.workspace = true diff --git a/crates/rustysnes-gfx-shaders/Cargo.toml b/crates/rustysnes-gfx-shaders/Cargo.toml index e2a5341..b0bebe6 100644 --- a/crates/rustysnes-gfx-shaders/Cargo.toml +++ b/crates/rustysnes-gfx-shaders/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustysnes-gfx-shaders" description = "RustySNES: shared WGSL presentation-shader sources (blit + post-filters)" -version = "1.19.0" +version = "1.20.0" edition.workspace = true rust-version.workspace = true license.workspace = true diff --git a/crates/rustysnes-ios/Cargo.toml b/crates/rustysnes-ios/Cargo.toml index 0d46df3..d5586d5 100644 --- a/crates/rustysnes-ios/Cargo.toml +++ b/crates/rustysnes-ios/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustysnes-ios" description = "RustySNES: iOS Metal presentation host (wgpu-on-CAMetalLayer, no emulation logic)" -version = "1.19.0" +version = "1.20.0" edition.workspace = true rust-version.workspace = true license.workspace = true diff --git a/crates/rustysnes-mobile/Cargo.toml b/crates/rustysnes-mobile/Cargo.toml index 0115ad1..4fc3cc6 100644 --- a/crates/rustysnes-mobile/Cargo.toml +++ b/crates/rustysnes-mobile/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustysnes-mobile" description = "RustySNES: UniFFI mobile bridge (Kotlin/Swift bindings over the emulation core)" -version = "1.19.0" +version = "1.20.0" edition.workspace = true rust-version.workspace = true license.workspace = true diff --git a/crates/rustysnes-monetization/Cargo.toml b/crates/rustysnes-monetization/Cargo.toml index 83704c4..1eaeaf3 100644 --- a/crates/rustysnes-monetization/Cargo.toml +++ b/crates/rustysnes-monetization/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustysnes-monetization" description = "RustySNES: dormant entitlement/ad-pacing policy scaffold (mobile-only, never a dependency of the deterministic core)" -version = "1.19.0" +version = "1.20.0" edition.workspace = true rust-version.workspace = true license.workspace = true diff --git a/crates/rustysnes-netplay/Cargo.toml b/crates/rustysnes-netplay/Cargo.toml index 6f1a0e4..e262ded 100644 --- a/crates/rustysnes-netplay/Cargo.toml +++ b/crates/rustysnes-netplay/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustysnes-netplay" description = "RustySNES: GGPO-style rollback netplay (UDP native, WebRTC browser)" -version = "1.19.0" +version = "1.20.0" edition.workspace = true rust-version.workspace = true license.workspace = true diff --git a/crates/rustysnes-ppu/Cargo.toml b/crates/rustysnes-ppu/Cargo.toml index 211a6a3..ba1b19a 100644 --- a/crates/rustysnes-ppu/Cargo.toml +++ b/crates/rustysnes-ppu/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rustysnes-ppu" -version = "1.19.0" +version = "1.20.0" edition.workspace = true rust-version.workspace = true license.workspace = true diff --git a/crates/rustysnes-savestate/Cargo.toml b/crates/rustysnes-savestate/Cargo.toml index 023ebbb..79a28b7 100644 --- a/crates/rustysnes-savestate/Cargo.toml +++ b/crates/rustysnes-savestate/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rustysnes-savestate" -version = "1.19.0" +version = "1.20.0" edition.workspace = true rust-version.workspace = true license.workspace = true diff --git a/crates/rustysnes-script/Cargo.toml b/crates/rustysnes-script/Cargo.toml index 2ced8f7..e95a89d 100644 --- a/crates/rustysnes-script/Cargo.toml +++ b/crates/rustysnes-script/Cargo.toml @@ -1,7 +1,7 @@ [package] name = "rustysnes-script" description = "RustySNES: sandboxed Lua 5.4 scripting (memory read/write + a per-frame callback)" -version = "1.19.0" +version = "1.20.0" edition.workspace = true rust-version.workspace = true license.workspace = true diff --git a/crates/rustysnes-test-harness/Cargo.toml b/crates/rustysnes-test-harness/Cargo.toml index 59322a1..7766b3e 100644 --- a/crates/rustysnes-test-harness/Cargo.toml +++ b/crates/rustysnes-test-harness/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rustysnes-test-harness" -version = "1.19.0" +version = "1.20.0" edition.workspace = true rust-version.workspace = true license.workspace = true diff --git a/docs/STATUS.md b/docs/STATUS.md index 55d9ad8..af94b60 100644 --- a/docs/STATUS.md +++ b/docs/STATUS.md @@ -3,7 +3,7 @@ This file is authoritative for per-suite pass counts, the board / coprocessor matrix, and version policy. Everything else defers to it. -**Current release:** `v1.19.0 "Afterburner"` (`v0.1.0 "Foundation"`, +**Current release:** `v1.20.0 "Aperture"` (`v0.1.0 "Foundation"`, `v0.2.0 "Persistence"`, `v0.3.0 "Continuum"`, `v0.4.0 "Completion"`, `v0.5.0 "Fidelity"`, `v0.6.0 "Shippable"`, `v0.7.0 "Resolution"`, `v0.8.0 "Community"`, `v0.9.0 "Threshold"`, `v1.0.0 "Zenith"`, `v1.0.1 "Aftertouch"`, `v1.1.0 "Latchkey"`, `v1.2.0 "Phosphor"`, @@ -53,7 +53,13 @@ real-verified end-to-end in this development environment including a genuine BOL found and fixed in PR review (`v1.19.0 "Afterburner"`) — all frontend/tooling/CI work with **zero change** to the accuracy dashboard, per-suite pass counts, or coprocessor tier matrix below, -which stayed byte-identical throughout; see `CHANGELOG.md` for full per-release detail. `v1.0.0` +which stayed byte-identical throughout; see `CHANGELOG.md` for full per-release detail. +**`v1.20.0 "Aperture"`** opens a new UI/UX-parity ladder (Phase A) auditing the desktop frontend +and wasm demo against RustyNES's own frontend maturity: two wasm demo menu items (`Cheats`/ +`Debugger overlay`) fixed from placeholder to real, live Mouse/Super Scope host-input capture +wired for the first time (`crate::peripherals`), a View → Hide Overscan toggle, and a new +Debug → ROM Info panel — again zero change to the accuracy dashboard; see `CHANGELOG.md` for +full detail. `v1.0.0` closes the production-cut gate: `Board: Send` (unblocking `emu-thread` to compile/test/lint clean for the first time, though it stays off-by-default pending full feature parity — see `docs/frontend.md`), the five diff --git a/to-dos/ROADMAP.md b/to-dos/ROADMAP.md index 411c5cb..2932a35 100644 --- a/to-dos/ROADMAP.md +++ b/to-dos/ROADMAP.md @@ -374,6 +374,16 @@ under `v1.0.0`) and the netplay save-state-cost pre-work. Tracked in lockstep against RustyNES's own continuing development via `to-dos/LOCKSTEP-CHECKLIST.md`, not a frozen snapshot target. Full detail in `to-dos/VERSION-PLAN.md`'s "RustyNES-parity ladder" section. +- **A new, separate UI/UX-parity ladder, Phase A (`v1.20.0 "Aperture"`, RELEASED 2026-07-15).** A + systematic audit of RustySNES's menus/settings/debugger against RustyNES's own frontend found + the wasm demo showing placeholder labels for two features never actually excluded for any real + reason (`cheats`/`debug-hooks`, now real), a desktop peripheral-input gap (Settings selected the + Mouse/Super Scope hardware but nothing captured host pointer input, now wired via a new + `crate::peripherals` module), a missing View → Hide Overscan toggle, and closed the ROM Info + debugger panel small-catch-up item named above. Full detail in `to-dos/VERSION-PLAN.md`'s + `v1.20.0 "Aperture"` entry. Phases B (in-app Help docs, deeper debugger panels) and C (wasm Lua + scripting, browser netplay lobby, browser RetroAchievements, i18n) remain scoped but not + started. - **Flagged by the 2026-07-12 lockstep re-check — no rung assigned yet, maintainer go/no-go needed.** RustyNES shipped two items since the roadmap's `v2.1.5` baseline that RustySNES's own ladder doesn't currently account for: (1) a **GIF/WAV screen+audio capture subsystem** @@ -404,7 +414,9 @@ under `v1.0.0`) and the netplay save-state-cost pre-work. its own, narrower scope, and no untrusted-input crash has ever been found), so neither is silently folded into an already-closed rung — see `to-dos/LOCKSTEP-CHECKLIST.md`'s 2026-07-15 log row for the full disposition, including three smaller items (a self-contained ROM Info - debugger panel judged a small catch-up; RustySNES's `movie.rs` deserializer already independently + debugger panel judged a small catch-up — **closed in `v1.20.0 "Aperture"`**, as part of that + rung's own separate UI/UX-parity audit against RustyNES's frontend, not this lockstep check + directly; RustySNES's `movie.rs` deserializer already independently hardened against the same OOM-DoS class RustyNES's fuzzing just found, so already covered; and a Zapper aperture-hardening technique that doesn't map onto RustySNES's own, architecturally different geometric Super Scope hit-detection model, so not directly applicable). diff --git a/to-dos/VERSION-PLAN.md b/to-dos/VERSION-PLAN.md index 72b5c92..0f8800a 100644 --- a/to-dos/VERSION-PLAN.md +++ b/to-dos/VERSION-PLAN.md @@ -1312,3 +1312,48 @@ reaches RustyNES's current maturity bar at RustySNES's own `v1.19.0`, not a lite If the store-launch decision above is ever greenlit, that's the natural point to consider a `v2.0.0` MAJOR bump (a platform-scope-expanding, non-backward-compatible milestone, matching this document's own MAJOR-bump rule) — decided then, via the lockstep checklist, not pre-committed here. + +### `v1.20.0 "Aperture"` — UI/UX-parity ladder, Phase A — **RELEASED 2026-07-15** + +A new ladder, separate from the just-closed RustyNES-parity one: a systematic audit of +RustySNES's menus/settings/debugger against RustyNES's own frontend found the GitHub Pages wasm +demo showing literal `(rebuild with --features X)` placeholders for two features +(`cheats`/`debug-hooks`) that were never actually excluded for any architectural reason, plus a +desktop peripheral-input gap (the Settings Mouse/Super Scope selector wired the emulated hardware +but nothing ever captured host pointer input) and two small, named catch-up items already on +record (`to-dos/ROADMAP.md`'s "Milestones beyond the phases", `to-dos/LOCKSTEP-CHECKLIST.md`'s +2026-07-15 entry). + +Delivered: `.github/workflows/web.yml`'s `trunk build` gained `--features cheats,debug-hooks`, +making the wasm demo's Tools → Cheats and Debug → Debugger overlay menu items real; a new +`crate::peripherals` module feeds `egui::Context`'s pointer state into `EmuCore::set_mouse`/ +`set_superscope` once per frame, mapped through the same letterbox transform the present path +already uses (real bugs found and fixed in review: mouse deltas needed `pixels_per_point` + +letterbox rescaling to stay window-size/DPI-independent, and Super Scope needed to map into the +SNES's fixed base 256×224/239 screen space rather than the PPU's raw, possibly pixel-doubled +`fb_dims`); a View → Hide Overscan toggle crops the SNES's `SETINI`-extended 239-line display +back to 224 by a height FRACTION (stays exact under HD-pack's own integer upscale), applied +against the finalized presented `dims` (a real desync bug found and fixed in review — an earlier +pre-captured flag could read a stale resolution across a run-ahead/`emu-thread` PresentBuffer +handoff); and a new Debug → ROM Info panel (CRC32/SHA-256/header decode of the loaded cart, +captured once per successful load rather than every frame) closes the ROM-Info-panel catch-up +item, gained a decoded `title: String` field on `rustysnes_cart::header::Header` along the way, +and — per a real review finding — only hashes the ROM when `debug-hooks` is on and the load +actually succeeded, not on every attempt. + +Also fixed a real, separate finding surfaced while scoping the peripheral-input work: +`docs/frontend.md`'s own "Status" line claimed controller port 1 had "keyboard + gilrs gamepad" +input, but `gilrs::Gilrs` is never actually instantiated anywhere in `rustysnes-frontend` — port +1 is keyboard-only today. Corrected the doc; real gamepad support (and the Super Multitap +sub-pad host input it blocks) is a genuinely separate, larger prerequisite, tracked in the +UI/UX-parity plan's backlog, not silently expanded into this rung. + +Verified for real: a local `trunk build --release` reproducing the exact CI command (gzip size +2.96 MiB, well under the 5 MiB budget); the full local regression gate (fmt/test/clippy across +every feature combination including `wasm32-unknown-unknown`/doc-warnings-as-errors) green on +every PR; every `gemini-code-assist`/`copilot-pull-request-reviewer` finding adjudicated and its +GitHub thread resolved before merge, including two independently-confirmed real bugs (the mouse/ +Super Scope scaling issues) and a real presented-frame desync (the overscan flag). Phases B and C +of the UI/UX-parity plan (in-app Help docs, deeper debugger panels, wasm Lua scripting via +`piccolo`, browser netplay lobby, browser RetroAchievements, i18n) remain scoped but not started — +each is its own future rung, sized like a small roadmap phase on its own.