fix(highway): user-selectable scoreboard to stop duplicate HUDs

The highway showed two overlapping note-detection scoreboards at once: the
core v3 live-performance HUD (#v3-live-performance-hud) and the note_detect
plugin's own HUD (.nd-hud). Both auto-render off the same note:hit/note:miss
events and neither suppressed the other.

Add a Settings → Visualization "Scoreboard" selector (Streak / Detailed /
Off, default Streak) backed by a single source of truth on
<html data-scoreboard>. CSS shows exactly one:
  core (default) → core HUD; hide .nd-hud
  detailed       → .nd-hud; hide the core HUD
  off            → hide both

CSS-based suppression keys the default off ":not(detailed):not(off)", so the
correct HUD is right even before the pref script runs (no flash) and it
robustly hides any .nd-hud regardless of how many note_detect instances load.
Detection itself is untouched — only the duplicate scoreboard panel is hidden.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Byron Gamatos 2026-06-19 20:56:38 +02:00
parent a7a93e9bef
commit 36aeea67ac
3 changed files with 72 additions and 0 deletions

View File

@ -708,6 +708,14 @@
<option value="0.5">Low</option>
</select>
</div>
<div class="v3-pop-row">
<span class="v3-pop-label" id="scoreboard-label">Scoreboard</span>
<select id="scoreboard-select" onchange="setScoreboard(this.value)" class="v3-pop-select" aria-labelledby="scoreboard-label" title="Highway scoreboard">
<option value="core" selected>Streak</option>
<option value="detailed">Detailed</option>
<option value="off">Off</option>
</select>
</div>
<div class="v3-pop-row">
<span class="v3-pop-label" id="venue-motion-label">Venue Motion</span>
<select id="venue-motion-select" class="v3-pop-select" aria-labelledby="venue-motion-label" title="Venue Motion">
@ -858,6 +866,7 @@
<script src="/static/v3/badges.js"></script>
<script src="/static/v3/stats-recorder.js"></script>
<script src="/static/v3/live-performance-hud.js"></script>
<script src="/static/v3/scoreboard-pref.js"></script>
<script src="/static/v3/venue-viz.js"></script>
<script src="/static/v3/venue-instrument-pov.js"></script>
<!-- venue-mood-fx must load before venue-scene-3d: the scene bridge reads

View File

@ -0,0 +1,50 @@
/*
* fee[dB]ack highway scoreboard preference.
*
* The 3D/2D highway can show note-detection scoring two ways: the core v3
* live-performance HUD (#v3-live-performance-hud) and the note_detect plugin's
* own HUD (.nd-hud). Both auto-render off the same note:hit/note:miss events,
* so without a preference you get two overlapping scoreboards.
*
* This module is the single source of truth: it writes <html data-scoreboard>
* (core | detailed | off) and CSS in v3.css hides the non-selected HUD(s).
* Default is 'core'. The CSS keys the default off "not detailed and not off",
* so the right HUD is correct even before this script runs (no flash).
*/
(function () {
'use strict';
var KEY = 'highwayScoreboard';
var VALID = { core: 1, detailed: 1, off: 1 };
function read() {
var v = null;
try { v = localStorage.getItem(KEY); } catch (_e) { /* private mode */ }
return VALID[v] ? v : 'core';
}
function apply(v) {
if (document.documentElement) {
document.documentElement.setAttribute('data-scoreboard', v);
}
}
function setScoreboard(v) {
if (!VALID[v]) v = 'core';
try { localStorage.setItem(KEY, v); } catch (_e) { /* private mode */ }
apply(v);
var sel = document.getElementById('scoreboard-select');
if (sel && sel.value !== v) sel.value = v;
}
// Apply immediately so the correct HUD is set before the first note arrives.
apply(read());
// onchange="setScoreboard(this.value)" on the Settings select.
window.setScoreboard = setScoreboard;
document.addEventListener('DOMContentLoaded', function () {
var sel = document.getElementById('scoreboard-select');
if (sel) sel.value = read();
});
})();

View File

@ -313,6 +313,19 @@
transition: border-color .35s ease, box-shadow .35s ease, background .35s ease;
}
.v3-live-performance-hud.hidden { display: none; }
/* Highway scoreboard preference (static/v3/scoreboard-pref.js).
One note-detection scoreboard at a time on the highway:
core (default) core live-performance HUD; hide the note_detect plugin HUD
detailed note_detect .nd-hud; hide the core HUD
off hide both
The default rule keys off "not detailed and not off" so it's correct even
before the pref script sets data-scoreboard (avoids a flash of both). */
html:not([data-scoreboard="detailed"]):not([data-scoreboard="off"]) .nd-hud { display: none !important; }
html[data-scoreboard="detailed"] #v3-live-performance-hud { display: none !important; }
html[data-scoreboard="off"] .nd-hud,
html[data-scoreboard="off"] #v3-live-performance-hud { display: none !important; }
.v3-live-performance-heading {
display: flex;
align-items: baseline;