v2.9.0 "Full Circle"
Rusty2600 v2.9.0 "Full Circle"
Sixth release of the RustyNES gap-closure arc — closes the remaining
wasm-winit capability gap against RustyNES's own wasm demo: a
share-link feature, PWA install, and a wasm32-safe debugger overlay —
plus a real, not re-deferred, investigation into in-browser Lua
scripting that concluded honestly deferred.
Shipped through PR #19, reviewed by GitHub Copilot and Gemini Code
Assist — 2 findings, both fixed.
?settings= share-link
Round-trips the whole Config (region, video, audio, both players' key
bindings) through a hand-rolled, URL-safe base64 codec — pure and
target-agnostic, so the encode/decode logic is exercised by 7 new native
unit tests without touching a single browser API. Applied on boot,
overriding Config::load()'s persisted localStorage value when a
?settings= parameter is present in the URL. Deliberately settings-only
(no ROM reference) — neither the native rfd file dialog nor the wasm
<input type=file> picker has a URL a share link could carry, so a
recipient still picks their own ROM file.
A wasm32-safe debugger overlay
debug-hooks is now confirmed wasm32-safe for wasm-winit: the CPU/
TIA/RIOT/Memory panels plus nearly every other native debugger panel
(Watch, Callstack, Events, Player-Missile-Ball, Access, Compare,
TAStudio's jump-to-frame) work identically in-browser. The one
exception — TAStudio's "Save branch" action, which needs rfd's
native-only save-file dialog — is scoped out specifically
(MenuAction::TastudioSaveBranch is not(target_arch = "wasm32")-gated)
rather than excluding all of debug-hooks from the wasm build.
PWA install
A web app manifest plus a service worker (web/manifest.json,
web/sw.js) make the deployed build installable ("Add to Home Screen" /
desktop install prompt) and usable offline after a first visit. Since
Trunk hashes build filenames per release, a static precache manifest
would go stale every rebuild — instead the service worker runtime-caches
same-origin GETs: cache-first-then-revalidate for sub-resources (wasm,
JS glue, CSS, icons, manifest), network-first for the app-shell
navigation request (see the PR review fix below for why that split
matters).
In-browser Lua scripting — investigated for real, deferred with a confirmed reason
This crate's own module doc has flagged a piccolo-backed wasm fallback
as a "genuine, scoped follow-up" since it was first built. This release
actually did that follow-up investigation rather than re-deferring on
the same old reasoning:
mluaonwasm32is confirmed, again, a hard wall. A direct
build attempt (cargo check --target wasm32-unknown-unknown -p rusty2600-script) fails insidelua-src's build script: "don't know
how to build Lua for wasm32-unknown-unknown." The vendored C build
genuinely cannot target that toolchain — not a bug to work around.piccolois not yet a workable substrate either, for two
compounding reasons: its only crates.io-published release (0.3.3)
implements almost none of Lua'sstring/tablestdlib — per its own
README, ruling out exactly the kind of ordinary script this crate's
emuAPI invites (string.formatfor a debug label,table.insert
for per-frame state tracking); and itsExecutor-based "stackless"
VM architecture (agc-arena-rooted,Send-incompatible design) has
no equivalent toengine.rs's "keep the VM around, call into it once
per real frame" pattern without building realgc-arena/Rootable!
plumbing from scratch — a genuine engine rewrite, not a parallel
engine_piccolo.rssibling. Its more-complete unpublishedmaster
branch is explicitly labeled pre-1.0-unstable by its own maintainer.
Native's mlua backend is completely unchanged — same crate, same
version pin, same feature gating. Documented in crates/rusty2600- script/src/lib.rs's module doc and docs/scripting.md; revisit once
piccolo publishes a crates.io release with real string/table
coverage — an upstream milestone, not one this project controls or can
schedule against.
PR review, for real
PR #19 was reviewed by GitHub Copilot and Gemini Code Assist — 2
findings, both genuine, both fixed:
- A real cache-safety bug (Copilot): the service worker's
activatehandler deleted every cache except its ownCACHE_NAME—
but Cache Storage is origin-wide, not scoped to one service worker, so
this could have wiped a sibling GitHub Pages project's caches sharing
the same origin. Fixed by filtering on aCACHE_PREFIXinstead, so
only a previous Rusty2600 shell cache is ever evicted. - A real offline-breaking race condition (Gemini Code Assist, high
priority): stale-while-revalidate on theindex.htmlnavigation
request, combined with Trunk's hashed sub-resource filenames, could
leave a later offline visit with HTML referencing hashed assets that
were never actually fetched (if the background revalidate silently
updated the cached HTML to a newer version before those new hashed
assets were ever cached). Fixed by switching navigation requests to
network-first; sub-resources keep cache-first-then-revalidate, since
they're effectively immutable-by-hash.
Test count
349 tests passing on default features (353 with --features test-roms)
— up from 342/346, the 7 new tests covering the share-link base64 codec
and its encode/decode round-trip. Full CI green — Linux/macOS/Windows,
the perf regression gate, and the no_std gate. Independently
re-verified beyond the standard gate: cargo check/cargo clippy --target wasm32-unknown-unknown --features wasm-winit and the new
--features wasm-winit,debug-hooks combination (the wasm debugger
overlay) both clean; --features wasm-canvas (the other wasm build)
unaffected.
Honest verification boundary
Live in-browser verification (the share-link actually round-tripping
via a real browser URL bar, the service worker actually caching
offline, the debugger overlay actually rendering) remains blocked by
the same sandboxed-headless-Chromium GPU limitation documented since
v2.5.0 — this sandbox can't render wasm-winit at all. Everything
verifiable without live browser GPU access (unit tests, wasm32 compile +
clippy checks) has been confirmed.
What's next
v2.10.0 "Prism" — Shader Stack Expansion: a higher-quality NTSC
composite demodulation pass, hqNx/xBRZ upscaling, and a constrained
RetroArch .slangp/.cgp preset importer, growing
rusty2600-gfx-shaders beyond its current CRT scanline + composite-
artifact approximation. See to-dos/ROADMAP.md for the complete
v2.4.0 -> v3.0.0 roadmap.