From 13bbfc0b3d205e950b06bccfeb6ac1dc1262d9bc Mon Sep 17 00:00:00 2001 From: Byron Gamatos Date: Fri, 26 Jun 2026 14:09:16 +0200 Subject: [PATCH] refactor(highway_3d): move Butterchurn controls into settings.html (#600) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Addresses the altitude finding from the Butterchurn review: the visualizer's on/off + slider options shipped as a parallel UI (a ~140-line floating in-canvas control panel) separate from the plugin's standard settings panel. Move the standard controls (Background on, opacity, dim-behind-lane + strength, chart accents + strength, color tint + strength, guitar gain, song gain) into settings.html, using the plugin's normal settings UI. They persist into the same 'viz3d_settings' blob the controller already reads; a new module-scope window.h3dBcApplySettings() hook lets settings.html push changes to a mounted highway live (it invalidates the controller's settings cache and re-applies). The in-canvas panel is now ONLY the live preset browser (pick / favorite / ban / cycle / hold / meters) — things that are inherently live tools and don't belong in a static settings form. cyclePool/hold and the favorites/bans lists stay there; reads were made cache-safe (read fresh via _bcLoadSettings) so a settings.html write can't be clobbered by a stale captured reference. Co-authored-by: Claude Opus 4.8 (1M context) --- plugins/highway_3d/screen.js | 53 +++++++--------- plugins/highway_3d/settings.html | 103 +++++++++++++++++++++++++++++++ 2 files changed, 124 insertions(+), 32 deletions(-) diff --git a/plugins/highway_3d/screen.js b/plugins/highway_3d/screen.js index 622d173..766abff 100644 --- a/plugins/highway_3d/screen.js +++ b/plugins/highway_3d/screen.js @@ -81,7 +81,7 @@ let polling = true, songLevel = 0, chartLevel = 0; let node = null, sp = null, silent = null; const api = (window.feedBackDesktop || window.slopsmithDesktop).audio; - const gainNow = () => (_bcSettings && _bcSettings.guitarGain) || 6; + const gainNow = () => (_bcLoadSettings().guitarGain) || 6; // Keep the source node processing (silently — JUCE already monitors the // guitar), and hand it to Butterchurn via the onReady callback. @@ -148,7 +148,7 @@ if (!polling) return; Promise.resolve(api.getLevels && api.getLevels()).then((L) => { if (L && typeof L.outputLevel === 'number') { - songLevel = Math.min(1, L.outputLevel * ((_bcSettings && _bcSettings.songGain) || 1.8)); + songLevel = Math.min(1, L.outputLevel * ((_bcLoadSettings().songGain) || 1.8)); _bcMeters.song = songLevel; if (node) node.port.postMessage({ song: songLevel, chart: chartLevel, gain: gainNow() }); } @@ -187,6 +187,18 @@ function _bcSaveSettings() { try { localStorage.setItem(BC_LS, JSON.stringify(_bcSettings)); } catch (e) {} } const _bcControllers = new Set(); function _bcApplyAll() { _bcControllers.forEach((c) => { try { c.applySettings(); } catch (e) {} }); } + // Live-apply hook for the plugin's settings.html. The visualizer's on/off + + // slider controls now live in the standard settings panel (settings.html), + // which persists them into the BC_LS blob and then calls this so a mounted + // highway re-reads and applies them immediately. Defined on window at module + // scope so it's available regardless of whether a highway is mounted yet; + // settings.html guards the call with `?.` for the not-yet-loaded case. + window.h3dBcApplySettings = function () { + _bcSettings = null; // drop the cache so the next read reloads from localStorage + _bcLoadSettings(); + _bcApplyAll(); + try { _bcUpdatePanelPreset(); } catch (e) {} + }; // Preset curation: favorites / bans (persisted globally) + the "primary" // controller the panel's preset buttons drive. @@ -335,17 +347,10 @@ 'box-shadow:0 2px 12px rgba(0,0,0,0.5);user-select:none;transition:transform 0.28s ease;'; p.innerHTML = '
🌀 Visualizer
' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '' + - '
' + + // On/off + opacity/dim/chart/tint/gain controls now live in the + // plugin's Settings panel (settings.html). This in-canvas panel is + // only the LIVE preset browser (pick / favorite / ban / cycle). + '
Background & reactivity options are in Settings ▸ 3D Highway.
' + '
' + '' + '
' + @@ -398,31 +403,15 @@ pane.querySelector('#vz-defaults').addEventListener('click', _bcRestoreDefaults); const q = (id) => p.querySelector(id); - const on = q('#vz-on'), op = q('#vz-op'), opv = q('#vz-opv'), ld = q('#vz-ld'), lds = q('#vz-lds'); - const ca = q('#vz-ca'), tn = q('#vz-ct'), cs = q('#vz-cs'), ts = q('#vz-ts'), gg = q('#vz-gg'), ggv = q('#vz-ggv'), sg = q('#vz-sg'), sgv = q('#vz-sgv'); - on.checked = s.enabled; op.value = Math.round(s.opacity * 100); opv.textContent = op.value + '%'; - ld.checked = s.laneDim; lds.value = Math.round(s.laneDimStrength * 100); - ca.checked = s.chartAccents; tn.checked = s.colorTint; - cs.value = Math.round((s.chartStrength != null ? s.chartStrength : 1) * 100); - ts.value = Math.round((s.tintStrength != null ? s.tintStrength : 0.65) * 100); - gg.value = s.guitarGain != null ? s.guitarGain : 6; ggv.textContent = '×' + gg.value; - sg.value = s.songGain != null ? s.songGain : 1.8; sgv.textContent = '×' + sg.value; - const commit = () => { - s.enabled = on.checked; s.opacity = op.value / 100; - s.laneDim = ld.checked; s.laneDimStrength = lds.value / 100; - s.chartAccents = ca.checked; s.colorTint = tn.checked; - s.chartStrength = cs.value / 100; s.tintStrength = ts.value / 100; s.guitarGain = parseFloat(gg.value); s.songGain = parseFloat(sg.value); - opv.textContent = op.value + '%'; ggv.textContent = '×' + gg.value; sgv.textContent = '×' + sg.value; - _bcSaveSettings(); _bcApplyAll(); - }; - [on, op, ld, lds, ca, tn, cs, ts, gg, sg].forEach((el) => el.addEventListener('input', commit)); _bcPanel = p; // Preset curation wiring (favorites / bans / cycle / reset) _bcLoadLists(); const cyc = q('#vz-cyc'); cyc.value = s.cyclePool || 'all'; - cyc.addEventListener('change', () => { s.cyclePool = cyc.value; _bcSaveSettings(); }); + // Read fresh: settings.html writes can replace _bcSettings, so the `s` + // captured at panel creation may be stale by the time this fires. + cyc.addEventListener('change', () => { _bcLoadSettings().cyclePool = cyc.value; _bcSaveSettings(); }); _bcSetHold(!!s.hold); // sync the Hold button label to the saved state q('#vz-hold').addEventListener('click', () => _bcSetHold(!_bcLoadSettings().hold)); q('#vz-listbtn').addEventListener('click', () => _bcSetPane(!_bcPaneOpen)); diff --git a/plugins/highway_3d/settings.html b/plugins/highway_3d/settings.html index b75da5f..e24c3c2 100644 --- a/plugins/highway_3d/settings.html +++ b/plugins/highway_3d/settings.html @@ -160,6 +160,109 @@

+ +
+

Butterchurn (visualizer)

+

Active when Background style is set to Butterchurn (visualizer).

+
+ +
+
+ + +
+
+ +
+
+ + +
+
+ +
+
+ + +
+
+ +
+
+ + +
+
+ + +
+
+ + +
+
+ +