From 9f0d48cb1f6d8cbe2146841c6ba876fe4bdf5805 Mon Sep 17 00:00:00 2001 From: topkoa Date: Wed, 1 Jul 2026 01:53:45 -0400 Subject: [PATCH] 3D highway wide-pane tuner: dismiss + per-pane targeting MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Two usability gaps in the wide-pane framing tuner: - No way to dismiss the panel. Add a × close button to the header and make the Shift+A shortcut open/close the panel (reveal/dismiss). The A/B enabled toggle now lives as a checkbox in the panel, so closing the panel no longer changes the framing state. - Edits hit every split pane at once. Add a Target selector (All panes, or a specific pane labelled by its arrangement, e.g. "Panel 1 — Rhythm"). Per- pane edits write a sparse override map (__panels[key]); each renderer resolves the shared base with its own pane's overrides laid on top via _resolveTuneFor(paneKey), so one pane can be framed independently. Reset on a pane clears its override (re-inherits the base); Copy exports the resolved values for the selected target. The live readout is keyed per pane. Panes are discovered from the existing per-panel key (_bgPanelKey / feedBackSplitscreen.panelIndexFor) and self-register each frame for the picker. Overrides persist to localStorage alongside the base. Tests extended in tests/js/highway_3d_wide_fov.test.js. Co-Authored-By: Claude Opus 4.8 Signed-off-by: topkoa --- plugins/highway_3d/screen.js | 251 ++++++++++++++++++++------- tests/js/highway_3d_wide_fov.test.js | 59 ++++++- 2 files changed, 236 insertions(+), 74 deletions(-) diff --git a/plugins/highway_3d/screen.js b/plugins/highway_3d/screen.js index ae7f8a7..beeaf12 100644 --- a/plugins/highway_3d/screen.js +++ b/plugins/highway_3d/screen.js @@ -1607,14 +1607,13 @@ ss.isCanvasFocused(highwayCanvas)); } - // A/B toggle for the wide-pane horizontal-FOV-hold. Flips - // window.__h3dAspectTune.enabled so the running app can switch between the - // current framing (off, the baseline) and the Hor+ framing (on) with one - // keypress, across all panes at once. Registered once per session via a - // module-level guard (it toggles a shared global, so per-instance - // registration would stack duplicate handlers and cancel itself out); it's - // a harmless debug control, so it is never unregistered. No-ops where the - // core shortcut API isn't present (older core / borrowed contexts). + // Shortcut for the wide-pane framing tuner. Opens/closes the floating panel + // (the A/B on/off and the per-pane target live inside it now). Registered + // once per session via a module-level guard (it drives shared module state, + // so per-instance registration would stack duplicate handlers and cancel + // itself out); it's a harmless debug control, so it is never unregistered. + // No-ops where the core shortcut API isn't present (older core / borrowed + // contexts). let _abShortcutRegistered = false; function _registerAspectAbShortcut() { if (_abShortcutRegistered) return; @@ -1623,17 +1622,13 @@ try { window.registerShortcut({ key: 'A', // uppercase e.key → produced with Shift held (Shift+A) - description: '3D Highway: toggle wide-pane framing A/B (Shift+A)', + description: '3D Highway: open/close wide-pane framing tuner (Shift+A)', scope: 'player', handler: () => { - const t = _aspectTune(); - t.enabled = !t.enabled; - try { console.log('[h3d] wide-pane framing', t.enabled ? 'ON' : 'OFF'); } catch (e) {} - // Surface the live tuner panel whenever the feature is on, - // hide it when off. Built lazily on first use. - _ensureAspectPanel(); - _setAspectPanelVisible(t.enabled); - _syncAspectPanel(); + // Open/close the live tuner panel. The A/B on/off and the + // per-pane target now live in the panel itself, so the + // shortcut is just a dismiss/reveal. + _toggleAspectPanel(); }, }); } catch (e) { @@ -1685,8 +1680,19 @@ let _aspectPanelEl = null; // the floating panel root (built once) let _aspectPanelRO = null; // readout
let _aspectPanelRAF = 0; // readout poll handle + let _aspectTargetSel = null; // the "Target" '); + assert.match(src, /function\s+_aspectRegisterPane\s*\(/, + '_aspectRegisterPane must record live panes for the picker'); + assert.match(src, /_aspectRegisterPane\(\s*_paneKey\s*,/, + 'camUpdate must register its pane each frame'); +}); + +test('the panel has a dismiss (close) control', () => { + assert.match( + src, + /close\.textContent\s*=\s*'×'[\s\S]*?_setAspectPanelVisible\(\s*false\s*\)/, + 'the panel header must have a × button that hides the panel', + ); }); test('camUpdate only writes cam.fov when it actually changes', () => { @@ -153,14 +192,16 @@ test('camUpdate only writes cam.fov when it actually changes', () => { ); }); -// ── A/B toggle + lifecycle reset ────────────────────────────────────────────── +// ── Shortcut (open/close) + lifecycle reset ─────────────────────────────────── -test('an A/B toggle shortcut flips the tune enabled flag', () => { +test('the shortcut opens/closes the tuner panel', () => { assert.match( src, - /registerShortcut\(\{[\s\S]*?const\s+t\s*=\s*_aspectTune\(\)\s*;[\s\S]*?t\.enabled\s*=\s*!\s*t\.enabled/, - 'a registerShortcut handler must toggle the bridge enabled flag', + /registerShortcut\(\{[\s\S]*?_toggleAspectPanel\(\)/, + 'a registerShortcut handler must toggle the tuner panel', ); + assert.match(src, /function\s+_toggleAspectPanel\s*\(\)/, + '_toggleAspectPanel() must exist to reveal/dismiss the panel'); }); test('destroy() resets the pane aspect and restores the base fov', () => {