mirror of
https://github.com/got-feedBack/feedBack.git
synced 2026-07-26 06:42:32 +00:00
window.h3dSetFretSpacing was the only 3D-highway setting that applied via location.reload(). The SPA boots with #home as the active screen and has no restore-last-screen mechanism, so the reload ejected the user from Settings onto the home screen. Apply it live like every other 3D-highway setting: rebind the module-scope _h3dFretUniform flag (so panels mounted later this session pick up the new mode), recompute the two fretX-derived scalars baked at init (_fretLabelScaleRefW, FRET_WIDTH_MID), and broadcast a 'fretSpacing' change over the existing _bgEmitChange pub-sub so every mounted panel rebuilds its board via buildBoard(). Per-frame note geometry already reads fretX live. Settings copy updated (no longer reloads) and tests/js pin the no-reload / live-rebuild behavior. Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
530995dd02
commit
fe8d30ce3e
@ -29,6 +29,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
||||
- **v3 library: exact artist/album filters + scroll/page-depth restore** (slopsmith#857). The v3 Songs toolbar gains Artist and Album dropdowns (Album populates from the selected artist and stays disabled until one is chosen), backed by new exact, case-insensitive (`COLLATE NOCASE`) `artist` / `album` query params threaded through `MetadataDB._build_where` → `query_page` / `query_artists` / `query_stats` and the `/api/library`, `/api/library/artists`, `/api/library/stats` endpoints (the free-text `q` search stays fuzzy and composes with the exact filters). The artist/album catalog is fetched independently of the active artist/album selection so the dropdowns always list the full set for the current provider/search. The toolbar is now sticky so filter controls stay reachable when browsing deep libraries, and returning from the player restores the previous scroll position **and** the loaded infinite-scroll page depth via a `sessionStorage` snapshot keyed by a filter/sort/view state hash (invalidated whenever those change, so a filter change still resets to the top). Tests: `tests/test_library_filters.py` (backend artist/album filters), `tests/js/v3_songs_scroll.test.js` (state-hash + snapshot helpers).
|
||||
|
||||
### Fixed
|
||||
- **Changing Settings → 3D Highway → Fret spacing no longer ejects you to the home screen.** The `highway_3d` plugin's `h3dSetFretSpacing` was the lone 3D-highway setting that called `location.reload()` to apply — and since the SPA boots with `#home` as the active screen (`index.html` `.screen.active`), the reload dropped the user out of Settings onto the homescreen. It now applies live like every other 3D-highway setting: it rebinds the module-scope `_h3dFretUniform` flag (so panels mounted later this session pick up the new mode), recomputes the two `fretX`-derived scalars that were baked at init (`_fretLabelScaleRefW` for fret-label sprite scaling, `FRET_WIDTH_MID` for camera hysteresis), and broadcasts a `fretSpacing` change over the existing `_bgEmitChange` pub-sub so every mounted panel rebuilds its board via `buildBoard()`. Per-frame note geometry already reads `fretX` live and needs no rebuild. No page reload, so the Settings screen stays put. Source-level regression tests in `tests/js/highway_3d_fret_spacing.test.js` now pin the no-reload / live-rebuild behavior.
|
||||
- **v3 library scroll-restore no longer breaks the classic v2 UI or drops off-screen searches** (slopsmith#857). Two regressions in the scroll-restore work above: (1) `playSong` remapped `home`-launched songs to return to the `#v3-songs` screen unconditionally, but `static/app.js` is shared with the v2 UI (served at `/v2` / `SLOPSMITH_UI=v2`) where that screen does not exist — Esc-from-player then called `showScreen('v3-songs')`, which threw on the missing element and stranded the user on a blank screen with playback still running; the remap now applies only when `#v3-songs` is present. (2) The Songs screen-entry fast-path skips reloading to preserve scroll, but the global topbar search routed through it, so once Songs had been visited, searching from another screen navigated there without applying the new query; the screen now tracks the state hash each fetch reflects and refetches when it has drifted, keeping the scroll-preserving no-op only when nothing changed.
|
||||
- **An active custom highway renderer is no longer starved of `draw()` when it hides the canvas** (#819). The per-frame draw gate in `static/highway.js` bailed on `if (!_lastVisible) return`, which conflated two different "hidden" states: a genuine off-screen canvas (`offsetParent === null` — navigate-away / `display:none` splitscreen panel, #246) versus a renderer-set *override-hide* (`setVisible(false)`, where an opaque overlay covers the canvas but the active renderer keeps painting its own surface). The gate now only pauses everything for the off-screen case (and still pauses the default 2D renderer on an override-hide); the **active custom renderer** keeps receiving `draw()` through its own override-hide. The `highway:visibility` event still fires before the gate, so sibling overlay renderers (e.g. 3D Highway's `.h3d-wrap`) still pause. This is the core-side root cause behind the Tab View cursor freezing in single-player (slopsmith#734; worked around plugin-side in slopsmith-plugin-tabview#25).
|
||||
- **Screensaver no longer kicks in during windowed-mode playback** (#686). While a song is playing, `static/app.js` now holds a [Screen Wake Lock](https://developer.mozilla.org/en-US/docs/Web/API/Screen_Wake_Lock_API) (`navigator.wakeLock.request('screen')`) so the OS display/screensaver stays awake even though only audio + the highway animation are active and the keyboard/mouse are idle. The lock is acquired on `song:play`/`song:resume` and released on `song:pause`/`song:ended`/`song:stop` (kept only while actually playing), and re-acquired on `visibilitychange` when the tab refocuses (the API auto-releases a lock whenever the page is hidden). Both the HTML5 `<audio>` and JUCE desktop playback paths emit the same `song:*` events, so the fix covers both. In slopsmith-desktop (Electron), where `navigator.wakeLock` is unreliable, it also drives a native `powerSaveBlocker` bridge via the optional `window.slopsmithDesktop.power.setScreenAwake` hook when present; both calls degrade silently where unsupported. Note: the browser Wake Lock API is secure-context only, so in a plain browser this is active on `localhost` / HTTPS only — a session opened over plain HTTP to a LAN IP (e.g. `http://192.168.1.100:8000`) won't keep the screen awake; front it with HTTPS or use the desktop app (see README → reverse-proxy notes).
|
||||
|
||||
@ -754,7 +754,16 @@
|
||||
if (localStorage.getItem('highway_3d.fretSpacing') === m) return;
|
||||
localStorage.setItem('highway_3d.fretSpacing', m);
|
||||
} catch (_) {}
|
||||
location.reload();
|
||||
// Apply live rather than reloading the page — a full page reload
|
||||
// reboots the SPA to the home screen (index.html's `.screen.active`),
|
||||
// ejecting the user from Settings. Rebind the module-scope flag so
|
||||
// panels mounted later this session pick up the new mode, recompute
|
||||
// the fretX-derived scalars, then broadcast a change so every mounted
|
||||
// panel rebuilds its board. Same live-update path as every other
|
||||
// 3D-highway setting.
|
||||
_h3dFretUniform = (m !== 'logarithmic');
|
||||
_recomputeFretSpacingDerived();
|
||||
_bgEmitChange('fretSpacing');
|
||||
};
|
||||
|
||||
const fretMid = f => (f <= 0 ? -2 * K : (fretX(f - 1) + fretX(f)) / 2);
|
||||
@ -767,7 +776,10 @@
|
||||
}
|
||||
/** Reference column (~mid board): prior fixed K-based sprites matched this neighborhood. */
|
||||
const FRET_LABEL_SCALE_REF_FRET = 5;
|
||||
const _fretLabelScaleRefW = Math.max(1e-8, fretColumnWorldW(FRET_LABEL_SCALE_REF_FRET));
|
||||
// `let` (not `const`): recomputed by _recomputeFretSpacingDerived when the
|
||||
// user flips Uniform/Logarithmic at runtime so label scaling tracks the
|
||||
// new geometry without a page reload.
|
||||
let _fretLabelScaleRefW = Math.max(1e-8, fretColumnWorldW(FRET_LABEL_SCALE_REF_FRET));
|
||||
function fretLabelScaleForFret(f) {
|
||||
const w = fretColumnWorldW(f);
|
||||
const m = w / _fretLabelScaleRefW;
|
||||
@ -823,7 +835,19 @@
|
||||
// World-units-per-fret near mid-neck. Used by the camera-X hysteresis
|
||||
// gate (issue #34) to convert a fret-equivalent dead zone into world
|
||||
// units. Pure function of SCALE — hoist out of update()'s hot path.
|
||||
const FRET_WIDTH_MID = fretX(7) - fretX(6);
|
||||
// `let` (not `const`): recomputed alongside _fretLabelScaleRefW when the
|
||||
// fret-spacing mode flips at runtime — see _recomputeFretSpacingDerived.
|
||||
let FRET_WIDTH_MID = fretX(7) - fretX(6);
|
||||
|
||||
// Recompute the fretX-derived scalars baked at module init. Called from
|
||||
// h3dSetFretSpacing after _h3dFretUniform flips so label scaling and the
|
||||
// camera hysteresis threshold track the newly chosen spacing — the live
|
||||
// alternative to the old location.reload(), which ejected the user from
|
||||
// Settings back to the home screen.
|
||||
function _recomputeFretSpacingDerived() {
|
||||
_fretLabelScaleRefW = Math.max(1e-8, fretColumnWorldW(FRET_LABEL_SCALE_REF_FRET));
|
||||
FRET_WIDTH_MID = fretX(7) - fretX(6);
|
||||
}
|
||||
|
||||
function computeBPM(beats, t) {
|
||||
if (!beats || beats.length < 2) return 120;
|
||||
@ -6214,6 +6238,15 @@
|
||||
scene.add(bgGroup);
|
||||
_bgMountStyle();
|
||||
_bgListener = (changedKey) => {
|
||||
if (changedKey === 'fretSpacing') {
|
||||
// _h3dFretUniform + the fretX-derived scalars were already
|
||||
// updated globally in h3dSetFretSpacing. Rebuild this
|
||||
// panel's static board geometry (fret wires, lanes, inlays)
|
||||
// so it re-lays-out for the new spacing; per-frame note
|
||||
// geometry reads fretX live and needs no rebuild.
|
||||
if (fretG) buildBoard();
|
||||
return;
|
||||
}
|
||||
if (changedKey === 'inlayLabelsVisible') {
|
||||
_bgLoadSettings();
|
||||
// Flip visibility on the already-built sprites; no
|
||||
|
||||
@ -52,7 +52,7 @@
|
||||
<option value="uniform">Uniform (equal width per fret)</option>
|
||||
<option value="logarithmic">Instrument (logarithmic — decreasing toward bridge)</option>
|
||||
</select>
|
||||
<p class="text-xs text-gray-500 mt-1">The page will reload when changed.</p>
|
||||
<p class="text-xs text-gray-500 mt-1">Applies to the 3D highway immediately.</p>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
|
||||
@ -42,3 +42,33 @@ test('h3dSetFretSpacing validates the mode against the two supported values', ()
|
||||
'h3dSetFretSpacing must coerce mode to a supported value before persisting',
|
||||
);
|
||||
});
|
||||
|
||||
test('h3dSetFretSpacing applies the change live, not via a page reload', () => {
|
||||
// A reload reboots the SPA to the home screen, ejecting the user from
|
||||
// Settings. The setter must instead rebind the spacing flag and broadcast
|
||||
// a 'fretSpacing' change so mounted panels rebuild in place — same path as
|
||||
// every other 3D-highway setting. Reintroducing location.reload() here is
|
||||
// the regression this guards against.
|
||||
const src = fs.readFileSync(SCREEN_JS, 'utf8');
|
||||
const setter = src.match(/window\.h3dSetFretSpacing\s*=\s*mode\s*=>\s*\{[\s\S]*?\n \};/);
|
||||
assert.ok(setter, 'h3dSetFretSpacing assignment must be present');
|
||||
assert.doesNotMatch(
|
||||
setter[0],
|
||||
/location\.reload/,
|
||||
'h3dSetFretSpacing must not reload the page (it ejects the user from Settings)',
|
||||
);
|
||||
assert.match(
|
||||
setter[0],
|
||||
/_bgEmitChange\(\s*'fretSpacing'\s*\)/,
|
||||
'h3dSetFretSpacing must broadcast a live fretSpacing change',
|
||||
);
|
||||
});
|
||||
|
||||
test('the fretSpacing change rebuilds a mounted board live', () => {
|
||||
const src = fs.readFileSync(SCREEN_JS, 'utf8');
|
||||
assert.match(
|
||||
src,
|
||||
/changedKey\s*===\s*'fretSpacing'[\s\S]*?if\s*\(fretG\)\s*buildBoard\(\)/,
|
||||
'the panel bg listener must rebuild the board when fretSpacing changes',
|
||||
);
|
||||
});
|
||||
|
||||
Loading…
Reference in New Issue
Block a user