Follow-up to E29. When the userscript runs in an isolated world
(Tampermonkey @sandbox DOM, Violentmonkey @inject-into content, checked
via GM_info), frame commands travel through the manager's per-script
storage (GM_setValue + GM_addValueChangeListener on random per-instance
keys), which pages can't write. Without isolation it stays same-origin
only: in page mode the attacker page can fake navigator.getGamepads for
SofaNav in its own top frame (shown by a negative control).
Also: activate() passes document.defaultView as the event view, since
userscript managers may wrap window (PointerEvent threw in VM page mode).
test:security now installs the userscript in a pinned, sha256-checked
Violentmonkey and adds a fake-controller attack.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
GitHub Pages for this account is served from the custom domain
mmis1000.me, so github.io only redirects. Update/download URLs in the
userscript, README links and og:image now point at https://mmis1000.me/SofaNav/.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- site/index.html: landing page that runs SofaNav itself (controller, or an
opt-in keyboard mode), demo video with poster, features, install links,
controls. scripts/build-site.js assembles _site/ (page, userscript,
extension zip, video) with no extra dependencies.
- .github/workflows/ci.yml: checks dist/ is rebuilt from content.js, runs
the Playwright regression checks, builds the site and deploys it to
GitHub Pages on main.
- Userscript header: @homepageURL/@downloadURL/@updateURL on the Pages site
so installs update themselves.
- One copy per page: the guard also marks <html data-sofanav>, so the
page's copy and an installed extension don't both run.
- E28: the button hint hides while its element is scrolled off screen
(it was clamped onto the screen next to nothing). New regression check.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- Package, extension and userscript are SofaNav / sofanav: dist/sofanav.user.js,
console prefix [sofanav], View toast, demo/sofanav-demo.mp4.
- Globally unique ids on mmis1000.me: userscript @namespace
https://sofanav.mmis1000.me, Firefox id sofanav@mmis1000.me, frame message
tag sofanav.mmis1000.me/1.
- Internal names: page-load guard __sofanavLoaded, debug hooks
__sofanavDebug / __sofanav, SVG marker ids sofanav-arrow-*.
- Userscript managers treat the new @name/@namespace as a new script:
remove the old "Gamepad Spatial Navigation" once.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@build isn't a userscript key, so linters warned about it. The hash stays
in @description and a plain "// Build <hash>" comment after the block,
which the build also reads to keep the version stable.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
So the build hash matches on every checkout regardless of local line
endings (git stores LF; files written on Windows may have CRLF).
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
- E22: frames run the same container/scope logic as the top page and report
container counts, scroll room and native clickability; the top frame
enters/leaves frame containers by message and scrolls them past their
edge. Frames judge "page-sized" against the top window's area, so a chat
list filling its frame is a container. Scrolling boxes with nothing
focusable (>= 120x60) are scroll-only stops for the right stick.
test/chat-frame.html reproduces YouTube live chat (real chat doesn't render
in automated browsers); two new regression checks.
- E23: userscript builds are stamped with a hash of content.js (@build,
description, console "[webpad] build <hash>", View toast) and a monotonic
@version 0.3.0.<UTC timestamp> that only changes with the code, so
userscript managers see updates.
- Version 0.3.0.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Console-style controller navigation for web pages:
- D-pad: scored 4-direction graph with orphan rescue
- Left stick: free-aim ray casting with a pie-chart visualization
- Keyboard-style repeat, stick dead/release zones and bounce filtering
- Focus recovery and scroll-area-aware re-entry
- Iframe support (top-frame engine, per-frame clients)
- Container scopes (X enters a card, B leaves); scrollable panels are
containers too and can be scrolled directly while focused
- Test pages and docs/test-cases.md (checklist + edge-case log E1-E17)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>